mirror of
https://github.com/servo/servo.git
synced 2025-06-19 06:38:59 +01:00
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:
commit
ea86eb64be
51 changed files with 899 additions and 438 deletions
14
Cargo.lock
generated
14
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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>;
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
26
components/style/cbindgen.toml
Normal file
26
components/style/cbindgen.toml
Normal 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"]
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
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(
|
||||
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?");
|
||||
|
||||
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)
|
||||
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;
|
||||
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!(),
|
||||
};
|
||||
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,7 +488,9 @@ 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) {
|
||||
return Ok(pseudo);
|
||||
if self.is_pseudo_element_enabled(&pseudo) {
|
||||
return Ok(pseudo);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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 attrs = nsCString::new();
|
||||
unsafe {
|
||||
bindings::Gecko_Element_DebugListAttributes(self.0, &mut attrs);
|
||||
}
|
||||
|
||||
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 _ = 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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
|||
}
|
||||
}
|
||||
|
||||
debug!("Collecting changes for: {:?}", element);
|
||||
debug!(" > state: {:?}", state_changes);
|
||||
debug!(
|
||||
" > id changed: {:?} -> +{:?} -{:?}",
|
||||
snapshot.id_changed(),
|
||||
id_added,
|
||||
id_removed
|
||||
);
|
||||
debug!(
|
||||
" > class changed: {:?} -> +{:?} -{:?}",
|
||||
snapshot.class_changed(),
|
||||
classes_added,
|
||||
classes_removed
|
||||
);
|
||||
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: +{:?} -{:?}",
|
||||
id_added,
|
||||
id_removed
|
||||
);
|
||||
}
|
||||
if snapshot.class_changed() {
|
||||
debug!(
|
||||
" > 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).
|
||||
|
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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",
|
||||
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")}
|
||||
${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",
|
||||
)}
|
||||
|
||||
${helpers.predefined_type("-moz-binding", "url::UrlOrNone", "computed::url::UrlOrNone::none()",
|
||||
products="gecko",
|
||||
|
|
|
@ -410,25 +410,44 @@ 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}",
|
||||
"${property.name}",
|
||||
% endfor
|
||||
];
|
||||
MAP[self.0]
|
||||
|
@ -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 {
|
||||
|
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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(..)) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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 element’s 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 element’s 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,
|
||||
}
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue