aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock8
-rw-r--r--components/canvas/Cargo.toml2
-rw-r--r--components/canvas/webgl_thread.rs34
-rw-r--r--components/devtools/actor.rs22
-rw-r--r--components/devtools/actors/browsing_context.rs46
-rw-r--r--components/devtools/actors/console.rs50
-rw-r--r--components/devtools/actors/device.rs4
-rw-r--r--components/devtools/actors/emulation.rs2
-rw-r--r--components/devtools/actors/framerate.rs2
-rw-r--r--components/devtools/actors/inspector.rs32
-rw-r--r--components/devtools/actors/memory.rs2
-rw-r--r--components/devtools/actors/network_event.rs18
-rw-r--r--components/devtools/actors/object.rs2
-rw-r--r--components/devtools/actors/performance.rs6
-rw-r--r--components/devtools/actors/preference.rs8
-rw-r--r--components/devtools/actors/process.rs4
-rw-r--r--components/devtools/actors/profiler.rs2
-rw-r--r--components/devtools/actors/root.rs20
-rw-r--r--components/devtools/actors/stylesheets.rs4
-rw-r--r--components/devtools/actors/tab.rs4
-rw-r--r--components/devtools/actors/thread.rs16
-rw-r--r--components/devtools/actors/timeline.rs25
-rw-r--r--components/devtools/actors/worker.rs34
-rw-r--r--components/devtools/lib.rs45
-rw-r--r--components/devtools/protocol.rs32
-rw-r--r--components/script/dom/mediasession.rs6
-rw-r--r--components/script/dom/mod.rs1
-rw-r--r--components/script/dom/webglframebuffer.rs10
-rw-r--r--components/script/dom/webglrenderingcontext.rs2
-rw-r--r--components/script/dom/webgltexture.rs43
-rw-r--r--components/script/dom/webidls/XRLayerEvent.webidl11
-rw-r--r--components/script/dom/xrlayerevent.rs62
-rw-r--r--components/script/dom/xrwebgllayer.rs6
-rw-r--r--components/servo/lib.rs3
-rw-r--r--components/webrender_surfman/Cargo.toml2
-rw-r--r--components/webrender_surfman/lib.rs2
-rw-r--r--ports/gstplugin/Cargo.toml2
-rw-r--r--python/servo/command_base.py1
-rw-r--r--support/hololens/ServoApp/BrowserPage.cpp35
-rw-r--r--support/hololens/ServoApp/BrowserPage.h4
-rw-r--r--support/hololens/ServoApp/BrowserPage.xaml4
-rw-r--r--support/hololens/ServoApp/Resources/PromotedPrefs.resw125
-rw-r--r--support/hololens/ServoApp/Resources/Strings/en-US/Resources.resw (renamed from support/hololens/ServoApp/Strings/en-US/Resources.resw)3
-rw-r--r--support/hololens/ServoApp/Resources/Strings/fr-FR/Resources.resw (renamed from support/hololens/ServoApp/Strings/fr-FR/Resources.resw)0
-rw-r--r--support/hololens/ServoApp/ServoApp.vcxproj11
-rw-r--r--support/hololens/ServoApp/ServoApp.vcxproj.filters20
-rw-r--r--support/hololens/ServoApp/ServoControl/Servo.cpp99
-rw-r--r--support/hololens/ServoApp/ServoControl/Servo.h1
-rw-r--r--support/hololens/ServoApp/ServoControl/ServoControl.cpp6
-rw-r--r--support/hololens/ServoApp/ServoControl/ServoControl.h10
-rw-r--r--support/hololens/ServoApp/ServoControl/ServoControl.idl2
-rw-r--r--support/hololens/ServoApp/pch.h1
-rw-r--r--tests/wpt/metadata-layout-2020/FileAPI/url/url-in-tags-revoke.window.js.ini2
-rw-r--r--tests/wpt/metadata-layout-2020/css/css-flexbox/position-absolute-015.html.ini4
-rw-r--r--tests/wpt/metadata-layout-2020/css/cssom-view/CaretPosition-001.html.ini4
-rw-r--r--tests/wpt/metadata-layout-2020/fetch/content-type/response.window.js.ini12
-rw-r--r--tests/wpt/metadata-layout-2020/fetch/content-type/script.window.js.ini3
-rw-r--r--tests/wpt/metadata-layout-2020/fetch/nosniff/parsing-nosniff.window.js.ini5
-rw-r--r--tests/wpt/metadata-layout-2020/html/browsers/history/the-history-interface/traverse_the_history_4.html.ini (renamed from tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_3.html.ini)2
-rw-r--r--tests/wpt/metadata-layout-2020/html/browsers/origin/cross-origin-objects/cross-origin-objects-on-new-window.html.ini2
-rw-r--r--tests/wpt/metadata-layout-2020/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/creating_browsing_context_test_01.html.ini4
-rw-r--r--tests/wpt/metadata-layout-2020/html/browsers/windows/embedded-opener-remove-frame.html.ini4
-rw-r--r--tests/wpt/metadata-layout-2020/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-flexbox.html.ini2
-rw-r--r--tests/wpt/metadata-layout-2020/html/semantics/embedded-content/image-maps/image-map-processing-model/hash-name-reference.html.ini3
-rw-r--r--tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-1.html.ini2
-rw-r--r--tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-2.html.ini1
-rw-r--r--tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-3.html.ini3
-rw-r--r--tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-1.html.ini2
-rw-r--r--tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-3.html.ini3
-rw-r--r--tests/wpt/metadata-layout-2020/html/semantics/forms/form-submission-0/form-double-submit-3.html.ini4
-rw-r--r--tests/wpt/metadata-layout-2020/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url-worker-importScripts.html.ini7
-rw-r--r--tests/wpt/metadata-layout-2020/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url.sub.html.ini7
-rw-r--r--tests/wpt/metadata-layout-2020/html/webappapis/dynamic-markup-insertion/document-write/iframe_005.html.ini4
-rw-r--r--tests/wpt/metadata-layout-2020/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-delayed.html.ini4
-rw-r--r--tests/wpt/metadata-layout-2020/html/webappapis/scripting/events/compile-event-handler-settings-objects.html.ini2
-rw-r--r--tests/wpt/metadata-layout-2020/streams/readable-streams/tee.any.js.ini59
-rw-r--r--tests/wpt/metadata-layout-2020/workers/interfaces/WorkerGlobalScope/onerror/exception-in-onerror.html.ini49
-rw-r--r--tests/wpt/metadata/FileAPI/url/url-in-tags-revoke.window.js.ini2
-rw-r--r--tests/wpt/metadata/MANIFEST.json534
-rw-r--r--tests/wpt/metadata/css/css-flexbox/position-absolute-015.html.ini4
-rw-r--r--tests/wpt/metadata/css/cssom-view/CaretPosition-001.html.ini4
-rw-r--r--tests/wpt/metadata/fetch/content-type/response.window.js.ini12
-rw-r--r--tests/wpt/metadata/fetch/content-type/script.window.js.ini3
-rw-r--r--tests/wpt/metadata/fetch/nosniff/parsing-nosniff.window.js.ini5
-rw-r--r--tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_4.html.ini (renamed from tests/wpt/metadata-layout-2020/html/browsers/history/the-history-interface/traverse_the_history_3.html.ini)2
-rw-r--r--tests/wpt/metadata/html/browsers/origin/cross-origin-objects/cross-origin-objects-on-new-window.html.ini2
-rw-r--r--tests/wpt/metadata/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/creating_browsing_context_test_01.html.ini4
-rw-r--r--tests/wpt/metadata/html/browsers/windows/embedded-opener-remove-frame.html.ini4
-rw-r--r--tests/wpt/metadata/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-flexbox.html.ini2
-rw-r--r--tests/wpt/metadata/html/semantics/embedded-content/image-maps/image-map-processing-model/hash-name-reference.html.ini3
-rw-r--r--tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-1.html.ini2
-rw-r--r--tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-2.html.ini1
-rw-r--r--tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-3.html.ini3
-rw-r--r--tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-1.html.ini2
-rw-r--r--tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-3.html.ini3
-rw-r--r--tests/wpt/metadata/html/semantics/forms/form-submission-0/form-double-submit-3.html.ini4
-rw-r--r--tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url-worker-importScripts.html.ini7
-rw-r--r--tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url.sub.html.ini7
-rw-r--r--tests/wpt/metadata/html/webappapis/dynamic-markup-insertion/document-write/iframe_005.html.ini4
-rw-r--r--tests/wpt/metadata/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-delayed.html.ini4
-rw-r--r--tests/wpt/metadata/html/webappapis/scripting/events/compile-event-handler-settings-objects.html.ini2
-rw-r--r--tests/wpt/metadata/streams/readable-streams/tee.any.js.ini44
-rw-r--r--tests/wpt/metadata/workers/interfaces/WorkerGlobalScope/onerror/exception-in-onerror.html.ini49
-rw-r--r--tests/wpt/mozilla/meta-layout-2020/mozilla/hit_test_multiple_sc.html.ini4
-rw-r--r--tests/wpt/mozilla/meta/MANIFEST.json7
-rw-r--r--tests/wpt/mozilla/meta/mozilla/getBoundingClientRect.html.ini4
-rw-r--r--tests/wpt/mozilla/meta/mozilla/hit-test-background.html.ini4
-rw-r--r--tests/wpt/mozilla/meta/mozilla/hit_test_multiple_sc.html.ini4
-rw-r--r--tests/wpt/mozilla/meta/mozilla/hit_test_pos_fixed.html.ini4
-rw-r--r--tests/wpt/mozilla/meta/webxr/layerevents.html.ini1
-rw-r--r--tests/wpt/mozilla/tests/webxr/layerevents.html36
-rw-r--r--tests/wpt/web-platform-tests/.taskcluster.yml2
-rw-r--r--tests/wpt/web-platform-tests/content-security-policy/reporting/report-frame-ancestors-with-x-frame-options.sub.html12
-rw-r--r--tests/wpt/web-platform-tests/content-security-policy/reporting/report-frame-ancestors.sub.html12
-rw-r--r--tests/wpt/web-platform-tests/content-security-policy/reporting/support/not-embeddable-frame.py10
-rw-r--r--tests/wpt/web-platform-tests/content-security-policy/sandbox/meta-element.sub.html46
-rw-r--r--tests/wpt/web-platform-tests/content-security-policy/sandbox/support/post-origin-on-load-worker.js1
-rw-r--r--tests/wpt/web-platform-tests/css/css-break/forced-break-at-fragmentainer-start-000.html11
-rw-r--r--tests/wpt/web-platform-tests/css/css-break/forced-break-at-fragmentainer-start-001.html12
-rw-r--r--tests/wpt/web-platform-tests/css/css-contain/content-visibility/content-visibility-074-ref.html35
-rw-r--r--tests/wpt/web-platform-tests/css/css-contain/content-visibility/content-visibility-074.html69
-rw-r--r--tests/wpt/web-platform-tests/css/css-flexbox/position-absolute-015.html19
-rw-r--r--tests/wpt/web-platform-tests/css/css-flexbox/quirks-auto-block-size-with-percentage-item.html14
-rw-r--r--tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-1-ref.html39
-rw-r--r--tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-1.html45
-rw-r--r--tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-10.html50
-rw-r--r--tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-2-ref.html53
-rw-r--r--tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-2.html50
-rw-r--r--tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-3-ref.html53
-rw-r--r--tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-3.html50
-rw-r--r--tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-4-ref.html53
-rw-r--r--tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-4.html50
-rw-r--r--tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-5-ref.html53
-rw-r--r--tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-5.html50
-rw-r--r--tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-6-ref.html54
-rw-r--r--tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-6.html51
-rw-r--r--tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-7-ref.html54
-rw-r--r--tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-7.html51
-rw-r--r--tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-8-ref.html27
-rw-r--r--tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-8.html50
-rw-r--r--tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-9.html50
-rw-r--r--tests/wpt/web-platform-tests/css/css-multicol/increase-prev-sibling-height-ref.html5
-rw-r--r--tests/wpt/web-platform-tests/css/css-multicol/increase-prev-sibling-height.html17
-rw-r--r--tests/wpt/web-platform-tests/css/css-paint-api/paint-function-this-value.https.html43
-rw-r--r--tests/wpt/web-platform-tests/docs/running-tests/from-local-system.md12
-rw-r--r--tests/wpt/web-platform-tests/docs/writing-tests/index.md90
-rw-r--r--tests/wpt/web-platform-tests/docs/writing-tests/testharness.md2
-rw-r--r--tests/wpt/web-platform-tests/dom/events/AddEventListenerOptions-once.html17
-rw-r--r--tests/wpt/web-platform-tests/dom/nodes/MutationObserver-callback-arguments.html31
-rw-r--r--tests/wpt/web-platform-tests/html/cross-origin-opener-policy/reporting/access-reporting/reporting-observer.html137
-rw-r--r--tests/wpt/web-platform-tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-redirect-with-same-origin-allow-popups.https.html155
-rw-r--r--tests/wpt/web-platform-tests/html/cross-origin-opener-policy/reporting/resources/dispatcher.py21
-rw-r--r--tests/wpt/web-platform-tests/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-flexbox.html11
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/allow-scripts-flag-changing-1.html8
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url-worker-importScripts.html7
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url-worker.sub.html8
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url.sub.html28
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/import.js1
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/worker-importScripts.sub.js15
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/beta/import.js1
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/beta/redirect.py19
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js58
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/import.js1
-rw-r--r--tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/protocol-handler-fragment-manual.https.html20
-rw-r--r--tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/protocol-handler-fragment-nosw-manual.https.html20
-rw-r--r--tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/protocol-handler-path-manual.https.html20
-rw-r--r--tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/protocol-handler-query-manual.https.html20
-rw-r--r--tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/protocol-handler-query-nosw-manual.https.html20
-rw-r--r--tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/resources/handler-sw.js3
-rw-r--r--tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/resources/handler-tools.js53
-rw-r--r--tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/resources/handler.html23
-rw-r--r--tests/wpt/web-platform-tests/input-events/input-events-get-target-ranges-backspace.tentative.html811
-rw-r--r--tests/wpt/web-platform-tests/input-events/input-events-get-target-ranges-forwarddelete.tentative.html808
-rw-r--r--tests/wpt/web-platform-tests/interfaces/web-share.idl2
-rw-r--r--tests/wpt/web-platform-tests/intersection-observer/observer-callback-arguments.html28
-rw-r--r--tests/wpt/web-platform-tests/largest-contentful-paint/invisible-images-composited-1.html12
-rw-r--r--tests/wpt/web-platform-tests/layout-instability/child-shift-with-parent-overflow-hidden.html32
-rw-r--r--tests/wpt/web-platform-tests/layout-instability/child-shift-with-parent.html34
-rw-r--r--tests/wpt/web-platform-tests/layout-instability/inline-flow-shift-vertical-rl.html4
-rw-r--r--tests/wpt/web-platform-tests/layout-instability/inline-flow-shift.html2
-rw-r--r--tests/wpt/web-platform-tests/origin-isolation/resources/child-frame-script.mjs8
-rw-r--r--tests/wpt/web-platform-tests/origin-isolation/resources/helpers.mjs24
-rw-r--r--tests/wpt/web-platform-tests/pointerevents/compat/pointerevent_compat-mouse-events-when-removing-nodes.html14
-rw-r--r--tests/wpt/web-platform-tests/pointerevents/compat/pointerevent_mouse-on-object.html23
-rw-r--r--tests/wpt/web-platform-tests/pointerevents/compat/pointerevent_mouse-pointer-preventdefault.html199
-rw-r--r--tests/wpt/web-platform-tests/streams/readable-streams/tee.any.js51
-rw-r--r--tests/wpt/web-platform-tests/svg/types/scripted/SVGGeometryElement.getPointAtLength-03.svg1
-rwxr-xr-xtests/wpt/web-platform-tests/tools/ci/run_tc.py7
-rwxr-xr-xtests/wpt/web-platform-tests/tools/ci/taskcluster-run.py21
-rw-r--r--tests/wpt/web-platform-tests/tools/ci/tc/decision.py2
-rw-r--r--tests/wpt/web-platform-tests/tools/ci/tc/github_checks_output.py29
-rw-r--r--tests/wpt/web-platform-tests/tools/ci/tc/tasks/test.yml27
-rw-r--r--tests/wpt/web-platform-tests/tools/ci/tc/tests/test_valid.py29
-rw-r--r--tests/wpt/web-platform-tests/tools/serve/commands.json1
-rw-r--r--tests/wpt/web-platform-tests/tools/serve/test_functional.py3
-rw-r--r--tests/wpt/web-platform-tests/tools/wpt/commands.json5
-rw-r--r--tests/wpt/web-platform-tests/tools/wpt/tests/test_wpt.py4
-rw-r--r--tests/wpt/web-platform-tests/tools/wpt/wpt.py2
-rw-r--r--tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/stability.py34
-rw-r--r--tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptcommandline.py5
-rw-r--r--tests/wpt/web-platform-tests/tools/wptserve/tests/functional/test_stash.py3
-rw-r--r--tests/wpt/web-platform-tests/user-timing/case-sensitivity.any.js25
-rw-r--r--tests/wpt/web-platform-tests/webdriver/tests/new_session/response.py14
-rw-r--r--tests/wpt/web-platform-tests/webdriver/tests/perform_actions/support/keys.py1407
-rw-r--r--tests/wpt/web-platform-tests/webxr/render_state_update.https.html96
-rw-r--r--tests/wpt/web-platform-tests/workers/interfaces/WorkerGlobalScope/onerror/exception-in-onerror.html102
-rw-r--r--tests/wpt/web-platform-tests/workers/interfaces/WorkerGlobalScope/onerror/exception-in-onerror.js28
-rw-r--r--tests/wpt/webgl/meta/conformance/renderbuffers/framebuffer-state-restoration.html.ini3
-rw-r--r--tests/wpt/webgl/meta/conformance/rendering/multisample-corruption.html.ini72
-rw-r--r--tests/wpt/webgl/meta/conformance2/rendering/draw-buffers.html.ini9
210 files changed, 6549 insertions, 1291 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 24bcfab54ed..098934e8a07 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -5878,9 +5878,9 @@ dependencies = [
[[package]]
name = "surfman-chains"
-version = "0.4.0"
+version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d51598e1772bda3dbb1b81a9dc4b46725896948ea58d0f128e5b492a92f297af"
+checksum = "d7370be9fb29386426ce52d9c3ac0501e7f71ea8218baf4bee061465f2fcec04"
dependencies = [
"euclid",
"fnv",
@@ -6910,7 +6910,7 @@ dependencies = [
[[package]]
name = "webxr"
version = "0.0.1"
-source = "git+https://github.com/servo/webxr#da44de55ca8c082a033787946cb59dbbd2903a15"
+source = "git+https://github.com/servo/webxr#7763f4826fb04a1b48dbf502e48ca9d6ff3b6378"
dependencies = [
"android_injected_glue",
"bindgen",
@@ -6933,7 +6933,7 @@ dependencies = [
[[package]]
name = "webxr-api"
version = "0.0.1"
-source = "git+https://github.com/servo/webxr#da44de55ca8c082a033787946cb59dbbd2903a15"
+source = "git+https://github.com/servo/webxr#7763f4826fb04a1b48dbf502e48ca9d6ff3b6378"
dependencies = [
"euclid",
"ipc-channel",
diff --git a/components/canvas/Cargo.toml b/components/canvas/Cargo.toml
index 2281ea30242..7e3267148e6 100644
--- a/components/canvas/Cargo.toml
+++ b/components/canvas/Cargo.toml
@@ -40,7 +40,7 @@ style = { path = "../style" }
style_traits = { path = "../style_traits" }
# NOTE: the sm-angle feature only enables angle on windows, not other platforms!
surfman = { version = "0.3", features = ["sm-angle","sm-angle-default"] }
-surfman-chains = "0.4"
+surfman-chains = "0.5"
surfman-chains-api = "0.2"
time = { version = "0.1.0", optional = true }
webrender = { git = "https://github.com/servo/webrender" }
diff --git a/components/canvas/webgl_thread.rs b/components/canvas/webgl_thread.rs
index 3c27c523866..168a7e9f070 100644
--- a/components/canvas/webgl_thread.rs
+++ b/components/canvas/webgl_thread.rs
@@ -827,22 +827,30 @@ impl WebGLThread {
debug!("Swapping {:?}", context_id);
swap_chain
- .swap_buffers(&mut self.device, &mut data.ctx)
+ .swap_buffers(
+ &mut self.device,
+ &mut data.ctx,
+ if data.attributes.preserve_drawing_buffer {
+ surfman_chains::PreserveBuffer::Yes(&*data.gl)
+ } else {
+ surfman_chains::PreserveBuffer::No
+ },
+ )
.unwrap();
debug_assert_eq!(data.gl.get_error(), gl::NO_ERROR);
- // TODO: if preserveDrawingBuffer is true, then blit the front buffer to the back buffer
- // https://github.com/servo/servo/issues/24604
- debug!("Clearing {:?}", context_id);
- let alpha = data
- .state
- .requested_flags
- .contains(ContextAttributeFlags::ALPHA);
- let clear_color = [0.0, 0.0, 0.0, !alpha as i32 as f32];
- swap_chain
- .clear_surface(&mut self.device, &mut data.ctx, &*data.gl, clear_color)
- .unwrap();
- debug_assert_eq!(data.gl.get_error(), gl::NO_ERROR);
+ if !data.attributes.preserve_drawing_buffer {
+ debug!("Clearing {:?}", context_id);
+ let alpha = data
+ .state
+ .requested_flags
+ .contains(ContextAttributeFlags::ALPHA);
+ let clear_color = [0.0, 0.0, 0.0, !alpha as i32 as f32];
+ swap_chain
+ .clear_surface(&mut self.device, &mut data.ctx, &*data.gl, clear_color)
+ .unwrap();
+ debug_assert_eq!(data.gl.get_error(), gl::NO_ERROR);
+ }
// Rebind framebuffers as appropriate.
debug!("Rebinding {:?}", context_id);
diff --git a/components/devtools/actor.rs b/components/devtools/actor.rs
index 158092ee1a8..641c6f717d4 100644
--- a/components/devtools/actor.rs
+++ b/components/devtools/actor.rs
@@ -3,6 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
/// General actor system infrastructure.
+use crate::StreamId;
use devtools_traits::PreciseTime;
use serde_json::{Map, Value};
use std::any::Any;
@@ -21,18 +22,20 @@ pub enum ActorMessageStatus {
/// A common trait for all devtools actors that encompasses an immutable name
/// and the ability to process messages that are directed to particular actors.
/// TODO: ensure the name is immutable
-pub trait Actor: Any + ActorAsAny {
+pub(crate) trait Actor: Any + ActorAsAny {
fn handle_message(
&self,
registry: &ActorRegistry,
msg_type: &str,
msg: &Map<String, Value>,
stream: &mut TcpStream,
+ id: StreamId,
) -> Result<ActorMessageStatus, ()>;
fn name(&self) -> String;
+ fn cleanup(&self, _id: StreamId) {}
}
-pub trait ActorAsAny {
+pub(crate) trait ActorAsAny {
fn actor_as_any(&self) -> &dyn Any;
fn actor_as_any_mut(&mut self) -> &mut dyn Any;
}
@@ -71,6 +74,12 @@ impl ActorRegistry {
}
}
+ pub(crate) fn cleanup(&self, id: StreamId) {
+ for actor in self.actors.values() {
+ actor.cleanup(id);
+ }
+ }
+
/// Creating shareable registry
pub fn create_shareable(self) -> Arc<Mutex<ActorRegistry>> {
if let Some(shareable) = self.shareable {
@@ -131,11 +140,11 @@ impl ActorRegistry {
}
/// Add an actor to the registry of known actors that can receive messages.
- pub fn register(&mut self, actor: Box<dyn Actor + Send>) {
+ pub(crate) fn register(&mut self, actor: Box<dyn Actor + Send>) {
self.actors.insert(actor.name(), actor);
}
- pub fn register_later(&self, actor: Box<dyn Actor + Send>) {
+ pub(crate) fn register_later(&self, actor: Box<dyn Actor + Send>) {
let mut actors = self.new_actors.borrow_mut();
actors.push(actor);
}
@@ -154,10 +163,11 @@ impl ActorRegistry {
/// Attempt to process a message as directed by its `to` property. If the actor is not
/// found or does not indicate that it knew how to process the message, ignore the failure.
- pub fn handle_message(
+ pub(crate) fn handle_message(
&mut self,
msg: &Map<String, Value>,
stream: &mut TcpStream,
+ id: StreamId,
) -> Result<(), ()> {
let to = match msg.get("to") {
Some(to) => to.as_str().unwrap(),
@@ -171,7 +181,7 @@ impl ActorRegistry {
None => debug!("message received for unknown actor \"{}\"", to),
Some(actor) => {
let msg_type = msg.get("type").unwrap().as_str().unwrap();
- if actor.handle_message(self, msg_type, msg, stream)? !=
+ if actor.handle_message(self, msg_type, msg, stream, id)? !=
ActorMessageStatus::Processed
{
debug!(
diff --git a/components/devtools/actors/browsing_context.rs b/components/devtools/actors/browsing_context.rs
index 708c9f69de9..beee86e50b5 100644
--- a/components/devtools/actors/browsing_context.rs
+++ b/components/devtools/actors/browsing_context.rs
@@ -17,6 +17,7 @@ use crate::actors::tab::TabDescriptorActor;
use crate::actors::thread::ThreadActor;
use crate::actors::timeline::TimelineActor;
use crate::protocol::JsonPacketStream;
+use crate::StreamId;
use devtools_traits::DevtoolScriptControlMsg::{self, WantsLiveNotifications};
use devtools_traits::DevtoolsPageInfo;
use devtools_traits::NavigationState;
@@ -24,6 +25,7 @@ use ipc_channel::ipc::IpcSender;
use msg::constellation_msg::{BrowsingContextId, PipelineId};
use serde_json::{Map, Value};
use std::cell::{Cell, RefCell};
+use std::collections::HashMap;
use std::net::TcpStream;
#[derive(Serialize)]
@@ -118,7 +120,7 @@ pub struct BrowsingContextActorMsg {
manifestActor: String,*/
}
-pub struct BrowsingContextActor {
+pub(crate) struct BrowsingContextActor {
pub name: String,
pub title: RefCell<String>,
pub url: RefCell<String>,
@@ -131,7 +133,7 @@ pub struct BrowsingContextActor {
pub styleSheets: String,
pub thread: String,
pub tab: String,
- pub streams: RefCell<Vec<TcpStream>>,
+ pub streams: RefCell<HashMap<StreamId, TcpStream>>,
pub browsing_context_id: BrowsingContextId,
pub active_pipeline: Cell<PipelineId>,
pub script_chan: IpcSender<DevtoolScriptControlMsg>,
@@ -148,6 +150,7 @@ impl Actor for BrowsingContextActor {
msg_type: &str,
msg: &Map<String, Value>,
stream: &mut TcpStream,
+ id: StreamId,
) -> Result<ActorMessageStatus, ()> {
Ok(match msg_type {
"reconfigure" => {
@@ -160,7 +163,7 @@ impl Actor for BrowsingContextActor {
}
}
}
- stream.write_json_packet(&ReconfigureReply { from: self.name() });
+ let _ = stream.write_json_packet(&ReconfigureReply { from: self.name() });
ActorMessageStatus::Processed
},
@@ -181,26 +184,26 @@ impl Actor for BrowsingContextActor {
watchpoints: false,
},
};
- self.streams.borrow_mut().push(stream.try_clone().unwrap());
- stream.write_json_packet(&msg);
+
+ if stream.write_json_packet(&msg).is_err() {
+ return Ok(ActorMessageStatus::Processed);
+ }
+ self.streams
+ .borrow_mut()
+ .insert(id, stream.try_clone().unwrap());
self.script_chan
.send(WantsLiveNotifications(self.active_pipeline.get(), true))
.unwrap();
ActorMessageStatus::Processed
},
- //FIXME: The current implementation won't work for multiple connections. Need to ensure
- // that the correct stream is removed.
"detach" => {
let msg = BrowsingContextDetachedReply {
from: self.name(),
type_: "detached".to_owned(),
};
- self.streams.borrow_mut().pop();
- stream.write_json_packet(&msg);
- self.script_chan
- .send(WantsLiveNotifications(self.active_pipeline.get(), false))
- .unwrap();
+ let _ = stream.write_json_packet(&msg);
+ self.cleanup(id);
ActorMessageStatus::Processed
},
@@ -215,7 +218,7 @@ impl Actor for BrowsingContextActor {
title: self.title.borrow().clone(),
}],
};
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
@@ -224,13 +227,22 @@ impl Actor for BrowsingContextActor {
from: self.name(),
workers: vec![],
};
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
_ => ActorMessageStatus::Ignored,
})
}
+
+ fn cleanup(&self, id: StreamId) {
+ self.streams.borrow_mut().remove(&id);
+ if self.streams.borrow().is_empty() {
+ self.script_chan
+ .send(WantsLiveNotifications(self.active_pipeline.get(), false))
+ .unwrap();
+ }
+ }
}
impl BrowsingContextActor {
@@ -284,7 +296,7 @@ impl BrowsingContextActor {
styleSheets: styleSheets.name(),
tab: tabdesc.name(),
thread: thread.name(),
- streams: RefCell::new(Vec::new()),
+ streams: RefCell::new(HashMap::new()),
browsing_context_id: id,
active_pipeline: Cell::new(pipeline),
};
@@ -347,8 +359,8 @@ impl BrowsingContextActor {
state: state.to_owned(),
isFrameSwitching: false,
};
- for stream in &mut *self.streams.borrow_mut() {
- stream.write_json_packet(&msg);
+ for stream in self.streams.borrow_mut().values_mut() {
+ let _ = stream.write_json_packet(&msg);
}
}
diff --git a/components/devtools/actors/console.rs b/components/devtools/actors/console.rs
index 4576a296775..86e4f39dd33 100644
--- a/components/devtools/actors/console.rs
+++ b/components/devtools/actors/console.rs
@@ -12,7 +12,7 @@ use crate::actors::browsing_context::BrowsingContextActor;
use crate::actors::object::ObjectActor;
use crate::actors::worker::WorkerActor;
use crate::protocol::JsonPacketStream;
-use crate::UniqueId;
+use crate::{StreamId, UniqueId};
use devtools_traits::CachedConsoleMessage;
use devtools_traits::ConsoleMessage;
use devtools_traits::EvaluateJSReply::{ActorValue, BooleanValue, StringValue};
@@ -23,7 +23,7 @@ use devtools_traits::{
use ipc_channel::ipc::{self, IpcSender};
use msg::constellation_msg::TEST_PIPELINE_ID;
use serde_json::{self, Map, Number, Value};
-use std::cell::{RefCell, RefMut};
+use std::cell::RefCell;
use std::collections::HashMap;
use std::net::TcpStream;
use time::precise_time_ns;
@@ -130,15 +130,20 @@ impl ConsoleActor {
}
}
- fn streams_mut<'a>(&self, registry: &'a ActorRegistry) -> RefMut<'a, Vec<TcpStream>> {
+ fn streams_mut<'a>(&self, registry: &'a ActorRegistry, cb: impl Fn(&mut TcpStream)) {
match &self.root {
Root::BrowsingContext(bc) => registry
.find::<BrowsingContextActor>(bc)
.streams
- .borrow_mut(),
- Root::DedicatedWorker(worker) => {
- registry.find::<WorkerActor>(worker).streams.borrow_mut()
- },
+ .borrow_mut()
+ .values_mut()
+ .for_each(cb),
+ Root::DedicatedWorker(worker) => registry
+ .find::<WorkerActor>(worker)
+ .streams
+ .borrow_mut()
+ .values_mut()
+ .for_each(cb),
}
}
@@ -255,9 +260,9 @@ impl ConsoleActor {
type_: "pageError".to_owned(),
pageError: page_error,
};
- for stream in &mut *self.streams_mut(registry) {
- stream.write_json_packet(&msg);
- }
+ self.streams_mut(registry, |stream| {
+ let _ = stream.write_json_packet(&msg);
+ });
}
}
@@ -303,9 +308,9 @@ impl ConsoleActor {
columnNumber: console_message.columnNumber,
},
};
- for stream in &mut *self.streams_mut(registry) {
- stream.write_json_packet(&msg);
- }
+ self.streams_mut(registry, |stream| {
+ let _ = stream.write_json_packet(&msg);
+ });
}
}
}
@@ -321,6 +326,7 @@ impl Actor for ConsoleActor {
msg_type: &str,
msg: &Map<String, Value>,
stream: &mut TcpStream,
+ _id: StreamId,
) -> Result<ActorMessageStatus, ()> {
Ok(match msg_type {
"clearMessagesCache" => {
@@ -380,7 +386,7 @@ impl Actor for ConsoleActor {
from: self.name(),
messages: messages,
};
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
@@ -396,7 +402,7 @@ impl Actor for ConsoleActor {
.collect(),
traits: StartedListenersTraits,
};
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
@@ -413,7 +419,7 @@ impl Actor for ConsoleActor {
.map(|listener| listener.as_str().unwrap().to_owned())
.collect(),
};
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
@@ -425,13 +431,13 @@ impl Actor for ConsoleActor {
matches: vec![],
matchProp: "".to_owned(),
};
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
"evaluateJS" => {
let msg = self.evaluateJS(&registry, &msg);
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
@@ -443,7 +449,9 @@ impl Actor for ConsoleActor {
};
// Emit an eager reply so that the client starts listening
// for an async event with the resultID
- stream.write_json_packet(&early_reply);
+ if stream.write_json_packet(&early_reply).is_err() {
+ return Ok(ActorMessageStatus::Processed);
+ }
if msg.get("eager").and_then(|v| v.as_bool()).unwrap_or(false) {
// We don't support the side-effect free evaluation that eager evalaution
@@ -464,7 +472,7 @@ impl Actor for ConsoleActor {
helperResult: reply.helperResult,
};
// Send the data from evaluateJS along with a resultID
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
@@ -473,7 +481,7 @@ impl Actor for ConsoleActor {
from: self.name(),
updated: vec![],
};
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
diff --git a/components/devtools/actors/device.rs b/components/devtools/actors/device.rs
index 11785d8c0b8..c54b72b6d5d 100644
--- a/components/devtools/actors/device.rs
+++ b/components/devtools/actors/device.rs
@@ -5,6 +5,7 @@
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
use crate::protocol::JsonPacketStream;
use crate::protocol::{ActorDescription, Method};
+use crate::StreamId;
use serde_json::{Map, Value};
use std::net::TcpStream;
@@ -34,6 +35,7 @@ impl Actor for DeviceActor {
msg_type: &str,
_msg: &Map<String, Value>,
stream: &mut TcpStream,
+ _id: StreamId,
) -> Result<ActorMessageStatus, ()> {
Ok(match msg_type {
"getDescription" => {
@@ -44,7 +46,7 @@ impl Actor for DeviceActor {
platformVersion: "71.0".to_string(),
},
};
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
diff --git a/components/devtools/actors/emulation.rs b/components/devtools/actors/emulation.rs
index 94b769a106f..58f13b16d34 100644
--- a/components/devtools/actors/emulation.rs
+++ b/components/devtools/actors/emulation.rs
@@ -3,6 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
+use crate::StreamId;
use serde_json::{Map, Value};
use std::net::TcpStream;
@@ -21,6 +22,7 @@ impl Actor for EmulationActor {
msg_type: &str,
_msg: &Map<String, Value>,
_stream: &mut TcpStream,
+ _id: StreamId,
) -> Result<ActorMessageStatus, ()> {
Ok(match msg_type {
_ => ActorMessageStatus::Ignored,
diff --git a/components/devtools/actors/framerate.rs b/components/devtools/actors/framerate.rs
index 243c7ea4c4c..6203be2c57e 100644
--- a/components/devtools/actors/framerate.rs
+++ b/components/devtools/actors/framerate.rs
@@ -4,6 +4,7 @@
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
use crate::actors::timeline::HighResolutionStamp;
+use crate::StreamId;
use devtools_traits::DevtoolScriptControlMsg;
use ipc_channel::ipc::IpcSender;
use msg::constellation_msg::PipelineId;
@@ -32,6 +33,7 @@ impl Actor for FramerateActor {
_msg_type: &str,
_msg: &Map<String, Value>,
_stream: &mut TcpStream,
+ _id: StreamId,
) -> Result<ActorMessageStatus, ()> {
Ok(ActorMessageStatus::Ignored)
}
diff --git a/components/devtools/actors/inspector.rs b/components/devtools/actors/inspector.rs
index d2f0929ac89..d01267b68e7 100644
--- a/components/devtools/actors/inspector.rs
+++ b/components/devtools/actors/inspector.rs
@@ -8,6 +8,7 @@
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
use crate::actors::browsing_context::BrowsingContextActor;
use crate::protocol::JsonPacketStream;
+use crate::StreamId;
use devtools_traits::DevtoolScriptControlMsg::{GetChildren, GetDocumentElement, GetRootNode};
use devtools_traits::DevtoolScriptControlMsg::{GetLayout, ModifyAttribute};
use devtools_traits::{ComputedNodeLayout, DevtoolScriptControlMsg, NodeInfo};
@@ -68,17 +69,18 @@ impl Actor for HighlighterActor {
msg_type: &str,
_msg: &Map<String, Value>,
stream: &mut TcpStream,
+ _id: StreamId,
) -> Result<ActorMessageStatus, ()> {
Ok(match msg_type {
"showBoxModel" => {
let msg = ShowBoxModelReply { from: self.name() };
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
"hideBoxModel" => {
let msg = HideBoxModelReply { from: self.name() };
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
@@ -103,6 +105,7 @@ impl Actor for NodeActor {
msg_type: &str,
msg: &Map<String, Value>,
stream: &mut TcpStream,
+ _id: StreamId,
) -> Result<ActorMessageStatus, ()> {
Ok(match msg_type {
"modifyAttributes" => {
@@ -123,7 +126,7 @@ impl Actor for NodeActor {
))
.unwrap();
let reply = ModifyAttributeReply { from: self.name() };
- stream.write_json_packet(&reply);
+ let _ = stream.write_json_packet(&reply);
ActorMessageStatus::Processed
},
@@ -289,11 +292,12 @@ impl Actor for WalkerActor {
msg_type: &str,
msg: &Map<String, Value>,
stream: &mut TcpStream,
+ _id: StreamId,
) -> Result<ActorMessageStatus, ()> {
Ok(match msg_type {
"querySelector" => {
let msg = QuerySelectorReply { from: self.name() };
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
@@ -310,13 +314,13 @@ impl Actor for WalkerActor {
from: self.name(),
node: node,
};
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
"clearPseudoClassLocks" => {
let msg = ClearPseudoclassesReply { from: self.name() };
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
@@ -343,7 +347,7 @@ impl Actor for WalkerActor {
.collect(),
from: self.name(),
};
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
@@ -471,6 +475,7 @@ impl Actor for PageStyleActor {
msg_type: &str,
msg: &Map<String, Value>,
stream: &mut TcpStream,
+ _id: StreamId,
) -> Result<ActorMessageStatus, ()> {
Ok(match msg_type {
"getApplied" => {
@@ -481,7 +486,7 @@ impl Actor for PageStyleActor {
sheets: vec![],
from: self.name(),
};
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
@@ -491,7 +496,7 @@ impl Actor for PageStyleActor {
computed: vec![],
from: self.name(),
};
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
@@ -576,7 +581,7 @@ impl Actor for PageStyleActor {
};
let msg = serde_json::to_string(&msg).unwrap();
let msg = serde_json::from_str::<Value>(&msg).unwrap();
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
@@ -596,6 +601,7 @@ impl Actor for InspectorActor {
msg_type: &str,
_msg: &Map<String, Value>,
stream: &mut TcpStream,
+ _id: StreamId,
) -> Result<ActorMessageStatus, ()> {
let browsing_context = registry.find::<BrowsingContextActor>(&self.browsing_context);
let pipeline = browsing_context.active_pipeline.get();
@@ -625,7 +631,7 @@ impl Actor for InspectorActor {
root: node,
},
};
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
@@ -647,7 +653,7 @@ impl Actor for InspectorActor {
actor: self.pageStyle.borrow().clone().unwrap(),
},
};
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
@@ -670,7 +676,7 @@ impl Actor for InspectorActor {
actor: self.highlighter.borrow().clone().unwrap(),
},
};
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
diff --git a/components/devtools/actors/memory.rs b/components/devtools/actors/memory.rs
index 3240a105260..67f83548f9c 100644
--- a/components/devtools/actors/memory.rs
+++ b/components/devtools/actors/memory.rs
@@ -3,6 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
+use crate::StreamId;
use serde_json::{Map, Value};
use std::net::TcpStream;
@@ -34,6 +35,7 @@ impl Actor for MemoryActor {
_msg_type: &str,
_msg: &Map<String, Value>,
_stream: &mut TcpStream,
+ _id: StreamId,
) -> Result<ActorMessageStatus, ()> {
Ok(ActorMessageStatus::Ignored)
}
diff --git a/components/devtools/actors/network_event.rs b/components/devtools/actors/network_event.rs
index 8af38f52c0c..622ac6002eb 100644
--- a/components/devtools/actors/network_event.rs
+++ b/components/devtools/actors/network_event.rs
@@ -8,6 +8,7 @@
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
use crate::protocol::JsonPacketStream;
+use crate::StreamId;
use devtools_traits::HttpRequest as DevtoolsHttpRequest;
use devtools_traits::HttpResponse as DevtoolsHttpResponse;
use headers::{ContentType, Cookie, HeaderMapExt};
@@ -180,6 +181,7 @@ impl Actor for NetworkEventActor {
msg_type: &str,
_msg: &Map<String, Value>,
stream: &mut TcpStream,
+ _id: StreamId,
) -> Result<ActorMessageStatus, ()> {
Ok(match msg_type {
"getRequestHeaders" => {
@@ -201,7 +203,7 @@ impl Actor for NetworkEventActor {
headerSize: headersSize,
rawHeaders: rawHeadersString,
};
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
"getRequestCookies" => {
@@ -217,7 +219,7 @@ impl Actor for NetworkEventActor {
from: self.name(),
cookies: cookies,
};
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
"getRequestPostData" => {
@@ -226,7 +228,7 @@ impl Actor for NetworkEventActor {
postData: self.request.body.clone(),
postDataDiscarded: false,
};
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
"getResponseHeaders" => {
@@ -251,7 +253,7 @@ impl Actor for NetworkEventActor {
headerSize: headersSize,
rawHeaders: rawHeadersString,
};
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
}
ActorMessageStatus::Processed
},
@@ -268,7 +270,7 @@ impl Actor for NetworkEventActor {
from: self.name(),
cookies: cookies,
};
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
"getResponseContent" => {
@@ -277,7 +279,7 @@ impl Actor for NetworkEventActor {
content: self.response.body.clone(),
contentDiscarded: self.response.body.is_none(),
};
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
"getEventTimings" => {
@@ -297,7 +299,7 @@ impl Actor for NetworkEventActor {
timings: timingsObj,
totalTime: total,
};
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
"getSecurityInfo" => {
@@ -308,7 +310,7 @@ impl Actor for NetworkEventActor {
state: "insecure".to_owned(),
},
};
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
_ => ActorMessageStatus::Ignored,
diff --git a/components/devtools/actors/object.rs b/components/devtools/actors/object.rs
index fc2a2002e7d..b10f5e9fd65 100644
--- a/components/devtools/actors/object.rs
+++ b/components/devtools/actors/object.rs
@@ -3,6 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
+use crate::StreamId;
use serde_json::{Map, Value};
use std::net::TcpStream;
@@ -21,6 +22,7 @@ impl Actor for ObjectActor {
_: &str,
_: &Map<String, Value>,
_: &mut TcpStream,
+ _: StreamId,
) -> Result<ActorMessageStatus, ()> {
Ok(ActorMessageStatus::Ignored)
}
diff --git a/components/devtools/actors/performance.rs b/components/devtools/actors/performance.rs
index d26e4aee1d6..497922a2745 100644
--- a/components/devtools/actors/performance.rs
+++ b/components/devtools/actors/performance.rs
@@ -4,6 +4,7 @@
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
use crate::protocol::{ActorDescription, JsonPacketStream, Method};
+use crate::StreamId;
use serde_json::{Map, Value};
use std::net::TcpStream;
@@ -57,6 +58,7 @@ impl Actor for PerformanceActor {
msg_type: &str,
_msg: &Map<String, Value>,
stream: &mut TcpStream,
+ _id: StreamId,
) -> Result<ActorMessageStatus, ()> {
Ok(match msg_type {
"connect" => {
@@ -72,7 +74,7 @@ impl Actor for PerformanceActor {
},
},
};
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
"canCurrentlyRecord" => {
@@ -83,7 +85,7 @@ impl Actor for PerformanceActor {
errors: vec![],
},
};
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
_ => ActorMessageStatus::Ignored,
diff --git a/components/devtools/actors/preference.rs b/components/devtools/actors/preference.rs
index aefd8638631..a690148342f 100644
--- a/components/devtools/actors/preference.rs
+++ b/components/devtools/actors/preference.rs
@@ -4,6 +4,7 @@
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
use crate::protocol::JsonPacketStream;
+use crate::StreamId;
use serde_json::{Map, Value};
use std::net::TcpStream;
@@ -28,6 +29,7 @@ impl Actor for PreferenceActor {
msg_type: &str,
_msg: &Map<String, Value>,
stream: &mut TcpStream,
+ _id: StreamId,
) -> Result<ActorMessageStatus, ()> {
Ok(match msg_type {
"getBoolPref" => {
@@ -35,7 +37,7 @@ impl Actor for PreferenceActor {
from: self.name(),
value: false,
};
- stream.write_json_packet(&reply);
+ let _ = stream.write_json_packet(&reply);
ActorMessageStatus::Processed
},
@@ -44,7 +46,7 @@ impl Actor for PreferenceActor {
from: self.name(),
value: "".to_owned(),
};
- stream.write_json_packet(&reply);
+ let _ = stream.write_json_packet(&reply);
ActorMessageStatus::Processed
},
@@ -53,7 +55,7 @@ impl Actor for PreferenceActor {
from: self.name(),
value: 0,
};
- stream.write_json_packet(&reply);
+ let _ = stream.write_json_packet(&reply);
ActorMessageStatus::Processed
},
diff --git a/components/devtools/actors/process.rs b/components/devtools/actors/process.rs
index de9a9f96ed1..8b2d54d5ee7 100644
--- a/components/devtools/actors/process.rs
+++ b/components/devtools/actors/process.rs
@@ -4,6 +4,7 @@
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
use crate::protocol::JsonPacketStream;
+use crate::StreamId;
use serde_json::{Map, Value};
use std::net::TcpStream;
@@ -34,6 +35,7 @@ impl Actor for ProcessActor {
msg_type: &str,
_msg: &Map<String, Value>,
stream: &mut TcpStream,
+ _id: StreamId,
) -> Result<ActorMessageStatus, ()> {
Ok(match msg_type {
"listWorkers" => {
@@ -41,7 +43,7 @@ impl Actor for ProcessActor {
from: self.name(),
workers: vec![],
};
- stream.write_json_packet(&reply);
+ let _ = stream.write_json_packet(&reply);
ActorMessageStatus::Processed
},
diff --git a/components/devtools/actors/profiler.rs b/components/devtools/actors/profiler.rs
index a6aacb66caa..f7d5a338525 100644
--- a/components/devtools/actors/profiler.rs
+++ b/components/devtools/actors/profiler.rs
@@ -3,6 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
+use crate::StreamId;
use serde_json::{Map, Value};
use std::net::TcpStream;
@@ -21,6 +22,7 @@ impl Actor for ProfilerActor {
_msg_type: &str,
_msg: &Map<String, Value>,
_stream: &mut TcpStream,
+ _id: StreamId,
) -> Result<ActorMessageStatus, ()> {
Ok(ActorMessageStatus::Ignored)
}
diff --git a/components/devtools/actors/root.rs b/components/devtools/actors/root.rs
index 1965d973728..1f0ae9cd33e 100644
--- a/components/devtools/actors/root.rs
+++ b/components/devtools/actors/root.rs
@@ -12,6 +12,7 @@ use crate::actors::performance::PerformanceActor;
use crate::actors::tab::{TabDescriptorActor, TabDescriptorActorMsg};
use crate::actors::worker::{WorkerActor, WorkerMsg};
use crate::protocol::{ActorDescription, JsonPacketStream};
+use crate::StreamId;
use serde_json::{Map, Value};
use std::net::TcpStream;
@@ -124,6 +125,7 @@ impl Actor for RootActor {
msg_type: &str,
_msg: &Map<String, Value>,
stream: &mut TcpStream,
+ _id: StreamId,
) -> Result<ActorMessageStatus, ()> {
Ok(match msg_type {
"listAddons" => {
@@ -131,7 +133,7 @@ impl Actor for RootActor {
from: "root".to_owned(),
addons: vec![],
};
- stream.write_json_packet(&actor);
+ let _ = stream.write_json_packet(&actor);
ActorMessageStatus::Processed
},
@@ -144,7 +146,7 @@ impl Actor for RootActor {
isParent: true,
}],
};
- stream.write_json_packet(&reply);
+ let _ = stream.write_json_packet(&reply);
ActorMessageStatus::Processed
},
@@ -157,7 +159,7 @@ impl Actor for RootActor {
isParent: true,
},
};
- stream.write_json_packet(&reply);
+ let _ = stream.write_json_packet(&reply);
ActorMessageStatus::Processed
},
@@ -169,7 +171,7 @@ impl Actor for RootActor {
deviceActor: self.device.clone(),
preferenceActor: self.preference.clone(),
};
- stream.write_json_packet(&actor);
+ let _ = stream.write_json_packet(&actor);
ActorMessageStatus::Processed
},
@@ -188,7 +190,7 @@ impl Actor for RootActor {
})
.collect(),
};
- stream.write_json_packet(&actor);
+ let _ = stream.write_json_packet(&actor);
ActorMessageStatus::Processed
},
@@ -197,7 +199,7 @@ impl Actor for RootActor {
from: self.name(),
registrations: vec![],
};
- stream.write_json_packet(&reply);
+ let _ = stream.write_json_packet(&reply);
ActorMessageStatus::Processed
},
@@ -210,7 +212,7 @@ impl Actor for RootActor {
.map(|name| registry.find::<WorkerActor>(name).encodable())
.collect(),
};
- stream.write_json_packet(&reply);
+ let _ = stream.write_json_packet(&reply);
ActorMessageStatus::Processed
},
@@ -220,7 +222,7 @@ impl Actor for RootActor {
from: self.name(),
tab: tab.encodable(&registry),
};
- stream.write_json_packet(&reply);
+ let _ = stream.write_json_packet(&reply);
ActorMessageStatus::Processed
},
@@ -232,7 +234,7 @@ impl Actor for RootActor {
device: DeviceActor::description(),
},
};
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
diff --git a/components/devtools/actors/stylesheets.rs b/components/devtools/actors/stylesheets.rs
index ccec3a7d30f..141a30ae106 100644
--- a/components/devtools/actors/stylesheets.rs
+++ b/components/devtools/actors/stylesheets.rs
@@ -4,6 +4,7 @@
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
use crate::protocol::JsonPacketStream;
+use crate::StreamId;
use serde_json::{Map, Value};
use std::net::TcpStream;
@@ -27,6 +28,7 @@ impl Actor for StyleSheetsActor {
msg_type: &str,
_msg: &Map<String, Value>,
stream: &mut TcpStream,
+ _id: StreamId,
) -> Result<ActorMessageStatus, ()> {
Ok(match msg_type {
"getStyleSheets" => {
@@ -34,7 +36,7 @@ impl Actor for StyleSheetsActor {
from: self.name(),
styleSheets: vec![],
};
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
diff --git a/components/devtools/actors/tab.rs b/components/devtools/actors/tab.rs
index 1f83d246233..bd2ab331769 100644
--- a/components/devtools/actors/tab.rs
+++ b/components/devtools/actors/tab.rs
@@ -6,6 +6,7 @@ use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
use crate::actors::browsing_context::{BrowsingContextActor, BrowsingContextActorMsg};
use crate::actors::root::RootActor;
use crate::protocol::JsonPacketStream;
+use crate::StreamId;
use serde_json::{Map, Value};
use std::net::TcpStream;
@@ -48,13 +49,14 @@ impl Actor for TabDescriptorActor {
msg_type: &str,
_msg: &Map<String, Value>,
stream: &mut TcpStream,
+ _id: StreamId,
) -> Result<ActorMessageStatus, ()> {
Ok(match msg_type {
"getTarget" => {
let frame = registry
.find::<BrowsingContextActor>(&self.browsing_context_actor)
.encodable();
- stream.write_json_packet(&GetTargetReply {
+ let _ = stream.write_json_packet(&GetTargetReply {
from: self.name(),
frame,
});
diff --git a/components/devtools/actors/thread.rs b/components/devtools/actors/thread.rs
index f0e2f1e98a2..084a7bcf506 100644
--- a/components/devtools/actors/thread.rs
+++ b/components/devtools/actors/thread.rs
@@ -4,6 +4,7 @@
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
use crate::protocol::JsonPacketStream;
+use crate::StreamId;
use serde_json::{Map, Value};
use std::net::TcpStream;
@@ -84,6 +85,7 @@ impl Actor for ThreadActor {
msg_type: &str,
_msg: &Map<String, Value>,
stream: &mut TcpStream,
+ _id: StreamId,
) -> Result<ActorMessageStatus, ()> {
Ok(match msg_type {
"attach" => {
@@ -100,8 +102,8 @@ impl Actor for ThreadActor {
type_: "attached".to_owned(),
},
};
- stream.write_json_packet(&msg);
- stream.write_json_packet(&VoidAttachedReply { from: self.name() });
+ let _ = stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&VoidAttachedReply { from: self.name() });
ActorMessageStatus::Processed
},
@@ -110,8 +112,8 @@ impl Actor for ThreadActor {
from: self.name(),
type_: "resumed".to_owned(),
};
- stream.write_json_packet(&msg);
- stream.write_json_packet(&VoidAttachedReply { from: self.name() });
+ let _ = stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&VoidAttachedReply { from: self.name() });
ActorMessageStatus::Processed
},
@@ -120,12 +122,12 @@ impl Actor for ThreadActor {
from: self.name(),
type_: "interrupted".to_owned(),
};
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
"reconfigure" => {
- stream.write_json_packet(&ReconfigureReply { from: self.name() });
+ let _ = stream.write_json_packet(&ReconfigureReply { from: self.name() });
ActorMessageStatus::Processed
},
@@ -134,7 +136,7 @@ impl Actor for ThreadActor {
from: self.name(),
sources: vec![],
};
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
diff --git a/components/devtools/actors/timeline.rs b/components/devtools/actors/timeline.rs
index 7ed53f9f8d4..b21990ae0b0 100644
--- a/components/devtools/actors/timeline.rs
+++ b/components/devtools/actors/timeline.rs
@@ -6,6 +6,7 @@ use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
use crate::actors::framerate::FramerateActor;
use crate::actors::memory::{MemoryActor, TimelineMemoryReply};
use crate::protocol::JsonPacketStream;
+use crate::StreamId;
use devtools_traits::DevtoolScriptControlMsg;
use devtools_traits::DevtoolScriptControlMsg::{DropTimelineMarkers, SetTimelineMarkers};
use devtools_traits::{PreciseTime, TimelineMarker, TimelineMarkerType};
@@ -14,6 +15,7 @@ use msg::constellation_msg::PipelineId;
use serde::{Serialize, Serializer};
use serde_json::{Map, Value};
use std::cell::RefCell;
+use std::error::Error;
use std::net::TcpStream;
use std::sync::{Arc, Mutex};
use std::thread;
@@ -166,7 +168,9 @@ impl TimelineActor {
while let Ok(Some(marker)) = receiver.try_recv() {
markers.push(emitter.marker(marker));
}
- emitter.send(markers);
+ if emitter.send(markers).is_err() {
+ break;
+ }
thread::sleep(Duration::from_millis(DEFAULT_TIMELINE_DATA_PULL_TIMEOUT));
})
@@ -185,6 +189,7 @@ impl Actor for TimelineActor {
msg_type: &str,
msg: &Map<String, Value>,
stream: &mut TcpStream,
+ _id: StreamId,
) -> Result<ActorMessageStatus, ()> {
Ok(match msg_type {
"start" => {
@@ -199,6 +204,7 @@ impl Actor for TimelineActor {
))
.unwrap();
+ //TODO: support multiple connections by using root actor's streams instead.
*self.stream.borrow_mut() = stream.try_clone().ok();
// init memory actor
@@ -235,7 +241,7 @@ impl Actor for TimelineActor {
from: self.name(),
value: HighResolutionStamp::new(registry.start_stamp(), PreciseTime::now()),
};
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
@@ -245,7 +251,7 @@ impl Actor for TimelineActor {
value: HighResolutionStamp::new(registry.start_stamp(), PreciseTime::now()),
};
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
self.script_sender
.send(DropTimelineMarkers(
self.pipeline,
@@ -253,6 +259,7 @@ impl Actor for TimelineActor {
))
.unwrap();
+ //TODO: move this to the cleanup method.
if let Some(ref actor_name) = *self.framerate_actor.borrow() {
registry.drop_actor_later(actor_name.clone());
}
@@ -272,7 +279,7 @@ impl Actor for TimelineActor {
value: self.is_recording.lock().unwrap().clone(),
};
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
@@ -311,7 +318,7 @@ impl Emitter {
}
}
- fn send(&mut self, markers: Vec<TimelineMarkerReply>) {
+ fn send(&mut self, markers: Vec<TimelineMarkerReply>) -> Result<(), Box<dyn Error>> {
let end_time = PreciseTime::now();
let reply = MarkersEmitterReply {
type_: "markers".to_owned(),
@@ -319,7 +326,7 @@ impl Emitter {
from: self.from.clone(),
endTime: HighResolutionStamp::new(self.start_stamp, end_time),
};
- self.stream.write_json_packet(&reply);
+ self.stream.write_json_packet(&reply)?;
if let Some(ref actor_name) = self.framerate_actor {
let mut lock = self.registry.lock();
@@ -331,7 +338,7 @@ impl Emitter {
delta: HighResolutionStamp::new(self.start_stamp, end_time),
timestamps: framerate_actor.take_pending_ticks(),
};
- self.stream.write_json_packet(&framerateReply);
+ self.stream.write_json_packet(&framerateReply)?;
}
if let Some(ref actor_name) = self.memory_actor {
@@ -343,7 +350,9 @@ impl Emitter {
delta: HighResolutionStamp::new(self.start_stamp, end_time),
measurement: memory_actor.measure(),
};
- self.stream.write_json_packet(&memoryReply);
+ self.stream.write_json_packet(&memoryReply)?;
}
+
+ Ok(())
}
}
diff --git a/components/devtools/actors/worker.rs b/components/devtools/actors/worker.rs
index fd578d0d3dc..cf7b26448fa 100644
--- a/components/devtools/actors/worker.rs
+++ b/components/devtools/actors/worker.rs
@@ -4,6 +4,7 @@
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
use crate::protocol::JsonPacketStream;
+use crate::StreamId;
use devtools_traits::DevtoolScriptControlMsg::WantsLiveNotifications;
use devtools_traits::{DevtoolScriptControlMsg, WorkerId};
use ipc_channel::ipc::IpcSender;
@@ -11,6 +12,7 @@ use msg::constellation_msg::TEST_PIPELINE_ID;
use serde_json::{Map, Value};
use servo_url::ServoUrl;
use std::cell::RefCell;
+use std::collections::HashMap;
use std::net::TcpStream;
#[derive(Clone, Copy)]
@@ -21,7 +23,7 @@ pub enum WorkerType {
Service = 2,
}
-pub struct WorkerActor {
+pub(crate) struct WorkerActor {
pub name: String,
pub console: String,
pub thread: String,
@@ -29,7 +31,7 @@ pub struct WorkerActor {
pub url: ServoUrl,
pub type_: WorkerType,
pub script_chan: IpcSender<DevtoolScriptControlMsg>,
- pub streams: RefCell<Vec<TcpStream>>,
+ pub streams: RefCell<HashMap<StreamId, TcpStream>>,
}
impl WorkerActor {
@@ -58,6 +60,7 @@ impl Actor for WorkerActor {
msg_type: &str,
_msg: &Map<String, Value>,
stream: &mut TcpStream,
+ id: StreamId,
) -> Result<ActorMessageStatus, ()> {
Ok(match msg_type {
"attach" => {
@@ -66,8 +69,12 @@ impl Actor for WorkerActor {
type_: "attached".to_owned(),
url: self.url.as_str().to_owned(),
};
- self.streams.borrow_mut().push(stream.try_clone().unwrap());
- stream.write_json_packet(&msg);
+ if stream.write_json_packet(&msg).is_err() {
+ return Ok(ActorMessageStatus::Processed);
+ }
+ self.streams
+ .borrow_mut()
+ .insert(id, stream.try_clone().unwrap());
// FIXME: fix messages to not require forging a pipeline for worker messages
self.script_chan
.send(WantsLiveNotifications(TEST_PIPELINE_ID, true))
@@ -82,7 +89,7 @@ impl Actor for WorkerActor {
threadActor: self.thread.clone(),
consoleActor: self.console.clone(),
};
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
@@ -91,18 +98,23 @@ impl Actor for WorkerActor {
from: self.name(),
type_: "detached".to_string(),
};
- // FIXME: we should ensure we're removing the correct stream.
- self.streams.borrow_mut().pop();
- stream.write_json_packet(&msg);
- self.script_chan
- .send(WantsLiveNotifications(TEST_PIPELINE_ID, false))
- .unwrap();
+ let _ = stream.write_json_packet(&msg);
+ self.cleanup(id);
ActorMessageStatus::Processed
},
_ => ActorMessageStatus::Ignored,
})
}
+
+ fn cleanup(&self, id: StreamId) {
+ self.streams.borrow_mut().remove(&id);
+ if self.streams.borrow().is_empty() {
+ self.script_chan
+ .send(WantsLiveNotifications(TEST_PIPELINE_ID, false))
+ .unwrap();
+ }
+ }
}
#[derive(Serialize)]
diff --git a/components/devtools/lib.rs b/components/devtools/lib.rs
index 62238c656ee..28c6675da42 100644
--- a/components/devtools/lib.rs
+++ b/components/devtools/lib.rs
@@ -127,6 +127,9 @@ pub fn start_server(port: u16, embedder: EmbedderProxy) -> Sender<DevtoolsContro
sender
}
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+pub(crate) struct StreamId(u32);
+
fn run_server(
sender: Sender<DevtoolsControlMsg>,
receiver: Receiver<DevtoolsControlMsg>,
@@ -188,22 +191,25 @@ fn run_server(
let mut actor_workers: HashMap<WorkerId, String> = HashMap::new();
/// Process the input from a single devtools client until EOF.
- fn handle_client(actors: Arc<Mutex<ActorRegistry>>, mut stream: TcpStream) {
+ fn handle_client(actors: Arc<Mutex<ActorRegistry>>, mut stream: TcpStream, id: StreamId) {
debug!("connection established to {}", stream.peer_addr().unwrap());
{
let actors = actors.lock().unwrap();
let msg = actors.find::<RootActor>("root").encodable();
- stream.write_json_packet(&msg);
+ if let Err(e) = stream.write_json_packet(&msg) {
+ warn!("Error writing response: {:?}", e);
+ return;
+ }
}
'outer: loop {
match stream.read_json_packet() {
Ok(Some(json_packet)) => {
- if let Err(()) = actors
- .lock()
- .unwrap()
- .handle_message(json_packet.as_object().unwrap(), &mut stream)
- {
+ if let Err(()) = actors.lock().unwrap().handle_message(
+ json_packet.as_object().unwrap(),
+ &mut stream,
+ id,
+ ) {
debug!("error: devtools actor stopped responding");
let _ = stream.shutdown(Shutdown::Both);
break 'outer;
@@ -219,6 +225,8 @@ fn run_server(
},
}
}
+
+ actors.lock().unwrap().cleanup(id);
}
fn handle_framerate_tick(actors: Arc<Mutex<ActorRegistry>>, actor_name: String, tick: f64) {
@@ -451,7 +459,7 @@ fn run_server(
eventActor: actor.event_actor(),
};
for stream in &mut connections {
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
}
},
NetworkEvent::HttpResponse(httpresponse) => {
@@ -464,7 +472,7 @@ fn run_server(
updateType: "requestHeaders".to_owned(),
};
for stream in &mut connections {
- stream.write_merged_json_packet(&msg, &actor.request_headers());
+ let _ = stream.write_merged_json_packet(&msg, &actor.request_headers());
}
let msg = NetworkEventUpdateMsg {
@@ -473,7 +481,7 @@ fn run_server(
updateType: "requestCookies".to_owned(),
};
for stream in &mut connections {
- stream.write_merged_json_packet(&msg, &actor.request_cookies());
+ let _ = stream.write_merged_json_packet(&msg, &actor.request_cookies());
}
//Send a networkEventUpdate (responseStart) to the client
@@ -485,7 +493,7 @@ fn run_server(
};
for stream in &mut connections {
- stream.write_json_packet(&msg);
+ let _ = stream.write_json_packet(&msg);
}
let msg = NetworkEventUpdateMsg {
from: netevent_actor_name.clone(),
@@ -496,7 +504,7 @@ fn run_server(
totalTime: actor.total_time(),
};
for stream in &mut connections {
- stream.write_merged_json_packet(&msg, &extra);
+ let _ = stream.write_merged_json_packet(&msg, &extra);
}
let msg = NetworkEventUpdateMsg {
@@ -508,7 +516,7 @@ fn run_server(
state: "insecure".to_owned(),
};
for stream in &mut connections {
- stream.write_merged_json_packet(&msg, &extra);
+ let _ = stream.write_merged_json_packet(&msg, &extra);
}
let msg = NetworkEventUpdateMsg {
@@ -517,7 +525,7 @@ fn run_server(
updateType: "responseContent".to_owned(),
};
for stream in &mut connections {
- stream.write_merged_json_packet(&msg, &actor.response_content());
+ let _ = stream.write_merged_json_packet(&msg, &actor.response_content());
}
let msg = NetworkEventUpdateMsg {
@@ -526,7 +534,7 @@ fn run_server(
updateType: "responseCookies".to_owned(),
};
for stream in &mut connections {
- stream.write_merged_json_packet(&msg, &actor.response_cookies());
+ let _ = stream.write_merged_json_packet(&msg, &actor.response_cookies());
}
let msg = NetworkEventUpdateMsg {
@@ -535,7 +543,7 @@ fn run_server(
updateType: "responseHeaders".to_owned(),
};
for stream in &mut connections {
- stream.write_merged_json_packet(&msg, &actor.response_headers());
+ let _ = stream.write_merged_json_packet(&msg, &actor.response_headers());
}
},
}
@@ -583,15 +591,18 @@ fn run_server(
})
.expect("Thread spawning failed");
+ let mut next_id = StreamId(0);
while let Ok(msg) = receiver.recv() {
debug!("{:?}", msg);
match msg {
DevtoolsControlMsg::FromChrome(ChromeToDevtoolsControlMsg::AddClient(stream)) => {
let actors = actors.clone();
+ let id = next_id;
+ next_id = StreamId(id.0 + 1);
accepted_connections.push(stream.try_clone().unwrap());
thread::Builder::new()
.name("DevtoolsClientHandler".to_owned())
- .spawn(move || handle_client(actors, stream.try_clone().unwrap()))
+ .spawn(move || handle_client(actors, stream.try_clone().unwrap(), id))
.expect("Thread spawning failed");
},
DevtoolsControlMsg::FromScript(ScriptToDevtoolsControlMsg::FramerateTick(
diff --git a/components/devtools/protocol.rs b/components/devtools/protocol.rs
index 29fbaa2beeb..b01c982a762 100644
--- a/components/devtools/protocol.rs
+++ b/components/devtools/protocol.rs
@@ -8,6 +8,7 @@
use serde::Serialize;
use serde_json::{self, Value};
+use std::error::Error;
use std::io::{Read, Write};
use std::net::TcpStream;
@@ -26,29 +27,38 @@ pub struct Method {
}
pub trait JsonPacketStream {
- fn write_json_packet<T: Serialize>(&mut self, obj: &T);
- fn write_merged_json_packet<T: Serialize, U: Serialize>(&mut self, base: &T, extra: &U);
+ fn write_json_packet<T: Serialize>(&mut self, obj: &T) -> Result<(), Box<dyn Error>>;
+ fn write_merged_json_packet<T: Serialize, U: Serialize>(
+ &mut self,
+ base: &T,
+ extra: &U,
+ ) -> Result<(), Box<dyn Error>>;
fn read_json_packet(&mut self) -> Result<Option<Value>, String>;
}
impl JsonPacketStream for TcpStream {
- fn write_json_packet<T: Serialize>(&mut self, obj: &T) {
- let s = serde_json::to_string(obj).unwrap();
+ fn write_json_packet<T: Serialize>(&mut self, obj: &T) -> Result<(), Box<dyn Error>> {
+ let s = serde_json::to_string(obj)?;
debug!("<- {}", s);
- write!(self, "{}:{}", s.len(), s).unwrap();
+ write!(self, "{}:{}", s.len(), s)?;
+ Ok(())
}
- fn write_merged_json_packet<T: Serialize, U: Serialize>(&mut self, base: &T, extra: &U) {
- let mut obj = serde_json::to_value(base).unwrap();
+ fn write_merged_json_packet<T: Serialize, U: Serialize>(
+ &mut self,
+ base: &T,
+ extra: &U,
+ ) -> Result<(), Box<dyn Error>> {
+ let mut obj = serde_json::to_value(base)?;
let obj = obj.as_object_mut().unwrap();
- let extra = serde_json::to_value(extra).unwrap();
+ let extra = serde_json::to_value(extra)?;
let extra = extra.as_object().unwrap();
for (key, value) in extra {
obj.insert(key.to_owned(), value.to_owned());
}
- self.write_json_packet(obj);
+ self.write_json_packet(obj)
}
fn read_json_packet(&mut self) -> Result<Option<Value>, String> {
@@ -74,7 +84,9 @@ impl JsonPacketStream for TcpStream {
Err(_) => return Err("packet length missing / not parsable".to_owned()),
};
let mut packet = String::new();
- self.take(packet_len).read_to_string(&mut packet).unwrap();
+ self.take(packet_len)
+ .read_to_string(&mut packet)
+ .map_err(|e| e.to_string())?;
debug!("{}", packet);
return match serde_json::from_str(&packet) {
Ok(json) => Ok(Some(json)),
diff --git a/components/script/dom/mediasession.rs b/components/script/dom/mediasession.rs
index f77efe3f54f..49112ba921b 100644
--- a/components/script/dom/mediasession.rs
+++ b/components/script/dom/mediasession.rs
@@ -20,7 +20,7 @@ use crate::dom::bindings::str::DOMString;
use crate::dom::htmlmediaelement::HTMLMediaElement;
use crate::dom::mediametadata::MediaMetadata;
use crate::dom::window::Window;
-use crate::realms::{AlreadyInRealm, InRealm};
+use crate::realms::{enter_realm, InRealm};
use dom_struct::dom_struct;
use embedder_traits::MediaMetadata as EmbedderMediaMetadata;
use embedder_traits::MediaSessionEvent;
@@ -80,8 +80,8 @@ impl MediaSession {
if let Some(media) = self.media_instance.get() {
match action {
MediaSessionActionType::Play => {
- let in_realm_proof = AlreadyInRealm::assert(&self.global());
- media.Play(InRealm::Already(&in_realm_proof));
+ let realm = enter_realm(self);
+ media.Play(InRealm::Entered(&realm));
},
MediaSessionActionType::Pause => {
media.Pause();
diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs
index 76ed789e8ad..a4d27057446 100644
--- a/components/script/dom/mod.rs
+++ b/components/script/dom/mod.rs
@@ -614,6 +614,7 @@ pub mod xrinputsourceschangeevent;
pub mod xrjointpose;
pub mod xrjointspace;
pub mod xrlayer;
+pub mod xrlayerevent;
pub mod xrmediabinding;
pub mod xrpose;
pub mod xrprojectionlayer;
diff --git a/components/script/dom/webglframebuffer.rs b/components/script/dom/webglframebuffer.rs
index 9539ac90507..8172b1b6c4e 100644
--- a/components/script/dom/webglframebuffer.rs
+++ b/components/script/dom/webglframebuffer.rs
@@ -205,6 +205,9 @@ impl WebGLFramebuffer {
}
pub fn is_deleted(&self) -> bool {
+ // TODO: if a framebuffer has an attachment which is invalid due to
+ // being outside a webxr rAF, should this make the framebuffer invalid?
+ // https://github.com/immersive-web/layers/issues/196
self.is_deleted.get()
}
@@ -447,6 +450,9 @@ impl WebGLFramebuffer {
} else {
self.status.get()
}
+ // TODO: if a framebuffer has an attachment which is invalid due to
+ // being outside a webxr rAF, should this make the framebuffer incomplete?
+ // https://github.com/immersive-web/layers/issues/196
}
pub fn check_status_for_rendering(&self) -> CompleteForRendering {
@@ -497,6 +503,10 @@ impl WebGLFramebuffer {
self.is_initialized.set(true);
}
+ // TODO: if a framebuffer has an attachment which is invalid due to
+ // being outside a webxr rAF, should this make the framebuffer incomplete?
+ // https://github.com/immersive-web/layers/issues/196
+
CompleteForRendering::Complete
}
diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs
index 168d31fdf5d..9ef96b1cd19 100644
--- a/components/script/dom/webglrenderingcontext.rs
+++ b/components/script/dom/webglrenderingcontext.rs
@@ -3563,7 +3563,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
fn IsTexture(&self, texture: Option<&WebGLTexture>) -> bool {
texture.map_or(false, |tex| {
- self.validate_ownership(tex).is_ok() && tex.target().is_some() && !tex.is_deleted()
+ self.validate_ownership(tex).is_ok() && tex.target().is_some() && !tex.is_invalid()
})
}
diff --git a/components/script/dom/webgltexture.rs b/components/script/dom/webgltexture.rs
index 02cedeb5755..7456f772dec 100644
--- a/components/script/dom/webgltexture.rs
+++ b/components/script/dom/webgltexture.rs
@@ -9,11 +9,13 @@ use crate::dom::bindings::codegen::Bindings::EXTTextureFilterAnisotropicBinding:
use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebGL2RenderingContextConstants as constants;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
+use crate::dom::bindings::root::Dom;
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
use crate::dom::webgl_validations::types::TexImageTarget;
use crate::dom::webglframebuffer::WebGLFramebuffer;
use crate::dom::webglobject::WebGLObject;
use crate::dom::webglrenderingcontext::{Operation, WebGLRenderingContext};
+use crate::dom::xrsession::XRSession;
use canvas_traits::webgl::{
webgl_channel, TexDataType, TexFormat, TexParameter, TexParameterBool, TexParameterInt,
WebGLResult, WebGLTextureId,
@@ -31,10 +33,11 @@ pub enum TexParameterValue {
// Textures generated for WebXR are owned by the WebXR device, not by the WebGL thread
// so the GL texture should not be deleted when the texture is garbage collected.
-#[derive(Clone, Copy, Debug, Eq, JSTraceable, MallocSizeOf, PartialEq)]
+#[unrooted_must_root_lint::must_root]
+#[derive(JSTraceable, MallocSizeOf)]
enum WebGLTextureOwner {
WebGL,
- WebXR,
+ WebXR(Dom<XRSession>),
}
const MAX_LEVEL_COUNT: usize = 31;
@@ -71,14 +74,16 @@ impl WebGLTexture {
fn new_inherited(
context: &WebGLRenderingContext,
id: WebGLTextureId,
- owner: WebGLTextureOwner,
+ owner: Option<&XRSession>,
) -> Self {
Self {
webgl_object: WebGLObject::new_inherited(context),
id: id,
target: Cell::new(None),
is_deleted: Cell::new(false),
- owner: owner,
+ owner: owner
+ .map(|session| WebGLTextureOwner::WebXR(Dom::from_ref(session)))
+ .unwrap_or(WebGLTextureOwner::WebGL),
immutable_levels: Cell::new(None),
face_count: Cell::new(0),
base_mipmap_level: 0,
@@ -101,22 +106,18 @@ impl WebGLTexture {
pub fn new(context: &WebGLRenderingContext, id: WebGLTextureId) -> DomRoot<Self> {
reflect_dom_object(
- Box::new(WebGLTexture::new_inherited(
- context,
- id,
- WebGLTextureOwner::WebGL,
- )),
+ Box::new(WebGLTexture::new_inherited(context, id, None)),
&*context.global(),
)
}
- pub fn new_webxr(context: &WebGLRenderingContext, id: WebGLTextureId) -> DomRoot<Self> {
+ pub fn new_webxr(
+ context: &WebGLRenderingContext,
+ id: WebGLTextureId,
+ session: &XRSession,
+ ) -> DomRoot<Self> {
reflect_dom_object(
- Box::new(WebGLTexture::new_inherited(
- context,
- id,
- WebGLTextureOwner::WebXR,
- )),
+ Box::new(WebGLTexture::new_inherited(context, id, Some(session))),
&*context.global(),
)
}
@@ -129,7 +130,7 @@ impl WebGLTexture {
// NB: Only valid texture targets come here
pub fn bind(&self, target: u32) -> WebGLResult<()> {
- if self.is_deleted.get() {
+ if self.is_invalid() {
return Err(WebGLError::InvalidOperation);
}
@@ -246,7 +247,7 @@ impl WebGLTexture {
}
// We don't delete textures owned by WebXR
- if self.owner == WebGLTextureOwner::WebXR {
+ if let WebGLTextureOwner::WebXR(_) = self.owner {
return;
}
@@ -258,7 +259,13 @@ impl WebGLTexture {
}
}
- pub fn is_deleted(&self) -> bool {
+ pub fn is_invalid(&self) -> bool {
+ // https://immersive-web.github.io/layers/#xrwebglsubimagetype
+ if let WebGLTextureOwner::WebXR(ref session) = self.owner {
+ if session.is_outside_raf() {
+ return true;
+ }
+ }
self.is_deleted.get()
}
diff --git a/components/script/dom/webidls/XRLayerEvent.webidl b/components/script/dom/webidls/XRLayerEvent.webidl
index c90b9bfb27b..9a05272138e 100644
--- a/components/script/dom/webidls/XRLayerEvent.webidl
+++ b/components/script/dom/webidls/XRLayerEvent.webidl
@@ -3,12 +3,11 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
// https://immersive-web.github.io/layers/#xrlayerevent-interface
-
-// [SecureContext, Exposed=Window]
-// interface XRLayerEvent : Event {
-// constructor(DOMString type, XRLayerEventInit eventInitDict);
-// [SameObject] readonly attribute XRLayer layer;
-// };
+[SecureContext, Exposed=Window, Pref="dom.webxr.layers.enabled"]
+interface XRLayerEvent : Event {
+ constructor(DOMString type, XRLayerEventInit eventInitDict);
+ [SameObject] readonly attribute XRLayer layer;
+};
dictionary XRLayerEventInit : EventInit {
required XRLayer layer;
diff --git a/components/script/dom/xrlayerevent.rs b/components/script/dom/xrlayerevent.rs
new file mode 100644
index 00000000000..d3485fa1c51
--- /dev/null
+++ b/components/script/dom/xrlayerevent.rs
@@ -0,0 +1,62 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+use crate::dom::bindings::codegen::Bindings::EventBinding::EventBinding::EventMethods;
+use crate::dom::bindings::codegen::Bindings::XRLayerEventBinding::XRLayerEventInit;
+use crate::dom::bindings::codegen::Bindings::XRLayerEventBinding::XRLayerEventMethods;
+use crate::dom::bindings::reflector::reflect_dom_object;
+use crate::dom::bindings::root::Dom;
+use crate::dom::bindings::root::DomRoot;
+use crate::dom::bindings::str::DOMString;
+use crate::dom::event::Event;
+use crate::dom::window::Window;
+use crate::dom::xrlayer::XRLayer;
+use dom_struct::dom_struct;
+use servo_atoms::Atom;
+
+// https://w3c.github.io/uievents/#interface-uievent
+#[dom_struct]
+pub struct XRLayerEvent {
+ event: Event,
+ layer: Dom<XRLayer>,
+}
+
+impl XRLayerEvent {
+ pub fn new_inherited(layer: &XRLayer) -> XRLayerEvent {
+ XRLayerEvent {
+ event: Event::new_inherited(),
+ layer: Dom::from_ref(layer),
+ }
+ }
+
+ pub fn new(window: &Window, layer: &XRLayer) -> DomRoot<XRLayerEvent> {
+ reflect_dom_object(Box::new(XRLayerEvent::new_inherited(layer)), window)
+ }
+
+ #[allow(non_snake_case)]
+ pub fn Constructor(
+ window: &Window,
+ type_: DOMString,
+ init: &XRLayerEventInit,
+ ) -> DomRoot<XRLayerEvent> {
+ let event = XRLayerEvent::new(window, &init.layer);
+ let type_ = Atom::from(type_);
+ let bubbles = init.parent.bubbles;
+ let cancelable = init.parent.cancelable;
+ event.event.init_event(type_, bubbles, cancelable);
+ event
+ }
+}
+
+impl XRLayerEventMethods for XRLayerEvent {
+ // https://immersive-web.github.io/layers/#dom-xrlayerevent-layer
+ fn Layer(&self) -> DomRoot<XRLayer> {
+ DomRoot::from_ref(&self.layer)
+ }
+
+ // https://dom.spec.whatwg.org/#dom-event-istrusted
+ fn IsTrusted(&self) -> bool {
+ self.event.IsTrusted()
+ }
+}
diff --git a/components/script/dom/xrwebgllayer.rs b/components/script/dom/xrwebgllayer.rs
index 7f0a7883961..dd1e4eff57f 100644
--- a/components/script/dom/xrwebgllayer.rs
+++ b/components/script/dom/xrwebgllayer.rs
@@ -193,10 +193,11 @@ impl XRWebGLLayer {
let framebuffer = self.framebuffer.as_ref()?;
let context = framebuffer.upcast::<WebGLObject>().context();
let sub_images = frame.get_sub_images(self.layer_id()?)?;
+ let session = self.session();
// TODO: Cache this texture
let color_texture_id =
WebGLTextureId::maybe_new(sub_images.sub_image.as_ref()?.color_texture)?;
- let color_texture = WebGLTexture::new_webxr(context, color_texture_id);
+ let color_texture = WebGLTexture::new_webxr(context, color_texture_id, session);
let target = self.texture_target();
// Save the current bindings
@@ -230,7 +231,8 @@ impl XRWebGLLayer {
if let Some(id) = sub_images.sub_image.as_ref()?.depth_stencil_texture {
// TODO: Cache this texture
let depth_stencil_texture_id = WebGLTextureId::maybe_new(id)?;
- let depth_stencil_texture = WebGLTexture::new_webxr(context, depth_stencil_texture_id);
+ let depth_stencil_texture =
+ WebGLTexture::new_webxr(context, depth_stencil_texture_id, session);
framebuffer
.texture2d_even_if_opaque(
constants::DEPTH_STENCIL_ATTACHMENT,
diff --git a/components/servo/lib.rs b/components/servo/lib.rs
index 2bcc5694074..09e6a3ef078 100644
--- a/components/servo/lib.rs
+++ b/components/servo/lib.rs
@@ -144,9 +144,8 @@ mod media_platform {
#[cfg(feature = "uwp")]
fn set_gstreamer_log_handler() {
- use gstreamer::{debug_add_log_function, debug_remove_default_log_function, DebugLevel};
+ use gstreamer::{debug_add_log_function, DebugLevel};
- debug_remove_default_log_function();
debug_add_log_function(|cat, level, file, function, line, _, message| {
let message = format!(
"{:?} {:?} {:?}:{:?}:{:?} {:?}",
diff --git a/components/webrender_surfman/Cargo.toml b/components/webrender_surfman/Cargo.toml
index 82ae827cbb7..663b30be7b1 100644
--- a/components/webrender_surfman/Cargo.toml
+++ b/components/webrender_surfman/Cargo.toml
@@ -13,5 +13,5 @@ path = "lib.rs"
[dependencies]
euclid = "0.20"
surfman = "0.3"
-surfman-chains = "0.4"
+surfman-chains = "0.5"
diff --git a/components/webrender_surfman/lib.rs b/components/webrender_surfman/lib.rs
index 530ca0ebfc7..533614256c1 100644
--- a/components/webrender_surfman/lib.rs
+++ b/components/webrender_surfman/lib.rs
@@ -147,7 +147,7 @@ impl WebrenderSurfman {
let ref mut device = self.0.device.borrow_mut();
let ref mut context = self.0.context.borrow_mut();
if let Some(ref swap_chain) = self.0.swap_chain {
- return swap_chain.swap_buffers(device, context);
+ return swap_chain.swap_buffers(device, context, surfman_chains::PreserveBuffer::No);
}
let mut surface = device.unbind_surface_from_context(context)?.unwrap();
device.present_surface(context, &mut surface)?;
diff --git a/ports/gstplugin/Cargo.toml b/ports/gstplugin/Cargo.toml
index 05816b4e629..4ad10399c0d 100644
--- a/ports/gstplugin/Cargo.toml
+++ b/ports/gstplugin/Cargo.toml
@@ -30,7 +30,7 @@ log = "0.4"
servo-media = { git = "https://github.com/servo/media" }
sparkle = "0.1"
surfman = "0.3"
-surfman-chains = "0.4"
+surfman-chains = "0.5"
surfman-chains-api = "0.2"
webxr = { git = "https://github.com/servo/webxr", features = ["glwindow"] }
diff --git a/python/servo/command_base.py b/python/servo/command_base.py
index f25721a5652..d1ed5271b67 100644
--- a/python/servo/command_base.py
+++ b/python/servo/command_base.py
@@ -864,6 +864,7 @@ install them, let us know by filing a bug!")
not target
or ("armv7" in target and "android" in target)
or "x86_64" in target
+ or "uwp" in target
):
media_stack = "gstreamer"
else:
diff --git a/support/hololens/ServoApp/BrowserPage.cpp b/support/hololens/ServoApp/BrowserPage.cpp
index d3f738427c6..42282357834 100644
--- a/support/hololens/ServoApp/BrowserPage.cpp
+++ b/support/hololens/ServoApp/BrowserPage.cpp
@@ -16,6 +16,7 @@ using namespace winrt::Windows::UI::Core;
using namespace winrt::Windows::UI::ViewManagement;
using namespace winrt::Windows::ApplicationModel::Core;
using namespace winrt::Windows::ApplicationModel::Resources;
+using namespace winrt::Windows::ApplicationModel::Resources::Core;
using namespace winrt::Windows::UI::Notifications;
using namespace winrt::Windows::Data::Json;
using namespace winrt::Windows::Data::Xml::Dom;
@@ -28,6 +29,17 @@ BrowserPage::BrowserPage() {
InitializeComponent();
BindServoEvents();
mLogs = winrt::single_threaded_observable_vector<IInspectable>();
+
+ auto ctx = ResourceContext::GetForCurrentView();
+ auto current = ResourceManager::Current();
+ auto tree = current.MainResourceMap().GetSubtree(L"PromotedPrefs");
+ for (auto s : tree) {
+ hstring k = s.Key();
+ std::wstring wk = k.c_str();
+ std::replace(wk.begin(), wk.end(), '/', '.');
+ hstring v = s.Value().Resolve(ctx).ValueAsString();
+ mPromotedPrefs.insert(std::pair(wk, v));
+ }
}
void BrowserPage::BindServoEvents() {
@@ -69,6 +81,8 @@ void BrowserPage::BindServoEvents() {
urlTextbox().GotFocus(std::bind(&BrowserPage::OnURLFocused, this, _1));
servoView().OnMediaSessionMetadata(
[=](hstring title, hstring artist, hstring album) {});
+ servoView().OnMediaSessionPosition(
+ [=](double duration, double position, double rate) {});
servoView().OnMediaSessionPlaybackStateChange([=](const auto &, int state) {
if (state == Servo::MediaSessionPlaybackState::None) {
mediaControls().Visibility(Visibility::Collapsed);
@@ -182,17 +196,34 @@ void BrowserPage::UpdatePref(ServoApp::Pref pref, Controls::Control ctrl) {
stack.Children().GetAt(2).as<Controls::Button>().IsEnabled(!pref.IsDefault());
}
+void BrowserPage::OnSeeAllPrefClicked(IInspectable const &,
+ RoutedEventArgs const &) {
+ BuildPrefList();
+}
+
// Retrieve the preference list from Servo and build the preference table.
void BrowserPage::BuildPrefList() {
+ prefList().Children().Clear();
+ bool promoted = !seeAllPrefCheckBox().IsChecked().GetBoolean();
+ preferenceSearchbox().Visibility(promoted ? Visibility::Collapsed
+ : Visibility::Visible);
+ preferenceSearchbox().Text(L"");
// It would be better to use a template and bindings, but the
// <ListView> takes too long to generate all the items, and
// it's pretty difficiult to have different controls depending
// on the pref type.
- prefList().Children().Clear();
auto resourceLoader = ResourceLoader::GetForCurrentView();
auto resetStr =
resourceLoader.GetString(L"devtoolsPreferenceResetButton/Content");
for (auto pref : servoView().Preferences()) {
+ std::optional<hstring> description = {};
+ if (promoted) {
+ auto search = mPromotedPrefs.find(pref.Key());
+ if (search == mPromotedPrefs.end()) {
+ continue;
+ }
+ description = {search->second};
+ }
auto value = pref.Value();
auto type = value.as<IPropertyValue>().Type();
std::optional<Controls::Control> ctrl;
@@ -243,7 +274,7 @@ void BrowserPage::BuildPrefList() {
stack.Padding({4, 4, 4, 4});
stack.Orientation(Controls::Orientation::Horizontal);
auto key = Controls::TextBlock();
- key.Text(pref.Key());
+ key.Text(promoted ? *description : pref.Key());
key.Width(350);
if (!pref.IsDefault()) {
auto font = winrt::Windows::UI::Text::FontWeights::Bold();
diff --git a/support/hololens/ServoApp/BrowserPage.h b/support/hololens/ServoApp/BrowserPage.h
index a5ad43b4286..2a434d19354 100644
--- a/support/hololens/ServoApp/BrowserPage.h
+++ b/support/hololens/ServoApp/BrowserPage.h
@@ -34,6 +34,7 @@ public:
void OnDevtoolsButtonClicked(IInspectable const &, RoutedEventArgs const &);
void OnJSInputEdited(IInspectable const &, Input::KeyRoutedEventArgs const &);
void OnURLEdited(IInspectable const &, Input::KeyRoutedEventArgs const &);
+ void OnSeeAllPrefClicked(IInspectable const &, RoutedEventArgs const &);
void OnURLFocused(IInspectable const &);
void
OnURLKeyboardAccelerator(IInspectable const &,
@@ -53,13 +54,13 @@ public:
void ClearConsole();
void OnDevtoolsDetached();
Collections::IObservableVector<IInspectable> ConsoleLogs() { return mLogs; };
+ void BuildPrefList();
private:
void SetTransientMode(bool);
void UpdatePref(ServoApp::Pref, Controls::Control);
void CheckCrashReport();
void BindServoEvents();
- void BuildPrefList();
void ShowToolbox();
void HideToolbox();
DevtoolsStatus mDevtoolsStatus = DevtoolsStatus::Stopped;
@@ -68,6 +69,7 @@ private:
bool mPanicking = false;
std::unique_ptr<servo::DevtoolsClient> mDevtoolsClient;
Collections::IObservableVector<IInspectable> mLogs;
+ std::map<hstring, hstring> mPromotedPrefs;
};
struct ConsoleLog : ConsoleLogT<ConsoleLog> {
diff --git a/support/hololens/ServoApp/BrowserPage.xaml b/support/hololens/ServoApp/BrowserPage.xaml
index d85947b8807..28d6871a3c9 100644
--- a/support/hololens/ServoApp/BrowserPage.xaml
+++ b/support/hololens/ServoApp/BrowserPage.xaml
@@ -192,11 +192,13 @@
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
+ <RowDefinition Height="auto"/>
</Grid.RowDefinitions>
- <TextBox Grid.Row="0" IsTabStop="true" x:Uid="preferenceSearchbox" x:Name="preferenceSearchbox" VerticalAlignment="Center" KeyUp="OnPrefererenceSearchboxEdited" IsSpellCheckEnabled="False" Margin="3"/>
+ <CheckBox Margin="3" x:Name="seeAllPrefCheckBox" x:Uid="seeAllPrefCheckBox" Click="OnSeeAllPrefClicked" IsChecked="False" Grid.Row="0"/>
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto">
<StackPanel x:Name="prefList"/>
</ScrollViewer>
+ <TextBox Grid.Row="2" IsTabStop="true" x:Uid="preferenceSearchbox" x:Name="preferenceSearchbox" VerticalAlignment="Center" KeyUp="OnPrefererenceSearchboxEdited" IsSpellCheckEnabled="False" Margin="3"/>
</Grid>
</muxc:TabViewItem>
<muxc:TabViewItem x:Uid="crashTab" x:Name="crashTab" IsClosable="False" Visibility="Collapsed">
diff --git a/support/hololens/ServoApp/Resources/PromotedPrefs.resw b/support/hololens/ServoApp/Resources/PromotedPrefs.resw
new file mode 100644
index 00000000000..abacabb99fa
--- /dev/null
+++ b/support/hololens/ServoApp/Resources/PromotedPrefs.resw
@@ -0,0 +1,125 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" use="required" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <data name="dom.webxr.hands.enabled"><value>WebXR: Enable articulated hand input</value></data>
+ <data name="dom.webxr.layers.enabled"><value>WebXR: Enable composition layers</value></data>
+ <data name="dom.webxr.sessionavailable"><value>WebXR: Enable "sessionavailable" event</value></data>
+ <data name="dom.webxr.first_person_observer_view"><value>WebXR: Enable first person observer view</value></data>
+ <data name="dom.webgl2.enabled"><value>Enable WebGL2</value></data>
+</root>
diff --git a/support/hololens/ServoApp/Strings/en-US/Resources.resw b/support/hololens/ServoApp/Resources/Strings/en-US/Resources.resw
index 717ffbff23b..2a271eed980 100644
--- a/support/hololens/ServoApp/Strings/en-US/Resources.resw
+++ b/support/hololens/ServoApp/Resources/Strings/en-US/Resources.resw
@@ -171,4 +171,7 @@
<data name="ContextMenu.title" xml:space="preserve">
<value>Menu</value>
</data>
+ <data name="seeAllPrefCheckBox.Content" xml:space="preserve">
+ <value>See all preferences</value>
+ </data>
</root>
diff --git a/support/hololens/ServoApp/Strings/fr-FR/Resources.resw b/support/hololens/ServoApp/Resources/Strings/fr-FR/Resources.resw
index 5fd44dbad16..5fd44dbad16 100644
--- a/support/hololens/ServoApp/Strings/fr-FR/Resources.resw
+++ b/support/hololens/ServoApp/Resources/Strings/fr-FR/Resources.resw
diff --git a/support/hololens/ServoApp/ServoApp.vcxproj b/support/hololens/ServoApp/ServoApp.vcxproj
index c5ec6a5317c..ec28c1d9a27 100644
--- a/support/hololens/ServoApp/ServoApp.vcxproj
+++ b/support/hololens/ServoApp/ServoApp.vcxproj
@@ -87,6 +87,8 @@
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories);$(ProjectDir)\..\..\..\target\aarch64-uwp-windows-msvc\debug\</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories);$(ProjectDir)\..\..\..\target\x86_64-uwp-windows-msvc\debug\</AdditionalIncludeDirectories>
+ <LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">stdcpplatest</LanguageStandard>
+ <LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">OneCore.lib;WindowsApp.lib;%(AdditionalDependencies);simpleservo.dll.lib</AdditionalDependencies>
@@ -105,6 +107,8 @@
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories);$(ProjectDir)\..\..\..\target\aarch64-uwp-windows-msvc\release</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories);$(ProjectDir)\..\..\..\target\x86_64-uwp-windows-msvc\release</AdditionalIncludeDirectories>
+ <LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">stdcpplatest</LanguageStandard>
+ <LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Release|x64'">stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">OneCore.lib;WindowsApp.lib;%(AdditionalDependencies);simpleservo.dll.lib</AdditionalDependencies>
@@ -988,8 +992,9 @@
<None Include="PropertySheet.props" />
</ItemGroup>
<ItemGroup>
- <PRIResource Include="Strings\en-US\Resources.resw" />
- <PRIResource Include="Strings\fr-FR\Resources.resw" />
+ <PRIResource Include="Resources\PromotedPrefs.resw" />
+ <PRIResource Include="Resources\Strings\en-US\Resources.resw" />
+ <PRIResource Include="Resources\Strings\fr-FR\Resources.resw" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
@@ -1009,4 +1014,4 @@
<Error Condition="!Exists('..\packages\ANGLE.WindowsStore.Servo.2.1.19\build\native\ANGLE.WindowsStore.Servo.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\ANGLE.WindowsStore.Servo.2.1.19\build\native\ANGLE.WindowsStore.Servo.targets'))" />
<Error Condition="!Exists('..\packages\Microsoft.UI.Xaml.2.4.2\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.UI.Xaml.2.4.2\build\native\Microsoft.UI.Xaml.targets'))" />
</Target>
-</Project>
+</Project> \ No newline at end of file
diff --git a/support/hololens/ServoApp/ServoApp.vcxproj.filters b/support/hololens/ServoApp/ServoApp.vcxproj.filters
index 0eb6821188e..a017554e1ba 100644
--- a/support/hololens/ServoApp/ServoApp.vcxproj.filters
+++ b/support/hololens/ServoApp/ServoApp.vcxproj.filters
@@ -924,13 +924,16 @@
<Filter Include="ServoControl">
<UniqueIdentifier>{d21a959c-19d1-4a54-b942-692c27e5b3a6}</UniqueIdentifier>
</Filter>
- <Filter Include="Strings">
+ <Filter Include="Resources">
+ <UniqueIdentifier>{c05cce0c-d62c-11ea-87d0-0242ac130003}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resources\Strings">
<UniqueIdentifier>{49e23631-d899-4caf-bf7b-30776fee4d09}</UniqueIdentifier>
</Filter>
- <Filter Include="Strings\en-US">
+ <Filter Include="Resources\Strings\en-US">
<UniqueIdentifier>{c12ff5d4-3730-4a0e-8b16-56ded3138875}</UniqueIdentifier>
</Filter>
- <Filter Include="Strings\fr-FR">
+ <Filter Include="Resources\Strings\fr-FR">
<UniqueIdentifier>{b7d3273d-a27c-4176-87a1-3d5222b796b3}</UniqueIdentifier>
</Filter>
<Filter Include="Devtools">
@@ -950,11 +953,14 @@
<ApplicationDefinition Include="App.xaml" />
</ItemGroup>
<ItemGroup>
- <PRIResource Include="Strings\en-US\Resources.resw">
- <Filter>Strings\en-US</Filter>
+ <PRIResource Include="Resources\PromotedPrefs.resw">
+ <Filter>Resources</Filter>
+ </PRIResource>
+ <PRIResource Include="Resources\Strings\en-US\Resources.resw">
+ <Filter>Resources\Strings\en-US</Filter>
</PRIResource>
- <PRIResource Include="Strings\fr-FR\Resources.resw">
- <Filter>Strings\fr-FR</Filter>
+ <PRIResource Include="Resources\Strings\fr-FR\Resources.resw">
+ <Filter>Resources\Strings\fr-FR</Filter>
</PRIResource>
</ItemGroup>
</Project>
diff --git a/support/hololens/ServoApp/ServoControl/Servo.cpp b/support/hololens/ServoApp/ServoControl/Servo.cpp
index 4e3eeedf981..0cc51903f4b 100644
--- a/support/hololens/ServoApp/ServoControl/Servo.cpp
+++ b/support/hololens/ServoApp/ServoControl/Servo.cpp
@@ -99,6 +99,12 @@ const char *get_clipboard_contents() {
return nullptr;
}
+void on_media_session_set_position_state(double duration, double position,
+ double playback_rate) {
+ return sServo->Delegate().OnServoMediaSessionPosition(duration, position,
+ playback_rate);
+}
+
void on_media_session_metadata(const char *title, const char *album,
const char *artist) {
return sServo->Delegate().OnServoMediaSessionMetadata(
@@ -185,9 +191,18 @@ Servo::Servo(std::optional<hstring> initUrl, hstring args, GLsizei width,
std::vector<capi::CPref> cprefs;
+ // Ensure few things stay in memories long enough as we send raw
+ // pointers to Rust.
+ std::vector<std::unique_ptr<char *>> memChar;
+ std::vector<std::unique_ptr<bool>> memBool;
+ std::vector<std::unique_ptr<int64_t>> memInt;
+ std::vector<std::unique_ptr<double>> memDouble;
+
for (auto pref : prefs.Values()) {
- auto key = *hstring2char(pref.Key());
+ auto charkey = hstring2char(pref.Key());
+ auto key = *charkey.get();
+ memChar.push_back(std::move(charkey));
auto value = pref.Value();
auto type = value.as<Windows::Foundation::IPropertyValue>().Type();
@@ -197,20 +212,24 @@ Servo::Servo(std::optional<hstring> initUrl, hstring args, GLsizei width,
cpref.value = NULL;
if (type == Windows::Foundation::PropertyType::Boolean) {
cpref.pref_type = capi::CPrefType::Bool;
- auto val = unbox_value<bool>(value);
- cpref.value = &val;
+ auto val = std::make_unique<bool>(unbox_value<bool>(value));
+ cpref.value = val.get();
+ memBool.push_back(std::move(val));
} else if (type == Windows::Foundation::PropertyType::String) {
cpref.pref_type = capi::CPrefType::Str;
- auto val = unbox_value<hstring>(value);
- cpref.value = *hstring2char(val);
+ auto val = hstring2char(unbox_value<hstring>(value));
+ cpref.value = *val.get();
+ memChar.push_back(std::move(val));
} else if (type == Windows::Foundation::PropertyType::Int64) {
cpref.pref_type = capi::CPrefType::Int;
- auto val = unbox_value<int64_t>(value);
- cpref.value = &val;
+ auto val = std::make_unique<int64_t>(unbox_value<int64_t>(value));
+ cpref.value = val.get();
+ memInt.push_back(std::move(val));
} else if (type == Windows::Foundation::PropertyType::Double) {
cpref.pref_type = capi::CPrefType::Float;
- auto val = unbox_value<double>(value);
- cpref.value = &val;
+ auto val = std::make_unique<double>(unbox_value<double>(value));
+ cpref.value = val.get();
+ memDouble.push_back(std::move(val));
} else if (type == Windows::Foundation::PropertyType::Empty) {
cpref.pref_type = capi::CPrefType::Missing;
} else {
@@ -268,6 +287,10 @@ Servo::Servo(std::optional<hstring> initUrl, hstring args, GLsizei width,
sServo = this; // FIXME;
auto current = ApplicationData::Current();
+ auto gstLog = std::wstring(current.LocalFolder().Path()) + L"\\gst.log";
+ SetEnvironmentVariable(L"GST_DEBUG_FILE", gstLog.c_str());
+ // SetEnvironmentVariableA("GST_DEBUG", "4");
+
auto filePath = std::wstring(current.LocalFolder().Path()) + L"\\stdout.txt";
sLogHandle =
CreateFile2(filePath.c_str(), GENERIC_WRITE, 0, CREATE_ALWAYS, nullptr);
@@ -283,29 +306,32 @@ Servo::Servo(std::optional<hstring> initUrl, hstring args, GLsizei width,
std::to_string(GetLastError()));
}
- capi::CHostCallbacks c;
- c.on_load_started = &on_load_started;
- c.on_load_ended = &on_load_ended;
- c.on_title_changed = &on_title_changed;
- c.on_url_changed = &on_url_changed;
- c.on_history_changed = &on_history_changed;
- c.on_animating_changed = &on_animating_changed;
- c.on_shutdown_complete = &on_shutdown_complete;
- c.on_allow_navigation = &on_allow_navigation;
- c.on_ime_show = &on_ime_show;
- c.on_ime_hide = &on_ime_hide;
- c.get_clipboard_contents = &get_clipboard_contents;
- c.set_clipboard_contents = &set_clipboard_contents;
- c.on_media_session_metadata = &on_media_session_metadata;
- c.on_media_session_playback_state_change =
- &on_media_session_playback_state_change;
- c.prompt_alert = &prompt_alert;
- c.prompt_ok_cancel = &prompt_ok_cancel;
- c.prompt_yes_no = &prompt_yes_no;
- c.prompt_input = &prompt_input;
- c.on_devtools_started = &on_devtools_started;
- c.show_context_menu = &show_context_menu;
- c.on_log_output = &on_log_output;
+ capi::CHostCallbacks c = capi::CHostCallbacks{
+ .on_load_started = &on_load_started,
+ .on_load_ended = &on_load_ended,
+ .on_title_changed = &on_title_changed,
+ .on_allow_navigation = &on_allow_navigation,
+ .on_url_changed = &on_url_changed,
+ .on_history_changed = &on_history_changed,
+ .on_animating_changed = &on_animating_changed,
+ .on_shutdown_complete = &on_shutdown_complete,
+ .on_ime_show = &on_ime_show,
+ .on_ime_hide = &on_ime_hide,
+ .get_clipboard_contents = &get_clipboard_contents,
+ .set_clipboard_contents = &set_clipboard_contents,
+ .on_media_session_metadata = &on_media_session_metadata,
+ .on_media_session_playback_state_change =
+ &on_media_session_playback_state_change,
+ .on_media_session_set_position_state =
+ &on_media_session_set_position_state,
+ .prompt_alert = &prompt_alert,
+ .prompt_ok_cancel = &prompt_ok_cancel,
+ .prompt_yes_no = &prompt_yes_no,
+ .prompt_input = &prompt_input,
+ .on_devtools_started = &on_devtools_started,
+ .show_context_menu = &show_context_menu,
+ .on_log_output = &on_log_output,
+ };
capi::register_panic_handler(&on_panic);
@@ -364,8 +390,13 @@ void Servo::GoHome() {
ApplicationData::Current().LocalSettings();
auto prefs = localSettings.Containers().Lookup(L"servoUserPrefs");
auto home_pref = prefs.Values().Lookup(L"shell.homepage");
- auto home =
- home_pref ? unbox_value<hstring>(home_pref) : FALLBACK_DEFAULT_URL;
+ auto home = home_pref ? unbox_value<hstring>(home_pref) :
+#ifdef OVERRIDE_DEFAULT_URL
+ OVERRIDE_DEFAULT_URL
+#else
+ FALLBACK_DEFAULT_URL
+#endif
+ ;
LoadUri(home);
}
diff --git a/support/hololens/ServoApp/ServoControl/Servo.h b/support/hololens/ServoApp/ServoControl/Servo.h
index fb2c2f5fb22..e0731ff4876 100644
--- a/support/hololens/ServoApp/ServoControl/Servo.h
+++ b/support/hololens/ServoApp/ServoControl/Servo.h
@@ -124,6 +124,7 @@ public:
virtual void OnServoIMEHide() = 0;
virtual void OnServoDevtoolsStarted(bool, const unsigned int, hstring) = 0;
virtual void OnServoMediaSessionMetadata(hstring, hstring, hstring) = 0;
+ virtual void OnServoMediaSessionPosition(double, double, double) = 0;
virtual void OnServoMediaSessionPlaybackStateChange(int) = 0;
virtual void OnServoPromptAlert(hstring, bool) = 0;
virtual void OnServoShowContextMenu(std::optional<hstring>,
diff --git a/support/hololens/ServoApp/ServoControl/ServoControl.cpp b/support/hololens/ServoApp/ServoControl/ServoControl.cpp
index b2ff048248f..12684efe149 100644
--- a/support/hololens/ServoApp/ServoControl/ServoControl.cpp
+++ b/support/hololens/ServoApp/ServoControl/ServoControl.cpp
@@ -548,6 +548,12 @@ void ServoControl::OnServoIMEShow(hstring text, int32_t x, int32_t y,
});
}
+void ServoControl::OnServoMediaSessionPosition(double duration, double position,
+ double playback_rate) {
+ RunOnUIThread(
+ [=] { mOnMediaSessionPositionEvent(duration, position, playback_rate); });
+}
+
void ServoControl::OnServoMediaSessionMetadata(hstring title, hstring artist,
hstring album) {
RunOnUIThread([=] { mOnMediaSessionMetadataEvent(title, artist, album); });
diff --git a/support/hololens/ServoApp/ServoControl/ServoControl.h b/support/hololens/ServoApp/ServoControl/ServoControl.h
index be1f8090776..8775127e206 100644
--- a/support/hololens/ServoApp/ServoControl/ServoControl.h
+++ b/support/hololens/ServoApp/ServoControl/ServoControl.h
@@ -152,6 +152,14 @@ struct ServoControl : ServoControlT<ServoControl>, public servo::ServoDelegate {
}
winrt::event_token
+ OnMediaSessionPosition(MediaSessionPositionDelegate const &handler) {
+ return mOnMediaSessionPositionEvent.add(handler);
+ };
+ void OnMediaSessionPosition(winrt::event_token const &token) noexcept {
+ mOnMediaSessionPositionEvent.remove(token);
+ }
+
+ winrt::event_token
OnMediaSessionMetadata(MediaSessionMetadataDelegate const &handler) {
return mOnMediaSessionMetadataEvent.add(handler);
};
@@ -187,6 +195,7 @@ struct ServoControl : ServoControlT<ServoControl>, public servo::ServoDelegate {
virtual void OnServoMediaSessionMetadata(winrt::hstring, winrt::hstring,
winrt::hstring);
virtual void OnServoMediaSessionPlaybackStateChange(int);
+ virtual void OnServoMediaSessionPosition(double, double, double);
virtual void OnServoPromptAlert(winrt::hstring, bool);
virtual void OnServoShowContextMenu(std::optional<winrt::hstring>,
std::vector<winrt::hstring>);
@@ -210,6 +219,7 @@ private:
winrt::event<EventDelegate> mOnCaptureGesturesStartedEvent;
winrt::event<EventDelegate> mOnCaptureGesturesEndedEvent;
winrt::event<MediaSessionMetadataDelegate> mOnMediaSessionMetadataEvent;
+ winrt::event<MediaSessionPositionDelegate> mOnMediaSessionPositionEvent;
winrt::event<Windows::Foundation::EventHandler<int>>
mOnMediaSessionPlaybackStateChangeEvent;
diff --git a/support/hololens/ServoApp/ServoControl/ServoControl.idl b/support/hololens/ServoApp/ServoControl/ServoControl.idl
index fe83d535322..72f45354095 100644
--- a/support/hololens/ServoApp/ServoControl/ServoControl.idl
+++ b/support/hololens/ServoApp/ServoControl/ServoControl.idl
@@ -3,6 +3,7 @@ namespace ServoApp {
delegate void EventDelegate();
delegate void HistoryChangedDelegate(Boolean back, Boolean forward);
delegate void MediaSessionMetadataDelegate(String title, String artist, String album);
+ delegate void MediaSessionPositionDelegate(Double duration, Double position, Double rate);
delegate void DevtoolsStatusChangedDelegate(DevtoolsStatus status, UInt32 port, String token);
enum DevtoolsStatus {
@@ -42,6 +43,7 @@ namespace ServoApp {
event Windows.Foundation.EventHandler<String> OnServoPanic;
event Windows.Foundation.EventHandler<String> OnURLChanged;
event MediaSessionMetadataDelegate OnMediaSessionMetadata;
+ event MediaSessionPositionDelegate OnMediaSessionPosition;
event Windows.Foundation.EventHandler<int> OnMediaSessionPlaybackStateChange;
Windows.Foundation.Collections.IVector<Pref> Preferences { get; };
Pref GetPref(String key);
diff --git a/support/hololens/ServoApp/pch.h b/support/hololens/ServoApp/pch.h
index 66759332c62..4ca8b52c4ba 100644
--- a/support/hololens/ServoApp/pch.h
+++ b/support/hololens/ServoApp/pch.h
@@ -31,6 +31,7 @@
#include <winrt/Windows.ApplicationModel.Activation.h>
#include <winrt/Windows.ApplicationModel.Core.h>
#include <winrt/Windows.ApplicationModel.Resources.h>
+#include <winrt/Windows.ApplicationModel.Resources.Core.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Metadata.h>
diff --git a/tests/wpt/metadata-layout-2020/FileAPI/url/url-in-tags-revoke.window.js.ini b/tests/wpt/metadata-layout-2020/FileAPI/url/url-in-tags-revoke.window.js.ini
index 76b44d9e9cf..3605e8f3fc9 100644
--- a/tests/wpt/metadata-layout-2020/FileAPI/url/url-in-tags-revoke.window.js.ini
+++ b/tests/wpt/metadata-layout-2020/FileAPI/url/url-in-tags-revoke.window.js.ini
@@ -4,7 +4,7 @@
expected: TIMEOUT
[Opening a blob URL in a new window immediately before revoking it works.]
- expected: FAIL
+ expected: TIMEOUT
[Fetching a blob URL immediately before revoking it works in an iframe.]
expected: FAIL
diff --git a/tests/wpt/metadata-layout-2020/css/css-flexbox/position-absolute-015.html.ini b/tests/wpt/metadata-layout-2020/css/css-flexbox/position-absolute-015.html.ini
new file mode 100644
index 00000000000..67ea4cdfde0
--- /dev/null
+++ b/tests/wpt/metadata-layout-2020/css/css-flexbox/position-absolute-015.html.ini
@@ -0,0 +1,4 @@
+[position-absolute-015.html]
+ [#abspos 1]
+ expected: FAIL
+
diff --git a/tests/wpt/metadata-layout-2020/css/cssom-view/CaretPosition-001.html.ini b/tests/wpt/metadata-layout-2020/css/cssom-view/CaretPosition-001.html.ini
deleted file mode 100644
index 4c79907309b..00000000000
--- a/tests/wpt/metadata-layout-2020/css/cssom-view/CaretPosition-001.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[CaretPosition-001.html]
- [Element at (400, 100)]
- expected: FAIL
-
diff --git a/tests/wpt/metadata-layout-2020/fetch/content-type/response.window.js.ini b/tests/wpt/metadata-layout-2020/fetch/content-type/response.window.js.ini
index 56752f6df92..5cbc5f156f4 100644
--- a/tests/wpt/metadata-layout-2020/fetch/content-type/response.window.js.ini
+++ b/tests/wpt/metadata-layout-2020/fetch/content-type/response.window.js.ini
@@ -315,24 +315,18 @@
[<iframe>: separate response Content-Type: text/plain */*;charset=gbk]
expected: FAIL
- [<iframe>: combined response Content-Type: text/html;" text/plain]
- expected: FAIL
-
[<iframe>: separate response Content-Type: text/html;" text/plain]
expected: FAIL
- [<iframe>: separate response Content-Type: text/html */*;charset=gbk]
+ [<iframe>: combined response Content-Type: text/html;" \\" text/plain]
expected: FAIL
- [<iframe>: separate response Content-Type: text/html */*]
+ [<iframe>: combined response Content-Type: */* text/html]
expected: FAIL
- [<iframe>: separate response Content-Type: text/plain */*]
+ [<iframe>: separate response Content-Type: text/html */*]
expected: FAIL
[<iframe>: combined response Content-Type: text/html */*;charset=gbk]
expected: FAIL
- [<iframe>: separate response Content-Type: text/html;" \\" text/plain]
- expected: FAIL
-
diff --git a/tests/wpt/metadata-layout-2020/fetch/content-type/script.window.js.ini b/tests/wpt/metadata-layout-2020/fetch/content-type/script.window.js.ini
index d2df9b78483..258fe374697 100644
--- a/tests/wpt/metadata-layout-2020/fetch/content-type/script.window.js.ini
+++ b/tests/wpt/metadata-layout-2020/fetch/content-type/script.window.js.ini
@@ -56,3 +56,6 @@
[separate text/javascript x/x]
expected: FAIL
+ [separate text/javascript ]
+ expected: FAIL
+
diff --git a/tests/wpt/metadata-layout-2020/fetch/nosniff/parsing-nosniff.window.js.ini b/tests/wpt/metadata-layout-2020/fetch/nosniff/parsing-nosniff.window.js.ini
index 97db72e5d96..61682d248e2 100644
--- a/tests/wpt/metadata-layout-2020/fetch/nosniff/parsing-nosniff.window.js.ini
+++ b/tests/wpt/metadata-layout-2020/fetch/nosniff/parsing-nosniff.window.js.ini
@@ -11,9 +11,6 @@
[X-Content-Type-Options%3A%20nosniff%2C%2C%40%23%24%23%25%25%26%5E%26%5E*()()11!]
expected: FAIL
- [Content-Type-Options%3A%20nosniff]
- expected: FAIL
-
- [X-Content-Type-Options%3A%0D%0AX-Content-Type-Options%3A%20nosniff]
+ [X-Content-Type-Options%3A%20%40%23%24%23%25%25%26%5E%26%5E*()()11!%2Cnosniff]
expected: FAIL
diff --git a/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_3.html.ini b/tests/wpt/metadata-layout-2020/html/browsers/history/the-history-interface/traverse_the_history_4.html.ini
index 51f8272a6de..385376c7321 100644
--- a/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_3.html.ini
+++ b/tests/wpt/metadata-layout-2020/html/browsers/history/the-history-interface/traverse_the_history_4.html.ini
@@ -1,4 +1,4 @@
-[traverse_the_history_3.html]
+[traverse_the_history_4.html]
[Multiple history traversals, last would be aborted]
expected: FAIL
diff --git a/tests/wpt/metadata-layout-2020/html/browsers/origin/cross-origin-objects/cross-origin-objects-on-new-window.html.ini b/tests/wpt/metadata-layout-2020/html/browsers/origin/cross-origin-objects/cross-origin-objects-on-new-window.html.ini
new file mode 100644
index 00000000000..735a9a75a2a
--- /dev/null
+++ b/tests/wpt/metadata-layout-2020/html/browsers/origin/cross-origin-objects/cross-origin-objects-on-new-window.html.ini
@@ -0,0 +1,2 @@
+[cross-origin-objects-on-new-window.html]
+ expected: TIMEOUT
diff --git a/tests/wpt/metadata-layout-2020/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/creating_browsing_context_test_01.html.ini b/tests/wpt/metadata-layout-2020/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/creating_browsing_context_test_01.html.ini
new file mode 100644
index 00000000000..16fa2c5cfc1
--- /dev/null
+++ b/tests/wpt/metadata-layout-2020/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/creating_browsing_context_test_01.html.ini
@@ -0,0 +1,4 @@
+[creating_browsing_context_test_01.html]
+ [first argument: absolute url]
+ expected: FAIL
+
diff --git a/tests/wpt/metadata-layout-2020/html/browsers/windows/embedded-opener-remove-frame.html.ini b/tests/wpt/metadata-layout-2020/html/browsers/windows/embedded-opener-remove-frame.html.ini
index 8e2a63e3b7f..8e2b6af33d8 100644
--- a/tests/wpt/metadata-layout-2020/html/browsers/windows/embedded-opener-remove-frame.html.ini
+++ b/tests/wpt/metadata-layout-2020/html/browsers/windows/embedded-opener-remove-frame.html.ini
@@ -1,8 +1,8 @@
[embedded-opener-remove-frame.html]
- expected: CRASH
+ expected: TIMEOUT
[opener of discarded nested browsing context]
expected: FAIL
[opener of discarded auxiliary browsing context]
- expected: FAIL
+ expected: TIMEOUT
diff --git a/tests/wpt/metadata-layout-2020/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-flexbox.html.ini b/tests/wpt/metadata-layout-2020/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-flexbox.html.ini
new file mode 100644
index 00000000000..ac9b670991a
--- /dev/null
+++ b/tests/wpt/metadata-layout-2020/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-flexbox.html.ini
@@ -0,0 +1,2 @@
+[fieldset-flexbox.html]
+ expected: CRASH
diff --git a/tests/wpt/metadata-layout-2020/html/semantics/embedded-content/image-maps/image-map-processing-model/hash-name-reference.html.ini b/tests/wpt/metadata-layout-2020/html/semantics/embedded-content/image-maps/image-map-processing-model/hash-name-reference.html.ini
index 09ae27d7480..5c3ac06f42a 100644
--- a/tests/wpt/metadata-layout-2020/html/semantics/embedded-content/image-maps/image-map-processing-model/hash-name-reference.html.ini
+++ b/tests/wpt/metadata-layout-2020/html/semantics/embedded-content/image-maps/image-map-processing-model/hash-name-reference.html.ini
@@ -171,6 +171,3 @@
[XHTML img usemap="#hash-id"]
expected: FAIL
- [HTML (standards) IMG usemap="no-hash-name"]
- expected: FAIL
-
diff --git a/tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-1.html.ini b/tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-1.html.ini
index 42ebcc9d57e..88f4ddd0e9a 100644
--- a/tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-1.html.ini
+++ b/tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-1.html.ini
@@ -1,5 +1,5 @@
[iframe_sandbox_popups_escaping-1.html]
- expected: TIMEOUT
+ expected: CRASH
[Check that popups from a sandboxed iframe escape the sandbox if\n allow-popups-to-escape-sandbox is used]
expected: TIMEOUT
diff --git a/tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-2.html.ini b/tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-2.html.ini
index 4df5d7a35de..daa518bd0e3 100644
--- a/tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-2.html.ini
+++ b/tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-2.html.ini
@@ -1,4 +1,5 @@
[iframe_sandbox_popups_escaping-2.html]
+ expected: CRASH
[Check that popups from a sandboxed iframe escape the sandbox if\n allow-popups-to-escape-sandbox is used]
expected: FAIL
diff --git a/tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-3.html.ini b/tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-3.html.ini
index 295031c1812..338d283eb0e 100644
--- a/tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-3.html.ini
+++ b/tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-3.html.ini
@@ -1,5 +1,4 @@
[iframe_sandbox_popups_escaping-3.html]
- expected: TIMEOUT
[Check that popups from a sandboxed iframe escape the sandbox if\n allow-popups-to-escape-sandbox is used]
- expected: TIMEOUT
+ expected: FAIL
diff --git a/tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-1.html.ini b/tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-1.html.ini
index d913fcbb129..3080be9afc0 100644
--- a/tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-1.html.ini
+++ b/tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-1.html.ini
@@ -1,5 +1,5 @@
[iframe_sandbox_popups_nonescaping-1.html]
- expected: TIMEOUT
+ expected: CRASH
[Check that popups from a sandboxed iframe do not escape the sandbox]
expected: NOTRUN
diff --git a/tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-3.html.ini b/tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-3.html.ini
index f4f994c5d6f..7a36937927c 100644
--- a/tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-3.html.ini
+++ b/tests/wpt/metadata-layout-2020/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-3.html.ini
@@ -1,5 +1,4 @@
[iframe_sandbox_popups_nonescaping-3.html]
- expected: TIMEOUT
[Check that popups from a sandboxed iframe do not escape the sandbox]
- expected: NOTRUN
+ expected: FAIL
diff --git a/tests/wpt/metadata-layout-2020/html/semantics/forms/form-submission-0/form-double-submit-3.html.ini b/tests/wpt/metadata-layout-2020/html/semantics/forms/form-submission-0/form-double-submit-3.html.ini
deleted file mode 100644
index 9f416703229..00000000000
--- a/tests/wpt/metadata-layout-2020/html/semantics/forms/form-submission-0/form-double-submit-3.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[form-double-submit-3.html]
- [<button> should have the same double-submit protection as <input type=submit>]
- expected: FAIL
-
diff --git a/tests/wpt/metadata-layout-2020/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url-worker-importScripts.html.ini b/tests/wpt/metadata-layout-2020/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url-worker-importScripts.html.ini
new file mode 100644
index 00000000000..5dff48bbfe8
--- /dev/null
+++ b/tests/wpt/metadata-layout-2020/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url-worker-importScripts.html.ini
@@ -0,0 +1,7 @@
+[base-url-worker-importScripts.html]
+ [Relative URL-like from same-origin importScripts()]
+ expected: FAIL
+
+ [Relative URL-like from cross-origin importScripts()]
+ expected: FAIL
+
diff --git a/tests/wpt/metadata-layout-2020/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url.sub.html.ini b/tests/wpt/metadata-layout-2020/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url.sub.html.ini
new file mode 100644
index 00000000000..df99f59baa0
--- /dev/null
+++ b/tests/wpt/metadata-layout-2020/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url.sub.html.ini
@@ -0,0 +1,7 @@
+[base-url.sub.html]
+ [Relative URL-like from cross origin classic <script> without crossorigin attribute]
+ expected: FAIL
+
+ [Relative URL-like from cross origin module <script>]
+ expected: FAIL
+
diff --git a/tests/wpt/metadata-layout-2020/html/webappapis/dynamic-markup-insertion/document-write/iframe_005.html.ini b/tests/wpt/metadata-layout-2020/html/webappapis/dynamic-markup-insertion/document-write/iframe_005.html.ini
deleted file mode 100644
index 6cf9d13975c..00000000000
--- a/tests/wpt/metadata-layout-2020/html/webappapis/dynamic-markup-insertion/document-write/iframe_005.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[iframe_005.html]
- [document.write external script into iframe write back into parent]
- expected: FAIL
-
diff --git a/tests/wpt/metadata-layout-2020/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-delayed.html.ini b/tests/wpt/metadata-layout-2020/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-delayed.html.ini
new file mode 100644
index 00000000000..fca4d908c89
--- /dev/null
+++ b/tests/wpt/metadata-layout-2020/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-delayed.html.ini
@@ -0,0 +1,4 @@
+[module-static-import-delayed.html]
+ [document.write in an imported module]
+ expected: FAIL
+
diff --git a/tests/wpt/metadata-layout-2020/html/webappapis/scripting/events/compile-event-handler-settings-objects.html.ini b/tests/wpt/metadata-layout-2020/html/webappapis/scripting/events/compile-event-handler-settings-objects.html.ini
index 450c88bd32b..5602ea31dbe 100644
--- a/tests/wpt/metadata-layout-2020/html/webappapis/scripting/events/compile-event-handler-settings-objects.html.ini
+++ b/tests/wpt/metadata-layout-2020/html/webappapis/scripting/events/compile-event-handler-settings-objects.html.ini
@@ -4,5 +4,5 @@
expected: TIMEOUT
[The entry settings object while executing the compiled callback via Web IDL's invoke must be that of the node document]
- expected: FAIL
+ expected: TIMEOUT
diff --git a/tests/wpt/metadata-layout-2020/streams/readable-streams/tee.any.js.ini b/tests/wpt/metadata-layout-2020/streams/readable-streams/tee.any.js.ini
new file mode 100644
index 00000000000..d7c055f3b60
--- /dev/null
+++ b/tests/wpt/metadata-layout-2020/streams/readable-streams/tee.any.js.ini
@@ -0,0 +1,59 @@
+[tee.any.sharedworker.html]
+ expected: ERROR
+
+[tee.any.worker.html]
+ expected: TIMEOUT
+ [ReadableStreamTee should not pull more chunks than can fit in the branch queue]
+ expected: NOTRUN
+
+ [ReadableStream teeing: canceling branch1 should finish when branch2 reads until end of stream]
+ expected: TIMEOUT
+
+ [ReadableStream teeing: canceling branch1 should finish when original stream errors]
+ expected: NOTRUN
+
+ [ReadableStreamTee should only pull enough to fill the emptiest queue]
+ expected: NOTRUN
+
+ [ReadableStreamTee stops pulling when original stream errors while both branches are reading]
+ expected: NOTRUN
+
+ [ReadableStreamTee stops pulling when original stream errors while branch 1 is reading]
+ expected: NOTRUN
+
+ [ReadableStreamTee stops pulling when original stream errors while branch 2 is reading]
+ expected: NOTRUN
+
+ [ReadableStreamTee should not pull when original is already errored]
+ expected: NOTRUN
+
+
+[tee.any.serviceworker.html]
+ expected: ERROR
+
+[tee.any.html]
+ expected: TIMEOUT
+ [ReadableStreamTee should not pull more chunks than can fit in the branch queue]
+ expected: NOTRUN
+
+ [ReadableStream teeing: canceling branch1 should finish when branch2 reads until end of stream]
+ expected: TIMEOUT
+
+ [ReadableStream teeing: canceling branch1 should finish when original stream errors]
+ expected: NOTRUN
+
+ [ReadableStreamTee should only pull enough to fill the emptiest queue]
+ expected: NOTRUN
+
+ [ReadableStreamTee stops pulling when original stream errors while both branches are reading]
+ expected: NOTRUN
+
+ [ReadableStreamTee stops pulling when original stream errors while branch 1 is reading]
+ expected: NOTRUN
+
+ [ReadableStreamTee stops pulling when original stream errors while branch 2 is reading]
+ expected: NOTRUN
+
+ [ReadableStreamTee should not pull when original is already errored]
+ expected: NOTRUN
+
diff --git a/tests/wpt/metadata-layout-2020/workers/interfaces/WorkerGlobalScope/onerror/exception-in-onerror.html.ini b/tests/wpt/metadata-layout-2020/workers/interfaces/WorkerGlobalScope/onerror/exception-in-onerror.html.ini
new file mode 100644
index 00000000000..ae39ac39151
--- /dev/null
+++ b/tests/wpt/metadata-layout-2020/workers/interfaces/WorkerGlobalScope/onerror/exception-in-onerror.html.ini
@@ -0,0 +1,49 @@
+[exception-in-onerror.html]
+ [Throw in setTimeout(string): classic: listener]
+ expected: FAIL
+
+ [Throw in setTimeout(function): module: listener]
+ expected: FAIL
+
+ [Throw in worker initialization: classic: handler]
+ expected: FAIL
+
+ [Throw in message handler: classic: listener]
+ expected: FAIL
+
+ [Throw in setTimeout(function): classic: handler]
+ expected: FAIL
+
+ [Throw in message handler: module: handler]
+ expected: FAIL
+
+ [Throw in setTimeout(function): module: handler]
+ expected: FAIL
+
+ [Throw in worker initialization: module: handler]
+ expected: FAIL
+
+ [Throw in setTimeout(string): module: listener]
+ expected: FAIL
+
+ [Throw in message handler: classic: handler]
+ expected: FAIL
+
+ [Throw in worker initialization: classic: listener]
+ expected: FAIL
+
+ [Throw in message handler: module: listener]
+ expected: FAIL
+
+ [Throw in setTimeout(string): module: handler]
+ expected: FAIL
+
+ [Throw in setTimeout(function): classic: listener]
+ expected: FAIL
+
+ [Throw in worker initialization: module: listener]
+ expected: FAIL
+
+ [Throw in setTimeout(string): classic: handler]
+ expected: FAIL
+
diff --git a/tests/wpt/metadata/FileAPI/url/url-in-tags-revoke.window.js.ini b/tests/wpt/metadata/FileAPI/url/url-in-tags-revoke.window.js.ini
index d4f62ed7113..faa00f45ecf 100644
--- a/tests/wpt/metadata/FileAPI/url/url-in-tags-revoke.window.js.ini
+++ b/tests/wpt/metadata/FileAPI/url/url-in-tags-revoke.window.js.ini
@@ -7,7 +7,7 @@
expected: FAIL
[Opening a blob URL in a new window immediately before revoking it works.]
- expected: FAIL
+ expected: TIMEOUT
[Opening a blob URL in a noopener about:blank window immediately before revoking it works.]
expected: TIMEOUT
diff --git a/tests/wpt/metadata/MANIFEST.json b/tests/wpt/metadata/MANIFEST.json
index a06c1a2d561..ceca26c219e 100644
--- a/tests/wpt/metadata/MANIFEST.json
+++ b/tests/wpt/metadata/MANIFEST.json
@@ -17086,6 +17086,41 @@
null,
{}
]
+ ],
+ "protocol-handler-fragment-manual.https.html": [
+ "15617865691878af2069dfbbf4d397bf3a442600",
+ [
+ null,
+ {}
+ ]
+ ],
+ "protocol-handler-fragment-nosw-manual.https.html": [
+ "be3a6be6665246ccffa1d60f0e11f376b3280cb5",
+ [
+ null,
+ {}
+ ]
+ ],
+ "protocol-handler-path-manual.https.html": [
+ "085c5723ec412d027ef0ccca13855839477ffe70",
+ [
+ null,
+ {}
+ ]
+ ],
+ "protocol-handler-query-manual.https.html": [
+ "8ce65a5bad8826326dc4b5c85c6476174bbd5954",
+ [
+ null,
+ {}
+ ]
+ ],
+ "protocol-handler-query-nosw-manual.https.html": [
+ "9b4473fb8952ba93c79d17b71725b97c6bf2b208",
+ [
+ null,
+ {}
+ ]
]
}
},
@@ -124256,6 +124291,32 @@
{}
]
],
+ "forced-break-at-fragmentainer-start-000.html": [
+ "d5796ba641b524b6379c1ab9f37dad6408bc5a10",
+ [
+ null,
+ [
+ [
+ "/css/reference/ref-filled-green-100px-square-only.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
+ "forced-break-at-fragmentainer-start-001.html": [
+ "b3ad80ca9a0dfac7574362e6ff8528ee0c39e8e9",
+ [
+ null,
+ [
+ [
+ "/css/reference/ref-filled-green-100px-square.xht",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
"form-control.html": [
"8ef6eedae252f36de3bfeef8c3a6db23bf6f3d89",
[
@@ -129834,6 +129895,19 @@
],
{}
]
+ ],
+ "content-visibility-074.html": [
+ "ff6381ce3d0950c0b3c3822171c2b81d851ded15",
+ [
+ null,
+ [
+ [
+ "/css/css-contain/content-visibility/content-visibility-074-ref.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
]
},
"counter-scoping-001.html": [
@@ -144074,6 +144148,136 @@
{}
]
],
+ "grid-item-no-aspect-ratio-stretch-1.html": [
+ "1b5ae0a6ad80610515ed53f5ea34e812fe040d27",
+ [
+ null,
+ [
+ [
+ "/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-1-ref.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
+ "grid-item-no-aspect-ratio-stretch-10.html": [
+ "6d8d7e848c24d6da176334b56f6b8af03341d374",
+ [
+ null,
+ [
+ [
+ "/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-8-ref.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
+ "grid-item-no-aspect-ratio-stretch-2.html": [
+ "5371e560a5f80eae466485ccd89486c33d741190",
+ [
+ null,
+ [
+ [
+ "/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-2-ref.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
+ "grid-item-no-aspect-ratio-stretch-3.html": [
+ "e2b05bd21664eaa61e4ec3a2abb74f431c8fdc1c",
+ [
+ null,
+ [
+ [
+ "/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-3-ref.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
+ "grid-item-no-aspect-ratio-stretch-4.html": [
+ "1cf2849dad3d067b7d097ab76a775e213e836d10",
+ [
+ null,
+ [
+ [
+ "/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-4-ref.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
+ "grid-item-no-aspect-ratio-stretch-5.html": [
+ "3000e9d97a1002b41753ca651a0313e090f42bf8",
+ [
+ null,
+ [
+ [
+ "/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-5-ref.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
+ "grid-item-no-aspect-ratio-stretch-6.html": [
+ "655040eb446497916470875c7312bfa81d343148",
+ [
+ null,
+ [
+ [
+ "/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-6-ref.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
+ "grid-item-no-aspect-ratio-stretch-7.html": [
+ "29dec490b79ac5ee7c21af8013c0917b0642221b",
+ [
+ null,
+ [
+ [
+ "/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-7-ref.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
+ "grid-item-no-aspect-ratio-stretch-8.html": [
+ "933ddd0504efe9a3202d3ded7f661b5cacd1a2c4",
+ [
+ null,
+ [
+ [
+ "/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-8-ref.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
+ "grid-item-no-aspect-ratio-stretch-9.html": [
+ "367adae9eb74d5975170ec94893ae84ad1046f0d",
+ [
+ null,
+ [
+ [
+ "/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-8-ref.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
"grid-item-self-baseline-001.html": [
"ccc50c764975906b59f54aa1205a4513149e85f2",
[
@@ -155386,6 +155590,19 @@
{}
]
],
+ "increase-prev-sibling-height.html": [
+ "109fe89952e923222071fea33ed9f92b69cf323f",
+ [
+ null,
+ [
+ [
+ "/css/css-multicol/increase-prev-sibling-height-ref.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
"inline-block-and-column-span-all.html": [
"c968a0875cd7cc41c3c1dd83abee425ba0e639bb",
[
@@ -159957,6 +160174,19 @@
{}
]
],
+ "paint-function-this-value.https.html": [
+ "216913899a931e8144d8a647eccb8ba01037f737",
+ [
+ null,
+ [
+ [
+ "/css/css-paint-api/parse-input-arguments-ref.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
"paint2d-composite.https.html": [
"d654ba49aad6048f88e6ddb6750554dc22b860fb",
[
@@ -248170,7 +248400,7 @@
[]
],
".taskcluster.yml": [
- "526fc13212e9b2ac9abfb54fcdcddea63a63c80a",
+ "b1a8162db4b21c594b3060ce6109d98bf6f98d31",
[]
],
".well-known": {
@@ -270664,6 +270894,10 @@
"6d1eedb1fcbfda2bf27f74af1b34763adc62d599",
[]
],
+ "not-embeddable-frame.py": [
+ "50f9c83cf5c2343535f36348459ab8144dbe8cd7",
+ []
+ ],
"redirect-throw-function.sub.py": [
"1bc89abf7176bbada8f0c8c35fd699f52bb0e8a9",
[]
@@ -270710,6 +270944,10 @@
},
"sandbox": {
"support": {
+ "post-origin-on-load-worker.js": [
+ "21ce5748ab8b1edbfd04c8f77a3fba54739a73d5",
+ []
+ ],
"sandboxed-data-iframe.sub.html": [
"fafd4dc7707ab0d26ed2c67f34c26920649795f8",
[]
@@ -293092,6 +293330,10 @@
"b2232a4a72546b12a05f4ab84d41ef85c20959dc",
[]
],
+ "content-visibility-074-ref.html": [
+ "82a6c263fa906d70f76dc78fcd6d7b6c3b461b86",
+ []
+ ],
"inline-container-with-child-ref.html": [
"af51cbd5db8f3eff56411345860548e95fe4d354",
[]
@@ -302430,6 +302672,38 @@
"d167a5f1542b5a71b51ce06b806a2f9425d7f6ab",
[]
],
+ "grid-item-no-aspect-ratio-stretch-1-ref.html": [
+ "6a7862c9acb626a72fda6138fdabd05a37e865ac",
+ []
+ ],
+ "grid-item-no-aspect-ratio-stretch-2-ref.html": [
+ "69d59e85a3c7134064f516d9e1a32ccb00dc1960",
+ []
+ ],
+ "grid-item-no-aspect-ratio-stretch-3-ref.html": [
+ "7ee8a2d6bdccc5f50b9f1444cb92a23febe9f81d",
+ []
+ ],
+ "grid-item-no-aspect-ratio-stretch-4-ref.html": [
+ "9edb8aa76f8fd40302a8dcac27db19b51f2c56b0",
+ []
+ ],
+ "grid-item-no-aspect-ratio-stretch-5-ref.html": [
+ "6a3446534a1a5e42952f521c9b1634284c4e594b",
+ []
+ ],
+ "grid-item-no-aspect-ratio-stretch-6-ref.html": [
+ "33f472e71b853651285ff7248226ed4be6c1a603",
+ []
+ ],
+ "grid-item-no-aspect-ratio-stretch-7-ref.html": [
+ "0d60375f560f3a2d379bd90eac4a062e0a7f420a",
+ []
+ ],
+ "grid-item-no-aspect-ratio-stretch-8-ref.html": [
+ "09dd27321ab5790927104ccadb4d002dba4f67a7",
+ []
+ ],
"grid-item-self-baseline-001-ref.html": [
"6eadf9a02a55822a54fa44715d80bece93997b0f",
[]
@@ -304593,6 +304867,10 @@
"7c33b48f5e6077ad87a230d8ca54976e55785445",
[]
],
+ "increase-prev-sibling-height-ref.html": [
+ "963f584f17d502f6d693dfe8d662ec2b3978f4ff",
+ []
+ ],
"multicol-block-no-clip-001-ref.xht": [
"1313948514e9cd6c96ad45ff60ba9c327a0b9838",
[]
@@ -322644,7 +322922,7 @@
[]
],
"from-local-system.md": [
- "8c71e535baa907f1ef86641ee6211adb7d0c2423",
+ "91823444d5d4813afb020d00b2fca188f4a22f21",
[]
],
"from-web.md": [
@@ -322714,7 +322992,7 @@
[]
],
"index.md": [
- "90a67c21fce2d1546544c0540d3158fd5bf16a26",
+ "c1d2fe17a31508d65a9b46da5bb93b3329648ad9",
[]
],
"lint-tool.md": [
@@ -322784,7 +323062,7 @@
[]
],
"testharness.md": [
- "1e9772a401796da1a9a15f1fea9958843c64dc7e",
+ "1037eaca03c702383c0b9caab07fa98cdec4b4c0",
[]
],
"tools.md": [
@@ -330324,7 +330602,7 @@
[]
],
"dispatcher.py": [
- "2617361b0b369bd9efd3aedd42a88f8f46906fe3",
+ "e77583e479f9506b3f6a5b53293ae25dc3cae8f1",
[]
],
"executor.html": [
@@ -337409,6 +337687,36 @@
[]
],
"dynamic-import": {
+ "alpha": {
+ "import.js": [
+ "b2ac52df2a18d4bdcf49310352c2bafbeb0269c4",
+ []
+ ],
+ "worker-importScripts.sub.js": [
+ "904d32f9bfd7110c1cb1c7104f54118c86aba30e",
+ []
+ ]
+ },
+ "beta": {
+ "import.js": [
+ "7de1c68182571b80afabd79661f3fed025a2a34f",
+ []
+ ],
+ "redirect.py": [
+ "f2fd1ebd51d4ad5f4ef0582510600eb3731fd2c7",
+ []
+ ]
+ },
+ "gamma": {
+ "base-url.sub.js": [
+ "ec7784983d1182831d3ab910bca7eb54322eec62",
+ []
+ ],
+ "import.js": [
+ "435c1369be2f7a214b003ee8efa734ba8478cc7b",
+ []
+ ]
+ },
"propagate-nonce-external.js": [
"3b97d2f40e914af5d22ecc338913dcb0591927ba",
[]
@@ -338885,6 +339193,24 @@
[]
]
},
+ "system-state-and-capabilities": {
+ "the-navigator-object": {
+ "resources": {
+ "handler-sw.js": [
+ "5fd915d17f98d8fa9c3c81451f46d71bc6cd024e",
+ []
+ ],
+ "handler-tools.js": [
+ "073287265cfe5f5b219ad6f61ffed89556a1e5cb",
+ []
+ ],
+ "handler.html": [
+ "552e5417842e67bb5b917268e0250a951614267c",
+ []
+ ]
+ }
+ }
+ },
"the-windoworworkerglobalscope-mixin": {
"README.md": [
"10ae3e5f03601a67e247f771cf73fdfddfdda12f",
@@ -340437,7 +340763,7 @@
[]
],
"web-share.idl": [
- "c29a29d0b4ede94153a75860344ab4824e91b6d5",
+ "b66bcd81fe9c951c2e70a58596380353b7046d97",
[]
],
"webaudio.idl": [
@@ -342776,7 +343102,7 @@
[]
],
"child-frame-script.mjs": [
- "2c6760a3e3707f06b5f3f904eec5e0aa21ec9586",
+ "783e36092daae6a3998a2701d110add2f55c3a0f",
[]
],
"child-frame-script.mjs.headers": [
@@ -342784,7 +343110,7 @@
[]
],
"helpers.mjs": [
- "e8425c240b5e5821bc16708044863f73bf5f4697",
+ "73f9406b476bb4afa708d043fb8bb68e6618d946",
[]
],
"helpers.mjs.headers": [
@@ -350528,11 +350854,11 @@
[]
],
"run_tc.py": [
- "a5a8ca7db29ab484fe397475f9b5cfc412d6517f",
+ "3a3b0d8090baf7ab60f364dfd6908b6be7011f8e",
[]
],
"taskcluster-run.py": [
- "61d05689287a33c3470089e929d0c8871b6a46ef",
+ "245ee7fa5925e20df7eead0c86993494475a55e4",
[]
],
"tc": {
@@ -350545,13 +350871,17 @@
[]
],
"decision.py": [
- "0820a6798b5b233581eb561a973cb97ff2af44e1",
+ "f52f5b093f0f41632613578f449188f82bc03ab9",
[]
],
"download.py": [
"359ec33405048c134ddcfac7a564ea9a17ac1b14",
[]
],
+ "github_checks_output.py": [
+ "16d399002984e0b9daf8a0239b49bedbea50914b",
+ []
+ ],
"sink_task.py": [
"ba76d27640c86197736d7edc9e8ed86fe8ec4bd0",
[]
@@ -350562,7 +350892,7 @@
],
"tasks": {
"test.yml": [
- "dd14fc71b915e90f0625dc1120aed3c86a787e53",
+ "b1534c9d230d0b443ba2ecf83aacc58598221ae8",
[]
]
},
@@ -350594,7 +350924,7 @@
[]
],
"test_valid.py": [
- "88ffdb2951133474884c89c2dfa0a2e029c9ca19",
+ "472f83f86a0fbb154502f48dfb5cfcc09cf8459f",
[]
]
}
@@ -351154,7 +351484,7 @@
[]
],
"commands.json": [
- "a5457b55a3308d47fac178aedd6282d93b36120f",
+ "ed1d72e60ec33c3b550308bc55eacbf96e0be4c4",
[]
],
"serve.py": [
@@ -351162,7 +351492,7 @@
[]
],
"test_functional.py": [
- "894479d111c90dad925c683cb0e93ac13fc68619",
+ "5a918c2ee473e55886dfc70878d3df17b728e6f1",
[]
],
"test_serve.py": [
@@ -356950,7 +357280,7 @@
[]
],
"commands.json": [
- "a47ab40d72847d5f536e0ac2e02eb3fe0fea233a",
+ "51f66d0decb09d7a17493ca72a5f13f829d04f3b",
[]
],
"create.py": [
@@ -357019,7 +357349,7 @@
[]
],
"test_wpt.py": [
- "b5ae79d13112bec1a4f264686338204ba3d62abc",
+ "0b6aff42d57d7dc8bb4ba936c86b913f58cba791",
[]
]
},
@@ -357040,7 +357370,7 @@
[]
],
"wpt.py": [
- "395db0394da67caa8bdc1ad9e689e583175192b0",
+ "efa985c7cc1740eb0fd6e5a80f9e89e24cf75d37",
[]
]
},
@@ -357563,7 +357893,7 @@
[]
],
"stability.py": [
- "3f8989729fde0ee45cf783bc698307e38c844d90",
+ "605b40281a1b559e47d6aa795bb5cbd4b8715177",
[]
],
"testdriver-extra.js": [
@@ -357697,7 +358027,7 @@
[]
],
"wptcommandline.py": [
- "f322d77fbddefabc8fd187ebbc8cadaea8ea1086",
+ "ea586825616132b410127124ad2152ae88554cde",
[]
],
"wptlogging.py": [
@@ -358038,7 +358368,7 @@
[]
],
"test_stash.py": [
- "1c4c9ad933a37746623a0195f553ad8cfe70688f",
+ "0b960c1e9f8609dcbd82dbb333434fe0d2700185",
[]
]
},
@@ -359954,7 +360284,7 @@
[]
],
"keys.py": [
- "a62318814f3617bab6376f960c8ffc82d22b8d9b",
+ "2d38e1dff8760ff6d29b6e06d0ba3ac510471e1e",
[]
],
"mouse.py": [
@@ -363424,7 +363754,7 @@
},
"onerror": {
"exception-in-onerror.js": [
- "2bf4124cb74b5fa34302ffddce7e44b953d0d472",
+ "61a95dda51f7e74c3fdff46fcfd09d7f2305dbe5",
[]
],
"handled.js": [
@@ -384835,6 +385165,20 @@
}
]
],
+ "report-frame-ancestors-with-x-frame-options.sub.html": [
+ "0c58a5efd54ceda6ad5f906b02862976c40f65cd",
+ [
+ null,
+ {}
+ ]
+ ],
+ "report-frame-ancestors.sub.html": [
+ "cd7bbcb9731009651c1646907e55e137e9d5fdb5",
+ [
+ null,
+ {}
+ ]
+ ],
"report-multiple-violations-01.html": [
"7a92f1b955639eb26bfd4a737ee1a930fdec6592",
[
@@ -385004,6 +385348,13 @@
{}
]
],
+ "meta-element.sub.html": [
+ "cd8da8f14c4ad775b9034131315867dec08cd2e8",
+ [
+ null,
+ {}
+ ]
+ ],
"sandbox-allow-scripts-subframe.sub.html": [
"1d6db3cde71cddb66f5536720a632b537465cbff",
[
@@ -393503,6 +393854,13 @@
{}
]
],
+ "position-absolute-015.html": [
+ "1c0f3bc4c2888a12d20e2ab704f835f359366b81",
+ [
+ null,
+ {}
+ ]
+ ],
"position-relative-percentage-top-001.html": [
"3ec47c1d42d69330c616a87f0b22208f8d6196a6",
[
@@ -393511,7 +393869,7 @@
]
],
"quirks-auto-block-size-with-percentage-item.html": [
- "966f39f173952f01268dcd26a9a5892bf4a689a9",
+ "f5c3d7c1818366c403896bc1da44af11ed4e0f5b",
[
null,
{}
@@ -415404,7 +415762,7 @@
},
"events": {
"AddEventListenerOptions-once.html": [
- "ae750702c79d0e2f493537ade1c78558987f536e",
+ "361c838b736258642c0bf5f26f243544edf2224b",
[
null,
{}
@@ -417044,6 +417402,13 @@
{}
]
],
+ "MutationObserver-callback-arguments.html": [
+ "d64758cb4fa00d25ad3dafe576a0098c902922b7",
+ [
+ null,
+ {}
+ ]
+ ],
"MutationObserver-characterData.html": [
"addaef03da1ac64ce9e6a6b1c5d244933b2c7f7b",
[
@@ -457830,10 +458195,12 @@
]
],
"reporting-observer.html": [
- "4d1eda941ae50ce4482c692dafe749ef9e455ac6",
+ "decad097b6d29acabb6252497f68658002c3478e",
[
null,
- {}
+ {
+ "timeout": "long"
+ }
]
]
},
@@ -457945,7 +458312,7 @@
]
],
"reporting-redirect-with-same-origin-allow-popups.https.html": [
- "7dba76c4ef5434d49d7800da14eb980f79728f44",
+ "f807561f17488c1b05ea779f6b0aa64c7a10d197",
[
null,
{
@@ -460625,7 +460992,7 @@
]
],
"fieldset-flexbox.html": [
- "07c73554e59ccb576e590192e923de6b7100e1ae",
+ "9e1c9ed152fb6597891b310f6a492d57ae136441",
[
null,
{}
@@ -461271,7 +461638,7 @@
"pragma-directives": {
"attr-meta-http-equiv-refresh": {
"allow-scripts-flag-changing-1.html": [
- "3bf8cfb6cc8949ec30f3491660f01fb452307ccb",
+ "196f6d0409a9cc97104f6c15fc7855fb549bfebe",
[
null,
{}
@@ -469554,6 +469921,29 @@
]
],
"dynamic-import": {
+ "alpha": {
+ "base-url-worker-importScripts.html": [
+ "817cf6d5ddfdc186454de0e3a672a865e2ced416",
+ [
+ null,
+ {}
+ ]
+ ],
+ "base-url-worker.sub.html": [
+ "a12204281cc43e64c7f1f4f7cdaf37958567b516",
+ [
+ null,
+ {}
+ ]
+ ],
+ "base-url.sub.html": [
+ "f7d4927a104c78e2f3d41e0899c7deadb5ca3d1c",
+ [
+ null,
+ {}
+ ]
+ ]
+ },
"dynamic-imports-credentials.sub.html": [
"b939a3ef1639db8027519ac004cd3197e254c0b9",
[
@@ -476172,6 +476562,24 @@
{}
]
],
+ "input-events-get-target-ranges-backspace.tentative.html": [
+ "cf512269b07e0177214f7d9059150a77b85eb225",
+ [
+ null,
+ {
+ "testdriver": true
+ }
+ ]
+ ],
+ "input-events-get-target-ranges-forwarddelete.tentative.html": [
+ "3780324cf92bfa0c712045d89e43e903e3a1c9c6",
+ [
+ null,
+ {
+ "testdriver": true
+ }
+ ]
+ ],
"input-events-typing.html": [
"a894beea9bd381313b999e45abe0b4b8f61c804b",
[
@@ -476391,6 +476799,13 @@
{}
]
],
+ "observer-callback-arguments.html": [
+ "6e816969d00641af4da1c86d7b7bafc4a3ffbc3b",
+ [
+ null,
+ {}
+ ]
+ ],
"observer-exceptions.html": [
"126790f290d9480dcda7eed6e1b2989ffcc6a70f",
[
@@ -477048,7 +477463,7 @@
]
],
"invisible-images-composited-1.html": [
- "495645ab41eccb80464a2ceb7de83a2136ecfbf7",
+ "7723d2f2bea5b622395e09ae1bd7fd4bb6cf87bc",
[
null,
{}
@@ -477189,6 +477604,20 @@
{}
]
],
+ "child-shift-with-parent-overflow-hidden.html": [
+ "d69e55a51b8088ca0a94f3975155646d21792d88",
+ [
+ null,
+ {}
+ ]
+ ],
+ "child-shift-with-parent.html": [
+ "7271af6d4a04fbbafebe2b20b372f6f41b31b3a9",
+ [
+ null,
+ {}
+ ]
+ ],
"clip-negative-bottom-margin.html": [
"2c329d9fcd66d86bf8c350c2ee419e28ef6596f4",
[
@@ -477227,14 +477656,14 @@
]
],
"inline-flow-shift-vertical-rl.html": [
- "06bc34c37dd0559bfe6bedcc956ec2e2734c14b3",
+ "a89cad145b277bb7a92b30781a63de18fb76c42f",
[
null,
{}
]
],
"inline-flow-shift.html": [
- "39550da6588eeb7aca7001ab592ee0177d26ca56",
+ "0385f29c2f9796818daf38ba5cad2aec7ba4b550",
[
null,
{}
@@ -487051,7 +487480,7 @@
"pointerevents": {
"compat": {
"pointerevent_compat-mouse-events-when-removing-nodes.html": [
- "4388b2db308d70a24b70d94ed2441a468c2267ee",
+ "88d03b7965efc241893b8fbfc4c8f2e2b0967bf5",
[
null,
{
@@ -487060,7 +487489,7 @@
]
],
"pointerevent_mouse-on-object.html": [
- "d8912a2652b405e6a5882b21f657308142c5e77b",
+ "fa0e97ff30c234c3311eadacef094e3c0b385acf",
[
null,
{
@@ -487077,6 +487506,15 @@
}
]
],
+ "pointerevent_mouse-pointer-preventdefault.html": [
+ "a727325a5b1d0e7d4f02899a98cfc5d457e106a4",
+ [
+ null,
+ {
+ "testdriver": true
+ }
+ ]
+ ],
"pointerevent_mouse-pointer-updown-events.html": [
"a5433aab535f075b58844481a44588cb578a6bf0",
[
@@ -507954,7 +508392,7 @@
]
],
"tee.any.js": [
- "b6a95368aa5e64df6ca9e15c034a1b4288883622",
+ "55d4532ff83929b53db7791be52de8a98743d0f8",
[
null,
{
@@ -512910,7 +513348,7 @@
]
],
"SVGGeometryElement.getPointAtLength-03.svg": [
- "61737efb7da187cb8bcb18c3eff49e5e204cf1c0",
+ "8d3f7e36123200a55f6d0232d4753d0b29ce1854",
[
null,
{}
@@ -516250,6 +516688,17 @@
{}
]
],
+ "case-sensitivity.any.js": [
+ "1c0b0dcac361fe02eefc1dd5035955d10dc37151",
+ [
+ "user-timing/case-sensitivity.any.html",
+ {}
+ ],
+ [
+ "user-timing/case-sensitivity.any.worker.html",
+ {}
+ ]
+ ],
"clearMarks.html": [
"92c60a3bbb856bd05bf13f12bde09dac7eefb6e6",
[
@@ -531528,6 +531977,13 @@
{}
]
],
+ "render_state_update.https.html": [
+ "2f28d442ec9889ae9cf6d54b70e1c4c64b862a0f",
+ [
+ null,
+ {}
+ ]
+ ],
"render_state_vertical_fov_immersive.https.html": [
"485438cabf6a633df42a0f94c04922e7274013e1",
[
@@ -533524,7 +533980,7 @@
},
"onerror": {
"exception-in-onerror.html": [
- "840433d3d894b1a298bbd5bbe2ea14f9fdd81ef4",
+ "d8aa02a01b8c841b2db575a1b7a77388d66d3dda",
[
null,
{}
@@ -561705,7 +562161,7 @@
]
],
"response.py": [
- "dc1328998810faacf74f1b94b54ed59f48e84e4d",
+ "cbe9e7d7fb14680f027d6fdc15d409ac19a7320c",
[
null,
{}
diff --git a/tests/wpt/metadata/css/css-flexbox/position-absolute-015.html.ini b/tests/wpt/metadata/css/css-flexbox/position-absolute-015.html.ini
new file mode 100644
index 00000000000..67ea4cdfde0
--- /dev/null
+++ b/tests/wpt/metadata/css/css-flexbox/position-absolute-015.html.ini
@@ -0,0 +1,4 @@
+[position-absolute-015.html]
+ [#abspos 1]
+ expected: FAIL
+
diff --git a/tests/wpt/metadata/css/cssom-view/CaretPosition-001.html.ini b/tests/wpt/metadata/css/cssom-view/CaretPosition-001.html.ini
deleted file mode 100644
index 4c79907309b..00000000000
--- a/tests/wpt/metadata/css/cssom-view/CaretPosition-001.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[CaretPosition-001.html]
- [Element at (400, 100)]
- expected: FAIL
-
diff --git a/tests/wpt/metadata/fetch/content-type/response.window.js.ini b/tests/wpt/metadata/fetch/content-type/response.window.js.ini
index 1c98035f7f7..8556333fa92 100644
--- a/tests/wpt/metadata/fetch/content-type/response.window.js.ini
+++ b/tests/wpt/metadata/fetch/content-type/response.window.js.ini
@@ -315,24 +315,18 @@
[<iframe>: separate response Content-Type: text/plain */*;charset=gbk]
expected: FAIL
- [<iframe>: combined response Content-Type: text/html;" text/plain]
- expected: FAIL
-
[<iframe>: separate response Content-Type: text/html;" text/plain]
expected: FAIL
- [<iframe>: separate response Content-Type: text/html */*;charset=gbk]
+ [<iframe>: combined response Content-Type: text/html;" \\" text/plain]
expected: FAIL
- [<iframe>: separate response Content-Type: text/html */*]
+ [<iframe>: combined response Content-Type: */* text/html]
expected: FAIL
- [<iframe>: separate response Content-Type: text/plain */*]
+ [<iframe>: separate response Content-Type: text/html */*]
expected: FAIL
[<iframe>: combined response Content-Type: text/html */*;charset=gbk]
expected: FAIL
- [<iframe>: separate response Content-Type: text/html;" \\" text/plain]
- expected: FAIL
-
diff --git a/tests/wpt/metadata/fetch/content-type/script.window.js.ini b/tests/wpt/metadata/fetch/content-type/script.window.js.ini
index d2df9b78483..258fe374697 100644
--- a/tests/wpt/metadata/fetch/content-type/script.window.js.ini
+++ b/tests/wpt/metadata/fetch/content-type/script.window.js.ini
@@ -56,3 +56,6 @@
[separate text/javascript x/x]
expected: FAIL
+ [separate text/javascript ]
+ expected: FAIL
+
diff --git a/tests/wpt/metadata/fetch/nosniff/parsing-nosniff.window.js.ini b/tests/wpt/metadata/fetch/nosniff/parsing-nosniff.window.js.ini
index 97db72e5d96..61682d248e2 100644
--- a/tests/wpt/metadata/fetch/nosniff/parsing-nosniff.window.js.ini
+++ b/tests/wpt/metadata/fetch/nosniff/parsing-nosniff.window.js.ini
@@ -11,9 +11,6 @@
[X-Content-Type-Options%3A%20nosniff%2C%2C%40%23%24%23%25%25%26%5E%26%5E*()()11!]
expected: FAIL
- [Content-Type-Options%3A%20nosniff]
- expected: FAIL
-
- [X-Content-Type-Options%3A%0D%0AX-Content-Type-Options%3A%20nosniff]
+ [X-Content-Type-Options%3A%20%40%23%24%23%25%25%26%5E%26%5E*()()11!%2Cnosniff]
expected: FAIL
diff --git a/tests/wpt/metadata-layout-2020/html/browsers/history/the-history-interface/traverse_the_history_3.html.ini b/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_4.html.ini
index 51f8272a6de..385376c7321 100644
--- a/tests/wpt/metadata-layout-2020/html/browsers/history/the-history-interface/traverse_the_history_3.html.ini
+++ b/tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_4.html.ini
@@ -1,4 +1,4 @@
-[traverse_the_history_3.html]
+[traverse_the_history_4.html]
[Multiple history traversals, last would be aborted]
expected: FAIL
diff --git a/tests/wpt/metadata/html/browsers/origin/cross-origin-objects/cross-origin-objects-on-new-window.html.ini b/tests/wpt/metadata/html/browsers/origin/cross-origin-objects/cross-origin-objects-on-new-window.html.ini
new file mode 100644
index 00000000000..735a9a75a2a
--- /dev/null
+++ b/tests/wpt/metadata/html/browsers/origin/cross-origin-objects/cross-origin-objects-on-new-window.html.ini
@@ -0,0 +1,2 @@
+[cross-origin-objects-on-new-window.html]
+ expected: TIMEOUT
diff --git a/tests/wpt/metadata/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/creating_browsing_context_test_01.html.ini b/tests/wpt/metadata/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/creating_browsing_context_test_01.html.ini
new file mode 100644
index 00000000000..16fa2c5cfc1
--- /dev/null
+++ b/tests/wpt/metadata/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/creating_browsing_context_test_01.html.ini
@@ -0,0 +1,4 @@
+[creating_browsing_context_test_01.html]
+ [first argument: absolute url]
+ expected: FAIL
+
diff --git a/tests/wpt/metadata/html/browsers/windows/embedded-opener-remove-frame.html.ini b/tests/wpt/metadata/html/browsers/windows/embedded-opener-remove-frame.html.ini
index 2532dceabac..fd369192a02 100644
--- a/tests/wpt/metadata/html/browsers/windows/embedded-opener-remove-frame.html.ini
+++ b/tests/wpt/metadata/html/browsers/windows/embedded-opener-remove-frame.html.ini
@@ -1,5 +1,5 @@
[embedded-opener-remove-frame.html]
- expected: CRASH
+ expected: TIMEOUT
[opener and "removed" embedded documents]
expected: FAIL
@@ -7,5 +7,5 @@
expected: FAIL
[opener of discarded auxiliary browsing context]
- expected: FAIL
+ expected: TIMEOUT
diff --git a/tests/wpt/metadata/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-flexbox.html.ini b/tests/wpt/metadata/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-flexbox.html.ini
new file mode 100644
index 00000000000..ac9b670991a
--- /dev/null
+++ b/tests/wpt/metadata/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-flexbox.html.ini
@@ -0,0 +1,2 @@
+[fieldset-flexbox.html]
+ expected: CRASH
diff --git a/tests/wpt/metadata/html/semantics/embedded-content/image-maps/image-map-processing-model/hash-name-reference.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/image-maps/image-map-processing-model/hash-name-reference.html.ini
index 98163335e40..1de3f8d68b2 100644
--- a/tests/wpt/metadata/html/semantics/embedded-content/image-maps/image-map-processing-model/hash-name-reference.html.ini
+++ b/tests/wpt/metadata/html/semantics/embedded-content/image-maps/image-map-processing-model/hash-name-reference.html.ini
@@ -172,6 +172,3 @@
[XHTML img usemap="http://example.org/#garbage-before-hash-id"]
expected: FAIL
- [HTML (standards) IMG usemap="no-hash-name"]
- expected: FAIL
-
diff --git a/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-1.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-1.html.ini
index fc37df7e3fa..2a166bb97b7 100644
--- a/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-1.html.ini
+++ b/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-1.html.ini
@@ -1,6 +1,6 @@
[iframe_sandbox_popups_escaping-1.html]
type: testharness
- expected: TIMEOUT
+ expected: CRASH
[Check that popups from a sandboxed iframe escape the sandbox if\n allow-popups-to-escape-sandbox is used]
expected: TIMEOUT
diff --git a/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-2.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-2.html.ini
index 4df5d7a35de..daa518bd0e3 100644
--- a/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-2.html.ini
+++ b/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-2.html.ini
@@ -1,4 +1,5 @@
[iframe_sandbox_popups_escaping-2.html]
+ expected: CRASH
[Check that popups from a sandboxed iframe escape the sandbox if\n allow-popups-to-escape-sandbox is used]
expected: FAIL
diff --git a/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-3.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-3.html.ini
index 5f60c78e73c..f6a7aca3306 100644
--- a/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-3.html.ini
+++ b/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-3.html.ini
@@ -1,6 +1,5 @@
[iframe_sandbox_popups_escaping-3.html]
type: testharness
- expected: TIMEOUT
[Check that popups from a sandboxed iframe escape the sandbox if\n allow-popups-to-escape-sandbox is used]
- expected: TIMEOUT
+ expected: FAIL
diff --git a/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-1.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-1.html.ini
index 9df1ac56f2a..963d4cd20ef 100644
--- a/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-1.html.ini
+++ b/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-1.html.ini
@@ -1,6 +1,6 @@
[iframe_sandbox_popups_nonescaping-1.html]
type: testharness
- expected: TIMEOUT
+ expected: CRASH
[Check that popups from a sandboxed iframe do not escape the sandbox]
expected: NOTRUN
diff --git a/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-3.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-3.html.ini
index e440b1e38c6..dc856a3d5a3 100644
--- a/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-3.html.ini
+++ b/tests/wpt/metadata/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-3.html.ini
@@ -1,6 +1,5 @@
[iframe_sandbox_popups_nonescaping-3.html]
type: testharness
- expected: TIMEOUT
[Check that popups from a sandboxed iframe do not escape the sandbox]
- expected: NOTRUN
+ expected: FAIL
diff --git a/tests/wpt/metadata/html/semantics/forms/form-submission-0/form-double-submit-3.html.ini b/tests/wpt/metadata/html/semantics/forms/form-submission-0/form-double-submit-3.html.ini
deleted file mode 100644
index 9f416703229..00000000000
--- a/tests/wpt/metadata/html/semantics/forms/form-submission-0/form-double-submit-3.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[form-double-submit-3.html]
- [<button> should have the same double-submit protection as <input type=submit>]
- expected: FAIL
-
diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url-worker-importScripts.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url-worker-importScripts.html.ini
new file mode 100644
index 00000000000..5dff48bbfe8
--- /dev/null
+++ b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url-worker-importScripts.html.ini
@@ -0,0 +1,7 @@
+[base-url-worker-importScripts.html]
+ [Relative URL-like from same-origin importScripts()]
+ expected: FAIL
+
+ [Relative URL-like from cross-origin importScripts()]
+ expected: FAIL
+
diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url.sub.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url.sub.html.ini
new file mode 100644
index 00000000000..df99f59baa0
--- /dev/null
+++ b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url.sub.html.ini
@@ -0,0 +1,7 @@
+[base-url.sub.html]
+ [Relative URL-like from cross origin classic <script> without crossorigin attribute]
+ expected: FAIL
+
+ [Relative URL-like from cross origin module <script>]
+ expected: FAIL
+
diff --git a/tests/wpt/metadata/html/webappapis/dynamic-markup-insertion/document-write/iframe_005.html.ini b/tests/wpt/metadata/html/webappapis/dynamic-markup-insertion/document-write/iframe_005.html.ini
deleted file mode 100644
index 6cf9d13975c..00000000000
--- a/tests/wpt/metadata/html/webappapis/dynamic-markup-insertion/document-write/iframe_005.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[iframe_005.html]
- [document.write external script into iframe write back into parent]
- expected: FAIL
-
diff --git a/tests/wpt/metadata/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-delayed.html.ini b/tests/wpt/metadata/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-delayed.html.ini
new file mode 100644
index 00000000000..fca4d908c89
--- /dev/null
+++ b/tests/wpt/metadata/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-delayed.html.ini
@@ -0,0 +1,4 @@
+[module-static-import-delayed.html]
+ [document.write in an imported module]
+ expected: FAIL
+
diff --git a/tests/wpt/metadata/html/webappapis/scripting/events/compile-event-handler-settings-objects.html.ini b/tests/wpt/metadata/html/webappapis/scripting/events/compile-event-handler-settings-objects.html.ini
index 01f7b72cbe7..edae5e5adcd 100644
--- a/tests/wpt/metadata/html/webappapis/scripting/events/compile-event-handler-settings-objects.html.ini
+++ b/tests/wpt/metadata/html/webappapis/scripting/events/compile-event-handler-settings-objects.html.ini
@@ -5,5 +5,5 @@
expected: TIMEOUT
[The entry settings object while executing the compiled callback via Web IDL's invoke must be that of the node document]
- expected: FAIL
+ expected: TIMEOUT
diff --git a/tests/wpt/metadata/streams/readable-streams/tee.any.js.ini b/tests/wpt/metadata/streams/readable-streams/tee.any.js.ini
index 75b63daffbc..953e38f599b 100644
--- a/tests/wpt/metadata/streams/readable-streams/tee.any.js.ini
+++ b/tests/wpt/metadata/streams/readable-streams/tee.any.js.ini
@@ -2,34 +2,58 @@
expected: ERROR
[tee.any.worker.html]
- expected: ERROR
+ expected: TIMEOUT
[ReadableStreamTee should not pull more chunks than can fit in the branch queue]
- expected: FAIL
+ expected: NOTRUN
[ReadableStreamTee stops pulling when original stream errors while branch 1 is reading]
- expected: FAIL
+ expected: NOTRUN
[ReadableStreamTee stops pulling when original stream errors while both branches are reading]
- expected: FAIL
+ expected: NOTRUN
[ReadableStreamTee stops pulling when original stream errors while branch 2 is reading]
- expected: FAIL
+ expected: NOTRUN
+
+ [ReadableStream teeing: canceling branch1 should finish when branch2 reads until end of stream]
+ expected: TIMEOUT
+
+ [ReadableStream teeing: canceling branch1 should finish when original stream errors]
+ expected: NOTRUN
+
+ [ReadableStreamTee should only pull enough to fill the emptiest queue]
+ expected: NOTRUN
+
+ [ReadableStreamTee should not pull when original is already errored]
+ expected: NOTRUN
[tee.any.serviceworker.html]
expected: ERROR
[tee.any.html]
- expected: ERROR
+ expected: TIMEOUT
[ReadableStreamTee should not pull more chunks than can fit in the branch queue]
- expected: FAIL
+ expected: NOTRUN
[ReadableStreamTee stops pulling when original stream errors while branch 1 is reading]
- expected: FAIL
+ expected: NOTRUN
[ReadableStreamTee stops pulling when original stream errors while both branches are reading]
- expected: FAIL
+ expected: NOTRUN
[ReadableStreamTee stops pulling when original stream errors while branch 2 is reading]
- expected: FAIL
+ expected: NOTRUN
+
+ [ReadableStream teeing: canceling branch1 should finish when branch2 reads until end of stream]
+ expected: TIMEOUT
+
+ [ReadableStream teeing: canceling branch1 should finish when original stream errors]
+ expected: NOTRUN
+
+ [ReadableStreamTee should only pull enough to fill the emptiest queue]
+ expected: NOTRUN
+
+ [ReadableStreamTee should not pull when original is already errored]
+ expected: NOTRUN
diff --git a/tests/wpt/metadata/workers/interfaces/WorkerGlobalScope/onerror/exception-in-onerror.html.ini b/tests/wpt/metadata/workers/interfaces/WorkerGlobalScope/onerror/exception-in-onerror.html.ini
new file mode 100644
index 00000000000..ae39ac39151
--- /dev/null
+++ b/tests/wpt/metadata/workers/interfaces/WorkerGlobalScope/onerror/exception-in-onerror.html.ini
@@ -0,0 +1,49 @@
+[exception-in-onerror.html]
+ [Throw in setTimeout(string): classic: listener]
+ expected: FAIL
+
+ [Throw in setTimeout(function): module: listener]
+ expected: FAIL
+
+ [Throw in worker initialization: classic: handler]
+ expected: FAIL
+
+ [Throw in message handler: classic: listener]
+ expected: FAIL
+
+ [Throw in setTimeout(function): classic: handler]
+ expected: FAIL
+
+ [Throw in message handler: module: handler]
+ expected: FAIL
+
+ [Throw in setTimeout(function): module: handler]
+ expected: FAIL
+
+ [Throw in worker initialization: module: handler]
+ expected: FAIL
+
+ [Throw in setTimeout(string): module: listener]
+ expected: FAIL
+
+ [Throw in message handler: classic: handler]
+ expected: FAIL
+
+ [Throw in worker initialization: classic: listener]
+ expected: FAIL
+
+ [Throw in message handler: module: listener]
+ expected: FAIL
+
+ [Throw in setTimeout(string): module: handler]
+ expected: FAIL
+
+ [Throw in setTimeout(function): classic: listener]
+ expected: FAIL
+
+ [Throw in worker initialization: module: listener]
+ expected: FAIL
+
+ [Throw in setTimeout(string): classic: handler]
+ expected: FAIL
+
diff --git a/tests/wpt/mozilla/meta-layout-2020/mozilla/hit_test_multiple_sc.html.ini b/tests/wpt/mozilla/meta-layout-2020/mozilla/hit_test_multiple_sc.html.ini
deleted file mode 100644
index 8ed8088a59f..00000000000
--- a/tests/wpt/mozilla/meta-layout-2020/mozilla/hit_test_multiple_sc.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[hit_test_multiple_sc.html]
- [Hit testing works for following stacking contexts]
- expected: FAIL
-
diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json
index b4d358816e2..3fc5519a4cc 100644
--- a/tests/wpt/mozilla/meta/MANIFEST.json
+++ b/tests/wpt/mozilla/meta/MANIFEST.json
@@ -14718,6 +14718,13 @@
{}
]
],
+ "layerevents.html": [
+ "6a0319366ec842a9b94d5897978975ebe3eb6f7f",
+ [
+ null,
+ {}
+ ]
+ ],
"layers.html": [
"b6749f208a8f3c5ae78fbe72cfa7364829abb127",
[
diff --git a/tests/wpt/mozilla/meta/mozilla/getBoundingClientRect.html.ini b/tests/wpt/mozilla/meta/mozilla/getBoundingClientRect.html.ini
new file mode 100644
index 00000000000..dcd88accd43
--- /dev/null
+++ b/tests/wpt/mozilla/meta/mozilla/getBoundingClientRect.html.ini
@@ -0,0 +1,4 @@
+[getBoundingClientRect.html]
+ [getBoundingClientRect 1]
+ expected: FAIL
+
diff --git a/tests/wpt/mozilla/meta/mozilla/hit-test-background.html.ini b/tests/wpt/mozilla/meta/mozilla/hit-test-background.html.ini
deleted file mode 100644
index 7b9e9d1430f..00000000000
--- a/tests/wpt/mozilla/meta/mozilla/hit-test-background.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[hit-test-background.html]
- [Hit testing backgrounds of content should report the same element as the content]
- expected: FAIL
-
diff --git a/tests/wpt/mozilla/meta/mozilla/hit_test_multiple_sc.html.ini b/tests/wpt/mozilla/meta/mozilla/hit_test_multiple_sc.html.ini
deleted file mode 100644
index 8ed8088a59f..00000000000
--- a/tests/wpt/mozilla/meta/mozilla/hit_test_multiple_sc.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[hit_test_multiple_sc.html]
- [Hit testing works for following stacking contexts]
- expected: FAIL
-
diff --git a/tests/wpt/mozilla/meta/mozilla/hit_test_pos_fixed.html.ini b/tests/wpt/mozilla/meta/mozilla/hit_test_pos_fixed.html.ini
deleted file mode 100644
index 9f5b10bd6af..00000000000
--- a/tests/wpt/mozilla/meta/mozilla/hit_test_pos_fixed.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[hit_test_pos_fixed.html]
- [Hit-test of an element with position: fixed should discard scroll offset]
- expected: FAIL
-
diff --git a/tests/wpt/mozilla/meta/webxr/layerevents.html.ini b/tests/wpt/mozilla/meta/webxr/layerevents.html.ini
new file mode 100644
index 00000000000..72e1e4fc0b2
--- /dev/null
+++ b/tests/wpt/mozilla/meta/webxr/layerevents.html.ini
@@ -0,0 +1 @@
+prefs: [dom.webxr.layers.enabled:true]
diff --git a/tests/wpt/mozilla/tests/webxr/layerevents.html b/tests/wpt/mozilla/tests/webxr/layerevents.html
new file mode 100644
index 00000000000..6a0319366ec
--- /dev/null
+++ b/tests/wpt/mozilla/tests/webxr/layerevents.html
@@ -0,0 +1,36 @@
+<html>
+ <head>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="./resources/webxr-util.js"></script>
+ </head>
+ <body>
+ <canvas id="canvas" width="640" height="480"></canvas>
+
+ <script>
+ let canvas = document.getElementById("canvas");
+ let gl = canvas.getContext('webgl');
+ promise_test(async function() {
+ let mock = await navigator.xr.test.simulateDeviceConnection({
+ supportedModes: ["immersive-vr"],
+ views: TEST_VIEWS,
+ viewerOrigin: {position: [0.5, 0.1, 0.1], orientation: [1, 0, 0, 1] }
+ });
+ let sessionPromise;
+ navigator.xr.test.simulateUserActivation(() => {
+ sessionPromise = navigator.xr.requestSession("immersive-vr");
+ });
+ let session = await sessionPromise;
+ let glLayerFactory = new XRWebGLBinding(session, gl);
+ let layer = new XRWebGLLayer(session, gl);
+ let event = new XRLayerEvent("foo", { layer: layer, bubbles: true });
+
+ assert_equals(event.type, "foo", "XRLeventLayer construxctor sets type");
+ assert_equals(event.bubbles, true, "XRLeventLayer construxctor sets bubbles");
+ assert_equals(event.cancelable, false, "XRLeventLayer construxctor sets cancelable");
+ assert_equals(event.isTrusted, false, "XRLeventLayer construxctor sets trusted");
+ assert_equals(event.layer, layer, "XRLeventLayer construxctor sets layer");
+ });
+ </script>
+ </body>
+</html>
diff --git a/tests/wpt/web-platform-tests/.taskcluster.yml b/tests/wpt/web-platform-tests/.taskcluster.yml
index 526fc13212e..b1a8162db4b 100644
--- a/tests/wpt/web-platform-tests/.taskcluster.yml
+++ b/tests/wpt/web-platform-tests/.taskcluster.yml
@@ -7,7 +7,7 @@ tasks:
run_task:
$if: 'tasks_for == "github-push"'
then:
- $if: 'event.ref in ["refs/heads/master", "refs/heads/epochs/daily", "refs/heads/epochs/weekly", "refs/heads/triggers/chrome_stable", "refs/heads/triggers/chrome_beta", "refs/heads/triggers/chrome_dev", "refs/heads/triggers/firefox_stable", "refs/heads/triggers/firefox_beta", "refs/heads/triggers/firefox_nightly", "refs/heads/triggers/webkitgtk_minibrowser_stable", "refs/heads/triggers/webkitgtk_minibrowser_nightly", "refs/heads/triggers/servo_nightly"]'
+ $if: 'event.ref in ["refs/heads/master", "refs/heads/epochs/daily", "refs/heads/epochs/weekly", "refs/heads/triggers/chrome_stable", "refs/heads/triggers/chrome_beta", "refs/heads/triggers/chrome_dev", "refs/heads/triggers/chrome_nightly", "refs/heads/triggers/firefox_stable", "refs/heads/triggers/firefox_beta", "refs/heads/triggers/firefox_nightly", "refs/heads/triggers/webkitgtk_minibrowser_stable", "refs/heads/triggers/webkitgtk_minibrowser_nightly", "refs/heads/triggers/servo_nightly"]'
then: true
else: false
else:
diff --git a/tests/wpt/web-platform-tests/content-security-policy/reporting/report-frame-ancestors-with-x-frame-options.sub.html b/tests/wpt/web-platform-tests/content-security-policy/reporting/report-frame-ancestors-with-x-frame-options.sub.html
new file mode 100644
index 00000000000..0c58a5efd54
--- /dev/null
+++ b/tests/wpt/web-platform-tests/content-security-policy/reporting/report-frame-ancestors-with-x-frame-options.sub.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <title>Reporting works with report-only frame-ancestors even if frame is blocked by X-Frame-Options</title>
+</head>
+<body>
+ <iframe src="./support/not-embeddable-frame.py?reportID={{$id:uuid()}}&reportOnly=true&xFrameOptions=DENY"></iframe>
+ <script async defer src='../support/checkReport.sub.js?reportField=violated-directive&reportValue=frame-ancestors&reportID={{$id}}'></script>
+</body>
+</html>
diff --git a/tests/wpt/web-platform-tests/content-security-policy/reporting/report-frame-ancestors.sub.html b/tests/wpt/web-platform-tests/content-security-policy/reporting/report-frame-ancestors.sub.html
new file mode 100644
index 00000000000..cd7bbcb9731
--- /dev/null
+++ b/tests/wpt/web-platform-tests/content-security-policy/reporting/report-frame-ancestors.sub.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <title>Reporting works with frame-ancestors</title>
+</head>
+<body>
+ <iframe src="./support/not-embeddable-frame.py?reportID={{$id:uuid()}}"></iframe>
+ <script async defer src='../support/checkReport.sub.js?reportField=violated-directive&reportValue=frame-ancestors&reportID={{$id}}'></script>
+</body>
+</html>
diff --git a/tests/wpt/web-platform-tests/content-security-policy/reporting/support/not-embeddable-frame.py b/tests/wpt/web-platform-tests/content-security-policy/reporting/support/not-embeddable-frame.py
new file mode 100644
index 00000000000..50f9c83cf5c
--- /dev/null
+++ b/tests/wpt/web-platform-tests/content-security-policy/reporting/support/not-embeddable-frame.py
@@ -0,0 +1,10 @@
+def main(request, response):
+ headers = []
+ if request.GET.first(b'xFrameOptions', None):
+ headers.append((b'X-Frame-Options', request.GET[b'xFrameOptions']))
+
+ csp_header = b'Content-Security-Policy-Report-Only' \
+ if request.GET.first(b'reportOnly', None) == 'true' else b'Content-Security-Policy'
+ headers.append((csp_header, b"frame-ancestors 'none'; report-uri ../../support/report.py?op=put&reportID=" + request.GET[b'reportID']))
+
+ return headers, b'{}'
diff --git a/tests/wpt/web-platform-tests/content-security-policy/sandbox/meta-element.sub.html b/tests/wpt/web-platform-tests/content-security-policy/sandbox/meta-element.sub.html
new file mode 100644
index 00000000000..cd8da8f14c4
--- /dev/null
+++ b/tests/wpt/web-platform-tests/content-security-policy/sandbox/meta-element.sub.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<meta content="sandbox allow-scripts" http-equiv="Content-Security-Policy">
+<body>
+<iframe id="iframe"></iframe>
+<script>
+// According to
+// https://html.spec.whatwg.org/multipage/semantics.html#attr-meta-http-equiv-content-security-policy
+// `sandbox` directives must be ignored when delivered via `<meta>`.
+test(() => {
+ assert_equals(location.origin, "{{location[scheme]}}://{{location[host]}}");
+}, "Document shouldn't be sandboxed by <meta>");
+
+// Note: sandbox directive for workers are not yet specified.
+// https://github.com/w3c/webappsec-csp/issues/279
+// Anyway workers shouldn't be affected by sandbox directives in `<meta>`.
+async_test(t => {
+ const worker = new Worker("support/post-origin-on-load-worker.js");
+ worker.onerror = t.unreached_func("Worker construction failed");
+ worker.onmessage = t.step_func_done(e => {
+ assert_equals(e.data, "{{location[scheme]}}://{{location[host]}}");
+ });
+}, "Worker shouldn't be sandboxed by inheriting <meta>");
+
+parent.async_test(t => {
+ // Although <iframe about:blank> should inherit parent's CSP,
+ // sandbox directives in <meta> should be ignored in the first place,
+ // so workers created from such <iframe>s shouldn't also be sandboxed.
+ const iframeDocument = document.querySelector("#iframe").contentDocument;
+ const script = iframeDocument.createElement("script");
+ script.innerText = `
+ const worker = new Worker("support/post-origin-on-load-worker.js");
+ worker.onerror = () => parent.postMessage("onerror", "*");
+ worker.onmessage = (e) => parent.postMessage(e.data, "*");
+ `;
+ iframeDocument.body.appendChild(script);
+
+ // Receive message from <iframe>.
+ onmessage = t.step_func_done(e => {
+ assert_equals(e.data, "{{location[scheme]}}://{{location[host]}}");
+ });
+}, "Worker shouldn't be sandboxed when created <iframe> inheriting parent's CSP with sandbox <meta>");
+</script>
+</body>
diff --git a/tests/wpt/web-platform-tests/content-security-policy/sandbox/support/post-origin-on-load-worker.js b/tests/wpt/web-platform-tests/content-security-policy/sandbox/support/post-origin-on-load-worker.js
new file mode 100644
index 00000000000..21ce5748ab8
--- /dev/null
+++ b/tests/wpt/web-platform-tests/content-security-policy/sandbox/support/post-origin-on-load-worker.js
@@ -0,0 +1 @@
+postMessage(self.origin);
diff --git a/tests/wpt/web-platform-tests/css/css-break/forced-break-at-fragmentainer-start-000.html b/tests/wpt/web-platform-tests/css/css-break/forced-break-at-fragmentainer-start-000.html
new file mode 100644
index 00000000000..d5796ba641b
--- /dev/null
+++ b/tests/wpt/web-platform-tests/css/css-break/forced-break-at-fragmentainer-start-000.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/css-break-3/#forced-breaks">
+<link rel="help" href="https://www.w3.org/TR/css-break-3/#unforced-breaks">
+<meta name="assert" content="A forced break at the block-start of the fragmentainer is allowed, as long as it's otherwise at a valid class A break point">
+<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
+<p>Test passes if there is a filled green square.</p>
+<div style="columns:1; column-fill:auto; width:100px; height:100px; background:green;">
+ <div style="break-after:column;"></div>
+ <div style="height:99px; background:white;"></div>
+</div>
diff --git a/tests/wpt/web-platform-tests/css/css-break/forced-break-at-fragmentainer-start-001.html b/tests/wpt/web-platform-tests/css/css-break/forced-break-at-fragmentainer-start-001.html
new file mode 100644
index 00000000000..b3ad80ca9a0
--- /dev/null
+++ b/tests/wpt/web-platform-tests/css/css-break/forced-break-at-fragmentainer-start-001.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/css-break-3/#forced-breaks">
+<link rel="help" href="https://www.w3.org/TR/css-break-3/#unforced-breaks">
+<meta name="assert" content="A forced break at the block-start of the fragmentainer is not allowed unless it's at a valid class A break point">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="columns:2; column-fill:auto; column-gap:0; width:100px; height:100px; background:red;">
+ <div>
+ <div style="break-before:column; height:200px; background:green;"></div>
+ </div>
+</div>
diff --git a/tests/wpt/web-platform-tests/css/css-contain/content-visibility/content-visibility-074-ref.html b/tests/wpt/web-platform-tests/css/css-contain/content-visibility/content-visibility-074-ref.html
new file mode 100644
index 00000000000..82a6c263fa9
--- /dev/null
+++ b/tests/wpt/web-platform-tests/css/css-contain/content-visibility/content-visibility-074-ref.html
@@ -0,0 +1,35 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>CSS Content Visibility: toggling auto with composited descedant (reference)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<style>
+#a { will-change: transform; }
+#b { height: 15000px; }
+#c {
+ width: 800px;
+ height: 600px;
+}
+#d {
+ will-change: transform;
+ top: 0px;
+ width: 500px;
+ height: 500px;
+ background: green;
+}
+.contain {
+ contain: layout style paint;
+}
+
+</style>
+
+<div id="a">
+</div>
+<div id="b">
+ <div id="c" class=contain>
+ <div id="d"></div>
+ </div>
+ </div>
+</div>
diff --git a/tests/wpt/web-platform-tests/css/css-contain/content-visibility/content-visibility-074.html b/tests/wpt/web-platform-tests/css/css-contain/content-visibility/content-visibility-074.html
new file mode 100644
index 00000000000..ff6381ce3d0
--- /dev/null
+++ b/tests/wpt/web-platform-tests/css/css-contain/content-visibility/content-visibility-074.html
@@ -0,0 +1,69 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: toggling auto with composited descedant</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-074-ref.html">
+<meta name="assert" content="after toggling content-visibility auto a few times, composited descedant is visible.">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+#a { will-change: transform; }
+#b { height: 15000px; }
+#c {
+ width: 800px;
+ height: 600px;
+}
+#d {
+ will-change: transform;
+ top: 0px;
+ width: 500px;
+ height: 500px;
+ background: green;
+}
+.auto {
+ content-visibility: auto;
+}
+
+</style>
+
+<div id="a">
+</div>
+<div id="b">
+ <div id="c" class=auto>
+ <div id="d"></div>
+ </div>
+ </div>
+</div>
+
+<script>
+function runTest(step) {
+ if (step % 2 == 0) {
+ requestAnimationFrame(() => runTest(step + 1));
+ return;
+ }
+
+ switch(step) {
+ case 1:
+ document.getElementById("c").classList.remove("auto");
+ break;
+ case 3:
+ document.getElementById("c").classList.add("auto");
+ break;
+ case 5:
+ document.getElementById("c").classList.remove("auto");
+ break;
+ case 7:
+ document.getElementById("c").classList.add("auto");
+ break;
+ case 9:
+ takeScreenshot();
+ return;
+ }
+ requestAnimationFrame(() => runTest(step + 1));
+}
+
+window.onload = () => requestAnimationFrame(() => runTest(0));
+</script>
diff --git a/tests/wpt/web-platform-tests/css/css-flexbox/position-absolute-015.html b/tests/wpt/web-platform-tests/css/css-flexbox/position-absolute-015.html
new file mode 100644
index 00000000000..1c0f3bc4c28
--- /dev/null
+++ b/tests/wpt/web-platform-tests/css/css-flexbox/position-absolute-015.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<title>abspos flex children with top margins</title>
+<link rel="author" title="Manuel Rego" href="mailto:rego@igalia.com">
+<link rel="author" title="David Grogan" href="mailto:dgrogan@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-flexbox/#abspos-items">
+<link rel="bookmark" href="https://crbug.com/886592">
+<meta name="assert" content="Check abspos position of flex children with margins in justify-content: flex-end container.">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+
+<div style="display: flex; width: 200px; height: 100px; justify-content: flex-end; border: solid thick; position: relative;">
+ <div style="background: cyan; margin: 20px; position: absolute; width: 30px; height: 40px;" data-offset-x="150" id="abspos"></div>
+</div>
+
+<script>
+checkLayout('#abspos');
+</script>
diff --git a/tests/wpt/web-platform-tests/css/css-flexbox/quirks-auto-block-size-with-percentage-item.html b/tests/wpt/web-platform-tests/css/css-flexbox/quirks-auto-block-size-with-percentage-item.html
index 966f39f1739..f5c3d7c1818 100644
--- a/tests/wpt/web-platform-tests/css/css-flexbox/quirks-auto-block-size-with-percentage-item.html
+++ b/tests/wpt/web-platform-tests/css/css-flexbox/quirks-auto-block-size-with-percentage-item.html
@@ -2,6 +2,14 @@
<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
<link rel="help" href="https://www.w3.org/TR/CSS22/visudet.html#the-height-property">
<meta name="assert" content="The percentage height resolution quirk isn't applied to flexboxes.">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+
+<!-- Have to wait for onload to fire to ensure the image is loaded. -->
+<body onload="checkLayout('#container')">
+
<p>There should be a green square to the left of a blue square, and no red.</p>
<div id="container" style="width:200px; height:456px;">
<div style="display:flex; background:blue;" data-expected-height="100">
@@ -9,9 +17,3 @@
<div style="width: 50px; height: 100%; background: red;" data-expected-height="0"></div>
</div>
</div>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/resources/check-layout-th.js"></script>
-<script>
- checkLayout("#container");
-</script>
diff --git a/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-1-ref.html b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-1-ref.html
new file mode 100644
index 00000000000..6a7862c9acb
--- /dev/null
+++ b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-1-ref.html
@@ -0,0 +1,39 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSS Test Reference</title>
+<style>
+ body {
+ line-height: 0;
+ }
+
+ div {
+ display: inline-block;
+ height: 250px;
+ width: 350px;
+ background: purple;
+ margin: 10px;
+ }
+
+ svg {
+ display: block;
+ background: green;
+ }
+ .justify {
+ width: 350px;
+ }
+ .align {
+ height: 250px;
+ }
+</style>
+<div>
+ <svg class="align justify"></svg>
+</div>
+<div>
+ <svg class="align"></svg>
+</div>
+<div>
+ <svg class="justify"></svg>
+</div>
+<div>
+ <svg></svg>
+</div>
diff --git a/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-1.html b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-1.html
new file mode 100644
index 00000000000..1b5ae0a6ad8
--- /dev/null
+++ b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-1.html
@@ -0,0 +1,45 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>stretching works for replaced items with no aspect ratio</title>
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-grid">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1656281">
+<link rel="match" href="grid-item-no-aspect-ratio-stretch-1-ref.html">
+<style>
+ body {
+ line-height: 0;
+ }
+
+ div {
+ display: inline-grid;
+ height: 250px;
+ width: 350px;
+ background: purple;
+ margin: 10px;
+ vertical-align: top;
+ }
+
+ svg {
+ background: green;
+ }
+
+ .justify {
+ justify-self: stretch;
+ }
+ .align {
+ align-self: stretch;
+ }
+</style>
+<div>
+ <svg class="align justify"></svg>
+</div>
+<div>
+ <svg class="align"></svg>
+</div>
+<div>
+ <svg class="justify"></svg>
+</div>
+<div>
+ <svg></svg>
+</div>
diff --git a/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-10.html b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-10.html
new file mode 100644
index 00000000000..6d8d7e848c2
--- /dev/null
+++ b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-10.html
@@ -0,0 +1,50 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>stretching works for replaced items with no aspect ratio</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-grid">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1656281">
+<link rel="match" href="grid-item-no-aspect-ratio-stretch-8-ref.html">
+<style>
+ body {
+ line-height: 0;
+ }
+
+ div {
+ display: inline-grid;
+ height: 250px;
+ width: 350px;
+ background: grey;
+ margin: 10px;
+ vertical-align: top;
+ }
+
+ .justify {
+ justify-self: stretch;
+ }
+ .align {
+ align-self: stretch;
+ }
+</style>
+<div>
+ <img class="align justify">
+</div>
+<div>
+ <img class="align">
+</div>
+<div>
+ <img class="justify">
+</div>
+<div>
+ <img>
+</div>
+
+<script>
+var url = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="0px" height="0px"><circle cx="50%" cy="50%" r="50%" fill="blue"/></svg>'
+var imgs = document.querySelectorAll('img');
+for (var i = 0; i < imgs.length; ++i) {
+ var img = imgs[i];
+ img.src = url;
+}
+</script>
diff --git a/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-2-ref.html b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-2-ref.html
new file mode 100644
index 00000000000..69d59e85a3c
--- /dev/null
+++ b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-2-ref.html
@@ -0,0 +1,53 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Reference: stretching works for replaced items with no aspect ratio</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<style>
+ body {
+ line-height: 0;
+ }
+
+ div {
+ display: inline-block;
+ height: 250px;
+ width: 350px;
+ background: grey;
+ margin: 10px;
+ vertical-align: top;
+ }
+
+ img {
+ display: block;
+ width: 300px;
+ height: 150px;
+ }
+
+ .justify {
+ width: 350px;
+ }
+ .align {
+ height: 250px;
+ }
+</style>
+<div>
+ <img class="align justify">
+</div>
+<div>
+ <img class="align" style="width:20px">
+</div>
+<div>
+ <img class="justify">
+</div>
+<div>
+ <img style="width:20px">
+</div>
+
+<script>
+var url = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="20px"><circle cx="50%" cy="50%" r="50%" fill="blue"/></svg>'
+var imgs = document.querySelectorAll('img');
+for (var i = 0; i < imgs.length; ++i) {
+ var img = imgs[i];
+ img.src = url;
+}
+</script>
diff --git a/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-2.html b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-2.html
new file mode 100644
index 00000000000..5371e560a5f
--- /dev/null
+++ b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-2.html
@@ -0,0 +1,50 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>stretching works for replaced items with no aspect ratio</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-grid">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1656281">
+<link rel="match" href="grid-item-no-aspect-ratio-stretch-2-ref.html">
+<style>
+ body {
+ line-height: 0;
+ }
+
+ div {
+ display: inline-grid;
+ height: 250px;
+ width: 350px;
+ background: grey;
+ margin: 10px;
+ vertical-align: top;
+ }
+
+ .justify {
+ justify-self: stretch;
+ }
+ .align {
+ align-self: stretch;
+ }
+</style>
+<div>
+ <img class="align justify">
+</div>
+<div>
+ <img class="align">
+</div>
+<div>
+ <img class="justify">
+</div>
+<div>
+ <img>
+</div>
+
+<script>
+var url = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="20px"><circle cx="50%" cy="50%" r="50%" fill="blue"/></svg>'
+var imgs = document.querySelectorAll('img');
+for (var i = 0; i < imgs.length; ++i) {
+ var img = imgs[i];
+ img.src = url;
+}
+</script>
diff --git a/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-3-ref.html b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-3-ref.html
new file mode 100644
index 00000000000..7ee8a2d6bdc
--- /dev/null
+++ b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-3-ref.html
@@ -0,0 +1,53 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Reference: stretching works for replaced items with no aspect ratio</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<style>
+ body {
+ line-height: 0;
+ }
+
+ div {
+ display: inline-block;
+ height: 250px;
+ width: 350px;
+ background: grey;
+ margin: 10px;
+ vertical-align: top;
+ }
+
+ img {
+ display: block;
+ width: 300px;
+ height: 150px;
+ }
+
+ .justify {
+ width: 350px;
+ }
+ .align {
+ height: 250px;
+ }
+</style>
+<div>
+ <img class="align justify">
+</div>
+<div>
+ <img class="align">
+</div>
+<div>
+ <img class="justify" style="height:20px">
+</div>
+<div>
+ <img style="height:20px">
+</div>
+
+<script>
+var url = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" height="20px"><circle cx="50%" cy="50%" r="50%" fill="blue"/></svg>'
+var imgs = document.querySelectorAll('img');
+for (var i = 0; i < imgs.length; ++i) {
+ var img = imgs[i];
+ img.src = url;
+}
+</script>
diff --git a/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-3.html b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-3.html
new file mode 100644
index 00000000000..e2b05bd2166
--- /dev/null
+++ b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-3.html
@@ -0,0 +1,50 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>stretching works for replaced items with no aspect ratio</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-grid">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1656281">
+<link rel="match" href="grid-item-no-aspect-ratio-stretch-3-ref.html">
+<style>
+ body {
+ line-height: 0;
+ }
+
+ div {
+ display: inline-grid;
+ height: 250px;
+ width: 350px;
+ background: grey;
+ margin: 10px;
+ vertical-align: top;
+ }
+
+ .justify {
+ justify-self: stretch;
+ }
+ .align {
+ align-self: stretch;
+ }
+</style>
+<div>
+ <img class="align justify">
+</div>
+<div>
+ <img class="align">
+</div>
+<div>
+ <img class="justify">
+</div>
+<div>
+ <img>
+</div>
+
+<script>
+var url = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" height="20px"><circle cx="50%" cy="50%" r="50%" fill="blue"/></svg>'
+var imgs = document.querySelectorAll('img');
+for (var i = 0; i < imgs.length; ++i) {
+ var img = imgs[i];
+ img.src = url;
+}
+</script>
diff --git a/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-4-ref.html b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-4-ref.html
new file mode 100644
index 00000000000..9edb8aa76f8
--- /dev/null
+++ b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-4-ref.html
@@ -0,0 +1,53 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Reference: stretching works for replaced items with no aspect ratio</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<style>
+ body {
+ line-height: 0;
+ }
+
+ div {
+ display: inline-block;
+ height: 250px;
+ width: 350px;
+ background: grey;
+ margin: 10px;
+ vertical-align: top;
+ }
+
+ img {
+ display: block;
+ width: 300px;
+ height: 150px;
+ }
+
+ .justify {
+ width: 350px;
+ }
+ .align {
+ height: 250px;
+ }
+</style>
+<div>
+ <img class="align justify">
+</div>
+<div>
+ <img class="align" style="width:10px">
+</div>
+<div>
+ <img class="justify" style="height:20px">
+</div>
+<div>
+ <img style="width:10px; height:20px">
+</div>
+
+<script>
+var url = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 100"><circle cx="50%" cy="50%" r="50%" fill="blue"/></svg>'
+var imgs = document.querySelectorAll('img');
+for (var i = 0; i < imgs.length; ++i) {
+ var img = imgs[i];
+ img.src = url;
+}
+</script>
diff --git a/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-4.html b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-4.html
new file mode 100644
index 00000000000..1cf2849dad3
--- /dev/null
+++ b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-4.html
@@ -0,0 +1,50 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>stretching works for replaced items with no aspect ratio</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-grid">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1656281">
+<link rel="match" href="grid-item-no-aspect-ratio-stretch-4-ref.html">
+<style>
+ body {
+ line-height: 0;
+ }
+
+ div {
+ display: inline-grid;
+ height: 250px;
+ width: 350px;
+ background: grey;
+ margin: 10px;
+ vertical-align: top;
+ }
+
+ .justify {
+ justify-self: stretch;
+ }
+ .align {
+ align-self: stretch;
+ }
+</style>
+<div>
+ <img class="align justify">
+</div>
+<div>
+ <img class="align">
+</div>
+<div>
+ <img class="justify">
+</div>
+<div>
+ <img>
+</div>
+
+<script>
+var url = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 0 50 100"><circle cx="50%" cy="50%" r="50%" fill="blue"/></svg>'
+var imgs = document.querySelectorAll('img');
+for (var i = 0; i < imgs.length; ++i) {
+ var img = imgs[i];
+ img.src = url;
+}
+</script>
diff --git a/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-5-ref.html b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-5-ref.html
new file mode 100644
index 00000000000..6a3446534a1
--- /dev/null
+++ b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-5-ref.html
@@ -0,0 +1,53 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Reference: stretching works for replaced items with no aspect ratio</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<style>
+ body {
+ line-height: 0;
+ }
+
+ div {
+ display: inline-block;
+ height: 250px;
+ width: 350px;
+ background: grey;
+ margin: 10px;
+ vertical-align: top;
+ }
+
+ img {
+ display: block;
+ width: 300px;
+ height: 150px;
+ }
+
+ .justify {
+ width: 350px;
+ }
+ .align {
+ height: 250px;
+ }
+</style>
+<div>
+ <img class="align justify">
+</div>
+<div>
+ <img class="align" style="width:20px">
+</div>
+<div>
+ <img class="justify" style="width:350px; height:40px">
+</div>
+<div>
+ <img style="width:20px; height:40px">
+</div>
+
+<script>
+var url = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 100"><circle cx="50%" cy="50%" r="50%" fill="blue"/></svg>'
+var imgs = document.querySelectorAll('img');
+for (var i = 0; i < imgs.length; ++i) {
+ var img = imgs[i];
+ img.src = url;
+}
+</script>
diff --git a/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-5.html b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-5.html
new file mode 100644
index 00000000000..3000e9d97a1
--- /dev/null
+++ b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-5.html
@@ -0,0 +1,50 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>stretching works for replaced items with no aspect ratio</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-grid">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1656281">
+<link rel="match" href="grid-item-no-aspect-ratio-stretch-5-ref.html">
+<style>
+ body {
+ line-height: 0;
+ }
+
+ div {
+ display: inline-grid;
+ height: 250px;
+ width: 350px;
+ background: grey;
+ margin: 10px;
+ vertical-align: top;
+ }
+
+ .justify {
+ justify-self: stretch;
+ }
+ .align {
+ align-self: stretch;
+ }
+</style>
+<div>
+ <img class="align justify">
+</div>
+<div>
+ <img class="align">
+</div>
+<div>
+ <img class="justify">
+</div>
+<div>
+ <img>
+</div>
+
+<script>
+var url = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="20px" viewBox="0 0 50 100"><circle cx="50%" cy="50%" r="50%" fill="blue"/></svg>'
+var imgs = document.querySelectorAll('img');
+for (var i = 0; i < imgs.length; ++i) {
+ var img = imgs[i];
+ img.src = url;
+}
+</script>
diff --git a/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-6-ref.html b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-6-ref.html
new file mode 100644
index 00000000000..33f472e71b8
--- /dev/null
+++ b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-6-ref.html
@@ -0,0 +1,54 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Reference: stretching works for replaced items with no aspect ratio</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<style>
+ body {
+ line-height: 0;
+ }
+
+ div {
+ display: inline-block;
+ height: 250px;
+ width: 350px;
+ background: grey;
+ margin: 10px;
+ vertical-align: top;
+ }
+
+ img {
+ display: block;
+ width: 300px;
+ height: 150px;
+ background: blue;
+ }
+
+ .justify {
+ width: 350px;
+ }
+ .align {
+ height: 250px;
+ }
+</style>
+<div>
+ <img class="align justify">
+</div>
+<div>
+ <img class="align" style="width:0px">
+</div>
+<div>
+ <img class="justify" style="height:20px">
+</div>
+<div>
+ <img style="width:0px; height:20px">
+</div>
+
+<script>
+var url = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg"></svg>'
+var imgs = document.querySelectorAll('img');
+for (var i = 0; i < imgs.length; ++i) {
+ var img = imgs[i];
+ img.src = url;
+}
+</script>
diff --git a/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-6.html b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-6.html
new file mode 100644
index 00000000000..655040eb446
--- /dev/null
+++ b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-6.html
@@ -0,0 +1,51 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>stretching works for replaced items with no aspect ratio</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-grid">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1656281">
+<link rel="match" href="grid-item-no-aspect-ratio-stretch-6-ref.html">
+<style>
+ body {
+ line-height: 0;
+ }
+
+ div {
+ display: inline-grid;
+ height: 250px;
+ width: 350px;
+ background: grey;
+ margin: 10px;
+ vertical-align: top;
+ }
+ img { background: blue; }
+
+ .justify {
+ justify-self: stretch;
+ }
+ .align {
+ align-self: stretch;
+ }
+</style>
+<div>
+ <img class="align justify">
+</div>
+<div>
+ <img class="align">
+</div>
+<div>
+ <img class="justify">
+</div>
+<div>
+ <img>
+</div>
+
+<script>
+var url = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="0px" height="20px" viewBox="0 0 50 100"></svg>'
+var imgs = document.querySelectorAll('img');
+for (var i = 0; i < imgs.length; ++i) {
+ var img = imgs[i];
+ img.src = url;
+}
+</script>
diff --git a/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-7-ref.html b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-7-ref.html
new file mode 100644
index 00000000000..0d60375f560
--- /dev/null
+++ b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-7-ref.html
@@ -0,0 +1,54 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Reference: stretching works for replaced items with no aspect ratio</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<style>
+ body {
+ line-height: 0;
+ }
+
+ div {
+ display: inline-block;
+ height: 250px;
+ width: 350px;
+ background: grey;
+ margin: 10px;
+ vertical-align: top;
+ }
+
+ img {
+ display: block;
+ width: 300px;
+ height: 150px;
+ background: blue;
+ }
+
+ .justify {
+ width: 350px;
+ }
+ .align {
+ height: 250px;
+ }
+</style>
+<div>
+ <img class="align justify">
+</div>
+<div>
+ <img class="align" style="width:20px">
+</div>
+<div>
+ <img class="justify" style="height:0px">
+</div>
+<div>
+ <img style="width:20px; height:0px">
+</div>
+
+<script>
+var url = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg"></svg>'
+var imgs = document.querySelectorAll('img');
+for (var i = 0; i < imgs.length; ++i) {
+ var img = imgs[i];
+ img.src = url;
+}
+</script>
diff --git a/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-7.html b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-7.html
new file mode 100644
index 00000000000..29dec490b79
--- /dev/null
+++ b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-7.html
@@ -0,0 +1,51 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>stretching works for replaced items with no aspect ratio</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-grid">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1656281">
+<link rel="match" href="grid-item-no-aspect-ratio-stretch-7-ref.html">
+<style>
+ body {
+ line-height: 0;
+ }
+
+ div {
+ display: inline-grid;
+ height: 250px;
+ width: 350px;
+ background: grey;
+ margin: 10px;
+ vertical-align: top;
+ }
+ img { background: blue; }
+
+ .justify {
+ justify-self: stretch;
+ }
+ .align {
+ align-self: stretch;
+ }
+</style>
+<div>
+ <img class="align justify">
+</div>
+<div>
+ <img class="align">
+</div>
+<div>
+ <img class="justify">
+</div>
+<div>
+ <img>
+</div>
+
+<script>
+var url = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="20px" height="0px" viewBox="0 0 50 100"></svg>'
+var imgs = document.querySelectorAll('img');
+for (var i = 0; i < imgs.length; ++i) {
+ var img = imgs[i];
+ img.src = url;
+}
+</script>
diff --git a/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-8-ref.html b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-8-ref.html
new file mode 100644
index 00000000000..09dd27321ab
--- /dev/null
+++ b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-8-ref.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Reference: stretching works for replaced items with no aspect ratio</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<style>
+ body {
+ line-height: 0;
+ }
+
+ div {
+ display: inline-block;
+ height: 250px;
+ width: 350px;
+ background: grey;
+ margin: 10px;
+ vertical-align: top;
+ }
+</style>
+<div>
+</div>
+<div>
+</div>
+<div>
+</div>
+<div>
+</div>
diff --git a/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-8.html b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-8.html
new file mode 100644
index 00000000000..933ddd0504e
--- /dev/null
+++ b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-8.html
@@ -0,0 +1,50 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>stretching works for replaced items with no aspect ratio</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-grid">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1656281">
+<link rel="match" href="grid-item-no-aspect-ratio-stretch-8-ref.html">
+<style>
+ body {
+ line-height: 0;
+ }
+
+ div {
+ display: inline-grid;
+ height: 250px;
+ width: 350px;
+ background: grey;
+ margin: 10px;
+ vertical-align: top;
+ }
+
+ .justify {
+ justify-self: stretch;
+ }
+ .align {
+ align-self: stretch;
+ }
+</style>
+<div>
+ <img class="align justify">
+</div>
+<div>
+ <img class="align">
+</div>
+<div>
+ <img class="justify">
+</div>
+<div>
+ <img>
+</div>
+
+<script>
+var url = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="0px" height="20px"><circle cx="50%" cy="50%" r="50%" fill="blue"/></svg>'
+var imgs = document.querySelectorAll('img');
+for (var i = 0; i < imgs.length; ++i) {
+ var img = imgs[i];
+ img.src = url;
+}
+</script>
diff --git a/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-9.html b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-9.html
new file mode 100644
index 00000000000..367adae9eb7
--- /dev/null
+++ b/tests/wpt/web-platform-tests/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-9.html
@@ -0,0 +1,50 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>stretching works for replaced items with no aspect ratio</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-grid">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1656281">
+<link rel="match" href="grid-item-no-aspect-ratio-stretch-8-ref.html">
+<style>
+ body {
+ line-height: 0;
+ }
+
+ div {
+ display: inline-grid;
+ height: 250px;
+ width: 350px;
+ background: grey;
+ margin: 10px;
+ vertical-align: top;
+ }
+
+ .justify {
+ justify-self: stretch;
+ }
+ .align {
+ align-self: stretch;
+ }
+</style>
+<div>
+ <img class="align justify">
+</div>
+<div>
+ <img class="align">
+</div>
+<div>
+ <img class="justify">
+</div>
+<div>
+ <img>
+</div>
+
+<script>
+var url = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="20px" height="0px"><circle cx="50%" cy="50%" r="50%" fill="blue"/></svg>'
+var imgs = document.querySelectorAll('img');
+for (var i = 0; i < imgs.length; ++i) {
+ var img = imgs[i];
+ img.src = url;
+}
+</script>
diff --git a/tests/wpt/web-platform-tests/css/css-multicol/increase-prev-sibling-height-ref.html b/tests/wpt/web-platform-tests/css/css-multicol/increase-prev-sibling-height-ref.html
new file mode 100644
index 00000000000..963f584f17d
--- /dev/null
+++ b/tests/wpt/web-platform-tests/css/css-multicol/increase-prev-sibling-height-ref.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<p>The word "PASS" should be seen below.</p>
+<div style="height:2em; background:black;"></div>
+PASS
diff --git a/tests/wpt/web-platform-tests/css/css-multicol/increase-prev-sibling-height.html b/tests/wpt/web-platform-tests/css/css-multicol/increase-prev-sibling-height.html
new file mode 100644
index 00000000000..109fe89952e
--- /dev/null
+++ b/tests/wpt/web-platform-tests/css/css-multicol/increase-prev-sibling-height.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/css-multicol-1/">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1066640">
+<link rel="match" href="increase-prev-sibling-height-ref.html">
+<p>The word "PASS" should be seen below.</p>
+<div id="elm" style="background:black;"></div>
+<div style="columns:2;">
+ PASS
+</div>
+<script>
+ requestAnimationFrame(()=>{
+ requestAnimationFrame(()=>{
+ elm.style.height = "2em";
+ });
+ });
+</script>
diff --git a/tests/wpt/web-platform-tests/css/css-paint-api/paint-function-this-value.https.html b/tests/wpt/web-platform-tests/css/css-paint-api/paint-function-this-value.https.html
new file mode 100644
index 00000000000..216913899a9
--- /dev/null
+++ b/tests/wpt/web-platform-tests/css/css-paint-api/paint-function-this-value.https.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta charset="utf-8">
+<title>Paint callback is invoked with `this` value of `paintInstance`</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-paint-api-1/#invoke-a-paint-callback">
+<link rel="match" href="parse-input-arguments-ref.html">
+<style>
+.container {
+ width: 100px;
+ height: 100px;
+}
+
+#canvas-geometry {
+ background-image: paint(geometry);
+}
+</style>
+<script src="/common/reftest-wait.js"></script>
+<script src="/common/worklet-reftest.js"></script>
+<body>
+<div id="canvas-geometry" class="container"></div>
+
+<script id="code" type="text/worklet">
+let paintInstance;
+
+registerPaint('geometry', class {
+ constructor() {
+ paintInstance = this;
+ }
+ paint(ctx, geom) {
+ if (this === paintInstance)
+ ctx.fillStyle = 'green';
+ else
+ ctx.fillStyle = 'red';
+ ctx.fillRect(0, 0, geom.width, geom.height);
+ }
+});
+</script>
+
+<script>
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
+</script>
+</body>
+</html>
diff --git a/tests/wpt/web-platform-tests/docs/running-tests/from-local-system.md b/tests/wpt/web-platform-tests/docs/running-tests/from-local-system.md
index 8c71e535baa..91823444d5d 100644
--- a/tests/wpt/web-platform-tests/docs/running-tests/from-local-system.md
+++ b/tests/wpt/web-platform-tests/docs/running-tests/from-local-system.md
@@ -39,9 +39,6 @@ wherever you currently set your PATH.
See also [additional setup required to run Safari](safari.md).
### Windows Setup
-**Note:** In general, Windows Subsystem for Linux will provide the smoothest
-user experience for running web-platform-tests on Windows, where installation
-and usage are similar to Linux.
Download and install [Python 2.7](https://www.python.org/downloads). The
installer includes `pip` by default.
@@ -63,6 +60,15 @@ started using:
python wpt serve
```
+#### Windows Subsystem for Linux
+
+Optionally on Windows you can use the [Windows Subsystem for
+Linux](https://docs.microsoft.com/en-us/windows/wsl/about) (WSL). If doing so,
+installation and usage are similar to the Linux instructions. Be aware that WSL
+may attempt to override `/etc/hosts` each time it is launched, which would then
+require you to re-run [`hosts` File Setup](#hosts-file-setup). This behavior
+[can be configured](https://docs.microsoft.com/en-us/windows/wsl/wsl-config#network).
+
### `hosts` File Setup
To get the tests running, you need to set up the test domains in your
diff --git a/tests/wpt/web-platform-tests/docs/writing-tests/index.md b/tests/wpt/web-platform-tests/docs/writing-tests/index.md
index 90a67c21fce..c1d2fe17a31 100644
--- a/tests/wpt/web-platform-tests/docs/writing-tests/index.md
+++ b/tests/wpt/web-platform-tests/docs/writing-tests/index.md
@@ -8,43 +8,14 @@ testing plan](making-a-testing-plan) will help you decide what to write.
There's also a load of [general guidelines](general-guidelines) that apply to all tests.
-```eval_rst
-.. toctree::
- :maxdepth: 1
+## Test Types
- general-guidelines
- ahem
- assumptions
- crashtest
- css-metadata
- css-user-styles
- file-names
- h2tests
- lint-tool
- making-a-testing-plan
- manual
- reftest-tutorial
- reftests
- print-reftests
- rendering
- server-features
- submission-process
- testdriver
- testdriver-extension-tutorial
- testharness
- testharness-tutorial
- tools
- visual
- wdspec
- test-templates
- github-intro
-```
-
-## Test Type
+There are various different ways of writing tests:
-Tests in this project use a few different approaches to verify expected
-behavior. The tests can be classified based on the way they express
-expectations:
+* [JavaScript tests (testharness.js)](testharness) are preferred for testing APIs and may be used
+ for other features too. They are built with the testharness.js unit testing framework, and consist
+ of assertions written in JavaScript. A high-level [testharness.js tutorial](testharness-tutorial)
+ is available.
* Rendering tests should be used to verify that the browser graphically
displays pages as expected. See the [rendering test guidelines](rendering)
@@ -53,7 +24,8 @@ expectations:
* [Reftests](reftests) should be used to test rendering and layout. They
consist of two or more pages with assertions as to whether they render
- identically or not.
+ identically or not. A high-level [reftest tutorial](reftest-tutorial) is available. A
+ [print reftests](print-reftests) variant is available too.
* [Visual tests](visual) should be used for checking rendering where there is
a large number of conforming renderings such that reftests are impractical.
@@ -61,10 +33,6 @@ expectations:
screenshot can be taken and compared to an expected rendering for that user
agent on that platform.
-* [testharness.js](testharness) tests should be used (where possible!) for
- testing everything else. They are built with the testharness.js unit testing
- framework, and consist of assertions written in JavaScript.
-
* [Crashtests](crashtest) tests are used to check that the browser is
able to load a given document without crashing or experiencing other
low-level issues (asserts, leaks, etc.). They pass if the load
@@ -78,14 +46,6 @@ expectations:
tested using any of the above. They consist of a page that needs manual
interaction or verification of the final result.
-In general, there is a strong preference towards reftests and testharness.js
-tests types (as they can be easily run without human interaction), so they
-should be used in preference to the others even if it results in a
-somewhat cumbersome test; there is a far weaker preference between the
-two test types, and it is at times advisable to use testharness.js tests
-for things which would typically be tested using reftests but for
-which it would be overly cumbersome.
-
See [file names](file-names) for test types and features determined by the file names,
and [server features](server-features) for advanced testing features.
@@ -94,3 +54,37 @@ and [server features](server-features) for advanced testing features.
Once you've written tests, please submit them using
the [typical GitHub Pull Request workflow](submission-process); please
make sure you run the [`lint` script](lint-tool) before opening a pull request!
+
+## Table of Contents
+
+```eval_rst
+.. toctree::
+ :maxdepth: 1
+
+ general-guidelines
+ making-a-testing-plan
+ testharness
+ testharness-tutorial
+ rendering
+ reftests
+ reftest-tutorial
+ print-reftests
+ visual
+ crashtest
+ wdspec
+ manual
+ file-names
+ server-features
+ submission-process
+ lint-tool
+ ahem
+ assumptions
+ css-metadata
+ css-user-styles
+ h2tests
+ testdriver
+ testdriver-extension-tutorial
+ tools
+ test-templates
+ github-intro
+```
diff --git a/tests/wpt/web-platform-tests/docs/writing-tests/testharness.md b/tests/wpt/web-platform-tests/docs/writing-tests/testharness.md
index 1e9772a4017..1037eaca03c 100644
--- a/tests/wpt/web-platform-tests/docs/writing-tests/testharness.md
+++ b/tests/wpt/web-platform-tests/docs/writing-tests/testharness.md
@@ -1,4 +1,4 @@
-# testharness.js Tests
+# JavaScript Tests (testharness.js)
```eval_rst
.. toctree::
diff --git a/tests/wpt/web-platform-tests/dom/events/AddEventListenerOptions-once.html b/tests/wpt/web-platform-tests/dom/events/AddEventListenerOptions-once.html
index ae750702c79..361c838b736 100644
--- a/tests/wpt/web-platform-tests/dom/events/AddEventListenerOptions-once.html
+++ b/tests/wpt/web-platform-tests/dom/events/AddEventListenerOptions-once.html
@@ -78,4 +78,21 @@ test(function() {
assert_equals(invoked_count, 0, "The handler should have been removed");
}, "Once listener should be added / removed like normal listeners");
+test(function() {
+ var invoked_count = 0;
+
+ for (let n = 4; n > 0; n--) {
+ document.addEventListener('test', (e) => {
+ invoked_count++;
+ e.stopImmediatePropagation();
+ }, {once: true});
+ }
+
+ for (let n = 4; n > 0; n--) {
+ document.dispatchEvent(new Event('test'));
+ }
+
+ assert_equals(invoked_count, 4, "The listeners should be invoked");
+}, "Multiple once listeners should be invoked even if the stopImmediatePropagation is set");
+
</script>
diff --git a/tests/wpt/web-platform-tests/dom/nodes/MutationObserver-callback-arguments.html b/tests/wpt/web-platform-tests/dom/nodes/MutationObserver-callback-arguments.html
new file mode 100644
index 00000000000..d64758cb4fa
--- /dev/null
+++ b/tests/wpt/web-platform-tests/dom/nodes/MutationObserver-callback-arguments.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<meta charset=utf-8>
+<title>MutationObserver: callback arguments</title>
+<link rel="help" href="https://dom.spec.whatwg.org/#notify-mutation-observers">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="mo-target"></div>
+<div id="log"></div>
+<script>
+"use strict";
+
+async_test(t => {
+ const moTarget = document.querySelector("#mo-target");
+ const mo = new MutationObserver(function(records, observer) {
+ t.step(() => {
+ assert_equals(this, mo);
+ assert_equals(arguments.length, 2);
+ assert_true(Array.isArray(records));
+ assert_equals(records.length, 1);
+ assert_true(records[0] instanceof MutationRecord);
+ assert_equals(observer, mo);
+
+ mo.disconnect();
+ t.done();
+ });
+ });
+
+ mo.observe(moTarget, {attributes: true});
+ moTarget.className = "trigger-mutation";
+}, "Callback is invoked with |this| value of MutationObserver and two arguments");
+</script>
diff --git a/tests/wpt/web-platform-tests/html/cross-origin-opener-policy/reporting/access-reporting/reporting-observer.html b/tests/wpt/web-platform-tests/html/cross-origin-opener-policy/reporting/access-reporting/reporting-observer.html
index 4d1eda941ae..decad097b6d 100644
--- a/tests/wpt/web-platform-tests/html/cross-origin-opener-policy/reporting/access-reporting/reporting-observer.html
+++ b/tests/wpt/web-platform-tests/html/cross-origin-opener-policy/reporting/access-reporting/reporting-observer.html
@@ -1,3 +1,6 @@
+<!doctype html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
<title>
Check the ReportingObserver(s) are notified about the coop-access-violation
events.
@@ -12,8 +15,10 @@
const directory = "/html/cross-origin-opener-policy/reporting";
const executor_path = directory + "/resources/executor.html?pipe=";
-const https = get_host_info().HTTPS_ORIGIN;
+const same_origin = get_host_info().HTTPS_ORIGIN;
+const cross_site = get_host_info().HTTPS_NOTSAMESITE_ORIGIN;
const coep_header = '|header(Cross-Origin-Embedder-Policy,require-corp)';
+const corp_header = '|header(Cross-Origin-Resource-Policy,cross-origin)';
promise_test(async t => {
// This test window.
@@ -22,13 +27,13 @@ promise_test(async t => {
// The "opener" window, using COOP-Report-Only and a reporter.
const opener_token = token();
const opener_reportTo = reportToHeaders(token());
- const opener_url = https + executor_path + opener_reportTo.header +
+ const opener_url = same_origin + executor_path + opener_reportTo.header +
opener_reportTo.coopReportOnlySameOriginHeader + coep_header +
`&uuid=${opener_token}`;
// The "openee" window, NOT using COOP.
const openee_token = token();
- const openee_url = https + executor_path + `&uuid=${openee_token}`;
+ const openee_url = same_origin + executor_path + `&uuid=${openee_token}`;
// 1. Create the opener window.
window.open(opener_url);
@@ -82,12 +87,12 @@ promise_test(async t => {
// The "opener" window, NOT using COOP.
const opener_token = token();
- const opener_url = https + executor_path + `&uuid=${opener_token}`;
+ const opener_url = same_origin + executor_path + `&uuid=${opener_token}`;
// The "openee" window, using COOP-Report-Only and a reporter.
const openee_token = token();
const openee_reportTo = reportToHeaders(token());
- const openee_url = https + executor_path + openee_reportTo.header +
+ const openee_url = same_origin + executor_path + openee_reportTo.header +
openee_reportTo.coopReportOnlySameOriginHeader + coep_header +
`&uuid=${openee_token}`;
@@ -132,4 +137,126 @@ promise_test(async t => {
let report_access_to = JSON.parse(await receive(this_window_token));
assert_equals(report_access_to.length, 0, "Unexpected report received.");
}, "Openee COOP");
+
+promise_test(async t => {
+ // This test window.
+ const this_window_token = token();
+
+ // The "opener" window, using COOP-Report-Only and a reporter.
+ const opener_token = token();
+ const opener_reportTo = reportToHeaders(token());
+ const opener_url = same_origin + executor_path + opener_reportTo.header +
+ opener_reportTo.coopReportOnlySameOriginHeader + coep_header +
+ `&uuid=${opener_token}`;
+
+ // The "opener's iframe", same-origin with its parent.
+ const opener_iframe_token = token();
+ const opener_iframe_url = same_origin + executor_path + coep_header +
+ `&uuid=${opener_iframe_token}`;
+
+ // The "openee" window, NOT using COOP.
+ const openee_token = token();
+ const openee_url = same_origin + executor_path + coep_header +
+ `&uuid=${openee_token}`;
+
+ // 1. Create the opener window.
+ window.open(opener_url);
+ t.add_cleanup(() => send(opener_token, "window.close();"));
+
+ // 2. The opener opens an iframe, and install a ReportingObserver to catch
+ // future accesses.
+ send(opener_token, `
+ iframe = document.createElement("iframe");
+ iframe.src = "${opener_iframe_url}";
+ document.body.appendChild(iframe);
+
+ let observer = new ReportingObserver(reports => {
+ send("${this_window_token}", JSON.stringify(reports));
+ observer.disconnect();
+ });
+ observer.observe();
+ `);
+
+ // 3. The iframe opens the openee.
+ send(opener_iframe_token, `openee = window.open('${openee_url}');`);
+ t.add_cleanup(() => send(openee_token, `window.close();`));
+
+ // 4. Wait for the openee to load its document.
+ send(openee_token, `send("${this_window_token}", "Ready");`);
+ assert_equals(await receive(this_window_token), "Ready");
+
+ // 4. The opener's iframe tries to access the openee. This is an
+ // "access-from-coop-page" from a same-origin iframe, so the
+ // ReportingObserver(s) are notified.
+ send(opener_iframe_token, `tryAccess(openee);`);
+
+ let reports = await receive(this_window_token);
+ assert_not_equals(reports, "timeout", "No report received.");
+ reports = JSON.parse(reports);
+ assert_equals(reports.length, 1, "No report received.");
+ assert_equals(reports[0].type, "coop-access-violation");
+ assert_equals(reports[0].url, opener_url.replace(/"/g, '%22'));
+ assert_true(reports[0].body.sourceFile.includes("try-access.js"));
+ assert_equals(reports[0].body.lineNumber, 6);
+ assert_equals(reports[0].body.columnNumber, 7);
+ assert_equals(reports[0].body.property, "blur");
+}, "Access from same-origin iframe")
+
+promise_test(async t => {
+ // This test window.
+ const this_window_token = token();
+
+ // The "opener" window, using COOP-Report-Only and a reporter.
+ const opener_token = token();
+ const opener_reportTo = reportToHeaders(token());
+ const opener_url = same_origin + executor_path + opener_reportTo.header +
+ opener_reportTo.coopReportOnlySameOriginHeader + coep_header +
+ `&uuid=${opener_token}`;
+
+ // The "opener's iframe", same-origin with its parent.
+ const opener_iframe_token = token();
+ const opener_iframe_url = cross_site + executor_path + coep_header +
+ corp_header +
+ `&uuid=${opener_iframe_token}`;
+
+ // The "openee" window, NOT using COOP.
+ const openee_token = token();
+ const openee_url = same_origin + executor_path + coep_header +
+ `&uuid=${openee_token}`;
+
+ // 1. Create the opener window.
+ window.open(opener_url);
+ t.add_cleanup(() => send(opener_token, "window.close();"));
+
+ // 2. The opener opens an iframe, and install a ReportingObserver to catch
+ // future accesses.
+ send(opener_token, `
+ iframe = document.createElement("iframe");
+ iframe.src = "${opener_iframe_url}";
+ document.body.appendChild(iframe);
+
+ let observer = new ReportingObserver(reports => {
+ send("${this_window_token}", JSON.stringify(reports));
+ observer.disconnect();
+ });
+ observer.observe();
+ `);
+
+ // 3. The iframe opens the openee.
+ send(opener_iframe_token, `openee = window.open('${openee_url}');`);
+ t.add_cleanup(() => send(openee_token, `window.close();`));
+
+ // 4. Wait for the openee to load its document.
+ send(openee_token, `send("${this_window_token}", "Ready");`);
+ assert_equals(await receive(this_window_token), "Ready");
+
+ // 5. The opener's iframe tries to access the openee. This is an
+ // "access-from-coop-page" from a cross-site iframe. The ReportingObservers
+ // from the main document aren't notified.
+ send(opener_iframe_token, `tryAccess(openee);`);
+
+ let reports = await receive(this_window_token);
+ assert_equals(reports, "timeout", "Unexpected report received.");
+}, "Access from cross-site iframe")
+
</script>
diff --git a/tests/wpt/web-platform-tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-redirect-with-same-origin-allow-popups.https.html b/tests/wpt/web-platform-tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-redirect-with-same-origin-allow-popups.https.html
index 7dba76c4ef5..f807561f174 100644
--- a/tests/wpt/web-platform-tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-redirect-with-same-origin-allow-popups.https.html
+++ b/tests/wpt/web-platform-tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-redirect-with-same-origin-allow-popups.https.html
@@ -1,6 +1,5 @@
<title>
- COOP reports are to the opener when the opener used COOP-RO+COEP and then its
- cross-origin openee tries to access it.
+ Tests the redirect interaction with COOP same-origin-allow-popups.
</title>
<meta name=timeout content=long>
<script src=/resources/testharness.js></script>
@@ -8,77 +7,109 @@
<script src=/common/get-host-info.sub.js></script>
<script src="/common/utils.js"></script>
<script src="../resources/dispatcher.js"></script>
-<script src="../resources/try-access.js"></script>
<script>
const directory = "/html/cross-origin-opener-policy/reporting";
const executor_path = directory + "/resources/executor.html?pipe=";
-const same_origin = get_host_info().HTTPS_ORIGIN;
-const cross_origin = get_host_info().HTTPS_REMOTE_ORIGIN;
+const same_origin = {
+ host: get_host_info().HTTPS_ORIGIN,
+ name: "Same origin"
+};
+const cross_origin = {
+ host: get_host_info().HTTPS_REMOTE_ORIGIN,
+ name: "Cross origin"
+};
const coep_header = '|header(Cross-Origin-Embedder-Policy,require-corp)';
-promise_test(async t => {
- // The test window.
- const this_window_token = token();
+// Tests the redirect interaction with COOP same-origin-allow-popups and
+// reporting:
+// 1 - open the opener document on origin same_origin wit COOP
+// same-origin-allow-popups.
+// 2 - opener opens popup with document on origin popup_origin, no COOP and a
+// redirect header (HTTP 302, location).
+// 3 - redirection to a document with origin same_origin and COOP
+// same-origin-allow-popups.
+//
+// The navigation (2) to the first document of the popup stays in the same
+// browsing context group due to the same-origin-allow-popups COOP of the
+// opener.
+// The redirect (3) to the final document does since it compares the
+// popup_origin/unsafe-none document with the
+// same-origin/same-origin-allow-popups document.
+//
+// A opens B, B redirects to C.
+//
+// Document Origin COOP
+// -------- ------------ ------------------------
+// A same-origin same-origin-allow-popups
+// B popup-origin unsafe-none
+// C same-origin same-origin-allow-popups
+function redirect_test( popup_origin ) {
+ promise_test(async t => {
+ // The test window.
+ const this_window_token = token();
- // The "opener" window. This has COOP same-origin-allow-popups and a reporter.
- const opener_report_token= token();
- const opener_token = token();
- const opener_reportTo = reportToHeaders(opener_report_token);
- const opener_url = same_origin + executor_path + opener_reportTo.header +
- opener_reportTo.coopSameOriginAllowPopupsHeader +
- `&uuid=${opener_token}`;
+ // The "opener" window. This has COOP same-origin-allow-popups and a
+ // reporter.
+ const opener_report_token= token();
+ const opener_token = token();
+ const opener_reportTo = reportToHeaders(opener_report_token);
+ const opener_url = same_origin.host + executor_path +
+ opener_reportTo.header + opener_reportTo.coopSameOriginAllowPopupsHeader +
+ `&uuid=${opener_token}`;
- // The "openee" window.
- // The initial URL is cross-origin with the opener, and redirects to a
- // same-origin page with same-origin-allow-popups.
- // The navigation to the cross-origin page stays in the same browsing context
- // group due to the same-origin-allow-popups policy, but the redirect to the
- // final page does since it compares the cross-origin/unsafe-none document
- // with the same-origin/same-origin-allow-popups document.
- const openee_token = token();
- const openee_redirect_url = same_origin + executor_path +
- opener_reportTo.header + opener_reportTo.coopSameOriginAllowPopupsHeader +
- `&uuid=${openee_token}`;
- const redirect_header = 'status(302)' +
- `|header(Location,${encodeURIComponent(
- openee_redirect_url
- .replace(/,/g, "\\,")
- .replace(/\\\\,/g, "\\\\\\,")
- .replace(/\(/g, "%28")
- .replace(/\)/g, "%29"))})`;
- const openee_url = cross_origin + executor_path + redirect_header +
- `&uuid=${openee_token}`;
- // 1. Create the opener window.
- let opener_window_proxy = window.open(opener_url);
- t.add_cleanup(() => send(opener_token, "window.close()"));
+ // The "openee" window.
+ // The initial document does not have COOP and is on popup_origin, it
+ // redirects to a same-origin (with the opener) document with COOP
+ // same-origin-allow-popups.
+ const openee_token = token();
+ const openee_redirect_url = same_origin.host + executor_path +
+ opener_reportTo.header + opener_reportTo.coopSameOriginAllowPopupsHeader +
+ `&uuid=${openee_token}`;
+ const redirect_header = 'status(302)' +
+ `|header(Location,${encodeURIComponent(
+ openee_redirect_url
+ .replace(/,/g, "\\,")
+ .replace(/\\\\,/g, "\\\\\\,")
+ .replace(/\(/g, "%28")
+ .replace(/\)/g, "%29"))})`;
+ const openee_url = popup_origin.host + executor_path + redirect_header +
+ `&uuid=${openee_token}`;
+ // 1. Create the opener window.
+ let opener_window_proxy = window.open(opener_url);
+ t.add_cleanup(() => send(opener_token, "window.close()"));
- // 2. The opener opens its openee.
- send(opener_token, `
- openee = window.open("${openee_url}");
- `);
- t.add_cleanup(() => send(openee_token, "window.close()"));
+ // 2. The opener opens its openee.
+ send(opener_token, `
+ openee = window.open("${openee_url}");
+ `);
+ t.add_cleanup(() => send(openee_token, "window.close()"));
- // 3. Check the opener status on the openee.
- send(openee_token, `
- send("${this_window_token}", opener !== null);
- `);
- assert_equals(await receive(this_window_token), "false", "opener");
+ // 3. Check the opener status on the openee.
+ send(openee_token, `
+ send("${this_window_token}", opener !== null);
+ `);
+ assert_equals(await receive(this_window_token), "false", "opener");
- // 4. Check the openee status on the opener.
- send(opener_token, `
- send("${this_window_token}", openee.closed);
- `);
- assert_equals(await receive(this_window_token), "true", "openee.closed");
+ // 4. Check the openee status on the opener.
+ send(opener_token, `
+ send("${this_window_token}", openee.closed);
+ `);
+ assert_equals(await receive(this_window_token), "true", "openee.closed");
- // 5. Check a report sent to the openee.
- let report = await receiveReport(opener_report_token, "navigation-to-document")
- assert_not_equals(report, "timeout", "Report not received");
- assert_equals(report.type, "coop");
- assert_equals(report.url, openee_redirect_url.replace(/"/g, '%22'));
- assert_equals(report.body["disposition"], "enforce");
- assert_equals(report.body["effective-policy"], "same-origin-allow-popups");
- assert_equals(report.body["document-uri"], openee_url);
-}, "Cross-origin openee redirected to same-origin with same-origin-allow-popups");
+ // 5. Check a report sent to the openee.
+ let report = await receiveReport(
+ opener_report_token,
+ "navigation-to-document");
+ assert_not_equals(report, "timeout", "Report not received");
+ assert_equals(report.type, "coop");
+ assert_equals(report.url, openee_redirect_url.replace(/"/g, '%22'));
+ assert_equals(report.body["disposition"], "enforce");
+ assert_equals(report.body["effective-policy"], "same-origin-allow-popups");
+ assert_equals(report.body["document-uri"], openee_url);
+ }, `${popup_origin.name} openee redirected to same-origin with same-origin-allow-popups`);
+}
+redirect_test(same_origin);
+redirect_test(cross_origin);
</script>
diff --git a/tests/wpt/web-platform-tests/html/cross-origin-opener-policy/reporting/resources/dispatcher.py b/tests/wpt/web-platform-tests/html/cross-origin-opener-policy/reporting/resources/dispatcher.py
index 2617361b0b3..e77583e479f 100644
--- a/tests/wpt/web-platform-tests/html/cross-origin-opener-policy/reporting/resources/dispatcher.py
+++ b/tests/wpt/web-platform-tests/html/cross-origin-opener-policy/reporting/resources/dispatcher.py
@@ -9,12 +9,19 @@ def main(request, response):
return b''
uuid = request.GET[b'uuid']
+ stash = request.server.stash;
+ with stash.lock:
+ queue = stash.take(uuid)
+ if queue is None:
+ queue = []
- if request.method == u'POST':
- return request.server.stash.put(uuid, request.body)
- else:
- body = request.server.stash.take(uuid)
- if body is None:
- return b'not ready'
+ if request.method == u'POST':
+ queue.append(request.body)
+ ret = b'done'
else:
- return body
+ if len(queue) == 0:
+ ret = b'not ready'
+ else:
+ ret = queue.pop(0)
+ stash.put(uuid, queue)
+ return ret;
diff --git a/tests/wpt/web-platform-tests/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-flexbox.html b/tests/wpt/web-platform-tests/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-flexbox.html
index 07c73554e59..9e1c9ed152f 100644
--- a/tests/wpt/web-platform-tests/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-flexbox.html
+++ b/tests/wpt/web-platform-tests/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-flexbox.html
@@ -81,4 +81,15 @@ legend {
testElm.querySelector('div').offsetTop, 'offsetTop')
}, "Inline flex");
+
+test(() => {
+ const testElm = document.getElementById('test');
+ testElm.style.flexDirection = 'row';
+ const item0 = testElm.querySelectorAll('div')[0];
+ const item1 = testElm.querySelectorAll('div')[1];
+ assert_equals(item0.offsetTop, item1.offsetTop);
+
+ testElm.style.flexDirection = 'column';
+ assert_true(item0.offsetTop < item1.offsetTop);
+}, "Dynamic change of flex-direction");
</script>
diff --git a/tests/wpt/web-platform-tests/html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/allow-scripts-flag-changing-1.html b/tests/wpt/web-platform-tests/html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/allow-scripts-flag-changing-1.html
index 3bf8cfb6cc8..196f6d0409a 100644
--- a/tests/wpt/web-platform-tests/html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/allow-scripts-flag-changing-1.html
+++ b/tests/wpt/web-platform-tests/html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/allow-scripts-flag-changing-1.html
@@ -33,7 +33,10 @@ destIFrame.onload = () => {
++destLoadCount;
if (destLoadCount === 2) {
- assert_unreached("The iframe into which the meta was moved must not refresh");
+ // destIFrame doesn't have the sandboxed automatic features browsing context
+ // flag sets, thus navigated.
+ assert_equals(destIFrame.contentDocument.body.textContent.trim(), "foo");
+ done();
}
maybeStartTest();
@@ -41,9 +44,6 @@ destIFrame.onload = () => {
function maybeStartTest() {
if (sourceLoadCount === 1 && destLoadCount === 1) {
- // Test that no refreshes occur within 3 seconds
- step_timeout(done, 3000);
-
const meta = sourceIFrame.contentDocument.querySelector("meta");
destIFrame.contentDocument.body.appendChild(meta);
}
diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url-worker-importScripts.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url-worker-importScripts.html
new file mode 100644
index 00000000000..817cf6d5ddf
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url-worker-importScripts.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<title>Base URLs used in resolving specifiers in dynamic imports from importScripts()</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+fetch_tests_from_worker(new Worker("./worker-importScripts.sub.js"));
+</script>
diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url-worker.sub.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url-worker.sub.html
new file mode 100644
index 00000000000..a12204281cc
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url-worker.sub.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<title>Base URLs used in resolving specifiers in dynamic imports from workers</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+fetch_tests_from_worker(new Worker(
+ "../beta/redirect.py?location=http://{{host}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js"));
+</script>
diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url.sub.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url.sub.html
new file mode 100644
index 00000000000..f7d4927a104
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url.sub.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<title>Base URLs used in resolving specifiers in dynamic imports</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+self.testName = "same origin classic <script>";
+self.baseUrlSanitized = false;
+</script>
+<script src="../beta/redirect.py?location=http://{{host}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js"></script>
+
+<script>
+self.testName = "cross origin classic <script> without crossorigin attribute";
+self.baseUrlSanitized = true;
+</script>
+<script src="../beta/redirect.py?location=http://{{hosts[alt][]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js"></script>
+
+<script>
+self.testName = "cross origin classic <script> with crossorigin attribute";
+self.baseUrlSanitized = false;
+</script>
+<script src="../beta/redirect.py?location=http://{{hosts[alt][]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js%3Fpipe=header(Access-Control-Allow-Origin,*)" crossorigin></script>
+
+<script>
+self.testName = "cross origin module <script>";
+self.baseUrlSanitized = false;
+</script>
+<script src="../beta/redirect.py?location=http://{{hosts[alt][]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js%3Fpipe=header(Access-Control-Allow-Origin,*)" type="module"></script>
diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/import.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/import.js
new file mode 100644
index 00000000000..b2ac52df2a1
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/import.js
@@ -0,0 +1 @@
+export const A = { "from": "alpha/import.js" };
diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/worker-importScripts.sub.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/worker-importScripts.sub.js
new file mode 100644
index 00000000000..904d32f9bfd
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/worker-importScripts.sub.js
@@ -0,0 +1,15 @@
+"use strict";
+
+importScripts("/resources/testharness.js");
+
+// CORS-same-origin
+self.testName = "same-origin importScripts()";
+self.baseUrlSanitized = false;
+importScripts("../beta/redirect.py?location=http://{{host}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js");
+
+// CORS-cross-origin
+self.testName = "cross-origin importScripts()";
+self.baseUrlSanitized = true;
+importScripts("../beta/redirect.py?location=http://{{hosts[alt][]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js");
+
+done();
diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/beta/import.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/beta/import.js
new file mode 100644
index 00000000000..7de1c681825
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/beta/import.js
@@ -0,0 +1 @@
+export const A = { "from": "beta/import.js" };
diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/beta/redirect.py b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/beta/redirect.py
new file mode 100644
index 00000000000..f2fd1ebd51d
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/beta/redirect.py
@@ -0,0 +1,19 @@
+def main(request, response):
+ """Simple handler that causes redirection.
+
+ The request should typically have two query parameters:
+ status - The status to use for the redirection. Defaults to 302.
+ location - The resource to redirect to.
+ """
+ status = 302
+ if b"status" in request.GET:
+ try:
+ status = int(request.GET.first(b"status"))
+ except ValueError:
+ pass
+
+ response.status = status
+
+ location = request.GET.first(b"location")
+
+ response.headers.set(b"Location", location)
diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js
new file mode 100644
index 00000000000..ec7784983d1
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js
@@ -0,0 +1,58 @@
+"use strict";
+
+// This script triggers import(), and thus the base URL of this script
+// (either loaded by `<script>` or `importScripts()`) is used as the base URL
+// of resolving relative URL-like specifiers in `import()`.
+
+// The following fields should be set by the callers of this script
+// (unless loaded as the worker top-level script):
+// - self.testName (string)
+// - self.baseUrlSanitized (boolean)
+
+// When this script is loaded as the worker top-level script:
+if ('DedicatedWorkerGlobalScope' in self &&
+ self instanceof DedicatedWorkerGlobalScope &&
+ !self.testName) {
+ importScripts("/resources/testharness.js");
+ self.testName = 'worker top-level script';
+ // Worker top-level scripts are always same-origin.
+ self.baseUrlSanitized = false;
+}
+
+{
+ // This could change by the time the test is executed, so we save it now.
+ // As this script is loaded multiple times, savedBaseUrlSanitized is scoped.
+ const savedBaseUrlSanitized = self.baseUrlSanitized;
+
+ promise_test(() => {
+ const promise = import("./import.js?pipe=header(Access-Control-Allow-Origin,*)&label=relative-" + self.testName);
+ if (savedBaseUrlSanitized) {
+ // The base URL is "about:blank" and thus import() here should fail.
+ return promise.then(module => {
+ // This code should be unreached, but assert_equals() is used here
+ // to log `module.A["from"]` in case of unexpected resolution.
+ assert_equals(module.A["from"], "(unreached)",
+ "Relative URL-like specifier resolution should fail");
+ assert_unreached();
+ },
+ () => {});
+ } else {
+ // The base URL is the response URL of this script, i.e.
+ // `.../gamma/base-url.sub.js`.
+ return promise.then(module => {
+ assert_equals(module.A["from"], "gamma/import.js");
+ });
+ }
+ },
+ "Relative URL-like from " + self.testName);
+}
+
+promise_test(() => {
+ return import("http://{{hosts[alt][]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/import.js?pipe=header(Access-Control-Allow-Origin,*)&label=absolute-" + self.testName)
+ .then(module => {
+ assert_equals(module.A["from"], "gamma/import.js");
+ })
+ },
+ "Absolute URL-like from " + self.testName);
+
+done();
diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/import.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/import.js
new file mode 100644
index 00000000000..435c1369be2
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/import.js
@@ -0,0 +1 @@
+export const A = { "from": "gamma/import.js" };
diff --git a/tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/protocol-handler-fragment-manual.https.html b/tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/protocol-handler-fragment-manual.https.html
new file mode 100644
index 00000000000..15617865691
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/protocol-handler-fragment-manual.https.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<!-- Use a non-UTF-8 encoding to see how the handler URL is parsed -->
+<meta charset=windows-1254>
+<meta name=timeout content=long>
+<title>registerProtocolHandler() and a handler with %s in the fragment</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/service-workers/service-worker/resources/test-helpers.sub.js></script>
+<script>
+// Configure expectations for individual test
+window.type = "fragment";
+window.noSW = false;
+</script>
+<script src=resources/handler-tools.js></script>
+<ol>
+ <li><p>First, register the handler: <button onclick='register()'>Register</button>.
+ <li><p>Then, run the test: <button onclick='runTest()'>Run</button>.
+ <li><p>Or, run the test with U+0000 NULL: <button onclick='runTest({ includeNull: true })'>Run NULL</button>.
+</ol>
+<div id=log></div>
diff --git a/tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/protocol-handler-fragment-nosw-manual.https.html b/tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/protocol-handler-fragment-nosw-manual.https.html
new file mode 100644
index 00000000000..be3a6be6665
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/protocol-handler-fragment-nosw-manual.https.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<!-- Use a non-UTF-8 encoding to see how the handler URL is parsed -->
+<meta charset=windows-1254>
+<meta name=timeout content=long>
+<title>registerProtocolHandler() and a handler with %s in the fragment (does not use a service worker)</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/service-workers/service-worker/resources/test-helpers.sub.js></script>
+<script>
+// Configure expectations for individual test
+window.type = "fragment";
+window.noSW = true;
+</script>
+<script src=resources/handler-tools.js></script>
+<ol>
+ <li><p>First, register the handler: <button onclick='register()'>Register</button>.
+ <li><p>Then, run the test: <button onclick='runTest()'>Run</button>.
+ <li><p>Or, run the test with U+0000 NULL: <button onclick='runTest({ includeNull: true })'>Run NULL</button>.
+</ol>
+<div id=log></div>
diff --git a/tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/protocol-handler-path-manual.https.html b/tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/protocol-handler-path-manual.https.html
new file mode 100644
index 00000000000..085c5723ec4
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/protocol-handler-path-manual.https.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<!-- Use a non-UTF-8 encoding to see how the handler URL is parsed -->
+<meta charset=windows-1254>
+<meta name=timeout content=long>
+<title>registerProtocolHandler() and a handler with %s in the path</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/service-workers/service-worker/resources/test-helpers.sub.js></script>
+<script>
+// Configure expectations for individual test
+window.type = "path";
+window.noSW = false;
+</script>
+<script src=resources/handler-tools.js></script>
+<ol>
+ <li><p>First, register the handler: <button onclick='register()'>Register</button>.
+ <li><p>Then, run the test: <button onclick='runTest()'>Run</button>.
+ <li><p>Or, run the test with U+0000 NULL: <button onclick='runTest({ includeNull: true })'>Run NULL</button>.
+</ol>
+<div id=log></div>
diff --git a/tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/protocol-handler-query-manual.https.html b/tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/protocol-handler-query-manual.https.html
new file mode 100644
index 00000000000..8ce65a5bad8
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/protocol-handler-query-manual.https.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<!-- Use a non-UTF-8 encoding to see how the handler URL is parsed -->
+<meta charset=windows-1254>
+<meta name=timeout content=long>
+<title>registerProtocolHandler() and a handler with %s in the query</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/service-workers/service-worker/resources/test-helpers.sub.js></script>
+<script>
+// Configure expectations for individual test
+window.type = "query";
+window.noSW = false;
+</script>
+<script src=resources/handler-tools.js></script>
+<ol>
+ <li><p>First, register the handler: <button onclick='register()'>Register</button>.
+ <li><p>Then, run the test: <button onclick='runTest()'>Run</button>.
+ <li><p>Or, run the test with U+0000 NULL: <button onclick='runTest({ includeNull: true })'>Run NULL</button>.
+</ol>
+<div id=log></div>
diff --git a/tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/protocol-handler-query-nosw-manual.https.html b/tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/protocol-handler-query-nosw-manual.https.html
new file mode 100644
index 00000000000..9b4473fb895
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/protocol-handler-query-nosw-manual.https.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<!-- Use a non-UTF-8 encoding to see how the handler URL is parsed -->
+<meta charset=windows-1254>
+<meta name=timeout content=long>
+<title>registerProtocolHandler() and a handler with %s in the query (does not use a service worker)</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/service-workers/service-worker/resources/test-helpers.sub.js></script>
+<script>
+// Configure expectations for individual test
+window.type = "query";
+window.noSW = true;
+</script>
+<script src=resources/handler-tools.js></script>
+<ol>
+ <li><p>First, register the handler: <button onclick='register()'>Register</button>.
+ <li><p>Then, run the test: <button onclick='runTest()'>Run</button>.
+ <li><p>Or, run the test with U+0000 NULL: <button onclick='runTest({ includeNull: true })'>Run NULL</button>.
+</ol>
+<div id=log></div>
diff --git a/tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/resources/handler-sw.js b/tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/resources/handler-sw.js
new file mode 100644
index 00000000000..5fd915d17f9
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/resources/handler-sw.js
@@ -0,0 +1,3 @@
+onfetch = e => {
+ e.respondWith(fetch("handler.html"));
+}
diff --git a/tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/resources/handler-tools.js b/tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/resources/handler-tools.js
new file mode 100644
index 00000000000..073287265cf
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/resources/handler-tools.js
@@ -0,0 +1,53 @@
+// These can be used in an environment that has these global variables defined:
+// * type (one of "path", "query", or "fragment")
+// * noSW (a boolean)
+
+if (type === "path" && noSW) {
+ throw new Error("There is no support for a path handler without a service worker.");
+}
+
+const swString = noSW ? "" : "sw";
+const handler = {
+ "path": "PSS%sPSE/?QES\u2020QEE#FES\u2020FEE",
+ "query": "?QES\u2020QEEPSS%sPSE#FES\u2020FEE",
+ "fragment": "?QES\u2020QEE#FES\u2020FEEPSS%sPSE"
+}[type];
+const scheme = `web+wpt${type}${swString}`;
+
+function register() {
+ const handlerURL = noSW ? `resources/handler.html${handler}${type}` : `resources/handler/${type}/${handler}`;
+ navigator.registerProtocolHandler(scheme, handlerURL, `WPT ${type} handler${noSW ? ", without service worker" : ""}`);
+}
+
+function runTest({ includeNull = false } = {}) {
+ promise_test(async t => {
+ const bc = new BroadcastChannel(`protocol-handler-${type}${swString}`);
+ if (!noSW) {
+ const reg = await service_worker_unregister_and_register(t, "resources/handler-sw.js", "resources/handler/");
+ t.add_cleanup(async () => await reg.unregister());
+ await wait_for_state(t, reg.installing, 'activated');
+ }
+ const a = document.body.appendChild(document.createElement("a"));
+ const codePoints = [];
+ let i = includeNull ? 0 : 1;
+ for (; i < 0x82; i++) {
+ codePoints.push(String.fromCharCode(i));
+ }
+ a.href = `${scheme}:${codePoints.join("")}`;
+ a.target = "_blank";
+ a.click();
+ await new Promise(resolve => {
+ bc.onmessage = t.step_func(e => {
+ resultingURL = e.data;
+ assert_equals(stringBetweenMarkers(resultingURL, "QES", "QEE"), "%86", "query baseline");
+ assert_equals(stringBetweenMarkers(resultingURL, "FES", "FEE"), "%E2%80%A0", "fragment baseline");
+ assert_equals(stringBetweenMarkers(resultingURL, "PSS", "PSE"), `${encodeURIComponent(scheme)}%3A${includeNull ? "%2500" : ""}%2501%2502%2503%2504%2505%2506%2507%2508%250B%250C%250E%250F%2510%2511%2512%2513%2514%2515%2516%2517%2518%2519%251A%251B%251C%251D%251E%251F%20!%22%23%24%25%26${type === "query" ? "%27" : "'"}()*%2B%2C-.%2F0123456789%3A%3B%3C%3D%3E%3F%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D~%257F%25C2%2580%25C2%2581`, "actual test");
+ resolve();
+ });
+ });
+ });
+}
+
+function stringBetweenMarkers(string, start, end) {
+ return string.substring(string.indexOf(start) + start.length, string.indexOf(end));
+}
diff --git a/tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/resources/handler.html b/tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/resources/handler.html
new file mode 100644
index 00000000000..552e5417842
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/webappapis/system-state-and-capabilities/the-navigator-object/resources/handler.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<p>This popup can be closed if it does not close itself.
+<p>
+<script>
+// This resource either gets navigated to through a service worker as a result of a URL that looks
+// like:
+// https://.../html/webappapis/system-state-and-capabilities/the-navigator-object/resources/handler/{type}/...
+// (the host is excluded to not upset the lint tool)
+// or it gets navigated to directly with the type appended to the end of the URL. In that case type
+// can only be fragment or query.
+
+let type = null;
+let swString = null;
+if (new URL(document.URL).pathname.endsWith("handler.html")) {
+ swString = "";
+ type = (document.URL.endsWith("fragment")) ? "fragment" : "query";
+} else {
+ type = document.URL.split("/")[9];
+ swString = "sw";
+}
+new BroadcastChannel(`protocol-handler-${type}${swString}`).postMessage(document.URL);
+window.close();
+</script>
diff --git a/tests/wpt/web-platform-tests/input-events/input-events-get-target-ranges-backspace.tentative.html b/tests/wpt/web-platform-tests/input-events/input-events-get-target-ranges-backspace.tentative.html
new file mode 100644
index 00000000000..cf512269b07
--- /dev/null
+++ b/tests/wpt/web-platform-tests/input-events/input-events-get-target-ranges-backspace.tentative.html
@@ -0,0 +1,811 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>InputEvent.getTargetRanges() at Backspace</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<div contenteditable></div>
+<script>
+const kBackspaceKey = "\uE003";
+const kShift = "\uE008";
+const kMeta = "\uE03d";
+const kControl = "\uE009";
+const kAlt = "\uE00A";
+
+let selection = getSelection();
+let editor = document.querySelector("div[contenteditable]");
+let beforeinput = [];
+let input = [];
+editor.addEventListener("beforeinput", (e) => {
+ // NOTE: Blink makes `getTargetRanges()` return empty range after propagaion,
+ // but this test wants to check the result during propagation.
+ // Therefore, we need to cache the result, but will assert if
+ // `getTargetRanges()` returns different ranges after checking the
+ // cached ranges.
+ e.cachedRanges = e.getTargetRanges();
+ beforeinput.push(e);
+});
+editor.addEventListener("input", (e) => {
+ e.cachedRanges = e.getTargetRanges();
+ input.push(e);
+});
+
+function reset() {
+ editor.focus();
+ beforeinput = [];
+ input = [];
+}
+
+function getRangeDescription(range) {
+ function getNodeDescription(node) {
+ if (!node) {
+ return "null";
+ }
+ switch (node.nodeType) {
+ case Node.TEXT_NODE:
+ case Node.COMMENT_NODE:
+ case Node.CDATA_SECTION_NODE:
+ return `${node.nodeName} "${node.data}"`;
+ case Node.ELEMENT_NODE:
+ return `<${node.nodeName.toLowerCase()}>`;
+ default:
+ return `${node.nodeName}`;
+ }
+ }
+ if (range === null) {
+ return "null";
+ }
+ if (range === undefined) {
+ return "undefined";
+ }
+ return range.startContainer == range.endContainer && range.startOffset == range.endOffset
+ ? `(${getNodeDescription(range.startContainer)}, ${range.startOffset})`
+ : `(${getNodeDescription(range.startContainer)}, ${range.startOffset}) - (${getNodeDescription(range.endContainer)}, ${range.endOffset})`;
+}
+
+function getArrayOfRangesDescription(arrayOfRanges) {
+ if (arrayOfRanges === null) {
+ return "null";
+ }
+ if (arrayOfRanges === undefined) {
+ return "undefined";
+ }
+ if (!Array.isArray(arrayOfRanges)) {
+ return "Unknown Object";
+ }
+ if (arrayOfRanges.length === 0) {
+ return "[]";
+ }
+ let result = "[";
+ for (let range of arrayOfRanges) {
+ result += `{${getRangeDescription(range)}},`;
+ }
+ result += "]";
+ return result;
+}
+
+function sendBackspaceKey(modifier) {
+ if (!modifier) {
+ return new test_driver.Actions()
+ .keyDown(kBackspaceKey)
+ .keyUp(kBackspaceKey)
+ .send();
+ }
+ return new test_driver.Actions()
+ .keyDown(modifier)
+ .keyDown(kBackspaceKey)
+ .keyUp(kBackspaceKey)
+ .keyUp(modifier)
+ .send();
+}
+
+function checkGetTargetRangesKeepReturningSameValue(event) {
+ // https://github.com/w3c/input-events/issues/114
+ assert_equals(getArrayOfRangesDescription(event.getTargetRanges()),
+ getArrayOfRangesDescription(event.cachedRanges),
+ `${event.type}.getTargetRanges() should keep returning the same array of ranges even after its propagation finished`);
+}
+
+function checkGetTargetRangesOfBeforeinputOnDeleteSomething(expectedRange) {
+ assert_equals(beforeinput.length, 1,
+ "One beforeinput event should be fired if the key operation deletes something");
+ assert_true(Array.isArray(beforeinput[0].cachedRanges),
+ "beforeinput[0].getTargetRanges() should return an array of StaticRange instances during propagation");
+ // Before checking the length of array of ranges, we should check first range
+ // first because the first range data is more important than whether there
+ // are additional unexpected ranges.
+ if (beforeinput[0].cachedRanges.length > 0) {
+ assert_equals(
+ getRangeDescription(beforeinput[0].cachedRanges[0]),
+ getRangeDescription(expectedRange),
+ `beforeinput.getTargetRanges() should return expected range (inputType is "${beforeinput[0].inputType}")`);
+ assert_equals(beforeinput[0].cachedRanges.length, 1,
+ "beforeinput.getTargetRanges() should return one range within an array");
+ }
+ assert_equals(beforeinput[0].cachedRanges, 1,
+ "One range should be returned from getTargetRanges() when the key operation deletes something");
+ checkGetTargetRangesKeepReturningSameValue(beforeinput[0]);
+}
+
+function checkGetTargetRangesOfInputOnDeleteSomething() {
+ assert_equals(input.length, 1,
+ "One input event should be fired if the key operation deletes something");
+ // https://github.com/w3c/input-events/issues/113
+ assert_true(Array.isArray(input[0].cachedRanges),
+ "input[0].getTargetRanges() should return an array of StaticRange instances during propagation");
+ assert_equals(input[0].cachedRanges.length, 0,
+ "input[0].getTargetRanges() should return empty array during propagation");
+ checkGetTargetRangesKeepReturningSameValue(input[0]);
+}
+
+function checkBeforeinputAndInputEventsOnNOOP() {
+ assert_equals(beforeinput.length, 0,
+ "beforeinput event shouldn't be fired when the key operation does not cause modifying the DOM tree");
+ assert_equals(input.length, 0,
+ "input event shouldn't be fired when the key operation does not cause modifying the DOM tree");
+}
+
+// Simply deletes the previous ASCII character of caret position.
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<p>abc</p>";
+ selection.collapse(editor.firstChild.firstChild, 1);
+ await sendBackspaceKey();
+ assert_equals(editor.innerHTML, "<p>bc</p>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: editor.firstChild.firstChild,
+ startOffset: 0,
+ endContainer: editor.firstChild.firstChild,
+ endOffset: 1,
+ });
+ checkGetTargetRangesOfInput();
+}, 'Backspace at "<p>a[]bc</p>"');
+
+// Simply deletes the previous ASCII character of caret position.
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<p>abc</p>";
+ selection.collapse(editor.firstChild.firstChild, 2);
+ await sendBackspaceKey();
+ assert_equals(editor.innerHTML, "<p>ac</p>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: editor.firstChild.firstChild,
+ startOffset: 1,
+ endContainer: editor.firstChild.firstChild,
+ endOffset: 2,
+ });
+ checkGetTargetRangesOfInput();
+}, 'Backspace at "<p>ab[]c</p>"');
+
+// Simply deletes the previous ASCII character of caret position.
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<p>abc</p>";
+ selection.collapse(editor.firstChild.firstChild, 3);
+ await sendBackspaceKey();
+ assert_equals(editor.innerHTML, "<p>ab</p>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: editor.firstChild.firstChild,
+ startOffset: 2,
+ endContainer: editor.firstChild.firstChild,
+ endOffset: 3,
+ });
+ checkGetTargetRangesOfInput();
+}, 'Backspace at "<p>abc[]</p>"');
+
+// Should delete the `<span>` element becase it becomes empty.
+// However, we need discussion whether the `<span>` element should be
+// contained by a range of `getTargetRanges()`.
+// https://github.com/w3c/input-events/issues/112
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<p>a<span>b</span>c</p>";
+ let c = editor.querySelector("span").nextSibling;
+ selection.collapse(c, 0);
+ await sendBackspaceKey();
+ assert_equals(editor.innerHTML, "<p>ac</p>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: editor.firstChild,
+ startOffset: 1,
+ endContainer: c,
+ endOffset: 0,
+ });
+ checkGetTargetRangesOfInput();
+}, 'Backspace at "<p>a<span>b</span>[]c</p>"');
+
+// Should delete the `<span>` element becase it becomes empty.
+// However, we need discussion whether the `<span>` element should be
+// contained by a range of `getTargetRanges()`.
+// https://github.com/w3c/input-events/issues/112
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<p>a<span>b</span>c</p>";
+ let b = editor.querySelector("span").firstChild;
+ selection.collapse(b, 1);
+ await sendBackspaceKey();
+ assert_equals(editor.innerHTML, "<p>ac</p>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: editor.firstChild,
+ startOffset: 1,
+ endContainer: editor.firstChild,
+ endOffset: 2,
+ });
+ checkGetTargetRangesOfInput();
+}, 'Backspace at "<p>a<span>b[]</span>c</p>"');
+
+// Invisible leading white-space may be deleted when the first visible
+// character is deleted. If it's deleted, it should be contained by
+// the range of `getTargetRanges()`, but needs discussion.
+// https://github.com/w3c/input-events/issues/112
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<p> abc</p>";
+ selection.collapse(editor.firstChild.firstChild, 2);
+ await sendBackspaceKey();
+ assert_in_array(editor.innerHTML, ["<p>bc</p>", "<p> bc</p>"]);
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: editor.firstChild.firstChild,
+ startOffset: editor.firstChild.firstChild.length == 2 ? 0 : 1,
+ endContainer: editor.firstChild.firstChild,
+ endOffset: 2,
+ });
+ checkGetTargetRangesOfInput();
+}, 'Backspace at "<p> a[]bc</p>"');
+
+// Invisible leading white-spaces in current block and invisible trailing
+// white-spaces in the previous block should be deleted for avoiding they
+// becoming visible when the blocks are joined. Perhaps, they should be
+// contained by the range of `getTargetRanges()`, but needs discussion.
+// https://github.com/w3c/input-events/issues/112
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<p>abc </p><p> def</p>";
+ let p1 = editor.firstChild;
+ let abc = p1.firstChild;
+ let p2 = p1.nextSibling;
+ let def = p2.firstChild;
+ selection.collapse(def, 3);
+ await sendBackspaceKey();
+ assert_equals(editor.innerHTML, "<p>abcdef</p>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: abc,
+ startOffset: 3,
+ endContainer: def,
+ endOffset: 3,
+ });
+ checkGetTargetRangesOfInput();
+}, 'Backspace at "<p>abc </p><p> []def</p>"');
+
+// Invisible leading white-spaces in current block and invisible trailing
+// white-spaces in the previous block should be deleted for avoiding they
+// becoming visible when the blocks are joined. Perhaps, they should be
+// contained by the range of `getTargetRanges()`, but needs discussion.
+// https://github.com/w3c/input-events/issues/112
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<p>abc </p><p> def</p>";
+ let p1 = editor.firstChild;
+ let abc = p1.firstChild;
+ let p2 = p1.nextSibling;
+ let def = p2.firstChild;
+ selection.collapse(def, 2);
+ await sendBackspaceKey();
+ assert_equals(editor.innerHTML, "<p>abcdef</p>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: abc,
+ startOffset: 3,
+ endContainer: def,
+ endOffset: 3,
+ });
+ checkGetTargetRangesOfInput();
+}, 'Backspace at "<p>abc </p><p> [] def</p>"');
+
+// Invisible leading white-spaces in current block and invisible trailing
+// white-spaces in the previous block should be deleted for avoiding they
+// becoming visible when the blocks are joined. Perhaps, they should be
+// contained by the range of `getTargetRanges()`, but needs discussion.
+// https://github.com/w3c/input-events/issues/112
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<p>abc </p><p> def</p>";
+ let p1 = editor.firstChild;
+ let abc = p1.firstChild;
+ let p2 = p1.nextSibling;
+ let def = p2.firstChild;
+ selection.collapse(def, 1);
+ await sendBackspaceKey();
+ assert_equals(editor.innerHTML, "<p>abcdef</p>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: abc,
+ startOffset: 3,
+ endContainer: def,
+ endOffset: 3,
+ });
+ checkGetTargetRangesOfInput();
+}, 'Backspace at "<p>abc </p><p> [] def</p>"');
+
+// Invisible leading white-spaces in current block and invisible trailing
+// white-spaces in the previous block should be deleted for avoiding they
+// becoming visible when the blocks are joined. Perhaps, they should be
+// contained by the range of `getTargetRanges()`, but needs discussion.
+// https://github.com/w3c/input-events/issues/112
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<p>abc </p><p> def</p>";
+ let p1 = editor.firstChild;
+ let abc = p1.firstChild;
+ let p2 = p1.nextSibling;
+ let def = p2.firstChild;
+ selection.collapse(def, 0);
+ await sendBackspaceKey();
+ assert_equals(editor.innerHTML, "<p>abcdef</p>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: abc,
+ startOffset: 3,
+ endContainer: def,
+ endOffset: 3,
+ });
+ checkGetTargetRangesOfInput();
+}, 'Backspace at "<p>abc </p><p>[] def</p>"');
+
+// Invisible leading white-spaces in current block and invisible trailing
+// white-spaces in the previous block should be deleted for avoiding they
+// becoming visible when the blocks are joined. Perhaps, they should be
+// contained by the range of `getTargetRanges()`, but needs discussion.
+// https://github.com/w3c/input-events/issues/112
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<p>abc </p><p> def</p>";
+ let p1 = editor.firstChild;
+ let abc = p1.firstChild;
+ let p2 = p1.nextSibling;
+ let def = p2.firstChild;
+ selection.setBaseAndExtent(abc, 6, def, 0);
+ await sendBackspaceKey();
+ assert_equals(editor.innerHTML, "<p>abcdef</p>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: abc,
+ startOffset: 3,
+ endContainer: def,
+ endOffset: 3,
+ });
+ checkGetTargetRangesOfInput();
+}, 'Backspace at "<p>abc [</p><p>] def</p>"');
+
+// Invisible leading white-spaces in the current block should be deleted
+// for avoiding they becoming visible when the blocks are joined, but
+// preformatted trailing white-spaces in the first block shouldn't be
+// deleted. Perhaps, the invisible white-spaces should be contained by
+// the range of `getTargetRanges()`, but needs discussion.
+// https://github.com/w3c/input-events/issues/112
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<pre>abc </pre><p> def</p>";
+ let pre = editor.firstChild;
+ let abc = pre.firstChild;
+ let p = pre.nextSibling;
+ let def = p.firstChild;
+ selection.collapse(def, 3);
+ await sendBackspaceKey();
+ // https://github.com/w3c/input-events/issues/112
+ // Shouldn't make the invisible white-spaces visible.
+ assert_equals(editor.innerHTML, "<pre>abc def</pre>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: abc,
+ startOffset: 6,
+ endContainer: def,
+ endOffset: 3,
+ });
+ checkGetTargetRangesOfInput();
+}, 'Backspace at "<pre>abc </pre><p> []def</p>"');
+
+// Invisible leading/trailing white-spaces in the current block should be
+// deleted for avoiding they becoming visible when the blocks are joined, but
+// preformatted trailing white-spaces in the first block shouldn't be
+// deleted. Perhaps, the invisible leading white-spaces should be contained
+// by the range of `getTargetRanges()`, but needs discussion.
+// And also not sure whether the trailing white-spaces should be contained
+// by additional range of `getTargetRanges()` or not because of the
+// implementation cost and runtime cost. Needs discuss.
+// https://github.com/w3c/input-events/issues/112
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<pre>abc </pre><p> def </p>";
+ let pre = editor.firstChild;
+ let abc = pre.firstChild;
+ let p = pre.nextSibling;
+ let def = p.firstChild;
+ selection.collapse(def, 3);
+ await sendBackspaceKey();
+ assert_equals(editor.innerHTML, "<pre>abc def </pre>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: abc,
+ startOffset: 6,
+ endContainer: def,
+ endOffset: 3,
+ });
+ checkGetTargetRangesOfInput();
+}, 'Backspace at "<pre>abc </pre><p> []def </p>"');
+
+// Invisible trailing white-spaces in the first block should be deleted
+// when the block is joined with the preformated following block, but
+// the leading white-spaces in the preformatted block shouldn't be
+// removed. So, in this case, the invisible trailing white-spaces should
+// be in the range of `getTargetRanges()`, but not so for the preformatted
+// visible leading white-spaces. But needs discussion.
+// https://github.com/w3c/input-events/issues/112
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<p>abc </p><pre> def</pre>";
+ let p = editor.firstChild;
+ let abc = p.firstChild;
+ let pre = p.nextSibling;
+ let def = pre.firstChild;
+ selection.collapse(def, 0);
+ await sendBackspaceKey();
+ assert_in_array(editor.innerHTML, ["<p>abc &nbsp; def</p>",
+ "<p>abc&nbsp;&nbsp; def</p>",
+ "<p>abc&nbsp; &nbsp;def</p>",
+ "<p>abc &nbsp;&nbsp;def</p>"]);
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: abc,
+ startOffset: 6,
+ endContainer: def,
+ endOffset: 0,
+ });
+ checkGetTargetRangesOfInput();
+}, 'Backspace at "<p>abc </p><pre>[] def</pre>"');
+
+// If the first block has invisible `<br>` element and joining it with
+// the following block, the invisible trailing `<br>` element should be
+// deleted and join the blocks. Therefore, the target range should contain
+// the `<br>` element and block boundaries. But maybe needs discussion.
+// https://github.com/w3c/input-events/issues/112
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<p>abc<br></p><p>def</p>";
+ let p1 = editor.firstChild;
+ let abc = p1.firstChild;
+ let p2 = p1.nextSibling;
+ let def = p2.firstChild;
+ selection.collapse(def, 0);
+ await sendBackspaceKey();
+ assert_equals(editor.innerHTML, "<p>abcdef</p>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: p1,
+ startOffset: 1,
+ endContainer: def,
+ endOffset: 0,
+ });
+ checkGetTargetRangesOfInput();
+}, 'Backspace at "<p>abc<br></p><p>[]def</p>"');
+
+// If the first block has invisible `<br>` element for empty last line and
+// joining it with the following block, the invisible trailing `<br>` element
+// should be deleted and join the blocks. Therefore, the target range should
+// contain the `<br>` element and block boundaries. But maybe needs discussion.
+// https://github.com/w3c/input-events/issues/112
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<p>abc<br><br></p><p>def</p>";
+ let p1 = editor.firstChild;
+ let abc = p1.firstChild;
+ let p2 = p1.nextSibling;
+ let def = p2.firstChild;
+ selection.collapse(def, 0);
+ await sendBackspaceKey();
+ assert_equals(editor.innerHTML, "<p>abc<br>def</p>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: p1,
+ startOffset: 2,
+ endContainer: def,
+ endOffset: 0,
+ });
+ checkGetTargetRangesOfInput();
+}, 'Backspace at "<p>abc<br><br></p><p>[]def</p>"');
+
+// Deleting visible `<br>` element should be contained by a range of
+// `getTargetRanges()`.
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<p>abc<br>def</p>";
+ let def = editor.querySelector("br").nextSibling;
+ selection.collapse(def, 0);
+ await sendBackspaceKey();
+ assert_equals(editor.innerHTML, "<p>abcdef</p>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: editor.firstChild,
+ startOffset: 1,
+ endContainer: def,
+ endOffset: 0,
+ });
+ checkGetTargetRangesOfInput();
+}, 'Backspace at "<p>abc<br>[]def</p>"');
+
+// Deleting visible `<br>` element should be contained by a range of
+// `getTargetRanges()`. However, when only the `<br>` element is selected,
+// the range shouldn't start from nor end by surrounding text nodes?
+// https://github.com/w3c/input-events/issues/112
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<p>abc<br>def</p>";
+ selection.setBaseAndExtent(editor.firstChild, 1, editor.firstChild, 2);
+ await sendBackspaceKey();
+ assert_equals(editor.innerHTML, "<p>abcdef</p>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: editor.firstChild,
+ startOffset: 1,
+ endContainer: editor.firstChild,
+ endOffset: 2,
+ });
+ checkGetTargetRangesOfInput();
+}, 'Backspace at "<p>abc{<br>}def</p>"');
+
+// Joining parent block and child block should remove invisible preceding
+// white-spaces of the child block and invisible leading white-spaces in
+// the child block, and they should be contained in a range of
+// `getTargetRanges()`, but maybe needs discussion.
+// https://github.com/w3c/input-events/issues/112
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<div>abc <p> def<br>ghi</p></div>";
+ let p = editor.querySelector("p");
+ let def = p.firstChild;
+ let abc = editor.firstChild.firstChild;
+ selection.collapse(def, 3);
+ await sendBackspaceKey();
+ assert_equals(editor.innerHTML, "<div>abcdef<p>ghi</p></div>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: abc,
+ startOffset: 3,
+ endContainer: def,
+ endOffset: 3,
+ });
+ checkGetTargetRangesOfInput();
+}, 'Backspace at "<div>abc <p> []def<br>ghi</p></div>"');
+
+// Joining child block and parent block should remove invisible trailing
+// white-spaces of the child block and invisible following white-spaces
+// in the parent block, and they should be contained by a range of
+// `getTaregetRanges()`, but maybe needs discussion.
+// https://github.com/w3c/input-events/issues/112
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<div><p>abc </p> def</div>";
+ let abc = editor.querySelector("p").firstChild;
+ let def = editor.querySelector("p").nextSibling;
+ selection.collapse(def, 3);
+ await sendBackspaceKey();
+ assert_equals(editor.innerHTML, "<div><p>abcdef</p></div>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: abc,
+ startOffset: 3,
+ endContainer: def,
+ endOffset: 3,
+ });
+ checkGetTargetRangesOfInput();
+}, 'Backspace at "<div><p>abc </p> []def</div>"');
+
+// The following tests check whether the range returned from
+// `beforeinput[0].getTargetRanges()` is modified or different range is
+// modified instead. I.e., they don't test which type of deletion should
+// occur. Therefore, their result depends on browser's key bindings,
+// system settings and running OS.
+
+function getFirstDifferentOffset(currentString, originalString) {
+ for (let i = 0; i < currentString.length; i++) {
+ if (currentString.charAt(i) !== originalString.charAt(i) &&
+ (originalString.charAt(i) !== " " || !currentString.charAt("\u00A0"))) {
+ return i;
+ }
+ }
+ return currentString.length;
+}
+
+promise_test(async () => {
+ reset();
+ const kText = "abc def ghi";
+ editor.innerHTML = `<p>${kText}</p>`;
+ let p = editor.querySelector("p");
+ selection.collapse(p.firstChild, "abc def".length);
+ await sendBackspaceKey(kShift);
+ let startOffset = getFirstDifferentOffset(p.firstChild.data, kText);
+ let length = kText.length - p.firstChild.data.length;
+ assert_equals(editor.innerHTML.replace(/&nbsp;/g, " "),
+ `<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length)}</p>`);
+ if (startOffset === kText.length) {
+ checkBeforeinputAndInputEventsOnNOOP();
+ return;
+ }
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: p.firstChild,
+ startOffset: startOffset,
+ endContainer: p.firstChild,
+ endOffset: startOffset + length,
+ });
+ checkGetTargetRangesOfInput();
+}, 'Shift + Backspace at "<p>abc def[] ghi</p>"');
+
+promise_test(async () => {
+ reset();
+ const kText = "abc def ghi";
+ editor.innerHTML = `<p>${kText}</p>`;
+ let p = editor.querySelector("p");
+ selection.collapse(p.firstChild, "abc def".length);
+ await sendBackspaceKey(kControl);
+ let startOffset = getFirstDifferentOffset(p.firstChild.data, kText);
+ let length = kText.length - p.firstChild.data.length;
+ assert_equals(editor.innerHTML.replace(/&nbsp;/g, " "),
+ `<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length)}</p>`);
+ if (startOffset === kText.length) {
+ checkBeforeinputAndInputEventsOnNOOP();
+ return;
+ }
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: p.firstChild,
+ startOffset: startOffset,
+ endContainer: p.firstChild,
+ endOffset: startOffset + length,
+ });
+ checkGetTargetRangesOfInput();
+}, 'Control + Backspace at "<p>abc def[] ghi</p>"');
+
+promise_test(async () => {
+ reset();
+ const kText = "abc def ghi";
+ editor.innerHTML = `<p>${kText}</p>`;
+ let p = editor.querySelector("p");
+ selection.collapse(p.firstChild, "abc def".length);
+ await sendBackspaceKey(kAlt);
+ let startOffset = getFirstDifferentOffset(p.firstChild.data, kText);
+ let length = kText.length - p.firstChild.data.length;
+ assert_equals(editor.innerHTML.replace(/&nbsp;/g, " "),
+ `<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length)}</p>`);
+ if (startOffset === kText.length) {
+ checkBeforeinputAndInputEventsOnNOOP();
+ return;
+ }
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: p.firstChild,
+ startOffset: startOffset,
+ endContainer: p.firstChild,
+ endOffset: startOffset + length,
+ });
+ checkGetTargetRangesOfInput();
+}, 'Alt + Backspace at "<p>abc def[] ghi</p>"');
+
+promise_test(async () => {
+ reset();
+ const kText = "abc def ghi";
+ editor.innerHTML = `<p>${kText}</p>`;
+ let p = editor.querySelector("p");
+ selection.collapse(p.firstChild, "abc def".length);
+ await sendBackspaceKey(kMeta);
+ let startOffset = getFirstDifferentOffset(p.firstChild.data, kText);
+ let length = kText.length - p.firstChild.data.length;
+ assert_equals(editor.innerHTML.replace(/&nbsp;/g, " "),
+ `<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length)}</p>`);
+ if (startOffset === kText.length) {
+ checkBeforeinputAndInputEventsOnNOOP();
+ return;
+ }
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: p.firstChild,
+ startOffset: startOffset,
+ endContainer: p.firstChild,
+ endOffset: startOffset + length,
+ });
+ checkGetTargetRangesOfInput();
+}, 'Meta + Backspace at "<p>abc def[] ghi</p>"');
+
+promise_test(async () => {
+ reset();
+ const kText = "abc def";
+ editor.innerHTML = `<p> ${kText}</p>`;
+ let p = editor.querySelector("p");
+ selection.collapse(p.firstChild, "abc".length);
+ await sendBackspaceKey(kShift);
+ let visibleText = p.firstChild.data.replace(/^\s+/, "");
+ let invisibleWhiteSpaces = " ".repeat(p.firstChild.data.length - visibleText.length);
+ let startOffset = invisibleWhiteSpaces.length + getFirstDifferentOffset(visibleText, kText);
+ let length = kText.length + 3 - p.firstChild.data.length;
+ // If invisible white-spaces are deleted, they should be contained in the target range.
+ assert_equals(editor.innerHTML.replace(/&nbsp;/g, " "),
+ `<p>${invisibleWhiteSpaces + kText.substr(0, startOffset) + kText.substr(startOffset + length)}</p>`);
+ if (startOffset === kText.length) {
+ checkBeforeinputAndInputEventsOnNOOP();
+ return;
+ }
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: p.firstChild,
+ startOffset: startOffset,
+ endContainer: p.firstChild,
+ endOffset: startOffset + length,
+ });
+ checkGetTargetRangesOfInput();
+}, 'Shift + Backspace at "<p> abc[] def</p>"');
+
+promise_test(async () => {
+ reset();
+ const kText = "abc def";
+ editor.innerHTML = `<p> ${kText}</p>`;
+ let p = editor.querySelector("p");
+ selection.collapse(p.firstChild, "abc".length);
+ await sendBackspaceKey(kControl);
+ let visibleText = p.firstChild.data.replace(/^\s+/, "");
+ let invisibleWhiteSpaces = " ".repeat(p.firstChild.data.length - visibleText.length);
+ let startOffset = invisibleWhiteSpaces.length + getFirstDifferentOffset(visibleText, kText);
+ let length = kText.length + 3 - p.firstChild.data.length;
+ // If invisible white-spaces are deleted, they should be contained in the target range.
+ assert_equals(editor.innerHTML.replace(/&nbsp;/g, " "),
+ `<p>${invisibleWhiteSpaces + kText.substr(0, startOffset) + kText.substr(startOffset + length)}</p>`);
+ if (startOffset === kText.length) {
+ checkBeforeinputAndInputEventsOnNOOP();
+ return;
+ }
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: p.firstChild,
+ startOffset: startOffset,
+ endContainer: p.firstChild,
+ endOffset: startOffset + length,
+ });
+ checkGetTargetRangesOfInput();
+}, 'Control + Backspace at "<p> abc[] def</p>"');
+
+promise_test(async () => {
+ reset();
+ const kText = "abc def";
+ editor.innerHTML = `<p> ${kText}</p>`;
+ let p = editor.querySelector("p");
+ selection.collapse(p.firstChild, "abc".length);
+ await sendBackspaceKey(kAlt);
+ let visibleText = p.firstChild.data.replace(/^\s+/, "");
+ let invisibleWhiteSpaces = " ".repeat(p.firstChild.data.length - visibleText.length);
+ let startOffset = invisibleWhiteSpaces.length + getFirstDifferentOffset(visibleText, kText);
+ let length = kText.length + 3 - p.firstChild.data.length;
+ // If invisible white-spaces are deleted, they should be contained in the target range.
+ assert_equals(editor.innerHTML.replace(/&nbsp;/g, " "),
+ `<p>${invisibleWhiteSpaces + kText.substr(0, startOffset) + kText.substr(startOffset + length)}</p>`);
+ if (startOffset === kText.length) {
+ checkBeforeinputAndInputEventsOnNOOP();
+ return;
+ }
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: p.firstChild,
+ startOffset: startOffset,
+ endContainer: p.firstChild,
+ endOffset: startOffset + length,
+ });
+ checkGetTargetRangesOfInput();
+}, 'Alt + Backspace at "<p> abc[] def</p>"');
+
+promise_test(async () => {
+ reset();
+ const kText = "abc def";
+ editor.innerHTML = `<p> ${kText}</p>`;
+ let p = editor.querySelector("p");
+ selection.collapse(p.firstChild, "abc".length);
+ await sendBackspaceKey(kMeta);
+ let visibleText = p.firstChild.data.replace(/^\s+/, "");
+ let invisibleWhiteSpaces = " ".repeat(p.firstChild.data.length - visibleText.length);
+ let startOffset = invisibleWhiteSpaces.length + getFirstDifferentOffset(visibleText, kText);
+ let length = kText.length + 3 - p.firstChild.data.length;
+ // If invisible white-spaces are deleted, they should be contained in the target range.
+ assert_equals(editor.innerHTML.replace(/&nbsp;/g, " "),
+ `<p>${invisibleWhiteSpaces + kText.substr(0, startOffset) + kText.substr(startOffset + length)}</p>`);
+ if (startOffset === kText.length) {
+ checkBeforeinputAndInputEventsOnNOOP();
+ return;
+ }
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: p.firstChild,
+ startOffset: startOffset,
+ endContainer: p.firstChild,
+ endOffset: startOffset + length,
+ });
+ checkGetTargetRangesOfInput();
+}, 'Meta + Backspace at "<p> abc[] def</p>"');
+
+</script>
diff --git a/tests/wpt/web-platform-tests/input-events/input-events-get-target-ranges-forwarddelete.tentative.html b/tests/wpt/web-platform-tests/input-events/input-events-get-target-ranges-forwarddelete.tentative.html
new file mode 100644
index 00000000000..3780324cf92
--- /dev/null
+++ b/tests/wpt/web-platform-tests/input-events/input-events-get-target-ranges-forwarddelete.tentative.html
@@ -0,0 +1,808 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>InputEvent.getTargetRanges() at Delete (forward delete)</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<div contenteditable></div>
+<script>
+const kDeleteKey = "\uE017";
+const kShift = "\uE008";
+const kMeta = "\uE03d";
+const kControl = "\uE009";
+const kAlt = "\uE00A";
+
+let selection = getSelection();
+let editor = document.querySelector("div[contenteditable]");
+let beforeinput = [];
+let input = [];
+editor.addEventListener("beforeinput", (e) => {
+ // NOTE: Blink makes `getTargetRanges()` return empty range after propagaion,
+ // but this test wants to check the result during propagation.
+ // Therefore, we need to cache the result, but will assert if
+ // `getTargetRanges()` returns different ranges after checking the
+ // cached ranges.
+ e.cachedRanges = e.getTargetRanges();
+ beforeinput.push(e);
+});
+editor.addEventListener("input", (e) => {
+ e.cachedRanges = e.getTargetRanges();
+ input.push(e);
+});
+
+function reset() {
+ editor.focus();
+ beforeinput = [];
+ input = [];
+}
+
+function getRangeDescription(range) {
+ function getNodeDescription(node) {
+ if (!node) {
+ return "null";
+ }
+ switch (node.nodeType) {
+ case Node.TEXT_NODE:
+ case Node.COMMENT_NODE:
+ case Node.CDATA_SECTION_NODE:
+ return `${node.nodeName} "${node.data}"`;
+ case Node.ELEMENT_NODE:
+ return `<${node.nodeName.toLowerCase()}>`;
+ default:
+ return `${node.nodeName}`;
+ }
+ }
+ if (range === null) {
+ return "null";
+ }
+ if (range === undefined) {
+ return "undefined";
+ }
+ return range.startContainer == range.endContainer && range.startOffset == range.endOffset
+ ? `(${getNodeDescription(range.startContainer)}, ${range.startOffset})`
+ : `(${getNodeDescription(range.startContainer)}, ${range.startOffset}) - (${getNodeDescription(range.endContainer)}, ${range.endOffset})`;
+}
+
+function getArrayOfRangesDescription(arrayOfRanges) {
+ if (arrayOfRanges === null) {
+ return "null";
+ }
+ if (arrayOfRanges === undefined) {
+ return "undefined";
+ }
+ if (!Array.isArray(arrayOfRanges)) {
+ return "Unknown Object";
+ }
+ if (arrayOfRanges.length === 0) {
+ return "[]";
+ }
+ let result = "[";
+ for (let range of arrayOfRanges) {
+ result += `{${getRangeDescription(range)}},`;
+ }
+ result += "]";
+ return result;
+}
+
+function sendDeleteKey(modifier) {
+ if (!modifier) {
+ return new test_driver.Actions()
+ .keyDown(kDeleteKey)
+ .keyUp(kDeleteKey)
+ .send();
+ }
+ return new test_driver.Actions()
+ .keyDown(modifier)
+ .keyDown(kDeleteKey)
+ .keyUp(kDeleteKey)
+ .keyUp(modifier)
+ .send();
+}
+
+function checkGetTargetRangesKeepReturningSameValue(event) {
+ // https://github.com/w3c/input-events/issues/114
+ assert_equals(getArrayOfRangesDescription(event.getTargetRanges()),
+ getArrayOfRangesDescription(event.cachedRanges),
+ `${event.type}.getTargetRanges() should keep returning the same array of ranges even after its propagation finished`);
+}
+
+function checkGetTargetRangesOfBeforeinputOnDeleteSomething(expectedRange) {
+ assert_equals(beforeinput.length, 1,
+ "One beforeinput event should be fired if the key operation deletes something");
+ assert_true(Array.isArray(beforeinput[0].cachedRanges),
+ "beforeinput[0].getTargetRanges() should return an array of StaticRange instances during propagation");
+ // Before checking the length of array of ranges, we should check the first
+ // range first because the first range data is more important than whether
+ // there are additional unexpected ranges.
+ if (beforeinput[0].cachedRanges.length > 0) {
+ assert_equals(
+ getRangeDescription(beforeinput[0].cachedRanges[0]),
+ getRangeDescription(expectedRange),
+ `beforeinput.getTargetRanges() should return expected range (inputType is "${beforeinput[0].inputType}")`);
+ assert_equals(beforeinput[0].cachedRanges.length, 1,
+ "beforeinput.getTargetRanges() should return one range within an array");
+ }
+ assert_equals(beforeinput[0].cachedRanges, 1,
+ "One range should be returned from getTargetRanges() when the key operation deletes something");
+ checkGetTargetRangesKeepReturningSameValue(beforeinput[0]);
+}
+
+function checkGetTargetRangesOfInputOnDeleteSomething() {
+ assert_equals(input.length, 1,
+ "One input event should be fired if the key operation deletes something");
+ // https://github.com/w3c/input-events/issues/113
+ assert_true(Array.isArray(input[0].cachedRanges),
+ "input[0].getTargetRanges() should return an array of StaticRange instances during propagation");
+ assert_equals(input[0].cachedRanges.length, 0,
+ "input[0].getTargetRanges() should return empty array during propagation");
+ checkGetTargetRangesKeepReturningSameValue(input[0]);
+}
+
+function checkBeforeinputAndInputEventsOnNOOP() {
+ assert_equals(beforeinput.length, 0,
+ "beforeinput event shouldn't be fired when the key operation does not cause modifying the DOM tree");
+ assert_equals(input.length, 0,
+ "input event shouldn't be fired when the key operation does not cause modifying the DOM tree");
+}
+
+// Simply deletes the next ASCII character of caret position.
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<p>abc</p>";
+ selection.collapse(editor.firstChild.firstChild, 2);
+ await sendDeleteKey();
+ assert_equals(editor.innerHTML, "<p>ab</p>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: editor.firstChild.firstChild,
+ startOffset: 2,
+ endContainer: editor.firstChild.firstChild,
+ endOffset: 3,
+ });
+ checkGetTargetRangesOfInputOnDeleteSomething();
+}, 'Delete at "<p>ab[]c</p>"');
+
+// Simply deletes the next ASCII character of caret position.
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<p>abc</p>";
+ selection.collapse(editor.firstChild.firstChild, 1);
+ await sendDeleteKey();
+ assert_equals(editor.innerHTML, "<p>ac</p>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: editor.firstChild.firstChild,
+ startOffset: 1,
+ endContainer: editor.firstChild.firstChild,
+ endOffset: 2,
+ });
+ checkGetTargetRangesOfInputOnDeleteSomething();
+}, 'Delete at "<p>a[]bc</p>"');
+
+// Simply deletes the next ASCII character of caret position.
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<p>abc</p>";
+ selection.collapse(editor.firstChild.firstChild, 0);
+ await sendDeleteKey();
+ assert_equals(editor.innerHTML, "<p>bc</p>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: editor.firstChild.firstChild,
+ startOffset: 0,
+ endContainer: editor.firstChild.firstChild,
+ endOffset: 1,
+ });
+ checkGetTargetRangesOfInputOnDeleteSomething();
+}, 'Delete at "<p>[]abc</p>"');
+
+// Should delete the `<span>` element becase it becomes empty.
+// However, we need discussion whether the `<span>` element should be
+// contained by a range of `getTargetRanges()`.
+// https://github.com/w3c/input-events/issues/112
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<p>a<span>b</span>c</p>";
+ let a = editor.querySelector("span").previousSibling;
+ selection.collapse(a, 1);
+ await sendDeleteKey();
+ assert_equals(editor.innerHTML, "<p>ac</p>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: a,
+ startOffset: 1,
+ endContainer: editor.firstChild,
+ endOffset: 2,
+ });
+ checkGetTargetRangesOfInputOnDeleteSomething();
+}, 'Delete at "<p>a[]<span>b</span>c</p>"');
+
+// Should delete the `<span>` element becase it becomes empty.
+// However, we need discussion whether the `<span>` element should be
+// contained by a range of `getTargetRanges()`.
+// https://github.com/w3c/input-events/issues/112
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<p>a<span>b</span>c</p>";
+ let b = editor.querySelector("span").firstChild;
+ selection.collapse(b, 0);
+ await sendDeleteKey();
+ assert_equals(editor.innerHTML, "<p>ac</p>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: editor.firstChild,
+ startOffset: 1,
+ endContainer: editor.firstChild,
+ endOffset: 2,
+ });
+ checkGetTargetRangesOfInputOnDeleteSomething();
+}, 'Delete at "<p>a<span>[]b</span>c</p>"');
+
+// Invisible trailing white-space may be deleted when the last visible
+// character is deleted. If it's deleted, it should be contained by
+// the range of `getTargetRanges()`, but needs discussion.
+// https://github.com/w3c/input-events/issues/112
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<p>abc </p>";
+ selection.collapse(editor.firstChild.firstChild, 2);
+ await sendDeleteKey();
+ assert_in_array(editor.innerHTML, ["<p>ab</p>", "<p>ab </p>"]);
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: editor.firstChild.firstChild,
+ startOffset: 2,
+ endContainer: editor.firstChild.firstChild,
+ endOffset: editor.firstChild.firstChild.data.length == 2 ? 4 : 3,
+ });
+ checkGetTargetRangesOfInputOnDeleteSomething();
+}, 'Delete at "<p>ab[]c </p>"');
+
+// Invisible trailing white-spaces in current block and invisible leading
+// white-spaces in the following block should be deleted for avoiding they
+// becoming visible when the blocks are joined. Perhaps, they should be
+// contained by the range of `getTargetRanges()`, but needs discussion.
+// https://github.com/w3c/input-events/issues/112
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<p>abc </p><p> def</p>";
+ let p1 = editor.firstChild;
+ let abc = p1.firstChild;
+ let p2 = p1.nextSibling;
+ let def = p2.firstChild;
+ selection.collapse(abc, 3);
+ await sendDeleteKey();
+ assert_equals(editor.innerHTML, "<p>abcdef</p>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: abc,
+ startOffset: 3,
+ endContainer: def,
+ endOffset: 3,
+ });
+ checkGetTargetRangesOfInputOnDeleteSomething();
+}, 'Delete at "<p>abc[] </p><p> def</p>"');
+
+// Invisible trailing white-spaces in current block and invisible leading
+// white-spaces in the following block should be deleted for avoiding they
+// becoming visible when the blocks are joined. Perhaps, they should be
+// contained by the range of `getTargetRanges()`, but needs discussion.
+// https://github.com/w3c/input-events/issues/112
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<p>abc </p><p> def</p>";
+ let p1 = editor.firstChild;
+ let abc = p1.firstChild;
+ let p2 = p1.nextSibling;
+ let def = p2.firstChild;
+ selection.collapse(abc, 4);
+ await sendDeleteKey();
+ assert_equals(editor.innerHTML, "<p>abcdef</p>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: abc,
+ startOffset: 3,
+ endContainer: def,
+ endOffset: 3,
+ });
+ checkGetTargetRangesOfInputOnDeleteSomething();
+}, 'Delete at "<p>abc [] </p><p> def</p>"');
+
+// Invisible trailing white-spaces in current block and invisible leading
+// white-spaces in the following block should be deleted for avoiding they
+// becoming visible when the blocks are joined. Perhaps, they should be
+// contained by the range of `getTargetRanges()`, but needs discussion.
+// https://github.com/w3c/input-events/issues/112
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<p>abc </p><p> def</p>";
+ let p1 = editor.firstChild;
+ let abc = p1.firstChild;
+ let p2 = p1.nextSibling;
+ let def = p2.firstChild;
+ selection.collapse(abc, 5);
+ await sendDeleteKey();
+ assert_equals(editor.innerHTML, "<p>abcdef</p>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: abc,
+ startOffset: 3,
+ endContainer: def,
+ endOffset: 3,
+ });
+ checkGetTargetRangesOfInputOnDeleteSomething();
+}, 'Delete at "<p>abc [] </p><p> def</p>"');
+
+// Invisible trailing white-spaces in current block and invisible leading
+// white-spaces in the following block should be deleted for avoiding they
+// becoming visible when the blocks are joined. Perhaps, they should be
+// contained by the range of `getTargetRanges()`, but needs discussion.
+// https://github.com/w3c/input-events/issues/112
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<p>abc </p><p> def</p>";
+ let p1 = editor.firstChild;
+ let abc = p1.firstChild;
+ let p2 = p1.nextSibling;
+ let def = p2.firstChild;
+ selection.collapse(abc, 6);
+ await sendDeleteKey();
+ assert_equals(editor.innerHTML, "<p>abcdef</p>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: abc,
+ startOffset: 3,
+ endContainer: def,
+ endOffset: 3,
+ });
+ checkGetTargetRangesOfInputOnDeleteSomething();
+}, 'Delete at "<p>abc []</p><p> def</p>"');
+
+// Invisible trailing white-spaces in current block and invisible leading
+// white-spaces in the following block should be deleted for avoiding they
+// becoming visible when the blocks are joined. Perhaps, they should be
+// contained by the range of `getTargetRanges()`, but needs discussion.
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<p>abc </p><p> def</p>";
+ let p1 = editor.firstChild;
+ let abc = p1.firstChild;
+ let p2 = p1.nextSibling;
+ let def = p2.firstChild;
+ selection.setBaseAndExtent(abc, 6, def, 0);
+ await sendDeleteKey();
+ assert_equals(editor.innerHTML, "<p>abcdef</p>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: abc,
+ startOffset: 3,
+ endContainer: def,
+ endOffset: 3,
+ });
+ checkGetTargetRangesOfInputOnDeleteSomething();
+}, 'Delete at "<p>abc [</p><p>] def</p>"');
+
+// Invisible leading white-spaces in the following block should be deleted
+// for avoiding they becoming visible when the blocks are joined, but
+// preformatted trailing white-spaces in the first block shouldn't be
+// deleted. Perhaps, the invisible white-spaces should be contained by
+// the range of `getTargetRanges()`, but needs discussion.
+// https://github.com/w3c/input-events/issues/112
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<pre>abc </pre><p> def</p>";
+ let pre = editor.firstChild;
+ let abc = pre.firstChild;
+ let p = pre.nextSibling;
+ let def = p.firstChild;
+ selection.collapse(abc, 6);
+ await sendDeleteKey();
+ assert_equals(editor.innerHTML, "<pre>abc def</pre>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: abc,
+ startOffset: 6,
+ endContainer: def,
+ endOffset: 3,
+ });
+ checkGetTargetRangesOfInputOnDeleteSomething();
+}, 'Delete at "<pre>abc []</pre><p> def</p>"');
+
+// Invisible leading/trailing white-spaces in the following block should be
+// deleted for avoiding they becoming visible when the blocks are joined, but
+// preformatted trailing white-spaces in the first block shouldn't be
+// deleted. Perhaps, the invisible leading white-spaces should be contained
+// by the range of `getTargetRanges()`, but needs discussion.
+// And also not sure whether the trailing white-spaces should be contained
+// by additional range of `getTargetRanges()` or not because of the
+// implementation cost and runtime cost. Needs discuss.
+// https://github.com/w3c/input-events/issues/112
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<pre>abc </pre><p> def</p>";
+ let pre = editor.firstChild;
+ let abc = pre.firstChild;
+ let p = pre.nextSibling;
+ let def = p.firstChild;
+ selection.collapse(abc, 6);
+ await sendDeleteKey();
+ assert_equals(editor.innerHTML, "<pre>abc def</pre>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: abc,
+ startOffset: 6,
+ endContainer: def,
+ endOffset: 3,
+ });
+ checkGetTargetRangesOfInputOnDeleteSomething();
+}, 'Delete at "<pre>abc []</pre><p> def </p>"');
+
+// Invisible trailing white-spaces in the first block should be deleted
+// when the block is joined with the preformated following block, but
+// the leading white-spaces in the preformatted block shouldn't be
+// removed. So, in this case, the invisible trailing white-spaces should
+// be in the range of `getTargetRanges()`, but not so for the preformatted
+// visible leading white-spaces. But needs discussion.
+// https://github.com/w3c/input-events/issues/112
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<p>abc </p><pre> def</pre>";
+ let p = editor.firstChild;
+ let abc = p.firstChild;
+ let pre = p.nextSibling;
+ let def = pre.firstChild;
+ selection.collapse(abc, 3);
+ await sendDeleteKey();
+ assert_in_array(editor.innerHTML, ["<p>abc &nbsp; def</p>",
+ "<p>abc&nbsp;&nbsp; def</p>",
+ "<p>abc&nbsp; &nbsp;def</p>",
+ "<p>abc &nbsp;&nbsp;def</p>"]);
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: abc,
+ startOffset: 3,
+ endContainer: def,
+ endOffset: 0,
+ });
+ checkGetTargetRangesOfInputOnDeleteSomething();
+}, 'Delete at "<p>abc[] </p><pre> def</pre>"');
+
+// Deleting from before invisible trailing `<br>` element of a block
+// should delete the `<br>` element and join the blocks. Therefore,
+// the target range should contain the `<br>` element and block boundaries.
+// But maybe needs discussion.
+// https://github.com/w3c/input-events/issues/112
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<p>abc<br></p><p>def</p>";
+ let p1 = editor.firstChild;
+ let abc = p1.firstChild;
+ let p2 = p1.nextSibling;
+ let def = p2.firstChild;
+ selection.collapse(abc, 3);
+ await sendDeleteKey();
+ assert_equals(editor.innerHTML, "<p>abcdef</p>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: abc,
+ startOffset: 3,
+ endContainer: def,
+ endOffset: 0,
+ });
+ checkGetTargetRangesOfInputOnDeleteSomething();
+}, 'Delete at "<p>abc[]<br></p><p>def</p>"');
+
+// Deleting from last empty line in the first block should delete the
+// invisible `<br>` element for the last empty line and join the blocks.
+// In this case, the invisible `<br>` element should be contained in the
+// range of `getTargetRanges()`, but needs discussion.
+// https://github.com/w3c/input-events/issues/112
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<p>abc<br><br></p><p>def</p>";
+ let p1 = editor.firstChild;
+ let abc = p1.firstChild;
+ let p2 = p1.nextSibling;
+ let def = p2.firstChild;
+ selection.collapse(p1, 2);
+ await sendDeleteKey();
+ assert_equals(editor.innerHTML, "<p>abc<br>def</p>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: p1,
+ startOffset: 2,
+ endContainer: def,
+ endOffset: 0,
+ });
+ checkGetTargetRangesOfInputOnDeleteSomething();
+}, 'Delete at "<p>abc<br>{}<br></p><p>def</p>"');
+
+// Deleting visible `<br>` element should be contained by a range of
+// `getTargetRanges()`.
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<p>abc<br>def</p>";
+ let abc = editor.firstChild.firstChild;
+ selection.collapse(abc, 3);
+ await sendDeleteKey();
+ assert_equals(editor.innerHTML, "<p>abcdef</p>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: abc,
+ startOffset: 3,
+ endContainer: editor.querySelector("p"),
+ endOffset: 2,
+ });
+ checkGetTargetRangesOfInputOnDeleteSomething();
+}, 'Delete at "<p>abc[]<br>def</p>"');
+
+// Deleting visible `<br>` element should be contained by a range of
+// `getTargetRanges()`. However, when only the `<br>` element is selected,
+// the range shouldn't start from nor end by surrounding text nodes?
+// https://github.com/w3c/input-events/issues/112
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<p>abc<br>def</p>";
+ selection.setBaseAndExtent(editor.firstChild, 1, editor.firstChild, 2);
+ await sendDeleteKey();
+ assert_equals(editor.innerHTML, "<p>abcdef</p>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: editor.firstChild,
+ startOffset: 1,
+ endContainer: editor.firstChild,
+ endOffset: 2,
+ });
+ checkGetTargetRangesOfInputOnDeleteSomething();
+}, 'Delete at "<p>abc{<br>}def</p>"');
+
+// Joining parent block and child block should remove invisible preceding
+// white-spaces of the child block and invisible leading white-spaces in
+// the child block, and they should be contained in a range of
+// `getTargetRanges()`, but maybe needs discussion.
+// https://github.com/w3c/input-events/issues/112
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<div>abc <p> def<br>ghi</p></div>";
+ let p = editor.querySelector("p");
+ let def = p.firstChild;
+ let abc = editor.firstChild.firstChild;
+ selection.collapse(abc, 3);
+ await sendDeleteKey();
+ assert_equals(editor.innerHTML, "<div>abcdef<p>ghi</p></div>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: abc,
+ startOffset: 3,
+ endContainer: def,
+ endOffset: 3,
+ });
+ checkGetTargetRangesOfInputOnDeleteSomething();
+}, 'Delete at "<div>abc[] <p> def<br>ghi</p></div>"');
+
+// Joining child block and parent block should remove invisible trailing
+// white-spaces of the child block and invisible following white-spaces
+// in the parent block, and they should be contained by a range of
+// `getTaregetRanges()`, but maybe needs discussion.
+// https://github.com/w3c/input-events/issues/112
+promise_test(async () => {
+ reset();
+ editor.innerHTML = "<div><p>abc </p> def</div>";
+ let abc = editor.querySelector("p").firstChild;
+ let def = editor.querySelector("p").nextSibling;
+ selection.collapse(abc, 3);
+ await sendDeleteKey();
+ assert_equals(editor.innerHTML, "<div><p>abcdef</p></div>");
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: abc,
+ startOffset: 3,
+ endContainer: def,
+ endOffset: 3,
+ });
+ checkGetTargetRangesOfInputOnDeleteSomething();
+}, 'Delete at "<div><p>abc[] </p> def</div>"');
+
+// The following tests check whether the range returned from
+// `beforeinput[0].getTargetRanges()` is modified or different range is
+// modified instead. I.e., they don't test which type of deletion should
+// occur. Therefore, their result depends on browser's key bindings,
+// system settings and running OS.
+
+function getFirstDifferentOffset(currentString, originalString) {
+ for (let i = 0; i < currentString.length; i++) {
+ if (currentString.charAt(i) !== originalString.charAt(i) &&
+ (originalString.charAt(i) !== " " || !currentString.charAt("\u00A0"))) {
+ return i;
+ }
+ }
+ return currentString.length;
+}
+
+promise_test(async () => {
+ reset();
+ const kText = "abc def ghi";
+ editor.innerHTML = `<p>${kText}</p>`;
+ let p = editor.querySelector("p");
+ selection.collapse(p.firstChild, "abc ".length);
+ await sendDeleteKey(kShift);
+ let startOffset = getFirstDifferentOffset(p.firstChild.data, kText);
+ let length = kText.length - p.firstChild.data.length;
+ assert_equals(editor.innerHTML.replace(/&nbsp;/g, " "),
+ `<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length)}</p>`);
+ if (startOffset === kText.length) {
+ checkBeforeinputAndInputEventsOnNOOP();
+ return;
+ }
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: p.firstChild,
+ startOffset: startOffset,
+ endContainer: p.firstChild,
+ endOffset: startOffset + length,
+ });
+ checkGetTargetRangesOfInputOnDeleteSomething();
+}, 'Shift + Delete at "<p>abc []def ghi</p>"');
+
+promise_test(async () => {
+ reset();
+ const kText = "abc def ghi";
+ editor.innerHTML = `<p>${kText}</p>`;
+ let p = editor.querySelector("p");
+ selection.collapse(p.firstChild, "abc ".length);
+ await sendDeleteKey(kControl);
+ let startOffset = getFirstDifferentOffset(p.firstChild.data, kText);
+ let length = kText.length - p.firstChild.data.length;
+ assert_equals(editor.innerHTML.replace(/&nbsp;/g, " "),
+ `<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length)}</p>`);
+ if (startOffset === kText.length) {
+ checkBeforeinputAndInputEventsOnNOOP();
+ return;
+ }
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: p.firstChild,
+ startOffset: startOffset,
+ endContainer: p.firstChild,
+ endOffset: startOffset + length,
+ });
+ checkGetTargetRangesOfInputOnDeleteSomething();
+}, 'Control + Delete at "<p>abc []def ghi</p>"');
+
+promise_test(async () => {
+ reset();
+ const kText = "abc def ghi";
+ editor.innerHTML = `<p>${kText}</p>`;
+ let p = editor.querySelector("p");
+ selection.collapse(p.firstChild, "abc ".length);
+ await sendDeleteKey(kAlt);
+ let startOffset = getFirstDifferentOffset(p.firstChild.data, kText);
+ let length = kText.length - p.firstChild.data.length;
+ assert_equals(editor.innerHTML.replace(/&nbsp;/g, " "),
+ `<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length)}</p>`);
+ if (startOffset === kText.length) {
+ checkBeforeinputAndInputEventsOnNOOP();
+ return;
+ }
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: p.firstChild,
+ startOffset: startOffset,
+ endContainer: p.firstChild,
+ endOffset: startOffset + length,
+ });
+ checkGetTargetRangesOfInputOnDeleteSomething();
+}, 'Alt + Delete at "<p>abc []def ghi</p>"');
+
+promise_test(async () => {
+ reset();
+ const kText = "abc def ghi";
+ editor.innerHTML = `<p>${kText}</p>`;
+ let p = editor.querySelector("p");
+ selection.collapse(p.firstChild, "abc ".length);
+ await sendDeleteKey(kMeta);
+ let startOffset = getFirstDifferentOffset(p.firstChild.data, kText);
+ let length = kText.length - p.firstChild.data.length;
+ assert_equals(editor.innerHTML.replace(/&nbsp;/g, " "),
+ `<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length)}</p>`);
+ if (startOffset === kText.length) {
+ checkBeforeinputAndInputEventsOnNOOP();
+ return;
+ }
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: p.firstChild,
+ startOffset: startOffset,
+ endContainer: p.firstChild,
+ endOffset: startOffset + length,
+ });
+ checkGetTargetRangesOfInputOnDeleteSomething();
+}, 'Meta + Delete at "<p>abc []def ghi</p>"');
+
+promise_test(async () => {
+ reset();
+ const kText = "abc def";
+ editor.innerHTML = `<p>${kText} </p>`;
+ let p = editor.querySelector("p");
+ selection.collapse(p.firstChild, "abc ".length);
+ await sendDeleteKey(kShift);
+ let visibleText = p.firstChild.data.replace(/%s+$/, "");
+ let invisibleWhiteSpaces = " ".repeat(p.firstChild.data.length - visibleText.length);
+ let startOffset = invisibleWhiteSpaces.length + getFirstDifferentOffset(visibleText, kText);
+ let length = kText.length + 3 - p.firstChild.data.length;
+ // If invisible white-spaces are deleted, they should be contained in the target range.
+ assert_equals(editor.innerHTML.replace(/&nbsp;/g, " "),
+ `<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length) + invisibleWhiteSpaces}</p>`);
+ if (startOffset === kText.length) {
+ checkBeforeinputAndInputEventsOnNOOP();
+ return;
+ }
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: p.firstChild,
+ startOffset: startOffset,
+ endContainer: p.firstChild,
+ endOffset: startOffset + length,
+ });
+ checkGetTargetRangesOfInputOnDeleteSomething();
+}, 'Shift + Delete at "<p>abc []def </p>"');
+
+promise_test(async () => {
+ reset();
+ const kText = "abc def";
+ editor.innerHTML = `<p>${kText} </p>`;
+ let p = editor.querySelector("p");
+ selection.collapse(p.firstChild, "abc ".length);
+ await sendDeleteKey(kControl);
+ let visibleText = p.firstChild.data.replace(/%s+$/, "");
+ let invisibleWhiteSpaces = " ".repeat(p.firstChild.data.length - visibleText.length);
+ let startOffset = invisibleWhiteSpaces.length + getFirstDifferentOffset(visibleText, kText);
+ let length = kText.length + 3 - p.firstChild.data.length;
+ // If invisible white-spaces are deleted, they should be contained in the target range.
+ assert_equals(editor.innerHTML.replace(/&nbsp;/g, " "),
+ `<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length) + invisibleWhiteSpaces}</p>`);
+ if (startOffset === kText.length) {
+ checkBeforeinputAndInputEventsOnNOOP();
+ return;
+ }
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: p.firstChild,
+ startOffset: startOffset,
+ endContainer: p.firstChild,
+ endOffset: startOffset + length,
+ });
+ checkGetTargetRangesOfInputOnDeleteSomething();
+}, 'Control + Delete at "<p>abc []def </p>"');
+
+promise_test(async () => {
+ reset();
+ const kText = "abc def";
+ editor.innerHTML = `<p>${kText} </p>`;
+ let p = editor.querySelector("p");
+ selection.collapse(p.firstChild, "abc ".length);
+ await sendDeleteKey(kAlt);
+ let visibleText = p.firstChild.data.replace(/%s+$/, "");
+ let invisibleWhiteSpaces = " ".repeat(p.firstChild.data.length - visibleText.length);
+ let startOffset = invisibleWhiteSpaces.length + getFirstDifferentOffset(visibleText, kText);
+ let length = kText.length + 3 - p.firstChild.data.length;
+ // If invisible white-spaces are deleted, they should be contained in the target range.
+ assert_equals(editor.innerHTML.replace(/&nbsp;/g, " "),
+ `<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length) + invisibleWhiteSpaces}</p>`);
+ if (startOffset === kText.length) {
+ checkBeforeinputAndInputEventsOnNOOP();
+ return;
+ }
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: p.firstChild,
+ startOffset: startOffset,
+ endContainer: p.firstChild,
+ endOffset: startOffset + length,
+ });
+ checkGetTargetRangesOfInputOnDeleteSomething();
+}, 'Alt + Delete at "<p>abc []def </p>"');
+
+promise_test(async () => {
+ reset();
+ const kText = "abc def";
+ editor.innerHTML = `<p>${kText} s</p>`;
+ let p = editor.querySelector("p");
+ selection.collapse(p.firstChild, "abc ".length);
+ await sendDeleteKey(kMeta);
+ let visibleText = p.firstChild.data.replace(/%s+$/, "");
+ let invisibleWhiteSpaces = " ".repeat(p.firstChild.data.length - visibleText.length);
+ let startOffset = invisibleWhiteSpaces.length + getFirstDifferentOffset(visibleText, kText);
+ let length = kText.length + 3 - p.firstChild.data.length;
+ // If invisible white-spaces are deleted, they should be contained in the target range.
+ assert_equals(editor.innerHTML.replace(/&nbsp;/g, " "),
+ `<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length) + invisibleWhiteSpaces}</p>`);
+ if (startOffset === kText.length) {
+ checkBeforeinputAndInputEventsOnNOOP();
+ return;
+ }
+ checkGetTargetRangesOfBeforeinputOnDeleteSomething({
+ startContainer: p.firstChild,
+ startOffset: startOffset,
+ endContainer: p.firstChild,
+ endOffset: startOffset + length,
+ });
+ checkGetTargetRangesOfInputOnDeleteSomething();
+}, 'Meta + Delete at "<p>abc []def</p>"');
+
+</script>
diff --git a/tests/wpt/web-platform-tests/interfaces/web-share.idl b/tests/wpt/web-platform-tests/interfaces/web-share.idl
index c29a29d0b4e..b66bcd81fe9 100644
--- a/tests/wpt/web-platform-tests/interfaces/web-share.idl
+++ b/tests/wpt/web-platform-tests/interfaces/web-share.idl
@@ -8,7 +8,7 @@ partial interface Navigator {
};
dictionary ShareData {
- FrozenArray<File> files;
+ sequence<File> files;
USVString title;
USVString text;
USVString url;
diff --git a/tests/wpt/web-platform-tests/intersection-observer/observer-callback-arguments.html b/tests/wpt/web-platform-tests/intersection-observer/observer-callback-arguments.html
new file mode 100644
index 00000000000..6e816969d00
--- /dev/null
+++ b/tests/wpt/web-platform-tests/intersection-observer/observer-callback-arguments.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<meta charset=utf-8>
+<title>IntersectionObserver: callback arguments</title>
+<link rel="help" href="https://w3c.github.io/IntersectionObserver/#notify-intersection-observers-algo">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+"use strict";
+
+async_test(t => {
+ const io = new IntersectionObserver(function(entries, observer) {
+ t.step(() => {
+ assert_equals(this, io);
+ assert_equals(arguments.length, 2);
+ assert_true(Array.isArray(entries));
+ assert_equals(entries.length, 1);
+ assert_true(entries[0] instanceof IntersectionObserverEntry);
+ assert_equals(observer, io);
+
+ io.disconnect();
+ t.done();
+ });
+ });
+
+ io.observe(document.body);
+}, "Callback is invoked with |this| value of IntersectionObserver and two arguments");
+</script>
diff --git a/tests/wpt/web-platform-tests/largest-contentful-paint/invisible-images-composited-1.html b/tests/wpt/web-platform-tests/largest-contentful-paint/invisible-images-composited-1.html
index 495645ab41e..7723d2f2bea 100644
--- a/tests/wpt/web-platform-tests/largest-contentful-paint/invisible-images-composited-1.html
+++ b/tests/wpt/web-platform-tests/largest-contentful-paint/invisible-images-composited-1.html
@@ -13,13 +13,17 @@
.displayNone {
display: none;
}
- .composited {
+ .willChangeTransform {
will-change: transform;
}
+ .willChangeOpacity {
+ will-change: opacity;
+ }
</style>
-<img src='/images/blue.png' class='opacity0 composited' id='opacity0'/>
-<img src='/images/green.png' class='visibilityHidden composited' id='visibilityHidden'/>
-<img src='/images/red.png' class='displayNone composited' id='displayNone'/>
+<img src='/images/blue.png' class='opacity0 willChangeTransform' id='opacity0-willChangeTransform'/>
+<img src='/images/green.png' class='visibilityHidden willChangeTransform' id='visibilityHidden'/>
+<img src='/images/red.png' class='displayNone willChangeTransform' id='displayNone'/>
+<img src='/images/blue.png' class='opacity0 willChangeOpacity' id='opacity0-willChangeOpacity'/>
<div class='opacity0 composited'><img src='/images/yellow.png' id='divOpacity0'/></div>
<div class='visibilityHidden composited'><img src='/images/yellow.png' id='divVisibilityHidden'/></div>
<div class='displayNone composited'><img src='/images/yellow.png' id='divDisplayNone'/></div>
diff --git a/tests/wpt/web-platform-tests/layout-instability/child-shift-with-parent-overflow-hidden.html b/tests/wpt/web-platform-tests/layout-instability/child-shift-with-parent-overflow-hidden.html
new file mode 100644
index 00000000000..d69e55a51b8
--- /dev/null
+++ b/tests/wpt/web-platform-tests/layout-instability/child-shift-with-parent-overflow-hidden.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<title>Layout Instability: parent (with overflow:hidden) and child moved together</title>
+<link rel="help" href="https://wicg.github.io/layout-instability/" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/util.js"></script>
+<div id="parent" style="position: relative; width: 200px; height: 200px;
+ border: 50px solid blue; overflow: hidden">
+ <div id="child" style="height: 400px"></div>
+</div>
+<script>
+
+promise_test(async () => {
+ const watcher = new ScoreWatcher;
+
+ // Wait for the initial render to complete.
+ await waitForAnimationFrames(2);
+
+ // Modify the position of the div.
+ const parent = document.querySelector("#parent");
+ parent.style.top = '100px';
+
+ // Only the parent area should be reported.
+ const expectedScore = computeExpectedScore(300 * (300 + 100), 100);
+
+ // Observer fires after the frame is painted.
+ assert_equals(watcher.score, 0);
+ await watcher.promise;
+ assert_equals(watcher.score, expectedScore);
+}, 'Parent (with overflow:hidden) and child moved together.');
+
+</script>
diff --git a/tests/wpt/web-platform-tests/layout-instability/child-shift-with-parent.html b/tests/wpt/web-platform-tests/layout-instability/child-shift-with-parent.html
new file mode 100644
index 00000000000..7271af6d4a0
--- /dev/null
+++ b/tests/wpt/web-platform-tests/layout-instability/child-shift-with-parent.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<title>Layout Instability: parent/child moved together</title>
+<link rel="help" href="https://wicg.github.io/layout-instability/" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/util.js"></script>
+<div id="parent" style="position: relative; width: 100px; height: 100px; border: 100px solid blue">
+ <div id="child" style="height: 300px"></div>
+</div>
+<script>
+
+promise_test(async () => {
+ const watcher = new ScoreWatcher;
+
+ // Wait for the initial render to complete.
+ await waitForAnimationFrames(2);
+
+ // Modify the position of the div.
+ const parent = document.querySelector("#parent");
+ parent.style.top = '100px';
+
+ // If the implementation reports child and parent separately
+ // (overlapping are should be excluded):
+ const expectedScoreMin = computeExpectedScore(300 * (300 + 100) + 100 * 100, 100);
+ // If the implementation reports parent bounding box (including child):
+ const expectedScoreMax = computeExpectedScore(300 * (400 + 100), 100);
+
+ // Observer fires after the frame is painted.
+ assert_equals(watcher.score, 0);
+ await watcher.promise;
+ assert_between_inclusive(watcher.score, expectedScoreMin, expectedScoreMax);
+}, 'Parent/child movement.');
+
+</script>
diff --git a/tests/wpt/web-platform-tests/layout-instability/inline-flow-shift-vertical-rl.html b/tests/wpt/web-platform-tests/layout-instability/inline-flow-shift-vertical-rl.html
index 06bc34c37dd..a89cad145b2 100644
--- a/tests/wpt/web-platform-tests/layout-instability/inline-flow-shift-vertical-rl.html
+++ b/tests/wpt/web-platform-tests/layout-instability/inline-flow-shift-vertical-rl.html
@@ -1,5 +1,5 @@
<!DOCTYPE html>
-<title>Layout Instability: simple block movement is detected</title>
+<title>Layout Instability: vertical-rl inline/text movement is detected</title>
<link rel="help" href="https://wicg.github.io/layout-instability/" />
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
@@ -38,7 +38,7 @@ promise_test(async () => {
assert_equals(watcher.score, 0);
await watcher.promise;
assert_between_exclusive(watcher.score, expectedScoreMin, expectedScoreMax);
-}, 'Inline flow movement.');
+}, 'Vertical-rl inline flow movement.');
</script>
</body>
diff --git a/tests/wpt/web-platform-tests/layout-instability/inline-flow-shift.html b/tests/wpt/web-platform-tests/layout-instability/inline-flow-shift.html
index 39550da6588..0385f29c2f9 100644
--- a/tests/wpt/web-platform-tests/layout-instability/inline-flow-shift.html
+++ b/tests/wpt/web-platform-tests/layout-instability/inline-flow-shift.html
@@ -1,5 +1,5 @@
<!DOCTYPE html>
-<title>Layout Instability: simple block movement is detected</title>
+<title>Layout Instability: inline/text movement is detected</title>
<link rel="help" href="https://wicg.github.io/layout-instability/" />
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
diff --git a/tests/wpt/web-platform-tests/origin-isolation/resources/child-frame-script.mjs b/tests/wpt/web-platform-tests/origin-isolation/resources/child-frame-script.mjs
index 2c6760a3e37..783e36092da 100644
--- a/tests/wpt/web-platform-tests/origin-isolation/resources/child-frame-script.mjs
+++ b/tests/wpt/web-platform-tests/origin-isolation/resources/child-frame-script.mjs
@@ -30,6 +30,14 @@ window.onmessage = async (e) => {
} catch (e) {
parent.postMessage(e.name, "*");
}
+ } else if (e.data.command === "access frameElement") {
+ if (frameElement === null) {
+ parent.postMessage("null", "*");
+ } else if (frameElement?.constructor?.name === "HTMLIFrameElement") {
+ parent.postMessage("frameElement accessed successfully", "*");
+ } else {
+ parent.postMessage("something wierd happened", "*");
+ }
} else if (e.data.command === "get originIsolationRestricted") {
parent.postMessage(self.originIsolationRestricted, "*");
}
diff --git a/tests/wpt/web-platform-tests/origin-isolation/resources/helpers.mjs b/tests/wpt/web-platform-tests/origin-isolation/resources/helpers.mjs
index e8425c240b5..73f9406b476 100644
--- a/tests/wpt/web-platform-tests/origin-isolation/resources/helpers.mjs
+++ b/tests/wpt/web-platform-tests/origin-isolation/resources/helpers.mjs
@@ -79,12 +79,18 @@ export function testSameAgentCluster(testFrames, testLabelPrefix) {
promise_test(async () => {
const frameWindow = frames[testFrames[1]];
+ const frameElement = document.querySelectorAll("iframe")[testFrames[1]];
// Must not throw
frameWindow.document;
// Must not throw
frameWindow.location.href;
+
+ assert_not_equals(frameElement.contentDocument, null, "contentDocument");
+
+ const whatHappened = await accessFrameElement(frameWindow);
+ assert_equals(whatHappened, "frameElement accessed successfully");
}, `${prefix}setting document.domain must give sync access`);
} else {
// Between the two children at the index given by testFrames[0] and
@@ -101,6 +107,9 @@ export function testSameAgentCluster(testFrames, testLabelPrefix) {
const whatHappened2 = await accessLocationHrefBetween(testFrames);
assert_equals(whatHappened2, "accessed location.href successfully");
+
+ // We don't test contentDocument/frameElement for these because accessing
+ // those via siblings has to go through the parent anyway.
}, `${prefix}setting document.domain must give sync access`);
}
}
@@ -130,13 +139,20 @@ export function testDifferentAgentClusters(testFrames, testLabelPrefix) {
promise_test(async () => {
const frameWindow = frames[testFrames[1]];
+ const frameElement = document.querySelectorAll("iframe")[testFrames[1]];
assert_throws_dom("SecurityError", DOMException, () => {
frameWindow.document;
});
+
assert_throws_dom("SecurityError", DOMException, () => {
frameWindow.location.href;
});
+
+ assert_equals(frameElement.contentDocument, null, "contentDocument");
+
+ const whatHappened = await accessFrameElement(frameWindow);
+ assert_equals(whatHappened, "null");
}, `${prefix}setting document.domain must not give sync access`);
} else {
// Between the two children at the index given by testFrames[0] and
@@ -153,6 +169,9 @@ export function testDifferentAgentClusters(testFrames, testLabelPrefix) {
const whatHappened2 = await accessLocationHrefBetween(testFrames);
assert_equals(whatHappened2, "SecurityError");
+
+ // We don't test contentDocument/frameElement for these because accessing
+ // those via siblings has to go through the parent anyway.
}, `${prefix}setting document.domain must not give sync access`);
}
}
@@ -263,6 +282,11 @@ async function accessLocationHrefBetween(testFrames) {
return waitForMessage(sourceFrame);
}
+async function accessFrameElement(frameWindow) {
+ frameWindow.postMessage({ command: "access frameElement" }, "*");
+ return waitForMessage(frameWindow);
+}
+
function waitForMessage(expectedSource) {
return new Promise(resolve => {
const handler = e => {
diff --git a/tests/wpt/web-platform-tests/pointerevents/compat/pointerevent_compat-mouse-events-when-removing-nodes.html b/tests/wpt/web-platform-tests/pointerevents/compat/pointerevent_compat-mouse-events-when-removing-nodes.html
index 4388b2db308..88d03b7965e 100644
--- a/tests/wpt/web-platform-tests/pointerevents/compat/pointerevent_compat-mouse-events-when-removing-nodes.html
+++ b/tests/wpt/web-platform-tests/pointerevents/compat/pointerevent_compat-mouse-events-when-removing-nodes.html
@@ -64,18 +64,16 @@ function createGreenBoxAndAddListeners() {
function performActions() {
var rect = document.getElementById("green").getBoundingClientRect();
- var x1 = rect.left + 5;
- var y1 = rect.top + 5;
+ var x1 = Math.ceil(rect.left + 5);
+ var y1 = Math.ceil(rect.top + 5);
return new test_driver.Actions()
.pointerMove(0, 0)
- .pointerMove(rect.left + 5, rect.top + 5)
- .pointerDown(0)
- .pointerUp(0)
+ .pointerMove(x1, y1)
+ .pointerDown()
+ .pointerUp()
.send()
- .then( () => {
- return resolveWhen( () => receivedEvents.length == 6 );
- });
+ .then( () => resolveWhen( () => receivedEvents.length == 6 ) );
}
function testScenario(targetEvent, expectedEvents, description) {
diff --git a/tests/wpt/web-platform-tests/pointerevents/compat/pointerevent_mouse-on-object.html b/tests/wpt/web-platform-tests/pointerevents/compat/pointerevent_mouse-on-object.html
index d8912a2652b..fa0e97ff30c 100644
--- a/tests/wpt/web-platform-tests/pointerevents/compat/pointerevent_mouse-on-object.html
+++ b/tests/wpt/web-platform-tests/pointerevents/compat/pointerevent_mouse-on-object.html
@@ -39,10 +39,13 @@ promise_test(async() => {
done_clicked = false;
receivedEvents = [];
- await new test_driver.Actions().pointerMove(rect.left+5, rect.top+5).pointerDown(0).pointerUp(0).send().then(() => {
- return clickInTarget("mouse", done);
- });
- await resolveWhen(()=>{return done_clicked;});
+ await new test_driver.Actions()
+ .pointerMove(Math.ceil(rect.left+5), Math.ceil(rect.top+5))
+ .pointerDown()
+ .pointerUp()
+ .send()
+ .then(() => clickInTarget("mouse", done));
+ await resolveWhen(() => done_clicked);
assert_array_equals(receivedEvents, ["pointermove", "mousemove", "pointerdown", "mousedown", "pointerup", "mouseup"],
"Click on object should result in the correct sequence of events");
@@ -52,10 +55,14 @@ promise_test(async() => {
done_clicked = false;
receivedEvents = [];
- await new test_driver.Actions().pointerMove(rect.left+5, rect.top+5).pointerDown(0).pointerMove(rect.left-5, rect.top-5).pointerUp(0).send().then(() => {
- return clickInTarget("mouse", done);
- });
- await resolveWhen(()=>{return done_clicked;});
+ await new test_driver.Actions()
+ .pointerMove(Math.ceil(rect.left+5), Math.ceil(rect.top+5))
+ .pointerDown()
+ .pointerMove(Math.ceil(rect.left-5), Math.ceil(rect.top-5))
+ .pointerUp()
+ .send()
+ .then(() => clickInTarget("mouse", done));
+ await resolveWhen(() => done_clicked);
assert_array_equals(receivedEvents, ["pointermove", "mousemove", "pointerdown", "mousedown", "pointermove", "mousemove", "pointerup", "mouseup"],
"Drag from object should result in the correct sequence of events");
diff --git a/tests/wpt/web-platform-tests/pointerevents/compat/pointerevent_mouse-pointer-preventdefault.html b/tests/wpt/web-platform-tests/pointerevents/compat/pointerevent_mouse-pointer-preventdefault.html
new file mode 100644
index 00000000000..a727325a5b1
--- /dev/null
+++ b/tests/wpt/web-platform-tests/pointerevents/compat/pointerevent_mouse-pointer-preventdefault.html
@@ -0,0 +1,199 @@
+<!DOCTYPE HTML>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script type="text/javascript" src="../pointerevent_support.js"></script>
+<style>
+div.box {
+ margin: 10px;
+ padding: 50px;
+ float: left;
+}
+</style>
+<h1>Verifies the effect of pointer event prevent-default on following pointer & mouse events.</h1>
+<div id="target" class="box" style="background-color:green;">
+</div>
+
+<script>
+var receivedEvents = [];
+var mouseEventList = ["mousedown", "mouseup", "mouseenter", "mouseleave", "mouseover", "mouseout", "mousemove"];
+var pointerEventList = ["pointerdown", "pointerup", "pointerenter", "pointerleave", "pointerover", "pointerout", "pointermove"];
+
+var preventDefaultList = ["none"].concat(pointerEventList);
+var eventToPreventDefault = "";
+var seqNo = 0;
+
+function init() {
+ var targetDiv = document.getElementById("target");
+
+ mouseEventList.forEach(function(eventName) {
+ targetDiv.addEventListener(eventName, function(event) {
+ ++seqNo;
+ receivedEvents.push(`${seqNo}.${eventName}@target`);
+ });
+ });
+
+ pointerEventList.forEach(function(eventName) {
+ targetDiv.addEventListener(eventName, function(event) {
+ var preventDefaultMsg = "";
+ if (event.type == eventToPreventDefault) {
+ event.preventDefault();
+ preventDefaultMsg = "_prevented_default";
+ }
+ ++seqNo;
+ receivedEvents.push(`${seqNo}.${eventName}@target${preventDefaultMsg}`);
+ });
+ });
+}
+
+var expectedEvents = new Map([
+ ["none", ["1.pointerover@target", "2.pointerenter@target", "3.mouseover@target",
+ "4.mouseenter@target", "5.pointermove@target", "6.mousemove@target",
+ "7.pointerdown@target", "8.mousedown@target", "9.pointerup@target",
+ "10.mouseup@target", "11.pointerdown@target", "12.mousedown@target",
+ "13.pointermove@target", "14.mousemove@target", "15.pointerout@target",
+ "16.pointerleave@target", "17.mouseout@target", "18.mouseleave@target",
+ "19.pointerover@target", "20.pointerenter@target", "21.mouseover@target",
+ "22.mouseenter@target", "23.pointermove@target", "24.mousemove@target",
+ "25.pointerup@target", "26.mouseup@target", "27.pointerout@target",
+ "28.pointerleave@target", "29.mouseout@target", "30.mouseleave@target"
+ ]],
+ ["pointerdown", ["1.pointerover@target", "2.pointerenter@target", "3.mouseover@target",
+ "4.mouseenter@target", "5.pointermove@target", "6.mousemove@target",
+ "7.pointerdown@target_prevented_default", "8.pointerup@target",
+ "9.pointerdown@target_prevented_default",
+ "10.pointermove@target", "11.pointerout@target", "12.pointerleave@target",
+ "13.mouseout@target", "14.mouseleave@target", "15.pointerover@target",
+ "16.pointerenter@target", "17.mouseover@target", "18.mouseenter@target",
+ "19.pointermove@target", "20.pointerup@target", "21.pointerout@target",
+ "22.pointerleave@target", "23.mouseout@target", "24.mouseleave@target"
+ ]],
+ ["pointerup", ["1.pointerover@target", "2.pointerenter@target", "3.mouseover@target",
+ "4.mouseenter@target", "5.pointermove@target", "6.mousemove@target",
+ "7.pointerdown@target", "8.mousedown@target", "9.pointerup@target_prevented_default",
+ "10.mouseup@target", "11.pointerdown@target", "12.mousedown@target",
+ "13.pointermove@target", "14.mousemove@target", "15.pointerout@target",
+ "16.pointerleave@target", "17.mouseout@target", "18.mouseleave@target",
+ "19.pointerover@target", "20.pointerenter@target", "21.mouseover@target",
+ "22.mouseenter@target", "23.pointermove@target", "24.mousemove@target",
+ "25.pointerup@target_prevented_default", "26.mouseup@target", "27.pointerout@target",
+ "28.pointerleave@target", "29.mouseout@target", "30.mouseleave@target"]],
+ ["pointerenter", ["1.pointerover@target", "2.pointerenter@target_prevented_default", "3.mouseover@target",
+ "4.mouseenter@target", "5.pointermove@target", "6.mousemove@target",
+ "7.pointerdown@target", "8.mousedown@target", "9.pointerup@target",
+ "10.mouseup@target", "11.pointerdown@target", "12.mousedown@target",
+ "13.pointermove@target", "14.mousemove@target", "15.pointerout@target",
+ "16.pointerleave@target", "17.mouseout@target", "18.mouseleave@target",
+ "19.pointerover@target", "20.pointerenter@target_prevented_default", "21.mouseover@target",
+ "22.mouseenter@target", "23.pointermove@target", "24.mousemove@target",
+ "25.pointerup@target", "26.mouseup@target", "27.pointerout@target",
+ "28.pointerleave@target", "29.mouseout@target", "30.mouseleave@target"]],
+ ["pointerleave", ["1.pointerover@target", "2.pointerenter@target", "3.mouseover@target",
+ "4.mouseenter@target", "5.pointermove@target", "6.mousemove@target",
+ "7.pointerdown@target", "8.mousedown@target", "9.pointerup@target",
+ "10.mouseup@target", "11.pointerdown@target", "12.mousedown@target",
+ "13.pointermove@target", "14.mousemove@target", "15.pointerout@target",
+ "16.pointerleave@target_prevented_default", "17.mouseout@target", "18.mouseleave@target",
+ "19.pointerover@target", "20.pointerenter@target", "21.mouseover@target",
+ "22.mouseenter@target", "23.pointermove@target", "24.mousemove@target",
+ "25.pointerup@target", "26.mouseup@target", "27.pointerout@target",
+ "28.pointerleave@target_prevented_default", "29.mouseout@target", "30.mouseleave@target"]],
+ ["pointerover", ["1.pointerover@target_prevented_default", "2.pointerenter@target", "3.mouseover@target",
+ "4.mouseenter@target", "5.pointermove@target", "6.mousemove@target",
+ "7.pointerdown@target", "8.mousedown@target", "9.pointerup@target",
+ "10.mouseup@target", "11.pointerdown@target", "12.mousedown@target",
+ "13.pointermove@target", "14.mousemove@target", "15.pointerout@target",
+ "16.pointerleave@target", "17.mouseout@target", "18.mouseleave@target",
+ "19.pointerover@target_prevented_default", "20.pointerenter@target", "21.mouseover@target",
+ "22.mouseenter@target", "23.pointermove@target", "24.mousemove@target",
+ "25.pointerup@target", "26.mouseup@target", "27.pointerout@target",
+ "28.pointerleave@target", "29.mouseout@target", "30.mouseleave@target"]],
+ ["pointerout", ["1.pointerover@target", "2.pointerenter@target", "3.mouseover@target",
+ "4.mouseenter@target", "5.pointermove@target", "6.mousemove@target",
+ "7.pointerdown@target", "8.mousedown@target", "9.pointerup@target",
+ "10.mouseup@target", "11.pointerdown@target", "12.mousedown@target",
+ "13.pointermove@target", "14.mousemove@target", "15.pointerout@target_prevented_default",
+ "16.pointerleave@target", "17.mouseout@target", "18.mouseleave@target",
+ "19.pointerover@target", "20.pointerenter@target", "21.mouseover@target",
+ "22.mouseenter@target", "23.pointermove@target", "24.mousemove@target",
+ "25.pointerup@target", "26.mouseup@target", "27.pointerout@target_prevented_default",
+ "28.pointerleave@target", "29.mouseout@target", "30.mouseleave@target"]],
+ ["pointermove", ["1.pointerover@target", "2.pointerenter@target", "3.mouseover@target",
+ "4.mouseenter@target", "5.pointermove@target_prevented_default", "6.mousemove@target",
+ "7.pointerdown@target", "8.mousedown@target", "9.pointerup@target",
+ "10.mouseup@target", "11.pointerdown@target", "12.mousedown@target",
+ "13.pointermove@target_prevented_default", "14.mousemove@target", "15.pointerout@target",
+ "16.pointerleave@target", "17.mouseout@target", "18.mouseleave@target",
+ "19.pointerover@target", "20.pointerenter@target", "21.mouseover@target",
+ "22.mouseenter@target", "23.pointermove@target_prevented_default", "24.mousemove@target",
+ "25.pointerup@target", "26.mouseup@target", "27.pointerout@target",
+ "28.pointerleave@target", "29.mouseout@target", "30.mouseleave@target"]]
+]);
+
+async function runTestForDefaultEvent(preventDefaultEvent) {
+ promise_test((test)=>
+ new Promise(async (resolve, reject)=>{
+ test.add_cleanup(()=>{
+ receivedEvents = [];
+ seqNo = 0;
+ eventToPreventDefault = "";
+ });
+ eventToPreventDefault = preventDefaultEvent;
+
+ try{
+ // if awaited Promise rejects then fail the test
+ await performActions(test, preventDefaultEvent);
+ }
+ catch(e){
+ reject(e);
+ }
+ test.step(()=>{
+ assert_array_equals(expectedEvents.get(preventDefaultEvent), receivedEvents);});
+ resolve();
+ }), `Verifies the effect of pointer event prevent-default on ${preventDefaultEvent}`);
+}
+
+async function runTests(){
+ // create one test for each event in preventDefaultList
+ // run all tests one by one
+ preventDefaultList.forEach(preventDefaultEvent=>runTestForDefaultEvent(preventDefaultEvent));
+}
+
+function performActions(test, preventDefaultEvent){
+ let targetDiv = document.getElementById("target");
+ let rect = targetDiv.getBoundingClientRect();
+ let x1 = Math.ceil(rect.left - 3);
+ let y1 = Math.ceil(rect.top - 5);
+ let x2 = Math.ceil(rect.left + 3);
+ let y2 = Math.ceil(rect.top + 5);
+
+ let eventWatcher = new EventWatcher(test, targetDiv, ["mouseleave"], ()=>waitForAnimationFrames(900));
+ // wait for all expected events to happen.
+ // Because each test ends with mouseleave and there are 2 mouseleave events,
+ // we use EventWatcher to wait for the two mouseleave events to happen
+ let donePromise = eventWatcher.wait_for(["mouseleave", "mouseleave"], { record: 'all' });
+ let actionsPromise = new test_driver.Actions()
+ .pointerMove(0, 0)
+ // start with mouse outside target
+ .pointerMove(x1, y1)
+ // move into target and click
+ .pointerMove(x2, y2)
+ .pointerDown()
+ .pointerUp()
+ // drag out of and into target & release within target
+ .pointerDown()
+ .pointerMove(x2+5, y2+5)
+ .pointerMove(x1, y1)
+ .pointerMove(x2, y2)
+ .pointerUp()
+ // move outside target again
+ .pointerMove(x1, y1)
+ .send();
+ return Promise.all([donePromise, actionsPromise]);
+}
+
+init();
+runTests();
+</script>
diff --git a/tests/wpt/web-platform-tests/streams/readable-streams/tee.any.js b/tests/wpt/web-platform-tests/streams/readable-streams/tee.any.js
index b6a95368aa5..55d4532ff83 100644
--- a/tests/wpt/web-platform-tests/streams/readable-streams/tee.any.js
+++ b/tests/wpt/web-platform-tests/streams/readable-streams/tee.any.js
@@ -317,6 +317,57 @@ promise_test(t => {
}, 'ReadableStream teeing: erroring the original should immediately error the branches');
+promise_test(async t => {
+
+ let controller;
+ const rs = new ReadableStream({
+ start(c) {
+ controller = c;
+ }
+ });
+
+ const [reader1, reader2] = rs.tee().map(branch => branch.getReader());
+ const cancelPromise = reader2.cancel();
+
+ controller.enqueue('a');
+
+ const read1 = await reader1.read();
+ assert_object_equals(read1, { value: 'a', done: false }, 'first read() from branch1 should fulfill with the chunk');
+
+ controller.close();
+
+ const read2 = await reader1.read();
+ assert_object_equals(read2, { value: undefined, done: true }, 'second read() from branch1 should be done');
+
+ await Promise.all([
+ reader1.closed,
+ cancelPromise
+ ]);
+
+}, 'ReadableStream teeing: canceling branch1 should finish when branch2 reads until end of stream');
+
+promise_test(async t => {
+
+ let controller;
+ const theError = { name: 'boo!' };
+ const rs = new ReadableStream({
+ start(c) {
+ controller = c;
+ }
+ });
+
+ const [reader1, reader2] = rs.tee().map(branch => branch.getReader());
+ const cancelPromise = reader2.cancel();
+
+ controller.error(theError);
+
+ await Promise.all([
+ promise_rejects_exactly(t, theError, reader1.read()),
+ cancelPromise
+ ]);
+
+}, 'ReadableStream teeing: canceling branch1 should finish when original stream errors');
+
test(t => {
// Copy original global.
diff --git a/tests/wpt/web-platform-tests/svg/types/scripted/SVGGeometryElement.getPointAtLength-03.svg b/tests/wpt/web-platform-tests/svg/types/scripted/SVGGeometryElement.getPointAtLength-03.svg
index 61737efb7da..8d3f7e36123 100644
--- a/tests/wpt/web-platform-tests/svg/types/scripted/SVGGeometryElement.getPointAtLength-03.svg
+++ b/tests/wpt/web-platform-tests/svg/types/scripted/SVGGeometryElement.getPointAtLength-03.svg
@@ -8,7 +8,6 @@
<script><![CDATA[
test(function() {
var pathElement = document.createElementNS("http://www.w3.org/2000/svg", "path");
- pathElement.setAttribute("d", 'M0,20 L400,20 L640,20');
assert_throws_dom("InvalidStateError", function() { pathElement.getPointAtLength(700) });
}, document.title + " with SVGPathElement");
diff --git a/tests/wpt/web-platform-tests/tools/ci/run_tc.py b/tests/wpt/web-platform-tests/tools/ci/run_tc.py
index a5a8ca7db29..3a3b0d8090b 100755
--- a/tests/wpt/web-platform-tests/tools/ci/run_tc.py
+++ b/tests/wpt/web-platform-tests/tools/ci/run_tc.py
@@ -141,7 +141,7 @@ def install_certificates():
def install_chrome(channel):
- if channel in ("experimental", "dev", "nightly"):
+ if channel in ("experimental", "dev"):
deb_archive = "google-chrome-unstable_current_amd64.deb"
elif channel == "beta":
deb_archive = "google-chrome-beta_current_amd64.deb"
@@ -323,7 +323,10 @@ def setup_environment(args):
if "chrome" in args.browser:
assert args.channel is not None
- install_chrome(args.channel)
+ # Chrome Nightly will be installed via `wpt run --install-browser`
+ # later in taskcluster-run.py.
+ if args.channel != "nightly":
+ install_chrome(args.channel)
elif "webkitgtk_minibrowser" in args.browser:
assert args.channel is not None
install_webkitgtk(args.channel)
diff --git a/tests/wpt/web-platform-tests/tools/ci/taskcluster-run.py b/tests/wpt/web-platform-tests/tools/ci/taskcluster-run.py
index 61d05689287..245ee7fa592 100755
--- a/tests/wpt/web-platform-tests/tools/ci/taskcluster-run.py
+++ b/tests/wpt/web-platform-tests/tools/ci/taskcluster-run.py
@@ -8,19 +8,19 @@ import shutil
import subprocess
import sys
-browser_specific_args = {
- "servo": ["--install-browser", "--processes=12"]
-}
-
-def get_browser_args(product):
+def get_browser_args(product, channel):
if product == "firefox":
local_binary = os.path.expanduser(os.path.join("~", "build", "firefox", "firefox"))
if os.path.exists(local_binary):
return ["--binary=%s" % local_binary]
print("WARNING: Local firefox binary not found")
return ["--install-browser", "--install-webdriver"]
- return browser_specific_args.get(product, [])
+ if product == "servo":
+ return ["--install-browser", "--processes=12"]
+ if product == "chrome" and channel == "nightly":
+ return ["--install-browser", "--install-webdriver"]
+ return []
def find_wptreport(args):
@@ -43,7 +43,7 @@ def gzip_file(filename, delete_original=True):
os.unlink(filename)
-def main(product, commit_range, wpt_args):
+def main(product, channel, commit_range, wpt_args):
"""Invoke the `wpt run` command according to the needs of the Taskcluster
continuous integration service."""
@@ -75,7 +75,7 @@ def main(product, commit_range, wpt_args):
"--no-headless",
"--verify-log-full"
]
- wpt_args += get_browser_args(product)
+ wpt_args += get_browser_args(product, channel)
# Hack to run servo with one process only for wdspec
if product == "servo" and "--test-type=wdspec" in wpt_args:
@@ -84,6 +84,9 @@ def main(product, commit_range, wpt_args):
command = ["python", "./wpt", "run"] + wpt_args + [product]
logger.info("Executing command: %s" % " ".join(command))
+ with open("/home/test/artifacts/checkrun.md", "a") as f:
+ f.write("\n**WPT Command:** `%s`\n\n" % " ".join(command))
+
retcode = subprocess.call(command, env=dict(os.environ, TERM="dumb"))
if retcode != 0:
sys.exit(retcode)
@@ -104,6 +107,8 @@ if __name__ == "__main__":
determine the list of test to execute""")
parser.add_argument("product", action="store",
help="Browser to run tests in")
+ parser.add_argument("channel", action="store",
+ help="Channel of the browser")
parser.add_argument("wpt_args", nargs="*",
help="Arguments to forward to `wpt run` command")
main(**vars(parser.parse_args()))
diff --git a/tests/wpt/web-platform-tests/tools/ci/tc/decision.py b/tests/wpt/web-platform-tests/tools/ci/tc/decision.py
index 0820a6798b5..f52f5b093f0 100644
--- a/tests/wpt/web-platform-tests/tools/ci/tc/decision.py
+++ b/tests/wpt/web-platform-tests/tools/ci/tc/decision.py
@@ -241,6 +241,8 @@ def create_tc_task(event, task, taskgroup_id, depends_on_ids, env_extra=None):
},
"routes": ["checks"]
}
+ if "extra" in task:
+ task_data["extra"].update(task["extra"])
if env_extra:
task_data["payload"]["env"].update(env_extra)
if depends_on_ids:
diff --git a/tests/wpt/web-platform-tests/tools/ci/tc/github_checks_output.py b/tests/wpt/web-platform-tests/tools/ci/tc/github_checks_output.py
new file mode 100644
index 00000000000..16d39900298
--- /dev/null
+++ b/tests/wpt/web-platform-tests/tools/ci/tc/github_checks_output.py
@@ -0,0 +1,29 @@
+class GitHubChecksOutputter(object):
+ """Provides a method to output data to be shown in the GitHub Checks UI.
+
+ This can be useful to provide a summary of a given check (e.g. the lint)
+ to enable developers to quickly understand what has gone wrong. The output
+ supports markdown format.
+
+ See https://docs.taskcluster.net/docs/reference/integrations/github/checks#custom-text-output-in-checks
+ """
+ def __init__(self, path):
+ self.path = path
+
+ def output(self, line):
+ with open(self.path, 'a') as f:
+ f.write(line)
+ f.write('\n')
+
+
+__outputter = None
+def get_gh_checks_outputter(kwargs):
+ """Return the outputter for GitHub Checks output, if enabled.
+
+ :param kwargs: The arguments passed to the program (to look for the
+ github_checks_text_file field)
+ """
+ global __outputter
+ if kwargs['github_checks_text_file'] and __outputter is None:
+ __outputter = GitHubChecksOutputter(kwargs['github_checks_text_file'])
+ return __outputter
diff --git a/tests/wpt/web-platform-tests/tools/ci/tc/tasks/test.yml b/tests/wpt/web-platform-tests/tools/ci/tc/tasks/test.yml
index dd14fc71b91..b1534c9d230 100644
--- a/tests/wpt/web-platform-tests/tools/ci/tc/tasks/test.yml
+++ b/tests/wpt/web-platform-tests/tools/ci/tc/tasks/test.yml
@@ -10,6 +10,13 @@ components:
public/results:
path: /home/test/artifacts
type: directory
+ extra:
+ github:
+ customCheckRun:
+ # We set both textArtifactName and annotationsArtifactName due
+ # to https://github.com/taskcluster/taskcluster/issues/3191
+ textArtifactName: public/results/checkrun.md
+ annotationsArtifactName: public/results/checkrun.md
wpt-testharness:
chunks: 16
@@ -52,6 +59,7 @@ components:
command: >-
./tools/ci/taskcluster-run.py
${vars.browser}
+ ${vars.channel}
--
--channel=${vars.channel}
--log-wptreport=../artifacts/wpt_report.json
@@ -60,6 +68,7 @@ components:
--this-chunk=${chunks.id}
--total-chunks=${chunks.total}
--test-type=${vars.suite}
+
trigger-master:
trigger:
branch:
@@ -164,6 +173,13 @@ tasks:
- trigger-daily
- trigger-push
- vars:
+ # Chromium ToT
+ browser: chrome
+ channel: nightly
+ use:
+ - trigger-daily
+ - trigger-push
+ - vars:
browser: chrome
channel: dev
use:
@@ -239,6 +255,13 @@ tasks:
- trigger-daily
- trigger-push
- vars:
+ # Chromium ToT
+ browser: chrome
+ channel: nightly
+ use:
+ - trigger-daily
+ - trigger-push
+ - vars:
browser: chrome
channel: dev
use:
@@ -292,10 +315,12 @@ tasks:
./tools/ci/taskcluster-run.py
--commit-range base_head
${vars.browser}
+ ${vars.channel}
--
--channel=${vars.channel}
--verify
--verify-no-chaos-mode
+ --github-checks-text-file="/home/test/artifacts/checkrun.md"
- wpt-${vars.browser}-${vars.channel}-results:
use:
@@ -311,6 +336,7 @@ tasks:
./tools/ci/taskcluster-run.py
--commit-range base_head
${vars.browser}
+ ${vars.channel}
--
--channel=${vars.channel}
--no-fail-on-unexpected
@@ -333,6 +359,7 @@ tasks:
./tools/ci/taskcluster-run.py
--commit-range task_head
${vars.browser}
+ ${vars.channel}
--
--channel=${vars.channel}
--no-fail-on-unexpected
diff --git a/tests/wpt/web-platform-tests/tools/ci/tc/tests/test_valid.py b/tests/wpt/web-platform-tests/tools/ci/tc/tests/test_valid.py
index 88ffdb29511..472f83f86a0 100644
--- a/tests/wpt/web-platform-tests/tools/ci/tc/tests/test_valid.py
+++ b/tests/wpt/web-platform-tests/tools/ci/tc/tests/test_valid.py
@@ -128,7 +128,7 @@ def test_verify_payload():
'wpt-firefox-nightly-print-reftest-1',
'wpt-chrome-dev-print-reftest-1',
'lint']),
- ("pr_event.json", True, {".taskcluster.yml",".travis.yml","tools/ci/start.sh"},
+ ("pr_event.json", True, {".taskcluster.yml", ".travis.yml", "tools/ci/start.sh"},
['lint',
'tools/ unittests (Python 2)',
'tools/ unittests (Python 3.6)',
@@ -171,6 +171,22 @@ def test_verify_payload():
'wpt-firefox-stable-testharness-14',
'wpt-firefox-stable-testharness-15',
'wpt-firefox-stable-testharness-16',
+ 'wpt-chrome-nightly-testharness-1',
+ 'wpt-chrome-nightly-testharness-2',
+ 'wpt-chrome-nightly-testharness-3',
+ 'wpt-chrome-nightly-testharness-4',
+ 'wpt-chrome-nightly-testharness-5',
+ 'wpt-chrome-nightly-testharness-6',
+ 'wpt-chrome-nightly-testharness-7',
+ 'wpt-chrome-nightly-testharness-8',
+ 'wpt-chrome-nightly-testharness-9',
+ 'wpt-chrome-nightly-testharness-10',
+ 'wpt-chrome-nightly-testharness-11',
+ 'wpt-chrome-nightly-testharness-12',
+ 'wpt-chrome-nightly-testharness-13',
+ 'wpt-chrome-nightly-testharness-14',
+ 'wpt-chrome-nightly-testharness-15',
+ 'wpt-chrome-nightly-testharness-16',
'wpt-chrome-stable-testharness-1',
'wpt-chrome-stable-testharness-2',
'wpt-chrome-stable-testharness-3',
@@ -224,6 +240,11 @@ def test_verify_payload():
'wpt-firefox-stable-reftest-3',
'wpt-firefox-stable-reftest-4',
'wpt-firefox-stable-reftest-5',
+ 'wpt-chrome-nightly-reftest-1',
+ 'wpt-chrome-nightly-reftest-2',
+ 'wpt-chrome-nightly-reftest-3',
+ 'wpt-chrome-nightly-reftest-4',
+ 'wpt-chrome-nightly-reftest-5',
'wpt-chrome-stable-reftest-1',
'wpt-chrome-stable-reftest-2',
'wpt-chrome-stable-reftest-3',
@@ -241,6 +262,8 @@ def test_verify_payload():
'wpt-servo-nightly-reftest-5',
'wpt-firefox-stable-wdspec-1',
'wpt-firefox-stable-wdspec-2',
+ 'wpt-chrome-nightly-wdspec-1',
+ 'wpt-chrome-nightly-wdspec-2',
'wpt-chrome-stable-wdspec-1',
'wpt-chrome-stable-wdspec-2',
'wpt-webkitgtk_minibrowser-nightly-wdspec-1',
@@ -248,11 +271,13 @@ def test_verify_payload():
'wpt-servo-nightly-wdspec-1',
'wpt-servo-nightly-wdspec-2',
'wpt-firefox-stable-crashtest-1',
+ 'wpt-chrome-nightly-crashtest-1',
'wpt-chrome-stable-crashtest-1',
'wpt-webkitgtk_minibrowser-nightly-crashtest-1',
'wpt-servo-nightly-crashtest-1',
'wpt-firefox-stable-print-reftest-1',
- 'wpt-chrome-stable-print-reftest-1',])
+ 'wpt-chrome-nightly-print-reftest-1',
+ 'wpt-chrome-stable-print-reftest-1'])
])
def test_schedule_tasks(event_path, is_pr, files_changed, expected):
with mock.patch("tools.ci.tc.decision.get_fetch_rev", return_value=(None, None, None)):
diff --git a/tests/wpt/web-platform-tests/tools/serve/commands.json b/tests/wpt/web-platform-tests/tools/serve/commands.json
index a5457b55a33..ed1d72e60ec 100644
--- a/tests/wpt/web-platform-tests/tools/serve/commands.json
+++ b/tests/wpt/web-platform-tests/tools/serve/commands.json
@@ -12,7 +12,6 @@
"parser": "get_parser",
"help": "Run wptserve server for WAVE",
"virtualenv": true,
- "install": ["ua-parser"],
"requirements": ["../wave/requirements.txt"]
}
}
diff --git a/tests/wpt/web-platform-tests/tools/serve/test_functional.py b/tests/wpt/web-platform-tests/tools/serve/test_functional.py
index 894479d111c..5a918c2ee47 100644
--- a/tests/wpt/web-platform-tests/tools/serve/test_functional.py
+++ b/tests/wpt/web-platform-tests/tools/serve/test_functional.py
@@ -9,6 +9,7 @@ try:
import Queue as queue # noqa: N813
except ImportError:
import queue
+import sys
import tempfile
import threading
@@ -45,6 +46,8 @@ def tempfile_name():
os.remove(name)
+@pytest.mark.skipif(sys.version_info >= (3, 8) and sys.platform == 'darwin',
+ reason="multiprocessing test hangs in Python 3.8 on macOS (#24880)")
def test_subprocess_exit(server_subprocesses, tempfile_name):
timeout = 30
diff --git a/tests/wpt/web-platform-tests/tools/wpt/commands.json b/tests/wpt/web-platform-tests/tools/wpt/commands.json
index a47ab40d728..51f66d0decb 100644
--- a/tests/wpt/web-platform-tests/tools/wpt/commands.json
+++ b/tests/wpt/web-platform-tests/tools/wpt/commands.json
@@ -6,7 +6,6 @@
"help": "Run tests in a browser",
"virtualenv": true,
"install": [
- "requests",
"zstandard"
],
"requirements": [
@@ -25,9 +24,6 @@
"parser": "create_parser_update",
"help": "Update expectations files from raw logs.",
"virtualenv": true,
- "install": [
- "requests"
- ],
"requirements": [
"../wptrunner/requirements.txt"
]
@@ -51,6 +47,7 @@
"script": "run",
"parser": "get_parser",
"help": "Install browser components",
+ "virtualenv": true,
"install": [
"mozinstall"
]
diff --git a/tests/wpt/web-platform-tests/tools/wpt/tests/test_wpt.py b/tests/wpt/web-platform-tests/tools/wpt/tests/test_wpt.py
index b5ae79d1311..0b6aff42d57 100644
--- a/tests/wpt/web-platform-tests/tools/wpt/tests/test_wpt.py
+++ b/tests/wpt/web-platform-tests/tools/wpt/tests/test_wpt.py
@@ -188,6 +188,8 @@ def test_run_zero_tests():
@pytest.mark.slow
@pytest.mark.remote_network
+@pytest.mark.skipif(sys.version_info >= (3, 8) and sys.platform == 'darwin',
+ reason="multiprocessing test hangs in Python 3.8 on macOS (#24880)")
def test_run_failing_test():
"""Failing tests should be reported with a non-zero exit status unless the
`--no-fail-on-unexpected` option has been specified."""
@@ -211,6 +213,8 @@ def test_run_failing_test():
@pytest.mark.slow
@pytest.mark.remote_network
+@pytest.mark.skipif(sys.version_info >= (3, 8) and sys.platform == 'darwin',
+ reason="multiprocessing test hangs in Python 3.8 on macOS (#24880)")
def test_run_verify_unstable(temp_test):
"""Unstable tests should be reported with a non-zero exit status. Stable
tests should be reported with a zero exit status."""
diff --git a/tests/wpt/web-platform-tests/tools/wpt/wpt.py b/tests/wpt/web-platform-tests/tools/wpt/wpt.py
index 395db0394da..efa985c7cc1 100644
--- a/tests/wpt/web-platform-tests/tools/wpt/wpt.py
+++ b/tests/wpt/web-platform-tests/tools/wpt/wpt.py
@@ -38,6 +38,8 @@ def load_commands():
"requirements": [os.path.join(base_dir, item)
for item in props.get("requirements", [])]
}
+ if rv[command]["install"] or rv[command]["requirements"]:
+ assert rv[command]["virtualenv"]
return rv
diff --git a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/stability.py b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/stability.py
index 3f8989729fd..605b40281a1 100644
--- a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/stability.py
+++ b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/stability.py
@@ -13,6 +13,7 @@ from mozlog.handlers import BaseHandler, StreamHandler, LogLevelFilter
here = os.path.dirname(__file__)
localpaths = imp.load_source("localpaths", os.path.abspath(os.path.join(here, os.pardir, os.pardir, "localpaths.py")))
+from ci.tc.github_checks_output import get_gh_checks_outputter
from wpt.markdown import markdown_adjust, table
@@ -178,8 +179,32 @@ def err_string(results_dict, iterations):
return rv
+def write_github_checks_summary_inconsistent(log, inconsistent, iterations):
+ """Outputs a summary of inconsistent tests for GitHub Checks."""
+ log("Some affected tests had inconsistent (flaky) results:\n")
+ write_inconsistent(log, inconsistent, iterations)
+ log("\n")
+ log("These may be pre-existing or new flakes. Please try to reproduce (see "
+ "the above WPT command, though some flags may not be needed when "
+ "running locally) and determine if your change introduced the flake. "
+ "If you are unable to reproduce the problem, please tag "
+ "`@web-platform-tests/wpt-core-team` in a comment for help.\n")
+
+
+def write_github_checks_summary_slow_tests(log, slow):
+ """Outputs a summary of slow tests for GitHub Checks."""
+ log("Some affected tests had slow results:\n")
+ write_slow_tests(log, slow)
+ log("\n")
+ log("These may be pre-existing or newly slow tests. Slow tests indicate "
+ "that a test ran very close to the test timeout limit and so may "
+ "become TIMEOUT-flaky in the future. Consider speeding up the test or "
+ "breaking it into multiple tests. For help, please tag "
+ "`@web-platform-tests/wpt-core-team` in a comment.\n")
+
+
def write_inconsistent(log, inconsistent, iterations):
- """Output inconsistent tests to logger.error."""
+ """Output inconsistent tests to the passed in logging function."""
log("## Unstable results ##\n")
strings = [(
"`%s`" % markdown_adjust(test),
@@ -191,6 +216,7 @@ def write_inconsistent(log, inconsistent, iterations):
def write_slow_tests(log, slow):
+ """Output slow tests to the passed in logging function."""
log("## Slow tests ##\n")
strings = [(
"`%s`" % markdown_adjust(test),
@@ -321,6 +347,8 @@ def check_stability(logger, repeat_loop=10, repeat_restart=5, chaos_mode=True, m
start_time = datetime.now()
step_results = []
+ github_checks_outputter = get_gh_checks_outputter(kwargs)
+
for desc, step_func in steps:
if max_time and datetime.now() - start_time > max_time:
logger.info("::: Test verification is taking too long: Giving up!")
@@ -337,12 +365,16 @@ def check_stability(logger, repeat_loop=10, repeat_restart=5, chaos_mode=True, m
if inconsistent:
step_results.append((desc, "FAIL"))
+ if github_checks_outputter:
+ write_github_checks_summary_inconsistent(github_checks_outputter.output, inconsistent, iterations)
write_inconsistent(logger.info, inconsistent, iterations)
write_summary(logger, step_results, "FAIL")
return 1
if slow:
step_results.append((desc, "FAIL"))
+ if github_checks_outputter:
+ write_github_checks_summary_slow_tests(github_checks_outputter.output, slow)
write_slow_tests(logger.info, slow)
write_summary(logger, step_results, "FAIL")
return 1
diff --git a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptcommandline.py b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptcommandline.py
index f322d77fbdd..ea586825616 100644
--- a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptcommandline.py
+++ b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptcommandline.py
@@ -348,6 +348,11 @@ scheme host and port.""")
help="Command-line argument to forward to the "
"Sauce Connect binary (repeatable)")
+ taskcluster_group = parser.add_argument_group("Taskcluster-specific")
+ taskcluster_group.add_argument("--github-checks-text-file",
+ dest="github_checks_text_file",
+ help="Path to GitHub checks output file")
+
webkit_group = parser.add_argument_group("WebKit-specific")
webkit_group.add_argument("--webkit-port", dest="webkit_port",
help="WebKit port")
diff --git a/tests/wpt/web-platform-tests/tools/wptserve/tests/functional/test_stash.py b/tests/wpt/web-platform-tests/tools/wptserve/tests/functional/test_stash.py
index 1c4c9ad933a..0b960c1e9f8 100644
--- a/tests/wpt/web-platform-tests/tools/wptserve/tests/functional/test_stash.py
+++ b/tests/wpt/web-platform-tests/tools/wptserve/tests/functional/test_stash.py
@@ -1,3 +1,4 @@
+import sys
import unittest
import uuid
@@ -9,6 +10,8 @@ from wptserve.stash import StashServer
from .base import TestUsingServer
+@pytest.mark.skipif(sys.version_info >= (3, 8) and sys.platform == 'darwin',
+ reason="multiprocessing test hangs in Python 3.8 on macOS (#24880)")
class TestResponseSetCookie(TestUsingServer):
def run(self, result=None):
with StashServer(None, authkey=str(uuid.uuid4())):
diff --git a/tests/wpt/web-platform-tests/user-timing/case-sensitivity.any.js b/tests/wpt/web-platform-tests/user-timing/case-sensitivity.any.js
new file mode 100644
index 00000000000..1c0b0dcac36
--- /dev/null
+++ b/tests/wpt/web-platform-tests/user-timing/case-sensitivity.any.js
@@ -0,0 +1,25 @@
+ test(function () {
+ assert_equals(typeof self.performance, "object");
+ assert_equals(typeof self.performance.getEntriesByType, "function");
+
+ self.performance.mark("mark1");
+ self.performance.measure("measure1");
+
+ const type = [
+ 'mark',
+ 'measure',
+ ];
+ type.forEach(function(entryType) {
+ if (PerformanceObserver.supportedEntryTypes.includes(entryType)) {
+ const entryTypeUpperCased = entryType.toUpperCase();
+ const entryTypeCapitalized = entryType[0].toUpperCase() + entryType.substring(1);
+ const lowerList = self.performance.getEntriesByType(entryType);
+ const upperList = self.performance.getEntriesByType(entryTypeUpperCased);
+ const mixedList = self.performance.getEntriesByType(entryTypeCapitalized);
+
+ assert_greater_than(lowerList.length, 0, "Entries exist");
+ assert_equals(upperList.length, 0, "getEntriesByType('" + entryTypeCapitalized + "').length");
+ assert_equals(mixedList.length, 0, "getEntriesByType('" + entryTypeCapitalized + "').length");
+ }
+ });
+ }, "getEntriesByType values are case sensitive");
diff --git a/tests/wpt/web-platform-tests/webdriver/tests/new_session/response.py b/tests/wpt/web-platform-tests/webdriver/tests/new_session/response.py
index dc132899881..cbe9e7d7fb1 100644
--- a/tests/wpt/web-platform-tests/webdriver/tests/new_session/response.py
+++ b/tests/wpt/web-platform-tests/webdriver/tests/new_session/response.py
@@ -1,7 +1,7 @@
import uuid
import pytest
-from six import text_type
+from six import string_types
from tests.support.asserts import assert_success
@@ -9,21 +9,21 @@ from tests.support.asserts import assert_success
def test_sessionid(new_session, add_browser_capabilities):
response, _ = new_session({"capabilities": {"alwaysMatch": add_browser_capabilities({})}})
value = assert_success(response)
- assert isinstance(value["sessionId"], text_type)
+ assert isinstance(value["sessionId"], string_types)
uuid.UUID(hex=value["sessionId"])
@pytest.mark.parametrize("capability, type", [
- ("browserName", text_type),
- ("browserVersion", text_type),
- ("platformName", text_type),
+ ("browserName", string_types),
+ ("browserVersion", string_types),
+ ("platformName", string_types),
("acceptInsecureCerts", bool),
- ("pageLoadStrategy", text_type),
+ ("pageLoadStrategy", string_types),
("proxy", dict),
("setWindowRect", bool),
("timeouts", dict),
("strictFileInteractability", bool),
- ("unhandledPromptBehavior", text_type),
+ ("unhandledPromptBehavior", string_types),
])
def test_capability_type(session, capability, type):
assert isinstance(session.capabilities, dict)
diff --git a/tests/wpt/web-platform-tests/webdriver/tests/perform_actions/support/keys.py b/tests/wpt/web-platform-tests/webdriver/tests/perform_actions/support/keys.py
index a62318814f3..2d38e1dff87 100644
--- a/tests/wpt/web-platform-tests/webdriver/tests/perform_actions/support/keys.py
+++ b/tests/wpt/web-platform-tests/webdriver/tests/perform_actions/support/keys.py
@@ -19,6 +19,7 @@
import sys
+from collections import OrderedDict
from inspect import getmembers
from six import text_type
@@ -108,638 +109,780 @@ class Keys(object):
ALL_KEYS = getmembers(Keys, lambda x: type(x) == text_type)
-ALL_EVENTS = {
- "ADD": {
- "code": "NumpadAdd",
- "ctrl": False,
- "key": "+",
- "location": 3,
- "meta": False,
- "shift": False,
- "value": u"\ue025",
- },
- "ALT": {
- "code": "AltLeft",
- "ctrl": False,
- "key": "Alt",
- "location": 1,
- "meta": False,
- "shift": False,
- "value": u"\ue00a",
- },
- "BACKSPACE": {
- "code": "Backspace",
- "ctrl": False,
- "key": "Backspace",
- "location": 0,
- "meta": False,
- "shift": False,
- "value": u"\ue003",
- },
- "CANCEL": {
- "code": "",
- "ctrl": False,
- "key": "Cancel",
- "location": 0,
- "meta": False,
- "shift": False,
- "value": u"\ue001",
- },
- "CLEAR": {
- "code": "",
- "ctrl": False,
- "key": "Clear",
- "location": 0,
- "meta": False,
- "shift": False,
- "value": u"\ue005",
- },
- "CONTROL": {
- "code": "ControlLeft",
- "ctrl": True,
- "key": "Control",
- "location": 1,
- "meta": False,
- "shift": False,
- "value": u"\ue009",
- },
- "DECIMAL": {
- "code": "NumpadDecimal",
- "ctrl": False,
- "key": ".",
- "location": 3,
- "meta": False,
- "shift": False,
- "value": u"\ue028",
- },
- "DELETE": {
- "code": "Delete",
- "ctrl": False,
- "key": "Delete",
- "location": 0,
- "meta": False,
- "shift": False,
- "value": u"\ue017",
- },
- "DIVIDE": {
- "code": "NumpadDivide",
- "ctrl": False,
- "key": "/",
- "location": 3,
- "meta": False,
- "shift": False,
- "value": u"\ue029",
- },
- "DOWN": {
- "code": "ArrowDown",
- "ctrl": False,
- "key": "ArrowDown",
- "location": 0,
- "meta": False,
- "shift": False,
- "value": u"\ue015",
- },
- "END": {
- "code": "End",
- "ctrl": False,
- "key": "End",
- "location": 0,
- "meta": False,
- "shift": False,
- "value": u"\ue010",
- },
- "ENTER": {
- "code": "NumpadEnter",
- "ctrl": False,
- "key": "Enter",
- "location": 1,
- "meta": False,
- "shift": False,
- "value": u"\ue007",
- },
- "EQUALS": {
- "code": "",
- "ctrl": False,
- "key": "=",
- "location": 0,
- "meta": False,
- "shift": False,
- "value": u"\ue019",
- },
- "ESCAPE": {
- "code": "Escape",
- "ctrl": False,
- "key": "Escape",
- "location": 0,
- "meta": False,
- "shift": False,
- "value": u"\ue00c",
- },
- "F1": {
- "code": "F1",
- "ctrl": False,
- "key": "F1",
- "location": 0,
- "meta": False,
- "shift": False,
- "value": u"\ue031",
- },
- "F10": {
- "code": "F10",
- "ctrl": False,
- "key": "F10",
- "location": 0,
- "meta": False,
- "shift": False,
- "value": u"\ue03a",
- },
- "F11": {
- "code": "F11",
- "ctrl": False,
- "key": "F11",
- "location": 0,
- "meta": False,
- "shift": False,
- "value": u"\ue03b",
- },
- "F12": {
- "code": "F12",
- "ctrl": False,
- "key": "F12",
- "location": 0,
- "meta": False,
- "shift": False,
- "value": u"\ue03c",
- },
- "F2": {
- "code": "F2",
- "ctrl": False,
- "key": "F2",
- "location": 0,
- "meta": False,
- "shift": False,
- "value": u"\ue032",
- },
- "F3": {
- "code": "F3",
- "ctrl": False,
- "key": "F3",
- "location": 0,
- "meta": False,
- "shift": False,
- "value": u"\ue033",
- },
- "F4": {
- "code": "F4",
- "ctrl": False,
- "key": "F4",
- "location": 0,
- "meta": False,
- "shift": False,
- "value": u"\ue034",
- },
- "F5": {
- "code": "F5",
- "ctrl": False,
- "key": "F5",
- "location": 0,
- "meta": False,
- "shift": False,
- "value": u"\ue035",
- },
- "F6": {
- "code": "F6",
- "ctrl": False,
- "key": "F6",
- "location": 0,
- "meta": False,
- "shift": False,
- "value": u"\ue036",
- },
- "F7": {
- "code": "F7",
- "ctrl": False,
- "key": "F7",
- "location": 0,
- "meta": False,
- "shift": False,
- "value": u"\ue037",
- },
- "F8": {
- "code": "F8",
- "ctrl": False,
- "key": "F8",
- "location": 0,
- "meta": False,
- "shift": False,
- "value": u"\ue038",
- },
- "F9": {
- "code": "F9",
- "ctrl": False,
- "key": "F9",
- "location": 0,
- "meta": False,
- "shift": False,
- "value": u"\ue039",
- },
- "HELP": {
- "code": "Help",
- "ctrl": False,
- "key": "Help",
- "location": 0,
- "meta": False,
- "shift": False,
- "value": u"\ue002",
- },
- "HOME": {
- "code": "Home",
- "ctrl": False,
- "key": "Home",
- "location": 0,
- "meta": False,
- "shift": False,
- "value": u"\ue011",
- },
- "INSERT": {
- "code": "Insert",
- "ctrl": False,
- "key": "Insert",
- "location": 0,
- "meta": False,
- "shift": False,
- "value": u"\ue016",
- },
- "LEFT": {
- "code": "ArrowLeft",
- "ctrl": False,
- "key": "ArrowLeft",
- "location": 0,
- "meta": False,
- "shift": False,
- "value": u"\ue012",
- },
- "META": {
- "code": "MetaLeft",
- "ctrl": False,
- "key": "Meta",
- "location": 1,
- "meta": True,
- "shift": False,
- "value": u"\ue03d",
- },
- "MULTIPLY": {
- "code": "NumpadMultiply",
- "ctrl": False,
- "key": "*",
- "location": 3,
- "meta": False,
- "shift": False,
- "value": u"\ue024",
- },
- "NULL": {
- "code": "",
- "ctrl": False,
- "key": "Unidentified",
- "location": 0,
- "meta": False,
- "shift": False,
- "value": u"\ue000",
- },
- "NUMPAD0": {
- "code": "Numpad0",
- "ctrl": False,
- "key": "0",
- "location": 3,
- "meta": False,
- "shift": False,
- "value": u"\ue01a",
- },
- "NUMPAD1": {
- "code": "Numpad1",
- "ctrl": False,
- "key": "1",
- "location": 3,
- "meta": False,
- "shift": False,
- "value": u"\ue01b",
- },
- "NUMPAD2": {
- "code": "Numpad2",
- "ctrl": False,
- "key": "2",
- "location": 3,
- "meta": False,
- "shift": False,
- "value": u"\ue01c",
- },
- "NUMPAD3": {
- "code": "Numpad3",
- "ctrl": False,
- "key": "3",
- "location": 3,
- "meta": False,
- "shift": False,
- "value": u"\ue01d",
- },
- "NUMPAD4": {
- "code": "Numpad4",
- "ctrl": False,
- "key": "4",
- "location": 3,
- "meta": False,
- "shift": False,
- "value": u"\ue01e",
- },
- "NUMPAD5": {
- "code": "Numpad5",
- "ctrl": False,
- "key": "5",
- "location": 3,
- "meta": False,
- "shift": False,
- "value": u"\ue01f",
- },
- "NUMPAD6": {
- "code": "Numpad6",
- "ctrl": False,
- "key": "6",
- "location": 3,
- "meta": False,
- "shift": False,
- "value": u"\ue020",
- },
- "NUMPAD7": {
- "code": "Numpad7",
- "ctrl": False,
- "key": "7",
- "location": 3,
- "meta": False,
- "shift": False,
- "value": u"\ue021",
- },
- "NUMPAD8": {
- "code": "Numpad8",
- "ctrl": False,
- "key": "8",
- "location": 3,
- "meta": False,
- "shift": False,
- "value": u"\ue022",
- },
- "NUMPAD9": {
- "code": "Numpad9",
- "ctrl": False,
- "key": "9",
- "location": 3,
- "meta": False,
- "shift": False,
- "value": u"\ue023",
- },
- "PAGE_DOWN": {
- "code": "PageDown",
- "ctrl": False,
- "key": "PageDown",
- "location": 0,
- "meta": False,
- "shift": False,
- "value": u"\ue00f",
- },
- "PAGE_UP": {
- "code": "PageUp",
- "ctrl": False,
- "key": "PageUp",
- "location": 0,
- "meta": False,
- "shift": False,
- "value": u"\ue00e",
- },
- "PAUSE": {
- "code": "",
- "ctrl": False,
- "key": "Pause",
- "location": 0,
- "meta": False,
- "shift": False,
- "value": u"\ue00b",
- },
- "RETURN": {
- "code": "Enter",
- "ctrl": False,
- "key": "Enter",
- "location": 0,
- "meta": False,
- "shift": False,
- "value": u"\ue006",
- },
- "RIGHT": {
- "code": "ArrowRight",
- "ctrl": False,
- "key": "ArrowRight",
- "location": 0,
- "meta": False,
- "shift": False,
- "value": u"\ue014",
- },
- "R_ALT": {
- "code": "AltRight",
- "ctrl": False,
- "key": "Alt",
- "location": 2,
- "meta": False,
- "shift": False,
- "value": u"\ue052",
- },
- "R_ARROWDOWN": {
- "code": "Numpad2",
- "ctrl": False,
- "key": "ArrowDown",
- "location": 3,
- "meta": False,
- "shift": False,
- "value": u"\ue05b",
- },
- "R_ARROWLEFT": {
- "code": "Numpad4",
- "ctrl": False,
- "key": "ArrowLeft",
- "location": 3,
- "meta": False,
- "shift": False,
- "value": u"\ue058",
- },
- "R_ARROWRIGHT": {
- "code": "Numpad6",
- "ctrl": False,
- "key": "ArrowRight",
- "location": 3,
- "meta": False,
- "shift": False,
- "value": u"\ue05a",
- },
- "R_ARROWUP": {
- "code": "Numpad8",
- "ctrl": False,
- "key": "ArrowUp",
- "location": 3,
- "meta": False,
- "shift": False,
- "value": u"\ue059",
- },
- "R_CONTROL": {
- "code": "ControlRight",
- "ctrl": True,
- "key": "Control",
- "location": 2,
- "meta": False,
- "shift": False,
- "value": u"\ue051",
- },
- "R_DELETE": {
- "code": "NumpadDecimal",
- "ctrl": False,
- "key": "Delete",
- "location": 3,
- "meta": False,
- "shift": False,
- "value": u"\ue05d",
- },
- "R_END": {
- "code": "Numpad1",
- "ctrl": False,
- "key": "End",
- "location": 3,
- "meta": False,
- "shift": False,
- "value": u"\ue056",
- },
- "R_HOME": {
- "code": "Numpad7",
- "ctrl": False,
- "key": "Home",
- "location": 3,
- "meta": False,
- "shift": False,
- "value": u"\ue057",
- },
- "R_INSERT": {
- "code": "Numpad0",
- "ctrl": False,
- "key": "Insert",
- "location": 3,
- "meta": False,
- "shift": False,
- "value": u"\ue05c",
- },
- "R_META": {
- "code": "MetaRight",
- "ctrl": False,
- "key": "Meta",
- "location": 2,
- "meta": True,
- "shift": False,
- "value": u"\ue053",
- },
- "R_PAGEDOWN": {
- "code": "Numpad3",
- "ctrl": False,
- "key": "PageDown",
- "location": 3,
- "meta": False,
- "shift": False,
- "value": u"\ue055",
- },
- "R_PAGEUP": {
- "code": "Numpad9",
- "ctrl": False,
- "key": "PageUp",
- "location": 3,
- "meta": False,
- "shift": False,
- "value": u"\ue054",
- },
- "R_SHIFT": {
- "code": "ShiftRight",
- "ctrl": False,
- "key": "Shift",
- "location": 2,
- "meta": False,
- "shift": True,
- "value": u"\ue050",
- },
- "SEMICOLON": {
- "code": "",
- "ctrl": False,
- "key": ";",
- "location": 0,
- "meta": False,
- "shift": False,
- "value": u"\ue018",
- },
- "SEPARATOR": {
- "code": "NumpadComma",
- "ctrl": False,
- "key": ",",
- "location": 3,
- "meta": False,
- "shift": False,
- "value": u"\ue026",
- },
- "SHIFT": {
- "code": "ShiftLeft",
- "ctrl": False,
- "key": "Shift",
- "location": 1,
- "meta": False,
- "shift": True,
- "value": u"\ue008",
- },
- "SPACE": {
- "code": "Space",
- "ctrl": False,
- "key": " ",
- "location": 0,
- "meta": False,
- "shift": False,
- "value": u"\ue00d",
- },
- "SUBTRACT": {
- "code": "NumpadSubtract",
- "ctrl": False,
- "key": "-",
- "location": 3,
- "meta": False,
- "shift": False,
- "value": u"\ue027",
- },
- "TAB": {
- "code": "Tab",
- "ctrl": False,
- "key": "Tab",
- "location": 0,
- "meta": False,
- "shift": False,
- "value": u"\ue004",
- },
- "UP": {
- "code": "ArrowUp",
- "ctrl": False,
- "key": "ArrowUp",
- "location": 0,
- "meta": False,
- "shift": False,
- "value": u"\ue013",
- },
- "ZENKAKUHANKAKU": {
- "code": "",
- "ctrl": False,
- "key": "ZenkakuHankaku",
- "location": 0,
- "meta": False,
- "shift": False,
- "value": u"\ue040",
- }
-}
+ALL_EVENTS = OrderedDict(
+ [
+ ("ADD", OrderedDict(
+ [
+ ("code", "NumpadAdd"),
+ ("ctrl", False),
+ ("key", "+"),
+ ("location", 3),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue025")
+ ]
+ )),
+ ("ALT", OrderedDict(
+ [
+ ("code", "AltLeft"),
+ ("ctrl", False),
+ ("key", "Alt"),
+ ("location", 1),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue00a")
+ ]
+ )),
+ ("BACKSPACE", OrderedDict(
+ [
+ ("code", "Backspace"),
+ ("ctrl", False),
+ ("key", "Backspace"),
+ ("location", 0),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue003")
+ ]
+ )),
+ ("CANCEL", OrderedDict(
+ [
+ ("code", ""),
+ ("ctrl", False),
+ ("key", "Cancel"),
+ ("location", 0),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue001")
+ ]
+ )),
+ ("CLEAR", OrderedDict(
+ [
+ ("code", ""),
+ ("ctrl", False),
+ ("key", "Clear"),
+ ("location", 0),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue005")
+ ]
+ )),
+ ("CONTROL", OrderedDict(
+ [
+ ("code", "ControlLeft"),
+ ("ctrl", True),
+ ("key", "Control"),
+ ("location", 1),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue009")
+ ]
+ )),
+ ("DECIMAL", OrderedDict(
+ [
+ ("code", "NumpadDecimal"),
+ ("ctrl", False),
+ ("key", "."),
+ ("location", 3),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue028")
+ ]
+ )),
+ ("DELETE", OrderedDict(
+ [
+ ("code", "Delete"),
+ ("ctrl", False),
+ ("key", "Delete"),
+ ("location", 0),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue017")
+ ]
+ )),
+ ("DIVIDE", OrderedDict(
+ [
+ ("code", "NumpadDivide"),
+ ("ctrl", False),
+ ("key", "/"),
+ ("location", 3),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue029")
+ ]
+ )),
+ ("DOWN", OrderedDict(
+ [
+ ("code", "ArrowDown"),
+ ("ctrl", False),
+ ("key", "ArrowDown"),
+ ("location", 0),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue015")
+ ]
+ )),
+ ("END", OrderedDict(
+ [
+ ("code", "End"),
+ ("ctrl", False),
+ ("key", "End"),
+ ("location", 0),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue010")
+ ]
+ )),
+ ("ENTER", OrderedDict(
+ [
+ ("code", "NumpadEnter"),
+ ("ctrl", False),
+ ("key", "Enter"),
+ ("location", 1),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue007")
+ ]
+ )),
+ ("EQUALS", OrderedDict(
+ [
+ ("code", ""),
+ ("ctrl", False),
+ ("key", "="),
+ ("location", 0),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue019")
+ ]
+ )),
+ ("ESCAPE", OrderedDict(
+ [
+ ("code", "Escape"),
+ ("ctrl", False),
+ ("key", "Escape"),
+ ("location", 0),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue00c")
+ ]
+ )),
+ ("F1", OrderedDict(
+ [
+ ("code", "F1"),
+ ("ctrl", False),
+ ("key", "F1"),
+ ("location", 0),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue031")
+ ]
+ )),
+ ("F10", OrderedDict(
+ [
+ ("code", "F10"),
+ ("ctrl", False),
+ ("key", "F10"),
+ ("location", 0),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue03a")
+ ]
+ )),
+ ("F11", OrderedDict(
+ [
+ ("code", "F11"),
+ ("ctrl", False),
+ ("key", "F11"),
+ ("location", 0),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue03b")
+ ]
+ )),
+ ("F12", OrderedDict(
+ [
+ ("code", "F12"),
+ ("ctrl", False),
+ ("key", "F12"),
+ ("location", 0),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue03c")
+ ]
+ )),
+ ("F2", OrderedDict(
+ [
+ ("code", "F2"),
+ ("ctrl", False),
+ ("key", "F2"),
+ ("location", 0),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue032")
+ ]
+ )),
+ ("F3", OrderedDict(
+ [
+ ("code", "F3"),
+ ("ctrl", False),
+ ("key", "F3"),
+ ("location", 0),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue033")
+ ]
+ )),
+ ("F4", OrderedDict(
+ [
+ ("code", "F4"),
+ ("ctrl", False),
+ ("key", "F4"),
+ ("location", 0),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue034")
+ ]
+ )),
+ ("F5", OrderedDict(
+ [
+ ("code", "F5"),
+ ("ctrl", False),
+ ("key", "F5"),
+ ("location", 0),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue035")
+ ]
+ )),
+ ("F6", OrderedDict(
+ [
+ ("code", "F6"),
+ ("ctrl", False),
+ ("key", "F6"),
+ ("location", 0),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue036")
+ ]
+ )),
+ ("F7", OrderedDict(
+ [
+ ("code", "F7"),
+ ("ctrl", False),
+ ("key", "F7"),
+ ("location", 0),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue037")
+ ]
+ )),
+ ("F8", OrderedDict(
+ [
+ ("code", "F8"),
+ ("ctrl", False),
+ ("key", "F8"),
+ ("location", 0),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue038")
+ ]
+ )),
+ ("F9", OrderedDict(
+ [
+ ("code", "F9"),
+ ("ctrl", False),
+ ("key", "F9"),
+ ("location", 0),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue039")
+ ]
+ )),
+ ("HELP", OrderedDict(
+ [
+ ("code", "Help"),
+ ("ctrl", False),
+ ("key", "Help"),
+ ("location", 0),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue002")
+ ]
+ )),
+ ("HOME", OrderedDict(
+ [
+ ("code", "Home"),
+ ("ctrl", False),
+ ("key", "Home"),
+ ("location", 0),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue011")
+ ]
+ )),
+ ("INSERT", OrderedDict(
+ [
+ ("code", "Insert"),
+ ("ctrl", False),
+ ("key", "Insert"),
+ ("location", 0),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue016")
+ ]
+ )),
+ ("LEFT", OrderedDict(
+ [
+ ("code", "ArrowLeft"),
+ ("ctrl", False),
+ ("key", "ArrowLeft"),
+ ("location", 0),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue012")
+ ]
+ )),
+ ("META", OrderedDict(
+ [
+ ("code", "MetaLeft"),
+ ("ctrl", False),
+ ("key", "Meta"),
+ ("location", 1),
+ ("meta", True),
+ ("shift", False),
+ ("value", u"\ue03d")
+ ]
+ )),
+ ("MULTIPLY", OrderedDict(
+ [
+ ("code", "NumpadMultiply"),
+ ("ctrl", False),
+ ("key", "*"),
+ ("location", 3),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue024")
+ ]
+ )),
+ ("NULL", OrderedDict(
+ [
+ ("code", ""),
+ ("ctrl", False),
+ ("key", "Unidentified"),
+ ("location", 0),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue000")
+ ]
+ )),
+ ("NUMPAD0", OrderedDict(
+ [
+ ("code", "Numpad0"),
+ ("ctrl", False),
+ ("key", "0"),
+ ("location", 3),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue01a")
+ ]
+ )),
+ ("NUMPAD1", OrderedDict(
+ [
+ ("code", "Numpad1"),
+ ("ctrl", False),
+ ("key", "1"),
+ ("location", 3),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue01b")
+ ]
+ )),
+ ("NUMPAD2", OrderedDict(
+ [
+ ("code", "Numpad2"),
+ ("ctrl", False),
+ ("key", "2"),
+ ("location", 3),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue01c")
+ ]
+ )),
+ ("NUMPAD3", OrderedDict(
+ [
+ ("code", "Numpad3"),
+ ("ctrl", False),
+ ("key", "3"),
+ ("location", 3),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue01d")
+ ]
+ )),
+ ("NUMPAD4", OrderedDict(
+ [
+ ("code", "Numpad4"),
+ ("ctrl", False),
+ ("key", "4"),
+ ("location", 3),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue01e")
+ ]
+ )),
+ ("NUMPAD5", OrderedDict(
+ [
+ ("code", "Numpad5"),
+ ("ctrl", False),
+ ("key", "5"),
+ ("location", 3),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue01f")
+ ]
+ )),
+ ("NUMPAD6", OrderedDict(
+ [
+ ("code", "Numpad6"),
+ ("ctrl", False),
+ ("key", "6"),
+ ("location", 3),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue020")
+ ]
+ )),
+ ("NUMPAD7", OrderedDict(
+ [
+ ("code", "Numpad7"),
+ ("ctrl", False),
+ ("key", "7"),
+ ("location", 3),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue021")
+ ]
+ )),
+ ("NUMPAD8", OrderedDict(
+ [
+ ("code", "Numpad8"),
+ ("ctrl", False),
+ ("key", "8"),
+ ("location", 3),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue022")
+ ]
+ )),
+ ("NUMPAD9", OrderedDict(
+ [
+ ("code", "Numpad9"),
+ ("ctrl", False),
+ ("key", "9"),
+ ("location", 3),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue023")
+ ]
+ )),
+ ("PAGE_DOWN", OrderedDict(
+ [
+ ("code", "PageDown"),
+ ("ctrl", False),
+ ("key", "PageDown"),
+ ("location", 0),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue00f")
+ ]
+ )),
+ ("PAGE_UP", OrderedDict(
+ [
+ ("code", "PageUp"),
+ ("ctrl", False),
+ ("key", "PageUp"),
+ ("location", 0),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue00e")
+ ]
+ )),
+ ("PAUSE", OrderedDict(
+ [
+ ("code", ""),
+ ("ctrl", False),
+ ("key", "Pause"),
+ ("location", 0),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue00b")
+ ]
+ )),
+ ("RETURN", OrderedDict(
+ [
+ ("code", "Enter"),
+ ("ctrl", False),
+ ("key", "Enter"),
+ ("location", 0),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue006")
+ ]
+ )),
+ ("RIGHT", OrderedDict(
+ [
+ ("code", "ArrowRight"),
+ ("ctrl", False),
+ ("key", "ArrowRight"),
+ ("location", 0),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue014")
+ ]
+ )),
+ ("R_ALT", OrderedDict(
+ [
+ ("code", "AltRight"),
+ ("ctrl", False),
+ ("key", "Alt"),
+ ("location", 2),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue052")
+ ]
+ )),
+ ("R_ARROWDOWN", OrderedDict(
+ [
+ ("code", "Numpad2"),
+ ("ctrl", False),
+ ("key", "ArrowDown"),
+ ("location", 3),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue05b")
+ ]
+ )),
+ ("R_ARROWLEFT", OrderedDict(
+ [
+ ("code", "Numpad4"),
+ ("ctrl", False),
+ ("key", "ArrowLeft"),
+ ("location", 3),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue058")
+ ]
+ )),
+ ("R_ARROWRIGHT", OrderedDict(
+ [
+ ("code", "Numpad6"),
+ ("ctrl", False),
+ ("key", "ArrowRight"),
+ ("location", 3),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue05a")
+ ]
+ )),
+ ("R_ARROWUP", OrderedDict(
+ [
+ ("code", "Numpad8"),
+ ("ctrl", False),
+ ("key", "ArrowUp"),
+ ("location", 3),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue059")
+ ]
+ )),
+ ("R_CONTROL", OrderedDict(
+ [
+ ("code", "ControlRight"),
+ ("ctrl", True),
+ ("key", "Control"),
+ ("location", 2),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue051")
+ ]
+ )),
+ ("R_DELETE", OrderedDict(
+ [
+ ("code", "NumpadDecimal"),
+ ("ctrl", False),
+ ("key", "Delete"),
+ ("location", 3),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue05d")
+ ]
+ )),
+ ("R_END", OrderedDict(
+ [
+ ("code", "Numpad1"),
+ ("ctrl", False),
+ ("key", "End"),
+ ("location", 3),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue056")
+ ]
+ )),
+ ("R_HOME", OrderedDict(
+ [
+ ("code", "Numpad7"),
+ ("ctrl", False),
+ ("key", "Home"),
+ ("location", 3),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue057")
+ ]
+ )),
+ ("R_INSERT", OrderedDict(
+ [
+ ("code", "Numpad0"),
+ ("ctrl", False),
+ ("key", "Insert"),
+ ("location", 3),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue05c")
+ ]
+ )),
+ ("R_META", OrderedDict(
+ [
+ ("code", "MetaRight"),
+ ("ctrl", False),
+ ("key", "Meta"),
+ ("location", 2),
+ ("meta", True),
+ ("shift", False),
+ ("value", u"\ue053")
+ ]
+ )),
+ ("R_PAGEDOWN", OrderedDict(
+ [
+ ("code", "Numpad3"),
+ ("ctrl", False),
+ ("key", "PageDown"),
+ ("location", 3),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue055")
+ ]
+ )),
+ ("R_PAGEUP", OrderedDict(
+ [
+ ("code", "Numpad9"),
+ ("ctrl", False),
+ ("key", "PageUp"),
+ ("location", 3),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue054")
+ ]
+ )),
+ ("R_SHIFT", OrderedDict(
+ [
+ ("code", "ShiftRight"),
+ ("ctrl", False),
+ ("key", "Shift"),
+ ("location", 2),
+ ("meta", False),
+ ("shift", True),
+ ("value", u"\ue050")
+ ]
+ )),
+ ("SEMICOLON", OrderedDict(
+ [
+ ("code", ""),
+ ("ctrl", False),
+ ("key", ";"),
+ ("location", 0),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue018")
+ ]
+ )),
+ ("SEPARATOR", OrderedDict(
+ [
+ ("code", "NumpadComma"),
+ ("ctrl", False),
+ ("key", ","),
+ ("location", 3),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue026")
+ ]
+ )),
+ ("SHIFT", OrderedDict(
+ [
+ ("code", "ShiftLeft"),
+ ("ctrl", False),
+ ("key", "Shift"),
+ ("location", 1),
+ ("meta", False),
+ ("shift", True),
+ ("value", u"\ue008")
+ ]
+ )),
+ ("SPACE", OrderedDict(
+ [
+ ("code", "Space"),
+ ("ctrl", False),
+ ("key", " "),
+ ("location", 0),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue00d")
+ ]
+ )),
+ ("SUBTRACT", OrderedDict(
+ [
+ ("code", "NumpadSubtract"),
+ ("ctrl", False),
+ ("key", "-"),
+ ("location", 3),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue027")
+ ]
+ )),
+ ("TAB", OrderedDict(
+ [
+ ("code", "Tab"),
+ ("ctrl", False),
+ ("key", "Tab"),
+ ("location", 0),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue004")
+ ]
+ )),
+ ("UP", OrderedDict(
+ [
+ ("code", "ArrowUp"),
+ ("ctrl", False),
+ ("key", "ArrowUp"),
+ ("location", 0),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue013")
+ ]
+ )),
+ ("ZENKAKUHANKAKU", OrderedDict(
+ [
+ ("code", ""),
+ ("ctrl", False),
+ ("key", "ZenkakuHankaku"),
+ ("location", 0),
+ ("meta", False),
+ ("shift", False),
+ ("value", u"\ue040")
+ ]
+ ))
+ ]
+)
ALTERNATIVE_KEY_NAMES = {
"ADD": "Add",
diff --git a/tests/wpt/web-platform-tests/webxr/render_state_update.https.html b/tests/wpt/web-platform-tests/webxr/render_state_update.https.html
new file mode 100644
index 00000000000..2f28d442ec9
--- /dev/null
+++ b/tests/wpt/web-platform-tests/webxr/render_state_update.https.html
@@ -0,0 +1,96 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/webxr_util.js"></script>
+<script src="resources/webxr_test_constants.js"></script>
+<canvas />
+
+<script>
+let fakeDeviceInitParams = TRACKED_IMMERSIVE_DEVICE;
+
+let testSessionEnded = function(session, fakeDeviceController, t) {
+ return new Promise((resolve, reject) => {
+ resolve(session.end().then(() => {
+ t.step(() => {
+ assert_throws_dom('InvalidStateError', () => session.updateRenderState({}));
+ });
+ }));
+ });
+};
+
+
+let testBaseLayer = function(session, fakeDeviceController, t, sessionObjects) {
+ return new Promise((resolve, reject) => {
+ navigator.xr.test.simulateUserActivation(() => {
+ navigator.xr.requestSession('inline').then((tempSession) => {
+ t.step(() => {
+ assert_not_equals(session, tempSession);
+ assert_throws_dom('InvalidStateError', () => session.updateRenderState({ baseLayer : new XRWebGLLayer(tempSession, sessionObjects.gl), }));
+ });
+ });
+ resolve();
+ });
+ });
+};
+
+let testFieldOfView = function(session, fakeDeviceController, t) {
+ return new Promise((resolve, reject) => {
+ t.step(() => {
+ assert_throws_dom('InvalidStateError', () => session.updateRenderState({ inlineVerticalFieldOfView : Math.PI, }));
+ });
+ resolve();
+ });
+};
+
+let testNoParams = function(session, fakeDeviceController, t) {
+ return new Promise((resolve, reject) => {
+ try {
+ session.updateRenderState({});
+ } catch (err) {
+ assert_unreached("updateRenderState should not fail (actually not do anything) with no params");
+ }
+ resolve();
+ });
+};
+
+let testParams = function(session, fakeDeviceController, t, sessionObjects) {
+ return new Promise((resolve, reject) => {
+ let gl = sessionObjects.gl;
+ try {
+ gl.makeXRCompatible().then(() => {
+ t.step(() => {
+ let fov = Math.PI;
+ let near = 0.2;
+ let far = 0.8;
+ let layer = new XRWebGLLayer(session, gl);
+ session.updateRenderState({ inlineVerticalFieldOfView: fov, depthNear: near, depthFar: far, baseLayer: layer });
+ // The update can only happen between frame boundaries, updateRenderState only queues changes.
+ assert_not_equals(session.renderState.inlineVerticalFieldOfView, fov);
+ assert_not_equals(session.renderState.depthNear, near);
+ assert_not_equals(session.renderState.depthFar, far);
+ assert_not_equals(session.renderState.baseLayer, layer);
+ });
+ });
+ } catch (err) {
+ assert_unreached("updateRenderState should not fail when all params are specified");
+ }
+ resolve();
+ });
+};
+
+let testName = "updateRenderState handles appropriately ended sessions";
+xr_session_promise_test(testName, testSessionEnded, fakeDeviceInitParams, 'immersive-vr');
+
+testName = "updateRenderState handles appropriately baseLayers created with different sessions";
+xr_session_promise_test(testName, testBaseLayer, fakeDeviceInitParams, 'immersive-vr');
+
+testName = "updateRenderState handles appropriately immersive sessions with specified inlineVerticalFieldOfView";
+xr_session_promise_test(testName, testFieldOfView, fakeDeviceInitParams, 'immersive-vr');
+
+testName = "updateRenderState handles appropriately XRRenderStateInit with no params";
+xr_session_promise_test(testName, testNoParams, fakeDeviceInitParams, 'immersive-vr');
+
+testName = "updateRenderState handles appropriately XRRenderStateInit params";
+xr_session_promise_test(testName, testParams, fakeDeviceInitParams, 'inline');
+
+</script>
diff --git a/tests/wpt/web-platform-tests/workers/interfaces/WorkerGlobalScope/onerror/exception-in-onerror.html b/tests/wpt/web-platform-tests/workers/interfaces/WorkerGlobalScope/onerror/exception-in-onerror.html
index 840433d3d89..d8aa02a01b8 100644
--- a/tests/wpt/web-platform-tests/workers/interfaces/WorkerGlobalScope/onerror/exception-in-onerror.html
+++ b/tests/wpt/web-platform-tests/workers/interfaces/WorkerGlobalScope/onerror/exception-in-onerror.html
@@ -1,19 +1,91 @@
<!doctype html>
-<title>onerror, "not handled" with an error in the onerror function</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
-<div id="log"></div>
<script>
-async_test(function() {
- var worker = new Worker('exception-in-onerror.js');
- worker.onerror = this.step_func(function(e) {
- assert_true(e instanceof ErrorEvent, 'e instanceof ErrorEvent');
- assert_equals(typeof e.message, 'string', 'typeof e.message');
- assert_equals(e.filename, document.URL.replace('.html', '.js'), 'e.filename');
- assert_equals(typeof e.lineno, 'number', 'typeof e.lineno');
- assert_equals(typeof e.colno, 'number', 'typeof e.column');
- e.preventDefault(); // "handled"
- this.done();
- });
-});
-</script> \ No newline at end of file
+// 1. Exception is thrown somewhere in a Worker.
+// Various contexts are tested: from worker initialization,
+// from setTimeout, from event handlers, etc.
+// 2. WorkerGlobalScope.onerror event handler is called.
+// (i.e. `onerror` in the worker script)
+// 3. From the event handler, another exception is thrown.
+// 4. Each of Worker.onerror handler (on the parent Document) and
+// Worker error event listener should be called twice:
+// once for each of the exceptions thrown in Step 1 and 2, respectively.
+// (We don't check the ordering of two Worker.onerror calls, because
+// browsers fires them in different orders)
+
+function prepareHandler(t, messages) {
+ const fired = {};
+ let fired_count = 0;
+ t.step_timeout(() => {
+ if (fired_count < messages.length) {
+ let error_description = 'Worker.onerror not fired for:';
+ for (const message of messages) {
+ if (!fired[message]) {
+ error_description += ' ';
+ error_description += message;
+ }
+ }
+ assert_unreached(error_description);
+ }
+ }, 2000);
+ return t.step_func(e => {
+ e.preventDefault();
+ for (const message of messages) {
+ if (!fired[message] && e.message.indexOf(message) >= 0) {
+ fired[message] = true;
+ ++fired_count;
+ if (fired_count === messages.length) {
+ // Worker.onerror is fired for all messages.
+ t.done();
+ }
+ return;
+ }
+ }
+ assert_unreached("Unexpected worker.onerror message: " + e.message);
+ });
+}
+
+function expectErrors(worker, title, messages) {
+ async_test(t => {
+ worker.addEventListener('error', prepareHandler(t, messages));
+ }, title+ ': listener');
+ async_test(t => {
+ worker.onerror = prepareHandler(t, messages);
+ }, title + ': handler');
+}
+
+for (const type of ['classic', 'module']) {
+ const workerOptions = type === 'module' ? {type: 'module'}: {};
+
+ const worker1 = new Worker(
+ 'exception-in-onerror.js?throw-in-worker-initialization',
+ workerOptions);
+ expectErrors(
+ worker1,
+ 'Throw in worker initialization: ' + type,
+ ['Throw in worker initialization', 'Throw in error handler']);
+
+ const worker2 = new Worker(
+ 'exception-in-onerror.js?throw-in-setTimeout-function', workerOptions);
+ expectErrors(
+ worker2,
+ 'Throw in setTimeout(function): ' + type,
+ ['Throw in setTimeout function', 'Throw in error handler']);
+
+ const worker3 = new Worker(
+ 'exception-in-onerror.js?throw-in-setTimeout-string', workerOptions);
+ expectErrors(
+ worker3,
+ 'Throw in setTimeout(string): ' + type,
+ ['Throw in setTimeout string', 'Throw in error handler']);
+
+ const worker4 = new Worker('exception-in-onerror.js', workerOptions);
+ worker4.postMessage('foo');
+ expectErrors(
+ worker4,
+ 'Throw in message handler: ' + type,
+ ['Throw in message handler', 'Throw in error handler']);
+
+}
+</script>
diff --git a/tests/wpt/web-platform-tests/workers/interfaces/WorkerGlobalScope/onerror/exception-in-onerror.js b/tests/wpt/web-platform-tests/workers/interfaces/WorkerGlobalScope/onerror/exception-in-onerror.js
index 2bf4124cb74..61a95dda51f 100644
--- a/tests/wpt/web-platform-tests/workers/interfaces/WorkerGlobalScope/onerror/exception-in-onerror.js
+++ b/tests/wpt/web-platform-tests/workers/interfaces/WorkerGlobalScope/onerror/exception-in-onerror.js
@@ -1,7 +1,25 @@
-onerror = function(a, b, c, d) {
- y(); // the error is "not handled"
+onerror = function() {
+ throw new Error('Throw in error handler');
+ return false;
+};
+onmessage = function() {
+ throw new Error('Throw in message handler');
+ return false;
+};
+
+if (self.location.href.indexOf(
+ 'throw-in-worker-initialization') >= 0) {
+ throw new Error('Throw in worker initialization');
}
-function x() {
- y();
+
+if (self.location.href.indexOf(
+ 'throw-in-setTimeout-function') >= 0) {
+ // To test the behavior of setTimeout(), raw setTimeout() is used.
+ setTimeout(() => { throw new Error('Throw in setTimeout function') }, 0);
+}
+
+if (self.location.href.indexOf(
+ 'throw-in-setTimeout-string') >= 0) {
+ // To test the behavior of setTimeout(), raw setTimeout() is used.
+ setTimeout("throw new Error('Throw in setTimeout string')", 0);
}
-x(); \ No newline at end of file
diff --git a/tests/wpt/webgl/meta/conformance/renderbuffers/framebuffer-state-restoration.html.ini b/tests/wpt/webgl/meta/conformance/renderbuffers/framebuffer-state-restoration.html.ini
index 196c07cc589..b17781ba017 100644
--- a/tests/wpt/webgl/meta/conformance/renderbuffers/framebuffer-state-restoration.html.ini
+++ b/tests/wpt/webgl/meta/conformance/renderbuffers/framebuffer-state-restoration.html.ini
@@ -6,3 +6,6 @@
[WebGL test #1: context does not exist]
expected: FAIL
+ [WebGL test #14: should be red\nat (0, 0) expected: 255,0,0,255 was 0,255,0,255]
+ expected: FAIL
+
diff --git a/tests/wpt/webgl/meta/conformance/rendering/multisample-corruption.html.ini b/tests/wpt/webgl/meta/conformance/rendering/multisample-corruption.html.ini
index a318722d23b..2d68d489d35 100644
--- a/tests/wpt/webgl/meta/conformance/rendering/multisample-corruption.html.ini
+++ b/tests/wpt/webgl/meta/conformance/rendering/multisample-corruption.html.ini
@@ -7,75 +7,3 @@
[WebGL test #1: context does not exist]
expected: FAIL
- [WebGL test #9: Canvas should be red]
- expected: FAIL
-
- [WebGL test #17: Canvas should be red]
- expected: FAIL
-
- [WebGL test #23: Canvas should be red]
- expected: FAIL
-
- [WebGL test #8: Canvas should be red]
- expected: FAIL
-
- [WebGL test #13: Canvas should be red]
- expected: FAIL
-
- [WebGL test #18: Canvas should be red]
- expected: FAIL
-
- [WebGL test #5: Canvas should be red]
- expected: FAIL
-
- [WebGL test #14: Canvas should be red]
- expected: FAIL
-
- [WebGL test #22: Canvas should be red]
- expected: FAIL
-
- [WebGL test #20: Canvas should be red]
- expected: FAIL
-
- [WebGL test #3: Canvas should be red]
- expected: FAIL
-
- [WebGL test #24: Canvas should be red]
- expected: FAIL
-
- [WebGL test #7: Canvas should be red]
- expected: FAIL
-
- [WebGL test #11: Canvas should be red]
- expected: FAIL
-
- [WebGL test #2: Canvas should be red]
- expected: FAIL
-
- [WebGL test #4: Canvas should be red]
- expected: FAIL
-
- [WebGL test #1: Canvas should be red]
- expected: FAIL
-
- [WebGL test #21: Canvas should be red]
- expected: FAIL
-
- [WebGL test #6: Canvas should be red]
- expected: FAIL
-
- [WebGL test #19: Canvas should be red]
- expected: FAIL
-
- [WebGL test #12: Canvas should be red]
- expected: FAIL
-
- [WebGL test #16: Canvas should be red]
- expected: FAIL
-
- [WebGL test #10: Canvas should be red]
- expected: FAIL
-
- [WebGL test #15: Canvas should be red]
- expected: FAIL
-
diff --git a/tests/wpt/webgl/meta/conformance2/rendering/draw-buffers.html.ini b/tests/wpt/webgl/meta/conformance2/rendering/draw-buffers.html.ini
index abd1336b54a..fd7fbe111ff 100644
--- a/tests/wpt/webgl/meta/conformance2/rendering/draw-buffers.html.ini
+++ b/tests/wpt/webgl/meta/conformance2/rendering/draw-buffers.html.ini
@@ -209,3 +209,12 @@
[WebGL test #44: attachment 7 should be 0,255,0,255\nat (0, 0) expected: 0,255,0,255 was 0,0,255,0]
expected: FAIL
+ [WebGL test #43: attachment 6 should be 0,255,0,255\nat (0, 0) expected: 0,255,0,255 was 0,0,0,255]
+ expected: FAIL
+
+ [WebGL test #44: attachment 7 should be 0,255,0,255\nat (0, 0) expected: 0,255,0,255 was 255,0,0,255]
+ expected: FAIL
+
+ [WebGL test #52: attachment 7 should be 0,255,0,255\nat (0, 0) expected: 0,255,0,255 was 255,0,0,255]
+ expected: FAIL
+