Auto merge of #21357 - emilio:gecko-sync, r=emilio

style: Sync changes from mozilla-central.

See each individual commit.

<!-- 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/21357)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2018-08-07 20:27:24 -04:00 committed by GitHub
commit ea86eb64be
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
51 changed files with 899 additions and 438 deletions

14
Cargo.lock generated
View file

@ -1716,6 +1716,7 @@ dependencies = [
"canvas_traits 0.0.1",
"euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx 0.0.1",
"gfx_traits 0.0.1",
"html5ever 0.22.3 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1759,6 +1760,7 @@ dependencies = [
"embedder_traits 0.0.1",
"euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx 0.0.1",
"gfx_traits 0.0.1",
"histogram 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1984,6 +1986,7 @@ dependencies = [
"smallbitvec 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
"thin-slice 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3088,6 +3091,7 @@ dependencies = [
"bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cssparser 0.24.0 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3095,6 +3099,7 @@ dependencies = [
"precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"servo_arc 0.1.1",
"smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"thin-slice 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -3498,7 +3503,7 @@ dependencies = [
"encoding_rs 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
"fallible 0.0.1",
"fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"hashglobe 0.1.0",
"html5ever 0.22.3 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3530,6 +3535,7 @@ dependencies = [
"string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
"style_derive 0.0.1",
"style_traits 0.0.1",
"thin-slice 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"uluru 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3680,6 +3686,11 @@ dependencies = [
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thin-slice"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "thread_local"
version = "0.3.5"
@ -4528,6 +4539,7 @@ dependencies = [
"checksum termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "adc4587ead41bf016f11af03e55a624c06568b5a19db4e90fde573d805074f83"
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
"checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693"
"checksum thin-slice 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c"
"checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963"
"checksum thread_profiler 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5920e77802b177479ab5795767fa48e68f61b2f516c2ac0041e2978dd8efe483"
"checksum threadpool 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "59f6d3eff89920113dac9db44dde461d71d01e88a5b57b258a0466c32b5d7fe1"

View file

@ -18,6 +18,7 @@ bitflags = "1.0"
canvas_traits = {path = "../canvas_traits"}
euclid = "0.19"
fnv = "1.0"
fxhash = "0.2"
gfx = {path = "../gfx"}
gfx_traits = {path = "../gfx_traits"}
html5ever = "0.22"

View file

@ -7,7 +7,7 @@
use context::LayoutContext;
use display_list::items::OpaqueNode;
use flow::{Flow, GetBaseFlow};
use fnv::FnvHashMap;
use fxhash::FxHashMap;
use ipc_channel::ipc::IpcSender;
use msg::constellation_msg::PipelineId;
use opaque_node::OpaqueNodeMethods;
@ -26,8 +26,8 @@ use style::timer::Timer;
pub fn update_animation_state<E>(
constellation_chan: &IpcSender<ConstellationMsg>,
script_chan: &IpcSender<ConstellationControlMsg>,
running_animations: &mut FnvHashMap<OpaqueNode, Vec<Animation>>,
expired_animations: &mut FnvHashMap<OpaqueNode, Vec<Animation>>,
running_animations: &mut FxHashMap<OpaqueNode, Vec<Animation>>,
expired_animations: &mut FxHashMap<OpaqueNode, Vec<Animation>>,
mut newly_transitioning_nodes: Option<&mut Vec<UntrustedNodeAddress>>,
new_animations_receiver: &Receiver<Animation>,
pipeline_id: PipelineId,
@ -153,7 +153,7 @@ where
pub fn recalc_style_for_animations<E>(
context: &LayoutContext,
flow: &mut Flow,
animations: &FnvHashMap<OpaqueNode, Vec<Animation>>,
animations: &FxHashMap<OpaqueNode, Vec<Animation>>,
)
where
E: TElement,

View file

@ -11,6 +11,7 @@ extern crate bitflags;
extern crate canvas_traits;
extern crate euclid;
extern crate fnv;
extern crate fxhash;
extern crate gfx;
extern crate gfx_traits;
#[macro_use] extern crate html5ever;

View file

@ -18,6 +18,7 @@ atomic_refcell = "0.1"
embedder_traits = {path = "../embedder_traits"}
euclid = "0.19"
fnv = "1.0"
fxhash = "0.2"
gfx = {path = "../gfx"}
gfx_traits = {path = "../gfx_traits"}
histogram = "0.6.8"

View file

@ -675,14 +675,6 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
None
}
fn first_child_element(&self) -> Option<ServoLayoutElement<'le>> {
self.as_node().dom_children().filter_map(|n| n.as_element()).next()
}
fn last_child_element(&self) -> Option<ServoLayoutElement<'le>> {
self.as_node().rev_children().filter_map(|n| n.as_element()).next()
}
fn prev_sibling_element(&self) -> Option<ServoLayoutElement<'le>> {
let mut node = self.as_node();
while let Some(sibling) = node.prev_sibling() {
@ -1223,17 +1215,6 @@ impl<'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> {
None
}
fn first_child_element(&self) -> Option<Self> {
warn!("ServoThreadSafeLayoutElement::first_child_element called");
None
}
// Skips non-element nodes
fn last_child_element(&self) -> Option<Self> {
warn!("ServoThreadSafeLayoutElement::last_child_element called");
None
}
// Skips non-element nodes
fn prev_sibling_element(&self) -> Option<Self> {
warn!("ServoThreadSafeLayoutElement::prev_sibling_element called");

View file

@ -12,6 +12,7 @@ extern crate atomic_refcell;
extern crate embedder_traits;
extern crate euclid;
extern crate fnv;
extern crate fxhash;
extern crate gfx;
extern crate gfx_traits;
extern crate histogram;
@ -59,6 +60,7 @@ use dom_wrapper::drop_style_and_layout_data;
use embedder_traits::resources::{self, Resource};
use euclid::{Point2D, Rect, Size2D, TypedScale, TypedSize2D};
use fnv::FnvHashMap;
use fxhash::FxHashMap;
use gfx::font;
use gfx::font_cache_thread::FontCacheThread;
use gfx::font_context;
@ -223,10 +225,10 @@ pub struct LayoutThread {
document_shared_lock: Option<SharedRwLock>,
/// The list of currently-running animations.
running_animations: ServoArc<RwLock<FnvHashMap<OpaqueNode, Vec<Animation>>>>,
running_animations: ServoArc<RwLock<FxHashMap<OpaqueNode, Vec<Animation>>>>,
/// The list of animations that have expired since the last style recalculation.
expired_animations: ServoArc<RwLock<FnvHashMap<OpaqueNode, Vec<Animation>>>>,
expired_animations: ServoArc<RwLock<FxHashMap<OpaqueNode, Vec<Animation>>>>,
/// A counter for epoch messages
epoch: Cell<Epoch>,
@ -503,7 +505,7 @@ impl LayoutThread {
constellation_chan: constellation_chan.clone(),
time_profiler_chan: time_profiler_chan,
mem_profiler_chan: mem_profiler_chan,
registered_painters: RegisteredPaintersImpl(FnvHashMap::default()),
registered_painters: RegisteredPaintersImpl(Default::default()),
image_cache: image_cache.clone(),
font_cache_thread: font_cache_thread,
first_reflow: Cell::new(true),
@ -517,8 +519,8 @@ impl LayoutThread {
outstanding_web_fonts: Arc::new(AtomicUsize::new(0)),
root_flow: RefCell::new(None),
document_shared_lock: None,
running_animations: ServoArc::new(RwLock::new(FnvHashMap::default())),
expired_animations: ServoArc::new(RwLock::new(FnvHashMap::default())),
running_animations: ServoArc::new(RwLock::new(Default::default())),
expired_animations: ServoArc::new(RwLock::new(Default::default())),
epoch: Cell::new(Epoch(0)),
viewport_size: Size2D::new(Au(0), Au(0)),
webrender_api: webrender_api_sender.create_api(),
@ -1813,7 +1815,8 @@ lazy_static! {
struct RegisteredPainterImpl {
painter: Box<Painter>,
name: Atom,
properties: FnvHashMap<Atom, PropertyId>,
// FIXME: Should be a PrecomputedHashMap.
properties: FxHashMap<Atom, PropertyId>,
}
impl SpeculativePainter for RegisteredPainterImpl {
@ -1823,7 +1826,7 @@ impl SpeculativePainter for RegisteredPainterImpl {
}
impl RegisteredSpeculativePainter for RegisteredPainterImpl {
fn properties(&self) -> &FnvHashMap<Atom, PropertyId> {
fn properties(&self) -> &FxHashMap<Atom, PropertyId> {
&self.properties
}
fn name(&self) -> Atom {

View file

@ -37,6 +37,7 @@ 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 }

View file

@ -63,6 +63,7 @@ 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")]
@ -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 () {
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
0
@ -770,7 +789,7 @@ where
}
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

View file

@ -2640,14 +2640,6 @@ impl<'a> SelectorsElement for DomRoot<Element> {
false
}
fn first_child_element(&self) -> Option<DomRoot<Element>> {
self.node.child_elements().next()
}
fn last_child_element(&self) -> Option<DomRoot<Element>> {
self.node.rev_children().filter_map(DomRoot::downcast).next()
}
fn prev_sibling_element(&self) -> Option<DomRoot<Element>> {
self.node.preceding_siblings().filter_map(DomRoot::downcast).next()
}

View file

@ -25,10 +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.2"
thin-slice = "0.1.0"
[build-dependencies]
phf_codegen = "0.7.18"

View file

@ -7,20 +7,20 @@ 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),
}
})
}
}

View file

@ -297,6 +297,9 @@ impl Clone for BloomStorageBool {
}
fn hash<T: Hash>(elem: &T) -> u32 {
// We generally use FxHasher in Stylo because it's faster than FnvHasher,
// but the increased collision rate has outsized effect on the bloom
// filter, so we use FnvHasher instead here.
let mut hasher = FnvHasher::default();
elem.hash(&mut hasher);
let hash: u64 = hasher.finish();

View file

@ -10,6 +10,7 @@ extern crate bitflags;
#[macro_use]
extern crate cssparser;
extern crate fnv;
extern crate fxhash;
#[macro_use]
extern crate log;
#[macro_use]
@ -18,6 +19,7 @@ extern crate phf;
extern crate precomputed_hash;
extern crate servo_arc;
extern crate smallvec;
extern crate thin_slice;
pub mod attr;
pub mod bloom;

View file

@ -699,7 +699,6 @@ where
},
Component::AttributeInNoNamespace {
ref local_name,
ref local_name_lower,
ref value,
operator,
case_sensitivity,
@ -711,7 +710,7 @@ where
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),
@ -724,8 +723,16 @@ where
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,

View file

@ -2,7 +2,7 @@
* 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 fnv::FnvHashMap;
use fxhash::FxHashMap;
use tree::OpaqueElement;
/// A cache to speed up matching of nth-index-like selectors.
@ -32,7 +32,7 @@ impl NthIndexCache {
/// The concrete per-pseudo-class cache.
#[derive(Default)]
pub struct NthIndexCacheInner(FnvHashMap<OpaqueElement, i32>);
pub struct NthIndexCacheInner(FxHashMap<OpaqueElement, i32>);
impl NthIndexCacheInner {
/// Does a lookup for a given element in the cache.

View file

@ -2,8 +2,9 @@
* 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;
@ -19,6 +20,7 @@ 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.
@ -45,6 +47,8 @@ pub trait NonTSPseudoClass: Sized + ToCss {
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();
@ -428,7 +432,6 @@ where
},
AttributeInNoNamespace {
ref local_name,
ref local_name_lower,
never_matches,
..
} if !never_matches =>
@ -436,14 +439,22 @@ where
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,
) {
@ -815,16 +826,16 @@ pub enum Component<Impl: SelectorImpl> {
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
///
@ -836,7 +847,7 @@ pub enum Component<Impl: SelectorImpl> {
/// 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,
@ -948,7 +959,7 @@ impl<Impl: SelectorImpl> Debug for Component<Impl> {
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)
}
@ -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
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 {
@ -1628,8 +1640,8 @@ where
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,
@ -1685,6 +1697,7 @@ where
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 {
@ -1699,15 +1712,16 @@ where
}
}
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,
@ -1718,7 +1732,6 @@ where
} else {
Ok(Component::AttributeInNoNamespace {
local_name: local_name,
local_name_lower: local_name_lower,
operator: operator,
value: value,
case_sensitivity: case_sensitivity,
@ -1785,7 +1798,7 @@ where
}
// Success.
Ok(Component::Negation(sequence.into_vec().into_boxed_slice()))
Ok(Component::Negation(sequence.into_vec().into_boxed_slice().into()))
}
/// simple_selector_sequence
@ -2625,7 +2638,7 @@ pub mod tests {
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),
@ -2642,7 +2655,7 @@ pub mod tests {
vec![
Component::DefaultNamespace(MATHML.into()),
Component::ExplicitUniversalType,
].into_boxed_slice(),
].into_boxed_slice().into(),
),
],
specificity(0, 0, 0),
@ -2662,7 +2675,7 @@ pub mod tests {
name: DummyAtom::from("e"),
lower_name: DummyAtom::from("e"),
}),
].into_boxed_slice(),
].into_boxed_slice().into(),
),
],
specificity(0, 0, 1),
@ -2676,7 +2689,6 @@ pub mod tests {
vec![
Component::AttributeInNoNamespace {
local_name: DummyAtom::from("attr"),
local_name_lower: DummyAtom::from("attr"),
operator: AttrSelectorOperator::DashMatch,
value: DummyAtom::from("foo"),
never_matches: false,
@ -2770,7 +2782,7 @@ pub mod tests {
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),
@ -2789,7 +2801,7 @@ pub mod tests {
name: DummyAtom::from("circle"),
lower_name: DummyAtom::from("circle"),
}),
].into_boxed_slice(),
].into_boxed_slice().into(),
),
],
specificity(0, 0, 1),
@ -2803,7 +2815,7 @@ pub mod tests {
Selector::from_vec(
vec![
Component::Negation(
vec![Component::ExplicitUniversalType].into_boxed_slice(),
vec![Component::ExplicitUniversalType].into_boxed_slice().into(),
),
],
specificity(0, 0, 0),
@ -2819,7 +2831,7 @@ pub mod tests {
vec![
Component::ExplicitNoNamespace,
Component::ExplicitUniversalType,
].into_boxed_slice(),
].into_boxed_slice().into(),
),
],
specificity(0, 0, 0),
@ -2834,7 +2846,7 @@ pub mod tests {
Selector::from_vec(
vec![
Component::Negation(
vec![Component::ExplicitUniversalType].into_boxed_slice(),
vec![Component::ExplicitUniversalType].into_boxed_slice().into(),
),
],
specificity(0, 0, 0),
@ -2850,7 +2862,7 @@ pub mod tests {
vec![
Component::Namespace(DummyAtom("svg".into()), SVG.into()),
Component::ExplicitUniversalType,
].into_boxed_slice(),
].into_boxed_slice().into(),
),
],
specificity(0, 0, 0),

View file

@ -45,12 +45,6 @@ pub trait Element: Sized + Clone + Debug {
self.parent_element()
}
/// Skips non-element nodes
fn first_child_element(&self) -> Option<Self>;
/// Skips non-element nodes
fn last_child_element(&self) -> Option<Self>;
/// Skips non-element nodes
fn prev_sibling_element(&self) -> Option<Self>;

View file

@ -36,7 +36,7 @@ new_debug_unreachable = "1.0"
encoding_rs = {version = "0.7", optional = true}
euclid = "0.19"
fallible = { path = "../fallible" }
fnv = "1.0"
fxhash = "0.2"
hashglobe = { path = "../hashglobe" }
html5ever = {version = "0.22", optional = true}
itertools = "0.7.6"
@ -65,6 +65,7 @@ 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"

View file

@ -120,7 +120,6 @@ mod bindings {
let mut file = File::open(&path).unwrap();
let mut content = String::new();
file.read_to_string(&mut content).unwrap();
println!("cargo:rerun-if-changed={}", path.to_str().unwrap());
added_paths.insert(path);
// Find all includes and add them recursively
for cap in INCLUDE_RE.captures_iter(&content) {
@ -286,6 +285,7 @@ mod bindings {
);
},
};
for fixup in fixups.iter() {
result = Regex::new(&fixup.pat)
.unwrap()
@ -602,6 +602,10 @@ mod bindings {
generate_bindings(),
generate_atoms(),
}
for path in ADDED_PATHS.lock().unwrap().iter() {
println!("cargo:rerun-if-changed={}", path.to_str().unwrap());
}
}
}

View file

@ -0,0 +1,26 @@
header = """/* 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/. */"""
autogen_warning = """/* DO NOT MODIFY THIS MANUALLY! This file was generated using cbindgen.
* To generate this file:
* 1. Get the latest cbindgen using `cargo install --force cbindgen`
* a. Alternatively, you can clone `https://github.com/eqrion/cbindgen` and use a tagged release
* 2. Run `rustup run nightly cbindgen toolkit/library/rust/ --lockfile Cargo.lock --crate style -o layout/style/ServoStyleConsts.h`
*/"""
include_version = true
braces = "SameLine"
line_length = 80
tab_width = 2
language = "C++"
namespaces = ["mozilla"]
[struct]
derive_eq = true
[enum]
derive_helper_methods = true
[export]
prefix = "Style"
include = ["StyleDisplay", "StyleAppearance"]
item_types = ["enums"]

View file

@ -14,8 +14,8 @@ use dom::{SendElement, TElement};
use dom::OpaqueNode;
use euclid::Size2D;
use euclid::TypedScale;
use fnv::FnvHashMap;
use font_metrics::FontMetricsProvider;
use fxhash::FxHashMap;
#[cfg(feature = "gecko")]
use gecko_bindings::structs;
use parallel::{STACK_SAFETY_MARGIN_KB, STYLE_THREAD_STACK_SIZE_KB};
@ -173,11 +173,11 @@ pub struct SharedStyleContext<'a> {
/// The animations that are currently running.
#[cfg(feature = "servo")]
pub running_animations: Arc<RwLock<FnvHashMap<OpaqueNode, Vec<Animation>>>>,
pub running_animations: Arc<RwLock<FxHashMap<OpaqueNode, Vec<Animation>>>>,
/// The list of animations that have expired since the last style recalculation.
#[cfg(feature = "servo")]
pub expired_animations: Arc<RwLock<FnvHashMap<OpaqueNode, Vec<Animation>>>>,
pub expired_animations: Arc<RwLock<FxHashMap<OpaqueNode, Vec<Animation>>>>,
/// Paint worklets
#[cfg(feature = "servo")]
@ -570,7 +570,7 @@ type CacheItem<E> = (SendElement<E>, ElementSelectorFlags);
/// flags until after the traversal.
pub struct SelectorFlagsMap<E: TElement> {
/// The hashmap storing the flags to apply.
map: FnvHashMap<SendElement<E>, ElementSelectorFlags>,
map: FxHashMap<SendElement<E>, ElementSelectorFlags>,
/// An LRU cache to avoid hashmap lookups, which can be slow if the map
/// gets big.
cache: LRUCache<[Entry<CacheItem<E>>; 4 + 1]>,
@ -587,7 +587,7 @@ impl<E: TElement> SelectorFlagsMap<E> {
/// Creates a new empty SelectorFlagsMap.
pub fn new() -> Self {
SelectorFlagsMap {
map: FnvHashMap::default(),
map: FxHashMap::default(),
cache: LRUCache::default(),
}
}
@ -833,7 +833,7 @@ pub trait RegisteredSpeculativePainter: SpeculativePainter {
/// The name it was registered with
fn name(&self) -> Atom;
/// The properties it was registered with
fn properties(&self) -> &FnvHashMap<Atom, PropertyId>;
fn properties(&self) -> &FxHashMap<Atom, PropertyId>;
}
/// A set of registered painters

View file

@ -16,7 +16,6 @@ use selector_parser::{PseudoElement, RestyleDamage, EAGER_PSEUDO_COUNT};
use selectors::NthIndexCache;
use servo_arc::Arc;
use shared_lock::StylesheetGuards;
use smallvec::SmallVec;
use std::fmt;
use std::mem;
use std::ops::{Deref, DerefMut};
@ -273,16 +272,8 @@ impl ElementData {
return InvalidationResult::empty();
}
let mut non_document_styles = SmallVec::<[_; 3]>::new();
let matches_doc_author_rules =
element.each_applicable_non_document_style_rule_data(|data, quirks_mode, host| {
non_document_styles.push((data, quirks_mode, host.map(|h| h.opaque())))
});
let mut processor = StateAndAttrInvalidationProcessor::new(
shared_context,
&non_document_styles,
matches_doc_author_rules,
element,
self,
nth_index_cache,

View file

@ -17,6 +17,7 @@ use gecko_bindings::structs::{nsCSSKTableEntry, nsCSSKeyword, nsCSSUnit, nsCSSVa
use gecko_bindings::structs::{nsMediaFeature, nsMediaFeature_RangeType};
use gecko_bindings::structs::{nsMediaFeature_ValueType, nsPresContext};
use gecko_bindings::structs::RawGeckoPresContextOwned;
use gecko_bindings::structs::nsCSSKeywordAndBoolTableEntry;
use media_queries::MediaType;
use parser::{Parse, ParserContext};
use properties::ComputedValues;
@ -374,6 +375,9 @@ pub enum MediaExpressionValue {
/// An enumerated value, defined by the variant keyword table in the
/// feature's `mData` member.
Enumerated(i16),
/// Similar to the above Enumerated but the variant keyword table has an
/// additional field what the keyword value means in the Boolean Context.
BoolEnumerated(i16),
/// An identifier.
Ident(Atom),
}
@ -420,6 +424,10 @@ impl MediaExpressionValue {
let value = css_value.integer_unchecked() as i16;
Some(MediaExpressionValue::Enumerated(value))
},
nsMediaFeature_ValueType::eBoolEnumerated => {
let value = css_value.integer_unchecked() as i16;
Some(MediaExpressionValue::BoolEnumerated(value))
},
nsMediaFeature_ValueType::eIdent => {
debug_assert_eq!(css_value.mUnit, nsCSSUnit::eCSSUnit_AtomIdent);
Some(MediaExpressionValue::Ident(unsafe {
@ -457,25 +465,43 @@ impl MediaExpressionValue {
MediaExpressionValue::Resolution(ref r) => r.to_css(dest),
MediaExpressionValue::Ident(ref ident) => serialize_atom_identifier(ident, dest),
MediaExpressionValue::Enumerated(value) => unsafe {
let keyword = find_in_table(
*for_expr.feature.mData.mKeywordTable.as_ref(),
|_kw, val| val == value,
|e| e.keyword(),
).expect("Value not found in the keyword table?");
MediaExpressionValue::keyword_to_css(keyword, dest)
},
MediaExpressionValue::BoolEnumerated(value) => unsafe {
let keyword = find_in_table(
*for_expr.feature.mData.mKeywordAndBoolTable.as_ref(),
|_kw, val| val == value,
|e| e.keyword(),
).expect("Value not found in the keyword table?");
MediaExpressionValue::keyword_to_css(keyword, dest)
}
}
}
fn keyword_to_css<W>(keyword: nsCSSKeyword, dest: &mut CssWriter<W>) -> fmt::Result
where
W: fmt::Write,
{
use std::{slice, str};
use std::os::raw::c_char;
// NB: All the keywords on nsMediaFeatures are static,
// well-formed utf-8.
let mut length = 0;
let (keyword, _value) = find_in_table(
*for_expr.feature.mData.mKeywordTable.as_ref(),
|_kw, val| val == value,
).expect("Value not found in the keyword table?");
unsafe {
let buffer: *const c_char = bindings::Gecko_CSSKeywordString(keyword, &mut length);
let buffer = slice::from_raw_parts(buffer as *const u8, length as usize);
let string = str::from_utf8_unchecked(buffer);
dest.write_str(string)
},
}
}
}
@ -496,23 +522,51 @@ where
None
}
unsafe fn find_in_table<F>(
mut current_entry: *const nsCSSKTableEntry,
mut f: F,
) -> Option<(nsCSSKeyword, i16)>
trait TableEntry {
fn value(&self) -> i16;
fn keyword(&self) -> nsCSSKeyword;
}
impl TableEntry for nsCSSKTableEntry {
fn value(&self) -> i16 {
self.mValue
}
fn keyword(&self) -> nsCSSKeyword {
self.mKeyword
}
}
impl TableEntry for nsCSSKeywordAndBoolTableEntry {
fn value(&self) -> i16 {
self._base.mValue
}
fn keyword(&self) -> nsCSSKeyword {
self._base.mKeyword
}
}
unsafe fn find_in_table<T, R, FindFunc, ResultFunc>(
current_entry: *const T,
find: FindFunc,
result_func: ResultFunc,
) -> Option<R>
where
F: FnMut(nsCSSKeyword, i16) -> bool,
T: TableEntry,
FindFunc: Fn(nsCSSKeyword, i16) -> bool,
ResultFunc: Fn(&T) -> R,
{
let mut current_entry = current_entry;
loop {
let value = (*current_entry).mValue;
let keyword = (*current_entry).mKeyword;
let value = (*current_entry).value();
let keyword = (*current_entry).keyword();
if value == -1 {
return None; // End of the table.
}
if f(keyword, value) {
return Some((keyword, value));
if find(keyword, value) {
return Some(result_func(&*current_entry));
}
current_entry = current_entry.offset(1);
@ -556,24 +610,21 @@ fn parse_feature_value<'i, 't>(
MediaExpressionValue::Resolution(Resolution::parse(context, input)?)
},
nsMediaFeature_ValueType::eEnumerated => {
let location = input.current_source_location();
let keyword = input.expect_ident()?;
let keyword = unsafe {
bindings::Gecko_LookupCSSKeyword(keyword.as_bytes().as_ptr(), keyword.len() as u32)
};
let first_table_entry: *const nsCSSKTableEntry =
unsafe { *feature.mData.mKeywordTable.as_ref() };
let value = match unsafe { find_in_table(first_table_entry, |kw, _| kw == keyword) } {
Some((_kw, value)) => value,
None => {
return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
},
};
let value = parse_keyword(input, first_table_entry)?;
MediaExpressionValue::Enumerated(value)
},
nsMediaFeature_ValueType::eBoolEnumerated => {
let first_table_entry: *const nsCSSKeywordAndBoolTableEntry =
unsafe { *feature.mData.mKeywordAndBoolTable.as_ref() };
let value = parse_keyword(input, first_table_entry)?;
MediaExpressionValue::BoolEnumerated(value)
},
nsMediaFeature_ValueType::eIdent => {
MediaExpressionValue::Ident(Atom::from(input.expect_ident()?.as_ref()))
},
@ -582,6 +633,30 @@ fn parse_feature_value<'i, 't>(
Ok(value)
}
/// Parse a keyword and returns the corresponding i16 value.
fn parse_keyword<'i, 't, T>(
input: &mut Parser<'i, 't>,
first_table_entry: *const T,
) -> Result<i16, ParseError<'i>>
where
T: TableEntry,
{
let location = input.current_source_location();
let keyword = input.expect_ident()?;
let keyword = unsafe {
bindings::Gecko_LookupCSSKeyword(keyword.as_bytes().as_ptr(), keyword.len() as u32)
};
let value = unsafe {
find_in_table(first_table_entry, |kw, _| kw == keyword, |e| e.value())
};
match value {
Some(value) => Ok(value),
None => Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError)),
}
}
/// Consumes an operation or a colon, or returns an error.
fn consume_operation_or_colon(
input: &mut Parser,
@ -834,6 +909,16 @@ impl MediaFeatureExpression {
quirks_mode,
|context| l.to_computed_value(&context).px() != 0.,
),
BoolEnumerated(value) => {
let value = unsafe {
find_in_table(
*self.feature.mData.mKeywordAndBoolTable.as_ref(),
|_kw, val| val == value,
|e| e.mValueInBooleanContext,
)
};
value.expect("Value not found in the keyword table?")
},
_ => true,
};
},
@ -880,6 +965,13 @@ impl MediaFeatureExpression {
);
return one == other;
},
(&BoolEnumerated(one), &BoolEnumerated(other)) => {
debug_assert_ne!(
self.feature.mRangeType,
nsMediaFeature_RangeType::eMinMaxAllowed
);
return one == other;
},
_ => unreachable!(),
};

View file

@ -15,6 +15,7 @@ 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!(
@ -161,15 +162,6 @@ impl PseudoElement {
self.is_anon_box() && !self.is_tree_pseudo_element()
}
/// Covert non-canonical pseudo-element to canonical one, and keep a
/// canonical one as it is.
pub fn canonical(&self) -> PseudoElement {
match *self {
PseudoElement::MozPlaceholder => PseudoElement::Placeholder,
_ => self.clone(),
}
}
/// Property flag that properties must have to apply to this pseudo-element.
#[inline]
pub fn property_restriction(&self) -> Option<PropertyFlags> {

View file

@ -8,7 +8,7 @@ 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
@ -112,7 +112,11 @@ impl PseudoElement {
% for pseudo in PSEUDOS:
${pseudo_element_variant(pseudo)} =>
% if pseudo.is_tree_pseudo_element():
0,
if unsafe { structs::StaticPrefs_sVarCache_layout_css_xul_tree_pseudos_content_enabled } {
0
} else {
structs::CSS_PSEUDO_ELEMENT_ENABLED_IN_UA_SHEETS_AND_CHROME
},
% elif pseudo.is_anon_box():
structs::CSS_PSEUDO_ELEMENT_ENABLED_IN_UA_SHEETS,
% else:
@ -209,7 +213,7 @@ impl PseudoElement {
% 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
@ -234,6 +238,9 @@ impl PseudoElement {
"-moz-selection" => {
return Some(PseudoElement::Selection);
}
"-moz-placeholder" => {
return Some(PseudoElement::Placeholder);
}
_ => {
// FIXME: -moz-tree check should probably be
// ascii-case-insensitive.
@ -256,7 +263,7 @@ impl PseudoElement {
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

View file

@ -13,11 +13,13 @@ 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::{SelectorParseErrorKind, Visit};
use selectors::parser::{self as selector_parser, Selector};
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;
@ -34,7 +36,7 @@ bitflags! {
}
/// 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),)*],
@ -56,7 +58,7 @@ macro_rules! pseudo_class_name {
///
/// 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>),
}
@ -405,7 +407,7 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
// 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(
@ -422,7 +424,7 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
selector_parser::parse_compound_selector_list(
self,
parser,
)?
)?.into()
)
}
_ => return Err(parser.new_custom_error(
@ -486,9 +488,11 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
}
let args = args.into_boxed_slice();
if let Some(pseudo) = PseudoElement::tree_pseudo_element(&name, args) {
if self.is_pseudo_element_enabled(&pseudo) {
return Ok(pseudo);
}
}
}
Err(
parser.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
name,

View file

@ -156,6 +156,15 @@ impl GeckoElementSnapshot {
}
impl ElementSnapshot for GeckoElementSnapshot {
fn debug_list_attributes(&self) -> String {
use nsstring::nsCString;
let mut string = nsCString::new();
unsafe {
bindings::Gecko_Snapshot_DebugListAttributes(self, &mut string);
}
String::from_utf8_lossy(&*string).into_owned()
}
fn state(&self) -> Option<ElementState> {
if self.has_any(Flags::State) {
Some(ElementState::from_bits_truncate(self.mState))

View file

@ -30,7 +30,7 @@ use gecko::selector_parser::{NonTSPseudoClass, PseudoElement, SelectorImpl};
use gecko::snapshot_helpers;
use gecko_bindings::bindings;
use gecko_bindings::bindings::{Gecko_ElementState, Gecko_GetDocumentLWTheme};
use gecko_bindings::bindings::{Gecko_GetLastChild, Gecko_GetNextStyleChild};
use gecko_bindings::bindings::{Gecko_GetLastChild, Gecko_GetPreviousSibling, Gecko_GetNextStyleChild};
use gecko_bindings::bindings::{Gecko_SetNodeFlags, Gecko_UnsetNodeFlags};
use gecko_bindings::bindings::Gecko_ClassOrClassList;
use gecko_bindings::bindings::Gecko_ElementHasAnimations;
@ -62,7 +62,7 @@ use gecko_bindings::structs::nsChangeHint;
use gecko_bindings::structs::nsIDocument_DocumentTheme as DocumentTheme;
use gecko_bindings::structs::nsRestyleHint;
use gecko_bindings::sugar::ownership::{HasArcFFI, HasSimpleFFI};
use hash::FnvHashMap;
use hash::FxHashMap;
use logical_geometry::WritingMode;
use media_queries::Device;
use properties::{ComputedValues, LonghandId};
@ -375,7 +375,12 @@ impl<'ln> TNode for GeckoNode<'ln> {
#[inline]
fn first_child(&self) -> Option<Self> {
unsafe { self.0.mFirstChild.as_ref().map(GeckoNode::from_content) }
unsafe {
self.0
.mFirstChild.raw::<nsIContent>()
.as_ref()
.map(GeckoNode::from_content)
}
}
#[inline]
@ -385,17 +390,17 @@ impl<'ln> TNode for GeckoNode<'ln> {
#[inline]
fn prev_sibling(&self) -> Option<Self> {
unsafe {
self.0
.mPreviousSibling
.as_ref()
.map(GeckoNode::from_content)
}
unsafe { Gecko_GetPreviousSibling(self.0).map(GeckoNode) }
}
#[inline]
fn next_sibling(&self) -> Option<Self> {
unsafe { self.0.mNextSibling.as_ref().map(GeckoNode::from_content) }
unsafe {
self.0
.mNextSibling.raw::<nsIContent>()
.as_ref()
.map(GeckoNode::from_content)
}
}
#[inline]
@ -562,28 +567,15 @@ pub struct GeckoElement<'le>(pub &'le RawGeckoElement);
impl<'le> fmt::Debug for GeckoElement<'le> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use nsstring::nsCString;
write!(f, "<{}", self.local_name())?;
if let Some(id) = self.id() {
write!(f, " id={}", id)?;
}
let mut first = true;
let mut any = false;
self.each_class(|c| {
if first {
first = false;
any = true;
let _ = f.write_str(" class=\"");
} else {
let _ = f.write_str(" ");
let mut attrs = nsCString::new();
unsafe {
bindings::Gecko_Element_DebugListAttributes(self.0, &mut attrs);
}
let _ = write!(f, "{}", c);
});
if any {
f.write_str("\"")?;
}
write!(f, "{}", attrs)?;
write!(f, "> ({:#x})", self.as_node().opaque().0)
}
}
@ -867,12 +859,12 @@ impl<'le> GeckoElement<'le> {
}
}
fn css_transitions_info(&self) -> FnvHashMap<LonghandId, Arc<AnimationValue>> {
fn css_transitions_info(&self) -> FxHashMap<LonghandId, Arc<AnimationValue>> {
use gecko_bindings::bindings::Gecko_ElementTransitions_EndValueAt;
use gecko_bindings::bindings::Gecko_ElementTransitions_Length;
let collection_length = unsafe { Gecko_ElementTransitions_Length(self.0) } as usize;
let mut map = FnvHashMap::with_capacity_and_hasher(collection_length, Default::default());
let mut map = FxHashMap::with_capacity_and_hasher(collection_length, Default::default());
for i in 0..collection_length {
let raw_end_value = unsafe { Gecko_ElementTransitions_EndValueAt(self.0, i) };
@ -893,7 +885,7 @@ impl<'le> GeckoElement<'le> {
combined_duration: f32,
before_change_style: &ComputedValues,
after_change_style: &ComputedValues,
existing_transitions: &FnvHashMap<LonghandId, Arc<AnimationValue>>,
existing_transitions: &FxHashMap<LonghandId, Arc<AnimationValue>>,
) -> bool {
use values::animated::{Animate, Procedure};
debug_assert!(!longhand_id.is_logical());
@ -1967,30 +1959,6 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
unsafe { Some(GeckoElement(&slot.as_ref()?._base._base._base._base)) }
}
#[inline]
fn first_child_element(&self) -> Option<Self> {
let mut child = self.as_node().first_child();
while let Some(child_node) = child {
if let Some(el) = child_node.as_element() {
return Some(el);
}
child = child_node.next_sibling();
}
None
}
#[inline]
fn last_child_element(&self) -> Option<Self> {
let mut child = self.as_node().last_child();
while let Some(child_node) = child {
if let Some(el) = child_node.as_element() {
return Some(el);
}
child = child_node.prev_sibling();
}
None
}
#[inline]
fn prev_sibling_element(&self) -> Option<Self> {
let mut sibling = self.as_node().prev_sibling();
@ -2087,15 +2055,15 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
#[inline]
fn is_root(&self) -> bool {
let parent_node = match self.as_node().parent_node() {
Some(parent_node) => parent_node,
None => return false,
};
if !parent_node.is_document() {
if self.as_node().get_bool_flag(nsINode_BooleanFlag::ParentIsContent) {
return false;
}
if !self.as_node().is_in_document() {
return false;
}
debug_assert!(self.as_node().parent_node().map_or(false, |p| p.is_document()));
unsafe { bindings::Gecko_IsRootElement(self.0) }
}
@ -2280,7 +2248,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
// match the proper pseudo-element, given how we rulehash the stuff
// based on the pseudo.
match self.implemented_pseudo_element() {
Some(ref pseudo) => *pseudo == pseudo_element.canonical(),
Some(ref pseudo) => *pseudo == *pseudo_element,
None => false,
}
}

View file

@ -7,7 +7,7 @@
//! Can go away when the stdlib gets fallible collections
//! https://github.com/rust-lang/rfcs/pull/2116
use fnv;
use fxhash;
#[cfg(feature = "gecko")]
pub use hashglobe::hash_map::HashMap;
@ -25,7 +25,7 @@ pub mod map {
pub use std::collections::hash_map::{Entry, Iter};
}
/// Hash map that uses the FNV hasher
pub type FnvHashMap<K, V> = HashMap<K, V, fnv::FnvBuildHasher>;
/// Hash set that uses the FNV hasher
pub type FnvHashSet<T> = HashSet<T, fnv::FnvBuildHasher>;
/// Hash map that uses the Fx hasher
pub type FxHashMap<K, V> = HashMap<K, V, fxhash::FxBuildHasher>;
/// Hash set that uses the Fx hasher
pub type FxHashSet<T> = HashSet<T, fxhash::FxBuildHasher>;

View file

@ -43,6 +43,11 @@ pub trait ElementSnapshot: Sized {
/// If this snapshot contains attribute information.
fn has_attrs(&self) -> bool;
/// Gets the attribute information of the snapshot as a string.
///
/// Only for debugging purposes.
fn debug_list_attributes(&self) -> String { String::new() }
/// The ID attribute per this snapshot. Should only be called if
/// `has_attrs()` returns true.
fn id_attr(&self) -> Option<&WeakAtom>;
@ -278,16 +283,6 @@ where
Some(Self::new(host, self.snapshot_map))
}
fn first_child_element(&self) -> Option<Self> {
let child = self.element.first_child_element()?;
Some(Self::new(child, self.snapshot_map))
}
fn last_child_element(&self) -> Option<Self> {
let child = self.element.last_child_element()?;
Some(Self::new(child, self.snapshot_map))
}
fn prev_sibling_element(&self) -> Option<Self> {
let sibling = self.element.prev_sibling_element()?;
Some(Self::new(sibling, self.snapshot_map))

View file

@ -6,7 +6,7 @@
//! changes.
use {Atom, WeakAtom};
use context::{QuirksMode, SharedStyleContext};
use context::SharedStyleContext;
use data::ElementData;
use dom::TElement;
use element_state::ElementState;
@ -18,13 +18,11 @@ use invalidation::element::restyle_hints::RestyleHint;
use selector_map::SelectorMap;
use selector_parser::Snapshot;
use selectors::NthIndexCache;
use selectors::OpaqueElement;
use selectors::attr::CaseSensitivity;
use selectors::matching::{MatchingContext, MatchingMode, VisitedHandlingMode};
use selectors::matching::matches_selector;
use smallvec::SmallVec;
use stylesheets::origin::{Origin, OriginSet};
use stylist::CascadeData;
#[derive(Debug, PartialEq)]
enum VisitedDependent {
@ -56,19 +54,15 @@ where
/// changes.
pub struct StateAndAttrInvalidationProcessor<'a, 'b: 'a, E: TElement> {
shared_context: &'a SharedStyleContext<'b>,
shadow_rule_datas: &'a [(&'b CascadeData, QuirksMode, Option<OpaqueElement>)],
matches_document_author_rules: bool,
element: E,
data: &'a mut ElementData,
matching_context: MatchingContext<'a, E::Impl>,
}
impl<'a, 'b: 'a, E: TElement> StateAndAttrInvalidationProcessor<'a, 'b, E> {
impl<'a, 'b: 'a, E: TElement + 'b> StateAndAttrInvalidationProcessor<'a, 'b, E> {
/// Creates a new StateAndAttrInvalidationProcessor.
pub fn new(
shared_context: &'a SharedStyleContext<'b>,
shadow_rule_datas: &'a [(&'b CascadeData, QuirksMode, Option<OpaqueElement>)],
matches_document_author_rules: bool,
element: E,
data: &'a mut ElementData,
nth_index_cache: &'a mut NthIndexCache,
@ -83,8 +77,6 @@ impl<'a, 'b: 'a, E: TElement> StateAndAttrInvalidationProcessor<'a, 'b, E> {
Self {
shared_context,
shadow_rule_datas,
matches_document_author_rules,
element,
data,
matching_context,
@ -157,6 +149,7 @@ where
descendant_invalidations: &mut DescendantInvalidationLists<'a>,
sibling_invalidations: &mut InvalidationVector<'a>,
) -> bool {
debug_assert_eq!(element, self.element);
debug_assert!(element.has_snapshot(), "Why bothering?");
let wrapper = ElementWrapper::new(element, &*self.shared_context.snapshot_map);
@ -208,20 +201,32 @@ where
}
}
if log_enabled!(::log::Level::Debug) {
debug!("Collecting changes for: {:?}", element);
if !state_changes.is_empty() {
debug!(" > state: {:?}", state_changes);
}
if snapshot.id_changed() {
debug!(
" > id changed: {:?} -> +{:?} -{:?}",
snapshot.id_changed(),
" > id changed: +{:?} -{:?}",
id_added,
id_removed
);
}
if snapshot.class_changed() {
debug!(
" > class changed: {:?} -> +{:?} -{:?}",
snapshot.class_changed(),
" > class changed: +{:?} -{:?}",
classes_added,
classes_removed
);
}
if snapshot.other_attr_changed() {
debug!(
" > attributes changed, old: {}",
snapshot.debug_list_attributes()
)
}
}
let lookup_element = if element.implemented_pseudo_element().is_some() {
element.pseudo_element_originating_element().unwrap()
@ -229,6 +234,13 @@ where
element
};
let mut shadow_rule_datas = SmallVec::<[_; 3]>::new();
let matches_document_author_rules =
element.each_applicable_non_document_style_rule_data(|data, quirks_mode, host| {
shadow_rule_datas.push((data, quirks_mode, host.map(|h| h.opaque())))
});
let invalidated_self = {
let mut collector = Collector {
wrapper,
@ -246,7 +258,7 @@ where
invalidates_self: false,
};
let document_origins = if !self.matches_document_author_rules {
let document_origins = if !matches_document_author_rules {
Origin::UserAgent.into()
} else {
OriginSet::all()
@ -259,7 +271,7 @@ where
}
}
for &(ref data, quirks_mode, ref host) in self.shadow_rule_datas {
for &(ref data, quirks_mode, ref host) in &shadow_rule_datas {
// FIXME(emilio): Replace with assert / remove when we figure
// out what to do with the quirks mode mismatches
// (that is, when bug 1406875 is properly fixed).

View file

@ -5,7 +5,7 @@
//! Code related to the invalidation of media-query-affected rules.
use context::QuirksMode;
use fnv::FnvHashSet;
use fxhash::FxHashSet;
use media_queries::Device;
use shared_lock::SharedRwLockReadGuard;
use stylesheets::{DocumentRule, ImportRule, MediaRule};
@ -54,14 +54,14 @@ impl ToMediaListKey for MediaRule {}
#[derive(Debug, MallocSizeOf, PartialEq)]
pub struct EffectiveMediaQueryResults {
/// The set of media lists that matched last time.
set: FnvHashSet<MediaListKey>,
set: FxHashSet<MediaListKey>,
}
impl EffectiveMediaQueryResults {
/// Trivially constructs an empty `EffectiveMediaQueryResults`.
pub fn new() -> Self {
Self {
set: FnvHashSet::default(),
set: FxHashSet::default(),
}
}

View file

@ -11,7 +11,7 @@ use Atom;
use CaseSensitivityExt;
use LocalName as SelectorLocalName;
use dom::{TDocument, TElement, TNode};
use fnv::FnvHashSet;
use fxhash::FxHashSet;
use invalidation::element::element_wrapper::{ElementSnapshot, ElementWrapper};
use invalidation::element::restyle_hints::RestyleHint;
use media_queries::Device;
@ -106,9 +106,9 @@ impl Invalidation {
#[derive(MallocSizeOf)]
pub struct StylesheetInvalidationSet {
/// The subtrees we know we have to restyle so far.
invalid_scopes: FnvHashSet<Invalidation>,
invalid_scopes: FxHashSet<Invalidation>,
/// The elements we know we have to restyle so far.
invalid_elements: FnvHashSet<Invalidation>,
invalid_elements: FxHashSet<Invalidation>,
/// Whether the whole document should be restyled.
fully_invalid: bool,
}
@ -117,8 +117,8 @@ impl StylesheetInvalidationSet {
/// Create an empty `StylesheetInvalidationSet`.
pub fn new() -> Self {
Self {
invalid_scopes: FnvHashSet::default(),
invalid_elements: FnvHashSet::default(),
invalid_scopes: FxHashSet::default(),
invalid_elements: FxHashSet::default(),
fully_invalid: false,
}
}

View file

@ -42,7 +42,7 @@ extern crate cssparser;
extern crate debug_unreachable;
extern crate euclid;
extern crate fallible;
extern crate fnv;
extern crate fxhash;
#[cfg(feature = "gecko")]
#[macro_use]
pub mod gecko_string_cache;
@ -93,6 +93,8 @@ extern crate string_cache;
#[macro_use]
extern crate style_derive;
extern crate style_traits;
#[cfg(feature = "gecko")]
extern crate thin_slice;
extern crate time;
extern crate uluru;
extern crate unicode_bidi;

View file

@ -368,6 +368,34 @@ def set_gecko_property(ffi_name, expr):
return "self.gecko.%s = %s;" % (ffi_name, expr)
%>
<%def name="impl_cbindgen_keyword(ident, gecko_ffi_name)">
#[allow(non_snake_case)]
#[inline]
pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
// unsafe: cbindgen ensures the representations match.
${set_gecko_property(gecko_ffi_name, "unsafe { transmute(v) }")}
}
#[allow(non_snake_case)]
#[inline]
pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
// unsafe: cbindgen ensures the representations match.
unsafe { transmute(${get_gecko_property(gecko_ffi_name)}) }
}
#[allow(non_snake_case)]
#[inline]
pub fn copy_${ident}_from(&mut self, other: &Self) {
self.gecko.${gecko_ffi_name} = other.gecko.${gecko_ffi_name};
}
#[allow(non_snake_case)]
#[inline]
pub fn reset_${ident}(&mut self, other: &Self) {
self.copy_${ident}_from(other)
}
</%def>
<%def name="impl_keyword_setter(ident, gecko_ffi_name, keyword, cast_type='u8', on_set=None)">
#[allow(non_snake_case)]
pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
@ -3015,7 +3043,7 @@ fn static_assert() {
}
</%def>
<% skip_box_longhands= """display overflow-y vertical-align
<% skip_box_longhands= """display -moz-appearance overflow-y vertical-align
animation-name animation-delay animation-duration
animation-direction animation-fill-mode animation-play-state
animation-iteration-count animation-timing-function
@ -3031,57 +3059,41 @@ fn static_assert() {
shape-outside contain touch-action translate
scale""" %>
<%self:impl_trait style_struct_name="Box" skip_longhands="${skip_box_longhands}">
// We manually-implement the |display| property until we get general
// infrastructure for preffing certain values.
<% display_keyword = Keyword("display", "inline block inline-block table inline-table table-row-group " +
"table-header-group table-footer-group table-row table-column-group " +
"table-column table-cell table-caption list-item flex none " +
"inline-flex grid inline-grid ruby ruby-base ruby-base-container " +
"ruby-text ruby-text-container contents flow-root -webkit-box " +
"-webkit-inline-box -moz-box -moz-inline-box -moz-grid -moz-inline-grid " +
"-moz-grid-group -moz-grid-line -moz-stack -moz-inline-stack -moz-deck " +
"-moz-popup -moz-groupbox",
gecko_enum_prefix="StyleDisplay",
gecko_strip_moz_prefix=False) %>
fn match_display_keyword(
v: longhands::display::computed_value::T
) -> structs::root::mozilla::StyleDisplay {
use properties::longhands::display::computed_value::T as Keyword;
// FIXME(bholley): Align binary representations and ditch |match| for cast + static_asserts
match v {
% for value in display_keyword.values_for('gecko'):
Keyword::${to_camel_case(value)} =>
structs::${display_keyword.gecko_constant(value)},
% endfor
}
}
#[inline]
pub fn set_display(&mut self, v: longhands::display::computed_value::T) {
let result = Self::match_display_keyword(v);
self.gecko.mDisplay = result;
self.gecko.mOriginalDisplay = result;
// unsafe: cbindgen ensures the representation is the same.
self.gecko.mDisplay = unsafe { transmute(v) };
self.gecko.mOriginalDisplay = unsafe { transmute(v) };
}
#[inline]
pub fn copy_display_from(&mut self, other: &Self) {
self.gecko.mDisplay = other.gecko.mDisplay;
self.gecko.mOriginalDisplay = other.gecko.mDisplay;
}
#[inline]
pub fn reset_display(&mut self, other: &Self) {
self.copy_display_from(other)
}
#[inline]
pub fn set_adjusted_display(
&mut self,
v: longhands::display::computed_value::T,
_is_item_or_root: bool
) {
self.gecko.mDisplay = Self::match_display_keyword(v);
// unsafe: cbindgen ensures the representation is the same.
self.gecko.mDisplay = unsafe { transmute(v) };
}
<%call expr="impl_keyword_clone('display', 'mDisplay', display_keyword)"></%call>
#[inline]
pub fn clone_display(&self) -> longhands::display::computed_value::T {
// unsafe: cbindgen ensures the representation is the same.
unsafe { transmute(self.gecko.mDisplay) }
}
${impl_cbindgen_keyword('_moz_appearance', 'mAppearance')}
<% float_keyword = Keyword("float", "Left Right None", gecko_enum_prefix="StyleFloat") %>
${impl_keyword('float', 'mFloat', float_keyword)}

View file

@ -25,7 +25,7 @@ use servo_arc::Arc;
use smallvec::SmallVec;
use std::{cmp, ptr};
use std::mem::{self, ManuallyDrop};
use hash::FnvHashMap;
use hash::FxHashMap;
use super::ComputedValues;
use values::CSSFloat;
use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
@ -232,7 +232,7 @@ impl AnimatedProperty {
/// A collection of AnimationValue that were composed on an element.
/// This HashMap stores the values that are the last AnimationValue to be
/// composed for each TransitionProperty.
pub type AnimationValueMap = FnvHashMap<LonghandId, AnimationValue>;
pub type AnimationValueMap = FxHashMap<LonghandId, AnimationValue>;
#[cfg(feature = "gecko")]
unsafe impl HasFFI for AnimationValueMap {

View file

@ -508,41 +508,15 @@ ${helpers.predefined_type("contain",
spec="https://drafts.csswg.org/css-contain/#contain-property")}
// Non-standard
${helpers.single_keyword("-moz-appearance",
"""none button button-arrow-down button-arrow-next button-arrow-previous button-arrow-up
button-bevel button-focus caret checkbox checkbox-container checkbox-label checkmenuitem
dialog dualbutton groupbox inner-spin-button listbox listitem menuarrow menubar menucheckbox
menuimage menuitem menuitemtext menulist menulist-button menulist-text menulist-textfield
menupopup menuradio menuseparator meterbar meterchunk number-input progressbar
progressbar-vertical progresschunk progresschunk-vertical radio radio-container radio-label
radiomenuitem range range-thumb resizer resizerpanel scale-horizontal scalethumbend
scalethumb-horizontal scalethumbstart scalethumbtick scalethumb-vertical scale-vertical
scrollbar scrollbar-horizontal scrollbar-small scrollbar-vertical scrollbarbutton-down
scrollbarbutton-left scrollbarbutton-right scrollbarbutton-up scrollbarthumb-horizontal
scrollbarthumb-vertical scrollbartrack-horizontal scrollbartrack-vertical scrollcorner
searchfield separator
spinner spinner-downbutton spinner-textfield spinner-upbutton splitter statusbar
statusbarpanel tab tabpanel tabpanels tab-scroll-arrow-back tab-scroll-arrow-forward
textfield textfield-multiline toolbar toolbarbutton toolbarbutton-dropdown toolbargripper
toolbox tooltip treeheader treeheadercell treeheadersortarrow treeitem treeline treetwisty
treetwistyopen treeview window
-moz-gtk-info-bar -moz-mac-active-source-list-selection -moz-mac-disclosure-button-closed
-moz-mac-disclosure-button-open -moz-mac-fullscreen-button -moz-mac-help-button
-moz-mac-source-list -moz-mac-source-list-selection -moz-mac-vibrancy-dark
-moz-mac-vibrancy-light -moz-mac-vibrant-titlebar-light -moz-mac-vibrant-titlebar-dark
-moz-win-borderless-glass -moz-win-browsertabbar-toolbox
-moz-win-communications-toolbox -moz-win-exclude-glass -moz-win-glass -moz-win-media-toolbox
-moz-window-button-box -moz-window-button-box-maximized -moz-window-button-close
-moz-window-button-maximize -moz-window-button-minimize -moz-window-button-restore
-moz-window-frame-bottom -moz-window-frame-left -moz-window-frame-right -moz-window-titlebar
-moz-window-titlebar-maximized
""",
gecko_ffi_name="mAppearance",
gecko_constant_prefix="ThemeWidgetType_NS_THEME",
${helpers.predefined_type(
"-moz-appearance",
"Appearance",
"computed::Appearance::None",
products="gecko",
alias="-webkit-appearance:layout.css.webkit-appearance.enabled",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-appearance)",
animation_value_type="discrete")}
animation_value_type="discrete",
)}
${helpers.predefined_type("-moz-binding", "url::UrlOrNone", "computed::url::UrlOrNone::none()",
products="gecko",

View file

@ -410,22 +410,41 @@ pub mod animated_properties {
#[derive(Clone, Copy, Debug)]
pub struct NonCustomPropertyId(usize);
% if product == "gecko":
#[allow(dead_code)]
unsafe fn static_assert_nscsspropertyid() {
% for i, property in enumerate(data.longhands + data.shorthands + data.all_aliases()):
::std::mem::transmute::<[u8; ${i}], [u8; ${property.nscsspropertyid()} as usize]>([0; ${i}]); // ${property.name}
% endfor
}
% endif
impl NonCustomPropertyId {
#[cfg(feature = "gecko")]
#[inline]
fn to_nscsspropertyid(self) -> nsCSSPropertyID {
static MAP: [nsCSSPropertyID; ${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())}] = [
% for property in data.longhands + data.shorthands + data.all_aliases():
${property.nscsspropertyid()},
% endfor
];
// unsafe: guaranteed by static_assert_nscsspropertyid above.
unsafe { ::std::mem::transmute(self.0 as i32) }
}
MAP[self.0]
/// Convert an `nsCSSPropertyID` into a `NonCustomPropertyId`.
#[cfg(feature = "gecko")]
#[inline]
pub fn from_nscsspropertyid(prop: nsCSSPropertyID) -> Result<Self, ()> {
let prop = prop as i32;
if prop < 0 {
return Err(());
}
if prop >= ${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())} {
return Err(());
}
// unsafe: guaranteed by static_assert_nscsspropertyid above.
Ok(unsafe { ::std::mem::transmute(prop as usize) })
}
/// Get the property name.
#[inline]
fn name(self) -> &'static str {
pub fn name(self) -> &'static str {
static MAP: [&'static str; ${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())}] = [
% for property in data.longhands + data.shorthands + data.all_aliases():
"${property.name}",
@ -464,7 +483,7 @@ impl NonCustomPropertyId {
PREFS.get(pref).as_boolean().unwrap_or(false)
% else:
unsafe { structs::nsCSSProps_gPropertyEnabled[self.to_nscsspropertyid() as usize] }
unsafe { structs::nsCSSProps_gPropertyEnabled[self.0] }
% endif
};
@ -585,6 +604,31 @@ impl NonCustomPropertyId {
];
COLLECT_FUNCTIONS[self.0](f);
}
/// Turns this `NonCustomPropertyId` into a `PropertyId`.
#[inline]
pub fn to_property_id(self) -> PropertyId {
use std::mem::transmute;
if self.0 < ${len(data.longhands)} {
return unsafe {
PropertyId::Longhand(transmute(self.0 as u16))
}
}
if self.0 < ${len(data.longhands) + len(data.shorthands)} {
return unsafe {
PropertyId::Shorthand(transmute((self.0 - ${len(data.longhands)}) as u16))
}
}
assert!(self.0 < ${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())});
let alias_id: AliasId = unsafe {
transmute((self.0 - ${len(data.longhands) + len(data.shorthands)}) as u16)
};
match alias_id.aliased_property() {
AliasedPropertyId::Longhand(longhand) => PropertyId::LonghandAlias(longhand, alias_id),
AliasedPropertyId::Shorthand(shorthand) => PropertyId::ShorthandAlias(shorthand, alias_id),
}
}
}
impl From<LonghandId> for NonCustomPropertyId {
@ -1237,10 +1281,11 @@ where
/// An identifier for a given shorthand property.
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
#[repr(u16)]
pub enum ShorthandId {
% for property in data.shorthands:
% for i, property in enumerate(data.shorthands):
/// ${property.name}
${property.camel_case},
${property.camel_case} = ${i},
% endfor
}
@ -1767,42 +1812,11 @@ impl PropertyId {
}
/// Returns a property id from Gecko's nsCSSPropertyID.
///
/// TODO(emilio): We should be able to make this a single integer cast to
/// `NonCustomPropertyId`.
#[cfg(feature = "gecko")]
#[allow(non_upper_case_globals)]
#[inline]
pub fn from_nscsspropertyid(id: nsCSSPropertyID) -> Result<Self, ()> {
use gecko_bindings::structs::*;
match id {
% for property in data.longhands:
${property.nscsspropertyid()} => {
Ok(PropertyId::Longhand(LonghandId::${property.camel_case}))
}
% for alias in property.alias:
${alias.nscsspropertyid()} => {
Ok(PropertyId::LonghandAlias(
LonghandId::${property.camel_case},
AliasId::${alias.camel_case}
))
}
% endfor
% endfor
% for property in data.shorthands:
${property.nscsspropertyid()} => {
Ok(PropertyId::Shorthand(ShorthandId::${property.camel_case}))
}
% for alias in property.alias:
${alias.nscsspropertyid()} => {
Ok(PropertyId::ShorthandAlias(
ShorthandId::${property.camel_case},
AliasId::${alias.camel_case}
))
}
% endfor
% endfor
_ => Err(())
}
Ok(NonCustomPropertyId::from_nscsspropertyid(id)?.to_property_id())
}
/// Returns true if the property is a shorthand or shorthand alias.
@ -1858,6 +1872,18 @@ impl PropertyId {
id.enabled_for_all_content()
}
/// Converts this PropertyId in nsCSSPropertyID, resolving aliases to the
/// resolved property, and returning eCSSPropertyExtra_variable for custom
/// properties.
#[cfg(feature = "gecko")]
#[inline]
pub fn to_nscsspropertyid_resolving_aliases(&self) -> nsCSSPropertyID {
match self.non_custom_non_alias_id() {
Some(id) => id.to_nscsspropertyid(),
None => nsCSSPropertyID::eCSSPropertyExtra_variable,
}
}
fn allowed_in(&self, context: &ParserContext) -> bool {
let id = match self.non_custom_id() {
// Custom properties are allowed everywhere
@ -2387,7 +2413,7 @@ pub use gecko_properties::style_structs;
/// The module where all the style structs are defined.
#[cfg(feature = "servo")]
pub mod style_structs {
use fnv::FnvHasher;
use fxhash::FxHasher;
use super::longhands;
use std::hash::{Hash, Hasher};
use logical_geometry::WritingMode;
@ -2534,7 +2560,7 @@ pub mod style_structs {
pub fn compute_font_hash(&mut self) {
// Corresponds to the fields in
// `gfx::font_template::FontTemplateDescriptor`.
let mut hasher: FnvHasher = Default::default();
let mut hasher: FxHasher = Default::default();
self.font_weight.hash(&mut hasher);
self.font_stretch.hash(&mut hasher);
self.font_style.hash(&mut hasher);
@ -4230,6 +4256,7 @@ pub fn adjust_border_width(style: &mut StyleBuilder) {
/// An identifier for a given alias property.
#[derive(Clone, Copy, Eq, PartialEq)]
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
#[repr(u16)]
pub enum AliasId {
% for i, property in enumerate(data.all_aliases()):
/// ${property.name}
@ -4237,17 +4264,38 @@ pub enum AliasId {
% endfor
}
#[derive(Clone, Copy, Eq, PartialEq)]
enum AliasedPropertyId {
#[allow(dead_code)] // Servo doesn't have aliased shorthands.
Shorthand(ShorthandId),
Longhand(LonghandId),
}
impl fmt::Debug for AliasId {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
let name = match *self {
% for property in data.all_aliases():
AliasId::${property.camel_case} => "${property.camel_case}",
% endfor
};
let name = NonCustomPropertyId::from(*self).name();
formatter.write_str(name)
}
}
impl AliasId {
/// Returns the property we're aliasing, as a longhand or a shorthand.
#[inline]
fn aliased_property(self) -> AliasedPropertyId {
static MAP: [AliasedPropertyId; ${len(data.all_aliases())}] = [
% for alias in data.all_aliases():
% if alias.original.type() == "longhand":
AliasedPropertyId::Longhand(LonghandId::${alias.original.camel_case}),
% else:
<% assert alias.original.type() == "shorthand" %>
AliasedPropertyId::Shorthand(ShorthandId::${alias.original.camel_case}),
% endif
% endfor
];
MAP[self as usize]
}
}
// NOTE(emilio): Callers are responsible to deal with prefs.
#[macro_export]
macro_rules! css_properties_accessors {

View file

@ -5,7 +5,7 @@
//! A cache from rule node to computed values, in order to cache reset
//! properties.
use fnv::FnvHashMap;
use fxhash::FxHashMap;
use logical_geometry::WritingMode;
use properties::{ComputedValues, StyleBuilder};
use rule_tree::StrongRuleNode;
@ -71,14 +71,14 @@ impl RuleCacheConditions {
/// A TLS cache from rules matched to computed values.
pub struct RuleCache {
// FIXME(emilio): Consider using LRUCache or something like that?
map: FnvHashMap<StrongRuleNode, SmallVec<[(RuleCacheConditions, Arc<ComputedValues>); 1]>>,
map: FxHashMap<StrongRuleNode, SmallVec<[(RuleCacheConditions, Arc<ComputedValues>); 1]>>,
}
impl RuleCache {
/// Creates an empty `RuleCache`.
pub fn new() -> Self {
Self {
map: FnvHashMap::default(),
map: FxHashMap::default(),
}
}

View file

@ -1146,13 +1146,13 @@ impl StrongRuleNode {
unsafe fn assert_free_list_has_no_duplicates_or_null(&self) {
assert!(cfg!(debug_assertions), "This is an expensive check!");
use hash::FnvHashSet;
use hash::FxHashSet;
let me = &*self.ptr();
assert!(me.is_root());
let mut current = self.ptr();
let mut seen = FnvHashSet::default();
let mut seen = FxHashSet::default();
while current != FREE_LIST_SENTINEL {
let next = (*current).next_free.load(Ordering::Relaxed);
assert!(!next.is_null());

View file

@ -96,6 +96,8 @@ pub trait SelectorMapEntry: Sized + Clone {
/// TODO: Tune the initial capacity of the HashMap
#[derive(Debug, MallocSizeOf)]
pub struct SelectorMap<T: 'static> {
/// Rules that have `:root` selectors.
pub root: SmallVec<[T; 1]>,
/// A hash from an ID to rules which contain that ID selector.
pub id_hash: MaybeCaseInsensitiveHashMap<Atom, SmallVec<[T; 1]>>,
/// A hash from a class name to rules which contain that class selector.
@ -104,7 +106,7 @@ pub struct SelectorMap<T: 'static> {
pub local_name_hash: PrecomputedHashMap<LocalName, SmallVec<[T; 1]>>,
/// A hash from namespace to rules which contain that namespace selector.
pub namespace_hash: PrecomputedHashMap<Namespace, SmallVec<[T; 1]>>,
/// Rules that don't have ID, class, or element selectors.
/// All other rules.
pub other: SmallVec<[T; 1]>,
/// The number of entries in this map.
pub count: usize,
@ -124,6 +126,7 @@ impl<T: 'static> SelectorMap<T> {
/// Trivially constructs an empty `SelectorMap`.
pub fn new() -> Self {
SelectorMap {
root: SmallVec::new(),
id_hash: MaybeCaseInsensitiveHashMap::new(),
class_hash: MaybeCaseInsensitiveHashMap::new(),
local_name_hash: HashMap::default(),
@ -135,6 +138,7 @@ impl<T: 'static> SelectorMap<T> {
/// Clears the hashmap retaining storage.
pub fn clear(&mut self) {
self.root.clear();
self.id_hash.clear();
self.class_hash.clear();
self.local_name_hash.clear();
@ -181,6 +185,19 @@ impl SelectorMap<Rule> {
// At the end, we're going to sort the rules that we added, so remember
// where we began.
let init_len = matching_rules_list.len();
if rule_hash_target.is_root() {
SelectorMap::get_matching_rules(
element,
&self.root,
matching_rules_list,
context,
flags_setter,
cascade_level,
shadow_cascade_order,
);
}
if let Some(id) = rule_hash_target.id() {
if let Some(rules) = self.id_hash.get(id, quirks_mode) {
SelectorMap::get_matching_rules(
@ -287,6 +304,7 @@ impl<T: SelectorMapEntry> SelectorMap<T> {
self.count += 1;
let vector = match find_bucket(entry.selector()) {
Bucket::Root => &mut self.root,
Bucket::ID(id) => self.id_hash
.try_entry(id.clone(), quirks_mode)?
.or_insert_with(SmallVec::new),
@ -340,6 +358,14 @@ impl<T: SelectorMapEntry> SelectorMap<T> {
E: TElement,
F: FnMut(&'a T) -> bool,
{
if element.is_root() {
for entry in self.root.iter() {
if !f(&entry) {
return false;
}
}
}
if let Some(id) = element.id() {
if let Some(v) = self.id_hash.get(id, quirks_mode) {
for entry in v.iter() {
@ -444,6 +470,7 @@ impl<T: SelectorMapEntry> SelectorMap<T> {
}
enum Bucket<'a> {
Root,
ID(&'a Atom),
Class(&'a Atom),
LocalName {
@ -456,6 +483,7 @@ enum Bucket<'a> {
fn specific_bucket_for<'a>(component: &'a Component<SelectorImpl>) -> Bucket<'a> {
match *component {
Component::Root => Bucket::Root,
Component::ID(ref id) => Bucket::ID(id),
Component::Class(ref class) => Bucket::Class(class),
Component::LocalName(ref selector) => Bucket::LocalName {
@ -498,14 +526,19 @@ fn find_bucket<'a>(mut iter: SelectorIter<'a, SelectorImpl>) -> Bucket<'a> {
// We basically want to find the most specific bucket,
// where:
//
// id > class > local name > namespace > universal.
// root > id > class > local name > namespace > universal.
//
for ss in &mut iter {
let new_bucket = specific_bucket_for(ss);
match new_bucket {
Bucket::ID(..) => return new_bucket,
Bucket::Class(..) => {
Bucket::Root => return new_bucket,
Bucket::ID(..) => {
current_bucket = new_bucket;
}
Bucket::Class(..) => {
if !matches!(current_bucket, Bucket::ID(..)) {
current_bucket = new_bucket;
}
},
Bucket::LocalName { .. } => {
if matches!(current_bucket, Bucket::Universal | Bucket::Namespace(..)) {

View file

@ -11,7 +11,7 @@ use attr::{AttrIdentifier, AttrValue};
use cssparser::{serialize_identifier, CowRcStr, Parser as CssParser, SourceLocation, ToCss};
use dom::{OpaqueNode, TElement, TNode};
use element_state::{DocumentState, ElementState};
use fnv::FnvHashMap;
use fxhash::FxHashMap;
use invalidation::element::document_state::InvalidationMatchingData;
use invalidation::element::element_wrapper::ElementSnapshot;
use properties::{ComputedValues, PropertyFlags};
@ -617,12 +617,12 @@ impl SelectorImpl {
/// A map from elements to snapshots for the Servo style back-end.
#[derive(Debug)]
pub struct SnapshotMap(FnvHashMap<OpaqueNode, ServoElementSnapshot>);
pub struct SnapshotMap(FxHashMap<OpaqueNode, ServoElementSnapshot>);
impl SnapshotMap {
/// Create a new empty `SnapshotMap`.
pub fn new() -> Self {
SnapshotMap(FnvHashMap::default())
SnapshotMap(FxHashMap::default())
}
/// Get a snapshot given an element.
@ -632,7 +632,7 @@ impl SnapshotMap {
}
impl Deref for SnapshotMap {
type Target = FnvHashMap<OpaqueNode, ServoElementSnapshot>;
type Target = FxHashMap<OpaqueNode, ServoElementSnapshot>;
fn deref(&self) -> &Self::Target {
&self.0

View file

@ -7,7 +7,7 @@ use context::QuirksMode;
use cssparser::{Parser, ParserInput, RuleListParser};
use error_reporting::{ContextualParseError, ParseErrorReporter};
use fallible::FallibleVec;
use fnv::FnvHashMap;
use fxhash::FxHashMap;
use invalidation::media_queries::{MediaListKey, ToMediaListKey};
#[cfg(feature = "gecko")]
use malloc_size_of::{MallocSizeOfOps, MallocUnconditionalShallowSizeOf};
@ -42,7 +42,7 @@ pub struct UserAgentStylesheets {
#[allow(missing_docs)]
pub struct Namespaces {
pub default: Option<Namespace>,
pub prefixes: FnvHashMap<Prefix, Namespace>,
pub prefixes: FxHashMap<Prefix, Namespace>,
}
/// The contents of a given stylesheet. This effectively maps to a

View file

@ -898,7 +898,6 @@ impl Stylist {
where
E: TElement,
{
let pseudo = pseudo.canonical();
debug_assert!(pseudo.is_lazy());
// Apply the selector flags. We should be in sequential mode
@ -1892,7 +1891,7 @@ impl ElementAndPseudoRules {
let map = match pseudo_element {
None => &mut self.element_map,
Some(pseudo) => self.pseudos_map
.get_or_insert_with(&pseudo.canonical(), || Box::new(SelectorMap::new())),
.get_or_insert_with(pseudo, || Box::new(SelectorMap::new())),
};
map.insert(rule, quirks_mode)
@ -1906,7 +1905,7 @@ impl ElementAndPseudoRules {
#[inline]
fn rules(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>> {
match pseudo {
Some(pseudo) => self.pseudos_map.get(&pseudo.canonical()).map(|p| &**p),
Some(pseudo) => self.pseudos_map.get(pseudo).map(|p| &**p),
None => Some(&self.element_map),
}
}
@ -2190,7 +2189,7 @@ impl CascadeData {
precomputed_pseudo_element_decls
.as_mut()
.expect("Expected precomputed declarations for the UA level")
.get_or_insert_with(&pseudo.canonical(), Vec::new)
.get_or_insert_with(pseudo, Vec::new)
.push(ApplicableDeclarationBlock::new(
StyleSource::from_rule(locked.clone()),
self.rules_source_order,

View file

@ -10,7 +10,7 @@ use values::generics::box_::AnimationIterationCount as GenericAnimationIteration
use values::generics::box_::Perspective as GenericPerspective;
use values::generics::box_::VerticalAlign as GenericVerticalAlign;
pub use values::specified::box_::{AnimationName, Contain, Display, OverflowClipBox};
pub use values::specified::box_::{AnimationName, Appearance, Contain, Display, OverflowClipBox};
pub use values::specified::box_::{Clear as SpecifiedClear, Float as SpecifiedFloat};
pub use values::specified::box_::{OverscrollBehavior, ScrollSnapType, TouchAction, TransitionProperty, WillChange};

View file

@ -43,7 +43,7 @@ pub use self::font::{FontFamily, FontLanguageOverride, FontStyle, FontVariantEas
pub use self::font::{FontFeatureSettings, FontVariantLigatures, FontVariantNumeric};
pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextZoom};
pub use self::box_::{AnimationIterationCount, AnimationName, Contain, Display, TransitionProperty};
pub use self::box_::{Clear, Float};
pub use self::box_::{Appearance, Clear, Float};
pub use self::box_::{OverflowClipBox, OverscrollBehavior, Perspective};
pub use self::box_::{ScrollSnapType, TouchAction, VerticalAlign, WillChange};
pub use self::color::{Color, ColorPropertyValue, RGBAColor};

View file

@ -19,12 +19,16 @@ use values::generics::box_::VerticalAlign as GenericVerticalAlign;
use values::specified::{AllowQuirks, Number};
use values::specified::length::{LengthOrPercentage, NonNegativeLength};
fn in_ua_or_chrome_sheet(context: &ParserContext) -> bool {
use stylesheets::Origin;
context.stylesheet_origin == Origin::UserAgent ||
context.chrome_rules_enabled()
}
#[cfg(feature = "gecko")]
fn moz_display_values_enabled(context: &ParserContext) -> bool {
use gecko_bindings::structs;
use stylesheets::Origin;
context.stylesheet_origin == Origin::UserAgent ||
context.chrome_rules_enabled() ||
in_ua_or_chrome_sheet(context) ||
unsafe {
structs::StaticPrefs_sVarCache_layout_css_xul_display_values_content_enabled
}
@ -33,37 +37,48 @@ fn moz_display_values_enabled(context: &ParserContext) -> bool {
#[cfg(feature = "gecko")]
fn moz_box_display_values_enabled(context: &ParserContext) -> bool {
use gecko_bindings::structs;
use stylesheets::Origin;
context.stylesheet_origin == Origin::UserAgent ||
context.chrome_rules_enabled() ||
in_ua_or_chrome_sheet(context) ||
unsafe {
structs::StaticPrefs_sVarCache_layout_css_xul_box_display_values_content_enabled
}
}
/// Defines an elements display type, which consists of
/// the two basic qualities of how an element generates boxes
/// <https://drafts.csswg.org/css-display/#propdef-display>
///
///
/// NOTE(emilio): Order is important in Gecko!
///
/// If you change it, make sure to take a look at the
/// FrameConstructionDataByDisplay stuff (both the XUL and non-XUL version), and
/// ensure it's still correct!
///
/// Also, when you change this from Gecko you may need to regenerate the
/// C++-side bindings (see components/style/cbindgen.toml).
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq,
SpecifiedValueInfo, ToComputedValue, ToCss)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
/// Defines an elements display type, which consists of
/// the two basic qualities of how an element generates boxes
/// <https://drafts.csswg.org/css-display/#propdef-display>
#[repr(u8)]
pub enum Display {
Inline,
None = 0,
Block,
#[cfg(feature = "gecko")]
FlowRoot,
Inline,
InlineBlock,
ListItem,
Table,
InlineTable,
TableRowGroup,
TableColumn,
TableColumnGroup,
TableHeaderGroup,
TableFooterGroup,
TableRow,
TableColumnGroup,
TableColumn,
TableCell,
TableCaption,
ListItem,
None,
#[parse(aliases = "-webkit-flex")]
Flex,
#[parse(aliases = "-webkit-inline-flex")]
@ -85,8 +100,6 @@ pub enum Display {
#[cfg(feature = "gecko")]
Contents,
#[cfg(feature = "gecko")]
FlowRoot,
#[cfg(feature = "gecko")]
WebkitBox,
#[cfg(feature = "gecko")]
WebkitInlineBox,
@ -119,10 +132,10 @@ pub enum Display {
MozDeck,
#[cfg(feature = "gecko")]
#[parse(condition = "moz_display_values_enabled")]
MozPopup,
MozGroupbox,
#[cfg(feature = "gecko")]
#[parse(condition = "moz_display_values_enabled")]
MozGroupbox,
MozPopup,
}
impl Display {
@ -870,3 +883,252 @@ pub enum Clear {
InlineStart,
InlineEnd
}
/// The value for the `appearance` property.
///
/// https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-appearance
///
/// NOTE(emilio): When changing this you may want to regenerate the C++ bindings
/// (see components/style/cbindgen.toml)
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq,
SpecifiedValueInfo, ToCss, ToComputedValue)]
#[repr(u8)]
pub enum Appearance {
/// No appearance at all.
None,
/// A typical dialog button.
Button,
/// Various arrows that go in buttons
ButtonArrowDown,
ButtonArrowNext,
ButtonArrowPrevious,
ButtonArrowUp,
/// A rectangular button that contains complex content
/// like images (e.g. HTML <button> elements)
ButtonBevel,
/// The focus outline box inside of a button.
ButtonFocus,
/// The caret of a text area
Caret,
/// A dual toolbar button (e.g., a Back button with a dropdown)
Dualbutton,
/// A groupbox.
Groupbox,
/// A inner-spin button.
InnerSpinButton,
/// List boxes.
Listbox,
/// A listbox item.
Listitem,
/// Menu Bar background
Menubar,
/// <menu> and <menuitem> appearances
Menuitem,
Checkmenuitem,
Radiomenuitem,
/// For text on non-iconic menuitems only
Menuitemtext,
/// A dropdown list.
Menulist,
/// The dropdown button(s) that open up a dropdown list.
MenulistButton,
/// The text part of a dropdown list, to left of button.
MenulistText,
/// An editable textfield with a dropdown list (a combobox).
MenulistTextfield,
/// Menu Popup background.
Menupopup,
/// menu checkbox/radio appearances
Menucheckbox,
Menuradio,
Menuseparator,
Menuarrow,
/// An image in the menu gutter, like in bookmarks or history.
Menuimage,
/// A horizontal meter bar.
Meterbar,
/// The meter bar's meter indicator.
Meterchunk,
/// The "arrowed" part of the dropdown button that open up a dropdown list.
#[parse(condition = "in_ua_or_chrome_sheet")]
MozMenulistButton,
/// For HTML's <input type=number>
NumberInput,
/// A horizontal progress bar.
Progressbar,
/// The progress bar's progress indicator
Progresschunk,
/// A vertical progress bar.
ProgressbarVertical,
/// A vertical progress chunk.
ProgresschunkVertical,
/// A checkbox element.
Checkbox,
/// A radio element within a radio group.
Radio,
/// A generic container that always repaints on state changes. This is a
/// hack to make XUL checkboxes and radio buttons work.
CheckboxContainer,
RadioContainer,
/// The label part of a checkbox or radio button, used for painting a focus
/// outline.
CheckboxLabel,
RadioLabel,
/// nsRangeFrame and its subparts
Range,
RangeThumb,
/// The resizer background area in a status bar for the resizer widget in
/// the corner of a window.
Resizerpanel,
/// The resizer itself.
Resizer,
/// A slider.
ScaleHorizontal,
ScaleVertical,
/// A slider's thumb.
ScalethumbHorizontal,
ScalethumbVertical,
/// If the platform supports it, the left/right chunks of the slider thumb.
Scalethumbstart,
Scalethumbend,
/// The ticks for a slider.
Scalethumbtick,
/// A scrollbar.
Scrollbar,
/// A small scrollbar.
ScrollbarSmall,
/// The scrollbar slider
ScrollbarHorizontal,
ScrollbarVertical,
/// A scrollbar button (up/down/left/right).
/// Keep these in order (some code casts these values to `int` in order to
/// compare them against each other).
ScrollbarbuttonUp,
ScrollbarbuttonDown,
ScrollbarbuttonLeft,
ScrollbarbuttonRight,
/// The scrollbar thumb.
ScrollbarthumbHorizontal,
ScrollbarthumbVertical,
/// The scrollbar track.
ScrollbartrackHorizontal,
ScrollbartrackVertical,
/// The scroll corner
Scrollcorner,
/// A searchfield.
Searchfield,
/// A separator. Can be horizontal or vertical.
Separator,
/// A spin control (up/down control for time/date pickers).
Spinner,
/// The up button of a spin control.
SpinnerUpbutton,
/// The down button of a spin control.
SpinnerDownbutton,
/// The textfield of a spin control
SpinnerTextfield,
/// A splitter. Can be horizontal or vertical.
Splitter,
/// A status bar in a main application window.
Statusbar,
/// A single pane of a status bar.
Statusbarpanel,
/// A single tab in a tab widget.
Tab,
/// A single pane (inside the tabpanels container).
Tabpanel,
/// The tab panels container.
Tabpanels,
/// The tabs scroll arrows (left/right).
TabScrollArrowBack,
TabScrollArrowForward,
/// A textfield or text area.
Textfield,
/// A multiline text field.
TextfieldMultiline,
/// A toolbar in an application window.
Toolbar,
/// A single toolbar button (with no associated dropdown).
Toolbarbutton,
/// The dropdown portion of a toolbar button
ToolbarbuttonDropdown,
/// The gripper for a toolbar.
Toolbargripper,
/// The toolbox that contains the toolbars.
Toolbox,
/// A tooltip.
Tooltip,
/// A listbox or tree widget header
Treeheader,
/// An individual header cell
Treeheadercell,
/// The sort arrow for a header.
Treeheadersortarrow,
/// A tree item.
Treeitem,
/// A tree widget branch line
Treeline,
/// A tree widget twisty.
Treetwisty,
/// Open tree widget twisty.
Treetwistyopen,
/// A tree widget.
Treeview,
/// Window and dialog backgrounds.
Window,
Dialog,
/// Vista Rebars.
MozWinCommunicationsToolbox,
MozWinMediaToolbox,
MozWinBrowsertabbarToolbox,
/// Vista glass.
MozWinGlass,
MozWinBorderlessGlass,
/// -moz-apperance style used in setting proper glass margins.
MozWinExcludeGlass,
/// Titlebar elements on the Mac.
MozMacFullscreenButton,
/// Mac help button.
MozMacHelpButton,
/// Windows themed window frame elements.
MozWindowButtonBox,
MozWindowButtonBoxMaximized,
MozWindowButtonClose,
MozWindowButtonMaximize,
MozWindowButtonMinimize,
MozWindowButtonRestore,
MozWindowFrameBottom,
MozWindowFrameLeft,
MozWindowFrameRight,
MozWindowTitlebar,
MozWindowTitlebarMaximized,
MozGtkInfoBar,
MozMacActiveSourceListSelection,
MozMacDisclosureButtonClosed,
MozMacDisclosureButtonOpen,
MozMacSourceList,
MozMacSourceListSelection,
MozMacVibrancyDark,
MozMacVibrancyLight,
MozMacVibrantTitlebarDark,
MozMacVibrantTitlebarLight,
/// A non-disappearing scrollbar.
#[css(skip)]
ScrollbarNonDisappearing,
/// A themed focus outline (for outline:auto).
///
/// This isn't exposed to CSS at all, just here for convenience.
#[css(skip)]
FocusOutline,
/// A dummy variant that should be last to let the GTK widget do hackery.
#[css(skip)]
Count,
}

View file

@ -38,7 +38,7 @@ pub use self::font::{FontFamily, FontLanguageOverride, FontStyle, FontVariantEas
pub use self::font::{FontFeatureSettings, FontVariantLigatures, FontVariantNumeric};
pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextZoom};
pub use self::box_::{AnimationIterationCount, AnimationName, Contain, Display};
pub use self::box_::{Clear, Float};
pub use self::box_::{Appearance, Clear, Float};
pub use self::box_::{OverflowClipBox, OverscrollBehavior, Perspective};
pub use self::box_::{ScrollSnapType, TouchAction, TransitionProperty, VerticalAlign, WillChange};
pub use self::color::{Color, ColorPropertyValue, RGBAColor};

View file

@ -8,7 +8,7 @@
//! [position]: https://drafts.csswg.org/css-backgrounds-3/#position
use cssparser::Parser;
use hash::FnvHashMap;
use hash::FxHashMap;
use parser::{Parse, ParserContext};
use selectors::parser::SelectorParseErrorKind;
use servo_arc::Arc;
@ -548,7 +548,7 @@ impl TemplateAreas {
let mut width = 0;
{
let mut row = 0u32;
let mut area_indices = FnvHashMap::<&str, usize>::default();
let mut area_indices = FxHashMap::<&str, usize>::default();
for string in &strings {
let mut current_area_index: Option<usize> = None;
row += 1;

View file

@ -98,7 +98,6 @@ fn test_parse_stylesheet() {
}),
Component::AttributeInNoNamespace {
local_name: local_name!("type"),
local_name_lower: local_name!("type"),
operator: AttrSelectorOperator::Equal,
value: "hidden".to_owned(),
case_sensitivity: ParsedCaseSensitivity::AsciiCaseInsensitive,