--- a/layout/style/test/test_selectors.html
+++ b/layout/style/test/test_selectors.html
@@ -298,16 +298,24 @@ function run() {
ifdoc.body.innerHTML = "";
style_text.data = "";
test_unparseable_via_api(selector);
}
// [attr] selector
test_parseable("[attr]")
test_parseable_via_api("[attr");
+ test_parseable("[ATTR]")
+ should_serialize_to("[attr]", "[attr]");
+ should_serialize_to("[ATTR]", "[ATTR]");
+
+ // Whether we should drop the bar is debatable. This matches Edge
+ // and Safari at the time of writing.
+ should_serialize_to("[|attr]", "[attr]");
+ should_serialize_to("[|ATTR]", "[ATTR]");
// [attr= ] selector
test_parseable("[attr=\"x\"]");
test_parseable("[attr='x']");
test_parseable("[attr=x]");
test_parseable("[attr=\"\"]");
test_parseable("[attr='']");
test_parseable("[attr=\"foo bar\"]");
--- a/servo/components/malloc_size_of/Cargo.toml
+++ b/servo/components/malloc_size_of/Cargo.toml
@@ -32,13 +32,14 @@ hyper_serde = { version = "0.8", optiona
mozjs = { version = "0.7.1", features = ["promises"], optional = true }
selectors = { path = "../selectors" }
serde = { version = "1.0.27", optional = true }
serde_bytes = { version = "0.10", optional = true }
servo_arc = { path = "../servo_arc" }
smallbitvec = "2.1.0"
smallvec = "0.6"
string_cache = { version = "0.7", optional = true }
+thin-slice = "0.1.0"
time = { version = "0.1.17", optional = true }
url = { version = "1.2", optional = true }
webrender_api = { git = "https://github.com/servo/webrender", features = ["ipc"], optional = true }
xml5ever = { version = "0.12", optional = true }
void = "1.0.2"
--- a/servo/components/malloc_size_of/lib.rs
+++ b/servo/components/malloc_size_of/lib.rs
@@ -58,16 +58,17 @@ extern crate selectors;
extern crate serde;
#[cfg(feature = "servo")]
extern crate serde_bytes;
extern crate servo_arc;
extern crate smallbitvec;
extern crate smallvec;
#[cfg(feature = "servo")]
extern crate string_cache;
+extern crate thin_slice;
#[cfg(feature = "servo")]
extern crate time;
#[cfg(feature = "url")]
extern crate url;
extern crate void;
#[cfg(feature = "webrender_api")]
extern crate webrender_api;
#[cfg(feature = "servo")]
@@ -226,16 +227,34 @@ impl<T: ?Sized> MallocShallowSizeOf for
}
impl<T: MallocSizeOf + ?Sized> MallocSizeOf for Box<T> {
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
self.shallow_size_of(ops) + (**self).size_of(ops)
}
}
+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 () {
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
0
}
}
impl<T1, T2> MallocSizeOf for (T1, T2)
where T1: MallocSizeOf, T2: MallocSizeOf
@@ -765,17 +784,17 @@ where
Component::LastOfType |
Component::OnlyOfType |
Component::Host(None) => 0,
}
}
}
impl<Impl: selectors::parser::SelectorImpl> MallocSizeOf
- for selectors::attr::AttrSelectorWithNamespace<Impl>
+ for selectors::attr::AttrSelectorWithOptionalNamespace<Impl>
{
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
0
}
}
impl MallocSizeOf for Void {
#[inline]
--- a/servo/components/selectors/Cargo.toml
+++ b/servo/components/selectors/Cargo.toml
@@ -25,11 +25,12 @@ matches = "0.1"
cssparser = "0.24.0"
log = "0.4"
fnv = "1.0"
fxhash = "0.2"
phf = "0.7.18"
precomputed-hash = "0.1"
servo_arc = { version = "0.1", path = "../servo_arc" }
smallvec = "0.6"
+thin-slice = "0.1.0"
[build-dependencies]
phf_codegen = "0.7.18"
--- a/servo/components/selectors/attr.rs
+++ b/servo/components/selectors/attr.rs
@@ -2,30 +2,30 @@
* 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/. */
use cssparser::ToCss;
use parser::SelectorImpl;
use std::fmt;
#[derive(Clone, Eq, PartialEq)]
-pub struct AttrSelectorWithNamespace<Impl: SelectorImpl> {
- pub namespace: NamespaceConstraint<(Impl::NamespacePrefix, Impl::NamespaceUrl)>,
+pub struct AttrSelectorWithOptionalNamespace<Impl: SelectorImpl> {
+ pub namespace: Option<NamespaceConstraint<(Impl::NamespacePrefix, Impl::NamespaceUrl)>>,
pub local_name: Impl::LocalName,
pub local_name_lower: Impl::LocalName,
pub operation: ParsedAttrSelectorOperation<Impl::AttrValue>,
pub never_matches: bool,
}
-impl<Impl: SelectorImpl> AttrSelectorWithNamespace<Impl> {
- pub fn namespace(&self) -> NamespaceConstraint<&Impl::NamespaceUrl> {
- match self.namespace {
+impl<Impl: SelectorImpl> AttrSelectorWithOptionalNamespace<Impl> {
+ pub fn namespace(&self) -> Option<NamespaceConstraint<&Impl::NamespaceUrl>> {
+ self.namespace.as_ref().map(|ns| match ns {
NamespaceConstraint::Any => NamespaceConstraint::Any,
NamespaceConstraint::Specific((_, ref url)) => NamespaceConstraint::Specific(url),
- }
+ })
}
}
#[derive(Clone, Eq, PartialEq)]
pub enum NamespaceConstraint<NamespaceUrl> {
Any,
/// Empty string for no namespace
--- a/servo/components/selectors/lib.rs
+++ b/servo/components/selectors/lib.rs
@@ -14,16 +14,17 @@ extern crate fxhash;
#[macro_use]
extern crate log;
#[macro_use]
extern crate matches;
extern crate phf;
extern crate precomputed_hash;
extern crate servo_arc;
extern crate smallvec;
+extern crate thin_slice;
pub mod attr;
pub mod bloom;
mod builder;
pub mod context;
pub mod matching;
mod nth_index_cache;
pub mod parser;
--- a/servo/components/selectors/matching.rs
+++ b/servo/components/selectors/matching.rs
@@ -694,43 +694,50 @@ where
element.attr_matches(
&NamespaceConstraint::Specific(&::parser::namespace_empty_string::<E::Impl>()),
select_name(is_html, local_name, local_name_lower),
&AttrSelectorOperation::Exists,
)
},
Component::AttributeInNoNamespace {
ref local_name,
- ref local_name_lower,
ref value,
operator,
case_sensitivity,
never_matches,
} => {
if never_matches {
return false;
}
let is_html = element.is_html_element_in_html_document();
element.attr_matches(
&NamespaceConstraint::Specific(&::parser::namespace_empty_string::<E::Impl>()),
- select_name(is_html, local_name, local_name_lower),
+ local_name,
&AttrSelectorOperation::WithValue {
operator: operator,
case_sensitivity: case_sensitivity.to_unconditional(is_html),
expected_value: value,
},
)
},
Component::AttributeOther(ref attr_sel) => {
if attr_sel.never_matches {
return false;
}
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(
- &attr_sel.namespace(),
+ &namespace,
select_name(is_html, &attr_sel.local_name, &attr_sel.local_name_lower),
&match attr_sel.operation {
ParsedAttrSelectorOperation::Exists => AttrSelectorOperation::Exists,
ParsedAttrSelectorOperation::WithValue {
operator,
case_sensitivity,
ref expected_value,
} => AttrSelectorOperation::WithValue {
--- a/servo/components/selectors/parser.rs
+++ b/servo/components/selectors/parser.rs
@@ -1,29 +1,31 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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/. */
-use attr::{AttrSelectorOperator, AttrSelectorWithNamespace, ParsedAttrSelectorOperation};
-use attr::{NamespaceConstraint, ParsedCaseSensitivity, SELECTOR_WHITESPACE};
+use attr::{AttrSelectorOperator, AttrSelectorWithOptionalNamespace};
+use attr::{NamespaceConstraint, ParsedAttrSelectorOperation};
+use attr::{ParsedCaseSensitivity, SELECTOR_WHITESPACE};
use bloom::BLOOM_HASH_MASK;
use builder::{SelectorBuilder, SpecificityAndFlags};
use context::QuirksMode;
use cssparser::{BasicParseError, BasicParseErrorKind, ParseError, ParseErrorKind};
use cssparser::{CowRcStr, Delimiter, SourceLocation};
use cssparser::{CssStringWriter, Parser as CssParser, ToCss, Token};
use cssparser::{parse_nth, serialize_identifier};
use precomputed_hash::PrecomputedHash;
use servo_arc::ThinArc;
use sink::Push;
use smallvec::SmallVec;
use std::borrow::{Borrow, Cow};
use std::fmt::{self, Debug, Display, Write};
use std::iter::Rev;
use std::slice;
+use thin_slice::ThinBoxedSlice;
pub use visitor::{SelectorVisitor, Visit};
/// A trait that represents a pseudo-element.
pub trait PseudoElement: Sized + ToCss {
/// The `SelectorImpl` this pseudo-element is used for.
type Impl: SelectorImpl;
/// Whether the pseudo-element supports a given state selector to the right
@@ -40,16 +42,18 @@ pub trait PseudoElement: Sized + ToCss {
pub trait NonTSPseudoClass: Sized + ToCss {
/// The `SelectorImpl` this pseudo-element is used for.
type Impl: SelectorImpl;
/// Whether this pseudo-class is :active or :hover.
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> {
if let Some(first_uppercase) = s.bytes().position(|byte| byte >= b'A' && byte <= b'Z') {
let mut string = s.to_owned();
string[first_uppercase..].make_ascii_lowercase();
string.into()
} else {
s.into()
}
@@ -423,32 +427,39 @@ where
local_name,
local_name_lower,
) {
return false;
}
},
AttributeInNoNamespace {
ref local_name,
- ref local_name_lower,
never_matches,
..
} if !never_matches =>
{
if !visitor.visit_attribute_selector(
&NamespaceConstraint::Specific(&namespace_empty_string::<Impl>()),
local_name,
- local_name_lower,
+ local_name,
) {
return false;
}
},
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(
- &attr_selector.namespace(),
+ &namespace,
&attr_selector.local_name,
&attr_selector.local_name_lower,
) {
return false;
}
},
NonTSPseudoClass(ref pseudo_class) => {
@@ -810,38 +821,38 @@ pub enum Component<Impl: SelectorImpl> {
ID(Impl::Identifier),
Class(Impl::ClassName),
AttributeInNoNamespaceExists {
local_name: Impl::LocalName,
local_name_lower: Impl::LocalName,
},
+ // Used only when local_name is already lowercase.
AttributeInNoNamespace {
local_name: Impl::LocalName,
- local_name_lower: Impl::LocalName,
operator: AttrSelectorOperator,
value: Impl::AttrValue,
case_sensitivity: ParsedCaseSensitivity,
never_matches: bool,
},
// 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
///
/// CSS3 Negation only takes a simple simple selector, but we still need to
/// treat it as a compound selector because it might be a type selector
/// which we represent as a namespace and a localname.
///
/// Note: if/when we upgrade this to CSS4, which supports combinators, we
/// need to think about how this should interact with
/// visit_complex_selector, and what the consumers of those APIs should do
/// about the presence of combinators in negation.
- Negation(Box<[Component<Impl>]>),
+ Negation(ThinBoxedSlice<Component<Impl>>),
FirstChild,
LastChild,
OnlyChild,
Root,
Empty,
Scope,
NthChild(i32, i32),
NthLastChild(i32, i32),
@@ -943,17 +954,17 @@ impl<Impl: SelectorImpl> Debug for Selec
}
}
impl<Impl: SelectorImpl> Debug for Component<Impl> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
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 {
self.to_css(f)
}
}
impl<Impl: SelectorImpl> Debug for LocalName<Impl> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.to_css(f)
}
@@ -1233,28 +1244,29 @@ impl<Impl: SelectorImpl> ToCss for Compo
write_affine(dest, a, b)?;
dest.write_char(')')
},
NonTSPseudoClass(ref pseudo) => pseudo.to_css(dest),
}
}
}
-impl<Impl: SelectorImpl> ToCss for AttrSelectorWithNamespace<Impl> {
+impl<Impl: SelectorImpl> ToCss for AttrSelectorWithOptionalNamespace<Impl> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
where
W: fmt::Write,
{
dest.write_char('[')?;
match self.namespace {
- NamespaceConstraint::Specific((ref prefix, _)) => {
+ Some(NamespaceConstraint::Specific((ref prefix, _))) => {
display_to_css_identifier(prefix, dest)?;
dest.write_char('|')?
},
- NamespaceConstraint::Any => dest.write_str("*|")?,
+ Some(NamespaceConstraint::Any) => dest.write_str("*|")?,
+ None => {}
}
display_to_css_identifier(&self.local_name, dest)?;
match self.operation {
ParsedAttrSelectorOperation::Exists => {},
ParsedAttrSelectorOperation::WithValue {
operator,
case_sensitivity,
ref expected_value,
@@ -1623,18 +1635,18 @@ where
let location = input.current_source_location();
let operator = match input.next() {
// [foo]
Err(_) => {
let local_name_lower = to_ascii_lowercase(&local_name).as_ref().into();
let local_name = local_name.as_ref().into();
if let Some(namespace) = namespace {
return Ok(Component::AttributeOther(Box::new(
- AttrSelectorWithNamespace {
- namespace: namespace,
+ AttrSelectorWithOptionalNamespace {
+ namespace: Some(namespace),
local_name: local_name,
local_name_lower: local_name_lower,
operation: ParsedAttrSelectorOperation::Exists,
never_matches: false,
},
)));
} else {
return Ok(Component::AttributeInNoNamespaceExists {
@@ -1680,50 +1692,51 @@ where
AttrSelectorOperator::Substring |
AttrSelectorOperator::Suffix => value.is_empty(),
};
let mut case_sensitivity = parse_attribute_flags(input)?;
let value = value.as_ref().into();
let local_name_lower;
+ let local_name_is_ascii_lowercase;
{
let local_name_lower_cow = to_ascii_lowercase(&local_name);
if let ParsedCaseSensitivity::CaseSensitive = case_sensitivity {
if namespace.is_none() &&
include!(concat!(
env!("OUT_DIR"),
"/ascii_case_insensitive_html_attributes.rs"
)).contains(&*local_name_lower_cow)
{
case_sensitivity =
ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument
}
}
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();
- if let Some(namespace) = namespace {
+ if namespace.is_some() || !local_name_is_ascii_lowercase {
Ok(Component::AttributeOther(Box::new(
- AttrSelectorWithNamespace {
- namespace: namespace,
- local_name: local_name,
- local_name_lower: local_name_lower,
- never_matches: never_matches,
+ AttrSelectorWithOptionalNamespace {
+ namespace,
+ local_name,
+ local_name_lower,
+ never_matches,
operation: ParsedAttrSelectorOperation::WithValue {
operator: operator,
case_sensitivity: case_sensitivity,
expected_value: value,
},
},
)))
} else {
Ok(Component::AttributeInNoNamespace {
local_name: local_name,
- local_name_lower: local_name_lower,
operator: operator,
value: value,
case_sensitivity: case_sensitivity,
never_matches: never_matches,
})
}
}
@@ -1780,17 +1793,17 @@ where
Some(SimpleSelectorParseResult::SlottedPseudo(_)) => {
let e = SelectorParseErrorKind::NonSimpleSelectorInNegation;
return Err(input.new_custom_error(e));
},
}
}
// Success.
- Ok(Component::Negation(sequence.into_vec().into_boxed_slice()))
+ Ok(Component::Negation(sequence.into_vec().into_boxed_slice().into()))
}
/// simple_selector_sequence
/// : [ type_selector | universal ] [ HASH | class | attrib | pseudo | negation ]*
/// | [ HASH | class | attrib | pseudo | negation ]+
///
/// `Err(())` means invalid selector.
/// `Ok(None)` is an empty selector
@@ -2620,34 +2633,34 @@ pub mod tests {
// but not otherwise.
assert_eq!(
parse_ns(":not(.cl)", &parser),
Ok(SelectorList::from_vec(vec![
Selector::from_vec(
vec![
Component::DefaultNamespace(MATHML.into()),
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),
),
]))
);
assert_eq!(
parse_ns(":not(*)", &parser),
Ok(SelectorList::from_vec(vec![
Selector::from_vec(
vec![
Component::DefaultNamespace(MATHML.into()),
Component::Negation(
vec![
Component::DefaultNamespace(MATHML.into()),
Component::ExplicitUniversalType,
- ].into_boxed_slice(),
+ ].into_boxed_slice().into(),
),
],
specificity(0, 0, 0),
),
]))
);
assert_eq!(
parse_ns(":not(e)", &parser),
@@ -2657,31 +2670,30 @@ pub mod tests {
Component::DefaultNamespace(MATHML.into()),
Component::Negation(
vec![
Component::DefaultNamespace(MATHML.into()),
Component::LocalName(LocalName {
name: DummyAtom::from("e"),
lower_name: DummyAtom::from("e"),
}),
- ].into_boxed_slice(),
+ ].into_boxed_slice().into(),
),
],
specificity(0, 0, 1),
),
]))
);
assert_eq!(
parse("[attr|=\"foo\"]"),
Ok(SelectorList::from_vec(vec![
Selector::from_vec(
vec![
Component::AttributeInNoNamespace {
local_name: DummyAtom::from("attr"),
- local_name_lower: DummyAtom::from("attr"),
operator: AttrSelectorOperator::DashMatch,
value: DummyAtom::from("foo"),
never_matches: false,
case_sensitivity: ParsedCaseSensitivity::CaseSensitive,
},
],
specificity(0, 1, 0),
),
@@ -2765,17 +2777,17 @@ pub mod tests {
assert!(parse(":not(#provel > old)").is_err());
assert!(parse("table[rules]:not([rules=\"none\"]):not([rules=\"\"])").is_ok());
assert_eq!(
parse(":not(#provel)"),
Ok(SelectorList::from_vec(vec![
Selector::from_vec(
vec![
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),
),
]))
);
assert_eq!(
parse_ns(":not(svg|circle)", &parser),
@@ -2784,78 +2796,78 @@ pub mod tests {
vec![
Component::Negation(
vec![
Component::Namespace(DummyAtom("svg".into()), SVG.into()),
Component::LocalName(LocalName {
name: DummyAtom::from("circle"),
lower_name: DummyAtom::from("circle"),
}),
- ].into_boxed_slice(),
+ ].into_boxed_slice().into(),
),
],
specificity(0, 0, 1),
),
]))
);
// https://github.com/servo/servo/issues/16017
assert_eq!(
parse_ns(":not(*)", &parser),
Ok(SelectorList::from_vec(vec![
Selector::from_vec(
vec![
Component::Negation(
- vec![Component::ExplicitUniversalType].into_boxed_slice(),
+ vec![Component::ExplicitUniversalType].into_boxed_slice().into(),
),
],
specificity(0, 0, 0),
),
]))
);
assert_eq!(
parse_ns(":not(|*)", &parser),
Ok(SelectorList::from_vec(vec![
Selector::from_vec(
vec![
Component::Negation(
vec![
Component::ExplicitNoNamespace,
Component::ExplicitUniversalType,
- ].into_boxed_slice(),
+ ].into_boxed_slice().into(),
),
],
specificity(0, 0, 0),
),
]))
);
// *| should be elided if there is no default namespace.
// https://github.com/servo/servo/pull/17537
assert_eq!(
parse_ns_expected(":not(*|*)", &parser, Some(":not(*)")),
Ok(SelectorList::from_vec(vec![
Selector::from_vec(
vec![
Component::Negation(
- vec![Component::ExplicitUniversalType].into_boxed_slice(),
+ vec![Component::ExplicitUniversalType].into_boxed_slice().into(),
),
],
specificity(0, 0, 0),
),
]))
);
assert_eq!(
parse_ns(":not(svg|*)", &parser),
Ok(SelectorList::from_vec(vec![
Selector::from_vec(
vec![
Component::Negation(
vec![
Component::Namespace(DummyAtom("svg".into()), SVG.into()),
Component::ExplicitUniversalType,
- ].into_boxed_slice(),
+ ].into_boxed_slice().into(),
),
],
specificity(0, 0, 0),
),
]))
);
assert!(parse("::slotted()").is_err());
--- a/servo/components/style/Cargo.toml
+++ b/servo/components/style/Cargo.toml
@@ -61,16 +61,17 @@ servo_arc = { path = "../servo_arc" }
servo_atoms = {path = "../atoms", optional = true}
servo_config = {path = "../config", optional = true}
smallbitvec = "2.1.1"
smallvec = "0.6"
string_cache = { version = "0.7", optional = true }
style_derive = {path = "../style_derive"}
style_traits = {path = "../style_traits"}
servo_url = {path = "../url", optional = true}
+thin-slice = "0.1.0"
time = "0.1"
uluru = "0.2"
unicode-bidi = "0.3"
unicode-segmentation = "1.0"
void = "1.0.2"
[target.'cfg(windows)'.dependencies]
kernel32-sys = "0.2"
--- a/servo/components/style/gecko/pseudo_element.rs
+++ b/servo/components/style/gecko/pseudo_element.rs
@@ -10,16 +10,17 @@
use cssparser::ToCss;
use gecko_bindings::structs::{self, CSSPseudoElementType};
use properties::{ComputedValues, PropertyFlags};
use properties::longhands::display::computed_value::T as Display;
use selector_parser::{NonTSPseudoClass, PseudoElementCascadeType, SelectorImpl};
use std::fmt;
use string_cache::Atom;
+use thin_slice::ThinBoxedSlice;
use values::serialize_atom_identifier;
include!(concat!(
env!("OUT_DIR"),
"/gecko/pseudo_element_definition.rs"
));
impl ::selectors::parser::PseudoElement for PseudoElement {
--- a/servo/components/style/gecko/pseudo_element_definition.mako.rs
+++ b/servo/components/style/gecko/pseudo_element_definition.mako.rs
@@ -3,17 +3,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/// Gecko's pseudo-element definition.
#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
pub enum PseudoElement {
% for pseudo in PSEUDOS:
/// ${pseudo.value}
% if pseudo.is_tree_pseudo_element():
- ${pseudo.capitalized()}(Box<[Atom]>),
+ ${pseudo.capitalized()}(ThinBoxedSlice<Atom>),
% else:
${pseudo.capitalized()},
% endif
% endfor
}
/// Important: If you change this, you should also update Gecko's
/// nsCSSPseudoElements::IsEagerlyCascadedInServo.
@@ -204,17 +204,17 @@ impl PseudoElement {
}
/// 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));
+ return Some(PseudoElement::${pseudo.capitalized()}(args.into()));
}
% endif
% endfor
None
}
/// Constructs a pseudo-element from a string of text.
///
@@ -251,17 +251,17 @@ impl PseudoElement {
///
/// Returns `None` if the pseudo-element is not recognized.
#[inline]
pub fn tree_pseudo_element(name: &str, args: Box<[Atom]>) -> Option<Self> {
debug_assert!(name.starts_with("-moz-tree-"));
let tree_part = &name[10..];
% for pseudo in TREE_PSEUDOS:
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
None
}
}
impl ToCss for PseudoElement {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
--- a/servo/components/style/gecko/selector_parser.rs
+++ b/servo/components/style/gecko/selector_parser.rs
@@ -8,38 +8,40 @@ use cssparser::{BasicParseError, BasicPa
use cssparser::{CowRcStr, SourceLocation, ToCss, Token};
use element_state::{DocumentState, ElementState};
use gecko_bindings::structs;
use gecko_bindings::structs::RawServoSelectorList;
use gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI};
use invalidation::element::document_state::InvalidationMatchingData;
use selector_parser::{Direction, SelectorParser};
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 std::fmt;
use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
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::snapshot::SnapshotMap;
bitflags! {
// See NonTSPseudoClass::is_enabled_in()
struct NonTSPseudoClassFlag: u8 {
const PSEUDO_CLASS_ENABLED_IN_UA_SHEETS = 1 << 0;
const PSEUDO_CLASS_ENABLED_IN_CHROME = 1 << 1;
const PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME =
NonTSPseudoClassFlag::PSEUDO_CLASS_ENABLED_IN_UA_SHEETS.bits |
NonTSPseudoClassFlag::PSEUDO_CLASS_ENABLED_IN_CHROME.bits;
}
}
/// The type used for storing pseudo-class string arguments.
-pub type PseudoClassStringArg = Box<[u16]>;
+pub type PseudoClassStringArg = ThinBoxedSlice<u16>;
macro_rules! pseudo_class_name {
(bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*],
string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*]) => {
/// Our representation of a non tree-structural pseudo-class.
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)]
pub enum NonTSPseudoClass {
$(
@@ -51,17 +53,17 @@ macro_rules! pseudo_class_name {
$s_name(PseudoClassStringArg),
)*
/// The `:dir` pseudo-class.
Dir(Box<Direction>),
/// The non-standard `:-moz-any` pseudo-class.
///
/// TODO(emilio): We disallow combinators and pseudos here, so we
/// should use SimpleSelector instead
- MozAny(Box<[Selector<SelectorImpl>]>),
+ MozAny(ThinBoxedSlice<Selector<SelectorImpl>>),
/// The non-standard `:-moz-locale-dir` pseudo-class.
MozLocaleDir(Box<Direction>),
}
}
}
apply_non_ts_list!(pseudo_class_name);
impl ToCss for NonTSPseudoClass {
@@ -400,34 +402,34 @@ impl<'a, 'i> ::selectors::Parser<'i> for
(bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*],
string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*]) => {
match_ignore_ascii_case! { &name,
$($s_css => {
let name = parser.expect_ident_or_string()?;
// convert to null terminated utf16 string
// since that's what Gecko deals with
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" => {
NonTSPseudoClass::MozLocaleDir(
Box::new(Direction::parse(parser)?)
)
},
"dir" => {
NonTSPseudoClass::Dir(
Box::new(Direction::parse(parser)?)
)
},
"-moz-any" => {
NonTSPseudoClass::MozAny(
selector_parser::parse_compound_selector_list(
self,
parser,
- )?
+ )?.into()
)
}
_ => return Err(parser.new_custom_error(
SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name.clone())
))
}
}
}
--- a/servo/components/style/lib.rs
+++ b/servo/components/style/lib.rs
@@ -88,16 +88,17 @@ extern crate servo_config;
extern crate servo_url;
extern crate smallbitvec;
extern crate smallvec;
#[cfg(feature = "servo")]
extern crate string_cache;
#[macro_use]
extern crate style_derive;
extern crate style_traits;
+extern crate thin_slice;
extern crate time;
extern crate uluru;
extern crate unicode_bidi;
#[allow(unused_extern_crates)]
extern crate unicode_segmentation;
extern crate void;
#[macro_use]
--- a/servo/ports/geckolib/tests/size_of.rs
+++ b/servo/ports/geckolib/tests/size_of.rs
@@ -9,20 +9,20 @@ use style::applicable_declarations::Appl
use style::data::{ElementData, ElementStyles};
use style::gecko::selector_parser::{self, SelectorImpl};
use style::properties::ComputedValues;
use style::rule_tree::{RuleNode, StrongRuleNode};
use style::values::computed;
use style::values::specified;
size_of_test!(size_of_selector, selectors::parser::Selector<SelectorImpl>, 8);
-size_of_test!(size_of_pseudo_element, selector_parser::PseudoElement, 24);
+size_of_test!(size_of_pseudo_element, selector_parser::PseudoElement, 16);
-size_of_test!(size_of_component, selectors::parser::Component<SelectorImpl>, 32);
-size_of_test!(size_of_pseudo_class, selector_parser::NonTSPseudoClass, 24);
+size_of_test!(size_of_component, selectors::parser::Component<SelectorImpl>, 24);
+size_of_test!(size_of_pseudo_class, selector_parser::NonTSPseudoClass, 16);
// The size of this is critical to performance on the bloom-basic microbenchmark.
// When iterating over a large Rule array, we want to be able to fast-reject
// selectors (with the inline hashes) with as few cache misses as possible.
size_of_test!(test_size_of_rule, style::stylist::Rule, 32);
// Large pages generate tens of thousands of ComputedValues.
size_of_test!(test_size_of_cv, ComputedValues, 248);
--- a/testing/web-platform/meta/FileAPI/file/__dir__.ini
+++ b/testing/web-platform/meta/FileAPI/file/__dir__.ini
@@ -1,1 +1,1 @@
-lsan-allowed: [Alloc, NewEmptyScopeData, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::dom::ChromeUtils::GenerateQI, mozilla::dom::Performance::CreateForMainThread]
+lsan-allowed: [Alloc, NewEmptyScopeData, __rdl_alloc, __rdl_realloc, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::dom::ChromeUtils::GenerateQI, mozilla::dom::Performance::CreateForMainThread]
--- a/testing/web-platform/meta/fetch/api/abort/__dir__.ini
+++ b/testing/web-platform/meta/fetch/api/abort/__dir__.ini
@@ -1,2 +1,2 @@
prefs: [javascript.options.streams:true, dom.streams.enabled:true]
-lsan-allowed: [Alloc, AllocateProtoAndIfaceCache, NewEmptyScopeData, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::dom::ChromeUtils::GenerateQI, mozilla::dom::DOMException::Create, mozilla::dom::FetchStream::Create, mozilla::dom::Performance::CreateForMainThread]
+lsan-allowed: [Alloc, AllocateProtoAndIfaceCache, NewEmptyScopeData, __rdl_alloc, __rdl_realloc, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::dom::ChromeUtils::GenerateQI, mozilla::dom::DOMException::Create, mozilla::dom::FetchStream::Create, mozilla::dom::Performance::CreateForMainThread]
--- a/testing/web-platform/meta/fetch/api/request/__dir__.ini
+++ b/testing/web-platform/meta/fetch/api/request/__dir__.ini
@@ -1,1 +1,1 @@
-lsan-allowed: [Alloc, NewEmptyScopeData, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::dom::ChromeUtils::GenerateQI, mozilla::dom::Performance::CreateForMainThread]
+lsan-allowed: [Alloc, NewEmptyScopeData, __rdl_alloc, __rdl_realloc, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::dom::ChromeUtils::GenerateQI, mozilla::dom::Performance::CreateForMainThread]
--- a/testing/web-platform/meta/html/semantics/forms/form-submission-0/__dir__.ini
+++ b/testing/web-platform/meta/html/semantics/forms/form-submission-0/__dir__.ini
@@ -1,1 +1,1 @@
-lsan-allowed: [Alloc, NewEmptyScopeData, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::dom::ChromeUtils::GenerateQI, mozilla::dom::Performance::CreateForMainThread]
+lsan-allowed: [Alloc, NewEmptyScopeData, __rdl_alloc, __rdl_realloc, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::dom::ChromeUtils::GenerateQI, mozilla::dom::Performance::CreateForMainThread]
--- a/testing/web-platform/meta/performance-timeline/__dir__.ini
+++ b/testing/web-platform/meta/performance-timeline/__dir__.ini
@@ -1,1 +1,1 @@
-lsan-allowed: [Alloc, NewEmptyScopeData, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::dom::ChromeUtils::GenerateQI, mozilla::dom::Performance::CreateForMainThread, mozilla::dom::PerformanceObserver::Constructor, xpc::CreateSandboxObject]
+lsan-allowed: [Alloc, NewEmptyScopeData, __rdl_alloc, __rdl_realloc, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::dom::ChromeUtils::GenerateQI, mozilla::dom::Performance::CreateForMainThread, mozilla::dom::PerformanceObserver::Constructor, xpc::CreateSandboxObject]
--- a/testing/web-platform/meta/service-workers/service-worker/__dir__.ini
+++ b/testing/web-platform/meta/service-workers/service-worker/__dir__.ini
@@ -1,2 +1,2 @@
prefs: [dom.serviceWorkers.enabled:true]
-lsan-allowed: [Alloc, Create, CreateInner, MakeUnique, NewEmptyScopeData, NewPage, OrInsert, Realloc, SharedMutex, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::ThrottledEventQueue::Create, mozilla::dom::ChromeUtils::GenerateQI, mozilla::dom::Performance::CreateForMainThread, mozilla::dom::PerformanceStorageWorker::Create, mozilla::dom::WorkerPrivate::WorkerPrivate, mozilla::net::HttpBaseChannel::HttpBaseChannel, mozilla::net::HttpChannelChild::HttpChannelChild, mozilla::net::nsHttpHandler::NewProxiedChannel2]
+lsan-allowed: [Alloc, Create, CreateInner, MakeUnique, NewEmptyScopeData, NewPage, OrInsert, Realloc, SharedMutex, __rdl_alloc, __rdl_realloc, js_new, js_pod_calloc, js_pod_malloc, js_pod_realloc, mozilla::BasePrincipal::CreateCodebasePrincipal, mozilla::ThrottledEventQueue::Create, mozilla::dom::ChromeUtils::GenerateQI, mozilla::dom::Performance::CreateForMainThread, mozilla::dom::PerformanceStorageWorker::Create, mozilla::dom::WorkerPrivate::WorkerPrivate, mozilla::net::HttpBaseChannel::HttpBaseChannel, mozilla::net::HttpChannelChild::HttpChannelChild, mozilla::net::nsHttpHandler::NewProxiedChannel2]