style: Shrink selectors::Component to 24 bytes.

This saves about 37 KiB of memory across the UA style sheets.

Bug: 1475197
Reviewed-by: emilio
This commit is contained in:
Cameron McCormack 2018-07-16 12:15:47 +10:00 committed by Emilio Cobos Álvarez
parent b05ace3e4a
commit 62419adaaa
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
12 changed files with 96 additions and 50 deletions

View file

@ -37,6 +37,7 @@ servo_arc = { path = "../servo_arc" }
smallbitvec = "2.1.0" smallbitvec = "2.1.0"
smallvec = "0.6" smallvec = "0.6"
string_cache = { version = "0.7", optional = true } string_cache = { version = "0.7", optional = true }
thin-slice = "0.1.0"
time = { version = "0.1.17", optional = true } time = { version = "0.1.17", optional = true }
url = { version = "1.2", optional = true } url = { version = "1.2", optional = true }
webrender_api = { git = "https://github.com/servo/webrender", features = ["ipc"], optional = true } webrender_api = { git = "https://github.com/servo/webrender", features = ["ipc"], optional = true }

View file

@ -63,6 +63,7 @@ extern crate smallbitvec;
extern crate smallvec; extern crate smallvec;
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
extern crate string_cache; extern crate string_cache;
extern crate thin_slice;
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
extern crate time; extern crate time;
#[cfg(feature = "url")] #[cfg(feature = "url")]
@ -231,6 +232,24 @@ impl<T: MallocSizeOf + ?Sized> MallocSizeOf for Box<T> {
} }
} }
impl<T> MallocShallowSizeOf for thin_slice::ThinBoxedSlice<T> {
fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
let mut n = 0;
unsafe {
n += thin_slice::ThinBoxedSlice::spilled_storage(self)
.map_or(0, |ptr| ops.malloc_size_of(ptr));
n += ops.malloc_size_of(&**self);
}
n
}
}
impl<T: MallocSizeOf> MallocSizeOf for thin_slice::ThinBoxedSlice<T> {
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
self.shallow_size_of(ops) + (**self).size_of(ops)
}
}
impl MallocSizeOf for () { impl MallocSizeOf for () {
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize { fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
0 0
@ -770,7 +789,7 @@ where
} }
impl<Impl: selectors::parser::SelectorImpl> MallocSizeOf impl<Impl: selectors::parser::SelectorImpl> MallocSizeOf
for selectors::attr::AttrSelectorWithNamespace<Impl> for selectors::attr::AttrSelectorWithOptionalNamespace<Impl>
{ {
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize { fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
0 0

View file

@ -30,6 +30,7 @@ phf = "0.7.18"
precomputed-hash = "0.1" precomputed-hash = "0.1"
servo_arc = { version = "0.1", path = "../servo_arc" } servo_arc = { version = "0.1", path = "../servo_arc" }
smallvec = "0.6.2" smallvec = "0.6.2"
thin-slice = "0.1.0"
[build-dependencies] [build-dependencies]
phf_codegen = "0.7.18" phf_codegen = "0.7.18"

View file

@ -7,20 +7,20 @@ use parser::SelectorImpl;
use std::fmt; use std::fmt;
#[derive(Clone, Eq, PartialEq)] #[derive(Clone, Eq, PartialEq)]
pub struct AttrSelectorWithNamespace<Impl: SelectorImpl> { pub struct AttrSelectorWithOptionalNamespace<Impl: SelectorImpl> {
pub namespace: NamespaceConstraint<(Impl::NamespacePrefix, Impl::NamespaceUrl)>, pub namespace: Option<NamespaceConstraint<(Impl::NamespacePrefix, Impl::NamespaceUrl)>>,
pub local_name: Impl::LocalName, pub local_name: Impl::LocalName,
pub local_name_lower: Impl::LocalName, pub local_name_lower: Impl::LocalName,
pub operation: ParsedAttrSelectorOperation<Impl::AttrValue>, pub operation: ParsedAttrSelectorOperation<Impl::AttrValue>,
pub never_matches: bool, pub never_matches: bool,
} }
impl<Impl: SelectorImpl> AttrSelectorWithNamespace<Impl> { impl<Impl: SelectorImpl> AttrSelectorWithOptionalNamespace<Impl> {
pub fn namespace(&self) -> NamespaceConstraint<&Impl::NamespaceUrl> { pub fn namespace(&self) -> Option<NamespaceConstraint<&Impl::NamespaceUrl>> {
match self.namespace { self.namespace.as_ref().map(|ns| match ns {
NamespaceConstraint::Any => NamespaceConstraint::Any, NamespaceConstraint::Any => NamespaceConstraint::Any,
NamespaceConstraint::Specific((_, ref url)) => NamespaceConstraint::Specific(url), NamespaceConstraint::Specific((_, ref url)) => NamespaceConstraint::Specific(url),
} })
} }
} }

View file

@ -19,6 +19,7 @@ extern crate phf;
extern crate precomputed_hash; extern crate precomputed_hash;
extern crate servo_arc; extern crate servo_arc;
extern crate smallvec; extern crate smallvec;
extern crate thin_slice;
pub mod attr; pub mod attr;
pub mod bloom; pub mod bloom;

View file

@ -699,7 +699,6 @@ where
}, },
Component::AttributeInNoNamespace { Component::AttributeInNoNamespace {
ref local_name, ref local_name,
ref local_name_lower,
ref value, ref value,
operator, operator,
case_sensitivity, case_sensitivity,
@ -711,7 +710,7 @@ where
let is_html = element.is_html_element_in_html_document(); let is_html = element.is_html_element_in_html_document();
element.attr_matches( element.attr_matches(
&NamespaceConstraint::Specific(&::parser::namespace_empty_string::<E::Impl>()), &NamespaceConstraint::Specific(&::parser::namespace_empty_string::<E::Impl>()),
select_name(is_html, local_name, local_name_lower), local_name,
&AttrSelectorOperation::WithValue { &AttrSelectorOperation::WithValue {
operator: operator, operator: operator,
case_sensitivity: case_sensitivity.to_unconditional(is_html), case_sensitivity: case_sensitivity.to_unconditional(is_html),
@ -724,8 +723,16 @@ where
return false; return false;
} }
let is_html = element.is_html_element_in_html_document(); let is_html = element.is_html_element_in_html_document();
let empty_string;
let namespace = match attr_sel.namespace() {
Some(ns) => ns,
None => {
empty_string = ::parser::namespace_empty_string::<E::Impl>();
NamespaceConstraint::Specific(&empty_string)
}
};
element.attr_matches( element.attr_matches(
&attr_sel.namespace(), &namespace,
select_name(is_html, &attr_sel.local_name, &attr_sel.local_name_lower), select_name(is_html, &attr_sel.local_name, &attr_sel.local_name_lower),
&match attr_sel.operation { &match attr_sel.operation {
ParsedAttrSelectorOperation::Exists => AttrSelectorOperation::Exists, ParsedAttrSelectorOperation::Exists => AttrSelectorOperation::Exists,

View file

@ -2,8 +2,9 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use attr::{AttrSelectorOperator, AttrSelectorWithNamespace, ParsedAttrSelectorOperation}; use attr::{AttrSelectorOperator, AttrSelectorWithOptionalNamespace};
use attr::{NamespaceConstraint, ParsedCaseSensitivity, SELECTOR_WHITESPACE}; use attr::{NamespaceConstraint, ParsedAttrSelectorOperation};
use attr::{ParsedCaseSensitivity, SELECTOR_WHITESPACE};
use bloom::BLOOM_HASH_MASK; use bloom::BLOOM_HASH_MASK;
use builder::{SelectorBuilder, SpecificityAndFlags}; use builder::{SelectorBuilder, SpecificityAndFlags};
use context::QuirksMode; use context::QuirksMode;
@ -19,6 +20,7 @@ use std::borrow::{Borrow, Cow};
use std::fmt::{self, Debug, Display, Write}; use std::fmt::{self, Debug, Display, Write};
use std::iter::Rev; use std::iter::Rev;
use std::slice; use std::slice;
use thin_slice::ThinBoxedSlice;
pub use visitor::{SelectorVisitor, Visit}; pub use visitor::{SelectorVisitor, Visit};
/// A trait that represents a pseudo-element. /// A trait that represents a pseudo-element.
@ -45,6 +47,8 @@ pub trait NonTSPseudoClass: Sized + ToCss {
fn is_active_or_hover(&self) -> bool; fn is_active_or_hover(&self) -> bool;
} }
/// Returns a Cow::Borrowed if `s` is already ASCII lowercase, and a
/// Cow::Owned if `s` had to be converted into ASCII lowercase.
fn to_ascii_lowercase(s: &str) -> Cow<str> { fn to_ascii_lowercase(s: &str) -> Cow<str> {
if let Some(first_uppercase) = s.bytes().position(|byte| byte >= b'A' && byte <= b'Z') { if let Some(first_uppercase) = s.bytes().position(|byte| byte >= b'A' && byte <= b'Z') {
let mut string = s.to_owned(); let mut string = s.to_owned();
@ -428,7 +432,6 @@ where
}, },
AttributeInNoNamespace { AttributeInNoNamespace {
ref local_name, ref local_name,
ref local_name_lower,
never_matches, never_matches,
.. ..
} if !never_matches => } if !never_matches =>
@ -436,14 +439,22 @@ where
if !visitor.visit_attribute_selector( if !visitor.visit_attribute_selector(
&NamespaceConstraint::Specific(&namespace_empty_string::<Impl>()), &NamespaceConstraint::Specific(&namespace_empty_string::<Impl>()),
local_name, local_name,
local_name_lower, local_name,
) { ) {
return false; return false;
} }
}, },
AttributeOther(ref attr_selector) if !attr_selector.never_matches => { AttributeOther(ref attr_selector) if !attr_selector.never_matches => {
let empty_string;
let namespace = match attr_selector.namespace() {
Some(ns) => ns,
None => {
empty_string = ::parser::namespace_empty_string::<Impl>();
NamespaceConstraint::Specific(&empty_string)
}
};
if !visitor.visit_attribute_selector( if !visitor.visit_attribute_selector(
&attr_selector.namespace(), &namespace,
&attr_selector.local_name, &attr_selector.local_name,
&attr_selector.local_name_lower, &attr_selector.local_name_lower,
) { ) {
@ -815,16 +826,16 @@ pub enum Component<Impl: SelectorImpl> {
local_name: Impl::LocalName, local_name: Impl::LocalName,
local_name_lower: Impl::LocalName, local_name_lower: Impl::LocalName,
}, },
// Used only when local_name is already lowercase.
AttributeInNoNamespace { AttributeInNoNamespace {
local_name: Impl::LocalName, local_name: Impl::LocalName,
local_name_lower: Impl::LocalName,
operator: AttrSelectorOperator, operator: AttrSelectorOperator,
value: Impl::AttrValue, value: Impl::AttrValue,
case_sensitivity: ParsedCaseSensitivity, case_sensitivity: ParsedCaseSensitivity,
never_matches: bool, never_matches: bool,
}, },
// Use a Box in the less common cases with more data to keep size_of::<Component>() small. // Use a Box in the less common cases with more data to keep size_of::<Component>() small.
AttributeOther(Box<AttrSelectorWithNamespace<Impl>>), AttributeOther(Box<AttrSelectorWithOptionalNamespace<Impl>>),
/// Pseudo-classes /// Pseudo-classes
/// ///
@ -836,7 +847,7 @@ pub enum Component<Impl: SelectorImpl> {
/// need to think about how this should interact with /// need to think about how this should interact with
/// visit_complex_selector, and what the consumers of those APIs should do /// visit_complex_selector, and what the consumers of those APIs should do
/// about the presence of combinators in negation. /// about the presence of combinators in negation.
Negation(Box<[Component<Impl>]>), Negation(ThinBoxedSlice<Component<Impl>>),
FirstChild, FirstChild,
LastChild, LastChild,
OnlyChild, OnlyChild,
@ -948,7 +959,7 @@ impl<Impl: SelectorImpl> Debug for Component<Impl> {
self.to_css(f) self.to_css(f)
} }
} }
impl<Impl: SelectorImpl> Debug for AttrSelectorWithNamespace<Impl> { impl<Impl: SelectorImpl> Debug for AttrSelectorWithOptionalNamespace<Impl> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.to_css(f) self.to_css(f)
} }
@ -1238,18 +1249,19 @@ impl<Impl: SelectorImpl> ToCss for Component<Impl> {
} }
} }
impl<Impl: SelectorImpl> ToCss for AttrSelectorWithNamespace<Impl> { impl<Impl: SelectorImpl> ToCss for AttrSelectorWithOptionalNamespace<Impl> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result fn to_css<W>(&self, dest: &mut W) -> fmt::Result
where where
W: fmt::Write, W: fmt::Write,
{ {
dest.write_char('[')?; dest.write_char('[')?;
match self.namespace { match self.namespace {
NamespaceConstraint::Specific((ref prefix, _)) => { Some(NamespaceConstraint::Specific((ref prefix, _))) => {
display_to_css_identifier(prefix, dest)?; display_to_css_identifier(prefix, dest)?;
dest.write_char('|')? dest.write_char('|')?
}, },
NamespaceConstraint::Any => dest.write_str("*|")?, Some(NamespaceConstraint::Any) => dest.write_str("*|")?,
None => {}
} }
display_to_css_identifier(&self.local_name, dest)?; display_to_css_identifier(&self.local_name, dest)?;
match self.operation { match self.operation {
@ -1628,8 +1640,8 @@ where
let local_name = local_name.as_ref().into(); let local_name = local_name.as_ref().into();
if let Some(namespace) = namespace { if let Some(namespace) = namespace {
return Ok(Component::AttributeOther(Box::new( return Ok(Component::AttributeOther(Box::new(
AttrSelectorWithNamespace { AttrSelectorWithOptionalNamespace {
namespace: namespace, namespace: Some(namespace),
local_name: local_name, local_name: local_name,
local_name_lower: local_name_lower, local_name_lower: local_name_lower,
operation: ParsedAttrSelectorOperation::Exists, operation: ParsedAttrSelectorOperation::Exists,
@ -1685,6 +1697,7 @@ where
let value = value.as_ref().into(); let value = value.as_ref().into();
let local_name_lower; let local_name_lower;
let local_name_is_ascii_lowercase;
{ {
let local_name_lower_cow = to_ascii_lowercase(&local_name); let local_name_lower_cow = to_ascii_lowercase(&local_name);
if let ParsedCaseSensitivity::CaseSensitive = case_sensitivity { if let ParsedCaseSensitivity::CaseSensitive = case_sensitivity {
@ -1699,15 +1712,16 @@ where
} }
} }
local_name_lower = local_name_lower_cow.as_ref().into(); local_name_lower = local_name_lower_cow.as_ref().into();
local_name_is_ascii_lowercase = matches!(local_name_lower_cow, Cow::Borrowed(..));
} }
let local_name = local_name.as_ref().into(); let local_name = local_name.as_ref().into();
if let Some(namespace) = namespace { if namespace.is_some() || !local_name_is_ascii_lowercase {
Ok(Component::AttributeOther(Box::new( Ok(Component::AttributeOther(Box::new(
AttrSelectorWithNamespace { AttrSelectorWithOptionalNamespace {
namespace: namespace, namespace,
local_name: local_name, local_name,
local_name_lower: local_name_lower, local_name_lower,
never_matches: never_matches, never_matches,
operation: ParsedAttrSelectorOperation::WithValue { operation: ParsedAttrSelectorOperation::WithValue {
operator: operator, operator: operator,
case_sensitivity: case_sensitivity, case_sensitivity: case_sensitivity,
@ -1718,7 +1732,6 @@ where
} else { } else {
Ok(Component::AttributeInNoNamespace { Ok(Component::AttributeInNoNamespace {
local_name: local_name, local_name: local_name,
local_name_lower: local_name_lower,
operator: operator, operator: operator,
value: value, value: value,
case_sensitivity: case_sensitivity, case_sensitivity: case_sensitivity,
@ -1785,7 +1798,7 @@ where
} }
// Success. // Success.
Ok(Component::Negation(sequence.into_vec().into_boxed_slice())) Ok(Component::Negation(sequence.into_vec().into_boxed_slice().into()))
} }
/// simple_selector_sequence /// simple_selector_sequence
@ -2625,7 +2638,7 @@ pub mod tests {
vec![ vec![
Component::DefaultNamespace(MATHML.into()), Component::DefaultNamespace(MATHML.into()),
Component::Negation( Component::Negation(
vec![Component::Class(DummyAtom::from("cl"))].into_boxed_slice(), vec![Component::Class(DummyAtom::from("cl"))].into_boxed_slice().into(),
), ),
], ],
specificity(0, 1, 0), specificity(0, 1, 0),
@ -2642,7 +2655,7 @@ pub mod tests {
vec![ vec![
Component::DefaultNamespace(MATHML.into()), Component::DefaultNamespace(MATHML.into()),
Component::ExplicitUniversalType, Component::ExplicitUniversalType,
].into_boxed_slice(), ].into_boxed_slice().into(),
), ),
], ],
specificity(0, 0, 0), specificity(0, 0, 0),
@ -2662,7 +2675,7 @@ pub mod tests {
name: DummyAtom::from("e"), name: DummyAtom::from("e"),
lower_name: DummyAtom::from("e"), lower_name: DummyAtom::from("e"),
}), }),
].into_boxed_slice(), ].into_boxed_slice().into(),
), ),
], ],
specificity(0, 0, 1), specificity(0, 0, 1),
@ -2676,7 +2689,6 @@ pub mod tests {
vec![ vec![
Component::AttributeInNoNamespace { Component::AttributeInNoNamespace {
local_name: DummyAtom::from("attr"), local_name: DummyAtom::from("attr"),
local_name_lower: DummyAtom::from("attr"),
operator: AttrSelectorOperator::DashMatch, operator: AttrSelectorOperator::DashMatch,
value: DummyAtom::from("foo"), value: DummyAtom::from("foo"),
never_matches: false, never_matches: false,
@ -2770,7 +2782,7 @@ pub mod tests {
Selector::from_vec( Selector::from_vec(
vec![ vec![
Component::Negation( Component::Negation(
vec![Component::ID(DummyAtom::from("provel"))].into_boxed_slice(), vec![Component::ID(DummyAtom::from("provel"))].into_boxed_slice().into(),
), ),
], ],
specificity(1, 0, 0), specificity(1, 0, 0),
@ -2789,7 +2801,7 @@ pub mod tests {
name: DummyAtom::from("circle"), name: DummyAtom::from("circle"),
lower_name: DummyAtom::from("circle"), lower_name: DummyAtom::from("circle"),
}), }),
].into_boxed_slice(), ].into_boxed_slice().into(),
), ),
], ],
specificity(0, 0, 1), specificity(0, 0, 1),
@ -2803,7 +2815,7 @@ pub mod tests {
Selector::from_vec( Selector::from_vec(
vec![ vec![
Component::Negation( Component::Negation(
vec![Component::ExplicitUniversalType].into_boxed_slice(), vec![Component::ExplicitUniversalType].into_boxed_slice().into(),
), ),
], ],
specificity(0, 0, 0), specificity(0, 0, 0),
@ -2819,7 +2831,7 @@ pub mod tests {
vec![ vec![
Component::ExplicitNoNamespace, Component::ExplicitNoNamespace,
Component::ExplicitUniversalType, Component::ExplicitUniversalType,
].into_boxed_slice(), ].into_boxed_slice().into(),
), ),
], ],
specificity(0, 0, 0), specificity(0, 0, 0),
@ -2834,7 +2846,7 @@ pub mod tests {
Selector::from_vec( Selector::from_vec(
vec![ vec![
Component::Negation( Component::Negation(
vec![Component::ExplicitUniversalType].into_boxed_slice(), vec![Component::ExplicitUniversalType].into_boxed_slice().into(),
), ),
], ],
specificity(0, 0, 0), specificity(0, 0, 0),
@ -2850,7 +2862,7 @@ pub mod tests {
vec![ vec![
Component::Namespace(DummyAtom("svg".into()), SVG.into()), Component::Namespace(DummyAtom("svg".into()), SVG.into()),
Component::ExplicitUniversalType, Component::ExplicitUniversalType,
].into_boxed_slice(), ].into_boxed_slice().into(),
), ),
], ],
specificity(0, 0, 0), specificity(0, 0, 0),

View file

@ -65,6 +65,7 @@ string_cache = { version = "0.7", optional = true }
style_derive = {path = "../style_derive"} style_derive = {path = "../style_derive"}
style_traits = {path = "../style_traits"} style_traits = {path = "../style_traits"}
servo_url = {path = "../url", optional = true} servo_url = {path = "../url", optional = true}
thin-slice = "0.1.0"
time = "0.1" time = "0.1"
uluru = "0.2" uluru = "0.2"
unicode-bidi = "0.3" unicode-bidi = "0.3"

View file

@ -15,6 +15,7 @@ use properties::longhands::display::computed_value::T as Display;
use selector_parser::{NonTSPseudoClass, PseudoElementCascadeType, SelectorImpl}; use selector_parser::{NonTSPseudoClass, PseudoElementCascadeType, SelectorImpl};
use std::fmt; use std::fmt;
use string_cache::Atom; use string_cache::Atom;
use thin_slice::ThinBoxedSlice;
use values::serialize_atom_identifier; use values::serialize_atom_identifier;
include!(concat!( include!(concat!(

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<[Atom]>), ${pseudo.capitalized()}(ThinBoxedSlice<Atom>),
% else: % else:
${pseudo.capitalized()}, ${pseudo.capitalized()},
% endif % endif
@ -209,7 +209,7 @@ impl PseudoElement {
% for pseudo in PSEUDOS: % for pseudo in PSEUDOS:
% if pseudo.is_tree_pseudo_element(): % if pseudo.is_tree_pseudo_element():
if atom == &atom!("${pseudo.value}") { if atom == &atom!("${pseudo.value}") {
return Some(PseudoElement::${pseudo.capitalized()}(args)); return Some(PseudoElement::${pseudo.capitalized()}(args.into()));
} }
% endif % endif
% endfor % endfor
@ -256,7 +256,7 @@ impl PseudoElement {
let tree_part = &name[10..]; let tree_part = &name[10..];
% for pseudo in TREE_PSEUDOS: % for pseudo in TREE_PSEUDOS:
if tree_part.eq_ignore_ascii_case("${pseudo.value[11:]}") { if tree_part.eq_ignore_ascii_case("${pseudo.value[11:]}") {
return Some(${pseudo_element_variant(pseudo, "args")}); return Some(${pseudo_element_variant(pseudo, "args.into()")});
} }
% endfor % endfor
None None

View file

@ -13,11 +13,13 @@ use gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI};
use invalidation::element::document_state::InvalidationMatchingData; use invalidation::element::document_state::InvalidationMatchingData;
use selector_parser::{Direction, SelectorParser}; use selector_parser::{Direction, SelectorParser};
use selectors::SelectorList; use selectors::SelectorList;
use selectors::parser::{self as selector_parser, Selector, SelectorParseErrorKind, Visit}; use selectors::parser::{self as selector_parser, Selector};
use selectors::parser::{SelectorParseErrorKind, Visit};
use selectors::visitor::SelectorVisitor; use selectors::visitor::SelectorVisitor;
use std::fmt; use std::fmt;
use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace}; use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss as ToCss_}; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss as ToCss_};
use thin_slice::ThinBoxedSlice;
pub use gecko::pseudo_element::{PseudoElement, EAGER_PSEUDOS, EAGER_PSEUDO_COUNT, 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;
@ -34,7 +36,7 @@ bitflags! {
} }
/// The type used for storing pseudo-class string arguments. /// The type used for storing pseudo-class string arguments.
pub type PseudoClassStringArg = Box<[u16]>; pub type PseudoClassStringArg = ThinBoxedSlice<u16>;
macro_rules! pseudo_class_name { macro_rules! pseudo_class_name {
(bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*], (bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*],
@ -56,7 +58,7 @@ macro_rules! pseudo_class_name {
/// ///
/// TODO(emilio): We disallow combinators and pseudos here, so we /// TODO(emilio): We disallow combinators and pseudos here, so we
/// should use SimpleSelector instead /// should use SimpleSelector instead
MozAny(Box<[Selector<SelectorImpl>]>), MozAny(ThinBoxedSlice<Selector<SelectorImpl>>),
/// The non-standard `:-moz-locale-dir` pseudo-class. /// The non-standard `:-moz-locale-dir` pseudo-class.
MozLocaleDir(Box<Direction>), MozLocaleDir(Box<Direction>),
} }
@ -405,7 +407,7 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
// convert to null terminated utf16 string // convert to null terminated utf16 string
// since that's what Gecko deals with // since that's what Gecko deals with
let utf16: Vec<u16> = name.encode_utf16().chain(Some(0u16)).collect(); let utf16: Vec<u16> = name.encode_utf16().chain(Some(0u16)).collect();
NonTSPseudoClass::$s_name(utf16.into_boxed_slice()) NonTSPseudoClass::$s_name(utf16.into_boxed_slice().into())
}, )* }, )*
"-moz-locale-dir" => { "-moz-locale-dir" => {
NonTSPseudoClass::MozLocaleDir( NonTSPseudoClass::MozLocaleDir(
@ -422,7 +424,7 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
selector_parser::parse_compound_selector_list( selector_parser::parse_compound_selector_list(
self, self,
parser, parser,
)? )?.into()
) )
} }
_ => return Err(parser.new_custom_error( _ => return Err(parser.new_custom_error(

View file

@ -93,6 +93,7 @@ extern crate string_cache;
#[macro_use] #[macro_use]
extern crate style_derive; extern crate style_derive;
extern crate style_traits; extern crate style_traits;
extern crate thin_slice;
extern crate time; extern crate time;
extern crate uluru; extern crate uluru;
extern crate unicode_bidi; extern crate unicode_bidi;