servo: Merge #17033 - style: Add support for resolving default computed styles (from heycam:default-cs); r=emilio

Servo-side changes from https://bugzilla.mozilla.org/show_bug.cgi?id=1366157.

Source-Repo: https://github.com/servo/servo
Source-Revision: 7780ef5e431b7c346c0f50ff914fbda9b5017900

--HG--
extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear
extra : subtree_revision : c4752fdd70885e2630d195618d06fb0d9ae1d120
This commit is contained in:
Cameron McCormack 2017-05-25 05:50:52 -05:00
Родитель 05e5c16a8e
Коммит 40bf61aba0
9 изменённых файлов: 2784 добавлений и 2437 удалений

Просмотреть файл

@ -25,6 +25,7 @@ use style::font_metrics::ServoMetricsProvider;
use style::properties::{CascadeFlags, ServoComputedValues}; use style::properties::{CascadeFlags, ServoComputedValues};
use style::selector_parser::{PseudoElement, PseudoElementCascadeType, SelectorImpl}; use style::selector_parser::{PseudoElement, PseudoElementCascadeType, SelectorImpl};
use style::stylearc::Arc; use style::stylearc::Arc;
use style::stylist::RuleInclusion;
use webrender_traits::ClipId; use webrender_traits::ClipId;
#[derive(Copy, PartialEq, Clone, Debug)] #[derive(Copy, PartialEq, Clone, Debug)]
@ -423,6 +424,7 @@ pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + Debug +
&context.guards, &context.guards,
unsafe { &self.unsafe_get() }, unsafe { &self.unsafe_get() },
&style_pseudo, &style_pseudo,
RuleInclusion::All,
data.styles().primary.values(), data.styles().primary.values(),
&ServoMetricsProvider) &ServoMetricsProvider)
.unwrap() .unwrap()

Просмотреть файл

@ -205,6 +205,7 @@ use gecko_bindings::structs::UpdateAnimationsTasks;
use gecko_bindings::structs::ParsingMode; use gecko_bindings::structs::ParsingMode;
use gecko_bindings::structs::InheritTarget; use gecko_bindings::structs::InheritTarget;
use gecko_bindings::structs::URLMatchingFunction; use gecko_bindings::structs::URLMatchingFunction;
use gecko_bindings::structs::StyleRuleInclusion;
pub type nsTArrayBorrowed_uintptr_t<'a> = &'a mut ::gecko_bindings::structs::nsTArray<usize>; pub type nsTArrayBorrowed_uintptr_t<'a> = &'a mut ::gecko_bindings::structs::nsTArray<usize>;
pub type RawServoStyleSetOwned = ::gecko_bindings::sugar::ownership::Owned<RawServoStyleSet>; pub type RawServoStyleSetOwned = ::gecko_bindings::sugar::ownership::Owned<RawServoStyleSet>;
pub type RawServoStyleSetOwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull<RawServoStyleSet>; pub type RawServoStyleSetOwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull<RawServoStyleSet>;
@ -2417,6 +2418,11 @@ extern "C" {
target: InheritTarget) target: InheritTarget)
-> ServoComputedValuesStrong; -> ServoComputedValuesStrong;
} }
extern "C" {
pub fn Servo_ComputedValues_GetVisitedStyle(values:
ServoComputedValuesBorrowed)
-> ServoComputedValuesStrong;
}
extern "C" { extern "C" {
pub fn Servo_Initialize(dummy_url_data: *mut RawGeckoURLExtraData); pub fn Servo_Initialize(dummy_url_data: *mut RawGeckoURLExtraData);
} }
@ -2457,6 +2463,7 @@ extern "C" {
extern "C" { extern "C" {
pub fn Servo_ResolveStyleLazily(element: RawGeckoElementBorrowed, pub fn Servo_ResolveStyleLazily(element: RawGeckoElementBorrowed,
pseudo_type: CSSPseudoElementType, pseudo_type: CSSPseudoElementType,
rule_inclusion: StyleRuleInclusion,
snapshots: snapshots:
*const ServoElementSnapshotTable, *const ServoElementSnapshotTable,
set: RawServoStyleSetBorrowed) set: RawServoStyleSetBorrowed)

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -72,6 +72,8 @@ use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt; use std::fmt;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::mem;
use std::ops::DerefMut;
use std::ptr; use std::ptr;
use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace}; use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
use stylearc::Arc; use stylearc::Arc;
@ -422,6 +424,29 @@ impl<'le> GeckoElement<'le> {
} }
} }
/// Sets the specified element data, return any existing data.
///
/// Like `ensure_data`, only safe to call with exclusive access to the
/// element.
pub unsafe fn set_data(&self, replace_data: Option<ElementData>) -> Option<ElementData> {
match (self.get_data(), replace_data) {
(Some(old), Some(replace_data)) => {
Some(mem::replace(old.borrow_mut().deref_mut(), replace_data))
}
(Some(old), None) => {
let old_data = mem::replace(old.borrow_mut().deref_mut(), ElementData::new(None));
self.0.mServoData.set(ptr::null_mut());
Some(old_data)
}
(None, Some(replace_data)) => {
let ptr = Box::into_raw(Box::new(AtomicRefCell::new(replace_data)));
self.0.mServoData.set(ptr);
None
}
(None, None) => None,
}
}
#[inline] #[inline]
fn has_id(&self) -> bool { fn has_id(&self) -> bool {
self.as_node().get_bool_flag(nsINode_BooleanFlag::ElementHasID) self.as_node().get_bool_flag(nsINode_BooleanFlag::ElementHasID)

Просмотреть файл

@ -24,7 +24,7 @@ use selectors::matching::{ElementSelectorFlags, MatchingContext, MatchingMode, S
use selectors::matching::{VisitedHandlingMode, AFFECTED_BY_PSEUDO_ELEMENTS}; use selectors::matching::{VisitedHandlingMode, AFFECTED_BY_PSEUDO_ELEMENTS};
use sharing::{StyleSharingBehavior, StyleSharingResult}; use sharing::{StyleSharingBehavior, StyleSharingResult};
use stylearc::Arc; use stylearc::Arc;
use stylist::ApplicableDeclarationList; use stylist::{ApplicableDeclarationList, RuleInclusion};
/// The way a style should be inherited. /// The way a style should be inherited.
enum InheritMode { enum InheritMode {
@ -346,7 +346,13 @@ trait PrivateMatchMethods: TElement {
// We could make that a bit better if the complexity cost is not too // We could make that a bit better if the complexity cost is not too
// big, but given further restyles are posted directly to // big, but given further restyles are posted directly to
// pseudo-elements, it doesn't seem worth the effort at a glance. // pseudo-elements, it doesn't seem worth the effort at a glance.
if pseudo.is_eager() { //
// For the same reason as described in match_primary, if we are
// computing default styles, we aren't guaranteed the parent
// will have eagerly computed our styles, so we just handled it
// below like a lazy pseudo.
let only_default_rules = context.shared.traversal_flags.for_default_styles();
if pseudo.is_eager() && !only_default_rules {
let parent = self.parent_element().unwrap(); let parent = self.parent_element().unwrap();
if !parent.may_have_animations() || if !parent.may_have_animations() ||
primary_style.rules.get_animation_rules().is_empty() { primary_style.rules.get_animation_rules().is_empty() {
@ -896,13 +902,24 @@ pub trait MatchMethods : TElement {
{ {
debug!("Match primary for {:?}, visited: {:?}", self, visited_handling); debug!("Match primary for {:?}, visited: {:?}", self, visited_handling);
let only_default_rules = context.shared.traversal_flags.for_default_styles();
let implemented_pseudo = self.implemented_pseudo_element(); let implemented_pseudo = self.implemented_pseudo_element();
if let Some(ref pseudo) = implemented_pseudo { if let Some(ref pseudo) = implemented_pseudo {
// We don't expect to match against a non-canonical pseudo-element. // We don't expect to match against a non-canonical pseudo-element.
debug_assert_eq!(*pseudo, pseudo.canonical()); debug_assert_eq!(*pseudo, pseudo.canonical());
if pseudo.is_eager() { if pseudo.is_eager() && !only_default_rules {
// If it's an eager element-backed pseudo, just grab the matched // If it's an eager element-backed pseudo, we can generally just
// rules from the parent, and update animations. // grab the matched rules from the parent, and then update
// animations.
//
// However, if we're computing default styles, then we might
// have traversed to this pseudo-implementing element without
// any pseudo styles stored on the parent. For example, if
// document-level style sheets cause the element to exist, due
// to ::before rules, then those rules won't be found when
// computing default styles on the parent, so we won't have
// bothered to store pseudo styles there. In this case, we just
// treat it like a lazily computed pseudo.
let parent = self.parent_element().unwrap(); let parent = self.parent_element().unwrap();
let parent_data = parent.borrow_data().unwrap(); let parent_data = parent.borrow_data().unwrap();
let pseudo_style = let pseudo_style =
@ -965,6 +982,12 @@ pub trait MatchMethods : TElement {
self.apply_selector_flags(map, element, flags); self.apply_selector_flags(map, element, flags);
}; };
let rule_inclusion = if only_default_rules {
RuleInclusion::DefaultOnly
} else {
RuleInclusion::All
};
let bloom_filter = context.thread_local.bloom_filter.filter(); let bloom_filter = context.thread_local.bloom_filter.filter();
let mut matching_context = let mut matching_context =
MatchingContext::new_for_visited(MatchingMode::Normal, MatchingContext::new_for_visited(MatchingMode::Normal,
@ -985,6 +1008,7 @@ pub trait MatchMethods : TElement {
style_attribute, style_attribute,
smil_override, smil_override,
animation_rules, animation_rules,
rule_inclusion,
&mut applicable_declarations, &mut applicable_declarations,
&mut matching_context, &mut matching_context,
&mut set_selector_flags); &mut set_selector_flags);
@ -1052,7 +1076,14 @@ pub trait MatchMethods : TElement {
let stylist = &context.shared.stylist; let stylist = &context.shared.stylist;
let guards = &context.shared.guards; let guards = &context.shared.guards;
let rule_inclusion = if context.shared.traversal_flags.for_default_styles() {
RuleInclusion::DefaultOnly
} else {
RuleInclusion::All
};
let bloom_filter = context.thread_local.bloom_filter.filter(); let bloom_filter = context.thread_local.bloom_filter.filter();
let mut matching_context = let mut matching_context =
MatchingContext::new_for_visited(MatchingMode::ForStatelessPseudoElement, MatchingContext::new_for_visited(MatchingMode::ForStatelessPseudoElement,
Some(bloom_filter), Some(bloom_filter),
@ -1076,6 +1107,7 @@ pub trait MatchMethods : TElement {
None, None,
None, None,
AnimationRules(None, None), AnimationRules(None, None),
rule_inclusion,
&mut applicable_declarations, &mut applicable_declarations,
&mut matching_context, &mut matching_context,
&mut set_selector_flags); &mut set_selector_flags);

Просмотреть файл

@ -13,7 +13,7 @@ use element_state::ElementState;
use error_reporting::RustLogReporter; use error_reporting::RustLogReporter;
use font_metrics::FontMetricsProvider; use font_metrics::FontMetricsProvider;
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use gecko_bindings::structs::nsIAtom; use gecko_bindings::structs::{nsIAtom, StyleRuleInclusion};
use keyframes::KeyframesAnimation; use keyframes::KeyframesAnimation;
use media_queries::Device; use media_queries::Device;
use properties::{self, CascadeFlags, ComputedValues}; use properties::{self, CascadeFlags, ComputedValues};
@ -205,6 +205,27 @@ impl<'a> ExtraStyleData<'a> {
fn clear(&mut self) {} fn clear(&mut self) {}
} }
/// What cascade levels to include when styling elements.
#[derive(Copy, Clone, PartialEq)]
pub enum RuleInclusion {
/// Include rules for style sheets at all cascade levels. This is the
/// normal rule inclusion mode.
All,
/// Only include rules from UA and user level sheets. Used to implement
/// `getDefaultComputedStyle`.
DefaultOnly,
}
#[cfg(feature = "gecko")]
impl From<StyleRuleInclusion> for RuleInclusion {
fn from(value: StyleRuleInclusion) -> Self {
match value {
StyleRuleInclusion::All => RuleInclusion::All,
StyleRuleInclusion::DefaultOnly => RuleInclusion::DefaultOnly,
}
}
}
impl Stylist { impl Stylist {
/// Construct a new `Stylist`, using given `Device` and `QuirksMode`. /// Construct a new `Stylist`, using given `Device` and `QuirksMode`.
/// If more members are added here, think about whether they should /// If more members are added here, think about whether they should
@ -625,13 +646,14 @@ impl Stylist {
guards: &StylesheetGuards, guards: &StylesheetGuards,
element: &E, element: &E,
pseudo: &PseudoElement, pseudo: &PseudoElement,
rule_inclusion: RuleInclusion,
parent_style: &ComputedValues, parent_style: &ComputedValues,
font_metrics: &FontMetricsProvider) font_metrics: &FontMetricsProvider)
-> Option<ComputedStyle> -> Option<ComputedStyle>
where E: TElement, where E: TElement,
{ {
let rule_node = let rule_node =
match self.lazy_pseudo_rules(guards, element, pseudo) { match self.lazy_pseudo_rules(guards, element, pseudo, rule_inclusion) {
Some(rule_node) => rule_node, Some(rule_node) => rule_node,
None => return None None => return None
}; };
@ -664,7 +686,8 @@ impl Stylist {
pub fn lazy_pseudo_rules<E>(&self, pub fn lazy_pseudo_rules<E>(&self,
guards: &StylesheetGuards, guards: &StylesheetGuards,
element: &E, element: &E,
pseudo: &PseudoElement) pseudo: &PseudoElement,
rule_inclusion: RuleInclusion)
-> Option<StrongRuleNode> -> Option<StrongRuleNode>
where E: TElement where E: TElement
{ {
@ -683,6 +706,12 @@ impl Stylist {
unreachable!("internal pseudo generated slow selector flags?"); unreachable!("internal pseudo generated slow selector flags?");
} }
// No need to bother setting the selector flags when we're computing
// default styles.
if rule_inclusion == RuleInclusion::DefaultOnly {
return;
}
// Gecko calls this from sequential mode, so we can directly apply // Gecko calls this from sequential mode, so we can directly apply
// the flags. // the flags.
debug_assert!(thread_state::get() == thread_state::LAYOUT); debug_assert!(thread_state::get() == thread_state::LAYOUT);
@ -707,6 +736,7 @@ impl Stylist {
None, None,
None, None,
AnimationRules(None, None), AnimationRules(None, None),
rule_inclusion,
&mut declarations, &mut declarations,
&mut matching_context, &mut matching_context,
&mut set_selector_flags); &mut set_selector_flags);
@ -836,6 +866,7 @@ impl Stylist {
style_attribute: Option<&Arc<Locked<PropertyDeclarationBlock>>>, style_attribute: Option<&Arc<Locked<PropertyDeclarationBlock>>>,
smil_override: Option<&Arc<Locked<PropertyDeclarationBlock>>>, smil_override: Option<&Arc<Locked<PropertyDeclarationBlock>>>,
animation_rules: AnimationRules, animation_rules: AnimationRules,
rule_inclusion: RuleInclusion,
applicable_declarations: &mut V, applicable_declarations: &mut V,
context: &mut MatchingContext, context: &mut MatchingContext,
flags_setter: &mut F) flags_setter: &mut F)
@ -871,6 +902,8 @@ impl Stylist {
debug!("Determining if style is shareable: pseudo: {}", debug!("Determining if style is shareable: pseudo: {}",
pseudo_element.is_some()); pseudo_element.is_some());
let only_default_rules = rule_inclusion == RuleInclusion::DefaultOnly;
// Step 1: Normal user-agent rules. // Step 1: Normal user-agent rules.
map.user_agent.get_all_matching_rules(element, map.user_agent.get_all_matching_rules(element,
&rule_hash_target, &rule_hash_target,
@ -880,7 +913,7 @@ impl Stylist {
CascadeLevel::UANormal); CascadeLevel::UANormal);
debug!("UA normal: {:?}", context.relations); debug!("UA normal: {:?}", context.relations);
if pseudo_element.is_none() { if pseudo_element.is_none() && !only_default_rules {
// Step 2: Presentational hints. // Step 2: Presentational hints.
let length_before_preshints = applicable_declarations.len(); let length_before_preshints = applicable_declarations.len();
element.synthesize_presentational_hints_for_legacy_attributes(applicable_declarations); element.synthesize_presentational_hints_for_legacy_attributes(applicable_declarations);
@ -905,7 +938,7 @@ impl Stylist {
// //
// Which may be more what you would probably expect. // Which may be more what you would probably expect.
if rule_hash_target.matches_user_and_author_rules() { if rule_hash_target.matches_user_and_author_rules() {
// Step 3: User and author normal rules. // Step 3a: User normal rules.
map.user.get_all_matching_rules(element, map.user.get_all_matching_rules(element,
&rule_hash_target, &rule_hash_target,
applicable_declarations, applicable_declarations,
@ -913,6 +946,12 @@ impl Stylist {
flags_setter, flags_setter,
CascadeLevel::UserNormal); CascadeLevel::UserNormal);
debug!("user normal: {:?}", context.relations); debug!("user normal: {:?}", context.relations);
} else {
debug!("skipping user rules");
}
if rule_hash_target.matches_user_and_author_rules() && !only_default_rules {
// Step 3b: Author normal rules.
map.author.get_all_matching_rules(element, map.author.get_all_matching_rules(element,
&rule_hash_target, &rule_hash_target,
applicable_declarations, applicable_declarations,
@ -961,15 +1000,20 @@ impl Stylist {
// rule tree insertion. // rule tree insertion.
// //
// Step 11: Transitions. if !only_default_rules {
// The transitions sheet (CSS transitions that are tied to CSS markup) // Step 11: Transitions.
if let Some(anim) = animation_rules.1 { // The transitions sheet (CSS transitions that are tied to CSS markup)
Push::push( if let Some(anim) = animation_rules.1 {
applicable_declarations, Push::push(
ApplicableDeclarationBlock::from_declarations(anim.clone(), applicable_declarations,
CascadeLevel::Transitions)); ApplicableDeclarationBlock::from_declarations(anim.clone(),
CascadeLevel::Transitions));
}
debug!("transition: {:?}", context.relations);
} else {
debug!("skipping transition rules");
} }
debug!("transition: {:?}", context.relations);
debug!("push_applicable_declarations: shareable: {:?}", context.relations); debug!("push_applicable_declarations: shareable: {:?}", context.relations);
} }

Просмотреть файл

@ -13,6 +13,7 @@ use restyle_hints::{HintComputationContext, RestyleHint};
use selector_parser::RestyleDamage; use selector_parser::RestyleDamage;
use sharing::StyleSharingBehavior; use sharing::StyleSharingBehavior;
#[cfg(feature = "servo")] use servo_config::opts; #[cfg(feature = "servo")] use servo_config::opts;
use smallvec::SmallVec;
use std::borrow::BorrowMut; use std::borrow::BorrowMut;
/// A per-traversal-level chunk of data. This is sent down by the traversal, and /// A per-traversal-level chunk of data. This is sent down by the traversal, and
@ -41,6 +42,8 @@ bitflags! {
/// Traverse and update all elements with CSS animations since /// Traverse and update all elements with CSS animations since
/// @keyframes rules may have changed /// @keyframes rules may have changed
const FOR_CSS_RULE_CHANGES = 0x08, const FOR_CSS_RULE_CHANGES = 0x08,
/// Only include user agent style sheets when selector matching.
const FOR_DEFAULT_STYLES = 0x10,
} }
} }
@ -64,6 +67,12 @@ impl TraversalFlags {
pub fn for_css_rule_changes(&self) -> bool { pub fn for_css_rule_changes(&self) -> bool {
self.contains(FOR_CSS_RULE_CHANGES) self.contains(FOR_CSS_RULE_CHANGES)
} }
/// Returns true if the traversal is to compute the default computed
/// styles for an element.
pub fn for_default_styles(&self) -> bool {
self.contains(FOR_DEFAULT_STYLES)
}
} }
/// This structure exists to enforce that callers invoke pre_traverse, and also /// This structure exists to enforce that callers invoke pre_traverse, and also
@ -537,10 +546,13 @@ fn resolve_style_internal<E, F>(context: &mut StyleContext<E>,
StyleSharingBehavior::Disallow); StyleSharingBehavior::Disallow);
context.thread_local.end_element(element); context.thread_local.end_element(element);
// Conservatively mark us as having dirty descendants, since there might if !context.shared.traversal_flags.for_default_styles() {
// be other unstyled siblings we miss when walking straight up the parent // Conservatively mark us as having dirty descendants, since there might
// chain. // be other unstyled siblings we miss when walking straight up the parent
unsafe { element.note_descendants::<DirtyDescendants>() }; // chain. No need to do this if we're computing default styles, since
// resolve_default_style will want the tree to be left as it is.
unsafe { element.note_descendants::<DirtyDescendants>() };
}
} }
// If we're display:none and none of our ancestors are, we're the root // If we're display:none and none of our ancestors are, we're the root
@ -598,6 +610,47 @@ pub fn resolve_style<E, F, G, H>(context: &mut StyleContext<E>, element: E,
} }
} }
/// Manually resolve default styles for the given Element, which are the styles
/// only taking into account user agent and user cascade levels. The resolved
/// style is made available via a callback, and will be dropped by the time this
/// function returns.
pub fn resolve_default_style<E, F, G, H>(context: &mut StyleContext<E>,
element: E,
ensure_data: &F,
set_data: &G,
callback: H)
where E: TElement,
F: Fn(E),
G: Fn(E, Option<ElementData>) -> Option<ElementData>,
H: FnOnce(&ElementStyles)
{
// Save and clear out element data from the element and its ancestors.
let mut old_data: SmallVec<[(E, Option<ElementData>); 8]> = SmallVec::new();
{
let mut e = element;
loop {
old_data.push((e, set_data(e, None)));
match e.parent_element() {
Some(parent) => e = parent,
None => break,
}
}
}
// Resolve styles up the tree.
resolve_style_internal(context, element, ensure_data);
// Make them available for the scope of the callback. The callee may use the
// argument, or perform any other processing that requires the styles to exist
// on the Element.
callback(element.borrow_data().unwrap().styles());
// Swap the old element data back into the element and its ancestors.
for entry in old_data {
set_data(entry.0, entry.1);
}
}
/// Calculates the style for a single node. /// Calculates the style for a single node.
#[inline] #[inline]
#[allow(unsafe_code)] #[allow(unsafe_code)]

Просмотреть файл

@ -72,6 +72,7 @@ use style::gecko_bindings::structs::IterationCompositeOperation;
use style::gecko_bindings::structs::Loader; use style::gecko_bindings::structs::Loader;
use style::gecko_bindings::structs::RawGeckoPresContextOwned; use style::gecko_bindings::structs::RawGeckoPresContextOwned;
use style::gecko_bindings::structs::ServoElementSnapshotTable; use style::gecko_bindings::structs::ServoElementSnapshotTable;
use style::gecko_bindings::structs::StyleRuleInclusion;
use style::gecko_bindings::structs::URLExtraData; use style::gecko_bindings::structs::URLExtraData;
use style::gecko_bindings::structs::nsCSSValueSharedList; use style::gecko_bindings::structs::nsCSSValueSharedList;
use style::gecko_bindings::structs::nsCompatibility; use style::gecko_bindings::structs::nsCompatibility;
@ -101,11 +102,13 @@ use style::stylesheets::{CssRule, CssRules, CssRuleType, CssRulesHelpers};
use style::stylesheets::{ImportRule, KeyframesRule, MediaRule, NamespaceRule, Origin}; use style::stylesheets::{ImportRule, KeyframesRule, MediaRule, NamespaceRule, Origin};
use style::stylesheets::{PageRule, Stylesheet, StyleRule, SupportsRule, DocumentRule}; use style::stylesheets::{PageRule, Stylesheet, StyleRule, SupportsRule, DocumentRule};
use style::stylesheets::StylesheetLoader as StyleStylesheetLoader; use style::stylesheets::StylesheetLoader as StyleStylesheetLoader;
use style::stylist::RuleInclusion;
use style::supports::parse_condition_or_declaration; use style::supports::parse_condition_or_declaration;
use style::thread_state; use style::thread_state;
use style::timer::Timer; use style::timer::Timer;
use style::traversal::{ANIMATION_ONLY, FOR_CSS_RULE_CHANGES, FOR_RECONSTRUCT, UNSTYLED_CHILDREN_ONLY}; use style::traversal::{ANIMATION_ONLY, DomTraversal, FOR_CSS_RULE_CHANGES, FOR_RECONSTRUCT};
use style::traversal::{resolve_style, DomTraversal, TraversalDriver, TraversalFlags}; use style::traversal::{FOR_DEFAULT_STYLES, TraversalDriver, TraversalFlags, UNSTYLED_CHILDREN_ONLY};
use style::traversal::{resolve_style, resolve_default_style};
use style::values::{CustomIdent, KeyframesName}; use style::values::{CustomIdent, KeyframesName};
use style_traits::ToCss; use style_traits::ToCss;
use super::stylesheet_loader::StylesheetLoader; use super::stylesheet_loader::StylesheetLoader;
@ -1233,7 +1236,8 @@ pub extern "C" fn Servo_ResolvePseudoStyle(element: RawGeckoElementBorrowed,
let global_style_data = &*GLOBAL_STYLE_DATA; let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read(); let guard = global_style_data.shared_lock.read();
match get_pseudo_style(&guard, element, &pseudo, data.styles(), doc_data) { match get_pseudo_style(&guard, element, &pseudo, RuleInclusion::All,
data.styles(), doc_data) {
Some(values) => values.into_strong(), Some(values) => values.into_strong(),
// FIXME(emilio): This looks pretty wrong! Shouldn't it be at least an // FIXME(emilio): This looks pretty wrong! Shouldn't it be at least an
// empty style inheriting from the element? // empty style inheriting from the element?
@ -1265,6 +1269,7 @@ pub extern "C" fn Servo_HasAuthorSpecifiedRules(element: RawGeckoElementBorrowed
fn get_pseudo_style(guard: &SharedRwLockReadGuard, fn get_pseudo_style(guard: &SharedRwLockReadGuard,
element: GeckoElement, element: GeckoElement,
pseudo: &PseudoElement, pseudo: &PseudoElement,
rule_inclusion: RuleInclusion,
styles: &ElementStyles, styles: &ElementStyles,
doc_data: &PerDocumentStyleData) doc_data: &PerDocumentStyleData)
-> Option<Arc<ComputedValues>> -> Option<Arc<ComputedValues>>
@ -1284,6 +1289,7 @@ fn get_pseudo_style(guard: &SharedRwLockReadGuard,
d.stylist.lazily_compute_pseudo_element_style(&guards, d.stylist.lazily_compute_pseudo_element_style(&guards,
&element, &element,
&pseudo, &pseudo,
rule_inclusion,
base, base,
&metrics) &metrics)
.map(|s| s.values().clone()) .map(|s| s.values().clone())
@ -2305,6 +2311,7 @@ pub extern "C" fn Servo_ResolveStyle(element: RawGeckoElementBorrowed,
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_ResolveStyleLazily(element: RawGeckoElementBorrowed, pub extern "C" fn Servo_ResolveStyleLazily(element: RawGeckoElementBorrowed,
pseudo_type: CSSPseudoElementType, pseudo_type: CSSPseudoElementType,
rule_inclusion: StyleRuleInclusion,
snapshots: *const ServoElementSnapshotTable, snapshots: *const ServoElementSnapshotTable,
raw_data: RawServoStyleSetBorrowed) raw_data: RawServoStyleSetBorrowed)
-> ServoComputedValuesStrong -> ServoComputedValuesStrong
@ -2314,26 +2321,35 @@ pub extern "C" fn Servo_ResolveStyleLazily(element: RawGeckoElementBorrowed,
let guard = global_style_data.shared_lock.read(); let guard = global_style_data.shared_lock.read();
let element = GeckoElement(element); let element = GeckoElement(element);
let doc_data = PerDocumentStyleData::from_ffi(raw_data); let doc_data = PerDocumentStyleData::from_ffi(raw_data);
let rule_inclusion = RuleInclusion::from(rule_inclusion);
let finish = |styles: &ElementStyles| -> Arc<ComputedValues> { let finish = |styles: &ElementStyles| -> Arc<ComputedValues> {
PseudoElement::from_pseudo_type(pseudo_type).and_then(|ref pseudo| { PseudoElement::from_pseudo_type(pseudo_type).and_then(|ref pseudo| {
get_pseudo_style(&guard, element, pseudo, styles, doc_data) get_pseudo_style(&guard, element, pseudo, rule_inclusion, styles, doc_data)
}).unwrap_or_else(|| styles.primary.values().clone()) }).unwrap_or_else(|| styles.primary.values().clone())
}; };
// In the common case we already have the style. Check that before setting // In the common case we already have the style. Check that before setting
// up all the computation machinery. // up all the computation machinery. (Don't use it when we're getting
let mut result = element.mutate_data() // default styles, though.)
.and_then(|d| d.get_styles().map(&finish)); if rule_inclusion == RuleInclusion::All {
if result.is_some() { if let Some(result) = element.mutate_data()
return result.unwrap().into_strong(); .and_then(|d| d.get_styles().map(&finish)) {
return result.into_strong();
}
} }
let traversal_flags = match rule_inclusion {
RuleInclusion::All => TraversalFlags::empty(),
RuleInclusion::DefaultOnly => FOR_DEFAULT_STYLES,
};
// We don't have the style ready. Go ahead and compute it as necessary. // We don't have the style ready. Go ahead and compute it as necessary.
let mut result = None;
let data = doc_data.borrow(); let data = doc_data.borrow();
let shared = create_shared_context(&global_style_data, let shared = create_shared_context(&global_style_data,
&guard, &guard,
&data, &data,
TraversalFlags::empty(), traversal_flags,
unsafe { &*snapshots }); unsafe { &*snapshots });
let mut tlc = ThreadLocalStyleContext::new(&shared); let mut tlc = ThreadLocalStyleContext::new(&shared);
let mut context = StyleContext { let mut context = StyleContext {
@ -2341,9 +2357,19 @@ pub extern "C" fn Servo_ResolveStyleLazily(element: RawGeckoElementBorrowed,
thread_local: &mut tlc, thread_local: &mut tlc,
}; };
let ensure = |el: GeckoElement| { unsafe { el.ensure_data(); } }; let ensure = |el: GeckoElement| { unsafe { el.ensure_data(); } };
let clear = |el: GeckoElement| el.clear_data();
resolve_style(&mut context, element, &ensure, &clear, match rule_inclusion {
|styles| result = Some(finish(styles))); RuleInclusion::All => {
let clear = |el: GeckoElement| el.clear_data();
resolve_style(&mut context, element, &ensure, &clear,
|styles| result = Some(finish(styles)));
}
RuleInclusion::DefaultOnly => {
let set_data = |el: GeckoElement, data| { unsafe { el.set_data(data) } };
resolve_default_style(&mut context, element, &ensure, &set_data,
|styles| result = Some(finish(styles)));
}
}
result.unwrap().into_strong() result.unwrap().into_strong()
} }