зеркало из 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::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()
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче