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

@ -15,6 +15,7 @@ use gecko_bindings::structs::mozilla::css::ImageValue;
use gecko_bindings::structs::mozilla::css::URLValue;
use gecko_bindings::structs::mozilla::css::URLValueData;
use gecko_bindings::structs::mozilla::AnonymousCounterStyle;
use gecko_bindings::structs::mozilla::AtomArray;
use gecko_bindings::structs::mozilla::MallocSizeOf;
use gecko_bindings::structs::mozilla::OriginFlags;
use gecko_bindings::structs::mozilla::UniquePtr;
@ -2945,6 +2946,19 @@ extern "C" {
set: RawServoStyleSetBorrowed)
-> 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" {
pub fn Servo_SetExplicitStyle(element: RawGeckoElementBorrowed,
primary_style: ServoStyleContextBorrowed);

View file

@ -140,29 +140,29 @@ pub enum PseudoElement {
/// :-moz-ruby-text-container
RubyTextContainer,
/// :-moz-tree-column
MozTreeColumn(Box<[String]>),
MozTreeColumn(Box<[Atom]>),
/// :-moz-tree-row
MozTreeRow(Box<[String]>),
MozTreeRow(Box<[Atom]>),
/// :-moz-tree-separator
MozTreeSeparator(Box<[String]>),
MozTreeSeparator(Box<[Atom]>),
/// :-moz-tree-cell
MozTreeCell(Box<[String]>),
MozTreeCell(Box<[Atom]>),
/// :-moz-tree-indentation
MozTreeIndentation(Box<[String]>),
MozTreeIndentation(Box<[Atom]>),
/// :-moz-tree-line
MozTreeLine(Box<[String]>),
MozTreeLine(Box<[Atom]>),
/// :-moz-tree-twisty
MozTreeTwisty(Box<[String]>),
MozTreeTwisty(Box<[Atom]>),
/// :-moz-tree-image
MozTreeImage(Box<[String]>),
MozTreeImage(Box<[Atom]>),
/// :-moz-tree-cell-text
MozTreeCellText(Box<[String]>),
MozTreeCellText(Box<[Atom]>),
/// :-moz-tree-checkbox
MozTreeCheckbox(Box<[String]>),
MozTreeCheckbox(Box<[Atom]>),
/// :-moz-tree-progressmeter
MozTreeProgressmeter(Box<[String]>),
MozTreeProgressmeter(Box<[Atom]>),
/// :-moz-tree-drop-feedback
MozTreeDropFeedback(Box<[String]>),
MozTreeDropFeedback(Box<[Atom]>),
/// :-moz-svg-marker-anon-child
MozSVGMarkerAnonChild,
/// :-moz-svg-outer-svg-anon-child
@ -185,6 +185,12 @@ pub const EAGER_PSEUDO_COUNT: usize = 4;
/// The number of non-functional pseudo-elements.
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.
pub const EAGER_PSEUDOS: [PseudoElement; EAGER_PSEUDO_COUNT] = [
PseudoElement::Before,
@ -286,162 +292,184 @@ impl PseudoElement {
}
}
/// Returns an index if the pseudo-element is a simple (non-functional)
/// pseudo.
/// Returns an index of the pseudo-element.
#[inline]
pub fn simple_index(&self) -> Option<usize> {
pub fn index(&self) -> usize {
match *self {
PseudoElement::After => Some(0),
PseudoElement::Before => Some(1),
PseudoElement::Backdrop => Some(2),
PseudoElement::Cue => Some(3),
PseudoElement::FirstLetter => Some(4),
PseudoElement::FirstLine => Some(5),
PseudoElement::MozSelection => Some(6),
PseudoElement::MozFocusInner => Some(7),
PseudoElement::MozFocusOuter => Some(8),
PseudoElement::MozListBullet => Some(9),
PseudoElement::MozListNumber => Some(10),
PseudoElement::MozMathAnonymous => Some(11),
PseudoElement::MozNumberWrapper => Some(12),
PseudoElement::MozNumberText => Some(13),
PseudoElement::MozNumberSpinBox => Some(14),
PseudoElement::MozNumberSpinUp => Some(15),
PseudoElement::MozNumberSpinDown => Some(16),
PseudoElement::MozProgressBar => Some(17),
PseudoElement::MozRangeTrack => Some(18),
PseudoElement::MozRangeProgress => Some(19),
PseudoElement::MozRangeThumb => Some(20),
PseudoElement::MozMeterBar => Some(21),
PseudoElement::MozPlaceholder => Some(22),
PseudoElement::Placeholder => Some(23),
PseudoElement::MozColorSwatch => Some(24),
PseudoElement::MozText => Some(25),
PseudoElement::OofPlaceholder => Some(26),
PseudoElement::FirstLetterContinuation => Some(27),
PseudoElement::MozBlockInsideInlineWrapper => Some(28),
PseudoElement::MozMathMLAnonymousBlock => Some(29),
PseudoElement::MozXULAnonymousBlock => Some(30),
PseudoElement::HorizontalFramesetBorder => Some(31),
PseudoElement::VerticalFramesetBorder => Some(32),
PseudoElement::MozLineFrame => Some(33),
PseudoElement::ButtonContent => Some(34),
PseudoElement::CellContent => Some(35),
PseudoElement::DropDownList => Some(36),
PseudoElement::FieldsetContent => Some(37),
PseudoElement::FramesetBlank => Some(38),
PseudoElement::MozDisplayComboboxControlFrame => Some(39),
PseudoElement::HtmlCanvasContent => Some(40),
PseudoElement::InlineTable => Some(41),
PseudoElement::Table => Some(42),
PseudoElement::TableCell => Some(43),
PseudoElement::TableColGroup => Some(44),
PseudoElement::TableCol => Some(45),
PseudoElement::TableWrapper => Some(46),
PseudoElement::TableRowGroup => Some(47),
PseudoElement::TableRow => Some(48),
PseudoElement::Canvas => Some(49),
PseudoElement::PageBreak => Some(50),
PseudoElement::Page => Some(51),
PseudoElement::PageContent => Some(52),
PseudoElement::PageSequence => Some(53),
PseudoElement::ScrolledContent => Some(54),
PseudoElement::ScrolledCanvas => Some(55),
PseudoElement::ScrolledPageSequence => Some(56),
PseudoElement::ColumnContent => Some(57),
PseudoElement::Viewport => Some(58),
PseudoElement::ViewportScroll => Some(59),
PseudoElement::AnonymousFlexItem => Some(60),
PseudoElement::AnonymousGridItem => Some(61),
PseudoElement::Ruby => Some(62),
PseudoElement::RubyBase => Some(63),
PseudoElement::RubyBaseContainer => Some(64),
PseudoElement::RubyText => Some(65),
PseudoElement::RubyTextContainer => Some(66),
PseudoElement::MozSVGMarkerAnonChild => Some(67),
PseudoElement::MozSVGOuterSVGAnonChild => Some(68),
PseudoElement::MozSVGForeignContent => Some(69),
PseudoElement::MozSVGText => Some(70),
_ => None,
PseudoElement::After => 0,
PseudoElement::Before => 1,
PseudoElement::Backdrop => 2,
PseudoElement::Cue => 3,
PseudoElement::FirstLetter => 4,
PseudoElement::FirstLine => 5,
PseudoElement::MozSelection => 6,
PseudoElement::MozFocusInner => 7,
PseudoElement::MozFocusOuter => 8,
PseudoElement::MozListBullet => 9,
PseudoElement::MozListNumber => 10,
PseudoElement::MozMathAnonymous => 11,
PseudoElement::MozNumberWrapper => 12,
PseudoElement::MozNumberText => 13,
PseudoElement::MozNumberSpinBox => 14,
PseudoElement::MozNumberSpinUp => 15,
PseudoElement::MozNumberSpinDown => 16,
PseudoElement::MozProgressBar => 17,
PseudoElement::MozRangeTrack => 18,
PseudoElement::MozRangeProgress => 19,
PseudoElement::MozRangeThumb => 20,
PseudoElement::MozMeterBar => 21,
PseudoElement::MozPlaceholder => 22,
PseudoElement::Placeholder => 23,
PseudoElement::MozColorSwatch => 24,
PseudoElement::MozText => 25,
PseudoElement::OofPlaceholder => 26,
PseudoElement::FirstLetterContinuation => 27,
PseudoElement::MozBlockInsideInlineWrapper => 28,
PseudoElement::MozMathMLAnonymousBlock => 29,
PseudoElement::MozXULAnonymousBlock => 30,
PseudoElement::HorizontalFramesetBorder => 31,
PseudoElement::VerticalFramesetBorder => 32,
PseudoElement::MozLineFrame => 33,
PseudoElement::ButtonContent => 34,
PseudoElement::CellContent => 35,
PseudoElement::DropDownList => 36,
PseudoElement::FieldsetContent => 37,
PseudoElement::FramesetBlank => 38,
PseudoElement::MozDisplayComboboxControlFrame => 39,
PseudoElement::HtmlCanvasContent => 40,
PseudoElement::InlineTable => 41,
PseudoElement::Table => 42,
PseudoElement::TableCell => 43,
PseudoElement::TableColGroup => 44,
PseudoElement::TableCol => 45,
PseudoElement::TableWrapper => 46,
PseudoElement::TableRowGroup => 47,
PseudoElement::TableRow => 48,
PseudoElement::Canvas => 49,
PseudoElement::PageBreak => 50,
PseudoElement::Page => 51,
PseudoElement::PageContent => 52,
PseudoElement::PageSequence => 53,
PseudoElement::ScrolledContent => 54,
PseudoElement::ScrolledCanvas => 55,
PseudoElement::ScrolledPageSequence => 56,
PseudoElement::ColumnContent => 57,
PseudoElement::Viewport => 58,
PseudoElement::ViewportScroll => 59,
PseudoElement::AnonymousFlexItem => 60,
PseudoElement::AnonymousGridItem => 61,
PseudoElement::Ruby => 62,
PseudoElement::RubyBase => 63,
PseudoElement::RubyBaseContainer => 64,
PseudoElement::RubyText => 65,
PseudoElement::RubyTextContainer => 66,
PseudoElement::MozTreeColumn(..) => 67,
PseudoElement::MozTreeRow(..) => 68,
PseudoElement::MozTreeSeparator(..) => 69,
PseudoElement::MozTreeCell(..) => 70,
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.
///
/// 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
]
}
@ -518,6 +546,26 @@ None
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
/// anonymous box.
pub fn flags(&self) -> u32 {
@ -847,18 +895,18 @@ None
PseudoElement::RubyBaseContainer => CSSPseudoElementType_InheritingAnonBox,
PseudoElement::RubyText => CSSPseudoElementType_InheritingAnonBox,
PseudoElement::RubyTextContainer => CSSPseudoElementType_InheritingAnonBox,
PseudoElement::MozTreeColumn(..) => CSSPseudoElementType_InheritingAnonBox,
PseudoElement::MozTreeRow(..) => CSSPseudoElementType_InheritingAnonBox,
PseudoElement::MozTreeSeparator(..) => CSSPseudoElementType_InheritingAnonBox,
PseudoElement::MozTreeCell(..) => CSSPseudoElementType_InheritingAnonBox,
PseudoElement::MozTreeIndentation(..) => CSSPseudoElementType_InheritingAnonBox,
PseudoElement::MozTreeLine(..) => CSSPseudoElementType_InheritingAnonBox,
PseudoElement::MozTreeTwisty(..) => CSSPseudoElementType_InheritingAnonBox,
PseudoElement::MozTreeImage(..) => CSSPseudoElementType_InheritingAnonBox,
PseudoElement::MozTreeCellText(..) => CSSPseudoElementType_InheritingAnonBox,
PseudoElement::MozTreeCheckbox(..) => CSSPseudoElementType_InheritingAnonBox,
PseudoElement::MozTreeProgressmeter(..) => CSSPseudoElementType_InheritingAnonBox,
PseudoElement::MozTreeDropFeedback(..) => CSSPseudoElementType_InheritingAnonBox,
PseudoElement::MozTreeColumn(..) => CSSPseudoElementType::XULTree,
PseudoElement::MozTreeRow(..) => CSSPseudoElementType::XULTree,
PseudoElement::MozTreeSeparator(..) => CSSPseudoElementType::XULTree,
PseudoElement::MozTreeCell(..) => CSSPseudoElementType::XULTree,
PseudoElement::MozTreeIndentation(..) => CSSPseudoElementType::XULTree,
PseudoElement::MozTreeLine(..) => CSSPseudoElementType::XULTree,
PseudoElement::MozTreeTwisty(..) => CSSPseudoElementType::XULTree,
PseudoElement::MozTreeImage(..) => CSSPseudoElementType::XULTree,
PseudoElement::MozTreeCellText(..) => CSSPseudoElementType::XULTree,
PseudoElement::MozTreeCheckbox(..) => CSSPseudoElementType::XULTree,
PseudoElement::MozTreeProgressmeter(..) => CSSPseudoElementType::XULTree,
PseudoElement::MozTreeDropFeedback(..) => CSSPseudoElementType::XULTree,
PseudoElement::MozSVGMarkerAnonChild => CSSPseudoElementType_InheritingAnonBox,
PseudoElement::MozSVGOuterSVGAnonChild => CSSPseudoElementType_InheritingAnonBox,
PseudoElement::MozSVGForeignContent => CSSPseudoElementType_InheritingAnonBox,
@ -871,6 +919,26 @@ None
(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`.
#[inline]
pub fn from_atom(atom: &Atom) -> Option<Self> {
@ -1258,6 +1326,48 @@ 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
/// user-agent stylesheet.
///
@ -1636,7 +1746,7 @@ None
///
/// Returns `None` if the pseudo-element is not recognized.
#[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;
debug_assert!(name.starts_with("-moz-tree-"));
let tree_part = &name[10..];
@ -1768,31 +1878,20 @@ impl ToCss for PseudoElement {
PseudoElement::MozSVGForeignContent => dest.write_str(":-moz-svg-foreign-content")?,
PseudoElement::MozSVGText => dest.write_str(":-moz-svg-text")?,
}
match *self {
PseudoElement::MozTreeColumn(ref args) |
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) => {
if let Some(args) = self.tree_pseudo_args() {
if !args.is_empty() {
dest.write_char('(')?;
let mut iter = args.iter();
if let Some(first) = iter.next() {
serialize_identifier(first, dest)?;
serialize_identifier(&first.to_string(), dest)?;
for item in iter {
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 {
_unused: [u8; 0],
}
pub type AtomArray = root::nsTArray<root::RefPtr<root::nsAtom>>;
/// EventStates is the class used to represent the event states of nsIContent
/// instances. These states are calculated by IntrinsicState() and
/// ContentStatesChanged() has to be called when one of them changes thus
@ -22385,8 +22386,6 @@ pub mod root {
pub struct nsAttrValue {
pub mBits: usize,
}
pub type nsAttrValue_AtomArray =
root::nsTArray<root::RefPtr<root::nsAtom>>;
pub const nsAttrValue_ValueType_eSVGTypesBegin:
root::nsAttrValue_ValueType =
nsAttrValue_ValueType::eSVGAngle;

View file

@ -46,7 +46,7 @@ impl PseudoElement {
return PseudoElementCascadeType::Eager
}
if self.is_anon_box() {
if self.is_precomputed() {
return PseudoElementCascadeType::Precomputed
}
@ -137,7 +137,7 @@ impl PseudoElement {
/// Whether this pseudo-element is precomputed.
#[inline]
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

View file

@ -8,7 +8,7 @@ pub enum PseudoElement {
% for pseudo in PSEUDOS:
/// ${pseudo.value}
% if pseudo.is_tree_pseudo_element():
${pseudo.capitalized()}(Box<[String]>),
${pseudo.capitalized()}(Box<[Atom]>),
% else:
${pseudo.capitalized()},
% endif
@ -27,6 +27,12 @@ pub const EAGER_PSEUDO_COUNT: usize = ${len(EAGER_PSEUDOS)};
/// The number of non-functional pseudo-elements.
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.
pub const EAGER_PSEUDOS: [PseudoElement; EAGER_PSEUDO_COUNT] = [
% 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)
/// pseudo.
/// Returns an index of the pseudo-element.
#[inline]
pub fn simple_index(&self) -> Option<usize> {
pub fn index(&self) -> usize {
match *self {
% for i, pseudo in enumerate(SIMPLE_PSEUDOS):
${pseudo_element_variant(pseudo)} => Some(${i}),
% for i, pseudo in enumerate(PSEUDOS):
${pseudo_element_variant(pseudo)} => ${i},
% endfor
_ => None,
}
}
/// Returns an array of `None` values.
///
/// 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))})
}
/// 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
/// anonymous box.
pub fn flags(&self) -> u32 {
@ -132,7 +147,7 @@ impl PseudoElement {
% if not pseudo.is_anon_box():
PseudoElement::${pseudo.capitalized()} => CSSPseudoElementType::${pseudo.original_ident},
% elif pseudo.is_tree_pseudo_element():
PseudoElement::${pseudo.capitalized()}(..) => CSSPseudoElementType_InheritingAnonBox,
PseudoElement::${pseudo.capitalized()}(..) => CSSPseudoElementType::XULTree,
% elif pseudo.is_inheriting_anon_box():
PseudoElement::${pseudo.capitalized()} => CSSPseudoElementType_InheritingAnonBox,
% else:
@ -147,6 +162,17 @@ impl PseudoElement {
(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`.
#[inline]
pub fn from_atom(atom: &Atom) -> Option<Self> {
@ -177,6 +203,19 @@ impl PseudoElement {
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
/// user-agent stylesheet.
///
@ -207,7 +246,7 @@ impl PseudoElement {
///
/// Returns `None` if the pseudo-element is not recognized.
#[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;
debug_assert!(name.starts_with("-moz-tree-"));
let tree_part = &name[10..];
@ -228,21 +267,20 @@ impl ToCss for PseudoElement {
${pseudo_element_variant(pseudo)} => dest.write_str("${pseudo.value}")?,
% endfor
}
match *self {
${" |\n ".join("PseudoElement::{}(ref args)".format(pseudo.capitalized())
for pseudo in TREE_PSEUDOS)} => {
if let Some(args) = self.tree_pseudo_args() {
if !args.is_empty() {
dest.write_char('(')?;
let mut iter = args.iter();
if let Some(first) = iter.next() {
serialize_identifier(first, dest)?;
serialize_identifier(&first.to_string(), dest)?;
for item in iter {
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 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;
bitflags! {
@ -388,6 +388,13 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
fn parse_pseudo_element(&self, location: SourceLocation, name: CowRcStr<'i>)
-> Result<PseudoElement, ParseError<'i>> {
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())))
}
@ -401,7 +408,7 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
loop {
let location = parser.current_source_location();
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(t) => return Err(location.new_unexpected_token_error(t.clone())),
Err(BasicParseError { kind: BasicParseErrorKind::EndOfInput, .. }) => break,

View file

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

View file

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

View file

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