зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
05e5c16a8e
Коммит
40bf61aba0
|
@ -25,6 +25,7 @@ use style::font_metrics::ServoMetricsProvider;
|
|||
use style::properties::{CascadeFlags, ServoComputedValues};
|
||||
use style::selector_parser::{PseudoElement, PseudoElementCascadeType, SelectorImpl};
|
||||
use style::stylearc::Arc;
|
||||
use style::stylist::RuleInclusion;
|
||||
use webrender_traits::ClipId;
|
||||
|
||||
#[derive(Copy, PartialEq, Clone, Debug)]
|
||||
|
@ -423,6 +424,7 @@ pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + Debug +
|
|||
&context.guards,
|
||||
unsafe { &self.unsafe_get() },
|
||||
&style_pseudo,
|
||||
RuleInclusion::All,
|
||||
data.styles().primary.values(),
|
||||
&ServoMetricsProvider)
|
||||
.unwrap()
|
||||
|
|
|
@ -205,6 +205,7 @@ use gecko_bindings::structs::UpdateAnimationsTasks;
|
|||
use gecko_bindings::structs::ParsingMode;
|
||||
use gecko_bindings::structs::InheritTarget;
|
||||
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 RawServoStyleSetOwned = ::gecko_bindings::sugar::ownership::Owned<RawServoStyleSet>;
|
||||
pub type RawServoStyleSetOwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull<RawServoStyleSet>;
|
||||
|
@ -2417,6 +2418,11 @@ extern "C" {
|
|||
target: InheritTarget)
|
||||
-> ServoComputedValuesStrong;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Servo_ComputedValues_GetVisitedStyle(values:
|
||||
ServoComputedValuesBorrowed)
|
||||
-> ServoComputedValuesStrong;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Servo_Initialize(dummy_url_data: *mut RawGeckoURLExtraData);
|
||||
}
|
||||
|
@ -2457,6 +2463,7 @@ extern "C" {
|
|||
extern "C" {
|
||||
pub fn Servo_ResolveStyleLazily(element: RawGeckoElementBorrowed,
|
||||
pseudo_type: CSSPseudoElementType,
|
||||
rule_inclusion: StyleRuleInclusion,
|
||||
snapshots:
|
||||
*const ServoElementSnapshotTable,
|
||||
set: RawServoStyleSetBorrowed)
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -72,6 +72,8 @@ use std::cell::RefCell;
|
|||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::mem;
|
||||
use std::ops::DerefMut;
|
||||
use std::ptr;
|
||||
use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
|
||||
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]
|
||||
fn has_id(&self) -> bool {
|
||||
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 sharing::{StyleSharingBehavior, StyleSharingResult};
|
||||
use stylearc::Arc;
|
||||
use stylist::ApplicableDeclarationList;
|
||||
use stylist::{ApplicableDeclarationList, RuleInclusion};
|
||||
|
||||
/// The way a style should be inherited.
|
||||
enum InheritMode {
|
||||
|
@ -346,7 +346,13 @@ trait PrivateMatchMethods: TElement {
|
|||
// 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() {
|
||||
//
|
||||
// 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();
|
||||
if !parent.may_have_animations() ||
|
||||
primary_style.rules.get_animation_rules().is_empty() {
|
||||
|
@ -896,13 +902,24 @@ pub trait MatchMethods : TElement {
|
|||
{
|
||||
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();
|
||||
if let Some(ref pseudo) = implemented_pseudo {
|
||||
// We don't expect to match against a non-canonical pseudo-element.
|
||||
debug_assert_eq!(*pseudo, pseudo.canonical());
|
||||
if pseudo.is_eager() {
|
||||
// If it's an eager element-backed pseudo, just grab the matched
|
||||
// rules from the parent, and update animations.
|
||||
if pseudo.is_eager() && !only_default_rules {
|
||||
// If it's an eager element-backed pseudo, we can generally just
|
||||
// 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_data = parent.borrow_data().unwrap();
|
||||
let pseudo_style =
|
||||
|
@ -965,6 +982,12 @@ pub trait MatchMethods : TElement {
|
|||
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 mut matching_context =
|
||||
MatchingContext::new_for_visited(MatchingMode::Normal,
|
||||
|
@ -985,6 +1008,7 @@ pub trait MatchMethods : TElement {
|
|||
style_attribute,
|
||||
smil_override,
|
||||
animation_rules,
|
||||
rule_inclusion,
|
||||
&mut applicable_declarations,
|
||||
&mut matching_context,
|
||||
&mut set_selector_flags);
|
||||
|
@ -1052,7 +1076,14 @@ pub trait MatchMethods : TElement {
|
|||
let stylist = &context.shared.stylist;
|
||||
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 mut matching_context =
|
||||
MatchingContext::new_for_visited(MatchingMode::ForStatelessPseudoElement,
|
||||
Some(bloom_filter),
|
||||
|
@ -1076,6 +1107,7 @@ pub trait MatchMethods : TElement {
|
|||
None,
|
||||
None,
|
||||
AnimationRules(None, None),
|
||||
rule_inclusion,
|
||||
&mut applicable_declarations,
|
||||
&mut matching_context,
|
||||
&mut set_selector_flags);
|
||||
|
|
|
@ -13,7 +13,7 @@ use element_state::ElementState;
|
|||
use error_reporting::RustLogReporter;
|
||||
use font_metrics::FontMetricsProvider;
|
||||
#[cfg(feature = "gecko")]
|
||||
use gecko_bindings::structs::nsIAtom;
|
||||
use gecko_bindings::structs::{nsIAtom, StyleRuleInclusion};
|
||||
use keyframes::KeyframesAnimation;
|
||||
use media_queries::Device;
|
||||
use properties::{self, CascadeFlags, ComputedValues};
|
||||
|
@ -205,6 +205,27 @@ impl<'a> ExtraStyleData<'a> {
|
|||
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 {
|
||||
/// Construct a new `Stylist`, using given `Device` and `QuirksMode`.
|
||||
/// If more members are added here, think about whether they should
|
||||
|
@ -625,13 +646,14 @@ impl Stylist {
|
|||
guards: &StylesheetGuards,
|
||||
element: &E,
|
||||
pseudo: &PseudoElement,
|
||||
rule_inclusion: RuleInclusion,
|
||||
parent_style: &ComputedValues,
|
||||
font_metrics: &FontMetricsProvider)
|
||||
-> Option<ComputedStyle>
|
||||
where E: TElement,
|
||||
{
|
||||
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,
|
||||
None => return None
|
||||
};
|
||||
|
@ -664,7 +686,8 @@ impl Stylist {
|
|||
pub fn lazy_pseudo_rules<E>(&self,
|
||||
guards: &StylesheetGuards,
|
||||
element: &E,
|
||||
pseudo: &PseudoElement)
|
||||
pseudo: &PseudoElement,
|
||||
rule_inclusion: RuleInclusion)
|
||||
-> Option<StrongRuleNode>
|
||||
where E: TElement
|
||||
{
|
||||
|
@ -683,6 +706,12 @@ impl Stylist {
|
|||
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
|
||||
// the flags.
|
||||
debug_assert!(thread_state::get() == thread_state::LAYOUT);
|
||||
|
@ -707,6 +736,7 @@ impl Stylist {
|
|||
None,
|
||||
None,
|
||||
AnimationRules(None, None),
|
||||
rule_inclusion,
|
||||
&mut declarations,
|
||||
&mut matching_context,
|
||||
&mut set_selector_flags);
|
||||
|
@ -836,6 +866,7 @@ impl Stylist {
|
|||
style_attribute: Option<&Arc<Locked<PropertyDeclarationBlock>>>,
|
||||
smil_override: Option<&Arc<Locked<PropertyDeclarationBlock>>>,
|
||||
animation_rules: AnimationRules,
|
||||
rule_inclusion: RuleInclusion,
|
||||
applicable_declarations: &mut V,
|
||||
context: &mut MatchingContext,
|
||||
flags_setter: &mut F)
|
||||
|
@ -871,6 +902,8 @@ impl Stylist {
|
|||
debug!("Determining if style is shareable: pseudo: {}",
|
||||
pseudo_element.is_some());
|
||||
|
||||
let only_default_rules = rule_inclusion == RuleInclusion::DefaultOnly;
|
||||
|
||||
// Step 1: Normal user-agent rules.
|
||||
map.user_agent.get_all_matching_rules(element,
|
||||
&rule_hash_target,
|
||||
|
@ -880,7 +913,7 @@ impl Stylist {
|
|||
CascadeLevel::UANormal);
|
||||
debug!("UA normal: {:?}", context.relations);
|
||||
|
||||
if pseudo_element.is_none() {
|
||||
if pseudo_element.is_none() && !only_default_rules {
|
||||
// Step 2: Presentational hints.
|
||||
let length_before_preshints = applicable_declarations.len();
|
||||
element.synthesize_presentational_hints_for_legacy_attributes(applicable_declarations);
|
||||
|
@ -905,7 +938,7 @@ impl Stylist {
|
|||
//
|
||||
// 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.
|
||||
// Step 3a: User normal rules.
|
||||
map.user.get_all_matching_rules(element,
|
||||
&rule_hash_target,
|
||||
applicable_declarations,
|
||||
|
@ -913,6 +946,12 @@ impl Stylist {
|
|||
flags_setter,
|
||||
CascadeLevel::UserNormal);
|
||||
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,
|
||||
&rule_hash_target,
|
||||
applicable_declarations,
|
||||
|
@ -961,6 +1000,7 @@ impl Stylist {
|
|||
// rule tree insertion.
|
||||
//
|
||||
|
||||
if !only_default_rules {
|
||||
// Step 11: Transitions.
|
||||
// The transitions sheet (CSS transitions that are tied to CSS markup)
|
||||
if let Some(anim) = animation_rules.1 {
|
||||
|
@ -970,6 +1010,10 @@ impl Stylist {
|
|||
CascadeLevel::Transitions));
|
||||
}
|
||||
debug!("transition: {:?}", context.relations);
|
||||
} else {
|
||||
debug!("skipping transition rules");
|
||||
}
|
||||
|
||||
debug!("push_applicable_declarations: shareable: {:?}", context.relations);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ use restyle_hints::{HintComputationContext, RestyleHint};
|
|||
use selector_parser::RestyleDamage;
|
||||
use sharing::StyleSharingBehavior;
|
||||
#[cfg(feature = "servo")] use servo_config::opts;
|
||||
use smallvec::SmallVec;
|
||||
use std::borrow::BorrowMut;
|
||||
|
||||
/// 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
|
||||
/// @keyframes rules may have changed
|
||||
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 {
|
||||
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
|
||||
|
@ -537,11 +546,14 @@ fn resolve_style_internal<E, F>(context: &mut StyleContext<E>,
|
|||
StyleSharingBehavior::Disallow);
|
||||
context.thread_local.end_element(element);
|
||||
|
||||
if !context.shared.traversal_flags.for_default_styles() {
|
||||
// Conservatively mark us as having dirty descendants, since there might
|
||||
// be other unstyled siblings we miss when walking straight up the parent
|
||||
// chain.
|
||||
// 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
|
||||
// of a display:none subtree.
|
||||
|
@ -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.
|
||||
#[inline]
|
||||
#[allow(unsafe_code)]
|
||||
|
|
|
@ -72,6 +72,7 @@ use style::gecko_bindings::structs::IterationCompositeOperation;
|
|||
use style::gecko_bindings::structs::Loader;
|
||||
use style::gecko_bindings::structs::RawGeckoPresContextOwned;
|
||||
use style::gecko_bindings::structs::ServoElementSnapshotTable;
|
||||
use style::gecko_bindings::structs::StyleRuleInclusion;
|
||||
use style::gecko_bindings::structs::URLExtraData;
|
||||
use style::gecko_bindings::structs::nsCSSValueSharedList;
|
||||
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::{PageRule, Stylesheet, StyleRule, SupportsRule, DocumentRule};
|
||||
use style::stylesheets::StylesheetLoader as StyleStylesheetLoader;
|
||||
use style::stylist::RuleInclusion;
|
||||
use style::supports::parse_condition_or_declaration;
|
||||
use style::thread_state;
|
||||
use style::timer::Timer;
|
||||
use style::traversal::{ANIMATION_ONLY, FOR_CSS_RULE_CHANGES, FOR_RECONSTRUCT, UNSTYLED_CHILDREN_ONLY};
|
||||
use style::traversal::{resolve_style, DomTraversal, TraversalDriver, TraversalFlags};
|
||||
use style::traversal::{ANIMATION_ONLY, DomTraversal, FOR_CSS_RULE_CHANGES, FOR_RECONSTRUCT};
|
||||
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_traits::ToCss;
|
||||
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 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(),
|
||||
// FIXME(emilio): This looks pretty wrong! Shouldn't it be at least an
|
||||
// empty style inheriting from the element?
|
||||
|
@ -1265,6 +1269,7 @@ pub extern "C" fn Servo_HasAuthorSpecifiedRules(element: RawGeckoElementBorrowed
|
|||
fn get_pseudo_style(guard: &SharedRwLockReadGuard,
|
||||
element: GeckoElement,
|
||||
pseudo: &PseudoElement,
|
||||
rule_inclusion: RuleInclusion,
|
||||
styles: &ElementStyles,
|
||||
doc_data: &PerDocumentStyleData)
|
||||
-> Option<Arc<ComputedValues>>
|
||||
|
@ -1284,6 +1289,7 @@ fn get_pseudo_style(guard: &SharedRwLockReadGuard,
|
|||
d.stylist.lazily_compute_pseudo_element_style(&guards,
|
||||
&element,
|
||||
&pseudo,
|
||||
rule_inclusion,
|
||||
base,
|
||||
&metrics)
|
||||
.map(|s| s.values().clone())
|
||||
|
@ -2305,6 +2311,7 @@ pub extern "C" fn Servo_ResolveStyle(element: RawGeckoElementBorrowed,
|
|||
#[no_mangle]
|
||||
pub extern "C" fn Servo_ResolveStyleLazily(element: RawGeckoElementBorrowed,
|
||||
pseudo_type: CSSPseudoElementType,
|
||||
rule_inclusion: StyleRuleInclusion,
|
||||
snapshots: *const ServoElementSnapshotTable,
|
||||
raw_data: RawServoStyleSetBorrowed)
|
||||
-> ServoComputedValuesStrong
|
||||
|
@ -2314,26 +2321,35 @@ pub extern "C" fn Servo_ResolveStyleLazily(element: RawGeckoElementBorrowed,
|
|||
let guard = global_style_data.shared_lock.read();
|
||||
let element = GeckoElement(element);
|
||||
let doc_data = PerDocumentStyleData::from_ffi(raw_data);
|
||||
let rule_inclusion = RuleInclusion::from(rule_inclusion);
|
||||
let finish = |styles: &ElementStyles| -> Arc<ComputedValues> {
|
||||
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())
|
||||
};
|
||||
|
||||
// In the common case we already have the style. Check that before setting
|
||||
// up all the computation machinery.
|
||||
let mut result = element.mutate_data()
|
||||
.and_then(|d| d.get_styles().map(&finish));
|
||||
if result.is_some() {
|
||||
return result.unwrap().into_strong();
|
||||
// up all the computation machinery. (Don't use it when we're getting
|
||||
// default styles, though.)
|
||||
if rule_inclusion == RuleInclusion::All {
|
||||
if let Some(result) = element.mutate_data()
|
||||
.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.
|
||||
let mut result = None;
|
||||
let data = doc_data.borrow();
|
||||
let shared = create_shared_context(&global_style_data,
|
||||
&guard,
|
||||
&data,
|
||||
TraversalFlags::empty(),
|
||||
traversal_flags,
|
||||
unsafe { &*snapshots });
|
||||
let mut tlc = ThreadLocalStyleContext::new(&shared);
|
||||
let mut context = StyleContext {
|
||||
|
@ -2341,9 +2357,19 @@ pub extern "C" fn Servo_ResolveStyleLazily(element: RawGeckoElementBorrowed,
|
|||
thread_local: &mut tlc,
|
||||
};
|
||||
let ensure = |el: GeckoElement| { unsafe { el.ensure_data(); } };
|
||||
|
||||
match rule_inclusion {
|
||||
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()
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче