aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEmilio Cobos Álvarez <ecoal95@gmail.com>2016-08-12 16:30:35 -0700
committerEmilio Cobos Álvarez <ecoal95@gmail.com>2016-08-16 10:58:16 -0700
commit9e88a495c84047d9df0ea07d95342639907c35d6 (patch)
treec51668ca3fce9a567c187bd1670742555c388ca7
parent40c04b4c6b6a3d52b5a3e658e11bccb595783336 (diff)
downloadservo-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.rs1
-rw-r--r--components/style/cascade_info.rs78
-rw-r--r--components/style/custom_properties.rs6
-rw-r--r--components/style/lib.rs1
-rw-r--r--components/style/matching.rs6
-rw-r--r--components/style/properties/helpers.mako.rs14
-rw-r--r--components/style/properties/properties.mako.rs57
-rw-r--r--components/style/selector_matching.rs10
-rw-r--r--tests/wpt/mozilla/meta/MANIFEST.json24
-rw-r--r--tests/wpt/mozilla/tests/css/dirty_viewport.html11
-rw-r--r--tests/wpt/mozilla/tests/css/dirty_viewport_inner.html11
-rw-r--r--tests/wpt/mozilla/tests/css/dirty_viewport_ref.html9
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>