mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
stylo: Get rules from Gecko XBL stylesheets in cascading (Bug 1290276)
This commit is contained in:
parent
ad47d33511
commit
2411749fcf
4 changed files with 138 additions and 11 deletions
|
@ -22,6 +22,7 @@ use selector_parser::{PseudoClassStringArg, PseudoElement};
|
||||||
use selectors::matching::{ElementSelectorFlags, VisitedHandlingMode};
|
use selectors::matching::{ElementSelectorFlags, VisitedHandlingMode};
|
||||||
use shared_lock::Locked;
|
use shared_lock::Locked;
|
||||||
use sink::Push;
|
use sink::Push;
|
||||||
|
use smallvec::VecLike;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
#[cfg(feature = "gecko")] use std::collections::HashMap;
|
#[cfg(feature = "gecko")] use std::collections::HashMap;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
@ -562,6 +563,14 @@ pub trait TElement : Eq + PartialEq + Debug + Hash + Sized + Copy + Clone +
|
||||||
.map_or(false, |r| r.hint.has_animation_hint());
|
.map_or(false, |r| r.hint.has_animation_hint());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets declarations from XBL bindings from the element. Only gecko element could have this.
|
||||||
|
fn get_declarations_from_xbl_bindings<V>(&self,
|
||||||
|
_: &mut V)
|
||||||
|
-> bool
|
||||||
|
where V: Push<ApplicableDeclarationBlock> + VecLike<ApplicableDeclarationBlock> {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
/// Gets the current existing CSS transitions, by |property, end value| pairs in a HashMap.
|
/// Gets the current existing CSS transitions, by |property, end value| pairs in a HashMap.
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
fn get_css_transitions_info(&self)
|
fn get_css_transitions_info(&self)
|
||||||
|
|
|
@ -23,6 +23,7 @@ use dom::{OpaqueNode, PresentationalHintsSynthesizer};
|
||||||
use element_state::ElementState;
|
use element_state::ElementState;
|
||||||
use error_reporting::RustLogReporter;
|
use error_reporting::RustLogReporter;
|
||||||
use font_metrics::{FontMetrics, FontMetricsProvider, FontMetricsQueryResult};
|
use font_metrics::{FontMetrics, FontMetricsProvider, FontMetricsQueryResult};
|
||||||
|
use gecko::data::PerDocumentStyleData;
|
||||||
use gecko::global_style_data::GLOBAL_STYLE_DATA;
|
use gecko::global_style_data::GLOBAL_STYLE_DATA;
|
||||||
use gecko::selector_parser::{SelectorImpl, NonTSPseudoClass, PseudoElement};
|
use gecko::selector_parser::{SelectorImpl, NonTSPseudoClass, PseudoElement};
|
||||||
use gecko::snapshot_helpers;
|
use gecko::snapshot_helpers;
|
||||||
|
@ -50,7 +51,7 @@ use gecko_bindings::bindings::Gecko_MatchStringArgPseudo;
|
||||||
use gecko_bindings::bindings::Gecko_UnsetDirtyStyleAttr;
|
use gecko_bindings::bindings::Gecko_UnsetDirtyStyleAttr;
|
||||||
use gecko_bindings::bindings::Gecko_UpdateAnimations;
|
use gecko_bindings::bindings::Gecko_UpdateAnimations;
|
||||||
use gecko_bindings::structs;
|
use gecko_bindings::structs;
|
||||||
use gecko_bindings::structs::{RawGeckoElement, RawGeckoNode};
|
use gecko_bindings::structs::{RawGeckoElement, RawGeckoNode, RawGeckoXBLBinding};
|
||||||
use gecko_bindings::structs::{nsIAtom, nsIContent, nsINode_BooleanFlag, nsStyleContext};
|
use gecko_bindings::structs::{nsIAtom, nsIContent, nsINode_BooleanFlag, nsStyleContext};
|
||||||
use gecko_bindings::structs::ELEMENT_HANDLED_SNAPSHOT;
|
use gecko_bindings::structs::ELEMENT_HANDLED_SNAPSHOT;
|
||||||
use gecko_bindings::structs::ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO;
|
use gecko_bindings::structs::ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO;
|
||||||
|
@ -59,7 +60,7 @@ use gecko_bindings::structs::ELEMENT_HAS_SNAPSHOT;
|
||||||
use gecko_bindings::structs::EffectCompositor_CascadeLevel as CascadeLevel;
|
use gecko_bindings::structs::EffectCompositor_CascadeLevel as CascadeLevel;
|
||||||
use gecko_bindings::structs::NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE;
|
use gecko_bindings::structs::NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE;
|
||||||
use gecko_bindings::structs::NODE_IS_NATIVE_ANONYMOUS;
|
use gecko_bindings::structs::NODE_IS_NATIVE_ANONYMOUS;
|
||||||
use gecko_bindings::sugar::ownership::HasArcFFI;
|
use gecko_bindings::sugar::ownership::{HasArcFFI, HasSimpleFFI};
|
||||||
use logical_geometry::WritingMode;
|
use logical_geometry::WritingMode;
|
||||||
use media_queries::Device;
|
use media_queries::Device;
|
||||||
use properties::{ComputedValues, parse_style_attribute};
|
use properties::{ComputedValues, parse_style_attribute};
|
||||||
|
@ -74,6 +75,7 @@ use selectors::matching::{ElementSelectorFlags, MatchingContext, MatchingMode};
|
||||||
use selectors::matching::{RelevantLinkStatus, VisitedHandlingMode};
|
use selectors::matching::{RelevantLinkStatus, VisitedHandlingMode};
|
||||||
use shared_lock::Locked;
|
use shared_lock::Locked;
|
||||||
use sink::Push;
|
use sink::Push;
|
||||||
|
use smallvec::VecLike;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -202,6 +204,12 @@ impl<'ln> GeckoNode<'ln> {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This logic is duplicated in Gecko's nsIContent::IsRootOfNativeAnonymousSubtree.
|
||||||
|
fn is_root_of_native_anonymous_subtree(&self) -> bool {
|
||||||
|
use gecko_bindings::structs::NODE_IS_NATIVE_ANONYMOUS_ROOT;
|
||||||
|
return self.flags() & (NODE_IS_NATIVE_ANONYMOUS_ROOT as u32) != 0
|
||||||
|
}
|
||||||
|
|
||||||
fn contains_non_whitespace_content(&self) -> bool {
|
fn contains_non_whitespace_content(&self) -> bool {
|
||||||
unsafe { Gecko_IsSignificantChild(self.0, true, false) }
|
unsafe { Gecko_IsSignificantChild(self.0, true, false) }
|
||||||
}
|
}
|
||||||
|
@ -341,6 +349,37 @@ impl<'a> Iterator for GeckoChildrenIterator<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A Simple wrapper over a non-null Gecko `nsXBLBinding` pointer.
|
||||||
|
pub struct GeckoXBLBinding<'lb>(pub &'lb RawGeckoXBLBinding);
|
||||||
|
|
||||||
|
impl<'lb> GeckoXBLBinding<'lb> {
|
||||||
|
fn base_binding(&self) -> Option<GeckoXBLBinding> {
|
||||||
|
unsafe { self.0.mNextBinding.mRawPtr.as_ref().map(GeckoXBLBinding) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inherits_style(&self) -> bool {
|
||||||
|
unsafe { bindings::Gecko_XBLBinding_InheritsStyle(self.0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements Gecko's nsXBLBinding::WalkRules().
|
||||||
|
fn get_declarations_for<E, V>(&self,
|
||||||
|
element: &E,
|
||||||
|
applicable_declarations: &mut V)
|
||||||
|
where E: TElement,
|
||||||
|
V: Push<ApplicableDeclarationBlock> + VecLike<ApplicableDeclarationBlock> {
|
||||||
|
if let Some(base_binding) = self.base_binding() {
|
||||||
|
base_binding.get_declarations_for(element, applicable_declarations);
|
||||||
|
}
|
||||||
|
|
||||||
|
let raw_data = unsafe { bindings::Gecko_XBLBinding_GetRawServoStyleSet(self.0) };
|
||||||
|
if let Some(raw_data) = raw_data {
|
||||||
|
let data = PerDocumentStyleData::from_ffi(&*raw_data).borrow();
|
||||||
|
data.stylist.push_applicable_declarations_as_xbl_only_stylist(element,
|
||||||
|
applicable_declarations);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A simple wrapper over a non-null Gecko `Element` pointer.
|
/// A simple wrapper over a non-null Gecko `Element` pointer.
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct GeckoElement<'le>(pub &'le RawGeckoElement);
|
pub struct GeckoElement<'le>(pub &'le RawGeckoElement);
|
||||||
|
@ -394,6 +433,14 @@ impl<'le> GeckoElement<'le> {
|
||||||
unsafe { slots.as_ref() }
|
unsafe { slots.as_ref() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_xbl_binding(&self) -> Option<GeckoXBLBinding> {
|
||||||
|
unsafe { bindings::Gecko_GetXBLBinding(self.0).map(GeckoXBLBinding) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_xbl_binding_parent(&self) -> Option<Self> {
|
||||||
|
unsafe { bindings::Gecko_GetBindingParent(self.0).map(GeckoElement) }
|
||||||
|
}
|
||||||
|
|
||||||
/// Clear the element data for a given element.
|
/// Clear the element data for a given element.
|
||||||
pub fn clear_data(&self) {
|
pub fn clear_data(&self) {
|
||||||
let ptr = self.0.mServoData.get();
|
let ptr = self.0.mServoData.get();
|
||||||
|
@ -857,6 +904,43 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
self.may_have_animations() && unsafe { Gecko_ElementHasCSSTransitions(self.0) }
|
self.may_have_animations() && unsafe { Gecko_ElementHasCSSTransitions(self.0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Implements Gecko's nsBindingManager::WalkRules(). Returns whether to cut off the
|
||||||
|
// inheritance.
|
||||||
|
fn get_declarations_from_xbl_bindings<V>(&self,
|
||||||
|
applicable_declarations: &mut V)
|
||||||
|
-> bool
|
||||||
|
where V: Push<ApplicableDeclarationBlock> + VecLike<ApplicableDeclarationBlock> {
|
||||||
|
// Walk the binding scope chain, starting with the binding attached to our content, up
|
||||||
|
// till we run out of scopes or we get cut off.
|
||||||
|
let mut current = Some(*self);
|
||||||
|
|
||||||
|
while let Some(element) = current {
|
||||||
|
if let Some(binding) = element.get_xbl_binding() {
|
||||||
|
binding.get_declarations_for(self, applicable_declarations);
|
||||||
|
|
||||||
|
// If we're not looking at our original element, allow the binding to cut off
|
||||||
|
// style inheritance.
|
||||||
|
if element != *self {
|
||||||
|
if !binding.inherits_style() {
|
||||||
|
// Go no further; we're not inheriting style from anything above here.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if element.as_node().is_root_of_native_anonymous_subtree() {
|
||||||
|
// Deliberately cut off style inheritance here.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = element.get_xbl_binding_parent();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If current has something, this means we cut off inheritance at some point in the
|
||||||
|
// loop.
|
||||||
|
current.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
fn get_css_transitions_info(&self)
|
fn get_css_transitions_info(&self)
|
||||||
-> HashMap<TransitionProperty, Arc<AnimationValue>> {
|
-> HashMap<TransitionProperty, Arc<AnimationValue>> {
|
||||||
use gecko_bindings::bindings::Gecko_ElementTransitions_EndValueAt;
|
use gecko_bindings::bindings::Gecko_ElementTransitions_EndValueAt;
|
||||||
|
|
|
@ -406,6 +406,8 @@ pub enum CascadeLevel {
|
||||||
PresHints,
|
PresHints,
|
||||||
/// User normal rules.
|
/// User normal rules.
|
||||||
UserNormal,
|
UserNormal,
|
||||||
|
/// XBL <stylesheet> rules.
|
||||||
|
XBL,
|
||||||
/// Author normal rules.
|
/// Author normal rules.
|
||||||
AuthorNormal,
|
AuthorNormal,
|
||||||
/// Style attribute normal rules.
|
/// Style attribute normal rules.
|
||||||
|
@ -1049,7 +1051,8 @@ impl StrongRuleNode {
|
||||||
CascadeLevel::UANormal |
|
CascadeLevel::UANormal |
|
||||||
CascadeLevel::UAImportant |
|
CascadeLevel::UAImportant |
|
||||||
CascadeLevel::UserNormal |
|
CascadeLevel::UserNormal |
|
||||||
CascadeLevel::UserImportant => {
|
CascadeLevel::UserImportant |
|
||||||
|
CascadeLevel::XBL => {
|
||||||
for (id, declaration) in longhands {
|
for (id, declaration) in longhands {
|
||||||
if properties.contains(id) {
|
if properties.contains(id) {
|
||||||
// This property was set by a non-author rule.
|
// This property was set by a non-author rule.
|
||||||
|
|
|
@ -917,6 +917,26 @@ impl Stylist {
|
||||||
self.quirks_mode = quirks_mode;
|
self.quirks_mode = quirks_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the applicable CSS declarations for the given element by
|
||||||
|
/// treating us as an XBL stylesheet-only stylist.
|
||||||
|
pub fn push_applicable_declarations_as_xbl_only_stylist<E, V>(&self,
|
||||||
|
element: &E,
|
||||||
|
applicable_declarations: &mut V)
|
||||||
|
where E: TElement,
|
||||||
|
V: Push<ApplicableDeclarationBlock> + VecLike<ApplicableDeclarationBlock>,
|
||||||
|
{
|
||||||
|
let mut matching_context =
|
||||||
|
MatchingContext::new(MatchingMode::Normal, None);
|
||||||
|
let mut dummy_flag_setter = |_: &E, _: ElementSelectorFlags| {};
|
||||||
|
|
||||||
|
self.element_map.author.get_all_matching_rules(element,
|
||||||
|
element,
|
||||||
|
applicable_declarations,
|
||||||
|
&mut matching_context,
|
||||||
|
&mut dummy_flag_setter,
|
||||||
|
CascadeLevel::XBL);
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the applicable CSS declarations for the given element.
|
/// Returns the applicable CSS declarations for the given element.
|
||||||
///
|
///
|
||||||
/// This corresponds to `ElementRuleCollector` in WebKit.
|
/// This corresponds to `ElementRuleCollector` in WebKit.
|
||||||
|
@ -1019,15 +1039,26 @@ impl Stylist {
|
||||||
debug!("skipping user rules");
|
debug!("skipping user rules");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Step 3b: XBL rules.
|
||||||
|
let cut_off_inheritance =
|
||||||
|
rule_hash_target.get_declarations_from_xbl_bindings(applicable_declarations);
|
||||||
|
debug!("XBL: {:?}", context.relations);
|
||||||
|
|
||||||
if rule_hash_target.matches_user_and_author_rules() && !only_default_rules {
|
if rule_hash_target.matches_user_and_author_rules() && !only_default_rules {
|
||||||
// Step 3b: Author normal rules.
|
// Gecko skips author normal rules if cutting off inheritance.
|
||||||
map.author.get_all_matching_rules(element,
|
// See nsStyleSet::FileRules().
|
||||||
&rule_hash_target,
|
if !cut_off_inheritance {
|
||||||
applicable_declarations,
|
// Step 3c: Author normal rules.
|
||||||
context,
|
map.author.get_all_matching_rules(element,
|
||||||
flags_setter,
|
&rule_hash_target,
|
||||||
CascadeLevel::AuthorNormal);
|
applicable_declarations,
|
||||||
debug!("author normal: {:?}", context.relations);
|
context,
|
||||||
|
flags_setter,
|
||||||
|
CascadeLevel::AuthorNormal);
|
||||||
|
debug!("author normal: {:?}", context.relations);
|
||||||
|
} else {
|
||||||
|
debug!("Skipping author normal rules due to cut off inheritance");
|
||||||
|
}
|
||||||
|
|
||||||
// Step 4: Normal style attributes.
|
// Step 4: Normal style attributes.
|
||||||
if let Some(sa) = style_attribute {
|
if let Some(sa) = style_attribute {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue