Auto merge of #18962 - upsuper:tree-pseudos, r=emilio

Support matching for ::-moz-tree-* pseudo-elements

This is the Servo side change of [bug 1397644](https://bugzilla.mozilla.org/show_bug.cgi?id=1397644).

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/18962)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-10-20 04:18:53 -05:00 committed by GitHub
commit b1e6f05ae4
13 changed files with 489 additions and 257 deletions

View file

@ -408,7 +408,8 @@ pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + Debug +
RuleInclusion::All, RuleInclusion::All,
data.styles.primary(), data.styles.primary(),
/* is_probe = */ false, /* is_probe = */ false,
&ServoMetricsProvider) &ServoMetricsProvider,
/* matching_func = */ None)
.unwrap() .unwrap()
.clone() .clone()
} }

View file

@ -109,6 +109,10 @@ where
/// The current nesting level of selectors that we're matching. /// The current nesting level of selectors that we're matching.
pub nesting_level: usize, pub nesting_level: usize,
/// An optional hook function for checking whether a pseudo-element
/// should match when matching_mode is ForStatelessPseudoElement.
pub pseudo_element_matching_fn: Option<&'a Fn(&Impl::PseudoElement) -> bool>,
quirks_mode: QuirksMode, quirks_mode: QuirksMode,
classes_and_ids_case_sensitivity: CaseSensitivity, classes_and_ids_case_sensitivity: CaseSensitivity,
_impl: ::std::marker::PhantomData<Impl>, _impl: ::std::marker::PhantomData<Impl>,
@ -152,6 +156,7 @@ where
classes_and_ids_case_sensitivity: quirks_mode.classes_and_ids_case_sensitivity(), classes_and_ids_case_sensitivity: quirks_mode.classes_and_ids_case_sensitivity(),
scope_element: None, scope_element: None,
nesting_level: 0, nesting_level: 0,
pseudo_element_matching_fn: None,
_impl: ::std::marker::PhantomData, _impl: ::std::marker::PhantomData,
} }
} }

View file

@ -387,9 +387,20 @@ where
if context.nesting_level == 0 && if context.nesting_level == 0 &&
context.matching_mode == MatchingMode::ForStatelessPseudoElement { context.matching_mode == MatchingMode::ForStatelessPseudoElement {
// Consume the pseudo. // Consume the pseudo.
let pseudo = iter.next().unwrap(); match *iter.next().unwrap() {
debug_assert!(matches!(*pseudo, Component::PseudoElement(..)), Component::PseudoElement(ref pseudo) => {
"Used MatchingMode::ForStatelessPseudoElement in a non-pseudo selector"); if let Some(ref f) = context.pseudo_element_matching_fn {
if !f(pseudo) {
return false;
}
}
}
_ => {
debug_assert!(false,
"Used MatchingMode::ForStatelessPseudoElement \
in a non-pseudo selector");
}
}
// The only other parser-allowed Component in this sequence is a state // The only other parser-allowed Component in this sequence is a state
// class. We just don't match in that case. // class. We just don't match in that case.

View file

@ -15,6 +15,7 @@ use gecko_bindings::structs::mozilla::css::ImageValue;
use gecko_bindings::structs::mozilla::css::URLValue; use gecko_bindings::structs::mozilla::css::URLValue;
use gecko_bindings::structs::mozilla::css::URLValueData; use gecko_bindings::structs::mozilla::css::URLValueData;
use gecko_bindings::structs::mozilla::AnonymousCounterStyle; use gecko_bindings::structs::mozilla::AnonymousCounterStyle;
use gecko_bindings::structs::mozilla::AtomArray;
use gecko_bindings::structs::mozilla::MallocSizeOf; use gecko_bindings::structs::mozilla::MallocSizeOf;
use gecko_bindings::structs::mozilla::OriginFlags; use gecko_bindings::structs::mozilla::OriginFlags;
use gecko_bindings::structs::mozilla::UniquePtr; use gecko_bindings::structs::mozilla::UniquePtr;
@ -2945,6 +2946,19 @@ extern "C" {
set: RawServoStyleSetBorrowed) set: RawServoStyleSetBorrowed)
-> ServoStyleContextStrong; -> ServoStyleContextStrong;
} }
extern "C" {
pub fn Servo_ComputedValues_ResolveXULTreePseudoStyle(element:
RawGeckoElementBorrowed,
pseudo_tag:
*mut nsAtom,
inherited_style:
ServoStyleContextBorrowed,
input_word:
*const AtomArray,
set:
RawServoStyleSetBorrowed)
-> ServoStyleContextStrong;
}
extern "C" { extern "C" {
pub fn Servo_SetExplicitStyle(element: RawGeckoElementBorrowed, pub fn Servo_SetExplicitStyle(element: RawGeckoElementBorrowed,
primary_style: ServoStyleContextBorrowed); primary_style: ServoStyleContextBorrowed);

View file

@ -140,29 +140,29 @@ pub enum PseudoElement {
/// :-moz-ruby-text-container /// :-moz-ruby-text-container
RubyTextContainer, RubyTextContainer,
/// :-moz-tree-column /// :-moz-tree-column
MozTreeColumn(Box<[String]>), MozTreeColumn(Box<[Atom]>),
/// :-moz-tree-row /// :-moz-tree-row
MozTreeRow(Box<[String]>), MozTreeRow(Box<[Atom]>),
/// :-moz-tree-separator /// :-moz-tree-separator
MozTreeSeparator(Box<[String]>), MozTreeSeparator(Box<[Atom]>),
/// :-moz-tree-cell /// :-moz-tree-cell
MozTreeCell(Box<[String]>), MozTreeCell(Box<[Atom]>),
/// :-moz-tree-indentation /// :-moz-tree-indentation
MozTreeIndentation(Box<[String]>), MozTreeIndentation(Box<[Atom]>),
/// :-moz-tree-line /// :-moz-tree-line
MozTreeLine(Box<[String]>), MozTreeLine(Box<[Atom]>),
/// :-moz-tree-twisty /// :-moz-tree-twisty
MozTreeTwisty(Box<[String]>), MozTreeTwisty(Box<[Atom]>),
/// :-moz-tree-image /// :-moz-tree-image
MozTreeImage(Box<[String]>), MozTreeImage(Box<[Atom]>),
/// :-moz-tree-cell-text /// :-moz-tree-cell-text
MozTreeCellText(Box<[String]>), MozTreeCellText(Box<[Atom]>),
/// :-moz-tree-checkbox /// :-moz-tree-checkbox
MozTreeCheckbox(Box<[String]>), MozTreeCheckbox(Box<[Atom]>),
/// :-moz-tree-progressmeter /// :-moz-tree-progressmeter
MozTreeProgressmeter(Box<[String]>), MozTreeProgressmeter(Box<[Atom]>),
/// :-moz-tree-drop-feedback /// :-moz-tree-drop-feedback
MozTreeDropFeedback(Box<[String]>), MozTreeDropFeedback(Box<[Atom]>),
/// :-moz-svg-marker-anon-child /// :-moz-svg-marker-anon-child
MozSVGMarkerAnonChild, MozSVGMarkerAnonChild,
/// :-moz-svg-outer-svg-anon-child /// :-moz-svg-outer-svg-anon-child
@ -185,6 +185,12 @@ pub const EAGER_PSEUDO_COUNT: usize = 4;
/// The number of non-functional pseudo-elements. /// The number of non-functional pseudo-elements.
pub const SIMPLE_PSEUDO_COUNT: usize = 71; pub const SIMPLE_PSEUDO_COUNT: usize = 71;
/// The number of tree pseudo-elements.
pub const TREE_PSEUDO_COUNT: usize = 12;
/// The number of all pseudo-elements.
pub const PSEUDO_COUNT: usize = 83;
/// The list of eager pseudos. /// The list of eager pseudos.
pub const EAGER_PSEUDOS: [PseudoElement; EAGER_PSEUDO_COUNT] = [ pub const EAGER_PSEUDOS: [PseudoElement; EAGER_PSEUDO_COUNT] = [
PseudoElement::Before, PseudoElement::Before,
@ -286,162 +292,184 @@ impl PseudoElement {
} }
} }
/// Returns an index if the pseudo-element is a simple (non-functional) /// Returns an index of the pseudo-element.
/// pseudo.
#[inline] #[inline]
pub fn simple_index(&self) -> Option<usize> { pub fn index(&self) -> usize {
match *self { match *self {
PseudoElement::After => Some(0), PseudoElement::After => 0,
PseudoElement::Before => Some(1), PseudoElement::Before => 1,
PseudoElement::Backdrop => Some(2), PseudoElement::Backdrop => 2,
PseudoElement::Cue => Some(3), PseudoElement::Cue => 3,
PseudoElement::FirstLetter => Some(4), PseudoElement::FirstLetter => 4,
PseudoElement::FirstLine => Some(5), PseudoElement::FirstLine => 5,
PseudoElement::MozSelection => Some(6), PseudoElement::MozSelection => 6,
PseudoElement::MozFocusInner => Some(7), PseudoElement::MozFocusInner => 7,
PseudoElement::MozFocusOuter => Some(8), PseudoElement::MozFocusOuter => 8,
PseudoElement::MozListBullet => Some(9), PseudoElement::MozListBullet => 9,
PseudoElement::MozListNumber => Some(10), PseudoElement::MozListNumber => 10,
PseudoElement::MozMathAnonymous => Some(11), PseudoElement::MozMathAnonymous => 11,
PseudoElement::MozNumberWrapper => Some(12), PseudoElement::MozNumberWrapper => 12,
PseudoElement::MozNumberText => Some(13), PseudoElement::MozNumberText => 13,
PseudoElement::MozNumberSpinBox => Some(14), PseudoElement::MozNumberSpinBox => 14,
PseudoElement::MozNumberSpinUp => Some(15), PseudoElement::MozNumberSpinUp => 15,
PseudoElement::MozNumberSpinDown => Some(16), PseudoElement::MozNumberSpinDown => 16,
PseudoElement::MozProgressBar => Some(17), PseudoElement::MozProgressBar => 17,
PseudoElement::MozRangeTrack => Some(18), PseudoElement::MozRangeTrack => 18,
PseudoElement::MozRangeProgress => Some(19), PseudoElement::MozRangeProgress => 19,
PseudoElement::MozRangeThumb => Some(20), PseudoElement::MozRangeThumb => 20,
PseudoElement::MozMeterBar => Some(21), PseudoElement::MozMeterBar => 21,
PseudoElement::MozPlaceholder => Some(22), PseudoElement::MozPlaceholder => 22,
PseudoElement::Placeholder => Some(23), PseudoElement::Placeholder => 23,
PseudoElement::MozColorSwatch => Some(24), PseudoElement::MozColorSwatch => 24,
PseudoElement::MozText => Some(25), PseudoElement::MozText => 25,
PseudoElement::OofPlaceholder => Some(26), PseudoElement::OofPlaceholder => 26,
PseudoElement::FirstLetterContinuation => Some(27), PseudoElement::FirstLetterContinuation => 27,
PseudoElement::MozBlockInsideInlineWrapper => Some(28), PseudoElement::MozBlockInsideInlineWrapper => 28,
PseudoElement::MozMathMLAnonymousBlock => Some(29), PseudoElement::MozMathMLAnonymousBlock => 29,
PseudoElement::MozXULAnonymousBlock => Some(30), PseudoElement::MozXULAnonymousBlock => 30,
PseudoElement::HorizontalFramesetBorder => Some(31), PseudoElement::HorizontalFramesetBorder => 31,
PseudoElement::VerticalFramesetBorder => Some(32), PseudoElement::VerticalFramesetBorder => 32,
PseudoElement::MozLineFrame => Some(33), PseudoElement::MozLineFrame => 33,
PseudoElement::ButtonContent => Some(34), PseudoElement::ButtonContent => 34,
PseudoElement::CellContent => Some(35), PseudoElement::CellContent => 35,
PseudoElement::DropDownList => Some(36), PseudoElement::DropDownList => 36,
PseudoElement::FieldsetContent => Some(37), PseudoElement::FieldsetContent => 37,
PseudoElement::FramesetBlank => Some(38), PseudoElement::FramesetBlank => 38,
PseudoElement::MozDisplayComboboxControlFrame => Some(39), PseudoElement::MozDisplayComboboxControlFrame => 39,
PseudoElement::HtmlCanvasContent => Some(40), PseudoElement::HtmlCanvasContent => 40,
PseudoElement::InlineTable => Some(41), PseudoElement::InlineTable => 41,
PseudoElement::Table => Some(42), PseudoElement::Table => 42,
PseudoElement::TableCell => Some(43), PseudoElement::TableCell => 43,
PseudoElement::TableColGroup => Some(44), PseudoElement::TableColGroup => 44,
PseudoElement::TableCol => Some(45), PseudoElement::TableCol => 45,
PseudoElement::TableWrapper => Some(46), PseudoElement::TableWrapper => 46,
PseudoElement::TableRowGroup => Some(47), PseudoElement::TableRowGroup => 47,
PseudoElement::TableRow => Some(48), PseudoElement::TableRow => 48,
PseudoElement::Canvas => Some(49), PseudoElement::Canvas => 49,
PseudoElement::PageBreak => Some(50), PseudoElement::PageBreak => 50,
PseudoElement::Page => Some(51), PseudoElement::Page => 51,
PseudoElement::PageContent => Some(52), PseudoElement::PageContent => 52,
PseudoElement::PageSequence => Some(53), PseudoElement::PageSequence => 53,
PseudoElement::ScrolledContent => Some(54), PseudoElement::ScrolledContent => 54,
PseudoElement::ScrolledCanvas => Some(55), PseudoElement::ScrolledCanvas => 55,
PseudoElement::ScrolledPageSequence => Some(56), PseudoElement::ScrolledPageSequence => 56,
PseudoElement::ColumnContent => Some(57), PseudoElement::ColumnContent => 57,
PseudoElement::Viewport => Some(58), PseudoElement::Viewport => 58,
PseudoElement::ViewportScroll => Some(59), PseudoElement::ViewportScroll => 59,
PseudoElement::AnonymousFlexItem => Some(60), PseudoElement::AnonymousFlexItem => 60,
PseudoElement::AnonymousGridItem => Some(61), PseudoElement::AnonymousGridItem => 61,
PseudoElement::Ruby => Some(62), PseudoElement::Ruby => 62,
PseudoElement::RubyBase => Some(63), PseudoElement::RubyBase => 63,
PseudoElement::RubyBaseContainer => Some(64), PseudoElement::RubyBaseContainer => 64,
PseudoElement::RubyText => Some(65), PseudoElement::RubyText => 65,
PseudoElement::RubyTextContainer => Some(66), PseudoElement::RubyTextContainer => 66,
PseudoElement::MozSVGMarkerAnonChild => Some(67), PseudoElement::MozTreeColumn(..) => 67,
PseudoElement::MozSVGOuterSVGAnonChild => Some(68), PseudoElement::MozTreeRow(..) => 68,
PseudoElement::MozSVGForeignContent => Some(69), PseudoElement::MozTreeSeparator(..) => 69,
PseudoElement::MozSVGText => Some(70), PseudoElement::MozTreeCell(..) => 70,
_ => None, PseudoElement::MozTreeIndentation(..) => 71,
PseudoElement::MozTreeLine(..) => 72,
PseudoElement::MozTreeTwisty(..) => 73,
PseudoElement::MozTreeImage(..) => 74,
PseudoElement::MozTreeCellText(..) => 75,
PseudoElement::MozTreeCheckbox(..) => 76,
PseudoElement::MozTreeProgressmeter(..) => 77,
PseudoElement::MozTreeDropFeedback(..) => 78,
PseudoElement::MozSVGMarkerAnonChild => 79,
PseudoElement::MozSVGOuterSVGAnonChild => 80,
PseudoElement::MozSVGForeignContent => 81,
PseudoElement::MozSVGText => 82,
} }
} }
/// Returns an array of `None` values. /// Returns an array of `None` values.
/// ///
/// FIXME(emilio): Integer generics can't come soon enough. /// FIXME(emilio): Integer generics can't come soon enough.
pub fn simple_pseudo_none_array<T>() -> [Option<T>; SIMPLE_PSEUDO_COUNT] { pub fn pseudo_none_array<T>() -> [Option<T>; PSEUDO_COUNT] {
[ [
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None, None,
None None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None
] ]
} }
@ -518,6 +546,26 @@ None
PseudoElement::Before | PseudoElement::After | PseudoElement::FirstLine | PseudoElement::FirstLetter) PseudoElement::Before | PseudoElement::After | PseudoElement::FirstLine | PseudoElement::FirstLetter)
} }
/// Whether this pseudo-element is tree pseudo-element.
#[inline]
pub fn is_tree_pseudo_element(&self) -> bool {
match *self {
PseudoElement::MozTreeColumn(..) => true,
PseudoElement::MozTreeRow(..) => true,
PseudoElement::MozTreeSeparator(..) => true,
PseudoElement::MozTreeCell(..) => true,
PseudoElement::MozTreeIndentation(..) => true,
PseudoElement::MozTreeLine(..) => true,
PseudoElement::MozTreeTwisty(..) => true,
PseudoElement::MozTreeImage(..) => true,
PseudoElement::MozTreeCellText(..) => true,
PseudoElement::MozTreeCheckbox(..) => true,
PseudoElement::MozTreeProgressmeter(..) => true,
PseudoElement::MozTreeDropFeedback(..) => true,
_ => false,
}
}
/// Gets the flags associated to this pseudo-element, or 0 if it's an /// Gets the flags associated to this pseudo-element, or 0 if it's an
/// anonymous box. /// anonymous box.
pub fn flags(&self) -> u32 { pub fn flags(&self) -> u32 {
@ -847,18 +895,18 @@ None
PseudoElement::RubyBaseContainer => CSSPseudoElementType_InheritingAnonBox, PseudoElement::RubyBaseContainer => CSSPseudoElementType_InheritingAnonBox,
PseudoElement::RubyText => CSSPseudoElementType_InheritingAnonBox, PseudoElement::RubyText => CSSPseudoElementType_InheritingAnonBox,
PseudoElement::RubyTextContainer => CSSPseudoElementType_InheritingAnonBox, PseudoElement::RubyTextContainer => CSSPseudoElementType_InheritingAnonBox,
PseudoElement::MozTreeColumn(..) => CSSPseudoElementType_InheritingAnonBox, PseudoElement::MozTreeColumn(..) => CSSPseudoElementType::XULTree,
PseudoElement::MozTreeRow(..) => CSSPseudoElementType_InheritingAnonBox, PseudoElement::MozTreeRow(..) => CSSPseudoElementType::XULTree,
PseudoElement::MozTreeSeparator(..) => CSSPseudoElementType_InheritingAnonBox, PseudoElement::MozTreeSeparator(..) => CSSPseudoElementType::XULTree,
PseudoElement::MozTreeCell(..) => CSSPseudoElementType_InheritingAnonBox, PseudoElement::MozTreeCell(..) => CSSPseudoElementType::XULTree,
PseudoElement::MozTreeIndentation(..) => CSSPseudoElementType_InheritingAnonBox, PseudoElement::MozTreeIndentation(..) => CSSPseudoElementType::XULTree,
PseudoElement::MozTreeLine(..) => CSSPseudoElementType_InheritingAnonBox, PseudoElement::MozTreeLine(..) => CSSPseudoElementType::XULTree,
PseudoElement::MozTreeTwisty(..) => CSSPseudoElementType_InheritingAnonBox, PseudoElement::MozTreeTwisty(..) => CSSPseudoElementType::XULTree,
PseudoElement::MozTreeImage(..) => CSSPseudoElementType_InheritingAnonBox, PseudoElement::MozTreeImage(..) => CSSPseudoElementType::XULTree,
PseudoElement::MozTreeCellText(..) => CSSPseudoElementType_InheritingAnonBox, PseudoElement::MozTreeCellText(..) => CSSPseudoElementType::XULTree,
PseudoElement::MozTreeCheckbox(..) => CSSPseudoElementType_InheritingAnonBox, PseudoElement::MozTreeCheckbox(..) => CSSPseudoElementType::XULTree,
PseudoElement::MozTreeProgressmeter(..) => CSSPseudoElementType_InheritingAnonBox, PseudoElement::MozTreeProgressmeter(..) => CSSPseudoElementType::XULTree,
PseudoElement::MozTreeDropFeedback(..) => CSSPseudoElementType_InheritingAnonBox, PseudoElement::MozTreeDropFeedback(..) => CSSPseudoElementType::XULTree,
PseudoElement::MozSVGMarkerAnonChild => CSSPseudoElementType_InheritingAnonBox, PseudoElement::MozSVGMarkerAnonChild => CSSPseudoElementType_InheritingAnonBox,
PseudoElement::MozSVGOuterSVGAnonChild => CSSPseudoElementType_InheritingAnonBox, PseudoElement::MozSVGOuterSVGAnonChild => CSSPseudoElementType_InheritingAnonBox,
PseudoElement::MozSVGForeignContent => CSSPseudoElementType_InheritingAnonBox, PseudoElement::MozSVGForeignContent => CSSPseudoElementType_InheritingAnonBox,
@ -871,6 +919,26 @@ None
(self.atom().as_ptr(), self.pseudo_type()) (self.atom().as_ptr(), self.pseudo_type())
} }
/// Get the argument list of a tree pseudo-element.
#[inline]
pub fn tree_pseudo_args(&self) -> Option<&[Atom]> {
match *self {
PseudoElement::MozTreeColumn(ref args) => Some(args),
PseudoElement::MozTreeRow(ref args) => Some(args),
PseudoElement::MozTreeSeparator(ref args) => Some(args),
PseudoElement::MozTreeCell(ref args) => Some(args),
PseudoElement::MozTreeIndentation(ref args) => Some(args),
PseudoElement::MozTreeLine(ref args) => Some(args),
PseudoElement::MozTreeTwisty(ref args) => Some(args),
PseudoElement::MozTreeImage(ref args) => Some(args),
PseudoElement::MozTreeCellText(ref args) => Some(args),
PseudoElement::MozTreeCheckbox(ref args) => Some(args),
PseudoElement::MozTreeProgressmeter(ref args) => Some(args),
PseudoElement::MozTreeDropFeedback(ref args) => Some(args),
_ => None,
}
}
/// Construct a pseudo-element from an `Atom`. /// Construct a pseudo-element from an `Atom`.
#[inline] #[inline]
pub fn from_atom(atom: &Atom) -> Option<Self> { pub fn from_atom(atom: &Atom) -> Option<Self> {
@ -1258,6 +1326,48 @@ None
None None
} }
/// Construct a tree pseudo-element from atom and args.
#[inline]
pub fn from_tree_pseudo_atom(atom: &Atom, args: Box<[Atom]>) -> Option<Self> {
if atom == &atom!(":-moz-tree-column") {
return Some(PseudoElement::MozTreeColumn(args));
}
if atom == &atom!(":-moz-tree-row") {
return Some(PseudoElement::MozTreeRow(args));
}
if atom == &atom!(":-moz-tree-separator") {
return Some(PseudoElement::MozTreeSeparator(args));
}
if atom == &atom!(":-moz-tree-cell") {
return Some(PseudoElement::MozTreeCell(args));
}
if atom == &atom!(":-moz-tree-indentation") {
return Some(PseudoElement::MozTreeIndentation(args));
}
if atom == &atom!(":-moz-tree-line") {
return Some(PseudoElement::MozTreeLine(args));
}
if atom == &atom!(":-moz-tree-twisty") {
return Some(PseudoElement::MozTreeTwisty(args));
}
if atom == &atom!(":-moz-tree-image") {
return Some(PseudoElement::MozTreeImage(args));
}
if atom == &atom!(":-moz-tree-cell-text") {
return Some(PseudoElement::MozTreeCellText(args));
}
if atom == &atom!(":-moz-tree-checkbox") {
return Some(PseudoElement::MozTreeCheckbox(args));
}
if atom == &atom!(":-moz-tree-progressmeter") {
return Some(PseudoElement::MozTreeProgressmeter(args));
}
if atom == &atom!(":-moz-tree-drop-feedback") {
return Some(PseudoElement::MozTreeDropFeedback(args));
}
None
}
/// Constructs an atom from a string of text, and whether we're in a /// Constructs an atom from a string of text, and whether we're in a
/// user-agent stylesheet. /// user-agent stylesheet.
/// ///
@ -1636,7 +1746,7 @@ None
/// ///
/// Returns `None` if the pseudo-element is not recognized. /// Returns `None` if the pseudo-element is not recognized.
#[inline] #[inline]
pub fn tree_pseudo_element(name: &str, args: Box<[String]>) -> Option<Self> { pub fn tree_pseudo_element(name: &str, args: Box<[Atom]>) -> Option<Self> {
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
debug_assert!(name.starts_with("-moz-tree-")); debug_assert!(name.starts_with("-moz-tree-"));
let tree_part = &name[10..]; let tree_part = &name[10..];
@ -1768,31 +1878,20 @@ impl ToCss for PseudoElement {
PseudoElement::MozSVGForeignContent => dest.write_str(":-moz-svg-foreign-content")?, PseudoElement::MozSVGForeignContent => dest.write_str(":-moz-svg-foreign-content")?,
PseudoElement::MozSVGText => dest.write_str(":-moz-svg-text")?, PseudoElement::MozSVGText => dest.write_str(":-moz-svg-text")?,
} }
match *self { if let Some(args) = self.tree_pseudo_args() {
PseudoElement::MozTreeColumn(ref args) | if !args.is_empty() {
PseudoElement::MozTreeRow(ref args) |
PseudoElement::MozTreeSeparator(ref args) |
PseudoElement::MozTreeCell(ref args) |
PseudoElement::MozTreeIndentation(ref args) |
PseudoElement::MozTreeLine(ref args) |
PseudoElement::MozTreeTwisty(ref args) |
PseudoElement::MozTreeImage(ref args) |
PseudoElement::MozTreeCellText(ref args) |
PseudoElement::MozTreeCheckbox(ref args) |
PseudoElement::MozTreeProgressmeter(ref args) |
PseudoElement::MozTreeDropFeedback(ref args) => {
dest.write_char('(')?; dest.write_char('(')?;
let mut iter = args.iter(); let mut iter = args.iter();
if let Some(first) = iter.next() { if let Some(first) = iter.next() {
serialize_identifier(first, dest)?; serialize_identifier(&first.to_string(), dest)?;
for item in iter { for item in iter {
dest.write_str(", ")?; dest.write_str(", ")?;
serialize_identifier(item, dest)?; serialize_identifier(&item.to_string(), dest)?;
} }
} }
dest.write_char(')') dest.write_char(')')?;
} }
_ => Ok(()),
} }
Ok(())
} }
} }

View file

@ -4175,6 +4175,7 @@ pub mod root {
pub struct ShortcutKeyCandidate { pub struct ShortcutKeyCandidate {
_unused: [u8; 0], _unused: [u8; 0],
} }
pub type AtomArray = root::nsTArray<root::RefPtr<root::nsAtom>>;
/// EventStates is the class used to represent the event states of nsIContent /// EventStates is the class used to represent the event states of nsIContent
/// instances. These states are calculated by IntrinsicState() and /// instances. These states are calculated by IntrinsicState() and
/// ContentStatesChanged() has to be called when one of them changes thus /// ContentStatesChanged() has to be called when one of them changes thus
@ -22385,8 +22386,6 @@ pub mod root {
pub struct nsAttrValue { pub struct nsAttrValue {
pub mBits: usize, pub mBits: usize,
} }
pub type nsAttrValue_AtomArray =
root::nsTArray<root::RefPtr<root::nsAtom>>;
pub const nsAttrValue_ValueType_eSVGTypesBegin: pub const nsAttrValue_ValueType_eSVGTypesBegin:
root::nsAttrValue_ValueType = root::nsAttrValue_ValueType =
nsAttrValue_ValueType::eSVGAngle; nsAttrValue_ValueType::eSVGAngle;

View file

@ -46,7 +46,7 @@ impl PseudoElement {
return PseudoElementCascadeType::Eager return PseudoElementCascadeType::Eager
} }
if self.is_anon_box() { if self.is_precomputed() {
return PseudoElementCascadeType::Precomputed return PseudoElementCascadeType::Precomputed
} }
@ -137,7 +137,7 @@ impl PseudoElement {
/// Whether this pseudo-element is precomputed. /// Whether this pseudo-element is precomputed.
#[inline] #[inline]
pub fn is_precomputed(&self) -> bool { pub fn is_precomputed(&self) -> bool {
self.is_anon_box() self.is_anon_box() && !self.is_tree_pseudo_element()
} }
/// Covert non-canonical pseudo-element to canonical one, and keep a /// Covert non-canonical pseudo-element to canonical one, and keep a

View file

@ -8,7 +8,7 @@ pub enum PseudoElement {
% for pseudo in PSEUDOS: % for pseudo in PSEUDOS:
/// ${pseudo.value} /// ${pseudo.value}
% if pseudo.is_tree_pseudo_element(): % if pseudo.is_tree_pseudo_element():
${pseudo.capitalized()}(Box<[String]>), ${pseudo.capitalized()}(Box<[Atom]>),
% else: % else:
${pseudo.capitalized()}, ${pseudo.capitalized()},
% endif % endif
@ -27,6 +27,12 @@ pub const EAGER_PSEUDO_COUNT: usize = ${len(EAGER_PSEUDOS)};
/// The number of non-functional pseudo-elements. /// The number of non-functional pseudo-elements.
pub const SIMPLE_PSEUDO_COUNT: usize = ${len(SIMPLE_PSEUDOS)}; pub const SIMPLE_PSEUDO_COUNT: usize = ${len(SIMPLE_PSEUDOS)};
/// The number of tree pseudo-elements.
pub const TREE_PSEUDO_COUNT: usize = ${len(TREE_PSEUDOS)};
/// The number of all pseudo-elements.
pub const PSEUDO_COUNT: usize = ${len(PSEUDOS)};
/// The list of eager pseudos. /// The list of eager pseudos.
pub const EAGER_PSEUDOS: [PseudoElement; EAGER_PSEUDO_COUNT] = [ pub const EAGER_PSEUDOS: [PseudoElement; EAGER_PSEUDO_COUNT] = [
% for eager_pseudo_name in EAGER_PSEUDOS: % for eager_pseudo_name in EAGER_PSEUDOS:
@ -49,24 +55,22 @@ impl PseudoElement {
} }
} }
/// Returns an index if the pseudo-element is a simple (non-functional) /// Returns an index of the pseudo-element.
/// pseudo.
#[inline] #[inline]
pub fn simple_index(&self) -> Option<usize> { pub fn index(&self) -> usize {
match *self { match *self {
% for i, pseudo in enumerate(SIMPLE_PSEUDOS): % for i, pseudo in enumerate(PSEUDOS):
${pseudo_element_variant(pseudo)} => Some(${i}), ${pseudo_element_variant(pseudo)} => ${i},
% endfor % endfor
_ => None,
} }
} }
/// Returns an array of `None` values. /// Returns an array of `None` values.
/// ///
/// FIXME(emilio): Integer generics can't come soon enough. /// FIXME(emilio): Integer generics can't come soon enough.
pub fn simple_pseudo_none_array<T>() -> [Option<T>; SIMPLE_PSEUDO_COUNT] { pub fn pseudo_none_array<T>() -> [Option<T>; PSEUDO_COUNT] {
[ [
${",\n".join(["None" for pseudo in SIMPLE_PSEUDOS])} ${",\n ".join(["None" for pseudo in PSEUDOS])}
] ]
} }
@ -90,6 +94,17 @@ impl PseudoElement {
${" | ".join(map(lambda name: "PseudoElement::{}".format(name), EAGER_PSEUDOS))}) ${" | ".join(map(lambda name: "PseudoElement::{}".format(name), EAGER_PSEUDOS))})
} }
/// Whether this pseudo-element is tree pseudo-element.
#[inline]
pub fn is_tree_pseudo_element(&self) -> bool {
match *self {
% for pseudo in TREE_PSEUDOS:
${pseudo_element_variant(pseudo)} => true,
% endfor
_ => false,
}
}
/// Gets the flags associated to this pseudo-element, or 0 if it's an /// Gets the flags associated to this pseudo-element, or 0 if it's an
/// anonymous box. /// anonymous box.
pub fn flags(&self) -> u32 { pub fn flags(&self) -> u32 {
@ -132,7 +147,7 @@ impl PseudoElement {
% if not pseudo.is_anon_box(): % if not pseudo.is_anon_box():
PseudoElement::${pseudo.capitalized()} => CSSPseudoElementType::${pseudo.original_ident}, PseudoElement::${pseudo.capitalized()} => CSSPseudoElementType::${pseudo.original_ident},
% elif pseudo.is_tree_pseudo_element(): % elif pseudo.is_tree_pseudo_element():
PseudoElement::${pseudo.capitalized()}(..) => CSSPseudoElementType_InheritingAnonBox, PseudoElement::${pseudo.capitalized()}(..) => CSSPseudoElementType::XULTree,
% elif pseudo.is_inheriting_anon_box(): % elif pseudo.is_inheriting_anon_box():
PseudoElement::${pseudo.capitalized()} => CSSPseudoElementType_InheritingAnonBox, PseudoElement::${pseudo.capitalized()} => CSSPseudoElementType_InheritingAnonBox,
% else: % else:
@ -147,6 +162,17 @@ impl PseudoElement {
(self.atom().as_ptr(), self.pseudo_type()) (self.atom().as_ptr(), self.pseudo_type())
} }
/// Get the argument list of a tree pseudo-element.
#[inline]
pub fn tree_pseudo_args(&self) -> Option<<&[Atom]> {
match *self {
% for pseudo in TREE_PSEUDOS:
PseudoElement::${pseudo.capitalized()}(ref args) => Some(args),
% endfor
_ => None,
}
}
/// Construct a pseudo-element from an `Atom`. /// Construct a pseudo-element from an `Atom`.
#[inline] #[inline]
pub fn from_atom(atom: &Atom) -> Option<Self> { pub fn from_atom(atom: &Atom) -> Option<Self> {
@ -177,6 +203,19 @@ impl PseudoElement {
None None
} }
/// Construct a tree pseudo-element from atom and args.
#[inline]
pub fn from_tree_pseudo_atom(atom: &Atom, args: Box<[Atom]>) -> Option<Self> {
% for pseudo in PSEUDOS:
% if pseudo.is_tree_pseudo_element():
if atom == &atom!("${pseudo.value}") {
return Some(PseudoElement::${pseudo.capitalized()}(args));
}
% endif
% endfor
None
}
/// Constructs an atom from a string of text, and whether we're in a /// Constructs an atom from a string of text, and whether we're in a
/// user-agent stylesheet. /// user-agent stylesheet.
/// ///
@ -207,7 +246,7 @@ impl PseudoElement {
/// ///
/// Returns `None` if the pseudo-element is not recognized. /// Returns `None` if the pseudo-element is not recognized.
#[inline] #[inline]
pub fn tree_pseudo_element(name: &str, args: Box<[String]>) -> Option<Self> { pub fn tree_pseudo_element(name: &str, args: Box<[Atom]>) -> Option<Self> {
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
debug_assert!(name.starts_with("-moz-tree-")); debug_assert!(name.starts_with("-moz-tree-"));
let tree_part = &name[10..]; let tree_part = &name[10..];
@ -228,21 +267,20 @@ impl ToCss for PseudoElement {
${pseudo_element_variant(pseudo)} => dest.write_str("${pseudo.value}")?, ${pseudo_element_variant(pseudo)} => dest.write_str("${pseudo.value}")?,
% endfor % endfor
} }
match *self { if let Some(args) = self.tree_pseudo_args() {
${" |\n ".join("PseudoElement::{}(ref args)".format(pseudo.capitalized()) if !args.is_empty() {
for pseudo in TREE_PSEUDOS)} => {
dest.write_char('(')?; dest.write_char('(')?;
let mut iter = args.iter(); let mut iter = args.iter();
if let Some(first) = iter.next() { if let Some(first) = iter.next() {
serialize_identifier(first, dest)?; serialize_identifier(&first.to_string(), dest)?;
for item in iter { for item in iter {
dest.write_str(", ")?; dest.write_str(", ")?;
serialize_identifier(item, dest)?; serialize_identifier(&item.to_string(), dest)?;
} }
} }
dest.write_char(')') dest.write_char(')')?;
} }
_ => Ok(()),
} }
Ok(())
} }
} }

View file

@ -17,7 +17,7 @@ use std::fmt;
use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace}; use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
use style_traits::{ParseError, StyleParseErrorKind}; use style_traits::{ParseError, StyleParseErrorKind};
pub use gecko::pseudo_element::{PseudoElement, EAGER_PSEUDOS, EAGER_PSEUDO_COUNT, SIMPLE_PSEUDO_COUNT}; pub use gecko::pseudo_element::{PseudoElement, EAGER_PSEUDOS, EAGER_PSEUDO_COUNT, PSEUDO_COUNT};
pub use gecko::snapshot::SnapshotMap; pub use gecko::snapshot::SnapshotMap;
bitflags! { bitflags! {
@ -388,6 +388,13 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
fn parse_pseudo_element(&self, location: SourceLocation, name: CowRcStr<'i>) fn parse_pseudo_element(&self, location: SourceLocation, name: CowRcStr<'i>)
-> Result<PseudoElement, ParseError<'i>> { -> Result<PseudoElement, ParseError<'i>> {
PseudoElement::from_slice(&name, self.in_user_agent_stylesheet()) PseudoElement::from_slice(&name, self.in_user_agent_stylesheet())
.or_else(|| {
if name.starts_with("-moz-tree-") {
PseudoElement::tree_pseudo_element(&name, Box::new([]))
} else {
None
}
})
.ok_or(location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name.clone()))) .ok_or(location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name.clone())))
} }
@ -401,7 +408,7 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
loop { loop {
let location = parser.current_source_location(); let location = parser.current_source_location();
match parser.next() { match parser.next() {
Ok(&Token::Ident(ref ident)) => args.push(ident.as_ref().to_owned()), Ok(&Token::Ident(ref ident)) => args.push(Atom::from(ident.as_ref())),
Ok(&Token::Comma) => {}, Ok(&Token::Comma) => {},
Ok(t) => return Err(location.new_unexpected_token_error(t.clone())), Ok(t) => return Err(location.new_unexpected_token_error(t.clone())),
Err(BasicParseError { kind: BasicParseErrorKind::EndOfInput, .. }) => break, Err(BasicParseError { kind: BasicParseErrorKind::EndOfInput, .. }) => break,

View file

@ -102,16 +102,16 @@ pub enum PseudoElementCascadeType {
Precomputed, Precomputed,
} }
/// A per-functional-pseudo map, from a given pseudo to a `T`. /// A per-pseudo map, from a given pseudo to a `T`.
#[derive(MallocSizeOf)] #[derive(MallocSizeOf)]
pub struct PerPseudoElementMap<T> { pub struct PerPseudoElementMap<T> {
entries: [Option<T>; SIMPLE_PSEUDO_COUNT], entries: [Option<T>; PSEUDO_COUNT],
} }
impl<T> Default for PerPseudoElementMap<T> { impl<T> Default for PerPseudoElementMap<T> {
fn default() -> Self { fn default() -> Self {
Self { Self {
entries: PseudoElement::simple_pseudo_none_array(), entries: PseudoElement::pseudo_none_array(),
} }
} }
} }
@ -137,11 +137,7 @@ where
impl<T> PerPseudoElementMap<T> { impl<T> PerPseudoElementMap<T> {
/// Get an entry in the map. /// Get an entry in the map.
pub fn get(&self, pseudo: &PseudoElement) -> Option<&T> { pub fn get(&self, pseudo: &PseudoElement) -> Option<&T> {
let index = match pseudo.simple_index() { self.entries[pseudo.index()].as_ref()
Some(i) => i,
None => return None,
};
self.entries[index].as_ref()
} }
/// Clear this enumerated array. /// Clear this enumerated array.
@ -161,13 +157,8 @@ impl<T> PerPseudoElementMap<T> {
/// Set an entry value. /// Set an entry value.
/// ///
/// Returns an error if the element is not a simple pseudo. /// Returns an error if the element is not a simple pseudo.
pub fn set(&mut self, pseudo: &PseudoElement, value: T) -> Result<(), ()> { pub fn set(&mut self, pseudo: &PseudoElement, value: T) {
let index = match pseudo.simple_index() { self.entries[pseudo.index()] = Some(value);
Some(i) => i,
None => return Err(()),
};
self.entries[index] = Some(value);
Ok(())
} }
/// Get an entry for `pseudo`, or create it with calling `f`. /// Get an entry for `pseudo`, or create it with calling `f`.
@ -175,18 +166,15 @@ impl<T> PerPseudoElementMap<T> {
&mut self, &mut self,
pseudo: &PseudoElement, pseudo: &PseudoElement,
f: F, f: F,
) -> Result<&mut T, ()> ) -> &mut T
where where
F: FnOnce() -> T, F: FnOnce() -> T,
{ {
let index = match pseudo.simple_index() { let index = pseudo.index();
Some(i) => i,
None => return Err(()),
};
if self.entries[index].is_none() { if self.entries[index].is_none() {
self.entries[index] = Some(f()); self.entries[index] = Some(f());
} }
Ok(self.entries[index].as_mut().unwrap()) self.entries[index].as_mut().unwrap()
} }
/// Get an iterator for the entries. /// Get an iterator for the entries.

View file

@ -62,9 +62,8 @@ pub enum PseudoElement {
ServoInlineAbsolute, ServoInlineAbsolute,
} }
/// The count of simple (non-functional) pseudo-elements (that is, all /// The count of all pseudo-elements.
/// pseudo-elements for now). pub const PSEUDO_COUNT: usize = PseudoElement::ServoInlineAbsolute as usize + 1;
pub const SIMPLE_PSEUDO_COUNT: usize = PseudoElement::ServoInlineAbsolute as usize + 1;
impl ::selectors::parser::PseudoElement for PseudoElement { impl ::selectors::parser::PseudoElement for PseudoElement {
type Impl = SelectorImpl; type Impl = SelectorImpl;
@ -110,12 +109,12 @@ impl PseudoElement {
/// An index for this pseudo-element to be indexed in an enumerated array. /// An index for this pseudo-element to be indexed in an enumerated array.
#[inline] #[inline]
pub fn simple_index(&self) -> Option<usize> { pub fn index(&self) -> usize {
Some(self.clone() as usize) self.clone() as usize
} }
/// An array of `None`, one per simple pseudo-element. /// An array of `None`, one per pseudo-element.
pub fn simple_pseudo_none_array<T>() -> [Option<T>; SIMPLE_PSEUDO_COUNT] { pub fn pseudo_none_array<T>() -> [Option<T>; PSEUDO_COUNT] {
Default::default() Default::default()
} }

View file

@ -819,13 +819,21 @@ impl Stylist {
rule_inclusion: RuleInclusion, rule_inclusion: RuleInclusion,
parent_style: &ComputedValues, parent_style: &ComputedValues,
is_probe: bool, is_probe: bool,
font_metrics: &FontMetricsProvider font_metrics: &FontMetricsProvider,
matching_fn: Option<&Fn(&PseudoElement) -> bool>,
) -> Option<Arc<ComputedValues>> ) -> Option<Arc<ComputedValues>>
where where
E: TElement, E: TElement,
{ {
let cascade_inputs = let cascade_inputs =
self.lazy_pseudo_rules(guards, element, pseudo, is_probe, rule_inclusion); self.lazy_pseudo_rules(
guards,
element,
pseudo,
is_probe,
rule_inclusion,
matching_fn
);
self.compute_pseudo_element_style_with_inputs( self.compute_pseudo_element_style_with_inputs(
&cascade_inputs, &cascade_inputs,
pseudo, pseudo,
@ -979,7 +987,8 @@ impl Stylist {
element: &E, element: &E,
pseudo: &PseudoElement, pseudo: &PseudoElement,
is_probe: bool, is_probe: bool,
rule_inclusion: RuleInclusion rule_inclusion: RuleInclusion,
matching_fn: Option<&Fn(&PseudoElement) -> bool>,
) -> CascadeInputs ) -> CascadeInputs
where where
E: TElement E: TElement
@ -1026,6 +1035,7 @@ impl Stylist {
None, None,
self.quirks_mode, self.quirks_mode,
); );
matching_context.pseudo_element_matching_fn = matching_fn;
self.push_applicable_declarations( self.push_applicable_declarations(
element, element,
@ -1062,6 +1072,7 @@ impl Stylist {
VisitedHandlingMode::RelevantLinkVisited, VisitedHandlingMode::RelevantLinkVisited,
self.quirks_mode, self.quirks_mode,
); );
matching_context.pseudo_element_matching_fn = matching_fn;
self.push_applicable_declarations( self.push_applicable_declarations(
element, element,
@ -1289,6 +1300,7 @@ impl Stylist {
context.nth_index_cache.as_mut().map(|s| &mut **s), context.nth_index_cache.as_mut().map(|s| &mut **s),
stylist.quirks_mode, stylist.quirks_mode,
); );
matching_context.pseudo_element_matching_fn = context.pseudo_element_matching_fn;
map.get_all_matching_rules( map.get_all_matching_rules(
element, element,
@ -1994,19 +2006,13 @@ impl CascadeData {
let map = match selector.pseudo_element() { let map = match selector.pseudo_element() {
Some(pseudo) if pseudo.is_precomputed() => { Some(pseudo) if pseudo.is_precomputed() => {
if !selector.is_universal() || debug_assert!(selector.is_universal());
!matches!(origin, Origin::UserAgent) { debug_assert!(matches!(origin, Origin::UserAgent));
// ::-moz-tree selectors may appear in
// non-UA sheets (even though they never
// match).
continue;
}
precomputed_pseudo_element_decls precomputed_pseudo_element_decls
.as_mut() .as_mut()
.expect("Expected precomputed declarations for the UA level") .expect("Expected precomputed declarations for the UA level")
.get_or_insert_with(&pseudo.canonical(), Vec::new) .get_or_insert_with(&pseudo.canonical(), Vec::new)
.expect("Unexpected tree pseudo-element?")
.push(ApplicableDeclarationBlock::new( .push(ApplicableDeclarationBlock::new(
StyleSource::Style(locked.clone()), StyleSource::Style(locked.clone()),
self.rules_source_order, self.rules_source_order,
@ -2023,7 +2029,7 @@ impl CascadeData {
let mut map = Box::new(SelectorMap::new()); let mut map = Box::new(SelectorMap::new());
map.begin_mutation(); map.begin_mutation();
map map
}).expect("Unexpected tree pseudo-element?") })
} }
}; };

View file

@ -84,6 +84,7 @@ use style::gecko_bindings::structs::{RawServoStyleRule, ServoStyleContextStrong,
use style::gecko_bindings::structs::{ServoStyleSheet, SheetParsingMode, nsAtom, nsCSSPropertyID}; use style::gecko_bindings::structs::{ServoStyleSheet, SheetParsingMode, nsAtom, nsCSSPropertyID};
use style::gecko_bindings::structs::{nsCSSFontFaceRule, nsCSSCounterStyleRule}; use style::gecko_bindings::structs::{nsCSSFontFaceRule, nsCSSCounterStyleRule};
use style::gecko_bindings::structs::{nsRestyleHint, nsChangeHint, PropertyValuePair}; use style::gecko_bindings::structs::{nsRestyleHint, nsChangeHint, PropertyValuePair};
use style::gecko_bindings::structs::AtomArray;
use style::gecko_bindings::structs::IterationCompositeOperation; use style::gecko_bindings::structs::IterationCompositeOperation;
use style::gecko_bindings::structs::MallocSizeOf as GeckoMallocSizeOf; use style::gecko_bindings::structs::MallocSizeOf as GeckoMallocSizeOf;
use style::gecko_bindings::structs::OriginFlags; use style::gecko_bindings::structs::OriginFlags;
@ -126,7 +127,7 @@ use style::rule_cache::RuleCacheConditions;
use style::rule_tree::{CascadeLevel, StrongRuleNode, StyleSource}; use style::rule_tree::{CascadeLevel, StrongRuleNode, StyleSource};
use style::selector_parser::{PseudoElementCascadeType, SelectorImpl}; use style::selector_parser::{PseudoElementCascadeType, SelectorImpl};
use style::shared_lock::{SharedRwLockReadGuard, StylesheetGuards, ToCssWithGuard, Locked}; use style::shared_lock::{SharedRwLockReadGuard, StylesheetGuards, ToCssWithGuard, Locked};
use style::string_cache::Atom; use style::string_cache::{Atom, WeakAtom};
use style::style_adjuster::StyleAdjuster; use style::style_adjuster::StyleAdjuster;
use style::stylesheets::{CssRule, CssRules, CssRuleType, CssRulesHelpers, DocumentRule}; use style::stylesheets::{CssRule, CssRules, CssRuleType, CssRulesHelpers, DocumentRule};
use style::stylesheets::{FontFeatureValuesRule, ImportRule, KeyframesRule, MediaRule}; use style::stylesheets::{FontFeatureValuesRule, ImportRule, KeyframesRule, MediaRule};
@ -1911,6 +1912,7 @@ pub extern "C" fn Servo_ResolvePseudoStyle(element: RawGeckoElementBorrowed,
inherited_style, inherited_style,
&*doc_data, &*doc_data,
is_probe, is_probe,
/* matching_func = */ None,
); );
match style { match style {
@ -1922,6 +1924,66 @@ pub extern "C" fn Servo_ResolvePseudoStyle(element: RawGeckoElementBorrowed,
} }
} }
fn debug_atom_array(atoms: &AtomArray) -> String {
let mut result = String::from("[");
for atom in atoms.iter() {
if atom.mRawPtr.is_null() {
result += "(null), ";
} else {
let atom = unsafe { WeakAtom::new(atom.mRawPtr) };
write!(result, "{}, ", atom).unwrap();
}
}
result.push(']');
result
}
#[no_mangle]
pub extern "C" fn Servo_ComputedValues_ResolveXULTreePseudoStyle(
element: RawGeckoElementBorrowed,
pseudo_tag: *mut nsAtom,
inherited_style: ServoStyleContextBorrowed,
input_word: *const AtomArray,
raw_data: RawServoStyleSetBorrowed
) -> ServoStyleContextStrong {
let element = GeckoElement(element);
let data = element.borrow_data()
.expect("Calling ResolveXULTreePseudoStyle on unstyled element?");
let pseudo = unsafe {
Atom::with(pseudo_tag, |atom| {
PseudoElement::from_tree_pseudo_atom(atom, Box::new([]))
}).expect("ResolveXULTreePseudoStyle with a non-tree pseudo?")
};
let input_word = unsafe { input_word.as_ref().unwrap() };
let doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow();
debug!("ResolveXULTreePseudoStyle: {:?} {:?} {}",
element, pseudo, debug_atom_array(input_word));
let matching_fn = |pseudo: &PseudoElement| {
let args = pseudo.tree_pseudo_args().expect("Not a tree pseudo-element?");
args.iter().all(|atom| {
input_word.iter().any(|item| atom.as_ptr() == item.mRawPtr)
})
};
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
get_pseudo_style(
&guard,
element,
&pseudo,
RuleInclusion::All,
&data.styles,
Some(inherited_style),
&*doc_data,
/* is_probe = */ false,
Some(&matching_fn),
).unwrap().into()
}
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_SetExplicitStyle(element: RawGeckoElementBorrowed, pub extern "C" fn Servo_SetExplicitStyle(element: RawGeckoElementBorrowed,
style: ServoStyleContextBorrowed) style: ServoStyleContextBorrowed)
@ -1965,6 +2027,7 @@ fn get_pseudo_style(
inherited_styles: Option<&ComputedValues>, inherited_styles: Option<&ComputedValues>,
doc_data: &PerDocumentStyleDataImpl, doc_data: &PerDocumentStyleDataImpl,
is_probe: bool, is_probe: bool,
matching_func: Option<&Fn(&PseudoElement) -> bool>,
) -> Option<Arc<ComputedValues>> { ) -> Option<Arc<ComputedValues>> {
let style = match pseudo.cascade_type() { let style = match pseudo.cascade_type() {
PseudoElementCascadeType::Eager => { PseudoElementCascadeType::Eager => {
@ -2038,6 +2101,7 @@ fn get_pseudo_style(
base, base,
is_probe, is_probe,
&metrics, &metrics,
matching_func,
) )
}, },
}; };
@ -3269,6 +3333,7 @@ pub extern "C" fn Servo_ResolveStyleLazily(
/* inherited_styles = */ None, /* inherited_styles = */ None,
&*data, &*data,
is_probe, is_probe,
/* matching_func = */ None,
) )
} }
None => Some(styles.primary().clone()), None => Some(styles.primary().clone()),