diff options
author | Emilio Cobos Álvarez <ecoal95@gmail.com> | 2016-08-12 16:30:35 -0700 |
---|---|---|
committer | Emilio Cobos Álvarez <ecoal95@gmail.com> | 2016-08-16 10:58:16 -0700 |
commit | 9e88a495c84047d9df0ea07d95342639907c35d6 (patch) | |
tree | c51668ca3fce9a567c187bd1670742555c388ca7 | |
parent | 40c04b4c6b6a3d52b5a3e658e11bccb595783336 (diff) | |
download | servo-9e88a495c84047d9df0ea07d95342639907c35d6.tar.gz servo-9e88a495c84047d9df0ea07d95342639907c35d6.zip |
style: Introduce a generic way of gathering information from the cascade, and use it for viewport units.
-rw-r--r-- | components/style/animation.rs | 1 | ||||
-rw-r--r-- | components/style/cascade_info.rs | 78 | ||||
-rw-r--r-- | components/style/custom_properties.rs | 6 | ||||
-rw-r--r-- | components/style/lib.rs | 1 | ||||
-rw-r--r-- | components/style/matching.rs | 6 | ||||
-rw-r--r-- | components/style/properties/helpers.mako.rs | 14 | ||||
-rw-r--r-- | components/style/properties/properties.mako.rs | 57 | ||||
-rw-r--r-- | components/style/selector_matching.rs | 10 | ||||
-rw-r--r-- | tests/wpt/mozilla/meta/MANIFEST.json | 24 | ||||
-rw-r--r-- | tests/wpt/mozilla/tests/css/dirty_viewport.html | 11 | ||||
-rw-r--r-- | tests/wpt/mozilla/tests/css/dirty_viewport_inner.html | 11 | ||||
-rw-r--r-- | tests/wpt/mozilla/tests/css/dirty_viewport_ref.html | 9 |
12 files changed, 205 insertions, 23 deletions
diff --git a/components/style/animation.rs b/components/style/animation.rs index 1767cd49234..63ddc9e8c69 100644 --- a/components/style/animation.rs +++ b/components/style/animation.rs @@ -394,6 +394,7 @@ fn compute_style_for_animation_step(context: &SharedStyleContext, false, Some(previous_style), None, + None, context.error_reporter.clone()); computed } diff --git a/components/style/cascade_info.rs b/components/style/cascade_info.rs new file mode 100644 index 00000000000..d0c584e7e0f --- /dev/null +++ b/components/style/cascade_info.rs @@ -0,0 +1,78 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use dom::TNode; +use properties::{DeclaredValue, PropertyDeclaration}; +use values::HasViewportPercentage; + +/// A structure to collect information about the cascade. +/// +/// This is useful to gather information about what an element is affected by, +/// and can be used in the future to track optimisations like when a +/// non-inherited property is explicitly inherited, in order to cut-off the +/// traversal. +pub struct CascadeInfo { + pub saw_viewport_units: bool, + #[cfg(debug_assertions)] + finished: bool, +} + +impl CascadeInfo { + #[cfg(debug_assertions)] + pub fn new() -> Self { + CascadeInfo { + saw_viewport_units: false, + finished: false, + } + } + + #[cfg(not(debug_assertions))] + pub fn new() -> Self { + CascadeInfo { + saw_viewport_units: false, + } + } + + /// Called when a property is cascaded. + /// + /// NOTE: We can add a vast amount of information here. + #[inline] + pub fn on_cascade_property<T>(&mut self, + _property_declaration: &PropertyDeclaration, + value: &DeclaredValue<T>) + where T: HasViewportPercentage + { + // TODO: we can be smarter and keep a property bitfield to keep track of + // the last applying rule. + if value.has_viewport_percentage() { + self.saw_viewport_units = true; + } + } + + #[cfg(debug_assertions)] + fn mark_as_finished_if_appropriate(&mut self) { + self.finished = true; + } + + #[cfg(not(debug_assertions))] + fn mark_as_finished_if_appropriate(&mut self) {} + + #[allow(unsafe_code)] + pub fn finish<N: TNode>(mut self, node: &N) { + self.mark_as_finished_if_appropriate(); + + if self.saw_viewport_units { + unsafe { + node.set_dirty_on_viewport_size_changed(); + } + } + } +} + +#[cfg(debug_assertions)] +impl Drop for CascadeInfo { + fn drop(&mut self) { + debug_assert!(self.finished, + "Didn't use the result of CascadeInfo, if you don't need it, consider passing None"); + } +} diff --git a/components/style/custom_properties.rs b/components/style/custom_properties.rs index 5a7109f77ac..5189bbeaa37 100644 --- a/components/style/custom_properties.rs +++ b/components/style/custom_properties.rs @@ -39,6 +39,12 @@ pub struct SpecifiedValue { references: HashSet<Name>, } +impl ::values::HasViewportPercentage for SpecifiedValue { + fn has_viewport_percentage(&self) -> bool { + panic!("has_viewport_percentage called before resolving!"); + } +} + pub struct BorrowedSpecifiedValue<'a> { css: &'a str, first_token_type: TokenSerializationType, diff --git a/components/style/lib.rs b/components/style/lib.rs index 1f760aa6d10..4cab0c84b47 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -74,6 +74,7 @@ pub mod animation; pub mod attr; pub mod bezier; pub mod cache; +pub mod cascade_info; pub mod context; pub mod custom_properties; pub mod data; diff --git a/components/style/matching.rs b/components/style/matching.rs index 16f0b7571b1..f3bd443ee43 100644 --- a/components/style/matching.rs +++ b/components/style/matching.rs @@ -9,6 +9,7 @@ use animation; use arc_ptr_eq; use cache::{LRUCache, SimpleHashCache}; +use cascade_info::CascadeInfo; use context::{StyleContext, SharedStyleContext}; use data::PrivateStyleData; use dom::{TElement, TNode, TRestyleDamage}; @@ -443,6 +444,7 @@ trait PrivateMatchMethods: TNode { &mut old_style) && cacheable; } + let mut cascade_info = CascadeInfo::new(); let (this_style, is_cacheable) = match parent_style { Some(ref parent_style) => { let cache_entry = applicable_declarations_cache.find(applicable_declarations); @@ -456,6 +458,7 @@ trait PrivateMatchMethods: TNode { shareable, Some(&***parent_style), cached_computed_values, + Some(&mut cascade_info), shared_context.error_reporter.clone()) } None => { @@ -464,9 +467,11 @@ trait PrivateMatchMethods: TNode { shareable, None, None, + Some(&mut cascade_info), shared_context.error_reporter.clone()) } }; + cascade_info.finish(self); cacheable = cacheable && is_cacheable; @@ -497,7 +502,6 @@ trait PrivateMatchMethods: TNode { cacheable = cacheable && !animations_started } - // Cache the resolved style if it was cacheable. if cacheable { applicable_declarations_cache.insert(applicable_declarations.to_vec(), diff --git a/components/style/properties/helpers.mako.rs b/components/style/properties/helpers.mako.rs index fc6caa1cda3..09ebc9318bc 100644 --- a/components/style/properties/helpers.mako.rs +++ b/components/style/properties/helpers.mako.rs @@ -167,6 +167,7 @@ use parser::{ParserContext, ParserContextExtraData}; use properties::{CSSWideKeyword, DeclaredValue, Shorthand}; % endif + use cascade_info::CascadeInfo; use error_reporting::ParseErrorReporter; use properties::longhands; use properties::property_bit_field::PropertyBitField; @@ -185,6 +186,7 @@ context: &mut computed::Context, seen: &mut PropertyBitField, cacheable: &mut bool, + cascade_info: &mut Option<<&mut CascadeInfo>, error_reporter: &mut StdBox<ParseErrorReporter + Send>) { let declared_value = match *declaration { PropertyDeclaration::${property.camel_case}(ref declared_value) => { @@ -200,7 +202,13 @@ { let custom_props = context.style().custom_properties(); ::properties::substitute_variables_${property.ident}( - declared_value, &custom_props, |value| match *value { + declared_value, &custom_props, + |value| { + if let Some(ref mut cascade_info) = *cascade_info { + cascade_info.on_cascade_property(&declaration, + &value); + } + match *value { DeclaredValue::Value(ref specified_value) => { let computed = specified_value.to_computed_value(context); context.mutate_style().mutate_${data.current_style_struct.name_lower}() @@ -226,8 +234,8 @@ context.mutate_style().mutate_${data.current_style_struct.name_lower}() .copy_${property.ident}_from(inherited_struct); } - }, error_reporter - ); + } + }, error_reporter); } % if property.custom_cascade: diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index 5e908f17d9a..986e0bc3e43 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -34,6 +34,7 @@ use stylesheets::Origin; use values::LocalToCss; use values::HasViewportPercentage; use values::computed::{self, ToComputedValue}; +use cascade_info::CascadeInfo; #[cfg(feature = "servo")] use values::specified::BorderStyle; use self::property_bit_field::PropertyBitField; @@ -773,6 +774,19 @@ pub enum DeclaredValue<T> { // depending on whether the property is inherited. } +impl<T: HasViewportPercentage> HasViewportPercentage for DeclaredValue<T> { + fn has_viewport_percentage(&self) -> bool { + match *self { + DeclaredValue::Value(ref v) + => v.has_viewport_percentage(), + DeclaredValue::WithVariables { .. } + => panic!("DeclaredValue::has_viewport_percentage without resolving variables!"), + DeclaredValue::Initial | + DeclaredValue::Inherit => false, + } + } +} + impl<T: ToCss> ToCss for DeclaredValue<T> { fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { match *self { @@ -797,6 +811,20 @@ pub enum PropertyDeclaration { Custom(::custom_properties::Name, DeclaredValue<::custom_properties::SpecifiedValue>), } +impl HasViewportPercentage for PropertyDeclaration { + fn has_viewport_percentage(&self) -> bool { + match *self { + % for property in data.longhands: + PropertyDeclaration::${property.camel_case}(ref val) => { + val.has_viewport_percentage() + }, + % endfor + PropertyDeclaration::Custom(_, ref val) => { + val.has_viewport_percentage() + } + } + } +} #[derive(Eq, PartialEq, Copy, Clone)] pub enum PropertyDeclarationParseResult { @@ -854,19 +882,6 @@ impl ToCss for PropertyDeclaration { } } -impl HasViewportPercentage for PropertyDeclaration { - fn has_viewport_percentage(&self) -> bool { - match *self { - % for property in data.longhands: - PropertyDeclaration::${property.camel_case}(DeclaredValue::Value(ref val)) => { - val.has_viewport_percentage() - }, - % endfor - _ => false - } - } -} - impl PropertyDeclaration { pub fn name(&self) -> PropertyDeclarationName { match *self { @@ -1622,6 +1637,7 @@ fn cascade_with_cached_declarations( parent_style: &ComputedValues, cached_style: &ComputedValues, custom_properties: Option<Arc<::custom_properties::ComputedValuesMap>>, + mut cascade_info: Option<<&mut CascadeInfo>, mut error_reporter: StdBox<ParseErrorReporter + Send>) -> ComputedValues { let mut context = computed::Context { @@ -1664,7 +1680,12 @@ fn cascade_with_cached_declarations( let custom_props = context.style().custom_properties(); substitute_variables_${property.ident}( declared_value, &custom_props, - |value| match *value { + |value| { + if let Some(ref mut cascade_info) = cascade_info { + cascade_info.on_cascade_property(&declaration, + &value); + } + match *value { DeclaredValue::Value(ref specified_value) => { let computed = specified_value.to_computed_value(&context); @@ -1688,8 +1709,8 @@ fn cascade_with_cached_declarations( .copy_${property.ident}_from(inherited_struct); } DeclaredValue::WithVariables { .. } => unreachable!() - }, &mut error_reporter - ); + } + }, &mut error_reporter); % endif % if property.name in data.derived_longhands: @@ -1728,6 +1749,7 @@ pub type CascadePropertyFn = context: &mut computed::Context, seen: &mut PropertyBitField, cacheable: &mut bool, + cascade_info: &mut Option<<&mut CascadeInfo>, error_reporter: &mut StdBox<ParseErrorReporter + Send>); #[cfg(feature = "servo")] @@ -1760,6 +1782,7 @@ pub fn cascade(viewport_size: Size2D<Au>, shareable: bool, parent_style: Option<<&ComputedValues>, cached_style: Option<<&ComputedValues>, + mut cascade_info: Option<<&mut CascadeInfo>, mut error_reporter: StdBox<ParseErrorReporter + Send>) -> (ComputedValues, bool) { let initial_values = ComputedValues::initial_values(); @@ -1794,6 +1817,7 @@ pub fn cascade(viewport_size: Size2D<Au>, parent_style, cached_style, custom_properties, + cascade_info, error_reporter); return (style, false) } @@ -1863,6 +1887,7 @@ pub fn cascade(viewport_size: Size2D<Au>, &mut context, &mut seen, &mut cacheable, + &mut cascade_info, &mut error_reporter); } } diff --git a/components/style/selector_matching.rs b/components/style/selector_matching.rs index 7b18a897d73..2ae05ce1d6f 100644 --- a/components/style/selector_matching.rs +++ b/components/style/selector_matching.rs @@ -230,6 +230,7 @@ impl Stylist { &declarations, false, parent.map(|p| &**p), None, + None, Box::new(StdoutErrorReporter)); Some(Arc::new(computed)) } else { @@ -242,8 +243,9 @@ impl Stylist { pseudo: &PseudoElement, parent: &Arc<ComputedValues>) -> Option<Arc<ComputedValues>> - where E: Element<Impl=TheSelectorImpl> + - PresentationalHintsSynthetizer { + where E: Element<Impl=TheSelectorImpl> + + PresentationalHintsSynthetizer + { debug_assert!(TheSelectorImpl::pseudo_element_cascade_type(pseudo).is_lazy()); if self.pseudos_map.get(pseudo).is_none() { return None; @@ -262,8 +264,10 @@ impl Stylist { let (computed, _) = properties::cascade(self.device.au_viewport_size(), &declarations, false, - Some(&**parent), None, + Some(&**parent), None, None, Box::new(StdoutErrorReporter)); + + Some(Arc::new(computed)) } diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json index da98ef5f303..cfe571f4892 100644 --- a/tests/wpt/mozilla/meta/MANIFEST.json +++ b/tests/wpt/mozilla/meta/MANIFEST.json @@ -1356,6 +1356,18 @@ "url": "/_mozilla/css/direction_style_caching.html" } ], + "css/dirty_viewport.html": [ + { + "path": "css/dirty_viewport.html", + "references": [ + [ + "/_mozilla/css/dirty_viewport_ref.html", + "==" + ] + ], + "url": "/_mozilla/css/dirty_viewport.html" + } + ], "css/empty_cells_a.html": [ { "path": "css/empty_cells_a.html", @@ -10576,6 +10588,18 @@ "url": "/_mozilla/css/direction_style_caching.html" } ], + "css/dirty_viewport.html": [ + { + "path": "css/dirty_viewport.html", + "references": [ + [ + "/_mozilla/css/dirty_viewport_ref.html", + "==" + ] + ], + "url": "/_mozilla/css/dirty_viewport.html" + } + ], "css/empty_cells_a.html": [ { "path": "css/empty_cells_a.html", diff --git a/tests/wpt/mozilla/tests/css/dirty_viewport.html b/tests/wpt/mozilla/tests/css/dirty_viewport.html new file mode 100644 index 00000000000..5adc2687d51 --- /dev/null +++ b/tests/wpt/mozilla/tests/css/dirty_viewport.html @@ -0,0 +1,11 @@ +<!doctype html> +<meta charset="utf-8"> +<title>Test elements subject to viewport units are restyled correctly</title> +<link rel="match" href="dirty_viewport_ref.html"> +<iframe seamless src="dirty_viewport_inner.html" width="500" height="500"></iframe> +<script> + window.onload = function() { + var iframe = document.querySelector('iframe'); + iframe.width = iframe.height = 100; + } +</script> diff --git a/tests/wpt/mozilla/tests/css/dirty_viewport_inner.html b/tests/wpt/mozilla/tests/css/dirty_viewport_inner.html new file mode 100644 index 00000000000..de6a46602a6 --- /dev/null +++ b/tests/wpt/mozilla/tests/css/dirty_viewport_inner.html @@ -0,0 +1,11 @@ +<!doctype html> +<title>Dirty viewport test (inner)</title> +<style> + div { + background: green; + width: 50vw; + height: 50vh; + } + html, body { margin: 0; padding: 0; } +</style> +<div></div> diff --git a/tests/wpt/mozilla/tests/css/dirty_viewport_ref.html b/tests/wpt/mozilla/tests/css/dirty_viewport_ref.html new file mode 100644 index 00000000000..759da0245ed --- /dev/null +++ b/tests/wpt/mozilla/tests/css/dirty_viewport_ref.html @@ -0,0 +1,9 @@ +<!doctype html> +<style> + div { + background: green; + width: 50px; + height: 50px; + } +</style> +<div></div> |