aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock63
-rw-r--r--components/atoms/static_atoms.txt1
-rw-r--r--components/canvas_traits/webgl.rs8
-rw-r--r--components/devtools/Cargo.toml1
-rw-r--r--components/devtools/actors/console.rs191
-rw-r--r--components/gfx/Cargo.toml4
-rw-r--r--components/gfx/text/shaping/harfbuzz.rs23
-rw-r--r--components/layout/Cargo.toml2
-rw-r--r--components/layout/display_list/gradient.rs11
-rw-r--r--components/layout/fragment.rs107
-rw-r--r--components/layout/inline.rs31
-rw-r--r--components/layout/table_cell.rs8
-rw-r--r--components/layout/text.rs12
-rw-r--r--components/layout_thread/dom_wrapper.rs11
-rw-r--r--components/malloc_size_of/Cargo.toml2
-rw-r--r--components/malloc_size_of/lib.rs18
-rw-r--r--components/script/dom/audiobuffer.rs1
-rw-r--r--components/script/dom/bindings/trace.rs7
-rw-r--r--components/script/dom/customelementregistry.rs2
-rw-r--r--components/script/dom/element.rs4
-rw-r--r--components/script/dom/extendablemessageevent.rs1
-rw-r--r--components/script/dom/filereader.rs2
-rw-r--r--components/script/dom/gamepad.rs1
-rw-r--r--components/script/dom/globalscope.rs2
-rw-r--r--components/script/dom/history.rs1
-rw-r--r--components/script/dom/htmlmediaelement.rs31
-rw-r--r--components/script/dom/imagedata.rs1
-rw-r--r--components/script/dom/mediadevices.rs12
-rw-r--r--components/script/dom/mediastream.rs117
-rw-r--r--components/script/dom/mediastreamtrack.rs74
-rw-r--r--components/script/dom/messageevent.rs1
-rw-r--r--components/script/dom/mod.rs3
-rw-r--r--components/script/dom/paintworkletglobalscope.rs3
-rw-r--r--components/script/dom/rtcpeerconnection.rs37
-rw-r--r--components/script/dom/rtctrackevent.rs78
-rw-r--r--components/script/dom/vrdisplay.rs87
-rw-r--r--components/script/dom/vreyeparameters.rs1
-rw-r--r--components/script/dom/vrframedata.rs4
-rw-r--r--components/script/dom/vrpose.rs6
-rw-r--r--components/script/dom/vrstageparameters.rs1
-rw-r--r--components/script/dom/webidls/MediaStream.webidl24
-rw-r--r--components/script/dom/webidls/MediaStreamTrack.webidl24
-rw-r--r--components/script/dom/webidls/RTCPeerConnection.webidl12
-rw-r--r--components/script/dom/webidls/RTCTrackEvent.webidl23
-rw-r--r--components/script/dom/webidls/XRInputSource.webidl26
-rw-r--r--components/script/dom/webidls/XRSession.webidl5
-rw-r--r--components/script/dom/xmlhttprequest.rs1
-rw-r--r--components/script/dom/xrinputsource.rs83
-rw-r--r--components/script/dom/xrreferencespace.rs2
-rw-r--r--components/script/dom/xrrigidtransform.rs3
-rw-r--r--components/script/dom/xrsession.rs11
-rw-r--r--components/script/dom/xrspace.rs39
-rw-r--r--components/script/dom/xrstationaryreferencespace.rs4
-rw-r--r--components/script/dom/xrview.rs2
-rw-r--r--components/script/dom/xrviewerpose.rs1
-rw-r--r--components/script/script_runtime.rs4
-rw-r--r--components/selectors/builder.rs2
-rw-r--r--components/selectors/context.rs4
-rw-r--r--components/selectors/matching.rs3
-rw-r--r--components/selectors/parser.rs446
-rw-r--r--components/selectors/tree.rs2
-rw-r--r--components/style/author_styles.rs12
-rw-r--r--components/style/dom.rs45
-rw-r--r--components/style/gecko/conversions.rs80
-rw-r--r--components/style/gecko/data.rs5
-rw-r--r--components/style/gecko/media_queries.rs1
-rw-r--r--components/style/gecko/pseudo_element.rs12
-rw-r--r--components/style/gecko/selector_parser.rs25
-rw-r--r--components/style/gecko/snapshot.rs12
-rw-r--r--components/style/gecko/snapshot_helpers.rs12
-rw-r--r--components/style/gecko/wrapper.rs100
-rw-r--r--components/style/invalidation/element/element_wrapper.rs11
-rw-r--r--components/style/invalidation/element/invalidation_map.rs1
-rw-r--r--components/style/invalidation/element/invalidator.rs8
-rw-r--r--components/style/invalidation/element/state_and_attributes.rs12
-rw-r--r--components/style/properties/data.py3
-rw-r--r--components/style/properties/gecko.mako.rs84
-rw-r--r--components/style/properties/longhands/box.mako.rs2
-rw-r--r--components/style/properties/longhands/inherited_table.mako.rs2
-rw-r--r--components/style/properties/longhands/inherited_text.mako.rs7
-rw-r--r--components/style/properties/properties.mako.rs142
-rw-r--r--components/style/properties/shorthands/position.mako.rs9
-rw-r--r--components/style/rule_collector.rs41
-rw-r--r--components/style/servo/selector_parser.rs17
-rw-r--r--components/style/sharing/mod.rs21
-rw-r--r--components/style/stylesheet_set.rs9
-rw-r--r--components/style/stylesheets/origin.rs11
-rw-r--r--components/style/stylist.rs69
-rw-r--r--components/style/values/computed/image.rs2
-rw-r--r--components/style/values/computed/mod.rs1
-rw-r--r--components/style/values/computed/text.rs1
-rw-r--r--components/style/values/generics/box.rs41
-rw-r--r--components/style/values/generics/counters.rs14
-rw-r--r--components/style/values/generics/image.rs30
-rw-r--r--components/style/values/specified/box.rs19
-rw-r--r--components/style/values/specified/image.rs104
-rw-r--r--components/style/values/specified/mod.rs1
-rw-r--r--components/style/values/specified/position.rs6
-rw-r--r--components/style/values/specified/text.rs176
-rw-r--r--components/webvr/Cargo.toml2
-rw-r--r--components/webvr/webvr_thread.rs48
-rw-r--r--components/webvr_traits/Cargo.toml2
-rw-r--r--components/webvr_traits/lib.rs6
-rw-r--r--components/webvr_traits/webvr_traits.rs4
-rwxr-xr-xetc/ci/update-wpt-checkout6
-rw-r--r--etc/taskcluster/decision_task.py92
-rw-r--r--etc/taskcluster/macos/Brewfile-wpt1
-rw-r--r--etc/taskcluster/windows/first-boot.ps12
-rw-r--r--ports/glutin/Cargo.toml2
-rw-r--r--python/mach_bootstrap.py6
-rw-r--r--python/servo/bootstrap.py8
-rw-r--r--python/servo/build_commands.py6
-rw-r--r--python/servo/package_commands.py6
-rw-r--r--resources/prefs.json4
-rw-r--r--support/magicleap/Servo2D/Servo2D.mabu4
-rwxr-xr-xsupport/magicleap/fake-ld.sh2
-rw-r--r--tests/wpt/metadata/css/css-text/parsing/text-transform-valid.html.ini43
-rw-r--r--tests/wpt/metadata/css/css-text/word-break/word-break-break-all-005.html.ini4
-rw-r--r--tests/wpt/metadata/css/css-variables/wide-keyword-fallback.html.ini2
-rw-r--r--tests/wpt/metadata/html/semantics/embedded-content/media-elements/mime-types/canPlayType.html.ini50
120 files changed, 1946 insertions, 1193 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 402e1bb8979..91d5ae31e4f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1017,6 +1017,7 @@ dependencies = [
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
+ "uuid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1444,7 +1445,7 @@ dependencies = [
"fontsan 0.4.0 (git+https://github.com/servo/fontsan)",
"freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx_traits 0.0.1",
- "harfbuzz-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "harfbuzz-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ipc-channel 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1466,7 +1467,7 @@ dependencies = [
"truetype 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ucd 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-bidi 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "unicode-script 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-script 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"webrender_api 0.60.0 (git+https://github.com/servo/webrender)",
"xi-unicode 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"xml5ever 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1866,10 +1867,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "harfbuzz-sys"
-version = "0.2.1"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cmake 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
+ "core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "core-text 13.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -2311,7 +2315,7 @@ dependencies = [
"style 0.0.1",
"style_traits 0.0.1",
"unicode-bidi 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "unicode-script 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-script 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"webrender_api 0.60.0 (git+https://github.com/servo/webrender)",
"xi-unicode 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -2580,7 +2584,6 @@ dependencies = [
"hyper 0.12.14 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper_serde 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"keyboard-types 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "mozjs 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"selectors 0.21.0",
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2807,13 +2810,13 @@ dependencies = [
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "mozjs_sys 0.61.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mozjs_sys 0.61.13 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "mozjs_sys"
-version = "0.61.12"
+version = "0.61.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bindgen 0.49.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3459,7 +3462,7 @@ dependencies = [
[[package]]
name = "rust-webvr"
-version = "0.10.4"
+version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bindgen 0.49.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3472,13 +3475,13 @@ dependencies = [
"libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"ovr-mobile-sys 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rust-webvr-api 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rust-webvr-api 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winit 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rust-webvr-api"
-version = "0.10.4"
+version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"android_injected_glue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3813,7 +3816,7 @@ dependencies = [
"mozangle 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"osmesa-src 0.1.0 (git+https://github.com/servo/osmesa-src)",
"osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "rust-webvr 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rust-webvr 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"sig 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tinyfiledialogs 3.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3860,7 +3863,7 @@ dependencies = [
[[package]]
name = "servo-media"
version = "0.1.0"
-source = "git+https://github.com/servo/media#01cd9be1b8e92e036b4ddff0294893f7e53ef373"
+source = "git+https://github.com/servo/media#8691ca03a37c45bf7efa9430e434dd5fbf0abfa3"
dependencies = [
"servo-media-audio 0.1.0 (git+https://github.com/servo/media)",
"servo-media-player 0.1.0 (git+https://github.com/servo/media)",
@@ -3871,7 +3874,7 @@ dependencies = [
[[package]]
name = "servo-media-audio"
version = "0.1.0"
-source = "git+https://github.com/servo/media#01cd9be1b8e92e036b4ddff0294893f7e53ef373"
+source = "git+https://github.com/servo/media#8691ca03a37c45bf7efa9430e434dd5fbf0abfa3"
dependencies = [
"boxfnonce 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byte-slice-cast 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3887,7 +3890,7 @@ dependencies = [
[[package]]
name = "servo-media-dummy"
version = "0.1.0"
-source = "git+https://github.com/servo/media#01cd9be1b8e92e036b4ddff0294893f7e53ef373"
+source = "git+https://github.com/servo/media#8691ca03a37c45bf7efa9430e434dd5fbf0abfa3"
dependencies = [
"boxfnonce 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ipc-channel 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3901,7 +3904,7 @@ dependencies = [
[[package]]
name = "servo-media-gstreamer"
version = "0.1.0"
-source = "git+https://github.com/servo/media#01cd9be1b8e92e036b4ddff0294893f7e53ef373"
+source = "git+https://github.com/servo/media#8691ca03a37c45bf7efa9430e434dd5fbf0abfa3"
dependencies = [
"boxfnonce 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byte-slice-cast 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3935,7 +3938,7 @@ dependencies = [
[[package]]
name = "servo-media-gstreamer-render"
version = "0.1.0"
-source = "git+https://github.com/servo/media#01cd9be1b8e92e036b4ddff0294893f7e53ef373"
+source = "git+https://github.com/servo/media#8691ca03a37c45bf7efa9430e434dd5fbf0abfa3"
dependencies = [
"gstreamer 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gstreamer-video 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3945,7 +3948,7 @@ dependencies = [
[[package]]
name = "servo-media-gstreamer-render-unix"
version = "0.1.0"
-source = "git+https://github.com/servo/media#01cd9be1b8e92e036b4ddff0294893f7e53ef373"
+source = "git+https://github.com/servo/media#8691ca03a37c45bf7efa9430e434dd5fbf0abfa3"
dependencies = [
"glib 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gstreamer 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3958,7 +3961,7 @@ dependencies = [
[[package]]
name = "servo-media-player"
version = "0.1.0"
-source = "git+https://github.com/servo/media#01cd9be1b8e92e036b4ddff0294893f7e53ef373"
+source = "git+https://github.com/servo/media#8691ca03a37c45bf7efa9430e434dd5fbf0abfa3"
dependencies = [
"ipc-channel 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3969,7 +3972,7 @@ dependencies = [
[[package]]
name = "servo-media-streams"
version = "0.1.0"
-source = "git+https://github.com/servo/media#01cd9be1b8e92e036b4ddff0294893f7e53ef373"
+source = "git+https://github.com/servo/media#8691ca03a37c45bf7efa9430e434dd5fbf0abfa3"
dependencies = [
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"uuid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3978,7 +3981,7 @@ dependencies = [
[[package]]
name = "servo-media-webrtc"
version = "0.1.0"
-source = "git+https://github.com/servo/media#01cd9be1b8e92e036b4ddff0294893f7e53ef373"
+source = "git+https://github.com/servo/media#8691ca03a37c45bf7efa9430e434dd5fbf0abfa3"
dependencies = [
"boxfnonce 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -4077,7 +4080,7 @@ dependencies = [
[[package]]
name = "servo_media_derive"
version = "0.1.0"
-source = "git+https://github.com/servo/media#01cd9be1b8e92e036b4ddff0294893f7e53ef373"
+source = "git+https://github.com/servo/media#8691ca03a37c45bf7efa9430e434dd5fbf0abfa3"
dependencies = [
"proc-macro2 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -4831,10 +4834,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-script"
-version = "0.2.0"
+version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "harfbuzz-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "harfbuzz-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -5140,7 +5143,7 @@ dependencies = [
"ipc-channel 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"msg 0.0.1",
- "rust-webvr 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rust-webvr 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"script_traits 0.0.1",
"servo_config 0.0.1",
"webvr_traits 0.0.1",
@@ -5152,7 +5155,7 @@ version = "0.0.1"
dependencies = [
"ipc-channel 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
"msg 0.0.1",
- "rust-webvr-api 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rust-webvr-api 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -5518,7 +5521,7 @@ dependencies = [
"checksum gvr-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1334b94d8ce67319ddc44663daef53d8c1538629a11562530c981dbd9085b9a"
"checksum h2 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "a27e7ed946e8335bdf9a191bc1b9b14a03ba822d013d2f58437f4fabcbd7fc2c"
"checksum half 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "63d68db75012a85555434ee079e7e6337931f87a087ab2988becbadf64673a7f"
-"checksum harfbuzz-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "87a29ce223fee4727c0c4810a1419a3412f65b29146339fb6a47ee39456c34ea"
+"checksum harfbuzz-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e1042ab0b3e7bc1ff64f7f5935778b644ff2194a1cae5ec52167127d3fd23961"
"checksum hashbrown 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "64b7d419d0622ae02fe5da6b9a5e1964b610a65bb37923b976aeebb6dbb8f86e"
"checksum headers-core 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7794c3bca3a5fb812a06d43f715cf857f7b037d52d6d8e054231d439dd839073"
"checksum headers-derive 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "93b8509be5e3893b8c9c37805a05aa57e4561cf1f1a2aab30cec4931127f36ca"
@@ -5591,7 +5594,7 @@ dependencies = [
"checksum mitochondria 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9de3eca27871df31c33b807f834b94ef7d000956f57aa25c5aed9c5f0aae8f6f"
"checksum mozangle 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c9ba1ce5212fd56a71cfbc463aedd4ece76090d98b96d5122f84dedffa0cc508"
"checksum mozjs 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "622108d35f4fdd68b3aa39bfe9bedaee5fa9efd19711d046e1d56ff607c0a36f"
-"checksum mozjs_sys 0.61.12 (registry+https://github.com/rust-lang/crates.io-index)" = "370887111c83436555cde840bb2639c5a088c77f01b152957d99e1f279397f48"
+"checksum mozjs_sys 0.61.13 (registry+https://github.com/rust-lang/crates.io-index)" = "c7d35502544cf3e70b305e028c6ca9e4c3d5a48264af220f8341598f54d189ba"
"checksum msdos_time 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aad9dfe950c057b1bfe9c1f2aa51583a8468ef2a5baba2ebbe06d775efeb7729"
"checksum muldiv 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "451a9a05d2a32c566c897835e0ea95cf79ed2fdfe957924045a1721a36c9980f"
"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
@@ -5650,8 +5653,8 @@ dependencies = [
"checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96"
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
"checksum ron 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "da06feaa07f69125ab9ddc769b11de29090122170b402547f64b86fe16ebc399"
-"checksum rust-webvr 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)" = "dd268264db4808e78ad1738ce1ff10a8bd53fb5ba408f595763174ca4a6fb875"
-"checksum rust-webvr-api 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1b2af5c6c86fb79e70b5a34daa3d488411225707c73dc5467c7da7c83d557daf"
+"checksum rust-webvr 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e9c827417035beccd02f5e1dde7866c80662efafb8bcfe659f0082d10def4faa"
+"checksum rust-webvr-api 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b5208a3b3f0b02abf17e66c0fe1e0cd3a4f5172c9bf6d1a3e1ac6338a3d218d3"
"checksum rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3058a43ada2c2d0b92b3ae38007a2d0fa5e9db971be260e0171408a4ff471c95"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
"checksum rusttype 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b8eb11f5b0a98c8eca2fb1483f42646d8c340e83e46ab416f8a063a0fd0eeb20"
@@ -5740,7 +5743,7 @@ dependencies = [
"checksum unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284b6d3db520d67fbe88fd778c21510d1b0ba4a551e5d0fbb023d33405f6de8a"
"checksum unicode-bidi 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a6a2c4e3710edd365cd7e78383153ed739fa31af19f9172f72d3575060f5a43a"
"checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f"
-"checksum unicode-script 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e8bd7bbf020b2885113e6304f68bcc33881c5552657c58d4e9699cd1b6606e81"
+"checksum unicode-script 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "09f03ad95feb4fde244d79985bfd79eb34ff2702fedb441d2ba3f4ff813efd19"
"checksum unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8083c594e02b8ae1654ae26f0ade5158b119bd88ad0e8227a5d8fcd72407946"
"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
diff --git a/components/atoms/static_atoms.txt b/components/atoms/static_atoms.txt
index 7a6022cb64c..a42e998c958 100644
--- a/components/atoms/static_atoms.txt
+++ b/components/atoms/static_atoms.txt
@@ -108,6 +108,7 @@ text
time
timeupdate
toggle
+track
transitionend
unhandledrejection
unload
diff --git a/components/canvas_traits/webgl.rs b/components/canvas_traits/webgl.rs
index 474ae4b603b..af88ca905aa 100644
--- a/components/canvas_traits/webgl.rs
+++ b/components/canvas_traits/webgl.rs
@@ -12,7 +12,7 @@ use std::fmt;
use std::num::NonZeroU32;
use std::ops::Deref;
use webrender_api::{DocumentId, ImageKey, PipelineId};
-use webvr_traits::WebVRFutureFrameData;
+use webvr_traits::WebVRPoseInformation;
/// Helper function that creates a WebGL channel (WebGLSender, WebGLReceiver) to be used in WebGLCommands.
pub use crate::webgl_channel::webgl_channel;
@@ -508,9 +508,13 @@ pub enum WebVRCommand {
/// Synchronize the pose information to be used in the frame.
SyncPoses(
WebVRDeviceId,
+ // near
f64,
+ // far
f64,
- WebGLSender<Result<WebVRFutureFrameData, ()>>,
+ // sync gamepads too
+ bool,
+ WebGLSender<Result<WebVRPoseInformation, ()>>,
),
/// Submit the frame to a VR device using the specified texture coordinates.
SubmitFrame(WebVRDeviceId, [f32; 4], [f32; 4]),
diff --git a/components/devtools/Cargo.toml b/components/devtools/Cargo.toml
index 20c2ff5abc8..8ec3b58ae83 100644
--- a/components/devtools/Cargo.toml
+++ b/components/devtools/Cargo.toml
@@ -24,3 +24,4 @@ msg = {path = "../msg"}
serde = "1.0"
serde_json = "1.0"
time = "0.1"
+uuid = {version = "0.7", features = ["v4"]}
diff --git a/components/devtools/actors/console.rs b/components/devtools/actors/console.rs
index 82d44266afe..a4d8f0b1591 100644
--- a/components/devtools/actors/console.rs
+++ b/components/devtools/actors/console.rs
@@ -19,6 +19,7 @@ use msg::constellation_msg::PipelineId;
use serde_json::{self, Map, Number, Value};
use std::cell::RefCell;
use std::net::TcpStream;
+use uuid::Uuid;
trait EncodableConsoleMessage {
fn encode(&self) -> serde_json::Result<String>;
@@ -72,11 +73,30 @@ struct EvaluateJSReply {
result: Value,
timestamp: u64,
exception: Value,
- exceptionMessage: String,
+ exceptionMessage: Value,
helperResult: Value,
}
#[derive(Serialize)]
+struct EvaluateJSEvent {
+ from: String,
+ r#type: String,
+ input: String,
+ result: Value,
+ timestamp: u64,
+ resultID: String,
+ exception: Value,
+ exceptionMessage: Value,
+ helperResult: Value,
+}
+
+#[derive(Serialize)]
+struct EvaluateJSAsyncReply {
+ from: String,
+ resultID: String,
+}
+
+#[derive(Serialize)]
struct SetPreferencesReply {
from: String,
updated: Vec<String>,
@@ -89,6 +109,86 @@ pub struct ConsoleActor {
pub streams: RefCell<Vec<TcpStream>>,
}
+impl ConsoleActor {
+ fn evaluateJS(
+ &self,
+ registry: &ActorRegistry,
+ msg: &Map<String, Value>,
+ ) -> Result<EvaluateJSReply, ()> {
+ let input = msg.get("text").unwrap().as_str().unwrap().to_owned();
+ let (chan, port) = ipc::channel().unwrap();
+ self.script_chan
+ .send(DevtoolScriptControlMsg::EvaluateJS(
+ self.pipeline,
+ input.clone(),
+ chan,
+ ))
+ .unwrap();
+
+ //TODO: extract conversion into protocol module or some other useful place
+ let result = match port.recv().map_err(|_| ())? {
+ VoidValue => {
+ let mut m = Map::new();
+ m.insert("type".to_owned(), Value::String("undefined".to_owned()));
+ Value::Object(m)
+ },
+ NullValue => {
+ let mut m = Map::new();
+ m.insert("type".to_owned(), Value::String("null".to_owned()));
+ Value::Object(m)
+ },
+ BooleanValue(val) => Value::Bool(val),
+ NumberValue(val) => {
+ if val.is_nan() {
+ let mut m = Map::new();
+ m.insert("type".to_owned(), Value::String("NaN".to_owned()));
+ Value::Object(m)
+ } else if val.is_infinite() {
+ let mut m = Map::new();
+ if val < 0. {
+ m.insert("type".to_owned(), Value::String("-Infinity".to_owned()));
+ } else {
+ m.insert("type".to_owned(), Value::String("Infinity".to_owned()));
+ }
+ Value::Object(m)
+ } else if val == 0. && val.is_sign_negative() {
+ let mut m = Map::new();
+ m.insert("type".to_owned(), Value::String("-0".to_owned()));
+ Value::Object(m)
+ } else {
+ Value::Number(Number::from_f64(val).unwrap())
+ }
+ },
+ StringValue(s) => Value::String(s),
+ ActorValue { class, uuid } => {
+ //TODO: make initial ActorValue message include these properties?
+ let mut m = Map::new();
+ let actor = ObjectActor::new(registry, uuid);
+
+ m.insert("type".to_owned(), Value::String("object".to_owned()));
+ m.insert("class".to_owned(), Value::String(class));
+ m.insert("actor".to_owned(), Value::String(actor));
+ m.insert("extensible".to_owned(), Value::Bool(true));
+ m.insert("frozen".to_owned(), Value::Bool(false));
+ m.insert("sealed".to_owned(), Value::Bool(false));
+ Value::Object(m)
+ },
+ };
+
+ //TODO: catch and return exception values from JS evaluation
+ let reply = EvaluateJSReply {
+ from: self.name(),
+ input: input,
+ result: result,
+ timestamp: 0,
+ exception: Value::Null,
+ exceptionMessage: Value::Null,
+ helperResult: Value::Null,
+ };
+ std::result::Result::Ok(reply)
+ }
+}
+
impl Actor for ConsoleActor {
fn name(&self) -> String {
self.name.clone()
@@ -191,76 +291,33 @@ impl Actor for ConsoleActor {
},
"evaluateJS" => {
- let input = msg.get("text").unwrap().as_str().unwrap().to_owned();
- let (chan, port) = ipc::channel().unwrap();
- self.script_chan
- .send(DevtoolScriptControlMsg::EvaluateJS(
- self.pipeline,
- input.clone(),
- chan,
- ))
- .unwrap();
-
- //TODO: extract conversion into protocol module or some other useful place
- let result = match port.recv().map_err(|_| ())? {
- VoidValue => {
- let mut m = Map::new();
- m.insert("type".to_owned(), Value::String("undefined".to_owned()));
- Value::Object(m)
- },
- NullValue => {
- let mut m = Map::new();
- m.insert("type".to_owned(), Value::String("null".to_owned()));
- Value::Object(m)
- },
- BooleanValue(val) => Value::Bool(val),
- NumberValue(val) => {
- if val.is_nan() {
- let mut m = Map::new();
- m.insert("type".to_owned(), Value::String("NaN".to_owned()));
- Value::Object(m)
- } else if val.is_infinite() {
- let mut m = Map::new();
- if val < 0. {
- m.insert("type".to_owned(), Value::String("-Infinity".to_owned()));
- } else {
- m.insert("type".to_owned(), Value::String("Infinity".to_owned()));
- }
- Value::Object(m)
- } else if val == 0. && val.is_sign_negative() {
- let mut m = Map::new();
- m.insert("type".to_owned(), Value::String("-0".to_owned()));
- Value::Object(m)
- } else {
- Value::Number(Number::from_f64(val).unwrap())
- }
- },
- StringValue(s) => Value::String(s),
- ActorValue { class, uuid } => {
- //TODO: make initial ActorValue message include these properties?
- let mut m = Map::new();
- let actor = ObjectActor::new(registry, uuid);
+ let msg = self.evaluateJS(&registry, &msg);
+ stream.write_json_packet(&msg);
+ ActorMessageStatus::Processed
+ },
- m.insert("type".to_owned(), Value::String("object".to_owned()));
- m.insert("class".to_owned(), Value::String(class));
- m.insert("actor".to_owned(), Value::String(actor));
- m.insert("extensible".to_owned(), Value::Bool(true));
- m.insert("frozen".to_owned(), Value::Bool(false));
- m.insert("sealed".to_owned(), Value::Bool(false));
- Value::Object(m)
- },
+ "evaluateJSAsync" => {
+ let resultID = Uuid::new_v4().to_string();
+ let early_reply = EvaluateJSAsyncReply {
+ from: self.name(),
+ resultID: resultID.clone(),
};
-
- //TODO: catch and return exception values from JS evaluation
- let msg = EvaluateJSReply {
+ // Emit an eager reply so that the client starts listening
+ // for an async event with the resultID
+ stream.write_json_packet(&early_reply);
+ let reply = self.evaluateJS(&registry, &msg).unwrap();
+ let msg = EvaluateJSEvent {
from: self.name(),
- input: input,
- result: result,
- timestamp: 0,
- exception: Value::Object(Map::new()),
- exceptionMessage: "".to_owned(),
- helperResult: Value::Object(Map::new()),
+ r#type: "evaluationResult".to_owned(),
+ input: reply.input,
+ result: reply.result,
+ timestamp: reply.timestamp,
+ resultID: resultID,
+ exception: reply.exception,
+ exceptionMessage: reply.exceptionMessage,
+ helperResult: reply.helperResult,
};
+ // Send the data from evaluateJS along with a resultID
stream.write_json_packet(&msg);
ActorMessageStatus::Processed
},
diff --git a/components/gfx/Cargo.toml b/components/gfx/Cargo.toml
index 28da033b807..b57c70ac0c9 100644
--- a/components/gfx/Cargo.toml
+++ b/components/gfx/Cargo.toml
@@ -23,7 +23,7 @@ euclid = "0.19"
fnv = "1.0"
fontsan = {git = "https://github.com/servo/fontsan"}
gfx_traits = {path = "../gfx_traits"}
-harfbuzz-sys = "0.2"
+harfbuzz-sys = "0.3"
ipc-channel = "0.11"
lazy_static = "1"
libc = "0.2"
@@ -41,7 +41,7 @@ smallvec = { version = "0.6", features = ["std", "union"] }
style = {path = "../style", features = ["servo"]}
time = "0.1.12"
unicode-bidi = {version = "0.3", features = ["with_serde"]}
-unicode-script = {version = "0.2", features = ["harfbuzz"]}
+unicode-script = {version = "0.3", features = ["harfbuzz"]}
webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]}
xi-unicode = "0.1.0"
ucd = "0.1.1"
diff --git a/components/gfx/text/shaping/harfbuzz.rs b/components/gfx/text/shaping/harfbuzz.rs
index 88cd19d59ff..ce8ce628f08 100644
--- a/components/gfx/text/shaping/harfbuzz.rs
+++ b/components/gfx/text/shaping/harfbuzz.rs
@@ -24,7 +24,6 @@ use harfbuzz_sys::hb_feature_t;
use harfbuzz_sys::hb_font_create;
use harfbuzz_sys::hb_font_funcs_create;
use harfbuzz_sys::hb_font_funcs_set_glyph_h_advance_func;
-use harfbuzz_sys::hb_font_funcs_set_glyph_h_kerning_func;
use harfbuzz_sys::hb_font_funcs_set_nominal_glyph_func;
use harfbuzz_sys::hb_font_set_funcs;
use harfbuzz_sys::hb_font_set_ppem;
@@ -459,12 +458,6 @@ lazy_static! {
ptr::null_mut(),
None,
);
- hb_font_funcs_set_glyph_h_kerning_func(
- hb_funcs,
- Some(glyph_h_kerning_func),
- ptr::null_mut(),
- None,
- );
FontFuncs(hb_funcs)
};
@@ -519,22 +512,6 @@ fn glyph_space_advance(font: *const Font) -> (hb_codepoint_t, f64) {
(space_glyph, space_advance)
}
-extern "C" fn glyph_h_kerning_func(
- _: *mut hb_font_t,
- font_data: *mut c_void,
- first_glyph: hb_codepoint_t,
- second_glyph: hb_codepoint_t,
- _: *mut c_void,
-) -> hb_position_t {
- let font: *mut Font = font_data as *mut Font;
- assert!(!font.is_null());
-
- unsafe {
- let advance = (*font).glyph_h_kerning(first_glyph as GlyphId, second_glyph as GlyphId);
- Shaper::float_to_fixed(advance)
- }
-}
-
// Callback to get a font table out of a font.
extern "C" fn font_table_func(
_: *mut hb_face_t,
diff --git a/components/layout/Cargo.toml b/components/layout/Cargo.toml
index 423d5ac9326..247a4623a43 100644
--- a/components/layout/Cargo.toml
+++ b/components/layout/Cargo.toml
@@ -51,7 +51,7 @@ smallvec = { version = "0.6", features = ["std", "union"] }
style = {path = "../style", features = ["servo"]}
style_traits = {path = "../style_traits"}
unicode-bidi = {version = "0.3", features = ["with_serde"]}
-unicode-script = {version = "0.2", features = ["harfbuzz"]}
+unicode-script = {version = "0.3", features = ["harfbuzz"]}
webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]}
xi-unicode = "0.1.0"
diff --git a/components/layout/display_list/gradient.rs b/components/layout/display_list/gradient.rs
index db5208eadac..9b19ee48299 100644
--- a/components/layout/display_list/gradient.rs
+++ b/components/layout/display_list/gradient.rs
@@ -12,7 +12,7 @@ use style::values::computed::image::{EndingShape, LineDirection};
use style::values::computed::{Angle, GradientItem, LengthPercentage, Percentage, Position};
use style::values::generics::image::EndingShape as GenericEndingShape;
use style::values::generics::image::GradientItem as GenericGradientItem;
-use style::values::generics::image::{Circle, Ellipse, ShapeExtent};
+use style::values::generics::image::{Circle, ColorStop, Ellipse, ShapeExtent};
use style::values::specified::position::{X, Y};
use webrender_api::{ExtendMode, Gradient, GradientBuilder, GradientStop, RadialGradient};
@@ -92,7 +92,14 @@ fn convert_gradient_stops(
let mut stop_items = gradient_items
.iter()
.filter_map(|item| match *item {
- GenericGradientItem::ColorStop(ref stop) => Some(*stop),
+ GenericGradientItem::SimpleColorStop(color) => Some(ColorStop {
+ color,
+ position: None,
+ }),
+ GenericGradientItem::ComplexColorStop { color, position } => Some(ColorStop {
+ color,
+ position: Some(position),
+ }),
_ => None,
})
.collect::<Vec<_>>();
diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs
index ff62cc79638..ccc3de5ec7e 100644
--- a/components/layout/fragment.rs
+++ b/components/layout/fragment.rs
@@ -61,8 +61,8 @@ use style::selector_parser::RestyleDamage;
use style::servo::restyle_damage::ServoRestyleDamage;
use style::str::char_is_whitespace;
use style::values::computed::counters::ContentItem;
-use style::values::computed::{LengthPercentage, LengthPercentageOrAuto, Size};
-use style::values::generics::box_::{Perspective, VerticalAlign};
+use style::values::computed::{LengthPercentage, LengthPercentageOrAuto, Size, VerticalAlign};
+use style::values::generics::box_::{Perspective, VerticalAlignKeyword};
use style::values::generics::transform;
use style::Zero;
use webrender_api::{self, LayoutTransform};
@@ -2397,47 +2397,49 @@ impl Fragment {
// FIXME(#5624, pcwalton): This passes our current reftests but isn't the right thing
// to do.
match style.get_box().vertical_align {
- VerticalAlign::Baseline => {},
- VerticalAlign::Middle => {
- let font_metrics =
- with_thread_local_font_context(layout_context, |font_context| {
- text::font_metrics_for_style(font_context, self.style.clone_font())
- });
- offset += (content_inline_metrics.ascent -
- content_inline_metrics.space_below_baseline -
- font_metrics.x_height)
- .scale_by(0.5)
- },
- VerticalAlign::Sub => {
- offset += minimum_line_metrics
- .space_needed()
- .scale_by(FONT_SUBSCRIPT_OFFSET_RATIO)
- },
- VerticalAlign::Super => {
- offset -= minimum_line_metrics
- .space_needed()
- .scale_by(FONT_SUPERSCRIPT_OFFSET_RATIO)
- },
- VerticalAlign::TextTop => {
- offset = self.content_inline_metrics(layout_context).ascent -
- minimum_line_metrics.space_above_baseline
- },
- VerticalAlign::TextBottom => {
- offset = minimum_line_metrics.space_below_baseline -
- self.content_inline_metrics(layout_context)
- .space_below_baseline
- },
- VerticalAlign::Top => {
- if let Some(actual_line_metrics) = actual_line_metrics {
- offset =
- content_inline_metrics.ascent - actual_line_metrics.space_above_baseline
- }
- },
- VerticalAlign::Bottom => {
- if let Some(actual_line_metrics) = actual_line_metrics {
- offset = actual_line_metrics.space_below_baseline -
- content_inline_metrics.space_below_baseline
- }
+ VerticalAlign::Keyword(kw) => match kw {
+ VerticalAlignKeyword::Baseline => {},
+ VerticalAlignKeyword::Middle => {
+ let font_metrics =
+ with_thread_local_font_context(layout_context, |font_context| {
+ text::font_metrics_for_style(font_context, self.style.clone_font())
+ });
+ offset += (content_inline_metrics.ascent -
+ content_inline_metrics.space_below_baseline -
+ font_metrics.x_height)
+ .scale_by(0.5)
+ },
+ VerticalAlignKeyword::Sub => {
+ offset += minimum_line_metrics
+ .space_needed()
+ .scale_by(FONT_SUBSCRIPT_OFFSET_RATIO)
+ },
+ VerticalAlignKeyword::Super => {
+ offset -= minimum_line_metrics
+ .space_needed()
+ .scale_by(FONT_SUPERSCRIPT_OFFSET_RATIO)
+ },
+ VerticalAlignKeyword::TextTop => {
+ offset = self.content_inline_metrics(layout_context).ascent -
+ minimum_line_metrics.space_above_baseline
+ },
+ VerticalAlignKeyword::TextBottom => {
+ offset = minimum_line_metrics.space_below_baseline -
+ self.content_inline_metrics(layout_context)
+ .space_below_baseline
+ },
+ VerticalAlignKeyword::Top => {
+ if let Some(actual_line_metrics) = actual_line_metrics {
+ offset = content_inline_metrics.ascent -
+ actual_line_metrics.space_above_baseline
+ }
+ },
+ VerticalAlignKeyword::Bottom => {
+ if let Some(actual_line_metrics) = actual_line_metrics {
+ offset = actual_line_metrics.space_below_baseline -
+ content_inline_metrics.space_below_baseline
+ }
+ },
},
VerticalAlign::Length(ref lp) => {
offset -= lp.to_used_value(minimum_line_metrics.space_needed());
@@ -3087,15 +3089,22 @@ impl Fragment {
/// Returns true if any of the inline styles associated with this fragment have
/// `vertical-align` set to `top` or `bottom`.
pub fn is_vertically_aligned_to_top_or_bottom(&self) -> bool {
- match self.style.get_box().vertical_align {
- VerticalAlign::Top | VerticalAlign::Bottom => return true,
- _ => {},
+ fn is_top_or_bottom(v: &VerticalAlign) -> bool {
+ match *v {
+ VerticalAlign::Keyword(VerticalAlignKeyword::Top) |
+ VerticalAlign::Keyword(VerticalAlignKeyword::Bottom) => true,
+ _ => false,
+ }
+ }
+
+ if is_top_or_bottom(&self.style.get_box().vertical_align) {
+ return true;
}
+
if let Some(ref inline_context) = self.inline_context {
for node in &inline_context.nodes {
- match node.style.get_box().vertical_align {
- VerticalAlign::Top | VerticalAlign::Bottom => return true,
- _ => {},
+ if is_top_or_bottom(&node.style.get_box().vertical_align) {
+ return true;
}
}
}
diff --git a/components/layout/inline.rs b/components/layout/inline.rs
index bef95a64f96..f4dacefc5ef 100644
--- a/components/layout/inline.rs
+++ b/components/layout/inline.rs
@@ -41,7 +41,7 @@ use style::logical_geometry::{LogicalRect, LogicalSize, WritingMode};
use style::properties::ComputedValues;
use style::servo::restyle_damage::ServoRestyleDamage;
use style::values::computed::box_::VerticalAlign;
-use style::values::generics::box_::VerticalAlign as GenericVerticalAlign;
+use style::values::generics::box_::VerticalAlignKeyword;
use style::values::specified::text::TextOverflowSide;
use unicode_bidi as bidi;
@@ -1269,13 +1269,13 @@ impl InlineFlow {
let mut largest_block_size_for_top_fragments = Au(0);
let mut largest_block_size_for_bottom_fragments = Au(0);
- // We use `VerticalAlign::Baseline` here because `vertical-align` must
+ // We use `VerticalAlign::baseline()` here because `vertical-align` must
// not apply to the inside of inline blocks.
update_line_metrics_for_fragment(
&mut line_metrics,
&inline_metrics,
style.get_box().display,
- GenericVerticalAlign::Baseline,
+ VerticalAlign::baseline(),
&mut largest_block_size_for_top_fragments,
&mut largest_block_size_for_bottom_fragments,
);
@@ -1322,11 +1322,20 @@ impl InlineFlow {
largest_block_size_for_top_fragments: &mut Au,
largest_block_size_for_bottom_fragments: &mut Au,
) {
+ // FIXME(emilio): This should probably be handled.
+ let vertical_align_value = match vertical_align_value {
+ VerticalAlign::Keyword(kw) => kw,
+ VerticalAlign::Length(..) => {
+ *line_metrics = line_metrics.new_metrics_for_fragment(inline_metrics);
+ return;
+ },
+ };
+
match (display_value, vertical_align_value) {
- (Display::Inline, GenericVerticalAlign::Top) |
- (Display::Block, GenericVerticalAlign::Top) |
- (Display::InlineFlex, GenericVerticalAlign::Top) |
- (Display::InlineBlock, GenericVerticalAlign::Top)
+ (Display::Inline, VerticalAlignKeyword::Top) |
+ (Display::Block, VerticalAlignKeyword::Top) |
+ (Display::InlineFlex, VerticalAlignKeyword::Top) |
+ (Display::InlineBlock, VerticalAlignKeyword::Top)
if inline_metrics.space_above_baseline >= Au(0) =>
{
*largest_block_size_for_top_fragments = max(
@@ -1334,10 +1343,10 @@ impl InlineFlow {
inline_metrics.space_above_baseline + inline_metrics.space_below_baseline,
)
},
- (Display::Inline, GenericVerticalAlign::Bottom) |
- (Display::Block, GenericVerticalAlign::Bottom) |
- (Display::InlineFlex, GenericVerticalAlign::Bottom) |
- (Display::InlineBlock, GenericVerticalAlign::Bottom)
+ (Display::Inline, VerticalAlignKeyword::Bottom) |
+ (Display::Block, VerticalAlignKeyword::Bottom) |
+ (Display::InlineFlex, VerticalAlignKeyword::Bottom) |
+ (Display::InlineBlock, VerticalAlignKeyword::Bottom)
if inline_metrics.space_below_baseline >= Au(0) =>
{
*largest_block_size_for_bottom_fragments = max(
diff --git a/components/layout/table_cell.rs b/components/layout/table_cell.rs
index 682a1c38ec4..ec79f9f4540 100644
--- a/components/layout/table_cell.rs
+++ b/components/layout/table_cell.rs
@@ -23,7 +23,7 @@ use style::logical_geometry::{LogicalMargin, LogicalRect, LogicalSize, WritingMo
use style::properties::ComputedValues;
use style::values::computed::length::Size;
use style::values::computed::Color;
-use style::values::generics::box_::VerticalAlign;
+use style::values::generics::box_::{VerticalAlign, VerticalAlignKeyword};
use style::values::specified::BorderStyle;
#[allow(unsafe_code)]
@@ -138,11 +138,11 @@ impl TableCellFlow {
self.block_flow.fragment.border_padding.block_start_end();
let kids_self_gap = self_size - kids_size;
- // This offset should also account for VerticalAlign::Baseline.
+ // This offset should also account for VerticalAlign::baseline.
// Need max cell ascent from the first row of this cell.
let offset = match self.block_flow.fragment.style().get_box().vertical_align {
- VerticalAlign::Middle => kids_self_gap / 2,
- VerticalAlign::Bottom => kids_self_gap,
+ VerticalAlign::Keyword(VerticalAlignKeyword::Middle) => kids_self_gap / 2,
+ VerticalAlign::Keyword(VerticalAlignKeyword::Bottom) => kids_self_gap,
_ => Au(0),
};
if offset == Au(0) {
diff --git a/components/layout/text.rs b/components/layout/text.rs
index b26e531e670..199bd7e07f2 100644
--- a/components/layout/text.rs
+++ b/components/layout/text.rs
@@ -21,13 +21,13 @@ use std::collections::LinkedList;
use std::mem;
use std::sync::Arc;
use style::computed_values::text_rendering::T as TextRendering;
-use style::computed_values::text_transform::T as TextTransform;
use style::computed_values::white_space::T as WhiteSpace;
use style::computed_values::word_break::T as WordBreak;
use style::logical_geometry::{LogicalSize, WritingMode};
use style::properties::style_structs::Font as FontStyleStruct;
use style::properties::ComputedValues;
use style::values::generics::text::LineHeight;
+use style::values::specified::text::{TextTransform, TextTransformCase};
use unicode_bidi as bidi;
use unicode_script::{get_script, Script};
use xi_unicode::LineBreakLeafIter;
@@ -738,23 +738,23 @@ fn apply_style_transform_if_necessary(
last_whitespace: bool,
is_first_run: bool,
) {
- match text_transform {
- TextTransform::None => {},
- TextTransform::Uppercase => {
+ match text_transform.case_ {
+ TextTransformCase::None => {},
+ TextTransformCase::Uppercase => {
let original = string[first_character_position..].to_owned();
string.truncate(first_character_position);
for ch in original.chars().flat_map(|ch| ch.to_uppercase()) {
string.push(ch);
}
},
- TextTransform::Lowercase => {
+ TextTransformCase::Lowercase => {
let original = string[first_character_position..].to_owned();
string.truncate(first_character_position);
for ch in original.chars().flat_map(|ch| ch.to_lowercase()) {
string.push(ch);
}
},
- TextTransform::Capitalize => {
+ TextTransformCase::Capitalize => {
let original = string[first_character_position..].to_owned();
string.truncate(first_character_position);
diff --git a/components/layout_thread/dom_wrapper.rs b/components/layout_thread/dom_wrapper.rs
index 88eedef7d17..301a7500713 100644
--- a/components/layout_thread/dom_wrapper.rs
+++ b/components/layout_thread/dom_wrapper.rs
@@ -973,6 +973,11 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
}
#[inline]
+ fn is_part(&self, _name: &Atom) -> bool {
+ false
+ }
+
+ #[inline]
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
unsafe { self.element.has_class_for_layout(name, case_sensitivity) }
}
@@ -1484,6 +1489,12 @@ impl<'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> {
false
}
+ #[inline]
+ fn is_part(&self, _name: &Atom) -> bool {
+ debug!("ServoThreadSafeLayoutElement::is_part called");
+ false
+ }
+
fn has_class(&self, _name: &Atom, _case_sensitivity: CaseSensitivity) -> bool {
debug!("ServoThreadSafeLayoutElement::has_class called");
false
diff --git a/components/malloc_size_of/Cargo.toml b/components/malloc_size_of/Cargo.toml
index e7acb0de25e..609a977b1dd 100644
--- a/components/malloc_size_of/Cargo.toml
+++ b/components/malloc_size_of/Cargo.toml
@@ -14,7 +14,6 @@ servo = [
"hyper",
"hyper_serde",
"keyboard-types",
- "mozjs",
"serde",
"serde_bytes",
"string_cache",
@@ -33,7 +32,6 @@ hashglobe = { path = "../hashglobe" }
hyper = { version = "0.12", optional = true }
hyper_serde = { version = "0.9", optional = true }
keyboard-types = {version = "0.4.3", optional = true}
-mozjs = { version = "0.10.0", optional = true}
selectors = { path = "../selectors" }
serde = { version = "1.0.27", optional = true }
serde_bytes = { version = "0.10", optional = true }
diff --git a/components/malloc_size_of/lib.rs b/components/malloc_size_of/lib.rs
index bb4fe1a6adc..d65f8e957e4 100644
--- a/components/malloc_size_of/lib.rs
+++ b/components/malloc_size_of/lib.rs
@@ -58,8 +58,6 @@ extern crate hyper;
extern crate hyper_serde;
#[cfg(feature = "servo")]
extern crate keyboard_types;
-#[cfg(feature = "servo")]
-extern crate mozjs as js;
extern crate selectors;
#[cfg(feature = "servo")]
extern crate serde;
@@ -749,6 +747,7 @@ where
Component::ExplicitUniversalType |
Component::LocalName(..) |
Component::ID(..) |
+ Component::Part(..) |
Component::Class(..) |
Component::AttributeInNoNamespaceExists { .. } |
Component::AttributeInNoNamespace { .. } |
@@ -778,12 +777,6 @@ impl<Impl: selectors::parser::SelectorImpl> MallocSizeOf
}
}
-impl MallocSizeOf for selectors::context::QuirksMode {
- fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
- 0
- }
-}
-
impl MallocSizeOf for Void {
#[inline]
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
@@ -798,15 +791,6 @@ impl<Static: string_cache::StaticAtomSet> MallocSizeOf for string_cache::Atom<St
}
}
-// This is measured properly by the heap measurement implemented in
-// SpiderMonkey.
-#[cfg(feature = "servo")]
-impl<T: Copy + js::rust::GCMethods> MallocSizeOf for js::jsapi::Heap<T> {
- fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
- 0
- }
-}
-
/// For use on types where size_of() returns 0.
#[macro_export]
macro_rules! malloc_size_of_is_0(
diff --git a/components/script/dom/audiobuffer.rs b/components/script/dom/audiobuffer.rs
index a021b61ac8c..cabd281dc63 100644
--- a/components/script/dom/audiobuffer.rs
+++ b/components/script/dom/audiobuffer.rs
@@ -42,6 +42,7 @@ type JSAudioChannel = Heap<*mut JSObject>;
pub struct AudioBuffer {
reflector_: Reflector,
/// Float32Arrays returned by calls to GetChannelData.
+ #[ignore_malloc_size_of = "mozjs"]
js_channels: DomRefCell<Vec<JSAudioChannel>>,
/// Aggregates the data from js_channels.
/// This is Some<T> iff the buffers in js_channels are detached.
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs
index 56805e4d9fe..023917c172c 100644
--- a/components/script/dom/bindings/trace.rs
+++ b/components/script/dom/bindings/trace.rs
@@ -105,6 +105,7 @@ use servo_media::audio::panner_node::{DistanceModel, PanningModel};
use servo_media::audio::param::ParamType;
use servo_media::player::Player;
use servo_media::streams::registry::MediaStreamId;
+use servo_media::streams::MediaStreamType;
use servo_media::webrtc::WebRtcController;
use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
use smallvec::SmallVec;
@@ -138,7 +139,7 @@ use tendril::{StrTendril, TendrilSink};
use time::{Duration, Timespec};
use uuid::Uuid;
use webrender_api::{DocumentId, ImageKey, RenderApiSender};
-use webvr_traits::WebVRGamepadHand;
+use webvr_traits::{WebVRGamepadData, WebVRGamepadHand, WebVRGamepadState};
/// A trait to allow tracing (only) DOM objects.
pub unsafe trait JSTraceable {
@@ -478,7 +479,7 @@ unsafe_no_jsmanaged_fields!(WebGLVertexArrayId);
unsafe_no_jsmanaged_fields!(WebGLVersion);
unsafe_no_jsmanaged_fields!(WebGLSLVersion);
unsafe_no_jsmanaged_fields!(MediaList);
-unsafe_no_jsmanaged_fields!(WebVRGamepadHand);
+unsafe_no_jsmanaged_fields!(WebVRGamepadData, WebVRGamepadState, WebVRGamepadHand);
unsafe_no_jsmanaged_fields!(ScriptToConstellationChan);
unsafe_no_jsmanaged_fields!(InteractiveMetrics);
unsafe_no_jsmanaged_fields!(InteractiveWindow);
@@ -490,7 +491,7 @@ unsafe_no_jsmanaged_fields!(NodeId);
unsafe_no_jsmanaged_fields!(AnalysisEngine, DistanceModel, PanningModel, ParamType);
unsafe_no_jsmanaged_fields!(dyn Player);
unsafe_no_jsmanaged_fields!(WebRtcController);
-unsafe_no_jsmanaged_fields!(MediaStreamId);
+unsafe_no_jsmanaged_fields!(MediaStreamId, MediaStreamType);
unsafe_no_jsmanaged_fields!(Mutex<MediaFrameRenderer>);
unsafe_no_jsmanaged_fields!(RenderApiSender);
unsafe_no_jsmanaged_fields!(ResourceFetchTiming);
diff --git a/components/script/dom/customelementregistry.rs b/components/script/dom/customelementregistry.rs
index 3d329119f4e..39824e334a2 100644
--- a/components/script/dom/customelementregistry.rs
+++ b/components/script/dom/customelementregistry.rs
@@ -719,7 +719,7 @@ pub enum CustomElementReaction {
Upgrade(#[ignore_malloc_size_of = "Rc"] Rc<CustomElementDefinition>),
Callback(
#[ignore_malloc_size_of = "Rc"] Rc<Function>,
- Box<[Heap<JSVal>]>,
+ #[ignore_malloc_size_of = "mozjs"] Box<[Heap<JSVal>]>,
),
}
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs
index 2d12e93774d..1b918c0537b 100644
--- a/components/script/dom/element.rs
+++ b/components/script/dom/element.rs
@@ -3075,6 +3075,10 @@ impl<'a> SelectorsElement for DomRoot<Element> {
.map_or(false, |atom| case_sensitivity.eq_atom(id, atom))
}
+ fn is_part(&self, _name: &Atom) -> bool {
+ false
+ }
+
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
Element::has_class(&**self, name, case_sensitivity)
}
diff --git a/components/script/dom/extendablemessageevent.rs b/components/script/dom/extendablemessageevent.rs
index f9c2de13a4b..7fd16aafec4 100644
--- a/components/script/dom/extendablemessageevent.rs
+++ b/components/script/dom/extendablemessageevent.rs
@@ -24,6 +24,7 @@ use servo_atoms::Atom;
#[dom_struct]
pub struct ExtendableMessageEvent {
event: ExtendableEvent,
+ #[ignore_malloc_size_of = "mozjs"]
data: Heap<JSVal>,
origin: DOMString,
lastEventId: DOMString,
diff --git a/components/script/dom/filereader.rs b/components/script/dom/filereader.rs
index 6092dcc9935..55989078d4f 100644
--- a/components/script/dom/filereader.rs
+++ b/components/script/dom/filereader.rs
@@ -83,7 +83,7 @@ pub enum FileReaderReadyState {
#[derive(JSTraceable, MallocSizeOf)]
pub enum FileReaderResult {
- ArrayBuffer(Heap<JSVal>),
+ ArrayBuffer(#[ignore_malloc_size_of = "mozjs"] Heap<JSVal>),
String(DOMString),
}
diff --git a/components/script/dom/gamepad.rs b/components/script/dom/gamepad.rs
index 3e65b0a11f5..fe86a3b2329 100644
--- a/components/script/dom/gamepad.rs
+++ b/components/script/dom/gamepad.rs
@@ -32,6 +32,7 @@ pub struct Gamepad {
connected: Cell<bool>,
timestamp: Cell<f64>,
mapping_type: String,
+ #[ignore_malloc_size_of = "mozjs"]
axes: Heap<*mut JSObject>,
buttons: Dom<GamepadButtonList>,
pose: Option<Dom<VRPose>>,
diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs
index 91112299034..33458bf2ece 100644
--- a/components/script/dom/globalscope.rs
+++ b/components/script/dom/globalscope.rs
@@ -145,6 +145,7 @@ pub struct GlobalScope {
/// they're consumed before it'd be reported.
///
/// <https://html.spec.whatwg.org/multipage/#about-to-be-notified-rejected-promises-list>
+ #[ignore_malloc_size_of = "mozjs"]
uncaught_rejections: DomRefCell<Vec<Box<Heap<*mut JSObject>>>>,
/// Promises in this list have previously been reported as rejected
@@ -152,6 +153,7 @@ pub struct GlobalScope {
/// in the last turn of the event loop.
///
/// <https://html.spec.whatwg.org/multipage/#outstanding-rejected-promises-weak-set>
+ #[ignore_malloc_size_of = "mozjs"]
consumed_rejections: DomRefCell<Vec<Box<Heap<*mut JSObject>>>>,
}
diff --git a/components/script/dom/history.rs b/components/script/dom/history.rs
index e468b79440c..787591af8a3 100644
--- a/components/script/dom/history.rs
+++ b/components/script/dom/history.rs
@@ -40,6 +40,7 @@ enum PushOrReplace {
pub struct History {
reflector_: Reflector,
window: Dom<Window>,
+ #[ignore_malloc_size_of = "mozjs"]
state: Heap<JSVal>,
state_id: Cell<Option<HistoryStateId>>,
}
diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs
index 8d41a685b7b..9bbfb30d46c 100644
--- a/components/script/dom/htmlmediaelement.rs
+++ b/components/script/dom/htmlmediaelement.rs
@@ -62,7 +62,6 @@ use html5ever::{LocalName, Prefix};
use http::header::{self, HeaderMap, HeaderValue};
use ipc_channel::ipc;
use ipc_channel::router::ROUTER;
-use mime::{self, Mime};
use net_traits::image::base::Image;
use net_traits::image_cache::ImageResponse;
use net_traits::request::{CredentialsMode, Destination, Referrer, RequestBuilder};
@@ -73,7 +72,7 @@ use servo_config::pref;
use servo_media::player::context::{GlContext, NativeDisplay, PlayerGLContext};
use servo_media::player::frame::{Frame, FrameRenderer};
use servo_media::player::{PlaybackState, Player, PlayerError, PlayerEvent, StreamType};
-use servo_media::ServoMedia;
+use servo_media::{ServoMedia, SupportsMediaType};
use servo_url::ServoUrl;
use std::cell::Cell;
use std::collections::VecDeque;
@@ -840,9 +839,13 @@ impl HTMLMediaElement {
self.fetch_request(None);
},
SrcObject::MediaStream(ref stream) => {
- for stream in stream.get_tracks() {
- if let Err(_) =
- self.player.borrow().as_ref().unwrap().set_stream(&stream)
+ for stream in &*stream.get_tracks() {
+ if let Err(_) = self
+ .player
+ .borrow()
+ .as_ref()
+ .unwrap()
+ .set_stream(&stream.id())
{
self.queue_dedicated_media_source_failure_steps();
}
@@ -1674,20 +1677,10 @@ impl HTMLMediaElementMethods for HTMLMediaElement {
// https://html.spec.whatwg.org/multipage/#dom-navigator-canplaytype
fn CanPlayType(&self, type_: DOMString) -> CanPlayTypeResult {
- match type_.parse::<Mime>() {
- // XXX GStreamer is currently not very reliable playing OGG and most of
- // the media related WPTs uses OGG if we report that we are able to
- // play this type. So we report that we are unable to play it to force
- // the usage of other types.
- // https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/issues/520
- Ok(ref mime)
- if (mime.type_() == mime::APPLICATION && mime.subtype() == mime::OCTET_STREAM) ||
- (mime.subtype() == mime::OGG) =>
- {
- CanPlayTypeResult::_empty
- },
- Err(_) => CanPlayTypeResult::_empty,
- _ => CanPlayTypeResult::Maybe,
+ match ServoMedia::get().unwrap().can_play_type(&type_) {
+ SupportsMediaType::No => CanPlayTypeResult::_empty,
+ SupportsMediaType::Maybe => CanPlayTypeResult::Maybe,
+ SupportsMediaType::Probably => CanPlayTypeResult::Probably,
}
}
diff --git a/components/script/dom/imagedata.rs b/components/script/dom/imagedata.rs
index 9566c7b0f39..29c15f665a4 100644
--- a/components/script/dom/imagedata.rs
+++ b/components/script/dom/imagedata.rs
@@ -25,6 +25,7 @@ pub struct ImageData {
reflector_: Reflector,
width: u32,
height: u32,
+ #[ignore_malloc_size_of = "mozjs"]
data: Heap<*mut JSObject>,
}
diff --git a/components/script/dom/mediadevices.rs b/components/script/dom/mediadevices.rs
index 0a4f00e2472..bcc575a2ef6 100644
--- a/components/script/dom/mediadevices.rs
+++ b/components/script/dom/mediadevices.rs
@@ -14,9 +14,11 @@ use crate::dom::bindings::root::DomRoot;
use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
use crate::dom::mediastream::MediaStream;
+use crate::dom::mediastreamtrack::MediaStreamTrack;
use crate::dom::promise::Promise;
use dom_struct::dom_struct;
use servo_media::streams::capture::{Constrain, ConstrainRange, MediaTrackConstraintSet};
+use servo_media::streams::MediaStreamType;
use servo_media::ServoMedia;
use std::rc::Rc;
@@ -51,18 +53,20 @@ impl MediaDevicesMethods for MediaDevices {
InCompartment::Already(&in_compartment_proof),
);
let media = ServoMedia::get().unwrap();
- let mut tracks = vec![];
+ let stream = MediaStream::new(&self.global());
if let Some(constraints) = convert_constraints(&constraints.audio) {
if let Some(audio) = media.create_audioinput_stream(constraints) {
- tracks.push(audio)
+ let track = MediaStreamTrack::new(&self.global(), audio, MediaStreamType::Audio);
+ stream.add_track(&track);
}
}
if let Some(constraints) = convert_constraints(&constraints.video) {
if let Some(video) = media.create_videoinput_stream(constraints) {
- tracks.push(video)
+ let track = MediaStreamTrack::new(&self.global(), video, MediaStreamType::Video);
+ stream.add_track(&track);
}
}
- let stream = MediaStream::new(&self.global(), tracks);
+
p.resolve_native(&stream);
p
}
diff --git a/components/script/dom/mediastream.rs b/components/script/dom/mediastream.rs
index 42588afc476..2ae573b290e 100644
--- a/components/script/dom/mediastream.rs
+++ b/components/script/dom/mediastream.rs
@@ -3,38 +3,131 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::dom::bindings::cell::DomRefCell;
-use crate::dom::bindings::codegen::Bindings::MediaStreamBinding;
-use crate::dom::bindings::reflector::reflect_dom_object;
-use crate::dom::bindings::root::DomRoot;
+use crate::dom::bindings::codegen::Bindings::MediaStreamBinding::{self, MediaStreamMethods};
+use crate::dom::bindings::error::Fallible;
+use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
+use crate::dom::bindings::root::{Dom, DomRoot};
+use crate::dom::bindings::str::DOMString;
use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
+use crate::dom::mediastreamtrack::MediaStreamTrack;
+use crate::dom::window::Window;
use dom_struct::dom_struct;
-use servo_media::streams::registry::MediaStreamId;
+use servo_media::streams::MediaStreamType;
+use std::cell::Ref;
#[dom_struct]
pub struct MediaStream {
eventtarget: EventTarget,
- #[ignore_malloc_size_of = "defined in servo-media"]
- tracks: DomRefCell<Vec<MediaStreamId>>,
+ tracks: DomRefCell<Vec<Dom<MediaStreamTrack>>>,
}
impl MediaStream {
- pub fn new_inherited(tracks: Vec<MediaStreamId>) -> MediaStream {
+ pub fn new_inherited() -> MediaStream {
MediaStream {
eventtarget: EventTarget::new_inherited(),
- tracks: DomRefCell::new(tracks),
+ tracks: DomRefCell::new(vec![]),
}
}
- pub fn new(global: &GlobalScope, tracks: Vec<MediaStreamId>) -> DomRoot<MediaStream> {
+ pub fn new(global: &GlobalScope) -> DomRoot<MediaStream> {
reflect_dom_object(
- Box::new(MediaStream::new_inherited(tracks)),
+ Box::new(MediaStream::new_inherited()),
global,
MediaStreamBinding::Wrap,
)
}
- pub fn get_tracks(&self) -> Vec<MediaStreamId> {
- self.tracks.borrow_mut().clone()
+ pub fn Constructor(global: &Window) -> Fallible<DomRoot<MediaStream>> {
+ Ok(MediaStream::new(&global.global()))
+ }
+
+ pub fn Constructor_(_: &Window, stream: &MediaStream) -> Fallible<DomRoot<MediaStream>> {
+ Ok(stream.Clone())
+ }
+
+ pub fn Constructor__(
+ global: &Window,
+ tracks: Vec<DomRoot<MediaStreamTrack>>,
+ ) -> Fallible<DomRoot<MediaStream>> {
+ let new = MediaStream::new(&global.global());
+ for track in tracks {
+ // this is quadratic, but shouldn't matter much
+ // if this becomes a problem we can use a hash map
+ new.AddTrack(&track)
+ }
+ Ok(new)
+ }
+
+ pub fn get_tracks(&self) -> Ref<[Dom<MediaStreamTrack>]> {
+ Ref::map(self.tracks.borrow(), |tracks| &**tracks)
+ }
+
+ pub fn add_track(&self, track: &MediaStreamTrack) {
+ self.tracks.borrow_mut().push(Dom::from_ref(track))
+ }
+}
+
+impl MediaStreamMethods for MediaStream {
+ /// https://w3c.github.io/mediacapture-main/#dom-mediastream-gettracks
+ fn GetTracks(&self) -> Vec<DomRoot<MediaStreamTrack>> {
+ self.tracks
+ .borrow()
+ .iter()
+ .map(|x| DomRoot::from_ref(&**x))
+ .collect()
+ }
+
+ /// https://w3c.github.io/mediacapture-main/#dom-mediastream-getaudiotracks
+ fn GetAudioTracks(&self) -> Vec<DomRoot<MediaStreamTrack>> {
+ self.tracks
+ .borrow()
+ .iter()
+ .filter(|x| x.ty() == MediaStreamType::Audio)
+ .map(|x| DomRoot::from_ref(&**x))
+ .collect()
+ }
+
+ /// https://w3c.github.io/mediacapture-main/#dom-mediastream-getvideotracks
+ fn GetVideoTracks(&self) -> Vec<DomRoot<MediaStreamTrack>> {
+ self.tracks
+ .borrow()
+ .iter()
+ .filter(|x| x.ty() == MediaStreamType::Video)
+ .map(|x| DomRoot::from_ref(&**x))
+ .collect()
+ }
+
+ /// https://w3c.github.io/mediacapture-main/#dom-mediastream-gettrackbyid
+ fn GetTrackById(&self, id: DOMString) -> Option<DomRoot<MediaStreamTrack>> {
+ self.tracks
+ .borrow()
+ .iter()
+ .find(|x| x.id().id().to_string() == &*id)
+ .map(|x| DomRoot::from_ref(&**x))
+ }
+
+ /// https://w3c.github.io/mediacapture-main/#dom-mediastream-addtrack
+ fn AddTrack(&self, track: &MediaStreamTrack) {
+ let existing = self.tracks.borrow().iter().find(|x| *x == &track).is_some();
+
+ if existing {
+ return;
+ }
+ self.add_track(track)
+ }
+
+ /// https://w3c.github.io/mediacapture-main/#dom-mediastream-removetrack
+ fn RemoveTrack(&self, track: &MediaStreamTrack) {
+ self.tracks.borrow_mut().retain(|x| *x != track);
+ }
+
+ /// https://w3c.github.io/mediacapture-main/#dom-mediastream-clone
+ fn Clone(&self) -> DomRoot<MediaStream> {
+ let new = MediaStream::new(&self.global());
+ for track in &*self.tracks.borrow() {
+ new.add_track(&track)
+ }
+ new
}
}
diff --git a/components/script/dom/mediastreamtrack.rs b/components/script/dom/mediastreamtrack.rs
new file mode 100644
index 00000000000..2cc0bde7442
--- /dev/null
+++ b/components/script/dom/mediastreamtrack.rs
@@ -0,0 +1,74 @@
+/* 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::MediaStreamTrackBinding::{
+ self, MediaStreamTrackMethods,
+};
+use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
+use crate::dom::bindings::root::DomRoot;
+use crate::dom::bindings::str::DOMString;
+use crate::dom::eventtarget::EventTarget;
+use crate::dom::globalscope::GlobalScope;
+use dom_struct::dom_struct;
+use servo_media::streams::registry::MediaStreamId;
+use servo_media::streams::MediaStreamType;
+
+#[dom_struct]
+pub struct MediaStreamTrack {
+ eventtarget: EventTarget,
+ #[ignore_malloc_size_of = "defined in servo-media"]
+ id: MediaStreamId,
+ #[ignore_malloc_size_of = "defined in servo-media"]
+ ty: MediaStreamType,
+}
+
+impl MediaStreamTrack {
+ pub fn new_inherited(id: MediaStreamId, ty: MediaStreamType) -> MediaStreamTrack {
+ MediaStreamTrack {
+ eventtarget: EventTarget::new_inherited(),
+ id,
+ ty,
+ }
+ }
+
+ pub fn new(
+ global: &GlobalScope,
+ id: MediaStreamId,
+ ty: MediaStreamType,
+ ) -> DomRoot<MediaStreamTrack> {
+ reflect_dom_object(
+ Box::new(MediaStreamTrack::new_inherited(id, ty)),
+ global,
+ MediaStreamTrackBinding::Wrap,
+ )
+ }
+
+ pub fn id(&self) -> MediaStreamId {
+ self.id
+ }
+
+ pub fn ty(&self) -> MediaStreamType {
+ self.ty
+ }
+}
+
+impl MediaStreamTrackMethods for MediaStreamTrack {
+ /// https://w3c.github.io/mediacapture-main/#dom-mediastreamtrack-kind
+ fn Kind(&self) -> DOMString {
+ match self.ty {
+ MediaStreamType::Video => "video".into(),
+ MediaStreamType::Audio => "audio".into(),
+ }
+ }
+
+ /// https://w3c.github.io/mediacapture-main/#dom-mediastreamtrack-id
+ fn Id(&self) -> DOMString {
+ self.id.id().to_string().into()
+ }
+
+ /// https://w3c.github.io/mediacapture-main/#dom-mediastreamtrack-clone
+ fn Clone(&self) -> DomRoot<MediaStreamTrack> {
+ MediaStreamTrack::new(&self.global(), self.id, self.ty)
+ }
+}
diff --git a/components/script/dom/messageevent.rs b/components/script/dom/messageevent.rs
index edde48f95e6..c02df1e8e61 100644
--- a/components/script/dom/messageevent.rs
+++ b/components/script/dom/messageevent.rs
@@ -25,6 +25,7 @@ use std::ptr::NonNull;
#[dom_struct]
pub struct MessageEvent {
event: Event,
+ #[ignore_malloc_size_of = "mozjs"]
data: Heap<JSVal>,
origin: DOMString,
source: Option<Dom<WindowProxy>>,
diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs
index ff1688fb6c3..1dbc1383101 100644
--- a/components/script/dom/mod.rs
+++ b/components/script/dom/mod.rs
@@ -399,6 +399,7 @@ pub mod medialist;
pub mod mediaquerylist;
pub mod mediaquerylistevent;
pub mod mediastream;
+pub mod mediastreamtrack;
pub mod messageevent;
pub mod mimetype;
pub mod mimetypearray;
@@ -450,6 +451,7 @@ pub mod rtcicecandidate;
pub mod rtcpeerconnection;
pub mod rtcpeerconnectioniceevent;
pub mod rtcsessiondescription;
+pub mod rtctrackevent;
pub mod screen;
pub mod serviceworker;
pub mod serviceworkercontainer;
@@ -540,6 +542,7 @@ pub mod xmlhttprequestupload;
pub mod xmlserializer;
pub mod xr;
pub mod xrframe;
+pub mod xrinputsource;
pub mod xrlayer;
pub mod xrpose;
pub mod xrreferencespace;
diff --git a/components/script/dom/paintworkletglobalscope.rs b/components/script/dom/paintworkletglobalscope.rs
index fe119eefbf3..89b9907c95c 100644
--- a/components/script/dom/paintworkletglobalscope.rs
+++ b/components/script/dom/paintworkletglobalscope.rs
@@ -76,6 +76,7 @@ pub struct PaintWorkletGlobalScope {
/// <https://drafts.css-houdini.org/css-paint-api/#paint-definitions>
paint_definitions: DomRefCell<HashMap<Atom, Box<PaintDefinition>>>,
/// <https://drafts.css-houdini.org/css-paint-api/#paint-class-instances>
+ #[ignore_malloc_size_of = "mozjs"]
paint_class_instances: DomRefCell<HashMap<Atom, Box<Heap<JSVal>>>>,
/// The most recent name the worklet was called with
cached_name: DomRefCell<Atom>,
@@ -473,7 +474,9 @@ pub enum PaintWorkletTask {
#[derive(JSTraceable, MallocSizeOf)]
#[must_root]
struct PaintDefinition {
+ #[ignore_malloc_size_of = "mozjs"]
class_constructor: Heap<JSVal>,
+ #[ignore_malloc_size_of = "mozjs"]
paint_function: Heap<JSVal>,
constructor_valid_flag: Cell<bool>,
context_alpha_flag: bool,
diff --git a/components/script/dom/rtcpeerconnection.rs b/components/script/dom/rtcpeerconnection.rs
index 962eb0fb02c..9ec1940bbb3 100644
--- a/components/script/dom/rtcpeerconnection.rs
+++ b/components/script/dom/rtcpeerconnection.rs
@@ -26,10 +26,12 @@ use crate::dom::event::{Event, EventBubbles, EventCancelable};
use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
use crate::dom::mediastream::MediaStream;
+use crate::dom::mediastreamtrack::MediaStreamTrack;
use crate::dom::promise::Promise;
use crate::dom::rtcicecandidate::RTCIceCandidate;
use crate::dom::rtcpeerconnectioniceevent::RTCPeerConnectionIceEvent;
use crate::dom::rtcsessiondescription::RTCSessionDescription;
+use crate::dom::rtctrackevent::RTCTrackEvent;
use crate::dom::window::Window;
use crate::task::TaskCanceller;
use crate::task_source::networking::NetworkingTaskSource;
@@ -37,6 +39,7 @@ use crate::task_source::TaskSource;
use dom_struct::dom_struct;
use servo_media::streams::registry::MediaStreamId;
+use servo_media::streams::MediaStreamType;
use servo_media::webrtc::{
BundlePolicy, GatheringState, IceCandidate, IceConnectionState, SdpType, SessionDescription,
SignalingState, WebRtcController, WebRtcSignaller,
@@ -128,7 +131,17 @@ impl WebRtcSignaller for RTCSignaller {
);
}
- fn on_add_stream(&self, _: &MediaStreamId) {}
+ fn on_add_stream(&self, id: &MediaStreamId, ty: MediaStreamType) {
+ let this = self.trusted.clone();
+ let id = *id;
+ let _ = self.task_source.queue_with_canceller(
+ task!(on_add_stream: move || {
+ let this = this.root();
+ this.on_add_stream(id, ty);
+ }),
+ &self.canceller,
+ );
+ }
fn close(&self) {
// do nothing
@@ -238,6 +251,15 @@ impl RTCPeerConnection {
event.upcast::<Event>().fire(self.upcast());
}
+ fn on_add_stream(&self, id: MediaStreamId, ty: MediaStreamType) {
+ if self.closed.get() {
+ return;
+ }
+ let track = MediaStreamTrack::new(&self.global(), id, ty);
+ let event = RTCTrackEvent::new(&self.global(), atom!("track"), false, false, &track);
+ event.upcast::<Event>().fire(self.upcast());
+ }
+
/// https://www.w3.org/TR/webrtc/#update-ice-gathering-state
fn update_gathering_state(&self, state: GatheringState) {
// step 1
@@ -399,6 +421,9 @@ impl RTCPeerConnectionMethods for RTCPeerConnection {
/// https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-icecandidate
event_handler!(icecandidate, GetOnicecandidate, SetOnicecandidate);
+ /// https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-ontrack
+ event_handler!(track, GetOntrack, SetOntrack);
+
/// https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-iceconnectionstatechange
event_handler!(
iceconnectionstatechange,
@@ -584,10 +609,12 @@ impl RTCPeerConnectionMethods for RTCPeerConnection {
// https://w3c.github.io/webrtc-pc/#legacy-interface-extensions
fn AddStream(&self, stream: &MediaStream) {
- let mut tracks = stream.get_tracks();
-
- for ref track in tracks.drain(..) {
- self.controller.borrow().as_ref().unwrap().add_stream(track);
+ for track in &*stream.get_tracks() {
+ self.controller
+ .borrow()
+ .as_ref()
+ .unwrap()
+ .add_stream(&track.id());
}
}
diff --git a/components/script/dom/rtctrackevent.rs b/components/script/dom/rtctrackevent.rs
new file mode 100644
index 00000000000..9c5d7bec362
--- /dev/null
+++ b/components/script/dom/rtctrackevent.rs
@@ -0,0 +1,78 @@
+/* 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::RTCTrackEventBinding::{self, RTCTrackEventMethods};
+use crate::dom::bindings::error::Fallible;
+use crate::dom::bindings::inheritance::Castable;
+use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
+use crate::dom::bindings::root::{Dom, DomRoot};
+use crate::dom::bindings::str::DOMString;
+use crate::dom::event::Event;
+use crate::dom::globalscope::GlobalScope;
+use crate::dom::mediastreamtrack::MediaStreamTrack;
+use crate::dom::window::Window;
+use dom_struct::dom_struct;
+use servo_atoms::Atom;
+
+#[dom_struct]
+pub struct RTCTrackEvent {
+ event: Event,
+ track: Dom<MediaStreamTrack>,
+}
+
+impl RTCTrackEvent {
+ #[allow(unrooted_must_root)]
+ fn new_inherited(track: &MediaStreamTrack) -> RTCTrackEvent {
+ RTCTrackEvent {
+ event: Event::new_inherited(),
+ track: Dom::from_ref(track),
+ }
+ }
+
+ pub fn new(
+ global: &GlobalScope,
+ type_: Atom,
+ bubbles: bool,
+ cancelable: bool,
+ track: &MediaStreamTrack,
+ ) -> DomRoot<RTCTrackEvent> {
+ let trackevent = reflect_dom_object(
+ Box::new(RTCTrackEvent::new_inherited(&track)),
+ global,
+ RTCTrackEventBinding::Wrap,
+ );
+ {
+ let event = trackevent.upcast::<Event>();
+ event.init_event(type_, bubbles, cancelable);
+ }
+ trackevent
+ }
+
+ pub fn Constructor(
+ window: &Window,
+ type_: DOMString,
+ init: &RTCTrackEventBinding::RTCTrackEventInit,
+ ) -> Fallible<DomRoot<RTCTrackEvent>> {
+ Ok(RTCTrackEvent::new(
+ &window.global(),
+ Atom::from(type_),
+ init.parent.bubbles,
+ init.parent.cancelable,
+ &init.track,
+ ))
+ }
+}
+
+impl RTCTrackEventMethods for RTCTrackEvent {
+ // https://w3c.github.io/webrtc-pc/#dom-rtctrackevent-track
+ fn Track(&self) -> DomRoot<MediaStreamTrack> {
+ DomRoot::from_ref(&*self.track)
+ }
+
+ // https://dom.spec.whatwg.org/#dom-event-istrusted
+ fn IsTrusted(&self) -> bool {
+ self.event.IsTrusted()
+ }
+}
diff --git a/components/script/dom/vrdisplay.rs b/components/script/dom/vrdisplay.rs
index a8cb594a2b1..77817bae2fc 100644
--- a/components/script/dom/vrdisplay.rs
+++ b/components/script/dom/vrdisplay.rs
@@ -22,7 +22,7 @@ use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::num::Finite;
use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
-use crate::dom::bindings::root::{DomRoot, MutDom, MutNullableDom};
+use crate::dom::bindings::root::{Dom, DomRoot, MutDom, MutNullableDom};
use crate::dom::bindings::str::DOMString;
use crate::dom::event::Event;
use crate::dom::eventtarget::EventTarget;
@@ -36,6 +36,7 @@ use crate::dom::vrpose::VRPose;
use crate::dom::vrstageparameters::VRStageParameters;
use crate::dom::webglrenderingcontext::WebGLRenderingContext;
use crate::dom::xrframe::XRFrame;
+use crate::dom::xrinputsource::XRInputSource;
use crate::dom::xrsession::XRSession;
use crate::dom::xrwebgllayer::XRWebGLLayer;
use crate::script_runtime::CommonScriptMsg;
@@ -47,11 +48,12 @@ use dom_struct::dom_struct;
use ipc_channel::ipc::IpcSender;
use profile_traits::ipc;
use std::cell::Cell;
+use std::collections::HashMap;
use std::mem;
use std::ops::Deref;
use std::rc::Rc;
use std::thread;
-use webvr_traits::{WebVRDisplayData, WebVRDisplayEvent, WebVRFrameData, WebVRFutureFrameData};
+use webvr_traits::{WebVRDisplayData, WebVRDisplayEvent, WebVRFrameData, WebVRPoseInformation};
use webvr_traits::{WebVRLayer, WebVRMsg};
#[dom_struct]
@@ -86,12 +88,16 @@ pub struct VRDisplay {
// Compositor VRFrameData synchonization
frame_data_status: Cell<VRFrameDataStatus>,
#[ignore_malloc_size_of = "closures are hard"]
- frame_data_receiver: DomRefCell<Option<WebGLReceiver<Result<WebVRFutureFrameData, ()>>>>,
+ frame_data_receiver: DomRefCell<Option<WebGLReceiver<Result<WebVRPoseInformation, ()>>>>,
running_display_raf: Cell<bool>,
paused: Cell<bool>,
stopped_on_pause: Cell<bool>,
/// Whether or not this is XR mode, and the session
xr_session: MutNullableDom<XRSession>,
+ /// Have inputs been initialized? (i.e, has getInputSources() been called?)
+ /// XR only
+ initialized_inputs: Cell<bool>,
+ input_sources: DomRefCell<HashMap<u32, Dom<XRInputSource>>>,
}
unsafe_no_jsmanaged_fields!(WebVRDisplayData);
@@ -115,6 +121,8 @@ struct VRRAFUpdate {
/// Number uniquely identifying the WebGL context
/// so that we may setup/tear down VR compositors as things change
context_id: usize,
+ /// Do we need input data?
+ needs_inputs: bool,
}
type VRRAFUpdateSender = Sender<Result<VRRAFUpdate, ()>>;
@@ -164,6 +172,8 @@ impl VRDisplay {
// When the VR Resume event is received and the flag is set, VR presentation automatically restarts.
stopped_on_pause: Cell::new(false),
xr_session: MutNullableDom::default(),
+ initialized_inputs: Cell::new(false),
+ input_sources: DomRefCell::new(HashMap::new()),
}
}
@@ -627,6 +637,7 @@ impl VRDisplay {
depth_far: self.depth_far.get(),
api_sender: self.api_sender(),
context_id: self.context_id(),
+ needs_inputs: self.initialized_inputs.get(),
}
}
@@ -690,6 +701,7 @@ impl VRDisplay {
let (raf_sender, raf_receiver) = unbounded();
let (wakeup_sender, wakeup_receiver) = unbounded();
*self.raf_wakeup_sender.borrow_mut() = Some(wakeup_sender);
+ let mut needs_inputs = false;
// The render loop at native headset frame rate is implemented using a dedicated thread.
// Every loop iteration syncs pose data with the HMD, submits the pixels to the display and waits for Vsync.
@@ -726,8 +738,13 @@ impl VRDisplay {
.unwrap();
// Run Sync Poses in parallell on Render thread
- let msg =
- WebVRCommand::SyncPoses(display_id, near, far, sync_sender.clone());
+ let msg = WebVRCommand::SyncPoses(
+ display_id,
+ near,
+ far,
+ needs_inputs,
+ sync_sender.clone(),
+ );
api_sender.send_vr(msg).unwrap();
} else {
let _ = wakeup_receiver.recv();
@@ -752,6 +769,7 @@ impl VRDisplay {
if let Ok(update) = raf_receiver.recv().unwrap() {
near = update.depth_near;
far = update.depth_far;
+ needs_inputs = update.needs_inputs;
if update.context_id != context_id {
if let Some(ref api_sender) = update.api_sender {
api_sender
@@ -808,8 +826,16 @@ impl VRDisplay {
fn sync_frame_data(&self) {
let status = if let Some(receiver) = self.frame_data_receiver.borrow().as_ref() {
match receiver.recv().unwrap() {
- Ok(future_data) => {
- *self.frame_data.borrow_mut() = future_data.block();
+ Ok(pose) => {
+ *self.frame_data.borrow_mut() = pose.frame.block();
+ if self.initialized_inputs.get() {
+ let inputs = self.input_sources.borrow();
+ for (id, state) in pose.gamepads {
+ if let Some(input) = inputs.get(&id) {
+ input.update_state(state);
+ }
+ }
+ }
VRFrameDataStatus::Synced
},
Err(()) => VRFrameDataStatus::Exit,
@@ -909,6 +935,53 @@ impl VRDisplay {
pair.1 = None;
}
}
+
+ /// Initialize XRInputSources
+ fn initialize_inputs(&self) {
+ if self.initialized_inputs.get() {
+ return;
+ }
+ self.initialized_inputs.set(true);
+
+ let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
+ let display = self.display.borrow().display_id;
+ self.webvr_thread()
+ .send(WebVRMsg::GetGamepadsForDisplay(display, sender))
+ .unwrap();
+ match receiver.recv().unwrap() {
+ Ok(gamepads) => {
+ let global = self.global();
+ let session = self
+ .xr_session
+ .get()
+ .expect("initialize_inputs called on a VR session");
+ let roots: Vec<_> = gamepads
+ .into_iter()
+ .map(|g| {
+ (
+ g.1.gamepad_id,
+ XRInputSource::new(&global, &session, g.0, g.1),
+ )
+ })
+ .collect();
+
+ let mut inputs = self.input_sources.borrow_mut();
+ for (id, root) in &roots {
+ inputs.insert(*id, Dom::from_ref(&root));
+ }
+ },
+ Err(_) => {},
+ }
+ }
+
+ pub fn get_input_sources(&self) -> Vec<DomRoot<XRInputSource>> {
+ self.initialize_inputs();
+ self.input_sources
+ .borrow()
+ .iter()
+ .map(|(_, x)| DomRoot::from_ref(&**x))
+ .collect()
+ }
}
// WebVR Spec: If the number of values in the leftBounds/rightBounds arrays
diff --git a/components/script/dom/vreyeparameters.rs b/components/script/dom/vreyeparameters.rs
index 2a212ab48bc..b7ea63bbd3e 100644
--- a/components/script/dom/vreyeparameters.rs
+++ b/components/script/dom/vreyeparameters.rs
@@ -22,6 +22,7 @@ pub struct VREyeParameters {
reflector_: Reflector,
#[ignore_malloc_size_of = "Defined in rust-webvr"]
parameters: DomRefCell<WebVREyeParameters>,
+ #[ignore_malloc_size_of = "mozjs"]
offset: Heap<*mut JSObject>,
fov: Dom<VRFieldOfView>,
}
diff --git a/components/script/dom/vrframedata.rs b/components/script/dom/vrframedata.rs
index 08acd74bb42..25f6af821a7 100644
--- a/components/script/dom/vrframedata.rs
+++ b/components/script/dom/vrframedata.rs
@@ -22,9 +22,13 @@ use webvr_traits::WebVRFrameData;
#[dom_struct]
pub struct VRFrameData {
reflector_: Reflector,
+ #[ignore_malloc_size_of = "mozjs"]
left_proj: Heap<*mut JSObject>,
+ #[ignore_malloc_size_of = "mozjs"]
left_view: Heap<*mut JSObject>,
+ #[ignore_malloc_size_of = "mozjs"]
right_proj: Heap<*mut JSObject>,
+ #[ignore_malloc_size_of = "mozjs"]
right_view: Heap<*mut JSObject>,
pose: Dom<VRPose>,
timestamp: Cell<f64>,
diff --git a/components/script/dom/vrpose.rs b/components/script/dom/vrpose.rs
index c807ab72c91..90bca0956ee 100644
--- a/components/script/dom/vrpose.rs
+++ b/components/script/dom/vrpose.rs
@@ -17,11 +17,17 @@ use webvr_traits::webvr;
#[dom_struct]
pub struct VRPose {
reflector_: Reflector,
+ #[ignore_malloc_size_of = "mozjs"]
position: Heap<*mut JSObject>,
+ #[ignore_malloc_size_of = "mozjs"]
orientation: Heap<*mut JSObject>,
+ #[ignore_malloc_size_of = "mozjs"]
linear_vel: Heap<*mut JSObject>,
+ #[ignore_malloc_size_of = "mozjs"]
angular_vel: Heap<*mut JSObject>,
+ #[ignore_malloc_size_of = "mozjs"]
linear_acc: Heap<*mut JSObject>,
+ #[ignore_malloc_size_of = "mozjs"]
angular_acc: Heap<*mut JSObject>,
}
diff --git a/components/script/dom/vrstageparameters.rs b/components/script/dom/vrstageparameters.rs
index ffbe6ce0f3f..41184091232 100644
--- a/components/script/dom/vrstageparameters.rs
+++ b/components/script/dom/vrstageparameters.rs
@@ -21,6 +21,7 @@ pub struct VRStageParameters {
reflector_: Reflector,
#[ignore_malloc_size_of = "Defined in rust-webvr"]
parameters: DomRefCell<WebVRStageParameters>,
+ #[ignore_malloc_size_of = "mozjs"]
transform: Heap<*mut JSObject>,
}
diff --git a/components/script/dom/webidls/MediaStream.webidl b/components/script/dom/webidls/MediaStream.webidl
index 0257e3c6061..b1d5664a7f7 100644
--- a/components/script/dom/webidls/MediaStream.webidl
+++ b/components/script/dom/webidls/MediaStream.webidl
@@ -4,20 +4,20 @@
// https://w3c.github.io/mediacapture-main/#dom-mediastream
-// [Exposed=Window,
-// Constructor,
-// Constructor(MediaStream stream),
-// Constructor(sequence<MediaStreamTrack> tracks)]
-[Exposed=Window, Pref="dom.webrtc.enabled"]
+[Exposed=Window,
+ Constructor,
+ Constructor(MediaStream stream),
+ Constructor(sequence<MediaStreamTrack> tracks),
+Pref="dom.webrtc.enabled"]
interface MediaStream : EventTarget {
// readonly attribute DOMString id;
- // sequence<MediaStreamTrack> getAudioTracks();
- // sequence<MediaStreamTrack> getVideoTracks();
- // sequence<MediaStreamTrack> getTracks();
- // MediaStreamTrack? getTrackById(DOMString trackId);
- // void addTrack(MediaStreamTrack track);
- // void removeTrack(MediaStreamTrack track);
- // MediaStream clone();
+ sequence<MediaStreamTrack> getAudioTracks();
+ sequence<MediaStreamTrack> getVideoTracks();
+ sequence<MediaStreamTrack> getTracks();
+ MediaStreamTrack? getTrackById(DOMString trackId);
+ void addTrack(MediaStreamTrack track);
+ void removeTrack(MediaStreamTrack track);
+ MediaStream clone();
// readonly attribute boolean active;
// attribute EventHandler onaddtrack;
// attribute EventHandler onremovetrack;
diff --git a/components/script/dom/webidls/MediaStreamTrack.webidl b/components/script/dom/webidls/MediaStreamTrack.webidl
new file mode 100644
index 00000000000..2f8bfb0bbec
--- /dev/null
+++ b/components/script/dom/webidls/MediaStreamTrack.webidl
@@ -0,0 +1,24 @@
+/* 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/. */
+
+// https://w3c.github.io/mediacapture-main/#dom-mediastreamtrack
+
+[Exposed=Window, Pref="dom.webrtc.enabled"]
+interface MediaStreamTrack : EventTarget {
+ readonly attribute DOMString kind;
+ readonly attribute DOMString id;
+ // readonly attribute DOMString label;
+ // attribute boolean enabled;
+ // readonly attribute boolean muted;
+ // attribute EventHandler onmute;
+ // attribute EventHandler onunmute;
+ // readonly attribute MediaStreamTrackState readyState;
+ // attribute EventHandler onended;
+ MediaStreamTrack clone();
+ // void stop();
+ // MediaTrackCapabilities getCapabilities();
+ // MediaTrackConstraints getConstraints();
+ // MediaTrackSettings getSettings();
+ // Promise<void> applyConstraints(optional MediaTrackConstraints constraints);
+};
diff --git a/components/script/dom/webidls/RTCPeerConnection.webidl b/components/script/dom/webidls/RTCPeerConnection.webidl
index 0f00f3b5b95..58cb7301ea3 100644
--- a/components/script/dom/webidls/RTCPeerConnection.webidl
+++ b/components/script/dom/webidls/RTCPeerConnection.webidl
@@ -114,3 +114,15 @@ enum RTCSignalingState {
"have-remote-pranswer",
"closed"
};
+
+partial interface RTCPeerConnection {
+ // sequence<RTCRtpSender> getSenders();
+ // sequence<RTCRtpReceiver> getReceivers();
+ // sequence<RTCRtpTransceiver> getTransceivers();
+ // RTCRtpSender addTrack(MediaStreamTrack track,
+ // MediaStream... streams);
+ // void removeTrack(RTCRtpSender sender);
+ // RTCRtpTransceiver addTransceiver((MediaStreamTrack or DOMString) trackOrKind,
+ // optional RTCRtpTransceiverInit init);
+ attribute EventHandler ontrack;
+};
diff --git a/components/script/dom/webidls/RTCTrackEvent.webidl b/components/script/dom/webidls/RTCTrackEvent.webidl
new file mode 100644
index 00000000000..fa07f36b9f5
--- /dev/null
+++ b/components/script/dom/webidls/RTCTrackEvent.webidl
@@ -0,0 +1,23 @@
+/* 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/. */
+
+// https://w3c.github.io/webrtc-pc/#dom-rtctrackevent
+
+[Constructor(DOMString type, RTCTrackEventInit eventInitDict),
+ Exposed=Window, Pref="dom.webrtc.enabled"]
+interface RTCTrackEvent : Event {
+ // readonly attribute RTCRtpReceiver receiver;
+ readonly attribute MediaStreamTrack track;
+ // [SameObject]
+ // readonly attribute FrozenArray<MediaStream> streams;
+ // readonly attribute RTCRtpTransceiver transceiver;
+};
+
+// https://www.w3.org/TR/webrtc/#dom-rtctrackeventinit
+dictionary RTCTrackEventInit : EventInit {
+ // required RTCRtpReceiver receiver;
+ required MediaStreamTrack track;
+ // sequence<MediaStream> streams = [];
+ // required RTCRtpTransceiver transceiver;
+};
diff --git a/components/script/dom/webidls/XRInputSource.webidl b/components/script/dom/webidls/XRInputSource.webidl
new file mode 100644
index 00000000000..5ad1e48628f
--- /dev/null
+++ b/components/script/dom/webidls/XRInputSource.webidl
@@ -0,0 +1,26 @@
+/* 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/. */
+
+// https://immersive-web.github.io/webxr/#xrinputsource-interface
+
+enum XRHandedness {
+ "none",
+ "left",
+ "right"
+};
+
+enum XRTargetRayMode {
+ "gaze",
+ "tracked-pointer",
+ "screen"
+};
+
+[SecureContext, Exposed=Window, Pref="dom.webxr.enabled"]
+interface XRInputSource {
+ readonly attribute XRHandedness handedness;
+ // [SameObject] readonly attribute XRTargetRayMode targetRayMode;
+ [SameObject] readonly attribute XRSpace targetRaySpace;
+ // [SameObject] readonly attribute XRSpace? gripSpace;
+ // [SameObject] readonly attribute Gamepad? gamepad;
+};
diff --git a/components/script/dom/webidls/XRSession.webidl b/components/script/dom/webidls/XRSession.webidl
index f22918d469d..0399f2d0bc1 100644
--- a/components/script/dom/webidls/XRSession.webidl
+++ b/components/script/dom/webidls/XRSession.webidl
@@ -20,12 +20,15 @@ interface XRSession : EventTarget {
readonly attribute XREnvironmentBlendMode environmentBlendMode;
readonly attribute XRRenderState renderState;
- readonly attribute XRSpace viewerSpace;
+ [SameObject] readonly attribute XRSpace viewerSpace;
// // Methods
Promise<XRReferenceSpace> requestReferenceSpace(XRReferenceSpaceOptions options);
+ // workaround until we have FrozenArray
+ // see https://github.com/servo/servo/issues/10427#issuecomment-449593626
// FrozenArray<XRInputSource> getInputSources();
+ sequence<XRInputSource> getInputSources();
Promise<void> updateRenderState(optional XRRenderStateInit state);
long requestAnimationFrame(XRFrameRequestCallback callback);
diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs
index 0b86f0eeb1c..3b9622b3cfb 100644
--- a/components/script/dom/xmlhttprequest.rs
+++ b/components/script/dom/xmlhttprequest.rs
@@ -137,6 +137,7 @@ pub struct XMLHttpRequest {
response_type: Cell<XMLHttpRequestResponseType>,
response_xml: MutNullableDom<Document>,
response_blob: MutNullableDom<Blob>,
+ #[ignore_malloc_size_of = "mozjs"]
response_arraybuffer: Heap<*mut JSObject>,
#[ignore_malloc_size_of = "Defined in rust-mozjs"]
response_json: Heap<JSVal>,
diff --git a/components/script/dom/xrinputsource.rs b/components/script/dom/xrinputsource.rs
new file mode 100644
index 00000000000..2b623864d56
--- /dev/null
+++ b/components/script/dom/xrinputsource.rs
@@ -0,0 +1,83 @@
+/* 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::cell::DomRefCell;
+use crate::dom::bindings::codegen::Bindings::XRInputSourceBinding;
+use crate::dom::bindings::codegen::Bindings::XRInputSourceBinding::{
+ XRHandedness, XRInputSourceMethods,
+};
+use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
+use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
+use crate::dom::globalscope::GlobalScope;
+use crate::dom::xrsession::XRSession;
+use crate::dom::xrspace::XRSpace;
+use dom_struct::dom_struct;
+use webvr_traits::{WebVRGamepadData, WebVRGamepadHand, WebVRGamepadState, WebVRPose};
+
+#[dom_struct]
+pub struct XRInputSource {
+ reflector: Reflector,
+ session: Dom<XRSession>,
+ #[ignore_malloc_size_of = "Defined in rust-webvr"]
+ data: WebVRGamepadData,
+ #[ignore_malloc_size_of = "Defined in rust-webvr"]
+ state: DomRefCell<WebVRGamepadState>,
+ target_ray_space: MutNullableDom<XRSpace>,
+}
+
+impl XRInputSource {
+ pub fn new_inherited(
+ session: &XRSession,
+ data: WebVRGamepadData,
+ state: WebVRGamepadState,
+ ) -> XRInputSource {
+ XRInputSource {
+ reflector: Reflector::new(),
+ session: Dom::from_ref(session),
+ data,
+ state: DomRefCell::new(state),
+ target_ray_space: Default::default(),
+ }
+ }
+
+ pub fn new(
+ global: &GlobalScope,
+ session: &XRSession,
+ data: WebVRGamepadData,
+ state: WebVRGamepadState,
+ ) -> DomRoot<XRInputSource> {
+ reflect_dom_object(
+ Box::new(XRInputSource::new_inherited(session, data, state)),
+ global,
+ XRInputSourceBinding::Wrap,
+ )
+ }
+
+ pub fn update_state(&self, state: WebVRGamepadState) {
+ *self.state.borrow_mut() = state;
+ }
+
+ pub fn pose(&self) -> WebVRPose {
+ self.state.borrow().pose
+ }
+}
+
+impl XRInputSourceMethods for XRInputSource {
+ /// https://immersive-web.github.io/webxr/#dom-xrinputsource-handedness
+ fn Handedness(&self) -> XRHandedness {
+ match self.data.hand {
+ WebVRGamepadHand::Unknown => XRHandedness::None,
+ WebVRGamepadHand::Left => XRHandedness::Left,
+ WebVRGamepadHand::Right => XRHandedness::Right,
+ }
+ }
+
+ /// https://immersive-web.github.io/webxr/#dom-xrinputsource-targetrayspace
+ fn TargetRaySpace(&self) -> DomRoot<XRSpace> {
+ self.target_ray_space.or_init(|| {
+ let global = self.global();
+ XRSpace::new_inputspace(&global, &self.session, &self)
+ })
+ }
+}
diff --git a/components/script/dom/xrreferencespace.rs b/components/script/dom/xrreferencespace.rs
index 664dc4f0e23..932f917b5a5 100644
--- a/components/script/dom/xrreferencespace.rs
+++ b/components/script/dom/xrreferencespace.rs
@@ -110,7 +110,7 @@ impl XRReferenceSpace {
// non-subclassed XRReferenceSpaces exist, obtained via the "identity"
// type. These are equivalent to the viewer pose and follow the headset
// around
- XRSpace::viewer_pose_from_frame_data(base_pose)
+ XRSpace::pose_to_transform(&base_pose.pose)
}
}
}
diff --git a/components/script/dom/xrrigidtransform.rs b/components/script/dom/xrrigidtransform.rs
index 969ec839292..f75d3f085fb 100644
--- a/components/script/dom/xrrigidtransform.rs
+++ b/components/script/dom/xrrigidtransform.rs
@@ -27,6 +27,7 @@ pub struct XRRigidTransform {
#[ignore_malloc_size_of = "defined in euclid"]
transform: RigidTransform3D<f64>,
inverse: MutNullableDom<XRRigidTransform>,
+ #[ignore_malloc_size_of = "defined in mozjs"]
matrix: Heap<*mut JSObject>,
}
@@ -93,7 +94,7 @@ impl XRRigidTransformMethods for XRRigidTransform {
}
// https://immersive-web.github.io/webxr/#dom-xrrigidtransform-orientation
fn Orientation(&self) -> DomRoot<DOMPointReadOnly> {
- self.position.or_init(|| {
+ self.orientation.or_init(|| {
let r = &self.transform.rotation;
DOMPointReadOnly::new(&self.global(), r.i, r.j, r.k, r.r)
})
diff --git a/components/script/dom/xrsession.rs b/components/script/dom/xrsession.rs
index 4b855cba4c8..5aab6341ca4 100644
--- a/components/script/dom/xrsession.rs
+++ b/components/script/dom/xrsession.rs
@@ -19,6 +19,7 @@ use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
use crate::dom::promise::Promise;
use crate::dom::vrdisplay::VRDisplay;
+use crate::dom::xrinputsource::XRInputSource;
use crate::dom::xrlayer::XRLayer;
use crate::dom::xrreferencespace::XRReferenceSpace;
use crate::dom::xrrenderstate::XRRenderState;
@@ -33,6 +34,7 @@ pub struct XRSession {
display: Dom<VRDisplay>,
base_layer: MutNullableDom<XRLayer>,
blend_mode: XREnvironmentBlendMode,
+ viewer_space: MutNullableDom<XRSpace>,
}
impl XRSession {
@@ -43,6 +45,7 @@ impl XRSession {
base_layer: Default::default(),
// we don't yet support any AR devices
blend_mode: XREnvironmentBlendMode::Opaque,
+ viewer_space: Default::default(),
}
}
@@ -86,7 +89,8 @@ impl XRSessionMethods for XRSession {
// https://immersive-web.github.io/webxr/#dom-xrsession-viewerspace
fn ViewerSpace(&self) -> DomRoot<XRSpace> {
- XRSpace::new_viewerspace(&self.global(), &self)
+ self.viewer_space
+ .or_init(|| XRSpace::new_viewerspace(&self.global(), &self))
}
/// https://immersive-web.github.io/webxr/#dom-xrsession-requestanimationframe
@@ -153,4 +157,9 @@ impl XRSessionMethods for XRSession {
p
}
+
+ /// https://immersive-web.github.io/webxr/#dom-xrsession-getinputsources
+ fn GetInputSources(&self) -> Vec<DomRoot<XRInputSource>> {
+ self.display.get_input_sources()
+ }
}
diff --git a/components/script/dom/xrspace.rs b/components/script/dom/xrspace.rs
index 8948ac03c8e..30f9246c354 100644
--- a/components/script/dom/xrspace.rs
+++ b/components/script/dom/xrspace.rs
@@ -5,20 +5,22 @@
use crate::dom::bindings::codegen::Bindings::XRSpaceBinding;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::reflector::reflect_dom_object;
-use crate::dom::bindings::root::{Dom, DomRoot};
+use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
+use crate::dom::xrinputsource::XRInputSource;
use crate::dom::xrreferencespace::XRReferenceSpace;
use crate::dom::xrsession::XRSession;
use dom_struct::dom_struct;
use euclid::{RigidTransform3D, Rotation3D, Vector3D};
-use webvr_traits::WebVRFrameData;
+use webvr_traits::{WebVRFrameData, WebVRPose};
#[dom_struct]
pub struct XRSpace {
eventtarget: EventTarget,
session: Dom<XRSession>,
is_viewerspace: bool,
+ input_source: MutNullableDom<XRInputSource>,
}
impl XRSpace {
@@ -27,6 +29,7 @@ impl XRSpace {
eventtarget: EventTarget::new_inherited(),
session: Dom::from_ref(session),
is_viewerspace: false,
+ input_source: Default::default(),
}
}
@@ -35,6 +38,7 @@ impl XRSpace {
eventtarget: EventTarget::new_inherited(),
session: Dom::from_ref(session),
is_viewerspace: true,
+ input_source: Default::default(),
}
}
@@ -45,6 +49,27 @@ impl XRSpace {
XRSpaceBinding::Wrap,
)
}
+
+ fn new_inputspace_inner(session: &XRSession, input: &XRInputSource) -> XRSpace {
+ XRSpace {
+ eventtarget: EventTarget::new_inherited(),
+ session: Dom::from_ref(session),
+ is_viewerspace: false,
+ input_source: MutNullableDom::new(Some(input)),
+ }
+ }
+
+ pub fn new_inputspace(
+ global: &GlobalScope,
+ session: &XRSession,
+ input: &XRInputSource,
+ ) -> DomRoot<XRSpace> {
+ reflect_dom_object(
+ Box::new(XRSpace::new_inputspace_inner(session, input)),
+ global,
+ XRSpaceBinding::Wrap,
+ )
+ }
}
impl XRSpace {
@@ -57,16 +82,18 @@ impl XRSpace {
if let Some(reference) = self.downcast::<XRReferenceSpace>() {
reference.get_pose(base_pose)
} else if self.is_viewerspace {
- XRSpace::viewer_pose_from_frame_data(base_pose)
+ XRSpace::pose_to_transform(&base_pose.pose)
+ } else if let Some(source) = self.input_source.get() {
+ XRSpace::pose_to_transform(&source.pose())
} else {
unreachable!()
}
}
- pub fn viewer_pose_from_frame_data(data: &WebVRFrameData) -> RigidTransform3D<f64> {
- let pos = data.pose.position.unwrap_or([0., 0., 0.]);
+ pub fn pose_to_transform(pose: &WebVRPose) -> RigidTransform3D<f64> {
+ let pos = pose.position.unwrap_or([0., 0., 0.]);
let translation = Vector3D::new(pos[0] as f64, pos[1] as f64, pos[2] as f64);
- let orient = data.pose.orientation.unwrap_or([0., 0., 0., 0.]);
+ let orient = pose.orientation.unwrap_or([0., 0., 0., 0.]);
let rotation = Rotation3D::quaternion(
orient[0] as f64,
orient[1] as f64,
diff --git a/components/script/dom/xrstationaryreferencespace.rs b/components/script/dom/xrstationaryreferencespace.rs
index a867aa0d976..65a0aebb790 100644
--- a/components/script/dom/xrstationaryreferencespace.rs
+++ b/components/script/dom/xrstationaryreferencespace.rs
@@ -55,7 +55,7 @@ impl XRStationaryReferenceSpace {
///
/// Does not apply originOffset, use get_viewer_pose on XRReferenceSpace instead
pub fn get_unoffset_viewer_pose(&self, viewer_pose: &WebVRFrameData) -> RigidTransform3D<f64> {
- let viewer_pose = XRSpace::viewer_pose_from_frame_data(viewer_pose);
+ let viewer_pose = XRSpace::pose_to_transform(&viewer_pose.pose);
// all math is in column-vector notation
// we use the following equation to verify correctness here:
// get_viewer_pose(space) = get_pose(space).inverse() * get_pose(viewer_space)
@@ -113,7 +113,7 @@ impl XRStationaryReferenceSpace {
},
XRStationaryReferenceSpaceSubtype::Position_disabled => {
// This space follows the user around, but does not mirror the user's orientation
- let viewer_pose = XRSpace::viewer_pose_from_frame_data(viewer_pose);
+ let viewer_pose = XRSpace::pose_to_transform(&viewer_pose.pose);
viewer_pose.translation.into()
},
}
diff --git a/components/script/dom/xrview.rs b/components/script/dom/xrview.rs
index a2eee03581d..c53eb8cb947 100644
--- a/components/script/dom/xrview.rs
+++ b/components/script/dom/xrview.rs
@@ -21,7 +21,9 @@ pub struct XRView {
reflector_: Reflector,
session: Dom<XRSession>,
eye: XREye,
+ #[ignore_malloc_size_of = "mozjs"]
proj: Heap<*mut JSObject>,
+ #[ignore_malloc_size_of = "mozjs"]
view: Heap<*mut JSObject>,
transform: Dom<XRRigidTransform>,
}
diff --git a/components/script/dom/xrviewerpose.rs b/components/script/dom/xrviewerpose.rs
index 717fdcea16e..92caa7f037b 100644
--- a/components/script/dom/xrviewerpose.rs
+++ b/components/script/dom/xrviewerpose.rs
@@ -22,6 +22,7 @@ use webvr_traits::WebVRFrameData;
#[dom_struct]
pub struct XRViewerPose {
pose: XRPose,
+ #[ignore_malloc_size_of = "mozjs"]
views: Heap<JSVal>,
}
diff --git a/components/script/script_runtime.rs b/components/script/script_runtime.rs
index 6cad5d4238e..80fe9cf31e5 100644
--- a/components/script/script_runtime.rs
+++ b/components/script/script_runtime.rs
@@ -685,11 +685,11 @@ unsafe fn set_gc_zeal_options(cx: *mut JSContext) {
use js::jsapi::{JS_SetGCZeal, JS_DEFAULT_ZEAL_FREQ};
let level = match pref!(js.mem.gc.zeal.level) {
- Some(level @ 0...14) => level as u8,
+ level @ 0...14 => level as u8,
_ => return,
};
let frequency = match pref!(js.mem.gc.zeal.frequency) {
- Some(frequency) if frequency >= 0 => frequency as u32,
+ frequency if frequency >= 0 => frequency as u32,
_ => JS_DEFAULT_ZEAL_FREQ,
};
JS_SetGCZeal(cx, level, frequency);
diff --git a/components/selectors/builder.rs b/components/selectors/builder.rs
index 72404de1084..b548ceb83ce 100644
--- a/components/selectors/builder.rs
+++ b/components/selectors/builder.rs
@@ -270,7 +270,7 @@ where
Component::Combinator(..) => {
unreachable!("Found combinator in simple selectors vector?");
},
- Component::PseudoElement(..) | Component::LocalName(..) => {
+ Component::Part(..) | Component::PseudoElement(..) | Component::LocalName(..) => {
specificity.element_selectors += 1
},
Component::Slotted(ref selector) => {
diff --git a/components/selectors/context.rs b/components/selectors/context.rs
index 3ecd4dd82d5..95caa4055d7 100644
--- a/components/selectors/context.rs
+++ b/components/selectors/context.rs
@@ -279,13 +279,13 @@ where
/// Runs F with a given shadow host which is the root of the tree whose
/// rules we're matching.
#[inline]
- pub fn with_shadow_host<F, E, R>(&mut self, host: Option<E>, f: F) -> R
+ pub fn with_shadow_host<F, E, R>(&mut self, host: E, f: F) -> R
where
E: Element,
F: FnOnce(&mut Self) -> R,
{
let original_host = self.current_host.take();
- self.current_host = host.map(|h| h.opaque());
+ self.current_host = Some(host.opaque());
let result = f(self);
self.current_host = original_host;
result
diff --git a/components/selectors/matching.rs b/components/selectors/matching.rs
index f50dc8ddecf..aa200cc4b26 100644
--- a/components/selectors/matching.rs
+++ b/components/selectors/matching.rs
@@ -450,6 +450,7 @@ where
element.containing_shadow_host()
},
+ Combinator::Part => element.containing_shadow_host(),
Combinator::SlotAssignment => {
debug_assert!(
context.current_host.is_some(),
@@ -517,6 +518,7 @@ where
Combinator::Child |
Combinator::Descendant |
Combinator::SlotAssignment |
+ Combinator::Part |
Combinator::PseudoElement => SelectorMatchingResult::NotMatchedGlobally,
};
@@ -671,6 +673,7 @@ where
match *selector {
Component::Combinator(_) => unreachable!(),
+ Component::Part(ref part) => element.is_part(part),
Component::Slotted(ref selector) => {
// <slots> are never flattened tree slottables.
!element.is_html_slot_element() &&
diff --git a/components/selectors/parser.rs b/components/selectors/parser.rs
index 0515eaca193..a924bbc17d0 100644
--- a/components/selectors/parser.rs
+++ b/components/selectors/parser.rs
@@ -30,10 +30,7 @@ pub trait PseudoElement: Sized + ToCss {
/// Whether the pseudo-element supports a given state selector to the right
/// of it.
- fn supports_pseudo_class(
- &self,
- _pseudo_class: &<Self::Impl as SelectorImpl>::NonTSPseudoClass,
- ) -> bool {
+ fn accepts_state_pseudo_classes(&self) -> bool {
false
}
@@ -50,6 +47,11 @@ pub trait NonTSPseudoClass: Sized + ToCss {
/// Whether this pseudo-class is :active or :hover.
fn is_active_or_hover(&self) -> bool;
+
+ /// Whether this pseudo-class belongs to:
+ ///
+ /// https://drafts.csswg.org/selectors-4/#useraction-pseudos
+ fn is_user_action_state(&self) -> bool;
}
/// Returns a Cow::Borrowed if `s` is already ASCII lowercase, and a
@@ -64,6 +66,72 @@ fn to_ascii_lowercase(s: &str) -> Cow<str> {
}
}
+bitflags! {
+ /// Flags that indicate at which point of parsing a selector are we.
+ struct SelectorParsingState: u8 {
+ /// Whether we're inside a negation. If we're inside a negation, we're
+ /// not allowed to add another negation or such, for example.
+ const INSIDE_NEGATION = 1 << 0;
+ /// Whether we've parsed a ::slotted() pseudo-element already.
+ ///
+ /// If so, then we can only parse a subset of pseudo-elements, and
+ /// whatever comes after them if so.
+ const AFTER_SLOTTED = 1 << 1;
+ /// Whether we've parsed a ::part() pseudo-element already.
+ ///
+ /// If so, then we can only parse a subset of pseudo-elements, and
+ /// whatever comes after them if so.
+ const AFTER_PART = 1 << 2;
+ /// Whether we've parsed a pseudo-element (as in, an
+ /// `Impl::PseudoElement` thus not accounting for `::slotted` or
+ /// `::part`) already.
+ ///
+ /// If so, then other pseudo-elements and most other selectors are
+ /// disallowed.
+ const AFTER_PSEUDO_ELEMENT = 1 << 3;
+ /// Whether we've parsed a non-stateful pseudo-element (again, as-in
+ /// `Impl::PseudoElement`) already. If so, then other pseudo-classes are
+ /// disallowed. If this flag is set, `AFTER_PSEUDO_ELEMENT` must be set
+ /// as well.
+ const AFTER_NON_STATEFUL_PSEUDO_ELEMENT = 1 << 4;
+ /// Whether we are after any of the pseudo-like things.
+ const AFTER_PSEUDO = Self::AFTER_PART.bits | Self::AFTER_SLOTTED.bits | Self::AFTER_PSEUDO_ELEMENT.bits;
+ }
+}
+
+impl SelectorParsingState {
+ #[inline]
+ fn allows_functional_pseudo_classes(self) -> bool {
+ !self.intersects(SelectorParsingState::AFTER_PSEUDO)
+ }
+
+ #[inline]
+ fn allows_slotted(self) -> bool {
+ !self.intersects(SelectorParsingState::AFTER_PSEUDO)
+ }
+
+ // TODO(emilio): Should we allow other ::part()s after ::part()?
+ //
+ // See https://github.com/w3c/csswg-drafts/issues/3841
+ #[inline]
+ fn allows_part(self) -> bool {
+ !self.intersects(SelectorParsingState::AFTER_PSEUDO)
+ }
+
+ #[inline]
+ fn allows_non_functional_pseudo_classes(self) -> bool {
+ !self.intersects(
+ SelectorParsingState::AFTER_SLOTTED |
+ SelectorParsingState::AFTER_NON_STATEFUL_PSEUDO_ELEMENT,
+ )
+ }
+
+ #[inline]
+ fn allows_tree_structural_pseudo_classes(self) -> bool {
+ !self.intersects(SelectorParsingState::AFTER_PSEUDO)
+ }
+}
+
pub type SelectorParseError<'i> = ParseError<'i, SelectorParseErrorKind<'i>>;
#[derive(Clone, Debug, PartialEq)]
@@ -76,6 +144,7 @@ pub enum SelectorParseErrorKind<'i> {
NonCompoundSelector,
NonPseudoElementAfterSlotted,
InvalidPseudoElementAfterSlotted,
+ InvalidState,
UnexpectedTokenInAttributeSelector(Token<'i>),
PseudoElementExpectedColon(Token<'i>),
PseudoElementExpectedIdent(Token<'i>),
@@ -108,6 +177,7 @@ macro_rules! with_all_bounds {
type AttrValue: $($InSelector)*;
type Identifier: $($InSelector)*;
type ClassName: $($InSelector)*;
+ type PartName: $($InSelector)*;
type LocalName: $($InSelector)* + Borrow<Self::BorrowedLocalName>;
type NamespaceUrl: $($CommonBounds)* + Default + Borrow<Self::BorrowedNamespaceUrl>;
type NamespacePrefix: $($InSelector)* + Default;
@@ -143,17 +213,16 @@ pub trait Parser<'i> {
type Impl: SelectorImpl;
type Error: 'i + From<SelectorParseErrorKind<'i>>;
- /// Whether the name is a pseudo-element that can be specified with
- /// the single colon syntax in addition to the double-colon syntax.
- fn pseudo_element_allows_single_colon(name: &str) -> bool {
- is_css2_pseudo_element(name)
- }
-
/// Whether to parse the `::slotted()` pseudo-element.
fn parse_slotted(&self) -> bool {
false
}
+ /// Whether to parse the `::part()` pseudo-element.
+ fn parse_part(&self) -> bool {
+ false
+ }
+
/// Whether to parse the `:host` pseudo-class.
fn parse_host(&self) -> bool {
false
@@ -694,7 +763,8 @@ impl<'a, Impl: 'a + SelectorImpl> SelectorIter<'a, Impl> {
/// combinators to the left.
#[inline]
pub(crate) fn is_featureless_host_selector(&mut self) -> bool {
- self.all(|component| matches!(*component, Component::Host(..))) &&
+ self.selector_length() > 0 &&
+ self.all(|component| matches!(*component, Component::Host(..))) &&
self.next_sequence().is_none()
}
@@ -798,6 +868,9 @@ pub enum Combinator {
/// Another combinator used for ::slotted(), which represent the jump from
/// a node to its assigned slot.
SlotAssignment,
+ /// Another combinator used for `::part()`, which represents the jump from
+ /// the part to the containing shadow host.
+ Part,
}
impl Combinator {
@@ -891,8 +964,7 @@ pub enum Component<Impl: SelectorImpl> {
LastOfType,
OnlyOfType,
NonTSPseudoClass(#[shmem(field_bound)] Impl::NonTSPseudoClass),
- /// The ::slotted() pseudo-element (which isn't actually a pseudo-element,
- /// and probably should be a pseudo-class):
+ /// The ::slotted() pseudo-element:
///
/// https://drafts.csswg.org/css-scoping/#slotted-pseudo
///
@@ -904,6 +976,9 @@ pub enum Component<Impl: SelectorImpl> {
///
/// See https://github.com/w3c/csswg-drafts/issues/2158
Slotted(Selector<Impl>),
+ /// The `::part` pseudo-element.
+ /// https://drafts.csswg.org/css-shadow-parts/#part
+ Part(#[shmem(field_bound)] Impl::PartName),
/// The `:host` pseudo-class:
///
/// https://drafts.csswg.org/css-scoping/#host-selector
@@ -1153,8 +1228,7 @@ impl ToCss for Combinator {
Combinator::Descendant => dest.write_str(" "),
Combinator::NextSibling => dest.write_str(" + "),
Combinator::LaterSibling => dest.write_str(" ~ "),
- Combinator::PseudoElement => Ok(()),
- Combinator::SlotAssignment => Ok(()),
+ Combinator::PseudoElement | Combinator::Part | Combinator::SlotAssignment => Ok(()),
}
}
}
@@ -1193,6 +1267,11 @@ impl<Impl: SelectorImpl> ToCss for Component<Impl> {
selector.to_css(dest)?;
dest.write_char(')')
},
+ Part(ref part_name) => {
+ dest.write_str("::part(")?;
+ display_to_css_identifier(part_name, dest)?;
+ dest.write_char(')')
+ },
PseudoElement(ref p) => p.to_css(dest),
ID(ref s) => {
dest.write_char('#')?;
@@ -1364,15 +1443,12 @@ where
{
let mut builder = SelectorBuilder::default();
- let mut has_pseudo_element;
- let mut slotted;
+ let mut has_pseudo_element = false;
+ let mut slotted = false;
'outer_loop: loop {
// Parse a sequence of simple selectors.
- match parse_compound_selector(parser, input, &mut builder)? {
- Some((has_pseudo, slot)) => {
- has_pseudo_element = has_pseudo;
- slotted = slot;
- },
+ let state = match parse_compound_selector(parser, input, &mut builder)? {
+ Some(state) => state,
None => {
return Err(input.new_custom_error(if builder.has_combinators() {
SelectorParseErrorKind::DanglingCombinator
@@ -1382,7 +1458,11 @@ where
},
};
- if has_pseudo_element || slotted {
+ if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
+ has_pseudo_element = state.intersects(SelectorParsingState::AFTER_PSEUDO_ELEMENT);
+ slotted = state.intersects(SelectorParsingState::AFTER_SLOTTED);
+ let part = state.intersects(SelectorParsingState::AFTER_PART);
+ debug_assert!(has_pseudo_element || slotted || part);
break;
}
@@ -1420,6 +1500,8 @@ where
builder.push_combinator(combinator);
}
+ // TODO(emilio): We'll have to flag part() somehow as well, but we need more
+ // bits!
Ok(Selector(builder.build(has_pseudo_element, slotted)))
}
@@ -1510,6 +1592,7 @@ enum SimpleSelectorParseResult<Impl: SelectorImpl> {
SimpleSelector(Component<Impl>),
PseudoElement(Impl::PseudoElement),
SlottedPseudo(Selector<Impl>),
+ PartPseudo(Impl::PartName),
}
#[derive(Debug)]
@@ -1848,7 +1931,7 @@ where
Err(e) => return Err(e.into()),
};
if !is_type_sel {
- match parse_one_simple_selector(parser, input, /* inside_negation = */ true)? {
+ match parse_one_simple_selector(parser, input, SelectorParsingState::INSIDE_NEGATION)? {
Some(SimpleSelectorParseResult::SimpleSelector(s)) => {
sequence.push(s);
},
@@ -1856,6 +1939,7 @@ where
return Err(input.new_custom_error(SelectorParseErrorKind::EmptyNegation));
},
Some(SimpleSelectorParseResult::PseudoElement(_)) |
+ Some(SimpleSelectorParseResult::PartPseudo(_)) |
Some(SimpleSelectorParseResult::SlottedPseudo(_)) => {
let e = SelectorParseErrorKind::NonSimpleSelectorInNegation;
return Err(input.new_custom_error(e));
@@ -1875,14 +1959,11 @@ where
///
/// `Err(())` means invalid selector.
/// `Ok(None)` is an empty selector
-///
-/// The booleans represent whether a pseudo-element has been parsed, and whether
-/// ::slotted() has been parsed, respectively.
fn parse_compound_selector<'i, 't, P, Impl>(
parser: &P,
input: &mut CssParser<'i, 't>,
builder: &mut SelectorBuilder<Impl>,
-) -> Result<Option<(bool, bool)>, ParseError<'i, P::Error>>
+) -> Result<Option<SelectorParsingState>, ParseError<'i, P::Error>>
where
P: Parser<'i, Impl = Impl>,
Impl: SelectorImpl,
@@ -1901,122 +1982,48 @@ where
empty = false;
}
- let mut pseudo = false;
- let mut slot = false;
+ let mut state = SelectorParsingState::empty();
loop {
- let parse_result =
- match parse_one_simple_selector(parser, input, /* inside_negation = */ false)? {
- None => break,
- Some(result) => result,
- };
+ let parse_result = match parse_one_simple_selector(parser, input, state)? {
+ None => break,
+ Some(result) => result,
+ };
empty = false;
- let slotted_selector;
- let pseudo_element;
-
match parse_result {
SimpleSelectorParseResult::SimpleSelector(s) => {
builder.push_simple_selector(s);
- continue;
},
- SimpleSelectorParseResult::PseudoElement(p) => {
- slotted_selector = None;
- pseudo_element = Some(p);
+ SimpleSelectorParseResult::PartPseudo(part_name) => {
+ state.insert(SelectorParsingState::AFTER_PART);
+ builder.push_combinator(Combinator::Part);
+ builder.push_simple_selector(Component::Part(part_name));
},
SimpleSelectorParseResult::SlottedPseudo(selector) => {
- slotted_selector = Some(selector);
- let maybe_pseudo =
- parse_one_simple_selector(parser, input, /* inside_negation = */ false)?;
-
- pseudo_element = match maybe_pseudo {
- None => None,
- Some(SimpleSelectorParseResult::PseudoElement(pseudo)) => {
- if !pseudo.valid_after_slotted() {
- return Err(input.new_custom_error(
- SelectorParseErrorKind::InvalidPseudoElementAfterSlotted,
- ));
- }
- Some(pseudo)
- },
- Some(SimpleSelectorParseResult::SimpleSelector(..)) |
- Some(SimpleSelectorParseResult::SlottedPseudo(..)) => {
- return Err(input.new_custom_error(
- SelectorParseErrorKind::NonPseudoElementAfterSlotted,
- ));
- },
- };
+ state.insert(SelectorParsingState::AFTER_SLOTTED);
+ if !builder.is_empty() {
+ builder.push_combinator(Combinator::SlotAssignment);
+ }
+ builder.push_simple_selector(Component::Slotted(selector));
},
- }
-
- debug_assert!(slotted_selector.is_some() || pseudo_element.is_some());
- // Try to parse state to the right of the pseudo-element.
- //
- // There are only 3 allowable state selectors that can go on
- // pseudo-elements as of right now.
- let mut state_selectors = SmallVec::<[Component<Impl>; 3]>::new();
- if let Some(ref p) = pseudo_element {
- loop {
- let location = input.current_source_location();
- match input.next_including_whitespace() {
- Ok(&Token::Colon) => {},
- Ok(&Token::WhiteSpace(_)) | Err(_) => break,
- Ok(t) => {
- let e = SelectorParseErrorKind::PseudoElementExpectedColon(t.clone());
- return Err(location.new_custom_error(e));
- },
+ SimpleSelectorParseResult::PseudoElement(p) => {
+ state.insert(SelectorParsingState::AFTER_PSEUDO_ELEMENT);
+ if !p.accepts_state_pseudo_classes() {
+ state.insert(SelectorParsingState::AFTER_NON_STATEFUL_PSEUDO_ELEMENT);
}
-
- let location = input.current_source_location();
- // TODO(emilio): Functional pseudo-classes too?
- // We don't need it for now.
- let name = match input.next_including_whitespace()? {
- &Token::Ident(ref name) => name.clone(),
- t => {
- return Err(location.new_custom_error(
- SelectorParseErrorKind::NoIdentForPseudo(t.clone()),
- ));
- },
- };
-
- let pseudo_class = P::parse_non_ts_pseudo_class(parser, location, name.clone())?;
- if !p.supports_pseudo_class(&pseudo_class) {
- return Err(input.new_custom_error(
- SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name),
- ));
+ if !builder.is_empty() {
+ builder.push_combinator(Combinator::PseudoElement);
}
- state_selectors.push(Component::NonTSPseudoClass(pseudo_class));
- }
- }
-
- if let Some(slotted) = slotted_selector {
- slot = true;
- if !builder.is_empty() {
- builder.push_combinator(Combinator::SlotAssignment);
- }
- builder.push_simple_selector(Component::Slotted(slotted));
- }
-
- if let Some(p) = pseudo_element {
- pseudo = true;
- if !builder.is_empty() {
- builder.push_combinator(Combinator::PseudoElement);
- }
-
- builder.push_simple_selector(Component::PseudoElement(p));
-
- for state_selector in state_selectors.drain() {
- builder.push_simple_selector(state_selector);
- }
+ builder.push_simple_selector(Component::PseudoElement(p));
+ },
}
-
- break;
}
if empty {
// An empty selector is invalid.
Ok(None)
} else {
- Ok(Some((pseudo, slot)))
+ Ok(Some(state))
}
}
@@ -2024,12 +2031,16 @@ fn parse_functional_pseudo_class<'i, 't, P, Impl>(
parser: &P,
input: &mut CssParser<'i, 't>,
name: CowRcStr<'i>,
- inside_negation: bool,
+ state: SelectorParsingState,
) -> Result<Component<Impl>, ParseError<'i, P::Error>>
where
P: Parser<'i, Impl = Impl>,
Impl: SelectorImpl,
{
+ if !state.allows_functional_pseudo_classes() {
+ return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
+ }
+ debug_assert!(state.allows_tree_structural_pseudo_classes());
match_ignore_ascii_case! { &name,
"nth-child" => return Ok(parse_nth_pseudo_class(input, Component::NthChild)?),
"nth-of-type" => return Ok(parse_nth_pseudo_class(input, Component::NthOfType)?),
@@ -2037,11 +2048,12 @@ where
"nth-last-of-type" => return Ok(parse_nth_pseudo_class(input, Component::NthLastOfType)?),
"host" => return Ok(Component::Host(Some(parse_inner_compound_selector(parser, input)?))),
"not" => {
- if inside_negation {
+ if state.intersects(SelectorParsingState::INSIDE_NEGATION) {
return Err(input.new_custom_error(
SelectorParseErrorKind::UnexpectedIdent("not".into())
));
}
+ debug_assert!(state.is_empty());
return parse_negation(parser, input)
},
_ => {}
@@ -2064,7 +2076,7 @@ where
/// Returns whether the name corresponds to a CSS2 pseudo-element that
/// can be specified with the single colon syntax (in addition to the
/// double-colon syntax, which can be used for all pseudo-elements).
-pub fn is_css2_pseudo_element(name: &str) -> bool {
+fn is_css2_pseudo_element(name: &str) -> bool {
// ** Do not add to this list! **
match_ignore_ascii_case! { name,
"before" | "after" | "first-line" | "first-letter" => true,
@@ -2080,37 +2092,52 @@ pub fn is_css2_pseudo_element(name: &str) -> bool {
fn parse_one_simple_selector<'i, 't, P, Impl>(
parser: &P,
input: &mut CssParser<'i, 't>,
- inside_negation: bool,
+ state: SelectorParsingState,
) -> Result<Option<SimpleSelectorParseResult<Impl>>, ParseError<'i, P::Error>>
where
P: Parser<'i, Impl = Impl>,
Impl: SelectorImpl,
{
let start = input.state();
- // FIXME: remove clone() when lifetimes are non-lexical
- match input.next_including_whitespace().map(|t| t.clone()) {
- Ok(Token::IDHash(id)) => {
+ let token = match input.next_including_whitespace().map(|t| t.clone()) {
+ Ok(t) => t,
+ Err(..) => {
+ input.reset(&start);
+ return Ok(None);
+ },
+ };
+
+ Ok(Some(match token {
+ Token::IDHash(id) => {
+ if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
+ return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
+ }
let id = Component::ID(id.as_ref().into());
- Ok(Some(SimpleSelectorParseResult::SimpleSelector(id)))
+ SimpleSelectorParseResult::SimpleSelector(id)
},
- Ok(Token::Delim('.')) => {
+ Token::Delim('.') => {
+ if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
+ return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
+ }
let location = input.current_source_location();
- match *input.next_including_whitespace()? {
- Token::Ident(ref class) => {
- let class = Component::Class(class.as_ref().into());
- Ok(Some(SimpleSelectorParseResult::SimpleSelector(class)))
- },
+ let class = match *input.next_including_whitespace()? {
+ Token::Ident(ref class) => class,
ref t => {
let e = SelectorParseErrorKind::ClassNeedsIdent(t.clone());
- Err(location.new_custom_error(e))
+ return Err(location.new_custom_error(e));
},
- }
+ };
+ let class = Component::Class(class.as_ref().into());
+ SimpleSelectorParseResult::SimpleSelector(class)
},
- Ok(Token::SquareBracketBlock) => {
+ Token::SquareBracketBlock => {
+ if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
+ return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
+ }
let attr = input.parse_nested_block(|input| parse_attribute_selector(parser, input))?;
- Ok(Some(SimpleSelectorParseResult::SimpleSelector(attr)))
+ SimpleSelectorParseResult::SimpleSelector(attr)
},
- Ok(Token::Colon) => {
+ Token::Colon => {
let location = input.current_source_location();
let (is_single_colon, next_token) = match input.next_including_whitespace()?.clone() {
Token::Colon => (false, input.next_including_whitespace()?.clone()),
@@ -2124,72 +2151,102 @@ where
return Err(input.new_custom_error(e));
},
};
- let is_pseudo_element =
- !is_single_colon || P::pseudo_element_allows_single_colon(&name);
+ let is_pseudo_element = !is_single_colon || is_css2_pseudo_element(&name);
if is_pseudo_element {
- let parse_result = if is_functional {
+ if state.intersects(SelectorParsingState::AFTER_PSEUDO_ELEMENT) {
+ return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
+ }
+ let pseudo_element = if is_functional {
+ if P::parse_part(parser) && name.eq_ignore_ascii_case("part") {
+ if !state.allows_part() {
+ return Err(
+ input.new_custom_error(SelectorParseErrorKind::InvalidState)
+ );
+ }
+ let name = input.parse_nested_block(|input| {
+ Ok(input.expect_ident()?.as_ref().into())
+ })?;
+ return Ok(Some(SimpleSelectorParseResult::PartPseudo(name)));
+ }
if P::parse_slotted(parser) && name.eq_ignore_ascii_case("slotted") {
+ if !state.allows_slotted() {
+ return Err(
+ input.new_custom_error(SelectorParseErrorKind::InvalidState)
+ );
+ }
let selector = input.parse_nested_block(|input| {
parse_inner_compound_selector(parser, input)
})?;
- SimpleSelectorParseResult::SlottedPseudo(selector)
- } else {
- let selector = input.parse_nested_block(|input| {
- P::parse_functional_pseudo_element(parser, name, input)
- })?;
- SimpleSelectorParseResult::PseudoElement(selector)
+ return Ok(Some(SimpleSelectorParseResult::SlottedPseudo(selector)));
}
+ input.parse_nested_block(|input| {
+ P::parse_functional_pseudo_element(parser, name, input)
+ })?
} else {
- SimpleSelectorParseResult::PseudoElement(P::parse_pseudo_element(
- parser, location, name,
- )?)
+ P::parse_pseudo_element(parser, location, name)?
};
- Ok(Some(parse_result))
+
+ if state.intersects(SelectorParsingState::AFTER_SLOTTED) &&
+ !pseudo_element.valid_after_slotted()
+ {
+ return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
+ }
+ SimpleSelectorParseResult::PseudoElement(pseudo_element)
} else {
let pseudo_class = if is_functional {
input.parse_nested_block(|input| {
- parse_functional_pseudo_class(parser, input, name, inside_negation)
+ parse_functional_pseudo_class(parser, input, name, state)
})?
} else {
- parse_simple_pseudo_class(parser, location, name)?
+ parse_simple_pseudo_class(parser, location, name, state)?
};
- Ok(Some(SimpleSelectorParseResult::SimpleSelector(
- pseudo_class,
- )))
+ SimpleSelectorParseResult::SimpleSelector(pseudo_class)
}
},
_ => {
input.reset(&start);
- Ok(None)
+ return Ok(None);
},
- }
+ }))
}
fn parse_simple_pseudo_class<'i, P, Impl>(
parser: &P,
location: SourceLocation,
name: CowRcStr<'i>,
+ state: SelectorParsingState,
) -> Result<Component<Impl>, ParseError<'i, P::Error>>
where
P: Parser<'i, Impl = Impl>,
Impl: SelectorImpl,
{
- (match_ignore_ascii_case! { &name,
- "first-child" => Ok(Component::FirstChild),
- "last-child" => Ok(Component::LastChild),
- "only-child" => Ok(Component::OnlyChild),
- "root" => Ok(Component::Root),
- "empty" => Ok(Component::Empty),
- "scope" => Ok(Component::Scope),
- "host" if P::parse_host(parser) => Ok(Component::Host(None)),
- "first-of-type" => Ok(Component::FirstOfType),
- "last-of-type" => Ok(Component::LastOfType),
- "only-of-type" => Ok(Component::OnlyOfType),
- _ => Err(())
- })
- .or_else(|()| {
- P::parse_non_ts_pseudo_class(parser, location, name).map(Component::NonTSPseudoClass)
- })
+ if !state.allows_non_functional_pseudo_classes() {
+ return Err(location.new_custom_error(SelectorParseErrorKind::InvalidState));
+ }
+
+ if state.allows_tree_structural_pseudo_classes() {
+ match_ignore_ascii_case! { &name,
+ "first-child" => return Ok(Component::FirstChild),
+ "last-child" => return Ok(Component::LastChild),
+ "only-child" => return Ok(Component::OnlyChild),
+ "root" => return Ok(Component::Root),
+ "empty" => return Ok(Component::Empty),
+ "scope" => return Ok(Component::Scope),
+ "host" if P::parse_host(parser) => return Ok(Component::Host(None)),
+ "first-of-type" => return Ok(Component::FirstOfType),
+ "last-of-type" => return Ok(Component::LastOfType),
+ "only-of-type" => return Ok(Component::OnlyOfType),
+ _ => {},
+ }
+ }
+
+ let pseudo_class = P::parse_non_ts_pseudo_class(parser, location, name)?;
+ if state.intersects(SelectorParsingState::AFTER_PSEUDO_ELEMENT) &&
+ !pseudo_class.is_user_action_state()
+ {
+ return Err(location.new_custom_error(SelectorParseErrorKind::InvalidState));
+ }
+ Ok(Component::NonTSPseudoClass(pseudo_class))
}
// NB: pub module in order to access the DummyParser
@@ -2218,11 +2275,8 @@ pub mod tests {
impl parser::PseudoElement for PseudoElement {
type Impl = DummySelectorImpl;
- fn supports_pseudo_class(&self, pc: &PseudoClass) -> bool {
- match *pc {
- PseudoClass::Hover => true,
- PseudoClass::Active | PseudoClass::Lang(..) => false,
- }
+ fn accepts_state_pseudo_classes(&self) -> bool {
+ true
}
fn valid_after_slotted(&self) -> bool {
@@ -2237,6 +2291,11 @@ pub mod tests {
fn is_active_or_hover(&self) -> bool {
matches!(*self, PseudoClass::Active | PseudoClass::Hover)
}
+
+ #[inline]
+ fn is_user_action_state(&self) -> bool {
+ self.is_active_or_hover()
+ }
}
impl ToCss for PseudoClass {
@@ -2302,6 +2361,7 @@ pub mod tests {
type AttrValue = DummyAtom;
type Identifier = DummyAtom;
type ClassName = DummyAtom;
+ type PartName = DummyAtom;
type LocalName = DummyAtom;
type NamespaceUrl = DummyAtom;
type NamespacePrefix = DummyAtom;
@@ -2340,6 +2400,10 @@ pub mod tests {
true
}
+ fn parse_part(&self) -> bool {
+ true
+ }
+
fn parse_non_ts_pseudo_class(
&self,
location: SourceLocation,
@@ -2789,11 +2853,11 @@ pub mod tests {
specificity(0, 2, 1) | HAS_PSEUDO_BIT,
)]))
);
- assert!(parse("::before:hover:active").is_err());
+ assert!(parse("::before:hover:lang(foo)").is_err());
assert!(parse("::before:hover .foo").is_err());
assert!(parse("::before .foo").is_err());
assert!(parse("::before ~ bar").is_err());
- assert!(parse("::before:active").is_err());
+ assert!(parse("::before:active").is_ok());
// https://github.com/servo/servo/issues/15335
assert!(parse(":: before").is_err());
@@ -2914,6 +2978,14 @@ pub mod tests {
assert!(parse("::slotted(div).foo").is_err());
assert!(parse("::slotted(div + bar)").is_err());
assert!(parse("::slotted(div) + foo").is_err());
+
+ assert!(parse("::part()").is_err());
+ assert!(parse("::part(42)").is_err());
+ // Though note https://github.com/w3c/csswg-drafts/issues/3502
+ assert!(parse("::part(foo bar)").is_err());
+ assert!(parse("::part(foo):hover").is_ok());
+ assert!(parse("::part(foo) + bar").is_err());
+
assert!(parse("div ::slotted(div)").is_ok());
assert!(parse("div + slot::slotted(div)").is_ok());
assert!(parse("div + slot::slotted(div.foo)").is_ok());
diff --git a/components/selectors/tree.rs b/components/selectors/tree.rs
index badfca86ed6..52599893d2f 100644
--- a/components/selectors/tree.rs
+++ b/components/selectors/tree.rs
@@ -110,6 +110,8 @@ pub trait Element: Sized + Clone + Debug {
case_sensitivity: CaseSensitivity,
) -> bool;
+ fn is_part(&self, name: &<Self::Impl as SelectorImpl>::PartName) -> bool;
+
/// Returns whether this element matches `:empty`.
///
/// That is, whether it does not contain any child element or any non-zero-length text node.
diff --git a/components/style/author_styles.rs b/components/style/author_styles.rs
index eff64ed6c1e..58d9bda423a 100644
--- a/components/style/author_styles.rs
+++ b/components/style/author_styles.rs
@@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
//! A set of author stylesheets and their computed representation, such as the
-//! ones used for ShadowRoot and XBL.
+//! ones used for ShadowRoot.
use crate::context::QuirksMode;
use crate::dom::TElement;
@@ -17,7 +17,7 @@ use crate::stylesheets::StylesheetInDocument;
use crate::stylist::CascadeData;
/// A set of author stylesheets and their computed representation, such as the
-/// ones used for ShadowRoot and XBL.
+/// ones used for ShadowRoot.
#[derive(MallocSizeOf)]
pub struct AuthorStyles<S>
where
@@ -28,9 +28,6 @@ where
pub stylesheets: AuthorStylesheetSet<S>,
/// The actual cascade data computed from the stylesheets.
pub data: CascadeData,
- /// The quirks mode of the last stylesheet flush, used because XBL sucks and
- /// we should really fix it, see bug 1406875.
- pub quirks_mode: QuirksMode,
}
impl<S> AuthorStyles<S>
@@ -43,7 +40,6 @@ where
Self {
stylesheets: AuthorStylesheetSet::new(),
data: CascadeData::new(),
- quirks_mode: QuirksMode::NoQuirks,
}
}
@@ -65,10 +61,6 @@ where
.stylesheets
.flush::<E>(/* host = */ None, /* snapshot_map = */ None);
- if flusher.sheets.dirty() {
- self.quirks_mode = quirks_mode;
- }
-
// Ignore OOM.
let _ = self
.data
diff --git a/components/style/dom.rs b/components/style/dom.rs
index 967b978bad4..9a81e2ec774 100644
--- a/components/style/dom.rs
+++ b/components/style/dom.rs
@@ -761,7 +761,7 @@ pub trait TElement:
/// Returns the anonymous content for the current element's XBL binding,
/// given if any.
///
- /// This is used in Gecko for XBL and shadow DOM.
+ /// This is used in Gecko for XBL.
fn xbl_binding_anonymous_content(&self) -> Option<Self::ConcreteNode> {
None
}
@@ -772,11 +772,6 @@ pub trait TElement:
/// The shadow root which roots the subtree this element is contained in.
fn containing_shadow(&self) -> Option<<Self::ConcreteNode as TNode>::ConcreteShadowRoot>;
- /// XBL hack for style sharing. :(
- fn has_same_xbl_proto_binding_as(&self, _other: Self) -> bool {
- true
- }
-
/// Return the element which we can use to look up rules in the selector
/// maps.
///
@@ -792,56 +787,34 @@ pub trait TElement:
}
}
- /// Implements Gecko's `nsBindingManager::WalkRules`.
- ///
- /// Returns whether to cut off the binding inheritance, that is, whether
- /// document rules should _not_ apply.
- fn each_xbl_cascade_data<'a, F>(&self, _: F) -> bool
- where
- Self: 'a,
- F: FnMut(&'a CascadeData, QuirksMode),
- {
- false
- }
-
/// Executes the callback for each applicable style rule data which isn't
/// the main document's data (which stores UA / author rules).
///
/// The element passed to the callback is the containing shadow host for the
- /// data if it comes from Shadow DOM, None if it comes from XBL.
+ /// data if it comes from Shadow DOM.
///
/// Returns whether normal document author rules should apply.
fn each_applicable_non_document_style_rule_data<'a, F>(&self, mut f: F) -> bool
where
Self: 'a,
- F: FnMut(&'a CascadeData, QuirksMode, Option<Self>),
+ F: FnMut(&'a CascadeData, Self),
{
use rule_collector::containing_shadow_ignoring_svg_use;
- let mut doc_rules_apply = !self.each_xbl_cascade_data(|data, quirks_mode| {
- f(data, quirks_mode, None);
- });
+ let mut doc_rules_apply = self.matches_user_and_author_rules();
// Use the same rules to look for the containing host as we do for rule
// collection.
if let Some(shadow) = containing_shadow_ignoring_svg_use(*self) {
doc_rules_apply = false;
if let Some(data) = shadow.style_data() {
- f(
- data,
- self.as_node().owner_doc().quirks_mode(),
- Some(shadow.host()),
- );
+ f(data, shadow.host());
}
}
if let Some(shadow) = self.shadow_root() {
if let Some(data) = shadow.style_data() {
- f(
- data,
- self.as_node().owner_doc().quirks_mode(),
- Some(shadow.host()),
- );
+ f(data, shadow.host());
}
}
@@ -850,11 +823,7 @@ pub trait TElement:
// Slots can only have assigned nodes when in a shadow tree.
let shadow = slot.containing_shadow().unwrap();
if let Some(data) = shadow.style_data() {
- f(
- data,
- self.as_node().owner_doc().quirks_mode(),
- Some(shadow.host()),
- );
+ f(data, shadow.host());
}
current = slot.assigned_slot();
}
diff --git a/components/style/gecko/conversions.rs b/components/style/gecko/conversions.rs
index 43438438a40..4cd5722bdb0 100644
--- a/components/style/gecko/conversions.rs
+++ b/components/style/gecko/conversions.rs
@@ -13,18 +13,17 @@
use crate::gecko::values::GeckoStyleCoordConvertible;
use crate::gecko_bindings::bindings;
use crate::gecko_bindings::structs::{self, nsStyleCoord_CalcValue, Matrix4x4Components};
-use crate::gecko_bindings::structs::{nsStyleImage, nsresult, SheetType};
+use crate::gecko_bindings::structs::{nsStyleImage, nsresult};
use crate::gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue};
-use crate::stylesheets::{Origin, RulesMutateError};
+use crate::stylesheets::RulesMutateError;
use crate::values::computed::image::LineDirection;
use crate::values::computed::transform::Matrix3D;
use crate::values::computed::url::ComputedImageUrl;
use crate::values::computed::{Angle, Gradient, Image};
use crate::values::computed::{Integer, LengthPercentage};
use crate::values::computed::{Length, Percentage, TextAlign};
-use crate::values::generics::box_::VerticalAlign;
use crate::values::generics::grid::{TrackListValue, TrackSize};
-use crate::values::generics::image::{CompatMode, GradientItem, Image as GenericImage};
+use crate::values::generics::image::{CompatMode, Image as GenericImage};
use crate::values::generics::rect::Rect;
use crate::Zero;
use app_units::Au;
@@ -154,7 +153,6 @@ impl nsStyleImage {
// FIXME(emilio): This is really complex, we should use cbindgen for this.
fn set_gradient(&mut self, gradient: Gradient) {
- use self::structs::nsStyleCoord;
use self::structs::NS_STYLE_GRADIENT_SIZE_CLOSEST_CORNER as CLOSEST_CORNER;
use self::structs::NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE as CLOSEST_SIDE;
use self::structs::NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER as FARTHEST_CORNER;
@@ -329,26 +327,9 @@ impl nsStyleImage {
},
};
- for (index, item) in gradient.items.iter().enumerate() {
- // NB: stops are guaranteed to be none in the gecko side by
- // default.
-
+ for (index, item) in gradient.items.into_iter().enumerate() {
let gecko_stop = unsafe { &mut (*gecko_gradient).mStops[index] };
- let mut coord = nsStyleCoord::null();
-
- match *item {
- GradientItem::ColorStop(ref stop) => {
- gecko_stop.mColor = stop.color.into();
- gecko_stop.mIsInterpolationHint = false;
- coord.set(stop.position);
- },
- GradientItem::InterpolationHint(hint) => {
- gecko_stop.mIsInterpolationHint = true;
- coord.set(Some(hint));
- },
- }
-
- gecko_stop.mLocation.move_from(coord);
+ *gecko_stop = item;
}
unsafe {
@@ -419,7 +400,7 @@ impl nsStyleImage {
use self::structs::NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER as FARTHEST_CORNER;
use self::structs::NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE as FARTHEST_SIDE;
use crate::values::computed::position::Position;
- use crate::values::generics::image::{Circle, ColorStop, Ellipse};
+ use crate::values::generics::image::{Circle, Ellipse};
use crate::values::generics::image::{EndingShape, GradientKind, ShapeExtent};
let gecko_gradient = bindings::Gecko_GetGradientImageValue(self)
@@ -531,24 +512,7 @@ impl nsStyleImage {
},
};
- let items = gecko_gradient
- .mStops
- .iter()
- .map(|ref stop| {
- if stop.mIsInterpolationHint {
- GradientItem::InterpolationHint(
- LengthPercentage::from_gecko_style_coord(&stop.mLocation)
- .expect("mLocation could not convert to LengthPercentage"),
- )
- } else {
- GradientItem::ColorStop(ColorStop {
- color: stop.mColor.into(),
- position: LengthPercentage::from_gecko_style_coord(&stop.mLocation),
- })
- }
- })
- .collect();
-
+ let items = gecko_gradient.mStops.iter().cloned().collect();
let compat_mode = if gecko_gradient.mMozLegacySyntax {
CompatMode::Moz
} else if gecko_gradient.mLegacySyntax {
@@ -818,16 +782,6 @@ impl From<RulesMutateError> for nsresult {
}
}
-impl From<Origin> for SheetType {
- fn from(other: Origin) -> Self {
- match other {
- Origin::UserAgent => SheetType::Agent,
- Origin::Author => SheetType::Doc,
- Origin::User => SheetType::User,
- }
- }
-}
-
impl TrackSize<LengthPercentage> {
/// Return TrackSize from given two nsStyleCoord
pub fn from_gecko_style_coords<T: CoordData>(gecko_min: &T, gecko_max: &T) -> Self {
@@ -920,26 +874,6 @@ where
}
}
-impl<L> VerticalAlign<L> {
- /// Converts an enumerated value coming from Gecko to a `VerticalAlign<L>`.
- pub fn from_gecko_keyword(value: u32) -> Self {
- match value {
- structs::NS_STYLE_VERTICAL_ALIGN_BASELINE => VerticalAlign::Baseline,
- structs::NS_STYLE_VERTICAL_ALIGN_SUB => VerticalAlign::Sub,
- structs::NS_STYLE_VERTICAL_ALIGN_SUPER => VerticalAlign::Super,
- structs::NS_STYLE_VERTICAL_ALIGN_TOP => VerticalAlign::Top,
- structs::NS_STYLE_VERTICAL_ALIGN_TEXT_TOP => VerticalAlign::TextTop,
- structs::NS_STYLE_VERTICAL_ALIGN_MIDDLE => VerticalAlign::Middle,
- structs::NS_STYLE_VERTICAL_ALIGN_BOTTOM => VerticalAlign::Bottom,
- structs::NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM => VerticalAlign::TextBottom,
- structs::NS_STYLE_VERTICAL_ALIGN_MIDDLE_WITH_BASELINE => {
- VerticalAlign::MozMiddleWithBaseline
- },
- _ => panic!("unexpected enumerated value for vertical-align"),
- }
- }
-}
-
impl TextAlign {
/// Obtain a specified value from a Gecko keyword value
///
diff --git a/components/style/gecko/data.rs b/components/style/gecko/data.rs
index ead7d88502b..0ce43bca46d 100644
--- a/components/style/gecko/data.rs
+++ b/components/style/gecko/data.rs
@@ -145,11 +145,6 @@ impl PerDocumentStyleData {
/// Create a `PerDocumentStyleData`.
pub fn new(document: *const structs::Document) -> Self {
let device = Device::new(document);
-
- // FIXME(emilio, tlin): How is this supposed to work with XBL? This is
- // right now not always honored, see bug 1405543...
- //
- // Should we just force XBL Stylists to be NoQuirks?
let quirks_mode = device.document().mCompatMode;
PerDocumentStyleData(AtomicRefCell::new(PerDocumentStyleDataImpl {
diff --git a/components/style/gecko/media_queries.rs b/components/style/gecko/media_queries.rs
index b39e748ce2b..4c04d9573e5 100644
--- a/components/style/gecko/media_queries.rs
+++ b/components/style/gecko/media_queries.rs
@@ -169,7 +169,6 @@ impl Device {
self.document()
.mPresShell
.as_ref()?
- ._base
.mPresContext
.mRawPtr
.as_ref()
diff --git a/components/style/gecko/pseudo_element.rs b/components/style/gecko/pseudo_element.rs
index 479c12b9cde..7538b785858 100644
--- a/components/style/gecko/pseudo_element.rs
+++ b/components/style/gecko/pseudo_element.rs
@@ -11,7 +11,7 @@
use crate::gecko_bindings::structs::{self, PseudoStyleType};
use crate::properties::longhands::display::computed_value::T as Display;
use crate::properties::{ComputedValues, PropertyFlags};
-use crate::selector_parser::{NonTSPseudoClass, PseudoElementCascadeType, SelectorImpl};
+use crate::selector_parser::{PseudoElementCascadeType, SelectorImpl};
use crate::str::{starts_with_ignore_ascii_case, string_as_ascii_lowercase};
use crate::string_cache::Atom;
use crate::values::serialize_atom_identifier;
@@ -30,6 +30,7 @@ impl ::selectors::parser::PseudoElement for PseudoElement {
// ::slotted() should support all tree-abiding pseudo-elements, see
// https://drafts.csswg.org/css-scoping/#slotted-pseudo
// https://drafts.csswg.org/css-pseudo-4/#treelike
+ #[inline]
fn valid_after_slotted(&self) -> bool {
matches!(
*self,
@@ -40,12 +41,9 @@ impl ::selectors::parser::PseudoElement for PseudoElement {
)
}
- fn supports_pseudo_class(&self, pseudo_class: &NonTSPseudoClass) -> bool {
- if !self.supports_user_action_state() {
- return false;
- }
-
- return pseudo_class.is_safe_user_action_state();
+ #[inline]
+ fn accepts_state_pseudo_classes(&self) -> bool {
+ self.supports_user_action_state()
}
}
diff --git a/components/style/gecko/selector_parser.rs b/components/style/gecko/selector_parser.rs
index 41de05c33b9..18718446c1a 100644
--- a/components/style/gecko/selector_parser.rs
+++ b/components/style/gecko/selector_parser.rs
@@ -184,16 +184,6 @@ impl NonTSPseudoClass {
}
}
- /// <https://drafts.csswg.org/selectors-4/#useraction-pseudos>
- ///
- /// We intentionally skip the link-related ones.
- pub fn is_safe_user_action_state(&self) -> bool {
- matches!(
- *self,
- NonTSPseudoClass::Hover | NonTSPseudoClass::Active | NonTSPseudoClass::Focus
- )
- }
-
/// Get the state flag associated with a pseudo-class, if any.
pub fn state_flag(&self) -> ElementState {
macro_rules! flag {
@@ -279,6 +269,15 @@ impl ::selectors::parser::NonTSPseudoClass for NonTSPseudoClass {
fn is_active_or_hover(&self) -> bool {
matches!(*self, NonTSPseudoClass::Active | NonTSPseudoClass::Hover)
}
+
+ /// We intentionally skip the link-related ones.
+ #[inline]
+ fn is_user_action_state(&self) -> bool {
+ matches!(
+ *self,
+ NonTSPseudoClass::Hover | NonTSPseudoClass::Active | NonTSPseudoClass::Focus
+ )
+ }
}
/// The dummy struct we use to implement our selector parsing.
@@ -290,6 +289,7 @@ impl ::selectors::SelectorImpl for SelectorImpl {
type AttrValue = Atom;
type Identifier = Atom;
type ClassName = Atom;
+ type PartName = Atom;
type LocalName = Atom;
type NamespacePrefix = Atom;
type NamespaceUrl = Namespace;
@@ -352,11 +352,6 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
self.parse_slotted()
}
- fn pseudo_element_allows_single_colon(name: &str) -> bool {
- // FIXME: -moz-tree check should probably be ascii-case-insensitive.
- ::selectors::parser::is_css2_pseudo_element(name) || name.starts_with("-moz-tree-")
- }
-
fn parse_non_ts_pseudo_class(
&self,
location: SourceLocation,
diff --git a/components/style/gecko/snapshot.rs b/components/style/gecko/snapshot.rs
index 6ac4003fa25..d294939baeb 100644
--- a/components/style/gecko/snapshot.rs
+++ b/components/style/gecko/snapshot.rs
@@ -184,12 +184,22 @@ impl ElementSnapshot for GeckoElementSnapshot {
}
#[inline]
+ fn is_part(&self, name: &Atom) -> bool {
+ let attr = match snapshot_helpers::find_attr(&*self.mAttrs, &atom!("part")) {
+ Some(attr) => attr,
+ None => return false,
+ };
+
+ snapshot_helpers::has_class_or_part(name, CaseSensitivity::CaseSensitive, attr)
+ }
+
+ #[inline]
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
if !self.has_any(Flags::MaybeClass) {
return false;
}
- snapshot_helpers::has_class(name, case_sensitivity, &self.mClass)
+ snapshot_helpers::has_class_or_part(name, case_sensitivity, &self.mClass)
}
#[inline]
diff --git a/components/style/gecko/snapshot_helpers.rs b/components/style/gecko/snapshot_helpers.rs
index 0eb84830546..aaa2254dbd7 100644
--- a/components/style/gecko/snapshot_helpers.rs
+++ b/components/style/gecko/snapshot_helpers.rs
@@ -29,7 +29,7 @@ unsafe fn ptr<T>(attr: &structs::nsAttrValue) -> *const T {
}
#[inline(always)]
-unsafe fn get_class_from_attr(attr: &structs::nsAttrValue) -> Class {
+unsafe fn get_class_or_part_from_attr(attr: &structs::nsAttrValue) -> Class {
debug_assert!(bindings::Gecko_AssertClassAttrValueIsSane(attr));
let base_type = base_type(attr);
if base_type == structs::nsAttrValue_ValueBaseType_eStringBase {
@@ -82,15 +82,15 @@ pub fn get_id(attrs: &[structs::AttrArray_InternalAttr]) -> Option<&WeakAtom> {
Some(unsafe { get_id_from_attr(find_attr(attrs, &atom!("id"))?) })
}
-/// Given a class name, a case sensitivity, and an array of attributes, returns
-/// whether the class has the attribute that name represents.
+/// Given a class or part name, a case sensitivity, and an array of attributes,
+/// returns whether the attribute has that name.
#[inline(always)]
-pub fn has_class(
+pub fn has_class_or_part(
name: &Atom,
case_sensitivity: CaseSensitivity,
attr: &structs::nsAttrValue,
) -> bool {
- match unsafe { get_class_from_attr(attr) } {
+ match unsafe { get_class_or_part_from_attr(attr) } {
Class::None => false,
Class::One(atom) => unsafe { case_sensitivity.eq_atom(name, WeakAtom::new(atom)) },
Class::More(atoms) => match case_sensitivity {
@@ -114,7 +114,7 @@ where
F: FnMut(&Atom),
{
unsafe {
- match get_class_from_attr(attr) {
+ match get_class_or_part_from_attr(attr) {
Class::None => {},
Class::One(atom) => Atom::with(atom, callback),
Class::More(atoms) => {
diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs
index 0fa354fb139..9d987c56308 100644
--- a/components/style/gecko/wrapper.rs
+++ b/components/style/gecko/wrapper.rs
@@ -172,15 +172,7 @@ impl<'lr> TShadowRoot for GeckoShadowRoot<'lr> {
Self: 'a,
{
let author_styles = unsafe { self.0.mServoStyles.mPtr.as_ref()? };
-
let author_styles = AuthorStyles::<GeckoStyleSheet>::from_ffi(author_styles);
-
- debug_assert!(
- author_styles.quirks_mode == self.as_node().owner_doc().quirks_mode() ||
- author_styles.stylesheets.is_empty() ||
- author_styles.stylesheets.dirty()
- );
-
Some(&author_styles.data)
}
@@ -536,11 +528,6 @@ impl<'lb> GeckoXBLBinding<'lb> {
self.0.mContent.raw::<nsIContent>()
}
- #[inline]
- fn inherits_style(&self) -> bool {
- unsafe { bindings::Gecko_XBLBinding_InheritsStyle(self.0) }
- }
-
// This duplicates the logic in Gecko's
// nsBindingManager::GetBindingWithContent.
fn binding_with_content(&self) -> Option<Self> {
@@ -552,22 +539,6 @@ impl<'lb> GeckoXBLBinding<'lb> {
binding = binding.base_binding()?;
}
}
-
- fn each_xbl_cascade_data<F>(&self, f: &mut F)
- where
- F: FnMut(&'lb CascadeData, QuirksMode),
- {
- if let Some(base) = self.base_binding() {
- base.each_xbl_cascade_data(f);
- }
-
- let data = unsafe { bindings::Gecko_XBLBinding_GetRawServoStyles(self.0).as_ref() };
-
- if let Some(data) = data {
- let data: &'lb _ = AuthorStyles::<GeckoStyleSheet>::from_ffi(data);
- f(&data.data, data.quirks_mode)
- }
- }
}
/// A simple wrapper over a non-null Gecko `Element` pointer.
@@ -603,6 +574,11 @@ impl<'le> GeckoElement<'le> {
}
#[inline(always)]
+ fn get_part_attr(&self) -> Option<&structs::nsAttrValue> {
+ snapshot_helpers::find_attr(self.attrs(), &atom!("part"))
+ }
+
+ #[inline(always)]
fn get_class_attr(&self) -> Option<&structs::nsAttrValue> {
if !self.may_have_class() {
return None;
@@ -894,10 +870,11 @@ impl<'le> GeckoElement<'le> {
if !self.as_node().is_in_shadow_tree() {
return false;
}
- match self.containing_shadow_host() {
- Some(e) => e.is_svg_element() && e.local_name() == &*local_name!("use"),
- None => false,
+ if !self.parent_node_is_shadow_root() {
+ return false;
}
+ let host = self.containing_shadow_host().unwrap();
+ host.is_svg_element() && host.local_name() == &*local_name!("use")
}
fn css_transitions_info(&self) -> FxHashMap<LonghandId, Arc<AnimationValue>> {
@@ -1250,14 +1227,6 @@ impl<'le> TElement for GeckoElement<'le> {
}
}
- fn has_same_xbl_proto_binding_as(&self, other: Self) -> bool {
- match (self.xbl_binding(), other.xbl_binding()) {
- (None, None) => true,
- (Some(a), Some(b)) => a.0.mPrototypeBinding == b.0.mPrototypeBinding,
- _ => false,
- }
- }
-
fn each_anonymous_content_child<F>(&self, mut f: F)
where
F: FnMut(Self),
@@ -1436,7 +1405,7 @@ impl<'le> TElement for GeckoElement<'le> {
#[inline]
fn matches_user_and_author_rules(&self) -> bool {
- !self.is_in_native_anonymous_subtree()
+ !self.rule_hash_target().is_in_native_anonymous_subtree()
}
#[inline]
@@ -1599,43 +1568,6 @@ impl<'le> TElement for GeckoElement<'le> {
self.may_have_animations() && unsafe { Gecko_ElementHasCSSTransitions(self.0) }
}
- fn each_xbl_cascade_data<'a, F>(&self, mut f: F) -> bool
- where
- 'le: 'a,
- F: FnMut(&'a CascadeData, QuirksMode),
- {
- // Walk the binding scope chain, starting with the binding attached to
- // our content, up till we run out of scopes or we get cut off.
- //
- // If we are a NAC pseudo-element, we want to get rules from our
- // rule_hash_target, that is, our originating element.
- let mut current = Some(self.rule_hash_target());
- while let Some(element) = current {
- if let Some(binding) = element.xbl_binding() {
- binding.each_xbl_cascade_data(&mut f);
-
- // If we're not looking at our original element, allow the
- // binding to cut off style inheritance.
- if element != *self && !binding.inherits_style() {
- // Go no further; we're not inheriting style from
- // anything above here.
- break;
- }
- }
-
- if element.is_root_of_native_anonymous_subtree() {
- // Deliberately cut off style inheritance here.
- break;
- }
-
- current = element.xbl_binding_parent();
- }
-
- // If current has something, this means we cut off inheritance at some
- // point in the loop.
- current.is_some()
- }
-
fn xbl_binding_anonymous_content(&self) -> Option<GeckoNode<'le>> {
self.xbl_binding_with_content()
.map(|b| unsafe { GeckoNode::from_content(&*b.anon_content()) })
@@ -2332,6 +2264,16 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
case_sensitivity.eq_atom(element_id, id)
}
+ #[inline]
+ fn is_part(&self, name: &Atom) -> bool {
+ let attr = match self.get_part_attr() {
+ Some(c) => c,
+ None => return false,
+ };
+
+ snapshot_helpers::has_class_or_part(name, CaseSensitivity::CaseSensitive, attr)
+ }
+
#[inline(always)]
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
let attr = match self.get_class_attr() {
@@ -2339,7 +2281,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
None => return false,
};
- snapshot_helpers::has_class(name, case_sensitivity, attr)
+ snapshot_helpers::has_class_or_part(name, case_sensitivity, attr)
}
#[inline]
diff --git a/components/style/invalidation/element/element_wrapper.rs b/components/style/invalidation/element/element_wrapper.rs
index c794eb15c2c..6e8e504c226 100644
--- a/components/style/invalidation/element/element_wrapper.rs
+++ b/components/style/invalidation/element/element_wrapper.rs
@@ -58,6 +58,10 @@ pub trait ElementSnapshot: Sized {
/// if `has_attrs()` returns true.
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool;
+ /// Whether this snapshot represents the part named `name`. Should only be
+ /// called if `has_attrs()` returns true.
+ fn is_part(&self, name: &Atom) -> bool;
+
/// A callback that should be called for each class of the snapshot. Should
/// only be called if `has_attrs()` returns true.
fn each_class<F>(&self, _: F)
@@ -340,6 +344,13 @@ where
}
}
+ fn is_part(&self, name: &Atom) -> bool {
+ match self.snapshot() {
+ Some(snapshot) if snapshot.has_attrs() => snapshot.is_part(name),
+ _ => self.element.is_part(name),
+ }
+ }
+
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
match self.snapshot() {
Some(snapshot) if snapshot.has_attrs() => snapshot.has_class(name, case_sensitivity),
diff --git a/components/style/invalidation/element/invalidation_map.rs b/components/style/invalidation/element/invalidation_map.rs
index e4cc8115760..63d6eb6acc4 100644
--- a/components/style/invalidation/element/invalidation_map.rs
+++ b/components/style/invalidation/element/invalidation_map.rs
@@ -98,6 +98,7 @@ impl Dependency {
// an eager pseudo, and return only Descendants here if not.
Some(Combinator::PseudoElement) => DependencyInvalidationKind::ElementAndDescendants,
Some(Combinator::SlotAssignment) => DependencyInvalidationKind::SlottedElements,
+ Some(Combinator::Part) => unimplemented!("Need to add invalidation for shadow parts"),
}
}
}
diff --git a/components/style/invalidation/element/invalidator.rs b/components/style/invalidation/element/invalidator.rs
index 371c0771183..ec1548f4aa3 100644
--- a/components/style/invalidation/element/invalidator.rs
+++ b/components/style/invalidation/element/invalidator.rs
@@ -158,7 +158,10 @@ impl<'a> Invalidation<'a> {
// We should be able to do better here!
match self.selector.combinator_at_parse_order(self.offset - 1) {
Combinator::Descendant | Combinator::LaterSibling | Combinator::PseudoElement => true,
- Combinator::SlotAssignment | Combinator::NextSibling | Combinator::Child => false,
+ Combinator::Part |
+ Combinator::SlotAssignment |
+ Combinator::NextSibling |
+ Combinator::Child => false,
}
}
@@ -171,6 +174,9 @@ impl<'a> Invalidation<'a> {
Combinator::Child | Combinator::Descendant | Combinator::PseudoElement => {
InvalidationKind::Descendant(DescendantInvalidationKind::Dom)
},
+ Combinator::Part => {
+ unimplemented!("Need to add invalidation for shadow parts");
+ },
Combinator::SlotAssignment => {
InvalidationKind::Descendant(DescendantInvalidationKind::Slotted)
},
diff --git a/components/style/invalidation/element/state_and_attributes.rs b/components/style/invalidation/element/state_and_attributes.rs
index e4555bb9a70..a49bb6306c5 100644
--- a/components/style/invalidation/element/state_and_attributes.rs
+++ b/components/style/invalidation/element/state_and_attributes.rs
@@ -224,8 +224,8 @@ where
let mut shadow_rule_datas = SmallVec::<[_; 3]>::new();
let matches_document_author_rules =
- element.each_applicable_non_document_style_rule_data(|data, quirks_mode, host| {
- shadow_rule_datas.push((data, quirks_mode, host.map(|h| h.opaque())))
+ element.each_applicable_non_document_style_rule_data(|data, host| {
+ shadow_rule_datas.push((data, host.opaque()))
});
let invalidated_self = {
@@ -258,12 +258,8 @@ where
}
}
- for &(ref data, quirks_mode, ref host) in &shadow_rule_datas {
- // FIXME(emilio): Replace with assert / remove when we figure
- // out what to do with the quirks mode mismatches
- // (that is, when bug 1406875 is properly fixed).
- collector.matching_context.set_quirks_mode(quirks_mode);
- collector.matching_context.current_host = host.clone();
+ for &(ref data, ref host) in &shadow_rule_datas {
+ collector.matching_context.current_host = Some(host.clone());
collector.collect_dependencies_in_invalidation_map(data.invalidation_map());
}
diff --git a/components/style/properties/data.py b/components/style/properties/data.py
index 407cc5fcdb0..7a96402c4a1 100644
--- a/components/style/properties/data.py
+++ b/components/style/properties/data.py
@@ -347,6 +347,7 @@ class Longhand(object):
"TextAlign",
"TextDecorationLine",
"TextEmphasisPosition",
+ "TextTransform",
"TouchAction",
"TransformStyle",
"UserSelect",
@@ -399,8 +400,6 @@ class Shorthand(object):
and allowed_in_keyframe_block != "False"
def get_animatable(self):
- if self.ident == "all":
- return False
for sub in self.sub_properties:
if sub.animatable:
return True
diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs
index 81e1ee4307d..b73bb073fa6 100644
--- a/components/style/properties/gecko.mako.rs
+++ b/components/style/properties/gecko.mako.rs
@@ -38,7 +38,7 @@ use crate::gecko_bindings::bindings::{Gecko_ResetFilters, Gecko_CopyFiltersFrom}
use crate::gecko_bindings::structs;
use crate::gecko_bindings::structs::nsCSSPropertyID;
use crate::gecko_bindings::structs::mozilla::PseudoStyleType;
-use crate::gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordData, CoordDataMut};
+use crate::gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordDataMut};
use crate::gecko_bindings::sugar::refptr::RefPtr;
use crate::gecko::values::GeckoStyleCoordConvertible;
use crate::gecko::values::round_border_to_device_pixels;
@@ -1104,9 +1104,6 @@ impl ${style_struct.gecko_struct_name} {
}
result
}
- pub fn get_gecko(&self) -> &${style_struct.gecko_ffi_name} {
- &self.gecko
- }
}
impl Drop for ${style_struct.gecko_struct_name} {
fn drop(&mut self) {
@@ -2508,7 +2505,7 @@ fn static_assert() {
}
</%def>
-<% skip_box_longhands= """display vertical-align
+<% skip_box_longhands= """display
animation-name animation-delay animation-duration
animation-direction animation-fill-mode animation-play-state
animation-iteration-count animation-timing-function
@@ -2564,47 +2561,6 @@ fn static_assert() {
) %>
${impl_keyword('clear', 'mBreakType', clear_keyword)}
- pub fn set_vertical_align(&mut self, v: longhands::vertical_align::computed_value::T) {
- use crate::values::generics::box_::VerticalAlign;
- let value = match v {
- VerticalAlign::Baseline => structs::NS_STYLE_VERTICAL_ALIGN_BASELINE,
- VerticalAlign::Sub => structs::NS_STYLE_VERTICAL_ALIGN_SUB,
- VerticalAlign::Super => structs::NS_STYLE_VERTICAL_ALIGN_SUPER,
- VerticalAlign::Top => structs::NS_STYLE_VERTICAL_ALIGN_TOP,
- VerticalAlign::TextTop => structs::NS_STYLE_VERTICAL_ALIGN_TEXT_TOP,
- VerticalAlign::Middle => structs::NS_STYLE_VERTICAL_ALIGN_MIDDLE,
- VerticalAlign::Bottom => structs::NS_STYLE_VERTICAL_ALIGN_BOTTOM,
- VerticalAlign::TextBottom => structs::NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM,
- VerticalAlign::MozMiddleWithBaseline => {
- structs::NS_STYLE_VERTICAL_ALIGN_MIDDLE_WITH_BASELINE
- },
- VerticalAlign::Length(length) => {
- self.gecko.mVerticalAlign.set(length);
- return;
- },
- };
- self.gecko.mVerticalAlign.set_value(CoordDataValue::Enumerated(value));
- }
-
- pub fn clone_vertical_align(&self) -> longhands::vertical_align::computed_value::T {
- use crate::values::computed::LengthPercentage;
- use crate::values::generics::box_::VerticalAlign;
-
- let gecko = &self.gecko.mVerticalAlign;
- match gecko.as_value() {
- CoordDataValue::Enumerated(value) => VerticalAlign::from_gecko_keyword(value),
- _ => {
- VerticalAlign::Length(
- LengthPercentage::from_gecko_style_coord(gecko).expect(
- "expected <length-percentage> for vertical-align",
- ),
- )
- },
- }
- }
-
- <%call expr="impl_coord_copy('vertical_align', 'mVerticalAlign')"></%call>
-
${impl_style_coord("scroll_snap_points_x", "mScrollSnapPointsX")}
${impl_style_coord("scroll_snap_points_y", "mScrollSnapPointsY")}
@@ -4455,7 +4411,7 @@ clip-path
fn set_counter_function(
data: &mut nsStyleContentData,
content_type: StyleContentType,
- name: &CustomIdent,
+ name: CustomIdent,
sep: &str,
style: CounterStyleOrNone,
) {
@@ -4464,7 +4420,9 @@ clip-path
let counter_func = unsafe {
bindings::Gecko_SetCounterFunction(data, content_type).as_mut().unwrap()
};
- counter_func.mIdent.assign(name.0.as_slice());
+ counter_func.mIdent.set_move(unsafe {
+ RefPtr::from_addrefed(name.0.into_addrefed())
+ });
if content_type == StyleContentType::Counters {
counter_func.mSeparator.assign_str(sep);
}
@@ -4493,14 +4451,14 @@ clip-path
Gecko_ClearAndResizeStyleContents(&mut self.gecko,
items.len() as u32);
}
- for (i, item) in items.into_iter().enumerate() {
+ for (i, item) in items.into_vec().into_iter().enumerate() {
// NB: Gecko compares the mString value if type is not image
// or URI independently of whatever gets there. In the quote
// cases, they set it to null, so do the same here.
unsafe {
*self.gecko.mContents[i].mContent.mString.as_mut() = ptr::null_mut();
}
- match *item {
+ match item {
ContentItem::String(ref value) => {
self.gecko.mContents[i].mType = StyleContentType::String;
unsafe {
@@ -4536,22 +4494,22 @@ clip-path
=> self.gecko.mContents[i].mType = StyleContentType::NoOpenQuote,
ContentItem::NoCloseQuote
=> self.gecko.mContents[i].mType = StyleContentType::NoCloseQuote,
- ContentItem::Counter(ref name, ref style) => {
+ ContentItem::Counter(name, style) => {
set_counter_function(
&mut self.gecko.mContents[i],
StyleContentType::Counter,
- &name,
+ name,
"",
- style.clone(),
+ style,
);
}
- ContentItem::Counters(ref name, ref sep, ref style) => {
+ ContentItem::Counters(name, sep, style) => {
set_counter_function(
&mut self.gecko.mContents[i],
StyleContentType::Counters,
- &name,
+ name,
&sep,
- style.clone(),
+ style,
);
}
ContentItem::Url(ref url) => {
@@ -4627,7 +4585,9 @@ clip-path
StyleContentType::Counter | StyleContentType::Counters => {
let gecko_function =
unsafe { &**gecko_content.mContent.mCounters.as_ref() };
- let ident = CustomIdent(Atom::from(&*gecko_function.mIdent));
+ let ident = CustomIdent(unsafe {
+ Atom::from_raw(gecko_function.mIdent.mRawPtr)
+ });
let style =
CounterStyleOrNone::from_gecko_value(&gecko_function.mCounterStyle);
let style = match style {
@@ -4664,8 +4624,10 @@ clip-path
) {
unsafe {
bindings::Gecko_ClearAndResizeCounter${counter_property}s(&mut self.gecko, v.len() as u32);
- for (i, ref pair) in v.iter().enumerate() {
- self.gecko.m${counter_property}s[i].mCounter.assign(pair.name.0.as_slice());
+ for (i, pair) in v.0.into_vec().into_iter().enumerate() {
+ self.gecko.m${counter_property}s[i].mCounter.set_move(
+ RefPtr::from_addrefed(pair.name.0.into_addrefed())
+ );
self.gecko.m${counter_property}s[i].mValue = pair.value;
}
}
@@ -4690,7 +4652,9 @@ clip-path
longhands::counter_${counter_property.lower()}::computed_value::T::new(
self.gecko.m${counter_property}s.iter().map(|ref gecko_counter| {
CounterPair {
- name: CustomIdent(Atom::from(gecko_counter.mCounter.to_string())),
+ name: CustomIdent(unsafe {
+ Atom::from_raw(gecko_counter.mCounter.mRawPtr)
+ }),
value: gecko_counter.mValue,
}
}).collect()
diff --git a/components/style/properties/longhands/box.mako.rs b/components/style/properties/longhands/box.mako.rs
index 397393ed3d8..a7a2cb9e348 100644
--- a/components/style/properties/longhands/box.mako.rs
+++ b/components/style/properties/longhands/box.mako.rs
@@ -337,11 +337,11 @@ ${helpers.predefined_type(
"Position",
"computed::Position::zero()",
vector=True,
+ allow_empty=True,
products="gecko",
gecko_pref="layout.css.scroll-snap.enabled",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-destination)",
animation_value_type="discrete",
- allow_empty="NotInitial",
)}
<% transform_extra_prefixes = "moz:layout.css.prefixes.transforms webkit" %>
diff --git a/components/style/properties/longhands/inherited_table.mako.rs b/components/style/properties/longhands/inherited_table.mako.rs
index 7dc4d73fe62..246a073d2a8 100644
--- a/components/style/properties/longhands/inherited_table.mako.rs
+++ b/components/style/properties/longhands/inherited_table.mako.rs
@@ -9,7 +9,7 @@
${helpers.single_keyword(
"border-collapse",
"separate collapse",
- gecko_constant_prefix="NS_STYLE_BORDER",
+ gecko_enum_prefix="StyleBorderCollapse",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-tables/#propdef-border-collapse",
servo_restyle_damage = "reflow",
diff --git a/components/style/properties/longhands/inherited_text.mako.rs b/components/style/properties/longhands/inherited_text.mako.rs
index f61c8754b5e..cdd7df93256 100644
--- a/components/style/properties/longhands/inherited_text.mako.rs
+++ b/components/style/properties/longhands/inherited_text.mako.rs
@@ -19,11 +19,10 @@ ${helpers.predefined_type(
// CSS Text Module Level 3
-// TODO(pcwalton): `full-width`
-${helpers.single_keyword(
+${helpers.predefined_type(
"text-transform",
- "none capitalize uppercase lowercase",
- extra_gecko_values="full-width full-size-kana",
+ "TextTransform",
+ "computed::TextTransform::none()",
animation_value_type="discrete",
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
spec="https://drafts.csswg.org/css-text/#propdef-text-transform",
diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs
index 5f44a259641..e7f9c72413e 100644
--- a/components/style/properties/properties.mako.rs
+++ b/components/style/properties/properties.mako.rs
@@ -27,7 +27,7 @@ use crate::context::QuirksMode;
#[cfg(feature = "servo")] use crate::logical_geometry::LogicalMargin;
#[cfg(feature = "servo")] use crate::computed_values;
use crate::logical_geometry::WritingMode;
-#[cfg(feature = "gecko")] use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
+use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use crate::media_queries::Device;
use crate::parser::ParserContext;
use crate::properties::longhands::system_font::SystemFont;
@@ -376,7 +376,6 @@ impl PartialEq for PropertyDeclaration {
}
}
-#[cfg(feature = "gecko")]
impl MallocSizeOf for PropertyDeclaration {
#[inline]
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
@@ -1086,6 +1085,8 @@ impl LonghandId {
}
}
+ // TODO(emilio): Should we use a function table like CASCADE_PROPERTY does
+ // to avoid blowing up code-size here?
fn parse_value<'i, 't>(
&self,
context: &ParserContext,
@@ -1533,64 +1534,7 @@ impl UnparsedValue {
quirks_mode: QuirksMode,
environment: &::custom_properties::CssEnvironment,
) -> PropertyDeclaration {
- crate::custom_properties::substitute(
- &self.css,
- self.first_token_type,
- custom_properties,
- environment,
- ).ok().and_then(|css| {
- // As of this writing, only the base URL is used for property
- // values.
- //
- // NOTE(emilio): we intentionally pase `None` as the rule type here.
- // If something starts depending on it, it's probably a bug, since
- // it'd change how values are parsed depending on whether we're in a
- // @keyframes rule or not, for example... So think twice about
- // whether you want to do this!
- //
- // FIXME(emilio): ParsingMode is slightly fishy...
- let context = ParserContext::new(
- Origin::Author,
- &self.url_data,
- None,
- ParsingMode::DEFAULT,
- quirks_mode,
- None,
- None,
- );
-
- let mut input = ParserInput::new(&css);
- Parser::new(&mut input).parse_entirely(|input| {
- match self.from_shorthand {
- None => longhand_id.parse_value(&context, input),
- Some(ShorthandId::All) => {
- // No need to parse the 'all' shorthand as anything other than a CSS-wide
- // keyword, after variable substitution.
- Err(input.new_custom_error(SelectorParseErrorKind::UnexpectedIdent("all".into())))
- }
- % for shorthand in data.shorthands_except_all():
- Some(ShorthandId::${shorthand.camel_case}) => {
- shorthands::${shorthand.ident}::parse_value(&context, input)
- .map(|longhands| {
- match longhand_id {
- % for property in shorthand.sub_properties:
- LonghandId::${property.camel_case} => {
- PropertyDeclaration::${property.camel_case}(
- longhands.${property.ident}
- )
- }
- % endfor
- _ => unreachable!()
- }
- })
- }
- % endfor
- }
- })
- .ok()
- })
- .unwrap_or_else(|| {
- // Invalid at computed-value time.
+ let invalid_at_computed_value_time = || {
let keyword = if longhand_id.inherited() {
CSSWideKeyword::Inherit
} else {
@@ -1600,7 +1544,80 @@ impl UnparsedValue {
id: longhand_id,
keyword,
})
- })
+ };
+
+ let css = match crate::custom_properties::substitute(
+ &self.css,
+ self.first_token_type,
+ custom_properties,
+ environment,
+ ) {
+ Ok(css) => css,
+ Err(..) => return invalid_at_computed_value_time(),
+ };
+
+ // As of this writing, only the base URL is used for property
+ // values.
+ //
+ // NOTE(emilio): we intentionally pase `None` as the rule type here.
+ // If something starts depending on it, it's probably a bug, since
+ // it'd change how values are parsed depending on whether we're in a
+ // @keyframes rule or not, for example... So think twice about
+ // whether you want to do this!
+ //
+ // FIXME(emilio): ParsingMode is slightly fishy...
+ let context = ParserContext::new(
+ Origin::Author,
+ &self.url_data,
+ None,
+ ParsingMode::DEFAULT,
+ quirks_mode,
+ None,
+ None,
+ );
+
+ let mut input = ParserInput::new(&css);
+ let mut input = Parser::new(&mut input);
+ input.skip_whitespace(); // Unnecessary for correctness, but may help try() rewind less.
+ if let Ok(keyword) = input.try(CSSWideKeyword::parse) {
+ return PropertyDeclaration::CSSWideKeyword(WideKeywordDeclaration {
+ id: longhand_id,
+ keyword,
+ });
+ }
+
+ let declaration = input.parse_entirely(|input| {
+ match self.from_shorthand {
+ None => longhand_id.parse_value(&context, input),
+ Some(ShorthandId::All) => {
+ // No need to parse the 'all' shorthand as anything other
+ // than a CSS-wide keyword, after variable substitution.
+ Err(input.new_custom_error(SelectorParseErrorKind::UnexpectedIdent("all".into())))
+ }
+ % for shorthand in data.shorthands_except_all():
+ Some(ShorthandId::${shorthand.camel_case}) => {
+ shorthands::${shorthand.ident}::parse_value(&context, input)
+ .map(|longhands| {
+ match longhand_id {
+ % for property in shorthand.sub_properties:
+ LonghandId::${property.camel_case} => {
+ PropertyDeclaration::${property.camel_case}(
+ longhands.${property.ident}
+ )
+ }
+ % endfor
+ _ => unreachable!()
+ }
+ })
+ }
+ % endfor
+ }
+ });
+
+ match declaration {
+ Ok(decl) => decl,
+ Err(..) => invalid_at_computed_value_time(),
+ }
}
}
@@ -3745,8 +3762,7 @@ pub fn adjust_border_width(style: &mut StyleBuilder) {
}
/// An identifier for a given alias property.
-#[derive(Clone, Copy, Eq, PartialEq)]
-#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
+#[derive(Clone, Copy, Eq, PartialEq, MallocSizeOf)]
#[repr(u16)]
pub enum AliasId {
% for i, property in enumerate(data.all_aliases()):
diff --git a/components/style/properties/shorthands/position.mako.rs b/components/style/properties/shorthands/position.mako.rs
index aaf97a0674c..6fdbe1235cf 100644
--- a/components/style/properties/shorthands/position.mako.rs
+++ b/components/style/properties/shorthands/position.mako.rs
@@ -254,7 +254,7 @@
use crate::parser::Parse;
use servo_arc::Arc;
use crate::values::{Either, None_};
- use crate::values::generics::grid::{LineNameList, TrackSize, TrackList, TrackListType};
+ use crate::values::generics::grid::{TrackSize, TrackList, TrackListType};
use crate::values::generics::grid::{TrackListValue, concat_serialize_idents};
use crate::values::specified::{GridTemplateComponent, GenericGridTemplateComponent};
use crate::values::specified::grid::parse_line_names;
@@ -265,12 +265,11 @@
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<(GridTemplateComponent, GridTemplateComponent, Either<TemplateAreasArc, None_>), ParseError<'i>> {
- // Other shorthand sub properties also parse `none` and `subgrid` keywords and this
- // shorthand should know after these keywords there is nothing to parse. Otherwise it
- // gets confused and rejects the sub properties that contains `none` or `subgrid`.
+ // Other shorthand sub properties also parse the `none` keyword and this shorthand
+ // should know after this keyword there is nothing to parse. Otherwise it gets
+ // confused and rejects the sub properties that contains `none`.
<% keywords = {
"none": "GenericGridTemplateComponent::None",
- "subgrid": "GenericGridTemplateComponent::Subgrid(LineNameList::default())"
}
%>
% for keyword, rust_type in keywords.items():
diff --git a/components/style/rule_collector.rs b/components/style/rule_collector.rs
index ba602ddca83..e87a86c5e47 100644
--- a/components/style/rule_collector.rs
+++ b/components/style/rule_collector.rs
@@ -98,7 +98,7 @@ where
flags_setter: &'a mut F,
) -> Self {
let rule_hash_target = element.rule_hash_target();
- let matches_user_and_author_rules = rule_hash_target.matches_user_and_author_rules();
+ let matches_user_and_author_rules = element.matches_user_and_author_rules();
// Gecko definitely has pseudo-elements with style attributes, like
// ::-moz-color-swatch.
@@ -198,7 +198,7 @@ where
let rules = &mut self.rules;
let flags_setter = &mut self.flags_setter;
let shadow_cascade_order = self.shadow_cascade_order;
- self.context.with_shadow_host(Some(shadow_host), |context| {
+ self.context.with_shadow_host(shadow_host, |context| {
map.get_all_matching_rules(
element,
rule_hash_target,
@@ -303,42 +303,6 @@ where
self.collect_stylist_rules(Origin::Author);
}
- fn collect_xbl_rules(&mut self) {
- let element = self.element;
- let cut_xbl_binding_inheritance =
- element.each_xbl_cascade_data(|cascade_data, quirks_mode| {
- let map = match cascade_data.normal_rules(self.pseudo_element) {
- Some(m) => m,
- None => return,
- };
-
- // NOTE(emilio): This is needed because the XBL stylist may
- // think it has a different quirks mode than the document.
- let mut matching_context = MatchingContext::new(
- self.context.matching_mode(),
- self.context.bloom_filter,
- self.context.nth_index_cache.as_mut().map(|s| &mut **s),
- quirks_mode,
- );
- matching_context.pseudo_element_matching_fn =
- self.context.pseudo_element_matching_fn;
-
- // SameTreeAuthorNormal instead of InnerShadowNormal to
- // preserve behavior, though that's kinda fishy...
- map.get_all_matching_rules(
- self.element,
- self.rule_hash_target,
- self.rules,
- &mut matching_context,
- self.flags_setter,
- CascadeLevel::SameTreeAuthorNormal,
- self.shadow_cascade_order,
- );
- });
-
- self.matches_document_author_rules &= !cut_xbl_binding_inheritance;
- }
-
fn collect_style_attribute_and_animation_rules(&mut self) {
if let Some(sa) = self.style_attribute {
self.rules
@@ -396,7 +360,6 @@ where
self.collect_host_rules();
self.collect_slotted_rules();
self.collect_normal_rules_from_containing_shadow_tree();
- self.collect_xbl_rules();
self.collect_document_author_rules();
self.collect_style_attribute_and_animation_rules();
}
diff --git a/components/style/servo/selector_parser.rs b/components/style/servo/selector_parser.rs
index 9d94c467b58..1ef49c87f9f 100644
--- a/components/style/servo/selector_parser.rs
+++ b/components/style/servo/selector_parser.rs
@@ -66,10 +66,6 @@ pub const PSEUDO_COUNT: usize = PseudoElement::ServoInlineAbsolute as usize + 1;
impl ::selectors::parser::PseudoElement for PseudoElement {
type Impl = SelectorImpl;
-
- fn supports_pseudo_class(&self, _: &NonTSPseudoClass) -> bool {
- false
- }
}
impl ToCss for PseudoElement {
@@ -293,6 +289,14 @@ impl ::selectors::parser::NonTSPseudoClass for NonTSPseudoClass {
fn is_active_or_hover(&self) -> bool {
matches!(*self, NonTSPseudoClass::Active | NonTSPseudoClass::Hover)
}
+
+ #[inline]
+ fn is_user_action_state(&self) -> bool {
+ matches!(
+ *self,
+ NonTSPseudoClass::Active | NonTSPseudoClass::Hover | NonTSPseudoClass::Focus
+ )
+ }
}
impl ToCss for NonTSPseudoClass {
@@ -393,6 +397,7 @@ impl ::selectors::SelectorImpl for SelectorImpl {
type AttrValue = String;
type Identifier = Atom;
type ClassName = Atom;
+ type PartName = Atom;
type LocalName = LocalName;
type NamespacePrefix = Prefix;
type NamespaceUrl = Namespace;
@@ -679,6 +684,10 @@ impl ElementSnapshot for ServoElementSnapshot {
.map(|v| v.as_atom())
}
+ fn is_part(&self, _name: &Atom) -> bool {
+ false
+ }
+
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
self.get_attr(&ns!(), &local_name!("class"))
.map_or(false, |v| {
diff --git a/components/style/sharing/mod.rs b/components/style/sharing/mod.rs
index 0675359ed77..3ce2a717dc8 100644
--- a/components/style/sharing/mod.rs
+++ b/components/style/sharing/mod.rs
@@ -727,27 +727,6 @@ impl<E: TElement> StyleSharingCache<E> {
return None;
}
- // Note that in theory we shouldn't need this XBL check. However, XBL is
- // absolutely broken in all sorts of ways.
- //
- // A style change that changes which XBL binding applies to an element
- // arrives there, with the element still having the old prototype
- // binding attached. And thus we try to match revalidation selectors
- // with the old XBL binding, because we can't look at the new ones of
- // course. And that causes us to revalidate with the wrong selectors and
- // hit assertions.
- //
- // Other than this, we don't need anything else like the containing XBL
- // binding parent or what not, since two elements with different XBL
- // bindings will necessarily end up with different style.
- if !target
- .element
- .has_same_xbl_proto_binding_as(candidate.element)
- {
- trace!("Miss: Different proto bindings");
- return None;
- }
-
// If the elements are not assigned to the same slot they could match
// different ::slotted() rules in the slot scope.
//
diff --git a/components/style/stylesheet_set.rs b/components/style/stylesheet_set.rs
index d2c3ad0f88e..d8c21d5494c 100644
--- a/components/style/stylesheet_set.rs
+++ b/components/style/stylesheet_set.rs
@@ -468,7 +468,14 @@ where
.fold(0, |s, (item, _)| s + item.len())
}
+ /// Returns the count of stylesheets for a given origin.
+ #[inline]
+ pub fn sheet_count(&self, origin: Origin) -> usize {
+ self.collections.borrow_for_origin(&origin).len()
+ }
+
/// Returns the `index`th stylesheet in the set for the given origin.
+ #[inline]
pub fn get(&self, origin: Origin, index: usize) -> Option<&S> {
self.collections.borrow_for_origin(&origin).get(index)
}
@@ -539,7 +546,7 @@ where
}
}
-/// The set of stylesheets effective for a given XBL binding or Shadow Root.
+/// The set of stylesheets effective for a given Shadow Root.
#[derive(MallocSizeOf)]
pub struct AuthorStylesheetSet<S>
where
diff --git a/components/style/stylesheets/origin.rs b/components/style/stylesheets/origin.rs
index 783b8f26a8b..a65b61fca13 100644
--- a/components/style/stylesheets/origin.rs
+++ b/components/style/stylesheets/origin.rs
@@ -10,18 +10,17 @@ use std::ops::BitOrAssign;
/// Each style rule has an origin, which determines where it enters the cascade.
///
/// <https://drafts.csswg.org/css-cascade/#cascading-origins>
-#[derive(Clone, Copy, Debug, Eq, PartialEq, ToShmem)]
+#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToShmem)]
#[repr(u8)]
-#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
pub enum Origin {
/// <https://drafts.csswg.org/css-cascade/#cascade-origin-user-agent>
- UserAgent = 1 << 0,
+ UserAgent = 0x1,
/// <https://drafts.csswg.org/css-cascade/#cascade-origin-user>
- User = 1 << 1,
+ User = 0x2,
/// <https://drafts.csswg.org/css-cascade/#cascade-origin-author>
- Author = 1 << 2,
+ Author = 0x4,
}
impl Origin {
@@ -59,7 +58,7 @@ impl Origin {
bitflags! {
/// A set of origins. This is equivalent to Gecko's OriginFlags.
- #[cfg_attr(feature = "servo", derive(MallocSizeOf))]
+ #[derive(MallocSizeOf)]
pub struct OriginSet: u8 {
/// <https://drafts.csswg.org/css-cascade/#cascade-origin-user-agent>
const ORIGIN_USER_AGENT = Origin::UserAgent as u8;
diff --git a/components/style/stylist.rs b/components/style/stylist.rs
index ece14e9896f..2953e3f0671 100644
--- a/components/style/stylist.rs
+++ b/components/style/stylist.rs
@@ -48,8 +48,9 @@ use selectors::visitor::SelectorVisitor;
use selectors::NthIndexCache;
use servo_arc::{Arc, ArcBorrow};
use smallbitvec::SmallBitVec;
-use std::ops;
+use smallvec::SmallVec;
use std::sync::Mutex;
+use std::{mem, ops};
use style_traits::viewport::ViewportConstraints;
/// The type of the stylesheets that the stylist contains.
@@ -128,15 +129,28 @@ impl UserAgentCascadeDataCache {
Ok(new_data)
}
- fn expire_unused(&mut self) {
- // is_unique() returns false for static references, but we never have
- // static references to UserAgentCascadeDatas. If we did, it may not
- // make sense to put them in the cache in the first place.
- self.entries.retain(|e| !e.is_unique())
+ /// Returns all the cascade datas that are not being used (that is, that are
+ /// held alive just by this cache).
+ ///
+ /// We return them instead of dropping in place because some of them may
+ /// keep alive some other documents (like the SVG documents kept alive by
+ /// URL references), and thus we don't want to drop them while locking the
+ /// cache to not deadlock.
+ fn take_unused(&mut self) -> SmallVec<[Arc<UserAgentCascadeData>; 3]> {
+ let mut unused = SmallVec::new();
+ for i in (0..self.entries.len()).rev() {
+ // is_unique() returns false for static references, but we never
+ // have static references to UserAgentCascadeDatas. If we did, it
+ // may not make sense to put them in the cache in the first place.
+ if self.entries[i].is_unique() {
+ unused.push(self.entries.remove(i));
+ }
+ }
+ unused
}
- fn clear(&mut self) {
- self.entries.clear();
+ fn take_all(&mut self) -> Vec<Arc<UserAgentCascadeData>> {
+ mem::replace(&mut self.entries, Vec::new())
}
#[cfg(feature = "gecko")]
@@ -254,13 +268,14 @@ impl DocumentCascadeData {
// First do UA sheets.
{
if flusher.flush_origin(Origin::UserAgent).dirty() {
- let mut ua_cache = UA_CASCADE_DATA_CACHE.lock().unwrap();
let origin_sheets = flusher.origin_sheets(Origin::UserAgent);
- let ua_cascade_data =
- ua_cache.lookup(origin_sheets, device, quirks_mode, guards.ua_or_user)?;
- ua_cache.expire_unused();
- debug!("User agent data cache size {:?}", ua_cache.len());
- self.user_agent = ua_cascade_data;
+ let _unused_cascade_datas = {
+ let mut ua_cache = UA_CASCADE_DATA_CACHE.lock().unwrap();
+ self.user_agent =
+ ua_cache.lookup(origin_sheets, device, quirks_mode, guards.ua_or_user)?;
+ debug!("User agent data cache size {:?}", ua_cache.len());
+ ua_cache.take_unused()
+ };
}
}
@@ -591,6 +606,18 @@ impl Stylist {
.remove_stylesheet(Some(&self.device), sheet, guard)
}
+ /// Appends a new stylesheet to the current set.
+ #[inline]
+ pub fn sheet_count(&self, origin: Origin) -> usize {
+ self.stylesheets.sheet_count(origin)
+ }
+
+ /// Appends a new stylesheet to the current set.
+ #[inline]
+ pub fn sheet_at(&self, origin: Origin, index: usize) -> Option<&StylistSheet> {
+ self.stylesheets.get(origin, index)
+ }
+
/// Returns whether for any of the applicable style rule data a given
/// condition is true.
pub fn any_applicable_rule_data<E, F>(&self, element: E, mut f: F) -> bool
@@ -605,7 +632,7 @@ impl Stylist {
let mut maybe = false;
let doc_author_rules_apply =
- element.each_applicable_non_document_style_rule_data(|data, _, _| {
+ element.each_applicable_non_document_style_rule_data(|data, _| {
maybe = maybe || f(&*data);
});
@@ -1041,12 +1068,6 @@ impl Stylist {
/// Returns whether, given a media feature change, any previously-applicable
/// style has become non-applicable, or vice-versa for each origin, using
/// `device`.
- ///
- /// Passing `device` is needed because this is used for XBL in Gecko, which
- /// can be stale in various ways, so we need to pass the device of the
- /// document itself, which is what is kept up-to-date.
- ///
- /// Arguably XBL should use something more lightweight than a Stylist.
pub fn media_features_change_changed_style(
&self,
guards: &StylesheetGuards,
@@ -1230,11 +1251,11 @@ impl Stylist {
let mut results = SmallBitVec::new();
let matches_document_rules =
- element.each_applicable_non_document_style_rule_data(|data, quirks_mode, host| {
+ element.each_applicable_non_document_style_rule_data(|data, host| {
matching_context.with_shadow_host(host, |matching_context| {
data.selectors_for_cache_revalidation.lookup(
element,
- quirks_mode,
+ self.quirks_mode,
|selector_and_hashes| {
results.push(matches_selector(
&selector_and_hashes.selector,
@@ -1356,7 +1377,7 @@ impl Stylist {
/// Shutdown the static data that this module stores.
pub fn shutdown() {
- UA_CASCADE_DATA_CACHE.lock().unwrap().clear()
+ let _entries = UA_CASCADE_DATA_CACHE.lock().unwrap().take_all();
}
}
diff --git a/components/style/values/computed/image.rs b/components/style/values/computed/image.rs
index 4070e51815a..70ecad6a04e 100644
--- a/components/style/values/computed/image.rs
+++ b/components/style/values/computed/image.rs
@@ -55,7 +55,7 @@ pub enum LineDirection {
pub type EndingShape = generic::EndingShape<Length, LengthPercentage>;
/// A computed gradient item.
-pub type GradientItem = generic::GradientItem<Color, LengthPercentage>;
+pub type GradientItem = generic::GenericGradientItem<Color, LengthPercentage>;
/// A computed color stop.
pub type ColorStop = generic::ColorStop<Color, LengthPercentage>;
diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs
index 3b32f8fecd7..3eb0c16836c 100644
--- a/components/style/values/computed/mod.rs
+++ b/components/style/values/computed/mod.rs
@@ -86,6 +86,7 @@ pub use self::transform::{TransformOrigin, TransformStyle, Translate};
#[cfg(feature = "gecko")]
pub use self::ui::CursorImage;
pub use self::ui::{Cursor, MozForceBrokenImageIcon, UserSelect};
+pub use super::specified::TextTransform;
pub use super::specified::{BorderStyle, TextDecorationLine};
pub use super::{Auto, Either, None_};
pub use app_units::Au;
diff --git a/components/style/values/computed/text.rs b/components/style/values/computed/text.rs
index 2fdb1e48c4f..c29d3d45210 100644
--- a/components/style/values/computed/text.rs
+++ b/components/style/values/computed/text.rs
@@ -19,6 +19,7 @@ use std::fmt::{self, Write};
use style_traits::{CssWriter, ToCss};
pub use crate::values::specified::TextAlignKeyword as TextAlign;
+pub use crate::values::specified::TextTransform;
pub use crate::values::specified::{OverflowWrap, WordBreak};
pub use crate::values::specified::{TextDecorationLine, TextEmphasisPosition};
diff --git a/components/style/values/generics/box.rs b/components/style/values/generics/box.rs
index 3e8f959f456..5d6e8e25031 100644
--- a/components/style/values/generics/box.rs
+++ b/components/style/values/generics/box.rs
@@ -6,14 +6,15 @@
use crate::values::animated::ToAnimatedZero;
-/// A generic value for the `vertical-align` property.
#[derive(
Animate,
Clone,
ComputeSquaredDistance,
Copy,
Debug,
+ FromPrimitive,
MallocSizeOf,
+ Parse,
PartialEq,
SpecifiedValueInfo,
ToComputedValue,
@@ -21,35 +22,51 @@ use crate::values::animated::ToAnimatedZero;
ToResolvedValue,
ToShmem,
)]
-pub enum VerticalAlign<LengthPercentage> {
- /// `baseline`
+#[repr(u8)]
+#[allow(missing_docs)]
+pub enum VerticalAlignKeyword {
Baseline,
- /// `sub`
Sub,
- /// `super`
Super,
- /// `top`
Top,
- /// `text-top`
TextTop,
- /// `middle`
Middle,
- /// `bottom`
Bottom,
- /// `text-bottom`
TextBottom,
- /// `-moz-middle-with-baseline`
#[cfg(feature = "gecko")]
MozMiddleWithBaseline,
+}
+
+/// A generic value for the `vertical-align` property.
+#[derive(
+ Animate,
+ Clone,
+ ComputeSquaredDistance,
+ Copy,
+ Debug,
+ MallocSizeOf,
+ PartialEq,
+ SpecifiedValueInfo,
+ ToComputedValue,
+ ToCss,
+ ToResolvedValue,
+ ToShmem,
+)]
+#[repr(C, u8)]
+pub enum GenericVerticalAlign<LengthPercentage> {
+ /// One of the vertical-align keywords.
+ Keyword(VerticalAlignKeyword),
/// `<length-percentage>`
Length(LengthPercentage),
}
+pub use self::GenericVerticalAlign as VerticalAlign;
+
impl<L> VerticalAlign<L> {
/// Returns `baseline`.
#[inline]
pub fn baseline() -> Self {
- VerticalAlign::Baseline
+ VerticalAlign::Keyword(VerticalAlignKeyword::Baseline)
}
}
diff --git a/components/style/values/generics/counters.rs b/components/style/values/generics/counters.rs
index 17ac687a670..fbb6927b9f1 100644
--- a/components/style/values/generics/counters.rs
+++ b/components/style/values/generics/counters.rs
@@ -45,7 +45,7 @@ pub struct CounterPair<Integer> {
ToResolvedValue,
ToShmem,
)]
-pub struct CounterIncrement<I>(Counters<I>);
+pub struct CounterIncrement<I>(pub Counters<I>);
impl<I> CounterIncrement<I> {
/// Returns a new value for `counter-increment`.
@@ -77,7 +77,7 @@ impl<I> Deref for CounterIncrement<I> {
ToResolvedValue,
ToShmem,
)]
-pub struct CounterSetOrReset<I>(Counters<I>);
+pub struct CounterSetOrReset<I>(pub Counters<I>);
impl<I> CounterSetOrReset<I> {
/// Returns a new value for `counter-set` / `counter-reset`.
@@ -102,6 +102,7 @@ impl<I> Deref for CounterSetOrReset<I> {
#[derive(
Clone,
Debug,
+ Default,
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
@@ -112,10 +113,13 @@ impl<I> Deref for CounterSetOrReset<I> {
)]
pub struct Counters<I>(#[css(iterable, if_empty = "none")] Box<[CounterPair<I>]>);
-impl<I> Default for Counters<I> {
+impl<I> Counters<I> {
+ /// Move out the Box into a vector. This could just return the Box<>, but
+ /// Vec<> is a bit more convenient because Box<[T]> doesn't implement
+ /// IntoIter: https://github.com/rust-lang/rust/issues/59878
#[inline]
- fn default() -> Self {
- Counters(vec![].into_boxed_slice())
+ pub fn into_vec(self) -> Vec<CounterPair<I>> {
+ self.0.into_vec()
}
}
diff --git a/components/style/values/generics/image.rs b/components/style/values/generics/image.rs
index 71d6a1b3849..1442ce604a2 100644
--- a/components/style/values/generics/image.rs
+++ b/components/style/values/generics/image.rs
@@ -135,13 +135,23 @@ pub enum ShapeExtent {
#[derive(
Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToResolvedValue, ToShmem,
)]
-pub enum GradientItem<Color, LengthPercentage> {
- /// A color stop.
- ColorStop(ColorStop<Color, LengthPercentage>),
+#[repr(C, u8)]
+pub enum GenericGradientItem<Color, LengthPercentage> {
+ /// A simple color stop, without position.
+ SimpleColorStop(Color),
+ /// A complex color stop, with a position.
+ ComplexColorStop {
+ /// The color for the stop.
+ color: Color,
+ /// The position for the stop.
+ position: LengthPercentage,
+ },
/// An interpolation hint.
InterpolationHint(LengthPercentage),
}
+pub use self::GenericGradientItem as GradientItem;
+
/// A color stop.
/// <https://drafts.csswg.org/css-images/#typedef-color-stop-list>
#[derive(
@@ -154,6 +164,20 @@ pub struct ColorStop<Color, LengthPercentage> {
pub position: Option<LengthPercentage>,
}
+impl<Color, LengthPercentage> ColorStop<Color, LengthPercentage> {
+ /// Convert the color stop into an appropriate `GradientItem`.
+ #[inline]
+ pub fn into_item(self) -> GradientItem<Color, LengthPercentage> {
+ match self.position {
+ Some(position) => GradientItem::ComplexColorStop {
+ color: self.color,
+ position,
+ },
+ None => GradientItem::SimpleColorStop(self.color),
+ }
+ }
+}
+
/// Specified values for a paint worklet.
/// <https://drafts.css-houdini.org/css-paint-api/>
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
diff --git a/components/style/values/specified/box.rs b/components/style/values/specified/box.rs
index c90c270c59f..31a79c141e1 100644
--- a/components/style/values/specified/box.rs
+++ b/components/style/values/specified/box.rs
@@ -10,7 +10,7 @@ use crate::properties::{LonghandId, PropertyDeclarationId, PropertyFlags};
use crate::properties::{PropertyId, ShorthandId};
use crate::values::generics::box_::AnimationIterationCount as GenericAnimationIterationCount;
use crate::values::generics::box_::Perspective as GenericPerspective;
-use crate::values::generics::box_::VerticalAlign as GenericVerticalAlign;
+use crate::values::generics::box_::{GenericVerticalAlign, VerticalAlignKeyword};
use crate::values::specified::length::{LengthPercentage, NonNegativeLength};
use crate::values::specified::{AllowQuirks, Number};
use crate::values::{CustomIdent, KeyframesName};
@@ -280,20 +280,9 @@ impl Parse for VerticalAlign {
return Ok(GenericVerticalAlign::Length(lp));
}
- try_match_ident_ignore_ascii_case! { input,
- "baseline" => Ok(GenericVerticalAlign::Baseline),
- "sub" => Ok(GenericVerticalAlign::Sub),
- "super" => Ok(GenericVerticalAlign::Super),
- "top" => Ok(GenericVerticalAlign::Top),
- "text-top" => Ok(GenericVerticalAlign::TextTop),
- "middle" => Ok(GenericVerticalAlign::Middle),
- "bottom" => Ok(GenericVerticalAlign::Bottom),
- "text-bottom" => Ok(GenericVerticalAlign::TextBottom),
- #[cfg(feature = "gecko")]
- "-moz-middle-with-baseline" => {
- Ok(GenericVerticalAlign::MozMiddleWithBaseline)
- },
- }
+ Ok(GenericVerticalAlign::Keyword(VerticalAlignKeyword::parse(
+ input,
+ )?))
}
}
diff --git a/components/style/values/specified/image.rs b/components/style/values/specified/image.rs
index 572db0ca1eb..ad2ecb18086 100644
--- a/components/style/values/specified/image.rs
+++ b/components/style/values/specified/image.rs
@@ -8,6 +8,8 @@
//! [image]: https://drafts.csswg.org/css-images/#image-values
use crate::custom_properties::SpecifiedValue;
+#[cfg(feature = "gecko")]
+use crate::gecko_bindings::structs;
use crate::parser::{Parse, ParserContext};
#[cfg(feature = "gecko")]
use crate::values::computed::{Context, Position as ComputedPosition, ToComputedValue};
@@ -266,16 +268,6 @@ impl Parse for Gradient {
},
};
- #[cfg(feature = "gecko")]
- {
- use crate::gecko_bindings::structs;
- if compat_mode == CompatMode::Moz &&
- !unsafe { structs::StaticPrefs_sVarCache_layout_css_prefixes_gradients }
- {
- return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedFunction(func)));
- }
- }
-
let (kind, items) = input.parse_nested_block(|i| {
let shape = match shape {
Shape::Linear => GradientKind::parse_linear(context, i, &mut compat_mode)?,
@@ -492,24 +484,24 @@ impl Gradient {
if reverse_stops {
p.reverse();
}
- Ok(generic::GradientItem::ColorStop(generic::ColorStop {
- color: color,
- position: Some(p.into()),
- }))
+ Ok(generic::GradientItem::ComplexColorStop {
+ color,
+ position: p.into(),
+ })
})
})
.unwrap_or(vec![]);
if items.is_empty() {
items = vec![
- generic::GradientItem::ColorStop(generic::ColorStop {
+ generic::GradientItem::ComplexColorStop {
color: Color::transparent().into(),
- position: Some(Percentage::zero().into()),
- }),
- generic::GradientItem::ColorStop(generic::ColorStop {
+ position: Percentage::zero().into(),
+ },
+ generic::GradientItem::ComplexColorStop {
color: Color::transparent().into(),
- position: Some(Percentage::hundred().into()),
- }),
+ position: Percentage::hundred().into(),
+ },
];
} else if items.len() == 1 {
let first = items[0].clone();
@@ -518,13 +510,16 @@ impl Gradient {
items.sort_by(|a, b| {
match (a, b) {
(
- &generic::GradientItem::ColorStop(ref a),
- &generic::GradientItem::ColorStop(ref b),
- ) => match (&a.position, &b.position) {
- (
- &Some(LengthPercentage::Percentage(a)),
- &Some(LengthPercentage::Percentage(b)),
- ) => {
+ &generic::GradientItem::ComplexColorStop {
+ position: ref a_position,
+ ..
+ },
+ &generic::GradientItem::ComplexColorStop {
+ position: ref b_position,
+ ..
+ },
+ ) => match (a_position, b_position) {
+ (&LengthPercentage::Percentage(a), &LengthPercentage::Percentage(b)) => {
return a.0.partial_cmp(&b.0).unwrap_or(Ordering::Equal);
},
_ => {},
@@ -548,6 +543,16 @@ impl Gradient {
}
}
+#[inline]
+fn simple_moz_gradient() -> bool {
+ #[cfg(feature = "gecko")]
+ unsafe {
+ return structs::StaticPrefs_sVarCache_layout_css_simple_moz_gradient_enabled;
+ }
+ #[cfg(not(feature = "gecko"))]
+ return false;
+}
+
impl GradientKind {
/// Parses a linear gradient.
/// CompatMode can change during `-moz-` prefixed gradient parsing if it come across a `to` keyword.
@@ -583,16 +588,6 @@ impl GradientKind {
});
(shape, position.ok(), None, None)
},
- CompatMode::WebKit => {
- let position = input.try(|i| Position::parse(context, i));
- let shape = input.try(|i| {
- if position.is_ok() {
- i.expect_comma()?;
- }
- EndingShape::parse(context, i, *compat_mode)
- });
- (shape, position.ok(), None, None)
- },
// The syntax of `-moz-` prefixed radial gradient is:
// -moz-radial-gradient(
// [ [ <position> || <angle> ]? [ ellipse | [ <length> | <percentage> ]{2} ] , |
@@ -603,7 +598,7 @@ impl GradientKind {
// where <extent-keyword> = closest-corner | closest-side | farthest-corner | farthest-side |
// cover | contain
// and <color-stop> = <color> [ <percentage> | <length> ]?
- CompatMode::Moz => {
+ CompatMode::Moz if !simple_moz_gradient() => {
let mut position = input.try(|i| LegacyPosition::parse(context, i));
let angle = input.try(|i| Angle::parse(context, i)).ok();
if position.is_err() {
@@ -619,6 +614,16 @@ impl GradientKind {
(shape, None, angle, position.ok())
},
+ _ => {
+ let position = input.try(|i| Position::parse(context, i));
+ let shape = input.try(|i| {
+ if position.is_ok() {
+ i.expect_comma()?;
+ }
+ EndingShape::parse(context, i, *compat_mode)
+ });
+ (shape, position.ok(), None, None)
+ },
};
if shape.is_ok() || position.is_some() || angle.is_some() || moz_position.is_some() {
@@ -631,7 +636,7 @@ impl GradientKind {
#[cfg(feature = "gecko")]
{
- if *compat_mode == CompatMode::Moz {
+ if *compat_mode == CompatMode::Moz && !simple_moz_gradient() {
// If this form can be represented in Modern mode, then convert the compat_mode to Modern.
if angle.is_none() {
*compat_mode = CompatMode::Modern;
@@ -751,7 +756,7 @@ impl LineDirection {
input: &mut Parser<'i, 't>,
compat_mode: &mut CompatMode,
) -> Result<Self, ParseError<'i>> {
- let mut _angle = if *compat_mode == CompatMode::Moz {
+ let mut _angle = if *compat_mode == CompatMode::Moz && !simple_moz_gradient() {
input.try(|i| Angle::parse(context, i)).ok()
} else {
// Gradients allow unitless zero angles as an exception, see:
@@ -784,7 +789,7 @@ impl LineDirection {
#[cfg(feature = "gecko")]
{
// `-moz-` prefixed linear gradient can be both Angle and Position.
- if *compat_mode == CompatMode::Moz {
+ if *compat_mode == CompatMode::Moz && !simple_moz_gradient() {
let position = i.try(|i| LegacyPosition::parse(context, i)).ok();
if _angle.is_none() {
_angle = i.try(|i| Angle::parse(context, i)).ok();
@@ -874,7 +879,7 @@ impl EndingShape {
}
// -moz- prefixed radial gradient doesn't allow EndingShape's Length or LengthPercentage
// to come before shape keyword. Otherwise it conflicts with <position>.
- if compat_mode != CompatMode::Moz {
+ if compat_mode != CompatMode::Moz || simple_moz_gradient() {
if let Ok(length) = input.try(|i| Length::parse(context, i)) {
if let Ok(y) = input.try(|i| LengthPercentage::parse(context, i)) {
if compat_mode == CompatMode::Modern {
@@ -958,13 +963,16 @@ impl GradientItem {
if let Ok(multi_position) = input.try(|i| LengthPercentage::parse(context, i)) {
let stop_color = stop.color.clone();
- items.push(generic::GradientItem::ColorStop(stop));
- items.push(generic::GradientItem::ColorStop(ColorStop {
- color: stop_color,
- position: Some(multi_position),
- }));
+ items.push(stop.into_item());
+ items.push(
+ ColorStop {
+ color: stop_color,
+ position: Some(multi_position),
+ }
+ .into_item(),
+ );
} else {
- items.push(generic::GradientItem::ColorStop(stop));
+ items.push(stop.into_item());
}
seen_stop = true;
diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs
index 64a76ccc582..7dbb93f6319 100644
--- a/components/style/values/specified/mod.rs
+++ b/components/style/values/specified/mod.rs
@@ -80,6 +80,7 @@ pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind};
pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth};
pub use self::svg_path::SVGPathData;
pub use self::table::XSpan;
+pub use self::text::TextTransform;
pub use self::text::{InitialLetter, LetterSpacing, LineHeight, TextAlign};
pub use self::text::{OverflowWrap, TextEmphasisPosition, TextEmphasisStyle, WordBreak};
pub use self::text::{TextAlignKeyword, TextDecorationLine, TextOverflow, WordSpacing};
diff --git a/components/style/values/specified/position.rs b/components/style/values/specified/position.rs
index f75af3f5585..c0ac56c9822 100644
--- a/components/style/values/specified/position.rs
+++ b/components/style/values/specified/position.rs
@@ -460,6 +460,11 @@ pub enum AutoFlow {
Column,
}
+/// If `dense` is specified, `row` is implied.
+fn is_row_dense(autoflow: &AutoFlow, dense: &bool) -> bool {
+ *autoflow == AutoFlow::Row && *dense
+}
+
#[derive(
Clone,
Copy,
@@ -477,6 +482,7 @@ pub enum AutoFlow {
/// specifying exactly how auto-placed items get flowed into the grid
pub struct GridAutoFlow {
/// Specifiy how auto-placement algorithm fills each `row` or `column` in turn
+ #[css(contextual_skip_if = "is_row_dense")]
pub autoflow: AutoFlow,
/// Specify use `dense` packing algorithm or not
#[css(represents_keyword)]
diff --git a/components/style/values/specified/text.rs b/components/style/values/specified/text.rs
index 9d4c6ae649c..6be20f58618 100644
--- a/components/style/values/specified/text.rs
+++ b/components/style/values/specified/text.rs
@@ -351,6 +351,177 @@ impl TextDecorationLine {
}
}
+#[derive(
+ Clone,
+ Copy,
+ Debug,
+ Eq,
+ MallocSizeOf,
+ PartialEq,
+ SpecifiedValueInfo,
+ ToComputedValue,
+ ToResolvedValue,
+ ToShmem,
+)]
+#[repr(C)]
+/// Specified value of the text-transform property, stored in two parts:
+/// the case-related transforms (mutually exclusive, only one may be in effect), and others (non-exclusive).
+pub struct TextTransform {
+ /// Case transform, if any.
+ pub case_: TextTransformCase,
+ /// Non-case transforms.
+ pub other_: TextTransformOther,
+}
+
+impl TextTransform {
+ #[inline]
+ /// Returns the initial value of text-transform
+ pub fn none() -> Self {
+ TextTransform {
+ case_: TextTransformCase::None,
+ other_: TextTransformOther::empty(),
+ }
+ }
+ #[inline]
+ /// Returns whether the value is 'none'
+ pub fn is_none(&self) -> bool {
+ self.case_ == TextTransformCase::None && self.other_.is_empty()
+ }
+}
+
+impl Parse for TextTransform {
+ fn parse<'i, 't>(
+ _context: &ParserContext,
+ input: &mut Parser<'i, 't>,
+ ) -> Result<Self, ParseError<'i>> {
+ let mut result = TextTransform::none();
+
+ // Case keywords are mutually exclusive; other transforms may co-occur.
+ loop {
+ let location = input.current_source_location();
+ let ident = match input.next() {
+ Ok(&Token::Ident(ref ident)) => ident,
+ Ok(other) => return Err(location.new_unexpected_token_error(other.clone())),
+ Err(..) => break,
+ };
+
+ match_ignore_ascii_case! { ident,
+ "none" if result.is_none() => {
+ return Ok(result);
+ },
+ "uppercase" if result.case_ == TextTransformCase::None => {
+ result.case_ = TextTransformCase::Uppercase
+ },
+ "lowercase" if result.case_ == TextTransformCase::None => {
+ result.case_ = TextTransformCase::Lowercase
+ },
+ "capitalize" if result.case_ == TextTransformCase::None => {
+ result.case_ = TextTransformCase::Capitalize
+ },
+ "full-width" if !result.other_.intersects(TextTransformOther::FULL_WIDTH) => {
+ result.other_.insert(TextTransformOther::FULL_WIDTH)
+ },
+ "full-size-kana" if !result.other_.intersects(TextTransformOther::FULL_SIZE_KANA) => {
+ result.other_.insert(TextTransformOther::FULL_SIZE_KANA)
+ }
+ _ => return Err(location.new_custom_error(
+ SelectorParseErrorKind::UnexpectedIdent(ident.clone())
+ )),
+ }
+ }
+
+ if result.is_none() {
+ Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
+ } else {
+ Ok(result)
+ }
+ }
+}
+
+impl ToCss for TextTransform {
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
+ where
+ W: Write,
+ {
+ if self.is_none() {
+ return dest.write_str("none");
+ }
+
+ if self.case_ != TextTransformCase::None {
+ self.case_.to_css(dest)?;
+ if !self.other_.is_empty() {
+ dest.write_str(" ")?;
+ }
+ }
+
+ self.other_.to_css(dest)
+ }
+}
+
+#[derive(
+ Clone,
+ Copy,
+ Debug,
+ Eq,
+ MallocSizeOf,
+ PartialEq,
+ SpecifiedValueInfo,
+ ToComputedValue,
+ ToCss,
+ ToResolvedValue,
+ ToShmem,
+)]
+#[repr(C)]
+/// Specified keyword values for case transforms in the text-transform property. (These are exclusive.)
+pub enum TextTransformCase {
+ /// No case transform.
+ None,
+ /// All uppercase.
+ Uppercase,
+ /// All lowercase.
+ Lowercase,
+ /// Capitalize each word.
+ Capitalize,
+}
+
+bitflags! {
+ #[derive(MallocSizeOf, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem)]
+ #[value_info(other_values = "none,full-width,full-size-kana")]
+ #[repr(C)]
+ /// Specified keyword values for non-case transforms in the text-transform property. (Non-exclusive.)
+ pub struct TextTransformOther: u8 {
+ /// full-width
+ const FULL_WIDTH = 1 << 0;
+ /// full-size-kana
+ const FULL_SIZE_KANA = 1 << 1;
+ }
+}
+
+impl ToCss for TextTransformOther {
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
+ where
+ W: Write,
+ {
+ let mut writer = SequenceWriter::new(dest, " ");
+ let mut any = false;
+ macro_rules! maybe_write {
+ ($ident:ident => $str:expr) => {
+ if self.contains(TextTransformOther::$ident) {
+ writer.raw_item($str)?;
+ any = true;
+ }
+ };
+ }
+
+ maybe_write!(FULL_WIDTH => "full-width");
+ maybe_write!(FULL_SIZE_KANA => "full-size-kana");
+
+ debug_assert!(any || self.is_empty());
+
+ Ok(())
+ }
+}
+
/// Specified value of text-align keyword value.
#[derive(
Clone,
@@ -394,8 +565,9 @@ pub enum TextAlignKeyword {
}
/// Specified value of text-align property.
-#[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
-#[derive(Clone, Copy, Debug, Eq, Hash, Parse, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
+#[derive(
+ Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss, ToShmem,
+)]
pub enum TextAlign {
/// Keyword value of text-align property.
Keyword(TextAlignKeyword),
diff --git a/components/webvr/Cargo.toml b/components/webvr/Cargo.toml
index faca3eb57a6..f4d195d29fe 100644
--- a/components/webvr/Cargo.toml
+++ b/components/webvr/Cargo.toml
@@ -22,7 +22,7 @@ gleam = "0.6"
ipc-channel = "0.11"
log = "0.4"
msg = {path = "../msg"}
-rust-webvr = {version = "0.10.2", features = ["openvr", "vrexternal"]}
+rust-webvr = {version = "=0.11.0", features = ["openvr", "vrexternal"]}
script_traits = {path = "../script_traits"}
servo_config = {path = "../config"}
webvr_traits = {path = "../webvr_traits" }
diff --git a/components/webvr/webvr_thread.rs b/components/webvr/webvr_thread.rs
index e7803509c82..e90ddbf7df5 100644
--- a/components/webvr/webvr_thread.rs
+++ b/components/webvr/webvr_thread.rs
@@ -16,7 +16,7 @@ use std::collections::hash_map::Entry;
use std::collections::{HashMap, HashSet};
use std::{thread, time};
use webvr_traits::webvr::*;
-use webvr_traits::{WebVRMsg, WebVRResult};
+use webvr_traits::{WebVRMsg, WebVRPoseInformation, WebVRResult};
/// WebVRThread owns native VRDisplays, handles their life cycle inside Servo and
/// acts a doorman for untrusted VR requests from DOM Objects. These are the key components
@@ -128,6 +128,9 @@ impl WebVRThread {
WebVRMsg::GetGamepads(synced_ids, sender) => {
self.handle_get_gamepads(synced_ids, sender);
},
+ WebVRMsg::GetGamepadsForDisplay(display_id, sender) => {
+ self.handle_get_gamepads_for_display(display_id, sender);
+ },
WebVRMsg::Exit => break,
}
}
@@ -251,6 +254,32 @@ impl WebVRThread {
self.vr_compositor_chan.send(compositor).unwrap();
}
+ fn handle_get_gamepads_for_display(
+ &mut self,
+ display_id: u32,
+ sender: IpcSender<WebVRResult<Vec<(VRGamepadData, VRGamepadState)>>>,
+ ) {
+ match self.service.get_display(display_id) {
+ Some(display) => {
+ let gamepads = display.borrow_mut().fetch_gamepads();
+ match gamepads {
+ Ok(gamepads) => {
+ let data = gamepads
+ .iter()
+ .map(|g| {
+ let g = g.borrow();
+ (g.data(), g.state())
+ })
+ .collect();
+ sender.send(Ok(data)).unwrap();
+ },
+ Err(e) => sender.send(Err(e)).unwrap(),
+ }
+ },
+ None => sender.send(Err("Device not found".into())).unwrap(),
+ }
+ }
+
fn handle_get_gamepads(
&mut self,
synced_ids: Vec<u32>,
@@ -386,10 +415,23 @@ impl webgl::WebVRRenderHandler for WebVRCompositorHandler {
unsafe { (*compositor.0).start_present(None) };
}
},
- webgl::WebVRCommand::SyncPoses(compositor_id, near, far, sender) => {
+ webgl::WebVRCommand::SyncPoses(compositor_id, near, far, get_gamepads, sender) => {
if let Some(compositor) = self.compositors.get(&compositor_id) {
let pose = unsafe { (*compositor.0).future_frame_data(near, far) };
- let _ = sender.send(Ok(pose));
+ let mut pose_information = WebVRPoseInformation {
+ frame: pose,
+ gamepads: vec![],
+ };
+ if get_gamepads {
+ let gamepads = unsafe { (*compositor.0).fetch_gamepads() };
+ if let Ok(gamepads) = gamepads {
+ for gamepad in gamepads {
+ let g = gamepad.borrow();
+ pose_information.gamepads.push((g.id(), g.state()));
+ }
+ }
+ }
+ let _ = sender.send(Ok(pose_information));
} else {
let _ = sender.send(Err(()));
}
diff --git a/components/webvr_traits/Cargo.toml b/components/webvr_traits/Cargo.toml
index 032729334f3..bf268053a9d 100644
--- a/components/webvr_traits/Cargo.toml
+++ b/components/webvr_traits/Cargo.toml
@@ -13,5 +13,5 @@ path = "lib.rs"
[dependencies]
ipc-channel = "0.11"
msg = {path = "../msg"}
-rust-webvr-api = {version = "0.10.3", features = ["ipc"]}
+rust-webvr-api = {version = "=0.11.0", features = ["ipc"]}
serde = "1.0"
diff --git a/components/webvr_traits/lib.rs b/components/webvr_traits/lib.rs
index ab31436c136..f96fee056e7 100644
--- a/components/webvr_traits/lib.rs
+++ b/components/webvr_traits/lib.rs
@@ -30,3 +30,9 @@ pub use rust_webvr_api::VRLayer as WebVRLayer;
pub use rust_webvr_api::VRMainThreadHeartbeat as WebVRMainThreadHeartbeat;
pub use rust_webvr_api::VRPose as WebVRPose;
pub use rust_webvr_api::VRStageParameters as WebVRStageParameters;
+
+#[derive(Deserialize, Serialize)]
+pub struct WebVRPoseInformation {
+ pub frame: WebVRFutureFrameData,
+ pub gamepads: Vec<(u32, WebVRGamepadState)>,
+}
diff --git a/components/webvr_traits/webvr_traits.rs b/components/webvr_traits/webvr_traits.rs
index 0f6dd069867..d21e6c3ff16 100644
--- a/components/webvr_traits/webvr_traits.rs
+++ b/components/webvr_traits/webvr_traits.rs
@@ -30,5 +30,9 @@ pub enum WebVRMsg {
Vec<u32>,
IpcSender<WebVRResult<Vec<(Option<VRGamepadData>, VRGamepadState)>>>,
),
+ GetGamepadsForDisplay(
+ u32,
+ IpcSender<WebVRResult<Vec<(VRGamepadData, VRGamepadState)>>>,
+ ),
Exit,
}
diff --git a/etc/ci/update-wpt-checkout b/etc/ci/update-wpt-checkout
index a058779f554..c8b3ece372d 100755
--- a/etc/ci/update-wpt-checkout
+++ b/etc/ci/update-wpt-checkout
@@ -92,12 +92,12 @@ function unsafe_open_pull_request() {
git checkout "${BRANCH_NAME}" || return 0
if [[ -z "${WPT_SYNC_TOKEN+set}" ]]; then
- SECRET_RESPONSE=$(curl $TASKCLUSTER_PROXY_URL/api/secrets/v1/secret/project/servo/wpt-sync)
- WPT_SYNC_TOKEN=`echo "${OPEN_PR_RESPONSE}" | jq '.token'`
+ SECRET_RESPONSE=$(curl ${TASKCLUSTER_PROXY_URL}/secrets/v1/secret/project/servo/wpt-sync)
+ WPT_SYNC_TOKEN=`echo "${SECRET_RESPONSE}" | jq --raw-output '.secret.token'`
fi
if [[ -z "${WPT_SYNC_TOKEN}" ]]; then
- echo "Github auth token missing from .wpt-token file."
+ echo "Github auth token missing from WPT_SYNC_TOKEN."
return 1
fi
diff --git a/etc/taskcluster/decision_task.py b/etc/taskcluster/decision_task.py
index e5b16c5b952..ac009c874ad 100644
--- a/etc/taskcluster/decision_task.py
+++ b/etc/taskcluster/decision_task.py
@@ -90,10 +90,10 @@ def main(task_for):
daily_tasks_setup()
with_rust_nightly()
linux_nightly()
- android_nightly("arm")
- android_nightly("x86")
+ android_nightly()
windows_nightly()
macos_nightly()
+ update_wpt()
# These are disabled in a "real" decision task,
@@ -264,36 +264,27 @@ def android_arm32_dev():
)
-def android_nightly(job):
- details = {
- "arm": {
- "mach_flag": "--android",
- "name": "ARMv7",
- "target": "armv7-linux-androideabi",
- },
- "x86": {
- "mach_flag": "--target i686-linux-android",
- "name": "x86",
- "target": "i686-linux-android",
- }
- }
-
+def android_nightly():
return (
android_build_task("Nightly build and upload")
- .with_treeherder("Android " + details[job]["name"], "Nightly")
+ .with_treeherder("Android Nightlies")
.with_features("taskclusterProxy")
.with_scopes("secrets:get:project/servo/s3-upload-credentials")
.with_script("""
- ./mach build {flag} --release
- ./mach package {flag} --release --maven
+ ./mach build --release --android
+ ./mach package --release --android --maven
+ ./mach build --release --target i686-linux-android
+ ./mach package --release --target i686-linux-android --maven
./mach upload-nightly android --secret-from-taskcluster
./mach upload-nightly maven --secret-from-taskcluster
- """.format(flag=details[job]["mach_flag"]))
+ """)
.with_artifacts(
- "/repo/target/android/%s/release/servoapp.apk" % details[job]["target"],
- "/repo/target/android/%s/release/servoview.aar" % details[job]["target"],
+ "/repo/target/android/armv7-linux-androideabi/release/servoapp.apk",
+ "/repo/target/android/armv7-linux-androideabi/release/servoview.aar",
+ "/repo/target/android/i686-linux-android/release/servoapp.apk",
+ "/repo/target/android/i686-linux-android/release/servoview.aar",
)
- .find_or_create(("build.android_%s_nightly." + CONFIG.git_sha) % details[job]["name"].lower())
+ .find_or_create("build.android_nightlies." + CONFIG.git_sha)
)
@@ -395,6 +386,7 @@ def windows_nightly():
return (
windows_build_task("Nightly build and upload")
.with_treeherder("Windows x64", "Nightly")
+ .with_features("taskclusterProxy")
.with_scopes("secrets:get:project/servo/s3-upload-credentials")
.with_script("mach build --release",
"mach package --release",
@@ -451,7 +443,6 @@ def macos_nightly():
.with_scopes(
"secrets:get:project/servo/s3-upload-credentials",
"secrets:get:project/servo/github-homebrew-token",
- "secrets:get:project/servo/wpt-sync",
)
.with_script(
"./mach build --release",
@@ -459,15 +450,36 @@ def macos_nightly():
"./mach upload-nightly mac --secret-from-taskcluster",
)
.with_artifacts("repo/target/release/servo-tech-demo.dmg")
- .with_script(
- "./etc/ci/update-wpt-checkout fetch-and-update-expectations",
- "./etc/ci/update-wpt-checkout open-pr",
- "./etc/ci/update-wpt-checkout cleanup",
- )
.find_or_create("build.mac_x64_nightly." + CONFIG.git_sha)
)
+def update_wpt():
+ # Reuse the release build that was made for landing the PR
+ build_task = decisionlib.Task.find("build.macos_x64_release." + CONFIG.git_sha)
+ update_task = (
+ macos_task("WPT update")
+ .with_python2()
+ .with_treeherder("macOS x64", "WPT update")
+ .with_features("taskclusterProxy")
+ .with_scopes("secrets:get:project/servo/wpt-sync")
+ .with_index_and_artifacts_expire_in(log_artifacts_expire_in)
+ .with_max_run_time_minutes(5 * 60)
+ )
+ return (
+ with_homebrew(update_task, "etc/taskcluster/macos/Brewfile-wpt")
+ .with_repo()
+ .with_curl_artifact_script(build_task, "target.tar.gz")
+ .with_script("""
+ tar -xzf target.tar.gz
+ ./etc/ci/update-wpt-checkout fetch-and-update-expectations
+ ./etc/ci/update-wpt-checkout open-pr
+ ./etc/ci/update-wpt-checkout cleanup
+ """)
+ .find_or_create("wpt_update." + CONFIG.git_sha)
+ )
+
+
def macos_wpt():
build_task = (
macos_build_task("Release build")
@@ -691,8 +703,19 @@ def windows_build_task(name, package=True, arch="x86_64"):
return task
+def with_homebrew(task, brewfile):
+ return task.with_script("""
+ mkdir -p "$HOME/homebrew"
+ export PATH="$HOME/homebrew/bin:$PATH"
+ which brew || curl -L https://github.com/Homebrew/brew/tarball/master \
+ | tar xz --strip 1 -C "$HOME/homebrew"
+
+ time brew bundle install --no-upgrade --file={brewfile}
+ """.format(brewfile=brewfile))
+
+
def macos_build_task(name):
- return (
+ build_task = (
macos_task(name)
# Allow long runtime in case the cache expired for all those Homebrew dependencies
.with_max_run_time_minutes(60 * 2)
@@ -700,13 +723,10 @@ def macos_build_task(name):
.with_repo()
.with_python2()
.with_rustup()
+ )
+ return (
+ with_homebrew(build_task, "etc/taskcluster/macos/Brewfile")
.with_script("""
- mkdir -p "$HOME/homebrew"
- export PATH="$HOME/homebrew/bin:$PATH"
- which brew || curl -L https://github.com/Homebrew/brew/tarball/master \
- | tar xz --strip 1 -C "$HOME/homebrew"
-
- time brew bundle install --no-upgrade --file=etc/taskcluster/macos/Brewfile
export OPENSSL_INCLUDE_DIR="$(brew --prefix openssl)/include"
export OPENSSL_LIB_DIR="$(brew --prefix openssl)/lib"
""")
diff --git a/etc/taskcluster/macos/Brewfile-wpt b/etc/taskcluster/macos/Brewfile-wpt
new file mode 100644
index 00000000000..f563d5e7bf9
--- /dev/null
+++ b/etc/taskcluster/macos/Brewfile-wpt
@@ -0,0 +1 @@
+brew "jq" \ No newline at end of file
diff --git a/etc/taskcluster/windows/first-boot.ps1 b/etc/taskcluster/windows/first-boot.ps1
index 896f562bacc..9da5091e99c 100644
--- a/etc/taskcluster/windows/first-boot.ps1
+++ b/etc/taskcluster/windows/first-boot.ps1
@@ -39,6 +39,8 @@ $client.DownloadFile("https://github.com/taskcluster/generic-worker/releases/dow
"/v14.1.0/generic-worker-nativeEngine-windows-amd64.exe", "C:\generic-worker\generic-worker.exe")
$client.DownloadFile("https://github.com/taskcluster/livelog/releases/download" +
"/v1.1.0/livelog-windows-amd64.exe", "C:\generic-worker\livelog.exe")
+$client.DownloadFile("https://github.com/taskcluster/taskcluster-proxy/releases/download" +
+ "/v5.1.0/taskcluster-proxy-windows-amd64.exe", "C:\generic-worker\taskcluster-proxy.exe")
Expand-ZIPFile -File "C:\nssm-2.24.zip" -Destination "C:\" `
-Url "https://www.nssm.cc/release/nssm-2.24.zip"
Start-Process C:\generic-worker\generic-worker.exe -ArgumentList `
diff --git a/ports/glutin/Cargo.toml b/ports/glutin/Cargo.toml
index 4c055116e39..9135e87b623 100644
--- a/ports/glutin/Cargo.toml
+++ b/ports/glutin/Cargo.toml
@@ -52,7 +52,7 @@ lazy_static = "1"
libservo = {path = "../../components/servo"}
libc = "0.2"
log = "0.4"
-rust-webvr = { version = "0.10.2", features = ["glwindow"] }
+rust-webvr = { version = "=0.11.0", features = ["glwindow"] }
tinyfiledialogs = "3.0"
[target.'cfg(any(target_os = "linux", target_os = "windows"))'.dependencies]
diff --git a/python/mach_bootstrap.py b/python/mach_bootstrap.py
index aded4c0a0e9..f94f2c6f772 100644
--- a/python/mach_bootstrap.py
+++ b/python/mach_bootstrap.py
@@ -293,6 +293,10 @@ def bootstrap(topdir):
mach.define_category(category, meta['short'], meta['long'], meta['priority'])
for path in MACH_MODULES:
- mach.load_commands_from_file(os.path.join(topdir, path))
+ # explicitly provide a module name
+ # workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=1549636
+ file = os.path.basename(path)
+ module_name = os.path.splitext(file)[0]
+ mach.load_commands_from_file(os.path.join(topdir, path), module_name)
return mach
diff --git a/python/servo/bootstrap.py b/python/servo/bootstrap.py
index 28292ea3510..0b5da09501d 100644
--- a/python/servo/bootstrap.py
+++ b/python/servo/bootstrap.py
@@ -124,7 +124,7 @@ def linux(context, force=False):
'ccache', 'mesa-libGLU-devel', 'clang', 'clang-libs', 'gstreamer1-devel',
'gstreamer1-plugins-base-devel', 'gstreamer1-plugins-bad-free-devel', 'autoconf213']
if context.distro == "Ubuntu":
- if context.distro_version == "17.04":
+ if context.distro_version in ["17.04", "19.04"]:
pkgs_apt += ["libssl-dev"]
elif int(context.distro_version.split(".")[0]) < 17:
pkgs_apt += ["libssl-dev"]
@@ -384,14 +384,16 @@ def get_linux_distribution():
base_version = '10.10'
else:
raise Exception('unsupported version of %s: %s' % (distro, version))
-
distro, version = 'Ubuntu', base_version
+ elif distro.lower() == 'ubuntu':
+ if version > '19.04':
+ raise Exception('unsupported version of %s: %s' % (distro, version))
+ # Fixme: we should allow checked/supported versions only
elif distro.lower() not in [
'centos',
'centos linux',
'debian',
'fedora',
- 'ubuntu',
]:
raise Exception('mach bootstrap does not support %s, please file a bug' % distro)
diff --git a/python/servo/build_commands.py b/python/servo/build_commands.py
index 3b01ebaa074..abe4e1003f9 100644
--- a/python/servo/build_commands.py
+++ b/python/servo/build_commands.py
@@ -212,11 +212,6 @@ class MachCommands(CommandBase):
print("Please specify either --target or --android.")
sys.exit(1)
- # https://github.com/servo/servo/issues/22069
- if debug_mozjs and magicleap:
- print("Please specify either --debug-mozjs or --magicleap.")
- sys.exit(1)
-
if android:
target = self.config["android"]["target"]
@@ -576,6 +571,7 @@ class MachCommands(CommandBase):
env.setdefault("HARFBUZZ_SYS_NO_PKG_CONFIG", "1")
env.setdefault("PKG_CONFIG_ALLOW_CROSS", "1")
env.setdefault("CMAKE_TOOLCHAIN_FILE", path.join(ml_support, "toolchain.cmake"))
+ env.setdefault("_LIBCPP_INLINE_VISIBILITY", "__attribute__((__always_inline__))")
# The Open SSL configuration
env.setdefault("OPENSSL_DIR", path.join(target_path, target, "native", "openssl"))
diff --git a/python/servo/package_commands.py b/python/servo/package_commands.py
index 8ff1170872d..12ab0607a3a 100644
--- a/python/servo/package_commands.py
+++ b/python/servo/package_commands.py
@@ -546,7 +546,11 @@ class PackageCommands(CommandBase):
import boto3
def get_taskcluster_secret(name):
- url = os.environ["TASKCLUSTER_PROXY_URL"] + "/secrets/v1/secret/project/servo/" + name
+ url = (
+ os.environ.get("TASKCLUSTER_PROXY_URL", "http://taskcluster") +
+ "/secrets/v1/secret/project/servo/" +
+ name
+ )
return json.load(urllib.urlopen(url))["secret"]
def get_s3_secret():
diff --git a/resources/prefs.json b/resources/prefs.json
index b882ad9ca46..23c42c3352d 100644
--- a/resources/prefs.json
+++ b/resources/prefs.json
@@ -42,8 +42,8 @@
"js.ion.enabled": true,
"js.ion.offthread_compilation.enabled": true,
"js.ion.unsafe_eager_compilation.enabled": false,
- "js.mem.gc.allocation_threshold_avoid_interrupt_factor": 1,
- "js.mem.gc.allocation_threshold_factor": 1,
+ "js.mem.gc.allocation_threshold_avoid_interrupt_factor": 100,
+ "js.mem.gc.allocation_threshold_factor": 100,
"js.mem.gc.allocation_threshold_mb": 30,
"js.mem.gc.compacting.enabled": true,
"js.mem.gc.decommit_threshold_mb": 32,
diff --git a/support/magicleap/Servo2D/Servo2D.mabu b/support/magicleap/Servo2D/Servo2D.mabu
index 60404f038ea..43d6fe26b3f 100644
--- a/support/magicleap/Servo2D/Servo2D.mabu
+++ b/support/magicleap/Servo2D/Servo2D.mabu
@@ -14,10 +14,14 @@ LIBPATHS.debug = \
LIBPATHS.release = \
../../../target/magicleap/aarch64-linux-android/release
+LDFLAGS.device = \
+ -L$(MLSDK)/lumin/stl/libc++/lib
+
STLIBS = \
mlservo
SHLIBS = \
+ c++abi \
log \
z
diff --git a/support/magicleap/fake-ld.sh b/support/magicleap/fake-ld.sh
index 9e6f7ca7132..634f1c324bf 100755
--- a/support/magicleap/fake-ld.sh
+++ b/support/magicleap/fake-ld.sh
@@ -11,7 +11,7 @@ set -o pipefail
MAGICLEAP_TOOLCHAIN=${MAGICLEAP_TOOLCHAIN:-"${MAGICLEAP_SDK}/tools/toolchains"}
TARGET=${TARGET:-"aarch64-linux-android"}
LD=${LD:-"${MAGICLEAP_TOOLCHAIN}/bin/${TARGET}-ld"}
-LDFLAGS=${LDFLAGS:-"-L${MAGICLEAP_SDK}/lumin/stl/libc++/lib -L${MAGICLEAP_SDK}/lumin/usr/lib -L${MAGICLEAP_TOOLCHAIN}/lib/gcc/${TARGET}/4.9.x ${MAGICLEAP_SDK}/lumin/usr/lib/crtbegin_so.o"}
+LDFLAGS=${LDFLAGS:-"-L${MAGICLEAP_SDK}/lumin/stl/libc++/lib -L${MAGICLEAP_SDK}/lumin/usr/lib -L${MAGICLEAP_TOOLCHAIN}/lib/gcc/${TARGET}/4.9.x"}
# Remove the -landroid flag, grr
ARGS=("$@")
diff --git a/tests/wpt/metadata/css/css-text/parsing/text-transform-valid.html.ini b/tests/wpt/metadata/css/css-text/parsing/text-transform-valid.html.ini
deleted file mode 100644
index c9e0f5c67db..00000000000
--- a/tests/wpt/metadata/css/css-text/parsing/text-transform-valid.html.ini
+++ /dev/null
@@ -1,43 +0,0 @@
-[text-transform-valid.html]
- [e.style['text-transform'\] = "full-size-kana full-width capitalize" should set the property value]
- expected: FAIL
-
- [e.style['text-transform'\] = "full-width" should set the property value]
- expected: FAIL
-
- [e.style['text-transform'\] = "capitalize full-width" should set the property value]
- expected: FAIL
-
- [e.style['text-transform'\] = "full-size-kana full-width" should set the property value]
- expected: FAIL
-
- [e.style['text-transform'\] = "capitalize full-width full-size-kana" should set the property value]
- expected: FAIL
-
- [e.style['text-transform'\] = "full-width full-size-kana" should set the property value]
- expected: FAIL
-
- [e.style['text-transform'\] = "full-size-kana lowercase full-width" should set the property value]
- expected: FAIL
-
- [e.style['text-transform'\] = "full-size-kana capitalize" should set the property value]
- expected: FAIL
-
- [e.style['text-transform'\] = "lowercase full-size-kana full-width" should set the property value]
- expected: FAIL
-
- [e.style['text-transform'\] = "full-width lowercase" should set the property value]
- expected: FAIL
-
- [e.style['text-transform'\] = "full-size-kana" should set the property value]
- expected: FAIL
-
- [e.style['text-transform'\] = "full-width full-size-kana uppercase" should set the property value]
- expected: FAIL
-
- [e.style['text-transform'\] = "uppercase full-size-kana" should set the property value]
- expected: FAIL
-
- [e.style['text-transform'\] = "full-width uppercase full-size-kana" should set the property value]
- expected: FAIL
-
diff --git a/tests/wpt/metadata/css/css-text/word-break/word-break-break-all-005.html.ini b/tests/wpt/metadata/css/css-text/word-break/word-break-break-all-005.html.ini
new file mode 100644
index 00000000000..a2b9601ab6f
--- /dev/null
+++ b/tests/wpt/metadata/css/css-text/word-break/word-break-break-all-005.html.ini
@@ -0,0 +1,4 @@
+[word-break-break-all-005.html]
+ type: reftest
+ expected:
+ if os == "linux": FAIL
diff --git a/tests/wpt/metadata/css/css-variables/wide-keyword-fallback.html.ini b/tests/wpt/metadata/css/css-variables/wide-keyword-fallback.html.ini
deleted file mode 100644
index 3bdd09230d8..00000000000
--- a/tests/wpt/metadata/css/css-variables/wide-keyword-fallback.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[wide-keyword-fallback.html]
- expected: FAIL
diff --git a/tests/wpt/metadata/html/semantics/embedded-content/media-elements/mime-types/canPlayType.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/mime-types/canPlayType.html.ini
index bc63975b5c0..acc60d48f6a 100644
--- a/tests/wpt/metadata/html/semantics/embedded-content/media-elements/mime-types/canPlayType.html.ini
+++ b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/mime-types/canPlayType.html.ini
@@ -2,9 +2,6 @@
[video/mp4; codecs="mp4v.20.8" (optional)]
expected: FAIL
- [video/webm with bogus codec]
- expected: FAIL
-
[video/3gpp; codecs="samr" (optional)]
expected: FAIL
@@ -14,16 +11,10 @@
[audio/webm (optional)]
expected: FAIL
- [audio/mp4; codecs="mp4a.40.2" (optional)]
- expected: FAIL
-
- [audio/mp4 with bogus codec]
+ [audio/webm with and without codecs]
expected: FAIL
- [audio/webm; codecs="vorbis" (optional)]
- expected: FAIL
-
- [video/webm; codecs="vp9" (optional)]
+ [audio/mp4; codecs="mp4a.40.2" (optional)]
expected: FAIL
[video/ogg; codecs="theora" (optional)]
@@ -32,15 +23,6 @@
[video/mp4; codecs="avc1.64001E" (optional)]
expected: FAIL
- [video/ogg; codecs="opus" (optional)]
- expected: FAIL
-
- [fictional formats and codecs not supported]
- expected: FAIL
-
- [video/mp4 with bogus codec]
- expected: FAIL
-
[video/mp4 (optional)]
expected: FAIL
@@ -50,10 +32,10 @@
[audio/ogg; codecs="opus" (optional)]
expected: FAIL
- [video/webm; codecs="vp8.0" (optional)]
+ [video/webm (optional)]
expected: FAIL
- [video/webm (optional)]
+ [video/webm with and without codecs]
expected: FAIL
[video/mp4; codecs="avc1.4D401E" (optional)]
@@ -62,9 +44,6 @@
[audio/wav; codecs="1" (optional)]
expected: FAIL
- [video/3gpp with bogus codec]
- expected: FAIL
-
[audio/wav (optional)]
expected: FAIL
@@ -80,9 +59,6 @@
[audio/mp4 (optional)]
expected: FAIL
- [video/webm; codecs="opus" (optional)]
- expected: FAIL
-
[video/3gpp (optional)]
expected: FAIL
@@ -95,24 +71,8 @@
[audio/ogg; codecs="vorbis" (optional)]
expected: FAIL
- [audio/webm; codecs="opus" (optional)]
- expected: FAIL
-
- [video/webm; codecs="vorbis" (optional)]
- expected: FAIL
-
- [audio/wav with bogus codec]
+ [video/ogg; codecs="opus" (optional)]
expected: FAIL
[video/3gpp; codecs="mp4v.20.8" (optional)]
expected: FAIL
-
- [video/webm; codecs="vp9.0" (optional)]
- expected: FAIL
-
- [video/webm; codecs="vp8" (optional)]
- expected: FAIL
-
- [audio/webm with bogus codec]
- expected: FAIL
-