mirror of
https://github.com/servo/servo.git
synced 2025-06-19 14:48: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",
|
"canvas_traits 0.0.1",
|
||||||
"euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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 0.0.1",
|
||||||
"gfx_traits 0.0.1",
|
"gfx_traits 0.0.1",
|
||||||
"html5ever 0.22.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"html5ever 0.22.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1759,6 +1760,7 @@ dependencies = [
|
||||||
"embedder_traits 0.0.1",
|
"embedder_traits 0.0.1",
|
||||||
"euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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 0.0.1",
|
||||||
"gfx_traits 0.0.1",
|
"gfx_traits 0.0.1",
|
||||||
"histogram 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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)",
|
"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)",
|
"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)",
|
"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)",
|
"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)",
|
"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)",
|
"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)",
|
"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)",
|
"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)",
|
"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)",
|
"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)",
|
"precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"servo_arc 0.1.1",
|
"servo_arc 0.1.1",
|
||||||
"smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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]]
|
[[package]]
|
||||||
|
@ -3498,7 +3503,7 @@ dependencies = [
|
||||||
"encoding_rs 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"fallible 0.0.1",
|
"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",
|
"hashglobe 0.1.0",
|
||||||
"html5ever 0.22.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"style_derive 0.0.1",
|
"style_derive 0.0.1",
|
||||||
"style_traits 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)",
|
"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)",
|
"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)",
|
"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)",
|
"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]]
|
[[package]]
|
||||||
name = "thread_local"
|
name = "thread_local"
|
||||||
version = "0.3.5"
|
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 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 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 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_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 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"
|
"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"}
|
canvas_traits = {path = "../canvas_traits"}
|
||||||
euclid = "0.19"
|
euclid = "0.19"
|
||||||
fnv = "1.0"
|
fnv = "1.0"
|
||||||
|
fxhash = "0.2"
|
||||||
gfx = {path = "../gfx"}
|
gfx = {path = "../gfx"}
|
||||||
gfx_traits = {path = "../gfx_traits"}
|
gfx_traits = {path = "../gfx_traits"}
|
||||||
html5ever = "0.22"
|
html5ever = "0.22"
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
use context::LayoutContext;
|
use context::LayoutContext;
|
||||||
use display_list::items::OpaqueNode;
|
use display_list::items::OpaqueNode;
|
||||||
use flow::{Flow, GetBaseFlow};
|
use flow::{Flow, GetBaseFlow};
|
||||||
use fnv::FnvHashMap;
|
use fxhash::FxHashMap;
|
||||||
use ipc_channel::ipc::IpcSender;
|
use ipc_channel::ipc::IpcSender;
|
||||||
use msg::constellation_msg::PipelineId;
|
use msg::constellation_msg::PipelineId;
|
||||||
use opaque_node::OpaqueNodeMethods;
|
use opaque_node::OpaqueNodeMethods;
|
||||||
|
@ -26,8 +26,8 @@ use style::timer::Timer;
|
||||||
pub fn update_animation_state<E>(
|
pub fn update_animation_state<E>(
|
||||||
constellation_chan: &IpcSender<ConstellationMsg>,
|
constellation_chan: &IpcSender<ConstellationMsg>,
|
||||||
script_chan: &IpcSender<ConstellationControlMsg>,
|
script_chan: &IpcSender<ConstellationControlMsg>,
|
||||||
running_animations: &mut FnvHashMap<OpaqueNode, Vec<Animation>>,
|
running_animations: &mut FxHashMap<OpaqueNode, Vec<Animation>>,
|
||||||
expired_animations: &mut FnvHashMap<OpaqueNode, Vec<Animation>>,
|
expired_animations: &mut FxHashMap<OpaqueNode, Vec<Animation>>,
|
||||||
mut newly_transitioning_nodes: Option<&mut Vec<UntrustedNodeAddress>>,
|
mut newly_transitioning_nodes: Option<&mut Vec<UntrustedNodeAddress>>,
|
||||||
new_animations_receiver: &Receiver<Animation>,
|
new_animations_receiver: &Receiver<Animation>,
|
||||||
pipeline_id: PipelineId,
|
pipeline_id: PipelineId,
|
||||||
|
@ -153,7 +153,7 @@ where
|
||||||
pub fn recalc_style_for_animations<E>(
|
pub fn recalc_style_for_animations<E>(
|
||||||
context: &LayoutContext,
|
context: &LayoutContext,
|
||||||
flow: &mut Flow,
|
flow: &mut Flow,
|
||||||
animations: &FnvHashMap<OpaqueNode, Vec<Animation>>,
|
animations: &FxHashMap<OpaqueNode, Vec<Animation>>,
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
E: TElement,
|
E: TElement,
|
||||||
|
|
|
@ -11,6 +11,7 @@ extern crate bitflags;
|
||||||
extern crate canvas_traits;
|
extern crate canvas_traits;
|
||||||
extern crate euclid;
|
extern crate euclid;
|
||||||
extern crate fnv;
|
extern crate fnv;
|
||||||
|
extern crate fxhash;
|
||||||
extern crate gfx;
|
extern crate gfx;
|
||||||
extern crate gfx_traits;
|
extern crate gfx_traits;
|
||||||
#[macro_use] extern crate html5ever;
|
#[macro_use] extern crate html5ever;
|
||||||
|
|
|
@ -18,6 +18,7 @@ atomic_refcell = "0.1"
|
||||||
embedder_traits = {path = "../embedder_traits"}
|
embedder_traits = {path = "../embedder_traits"}
|
||||||
euclid = "0.19"
|
euclid = "0.19"
|
||||||
fnv = "1.0"
|
fnv = "1.0"
|
||||||
|
fxhash = "0.2"
|
||||||
gfx = {path = "../gfx"}
|
gfx = {path = "../gfx"}
|
||||||
gfx_traits = {path = "../gfx_traits"}
|
gfx_traits = {path = "../gfx_traits"}
|
||||||
histogram = "0.6.8"
|
histogram = "0.6.8"
|
||||||
|
|
|
@ -675,14 +675,6 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
|
||||||
None
|
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>> {
|
fn prev_sibling_element(&self) -> Option<ServoLayoutElement<'le>> {
|
||||||
let mut node = self.as_node();
|
let mut node = self.as_node();
|
||||||
while let Some(sibling) = node.prev_sibling() {
|
while let Some(sibling) = node.prev_sibling() {
|
||||||
|
@ -1223,17 +1215,6 @@ impl<'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> {
|
||||||
None
|
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
|
// Skips non-element nodes
|
||||||
fn prev_sibling_element(&self) -> Option<Self> {
|
fn prev_sibling_element(&self) -> Option<Self> {
|
||||||
warn!("ServoThreadSafeLayoutElement::prev_sibling_element called");
|
warn!("ServoThreadSafeLayoutElement::prev_sibling_element called");
|
||||||
|
|
|
@ -12,6 +12,7 @@ extern crate atomic_refcell;
|
||||||
extern crate embedder_traits;
|
extern crate embedder_traits;
|
||||||
extern crate euclid;
|
extern crate euclid;
|
||||||
extern crate fnv;
|
extern crate fnv;
|
||||||
|
extern crate fxhash;
|
||||||
extern crate gfx;
|
extern crate gfx;
|
||||||
extern crate gfx_traits;
|
extern crate gfx_traits;
|
||||||
extern crate histogram;
|
extern crate histogram;
|
||||||
|
@ -59,6 +60,7 @@ use dom_wrapper::drop_style_and_layout_data;
|
||||||
use embedder_traits::resources::{self, Resource};
|
use embedder_traits::resources::{self, Resource};
|
||||||
use euclid::{Point2D, Rect, Size2D, TypedScale, TypedSize2D};
|
use euclid::{Point2D, Rect, Size2D, TypedScale, TypedSize2D};
|
||||||
use fnv::FnvHashMap;
|
use fnv::FnvHashMap;
|
||||||
|
use fxhash::FxHashMap;
|
||||||
use gfx::font;
|
use gfx::font;
|
||||||
use gfx::font_cache_thread::FontCacheThread;
|
use gfx::font_cache_thread::FontCacheThread;
|
||||||
use gfx::font_context;
|
use gfx::font_context;
|
||||||
|
@ -223,10 +225,10 @@ pub struct LayoutThread {
|
||||||
document_shared_lock: Option<SharedRwLock>,
|
document_shared_lock: Option<SharedRwLock>,
|
||||||
|
|
||||||
/// The list of currently-running animations.
|
/// 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.
|
/// 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
|
/// A counter for epoch messages
|
||||||
epoch: Cell<Epoch>,
|
epoch: Cell<Epoch>,
|
||||||
|
@ -503,7 +505,7 @@ impl LayoutThread {
|
||||||
constellation_chan: constellation_chan.clone(),
|
constellation_chan: constellation_chan.clone(),
|
||||||
time_profiler_chan: time_profiler_chan,
|
time_profiler_chan: time_profiler_chan,
|
||||||
mem_profiler_chan: mem_profiler_chan,
|
mem_profiler_chan: mem_profiler_chan,
|
||||||
registered_painters: RegisteredPaintersImpl(FnvHashMap::default()),
|
registered_painters: RegisteredPaintersImpl(Default::default()),
|
||||||
image_cache: image_cache.clone(),
|
image_cache: image_cache.clone(),
|
||||||
font_cache_thread: font_cache_thread,
|
font_cache_thread: font_cache_thread,
|
||||||
first_reflow: Cell::new(true),
|
first_reflow: Cell::new(true),
|
||||||
|
@ -517,8 +519,8 @@ impl LayoutThread {
|
||||||
outstanding_web_fonts: Arc::new(AtomicUsize::new(0)),
|
outstanding_web_fonts: Arc::new(AtomicUsize::new(0)),
|
||||||
root_flow: RefCell::new(None),
|
root_flow: RefCell::new(None),
|
||||||
document_shared_lock: None,
|
document_shared_lock: None,
|
||||||
running_animations: ServoArc::new(RwLock::new(FnvHashMap::default())),
|
running_animations: ServoArc::new(RwLock::new(Default::default())),
|
||||||
expired_animations: ServoArc::new(RwLock::new(FnvHashMap::default())),
|
expired_animations: ServoArc::new(RwLock::new(Default::default())),
|
||||||
epoch: Cell::new(Epoch(0)),
|
epoch: Cell::new(Epoch(0)),
|
||||||
viewport_size: Size2D::new(Au(0), Au(0)),
|
viewport_size: Size2D::new(Au(0), Au(0)),
|
||||||
webrender_api: webrender_api_sender.create_api(),
|
webrender_api: webrender_api_sender.create_api(),
|
||||||
|
@ -1813,7 +1815,8 @@ lazy_static! {
|
||||||
struct RegisteredPainterImpl {
|
struct RegisteredPainterImpl {
|
||||||
painter: Box<Painter>,
|
painter: Box<Painter>,
|
||||||
name: Atom,
|
name: Atom,
|
||||||
properties: FnvHashMap<Atom, PropertyId>,
|
// FIXME: Should be a PrecomputedHashMap.
|
||||||
|
properties: FxHashMap<Atom, PropertyId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SpeculativePainter for RegisteredPainterImpl {
|
impl SpeculativePainter for RegisteredPainterImpl {
|
||||||
|
@ -1823,7 +1826,7 @@ impl SpeculativePainter for RegisteredPainterImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RegisteredSpeculativePainter for RegisteredPainterImpl {
|
impl RegisteredSpeculativePainter for RegisteredPainterImpl {
|
||||||
fn properties(&self) -> &FnvHashMap<Atom, PropertyId> {
|
fn properties(&self) -> &FxHashMap<Atom, PropertyId> {
|
||||||
&self.properties
|
&self.properties
|
||||||
}
|
}
|
||||||
fn name(&self) -> Atom {
|
fn name(&self) -> Atom {
|
||||||
|
|
|
@ -37,6 +37,7 @@ servo_arc = { path = "../servo_arc" }
|
||||||
smallbitvec = "2.1.0"
|
smallbitvec = "2.1.0"
|
||||||
smallvec = "0.6"
|
smallvec = "0.6"
|
||||||
string_cache = { version = "0.7", optional = true }
|
string_cache = { version = "0.7", optional = true }
|
||||||
|
thin-slice = "0.1.0"
|
||||||
time = { version = "0.1.17", optional = true }
|
time = { version = "0.1.17", optional = true }
|
||||||
url = { version = "1.2", optional = true }
|
url = { version = "1.2", optional = true }
|
||||||
webrender_api = { git = "https://github.com/servo/webrender", features = ["ipc"], optional = true }
|
webrender_api = { git = "https://github.com/servo/webrender", features = ["ipc"], optional = true }
|
||||||
|
|
|
@ -63,6 +63,7 @@ extern crate smallbitvec;
|
||||||
extern crate smallvec;
|
extern crate smallvec;
|
||||||
#[cfg(feature = "servo")]
|
#[cfg(feature = "servo")]
|
||||||
extern crate string_cache;
|
extern crate string_cache;
|
||||||
|
extern crate thin_slice;
|
||||||
#[cfg(feature = "servo")]
|
#[cfg(feature = "servo")]
|
||||||
extern crate time;
|
extern crate time;
|
||||||
#[cfg(feature = "url")]
|
#[cfg(feature = "url")]
|
||||||
|
@ -231,6 +232,24 @@ impl<T: MallocSizeOf + ?Sized> MallocSizeOf for Box<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> MallocShallowSizeOf for thin_slice::ThinBoxedSlice<T> {
|
||||||
|
fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
|
||||||
|
let mut n = 0;
|
||||||
|
unsafe {
|
||||||
|
n += thin_slice::ThinBoxedSlice::spilled_storage(self)
|
||||||
|
.map_or(0, |ptr| ops.malloc_size_of(ptr));
|
||||||
|
n += ops.malloc_size_of(&**self);
|
||||||
|
}
|
||||||
|
n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: MallocSizeOf> MallocSizeOf for thin_slice::ThinBoxedSlice<T> {
|
||||||
|
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
|
||||||
|
self.shallow_size_of(ops) + (**self).size_of(ops)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl MallocSizeOf for () {
|
impl MallocSizeOf for () {
|
||||||
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
|
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
|
||||||
0
|
0
|
||||||
|
@ -770,7 +789,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Impl: selectors::parser::SelectorImpl> MallocSizeOf
|
impl<Impl: selectors::parser::SelectorImpl> MallocSizeOf
|
||||||
for selectors::attr::AttrSelectorWithNamespace<Impl>
|
for selectors::attr::AttrSelectorWithOptionalNamespace<Impl>
|
||||||
{
|
{
|
||||||
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
|
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
|
||||||
0
|
0
|
||||||
|
|
|
@ -2640,14 +2640,6 @@ impl<'a> SelectorsElement for DomRoot<Element> {
|
||||||
false
|
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>> {
|
fn prev_sibling_element(&self) -> Option<DomRoot<Element>> {
|
||||||
self.node.preceding_siblings().filter_map(DomRoot::downcast).next()
|
self.node.preceding_siblings().filter_map(DomRoot::downcast).next()
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,10 +25,12 @@ matches = "0.1"
|
||||||
cssparser = "0.24.0"
|
cssparser = "0.24.0"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
fnv = "1.0"
|
fnv = "1.0"
|
||||||
|
fxhash = "0.2"
|
||||||
phf = "0.7.18"
|
phf = "0.7.18"
|
||||||
precomputed-hash = "0.1"
|
precomputed-hash = "0.1"
|
||||||
servo_arc = { version = "0.1", path = "../servo_arc" }
|
servo_arc = { version = "0.1", path = "../servo_arc" }
|
||||||
smallvec = "0.6.2"
|
smallvec = "0.6.2"
|
||||||
|
thin-slice = "0.1.0"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
phf_codegen = "0.7.18"
|
phf_codegen = "0.7.18"
|
||||||
|
|
|
@ -7,20 +7,20 @@ use parser::SelectorImpl;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq)]
|
#[derive(Clone, Eq, PartialEq)]
|
||||||
pub struct AttrSelectorWithNamespace<Impl: SelectorImpl> {
|
pub struct AttrSelectorWithOptionalNamespace<Impl: SelectorImpl> {
|
||||||
pub namespace: NamespaceConstraint<(Impl::NamespacePrefix, Impl::NamespaceUrl)>,
|
pub namespace: Option<NamespaceConstraint<(Impl::NamespacePrefix, Impl::NamespaceUrl)>>,
|
||||||
pub local_name: Impl::LocalName,
|
pub local_name: Impl::LocalName,
|
||||||
pub local_name_lower: Impl::LocalName,
|
pub local_name_lower: Impl::LocalName,
|
||||||
pub operation: ParsedAttrSelectorOperation<Impl::AttrValue>,
|
pub operation: ParsedAttrSelectorOperation<Impl::AttrValue>,
|
||||||
pub never_matches: bool,
|
pub never_matches: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Impl: SelectorImpl> AttrSelectorWithNamespace<Impl> {
|
impl<Impl: SelectorImpl> AttrSelectorWithOptionalNamespace<Impl> {
|
||||||
pub fn namespace(&self) -> NamespaceConstraint<&Impl::NamespaceUrl> {
|
pub fn namespace(&self) -> Option<NamespaceConstraint<&Impl::NamespaceUrl>> {
|
||||||
match self.namespace {
|
self.namespace.as_ref().map(|ns| match ns {
|
||||||
NamespaceConstraint::Any => NamespaceConstraint::Any,
|
NamespaceConstraint::Any => NamespaceConstraint::Any,
|
||||||
NamespaceConstraint::Specific((_, ref url)) => NamespaceConstraint::Specific(url),
|
NamespaceConstraint::Specific((_, ref url)) => NamespaceConstraint::Specific(url),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -297,6 +297,9 @@ impl Clone for BloomStorageBool {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hash<T: Hash>(elem: &T) -> u32 {
|
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();
|
let mut hasher = FnvHasher::default();
|
||||||
elem.hash(&mut hasher);
|
elem.hash(&mut hasher);
|
||||||
let hash: u64 = hasher.finish();
|
let hash: u64 = hasher.finish();
|
||||||
|
|
|
@ -10,6 +10,7 @@ extern crate bitflags;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate cssparser;
|
extern crate cssparser;
|
||||||
extern crate fnv;
|
extern crate fnv;
|
||||||
|
extern crate fxhash;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
@ -18,6 +19,7 @@ extern crate phf;
|
||||||
extern crate precomputed_hash;
|
extern crate precomputed_hash;
|
||||||
extern crate servo_arc;
|
extern crate servo_arc;
|
||||||
extern crate smallvec;
|
extern crate smallvec;
|
||||||
|
extern crate thin_slice;
|
||||||
|
|
||||||
pub mod attr;
|
pub mod attr;
|
||||||
pub mod bloom;
|
pub mod bloom;
|
||||||
|
|
|
@ -699,7 +699,6 @@ where
|
||||||
},
|
},
|
||||||
Component::AttributeInNoNamespace {
|
Component::AttributeInNoNamespace {
|
||||||
ref local_name,
|
ref local_name,
|
||||||
ref local_name_lower,
|
|
||||||
ref value,
|
ref value,
|
||||||
operator,
|
operator,
|
||||||
case_sensitivity,
|
case_sensitivity,
|
||||||
|
@ -711,7 +710,7 @@ where
|
||||||
let is_html = element.is_html_element_in_html_document();
|
let is_html = element.is_html_element_in_html_document();
|
||||||
element.attr_matches(
|
element.attr_matches(
|
||||||
&NamespaceConstraint::Specific(&::parser::namespace_empty_string::<E::Impl>()),
|
&NamespaceConstraint::Specific(&::parser::namespace_empty_string::<E::Impl>()),
|
||||||
select_name(is_html, local_name, local_name_lower),
|
local_name,
|
||||||
&AttrSelectorOperation::WithValue {
|
&AttrSelectorOperation::WithValue {
|
||||||
operator: operator,
|
operator: operator,
|
||||||
case_sensitivity: case_sensitivity.to_unconditional(is_html),
|
case_sensitivity: case_sensitivity.to_unconditional(is_html),
|
||||||
|
@ -724,8 +723,16 @@ where
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let is_html = element.is_html_element_in_html_document();
|
let is_html = element.is_html_element_in_html_document();
|
||||||
|
let empty_string;
|
||||||
|
let namespace = match attr_sel.namespace() {
|
||||||
|
Some(ns) => ns,
|
||||||
|
None => {
|
||||||
|
empty_string = ::parser::namespace_empty_string::<E::Impl>();
|
||||||
|
NamespaceConstraint::Specific(&empty_string)
|
||||||
|
}
|
||||||
|
};
|
||||||
element.attr_matches(
|
element.attr_matches(
|
||||||
&attr_sel.namespace(),
|
&namespace,
|
||||||
select_name(is_html, &attr_sel.local_name, &attr_sel.local_name_lower),
|
select_name(is_html, &attr_sel.local_name, &attr_sel.local_name_lower),
|
||||||
&match attr_sel.operation {
|
&match attr_sel.operation {
|
||||||
ParsedAttrSelectorOperation::Exists => AttrSelectorOperation::Exists,
|
ParsedAttrSelectorOperation::Exists => AttrSelectorOperation::Exists,
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use fnv::FnvHashMap;
|
use fxhash::FxHashMap;
|
||||||
use tree::OpaqueElement;
|
use tree::OpaqueElement;
|
||||||
|
|
||||||
/// A cache to speed up matching of nth-index-like selectors.
|
/// A cache to speed up matching of nth-index-like selectors.
|
||||||
|
@ -32,7 +32,7 @@ impl NthIndexCache {
|
||||||
|
|
||||||
/// The concrete per-pseudo-class cache.
|
/// The concrete per-pseudo-class cache.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct NthIndexCacheInner(FnvHashMap<OpaqueElement, i32>);
|
pub struct NthIndexCacheInner(FxHashMap<OpaqueElement, i32>);
|
||||||
|
|
||||||
impl NthIndexCacheInner {
|
impl NthIndexCacheInner {
|
||||||
/// Does a lookup for a given element in the cache.
|
/// 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
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use attr::{AttrSelectorOperator, AttrSelectorWithNamespace, ParsedAttrSelectorOperation};
|
use attr::{AttrSelectorOperator, AttrSelectorWithOptionalNamespace};
|
||||||
use attr::{NamespaceConstraint, ParsedCaseSensitivity, SELECTOR_WHITESPACE};
|
use attr::{NamespaceConstraint, ParsedAttrSelectorOperation};
|
||||||
|
use attr::{ParsedCaseSensitivity, SELECTOR_WHITESPACE};
|
||||||
use bloom::BLOOM_HASH_MASK;
|
use bloom::BLOOM_HASH_MASK;
|
||||||
use builder::{SelectorBuilder, SpecificityAndFlags};
|
use builder::{SelectorBuilder, SpecificityAndFlags};
|
||||||
use context::QuirksMode;
|
use context::QuirksMode;
|
||||||
|
@ -19,6 +20,7 @@ use std::borrow::{Borrow, Cow};
|
||||||
use std::fmt::{self, Debug, Display, Write};
|
use std::fmt::{self, Debug, Display, Write};
|
||||||
use std::iter::Rev;
|
use std::iter::Rev;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
|
use thin_slice::ThinBoxedSlice;
|
||||||
pub use visitor::{SelectorVisitor, Visit};
|
pub use visitor::{SelectorVisitor, Visit};
|
||||||
|
|
||||||
/// A trait that represents a pseudo-element.
|
/// A trait that represents a pseudo-element.
|
||||||
|
@ -45,6 +47,8 @@ pub trait NonTSPseudoClass: Sized + ToCss {
|
||||||
fn is_active_or_hover(&self) -> bool;
|
fn is_active_or_hover(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a Cow::Borrowed if `s` is already ASCII lowercase, and a
|
||||||
|
/// Cow::Owned if `s` had to be converted into ASCII lowercase.
|
||||||
fn to_ascii_lowercase(s: &str) -> Cow<str> {
|
fn to_ascii_lowercase(s: &str) -> Cow<str> {
|
||||||
if let Some(first_uppercase) = s.bytes().position(|byte| byte >= b'A' && byte <= b'Z') {
|
if let Some(first_uppercase) = s.bytes().position(|byte| byte >= b'A' && byte <= b'Z') {
|
||||||
let mut string = s.to_owned();
|
let mut string = s.to_owned();
|
||||||
|
@ -428,7 +432,6 @@ where
|
||||||
},
|
},
|
||||||
AttributeInNoNamespace {
|
AttributeInNoNamespace {
|
||||||
ref local_name,
|
ref local_name,
|
||||||
ref local_name_lower,
|
|
||||||
never_matches,
|
never_matches,
|
||||||
..
|
..
|
||||||
} if !never_matches =>
|
} if !never_matches =>
|
||||||
|
@ -436,14 +439,22 @@ where
|
||||||
if !visitor.visit_attribute_selector(
|
if !visitor.visit_attribute_selector(
|
||||||
&NamespaceConstraint::Specific(&namespace_empty_string::<Impl>()),
|
&NamespaceConstraint::Specific(&namespace_empty_string::<Impl>()),
|
||||||
local_name,
|
local_name,
|
||||||
local_name_lower,
|
local_name,
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
AttributeOther(ref attr_selector) if !attr_selector.never_matches => {
|
AttributeOther(ref attr_selector) if !attr_selector.never_matches => {
|
||||||
|
let empty_string;
|
||||||
|
let namespace = match attr_selector.namespace() {
|
||||||
|
Some(ns) => ns,
|
||||||
|
None => {
|
||||||
|
empty_string = ::parser::namespace_empty_string::<Impl>();
|
||||||
|
NamespaceConstraint::Specific(&empty_string)
|
||||||
|
}
|
||||||
|
};
|
||||||
if !visitor.visit_attribute_selector(
|
if !visitor.visit_attribute_selector(
|
||||||
&attr_selector.namespace(),
|
&namespace,
|
||||||
&attr_selector.local_name,
|
&attr_selector.local_name,
|
||||||
&attr_selector.local_name_lower,
|
&attr_selector.local_name_lower,
|
||||||
) {
|
) {
|
||||||
|
@ -815,16 +826,16 @@ pub enum Component<Impl: SelectorImpl> {
|
||||||
local_name: Impl::LocalName,
|
local_name: Impl::LocalName,
|
||||||
local_name_lower: Impl::LocalName,
|
local_name_lower: Impl::LocalName,
|
||||||
},
|
},
|
||||||
|
// Used only when local_name is already lowercase.
|
||||||
AttributeInNoNamespace {
|
AttributeInNoNamespace {
|
||||||
local_name: Impl::LocalName,
|
local_name: Impl::LocalName,
|
||||||
local_name_lower: Impl::LocalName,
|
|
||||||
operator: AttrSelectorOperator,
|
operator: AttrSelectorOperator,
|
||||||
value: Impl::AttrValue,
|
value: Impl::AttrValue,
|
||||||
case_sensitivity: ParsedCaseSensitivity,
|
case_sensitivity: ParsedCaseSensitivity,
|
||||||
never_matches: bool,
|
never_matches: bool,
|
||||||
},
|
},
|
||||||
// Use a Box in the less common cases with more data to keep size_of::<Component>() small.
|
// Use a Box in the less common cases with more data to keep size_of::<Component>() small.
|
||||||
AttributeOther(Box<AttrSelectorWithNamespace<Impl>>),
|
AttributeOther(Box<AttrSelectorWithOptionalNamespace<Impl>>),
|
||||||
|
|
||||||
/// Pseudo-classes
|
/// Pseudo-classes
|
||||||
///
|
///
|
||||||
|
@ -836,7 +847,7 @@ pub enum Component<Impl: SelectorImpl> {
|
||||||
/// need to think about how this should interact with
|
/// need to think about how this should interact with
|
||||||
/// visit_complex_selector, and what the consumers of those APIs should do
|
/// visit_complex_selector, and what the consumers of those APIs should do
|
||||||
/// about the presence of combinators in negation.
|
/// about the presence of combinators in negation.
|
||||||
Negation(Box<[Component<Impl>]>),
|
Negation(ThinBoxedSlice<Component<Impl>>),
|
||||||
FirstChild,
|
FirstChild,
|
||||||
LastChild,
|
LastChild,
|
||||||
OnlyChild,
|
OnlyChild,
|
||||||
|
@ -948,7 +959,7 @@ impl<Impl: SelectorImpl> Debug for Component<Impl> {
|
||||||
self.to_css(f)
|
self.to_css(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<Impl: SelectorImpl> Debug for AttrSelectorWithNamespace<Impl> {
|
impl<Impl: SelectorImpl> Debug for AttrSelectorWithOptionalNamespace<Impl> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
self.to_css(f)
|
self.to_css(f)
|
||||||
}
|
}
|
||||||
|
@ -1238,18 +1249,19 @@ impl<Impl: SelectorImpl> ToCss for Component<Impl> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Impl: SelectorImpl> ToCss for AttrSelectorWithNamespace<Impl> {
|
impl<Impl: SelectorImpl> ToCss for AttrSelectorWithOptionalNamespace<Impl> {
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
|
||||||
where
|
where
|
||||||
W: fmt::Write,
|
W: fmt::Write,
|
||||||
{
|
{
|
||||||
dest.write_char('[')?;
|
dest.write_char('[')?;
|
||||||
match self.namespace {
|
match self.namespace {
|
||||||
NamespaceConstraint::Specific((ref prefix, _)) => {
|
Some(NamespaceConstraint::Specific((ref prefix, _))) => {
|
||||||
display_to_css_identifier(prefix, dest)?;
|
display_to_css_identifier(prefix, dest)?;
|
||||||
dest.write_char('|')?
|
dest.write_char('|')?
|
||||||
},
|
},
|
||||||
NamespaceConstraint::Any => dest.write_str("*|")?,
|
Some(NamespaceConstraint::Any) => dest.write_str("*|")?,
|
||||||
|
None => {}
|
||||||
}
|
}
|
||||||
display_to_css_identifier(&self.local_name, dest)?;
|
display_to_css_identifier(&self.local_name, dest)?;
|
||||||
match self.operation {
|
match self.operation {
|
||||||
|
@ -1628,8 +1640,8 @@ where
|
||||||
let local_name = local_name.as_ref().into();
|
let local_name = local_name.as_ref().into();
|
||||||
if let Some(namespace) = namespace {
|
if let Some(namespace) = namespace {
|
||||||
return Ok(Component::AttributeOther(Box::new(
|
return Ok(Component::AttributeOther(Box::new(
|
||||||
AttrSelectorWithNamespace {
|
AttrSelectorWithOptionalNamespace {
|
||||||
namespace: namespace,
|
namespace: Some(namespace),
|
||||||
local_name: local_name,
|
local_name: local_name,
|
||||||
local_name_lower: local_name_lower,
|
local_name_lower: local_name_lower,
|
||||||
operation: ParsedAttrSelectorOperation::Exists,
|
operation: ParsedAttrSelectorOperation::Exists,
|
||||||
|
@ -1685,6 +1697,7 @@ where
|
||||||
|
|
||||||
let value = value.as_ref().into();
|
let value = value.as_ref().into();
|
||||||
let local_name_lower;
|
let local_name_lower;
|
||||||
|
let local_name_is_ascii_lowercase;
|
||||||
{
|
{
|
||||||
let local_name_lower_cow = to_ascii_lowercase(&local_name);
|
let local_name_lower_cow = to_ascii_lowercase(&local_name);
|
||||||
if let ParsedCaseSensitivity::CaseSensitive = case_sensitivity {
|
if let ParsedCaseSensitivity::CaseSensitive = case_sensitivity {
|
||||||
|
@ -1699,15 +1712,16 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
local_name_lower = local_name_lower_cow.as_ref().into();
|
local_name_lower = local_name_lower_cow.as_ref().into();
|
||||||
|
local_name_is_ascii_lowercase = matches!(local_name_lower_cow, Cow::Borrowed(..));
|
||||||
}
|
}
|
||||||
let local_name = local_name.as_ref().into();
|
let local_name = local_name.as_ref().into();
|
||||||
if let Some(namespace) = namespace {
|
if namespace.is_some() || !local_name_is_ascii_lowercase {
|
||||||
Ok(Component::AttributeOther(Box::new(
|
Ok(Component::AttributeOther(Box::new(
|
||||||
AttrSelectorWithNamespace {
|
AttrSelectorWithOptionalNamespace {
|
||||||
namespace: namespace,
|
namespace,
|
||||||
local_name: local_name,
|
local_name,
|
||||||
local_name_lower: local_name_lower,
|
local_name_lower,
|
||||||
never_matches: never_matches,
|
never_matches,
|
||||||
operation: ParsedAttrSelectorOperation::WithValue {
|
operation: ParsedAttrSelectorOperation::WithValue {
|
||||||
operator: operator,
|
operator: operator,
|
||||||
case_sensitivity: case_sensitivity,
|
case_sensitivity: case_sensitivity,
|
||||||
|
@ -1718,7 +1732,6 @@ where
|
||||||
} else {
|
} else {
|
||||||
Ok(Component::AttributeInNoNamespace {
|
Ok(Component::AttributeInNoNamespace {
|
||||||
local_name: local_name,
|
local_name: local_name,
|
||||||
local_name_lower: local_name_lower,
|
|
||||||
operator: operator,
|
operator: operator,
|
||||||
value: value,
|
value: value,
|
||||||
case_sensitivity: case_sensitivity,
|
case_sensitivity: case_sensitivity,
|
||||||
|
@ -1785,7 +1798,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
// Success.
|
// Success.
|
||||||
Ok(Component::Negation(sequence.into_vec().into_boxed_slice()))
|
Ok(Component::Negation(sequence.into_vec().into_boxed_slice().into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// simple_selector_sequence
|
/// simple_selector_sequence
|
||||||
|
@ -2625,7 +2638,7 @@ pub mod tests {
|
||||||
vec![
|
vec![
|
||||||
Component::DefaultNamespace(MATHML.into()),
|
Component::DefaultNamespace(MATHML.into()),
|
||||||
Component::Negation(
|
Component::Negation(
|
||||||
vec![Component::Class(DummyAtom::from("cl"))].into_boxed_slice(),
|
vec![Component::Class(DummyAtom::from("cl"))].into_boxed_slice().into(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
specificity(0, 1, 0),
|
specificity(0, 1, 0),
|
||||||
|
@ -2642,7 +2655,7 @@ pub mod tests {
|
||||||
vec![
|
vec![
|
||||||
Component::DefaultNamespace(MATHML.into()),
|
Component::DefaultNamespace(MATHML.into()),
|
||||||
Component::ExplicitUniversalType,
|
Component::ExplicitUniversalType,
|
||||||
].into_boxed_slice(),
|
].into_boxed_slice().into(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
specificity(0, 0, 0),
|
specificity(0, 0, 0),
|
||||||
|
@ -2662,7 +2675,7 @@ pub mod tests {
|
||||||
name: DummyAtom::from("e"),
|
name: DummyAtom::from("e"),
|
||||||
lower_name: DummyAtom::from("e"),
|
lower_name: DummyAtom::from("e"),
|
||||||
}),
|
}),
|
||||||
].into_boxed_slice(),
|
].into_boxed_slice().into(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
specificity(0, 0, 1),
|
specificity(0, 0, 1),
|
||||||
|
@ -2676,7 +2689,6 @@ pub mod tests {
|
||||||
vec![
|
vec![
|
||||||
Component::AttributeInNoNamespace {
|
Component::AttributeInNoNamespace {
|
||||||
local_name: DummyAtom::from("attr"),
|
local_name: DummyAtom::from("attr"),
|
||||||
local_name_lower: DummyAtom::from("attr"),
|
|
||||||
operator: AttrSelectorOperator::DashMatch,
|
operator: AttrSelectorOperator::DashMatch,
|
||||||
value: DummyAtom::from("foo"),
|
value: DummyAtom::from("foo"),
|
||||||
never_matches: false,
|
never_matches: false,
|
||||||
|
@ -2770,7 +2782,7 @@ pub mod tests {
|
||||||
Selector::from_vec(
|
Selector::from_vec(
|
||||||
vec![
|
vec![
|
||||||
Component::Negation(
|
Component::Negation(
|
||||||
vec![Component::ID(DummyAtom::from("provel"))].into_boxed_slice(),
|
vec![Component::ID(DummyAtom::from("provel"))].into_boxed_slice().into(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
specificity(1, 0, 0),
|
specificity(1, 0, 0),
|
||||||
|
@ -2789,7 +2801,7 @@ pub mod tests {
|
||||||
name: DummyAtom::from("circle"),
|
name: DummyAtom::from("circle"),
|
||||||
lower_name: DummyAtom::from("circle"),
|
lower_name: DummyAtom::from("circle"),
|
||||||
}),
|
}),
|
||||||
].into_boxed_slice(),
|
].into_boxed_slice().into(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
specificity(0, 0, 1),
|
specificity(0, 0, 1),
|
||||||
|
@ -2803,7 +2815,7 @@ pub mod tests {
|
||||||
Selector::from_vec(
|
Selector::from_vec(
|
||||||
vec![
|
vec![
|
||||||
Component::Negation(
|
Component::Negation(
|
||||||
vec![Component::ExplicitUniversalType].into_boxed_slice(),
|
vec![Component::ExplicitUniversalType].into_boxed_slice().into(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
specificity(0, 0, 0),
|
specificity(0, 0, 0),
|
||||||
|
@ -2819,7 +2831,7 @@ pub mod tests {
|
||||||
vec![
|
vec![
|
||||||
Component::ExplicitNoNamespace,
|
Component::ExplicitNoNamespace,
|
||||||
Component::ExplicitUniversalType,
|
Component::ExplicitUniversalType,
|
||||||
].into_boxed_slice(),
|
].into_boxed_slice().into(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
specificity(0, 0, 0),
|
specificity(0, 0, 0),
|
||||||
|
@ -2834,7 +2846,7 @@ pub mod tests {
|
||||||
Selector::from_vec(
|
Selector::from_vec(
|
||||||
vec![
|
vec![
|
||||||
Component::Negation(
|
Component::Negation(
|
||||||
vec![Component::ExplicitUniversalType].into_boxed_slice(),
|
vec![Component::ExplicitUniversalType].into_boxed_slice().into(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
specificity(0, 0, 0),
|
specificity(0, 0, 0),
|
||||||
|
@ -2850,7 +2862,7 @@ pub mod tests {
|
||||||
vec![
|
vec![
|
||||||
Component::Namespace(DummyAtom("svg".into()), SVG.into()),
|
Component::Namespace(DummyAtom("svg".into()), SVG.into()),
|
||||||
Component::ExplicitUniversalType,
|
Component::ExplicitUniversalType,
|
||||||
].into_boxed_slice(),
|
].into_boxed_slice().into(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
specificity(0, 0, 0),
|
specificity(0, 0, 0),
|
||||||
|
|
|
@ -45,12 +45,6 @@ pub trait Element: Sized + Clone + Debug {
|
||||||
self.parent_element()
|
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
|
/// Skips non-element nodes
|
||||||
fn prev_sibling_element(&self) -> Option<Self>;
|
fn prev_sibling_element(&self) -> Option<Self>;
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ new_debug_unreachable = "1.0"
|
||||||
encoding_rs = {version = "0.7", optional = true}
|
encoding_rs = {version = "0.7", optional = true}
|
||||||
euclid = "0.19"
|
euclid = "0.19"
|
||||||
fallible = { path = "../fallible" }
|
fallible = { path = "../fallible" }
|
||||||
fnv = "1.0"
|
fxhash = "0.2"
|
||||||
hashglobe = { path = "../hashglobe" }
|
hashglobe = { path = "../hashglobe" }
|
||||||
html5ever = {version = "0.22", optional = true}
|
html5ever = {version = "0.22", optional = true}
|
||||||
itertools = "0.7.6"
|
itertools = "0.7.6"
|
||||||
|
@ -65,6 +65,7 @@ string_cache = { version = "0.7", optional = true }
|
||||||
style_derive = {path = "../style_derive"}
|
style_derive = {path = "../style_derive"}
|
||||||
style_traits = {path = "../style_traits"}
|
style_traits = {path = "../style_traits"}
|
||||||
servo_url = {path = "../url", optional = true}
|
servo_url = {path = "../url", optional = true}
|
||||||
|
thin-slice = "0.1.0"
|
||||||
time = "0.1"
|
time = "0.1"
|
||||||
uluru = "0.2"
|
uluru = "0.2"
|
||||||
unicode-bidi = "0.3"
|
unicode-bidi = "0.3"
|
||||||
|
|
|
@ -120,7 +120,6 @@ mod bindings {
|
||||||
let mut file = File::open(&path).unwrap();
|
let mut file = File::open(&path).unwrap();
|
||||||
let mut content = String::new();
|
let mut content = String::new();
|
||||||
file.read_to_string(&mut content).unwrap();
|
file.read_to_string(&mut content).unwrap();
|
||||||
println!("cargo:rerun-if-changed={}", path.to_str().unwrap());
|
|
||||||
added_paths.insert(path);
|
added_paths.insert(path);
|
||||||
// Find all includes and add them recursively
|
// Find all includes and add them recursively
|
||||||
for cap in INCLUDE_RE.captures_iter(&content) {
|
for cap in INCLUDE_RE.captures_iter(&content) {
|
||||||
|
@ -286,6 +285,7 @@ mod bindings {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
for fixup in fixups.iter() {
|
for fixup in fixups.iter() {
|
||||||
result = Regex::new(&fixup.pat)
|
result = Regex::new(&fixup.pat)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -602,6 +602,10 @@ mod bindings {
|
||||||
generate_bindings(),
|
generate_bindings(),
|
||||||
generate_atoms(),
|
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 dom::OpaqueNode;
|
||||||
use euclid::Size2D;
|
use euclid::Size2D;
|
||||||
use euclid::TypedScale;
|
use euclid::TypedScale;
|
||||||
use fnv::FnvHashMap;
|
|
||||||
use font_metrics::FontMetricsProvider;
|
use font_metrics::FontMetricsProvider;
|
||||||
|
use fxhash::FxHashMap;
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
use gecko_bindings::structs;
|
use gecko_bindings::structs;
|
||||||
use parallel::{STACK_SAFETY_MARGIN_KB, STYLE_THREAD_STACK_SIZE_KB};
|
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.
|
/// The animations that are currently running.
|
||||||
#[cfg(feature = "servo")]
|
#[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.
|
/// The list of animations that have expired since the last style recalculation.
|
||||||
#[cfg(feature = "servo")]
|
#[cfg(feature = "servo")]
|
||||||
pub expired_animations: Arc<RwLock<FnvHashMap<OpaqueNode, Vec<Animation>>>>,
|
pub expired_animations: Arc<RwLock<FxHashMap<OpaqueNode, Vec<Animation>>>>,
|
||||||
|
|
||||||
/// Paint worklets
|
/// Paint worklets
|
||||||
#[cfg(feature = "servo")]
|
#[cfg(feature = "servo")]
|
||||||
|
@ -570,7 +570,7 @@ type CacheItem<E> = (SendElement<E>, ElementSelectorFlags);
|
||||||
/// flags until after the traversal.
|
/// flags until after the traversal.
|
||||||
pub struct SelectorFlagsMap<E: TElement> {
|
pub struct SelectorFlagsMap<E: TElement> {
|
||||||
/// The hashmap storing the flags to apply.
|
/// 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
|
/// An LRU cache to avoid hashmap lookups, which can be slow if the map
|
||||||
/// gets big.
|
/// gets big.
|
||||||
cache: LRUCache<[Entry<CacheItem<E>>; 4 + 1]>,
|
cache: LRUCache<[Entry<CacheItem<E>>; 4 + 1]>,
|
||||||
|
@ -587,7 +587,7 @@ impl<E: TElement> SelectorFlagsMap<E> {
|
||||||
/// Creates a new empty SelectorFlagsMap.
|
/// Creates a new empty SelectorFlagsMap.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
SelectorFlagsMap {
|
SelectorFlagsMap {
|
||||||
map: FnvHashMap::default(),
|
map: FxHashMap::default(),
|
||||||
cache: LRUCache::default(),
|
cache: LRUCache::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -833,7 +833,7 @@ pub trait RegisteredSpeculativePainter: SpeculativePainter {
|
||||||
/// The name it was registered with
|
/// The name it was registered with
|
||||||
fn name(&self) -> Atom;
|
fn name(&self) -> Atom;
|
||||||
/// The properties it was registered with
|
/// The properties it was registered with
|
||||||
fn properties(&self) -> &FnvHashMap<Atom, PropertyId>;
|
fn properties(&self) -> &FxHashMap<Atom, PropertyId>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A set of registered painters
|
/// A set of registered painters
|
||||||
|
|
|
@ -16,7 +16,6 @@ use selector_parser::{PseudoElement, RestyleDamage, EAGER_PSEUDO_COUNT};
|
||||||
use selectors::NthIndexCache;
|
use selectors::NthIndexCache;
|
||||||
use servo_arc::Arc;
|
use servo_arc::Arc;
|
||||||
use shared_lock::StylesheetGuards;
|
use shared_lock::StylesheetGuards;
|
||||||
use smallvec::SmallVec;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
@ -273,16 +272,8 @@ impl ElementData {
|
||||||
return InvalidationResult::empty();
|
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(
|
let mut processor = StateAndAttrInvalidationProcessor::new(
|
||||||
shared_context,
|
shared_context,
|
||||||
&non_document_styles,
|
|
||||||
matches_doc_author_rules,
|
|
||||||
element,
|
element,
|
||||||
self,
|
self,
|
||||||
nth_index_cache,
|
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, nsMediaFeature_RangeType};
|
||||||
use gecko_bindings::structs::{nsMediaFeature_ValueType, nsPresContext};
|
use gecko_bindings::structs::{nsMediaFeature_ValueType, nsPresContext};
|
||||||
use gecko_bindings::structs::RawGeckoPresContextOwned;
|
use gecko_bindings::structs::RawGeckoPresContextOwned;
|
||||||
|
use gecko_bindings::structs::nsCSSKeywordAndBoolTableEntry;
|
||||||
use media_queries::MediaType;
|
use media_queries::MediaType;
|
||||||
use parser::{Parse, ParserContext};
|
use parser::{Parse, ParserContext};
|
||||||
use properties::ComputedValues;
|
use properties::ComputedValues;
|
||||||
|
@ -374,6 +375,9 @@ pub enum MediaExpressionValue {
|
||||||
/// An enumerated value, defined by the variant keyword table in the
|
/// An enumerated value, defined by the variant keyword table in the
|
||||||
/// feature's `mData` member.
|
/// feature's `mData` member.
|
||||||
Enumerated(i16),
|
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.
|
/// An identifier.
|
||||||
Ident(Atom),
|
Ident(Atom),
|
||||||
}
|
}
|
||||||
|
@ -420,6 +424,10 @@ impl MediaExpressionValue {
|
||||||
let value = css_value.integer_unchecked() as i16;
|
let value = css_value.integer_unchecked() as i16;
|
||||||
Some(MediaExpressionValue::Enumerated(value))
|
Some(MediaExpressionValue::Enumerated(value))
|
||||||
},
|
},
|
||||||
|
nsMediaFeature_ValueType::eBoolEnumerated => {
|
||||||
|
let value = css_value.integer_unchecked() as i16;
|
||||||
|
Some(MediaExpressionValue::BoolEnumerated(value))
|
||||||
|
},
|
||||||
nsMediaFeature_ValueType::eIdent => {
|
nsMediaFeature_ValueType::eIdent => {
|
||||||
debug_assert_eq!(css_value.mUnit, nsCSSUnit::eCSSUnit_AtomIdent);
|
debug_assert_eq!(css_value.mUnit, nsCSSUnit::eCSSUnit_AtomIdent);
|
||||||
Some(MediaExpressionValue::Ident(unsafe {
|
Some(MediaExpressionValue::Ident(unsafe {
|
||||||
|
@ -457,25 +465,43 @@ impl MediaExpressionValue {
|
||||||
MediaExpressionValue::Resolution(ref r) => r.to_css(dest),
|
MediaExpressionValue::Resolution(ref r) => r.to_css(dest),
|
||||||
MediaExpressionValue::Ident(ref ident) => serialize_atom_identifier(ident, dest),
|
MediaExpressionValue::Ident(ref ident) => serialize_atom_identifier(ident, dest),
|
||||||
MediaExpressionValue::Enumerated(value) => unsafe {
|
MediaExpressionValue::Enumerated(value) => unsafe {
|
||||||
use std::{slice, str};
|
let keyword = find_in_table(
|
||||||
use std::os::raw::c_char;
|
|
||||||
|
|
||||||
// NB: All the keywords on nsMediaFeatures are static,
|
|
||||||
// well-formed utf-8.
|
|
||||||
let mut length = 0;
|
|
||||||
|
|
||||||
let (keyword, _value) = find_in_table(
|
|
||||||
*for_expr.feature.mData.mKeywordTable.as_ref(),
|
*for_expr.feature.mData.mKeywordTable.as_ref(),
|
||||||
|_kw, val| val == value,
|
|_kw, val| val == value,
|
||||||
|
|e| e.keyword(),
|
||||||
).expect("Value not found in the keyword table?");
|
).expect("Value not found in the keyword table?");
|
||||||
|
|
||||||
let buffer: *const c_char = bindings::Gecko_CSSKeywordString(keyword, &mut length);
|
MediaExpressionValue::keyword_to_css(keyword, dest)
|
||||||
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::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
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn find_in_table<F>(
|
trait TableEntry {
|
||||||
mut current_entry: *const nsCSSKTableEntry,
|
fn value(&self) -> i16;
|
||||||
mut f: F,
|
fn keyword(&self) -> nsCSSKeyword;
|
||||||
) -> Option<(nsCSSKeyword, i16)>
|
}
|
||||||
|
|
||||||
|
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
|
where
|
||||||
F: FnMut(nsCSSKeyword, i16) -> bool,
|
T: TableEntry,
|
||||||
|
FindFunc: Fn(nsCSSKeyword, i16) -> bool,
|
||||||
|
ResultFunc: Fn(&T) -> R,
|
||||||
{
|
{
|
||||||
|
let mut current_entry = current_entry;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let value = (*current_entry).mValue;
|
let value = (*current_entry).value();
|
||||||
let keyword = (*current_entry).mKeyword;
|
let keyword = (*current_entry).keyword();
|
||||||
|
|
||||||
if value == -1 {
|
if value == -1 {
|
||||||
return None; // End of the table.
|
return None; // End of the table.
|
||||||
}
|
}
|
||||||
|
|
||||||
if f(keyword, value) {
|
if find(keyword, value) {
|
||||||
return Some((keyword, value));
|
return Some(result_func(&*current_entry));
|
||||||
}
|
}
|
||||||
|
|
||||||
current_entry = current_entry.offset(1);
|
current_entry = current_entry.offset(1);
|
||||||
|
@ -556,24 +610,21 @@ fn parse_feature_value<'i, 't>(
|
||||||
MediaExpressionValue::Resolution(Resolution::parse(context, input)?)
|
MediaExpressionValue::Resolution(Resolution::parse(context, input)?)
|
||||||
},
|
},
|
||||||
nsMediaFeature_ValueType::eEnumerated => {
|
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 =
|
let first_table_entry: *const nsCSSKTableEntry =
|
||||||
unsafe { *feature.mData.mKeywordTable.as_ref() };
|
unsafe { *feature.mData.mKeywordTable.as_ref() };
|
||||||
|
|
||||||
let value = match unsafe { find_in_table(first_table_entry, |kw, _| kw == keyword) } {
|
let value = parse_keyword(input, first_table_entry)?;
|
||||||
Some((_kw, value)) => value,
|
|
||||||
None => {
|
|
||||||
return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
MediaExpressionValue::Enumerated(value)
|
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 => {
|
nsMediaFeature_ValueType::eIdent => {
|
||||||
MediaExpressionValue::Ident(Atom::from(input.expect_ident()?.as_ref()))
|
MediaExpressionValue::Ident(Atom::from(input.expect_ident()?.as_ref()))
|
||||||
},
|
},
|
||||||
|
@ -582,6 +633,30 @@ fn parse_feature_value<'i, 't>(
|
||||||
Ok(value)
|
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.
|
/// Consumes an operation or a colon, or returns an error.
|
||||||
fn consume_operation_or_colon(
|
fn consume_operation_or_colon(
|
||||||
input: &mut Parser,
|
input: &mut Parser,
|
||||||
|
@ -834,6 +909,16 @@ impl MediaFeatureExpression {
|
||||||
quirks_mode,
|
quirks_mode,
|
||||||
|context| l.to_computed_value(&context).px() != 0.,
|
|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,
|
_ => true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -880,6 +965,13 @@ impl MediaFeatureExpression {
|
||||||
);
|
);
|
||||||
return one == other;
|
return one == other;
|
||||||
},
|
},
|
||||||
|
(&BoolEnumerated(one), &BoolEnumerated(other)) => {
|
||||||
|
debug_assert_ne!(
|
||||||
|
self.feature.mRangeType,
|
||||||
|
nsMediaFeature_RangeType::eMinMaxAllowed
|
||||||
|
);
|
||||||
|
return one == other;
|
||||||
|
},
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ use properties::longhands::display::computed_value::T as Display;
|
||||||
use selector_parser::{NonTSPseudoClass, PseudoElementCascadeType, SelectorImpl};
|
use selector_parser::{NonTSPseudoClass, PseudoElementCascadeType, SelectorImpl};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use string_cache::Atom;
|
use string_cache::Atom;
|
||||||
|
use thin_slice::ThinBoxedSlice;
|
||||||
use values::serialize_atom_identifier;
|
use values::serialize_atom_identifier;
|
||||||
|
|
||||||
include!(concat!(
|
include!(concat!(
|
||||||
|
@ -161,15 +162,6 @@ impl PseudoElement {
|
||||||
self.is_anon_box() && !self.is_tree_pseudo_element()
|
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.
|
/// Property flag that properties must have to apply to this pseudo-element.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn property_restriction(&self) -> Option<PropertyFlags> {
|
pub fn property_restriction(&self) -> Option<PropertyFlags> {
|
||||||
|
|
|
@ -8,7 +8,7 @@ pub enum PseudoElement {
|
||||||
% for pseudo in PSEUDOS:
|
% for pseudo in PSEUDOS:
|
||||||
/// ${pseudo.value}
|
/// ${pseudo.value}
|
||||||
% if pseudo.is_tree_pseudo_element():
|
% if pseudo.is_tree_pseudo_element():
|
||||||
${pseudo.capitalized()}(Box<[Atom]>),
|
${pseudo.capitalized()}(ThinBoxedSlice<Atom>),
|
||||||
% else:
|
% else:
|
||||||
${pseudo.capitalized()},
|
${pseudo.capitalized()},
|
||||||
% endif
|
% endif
|
||||||
|
@ -112,7 +112,11 @@ impl PseudoElement {
|
||||||
% for pseudo in PSEUDOS:
|
% for pseudo in PSEUDOS:
|
||||||
${pseudo_element_variant(pseudo)} =>
|
${pseudo_element_variant(pseudo)} =>
|
||||||
% if pseudo.is_tree_pseudo_element():
|
% 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():
|
% elif pseudo.is_anon_box():
|
||||||
structs::CSS_PSEUDO_ELEMENT_ENABLED_IN_UA_SHEETS,
|
structs::CSS_PSEUDO_ELEMENT_ENABLED_IN_UA_SHEETS,
|
||||||
% else:
|
% else:
|
||||||
|
@ -209,7 +213,7 @@ impl PseudoElement {
|
||||||
% for pseudo in PSEUDOS:
|
% for pseudo in PSEUDOS:
|
||||||
% if pseudo.is_tree_pseudo_element():
|
% if pseudo.is_tree_pseudo_element():
|
||||||
if atom == &atom!("${pseudo.value}") {
|
if atom == &atom!("${pseudo.value}") {
|
||||||
return Some(PseudoElement::${pseudo.capitalized()}(args));
|
return Some(PseudoElement::${pseudo.capitalized()}(args.into()));
|
||||||
}
|
}
|
||||||
% endif
|
% endif
|
||||||
% endfor
|
% endfor
|
||||||
|
@ -234,6 +238,9 @@ impl PseudoElement {
|
||||||
"-moz-selection" => {
|
"-moz-selection" => {
|
||||||
return Some(PseudoElement::Selection);
|
return Some(PseudoElement::Selection);
|
||||||
}
|
}
|
||||||
|
"-moz-placeholder" => {
|
||||||
|
return Some(PseudoElement::Placeholder);
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// FIXME: -moz-tree check should probably be
|
// FIXME: -moz-tree check should probably be
|
||||||
// ascii-case-insensitive.
|
// ascii-case-insensitive.
|
||||||
|
@ -256,7 +263,7 @@ impl PseudoElement {
|
||||||
let tree_part = &name[10..];
|
let tree_part = &name[10..];
|
||||||
% for pseudo in TREE_PSEUDOS:
|
% for pseudo in TREE_PSEUDOS:
|
||||||
if tree_part.eq_ignore_ascii_case("${pseudo.value[11:]}") {
|
if tree_part.eq_ignore_ascii_case("${pseudo.value[11:]}") {
|
||||||
return Some(${pseudo_element_variant(pseudo, "args")});
|
return Some(${pseudo_element_variant(pseudo, "args.into()")});
|
||||||
}
|
}
|
||||||
% endfor
|
% endfor
|
||||||
None
|
None
|
||||||
|
|
|
@ -13,11 +13,13 @@ use gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI};
|
||||||
use invalidation::element::document_state::InvalidationMatchingData;
|
use invalidation::element::document_state::InvalidationMatchingData;
|
||||||
use selector_parser::{Direction, SelectorParser};
|
use selector_parser::{Direction, SelectorParser};
|
||||||
use selectors::SelectorList;
|
use selectors::SelectorList;
|
||||||
use selectors::parser::{self as selector_parser, Selector, SelectorParseErrorKind, Visit};
|
use selectors::parser::{SelectorParseErrorKind, Visit};
|
||||||
|
use selectors::parser::{self as selector_parser, Selector};
|
||||||
use selectors::visitor::SelectorVisitor;
|
use selectors::visitor::SelectorVisitor;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
|
use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
|
||||||
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss as ToCss_};
|
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss as ToCss_};
|
||||||
|
use thin_slice::ThinBoxedSlice;
|
||||||
|
|
||||||
pub use gecko::pseudo_element::{PseudoElement, EAGER_PSEUDOS, EAGER_PSEUDO_COUNT, PSEUDO_COUNT};
|
pub use gecko::pseudo_element::{PseudoElement, EAGER_PSEUDOS, EAGER_PSEUDO_COUNT, PSEUDO_COUNT};
|
||||||
pub use gecko::snapshot::SnapshotMap;
|
pub use gecko::snapshot::SnapshotMap;
|
||||||
|
@ -34,7 +36,7 @@ bitflags! {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The type used for storing pseudo-class string arguments.
|
/// The type used for storing pseudo-class string arguments.
|
||||||
pub type PseudoClassStringArg = Box<[u16]>;
|
pub type PseudoClassStringArg = ThinBoxedSlice<u16>;
|
||||||
|
|
||||||
macro_rules! pseudo_class_name {
|
macro_rules! pseudo_class_name {
|
||||||
(bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*],
|
(bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*],
|
||||||
|
@ -56,7 +58,7 @@ macro_rules! pseudo_class_name {
|
||||||
///
|
///
|
||||||
/// TODO(emilio): We disallow combinators and pseudos here, so we
|
/// TODO(emilio): We disallow combinators and pseudos here, so we
|
||||||
/// should use SimpleSelector instead
|
/// should use SimpleSelector instead
|
||||||
MozAny(Box<[Selector<SelectorImpl>]>),
|
MozAny(ThinBoxedSlice<Selector<SelectorImpl>>),
|
||||||
/// The non-standard `:-moz-locale-dir` pseudo-class.
|
/// The non-standard `:-moz-locale-dir` pseudo-class.
|
||||||
MozLocaleDir(Box<Direction>),
|
MozLocaleDir(Box<Direction>),
|
||||||
}
|
}
|
||||||
|
@ -405,7 +407,7 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
|
||||||
// convert to null terminated utf16 string
|
// convert to null terminated utf16 string
|
||||||
// since that's what Gecko deals with
|
// since that's what Gecko deals with
|
||||||
let utf16: Vec<u16> = name.encode_utf16().chain(Some(0u16)).collect();
|
let utf16: Vec<u16> = name.encode_utf16().chain(Some(0u16)).collect();
|
||||||
NonTSPseudoClass::$s_name(utf16.into_boxed_slice())
|
NonTSPseudoClass::$s_name(utf16.into_boxed_slice().into())
|
||||||
}, )*
|
}, )*
|
||||||
"-moz-locale-dir" => {
|
"-moz-locale-dir" => {
|
||||||
NonTSPseudoClass::MozLocaleDir(
|
NonTSPseudoClass::MozLocaleDir(
|
||||||
|
@ -422,7 +424,7 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
|
||||||
selector_parser::parse_compound_selector_list(
|
selector_parser::parse_compound_selector_list(
|
||||||
self,
|
self,
|
||||||
parser,
|
parser,
|
||||||
)?
|
)?.into()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
_ => return Err(parser.new_custom_error(
|
_ => return Err(parser.new_custom_error(
|
||||||
|
@ -486,7 +488,9 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
|
||||||
}
|
}
|
||||||
let args = args.into_boxed_slice();
|
let args = args.into_boxed_slice();
|
||||||
if let Some(pseudo) = PseudoElement::tree_pseudo_element(&name, args) {
|
if let Some(pseudo) = PseudoElement::tree_pseudo_element(&name, args) {
|
||||||
return Ok(pseudo);
|
if self.is_pseudo_element_enabled(&pseudo) {
|
||||||
|
return Ok(pseudo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(
|
Err(
|
||||||
|
|
|
@ -156,6 +156,15 @@ impl GeckoElementSnapshot {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ElementSnapshot for 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> {
|
fn state(&self) -> Option<ElementState> {
|
||||||
if self.has_any(Flags::State) {
|
if self.has_any(Flags::State) {
|
||||||
Some(ElementState::from_bits_truncate(self.mState))
|
Some(ElementState::from_bits_truncate(self.mState))
|
||||||
|
|
|
@ -30,7 +30,7 @@ use gecko::selector_parser::{NonTSPseudoClass, PseudoElement, SelectorImpl};
|
||||||
use gecko::snapshot_helpers;
|
use gecko::snapshot_helpers;
|
||||||
use gecko_bindings::bindings;
|
use gecko_bindings::bindings;
|
||||||
use gecko_bindings::bindings::{Gecko_ElementState, Gecko_GetDocumentLWTheme};
|
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_SetNodeFlags, Gecko_UnsetNodeFlags};
|
||||||
use gecko_bindings::bindings::Gecko_ClassOrClassList;
|
use gecko_bindings::bindings::Gecko_ClassOrClassList;
|
||||||
use gecko_bindings::bindings::Gecko_ElementHasAnimations;
|
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::nsIDocument_DocumentTheme as DocumentTheme;
|
||||||
use gecko_bindings::structs::nsRestyleHint;
|
use gecko_bindings::structs::nsRestyleHint;
|
||||||
use gecko_bindings::sugar::ownership::{HasArcFFI, HasSimpleFFI};
|
use gecko_bindings::sugar::ownership::{HasArcFFI, HasSimpleFFI};
|
||||||
use hash::FnvHashMap;
|
use hash::FxHashMap;
|
||||||
use logical_geometry::WritingMode;
|
use logical_geometry::WritingMode;
|
||||||
use media_queries::Device;
|
use media_queries::Device;
|
||||||
use properties::{ComputedValues, LonghandId};
|
use properties::{ComputedValues, LonghandId};
|
||||||
|
@ -375,7 +375,12 @@ impl<'ln> TNode for GeckoNode<'ln> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn first_child(&self) -> Option<Self> {
|
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]
|
#[inline]
|
||||||
|
@ -385,17 +390,17 @@ impl<'ln> TNode for GeckoNode<'ln> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn prev_sibling(&self) -> Option<Self> {
|
fn prev_sibling(&self) -> Option<Self> {
|
||||||
unsafe {
|
unsafe { Gecko_GetPreviousSibling(self.0).map(GeckoNode) }
|
||||||
self.0
|
|
||||||
.mPreviousSibling
|
|
||||||
.as_ref()
|
|
||||||
.map(GeckoNode::from_content)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn next_sibling(&self) -> Option<Self> {
|
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]
|
#[inline]
|
||||||
|
@ -562,28 +567,15 @@ pub struct GeckoElement<'le>(pub &'le RawGeckoElement);
|
||||||
|
|
||||||
impl<'le> fmt::Debug for GeckoElement<'le> {
|
impl<'le> fmt::Debug for GeckoElement<'le> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
use nsstring::nsCString;
|
||||||
|
|
||||||
write!(f, "<{}", self.local_name())?;
|
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);
|
||||||
}
|
}
|
||||||
|
write!(f, "{}", 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, "> ({:#x})", self.as_node().opaque().0)
|
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_EndValueAt;
|
||||||
use gecko_bindings::bindings::Gecko_ElementTransitions_Length;
|
use gecko_bindings::bindings::Gecko_ElementTransitions_Length;
|
||||||
|
|
||||||
let collection_length = unsafe { Gecko_ElementTransitions_Length(self.0) } as usize;
|
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 {
|
for i in 0..collection_length {
|
||||||
let raw_end_value = unsafe { Gecko_ElementTransitions_EndValueAt(self.0, i) };
|
let raw_end_value = unsafe { Gecko_ElementTransitions_EndValueAt(self.0, i) };
|
||||||
|
@ -893,7 +885,7 @@ impl<'le> GeckoElement<'le> {
|
||||||
combined_duration: f32,
|
combined_duration: f32,
|
||||||
before_change_style: &ComputedValues,
|
before_change_style: &ComputedValues,
|
||||||
after_change_style: &ComputedValues,
|
after_change_style: &ComputedValues,
|
||||||
existing_transitions: &FnvHashMap<LonghandId, Arc<AnimationValue>>,
|
existing_transitions: &FxHashMap<LonghandId, Arc<AnimationValue>>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
use values::animated::{Animate, Procedure};
|
use values::animated::{Animate, Procedure};
|
||||||
debug_assert!(!longhand_id.is_logical());
|
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)) }
|
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]
|
#[inline]
|
||||||
fn prev_sibling_element(&self) -> Option<Self> {
|
fn prev_sibling_element(&self) -> Option<Self> {
|
||||||
let mut sibling = self.as_node().prev_sibling();
|
let mut sibling = self.as_node().prev_sibling();
|
||||||
|
@ -2087,15 +2055,15 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_root(&self) -> bool {
|
fn is_root(&self) -> bool {
|
||||||
let parent_node = match self.as_node().parent_node() {
|
if self.as_node().get_bool_flag(nsINode_BooleanFlag::ParentIsContent) {
|
||||||
Some(parent_node) => parent_node,
|
|
||||||
None => return false,
|
|
||||||
};
|
|
||||||
|
|
||||||
if !parent_node.is_document() {
|
|
||||||
return false;
|
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) }
|
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
|
// match the proper pseudo-element, given how we rulehash the stuff
|
||||||
// based on the pseudo.
|
// based on the pseudo.
|
||||||
match self.implemented_pseudo_element() {
|
match self.implemented_pseudo_element() {
|
||||||
Some(ref pseudo) => *pseudo == pseudo_element.canonical(),
|
Some(ref pseudo) => *pseudo == *pseudo_element,
|
||||||
None => false,
|
None => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
//! Can go away when the stdlib gets fallible collections
|
//! Can go away when the stdlib gets fallible collections
|
||||||
//! https://github.com/rust-lang/rfcs/pull/2116
|
//! https://github.com/rust-lang/rfcs/pull/2116
|
||||||
|
|
||||||
use fnv;
|
use fxhash;
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
pub use hashglobe::hash_map::HashMap;
|
pub use hashglobe::hash_map::HashMap;
|
||||||
|
@ -25,7 +25,7 @@ pub mod map {
|
||||||
pub use std::collections::hash_map::{Entry, Iter};
|
pub use std::collections::hash_map::{Entry, Iter};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Hash map that uses the FNV hasher
|
/// Hash map that uses the Fx hasher
|
||||||
pub type FnvHashMap<K, V> = HashMap<K, V, fnv::FnvBuildHasher>;
|
pub type FxHashMap<K, V> = HashMap<K, V, fxhash::FxBuildHasher>;
|
||||||
/// Hash set that uses the FNV hasher
|
/// Hash set that uses the Fx hasher
|
||||||
pub type FnvHashSet<T> = HashSet<T, fnv::FnvBuildHasher>;
|
pub type FxHashSet<T> = HashSet<T, fxhash::FxBuildHasher>;
|
||||||
|
|
|
@ -43,6 +43,11 @@ pub trait ElementSnapshot: Sized {
|
||||||
/// If this snapshot contains attribute information.
|
/// If this snapshot contains attribute information.
|
||||||
fn has_attrs(&self) -> bool;
|
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
|
/// The ID attribute per this snapshot. Should only be called if
|
||||||
/// `has_attrs()` returns true.
|
/// `has_attrs()` returns true.
|
||||||
fn id_attr(&self) -> Option<&WeakAtom>;
|
fn id_attr(&self) -> Option<&WeakAtom>;
|
||||||
|
@ -278,16 +283,6 @@ where
|
||||||
Some(Self::new(host, self.snapshot_map))
|
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> {
|
fn prev_sibling_element(&self) -> Option<Self> {
|
||||||
let sibling = self.element.prev_sibling_element()?;
|
let sibling = self.element.prev_sibling_element()?;
|
||||||
Some(Self::new(sibling, self.snapshot_map))
|
Some(Self::new(sibling, self.snapshot_map))
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
//! changes.
|
//! changes.
|
||||||
|
|
||||||
use {Atom, WeakAtom};
|
use {Atom, WeakAtom};
|
||||||
use context::{QuirksMode, SharedStyleContext};
|
use context::SharedStyleContext;
|
||||||
use data::ElementData;
|
use data::ElementData;
|
||||||
use dom::TElement;
|
use dom::TElement;
|
||||||
use element_state::ElementState;
|
use element_state::ElementState;
|
||||||
|
@ -18,13 +18,11 @@ use invalidation::element::restyle_hints::RestyleHint;
|
||||||
use selector_map::SelectorMap;
|
use selector_map::SelectorMap;
|
||||||
use selector_parser::Snapshot;
|
use selector_parser::Snapshot;
|
||||||
use selectors::NthIndexCache;
|
use selectors::NthIndexCache;
|
||||||
use selectors::OpaqueElement;
|
|
||||||
use selectors::attr::CaseSensitivity;
|
use selectors::attr::CaseSensitivity;
|
||||||
use selectors::matching::{MatchingContext, MatchingMode, VisitedHandlingMode};
|
use selectors::matching::{MatchingContext, MatchingMode, VisitedHandlingMode};
|
||||||
use selectors::matching::matches_selector;
|
use selectors::matching::matches_selector;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use stylesheets::origin::{Origin, OriginSet};
|
use stylesheets::origin::{Origin, OriginSet};
|
||||||
use stylist::CascadeData;
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
enum VisitedDependent {
|
enum VisitedDependent {
|
||||||
|
@ -56,19 +54,15 @@ where
|
||||||
/// changes.
|
/// changes.
|
||||||
pub struct StateAndAttrInvalidationProcessor<'a, 'b: 'a, E: TElement> {
|
pub struct StateAndAttrInvalidationProcessor<'a, 'b: 'a, E: TElement> {
|
||||||
shared_context: &'a SharedStyleContext<'b>,
|
shared_context: &'a SharedStyleContext<'b>,
|
||||||
shadow_rule_datas: &'a [(&'b CascadeData, QuirksMode, Option<OpaqueElement>)],
|
|
||||||
matches_document_author_rules: bool,
|
|
||||||
element: E,
|
element: E,
|
||||||
data: &'a mut ElementData,
|
data: &'a mut ElementData,
|
||||||
matching_context: MatchingContext<'a, E::Impl>,
|
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.
|
/// Creates a new StateAndAttrInvalidationProcessor.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
shared_context: &'a SharedStyleContext<'b>,
|
shared_context: &'a SharedStyleContext<'b>,
|
||||||
shadow_rule_datas: &'a [(&'b CascadeData, QuirksMode, Option<OpaqueElement>)],
|
|
||||||
matches_document_author_rules: bool,
|
|
||||||
element: E,
|
element: E,
|
||||||
data: &'a mut ElementData,
|
data: &'a mut ElementData,
|
||||||
nth_index_cache: &'a mut NthIndexCache,
|
nth_index_cache: &'a mut NthIndexCache,
|
||||||
|
@ -83,8 +77,6 @@ impl<'a, 'b: 'a, E: TElement> StateAndAttrInvalidationProcessor<'a, 'b, E> {
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
shared_context,
|
shared_context,
|
||||||
shadow_rule_datas,
|
|
||||||
matches_document_author_rules,
|
|
||||||
element,
|
element,
|
||||||
data,
|
data,
|
||||||
matching_context,
|
matching_context,
|
||||||
|
@ -157,6 +149,7 @@ where
|
||||||
descendant_invalidations: &mut DescendantInvalidationLists<'a>,
|
descendant_invalidations: &mut DescendantInvalidationLists<'a>,
|
||||||
sibling_invalidations: &mut InvalidationVector<'a>,
|
sibling_invalidations: &mut InvalidationVector<'a>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
debug_assert_eq!(element, self.element);
|
||||||
debug_assert!(element.has_snapshot(), "Why bothering?");
|
debug_assert!(element.has_snapshot(), "Why bothering?");
|
||||||
|
|
||||||
let wrapper = ElementWrapper::new(element, &*self.shared_context.snapshot_map);
|
let wrapper = ElementWrapper::new(element, &*self.shared_context.snapshot_map);
|
||||||
|
@ -208,20 +201,32 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("Collecting changes for: {:?}", element);
|
if log_enabled!(::log::Level::Debug) {
|
||||||
debug!(" > state: {:?}", state_changes);
|
debug!("Collecting changes for: {:?}", element);
|
||||||
debug!(
|
if !state_changes.is_empty() {
|
||||||
" > id changed: {:?} -> +{:?} -{:?}",
|
debug!(" > state: {:?}", state_changes);
|
||||||
snapshot.id_changed(),
|
}
|
||||||
id_added,
|
if snapshot.id_changed() {
|
||||||
id_removed
|
debug!(
|
||||||
);
|
" > id changed: +{:?} -{:?}",
|
||||||
debug!(
|
id_added,
|
||||||
" > class changed: {:?} -> +{:?} -{:?}",
|
id_removed
|
||||||
snapshot.class_changed(),
|
);
|
||||||
classes_added,
|
}
|
||||||
classes_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() {
|
let lookup_element = if element.implemented_pseudo_element().is_some() {
|
||||||
element.pseudo_element_originating_element().unwrap()
|
element.pseudo_element_originating_element().unwrap()
|
||||||
|
@ -229,6 +234,13 @@ where
|
||||||
element
|
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 invalidated_self = {
|
||||||
let mut collector = Collector {
|
let mut collector = Collector {
|
||||||
wrapper,
|
wrapper,
|
||||||
|
@ -246,7 +258,7 @@ where
|
||||||
invalidates_self: false,
|
invalidates_self: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let document_origins = if !self.matches_document_author_rules {
|
let document_origins = if !matches_document_author_rules {
|
||||||
Origin::UserAgent.into()
|
Origin::UserAgent.into()
|
||||||
} else {
|
} else {
|
||||||
OriginSet::all()
|
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
|
// FIXME(emilio): Replace with assert / remove when we figure
|
||||||
// out what to do with the quirks mode mismatches
|
// out what to do with the quirks mode mismatches
|
||||||
// (that is, when bug 1406875 is properly fixed).
|
// (that is, when bug 1406875 is properly fixed).
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
//! Code related to the invalidation of media-query-affected rules.
|
//! Code related to the invalidation of media-query-affected rules.
|
||||||
|
|
||||||
use context::QuirksMode;
|
use context::QuirksMode;
|
||||||
use fnv::FnvHashSet;
|
use fxhash::FxHashSet;
|
||||||
use media_queries::Device;
|
use media_queries::Device;
|
||||||
use shared_lock::SharedRwLockReadGuard;
|
use shared_lock::SharedRwLockReadGuard;
|
||||||
use stylesheets::{DocumentRule, ImportRule, MediaRule};
|
use stylesheets::{DocumentRule, ImportRule, MediaRule};
|
||||||
|
@ -54,14 +54,14 @@ impl ToMediaListKey for MediaRule {}
|
||||||
#[derive(Debug, MallocSizeOf, PartialEq)]
|
#[derive(Debug, MallocSizeOf, PartialEq)]
|
||||||
pub struct EffectiveMediaQueryResults {
|
pub struct EffectiveMediaQueryResults {
|
||||||
/// The set of media lists that matched last time.
|
/// The set of media lists that matched last time.
|
||||||
set: FnvHashSet<MediaListKey>,
|
set: FxHashSet<MediaListKey>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EffectiveMediaQueryResults {
|
impl EffectiveMediaQueryResults {
|
||||||
/// Trivially constructs an empty `EffectiveMediaQueryResults`.
|
/// Trivially constructs an empty `EffectiveMediaQueryResults`.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
set: FnvHashSet::default(),
|
set: FxHashSet::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ use Atom;
|
||||||
use CaseSensitivityExt;
|
use CaseSensitivityExt;
|
||||||
use LocalName as SelectorLocalName;
|
use LocalName as SelectorLocalName;
|
||||||
use dom::{TDocument, TElement, TNode};
|
use dom::{TDocument, TElement, TNode};
|
||||||
use fnv::FnvHashSet;
|
use fxhash::FxHashSet;
|
||||||
use invalidation::element::element_wrapper::{ElementSnapshot, ElementWrapper};
|
use invalidation::element::element_wrapper::{ElementSnapshot, ElementWrapper};
|
||||||
use invalidation::element::restyle_hints::RestyleHint;
|
use invalidation::element::restyle_hints::RestyleHint;
|
||||||
use media_queries::Device;
|
use media_queries::Device;
|
||||||
|
@ -106,9 +106,9 @@ impl Invalidation {
|
||||||
#[derive(MallocSizeOf)]
|
#[derive(MallocSizeOf)]
|
||||||
pub struct StylesheetInvalidationSet {
|
pub struct StylesheetInvalidationSet {
|
||||||
/// The subtrees we know we have to restyle so far.
|
/// 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.
|
/// 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.
|
/// Whether the whole document should be restyled.
|
||||||
fully_invalid: bool,
|
fully_invalid: bool,
|
||||||
}
|
}
|
||||||
|
@ -117,8 +117,8 @@ impl StylesheetInvalidationSet {
|
||||||
/// Create an empty `StylesheetInvalidationSet`.
|
/// Create an empty `StylesheetInvalidationSet`.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
invalid_scopes: FnvHashSet::default(),
|
invalid_scopes: FxHashSet::default(),
|
||||||
invalid_elements: FnvHashSet::default(),
|
invalid_elements: FxHashSet::default(),
|
||||||
fully_invalid: false,
|
fully_invalid: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ extern crate cssparser;
|
||||||
extern crate debug_unreachable;
|
extern crate debug_unreachable;
|
||||||
extern crate euclid;
|
extern crate euclid;
|
||||||
extern crate fallible;
|
extern crate fallible;
|
||||||
extern crate fnv;
|
extern crate fxhash;
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod gecko_string_cache;
|
pub mod gecko_string_cache;
|
||||||
|
@ -93,6 +93,8 @@ extern crate string_cache;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate style_derive;
|
extern crate style_derive;
|
||||||
extern crate style_traits;
|
extern crate style_traits;
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
extern crate thin_slice;
|
||||||
extern crate time;
|
extern crate time;
|
||||||
extern crate uluru;
|
extern crate uluru;
|
||||||
extern crate unicode_bidi;
|
extern crate unicode_bidi;
|
||||||
|
|
|
@ -368,6 +368,34 @@ def set_gecko_property(ffi_name, expr):
|
||||||
return "self.gecko.%s = %s;" % (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)">
|
<%def name="impl_keyword_setter(ident, gecko_ffi_name, keyword, cast_type='u8', on_set=None)">
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
|
pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
|
||||||
|
@ -3015,7 +3043,7 @@ fn static_assert() {
|
||||||
}
|
}
|
||||||
</%def>
|
</%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-name animation-delay animation-duration
|
||||||
animation-direction animation-fill-mode animation-play-state
|
animation-direction animation-fill-mode animation-play-state
|
||||||
animation-iteration-count animation-timing-function
|
animation-iteration-count animation-timing-function
|
||||||
|
@ -3031,57 +3059,41 @@ fn static_assert() {
|
||||||
shape-outside contain touch-action translate
|
shape-outside contain touch-action translate
|
||||||
scale""" %>
|
scale""" %>
|
||||||
<%self:impl_trait style_struct_name="Box" skip_longhands="${skip_box_longhands}">
|
<%self:impl_trait style_struct_name="Box" skip_longhands="${skip_box_longhands}">
|
||||||
|
#[inline]
|
||||||
// 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_display(&mut self, v: longhands::display::computed_value::T) {
|
pub fn set_display(&mut self, v: longhands::display::computed_value::T) {
|
||||||
let result = Self::match_display_keyword(v);
|
// unsafe: cbindgen ensures the representation is the same.
|
||||||
self.gecko.mDisplay = result;
|
self.gecko.mDisplay = unsafe { transmute(v) };
|
||||||
self.gecko.mOriginalDisplay = result;
|
self.gecko.mOriginalDisplay = unsafe { transmute(v) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn copy_display_from(&mut self, other: &Self) {
|
pub fn copy_display_from(&mut self, other: &Self) {
|
||||||
self.gecko.mDisplay = other.gecko.mDisplay;
|
self.gecko.mDisplay = other.gecko.mDisplay;
|
||||||
self.gecko.mOriginalDisplay = other.gecko.mDisplay;
|
self.gecko.mOriginalDisplay = other.gecko.mDisplay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn reset_display(&mut self, other: &Self) {
|
pub fn reset_display(&mut self, other: &Self) {
|
||||||
self.copy_display_from(other)
|
self.copy_display_from(other)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn set_adjusted_display(
|
pub fn set_adjusted_display(
|
||||||
&mut self,
|
&mut self,
|
||||||
v: longhands::display::computed_value::T,
|
v: longhands::display::computed_value::T,
|
||||||
_is_item_or_root: bool
|
_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") %>
|
<% float_keyword = Keyword("float", "Left Right None", gecko_enum_prefix="StyleFloat") %>
|
||||||
${impl_keyword('float', 'mFloat', float_keyword)}
|
${impl_keyword('float', 'mFloat', float_keyword)}
|
||||||
|
|
|
@ -25,7 +25,7 @@ use servo_arc::Arc;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::{cmp, ptr};
|
use std::{cmp, ptr};
|
||||||
use std::mem::{self, ManuallyDrop};
|
use std::mem::{self, ManuallyDrop};
|
||||||
use hash::FnvHashMap;
|
use hash::FxHashMap;
|
||||||
use super::ComputedValues;
|
use super::ComputedValues;
|
||||||
use values::CSSFloat;
|
use values::CSSFloat;
|
||||||
use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
|
use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
|
||||||
|
@ -232,7 +232,7 @@ impl AnimatedProperty {
|
||||||
/// A collection of AnimationValue that were composed on an element.
|
/// A collection of AnimationValue that were composed on an element.
|
||||||
/// This HashMap stores the values that are the last AnimationValue to be
|
/// This HashMap stores the values that are the last AnimationValue to be
|
||||||
/// composed for each TransitionProperty.
|
/// composed for each TransitionProperty.
|
||||||
pub type AnimationValueMap = FnvHashMap<LonghandId, AnimationValue>;
|
pub type AnimationValueMap = FxHashMap<LonghandId, AnimationValue>;
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
unsafe impl HasFFI for AnimationValueMap {
|
unsafe impl HasFFI for AnimationValueMap {
|
||||||
|
|
|
@ -508,41 +508,15 @@ ${helpers.predefined_type("contain",
|
||||||
spec="https://drafts.csswg.org/css-contain/#contain-property")}
|
spec="https://drafts.csswg.org/css-contain/#contain-property")}
|
||||||
|
|
||||||
// Non-standard
|
// Non-standard
|
||||||
${helpers.single_keyword("-moz-appearance",
|
${helpers.predefined_type(
|
||||||
"""none button button-arrow-down button-arrow-next button-arrow-previous button-arrow-up
|
"-moz-appearance",
|
||||||
button-bevel button-focus caret checkbox checkbox-container checkbox-label checkmenuitem
|
"Appearance",
|
||||||
dialog dualbutton groupbox inner-spin-button listbox listitem menuarrow menubar menucheckbox
|
"computed::Appearance::None",
|
||||||
menuimage menuitem menuitemtext menulist menulist-button menulist-text menulist-textfield
|
products="gecko",
|
||||||
menupopup menuradio menuseparator meterbar meterchunk number-input progressbar
|
alias="-webkit-appearance:layout.css.webkit-appearance.enabled",
|
||||||
progressbar-vertical progresschunk progresschunk-vertical radio radio-container radio-label
|
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-appearance)",
|
||||||
radiomenuitem range range-thumb resizer resizerpanel scale-horizontal scalethumbend
|
animation_value_type="discrete",
|
||||||
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-binding", "url::UrlOrNone", "computed::url::UrlOrNone::none()",
|
${helpers.predefined_type("-moz-binding", "url::UrlOrNone", "computed::url::UrlOrNone::none()",
|
||||||
products="gecko",
|
products="gecko",
|
||||||
|
|
|
@ -410,25 +410,44 @@ pub mod animated_properties {
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct NonCustomPropertyId(usize);
|
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 {
|
impl NonCustomPropertyId {
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_nscsspropertyid(self) -> nsCSSPropertyID {
|
fn to_nscsspropertyid(self) -> nsCSSPropertyID {
|
||||||
static MAP: [nsCSSPropertyID; ${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())}] = [
|
// unsafe: guaranteed by static_assert_nscsspropertyid above.
|
||||||
% for property in data.longhands + data.shorthands + data.all_aliases():
|
unsafe { ::std::mem::transmute(self.0 as i32) }
|
||||||
${property.nscsspropertyid()},
|
}
|
||||||
% endfor
|
|
||||||
];
|
|
||||||
|
|
||||||
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.
|
/// Get the property name.
|
||||||
#[inline]
|
#[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())}] = [
|
static MAP: [&'static str; ${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())}] = [
|
||||||
% for property in data.longhands + data.shorthands + data.all_aliases():
|
% for property in data.longhands + data.shorthands + data.all_aliases():
|
||||||
"${property.name}",
|
"${property.name}",
|
||||||
% endfor
|
% endfor
|
||||||
];
|
];
|
||||||
MAP[self.0]
|
MAP[self.0]
|
||||||
|
@ -464,7 +483,7 @@ impl NonCustomPropertyId {
|
||||||
|
|
||||||
PREFS.get(pref).as_boolean().unwrap_or(false)
|
PREFS.get(pref).as_boolean().unwrap_or(false)
|
||||||
% else:
|
% else:
|
||||||
unsafe { structs::nsCSSProps_gPropertyEnabled[self.to_nscsspropertyid() as usize] }
|
unsafe { structs::nsCSSProps_gPropertyEnabled[self.0] }
|
||||||
% endif
|
% endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -585,6 +604,31 @@ impl NonCustomPropertyId {
|
||||||
];
|
];
|
||||||
COLLECT_FUNCTIONS[self.0](f);
|
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 {
|
impl From<LonghandId> for NonCustomPropertyId {
|
||||||
|
@ -1237,10 +1281,11 @@ where
|
||||||
|
|
||||||
/// An identifier for a given shorthand property.
|
/// An identifier for a given shorthand property.
|
||||||
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
|
||||||
|
#[repr(u16)]
|
||||||
pub enum ShorthandId {
|
pub enum ShorthandId {
|
||||||
% for property in data.shorthands:
|
% for i, property in enumerate(data.shorthands):
|
||||||
/// ${property.name}
|
/// ${property.name}
|
||||||
${property.camel_case},
|
${property.camel_case} = ${i},
|
||||||
% endfor
|
% endfor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1767,42 +1812,11 @@ impl PropertyId {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a property id from Gecko's nsCSSPropertyID.
|
/// 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")]
|
#[cfg(feature = "gecko")]
|
||||||
#[allow(non_upper_case_globals)]
|
#[allow(non_upper_case_globals)]
|
||||||
|
#[inline]
|
||||||
pub fn from_nscsspropertyid(id: nsCSSPropertyID) -> Result<Self, ()> {
|
pub fn from_nscsspropertyid(id: nsCSSPropertyID) -> Result<Self, ()> {
|
||||||
use gecko_bindings::structs::*;
|
Ok(NonCustomPropertyId::from_nscsspropertyid(id)?.to_property_id())
|
||||||
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(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the property is a shorthand or shorthand alias.
|
/// Returns true if the property is a shorthand or shorthand alias.
|
||||||
|
@ -1858,6 +1872,18 @@ impl PropertyId {
|
||||||
id.enabled_for_all_content()
|
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 {
|
fn allowed_in(&self, context: &ParserContext) -> bool {
|
||||||
let id = match self.non_custom_id() {
|
let id = match self.non_custom_id() {
|
||||||
// Custom properties are allowed everywhere
|
// Custom properties are allowed everywhere
|
||||||
|
@ -2387,7 +2413,7 @@ pub use gecko_properties::style_structs;
|
||||||
/// The module where all the style structs are defined.
|
/// The module where all the style structs are defined.
|
||||||
#[cfg(feature = "servo")]
|
#[cfg(feature = "servo")]
|
||||||
pub mod style_structs {
|
pub mod style_structs {
|
||||||
use fnv::FnvHasher;
|
use fxhash::FxHasher;
|
||||||
use super::longhands;
|
use super::longhands;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use logical_geometry::WritingMode;
|
use logical_geometry::WritingMode;
|
||||||
|
@ -2534,7 +2560,7 @@ pub mod style_structs {
|
||||||
pub fn compute_font_hash(&mut self) {
|
pub fn compute_font_hash(&mut self) {
|
||||||
// Corresponds to the fields in
|
// Corresponds to the fields in
|
||||||
// `gfx::font_template::FontTemplateDescriptor`.
|
// `gfx::font_template::FontTemplateDescriptor`.
|
||||||
let mut hasher: FnvHasher = Default::default();
|
let mut hasher: FxHasher = Default::default();
|
||||||
self.font_weight.hash(&mut hasher);
|
self.font_weight.hash(&mut hasher);
|
||||||
self.font_stretch.hash(&mut hasher);
|
self.font_stretch.hash(&mut hasher);
|
||||||
self.font_style.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.
|
/// An identifier for a given alias property.
|
||||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||||
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
|
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
|
||||||
|
#[repr(u16)]
|
||||||
pub enum AliasId {
|
pub enum AliasId {
|
||||||
% for i, property in enumerate(data.all_aliases()):
|
% for i, property in enumerate(data.all_aliases()):
|
||||||
/// ${property.name}
|
/// ${property.name}
|
||||||
|
@ -4237,17 +4264,38 @@ pub enum AliasId {
|
||||||
% endfor
|
% 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 {
|
impl fmt::Debug for AliasId {
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
let name = match *self {
|
let name = NonCustomPropertyId::from(*self).name();
|
||||||
% for property in data.all_aliases():
|
|
||||||
AliasId::${property.camel_case} => "${property.camel_case}",
|
|
||||||
% endfor
|
|
||||||
};
|
|
||||||
formatter.write_str(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.
|
// NOTE(emilio): Callers are responsible to deal with prefs.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! css_properties_accessors {
|
macro_rules! css_properties_accessors {
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
//! A cache from rule node to computed values, in order to cache reset
|
//! A cache from rule node to computed values, in order to cache reset
|
||||||
//! properties.
|
//! properties.
|
||||||
|
|
||||||
use fnv::FnvHashMap;
|
use fxhash::FxHashMap;
|
||||||
use logical_geometry::WritingMode;
|
use logical_geometry::WritingMode;
|
||||||
use properties::{ComputedValues, StyleBuilder};
|
use properties::{ComputedValues, StyleBuilder};
|
||||||
use rule_tree::StrongRuleNode;
|
use rule_tree::StrongRuleNode;
|
||||||
|
@ -71,14 +71,14 @@ impl RuleCacheConditions {
|
||||||
/// A TLS cache from rules matched to computed values.
|
/// A TLS cache from rules matched to computed values.
|
||||||
pub struct RuleCache {
|
pub struct RuleCache {
|
||||||
// FIXME(emilio): Consider using LRUCache or something like that?
|
// 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 {
|
impl RuleCache {
|
||||||
/// Creates an empty `RuleCache`.
|
/// Creates an empty `RuleCache`.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
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) {
|
unsafe fn assert_free_list_has_no_duplicates_or_null(&self) {
|
||||||
assert!(cfg!(debug_assertions), "This is an expensive check!");
|
assert!(cfg!(debug_assertions), "This is an expensive check!");
|
||||||
use hash::FnvHashSet;
|
use hash::FxHashSet;
|
||||||
|
|
||||||
let me = &*self.ptr();
|
let me = &*self.ptr();
|
||||||
assert!(me.is_root());
|
assert!(me.is_root());
|
||||||
|
|
||||||
let mut current = self.ptr();
|
let mut current = self.ptr();
|
||||||
let mut seen = FnvHashSet::default();
|
let mut seen = FxHashSet::default();
|
||||||
while current != FREE_LIST_SENTINEL {
|
while current != FREE_LIST_SENTINEL {
|
||||||
let next = (*current).next_free.load(Ordering::Relaxed);
|
let next = (*current).next_free.load(Ordering::Relaxed);
|
||||||
assert!(!next.is_null());
|
assert!(!next.is_null());
|
||||||
|
|
|
@ -96,6 +96,8 @@ pub trait SelectorMapEntry: Sized + Clone {
|
||||||
/// TODO: Tune the initial capacity of the HashMap
|
/// TODO: Tune the initial capacity of the HashMap
|
||||||
#[derive(Debug, MallocSizeOf)]
|
#[derive(Debug, MallocSizeOf)]
|
||||||
pub struct SelectorMap<T: 'static> {
|
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.
|
/// A hash from an ID to rules which contain that ID selector.
|
||||||
pub id_hash: MaybeCaseInsensitiveHashMap<Atom, SmallVec<[T; 1]>>,
|
pub id_hash: MaybeCaseInsensitiveHashMap<Atom, SmallVec<[T; 1]>>,
|
||||||
/// A hash from a class name to rules which contain that class selector.
|
/// 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]>>,
|
pub local_name_hash: PrecomputedHashMap<LocalName, SmallVec<[T; 1]>>,
|
||||||
/// A hash from namespace to rules which contain that namespace selector.
|
/// A hash from namespace to rules which contain that namespace selector.
|
||||||
pub namespace_hash: PrecomputedHashMap<Namespace, SmallVec<[T; 1]>>,
|
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]>,
|
pub other: SmallVec<[T; 1]>,
|
||||||
/// The number of entries in this map.
|
/// The number of entries in this map.
|
||||||
pub count: usize,
|
pub count: usize,
|
||||||
|
@ -124,6 +126,7 @@ impl<T: 'static> SelectorMap<T> {
|
||||||
/// Trivially constructs an empty `SelectorMap`.
|
/// Trivially constructs an empty `SelectorMap`.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
SelectorMap {
|
SelectorMap {
|
||||||
|
root: SmallVec::new(),
|
||||||
id_hash: MaybeCaseInsensitiveHashMap::new(),
|
id_hash: MaybeCaseInsensitiveHashMap::new(),
|
||||||
class_hash: MaybeCaseInsensitiveHashMap::new(),
|
class_hash: MaybeCaseInsensitiveHashMap::new(),
|
||||||
local_name_hash: HashMap::default(),
|
local_name_hash: HashMap::default(),
|
||||||
|
@ -135,6 +138,7 @@ impl<T: 'static> SelectorMap<T> {
|
||||||
|
|
||||||
/// Clears the hashmap retaining storage.
|
/// Clears the hashmap retaining storage.
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
|
self.root.clear();
|
||||||
self.id_hash.clear();
|
self.id_hash.clear();
|
||||||
self.class_hash.clear();
|
self.class_hash.clear();
|
||||||
self.local_name_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
|
// At the end, we're going to sort the rules that we added, so remember
|
||||||
// where we began.
|
// where we began.
|
||||||
let init_len = matching_rules_list.len();
|
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(id) = rule_hash_target.id() {
|
||||||
if let Some(rules) = self.id_hash.get(id, quirks_mode) {
|
if let Some(rules) = self.id_hash.get(id, quirks_mode) {
|
||||||
SelectorMap::get_matching_rules(
|
SelectorMap::get_matching_rules(
|
||||||
|
@ -287,6 +304,7 @@ impl<T: SelectorMapEntry> SelectorMap<T> {
|
||||||
self.count += 1;
|
self.count += 1;
|
||||||
|
|
||||||
let vector = match find_bucket(entry.selector()) {
|
let vector = match find_bucket(entry.selector()) {
|
||||||
|
Bucket::Root => &mut self.root,
|
||||||
Bucket::ID(id) => self.id_hash
|
Bucket::ID(id) => self.id_hash
|
||||||
.try_entry(id.clone(), quirks_mode)?
|
.try_entry(id.clone(), quirks_mode)?
|
||||||
.or_insert_with(SmallVec::new),
|
.or_insert_with(SmallVec::new),
|
||||||
|
@ -340,6 +358,14 @@ impl<T: SelectorMapEntry> SelectorMap<T> {
|
||||||
E: TElement,
|
E: TElement,
|
||||||
F: FnMut(&'a T) -> bool,
|
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(id) = element.id() {
|
||||||
if let Some(v) = self.id_hash.get(id, quirks_mode) {
|
if let Some(v) = self.id_hash.get(id, quirks_mode) {
|
||||||
for entry in v.iter() {
|
for entry in v.iter() {
|
||||||
|
@ -444,6 +470,7 @@ impl<T: SelectorMapEntry> SelectorMap<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Bucket<'a> {
|
enum Bucket<'a> {
|
||||||
|
Root,
|
||||||
ID(&'a Atom),
|
ID(&'a Atom),
|
||||||
Class(&'a Atom),
|
Class(&'a Atom),
|
||||||
LocalName {
|
LocalName {
|
||||||
|
@ -456,6 +483,7 @@ enum Bucket<'a> {
|
||||||
|
|
||||||
fn specific_bucket_for<'a>(component: &'a Component<SelectorImpl>) -> Bucket<'a> {
|
fn specific_bucket_for<'a>(component: &'a Component<SelectorImpl>) -> Bucket<'a> {
|
||||||
match *component {
|
match *component {
|
||||||
|
Component::Root => Bucket::Root,
|
||||||
Component::ID(ref id) => Bucket::ID(id),
|
Component::ID(ref id) => Bucket::ID(id),
|
||||||
Component::Class(ref class) => Bucket::Class(class),
|
Component::Class(ref class) => Bucket::Class(class),
|
||||||
Component::LocalName(ref selector) => Bucket::LocalName {
|
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,
|
// We basically want to find the most specific bucket,
|
||||||
// where:
|
// where:
|
||||||
//
|
//
|
||||||
// id > class > local name > namespace > universal.
|
// root > id > class > local name > namespace > universal.
|
||||||
//
|
//
|
||||||
for ss in &mut iter {
|
for ss in &mut iter {
|
||||||
let new_bucket = specific_bucket_for(ss);
|
let new_bucket = specific_bucket_for(ss);
|
||||||
match new_bucket {
|
match new_bucket {
|
||||||
Bucket::ID(..) => return new_bucket,
|
Bucket::Root => return new_bucket,
|
||||||
Bucket::Class(..) => {
|
Bucket::ID(..) => {
|
||||||
current_bucket = new_bucket;
|
current_bucket = new_bucket;
|
||||||
|
}
|
||||||
|
Bucket::Class(..) => {
|
||||||
|
if !matches!(current_bucket, Bucket::ID(..)) {
|
||||||
|
current_bucket = new_bucket;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Bucket::LocalName { .. } => {
|
Bucket::LocalName { .. } => {
|
||||||
if matches!(current_bucket, Bucket::Universal | Bucket::Namespace(..)) {
|
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 cssparser::{serialize_identifier, CowRcStr, Parser as CssParser, SourceLocation, ToCss};
|
||||||
use dom::{OpaqueNode, TElement, TNode};
|
use dom::{OpaqueNode, TElement, TNode};
|
||||||
use element_state::{DocumentState, ElementState};
|
use element_state::{DocumentState, ElementState};
|
||||||
use fnv::FnvHashMap;
|
use fxhash::FxHashMap;
|
||||||
use invalidation::element::document_state::InvalidationMatchingData;
|
use invalidation::element::document_state::InvalidationMatchingData;
|
||||||
use invalidation::element::element_wrapper::ElementSnapshot;
|
use invalidation::element::element_wrapper::ElementSnapshot;
|
||||||
use properties::{ComputedValues, PropertyFlags};
|
use properties::{ComputedValues, PropertyFlags};
|
||||||
|
@ -617,12 +617,12 @@ impl SelectorImpl {
|
||||||
|
|
||||||
/// A map from elements to snapshots for the Servo style back-end.
|
/// A map from elements to snapshots for the Servo style back-end.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SnapshotMap(FnvHashMap<OpaqueNode, ServoElementSnapshot>);
|
pub struct SnapshotMap(FxHashMap<OpaqueNode, ServoElementSnapshot>);
|
||||||
|
|
||||||
impl SnapshotMap {
|
impl SnapshotMap {
|
||||||
/// Create a new empty `SnapshotMap`.
|
/// Create a new empty `SnapshotMap`.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
SnapshotMap(FnvHashMap::default())
|
SnapshotMap(FxHashMap::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a snapshot given an element.
|
/// Get a snapshot given an element.
|
||||||
|
@ -632,7 +632,7 @@ impl SnapshotMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for SnapshotMap {
|
impl Deref for SnapshotMap {
|
||||||
type Target = FnvHashMap<OpaqueNode, ServoElementSnapshot>;
|
type Target = FxHashMap<OpaqueNode, ServoElementSnapshot>;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.0
|
&self.0
|
||||||
|
|
|
@ -7,7 +7,7 @@ use context::QuirksMode;
|
||||||
use cssparser::{Parser, ParserInput, RuleListParser};
|
use cssparser::{Parser, ParserInput, RuleListParser};
|
||||||
use error_reporting::{ContextualParseError, ParseErrorReporter};
|
use error_reporting::{ContextualParseError, ParseErrorReporter};
|
||||||
use fallible::FallibleVec;
|
use fallible::FallibleVec;
|
||||||
use fnv::FnvHashMap;
|
use fxhash::FxHashMap;
|
||||||
use invalidation::media_queries::{MediaListKey, ToMediaListKey};
|
use invalidation::media_queries::{MediaListKey, ToMediaListKey};
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
use malloc_size_of::{MallocSizeOfOps, MallocUnconditionalShallowSizeOf};
|
use malloc_size_of::{MallocSizeOfOps, MallocUnconditionalShallowSizeOf};
|
||||||
|
@ -42,7 +42,7 @@ pub struct UserAgentStylesheets {
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub struct Namespaces {
|
pub struct Namespaces {
|
||||||
pub default: Option<Namespace>,
|
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
|
/// The contents of a given stylesheet. This effectively maps to a
|
||||||
|
|
|
@ -898,7 +898,6 @@ impl Stylist {
|
||||||
where
|
where
|
||||||
E: TElement,
|
E: TElement,
|
||||||
{
|
{
|
||||||
let pseudo = pseudo.canonical();
|
|
||||||
debug_assert!(pseudo.is_lazy());
|
debug_assert!(pseudo.is_lazy());
|
||||||
|
|
||||||
// Apply the selector flags. We should be in sequential mode
|
// Apply the selector flags. We should be in sequential mode
|
||||||
|
@ -1892,7 +1891,7 @@ impl ElementAndPseudoRules {
|
||||||
let map = match pseudo_element {
|
let map = match pseudo_element {
|
||||||
None => &mut self.element_map,
|
None => &mut self.element_map,
|
||||||
Some(pseudo) => self.pseudos_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)
|
map.insert(rule, quirks_mode)
|
||||||
|
@ -1906,7 +1905,7 @@ impl ElementAndPseudoRules {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn rules(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>> {
|
fn rules(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>> {
|
||||||
match pseudo {
|
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),
|
None => Some(&self.element_map),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2190,7 +2189,7 @@ impl CascadeData {
|
||||||
precomputed_pseudo_element_decls
|
precomputed_pseudo_element_decls
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.expect("Expected precomputed declarations for the UA level")
|
.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(
|
.push(ApplicableDeclarationBlock::new(
|
||||||
StyleSource::from_rule(locked.clone()),
|
StyleSource::from_rule(locked.clone()),
|
||||||
self.rules_source_order,
|
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_::Perspective as GenericPerspective;
|
||||||
use values::generics::box_::VerticalAlign as GenericVerticalAlign;
|
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_::{Clear as SpecifiedClear, Float as SpecifiedFloat};
|
||||||
pub use values::specified::box_::{OverscrollBehavior, ScrollSnapType, TouchAction, TransitionProperty, WillChange};
|
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::{FontFeatureSettings, FontVariantLigatures, FontVariantNumeric};
|
||||||
pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextZoom};
|
pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextZoom};
|
||||||
pub use self::box_::{AnimationIterationCount, AnimationName, Contain, Display, TransitionProperty};
|
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_::{OverflowClipBox, OverscrollBehavior, Perspective};
|
||||||
pub use self::box_::{ScrollSnapType, TouchAction, VerticalAlign, WillChange};
|
pub use self::box_::{ScrollSnapType, TouchAction, VerticalAlign, WillChange};
|
||||||
pub use self::color::{Color, ColorPropertyValue, RGBAColor};
|
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::{AllowQuirks, Number};
|
||||||
use values::specified::length::{LengthOrPercentage, NonNegativeLength};
|
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")]
|
#[cfg(feature = "gecko")]
|
||||||
fn moz_display_values_enabled(context: &ParserContext) -> bool {
|
fn moz_display_values_enabled(context: &ParserContext) -> bool {
|
||||||
use gecko_bindings::structs;
|
use gecko_bindings::structs;
|
||||||
use stylesheets::Origin;
|
in_ua_or_chrome_sheet(context) ||
|
||||||
context.stylesheet_origin == Origin::UserAgent ||
|
|
||||||
context.chrome_rules_enabled() ||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
structs::StaticPrefs_sVarCache_layout_css_xul_display_values_content_enabled
|
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")]
|
#[cfg(feature = "gecko")]
|
||||||
fn moz_box_display_values_enabled(context: &ParserContext) -> bool {
|
fn moz_box_display_values_enabled(context: &ParserContext) -> bool {
|
||||||
use gecko_bindings::structs;
|
use gecko_bindings::structs;
|
||||||
use stylesheets::Origin;
|
in_ua_or_chrome_sheet(context) ||
|
||||||
context.stylesheet_origin == Origin::UserAgent ||
|
|
||||||
context.chrome_rules_enabled() ||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
structs::StaticPrefs_sVarCache_layout_css_xul_box_display_values_content_enabled
|
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)]
|
#[allow(missing_docs)]
|
||||||
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq,
|
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq,
|
||||||
SpecifiedValueInfo, ToComputedValue, ToCss)]
|
SpecifiedValueInfo, ToComputedValue, ToCss)]
|
||||||
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
|
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
|
||||||
/// Defines an element’s display type, which consists of
|
#[repr(u8)]
|
||||||
/// the two basic qualities of how an element generates boxes
|
|
||||||
/// <https://drafts.csswg.org/css-display/#propdef-display>
|
|
||||||
pub enum Display {
|
pub enum Display {
|
||||||
Inline,
|
None = 0,
|
||||||
Block,
|
Block,
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
FlowRoot,
|
||||||
|
Inline,
|
||||||
InlineBlock,
|
InlineBlock,
|
||||||
|
ListItem,
|
||||||
Table,
|
Table,
|
||||||
InlineTable,
|
InlineTable,
|
||||||
TableRowGroup,
|
TableRowGroup,
|
||||||
|
TableColumn,
|
||||||
|
TableColumnGroup,
|
||||||
TableHeaderGroup,
|
TableHeaderGroup,
|
||||||
TableFooterGroup,
|
TableFooterGroup,
|
||||||
TableRow,
|
TableRow,
|
||||||
TableColumnGroup,
|
|
||||||
TableColumn,
|
|
||||||
TableCell,
|
TableCell,
|
||||||
TableCaption,
|
TableCaption,
|
||||||
ListItem,
|
|
||||||
None,
|
|
||||||
#[parse(aliases = "-webkit-flex")]
|
#[parse(aliases = "-webkit-flex")]
|
||||||
Flex,
|
Flex,
|
||||||
#[parse(aliases = "-webkit-inline-flex")]
|
#[parse(aliases = "-webkit-inline-flex")]
|
||||||
|
@ -85,8 +100,6 @@ pub enum Display {
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
Contents,
|
Contents,
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
FlowRoot,
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
WebkitBox,
|
WebkitBox,
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
WebkitInlineBox,
|
WebkitInlineBox,
|
||||||
|
@ -119,10 +132,10 @@ pub enum Display {
|
||||||
MozDeck,
|
MozDeck,
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
#[parse(condition = "moz_display_values_enabled")]
|
#[parse(condition = "moz_display_values_enabled")]
|
||||||
MozPopup,
|
MozGroupbox,
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
#[parse(condition = "moz_display_values_enabled")]
|
#[parse(condition = "moz_display_values_enabled")]
|
||||||
MozGroupbox,
|
MozPopup,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display {
|
impl Display {
|
||||||
|
@ -870,3 +883,252 @@ pub enum Clear {
|
||||||
InlineStart,
|
InlineStart,
|
||||||
InlineEnd
|
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::{FontFeatureSettings, FontVariantLigatures, FontVariantNumeric};
|
||||||
pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextZoom};
|
pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextZoom};
|
||||||
pub use self::box_::{AnimationIterationCount, AnimationName, Contain, Display};
|
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_::{OverflowClipBox, OverscrollBehavior, Perspective};
|
||||||
pub use self::box_::{ScrollSnapType, TouchAction, TransitionProperty, VerticalAlign, WillChange};
|
pub use self::box_::{ScrollSnapType, TouchAction, TransitionProperty, VerticalAlign, WillChange};
|
||||||
pub use self::color::{Color, ColorPropertyValue, RGBAColor};
|
pub use self::color::{Color, ColorPropertyValue, RGBAColor};
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
//! [position]: https://drafts.csswg.org/css-backgrounds-3/#position
|
//! [position]: https://drafts.csswg.org/css-backgrounds-3/#position
|
||||||
|
|
||||||
use cssparser::Parser;
|
use cssparser::Parser;
|
||||||
use hash::FnvHashMap;
|
use hash::FxHashMap;
|
||||||
use parser::{Parse, ParserContext};
|
use parser::{Parse, ParserContext};
|
||||||
use selectors::parser::SelectorParseErrorKind;
|
use selectors::parser::SelectorParseErrorKind;
|
||||||
use servo_arc::Arc;
|
use servo_arc::Arc;
|
||||||
|
@ -548,7 +548,7 @@ impl TemplateAreas {
|
||||||
let mut width = 0;
|
let mut width = 0;
|
||||||
{
|
{
|
||||||
let mut row = 0u32;
|
let mut row = 0u32;
|
||||||
let mut area_indices = FnvHashMap::<&str, usize>::default();
|
let mut area_indices = FxHashMap::<&str, usize>::default();
|
||||||
for string in &strings {
|
for string in &strings {
|
||||||
let mut current_area_index: Option<usize> = None;
|
let mut current_area_index: Option<usize> = None;
|
||||||
row += 1;
|
row += 1;
|
||||||
|
|
|
@ -98,7 +98,6 @@ fn test_parse_stylesheet() {
|
||||||
}),
|
}),
|
||||||
Component::AttributeInNoNamespace {
|
Component::AttributeInNoNamespace {
|
||||||
local_name: local_name!("type"),
|
local_name: local_name!("type"),
|
||||||
local_name_lower: local_name!("type"),
|
|
||||||
operator: AttrSelectorOperator::Equal,
|
operator: AttrSelectorOperator::Equal,
|
||||||
value: "hidden".to_owned(),
|
value: "hidden".to_owned(),
|
||||||
case_sensitivity: ParsedCaseSensitivity::AsciiCaseInsensitive,
|
case_sensitivity: ParsedCaseSensitivity::AsciiCaseInsensitive,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue