aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock81
-rw-r--r--components/config/opts.rs2
-rw-r--r--components/constellation/browsingcontext.rs (renamed from components/constellation/frame.rs)140
-rw-r--r--components/constellation/constellation.rs905
-rw-r--r--components/constellation/lib.rs2
-rw-r--r--components/constellation/pipeline.rs60
-rw-r--r--components/gfx/display_list/mod.rs18
-rw-r--r--components/layout/block.rs36
-rw-r--r--components/layout/display_list_builder.rs66
-rw-r--r--components/layout/flex.rs23
-rw-r--r--components/layout/fragment.rs80
-rw-r--r--components/layout/model.rs36
-rw-r--r--components/layout/webrender_helpers.rs27
-rw-r--r--components/layout_thread/lib.rs12
-rw-r--r--components/layout_traits/lib.rs4
-rw-r--r--components/msg/constellation_msg.rs42
-rw-r--r--components/profile/time.rs1
-rw-r--r--components/profile_traits/time.rs1
-rw-r--r--components/script/Cargo.toml1
-rw-r--r--components/script/dom/attr.rs8
-rw-r--r--components/script/dom/bindings/refcounted.rs39
-rw-r--r--components/script/dom/bindings/structuredclone.rs52
-rw-r--r--components/script/dom/bindings/trace.rs4
-rw-r--r--components/script/dom/dedicatedworkerglobalscope.rs8
-rw-r--r--components/script/dom/dissimilaroriginwindow.rs4
-rw-r--r--components/script/dom/document.rs6
-rw-r--r--components/script/dom/element.rs115
-rw-r--r--components/script/dom/globalscope.rs38
-rw-r--r--components/script/dom/htmliframeelement.rs32
-rw-r--r--components/script/dom/mod.rs4
-rw-r--r--components/script/dom/mutationobserver.rs216
-rw-r--r--components/script/dom/mutationrecord.rs83
-rw-r--r--components/script/dom/node.rs32
-rw-r--r--components/script/dom/promise.rs1
-rw-r--r--components/script/dom/testworklet.rs61
-rw-r--r--components/script/dom/testworkletglobalscope.rs66
-rw-r--r--components/script/dom/webidls/Console.webidl2
-rw-r--r--components/script/dom/webidls/EventTarget.webidl2
-rw-r--r--components/script/dom/webidls/GlobalScope.webidl2
-rw-r--r--components/script/dom/webidls/MutationObserver.webidl3
-rw-r--r--components/script/dom/webidls/MutationRecord.webidl18
-rw-r--r--components/script/dom/webidls/TestWorklet.webidl12
-rw-r--r--components/script/dom/webidls/TestWorkletGlobalScope.webidl11
-rw-r--r--components/script/dom/webidls/VoidFunction.webidl13
-rw-r--r--components/script/dom/webidls/Window.webidl1
-rw-r--r--components/script/dom/webidls/Worklet.webidl13
-rw-r--r--components/script/dom/webidls/WorkletGlobalScope.webidl10
-rw-r--r--components/script/dom/window.rs5
-rw-r--r--components/script/dom/windowproxy.rs24
-rw-r--r--components/script/dom/worklet.rs637
-rw-r--r--components/script/dom/workletglobalscope.rs143
-rw-r--r--components/script/layout_wrapper.rs162
-rw-r--r--components/script/lib.rs5
-rw-r--r--components/script/microtask.rs5
-rw-r--r--components/script/script_runtime.rs1
-rw-r--r--components/script/script_thread.rs178
-rw-r--r--components/script/webdriver_handlers.rs8
-rw-r--r--components/script_layout_interface/wrapper_traits.rs11
-rw-r--r--components/script_traits/Cargo.toml1
-rw-r--r--components/script_traits/lib.rs48
-rw-r--r--components/script_traits/script_msg.rs16
-rw-r--r--components/script_traits/webdriver_msg.rs2
-rw-r--r--components/selectors/Cargo.toml5
-rw-r--r--components/selectors/attr.rs190
-rw-r--r--components/selectors/build.rs75
-rw-r--r--components/selectors/gecko_like_types.rs3
-rw-r--r--components/selectors/lib.rs3
-rw-r--r--components/selectors/matching.rs284
-rw-r--r--components/selectors/parser.rs1091
-rw-r--r--components/selectors/size_of_tests.rs16
-rw-r--r--components/selectors/tree.rs154
-rw-r--r--components/selectors/visitor.rs11
-rw-r--r--components/servo/lib.rs2
-rw-r--r--components/style/Cargo.toml6
-rw-r--r--components/style/attr.rs17
-rw-r--r--components/style/build.rs2
-rw-r--r--components/style/build_gecko.rs809
-rw-r--r--components/style/dom.rs5
-rw-r--r--components/style/gecko/conversions.rs7
-rw-r--r--components/style/gecko/generated/bindings.rs25
-rw-r--r--components/style/gecko/generated/structs_debug.rs1004
-rw-r--r--components/style/gecko/generated/structs_release.rs623
-rw-r--r--components/style/gecko/global_style_data.rs17
-rw-r--r--components/style/gecko/non_ts_pseudo_class_list.rs3
-rw-r--r--components/style/gecko/pseudo_element.rs14
-rw-r--r--components/style/gecko/selector_parser.rs101
-rw-r--r--components/style/gecko/snapshot.rs154
-rw-r--r--components/style/gecko/wrapper.rs262
-rw-r--r--components/style/lib.rs1
-rw-r--r--components/style/matching.rs204
-rw-r--r--components/style/properties/gecko.mako.rs158
-rw-r--r--components/style/properties/helpers/animated_properties.mako.rs22
-rw-r--r--components/style/properties/longhand/background.mako.rs4
-rw-r--r--components/style/properties/longhand/border.mako.rs4
-rw-r--r--components/style/properties/longhand/color.mako.rs4
-rw-r--r--components/style/properties/longhand/font.mako.rs3
-rw-r--r--components/style/properties/longhand/inherited_text.mako.rs3
-rw-r--r--components/style/properties/longhand/position.mako.rs11
-rw-r--r--components/style/properties/properties.mako.rs37
-rw-r--r--components/style/properties/shorthand/background.mako.rs8
-rw-r--r--components/style/properties/shorthand/position.mako.rs4
-rw-r--r--components/style/restyle_hints.rs292
-rw-r--r--components/style/selector_parser.rs2
-rw-r--r--components/style/servo/restyle_damage.rs10
-rw-r--r--components/style/servo/selector_parser.rs104
-rw-r--r--components/style/stylist.rs263
-rw-r--r--components/style/values/computed/length.rs91
-rw-r--r--components/style/values/computed/mod.rs8
-rw-r--r--components/style/values/specified/calc.rs20
-rw-r--r--components/style/values/specified/color.rs14
-rw-r--r--components/style/values/specified/grid.rs663
-rw-r--r--components/style/values/specified/length.rs21
-rw-r--r--components/style/values/specified/mod.rs88
-rw-r--r--components/style/values/specified/position.rs11
-rw-r--r--components/style/viewport.rs3
-rw-r--r--components/style_traits/values.rs8
-rw-r--r--components/webdriver_server/lib.rs24
-rw-r--r--ports/cef/lib.rs1
-rw-r--r--ports/cef/stubs.rs4
-rw-r--r--ports/geckolib/glue.rs53
-rw-r--r--ports/servo/main.rs10
-rw-r--r--python/servo/build_commands.py8
-rw-r--r--python/tidy/servo_tidy/tidy.py11
-rw-r--r--resources/presentational-hints.css14
-rw-r--r--servo-tidy.toml3
-rw-r--r--tests/unit/script/size_of.rs14
-rw-r--r--tests/unit/style/attr.rs15
-rw-r--r--tests/unit/style/parsing/mod.rs32
-rw-r--r--tests/unit/style/parsing/position.rs67
-rw-r--r--tests/unit/style/stylesheets.rs78
-rw-r--r--tests/unit/style/stylist.rs4
-rw-r--r--tests/unit/stylo/Cargo.toml1
-rw-r--r--tests/unit/stylo/lib.rs1
-rw-r--r--tests/unit/stylo/size_of.rs4
-rw-r--r--tests/wpt/metadata-css/css-transforms-1_dev/html/css-transform-3d-transform-style.htm.ini3
-rw-r--r--tests/wpt/metadata-css/css-transforms-1_dev/html/transform3d-sorting-004.htm.ini4
-rw-r--r--tests/wpt/metadata-css/css-transforms-1_dev/html/transform3d-sorting-005.htm.ini3
-rw-r--r--tests/wpt/metadata-css/css-transforms-1_dev/html/transform3d-sorting-006.htm.ini1
-rw-r--r--tests/wpt/metadata-css/selectors-3_dev/html/css3-selectors-lang-024.htm.ini5
-rw-r--r--tests/wpt/metadata-css/selectors-3_dev/html/css3-selectors-lang-035.htm.ini5
-rw-r--r--tests/wpt/metadata-css/selectors-3_dev/html/css3-selectors-lang-044.htm.ini5
-rw-r--r--tests/wpt/metadata-css/selectors-3_dev/html/css3-selectors-lang-055.htm.ini5
-rw-r--r--tests/wpt/metadata/dom/nodes/MutationObserver-attributes.html.ini95
-rw-r--r--tests/wpt/metadata/dom/nodes/MutationObserver-characterData.html.ini39
-rw-r--r--tests/wpt/metadata/dom/nodes/MutationObserver-childList.html.ini65
-rw-r--r--tests/wpt/metadata/dom/nodes/MutationObserver-inner-outer.html.ini5
-rw-r--r--tests/wpt/metadata/html/rendering/non-replaced-elements/lists/li-type-supported-xhtml.xhtml.ini3
-rw-r--r--tests/wpt/metadata/html/rendering/non-replaced-elements/lists/li-type-supported.html.ini3
-rw-r--r--tests/wpt/metadata/quirks-mode/supports.html.ini3
-rw-r--r--tests/wpt/mozilla/meta/MANIFEST.json89
-rw-r--r--tests/wpt/mozilla/meta/mozilla/adopted_node_is_same_origin_domain.html.ini1
-rw-r--r--tests/wpt/mozilla/meta/mozilla/worklets/test_worklet.html.ini3
-rw-r--r--tests/wpt/mozilla/tests/css/min_width_percent_root_a.html16
-rw-r--r--tests/wpt/mozilla/tests/css/min_width_percent_root_b.html14
-rw-r--r--tests/wpt/mozilla/tests/css/transform_3d_from_outside_viewport.html33
-rw-r--r--tests/wpt/mozilla/tests/css/transform_3d_from_outside_viewport_ref.html15
-rw-r--r--tests/wpt/mozilla/tests/mozilla/interfaces.html1
-rw-r--r--tests/wpt/mozilla/tests/mozilla/worklets/syntax_error.js1
-rw-r--r--tests/wpt/mozilla/tests/mozilla/worklets/test_worklet.html35
-rw-r--r--tests/wpt/mozilla/tests/mozilla/worklets/test_worklet.js1
-rw-r--r--tests/wpt/mozilla/tests/mozilla/worklets/throw_exception.js1
161 files changed, 7193 insertions, 4188 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 3610f0cf2cb..bb087bfd3a2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -196,6 +196,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bitflags"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "bitflags"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -299,7 +304,7 @@ version = "0.0.1"
dependencies = [
"azure 0.15.0 (git+https://github.com/servo/rust-azure)",
"canvas_traits 0.0.1",
- "cssparser 0.13.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cssparser 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"ipc-channel 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -314,7 +319,7 @@ dependencies = [
name = "canvas_traits"
version = "0.0.1"
dependencies = [
- "cssparser 0.13.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cssparser 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
"heapsize 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -528,7 +533,7 @@ dependencies = [
[[package]]
name = "cssparser"
-version = "0.13.3"
+version = "0.13.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cssparser-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -959,7 +964,7 @@ name = "geckoservo"
version = "0.0.1"
dependencies = [
"atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cssparser 0.13.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cssparser 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1024,7 +1029,7 @@ dependencies = [
name = "gfx_tests"
version = "0.0.1"
dependencies = [
- "cssparser 0.13.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cssparser 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx 0.0.1",
"ipc-channel 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"style 0.0.1",
@@ -1366,7 +1371,7 @@ dependencies = [
"atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"canvas_traits 0.0.1",
- "cssparser 0.13.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cssparser 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx 0.0.1",
@@ -1701,7 +1706,7 @@ name = "msg"
version = "0.0.1"
dependencies = [
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cssparser 0.13.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cssparser 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)",
"heapsize 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2143,6 +2148,15 @@ dependencies = [
]
[[package]]
+name = "pulldown-cmark"
+version = "0.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "quasi"
version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2300,7 +2314,7 @@ dependencies = [
"caseless 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
"cookie 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "cssparser 0.13.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cssparser 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)",
"deny_public_fields 0.0.1",
"devtools_traits 0.0.1",
"dom_struct 0.0.1",
@@ -2351,6 +2365,7 @@ dependencies = [
"smallvec 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"style 0.0.1",
"style_traits 0.0.1",
+ "swapper 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"tinyfiledialogs 2.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2369,7 +2384,7 @@ dependencies = [
"app_units 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"canvas_traits 0.0.1",
- "cssparser 0.13.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cssparser 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx_traits 0.0.1",
"heapsize 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2407,7 +2422,6 @@ dependencies = [
name = "script_traits"
version = "0.0.1"
dependencies = [
- "app_units 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bluetooth_traits 0.0.1",
"canvas_traits 0.0.1",
"cookie 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2440,9 +2454,11 @@ name = "selectors"
version = "0.18.0"
dependencies = [
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cssparser 0.13.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cssparser 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
"precomputed-hash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"size_of_test 0.0.1",
"smallvec 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2739,6 +2755,15 @@ name = "size_of_test"
version = "0.0.1"
[[package]]
+name = "skeptic"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "pulldown-cmark 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "slab"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2798,13 +2823,14 @@ dependencies = [
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cssparser 0.13.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cssparser 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)",
"encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"heapsize 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"html5ever 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2828,6 +2854,7 @@ dependencies = [
"smallvec 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"style_traits 0.0.1",
"time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -2838,7 +2865,7 @@ version = "0.0.1"
dependencies = [
"app_units 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cssparser 0.13.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cssparser 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
"html5ever 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2857,7 +2884,7 @@ name = "style_traits"
version = "0.0.1"
dependencies = [
"app_units 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cssparser 0.13.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cssparser 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
"heapsize 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2870,19 +2897,26 @@ name = "stylo_tests"
version = "0.0.1"
dependencies = [
"atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cssparser 0.13.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cssparser 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
"geckoservo 0.0.1",
"libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"selectors 0.18.0",
"style 0.0.1",
"style_traits 0.0.1",
]
[[package]]
+name = "swapper"
+version = "0.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "skeptic 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "syn"
version = "0.11.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2969,6 +3003,14 @@ dependencies = [
]
[[package]]
+name = "tempdir"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "tendril"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3395,6 +3437,7 @@ dependencies = [
"checksum bindgen 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ccaf8958532d7e570e905266ee2dc1094c3e5c3c3cfc2c299368747a30a5e654"
"checksum bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9bf6104718e80d7b26a68fdbacff3481cfc05df670821affc7e9cbc1884400c"
"checksum bit-vec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5b97c2c8e8bbb4251754f559df8af22fb264853c7d009084a576cdf12565089d"
+"checksum bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4f67931368edf3a9a51d29886d245f1c3db2f1ef0dcc9e35ff70341b78c10d23"
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
"checksum bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4"
"checksum bitreader 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "80b13e2ab064ff3aa0bdbf1eff533f9822dc37899821f5f98c67f263eab51707"
@@ -3422,7 +3465,7 @@ dependencies = [
"checksum core-foundation-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "41115a6aa5d3e1e5ef98148373f25971d1fad53818553f216495f9e67e90a624"
"checksum core-graphics 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ead017dcf77f503dc991f6b52de6084eeea60a94b0a652baa9bf88654a28e83f"
"checksum core-text 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0e9719616a10f717628e074744f8c55df7b450f7a34d29c196d14f4498aad05d"
-"checksum cssparser 0.13.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9d2214de0e040001626d6a36020538d4b35a07cb260fcad0cf64f61fd1857e0e"
+"checksum cssparser 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)" = "88dc7bd2a41b9c6c66456ac709d9efead1deb390d2c252c59e0ddfff9cdf0c94"
"checksum cssparser-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "079adec4af52bb5275eadd004292028c79eb3c5f5b4ee8086a36d4197032f6df"
"checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850"
"checksum dbus 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "47f881971824401c27bc1ff9f641d54ac66e0f409631806fa7be8cad8e6be450"
@@ -3550,6 +3593,7 @@ dependencies = [
"checksum png 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3cb773e9a557edb568ce9935cf783e3cdcabe06a9449d41b3e5506d88e582c82"
"checksum precomputed-hash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf1fc3616b3ef726a847f2cd2388c646ef6a1f1ba4835c2629004da48184150"
"checksum procedural-masquerade 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9f566249236c6ca4340f7ca78968271f0ed2b0f234007a61b66f9ecd0af09260"
+"checksum pulldown-cmark 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1058d7bb927ca067656537eec4e02c2b4b70eaaa129664c5b90c111e20326f41"
"checksum quasi 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18c45c4854d6d1cf5d531db97c75880feb91c958b0720f4ec1057135fec358b3"
"checksum quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9e25fa23c044c1803f43ca59c98dac608976dd04ce799411edd58ece776d4"
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
@@ -3586,12 +3630,14 @@ dependencies = [
"checksum signpost 0.1.0 (git+https://github.com/pcwalton/signpost.git)" = "<none>"
"checksum simd 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a94d14a2ae1f1f110937de5fb69e494372560181c7e1739a097fcc2cee37ba0"
"checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537"
+"checksum skeptic 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dd7d8dc1315094150052d0ab767840376335a98ac66ef313ff911cdf439a5b69"
"checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23"
"checksum smallvec 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4f8266519bc1d17d0b5b16f6c21295625d562841c708f6376f49028a43e9c11e"
"checksum string_cache 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f55fba06c5e294108f22e8512eb598cb13388a117991e411a8df8f41a1219a75"
"checksum string_cache_codegen 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "479cde50c3539481f33906a387f2bd17c8e87cb848c35b6021d41fb81ff9b4d7"
"checksum string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc"
"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
+"checksum swapper 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca610b32bb8bfc5e7f705480c3a1edfeb70b6582495d343872c8bee0dcf758c"
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
"checksum synstructure 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5ccc9780bf1aa601943988c2876ab22413c01ad1739689aa6af18d0aa0b3f38b"
@@ -3600,6 +3646,7 @@ dependencies = [
"checksum syntex_pos 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "13ad4762fe52abc9f4008e85c4fb1b1fe3aa91ccb99ff4826a439c7c598e1047"
"checksum syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6e0e4dbae163dd98989464c23dd503161b338790640e11537686f2ef0f25c791"
"checksum target_build_utils 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f42dc058080c19c6a58bdd1bf962904ee4f5ef1fe2a81b529f31dacc750c679f"
+"checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6"
"checksum tendril 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4ce04c250d202db8004921e3d3bc95eaa4f2126c6937a428ae39d12d0e38df62"
"checksum term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d168af3930b369cfe245132550579d47dfd873d69470755a19c2c6568dbbd989"
"checksum term_size 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "07b6c1ac5b3fffd75073276bca1ceed01f67a28537097a2a9539e116e50fb21a"
diff --git a/components/config/opts.rs b/components/config/opts.rs
index 9130fb4cb5d..1b0938a5e9c 100644
--- a/components/config/opts.rs
+++ b/components/config/opts.rs
@@ -485,7 +485,7 @@ pub fn default_opts() -> Opts {
replace_surrogates: false,
gc_profile: false,
load_webfonts_synchronously: false,
- headless: true,
+ headless: false,
hard_fail: true,
bubble_inline_sizes_separately: false,
show_debug_fragment_borders: false,
diff --git a/components/constellation/frame.rs b/components/constellation/browsingcontext.rs
index ac85c14d214..5f6f29aecf6 100644
--- a/components/constellation/frame.rs
+++ b/components/constellation/browsingcontext.rs
@@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use euclid::size::TypedSize2D;
-use msg::constellation_msg::{FrameId, PipelineId};
+use msg::constellation_msg::{BrowsingContextId, PipelineId};
use pipeline::Pipeline;
use script_traits::LoadData;
use std::collections::HashMap;
@@ -12,17 +12,16 @@ use std::mem::replace;
use std::time::Instant;
use style_traits::CSSPixel;
-/// A frame in the frame tree.
-/// Each frame is the constellation's view of a browsing context.
+/// The constellation's view of a browsing context.
/// Each browsing context has a session history, caused by
-/// navigation and traversing the history. Each frame has its
+/// navigation and traversing the history. Each browsing contest has its
/// current entry, plus past and future entries. The past is sorted
/// chronologically, the future is sorted reverse chronologically:
/// in particular prev.pop() is the latest past entry, and
/// next.pop() is the earliest future entry.
-pub struct Frame {
- /// The frame id.
- pub id: FrameId,
+pub struct BrowsingContext {
+ /// The browsing context id.
+ pub id: BrowsingContextId,
/// The size of the frame.
pub size: Option<TypedSize2D<f32, CSSPixel>>,
@@ -37,17 +36,17 @@ pub struct Frame {
pub load_data: LoadData,
/// The past session history, ordered chronologically.
- pub prev: Vec<FrameState>,
+ pub prev: Vec<SessionHistoryEntry>,
/// The future session history, ordered reverse chronologically.
- pub next: Vec<FrameState>,
+ pub next: Vec<SessionHistoryEntry>,
}
-impl Frame {
- /// Create a new frame.
- /// Note this just creates the frame, it doesn't add it to the frame tree.
- pub fn new(id: FrameId, pipeline_id: PipelineId, load_data: LoadData) -> Frame {
- Frame {
+impl BrowsingContext {
+ /// Create a new browsing context.
+ /// Note this just creates the browsing context, it doesn't add it to the constellation's set of browsing contexts.
+ pub fn new(id: BrowsingContextId, pipeline_id: PipelineId, load_data: LoadData) -> BrowsingContext {
+ BrowsingContext {
id: id,
size: None,
pipeline_id: pipeline_id,
@@ -58,17 +57,17 @@ impl Frame {
}
}
- /// Get the current frame state.
- pub fn current(&self) -> FrameState {
- FrameState {
+ /// Get the current session history entry.
+ pub fn current(&self) -> SessionHistoryEntry {
+ SessionHistoryEntry {
instant: self.instant,
- frame_id: self.id,
+ browsing_context_id: self.id,
pipeline_id: Some(self.pipeline_id),
load_data: self.load_data.clone(),
}
}
- /// Set the current frame entry, and push the current frame entry into the past.
+ /// Set the current session history entry, and push the current frame entry into the past.
pub fn load(&mut self, pipeline_id: PipelineId, load_data: LoadData) {
let current = self.current();
self.prev.push(current);
@@ -78,25 +77,27 @@ impl Frame {
}
/// Set the future to be empty.
- pub fn remove_forward_entries(&mut self) -> Vec<FrameState> {
+ pub fn remove_forward_entries(&mut self) -> Vec<SessionHistoryEntry> {
replace(&mut self.next, vec!())
}
- /// Update the current entry of the Frame from an entry that has been traversed to.
- pub fn update_current(&mut self, pipeline_id: PipelineId, entry: FrameState) {
+ /// Update the current entry of the BrowsingContext from an entry that has been traversed to.
+ pub fn update_current(&mut self, pipeline_id: PipelineId, entry: SessionHistoryEntry) {
self.pipeline_id = pipeline_id;
self.instant = entry.instant;
self.load_data = entry.load_data;
}
}
-/// An entry in a frame's session history.
+/// An entry in a browsing context's session history.
/// Each entry stores the pipeline id for a document in the session history.
///
/// When we operate on the joint session history, entries are sorted chronologically,
/// so we timestamp the entries by when the entry was added to the session history.
+///
+/// https://html.spec.whatwg.org/multipage/#session-history-entry
#[derive(Clone)]
-pub struct FrameState {
+pub struct SessionHistoryEntry {
/// The timestamp for when the session history entry was created
pub instant: Instant,
@@ -108,14 +109,14 @@ pub struct FrameState {
pub load_data: LoadData,
/// The frame that this session history entry is part of
- pub frame_id: FrameId,
+ pub browsing_context_id: BrowsingContextId,
}
-/// Represents a pending change in the frame tree, that will be applied
+/// Represents a pending change in a session history, that will be applied
/// once the new pipeline has loaded and completed initial layout / paint.
-pub struct FrameChange {
- /// The frame to change.
- pub frame_id: FrameId,
+pub struct SessionHistoryChange {
+ /// The browsing context to change.
+ pub browsing_context_id: BrowsingContextId,
/// The pipeline for the document being loaded.
pub new_pipeline_id: PipelineId,
@@ -129,16 +130,15 @@ pub struct FrameChange {
pub replace_instant: Option<Instant>,
}
-/// An iterator over a frame tree, returning the fully active frames in
-/// depth-first order. Note that this iterator only returns the fully
-/// active frames, that is ones where every ancestor frame is
-/// in the currently active pipeline of its parent frame.
-pub struct FrameTreeIterator<'a> {
- /// The frames still to iterate over.
- pub stack: Vec<FrameId>,
+/// An iterator over browsing contexts, returning the descendant
+/// contexts whose active documents are fully active, in depth-first
+/// order.
+pub struct FullyActiveBrowsingContextsIterator<'a> {
+ /// The browsing contexts still to iterate over.
+ pub stack: Vec<BrowsingContextId>,
- /// The set of all frames.
- pub frames: &'a HashMap<FrameId, Frame>,
+ /// The set of all browsing contexts.
+ pub browsing_contexts: &'a HashMap<BrowsingContextId, BrowsingContext>,
/// The set of all pipelines. We use this to find the active
/// children of a frame, which are the iframes in the currently
@@ -146,73 +146,73 @@ pub struct FrameTreeIterator<'a> {
pub pipelines: &'a HashMap<PipelineId, Pipeline>,
}
-impl<'a> Iterator for FrameTreeIterator<'a> {
- type Item = &'a Frame;
- fn next(&mut self) -> Option<&'a Frame> {
+impl<'a> Iterator for FullyActiveBrowsingContextsIterator<'a> {
+ type Item = &'a BrowsingContext;
+ fn next(&mut self) -> Option<&'a BrowsingContext> {
loop {
- let frame_id = match self.stack.pop() {
- Some(frame_id) => frame_id,
+ let browsing_context_id = match self.stack.pop() {
+ Some(browsing_context_id) => browsing_context_id,
None => return None,
};
- let frame = match self.frames.get(&frame_id) {
- Some(frame) => frame,
+ let browsing_context = match self.browsing_contexts.get(&browsing_context_id) {
+ Some(browsing_context) => browsing_context,
None => {
- warn!("Frame {:?} iterated after closure.", frame_id);
+ warn!("BrowsingContext {:?} iterated after closure.", browsing_context_id);
continue;
},
};
- let pipeline = match self.pipelines.get(&frame.pipeline_id) {
+ let pipeline = match self.pipelines.get(&browsing_context.pipeline_id) {
Some(pipeline) => pipeline,
None => {
- warn!("Pipeline {:?} iterated after closure.", frame.pipeline_id);
+ warn!("Pipeline {:?} iterated after closure.", browsing_context.pipeline_id);
continue;
},
};
self.stack.extend(pipeline.children.iter());
- return Some(frame)
+ return Some(browsing_context)
}
}
}
-/// An iterator over a frame tree, returning all frames in depth-first
-/// order. Note that this iterator returns all frames, not just the
-/// fully active ones.
-pub struct FullFrameTreeIterator<'a> {
- /// The frames still to iterate over.
- pub stack: Vec<FrameId>,
+/// An iterator over browsing contexts, returning all descendant
+/// contexts in depth-first order. Note that this iterator returns all
+/// contexts, not just the fully active ones.
+pub struct AllBrowsingContextsIterator<'a> {
+ /// The browsing contexts still to iterate over.
+ pub stack: Vec<BrowsingContextId>,
- /// The set of all frames.
- pub frames: &'a HashMap<FrameId, Frame>,
+ /// The set of all browsing contexts.
+ pub browsing_contexts: &'a HashMap<BrowsingContextId, BrowsingContext>,
/// The set of all pipelines. We use this to find the
- /// children of a frame, which are the iframes in all documents
+ /// children of a browsing context, which are the iframes in all documents
/// in the session history.
pub pipelines: &'a HashMap<PipelineId, Pipeline>,
}
-impl<'a> Iterator for FullFrameTreeIterator<'a> {
- type Item = &'a Frame;
- fn next(&mut self) -> Option<&'a Frame> {
+impl<'a> Iterator for AllBrowsingContextsIterator<'a> {
+ type Item = &'a BrowsingContext;
+ fn next(&mut self) -> Option<&'a BrowsingContext> {
let pipelines = self.pipelines;
loop {
- let frame_id = match self.stack.pop() {
- Some(frame_id) => frame_id,
+ let browsing_context_id = match self.stack.pop() {
+ Some(browsing_context_id) => browsing_context_id,
None => return None,
};
- let frame = match self.frames.get(&frame_id) {
- Some(frame) => frame,
+ let browsing_context = match self.browsing_contexts.get(&browsing_context_id) {
+ Some(browsing_context) => browsing_context,
None => {
- warn!("Frame {:?} iterated after closure.", frame_id);
+ warn!("BrowsingContext {:?} iterated after closure.", browsing_context_id);
continue;
},
};
- let child_frame_ids = frame.prev.iter().chain(frame.next.iter())
+ let child_browsing_context_ids = browsing_context.prev.iter().chain(browsing_context.next.iter())
.filter_map(|entry| entry.pipeline_id)
- .chain(once(frame.pipeline_id))
+ .chain(once(browsing_context.pipeline_id))
.filter_map(|pipeline_id| pipelines.get(&pipeline_id))
.flat_map(|pipeline| pipeline.children.iter());
- self.stack.extend(child_frame_ids);
- return Some(frame)
+ self.stack.extend(child_browsing_context_ids);
+ return Some(browsing_context)
}
}
}
diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs
index 01a59070730..c16ff8c2049 100644
--- a/components/constellation/constellation.rs
+++ b/components/constellation/constellation.rs
@@ -16,32 +16,34 @@
//! layout threads. Pipelines may share script threads, but not
//! layout threads.
//!
-//! * The set of all `Frame` objects. Each frame gives the constellation's
-//! view of a browsing context. Each browsing context stores an independent
-//! session history, created by navigation of that frame. The session
+//! * The set of all `BrowsingContext` objects. Each browsing context
+//! gives the constellation's view of a `WindowProxy`.
+//! Each browsing context stores an independent
+//! session history, created by navigation. The session
//! history can be traversed, for example by the back and forwards UI,
//! so each session history maintains a list of past and future pipelines,
//! as well as the current active pipeline.
//!
-//! There are two kinds of frames: top-level frames (for example tabs
-//! in a browser UI), and nested frames (typically caused by `iframe`
-//! elements). Frames have a hierarchy (typically caused by `iframe`s
-//! containing `iframe`s), giving rise to a frame tree with a root frame.
-//! The logical relationship between these types is:
+//! There are two kinds of browsing context: top-level ones (for
+//! example tabs in a browser UI), and nested ones (typically caused
+//! by `iframe` elements). Browsing contexts have a hierarchy
+//! (typically caused by `iframe`s containing `iframe`s), giving rise
+//! to a tree with a root top-level browsing context. The logical
+//! relationship between these types is:
//!
//! ```
-//! +---------+ +------------+ +-------------+
-//! | Frame | --parent?--> | Pipeline | --event_loop--> | EventLoop |
-//! | | --current--> | | | |
-//! | | --prev*----> | | <---pipeline*-- | |
-//! | | --next*----> | | +-------------+
-//! | | | |
-//! | | <----frame-- | |
-//! +---------+ +------------+
+//! +------------+ +------------+ +---------+
+//! | Browsing | ------parent?------> | Pipeline | --event_loop--> | Event |
+//! | Context | ------current------> | | | Loop |
+//! | | ------prev*--------> | | <---pipeline*-- | |
+//! | | ------next*--------> | | +---------+
+//! | | | |
+//! | | <-browsing_context-- | |
+//! +------------+ +------------+
//! ```
//
//! Complicating matters, there are also mozbrowser iframes, which are top-level
-//! frames with a parent.
+//! iframes with a parent.
//!
//! The constellation also maintains channels to threads, including:
//!
@@ -53,7 +55,7 @@
//! * The devtools, debugger and webdriver servers.
//!
//! The constellation passes messages between the threads, and updates its state
-//! to track the evolving state of the frame tree.
+//! to track the evolving state of the browsing context tree.
//!
//! The constellation acts as a logger, tracking any `warn!` messages from threads,
//! and converting any `error!` or `panic!` into a crash report, which is filed
@@ -64,6 +66,8 @@
use backtrace::Backtrace;
use bluetooth_traits::BluetoothRequest;
+use browsingcontext::{BrowsingContext, SessionHistoryChange, SessionHistoryEntry};
+use browsingcontext::{FullyActiveBrowsingContextsIterator, AllBrowsingContextsIterator};
use canvas::canvas_paint_thread::CanvasPaintThread;
use canvas::webgl_paint_thread::WebGLPaintThread;
use canvas_traits::CanvasMsg;
@@ -75,7 +79,6 @@ use devtools_traits::{ChromeToDevtoolsControlMsg, DevtoolsControlMsg};
use euclid::scale_factor::ScaleFactor;
use euclid::size::{Size2D, TypedSize2D};
use event_loop::EventLoop;
-use frame::{Frame, FrameChange, FrameState, FrameTreeIterator, FullFrameTreeIterator};
use gfx::font_cache_thread::FontCacheThread;
use gfx_traits::Epoch;
use ipc_channel::{Error as IpcError};
@@ -84,7 +87,7 @@ use ipc_channel::router::ROUTER;
use itertools::Itertools;
use layout_traits::LayoutThreadFactory;
use log::{Log, LogLevel, LogLevelFilter, LogMetadata, LogRecord};
-use msg::constellation_msg::{FrameId, FrameType, PipelineId};
+use msg::constellation_msg::{BrowsingContextId, FrameType, PipelineId};
use msg::constellation_msg::{Key, KeyModifiers, KeyState};
use msg::constellation_msg::{PipelineNamespace, PipelineNamespaceId, TraversalDirection};
use net_traits::{self, IpcSend, ResourceThreads};
@@ -222,32 +225,33 @@ pub struct Constellation<Message, LTF, STF> {
/// The set of all event loops in the browser. We generate a new
/// event loop for each registered domain name (aka eTLD+1) in
- /// each top-level frame. We store the event loops in a map
- /// indexed by top-level frame id (as a `FrameId`) and registered
+ /// each top-level browsing context. We store the event loops in a map
+ /// indexed by top-level browsing context id
+ /// (as a `BrowsingContextId`) and registered
/// domain name (as a `Host`) to event loops. This double
/// indirection ensures that separate tabs do not share event
/// loops, even if the same domain is loaded in each.
/// It is important that scripts with the same eTLD+1
/// share an event loop, since they can use `document.domain`
/// to become same-origin, at which point they can share DOM objects.
- event_loops: HashMap<FrameId, HashMap<Host, Weak<EventLoop>>>,
+ event_loops: HashMap<BrowsingContextId, HashMap<Host, Weak<EventLoop>>>,
/// The set of all the pipelines in the browser.
/// (See the `pipeline` module for more details.)
pipelines: HashMap<PipelineId, Pipeline>,
- /// The set of all the frames in the browser.
- frames: HashMap<FrameId, Frame>,
+ /// The set of all the browsing contexts in the browser.
+ browsing_contexts: HashMap<BrowsingContextId, BrowsingContext>,
/// When a navigation is performed, we do not immediately update
- /// the frame tree, instead we ask the event loop to begin loading
- /// the new document, and do not update the frame tree until the
+ /// the session history, instead we ask the event loop to begin loading
+ /// the new document, and do not update the browsing context until the
/// document is active. Between starting the load and it activating,
- /// we store a `FrameChange` object for the navigation in progress.
- pending_frames: Vec<FrameChange>,
+ /// we store a `SessionHistoryChange` object for the navigation in progress.
+ pending_changes: Vec<SessionHistoryChange>,
- /// The root frame.
- root_frame_id: FrameId,
+ /// The root browsing context.
+ root_browsing_context_id: BrowsingContextId,
/// The currently focused pipeline for key events.
focus_pipeline_id: Option<PipelineId>,
@@ -339,8 +343,8 @@ impl WebDriverData {
/// This enum gives the possible states of preparing such an image.
#[derive(Debug, PartialEq)]
enum ReadyToSave {
- NoRootFrame,
- PendingFrames,
+ NoRootBrowsingContext,
+ PendingChanges,
WebFontNotLoaded,
DocumentLoading,
EpochMismatch,
@@ -391,9 +395,9 @@ impl Log for FromScriptLogger {
fn log(&self, record: &LogRecord) {
if let Some(entry) = log_entry(record) {
debug!("Sending log entry {:?}.", entry);
- let top_level_frame_id = FrameId::installed();
+ let top_level_id = BrowsingContextId::installed();
let thread_name = thread::current().name().map(ToOwned::to_owned);
- let msg = FromScriptMsg::LogEntry(top_level_frame_id, thread_name, entry);
+ let msg = FromScriptMsg::LogEntry(top_level_id, thread_name, entry);
let chan = self.constellation_chan.lock().unwrap_or_else(|err| err.into_inner());
let _ = chan.send(msg);
}
@@ -429,9 +433,9 @@ impl Log for FromCompositorLogger {
fn log(&self, record: &LogRecord) {
if let Some(entry) = log_entry(record) {
debug!("Sending log entry {:?}.", entry);
- let top_level_frame_id = FrameId::installed();
+ let top_level_id = BrowsingContextId::installed();
let thread_name = thread::current().name().map(ToOwned::to_owned);
- let msg = FromCompositorMsg::LogEntry(top_level_frame_id, thread_name, entry);
+ let msg = FromCompositorMsg::LogEntry(top_level_id, thread_name, entry);
let chan = self.constellation_chan.lock().unwrap_or_else(|err| err.into_inner());
let _ = chan.send(msg);
}
@@ -516,11 +520,11 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
swmanager_sender: sw_mgr_clone,
event_loops: HashMap::new(),
pipelines: HashMap::new(),
- frames: HashMap::new(),
- pending_frames: vec!(),
+ browsing_contexts: HashMap::new(),
+ pending_changes: vec!(),
// We initialize the namespace at 1, since we reserved namespace 0 for the constellation
next_pipeline_namespace_id: PipelineNamespaceId(1),
- root_frame_id: FrameId::new(),
+ root_browsing_context_id: BrowsingContextId::new(),
focus_pipeline_id: None,
time_profiler_chan: state.time_profiler_chan,
mem_profiler_chan: state.mem_profiler_chan,
@@ -575,7 +579,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
/// Helper function for creating a pipeline
fn new_pipeline(&mut self,
pipeline_id: PipelineId,
- frame_id: FrameId,
+ browsing_context_id: BrowsingContextId,
parent_info: Option<(PipelineId, FrameType)>,
initial_window_size: Option<TypedSize2D<f32, CSSPixel>>,
// TODO: we have to provide ownership of the LoadData
@@ -589,13 +593,13 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
// TODO: can we get a case where the child pipeline is created
// before the parent is part of the frame tree?
- let top_level_frame_id = match parent_info {
- Some((_, FrameType::MozBrowserIFrame)) => frame_id,
- Some((parent_id, _)) => self.get_top_level_frame_for_pipeline(parent_id),
- None => self.root_frame_id,
+ let top_level_id = match parent_info {
+ Some((_, FrameType::MozBrowserIFrame)) => browsing_context_id,
+ Some((parent_id, _)) => self.get_top_level_browsing_context_for_pipeline(parent_id),
+ None => self.root_browsing_context_id,
};
- debug!("Creating new pipeline {} in top-level frame {}.", pipeline_id, top_level_frame_id);
+ debug!("Creating new pipeline {} in top-level browsing context {}.", pipeline_id, top_level_id);
let (event_loop, host) = match sandbox {
IFrameSandboxState::IFrameSandboxed => (None, None),
@@ -606,7 +610,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
match reg_host(&load_data.url) {
None => (None, None),
Some(host) => {
- let event_loop = self.event_loops.get(&top_level_frame_id)
+ let event_loop = self.event_loops.get(&top_level_id)
.and_then(|map| map.get(&host))
.and_then(|weak| weak.upgrade());
match event_loop {
@@ -637,23 +641,23 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
.and_then(|(parent_pipeline_id, _)| self.pipelines.get(&parent_pipeline_id))
.map(|pipeline| pipeline.visible);
- let prev_visibility = self.frames.get(&frame_id)
- .and_then(|frame| self.pipelines.get(&frame.pipeline_id))
+ let prev_visibility = self.browsing_contexts.get(&browsing_context_id)
+ .and_then(|browsing_context| self.pipelines.get(&browsing_context.pipeline_id))
.map(|pipeline| pipeline.visible)
.or(parent_visibility);
// TODO: think about the case where the child pipeline is created
// before the parent is part of the frame tree.
- let top_level_frame_id = match parent_info {
- Some((_, FrameType::MozBrowserIFrame)) => frame_id,
- Some((parent_id, _)) => self.get_top_level_frame_for_pipeline(parent_id),
- None => self.root_frame_id,
+ let top_level_browsing_context_id = match parent_info {
+ Some((_, FrameType::MozBrowserIFrame)) => browsing_context_id,
+ Some((parent_id, _)) => self.get_top_level_browsing_context_for_pipeline(parent_id),
+ None => self.root_browsing_context_id,
};
let result = Pipeline::spawn::<Message, LTF, STF>(InitialPipelineState {
id: pipeline_id,
- frame_id: frame_id,
- top_level_frame_id: top_level_frame_id,
+ browsing_context_id: browsing_context_id,
+ top_level_browsing_context_id: top_level_browsing_context_id,
parent_info: parent_info,
constellation_chan: self.script_sender.clone(),
layout_to_constellation_chan: self.layout_sender.clone(),
@@ -683,8 +687,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
};
if let Some(host) = host {
- debug!("Adding new host entry {} for top-level frame {}.", host, top_level_frame_id);
- self.event_loops.entry(top_level_frame_id)
+ debug!("Adding new host entry {} for top-level browsing context {}.", host, top_level_browsing_context_id);
+ self.event_loops.entry(top_level_browsing_context_id)
.or_insert_with(HashMap::new)
.insert(host, Rc::downgrade(&pipeline.event_loop));
}
@@ -693,75 +697,84 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
self.pipelines.insert(pipeline_id, pipeline);
}
- /// Get an iterator for the current frame tree. Specify self.root_frame_id to
- /// iterate the entire tree, or a specific frame id to iterate only that sub-tree.
- /// Iterates over the fully active frames in the tree.
- fn current_frame_tree_iter(&self, frame_id_root: FrameId) -> FrameTreeIterator {
- FrameTreeIterator {
- stack: vec!(frame_id_root),
+ /// Get an iterator for browsing contexts. Specify self.root_browsing context_id to
+ /// iterate the entire tree, or a specific browsing context id to iterate only that sub-tree.
+ /// Iterates over the fully active browsing contexts in the tree.
+ fn fully_active_browsing_contexts_iter(&self, browsing_context_id: BrowsingContextId)
+ -> FullyActiveBrowsingContextsIterator
+ {
+ FullyActiveBrowsingContextsIterator {
+ stack: vec!(browsing_context_id),
pipelines: &self.pipelines,
- frames: &self.frames,
+ browsing_contexts: &self.browsing_contexts,
}
}
- /// Get an iterator for the current frame tree. Specify self.root_frame_id to
- /// iterate the entire tree, or a specific frame id to iterate only that sub-tree.
- /// Iterates over all frames in the tree.
- fn full_frame_tree_iter(&self, frame_id_root: FrameId) -> FullFrameTreeIterator {
- FullFrameTreeIterator {
- stack: vec!(frame_id_root),
+ /// Get an iterator for browsing contexts. Specify self.root_browsing_context_id to
+ /// iterate the entire tree, or a specific browsing context id to iterate only that sub-tree.
+ /// Iterates over all browsing contexts in the tree.
+ fn all_browsing_contexts_iter(&self, browsing_context_id: BrowsingContextId)
+ -> AllBrowsingContextsIterator
+ {
+ AllBrowsingContextsIterator {
+ stack: vec!(browsing_context_id),
pipelines: &self.pipelines,
- frames: &self.frames,
+ browsing_contexts: &self.browsing_contexts,
}
}
/// The joint session future is the merge of the session future of every
- /// frame in the frame tree, sorted chronologically.
- fn joint_session_future<'a>(&'a self, frame_id_root: FrameId) -> impl Iterator<Item = &'a FrameState> + 'a {
- self.full_frame_tree_iter(frame_id_root)
- .map(|frame| frame.next.iter().rev())
+ /// browsing_context, sorted chronologically.
+ fn joint_session_future<'a>(&'a self, browsing_context_id: BrowsingContextId)
+ -> impl Iterator<Item = &'a SessionHistoryEntry> + 'a
+ {
+ self.all_browsing_contexts_iter(browsing_context_id)
+ .map(|browsing_context| browsing_context.next.iter().rev())
.kmerge_by(|a, b| a.instant.cmp(&b.instant) == Ordering::Less)
}
/// Is the joint session future empty?
- fn joint_session_future_is_empty(&self, frame_id_root: FrameId) -> bool {
- self.full_frame_tree_iter(frame_id_root)
- .all(|frame| frame.next.is_empty())
+ fn joint_session_future_is_empty(&self, browsing_context_id: BrowsingContextId) -> bool {
+ self.all_browsing_contexts_iter(browsing_context_id)
+ .all(|browsing_context| browsing_context.next.is_empty())
}
/// The joint session past is the merge of the session past of every
- /// frame in the frame tree, sorted reverse chronologically.
- fn joint_session_past<'a>(&'a self, frame_id_root: FrameId) -> impl Iterator<Item = &'a FrameState> + 'a {
- self.full_frame_tree_iter(frame_id_root)
- .map(|frame| frame.prev.iter().rev().scan(frame.instant, |prev_instant, entry| {
- let instant = *prev_instant;
- *prev_instant = entry.instant;
- Some((instant, entry))
- }))
+ /// browsing_context, sorted reverse chronologically.
+ fn joint_session_past<'a>(&'a self, browsing_context_id: BrowsingContextId)
+ -> impl Iterator<Item = &'a SessionHistoryEntry> + 'a
+ {
+ self.all_browsing_contexts_iter(browsing_context_id)
+ .map(|browsing_context| browsing_context.prev.iter().rev()
+ .scan(browsing_context.instant, |prev_instant, entry| {
+ let instant = *prev_instant;
+ *prev_instant = entry.instant;
+ Some((instant, entry))
+ }))
.kmerge_by(|a, b| a.0.cmp(&b.0) == Ordering::Greater)
.map(|(_, entry)| entry)
}
/// Is the joint session past empty?
- fn joint_session_past_is_empty(&self, frame_id_root: FrameId) -> bool {
- self.full_frame_tree_iter(frame_id_root)
- .all(|frame| frame.prev.is_empty())
+ fn joint_session_past_is_empty(&self, browsing_context_id: BrowsingContextId) -> bool {
+ self.all_browsing_contexts_iter(browsing_context_id)
+ .all(|browsing_context| browsing_context.prev.is_empty())
}
- /// Create a new frame and update the internal bookkeeping.
- fn new_frame(&mut self,
- frame_id: FrameId,
+ /// Create a new browsing context and update the internal bookkeeping.
+ fn new_browsing_context(&mut self,
+ browsing_context_id: BrowsingContextId,
pipeline_id: PipelineId,
load_data: LoadData) {
- let frame = Frame::new(frame_id, pipeline_id, load_data);
- self.frames.insert(frame_id, frame);
+ let browsing_context = BrowsingContext::new(browsing_context_id, pipeline_id, load_data);
+ self.browsing_contexts.insert(browsing_context_id, browsing_context);
- // If a child frame, add it to the parent pipeline.
+ // If a child browsing_context, add it to the parent pipeline.
let parent_info = self.pipelines.get(&pipeline_id)
.and_then(|pipeline| pipeline.parent_info);
if let Some((parent_id, _)) = parent_info {
if let Some(parent) = self.pipelines.get_mut(&parent_id) {
- parent.add_child(frame_id);
+ parent.add_child(browsing_context_id);
}
}
}
@@ -810,8 +823,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
// Treat deserialization error the same as receiving a panic message
debug!("Deserialization failed ({:?}).", err);
let reason = format!("Deserialization failed ({})", err);
- let root_frame_id = self.root_frame_id;
- return self.handle_panic(root_frame_id, reason, None);
+ let root_browsing_context_id = self.root_browsing_context_id;
+ return self.handle_panic(root_browsing_context_id, reason, None);
}
};
@@ -846,13 +859,13 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
debug!("constellation exiting");
self.handle_exit();
}
- FromCompositorMsg::GetFrame(pipeline_id, resp_chan) => {
- debug!("constellation got get root pipeline message");
- self.handle_get_frame(pipeline_id, resp_chan);
+ FromCompositorMsg::GetBrowsingContext(pipeline_id, resp_chan) => {
+ debug!("constellation got get browsing context message");
+ self.handle_get_browsing_context(pipeline_id, resp_chan);
}
- FromCompositorMsg::GetPipeline(frame_id, resp_chan) => {
+ FromCompositorMsg::GetPipeline(browsing_context_id, resp_chan) => {
debug!("constellation got get root pipeline message");
- self.handle_get_pipeline(frame_id, resp_chan);
+ self.handle_get_pipeline(browsing_context_id, resp_chan);
}
FromCompositorMsg::GetPipelineTitle(pipeline_id) => {
debug!("constellation got get-pipeline-title message");
@@ -863,7 +876,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
self.handle_key_msg(ch, key, state, modifiers);
}
// Load a new page from a typed url
- // If there is already a pending page (self.pending_frames), it will not be overridden;
+ // If there is already a pending page (self.pending_changes), it will not be overridden;
// However, if the id is not encompassed by another change, it will be.
FromCompositorMsg::LoadUrl(source_id, load_data) => {
debug!("constellation got URL load message from compositor");
@@ -906,8 +919,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
debug!("constellation got reload message");
self.handle_reload_msg();
}
- FromCompositorMsg::LogEntry(top_level_frame_id, thread_name, entry) => {
- self.handle_log_entry(top_level_frame_id, thread_name, entry);
+ FromCompositorMsg::LogEntry(top_level_browsing_context_id, thread_name, entry) => {
+ self.handle_log_entry(top_level_browsing_context_id, thread_name, entry);
}
FromCompositorMsg::SetWebVRThread(webvr_thread) => {
assert!(self.webvr_thread.is_none());
@@ -942,7 +955,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
self.handle_change_running_animations_state(pipeline_id, animation_state)
}
// Load a new page from a mouse click
- // If there is already a pending page (self.pending_frames), it will not be overridden;
+ // If there is already a pending page (self.pending_changes), it will not be overridden;
// However, if the id is not encompassed by another change, it will be.
FromScriptMsg::LoadUrl(source_id, load_data, replace) => {
debug!("constellation got URL load message from script");
@@ -978,9 +991,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
warn!("constellation got set final url message for dead pipeline");
}
}
- FromScriptMsg::PostMessage(frame_id, origin, data) => {
+ FromScriptMsg::PostMessage(browsing_context_id, origin, data) => {
debug!("constellation got postMessage message");
- self.handle_post_message_msg(frame_id, origin, data);
+ self.handle_post_message_msg(browsing_context_id, origin, data);
}
FromScriptMsg::MozBrowserEvent(parent_pipeline_id, pipeline_id, event) => {
debug!("constellation got mozbrowser event message");
@@ -1017,9 +1030,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
debug!("constellation got set visibility change complete message");
self.handle_visibility_change_complete(pipeline_id, visible);
}
- FromScriptMsg::RemoveIFrame(frame_id, sender) => {
+ FromScriptMsg::RemoveIFrame(browsing_context_id, sender) => {
debug!("constellation got remove iframe message");
- let removed_pipeline_ids = self.handle_remove_iframe_msg(frame_id);
+ let removed_pipeline_ids = self.handle_remove_iframe_msg(browsing_context_id);
if let Err(e) = sender.send(removed_pipeline_ids) {
warn!("Error replying to remove iframe ({})", e);
}
@@ -1074,8 +1087,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
FromScriptMsg::Exit => {
self.compositor_proxy.send(ToCompositorMsg::Exit);
}
- FromScriptMsg::LogEntry(top_level_frame_id, thread_name, entry) => {
- self.handle_log_entry(top_level_frame_id, thread_name, entry);
+ FromScriptMsg::LogEntry(top_level_browsing_context_id, thread_name, entry) => {
+ self.handle_log_entry(top_level_browsing_context_id, thread_name, entry);
}
FromScriptMsg::SetTitle(pipeline_id, title) => {
@@ -1089,10 +1102,10 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
FromScriptMsg::TouchEventProcessed(result) => {
self.compositor_proxy.send(ToCompositorMsg::TouchEventProcessed(result))
}
- FromScriptMsg::GetFrameId(pipeline_id, sender) => {
- let result = self.pipelines.get(&pipeline_id).map(|pipeline| pipeline.frame_id);
+ FromScriptMsg::GetBrowsingContextId(pipeline_id, sender) => {
+ let result = self.pipelines.get(&pipeline_id).map(|pipeline| pipeline.browsing_context_id);
if let Err(e) = sender.send(result) {
- warn!("Sending reply to get frame id failed ({:?}).", e);
+ warn!("Sending reply to get browsing context failed ({:?}).", e);
}
}
FromScriptMsg::GetParentInfo(pipeline_id, sender) => {
@@ -1128,9 +1141,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
}
// Layout sends new sizes for all subframes. This needs to be reflected by all
// frame trees in the navigation context containing the subframe.
- FromLayoutMsg::FrameSizes(iframe_sizes) => {
- debug!("constellation got frame size message");
- self.handle_frame_size_msg(iframe_sizes);
+ FromLayoutMsg::IFrameSizes(iframe_sizes) => {
+ debug!("constellation got iframe size message");
+ self.handle_iframe_size_msg(iframe_sizes);
}
FromLayoutMsg::SetCursor(cursor) => {
self.handle_set_cursor_msg(cursor)
@@ -1172,24 +1185,24 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
self.mem_profiler_chan.send(mem::ProfilerMsg::Exit);
- // TODO: exit before the root frame is initialized?
- debug!("Removing root frame.");
- let root_frame_id = self.root_frame_id;
- self.close_frame(root_frame_id, ExitPipelineMode::Normal);
+ // TODO: exit before the root browsing context is initialized?
+ debug!("Removing root browsing context.");
+ let root_browsing_context_id = self.root_browsing_context_id;
+ self.close_browsing_context(root_browsing_context_id, ExitPipelineMode::Normal);
- // Close any pending frames and pipelines
- while let Some(pending) = self.pending_frames.pop() {
- debug!("Removing pending frame {}.", pending.frame_id);
- self.close_frame(pending.frame_id, ExitPipelineMode::Normal);
+ // Close any pending changes and pipelines
+ while let Some(pending) = self.pending_changes.pop() {
+ debug!("Removing pending browsing context {}.", pending.browsing_context_id);
+ self.close_browsing_context(pending.browsing_context_id, ExitPipelineMode::Normal);
debug!("Removing pending pipeline {}.", pending.new_pipeline_id);
self.close_pipeline(pending.new_pipeline_id, DiscardBrowsingContext::Yes, ExitPipelineMode::Normal);
}
- // In case there are frames which weren't attached to the frame tree, we close them.
- let frame_ids: Vec<FrameId> = self.frames.keys().cloned().collect();
- for frame_id in frame_ids {
- debug!("Removing detached frame {}.", frame_id);
- self.close_frame(frame_id, ExitPipelineMode::Normal);
+ // In case there are browsing contexts which weren't attached, we close them.
+ let browsing_context_ids: Vec<BrowsingContextId> = self.browsing_contexts.keys().cloned().collect();
+ for browsing_context_id in browsing_context_ids {
+ debug!("Removing detached browsing context {}.", browsing_context_id);
+ self.close_browsing_context(browsing_context_id, ExitPipelineMode::Normal);
}
// In case there are pipelines which weren't attached to the pipeline tree, we close them.
@@ -1276,12 +1289,15 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
fn handle_send_error(&mut self, pipeline_id: PipelineId, err: IpcError) {
// Treat send error the same as receiving a panic message
debug!("Pipeline {:?} send error ({}).", pipeline_id, err);
- let top_level_frame_id = self.get_top_level_frame_for_pipeline(pipeline_id);
+ let top_level_browsing_context_id = self.get_top_level_browsing_context_for_pipeline(pipeline_id);
let reason = format!("Send failed ({})", err);
- self.handle_panic(top_level_frame_id, reason, None);
+ self.handle_panic(top_level_browsing_context_id, reason, None);
}
- fn handle_panic(&mut self, top_level_frame_id: FrameId, reason: String, backtrace: Option<String>) {
+ fn handle_panic(&mut self, top_level_browsing_context_id: BrowsingContextId,
+ reason: String,
+ backtrace: Option<String>)
+ {
if opts::get().hard_fail {
// It's quite difficult to make Servo exit cleanly if some threads have failed.
// Hard fail exists for test runners so we crash and that's good enough.
@@ -1289,15 +1305,15 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
process::exit(1);
}
- debug!("Panic handler for top-level frame {}: {}.", top_level_frame_id, reason);
+ debug!("Panic handler for top-level browsing context {}: {}.", top_level_browsing_context_id, reason);
// Notify the browser chrome that the pipeline has failed
- self.trigger_mozbrowsererror(top_level_frame_id, reason, backtrace);
+ self.trigger_mozbrowsererror(top_level_browsing_context_id, reason, backtrace);
let (window_size, pipeline_id) = {
- let frame = self.frames.get(&top_level_frame_id);
- let window_size = frame.and_then(|frame| frame.size);
- let pipeline_id = frame.map(|frame| frame.pipeline_id);
+ let browsing_context = self.browsing_contexts.get(&top_level_browsing_context_id);
+ let window_size = browsing_context.and_then(|browsing_context| browsing_context.size);
+ let pipeline_id = browsing_context.map(|browsing_context| browsing_context.pipeline_id);
(window_size, pipeline_id)
};
@@ -1308,7 +1324,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
(pipeline_url, parent_info)
};
- self.close_frame_children(top_level_frame_id, DiscardBrowsingContext::No, ExitPipelineMode::Force);
+ self.close_browsing_context_children(top_level_browsing_context_id,
+ DiscardBrowsingContext::No,
+ ExitPipelineMode::Force);
let failure_url = ServoUrl::parse("about:failure").expect("infallible");
@@ -1323,22 +1341,26 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
let new_pipeline_id = PipelineId::new();
let load_data = LoadData::new(failure_url, None, None, None);
let sandbox = IFrameSandboxState::IFrameSandboxed;
- self.new_pipeline(new_pipeline_id, top_level_frame_id, parent_info,
+ self.new_pipeline(new_pipeline_id, top_level_browsing_context_id, parent_info,
window_size, load_data.clone(), sandbox, false);
- self.pending_frames.push(FrameChange {
- frame_id: top_level_frame_id,
+ self.pending_changes.push(SessionHistoryChange {
+ browsing_context_id: top_level_browsing_context_id,
new_pipeline_id: new_pipeline_id,
load_data: load_data,
replace_instant: None,
});
}
- fn handle_log_entry(&mut self, top_level_frame_id: Option<FrameId>, thread_name: Option<String>, entry: LogEntry) {
+ fn handle_log_entry(&mut self,
+ top_level_browsing_context_id: Option<BrowsingContextId>,
+ thread_name: Option<String>,
+ entry: LogEntry)
+ {
debug!("Received log entry {:?}.", entry);
+ let top_level_browsing_context_id = top_level_browsing_context_id.unwrap_or(self.root_browsing_context_id);
match entry {
LogEntry::Panic(reason, backtrace) => {
- let top_level_frame_id = top_level_frame_id.unwrap_or(self.root_frame_id);
- self.handle_panic(top_level_frame_id, reason, Some(backtrace));
+ self.handle_panic(top_level_browsing_context_id, reason, Some(backtrace));
},
LogEntry::Error(reason) | LogEntry::Warn(reason) => {
// VecDeque::truncate is unstable
@@ -1365,47 +1387,53 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
fn handle_init_load(&mut self, url: ServoUrl) {
let window_size = self.window_size.initial_viewport;
let root_pipeline_id = PipelineId::new();
- let root_frame_id = self.root_frame_id;
+ let root_browsing_context_id = self.root_browsing_context_id;
let load_data = LoadData::new(url.clone(), None, None, None);
let sandbox = IFrameSandboxState::IFrameUnsandboxed;
- self.new_pipeline(root_pipeline_id, root_frame_id, None, Some(window_size), load_data.clone(), sandbox, false);
+ self.new_pipeline(root_pipeline_id,
+ root_browsing_context_id,
+ None,
+ Some(window_size),
+ load_data.clone(),
+ sandbox,
+ false);
self.handle_load_start_msg(root_pipeline_id);
- self.pending_frames.push(FrameChange {
- frame_id: self.root_frame_id,
+ self.pending_changes.push(SessionHistoryChange {
+ browsing_context_id: self.root_browsing_context_id,
new_pipeline_id: root_pipeline_id,
load_data: load_data,
replace_instant: None,
});
}
- fn handle_frame_size_msg(&mut self,
- iframe_sizes: Vec<(FrameId, TypedSize2D<f32, CSSPixel>)>) {
- for (frame_id, size) in iframe_sizes {
+ fn handle_iframe_size_msg(&mut self,
+ iframe_sizes: Vec<(BrowsingContextId, TypedSize2D<f32, CSSPixel>)>) {
+ for (browsing_context_id, size) in iframe_sizes {
let window_size = WindowSizeData {
initial_viewport: size,
device_pixel_ratio: self.window_size.device_pixel_ratio,
};
- self.resize_frame(window_size, WindowSizeType::Initial, frame_id);
+ self.resize_frame(window_size, WindowSizeType::Initial, browsing_context_id);
}
}
fn handle_subframe_loaded(&mut self, pipeline_id: PipelineId) {
- let (frame_id, parent_id) = match self.pipelines.get(&pipeline_id) {
+ let (browsing_context_id, parent_id) = match self.pipelines.get(&pipeline_id) {
Some(pipeline) => match pipeline.parent_info {
- Some((parent_id, _)) => (pipeline.frame_id, parent_id),
+ Some((parent_id, _)) => (pipeline.browsing_context_id, parent_id),
None => return warn!("Pipeline {} has no parent.", pipeline_id),
},
None => return warn!("Pipeline {} loaded after closure.", pipeline_id),
};
- let msg = ConstellationControlMsg::DispatchFrameLoadEvent {
- target: frame_id,
+ let msg = ConstellationControlMsg::DispatchIFrameLoadEvent {
+ target: browsing_context_id,
parent: parent_id,
child: pipeline_id,
};
let result = match self.pipelines.get(&parent_id) {
Some(parent) => parent.event_loop.send(msg),
- None => return warn!("Parent {} frame loaded after closure.", parent_id),
+ None => return warn!("Parent {} browsing context loaded after closure.", parent_id),
};
if let Err(e) = result {
self.handle_send_error(parent_id, e);
@@ -1413,8 +1441,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
}
// The script thread associated with pipeline_id has loaded a URL in an iframe via script. This
- // will result in a new pipeline being spawned and a frame tree being added to
- // parent_pipeline_id's frame tree's children. This message is never the result of a
+ // will result in a new pipeline being spawned and a child being added to
+ // the parent pipeline. This message is never the result of a
// page navigation.
fn handle_script_loaded_url_in_iframe_msg(&mut self, load_info: IFrameLoadInfoWithData) {
let (load_data, window_size, is_private) = {
@@ -1439,27 +1467,29 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
let is_private = load_info.info.is_private || source_pipeline.is_private;
- let window_size = self.frames.get(&load_info.info.frame_id).and_then(|frame| frame.size);
+ let window_size = self.browsing_contexts.get(&load_info.info.browsing_context_id)
+ .and_then(|browsing_context| browsing_context.size);
(load_data, window_size, is_private)
};
let replace_instant = if load_info.info.replace {
- self.frames.get(&load_info.info.frame_id).map(|frame| frame.instant)
+ self.browsing_contexts.get(&load_info.info.browsing_context_id)
+ .map(|browsing_context| browsing_context.instant)
} else {
None
};
- // Create the new pipeline, attached to the parent and push to pending frames
- self.pending_frames.push(FrameChange {
- frame_id: load_info.info.frame_id,
+ // Create the new pipeline, attached to the parent and push to pending changes
+ self.pending_changes.push(SessionHistoryChange {
+ browsing_context_id: load_info.info.browsing_context_id,
new_pipeline_id: load_info.info.new_pipeline_id,
load_data: load_data.clone(),
replace_instant: replace_instant,
});
self.new_pipeline(load_info.info.new_pipeline_id,
- load_info.info.frame_id,
+ load_info.info.browsing_context_id,
Some((load_info.info.parent_pipeline_id, load_info.info.frame_type)),
window_size,
load_data,
@@ -1475,7 +1505,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
new_pipeline_id,
frame_type,
replace,
- frame_id,
+ browsing_context_id,
is_private,
} = load_info;
@@ -1490,7 +1520,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
let script_sender = parent_pipeline.event_loop.clone();
Pipeline::new(new_pipeline_id,
- frame_id,
+ browsing_context_id,
Some((parent_pipeline_id, frame_type)),
script_sender,
layout_sender,
@@ -1504,7 +1534,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
let load_data = LoadData::new(url, Some(parent_pipeline_id), None, None);
let replace_instant = if replace {
- self.frames.get(&frame_id).map(|frame| frame.instant)
+ self.browsing_contexts.get(&browsing_context_id).map(|browsing_context| browsing_context.instant)
} else {
None
};
@@ -1512,8 +1542,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
assert!(!self.pipelines.contains_key(&new_pipeline_id));
self.pipelines.insert(new_pipeline_id, pipeline);
- self.pending_frames.push(FrameChange {
- frame_id: frame_id,
+ self.pending_changes.push(SessionHistoryChange {
+ browsing_context_id: browsing_context_id,
new_pipeline_id: new_pipeline_id,
load_data: load_data,
replace_instant: replace_instant,
@@ -1566,13 +1596,13 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
let title = String::from("Alert");
let return_value = String::from("");
let event = MozBrowserEvent::ShowModalPrompt(prompt_type, title, message, return_value);
- let top_level_frame_id = self.get_top_level_frame_for_pipeline(pipeline_id);
+ let top_level_browsing_context_id = self.get_top_level_browsing_context_for_pipeline(pipeline_id);
- match self.frames.get(&self.root_frame_id) {
- None => warn!("Alert sent after root frame closure."),
- Some(root_frame) => match self.pipelines.get(&root_frame.pipeline_id) {
+ match self.browsing_contexts.get(&self.root_browsing_context_id) {
+ None => warn!("Alert sent after root browsing context closure."),
+ Some(root_browsing_context) => match self.pipelines.get(&root_browsing_context.pipeline_id) {
None => warn!("Alert sent after root pipeline closure."),
- Some(root_pipeline) => root_pipeline.trigger_mozbrowser_event(Some(top_level_frame_id), event),
+ Some(pipeline) => pipeline.trigger_mozbrowser_event(Some(top_level_browsing_context_id), event),
}
}
}
@@ -1602,8 +1632,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
// requested change so it can update its internal state.
//
// If replace is true, the current entry is replaced instead of a new entry being added.
- let (frame_id, parent_info) = match self.pipelines.get(&source_id) {
- Some(pipeline) => (pipeline.frame_id, pipeline.parent_info),
+ let (browsing_context_id, parent_info) = match self.pipelines.get(&source_id) {
+ Some(pipeline) => (pipeline.browsing_context_id, pipeline.parent_info),
None => {
warn!("Pipeline {:?} loaded after closure.", source_id);
return None;
@@ -1614,7 +1644,10 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
self.handle_load_start_msg(source_id);
// Message the constellation to find the script thread for this iframe
// and issue an iframe load through there.
- let msg = ConstellationControlMsg::Navigate(parent_pipeline_id, frame_id, load_data, replace);
+ let msg = ConstellationControlMsg::Navigate(parent_pipeline_id,
+ browsing_context_id,
+ load_data,
+ replace);
let result = match self.pipelines.get(&parent_pipeline_id) {
Some(parent_pipeline) => parent_pipeline.event_loop.send(msg),
None => {
@@ -1628,17 +1661,17 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
Some(source_id)
}
None => {
- let root_frame_id = self.root_frame_id;
+ let root_browsing_context_id = self.root_browsing_context_id;
// Make sure no pending page would be overridden.
- for frame_change in &self.pending_frames {
- if frame_change.frame_id == root_frame_id {
+ for change in &self.pending_changes {
+ if change.browsing_context_id == root_browsing_context_id {
// id that sent load msg is being changed already; abort
return None;
}
}
- if !self.pipeline_is_in_current_frame(source_id) {
+ if self.get_activity(source_id) == DocumentActivity::Inactive {
// Disregard this load if the navigating pipeline is not actually
// active. This could be caused by a delayed navigation (eg. from
// a timer) or a race between multiple navigations (such as an
@@ -1647,26 +1680,32 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
}
self.handle_load_start_msg(source_id);
- // Being here means either there are no pending frames, or none of the pending
+ // Being here means either there are no pending changes, or none of the pending
// changes would be overridden by changing the subframe associated with source_id.
// Create the new pipeline
- let window_size = self.frames.get(&root_frame_id).and_then(|frame| frame.size);
+ let window_size = self.browsing_contexts.get(&root_browsing_context_id)
+ .and_then(|browsing_context| browsing_context.size);
let new_pipeline_id = PipelineId::new();
let sandbox = IFrameSandboxState::IFrameUnsandboxed;
let replace_instant = if replace {
- self.frames.get(&frame_id).map(|frame| frame.instant)
+ self.browsing_contexts.get(&browsing_context_id).map(|browsing_context| browsing_context.instant)
} else {
None
};
- self.pending_frames.push(FrameChange {
- frame_id: root_frame_id,
+ self.pending_changes.push(SessionHistoryChange {
+ browsing_context_id: root_browsing_context_id,
new_pipeline_id: new_pipeline_id,
load_data: load_data.clone(),
replace_instant: replace_instant,
});
- self.new_pipeline(new_pipeline_id, root_frame_id, None, window_size, load_data, sandbox, false);
-
+ self.new_pipeline(new_pipeline_id,
+ root_browsing_context_id,
+ None,
+ window_size,
+ load_data,
+ sandbox,
+ false);
Some(new_pipeline_id)
}
}
@@ -1695,27 +1734,27 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
fn handle_traverse_history_msg(&mut self,
pipeline_id: Option<PipelineId>,
direction: TraversalDirection) {
- let top_level_frame_id = pipeline_id
- .map(|pipeline_id| self.get_top_level_frame_for_pipeline(pipeline_id))
- .unwrap_or(self.root_frame_id);
+ let top_level_browsing_context_id = pipeline_id
+ .map(|pipeline_id| self.get_top_level_browsing_context_for_pipeline(pipeline_id))
+ .unwrap_or(self.root_browsing_context_id);
let mut size = 0;
let mut table = HashMap::new();
match direction {
TraversalDirection::Forward(delta) => {
- for entry in self.joint_session_future(top_level_frame_id).take(delta) {
+ for entry in self.joint_session_future(top_level_browsing_context_id).take(delta) {
size = size + 1;
- table.insert(entry.frame_id, entry.clone());
+ table.insert(entry.browsing_context_id, entry.clone());
}
if size < delta {
return debug!("Traversing forward too much.");
}
},
TraversalDirection::Back(delta) => {
- for entry in self.joint_session_past(top_level_frame_id).take(delta) {
+ for entry in self.joint_session_past(top_level_browsing_context_id).take(delta) {
size = size + 1;
- table.insert(entry.frame_id, entry.clone());
+ table.insert(entry.browsing_context_id, entry.clone());
}
if size < delta {
return debug!("Traversing back too much.");
@@ -1729,23 +1768,23 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
}
fn handle_joint_session_history_length(&self, pipeline_id: PipelineId, sender: IpcSender<u32>) {
- let frame_id = self.get_top_level_frame_for_pipeline(pipeline_id);
+ let browsing_context_id = self.get_top_level_browsing_context_for_pipeline(pipeline_id);
// Initialize length at 1 to count for the current active entry
let mut length = 1;
- for frame in self.full_frame_tree_iter(frame_id) {
- length += frame.next.len();
- length += frame.prev.len();
+ for browsing_context in self.all_browsing_contexts_iter(browsing_context_id) {
+ length += browsing_context.next.len();
+ length += browsing_context.prev.len();
}
let _ = sender.send(length as u32);
}
fn handle_key_msg(&mut self, ch: Option<char>, key: Key, state: KeyState, mods: KeyModifiers) {
// Send to the explicitly focused pipeline (if it exists), or the root
- // frame's current pipeline. If neither exist, fall back to sending to
+ // browsing context's current pipeline. If neither exist, fall back to sending to
// the compositor below.
- let root_pipeline_id = self.frames.get(&self.root_frame_id)
- .map(|root_frame| root_frame.pipeline_id);
+ let root_pipeline_id = self.browsing_contexts.get(&self.root_browsing_context_id)
+ .map(|root_browsing_context| root_browsing_context.pipeline_id);
let pipeline_id = self.focus_pipeline_id.or(root_pipeline_id);
match pipeline_id {
@@ -1769,8 +1808,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
fn handle_reload_msg(&mut self) {
// Send Reload constellation msg to root script channel.
- let root_pipeline_id = self.frames.get(&self.root_frame_id)
- .map(|root_frame| root_frame.pipeline_id);
+ let root_pipeline_id = self.browsing_contexts.get(&self.root_browsing_context_id)
+ .map(|root_browsing_context| root_browsing_context.pipeline_id);
if let Some(pipeline_id) = root_pipeline_id {
let msg = ConstellationControlMsg::Reload(pipeline_id);
@@ -1794,10 +1833,14 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
}
}
- fn handle_post_message_msg(&mut self, frame_id: FrameId, origin: Option<ImmutableOrigin>, data: Vec<u8>) {
- let pipeline_id = match self.frames.get(&frame_id) {
- None => return warn!("postMessage to closed frame {}.", frame_id),
- Some(frame) => frame.pipeline_id,
+ fn handle_post_message_msg(&mut self,
+ browsing_context_id: BrowsingContextId,
+ origin: Option<ImmutableOrigin>,
+ data: Vec<u8>)
+ {
+ let pipeline_id = match self.browsing_contexts.get(&browsing_context_id) {
+ None => return warn!("postMessage to closed browsing_context {}.", browsing_context_id),
+ Some(browsing_context) => browsing_context.pipeline_id,
};
let msg = ConstellationControlMsg::PostMessage(pipeline_id, origin, data);
let result = match self.pipelines.get(&pipeline_id) {
@@ -1819,20 +1862,21 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
// and pass the event to that script thread.
// If the pipeline lookup fails, it is because we have torn down the pipeline,
// so it is reasonable to silently ignore the event.
- let frame_id = self.pipelines.get(&pipeline_id).map(|pipeline| pipeline.frame_id);
+ let browsing_context_id = self.pipelines.get(&pipeline_id).map(|pipeline| pipeline.browsing_context_id);
match self.pipelines.get(&parent_pipeline_id) {
- Some(pipeline) => pipeline.trigger_mozbrowser_event(frame_id, event),
+ Some(pipeline) => pipeline.trigger_mozbrowser_event(browsing_context_id, event),
None => warn!("Pipeline {:?} handling mozbrowser event after closure.", parent_pipeline_id),
}
}
- fn handle_get_pipeline(&mut self, frame_id: Option<FrameId>,
+ fn handle_get_pipeline(&mut self,
+ browsing_context_id: Option<BrowsingContextId>,
resp_chan: IpcSender<Option<PipelineId>>) {
- let frame_id = frame_id.unwrap_or(self.root_frame_id);
- let current_pipeline_id = self.frames.get(&frame_id)
- .map(|frame| frame.pipeline_id);
- let pipeline_id_loaded = self.pending_frames.iter().rev()
- .find(|x| x.frame_id == frame_id)
+ let browsing_context_id = browsing_context_id.unwrap_or(self.root_browsing_context_id);
+ let current_pipeline_id = self.browsing_contexts.get(&browsing_context_id)
+ .map(|browsing_context| browsing_context.pipeline_id);
+ let pipeline_id_loaded = self.pending_changes.iter().rev()
+ .find(|x| x.browsing_context_id == browsing_context_id)
.map(|x| x.new_pipeline_id)
.or(current_pipeline_id);
if let Err(e) = resp_chan.send(pipeline_id_loaded) {
@@ -1840,18 +1884,18 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
}
}
- fn handle_get_frame(&mut self,
- pipeline_id: PipelineId,
- resp_chan: IpcSender<Option<FrameId>>) {
- let frame_id = self.pipelines.get(&pipeline_id).map(|pipeline| pipeline.frame_id);
- if let Err(e) = resp_chan.send(frame_id) {
- warn!("Failed get_frame response ({}).", e);
+ fn handle_get_browsing_context(&mut self,
+ pipeline_id: PipelineId,
+ resp_chan: IpcSender<Option<BrowsingContextId>>) {
+ let browsing_context_id = self.pipelines.get(&pipeline_id).map(|pipeline| pipeline.browsing_context_id);
+ if let Err(e) = resp_chan.send(browsing_context_id) {
+ warn!("Failed get_browsing_context response ({}).", e);
}
}
fn focus_parent_pipeline(&mut self, pipeline_id: PipelineId) {
- let (frame_id, parent_info) = match self.pipelines.get(&pipeline_id) {
- Some(pipeline) => (pipeline.frame_id, pipeline.parent_info),
+ let (browsing_context_id, parent_info) = match self.pipelines.get(&pipeline_id) {
+ Some(pipeline) => (pipeline.browsing_context_id, pipeline.parent_info),
None => return warn!("Pipeline {:?} focus parent after closure.", pipeline_id),
};
let (parent_pipeline_id, _) = match parent_info {
@@ -1861,7 +1905,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
// Send a message to the parent of the provided pipeline (if it exists)
// telling it to mark the iframe element as focused.
- let msg = ConstellationControlMsg::FocusIFrame(parent_pipeline_id, frame_id);
+ let msg = ConstellationControlMsg::FocusIFrame(parent_pipeline_id, browsing_context_id);
let result = match self.pipelines.get(&parent_pipeline_id) {
Some(pipeline) => pipeline.event_loop.send(msg),
None => return warn!("Pipeline {:?} focus after closure.", parent_pipeline_id),
@@ -1879,26 +1923,26 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
self.focus_parent_pipeline(pipeline_id);
}
- fn handle_remove_iframe_msg(&mut self, frame_id: FrameId) -> Vec<PipelineId> {
- let result = self.full_frame_tree_iter(frame_id)
- .flat_map(|frame| frame.next.iter().chain(frame.prev.iter())
+ fn handle_remove_iframe_msg(&mut self, browsing_context_id: BrowsingContextId) -> Vec<PipelineId> {
+ let result = self.all_browsing_contexts_iter(browsing_context_id)
+ .flat_map(|browsing_context| browsing_context.next.iter().chain(browsing_context.prev.iter())
.filter_map(|entry| entry.pipeline_id)
- .chain(once(frame.pipeline_id)))
+ .chain(once(browsing_context.pipeline_id)))
.collect();
- self.close_frame(frame_id, ExitPipelineMode::Normal);
+ self.close_browsing_context(browsing_context_id, ExitPipelineMode::Normal);
result
}
fn handle_set_visible_msg(&mut self, pipeline_id: PipelineId, visible: bool) {
- let frame_id = match self.pipelines.get(&pipeline_id) {
- Some(pipeline) => pipeline.frame_id,
- None => return warn!("No frame associated with pipeline {:?}", pipeline_id),
+ let browsing_context_id = match self.pipelines.get(&pipeline_id) {
+ Some(pipeline) => pipeline.browsing_context_id,
+ None => return warn!("No browsing context associated with pipeline {:?}", pipeline_id),
};
- let child_pipeline_ids: Vec<PipelineId> = self.full_frame_tree_iter(frame_id)
- .flat_map(|frame| frame.prev.iter().chain(frame.next.iter())
+ let child_pipeline_ids: Vec<PipelineId> = self.all_browsing_contexts_iter(browsing_context_id)
+ .flat_map(|browsing_context| browsing_context.prev.iter().chain(browsing_context.next.iter())
.filter_map(|entry| entry.pipeline_id)
- .chain(once(frame.pipeline_id)))
+ .chain(once(browsing_context.pipeline_id)))
.collect();
for id in child_pipeline_ids {
@@ -1909,13 +1953,13 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
}
fn handle_visibility_change_complete(&mut self, pipeline_id: PipelineId, visibility: bool) {
- let (frame_id, parent_pipeline_info) = match self.pipelines.get(&pipeline_id) {
+ let (browsing_context_id, parent_pipeline_info) = match self.pipelines.get(&pipeline_id) {
None => return warn!("Visibity change for closed pipeline {:?}.", pipeline_id),
- Some(pipeline) => (pipeline.frame_id, pipeline.parent_info),
+ Some(pipeline) => (pipeline.browsing_context_id, pipeline.parent_info),
};
if let Some((parent_pipeline_id, _)) = parent_pipeline_info {
let visibility_msg = ConstellationControlMsg::NotifyVisibilityChange(parent_pipeline_id,
- frame_id,
+ browsing_context_id,
visibility);
let result = match self.pipelines.get(&parent_pipeline_id) {
None => return warn!("Parent pipeline {:?} closed", parent_pipeline_id),
@@ -1998,8 +2042,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
}
},
WebDriverCommandMsg::TakeScreenshot(pipeline_id, reply) => {
- let current_pipeline_id = self.frames.get(&self.root_frame_id)
- .map(|root_frame| root_frame.pipeline_id);
+ let current_pipeline_id = self.browsing_contexts.get(&self.root_browsing_context_id)
+ .map(|root_browsing_context| root_browsing_context.pipeline_id);
if Some(pipeline_id) == current_pipeline_id {
self.compositor_proxy.send(ToCompositorMsg::CreatePng(reply));
} else {
@@ -2012,9 +2056,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
}
// https://html.spec.whatwg.org/multipage/#traverse-the-history
- fn traverse_to_entry(&mut self, entry: FrameState) {
+ fn traverse_to_entry(&mut self, entry: SessionHistoryEntry) {
// Step 1.
- let frame_id = entry.frame_id;
+ let browsing_context_id = entry.browsing_context_id;
let pipeline_id = match entry.pipeline_id {
Some(pipeline_id) => pipeline_id,
None => {
@@ -2022,22 +2066,22 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
// entry has been discarded, so we navigate to the entry
// URL instead. When the document has activated, it will
// traverse to the entry, but with the new pipeline id.
- debug!("Reloading document {} for frame {}.", entry.load_data.url, entry.frame_id);
+ debug!("Reloading document {} in browsing context {}.", entry.load_data.url, entry.browsing_context_id);
// TODO: save the sandbox state so it can be restored here.
let sandbox = IFrameSandboxState::IFrameUnsandboxed;
let new_pipeline_id = PipelineId::new();
let load_data = entry.load_data;
- let (parent_info, window_size, is_private) = match self.frames.get(&frame_id) {
- Some(frame) => match self.pipelines.get(&frame.pipeline_id) {
- Some(pipeline) => (pipeline.parent_info, frame.size, pipeline.is_private),
- None => (None, frame.size, false),
+ let (parent_info, window_size, is_private) = match self.browsing_contexts.get(&browsing_context_id) {
+ Some(browsing_context) => match self.pipelines.get(&browsing_context.pipeline_id) {
+ Some(pipeline) => (pipeline.parent_info, browsing_context.size, pipeline.is_private),
+ None => (None, browsing_context.size, false),
},
- None => return warn!("no frame to traverse"),
+ None => return warn!("no browsing context to traverse"),
};
- self.new_pipeline(new_pipeline_id, frame_id, parent_info,
+ self.new_pipeline(new_pipeline_id, browsing_context_id, parent_info,
window_size, load_data.clone(), sandbox, is_private);
- self.pending_frames.push(FrameChange {
- frame_id: frame_id,
+ self.pending_changes.push(SessionHistoryChange {
+ browsing_context_id: browsing_context_id,
new_pipeline_id: new_pipeline_id,
load_data: load_data,
replace_instant: Some(entry.instant),
@@ -2049,24 +2093,24 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
// Check if the currently focused pipeline is the pipeline being replaced
// (or a child of it). This has to be done here, before the current
// frame tree is modified below.
- let update_focus_pipeline = self.focused_pipeline_in_tree(entry.frame_id);
+ let update_focus_pipeline = self.focused_pipeline_is_descendant_of(entry.browsing_context_id);
- let (old_pipeline_id, replaced_pipeline_id) = match self.frames.get_mut(&frame_id) {
- Some(frame) => {
- let old_pipeline_id = frame.pipeline_id;
- let mut curr_entry = frame.current();
+ let (old_pipeline_id, replaced_pipeline_id) = match self.browsing_contexts.get_mut(&browsing_context_id) {
+ Some(browsing_context) => {
+ let old_pipeline_id = browsing_context.pipeline_id;
+ let mut curr_entry = browsing_context.current();
- if entry.instant > frame.instant {
+ if entry.instant > browsing_context.instant {
// We are traversing to the future.
- while let Some(next) = frame.next.pop() {
- frame.prev.push(curr_entry);
+ while let Some(next) = browsing_context.next.pop() {
+ browsing_context.prev.push(curr_entry);
curr_entry = next;
if entry.instant <= curr_entry.instant { break; }
}
- } else if entry.instant < frame.instant {
+ } else if entry.instant < browsing_context.instant {
// We are traversing to the past.
- while let Some(prev) = frame.prev.pop() {
- frame.next.push(curr_entry);
+ while let Some(prev) = browsing_context.prev.pop() {
+ browsing_context.next.push(curr_entry);
curr_entry = prev;
if entry.instant >= curr_entry.instant { break; }
}
@@ -2076,11 +2120,11 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
let replaced_pipeline_id = curr_entry.pipeline_id;
- frame.update_current(pipeline_id, entry);
+ browsing_context.update_current(pipeline_id, entry);
(old_pipeline_id, replaced_pipeline_id)
},
- None => return warn!("no frame to traverse"),
+ None => return warn!("no browsing context to traverse"),
};
let parent_info = self.pipelines.get(&old_pipeline_id)
@@ -2112,7 +2156,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
// This makes things like contentDocument work correctly.
if let Some((parent_pipeline_id, _)) = parent_info {
let msg = ConstellationControlMsg::UpdatePipelineId(parent_pipeline_id,
- frame_id, pipeline_id, UpdatePipelineIdReason::Traversal);
+ browsing_context_id, pipeline_id, UpdatePipelineIdReason::Traversal);
let result = match self.pipelines.get(&parent_pipeline_id) {
None => return warn!("Pipeline {:?} child traversed after closure.", parent_pipeline_id),
Some(pipeline) => pipeline.event_loop.send(msg),
@@ -2133,17 +2177,17 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
// the current entry and the future entries.
// LoadData of inner frames are ignored and replaced with the LoadData of the parent.
- let top_level_frame_id = self.get_top_level_frame_for_pipeline(pipeline_id);
+ let top_level_browsing_context_id = self.get_top_level_browsing_context_for_pipeline(pipeline_id);
- // Ignore LoadData of non-top-level frames.
- let keep_load_data_if_top_frame = |state: &FrameState| {
- match state.pipeline_id {
- None => Some(state.load_data.clone()),
+ // Ignore LoadData of non-top-level browsing contexts.
+ let keep_load_data_if_top_browsing_context = |entry: &SessionHistoryEntry| {
+ match entry.pipeline_id {
+ None => Some(entry.load_data.clone()),
Some(pipeline_id) => {
match self.pipelines.get(&pipeline_id) {
- None => Some(state.load_data.clone()),
+ None => Some(entry.load_data.clone()),
Some(pipeline) => match pipeline.parent_info {
- None => Some(state.load_data.clone()),
+ None => Some(entry.load_data.clone()),
Some(_) => None,
}
}
@@ -2151,8 +2195,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
}
};
- // If LoadData was ignored, use the LoadData of the previous FrameState, which
- // is the LoadData of the parent frame.
+ // If LoadData was ignored, use the LoadData of the previous SessionHistoryEntry, which
+ // is the LoadData of the parent browsing context.
let resolve_load_data = |previous_load_data: &mut LoadData, load_data| {
let load_data = match load_data {
None => previous_load_data.clone(),
@@ -2162,13 +2206,13 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
Some(load_data)
};
- let current_load_data = match self.frames.get(&top_level_frame_id) {
- Some(frame) => frame.load_data.clone(),
- None => return warn!("notify_history_changed error after top-level frame closed."),
+ let current_load_data = match self.browsing_contexts.get(&top_level_browsing_context_id) {
+ Some(browsing_context) => browsing_context.load_data.clone(),
+ None => return warn!("notify_history_changed error after top-level browsing context closed."),
};
- let mut entries: Vec<LoadData> = self.joint_session_past(top_level_frame_id)
- .map(&keep_load_data_if_top_frame)
+ let mut entries: Vec<LoadData> = self.joint_session_past(top_level_browsing_context_id)
+ .map(&keep_load_data_if_top_browsing_context)
.scan(current_load_data.clone(), &resolve_load_data)
.collect();
@@ -2178,31 +2222,31 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
entries.push(current_load_data.clone());
- entries.extend(self.joint_session_future(top_level_frame_id)
- .map(&keep_load_data_if_top_frame)
+ entries.extend(self.joint_session_future(top_level_browsing_context_id)
+ .map(&keep_load_data_if_top_browsing_context)
.scan(current_load_data.clone(), &resolve_load_data));
self.compositor_proxy.send(ToCompositorMsg::HistoryChanged(entries, current_index));
}
- fn get_top_level_frame_for_pipeline(&self, mut pipeline_id: PipelineId) -> FrameId {
+ fn get_top_level_browsing_context_for_pipeline(&self, mut pipeline_id: PipelineId) -> BrowsingContextId {
if PREFS.is_mozbrowser_enabled() {
loop {
match self.pipelines.get(&pipeline_id) {
Some(pipeline) => match pipeline.parent_info {
- Some((_, FrameType::MozBrowserIFrame)) => return pipeline.frame_id,
+ Some((_, FrameType::MozBrowserIFrame)) => return pipeline.browsing_context_id,
Some((parent_id, _)) => pipeline_id = parent_id,
- None => return self.root_frame_id,
+ None => return self.root_browsing_context_id,
},
None => {
warn!("Finding top-level ancestor for pipeline {} after closure.", pipeline_id);
- return self.root_frame_id;
+ return self.root_browsing_context_id;
},
}
}
} else {
- // If mozbrowser is not enabled, the root frame is the only top-level frame
- self.root_frame_id
+ // If mozbrowser is not enabled, the root browsing context is the only top-level browsing context
+ self.root_browsing_context_id
}
}
@@ -2217,37 +2261,37 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
}
}
- fn add_or_replace_pipeline_in_frame_tree(&mut self, frame_change: FrameChange) {
- debug!("Setting frame {} to be pipeline {}.", frame_change.frame_id, frame_change.new_pipeline_id);
+ fn change_session_history(&mut self, change: SessionHistoryChange) {
+ debug!("Setting browsing context {} to be pipeline {}.", change.browsing_context_id, change.new_pipeline_id);
// If the currently focused pipeline is the one being changed (or a child
// of the pipeline being changed) then update the focus pipeline to be
// the replacement.
- if self.focused_pipeline_in_tree(frame_change.frame_id) {
- self.focus_pipeline_id = Some(frame_change.new_pipeline_id);
+ if self.focused_pipeline_is_descendant_of(change.browsing_context_id) {
+ self.focus_pipeline_id = Some(change.new_pipeline_id);
}
- let (evicted_id, new_frame, navigated, location_changed) = if let Some(instant) = frame_change.replace_instant {
- debug!("Replacing pipeline in existing frame with timestamp {:?}.", instant);
- let entry = FrameState {
- frame_id: frame_change.frame_id,
- pipeline_id: Some(frame_change.new_pipeline_id),
- load_data: frame_change.load_data.clone(),
+ let (evicted_id, new_context, navigated, location_changed) = if let Some(instant) = change.replace_instant {
+ debug!("Replacing pipeline in existing browsing context with timestamp {:?}.", instant);
+ let entry = SessionHistoryEntry {
+ browsing_context_id: change.browsing_context_id,
+ pipeline_id: Some(change.new_pipeline_id),
+ load_data: change.load_data.clone(),
instant: instant,
};
self.traverse_to_entry(entry);
(None, false, None, false)
- } else if let Some(frame) = self.frames.get_mut(&frame_change.frame_id) {
- debug!("Adding pipeline to existing frame.");
- let old_pipeline_id = frame.pipeline_id;
- frame.load(frame_change.new_pipeline_id, frame_change.load_data.clone());
- let evicted_id = frame.prev.len()
+ } else if let Some(browsing_context) = self.browsing_contexts.get_mut(&change.browsing_context_id) {
+ debug!("Adding pipeline to existing browsing context.");
+ let old_pipeline_id = browsing_context.pipeline_id;
+ browsing_context.load(change.new_pipeline_id, change.load_data.clone());
+ let evicted_id = browsing_context.prev.len()
.checked_sub(PREFS.get("session-history.max-length").as_u64().unwrap_or(20) as usize)
- .and_then(|index| frame.prev.get_mut(index))
+ .and_then(|index| browsing_context.prev.get_mut(index))
.and_then(|entry| entry.pipeline_id.take());
(evicted_id, false, Some(old_pipeline_id), true)
} else {
- debug!("Adding pipeline to new frame.");
+ debug!("Adding pipeline to new browsing context.");
(None, true, None, true)
};
@@ -2255,26 +2299,26 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
self.close_pipeline(evicted_id, DiscardBrowsingContext::No, ExitPipelineMode::Normal);
}
- if new_frame {
- self.new_frame(frame_change.frame_id,
- frame_change.new_pipeline_id,
- frame_change.load_data);
- self.update_activity(frame_change.new_pipeline_id);
- self.notify_history_changed(frame_change.new_pipeline_id);
+ if new_context {
+ self.new_browsing_context(change.browsing_context_id,
+ change.new_pipeline_id,
+ change.load_data);
+ self.update_activity(change.new_pipeline_id);
+ self.notify_history_changed(change.new_pipeline_id);
};
if let Some(old_pipeline_id) = navigated {
// Deactivate the old pipeline, and activate the new one.
self.update_activity(old_pipeline_id);
- self.update_activity(frame_change.new_pipeline_id);
+ self.update_activity(change.new_pipeline_id);
// Clear the joint session future
- let top_level_frame_id = self.get_top_level_frame_for_pipeline(frame_change.new_pipeline_id);
- self.clear_joint_session_future(top_level_frame_id);
- self.notify_history_changed(frame_change.new_pipeline_id);
+ let top_level_id = self.get_top_level_browsing_context_for_pipeline(change.new_pipeline_id);
+ self.clear_joint_session_future(top_level_id);
+ self.notify_history_changed(change.new_pipeline_id);
}
if location_changed {
- self.trigger_mozbrowserlocationchange(frame_change.new_pipeline_id);
+ self.trigger_mozbrowserlocationchange(change.new_pipeline_id);
}
// Build frame tree
@@ -2289,22 +2333,22 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
if let Some((parent_pipeline_id, _)) = pipeline.parent_info {
if let Some(parent_pipeline) = self.pipelines.get(&parent_pipeline_id) {
let msg = ConstellationControlMsg::UpdatePipelineId(parent_pipeline_id,
- pipeline.frame_id, pipeline_id, UpdatePipelineIdReason::Navigation);
+ pipeline.browsing_context_id, pipeline_id, UpdatePipelineIdReason::Navigation);
let _ = parent_pipeline.event_loop.send(msg);
}
}
}
- // Find the pending frame change whose new pipeline id is pipeline_id.
- let pending_index = self.pending_frames.iter().rposition(|frame_change| {
- frame_change.new_pipeline_id == pipeline_id
+ // Find the pending change whose new pipeline id is pipeline_id.
+ let pending_index = self.pending_changes.iter().rposition(|change| {
+ change.new_pipeline_id == pipeline_id
});
- // If it is found, remove it from the pending frames, and make it
+ // If it is found, remove it from the pending changes, and make it
// the active document of its frame.
if let Some(pending_index) = pending_index {
- let frame_change = self.pending_frames.swap_remove(pending_index);
- self.add_or_replace_pipeline_in_frame_tree(frame_change);
+ let change = self.pending_changes.swap_remove(pending_index);
+ self.change_session_history(change);
}
}
@@ -2312,8 +2356,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
fn handle_window_size_msg(&mut self, new_size: WindowSizeData, size_type: WindowSizeType) {
debug!("handle_window_size_msg: {:?}", new_size.initial_viewport.to_untyped());
- let frame_id = self.root_frame_id;
- self.resize_frame(new_size, size_type, frame_id);
+ let browsing_context_id = self.root_browsing_context_id;
+ self.resize_frame(new_size, size_type, browsing_context_id);
if let Some(resize_channel) = self.webdriver.resize_channel.take() {
let _ = resize_channel.send(new_size);
@@ -2340,28 +2384,28 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
// avoiding this panic would require a mechanism for dealing
// with low-resource scenarios.
//
- // If there is no root frame yet, the initial page has
+ // If there is no root browsing context yet, the initial page has
// not loaded, so there is nothing to save yet.
- if !self.frames.contains_key(&self.root_frame_id) {
- return ReadyToSave::NoRootFrame;
+ if !self.browsing_contexts.contains_key(&self.root_browsing_context_id) {
+ return ReadyToSave::NoRootBrowsingContext;
}
// If there are pending loads, wait for those to complete.
- if !self.pending_frames.is_empty() {
- return ReadyToSave::PendingFrames;
+ if !self.pending_changes.is_empty() {
+ return ReadyToSave::PendingChanges;
}
let (state_sender, state_receiver) = ipc::channel().expect("Failed to create IPC channel!");
let (epoch_sender, epoch_receiver) = ipc::channel().expect("Failed to create IPC channel!");
- // Step through the current frame tree, checking that the script
+ // Step through the fully active browsing contexts, checking that the script
// thread is idle, and that the current epoch of the layout thread
// matches what the compositor has painted. If all these conditions
// are met, then the output image should not change and a reftest
// screenshot can safely be written.
- for frame in self.current_frame_tree_iter(self.root_frame_id) {
- let pipeline_id = frame.pipeline_id;
- debug!("Checking readiness of frame {}, pipeline {}.", frame.id, pipeline_id);
+ for browsing_context in self.fully_active_browsing_contexts_iter(self.root_browsing_context_id) {
+ let pipeline_id = browsing_context.pipeline_id;
+ debug!("Checking readiness of browsing context {}, pipeline {}.", browsing_context.id, pipeline_id);
let pipeline = match self.pipelines.get(&pipeline_id) {
None => {
@@ -2388,7 +2432,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
}
// See if this pipeline has reached idle script state yet.
- match self.document_states.get(&frame.pipeline_id) {
+ match self.document_states.get(&browsing_context.pipeline_id) {
Some(&DocumentState::Idle) => {}
Some(&DocumentState::Pending) | None => {
return ReadyToSave::DocumentLoading;
@@ -2399,7 +2443,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
// size for the pipeline, then its painting should be up to date. If the constellation
// *hasn't* received a size, it could be that the layer was hidden by script before the
// compositor discovered it, so we just don't check the layer.
- if let Some(size) = frame.size {
+ if let Some(size) = browsing_context.size {
// If the rectangle for this pipeline is zero sized, it will
// never be painted. In this case, don't query the layout
// thread as it won't contribute to the final output image.
@@ -2408,7 +2452,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
}
// Get the epoch that the compositor has drawn for this pipeline.
- let compositor_epoch = pipeline_states.get(&frame.pipeline_id);
+ let compositor_epoch = pipeline_states.get(&browsing_context.pipeline_id);
match compositor_epoch {
Some(compositor_epoch) => {
// Synchronously query the layout thread to see if the current
@@ -2444,8 +2488,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
let mut ancestor_id = pipeline_id;
loop {
if let Some(ancestor) = self.pipelines.get(&ancestor_id) {
- if let Some(frame) = self.frames.get(&ancestor.frame_id) {
- if frame.pipeline_id == ancestor_id {
+ if let Some(browsing_context) = self.browsing_contexts.get(&ancestor.browsing_context_id) {
+ if browsing_context.pipeline_id == ancestor_id {
if let Some((parent_id, FrameType::IFrame)) = ancestor.parent_info {
ancestor_id = parent_id;
continue;
@@ -2474,7 +2518,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
activity
};
for child_id in &pipeline.children {
- if let Some(child) = self.frames.get(child_id) {
+ if let Some(child) = self.browsing_contexts.get(child_id) {
self.set_activity(child.pipeline_id, child_activity);
}
}
@@ -2488,15 +2532,19 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
/// Handle updating the size of a frame. This notifies every pipeline in the frame of the new
/// size.
- fn resize_frame(&mut self, new_size: WindowSizeData, size_type: WindowSizeType, frame_id: FrameId) {
- if let Some(frame) = self.frames.get_mut(&frame_id) {
- frame.size = Some(new_size.initial_viewport);
+ fn resize_frame(&mut self,
+ new_size: WindowSizeData,
+ size_type: WindowSizeType,
+ browsing_context_id: BrowsingContextId)
+ {
+ if let Some(browsing_context) = self.browsing_contexts.get_mut(&browsing_context_id) {
+ browsing_context.size = Some(new_size.initial_viewport);
}
- if let Some(frame) = self.frames.get(&frame_id) {
+ if let Some(browsing_context) = self.browsing_contexts.get(&browsing_context_id) {
// Send Resize (or ResizeInactive) messages to each
// pipeline in the frame tree.
- let pipeline_id = frame.pipeline_id;
+ let pipeline_id = browsing_context.pipeline_id;
let pipeline = match self.pipelines.get(&pipeline_id) {
None => return warn!("Pipeline {:?} resized after closing.", pipeline_id),
Some(pipeline) => pipeline,
@@ -2506,7 +2554,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
new_size,
size_type
));
- let pipelines = frame.prev.iter().chain(frame.next.iter())
+ let pipelines = browsing_context.prev.iter().chain(browsing_context.next.iter())
.filter_map(|entry| entry.pipeline_id)
.filter_map(|pipeline_id| self.pipelines.get(&pipeline_id));
for pipeline in pipelines {
@@ -2518,13 +2566,13 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
}
// Send resize message to any pending pipelines that aren't loaded yet.
- for pending_frame in &self.pending_frames {
- let pipeline_id = pending_frame.new_pipeline_id;
+ for change in &self.pending_changes {
+ let pipeline_id = change.new_pipeline_id;
let pipeline = match self.pipelines.get(&pipeline_id) {
None => { warn!("Pending pipeline {:?} is closed", pipeline_id); continue; }
Some(pipeline) => pipeline,
};
- if pipeline.frame_id == frame_id {
+ if pipeline.browsing_context_id == browsing_context_id {
let _ = pipeline.event_loop.send(ConstellationControlMsg::Resize(
pipeline.id,
new_size,
@@ -2534,13 +2582,13 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
}
}
- fn clear_joint_session_future(&mut self, frame_id: FrameId) {
- let frame_ids: Vec<FrameId> = self.full_frame_tree_iter(frame_id)
- .map(|frame| frame.id)
+ fn clear_joint_session_future(&mut self, browsing_context_id: BrowsingContextId) {
+ let browsing_context_ids: Vec<BrowsingContextId> = self.all_browsing_contexts_iter(browsing_context_id)
+ .map(|browsing_context| browsing_context.id)
.collect();
- for frame_id in frame_ids {
- let evicted = match self.frames.get_mut(&frame_id) {
- Some(frame) => frame.remove_forward_entries(),
+ for browsing_context_id in browsing_context_ids {
+ let evicted = match self.browsing_contexts.get_mut(&browsing_context_id) {
+ Some(browsing_context) => browsing_context.remove_forward_entries(),
None => continue,
};
for entry in evicted {
@@ -2551,18 +2599,18 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
}
}
- // Close a frame (and all children)
- fn close_frame(&mut self, frame_id: FrameId, exit_mode: ExitPipelineMode) {
- debug!("Closing frame {}.", frame_id);
- let parent_info = self.frames.get(&frame_id)
- .and_then(|frame| self.pipelines.get(&frame.pipeline_id))
+ // Close a browsing context (and all children)
+ fn close_browsing_context(&mut self, browsing_context_id: BrowsingContextId, exit_mode: ExitPipelineMode) {
+ debug!("Closing browsing context {}.", browsing_context_id);
+ let parent_info = self.browsing_contexts.get(&browsing_context_id)
+ .and_then(|browsing_context| self.pipelines.get(&browsing_context.pipeline_id))
.and_then(|pipeline| pipeline.parent_info);
- self.close_frame_children(frame_id, DiscardBrowsingContext::Yes, exit_mode);
+ self.close_browsing_context_children(browsing_context_id, DiscardBrowsingContext::Yes, exit_mode);
- self.event_loops.remove(&frame_id);
- if self.frames.remove(&frame_id).is_none() {
- warn!("Closing frame {:?} twice.", frame_id);
+ self.event_loops.remove(&browsing_context_id);
+ if self.browsing_contexts.remove(&browsing_context_id).is_none() {
+ warn!("Closing browsing context {:?} twice.", browsing_context_id);
}
if let Some((parent_pipeline_id, _)) = parent_info {
@@ -2570,56 +2618,60 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
None => return warn!("Pipeline {:?} child closed after parent.", parent_pipeline_id),
Some(parent_pipeline) => parent_pipeline,
};
- parent_pipeline.remove_child(frame_id);
+ parent_pipeline.remove_child(browsing_context_id);
}
- debug!("Closed frame {:?}.", frame_id);
+ debug!("Closed browsing context {:?}.", browsing_context_id);
}
- // Close the children of a frame
- fn close_frame_children(&mut self, frame_id: FrameId, dbc: DiscardBrowsingContext, exit_mode: ExitPipelineMode) {
- debug!("Closing frame children {}.", frame_id);
+ // Close the children of a browsing context
+ fn close_browsing_context_children(&mut self,
+ browsing_context_id: BrowsingContextId,
+ dbc: DiscardBrowsingContext,
+ exit_mode: ExitPipelineMode)
+ {
+ debug!("Closing browsing context children {}.", browsing_context_id);
// Store information about the pipelines to be closed. Then close the
- // pipelines, before removing ourself from the frames hash map. This
+ // pipelines, before removing ourself from the browsing_contexts hash map. This
// ordering is vital - so that if close_pipeline() ends up closing
- // any child frames, they can be removed from the parent frame correctly.
- let mut pipelines_to_close: Vec<PipelineId> = self.pending_frames.iter()
- .filter(|frame_change| frame_change.frame_id == frame_id)
- .map(|frame_change| frame_change.new_pipeline_id)
+ // any child browsing contexts, they can be removed from the parent browsing context correctly.
+ let mut pipelines_to_close: Vec<PipelineId> = self.pending_changes.iter()
+ .filter(|change| change.browsing_context_id == browsing_context_id)
+ .map(|change| change.new_pipeline_id)
.collect();
- if let Some(frame) = self.frames.get(&frame_id) {
- pipelines_to_close.extend(frame.next.iter().filter_map(|state| state.pipeline_id));
- pipelines_to_close.push(frame.pipeline_id);
- pipelines_to_close.extend(frame.prev.iter().filter_map(|state| state.pipeline_id));
+ if let Some(browsing_context) = self.browsing_contexts.get(&browsing_context_id) {
+ pipelines_to_close.extend(browsing_context.next.iter().filter_map(|state| state.pipeline_id));
+ pipelines_to_close.push(browsing_context.pipeline_id);
+ pipelines_to_close.extend(browsing_context.prev.iter().filter_map(|state| state.pipeline_id));
}
for pipeline_id in pipelines_to_close {
self.close_pipeline(pipeline_id, dbc, exit_mode);
}
- debug!("Closed frame children {}.", frame_id);
+ debug!("Closed browsing context children {}.", browsing_context_id);
}
- // Close all pipelines at and beneath a given frame
+ // Close all pipelines at and beneath a given browsing context
fn close_pipeline(&mut self, pipeline_id: PipelineId, dbc: DiscardBrowsingContext, exit_mode: ExitPipelineMode) {
debug!("Closing pipeline {:?}.", pipeline_id);
- // Store information about the frames to be closed. Then close the
- // frames, before removing ourself from the pipelines hash map. This
- // ordering is vital - so that if close_frame() ends up closing
+ // Store information about the browsing contexts to be closed. Then close the
+ // browsing contexts, before removing ourself from the pipelines hash map. This
+ // ordering is vital - so that if close_browsing_context() ends up closing
// any child pipelines, they can be removed from the parent pipeline correctly.
- let frames_to_close = {
- let mut frames_to_close = vec!();
+ let browsing_contexts_to_close = {
+ let mut browsing_contexts_to_close = vec!();
if let Some(pipeline) = self.pipelines.get(&pipeline_id) {
- frames_to_close.extend_from_slice(&pipeline.children);
+ browsing_contexts_to_close.extend_from_slice(&pipeline.children);
}
- frames_to_close
+ browsing_contexts_to_close
};
- // Remove any child frames
- for child_frame in &frames_to_close {
- self.close_frame(*child_frame, exit_mode);
+ // Remove any child browsing contexts
+ for child_browsing_context in &browsing_contexts_to_close {
+ self.close_browsing_context(*child_browsing_context, exit_mode);
}
// Note, we don't remove the pipeline now, we wait for the message to come back from
@@ -2629,12 +2681,12 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
None => return warn!("Closing pipeline {:?} twice.", pipeline_id),
};
- // Remove this pipeline from pending frames if it hasn't loaded yet.
- let pending_index = self.pending_frames.iter().position(|frame_change| {
- frame_change.new_pipeline_id == pipeline_id
+ // Remove this pipeline from pending changes if it hasn't loaded yet.
+ let pending_index = self.pending_changes.iter().position(|change| {
+ change.new_pipeline_id == pipeline_id
});
if let Some(pending_index) = pending_index {
- self.pending_frames.remove(pending_index);
+ self.pending_changes.remove(pending_index);
}
// Inform script, compositor that this pipeline has exited.
@@ -2671,19 +2723,19 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
}
}
- // Convert a frame to a sendable form to pass to the compositor
- fn frame_to_sendable(&self, frame_id: FrameId) -> Option<SendableFrameTree> {
- self.frames.get(&frame_id).and_then(|frame: &Frame| {
- self.pipelines.get(&frame.pipeline_id).map(|pipeline: &Pipeline| {
+ // Convert a browsing context to a sendable form to pass to the compositor
+ fn browsing_context_to_sendable(&self, browsing_context_id: BrowsingContextId) -> Option<SendableFrameTree> {
+ self.browsing_contexts.get(&browsing_context_id).and_then(|browsing_context| {
+ self.pipelines.get(&browsing_context.pipeline_id).map(|pipeline| {
let mut frame_tree = SendableFrameTree {
pipeline: pipeline.to_sendable(),
- size: frame.size,
+ size: browsing_context.size,
children: vec!(),
};
- for child_frame_id in &pipeline.children {
- if let Some(frame) = self.frame_to_sendable(*child_frame_id) {
- frame_tree.children.push(frame);
+ for child_browsing_context_id in &pipeline.children {
+ if let Some(child) = self.browsing_context_to_sendable(*child_browsing_context_id) {
+ frame_tree.children.push(child);
}
}
@@ -2697,8 +2749,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
// Note that this function can panic, due to ipc-channel creation failure.
// avoiding this panic would require a mechanism for dealing
// with low-resource scenarios.
- debug!("Sending frame tree for frame {}.", self.root_frame_id);
- if let Some(frame_tree) = self.frame_to_sendable(self.root_frame_id) {
+ debug!("Sending frame tree for browsing context {}.", self.root_browsing_context_id);
+ if let Some(frame_tree) = self.browsing_context_to_sendable(self.root_browsing_context_id) {
let (chan, port) = ipc::channel().expect("Failed to create IPC channel!");
self.compositor_proxy.send(ToCompositorMsg::SetFrameTree(frame_tree,
chan));
@@ -2716,11 +2768,11 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
Some(pipeline) => if let Some((parent_id, FrameType::MozBrowserIFrame)) = pipeline.parent_info {
match self.pipelines.get(&parent_id) {
Some(parent) => {
- let can_go_forward = !self.joint_session_future_is_empty(pipeline.frame_id);
- let can_go_back = !self.joint_session_past_is_empty(pipeline.frame_id);
+ let can_go_forward = !self.joint_session_future_is_empty(pipeline.browsing_context_id);
+ let can_go_back = !self.joint_session_past_is_empty(pipeline.browsing_context_id);
let url = pipeline.url.to_string();
let event = MozBrowserEvent::LocationChange(url, can_go_back, can_go_forward);
- parent.trigger_mozbrowser_event(Some(pipeline.frame_id), event);
+ parent.trigger_mozbrowser_event(Some(pipeline.browsing_context_id), event);
},
None => warn!("triggered mozbrowser location change on closed parent {}", parent_id),
}
@@ -2731,7 +2783,11 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
// https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowsererror
// Note that this does not require the pipeline to be an immediate child of the root
- fn trigger_mozbrowsererror(&mut self, top_level_frame_id: FrameId, reason: String, backtrace: Option<String>) {
+ fn trigger_mozbrowsererror(&mut self,
+ top_level_browsing_context_id: BrowsingContextId,
+ reason: String,
+ backtrace: Option<String>)
+ {
if !PREFS.is_mozbrowser_enabled() { return; }
let mut report = String::new();
@@ -2753,36 +2809,25 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
let event = MozBrowserEvent::Error(MozBrowserErrorType::Fatal, reason, report);
- match self.frames.get(&top_level_frame_id) {
- None => warn!("Mozbrowser error after top-level frame closed."),
- Some(frame) => match self.pipelines.get(&frame.pipeline_id) {
+ match self.browsing_contexts.get(&top_level_browsing_context_id) {
+ None => warn!("Mozbrowser error after top-level browsing context closed."),
+ Some(browsing_context) => match self.pipelines.get(&browsing_context.pipeline_id) {
None => warn!("Mozbrowser error after top-level pipeline closed."),
Some(pipeline) => match pipeline.parent_info {
None => pipeline.trigger_mozbrowser_event(None, event),
Some((parent_id, _)) => match self.pipelines.get(&parent_id) {
None => warn!("Mozbrowser error after root pipeline closed."),
- Some(parent) => parent.trigger_mozbrowser_event(Some(top_level_frame_id), event),
+ Some(parent) => parent.trigger_mozbrowser_event(Some(top_level_browsing_context_id), event),
},
},
},
};
}
- fn focused_pipeline_in_tree(&self, frame_id: FrameId) -> bool {
+ fn focused_pipeline_is_descendant_of(&self, browsing_context_id: BrowsingContextId) -> bool {
self.focus_pipeline_id.map_or(false, |pipeline_id| {
- self.pipeline_exists_in_tree(pipeline_id, frame_id)
+ self.fully_active_browsing_contexts_iter(browsing_context_id)
+ .any(|browsing_context| browsing_context.pipeline_id == pipeline_id)
})
}
-
- fn pipeline_is_in_current_frame(&self, pipeline_id: PipelineId) -> bool {
- self.pipeline_exists_in_tree(pipeline_id, self.root_frame_id)
- }
-
- fn pipeline_exists_in_tree(&self,
- pipeline_id: PipelineId,
- root_frame_id: FrameId) -> bool {
- self.current_frame_tree_iter(root_frame_id)
- .any(|current_frame| current_frame.pipeline_id == pipeline_id)
- }
-
}
diff --git a/components/constellation/lib.rs b/components/constellation/lib.rs
index 536775de0ef..6958a5b7c39 100644
--- a/components/constellation/lib.rs
+++ b/components/constellation/lib.rs
@@ -41,9 +41,9 @@ extern crate style_traits;
extern crate webrender_traits;
extern crate webvr_traits;
+mod browsingcontext;
mod constellation;
mod event_loop;
-mod frame;
mod pipeline;
#[cfg(not(target_os = "windows"))]
mod sandboxing;
diff --git a/components/constellation/pipeline.rs b/components/constellation/pipeline.rs
index 60401f4313c..01c386779bb 100644
--- a/components/constellation/pipeline.rs
+++ b/components/constellation/pipeline.rs
@@ -15,7 +15,7 @@ use ipc_channel::Error;
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use ipc_channel::router::ROUTER;
use layout_traits::LayoutThreadFactory;
-use msg::constellation_msg::{FrameId, FrameType, PipelineId, PipelineNamespaceId};
+use msg::constellation_msg::{BrowsingContextId, FrameType, PipelineId, PipelineNamespaceId};
use net::image_cache::ImageCacheImpl;
use net_traits::{IpcSend, ResourceThreads};
use net_traits::image_cache::ImageCache;
@@ -49,14 +49,14 @@ pub struct Pipeline {
/// The ID of the pipeline.
pub id: PipelineId,
- /// The ID of the frame that contains this Pipeline.
- pub frame_id: FrameId,
+ /// The ID of the browsing context that contains this Pipeline.
+ pub browsing_context_id: BrowsingContextId,
/// The parent pipeline of this one. `None` if this is a root pipeline.
/// Note that because of mozbrowser iframes, even top-level pipelines
/// may have a parent (in which case the frame type will be
/// `MozbrowserIFrame`).
- /// TODO: move this field to `Frame`.
+ /// TODO: move this field to `BrowsingContext`.
pub parent_info: Option<(PipelineId, FrameType)>,
/// The event loop handling this pipeline.
@@ -80,11 +80,11 @@ pub struct Pipeline {
/// animations cause composites to be continually scheduled.
pub running_animations: bool,
- /// The child frames of this pipeline (these are iframes in the document).
- pub children: Vec<FrameId>,
+ /// The child browsing contexts of this pipeline (these are iframes in the document).
+ pub children: Vec<BrowsingContextId>,
/// Whether this pipeline is in private browsing mode.
- /// TODO: move this field to `Frame`.
+ /// TODO: move this field to `BrowsingContext`.
pub is_private: bool,
/// Whether this pipeline should be treated as visible for the purposes of scheduling and
@@ -100,11 +100,11 @@ pub struct InitialPipelineState {
/// The ID of the pipeline to create.
pub id: PipelineId,
- /// The ID of the frame that contains this Pipeline.
- pub frame_id: FrameId,
+ /// The ID of the browsing context that contains this Pipeline.
+ pub browsing_context_id: BrowsingContextId,
- /// The ID of the top-level frame that contains this Pipeline.
- pub top_level_frame_id: FrameId,
+ /// The ID of the top-level browsing context that contains this Pipeline.
+ pub top_level_browsing_context_id: BrowsingContextId,
/// The ID of the parent pipeline and frame type, if any.
/// If `None`, this is the root.
@@ -200,7 +200,7 @@ impl Pipeline {
let new_layout_info = NewLayoutInfo {
parent_info: state.parent_info,
new_pipeline_id: state.id,
- frame_id: state.frame_id,
+ browsing_context_id: state.browsing_context_id,
load_data: state.load_data,
window_size: window_size,
pipeline_port: pipeline_port,
@@ -237,8 +237,8 @@ impl Pipeline {
let unprivileged_pipeline_content = UnprivilegedPipelineContent {
id: state.id,
- frame_id: state.frame_id,
- top_level_frame_id: state.top_level_frame_id,
+ browsing_context_id: state.browsing_context_id,
+ top_level_browsing_context_id: state.top_level_browsing_context_id,
parent_info: state.parent_info,
constellation_chan: state.constellation_chan,
scheduler_chan: state.scheduler_chan,
@@ -280,7 +280,7 @@ impl Pipeline {
};
Ok(Pipeline::new(state.id,
- state.frame_id,
+ state.browsing_context_id,
state.parent_info,
script_chan,
pipeline_chan,
@@ -293,7 +293,7 @@ impl Pipeline {
/// Creates a new `Pipeline`, after the script and layout threads have been
/// spawned.
pub fn new(id: PipelineId,
- frame_id: FrameId,
+ browsing_context_id: BrowsingContextId,
parent_info: Option<(PipelineId, FrameType)>,
event_loop: Rc<EventLoop>,
layout_chan: IpcSender<LayoutControlMsg>,
@@ -304,7 +304,7 @@ impl Pipeline {
-> Pipeline {
let pipeline = Pipeline {
id: id,
- frame_id: frame_id,
+ browsing_context_id: browsing_context_id,
parent_info: parent_info,
event_loop: event_loop,
layout_chan: layout_chan,
@@ -376,15 +376,15 @@ impl Pipeline {
}
}
- /// Add a new child frame.
- pub fn add_child(&mut self, frame_id: FrameId) {
- self.children.push(frame_id);
+ /// Add a new child browsing context.
+ pub fn add_child(&mut self, browsing_context_id: BrowsingContextId) {
+ self.children.push(browsing_context_id);
}
- /// Remove a child frame.
- pub fn remove_child(&mut self, frame_id: FrameId) {
- match self.children.iter().position(|id| *id == frame_id) {
- None => return warn!("Pipeline remove child already removed ({:?}).", frame_id),
+ /// Remove a child browsing context.
+ pub fn remove_child(&mut self, browsing_context_id: BrowsingContextId) {
+ match self.children.iter().position(|id| *id == browsing_context_id) {
+ None => return warn!("Pipeline remove child already removed ({:?}).", browsing_context_id),
Some(index) => self.children.remove(index),
};
}
@@ -393,7 +393,7 @@ impl Pipeline {
/// This will cause an event to be fired on an iframe in the document,
/// or on the `Window` if no frame is given.
pub fn trigger_mozbrowser_event(&self,
- child_id: Option<FrameId>,
+ child_id: Option<BrowsingContextId>,
event: MozBrowserEvent) {
assert!(PREFS.is_mozbrowser_enabled());
@@ -433,8 +433,8 @@ impl Pipeline {
#[derive(Deserialize, Serialize)]
pub struct UnprivilegedPipelineContent {
id: PipelineId,
- frame_id: FrameId,
- top_level_frame_id: FrameId,
+ browsing_context_id: BrowsingContextId,
+ top_level_browsing_context_id: BrowsingContextId,
parent_info: Option<(PipelineId, FrameType)>,
constellation_chan: IpcSender<ScriptMsg>,
layout_to_constellation_chan: IpcSender<LayoutMsg>,
@@ -470,8 +470,8 @@ impl UnprivilegedPipelineContent {
let image_cache = Arc::new(ImageCacheImpl::new(self.webrender_api_sender.create_api()));
let layout_pair = STF::create(InitialScriptState {
id: self.id,
- frame_id: self.frame_id,
- top_level_frame_id: self.top_level_frame_id,
+ browsing_context_id: self.browsing_context_id,
+ top_level_browsing_context_id: self.top_level_browsing_context_id,
parent_info: self.parent_info,
control_chan: self.script_chan.clone(),
control_port: self.script_port,
@@ -491,7 +491,7 @@ impl UnprivilegedPipelineContent {
}, self.load_data.clone());
LTF::create(self.id,
- Some(self.top_level_frame_id),
+ Some(self.top_level_browsing_context_id),
self.load_data.url,
self.parent_info.is_some(),
layout_pair,
diff --git a/components/gfx/display_list/mod.rs b/components/gfx/display_list/mod.rs
index 626c3f56b3d..8ca587bfca4 100644
--- a/components/gfx/display_list/mod.rs
+++ b/components/gfx/display_list/mod.rs
@@ -30,11 +30,11 @@ use std::cmp::{self, Ordering};
use std::collections::HashMap;
use std::fmt;
use std::sync::Arc;
-use style::computed_values::{border_style, filter, image_rendering, mix_blend_mode};
+use style::computed_values::{border_style, filter, image_rendering};
use style_traits::cursor::Cursor;
use text::TextRun;
use text::glyph::ByteIndex;
-use webrender_traits::{self, ClipId, ColorF, GradientStop, ScrollPolicy, WebGLContextId};
+use webrender_traits::{self, ClipId, ColorF, GradientStop, MixBlendMode, ScrollPolicy, TransformStyle, WebGLContextId};
pub use style::dom::OpaqueNode;
@@ -424,11 +424,14 @@ pub struct StackingContext {
pub filters: filter::T,
/// The blend mode with which this stacking context blends with its backdrop.
- pub blend_mode: mix_blend_mode::T,
+ pub mix_blend_mode: MixBlendMode,
/// A transform to be applied to this stacking context.
pub transform: Option<Matrix4D<f32>>,
+ /// The transform style of this stacking context.
+ pub transform_style: TransformStyle,
+
/// The perspective matrix to be applied to children.
pub perspective: Option<Matrix4D<f32>>,
@@ -448,8 +451,9 @@ impl StackingContext {
overflow: &Rect<Au>,
z_index: i32,
filters: filter::T,
- blend_mode: mix_blend_mode::T,
+ mix_blend_mode: MixBlendMode,
transform: Option<Matrix4D<f32>>,
+ transform_style: TransformStyle,
perspective: Option<Matrix4D<f32>>,
scroll_policy: ScrollPolicy,
parent_scroll_id: ClipId)
@@ -461,8 +465,9 @@ impl StackingContext {
overflow: *overflow,
z_index: z_index,
filters: filters,
- blend_mode: blend_mode,
+ mix_blend_mode: mix_blend_mode,
transform: transform,
+ transform_style: transform_style,
perspective: perspective,
scroll_policy: scroll_policy,
parent_scroll_id: parent_scroll_id,
@@ -477,8 +482,9 @@ impl StackingContext {
&Rect::zero(),
0,
filter::T::new(Vec::new()),
- mix_blend_mode::T::normal,
+ MixBlendMode::Normal,
None,
+ TransformStyle::Flat,
None,
ScrollPolicy::Scrollable,
pipeline_id.root_scroll_node())
diff --git a/components/layout/block.rs b/components/layout/block.rs
index 5e30c6f08ee..adeb04730a3 100644
--- a/components/layout/block.rs
+++ b/components/layout/block.rs
@@ -46,7 +46,6 @@ use gfx_traits::print_tree::PrintTree;
use incremental::RelayoutMode;
use layout_debug;
use model::{AdjoiningMargins, CollapsibleMargins, IntrinsicISizes, MarginCollapseInfo, MaybeAuto};
-use model::{specified, specified_or_none};
use sequential;
use serde::{Serialize, Serializer};
use servo_geometry::max_rect;
@@ -326,7 +325,7 @@ impl CandidateBSizeIterator {
MaybeAuto::Specified(block_container_block_size.scale_by(percent))
}
(LengthOrPercentageOrAuto::Calc(calc), _) => {
- MaybeAuto::from_option(calc.to_computed(block_container_block_size))
+ MaybeAuto::from_option(calc.to_used_value(block_container_block_size))
}
(LengthOrPercentageOrAuto::Percentage(_), None) |
(LengthOrPercentageOrAuto::Auto, _) => MaybeAuto::Auto,
@@ -337,7 +336,7 @@ impl CandidateBSizeIterator {
Some(block_container_block_size.scale_by(percent))
}
(LengthOrPercentageOrNone::Calc(calc), _) => {
- calc.to_computed(block_container_block_size)
+ calc.to_used_value(block_container_block_size)
}
(LengthOrPercentageOrNone::Percentage(_), None) |
(LengthOrPercentageOrNone::None, _) => None,
@@ -348,7 +347,7 @@ impl CandidateBSizeIterator {
block_container_block_size.scale_by(percent)
}
(LengthOrPercentage::Calc(calc), _) => {
- calc.to_computed(block_container_block_size).unwrap_or(Au(0))
+ calc.to_used_value(block_container_block_size).unwrap_or(Au(0))
}
(LengthOrPercentage::Percentage(_), None) => Au(0),
(LengthOrPercentage::Length(length), _) => length,
@@ -657,7 +656,7 @@ impl BlockFlow {
pub fn containing_block_size(&self, viewport_size: &Size2D<Au>, descendant: OpaqueFlow)
-> LogicalSize<Au> {
debug_assert!(self.base.flags.contains(IS_ABSOLUTELY_POSITIONED));
- if self.is_fixed() {
+ if self.is_fixed() || self.is_root() {
// Initial containing block is the CB for the root
LogicalSize::from_physical(self.base.writing_mode, *viewport_size)
} else {
@@ -1167,7 +1166,7 @@ impl BlockFlow {
match (content_block_size, containing_block_size) {
(LengthOrPercentageOrAuto::Calc(calc), _) => {
- calc.to_computed(containing_block_size)
+ calc.to_used_value(containing_block_size)
}
(LengthOrPercentageOrAuto::Length(length), _) => Some(length),
(LengthOrPercentageOrAuto::Percentage(percent), Some(container_size)) => {
@@ -1417,8 +1416,8 @@ impl BlockFlow {
// we know.
if kid.is_inline_flow() {
kid.as_mut_inline().first_line_indentation =
- specified(self.fragment.style().get_inheritedtext().text_indent,
- containing_block_size);
+ self.fragment.style().get_inheritedtext().text_indent
+ .to_used_value(containing_block_size);
}
}
}
@@ -1512,14 +1511,12 @@ impl BlockFlow {
} else {
content_box.size.inline
} - self.fragment.margin.inline_start_end();
- let max_inline_size = specified_or_none(
- self.fragment.style().max_inline_size(),
- self.base.block_container_inline_size
- ).unwrap_or(MAX_AU);
- let min_inline_size = specified(
- self.fragment.style().min_inline_size(),
- self.base.block_container_inline_size
- );
+ let max_inline_size =
+ self.fragment.style().max_inline_size()
+ .to_used_value(self.base.block_container_inline_size)
+ .unwrap_or(MAX_AU);
+ let min_inline_size =
+ self.fragment.style().min_inline_size().to_used_value(self.base.block_container_inline_size);
let specified_inline_size = self.fragment.style().content_inline_size();
let container_size = self.base.block_container_inline_size;
let inline_size =
@@ -2413,8 +2410,7 @@ pub trait ISizeAndMarginsComputer {
// If the tentative used inline-size is greater than 'max-inline-size', inline-size should
// be recalculated, but this time using the computed value of 'max-inline-size' as the
// computed value for 'inline-size'.
- match specified_or_none(block.fragment().style().max_inline_size(),
- containing_block_inline_size) {
+ match block.fragment().style().max_inline_size().to_used_value(containing_block_inline_size) {
Some(max_inline_size) if max_inline_size < solution.inline_size => {
input.computed_inline_size = MaybeAuto::Specified(max_inline_size);
solution = self.solve_inline_size_constraints(block, &input);
@@ -2425,8 +2421,8 @@ pub trait ISizeAndMarginsComputer {
// If the resulting inline-size is smaller than 'min-inline-size', inline-size should be
// recalculated, but this time using the value of 'min-inline-size' as the computed value
// for 'inline-size'.
- let computed_min_inline_size = specified(block.fragment().style().min_inline_size(),
- containing_block_inline_size);
+ let computed_min_inline_size =
+ block.fragment().style().min_inline_size().to_used_value(containing_block_inline_size);
if computed_min_inline_size > solution.inline_size {
input.computed_inline_size = MaybeAuto::Specified(computed_min_inline_size);
solution = self.solve_inline_size_constraints(block, &input);
diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs
index c3ac7f09048..63ec70b7096 100644
--- a/components/layout/display_list_builder.rs
+++ b/components/layout/display_list_builder.rs
@@ -33,8 +33,8 @@ use gfx_traits::{combine_id_with_fragment_type, FragmentType, StackingContextId}
use inline::{FIRST_FRAGMENT_OF_ELEMENT, InlineFlow, LAST_FRAGMENT_OF_ELEMENT};
use ipc_channel::ipc;
use list_item::ListItemFlow;
-use model::{self, MaybeAuto, specified};
-use msg::constellation_msg::FrameId;
+use model::{self, MaybeAuto};
+use msg::constellation_msg::BrowsingContextId;
use net_traits::image::base::PixelFormat;
use net_traits::image_cache::UsePlaceholder;
use range::Range;
@@ -68,7 +68,8 @@ use style::values::specified::position::{X, Y};
use style_traits::CSSPixel;
use style_traits::cursor::Cursor;
use table_cell::CollapsedBordersForCell;
-use webrender_traits::{ColorF, ClipId, GradientStop, RepeatMode, ScrollPolicy};
+use webrender_helpers::{ToMixBlendMode, ToTransformStyle};
+use webrender_traits::{ColorF, ClipId, GradientStop, RepeatMode, ScrollPolicy, TransformStyle};
trait ResolvePercentage {
fn resolve(&self, length: u32) -> u32;
@@ -175,7 +176,7 @@ pub struct DisplayListBuildState<'a> {
/// Vector containing iframe sizes, used to inform the constellation about
/// new iframe sizes
- pub iframe_sizes: Vec<(FrameId, TypedSize2D<f32, CSSPixel>)>,
+ pub iframe_sizes: Vec<(BrowsingContextId, TypedSize2D<f32, CSSPixel>)>,
/// A stack of clips used to cull display list entries that are outside the
/// rendered region.
@@ -184,6 +185,9 @@ pub struct DisplayListBuildState<'a> {
/// A stack of clips used to cull display list entries that are outside the
/// rendered region, but only collected at containing block boundaries.
pub containing_block_clip_stack: Vec<Rect<Au>>,
+
+ /// The current transform style of the stacking context.
+ current_transform_style: TransformStyle,
}
impl<'a> DisplayListBuildState<'a> {
@@ -201,6 +205,7 @@ impl<'a> DisplayListBuildState<'a> {
iframe_sizes: Vec::new(),
clip_stack: Vec::new(),
containing_block_clip_stack: Vec::new(),
+ current_transform_style: TransformStyle::Flat,
}
}
@@ -212,6 +217,7 @@ impl<'a> DisplayListBuildState<'a> {
fn add_stacking_context(&mut self,
parent_id: StackingContextId,
stacking_context: StackingContext) {
+ self.current_transform_style = stacking_context.transform_style;
let info = self.stacking_context_info
.entry(parent_id)
.or_insert(StackingContextInfo::new());
@@ -1020,10 +1026,8 @@ impl FragmentDisplayListBuilding for Fragment {
let horiz_position = *get_cyclic(&background.background_position_x.0, index);
let vert_position = *get_cyclic(&background.background_position_y.0, index);
// Use `background-position` to get the offset.
- let horizontal_position = model::specified(horiz_position,
- bounds.size.width - image_size.width);
- let vertical_position = model::specified(vert_position,
- bounds.size.height - image_size.height);
+ let horizontal_position = horiz_position.to_used_value(bounds.size.width - image_size.width);
+ let vertical_position = vert_position.to_used_value(bounds.size.height - image_size.height);
// The anchor position for this background, based on both the background-attachment
// and background-position properties.
@@ -1179,8 +1183,8 @@ impl FragmentDisplayListBuilding for Fragment {
repeating: bool,
style: &ServoComputedValues)
-> display_list::RadialGradient {
- let center = Point2D::new(specified(center.horizontal, bounds.size.width),
- specified(center.vertical, bounds.size.height));
+ let center = Point2D::new(center.horizontal.to_used_value(bounds.size.width),
+ center.vertical.to_used_value(bounds.size.height));
let radius = match *shape {
GenericEndingShape::Circle(Circle::Radius(length)) => {
Size2D::new(length, length)
@@ -1189,7 +1193,7 @@ impl FragmentDisplayListBuilding for Fragment {
convert_circle_size_keyword(extent, &bounds.size, &center)
},
GenericEndingShape::Ellipse(Ellipse::Radii(x, y)) => {
- Size2D::new(specified(x, bounds.size.width), specified(y, bounds.size.height))
+ Size2D::new(x.to_used_value(bounds.size.width), y.to_used_value(bounds.size.height))
},
GenericEndingShape::Ellipse(Ellipse::Extent(extent)) => {
convert_ellipse_size_keyword(extent, &bounds.size, &center)
@@ -1823,7 +1827,7 @@ impl FragmentDisplayListBuilding for Fragment {
let size = Size2D::new(item.bounds().size.width.to_f32_px(),
item.bounds().size.height.to_f32_px());
- state.iframe_sizes.push((fragment_info.frame_id, TypedSize2D::from_untyped(&size)));
+ state.iframe_sizes.push((fragment_info.browsing_context_id, TypedSize2D::from_untyped(&size)));
state.add_display_item(item);
}
@@ -1947,8 +1951,9 @@ impl FragmentDisplayListBuilding for Fragment {
&overflow,
self.effective_z_index(),
filters,
- self.style().get_effects().mix_blend_mode,
+ self.style().get_effects().mix_blend_mode.to_mix_blend_mode(),
self.transform_matrix(&border_box),
+ self.style().get_used_transform_style().to_transform_style(),
self.perspective_matrix(&border_box),
scroll_policy,
parent_scroll_id)
@@ -2153,6 +2158,7 @@ pub struct PreservedDisplayListState {
containing_block_scroll_root_id: ClipId,
clips_pushed: usize,
containing_block_clips_pushed: usize,
+ transform_style: TransformStyle,
}
impl PreservedDisplayListState {
@@ -2163,6 +2169,7 @@ impl PreservedDisplayListState {
containing_block_scroll_root_id: state.containing_block_scroll_root_id,
clips_pushed: 0,
containing_block_clips_pushed: 0,
+ transform_style: state.current_transform_style,
}
}
@@ -2183,6 +2190,8 @@ impl PreservedDisplayListState {
let truncate_length = state.containing_block_clip_stack.len() -
self.containing_block_clips_pushed;
state.containing_block_clip_stack.truncate(truncate_length);
+
+ state.current_transform_style = self.transform_style;
}
fn push_clip(&mut self,
@@ -2236,6 +2245,14 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
}
match transform {
+ Some(transform) if transform.m13 != 0.0 || transform.m23 != 0.0 => {
+ // We cannot properly handle perspective transforms, because there may be a
+ // situation where an element is transformed from outside the clip into the
+ // clip region. Here we don't have enough information to detect when that is
+ // happening. For the moment we just punt on trying to optimize the display
+ // list for those cases.
+ max_rect()
+ }
Some(transform) => {
let clip = Rect::new(Point2D::new((clip.origin.x - origin.x).to_f32_px(),
(clip.origin.y - origin.y).to_f32_px()),
@@ -2614,14 +2631,14 @@ impl InlineFlowDisplayListBuilding for InlineFlow {
fragment.stacking_context_id = fragment.stacking_context_id();
let current_stacking_context_id = state.current_stacking_context_id;
- let current_scroll_root_id = state.current_scroll_root_id;
+ let stacking_context = fragment.create_stacking_context(fragment.stacking_context_id,
+ &self.base,
+ ScrollPolicy::Scrollable,
+ StackingContextCreationMode::Normal,
+ state.current_scroll_root_id);
+
state.add_stacking_context(current_stacking_context_id,
- fragment.create_stacking_context(
- fragment.stacking_context_id,
- &self.base,
- ScrollPolicy::Scrollable,
- StackingContextCreationMode::Normal,
- current_scroll_root_id));
+ stacking_context);
}
_ => fragment.stacking_context_id = state.current_stacking_context_id,
}
@@ -2786,12 +2803,13 @@ struct StopRun {
stop_count: usize,
}
-fn position_to_offset(position: LengthOrPercentage, Au(total_length): Au) -> f32 {
+fn position_to_offset(position: LengthOrPercentage, total_length: Au) -> f32 {
match position {
- LengthOrPercentage::Length(Au(length)) => length as f32 / total_length as f32,
+ LengthOrPercentage::Length(Au(length)) => length as f32 / total_length.0 as f32,
LengthOrPercentage::Percentage(percentage) => percentage as f32,
- LengthOrPercentage::Calc(calc) =>
- calc.percentage() + (calc.length().0 as f32) / (total_length as f32),
+ LengthOrPercentage::Calc(calc) => {
+ calc.to_used_value(Some(total_length)).unwrap().0 as f32 / total_length.0 as f32
+ },
}
}
diff --git a/components/layout/flex.rs b/components/layout/flex.rs
index dd990c61510..0abd32b6dc0 100644
--- a/components/layout/flex.rs
+++ b/components/layout/flex.rs
@@ -18,7 +18,6 @@ use flow::{INLINE_POSITION_IS_STATIC, IS_ABSOLUTELY_POSITIONED};
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
use layout_debug;
use model::{IntrinsicISizes, MaybeAuto, SizeConstraint};
-use model::{specified, specified_or_none};
use std::cmp::{max, min};
use std::ops::Range;
use style::computed_values::{align_content, align_self, flex_direction, flex_wrap, justify_content};
@@ -52,7 +51,7 @@ impl AxisSize {
}
}
LengthOrPercentageOrAuto::Calc(calc) => {
- match calc.to_computed(content_size) {
+ match calc.to_used_value(content_size) {
Some(length) => AxisSize::Definite(length),
None => AxisSize::Infinite,
}
@@ -79,7 +78,7 @@ fn from_flex_basis(flex_basis: LengthOrPercentageOrAutoOrContent,
(LengthOrPercentageOrAutoOrContent::Percentage(_), None) =>
MaybeAuto::Auto,
(LengthOrPercentageOrAutoOrContent::Calc(calc), _) =>
- MaybeAuto::from_option(calc.to_computed(containing_length)),
+ MaybeAuto::from_option(calc.to_used_value(containing_length)),
(LengthOrPercentageOrAutoOrContent::Content, _) =>
MaybeAuto::Auto,
(LengthOrPercentageOrAutoOrContent::Auto, Some(size)) =>
@@ -169,10 +168,11 @@ impl FlexItem {
- margin
+ block.fragment.box_sizing_boundary(direction);
self.base_size = basis.specified_or_default(content_size);
- self.max_size = specified_or_none(block.fragment.style.max_inline_size(),
- containing_length).unwrap_or(MAX_AU);
- self.min_size = specified(block.fragment.style.min_inline_size(),
- containing_length);
+ self.max_size =
+ block.fragment.style.max_inline_size()
+ .to_used_value(containing_length)
+ .unwrap_or(MAX_AU);
+ self.min_size = block.fragment.style.min_inline_size().to_used_value(containing_length);
}
Direction::Block => {
let basis = from_flex_basis(block.fragment.style.get_position().flex_basis,
@@ -182,10 +182,11 @@ impl FlexItem {
- block.fragment.border_padding.block_start_end()
+ block.fragment.box_sizing_boundary(direction);
self.base_size = basis.specified_or_default(content_size);
- self.max_size = specified_or_none(block.fragment.style.max_block_size(),
- containing_length).unwrap_or(MAX_AU);
- self.min_size = specified(block.fragment.style.min_block_size(),
- containing_length);
+ self.max_size =
+ block.fragment.style.max_block_size()
+ .to_used_value(containing_length)
+ .unwrap_or(MAX_AU);
+ self.min_size = block.fragment.style.min_block_size().to_used_value(containing_length);
}
}
}
diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs
index c4dfefcc696..c0991ea2535 100644
--- a/components/layout/fragment.rs
+++ b/components/layout/fragment.rs
@@ -26,7 +26,7 @@ use ipc_channel::ipc::IpcSender;
use layout_debug;
use model::{self, IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto, SizeConstraint};
use model::{style_length, ToGfxMatrix};
-use msg::constellation_msg::{FrameId, PipelineId};
+use msg::constellation_msg::{BrowsingContextId, PipelineId};
use net_traits::image::base::{Image, ImageMetadata};
use net_traits::image_cache::{ImageOrMetadataAvailable, UsePlaceholder};
use range::*;
@@ -472,7 +472,7 @@ impl ImageFragmentInfo {
#[derive(Clone)]
pub struct IframeFragmentInfo {
/// The frame ID of this iframe.
- pub frame_id: FrameId,
+ pub browsing_context_id: BrowsingContextId,
/// The pipelineID of this iframe.
pub pipeline_id: PipelineId,
}
@@ -480,10 +480,10 @@ pub struct IframeFragmentInfo {
impl IframeFragmentInfo {
/// Creates the information specific to an iframe fragment.
pub fn new<N: ThreadSafeLayoutNode>(node: &N) -> IframeFragmentInfo {
- let frame_id = node.iframe_frame_id();
+ let browsing_context_id = node.iframe_browsing_context_id();
let pipeline_id = node.iframe_pipeline_id();
IframeFragmentInfo {
- frame_id: frame_id,
+ browsing_context_id: browsing_context_id,
pipeline_id: pipeline_id,
}
}
@@ -907,8 +907,8 @@ impl Fragment {
// cascading.
let padding = if flags.contains(INTRINSIC_INLINE_SIZE_INCLUDES_PADDING) {
let padding = style.logical_padding();
- (model::specified(padding.inline_start, Au(0)) +
- model::specified(padding.inline_end, Au(0)))
+ (padding.inline_start.to_used_value(Au(0)) +
+ padding.inline_end.to_used_value(Au(0)))
} else {
Au(0)
};
@@ -935,8 +935,8 @@ impl Fragment {
if flags.contains(INTRINSIC_INLINE_SIZE_INCLUDES_SPECIFIED) {
specified = MaybeAuto::from_style(style.content_inline_size(),
Au(0)).specified_or_zero();
- specified = max(model::specified(style.min_inline_size(), Au(0)), specified);
- if let Some(max) = model::specified_or_none(style.max_inline_size(), Au(0)) {
+ specified = max(style.min_inline_size().to_used_value(Au(0)), specified);
+ if let Some(max) = style.max_inline_size().to_used_value(Au(0)) {
specified = min(specified, max)
}
@@ -1159,10 +1159,10 @@ impl Fragment {
let border_width = self.border_width();
SpeculatedInlineContentEdgeOffsets {
start: MaybeAuto::from_style(logical_margin.inline_start, Au(0)).specified_or_zero() +
- model::specified(logical_padding.inline_start, Au(0)) +
+ logical_padding.inline_start.to_used_value(Au(0)) +
border_width.inline_start,
end: MaybeAuto::from_style(logical_margin.inline_end, Au(0)).specified_or_zero() +
- model::specified(logical_padding.inline_end, Au(0)) +
+ logical_padding.inline_end.to_used_value(Au(0)) +
border_width.inline_end,
}
}
@@ -1491,10 +1491,10 @@ impl Fragment {
// the size constraints work properly.
// TODO(stshine): Find a cleaner way to do this.
let padding = self.style.logical_padding();
- self.border_padding.inline_start = model::specified(padding.inline_start, Au(0));
- self.border_padding.inline_end = model::specified(padding.inline_end, Au(0));
- self.border_padding.block_start = model::specified(padding.block_start, Au(0));
- self.border_padding.block_end = model::specified(padding.block_end, Au(0));
+ self.border_padding.inline_start = padding.inline_start.to_used_value(Au(0));
+ self.border_padding.inline_end = padding.inline_end.to_used_value(Au(0));
+ self.border_padding.block_start = padding.block_start.to_used_value(Au(0));
+ self.border_padding.block_end = padding.block_end.to_used_value(Au(0));
let border = self.border_width();
self.border_padding.inline_start += border.inline_start;
self.border_padding.inline_end += border.inline_end;
@@ -1504,7 +1504,11 @@ impl Fragment {
result_inline
}
LengthOrPercentageOrAuto::Length(length) => length,
- LengthOrPercentageOrAuto::Calc(calc) => calc.length(),
+ LengthOrPercentageOrAuto::Calc(calc) => {
+ // TODO(nox): This is probably wrong, because it accounts neither for
+ // clamping (not sure if necessary here) nor percentage.
+ calc.unclamped_length()
+ },
};
let size_constraint = self.size_constraint(None, Direction::Inline);
@@ -2233,8 +2237,7 @@ impl Fragment {
offset -= minimum_line_metrics.space_needed().scale_by(percentage)
}
vertical_align::T::LengthOrPercentage(LengthOrPercentage::Calc(formula)) => {
- offset -= minimum_line_metrics.space_needed().scale_by(formula.percentage()) +
- formula.length()
+ offset -= formula.to_used_value(Some(minimum_line_metrics.space_needed())).unwrap()
}
}
}
@@ -2470,7 +2473,10 @@ impl Fragment {
if self.style().get_effects().mix_blend_mode != mix_blend_mode::T::normal {
return true
}
- if self.style().get_box().transform.0.is_some() {
+
+ if self.style().get_box().transform.0.is_some() ||
+ self.style().get_box().transform_style == transform_style::T::preserve_3d ||
+ self.style().overrides_transform_style() {
return true
}
@@ -2485,13 +2491,6 @@ impl Fragment {
return true
}
- match self.style().get_used_transform_style() {
- transform_style::T::flat | transform_style::T::preserve_3d => {
- return true
- }
- transform_style::T::auto => {}
- }
-
match (self.style().get_box().position,
self.style().get_position().z_index,
self.style().get_box().overflow_x,
@@ -2851,12 +2850,14 @@ impl Fragment {
let mut transform = Matrix4D::identity();
let transform_origin = &self.style.get_box().transform_origin;
- let transform_origin_x = model::specified(transform_origin.horizontal,
- stacking_relative_border_box.size
- .width).to_f32_px();
- let transform_origin_y = model::specified(transform_origin.vertical,
- stacking_relative_border_box.size
- .height).to_f32_px();
+ let transform_origin_x =
+ transform_origin.horizontal
+ .to_used_value(stacking_relative_border_box.size.width)
+ .to_f32_px();
+ let transform_origin_y =
+ transform_origin.vertical
+ .to_used_value(stacking_relative_border_box.size.height)
+ .to_f32_px();
let transform_origin_z = transform_origin.depth.to_f32_px();
let pre_transform = Matrix4D::create_translation(transform_origin_x,
@@ -2879,10 +2880,8 @@ impl Fragment {
Matrix4D::create_scale(sx, sy, sz)
}
transform::ComputedOperation::Translate(tx, ty, tz) => {
- let tx =
- model::specified(tx, stacking_relative_border_box.size.width).to_f32_px();
- let ty =
- model::specified(ty, stacking_relative_border_box.size.height).to_f32_px();
+ let tx = tx.to_used_value(stacking_relative_border_box.size.width).to_f32_px();
+ let ty = ty.to_used_value(stacking_relative_border_box.size.height).to_f32_px();
let tz = tz.to_f32_px();
Matrix4D::create_translation(tx, ty, tz)
}
@@ -2911,10 +2910,13 @@ impl Fragment {
Either::First(length) => {
let perspective_origin = self.style().get_box().perspective_origin;
let perspective_origin =
- Point2D::new(model::specified(perspective_origin.horizontal,
- stacking_relative_border_box.size.width).to_f32_px(),
- model::specified(perspective_origin.vertical,
- stacking_relative_border_box.size.height).to_f32_px());
+ Point2D::new(
+ perspective_origin.horizontal
+ .to_used_value(stacking_relative_border_box.size.width)
+ .to_f32_px(),
+ perspective_origin.vertical
+ .to_used_value(stacking_relative_border_box.size.height)
+ .to_f32_px());
let pre_transform = Matrix4D::create_translation(perspective_origin.x,
perspective_origin.y,
diff --git a/components/layout/model.rs b/components/layout/model.rs
index aba7c3f3927..a762c1d59c8 100644
--- a/components/layout/model.rs
+++ b/components/layout/model.rs
@@ -412,7 +412,7 @@ impl MaybeAuto {
MaybeAuto::Specified(containing_length.scale_by(percent))
}
LengthOrPercentageOrAuto::Calc(calc) => {
- MaybeAuto::from_option(calc.to_computed(Some(containing_length)))
+ MaybeAuto::from_option(calc.to_used_value(Some(containing_length)))
}
LengthOrPercentageOrAuto::Length(length) => MaybeAuto::Specified(length)
}
@@ -463,24 +463,6 @@ pub fn style_length(style_length: LengthOrPercentageOrAuto,
}
}
-pub fn specified_or_none(length: LengthOrPercentageOrNone, containing_length: Au) -> Option<Au> {
- match length {
- LengthOrPercentageOrNone::None => None,
- LengthOrPercentageOrNone::Percentage(percent) => Some(containing_length.scale_by(percent)),
- LengthOrPercentageOrNone::Calc(calc) => calc.to_computed(Some(containing_length)),
- LengthOrPercentageOrNone::Length(length) => Some(length),
- }
-}
-
-pub fn specified(length: LengthOrPercentage, containing_length: Au) -> Au {
- match length {
- LengthOrPercentage::Length(length) => length,
- LengthOrPercentage::Percentage(p) => containing_length.scale_by(p),
- LengthOrPercentage::Calc(calc) =>
- containing_length.scale_by(calc.percentage()) + calc.length(),
- }
-}
-
/// Computes a border radius size against the containing size.
///
/// Note that percentages in `border-radius` are resolved against the relevant
@@ -495,8 +477,8 @@ pub fn specified_border_radius(
-> Size2D<Au>
{
let generics::BorderRadiusSize(size) = radius;
- let w = specified(size.width, containing_size.width);
- let h = specified(size.height, containing_size.height);
+ let w = size.width.to_used_value(containing_size.width);
+ let h = size.height.to_used_value(containing_size.height);
Size2D::new(w, h)
}
@@ -507,10 +489,10 @@ pub fn padding_from_style(style: &ServoComputedValues,
-> LogicalMargin<Au> {
let padding_style = style.get_padding();
LogicalMargin::from_physical(writing_mode, SideOffsets2D::new(
- specified(padding_style.padding_top, containing_block_inline_size),
- specified(padding_style.padding_right, containing_block_inline_size),
- specified(padding_style.padding_bottom, containing_block_inline_size),
- specified(padding_style.padding_left, containing_block_inline_size)))
+ padding_style.padding_top.to_used_value(containing_block_inline_size),
+ padding_style.padding_right.to_used_value(containing_block_inline_size),
+ padding_style.padding_bottom.to_used_value(containing_block_inline_size),
+ padding_style.padding_left.to_used_value(containing_block_inline_size)))
}
/// Returns the explicitly-specified margin lengths from the given style. Percentage and auto
@@ -559,7 +541,7 @@ impl SizeConstraint {
max_size: LengthOrPercentageOrNone,
border: Option<Au>) -> SizeConstraint {
let mut min_size = match container_size {
- Some(container_size) => specified(min_size, container_size),
+ Some(container_size) => min_size.to_used_value(container_size),
None => if let LengthOrPercentage::Length(length) = min_size {
length
} else {
@@ -568,7 +550,7 @@ impl SizeConstraint {
};
let mut max_size = match container_size {
- Some(container_size) => specified_or_none(max_size, container_size),
+ Some(container_size) => max_size.to_used_value(container_size),
None => if let LengthOrPercentageOrNone::Length(length) = max_size {
Some(length)
} else {
diff --git a/components/layout/webrender_helpers.rs b/components/layout/webrender_helpers.rs
index ca7cdb27a3f..537d5f04267 100644
--- a/components/layout/webrender_helpers.rs
+++ b/components/layout/webrender_helpers.rs
@@ -12,7 +12,7 @@ use euclid::{Point2D, Rect, SideOffsets2D, Size2D};
use gfx::display_list::{BorderDetails, BorderRadii, BoxShadowClipMode, ClippingRegion};
use gfx::display_list::{DisplayItem, DisplayList, DisplayListTraversal, StackingContextType};
use msg::constellation_msg::PipelineId;
-use style::computed_values::{image_rendering, mix_blend_mode};
+use style::computed_values::{image_rendering, mix_blend_mode, transform_style};
use style::computed_values::filter::{self, Filter};
use style::values::computed::BorderStyle;
use webrender_traits::{self, DisplayListBuilder, ExtendMode};
@@ -146,12 +146,12 @@ impl ToBorderRadius for BorderRadii<Au> {
}
}
-trait ToBlendMode {
- fn to_blend_mode(&self) -> webrender_traits::MixBlendMode;
+pub trait ToMixBlendMode {
+ fn to_mix_blend_mode(&self) -> webrender_traits::MixBlendMode;
}
-impl ToBlendMode for mix_blend_mode::T {
- fn to_blend_mode(&self) -> webrender_traits::MixBlendMode {
+impl ToMixBlendMode for mix_blend_mode::T {
+ fn to_mix_blend_mode(&self) -> webrender_traits::MixBlendMode {
match *self {
mix_blend_mode::T::normal => webrender_traits::MixBlendMode::Normal,
mix_blend_mode::T::multiply => webrender_traits::MixBlendMode::Multiply,
@@ -211,6 +211,19 @@ impl ToFilterOps for filter::T {
}
}
+pub trait ToTransformStyle {
+ fn to_transform_style(&self) -> webrender_traits::TransformStyle;
+}
+
+impl ToTransformStyle for transform_style::T {
+ fn to_transform_style(&self) -> webrender_traits::TransformStyle {
+ match *self {
+ transform_style::T::auto | transform_style::T::flat => webrender_traits::TransformStyle::Flat,
+ transform_style::T::preserve_3d => webrender_traits::TransformStyle::Preserve3D,
+ }
+ }
+}
+
impl WebRenderDisplayListConverter for DisplayList {
fn convert_to_webrender(&self, pipeline_id: PipelineId) -> DisplayListBuilder {
let traversal = DisplayListTraversal::new(self);
@@ -464,9 +477,9 @@ impl WebRenderDisplayItemConverter for DisplayItem {
builder.push_stacking_context(stacking_context.scroll_policy,
stacking_context.bounds.to_rectf(),
transform,
- webrender_traits::TransformStyle::Flat,
+ stacking_context.transform_style,
perspective,
- stacking_context.blend_mode.to_blend_mode(),
+ stacking_context.mix_blend_mode,
stacking_context.filters.to_filter_ops());
}
DisplayItem::PopStackingContext(_) => builder.pop_stacking_context(),
diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs
index eed95ecb9ea..8185aa6e409 100644
--- a/components/layout_thread/lib.rs
+++ b/components/layout_thread/lib.rs
@@ -74,7 +74,7 @@ use layout::webrender_helpers::WebRenderDisplayListConverter;
use layout::wrapper::LayoutNodeLayoutData;
use layout::wrapper::drop_style_and_layout_data;
use layout_traits::LayoutThreadFactory;
-use msg::constellation_msg::{FrameId, PipelineId};
+use msg::constellation_msg::{BrowsingContextId, PipelineId};
use net_traits::image_cache::{ImageCache, UsePlaceholder};
use parking_lot::RwLock;
use profile_traits::mem::{self, Report, ReportKind, ReportsChan};
@@ -244,7 +244,7 @@ impl LayoutThreadFactory for LayoutThread {
/// Spawns a new layout thread.
fn create(id: PipelineId,
- top_level_frame_id: Option<FrameId>,
+ top_level_browsing_context_id: Option<BrowsingContextId>,
url: ServoUrl,
is_iframe: bool,
chan: (Sender<Msg>, Receiver<Msg>),
@@ -261,8 +261,8 @@ impl LayoutThreadFactory for LayoutThread {
thread::Builder::new().name(format!("LayoutThread {:?}", id)).spawn(move || {
thread_state::initialize(thread_state::LAYOUT);
- if let Some(top_level_frame_id) = top_level_frame_id {
- FrameId::install(top_level_frame_id);
+ if let Some(top_level_browsing_context_id) = top_level_browsing_context_id {
+ BrowsingContextId::install(top_level_browsing_context_id);
}
{ // Ensures layout thread is destroyed before we send shutdown message
@@ -732,7 +732,7 @@ impl LayoutThread {
fn create_layout_thread(&self, info: NewLayoutThreadInfo) {
LayoutThread::create(info.id,
- FrameId::installed(),
+ BrowsingContextId::installed(),
info.url.clone(),
info.is_parent,
info.layout_pair,
@@ -930,7 +930,7 @@ impl LayoutThread {
// build_state.iframe_sizes is only used here, so its okay to replace
// it with an empty vector
let iframe_sizes = std::mem::replace(&mut build_state.iframe_sizes, vec![]);
- let msg = ConstellationMsg::FrameSizes(iframe_sizes);
+ let msg = ConstellationMsg::IFrameSizes(iframe_sizes);
if let Err(e) = self.constellation_chan.send(msg) {
warn!("Layout resize to constellation failed ({}).", e);
}
diff --git a/components/layout_traits/lib.rs b/components/layout_traits/lib.rs
index 9d97a89a53c..53aa2529cb0 100644
--- a/components/layout_traits/lib.rs
+++ b/components/layout_traits/lib.rs
@@ -20,7 +20,7 @@ extern crate webrender_traits;
use gfx::font_cache_thread::FontCacheThread;
use ipc_channel::ipc::{IpcReceiver, IpcSender};
-use msg::constellation_msg::{FrameId, PipelineId};
+use msg::constellation_msg::{BrowsingContextId, PipelineId};
use net_traits::image_cache::ImageCache;
use profile_traits::{mem, time};
use script_traits::{ConstellationControlMsg, LayoutControlMsg};
@@ -34,7 +34,7 @@ use std::sync::mpsc::{Receiver, Sender};
pub trait LayoutThreadFactory {
type Message;
fn create(id: PipelineId,
- top_level_frame_id: Option<FrameId>,
+ top_level_browsing_context_id: Option<BrowsingContextId>,
url: ServoUrl,
is_iframe: bool,
chan: (Sender<Self::Message>, Receiver<Self::Message>),
diff --git a/components/msg/constellation_msg.rs b/components/msg/constellation_msg.rs
index 02d4157f20c..edec5fb5231 100644
--- a/components/msg/constellation_msg.rs
+++ b/components/msg/constellation_msg.rs
@@ -207,10 +207,10 @@ impl PipelineNamespace {
}
}
- fn next_frame_id(&mut self) -> FrameId {
- FrameId {
+ fn next_browsing_context_id(&mut self) -> BrowsingContextId {
+ BrowsingContextId {
namespace_id: self.id,
- index: FrameIndex(self.next_index()),
+ index: BrowsingContextIndex(self.next_index()),
}
}
}
@@ -258,42 +258,41 @@ impl fmt::Display for PipelineId {
}
}
-thread_local!(pub static TOP_LEVEL_FRAME_ID: Cell<Option<FrameId>> = Cell::new(None));
+thread_local!(pub static TOP_LEVEL_BROWSING_CONTEXT_ID: Cell<Option<BrowsingContextId>> = Cell::new(None));
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)]
-pub struct FrameIndex(pub u32);
+pub struct BrowsingContextIndex(pub u32);
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)]
-pub struct FrameId {
+pub struct BrowsingContextId {
pub namespace_id: PipelineNamespaceId,
- pub index: FrameIndex
+ pub index: BrowsingContextIndex
}
-impl FrameId {
- pub fn new() -> FrameId {
+impl BrowsingContextId {
+ pub fn new() -> BrowsingContextId {
PIPELINE_NAMESPACE.with(|tls| {
let mut namespace = tls.get().expect("No namespace set for this thread!");
- let new_frame_id = namespace.next_frame_id();
+ let new_browsing_context_id = namespace.next_browsing_context_id();
tls.set(Some(namespace));
- new_frame_id
+ new_browsing_context_id
})
}
-
- /// Each script and layout thread should have the top-level frame id installed,
+ /// Each script and layout thread should have the top-level browsing context id installed,
/// since it is used by crash reporting.
- pub fn install(id: FrameId) {
- TOP_LEVEL_FRAME_ID.with(|tls| tls.set(Some(id)))
+ pub fn install(id: BrowsingContextId) {
+ TOP_LEVEL_BROWSING_CONTEXT_ID.with(|tls| tls.set(Some(id)))
}
- pub fn installed() -> Option<FrameId> {
- TOP_LEVEL_FRAME_ID.with(|tls| tls.get())
+ pub fn installed() -> Option<BrowsingContextId> {
+ TOP_LEVEL_BROWSING_CONTEXT_ID.with(|tls| tls.get())
}
}
-impl fmt::Display for FrameId {
+impl fmt::Display for BrowsingContextId {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let PipelineNamespaceId(namespace_id) = self.namespace_id;
- let FrameIndex(index) = self.index;
+ let BrowsingContextIndex(index) = self.index;
write!(fmt, "({},{})", namespace_id, index)
}
}
@@ -302,8 +301,9 @@ impl fmt::Display for FrameId {
pub const TEST_NAMESPACE: PipelineNamespaceId = PipelineNamespaceId(1234);
pub const TEST_PIPELINE_INDEX: PipelineIndex = PipelineIndex(5678);
pub const TEST_PIPELINE_ID: PipelineId = PipelineId { namespace_id: TEST_NAMESPACE, index: TEST_PIPELINE_INDEX };
-pub const TEST_FRAME_INDEX: FrameIndex = FrameIndex(8765);
-pub const TEST_FRAME_ID: FrameId = FrameId { namespace_id: TEST_NAMESPACE, index: TEST_FRAME_INDEX };
+pub const TEST_BROWSING_CONTEXT_INDEX: BrowsingContextIndex = BrowsingContextIndex(8765);
+pub const TEST_BROWSING_CONTEXT_ID: BrowsingContextId =
+ BrowsingContextId { namespace_id: TEST_NAMESPACE, index: TEST_BROWSING_CONTEXT_INDEX };
#[derive(Clone, PartialEq, Eq, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)]
pub enum FrameType {
diff --git a/components/profile/time.rs b/components/profile/time.rs
index 928eca4a263..dfe5c37068d 100644
--- a/components/profile/time.rs
+++ b/components/profile/time.rs
@@ -150,6 +150,7 @@ impl Formattable for ProfilerCategory {
ProfilerCategory::ScriptEnterFullscreen => "Script Enter Fullscreen",
ProfilerCategory::ScriptExitFullscreen => "Script Exit Fullscreen",
ProfilerCategory::ScriptWebVREvent => "Script WebVR Event",
+ ProfilerCategory::ScriptWorkletEvent => "Script Worklet Event",
ProfilerCategory::ApplicationHeartbeat => "Application Heartbeat",
};
format!("{}{}", padding, name)
diff --git a/components/profile_traits/time.rs b/components/profile_traits/time.rs
index 7bbebf5f465..369c2fa366d 100644
--- a/components/profile_traits/time.rs
+++ b/components/profile_traits/time.rs
@@ -89,6 +89,7 @@ pub enum ProfilerCategory {
ScriptEnterFullscreen = 0x77,
ScriptExitFullscreen = 0x78,
ScriptWebVREvent = 0x79,
+ ScriptWorkletEvent = 0x7a,
ApplicationHeartbeat = 0x90,
}
diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml
index 306dd2a748d..388801aa011 100644
--- a/components/script/Cargo.toml
+++ b/components/script/Cargo.toml
@@ -83,6 +83,7 @@ servo_url = {path = "../url"}
smallvec = "0.3"
style = {path = "../style"}
style_traits = {path = "../style_traits"}
+swapper = "0.0.4"
time = "0.1.12"
unicode-segmentation = "1.1.0"
url = {version = "1.2", features = ["heap_size", "query_encoding"]}
diff --git a/components/script/dom/attr.rs b/components/script/dom/attr.rs
index 3c775ffdf57..af5f0107ae4 100644
--- a/components/script/dom/attr.rs
+++ b/components/script/dom/attr.rs
@@ -10,6 +10,8 @@ use dom::bindings::js::{LayoutJS, MutNullableJS, Root, RootedReference};
use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::bindings::str::DOMString;
use dom::element::{AttributeMutation, Element};
+use dom::mutationobserver::{Mutation, MutationObserver};
+use dom::node::Node;
use dom::virtualmethods::vtable_for;
use dom::window::Window;
use dom_struct::dom_struct;
@@ -170,6 +172,12 @@ impl AttrMethods for Attr {
impl Attr {
pub fn set_value(&self, mut value: AttrValue, owner: &Element) {
+ let name = self.local_name().clone();
+ let namespace = self.namespace().clone();
+ let old_value = DOMString::from(&**self.value());
+ let mutation = Mutation::Attribute { name, namespace, old_value };
+ MutationObserver::queue_a_mutation_record(owner.upcast::<Node>(), mutation);
+
assert!(Some(owner) == self.owner().r());
owner.will_mutate_attr(self);
self.swap_value(&mut value);
diff --git a/components/script/dom/bindings/refcounted.rs b/components/script/dom/bindings/refcounted.rs
index dcf11626543..f22074d5fef 100644
--- a/components/script/dom/bindings/refcounted.rs
+++ b/components/script/dom/bindings/refcounted.rs
@@ -23,12 +23,17 @@
//! as JS roots.
use core::nonzero::NonZero;
+use dom::bindings::conversions::ToJSValConvertible;
+use dom::bindings::error::Error;
use dom::bindings::js::Root;
use dom::bindings::reflector::{DomObject, Reflector};
use dom::bindings::trace::trace_reflector;
use dom::promise::Promise;
+use js::jsapi::JSAutoCompartment;
use js::jsapi::JSTracer;
use libc;
+use script_thread::Runnable;
+use script_thread::ScriptThread;
use std::cell::RefCell;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::collections::hash_map::HashMap;
@@ -115,6 +120,40 @@ impl TrustedPromise {
promise
})
}
+
+ /// A runnable which will reject the promise.
+ #[allow(unrooted_must_root)]
+ pub fn reject_runnable(self, error: Error) -> impl Runnable + Send {
+ struct RejectPromise(TrustedPromise, Error);
+ impl Runnable for RejectPromise {
+ fn main_thread_handler(self: Box<Self>, script_thread: &ScriptThread) {
+ let this = *self;
+ let cx = script_thread.get_cx();
+ let promise = this.0.root();
+ let _ac = JSAutoCompartment::new(cx, promise.reflector().get_jsobject().get());
+ promise.reject_error(cx, this.1);
+ }
+ }
+ RejectPromise(self, error)
+ }
+
+ /// A runnable which will resolve the promise.
+ #[allow(unrooted_must_root)]
+ pub fn resolve_runnable<T>(self, value: T) -> impl Runnable + Send where
+ T: ToJSValConvertible + Send
+ {
+ struct ResolvePromise<T>(TrustedPromise, T);
+ impl<T: ToJSValConvertible> Runnable for ResolvePromise<T> {
+ fn main_thread_handler(self: Box<Self>, script_thread: &ScriptThread) {
+ let this = *self;
+ let cx = script_thread.get_cx();
+ let promise = this.0.root();
+ let _ac = JSAutoCompartment::new(cx, promise.reflector().get_jsobject().get());
+ promise.resolve_native(cx, &this.1);
+ }
+ }
+ ResolvePromise(self, value)
+ }
}
/// A safe wrapper around a raw pointer to a DOM object that can be
diff --git a/components/script/dom/bindings/structuredclone.rs b/components/script/dom/bindings/structuredclone.rs
index b3a9df32695..53f3b63e085 100644
--- a/components/script/dom/bindings/structuredclone.rs
+++ b/components/script/dom/bindings/structuredclone.rs
@@ -67,16 +67,44 @@ unsafe fn read_length(r: *mut JSStructuredCloneReader)
return length as usize;
}
+struct StructuredCloneWriter {
+ w: *mut JSStructuredCloneWriter,
+}
+
+impl StructuredCloneWriter {
+ unsafe fn write_slice(&self, v: &[u8]) {
+ let type_length = v.len();
+ write_length(self.w, type_length);
+ assert!(JS_WriteBytes(self.w, v.as_ptr() as *const raw::c_void, type_length));
+ }
+ unsafe fn write_str(&self, s: &str) {
+ self.write_slice(s.as_bytes());
+ }
+}
+
+struct StructuredCloneReader {
+ r: *mut JSStructuredCloneReader,
+}
+
+impl StructuredCloneReader {
+ unsafe fn read_bytes(&self) -> Vec<u8> {
+ let mut bytes = vec![0u8; read_length(self.r)];
+ let blob_length = bytes.len();
+ assert!(JS_ReadBytes(self.r, bytes.as_mut_ptr() as *mut raw::c_void, blob_length));
+ return bytes;
+ }
+ unsafe fn read_str(&self) -> String {
+ let str_buffer = self.read_bytes();
+ return String::from_utf8_unchecked(str_buffer);
+ }
+}
+
unsafe fn read_blob(cx: *mut JSContext,
r: *mut JSStructuredCloneReader)
-> *mut JSObject {
- let blob_length = read_length(r);
- let type_str_length = read_length(r);
- let mut blob_buffer = vec![0u8; blob_length];
- assert!(JS_ReadBytes(r, blob_buffer.as_mut_ptr() as *mut raw::c_void, blob_length));
- let mut type_str_buffer = vec![0u8; type_str_length];
- assert!(JS_ReadBytes(r, type_str_buffer.as_mut_ptr() as *mut raw::c_void, type_str_length));
- let type_str = String::from_utf8_unchecked(type_str_buffer);
+ let structured_reader = StructuredCloneReader { r: r };
+ let blob_buffer = structured_reader.read_bytes();
+ let type_str = structured_reader.read_str();
let target_global = GlobalScope::from_context(cx);
let blob = Blob::new(&target_global, BlobImpl::new_from_bytes(blob_buffer), type_str);
return blob.reflector().get_jsobject().get()
@@ -85,15 +113,11 @@ unsafe fn read_blob(cx: *mut JSContext,
unsafe fn write_blob(blob: Root<Blob>,
w: *mut JSStructuredCloneWriter)
-> Result<(), ()> {
+ let structured_writer = StructuredCloneWriter { w: w };
let blob_vec = try!(blob.get_bytes());
- let blob_length = blob_vec.len();
- let type_string_bytes = blob.type_string().as_bytes().to_vec();
- let type_string_length = type_string_bytes.len();
assert!(JS_WriteUint32Pair(w, StructuredCloneTags::DomBlob as u32, 0));
- write_length(w, blob_length);
- write_length(w, type_string_length);
- assert!(JS_WriteBytes(w, blob_vec.as_ptr() as *const raw::c_void, blob_length));
- assert!(JS_WriteBytes(w, type_string_bytes.as_ptr() as *const raw::c_void, type_string_length));
+ structured_writer.write_slice(&blob_vec);
+ structured_writer.write_str(&blob.type_string());
return Ok(())
}
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs
index a0f26d12c23..2b3bfceceb2 100644
--- a/components/script/dom/bindings/trace.rs
+++ b/components/script/dom/bindings/trace.rs
@@ -58,7 +58,7 @@ use js::glue::{CallObjectTracer, CallValueTracer};
use js::jsapi::{GCTraceKindToAscii, Heap, JSObject, JSTracer, TraceKind};
use js::jsval::JSVal;
use js::rust::Runtime;
-use msg::constellation_msg::{FrameId, FrameType, PipelineId};
+use msg::constellation_msg::{BrowsingContextId, FrameType, PipelineId};
use net_traits::{Metadata, NetworkError, ReferrerPolicy, ResourceThreads};
use net_traits::filemanager_thread::RelativePos;
use net_traits::image::base::{Image, ImageMetadata};
@@ -336,7 +336,7 @@ unsafe_no_jsmanaged_fields!(TrustedPromise);
unsafe_no_jsmanaged_fields!(PropertyDeclarationBlock);
// These three are interdependent, if you plan to put jsmanaged data
// in one of these make sure it is propagated properly to containing structs
-unsafe_no_jsmanaged_fields!(DocumentActivity, FrameId, FrameType, WindowSizeData, WindowSizeType, PipelineId);
+unsafe_no_jsmanaged_fields!(DocumentActivity, BrowsingContextId, FrameType, WindowSizeData, WindowSizeType, PipelineId);
unsafe_no_jsmanaged_fields!(TimerEventId, TimerSource);
unsafe_no_jsmanaged_fields!(TimelineMarkerType);
unsafe_no_jsmanaged_fields!(WorkerId);
diff --git a/components/script/dom/dedicatedworkerglobalscope.rs b/components/script/dom/dedicatedworkerglobalscope.rs
index 14dd070f44d..6b73df12dfc 100644
--- a/components/script/dom/dedicatedworkerglobalscope.rs
+++ b/components/script/dom/dedicatedworkerglobalscope.rs
@@ -27,7 +27,7 @@ use js::jsapi::{HandleValue, JS_SetInterruptCallback};
use js::jsapi::{JSAutoCompartment, JSContext};
use js::jsval::UndefinedValue;
use js::rust::Runtime;
-use msg::constellation_msg::FrameId;
+use msg::constellation_msg::BrowsingContextId;
use net_traits::{IpcSend, load_whole_resource};
use net_traits::request::{CredentialsMode, Destination, RequestInit, Type as RequestType};
use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort, StackRootTLS, get_reports, new_rt_and_cx};
@@ -159,13 +159,13 @@ impl DedicatedWorkerGlobalScope {
closing: Arc<AtomicBool>) {
let serialized_worker_url = worker_url.to_string();
let name = format!("WebWorker for {}", serialized_worker_url);
- let top_level_frame_id = FrameId::installed();
+ let top_level_browsing_context_id = BrowsingContextId::installed();
thread::Builder::new().name(name).spawn(move || {
thread_state::initialize(thread_state::SCRIPT | thread_state::IN_WORKER);
- if let Some(top_level_frame_id) = top_level_frame_id {
- FrameId::install(top_level_frame_id);
+ if let Some(top_level_browsing_context_id) = top_level_browsing_context_id {
+ BrowsingContextId::install(top_level_browsing_context_id);
}
let roots = RootCollection::new();
diff --git a/components/script/dom/dissimilaroriginwindow.rs b/components/script/dom/dissimilaroriginwindow.rs
index 7d5bef36344..a4e230e90a2 100644
--- a/components/script/dom/dissimilaroriginwindow.rs
+++ b/components/script/dom/dissimilaroriginwindow.rs
@@ -184,7 +184,9 @@ impl DissimilarOriginWindowMethods for DissimilarOriginWindow {
impl DissimilarOriginWindow {
pub fn post_message(&self, origin: Option<ImmutableOrigin>, data: StructuredCloneData) {
- let msg = ConstellationMsg::PostMessage(self.window_proxy.frame_id(), origin, data.move_to_arraybuffer());
+ let msg = ConstellationMsg::PostMessage(self.window_proxy.browsing_context_id(),
+ origin,
+ data.move_to_arraybuffer());
let _ = self.upcast::<GlobalScope>().constellation_chan().send(msg);
}
}
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index e44de8be727..81ea073ab41 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -100,7 +100,7 @@ use ipc_channel::ipc::{self, IpcSender};
use js::jsapi::{JSContext, JSObject, JSRuntime};
use js::jsapi::JS_GetRuntime;
use msg::constellation_msg::{ALT, CONTROL, SHIFT, SUPER};
-use msg::constellation_msg::{FrameId, Key, KeyModifiers, KeyState};
+use msg::constellation_msg::{BrowsingContextId, Key, KeyModifiers, KeyState};
use net_traits::{FetchResponseMsg, IpcSend, ReferrerPolicy};
use net_traits::CookieSource::NonHTTP;
use net_traits::CoreResourceMsg::{GetCookiesForUrl, SetCookiesForUrl};
@@ -1897,9 +1897,9 @@ impl Document {
}
/// Find an iframe element in the document.
- pub fn find_iframe(&self, frame_id: FrameId) -> Option<Root<HTMLIFrameElement>> {
+ pub fn find_iframe(&self, browsing_context_id: BrowsingContextId) -> Option<Root<HTMLIFrameElement>> {
self.iter_iframes()
- .find(|node| node.frame_id() == frame_id)
+ .find(|node| node.browsing_context_id() == browsing_context_id)
}
pub fn get_dom_loading(&self) -> u64 {
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs
index aa32370127c..55175fd45c6 100644
--- a/components/script/dom/element.rs
+++ b/components/script/dom/element.rs
@@ -63,6 +63,7 @@ use dom::htmltablerowelement::{HTMLTableRowElement, HTMLTableRowElementLayoutHel
use dom::htmltablesectionelement::{HTMLTableSectionElement, HTMLTableSectionElementLayoutHelpers};
use dom::htmltemplateelement::HTMLTemplateElement;
use dom::htmltextareaelement::{HTMLTextAreaElement, LayoutHTMLTextAreaElementHelpers};
+use dom::mutationobserver::{Mutation, MutationObserver};
use dom::namednodemap::NamedNodeMap;
use dom::node::{CLICK_IN_PROGRESS, ChildrenMutation, LayoutNodeHelpers, Node};
use dom::node::{NodeDamage, SEQUENTIALLY_FOCUSABLE, UnbindContext};
@@ -85,9 +86,9 @@ use net_traits::request::CorsSettings;
use ref_filter_map::ref_filter_map;
use script_layout_interface::message::ReflowQueryType;
use script_thread::Runnable;
-use selectors::matching::{ElementSelectorFlags, StyleRelations, matches_selector_list};
+use selectors::attr::{AttrSelectorOperation, NamespaceConstraint};
+use selectors::matching::{ElementSelectorFlags, MatchingContext, MatchingMode, matches_selector_list};
use selectors::matching::{HAS_EDGE_CHILD_SELECTOR, HAS_SLOW_SELECTOR, HAS_SLOW_SELECTOR_LATER_SIBLINGS};
-use selectors::parser::{AttrSelector, NamespaceConstraint};
use servo_atoms::Atom;
use std::ascii::AsciiExt;
use std::borrow::Cow;
@@ -103,7 +104,7 @@ use style::properties::{Importance, PropertyDeclaration, PropertyDeclarationBloc
use style::properties::longhands::{self, background_image, border_spacing, font_family, font_size, overflow_x};
use style::restyle_hints::RESTYLE_SELF;
use style::rule_tree::CascadeLevel;
-use style::selector_parser::{NonTSPseudoClass, RestyleDamage, SelectorImpl, SelectorParser};
+use style::selector_parser::{NonTSPseudoClass, PseudoElement, RestyleDamage, SelectorImpl, SelectorParser};
use style::shared_lock::{SharedRwLock, Locked};
use style::sink::Push;
use style::stylearc::Arc;
@@ -287,7 +288,7 @@ pub trait RawLayoutElementHelpers {
-> Option<&'a AttrValue>;
unsafe fn get_attr_val_for_layout<'a>(&'a self, namespace: &Namespace, name: &LocalName)
-> Option<&'a str>;
- unsafe fn get_attr_vals_for_layout<'a>(&'a self, name: &LocalName) -> Vec<&'a str>;
+ unsafe fn get_attr_vals_for_layout<'a>(&'a self, name: &LocalName) -> Vec<&'a AttrValue>;
}
#[inline]
@@ -313,6 +314,7 @@ impl RawLayoutElementHelpers for Element {
})
}
+ #[inline]
unsafe fn get_attr_val_for_layout<'a>(&'a self, namespace: &Namespace, name: &LocalName)
-> Option<&'a str> {
get_attr_for_layout(self, namespace, name).map(|attr| {
@@ -321,12 +323,12 @@ impl RawLayoutElementHelpers for Element {
}
#[inline]
- unsafe fn get_attr_vals_for_layout<'a>(&'a self, name: &LocalName) -> Vec<&'a str> {
+ unsafe fn get_attr_vals_for_layout<'a>(&'a self, name: &LocalName) -> Vec<&'a AttrValue> {
let attrs = self.attrs.borrow_for_layout();
attrs.iter().filter_map(|attr| {
let attr = attr.to_layout();
if *name == attr.local_name_atom_forever() {
- Some(attr.value_ref_forever())
+ Some(attr.value_forever())
} else {
None
}
@@ -1003,6 +1005,12 @@ impl Element {
}
pub fn push_attribute(&self, attr: &Attr) {
+ let name = attr.local_name().clone();
+ let namespace = attr.namespace().clone();
+ let old_value = DOMString::from(&**attr.value());
+ let mutation = Mutation::Attribute { name, namespace, old_value };
+ MutationObserver::queue_a_mutation_record(&self.node, mutation);
+
assert!(attr.GetOwnerElement().r() == Some(self));
self.will_mutate_attr(attr);
self.attrs.borrow_mut().push(JS::from_ref(attr));
@@ -1125,13 +1133,18 @@ impl Element {
}
fn remove_first_matching_attribute<F>(&self, find: F) -> Option<Root<Attr>>
- where F: Fn(&Attr) -> bool
- {
+ where F: Fn(&Attr) -> bool {
let idx = self.attrs.borrow().iter().position(|attr| find(&attr));
-
idx.map(|idx| {
let attr = Root::from_ref(&*(*self.attrs.borrow())[idx]);
self.will_mutate_attr(&attr);
+
+ let name = attr.local_name().clone();
+ let namespace = attr.namespace().clone();
+ let old_value = DOMString::from(&**attr.value());
+ let mutation = Mutation::Attribute { name, namespace, old_value, };
+ MutationObserver::queue_a_mutation_record(&self.node, mutation);
+
self.attrs.borrow_mut().remove(idx);
attr.set_owner(None);
if attr.namespace() == &ns!() {
@@ -2046,7 +2059,8 @@ impl ElementMethods for Element {
match SelectorParser::parse_author_origin_no_namespace(&selectors) {
Err(()) => Err(Error::Syntax),
Ok(selectors) => {
- Ok(matches_selector_list(&selectors.0, &Root::from_ref(self), None))
+ let mut ctx = MatchingContext::new(MatchingMode::Normal, None);
+ Ok(matches_selector_list(&selectors.0, &Root::from_ref(self), &mut ctx))
}
}
}
@@ -2064,8 +2078,8 @@ impl ElementMethods for Element {
let root = self.upcast::<Node>();
for element in root.inclusive_ancestors() {
if let Some(element) = Root::downcast::<Element>(element) {
- if matches_selector_list(&selectors.0, &element, None)
- {
+ let mut ctx = MatchingContext::new(MatchingMode::Normal, None);
+ if matches_selector_list(&selectors.0, &element, &mut ctx) {
return Ok(Some(element));
}
}
@@ -2339,41 +2353,22 @@ impl VirtualMethods for Element {
}
}
-impl<'a> ::selectors::MatchAttrGeneric for Root<Element> {
+impl<'a> ::selectors::Element for Root<Element> {
type Impl = SelectorImpl;
- fn match_attr<F>(&self, attr: &AttrSelector<SelectorImpl>, test: F) -> bool
- where F: Fn(&str) -> bool
- {
- use ::selectors::Element;
- let local_name = {
- if self.is_html_element_in_html_document() {
- &attr.lower_name
- } else {
- &attr.name
- }
- };
- match attr.namespace {
- NamespaceConstraint::Specific(ref ns) => {
- self.get_attribute(&ns.url, local_name)
- .map_or(false, |attr| {
- test(&attr.value())
- })
- },
- NamespaceConstraint::Any => {
- self.attrs.borrow().iter().any(|attr| {
- attr.local_name() == local_name && test(&attr.value())
- })
- }
- }
- }
-}
-
-impl<'a> ::selectors::Element for Root<Element> {
fn parent_element(&self) -> Option<Root<Element>> {
self.upcast::<Node>().GetParentElement()
}
+ fn match_pseudo_element(&self,
+ _pseudo: &PseudoElement,
+ _context: &mut MatchingContext)
+ -> bool
+ {
+ false
+ }
+
+
fn first_child_element(&self) -> Option<Root<Element>> {
self.node.child_elements().next()
}
@@ -2390,6 +2385,25 @@ impl<'a> ::selectors::Element for Root<Element> {
self.node.following_siblings().filter_map(Root::downcast).next()
}
+ fn attr_matches(&self,
+ ns: &NamespaceConstraint<&Namespace>,
+ local_name: &LocalName,
+ operation: &AttrSelectorOperation<&String>)
+ -> bool {
+ match *ns {
+ NamespaceConstraint::Specific(ref ns) => {
+ self.get_attribute(ns, local_name)
+ .map_or(false, |attr| attr.value().eval_selector(operation))
+ }
+ NamespaceConstraint::Any => {
+ self.attrs.borrow().iter().any(|attr| {
+ attr.local_name() == local_name &&
+ attr.value().eval_selector(operation)
+ })
+ }
+ }
+ }
+
fn is_root(&self) -> bool {
match self.node.GetParentNode() {
None => false,
@@ -2414,7 +2428,7 @@ impl<'a> ::selectors::Element for Root<Element> {
fn match_non_ts_pseudo_class<F>(&self,
pseudo_class: &NonTSPseudoClass,
- _: &mut StyleRelations,
+ _: &mut MatchingContext,
_: &mut F)
-> bool
where F: FnMut(&Self, ElementSelectorFlags),
@@ -2437,6 +2451,11 @@ impl<'a> ::selectors::Element for Root<Element> {
}
},
+ NonTSPseudoClass::ServoCaseSensitiveTypeAttr(ref expected_value) => {
+ self.get_attribute(&ns!(), &local_name!("type"))
+ .map_or(false, |attr| attr.value().eq(expected_value))
+ }
+
// FIXME(#15746): This is wrong, we need to instead use extended filtering as per RFC4647
// https://tools.ietf.org/html/rfc4647#section-3.3.2
NonTSPseudoClass::Lang(ref lang) => extended_filtering(&*self.get_lang(), &*lang),
@@ -2467,18 +2486,6 @@ impl<'a> ::selectors::Element for Root<Element> {
Element::has_class(&**self, name)
}
- fn each_class<F>(&self, mut callback: F)
- where F: FnMut(&Atom)
- {
- if let Some(ref attr) = self.get_attribute(&ns!(), &local_name!("class")) {
- let tokens = attr.value();
- let tokens = tokens.as_tokens();
- for token in tokens {
- callback(token);
- }
- }
- }
-
fn is_html_element_in_html_document(&self) -> bool {
self.html_element_in_html_document()
}
diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs
index 931d1f576aa..ce81958a2cb 100644
--- a/components/script/dom/globalscope.rs
+++ b/components/script/dom/globalscope.rs
@@ -19,6 +19,7 @@ use dom::event::{Event, EventBubbles, EventCancelable, EventStatus};
use dom::eventtarget::EventTarget;
use dom::window::Window;
use dom::workerglobalscope::WorkerGlobalScope;
+use dom::workletglobalscope::WorkletGlobalScope;
use dom_struct::dom_struct;
use ipc_channel::ipc::IpcSender;
use js::{JSCLASS_IS_DOMJSCLASS, JSCLASS_IS_GLOBAL};
@@ -259,6 +260,10 @@ impl GlobalScope {
// https://html.spec.whatwg.org/multipage/#script-settings-for-workers:api-base-url
return worker.get_url().clone();
}
+ if let Some(worker) = self.downcast::<WorkletGlobalScope>() {
+ // https://drafts.css-houdini.org/worklets/#script-settings-for-worklets
+ return worker.base_url();
+ }
unreachable!();
}
@@ -270,6 +275,10 @@ impl GlobalScope {
if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
return worker.get_url().clone();
}
+ if let Some(worker) = self.downcast::<WorkletGlobalScope>() {
+ // TODO: is this the right URL to return?
+ return worker.base_url();
+ }
unreachable!();
}
@@ -349,14 +358,14 @@ impl GlobalScope {
/// Evaluate JS code on this global scope.
pub fn evaluate_js_on_global_with_result(
- &self, code: &str, rval: MutableHandleValue) {
+ &self, code: &str, rval: MutableHandleValue) -> bool {
self.evaluate_script_on_global_with_result(code, "", rval, 1)
}
/// Evaluate a JS script on this global scope.
#[allow(unsafe_code)]
pub fn evaluate_script_on_global_with_result(
- &self, code: &str, filename: &str, rval: MutableHandleValue, line_number: u32) {
+ &self, code: &str, filename: &str, rval: MutableHandleValue, line_number: u32) -> bool {
let metadata = time::TimerMetadata {
url: if filename.is_empty() {
self.get_url().as_str().into()
@@ -379,16 +388,21 @@ impl GlobalScope {
let _ac = JSAutoCompartment::new(cx, globalhandle.get());
let _aes = AutoEntryScript::new(self);
let options = CompileOptionsWrapper::new(cx, filename.as_ptr(), line_number);
- unsafe {
- if !Evaluate2(cx, options.ptr, code.as_ptr(),
- code.len() as libc::size_t,
- rval) {
- debug!("error evaluating JS string");
- report_pending_exception(cx, true);
- }
+
+ debug!("evaluating JS string");
+ let result = unsafe {
+ Evaluate2(cx, options.ptr, code.as_ptr(),
+ code.len() as libc::size_t,
+ rval)
+ };
+
+ if !result {
+ debug!("error evaluating JS string");
+ unsafe { report_pending_exception(cx, true) };
}
maybe_resume_unwind();
+ result
}
)
}
@@ -468,6 +482,9 @@ impl GlobalScope {
if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
return worker.perform_a_microtask_checkpoint();
}
+ if let Some(worker) = self.downcast::<WorkletGlobalScope>() {
+ return worker.perform_a_microtask_checkpoint();
+ }
unreachable!();
}
@@ -479,6 +496,9 @@ impl GlobalScope {
if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
return worker.enqueue_microtask(job);
}
+ if let Some(worker) = self.downcast::<WorkletGlobalScope>() {
+ return worker.enqueue_microtask(job);
+ }
unreachable!();
}
diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs
index 1e6615ce36a..8334b4cb421 100644
--- a/components/script/dom/htmliframeelement.rs
+++ b/components/script/dom/htmliframeelement.rs
@@ -40,7 +40,7 @@ use html5ever::{LocalName, Prefix};
use ipc_channel::ipc;
use js::jsapi::{JSAutoCompartment, JSContext, MutableHandleValue};
use js::jsval::{NullValue, UndefinedValue};
-use msg::constellation_msg::{FrameType, FrameId, PipelineId, TraversalDirection};
+use msg::constellation_msg::{FrameType, BrowsingContextId, PipelineId, TraversalDirection};
use net_traits::response::HttpsState;
use script_layout_interface::message::ReflowQueryType;
use script_thread::{ScriptThread, Runnable};
@@ -84,7 +84,7 @@ enum ProcessingMode {
#[dom_struct]
pub struct HTMLIFrameElement {
htmlelement: HTMLElement,
- frame_id: FrameId,
+ browsing_context_id: BrowsingContextId,
pipeline_id: Cell<Option<PipelineId>>,
pending_pipeline_id: Cell<Option<PipelineId>>,
sandbox: MutNullableJS<DOMTokenList>,
@@ -115,7 +115,7 @@ impl HTMLIFrameElement {
pub fn generate_new_pipeline_id(&self) -> (Option<PipelineId>, PipelineId) {
let old_pipeline_id = self.pipeline_id.get();
let new_pipeline_id = PipelineId::new();
- debug!("Frame {} created pipeline {}.", self.frame_id, new_pipeline_id);
+ debug!("Frame {} created pipeline {}.", self.browsing_context_id, new_pipeline_id);
(old_pipeline_id, new_pipeline_id)
}
@@ -152,7 +152,7 @@ impl HTMLIFrameElement {
let global_scope = window.upcast::<GlobalScope>();
let load_info = IFrameLoadInfo {
parent_pipeline_id: global_scope.pipeline_id(),
- frame_id: self.frame_id,
+ browsing_context_id: self.browsing_context_id,
new_pipeline_id: new_pipeline_id,
is_private: private_iframe,
frame_type: frame_type,
@@ -171,7 +171,7 @@ impl HTMLIFrameElement {
let new_layout_info = NewLayoutInfo {
parent_info: Some((global_scope.pipeline_id(), frame_type)),
new_pipeline_id: new_pipeline_id,
- frame_id: self.frame_id,
+ browsing_context_id: self.browsing_context_id,
load_data: load_data.unwrap(),
pipeline_port: pipeline_receiver,
content_process_shutdown_chan: None,
@@ -277,7 +277,7 @@ impl HTMLIFrameElement {
document: &Document) -> HTMLIFrameElement {
HTMLIFrameElement {
htmlelement: HTMLElement::new_inherited(local_name, prefix, document),
- frame_id: FrameId::new(),
+ browsing_context_id: BrowsingContextId::new(),
pipeline_id: Cell::new(None),
pending_pipeline_id: Cell::new(None),
sandbox: Default::default(),
@@ -302,8 +302,8 @@ impl HTMLIFrameElement {
}
#[inline]
- pub fn frame_id(&self) -> FrameId {
- self.frame_id
+ pub fn browsing_context_id(&self) -> BrowsingContextId {
+ self.browsing_context_id
}
pub fn change_visibility_status(&self, visibility: bool) {
@@ -364,7 +364,7 @@ impl HTMLIFrameElement {
pub trait HTMLIFrameElementLayoutMethods {
fn pipeline_id(&self) -> Option<PipelineId>;
- fn frame_id(&self) -> FrameId;
+ fn browsing_context_id(&self) -> BrowsingContextId;
fn get_width(&self) -> LengthOrPercentageOrAuto;
fn get_height(&self) -> LengthOrPercentageOrAuto;
}
@@ -380,9 +380,9 @@ impl HTMLIFrameElementLayoutMethods for LayoutJS<HTMLIFrameElement> {
#[inline]
#[allow(unsafe_code)]
- fn frame_id(&self) -> FrameId {
+ fn browsing_context_id(&self) -> BrowsingContextId {
unsafe {
- (*self.unsafe_get()).frame_id
+ (*self.unsafe_get()).browsing_context_id
}
}
@@ -541,7 +541,7 @@ impl HTMLIFrameElementMethods for HTMLIFrameElement {
// https://html.spec.whatwg.org/multipage/#dom-iframe-contentwindow
fn GetContentWindow(&self) -> Option<Root<WindowProxy>> {
- self.pipeline_id.get().and_then(|_| ScriptThread::find_window_proxy(self.frame_id))
+ self.pipeline_id.get().and_then(|_| ScriptThread::find_window_proxy(self.browsing_context_id))
}
// https://html.spec.whatwg.org/multipage/#dom-iframe-contentdocument
@@ -711,7 +711,7 @@ impl VirtualMethods for HTMLIFrameElement {
// is in a document tree and has a browsing context, which is what causes
// the child browsing context to be created.
if self.upcast::<Node>().is_in_doc_with_browsing_context() {
- debug!("iframe {} src set while in browsing context.", self.frame_id);
+ debug!("iframe {} src set while in browsing context.", self.browsing_context_id);
self.process_the_iframe_attributes(ProcessingMode::NotFirstTime);
}
},
@@ -740,7 +740,7 @@ impl VirtualMethods for HTMLIFrameElement {
// to the newly-created browsing context, and then process the
// iframe attributes for the "first time"."
if self.upcast::<Node>().is_in_doc_with_browsing_context() {
- debug!("iframe {} bound to browsing context.", self.frame_id);
+ debug!("iframe {} bound to browsing context.", self.browsing_context_id);
debug_assert!(tree_in_doc, "is_in_doc_with_bc, but not tree_in_doc");
self.create_nested_browsing_context();
self.process_the_iframe_attributes(ProcessingMode::FirstTime);
@@ -754,13 +754,13 @@ impl VirtualMethods for HTMLIFrameElement {
LoadBlocker::terminate(&mut blocker);
// https://html.spec.whatwg.org/multipage/#a-browsing-context-is-discarded
- debug!("Unbinding frame {}.", self.frame_id);
+ debug!("Unbinding frame {}.", self.browsing_context_id);
let window = window_from_node(self);
let (sender, receiver) = ipc::channel().unwrap();
// Ask the constellation to remove the iframe, and tell us the
// pipeline ids of the closed pipelines.
- let msg = ConstellationMsg::RemoveIFrame(self.frame_id, sender);
+ let msg = ConstellationMsg::RemoveIFrame(self.browsing_context_id, sender);
window.upcast::<GlobalScope>().constellation_chan().send(msg).unwrap();
let exited_pipeline_ids = receiver.recv().unwrap();
diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs
index d155b8b6a47..62bffbdcbcd 100644
--- a/components/script/dom/mod.rs
+++ b/components/script/dom/mod.rs
@@ -423,6 +423,8 @@ pub mod testbindingiterable;
pub mod testbindingpairiterable;
pub mod testbindingproxy;
pub mod testrunner;
+pub mod testworklet;
+pub mod testworkletglobalscope;
pub mod text;
pub mod textdecoder;
pub mod textencoder;
@@ -469,6 +471,8 @@ pub mod worker;
pub mod workerglobalscope;
pub mod workerlocation;
pub mod workernavigator;
+pub mod worklet;
+pub mod workletglobalscope;
pub mod xmldocument;
pub mod xmlhttprequest;
pub mod xmlhttprequesteventtarget;
diff --git a/components/script/dom/mutationobserver.rs b/components/script/dom/mutationobserver.rs
index 4dc745c1ce8..48c8fe24b87 100644
--- a/components/script/dom/mutationobserver.rs
+++ b/components/script/dom/mutationobserver.rs
@@ -2,13 +2,22 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+use dom::bindings::callback::ExceptionHandling;
+use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::MutationObserverBinding;
use dom::bindings::codegen::Bindings::MutationObserverBinding::MutationCallback;
-use dom::bindings::error::Fallible;
+use dom::bindings::codegen::Bindings::MutationObserverBinding::MutationObserverBinding::MutationObserverMethods;
+use dom::bindings::codegen::Bindings::MutationObserverBinding::MutationObserverInit;
+use dom::bindings::error::{Error, Fallible};
use dom::bindings::js::Root;
use dom::bindings::reflector::{Reflector, reflect_dom_object};
+use dom::bindings::str::DOMString;
+use dom::mutationrecord::MutationRecord;
+use dom::node::Node;
use dom::window::Window;
use dom_struct::dom_struct;
+use html5ever::{Namespace, LocalName};
+use microtask::Microtask;
use script_thread::ScriptThread;
use std::rc::Rc;
@@ -17,6 +26,29 @@ pub struct MutationObserver {
reflector_: Reflector,
#[ignore_heap_size_of = "can't measure Rc values"]
callback: Rc<MutationCallback>,
+ record_queue: DOMRefCell<Vec<Root<MutationRecord>>>,
+}
+
+#[derive(Clone)]
+pub enum Mutation {
+ Attribute { name: LocalName, namespace: Namespace, old_value: DOMString }
+}
+
+#[derive(HeapSizeOf, JSTraceable)]
+pub struct RegisteredObserver {
+ observer: Root<MutationObserver>,
+ options: ObserverOptions,
+}
+
+#[derive(HeapSizeOf, JSTraceable)]
+pub struct ObserverOptions {
+ attribute_old_value: bool,
+ attributes: bool,
+ character_data: bool,
+ character_data_old_value: bool,
+ child_list: bool,
+ subtree: bool,
+ attribute_filter: Vec<DOMString>,
}
impl MutationObserver {
@@ -29,6 +61,7 @@ impl MutationObserver {
MutationObserver {
reflector_: Reflector::new(),
callback: callback,
+ record_queue: DOMRefCell::new(vec![]),
}
}
@@ -37,4 +70,185 @@ impl MutationObserver {
ScriptThread::add_mutation_observer(&*observer);
Ok(observer)
}
+
+ /// https://dom.spec.whatwg.org/#queue-a-mutation-observer-compound-microtask
+ pub fn queue_mutation_observer_compound_microtask() {
+ // Step 1
+ if ScriptThread::is_mutation_observer_compound_microtask_queued() {
+ return;
+ }
+ // Step 2
+ ScriptThread::set_mutation_observer_compound_microtask_queued(true);
+ // Step 3
+ ScriptThread::enqueue_microtask(Microtask::NotifyMutationObservers);
+ }
+
+ /// https://dom.spec.whatwg.org/#notify-mutation-observers
+ pub fn notify_mutation_observers() {
+ // Step 1
+ ScriptThread::set_mutation_observer_compound_microtask_queued(false);
+ // Step 2
+ let notify_list = ScriptThread::get_mutation_observers();
+ // TODO: steps 3-4 (slots)
+ // Step 5
+ for mo in &notify_list {
+ let queue: Vec<Root<MutationRecord>> = mo.record_queue.borrow().clone();
+ mo.record_queue.borrow_mut().clear();
+ // TODO: Step 5.3 Remove all transient registered observers whose observer is mo.
+ if !queue.is_empty() {
+ let _ = mo.callback.Call_(&**mo, queue, &**mo, ExceptionHandling::Report);
+ }
+ }
+ // TODO: Step 6 (slot signals)
+ }
+
+ /// https://dom.spec.whatwg.org/#queueing-a-mutation-record
+ pub fn queue_a_mutation_record(target: &Node, attr_type: Mutation) {
+ // Step 1
+ let mut interestedObservers: Vec<(Root<MutationObserver>, Option<DOMString>)> = vec![];
+ // Step 2 & 3
+ for node in target.inclusive_ancestors() {
+ for registered in &*node.registered_mutation_observers() {
+ if &*node != target && !registered.options.subtree {
+ continue;
+ }
+
+ match attr_type {
+ Mutation::Attribute { ref name, ref namespace, ref old_value } => {
+ // Step 3.1
+ if !registered.options.attributes {
+ continue;
+ }
+ if !registered.options.attribute_filter.is_empty() {
+ if *namespace != ns!() {
+ continue;
+ }
+ if registered.options.attribute_filter.iter()
+ .find(|s| &**s == &**name).is_some() {
+ continue;
+ }
+ }
+ // Step 3.1.2
+ let paired_string = if registered.options.attribute_old_value {
+ Some(old_value.clone())
+ } else {
+ None
+ };
+ // Step 3.1.1
+ let idx = interestedObservers.iter().position(|&(ref o, _)|
+ &**o as *const _ == &*registered.observer as *const _);
+ if let Some(idx) = idx {
+ interestedObservers[idx].1 = paired_string;
+ } else {
+ interestedObservers.push((Root::from_ref(&*registered.observer),
+ paired_string));
+ }
+ }
+ }
+ }
+ }
+
+ // Step 4
+ for &(ref observer, ref paired_string) in &interestedObservers {
+ // Steps 4.1-4.7
+ let record = match attr_type {
+ Mutation::Attribute { ref name, ref namespace, .. } => {
+ let namespace = if *namespace != ns!() {
+ Some(namespace)
+ } else {
+ None
+ };
+ MutationRecord::attribute_mutated(target, name, namespace, paired_string.clone())
+ }
+ };
+ // Step 4.8
+ observer.record_queue.borrow_mut().push(record);
+ }
+
+ // Step 5
+ MutationObserver::queue_mutation_observer_compound_microtask();
+ }
+
+}
+
+impl MutationObserverMethods for MutationObserver {
+ /// https://dom.spec.whatwg.org/#dom-mutationobserver-observe
+ fn Observe(&self, target: &Node, options: &MutationObserverInit) -> Fallible<()> {
+ let attribute_filter = options.attributeFilter.clone().unwrap_or(vec![]);
+ let attribute_old_value = options.attributeOldValue.unwrap_or(false);
+ let mut attributes = options.attributes.unwrap_or(false);
+ let mut character_data = options.characterData.unwrap_or(false);
+ let character_data_old_value = options.characterDataOldValue.unwrap_or(false);
+ let child_list = options.childList;
+ let subtree = options.subtree;
+
+ // Step 1
+ if (options.attributeOldValue.is_some() || options.attributeFilter.is_some()) &&
+ options.attributes.is_none() {
+ attributes = true;
+ }
+
+ // Step 2
+ if options.characterDataOldValue.is_some() && options.characterData.is_none() {
+ character_data = true;
+ }
+
+ // Step 3
+ if !child_list && !attributes && !character_data {
+ return Err(Error::Type("One of childList, attributes, or characterData must be true".into()));
+ }
+
+ // Step 4
+ if attribute_old_value && !attributes {
+ return Err(Error::Type("attributeOldValue is true but attributes is false".into()));
+ }
+
+ // Step 5
+ if options.attributeFilter.is_some() && !attributes {
+ return Err(Error::Type("attributeFilter is present but attributes is false".into()));
+ }
+
+ // Step 6
+ if character_data_old_value && !character_data {
+ return Err(Error::Type("characterDataOldValue is true but characterData is false".into()));
+ }
+
+ // Step 7
+ let add_new_observer = {
+ let mut replaced = false;
+ for registered in &mut *target.registered_mutation_observers() {
+ if &*registered.observer as *const MutationObserver != self as *const MutationObserver {
+ continue;
+ }
+ // TODO: remove matching transient registered observers
+ registered.options.attribute_old_value = attribute_old_value;
+ registered.options.attributes = attributes;
+ registered.options.character_data = character_data;
+ registered.options.character_data_old_value = character_data_old_value;
+ registered.options.child_list = child_list;
+ registered.options.subtree = subtree;
+ registered.options.attribute_filter = attribute_filter.clone();
+ replaced = true;
+ }
+ !replaced
+ };
+
+ // Step 8
+ if add_new_observer {
+ target.registered_mutation_observers().push(RegisteredObserver {
+ observer: Root::from_ref(self),
+ options: ObserverOptions {
+ attributes,
+ attribute_old_value,
+ character_data,
+ character_data_old_value,
+ subtree,
+ attribute_filter,
+ child_list
+ },
+ });
+ }
+
+ Ok(())
+ }
}
diff --git a/components/script/dom/mutationrecord.rs b/components/script/dom/mutationrecord.rs
index c39d61ef18a..439f4ae02b5 100644
--- a/components/script/dom/mutationrecord.rs
+++ b/components/script/dom/mutationrecord.rs
@@ -2,22 +2,54 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+use dom::bindings::codegen::Bindings::MutationRecordBinding::MutationRecordBinding;
use dom::bindings::codegen::Bindings::MutationRecordBinding::MutationRecordBinding::MutationRecordMethods;
use dom::bindings::js::{JS, Root};
-use dom::bindings::reflector::Reflector;
+use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::bindings::str::DOMString;
-use dom::node::Node;
+use dom::node::{Node, window_from_node};
+use dom::nodelist::NodeList;
use dom_struct::dom_struct;
+use html5ever::{LocalName, Namespace};
#[dom_struct]
pub struct MutationRecord {
reflector_: Reflector,
-
- //property for record type
record_type: DOMString,
-
- //property for target node
target: JS<Node>,
+ attribute_name: Option<DOMString>,
+ attribute_namespace: Option<DOMString>,
+ old_value: Option<DOMString>,
+}
+
+impl MutationRecord {
+ #[allow(unrooted_must_root)]
+ pub fn attribute_mutated(target: &Node,
+ attribute_name: &LocalName,
+ attribute_namespace: Option<&Namespace>,
+ old_value: Option<DOMString>) -> Root<MutationRecord> {
+ let record = box MutationRecord::new_inherited("attributes",
+ target,
+ Some(DOMString::from(&**attribute_name)),
+ attribute_namespace.map(|n| DOMString::from(&**n)),
+ old_value);
+ reflect_dom_object(record, &*window_from_node(target), MutationRecordBinding::Wrap)
+ }
+
+ fn new_inherited(record_type: &str,
+ target: &Node,
+ attribute_name: Option<DOMString>,
+ attribute_namespace: Option<DOMString>,
+ old_value: Option<DOMString>) -> MutationRecord {
+ MutationRecord {
+ reflector_: Reflector::new(),
+ record_type: DOMString::from(record_type),
+ target: JS::from_ref(target),
+ attribute_name: attribute_name,
+ attribute_namespace: attribute_namespace,
+ old_value: old_value,
+ }
+ }
}
impl MutationRecordMethods for MutationRecord {
@@ -28,7 +60,44 @@ impl MutationRecordMethods for MutationRecord {
// https://dom.spec.whatwg.org/#dom-mutationrecord-target
fn Target(&self) -> Root<Node> {
- return Root::from_ref(&*self.target);
+ Root::from_ref(&*self.target)
+ }
+
+ // https://dom.spec.whatwg.org/#dom-mutationrecord-attributename
+ fn GetAttributeName(&self) -> Option<DOMString> {
+ self.attribute_name.clone()
+ }
+
+ // https://dom.spec.whatwg.org/#dom-mutationrecord-attributenamespace
+ fn GetAttributeNamespace(&self) -> Option<DOMString> {
+ self.attribute_namespace.clone()
+ }
+
+ // https://dom.spec.whatwg.org/#dom-mutationrecord-oldvalue
+ fn GetOldValue(&self) -> Option<DOMString> {
+ self.old_value.clone()
+ }
+
+ // https://dom.spec.whatwg.org/#dom-mutationrecord-addednodes
+ fn AddedNodes(&self) -> Root<NodeList> {
+ let window = window_from_node(&*self.target);
+ NodeList::empty(&window)
+ }
+
+ // https://dom.spec.whatwg.org/#dom-mutationrecord-removednodes
+ fn RemovedNodes(&self) -> Root<NodeList> {
+ let window = window_from_node(&*self.target);
+ NodeList::empty(&window)
+ }
+
+ // https://dom.spec.whatwg.org/#dom-mutationrecord-previoussibling
+ fn GetPreviousSibling(&self) -> Option<Root<Node>> {
+ None
+ }
+
+ // https://dom.spec.whatwg.org/#dom-mutationrecord-previoussibling
+ fn GetNextSibling(&self) -> Option<Root<Node>> {
+ None
}
}
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs
index 6d16cac6731..1ad28974f3d 100644
--- a/components/script/dom/node.rs
+++ b/components/script/dom/node.rs
@@ -7,6 +7,7 @@
use app_units::Au;
use devtools_traits::NodeInfo;
use document_loader::DocumentLoader;
+use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods;
use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
@@ -46,6 +47,7 @@ use dom::htmllinkelement::HTMLLinkElement;
use dom::htmlmetaelement::HTMLMetaElement;
use dom::htmlstyleelement::HTMLStyleElement;
use dom::htmltextareaelement::{HTMLTextAreaElement, LayoutHTMLTextAreaElementHelpers};
+use dom::mutationobserver::RegisteredObserver;
use dom::nodelist::NodeList;
use dom::processinginstruction::ProcessingInstruction;
use dom::range::WeakRangeVec;
@@ -61,18 +63,18 @@ use heapsize::{HeapSizeOf, heap_size_of};
use html5ever::{Prefix, Namespace, QualName};
use js::jsapi::{JSContext, JSObject, JSRuntime};
use libc::{self, c_void, uintptr_t};
-use msg::constellation_msg::{FrameId, PipelineId};
+use msg::constellation_msg::{BrowsingContextId, PipelineId};
use ref_slice::ref_slice;
use script_layout_interface::{HTMLCanvasData, OpaqueStyleAndLayoutData, SVGSVGData};
use script_layout_interface::{LayoutElementType, LayoutNodeType, TrustedNodeAddress};
use script_layout_interface::message::Msg;
use script_traits::DocumentActivity;
use script_traits::UntrustedNodeAddress;
-use selectors::matching::matches_selector_list;
+use selectors::matching::{matches_selector_list, MatchingContext, MatchingMode};
use selectors::parser::SelectorList;
use servo_url::ServoUrl;
use std::borrow::ToOwned;
-use std::cell::{Cell, UnsafeCell};
+use std::cell::{Cell, UnsafeCell, RefMut};
use std::cmp::max;
use std::default::Default;
use std::iter;
@@ -138,6 +140,9 @@ pub struct Node {
/// node is finalized.
style_and_layout_data: Cell<Option<OpaqueStyleAndLayoutData>>,
+ /// Registered observers for this node.
+ mutation_observers: DOMRefCell<Vec<RegisteredObserver>>,
+
unique_id: UniqueId,
}
@@ -341,11 +346,14 @@ impl<'a> Iterator for QuerySelectorIterator {
fn next(&mut self) -> Option<Root<Node>> {
let selectors = &self.selectors.0;
+
// TODO(cgaebel): Is it worth it to build a bloom filter here
// (instead of passing `None`)? Probably.
+ let mut ctx = MatchingContext::new(MatchingMode::Normal, None);
+
self.iterator.by_ref().filter_map(|node| {
if let Some(element) = Root::downcast(node) {
- if matches_selector_list(selectors, &element, None) {
+ if matches_selector_list(selectors, &element, &mut ctx) {
return Some(Root::upcast(element));
}
}
@@ -363,6 +371,11 @@ impl Node {
}
}
+ /// Return all registered mutation observers for this node.
+ pub fn registered_mutation_observers(&self) -> RefMut<Vec<RegisteredObserver>> {
+ self.mutation_observers.borrow_mut()
+ }
+
/// Dumps the subtree rooted at this node, for debugging.
pub fn dump(&self) {
self.dump_indent(0);
@@ -707,8 +720,9 @@ impl Node {
Err(()) => Err(Error::Syntax),
// Step 3.
Ok(selectors) => {
+ let mut ctx = MatchingContext::new(MatchingMode::Normal, None);
Ok(self.traverse_preorder().filter_map(Root::downcast).find(|element| {
- matches_selector_list(&selectors.0, element, None)
+ matches_selector_list(&selectors.0, element, &mut ctx)
}))
}
}
@@ -968,7 +982,7 @@ pub trait LayoutNodeHelpers {
fn image_url(&self) -> Option<ServoUrl>;
fn canvas_data(&self) -> Option<HTMLCanvasData>;
fn svg_data(&self) -> Option<SVGSVGData>;
- fn iframe_frame_id(&self) -> FrameId;
+ fn iframe_browsing_context_id(&self) -> BrowsingContextId;
fn iframe_pipeline_id(&self) -> PipelineId;
fn opaque(&self) -> OpaqueNode;
}
@@ -1119,10 +1133,10 @@ impl LayoutNodeHelpers for LayoutJS<Node> {
.map(|svg| svg.data())
}
- fn iframe_frame_id(&self) -> FrameId {
+ fn iframe_browsing_context_id(&self) -> BrowsingContextId {
let iframe_element = self.downcast::<HTMLIFrameElement>()
.expect("not an iframe element!");
- iframe_element.frame_id()
+ iframe_element.browsing_context_id()
}
fn iframe_pipeline_id(&self) -> PipelineId {
@@ -1411,6 +1425,8 @@ impl Node {
style_and_layout_data: Cell::new(None),
+ mutation_observers: Default::default(),
+
unique_id: UniqueId::new(),
}
}
diff --git a/components/script/dom/promise.rs b/components/script/dom/promise.rs
index 13689023462..5595e999c9d 100644
--- a/components/script/dom/promise.rs
+++ b/components/script/dom/promise.rs
@@ -296,3 +296,4 @@ fn create_native_handler_function(cx: *mut JSContext,
obj.get()
}
}
+
diff --git a/components/script/dom/testworklet.rs b/components/script/dom/testworklet.rs
new file mode 100644
index 00000000000..ea032e66faa
--- /dev/null
+++ b/components/script/dom/testworklet.rs
@@ -0,0 +1,61 @@
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+// check-tidy: no specs after this line
+
+use dom::bindings::codegen::Bindings::TestWorkletBinding::TestWorkletMethods;
+use dom::bindings::codegen::Bindings::TestWorkletBinding::Wrap;
+use dom::bindings::codegen::Bindings::WorkletBinding::WorkletBinding::WorkletMethods;
+use dom::bindings::codegen::Bindings::WorkletBinding::WorkletOptions;
+use dom::bindings::error::Fallible;
+use dom::bindings::js::JS;
+use dom::bindings::js::Root;
+use dom::bindings::reflector::Reflector;
+use dom::bindings::reflector::reflect_dom_object;
+use dom::bindings::str::DOMString;
+use dom::bindings::str::USVString;
+use dom::promise::Promise;
+use dom::window::Window;
+use dom::worklet::Worklet;
+use dom::workletglobalscope::WorkletGlobalScopeType;
+use dom_struct::dom_struct;
+use script_thread::ScriptThread;
+use std::rc::Rc;
+
+#[dom_struct]
+pub struct TestWorklet {
+ reflector: Reflector,
+ worklet: JS<Worklet>,
+}
+
+impl TestWorklet {
+ fn new_inherited(worklet: &Worklet) -> TestWorklet {
+ TestWorklet {
+ reflector: Reflector::new(),
+ worklet: JS::from_ref(worklet),
+ }
+ }
+
+ fn new(window: &Window) -> Root<TestWorklet> {
+ let worklet = Worklet::new(window, WorkletGlobalScopeType::Test);
+ reflect_dom_object(box TestWorklet::new_inherited(&*worklet), window, Wrap)
+ }
+
+ pub fn Constructor(window: &Window) -> Fallible<Root<TestWorklet>> {
+ Ok(TestWorklet::new(window))
+ }
+}
+
+impl TestWorkletMethods for TestWorklet {
+ #[allow(unrooted_must_root)]
+ fn AddModule(&self, moduleURL: USVString, options: &WorkletOptions) -> Rc<Promise> {
+ self.worklet.AddModule(moduleURL, options)
+ }
+
+ fn Lookup(&self, key: DOMString) -> Option<DOMString> {
+ let id = self.worklet.worklet_id();
+ let pool = ScriptThread::worklet_thread_pool();
+ pool.test_worklet_lookup(id, String::from(key)).map(DOMString::from)
+ }
+}
diff --git a/components/script/dom/testworkletglobalscope.rs b/components/script/dom/testworkletglobalscope.rs
new file mode 100644
index 00000000000..dfd000ac5c1
--- /dev/null
+++ b/components/script/dom/testworkletglobalscope.rs
@@ -0,0 +1,66 @@
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+use dom::bindings::cell::DOMRefCell;
+use dom::bindings::codegen::Bindings::TestWorkletGlobalScopeBinding;
+use dom::bindings::codegen::Bindings::TestWorkletGlobalScopeBinding::TestWorkletGlobalScopeMethods;
+use dom::bindings::js::Root;
+use dom::bindings::str::DOMString;
+use dom::workletglobalscope::WorkletGlobalScope;
+use dom::workletglobalscope::WorkletGlobalScopeInit;
+use dom_struct::dom_struct;
+use js::rust::Runtime;
+use msg::constellation_msg::PipelineId;
+use servo_url::ServoUrl;
+use std::collections::HashMap;
+use std::sync::mpsc::Sender;
+
+// check-tidy: no specs after this line
+
+#[dom_struct]
+pub struct TestWorkletGlobalScope {
+ // The worklet global for this object
+ worklet_global: WorkletGlobalScope,
+ // The key/value pairs
+ lookup_table: DOMRefCell<HashMap<String, String>>,
+}
+
+impl TestWorkletGlobalScope {
+ #[allow(unsafe_code)]
+ pub fn new(runtime: &Runtime,
+ pipeline_id: PipelineId,
+ base_url: ServoUrl,
+ init: &WorkletGlobalScopeInit)
+ -> Root<TestWorkletGlobalScope>
+ {
+ debug!("Creating test worklet global scope for pipeline {}.", pipeline_id);
+ let global = box TestWorkletGlobalScope {
+ worklet_global: WorkletGlobalScope::new_inherited(pipeline_id, base_url, init),
+ lookup_table: Default::default(),
+ };
+ unsafe { TestWorkletGlobalScopeBinding::Wrap(runtime.cx(), global) }
+ }
+
+ pub fn perform_a_worklet_task(&self, task: TestWorkletTask) {
+ match task {
+ TestWorkletTask::Lookup(key, sender) => {
+ debug!("Looking up key {}.", key);
+ let result = self.lookup_table.borrow().get(&key).cloned();
+ let _ = sender.send(result);
+ }
+ }
+ }
+}
+
+impl TestWorkletGlobalScopeMethods for TestWorkletGlobalScope {
+ fn RegisterKeyValue(&self, key: DOMString, value: DOMString) {
+ debug!("Registering test worklet key/value {}/{}.", key, value);
+ self.lookup_table.borrow_mut().insert(String::from(key), String::from(value));
+ }
+}
+
+/// Tasks which can be performed by test worklets.
+pub enum TestWorkletTask {
+ Lookup(String, Sender<Option<String>>),
+}
diff --git a/components/script/dom/webidls/Console.webidl b/components/script/dom/webidls/Console.webidl
index 90f9bb9f58e..7c4c6906a27 100644
--- a/components/script/dom/webidls/Console.webidl
+++ b/components/script/dom/webidls/Console.webidl
@@ -10,7 +10,7 @@
*/
[ClassString="Console",
- Exposed=(Window,Worker),
+ Exposed=(Window,Worker,Worklet),
ProtoObjectHack]
namespace console {
// These should be DOMString message, DOMString message2, ...
diff --git a/components/script/dom/webidls/EventTarget.webidl b/components/script/dom/webidls/EventTarget.webidl
index ee6e5d722a8..ad25712122a 100644
--- a/components/script/dom/webidls/EventTarget.webidl
+++ b/components/script/dom/webidls/EventTarget.webidl
@@ -5,7 +5,7 @@
* https://dom.spec.whatwg.org/#interface-eventtarget
*/
-[Abstract, Exposed=(Window,Worker)]
+[Abstract, Exposed=(Window,Worker,Worklet)]
interface EventTarget {
void addEventListener(DOMString type,
EventListener? listener,
diff --git a/components/script/dom/webidls/GlobalScope.webidl b/components/script/dom/webidls/GlobalScope.webidl
index 7dab4f3afa7..2681d236dbc 100644
--- a/components/script/dom/webidls/GlobalScope.webidl
+++ b/components/script/dom/webidls/GlobalScope.webidl
@@ -5,6 +5,6 @@
// This interface is entirely internal to Servo, and should not be accessible to
// web pages.
-[Exposed=(Window,Worker),
+[Exposed=(Window,Worker,Worklet),
Inline]
interface GlobalScope : EventTarget {};
diff --git a/components/script/dom/webidls/MutationObserver.webidl b/components/script/dom/webidls/MutationObserver.webidl
index dbcfa945d4a..738c711d8e7 100644
--- a/components/script/dom/webidls/MutationObserver.webidl
+++ b/components/script/dom/webidls/MutationObserver.webidl
@@ -9,7 +9,8 @@
// https://dom.spec.whatwg.org/#mutationobserver
[Pref="dom.mutation_observer.enabled", Constructor(MutationCallback callback)]
interface MutationObserver {
- //void observe(Node target, optional MutationObserverInit options);
+ [Throws]
+ void observe(Node target, optional MutationObserverInit options);
//void disconnect();
//sequence<MutationRecord> takeRecords();
};
diff --git a/components/script/dom/webidls/MutationRecord.webidl b/components/script/dom/webidls/MutationRecord.webidl
index 286801bf2ab..1cd364091fc 100644
--- a/components/script/dom/webidls/MutationRecord.webidl
+++ b/components/script/dom/webidls/MutationRecord.webidl
@@ -12,13 +12,13 @@ interface MutationRecord {
readonly attribute DOMString type;
[SameObject]
readonly attribute Node target;
- //[SameObject]
- //readonly attribute NodeList addedNodes;
- //[SameObject]
- //readonly attribute NodeList removedNodes;
- //readonly attribute Node? previousSibling;
- //readonly attribute Node? nextSibling;
- //readonly attribute DOMString? attributeName;
- //readonly attribute DOMString? attributeNamespace;
- //readonly attribute DOMString? oldValue;
+ [SameObject]
+ readonly attribute NodeList addedNodes;
+ [SameObject]
+ readonly attribute NodeList removedNodes;
+ readonly attribute Node? previousSibling;
+ readonly attribute Node? nextSibling;
+ readonly attribute DOMString? attributeName;
+ readonly attribute DOMString? attributeNamespace;
+ readonly attribute DOMString? oldValue;
};
diff --git a/components/script/dom/webidls/TestWorklet.webidl b/components/script/dom/webidls/TestWorklet.webidl
new file mode 100644
index 00000000000..c1f1965a1e0
--- /dev/null
+++ b/components/script/dom/webidls/TestWorklet.webidl
@@ -0,0 +1,12 @@
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+// This interface is entirely internal to Servo, and should not be accessible to
+// web pages.
+
+[Pref="dom.worklet.testing.enabled", Exposed=(Window), Constructor]
+interface TestWorklet {
+ [NewObject] Promise<void> addModule(USVString moduleURL, optional WorkletOptions options);
+ DOMString? lookup(DOMString key);
+};
diff --git a/components/script/dom/webidls/TestWorkletGlobalScope.webidl b/components/script/dom/webidls/TestWorkletGlobalScope.webidl
new file mode 100644
index 00000000000..44027ab8dc6
--- /dev/null
+++ b/components/script/dom/webidls/TestWorkletGlobalScope.webidl
@@ -0,0 +1,11 @@
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+// This interface is entirely internal to Servo, and should not be accessible to
+// web pages.
+
+[Global=(Worklet,TestWorklet), Exposed=TestWorklet]
+interface TestWorkletGlobalScope : WorkletGlobalScope {
+ void registerKeyValue(DOMString key, DOMString value);
+};
diff --git a/components/script/dom/webidls/VoidFunction.webidl b/components/script/dom/webidls/VoidFunction.webidl
new file mode 100644
index 00000000000..82d4a666c51
--- /dev/null
+++ b/components/script/dom/webidls/VoidFunction.webidl
@@ -0,0 +1,13 @@
+/* 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 http://mozilla.org/MPL/2.0/. */
+/*
+ * The origin of this IDL file is
+ * https://heycam.github.io/webidl/#VoidFunction
+ *
+ * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
+ * Opera Software ASA. You are granted a license to use, reproduce
+ * and create derivative works of this document.
+ */
+
+callback VoidFunction = void ();
diff --git a/components/script/dom/webidls/Window.webidl b/components/script/dom/webidls/Window.webidl
index 47c753f43b1..548821ac971 100644
--- a/components/script/dom/webidls/Window.webidl
+++ b/components/script/dom/webidls/Window.webidl
@@ -201,3 +201,4 @@ partial interface Window {
readonly attribute TestRunner testRunner;
//readonly attribute EventSender eventSender;
};
+
diff --git a/components/script/dom/webidls/Worklet.webidl b/components/script/dom/webidls/Worklet.webidl
new file mode 100644
index 00000000000..5bb39bebd96
--- /dev/null
+++ b/components/script/dom/webidls/Worklet.webidl
@@ -0,0 +1,13 @@
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+// https://drafts.css-houdini.org/worklets/#worklet
+[Exposed=(Window)]
+interface Worklet {
+ [NewObject] Promise<void> addModule(USVString moduleURL, optional WorkletOptions options);
+};
+
+dictionary WorkletOptions {
+ RequestCredentials credentials = "omit";
+};
diff --git a/components/script/dom/webidls/WorkletGlobalScope.webidl b/components/script/dom/webidls/WorkletGlobalScope.webidl
new file mode 100644
index 00000000000..ca29296a10e
--- /dev/null
+++ b/components/script/dom/webidls/WorkletGlobalScope.webidl
@@ -0,0 +1,10 @@
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+// https://drafts.css-houdini.org/worklets/#workletglobalscope
+// TODO: The spec IDL doesn't make this a subclass of EventTarget
+// https://github.com/whatwg/html/issues/2611
+[Exposed=Worklet]
+interface WorkletGlobalScope: GlobalScope {
+};
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index 65d1a591adc..097f136e29c 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -49,6 +49,7 @@ use dom::screen::Screen;
use dom::storage::Storage;
use dom::testrunner::TestRunner;
use dom::windowproxy::WindowProxy;
+use dom::worklet::Worklet;
use dom_struct::dom_struct;
use euclid::{Point2D, Rect, Size2D};
use fetch;
@@ -273,6 +274,9 @@ pub struct Window {
/// Directory to store unminified scripts for this window if unminify-js
/// opt is enabled.
unminified_js_dir: DOMRefCell<Option<String>>,
+
+ /// Worklets
+ test_worklet: MutNullableJS<Worklet>,
}
impl Window {
@@ -1830,6 +1834,7 @@ impl Window {
permission_state_invocation_results: DOMRefCell::new(HashMap::new()),
pending_layout_images: DOMRefCell::new(HashMap::new()),
unminified_js_dir: DOMRefCell::new(None),
+ test_worklet: Default::default(),
};
unsafe {
diff --git a/components/script/dom/windowproxy.rs b/components/script/dom/windowproxy.rs
index 3290afa1f2c..e022e69a810 100644
--- a/components/script/dom/windowproxy.rs
+++ b/components/script/dom/windowproxy.rs
@@ -28,7 +28,7 @@ use js::jsapi::{MutableHandle, MutableHandleObject, MutableHandleValue};
use js::jsapi::{ObjectOpResult, PropertyDescriptor};
use js::jsval::{UndefinedValue, PrivateValue};
use js::rust::get_object_class;
-use msg::constellation_msg::FrameId;
+use msg::constellation_msg::BrowsingContextId;
use msg::constellation_msg::PipelineId;
use std::cell::Cell;
use std::ptr;
@@ -45,10 +45,10 @@ pub struct WindowProxy {
/// changes Window.
reflector: Reflector,
- /// The frame id of the browsing context.
- /// In the case that this is a nested browsing context, this is the frame id
+ /// The id of the browsing context.
+ /// In the case that this is a nested browsing context, this is the id
/// of the container.
- frame_id: FrameId,
+ browsing_context_id: BrowsingContextId,
/// The pipeline id of the currently active document.
/// May be None, when the currently active document is in another script thread.
@@ -68,7 +68,7 @@ pub struct WindowProxy {
}
impl WindowProxy {
- pub fn new_inherited(frame_id: FrameId,
+ pub fn new_inherited(browsing_context_id: BrowsingContextId,
currently_active: Option<PipelineId>,
frame_element: Option<&Element>,
parent: Option<&WindowProxy>)
@@ -76,7 +76,7 @@ impl WindowProxy {
{
WindowProxy {
reflector: Reflector::new(),
- frame_id: frame_id,
+ browsing_context_id: browsing_context_id,
currently_active: Cell::new(currently_active),
discarded: Cell::new(false),
frame_element: frame_element.map(JS::from_ref),
@@ -86,7 +86,7 @@ impl WindowProxy {
#[allow(unsafe_code)]
pub fn new(window: &Window,
- frame_id: FrameId,
+ browsing_context_id: BrowsingContextId,
frame_element: Option<&Element>,
parent: Option<&WindowProxy>)
-> Root<WindowProxy>
@@ -107,7 +107,7 @@ impl WindowProxy {
// Create a new browsing context.
let current = Some(window.global().pipeline_id());
- let mut window_proxy = box WindowProxy::new_inherited(frame_id, current, frame_element, parent);
+ let mut window_proxy = box WindowProxy::new_inherited(browsing_context_id, current, frame_element, parent);
// The window proxy owns the browsing context.
// When we finalize the window proxy, it drops the browsing context it owns.
@@ -125,7 +125,7 @@ impl WindowProxy {
#[allow(unsafe_code)]
pub fn new_dissimilar_origin(global_to_clone_from: &GlobalScope,
- frame_id: FrameId,
+ browsing_context_id: BrowsingContextId,
parent: Option<&WindowProxy>)
-> Root<WindowProxy>
{
@@ -136,7 +136,7 @@ impl WindowProxy {
let cx = global_to_clone_from.get_cx();
// Create a new browsing context.
- let mut window_proxy = box WindowProxy::new_inherited(frame_id, None, None, parent);
+ let mut window_proxy = box WindowProxy::new_inherited(browsing_context_id, None, None, parent);
// Create a new dissimilar-origin window.
let window = DissimilarOriginWindow::new(global_to_clone_from, &*window_proxy);
@@ -171,8 +171,8 @@ impl WindowProxy {
self.discarded.get()
}
- pub fn frame_id(&self) -> FrameId {
- self.frame_id
+ pub fn browsing_context_id(&self) -> BrowsingContextId {
+ self.browsing_context_id
}
pub fn frame_element(&self) -> Option<&Element> {
diff --git a/components/script/dom/worklet.rs b/components/script/dom/worklet.rs
new file mode 100644
index 00000000000..fa5b3950b51
--- /dev/null
+++ b/components/script/dom/worklet.rs
@@ -0,0 +1,637 @@
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+//! An implementation of Houdini worklets.
+//!
+//! The goal of this implementation is to maximize responsiveness of worklets,
+//! and in particular to ensure that the thread performing worklet tasks
+//! is never busy GCing or loading worklet code. We do this by providing a custom
+//! thread pool implementation, which only performs GC or code loading on
+//! a backup thread, not on the primary worklet thread.
+
+use dom::bindings::codegen::Bindings::RequestBinding::RequestCredentials;
+use dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
+use dom::bindings::codegen::Bindings::WorkletBinding::WorkletMethods;
+use dom::bindings::codegen::Bindings::WorkletBinding::WorkletOptions;
+use dom::bindings::codegen::Bindings::WorkletBinding::Wrap;
+use dom::bindings::error::Error;
+use dom::bindings::inheritance::Castable;
+use dom::bindings::js::JS;
+use dom::bindings::js::Root;
+use dom::bindings::js::RootCollection;
+use dom::bindings::refcounted::TrustedPromise;
+use dom::bindings::reflector::Reflector;
+use dom::bindings::reflector::reflect_dom_object;
+use dom::bindings::str::USVString;
+use dom::bindings::trace::JSTraceable;
+use dom::bindings::trace::RootedTraceableBox;
+use dom::globalscope::GlobalScope;
+use dom::promise::Promise;
+use dom::testworkletglobalscope::TestWorkletTask;
+use dom::window::Window;
+use dom::workletglobalscope::WorkletGlobalScope;
+use dom::workletglobalscope::WorkletGlobalScopeInit;
+use dom::workletglobalscope::WorkletGlobalScopeType;
+use dom::workletglobalscope::WorkletTask;
+use dom_struct::dom_struct;
+use js::jsapi::JSGCParamKey;
+use js::jsapi::JSTracer;
+use js::jsapi::JS_GC;
+use js::jsapi::JS_GetGCParameter;
+use js::rust::Runtime;
+use msg::constellation_msg::PipelineId;
+use net_traits::IpcSend;
+use net_traits::load_whole_resource;
+use net_traits::request::Destination;
+use net_traits::request::RequestInit;
+use net_traits::request::RequestMode;
+use net_traits::request::Type as RequestType;
+use script_runtime::CommonScriptMsg;
+use script_runtime::ScriptThreadEventCategory;
+use script_runtime::StackRootTLS;
+use script_runtime::new_rt_and_cx;
+use script_thread::MainThreadScriptMsg;
+use script_thread::Runnable;
+use script_thread::ScriptThread;
+use servo_rand;
+use servo_url::ImmutableOrigin;
+use servo_url::ServoUrl;
+use std::cmp::max;
+use std::collections::HashMap;
+use std::collections::hash_map;
+use std::rc::Rc;
+use std::sync::Arc;
+use std::sync::atomic::AtomicIsize;
+use std::sync::atomic::Ordering;
+use std::sync::mpsc;
+use std::sync::mpsc::Receiver;
+use std::sync::mpsc::Sender;
+use std::thread;
+use style::thread_state;
+use swapper::Swapper;
+use swapper::swapper;
+use uuid::Uuid;
+
+// Magic numbers
+const WORKLET_THREAD_POOL_SIZE: u32 = 3;
+const MIN_GC_THRESHOLD: u32 = 1_000_000;
+
+#[dom_struct]
+/// https://drafts.css-houdini.org/worklets/#worklet
+pub struct Worklet {
+ reflector: Reflector,
+ window: JS<Window>,
+ worklet_id: WorkletId,
+ global_type: WorkletGlobalScopeType,
+}
+
+impl Worklet {
+ fn new_inherited(window: &Window, global_type: WorkletGlobalScopeType) -> Worklet {
+ Worklet {
+ reflector: Reflector::new(),
+ window: JS::from_ref(window),
+ worklet_id: WorkletId::new(),
+ global_type: global_type,
+ }
+ }
+
+ pub fn new(window: &Window, global_type: WorkletGlobalScopeType) -> Root<Worklet> {
+ debug!("Creating worklet {:?}.", global_type);
+ reflect_dom_object(box Worklet::new_inherited(window, global_type), window, Wrap)
+ }
+
+ pub fn worklet_id(&self) -> WorkletId {
+ self.worklet_id
+ }
+
+ #[allow(dead_code)]
+ pub fn worklet_global_scope_type(&self) -> WorkletGlobalScopeType {
+ self.global_type
+ }
+}
+
+impl WorkletMethods for Worklet {
+ #[allow(unrooted_must_root)]
+ /// https://drafts.css-houdini.org/worklets/#dom-worklet-addmodule
+ fn AddModule(&self, module_url: USVString, options: &WorkletOptions) -> Rc<Promise> {
+ // Step 1.
+ let promise = Promise::new(self.window.upcast());
+
+ // Step 3.
+ let module_url_record = match self.window.Document().base_url().join(&module_url.0) {
+ Ok(url) => url,
+ Err(err) => {
+ // Step 4.
+ debug!("URL {:?} parse error {:?}.", module_url.0, err);
+ promise.reject_error(self.window.get_cx(), Error::Syntax);
+ return promise;
+ }
+ };
+ debug!("Adding Worklet module {}.", module_url_record);
+
+ // Steps 6-12 in parallel.
+ let pending_tasks_struct = PendingTasksStruct::new();
+ let global = self.window.upcast::<GlobalScope>();
+ let pool = ScriptThread::worklet_thread_pool();
+
+ pool.fetch_and_invoke_a_worklet_script(global.pipeline_id(),
+ self.worklet_id,
+ self.global_type,
+ self.window.origin().immutable().clone(),
+ global.api_base_url(),
+ module_url_record,
+ options.credentials.clone(),
+ pending_tasks_struct,
+ &promise);
+
+ // Step 5.
+ promise
+ }
+}
+
+/// A guid for worklets.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, JSTraceable)]
+pub struct WorkletId(Uuid);
+
+known_heap_size!(0, WorkletId);
+
+impl WorkletId {
+ fn new() -> WorkletId {
+ WorkletId(servo_rand::random())
+ }
+}
+
+/// https://drafts.css-houdini.org/worklets/#pending-tasks-struct
+#[derive(Clone, Debug)]
+struct PendingTasksStruct(Arc<AtomicIsize>);
+
+impl PendingTasksStruct {
+ fn new() -> PendingTasksStruct {
+ PendingTasksStruct(Arc::new(AtomicIsize::new(WORKLET_THREAD_POOL_SIZE as isize)))
+ }
+
+ fn set_counter_to(&self, value: isize) -> isize {
+ self.0.swap(value, Ordering::AcqRel)
+ }
+
+ fn decrement_counter_by(&self, offset: isize) -> isize {
+ self.0.fetch_sub(offset, Ordering::AcqRel)
+ }
+}
+
+/// Worklets execute in a dedicated thread pool.
+///
+/// The goal is to ensure that there is a primary worklet thread,
+/// which is able to responsively execute worklet code. In particular,
+/// worklet execution should not be delayed by GC, or by script
+/// loading.
+///
+/// To achieve this, we implement a three-thread pool, with the
+/// threads cycling between three thread roles:
+///
+/// * The primary worklet thread is the one available to execute
+/// worklet code.
+///
+/// * The hot backup thread may peform GC, but otherwise is expected
+/// to take over the primary role.
+///
+/// * The cold backup thread may peform script loading and other
+/// long-running tasks.
+///
+/// In the implementation, we use two kinds of messages:
+///
+/// * Data messages are expected to be processed quickly, and include
+/// the worklet tasks to be performed by the primary thread, as
+/// well as requests to change role or quit execution.
+///
+/// * Control messages are expected to be processed more slowly, and
+/// include script loading.
+///
+/// Data messages are targeted at a role, for example, task execution
+/// is expected to be performed by whichever thread is currently
+/// primary. Control messages are targeted at a thread, for example
+/// adding a module is performed in every thread, even if they change roles
+/// in the middle of module loading.
+///
+/// The thread pool lives in the script thread, and is initialized
+/// when a worklet adds a module. It is dropped when the script thread
+/// is dropped, and asks each of the worklet threads to quit.
+
+#[derive(Clone, JSTraceable)]
+pub struct WorkletThreadPool {
+ // Channels to send data messages to the three roles.
+ primary_sender: Sender<WorkletData>,
+ hot_backup_sender: Sender<WorkletData>,
+ cold_backup_sender: Sender<WorkletData>,
+ // Channels to send control messages to the three threads.
+ control_sender_0: Sender<WorkletControl>,
+ control_sender_1: Sender<WorkletControl>,
+ control_sender_2: Sender<WorkletControl>,
+}
+
+impl Drop for WorkletThreadPool {
+ fn drop(&mut self) {
+ let _ = self.cold_backup_sender.send(WorkletData::Quit);
+ let _ = self.hot_backup_sender.send(WorkletData::Quit);
+ let _ = self.primary_sender.send(WorkletData::Quit);
+ }
+}
+
+impl WorkletThreadPool {
+ /// Create a new thread pool and spawn the threads.
+ /// When the thread pool is dropped, the threads will be asked to quit.
+ pub fn spawn(script_sender: Sender<MainThreadScriptMsg>, global_init: WorkletGlobalScopeInit) -> WorkletThreadPool {
+ let primary_role = WorkletThreadRole::new(false, false);
+ let hot_backup_role = WorkletThreadRole::new(true, false);
+ let cold_backup_role = WorkletThreadRole::new(false, true);
+ let primary_sender = primary_role.sender.clone();
+ let hot_backup_sender = hot_backup_role.sender.clone();
+ let cold_backup_sender = cold_backup_role.sender.clone();
+ let init = WorkletThreadInit {
+ hot_backup_sender: hot_backup_sender.clone(),
+ cold_backup_sender: cold_backup_sender.clone(),
+ script_sender: script_sender.clone(),
+ global_init: global_init,
+ };
+ WorkletThreadPool {
+ primary_sender: primary_sender,
+ hot_backup_sender: hot_backup_sender,
+ cold_backup_sender: cold_backup_sender,
+ control_sender_0: WorkletThread::spawn(primary_role, init.clone()),
+ control_sender_1: WorkletThread::spawn(hot_backup_role, init.clone()),
+ control_sender_2: WorkletThread::spawn(cold_backup_role, init),
+ }
+ }
+
+ /// Loads a worklet module into every worklet thread.
+ /// If all of the threads load successfully, the promise is resolved.
+ /// If any of the threads fails to load, the promise is rejected.
+ /// https://drafts.css-houdini.org/worklets/#fetch-and-invoke-a-worklet-script
+ fn fetch_and_invoke_a_worklet_script(&self,
+ pipeline_id: PipelineId,
+ worklet_id: WorkletId,
+ global_type: WorkletGlobalScopeType,
+ origin: ImmutableOrigin,
+ base_url: ServoUrl,
+ script_url: ServoUrl,
+ credentials: RequestCredentials,
+ pending_tasks_struct: PendingTasksStruct,
+ promise: &Rc<Promise>)
+ {
+ // Send each thread a control message asking it to load the script.
+ for sender in &[&self.control_sender_0, &self.control_sender_1, &self.control_sender_2] {
+ let _ = sender.send(WorkletControl::FetchAndInvokeAWorkletScript {
+ pipeline_id: pipeline_id,
+ worklet_id: worklet_id,
+ global_type: global_type,
+ origin: origin.clone(),
+ base_url: base_url.clone(),
+ script_url: script_url.clone(),
+ credentials: credentials,
+ pending_tasks_struct: pending_tasks_struct.clone(),
+ promise: TrustedPromise::new(promise.clone()),
+ });
+ }
+ // If any of the threads are blocked waiting on data, wake them up.
+ let _ = self.cold_backup_sender.send(WorkletData::WakeUp);
+ let _ = self.hot_backup_sender.send(WorkletData::WakeUp);
+ let _ = self.primary_sender.send(WorkletData::WakeUp);
+ }
+
+ /// For testing.
+ pub fn test_worklet_lookup(&self, id: WorkletId, key: String) -> Option<String> {
+ let (sender, receiver) = mpsc::channel();
+ let msg = WorkletData::Task(id, WorkletTask::Test(TestWorkletTask::Lookup(key, sender)));
+ let _ = self.primary_sender.send(msg);
+ receiver.recv().expect("Test worklet has died?")
+ }
+}
+
+/// The data messages sent to worklet threads
+enum WorkletData {
+ Task(WorkletId, WorkletTask),
+ StartSwapRoles(Sender<WorkletData>),
+ FinishSwapRoles(Swapper<WorkletThreadRole>),
+ WakeUp,
+ Quit,
+}
+
+/// The control message sent to worklet threads
+enum WorkletControl {
+ FetchAndInvokeAWorkletScript {
+ pipeline_id: PipelineId,
+ worklet_id: WorkletId,
+ global_type: WorkletGlobalScopeType,
+ origin: ImmutableOrigin,
+ base_url: ServoUrl,
+ script_url: ServoUrl,
+ credentials: RequestCredentials,
+ pending_tasks_struct: PendingTasksStruct,
+ promise: TrustedPromise,
+ },
+}
+
+/// A role that a worklet thread can be playing.
+///
+/// These roles are used as tokens or capabilities, we track unique
+/// ownership using Rust's types, and use atomic swapping to exchange
+/// them between worklet threads. This ensures that each thread pool has
+/// exactly one primary, one hot backup and one cold backup.
+struct WorkletThreadRole {
+ receiver: Receiver<WorkletData>,
+ sender: Sender<WorkletData>,
+ is_hot_backup: bool,
+ is_cold_backup: bool,
+}
+
+impl WorkletThreadRole {
+ fn new(is_hot_backup: bool, is_cold_backup: bool) -> WorkletThreadRole {
+ let (sender, receiver) = mpsc::channel();
+ WorkletThreadRole {
+ sender: sender,
+ receiver: receiver,
+ is_hot_backup: is_hot_backup,
+ is_cold_backup: is_cold_backup,
+ }
+ }
+}
+
+/// Data to initialize a worklet thread.
+#[derive(Clone)]
+struct WorkletThreadInit {
+ /// Senders
+ hot_backup_sender: Sender<WorkletData>,
+ cold_backup_sender: Sender<WorkletData>,
+ script_sender: Sender<MainThreadScriptMsg>,
+
+ /// Data for initializing new worklet global scopes
+ global_init: WorkletGlobalScopeInit,
+}
+
+/// A thread for executing worklets.
+#[must_root]
+struct WorkletThread {
+ /// Which role the thread is currently playing
+ role: WorkletThreadRole,
+
+ /// The thread's receiver for control messages
+ control_receiver: Receiver<WorkletControl>,
+
+ /// Senders
+ hot_backup_sender: Sender<WorkletData>,
+ cold_backup_sender: Sender<WorkletData>,
+ script_sender: Sender<MainThreadScriptMsg>,
+
+ /// Data for initializing new worklet global scopes
+ global_init: WorkletGlobalScopeInit,
+
+ /// The global scopes created by this thread
+ global_scopes: HashMap<WorkletId, JS<WorkletGlobalScope>>,
+
+ /// A one-place buffer for control messages
+ control_buffer: Option<WorkletControl>,
+
+ /// The JS runtime
+ runtime: Runtime,
+ should_gc: bool,
+ gc_threshold: u32,
+}
+
+#[allow(unsafe_code)]
+unsafe impl JSTraceable for WorkletThread {
+ unsafe fn trace(&self, trc: *mut JSTracer) {
+ debug!("Tracing worklet thread.");
+ self.global_scopes.trace(trc);
+ }
+}
+
+impl WorkletThread {
+ /// Spawn a new worklet thread, returning the channel to send it control messages.
+ #[allow(unsafe_code)]
+ #[allow(unrooted_must_root)]
+ fn spawn(role: WorkletThreadRole, init: WorkletThreadInit) -> Sender<WorkletControl> {
+ let (control_sender, control_receiver) = mpsc::channel();
+ // TODO: name this thread
+ thread::spawn(move || {
+ // TODO: add a new IN_WORKLET thread state?
+ // TODO: set interrupt handler?
+ // TODO: configure the JS runtime (e.g. discourage GC, encourage agressive JIT)
+ debug!("Initializing worklet thread.");
+ thread_state::initialize(thread_state::SCRIPT | thread_state::IN_WORKER);
+ let roots = RootCollection::new();
+ let _stack_roots_tls = StackRootTLS::new(&roots);
+ let mut thread = RootedTraceableBox::new(WorkletThread {
+ role: role,
+ control_receiver: control_receiver,
+ hot_backup_sender: init.hot_backup_sender,
+ cold_backup_sender: init.cold_backup_sender,
+ script_sender: init.script_sender,
+ global_init: init.global_init,
+ global_scopes: HashMap::new(),
+ control_buffer: None,
+ runtime: unsafe { new_rt_and_cx() },
+ should_gc: false,
+ gc_threshold: MIN_GC_THRESHOLD,
+ });
+ thread.run();
+ });
+ control_sender
+ }
+
+ /// The main event loop for a worklet thread
+ fn run(&mut self) {
+ loop {
+ // The handler for data messages
+ let message = self.role.receiver.recv().unwrap();
+ match message {
+ // The whole point of this thread pool is to perform tasks!
+ WorkletData::Task(id, task) => {
+ self.perform_a_worklet_task(id, task);
+ }
+ // To start swapping roles, get ready to perform an atomic swap,
+ // and block waiting for the other end to finish it.
+ // NOTE: the cold backup can block on the primary or the hot backup;
+ // the hot backup can block on the primary;
+ // the primary can block on nothing;
+ // this total ordering on thread roles is what guarantees deadlock-freedom.
+ WorkletData::StartSwapRoles(sender) => {
+ let (our_swapper, their_swapper) = swapper();
+ sender.send(WorkletData::FinishSwapRoles(their_swapper)).unwrap();
+ let _ = our_swapper.swap(&mut self.role);
+ }
+ // To finish swapping roles, perform the atomic swap.
+ // The other end should have already started the swap, so this shouldn't block.
+ WorkletData::FinishSwapRoles(swapper) => {
+ let _ = swapper.swap(&mut self.role);
+ }
+ // Wake up! There may be control messages to process.
+ WorkletData::WakeUp => {
+ }
+ // Quit!
+ WorkletData::Quit => {
+ return;
+ }
+ }
+ // Only process control messages if we're the cold backup,
+ // otherwise if there are outstanding control messages,
+ // try to become the cold backup.
+ if self.role.is_cold_backup {
+ if let Some(control) = self.control_buffer.take() {
+ self.process_control(control);
+ }
+ while let Ok(control) = self.control_receiver.try_recv() {
+ self.process_control(control);
+ }
+ self.gc();
+ } else if self.control_buffer.is_none() {
+ if let Ok(control) = self.control_receiver.try_recv() {
+ self.control_buffer = Some(control);
+ let msg = WorkletData::StartSwapRoles(self.role.sender.clone());
+ let _ = self.cold_backup_sender.send(msg);
+ }
+ }
+ // If we are tight on memory, and we're a backup then perform a gc.
+ // If we are tight on memory, and we're the primary then try to become the hot backup.
+ // Hopefully this happens soon!
+ if self.current_memory_usage() > self.gc_threshold {
+ if self.role.is_hot_backup || self.role.is_cold_backup {
+ self.should_gc = false;
+ self.gc();
+ } else if !self.should_gc {
+ self.should_gc = true;
+ let msg = WorkletData::StartSwapRoles(self.role.sender.clone());
+ let _ = self.hot_backup_sender.send(msg);
+ }
+ }
+ }
+ }
+
+ /// The current memory usage of the thread
+ #[allow(unsafe_code)]
+ fn current_memory_usage(&self) -> u32 {
+ unsafe { JS_GetGCParameter(self.runtime.rt(), JSGCParamKey::JSGC_BYTES) }
+ }
+
+ /// Perform a GC.
+ #[allow(unsafe_code)]
+ fn gc(&mut self) {
+ debug!("BEGIN GC (usage = {}, threshold = {}).", self.current_memory_usage(), self.gc_threshold);
+ unsafe { JS_GC(self.runtime.rt()) };
+ self.gc_threshold = max(MIN_GC_THRESHOLD, self.current_memory_usage() * 2);
+ debug!("END GC (usage = {}, threshold = {}).", self.current_memory_usage(), self.gc_threshold);
+ }
+
+ /// Get the worklet global scope for a given worklet.
+ /// Creates the worklet global scope if it doesn't exist.
+ fn get_worklet_global_scope(&mut self,
+ pipeline_id: PipelineId,
+ worklet_id: WorkletId,
+ global_type: WorkletGlobalScopeType,
+ base_url: ServoUrl)
+ -> Root<WorkletGlobalScope>
+ {
+ match self.global_scopes.entry(worklet_id) {
+ hash_map::Entry::Occupied(entry) => Root::from_ref(entry.get()),
+ hash_map::Entry::Vacant(entry) => {
+ let result = global_type.new(&self.runtime, pipeline_id, base_url, &self.global_init);
+ entry.insert(JS::from_ref(&*result));
+ result
+ },
+ }
+ }
+
+ /// Fetch and invoke a worklet script.
+ /// https://drafts.css-houdini.org/worklets/#fetch-and-invoke-a-worklet-script
+ fn fetch_and_invoke_a_worklet_script(&self,
+ global_scope: &WorkletGlobalScope,
+ origin: ImmutableOrigin,
+ script_url: ServoUrl,
+ credentials: RequestCredentials,
+ pending_tasks_struct: PendingTasksStruct,
+ promise: TrustedPromise)
+ {
+ debug!("Fetching from {}.", script_url);
+ // Step 1.
+ // TODO: Settings object?
+
+ // Step 2.
+ // TODO: Fetch a module graph, not just a single script.
+ // TODO: Fetch the script asynchronously?
+ // TODO: Caching.
+ // TODO: Avoid re-parsing the origin as a URL.
+ let resource_fetcher = self.global_init.resource_threads.sender();
+ let origin_url = ServoUrl::parse(&*origin.unicode_serialization()).expect("Failed to parse origin as URL.");
+ let request = RequestInit {
+ url: script_url,
+ type_: RequestType::Script,
+ destination: Destination::Script,
+ mode: RequestMode::CorsMode,
+ origin: origin_url,
+ credentials_mode: credentials.into(),
+ .. RequestInit::default()
+ };
+ let script = load_whole_resource(request, &resource_fetcher).ok()
+ .and_then(|(_, bytes)| String::from_utf8(bytes).ok());
+
+ // Step 4.
+ // NOTE: the spec parses and executes the script in separate steps,
+ // but our JS API doesn't separate these, so we do the steps out of order.
+ let ok = script.map(|script| global_scope.evaluate_js(&*script)).unwrap_or(false);
+
+ if !ok {
+ // Step 3.
+ debug!("Failed to load script.");
+ let old_counter = pending_tasks_struct.set_counter_to(-1);
+ if old_counter > 0 {
+ self.run_in_script_thread(promise.reject_runnable(Error::Abort));
+ }
+ } else {
+ // Step 5.
+ debug!("Finished adding script.");
+ let old_counter = pending_tasks_struct.decrement_counter_by(1);
+ if old_counter == 1 {
+ // TODO: trigger a reflow?
+ self.run_in_script_thread(promise.resolve_runnable(()));
+ }
+ }
+ }
+
+ /// Perform a task.
+ fn perform_a_worklet_task(&self, worklet_id: WorkletId, task: WorkletTask) {
+ match self.global_scopes.get(&worklet_id) {
+ Some(global) => global.perform_a_worklet_task(task),
+ None => return warn!("No such worklet as {:?}.", worklet_id),
+ }
+ }
+
+ /// Process a control message.
+ fn process_control(&mut self, control: WorkletControl) {
+ match control {
+ WorkletControl::FetchAndInvokeAWorkletScript {
+ pipeline_id, worklet_id, global_type, origin, base_url,
+ script_url, credentials, pending_tasks_struct, promise,
+ } => {
+ let global = self.get_worklet_global_scope(pipeline_id,
+ worklet_id,
+ global_type,
+ base_url);
+ self.fetch_and_invoke_a_worklet_script(&*global,
+ origin,
+ script_url,
+ credentials,
+ pending_tasks_struct,
+ promise)
+ }
+ }
+ }
+
+ /// Run a runnable in the main script thread.
+ fn run_in_script_thread<R>(&self, runnable: R) where
+ R: 'static + Send + Runnable,
+ {
+ let msg = CommonScriptMsg::RunnableMsg(ScriptThreadEventCategory::WorkletEvent, box runnable);
+ let msg = MainThreadScriptMsg::Common(msg);
+ self.script_sender.send(msg).expect("Worklet thread outlived script thread.");
+ }
+}
diff --git a/components/script/dom/workletglobalscope.rs b/components/script/dom/workletglobalscope.rs
new file mode 100644
index 00000000000..a2e2463ca27
--- /dev/null
+++ b/components/script/dom/workletglobalscope.rs
@@ -0,0 +1,143 @@
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+use devtools_traits::ScriptToDevtoolsControlMsg;
+use dom::bindings::inheritance::Castable;
+use dom::bindings::js::Root;
+use dom::globalscope::GlobalScope;
+use dom::testworkletglobalscope::TestWorkletGlobalScope;
+use dom::testworkletglobalscope::TestWorkletTask;
+use dom_struct::dom_struct;
+use ipc_channel::ipc;
+use ipc_channel::ipc::IpcSender;
+use js::jsval::UndefinedValue;
+use js::rust::Runtime;
+use microtask::Microtask;
+use microtask::MicrotaskQueue;
+use msg::constellation_msg::PipelineId;
+use net_traits::ResourceThreads;
+use profile_traits::mem;
+use profile_traits::time;
+use script_traits::ScriptMsg;
+use script_traits::TimerSchedulerMsg;
+use servo_url::ImmutableOrigin;
+use servo_url::MutableOrigin;
+use servo_url::ServoUrl;
+
+#[dom_struct]
+/// https://drafts.css-houdini.org/worklets/#workletglobalscope
+pub struct WorkletGlobalScope {
+ /// The global for this worklet.
+ globalscope: GlobalScope,
+ /// The base URL for this worklet.
+ base_url: ServoUrl,
+ /// The microtask queue for this worklet
+ microtask_queue: MicrotaskQueue,
+}
+
+impl WorkletGlobalScope {
+ /// Create a new stack-allocated `WorkletGlobalScope`.
+ pub fn new_inherited(pipeline_id: PipelineId,
+ base_url: ServoUrl,
+ init: &WorkletGlobalScopeInit)
+ -> WorkletGlobalScope {
+ // Any timer events fired on this global are ignored.
+ let (timer_event_chan, _) = ipc::channel().unwrap();
+ WorkletGlobalScope {
+ globalscope: GlobalScope::new_inherited(pipeline_id,
+ init.devtools_chan.clone(),
+ init.mem_profiler_chan.clone(),
+ init.time_profiler_chan.clone(),
+ init.constellation_chan.clone(),
+ init.scheduler_chan.clone(),
+ init.resource_threads.clone(),
+ timer_event_chan,
+ MutableOrigin::new(ImmutableOrigin::new_opaque())),
+ base_url: base_url,
+ microtask_queue: MicrotaskQueue::default(),
+ }
+ }
+
+ /// Evaluate a JS script in this global.
+ pub fn evaluate_js(&self, script: &str) -> bool {
+ debug!("Evaluating JS.");
+ rooted!(in (self.globalscope.get_cx()) let mut rval = UndefinedValue());
+ self.globalscope.evaluate_js_on_global_with_result(&*script, rval.handle_mut())
+ }
+
+ /// The base URL of this global.
+ pub fn base_url(&self) -> ServoUrl {
+ self.base_url.clone()
+ }
+
+ /// Queue up a microtask to be executed in this global.
+ pub fn enqueue_microtask(&self, job: Microtask) {
+ self.microtask_queue.enqueue(job);
+ }
+
+ /// Perform any queued microtasks.
+ pub fn perform_a_microtask_checkpoint(&self) {
+ self.microtask_queue.checkpoint(|id| {
+ let global = self.upcast::<GlobalScope>();
+ assert_eq!(global.pipeline_id(), id);
+ Some(Root::from_ref(global))
+ });
+ }
+
+ /// Perform a worklet task
+ pub fn perform_a_worklet_task(&self, task: WorkletTask) {
+ match task {
+ WorkletTask::Test(task) => match self.downcast::<TestWorkletGlobalScope>() {
+ Some(global) => global.perform_a_worklet_task(task),
+ None => warn!("This is not a test worklet."),
+ },
+ }
+ }
+}
+
+/// Resources required by workletglobalscopes
+#[derive(Clone)]
+pub struct WorkletGlobalScopeInit {
+ /// Channel to a resource thread
+ pub resource_threads: ResourceThreads,
+ /// Channel to the memory profiler
+ pub mem_profiler_chan: mem::ProfilerChan,
+ /// Channel to the time profiler
+ pub time_profiler_chan: time::ProfilerChan,
+ /// Channel to devtools
+ pub devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
+ /// Messages to send to constellation
+ pub constellation_chan: IpcSender<ScriptMsg>,
+ /// Message to send to the scheduler
+ pub scheduler_chan: IpcSender<TimerSchedulerMsg>,
+}
+
+/// https://drafts.css-houdini.org/worklets/#worklet-global-scope-type
+#[derive(Clone, Copy, Debug, HeapSizeOf, JSTraceable)]
+pub enum WorkletGlobalScopeType {
+ /// https://drafts.css-houdini.org/worklets/#examples
+ Test,
+}
+
+impl WorkletGlobalScopeType {
+ /// Create a new heap-allocated `WorkletGlobalScope`.
+ pub fn new(&self,
+ runtime: &Runtime,
+ pipeline_id: PipelineId,
+ base_url: ServoUrl,
+ init: &WorkletGlobalScopeInit)
+ -> Root<WorkletGlobalScope>
+ {
+ match *self {
+ WorkletGlobalScopeType::Test =>
+ Root::upcast(TestWorkletGlobalScope::new(runtime, pipeline_id, base_url, init)),
+ }
+ }
+}
+
+/// A task which can be performed in the context of a worklet global.
+pub enum WorkletTask {
+ Test(TestWorkletTask),
+}
+
diff --git a/components/script/layout_wrapper.rs b/components/script/layout_wrapper.rs
index 3d4b90eaeab..62e5158f321 100644
--- a/components/script/layout_wrapper.rs
+++ b/components/script/layout_wrapper.rs
@@ -44,14 +44,14 @@ use dom::node::{LayoutNodeHelpers, Node};
use dom::text::Text;
use gfx_traits::ByteIndex;
use html5ever::{LocalName, Namespace};
-use msg::constellation_msg::{FrameId, PipelineId};
+use msg::constellation_msg::{BrowsingContextId, PipelineId};
use range::Range;
use script_layout_interface::{HTMLCanvasData, LayoutNodeType, SVGSVGData, TrustedNodeAddress};
use script_layout_interface::{OpaqueStyleAndLayoutData, PartialPersistentLayoutData};
use script_layout_interface::wrapper_traits::{DangerousThreadSafeLayoutNode, GetLayoutData, LayoutNode};
use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
-use selectors::matching::{ElementSelectorFlags, StyleRelations};
-use selectors::parser::{AttrSelector, NamespaceConstraint};
+use selectors::attr::{AttrSelectorOperation, NamespaceConstraint};
+use selectors::matching::{ElementSelectorFlags, MatchingContext};
use servo_atoms::Atom;
use servo_url::ServoUrl;
use std::fmt;
@@ -402,11 +402,22 @@ impl<'le> TElement for ServoLayoutElement<'le> {
self.get_attr(namespace, attr).map_or(false, |x| x == val)
}
+ #[inline(always)]
+ fn each_class<F>(&self, mut callback: F) where F: FnMut(&Atom) {
+ unsafe {
+ if let Some(ref classes) = self.element.get_classes_for_layout() {
+ for class in *classes {
+ callback(class)
+ }
+ }
+ }
+ }
+
#[inline]
fn existing_style_for_restyle_damage<'a>(&'a self,
- current_cv: &'a Arc<ComputedValues>,
+ current_cv: &'a ComputedValues,
_pseudo_element: Option<&PseudoElement>)
- -> Option<&'a Arc<ComputedValues>> {
+ -> Option<&'a ComputedValues> {
Some(current_cv)
}
@@ -510,6 +521,13 @@ impl<'le> ServoLayoutElement<'le> {
}
#[inline]
+ fn get_attr_enum(&self, namespace: &Namespace, name: &LocalName) -> Option<&AttrValue> {
+ unsafe {
+ (*self.element.unsafe_get()).get_attr_for_layout(namespace, name)
+ }
+ }
+
+ #[inline]
fn get_attr(&self, namespace: &Namespace, name: &LocalName) -> Option<&str> {
unsafe {
(*self.element.unsafe_get()).get_attr_val_for_layout(namespace, name)
@@ -558,32 +576,9 @@ fn as_element<'le>(node: LayoutJS<Node>) -> Option<ServoLayoutElement<'le>> {
node.downcast().map(ServoLayoutElement::from_layout_js)
}
-impl<'le> ::selectors::MatchAttrGeneric for ServoLayoutElement<'le> {
+impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
type Impl = SelectorImpl;
- fn match_attr<F>(&self, attr: &AttrSelector<SelectorImpl>, test: F) -> bool
- where F: Fn(&str) -> bool {
- use ::selectors::Element;
- let name = if self.is_html_element_in_html_document() {
- &attr.lower_name
- } else {
- &attr.name
- };
- match attr.namespace {
- NamespaceConstraint::Specific(ref ns) => {
- self.get_attr(&ns.url, name).map_or(false, |attr| test(attr))
- },
- NamespaceConstraint::Any => {
- let attrs = unsafe {
- (*self.element.unsafe_get()).get_attr_vals_for_layout(name)
- };
- attrs.iter().any(|attr| test(*attr))
- }
- }
- }
-}
-
-impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
fn parent_element(&self) -> Option<ServoLayoutElement<'le>> {
unsafe {
self.element.upcast().parent_node_ref().and_then(as_element)
@@ -620,6 +615,25 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
None
}
+ fn attr_matches(&self,
+ ns: &NamespaceConstraint<&Namespace>,
+ local_name: &LocalName,
+ operation: &AttrSelectorOperation<&String>)
+ -> bool {
+ match *ns {
+ NamespaceConstraint::Specific(ref ns) => {
+ self.get_attr_enum(ns, local_name)
+ .map_or(false, |value| value.eval_selector(operation))
+ }
+ NamespaceConstraint::Any => {
+ let values = unsafe {
+ (*self.element.unsafe_get()).get_attr_vals_for_layout(local_name)
+ };
+ values.iter().any(|value| value.eval_selector(operation))
+ }
+ }
+ }
+
fn is_root(&self) -> bool {
match self.as_node().parent_node() {
None => false,
@@ -652,9 +666,17 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
self.element.namespace()
}
+ fn match_pseudo_element(&self,
+ _pseudo: &PseudoElement,
+ _context: &mut MatchingContext)
+ -> bool
+ {
+ false
+ }
+
fn match_non_ts_pseudo_class<F>(&self,
pseudo_class: &NonTSPseudoClass,
- _: &mut StyleRelations,
+ _: &mut MatchingContext,
_: &mut F)
-> bool
where F: FnMut(&Self, ElementSelectorFlags),
@@ -684,7 +706,10 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
_ => true,
}
},
-
+ NonTSPseudoClass::ServoCaseSensitiveTypeAttr(ref expected_value) => {
+ self.get_attr_enum(&ns!(), &local_name!("type"))
+ .map_or(false, |attr| attr == expected_value)
+ }
NonTSPseudoClass::ReadOnly =>
!self.element.get_state_for_layout().contains(pseudo_class.state_flag()),
@@ -717,17 +742,6 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
}
}
- #[inline(always)]
- fn each_class<F>(&self, mut callback: F) where F: FnMut(&Atom) {
- unsafe {
- if let Some(ref classes) = self.element.get_classes_for_layout() {
- for class in *classes {
- callback(class)
- }
- }
- }
- }
-
fn is_html_element_in_html_document(&self) -> bool {
unsafe {
self.element.html_element_in_html_document_for_layout()
@@ -908,9 +922,9 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> {
this.svg_data()
}
- fn iframe_frame_id(&self) -> FrameId {
+ fn iframe_browsing_context_id(&self) -> BrowsingContextId {
let this = unsafe { self.get_jsmanaged() };
- this.iframe_frame_id()
+ this.iframe_browsing_context_id()
}
fn iframe_pipeline_id(&self) -> PipelineId {
@@ -1067,6 +1081,10 @@ impl<'le> ThreadSafeLayoutElement for ServoThreadSafeLayoutElement<'le> {
self.element
}
+ fn get_attr_enum(&self, namespace: &Namespace, name: &LocalName) -> Option<&AttrValue> {
+ self.element.get_attr_enum(namespace, name)
+ }
+
fn get_attr<'a>(&'a self, namespace: &Namespace, name: &LocalName) -> Option<&'a str> {
self.element.get_attr(namespace, name)
}
@@ -1083,30 +1101,14 @@ impl<'le> ThreadSafeLayoutElement for ServoThreadSafeLayoutElement<'le> {
/// i.e., local_name, attributes, so they can only be used for **private**
/// pseudo-elements (like `::-servo-details-content`).
///
-/// Probably a few more of this functions can be implemented (like `has_class`,
-/// `each_class`, etc), but they have no use right now.
+/// Probably a few more of this functions can be implemented (like `has_class`, etc.),
+/// but they have no use right now.
///
/// Note that the element implementation is needed only for selector matching,
/// not for inheritance (styles are inherited appropiately).
-impl<'le> ::selectors::MatchAttrGeneric for ServoThreadSafeLayoutElement<'le> {
+impl<'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> {
type Impl = SelectorImpl;
- fn match_attr<F>(&self, attr: &AttrSelector<SelectorImpl>, test: F) -> bool
- where F: Fn(&str) -> bool {
- match attr.namespace {
- NamespaceConstraint::Specific(ref ns) => {
- self.get_attr(&ns.url, &attr.name).map_or(false, |attr| test(attr))
- },
- NamespaceConstraint::Any => {
- unsafe {
- (*self.element.element.unsafe_get()).get_attr_vals_for_layout(&attr.name).iter()
- .any(|attr| test(*attr))
- }
- }
- }
- }
-}
-impl<'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> {
fn parent_element(&self) -> Option<Self> {
warn!("ServoThreadSafeLayoutElement::parent_element called");
None
@@ -1150,9 +1152,36 @@ impl<'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> {
self.element.get_namespace()
}
+ fn match_pseudo_element(&self,
+ _pseudo: &PseudoElement,
+ _context: &mut MatchingContext)
+ -> bool
+ {
+ false
+ }
+
+ fn attr_matches(&self,
+ ns: &NamespaceConstraint<&Namespace>,
+ local_name: &LocalName,
+ operation: &AttrSelectorOperation<&String>)
+ -> bool {
+ match *ns {
+ NamespaceConstraint::Specific(ref ns) => {
+ self.get_attr_enum(ns, local_name)
+ .map_or(false, |value| value.eval_selector(operation))
+ }
+ NamespaceConstraint::Any => {
+ let values = unsafe {
+ (*self.element.element.unsafe_get()).get_attr_vals_for_layout(local_name)
+ };
+ values.iter().any(|v| v.eval_selector(operation))
+ }
+ }
+ }
+
fn match_non_ts_pseudo_class<F>(&self,
_: &NonTSPseudoClass,
- _: &mut StyleRelations,
+ _: &mut MatchingContext,
_: &mut F)
-> bool
where F: FnMut(&Self, ElementSelectorFlags),
@@ -1181,11 +1210,6 @@ impl<'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> {
warn!("ServoThreadSafeLayoutElement::is_root called");
false
}
-
- fn each_class<F>(&self, _callback: F)
- where F: FnMut(&Atom) {
- warn!("ServoThreadSafeLayoutElement::each_class called");
- }
}
impl<'le> PresentationalHintsSynthesizer for ServoThreadSafeLayoutElement<'le> {
diff --git a/components/script/lib.rs b/components/script/lib.rs
index c1bd886b927..703209604b0 100644
--- a/components/script/lib.rs
+++ b/components/script/lib.rs
@@ -10,10 +10,12 @@
#![feature(nonzero)]
#![feature(on_unimplemented)]
#![feature(optin_builtin_traits)]
+#![feature(option_entry)]
#![feature(plugin)]
#![feature(proc_macro)]
#![feature(stmt_expr_attributes)]
#![feature(try_from)]
+#![feature(unboxed_closures)]
#![feature(untagged_unions)]
#![deny(unsafe_code)]
@@ -46,7 +48,7 @@ extern crate encoding;
extern crate euclid;
extern crate fnv;
extern crate gfx_traits;
-extern crate heapsize;
+#[macro_use] extern crate heapsize;
#[macro_use] extern crate heapsize_derive;
#[macro_use] extern crate html5ever;
#[macro_use]
@@ -92,6 +94,7 @@ extern crate smallvec;
#[macro_use]
extern crate style;
extern crate style_traits;
+extern crate swapper;
extern crate time;
#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
extern crate tinyfiledialogs;
diff --git a/components/script/microtask.rs b/components/script/microtask.rs
index da04d1ed6ab..7fadf111ddb 100644
--- a/components/script/microtask.rs
+++ b/components/script/microtask.rs
@@ -11,6 +11,7 @@ use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::PromiseBinding::PromiseJobCallback;
use dom::bindings::js::Root;
use dom::globalscope::GlobalScope;
+use dom::mutationobserver::MutationObserver;
use msg::constellation_msg::PipelineId;
use std::cell::Cell;
use std::mem;
@@ -28,6 +29,7 @@ pub struct MicrotaskQueue {
#[derive(JSTraceable, HeapSizeOf)]
pub enum Microtask {
Promise(EnqueuedPromiseCallback),
+ NotifyMutationObservers,
}
/// A promise callback scheduled to run during the next microtask checkpoint (#4283).
@@ -71,6 +73,9 @@ impl MicrotaskQueue {
let _ = job.callback.Call_(&*target, ExceptionHandling::Report);
}
}
+ Microtask::NotifyMutationObservers => {
+ MutationObserver::notify_mutation_observers();
+ }
}
}
}
diff --git a/components/script/script_runtime.rs b/components/script/script_runtime.rs
index c4f90edf8ea..8c243b18695 100644
--- a/components/script/script_runtime.rs
+++ b/components/script/script_runtime.rs
@@ -74,6 +74,7 @@ pub enum ScriptThreadEventCategory {
UpdateReplacedElement,
WebSocketEvent,
WorkerEvent,
+ WorkletEvent,
ServiceWorkerEvent,
EnterFullscreen,
ExitFullscreen,
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs
index b817fc77d1d..8a6efa946ad 100644
--- a/components/script/script_thread.rs
+++ b/components/script/script_thread.rs
@@ -56,6 +56,8 @@ use dom::uievent::UIEvent;
use dom::window::{ReflowReason, Window};
use dom::windowproxy::WindowProxy;
use dom::worker::TrustedWorkerAddress;
+use dom::worklet::WorkletThreadPool;
+use dom::workletglobalscope::WorkletGlobalScopeInit;
use euclid::Rect;
use euclid::point::Point2D;
use hyper::header::{ContentType, HttpDate, LastModified, Headers};
@@ -71,7 +73,7 @@ use js::jsval::UndefinedValue;
use js::rust::Runtime;
use mem::heap_size_of_self_and_children;
use microtask::{MicrotaskQueue, Microtask};
-use msg::constellation_msg::{FrameId, FrameType, PipelineId, PipelineNamespace};
+use msg::constellation_msg::{BrowsingContextId, FrameType, PipelineId, PipelineNamespace};
use net_traits::{CoreResourceMsg, FetchMetadata, FetchResponseListener};
use net_traits::{IpcSend, Metadata, ReferrerPolicy, ResourceThreads};
use net_traits::image_cache::{ImageCache, PendingImageResponse};
@@ -142,7 +144,7 @@ struct InProgressLoad {
/// The pipeline which requested this load.
pipeline_id: PipelineId,
/// The frame being loaded into.
- frame_id: FrameId,
+ browsing_context_id: BrowsingContextId,
/// The parent pipeline and frame type associated with this load, if any.
parent_info: Option<(PipelineId, FrameType)>,
/// The current window size associated with this pipeline.
@@ -162,7 +164,7 @@ struct InProgressLoad {
impl InProgressLoad {
/// Create a new InProgressLoad object.
fn new(id: PipelineId,
- frame_id: FrameId,
+ browsing_context_id: BrowsingContextId,
parent_info: Option<(PipelineId, FrameType)>,
layout_chan: Sender<message::Msg>,
window_size: Option<WindowSizeData>,
@@ -170,7 +172,7 @@ impl InProgressLoad {
origin: MutableOrigin) -> InProgressLoad {
InProgressLoad {
pipeline_id: id,
- frame_id: frame_id,
+ browsing_context_id: browsing_context_id,
parent_info: parent_info,
layout_chan: layout_chan,
window_size: window_size,
@@ -368,8 +370,10 @@ impl Documents {
self.find_window(pipeline_id).map(|window| Root::from_ref(window.upcast()))
}
- pub fn find_iframe(&self, pipeline_id: PipelineId, frame_id: FrameId) -> Option<Root<HTMLIFrameElement>> {
- self.find_document(pipeline_id).and_then(|doc| doc.find_iframe(frame_id))
+ pub fn find_iframe(&self, pipeline_id: PipelineId, browsing_context_id: BrowsingContextId)
+ -> Option<Root<HTMLIFrameElement>>
+ {
+ self.find_document(pipeline_id).and_then(|doc| doc.find_iframe(browsing_context_id))
}
pub fn iter<'a>(&'a self) -> DocumentsIter<'a> {
@@ -400,7 +404,7 @@ pub struct ScriptThread {
documents: DOMRefCell<Documents>,
/// The window proxies known by this thread
/// TODO: this map grows, but never shrinks. Issue #15258.
- window_proxies: DOMRefCell<HashMap<FrameId, JS<WindowProxy>>>,
+ window_proxies: DOMRefCell<HashMap<BrowsingContextId, JS<WindowProxy>>>,
/// A list of data pertaining to loads that have not yet received a network response
incomplete_loads: DOMRefCell<Vec<InProgressLoad>>,
/// A map to store service worker registrations for a given origin
@@ -479,12 +483,18 @@ pub struct ScriptThread {
microtask_queue: MicrotaskQueue,
+ /// Microtask Queue for adding support for mutation observer microtasks
+ mutation_observer_compound_microtask_queued: Cell<bool>,
+
/// The unit of related similar-origin browsing contexts' list of MutationObserver objects
mutation_observers: DOMRefCell<Vec<JS<MutationObserver>>>,
/// A handle to the webvr thread, if available
webvr_thread: Option<IpcSender<WebVRMsg>>,
+ /// The worklet thread pool
+ worklet_thread_pool: DOMRefCell<Option<Rc<WorkletThreadPool>>>,
+
/// A list of pipelines containing documents that finished loading all their blocking
/// resources during a turn of the event loop.
docs_with_no_blocking_loads: DOMRefCell<HashSet<JS<Document>>>,
@@ -538,11 +548,11 @@ impl ScriptThreadFactory for ScriptThread {
thread::Builder::new().name(format!("ScriptThread {:?}", state.id)).spawn(move || {
thread_state::initialize(thread_state::SCRIPT);
PipelineNamespace::install(state.pipeline_namespace_id);
- FrameId::install(state.top_level_frame_id);
+ BrowsingContextId::install(state.top_level_browsing_context_id);
let roots = RootCollection::new();
let _stack_roots_tls = StackRootTLS::new(&roots);
let id = state.id;
- let frame_id = state.frame_id;
+ let browsing_context_id = state.browsing_context_id;
let parent_info = state.parent_info;
let mem_profiler_chan = state.mem_profiler_chan.clone();
let window_size = state.window_size;
@@ -557,7 +567,7 @@ impl ScriptThreadFactory for ScriptThread {
let mut failsafe = ScriptMemoryFailsafe::new(&script_thread);
let origin = MutableOrigin::new(load_data.url.origin());
- let new_load = InProgressLoad::new(id, frame_id, parent_info,
+ let new_load = InProgressLoad::new(id, browsing_context_id, parent_info,
layout_chan, window_size, load_data.url.clone(), origin);
script_thread.start_page_load(new_load, load_data);
@@ -587,6 +597,20 @@ impl ScriptThread {
})
}
+ pub fn set_mutation_observer_compound_microtask_queued(value: bool) {
+ SCRIPT_THREAD_ROOT.with(|root| {
+ let script_thread = unsafe { &*root.get().unwrap() };
+ script_thread.mutation_observer_compound_microtask_queued.set(value);
+ })
+ }
+
+ pub fn is_mutation_observer_compound_microtask_queued() -> bool {
+ SCRIPT_THREAD_ROOT.with(|root| {
+ let script_thread = unsafe { &*root.get().unwrap() };
+ return script_thread.mutation_observer_compound_microtask_queued.get();
+ })
+ }
+
pub fn add_mutation_observer(observer: &MutationObserver) {
SCRIPT_THREAD_ROOT.with(|root| {
let script_thread = unsafe { &*root.get().unwrap() };
@@ -596,6 +620,13 @@ impl ScriptThread {
})
}
+ pub fn get_mutation_observers() -> Vec<Root<MutationObserver>> {
+ SCRIPT_THREAD_ROOT.with(|root| {
+ let script_thread = unsafe { &*root.get().unwrap() };
+ script_thread.mutation_observers.borrow().iter().map(|o| Root::from_ref(&**o)).collect()
+ })
+ }
+
pub fn mark_document_with_no_blocked_loads(doc: &Document) {
SCRIPT_THREAD_ROOT.with(|root| {
let script_thread = unsafe { &*root.get().unwrap() };
@@ -669,7 +700,7 @@ impl ScriptThread {
}))
}
- pub fn find_window_proxy(id: FrameId) -> Option<Root<WindowProxy>> {
+ pub fn find_window_proxy(id: BrowsingContextId) -> Option<Root<WindowProxy>> {
SCRIPT_THREAD_ROOT.with(|root| root.get().and_then(|script_thread| {
let script_thread = unsafe { &*script_thread };
script_thread.window_proxies.borrow().get(&id)
@@ -677,6 +708,24 @@ impl ScriptThread {
}))
}
+ pub fn worklet_thread_pool() -> Rc<WorkletThreadPool> {
+ SCRIPT_THREAD_ROOT.with(|root| {
+ let script_thread = unsafe { &*root.get().unwrap() };
+ script_thread.worklet_thread_pool.borrow_mut().get_or_insert_with(|| {
+ let chan = script_thread.chan.0.clone();
+ let init = WorkletGlobalScopeInit {
+ resource_threads: script_thread.resource_threads.clone(),
+ mem_profiler_chan: script_thread.mem_profiler_chan.clone(),
+ time_profiler_chan: script_thread.time_profiler_chan.clone(),
+ devtools_chan: script_thread.devtools_chan.clone(),
+ constellation_chan: script_thread.constellation_chan.clone(),
+ scheduler_chan: script_thread.scheduler_chan.clone(),
+ };
+ Rc::new(WorkletThreadPool::spawn(chan, init))
+ }).clone()
+ })
+ }
+
/// Creates a new script thread.
pub fn new(state: InitialScriptState,
port: Receiver<MainThreadScriptMsg>,
@@ -748,12 +797,16 @@ impl ScriptThread {
microtask_queue: MicrotaskQueue::default(),
+ mutation_observer_compound_microtask_queued: Default::default(),
+
mutation_observers: Default::default(),
layout_to_constellation_chan: state.layout_to_constellation_chan,
webvr_thread: state.webvr_thread,
+ worklet_thread_pool: Default::default(),
+
docs_with_no_blocking_loads: Default::default(),
transitioning_nodes: Default::default(),
@@ -1037,6 +1090,7 @@ impl ScriptThread {
ScriptThreadEventCategory::WebSocketEvent => ProfilerCategory::ScriptWebSocketEvent,
ScriptThreadEventCategory::WebVREvent => ProfilerCategory::ScriptWebVREvent,
ScriptThreadEventCategory::WorkerEvent => ProfilerCategory::ScriptWorkerEvent,
+ ScriptThreadEventCategory::WorkletEvent => ProfilerCategory::ScriptWorkletEvent,
ScriptThreadEventCategory::ServiceWorkerEvent => ProfilerCategory::ScriptServiceWorkerEvent,
ScriptThreadEventCategory::EnterFullscreen => ProfilerCategory::ScriptEnterFullscreen,
ScriptThreadEventCategory::ExitFullscreen => ProfilerCategory::ScriptExitFullscreen,
@@ -1049,8 +1103,8 @@ impl ScriptThread {
fn handle_msg_from_constellation(&self, msg: ConstellationControlMsg) {
match msg {
- ConstellationControlMsg::Navigate(parent_pipeline_id, frame_id, load_data, replace) =>
- self.handle_navigate(parent_pipeline_id, Some(frame_id), load_data, replace),
+ ConstellationControlMsg::Navigate(parent_pipeline_id, browsing_context_id, load_data, replace) =>
+ self.handle_navigate(parent_pipeline_id, Some(browsing_context_id), load_data, replace),
ConstellationControlMsg::SendEvent(id, event) =>
self.handle_event(id, event),
ConstellationControlMsg::ResizeInactive(id, new_size) =>
@@ -1061,22 +1115,22 @@ impl ScriptThread {
self.handle_set_document_activity_msg(pipeline_id, activity),
ConstellationControlMsg::ChangeFrameVisibilityStatus(pipeline_id, visible) =>
self.handle_visibility_change_msg(pipeline_id, visible),
- ConstellationControlMsg::NotifyVisibilityChange(parent_pipeline_id, frame_id, visible) =>
- self.handle_visibility_change_complete_msg(parent_pipeline_id, frame_id, visible),
+ ConstellationControlMsg::NotifyVisibilityChange(parent_pipeline_id, browsing_context_id, visible) =>
+ self.handle_visibility_change_complete_msg(parent_pipeline_id, browsing_context_id, visible),
ConstellationControlMsg::PostMessage(pipeline_id, origin, data) =>
self.handle_post_message_msg(pipeline_id, origin, data),
ConstellationControlMsg::MozBrowserEvent(parent_pipeline_id,
- frame_id,
+ browsing_context_id,
event) =>
self.handle_mozbrowser_event_msg(parent_pipeline_id,
- frame_id,
+ browsing_context_id,
event),
ConstellationControlMsg::UpdatePipelineId(parent_pipeline_id,
- frame_id,
+ browsing_context_id,
new_pipeline_id,
reason) =>
self.handle_update_pipeline_id(parent_pipeline_id,
- frame_id,
+ browsing_context_id,
new_pipeline_id,
reason),
ConstellationControlMsg::FocusIFrame(parent_pipeline_id, frame_id) =>
@@ -1089,9 +1143,9 @@ impl ScriptThread {
self.handle_transition_event(unsafe_node, name, duration),
ConstellationControlMsg::WebFontLoaded(pipeline_id) =>
self.handle_web_font_loaded(pipeline_id),
- ConstellationControlMsg::DispatchFrameLoadEvent {
- target: frame_id, parent: parent_id, child: child_id } =>
- self.handle_frame_load_event(parent_id, frame_id, child_id),
+ ConstellationControlMsg::DispatchIFrameLoadEvent {
+ target: browsing_context_id, parent: parent_id, child: child_id } =>
+ self.handle_iframe_load_event(parent_id, browsing_context_id, child_id),
ConstellationControlMsg::DispatchStorageEvent(pipeline_id, storage, url, key, old_value, new_value) =>
self.handle_storage_event(pipeline_id, storage, url, key, old_value, new_value),
ConstellationControlMsg::ReportCSSError(pipeline_id, filename, line, column, msg) =>
@@ -1121,7 +1175,7 @@ impl ScriptThread {
// The category of the runnable is ignored by the pattern, however
// it is still respected by profiling (see categorize_msg).
if !runnable.is_cancelled() {
- runnable.handler()
+ runnable.main_thread_handler(self)
}
}
MainThreadScriptMsg::Common(CommonScriptMsg::CollectReports(reports_chan)) =>
@@ -1224,8 +1278,8 @@ impl ScriptThread {
webdriver_handlers::handle_get_rect(&*documents, pipeline_id, node_id, reply),
WebDriverScriptCommand::GetElementText(node_id, reply) =>
webdriver_handlers::handle_get_text(&*documents, pipeline_id, node_id, reply),
- WebDriverScriptCommand::GetFrameId(frame_id, reply) =>
- webdriver_handlers::handle_get_frame_id(&*documents, pipeline_id, frame_id, reply),
+ WebDriverScriptCommand::GetPipelineId(browsing_context_id, reply) =>
+ webdriver_handlers::handle_get_pipeline_id(&*documents, pipeline_id, browsing_context_id, reply),
WebDriverScriptCommand::GetUrl(reply) =>
webdriver_handlers::handle_get_url(&*documents, pipeline_id, reply),
WebDriverScriptCommand::IsEnabled(element_id, reply) =>
@@ -1292,7 +1346,7 @@ impl ScriptThread {
let NewLayoutInfo {
parent_info,
new_pipeline_id,
- frame_id,
+ browsing_context_id,
load_data,
window_size,
pipeline_port,
@@ -1328,7 +1382,7 @@ impl ScriptThread {
};
// Kick off the fetch for the new resource.
- let new_load = InProgressLoad::new(new_pipeline_id, frame_id, parent_info,
+ let new_load = InProgressLoad::new(new_pipeline_id, browsing_context_id, parent_info,
layout_chan, window_size,
load_data.url.clone(), origin);
if load_data.url.as_str() == "about:blank" {
@@ -1369,8 +1423,12 @@ impl ScriptThread {
}
/// Updates iframe element after a change in visibility
- fn handle_visibility_change_complete_msg(&self, parent_pipeline_id: PipelineId, id: FrameId, visible: bool) {
- let iframe = self.documents.borrow().find_iframe(parent_pipeline_id, id);
+ fn handle_visibility_change_complete_msg(&self,
+ parent_pipeline_id: PipelineId,
+ browsing_context_id: BrowsingContextId,
+ visible: bool)
+ {
+ let iframe = self.documents.borrow().find_iframe(parent_pipeline_id, browsing_context_id);
if let Some(iframe) = iframe {
iframe.change_visibility_status(visible);
}
@@ -1418,9 +1476,9 @@ impl ScriptThread {
fn handle_focus_iframe_msg(&self,
parent_pipeline_id: PipelineId,
- frame_id: FrameId) {
+ browsing_context_id: BrowsingContextId) {
let doc = self.documents.borrow().find_document(parent_pipeline_id).unwrap();
- let frame_element = doc.find_iframe(frame_id);
+ let frame_element = doc.find_iframe(browsing_context_id);
if let Some(ref frame_element) = frame_element {
doc.begin_focus_transaction();
@@ -1440,17 +1498,17 @@ impl ScriptThread {
/// https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowserloadstart
fn handle_mozbrowser_event_msg(&self,
parent_pipeline_id: PipelineId,
- frame_id: Option<FrameId>,
+ browsing_context_id: Option<BrowsingContextId>,
event: MozBrowserEvent) {
let doc = match { self.documents.borrow().find_document(parent_pipeline_id) } {
- None => return warn!("Mozbrowser event after pipeline {:?} closed.", parent_pipeline_id),
+ None => return warn!("Mozbrowser event after pipeline {} closed.", parent_pipeline_id),
Some(doc) => doc,
};
- match frame_id {
+ match browsing_context_id {
None => doc.window().dispatch_mozbrowser_event(event),
- Some(frame_id) => match doc.find_iframe(frame_id) {
- None => warn!("Mozbrowser event after iframe {:?}/{:?} closed.", parent_pipeline_id, frame_id),
+ Some(browsing_context_id) => match doc.find_iframe(browsing_context_id) {
+ None => warn!("Mozbrowser event after iframe {}/{} closed.", parent_pipeline_id, browsing_context_id),
Some(frame_element) => frame_element.dispatch_mozbrowser_event(event),
},
}
@@ -1458,10 +1516,10 @@ impl ScriptThread {
fn handle_update_pipeline_id(&self,
parent_pipeline_id: PipelineId,
- frame_id: FrameId,
+ browsing_context_id: BrowsingContextId,
new_pipeline_id: PipelineId,
reason: UpdatePipelineIdReason) {
- let frame_element = self.documents.borrow().find_iframe(parent_pipeline_id, frame_id);
+ let frame_element = self.documents.borrow().find_iframe(parent_pipeline_id, browsing_context_id);
if let Some(frame_element) = frame_element {
frame_element.update_pipeline_id(new_pipeline_id, reason);
}
@@ -1690,18 +1748,22 @@ impl ScriptThread {
storage.queue_storage_event(url, key, old_value, new_value);
}
- /// Notify the containing document of a child frame that has completed loading.
- fn handle_frame_load_event(&self, parent_id: PipelineId, frame_id: FrameId, child_id: PipelineId) {
- let iframe = self.documents.borrow().find_iframe(parent_id, frame_id);
+ /// Notify the containing document of a child iframe that has completed loading.
+ fn handle_iframe_load_event(&self,
+ parent_id: PipelineId,
+ browsing_context_id: BrowsingContextId,
+ child_id: PipelineId)
+ {
+ let iframe = self.documents.borrow().find_iframe(parent_id, browsing_context_id);
match iframe {
Some(iframe) => iframe.iframe_load_event_steps(child_id),
None => warn!("Message sent to closed pipeline {}.", parent_id),
}
}
- fn ask_constellation_for_frame_id(&self, pipeline_id: PipelineId) -> Option<FrameId> {
+ fn ask_constellation_for_browsing_context_id(&self, pipeline_id: PipelineId) -> Option<BrowsingContextId> {
let (result_sender, result_receiver) = ipc::channel().unwrap();
- let msg = ConstellationMsg::GetFrameId(pipeline_id, result_sender);
+ let msg = ConstellationMsg::GetBrowsingContextId(pipeline_id, result_sender);
self.constellation_chan.send(msg).expect("Failed to send to constellation.");
result_receiver.recv().expect("Failed to get frame id from constellation.")
}
@@ -1724,19 +1786,19 @@ impl ScriptThread {
pipeline_id: PipelineId)
-> Option<Root<WindowProxy>>
{
- let frame_id = match self.ask_constellation_for_frame_id(pipeline_id) {
- Some(frame_id) => frame_id,
+ let browsing_context_id = match self.ask_constellation_for_browsing_context_id(pipeline_id) {
+ Some(browsing_context_id) => browsing_context_id,
None => return None,
};
- if let Some(window_proxy) = self.window_proxies.borrow().get(&frame_id) {
+ if let Some(window_proxy) = self.window_proxies.borrow().get(&browsing_context_id) {
return Some(Root::from_ref(window_proxy));
}
let parent = match self.ask_constellation_for_parent_info(pipeline_id) {
Some((parent_id, FrameType::IFrame)) => self.remote_window_proxy(global_to_clone, parent_id),
_ => None,
};
- let window_proxy = WindowProxy::new_dissimilar_origin(global_to_clone, frame_id, parent.r());
- self.window_proxies.borrow_mut().insert(frame_id, JS::from_ref(&*window_proxy));
+ let window_proxy = WindowProxy::new_dissimilar_origin(global_to_clone, browsing_context_id, parent.r());
+ self.window_proxies.borrow_mut().insert(browsing_context_id, JS::from_ref(&*window_proxy));
Some(window_proxy)
}
@@ -1748,16 +1810,16 @@ impl ScriptThread {
// to the `window_proxies` map, and return it.
fn local_window_proxy(&self,
window: &Window,
- frame_id: FrameId,
+ browsing_context_id: BrowsingContextId,
parent_info: Option<(PipelineId, FrameType)>)
-> Root<WindowProxy>
{
- if let Some(window_proxy) = self.window_proxies.borrow().get(&frame_id) {
+ if let Some(window_proxy) = self.window_proxies.borrow().get(&browsing_context_id) {
window_proxy.set_currently_active(&*window);
return Root::from_ref(window_proxy);
}
let iframe = match parent_info {
- Some((parent_id, FrameType::IFrame)) => self.documents.borrow().find_iframe(parent_id, frame_id),
+ Some((parent_id, FrameType::IFrame)) => self.documents.borrow().find_iframe(parent_id, browsing_context_id),
_ => None,
};
let parent = match (parent_info, iframe.as_ref()) {
@@ -1765,8 +1827,8 @@ impl ScriptThread {
(Some((parent_id, FrameType::IFrame)), _) => self.remote_window_proxy(window.upcast(), parent_id),
_ => None,
};
- let window_proxy = WindowProxy::new(&window, frame_id, iframe.r().map(Castable::upcast), parent.r());
- self.window_proxies.borrow_mut().insert(frame_id, JS::from_ref(&*window_proxy));
+ let window_proxy = WindowProxy::new(&window, browsing_context_id, iframe.r().map(Castable::upcast), parent.r());
+ self.window_proxies.borrow_mut().insert(browsing_context_id, JS::from_ref(&*window_proxy));
window_proxy
}
@@ -1823,7 +1885,7 @@ impl ScriptThread {
self.webvr_thread.clone());
// Initialize the browsing context for the window.
- let window_proxy = self.local_window_proxy(&window, incomplete.frame_id, incomplete.parent_info);
+ let window_proxy = self.local_window_proxy(&window, incomplete.browsing_context_id, incomplete.parent_info);
window.init_window_proxy(&window_proxy);
let last_modified = metadata.headers.as_ref().and_then(|headers| {
@@ -2093,12 +2155,12 @@ impl ScriptThread {
/// The entry point for content to notify that a new load has been requested
/// for the given pipeline (specifically the "navigate" algorithm).
fn handle_navigate(&self, parent_pipeline_id: PipelineId,
- frame_id: Option<FrameId>,
+ browsing_context_id: Option<BrowsingContextId>,
load_data: LoadData,
replace: bool) {
- match frame_id {
- Some(frame_id) => {
- let iframe = self.documents.borrow().find_iframe(parent_pipeline_id, frame_id);
+ match browsing_context_id {
+ Some(browsing_context_id) => {
+ let iframe = self.documents.borrow().find_iframe(parent_pipeline_id, browsing_context_id);
if let Some(iframe) = iframe {
iframe.navigate_or_reload_child_browsing_context(Some(load_data), NavigationType::Regular, replace);
}
diff --git a/components/script/webdriver_handlers.rs b/components/script/webdriver_handlers.rs
index 7e7fe95122b..7bc31263c25 100644
--- a/components/script/webdriver_handlers.rs
+++ b/components/script/webdriver_handlers.rs
@@ -109,10 +109,10 @@ pub fn handle_execute_async_script(documents: &Documents,
window.upcast::<GlobalScope>().evaluate_js_on_global_with_result(&eval, rval.handle_mut());
}
-pub fn handle_get_frame_id(documents: &Documents,
- pipeline: PipelineId,
- webdriver_frame_id: WebDriverFrameId,
- reply: IpcSender<Result<Option<PipelineId>, ()>>) {
+pub fn handle_get_pipeline_id(documents: &Documents,
+ pipeline: PipelineId,
+ webdriver_frame_id: WebDriverFrameId,
+ reply: IpcSender<Result<Option<PipelineId>, ()>>) {
let result = match webdriver_frame_id {
WebDriverFrameId::Short(_) => {
// This isn't supported yet
diff --git a/components/script_layout_interface/wrapper_traits.rs b/components/script_layout_interface/wrapper_traits.rs
index 9219f1e4b09..40b719f6dbd 100644
--- a/components/script_layout_interface/wrapper_traits.rs
+++ b/components/script_layout_interface/wrapper_traits.rs
@@ -11,16 +11,16 @@ use SVGSVGData;
use atomic_refcell::AtomicRefCell;
use gfx_traits::{ByteIndex, FragmentType, combine_id_with_fragment_type};
use html5ever::{Namespace, LocalName};
-use msg::constellation_msg::{FrameId, PipelineId};
+use msg::constellation_msg::{BrowsingContextId, PipelineId};
use range::Range;
use servo_url::ServoUrl;
use std::fmt::Debug;
+use style::attr::AttrValue;
use style::computed_values::display;
use style::context::SharedStyleContext;
use style::data::ElementData;
use style::dom::{LayoutIterator, NodeInfo, PresentationalHintsSynthesizer, TNode};
use style::dom::OpaqueNode;
-use style::element_state::ElementState;
use style::font_metrics::ServoMetricsProvider;
use style::properties::{CascadeFlags, ServoComputedValues};
use style::selector_parser::{PseudoElement, PseudoElementCascadeType, SelectorImpl};
@@ -272,9 +272,9 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + Debug + GetLayoutData + NodeInfo
fn svg_data(&self) -> Option<SVGSVGData>;
- /// If this node is an iframe element, returns its frame ID. If this node is
+ /// If this node is an iframe element, returns its browsing context ID. If this node is
/// not an iframe element, fails.
- fn iframe_frame_id(&self) -> FrameId;
+ fn iframe_browsing_context_id(&self) -> BrowsingContextId;
/// If this node is an iframe element, returns its pipeline ID. If this node is
/// not an iframe element, fails.
@@ -336,6 +336,8 @@ pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + Debug +
#[inline]
fn get_attr(&self, namespace: &Namespace, name: &LocalName) -> Option<&str>;
+ fn get_attr_enum(&self, namespace: &Namespace, name: &LocalName) -> Option<&AttrValue>;
+
fn get_style_data(&self) -> Option<&AtomicRefCell<ElementData>>;
#[inline]
@@ -435,7 +437,6 @@ pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + Debug +
&context.guards,
unsafe { &self.unsafe_get() },
&style_pseudo,
- ElementState::empty(),
data.styles().primary.values(),
&ServoMetricsProvider);
data.styles_mut().cached_pseudos
diff --git a/components/script_traits/Cargo.toml b/components/script_traits/Cargo.toml
index da5fcc78704..993c14c43b0 100644
--- a/components/script_traits/Cargo.toml
+++ b/components/script_traits/Cargo.toml
@@ -10,7 +10,6 @@ name = "script_traits"
path = "lib.rs"
[dependencies]
-app_units = "0.4"
bluetooth_traits = {path = "../bluetooth_traits"}
canvas_traits = {path = "../canvas_traits"}
cookie = "0.6"
diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs
index bfc1e63fcc8..889a06e5cb3 100644
--- a/components/script_traits/lib.rs
+++ b/components/script_traits/lib.rs
@@ -53,7 +53,7 @@ use hyper::header::Headers;
use hyper::method::Method;
use ipc_channel::ipc::{IpcReceiver, IpcSender};
use libc::c_void;
-use msg::constellation_msg::{FrameId, FrameType, Key, KeyModifiers, KeyState};
+use msg::constellation_msg::{BrowsingContextId, FrameType, Key, KeyModifiers, KeyState};
use msg::constellation_msg::{PipelineId, PipelineNamespaceId, TraversalDirection};
use net_traits::{ReferrerPolicy, ResourceThreads};
use net_traits::image::base::Image;
@@ -179,8 +179,8 @@ pub struct NewLayoutInfo {
pub parent_info: Option<(PipelineId, FrameType)>,
/// Id of the newly-created pipeline.
pub new_pipeline_id: PipelineId,
- /// Id of the frame associated with this pipeline.
- pub frame_id: FrameId,
+ /// Id of the browsing context associated with this pipeline.
+ pub browsing_context_id: BrowsingContextId,
/// Network request data which will be initiated by the script thread.
pub load_data: LoadData,
/// Information about the initial window size.
@@ -253,22 +253,22 @@ pub enum ConstellationControlMsg {
/// Notifies script thread whether frame is visible
ChangeFrameVisibilityStatus(PipelineId, bool),
/// Notifies script thread that frame visibility change is complete
- /// PipelineId is for the parent, FrameId is for the actual frame.
- NotifyVisibilityChange(PipelineId, FrameId, bool),
+ /// PipelineId is for the parent, BrowsingContextId is for the nested browsing context
+ NotifyVisibilityChange(PipelineId, BrowsingContextId, bool),
/// Notifies script thread that a url should be loaded in this iframe.
- /// PipelineId is for the parent, FrameId is for the actual frame.
- Navigate(PipelineId, FrameId, LoadData, bool),
+ /// PipelineId is for the parent, BrowsingContextId is for the nested browsing context
+ Navigate(PipelineId, BrowsingContextId, LoadData, bool),
/// Post a message to a given window.
PostMessage(PipelineId, Option<ImmutableOrigin>, Vec<u8>),
/// Requests the script thread forward a mozbrowser event to an iframe it owns,
- /// or to the window if no child frame id is provided.
- MozBrowserEvent(PipelineId, Option<FrameId>, MozBrowserEvent),
+ /// or to the window if no browsing context id is provided.
+ MozBrowserEvent(PipelineId, Option<BrowsingContextId>, MozBrowserEvent),
/// Updates the current pipeline ID of a given iframe.
/// First PipelineId is for the parent, second is the new PipelineId for the frame.
- UpdatePipelineId(PipelineId, FrameId, PipelineId, UpdatePipelineIdReason),
+ UpdatePipelineId(PipelineId, BrowsingContextId, PipelineId, UpdatePipelineIdReason),
/// Set an iframe to be focused. Used when an element in an iframe gains focus.
- /// PipelineId is for the parent, FrameId is for the actual frame.
- FocusIFrame(PipelineId, FrameId),
+ /// PipelineId is for the parent, BrowsingContextId is for the nested browsing context
+ FocusIFrame(PipelineId, BrowsingContextId),
/// Passes a webdriver command to the script thread for execution
WebDriverScriptCommand(PipelineId, WebDriverScriptCommand),
/// Notifies script thread that all animations are done
@@ -278,10 +278,10 @@ pub enum ConstellationControlMsg {
/// Notifies the script thread that a new Web font has been loaded, and thus the page should be
/// reflowed.
WebFontLoaded(PipelineId),
- /// Cause a `load` event to be dispatched at the appropriate frame element.
- DispatchFrameLoadEvent {
+ /// Cause a `load` event to be dispatched at the appropriate iframe element.
+ DispatchIFrameLoadEvent {
/// The frame that has been marked as loaded.
- target: FrameId,
+ target: BrowsingContextId,
/// The pipeline that contains a frame loading the target pipeline.
parent: PipelineId,
/// The pipeline that has completed loading.
@@ -323,7 +323,7 @@ impl fmt::Debug for ConstellationControlMsg {
TickAllAnimations(..) => "TickAllAnimations",
TransitionEnd(..) => "TransitionEnd",
WebFontLoaded(..) => "WebFontLoaded",
- DispatchFrameLoadEvent { .. } => "DispatchFrameLoadEvent",
+ DispatchIFrameLoadEvent { .. } => "DispatchIFrameLoadEvent",
DispatchStorageEvent(..) => "DispatchStorageEvent",
ReportCSSError(..) => "ReportCSSError",
Reload(..) => "Reload",
@@ -489,9 +489,9 @@ pub struct InitialScriptState {
/// If `None`, this is the root.
pub parent_info: Option<(PipelineId, FrameType)>,
/// The ID of the frame this script is part of.
- pub frame_id: FrameId,
+ pub browsing_context_id: BrowsingContextId,
/// The ID of the top-level frame this script is part of.
- pub top_level_frame_id: FrameId,
+ pub top_level_browsing_context_id: BrowsingContextId,
/// A channel with which messages can be sent to us (the script thread).
pub control_chan: IpcSender<ConstellationControlMsg>,
/// A port on which messages sent by the constellation to script can be received.
@@ -549,7 +549,7 @@ pub struct IFrameLoadInfo {
/// Pipeline ID of the parent of this iframe
pub parent_pipeline_id: PipelineId,
/// The ID for this iframe.
- pub frame_id: FrameId,
+ pub browsing_context_id: BrowsingContextId,
/// The new pipeline ID that the iframe has generated.
pub new_pipeline_id: PipelineId,
/// Whether this iframe should be considered private
@@ -732,13 +732,13 @@ pub enum WebDriverCommandMsg {
pub enum ConstellationMsg {
/// Exit the constellation.
Exit,
- /// Request that the constellation send the FrameId corresponding to the document
+ /// Request that the constellation send the BrowsingContextId corresponding to the document
/// with the provided pipeline id
- GetFrame(PipelineId, IpcSender<Option<FrameId>>),
+ GetBrowsingContext(PipelineId, IpcSender<Option<BrowsingContextId>>),
/// Request that the constellation send the current pipeline id for the provided frame
/// id, or for the root frame if this is None, over a provided channel.
/// Also returns a boolean saying whether the document has finished loading or not.
- GetPipeline(Option<FrameId>, IpcSender<Option<PipelineId>>),
+ GetPipeline(Option<BrowsingContextId>, IpcSender<Option<PipelineId>>),
/// Requests that the constellation inform the compositor of the title of the pipeline
/// immediately.
GetPipelineTitle(PipelineId),
@@ -760,8 +760,8 @@ pub enum ConstellationMsg {
WebDriverCommand(WebDriverCommandMsg),
/// Reload the current page.
Reload,
- /// A log entry, with the top-level frame id and thread name
- LogEntry(Option<FrameId>, Option<String>, LogEntry),
+ /// A log entry, with the top-level browsing context id and thread name
+ LogEntry(Option<BrowsingContextId>, Option<String>, LogEntry),
/// Set the WebVR thread channel.
SetWebVRThread(IpcSender<WebVRMsg>),
/// Dispatch WebVR events to the subscribed script threads.
diff --git a/components/script_traits/script_msg.rs b/components/script_traits/script_msg.rs
index 0402e3ddad6..d34f2feeb5f 100644
--- a/components/script_traits/script_msg.rs
+++ b/components/script_traits/script_msg.rs
@@ -17,7 +17,7 @@ use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId};
use euclid::point::Point2D;
use euclid::size::{Size2D, TypedSize2D};
use ipc_channel::ipc::IpcSender;
-use msg::constellation_msg::{FrameId, FrameType, PipelineId, TraversalDirection};
+use msg::constellation_msg::{BrowsingContextId, FrameType, PipelineId, TraversalDirection};
use msg::constellation_msg::{Key, KeyModifiers, KeyState};
use net_traits::CoreResourceMsg;
use net_traits::storage_thread::StorageType;
@@ -34,8 +34,8 @@ use webrender_traits::ClipId;
pub enum LayoutMsg {
/// Indicates whether this pipeline is currently running animations.
ChangeRunningAnimationsState(PipelineId, AnimationState),
- /// Inform the constellation of the size of the frame's viewport.
- FrameSizes(Vec<(FrameId, TypedSize2D<f32, CSSPixel>)>),
+ /// Inform the constellation of the size of the iframe's viewport.
+ IFrameSizes(Vec<(BrowsingContextId, TypedSize2D<f32, CSSPixel>)>),
/// Requests that the constellation inform the compositor of the a cursor change.
SetCursor(Cursor),
/// Notifies the constellation that the viewport has been constrained in some manner
@@ -87,7 +87,7 @@ pub enum ScriptMsg {
/// Requests that the constellation retrieve the current contents of the clipboard
GetClipboardContents(IpcSender<String>),
/// Get the frame id for a given pipeline.
- GetFrameId(PipelineId, IpcSender<Option<FrameId>>),
+ GetBrowsingContextId(PipelineId, IpcSender<Option<BrowsingContextId>>),
/// Get the parent info for a given pipeline.
GetParentInfo(PipelineId, IpcSender<Option<(PipelineId, FrameType)>>),
/// <head> tag finished parsing
@@ -99,7 +99,7 @@ pub enum ScriptMsg {
/// instead of adding a new entry.
LoadUrl(PipelineId, LoadData, bool),
/// Post a message to the currently active window of a given browsing context.
- PostMessage(FrameId, Option<ImmutableOrigin>, Vec<u8>),
+ PostMessage(BrowsingContextId, Option<ImmutableOrigin>, Vec<u8>),
/// Dispatch a mozbrowser event to the parent of this pipeline.
/// The first PipelineId is for the parent, the second is for the originating pipeline.
MozBrowserEvent(PipelineId, PipelineId, MozBrowserEvent),
@@ -113,7 +113,7 @@ pub enum ScriptMsg {
NodeStatus(Option<String>),
/// Notification that this iframe should be removed.
/// Returns a list of pipelines which were closed.
- RemoveIFrame(FrameId, IpcSender<Vec<PipelineId>>),
+ RemoveIFrame(BrowsingContextId, IpcSender<Vec<PipelineId>>),
/// Change pipeline visibility
SetVisible(PipelineId, bool),
/// Notifies constellation that an iframe's visibility has been changed.
@@ -147,8 +147,8 @@ pub enum ScriptMsg {
ResizeTo(Size2D<u32>),
/// Script has handled a touch event, and either prevented or allowed default actions.
TouchEventProcessed(EventResult),
- /// A log entry, with the top-level frame id and thread name
- LogEntry(Option<FrameId>, Option<String>, LogEntry),
+ /// A log entry, with the top-level browsing context id and thread name
+ LogEntry(Option<BrowsingContextId>, Option<String>, LogEntry),
/// Notifies the constellation that this pipeline has exited.
PipelineExited(PipelineId),
/// Send messages from postMessage calls from serviceworker
diff --git a/components/script_traits/webdriver_msg.rs b/components/script_traits/webdriver_msg.rs
index c09f1f19dae..b92e32ff65c 100644
--- a/components/script_traits/webdriver_msg.rs
+++ b/components/script_traits/webdriver_msg.rs
@@ -31,7 +31,7 @@ pub enum WebDriverScriptCommand {
GetElementRect(String, IpcSender<Result<Rect<f64>, ()>>),
GetElementTagName(String, IpcSender<Result<String, ()>>),
GetElementText(String, IpcSender<Result<String, ()>>),
- GetFrameId(WebDriverFrameId, IpcSender<Result<Option<PipelineId>, ()>>),
+ GetPipelineId(WebDriverFrameId, IpcSender<Result<Option<PipelineId>, ()>>),
GetUrl(IpcSender<ServoUrl>),
IsEnabled(String, IpcSender<Result<bool, ()>>),
IsSelected(String, IpcSender<Result<bool, ()>>),
diff --git a/components/selectors/Cargo.toml b/components/selectors/Cargo.toml
index ceef176eae1..4ca9a240c67 100644
--- a/components/selectors/Cargo.toml
+++ b/components/selectors/Cargo.toml
@@ -10,6 +10,7 @@ repository = "https://github.com/servo/servo"
readme = "README.md"
keywords = ["css", "selectors"]
license = "MPL-2.0"
+build = "build.rs"
[lib]
name = "selectors"
@@ -25,8 +26,12 @@ bitflags = "0.7"
matches = "0.1"
cssparser = "0.13.3"
fnv = "1.0"
+phf = "0.7.18"
precomputed-hash = "0.1"
smallvec = "0.3"
[dev-dependencies]
size_of_test = {path = "../size_of_test"}
+
+[build-dependencies]
+phf_codegen = "0.7.18"
diff --git a/components/selectors/attr.rs b/components/selectors/attr.rs
new file mode 100644
index 00000000000..274081ae9f7
--- /dev/null
+++ b/components/selectors/attr.rs
@@ -0,0 +1,190 @@
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+use cssparser::ToCss;
+use parser::SelectorImpl;
+use std::ascii::AsciiExt;
+use std::fmt;
+
+#[derive(Eq, PartialEq, Clone)]
+pub struct AttrSelectorWithNamespace<Impl: SelectorImpl> {
+ pub namespace: NamespaceConstraint<(Impl::NamespacePrefix, Impl::NamespaceUrl)>,
+ pub local_name: Impl::LocalName,
+ pub local_name_lower: Impl::LocalName,
+ pub operation: ParsedAttrSelectorOperation<Impl::AttrValue>,
+ pub never_matches: bool,
+}
+
+impl<Impl: SelectorImpl> AttrSelectorWithNamespace<Impl> {
+ pub fn namespace(&self) -> NamespaceConstraint<&Impl::NamespaceUrl> {
+ match self.namespace {
+ NamespaceConstraint::Any => NamespaceConstraint::Any,
+ NamespaceConstraint::Specific((_, ref url)) => {
+ NamespaceConstraint::Specific(url)
+ }
+ }
+ }
+}
+
+#[derive(Eq, PartialEq, Clone)]
+pub enum NamespaceConstraint<NamespaceUrl> {
+ Any,
+
+ /// Empty string for no namespace
+ Specific(NamespaceUrl),
+}
+
+#[derive(Eq, PartialEq, Clone)]
+pub enum ParsedAttrSelectorOperation<AttrValue> {
+ Exists,
+ WithValue {
+ operator: AttrSelectorOperator,
+ case_sensitivity: ParsedCaseSensitivity,
+ expected_value: AttrValue,
+ }
+}
+
+#[derive(Eq, PartialEq, Clone)]
+pub enum AttrSelectorOperation<AttrValue> {
+ Exists,
+ WithValue {
+ operator: AttrSelectorOperator,
+ case_sensitivity: CaseSensitivity,
+ expected_value: AttrValue,
+ }
+}
+
+impl<AttrValue> AttrSelectorOperation<AttrValue> {
+ pub fn eval_str(&self, element_attr_value: &str) -> bool where AttrValue: AsRef<str> {
+ match *self {
+ AttrSelectorOperation::Exists => true,
+ AttrSelectorOperation::WithValue { operator, case_sensitivity, ref expected_value } => {
+ operator.eval_str(element_attr_value, expected_value.as_ref(), case_sensitivity)
+ }
+ }
+ }
+}
+
+#[derive(Eq, PartialEq, Clone, Copy)]
+pub enum AttrSelectorOperator {
+ Equal,
+ Includes,
+ DashMatch,
+ Prefix,
+ Substring,
+ Suffix,
+}
+
+impl ToCss for AttrSelectorOperator {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ dest.write_str(match *self {
+ AttrSelectorOperator::Equal => " = ",
+ AttrSelectorOperator::Includes => " ~= ",
+ AttrSelectorOperator::DashMatch => " |= ",
+ AttrSelectorOperator::Prefix => " ^= ",
+ AttrSelectorOperator::Substring => " *= ",
+ AttrSelectorOperator::Suffix => " $= ",
+ })
+ }
+}
+
+impl AttrSelectorOperator {
+ pub fn eval_str(self, element_attr_value: &str, attr_selector_value: &str,
+ case_sensitivity: CaseSensitivity) -> bool {
+ let e = element_attr_value.as_bytes();
+ let s = attr_selector_value.as_bytes();
+ let case = case_sensitivity;
+ match self {
+ AttrSelectorOperator::Equal => {
+ case.eq(e, s)
+ }
+ AttrSelectorOperator::Prefix => {
+ e.len() >= s.len() && case.eq(&e[..s.len()], s)
+ }
+ AttrSelectorOperator::Suffix => {
+ e.len() >= s.len() && case.eq(&e[(e.len() - s.len())..], s)
+ }
+ AttrSelectorOperator::Substring => {
+ case.contains(element_attr_value, attr_selector_value)
+ }
+ AttrSelectorOperator::Includes => {
+ element_attr_value.split(SELECTOR_WHITESPACE)
+ .any(|part| case.eq(part.as_bytes(), s))
+ }
+ AttrSelectorOperator::DashMatch => {
+ case.eq(e, s) || (
+ e.get(s.len()) == Some(&b'-') &&
+ case.eq(&e[..s.len()], s)
+ )
+ }
+ }
+ }
+}
+
+/// The definition of whitespace per CSS Selectors Level 3 § 4.
+pub static SELECTOR_WHITESPACE: &'static [char] = &[' ', '\t', '\n', '\r', '\x0C'];
+
+#[derive(Eq, PartialEq, Clone, Copy, Debug)]
+pub enum ParsedCaseSensitivity {
+ CaseSensitive, // Selectors spec says language-defined, but HTML says sensitive.
+ AsciiCaseInsensitive,
+ AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument,
+}
+
+impl ParsedCaseSensitivity {
+ pub fn to_unconditional(self, is_html_element_in_html_document: bool) -> CaseSensitivity {
+ match self {
+ ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument
+ if is_html_element_in_html_document => {
+ CaseSensitivity::AsciiCaseInsensitive
+ }
+ ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument => {
+ CaseSensitivity::CaseSensitive
+ }
+ ParsedCaseSensitivity::CaseSensitive => CaseSensitivity::CaseSensitive,
+ ParsedCaseSensitivity::AsciiCaseInsensitive => CaseSensitivity::AsciiCaseInsensitive,
+ }
+ }
+}
+
+#[derive(Eq, PartialEq, Clone, Copy, Debug)]
+pub enum CaseSensitivity {
+ CaseSensitive, // Selectors spec says language-defined, but HTML says sensitive.
+ AsciiCaseInsensitive,
+}
+
+impl CaseSensitivity {
+ pub fn eq(self, a: &[u8], b: &[u8]) -> bool {
+ match self {
+ CaseSensitivity::CaseSensitive => a == b,
+ CaseSensitivity::AsciiCaseInsensitive => a.eq_ignore_ascii_case(b),
+ }
+ }
+
+ pub fn contains(self, haystack: &str, needle: &str) -> bool {
+ match self {
+ CaseSensitivity::CaseSensitive => haystack.contains(needle),
+ CaseSensitivity::AsciiCaseInsensitive => {
+ if let Some((&n_first_byte, n_rest)) = needle.as_bytes().split_first() {
+ haystack.bytes().enumerate().any(|(i, byte)| {
+ if !byte.eq_ignore_ascii_case(&n_first_byte) {
+ return false
+ }
+ let after_this_byte = &haystack.as_bytes()[i + 1..];
+ match after_this_byte.get(..n_rest.len()) {
+ None => false,
+ Some(haystack_slice) => {
+ haystack_slice.eq_ignore_ascii_case(n_rest)
+ }
+ }
+ })
+ } else {
+ // any_str.contains("") == true,
+ // though these cases should be handled with *NeverMatches and never go here.
+ true
+ }
+ }
+ }
+ }
+}
diff --git a/components/selectors/build.rs b/components/selectors/build.rs
new file mode 100644
index 00000000000..0d0a40256f3
--- /dev/null
+++ b/components/selectors/build.rs
@@ -0,0 +1,75 @@
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+extern crate phf_codegen;
+
+use std::env;
+use std::fs::File;
+use std::io::{BufWriter, Write};
+use std::path::Path;
+
+fn main() {
+ let path = Path::new(&env::var("OUT_DIR").unwrap())
+ .join("ascii_case_insensitive_html_attributes.rs");
+ let mut file = BufWriter::new(File::create(&path).unwrap());
+
+ write!(&mut file, "{{ static SET: ::phf::Set<&'static str> = ",
+ ).unwrap();
+ let mut set = phf_codegen::Set::new();
+ for name in ASCII_CASE_INSENSITIVE_HTML_ATTRIBUTES.split_whitespace() {
+ set.entry(name);
+ }
+ set.build(&mut file).unwrap();
+ write!(&mut file, "; &SET }}").unwrap();
+}
+
+/// https://html.spec.whatwg.org/multipage/#selectors
+static ASCII_CASE_INSENSITIVE_HTML_ATTRIBUTES: &'static str = r#"
+ accept
+ accept-charset
+ align
+ alink
+ axis
+ bgcolor
+ charset
+ checked
+ clear
+ codetype
+ color
+ compact
+ declare
+ defer
+ dir
+ direction
+ disabled
+ enctype
+ face
+ frame
+ hreflang
+ http-equiv
+ lang
+ language
+ link
+ media
+ method
+ multiple
+ nohref
+ noresize
+ noshade
+ nowrap
+ readonly
+ rel
+ rev
+ rules
+ scope
+ scrolling
+ selected
+ shape
+ target
+ text
+ type
+ valign
+ valuetype
+ vlink
+"#;
diff --git a/components/selectors/gecko_like_types.rs b/components/selectors/gecko_like_types.rs
index bbb78823c50..9ffffaf2aed 100644
--- a/components/selectors/gecko_like_types.rs
+++ b/components/selectors/gecko_like_types.rs
@@ -19,9 +19,6 @@ pub enum PseudoElement {
B,
}
-#[derive(Eq, PartialEq, Clone, Debug)]
-pub struct PseudoElementSelector(PseudoElement, u64);
-
#[derive(Eq, PartialEq, Clone, Debug, Default)]
pub struct Atom(usize);
diff --git a/components/selectors/lib.rs b/components/selectors/lib.rs
index d352d2f1d3c..3e413c0c08b 100644
--- a/components/selectors/lib.rs
+++ b/components/selectors/lib.rs
@@ -6,11 +6,13 @@
#[macro_use] extern crate cssparser;
#[macro_use] extern crate matches;
extern crate fnv;
+extern crate phf;
extern crate precomputed_hash;
#[cfg(test)] #[macro_use] extern crate size_of_test;
extern crate smallvec;
pub mod arcslice;
+pub mod attr;
pub mod bloom;
pub mod matching;
pub mod parser;
@@ -21,4 +23,3 @@ pub mod visitor;
pub use parser::{SelectorImpl, Parser, SelectorList};
pub use tree::Element;
-pub use tree::{MatchAttr, MatchAttrGeneric};
diff --git a/components/selectors/matching.rs b/components/selectors/matching.rs
index ada15089061..50b686f2558 100644
--- a/components/selectors/matching.rs
+++ b/components/selectors/matching.rs
@@ -1,8 +1,10 @@
/* 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 http://mozilla.org/MPL/2.0/. */
+
+use attr::{ParsedAttrSelectorOperation, AttrSelectorOperation, NamespaceConstraint};
use bloom::BloomFilter;
-use parser::{CaseSensitivity, Combinator, ComplexSelector, Component, LocalName};
+use parser::{Combinator, ComplexSelector, Component, LocalName};
use parser::{Selector, SelectorInner, SelectorIter};
use std::borrow::Borrow;
use tree::Element;
@@ -17,6 +19,7 @@ bitflags! {
/// the selector matching process.
///
/// This is used to implement efficient sharing.
+ #[derive(Default)]
pub flags StyleRelations: usize {
/// Whether this element is affected by an ID selector.
const AFFECTED_BY_ID_SELECTOR = 1 << 0,
@@ -68,18 +71,67 @@ impl ElementSelectorFlags {
}
}
+/// What kind of selector matching mode we should use.
+///
+/// There are two modes of selector matching. The difference is only noticeable
+/// in presence of pseudo-elements.
+#[derive(Debug, PartialEq)]
+pub enum MatchingMode {
+ /// Don't ignore any pseudo-element selectors.
+ Normal,
+
+ /// Ignores any stateless pseudo-element selectors in the rightmost sequence
+ /// of simple selectors.
+ ///
+ /// This is useful, for example, to match against ::before when you aren't a
+ /// pseudo-element yourself.
+ ///
+ /// For example, in presence of `::before:hover`, it would never match, but
+ /// `::before` would be ignored as in "matching".
+ ///
+ /// It's required for all the selectors you match using this mode to have a
+ /// pseudo-element.
+ ForStatelessPseudoElement,
+}
+
+
+/// Data associated with the matching process for a element. This context is
+/// used across many selectors for an element, so it's not appropriate for
+/// transient data that applies to only a single selector.
+pub struct MatchingContext<'a> {
+ /// Output that records certains relations between elements noticed during
+ /// matching (and also extended after matching).
+ pub relations: StyleRelations,
+ /// The matching mode we should use when matching selectors.
+ pub matching_mode: MatchingMode,
+ /// The bloom filter used to fast-reject selectors.
+ pub bloom_filter: Option<&'a BloomFilter>,
+}
+
+impl<'a> MatchingContext<'a> {
+ /// Constructs a new `MatchingContext`.
+ pub fn new(matching_mode: MatchingMode,
+ bloom_filter: Option<&'a BloomFilter>)
+ -> Self
+ {
+ Self {
+ relations: StyleRelations::empty(),
+ matching_mode: matching_mode,
+ bloom_filter: bloom_filter,
+ }
+ }
+}
+
pub fn matches_selector_list<E>(selector_list: &[Selector<E::Impl>],
element: &E,
- parent_bf: Option<&BloomFilter>)
+ context: &mut MatchingContext)
-> bool
where E: Element
{
selector_list.iter().any(|selector| {
- selector.pseudo_element.is_none() &&
matches_selector(&selector.inner,
element,
- parent_bf,
- &mut StyleRelations::empty(),
+ context,
&mut |_, _| {})
})
}
@@ -104,27 +156,6 @@ fn may_match<E>(sel: &SelectorInner<E::Impl>,
true
}
-/// Determines whether the given element matches the given complex selector.
-pub fn matches_selector<E, F>(selector: &SelectorInner<E::Impl>,
- element: &E,
- parent_bf: Option<&BloomFilter>,
- relations: &mut StyleRelations,
- flags_setter: &mut F)
- -> bool
- where E: Element,
- F: FnMut(&E, ElementSelectorFlags),
-{
- // Use the bloom filter to fast-reject.
- if let Some(filter) = parent_bf {
- if !may_match::<E>(selector, filter) {
- return false;
- }
- }
-
- // Match the selector.
- matches_complex_selector(&selector.complex, element, relations, flags_setter)
-}
-
/// A result of selector matching, includes 3 failure types,
///
/// NotMatchedAndRestartFromClosestLaterSibling
@@ -175,18 +206,67 @@ enum SelectorMatchingResult {
NotMatchedGlobally,
}
+/// Matches an inner selector.
+pub fn matches_selector<E, F>(selector: &SelectorInner<E::Impl>,
+ element: &E,
+ context: &mut MatchingContext,
+ flags_setter: &mut F)
+ -> bool
+ where E: Element,
+ F: FnMut(&E, ElementSelectorFlags),
+{
+ // Use the bloom filter to fast-reject.
+ if let Some(filter) = context.bloom_filter {
+ if !may_match::<E>(&selector, filter) {
+ return false;
+ }
+ }
+
+ matches_complex_selector(&selector.complex, element, context, flags_setter)
+}
+
/// Matches a complex selector.
-pub fn matches_complex_selector<E, F>(selector: &ComplexSelector<E::Impl>,
+///
+/// Use `matches_selector` if you need to skip pseudos.
+pub fn matches_complex_selector<E, F>(complex_selector: &ComplexSelector<E::Impl>,
element: &E,
- relations: &mut StyleRelations,
+ context: &mut MatchingContext,
flags_setter: &mut F)
-> bool
- where E: Element,
- F: FnMut(&E, ElementSelectorFlags),
+ where E: Element,
+ F: FnMut(&E, ElementSelectorFlags),
{
- match matches_complex_selector_internal(selector.iter(),
+ let mut iter = complex_selector.iter();
+
+ if cfg!(debug_assertions) {
+ if context.matching_mode == MatchingMode::ForStatelessPseudoElement {
+ assert!(complex_selector.iter().any(|c| {
+ matches!(*c, Component::PseudoElement(..))
+ }));
+ }
+ }
+
+ if context.matching_mode == MatchingMode::ForStatelessPseudoElement {
+ match *iter.next().unwrap() {
+ // Stateful pseudo, just don't match.
+ Component::NonTSPseudoClass(..) => return false,
+ Component::PseudoElement(..) => {
+ // Pseudo, just eat the whole sequence.
+ let next = iter.next();
+ debug_assert!(next.is_none(),
+ "Someone messed up pseudo-element parsing?");
+
+ if iter.next_sequence().is_none() {
+ return true;
+ }
+ }
+ _ => panic!("Used MatchingMode::ForStatelessPseudoElement in a non-pseudo selector"),
+ }
+ }
+
+ match matches_complex_selector_internal(iter,
element,
- relations,
+ context,
flags_setter) {
SelectorMatchingResult::Matched => true,
_ => false
@@ -195,14 +275,14 @@ pub fn matches_complex_selector<E, F>(selector: &ComplexSelector<E::Impl>,
fn matches_complex_selector_internal<E, F>(mut selector_iter: SelectorIter<E::Impl>,
element: &E,
- relations: &mut StyleRelations,
+ context: &mut MatchingContext,
flags_setter: &mut F)
-> SelectorMatchingResult
where E: Element,
F: FnMut(&E, ElementSelectorFlags),
{
let matches_all_simple_selectors = selector_iter.all(|simple| {
- matches_simple_selector(simple, element, relations, flags_setter)
+ matches_simple_selector(simple, element, context, flags_setter)
});
let combinator = selector_iter.next_sequence();
@@ -218,12 +298,19 @@ fn matches_complex_selector_internal<E, F>(mut selector_iter: SelectorIter<E::Im
match combinator {
None => SelectorMatchingResult::Matched,
Some(c) => {
- let (mut next_element, candidate_not_found) = if siblings {
- (element.prev_sibling_element(),
- SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant)
- } else {
- (element.parent_element(),
- SelectorMatchingResult::NotMatchedGlobally)
+ let (mut next_element, candidate_not_found) = match c {
+ Combinator::NextSibling | Combinator::LaterSibling => {
+ (element.prev_sibling_element(),
+ SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant)
+ }
+ Combinator::Child | Combinator::Descendant => {
+ (element.parent_element(),
+ SelectorMatchingResult::NotMatchedGlobally)
+ }
+ Combinator::PseudoElement => {
+ (element.pseudo_element_originating_element(),
+ SelectorMatchingResult::NotMatchedGlobally)
+ }
};
loop {
@@ -233,7 +320,7 @@ fn matches_complex_selector_internal<E, F>(mut selector_iter: SelectorIter<E::Im
};
let result = matches_complex_selector_internal(selector_iter.clone(),
&element,
- relations,
+ context,
flags_setter);
match (result, c) {
// Return the status immediately.
@@ -242,6 +329,7 @@ fn matches_complex_selector_internal<E, F>(mut selector_iter: SelectorIter<E::Im
// Upgrade the failure status to
// NotMatchedAndRestartFromClosestDescendant.
+ (_, Combinator::PseudoElement) |
(_, Combinator::Child) => return SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant,
// Return the status directly.
@@ -276,7 +364,7 @@ fn matches_complex_selector_internal<E, F>(mut selector_iter: SelectorIter<E::Im
fn matches_simple_selector<E, F>(
selector: &Component<E::Impl>,
element: &E,
- relations: &mut StyleRelations,
+ context: &mut MatchingContext,
flags_setter: &mut F)
-> bool
where E: Element,
@@ -285,7 +373,7 @@ fn matches_simple_selector<E, F>(
macro_rules! relation_if {
($ex:expr, $flag:ident) => {
if $ex {
- *relations |= $flag;
+ context.relations |= $flag;
true
} else {
false
@@ -295,12 +383,24 @@ fn matches_simple_selector<E, F>(
match *selector {
Component::Combinator(_) => unreachable!(),
+ Component::PseudoElement(ref pseudo) => {
+ element.match_pseudo_element(pseudo, context)
+ }
Component::LocalName(LocalName { ref name, ref lower_name }) => {
- let name = if element.is_html_element_in_html_document() { lower_name } else { name };
- element.get_local_name() == name.borrow()
+ let is_html = element.is_html_element_in_html_document();
+ element.get_local_name() == select_name(is_html, name, lower_name).borrow()
+ }
+ Component::ExplicitUniversalType |
+ Component::ExplicitAnyNamespace => {
+ true
}
- Component::Namespace(ref namespace) => {
- element.get_namespace() == namespace.url.borrow()
+ Component::Namespace(_, ref url) |
+ Component::DefaultNamespace(ref url) => {
+ element.get_namespace() == url.borrow()
+ }
+ Component::ExplicitNoNamespace => {
+ let ns = ::parser::namespace_empty_string::<E::Impl>();
+ element.get_namespace() == ns.borrow()
}
// TODO: case-sensitivity depends on the document type and quirks mode
Component::ID(ref id) => {
@@ -310,38 +410,62 @@ fn matches_simple_selector<E, F>(
Component::Class(ref class) => {
element.has_class(class)
}
- Component::AttrExists(ref attr) => {
- element.match_attr_has(attr)
- }
- Component::AttrEqual(ref attr, ref value, case_sensitivity) => {
- match case_sensitivity {
- CaseSensitivity::CaseSensitive => element.match_attr_equals(attr, value),
- CaseSensitivity::CaseInsensitive => element.match_attr_equals_ignore_ascii_case(attr, value),
+ Component::AttributeInNoNamespaceExists { ref local_name, ref local_name_lower } => {
+ let is_html = element.is_html_element_in_html_document();
+ element.attr_matches(
+ &NamespaceConstraint::Specific(&::parser::namespace_empty_string::<E::Impl>()),
+ select_name(is_html, local_name, local_name_lower),
+ &AttrSelectorOperation::Exists
+ )
+ }
+ Component::AttributeInNoNamespace {
+ ref local_name,
+ ref local_name_lower,
+ ref value,
+ operator,
+ case_sensitivity,
+ never_matches,
+ } => {
+ if never_matches {
+ return false
}
+ let is_html = element.is_html_element_in_html_document();
+ element.attr_matches(
+ &NamespaceConstraint::Specific(&::parser::namespace_empty_string::<E::Impl>()),
+ select_name(is_html, local_name, local_name_lower),
+ &AttrSelectorOperation::WithValue {
+ operator: operator,
+ case_sensitivity: case_sensitivity.to_unconditional(is_html),
+ expected_value: value,
+ }
+ )
}
- Component::AttrIncludes(ref attr, ref value) => {
- element.match_attr_includes(attr, value)
- }
- Component::AttrDashMatch(ref attr, ref value) => {
- element.match_attr_dash(attr, value)
- }
- Component::AttrPrefixMatch(ref attr, ref value) => {
- element.match_attr_prefix(attr, value)
- }
- Component::AttrSubstringMatch(ref attr, ref value) => {
- element.match_attr_substring(attr, value)
- }
- Component::AttrSuffixMatch(ref attr, ref value) => {
- element.match_attr_suffix(attr, value)
- }
- Component::AttrIncludesNeverMatch(..) |
- Component::AttrPrefixNeverMatch(..) |
- Component::AttrSubstringNeverMatch(..) |
- Component::AttrSuffixNeverMatch(..) => {
- false
+ Component::AttributeOther(ref attr_sel) => {
+ if attr_sel.never_matches {
+ return false
+ }
+ let is_html = element.is_html_element_in_html_document();
+ element.attr_matches(
+ &attr_sel.namespace(),
+ select_name(is_html, &attr_sel.local_name, &attr_sel.local_name_lower),
+ &match attr_sel.operation {
+ ParsedAttrSelectorOperation::Exists => AttrSelectorOperation::Exists,
+ ParsedAttrSelectorOperation::WithValue {
+ operator,
+ case_sensitivity,
+ ref expected_value,
+ } => {
+ AttrSelectorOperation::WithValue {
+ operator: operator,
+ case_sensitivity: case_sensitivity.to_unconditional(is_html),
+ expected_value: expected_value,
+ }
+ }
+ }
+ )
}
Component::NonTSPseudoClass(ref pc) => {
- element.match_non_ts_pseudo_class(pc, relations, flags_setter)
+ element.match_non_ts_pseudo_class(pc, context, flags_setter)
}
Component::FirstChild => {
matches_first_child(element, flags_setter)
@@ -385,11 +509,19 @@ fn matches_simple_selector<E, F>(
matches_generic_nth_child(element, 0, 1, true, true, flags_setter)
}
Component::Negation(ref negated) => {
- !negated.iter().all(|ss| matches_simple_selector(ss, element, relations, flags_setter))
+ !negated.iter().all(|ss| matches_simple_selector(ss, element, context, flags_setter))
}
}
}
+fn select_name<'a, T>(is_html: bool, local_name: &'a T, local_name_lower: &'a T) -> &'a T {
+ if is_html {
+ local_name_lower
+ } else {
+ local_name
+ }
+}
+
#[inline]
fn matches_generic_nth_child<E, F>(element: &E,
a: i32,
diff --git a/components/selectors/parser.rs b/components/selectors/parser.rs
index 82571d9bd5e..197ce4f2629 100644
--- a/components/selectors/parser.rs
+++ b/components/selectors/parser.rs
@@ -3,6 +3,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use arcslice::ArcSlice;
+use attr::{AttrSelectorWithNamespace, ParsedAttrSelectorOperation, AttrSelectorOperator};
+use attr::{ParsedCaseSensitivity, SELECTOR_WHITESPACE, NamespaceConstraint};
use cssparser::{Token, Parser as CssParser, parse_nth, ToCss, serialize_identifier, CssStringWriter};
use precomputed_hash::PrecomputedHash;
use smallvec::SmallVec;
@@ -13,9 +15,34 @@ use std::fmt::{self, Display, Debug, Write};
use std::iter::Rev;
use std::ops::Add;
use std::slice;
-use tree::SELECTOR_WHITESPACE;
use visitor::SelectorVisitor;
+/// A trait that represents a pseudo-element.
+pub trait PseudoElement : Sized + ToCss {
+ /// The `SelectorImpl` this pseudo-element is used for.
+ type Impl: SelectorImpl;
+
+ /// 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
+ {
+ false
+ }
+}
+
+fn to_ascii_lowercase(s: &str) -> Cow<str> {
+ if let Some(first_uppercase) = s.bytes().position(|byte| byte >= b'A' && byte <= b'Z') {
+ let mut string = s.to_owned();
+ string[first_uppercase..].make_ascii_lowercase();
+ string.into()
+ } else {
+ s.into()
+ }
+}
+
macro_rules! with_all_bounds {
(
[ $( $InSelector: tt )* ]
@@ -29,16 +56,6 @@ macro_rules! with_all_bounds {
}
}
- fn from_ascii_lowercase<T>(s: &str) -> T where T: $($FromStr)* {
- if let Some(first_uppercase) = s.bytes().position(|byte| byte >= b'A' && byte <= b'Z') {
- let mut string = s.to_owned();
- string[first_uppercase..].make_ascii_lowercase();
- T::from(string)
- } else {
- T::from(s)
- }
- }
-
/// This trait allows to define the parser implementation in regards
/// of pseudo-classes/elements
///
@@ -60,7 +77,7 @@ macro_rules! with_all_bounds {
type NonTSPseudoClass: $($CommonBounds)* + Sized + ToCss + SelectorMethods<Impl = Self>;
/// pseudo-elements
- type PseudoElementSelector: $($CommonBounds)* + Sized + ToCss;
+ type PseudoElement: $($CommonBounds)* + PseudoElement<Impl = Self>;
}
}
}
@@ -97,8 +114,8 @@ pub trait Parser {
Err(())
}
- fn parse_pseudo_element(&self, _name: Cow<str>, _input: &mut CssParser)
- -> Result<<Self::Impl as SelectorImpl>::PseudoElementSelector, ()> {
+ fn parse_pseudo_element(&self, _name: Cow<str>)
+ -> Result<<Self::Impl as SelectorImpl>::PseudoElement, ()> {
Err(())
}
@@ -178,8 +195,59 @@ impl<Impl: SelectorImpl> SelectorInner<Impl> {
#[derive(PartialEq, Eq, Clone)]
pub struct Selector<Impl: SelectorImpl> {
pub inner: SelectorInner<Impl>,
- pub pseudo_element: Option<Impl::PseudoElementSelector>,
- pub specificity: u32,
+ specificity_and_flags: u32,
+}
+
+impl<Impl: SelectorImpl> ::std::borrow::Borrow<SelectorInner<Impl>> for Selector<Impl> {
+ fn borrow(&self) -> &SelectorInner<Impl> {
+ &self.inner
+ }
+}
+
+const HAS_PSEUDO_BIT: u32 = 1 << 30;
+
+impl<Impl: SelectorImpl> Selector<Impl> {
+ pub fn specificity(&self) -> u32 {
+ self.specificity_and_flags & !HAS_PSEUDO_BIT
+ }
+
+ pub fn new_for_unit_testing(inner: SelectorInner<Impl>, specificity: u32) -> Self {
+ Self {
+ inner: inner,
+ specificity_and_flags: specificity,
+ }
+ }
+
+ pub fn pseudo_element(&self) -> Option<&Impl::PseudoElement> {
+ if !self.has_pseudo_element() {
+ return None
+ }
+
+ for component in self.inner.complex.iter() {
+ if let Component::PseudoElement(ref pseudo) = *component {
+ return Some(pseudo)
+ }
+ }
+
+ debug_assert!(false, "has_pseudo_element lied!");
+ None
+ }
+
+ pub fn has_pseudo_element(&self) -> bool {
+ (self.specificity_and_flags & HAS_PSEUDO_BIT) != 0
+ }
+
+ /// Whether this selector (pseudo-element part excluded) matches every element.
+ ///
+ /// Used for "pre-computed" pseudo-elements in components/style/stylist.rs
+ pub fn is_universal(&self) -> bool {
+ self.inner.complex.iter_raw().all(|c| matches!(*c,
+ Component::ExplicitUniversalType |
+ Component::ExplicitAnyNamespace |
+ Component::Combinator(Combinator::PseudoElement) |
+ Component::PseudoElement(..)
+ ))
+ }
}
pub trait SelectorMethods {
@@ -246,18 +314,37 @@ impl<Impl: SelectorImpl> SelectorMethods for Component<Impl> {
return false;
}
}
- },
- AttrExists(ref selector) |
- AttrEqual(ref selector, _, _) |
- AttrIncludes(ref selector, _) |
- AttrDashMatch(ref selector, _) |
- AttrPrefixMatch(ref selector, _) |
- AttrSubstringMatch(ref selector, _) |
- AttrSuffixMatch(ref selector, _) => {
- if !visitor.visit_attribute_selector(selector) {
+ }
+
+ AttributeInNoNamespaceExists { ref local_name, ref local_name_lower } => {
+ if !visitor.visit_attribute_selector(
+ &NamespaceConstraint::Specific(&namespace_empty_string::<Impl>()),
+ local_name,
+ local_name_lower,
+ ) {
+ return false;
+ }
+ }
+ AttributeInNoNamespace { ref local_name, ref local_name_lower, never_matches, .. }
+ if !never_matches => {
+ if !visitor.visit_attribute_selector(
+ &NamespaceConstraint::Specific(&namespace_empty_string::<Impl>()),
+ local_name,
+ local_name_lower,
+ ) {
return false;
}
}
+ AttributeOther(ref attr_selector) if !attr_selector.never_matches => {
+ if !visitor.visit_attribute_selector(
+ &attr_selector.namespace(),
+ &attr_selector.local_name,
+ &attr_selector.local_name_lower,
+ ) {
+ return false;
+ }
+ }
+
NonTSPseudoClass(ref pseudo_class) => {
if !pseudo_class.visit(visitor) {
return false;
@@ -270,6 +357,11 @@ impl<Impl: SelectorImpl> SelectorMethods for Component<Impl> {
}
}
+pub fn namespace_empty_string<Impl: SelectorImpl>() -> Impl::NamespaceUrl {
+ // Rust type’s default, not default namespace
+ Impl::NamespaceUrl::default()
+}
+
/// A ComplexSelectors stores a sequence of simple selectors and combinators. The
/// iterator classes allow callers to iterate at either the raw sequence level or
/// at the level of sequences of simple selectors separated by combinators. Most
@@ -349,7 +441,8 @@ impl<'a, Impl: 'a + SelectorImpl> SelectorIter<'a, Impl> {
impl<'a, Impl: SelectorImpl> Iterator for SelectorIter<'a, Impl> {
type Item = &'a Component<Impl>;
fn next(&mut self) -> Option<Self::Item> {
- debug_assert!(self.next_combinator.is_none(), "Should call take_combinator!");
+ debug_assert!(self.next_combinator.is_none(),
+ "You should call next_sequence!");
match self.iter.next() {
None => None,
Some(&Component::Combinator(c)) => {
@@ -372,12 +465,12 @@ impl<'a, Impl: 'a + SelectorImpl> AncestorIter<'a, Impl> {
result
}
- /// Skips a sequence of simple selectors and all subsequent sequences until an
- /// ancestor combinator is reached.
+ /// Skips a sequence of simple selectors and all subsequent sequences until
+ /// a non-pseudo-element ancestor combinator is reached.
fn skip_until_ancestor(&mut self) {
loop {
- while let Some(_) = self.0.next() {}
- if self.0.next_sequence().map_or(true, |x| x.is_ancestor()) {
+ while self.0.next().is_some() {}
+ if self.0.next_sequence().map_or(true, |x| matches!(x, Combinator::Child | Combinator::Descendant)) {
break;
}
}
@@ -395,7 +488,7 @@ impl<'a, Impl: SelectorImpl> Iterator for AncestorIter<'a, Impl> {
// See if there are more sequences. If so, skip any non-ancestor sequences.
if let Some(combinator) = self.0.next_sequence() {
- if !combinator.is_ancestor() {
+ if !matches!(combinator, Combinator::Child | Combinator::Descendant) {
self.skip_until_ancestor();
}
}
@@ -410,12 +503,24 @@ pub enum Combinator {
Descendant, // space
NextSibling, // +
LaterSibling, // ~
+ /// A dummy combinator we use to the left of pseudo-elements.
+ ///
+ /// It serializes as the empty string, and acts effectively as a child
+ /// combinator.
+ PseudoElement,
}
impl Combinator {
/// Returns true if this combinator is a child or descendant combinator.
pub fn is_ancestor(&self) -> bool {
- matches!(*self, Combinator::Child | Combinator::Descendant)
+ matches!(*self, Combinator::Child |
+ Combinator::Descendant |
+ Combinator::PseudoElement)
+ }
+
+ /// Returns true if this combinator is a pseudo-element combinator.
+ pub fn is_pseudo_element(&self) -> bool {
+ matches!(*self, Combinator::PseudoElement)
}
/// Returns true if this combinator is a next- or later-sibling combinator.
@@ -431,24 +536,32 @@ impl Combinator {
#[derive(Eq, PartialEq, Clone)]
pub enum Component<Impl: SelectorImpl> {
Combinator(Combinator),
+
+ ExplicitAnyNamespace,
+ ExplicitNoNamespace,
+ DefaultNamespace(Impl::NamespaceUrl),
+ Namespace(Impl::NamespacePrefix, Impl::NamespaceUrl),
+
+ ExplicitUniversalType,
+ LocalName(LocalName<Impl>),
+
ID(Impl::Identifier),
Class(Impl::ClassName),
- LocalName(LocalName<Impl>),
- Namespace(Namespace<Impl>),
-
- // Attribute selectors
- AttrExists(AttrSelector<Impl>), // [foo]
- AttrEqual(AttrSelector<Impl>, Impl::AttrValue, CaseSensitivity), // [foo=bar]
- AttrIncludes(AttrSelector<Impl>, Impl::AttrValue), // [foo~=bar]
- AttrDashMatch(AttrSelector<Impl>, Impl::AttrValue), // [foo|=bar]
- AttrPrefixMatch(AttrSelector<Impl>, Impl::AttrValue), // [foo^=bar]
- AttrSubstringMatch(AttrSelector<Impl>, Impl::AttrValue), // [foo*=bar]
- AttrSuffixMatch(AttrSelector<Impl>, Impl::AttrValue), // [foo$=bar]
-
- AttrIncludesNeverMatch(AttrSelector<Impl>, Impl::AttrValue), // empty value or with whitespace
- AttrPrefixNeverMatch(AttrSelector<Impl>, Impl::AttrValue), // empty value
- AttrSubstringNeverMatch(AttrSelector<Impl>, Impl::AttrValue), // empty value
- AttrSuffixNeverMatch(AttrSelector<Impl>, Impl::AttrValue), // empty value
+
+ AttributeInNoNamespaceExists {
+ local_name: Impl::LocalName,
+ local_name_lower: Impl::LocalName,
+ },
+ AttributeInNoNamespace {
+ local_name: Impl::LocalName,
+ local_name_lower: Impl::LocalName,
+ operator: AttrSelectorOperator,
+ value: Impl::AttrValue,
+ case_sensitivity: ParsedCaseSensitivity,
+ never_matches: bool,
+ },
+ // Use a Box in the less common cases with more data to keep size_of::<Component>() small.
+ AttributeOther(Box<AttrSelectorWithNamespace<Impl>>),
// Pseudo-classes
//
@@ -472,7 +585,7 @@ pub enum Component<Impl: SelectorImpl> {
LastOfType,
OnlyOfType,
NonTSPseudoClass(Impl::NonTSPseudoClass),
- // ...
+ PseudoElement(Impl::PseudoElement),
}
impl<Impl: SelectorImpl> Component<Impl> {
@@ -489,8 +602,9 @@ impl<Impl: SelectorImpl> Component<Impl> {
None
}
},
- Component::Namespace(ref namespace) => {
- Some(namespace.url.precomputed_hash())
+ Component::DefaultNamespace(ref url) |
+ Component::Namespace(_, ref url) => {
+ Some(url.precomputed_hash())
},
Component::ID(ref id) => {
Some(id.precomputed_hash())
@@ -516,53 +630,17 @@ impl<Impl: SelectorImpl> Component<Impl> {
}
}
-#[derive(Eq, PartialEq, Clone, Copy, Debug)]
-pub enum CaseSensitivity {
- CaseSensitive, // Selectors spec says language-defined, but HTML says sensitive.
- CaseInsensitive,
-}
-
-
#[derive(Eq, PartialEq, Clone)]
pub struct LocalName<Impl: SelectorImpl> {
pub name: Impl::LocalName,
pub lower_name: Impl::LocalName,
}
-#[derive(Eq, PartialEq, Clone)]
-pub struct AttrSelector<Impl: SelectorImpl> {
- pub name: Impl::LocalName,
- pub lower_name: Impl::LocalName,
- pub namespace: NamespaceConstraint<Impl>,
-}
-
-#[derive(Eq, PartialEq, Clone, Debug)]
-pub enum NamespaceConstraint<Impl: SelectorImpl> {
- Any,
- Specific(Namespace<Impl>),
-}
-
-#[derive(Eq, PartialEq, Clone)]
-pub struct Namespace<Impl: SelectorImpl> {
- pub prefix: Option<Impl::NamespacePrefix>,
- pub url: Impl::NamespaceUrl,
-}
-
-impl<Impl: SelectorImpl> Default for Namespace<Impl> {
- fn default() -> Self {
- Namespace {
- prefix: None,
- url: Impl::NamespaceUrl::default(), // empty string
- }
- }
-}
-
-
impl<Impl: SelectorImpl> Debug for Selector<Impl> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("Selector(")?;
self.to_css(f)?;
- write!(f, ", specificity = 0x{:x})", self.specificity)
+ write!(f, ", specificity = 0x{:x})", self.specificity())
}
}
@@ -575,10 +653,7 @@ impl<Impl: SelectorImpl> Debug for ComplexSelector<Impl> {
impl<Impl: SelectorImpl> Debug for Component<Impl> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.to_css(f) }
}
-impl<Impl: SelectorImpl> Debug for AttrSelector<Impl> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.to_css(f) }
-}
-impl<Impl: SelectorImpl> Debug for Namespace<Impl> {
+impl<Impl: SelectorImpl> Debug for AttrSelectorWithNamespace<Impl> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.to_css(f) }
}
impl<Impl: SelectorImpl> Debug for LocalName<Impl> {
@@ -601,11 +676,7 @@ impl<Impl: SelectorImpl> ToCss for SelectorList<Impl> {
impl<Impl: SelectorImpl> ToCss for Selector<Impl> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- self.inner.complex.to_css(dest)?;
- if let Some(ref pseudo) = self.pseudo_element {
- pseudo.to_css(dest)?;
- }
- Ok(())
+ self.inner.complex.to_css(dest)
}
}
@@ -626,6 +697,7 @@ impl ToCss for Combinator {
Combinator::Descendant => dest.write_str(" "),
Combinator::NextSibling => dest.write_str(" + "),
Combinator::LaterSibling => dest.write_str(" ~ "),
+ Combinator::PseudoElement => Ok(()),
}
}
}
@@ -637,6 +709,9 @@ impl<Impl: SelectorImpl> ToCss for Component<Impl> {
Combinator(ref c) => {
c.to_css(dest)
}
+ PseudoElement(ref p) => {
+ p.to_css(dest)
+ }
ID(ref s) => {
dest.write_char('#')?;
display_to_css_identifier(s, dest)
@@ -646,34 +721,41 @@ impl<Impl: SelectorImpl> ToCss for Component<Impl> {
display_to_css_identifier(s, dest)
}
LocalName(ref s) => s.to_css(dest),
- Namespace(ref ns) => ns.to_css(dest),
+ ExplicitUniversalType => dest.write_char('*'),
+
+ DefaultNamespace(_) => Ok(()),
+ ExplicitNoNamespace => dest.write_char('|'),
+ ExplicitAnyNamespace => dest.write_str("*|"),
+ Namespace(ref prefix, _) => {
+ display_to_css_identifier(prefix, dest)?;
+ dest.write_char('|')
+ }
- // Attribute selectors
- AttrExists(ref a) => {
+ AttributeInNoNamespaceExists { ref local_name, .. } => {
dest.write_char('[')?;
- a.to_css(dest)?;
+ display_to_css_identifier(local_name, dest)?;
dest.write_char(']')
}
- AttrEqual(ref a, ref v, case) => {
- attr_selector_to_css(a, " = ", v, match case {
- CaseSensitivity::CaseSensitive => None,
- CaseSensitivity::CaseInsensitive => Some(" i"),
- }, dest)
+ AttributeInNoNamespace { ref local_name, operator, ref value, case_sensitivity, .. } => {
+ dest.write_char('[')?;
+ display_to_css_identifier(local_name, dest)?;
+ operator.to_css(dest)?;
+ dest.write_char('"')?;
+ write!(CssStringWriter::new(dest), "{}", value)?;
+ dest.write_char('"')?;
+ match case_sensitivity {
+ ParsedCaseSensitivity::CaseSensitive |
+ ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument => {},
+ ParsedCaseSensitivity::AsciiCaseInsensitive => dest.write_str(" i")?,
+ }
+ dest.write_char(']')
}
- AttrDashMatch(ref a, ref v) => attr_selector_to_css(a, " |= ", v, None, dest),
- AttrIncludesNeverMatch(ref a, ref v) |
- AttrIncludes(ref a, ref v) => attr_selector_to_css(a, " ~= ", v, None, dest),
- AttrPrefixNeverMatch(ref a, ref v) |
- AttrPrefixMatch(ref a, ref v) => attr_selector_to_css(a, " ^= ", v, None, dest),
- AttrSubstringNeverMatch(ref a, ref v) |
- AttrSubstringMatch(ref a, ref v) => attr_selector_to_css(a, " *= ", v, None, dest),
- AttrSuffixNeverMatch(ref a, ref v) |
- AttrSuffixMatch(ref a, ref v) => attr_selector_to_css(a, " $= ", v, None, dest),
+ AttributeOther(ref attr_selector) => attr_selector.to_css(dest),
// Pseudo-classes
Negation(ref arg) => {
dest.write_str(":not(")?;
- debug_assert!(arg.len() <= 1 || (arg.len() == 2 && matches!(arg[0], Component::Namespace(_))));
+ debug_assert!(single_simple_selector(arg));
for component in arg.iter() {
component.to_css(dest)?;
}
@@ -697,22 +779,36 @@ impl<Impl: SelectorImpl> ToCss for Component<Impl> {
}
}
-impl<Impl: SelectorImpl> ToCss for AttrSelector<Impl> {
+impl<Impl: SelectorImpl> ToCss for AttrSelectorWithNamespace<Impl> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- if let NamespaceConstraint::Specific(ref ns) = self.namespace {
- ns.to_css(dest)?;
+ dest.write_char('[')?;
+ match self.namespace {
+ NamespaceConstraint::Specific((ref prefix, _)) => {
+ display_to_css_identifier(prefix, dest)?;
+ dest.write_char('|')?
+ }
+ NamespaceConstraint::Any => {
+ dest.write_str("*|")?
+ }
}
- display_to_css_identifier(&self.name, dest)
- }
-}
-
-impl<Impl: SelectorImpl> ToCss for Namespace<Impl> {
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- if let Some(ref prefix) = self.prefix {
- display_to_css_identifier(prefix, dest)?;
- dest.write_char('|')?;
+ display_to_css_identifier(&self.local_name, dest)?;
+ match self.operation {
+ ParsedAttrSelectorOperation::Exists => {},
+ ParsedAttrSelectorOperation::WithValue {
+ operator, case_sensitivity, ref expected_value
+ } => {
+ operator.to_css(dest)?;
+ dest.write_char('"')?;
+ write!(CssStringWriter::new(dest), "{}", expected_value)?;
+ dest.write_char('"')?;
+ match case_sensitivity {
+ ParsedCaseSensitivity::CaseSensitive |
+ ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument => {},
+ ParsedCaseSensitivity::AsciiCaseInsensitive => dest.write_str(" i")?,
+ }
+ },
}
- Ok(())
+ dest.write_char(']')
}
}
@@ -722,26 +818,6 @@ impl<Impl: SelectorImpl> ToCss for LocalName<Impl> {
}
}
-fn attr_selector_to_css<Impl, W>(attr: &AttrSelector<Impl>,
- operator: &str,
- value: &Impl::AttrValue,
- modifier: Option<&str>,
- dest: &mut W)
- -> fmt::Result
-where Impl: SelectorImpl, W: fmt::Write
-{
- dest.write_char('[')?;
- attr.to_css(dest)?;
- dest.write_str(operator)?;
- dest.write_char('"')?;
- write!(CssStringWriter::new(dest), "{}", value)?;
- dest.write_char('"')?;
- if let Some(m) = modifier {
- dest.write_str(m)?;
- }
- dest.write_char(']')
-}
-
/// Serialize the output of Display as a CSS identifier
fn display_to_css_identifier<T: Display, W: fmt::Write>(x: &T, dest: &mut W) -> fmt::Result {
// FIXME(SimonSapin): it is possible to avoid this heap allocation
@@ -813,42 +889,33 @@ impl From<Specificity> for u32 {
}
}
-fn specificity<Impl>(complex_selector: &ComplexSelector<Impl>,
- pseudo_element: Option<&Impl::PseudoElementSelector>)
- -> u32
- where Impl: SelectorImpl {
- let mut specificity = complex_selector_specificity(complex_selector);
- if pseudo_element.is_some() {
- specificity.element_selectors += 1;
- }
- specificity.into()
+fn specificity<Impl>(complex_selector: &ComplexSelector<Impl>) -> u32
+ where Impl: SelectorImpl
+{
+ complex_selector_specificity(complex_selector).into()
}
fn complex_selector_specificity<Impl>(selector: &ComplexSelector<Impl>)
-> Specificity
- where Impl: SelectorImpl {
+ where Impl: SelectorImpl
+{
fn simple_selector_specificity<Impl>(simple_selector: &Component<Impl>,
specificity: &mut Specificity)
- where Impl: SelectorImpl {
+ where Impl: SelectorImpl
+ {
match *simple_selector {
Component::Combinator(..) => unreachable!(),
- Component::LocalName(..) =>
- specificity.element_selectors += 1,
- Component::ID(..) =>
- specificity.id_selectors += 1,
+ Component::PseudoElement(..) |
+ Component::LocalName(..) => {
+ specificity.element_selectors += 1
+ }
+ Component::ID(..) => {
+ specificity.id_selectors += 1
+ }
Component::Class(..) |
- Component::AttrExists(..) |
- Component::AttrEqual(..) |
- Component::AttrIncludes(..) |
- Component::AttrDashMatch(..) |
- Component::AttrPrefixMatch(..) |
- Component::AttrSubstringMatch(..) |
- Component::AttrSuffixMatch(..) |
-
- Component::AttrIncludesNeverMatch(..) |
- Component::AttrPrefixNeverMatch(..) |
- Component::AttrSubstringNeverMatch(..) |
- Component::AttrSuffixNeverMatch(..) |
+ Component::AttributeInNoNamespace { .. } |
+ Component::AttributeInNoNamespaceExists { .. } |
+ Component::AttributeOther(..) |
Component::FirstChild | Component::LastChild |
Component::OnlyChild | Component::Root |
@@ -859,10 +926,16 @@ fn complex_selector_specificity<Impl>(selector: &ComplexSelector<Impl>)
Component::NthLastOfType(..) |
Component::FirstOfType | Component::LastOfType |
Component::OnlyOfType |
- Component::NonTSPseudoClass(..) =>
- specificity.class_like_selectors += 1,
-
- Component::Namespace(..) => (),
+ Component::NonTSPseudoClass(..) => {
+ specificity.class_like_selectors += 1
+ }
+ Component::ExplicitUniversalType |
+ Component::ExplicitAnyNamespace |
+ Component::ExplicitNoNamespace |
+ Component::DefaultNamespace(..) |
+ Component::Namespace(..) => {
+ // Does not affect specificity
+ }
Component::Negation(ref negated) => {
for ss in negated.iter() {
simple_selector_specificity(&ss, specificity);
@@ -892,12 +965,14 @@ fn complex_selector_specificity<Impl>(selector: &ComplexSelector<Impl>)
fn parse_selector<P, Impl>(parser: &P, input: &mut CssParser) -> Result<Selector<Impl>, ()>
where P: Parser<Impl=Impl>, Impl: SelectorImpl
{
- let (complex, pseudo_element) =
- parse_complex_selector_and_pseudo_element(parser, input)?;
+ let (complex, has_pseudo_element) = parse_complex_selector(parser, input)?;
+ let mut specificity = specificity(&complex);
+ if has_pseudo_element {
+ specificity |= HAS_PSEUDO_BIT;
+ }
Ok(Selector {
- specificity: specificity(&complex, pseudo_element.as_ref()),
+ specificity_and_flags: specificity,
inner: SelectorInner::new(complex),
- pseudo_element: pseudo_element,
})
}
@@ -911,19 +986,25 @@ fn parse_selector<P, Impl>(parser: &P, input: &mut CssParser) -> Result<Selector
/// If we parse N > 8 entries, we save two reallocations.
type ParseVec<Impl> = SmallVec<[Component<Impl>; 8]>;
-fn parse_complex_selector_and_pseudo_element<P, Impl>(
+/// Parses a complex selector, including any pseudo-element.
+///
+/// For now, it always forces the pseudo-element to be at the end of the
+/// selector, and the boolean represents whether the last thing parsed was a
+/// pseudo-element.
+fn parse_complex_selector<P, Impl>(
parser: &P,
input: &mut CssParser)
- -> Result<(ComplexSelector<Impl>, Option<Impl::PseudoElementSelector>), ()>
+ -> Result<(ComplexSelector<Impl>, bool), ()>
where P: Parser<Impl=Impl>, Impl: SelectorImpl
{
let mut sequence = ParseVec::new();
- let mut pseudo_element;
+ let mut parsed_pseudo_element;
'outer_loop: loop {
// Parse a sequence of simple selectors.
- pseudo_element = parse_compound_selector(parser, input, &mut sequence,
- /* inside_negation = */ false)?;
- if pseudo_element.is_some() {
+ parsed_pseudo_element =
+ parse_compound_selector(parser, input, &mut sequence,
+ /* inside_negation = */ false)?;
+ if parsed_pseudo_element {
break;
}
@@ -962,17 +1043,17 @@ fn parse_complex_selector_and_pseudo_element<P, Impl>(
}
let complex = ComplexSelector(ArcSlice::new(sequence.into_vec().into_boxed_slice()));
- Ok((complex, pseudo_element))
+ Ok((complex, parsed_pseudo_element))
}
impl<Impl: SelectorImpl> ComplexSelector<Impl> {
- /// Parse a complex selector.
+ /// Parse a complex selector, without any pseudo-element.
pub fn parse<P>(parser: &P, input: &mut CssParser) -> Result<Self, ()>
where P: Parser<Impl=Impl>
{
- let (complex, pseudo_element) =
- parse_complex_selector_and_pseudo_element(parser, input)?;
- if pseudo_element.is_some() {
+ let (complex, has_pseudo_element) =
+ parse_complex_selector(parser, input)?;
+ if has_pseudo_element {
return Err(())
}
Ok(complex)
@@ -990,19 +1071,33 @@ fn parse_type_selector<P, Impl>(parser: &P, input: &mut CssParser, sequence: &mu
None => Ok(false),
Some((namespace, local_name)) => {
match namespace {
- NamespaceConstraint::Specific(ns) => {
- sequence.push(Component::Namespace(ns))
- },
- NamespaceConstraint::Any => (),
+ QNamePrefix::ImplicitAnyNamespace => {}
+ QNamePrefix::ImplicitDefaultNamespace(url) => {
+ sequence.push(Component::DefaultNamespace(url))
+ }
+ QNamePrefix::ExplicitNamespace(prefix, url) => {
+ sequence.push(Component::Namespace(prefix, url))
+ }
+ QNamePrefix::ExplicitNoNamespace => {
+ sequence.push(Component::ExplicitNoNamespace)
+ }
+ QNamePrefix::ExplicitAnyNamespace => {
+ sequence.push(Component::ExplicitAnyNamespace)
+ }
+ QNamePrefix::ImplicitNoNamespace => {
+ unreachable!() // Not returned with in_attr_selector = false
+ }
}
match local_name {
Some(name) => {
sequence.push(Component::LocalName(LocalName {
- lower_name: from_ascii_lowercase(&name),
+ lower_name: from_cow_str(to_ascii_lowercase(&name)),
name: from_cow_str(name),
}))
}
- None => (),
+ None => {
+ sequence.push(Component::ExplicitUniversalType)
+ }
}
Ok(true)
}
@@ -1012,7 +1107,17 @@ fn parse_type_selector<P, Impl>(parser: &P, input: &mut CssParser, sequence: &mu
#[derive(Debug)]
enum SimpleSelectorParseResult<Impl: SelectorImpl> {
SimpleSelector(Component<Impl>),
- PseudoElement(Impl::PseudoElementSelector),
+ PseudoElement(Impl::PseudoElement),
+}
+
+#[derive(Debug)]
+enum QNamePrefix<Impl: SelectorImpl> {
+ ImplicitNoNamespace, // `foo` in attr selectors
+ ImplicitAnyNamespace, // `foo` in type selectors, without a default ns
+ ImplicitDefaultNamespace(Impl::NamespaceUrl), // `foo` in type selectors, with a default ns
+ ExplicitNoNamespace, // `|foo`
+ ExplicitAnyNamespace, // `*|foo`
+ ExplicitNamespace(Impl::NamespacePrefix, Impl::NamespaceUrl), // `prefix|foo`
}
/// * `Err(())`: Invalid selector, abort
@@ -1021,16 +1126,13 @@ enum SimpleSelectorParseResult<Impl: SelectorImpl> {
fn parse_qualified_name<'i, 't, P, Impl>
(parser: &P, input: &mut CssParser<'i, 't>,
in_attr_selector: bool)
- -> Result<Option<(NamespaceConstraint<Impl>, Option<Cow<'i, str>>)>, ()>
+ -> Result<Option<(QNamePrefix<Impl>, Option<Cow<'i, str>>)>, ()>
where P: Parser<Impl=Impl>, Impl: SelectorImpl
{
let default_namespace = |local_name| {
let namespace = match parser.default_namespace() {
- Some(url) => NamespaceConstraint::Specific(Namespace {
- prefix: None,
- url: url
- }),
- None => NamespaceConstraint::Any,
+ Some(url) => QNamePrefix::ImplicitDefaultNamespace(url),
+ None => QNamePrefix::ImplicitAnyNamespace,
};
Ok(Some((namespace, local_name)))
};
@@ -1056,15 +1158,12 @@ fn parse_qualified_name<'i, 't, P, Impl>
let prefix = from_cow_str(value);
let result = parser.namespace_for_prefix(&prefix);
let url = result.ok_or(())?;
- explicit_namespace(input, NamespaceConstraint::Specific(Namespace {
- prefix: Some(prefix),
- url: url
- }))
+ explicit_namespace(input, QNamePrefix::ExplicitNamespace(prefix, url))
},
_ => {
input.reset(position);
if in_attr_selector {
- Ok(Some((NamespaceConstraint::Specific(Default::default()), Some(value))))
+ Ok(Some((QNamePrefix::ImplicitNoNamespace, Some(value))))
} else {
default_namespace(Some(value))
}
@@ -1074,7 +1173,9 @@ fn parse_qualified_name<'i, 't, P, Impl>
Ok(Token::Delim('*')) => {
let position = input.position();
match input.next_including_whitespace() {
- Ok(Token::Delim('|')) => explicit_namespace(input, NamespaceConstraint::Any),
+ Ok(Token::Delim('|')) => {
+ explicit_namespace(input, QNamePrefix::ExplicitAnyNamespace)
+ }
_ => {
input.reset(position);
if in_attr_selector {
@@ -1086,7 +1187,7 @@ fn parse_qualified_name<'i, 't, P, Impl>
}
},
Ok(Token::Delim('|')) => {
- explicit_namespace(input, NamespaceConstraint::Specific(Default::default()))
+ explicit_namespace(input, QNamePrefix::ExplicitNoNamespace)
}
_ => {
input.reset(position);
@@ -1100,77 +1201,143 @@ fn parse_attribute_selector<P, Impl>(parser: &P, input: &mut CssParser)
-> Result<Component<Impl>, ()>
where P: Parser<Impl=Impl>, Impl: SelectorImpl
{
- let attr = match parse_qualified_name(parser, input, /* in_attr_selector = */ true)? {
+ let namespace;
+ let local_name;
+ match parse_qualified_name(parser, input, /* in_attr_selector = */ true)? {
None => return Err(()),
Some((_, None)) => unreachable!(),
- Some((namespace, Some(local_name))) => AttrSelector {
- namespace: namespace,
- lower_name: from_ascii_lowercase(&local_name),
- name: from_cow_str(local_name),
- },
- };
+ Some((ns, Some(ln))) => {
+ local_name = ln;
+ namespace = match ns {
+ QNamePrefix::ImplicitNoNamespace |
+ QNamePrefix::ExplicitNoNamespace => {
+ None
+ }
+ QNamePrefix::ExplicitNamespace(prefix, url) => {
+ Some(NamespaceConstraint::Specific((prefix, url)))
+ }
+ QNamePrefix::ExplicitAnyNamespace => {
+ Some(NamespaceConstraint::Any)
+ }
+ QNamePrefix::ImplicitAnyNamespace |
+ QNamePrefix::ImplicitDefaultNamespace(_) => {
+ unreachable!() // Not returned with in_attr_selector = true
+ }
+ }
+ }
+ }
+ let operator;
+ let value;
+ let never_matches;
match input.next() {
// [foo]
- Err(()) => Ok(Component::AttrExists(attr)),
+ Err(()) => {
+ let local_name_lower = from_cow_str(to_ascii_lowercase(&local_name));
+ let local_name = from_cow_str(local_name);
+ if let Some(namespace) = namespace {
+ return Ok(Component::AttributeOther(Box::new(AttrSelectorWithNamespace {
+ namespace: namespace,
+ local_name: local_name,
+ local_name_lower: local_name_lower,
+ operation: ParsedAttrSelectorOperation::Exists,
+ never_matches: false,
+ })))
+ } else {
+ return Ok(Component::AttributeInNoNamespaceExists {
+ local_name: local_name,
+ local_name_lower: local_name_lower,
+ })
+ }
+ }
// [foo=bar]
Ok(Token::Delim('=')) => {
- let value = input.expect_ident_or_string()?;
- let flags = parse_attribute_flags(input)?;
- Ok(Component::AttrEqual(attr, from_cow_str(value), flags))
+ value = input.expect_ident_or_string()?;
+ never_matches = false;
+ operator = AttrSelectorOperator::Equal;
}
// [foo~=bar]
Ok(Token::IncludeMatch) => {
- let value = input.expect_ident_or_string()?;
- if value.is_empty() || value.contains(SELECTOR_WHITESPACE) {
- Ok(Component::AttrIncludesNeverMatch(attr, from_cow_str(value)))
- } else {
- Ok(Component::AttrIncludes(attr, from_cow_str(value)))
- }
+ value = input.expect_ident_or_string()?;
+ never_matches = value.is_empty() || value.contains(SELECTOR_WHITESPACE);
+ operator = AttrSelectorOperator::Includes;
}
// [foo|=bar]
Ok(Token::DashMatch) => {
- let value = input.expect_ident_or_string()?;
- Ok(Component::AttrDashMatch(attr, from_cow_str(value)))
+ value = input.expect_ident_or_string()?;
+ never_matches = false;
+ operator = AttrSelectorOperator::DashMatch;
}
// [foo^=bar]
Ok(Token::PrefixMatch) => {
- let value = input.expect_ident_or_string()?;
- if value.is_empty() {
- Ok(Component::AttrPrefixNeverMatch(attr, from_cow_str(value)))
- } else {
- Ok(Component::AttrPrefixMatch(attr, from_cow_str(value)))
- }
+ value = input.expect_ident_or_string()?;
+ never_matches = value.is_empty();
+ operator = AttrSelectorOperator::Prefix;
}
// [foo*=bar]
Ok(Token::SubstringMatch) => {
- let value = input.expect_ident_or_string()?;
- if value.is_empty() {
- Ok(Component::AttrSubstringNeverMatch(attr, from_cow_str(value)))
- } else {
- Ok(Component::AttrSubstringMatch(attr, from_cow_str(value)))
- }
+ value = input.expect_ident_or_string()?;
+ never_matches = value.is_empty();
+ operator = AttrSelectorOperator::Substring;
}
// [foo$=bar]
Ok(Token::SuffixMatch) => {
- let value = input.expect_ident_or_string()?;
- if value.is_empty() {
- Ok(Component::AttrSuffixNeverMatch(attr, from_cow_str(value)))
- } else {
- Ok(Component::AttrSuffixMatch(attr, from_cow_str(value)))
+ value = input.expect_ident_or_string()?;
+ never_matches = value.is_empty();
+ operator = AttrSelectorOperator::Suffix;
+ }
+ _ => return Err(())
+ }
+
+ let mut case_sensitivity = parse_attribute_flags(input)?;
+
+ let value = from_cow_str(value);
+ let local_name_lower;
+ {
+ let local_name_lower_cow = to_ascii_lowercase(&local_name);
+ if let ParsedCaseSensitivity::CaseSensitive = case_sensitivity {
+ if namespace.is_none() &&
+ include!(concat!(env!("OUT_DIR"), "/ascii_case_insensitive_html_attributes.rs"))
+ .contains(&*local_name_lower_cow)
+ {
+ case_sensitivity =
+ ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument
}
}
- _ => Err(())
+ local_name_lower = from_cow_str(local_name_lower_cow);
+ }
+ let local_name = from_cow_str(local_name);
+ if let Some(namespace) = namespace {
+ Ok(Component::AttributeOther(Box::new(AttrSelectorWithNamespace {
+ namespace: namespace,
+ local_name: local_name,
+ local_name_lower: local_name_lower,
+ never_matches: never_matches,
+ operation: ParsedAttrSelectorOperation::WithValue {
+ operator: operator,
+ case_sensitivity: case_sensitivity,
+ expected_value: value,
+ }
+ })))
+ } else {
+ Ok(Component::AttributeInNoNamespace {
+ local_name: local_name,
+ local_name_lower: local_name_lower,
+ operator: operator,
+ value: value,
+ case_sensitivity: case_sensitivity,
+ never_matches: never_matches,
+ })
}
}
-fn parse_attribute_flags(input: &mut CssParser) -> Result<CaseSensitivity, ()> {
+fn parse_attribute_flags(input: &mut CssParser) -> Result<ParsedCaseSensitivity, ()> {
match input.next() {
- Err(()) => Ok(CaseSensitivity::CaseSensitive),
+ Err(()) => Ok(ParsedCaseSensitivity::CaseSensitive),
Ok(Token::Ident(ref value)) if value.eq_ignore_ascii_case("i") => {
- Ok(CaseSensitivity::CaseInsensitive)
+ Ok(ParsedCaseSensitivity::AsciiCaseInsensitive)
}
_ => Err(())
}
@@ -1187,28 +1354,46 @@ fn parse_negation<P, Impl>(parser: &P,
let mut v = ParseVec::new();
parse_compound_selector(parser, input, &mut v, /* inside_negation = */ true)?;
- let allow = v.len() <= 1 ||
- (v.len() == 2 && matches!(v[0], Component::Namespace(_)) &&
- matches!(v[1], Component::LocalName(_)));
-
- if allow {
+ if single_simple_selector(&v) {
Ok(Component::Negation(v.into_vec().into_boxed_slice()))
} else {
Err(())
}
}
+// A single type selector can be represented as two components
+fn single_simple_selector<Impl: SelectorImpl>(v: &[Component<Impl>]) -> bool {
+ v.len() == 1 || (
+ v.len() == 2 &&
+ match v[1] {
+ Component::LocalName(_) | Component::ExplicitUniversalType => {
+ debug_assert!(matches!(v[0],
+ Component::ExplicitAnyNamespace |
+ Component::ExplicitNoNamespace |
+ Component::DefaultNamespace(_) |
+ Component::Namespace(..)
+ ));
+ true
+ }
+ _ => false,
+ }
+ )
+
+}
+
/// simple_selector_sequence
/// : [ type_selector | universal ] [ HASH | class | attrib | pseudo | negation ]*
/// | [ HASH | class | attrib | pseudo | negation ]+
///
-/// `Err(())` means invalid selector
+/// `Err(())` means invalid selector.
+///
+/// The boolean represent whether a pseudo-element has been parsed.
fn parse_compound_selector<P, Impl>(
parser: &P,
input: &mut CssParser,
mut sequence: &mut ParseVec<Impl>,
inside_negation: bool)
- -> Result<Option<Impl::PseudoElementSelector>, ()>
+ -> Result<bool, ()>
where P: Parser<Impl=Impl>, Impl: SelectorImpl
{
// Consume any leading whitespace.
@@ -1228,17 +1413,14 @@ fn parse_compound_selector<P, Impl>(
//
// Note that this doesn't apply to :not() and :matches() per spec.
if !inside_negation {
- sequence.push(Component::Namespace(Namespace {
- prefix: None,
- url: url
- }));
+ sequence.push(Component::DefaultNamespace(url))
}
}
} else {
empty = false;
}
- let mut pseudo_element = None;
+ let mut pseudo = false;
loop {
match parse_one_simple_selector(parser, input, inside_negation)? {
None => break,
@@ -1247,7 +1429,41 @@ fn parse_compound_selector<P, Impl>(
empty = false
}
Some(SimpleSelectorParseResult::PseudoElement(p)) => {
- pseudo_element = Some(p);
+ // Try to parse state to its right.
+ let mut state_selectors = ParseVec::new();
+
+ loop {
+ match input.next_including_whitespace() {
+ Ok(Token::Colon) => {},
+ Ok(Token::WhiteSpace(_)) | Err(()) => break,
+ _ => return Err(()),
+ }
+
+ // TODO(emilio): Functional pseudo-classes too?
+ // We don't need it for now.
+ let name = match input.next_including_whitespace() {
+ Ok(Token::Ident(name)) => name,
+ _ => return Err(()),
+ };
+
+ let pseudo_class =
+ P::parse_non_ts_pseudo_class(parser, name)?;
+ if !p.supports_pseudo_class(&pseudo_class) {
+ return Err(());
+ }
+ state_selectors.push(Component::NonTSPseudoClass(pseudo_class));
+ }
+
+ if !sequence.is_empty() {
+ sequence.push(Component::Combinator(Combinator::PseudoElement));
+ }
+
+ sequence.push(Component::PseudoElement(p));
+ for state_selector in state_selectors {
+ sequence.push(state_selector);
+ }
+
+ pseudo = true;
empty = false;
break
}
@@ -1257,7 +1473,7 @@ fn parse_compound_selector<P, Impl>(
// An empty selector is invalid.
Err(())
} else {
- Ok(pseudo_element)
+ Ok(pseudo)
}
}
@@ -1333,7 +1549,7 @@ fn parse_one_simple_selector<P, Impl>(parser: &P,
name.eq_ignore_ascii_case("after") ||
name.eq_ignore_ascii_case("first-line") ||
name.eq_ignore_ascii_case("first-letter") {
- let pseudo_element = P::parse_pseudo_element(parser, name, input)?;
+ let pseudo_element = P::parse_pseudo_element(parser, name)?;
Ok(Some(SimpleSelectorParseResult::PseudoElement(pseudo_element)))
} else {
let pseudo_class = parse_simple_pseudo_class(parser, name)?;
@@ -1349,7 +1565,7 @@ fn parse_one_simple_selector<P, Impl>(parser: &P,
Ok(Token::Colon) => {
match input.next_including_whitespace() {
Ok(Token::Ident(name)) => {
- let pseudo = P::parse_pseudo_element(parser, name, input)?;
+ let pseudo = P::parse_pseudo_element(parser, name)?;
Ok(Some(SimpleSelectorParseResult::PseudoElement(pseudo)))
}
_ => Err(())
@@ -1388,6 +1604,7 @@ fn parse_simple_pseudo_class<P, Impl>(parser: &P, name: Cow<str>) -> Result<Comp
#[cfg(test)]
pub mod tests {
use cssparser::{Parser as CssParser, ToCss, serialize_identifier};
+ use parser;
use std::borrow::Cow;
use std::collections::HashMap;
use std::fmt;
@@ -1396,6 +1613,7 @@ pub mod tests {
#[derive(PartialEq, Clone, Debug, Eq)]
pub enum PseudoClass {
Hover,
+ Active,
Lang(String),
}
@@ -1405,10 +1623,23 @@ pub mod tests {
After,
}
+ 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,
+ }
+ }
+ }
+
impl ToCss for PseudoClass {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
PseudoClass::Hover => dest.write_str(":hover"),
+ PseudoClass::Active => dest.write_str(":active"),
PseudoClass::Lang(ref lang) => {
dest.write_str(":lang(")?;
serialize_identifier(lang, dest)?;
@@ -1453,7 +1684,7 @@ pub mod tests {
type BorrowedLocalName = DummyAtom;
type BorrowedNamespaceUrl = DummyAtom;
type NonTSPseudoClass = PseudoClass;
- type PseudoElementSelector = PseudoElement;
+ type PseudoElement = PseudoElement;
}
#[derive(Default, Debug, Clone, PartialEq, Eq, Hash)]
@@ -1490,6 +1721,7 @@ pub mod tests {
-> Result<PseudoClass, ()> {
match_ignore_ascii_case! { &name,
"hover" => Ok(PseudoClass::Hover),
+ "active" => Ok(PseudoClass::Active),
_ => Err(())
}
}
@@ -1503,8 +1735,7 @@ pub mod tests {
}
}
- fn parse_pseudo_element(&self, name: Cow<str>, _input: &mut CssParser)
- -> Result<PseudoElement, ()> {
+ fn parse_pseudo_element(&self, name: Cow<str>) -> Result<PseudoElement, ()> {
match_ignore_ascii_case! { &name,
"before" => Ok(PseudoElement::Before),
"after" => Ok(PseudoElement::After),
@@ -1554,25 +1785,64 @@ pub mod tests {
assert_eq!(parse(":lang(4)"), Err(())) ;
assert_eq!(parse(":lang(en US)"), Err(())) ;
assert_eq!(parse("EeÉ"), Ok(SelectorList(vec!(Selector {
- inner: SelectorInner::from_vec(vec!(Component::LocalName(LocalName {
+ inner: SelectorInner::from_vec(vec!(
+ Component::LocalName(LocalName {
name: DummyAtom::from("EeÉ"),
lower_name: DummyAtom::from("eeÉ") })),
),
- pseudo_element: None,
- specificity: specificity(0, 0, 1),
+ specificity_and_flags: specificity(0, 0, 1),
+ }))));
+ assert_eq!(parse("|e"), Ok(SelectorList(vec!(Selector {
+ inner: SelectorInner::from_vec(vec!(
+ Component::ExplicitNoNamespace,
+ Component::LocalName(LocalName {
+ name: DummyAtom::from("e"),
+ lower_name: DummyAtom::from("e")
+ }),
+ )),
+ specificity_and_flags: specificity(0, 0, 1),
+ }))));
+ // https://github.com/servo/servo/issues/16020
+ assert_eq!(parse("*|e"), Ok(SelectorList(vec!(Selector {
+ inner: SelectorInner::from_vec(vec!(
+ Component::ExplicitAnyNamespace,
+ Component::LocalName(LocalName {
+ name: DummyAtom::from("e"),
+ lower_name: DummyAtom::from("e")
+ }),
+ )),
+ specificity_and_flags: specificity(0, 0, 1),
+ }))));
+ assert_eq!(parse("*"), Ok(SelectorList(vec!(Selector {
+ inner: SelectorInner::from_vec(vec!(
+ Component::ExplicitUniversalType,
+ )),
+ specificity_and_flags: specificity(0, 0, 0),
+ }))));
+ assert_eq!(parse("|*"), Ok(SelectorList(vec!(Selector {
+ inner: SelectorInner::from_vec(vec!(
+ Component::ExplicitNoNamespace,
+ Component::ExplicitUniversalType,
+ )),
+ specificity_and_flags: specificity(0, 0, 0),
+ }))));
+ assert_eq!(parse("*|*"), Ok(SelectorList(vec!(Selector {
+ inner: SelectorInner::from_vec(vec!(
+ Component::ExplicitAnyNamespace,
+ Component::ExplicitUniversalType,
+ )),
+ specificity_and_flags: specificity(0, 0, 0),
}))));
assert_eq!(parse(".foo:lang(en-US)"), Ok(SelectorList(vec!(Selector {
inner: SelectorInner::from_vec(vec![
Component::Class(DummyAtom::from("foo")),
Component::NonTSPseudoClass(PseudoClass::Lang("en-US".to_owned()))
]),
- pseudo_element: None,
- specificity: specificity(0, 2, 0),
+ specificity_and_flags: specificity(0, 2, 0),
}))));
assert_eq!(parse("#bar"), Ok(SelectorList(vec!(Selector {
inner: SelectorInner::from_vec(vec!(Component::ID(DummyAtom::from("bar")))),
- pseudo_element: None,
- specificity: specificity(1, 0, 0),
+ specificity_and_flags: specificity(1, 0, 0),
}))));
assert_eq!(parse("e.foo#bar"), Ok(SelectorList(vec!(Selector {
inner: SelectorInner::from_vec(vec!(Component::LocalName(LocalName {
@@ -1580,8 +1850,7 @@ pub mod tests {
lower_name: DummyAtom::from("e") }),
Component::Class(DummyAtom::from("foo")),
Component::ID(DummyAtom::from("bar")))),
- pseudo_element: None,
- specificity: specificity(1, 1, 1),
+ specificity_and_flags: specificity(1, 1, 1),
}))));
assert_eq!(parse("e.foo #bar"), Ok(SelectorList(vec!(Selector {
inner: SelectorInner::from_vec(vec!(
@@ -1593,40 +1862,40 @@ pub mod tests {
Component::Combinator(Combinator::Descendant),
Component::ID(DummyAtom::from("bar")),
)),
- pseudo_element: None,
- specificity: specificity(1, 1, 1),
+ specificity_and_flags: specificity(1, 1, 1),
}))));
// Default namespace does not apply to attribute selectors
// https://github.com/mozilla/servo/pull/1652
let mut parser = DummyParser::default();
assert_eq!(parse_ns("[Foo]", &parser), Ok(SelectorList(vec!(Selector {
- inner: SelectorInner::from_vec(vec!(
- Component::AttrExists(AttrSelector {
- name: DummyAtom::from("Foo"),
- lower_name: DummyAtom::from("foo"),
- namespace: NamespaceConstraint::Specific(Namespace {
- prefix: None,
- url: "".into(),
- }) }))),
- pseudo_element: None,
- specificity: specificity(0, 1, 0),
+ inner: SelectorInner::from_vec(vec![
+ Component::AttributeInNoNamespaceExists {
+ local_name: DummyAtom::from("Foo"),
+ local_name_lower: DummyAtom::from("foo"),
+ }
+ ]),
+ specificity_and_flags: specificity(0, 1, 0),
}))));
assert_eq!(parse_ns("svg|circle", &parser), Err(()));
parser.ns_prefixes.insert(DummyAtom("svg".into()), DummyAtom(SVG.into()));
assert_eq!(parse_ns("svg|circle", &parser), Ok(SelectorList(vec![Selector {
inner: SelectorInner::from_vec(
vec![
- Component::Namespace(Namespace {
- prefix: Some(DummyAtom("svg".into())),
- url: SVG.into(),
- }),
+ Component::Namespace(DummyAtom("svg".into()), SVG.into()),
Component::LocalName(LocalName {
name: DummyAtom::from("circle"),
lower_name: DummyAtom::from("circle"),
})
]),
- pseudo_element: None,
- specificity: specificity(0, 0, 1),
+ specificity_and_flags: specificity(0, 0, 1),
+ }])));
+ assert_eq!(parse_ns("svg|*", &parser), Ok(SelectorList(vec![Selector {
+ inner: SelectorInner::from_vec(
+ vec![
+ Component::Namespace(DummyAtom("svg".into()), SVG.into()),
+ Component::ExplicitUniversalType,
+ ]),
+ specificity_and_flags: specificity(0, 0, 0),
}])));
// Default namespace does not apply to attribute selectors
// https://github.com/mozilla/servo/pull/1652
@@ -1636,58 +1905,123 @@ pub mod tests {
assert_eq!(parse_ns("[Foo]", &parser), Ok(SelectorList(vec!(Selector {
inner: SelectorInner::from_vec(
vec![
- Component::Namespace(Namespace {
- prefix: None,
- url: MATHML.into(),
- }),
- Component::AttrExists(AttrSelector {
- name: DummyAtom::from("Foo"),
- lower_name: DummyAtom::from("foo"),
- namespace: NamespaceConstraint::Specific(Namespace {
- prefix: None,
- url: "".into(),
- }),
- }),
+ Component::DefaultNamespace(MATHML.into()),
+ Component::AttributeInNoNamespaceExists {
+ local_name: DummyAtom::from("Foo"),
+ local_name_lower: DummyAtom::from("foo"),
+ },
]),
- pseudo_element: None,
- specificity: specificity(0, 1, 0),
+ specificity_and_flags: specificity(0, 1, 0),
}))));
// Default namespace does apply to type selectors
assert_eq!(parse_ns("e", &parser), Ok(SelectorList(vec!(Selector {
inner: SelectorInner::from_vec(
vec!(
- Component::Namespace(Namespace {
- prefix: None,
- url: MATHML.into(),
- }),
+ Component::DefaultNamespace(MATHML.into()),
Component::LocalName(LocalName {
name: DummyAtom::from("e"),
lower_name: DummyAtom::from("e") }),
)),
- pseudo_element: None,
- specificity: specificity(0, 0, 1),
+ specificity_and_flags: specificity(0, 0, 1),
+ }))));
+ assert_eq!(parse_ns("*", &parser), Ok(SelectorList(vec!(Selector {
+ inner: SelectorInner::from_vec(
+ vec!(
+ Component::DefaultNamespace(MATHML.into()),
+ Component::ExplicitUniversalType,
+ )),
+ specificity_and_flags: specificity(0, 0, 0),
+ }))));
+ assert_eq!(parse_ns("*|*", &parser), Ok(SelectorList(vec!(Selector {
+ inner: SelectorInner::from_vec(
+ vec!(
+ Component::ExplicitAnyNamespace,
+ Component::ExplicitUniversalType,
+ )),
+ specificity_and_flags: specificity(0, 0, 0),
+ }))));
+ // Default namespace applies to universal and type selectors inside :not and :matches,
+ // but not otherwise.
+ assert_eq!(parse_ns(":not(.cl)", &parser), Ok(SelectorList(vec!(Selector {
+ inner: SelectorInner::from_vec(vec!(
+ Component::DefaultNamespace(MATHML.into()),
+ Component::Negation(vec![
+ Component::Class(DummyAtom::from("cl"))
+ ].into_boxed_slice()),
+ )),
+ specificity_and_flags: specificity(0, 1, 0),
+ }))));
+ assert_eq!(parse_ns(":not(*)", &parser), Ok(SelectorList(vec!(Selector {
+ inner: SelectorInner::from_vec(vec!(
+ Component::DefaultNamespace(MATHML.into()),
+ Component::Negation(vec![
+ Component::DefaultNamespace(MATHML.into()),
+ Component::ExplicitUniversalType,
+ ].into_boxed_slice()),
+ )),
+ specificity_and_flags: specificity(0, 0, 0),
+ }))));
+ assert_eq!(parse_ns(":not(e)", &parser), Ok(SelectorList(vec!(Selector {
+ inner: SelectorInner::from_vec(vec!(
+ Component::DefaultNamespace(MATHML.into()),
+ Component::Negation(vec![
+ Component::DefaultNamespace(MATHML.into()),
+ Component::LocalName(LocalName {
+ name: DummyAtom::from("e"),
+ lower_name: DummyAtom::from("e")
+ }),
+ ].into_boxed_slice())
+ )),
+ specificity_and_flags: specificity(0, 0, 1),
}))));
assert_eq!(parse("[attr |= \"foo\"]"), Ok(SelectorList(vec![Selector {
inner: SelectorInner::from_vec(
vec![
- Component::AttrDashMatch(AttrSelector {
- name: DummyAtom::from("attr"),
- lower_name: DummyAtom::from("attr"),
- namespace: NamespaceConstraint::Specific(Namespace {
- prefix: None,
- url: "".into(),
- }),
- }, DummyAtom::from("foo"))
+ Component::AttributeInNoNamespace {
+ local_name: DummyAtom::from("attr"),
+ local_name_lower: DummyAtom::from("attr"),
+ operator: AttrSelectorOperator::DashMatch,
+ value: DummyAtom::from("foo"),
+ never_matches: false,
+ case_sensitivity: ParsedCaseSensitivity::CaseSensitive,
+ }
]),
- pseudo_element: None,
- specificity: specificity(0, 1, 0),
+ specificity_and_flags: specificity(0, 1, 0),
}])));
// https://github.com/mozilla/servo/issues/1723
assert_eq!(parse("::before"), Ok(SelectorList(vec!(Selector {
- inner: SelectorInner::from_vec(vec![]),
- pseudo_element: Some(PseudoElement::Before),
- specificity: specificity(0, 0, 1),
+ inner: SelectorInner::from_vec(
+ vec![
+ Component::PseudoElement(PseudoElement::Before),
+ ]
+ ),
+ specificity_and_flags: specificity(0, 0, 1) | HAS_PSEUDO_BIT,
+ }))));
+ assert_eq!(parse("::before:hover"), Ok(SelectorList(vec!(Selector {
+ inner: SelectorInner::from_vec(
+ vec![
+ Component::PseudoElement(PseudoElement::Before),
+ Component::NonTSPseudoClass(PseudoClass::Hover),
+ ]
+ ),
+ specificity_and_flags: specificity(0, 1, 1) | HAS_PSEUDO_BIT,
+ }))));
+ assert_eq!(parse("::before:hover:hover"), Ok(SelectorList(vec!(Selector {
+ inner: SelectorInner::from_vec(
+ vec![
+ Component::PseudoElement(PseudoElement::Before),
+ Component::NonTSPseudoClass(PseudoClass::Hover),
+ Component::NonTSPseudoClass(PseudoClass::Hover),
+ ]
+ ),
+ specificity_and_flags: specificity(0, 2, 1) | HAS_PSEUDO_BIT,
}))));
+ assert_eq!(parse("::before:hover:active"), Err(()));
+ assert_eq!(parse("::before:hover .foo"), Err(()));
+ assert_eq!(parse("::before .foo"), Err(()));
+ assert_eq!(parse("::before ~ bar"), Err(()));
+ assert_eq!(parse("::before:active"), Err(()));
+
// https://github.com/servo/servo/issues/15335
assert_eq!(parse(":: before"), Err(()));
assert_eq!(parse("div ::after"), Ok(SelectorList(vec!(Selector {
@@ -1697,9 +2031,10 @@ pub mod tests {
name: DummyAtom::from("div"),
lower_name: DummyAtom::from("div") }),
Component::Combinator(Combinator::Descendant),
+ Component::Combinator(Combinator::PseudoElement),
+ Component::PseudoElement(PseudoElement::After),
]),
- pseudo_element: Some(PseudoElement::After),
- specificity: specificity(0, 0, 2),
+ specificity_and_flags: specificity(0, 0, 2) | HAS_PSEUDO_BIT,
}))));
assert_eq!(parse("#d1 > .ok"), Ok(SelectorList(vec![Selector {
inner: SelectorInner::from_vec(
@@ -1708,8 +2043,7 @@ pub mod tests {
Component::Combinator(Combinator::Child),
Component::Class(DummyAtom::from("ok")),
]),
- pseudo_element: None,
- specificity: (1 << 20) + (1 << 10) + (0 << 0),
+ specificity_and_flags: (1 << 20) + (1 << 10) + (0 << 0),
}])));
parser.default_ns = None;
assert_eq!(parse(":not(#provel.old)"), Err(()));
@@ -1721,25 +2055,86 @@ pub mod tests {
Component::ID(DummyAtom::from("provel")),
].into_boxed_slice()
))),
- pseudo_element: None,
- specificity: specificity(1, 0, 0),
+ specificity_and_flags: specificity(1, 0, 0),
}))));
assert_eq!(parse_ns(":not(svg|circle)", &parser), Ok(SelectorList(vec!(Selector {
inner: SelectorInner::from_vec(vec!(Component::Negation(
vec![
- Component::Namespace(Namespace {
- prefix: Some(DummyAtom("svg".into())),
- url: SVG.into(),
- }),
+ Component::Namespace(DummyAtom("svg".into()), SVG.into()),
Component::LocalName(LocalName {
name: DummyAtom::from("circle"),
lower_name: DummyAtom::from("circle")
}),
].into_boxed_slice()
))),
- pseudo_element: None,
- specificity: specificity(0, 0, 1),
+ specificity_and_flags: specificity(0, 0, 1),
}))));
+ // https://github.com/servo/servo/issues/16017
+ assert_eq!(parse_ns(":not(*)", &parser), Ok(SelectorList(vec!(Selector {
+ inner: SelectorInner::from_vec(vec!(Component::Negation(
+ vec![
+ Component::ExplicitUniversalType,
+ ].into_boxed_slice()
+ ))),
+ specificity_and_flags: specificity(0, 0, 0),
+ }))));
+ assert_eq!(parse_ns(":not(|*)", &parser), Ok(SelectorList(vec!(Selector {
+ inner: SelectorInner::from_vec(vec!(Component::Negation(
+ vec![
+ Component::ExplicitNoNamespace,
+ Component::ExplicitUniversalType,
+ ].into_boxed_slice()
+ ))),
+ specificity_and_flags: specificity(0, 0, 0),
+ }))));
+ assert_eq!(parse_ns(":not(*|*)", &parser), Ok(SelectorList(vec!(Selector {
+ inner: SelectorInner::from_vec(vec!(Component::Negation(
+ vec![
+ Component::ExplicitAnyNamespace,
+ Component::ExplicitUniversalType,
+ ].into_boxed_slice()
+ ))),
+ specificity_and_flags: specificity(0, 0, 0),
+ }))));
+ assert_eq!(parse_ns(":not(svg|*)", &parser), Ok(SelectorList(vec!(Selector {
+ inner: SelectorInner::from_vec(vec!(Component::Negation(
+ vec![
+ Component::Namespace(DummyAtom("svg".into()), SVG.into()),
+ Component::ExplicitUniversalType,
+ ].into_boxed_slice()
+ ))),
+ specificity_and_flags: specificity(0, 0, 0),
+ }))));
+ }
+
+ #[test]
+ fn test_pseudo_iter() {
+ let selector = &parse("q::before").unwrap().0[0];
+ assert!(!selector.is_universal());
+ let mut iter = selector.inner.complex.iter();
+ assert_eq!(iter.next(), Some(&Component::PseudoElement(PseudoElement::Before)));
+ assert_eq!(iter.next(), None);
+ let combinator = iter.next_sequence();
+ assert_eq!(combinator, Some(Combinator::PseudoElement));
+ assert!(matches!(iter.next(), Some(&Component::LocalName(..))));
+ assert_eq!(iter.next(), None);
+ assert_eq!(iter.next_sequence(), None);
+ }
+
+ #[test]
+ fn test_universal() {
+ let selector = &parse("*|*::before").unwrap().0[0];
+ assert!(selector.is_universal());
+ }
+
+ #[test]
+ fn test_empty_pseudo_iter() {
+ let selector = &parse("::before").unwrap().0[0];
+ assert!(selector.is_universal());
+ let mut iter = selector.inner.complex.iter();
+ assert_eq!(iter.next(), Some(&Component::PseudoElement(PseudoElement::Before)));
+ assert_eq!(iter.next(), None);
+ assert_eq!(iter.next_sequence(), None);
}
struct TestVisitor {
@@ -1762,5 +2157,9 @@ pub mod tests {
let mut test_visitor = TestVisitor { seen: vec![], };
parse(":not(:hover) ~ label").unwrap().0[0].visit(&mut test_visitor);
assert!(test_visitor.seen.contains(&":hover".into()));
+
+ let mut test_visitor = TestVisitor { seen: vec![], };
+ parse("::before:hover").unwrap().0[0].visit(&mut test_visitor);
+ assert!(test_visitor.seen.contains(&":hover".into()));
}
}
diff --git a/components/selectors/size_of_tests.rs b/components/selectors/size_of_tests.rs
index 1d06278abd5..5fec3085fcb 100644
--- a/components/selectors/size_of_tests.rs
+++ b/components/selectors/size_of_tests.rs
@@ -3,21 +3,25 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use cssparser::ToCss;
+use gecko_like_types;
use gecko_like_types::*;
+use parser;
use parser::*;
use precomputed_hash::PrecomputedHash;
use std::fmt;
use visitor::SelectorVisitor;
-size_of_test!(size_of_selector, Selector<Impl>, 72);
-size_of_test!(size_of_pseudo_element, PseudoElementSelector, 16);
+size_of_test!(size_of_selector, Selector<Impl>, 48);
+size_of_test!(size_of_pseudo_element, gecko_like_types::PseudoElement, 1);
size_of_test!(size_of_selector_inner, SelectorInner<Impl>, 40);
size_of_test!(size_of_complex_selector, ComplexSelector<Impl>, 24);
-size_of_test!(size_of_component, Component<Impl>, 64);
-size_of_test!(size_of_attr_selector, AttrSelector<Impl>, 48);
+size_of_test!(size_of_component, Component<Impl>, 32);
size_of_test!(size_of_pseudo_class, PseudoClass, 24);
+impl parser::PseudoElement for gecko_like_types::PseudoElement {
+ type Impl = Impl;
+}
// Boilerplate
@@ -31,7 +35,7 @@ impl SelectorImpl for Impl {
type BorrowedLocalName = Atom;
type BorrowedNamespaceUrl = Atom;
type NonTSPseudoClass = PseudoClass;
- type PseudoElementSelector = PseudoElementSelector;
+ type PseudoElement = gecko_like_types::PseudoElement;
}
impl SelectorMethods for PseudoClass {
@@ -45,7 +49,7 @@ impl ToCss for PseudoClass {
fn to_css<W>(&self, _: &mut W) -> fmt::Result where W: fmt::Write { unimplemented!() }
}
-impl ToCss for PseudoElementSelector {
+impl ToCss for gecko_like_types::PseudoElement {
fn to_css<W>(&self, _: &mut W) -> fmt::Result where W: fmt::Write { unimplemented!() }
}
diff --git a/components/selectors/tree.rs b/components/selectors/tree.rs
index abd56e85cd4..276c788d05b 100644
--- a/components/selectors/tree.rs
+++ b/components/selectors/tree.rs
@@ -5,147 +5,61 @@
//! Traits that nodes must implement. Breaks the otherwise-cyclic dependency between layout and
//! style.
-use matching::{ElementSelectorFlags, StyleRelations};
-use parser::{AttrSelector, SelectorImpl};
-use std::ascii::AsciiExt;
+use attr::{AttrSelectorOperation, NamespaceConstraint};
+use matching::{ElementSelectorFlags, MatchingContext};
+use parser::SelectorImpl;
-/// The definition of whitespace per CSS Selectors Level 3 § 4.
-pub static SELECTOR_WHITESPACE: &'static [char] = &[' ', '\t', '\n', '\r', '\x0C'];
-
-// Attribute matching routines. Consumers with simple implementations can implement
-// MatchAttrGeneric instead.
-pub trait MatchAttr {
- type Impl: SelectorImpl;
-
- fn match_attr_has(
- &self,
- attr: &AttrSelector<Self::Impl>) -> bool;
-
- fn match_attr_equals(
- &self,
- attr: &AttrSelector<Self::Impl>,
- value: &<Self::Impl as SelectorImpl>::AttrValue) -> bool;
-
- fn match_attr_equals_ignore_ascii_case(
- &self,
- attr: &AttrSelector<Self::Impl>,
- value: &<Self::Impl as SelectorImpl>::AttrValue) -> bool;
-
- fn match_attr_includes(
- &self,
- attr: &AttrSelector<Self::Impl>,
- value: &<Self::Impl as SelectorImpl>::AttrValue) -> bool;
-
- fn match_attr_dash(
- &self,
- attr: &AttrSelector<Self::Impl>,
- value: &<Self::Impl as SelectorImpl>::AttrValue) -> bool;
-
- fn match_attr_prefix(
- &self,
- attr: &AttrSelector<Self::Impl>,
- value: &<Self::Impl as SelectorImpl>::AttrValue) -> bool;
-
- fn match_attr_substring(
- &self,
- attr: &AttrSelector<Self::Impl>,
- value: &<Self::Impl as SelectorImpl>::AttrValue) -> bool;
-
- fn match_attr_suffix(
- &self,
- attr: &AttrSelector<Self::Impl>,
- value: &<Self::Impl as SelectorImpl>::AttrValue) -> bool;
-}
-
-pub trait MatchAttrGeneric {
+pub trait Element: Sized {
type Impl: SelectorImpl;
- fn match_attr<F>(&self, attr: &AttrSelector<Self::Impl>, test: F) -> bool where F: Fn(&str) -> bool;
-}
-
-impl<T> MatchAttr for T where T: MatchAttrGeneric, T::Impl: SelectorImpl<AttrValue = String> {
- type Impl = T::Impl;
-
- fn match_attr_has(&self, attr: &AttrSelector<Self::Impl>) -> bool {
- self.match_attr(attr, |_| true)
- }
-
- fn match_attr_equals(&self, attr: &AttrSelector<Self::Impl>, value: &String) -> bool {
- self.match_attr(attr, |v| v == value)
- }
-
- fn match_attr_equals_ignore_ascii_case(&self, attr: &AttrSelector<Self::Impl>,
- value: &String) -> bool {
- self.match_attr(attr, |v| v.eq_ignore_ascii_case(value))
- }
-
- fn match_attr_includes(&self, attr: &AttrSelector<Self::Impl>, value: &String) -> bool {
- self.match_attr(attr, |attr_value| {
- attr_value.split(SELECTOR_WHITESPACE).any(|v| v == value)
- })
- }
- fn match_attr_dash(&self, attr: &AttrSelector<Self::Impl>, value: &String) -> bool {
- self.match_attr(attr, |attr_value| {
- // The attribute must start with the pattern.
- if !attr_value.starts_with(value) {
- return false
- }
-
- // If the strings are the same, we're done.
- if attr_value.len() == value.len() {
- return true
- }
-
- // The attribute is long than the pattern, so the next character must be '-'.
- attr_value.as_bytes()[value.len()] == '-' as u8
- })
- }
-
- fn match_attr_prefix(&self, attr: &AttrSelector<Self::Impl>, value: &String) -> bool {
- self.match_attr(attr, |attr_value| {
- attr_value.starts_with(value)
- })
- }
-
- fn match_attr_substring(&self, attr: &AttrSelector<Self::Impl>, value: &String) -> bool {
- self.match_attr(attr, |attr_value| {
- attr_value.contains(value)
- })
- }
+ fn parent_element(&self) -> Option<Self>;
- fn match_attr_suffix(&self, attr: &AttrSelector<Self::Impl>, value: &String) -> bool {
- self.match_attr(attr, |attr_value| {
- attr_value.ends_with(value)
- })
+ /// The parent of a given pseudo-element, after matching a pseudo-element
+ /// selector.
+ ///
+ /// This is guaranteed to be called in a pseudo-element.
+ fn pseudo_element_originating_element(&self) -> Option<Self> {
+ self.parent_element()
}
-}
-pub trait Element: MatchAttr + Sized {
- fn parent_element(&self) -> Option<Self>;
-
- // Skips non-element nodes
+ /// Skips non-element nodes
fn first_child_element(&self) -> Option<Self>;
- // Skips non-element nodes
+ /// Skips non-element nodes
fn last_child_element(&self) -> Option<Self>;
- // Skips non-element nodes
+ /// Skips non-element nodes
fn prev_sibling_element(&self) -> Option<Self>;
- // Skips non-element nodes
+ /// Skips non-element nodes
fn next_sibling_element(&self) -> Option<Self>;
fn is_html_element_in_html_document(&self) -> bool;
+
fn get_local_name(&self) -> &<Self::Impl as SelectorImpl>::BorrowedLocalName;
+
+ /// Empty string for no namespace
fn get_namespace(&self) -> &<Self::Impl as SelectorImpl>::BorrowedNamespaceUrl;
+ fn attr_matches(&self,
+ ns: &NamespaceConstraint<&<Self::Impl as SelectorImpl>::NamespaceUrl>,
+ local_name: &<Self::Impl as SelectorImpl>::LocalName,
+ operation: &AttrSelectorOperation<&<Self::Impl as SelectorImpl>::AttrValue>)
+ -> bool;
+
fn match_non_ts_pseudo_class<F>(&self,
pc: &<Self::Impl as SelectorImpl>::NonTSPseudoClass,
- relations: &mut StyleRelations,
+ context: &mut MatchingContext,
flags_setter: &mut F) -> bool
where F: FnMut(&Self, ElementSelectorFlags);
+ fn match_pseudo_element(&self,
+ pe: &<Self::Impl as SelectorImpl>::PseudoElement,
+ context: &mut MatchingContext)
+ -> bool;
+
fn get_id(&self) -> Option<<Self::Impl as SelectorImpl>::Identifier>;
+
fn has_class(&self, name: &<Self::Impl as SelectorImpl>::ClassName) -> bool;
/// Returns whether this element matches `:empty`.
@@ -160,10 +74,4 @@ pub trait Element: MatchAttr + Sized {
/// Note: this can be false even if `.parent_element()` is `None`
/// if the parent node is a `DocumentFragment`.
fn is_root(&self) -> bool;
-
- // Ordinarily I wouldn't use callbacks like this, but the alternative is
- // really messy, since there is a `JSRef` and a `RefCell` involved. Maybe
- // in the future when we have associated types and/or a more convenient
- // JS GC story... --pcwalton
- fn each_class<F>(&self, callback: F) where F: FnMut(&<Self::Impl as SelectorImpl>::ClassName);
}
diff --git a/components/selectors/visitor.rs b/components/selectors/visitor.rs
index be335aed87b..07f121fe82f 100644
--- a/components/selectors/visitor.rs
+++ b/components/selectors/visitor.rs
@@ -6,8 +6,8 @@
#![deny(missing_docs)]
-use parser::{AttrSelector, Combinator, Component};
-use parser::{SelectorImpl, SelectorIter};
+use attr::NamespaceConstraint;
+use parser::{Combinator, Component, SelectorImpl, SelectorIter};
/// A trait to visit selector properties.
///
@@ -20,7 +20,12 @@ pub trait SelectorVisitor {
/// Visit an attribute selector that may match (there are other selectors
/// that may never match, like those containing whitespace or the empty
/// string).
- fn visit_attribute_selector(&mut self, _: &AttrSelector<Self::Impl>) -> bool {
+ fn visit_attribute_selector(
+ &mut self,
+ _namespace: &NamespaceConstraint<&<Self::Impl as SelectorImpl>::NamespaceUrl>,
+ _local_name: &<Self::Impl as SelectorImpl>::LocalName,
+ _local_name_lower: &<Self::Impl as SelectorImpl>::LocalName,
+ ) -> bool {
true
}
diff --git a/components/servo/lib.rs b/components/servo/lib.rs
index e3afaada420..83362789b05 100644
--- a/components/servo/lib.rs
+++ b/components/servo/lib.rs
@@ -126,6 +126,8 @@ impl<Window> Browser<Window> where Window: WindowMethods + 'static {
// Global configuration options, parsed from the command line.
let opts = opts::get();
+ // Make sure the gl context is made current.
+ window.prepare_for_composite(0, 0);
// Get both endpoints of a special channel for communication between
// the client window and the compositor. This channel is unique because
diff --git a/components/style/Cargo.toml b/components/style/Cargo.toml
index 57bc8e31a97..f9b93b7500d 100644
--- a/components/style/Cargo.toml
+++ b/components/style/Cargo.toml
@@ -14,7 +14,7 @@ doctest = false
[features]
gecko = ["nsstring_vendor", "rayon/unstable", "num_cpus", "style_traits/gecko"]
-use_bindgen = ["bindgen", "regex"]
+use_bindgen = ["bindgen", "regex", "toml"]
servo = ["serde", "serde_derive", "heapsize", "heapsize_derive",
"style_traits/servo", "servo_atoms", "servo_config", "html5ever",
"cssparser/heapsize", "cssparser/serde", "encoding", "smallvec/heapsizeof",
@@ -29,12 +29,13 @@ bitflags = "0.7"
bit-vec = "0.4.3"
byteorder = "1.0"
cfg-if = "0.1.0"
-cssparser = "0.13.3"
+cssparser = "0.13.5"
encoding = {version = "0.2", optional = true}
euclid = "0.11"
fnv = "1.0"
heapsize = {version = "0.3.0", optional = true}
heapsize_derive = {version = "0.1", optional = true}
+itoa = "0.3"
html5ever = {version = "0.16", optional = true}
lazy_static = "0.2"
log = "0.3"
@@ -68,3 +69,4 @@ log = "0.3"
bindgen = { version = "0.25", optional = true }
regex = {version = "0.2", optional = true}
walkdir = "1.0"
+toml = {version = "0.2.1", optional = true, default-features = false}
diff --git a/components/style/attr.rs b/components/style/attr.rs
index bbf8d53a430..535d9109151 100644
--- a/components/style/attr.rs
+++ b/components/style/attr.rs
@@ -12,6 +12,7 @@ use cssparser::{self, Color, RGBA};
use euclid::num::Zero;
use num_traits::ToPrimitive;
use properties::PropertyDeclarationBlock;
+use selectors::attr::AttrSelectorOperation;
use servo_url::ServoUrl;
use shared_lock::Locked;
use std::ascii::AsciiExt;
@@ -349,6 +350,13 @@ impl AttrValue {
panic!("Uint not found");
}
}
+
+ pub fn eval_selector(&self, selector: &AttrSelectorOperation<&String>) -> bool {
+ // FIXME(SimonSapin) this can be more efficient by matching on `(self, selector)` variants
+ // and doing Atom comparisons instead of string comparisons where possible,
+ // with SelectorImpl::AttrValue changed to Atom.
+ selector.eval_str(self)
+ }
}
impl ::std::ops::Deref for AttrValue {
@@ -371,6 +379,15 @@ impl ::std::ops::Deref for AttrValue {
}
}
+impl PartialEq<Atom> for AttrValue {
+ fn eq(&self, other: &Atom) -> bool {
+ match *self {
+ AttrValue::Atom(ref value) => value == other,
+ _ => other == &**self,
+ }
+ }
+}
+
/// https://html.spec.whatwg.org/multipage/#rules-for-parsing-non-zero-dimension-values
pub fn parse_nonzero_length(value: &str) -> LengthOrPercentageOrAuto {
match parse_length(value) {
diff --git a/components/style/build.rs b/components/style/build.rs
index 8d40ccb9969..e5d3b40c204 100644
--- a/components/style/build.rs
+++ b/components/style/build.rs
@@ -10,6 +10,8 @@ extern crate bindgen;
extern crate log;
#[cfg(feature = "bindgen")]
extern crate regex;
+#[cfg(feature = "bindgen")]
+extern crate toml;
extern crate walkdir;
use std::env;
diff --git a/components/style/build_gecko.rs b/components/style/build_gecko.rs
index 6da76e25f42..a6ecb8ac732 100644
--- a/components/style/build_gecko.rs
+++ b/components/style/build_gecko.rs
@@ -29,18 +29,20 @@ mod common {
mod bindings {
use bindgen::{Builder, CodegenConfig};
use bindgen::callbacks::{EnumVariantCustomBehavior, EnumVariantValue, ParseCallbacks};
- use regex::Regex;
+ use regex::{Regex, RegexSet};
use std::cmp;
- use std::collections::HashSet;
+ use std::collections::{HashSet, HashMap};
use std::env;
use std::fs::{self, File};
use std::io::{Read, Write};
use std::path::{Path, PathBuf};
use std::process::{Command, exit};
+ use std::slice;
use std::sync::Mutex;
use std::time::SystemTime;
use super::common::*;
use super::super::PYTHON;
+ use toml;
const STRUCTS_DEBUG_FILE: &'static str = "structs_debug.rs";
const STRUCTS_RELEASE_FILE: &'static str = "structs_release.rs";
@@ -60,6 +62,41 @@ mod bindings {
}
lazy_static! {
+ static ref CONFIG: toml::Table = {
+ let path = PathBuf::from(env::var("MOZ_SRC").unwrap())
+ .join("layout/style/ServoBindings.toml");
+ println!("cargo:rerun-if-changed={}", path.to_str().unwrap());
+ update_last_modified(&path);
+
+ let mut contents = String::new();
+ File::open(path).expect("Failed to open config file")
+ .read_to_string(&mut contents).expect("Failed to read config file");
+ let mut parser = toml::Parser::new(&contents);
+ if let Some(result) = parser.parse() {
+ result
+ } else {
+ use std::fmt::Write;
+ let mut reason = String::from("Failed to parse config file:");
+ for err in parser.errors.iter() {
+ let parsed = &contents[..err.lo];
+ write!(&mut reason, "\n* line {} column {}: {}",
+ parsed.lines().count(),
+ parsed.lines().last().map_or(0, |l| l.len()),
+ err).unwrap();
+ }
+ panic!(reason)
+ }
+ };
+ static ref TARGET_INFO: HashMap<String, String> = {
+ const TARGET_PREFIX: &'static str = "CARGO_CFG_TARGET_";
+ let mut result = HashMap::new();
+ for (k, v) in env::vars() {
+ if k.starts_with(TARGET_PREFIX) {
+ result.insert(k[TARGET_PREFIX.len()..].to_lowercase(), v);
+ }
+ }
+ result
+ };
static ref INCLUDE_RE: Regex = Regex::new(r#"#include\s*"(.+?)""#).unwrap();
static ref DISTDIR_PATH: PathBuf = {
let path = PathBuf::from(env::var("MOZ_DIST").unwrap());
@@ -73,7 +110,7 @@ mod bindings {
DISTDIR_PATH.join("include/nspr"),
];
static ref ADDED_PATHS: Mutex<HashSet<PathBuf>> = Mutex::new(HashSet::new());
- pub static ref LAST_MODIFIED: Mutex<SystemTime> =
+ static ref LAST_MODIFIED: Mutex<SystemTime> =
Mutex::new(get_modified_time(&env::current_exe().unwrap())
.expect("Failed to get modified time of executable"));
}
@@ -82,16 +119,19 @@ mod bindings {
file.metadata().and_then(|m| m.modified()).ok()
}
+ fn update_last_modified(file: &Path) {
+ let modified = get_modified_time(file).unwrap();
+ let mut last_modified = LAST_MODIFIED.lock().unwrap();
+ *last_modified = cmp::max(modified, *last_modified);
+ }
+
fn search_include(name: &str) -> Option<PathBuf> {
for path in SEARCH_PATHS.iter() {
let file = path.join(name);
- if !file.is_file() {
- continue;
+ if file.is_file() {
+ update_last_modified(&file);
+ return Some(file);
}
- let modified = get_modified_time(&file).unwrap();
- let mut last_modified = LAST_MODIFIED.lock().unwrap();
- *last_modified = cmp::max(modified, *last_modified);
- return Some(file);
}
None
}
@@ -124,22 +164,43 @@ mod bindings {
trait BuilderExt {
fn get_initial_builder(build_type: BuildType) -> Builder;
fn include<T: Into<String>>(self, file: T) -> Builder;
- fn zero_size_type(self, ty: &str, structs_list: &[&str]) -> Builder;
+ fn zero_size_type(self, ty: &str, structs_list: &HashSet<&str>) -> Builder;
fn borrowed_type(self, ty: &str) -> Builder;
fn mutable_borrowed_type(self, ty: &str) -> Builder;
}
+ fn add_clang_args(mut builder: Builder, config: &toml::Table, matched_os: &mut bool) -> Builder {
+ fn add_args(mut builder: Builder, values: &[toml::Value]) -> Builder {
+ for item in values.iter() {
+ builder = builder.clang_arg(item.as_str().expect("Expect string in list"));
+ }
+ builder
+ }
+ for (k, v) in config.iter() {
+ if k == "args" {
+ builder = add_args(builder, v.as_slice().unwrap());
+ continue;
+ }
+ let equal_idx = k.find('=').expect(&format!("Invalid key: {}", k));
+ let (target_type, target_value) = k.split_at(equal_idx);
+ if TARGET_INFO[target_type] != target_value[1..] {
+ continue;
+ }
+ if target_type == "os" {
+ *matched_os = true;
+ }
+ builder = match *v {
+ toml::Value::Table(ref table) => add_clang_args(builder, table, matched_os),
+ toml::Value::Array(ref array) => add_args(builder, array),
+ _ => panic!("Unknown type"),
+ };
+ }
+ builder
+ }
+
impl BuilderExt for Builder {
fn get_initial_builder(build_type: BuildType) -> Builder {
let mut builder = Builder::default().no_unstable_rust();
- let args = [
- "-x", "c++", "-std=c++14",
- "-DTRACING=1", "-DIMPL_LIBXUL", "-DMOZ_STYLO_BINDINGS=1",
- "-DMOZILLA_INTERNAL_API", "-DRUST_BINDGEN", "-DMOZ_STYLO"
- ];
- for &arg in args.iter() {
- builder = builder.clang_arg(arg);
- }
for dir in SEARCH_PATHS.iter() {
builder = builder.clang_arg("-I").clang_arg(dir.to_str().unwrap());
}
@@ -148,55 +209,11 @@ mod bindings {
if build_type == BuildType::Debug {
builder = builder.clang_arg("-DDEBUG=1").clang_arg("-DJS_DEBUG=1");
}
- if cfg!(target_family = "unix") {
- builder = builder.clang_arg("-DOS_POSIX=1");
- }
- if cfg!(target_os = "linux") {
- builder = builder.clang_arg("-DOS_LINUX=1");
- // We may be cross-compiling with a clang that defaults to
- // a different architecture, so we should explicitly specify
- // the bitness being used here. Specifying --target instead
- // leads to difficulties with LLVM search paths.
- if cfg!(target_arch = "x86") {
- builder = builder.clang_arg("-m32")
- } else if cfg!(target_arch = "x86_64") {
- builder = builder.clang_arg("-m64")
- }
- } else if cfg!(target_os = "solaris") {
- builder = builder.clang_arg("-DOS_SOLARIS=1");
- } else if cfg!(target_os = "dragonfly") {
- builder = builder.clang_arg("-DOS_BSD=1").clang_arg("-DOS_DRAGONFLY=1");
- } else if cfg!(target_os = "freebsd") {
- builder = builder.clang_arg("-DOS_BSD=1").clang_arg("-DOS_FREEBSD=1");
- } else if cfg!(target_os = "netbsd") {
- builder = builder.clang_arg("-DOS_BSD=1").clang_arg("-DOS_NETBSD=1");
- } else if cfg!(target_os = "openbsd") {
- builder = builder.clang_arg("-DOS_BSD=1").clang_arg("-DOS_OPENBSD=1");
- } else if cfg!(target_os = "macos") {
- builder = builder.clang_arg("-DOS_MACOSX=1")
- .clang_arg("-stdlib=libc++")
- // To disable the fixup bindgen applies which adds search
- // paths from clang command line in order to avoid potential
- // conflict with -stdlib=libc++.
- .clang_arg("--target=x86_64-apple-darwin");
- } else if cfg!(target_env = "msvc") {
- builder = builder.clang_arg("-DOS_WIN=1").clang_arg("-DWIN32=1")
- // For compatibility with MSVC 2015
- .clang_arg("-fms-compatibility-version=19")
- // To enable the builtin __builtin_offsetof so that CRT wouldn't
- // use reinterpret_cast in offsetof() which is not allowed inside
- // static_assert().
- .clang_arg("-D_CRT_USE_BUILTIN_OFFSETOF")
- // Enable hidden attribute (which is not supported by MSVC and
- // thus not enabled by default with a MSVC-compatibile build)
- // to exclude hidden symbols from the generated file.
- .clang_arg("-DHAVE_VISIBILITY_HIDDEN_ATTRIBUTE=1");
- if cfg!(target_pointer_width = "32") {
- builder = builder.clang_arg("--target=i686-pc-win32");
- } else {
- builder = builder.clang_arg("--target=x86_64-pc-win32");
- }
- } else {
+
+ let mut matched_os = false;
+ let build_config = CONFIG["build"].as_table().expect("Malformed config file");
+ builder = add_clang_args(builder, build_config, &mut matched_os);
+ if !matched_os {
panic!("Unknown platform");
}
builder
@@ -212,8 +229,8 @@ mod bindings {
// Not 100% sure of how safe this is, but it's what we're using
// in the XPCOM ffi too
// https://github.com/nikomatsakis/rust-memory-model/issues/2
- fn zero_size_type(self, ty: &str, structs_list: &[&str]) -> Builder {
- if !structs_list.contains(&ty) {
+ fn zero_size_type(self, ty: &str, structs_list: &HashSet<&str>) -> Builder {
+ if !structs_list.contains(ty) {
self.hide_type(ty)
.raw_line(format!("enum {}Void {{ }}", ty))
.raw_line(format!("pub struct {0}({0}Void);", ty))
@@ -284,318 +301,123 @@ mod bindings {
.collect()
}
- #[derive(Debug)]
- struct Callbacks;
- impl ParseCallbacks for Callbacks {
- fn enum_variant_behavior(&self,
- enum_name: Option<&str>,
- variant_name: &str,
- _variant_value: EnumVariantValue)
- -> Option<EnumVariantCustomBehavior> {
- if enum_name.map_or(false, |n| n == "nsCSSPropertyID") &&
- variant_name.starts_with("eCSSProperty_COUNT") {
- Some(EnumVariantCustomBehavior::Constify)
- } else {
- None
+ struct BuilderWithConfig<'a> {
+ builder: Builder,
+ config: &'a toml::Table,
+ used_keys: HashSet<&'static str>,
+ }
+ impl<'a> BuilderWithConfig<'a> {
+ fn new(builder: Builder, config: &'a toml::Table) -> Self {
+ BuilderWithConfig {
+ builder, config,
+ used_keys: HashSet::new(),
+ }
+ }
+
+ fn handle_list<F>(self, key: &'static str, func: F) -> BuilderWithConfig<'a>
+ where F: FnOnce(Builder, slice::Iter<'a, toml::Value>) -> Builder {
+ let mut builder = self.builder;
+ let config = self.config;
+ let mut used_keys = self.used_keys;
+ if let Some(list) = config.get(key) {
+ used_keys.insert(key);
+ builder = func(builder, list.as_slice().unwrap().iter());
+ }
+ BuilderWithConfig { builder, config, used_keys }
+ }
+ fn handle_items<F>(self, key: &'static str, mut func: F) -> BuilderWithConfig<'a>
+ where F: FnMut(Builder, &'a toml::Value) -> Builder {
+ self.handle_list(key, |b, iter| iter.fold(b, |b, item| func(b, item)))
+ }
+ fn handle_str_items<F>(self, key: &'static str, mut func: F) -> BuilderWithConfig<'a>
+ where F: FnMut(Builder, &'a str) -> Builder {
+ self.handle_items(key, |b, item| func(b, item.as_str().unwrap()))
+ }
+ fn handle_table_items<F>(self, key: &'static str, mut func: F) -> BuilderWithConfig<'a>
+ where F: FnMut(Builder, &'a toml::Table) -> Builder {
+ self.handle_items(key, |b, item| func(b, item.as_table().unwrap()))
+ }
+ fn handle_common(self, fixups: &mut Vec<Fixup>) -> BuilderWithConfig<'a> {
+ self.handle_str_items("headers", |b, item| b.header(add_include(item)))
+ .handle_str_items("raw-lines", |b, item| b.raw_line(item))
+ .handle_str_items("hide-types", |b, item| b.hide_type(item))
+ .handle_table_items("fixups", |builder, item| {
+ fixups.push(Fixup {
+ pat: item["pat"].as_str().unwrap().into(),
+ rep: item["rep"].as_str().unwrap().into(),
+ });
+ builder
+ })
+ }
+
+ fn get_builder(self) -> Builder {
+ for key in self.config.keys() {
+ if !self.used_keys.contains(key.as_str()) {
+ panic!(format!("Unknown key: {}", key));
+ }
}
+ self.builder
}
}
fn generate_structs(build_type: BuildType) {
- let mut builder = Builder::get_initial_builder(build_type)
+ #[derive(Debug)]
+ struct Callbacks(HashMap<String, RegexSet>);
+ impl ParseCallbacks for Callbacks {
+ fn enum_variant_behavior(&self,
+ enum_name: Option<&str>,
+ variant_name: &str,
+ _variant_value: EnumVariantValue)
+ -> Option<EnumVariantCustomBehavior> {
+ enum_name.and_then(|enum_name| self.0.get(enum_name))
+ .and_then(|regex| if regex.is_match(variant_name) {
+ Some(EnumVariantCustomBehavior::Constify)
+ } else {
+ None
+ })
+ }
+ }
+
+ let builder = Builder::get_initial_builder(build_type)
.enable_cxx_namespaces()
.with_codegen_config(CodegenConfig {
types: true,
vars: true,
..CodegenConfig::nothing()
- })
- .header(add_include("nsCSSPseudoClasses.h")) // servo/rust-bindgen#599
- .include(add_include("nsStyleStruct.h"))
- .include(add_include("mozilla/ServoPropPrefList.h"))
- .include(add_include("mozilla/StyleAnimationValue.h"))
- .include(add_include("gfxFontConstants.h"))
- .include(add_include("nsThemeConstants.h"))
- .include(add_include("mozilla/dom/AnimationEffectReadOnlyBinding.h"))
- .include(add_include("mozilla/AnimationPropertySegment.h"))
- .include(add_include("mozilla/ComputedTiming.h"))
- .include(add_include("mozilla/ComputedTimingFunction.h"))
- .include(add_include("mozilla/Keyframe.h"))
- .include(add_include("mozilla/ServoElementSnapshot.h"))
- .include(add_include("mozilla/ServoElementSnapshotTable.h"))
- .include(add_include("mozilla/dom/Element.h"))
- .include(add_include("mozilla/dom/NameSpaceConstants.h"))
- .include(add_include("mozilla/LookAndFeel.h"))
- .include(add_include("mozilla/ServoBindings.h"))
- .include(add_include("nsCSSCounterStyleRule.h"))
- .include(add_include("nsCSSFontFaceRule.h"))
- .include(add_include("nsMediaFeatures.h"))
- .include(add_include("nsMediaList.h"))
- // FIXME(emilio): Incrementally remove these "pub use"s. Probably
- // mozilla::css and mozilla::dom are easier.
- .raw_line("pub use self::root::*;")
- .raw_line("pub use self::root::mozilla::*;")
- .raw_line("pub use self::root::mozilla::css::*;")
- .raw_line("pub use self::root::mozilla::dom::*;")
- .raw_line("use atomic_refcell::AtomicRefCell;")
- .raw_line("use data::ElementData;")
- .hide_type("nsString")
- .bitfield_enum("nsChangeHint")
- .bitfield_enum("nsRestyleHint")
- .constified_enum("UpdateAnimationsTasks")
- .constified_enum("ParsingMode")
- .parse_callbacks(Box::new(Callbacks));
- let whitelist_vars = [
- "NS_AUTHOR_SPECIFIED_.*",
- "NS_THEME_.*",
- "NODE_.*",
- "ELEMENT_.*",
- "NS_FONT_.*",
- "NS_STYLE_.*",
- "NS_MATHML_.*",
- "NS_RADIUS_.*",
- "BORDER_COLOR_.*",
- "BORDER_STYLE_.*",
- "mozilla::SERVO_PREF_.*",
- "CSS_PSEUDO_ELEMENT_.*",
- "SERVO_CSS_PSEUDO_ELEMENT_FLAGS_.*",
- "kNameSpaceID_.*",
- "kGenericFont_.*",
- "kPresContext_.*",
- ];
- let whitelist = [
- "RawGecko.*",
- "mozilla::AnimationPropertySegment",
- "mozilla::ComputedTiming",
- "mozilla::ComputedTimingFunction",
- "mozilla::ComputedTimingFunction::BeforeFlag",
- "mozilla::ServoStyleSheet",
- "mozilla::ServoElementSnapshot.*",
- "mozilla::CSSPseudoClassType",
- "mozilla::css::SheetParsingMode",
- "mozilla::css::URLMatchingFunction",
- "mozilla::HalfCorner",
- "mozilla::PropertyStyleAnimationValuePair",
- "mozilla::TraversalRestyleBehavior",
- "mozilla::TraversalRootBehavior",
- "mozilla::StyleShapeRadius",
- "mozilla::StyleGrid.*",
- "mozilla::UpdateAnimationsTasks",
- "mozilla::LookAndFeel",
- ".*ThreadSafe.*Holder",
- "AnonymousContent",
- "AudioContext",
- "CapturingContentInfo",
- "DefaultDelete",
- "DOMIntersectionObserverEntry",
- "Element",
- "FontFamilyList",
- "FontFamilyListRefCnt",
- "FontFamilyName",
- "FontFamilyType",
- "FontSizePrefs",
- "FragmentOrURL",
- "FrameRequestCallback",
- "GeckoParserExtraData",
- "GeckoFontMetrics",
- "gfxAlternateValue",
- "gfxFontFeature",
- "gfxFontVariation",
- "GridNamedArea",
- "HalfCorner",
- "Image",
- "ImageURL",
- "Keyframe",
- "nsAttrName",
- "nsAttrValue",
- "nsBorderColors",
- "nscolor",
- "nsChangeHint",
- "nsCSSCounterStyleRule",
- "nsCSSFontFaceRule",
- "nsCSSKeyword",
- "nsCSSPropertyID",
- "nsCSSProps",
- "nsCSSRect",
- "nsCSSRect_heap",
- "nsCSSShadowArray",
- "nsCSSValue",
- "nsCSSValueFloatColor",
- "nsCSSValueGradient",
- "nsCSSValueGradientStop",
- "nsCSSValueList",
- "nsCSSValueList_heap",
- "nsCSSValuePair_heap",
- "nsCSSValuePairList",
- "nsCSSValuePairList_heap",
- "nsCSSValueTokenStream",
- "nsCSSValueTriplet_heap",
- "nsCursorImage",
- "nsFont",
- "nsIAtom",
- "nsMainThreadPtrHandle",
- "nsMainThreadPtrHolder",
- "nsMargin",
- "nsMediaExpression",
- "nsMediaFeature",
- "nsMediaFeatures",
- "nsMediaList",
- "nsRect",
- "nsRestyleHint",
- "nsresult",
- "nsSize",
- "nsStyleBackground",
- "nsStyleBorder",
- "nsStyleColor",
- "nsStyleColumn",
- "nsStyleContent",
- "nsStyleContentData",
- "nsStyleContext",
- "nsStyleCoord",
- "nsStyleCounterData",
- "nsStyleDisplay",
- "nsStyleEffects",
- "nsStyleFilter",
- "nsStyleFont",
- "nsStyleGradient",
- "nsStyleGradientStop",
- "nsStyleGridTemplate",
- "nsStyleImage",
- "nsStyleImageLayers",
- "nsStyleList",
- "nsStyleMargin",
- "nsStyleOutline",
- "nsStylePadding",
- "nsStylePosition",
- "nsStyleSVG",
- "nsStyleSVGPaint",
- "nsStyleSVGReset",
- "nsStyleTable",
- "nsStyleTableBorder",
- "nsStyleText",
- "nsStyleTextReset",
- "nsStyleUIReset",
- "nsStyleUnion",
- "nsStyleUnit",
- "nsStyleUserInterface",
- "nsStyleVariables",
- "nsStyleVisibility",
- "nsStyleXUL",
- "nsTArray",
- "nsTArrayHeader",
- "Position",
- "PropertyValuePair",
- "Runnable",
- "ServoAttrSnapshot",
- "ServoBundledURI",
- "ServoElementSnapshot",
- "SheetParsingMode",
- "StaticRefPtr",
- "StyleAnimation",
- "StyleBasicShape",
- "StyleBasicShapeType",
- "StyleGeometryBox",
- "StyleShapeSource",
- "StyleTransition",
- "mozilla::UniquePtr",
- "mozilla::DefaultDelete",
- "mozilla::Side",
- "mozilla::binding_danger::AssertAndSuppressCleanupPolicy",
- "mozilla::ParsingMode",
- "mozilla::InheritTarget",
- ];
- let opaque_types = [
- "std::pair__PCCP",
- "std::namespace::atomic___base", "std::atomic__My_base",
- "std::atomic",
- "std::atomic___base",
- "mozilla::gfx::.*",
- "FallibleTArray",
- "mozilla::dom::Sequence",
- "mozilla::dom::Optional",
- "mozilla::dom::Nullable",
- "RefPtr_Proxy",
- "RefPtr_Proxy_member_function",
- "nsAutoPtr_Proxy",
- "nsAutoPtr_Proxy_member_function",
- "mozilla::detail::PointerType",
- "mozilla::Pair_Base",
- "mozilla::SupportsWeakPtr",
- "SupportsWeakPtr",
- "mozilla::detail::WeakReference",
- "mozilla::WeakPtr",
- "nsWritingIterator_reference", "nsReadingIterator_reference",
- "nsTObserverArray", // <- Inherits from nsAutoTObserverArray<T, 0>
- "nsTHashtable", // <- Inheriting from inner typedefs that clang
- // doesn't expose properly.
- "nsRefPtrHashtable", "nsDataHashtable", "nsClassHashtable", // <- Ditto
- "nsIDocument_SelectorCache", // <- Inherits from nsExpirationTracker<.., 4>
- "nsIPresShell_ScrollAxis", // <- For some reason the alignment of this is 4
- // for clang.
- "nsPIDOMWindow", // <- Takes the vtable from a template parameter, and we can't
- // generate it conditionally.
- "JS::Rooted",
- "mozilla::Maybe",
- "gfxSize", // <- union { struct { T width; T height; }; T components[2] };
- "gfxSize_Super", // Ditto.
- "mozilla::ErrorResult", // Causes JSWhyMagic to be included & handled incorrectly.
- "mozilla::StyleAnimationValue",
- "StyleAnimationValue", // pulls in a whole bunch of stuff we don't need in the bindings
- ];
- let blacklist = [
- ".*char_traits",
- ".*incompatible_char_type",
- ];
-
- struct MappedGenericType {
- generic: bool,
- gecko: &'static str,
- servo: &'static str,
- }
- let servo_mapped_generic_types = [
- MappedGenericType {
- generic: true,
- gecko: "mozilla::ServoUnsafeCell",
- servo: "::std::cell::UnsafeCell"
- },
- MappedGenericType {
- generic: true,
- gecko: "mozilla::ServoCell",
- servo: "::std::cell::Cell"
- },
- MappedGenericType {
- generic: false,
- gecko: "ServoNodeData",
- servo: "AtomicRefCell<ElementData>",
- }
- ];
- let mut fixups = vec![
- Fixup {
- pat: "root::nsString".into(),
- rep: "::nsstring::nsStringRepr".into()
- },
- ];
- for &var in whitelist_vars.iter() {
- builder = builder.whitelisted_var(var);
- }
- for &ty in whitelist.iter() {
- builder = builder.whitelisted_type(ty);
- }
- for &ty in opaque_types.iter() {
- builder = builder.opaque_type(ty);
- }
- for &ty in blacklist.iter() {
- builder = builder.hide_type(ty);
- }
- for ty in servo_mapped_generic_types.iter() {
- let gecko_name = ty.gecko.rsplit("::").next().unwrap();
- builder = builder.hide_type(ty.gecko)
- .raw_line(format!("pub type {0}{2} = {1}{2};", gecko_name, ty.servo,
- if ty.generic { "<T>" } else { "" }));
- fixups.push(Fixup {
- pat: format!("root::{}", ty.gecko),
- rep: format!("::gecko_bindings::structs::{}", gecko_name)
});
- }
+ let mut fixups = vec![];
+ let builder = BuilderWithConfig::new(builder, CONFIG["structs"].as_table().unwrap())
+ .handle_common(&mut fixups)
+ .handle_str_items("bitfield-enums", |b, item| b.bitfield_enum(item))
+ .handle_str_items("constified-enums", |b, item| b.constified_enum(item))
+ .handle_str_items("whitelist-vars", |b, item| b.whitelisted_var(item))
+ .handle_str_items("whitelist-types", |b, item| b.whitelisted_type(item))
+ .handle_str_items("opaque-types", |b, item| b.opaque_type(item))
+ .handle_list("constified-enum-variants", |builder, iter| {
+ let mut map = HashMap::new();
+ for item in iter {
+ let item = item.as_table().unwrap();
+ let name = item["enum"].as_str().unwrap();
+ let variants = item["variants"].as_slice().unwrap().iter()
+ .map(|item| item.as_str().unwrap());
+ map.insert(name.into(), RegexSet::new(variants).unwrap());
+ }
+ builder.parse_callbacks(Box::new(Callbacks(map)))
+ })
+ .handle_table_items("mapped-generic-types", |builder, item| {
+ let generic = item["generic"].as_bool().unwrap();
+ let gecko = item["gecko"].as_str().unwrap();
+ let servo = item["servo"].as_str().unwrap();
+ let gecko_name = gecko.rsplit("::").next().unwrap();
+ fixups.push(Fixup {
+ pat: format!("root::{}", gecko),
+ rep: format!("::gecko_bindings::structs::{}", gecko_name)
+ });
+ builder.hide_type(gecko)
+ .raw_line(format!("pub type {0}{2} = {1}{2};", gecko_name, servo,
+ if generic { "<T>" } else { "" }))
+ })
+ .get_builder();
write_binding_file(builder, structs_file(build_type), &fixups);
}
@@ -645,183 +467,62 @@ mod bindings {
}
fn generate_bindings() {
- let mut builder = Builder::get_initial_builder(BuildType::Release)
+ let builder = Builder::get_initial_builder(BuildType::Release)
.disable_name_namespacing()
.with_codegen_config(CodegenConfig {
functions: true,
..CodegenConfig::nothing()
+ });
+ let config = CONFIG["bindings"].as_table().unwrap();
+ let mut structs_types = HashSet::new();
+ let mut fixups = vec![];
+ let mut builder = BuilderWithConfig::new(builder, config)
+ .handle_common(&mut fixups)
+ .handle_str_items("whitelist-functions", |b, item| b.whitelisted_function(item))
+ .handle_str_items("structs-types", |mut builder, ty| {
+ builder = builder.hide_type(ty)
+ .raw_line(format!("use gecko_bindings::structs::{};", ty));
+ structs_types.insert(ty);
+ // TODO this is hacky, figure out a better way to do it without
+ // hardcoding everything...
+ if ty.starts_with("nsStyle") {
+ builder = builder
+ .raw_line(format!("unsafe impl Send for {} {{}}", ty))
+ .raw_line(format!("unsafe impl Sync for {} {{}}", ty));
+ }
+ builder
})
- .header(add_include("mozilla/ServoBindings.h"))
- .hide_type("nsACString_internal")
- .hide_type("nsAString_internal")
- .raw_line("pub use nsstring::{nsACString, nsAString, nsString};")
- .raw_line("type nsACString_internal = nsACString;")
- .raw_line("type nsAString_internal = nsAString;")
- .whitelisted_function("Servo_.*")
- .whitelisted_function("Gecko_.*");
- let structs_types = [
- "mozilla::css::GridTemplateAreasValue",
- "mozilla::css::ImageValue",
- "mozilla::css::URLValue",
- "mozilla::Side",
- "RawGeckoAnimationPropertySegment",
- "RawGeckoComputedTiming",
- "RawGeckoDocument",
- "RawGeckoElement",
- "RawGeckoKeyframeList",
- "RawGeckoComputedKeyframeValuesList",
- "RawGeckoFontFaceRuleList",
- "RawGeckoNode",
- "RawGeckoAnimationValueList",
- "RawServoAnimationValue",
- "RawServoDeclarationBlock",
- "RawServoStyleRule",
- "RawGeckoPresContext",
- "RawGeckoPresContextOwned",
- "RawGeckoStyleAnimationList",
- "RawGeckoServoStyleRuleList",
- "RawGeckoURLExtraData",
- "RefPtr",
- "CSSPseudoClassType",
- "CSSPseudoElementType",
- "TraversalRestyleBehavior",
- "TraversalRootBehavior",
- "ComputedTimingFunction_BeforeFlag",
- "FontFamilyList",
- "FontFamilyType",
- "FontSizePrefs",
- "GeckoFontMetrics",
- "Keyframe",
- "ServoBundledURI",
- "ServoElementSnapshot",
- "ServoElementSnapshotTable",
- "SheetParsingMode",
- "StyleBasicShape",
- "StyleBasicShapeType",
- "StyleShapeSource",
- "StyleTransition",
- "nsCSSCounterStyleRule",
- "nsCSSFontFaceRule",
- "nsCSSKeyword",
- "nsCSSPropertyID",
- "nsCSSShadowArray",
- "nsCSSUnit",
- "nsCSSValue",
- "nsCSSValueSharedList",
- "nsChangeHint",
- "nsCursorImage",
- "nsFont",
- "nsIAtom",
- "nsCompatibility",
- "nsMediaFeature",
- "nsRestyleHint",
- "nsStyleBackground",
- "nsStyleBorder",
- "nsStyleColor",
- "nsStyleColumn",
- "nsStyleContent",
- "nsStyleContentData",
- "nsStyleContentType",
- "nsStyleContext",
- "nsStyleCoord",
- "nsStyleCoord_Calc",
- "nsStyleCoord_CalcValue",
- "nsStyleDisplay",
- "nsStyleEffects",
- "nsStyleFilter",
- "nsStyleFont",
- "nsStyleGradient",
- "nsStyleGradientStop",
- "nsStyleGridTemplate",
- "nsStyleImage",
- "nsStyleImageLayers",
- "nsStyleImageLayers_Layer",
- "nsStyleImageLayers_LayerType",
- "nsStyleImageRequest",
- "nsStyleList",
- "nsStyleMargin",
- "nsStyleOutline",
- "nsStylePadding",
- "nsStylePosition",
- "nsStyleQuoteValues",
- "nsStyleSVG",
- "nsStyleSVGPaint",
- "nsStyleSVGReset",
- "nsStyleTable",
- "nsStyleTableBorder",
- "nsStyleText",
- "nsStyleTextReset",
- "nsStyleUIReset",
- "nsStyleUnion",
- "nsStyleUnit",
- "nsStyleUserInterface",
- "nsStyleVariables",
- "nsStyleVisibility",
- "nsStyleXUL",
- "nsTimingFunction",
- "nscolor",
- "nscoord",
- "nsresult",
- "Loader",
- "ServoStyleSheet",
- "EffectCompositor_CascadeLevel",
- "UpdateAnimationsTasks",
- "ParsingMode",
- "InheritTarget",
- "URLMatchingFunction",
- ];
- struct ArrayType {
- cpp_type: &'static str,
- rust_type: &'static str
- }
- let array_types = [
- ArrayType { cpp_type: "uintptr_t", rust_type: "usize" },
- ];
- struct ServoOwnedType {
- name: &'static str,
- opaque: bool,
- }
- let servo_owned_types = [
- ServoOwnedType { name: "RawServoStyleSet", opaque: true },
- ServoOwnedType { name: "StyleChildrenIterator", opaque: true },
- ServoOwnedType { name: "ServoElementSnapshot", opaque: false },
- ServoOwnedType { name: "RawServoAnimationValueMap", opaque: true },
- ];
- let servo_immutable_borrow_types = [
- "RawGeckoNode",
- "RawGeckoElement",
- "RawGeckoDocument",
- "RawServoDeclarationBlockStrong",
- "RawGeckoPresContext",
- "RawGeckoStyleAnimationList",
- ];
- let servo_borrow_types = [
- "nsCSSValue",
- "nsTimingFunction",
- "RawGeckoAnimationPropertySegment",
- "RawGeckoAnimationValueList",
- "RawGeckoComputedTiming",
- "RawGeckoKeyframeList",
- "RawGeckoComputedKeyframeValuesList",
- "RawGeckoFontFaceRuleList",
- "RawGeckoServoStyleRuleList",
- ];
- for &ty in structs_types.iter() {
- builder = builder.hide_type(ty)
- .raw_line(format!("use gecko_bindings::structs::{};", ty));
- // TODO this is hacky, figure out a better way to do it without
- // hardcoding everything...
- if ty.starts_with("nsStyle") {
- builder = builder
- .raw_line(format!("unsafe impl Send for {} {{}}", ty))
- .raw_line(format!("unsafe impl Sync for {} {{}}", ty));
- }
- }
- for &ArrayType { cpp_type, rust_type } in array_types.iter() {
- builder = builder.hide_type(format!("nsTArrayBorrowed_{}", cpp_type))
- .raw_line(format!("pub type nsTArrayBorrowed_{}<'a> = &'a mut ::gecko_bindings::structs::nsTArray<{}>;",
- cpp_type, rust_type))
- }
+ // TODO This was added due to servo/rust-bindgen#75, but
+ // that has been fixed in clang 4.0+. When we switch people
+ // to libclang 4.0, we can remove this.
+ .handle_table_items("array-types", |builder, item| {
+ let cpp_type = item["cpp-type"].as_str().unwrap();
+ let rust_type = item["rust-type"].as_str().unwrap();
+ builder.hide_type(format!("nsTArrayBorrowed_{}", cpp_type))
+ .raw_line(format!(concat!("pub type nsTArrayBorrowed_{}<'a> = ",
+ "&'a mut ::gecko_bindings::structs::nsTArray<{}>;"),
+ cpp_type, rust_type))
+ })
+ .handle_table_items("servo-owned-types", |mut builder, item| {
+ let name = item["name"].as_str().unwrap();
+ builder = builder.hide_type(format!("{}Owned", name))
+ .raw_line(format!("pub type {0}Owned = ::gecko_bindings::sugar::ownership::Owned<{0}>;", name))
+ .hide_type(format!("{}OwnedOrNull", name))
+ .raw_line(format!(concat!("pub type {0}OwnedOrNull = ",
+ "::gecko_bindings::sugar::ownership::OwnedOrNull<{0}>;"), name))
+ .mutable_borrowed_type(name);
+ if item["opaque"].as_bool().unwrap() {
+ builder = builder.zero_size_type(name, &structs_types);
+ }
+ builder
+ })
+ .handle_str_items("servo-immutable-borrow-types", |b, ty| b.borrowed_type(ty))
+ // Right now the only immutable borrow types are ones which we import
+ // from the |structs| module. As such, we don't need to create an opaque
+ // type with zero_size_type. If we ever introduce immutable borrow types
+ // which _do_ need to be opaque, we'll need a separate mode.
+ .handle_str_items("servo-borrow-types", |b, ty| b.mutable_borrowed_type(ty))
+ .get_builder();
for ty in get_arc_types().iter() {
builder = builder
.hide_type(format!("{}Strong", ty))
@@ -829,29 +530,7 @@ mod bindings {
.borrowed_type(ty)
.zero_size_type(ty, &structs_types);
}
- for &ServoOwnedType { name, opaque } in servo_owned_types.iter() {
- builder = builder
- .hide_type(format!("{}Owned", name))
- .raw_line(format!("pub type {0}Owned = ::gecko_bindings::sugar::ownership::Owned<{0}>;", name))
- .hide_type(format!("{}OwnedOrNull", name))
- .raw_line(format!("pub type {0}OwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull<{0}>;",
- name))
- .mutable_borrowed_type(name);
- if opaque {
- builder = builder.zero_size_type(name, &structs_types);
- }
- }
- for &ty in servo_immutable_borrow_types.iter() {
- builder = builder.borrowed_type(ty);
- }
- for &ty in servo_borrow_types.iter() {
- builder = builder.mutable_borrowed_type(ty);
- // Right now the only immutable borrow types are ones which we import
- // from the |structs| module. As such, we don't need to create an opaque
- // type with zero_size_type. If we ever introduce immutable borrow types
- // which _do_ need to be opaque, we'll need a separate mode.
- }
- write_binding_file(builder, BINDINGS_FILE, &Vec::new());
+ write_binding_file(builder, BINDINGS_FILE, &fixups);
}
fn generate_atoms() {
diff --git a/components/style/dom.rs b/components/style/dom.rs
index 4dab32eba22..36997de5c32 100644
--- a/components/style/dom.rs
+++ b/components/style/dom.rs
@@ -381,6 +381,9 @@ pub trait TElement : Eq + PartialEq + Debug + Hash + Sized + Copy + Clone +
/// Whether an attribute value equals `value`.
fn attr_equals(&self, namespace: &Namespace, attr: &LocalName, value: &Atom) -> bool;
+ /// Internal iterator for the classes of this element.
+ fn each_class<F>(&self, callback: F) where F: FnMut(&Atom);
+
/// Get the pre-existing style to calculate restyle damage (change hints).
///
/// This needs to be generic since it varies between Servo and Gecko.
@@ -389,7 +392,7 @@ pub trait TElement : Eq + PartialEq + Debug + Hash + Sized + Copy + Clone +
/// values as an argument here, but otherwise Servo would crash due to
/// double borrows to return it.
fn existing_style_for_restyle_damage<'a>(&'a self,
- current_computed_values: &'a Arc<ComputedValues>,
+ current_computed_values: &'a ComputedValues,
pseudo: Option<&PseudoElement>)
-> Option<&'a PreExistingComputedValues>;
diff --git a/components/style/gecko/conversions.rs b/components/style/gecko/conversions.rs
index 980ef36b280..1899a9799e1 100644
--- a/components/style/gecko/conversions.rs
+++ b/components/style/gecko/conversions.rs
@@ -24,7 +24,7 @@ impl From<CalcLengthOrPercentage> for nsStyleCoord_CalcValue {
fn from(other: CalcLengthOrPercentage) -> nsStyleCoord_CalcValue {
let has_percentage = other.percentage.is_some();
nsStyleCoord_CalcValue {
- mLength: other.length.0,
+ mLength: other.unclamped_length().0,
mPercent: other.percentage.unwrap_or(0.0),
mHasPercent: has_percentage,
}
@@ -38,10 +38,7 @@ impl From<nsStyleCoord_CalcValue> for CalcLengthOrPercentage {
} else {
None
};
- CalcLengthOrPercentage {
- length: Au(other.mLength),
- percentage: percentage,
- }
+ Self::new(Au(other.mLength), percentage)
}
}
diff --git a/components/style/gecko/generated/bindings.rs b/components/style/gecko/generated/bindings.rs
index 439a3cd9ed0..ee99ffb4fe0 100644
--- a/components/style/gecko/generated/bindings.rs
+++ b/components/style/gecko/generated/bindings.rs
@@ -1,6 +1,7 @@
/* automatically generated by rust-bindgen */
-pub use nsstring::{nsACString, nsAString, nsString};
+pub use nsstring::{nsACString, nsAString, nsString, nsStringRepr};
+use gecko_bindings::structs::nsTArray;
type nsACString_internal = nsACString;
type nsAString_internal = nsAString;
use gecko_bindings::structs::mozilla::css::GridTemplateAreasValue;
@@ -944,6 +945,15 @@ extern "C" {
pub fn Gecko_DropElementSnapshot(snapshot: ServoElementSnapshotOwned);
}
extern "C" {
+ pub fn Gecko_ResizeTArrayForStrings(array: *mut nsTArray<nsStringRepr>,
+ length: u32);
+}
+extern "C" {
+ pub fn Gecko_SetStyleGridTemplateArrayLengths(grid_template:
+ *mut nsStyleGridTemplate,
+ track_sizes: u32);
+}
+extern "C" {
pub fn Gecko_CopyStyleGridTemplateValues(grid_template:
*mut nsStyleGridTemplate,
other:
@@ -1670,7 +1680,8 @@ extern "C" {
*const RawServoMediaList,
extra_data:
*mut RawGeckoURLExtraData,
- line_number_offset: u32)
+ line_number_offset: u32,
+ quirks_mode: nsCompatibility)
-> RawServoStyleSheetStrong;
}
extern "C" {
@@ -1933,7 +1944,8 @@ extern "C" {
pub fn Servo_ParseProperty(property: nsCSSPropertyID,
value: *const nsACString,
data: *mut RawGeckoURLExtraData,
- parsing_mode: ParsingMode)
+ parsing_mode: ParsingMode,
+ quirks_mode: nsCompatibility)
-> RawServoDeclarationBlockStrong;
}
extern "C" {
@@ -2103,7 +2115,8 @@ extern "C" {
value: *const nsACString,
is_important: bool,
data: *mut RawGeckoURLExtraData,
- parsing_mode: ParsingMode)
+ parsing_mode: ParsingMode,
+ quirks_mode: nsCompatibility)
-> bool;
}
extern "C" {
@@ -2114,7 +2127,9 @@ extern "C" {
is_important: bool,
data:
*mut RawGeckoURLExtraData,
- parsing_mode: ParsingMode)
+ parsing_mode: ParsingMode,
+ quirks_mode:
+ nsCompatibility)
-> bool;
}
extern "C" {
diff --git a/components/style/gecko/generated/structs_debug.rs b/components/style/gecko/generated/structs_debug.rs
index a693eaa3b7c..2f8b574b209 100644
--- a/components/style/gecko/generated/structs_debug.rs
+++ b/components/style/gecko/generated/structs_debug.rs
@@ -1196,65 +1196,101 @@ pub mod root {
fn clone(&self) -> Self { *self }
}
#[repr(C)]
+ #[derive(Debug, Copy)]
+ pub struct forward_iterator_tag {
+ pub _address: u8,
+ }
+ #[test]
+ fn bindgen_test_layout_forward_iterator_tag() {
+ assert_eq!(::std::mem::size_of::<forward_iterator_tag>() , 1usize
+ , concat ! (
+ "Size of: " , stringify ! ( forward_iterator_tag ) ));
+ assert_eq! (::std::mem::align_of::<forward_iterator_tag>() ,
+ 1usize , concat ! (
+ "Alignment of " , stringify ! ( forward_iterator_tag )
+ ));
+ }
+ impl Clone for forward_iterator_tag {
+ fn clone(&self) -> Self { *self }
+ }
+ #[repr(C)]
+ #[derive(Debug, Copy)]
+ pub struct bidirectional_iterator_tag {
+ pub _address: u8,
+ }
+ #[test]
+ fn bindgen_test_layout_bidirectional_iterator_tag() {
+ assert_eq!(::std::mem::size_of::<bidirectional_iterator_tag>() ,
+ 1usize , concat ! (
+ "Size of: " , stringify ! ( bidirectional_iterator_tag
+ ) ));
+ assert_eq! (::std::mem::align_of::<bidirectional_iterator_tag>() ,
+ 1usize , concat ! (
+ "Alignment of " , stringify ! (
+ bidirectional_iterator_tag ) ));
+ }
+ impl Clone for bidirectional_iterator_tag {
+ fn clone(&self) -> Self { *self }
+ }
+ #[repr(C)]
+ #[derive(Debug, Copy)]
+ pub struct random_access_iterator_tag {
+ pub _address: u8,
+ }
+ #[test]
+ fn bindgen_test_layout_random_access_iterator_tag() {
+ assert_eq!(::std::mem::size_of::<random_access_iterator_tag>() ,
+ 1usize , concat ! (
+ "Size of: " , stringify ! ( random_access_iterator_tag
+ ) ));
+ assert_eq! (::std::mem::align_of::<random_access_iterator_tag>() ,
+ 1usize , concat ! (
+ "Alignment of " , stringify ! (
+ random_access_iterator_tag ) ));
+ }
+ impl Clone for random_access_iterator_tag {
+ fn clone(&self) -> Self { *self }
+ }
+ #[repr(C)]
+ pub struct iterator_traits {
+ pub _address: u8,
+ }
+ #[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct iterator {
pub _address: u8,
}
- pub type iterator_iterator_category<_Category> = _Category;
pub type iterator_value_type<_Tp> = _Tp;
pub type iterator_difference_type<_Distance> = _Distance;
pub type iterator_pointer<_Pointer> = _Pointer;
pub type iterator_reference<_Reference> = _Reference;
+ pub type iterator_iterator_category<_Category> = _Category;
#[repr(C)]
- pub struct iterator_traits {
- pub _address: u8,
- }
- #[repr(C)]
- pub struct reverse_iterator<_Iterator> {
- pub current: _Iterator,
- pub _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell<_Iterator>>,
+ pub struct reverse_iterator<_Iter> {
+ pub __t: _Iter,
+ pub current: _Iter,
+ pub _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell<_Iter>>,
}
- pub type reverse_iterator___traits_type = root::std::iterator_traits;
- pub type reverse_iterator_iterator_type<_Iterator> = _Iterator;
+ pub type reverse_iterator_iterator_type<_Iter> = _Iter;
pub type reverse_iterator_difference_type =
- root::std::reverse_iterator___traits_type;
- pub type reverse_iterator_pointer =
- root::std::reverse_iterator___traits_type;
- pub type reverse_iterator_reference =
- root::std::reverse_iterator___traits_type;
+ root::std::iterator_traits;
+ pub type reverse_iterator_reference = root::std::iterator_traits;
+ pub type reverse_iterator_pointer = root::std::iterator_traits;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct atomic {
}
- #[test]
- fn __bindgen_test_layout_atomic_instantiation_89754() {
- assert_eq!(::std::mem::size_of::<u32>() , 4usize , concat ! (
- "Size of template specialization: " , stringify ! ( u32
- ) ));
- assert_eq!(::std::mem::align_of::<u32>() , 4usize , concat ! (
- "Alignment of template specialization: " , stringify !
- ( u32 ) ));
- }
- #[test]
- fn __bindgen_test_layout_atomic_instantiation_89762() {
- assert_eq!(::std::mem::size_of::<u64>() , 8usize , concat ! (
- "Size of template specialization: " , stringify ! ( u64
- ) ));
- assert_eq!(::std::mem::align_of::<u64>() , 8usize , concat ! (
- "Alignment of template specialization: " , stringify !
- ( u64 ) ));
- }
- pub mod chrono {
- #[allow(unused_imports)]
- use self::super::super::super::root;
+ pub type atomic___base = u8;
+ #[repr(C)]
+ pub struct __bit_const_reference {
+ pub __seg_: root::std::__bit_const_reference___storage_pointer,
+ pub __mask_: root::std::__bit_const_reference___storage_type,
}
+ pub type __bit_const_reference___storage_type = [u8; 0usize];
+ pub type __bit_const_reference___storage_pointer = [u8; 0usize];
}
- pub mod __gnu_cxx {
- #[allow(unused_imports)]
- use self::super::super::root;
- }
- pub type __off_t = ::std::os::raw::c_long;
- pub type __off64_t = ::std::os::raw::c_long;
+ pub type __int64_t = ::std::os::raw::c_longlong;
+ pub type __darwin_off_t = root::__int64_t;
pub mod mozilla {
#[allow(unused_imports)]
use self::super::super::root;
@@ -1544,7 +1580,7 @@ pub mod root {
#[repr(C)]
#[derive(Debug)]
pub struct MutexImpl {
- pub platformData_: [*mut ::std::os::raw::c_void; 5usize],
+ pub platformData_: [*mut ::std::os::raw::c_void; 8usize],
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
@@ -1553,7 +1589,7 @@ pub mod root {
}
#[test]
fn bindgen_test_layout_MutexImpl() {
- assert_eq!(::std::mem::size_of::<MutexImpl>() , 40usize ,
+ assert_eq!(::std::mem::size_of::<MutexImpl>() , 64usize ,
concat ! ( "Size of: " , stringify ! ( MutexImpl )
));
assert_eq! (::std::mem::align_of::<MutexImpl>() , 8usize ,
@@ -2184,7 +2220,7 @@ pub mod root {
}
}
#[repr(C)]
- #[derive(Debug)]
+ #[derive(Debug, Copy)]
pub struct ThreadSafeAutoRefCnt {
pub mValue: u64,
}
@@ -2205,6 +2241,9 @@ pub mod root {
ThreadSafeAutoRefCnt ) , "::" , stringify ! ( mValue )
));
}
+ impl Clone for ThreadSafeAutoRefCnt {
+ fn clone(&self) -> Self { *self }
+ }
#[repr(C)]
#[derive(Debug)]
pub struct OwningNonNull<T> {
@@ -3758,20 +3797,9 @@ pub mod root {
_unused: [u8; 0],
}
#[repr(C)]
- #[derive(Debug)]
+ #[derive(Debug, Copy, Clone)]
pub struct EventHandlerNonNull {
- pub _base: root::mozilla::dom::CallbackFunction,
- }
- #[test]
- fn bindgen_test_layout_EventHandlerNonNull() {
- assert_eq!(::std::mem::size_of::<EventHandlerNonNull>() ,
- 56usize , concat ! (
- "Size of: " , stringify ! ( EventHandlerNonNull )
- ));
- assert_eq! (::std::mem::align_of::<EventHandlerNonNull>() ,
- 8usize , concat ! (
- "Alignment of " , stringify ! (
- EventHandlerNonNull ) ));
+ _unused: [u8; 0],
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
@@ -6900,7 +6928,7 @@ pub mod root {
_unused: [u8; 0],
}
#[test]
- fn __bindgen_test_layout_StaticRefPtr_instantiation_141650() {
+ fn __bindgen_test_layout_StaticRefPtr_instantiation_118261() {
assert_eq!(::std::mem::size_of::<root::mozilla::StaticRefPtr<root::mozilla::URLExtraData>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -7996,7 +8024,7 @@ pub mod root {
}
#[test]
fn bindgen_test_layout_OffTheBooksMutex() {
- assert_eq!(::std::mem::size_of::<OffTheBooksMutex>() , 72usize ,
+ assert_eq!(::std::mem::size_of::<OffTheBooksMutex>() , 96usize ,
concat ! (
"Size of: " , stringify ! ( OffTheBooksMutex ) ));
assert_eq! (::std::mem::align_of::<OffTheBooksMutex>() , 8usize ,
@@ -8004,7 +8032,7 @@ pub mod root {
"Alignment of " , stringify ! ( OffTheBooksMutex ) ));
assert_eq! (unsafe {
& ( * ( 0 as * const OffTheBooksMutex ) ) .
- mOwningThread as * const _ as usize } , 64usize ,
+ mOwningThread as * const _ as usize } , 88usize ,
concat ! (
"Alignment of field: " , stringify ! (
OffTheBooksMutex ) , "::" , stringify ! (
@@ -8022,7 +8050,7 @@ pub mod root {
}
#[test]
fn bindgen_test_layout_Mutex() {
- assert_eq!(::std::mem::size_of::<Mutex>() , 72usize , concat ! (
+ assert_eq!(::std::mem::size_of::<Mutex>() , 96usize , concat ! (
"Size of: " , stringify ! ( Mutex ) ));
assert_eq! (::std::mem::align_of::<Mutex>() , 8usize , concat ! (
"Alignment of " , stringify ! ( Mutex ) ));
@@ -8832,9 +8860,9 @@ pub mod root {
#[repr(C)]
#[derive(Debug)]
pub struct ServoElementSnapshot {
- pub mContains: root::mozilla::ServoElementSnapshot_Flags,
pub mAttrs: root::nsTArray<root::mozilla::ServoAttrSnapshot>,
pub mState: root::mozilla::ServoElementSnapshot_ServoStateType,
+ pub mContains: root::mozilla::ServoElementSnapshot_Flags,
pub mIsHTMLElementInHTMLDocument: bool,
pub mIsInChromeDocument: bool,
}
@@ -8847,7 +8875,7 @@ pub mod root {
as ServoElementSnapshot_Flags;
#[test]
fn bindgen_test_layout_ServoElementSnapshot() {
- assert_eq!(::std::mem::size_of::<ServoElementSnapshot>() , 32usize
+ assert_eq!(::std::mem::size_of::<ServoElementSnapshot>() , 24usize
, concat ! (
"Size of: " , stringify ! ( ServoElementSnapshot ) ));
assert_eq! (::std::mem::align_of::<ServoElementSnapshot>() ,
@@ -8855,34 +8883,34 @@ pub mod root {
"Alignment of " , stringify ! ( ServoElementSnapshot )
));
assert_eq! (unsafe {
- & ( * ( 0 as * const ServoElementSnapshot ) ) .
- mContains as * const _ as usize } , 0usize , concat !
- (
- "Alignment of field: " , stringify ! (
- ServoElementSnapshot ) , "::" , stringify ! (
- mContains ) ));
- assert_eq! (unsafe {
& ( * ( 0 as * const ServoElementSnapshot ) ) . mAttrs
- as * const _ as usize } , 8usize , concat ! (
+ as * const _ as usize } , 0usize , concat ! (
"Alignment of field: " , stringify ! (
ServoElementSnapshot ) , "::" , stringify ! ( mAttrs )
));
assert_eq! (unsafe {
& ( * ( 0 as * const ServoElementSnapshot ) ) . mState
- as * const _ as usize } , 16usize , concat ! (
+ as * const _ as usize } , 8usize , concat ! (
"Alignment of field: " , stringify ! (
ServoElementSnapshot ) , "::" , stringify ! ( mState )
));
assert_eq! (unsafe {
& ( * ( 0 as * const ServoElementSnapshot ) ) .
+ mContains as * const _ as usize } , 16usize , concat !
+ (
+ "Alignment of field: " , stringify ! (
+ ServoElementSnapshot ) , "::" , stringify ! (
+ mContains ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const ServoElementSnapshot ) ) .
mIsHTMLElementInHTMLDocument as * const _ as usize } ,
- 24usize , concat ! (
+ 17usize , concat ! (
"Alignment of field: " , stringify ! (
ServoElementSnapshot ) , "::" , stringify ! (
mIsHTMLElementInHTMLDocument ) ));
assert_eq! (unsafe {
& ( * ( 0 as * const ServoElementSnapshot ) ) .
- mIsInChromeDocument as * const _ as usize } , 25usize
+ mIsInChromeDocument as * const _ as usize } , 18usize
, concat ! (
"Alignment of field: " , stringify ! (
ServoElementSnapshot ) , "::" , stringify ! (
@@ -9141,7 +9169,7 @@ pub mod root {
( mValue ) ));
}
#[test]
- fn __bindgen_test_layout_DefaultDelete_instantiation_178959() {
+ fn __bindgen_test_layout_DefaultDelete_instantiation_155741() {
assert_eq!(::std::mem::size_of::<root::mozilla::DefaultDelete>() ,
1usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -9597,7 +9625,8 @@ pub mod root {
pub enum ServoElementSnapshotFlags {
State = 1,
Attributes = 2,
- All = 3,
+ Id = 4,
+ MaybeClass = 8,
}
#[repr(C)]
#[derive(Debug, Copy)]
@@ -10258,196 +10287,194 @@ pub mod root {
pub _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell<T>>,
}
}
+ pub type va_list = root::__builtin_va_list;
+ pub type fpos_t = root::__darwin_off_t;
#[repr(C)]
#[derive(Debug, Copy)]
- pub struct _IO_FILE {
- pub _flags: ::std::os::raw::c_int,
- pub _IO_read_ptr: *mut ::std::os::raw::c_char,
- pub _IO_read_end: *mut ::std::os::raw::c_char,
- pub _IO_read_base: *mut ::std::os::raw::c_char,
- pub _IO_write_base: *mut ::std::os::raw::c_char,
- pub _IO_write_ptr: *mut ::std::os::raw::c_char,
- pub _IO_write_end: *mut ::std::os::raw::c_char,
- pub _IO_buf_base: *mut ::std::os::raw::c_char,
- pub _IO_buf_end: *mut ::std::os::raw::c_char,
- pub _IO_save_base: *mut ::std::os::raw::c_char,
- pub _IO_backup_base: *mut ::std::os::raw::c_char,
- pub _IO_save_end: *mut ::std::os::raw::c_char,
- pub _markers: *mut root::_IO_marker,
- pub _chain: *mut root::_IO_FILE,
- pub _fileno: ::std::os::raw::c_int,
- pub _flags2: ::std::os::raw::c_int,
- pub _old_offset: root::__off_t,
- pub _cur_column: ::std::os::raw::c_ushort,
- pub _vtable_offset: ::std::os::raw::c_schar,
- pub _shortbuf: [::std::os::raw::c_char; 1usize],
- pub _lock: *mut root::_IO_lock_t,
- pub _offset: root::__off64_t,
- pub __pad1: *mut ::std::os::raw::c_void,
- pub __pad2: *mut ::std::os::raw::c_void,
- pub __pad3: *mut ::std::os::raw::c_void,
- pub __pad4: *mut ::std::os::raw::c_void,
- pub __pad5: usize,
- pub _mode: ::std::os::raw::c_int,
- pub _unused2: [::std::os::raw::c_char; 20usize],
- }
- #[test]
- fn bindgen_test_layout__IO_FILE() {
- assert_eq!(::std::mem::size_of::<_IO_FILE>() , 216usize , concat ! (
- "Size of: " , stringify ! ( _IO_FILE ) ));
- assert_eq! (::std::mem::align_of::<_IO_FILE>() , 8usize , concat ! (
- "Alignment of " , stringify ! ( _IO_FILE ) ));
- assert_eq! (unsafe {
- & ( * ( 0 as * const _IO_FILE ) ) . _flags as * const _ as
+ pub struct __sbuf {
+ pub _base: *mut ::std::os::raw::c_uchar,
+ pub _size: ::std::os::raw::c_int,
+ }
+ #[test]
+ fn bindgen_test_layout___sbuf() {
+ assert_eq!(::std::mem::size_of::<__sbuf>() , 16usize , concat ! (
+ "Size of: " , stringify ! ( __sbuf ) ));
+ assert_eq! (::std::mem::align_of::<__sbuf>() , 8usize , concat ! (
+ "Alignment of " , stringify ! ( __sbuf ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const __sbuf ) ) . _base as * const _ as
usize } , 0usize , concat ! (
- "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
- stringify ! ( _flags ) ));
+ "Alignment of field: " , stringify ! ( __sbuf ) , "::" ,
+ stringify ! ( _base ) ));
assert_eq! (unsafe {
- & ( * ( 0 as * const _IO_FILE ) ) . _IO_read_ptr as *
- const _ as usize } , 8usize , concat ! (
- "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
- stringify ! ( _IO_read_ptr ) ));
+ & ( * ( 0 as * const __sbuf ) ) . _size as * const _ as
+ usize } , 8usize , concat ! (
+ "Alignment of field: " , stringify ! ( __sbuf ) , "::" ,
+ stringify ! ( _size ) ));
+ }
+ impl Clone for __sbuf {
+ fn clone(&self) -> Self { *self }
+ }
+ #[repr(C)]
+ #[derive(Debug, Copy, Clone)]
+ pub struct __sFILEX {
+ _unused: [u8; 0],
+ }
+ #[repr(C)]
+ #[derive(Debug, Copy)]
+ pub struct __sFILE {
+ pub _p: *mut ::std::os::raw::c_uchar,
+ pub _r: ::std::os::raw::c_int,
+ pub _w: ::std::os::raw::c_int,
+ pub _flags: ::std::os::raw::c_short,
+ pub _file: ::std::os::raw::c_short,
+ pub _bf: root::__sbuf,
+ pub _lbfsize: ::std::os::raw::c_int,
+ pub _cookie: *mut ::std::os::raw::c_void,
+ pub _close: ::std::option::Option<unsafe extern "C" fn(arg1:
+ *mut ::std::os::raw::c_void)
+ -> ::std::os::raw::c_int>,
+ pub _read: ::std::option::Option<unsafe extern "C" fn(arg1:
+ *mut ::std::os::raw::c_void,
+ arg2:
+ *mut ::std::os::raw::c_char,
+ arg3:
+ ::std::os::raw::c_int)
+ -> ::std::os::raw::c_int>,
+ pub _seek: ::std::option::Option<unsafe extern "C" fn(arg1:
+ *mut ::std::os::raw::c_void,
+ arg2:
+ root::fpos_t,
+ arg3:
+ ::std::os::raw::c_int)
+ -> root::fpos_t>,
+ pub _write: ::std::option::Option<unsafe extern "C" fn(arg1:
+ *mut ::std::os::raw::c_void,
+ arg2:
+ *const ::std::os::raw::c_char,
+ arg3:
+ ::std::os::raw::c_int)
+ -> ::std::os::raw::c_int>,
+ pub _ub: root::__sbuf,
+ pub _extra: *mut root::__sFILEX,
+ pub _ur: ::std::os::raw::c_int,
+ pub _ubuf: [::std::os::raw::c_uchar; 3usize],
+ pub _nbuf: [::std::os::raw::c_uchar; 1usize],
+ pub _lb: root::__sbuf,
+ pub _blksize: ::std::os::raw::c_int,
+ pub _offset: root::fpos_t,
+ }
+ #[test]
+ fn bindgen_test_layout___sFILE() {
+ assert_eq!(::std::mem::size_of::<__sFILE>() , 152usize , concat ! (
+ "Size of: " , stringify ! ( __sFILE ) ));
+ assert_eq! (::std::mem::align_of::<__sFILE>() , 8usize , concat ! (
+ "Alignment of " , stringify ! ( __sFILE ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const __sFILE ) ) . _p as * const _ as
+ usize } , 0usize , concat ! (
+ "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
+ stringify ! ( _p ) ));
assert_eq! (unsafe {
- & ( * ( 0 as * const _IO_FILE ) ) . _IO_read_end as *
- const _ as usize } , 16usize , concat ! (
- "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
- stringify ! ( _IO_read_end ) ));
+ & ( * ( 0 as * const __sFILE ) ) . _r as * const _ as
+ usize } , 8usize , concat ! (
+ "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
+ stringify ! ( _r ) ));
assert_eq! (unsafe {
- & ( * ( 0 as * const _IO_FILE ) ) . _IO_read_base as *
- const _ as usize } , 24usize , concat ! (
- "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
- stringify ! ( _IO_read_base ) ));
+ & ( * ( 0 as * const __sFILE ) ) . _w as * const _ as
+ usize } , 12usize , concat ! (
+ "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
+ stringify ! ( _w ) ));
assert_eq! (unsafe {
- & ( * ( 0 as * const _IO_FILE ) ) . _IO_write_base as *
- const _ as usize } , 32usize , concat ! (
- "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
- stringify ! ( _IO_write_base ) ));
+ & ( * ( 0 as * const __sFILE ) ) . _flags as * const _ as
+ usize } , 16usize , concat ! (
+ "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
+ stringify ! ( _flags ) ));
assert_eq! (unsafe {
- & ( * ( 0 as * const _IO_FILE ) ) . _IO_write_ptr as *
- const _ as usize } , 40usize , concat ! (
- "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
- stringify ! ( _IO_write_ptr ) ));
+ & ( * ( 0 as * const __sFILE ) ) . _file as * const _ as
+ usize } , 18usize , concat ! (
+ "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
+ stringify ! ( _file ) ));
assert_eq! (unsafe {
- & ( * ( 0 as * const _IO_FILE ) ) . _IO_write_end as *
- const _ as usize } , 48usize , concat ! (
- "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
- stringify ! ( _IO_write_end ) ));
+ & ( * ( 0 as * const __sFILE ) ) . _bf as * const _ as
+ usize } , 24usize , concat ! (
+ "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
+ stringify ! ( _bf ) ));
assert_eq! (unsafe {
- & ( * ( 0 as * const _IO_FILE ) ) . _IO_buf_base as *
- const _ as usize } , 56usize , concat ! (
- "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
- stringify ! ( _IO_buf_base ) ));
+ & ( * ( 0 as * const __sFILE ) ) . _lbfsize as * const _
+ as usize } , 40usize , concat ! (
+ "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
+ stringify ! ( _lbfsize ) ));
assert_eq! (unsafe {
- & ( * ( 0 as * const _IO_FILE ) ) . _IO_buf_end as * const
- _ as usize } , 64usize , concat ! (
- "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
- stringify ! ( _IO_buf_end ) ));
+ & ( * ( 0 as * const __sFILE ) ) . _cookie as * const _ as
+ usize } , 48usize , concat ! (
+ "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
+ stringify ! ( _cookie ) ));
assert_eq! (unsafe {
- & ( * ( 0 as * const _IO_FILE ) ) . _IO_save_base as *
- const _ as usize } , 72usize , concat ! (
- "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
- stringify ! ( _IO_save_base ) ));
+ & ( * ( 0 as * const __sFILE ) ) . _close as * const _ as
+ usize } , 56usize , concat ! (
+ "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
+ stringify ! ( _close ) ));
assert_eq! (unsafe {
- & ( * ( 0 as * const _IO_FILE ) ) . _IO_backup_base as *
- const _ as usize } , 80usize , concat ! (
- "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
- stringify ! ( _IO_backup_base ) ));
+ & ( * ( 0 as * const __sFILE ) ) . _read as * const _ as
+ usize } , 64usize , concat ! (
+ "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
+ stringify ! ( _read ) ));
assert_eq! (unsafe {
- & ( * ( 0 as * const _IO_FILE ) ) . _IO_save_end as *
- const _ as usize } , 88usize , concat ! (
- "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
- stringify ! ( _IO_save_end ) ));
+ & ( * ( 0 as * const __sFILE ) ) . _seek as * const _ as
+ usize } , 72usize , concat ! (
+ "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
+ stringify ! ( _seek ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const __sFILE ) ) . _write as * const _ as
+ usize } , 80usize , concat ! (
+ "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
+ stringify ! ( _write ) ));
assert_eq! (unsafe {
- & ( * ( 0 as * const _IO_FILE ) ) . _markers as * const _
- as usize } , 96usize , concat ! (
- "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
- stringify ! ( _markers ) ));
+ & ( * ( 0 as * const __sFILE ) ) . _ub as * const _ as
+ usize } , 88usize , concat ! (
+ "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
+ stringify ! ( _ub ) ));
assert_eq! (unsafe {
- & ( * ( 0 as * const _IO_FILE ) ) . _chain as * const _ as
+ & ( * ( 0 as * const __sFILE ) ) . _extra as * const _ as
usize } , 104usize , concat ! (
- "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
- stringify ! ( _chain ) ));
- assert_eq! (unsafe {
- & ( * ( 0 as * const _IO_FILE ) ) . _fileno as * const _
- as usize } , 112usize , concat ! (
- "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
- stringify ! ( _fileno ) ));
- assert_eq! (unsafe {
- & ( * ( 0 as * const _IO_FILE ) ) . _flags2 as * const _
- as usize } , 116usize , concat ! (
- "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
- stringify ! ( _flags2 ) ));
- assert_eq! (unsafe {
- & ( * ( 0 as * const _IO_FILE ) ) . _old_offset as * const
- _ as usize } , 120usize , concat ! (
- "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
- stringify ! ( _old_offset ) ));
- assert_eq! (unsafe {
- & ( * ( 0 as * const _IO_FILE ) ) . _cur_column as * const
- _ as usize } , 128usize , concat ! (
- "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
- stringify ! ( _cur_column ) ));
- assert_eq! (unsafe {
- & ( * ( 0 as * const _IO_FILE ) ) . _vtable_offset as *
- const _ as usize } , 130usize , concat ! (
- "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
- stringify ! ( _vtable_offset ) ));
- assert_eq! (unsafe {
- & ( * ( 0 as * const _IO_FILE ) ) . _shortbuf as * const _
- as usize } , 131usize , concat ! (
- "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
- stringify ! ( _shortbuf ) ));
- assert_eq! (unsafe {
- & ( * ( 0 as * const _IO_FILE ) ) . _lock as * const _ as
- usize } , 136usize , concat ! (
- "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
- stringify ! ( _lock ) ));
- assert_eq! (unsafe {
- & ( * ( 0 as * const _IO_FILE ) ) . _offset as * const _
- as usize } , 144usize , concat ! (
- "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
+ "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
+ stringify ! ( _extra ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const __sFILE ) ) . _ur as * const _ as
+ usize } , 112usize , concat ! (
+ "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
+ stringify ! ( _ur ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const __sFILE ) ) . _ubuf as * const _ as
+ usize } , 116usize , concat ! (
+ "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
+ stringify ! ( _ubuf ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const __sFILE ) ) . _nbuf as * const _ as
+ usize } , 119usize , concat ! (
+ "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
+ stringify ! ( _nbuf ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const __sFILE ) ) . _lb as * const _ as
+ usize } , 120usize , concat ! (
+ "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
+ stringify ! ( _lb ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const __sFILE ) ) . _blksize as * const _
+ as usize } , 136usize , concat ! (
+ "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
+ stringify ! ( _blksize ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const __sFILE ) ) . _offset as * const _ as
+ usize } , 144usize , concat ! (
+ "Alignment of field: " , stringify ! ( __sFILE ) , "::" ,
stringify ! ( _offset ) ));
- assert_eq! (unsafe {
- & ( * ( 0 as * const _IO_FILE ) ) . __pad1 as * const _ as
- usize } , 152usize , concat ! (
- "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
- stringify ! ( __pad1 ) ));
- assert_eq! (unsafe {
- & ( * ( 0 as * const _IO_FILE ) ) . __pad2 as * const _ as
- usize } , 160usize , concat ! (
- "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
- stringify ! ( __pad2 ) ));
- assert_eq! (unsafe {
- & ( * ( 0 as * const _IO_FILE ) ) . __pad3 as * const _ as
- usize } , 168usize , concat ! (
- "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
- stringify ! ( __pad3 ) ));
- assert_eq! (unsafe {
- & ( * ( 0 as * const _IO_FILE ) ) . __pad4 as * const _ as
- usize } , 176usize , concat ! (
- "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
- stringify ! ( __pad4 ) ));
- assert_eq! (unsafe {
- & ( * ( 0 as * const _IO_FILE ) ) . __pad5 as * const _ as
- usize } , 184usize , concat ! (
- "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
- stringify ! ( __pad5 ) ));
- assert_eq! (unsafe {
- & ( * ( 0 as * const _IO_FILE ) ) . _mode as * const _ as
- usize } , 192usize , concat ! (
- "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
- stringify ! ( _mode ) ));
- assert_eq! (unsafe {
- & ( * ( 0 as * const _IO_FILE ) ) . _unused2 as * const _
- as usize } , 196usize , concat ! (
- "Alignment of field: " , stringify ! ( _IO_FILE ) , "::" ,
- stringify ! ( _unused2 ) ));
- }
- impl Clone for _IO_FILE {
+ }
+ impl Clone for __sFILE {
fn clone(&self) -> Self { *self }
}
- pub type FILE = root::_IO_FILE;
- pub type va_list = root::__builtin_va_list;
+ pub type FILE = root::__sFILE;
#[repr(C)]
#[derive(Debug, Copy)]
pub struct InfallibleAllocPolicy {
@@ -11004,39 +11031,6 @@ pub mod root {
NS_OK_NO_NAME_CLAUSE_HANDLED = 7864354,
}
pub type nsrefcnt = root::MozRefCountType;
- pub type _IO_lock_t = ::std::os::raw::c_void;
- #[repr(C)]
- #[derive(Debug, Copy)]
- pub struct _IO_marker {
- pub _next: *mut root::_IO_marker,
- pub _sbuf: *mut root::_IO_FILE,
- pub _pos: ::std::os::raw::c_int,
- }
- #[test]
- fn bindgen_test_layout__IO_marker() {
- assert_eq!(::std::mem::size_of::<_IO_marker>() , 24usize , concat ! (
- "Size of: " , stringify ! ( _IO_marker ) ));
- assert_eq! (::std::mem::align_of::<_IO_marker>() , 8usize , concat ! (
- "Alignment of " , stringify ! ( _IO_marker ) ));
- assert_eq! (unsafe {
- & ( * ( 0 as * const _IO_marker ) ) . _next as * const _
- as usize } , 0usize , concat ! (
- "Alignment of field: " , stringify ! ( _IO_marker ) , "::"
- , stringify ! ( _next ) ));
- assert_eq! (unsafe {
- & ( * ( 0 as * const _IO_marker ) ) . _sbuf as * const _
- as usize } , 8usize , concat ! (
- "Alignment of field: " , stringify ! ( _IO_marker ) , "::"
- , stringify ! ( _sbuf ) ));
- assert_eq! (unsafe {
- & ( * ( 0 as * const _IO_marker ) ) . _pos as * const _ as
- usize } , 16usize , concat ! (
- "Alignment of field: " , stringify ! ( _IO_marker ) , "::"
- , stringify ! ( _pos ) ));
- }
- impl Clone for _IO_marker {
- fn clone(&self) -> Self { *self }
- }
#[repr(C)]
pub struct nsQueryFrame__bindgen_vtable(::std::os::raw::c_void);
#[repr(C)]
@@ -11596,7 +11590,7 @@ pub mod root {
pub _address: u8,
}
#[test]
- fn __bindgen_test_layout_nsCharTraits_instantiation_55138() {
+ fn __bindgen_test_layout_nsCharTraits_instantiation_52974() {
assert_eq!(::std::mem::size_of::<root::nsCharTraits>() , 1usize ,
concat ! (
"Size of template specialization: " , stringify ! (
@@ -11607,7 +11601,7 @@ pub mod root {
root::nsCharTraits ) ));
}
#[test]
- fn __bindgen_test_layout_nsCharTraits_instantiation_55142() {
+ fn __bindgen_test_layout_nsCharTraits_instantiation_52978() {
assert_eq!(::std::mem::size_of::<root::nsCharTraits>() , 1usize ,
concat ! (
"Size of template specialization: " , stringify ! (
@@ -13080,7 +13074,7 @@ pub mod root {
}
pub type nsCOMPtr_element_type<T> = T;
#[test]
- fn __bindgen_test_layout_nsCOMPtr_instantiation_92969() {
+ fn __bindgen_test_layout_nsCOMPtr_instantiation_62108() {
assert_eq!(::std::mem::size_of::<root::nsCOMPtr<root::nsISupports>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -14679,7 +14673,7 @@ pub mod root {
* count is 1.
*/
#[repr(C)]
- #[derive(Debug)]
+ #[derive(Debug, Copy)]
pub struct nsStringBuffer {
pub mRefCount: u32,
pub mStorageSize: u32,
@@ -14701,6 +14695,9 @@ pub mod root {
"Alignment of field: " , stringify ! ( nsStringBuffer ) ,
"::" , stringify ! ( mStorageSize ) ));
}
+ impl Clone for nsStringBuffer {
+ fn clone(&self) -> Self { *self }
+ }
#[repr(C)]
#[derive(Debug, Copy)]
pub struct nsIAtom {
@@ -20789,57 +20786,57 @@ pub mod root {
pub struct nsDOMMutationObserver {
_unused: [u8; 0],
}
- pub const NODE_HAS_LISTENERMANAGER: root::_bindgen_ty_84 =
- _bindgen_ty_84::NODE_HAS_LISTENERMANAGER;
- pub const NODE_HAS_PROPERTIES: root::_bindgen_ty_84 =
- _bindgen_ty_84::NODE_HAS_PROPERTIES;
- pub const NODE_IS_ANONYMOUS_ROOT: root::_bindgen_ty_84 =
- _bindgen_ty_84::NODE_IS_ANONYMOUS_ROOT;
- pub const NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE: root::_bindgen_ty_84 =
- _bindgen_ty_84::NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE;
- pub const NODE_IS_NATIVE_ANONYMOUS_ROOT: root::_bindgen_ty_84 =
- _bindgen_ty_84::NODE_IS_NATIVE_ANONYMOUS_ROOT;
- pub const NODE_FORCE_XBL_BINDINGS: root::_bindgen_ty_84 =
- _bindgen_ty_84::NODE_FORCE_XBL_BINDINGS;
- pub const NODE_MAY_BE_IN_BINDING_MNGR: root::_bindgen_ty_84 =
- _bindgen_ty_84::NODE_MAY_BE_IN_BINDING_MNGR;
- pub const NODE_IS_EDITABLE: root::_bindgen_ty_84 =
- _bindgen_ty_84::NODE_IS_EDITABLE;
- pub const NODE_IS_NATIVE_ANONYMOUS: root::_bindgen_ty_84 =
- _bindgen_ty_84::NODE_IS_NATIVE_ANONYMOUS;
- pub const NODE_IS_IN_SHADOW_TREE: root::_bindgen_ty_84 =
- _bindgen_ty_84::NODE_IS_IN_SHADOW_TREE;
- pub const NODE_HAS_EMPTY_SELECTOR: root::_bindgen_ty_84 =
- _bindgen_ty_84::NODE_HAS_EMPTY_SELECTOR;
- pub const NODE_HAS_SLOW_SELECTOR: root::_bindgen_ty_84 =
- _bindgen_ty_84::NODE_HAS_SLOW_SELECTOR;
- pub const NODE_HAS_EDGE_CHILD_SELECTOR: root::_bindgen_ty_84 =
- _bindgen_ty_84::NODE_HAS_EDGE_CHILD_SELECTOR;
- pub const NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS: root::_bindgen_ty_84 =
- _bindgen_ty_84::NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS;
- pub const NODE_ALL_SELECTOR_FLAGS: root::_bindgen_ty_84 =
- _bindgen_ty_84::NODE_ALL_SELECTOR_FLAGS;
- pub const NODE_NEEDS_FRAME: root::_bindgen_ty_84 =
- _bindgen_ty_84::NODE_NEEDS_FRAME;
- pub const NODE_DESCENDANTS_NEED_FRAMES: root::_bindgen_ty_84 =
- _bindgen_ty_84::NODE_DESCENDANTS_NEED_FRAMES;
- pub const NODE_HAS_ACCESSKEY: root::_bindgen_ty_84 =
- _bindgen_ty_84::NODE_HAS_ACCESSKEY;
- pub const NODE_HAS_DIRECTION_RTL: root::_bindgen_ty_84 =
- _bindgen_ty_84::NODE_HAS_DIRECTION_RTL;
- pub const NODE_HAS_DIRECTION_LTR: root::_bindgen_ty_84 =
- _bindgen_ty_84::NODE_HAS_DIRECTION_LTR;
- pub const NODE_ALL_DIRECTION_FLAGS: root::_bindgen_ty_84 =
- _bindgen_ty_84::NODE_ALL_DIRECTION_FLAGS;
- pub const NODE_CHROME_ONLY_ACCESS: root::_bindgen_ty_84 =
- _bindgen_ty_84::NODE_CHROME_ONLY_ACCESS;
- pub const NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS: root::_bindgen_ty_84 =
- _bindgen_ty_84::NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS;
- pub const NODE_TYPE_SPECIFIC_BITS_OFFSET: root::_bindgen_ty_84 =
- _bindgen_ty_84::NODE_TYPE_SPECIFIC_BITS_OFFSET;
+ pub const NODE_HAS_LISTENERMANAGER: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_HAS_LISTENERMANAGER;
+ pub const NODE_HAS_PROPERTIES: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_HAS_PROPERTIES;
+ pub const NODE_IS_ANONYMOUS_ROOT: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_IS_ANONYMOUS_ROOT;
+ pub const NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE;
+ pub const NODE_IS_NATIVE_ANONYMOUS_ROOT: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_IS_NATIVE_ANONYMOUS_ROOT;
+ pub const NODE_FORCE_XBL_BINDINGS: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_FORCE_XBL_BINDINGS;
+ pub const NODE_MAY_BE_IN_BINDING_MNGR: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_MAY_BE_IN_BINDING_MNGR;
+ pub const NODE_IS_EDITABLE: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_IS_EDITABLE;
+ pub const NODE_IS_NATIVE_ANONYMOUS: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_IS_NATIVE_ANONYMOUS;
+ pub const NODE_IS_IN_SHADOW_TREE: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_IS_IN_SHADOW_TREE;
+ pub const NODE_HAS_EMPTY_SELECTOR: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_HAS_EMPTY_SELECTOR;
+ pub const NODE_HAS_SLOW_SELECTOR: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_HAS_SLOW_SELECTOR;
+ pub const NODE_HAS_EDGE_CHILD_SELECTOR: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_HAS_EDGE_CHILD_SELECTOR;
+ pub const NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS;
+ pub const NODE_ALL_SELECTOR_FLAGS: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_ALL_SELECTOR_FLAGS;
+ pub const NODE_NEEDS_FRAME: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_NEEDS_FRAME;
+ pub const NODE_DESCENDANTS_NEED_FRAMES: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_DESCENDANTS_NEED_FRAMES;
+ pub const NODE_HAS_ACCESSKEY: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_HAS_ACCESSKEY;
+ pub const NODE_HAS_DIRECTION_RTL: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_HAS_DIRECTION_RTL;
+ pub const NODE_HAS_DIRECTION_LTR: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_HAS_DIRECTION_LTR;
+ pub const NODE_ALL_DIRECTION_FLAGS: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_ALL_DIRECTION_FLAGS;
+ pub const NODE_CHROME_ONLY_ACCESS: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_CHROME_ONLY_ACCESS;
+ pub const NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS;
+ pub const NODE_TYPE_SPECIFIC_BITS_OFFSET: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_TYPE_SPECIFIC_BITS_OFFSET;
#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
- pub enum _bindgen_ty_84 {
+ pub enum _bindgen_ty_17 {
NODE_HAS_LISTENERMANAGER = 4,
NODE_HAS_PROPERTIES = 8,
NODE_IS_ANONYMOUS_ROOT = 16,
@@ -27266,7 +27263,7 @@ pub mod root {
pub type imgRequest_HasThreadSafeRefCnt = root::mozilla::TrueType;
#[test]
fn bindgen_test_layout_imgRequest() {
- assert_eq!(::std::mem::size_of::<imgRequest>() , 416usize , concat ! (
+ assert_eq!(::std::mem::size_of::<imgRequest>() , 440usize , concat ! (
"Size of: " , stringify ! ( imgRequest ) ));
assert_eq! (::std::mem::align_of::<imgRequest>() , 8usize , concat ! (
"Alignment of " , stringify ! ( imgRequest ) ));
@@ -28682,7 +28679,7 @@ pub mod root {
) , "::" , stringify ! ( mQuotePairs ) ));
}
#[test]
- fn __bindgen_test_layout_StaticRefPtr_instantiation_174951() {
+ fn __bindgen_test_layout_StaticRefPtr_instantiation_151733() {
assert_eq!(::std::mem::size_of::<root::mozilla::StaticRefPtr<root::nsStyleQuoteValues>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31150,48 +31147,48 @@ pub mod root {
pub struct nsAttrValueOrString {
_unused: [u8; 0],
}
- pub const ELEMENT_SHARED_RESTYLE_BIT_1: root::_bindgen_ty_86 =
- _bindgen_ty_86::ELEMENT_SHARED_RESTYLE_BIT_1;
- pub const ELEMENT_SHARED_RESTYLE_BIT_2: root::_bindgen_ty_86 =
- _bindgen_ty_86::ELEMENT_SHARED_RESTYLE_BIT_2;
- pub const ELEMENT_SHARED_RESTYLE_BIT_3: root::_bindgen_ty_86 =
- _bindgen_ty_86::ELEMENT_SHARED_RESTYLE_BIT_3;
- pub const ELEMENT_SHARED_RESTYLE_BIT_4: root::_bindgen_ty_86 =
- _bindgen_ty_86::ELEMENT_SHARED_RESTYLE_BIT_4;
- pub const ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO: root::_bindgen_ty_86 =
- _bindgen_ty_86::ELEMENT_SHARED_RESTYLE_BIT_1;
+ pub const ELEMENT_SHARED_RESTYLE_BIT_1: root::_bindgen_ty_19 =
+ _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_1;
+ pub const ELEMENT_SHARED_RESTYLE_BIT_2: root::_bindgen_ty_19 =
+ _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_2;
+ pub const ELEMENT_SHARED_RESTYLE_BIT_3: root::_bindgen_ty_19 =
+ _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_3;
+ pub const ELEMENT_SHARED_RESTYLE_BIT_4: root::_bindgen_ty_19 =
+ _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_4;
+ pub const ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO: root::_bindgen_ty_19 =
+ _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_1;
pub const ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO:
- root::_bindgen_ty_86 =
- _bindgen_ty_86::ELEMENT_SHARED_RESTYLE_BIT_2;
- pub const ELEMENT_HAS_SNAPSHOT: root::_bindgen_ty_86 =
- _bindgen_ty_86::ELEMENT_SHARED_RESTYLE_BIT_3;
- pub const ELEMENT_HANDLED_SNAPSHOT: root::_bindgen_ty_86 =
- _bindgen_ty_86::ELEMENT_SHARED_RESTYLE_BIT_4;
- pub const ELEMENT_HAS_PENDING_RESTYLE: root::_bindgen_ty_86 =
- _bindgen_ty_86::ELEMENT_SHARED_RESTYLE_BIT_1;
- pub const ELEMENT_IS_POTENTIAL_RESTYLE_ROOT: root::_bindgen_ty_86 =
- _bindgen_ty_86::ELEMENT_SHARED_RESTYLE_BIT_2;
- pub const ELEMENT_HAS_PENDING_ANIMATION_ONLY_RESTYLE: root::_bindgen_ty_86
+ root::_bindgen_ty_19 =
+ _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_2;
+ pub const ELEMENT_HAS_SNAPSHOT: root::_bindgen_ty_19 =
+ _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_3;
+ pub const ELEMENT_HANDLED_SNAPSHOT: root::_bindgen_ty_19 =
+ _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_4;
+ pub const ELEMENT_HAS_PENDING_RESTYLE: root::_bindgen_ty_19 =
+ _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_1;
+ pub const ELEMENT_IS_POTENTIAL_RESTYLE_ROOT: root::_bindgen_ty_19 =
+ _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_2;
+ pub const ELEMENT_HAS_PENDING_ANIMATION_ONLY_RESTYLE: root::_bindgen_ty_19
=
- _bindgen_ty_86::ELEMENT_SHARED_RESTYLE_BIT_3;
+ _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_3;
pub const ELEMENT_IS_POTENTIAL_ANIMATION_ONLY_RESTYLE_ROOT:
- root::_bindgen_ty_86 =
- _bindgen_ty_86::ELEMENT_SHARED_RESTYLE_BIT_4;
- pub const ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR: root::_bindgen_ty_86 =
- _bindgen_ty_86::ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR;
- pub const ELEMENT_PENDING_RESTYLE_FLAGS: root::_bindgen_ty_86 =
- _bindgen_ty_86::ELEMENT_PENDING_RESTYLE_FLAGS;
- pub const ELEMENT_POTENTIAL_RESTYLE_ROOT_FLAGS: root::_bindgen_ty_86 =
- _bindgen_ty_86::ELEMENT_POTENTIAL_RESTYLE_ROOT_FLAGS;
- pub const ELEMENT_ALL_RESTYLE_FLAGS: root::_bindgen_ty_86 =
- _bindgen_ty_86::ELEMENT_ALL_RESTYLE_FLAGS;
- pub const ELEMENT_HAS_SCROLLGRAB: root::_bindgen_ty_86 =
- _bindgen_ty_86::ELEMENT_HAS_SCROLLGRAB;
- pub const ELEMENT_TYPE_SPECIFIC_BITS_OFFSET: root::_bindgen_ty_86 =
- _bindgen_ty_86::ELEMENT_TYPE_SPECIFIC_BITS_OFFSET;
+ root::_bindgen_ty_19 =
+ _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_4;
+ pub const ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR: root::_bindgen_ty_19 =
+ _bindgen_ty_19::ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR;
+ pub const ELEMENT_PENDING_RESTYLE_FLAGS: root::_bindgen_ty_19 =
+ _bindgen_ty_19::ELEMENT_PENDING_RESTYLE_FLAGS;
+ pub const ELEMENT_POTENTIAL_RESTYLE_ROOT_FLAGS: root::_bindgen_ty_19 =
+ _bindgen_ty_19::ELEMENT_POTENTIAL_RESTYLE_ROOT_FLAGS;
+ pub const ELEMENT_ALL_RESTYLE_FLAGS: root::_bindgen_ty_19 =
+ _bindgen_ty_19::ELEMENT_ALL_RESTYLE_FLAGS;
+ pub const ELEMENT_HAS_SCROLLGRAB: root::_bindgen_ty_19 =
+ _bindgen_ty_19::ELEMENT_HAS_SCROLLGRAB;
+ pub const ELEMENT_TYPE_SPECIFIC_BITS_OFFSET: root::_bindgen_ty_19 =
+ _bindgen_ty_19::ELEMENT_TYPE_SPECIFIC_BITS_OFFSET;
#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
- pub enum _bindgen_ty_86 {
+ pub enum _bindgen_ty_19 {
ELEMENT_SHARED_RESTYLE_BIT_1 = 8388608,
ELEMENT_SHARED_RESTYLE_BIT_2 = 16777216,
ELEMENT_SHARED_RESTYLE_BIT_3 = 33554432,
@@ -31960,7 +31957,7 @@ pub mod root {
}
pub type __builtin_va_list = [root::__va_list_tag; 1usize];
#[test]
- fn __bindgen_test_layout_IntegralConstant_instantiation_202803() {
+ fn __bindgen_test_layout_IntegralConstant_instantiation_173405() {
assert_eq!(::std::mem::size_of::<u8>() , 1usize , concat ! (
"Size of template specialization: " , stringify ! ( u8 )
));
@@ -31969,7 +31966,7 @@ pub mod root {
) ));
}
#[test]
- fn __bindgen_test_layout_IntegralConstant_instantiation_202807() {
+ fn __bindgen_test_layout_IntegralConstant_instantiation_173409() {
assert_eq!(::std::mem::size_of::<u8>() , 1usize , concat ! (
"Size of template specialization: " , stringify ! ( u8 )
));
@@ -31978,7 +31975,7 @@ pub mod root {
) ));
}
#[test]
- fn __bindgen_test_layout_nsReadingIterator_instantiation_203634() {
+ fn __bindgen_test_layout_nsReadingIterator_instantiation_173626() {
assert_eq!(::std::mem::size_of::<root::nsReadingIterator<u16>>() ,
24usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31989,7 +31986,7 @@ pub mod root {
root::nsReadingIterator<u16> ) ));
}
#[test]
- fn __bindgen_test_layout_nsWritingIterator_instantiation_203638() {
+ fn __bindgen_test_layout_nsWritingIterator_instantiation_173630() {
assert_eq!(::std::mem::size_of::<root::nsWritingIterator<u16>>() ,
24usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32000,7 +31997,7 @@ pub mod root {
root::nsWritingIterator<u16> ) ));
}
#[test]
- fn __bindgen_test_layout_nsReadingIterator_instantiation_203711() {
+ fn __bindgen_test_layout_nsReadingIterator_instantiation_173703() {
assert_eq!(::std::mem::size_of::<root::nsReadingIterator<::std::os::raw::c_char>>()
, 24usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32011,7 +32008,7 @@ pub mod root {
root::nsReadingIterator<::std::os::raw::c_char> ) ));
}
#[test]
- fn __bindgen_test_layout_nsWritingIterator_instantiation_203715() {
+ fn __bindgen_test_layout_nsWritingIterator_instantiation_173707() {
assert_eq!(::std::mem::size_of::<root::nsWritingIterator<::std::os::raw::c_char>>()
, 24usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32022,7 +32019,25 @@ pub mod root {
root::nsWritingIterator<::std::os::raw::c_char> ) ));
}
#[test]
- fn __bindgen_test_layout__bindgen_ty_id_209541_instantiation_209538() {
+ fn __bindgen_test_layout_atomic_instantiation_175747() {
+ assert_eq!(::std::mem::size_of::<u32>() , 4usize , concat ! (
+ "Size of template specialization: " , stringify ! ( u32 )
+ ));
+ assert_eq!(::std::mem::align_of::<u32>() , 4usize , concat ! (
+ "Alignment of template specialization: " , stringify ! (
+ u32 ) ));
+ }
+ #[test]
+ fn __bindgen_test_layout_atomic_instantiation_175755() {
+ assert_eq!(::std::mem::size_of::<u64>() , 8usize , concat ! (
+ "Size of template specialization: " , stringify ! ( u64 )
+ ));
+ assert_eq!(::std::mem::align_of::<u64>() , 8usize , concat ! (
+ "Alignment of template specialization: " , stringify ! (
+ u64 ) ));
+ }
+ #[test]
+ fn __bindgen_test_layout__bindgen_ty_id_176012_instantiation_176009() {
assert_eq!(::std::mem::size_of::<u8>() , 1usize , concat ! (
"Size of template specialization: " , stringify ! ( u8 )
));
@@ -32031,7 +32046,7 @@ pub mod root {
) ));
}
#[test]
- fn __bindgen_test_layout__bindgen_ty_id_209574_instantiation_209571() {
+ fn __bindgen_test_layout__bindgen_ty_id_176045_instantiation_176042() {
assert_eq!(::std::mem::size_of::<u8>() , 1usize , concat ! (
"Size of template specialization: " , stringify ! ( u8 )
));
@@ -32040,7 +32055,7 @@ pub mod root {
) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_209842() {
+ fn __bindgen_test_layout_nsTArray_instantiation_176313() {
assert_eq!(::std::mem::size_of::<root::nsTArray<root::nsCString>>() ,
8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32051,7 +32066,7 @@ pub mod root {
root::nsTArray<root::nsCString> ) ));
}
#[test]
- fn __bindgen_test_layout_Handle_instantiation_210801() {
+ fn __bindgen_test_layout_Handle_instantiation_177145() {
assert_eq!(::std::mem::size_of::<root::JS::Handle<*mut root::JSObject>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32062,7 +32077,7 @@ pub mod root {
root::JS::Handle<*mut root::JSObject> ) ));
}
#[test]
- fn __bindgen_test_layout_Handle_instantiation_210817() {
+ fn __bindgen_test_layout_Handle_instantiation_177161() {
assert_eq!(::std::mem::size_of::<root::JS::Handle<root::JS::Value>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32073,7 +32088,7 @@ pub mod root {
root::JS::Handle<root::JS::Value> ) ));
}
#[test]
- fn __bindgen_test_layout_MutableHandle_instantiation_210827() {
+ fn __bindgen_test_layout_MutableHandle_instantiation_177171() {
assert_eq!(::std::mem::size_of::<root::JS::MutableHandle<*mut root::JSObject>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32084,7 +32099,7 @@ pub mod root {
root::JS::MutableHandle<*mut root::JSObject> ) ));
}
#[test]
- fn __bindgen_test_layout_MutableHandle_instantiation_210843() {
+ fn __bindgen_test_layout_MutableHandle_instantiation_177187() {
assert_eq!(::std::mem::size_of::<root::JS::MutableHandle<root::JS::Value>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32095,7 +32110,7 @@ pub mod root {
root::JS::MutableHandle<root::JS::Value> ) ));
}
#[test]
- fn __bindgen_test_layout_Rooted_instantiation_210846() {
+ fn __bindgen_test_layout_Rooted_instantiation_177190() {
assert_eq!(::std::mem::size_of::<[u64; 3usize]>() , 24usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32106,7 +32121,7 @@ pub mod root {
[u64; 3usize] ) ));
}
#[test]
- fn __bindgen_test_layout_DeletePolicy_instantiation_211183() {
+ fn __bindgen_test_layout_DeletePolicy_instantiation_177527() {
assert_eq!(::std::mem::size_of::<root::JS::DeletePolicy>() , 1usize ,
concat ! (
"Size of template specialization: " , stringify ! (
@@ -32117,7 +32132,7 @@ pub mod root {
root::JS::DeletePolicy ) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_213233() {
+ fn __bindgen_test_layout_nsTArray_instantiation_182503() {
assert_eq!(::std::mem::size_of::<root::nsTArray<::nsstring::nsStringRepr>>() ,
8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32128,7 +32143,7 @@ pub mod root {
root::nsTArray<::nsstring::nsStringRepr> ) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_213237() {
+ fn __bindgen_test_layout_nsTArray_instantiation_182507() {
assert_eq!(::std::mem::size_of::<root::nsTArray<root::mozilla::FontFamilyName>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32139,7 +32154,7 @@ pub mod root {
root::nsTArray<root::mozilla::FontFamilyName> ) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_213250() {
+ fn __bindgen_test_layout_nsTArray_instantiation_182520() {
assert_eq!(::std::mem::size_of::<root::nsTArray<::std::os::raw::c_uint>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32150,7 +32165,7 @@ pub mod root {
root::nsTArray<::std::os::raw::c_uint> ) ));
}
#[test]
- fn __bindgen_test_layout_TenuredHeap_instantiation_214375() {
+ fn __bindgen_test_layout_TenuredHeap_instantiation_183432() {
assert_eq!(::std::mem::size_of::<root::JS::TenuredHeap>() , 8usize ,
concat ! (
"Size of template specialization: " , stringify ! (
@@ -32161,7 +32176,7 @@ pub mod root {
root::JS::TenuredHeap ) ));
}
#[test]
- fn __bindgen_test_layout_Heap_instantiation_214465() {
+ fn __bindgen_test_layout_Heap_instantiation_183522() {
assert_eq!(::std::mem::size_of::<root::JS::Heap<*mut root::JSObject>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32172,7 +32187,7 @@ pub mod root {
root::JS::Heap<*mut root::JSObject> ) ));
}
#[test]
- fn __bindgen_test_layout_Heap_instantiation_214580() {
+ fn __bindgen_test_layout_Heap_instantiation_183637() {
assert_eq!(::std::mem::size_of::<root::JS::Heap<root::JS::Value>>() ,
8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32183,7 +32198,7 @@ pub mod root {
root::JS::Heap<root::JS::Value> ) ));
}
#[test]
- fn __bindgen_test_layout_TErrorResult_instantiation_214587() {
+ fn __bindgen_test_layout_TErrorResult_instantiation_183644() {
assert_eq!(::std::mem::size_of::<root::mozilla::binding_danger::TErrorResult>()
, 32usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32194,7 +32209,7 @@ pub mod root {
root::mozilla::binding_danger::TErrorResult ) ));
}
#[test]
- fn __bindgen_test_layout_TErrorResult_instantiation_214603() {
+ fn __bindgen_test_layout_TErrorResult_instantiation_183660() {
assert_eq!(::std::mem::size_of::<root::mozilla::binding_danger::TErrorResult>()
, 32usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32205,7 +32220,7 @@ pub mod root {
root::mozilla::binding_danger::TErrorResult ) ));
}
#[test]
- fn __bindgen_test_layout_already_AddRefed_instantiation_214608() {
+ fn __bindgen_test_layout_already_AddRefed_instantiation_183666() {
assert_eq!(::std::mem::size_of::<root::already_AddRefed<root::nsStringBuffer>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32216,7 +32231,7 @@ pub mod root {
root::already_AddRefed<root::nsStringBuffer> ) ));
}
#[test]
- fn __bindgen_test_layout_already_AddRefed_instantiation_214660() {
+ fn __bindgen_test_layout_already_AddRefed_instantiation_183718() {
assert_eq!(::std::mem::size_of::<root::already_AddRefed<root::nsIAtom>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32227,7 +32242,7 @@ pub mod root {
root::already_AddRefed<root::nsIAtom> ) ));
}
#[test]
- fn __bindgen_test_layout_RefPtr_instantiation_215143() {
+ fn __bindgen_test_layout_RefPtr_instantiation_184201() {
assert_eq!(::std::mem::size_of::<root::RefPtr<root::mozilla::StyleSheet>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32238,7 +32253,7 @@ pub mod root {
root::RefPtr<root::mozilla::StyleSheet> ) ));
}
#[test]
- fn __bindgen_test_layout_already_AddRefed_instantiation_215489() {
+ fn __bindgen_test_layout_already_AddRefed_instantiation_184547() {
assert_eq!(::std::mem::size_of::<root::already_AddRefed<root::mozilla::dom::NodeInfo>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32249,7 +32264,7 @@ pub mod root {
root::already_AddRefed<root::mozilla::dom::NodeInfo> ) ));
}
#[test]
- fn __bindgen_test_layout_already_AddRefed_instantiation_215734() {
+ fn __bindgen_test_layout_already_AddRefed_instantiation_184792() {
assert_eq!(::std::mem::size_of::<root::already_AddRefed<root::nsIURI>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32260,7 +32275,7 @@ pub mod root {
root::already_AddRefed<root::nsIURI> ) ));
}
#[test]
- fn __bindgen_test_layout_already_AddRefed_instantiation_215881() {
+ fn __bindgen_test_layout_already_AddRefed_instantiation_184939() {
assert_eq!(::std::mem::size_of::<root::already_AddRefed<root::nsINode>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32271,7 +32286,7 @@ pub mod root {
root::already_AddRefed<root::nsINode> ) ));
}
#[test]
- fn __bindgen_test_layout_DeletePolicy_instantiation_220000() {
+ fn __bindgen_test_layout_DeletePolicy_instantiation_189058() {
assert_eq!(::std::mem::size_of::<root::JS::DeletePolicy>() , 1usize ,
concat ! (
"Size of template specialization: " , stringify ! (
@@ -32282,7 +32297,7 @@ pub mod root {
root::JS::DeletePolicy ) ));
}
#[test]
- fn __bindgen_test_layout_UniquePtr_instantiation_219998() {
+ fn __bindgen_test_layout_UniquePtr_instantiation_189056() {
assert_eq!(::std::mem::size_of::<root::mozilla::UniquePtr<root::JSErrorNotes_Note>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32293,7 +32308,7 @@ pub mod root {
root::mozilla::UniquePtr<root::JSErrorNotes_Note> ) ));
}
#[test]
- fn __bindgen_test_layout_iterator_instantiation_220033() {
+ fn __bindgen_test_layout_iterator_instantiation_189091() {
assert_eq!(::std::mem::size_of::<root::std::iterator>() , 1usize ,
concat ! (
"Size of template specialization: " , stringify ! (
@@ -32304,7 +32319,7 @@ pub mod root {
root::std::iterator ) ));
}
#[test]
- fn __bindgen_test_layout_nsCOMPtr_instantiation_220601() {
+ fn __bindgen_test_layout_nsCOMPtr_instantiation_189647() {
assert_eq!(::std::mem::size_of::<root::nsCOMPtr<root::nsIPrincipal>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32315,7 +32330,7 @@ pub mod root {
root::nsCOMPtr<root::nsIPrincipal> ) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_222194() {
+ fn __bindgen_test_layout_nsTArray_instantiation_191240() {
assert_eq!(::std::mem::size_of::<root::nsTArray<root::RefPtr<root::mozilla::dom::AnonymousContent>>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32328,7 +32343,7 @@ pub mod root {
) ));
}
#[test]
- fn __bindgen_test_layout_LinkedList_instantiation_222470() {
+ fn __bindgen_test_layout_LinkedList_instantiation_191516() {
assert_eq!(::std::mem::size_of::<root::mozilla::LinkedList>() ,
24usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32339,7 +32354,7 @@ pub mod root {
root::mozilla::LinkedList ) ));
}
#[test]
- fn __bindgen_test_layout_RefPtr_instantiation_222486() {
+ fn __bindgen_test_layout_RefPtr_instantiation_191532() {
assert_eq!(::std::mem::size_of::<root::RefPtr<root::mozilla::dom::Element>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32350,7 +32365,7 @@ pub mod root {
root::RefPtr<root::mozilla::dom::Element> ) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_222485() {
+ fn __bindgen_test_layout_nsTArray_instantiation_191531() {
assert_eq!(::std::mem::size_of::<root::nsTArray<root::RefPtr<root::mozilla::dom::Element>>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32363,7 +32378,7 @@ pub mod root {
));
}
#[test]
- fn __bindgen_test_layout_nsCOMPtr_instantiation_222515() {
+ fn __bindgen_test_layout_nsCOMPtr_instantiation_191561() {
assert_eq!(::std::mem::size_of::<root::nsCOMPtr<root::nsIObserver>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32374,7 +32389,7 @@ pub mod root {
root::nsCOMPtr<root::nsIObserver> ) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_222514() {
+ fn __bindgen_test_layout_nsTArray_instantiation_191560() {
assert_eq!(::std::mem::size_of::<root::nsTArray<root::nsCOMPtr<root::nsIObserver>>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32385,7 +32400,7 @@ pub mod root {
root::nsTArray<root::nsCOMPtr<root::nsIObserver>> ) ));
}
#[test]
- fn __bindgen_test_layout_already_AddRefed_instantiation_222560() {
+ fn __bindgen_test_layout_already_AddRefed_instantiation_191606() {
assert_eq!(::std::mem::size_of::<root::already_AddRefed<root::nsIDocument>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32396,7 +32411,7 @@ pub mod root {
root::already_AddRefed<root::nsIDocument> ) ));
}
#[test]
- fn __bindgen_test_layout_already_AddRefed_instantiation_222725() {
+ fn __bindgen_test_layout_already_AddRefed_instantiation_191771() {
assert_eq!(::std::mem::size_of::<root::already_AddRefed<root::nsContentList>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32407,7 +32422,7 @@ pub mod root {
root::already_AddRefed<root::nsContentList> ) ));
}
#[test]
- fn __bindgen_test_layout_already_AddRefed_instantiation_223052() {
+ fn __bindgen_test_layout_already_AddRefed_instantiation_192098() {
assert_eq!(::std::mem::size_of::<root::already_AddRefed<root::nsIRunnable>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32418,7 +32433,7 @@ pub mod root {
root::already_AddRefed<root::nsIRunnable> ) ));
}
#[test]
- fn __bindgen_test_layout_nsCOMPtr_instantiation_223145() {
+ fn __bindgen_test_layout_nsCOMPtr_instantiation_192191() {
assert_eq!(::std::mem::size_of::<root::nsCOMPtr<root::mozilla::dom::Link>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32429,7 +32444,7 @@ pub mod root {
root::nsCOMPtr<root::mozilla::dom::Link> ) ));
}
#[test]
- fn __bindgen_test_layout_nsCOMPtr_instantiation_223182() {
+ fn __bindgen_test_layout_nsCOMPtr_instantiation_192228() {
assert_eq!(::std::mem::size_of::<root::nsCOMPtr<root::nsIWeakReference>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32440,7 +32455,7 @@ pub mod root {
root::nsCOMPtr<root::nsIWeakReference> ) ));
}
#[test]
- fn __bindgen_test_layout_DefaultDelete_instantiation_223440() {
+ fn __bindgen_test_layout_DefaultDelete_instantiation_192486() {
assert_eq!(::std::mem::size_of::<root::mozilla::DefaultDelete>() ,
1usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32451,7 +32466,7 @@ pub mod root {
root::mozilla::DefaultDelete ) ));
}
#[test]
- fn __bindgen_test_layout_UniquePtr_instantiation_223438() {
+ fn __bindgen_test_layout_UniquePtr_instantiation_192484() {
assert_eq!(::std::mem::size_of::<root::mozilla::UniquePtr<root::nsISMILAttr>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32462,7 +32477,7 @@ pub mod root {
root::mozilla::UniquePtr<root::nsISMILAttr> ) ));
}
#[test]
- fn __bindgen_test_layout_nsRefPtrHashKey_instantiation_223988() {
+ fn __bindgen_test_layout_nsRefPtrHashKey_instantiation_193034() {
assert_eq!(::std::mem::size_of::<root::nsRefPtrHashKey<root::mozilla::dom::DOMIntersectionObserver>>()
, 16usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32475,7 +32490,7 @@ pub mod root {
) ));
}
#[test]
- fn __bindgen_test_layout_nsDataHashtable_instantiation_223987() {
+ fn __bindgen_test_layout_nsDataHashtable_instantiation_193033() {
assert_eq!(::std::mem::size_of::<[u64; 6usize]>() , 48usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32486,7 +32501,7 @@ pub mod root {
[u64; 6usize] ) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_224194() {
+ fn __bindgen_test_layout_nsTArray_instantiation_193240() {
assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsIContent>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32497,7 +32512,7 @@ pub mod root {
root::nsTArray<*mut root::nsIContent> ) ));
}
#[test]
- fn __bindgen_test_layout_SupportsWeakPtr_instantiation_224245() {
+ fn __bindgen_test_layout_SupportsWeakPtr_instantiation_193291() {
assert_eq!(::std::mem::size_of::<u64>() , 8usize , concat ! (
"Size of template specialization: " , stringify ! ( u64 )
));
@@ -32506,7 +32521,7 @@ pub mod root {
u64 ) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_224425() {
+ fn __bindgen_test_layout_nsTArray_instantiation_193466() {
assert_eq!(::std::mem::size_of::<root::nsTArray<root::nsRect>>() ,
8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32517,7 +32532,7 @@ pub mod root {
root::nsTArray<root::nsRect> ) ));
}
#[test]
- fn __bindgen_test_layout_DefaultDelete_instantiation_224541() {
+ fn __bindgen_test_layout_DefaultDelete_instantiation_193582() {
assert_eq!(::std::mem::size_of::<root::mozilla::DefaultDelete>() ,
1usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32528,7 +32543,7 @@ pub mod root {
root::mozilla::DefaultDelete ) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_224710() {
+ fn __bindgen_test_layout_nsTArray_instantiation_193751() {
assert_eq!(::std::mem::size_of::<root::nsTArray<root::nsCOMPtr<root::nsIAtom>>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32539,7 +32554,7 @@ pub mod root {
root::nsTArray<root::nsCOMPtr<root::nsIAtom>> ) ));
}
#[test]
- fn __bindgen_test_layout_nsPIDOMWindow_instantiation_225497() {
+ fn __bindgen_test_layout_nsPIDOMWindow_instantiation_194538() {
assert_eq!(::std::mem::size_of::<[u64; 29usize]>() , 232usize , concat
! (
"Size of template specialization: " , stringify ! (
@@ -32550,7 +32565,7 @@ pub mod root {
[u64; 29usize] ) ));
}
#[test]
- fn __bindgen_test_layout_already_AddRefed_instantiation_225589() {
+ fn __bindgen_test_layout_already_AddRefed_instantiation_194590() {
assert_eq!(::std::mem::size_of::<root::already_AddRefed<root::nsIContent>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32561,7 +32576,7 @@ pub mod root {
root::already_AddRefed<root::nsIContent> ) ));
}
#[test]
- fn __bindgen_test_layout_nsRefPtrHashtable_instantiation_225770() {
+ fn __bindgen_test_layout_nsRefPtrHashtable_instantiation_194771() {
assert_eq!(::std::mem::size_of::<[u64; 6usize]>() , 48usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32572,7 +32587,7 @@ pub mod root {
[u64; 6usize] ) ));
}
#[test]
- fn __bindgen_test_layout_nsPtrHashKey_instantiation_226293() {
+ fn __bindgen_test_layout_nsPtrHashKey_instantiation_195278() {
assert_eq!(::std::mem::size_of::<root::nsPtrHashKey<::std::os::raw::c_void>>()
, 16usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32583,7 +32598,7 @@ pub mod root {
root::nsPtrHashKey<::std::os::raw::c_void> ) ));
}
#[test]
- fn __bindgen_test_layout_nsPtrHashKey_instantiation_226301() {
+ fn __bindgen_test_layout_nsPtrHashKey_instantiation_195286() {
assert_eq!(::std::mem::size_of::<root::nsPtrHashKey<root::WeakFrame>>()
, 16usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32594,7 +32609,7 @@ pub mod root {
root::nsPtrHashKey<root::WeakFrame> ) ));
}
#[test]
- fn __bindgen_test_layout_OwningNonNull_instantiation_226416() {
+ fn __bindgen_test_layout_OwningNonNull_instantiation_195401() {
assert_eq!(::std::mem::size_of::<root::mozilla::OwningNonNull<root::nsINode>>()
, 16usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32605,7 +32620,7 @@ pub mod root {
root::mozilla::OwningNonNull<root::nsINode> ) ));
}
#[test]
- fn __bindgen_test_layout_PointTyped_instantiation_227495() {
+ fn __bindgen_test_layout_PointTyped_instantiation_196480() {
assert_eq!(::std::mem::size_of::<[u32; 2usize]>() , 8usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32616,7 +32631,7 @@ pub mod root {
[u32; 2usize] ) ));
}
#[test]
- fn __bindgen_test_layout_IntPointTyped_instantiation_227500() {
+ fn __bindgen_test_layout_IntPointTyped_instantiation_196485() {
assert_eq!(::std::mem::size_of::<[u32; 2usize]>() , 8usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32627,7 +32642,7 @@ pub mod root {
[u32; 2usize] ) ));
}
#[test]
- fn __bindgen_test_layout_SizeTyped_instantiation_227503() {
+ fn __bindgen_test_layout_SizeTyped_instantiation_196488() {
assert_eq!(::std::mem::size_of::<[u32; 2usize]>() , 8usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32638,7 +32653,7 @@ pub mod root {
[u32; 2usize] ) ));
}
#[test]
- fn __bindgen_test_layout_RectTyped_instantiation_227511() {
+ fn __bindgen_test_layout_RectTyped_instantiation_196496() {
assert_eq!(::std::mem::size_of::<[u32; 4usize]>() , 16usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32649,7 +32664,7 @@ pub mod root {
[u32; 4usize] ) ));
}
#[test]
- fn __bindgen_test_layout_IntPointTyped_instantiation_227543() {
+ fn __bindgen_test_layout_IntPointTyped_instantiation_196528() {
assert_eq!(::std::mem::size_of::<[u32; 2usize]>() , 8usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32660,7 +32675,7 @@ pub mod root {
[u32; 2usize] ) ));
}
#[test]
- fn __bindgen_test_layout_IntSizeTyped_instantiation_227551() {
+ fn __bindgen_test_layout_IntSizeTyped_instantiation_196536() {
assert_eq!(::std::mem::size_of::<[u32; 2usize]>() , 8usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32671,7 +32686,7 @@ pub mod root {
[u32; 2usize] ) ));
}
#[test]
- fn __bindgen_test_layout_IntRectTyped_instantiation_227559() {
+ fn __bindgen_test_layout_IntRectTyped_instantiation_196544() {
assert_eq!(::std::mem::size_of::<[u32; 4usize]>() , 16usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32682,7 +32697,7 @@ pub mod root {
[u32; 4usize] ) ));
}
#[test]
- fn __bindgen_test_layout_MarginTyped_instantiation_227726() {
+ fn __bindgen_test_layout_MarginTyped_instantiation_196711() {
assert_eq!(::std::mem::size_of::<[u32; 4usize]>() , 16usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32693,7 +32708,7 @@ pub mod root {
[u32; 4usize] ) ));
}
#[test]
- fn __bindgen_test_layout_RectTyped_instantiation_227761() {
+ fn __bindgen_test_layout_RectTyped_instantiation_196746() {
assert_eq!(::std::mem::size_of::<[u32; 4usize]>() , 16usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32704,7 +32719,7 @@ pub mod root {
[u32; 4usize] ) ));
}
#[test]
- fn __bindgen_test_layout_IntRectTyped_instantiation_227766() {
+ fn __bindgen_test_layout_IntRectTyped_instantiation_196751() {
assert_eq!(::std::mem::size_of::<[u32; 4usize]>() , 16usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32715,7 +32730,7 @@ pub mod root {
[u32; 4usize] ) ));
}
#[test]
- fn __bindgen_test_layout_ScaleFactor_instantiation_227812() {
+ fn __bindgen_test_layout_ScaleFactor_instantiation_196797() {
assert_eq!(::std::mem::size_of::<u32>() , 4usize , concat ! (
"Size of template specialization: " , stringify ! ( u32 )
));
@@ -32724,7 +32739,7 @@ pub mod root {
u32 ) ));
}
#[test]
- fn __bindgen_test_layout_ScaleFactors2D_instantiation_227912() {
+ fn __bindgen_test_layout_ScaleFactors2D_instantiation_196897() {
assert_eq!(::std::mem::size_of::<[u32; 2usize]>() , 8usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32735,7 +32750,7 @@ pub mod root {
[u32; 2usize] ) ));
}
#[test]
- fn __bindgen_test_layout_ScaleFactors2D_instantiation_227920() {
+ fn __bindgen_test_layout_ScaleFactors2D_instantiation_196905() {
assert_eq!(::std::mem::size_of::<[u32; 2usize]>() , 8usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32746,7 +32761,7 @@ pub mod root {
[u32; 2usize] ) ));
}
#[test]
- fn __bindgen_test_layout_ScaleFactors2D_instantiation_227964() {
+ fn __bindgen_test_layout_ScaleFactors2D_instantiation_196949() {
assert_eq!(::std::mem::size_of::<[u32; 2usize]>() , 8usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32757,7 +32772,7 @@ pub mod root {
[u32; 2usize] ) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_228594() {
+ fn __bindgen_test_layout_nsTArray_instantiation_197579() {
assert_eq!(::std::mem::size_of::<root::nsTArray<root::mozilla::FramePropertyTable_PropertyValue>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32770,7 +32785,7 @@ pub mod root {
) ));
}
#[test]
- fn __bindgen_test_layout_nsPtrHashKey_instantiation_228610() {
+ fn __bindgen_test_layout_nsPtrHashKey_instantiation_197595() {
assert_eq!(::std::mem::size_of::<root::nsPtrHashKey<root::nsIFrame>>()
, 16usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32781,7 +32796,7 @@ pub mod root {
root::nsPtrHashKey<root::nsIFrame> ) ));
}
#[test]
- fn __bindgen_test_layout_nsPIDOMWindow_instantiation_231884() {
+ fn __bindgen_test_layout_nsPIDOMWindow_instantiation_200803() {
assert_eq!(::std::mem::size_of::<[u64; 29usize]>() , 232usize , concat
! (
"Size of template specialization: " , stringify ! (
@@ -32792,7 +32807,7 @@ pub mod root {
[u64; 29usize] ) ));
}
#[test]
- fn __bindgen_test_layout_already_AddRefed_instantiation_232520() {
+ fn __bindgen_test_layout_already_AddRefed_instantiation_201439() {
assert_eq!(::std::mem::size_of::<root::already_AddRefed<root::mozilla::dom::CSSValue>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32803,7 +32818,7 @@ pub mod root {
root::already_AddRefed<root::mozilla::dom::CSSValue> ) ));
}
#[test]
- fn __bindgen_test_layout_DefaultDelete_instantiation_232611() {
+ fn __bindgen_test_layout_DefaultDelete_instantiation_201530() {
assert_eq!(::std::mem::size_of::<root::mozilla::DefaultDelete>() ,
1usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32814,7 +32829,7 @@ pub mod root {
root::mozilla::DefaultDelete ) ));
}
#[test]
- fn __bindgen_test_layout_nsRefPtrHashtable_instantiation_232615() {
+ fn __bindgen_test_layout_nsRefPtrHashtable_instantiation_201534() {
assert_eq!(::std::mem::size_of::<[u64; 6usize]>() , 48usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32825,7 +32840,7 @@ pub mod root {
[u64; 6usize] ) ));
}
#[test]
- fn __bindgen_test_layout_already_AddRefed_instantiation_233804() {
+ fn __bindgen_test_layout_already_AddRefed_instantiation_202723() {
assert_eq!(::std::mem::size_of::<root::already_AddRefed<root::nsISupports>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32836,7 +32851,7 @@ pub mod root {
root::already_AddRefed<root::nsISupports> ) ));
}
#[test]
- fn __bindgen_test_layout_nsCOMPtr_instantiation_234090() {
+ fn __bindgen_test_layout_nsCOMPtr_instantiation_203310() {
assert_eq!(::std::mem::size_of::<root::nsCOMPtr<root::nsIRunnable>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32847,7 +32862,7 @@ pub mod root {
root::nsCOMPtr<root::nsIRunnable> ) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_235680() {
+ fn __bindgen_test_layout_nsTArray_instantiation_204853() {
assert_eq!(::std::mem::size_of::<root::nsTArray<f64>>() , 8usize ,
concat ! (
"Size of template specialization: " , stringify ! (
@@ -32858,7 +32873,7 @@ pub mod root {
root::nsTArray<f64> ) ));
}
#[test]
- fn __bindgen_test_layout_RefPtr_instantiation_235692() {
+ fn __bindgen_test_layout_RefPtr_instantiation_204865() {
assert_eq!(::std::mem::size_of::<root::RefPtr<root::mozilla::dom::DOMIntersectionObserverEntry>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32871,7 +32886,7 @@ pub mod root {
) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_235691() {
+ fn __bindgen_test_layout_nsTArray_instantiation_204864() {
assert_eq!(::std::mem::size_of::<root::nsTArray<root::RefPtr<root::mozilla::dom::DOMIntersectionObserverEntry>>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32884,7 +32899,7 @@ pub mod root {
) ));
}
#[test]
- fn __bindgen_test_layout_nsPtrHashKey_instantiation_235725() {
+ fn __bindgen_test_layout_nsPtrHashKey_instantiation_204898() {
assert_eq!(::std::mem::size_of::<root::nsPtrHashKey<root::mozilla::dom::Element>>()
, 16usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32895,7 +32910,7 @@ pub mod root {
root::nsPtrHashKey<root::mozilla::dom::Element> ) ));
}
#[test]
- fn __bindgen_test_layout_UniquePtr_instantiation_235822() {
+ fn __bindgen_test_layout_UniquePtr_instantiation_204995() {
assert_eq!(::std::mem::size_of::<root::mozilla::UniquePtr<root::ProfilerBacktrace>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32906,7 +32921,7 @@ pub mod root {
root::mozilla::UniquePtr<root::ProfilerBacktrace> ) ));
}
#[test]
- fn __bindgen_test_layout_nsDataHashtable_instantiation_237602() {
+ fn __bindgen_test_layout_nsDataHashtable_instantiation_206793() {
assert_eq!(::std::mem::size_of::<[u64; 6usize]>() , 48usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32917,7 +32932,7 @@ pub mod root {
[u64; 6usize] ) ));
}
#[test]
- fn __bindgen_test_layout_OwningNonNull_instantiation_237641() {
+ fn __bindgen_test_layout_OwningNonNull_instantiation_206832() {
assert_eq!(::std::mem::size_of::<root::mozilla::OwningNonNull<root::mozilla::EffectCompositor_AnimationStyleRuleProcessor>>()
, 16usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32930,7 +32945,7 @@ pub mod root {
) ));
}
#[test]
- fn __bindgen_test_layout_nsRefPtrHashKey_instantiation_237664() {
+ fn __bindgen_test_layout_nsRefPtrHashKey_instantiation_206855() {
assert_eq!(::std::mem::size_of::<root::nsRefPtrHashKey<root::nsIAtom>>()
, 16usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32941,7 +32956,7 @@ pub mod root {
root::nsRefPtrHashKey<root::nsIAtom> ) ));
}
#[test]
- fn __bindgen_test_layout_nsRefPtrHashKey_instantiation_237700() {
+ fn __bindgen_test_layout_nsRefPtrHashKey_instantiation_206891() {
assert_eq!(::std::mem::size_of::<root::nsRefPtrHashKey<root::nsIContent>>()
, 16usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32952,7 +32967,7 @@ pub mod root {
root::nsRefPtrHashKey<root::nsIContent> ) ));
}
#[test]
- fn __bindgen_test_layout_DefaultDelete_instantiation_238245() {
+ fn __bindgen_test_layout_DefaultDelete_instantiation_207436() {
assert_eq!(::std::mem::size_of::<root::mozilla::DefaultDelete>() ,
1usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32963,7 +32978,7 @@ pub mod root {
root::mozilla::DefaultDelete ) ));
}
#[test]
- fn __bindgen_test_layout_already_AddRefed_instantiation_238259() {
+ fn __bindgen_test_layout_already_AddRefed_instantiation_207450() {
assert_eq!(::std::mem::size_of::<root::already_AddRefed<root::mozilla::URLExtraData>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32974,7 +32989,7 @@ pub mod root {
root::already_AddRefed<root::mozilla::URLExtraData> ) ));
}
#[test]
- fn __bindgen_test_layout_nsMainThreadPtrHolder_instantiation_238263() {
+ fn __bindgen_test_layout_nsMainThreadPtrHolder_instantiation_207454() {
assert_eq!(::std::mem::size_of::<root::nsMainThreadPtrHolder<root::nsIURI>>()
, 24usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32985,7 +33000,7 @@ pub mod root {
root::nsMainThreadPtrHolder<root::nsIURI> ) ));
}
#[test]
- fn __bindgen_test_layout_nsPtrHashKey_instantiation_238337() {
+ fn __bindgen_test_layout_nsPtrHashKey_instantiation_207528() {
assert_eq!(::std::mem::size_of::<root::nsPtrHashKey<root::nsIDocument>>()
, 16usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32996,7 +33011,7 @@ pub mod root {
root::nsPtrHashKey<root::nsIDocument> ) ));
}
#[test]
- fn __bindgen_test_layout_DefaultDelete_instantiation_238624() {
+ fn __bindgen_test_layout_DefaultDelete_instantiation_207815() {
assert_eq!(::std::mem::size_of::<root::mozilla::DefaultDelete>() ,
1usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -33007,7 +33022,7 @@ pub mod root {
root::mozilla::DefaultDelete ) ));
}
#[test]
- fn __bindgen_test_layout_UniquePtr_instantiation_238622() {
+ fn __bindgen_test_layout_UniquePtr_instantiation_207813() {
assert_eq!(::std::mem::size_of::<root::mozilla::UniquePtr<root::nsCSSValueList>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -33018,7 +33033,7 @@ pub mod root {
root::mozilla::UniquePtr<root::nsCSSValueList> ) ));
}
#[test]
- fn __bindgen_test_layout_DefaultDelete_instantiation_238630() {
+ fn __bindgen_test_layout_DefaultDelete_instantiation_207821() {
assert_eq!(::std::mem::size_of::<root::mozilla::DefaultDelete>() ,
1usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -33029,7 +33044,7 @@ pub mod root {
root::mozilla::DefaultDelete ) ));
}
#[test]
- fn __bindgen_test_layout_UniquePtr_instantiation_238628() {
+ fn __bindgen_test_layout_UniquePtr_instantiation_207819() {
assert_eq!(::std::mem::size_of::<root::mozilla::UniquePtr<root::nsCSSValuePairList>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -33040,7 +33055,7 @@ pub mod root {
root::mozilla::UniquePtr<root::nsCSSValuePairList> ) ));
}
#[test]
- fn __bindgen_test_layout_Maybe_instantiation_238973() {
+ fn __bindgen_test_layout_Maybe_instantiation_208164() {
assert_eq!(::std::mem::size_of::<[u64; 2usize]>() , 16usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -33051,7 +33066,7 @@ pub mod root {
[u64; 2usize] ) ));
}
#[test]
- fn __bindgen_test_layout_SupportsWeakPtr_instantiation_239140() {
+ fn __bindgen_test_layout_SupportsWeakPtr_instantiation_208331() {
assert_eq!(::std::mem::size_of::<u64>() , 8usize , concat ! (
"Size of template specialization: " , stringify ! ( u64 )
));
@@ -33060,7 +33075,7 @@ pub mod root {
u64 ) ));
}
#[test]
- fn __bindgen_test_layout_Maybe_instantiation_239301() {
+ fn __bindgen_test_layout_Maybe_instantiation_208492() {
assert_eq!(::std::mem::size_of::<[u32; 3usize]>() , 12usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -33071,7 +33086,7 @@ pub mod root {
[u32; 3usize] ) ));
}
#[test]
- fn __bindgen_test_layout_already_AddRefed_instantiation_239316() {
+ fn __bindgen_test_layout_already_AddRefed_instantiation_208507() {
assert_eq!(::std::mem::size_of::<root::already_AddRefed<root::nsStyleImageRequest>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -33082,7 +33097,7 @@ pub mod root {
root::already_AddRefed<root::nsStyleImageRequest> ) ));
}
#[test]
- fn __bindgen_test_layout_DefaultDelete_instantiation_239324() {
+ fn __bindgen_test_layout_DefaultDelete_instantiation_208515() {
assert_eq!(::std::mem::size_of::<root::mozilla::DefaultDelete>() ,
1usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -33093,7 +33108,7 @@ pub mod root {
root::mozilla::DefaultDelete ) ));
}
#[test]
- fn __bindgen_test_layout_UniquePtr_instantiation_239322() {
+ fn __bindgen_test_layout_UniquePtr_instantiation_208513() {
assert_eq!(::std::mem::size_of::<root::mozilla::UniquePtr<root::nsStyleSides>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -33104,7 +33119,7 @@ pub mod root {
root::mozilla::UniquePtr<root::nsStyleSides> ) ));
}
#[test]
- fn __bindgen_test_layout_DefaultDelete_instantiation_239363() {
+ fn __bindgen_test_layout_DefaultDelete_instantiation_208554() {
assert_eq!(::std::mem::size_of::<root::mozilla::DefaultDelete>() ,
1usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -33115,7 +33130,7 @@ pub mod root {
root::mozilla::DefaultDelete ) ));
}
#[test]
- fn __bindgen_test_layout_pair_instantiation_239514() {
+ fn __bindgen_test_layout_pair_instantiation_208705() {
assert_eq!(::std::mem::size_of::<root::std::pair<::nsstring::nsStringRepr, ::nsstring::nsStringRepr>>()
, 32usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -33126,7 +33141,7 @@ pub mod root {
root::std::pair<::nsstring::nsStringRepr, ::nsstring::nsStringRepr> ) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_239513() {
+ fn __bindgen_test_layout_nsTArray_instantiation_208704() {
assert_eq!(::std::mem::size_of::<root::nsTArray<root::std::pair<::nsstring::nsStringRepr,
::nsstring::nsStringRepr>>>()
, 8usize , concat ! (
@@ -33141,7 +33156,7 @@ pub mod root {
) ));
}
#[test]
- fn __bindgen_test_layout_RefPtr_instantiation_240507() {
+ fn __bindgen_test_layout_RefPtr_instantiation_209698() {
assert_eq!(::std::mem::size_of::<root::RefPtr<root::RawServoAnimationValue>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -33152,7 +33167,7 @@ pub mod root {
root::RefPtr<root::RawServoAnimationValue> ) ));
}
#[test]
- fn __bindgen_test_layout_BaseTimeDuration_instantiation_244499() {
+ fn __bindgen_test_layout_BaseTimeDuration_instantiation_211420() {
assert_eq!(::std::mem::size_of::<root::mozilla::BaseTimeDuration>() ,
8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -33163,7 +33178,7 @@ pub mod root {
root::mozilla::BaseTimeDuration ) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_245091() {
+ fn __bindgen_test_layout_nsTArray_instantiation_212012() {
assert_eq!(::std::mem::size_of::<root::nsTArray<root::mozilla::DisplayItemClip_RoundedRect>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -33176,7 +33191,18 @@ pub mod root {
) ));
}
#[test]
- fn __bindgen_test_layout_Maybe_instantiation_245273() {
+ fn __bindgen_test_layout_Maybe_instantiation_212274() {
+ assert_eq!(::std::mem::size_of::<[u64; 2usize]>() , 16usize , concat !
+ (
+ "Size of template specialization: " , stringify ! (
+ [u64; 2usize] ) ));
+ assert_eq!(::std::mem::align_of::<[u64; 2usize]>() , 8usize , concat !
+ (
+ "Alignment of template specialization: " , stringify ! (
+ [u64; 2usize] ) ));
+ }
+ #[test]
+ fn __bindgen_test_layout_Maybe_instantiation_212281() {
assert_eq!(::std::mem::size_of::<[u64; 5usize]>() , 40usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -33187,7 +33213,7 @@ pub mod root {
[u64; 5usize] ) ));
}
#[test]
- fn __bindgen_test_layout_RefPtr_instantiation_245448() {
+ fn __bindgen_test_layout_RefPtr_instantiation_212456() {
assert_eq!(::std::mem::size_of::<root::RefPtr<root::mozilla::dom::DOMRect>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -33198,7 +33224,7 @@ pub mod root {
root::RefPtr<root::mozilla::dom::DOMRect> ) ));
}
#[test]
- fn __bindgen_test_layout_Sequence_instantiation_245692() {
+ fn __bindgen_test_layout_Sequence_instantiation_212700() {
assert_eq!(::std::mem::size_of::<u64>() , 8usize , concat ! (
"Size of template specialization: " , stringify ! ( u64 )
));
@@ -33207,7 +33233,7 @@ pub mod root {
u64 ) ));
}
#[test]
- fn __bindgen_test_layout_nsRefPtrHashKey_instantiation_245991() {
+ fn __bindgen_test_layout_nsRefPtrHashKey_instantiation_212999() {
assert_eq!(::std::mem::size_of::<root::nsRefPtrHashKey<root::mozilla::dom::Element>>()
, 16usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -33218,7 +33244,7 @@ pub mod root {
root::nsRefPtrHashKey<root::mozilla::dom::Element> ) ));
}
#[test]
- fn __bindgen_test_layout_nsClassHashtable_instantiation_245990() {
+ fn __bindgen_test_layout_nsClassHashtable_instantiation_212998() {
assert_eq!(::std::mem::size_of::<[u64; 6usize]>() , 48usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -33229,7 +33255,7 @@ pub mod root {
[u64; 6usize] ) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_247222() {
+ fn __bindgen_test_layout_nsTArray_instantiation_214230() {
assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::css::DocumentRule>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -33240,7 +33266,7 @@ pub mod root {
root::nsTArray<*mut root::mozilla::css::DocumentRule> ) ));
}
#[test]
- fn __bindgen_test_layout_nsAutoPtr_instantiation_247260() {
+ fn __bindgen_test_layout_nsAutoPtr_instantiation_214268() {
assert_eq!(::std::mem::size_of::<root::nsAutoPtr<root::nsMediaQuery>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
diff --git a/components/style/gecko/generated/structs_release.rs b/components/style/gecko/generated/structs_release.rs
index 07d34bef02a..78760c4956b 100644
--- a/components/style/gecko/generated/structs_release.rs
+++ b/components/style/gecko/generated/structs_release.rs
@@ -1196,58 +1196,98 @@ pub mod root {
fn clone(&self) -> Self { *self }
}
#[repr(C)]
+ #[derive(Debug, Copy)]
+ pub struct forward_iterator_tag {
+ pub _address: u8,
+ }
+ #[test]
+ fn bindgen_test_layout_forward_iterator_tag() {
+ assert_eq!(::std::mem::size_of::<forward_iterator_tag>() , 1usize
+ , concat ! (
+ "Size of: " , stringify ! ( forward_iterator_tag ) ));
+ assert_eq! (::std::mem::align_of::<forward_iterator_tag>() ,
+ 1usize , concat ! (
+ "Alignment of " , stringify ! ( forward_iterator_tag )
+ ));
+ }
+ impl Clone for forward_iterator_tag {
+ fn clone(&self) -> Self { *self }
+ }
+ #[repr(C)]
+ #[derive(Debug, Copy)]
+ pub struct bidirectional_iterator_tag {
+ pub _address: u8,
+ }
+ #[test]
+ fn bindgen_test_layout_bidirectional_iterator_tag() {
+ assert_eq!(::std::mem::size_of::<bidirectional_iterator_tag>() ,
+ 1usize , concat ! (
+ "Size of: " , stringify ! ( bidirectional_iterator_tag
+ ) ));
+ assert_eq! (::std::mem::align_of::<bidirectional_iterator_tag>() ,
+ 1usize , concat ! (
+ "Alignment of " , stringify ! (
+ bidirectional_iterator_tag ) ));
+ }
+ impl Clone for bidirectional_iterator_tag {
+ fn clone(&self) -> Self { *self }
+ }
+ #[repr(C)]
+ #[derive(Debug, Copy)]
+ pub struct random_access_iterator_tag {
+ pub _address: u8,
+ }
+ #[test]
+ fn bindgen_test_layout_random_access_iterator_tag() {
+ assert_eq!(::std::mem::size_of::<random_access_iterator_tag>() ,
+ 1usize , concat ! (
+ "Size of: " , stringify ! ( random_access_iterator_tag
+ ) ));
+ assert_eq! (::std::mem::align_of::<random_access_iterator_tag>() ,
+ 1usize , concat ! (
+ "Alignment of " , stringify ! (
+ random_access_iterator_tag ) ));
+ }
+ impl Clone for random_access_iterator_tag {
+ fn clone(&self) -> Self { *self }
+ }
+ #[repr(C)]
+ pub struct iterator_traits {
+ pub _address: u8,
+ }
+ #[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct iterator {
pub _address: u8,
}
- pub type iterator_iterator_category<_Category> = _Category;
pub type iterator_value_type<_Tp> = _Tp;
pub type iterator_difference_type<_Distance> = _Distance;
pub type iterator_pointer<_Pointer> = _Pointer;
pub type iterator_reference<_Reference> = _Reference;
+ pub type iterator_iterator_category<_Category> = _Category;
#[repr(C)]
- pub struct iterator_traits {
- pub _address: u8,
- }
- #[repr(C)]
- pub struct reverse_iterator<_Iterator> {
- pub current: _Iterator,
- pub _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell<_Iterator>>,
+ pub struct reverse_iterator<_Iter> {
+ pub __t: _Iter,
+ pub current: _Iter,
+ pub _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell<_Iter>>,
}
- pub type reverse_iterator___traits_type = root::std::iterator_traits;
- pub type reverse_iterator_iterator_type<_Iterator> = _Iterator;
+ pub type reverse_iterator_iterator_type<_Iter> = _Iter;
pub type reverse_iterator_difference_type =
- root::std::reverse_iterator___traits_type;
- pub type reverse_iterator_pointer =
- root::std::reverse_iterator___traits_type;
- pub type reverse_iterator_reference =
- root::std::reverse_iterator___traits_type;
+ root::std::iterator_traits;
+ pub type reverse_iterator_reference = root::std::iterator_traits;
+ pub type reverse_iterator_pointer = root::std::iterator_traits;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct atomic {
}
- #[test]
- fn __bindgen_test_layout_atomic_instantiation_88637() {
- assert_eq!(::std::mem::size_of::<u32>() , 4usize , concat ! (
- "Size of template specialization: " , stringify ! ( u32
- ) ));
- assert_eq!(::std::mem::align_of::<u32>() , 4usize , concat ! (
- "Alignment of template specialization: " , stringify !
- ( u32 ) ));
- }
- #[test]
- fn __bindgen_test_layout_atomic_instantiation_88645() {
- assert_eq!(::std::mem::size_of::<u64>() , 8usize , concat ! (
- "Size of template specialization: " , stringify ! ( u64
- ) ));
- assert_eq!(::std::mem::align_of::<u64>() , 8usize , concat ! (
- "Alignment of template specialization: " , stringify !
- ( u64 ) ));
+ pub type atomic___base = u8;
+ #[repr(C)]
+ pub struct __bit_const_reference {
+ pub __seg_: root::std::__bit_const_reference___storage_pointer,
+ pub __mask_: root::std::__bit_const_reference___storage_type,
}
- }
- pub mod __gnu_cxx {
- #[allow(unused_imports)]
- use self::super::super::root;
+ pub type __bit_const_reference___storage_type = [u8; 0usize];
+ pub type __bit_const_reference___storage_pointer = [u8; 0usize];
}
pub mod mozilla {
#[allow(unused_imports)]
@@ -1486,7 +1526,7 @@ pub mod root {
#[repr(C)]
#[derive(Debug)]
pub struct MutexImpl {
- pub platformData_: [*mut ::std::os::raw::c_void; 5usize],
+ pub platformData_: [*mut ::std::os::raw::c_void; 8usize],
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
@@ -1495,7 +1535,7 @@ pub mod root {
}
#[test]
fn bindgen_test_layout_MutexImpl() {
- assert_eq!(::std::mem::size_of::<MutexImpl>() , 40usize ,
+ assert_eq!(::std::mem::size_of::<MutexImpl>() , 64usize ,
concat ! ( "Size of: " , stringify ! ( MutexImpl )
));
assert_eq! (::std::mem::align_of::<MutexImpl>() , 8usize ,
@@ -2091,7 +2131,7 @@ pub mod root {
}
}
#[repr(C)]
- #[derive(Debug)]
+ #[derive(Debug, Copy)]
pub struct ThreadSafeAutoRefCnt {
pub mValue: u64,
}
@@ -2112,6 +2152,9 @@ pub mod root {
ThreadSafeAutoRefCnt ) , "::" , stringify ! ( mValue )
));
}
+ impl Clone for ThreadSafeAutoRefCnt {
+ fn clone(&self) -> Self { *self }
+ }
#[repr(C)]
#[derive(Debug)]
pub struct OwningNonNull<T> {
@@ -3657,20 +3700,9 @@ pub mod root {
_unused: [u8; 0],
}
#[repr(C)]
- #[derive(Debug)]
+ #[derive(Debug, Copy, Clone)]
pub struct EventHandlerNonNull {
- pub _base: root::mozilla::dom::CallbackFunction,
- }
- #[test]
- fn bindgen_test_layout_EventHandlerNonNull() {
- assert_eq!(::std::mem::size_of::<EventHandlerNonNull>() ,
- 48usize , concat ! (
- "Size of: " , stringify ! ( EventHandlerNonNull )
- ));
- assert_eq! (::std::mem::align_of::<EventHandlerNonNull>() ,
- 8usize , concat ! (
- "Alignment of " , stringify ! (
- EventHandlerNonNull ) ));
+ _unused: [u8; 0],
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
@@ -6771,7 +6803,7 @@ pub mod root {
_unused: [u8; 0],
}
#[test]
- fn __bindgen_test_layout_StaticRefPtr_instantiation_138533() {
+ fn __bindgen_test_layout_StaticRefPtr_instantiation_116395() {
assert_eq!(::std::mem::size_of::<root::mozilla::StaticRefPtr<root::mozilla::URLExtraData>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -7764,7 +7796,7 @@ pub mod root {
}
#[test]
fn bindgen_test_layout_OffTheBooksMutex() {
- assert_eq!(::std::mem::size_of::<OffTheBooksMutex>() , 40usize ,
+ assert_eq!(::std::mem::size_of::<OffTheBooksMutex>() , 64usize ,
concat ! (
"Size of: " , stringify ! ( OffTheBooksMutex ) ));
assert_eq! (::std::mem::align_of::<OffTheBooksMutex>() , 8usize ,
@@ -7783,7 +7815,7 @@ pub mod root {
}
#[test]
fn bindgen_test_layout_Mutex() {
- assert_eq!(::std::mem::size_of::<Mutex>() , 40usize , concat ! (
+ assert_eq!(::std::mem::size_of::<Mutex>() , 64usize , concat ! (
"Size of: " , stringify ! ( Mutex ) ));
assert_eq! (::std::mem::align_of::<Mutex>() , 8usize , concat ! (
"Alignment of " , stringify ! ( Mutex ) ));
@@ -8593,9 +8625,9 @@ pub mod root {
#[repr(C)]
#[derive(Debug)]
pub struct ServoElementSnapshot {
- pub mContains: root::mozilla::ServoElementSnapshot_Flags,
pub mAttrs: root::nsTArray<root::mozilla::ServoAttrSnapshot>,
pub mState: root::mozilla::ServoElementSnapshot_ServoStateType,
+ pub mContains: root::mozilla::ServoElementSnapshot_Flags,
pub mIsHTMLElementInHTMLDocument: bool,
pub mIsInChromeDocument: bool,
}
@@ -8608,7 +8640,7 @@ pub mod root {
as ServoElementSnapshot_Flags;
#[test]
fn bindgen_test_layout_ServoElementSnapshot() {
- assert_eq!(::std::mem::size_of::<ServoElementSnapshot>() , 32usize
+ assert_eq!(::std::mem::size_of::<ServoElementSnapshot>() , 24usize
, concat ! (
"Size of: " , stringify ! ( ServoElementSnapshot ) ));
assert_eq! (::std::mem::align_of::<ServoElementSnapshot>() ,
@@ -8616,34 +8648,34 @@ pub mod root {
"Alignment of " , stringify ! ( ServoElementSnapshot )
));
assert_eq! (unsafe {
- & ( * ( 0 as * const ServoElementSnapshot ) ) .
- mContains as * const _ as usize } , 0usize , concat !
- (
- "Alignment of field: " , stringify ! (
- ServoElementSnapshot ) , "::" , stringify ! (
- mContains ) ));
- assert_eq! (unsafe {
& ( * ( 0 as * const ServoElementSnapshot ) ) . mAttrs
- as * const _ as usize } , 8usize , concat ! (
+ as * const _ as usize } , 0usize , concat ! (
"Alignment of field: " , stringify ! (
ServoElementSnapshot ) , "::" , stringify ! ( mAttrs )
));
assert_eq! (unsafe {
& ( * ( 0 as * const ServoElementSnapshot ) ) . mState
- as * const _ as usize } , 16usize , concat ! (
+ as * const _ as usize } , 8usize , concat ! (
"Alignment of field: " , stringify ! (
ServoElementSnapshot ) , "::" , stringify ! ( mState )
));
assert_eq! (unsafe {
& ( * ( 0 as * const ServoElementSnapshot ) ) .
+ mContains as * const _ as usize } , 16usize , concat !
+ (
+ "Alignment of field: " , stringify ! (
+ ServoElementSnapshot ) , "::" , stringify ! (
+ mContains ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const ServoElementSnapshot ) ) .
mIsHTMLElementInHTMLDocument as * const _ as usize } ,
- 24usize , concat ! (
+ 17usize , concat ! (
"Alignment of field: " , stringify ! (
ServoElementSnapshot ) , "::" , stringify ! (
mIsHTMLElementInHTMLDocument ) ));
assert_eq! (unsafe {
& ( * ( 0 as * const ServoElementSnapshot ) ) .
- mIsInChromeDocument as * const _ as usize } , 25usize
+ mIsInChromeDocument as * const _ as usize } , 18usize
, concat ! (
"Alignment of field: " , stringify ! (
ServoElementSnapshot ) , "::" , stringify ! (
@@ -8902,7 +8934,7 @@ pub mod root {
( mValue ) ));
}
#[test]
- fn __bindgen_test_layout_DefaultDelete_instantiation_175461() {
+ fn __bindgen_test_layout_DefaultDelete_instantiation_153384() {
assert_eq!(::std::mem::size_of::<root::mozilla::DefaultDelete>() ,
1usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -9358,7 +9390,8 @@ pub mod root {
pub enum ServoElementSnapshotFlags {
State = 1,
Attributes = 2,
- All = 3,
+ Id = 4,
+ MaybeClass = 8,
}
#[repr(C)]
#[derive(Debug, Copy)]
@@ -11135,7 +11168,7 @@ pub mod root {
pub _address: u8,
}
#[test]
- fn __bindgen_test_layout_nsCharTraits_instantiation_53929() {
+ fn __bindgen_test_layout_nsCharTraits_instantiation_51822() {
assert_eq!(::std::mem::size_of::<root::nsCharTraits>() , 1usize ,
concat ! (
"Size of template specialization: " , stringify ! (
@@ -11146,7 +11179,7 @@ pub mod root {
root::nsCharTraits ) ));
}
#[test]
- fn __bindgen_test_layout_nsCharTraits_instantiation_53933() {
+ fn __bindgen_test_layout_nsCharTraits_instantiation_51826() {
assert_eq!(::std::mem::size_of::<root::nsCharTraits>() , 1usize ,
concat ! (
"Size of template specialization: " , stringify ! (
@@ -12783,7 +12816,7 @@ pub mod root {
}
pub type nsCOMPtr_element_type<T> = T;
#[test]
- fn __bindgen_test_layout_nsCOMPtr_instantiation_91725() {
+ fn __bindgen_test_layout_nsCOMPtr_instantiation_60935() {
assert_eq!(::std::mem::size_of::<root::nsCOMPtr>() , 8usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -14343,7 +14376,7 @@ pub mod root {
* count is 1.
*/
#[repr(C)]
- #[derive(Debug)]
+ #[derive(Debug, Copy)]
pub struct nsStringBuffer {
pub mRefCount: u32,
pub mStorageSize: u32,
@@ -14365,6 +14398,9 @@ pub mod root {
"Alignment of field: " , stringify ! ( nsStringBuffer ) ,
"::" , stringify ! ( mStorageSize ) ));
}
+ impl Clone for nsStringBuffer {
+ fn clone(&self) -> Self { *self }
+ }
#[repr(C)]
#[derive(Debug, Copy)]
pub struct nsIAtom {
@@ -20373,57 +20409,57 @@ pub mod root {
pub struct nsDOMMutationObserver {
_unused: [u8; 0],
}
- pub const NODE_HAS_LISTENERMANAGER: root::_bindgen_ty_82 =
- _bindgen_ty_82::NODE_HAS_LISTENERMANAGER;
- pub const NODE_HAS_PROPERTIES: root::_bindgen_ty_82 =
- _bindgen_ty_82::NODE_HAS_PROPERTIES;
- pub const NODE_IS_ANONYMOUS_ROOT: root::_bindgen_ty_82 =
- _bindgen_ty_82::NODE_IS_ANONYMOUS_ROOT;
- pub const NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE: root::_bindgen_ty_82 =
- _bindgen_ty_82::NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE;
- pub const NODE_IS_NATIVE_ANONYMOUS_ROOT: root::_bindgen_ty_82 =
- _bindgen_ty_82::NODE_IS_NATIVE_ANONYMOUS_ROOT;
- pub const NODE_FORCE_XBL_BINDINGS: root::_bindgen_ty_82 =
- _bindgen_ty_82::NODE_FORCE_XBL_BINDINGS;
- pub const NODE_MAY_BE_IN_BINDING_MNGR: root::_bindgen_ty_82 =
- _bindgen_ty_82::NODE_MAY_BE_IN_BINDING_MNGR;
- pub const NODE_IS_EDITABLE: root::_bindgen_ty_82 =
- _bindgen_ty_82::NODE_IS_EDITABLE;
- pub const NODE_IS_NATIVE_ANONYMOUS: root::_bindgen_ty_82 =
- _bindgen_ty_82::NODE_IS_NATIVE_ANONYMOUS;
- pub const NODE_IS_IN_SHADOW_TREE: root::_bindgen_ty_82 =
- _bindgen_ty_82::NODE_IS_IN_SHADOW_TREE;
- pub const NODE_HAS_EMPTY_SELECTOR: root::_bindgen_ty_82 =
- _bindgen_ty_82::NODE_HAS_EMPTY_SELECTOR;
- pub const NODE_HAS_SLOW_SELECTOR: root::_bindgen_ty_82 =
- _bindgen_ty_82::NODE_HAS_SLOW_SELECTOR;
- pub const NODE_HAS_EDGE_CHILD_SELECTOR: root::_bindgen_ty_82 =
- _bindgen_ty_82::NODE_HAS_EDGE_CHILD_SELECTOR;
- pub const NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS: root::_bindgen_ty_82 =
- _bindgen_ty_82::NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS;
- pub const NODE_ALL_SELECTOR_FLAGS: root::_bindgen_ty_82 =
- _bindgen_ty_82::NODE_ALL_SELECTOR_FLAGS;
- pub const NODE_NEEDS_FRAME: root::_bindgen_ty_82 =
- _bindgen_ty_82::NODE_NEEDS_FRAME;
- pub const NODE_DESCENDANTS_NEED_FRAMES: root::_bindgen_ty_82 =
- _bindgen_ty_82::NODE_DESCENDANTS_NEED_FRAMES;
- pub const NODE_HAS_ACCESSKEY: root::_bindgen_ty_82 =
- _bindgen_ty_82::NODE_HAS_ACCESSKEY;
- pub const NODE_HAS_DIRECTION_RTL: root::_bindgen_ty_82 =
- _bindgen_ty_82::NODE_HAS_DIRECTION_RTL;
- pub const NODE_HAS_DIRECTION_LTR: root::_bindgen_ty_82 =
- _bindgen_ty_82::NODE_HAS_DIRECTION_LTR;
- pub const NODE_ALL_DIRECTION_FLAGS: root::_bindgen_ty_82 =
- _bindgen_ty_82::NODE_ALL_DIRECTION_FLAGS;
- pub const NODE_CHROME_ONLY_ACCESS: root::_bindgen_ty_82 =
- _bindgen_ty_82::NODE_CHROME_ONLY_ACCESS;
- pub const NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS: root::_bindgen_ty_82 =
- _bindgen_ty_82::NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS;
- pub const NODE_TYPE_SPECIFIC_BITS_OFFSET: root::_bindgen_ty_82 =
- _bindgen_ty_82::NODE_TYPE_SPECIFIC_BITS_OFFSET;
+ pub const NODE_HAS_LISTENERMANAGER: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_HAS_LISTENERMANAGER;
+ pub const NODE_HAS_PROPERTIES: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_HAS_PROPERTIES;
+ pub const NODE_IS_ANONYMOUS_ROOT: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_IS_ANONYMOUS_ROOT;
+ pub const NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE;
+ pub const NODE_IS_NATIVE_ANONYMOUS_ROOT: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_IS_NATIVE_ANONYMOUS_ROOT;
+ pub const NODE_FORCE_XBL_BINDINGS: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_FORCE_XBL_BINDINGS;
+ pub const NODE_MAY_BE_IN_BINDING_MNGR: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_MAY_BE_IN_BINDING_MNGR;
+ pub const NODE_IS_EDITABLE: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_IS_EDITABLE;
+ pub const NODE_IS_NATIVE_ANONYMOUS: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_IS_NATIVE_ANONYMOUS;
+ pub const NODE_IS_IN_SHADOW_TREE: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_IS_IN_SHADOW_TREE;
+ pub const NODE_HAS_EMPTY_SELECTOR: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_HAS_EMPTY_SELECTOR;
+ pub const NODE_HAS_SLOW_SELECTOR: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_HAS_SLOW_SELECTOR;
+ pub const NODE_HAS_EDGE_CHILD_SELECTOR: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_HAS_EDGE_CHILD_SELECTOR;
+ pub const NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS;
+ pub const NODE_ALL_SELECTOR_FLAGS: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_ALL_SELECTOR_FLAGS;
+ pub const NODE_NEEDS_FRAME: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_NEEDS_FRAME;
+ pub const NODE_DESCENDANTS_NEED_FRAMES: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_DESCENDANTS_NEED_FRAMES;
+ pub const NODE_HAS_ACCESSKEY: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_HAS_ACCESSKEY;
+ pub const NODE_HAS_DIRECTION_RTL: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_HAS_DIRECTION_RTL;
+ pub const NODE_HAS_DIRECTION_LTR: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_HAS_DIRECTION_LTR;
+ pub const NODE_ALL_DIRECTION_FLAGS: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_ALL_DIRECTION_FLAGS;
+ pub const NODE_CHROME_ONLY_ACCESS: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_CHROME_ONLY_ACCESS;
+ pub const NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS;
+ pub const NODE_TYPE_SPECIFIC_BITS_OFFSET: root::_bindgen_ty_17 =
+ _bindgen_ty_17::NODE_TYPE_SPECIFIC_BITS_OFFSET;
#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
- pub enum _bindgen_ty_82 {
+ pub enum _bindgen_ty_17 {
NODE_HAS_LISTENERMANAGER = 4,
NODE_HAS_PROPERTIES = 8,
NODE_IS_ANONYMOUS_ROOT = 16,
@@ -26756,7 +26792,7 @@ pub mod root {
pub type imgRequest_HasThreadSafeRefCnt = root::mozilla::TrueType;
#[test]
fn bindgen_test_layout_imgRequest() {
- assert_eq!(::std::mem::size_of::<imgRequest>() , 376usize , concat ! (
+ assert_eq!(::std::mem::size_of::<imgRequest>() , 400usize , concat ! (
"Size of: " , stringify ! ( imgRequest ) ));
assert_eq! (::std::mem::align_of::<imgRequest>() , 8usize , concat ! (
"Alignment of " , stringify ! ( imgRequest ) ));
@@ -28172,7 +28208,7 @@ pub mod root {
) , "::" , stringify ! ( mQuotePairs ) ));
}
#[test]
- fn __bindgen_test_layout_StaticRefPtr_instantiation_171453() {
+ fn __bindgen_test_layout_StaticRefPtr_instantiation_149376() {
assert_eq!(::std::mem::size_of::<root::mozilla::StaticRefPtr<root::nsStyleQuoteValues>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -30640,48 +30676,48 @@ pub mod root {
pub struct nsAttrValueOrString {
_unused: [u8; 0],
}
- pub const ELEMENT_SHARED_RESTYLE_BIT_1: root::_bindgen_ty_84 =
- _bindgen_ty_84::ELEMENT_SHARED_RESTYLE_BIT_1;
- pub const ELEMENT_SHARED_RESTYLE_BIT_2: root::_bindgen_ty_84 =
- _bindgen_ty_84::ELEMENT_SHARED_RESTYLE_BIT_2;
- pub const ELEMENT_SHARED_RESTYLE_BIT_3: root::_bindgen_ty_84 =
- _bindgen_ty_84::ELEMENT_SHARED_RESTYLE_BIT_3;
- pub const ELEMENT_SHARED_RESTYLE_BIT_4: root::_bindgen_ty_84 =
- _bindgen_ty_84::ELEMENT_SHARED_RESTYLE_BIT_4;
- pub const ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO: root::_bindgen_ty_84 =
- _bindgen_ty_84::ELEMENT_SHARED_RESTYLE_BIT_1;
+ pub const ELEMENT_SHARED_RESTYLE_BIT_1: root::_bindgen_ty_19 =
+ _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_1;
+ pub const ELEMENT_SHARED_RESTYLE_BIT_2: root::_bindgen_ty_19 =
+ _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_2;
+ pub const ELEMENT_SHARED_RESTYLE_BIT_3: root::_bindgen_ty_19 =
+ _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_3;
+ pub const ELEMENT_SHARED_RESTYLE_BIT_4: root::_bindgen_ty_19 =
+ _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_4;
+ pub const ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO: root::_bindgen_ty_19 =
+ _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_1;
pub const ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO:
- root::_bindgen_ty_84 =
- _bindgen_ty_84::ELEMENT_SHARED_RESTYLE_BIT_2;
- pub const ELEMENT_HAS_SNAPSHOT: root::_bindgen_ty_84 =
- _bindgen_ty_84::ELEMENT_SHARED_RESTYLE_BIT_3;
- pub const ELEMENT_HANDLED_SNAPSHOT: root::_bindgen_ty_84 =
- _bindgen_ty_84::ELEMENT_SHARED_RESTYLE_BIT_4;
- pub const ELEMENT_HAS_PENDING_RESTYLE: root::_bindgen_ty_84 =
- _bindgen_ty_84::ELEMENT_SHARED_RESTYLE_BIT_1;
- pub const ELEMENT_IS_POTENTIAL_RESTYLE_ROOT: root::_bindgen_ty_84 =
- _bindgen_ty_84::ELEMENT_SHARED_RESTYLE_BIT_2;
- pub const ELEMENT_HAS_PENDING_ANIMATION_ONLY_RESTYLE: root::_bindgen_ty_84
+ root::_bindgen_ty_19 =
+ _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_2;
+ pub const ELEMENT_HAS_SNAPSHOT: root::_bindgen_ty_19 =
+ _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_3;
+ pub const ELEMENT_HANDLED_SNAPSHOT: root::_bindgen_ty_19 =
+ _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_4;
+ pub const ELEMENT_HAS_PENDING_RESTYLE: root::_bindgen_ty_19 =
+ _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_1;
+ pub const ELEMENT_IS_POTENTIAL_RESTYLE_ROOT: root::_bindgen_ty_19 =
+ _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_2;
+ pub const ELEMENT_HAS_PENDING_ANIMATION_ONLY_RESTYLE: root::_bindgen_ty_19
=
- _bindgen_ty_84::ELEMENT_SHARED_RESTYLE_BIT_3;
+ _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_3;
pub const ELEMENT_IS_POTENTIAL_ANIMATION_ONLY_RESTYLE_ROOT:
- root::_bindgen_ty_84 =
- _bindgen_ty_84::ELEMENT_SHARED_RESTYLE_BIT_4;
- pub const ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR: root::_bindgen_ty_84 =
- _bindgen_ty_84::ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR;
- pub const ELEMENT_PENDING_RESTYLE_FLAGS: root::_bindgen_ty_84 =
- _bindgen_ty_84::ELEMENT_PENDING_RESTYLE_FLAGS;
- pub const ELEMENT_POTENTIAL_RESTYLE_ROOT_FLAGS: root::_bindgen_ty_84 =
- _bindgen_ty_84::ELEMENT_POTENTIAL_RESTYLE_ROOT_FLAGS;
- pub const ELEMENT_ALL_RESTYLE_FLAGS: root::_bindgen_ty_84 =
- _bindgen_ty_84::ELEMENT_ALL_RESTYLE_FLAGS;
- pub const ELEMENT_HAS_SCROLLGRAB: root::_bindgen_ty_84 =
- _bindgen_ty_84::ELEMENT_HAS_SCROLLGRAB;
- pub const ELEMENT_TYPE_SPECIFIC_BITS_OFFSET: root::_bindgen_ty_84 =
- _bindgen_ty_84::ELEMENT_TYPE_SPECIFIC_BITS_OFFSET;
+ root::_bindgen_ty_19 =
+ _bindgen_ty_19::ELEMENT_SHARED_RESTYLE_BIT_4;
+ pub const ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR: root::_bindgen_ty_19 =
+ _bindgen_ty_19::ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR;
+ pub const ELEMENT_PENDING_RESTYLE_FLAGS: root::_bindgen_ty_19 =
+ _bindgen_ty_19::ELEMENT_PENDING_RESTYLE_FLAGS;
+ pub const ELEMENT_POTENTIAL_RESTYLE_ROOT_FLAGS: root::_bindgen_ty_19 =
+ _bindgen_ty_19::ELEMENT_POTENTIAL_RESTYLE_ROOT_FLAGS;
+ pub const ELEMENT_ALL_RESTYLE_FLAGS: root::_bindgen_ty_19 =
+ _bindgen_ty_19::ELEMENT_ALL_RESTYLE_FLAGS;
+ pub const ELEMENT_HAS_SCROLLGRAB: root::_bindgen_ty_19 =
+ _bindgen_ty_19::ELEMENT_HAS_SCROLLGRAB;
+ pub const ELEMENT_TYPE_SPECIFIC_BITS_OFFSET: root::_bindgen_ty_19 =
+ _bindgen_ty_19::ELEMENT_TYPE_SPECIFIC_BITS_OFFSET;
#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
- pub enum _bindgen_ty_84 {
+ pub enum _bindgen_ty_19 {
ELEMENT_SHARED_RESTYLE_BIT_1 = 8388608,
ELEMENT_SHARED_RESTYLE_BIT_2 = 16777216,
ELEMENT_SHARED_RESTYLE_BIT_3 = 33554432,
@@ -31450,7 +31486,7 @@ pub mod root {
}
pub type __builtin_va_list = [root::__va_list_tag; 1usize];
#[test]
- fn __bindgen_test_layout_IntegralConstant_instantiation_199188() {
+ fn __bindgen_test_layout_IntegralConstant_instantiation_170931() {
assert_eq!(::std::mem::size_of::<u8>() , 1usize , concat ! (
"Size of template specialization: " , stringify ! ( u8 )
));
@@ -31459,7 +31495,7 @@ pub mod root {
) ));
}
#[test]
- fn __bindgen_test_layout_IntegralConstant_instantiation_199192() {
+ fn __bindgen_test_layout_IntegralConstant_instantiation_170935() {
assert_eq!(::std::mem::size_of::<u8>() , 1usize , concat ! (
"Size of template specialization: " , stringify ! ( u8 )
));
@@ -31468,7 +31504,7 @@ pub mod root {
) ));
}
#[test]
- fn __bindgen_test_layout_nsReadingIterator_instantiation_200016() {
+ fn __bindgen_test_layout_nsReadingIterator_instantiation_171149() {
assert_eq!(::std::mem::size_of::<root::nsReadingIterator<u16>>() ,
24usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31479,7 +31515,7 @@ pub mod root {
root::nsReadingIterator<u16> ) ));
}
#[test]
- fn __bindgen_test_layout_nsWritingIterator_instantiation_200020() {
+ fn __bindgen_test_layout_nsWritingIterator_instantiation_171153() {
assert_eq!(::std::mem::size_of::<root::nsWritingIterator<u16>>() ,
24usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31490,7 +31526,7 @@ pub mod root {
root::nsWritingIterator<u16> ) ));
}
#[test]
- fn __bindgen_test_layout_nsReadingIterator_instantiation_200093() {
+ fn __bindgen_test_layout_nsReadingIterator_instantiation_171226() {
assert_eq!(::std::mem::size_of::<root::nsReadingIterator<::std::os::raw::c_char>>()
, 24usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31501,7 +31537,7 @@ pub mod root {
root::nsReadingIterator<::std::os::raw::c_char> ) ));
}
#[test]
- fn __bindgen_test_layout_nsWritingIterator_instantiation_200097() {
+ fn __bindgen_test_layout_nsWritingIterator_instantiation_171230() {
assert_eq!(::std::mem::size_of::<root::nsWritingIterator<::std::os::raw::c_char>>()
, 24usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31512,7 +31548,25 @@ pub mod root {
root::nsWritingIterator<::std::os::raw::c_char> ) ));
}
#[test]
- fn __bindgen_test_layout__bindgen_ty_id_205866_instantiation_205863() {
+ fn __bindgen_test_layout_atomic_instantiation_173213() {
+ assert_eq!(::std::mem::size_of::<u32>() , 4usize , concat ! (
+ "Size of template specialization: " , stringify ! ( u32 )
+ ));
+ assert_eq!(::std::mem::align_of::<u32>() , 4usize , concat ! (
+ "Alignment of template specialization: " , stringify ! (
+ u32 ) ));
+ }
+ #[test]
+ fn __bindgen_test_layout_atomic_instantiation_173221() {
+ assert_eq!(::std::mem::size_of::<u64>() , 8usize , concat ! (
+ "Size of template specialization: " , stringify ! ( u64 )
+ ));
+ assert_eq!(::std::mem::align_of::<u64>() , 8usize , concat ! (
+ "Alignment of template specialization: " , stringify ! (
+ u64 ) ));
+ }
+ #[test]
+ fn __bindgen_test_layout__bindgen_ty_id_173478_instantiation_173475() {
assert_eq!(::std::mem::size_of::<u8>() , 1usize , concat ! (
"Size of template specialization: " , stringify ! ( u8 )
));
@@ -31521,7 +31575,7 @@ pub mod root {
) ));
}
#[test]
- fn __bindgen_test_layout__bindgen_ty_id_205899_instantiation_205896() {
+ fn __bindgen_test_layout__bindgen_ty_id_173511_instantiation_173508() {
assert_eq!(::std::mem::size_of::<u8>() , 1usize , concat ! (
"Size of template specialization: " , stringify ! ( u8 )
));
@@ -31530,7 +31584,7 @@ pub mod root {
) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_206167() {
+ fn __bindgen_test_layout_nsTArray_instantiation_173779() {
assert_eq!(::std::mem::size_of::<root::nsTArray<root::nsCString>>() ,
8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31541,7 +31595,7 @@ pub mod root {
root::nsTArray<root::nsCString> ) ));
}
#[test]
- fn __bindgen_test_layout_Handle_instantiation_207119() {
+ fn __bindgen_test_layout_Handle_instantiation_174604() {
assert_eq!(::std::mem::size_of::<root::JS::Handle<*mut root::JSObject>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31552,7 +31606,7 @@ pub mod root {
root::JS::Handle<*mut root::JSObject> ) ));
}
#[test]
- fn __bindgen_test_layout_Handle_instantiation_207135() {
+ fn __bindgen_test_layout_Handle_instantiation_174620() {
assert_eq!(::std::mem::size_of::<root::JS::Handle<root::JS::Value>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31563,7 +31617,7 @@ pub mod root {
root::JS::Handle<root::JS::Value> ) ));
}
#[test]
- fn __bindgen_test_layout_MutableHandle_instantiation_207145() {
+ fn __bindgen_test_layout_MutableHandle_instantiation_174630() {
assert_eq!(::std::mem::size_of::<root::JS::MutableHandle<*mut root::JSObject>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31574,7 +31628,7 @@ pub mod root {
root::JS::MutableHandle<*mut root::JSObject> ) ));
}
#[test]
- fn __bindgen_test_layout_MutableHandle_instantiation_207161() {
+ fn __bindgen_test_layout_MutableHandle_instantiation_174646() {
assert_eq!(::std::mem::size_of::<root::JS::MutableHandle<root::JS::Value>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31585,7 +31639,7 @@ pub mod root {
root::JS::MutableHandle<root::JS::Value> ) ));
}
#[test]
- fn __bindgen_test_layout_Rooted_instantiation_207164() {
+ fn __bindgen_test_layout_Rooted_instantiation_174649() {
assert_eq!(::std::mem::size_of::<[u64; 3usize]>() , 24usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -31596,7 +31650,7 @@ pub mod root {
[u64; 3usize] ) ));
}
#[test]
- fn __bindgen_test_layout_DeletePolicy_instantiation_207501() {
+ fn __bindgen_test_layout_DeletePolicy_instantiation_174986() {
assert_eq!(::std::mem::size_of::<root::JS::DeletePolicy>() , 1usize ,
concat ! (
"Size of template specialization: " , stringify ! (
@@ -31607,7 +31661,7 @@ pub mod root {
root::JS::DeletePolicy ) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_209504() {
+ fn __bindgen_test_layout_nsTArray_instantiation_179915() {
assert_eq!(::std::mem::size_of::<root::nsTArray<::nsstring::nsStringRepr>>() ,
8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31618,7 +31672,7 @@ pub mod root {
root::nsTArray<::nsstring::nsStringRepr> ) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_209508() {
+ fn __bindgen_test_layout_nsTArray_instantiation_179919() {
assert_eq!(::std::mem::size_of::<root::nsTArray<root::mozilla::FontFamilyName>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31629,7 +31683,7 @@ pub mod root {
root::nsTArray<root::mozilla::FontFamilyName> ) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_209521() {
+ fn __bindgen_test_layout_nsTArray_instantiation_179932() {
assert_eq!(::std::mem::size_of::<root::nsTArray<::std::os::raw::c_uint>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31640,7 +31694,7 @@ pub mod root {
root::nsTArray<::std::os::raw::c_uint> ) ));
}
#[test]
- fn __bindgen_test_layout_TenuredHeap_instantiation_210388() {
+ fn __bindgen_test_layout_TenuredHeap_instantiation_180792() {
assert_eq!(::std::mem::size_of::<root::JS::TenuredHeap>() , 8usize ,
concat ! (
"Size of template specialization: " , stringify ! (
@@ -31651,7 +31705,7 @@ pub mod root {
root::JS::TenuredHeap ) ));
}
#[test]
- fn __bindgen_test_layout_Heap_instantiation_210478() {
+ fn __bindgen_test_layout_Heap_instantiation_180882() {
assert_eq!(::std::mem::size_of::<root::JS::Heap<*mut root::JSObject>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31662,7 +31716,7 @@ pub mod root {
root::JS::Heap<*mut root::JSObject> ) ));
}
#[test]
- fn __bindgen_test_layout_TErrorResult_instantiation_210588() {
+ fn __bindgen_test_layout_TErrorResult_instantiation_180992() {
assert_eq!(::std::mem::size_of::<root::mozilla::binding_danger::TErrorResult>()
, 16usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31673,7 +31727,7 @@ pub mod root {
root::mozilla::binding_danger::TErrorResult ) ));
}
#[test]
- fn __bindgen_test_layout_TErrorResult_instantiation_210604() {
+ fn __bindgen_test_layout_TErrorResult_instantiation_181008() {
assert_eq!(::std::mem::size_of::<root::mozilla::binding_danger::TErrorResult>()
, 16usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31684,7 +31738,7 @@ pub mod root {
root::mozilla::binding_danger::TErrorResult ) ));
}
#[test]
- fn __bindgen_test_layout_already_AddRefed_instantiation_210609() {
+ fn __bindgen_test_layout_already_AddRefed_instantiation_181014() {
assert_eq!(::std::mem::size_of::<root::already_AddRefed<root::nsStringBuffer>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31695,7 +31749,7 @@ pub mod root {
root::already_AddRefed<root::nsStringBuffer> ) ));
}
#[test]
- fn __bindgen_test_layout_already_AddRefed_instantiation_210661() {
+ fn __bindgen_test_layout_already_AddRefed_instantiation_181066() {
assert_eq!(::std::mem::size_of::<root::already_AddRefed<root::nsIAtom>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31706,7 +31760,7 @@ pub mod root {
root::already_AddRefed<root::nsIAtom> ) ));
}
#[test]
- fn __bindgen_test_layout_RefPtr_instantiation_211135() {
+ fn __bindgen_test_layout_RefPtr_instantiation_181540() {
assert_eq!(::std::mem::size_of::<root::RefPtr<root::mozilla::StyleSheet>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31717,7 +31771,7 @@ pub mod root {
root::RefPtr<root::mozilla::StyleSheet> ) ));
}
#[test]
- fn __bindgen_test_layout_already_AddRefed_instantiation_211481() {
+ fn __bindgen_test_layout_already_AddRefed_instantiation_181886() {
assert_eq!(::std::mem::size_of::<root::already_AddRefed<root::mozilla::dom::NodeInfo>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31728,7 +31782,7 @@ pub mod root {
root::already_AddRefed<root::mozilla::dom::NodeInfo> ) ));
}
#[test]
- fn __bindgen_test_layout_already_AddRefed_instantiation_211724() {
+ fn __bindgen_test_layout_already_AddRefed_instantiation_182129() {
assert_eq!(::std::mem::size_of::<root::already_AddRefed<root::nsIURI>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31739,7 +31793,7 @@ pub mod root {
root::already_AddRefed<root::nsIURI> ) ));
}
#[test]
- fn __bindgen_test_layout_already_AddRefed_instantiation_211871() {
+ fn __bindgen_test_layout_already_AddRefed_instantiation_182276() {
assert_eq!(::std::mem::size_of::<root::already_AddRefed<root::nsINode>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31750,7 +31804,7 @@ pub mod root {
root::already_AddRefed<root::nsINode> ) ));
}
#[test]
- fn __bindgen_test_layout_DeletePolicy_instantiation_215966() {
+ fn __bindgen_test_layout_DeletePolicy_instantiation_186364() {
assert_eq!(::std::mem::size_of::<root::JS::DeletePolicy>() , 1usize ,
concat ! (
"Size of template specialization: " , stringify ! (
@@ -31761,7 +31815,7 @@ pub mod root {
root::JS::DeletePolicy ) ));
}
#[test]
- fn __bindgen_test_layout_UniquePtr_instantiation_215964() {
+ fn __bindgen_test_layout_UniquePtr_instantiation_186362() {
assert_eq!(::std::mem::size_of::<root::mozilla::UniquePtr<root::JSErrorNotes_Note>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31772,7 +31826,7 @@ pub mod root {
root::mozilla::UniquePtr<root::JSErrorNotes_Note> ) ));
}
#[test]
- fn __bindgen_test_layout_iterator_instantiation_215999() {
+ fn __bindgen_test_layout_iterator_instantiation_186397() {
assert_eq!(::std::mem::size_of::<root::std::iterator>() , 1usize ,
concat ! (
"Size of template specialization: " , stringify ! (
@@ -31783,7 +31837,7 @@ pub mod root {
root::std::iterator ) ));
}
#[test]
- fn __bindgen_test_layout_nsCOMPtr_instantiation_216565() {
+ fn __bindgen_test_layout_nsCOMPtr_instantiation_186951() {
assert_eq!(::std::mem::size_of::<root::nsCOMPtr>() , 8usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -31794,7 +31848,7 @@ pub mod root {
root::nsCOMPtr ) ));
}
#[test]
- fn __bindgen_test_layout_Heap_instantiation_217818() {
+ fn __bindgen_test_layout_Heap_instantiation_188204() {
assert_eq!(::std::mem::size_of::<root::JS::Heap<root::JS::Value>>() ,
8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31805,7 +31859,7 @@ pub mod root {
root::JS::Heap<root::JS::Value> ) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_218160() {
+ fn __bindgen_test_layout_nsTArray_instantiation_188546() {
assert_eq!(::std::mem::size_of::<root::nsTArray<root::RefPtr<root::mozilla::dom::AnonymousContent>>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31818,7 +31872,7 @@ pub mod root {
) ));
}
#[test]
- fn __bindgen_test_layout_LinkedList_instantiation_218436() {
+ fn __bindgen_test_layout_LinkedList_instantiation_188822() {
assert_eq!(::std::mem::size_of::<root::mozilla::LinkedList>() ,
24usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31829,7 +31883,7 @@ pub mod root {
root::mozilla::LinkedList ) ));
}
#[test]
- fn __bindgen_test_layout_RefPtr_instantiation_218452() {
+ fn __bindgen_test_layout_RefPtr_instantiation_188838() {
assert_eq!(::std::mem::size_of::<root::RefPtr<root::mozilla::dom::Element>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31840,7 +31894,7 @@ pub mod root {
root::RefPtr<root::mozilla::dom::Element> ) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_218451() {
+ fn __bindgen_test_layout_nsTArray_instantiation_188837() {
assert_eq!(::std::mem::size_of::<root::nsTArray<root::RefPtr<root::mozilla::dom::Element>>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31853,7 +31907,7 @@ pub mod root {
));
}
#[test]
- fn __bindgen_test_layout_nsCOMPtr_instantiation_218481() {
+ fn __bindgen_test_layout_nsCOMPtr_instantiation_188867() {
assert_eq!(::std::mem::size_of::<root::nsCOMPtr>() , 8usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -31864,7 +31918,7 @@ pub mod root {
root::nsCOMPtr ) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_218480() {
+ fn __bindgen_test_layout_nsTArray_instantiation_188866() {
assert_eq!(::std::mem::size_of::<root::nsTArray<root::nsCOMPtr>>() ,
8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31875,7 +31929,7 @@ pub mod root {
root::nsTArray<root::nsCOMPtr> ) ));
}
#[test]
- fn __bindgen_test_layout_already_AddRefed_instantiation_218526() {
+ fn __bindgen_test_layout_already_AddRefed_instantiation_188912() {
assert_eq!(::std::mem::size_of::<root::already_AddRefed<root::nsIDocument>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31886,7 +31940,7 @@ pub mod root {
root::already_AddRefed<root::nsIDocument> ) ));
}
#[test]
- fn __bindgen_test_layout_already_AddRefed_instantiation_218691() {
+ fn __bindgen_test_layout_already_AddRefed_instantiation_189077() {
assert_eq!(::std::mem::size_of::<root::already_AddRefed<root::nsContentList>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31897,7 +31951,7 @@ pub mod root {
root::already_AddRefed<root::nsContentList> ) ));
}
#[test]
- fn __bindgen_test_layout_already_AddRefed_instantiation_219018() {
+ fn __bindgen_test_layout_already_AddRefed_instantiation_189404() {
assert_eq!(::std::mem::size_of::<root::already_AddRefed<root::nsIRunnable>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31908,7 +31962,7 @@ pub mod root {
root::already_AddRefed<root::nsIRunnable> ) ));
}
#[test]
- fn __bindgen_test_layout_nsCOMPtr_instantiation_219111() {
+ fn __bindgen_test_layout_nsCOMPtr_instantiation_189497() {
assert_eq!(::std::mem::size_of::<root::nsCOMPtr>() , 8usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -31919,7 +31973,7 @@ pub mod root {
root::nsCOMPtr ) ));
}
#[test]
- fn __bindgen_test_layout_nsCOMPtr_instantiation_219148() {
+ fn __bindgen_test_layout_nsCOMPtr_instantiation_189534() {
assert_eq!(::std::mem::size_of::<root::nsCOMPtr>() , 8usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -31930,7 +31984,7 @@ pub mod root {
root::nsCOMPtr ) ));
}
#[test]
- fn __bindgen_test_layout_DefaultDelete_instantiation_219404() {
+ fn __bindgen_test_layout_DefaultDelete_instantiation_189790() {
assert_eq!(::std::mem::size_of::<root::mozilla::DefaultDelete>() ,
1usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31941,7 +31995,7 @@ pub mod root {
root::mozilla::DefaultDelete ) ));
}
#[test]
- fn __bindgen_test_layout_UniquePtr_instantiation_219402() {
+ fn __bindgen_test_layout_UniquePtr_instantiation_189788() {
assert_eq!(::std::mem::size_of::<root::mozilla::UniquePtr<root::nsISMILAttr>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31952,7 +32006,7 @@ pub mod root {
root::mozilla::UniquePtr<root::nsISMILAttr> ) ));
}
#[test]
- fn __bindgen_test_layout_nsRefPtrHashKey_instantiation_219942() {
+ fn __bindgen_test_layout_nsRefPtrHashKey_instantiation_190328() {
assert_eq!(::std::mem::size_of::<root::nsRefPtrHashKey<root::mozilla::dom::DOMIntersectionObserver>>()
, 16usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31965,7 +32019,7 @@ pub mod root {
) ));
}
#[test]
- fn __bindgen_test_layout_nsDataHashtable_instantiation_219941() {
+ fn __bindgen_test_layout_nsDataHashtable_instantiation_190327() {
assert_eq!(::std::mem::size_of::<[u64; 5usize]>() , 40usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -31976,7 +32030,7 @@ pub mod root {
[u64; 5usize] ) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_220146() {
+ fn __bindgen_test_layout_nsTArray_instantiation_190532() {
assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsIContent>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -31987,7 +32041,7 @@ pub mod root {
root::nsTArray<*mut root::nsIContent> ) ));
}
#[test]
- fn __bindgen_test_layout_SupportsWeakPtr_instantiation_220193() {
+ fn __bindgen_test_layout_SupportsWeakPtr_instantiation_190579() {
assert_eq!(::std::mem::size_of::<u64>() , 8usize , concat ! (
"Size of template specialization: " , stringify ! ( u64 )
));
@@ -31996,7 +32050,7 @@ pub mod root {
u64 ) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_220370() {
+ fn __bindgen_test_layout_nsTArray_instantiation_190751() {
assert_eq!(::std::mem::size_of::<root::nsTArray<root::nsRect>>() ,
8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32007,7 +32061,7 @@ pub mod root {
root::nsTArray<root::nsRect> ) ));
}
#[test]
- fn __bindgen_test_layout_DefaultDelete_instantiation_220486() {
+ fn __bindgen_test_layout_DefaultDelete_instantiation_190867() {
assert_eq!(::std::mem::size_of::<root::mozilla::DefaultDelete>() ,
1usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32018,7 +32072,7 @@ pub mod root {
root::mozilla::DefaultDelete ) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_220652() {
+ fn __bindgen_test_layout_nsTArray_instantiation_191033() {
assert_eq!(::std::mem::size_of::<root::nsTArray<root::nsCOMPtr>>() ,
8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32029,7 +32083,7 @@ pub mod root {
root::nsTArray<root::nsCOMPtr> ) ));
}
#[test]
- fn __bindgen_test_layout_nsPIDOMWindow_instantiation_221439() {
+ fn __bindgen_test_layout_nsPIDOMWindow_instantiation_191820() {
assert_eq!(::std::mem::size_of::<[u64; 28usize]>() , 224usize , concat
! (
"Size of template specialization: " , stringify ! (
@@ -32040,7 +32094,7 @@ pub mod root {
[u64; 28usize] ) ));
}
#[test]
- fn __bindgen_test_layout_already_AddRefed_instantiation_221531() {
+ fn __bindgen_test_layout_already_AddRefed_instantiation_191872() {
assert_eq!(::std::mem::size_of::<root::already_AddRefed<root::nsIContent>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32051,7 +32105,7 @@ pub mod root {
root::already_AddRefed<root::nsIContent> ) ));
}
#[test]
- fn __bindgen_test_layout_nsRefPtrHashtable_instantiation_221712() {
+ fn __bindgen_test_layout_nsRefPtrHashtable_instantiation_192053() {
assert_eq!(::std::mem::size_of::<[u64; 5usize]>() , 40usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32062,7 +32116,7 @@ pub mod root {
[u64; 5usize] ) ));
}
#[test]
- fn __bindgen_test_layout_nsPtrHashKey_instantiation_222229() {
+ fn __bindgen_test_layout_nsPtrHashKey_instantiation_192554() {
assert_eq!(::std::mem::size_of::<root::nsPtrHashKey<root::WeakFrame>>()
, 16usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32073,7 +32127,7 @@ pub mod root {
root::nsPtrHashKey<root::WeakFrame> ) ));
}
#[test]
- fn __bindgen_test_layout_OwningNonNull_instantiation_222344() {
+ fn __bindgen_test_layout_OwningNonNull_instantiation_192669() {
assert_eq!(::std::mem::size_of::<root::mozilla::OwningNonNull<root::nsINode>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32084,7 +32138,7 @@ pub mod root {
root::mozilla::OwningNonNull<root::nsINode> ) ));
}
#[test]
- fn __bindgen_test_layout_nsPtrHashKey_instantiation_222629() {
+ fn __bindgen_test_layout_nsPtrHashKey_instantiation_192954() {
assert_eq!(::std::mem::size_of::<root::nsPtrHashKey<::std::os::raw::c_void>>()
, 16usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32095,7 +32149,7 @@ pub mod root {
root::nsPtrHashKey<::std::os::raw::c_void> ) ));
}
#[test]
- fn __bindgen_test_layout_PointTyped_instantiation_223420() {
+ fn __bindgen_test_layout_PointTyped_instantiation_193745() {
assert_eq!(::std::mem::size_of::<[u32; 2usize]>() , 8usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32106,7 +32160,7 @@ pub mod root {
[u32; 2usize] ) ));
}
#[test]
- fn __bindgen_test_layout_IntPointTyped_instantiation_223425() {
+ fn __bindgen_test_layout_IntPointTyped_instantiation_193750() {
assert_eq!(::std::mem::size_of::<[u32; 2usize]>() , 8usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32117,7 +32171,7 @@ pub mod root {
[u32; 2usize] ) ));
}
#[test]
- fn __bindgen_test_layout_SizeTyped_instantiation_223428() {
+ fn __bindgen_test_layout_SizeTyped_instantiation_193753() {
assert_eq!(::std::mem::size_of::<[u32; 2usize]>() , 8usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32128,7 +32182,7 @@ pub mod root {
[u32; 2usize] ) ));
}
#[test]
- fn __bindgen_test_layout_RectTyped_instantiation_223436() {
+ fn __bindgen_test_layout_RectTyped_instantiation_193761() {
assert_eq!(::std::mem::size_of::<[u32; 4usize]>() , 16usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32139,7 +32193,7 @@ pub mod root {
[u32; 4usize] ) ));
}
#[test]
- fn __bindgen_test_layout_IntPointTyped_instantiation_223468() {
+ fn __bindgen_test_layout_IntPointTyped_instantiation_193793() {
assert_eq!(::std::mem::size_of::<[u32; 2usize]>() , 8usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32150,7 +32204,7 @@ pub mod root {
[u32; 2usize] ) ));
}
#[test]
- fn __bindgen_test_layout_IntSizeTyped_instantiation_223476() {
+ fn __bindgen_test_layout_IntSizeTyped_instantiation_193801() {
assert_eq!(::std::mem::size_of::<[u32; 2usize]>() , 8usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32161,7 +32215,7 @@ pub mod root {
[u32; 2usize] ) ));
}
#[test]
- fn __bindgen_test_layout_IntRectTyped_instantiation_223484() {
+ fn __bindgen_test_layout_IntRectTyped_instantiation_193809() {
assert_eq!(::std::mem::size_of::<[u32; 4usize]>() , 16usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32172,7 +32226,7 @@ pub mod root {
[u32; 4usize] ) ));
}
#[test]
- fn __bindgen_test_layout_MarginTyped_instantiation_223651() {
+ fn __bindgen_test_layout_MarginTyped_instantiation_193976() {
assert_eq!(::std::mem::size_of::<[u32; 4usize]>() , 16usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32183,7 +32237,7 @@ pub mod root {
[u32; 4usize] ) ));
}
#[test]
- fn __bindgen_test_layout_RectTyped_instantiation_223686() {
+ fn __bindgen_test_layout_RectTyped_instantiation_194011() {
assert_eq!(::std::mem::size_of::<[u32; 4usize]>() , 16usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32194,7 +32248,7 @@ pub mod root {
[u32; 4usize] ) ));
}
#[test]
- fn __bindgen_test_layout_IntRectTyped_instantiation_223691() {
+ fn __bindgen_test_layout_IntRectTyped_instantiation_194016() {
assert_eq!(::std::mem::size_of::<[u32; 4usize]>() , 16usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32205,7 +32259,7 @@ pub mod root {
[u32; 4usize] ) ));
}
#[test]
- fn __bindgen_test_layout_ScaleFactor_instantiation_223737() {
+ fn __bindgen_test_layout_ScaleFactor_instantiation_194062() {
assert_eq!(::std::mem::size_of::<u32>() , 4usize , concat ! (
"Size of template specialization: " , stringify ! ( u32 )
));
@@ -32214,7 +32268,7 @@ pub mod root {
u32 ) ));
}
#[test]
- fn __bindgen_test_layout_ScaleFactors2D_instantiation_223837() {
+ fn __bindgen_test_layout_ScaleFactors2D_instantiation_194162() {
assert_eq!(::std::mem::size_of::<[u32; 2usize]>() , 8usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32225,7 +32279,7 @@ pub mod root {
[u32; 2usize] ) ));
}
#[test]
- fn __bindgen_test_layout_ScaleFactors2D_instantiation_223845() {
+ fn __bindgen_test_layout_ScaleFactors2D_instantiation_194170() {
assert_eq!(::std::mem::size_of::<[u32; 2usize]>() , 8usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32236,7 +32290,7 @@ pub mod root {
[u32; 2usize] ) ));
}
#[test]
- fn __bindgen_test_layout_ScaleFactors2D_instantiation_223889() {
+ fn __bindgen_test_layout_ScaleFactors2D_instantiation_194214() {
assert_eq!(::std::mem::size_of::<[u32; 2usize]>() , 8usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32247,7 +32301,7 @@ pub mod root {
[u32; 2usize] ) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_224519() {
+ fn __bindgen_test_layout_nsTArray_instantiation_194844() {
assert_eq!(::std::mem::size_of::<root::nsTArray<root::mozilla::FramePropertyTable_PropertyValue>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32260,7 +32314,7 @@ pub mod root {
) ));
}
#[test]
- fn __bindgen_test_layout_nsPtrHashKey_instantiation_224535() {
+ fn __bindgen_test_layout_nsPtrHashKey_instantiation_194860() {
assert_eq!(::std::mem::size_of::<root::nsPtrHashKey<root::nsIFrame>>()
, 16usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32271,7 +32325,7 @@ pub mod root {
root::nsPtrHashKey<root::nsIFrame> ) ));
}
#[test]
- fn __bindgen_test_layout_nsPIDOMWindow_instantiation_227807() {
+ fn __bindgen_test_layout_nsPIDOMWindow_instantiation_197996() {
assert_eq!(::std::mem::size_of::<[u64; 28usize]>() , 224usize , concat
! (
"Size of template specialization: " , stringify ! (
@@ -32282,7 +32336,7 @@ pub mod root {
[u64; 28usize] ) ));
}
#[test]
- fn __bindgen_test_layout_already_AddRefed_instantiation_228437() {
+ fn __bindgen_test_layout_already_AddRefed_instantiation_198626() {
assert_eq!(::std::mem::size_of::<root::already_AddRefed<root::mozilla::dom::CSSValue>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32293,7 +32347,7 @@ pub mod root {
root::already_AddRefed<root::mozilla::dom::CSSValue> ) ));
}
#[test]
- fn __bindgen_test_layout_DefaultDelete_instantiation_228528() {
+ fn __bindgen_test_layout_DefaultDelete_instantiation_198717() {
assert_eq!(::std::mem::size_of::<root::mozilla::DefaultDelete>() ,
1usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32304,7 +32358,7 @@ pub mod root {
root::mozilla::DefaultDelete ) ));
}
#[test]
- fn __bindgen_test_layout_nsRefPtrHashtable_instantiation_228532() {
+ fn __bindgen_test_layout_nsRefPtrHashtable_instantiation_198721() {
assert_eq!(::std::mem::size_of::<[u64; 5usize]>() , 40usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32315,7 +32369,7 @@ pub mod root {
[u64; 5usize] ) ));
}
#[test]
- fn __bindgen_test_layout_already_AddRefed_instantiation_229721() {
+ fn __bindgen_test_layout_already_AddRefed_instantiation_199910() {
assert_eq!(::std::mem::size_of::<root::already_AddRefed<root::nsISupports>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32326,7 +32380,7 @@ pub mod root {
root::already_AddRefed<root::nsISupports> ) ));
}
#[test]
- fn __bindgen_test_layout_nsCOMPtr_instantiation_230007() {
+ fn __bindgen_test_layout_nsCOMPtr_instantiation_200497() {
assert_eq!(::std::mem::size_of::<root::nsCOMPtr>() , 8usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32337,7 +32391,7 @@ pub mod root {
root::nsCOMPtr ) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_231597() {
+ fn __bindgen_test_layout_nsTArray_instantiation_202040() {
assert_eq!(::std::mem::size_of::<root::nsTArray<f64>>() , 8usize ,
concat ! (
"Size of template specialization: " , stringify ! (
@@ -32348,7 +32402,7 @@ pub mod root {
root::nsTArray<f64> ) ));
}
#[test]
- fn __bindgen_test_layout_RefPtr_instantiation_231609() {
+ fn __bindgen_test_layout_RefPtr_instantiation_202052() {
assert_eq!(::std::mem::size_of::<root::RefPtr<root::mozilla::dom::DOMIntersectionObserverEntry>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32361,7 +32415,7 @@ pub mod root {
) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_231608() {
+ fn __bindgen_test_layout_nsTArray_instantiation_202051() {
assert_eq!(::std::mem::size_of::<root::nsTArray<root::RefPtr<root::mozilla::dom::DOMIntersectionObserverEntry>>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32374,7 +32428,7 @@ pub mod root {
) ));
}
#[test]
- fn __bindgen_test_layout_nsPtrHashKey_instantiation_231642() {
+ fn __bindgen_test_layout_nsPtrHashKey_instantiation_202085() {
assert_eq!(::std::mem::size_of::<root::nsPtrHashKey<root::mozilla::dom::Element>>()
, 16usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32385,7 +32439,7 @@ pub mod root {
root::nsPtrHashKey<root::mozilla::dom::Element> ) ));
}
#[test]
- fn __bindgen_test_layout_UniquePtr_instantiation_231739() {
+ fn __bindgen_test_layout_UniquePtr_instantiation_202182() {
assert_eq!(::std::mem::size_of::<root::mozilla::UniquePtr<root::ProfilerBacktrace>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32396,7 +32450,7 @@ pub mod root {
root::mozilla::UniquePtr<root::ProfilerBacktrace> ) ));
}
#[test]
- fn __bindgen_test_layout_nsDataHashtable_instantiation_233499() {
+ fn __bindgen_test_layout_nsDataHashtable_instantiation_203960() {
assert_eq!(::std::mem::size_of::<[u64; 5usize]>() , 40usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32407,7 +32461,7 @@ pub mod root {
[u64; 5usize] ) ));
}
#[test]
- fn __bindgen_test_layout_OwningNonNull_instantiation_233538() {
+ fn __bindgen_test_layout_OwningNonNull_instantiation_203999() {
assert_eq!(::std::mem::size_of::<root::mozilla::OwningNonNull<root::mozilla::EffectCompositor_AnimationStyleRuleProcessor>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32420,7 +32474,7 @@ pub mod root {
) ));
}
#[test]
- fn __bindgen_test_layout_nsRefPtrHashKey_instantiation_233561() {
+ fn __bindgen_test_layout_nsRefPtrHashKey_instantiation_204022() {
assert_eq!(::std::mem::size_of::<root::nsRefPtrHashKey<root::nsIAtom>>()
, 16usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32431,7 +32485,7 @@ pub mod root {
root::nsRefPtrHashKey<root::nsIAtom> ) ));
}
#[test]
- fn __bindgen_test_layout_nsRefPtrHashKey_instantiation_233597() {
+ fn __bindgen_test_layout_nsRefPtrHashKey_instantiation_204058() {
assert_eq!(::std::mem::size_of::<root::nsRefPtrHashKey<root::nsIContent>>()
, 16usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32442,7 +32496,7 @@ pub mod root {
root::nsRefPtrHashKey<root::nsIContent> ) ));
}
#[test]
- fn __bindgen_test_layout_DefaultDelete_instantiation_234142() {
+ fn __bindgen_test_layout_DefaultDelete_instantiation_204603() {
assert_eq!(::std::mem::size_of::<root::mozilla::DefaultDelete>() ,
1usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32453,7 +32507,7 @@ pub mod root {
root::mozilla::DefaultDelete ) ));
}
#[test]
- fn __bindgen_test_layout_already_AddRefed_instantiation_234156() {
+ fn __bindgen_test_layout_already_AddRefed_instantiation_204617() {
assert_eq!(::std::mem::size_of::<root::already_AddRefed<root::mozilla::URLExtraData>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32464,7 +32518,7 @@ pub mod root {
root::already_AddRefed<root::mozilla::URLExtraData> ) ));
}
#[test]
- fn __bindgen_test_layout_nsMainThreadPtrHolder_instantiation_234160() {
+ fn __bindgen_test_layout_nsMainThreadPtrHolder_instantiation_204621() {
assert_eq!(::std::mem::size_of::<root::nsMainThreadPtrHolder<root::nsIURI>>()
, 24usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32475,7 +32529,7 @@ pub mod root {
root::nsMainThreadPtrHolder<root::nsIURI> ) ));
}
#[test]
- fn __bindgen_test_layout_nsPtrHashKey_instantiation_234234() {
+ fn __bindgen_test_layout_nsPtrHashKey_instantiation_204695() {
assert_eq!(::std::mem::size_of::<root::nsPtrHashKey<root::nsIDocument>>()
, 16usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32486,7 +32540,7 @@ pub mod root {
root::nsPtrHashKey<root::nsIDocument> ) ));
}
#[test]
- fn __bindgen_test_layout_DefaultDelete_instantiation_234521() {
+ fn __bindgen_test_layout_DefaultDelete_instantiation_204982() {
assert_eq!(::std::mem::size_of::<root::mozilla::DefaultDelete>() ,
1usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32497,7 +32551,7 @@ pub mod root {
root::mozilla::DefaultDelete ) ));
}
#[test]
- fn __bindgen_test_layout_UniquePtr_instantiation_234519() {
+ fn __bindgen_test_layout_UniquePtr_instantiation_204980() {
assert_eq!(::std::mem::size_of::<root::mozilla::UniquePtr<root::nsCSSValueList>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32508,7 +32562,7 @@ pub mod root {
root::mozilla::UniquePtr<root::nsCSSValueList> ) ));
}
#[test]
- fn __bindgen_test_layout_DefaultDelete_instantiation_234527() {
+ fn __bindgen_test_layout_DefaultDelete_instantiation_204988() {
assert_eq!(::std::mem::size_of::<root::mozilla::DefaultDelete>() ,
1usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32519,7 +32573,7 @@ pub mod root {
root::mozilla::DefaultDelete ) ));
}
#[test]
- fn __bindgen_test_layout_UniquePtr_instantiation_234525() {
+ fn __bindgen_test_layout_UniquePtr_instantiation_204986() {
assert_eq!(::std::mem::size_of::<root::mozilla::UniquePtr<root::nsCSSValuePairList>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32530,7 +32584,7 @@ pub mod root {
root::mozilla::UniquePtr<root::nsCSSValuePairList> ) ));
}
#[test]
- fn __bindgen_test_layout_Maybe_instantiation_234797() {
+ fn __bindgen_test_layout_Maybe_instantiation_205258() {
assert_eq!(::std::mem::size_of::<[u64; 2usize]>() , 16usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32541,7 +32595,7 @@ pub mod root {
[u64; 2usize] ) ));
}
#[test]
- fn __bindgen_test_layout_SupportsWeakPtr_instantiation_234964() {
+ fn __bindgen_test_layout_SupportsWeakPtr_instantiation_205425() {
assert_eq!(::std::mem::size_of::<u64>() , 8usize , concat ! (
"Size of template specialization: " , stringify ! ( u64 )
));
@@ -32550,7 +32604,7 @@ pub mod root {
u64 ) ));
}
#[test]
- fn __bindgen_test_layout_Maybe_instantiation_235122() {
+ fn __bindgen_test_layout_Maybe_instantiation_205583() {
assert_eq!(::std::mem::size_of::<[u32; 3usize]>() , 12usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32561,7 +32615,7 @@ pub mod root {
[u32; 3usize] ) ));
}
#[test]
- fn __bindgen_test_layout_already_AddRefed_instantiation_235137() {
+ fn __bindgen_test_layout_already_AddRefed_instantiation_205598() {
assert_eq!(::std::mem::size_of::<root::already_AddRefed<root::nsStyleImageRequest>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32572,7 +32626,7 @@ pub mod root {
root::already_AddRefed<root::nsStyleImageRequest> ) ));
}
#[test]
- fn __bindgen_test_layout_DefaultDelete_instantiation_235145() {
+ fn __bindgen_test_layout_DefaultDelete_instantiation_205606() {
assert_eq!(::std::mem::size_of::<root::mozilla::DefaultDelete>() ,
1usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32583,7 +32637,7 @@ pub mod root {
root::mozilla::DefaultDelete ) ));
}
#[test]
- fn __bindgen_test_layout_UniquePtr_instantiation_235143() {
+ fn __bindgen_test_layout_UniquePtr_instantiation_205604() {
assert_eq!(::std::mem::size_of::<root::mozilla::UniquePtr<root::nsStyleSides>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32594,7 +32648,7 @@ pub mod root {
root::mozilla::UniquePtr<root::nsStyleSides> ) ));
}
#[test]
- fn __bindgen_test_layout_DefaultDelete_instantiation_235184() {
+ fn __bindgen_test_layout_DefaultDelete_instantiation_205645() {
assert_eq!(::std::mem::size_of::<root::mozilla::DefaultDelete>() ,
1usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32605,7 +32659,7 @@ pub mod root {
root::mozilla::DefaultDelete ) ));
}
#[test]
- fn __bindgen_test_layout_pair_instantiation_235335() {
+ fn __bindgen_test_layout_pair_instantiation_205796() {
assert_eq!(::std::mem::size_of::<root::std::pair<::nsstring::nsStringRepr, ::nsstring::nsStringRepr>>()
, 32usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32616,7 +32670,7 @@ pub mod root {
root::std::pair<::nsstring::nsStringRepr, ::nsstring::nsStringRepr> ) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_235334() {
+ fn __bindgen_test_layout_nsTArray_instantiation_205795() {
assert_eq!(::std::mem::size_of::<root::nsTArray<root::std::pair<::nsstring::nsStringRepr,
::nsstring::nsStringRepr>>>()
, 8usize , concat ! (
@@ -32631,7 +32685,7 @@ pub mod root {
) ));
}
#[test]
- fn __bindgen_test_layout_RefPtr_instantiation_236328() {
+ fn __bindgen_test_layout_RefPtr_instantiation_206789() {
assert_eq!(::std::mem::size_of::<root::RefPtr<root::RawServoAnimationValue>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32642,7 +32696,7 @@ pub mod root {
root::RefPtr<root::RawServoAnimationValue> ) ));
}
#[test]
- fn __bindgen_test_layout_BaseTimeDuration_instantiation_240320() {
+ fn __bindgen_test_layout_BaseTimeDuration_instantiation_208511() {
assert_eq!(::std::mem::size_of::<root::mozilla::BaseTimeDuration>() ,
8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32653,7 +32707,7 @@ pub mod root {
root::mozilla::BaseTimeDuration ) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_240912() {
+ fn __bindgen_test_layout_nsTArray_instantiation_209103() {
assert_eq!(::std::mem::size_of::<root::nsTArray<root::mozilla::DisplayItemClip_RoundedRect>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32666,7 +32720,18 @@ pub mod root {
) ));
}
#[test]
- fn __bindgen_test_layout_Maybe_instantiation_241088() {
+ fn __bindgen_test_layout_Maybe_instantiation_209359() {
+ assert_eq!(::std::mem::size_of::<[u64; 2usize]>() , 16usize , concat !
+ (
+ "Size of template specialization: " , stringify ! (
+ [u64; 2usize] ) ));
+ assert_eq!(::std::mem::align_of::<[u64; 2usize]>() , 8usize , concat !
+ (
+ "Alignment of template specialization: " , stringify ! (
+ [u64; 2usize] ) ));
+ }
+ #[test]
+ fn __bindgen_test_layout_Maybe_instantiation_209366() {
assert_eq!(::std::mem::size_of::<[u64; 5usize]>() , 40usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32677,7 +32742,7 @@ pub mod root {
[u64; 5usize] ) ));
}
#[test]
- fn __bindgen_test_layout_RefPtr_instantiation_241263() {
+ fn __bindgen_test_layout_RefPtr_instantiation_209541() {
assert_eq!(::std::mem::size_of::<root::RefPtr<root::mozilla::dom::DOMRect>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32688,7 +32753,7 @@ pub mod root {
root::RefPtr<root::mozilla::dom::DOMRect> ) ));
}
#[test]
- fn __bindgen_test_layout_Sequence_instantiation_241507() {
+ fn __bindgen_test_layout_Sequence_instantiation_209785() {
assert_eq!(::std::mem::size_of::<u64>() , 8usize , concat ! (
"Size of template specialization: " , stringify ! ( u64 )
));
@@ -32697,7 +32762,7 @@ pub mod root {
u64 ) ));
}
#[test]
- fn __bindgen_test_layout_nsRefPtrHashKey_instantiation_241806() {
+ fn __bindgen_test_layout_nsRefPtrHashKey_instantiation_210084() {
assert_eq!(::std::mem::size_of::<root::nsRefPtrHashKey<root::mozilla::dom::Element>>()
, 16usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32708,7 +32773,7 @@ pub mod root {
root::nsRefPtrHashKey<root::mozilla::dom::Element> ) ));
}
#[test]
- fn __bindgen_test_layout_nsClassHashtable_instantiation_241805() {
+ fn __bindgen_test_layout_nsClassHashtable_instantiation_210083() {
assert_eq!(::std::mem::size_of::<[u64; 5usize]>() , 40usize , concat !
(
"Size of template specialization: " , stringify ! (
@@ -32719,7 +32784,7 @@ pub mod root {
[u64; 5usize] ) ));
}
#[test]
- fn __bindgen_test_layout_nsTArray_instantiation_243035() {
+ fn __bindgen_test_layout_nsTArray_instantiation_211313() {
assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::css::DocumentRule>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -32730,7 +32795,7 @@ pub mod root {
root::nsTArray<*mut root::mozilla::css::DocumentRule> ) ));
}
#[test]
- fn __bindgen_test_layout_nsAutoPtr_instantiation_243071() {
+ fn __bindgen_test_layout_nsAutoPtr_instantiation_211349() {
assert_eq!(::std::mem::size_of::<root::nsAutoPtr<root::nsMediaQuery>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
diff --git a/components/style/gecko/global_style_data.rs b/components/style/gecko/global_style_data.rs
index 3cbace9b90a..2ba8749e24f 100644
--- a/components/style/gecko/global_style_data.rs
+++ b/components/style/gecko/global_style_data.rs
@@ -57,12 +57,25 @@ lazy_static! {
pub static ref GLOBAL_STYLE_DATA: GlobalStyleData = {
let stylo_threads = env::var("STYLO_THREADS")
.map(|s| s.parse::<usize>().expect("invalid STYLO_THREADS value"));
- let num_threads = match stylo_threads {
+ let mut num_threads = match stylo_threads {
Ok(num) => num,
_ => cmp::max(num_cpus::get() * 3 / 4, 1),
};
- let pool = if num_threads <= 1 {
+ // If num_threads is one, there's no point in creating a thread pool, so
+ // force it to zero.
+ //
+ // We allow developers to force a one-thread pool for testing via a
+ // special environmental variable.
+ if num_threads == 1 {
+ let force_pool = env::var("FORCE_STYLO_THREAD_POOL")
+ .ok().map_or(false, |s| s.parse::<usize>().expect("invalid FORCE_STYLO_THREAD_POOL value") == 1);
+ if !force_pool {
+ num_threads = 0;
+ }
+ }
+
+ let pool = if num_threads < 1 {
None
} else {
let configuration = rayon::Configuration::new()
diff --git a/components/style/gecko/non_ts_pseudo_class_list.rs b/components/style/gecko/non_ts_pseudo_class_list.rs
index 5b1b056ba91..f6551ce90d4 100644
--- a/components/style/gecko/non_ts_pseudo_class_list.rs
+++ b/components/style/gecko/non_ts_pseudo_class_list.rs
@@ -25,8 +25,6 @@
*
* Pending pseudo-classes:
*
- * :-moz-is-html -> Used only in UA sheets, should be easy to support.
- *
* :-moz-lwtheme, :-moz-lwtheme-brighttext, :-moz-lwtheme-darktext,
* :-moz-window-inactive.
*
@@ -108,6 +106,7 @@ macro_rules! apply_non_ts_list {
("-moz-last-node", MozLastNode, lastNode, _, _),
("-moz-only-whitespace", MozOnlyWhitespace, mozOnlyWhitespace, _, _),
("-moz-native-anonymous", MozNativeAnonymous, mozNativeAnonymous, _, PSEUDO_CLASS_INTERNAL),
+ ("-moz-is-html", MozIsHTML, mozIsHTML, _, _),
],
string: [
("-moz-system-metric", MozSystemMetric, mozSystemMetric, _, PSEUDO_CLASS_INTERNAL),
diff --git a/components/style/gecko/pseudo_element.rs b/components/style/gecko/pseudo_element.rs
index f01c182802e..b15e17e6f38 100644
--- a/components/style/gecko/pseudo_element.rs
+++ b/components/style/gecko/pseudo_element.rs
@@ -10,12 +10,24 @@
use cssparser::ToCss;
use gecko_bindings::structs::{self, CSSPseudoElementType};
-use selector_parser::PseudoElementCascadeType;
+use selector_parser::{NonTSPseudoClass, PseudoElementCascadeType, SelectorImpl};
use std::fmt;
use string_cache::Atom;
include!(concat!(env!("OUT_DIR"), "/gecko/pseudo_element_definition.rs"));
+impl ::selectors::parser::PseudoElement for PseudoElement {
+ type Impl = SelectorImpl;
+
+ 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();
+ }
+}
+
impl PseudoElement {
/// Returns the kind of cascade type that a given pseudo is going to use.
///
diff --git a/components/style/gecko/selector_parser.rs b/components/style/gecko/selector_parser.rs
index bed3737db99..787ecd5b2cb 100644
--- a/components/style/gecko/selector_parser.rs
+++ b/components/style/gecko/selector_parser.rs
@@ -5,7 +5,6 @@
//! Gecko-specific bits for selector-parsing.
use cssparser::{Parser, ToCss};
-use element_state::{IN_ACTIVE_STATE, IN_FOCUS_STATE, IN_HOVER_STATE};
use element_state::ElementState;
use gecko_bindings::structs::CSSPseudoClassType;
use selector_parser::{SelectorParser, PseudoElementCascadeType};
@@ -132,7 +131,7 @@ impl NonTSPseudoClass {
/// https://drafts.csswg.org/selectors-4/#useraction-pseudos
///
/// We intentionally skip the link-related ones.
- fn is_safe_user_action_state(&self) -> bool {
+ pub fn is_safe_user_action_state(&self) -> bool {
matches!(*self, NonTSPseudoClass::Hover |
NonTSPseudoClass::Active |
NonTSPseudoClass::Focus)
@@ -159,8 +158,15 @@ impl NonTSPseudoClass {
/// Returns true if the given pseudoclass should trigger style sharing cache revalidation.
pub fn needs_cache_revalidation(&self) -> bool {
+ // :dir() depends on state only, but doesn't use state_flag because its
+ // semantics don't quite match. Nevertheless, it doesn't need cache
+ // revalidation, because we already compare states for elements and
+ // candidates.
self.state_flag().is_empty() &&
- !matches!(*self, NonTSPseudoClass::MozAny(_))
+ !matches!(*self,
+ NonTSPseudoClass::MozAny(_) |
+ NonTSPseudoClass::Dir(_) |
+ NonTSPseudoClass::MozIsHTML)
}
/// Convert NonTSPseudoClass to Gecko's CSSPseudoClassType.
@@ -188,58 +194,6 @@ impl NonTSPseudoClass {
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SelectorImpl;
-/// Some subset of pseudo-elements in Gecko are sensitive to some state
-/// selectors.
-///
-/// We store the sensitive states in this struct in order to properly handle
-/// these.
-#[derive(Clone, Debug, PartialEq, Eq, Hash)]
-pub struct PseudoElementSelector {
- pseudo: PseudoElement,
- state: ElementState,
-}
-
-impl PseudoElementSelector {
- /// Returns the pseudo-element this selector represents.
- pub fn pseudo_element(&self) -> &PseudoElement {
- &self.pseudo
- }
-
- /// Returns the pseudo-element selector state.
- pub fn state(&self) -> ElementState {
- self.state
- }
-}
-
-impl ToCss for PseudoElementSelector {
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result
- where W: fmt::Write,
- {
- if cfg!(debug_assertions) {
- let mut state = self.state;
- state.remove(IN_HOVER_STATE | IN_ACTIVE_STATE | IN_FOCUS_STATE);
- assert_eq!(state, ElementState::empty(),
- "Unhandled pseudo-element state selector?");
- }
-
- self.pseudo.to_css(dest)?;
-
- if self.state.contains(IN_HOVER_STATE) {
- dest.write_str(":hover")?
- }
-
- if self.state.contains(IN_ACTIVE_STATE) {
- dest.write_str(":active")?
- }
-
- if self.state.contains(IN_FOCUS_STATE) {
- dest.write_str(":focus")?
- }
-
- Ok(())
- }
-}
-
impl ::selectors::SelectorImpl for SelectorImpl {
type AttrValue = Atom;
type Identifier = Atom;
@@ -250,7 +204,7 @@ impl ::selectors::SelectorImpl for SelectorImpl {
type BorrowedNamespaceUrl = WeakNamespace;
type BorrowedLocalName = WeakAtom;
- type PseudoElementSelector = PseudoElementSelector;
+ type PseudoElement = PseudoElement;
type NonTSPseudoClass = NonTSPseudoClass;
}
@@ -312,38 +266,9 @@ impl<'a> ::selectors::Parser for SelectorParser<'a> {
}
}
- fn parse_pseudo_element(&self, name: Cow<str>, input: &mut Parser) -> Result<PseudoElementSelector, ()> {
- let pseudo =
- match PseudoElement::from_slice(&name, self.in_user_agent_stylesheet()) {
- Some(pseudo) => pseudo,
- None => return Err(()),
- };
-
- let state = if pseudo.supports_user_action_state() {
- input.try(|input| {
- let mut state = ElementState::empty();
-
- while !input.is_exhausted() {
- input.expect_colon()?;
- let ident = input.expect_ident()?;
- let pseudo_class = self.parse_non_ts_pseudo_class(ident)?;
-
- if !pseudo_class.is_safe_user_action_state() {
- return Err(())
- }
- state.insert(pseudo_class.state_flag());
- }
-
- Ok(state)
- }).ok()
- } else {
- None
- };
-
- Ok(PseudoElementSelector {
- pseudo: pseudo,
- state: state.unwrap_or(ElementState::empty()),
- })
+ fn parse_pseudo_element(&self, name: Cow<str>) -> Result<PseudoElement, ()> {
+ PseudoElement::from_slice(&name, self.in_user_agent_stylesheet())
+ .ok_or(())
}
fn default_namespace(&self) -> Option<Namespace> {
diff --git a/components/style/gecko/snapshot.rs b/components/style/gecko/snapshot.rs
index ea4871bc2a7..4a79b492996 100644
--- a/components/style/gecko/snapshot.rs
+++ b/components/style/gecko/snapshot.rs
@@ -8,15 +8,14 @@
use dom::TElement;
use element_state::ElementState;
use gecko::snapshot_helpers;
-use gecko::wrapper::{AttrSelectorHelpers, GeckoElement};
+use gecko::wrapper::{NamespaceConstraintHelpers, GeckoElement};
use gecko_bindings::bindings;
use gecko_bindings::structs::ServoElementSnapshot;
use gecko_bindings::structs::ServoElementSnapshotFlags as Flags;
use gecko_bindings::structs::ServoElementSnapshotTable;
use restyle_hints::ElementSnapshot;
-use selector_parser::SelectorImpl;
-use selectors::parser::AttrSelector;
-use string_cache::Atom;
+use selectors::attr::{AttrSelectorOperation, AttrSelectorOperator, CaseSensitivity, NamespaceConstraint};
+use string_cache::{Atom, Namespace};
/// A snapshot of a Gecko element.
pub type GeckoElementSnapshot = ServoElementSnapshot;
@@ -48,11 +47,6 @@ impl SnapshotMap {
impl GeckoElementSnapshot {
#[inline]
- fn is_html_element_in_html_document(&self) -> bool {
- self.mIsHTMLElementInHTMLDocument
- }
-
- #[inline]
fn has_any(&self, flags: Flags) -> bool {
(self.mContains as u8 & flags as u8) != 0
}
@@ -60,76 +54,67 @@ impl GeckoElementSnapshot {
fn as_ptr(&self) -> *const Self {
self
}
-}
-
-impl ::selectors::MatchAttr for GeckoElementSnapshot {
- type Impl = SelectorImpl;
-
- fn match_attr_has(&self, attr: &AttrSelector<SelectorImpl>) -> bool {
- unsafe {
- bindings::Gecko_SnapshotHasAttr(self,
- attr.ns_or_null(),
- attr.select_name(self.is_html_element_in_html_document()))
- }
- }
- fn match_attr_equals(&self, attr: &AttrSelector<SelectorImpl>, value: &Atom) -> bool {
- unsafe {
- bindings::Gecko_SnapshotAttrEquals(self,
- attr.ns_or_null(),
- attr.select_name(self.is_html_element_in_html_document()),
- value.as_ptr(),
- /* ignoreCase = */ false)
- }
- }
-
- fn match_attr_equals_ignore_ascii_case(&self, attr: &AttrSelector<SelectorImpl>, value: &Atom) -> bool {
- unsafe {
- bindings::Gecko_SnapshotAttrEquals(self,
- attr.ns_or_null(),
- attr.select_name(self.is_html_element_in_html_document()),
- value.as_ptr(),
- /* ignoreCase = */ true)
- }
- }
- fn match_attr_includes(&self, attr: &AttrSelector<SelectorImpl>, value: &Atom) -> bool {
- unsafe {
- bindings::Gecko_SnapshotAttrIncludes(self,
- attr.ns_or_null(),
- attr.select_name(self.is_html_element_in_html_document()),
- value.as_ptr())
- }
- }
- fn match_attr_dash(&self, attr: &AttrSelector<SelectorImpl>, value: &Atom) -> bool {
+ /// selectors::Element::attr_matches
+ pub fn attr_matches(&self,
+ ns: &NamespaceConstraint<&Namespace>,
+ local_name: &Atom,
+ operation: &AttrSelectorOperation<&Atom>)
+ -> bool {
unsafe {
- bindings::Gecko_SnapshotAttrDashEquals(self,
- attr.ns_or_null(),
- attr.select_name(self.is_html_element_in_html_document()),
- value.as_ptr())
- }
- }
- fn match_attr_prefix(&self, attr: &AttrSelector<SelectorImpl>, value: &Atom) -> bool {
- unsafe {
- bindings::Gecko_SnapshotAttrHasPrefix(self,
- attr.ns_or_null(),
- attr.select_name(self.is_html_element_in_html_document()),
- value.as_ptr())
- }
- }
- fn match_attr_substring(&self, attr: &AttrSelector<SelectorImpl>, value: &Atom) -> bool {
- unsafe {
- bindings::Gecko_SnapshotAttrHasSubstring(self,
- attr.ns_or_null(),
- attr.select_name(self.is_html_element_in_html_document()),
- value.as_ptr())
- }
- }
- fn match_attr_suffix(&self, attr: &AttrSelector<SelectorImpl>, value: &Atom) -> bool {
- unsafe {
- bindings::Gecko_SnapshotAttrHasSuffix(self,
- attr.ns_or_null(),
- attr.select_name(self.is_html_element_in_html_document()),
- value.as_ptr())
+ match *operation {
+ AttrSelectorOperation::Exists => {
+ bindings:: Gecko_SnapshotHasAttr(self,
+ ns.atom_or_null(),
+ local_name.as_ptr())
+ }
+ AttrSelectorOperation::WithValue { operator, case_sensitivity, expected_value } => {
+ let ignore_case = match case_sensitivity {
+ CaseSensitivity::CaseSensitive => false,
+ CaseSensitivity::AsciiCaseInsensitive => true,
+ };
+ // FIXME: case sensitivity for operators other than Equal
+ match operator {
+ AttrSelectorOperator::Equal => bindings::Gecko_SnapshotAttrEquals(
+ self,
+ ns.atom_or_null(),
+ local_name.as_ptr(),
+ expected_value.as_ptr(),
+ ignore_case
+ ),
+ AttrSelectorOperator::Includes => bindings::Gecko_SnapshotAttrIncludes(
+ self,
+ ns.atom_or_null(),
+ local_name.as_ptr(),
+ expected_value.as_ptr(),
+ ),
+ AttrSelectorOperator::DashMatch => bindings::Gecko_SnapshotAttrDashEquals(
+ self,
+ ns.atom_or_null(),
+ local_name.as_ptr(),
+ expected_value.as_ptr(),
+ ),
+ AttrSelectorOperator::Prefix => bindings::Gecko_SnapshotAttrHasPrefix(
+ self,
+ ns.atom_or_null(),
+ local_name.as_ptr(),
+ expected_value.as_ptr(),
+ ),
+ AttrSelectorOperator::Suffix => bindings::Gecko_SnapshotAttrHasSuffix(
+ self,
+ ns.atom_or_null(),
+ local_name.as_ptr(),
+ expected_value.as_ptr(),
+ ),
+ AttrSelectorOperator::Substring => bindings::Gecko_SnapshotAttrHasSubstring(
+ self,
+ ns.atom_or_null(),
+ local_name.as_ptr(),
+ expected_value.as_ptr(),
+ ),
+ }
+ }
+ }
}
}
}
@@ -148,7 +133,12 @@ impl ElementSnapshot for GeckoElementSnapshot {
self.has_any(Flags::Attributes)
}
+ #[inline]
fn id_attr(&self) -> Option<Atom> {
+ if !self.has_any(Flags::Id) {
+ return None
+ }
+
let ptr = unsafe {
bindings::Gecko_SnapshotAtomAttrValue(self,
atom!("id").as_ptr())
@@ -161,15 +151,25 @@ impl ElementSnapshot for GeckoElementSnapshot {
}
}
+ #[inline]
fn has_class(&self, name: &Atom) -> bool {
+ if !self.has_any(Flags::MaybeClass) {
+ return false;
+ }
+
snapshot_helpers::has_class(self.as_ptr(),
name,
bindings::Gecko_SnapshotClassOrClassList)
}
+ #[inline]
fn each_class<F>(&self, callback: F)
where F: FnMut(&Atom)
{
+ if !self.has_any(Flags::MaybeClass) {
+ return;
+ }
+
snapshot_helpers::each_class(self.as_ptr(),
callback,
bindings::Gecko_SnapshotClassOrClassList)
diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs
index 41224c0b403..3d8ab270658 100644
--- a/components/style/gecko/wrapper.rs
+++ b/components/style/gecko/wrapper.rs
@@ -46,7 +46,7 @@ use gecko_bindings::bindings::Gecko_MatchStringArgPseudo;
use gecko_bindings::bindings::Gecko_UpdateAnimations;
use gecko_bindings::structs;
use gecko_bindings::structs::{RawGeckoElement, RawGeckoNode};
-use gecko_bindings::structs::{nsIAtom, nsIContent, nsStyleContext};
+use gecko_bindings::structs::{nsIAtom, nsIContent, nsINode_BooleanFlag, nsStyleContext};
use gecko_bindings::structs::ELEMENT_HANDLED_SNAPSHOT;
use gecko_bindings::structs::ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO;
use gecko_bindings::structs::ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO;
@@ -64,8 +64,8 @@ use properties::style_structs::Font;
use rule_tree::CascadeLevel as ServoCascadeLevel;
use selector_parser::ElementExt;
use selectors::Element;
-use selectors::matching::{ElementSelectorFlags, StyleRelations};
-use selectors::parser::{AttrSelector, NamespaceConstraint};
+use selectors::attr::{AttrSelectorOperation, AttrSelectorOperator, CaseSensitivity, NamespaceConstraint};
+use selectors::matching::{ElementSelectorFlags, MatchingContext, MatchingMode};
use shared_lock::Locked;
use sink::Push;
use std::cell::RefCell;
@@ -104,14 +104,17 @@ impl<'ln> fmt::Debug for GeckoNode<'ln> {
}
impl<'ln> GeckoNode<'ln> {
+ #[inline]
fn from_content(content: &'ln nsIContent) -> Self {
GeckoNode(&content._base)
}
+ #[inline]
fn flags(&self) -> u32 {
(self.0)._base._base_1.mFlags
}
+ #[inline]
fn node_info(&self) -> &structs::NodeInfo {
debug_assert!(!self.0.mNodeInfo.mRawPtr.is_null());
unsafe { &*self.0.mNodeInfo.mRawPtr }
@@ -119,32 +122,43 @@ impl<'ln> GeckoNode<'ln> {
// These live in different locations depending on processor architecture.
#[cfg(target_pointer_width = "64")]
+ #[inline]
fn bool_flags(&self) -> u32 {
(self.0)._base._base_1.mBoolFlags
}
#[cfg(target_pointer_width = "32")]
+ #[inline]
fn bool_flags(&self) -> u32 {
(self.0).mBoolFlags
}
+ #[inline]
+ fn get_bool_flag(&self, flag: nsINode_BooleanFlag) -> bool {
+ self.bool_flags() & (1u32 << flag as u32) != 0
+ }
+
fn owner_doc(&self) -> &structs::nsIDocument {
debug_assert!(!self.node_info().mDocument.is_null());
unsafe { &*self.node_info().mDocument }
}
+ #[inline]
fn first_child(&self) -> Option<GeckoNode<'ln>> {
unsafe { self.0.mFirstChild.as_ref().map(GeckoNode::from_content) }
}
+ #[inline]
fn last_child(&self) -> Option<GeckoNode<'ln>> {
unsafe { Gecko_GetLastChild(self.0).map(GeckoNode) }
}
+ #[inline]
fn prev_sibling(&self) -> Option<GeckoNode<'ln>> {
unsafe { self.0.mPreviousSibling.as_ref().map(GeckoNode::from_content) }
}
+ #[inline]
fn next_sibling(&self) -> Option<GeckoNode<'ln>> {
unsafe { self.0.mNextSibling.as_ref().map(GeckoNode::from_content) }
}
@@ -186,9 +200,9 @@ impl<'ln> GeckoNode<'ln> {
}
impl<'ln> NodeInfo for GeckoNode<'ln> {
+ #[inline]
fn is_element(&self) -> bool {
- use gecko_bindings::structs::nsINode_BooleanFlag;
- self.bool_flags() & (1u32 << nsINode_BooleanFlag::NodeIsElement as u32) != 0
+ self.get_bool_flag(nsINode_BooleanFlag::NodeIsElement)
}
fn is_text_node(&self) -> bool {
@@ -408,10 +422,24 @@ impl<'le> GeckoElement<'le> {
}
}
+ #[inline]
fn may_have_animations(&self) -> bool {
- use gecko_bindings::structs::nsINode_BooleanFlag;
- self.as_node().bool_flags() &
- (1u32 << nsINode_BooleanFlag::ElementHasAnimations as u32) != 0
+ self.as_node().get_bool_flag(nsINode_BooleanFlag::ElementHasAnimations)
+ }
+
+ #[inline]
+ fn has_id(&self) -> bool {
+ self.as_node().get_bool_flag(nsINode_BooleanFlag::ElementHasID)
+ }
+
+ #[inline]
+ fn may_have_class(&self) -> bool {
+ self.as_node().get_bool_flag(nsINode_BooleanFlag::ElementMayHaveClass)
+ }
+
+ #[inline]
+ fn may_have_style_attribute(&self) -> bool {
+ self.as_node().get_bool_flag(nsINode_BooleanFlag::ElementMayHaveStyle)
}
}
@@ -564,8 +592,12 @@ impl<'le> TElement for GeckoElement<'le> {
}
fn style_attribute(&self) -> Option<&Arc<Locked<PropertyDeclarationBlock>>> {
+ if !self.may_have_style_attribute() {
+ return None;
+ }
+
let declarations = unsafe { Gecko_GetStyleAttrDeclarationBlock(self.0) };
- declarations.map(|s| s.as_arc_opt()).unwrap_or(None)
+ declarations.map_or(None, |s| s.as_arc_opt())
}
fn get_smil_override(&self) -> Option<&Arc<Locked<PropertyDeclarationBlock>>> {
@@ -623,8 +655,16 @@ impl<'le> TElement for GeckoElement<'le> {
}
}
+ fn each_class<F>(&self, callback: F)
+ where F: FnMut(&Atom)
+ {
+ snapshot_helpers::each_class(self.0,
+ callback,
+ Gecko_ClassOrClassList)
+ }
+
fn existing_style_for_restyle_damage<'a>(&'a self,
- _existing_values: &'a Arc<ComputedValues>,
+ _existing_values: &'a ComputedValues,
pseudo: Option<&PseudoElement>)
-> Option<&'a nsStyleContext> {
// TODO(emilio): Migrate this to CSSPseudoElementType.
@@ -1050,11 +1090,18 @@ impl<'le> PresentationalHintsSynthesizer for GeckoElement<'le> {
}
impl<'le> ::selectors::Element for GeckoElement<'le> {
+ type Impl = SelectorImpl;
+
fn parent_element(&self) -> Option<Self> {
let parent_node = self.as_node().parent_node();
parent_node.and_then(|n| n.as_element())
}
+ fn pseudo_element_originating_element(&self) -> Option<Self> {
+ debug_assert!(self.implemented_pseudo_element().is_some());
+ self.closest_non_native_anonymous_ancestor()
+ }
+
fn first_child_element(&self) -> Option<Self> {
let mut child = self.as_node().first_child();
while let Some(child_node) = child {
@@ -1099,6 +1146,68 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
None
}
+ fn attr_matches(&self,
+ ns: &NamespaceConstraint<&Namespace>,
+ local_name: &Atom,
+ operation: &AttrSelectorOperation<&Atom>)
+ -> bool {
+ unsafe {
+ match *operation {
+ AttrSelectorOperation::Exists => {
+ bindings::Gecko_HasAttr(self.0,
+ ns.atom_or_null(),
+ local_name.as_ptr())
+ }
+ AttrSelectorOperation::WithValue { operator, case_sensitivity, expected_value } => {
+ let ignore_case = match case_sensitivity {
+ CaseSensitivity::CaseSensitive => false,
+ CaseSensitivity::AsciiCaseInsensitive => true,
+ };
+ // FIXME: case sensitivity for operators other than Equal
+ match operator {
+ AttrSelectorOperator::Equal => bindings::Gecko_AttrEquals(
+ self.0,
+ ns.atom_or_null(),
+ local_name.as_ptr(),
+ expected_value.as_ptr(),
+ ignore_case
+ ),
+ AttrSelectorOperator::Includes => bindings::Gecko_AttrIncludes(
+ self.0,
+ ns.atom_or_null(),
+ local_name.as_ptr(),
+ expected_value.as_ptr(),
+ ),
+ AttrSelectorOperator::DashMatch => bindings::Gecko_AttrDashEquals(
+ self.0,
+ ns.atom_or_null(),
+ local_name.as_ptr(),
+ expected_value.as_ptr(),
+ ),
+ AttrSelectorOperator::Prefix => bindings::Gecko_AttrHasPrefix(
+ self.0,
+ ns.atom_or_null(),
+ local_name.as_ptr(),
+ expected_value.as_ptr(),
+ ),
+ AttrSelectorOperator::Suffix => bindings::Gecko_AttrHasSuffix(
+ self.0,
+ ns.atom_or_null(),
+ local_name.as_ptr(),
+ expected_value.as_ptr(),
+ ),
+ AttrSelectorOperator::Substring => bindings::Gecko_AttrHasSubstring(
+ self.0,
+ ns.atom_or_null(),
+ local_name.as_ptr(),
+ expected_value.as_ptr(),
+ ),
+ }
+ }
+ }
+ }
+ }
+
fn is_root(&self) -> bool {
unsafe {
Gecko_IsRootElement(self.0)
@@ -1125,7 +1234,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
fn match_non_ts_pseudo_class<F>(&self,
pseudo_class: &NonTSPseudoClass,
- relations: &mut StyleRelations,
+ context: &mut MatchingContext,
flags_setter: &mut F)
-> bool
where F: FnMut(&Self, ElementSelectorFlags),
@@ -1217,9 +1326,12 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
NonTSPseudoClass::MozNativeAnonymous => unsafe {
Gecko_MatchesElement(pseudo_class.to_gecko_pseudoclasstype().unwrap(), self.0)
},
+ NonTSPseudoClass::MozIsHTML => {
+ self.is_html_element_in_html_document()
+ }
NonTSPseudoClass::MozAny(ref sels) => {
sels.iter().any(|s| {
- matches_complex_selector(s, self, relations, flags_setter)
+ matches_complex_selector(s, self, context, flags_setter)
})
}
NonTSPseudoClass::MozSystemMetric(ref s) |
@@ -1241,7 +1353,25 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
}
}
+ fn match_pseudo_element(&self,
+ pseudo_element: &PseudoElement,
+ _context: &mut MatchingContext)
+ -> bool
+ {
+ // TODO(emilio): I believe we could assert we are a pseudo-element and
+ // match the proper pseudo-element, given how we rulehash the stuff
+ // based on the pseudo.
+ match self.implemented_pseudo_element() {
+ Some(ref pseudo) => pseudo == pseudo_element,
+ None => false,
+ }
+ }
+
fn get_id(&self) -> Option<Atom> {
+ if !self.has_id() {
+ return None;
+ }
+
let ptr = unsafe {
bindings::Gecko_AtomAttrValue(self.0,
atom!("id").as_ptr())
@@ -1255,19 +1385,15 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
}
fn has_class(&self, name: &Atom) -> bool {
+ if !self.may_have_class() {
+ return false;
+ }
+
snapshot_helpers::has_class(self.0,
name,
Gecko_ClassOrClassList)
}
- fn each_class<F>(&self, callback: F)
- where F: FnMut(&Atom)
- {
- snapshot_helpers::each_class(self.0,
- callback,
- Gecko_ClassOrClassList)
- }
-
fn is_html_element_in_html_document(&self) -> bool {
let node = self.as_node();
let node_info = node.node_info();
@@ -1277,97 +1403,16 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
}
/// A few helpers to help with attribute selectors and snapshotting.
-pub trait AttrSelectorHelpers {
+pub trait NamespaceConstraintHelpers {
/// Returns the namespace of the selector, or null otherwise.
- fn ns_or_null(&self) -> *mut nsIAtom;
- /// Returns the proper selector name depending on whether the requesting
- /// element is an HTML element in an HTML document or not.
- fn select_name(&self, is_html_element_in_html_document: bool) -> *mut nsIAtom;
+ fn atom_or_null(&self) -> *mut nsIAtom;
}
-impl AttrSelectorHelpers for AttrSelector<SelectorImpl> {
- fn ns_or_null(&self) -> *mut nsIAtom {
- match self.namespace {
+impl<'a> NamespaceConstraintHelpers for NamespaceConstraint<&'a Namespace> {
+ fn atom_or_null(&self) -> *mut nsIAtom {
+ match *self {
NamespaceConstraint::Any => ptr::null_mut(),
- NamespaceConstraint::Specific(ref ns) => ns.url.0.as_ptr(),
- }
- }
-
- fn select_name(&self, is_html_element_in_html_document: bool) -> *mut nsIAtom {
- if is_html_element_in_html_document {
- self.lower_name.as_ptr()
- } else {
- self.name.as_ptr()
- }
- }
-}
-
-impl<'le> ::selectors::MatchAttr for GeckoElement<'le> {
- type Impl = SelectorImpl;
-
- fn match_attr_has(&self, attr: &AttrSelector<Self::Impl>) -> bool {
- unsafe {
- bindings::Gecko_HasAttr(self.0,
- attr.ns_or_null(),
- attr.select_name(self.is_html_element_in_html_document()))
- }
- }
- fn match_attr_equals(&self, attr: &AttrSelector<Self::Impl>, value: &Atom) -> bool {
- unsafe {
- bindings::Gecko_AttrEquals(self.0,
- attr.ns_or_null(),
- attr.select_name(self.is_html_element_in_html_document()),
- value.as_ptr(),
- /* ignoreCase = */ false)
- }
- }
- fn match_attr_equals_ignore_ascii_case(&self, attr: &AttrSelector<Self::Impl>, value: &Atom) -> bool {
- unsafe {
- bindings::Gecko_AttrEquals(self.0,
- attr.ns_or_null(),
- attr.select_name(self.is_html_element_in_html_document()),
- value.as_ptr(),
- /* ignoreCase = */ false)
- }
- }
- fn match_attr_includes(&self, attr: &AttrSelector<Self::Impl>, value: &Atom) -> bool {
- unsafe {
- bindings::Gecko_AttrIncludes(self.0,
- attr.ns_or_null(),
- attr.select_name(self.is_html_element_in_html_document()),
- value.as_ptr())
- }
- }
- fn match_attr_dash(&self, attr: &AttrSelector<Self::Impl>, value: &Atom) -> bool {
- unsafe {
- bindings::Gecko_AttrDashEquals(self.0,
- attr.ns_or_null(),
- attr.select_name(self.is_html_element_in_html_document()),
- value.as_ptr())
- }
- }
- fn match_attr_prefix(&self, attr: &AttrSelector<Self::Impl>, value: &Atom) -> bool {
- unsafe {
- bindings::Gecko_AttrHasPrefix(self.0,
- attr.ns_or_null(),
- attr.select_name(self.is_html_element_in_html_document()),
- value.as_ptr())
- }
- }
- fn match_attr_substring(&self, attr: &AttrSelector<Self::Impl>, value: &Atom) -> bool {
- unsafe {
- bindings::Gecko_AttrHasSubstring(self.0,
- attr.ns_or_null(),
- attr.select_name(self.is_html_element_in_html_document()),
- value.as_ptr())
- }
- }
- fn match_attr_suffix(&self, attr: &AttrSelector<Self::Impl>, value: &Atom) -> bool {
- unsafe {
- bindings::Gecko_AttrHasSuffix(self.0,
- attr.ns_or_null(),
- attr.select_name(self.is_html_element_in_html_document()),
- value.as_ptr())
+ NamespaceConstraint::Specific(ref ns) => ns.0.as_ptr(),
}
}
}
@@ -1375,8 +1420,9 @@ impl<'le> ::selectors::MatchAttr for GeckoElement<'le> {
impl<'le> ElementExt for GeckoElement<'le> {
#[inline]
fn is_link(&self) -> bool {
+ let mut context = MatchingContext::new(MatchingMode::Normal, None);
self.match_non_ts_pseudo_class(&NonTSPseudoClass::AnyLink,
- &mut StyleRelations::empty(),
+ &mut context,
&mut |_, _| {})
}
diff --git a/components/style/lib.rs b/components/style/lib.rs
index 91c8727a2e7..4210304217f 100644
--- a/components/style/lib.rs
+++ b/components/style/lib.rs
@@ -50,6 +50,7 @@ extern crate fnv;
#[cfg(feature = "gecko")] #[macro_use] pub mod gecko_string_cache;
#[cfg(feature = "servo")] extern crate heapsize;
#[cfg(feature = "servo")] #[macro_use] extern crate heapsize_derive;
+extern crate itoa;
#[cfg(feature = "servo")] #[macro_use] extern crate html5ever;
#[macro_use]
extern crate lazy_static;
diff --git a/components/style/matching.rs b/components/style/matching.rs
index 764f58ec080..289a6fb1975 100644
--- a/components/style/matching.rs
+++ b/components/style/matching.rs
@@ -15,7 +15,6 @@ use cascade_info::CascadeInfo;
use context::{CurrentElementInfo, SelectorFlagsMap, SharedStyleContext, StyleContext};
use data::{ComputedStyle, ElementData, ElementStyles, RestyleData};
use dom::{AnimationRules, SendElement, TElement, TNode};
-use element_state::ElementState;
use font_metrics::FontMetricsProvider;
use properties::{CascadeFlags, ComputedValues, SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP, cascade};
use properties::longhands::display::computed_value as display;
@@ -24,7 +23,7 @@ use restyle_hints::{RESTYLE_STYLE_ATTRIBUTE, RESTYLE_SMIL};
use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode};
use selector_parser::{PseudoElement, RestyleDamage, SelectorImpl};
use selectors::bloom::BloomFilter;
-use selectors::matching::{ElementSelectorFlags, StyleRelations};
+use selectors::matching::{ElementSelectorFlags, MatchingContext, MatchingMode, StyleRelations};
use selectors::matching::AFFECTED_BY_PSEUDO_ELEMENTS;
use shared_lock::StylesheetGuards;
use sink::ForgetfulSink;
@@ -497,6 +496,27 @@ trait PrivateMatchMethods: TElement {
primary_style: &ComputedStyle,
eager_pseudo_style: Option<&ComputedStyle>)
-> Arc<ComputedValues> {
+ if let Some(pseudo) = self.implemented_pseudo_element() {
+ debug_assert!(eager_pseudo_style.is_none());
+
+ // This is an element-backed pseudo, just grab the styles from the
+ // parent if it's eager, and recascade otherwise.
+ //
+ // We also recascade if the eager pseudo-style has any animation
+ // rules, because we don't cascade those during the eager traversal.
+ //
+ // We could make that a bit better if the complexity cost is not too
+ // big, but given further restyles are posted directly to
+ // pseudo-elements, it doesn't seem worth the effort at a glance.
+ if pseudo.is_eager() && self.get_animation_rules().is_empty() {
+ let parent = self.parent_element().unwrap();
+ let parent_data = parent.borrow_data().unwrap();
+ let pseudo_style =
+ parent_data.styles().pseudos.get(&pseudo).unwrap();
+ return pseudo_style.values().clone()
+ }
+ }
+
// Grab the rule node.
let rule_node = &eager_pseudo_style.unwrap_or(primary_style).rules;
let inherit_mode = if eager_pseudo_style.is_some() {
@@ -514,97 +534,66 @@ trait PrivateMatchMethods: TElement {
/// Computes values and damage for the primary or pseudo style of an element,
/// setting them on the ElementData.
- fn cascade_primary_or_pseudo(&self,
- context: &mut StyleContext<Self>,
- data: &mut ElementData,
- pseudo: Option<&PseudoElement>) {
- debug_assert!(pseudo.is_none() || self.implemented_pseudo_element().is_none(),
- "Pseudo-element-implementing elements can't have pseudos!");
+ fn cascade_primary(&self,
+ context: &mut StyleContext<Self>,
+ data: &mut ElementData) {
// Collect some values.
let (mut styles, restyle) = data.styles_and_restyle_mut();
let mut primary_style = &mut styles.primary;
- let pseudos = &mut styles.pseudos;
- let mut pseudo_style = match pseudo {
- Some(p) => {
- let style = pseudos.get_mut(p);
- debug_assert!(style.is_some());
- style
- }
- None => None,
- };
-
- let mut old_values = match pseudo_style {
- Some(ref mut s) => s.values.take(),
- None => primary_style.values.take(),
- };
+ let mut old_values = primary_style.values.take();
// Compute the new values.
- let mut new_values = match self.implemented_pseudo_element() {
- Some(ref pseudo) => {
- // This is an element-backed pseudo, just grab the styles from
- // the parent if it's eager, and recascade otherwise.
- //
- // We also recascade if the eager pseudo-style has any animation
- // rules, because we don't cascade those during the eager
- // traversal. We could make that a bit better if the complexity
- // cost is not too big, but given further restyles are posted
- // directly to pseudo-elements, it doesn't seem worth the effort
- // at a glance.
- if pseudo.is_eager() &&
- self.get_animation_rules().is_empty() {
- let parent = self.parent_element().unwrap();
-
- let parent_data = parent.borrow_data().unwrap();
- let pseudo_style =
- parent_data.styles().pseudos.get(pseudo).unwrap();
- pseudo_style.values().clone()
- } else {
- self.cascade_internal(context,
- primary_style,
- None)
- }
- }
- None => {
- // Else it's an eager pseudo or a normal element, do the cascade
- // work.
- self.cascade_internal(context,
- primary_style,
- pseudo_style.as_ref().map(|s| &**s))
- }
- };
+ let mut new_values = self.cascade_internal(context, primary_style, None);
// NB: Animations for pseudo-elements in Gecko are handled while
// traversing the pseudo-elements themselves.
- if pseudo.is_none() &&
- !context.shared.traversal_flags.for_animation_only() {
+ if !context.shared.traversal_flags.for_animation_only() {
self.process_animations(context,
&mut old_values,
&mut new_values,
primary_style);
}
- // Accumulate restyle damage.
+ if let Some(old) = old_values {
+ self.accumulate_damage(&context.shared,
+ restyle.unwrap(),
+ &old,
+ &new_values,
+ None);
+ }
+
+ // Set the new computed values.
+ primary_style.values = Some(new_values);
+ }
+
+ fn cascade_eager_pseudo(&self,
+ context: &mut StyleContext<Self>,
+ data: &mut ElementData,
+ pseudo: &PseudoElement) {
+ debug_assert!(pseudo.is_eager());
+ let (mut styles, restyle) = data.styles_and_restyle_mut();
+ let mut pseudo_style = styles.pseudos.get_mut(pseudo).unwrap();
+ let old_values = pseudo_style.values.take();
+
+ let new_values =
+ self.cascade_internal(context, &styles.primary, Some(pseudo_style));
+
if let Some(old) = old_values {
// ::before and ::after are element-backed in Gecko, so they do
// the damage calculation for themselves.
- //
- // FIXME(emilio): We have more element-backed stuff, and this is
- // redundant for them right now.
- if cfg!(feature = "servo") ||
- pseudo.map_or(true, |p| !p.is_before_or_after()) {
+ if cfg!(feature = "servo") || !pseudo.is_before_or_after() {
self.accumulate_damage(&context.shared,
restyle.unwrap(),
&old,
&new_values,
- pseudo);
+ Some(pseudo));
}
}
- // Set the new computed values.
- let mut relevant_style = pseudo_style.unwrap_or(primary_style);
- relevant_style.values = Some(new_values);
+ pseudo_style.values = Some(new_values)
}
+
/// get_after_change_style removes the transition rules from the ComputedValues.
/// If there is no transition rule in the ComputedValues, it returns None.
#[cfg(feature = "gecko")]
@@ -754,15 +743,11 @@ trait PrivateMatchMethods: TElement {
}
/// Computes and applies non-redundant damage.
- ///
- /// FIXME(emilio): Damage for non-::before and non-::after element-backed
- /// pseudo-elements should be refactored to go on themselves (right now they
- /// do, but we apply this twice).
#[cfg(feature = "gecko")]
fn accumulate_damage(&self,
shared_context: &SharedStyleContext,
restyle: &mut RestyleData,
- old_values: &Arc<ComputedValues>,
+ old_values: &ComputedValues,
new_values: &Arc<ComputedValues>,
pseudo: Option<&PseudoElement>) {
// Don't accumulate damage if we're in a restyle for reconstruction.
@@ -798,12 +783,12 @@ trait PrivateMatchMethods: TElement {
fn accumulate_damage(&self,
_shared_context: &SharedStyleContext,
restyle: &mut RestyleData,
- old_values: &Arc<ComputedValues>,
+ old_values: &ComputedValues,
new_values: &Arc<ComputedValues>,
pseudo: Option<&PseudoElement>) {
if restyle.damage != RestyleDamage::rebuild_and_reflow() {
- let d = self.compute_restyle_damage(&old_values, &new_values, pseudo);
- restyle.damage |= d;
+ restyle.damage |=
+ self.compute_restyle_damage(&old_values, &new_values, pseudo);
}
}
@@ -895,8 +880,10 @@ pub trait MatchMethods : TElement {
sharing: StyleSharingBehavior)
{
// Perform selector matching for the primary style.
- let mut primary_relations = StyleRelations::empty();
- let _rule_node_changed = self.match_primary(context, data, &mut primary_relations);
+ let mut relations = StyleRelations::empty();
+ let _rule_node_changed = self.match_primary(context,
+ data,
+ &mut relations);
// Cascade properties and compute primary values.
self.cascade_primary(context, data);
@@ -910,7 +897,7 @@ pub trait MatchMethods : TElement {
// If we have any pseudo elements, indicate so in the primary StyleRelations.
if !data.styles().pseudos.is_empty() {
- primary_relations |= AFFECTED_BY_PSEUDO_ELEMENTS;
+ relations |= AFFECTED_BY_PSEUDO_ELEMENTS;
}
// If the style is shareable, add it to the LRU cache.
@@ -930,7 +917,7 @@ pub trait MatchMethods : TElement {
.style_sharing_candidate_cache
.insert_if_possible(self,
data.styles().primary.values(),
- primary_relations,
+ relations,
revalidation_match_results);
}
}
@@ -1002,33 +989,26 @@ pub trait MatchMethods : TElement {
let animation_rules = self.get_animation_rules();
let bloom = context.thread_local.bloom_filter.filter();
+
let map = &mut context.thread_local.selector_flags;
let mut set_selector_flags = |element: &Self, flags: ElementSelectorFlags| {
self.apply_selector_flags(map, element, flags);
};
- let selector_matching_target = match implemented_pseudo {
- Some(..) => {
- self.closest_non_native_anonymous_ancestor()
- .expect("Pseudo-element without non-NAC parent?")
- },
- None => *self,
- };
-
- let pseudo_and_state = match implemented_pseudo {
- Some(ref pseudo) => Some((pseudo, self.get_state())),
- None => None,
- };
+ let mut matching_context =
+ MatchingContext::new(MatchingMode::Normal, Some(bloom));
// Compute the primary rule node.
- *relations = stylist.push_applicable_declarations(&selector_matching_target,
- Some(bloom),
- style_attribute,
- smil_override,
- animation_rules,
- pseudo_and_state,
- &mut applicable_declarations,
- &mut set_selector_flags);
+ stylist.push_applicable_declarations(self,
+ implemented_pseudo.as_ref(),
+ style_attribute,
+ smil_override,
+ animation_rules,
+ &mut applicable_declarations,
+ &mut matching_context,
+ &mut set_selector_flags);
+
+ *relations = matching_context.relations;
let primary_rule_node =
compute_rule_node::<Self>(&stylist.rule_tree,
@@ -1038,8 +1018,8 @@ pub trait MatchMethods : TElement {
return data.set_primary_rules(primary_rule_node);
}
- /// Runs selector matching to (re)compute eager pseudo-element rule nodes for this
- /// element.
+ /// Runs selector matching to (re)compute eager pseudo-element rule nodes
+ /// for this element.
///
/// Returns whether any of the pseudo rule nodes changed (including, but not
/// limited to, cases where we match different pseudos altogether).
@@ -1067,6 +1047,10 @@ pub trait MatchMethods : TElement {
let rule_tree = &stylist.rule_tree;
let bloom_filter = context.thread_local.bloom_filter.filter();
+ let mut matching_context =
+ MatchingContext::new(MatchingMode::ForStatelessPseudoElement,
+ Some(bloom_filter));
+
// Compute rule nodes for eagerly-cascaded pseudo-elements.
let mut matches_different_pseudos = false;
let mut rule_nodes_changed = false;
@@ -1076,12 +1060,12 @@ pub trait MatchMethods : TElement {
// NB: We handle animation rules for ::before and ::after when
// traversing them.
stylist.push_applicable_declarations(self,
- Some(bloom_filter),
+ Some(&pseudo),
None,
None,
AnimationRules(None, None),
- Some((&pseudo, ElementState::empty())),
&mut applicable_declarations,
+ &mut matching_context,
&mut set_selector_flags);
if !applicable_declarations.is_empty() {
@@ -1396,7 +1380,7 @@ pub trait MatchMethods : TElement {
/// pseudo-element, compute the restyle damage used to determine which
/// kind of layout or painting operations we'll need.
fn compute_restyle_damage(&self,
- old_values: &Arc<ComputedValues>,
+ old_values: &ComputedValues,
new_values: &Arc<ComputedValues>,
pseudo: Option<&PseudoElement>)
-> RestyleDamage
@@ -1420,15 +1404,7 @@ pub trait MatchMethods : TElement {
}
}
- /// Performs the cascade for the element's primary style.
- fn cascade_primary(&self,
- context: &mut StyleContext<Self>,
- mut data: &mut ElementData)
- {
- self.cascade_primary_or_pseudo(context, &mut data, None);
- }
-
- /// Performs the cascade for the element's eager pseudos.
+ /// Cascade the eager pseudo-elements of this element.
fn cascade_pseudos(&self,
context: &mut StyleContext<Self>,
mut data: &mut ElementData)
@@ -1440,7 +1416,7 @@ pub trait MatchMethods : TElement {
// let us pass the mutable |data| to the cascade function.
let matched_pseudos = data.styles().pseudos.keys();
for pseudo in matched_pseudos {
- self.cascade_primary_or_pseudo(context, data, Some(&pseudo));
+ self.cascade_eager_pseudo(context, data, &pseudo);
}
}
diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs
index 6e35cdaf9f3..4fd410c161f 100644
--- a/components/style/properties/gecko.mako.rs
+++ b/components/style/properties/gecko.mako.rs
@@ -1053,7 +1053,7 @@ fn static_assert() {
skip_longhands="${skip_position_longhands} z-index box-sizing order align-content
justify-content align-self justify-self align-items
justify-items grid-auto-rows grid-auto-columns grid-auto-flow
- grid-template-areas">
+ grid-template-areas grid-template-rows grid-template-columns">
% for side in SIDES:
<% impl_split_style_coord("%s" % side.ident,
"mOffset",
@@ -1165,9 +1165,9 @@ fn static_assert() {
let ident = v.ident.unwrap_or(String::new());
self.gecko.${value.gecko}.mLineName.assign_utf8(&ident);
self.gecko.${value.gecko}.mHasSpan = v.is_span;
- self.gecko.${value.gecko}.mInteger = v.integer.map(|i| {
+ self.gecko.${value.gecko}.mInteger = v.line_num.map(|i| {
// clamping the integer between a range
- cmp::max(nsStyleGridLine_kMinLine, cmp::min(i, nsStyleGridLine_kMaxLine))
+ cmp::max(nsStyleGridLine_kMinLine, cmp::min(i.value(), nsStyleGridLine_kMaxLine))
}).unwrap_or(0);
}
@@ -1179,7 +1179,7 @@ fn static_assert() {
% endfor
% for kind in ["rows", "columns"]:
- pub fn set_grid_auto_${kind}(&mut self, v: longhands::grid_auto_rows::computed_value::T) {
+ pub fn set_grid_auto_${kind}(&mut self, v: longhands::grid_auto_${kind}::computed_value::T) {
use values::specified::grid::TrackSize;
match v {
@@ -1206,6 +1206,136 @@ fn static_assert() {
self.gecko.mGridAuto${kind.title()}Min.copy_from(&other.gecko.mGridAuto${kind.title()}Min);
self.gecko.mGridAuto${kind.title()}Max.copy_from(&other.gecko.mGridAuto${kind.title()}Max);
}
+
+ pub fn set_grid_template_${kind}(&mut self, v: longhands::grid_template_${kind}::computed_value::T) {
+ <% self_grid = "self.gecko.mGridTemplate%s" % kind.title() %>
+ use gecko::values::GeckoStyleCoordConvertible;
+ use gecko_bindings::structs::{nsTArray, nsStyleGridLine_kMaxLine};
+ use nsstring::{nsCString, nsStringRepr};
+ use std::usize;
+ use values::specified::grid::TrackListType::Auto;
+ use values::specified::grid::{RepeatCount, TrackSize};
+
+ #[inline]
+ fn set_bitfield(bitfield: &mut u8, pos: u8, val: bool) {
+ let mask = 1 << (pos - 1);
+ *bitfield &= !mask;
+ *bitfield |= (val as u8) << (pos - 1);
+ }
+
+ #[inline]
+ fn set_line_names(servo_names: &[String], gecko_names: &mut nsTArray<nsStringRepr>) {
+ unsafe {
+ bindings::Gecko_ResizeTArrayForStrings(gecko_names, servo_names.len() as u32);
+ }
+
+ for (servo_name, gecko_name) in servo_names.iter().zip(gecko_names.iter_mut()) {
+ gecko_name.assign_utf8(&nsCString::from(&*servo_name));
+ }
+ }
+
+ fn set_track_size<G, T>(value: TrackSize<T>, gecko_min: &mut G, gecko_max: &mut G)
+ where G: CoordDataMut, T: GeckoStyleCoordConvertible
+ {
+ match value {
+ TrackSize::FitContent(lop) => {
+ gecko_min.set_value(CoordDataValue::None);
+ lop.to_gecko_style_coord(gecko_max);
+ },
+ TrackSize::Breadth(breadth) => {
+ breadth.to_gecko_style_coord(gecko_min);
+ breadth.to_gecko_style_coord(gecko_max);
+ },
+ TrackSize::MinMax(min, max) => {
+ min.to_gecko_style_coord(gecko_min);
+ max.to_gecko_style_coord(gecko_max);
+ },
+ }
+ }
+
+ // Set defaults
+ ${self_grid}.mRepeatAutoIndex = -1;
+ set_bitfield(&mut ${self_grid}._bitfield_1, 1, false); // mIsAutoFill
+ set_bitfield(&mut ${self_grid}._bitfield_1, 2, false); // mIsSubgrid
+ // FIXME: mIsSubgrid is false only for <none>, but we don't support subgrid name lists at the moment.
+
+ match v {
+ Either::First(track) => {
+ let mut auto_idx = usize::MAX;
+ let mut auto_track_size = None;
+ if let Auto(idx) = track.list_type {
+ auto_idx = idx as usize;
+ let auto_repeat = track.auto_repeat.as_ref().expect("expected <auto-track-repeat> value");
+
+ if auto_repeat.count == RepeatCount::AutoFill {
+ set_bitfield(&mut ${self_grid}._bitfield_1, 1, true);
+ }
+
+ ${self_grid}.mRepeatAutoIndex = idx as i16;
+ // NOTE: Gecko supports only one set of values in <auto-repeat>
+ // i.e., it can only take repeat(auto-fill, [a] 10px [b]), and no more.
+ set_line_names(&auto_repeat.line_names[0], &mut ${self_grid}.mRepeatAutoLineNameListBefore);
+ set_line_names(&auto_repeat.line_names[1], &mut ${self_grid}.mRepeatAutoLineNameListAfter);
+ auto_track_size = Some(auto_repeat.track_sizes.get(0).unwrap().clone());
+ } else {
+ unsafe {
+ bindings::Gecko_ResizeTArrayForStrings(
+ &mut ${self_grid}.mRepeatAutoLineNameListBefore, 0);
+ bindings::Gecko_ResizeTArrayForStrings(
+ &mut ${self_grid}.mRepeatAutoLineNameListAfter, 0);
+ }
+ }
+
+ let mut num_values = track.values.len();
+ if auto_track_size.is_some() {
+ num_values += 1;
+ }
+
+ let max_lines = nsStyleGridLine_kMaxLine as usize - 1; // for accounting the final <line-names>
+ num_values = cmp::min(num_values, max_lines);
+ unsafe {
+ bindings::Gecko_SetStyleGridTemplateArrayLengths(&mut ${self_grid}, num_values as u32);
+ }
+
+ let mut line_names = track.line_names.into_iter();
+ let mut values_iter = track.values.into_iter();
+ let min_max_iter = ${self_grid}.mMinTrackSizingFunctions.iter_mut()
+ .zip(${self_grid}.mMaxTrackSizingFunctions.iter_mut());
+
+ for (i, (gecko_min, gecko_max)) in min_max_iter.enumerate().take(max_lines) {
+ let name_list = line_names.next().expect("expected line-names");
+ set_line_names(&name_list, &mut ${self_grid}.mLineNameLists[i]);
+ if i == auto_idx {
+ set_track_size(auto_track_size.take().expect("expected <track-size> for <auto-track-repeat>"),
+ gecko_min, gecko_max);
+ continue
+ }
+
+ let track_size = values_iter.next().expect("expected <track-size> value");
+ set_track_size(track_size, gecko_min, gecko_max);
+ }
+
+ let final_names = line_names.next().unwrap();
+ set_line_names(&final_names, ${self_grid}.mLineNameLists.last_mut().unwrap());
+ },
+ Either::Second(_none) => {
+ unsafe {
+ bindings::Gecko_SetStyleGridTemplateArrayLengths(&mut ${self_grid}, 0);
+ bindings::Gecko_ResizeTArrayForStrings(
+ &mut ${self_grid}.mRepeatAutoLineNameListBefore, 0);
+ bindings::Gecko_ResizeTArrayForStrings(
+ &mut ${self_grid}.mRepeatAutoLineNameListAfter, 0);
+ }
+ },
+ }
+ }
+
+ pub fn copy_grid_template_${kind}_from(&mut self, other: &Self) {
+ unsafe {
+ bindings::Gecko_CopyStyleGridTemplateValues(&mut ${self_grid},
+ &other.gecko.mGridTemplate${kind.title()});
+ }
+ }
% endfor
pub fn set_grid_auto_flow(&mut self, v: longhands::grid_auto_flow::computed_value::T) {
@@ -2850,9 +2980,21 @@ fn static_assert() {
pub fn copy_${shorthand}_image_from(&mut self, other: &Self) {
+ use gecko_bindings::structs::nsStyleImageLayers_LayerType as LayerType;
unsafe {
- Gecko_CopyImageValueFrom(&mut self.gecko.${image_layers_field}.mLayers.mFirstElement.mImage,
- &other.gecko.${image_layers_field}.mLayers.mFirstElement.mImage);
+ let count = other.gecko.${image_layers_field}.mImageCount;
+ unsafe {
+ Gecko_EnsureImageLayersLength(&mut self.gecko.${image_layers_field},
+ count as usize,
+ LayerType::${shorthand.capitalize()});
+ }
+
+ for (layer, other) in self.gecko.${image_layers_field}.mLayers.iter_mut()
+ .zip(other.gecko.${image_layers_field}.mLayers.iter())
+ .take(count as usize) {
+ Gecko_CopyImageValueFrom(&mut layer.mImage, &other.mImage);
+ }
+ self.gecko.${image_layers_field}.mImageCount = count;
}
}
@@ -3626,9 +3768,7 @@ fn static_assert() {
}
self.clear_overflow_sides_if_string();
- if v.second.is_none() {
- self.gecko.mTextOverflow.mLogicalDirections = true;
- }
+ self.gecko.mTextOverflow.mLogicalDirections = v.second.is_none();
let SpecifiedValue { ref first, ref second } = v;
let second = second.as_ref().unwrap_or(&first);
diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs
index e23b4877e56..071454dd2ba 100644
--- a/components/style/properties/helpers/animated_properties.mako.rs
+++ b/components/style/properties/helpers/animated_properties.mako.rs
@@ -1035,11 +1035,9 @@ impl Animatable for CalcLengthOrPercentage {
}
}
- Ok(CalcLengthOrPercentage {
- length: try!(self.length.add_weighted(&other.length, self_portion, other_portion)),
- percentage: try!(add_weighted_half(self.percentage, other.percentage,
- self_portion, other_portion)),
- })
+ let length = self.unclamped_length().add_weighted(&other.unclamped_length(), self_portion, other_portion)?;
+ let percentage = add_weighted_half(self.percentage, other.percentage, self_portion, other_portion)?;
+ Ok(CalcLengthOrPercentage::with_clamping_mode(length, percentage, self.clamping_mode))
}
#[inline]
@@ -1049,7 +1047,7 @@ impl Animatable for CalcLengthOrPercentage {
#[inline]
fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> {
- let length_diff = (self.length().0 - other.length().0) as f64;
+ let length_diff = (self.unclamped_length().0 - other.unclamped_length().0) as f64;
let percentage_diff = (self.percentage() - other.percentage()) as f64;
Ok(length_diff * length_diff + percentage_diff * percentage_diff)
}
@@ -1114,7 +1112,7 @@ impl Animatable for LengthOrPercentage {
(this, other) => {
let this: CalcLengthOrPercentage = From::from(this);
let other: CalcLengthOrPercentage = From::from(other);
- let length_diff = (this.length().0 - other.length().0) as f64;
+ let length_diff = (this.unclamped_length().0 - other.unclamped_length().0) as f64;
let percentage_diff = (this.percentage() - other.percentage()) as f64;
Ok(length_diff * length_diff + percentage_diff * percentage_diff)
}
@@ -1187,12 +1185,12 @@ impl Animatable for LengthOrPercentageOrAuto {
(this, other) => {
let this: Option<CalcLengthOrPercentage> = From::from(this);
let other: Option<CalcLengthOrPercentage> = From::from(other);
- if this.is_none() || other.is_none() {
- Err(())
- } else {
- let length_diff = (this.unwrap().length().0 - other.unwrap().length().0) as f64;
- let percentage_diff = (this.unwrap().percentage() - other.unwrap().percentage()) as f64;
+ if let (Some(this), Some(other)) = (this, other) {
+ let length_diff = (this.unclamped_length().0 - other.unclamped_length().0) as f64;
+ let percentage_diff = (this.percentage() - other.percentage()) as f64;
Ok(length_diff * length_diff + percentage_diff * percentage_diff)
+ } else {
+ Err(())
}
}
}
diff --git a/components/style/properties/longhand/background.mako.rs b/components/style/properties/longhand/background.mako.rs
index e5c3d628f64..3b41a5714cf 100644
--- a/components/style/properties/longhand/background.mako.rs
+++ b/components/style/properties/longhand/background.mako.rs
@@ -10,7 +10,9 @@ ${helpers.predefined_type("background-color", "CSSColor",
"::cssparser::Color::RGBA(::cssparser::RGBA::transparent())",
initial_specified_value="SpecifiedValue::transparent()",
spec="https://drafts.csswg.org/css-backgrounds/#background-color",
- animation_value_type="IntermediateColor", complex_color=True)}
+ animation_value_type="IntermediateColor",
+ complex_color=True,
+ allow_quirks=True)}
${helpers.predefined_type("background-image", "ImageLayer",
initial_value="Either::First(None_)",
diff --git a/components/style/properties/longhand/border.mako.rs b/components/style/properties/longhand/border.mako.rs
index f18ae154428..e5270e30fb9 100644
--- a/components/style/properties/longhand/border.mako.rs
+++ b/components/style/properties/longhand/border.mako.rs
@@ -20,7 +20,9 @@
"::cssparser::Color::CurrentColor",
alias=maybe_moz_logical_alias(product, side, "-moz-border-%s-color"),
spec=maybe_logical_spec(side, "color"),
- animation_value_type="IntermediateColor", logical = side[1])}
+ animation_value_type="IntermediateColor",
+ logical=side[1],
+ allow_quirks=not side[1])}
${helpers.predefined_type("border-%s-style" % side[0], "BorderStyle",
"specified::BorderStyle::none",
diff --git a/components/style/properties/longhand/color.mako.rs b/components/style/properties/longhand/color.mako.rs
index 0a5dd2f8d63..e4c3ef4b1fb 100644
--- a/components/style/properties/longhand/color.mako.rs
+++ b/components/style/properties/longhand/color.mako.rs
@@ -14,7 +14,7 @@
use cssparser::RGBA;
use std::fmt;
use style_traits::ToCss;
- use values::specified::{Color, CSSColor, CSSRGBA};
+ use values::specified::{AllowQuirks, Color, CSSColor, CSSRGBA};
impl ToComputedValue for SpecifiedValue {
type ComputedValue = computed_value::T;
@@ -50,7 +50,7 @@
RGBA::new(0, 0, 0, 255) // black
}
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
- CSSColor::parse(context, input).map(SpecifiedValue)
+ CSSColor::parse_quirky(context, input, AllowQuirks::Yes).map(SpecifiedValue)
}
// FIXME(#15973): Add servo support for system colors
diff --git a/components/style/properties/longhand/font.mako.rs b/components/style/properties/longhand/font.mako.rs
index aed5221e4b6..9d2ec4215d4 100644
--- a/components/style/properties/longhand/font.mako.rs
+++ b/components/style/properties/longhand/font.mako.rs
@@ -800,8 +800,7 @@ ${helpers.single_keyword_system("font-variant-caps",
}
SpecifiedValue::Length(LengthOrPercentage::Calc(ref calc)) => {
let calc = calc.to_computed_value(context);
- calc.length() + base_size.resolve(context)
- .scale_by(calc.percentage())
+ calc.to_used_value(Some(base_size.resolve(context))).unwrap()
}
SpecifiedValue::Keyword(ref key, fraction) => {
key.to_computed_value(context).scale_by(fraction)
diff --git a/components/style/properties/longhand/inherited_text.mako.rs b/components/style/properties/longhand/inherited_text.mako.rs
index b2d57a72393..a1f6dfc0418 100644
--- a/components/style/properties/longhand/inherited_text.mako.rs
+++ b/components/style/properties/longhand/inherited_text.mako.rs
@@ -132,7 +132,8 @@
let calc = calc.to_computed_value(context);
let fr = specified::FontRelativeLength::Em(calc.percentage());
let fr = specified::Length::NoCalc(specified::NoCalcLength::FontRelative(fr));
- computed_value::T::Length(calc.length() + fr.to_computed_value(context))
+ let length = calc.unclamped_length();
+ computed_value::T::Length(calc.clamping_mode.clamp(length + fr.to_computed_value(context)))
}
}
}
diff --git a/components/style/properties/longhand/position.mako.rs b/components/style/properties/longhand/position.mako.rs
index 370a538e893..0cea82301cc 100644
--- a/components/style/properties/longhand/position.mako.rs
+++ b/components/style/properties/longhand/position.mako.rs
@@ -319,6 +319,17 @@ ${helpers.predefined_type("object-position",
spec="https://drafts.csswg.org/css-grid/#propdef-grid-auto-%ss" % kind,
products="gecko",
boxed=True)}
+
+ // NOTE: The spec lists only `none | <track-list> | <auto-track-list>`, but gecko seems to support
+ // `subgrid <line-name-list>?` in addition to this (probably old spec). We should support it soon.
+ ${helpers.predefined_type("grid-template-%ss" % kind,
+ "TrackListOrNone",
+ "Either::Second(None_)",
+ products="gecko",
+ spec="https://drafts.csswg.org/css-grid/#propdef-grid-template-%ss" % kind,
+ boxed=True,
+ animation_value_type="none")}
+
% endfor
<%helpers:longhand name="grid-auto-flow"
diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs
index 79505e92657..1f5c951d1f4 100644
--- a/components/style/properties/properties.mako.rs
+++ b/components/style/properties/properties.mako.rs
@@ -1954,33 +1954,30 @@ impl ComputedValues {
))
}
- /// https://drafts.csswg.org/css-transforms/#grouping-property-values
- pub fn get_used_transform_style(&self) -> computed_values::transform_style::T {
+ /// Return true if the effects force the transform style to be Flat
+ pub fn overrides_transform_style(&self) -> bool {
use computed_values::mix_blend_mode;
- use computed_values::transform_style;
let effects = self.get_effects();
- let box_ = self.get_box();
-
// TODO(gw): Add clip-path, isolation, mask-image, mask-border-source when supported.
- if effects.opacity < 1.0 ||
+ effects.opacity < 1.0 ||
!effects.filter.is_empty() ||
- !effects.clip.is_auto() {
- effects.mix_blend_mode != mix_blend_mode::T::normal ||
- return transform_style::T::flat;
- }
+ !effects.clip.is_auto() ||
+ effects.mix_blend_mode != mix_blend_mode::T::normal
+ }
- if box_.transform_style == transform_style::T::auto {
- if box_.transform.0.is_some() {
- return transform_style::T::flat;
- }
- if let Either::First(ref _length) = box_.perspective {
- return transform_style::T::flat;
- }
- }
+ /// https://drafts.csswg.org/css-transforms/#grouping-property-values
+ pub fn get_used_transform_style(&self) -> computed_values::transform_style::T {
+ use computed_values::transform_style;
- // Return the computed value if not overridden by the above exceptions
- box_.transform_style
+ let box_ = self.get_box();
+
+ if self.overrides_transform_style() {
+ transform_style::T::flat
+ } else {
+ // Return the computed value if not overridden by the above exceptions
+ box_.transform_style
+ }
}
/// Whether given this transform value, the compositor would require a
diff --git a/components/style/properties/shorthand/background.mako.rs b/components/style/properties/shorthand/background.mako.rs
index 7732a84ff73..89874f82084 100644
--- a/components/style/properties/shorthand/background.mako.rs
+++ b/components/style/properties/shorthand/background.mako.rs
@@ -10,12 +10,12 @@
background-attachment background-image background-size background-origin
background-clip"
spec="https://drafts.csswg.org/css-backgrounds/#the-background">
- use properties::longhands::{background_color, background_position_x, background_position_y, background_repeat};
+ use properties::longhands::{background_position_x, background_position_y, background_repeat};
use properties::longhands::{background_attachment, background_image, background_size, background_origin};
use properties::longhands::background_clip;
use properties::longhands::background_clip::single_value::computed_value::T as Clip;
use properties::longhands::background_origin::single_value::computed_value::T as Origin;
- use values::specified::{Position, PositionComponent};
+ use values::specified::{CSSColor, Position, PositionComponent};
use parser::Parse;
impl From<background_origin::single_value::SpecifiedValue> for background_clip::single_value::SpecifiedValue {
@@ -43,7 +43,7 @@
let mut ${name} = None;
% endfor
loop {
- if let Ok(value) = input.try(|input| background_color::parse(context, input)) {
+ if let Ok(value) = input.try(|i| CSSColor::parse(context, i)) {
if background_color.is_none() {
background_color = Some(value);
continue
@@ -109,7 +109,7 @@
}));
Ok(Longhands {
- background_color: unwrap_or_initial!(background_color),
+ background_color: background_color.unwrap_or(CSSColor::transparent()),
background_image: background_image,
background_position_x: background_position_x,
background_position_y: background_position_y,
diff --git a/components/style/properties/shorthand/position.mako.rs b/components/style/properties/shorthand/position.mako.rs
index 017b592edea..58206bb67f4 100644
--- a/components/style/properties/shorthand/position.mako.rs
+++ b/components/style/properties/shorthand/position.mako.rs
@@ -154,7 +154,7 @@
GridLine::parse(context, input)?
} else {
let mut line = GridLine::default();
- if start.integer.is_none() && !start.is_span {
+ if start.line_num.is_none() && !start.is_span {
line.ident = start.ident.clone(); // ident from start value should be taken
}
@@ -188,7 +188,7 @@
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
fn line_with_ident_from(other: &GridLine) -> GridLine {
let mut this = GridLine::default();
- if other.integer.is_none() && !other.is_span {
+ if other.line_num.is_none() && !other.is_span {
this.ident = other.ident.clone();
}
diff --git a/components/style/restyle_hints.rs b/components/style/restyle_hints.rs
index 54d92151dbd..73bd39ec1b3 100644
--- a/components/style/restyle_hints.rs
+++ b/components/style/restyle_hints.rs
@@ -7,19 +7,20 @@
#![deny(missing_docs)]
use Atom;
+use LocalName;
+use Namespace;
use dom::TElement;
use element_state::*;
-use fnv::FnvHashMap;
#[cfg(feature = "gecko")]
use gecko_bindings::structs::nsRestyleHint;
#[cfg(feature = "servo")]
use heapsize::HeapSizeOf;
-use selector_parser::{AttrValue, NonTSPseudoClass, PseudoElement, SelectorImpl, Snapshot, SnapshotMap};
-use selectors::{Element, MatchAttr};
-use selectors::matching::{ElementSelectorFlags, StyleRelations};
+use selector_parser::{NonTSPseudoClass, PseudoElement, SelectorImpl, Snapshot, SnapshotMap, AttrValue};
+use selectors::Element;
+use selectors::attr::{AttrSelectorOperation, NamespaceConstraint};
+use selectors::matching::{ElementSelectorFlags, MatchingContext, MatchingMode};
use selectors::matching::matches_selector;
-use selectors::parser::{AttrSelector, Combinator, Component, Selector};
-use selectors::parser::{SelectorInner, SelectorMethods};
+use selectors::parser::{Combinator, Component, Selector, SelectorInner, SelectorMethods};
use selectors::visitor::SelectorVisitor;
use smallvec::SmallVec;
use std::borrow::Borrow;
@@ -171,7 +172,7 @@ impl HeapSizeOf for RestyleHint {
/// still need to take the ElementWrapper approach for attribute-dependent
/// style. So we do it the same both ways for now to reduce complexity, but it's
/// worth measuring the performance impact (if any) of the mStateMask approach.
-pub trait ElementSnapshot : Sized + MatchAttr<Impl=SelectorImpl> {
+pub trait ElementSnapshot : Sized {
/// The state of the snapshot, if any.
fn state(&self) -> Option<ElementState>;
@@ -243,90 +244,6 @@ impl<'a, E> ElementWrapper<'a, E>
}
}
-impl<'a, E> MatchAttr for ElementWrapper<'a, E>
- where E: TElement,
-{
- type Impl = SelectorImpl;
-
- fn match_attr_has(&self, attr: &AttrSelector<SelectorImpl>) -> bool {
- match self.snapshot() {
- Some(snapshot) if snapshot.has_attrs()
- => snapshot.match_attr_has(attr),
- _ => self.element.match_attr_has(attr)
- }
- }
-
- fn match_attr_equals(&self,
- attr: &AttrSelector<SelectorImpl>,
- value: &AttrValue) -> bool {
- match self.snapshot() {
- Some(snapshot) if snapshot.has_attrs()
- => snapshot.match_attr_equals(attr, value),
- _ => self.element.match_attr_equals(attr, value)
- }
- }
-
- fn match_attr_equals_ignore_ascii_case(&self,
- attr: &AttrSelector<SelectorImpl>,
- value: &AttrValue) -> bool {
- match self.snapshot() {
- Some(snapshot) if snapshot.has_attrs()
- => snapshot.match_attr_equals_ignore_ascii_case(attr, value),
- _ => self.element.match_attr_equals_ignore_ascii_case(attr, value)
- }
- }
-
- fn match_attr_includes(&self,
- attr: &AttrSelector<SelectorImpl>,
- value: &AttrValue) -> bool {
- match self.snapshot() {
- Some(snapshot) if snapshot.has_attrs()
- => snapshot.match_attr_includes(attr, value),
- _ => self.element.match_attr_includes(attr, value)
- }
- }
-
- fn match_attr_dash(&self,
- attr: &AttrSelector<SelectorImpl>,
- value: &AttrValue) -> bool {
- match self.snapshot() {
- Some(snapshot) if snapshot.has_attrs()
- => snapshot.match_attr_dash(attr, value),
- _ => self.element.match_attr_dash(attr, value)
- }
- }
-
- fn match_attr_prefix(&self,
- attr: &AttrSelector<SelectorImpl>,
- value: &AttrValue) -> bool {
- match self.snapshot() {
- Some(snapshot) if snapshot.has_attrs()
- => snapshot.match_attr_prefix(attr, value),
- _ => self.element.match_attr_prefix(attr, value)
- }
- }
-
- fn match_attr_substring(&self,
- attr: &AttrSelector<SelectorImpl>,
- value: &AttrValue) -> bool {
- match self.snapshot() {
- Some(snapshot) if snapshot.has_attrs()
- => snapshot.match_attr_substring(attr, value),
- _ => self.element.match_attr_substring(attr, value)
- }
- }
-
- fn match_attr_suffix(&self,
- attr: &AttrSelector<SelectorImpl>,
- value: &AttrValue) -> bool {
- match self.snapshot() {
- Some(snapshot) if snapshot.has_attrs()
- => snapshot.match_attr_suffix(attr, value),
- _ => self.element.match_attr_suffix(attr, value)
- }
- }
-}
-
#[cfg(feature = "gecko")]
fn dir_selector_to_state(s: &[u16]) -> ElementState {
// Jump through some hoops to deal with our Box<[u16]> thing.
@@ -346,9 +263,11 @@ fn dir_selector_to_state(s: &[u16]) -> ElementState {
impl<'a, E> Element for ElementWrapper<'a, E>
where E: TElement,
{
+ type Impl = SelectorImpl;
+
fn match_non_ts_pseudo_class<F>(&self,
pseudo_class: &NonTSPseudoClass,
- relations: &mut StyleRelations,
+ context: &mut MatchingContext,
_setter: &mut F)
-> bool
where F: FnMut(&Self, ElementSelectorFlags),
@@ -360,7 +279,7 @@ impl<'a, E> Element for ElementWrapper<'a, E>
use selectors::matching::matches_complex_selector;
if let NonTSPseudoClass::MozAny(ref selectors) = *pseudo_class {
return selectors.iter().any(|s| {
- matches_complex_selector(s, self, relations, _setter)
+ matches_complex_selector(s, self, context, _setter)
})
}
}
@@ -393,19 +312,27 @@ impl<'a, E> Element for ElementWrapper<'a, E>
let flag = pseudo_class.state_flag();
if flag.is_empty() {
return self.element.match_non_ts_pseudo_class(pseudo_class,
- relations,
+ context,
&mut |_, _| {})
}
match self.snapshot().and_then(|s| s.state()) {
Some(snapshot_state) => snapshot_state.intersects(flag),
None => {
self.element.match_non_ts_pseudo_class(pseudo_class,
- relations,
+ context,
&mut |_, _| {})
}
}
}
+ fn match_pseudo_element(&self,
+ pseudo_element: &PseudoElement,
+ context: &mut MatchingContext)
+ -> bool
+ {
+ self.element.match_pseudo_element(pseudo_element, context)
+ }
+
fn parent_element(&self) -> Option<Self> {
self.element.parent_element()
.map(|e| ElementWrapper::new(e, self.snapshot_map))
@@ -443,6 +370,19 @@ impl<'a, E> Element for ElementWrapper<'a, E>
self.element.get_namespace()
}
+ fn attr_matches(&self,
+ ns: &NamespaceConstraint<&Namespace>,
+ local_name: &LocalName,
+ operation: &AttrSelectorOperation<&AttrValue>)
+ -> bool {
+ match self.snapshot() {
+ Some(snapshot) if snapshot.has_attrs() => {
+ snapshot.attr_matches(ns, local_name, operation)
+ }
+ _ => self.element.attr_matches(ns, local_name, operation)
+ }
+ }
+
fn get_id(&self) -> Option<Atom> {
match self.snapshot() {
Some(snapshot) if snapshot.has_attrs()
@@ -467,13 +407,9 @@ impl<'a, E> Element for ElementWrapper<'a, E>
self.element.is_root()
}
- fn each_class<F>(&self, callback: F)
- where F: FnMut(&Atom) {
- match self.snapshot() {
- Some(snapshot) if snapshot.has_attrs()
- => snapshot.each_class(callback),
- _ => self.element.each_class(callback)
- }
+ fn pseudo_element_originating_element(&self) -> Option<Self> {
+ self.element.closest_non_native_anonymous_ancestor()
+ .map(|e| ElementWrapper::new(e, self.snapshot_map))
}
}
@@ -492,13 +428,9 @@ fn is_attr_selector(sel: &Component<SelectorImpl>) -> bool {
match *sel {
Component::ID(_) |
Component::Class(_) |
- Component::AttrExists(_) |
- Component::AttrEqual(_, _, _) |
- Component::AttrIncludes(_, _) |
- Component::AttrDashMatch(_, _) |
- Component::AttrPrefixMatch(_, _) |
- Component::AttrSubstringMatch(_, _) |
- Component::AttrSuffixMatch(_, _) => true,
+ Component::AttributeInNoNamespaceExists { .. } |
+ Component::AttributeInNoNamespace { .. } |
+ Component::AttributeOther(_) => true,
_ => false,
}
}
@@ -507,6 +439,9 @@ fn combinator_to_restyle_hint(combinator: Option<Combinator>) -> RestyleHint {
match combinator {
None => RESTYLE_SELF,
Some(c) => match c {
+ // NB: RESTYLE_SELF is needed to handle properly eager pseudos,
+ // otherwise we may leave a stale style on the parent.
+ Combinator::PseudoElement => RESTYLE_SELF | RESTYLE_DESCENDANTS,
Combinator::Child => RESTYLE_DESCENDANTS,
Combinator::Descendant => RESTYLE_DESCENDANTS,
Combinator::NextSibling => RESTYLE_LATER_SIBLINGS,
@@ -634,13 +569,6 @@ impl SelectorVisitor for SensitivitiesVisitor {
#[derive(Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct DependencySet {
- /// A map used for pseudo-element's dependencies.
- ///
- /// Note that pseudo-elements are somewhat special, because some of them in
- /// Gecko track state, and also because they don't do selector-matching as
- /// normal, but against their parent element.
- pseudo_dependencies: FnvHashMap<PseudoElement, SelectorMap<PseudoElementDependency>>,
-
/// This is for all other normal element's selectors/selector parts.
dependencies: SelectorMap<Dependency>,
}
@@ -668,34 +596,9 @@ impl DependencySet {
index += 1; // Account for the simple selector.
}
-
- let pseudo_selector_is_state_dependent =
- sequence_start == 0 &&
- selector.pseudo_element.as_ref().map_or(false, |pseudo_selector| {
- !pseudo_selector.state().is_empty()
- });
-
- if pseudo_selector_is_state_dependent {
- let pseudo_selector = selector.pseudo_element.as_ref().unwrap();
- self.pseudo_dependencies
- .entry(pseudo_selector.pseudo_element().clone())
- .or_insert_with(SelectorMap::new)
- .insert(PseudoElementDependency {
- selector: selector.clone(),
- });
- }
-
// If we found a sensitivity, add an entry in the dependency set.
if !visitor.sensitivities.is_empty() {
- let mut hint = combinator_to_restyle_hint(combinator);
-
- if sequence_start == 0 && selector.pseudo_element.is_some() {
- // FIXME(emilio): Be more granular about this. See the
- // comment in `PseudoElementDependency` about how could this
- // be modified in order to be more efficient and restyle
- // less.
- hint |= RESTYLE_DESCENDANTS;
- }
+ let hint = combinator_to_restyle_hint(combinator);
let dep_selector = if sequence_start == 0 {
// Reuse the bloom hashes if this is the base selector.
@@ -724,82 +627,22 @@ impl DependencySet {
pub fn new() -> Self {
DependencySet {
dependencies: SelectorMap::new(),
- pseudo_dependencies: FnvHashMap::default(),
}
}
/// Return the total number of dependencies that this set contains.
pub fn len(&self) -> usize {
- self.dependencies.len() +
- self.pseudo_dependencies.values().fold(0, |acc, val| acc + val.len())
+ self.dependencies.len()
}
/// Clear this dependency set.
pub fn clear(&mut self) {
self.dependencies = SelectorMap::new();
- self.pseudo_dependencies.clear()
}
- fn compute_pseudo_hint<E>(
- &self,
- pseudo: &E,
- pseudo_element: PseudoElement,
- snapshots: &SnapshotMap)
- -> RestyleHint
- where E: TElement,
- {
- debug!("compute_pseudo_hint: {:?}, {:?}", pseudo, pseudo_element);
- debug_assert!(pseudo.has_snapshot());
-
- let map = match self.pseudo_dependencies.get(&pseudo_element) {
- Some(map) => map,
- None => return RestyleHint::empty(),
- };
-
- // Only pseudo-element's state is relevant.
- let pseudo_state_changes =
- ElementWrapper::new(*pseudo, snapshots).state_changes();
-
- debug!("pseudo_state_changes: {:?}", pseudo_state_changes);
- if pseudo_state_changes.is_empty() {
- return RestyleHint::empty();
- }
-
- let selector_matching_target =
- pseudo.closest_non_native_anonymous_ancestor().unwrap();
-
- // Note that we rely on that, if the originating element changes, it'll
- // post a restyle hint that would make us redo selector matching, so we
- // don't need to care about that.
- //
- // If that ever changes, we'd need to share more code with
- // `compute_element_hint`.
- let mut hint = RestyleHint::empty();
- map.lookup(selector_matching_target, &mut |dep| {
- // If the selector didn't match before, it either doesn't match now
- // either (or it doesn't matter because our parent posted a restyle
- // for us above).
- if !matches_selector(&dep.selector.inner, &selector_matching_target,
- None, &mut StyleRelations::empty(),
- &mut |_, _| {}) {
- return true;
- }
-
- let pseudo_selector = dep.selector.pseudo_element.as_ref().unwrap();
- debug_assert!(!pseudo_selector.state().is_empty());
-
- if pseudo_selector.state().intersects(pseudo_state_changes) {
- hint = RESTYLE_SELF;
- return false;
- }
-
- true
- });
-
- hint
- }
-
- fn compute_element_hint<E>(
+ /// Compute a restyle hint given an element and a snapshot, per the rules
+ /// explained in the rest of the documentation.
+ pub fn compute_hint<E>(
&self,
el: &E,
snapshots: &SnapshotMap)
@@ -838,8 +681,18 @@ impl DependencySet {
});
}
+ // FIXME(emilio): A bloom filter here would be neat.
+ let mut matching_context =
+ MatchingContext::new(MatchingMode::Normal, None);
+
+ let lookup_element = if el.implemented_pseudo_element().is_some() {
+ el.closest_non_native_anonymous_ancestor().unwrap()
+ } else {
+ *el
+ };
+
self.dependencies
- .lookup_with_additional(*el, additional_id, &additional_classes, &mut |dep| {
+ .lookup_with_additional(lookup_element, additional_id, &additional_classes, &mut |dep| {
trace!("scanning dependency: {:?}", dep);
if !dep.sensitivities.sensitive_to(attrs_changed,
state_changes) {
@@ -856,12 +709,12 @@ impl DependencySet {
// been set during original matching for any element that might
// change its matching behavior here.
let matched_then =
- matches_selector(&dep.selector, &snapshot_el, None,
- &mut StyleRelations::empty(),
+ matches_selector(&dep.selector, &snapshot_el,
+ &mut matching_context,
&mut |_, _| {});
let matches_now =
- matches_selector(&dep.selector, el, None,
- &mut StyleRelations::empty(),
+ matches_selector(&dep.selector, el,
+ &mut matching_context,
&mut |_, _| {});
if matched_then != matches_now {
hint.insert(dep.hint);
@@ -875,21 +728,4 @@ impl DependencySet {
hint
}
-
-
- /// Compute a restyle hint given an element and a snapshot, per the rules
- /// explained in the rest of the documentation.
- pub fn compute_hint<E>(&self,
- el: &E,
- snapshots: &SnapshotMap)
- -> RestyleHint
- where E: TElement + Clone,
- {
- debug!("DependencySet::compute_hint({:?})", el);
- if let Some(pseudo) = el.implemented_pseudo_element() {
- return self.compute_pseudo_hint(el, pseudo, snapshots);
- }
-
- self.compute_element_hint(el, snapshots)
- }
}
diff --git a/components/style/selector_parser.rs b/components/style/selector_parser.rs
index 0af60279af8..9e4e5deeaeb 100644
--- a/components/style/selector_parser.rs
+++ b/components/style/selector_parser.rs
@@ -37,7 +37,7 @@ pub use gecko::restyle_damage::GeckoRestyleDamage as RestyleDamage;
/// A type that represents the previous computed values needed for restyle
/// damage calculation.
#[cfg(feature = "servo")]
-pub type PreExistingComputedValues = ::stylearc::Arc<::properties::ServoComputedValues>;
+pub type PreExistingComputedValues = ::properties::ServoComputedValues;
/// A type that represents the previous computed values needed for restyle
/// damage calculation.
diff --git a/components/style/servo/restyle_damage.rs b/components/style/servo/restyle_damage.rs
index 1fd7b38cae2..69199d6e982 100644
--- a/components/style/servo/restyle_damage.rs
+++ b/components/style/servo/restyle_damage.rs
@@ -11,7 +11,6 @@ use computed_values::display;
use heapsize::HeapSizeOf;
use properties::ServoComputedValues;
use std::fmt;
-use stylearc::Arc;
bitflags! {
#[doc = "Individual layout actions that may be necessary after restyling."]
@@ -60,16 +59,17 @@ impl HeapSizeOf for ServoRestyleDamage {
impl ServoRestyleDamage {
/// Compute the appropriate restyle damage for a given style change between
/// `old` and `new`.
- pub fn compute(old: &Arc<ServoComputedValues>,
- new: &Arc<ServoComputedValues>) -> ServoRestyleDamage {
+ pub fn compute(old: &ServoComputedValues,
+ new: &ServoComputedValues)
+ -> ServoRestyleDamage {
compute_damage(old, new)
}
/// Returns a bitmask that represents a flow that needs to be rebuilt and
/// reflowed.
///
- /// FIXME(bholley): Do we ever actually need this? Shouldn't RECONSTRUCT_FLOW
- /// imply everything else?
+ /// FIXME(bholley): Do we ever actually need this? Shouldn't
+ /// RECONSTRUCT_FLOW imply everything else?
pub fn rebuild_and_reflow() -> ServoRestyleDamage {
REPAINT | REPOSITION | STORE_OVERFLOW | BUBBLE_ISIZES | REFLOW_OUT_OF_FLOW | REFLOW |
RECONSTRUCT_FLOW
diff --git a/components/style/servo/selector_parser.rs b/components/style/servo/selector_parser.rs
index e801738866c..fdc14b11e29 100644
--- a/components/style/servo/selector_parser.rs
+++ b/components/style/servo/selector_parser.rs
@@ -14,9 +14,10 @@ use element_state::ElementState;
use fnv::FnvHashMap;
use restyle_hints::ElementSnapshot;
use selector_parser::{ElementExt, PseudoElementCascadeType, SelectorParser};
-use selectors::{Element, MatchAttrGeneric};
-use selectors::matching::StyleRelations;
-use selectors::parser::{AttrSelector, SelectorMethods};
+use selectors::Element;
+use selectors::attr::{AttrSelectorOperation, NamespaceConstraint};
+use selectors::matching::{MatchingContext, MatchingMode};
+use selectors::parser::SelectorMethods;
use selectors::visitor::SelectorVisitor;
use std::borrow::Cow;
use std::fmt;
@@ -51,6 +52,14 @@ pub enum PseudoElement {
ServoInlineAbsolute,
}
+impl ::selectors::parser::PseudoElement for PseudoElement {
+ type Impl = SelectorImpl;
+
+ fn supports_pseudo_class(&self, _: &NonTSPseudoClass) -> bool {
+ false
+ }
+}
+
impl ToCss for PseudoElement {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
use self::PseudoElement::*;
@@ -78,18 +87,6 @@ impl ToCss for PseudoElement {
pub const EAGER_PSEUDO_COUNT: usize = 3;
impl PseudoElement {
- /// The pseudo-element, used for compatibility with Gecko's
- /// `PseudoElementSelector`.
- pub fn pseudo_element(&self) -> &Self {
- self
- }
-
- /// The pseudo-element selector's state, used for compatibility with Gecko's
- /// `PseudoElementSelector`.
- pub fn state(&self) -> ElementState {
- ElementState::empty()
- }
-
/// Gets the canonical index of this eagerly-cascaded pseudo-element.
#[inline]
pub fn eager_index(&self) -> usize {
@@ -178,6 +175,7 @@ pub enum NonTSPseudoClass {
ReadWrite,
ReadOnly,
ServoNonZeroBorder,
+ ServoCaseSensitiveTypeAttr(Atom),
Target,
Visited,
}
@@ -185,10 +183,18 @@ pub enum NonTSPseudoClass {
impl ToCss for NonTSPseudoClass {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
use self::NonTSPseudoClass::*;
- if let Lang(ref lang) = *self {
- dest.write_str(":lang(")?;
- serialize_identifier(lang, dest)?;
- return dest.write_str(")");
+ match *self {
+ Lang(ref lang) => {
+ dest.write_str(":lang(")?;
+ serialize_identifier(lang, dest)?;
+ return dest.write_str(")")
+ }
+ ServoCaseSensitiveTypeAttr(ref value) => {
+ dest.write_str(":-servo-case-sensitive-type-attr(")?;
+ serialize_identifier(value, dest)?;
+ return dest.write_str(")")
+ }
+ _ => {}
}
dest.write_str(match *self {
@@ -201,7 +207,6 @@ impl ToCss for NonTSPseudoClass {
Fullscreen => ":fullscreen",
Hover => ":hover",
Indeterminate => ":indeterminate",
- Lang(_) => unreachable!(),
Link => ":link",
PlaceholderShown => ":placeholder-shown",
ReadWrite => ":read-write",
@@ -209,6 +214,8 @@ impl ToCss for NonTSPseudoClass {
ServoNonZeroBorder => ":-servo-nonzero-border",
Target => ":target",
Visited => ":visited",
+ Lang(_) |
+ ServoCaseSensitiveTypeAttr(_) => unreachable!(),
})
}
}
@@ -247,7 +254,8 @@ impl NonTSPseudoClass {
Lang(_) |
Link |
Visited |
- ServoNonZeroBorder => ElementState::empty(),
+ ServoNonZeroBorder |
+ ServoCaseSensitiveTypeAttr(_) => ElementState::empty(),
}
}
@@ -264,7 +272,7 @@ impl NonTSPseudoClass {
pub struct SelectorImpl;
impl ::selectors::SelectorImpl for SelectorImpl {
- type PseudoElementSelector = PseudoElement;
+ type PseudoElement = PseudoElement;
type NonTSPseudoClass = NonTSPseudoClass;
type AttrValue = String;
@@ -316,16 +324,22 @@ impl<'a> ::selectors::Parser for SelectorParser<'a> {
-> Result<NonTSPseudoClass, ()> {
use self::NonTSPseudoClass::*;
let pseudo_class = match_ignore_ascii_case!{ &name,
- "lang" => Lang(String::from(try!(parser.expect_ident_or_string())).into_boxed_str()),
+ "lang" => {
+ Lang(parser.expect_ident_or_string()?.into_owned().into_boxed_str())
+ }
+ "-servo-case-sensitive-type-attr" => {
+ if !self.in_user_agent_stylesheet() {
+ return Err(());
+ }
+ ServoCaseSensitiveTypeAttr(Atom::from(parser.expect_ident()?))
+ }
_ => return Err(())
};
Ok(pseudo_class)
}
- fn parse_pseudo_element(&self,
- name: Cow<str>,
- _input: &mut CssParser)
+ fn parse_pseudo_element(&self, name: Cow<str>)
-> Result<PseudoElement, ()> {
use self::PseudoElement::*;
let pseudo_element = match_ignore_ascii_case! { &name,
@@ -525,10 +539,10 @@ impl ServoElementSnapshot {
.map(|&(_, ref v)| v)
}
- fn get_attr_ignore_ns(&self, name: &LocalName) -> Option<&AttrValue> {
+ fn any_attr_ignore_ns<F>(&self, name: &LocalName, mut f: F) -> bool
+ where F: FnMut(&AttrValue) -> bool {
self.attrs.as_ref().unwrap().iter()
- .find(|&&(ref ident, _)| ident.local_name == *name)
- .map(|&(_, ref v)| v)
+ .any(|&(ref ident, ref v)| ident.local_name == *name && f(v))
}
}
@@ -561,26 +575,30 @@ impl ElementSnapshot for ServoElementSnapshot {
}
}
-impl MatchAttrGeneric for ServoElementSnapshot {
- type Impl = SelectorImpl;
-
- fn match_attr<F>(&self, attr: &AttrSelector<SelectorImpl>, test: F) -> bool
- where F: Fn(&str) -> bool
- {
- use selectors::parser::NamespaceConstraint;
- let html = self.is_html_element_in_html_document;
- let local_name = if html { &attr.lower_name } else { &attr.name };
- match attr.namespace {
- NamespaceConstraint::Specific(ref ns) => self.get_attr(&ns.url, local_name),
- NamespaceConstraint::Any => self.get_attr_ignore_ns(local_name),
- }.map_or(false, |v| test(v))
+impl ServoElementSnapshot {
+ /// selectors::Element::attr_matches
+ pub fn attr_matches(&self,
+ ns: &NamespaceConstraint<&Namespace>,
+ local_name: &LocalName,
+ operation: &AttrSelectorOperation<&String>)
+ -> bool {
+ match *ns {
+ NamespaceConstraint::Specific(ref ns) => {
+ self.get_attr(ns, local_name)
+ .map_or(false, |value| value.eval_selector(operation))
+ }
+ NamespaceConstraint::Any => {
+ self.any_attr_ignore_ns(local_name, |value| value.eval_selector(operation))
+ }
+ }
}
}
impl<E: Element<Impl=SelectorImpl> + Debug> ElementExt for E {
fn is_link(&self) -> bool {
+ let mut context = MatchingContext::new(MatchingMode::Normal, None);
self.match_non_ts_pseudo_class(&NonTSPseudoClass::AnyLink,
- &mut StyleRelations::empty(),
+ &mut context,
&mut |_, _| {})
}
diff --git a/components/style/stylist.rs b/components/style/stylist.rs
index d8b76bd01b0..a5c103c5a55 100644
--- a/components/style/stylist.rs
+++ b/components/style/stylist.rs
@@ -6,7 +6,7 @@
#![deny(missing_docs)]
-use {Atom, LocalName};
+use {Atom, LocalName, Namespace};
use bit_vec::BitVec;
use context::QuirksMode;
use data::ComputedStyle;
@@ -26,11 +26,11 @@ use properties::PropertyDeclarationBlock;
use restyle_hints::{RestyleHint, DependencySet};
use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource};
use selector_parser::{SelectorImpl, PseudoElement, SnapshotMap};
-use selectors::Element;
+use selectors::attr::NamespaceConstraint;
use selectors::bloom::BloomFilter;
use selectors::matching::{AFFECTED_BY_STYLE_ATTRIBUTE, AFFECTED_BY_PRESENTATIONAL_HINTS};
-use selectors::matching::{ElementSelectorFlags, StyleRelations, matches_selector};
-use selectors::parser::{AttrSelector, Combinator, Component, Selector, SelectorInner, SelectorIter};
+use selectors::matching::{ElementSelectorFlags, matches_selector, MatchingContext, MatchingMode};
+use selectors::parser::{Combinator, Component, Selector, SelectorInner, SelectorIter};
use selectors::parser::{SelectorMethods, LocalName as LocalNameSelector};
use selectors::visitor::SelectorVisitor;
use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
@@ -479,9 +479,9 @@ impl Stylist {
rule: &Arc<Locked<StyleRule>>,
stylesheet: &Stylesheet)
{
- let map = if let Some(ref pseudo_selector) = selector.pseudo_element {
+ let map = if let Some(pseudo) = selector.pseudo_element() {
self.pseudos_map
- .entry(pseudo_selector.pseudo_element().clone())
+ .entry(pseudo.clone())
.or_insert_with(PerPseudoElementSelectorMap::new)
.borrow_for_origin(&stylesheet.origin)
} else {
@@ -503,7 +503,7 @@ impl Stylist {
/// Returns whether the given attribute might appear in an attribute
/// selector of some rule in the stylist.
pub fn might_have_attribute_dependency(&self,
- local_name: &<SelectorImpl as ::selectors::SelectorImpl>::LocalName)
+ local_name: &LocalName)
-> bool {
#[cfg(feature = "servo")]
let style_lower_name = local_name!("style");
@@ -525,9 +525,6 @@ impl Stylist {
#[inline]
fn note_attribute_and_state_dependencies(&mut self, selector: &Selector<SelectorImpl>) {
- if let Some(ref pseudo_selector) = selector.pseudo_element {
- self.state_dependencies.insert(pseudo_selector.state());
- }
selector.visit(&mut AttributeAndStateDependencyVisitor(self));
}
@@ -635,14 +632,13 @@ impl Stylist {
guards: &StylesheetGuards,
element: &E,
pseudo: &PseudoElement,
- pseudo_state: ElementState,
parent: &Arc<ComputedValues>,
font_metrics: &FontMetricsProvider)
-> Option<ComputedStyle>
where E: TElement,
{
let rule_node =
- match self.lazy_pseudo_rules(guards, element, pseudo, pseudo_state) {
+ match self.lazy_pseudo_rules(guards, element, pseudo) {
Some(rule_node) => rule_node,
None => return None
};
@@ -673,8 +669,7 @@ impl Stylist {
pub fn lazy_pseudo_rules<E>(&self,
guards: &StylesheetGuards,
element: &E,
- pseudo: &PseudoElement,
- pseudo_state: ElementState)
+ pseudo: &PseudoElement)
-> Option<StrongRuleNode>
where E: TElement
{
@@ -707,15 +702,16 @@ impl Stylist {
}
};
-
let mut declarations = ApplicableDeclarationList::new();
+ let mut matching_context =
+ MatchingContext::new(MatchingMode::ForStatelessPseudoElement, None);
self.push_applicable_declarations(element,
- None,
+ Some(pseudo),
None,
None,
AnimationRules(None, None),
- Some((pseudo, pseudo_state)),
&mut declarations,
+ &mut matching_context,
&mut set_selector_flags);
if declarations.is_empty() {
return None
@@ -834,21 +830,20 @@ impl Stylist {
///
/// This corresponds to `ElementRuleCollector` in WebKit.
///
- /// The returned `StyleRelations` indicate hints about which kind of rules
- /// have matched.
+ /// The `StyleRelations` recorded in `MatchingContext` indicate hints about
+ /// which kind of rules have matched.
pub fn push_applicable_declarations<E, V, F>(
&self,
element: &E,
- parent_bf: Option<&BloomFilter>,
+ pseudo_element: Option<&PseudoElement>,
style_attribute: Option<&Arc<Locked<PropertyDeclarationBlock>>>,
smil_override: Option<&Arc<Locked<PropertyDeclarationBlock>>>,
animation_rules: AnimationRules,
- pseudo_element: Option<(&PseudoElement, ElementState)>,
applicable_declarations: &mut V,
+ context: &mut MatchingContext,
flags_setter: &mut F)
- -> StyleRelations
where E: TElement,
- V: Push<ApplicableDeclarationBlock> + VecLike<ApplicableDeclarationBlock>,
+ V: Push<ApplicableDeclarationBlock> + VecLike<ApplicableDeclarationBlock> + ::std::fmt::Debug,
F: FnMut(&E, ElementSelectorFlags),
{
debug_assert!(!self.is_device_dirty);
@@ -857,27 +852,36 @@ impl Stylist {
debug_assert!(cfg!(feature = "gecko") ||
style_attribute.is_none() || pseudo_element.is_none(),
"Style attributes do not apply to pseudo-elements");
- debug_assert!(pseudo_element.as_ref().map_or(true, |p| !p.0.is_precomputed()));
+ debug_assert!(pseudo_element.map_or(true, |p| !p.is_precomputed()));
let map = match pseudo_element {
- Some((ref pseudo, _)) => self.pseudos_map.get(pseudo).unwrap(),
+ Some(pseudo) => self.pseudos_map.get(pseudo).unwrap(),
None => &self.element_map,
};
- let mut relations = StyleRelations::empty();
+ let is_implemented_pseudo =
+ element.implemented_pseudo_element().is_some();
+
+ // NB: This causes use to rule has pseudo selectors based on the
+ // properties of the originating element (which is fine, given the
+ // find_first_from_right usage).
+ let rule_hash_target = if is_implemented_pseudo {
+ element.closest_non_native_anonymous_ancestor().unwrap()
+ } else {
+ *element
+ };
debug!("Determining if style is shareable: pseudo: {}",
pseudo_element.is_some());
// Step 1: Normal user-agent rules.
map.user_agent.get_all_matching_rules(element,
- pseudo_element,
- parent_bf,
+ &rule_hash_target,
applicable_declarations,
- &mut relations,
+ context,
flags_setter,
CascadeLevel::UANormal);
- debug!("UA normal: {:?}", relations);
+ debug!("UA normal: {:?}", context.relations);
if pseudo_element.is_none() {
// Step 2: Presentational hints.
@@ -890,40 +894,46 @@ impl Stylist {
}
}
// Never share style for elements with preshints
- relations |= AFFECTED_BY_PRESENTATIONAL_HINTS;
+ context.relations |= AFFECTED_BY_PRESENTATIONAL_HINTS;
}
- debug!("preshints: {:?}", relations);
+ debug!("preshints: {:?}", context.relations);
}
- if element.matches_user_and_author_rules() {
+ // NB: the following condition, although it may look somewhat
+ // inaccurate, would be equivalent to something like:
+ //
+ // element.matches_user_and_author_rules() ||
+ // (is_implemented_pseudo &&
+ // rule_hash_target.matches_user_and_author_rules())
+ //
+ // Which may be more what you would probably expect.
+ if rule_hash_target.matches_user_and_author_rules() {
// Step 3: User and author normal rules.
map.user.get_all_matching_rules(element,
- pseudo_element,
- parent_bf,
+ &rule_hash_target,
applicable_declarations,
- &mut relations,
+ context,
flags_setter,
CascadeLevel::UserNormal);
- debug!("user normal: {:?}", relations);
+ debug!("user normal: {:?}", context.relations);
map.author.get_all_matching_rules(element,
- pseudo_element,
- parent_bf,
+ &rule_hash_target,
applicable_declarations,
- &mut relations,
+ context,
flags_setter,
CascadeLevel::AuthorNormal);
- debug!("author normal: {:?}", relations);
+ debug!("author normal: {:?}", context.relations);
// Step 4: Normal style attributes.
if let Some(sa) = style_attribute {
- relations |= AFFECTED_BY_STYLE_ATTRIBUTE;
+ context.relations |= AFFECTED_BY_STYLE_ATTRIBUTE;
Push::push(
applicable_declarations,
ApplicableDeclarationBlock::from_declarations(sa.clone(),
CascadeLevel::StyleAttributeNormal));
}
- debug!("style attr: {:?}", relations);
+ debug!("style attr: {:?}", context.relations);
// Step 5: SMIL override.
// Declarations from SVG SMIL animation elements.
@@ -933,7 +943,7 @@ impl Stylist {
ApplicableDeclarationBlock::from_declarations(so.clone(),
CascadeLevel::SMILOverride));
}
- debug!("SMIL: {:?}", relations);
+ debug!("SMIL: {:?}", context.relations);
// Step 6: Animations.
// The animations sheet (CSS animations, script-generated animations,
@@ -944,7 +954,7 @@ impl Stylist {
ApplicableDeclarationBlock::from_declarations(anim,
CascadeLevel::Animations));
}
- debug!("animation: {:?}", relations);
+ debug!("animation: {:?}", context.relations);
} else {
debug!("skipping non-agent rules");
}
@@ -961,11 +971,8 @@ impl Stylist {
applicable_declarations,
ApplicableDeclarationBlock::from_declarations(anim, CascadeLevel::Transitions));
}
- debug!("transition: {:?}", relations);
-
- debug!("push_applicable_declarations: shareable: {:?}", relations);
-
- relations
+ debug!("transition: {:?}", context.relations);
+ debug!("push_applicable_declarations: shareable: {:?}", context.relations);
}
/// Return whether the device is dirty, that is, whether the screen size or
@@ -997,8 +1004,10 @@ impl Stylist {
where E: TElement,
F: FnMut(&E, ElementSelectorFlags),
{
- use selectors::matching::StyleRelations;
- use selectors::matching::matches_selector;
+ // NB: `MatchingMode` doesn't really matter, given we don't share style
+ // between pseudos.
+ let mut matching_context =
+ MatchingContext::new(MatchingMode::Normal, Some(bloom));
// Note that, by the time we're revalidating, we're guaranteed that the
// candidate and the entry have the same id, classes, and local name.
@@ -1009,8 +1018,7 @@ impl Stylist {
self.selectors_for_cache_revalidation.lookup(*element, &mut |selector| {
results.push(matches_selector(selector,
element,
- Some(bloom),
- &mut StyleRelations::empty(),
+ &mut matching_context,
flags_setter));
true
});
@@ -1081,17 +1089,19 @@ struct AttributeAndStateDependencyVisitor<'a>(&'a mut Stylist);
impl<'a> SelectorVisitor for AttributeAndStateDependencyVisitor<'a> {
type Impl = SelectorImpl;
- fn visit_attribute_selector(&mut self, selector: &AttrSelector<Self::Impl>) -> bool {
+ fn visit_attribute_selector(&mut self, _ns: &NamespaceConstraint<&Namespace>,
+ name: &LocalName, lower_name: &LocalName)
+ -> bool {
#[cfg(feature = "servo")]
let style_lower_name = local_name!("style");
#[cfg(feature = "gecko")]
let style_lower_name = atom!("style");
- if selector.lower_name == style_lower_name {
+ if *lower_name == style_lower_name {
self.0.style_attribute_dependency = true;
} else {
- self.0.attribute_dependencies.insert(&selector.name);
- self.0.attribute_dependencies.insert(&selector.lower_name);
+ self.0.attribute_dependencies.insert(&name);
+ self.0.attribute_dependencies.insert(&lower_name);
}
true
}
@@ -1150,13 +1160,9 @@ impl SelectorVisitor for RevalidationVisitor {
/// concerned.
fn visit_simple_selector(&mut self, s: &Component<SelectorImpl>) -> bool {
match *s {
- Component::AttrExists(_) |
- Component::AttrEqual(_, _, _) |
- Component::AttrIncludes(_, _) |
- Component::AttrDashMatch(_, _) |
- Component::AttrPrefixMatch(_, _) |
- Component::AttrSubstringMatch(_, _) |
- Component::AttrSuffixMatch(_, _) |
+ Component::AttributeInNoNamespaceExists { .. } |
+ Component::AttributeInNoNamespace { .. } |
+ Component::AttributeOther(_) |
Component::Empty |
Component::FirstChild |
Component::LastChild |
@@ -1189,6 +1195,7 @@ pub fn needs_revalidation(selector: &Selector<SelectorImpl>) -> bool {
/// Map that contains the CSS rules for a specific PseudoElement
/// (or lack of PseudoElement).
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+#[derive(Debug)]
struct PerPseudoElementSelectorMap {
/// Rules from user agent stylesheets
user_agent: SelectorMap<Rule>,
@@ -1290,13 +1297,12 @@ impl SelectorMap<Rule> {
/// Sort the Rules at the end to maintain cascading order.
pub fn get_all_matching_rules<E, V, F>(&self,
element: &E,
- pseudo_element: Option<(&PseudoElement, ElementState)>,
- parent_bf: Option<&BloomFilter>,
+ rule_hash_target: &E,
matching_rules_list: &mut V,
- relations: &mut StyleRelations,
+ context: &mut MatchingContext,
flags_setter: &mut F,
cascade_level: CascadeLevel)
- where E: Element<Impl=SelectorImpl>,
+ where E: TElement,
V: VecLike<ApplicableDeclarationBlock>,
F: FnMut(&E, ElementSelectorFlags),
{
@@ -1306,46 +1312,38 @@ impl SelectorMap<Rule> {
// At the end, we're going to sort the rules that we added, so remember where we began.
let init_len = matching_rules_list.len();
- if let Some(id) = element.get_id() {
+ if let Some(id) = rule_hash_target.get_id() {
SelectorMap::get_matching_rules_from_hash(element,
- pseudo_element,
- parent_bf,
&self.id_hash,
&id,
matching_rules_list,
- relations,
+ context,
flags_setter,
cascade_level)
}
- element.each_class(|class| {
+ rule_hash_target.each_class(|class| {
SelectorMap::get_matching_rules_from_hash(element,
- pseudo_element,
- parent_bf,
&self.class_hash,
class,
matching_rules_list,
- relations,
+ context,
flags_setter,
cascade_level);
});
SelectorMap::get_matching_rules_from_hash(element,
- pseudo_element,
- parent_bf,
&self.local_name_hash,
- element.get_local_name(),
+ rule_hash_target.get_local_name(),
matching_rules_list,
- relations,
+ context,
flags_setter,
cascade_level);
SelectorMap::get_matching_rules(element,
- pseudo_element,
- parent_bf,
&self.other,
matching_rules_list,
- relations,
+ context,
flags_setter,
cascade_level);
@@ -1366,8 +1364,8 @@ impl SelectorMap<Rule> {
let mut rules_list = vec![];
for rule in self.other.iter() {
- if rule.selector.inner.complex.iter_raw().next().is_none() {
- rules_list.push(rule.to_applicable_declaration_block(cascade_level));
+ if rule.selector.is_universal() {
+ rules_list.push(rule.to_applicable_declaration_block(cascade_level))
}
}
@@ -1379,15 +1377,13 @@ impl SelectorMap<Rule> {
fn get_matching_rules_from_hash<E, Str, BorrowedStr: ?Sized, Vector, F>(
element: &E,
- pseudo_element: Option<(&PseudoElement, ElementState)>,
- parent_bf: Option<&BloomFilter>,
hash: &FnvHashMap<Str, Vec<Rule>>,
key: &BorrowedStr,
matching_rules: &mut Vector,
- relations: &mut StyleRelations,
+ context: &mut MatchingContext,
flags_setter: &mut F,
cascade_level: CascadeLevel)
- where E: Element<Impl=SelectorImpl>,
+ where E: TElement,
Str: Borrow<BorrowedStr> + Eq + Hash,
BorrowedStr: Eq + Hash,
Vector: VecLike<ApplicableDeclarationBlock>,
@@ -1395,11 +1391,9 @@ impl SelectorMap<Rule> {
{
if let Some(rules) = hash.get(key) {
SelectorMap::get_matching_rules(element,
- pseudo_element,
- parent_bf,
rules,
matching_rules,
- relations,
+ context,
flags_setter,
cascade_level)
}
@@ -1407,43 +1401,19 @@ impl SelectorMap<Rule> {
/// Adds rules in `rules` that match `element` to the `matching_rules` list.
fn get_matching_rules<E, V, F>(element: &E,
- pseudo_element: Option<(&PseudoElement, ElementState)>,
- parent_bf: Option<&BloomFilter>,
rules: &[Rule],
matching_rules: &mut V,
- relations: &mut StyleRelations,
+ context: &mut MatchingContext,
flags_setter: &mut F,
cascade_level: CascadeLevel)
- where E: Element<Impl=SelectorImpl>,
+ where E: TElement,
V: VecLike<ApplicableDeclarationBlock>,
F: FnMut(&E, ElementSelectorFlags),
{
- for rule in rules.iter() {
- debug_assert_eq!(rule.selector.pseudo_element.is_some(),
- pseudo_element.is_some(),
- "Testing pseudo-elements against the wrong map");
-
- if let Some((pseudo, pseudo_state)) = pseudo_element {
- let pseudo_selector =
- rule.selector.pseudo_element.as_ref().unwrap();
-
- debug_assert_eq!(pseudo_selector.pseudo_element(), pseudo,
- "Testing pseudo-element against the wrong entry");
-
- let state = pseudo_selector.state();
-
- // NB: We only allow a subset of the flags here, so using
- // contains for them is fine, (and it's necessary, to handle
- // multiple state flags properly).
- if !state.is_empty() && !pseudo_state.contains(state) {
- continue;
- }
- }
-
+ for rule in rules {
if matches_selector(&rule.selector.inner,
element,
- parent_bf,
- relations,
+ context,
flags_setter) {
matching_rules.push(
rule.to_applicable_declaration_block(cascade_level));
@@ -1600,45 +1570,70 @@ impl<T> SelectorMap<T> where T: Clone + Borrow<SelectorInner<SelectorImpl>> {
}
}
+/// Searches the selector from right to left, beginning to the left of the
+/// ::pseudo-element (if any), and ending at the first combinator.
+///
+/// The first non-None value returned from |f| is returned.
+///
+/// Effectively, pseudo-elements are ignored, given only state pseudo-classes
+/// may appear before them.
+fn find_from_right<F, R>(selector: &SelectorInner<SelectorImpl>, mut f: F) -> Option<R>
+ where F: FnMut(&Component<SelectorImpl>) -> Option<R>,
+{
+ let mut iter = selector.complex.iter();
+ for ss in &mut iter {
+ if let Some(r) = f(ss) {
+ return Some(r)
+ }
+ }
+
+ if iter.next_sequence() == Some(Combinator::PseudoElement) {
+ for ss in &mut iter {
+ if let Some(r) = f(ss) {
+ return Some(r)
+ }
+ }
+ }
+
+ None
+}
+
/// Retrieve the first ID name in the selector, or None otherwise.
pub fn get_id_name(selector: &SelectorInner<SelectorImpl>) -> Option<Atom> {
- for ss in selector.complex.iter() {
+ find_from_right(selector, |ss| {
// TODO(pradeep): Implement case-sensitivity based on the
// document type and quirks mode.
if let Component::ID(ref id) = *ss {
return Some(id.clone());
}
- }
-
- None
+ None
+ })
}
/// Retrieve the FIRST class name in the selector, or None otherwise.
pub fn get_class_name(selector: &SelectorInner<SelectorImpl>) -> Option<Atom> {
- for ss in selector.complex.iter() {
+ find_from_right(selector, |ss| {
// TODO(pradeep): Implement case-sensitivity based on the
// document type and quirks mode.
if let Component::Class(ref class) = *ss {
return Some(class.clone());
}
- }
-
- None
+ None
+ })
}
/// Retrieve the name if it is a type selector, or None otherwise.
pub fn get_local_name(selector: &SelectorInner<SelectorImpl>)
-> Option<LocalNameSelector<SelectorImpl>> {
- for ss in selector.complex.iter() {
+ find_from_right(selector, |ss| {
if let Component::LocalName(ref n) = *ss {
return Some(LocalNameSelector {
name: n.name.clone(),
lower_name: n.lower_name.clone(),
})
}
- }
-
- None
+ None
+ })
}
/// A rule, that wraps a style rule, but represents a single selector of the
@@ -1668,7 +1663,7 @@ impl Borrow<SelectorInner<SelectorImpl>> for Rule {
impl Rule {
/// Returns the specificity of the rule.
pub fn specificity(&self) -> u32 {
- self.selector.specificity
+ self.selector.specificity()
}
fn to_applicable_declaration_block(&self, level: CascadeLevel) -> ApplicableDeclarationBlock {
diff --git a/components/style/values/computed/length.rs b/components/style/values/computed/length.rs
index 1bab68160be..89702468570 100644
--- a/components/style/values/computed/length.rs
+++ b/components/style/values/computed/length.rs
@@ -8,6 +8,7 @@ use app_units::{Au, AU_PER_PX};
use ordered_float::NotNaN;
use std::fmt;
use style_traits::ToCss;
+use style_traits::values::specified::AllowedLengthType;
use super::{Number, ToComputedValue, Context};
use values::{Auto, CSSFloat, Either, ExtremumLength, None_, Normal, specified};
use values::specified::length::{AbsoluteLength, FontBaseSize, FontRelativeLength, ViewportPercentageLength};
@@ -48,7 +49,7 @@ impl ToComputedValue for specified::Length {
fn to_computed_value(&self, context: &Context) -> Au {
match *self {
specified::Length::NoCalc(l) => l.to_computed_value(context),
- specified::Length::Calc(range, ref calc) => range.clamp(calc.to_computed_value(context).length()),
+ specified::Length::Calc(ref calc) => calc.to_computed_value(context).length(),
}
}
@@ -62,14 +63,43 @@ impl ToComputedValue for specified::Length {
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct CalcLengthOrPercentage {
- pub length: Au,
+ pub clamping_mode: AllowedLengthType,
+ length: Au,
pub percentage: Option<CSSFloat>,
}
impl CalcLengthOrPercentage {
+ /// Returns a new `CalcLengthOrPercentage`.
+ #[inline]
+ pub fn new(length: Au, percentage: Option<CSSFloat>) -> Self {
+ Self::with_clamping_mode(length, percentage, AllowedLengthType::All)
+ }
+
+ /// Returns a new `CalcLengthOrPercentage` with a specific clamping mode.
+ #[inline]
+ pub fn with_clamping_mode(length: Au,
+ percentage: Option<CSSFloat>,
+ clamping_mode: AllowedLengthType)
+ -> Self {
+ Self {
+ clamping_mode: clamping_mode,
+ length: length,
+ percentage: percentage,
+ }
+ }
+
+ /// Returns this `calc()` as a `<length>`.
+ ///
+ /// Panics in debug mode if a percentage is present in the expression.
#[inline]
- #[allow(missing_docs)]
pub fn length(&self) -> Au {
+ debug_assert!(self.percentage.is_none());
+ self.clamping_mode.clamp(self.length)
+ }
+
+ /// Returns the `<length>` component of this `calc()`, unclamped.
+ #[inline]
+ pub fn unclamped_length(&self) -> Au {
self.length
}
@@ -81,10 +111,12 @@ impl CalcLengthOrPercentage {
/// If there are special rules for computing percentages in a value (e.g. the height property),
/// they apply whenever a calc() expression contains percentages.
- pub fn to_computed(&self, container_len: Option<Au>) -> Option<Au> {
+ pub fn to_used_value(&self, container_len: Option<Au>) -> Option<Au> {
match (container_len, self.percentage) {
- (Some(len), Some(percent)) => Some(self.length + len.scale_by(percent)),
- (_, None) => Some(self.length),
+ (Some(len), Some(percent)) => {
+ Some(self.clamping_mode.clamp(self.length + len.scale_by(percent)))
+ },
+ (_, None) => Some(self.length()),
_ => None,
}
}
@@ -94,16 +126,10 @@ impl From<LengthOrPercentage> for CalcLengthOrPercentage {
fn from(len: LengthOrPercentage) -> CalcLengthOrPercentage {
match len {
LengthOrPercentage::Percentage(this) => {
- CalcLengthOrPercentage {
- length: Au(0),
- percentage: Some(this),
- }
+ CalcLengthOrPercentage::new(Au(0), Some(this))
}
LengthOrPercentage::Length(this) => {
- CalcLengthOrPercentage {
- length: this,
- percentage: None,
- }
+ CalcLengthOrPercentage::new(this, None)
}
LengthOrPercentage::Calc(this) => {
this
@@ -116,16 +142,10 @@ impl From<LengthOrPercentageOrAuto> for Option<CalcLengthOrPercentage> {
fn from(len: LengthOrPercentageOrAuto) -> Option<CalcLengthOrPercentage> {
match len {
LengthOrPercentageOrAuto::Percentage(this) => {
- Some(CalcLengthOrPercentage {
- length: Au(0),
- percentage: Some(this),
- })
+ Some(CalcLengthOrPercentage::new(Au(0), Some(this)))
}
LengthOrPercentageOrAuto::Length(this) => {
- Some(CalcLengthOrPercentage {
- length: this,
- percentage: None,
- })
+ Some(CalcLengthOrPercentage::new(this, None))
}
LengthOrPercentageOrAuto::Calc(this) => {
Some(this)
@@ -176,6 +196,7 @@ impl ToComputedValue for specified::CalcLengthOrPercentage {
}
CalcLengthOrPercentage {
+ clamping_mode: self.clamping_mode,
length: length,
percentage: self.percentage,
}
@@ -184,6 +205,7 @@ impl ToComputedValue for specified::CalcLengthOrPercentage {
#[inline]
fn from_computed_value(computed: &CalcLengthOrPercentage) -> Self {
specified::CalcLengthOrPercentage {
+ clamping_mode: computed.clamping_mode,
absolute: Some(computed.length),
percentage: computed.percentage,
..Default::default()
@@ -232,7 +254,18 @@ impl LengthOrPercentage {
match *self {
Length(l) => (l, NotNaN::new(0.0).unwrap()),
Percentage(p) => (Au(0), NotNaN::new(p).unwrap()),
- Calc(c) => (c.length(), NotNaN::new(c.percentage()).unwrap()),
+ Calc(c) => (c.unclamped_length(), NotNaN::new(c.percentage()).unwrap()),
+ }
+ }
+
+ /// Returns the used value.
+ pub fn to_used_value(&self, containing_length: Au) -> Au {
+ match *self {
+ LengthOrPercentage::Length(length) => length,
+ LengthOrPercentage::Percentage(p) => containing_length.scale_by(p),
+ LengthOrPercentage::Calc(ref calc) => {
+ calc.to_used_value(Some(containing_length)).unwrap()
+ },
}
}
}
@@ -481,6 +514,18 @@ pub enum LengthOrPercentageOrNone {
None,
}
+impl LengthOrPercentageOrNone {
+ /// Returns the used value.
+ pub fn to_used_value(&self, containing_length: Au) -> Option<Au> {
+ match *self {
+ LengthOrPercentageOrNone::None => None,
+ LengthOrPercentageOrNone::Length(length) => Some(length),
+ LengthOrPercentageOrNone::Percentage(percent) => Some(containing_length.scale_by(percent)),
+ LengthOrPercentageOrNone::Calc(ref calc) => calc.to_used_value(Some(containing_length)),
+ }
+ }
+}
+
impl fmt::Debug for LengthOrPercentageOrNone {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs
index 02a71c6b313..7101192be1a 100644
--- a/components/style/values/computed/mod.rs
+++ b/components/style/values/computed/mod.rs
@@ -19,6 +19,7 @@ use super::{CSSFloat, CSSInteger, RGBA};
use super::generics::BorderRadiusSize as GenericBorderRadiusSize;
use super::specified;
use super::specified::grid::{TrackBreadth as GenericTrackBreadth, TrackSize as GenericTrackSize};
+use super::specified::grid::TrackList as GenericTrackList;
pub use app_units::Au;
pub use cssparser::Color as CSSColor;
@@ -595,6 +596,13 @@ pub type TrackBreadth = GenericTrackBreadth<LengthOrPercentage>;
/// The computed value of a grid `<track-size>`
pub type TrackSize = GenericTrackSize<LengthOrPercentage>;
+/// The computed value of a grid `<track-list>`
+/// (could also be `<auto-track-list>` or `<explicit-track-list>`)
+pub type TrackList = GenericTrackList<TrackSize>;
+
+/// `<track-list> | none`
+pub type TrackListOrNone = Either<TrackList, None_>;
+
impl ClipRectOrAuto {
/// Return an auto (default for clip-rect and image-region) value
pub fn auto() -> Self {
diff --git a/components/style/values/specified/calc.rs b/components/style/values/specified/calc.rs
index 4f49df256e7..4db36e998c2 100644
--- a/components/style/values/specified/calc.rs
+++ b/components/style/values/specified/calc.rs
@@ -12,6 +12,7 @@ use parser::ParserContext;
use std::ascii::AsciiExt;
use std::fmt;
use style_traits::ToCss;
+use style_traits::values::specified::AllowedLengthType;
use values::{CSSInteger, CSSFloat, HasViewportPercentage};
use values::specified::{Angle, Time};
use values::specified::length::{FontRelativeLength, NoCalcLength, ViewportPercentageLength};
@@ -63,6 +64,7 @@ pub enum CalcUnit {
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct CalcLengthOrPercentage {
+ pub clamping_mode: AllowedLengthType,
pub absolute: Option<Au>,
pub vw: Option<CSSFloat>,
pub vh: Option<CSSFloat>,
@@ -271,8 +273,12 @@ impl CalcNode {
/// Tries to simplify this expression into a `<length>` or `<percentage`>
/// value.
- fn to_length_or_percentage(&self) -> Result<CalcLengthOrPercentage, ()> {
- let mut ret = CalcLengthOrPercentage::default();
+ fn to_length_or_percentage(&self, clamping_mode: AllowedLengthType)
+ -> Result<CalcLengthOrPercentage, ()> {
+ let mut ret = CalcLengthOrPercentage {
+ clamping_mode: clamping_mode,
+ .. Default::default()
+ };
self.add_length_or_percentage_to(&mut ret, 1.0)?;
Ok(ret)
}
@@ -498,21 +504,23 @@ impl CalcNode {
/// Convenience parsing function for `<length> | <percentage>`.
pub fn parse_length_or_percentage(
context: &ParserContext,
- input: &mut Parser)
+ input: &mut Parser,
+ clamping_mode: AllowedLengthType)
-> Result<CalcLengthOrPercentage, ()>
{
Self::parse(context, input, CalcUnit::LengthOrPercentage)?
- .to_length_or_percentage()
+ .to_length_or_percentage(clamping_mode)
}
/// Convenience parsing function for `<length>`.
pub fn parse_length(
context: &ParserContext,
- input: &mut Parser)
+ input: &mut Parser,
+ clamping_mode: AllowedLengthType)
-> Result<CalcLengthOrPercentage, ()>
{
Self::parse(context, input, CalcUnit::Length)?
- .to_length_or_percentage()
+ .to_length_or_percentage(clamping_mode)
}
/// Convenience parsing function for `<number>`.
diff --git a/components/style/values/specified/color.rs b/components/style/values/specified/color.rs
index 4c0d50f0e54..0599563a494 100644
--- a/components/style/values/specified/color.rs
+++ b/components/style/values/specified/color.rs
@@ -53,13 +53,19 @@ mod gecko {
no_viewport_percentage!(Color);
+ impl From<CSSParserColor> for Color {
+ fn from(value: CSSParserColor) -> Self {
+ match value {
+ CSSParserColor::CurrentColor => Color::CurrentColor,
+ CSSParserColor::RGBA(x) => Color::RGBA(x),
+ }
+ }
+ }
+
impl Parse for Color {
fn parse(_: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
if let Ok(value) = input.try(CSSParserColor::parse) {
- match value {
- CSSParserColor::CurrentColor => Ok(Color::CurrentColor),
- CSSParserColor::RGBA(x) => Ok(Color::RGBA(x)),
- }
+ Ok(value.into())
} else if let Ok(system) = input.try(SystemColor::parse) {
Ok(Color::System(system))
} else {
diff --git a/components/style/values/specified/grid.rs b/components/style/values/specified/grid.rs
index 92dbc4fbcaa..45f888d9702 100644
--- a/components/style/values/specified/grid.rs
+++ b/components/style/values/specified/grid.rs
@@ -4,21 +4,20 @@
//! Necessary types for [grid](https://drafts.csswg.org/css-grid/).
-use cssparser::{Parser, Token};
+use cssparser::{Parser, Token, serialize_identifier};
use parser::{Parse, ParserContext};
+use std::{fmt, mem, usize};
use std::ascii::AsciiExt;
-use std::fmt;
use style_traits::ToCss;
-use values::{CSSFloat, HasViewportPercentage};
-use values::computed::{ComputedValueAsSpecified, Context, ToComputedValue};
-use values::specified::LengthOrPercentage;
+use values::{CSSFloat, CustomIdent, Either, HasViewportPercentage};
+use values::computed::{self, ComputedValueAsSpecified, Context, ToComputedValue};
+use values::specified::{Integer, LengthOrPercentage};
#[derive(PartialEq, Clone, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// A `<grid-line>` type.
///
/// https://drafts.csswg.org/css-grid/#typedef-grid-row-start-grid-line
-#[allow(missing_docs)]
pub struct GridLine {
/// Flag to check whether it's a `span` keyword.
pub is_span: bool,
@@ -27,7 +26,14 @@ pub struct GridLine {
/// https://drafts.csswg.org/css-grid/#grid-placement-slot
pub ident: Option<String>,
/// Denotes the nth grid line from grid item's placement.
- pub integer: Option<i32>,
+ pub line_num: Option<Integer>,
+}
+
+impl GridLine {
+ /// Check whether this `<grid-line>` represents an `auto` value.
+ pub fn is_auto(&self) -> bool {
+ self.ident.is_none() && self.line_num.is_none() && !self.is_span
+ }
}
impl Default for GridLine {
@@ -35,27 +41,28 @@ impl Default for GridLine {
GridLine {
is_span: false,
ident: None,
- integer: None,
+ line_num: None,
}
}
}
impl ToCss for GridLine {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- if !self.is_span && self.ident.is_none() && self.integer.is_none() {
+ if self.is_auto() {
return dest.write_str("auto")
}
if self.is_span {
- try!(dest.write_str("span"));
+ dest.write_str("span")?;
}
- if let Some(i) = self.integer {
- try!(write!(dest, " {}", i));
+ if let Some(i) = self.line_num {
+ write!(dest, " {}", i.value)?;
}
if let Some(ref s) = self.ident {
- try!(write!(dest, " {}", s));
+ dest.write_str(" ")?;
+ serialize_identifier(s, dest)?;
}
Ok(())
@@ -63,7 +70,7 @@ impl ToCss for GridLine {
}
impl Parse for GridLine {
- fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+ fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
let mut grid_line = Default::default();
if input.try(|i| i.expect_ident_matching("auto")).is_ok() {
return Ok(grid_line)
@@ -71,17 +78,17 @@ impl Parse for GridLine {
for _ in 0..3 { // Maximum possible entities for <grid-line>
if input.try(|i| i.expect_ident_matching("span")).is_ok() {
- if grid_line.is_span {
- return Err(())
+ if grid_line.is_span || grid_line.line_num.is_some() || grid_line.ident.is_some() {
+ return Err(()) // span (if specified) should be first
}
- grid_line.is_span = true;
- } else if let Ok(i) = input.try(|i| i.expect_integer()) {
- if i == 0 || grid_line.integer.is_some() {
+ grid_line.is_span = true; // span (if specified) should be first
+ } else if let Ok(i) = input.try(|i| Integer::parse(context, i)) {
+ if i.value == 0 || grid_line.line_num.is_some() {
return Err(())
}
- grid_line.integer = Some(i);
+ grid_line.line_num = Some(i);
} else if let Ok(name) = input.try(|i| i.expect_ident()) {
- if grid_line.ident.is_some() {
+ if grid_line.ident.is_some() || CustomIdent::from_ident((&*name).into(), &[]).is_err() {
return Err(())
}
grid_line.ident = Some(name.into_owned());
@@ -90,13 +97,19 @@ impl Parse for GridLine {
}
}
+ if grid_line.is_auto() {
+ return Err(())
+ }
+
if grid_line.is_span {
- if let Some(i) = grid_line.integer {
- if i < 0 { // disallow negative integers for grid spans
+ if let Some(i) = grid_line.line_num {
+ if i.value <= 0 { // disallow negative integers for grid spans
return Err(())
}
+ } else if grid_line.ident.is_some() { // integer could be omitted
+ grid_line.line_num = Some(Integer::new(1));
} else {
- grid_line.integer = Some(1);
+ return Err(())
}
}
@@ -128,9 +141,22 @@ pub enum TrackBreadth<L> {
Keyword(TrackKeyword),
}
+impl<L> TrackBreadth<L> {
+ /// Check whether this is a `<fixed-breadth>` (i.e., it only has `<length-percentage>`)
+ ///
+ /// https://drafts.csswg.org/css-grid/#typedef-fixed-breadth
+ #[inline]
+ pub fn is_fixed(&self) -> bool {
+ match *self {
+ TrackBreadth::Breadth(ref _lop) => true,
+ _ => false,
+ }
+ }
+}
+
/// Parse a single flexible length.
pub fn parse_flex(input: &mut Parser) -> Result<CSSFloat, ()> {
- match try!(input.next()) {
+ match input.next()? {
Token::Dimension(ref value, ref unit) if unit.eq_ignore_ascii_case("fr") && value.value.is_sign_positive()
=> Ok(value.value),
_ => Err(()),
@@ -215,6 +241,32 @@ pub enum TrackSize<L> {
FitContent(L),
}
+impl<L> TrackSize<L> {
+ /// Check whether this is a `<fixed-size>`
+ ///
+ /// https://drafts.csswg.org/css-grid/#typedef-fixed-size
+ pub fn is_fixed(&self) -> bool {
+ match *self {
+ TrackSize::Breadth(ref breadth) => breadth.is_fixed(),
+ // For minmax function, it could be either
+ // minmax(<fixed-breadth>, <track-breadth>) or minmax(<inflexible-breadth>, <fixed-breadth>),
+ // and since both variants are a subset of minmax(<inflexible-breadth>, <track-breadth>), we only
+ // need to make sure that they're fixed. So, we don't have to modify the parsing function.
+ TrackSize::MinMax(ref breadth_1, ref breadth_2) => {
+ if breadth_1.is_fixed() {
+ return true // the second value is always a <track-breadth>
+ }
+
+ match *breadth_1 {
+ TrackBreadth::Flex(_) => false, // should be <inflexible-breadth> at this point
+ _ => breadth_2.is_fixed(),
+ }
+ },
+ TrackSize::FitContent(_) => false,
+ }
+ }
+}
+
impl<L> Default for TrackSize<L> {
fn default() -> Self {
TrackSize::Breadth(TrackBreadth::Keyword(TrackKeyword::Auto))
@@ -233,19 +285,19 @@ impl Parse for TrackSize<LengthOrPercentage> {
match input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
Ok(lop) => TrackBreadth::Breadth(lop),
Err(..) => {
- let keyword = try!(TrackKeyword::parse(input));
+ let keyword = TrackKeyword::parse(input)?;
TrackBreadth::Keyword(keyword)
}
};
- try!(input.expect_comma());
- Ok(TrackSize::MinMax(inflexible_breadth, try!(TrackBreadth::parse(context, input))))
+ input.expect_comma()?;
+ Ok(TrackSize::MinMax(inflexible_breadth, TrackBreadth::parse(context, input)?))
});
}
- try!(input.expect_function_matching("fit-content"));
- // FIXME(emilio): This needs a parse_nested_block, doesn't it?
- Ok(try!(LengthOrPercentage::parse(context, input).map(TrackSize::FitContent)))
+ input.expect_function_matching("fit-content")?;
+ let lop = input.parse_nested_block(|i| LengthOrPercentage::parse_non_negative(context, i))?;
+ Ok(TrackSize::FitContent(lop))
}
}
@@ -254,15 +306,15 @@ impl<L: ToCss> ToCss for TrackSize<L> {
match *self {
TrackSize::Breadth(ref b) => b.to_css(dest),
TrackSize::MinMax(ref infexible, ref flexible) => {
- try!(dest.write_str("minmax("));
- try!(infexible.to_css(dest));
- try!(dest.write_str(","));
- try!(flexible.to_css(dest));
+ dest.write_str("minmax(")?;
+ infexible.to_css(dest)?;
+ dest.write_str(", ")?;
+ flexible.to_css(dest)?;
dest.write_str(")")
},
TrackSize::FitContent(ref lop) => {
- try!(dest.write_str("fit-content("));
- try!(lop.to_css(dest));
+ dest.write_str("fit-content(")?;
+ lop.to_css(dest)?;
dest.write_str(")")
},
}
@@ -286,7 +338,13 @@ impl<L: ToComputedValue> ToComputedValue for TrackSize<L> {
#[inline]
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
match *self {
- TrackSize::Breadth(ref b) => TrackSize::Breadth(b.to_computed_value(context)),
+ TrackSize::Breadth(ref b) => match *b {
+ // <flex> outside `minmax()` expands to `mimmax(auto, <flex>)`
+ // https://drafts.csswg.org/css-grid/#valdef-grid-template-columns-flex
+ TrackBreadth::Flex(f) =>
+ TrackSize::MinMax(TrackBreadth::Keyword(TrackKeyword::Auto), TrackBreadth::Flex(f)),
+ _ => TrackSize::Breadth(b.to_computed_value(context)),
+ },
TrackSize::MinMax(ref b_1, ref b_2) =>
TrackSize::MinMax(b_1.to_computed_value(context), b_2.to_computed_value(context)),
TrackSize::FitContent(ref lop) => TrackSize::FitContent(lop.to_computed_value(context)),
@@ -306,3 +364,532 @@ impl<L: ToComputedValue> ToComputedValue for TrackSize<L> {
}
}
}
+
+/// Parse the grid line names into a vector of owned strings.
+///
+/// https://drafts.csswg.org/css-grid/#typedef-line-names
+pub fn parse_line_names(input: &mut Parser) -> Result<Vec<String>, ()> {
+ input.expect_square_bracket_block()?;
+ input.parse_nested_block(|input| {
+ let mut values = vec![];
+ while let Ok(ident) = input.try(|i| i.expect_ident()) {
+ if CustomIdent::from_ident((&*ident).into(), &["span"]).is_err() {
+ return Err(())
+ }
+
+ values.push(ident.into_owned());
+ }
+
+ Ok(values)
+ })
+}
+
+fn concat_serialize_idents<W>(prefix: &str, suffix: &str,
+ slice: &[String], sep: &str, dest: &mut W) -> fmt::Result
+ where W: fmt::Write
+{
+ if let Some((ref first, rest)) = slice.split_first() {
+ dest.write_str(prefix)?;
+ serialize_identifier(first, dest)?;
+ for thing in rest {
+ dest.write_str(sep)?;
+ serialize_identifier(thing, dest)?;
+ }
+
+ dest.write_str(suffix)?;
+ }
+
+ Ok(())
+}
+
+/// The initial argument of the `repeat` function.
+///
+/// https://drafts.csswg.org/css-grid/#typedef-track-repeat
+#[derive(Clone, Copy, PartialEq, Debug)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub enum RepeatCount {
+ /// A positive integer. This is allowed only for `<track-repeat>` and `<fixed-repeat>`
+ Number(Integer),
+ /// An `<auto-fill>` keyword allowed only for `<auto-repeat>`
+ AutoFill,
+ /// An `<auto-fit>` keyword allowed only for `<auto-repeat>`
+ AutoFit,
+}
+
+impl Parse for RepeatCount {
+ fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+ if let Ok(i) = input.try(|i| Integer::parse(context, i)) {
+ if i.value > 0 {
+ Ok(RepeatCount::Number(i))
+ } else {
+ Err(())
+ }
+ } else {
+ match_ignore_ascii_case! { &input.expect_ident()?,
+ "auto-fill" => Ok(RepeatCount::AutoFill),
+ "auto-fit" => Ok(RepeatCount::AutoFit),
+ _ => Err(()),
+ }
+ }
+ }
+}
+
+impl ToCss for RepeatCount {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ match *self {
+ RepeatCount::Number(ref c) => c.to_css(dest),
+ RepeatCount::AutoFill => dest.write_str("auto-fill"),
+ RepeatCount::AutoFit => dest.write_str("auto-fit"),
+ }
+ }
+}
+
+impl ComputedValueAsSpecified for RepeatCount {}
+no_viewport_percentage!(RepeatCount);
+
+/// The type of `repeat` function (only used in parsing).
+///
+/// https://drafts.csswg.org/css-grid/#typedef-track-repeat
+#[derive(Clone, Copy, PartialEq, Debug)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+enum RepeatType {
+ /// [`<auto-repeat>`](https://drafts.csswg.org/css-grid/#typedef-auto-repeat)
+ Auto,
+ /// [`<track-repeat>`](https://drafts.csswg.org/css-grid/#typedef-track-repeat)
+ Normal,
+ /// [`<fixed-repeat>`](https://drafts.csswg.org/css-grid/#typedef-fixed-repeat)
+ Fixed,
+}
+
+/// The structure containing `<line-names>` and `<track-size>` values.
+///
+/// It can also hold `repeat()` function parameters, which expands into the respective
+/// values in its computed form.
+#[derive(Clone, PartialEq, Debug)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub struct TrackRepeat<L> {
+ /// The number of times for the value to be repeated (could also be `auto-fit` or `auto-fill`)
+ pub count: RepeatCount,
+ /// `<line-names>` accompanying `<track_size>` values.
+ ///
+ /// If there's no `<line-names>`, then it's represented by an empty vector.
+ /// For N `<track-size>` values, there will be N+1 `<line-names>`, and so this vector's
+ /// length is always one value more than that of the `<track-size>`.
+ pub line_names: Vec<Vec<String>>,
+ /// `<track-size>` values.
+ pub track_sizes: Vec<TrackSize<L>>,
+}
+
+impl TrackRepeat<LengthOrPercentage> {
+ fn parse_with_repeat_type(context: &ParserContext, input: &mut Parser)
+ -> Result<(TrackRepeat<LengthOrPercentage>, RepeatType), ()> {
+ input.try(|i| i.expect_function_matching("repeat")).and_then(|_| {
+ input.parse_nested_block(|input| {
+ let count = RepeatCount::parse(context, input)?;
+ input.expect_comma()?;
+
+ let is_auto = count == RepeatCount::AutoFit || count == RepeatCount::AutoFill;
+ let mut repeat_type = if is_auto {
+ RepeatType::Auto
+ } else { // <fixed-size> is a subset of <track_size>, so it should work for both
+ RepeatType::Fixed
+ };
+
+ let mut names = vec![];
+ let mut values = vec![];
+ let mut current_names;
+
+ loop {
+ current_names = input.try(parse_line_names).unwrap_or(vec![]);
+ if let Ok(track_size) = input.try(|i| TrackSize::parse(context, i)) {
+ if !track_size.is_fixed() {
+ if is_auto {
+ return Err(()) // should be <fixed-size> for <auto-repeat>
+ }
+
+ if repeat_type == RepeatType::Fixed {
+ repeat_type = RepeatType::Normal // <track-size> for sure
+ }
+ }
+
+ values.push(track_size);
+ names.push(current_names);
+ } else {
+ if values.is_empty() {
+ return Err(()) // expecting at least one <track-size>
+ }
+
+ names.push(current_names); // final `<line-names>`
+ break // no more <track-size>, breaking
+ }
+ }
+
+ let repeat = TrackRepeat {
+ count: count,
+ track_sizes: values,
+ line_names: names,
+ };
+
+ Ok((repeat, repeat_type))
+ })
+ })
+ }
+}
+
+impl<L: ToCss> ToCss for TrackRepeat<L> {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ dest.write_str("repeat(")?;
+ self.count.to_css(dest)?;
+ dest.write_str(", ")?;
+
+ let mut line_names_iter = self.line_names.iter();
+ for (i, (ref size, ref names)) in self.track_sizes.iter()
+ .zip(&mut line_names_iter).enumerate() {
+ if i > 0 {
+ dest.write_str(" ")?;
+ }
+
+ concat_serialize_idents("[", "] ", names, " ", dest)?;
+ size.to_css(dest)?;
+ }
+
+ if let Some(line_names_last) = line_names_iter.next() {
+ concat_serialize_idents(" [", "]", line_names_last, " ", dest)?;
+ }
+
+ dest.write_str(")")?;
+ Ok(())
+ }
+}
+
+impl HasViewportPercentage for TrackRepeat<LengthOrPercentage> {
+ #[inline]
+ fn has_viewport_percentage(&self) -> bool {
+ self.track_sizes.iter().any(|ref v| v.has_viewport_percentage())
+ }
+}
+
+impl<L: ToComputedValue> ToComputedValue for TrackRepeat<L> {
+ type ComputedValue = TrackRepeat<L::ComputedValue>;
+
+ #[inline]
+ fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
+ // If the repeat count is numeric, then expand the values and merge accordingly.
+ if let RepeatCount::Number(num) = self.count {
+ let mut line_names = vec![];
+ let mut track_sizes = vec![];
+ let mut prev_names = vec![];
+
+ for _ in 0..num.value {
+ let mut names_iter = self.line_names.iter();
+ for (size, names) in self.track_sizes.iter().zip(&mut names_iter) {
+ prev_names.extend_from_slice(&names);
+ line_names.push(mem::replace(&mut prev_names, vec![]));
+ track_sizes.push(size.to_computed_value(context));
+ }
+
+ if let Some(names) = names_iter.next() {
+ prev_names.extend_from_slice(&names);
+ }
+ }
+
+ line_names.push(prev_names);
+ TrackRepeat {
+ count: self.count,
+ track_sizes: track_sizes,
+ line_names: line_names,
+ }
+
+ } else { // if it's auto-fit/auto-fill, then it's left to the layout.
+ TrackRepeat {
+ count: self.count,
+ track_sizes: self.track_sizes.iter()
+ .map(|l| l.to_computed_value(context))
+ .collect(),
+ line_names: self.line_names.clone(),
+ }
+ }
+ }
+
+ #[inline]
+ fn from_computed_value(computed: &Self::ComputedValue) -> Self {
+ TrackRepeat {
+ count: computed.count,
+ track_sizes: computed.track_sizes.iter()
+ .map(ToComputedValue::from_computed_value)
+ .collect(),
+ line_names: computed.line_names.clone(),
+ }
+ }
+}
+
+/// The type of a `<track-list>` as determined during parsing.
+///
+/// https://drafts.csswg.org/css-grid/#typedef-track-list
+#[derive(Clone, Copy, PartialEq, Debug)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub enum TrackListType {
+ /// [`<auto-track-list>`](https://drafts.csswg.org/css-grid/#typedef-auto-track-list)
+ ///
+ /// If this type exists, then the value at the index in `line_names` field in `TrackList`
+ /// has the `<line-names>?` list that comes before `<auto-repeat>`. If it's a specified value,
+ /// then the `repeat()` function (that follows the line names list) is also at the given index
+ /// in `values` field. On the contrary, if it's a computed value, then the `repeat()` function
+ /// is in the `auto_repeat` field.
+ Auto(u16),
+ /// [`<track-list>`](https://drafts.csswg.org/css-grid/#typedef-track-list)
+ Normal,
+ /// [`<explicit-track-list>`](https://drafts.csswg.org/css-grid/#typedef-explicit-track-list)
+ ///
+ /// Note that this is a subset of the normal `<track-list>`, and so it could be used in place
+ /// of the latter.
+ Explicit,
+}
+
+/// A grid `<track-list>` type.
+///
+/// https://drafts.csswg.org/css-grid/#typedef-track-list
+#[derive(Clone, PartialEq, Debug)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub struct TrackList<T> {
+ /// The type of this `<track-list>` (auto, explicit or general).
+ ///
+ /// In order to avoid parsing the same value multiple times, this does a single traversal
+ /// and arrives at the type of value it has parsed (or bails out gracefully with an error).
+ pub list_type: TrackListType,
+ /// A vector of `<track-size> | <track-repeat>` values. In its specified form, it may contain
+ /// any value, but once it's computed, it contains only `<track_size>` values.
+ ///
+ /// Note that this may also contain `<auto-repeat>` at an index. If it exists, it's
+ /// given by the index in `TrackListType::Auto`
+ pub values: Vec<T>,
+ /// `<line-names>` accompanying `<track-size> | <track-repeat>` values.
+ ///
+ /// If there's no `<line-names>`, then it's represented by an empty vector.
+ /// For N values, there will be N+1 `<line-names>`, and so this vector's
+ /// length is always one value more than that of the `<track-size>`.
+ pub line_names: Vec<Vec<String>>,
+ /// `<auto-repeat>` value after computation. This field is necessary, because
+ /// the `values` field (after computation) will only contain `<track-size>` values, and
+ /// we need something to represent this function.
+ pub auto_repeat: Option<TrackRepeat<computed::LengthOrPercentage>>,
+}
+
+/// Either a `<track-size>` or `<track-repeat>` component of `<track-list>`
+///
+/// This is required only for the specified form of `<track-list>`, and will become
+/// `TrackSize<LengthOrPercentage>` in its computed form.
+pub type TrackSizeOrRepeat = Either<TrackSize<LengthOrPercentage>, TrackRepeat<LengthOrPercentage>>;
+
+impl Parse for TrackList<TrackSizeOrRepeat> {
+ fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+ let mut current_names;
+ let mut names = vec![];
+ let mut values = vec![];
+
+ let mut list_type = TrackListType::Explicit; // assume it's the simplest case
+ // marker to check whether we've already encountered <auto-repeat> along the way
+ let mut is_auto = false;
+ // assume that everything is <fixed-size>. This flag is useful when we encounter <auto-repeat>
+ let mut atleast_one_not_fixed = false;
+
+ loop {
+ current_names = input.try(parse_line_names).unwrap_or(vec![]);
+ if let Ok(track_size) = input.try(|i| TrackSize::parse(context, i)) {
+ if !track_size.is_fixed() {
+ atleast_one_not_fixed = true;
+ if is_auto {
+ return Err(()) // <auto-track-list> only accepts <fixed-size> and <fixed-repeat>
+ }
+ }
+
+ names.push(current_names);
+ values.push(Either::First(track_size));
+ } else if let Ok((repeat, type_)) = input.try(|i| TrackRepeat::parse_with_repeat_type(context, i)) {
+ if list_type == TrackListType::Explicit {
+ list_type = TrackListType::Normal; // <explicit-track-list> doesn't contain repeat()
+ }
+
+ match type_ {
+ RepeatType::Normal => {
+ atleast_one_not_fixed = true;
+ if is_auto { // only <fixed-repeat>
+ return Err(())
+ }
+ },
+ RepeatType::Auto => {
+ if is_auto || atleast_one_not_fixed {
+ // We've either seen <auto-repeat> earlier, or there's at least one non-fixed value
+ return Err(())
+ }
+
+ is_auto = true;
+ list_type = TrackListType::Auto(values.len() as u16);
+ },
+ RepeatType::Fixed => (),
+ }
+
+ names.push(current_names);
+ values.push(Either::Second(repeat));
+ } else {
+ if values.is_empty() {
+ return Err(())
+ }
+
+ names.push(current_names);
+ break
+ }
+ }
+
+ Ok(TrackList {
+ list_type: list_type,
+ values: values,
+ line_names: names,
+ auto_repeat: None, // filled only in computation
+ })
+ }
+}
+
+impl<T: ToCss> ToCss for TrackList<T> {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ let auto_idx = match self.list_type {
+ TrackListType::Auto(i) => i as usize,
+ _ => usize::MAX,
+ };
+
+ let mut values_iter = self.values.iter().peekable();
+ let mut line_names_iter = self.line_names.iter().peekable();
+
+ for idx in 0.. {
+ let names = line_names_iter.next().unwrap(); // This should exist!
+ concat_serialize_idents("[", "]", names, " ", dest)?;
+
+ match self.auto_repeat {
+ Some(ref repeat) if idx == auto_idx => {
+ if !names.is_empty() {
+ dest.write_str(" ")?;
+ }
+
+ repeat.to_css(dest)?;
+ },
+ _ => match values_iter.next() {
+ Some(value) => {
+ if !names.is_empty() {
+ dest.write_str(" ")?;
+ }
+
+ value.to_css(dest)?;
+ },
+ None => break,
+ },
+ }
+
+ if values_iter.peek().is_some() || line_names_iter.peek().map_or(false, |v| !v.is_empty()) {
+ dest.write_str(" ")?;
+ }
+ }
+
+ Ok(())
+ }
+}
+
+impl HasViewportPercentage for TrackList<TrackSizeOrRepeat> {
+ #[inline]
+ fn has_viewport_percentage(&self) -> bool {
+ self.values.iter().any(|ref v| v.has_viewport_percentage())
+ }
+}
+
+impl ToComputedValue for TrackList<TrackSizeOrRepeat> {
+ type ComputedValue = TrackList<TrackSize<computed::LengthOrPercentage>>;
+
+ #[inline]
+ fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
+ // Merge the line names while computing values. The resulting values will
+ // all be a bunch of `<track-size>`.
+ //
+ // For example,
+ // `[a b] 100px [c d] repeat(1, 30px [g]) [h]` will be merged as `[a b] 100px [c d] 30px [g h]`
+ // whereas, `[a b] repeat(2, [c] 50px [d]) [e f] repeat(auto-fill, [g] 12px) 10px [h]` will be merged as
+ // `[a b c] 50px [d c] 50px [d e f] repeat(auto-fill, [g] 12px) 10px [h]`, with the `<auto-repeat>` value
+ // set in the `auto_repeat` field, and the `idx` in TrackListType::Auto pointing to the values after
+ // `<auto-repeat>` (in this case, `10px [h]`).
+ let mut line_names = vec![];
+ let mut list_type = self.list_type;
+ let mut values = vec![];
+ let mut prev_names = vec![];
+ let mut auto_repeat = None;
+
+ let mut names_iter = self.line_names.iter();
+ for (size_or_repeat, names) in self.values.iter().zip(&mut names_iter) {
+ prev_names.extend_from_slice(names);
+
+ match *size_or_repeat {
+ Either::First(ref size) => values.push(size.to_computed_value(context)),
+ Either::Second(ref repeat) => {
+ let mut computed = repeat.to_computed_value(context);
+ if computed.count == RepeatCount::AutoFit || computed.count == RepeatCount::AutoFill {
+ line_names.push(mem::replace(&mut prev_names, vec![])); // don't merge for auto
+ list_type = TrackListType::Auto(values.len() as u16);
+ auto_repeat = Some(computed);
+ continue
+ }
+
+ let mut repeat_names_iter = computed.line_names.drain(..);
+ for (size, mut names) in computed.track_sizes.drain(..).zip(&mut repeat_names_iter) {
+ prev_names.append(&mut names);
+ line_names.push(mem::replace(&mut prev_names, vec![]));
+ values.push(size);
+ }
+
+ if let Some(mut names) = repeat_names_iter.next() {
+ prev_names.append(&mut names);
+ }
+
+ continue // last `<line-names>` in repeat() may merge with the next set
+ }
+ }
+
+ line_names.push(mem::replace(&mut prev_names, vec![]));
+ }
+
+ if let Some(names) = names_iter.next() {
+ prev_names.extend_from_slice(names);
+ }
+
+ line_names.push(mem::replace(&mut prev_names, vec![]));
+
+ TrackList {
+ list_type: list_type,
+ values: values,
+ line_names: line_names,
+ auto_repeat: auto_repeat,
+ }
+ }
+
+ #[inline]
+ fn from_computed_value(computed: &Self::ComputedValue) -> Self {
+ let auto_idx = if let TrackListType::Auto(idx) = computed.list_type {
+ idx as usize
+ } else {
+ usize::MAX
+ };
+
+ let mut values = Vec::with_capacity(computed.values.len() + 1);
+ for (i, value) in computed.values.iter().map(ToComputedValue::from_computed_value).enumerate() {
+ if i == auto_idx {
+ let value = TrackRepeat::from_computed_value(computed.auto_repeat.as_ref().unwrap());
+ values.push(Either::Second(value));
+ }
+
+ values.push(Either::First(value));
+ }
+
+ TrackList {
+ list_type: computed.list_type,
+ values: values,
+ line_names: computed.line_names.clone(),
+ auto_repeat: None,
+ }
+ }
+}
diff --git a/components/style/values/specified/length.rs b/components/style/values/specified/length.rs
index 7a6f6259732..d117593738c 100644
--- a/components/style/values/specified/length.rs
+++ b/components/style/values/specified/length.rs
@@ -539,7 +539,7 @@ pub enum Length {
/// A calc expression.
///
/// https://drafts.csswg.org/css-values/#calc-notation
- Calc(AllowedLengthType, Box<CalcLengthOrPercentage>),
+ Calc(Box<CalcLengthOrPercentage>),
}
impl From<NoCalcLength> for Length {
@@ -553,7 +553,7 @@ impl HasViewportPercentage for Length {
fn has_viewport_percentage(&self) -> bool {
match *self {
Length::NoCalc(ref inner) => inner.has_viewport_percentage(),
- Length::Calc(_, ref calc) => calc.has_viewport_percentage(),
+ Length::Calc(ref calc) => calc.has_viewport_percentage(),
}
}
}
@@ -562,7 +562,7 @@ impl ToCss for Length {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
Length::NoCalc(ref inner) => inner.to_css(dest),
- Length::Calc(_, ref calc) => calc.to_css(dest),
+ Length::Calc(ref calc) => calc.to_css(dest),
}
}
}
@@ -637,10 +637,7 @@ impl Length {
},
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") =>
input.parse_nested_block(|input| {
- CalcNode::parse_length(context, input)
- .map(|calc| {
- Length::Calc(num_context, Box::new(calc))
- })
+ CalcNode::parse_length(context, input, num_context).map(|calc| Length::Calc(Box::new(calc)))
}),
_ => Err(())
}
@@ -770,7 +767,7 @@ impl From<Length> for LengthOrPercentage {
fn from(len: Length) -> LengthOrPercentage {
match len {
Length::NoCalc(l) => LengthOrPercentage::Length(l),
- Length::Calc(_, l) => LengthOrPercentage::Calc(l),
+ Length::Calc(l) => LengthOrPercentage::Calc(l),
}
}
}
@@ -832,7 +829,7 @@ impl LengthOrPercentage {
Ok(LengthOrPercentage::Length(NoCalcLength::from_px(value.value))),
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
let calc = try!(input.parse_nested_block(|i| {
- CalcNode::parse_length_or_percentage(context, i)
+ CalcNode::parse_length_or_percentage(context, i, num_context)
}));
Ok(LengthOrPercentage::Calc(Box::new(calc)))
},
@@ -986,7 +983,7 @@ impl LengthOrPercentageOrAuto {
Ok(LengthOrPercentageOrAuto::Auto),
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
let calc = try!(input.parse_nested_block(|i| {
- CalcNode::parse_length_or_percentage(context, i)
+ CalcNode::parse_length_or_percentage(context, i, num_context)
}));
Ok(LengthOrPercentageOrAuto::Calc(Box::new(calc)))
},
@@ -1092,7 +1089,7 @@ impl LengthOrPercentageOrNone {
}
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
let calc = try!(input.parse_nested_block(|i| {
- CalcNode::parse_length_or_percentage(context, i)
+ CalcNode::parse_length_or_percentage(context, i, num_context)
}));
Ok(LengthOrPercentageOrNone::Calc(Box::new(calc)))
},
@@ -1169,7 +1166,7 @@ impl LengthOrPercentageOrAutoOrContent {
Ok(LengthOrPercentageOrAutoOrContent::Content),
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
let calc = try!(input.parse_nested_block(|i| {
- CalcNode::parse_length_or_percentage(context, i)
+ CalcNode::parse_length_or_percentage(context, i, num_context)
}));
Ok(LengthOrPercentageOrAutoOrContent::Calc(Box::new(calc)))
},
diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs
index 04df41c542a..3fb46c473b9 100644
--- a/components/style/values/specified/mod.rs
+++ b/components/style/values/specified/mod.rs
@@ -10,12 +10,15 @@ use app_units::Au;
use context::QuirksMode;
use cssparser::{self, Parser, Token};
use euclid::size::Size2D;
+use itoa;
use parser::{ParserContext, Parse};
use self::grid::{TrackBreadth as GenericTrackBreadth, TrackSize as GenericTrackSize};
+use self::grid::{TrackList as GenericTrackList, TrackSizeOrRepeat};
use self::url::SpecifiedUrl;
use std::ascii::AsciiExt;
use std::f32;
use std::fmt;
+use std::io::Write;
use style_traits::ToCss;
use style_traits::values::specified::AllowedNumericType;
use super::{Auto, CSSFloat, CSSInteger, HasViewportPercentage, Either, None_};
@@ -85,15 +88,89 @@ pub struct CSSColor {
impl Parse for CSSColor {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+ Self::parse_quirky(context, input, AllowQuirks::No)
+ }
+}
+
+impl CSSColor {
+ /// Parse a color, with quirks.
+ ///
+ /// https://quirks.spec.whatwg.org/#the-hashless-hex-color-quirk
+ pub fn parse_quirky(context: &ParserContext,
+ input: &mut Parser,
+ allow_quirks: AllowQuirks)
+ -> Result<Self, ()> {
let start_position = input.position();
let authored = match input.next() {
Ok(Token::Ident(s)) => Some(s.into_owned().into_boxed_str()),
_ => None,
};
input.reset(start_position);
+ if let Ok(parsed) = input.try(|i| Parse::parse(context, i)) {
+ return Ok(CSSColor {
+ parsed: parsed,
+ authored: authored,
+ });
+ }
+ if !allow_quirks.allowed(context.quirks_mode) {
+ return Err(());
+ }
+ let (number, dimension) = match input.next()? {
+ Token::Number(number) => {
+ (number, None)
+ },
+ Token::Dimension(number, dimension) => {
+ (number, Some(dimension))
+ },
+ Token::Ident(ident) => {
+ if ident.len() != 3 && ident.len() != 6 {
+ return Err(());
+ }
+ return cssparser::Color::parse_hash(ident.as_bytes()).map(|color| {
+ Self {
+ parsed: color.into(),
+ authored: None
+ }
+ });
+ }
+ _ => {
+ return Err(());
+ },
+ };
+ let value = number.int_value.ok_or(())?;
+ if value < 0 {
+ return Err(());
+ }
+ let length = if value <= 9 {
+ 1
+ } else if value <= 99 {
+ 2
+ } else if value <= 999 {
+ 3
+ } else if value <= 9999 {
+ 4
+ } else if value <= 99999 {
+ 5
+ } else if value <= 999999 {
+ 6
+ } else {
+ return Err(())
+ };
+ let total = length + dimension.as_ref().map_or(0, |d| d.len());
+ if total > 6 {
+ return Err(());
+ }
+ let mut serialization = [b'0'; 6];
+ let space_padding = 6 - total;
+ let mut written = space_padding;
+ written += itoa::write(&mut serialization[written..], value).unwrap();
+ if let Some(dimension) = dimension {
+ written += (&mut serialization[written..]).write(dimension.as_bytes()).unwrap();
+ }
+ debug_assert!(written == 6);
Ok(CSSColor {
- parsed: try!(Parse::parse(context, input)),
- authored: authored,
+ parsed: cssparser::Color::parse_hash(&serialization).map(From::from)?,
+ authored: None,
})
}
}
@@ -866,6 +943,13 @@ pub type TrackBreadth = GenericTrackBreadth<LengthOrPercentage>;
/// The specified value of a grid `<track-size>`
pub type TrackSize = GenericTrackSize<LengthOrPercentage>;
+/// The specified value of a grid `<track-list>`
+/// (could also be `<auto-track-list>` or `<explicit-track-list>`)
+pub type TrackList = GenericTrackList<TrackSizeOrRepeat>;
+
+/// `<track-list> | none`
+pub type TrackListOrNone = Either<TrackList, None_>;
+
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
diff --git a/components/style/values/specified/position.rs b/components/style/values/specified/position.rs
index 678d2a8777d..c2991ede864 100644
--- a/components/style/values/specified/position.rs
+++ b/components/style/values/specified/position.rs
@@ -234,19 +234,14 @@ impl<S: Side> ToComputedValue for PositionComponent<S> {
PositionComponent::Side(ref keyword, Some(ref length)) if !keyword.is_start() => {
match length.to_computed_value(context) {
ComputedLengthOrPercentage::Length(length) => {
- ComputedLengthOrPercentage::Calc(CalcLengthOrPercentage {
- length: -length,
- percentage: Some(1.0),
- })
+ ComputedLengthOrPercentage::Calc(CalcLengthOrPercentage::new(-length, Some(1.0)))
},
ComputedLengthOrPercentage::Percentage(p) => {
ComputedLengthOrPercentage::Percentage(1.0 - p)
},
ComputedLengthOrPercentage::Calc(calc) => {
- ComputedLengthOrPercentage::Calc(CalcLengthOrPercentage {
- length: -calc.length,
- percentage: Some(1.0 - calc.percentage.unwrap_or(0.)),
- })
+ let p = 1. - calc.percentage.unwrap_or(0.);
+ ComputedLengthOrPercentage::Calc(CalcLengthOrPercentage::new(-calc.unclamped_length(), Some(p)))
},
}
},
diff --git a/components/style/viewport.rs b/components/style/viewport.rs
index c887614ad57..0953d9a4b7a 100644
--- a/components/style/viewport.rs
+++ b/components/style/viewport.rs
@@ -718,8 +718,7 @@ impl MaybeNew for ViewportConstraints {
Some(initial_viewport.$dimension.scale_by(value.0)),
LengthOrPercentageOrAuto::Auto => None,
LengthOrPercentageOrAuto::Calc(ref calc) => {
- let calc = calc.to_computed_value(&context);
- Some(initial_viewport.$dimension.scale_by(calc.percentage()) + calc.length())
+ calc.to_computed_value(&context).to_used_value(Some(initial_viewport.$dimension))
}
},
ViewportLength::ExtendToZoom => {
diff --git a/components/style_traits/values.rs b/components/style_traits/values.rs
index 663a39fb6ac..aaff1a998ea 100644
--- a/components/style_traits/values.rs
+++ b/components/style_traits/values.rs
@@ -74,6 +74,7 @@ macro_rules! impl_to_css_for_predefined_type {
impl_to_css_for_predefined_type!(f32);
impl_to_css_for_predefined_type!(i32);
+impl_to_css_for_predefined_type!(u16);
impl_to_css_for_predefined_type!(u32);
impl_to_css_for_predefined_type!(::cssparser::Token<'a>);
impl_to_css_for_predefined_type!(::cssparser::RGBA);
@@ -189,6 +190,13 @@ pub mod specified {
NonNegative
}
+ impl Default for AllowedLengthType {
+ #[inline]
+ fn default() -> Self {
+ AllowedLengthType::All
+ }
+ }
+
impl AllowedLengthType {
/// Whether value is valid for this allowed length type.
#[inline]
diff --git a/components/webdriver_server/lib.rs b/components/webdriver_server/lib.rs
index 250ad21813b..404f965bbb9 100644
--- a/components/webdriver_server/lib.rs
+++ b/components/webdriver_server/lib.rs
@@ -32,7 +32,7 @@ use hyper::method::Method::{self, Post};
use image::{DynamicImage, ImageFormat, RgbImage};
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use keys::keycodes_to_keys;
-use msg::constellation_msg::{FrameId, PipelineId, TraversalDirection};
+use msg::constellation_msg::{BrowsingContextId, PipelineId, TraversalDirection};
use net_traits::image::base::PixelFormat;
use regex::Captures;
use rustc_serialize::json::{Json, ToJson};
@@ -102,7 +102,7 @@ pub fn start_server(port: u16, constellation_chan: Sender<ConstellationMsg>) {
/// Represents the current WebDriver session and holds relevant session state.
struct WebDriverSession {
id: Uuid,
- frame_id: Option<FrameId>,
+ browsing_context_id: Option<BrowsingContextId>,
/// Time to wait for injected scripts to run before interrupting them. A [`None`] value
/// specifies that the script should run indefinitely.
@@ -120,7 +120,7 @@ impl WebDriverSession {
pub fn new() -> WebDriverSession {
WebDriverSession {
id: Uuid::new_v4(),
- frame_id: None,
+ browsing_context_id: None,
script_timeout: Some(30_000),
load_timeout: Some(300_000),
@@ -264,7 +264,7 @@ impl Handler {
}
}
- fn pipeline_id(&self, frame_id: Option<FrameId>) -> WebDriverResult<PipelineId> {
+ fn pipeline_id(&self, frame_id: Option<BrowsingContextId>) -> WebDriverResult<PipelineId> {
let interval = 20;
let iterations = 30_000 / interval;
let (sender, receiver) = ipc::channel().unwrap();
@@ -288,7 +288,7 @@ impl Handler {
}
fn frame_pipeline(&self) -> WebDriverResult<PipelineId> {
- self.pipeline_id(self.session.as_ref().and_then(|session| session.frame_id))
+ self.pipeline_id(self.session.as_ref().and_then(|session| session.browsing_context_id))
}
fn session(&self) -> WebDriverResult<&WebDriverSession> {
@@ -299,10 +299,10 @@ impl Handler {
}
}
- fn set_frame_id(&mut self, frame_id: Option<FrameId>) -> WebDriverResult<()> {
+ fn set_browsing_context_id(&mut self, browsing_context_id: Option<BrowsingContextId>) -> WebDriverResult<()> {
match self.session {
Some(ref mut x) => {
- x.frame_id = frame_id;
+ x.browsing_context_id = browsing_context_id;
Ok(())
},
None => Err(WebDriverError::new(ErrorStatus::SessionNotCreated,
@@ -525,7 +525,7 @@ impl Handler {
use webdriver::common::FrameId;
let frame_id = match parameters.id {
FrameId::Null => {
- self.set_frame_id(None).unwrap();
+ self.set_browsing_context_id(None).unwrap();
return Ok(WebDriverResponse::Void)
},
FrameId::Short(ref x) => WebDriverFrameId::Short(*x),
@@ -547,16 +547,16 @@ impl Handler {
}
let pipeline_id = try!(self.frame_pipeline());
let (sender, receiver) = ipc::channel().unwrap();
- let cmd = WebDriverScriptCommand::GetFrameId(frame_id, sender);
+ let cmd = WebDriverScriptCommand::GetPipelineId(frame_id, sender);
{
self.constellation_chan.send(ConstellationMsg::WebDriverCommand(
WebDriverCommandMsg::ScriptCommand(pipeline_id, cmd))).unwrap();
}
- let frame = match receiver.recv().unwrap() {
+ let context_id = match receiver.recv().unwrap() {
Ok(Some(pipeline_id)) => {
let (sender, receiver) = ipc::channel().unwrap();
- self.constellation_chan.send(ConstellationMsg::GetFrame(pipeline_id, sender)).unwrap();
+ self.constellation_chan.send(ConstellationMsg::GetBrowsingContext(pipeline_id, sender)).unwrap();
receiver.recv().unwrap()
},
Ok(None) => None,
@@ -566,7 +566,7 @@ impl Handler {
}
};
- self.set_frame_id(frame).unwrap();
+ self.set_browsing_context_id(context_id).unwrap();
Ok(WebDriverResponse::Void)
}
diff --git a/ports/cef/lib.rs b/ports/cef/lib.rs
index 809fccc412b..f953358e4a9 100644
--- a/ports/cef/lib.rs
+++ b/ports/cef/lib.rs
@@ -4,6 +4,7 @@
#![allow(non_camel_case_types)]
#![feature(box_syntax)]
+#![feature(core_intrinsics)]
#![feature(link_args)]
#[macro_use]
diff --git a/ports/cef/stubs.rs b/ports/cef/stubs.rs
index df35e050852..8f4a9b73820 100644
--- a/ports/cef/stubs.rs
+++ b/ports/cef/stubs.rs
@@ -12,7 +12,9 @@ macro_rules! stub(
#[allow(non_snake_case)]
pub extern "C" fn $name() {
println!("CEF stub function called: {}", stringify!($name));
- ::std::process::abort()
+ unsafe {
+ ::std::intrinsics::abort()
+ }
}
)
);
diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs
index f7aca89a524..d04625727aa 100644
--- a/ports/geckolib/glue.rs
+++ b/ports/geckolib/glue.rs
@@ -210,7 +210,7 @@ fn traverse_subtree(element: GeckoElement,
debug!("Traversing subtree:");
debug!("{:?}", ShowSubtreeData(element.as_node()));
- let traversal_driver = if global_style_data.style_thread_pool.is_none() {
+ let traversal_driver = if global_style_data.style_thread_pool.is_none() || !element.is_root() {
TraversalDriver::Sequential
} else {
TraversalDriver::Parallel
@@ -567,7 +567,8 @@ pub extern "C" fn Servo_StyleSheet_FromUTF8Bytes(loader: *mut Loader,
mode: SheetParsingMode,
media_list: *const RawServoMediaList,
extra_data: *mut URLExtraData,
- line_number_offset: u32)
+ line_number_offset: u32,
+ quirks_mode: nsCompatibility)
-> RawServoStyleSheetStrong {
let global_style_data = &*GLOBAL_STYLE_DATA;
let input = unsafe { data.as_ref().unwrap().as_str_unchecked() };
@@ -602,7 +603,7 @@ pub extern "C" fn Servo_StyleSheet_FromUTF8Bytes(loader: *mut Loader,
Arc::new(Stylesheet::from_str(
input, url_data.clone(), origin, media,
shared_lock, loader, &RustLogReporter,
- QuirksMode::NoQuirks, line_number_offset as u64)
+ quirks_mode.into(), line_number_offset as u64)
).into_strong()
}
@@ -1068,7 +1069,6 @@ fn get_pseudo_style(guard: &SharedRwLockReadGuard,
d.stylist.lazily_compute_pseudo_element_style(&guards,
&element,
&pseudo,
- ElementState::empty(),
base,
&metrics)
.map(|s| s.values().clone())
@@ -1123,6 +1123,12 @@ pub extern "C" fn Servo_StyleSet_RebuildData(raw_data: RawServoStyleSetBorrowed)
}
#[no_mangle]
+pub extern "C" fn Servo_StyleSet_Clear(raw_data: RawServoStyleSetBorrowed) {
+ let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
+ data.clear_stylist();
+}
+
+#[no_mangle]
pub extern "C" fn Servo_StyleSet_Drop(data: RawServoStyleSetOwned) {
let _ = data.into_box::<PerDocumentStyleData>();
}
@@ -1130,9 +1136,9 @@ pub extern "C" fn Servo_StyleSet_Drop(data: RawServoStyleSetOwned) {
fn parse_property(property_id: PropertyId,
value: *const nsACString,
data: *mut URLExtraData,
- parsing_mode: structs::ParsingMode) -> Result<ParsedDeclaration, ()> {
+ parsing_mode: structs::ParsingMode,
+ quirks_mode: QuirksMode) -> Result<ParsedDeclaration, ()> {
use style::parser::ParsingMode;
-
let value = unsafe { value.as_ref().unwrap().as_str_unchecked() };
let url_data = unsafe { RefPtr::from_ptr_ref(&data) };
let parsing_mode = ParsingMode::from_bits_truncate(parsing_mode);
@@ -1142,17 +1148,18 @@ fn parse_property(property_id: PropertyId,
url_data,
&RustLogReporter,
parsing_mode,
- QuirksMode::NoQuirks)
+ quirks_mode)
}
#[no_mangle]
pub extern "C" fn Servo_ParseProperty(property: nsCSSPropertyID, value: *const nsACString,
data: *mut URLExtraData,
- parsing_mode: structs::ParsingMode)
+ parsing_mode: structs::ParsingMode,
+ quirks_mode: nsCompatibility)
-> RawServoDeclarationBlockStrong {
let id = get_property_id_from_nscsspropertyid!(property,
RawServoDeclarationBlockStrong::null());
- match parse_property(id, value, data, parsing_mode) {
+ match parse_property(id, value, data, parsing_mode, quirks_mode.into()) {
Ok(parsed) => {
let global_style_data = &*GLOBAL_STYLE_DATA;
let mut block = PropertyDeclarationBlock::new();
@@ -1311,8 +1318,9 @@ pub extern "C" fn Servo_DeclarationBlock_GetPropertyIsImportant(declarations: Ra
fn set_property(declarations: RawServoDeclarationBlockBorrowed, property_id: PropertyId,
value: *const nsACString, is_important: bool, data: *mut URLExtraData,
- parsing_mode: structs::ParsingMode) -> bool {
- match parse_property(property_id, value, data, parsing_mode) {
+ parsing_mode: structs::ParsingMode,
+ quirks_mode: QuirksMode) -> bool {
+ match parse_property(property_id, value, data, parsing_mode, quirks_mode) {
Ok(parsed) => {
let importance = if is_important { Importance::Important } else { Importance::Normal };
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
@@ -1327,18 +1335,20 @@ fn set_property(declarations: RawServoDeclarationBlockBorrowed, property_id: Pro
pub extern "C" fn Servo_DeclarationBlock_SetProperty(declarations: RawServoDeclarationBlockBorrowed,
property: *const nsACString, value: *const nsACString,
is_important: bool, data: *mut URLExtraData,
- parsing_mode: structs::ParsingMode) -> bool {
+ parsing_mode: structs::ParsingMode,
+ quirks_mode: nsCompatibility) -> bool {
set_property(declarations, get_property_id_from_property!(property, false),
- value, is_important, data, parsing_mode)
+ value, is_important, data, parsing_mode, quirks_mode.into())
}
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_SetPropertyById(declarations: RawServoDeclarationBlockBorrowed,
property: nsCSSPropertyID, value: *const nsACString,
is_important: bool, data: *mut URLExtraData,
- parsing_mode: structs::ParsingMode) -> bool {
+ parsing_mode: structs::ParsingMode,
+ quirks_mode: nsCompatibility) -> bool {
set_property(declarations, get_property_id_from_nscsspropertyid!(property, false),
- value, is_important, data, parsing_mode)
+ value, is_important, data, parsing_mode, quirks_mode.into())
}
fn remove_property(declarations: RawServoDeclarationBlockBorrowed, property_id: PropertyId) {
@@ -1380,7 +1390,7 @@ pub extern "C" fn Servo_MediaList_Matches(list: RawServoMediaListBorrowed,
-> bool {
let per_doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow();
read_locked_arc(list, |list: &MediaList| {
- list.evaluate(&per_doc_data.stylist.device, QuirksMode::NoQuirks)
+ list.evaluate(&per_doc_data.stylist.device, per_doc_data.stylist.quirks_mode())
})
}
@@ -1835,10 +1845,15 @@ pub extern "C" fn Servo_DeclarationBlock_SetTextDecorationColorOverride(declarat
}
#[no_mangle]
-pub extern "C" fn Servo_CSSSupports2(property: *const nsACString, value: *const nsACString) -> bool {
+pub extern "C" fn Servo_CSSSupports2(property: *const nsACString,
+ value: *const nsACString) -> bool {
let id = get_property_id_from_property!(property, false);
- parse_property(id, value, unsafe { DUMMY_URL_DATA }, structs::ParsingMode_Default).is_ok()
+ parse_property(id,
+ value,
+ unsafe { DUMMY_URL_DATA },
+ structs::ParsingMode_Default,
+ QuirksMode::NoQuirks).is_ok()
}
#[no_mangle]
@@ -2144,7 +2159,7 @@ pub extern "C" fn Servo_AnimationValue_Compute(declarations: RawServoDeclaration
font_metrics_provider: &metrics,
cached_system_font: None,
in_media_query: false,
- quirks_mode: QuirksMode::NoQuirks,
+ quirks_mode: data.stylist.quirks_mode(),
};
let global_style_data = &*GLOBAL_STYLE_DATA;
diff --git a/ports/servo/main.rs b/ports/servo/main.rs
index 6534aed75c0..bec8ffa8089 100644
--- a/ports/servo/main.rs
+++ b/ports/servo/main.rs
@@ -15,7 +15,7 @@
//!
//! [glutin]: https://github.com/tomaka/glutin
-#![feature(start)]
+#![feature(start, core_intrinsics)]
#[cfg(target_os = "android")]
extern crate android_injected_glue;
@@ -58,7 +58,7 @@ pub mod platform {
fn install_crash_handler() {
use backtrace::Backtrace;
use sig::ffi::Sig;
- use std::process::abort;
+ use std::intrinsics::abort;
use std::thread;
fn handler(_sig: i32) {
@@ -67,7 +67,11 @@ fn install_crash_handler() {
.map(|n| format!(" for thread \"{}\"", n))
.unwrap_or("".to_owned());
println!("Stack trace{}\n{:?}", name, Backtrace::new());
- abort();
+ unsafe {
+ // N.B. Using process::abort() here causes the crash handler to be
+ // triggered recursively.
+ abort();
+ }
}
signal!(Sig::SEGV, handler); // handle segfaults
diff --git a/python/servo/build_commands.py b/python/servo/build_commands.py
index 546fcfdf911..93ea76e63c7 100644
--- a/python/servo/build_commands.py
+++ b/python/servo/build_commands.py
@@ -407,9 +407,6 @@ class MachCommands(CommandBase):
@Command('build-geckolib',
description='Build a static library of components used by Gecko',
category='build')
- @CommandArgument('--with-gecko',
- default=None,
- help='Build with Gecko dist directory')
@CommandArgument('--jobs', '-j',
default=None,
help='Number of jobs to run in parallel')
@@ -419,7 +416,7 @@ class MachCommands(CommandBase):
@CommandArgument('--release', '-r',
action='store_true',
help='Build in release mode')
- def build_geckolib(self, with_gecko=None, jobs=None, verbose=False, release=False):
+ def build_geckolib(self, jobs=None, verbose=False, release=False):
self.set_use_stable_rust()
self.ensure_bootstrapped()
self.ensure_clobbered()
@@ -429,9 +426,6 @@ class MachCommands(CommandBase):
ret = None
opts = []
features = []
- if with_gecko is not None:
- features += ["bindgen"]
- env["MOZ_DIST"] = path.abspath(path.expanduser(with_gecko))
if jobs is not None:
opts += ["-j", jobs]
if verbose:
diff --git a/python/tidy/servo_tidy/tidy.py b/python/tidy/servo_tidy/tidy.py
index ccca233db9c..51e7e69f8d4 100644
--- a/python/tidy/servo_tidy/tidy.py
+++ b/python/tidy/servo_tidy/tidy.py
@@ -67,6 +67,7 @@ WEBIDL_STANDARDS = [
"//dom.spec.whatwg.org",
"//domparsing.spec.whatwg.org",
"//drafts.csswg.org",
+ "//drafts.css-houdini.org",
"//drafts.fxtf.org",
"//encoding.spec.whatwg.org",
"//fetch.spec.whatwg.org",
@@ -446,6 +447,7 @@ def check_rust(file_name, lines):
prev_use = None
prev_open_brace = False
+ multi_line_string = False
current_indent = 0
prev_crate = {}
prev_mod = {}
@@ -463,6 +465,15 @@ def check_rust(file_name, lines):
prev_indent = indent
indent = len(original_line) - len(line)
+ # Hack for components/selectors/build.rs
+ if multi_line_string:
+ if line.startswith('"#'):
+ multi_line_string = False
+ else:
+ continue
+ if line.endswith('r#"'):
+ multi_line_string = True
+
is_attribute = re.search(r"#\[.*\]", line)
is_comment = re.search(r"^//|^/\*|^\*", line)
diff --git a/resources/presentational-hints.css b/resources/presentational-hints.css
index 84157dcb4bd..63f42491dd3 100644
--- a/resources/presentational-hints.css
+++ b/resources/presentational-hints.css
@@ -18,11 +18,15 @@ br[clear=right i] { clear: right; }
br[clear=all i], br[clear=both i] { clear: both; }
-ol[type=1], li[type=1] { list-style-type: decimal; }
-ol[type=a], li[type=a] { list-style-type: lower-alpha; }
-ol[type=A], li[type=A] { list-style-type: upper-alpha; }
-ol[type=i], li[type=i] { list-style-type: lower-roman; }
-ol[type=I], li[type=I] { list-style-type: upper-roman; }
+ol[type="1"], li[type="1"] { list-style-type: decimal; }
+ol:-servo-case-sensitive-type-attr(a),
+li:-servo-case-sensitive-type-attr(a) { list-style-type: lower-alpha; }
+ol:-servo-case-sensitive-type-attr(A),
+li:-servo-case-sensitive-type-attr(A) { list-style-type: upper-alpha; }
+ol:-servo-case-sensitive-type-attr(i),
+li:-servo-case-sensitive-type-attr(i) { list-style-type: lower-roman; }
+ol:-servo-case-sensitive-type-attr(I),
+li:-servo-case-sensitive-type-attr(I) { list-style-type: upper-roman; }
ul[type=none i], li[type=none i] { list-style-type: none; }
ul[type=disc i], li[type=disc i] { list-style-type: disc; }
ul[type=circle i], li[type=circle i] { list-style-type: circle; }
diff --git a/servo-tidy.toml b/servo-tidy.toml
index 1b07e242ff9..55357dfe1ce 100644
--- a/servo-tidy.toml
+++ b/servo-tidy.toml
@@ -56,9 +56,6 @@ files = [
"./tests/wpt/mozilla/tests/css/fonts",
"./tests/wpt/mozilla/tests/css/pre_with_tab.html",
"./tests/wpt/mozilla/tests/mozilla/textarea_placeholder.html",
- # Tidy complains about taking &String instead of &str, but they aren't
- # equivalent given the way the traits are set up.
- "./components/selectors/tree.rs",
]
# Directories that are ignored for the non-WPT tidy check.
directories = [
diff --git a/tests/unit/script/size_of.rs b/tests/unit/script/size_of.rs
index a328bcbf6f5..3368271d8e1 100644
--- a/tests/unit/script/size_of.rs
+++ b/tests/unit/script/size_of.rs
@@ -30,13 +30,13 @@ macro_rules! sizeof_checker (
// Update the sizes here
sizeof_checker!(size_event_target, EventTarget, 40);
-sizeof_checker!(size_node, Node, 152);
-sizeof_checker!(size_element, Element, 320);
-sizeof_checker!(size_htmlelement, HTMLElement, 336);
-sizeof_checker!(size_div, HTMLDivElement, 336);
-sizeof_checker!(size_span, HTMLSpanElement, 336);
-sizeof_checker!(size_text, Text, 184);
-sizeof_checker!(size_characterdata, CharacterData, 184);
+sizeof_checker!(size_node, Node, 184);
+sizeof_checker!(size_element, Element, 352);
+sizeof_checker!(size_htmlelement, HTMLElement, 368);
+sizeof_checker!(size_div, HTMLDivElement, 368);
+sizeof_checker!(size_span, HTMLSpanElement, 368);
+sizeof_checker!(size_text, Text, 216);
+sizeof_checker!(size_characterdata, CharacterData, 216);
sizeof_checker!(size_servothreadsafelayoutnode, ServoThreadSafeLayoutNode, 16);
// We use these types in the parallel traversal. They should stay pointer-sized.
diff --git a/tests/unit/style/attr.rs b/tests/unit/style/attr.rs
index 10f1bd5e585..25fe085a637 100644
--- a/tests/unit/style/attr.rs
+++ b/tests/unit/style/attr.rs
@@ -5,17 +5,18 @@
use app_units::Au;
use style::attr::{AttrValue, LengthOrPercentageOrAuto, parse_length};
use style::values::computed::CalcLengthOrPercentage;
+use style_traits::values::specified::AllowedLengthType;
#[test]
fn test_length_calc() {
- let calc = CalcLengthOrPercentage { length: Au(10), percentage: Some(0.2) };
- assert_eq!(calc.to_computed(Some(Au(10))), Some(Au(12)));
- assert_eq!(calc.to_computed(Some(Au(0))), Some(Au(10)));
- assert_eq!(calc.to_computed(None), None);
+ let calc = CalcLengthOrPercentage::new(Au(10), Some(0.2));
+ assert_eq!(calc.to_used_value(Some(Au(10))), Some(Au(12)));
+ assert_eq!(calc.to_used_value(Some(Au(0))), Some(Au(10)));
+ assert_eq!(calc.to_used_value(None), None);
- let calc = CalcLengthOrPercentage { length: Au(10), percentage: None };
- assert_eq!(calc.to_computed(Some(Au(0))), Some(Au(10)));
- assert_eq!(calc.to_computed(None), Some(Au(10)));
+ let calc = CalcLengthOrPercentage::new(Au(10), None);
+ assert_eq!(calc.to_used_value(Some(Au(0))), Some(Au(10)));
+ assert_eq!(calc.to_used_value(None), Some(Au(10)));
}
#[test]
diff --git a/tests/unit/style/parsing/mod.rs b/tests/unit/style/parsing/mod.rs
index e15d2dca21b..5f48483affa 100644
--- a/tests/unit/style/parsing/mod.rs
+++ b/tests/unit/style/parsing/mod.rs
@@ -5,10 +5,16 @@
//! Tests for parsing and serialization of values/properties
use cssparser::Parser;
+use euclid::size::TypedSize2D;
use media_queries::CSSErrorReporterTest;
use style::context::QuirksMode;
+use style::font_metrics::ServoMetricsProvider;
+use style::media_queries::{Device, MediaType};
use style::parser::{PARSING_MODE_DEFAULT, ParserContext};
+use style::properties::{ComputedValues, StyleBuilder};
use style::stylesheets::{CssRuleType, Origin};
+use style::values::computed::{Context, ToComputedValue};
+use style_traits::ToCss;
fn parse<T, F: Fn(&ParserContext, &mut Parser) -> Result<T, ()>>(f: F, s: &str) -> Result<T, ()> {
let url = ::servo_url::ServoUrl::parse("http://localhost").unwrap();
@@ -24,6 +30,32 @@ fn parse_entirely<T, F: Fn(&ParserContext, &mut Parser) -> Result<T, ()>>(f: F,
parse(|context, parser| parser.parse_entirely(|p| f(context, p)), s)
}
+fn assert_computed_serialization<C, F, T>(f: F, input: &str, output: &str)
+ where F: Fn(&ParserContext, &mut Parser) -> Result<T, ()>,
+ T: ToComputedValue<ComputedValue=C>, C: ToCss
+{
+ let viewport_size = TypedSize2D::new(0., 0.);
+ let initial_style = ComputedValues::initial_values();
+ let device = Device::new(MediaType::Screen, viewport_size);
+
+ let context = Context {
+ is_root_element: true,
+ device: &device,
+ inherited_style: initial_style,
+ layout_parent_style: initial_style,
+ style: StyleBuilder::for_derived_style(&initial_style),
+ cached_system_font: None,
+ font_metrics_provider: &ServoMetricsProvider,
+ in_media_query: false,
+ quirks_mode: QuirksMode::NoQuirks,
+ };
+
+ let parsed = parse(f, input).unwrap();
+ let computed = parsed.to_computed_value(&context);
+ let serialized = ToCss::to_css_string(&computed);
+ assert_eq!(serialized, output);
+}
+
// This is a macro so that the file/line information
// is preserved in the panic
macro_rules! assert_roundtrip_with_context {
diff --git a/tests/unit/style/parsing/position.rs b/tests/unit/style/parsing/position.rs
index 7a3bfe1bae3..c1527c2f233 100644
--- a/tests/unit/style/parsing/position.rs
+++ b/tests/unit/style/parsing/position.rs
@@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-use parsing::{parse, parse_entirely};
+use parsing::{assert_computed_serialization, parse, parse_entirely};
use style::parser::Parse;
use style::values::specified::position::*;
use style_traits::ToCss;
@@ -168,3 +168,68 @@ fn test_grid_auto_flow() {
assert!(parse(grid_auto_flow::parse, "column 'dense'").is_err());
assert!(parse(grid_auto_flow::parse, "column 2px dense").is_err());
}
+
+#[test]
+fn test_grid_auto_rows_columns() {
+ use style::properties::longhands::grid_auto_rows;
+
+ // the grammar is <track-size>+ but gecko supports only a single value, so we've clamped ourselves
+ assert_roundtrip_with_context!(grid_auto_rows::parse, "55%");
+ assert_roundtrip_with_context!(grid_auto_rows::parse, "0.5fr");
+ assert_roundtrip_with_context!(grid_auto_rows::parse, "fit-content(11%)");
+ // only <inflexible-breadth> is allowed in first arg of minmax
+ assert!(parse(grid_auto_rows::parse, "minmax(1fr, max-content)").is_err());
+}
+
+#[test]
+fn test_grid_template_rows_columns() {
+ use style::properties::longhands::grid_template_rows;
+
+ assert_roundtrip_with_context!(grid_template_rows::parse, "none"); // none keyword
+ // <track-size>{2} with `<track-breadth> minmax(<inflexible-breadth>, <track-breadth>)`
+ assert_roundtrip_with_context!(grid_template_rows::parse, "1fr minmax(min-content, 1fr)");
+ // <track-size> with <track-breadth> as <length-percentage>
+ assert_roundtrip_with_context!(grid_template_rows::parse, "calc(4em + 5px)");
+ // <track-size> with <length> followed by <track-repeat> with `<track-size>{3}` (<flex>, auto, minmax)
+ assert_roundtrip_with_context!(grid_template_rows::parse, "10px repeat(2, 1fr auto minmax(200px, 1fr))");
+ // <track-repeat> with `<track-size> <line-names>` followed by <track-size>
+ assert_roundtrip_with_context!(grid_template_rows::parse, "repeat(4, 10px [col-start] 250px [col-end]) 10px");
+ // mixture of <track-size>, <track-repeat> and <line-names>
+ assert_roundtrip_with_context!(grid_template_rows::parse,
+ "[a] auto [b] minmax(min-content, 1fr) [b c d] repeat(2, [e] 40px) repeat(5, [f g] auto [h]) [i]");
+
+ // no span allowed in <line-names>
+ assert!(parse(grid_template_rows::parse, "[a span] 10px").is_err());
+ // <track-list> needs at least one <track-size> | <track-repeat>
+ assert!(parse(grid_template_rows::parse, "[a b c]").is_err());
+ // at least one argument of <fixed-size> should be a <fixed-breadth> (i.e., <length-percentage>)
+ assert!(parse(grid_template_rows::parse, "[a b] repeat(auto-fill, 50px) minmax(auto, 1fr)").is_err());
+ // fit-content is not a <fixed-size>
+ assert!(parse(grid_template_rows::parse, "[a b] repeat(auto-fill, fit-content(20%))").is_err());
+ // <auto-track-list> only allows <fixed-size> | <fixed-repeat>
+ assert!(parse(grid_template_rows::parse, "[a] repeat(2, auto) repeat(auto-fill, 10px)").is_err());
+ // only <inflexible-breadth> allowed in <auto-track-repeat>
+ assert!(parse(grid_template_rows::parse, "[a] repeat(auto-fill, 1fr)").is_err());
+ // <auto-track-repeat> is allowed only once
+ assert!(parse(grid_template_rows::parse, "[a] repeat(auto-fit, [b] 8px) [c] repeat(auto-fill, [c] 8px)").is_err());
+}
+
+#[test]
+fn test_computed_grid_template_rows_colums() {
+ use style::properties::longhands::grid_template_rows;
+
+ assert_computed_serialization(grid_template_rows::parse,
+ "[a] repeat(calc(1 + 1), [b] auto)", "[a b] auto [b] auto");
+
+ assert_computed_serialization(grid_template_rows::parse,
+ "[a] repeat(2, [b c] auto [e] auto [d])",
+ "[a b c] auto [e] auto [d b c] auto [e] auto [d]");
+
+ assert_computed_serialization(grid_template_rows::parse,
+ "[a] 50px [b] 10% [b c d] repeat(2, [e] 40px [f]) [g] repeat(auto-fill, [h i] 20px [j]) [k] 10px [l]",
+ "[a] 50px [b] 10% [b c d e] 40px [f e] 40px [f g] repeat(auto-fill, [h i] 20px [j]) [k] 10px [l]");
+
+ assert_computed_serialization(grid_template_rows::parse,
+ "10px repeat(2, 1fr auto minmax(200px, 1fr))",
+ "10px minmax(auto, 1fr) auto minmax(200px, 1fr) minmax(auto, 1fr) auto minmax(200px, 1fr)");
+}
diff --git a/tests/unit/style/stylesheets.rs b/tests/unit/style/stylesheets.rs
index 1cef0f377be..44c02f6c1f2 100644
--- a/tests/unit/style/stylesheets.rs
+++ b/tests/unit/style/stylesheets.rs
@@ -6,6 +6,7 @@ use cssparser::{self, Parser as CssParser, SourcePosition, SourceLocation};
use html5ever::{Namespace as NsAtom};
use media_queries::CSSErrorReporterTest;
use parking_lot::RwLock;
+use selectors::attr::*;
use selectors::parser::*;
use servo_atoms::Atom;
use servo_url::ServoUrl;
@@ -90,28 +91,24 @@ fn test_parse_stylesheet() {
}))),
CssRule::Style(Arc::new(stylesheet.shared_lock.wrap(StyleRule {
selectors: SelectorList(vec![
- Selector {
- inner: SelectorInner::from_vec(vec![
- Component::Namespace(Namespace {
- prefix: None,
- url: NsAtom::from("http://www.w3.org/1999/xhtml")
- }),
+ Selector::new_for_unit_testing(
+ SelectorInner::from_vec(vec![
+ Component::DefaultNamespace(NsAtom::from("http://www.w3.org/1999/xhtml")),
Component::LocalName(LocalName {
name: local_name!("input"),
lower_name: local_name!("input"),
}),
- Component::AttrEqual(AttrSelector {
- name: local_name!("type"),
- lower_name: local_name!("type"),
- namespace: NamespaceConstraint::Specific(Namespace {
- prefix: None,
- url: ns!()
- }),
- }, "hidden".to_owned(), CaseSensitivity::CaseInsensitive)
+ Component::AttributeInNoNamespace {
+ local_name: local_name!("type"),
+ local_name_lower: local_name!("type"),
+ operator: AttrSelectorOperator::Equal,
+ value: "hidden".to_owned(),
+ case_sensitivity: ParsedCaseSensitivity::AsciiCaseInsensitive,
+ never_matches: false,
+ }
]),
- pseudo_element: None,
- specificity: (0 << 20) + (1 << 10) + (1 << 0),
- },
+ (0 << 20) + (1 << 10) + (1 << 0)
+ ),
]),
block: Arc::new(stylesheet.shared_lock.wrap(block_from(vec![
(PropertyDeclaration::Display(longhands::display::SpecifiedValue::none),
@@ -127,34 +124,26 @@ fn test_parse_stylesheet() {
}))),
CssRule::Style(Arc::new(stylesheet.shared_lock.wrap(StyleRule {
selectors: SelectorList(vec![
- Selector {
- inner: SelectorInner::from_vec(vec![
- Component::Namespace(Namespace {
- prefix: None,
- url: NsAtom::from("http://www.w3.org/1999/xhtml")
- }),
+ Selector::new_for_unit_testing(
+ SelectorInner::from_vec(vec![
+ Component::DefaultNamespace(NsAtom::from("http://www.w3.org/1999/xhtml")),
Component::LocalName(LocalName {
name: local_name!("html"),
lower_name: local_name!("html"),
}),
]),
- pseudo_element: None,
- specificity: (0 << 20) + (0 << 10) + (1 << 0),
- },
- Selector {
- inner: SelectorInner::from_vec(vec![
- Component::Namespace(Namespace {
- prefix: None,
- url: NsAtom::from("http://www.w3.org/1999/xhtml")
- }),
+ (0 << 20) + (0 << 10) + (1 << 0)
+ ),
+ Selector::new_for_unit_testing(
+ SelectorInner::from_vec(vec![
+ Component::DefaultNamespace(NsAtom::from("http://www.w3.org/1999/xhtml")),
Component::LocalName(LocalName {
name: local_name!("body"),
lower_name: local_name!("body"),
}),
]),
- pseudo_element: None,
- specificity: (0 << 20) + (0 << 10) + (1 << 0),
- },
+ (0 << 20) + (0 << 10) + (1 << 0)
+ ),
]),
block: Arc::new(stylesheet.shared_lock.wrap(block_from(vec![
(PropertyDeclaration::Display(longhands::display::SpecifiedValue::block),
@@ -167,23 +156,16 @@ fn test_parse_stylesheet() {
}))),
CssRule::Style(Arc::new(stylesheet.shared_lock.wrap(StyleRule {
selectors: SelectorList(vec![
- Selector {
- inner: SelectorInner::from_vec(vec![
- Component::Namespace(Namespace {
- prefix: None,
- url: NsAtom::from("http://www.w3.org/1999/xhtml")
- }),
+ Selector::new_for_unit_testing(
+ SelectorInner::from_vec(vec![
+ Component::DefaultNamespace(NsAtom::from("http://www.w3.org/1999/xhtml")),
Component::ID(Atom::from("d1")),
Component::Combinator(Combinator::Child),
- Component::Namespace(Namespace {
- prefix: None,
- url: NsAtom::from("http://www.w3.org/1999/xhtml")
- }),
+ Component::DefaultNamespace(NsAtom::from("http://www.w3.org/1999/xhtml")),
Component::Class(Atom::from("ok")),
]),
- pseudo_element: None,
- specificity: (1 << 20) + (1 << 10) + (0 << 0),
- },
+ (1 << 20) + (1 << 10) + (0 << 0)
+ ),
]),
block: Arc::new(stylesheet.shared_lock.wrap(block_from(vec![
(PropertyDeclaration::BackgroundColor(
diff --git a/tests/unit/style/stylist.rs b/tests/unit/style/stylist.rs
index 073c003b0bb..3c136edcef3 100644
--- a/tests/unit/style/stylist.rs
+++ b/tests/unit/style/stylist.rs
@@ -212,9 +212,9 @@ fn test_insert() {
#[test]
fn test_get_universal_rules() {
thread_state::initialize(thread_state::LAYOUT);
- let (map, shared_lock) = get_mock_map(&["*|*", "#foo > *|*", ".klass", "#id"]);
+ let (map, shared_lock) = get_mock_map(&["*|*", "#foo > *|*", "*|* > *|*", ".klass", "#id"]);
let decls = map.get_universal_rules(CascadeLevel::UserNormal);
- assert_eq!(decls.len(), 1);
+ assert_eq!(decls.len(), 1, "{:?}", decls);
}
diff --git a/tests/unit/stylo/Cargo.toml b/tests/unit/stylo/Cargo.toml
index 8c6478be76e..46d9c6df281 100644
--- a/tests/unit/stylo/Cargo.toml
+++ b/tests/unit/stylo/Cargo.toml
@@ -21,7 +21,6 @@ env_logger = "0.4"
euclid = "0.11"
libc = "0.2"
log = {version = "0.3.5", features = ["release_max_level_info"]}
-parking_lot = "0.3"
selectors = {path = "../../../components/selectors", features = ["gecko_like_types"]}
style_traits = {path = "../../../components/style_traits"}
geckoservo = {path = "../../../ports/geckolib"}
diff --git a/tests/unit/stylo/lib.rs b/tests/unit/stylo/lib.rs
index 76b54a45b7d..fedbba703b9 100644
--- a/tests/unit/stylo/lib.rs
+++ b/tests/unit/stylo/lib.rs
@@ -7,7 +7,6 @@ extern crate cssparser;
extern crate env_logger;
extern crate geckoservo;
#[macro_use] extern crate log;
-extern crate parking_lot;
extern crate selectors;
#[macro_use] extern crate style;
extern crate style_traits;
diff --git a/tests/unit/stylo/size_of.rs b/tests/unit/stylo/size_of.rs
index 4ae541c8de0..f8770a8842e 100644
--- a/tests/unit/stylo/size_of.rs
+++ b/tests/unit/stylo/size_of.rs
@@ -12,8 +12,8 @@ fn size_of_selectors_dummy_types() {
assert_eq!(size_of::<dummies::PseudoClass>(), size_of::<real::NonTSPseudoClass>());
assert_eq!(align_of::<dummies::PseudoClass>(), align_of::<real::NonTSPseudoClass>());
- assert_eq!(size_of::<dummies::PseudoElementSelector>(), size_of::<real::PseudoElementSelector>());
- assert_eq!(align_of::<dummies::PseudoElementSelector>(), align_of::<real::PseudoElementSelector>());
+ assert_eq!(size_of::<dummies::PseudoElement>(), size_of::<real::PseudoElement>());
+ assert_eq!(align_of::<dummies::PseudoElement>(), align_of::<real::PseudoElement>());
assert_eq!(size_of::<dummies::Atom>(), size_of::<style::Atom>());
assert_eq!(align_of::<dummies::Atom>(), align_of::<style::Atom>());
diff --git a/tests/wpt/metadata-css/css-transforms-1_dev/html/css-transform-3d-transform-style.htm.ini b/tests/wpt/metadata-css/css-transforms-1_dev/html/css-transform-3d-transform-style.htm.ini
deleted file mode 100644
index 5057dc804a7..00000000000
--- a/tests/wpt/metadata-css/css-transforms-1_dev/html/css-transform-3d-transform-style.htm.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[css-transform-3d-transform-style.htm]
- type: reftest
- expected: FAIL
diff --git a/tests/wpt/metadata-css/css-transforms-1_dev/html/transform3d-sorting-004.htm.ini b/tests/wpt/metadata-css/css-transforms-1_dev/html/transform3d-sorting-004.htm.ini
new file mode 100644
index 00000000000..680f6a37a89
--- /dev/null
+++ b/tests/wpt/metadata-css/css-transforms-1_dev/html/transform3d-sorting-004.htm.ini
@@ -0,0 +1,4 @@
+[transform3d-sorting-004.htm]
+ type: reftest
+ expected: FAIL
+ bug: https://github.com/w3c/web-platform-tests/issues/5931
diff --git a/tests/wpt/metadata-css/css-transforms-1_dev/html/transform3d-sorting-005.htm.ini b/tests/wpt/metadata-css/css-transforms-1_dev/html/transform3d-sorting-005.htm.ini
deleted file mode 100644
index d51b70bab1b..00000000000
--- a/tests/wpt/metadata-css/css-transforms-1_dev/html/transform3d-sorting-005.htm.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[transform3d-sorting-005.htm]
- type: reftest
- expected: FAIL
diff --git a/tests/wpt/metadata-css/css-transforms-1_dev/html/transform3d-sorting-006.htm.ini b/tests/wpt/metadata-css/css-transforms-1_dev/html/transform3d-sorting-006.htm.ini
index e275c5457a6..e3fa053475b 100644
--- a/tests/wpt/metadata-css/css-transforms-1_dev/html/transform3d-sorting-006.htm.ini
+++ b/tests/wpt/metadata-css/css-transforms-1_dev/html/transform3d-sorting-006.htm.ini
@@ -1,3 +1,4 @@
[transform3d-sorting-006.htm]
type: reftest
expected: FAIL
+ bug: https://github.com/w3c/web-platform-tests/pull/5922
diff --git a/tests/wpt/metadata-css/selectors-3_dev/html/css3-selectors-lang-024.htm.ini b/tests/wpt/metadata-css/selectors-3_dev/html/css3-selectors-lang-024.htm.ini
deleted file mode 100644
index 8d25a735ed8..00000000000
--- a/tests/wpt/metadata-css/selectors-3_dev/html/css3-selectors-lang-024.htm.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[css3-selectors-lang-024.htm]
- type: testharness
- [A lang|= value will match a lang attribute value regardless of case differences.]
- expected: FAIL
-
diff --git a/tests/wpt/metadata-css/selectors-3_dev/html/css3-selectors-lang-035.htm.ini b/tests/wpt/metadata-css/selectors-3_dev/html/css3-selectors-lang-035.htm.ini
deleted file mode 100644
index f1eb302573d..00000000000
--- a/tests/wpt/metadata-css/selectors-3_dev/html/css3-selectors-lang-035.htm.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[css3-selectors-lang-035.htm]
- type: testharness
- [A lang|= value will match a lang attribute value regardless of case differences in the script tag.]
- expected: FAIL
-
diff --git a/tests/wpt/metadata-css/selectors-3_dev/html/css3-selectors-lang-044.htm.ini b/tests/wpt/metadata-css/selectors-3_dev/html/css3-selectors-lang-044.htm.ini
deleted file mode 100644
index 0a343c73563..00000000000
--- a/tests/wpt/metadata-css/selectors-3_dev/html/css3-selectors-lang-044.htm.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[css3-selectors-lang-044.htm]
- type: testharness
- [A lang= value will match a lang attribute value regardless of case differences.]
- expected: FAIL
-
diff --git a/tests/wpt/metadata-css/selectors-3_dev/html/css3-selectors-lang-055.htm.ini b/tests/wpt/metadata-css/selectors-3_dev/html/css3-selectors-lang-055.htm.ini
deleted file mode 100644
index f8ff6b5f1f9..00000000000
--- a/tests/wpt/metadata-css/selectors-3_dev/html/css3-selectors-lang-055.htm.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[css3-selectors-lang-055.htm]
- type: testharness
- [A lang= value will match a lang attribute value regardless of case differences in the script tag.]
- expected: FAIL
-
diff --git a/tests/wpt/metadata/dom/nodes/MutationObserver-attributes.html.ini b/tests/wpt/metadata/dom/nodes/MutationObserver-attributes.html.ini
index 66e97c704e6..52a6a920412 100644
--- a/tests/wpt/metadata/dom/nodes/MutationObserver-attributes.html.ini
+++ b/tests/wpt/metadata/dom/nodes/MutationObserver-attributes.html.ini
@@ -1,114 +1,27 @@
[MutationObserver-attributes.html]
type: testharness
- [attributes Element.id: update, no oldValue, mutation]
- expected: FAIL
-
- [attributes Element.id: update mutation]
- expected: FAIL
-
- [attributes Element.id: empty string update mutation]
- expected: FAIL
-
[attributes Element.id: same value mutation]
expected: FAIL
- [attributes Element.unknown: IDL attribute no mutation]
- expected: FAIL
-
- [attributes HTMLInputElement.type: type update mutation]
- expected: FAIL
-
[attributes Element.className: new value mutation]
expected: FAIL
- [attributes Element.className: empty string update mutation]
- expected: FAIL
-
- [attributes Element.className: same value mutation]
- expected: FAIL
-
- [attributes Element.className: same multiple values mutation]
- expected: FAIL
-
[attributes Element.classList.add: single token addition mutation]
expected: FAIL
[attributes Element.classList.add: multiple tokens addition mutation]
expected: FAIL
- [attributes Element.classList.add: syntax err/no mutation]
- expected: FAIL
-
- [attributes Element.classList.add: invalid character/no mutation]
- expected: FAIL
-
- [attributes Element.classList.add: same value mutation]
- expected: FAIL
-
- [attributes Element.classList.remove: single token removal mutation]
- expected: FAIL
-
- [attributes Element.classList.remove: multiple tokens removal mutation]
- expected: FAIL
-
- [attributes Element.classList.remove: missing token removal mutation]
- expected: FAIL
-
- [attributes Element.classList.toggle: token removal mutation]
- expected: FAIL
-
- [attributes Element.classList.toggle: token addition mutation]
- expected: FAIL
-
- [attributes Element.classList.toggle: forced token removal mutation]
- expected: FAIL
-
- [attributes Element.classList.toggle: forced missing token removal no mutation]
- expected: FAIL
-
- [attributes Element.classList.toggle: forced existing token addition no mutation]
- expected: FAIL
-
- [attributes Element.classList.toggle: forced token addition mutation]
- expected: FAIL
-
- [attributes Element.attributes.value: update mutation]
- expected: FAIL
-
- [attributes Element.attributes.value: same id mutation]
- expected: FAIL
-
- [attributes Element.setAttribute: id mutation]
- expected: FAIL
-
- [attributes Element.setAttribute: same class mutation]
- expected: FAIL
-
[attributes Element.setAttribute: classname mutation]
expected: FAIL
- [attributes Element.removeAttribute: removal mutation]
- expected: FAIL
-
- [attributes Element.removeAttribute: removal no mutation]
- expected: FAIL
-
- [childList HTMLInputElement.removeAttribute: type removal mutation]
- expected: FAIL
-
[attributes Element.setAttributeNS: creation mutation]
expected: FAIL
[attributes Element.setAttributeNS: prefixed attribute creation mutation]
expected: FAIL
- [attributes Element.removeAttributeNS: removal mutation]
- expected: FAIL
-
- [attributes Element.removeAttributeNS: removal no mutation]
- expected: FAIL
-
- [attributes Element.removeAttributeNS: prefixed attribute removal no mutation]
+ [attributes Element.className: empty string update mutation]
expected: FAIL
[attributes/attributeFilter Element.id/Element.className: update mutation]
@@ -117,12 +30,6 @@
[attributes/attributeFilter Element.id/Element.className: multiple filter update mutation]
expected: FAIL
- [attributeOldValue alone Element.id: update mutation]
- expected: FAIL
-
[attributeFilter alone Element.id/Element.className: multiple filter update mutation]
expected: FAIL
- [childList false: no childList mutation]
- expected: FAIL
-
diff --git a/tests/wpt/metadata/dom/nodes/MutationObserver-characterData.html.ini b/tests/wpt/metadata/dom/nodes/MutationObserver-characterData.html.ini
index 37abce874dc..6e8512d76d9 100644
--- a/tests/wpt/metadata/dom/nodes/MutationObserver-characterData.html.ini
+++ b/tests/wpt/metadata/dom/nodes/MutationObserver-characterData.html.ini
@@ -1,59 +1,60 @@
[MutationObserver-characterData.html]
type: testharness
+ expected: TIMEOUT
[characterData Text.data: simple mutation without oldValue]
- expected: FAIL
+ expected: TIMEOUT
[characterData Text.data: simple mutation]
- expected: FAIL
+ expected: TIMEOUT
[characterData Text.appendData: simple mutation]
- expected: FAIL
+ expected: TIMEOUT
[characterData Text.appendData: empty string mutation]
- expected: FAIL
+ expected: TIMEOUT
[characterData Text.appendData: null string mutation]
- expected: FAIL
+ expected: TIMEOUT
[characterData Text.insertData: simple mutation]
- expected: FAIL
+ expected: TIMEOUT
[characterData Text.insertData: empty string mutation]
- expected: FAIL
+ expected: TIMEOUT
[characterData Text.insertData: null string mutation]
- expected: FAIL
+ expected: TIMEOUT
[characterData Text.deleteData: simple mutation]
- expected: FAIL
+ expected: TIMEOUT
[characterData Text.deleteData: empty mutation]
- expected: FAIL
+ expected: TIMEOUT
[characterData Text.replaceData: simple mutation]
- expected: FAIL
+ expected: TIMEOUT
[characterData Text.replaceData: empty mutation]
- expected: FAIL
+ expected: TIMEOUT
[characterData ProcessingInstruction: data mutations]
- expected: FAIL
+ expected: TIMEOUT
[characterData Comment: data mutations]
- expected: FAIL
+ expected: TIMEOUT
[characterData Range.deleteContents: child and data removal mutation]
- expected: FAIL
+ expected: TIMEOUT
[characterData Range.deleteContents: child and data removal mutation (2)]
- expected: FAIL
+ expected: TIMEOUT
[characterData Range.extractContents: child and data removal mutation]
- expected: FAIL
+ expected: TIMEOUT
[characterData Range.extractContents: child and data removal mutation (2)]
- expected: FAIL
+ expected: TIMEOUT
[characterData/characterDataOldValue alone Text.data: simple mutation]
- expected: FAIL
+ expected: TIMEOUT
diff --git a/tests/wpt/metadata/dom/nodes/MutationObserver-childList.html.ini b/tests/wpt/metadata/dom/nodes/MutationObserver-childList.html.ini
index 7d5ce7fb070..91a99722ec5 100644
--- a/tests/wpt/metadata/dom/nodes/MutationObserver-childList.html.ini
+++ b/tests/wpt/metadata/dom/nodes/MutationObserver-childList.html.ini
@@ -1,95 +1,90 @@
[MutationObserver-childList.html]
type: testharness
- [childList Node.nodeValue: no mutation]
- expected: FAIL
-
+ expected: TIMEOUT
[childList Node.textContent: replace content mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.textContent: no previous content mutation]
- expected: FAIL
-
- [childList Node.textContent: textContent no mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.textContent: empty string mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.normalize mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.normalize mutations]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.insertBefore: addition mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.insertBefore: removal mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.insertBefore: removal and addition mutations]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.insertBefore: fragment addition mutations]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.insertBefore: fragment removal mutations]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.insertBefore: last child addition mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.appendChild: addition mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.appendChild: removal mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.appendChild: removal and addition mutations]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.appendChild: fragment addition mutations]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.appendChild: fragment removal mutations]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.appendChild: addition outside document tree mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.replaceChild: replacement mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.replaceChild: removal mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.replaceChild: internal replacement mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.removeChild: removal mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Range.deleteContents: child removal mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Range.deleteContents: child and data removal mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Range.extractContents: child removal mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Range.extractContents: child and data removal mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Range.insertNode: child insertion mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Range.insertNode: children insertion mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Range.surroundContents: children removal and addition mutation]
- expected: FAIL
+ expected: TIMEOUT
[childList Node.replaceChild: self internal replacement mutation]
- expected: FAIL
+ expected: TIMEOUT
diff --git a/tests/wpt/metadata/dom/nodes/MutationObserver-inner-outer.html.ini b/tests/wpt/metadata/dom/nodes/MutationObserver-inner-outer.html.ini
index cc46ef272e3..5c86ae99f38 100644
--- a/tests/wpt/metadata/dom/nodes/MutationObserver-inner-outer.html.ini
+++ b/tests/wpt/metadata/dom/nodes/MutationObserver-inner-outer.html.ini
@@ -1,11 +1,12 @@
[MutationObserver-inner-outer.html]
type: testharness
+ expected: TIMEOUT
[innerHTML mutation]
expected: FAIL
[innerHTML with 2 children mutation]
- expected: FAIL
+ expected: TIMEOUT
[outerHTML mutation]
- expected: FAIL
+ expected: TIMEOUT
diff --git a/tests/wpt/metadata/html/rendering/non-replaced-elements/lists/li-type-supported-xhtml.xhtml.ini b/tests/wpt/metadata/html/rendering/non-replaced-elements/lists/li-type-supported-xhtml.xhtml.ini
deleted file mode 100644
index 3ac5a7343ca..00000000000
--- a/tests/wpt/metadata/html/rendering/non-replaced-elements/lists/li-type-supported-xhtml.xhtml.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[li-type-supported-xhtml.xhtml]
- type: reftest
- expected: FAIL
diff --git a/tests/wpt/metadata/html/rendering/non-replaced-elements/lists/li-type-supported.html.ini b/tests/wpt/metadata/html/rendering/non-replaced-elements/lists/li-type-supported.html.ini
deleted file mode 100644
index 1f631a1d1b8..00000000000
--- a/tests/wpt/metadata/html/rendering/non-replaced-elements/lists/li-type-supported.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[li-type-supported.html]
- type: reftest
- expected: FAIL
diff --git a/tests/wpt/metadata/quirks-mode/supports.html.ini b/tests/wpt/metadata/quirks-mode/supports.html.ini
index d3fb177270f..f1968d02eba 100644
--- a/tests/wpt/metadata/quirks-mode/supports.html.ini
+++ b/tests/wpt/metadata/quirks-mode/supports.html.ini
@@ -1,8 +1,5 @@
[supports.html]
type: testharness
- [@supports quirky color]
- expected: FAIL
-
[Sanity check @supports length]
expected: FAIL
diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json
index f5cd627bb58..6e1e2c6fd99 100644
--- a/tests/wpt/mozilla/meta/MANIFEST.json
+++ b/tests/wpt/mozilla/meta/MANIFEST.json
@@ -3731,6 +3731,18 @@
{}
]
],
+ "css/min_width_percent_root_a.html": [
+ [
+ "/_mozilla/css/min_width_percent_root_a.html",
+ [
+ [
+ "/_mozilla/css/min_width_percent_root_b.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
"css/min_width_simple_a.html": [
[
"/_mozilla/css/min_width_simple_a.html",
@@ -5849,6 +5861,18 @@
{}
]
],
+ "css/transform_3d_from_outside_viewport.html": [
+ [
+ "/_mozilla/css/transform_3d_from_outside_viewport.html",
+ [
+ [
+ "/_mozilla/css/transform_3d_from_outside_viewport_ref.html",
+ "!="
+ ]
+ ],
+ {}
+ ]
+ ],
"css/transform_optimization.html": [
[
"/_mozilla/css/transform_optimization.html",
@@ -8359,6 +8383,11 @@
{}
]
],
+ "css/min_width_percent_root_b.html": [
+ [
+ {}
+ ]
+ ],
"css/min_width_simple_b.html": [
[
{}
@@ -9259,6 +9288,11 @@
{}
]
],
+ "css/transform_3d_from_outside_viewport_ref.html": [
+ [
+ {}
+ ]
+ ],
"css/transform_3d_ref.html": [
[
{}
@@ -11168,6 +11202,21 @@
[
{}
]
+ ],
+ "mozilla/worklets/syntax_error.js": [
+ [
+ {}
+ ]
+ ],
+ "mozilla/worklets/test_worklet.js": [
+ [
+ {}
+ ]
+ ],
+ "mozilla/worklets/throw_exception.js": [
+ [
+ {}
+ ]
]
},
"testharness": {
@@ -20010,6 +20059,12 @@
"/_mozilla/mozilla/windowproxy.html",
{}
]
+ ],
+ "mozilla/worklets/test_worklet.html": [
+ [
+ "/_mozilla/mozilla/worklets/test_worklet.html",
+ {}
+ ]
]
}
},
@@ -22622,6 +22677,14 @@
"e8ee634ab6350ad4c870cb1d0ce4f1a88b285581",
"support"
],
+ "css/min_width_percent_root_a.html": [
+ "e8c23bc78daed932d5b513b972582e21711ea06a",
+ "reftest"
+ ],
+ "css/min_width_percent_root_b.html": [
+ "4c5b54f6b4e1bb77a15fdf7d99f9be3a47df7e8b",
+ "support"
+ ],
"css/min_width_simple_a.html": [
"e709d1ab4096401ecb7b848d9297c00ef7786bf9",
"reftest"
@@ -24074,6 +24137,14 @@
"1450d169d4c5506fff240adca5c28b0cb6accd9f",
"reftest"
],
+ "css/transform_3d_from_outside_viewport.html": [
+ "b59ccc70dec5de8bf55440ef3d4dd35d2ec1493a",
+ "reftest"
+ ],
+ "css/transform_3d_from_outside_viewport_ref.html": [
+ "87531bec4e8b60f17d885d6236ec0629f68f6c9a",
+ "support"
+ ],
"css/transform_3d_ref.html": [
"e59866f74ae9dc10a2220c1bb240862371f3edc9",
"support"
@@ -25771,7 +25842,7 @@
"testharness"
],
"mozilla/interfaces.html": [
- "21e18bafdbfe5f3aa0ee71766bdc3b6a7e334226",
+ "49dd9f6ef449813f2ce943d4c9fac351357e5c74",
"testharness"
],
"mozilla/interfaces.js": [
@@ -31689,6 +31760,22 @@
"mozilla/windowproxy.html": [
"128cd0aa5cf80f60078979039036d32b470b0616",
"testharness"
+ ],
+ "mozilla/worklets/syntax_error.js": [
+ "f3a9b8c78346507bc0b3190c8000ccf80cc133f6",
+ "support"
+ ],
+ "mozilla/worklets/test_worklet.html": [
+ "fe9c93a5307c616f878b6623155e1b04c86dd994",
+ "testharness"
+ ],
+ "mozilla/worklets/test_worklet.js": [
+ "9d5f8a07cd62a10f4f5ff93744672e5a6fdbc2b0",
+ "support"
+ ],
+ "mozilla/worklets/throw_exception.js": [
+ "ebfdae19db68fed8e69142ef73842ac9921e4463",
+ "support"
]
},
"url_base": "/_mozilla/",
diff --git a/tests/wpt/mozilla/meta/mozilla/adopted_node_is_same_origin_domain.html.ini b/tests/wpt/mozilla/meta/mozilla/adopted_node_is_same_origin_domain.html.ini
index 3c4d9edc50f..829514a8656 100644
--- a/tests/wpt/mozilla/meta/mozilla/adopted_node_is_same_origin_domain.html.ini
+++ b/tests/wpt/mozilla/meta/mozilla/adopted_node_is_same_origin_domain.html.ini
@@ -2,3 +2,4 @@
type: testharness
[Adopting a node should make it same-origin-domain.]
expected: FAIL
+
diff --git a/tests/wpt/mozilla/meta/mozilla/worklets/test_worklet.html.ini b/tests/wpt/mozilla/meta/mozilla/worklets/test_worklet.html.ini
new file mode 100644
index 00000000000..37762a513dd
--- /dev/null
+++ b/tests/wpt/mozilla/meta/mozilla/worklets/test_worklet.html.ini
@@ -0,0 +1,3 @@
+[test_worklet.html]
+ type: testharness
+ prefs: [dom.worklet.testing.enabled:true]
diff --git a/tests/wpt/mozilla/tests/css/min_width_percent_root_a.html b/tests/wpt/mozilla/tests/css/min_width_percent_root_a.html
new file mode 100644
index 00000000000..0def43e7e3c
--- /dev/null
+++ b/tests/wpt/mozilla/tests/css/min_width_percent_root_a.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="UTF-8">
+ <link rel="match" href="min_width_percent_root_b.html">
+ <title>absolute root element with percentage min-width</title>
+ <style>
+ html {
+ position: absolute;
+ min-width: 100%;
+ border: 2px solid red;
+ }
+ </style>
+ </head>
+ <body></body>
+</html>
diff --git a/tests/wpt/mozilla/tests/css/min_width_percent_root_b.html b/tests/wpt/mozilla/tests/css/min_width_percent_root_b.html
new file mode 100644
index 00000000000..fad1df06f09
--- /dev/null
+++ b/tests/wpt/mozilla/tests/css/min_width_percent_root_b.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="UTF-8">
+ <title>absolute root element with percentage min-width reference</title>
+ <style>
+ html {
+ min-width: 100%;
+ border: 2px solid red;
+ }
+ </style>
+ </head>
+ <body></body>
+</html>
diff --git a/tests/wpt/mozilla/tests/css/transform_3d_from_outside_viewport.html b/tests/wpt/mozilla/tests/css/transform_3d_from_outside_viewport.html
new file mode 100644
index 00000000000..f400968bb85
--- /dev/null
+++ b/tests/wpt/mozilla/tests/css/transform_3d_from_outside_viewport.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Ensure that content transformed from outside the viewport is displayed</title>
+ <link rel="match" href="transform_3d_from_outside_viewport_ref.html">
+ <style>
+ #container {
+ left: 0;
+ top: 0;
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+ perspective: 2000px;
+ perspective-origin: 20% 50%;
+ background: yellow;
+ }
+
+ #transformed {
+ height: 200px;
+ transform: translate3d(0px, 0px, -1300px) rotateY(45deg);
+ background: green;
+ }
+ </style>
+</head>
+
+<body>
+ <div id="container">
+ <div id="transformed"></div>
+ </div>
+</body>
+</html>
diff --git a/tests/wpt/mozilla/tests/css/transform_3d_from_outside_viewport_ref.html b/tests/wpt/mozilla/tests/css/transform_3d_from_outside_viewport_ref.html
new file mode 100644
index 00000000000..1cd20131596
--- /dev/null
+++ b/tests/wpt/mozilla/tests/css/transform_3d_from_outside_viewport_ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Ensure that content transformed from outside the viewport is displayed</title>
+ <style>
+ body {
+ background: yellow;
+ }
+ </style>
+</head>
+
+<body>
+</body>
+</html>
diff --git a/tests/wpt/mozilla/tests/mozilla/interfaces.html b/tests/wpt/mozilla/tests/mozilla/interfaces.html
index a29f439a7c6..ee987ae9322 100644
--- a/tests/wpt/mozilla/tests/mozilla/interfaces.html
+++ b/tests/wpt/mozilla/tests/mozilla/interfaces.html
@@ -200,6 +200,7 @@ test_interfaces([
"WebSocket",
"Window",
"Worker",
+ "Worklet",
"XMLDocument",
"XMLHttpRequest",
"XMLHttpRequestEventTarget",
diff --git a/tests/wpt/mozilla/tests/mozilla/worklets/syntax_error.js b/tests/wpt/mozilla/tests/mozilla/worklets/syntax_error.js
new file mode 100644
index 00000000000..4adade8939c
--- /dev/null
+++ b/tests/wpt/mozilla/tests/mozilla/worklets/syntax_error.js
@@ -0,0 +1 @@
+{];
diff --git a/tests/wpt/mozilla/tests/mozilla/worklets/test_worklet.html b/tests/wpt/mozilla/tests/mozilla/worklets/test_worklet.html
new file mode 100644
index 00000000000..d7a9efa04fe
--- /dev/null
+++ b/tests/wpt/mozilla/tests/mozilla/worklets/test_worklet.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Test worklet loading</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script>
+var testWorklet = new TestWorklet();
+var host_info = get_host_info();
+
+promise_test(function() {
+ return testWorklet.addModule("test_worklet.js")
+ .then(function () {
+ assert_equals(testWorklet.lookup("hello"), "world");
+ });
+}, "Loading a test worklet.");
+
+promise_test(function(t) {
+ var path = new URL("test_worklet.js", document.location).pathname;
+ var url = new URL(path, host_info.HTTP_REMOTE_ORIGIN);
+ return promise_rejects(t, "AbortError", testWorklet.addModule(url));
+}, "Loading a cross-origin test worklet.");
+
+promise_test(function(t) {
+ return promise_rejects(t, "AbortError", testWorklet.addModule("nonexistent_worklet.js"));
+}, "Loading a nonexistent test worklet.");
+
+promise_test(function(t) {
+ return promise_rejects(t, "AbortError", testWorklet.addModule("syntax_error.js"));
+}, "Loading a syntactically incorrect test worklet.");
+
+promise_test(function(t) {
+ return promise_rejects(t, "AbortError", testWorklet.addModule("throw_exception.js"));
+}, "Loading an exception-throwing test worklet.");
+</script>
diff --git a/tests/wpt/mozilla/tests/mozilla/worklets/test_worklet.js b/tests/wpt/mozilla/tests/mozilla/worklets/test_worklet.js
new file mode 100644
index 00000000000..9c0b392a6ab
--- /dev/null
+++ b/tests/wpt/mozilla/tests/mozilla/worklets/test_worklet.js
@@ -0,0 +1 @@
+registerKeyValue("hello", "world");
diff --git a/tests/wpt/mozilla/tests/mozilla/worklets/throw_exception.js b/tests/wpt/mozilla/tests/mozilla/worklets/throw_exception.js
new file mode 100644
index 00000000000..6ca4f80fc27
--- /dev/null
+++ b/tests/wpt/mozilla/tests/mozilla/worklets/throw_exception.js
@@ -0,0 +1 @@
+throw new TypeError();