mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-15 06:15:43 +00:00
servo: Merge #20229 - style: Separate the XBL and shadow dom styling bits (from emilio:finally); r=xidorn
Bug: 1441022 Reviewed-by: xidorn MozReview-Commit-ID: 2W0BmZ8wWXg Source-Repo: https://github.com/servo/servo Source-Revision: 6272233c50071534ddbab118b64ecdb8fdda7c8a --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 0ce28863b2082d97c58833aae1c092b1723e1aa9
This commit is contained in:
parent
aa14676e33
commit
93ea7b41e1
@ -74,6 +74,7 @@ use style::selector_parser::{AttrValue as SelectorAttrValue, NonTSPseudoClass, P
|
|||||||
use style::selector_parser::{PseudoElement, SelectorImpl, extended_filtering};
|
use style::selector_parser::{PseudoElement, SelectorImpl, extended_filtering};
|
||||||
use style::shared_lock::{SharedRwLock as StyleSharedRwLock, Locked as StyleLocked};
|
use style::shared_lock::{SharedRwLock as StyleSharedRwLock, Locked as StyleLocked};
|
||||||
use style::str::is_whitespace;
|
use style::str::is_whitespace;
|
||||||
|
use style::stylist::CascadeData;
|
||||||
|
|
||||||
pub unsafe fn drop_style_and_layout_data(data: OpaqueStyleAndLayoutData) {
|
pub unsafe fn drop_style_and_layout_data(data: OpaqueStyleAndLayoutData) {
|
||||||
let ptr = data.ptr.as_ptr() as *mut StyleData;
|
let ptr = data.ptr.as_ptr() as *mut StyleData;
|
||||||
@ -166,6 +167,13 @@ impl<'lr> TShadowRoot for ShadowRoot<'lr> {
|
|||||||
fn host(&self) -> ServoLayoutElement<'lr> {
|
fn host(&self) -> ServoLayoutElement<'lr> {
|
||||||
match self.0 { }
|
match self.0 { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn style_data<'a>(&self) -> &'a CascadeData
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
{
|
||||||
|
match self.0 { }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ln> TNode for ServoLayoutNode<'ln> {
|
impl<'ln> TNode for ServoLayoutNode<'ln> {
|
||||||
|
@ -260,18 +260,16 @@ impl ElementData {
|
|||||||
return InvalidationResult::empty();
|
return InvalidationResult::empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut xbl_stylists = SmallVec::<[_; 3]>::new();
|
let mut non_document_styles = SmallVec::<[_; 3]>::new();
|
||||||
// FIXME(emilio): This is wrong, needs to account for ::slotted rules
|
let matches_doc_author_rules =
|
||||||
// that may apply to elements down the tree.
|
|
||||||
let cut_off_inheritance =
|
|
||||||
element.each_applicable_non_document_style_rule_data(|data, quirks_mode| {
|
element.each_applicable_non_document_style_rule_data(|data, quirks_mode| {
|
||||||
xbl_stylists.push((data, quirks_mode))
|
non_document_styles.push((data, quirks_mode))
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut processor = StateAndAttrInvalidationProcessor::new(
|
let mut processor = StateAndAttrInvalidationProcessor::new(
|
||||||
shared_context,
|
shared_context,
|
||||||
&xbl_stylists,
|
&non_document_styles,
|
||||||
cut_off_inheritance,
|
matches_doc_author_rules,
|
||||||
element,
|
element,
|
||||||
self,
|
self,
|
||||||
nth_index_cache,
|
nth_index_cache,
|
||||||
|
@ -330,6 +330,11 @@ pub trait TShadowRoot : Sized + Copy + Clone {
|
|||||||
|
|
||||||
/// Get the shadow host that hosts this ShadowRoot.
|
/// Get the shadow host that hosts this ShadowRoot.
|
||||||
fn host(&self) -> <Self::ConcreteNode as TNode>::ConcreteElement;
|
fn host(&self) -> <Self::ConcreteNode as TNode>::ConcreteElement;
|
||||||
|
|
||||||
|
/// Get the style data for this ShadowRoot.
|
||||||
|
fn style_data<'a>(&self) -> &'a CascadeData
|
||||||
|
where
|
||||||
|
Self: 'a;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The element trait, the main abstraction the style crate acts over.
|
/// The element trait, the main abstraction the style crate acts over.
|
||||||
@ -760,7 +765,8 @@ pub trait TElement
|
|||||||
|
|
||||||
/// Implements Gecko's `nsBindingManager::WalkRules`.
|
/// Implements Gecko's `nsBindingManager::WalkRules`.
|
||||||
///
|
///
|
||||||
/// Returns whether to cut off the inheritance.
|
/// Returns whether to cut off the binding inheritance, that is, whether
|
||||||
|
/// document rules should _not_ apply.
|
||||||
fn each_xbl_cascade_data<'a, F>(&self, _: F) -> bool
|
fn each_xbl_cascade_data<'a, F>(&self, _: F) -> bool
|
||||||
where
|
where
|
||||||
Self: 'a,
|
Self: 'a,
|
||||||
@ -778,15 +784,22 @@ pub trait TElement
|
|||||||
Self: 'a,
|
Self: 'a,
|
||||||
F: FnMut(&'a CascadeData, QuirksMode),
|
F: FnMut(&'a CascadeData, QuirksMode),
|
||||||
{
|
{
|
||||||
let cut_off_inheritance = self.each_xbl_cascade_data(&mut f);
|
let mut doc_rules_apply = !self.each_xbl_cascade_data(&mut f);
|
||||||
|
|
||||||
|
if let Some(shadow) = self.containing_shadow() {
|
||||||
|
doc_rules_apply = false;
|
||||||
|
f(shadow.style_data(), self.as_node().owner_doc().quirks_mode());
|
||||||
|
}
|
||||||
|
|
||||||
let mut current = self.assigned_slot();
|
let mut current = self.assigned_slot();
|
||||||
while let Some(slot) = current {
|
while let Some(slot) = current {
|
||||||
slot.each_xbl_cascade_data(&mut f);
|
// Slots can only have assigned nodes when in a shadow tree.
|
||||||
|
let data = slot.containing_shadow().unwrap().style_data();
|
||||||
|
f(data, self.as_node().owner_doc().quirks_mode());
|
||||||
current = slot.assigned_slot();
|
current = slot.assigned_slot();
|
||||||
}
|
}
|
||||||
|
|
||||||
cut_off_inheritance
|
doc_rules_apply
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Does a rough (and cheap) check for whether or not transitions might need to be updated that
|
/// Does a rough (and cheap) check for whether or not transitions might need to be updated that
|
||||||
|
@ -147,6 +147,30 @@ impl<'lr> TShadowRoot for GeckoShadowRoot<'lr> {
|
|||||||
fn host(&self) -> GeckoElement<'lr> {
|
fn host(&self) -> GeckoElement<'lr> {
|
||||||
GeckoElement(unsafe { &*self.0._base.mHost.mRawPtr })
|
GeckoElement(unsafe { &*self.0._base.mHost.mRawPtr })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn style_data<'a>(&self) -> &'a CascadeData
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
{
|
||||||
|
debug_assert!(!self.0.mServoStyles.mPtr.is_null());
|
||||||
|
|
||||||
|
let author_styles = unsafe {
|
||||||
|
&*(self.0.mServoStyles.mPtr
|
||||||
|
as *const structs::RawServoAuthorStyles
|
||||||
|
as *const bindings::RawServoAuthorStyles)
|
||||||
|
};
|
||||||
|
|
||||||
|
let author_styles =
|
||||||
|
AuthorStyles::<GeckoStyleSheet>::from_ffi(author_styles);
|
||||||
|
|
||||||
|
debug_assert!(
|
||||||
|
author_styles.quirks_mode == self.as_node().owner_doc().quirks_mode() ||
|
||||||
|
author_styles.stylesheets.is_empty()
|
||||||
|
);
|
||||||
|
|
||||||
|
&author_styles.data
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A simple wrapper over a non-null Gecko node (`nsINode`) pointer.
|
/// A simple wrapper over a non-null Gecko node (`nsINode`) pointer.
|
||||||
@ -1457,26 +1481,6 @@ impl<'le> TElement for GeckoElement<'le> {
|
|||||||
// rule_hash_target, that is, our originating element.
|
// rule_hash_target, that is, our originating element.
|
||||||
let mut current = Some(self.rule_hash_target());
|
let mut current = Some(self.rule_hash_target());
|
||||||
while let Some(element) = current {
|
while let Some(element) = current {
|
||||||
// TODO(emilio): Deal with Shadow DOM separately than with XBL
|
|
||||||
// (right now we still rely on get_xbl_binding_parent()).
|
|
||||||
//
|
|
||||||
// That will allow to clean up a bunch in
|
|
||||||
// push_applicable_declarations.
|
|
||||||
if let Some(shadow) = element.shadow_root() {
|
|
||||||
debug_assert!(!shadow.0.mServoStyles.mPtr.is_null());
|
|
||||||
let author_styles = unsafe {
|
|
||||||
&*(shadow.0.mServoStyles.mPtr
|
|
||||||
as *const structs::RawServoAuthorStyles
|
|
||||||
as *const bindings::RawServoAuthorStyles)
|
|
||||||
};
|
|
||||||
|
|
||||||
let author_styles: &'a _ = AuthorStyles::<GeckoStyleSheet>::from_ffi(author_styles);
|
|
||||||
f(&author_styles.data, author_styles.quirks_mode);
|
|
||||||
if element != *self {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(binding) = element.xbl_binding() {
|
if let Some(binding) = element.xbl_binding() {
|
||||||
binding.each_xbl_cascade_data(&mut f);
|
binding.each_xbl_cascade_data(&mut f);
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ where
|
|||||||
pub struct StateAndAttrInvalidationProcessor<'a, 'b: 'a, E: TElement> {
|
pub struct StateAndAttrInvalidationProcessor<'a, 'b: 'a, E: TElement> {
|
||||||
shared_context: &'a SharedStyleContext<'b>,
|
shared_context: &'a SharedStyleContext<'b>,
|
||||||
shadow_rule_datas: &'a [(&'b CascadeData, QuirksMode)],
|
shadow_rule_datas: &'a [(&'b CascadeData, QuirksMode)],
|
||||||
cut_off_inheritance: bool,
|
matches_document_author_rules: bool,
|
||||||
element: E,
|
element: E,
|
||||||
data: &'a mut ElementData,
|
data: &'a mut ElementData,
|
||||||
matching_context: MatchingContext<'a, E::Impl>,
|
matching_context: MatchingContext<'a, E::Impl>,
|
||||||
@ -68,7 +68,7 @@ impl<'a, 'b: 'a, E: TElement> StateAndAttrInvalidationProcessor<'a, 'b, E> {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
shared_context: &'a SharedStyleContext<'b>,
|
shared_context: &'a SharedStyleContext<'b>,
|
||||||
shadow_rule_datas: &'a [(&'b CascadeData, QuirksMode)],
|
shadow_rule_datas: &'a [(&'b CascadeData, QuirksMode)],
|
||||||
cut_off_inheritance: bool,
|
matches_document_author_rules: bool,
|
||||||
element: E,
|
element: E,
|
||||||
data: &'a mut ElementData,
|
data: &'a mut ElementData,
|
||||||
nth_index_cache: &'a mut NthIndexCache,
|
nth_index_cache: &'a mut NthIndexCache,
|
||||||
@ -84,7 +84,7 @@ impl<'a, 'b: 'a, E: TElement> StateAndAttrInvalidationProcessor<'a, 'b, E> {
|
|||||||
Self {
|
Self {
|
||||||
shared_context,
|
shared_context,
|
||||||
shadow_rule_datas,
|
shadow_rule_datas,
|
||||||
cut_off_inheritance,
|
matches_document_author_rules,
|
||||||
element,
|
element,
|
||||||
data,
|
data,
|
||||||
matching_context,
|
matching_context,
|
||||||
@ -248,7 +248,7 @@ where
|
|||||||
invalidates_self: false,
|
invalidates_self: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let document_origins = if self.cut_off_inheritance {
|
let document_origins = if !self.matches_document_author_rules {
|
||||||
Origin::UserAgent.into()
|
Origin::UserAgent.into()
|
||||||
} else {
|
} else {
|
||||||
OriginSet::all()
|
OriginSet::all()
|
||||||
|
@ -263,7 +263,7 @@ where
|
|||||||
Self {
|
Self {
|
||||||
entries: vec![],
|
entries: vec![],
|
||||||
data_validity: DataValidity::Valid,
|
data_validity: DataValidity::Valid,
|
||||||
dirty: false,
|
dirty: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -597,6 +597,11 @@ where
|
|||||||
self.collection.dirty
|
self.collection.dirty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether the collection is empty.
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.collection.len() == 0
|
||||||
|
}
|
||||||
|
|
||||||
fn collection_for(
|
fn collection_for(
|
||||||
&mut self,
|
&mut self,
|
||||||
_sheet: &S,
|
_sheet: &S,
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
use {Atom, LocalName, Namespace, WeakAtom};
|
use {Atom, LocalName, Namespace, WeakAtom};
|
||||||
use applicable_declarations::{ApplicableDeclarationBlock, ApplicableDeclarationList};
|
use applicable_declarations::{ApplicableDeclarationBlock, ApplicableDeclarationList};
|
||||||
use context::{CascadeInputs, QuirksMode};
|
use context::{CascadeInputs, QuirksMode};
|
||||||
use dom::TElement;
|
use dom::{TElement, TShadowRoot};
|
||||||
use element_state::{DocumentState, ElementState};
|
use element_state::{DocumentState, ElementState};
|
||||||
use font_metrics::FontMetricsProvider;
|
use font_metrics::FontMetricsProvider;
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
@ -599,11 +599,12 @@ impl Stylist {
|
|||||||
|
|
||||||
let mut maybe = false;
|
let mut maybe = false;
|
||||||
|
|
||||||
let cut_off = element.each_applicable_non_document_style_rule_data(|data, quirks_mode| {
|
let doc_author_rules_apply =
|
||||||
maybe = maybe || f(&*data, quirks_mode);
|
element.each_applicable_non_document_style_rule_data(|data, quirks_mode| {
|
||||||
});
|
maybe = maybe || f(&*data, quirks_mode);
|
||||||
|
});
|
||||||
|
|
||||||
if maybe || cut_off {
|
if maybe || !doc_author_rules_apply {
|
||||||
return maybe;
|
return maybe;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1251,6 +1252,8 @@ impl Stylist {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut match_document_author_rules = matches_author_rules;
|
||||||
|
|
||||||
// XBL / Shadow DOM rules, which are author rules too.
|
// XBL / Shadow DOM rules, which are author rules too.
|
||||||
//
|
//
|
||||||
// TODO(emilio): Cascade order here is wrong for Shadow DOM. In
|
// TODO(emilio): Cascade order here is wrong for Shadow DOM. In
|
||||||
@ -1268,26 +1271,43 @@ impl Stylist {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for slot in slots.iter().rev() {
|
for slot in slots.iter().rev() {
|
||||||
slot.each_xbl_cascade_data(|cascade_data, _quirks_mode| {
|
let styles = slot.containing_shadow().unwrap().style_data();
|
||||||
if let Some(map) = cascade_data.slotted_rules(pseudo_element) {
|
if let Some(map) = styles.slotted_rules(pseudo_element) {
|
||||||
map.get_all_matching_rules(
|
map.get_all_matching_rules(
|
||||||
element,
|
element,
|
||||||
rule_hash_target,
|
rule_hash_target,
|
||||||
applicable_declarations,
|
applicable_declarations,
|
||||||
context,
|
context,
|
||||||
flags_setter,
|
flags_setter,
|
||||||
CascadeLevel::AuthorNormal
|
CascadeLevel::AuthorNormal,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
// TODO(emilio): We need to look up :host rules if the element is a
|
||||||
|
// shadow host, when we implement that.
|
||||||
|
if let Some(containing_shadow) = rule_hash_target.containing_shadow() {
|
||||||
|
let cascade_data = containing_shadow.style_data();
|
||||||
|
if let Some(map) = cascade_data.normal_rules(pseudo_element) {
|
||||||
|
map.get_all_matching_rules(
|
||||||
|
element,
|
||||||
|
rule_hash_target,
|
||||||
|
applicable_declarations,
|
||||||
|
context,
|
||||||
|
flags_setter,
|
||||||
|
CascadeLevel::AuthorNormal,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
match_document_author_rules = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(emilio): It looks very wrong to match XBL / Shadow DOM rules
|
// FIXME(emilio): It looks very wrong to match XBL rules even for
|
||||||
// even for getDefaultComputedStyle!
|
// getDefaultComputedStyle!
|
||||||
//
|
//
|
||||||
// Also, this doesn't account for the author_styles_enabled stuff.
|
// Also, this doesn't account for the author_styles_enabled stuff.
|
||||||
let cut_off_inheritance = element.each_xbl_cascade_data(|cascade_data, quirks_mode| {
|
let cut_xbl_binding_inheritance = element.each_xbl_cascade_data(|cascade_data, quirks_mode| {
|
||||||
if let Some(map) = cascade_data.normal_rules(pseudo_element) {
|
if let Some(map) = cascade_data.normal_rules(pseudo_element) {
|
||||||
// NOTE(emilio): This is needed because the XBL stylist may
|
// NOTE(emilio): This is needed because the XBL stylist may
|
||||||
// think it has a different quirks mode than the document.
|
// think it has a different quirks mode than the document.
|
||||||
@ -1314,7 +1334,9 @@ impl Stylist {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if matches_author_rules && !only_default_rules && !cut_off_inheritance {
|
match_document_author_rules &= !cut_xbl_binding_inheritance;
|
||||||
|
|
||||||
|
if match_document_author_rules && !only_default_rules {
|
||||||
// Author normal rules.
|
// Author normal rules.
|
||||||
if let Some(map) = self.cascade_data.author.normal_rules(pseudo_element) {
|
if let Some(map) = self.cascade_data.author.normal_rules(pseudo_element) {
|
||||||
map.get_all_matching_rules(
|
map.get_all_matching_rules(
|
||||||
|
Loading…
Reference in New Issue
Block a user