Auto merge of #18398 - canaltinova:at-page-rule, r=emilio

stylo: Pass the @page values to precomputed pseudo element declarations

We were parsing @page rules correctly and serializing for cssom when we
we need. But we weren't actually including them to the pseudo element
declarations when we need to print a page.

Reviewed by emilio on Bugzilla.

---
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] These changes fix [Bug 1394035](https://bugzilla.mozilla.org/show_bug.cgi?id=1394035)

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/18398)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-09-06 16:40:33 -05:00 committed by GitHub
commit 094502e55f
2 changed files with 119 additions and 16 deletions

View file

@ -21,7 +21,7 @@ use properties::{AnimationRules, PropertyDeclarationBlock};
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
use properties::INHERIT_ALL; use properties::INHERIT_ALL;
use properties::IS_LINK; use properties::IS_LINK;
use rule_tree::{CascadeLevel, RuleTree, StyleSource}; use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource};
use selector_map::{PrecomputedHashMap, SelectorMap, SelectorMapEntry}; use selector_map::{PrecomputedHashMap, SelectorMap, SelectorMapEntry};
use selector_parser::{SelectorImpl, PerPseudoElementMap, PseudoElement}; use selector_parser::{SelectorImpl, PerPseudoElementMap, PseudoElement};
use selectors::attr::NamespaceConstraint; use selectors::attr::NamespaceConstraint;
@ -40,7 +40,7 @@ use std::ops;
use style_traits::viewport::ViewportConstraints; use style_traits::viewport::ViewportConstraints;
use stylesheet_set::{OriginValidity, SheetRebuildKind, StylesheetSet, StylesheetIterator, StylesheetFlusher}; use stylesheet_set::{OriginValidity, SheetRebuildKind, StylesheetSet, StylesheetIterator, StylesheetFlusher};
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use stylesheets::{CounterStyleRule, FontFaceRule, FontFeatureValuesRule}; use stylesheets::{CounterStyleRule, FontFaceRule, FontFeatureValuesRule, PageRule};
use stylesheets::{CssRule, Origin, OriginSet, PerOrigin, PerOriginIter}; use stylesheets::{CssRule, Origin, OriginSet, PerOrigin, PerOriginIter};
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use stylesheets::{MallocEnclosingSizeOfFn, MallocSizeOf, MallocSizeOfBox, MallocSizeOfFn}; use stylesheets::{MallocEnclosingSizeOfFn, MallocSizeOf, MallocSizeOfBox, MallocSizeOfFn};
@ -357,6 +357,12 @@ impl DocumentCascadeData {
.borrow_mut_for_origin(&origin) .borrow_mut_for_origin(&origin)
.add_counter_style(guard, rule); .add_counter_style(guard, rule);
} }
#[cfg(feature = "gecko")]
CssRule::Page(ref rule) => {
_extra_data
.borrow_mut_for_origin(&origin)
.add_page(rule);
}
// We don't care about any other rule. // We don't care about any other rule.
_ => {} _ => {}
} }
@ -711,17 +717,33 @@ impl Stylist {
) -> Arc<ComputedValues> { ) -> Arc<ComputedValues> {
debug_assert!(pseudo.is_precomputed()); debug_assert!(pseudo.is_precomputed());
let rule_node = let rule_node = self.rule_node_for_precomputed_pseudo(
match self.cascade_data.precomputed_pseudo_element_decls.get(pseudo) { guards,
Some(declarations) => { pseudo,
self.rule_tree.insert_ordered_rules_with_important( None,
declarations.into_iter().map(|a| (a.source.clone(), a.level())), );
guards
)
}
None => self.rule_tree.root().clone(),
};
self.precomputed_values_for_pseudo_with_rule_node(
guards,
pseudo,
parent,
cascade_flags,
font_metrics,
&rule_node
)
}
/// Computes the style for a given "precomputed" pseudo-element with
/// given rule node.
pub fn precomputed_values_for_pseudo_with_rule_node(
&self,
guards: &StylesheetGuards,
pseudo: &PseudoElement,
parent: Option<&ComputedValues>,
cascade_flags: CascadeFlags,
font_metrics: &FontMetricsProvider,
rule_node: &StrongRuleNode
) -> Arc<ComputedValues> {
// NOTE(emilio): We skip calculating the proper layout parent style // NOTE(emilio): We skip calculating the proper layout parent style
// here. // here.
// //
@ -739,7 +761,7 @@ impl Stylist {
properties::cascade( properties::cascade(
&self.device, &self.device,
Some(pseudo), Some(pseudo),
&rule_node, rule_node,
guards, guards,
parent, parent,
parent, parent,
@ -751,6 +773,43 @@ impl Stylist {
) )
} }
/// Returns the rule node for given precomputed pseudo-element.
///
/// If we want to include extra declarations to this precomputed pseudo-element,
/// we can provide a vector of ApplicableDeclarationBlock to extra_declarations
/// argument. This is useful for providing extra @page rules.
pub fn rule_node_for_precomputed_pseudo(
&self,
guards: &StylesheetGuards,
pseudo: &PseudoElement,
extra_declarations: Option<Vec<ApplicableDeclarationBlock>>,
) -> StrongRuleNode {
let mut decl;
let declarations = match self.cascade_data.precomputed_pseudo_element_decls.get(pseudo) {
Some(declarations) => {
match extra_declarations {
Some(mut extra_decls) => {
decl = declarations.clone();
decl.append(&mut extra_decls);
Some(&decl)
},
None => Some(declarations),
}
}
None => extra_declarations.as_ref(),
};
match declarations {
Some(decls) => {
self.rule_tree.insert_ordered_rules_with_important(
decls.into_iter().map(|a| (a.source.clone(), a.level())),
guards
)
},
None => self.rule_tree.root().clone(),
}
}
/// Returns the style for an anonymous box of the given type. /// Returns the style for an anonymous box of the given type.
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
pub fn style_for_anonymous( pub fn style_for_anonymous(
@ -1611,6 +1670,10 @@ pub struct ExtraStyleData {
/// A map of effective counter-style rules. /// A map of effective counter-style rules.
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
pub counter_styles: PrecomputedHashMap<Atom, Arc<Locked<CounterStyleRule>>>, pub counter_styles: PrecomputedHashMap<Atom, Arc<Locked<CounterStyleRule>>>,
/// A map of effective page rules.
#[cfg(feature = "gecko")]
pub pages: Vec<Arc<Locked<PageRule>>>,
} }
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
@ -1634,6 +1697,11 @@ impl ExtraStyleData {
let name = rule.read_with(guard).mName.raw::<nsIAtom>().into(); let name = rule.read_with(guard).mName.raw::<nsIAtom>().into();
self.counter_styles.insert(name, rule.clone()); self.counter_styles.insert(name, rule.clone());
} }
/// Add the given @page rule.
fn add_page(&mut self, rule: &Arc<Locked<PageRule>>) {
self.pages.push(rule.clone());
}
} }
impl ExtraStyleData { impl ExtraStyleData {
@ -1643,6 +1711,7 @@ impl ExtraStyleData {
self.font_faces.clear(); self.font_faces.clear();
self.font_feature_values.clear(); self.font_feature_values.clear();
self.counter_styles.clear(); self.counter_styles.clear();
self.pages.clear();
} }
} }

View file

@ -12,6 +12,7 @@ use std::env;
use std::fmt::Write; use std::fmt::Write;
use std::iter; use std::iter;
use std::ptr; use std::ptr;
use style::applicable_declarations::ApplicableDeclarationBlock;
use style::context::{CascadeInputs, QuirksMode, SharedStyleContext, StyleContext}; use style::context::{CascadeInputs, QuirksMode, SharedStyleContext, StyleContext};
use style::context::ThreadLocalStyleContext; use style::context::ThreadLocalStyleContext;
use style::data::ElementStyles; use style::data::ElementStyles;
@ -113,7 +114,7 @@ use style::properties::PROHIBIT_DISPLAY_CONTENTS;
use style::properties::animated_properties::{AnimatableLonghand, AnimationValue}; use style::properties::animated_properties::{AnimatableLonghand, AnimationValue};
use style::properties::animated_properties::compare_property_priority; use style::properties::animated_properties::compare_property_priority;
use style::properties::parse_one_declaration_into; use style::properties::parse_one_declaration_into;
use style::rule_tree::StyleSource; use style::rule_tree::{CascadeLevel, StyleSource};
use style::selector_parser::PseudoElementCascadeType; use style::selector_parser::PseudoElementCascadeType;
use style::shared_lock::{SharedRwLockReadGuard, StylesheetGuards, ToCssWithGuard, Locked}; use style::shared_lock::{SharedRwLockReadGuard, StylesheetGuards, ToCssWithGuard, Locked};
use style::string_cache::Atom; use style::string_cache::Atom;
@ -1679,11 +1680,44 @@ pub extern "C" fn Servo_ComputedValues_GetForAnonymousBox(parent_style_or_null:
cascade_flags.insert(IS_FIELDSET_CONTENT); cascade_flags.insert(IS_FIELDSET_CONTENT);
} }
let metrics = get_metrics_provider_for_product(); let metrics = get_metrics_provider_for_product();
data.stylist.precomputed_values_for_pseudo(
// If the pseudo element is PageContent, we should append the precomputed
// pseudo element declerations with specified page rules.
let page_decls = match pseudo {
PseudoElement::PageContent => {
let mut declarations = vec![];
let iter = data.extra_style_data.iter_origins_rev();
for (data, origin) in iter {
let level = match origin {
Origin::UserAgent => CascadeLevel::UANormal,
Origin::User => CascadeLevel::UserNormal,
Origin::Author => CascadeLevel::AuthorNormal,
};
for rule in data.pages.iter() {
declarations.push(ApplicableDeclarationBlock::from_declarations(
rule.read_with(level.guard(&guards)).block.clone(),
level
));
}
}
Some(declarations)
},
_ => None,
};
let rule_node = data.stylist.rule_node_for_precomputed_pseudo(
&guards,
&pseudo,
page_decls,
);
data.stylist.precomputed_values_for_pseudo_with_rule_node(
&guards, &guards,
&pseudo, &pseudo,
parent_style_or_null.map(|x| &*x), parent_style_or_null.map(|x| &*x),
cascade_flags, &metrics cascade_flags,
&metrics,
&rule_node
).into() ).into()
} }