mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
Auto merge of #24978 - emilio:gecko-sync, r=emilio
style: Sync changes from mozilla-central. See individual commits for details.
This commit is contained in:
commit
1dd6ad7063
76 changed files with 1328 additions and 1043 deletions
8
Cargo.lock
generated
8
Cargo.lock
generated
|
@ -5333,7 +5333,7 @@ name = "style"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"app_units",
|
"app_units",
|
||||||
"arrayvec 0.4.6",
|
"arrayvec 0.5.1",
|
||||||
"atomic_refcell",
|
"atomic_refcell",
|
||||||
"bindgen",
|
"bindgen",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
|
@ -5941,11 +5941,11 @@ checksum = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uluru"
|
name = "uluru"
|
||||||
version = "0.3.0"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d2606e9192f308ddc4f0b3c5d1bf3400e28a70fff956e9d9f46d23b094746d9f"
|
checksum = "6d7b39d0c32eba57d52d334e4bdd150df6e755264eefaa1ae2e7cd125f35e1ca"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec 0.4.6",
|
"arrayvec 0.5.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -22,7 +22,7 @@ bitflags = "1.0"
|
||||||
byteorder = "1"
|
byteorder = "1"
|
||||||
canvas_traits = {path = "../canvas_traits"}
|
canvas_traits = {path = "../canvas_traits"}
|
||||||
crossbeam-channel = "0.3"
|
crossbeam-channel = "0.3"
|
||||||
cssparser = "0.27.1"
|
cssparser = "0.27"
|
||||||
embedder_traits = {path = "../embedder_traits"}
|
embedder_traits = {path = "../embedder_traits"}
|
||||||
euclid = "0.20"
|
euclid = "0.20"
|
||||||
fnv = "1.0"
|
fnv = "1.0"
|
||||||
|
|
|
@ -14,7 +14,7 @@ path = "lib.rs"
|
||||||
webgl_backtrace = []
|
webgl_backtrace = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cssparser = "0.27.1"
|
cssparser = "0.27"
|
||||||
euclid = "0.20"
|
euclid = "0.20"
|
||||||
ipc-channel = "0.12"
|
ipc-channel = "0.12"
|
||||||
lazy_static = "1"
|
lazy_static = "1"
|
||||||
|
|
|
@ -514,6 +514,10 @@ impl<'le> TElement for ServoLayoutElement<'le> {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn exports_any_part(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
fn style_attribute(&self) -> Option<ArcBorrow<StyleLocked<PropertyDeclarationBlock>>> {
|
fn style_attribute(&self) -> Option<ArcBorrow<StyleLocked<PropertyDeclarationBlock>>> {
|
||||||
unsafe {
|
unsafe {
|
||||||
(*self.element.style_attribute())
|
(*self.element.style_attribute())
|
||||||
|
@ -999,6 +1003,14 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn exported_part(&self, _: &Atom) -> Option<Atom> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn imported_part(&self, _: &Atom) -> Option<Atom> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
|
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
|
||||||
unsafe { self.element.has_class_for_layout(name, case_sensitivity) }
|
unsafe { self.element.has_class_for_layout(name, case_sensitivity) }
|
||||||
|
@ -1533,6 +1545,16 @@ impl<'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn exported_part(&self, _: &Atom) -> Option<Atom> {
|
||||||
|
debug!("ServoThreadSafeLayoutElement::exported_part called");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn imported_part(&self, _: &Atom) -> Option<Atom> {
|
||||||
|
debug!("ServoThreadSafeLayoutElement::imported_part called");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn has_class(&self, _name: &Atom, _case_sensitivity: CaseSensitivity) -> bool {
|
fn has_class(&self, _name: &Atom, _case_sensitivity: CaseSensitivity) -> bool {
|
||||||
debug!("ServoThreadSafeLayoutElement::has_class called");
|
debug!("ServoThreadSafeLayoutElement::has_class called");
|
||||||
false
|
false
|
||||||
|
|
|
@ -521,6 +521,10 @@ impl<'le> TElement for ServoLayoutElement<'le> {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn exports_any_part(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
fn style_attribute(&self) -> Option<ArcBorrow<StyleLocked<PropertyDeclarationBlock>>> {
|
fn style_attribute(&self) -> Option<ArcBorrow<StyleLocked<PropertyDeclarationBlock>>> {
|
||||||
unsafe {
|
unsafe {
|
||||||
(*self.element.style_attribute())
|
(*self.element.style_attribute())
|
||||||
|
@ -1006,6 +1010,14 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn exported_part(&self, _: &Atom) -> Option<Atom> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn imported_part(&self, _: &Atom) -> Option<Atom> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
|
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
|
||||||
unsafe { self.element.has_class_for_layout(name, case_sensitivity) }
|
unsafe { self.element.has_class_for_layout(name, case_sensitivity) }
|
||||||
|
@ -1540,6 +1552,16 @@ impl<'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn exported_part(&self, _: &Atom) -> Option<Atom> {
|
||||||
|
debug!("ServoThreadSafeLayoutElement::exported_part called");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn imported_part(&self, _: &Atom) -> Option<Atom> {
|
||||||
|
debug!("ServoThreadSafeLayoutElement::imported_part called");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn has_class(&self, _name: &Atom, _case_sensitivity: CaseSensitivity) -> bool {
|
fn has_class(&self, _name: &Atom, _case_sensitivity: CaseSensitivity) -> bool {
|
||||||
debug!("ServoThreadSafeLayoutElement::has_class called");
|
debug!("ServoThreadSafeLayoutElement::has_class called");
|
||||||
false
|
false
|
||||||
|
|
|
@ -28,7 +28,7 @@ servo = [
|
||||||
app_units = "0.7"
|
app_units = "0.7"
|
||||||
content-security-policy = {version = "0.3.0", features = ["serde"], optional = true}
|
content-security-policy = {version = "0.3.0", features = ["serde"], optional = true}
|
||||||
crossbeam-channel = { version = "0.3", optional = true }
|
crossbeam-channel = { version = "0.3", optional = true }
|
||||||
cssparser = "0.27.1"
|
cssparser = "0.27"
|
||||||
euclid = "0.20"
|
euclid = "0.20"
|
||||||
hashglobe = { path = "../hashglobe" }
|
hashglobe = { path = "../hashglobe" }
|
||||||
hyper = { version = "0.12", optional = true }
|
hyper = { version = "0.12", optional = true }
|
||||||
|
|
|
@ -43,7 +43,7 @@ content-security-policy = {version = "0.3.0", features = ["serde"]}
|
||||||
cookie = "0.11"
|
cookie = "0.11"
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
crossbeam-channel = "0.3"
|
crossbeam-channel = "0.3"
|
||||||
cssparser = "0.27.1"
|
cssparser = "0.27"
|
||||||
deny_public_fields = {path = "../deny_public_fields"}
|
deny_public_fields = {path = "../deny_public_fields"}
|
||||||
devtools_traits = {path = "../devtools_traits"}
|
devtools_traits = {path = "../devtools_traits"}
|
||||||
dom_struct = {path = "../dom_struct"}
|
dom_struct = {path = "../dom_struct"}
|
||||||
|
|
|
@ -3073,6 +3073,14 @@ impl<'a> SelectorsElement for DomRoot<Element> {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn exported_part(&self, _: &Atom) -> Option<Atom> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn imported_part(&self, _: &Atom) -> Option<Atom> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
|
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
|
||||||
Element::has_class(&**self, name, case_sensitivity)
|
Element::has_class(&**self, name, case_sensitivity)
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ bench = []
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bitflags = "1.0"
|
bitflags = "1.0"
|
||||||
matches = "0.1"
|
matches = "0.1"
|
||||||
cssparser = "0.27.1"
|
cssparser = "0.27"
|
||||||
derive_more = "0.13"
|
derive_more = "0.13"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
fxhash = "0.2"
|
fxhash = "0.2"
|
||||||
|
|
|
@ -8,6 +8,7 @@ use crate::nth_index_cache::NthIndexCacheInner;
|
||||||
use crate::parser::{AncestorHashes, Combinator, Component, LocalName};
|
use crate::parser::{AncestorHashes, Combinator, Component, LocalName};
|
||||||
use crate::parser::{NonTSPseudoClass, Selector, SelectorImpl, SelectorIter, SelectorList};
|
use crate::parser::{NonTSPseudoClass, Selector, SelectorImpl, SelectorIter, SelectorList};
|
||||||
use crate::tree::Element;
|
use crate::tree::Element;
|
||||||
|
use smallvec::SmallVec;
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
|
@ -667,7 +668,41 @@ where
|
||||||
|
|
||||||
match *selector {
|
match *selector {
|
||||||
Component::Combinator(_) => unreachable!(),
|
Component::Combinator(_) => unreachable!(),
|
||||||
Component::Part(ref parts) => parts.iter().all(|part| element.is_part(part)),
|
Component::Part(ref parts) => {
|
||||||
|
let mut hosts = SmallVec::<[E; 4]>::new();
|
||||||
|
|
||||||
|
let mut host = match element.containing_shadow_host() {
|
||||||
|
Some(h) => h,
|
||||||
|
None => return false,
|
||||||
|
};
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let outer_host = host.containing_shadow_host();
|
||||||
|
if outer_host.as_ref().map(|h| h.opaque()) == context.shared.current_host {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let outer_host = match outer_host {
|
||||||
|
Some(h) => h,
|
||||||
|
None => return false,
|
||||||
|
};
|
||||||
|
// TODO(emilio): if worth it, we could early return if
|
||||||
|
// host doesn't have the exportparts attribute.
|
||||||
|
hosts.push(host);
|
||||||
|
host = outer_host;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Translate the part into the right scope.
|
||||||
|
parts.iter().all(|part| {
|
||||||
|
let mut part = part.clone();
|
||||||
|
for host in hosts.iter().rev() {
|
||||||
|
part = match host.imported_part(&part) {
|
||||||
|
Some(p) => p,
|
||||||
|
None => return false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
element.is_part(&part)
|
||||||
|
})
|
||||||
|
},
|
||||||
Component::Slotted(ref selector) => {
|
Component::Slotted(ref selector) => {
|
||||||
// <slots> are never flattened tree slottables.
|
// <slots> are never flattened tree slottables.
|
||||||
!element.is_html_slot_element() &&
|
!element.is_html_slot_element() &&
|
||||||
|
|
|
@ -117,6 +117,20 @@ pub trait Element: Sized + Clone + Debug {
|
||||||
case_sensitivity: CaseSensitivity,
|
case_sensitivity: CaseSensitivity,
|
||||||
) -> bool;
|
) -> bool;
|
||||||
|
|
||||||
|
/// Returns the mapping from the `exportparts` attribute in the regular
|
||||||
|
/// direction, that is, inner-tree -> outer-tree.
|
||||||
|
fn exported_part(
|
||||||
|
&self,
|
||||||
|
name: &<Self::Impl as SelectorImpl>::PartName,
|
||||||
|
) -> Option<<Self::Impl as SelectorImpl>::PartName>;
|
||||||
|
|
||||||
|
/// Returns the mapping from the `exportparts` attribute in the reverse
|
||||||
|
/// direction, that is, in an outer-tree -> inner-tree direction.
|
||||||
|
fn imported_part(
|
||||||
|
&self,
|
||||||
|
name: &<Self::Impl as SelectorImpl>::PartName,
|
||||||
|
) -> Option<<Self::Impl as SelectorImpl>::PartName>;
|
||||||
|
|
||||||
fn is_part(&self, name: &<Self::Impl as SelectorImpl>::PartName) -> bool;
|
fn is_part(&self, name: &<Self::Impl as SelectorImpl>::PartName) -> bool;
|
||||||
|
|
||||||
/// Returns whether this element matches `:empty`.
|
/// Returns whether this element matches `:empty`.
|
||||||
|
|
|
@ -485,6 +485,14 @@ impl<T: ?Sized> Arc<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether or not the `Arc` is a static reference.
|
||||||
|
#[inline]
|
||||||
|
pub fn is_static(&self) -> bool {
|
||||||
|
// Using a relaxed ordering to check for STATIC_REFCOUNT is safe, since
|
||||||
|
// `count` never changes between STATIC_REFCOUNT and other values.
|
||||||
|
self.inner().count.load(Relaxed) == STATIC_REFCOUNT
|
||||||
|
}
|
||||||
|
|
||||||
/// Whether or not the `Arc` is uniquely owned (is the refcount 1?) and not
|
/// Whether or not the `Arc` is uniquely owned (is the refcount 1?) and not
|
||||||
/// a static reference.
|
/// a static reference.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -501,10 +509,7 @@ impl<T: ?Sized> Drop for Arc<T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// NOTE(emilio): If you change anything here, make sure that the
|
// NOTE(emilio): If you change anything here, make sure that the
|
||||||
// implementation in layout/style/ServoStyleConstsInlines.h matches!
|
// implementation in layout/style/ServoStyleConstsInlines.h matches!
|
||||||
//
|
if self.is_static() {
|
||||||
// Using a relaxed ordering to check for STATIC_REFCOUNT is safe, since
|
|
||||||
// `count` never changes between STATIC_REFCOUNT and other values.
|
|
||||||
if self.inner().count.load(Relaxed) == STATIC_REFCOUNT {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,9 @@ doctest = false
|
||||||
[features]
|
[features]
|
||||||
gecko = ["style_traits/gecko", "fallible/known_system_malloc", "bindgen", "regex", "toml"]
|
gecko = ["style_traits/gecko", "fallible/known_system_malloc", "bindgen", "regex", "toml"]
|
||||||
servo = ["serde", "style_traits/servo", "servo_atoms", "servo_config", "html5ever",
|
servo = ["serde", "style_traits/servo", "servo_atoms", "servo_config", "html5ever",
|
||||||
"cssparser/serde", "encoding_rs", "malloc_size_of/servo", "arrayvec/use_union",
|
"cssparser/serde", "encoding_rs", "malloc_size_of/servo", "servo_url",
|
||||||
"servo_url", "string_cache", "crossbeam-channel", "to_shmem/servo", "servo_arc/servo"]
|
"string_cache", "crossbeam-channel", "to_shmem/servo",
|
||||||
|
"servo_arc/servo"]
|
||||||
servo-layout-2013 = []
|
servo-layout-2013 = []
|
||||||
servo-layout-2020 = []
|
servo-layout-2020 = []
|
||||||
gecko_debug = []
|
gecko_debug = []
|
||||||
|
@ -28,11 +29,11 @@ gecko_profiler = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
app_units = "0.7"
|
app_units = "0.7"
|
||||||
arrayvec = "0.4.6"
|
arrayvec = "0.5"
|
||||||
atomic_refcell = "0.1"
|
atomic_refcell = "0.1"
|
||||||
bitflags = "1.0"
|
bitflags = "1.0"
|
||||||
byteorder = "1.0"
|
byteorder = "1.0"
|
||||||
cssparser = "0.27.1"
|
cssparser = "0.27"
|
||||||
crossbeam-channel = { version = "0.3", optional = true }
|
crossbeam-channel = { version = "0.3", optional = true }
|
||||||
derive_more = "0.13"
|
derive_more = "0.13"
|
||||||
new_debug_unreachable = "1.0"
|
new_debug_unreachable = "1.0"
|
||||||
|
@ -74,7 +75,7 @@ thin-slice = "0.1.0"
|
||||||
to_shmem = {path = "../to_shmem"}
|
to_shmem = {path = "../to_shmem"}
|
||||||
to_shmem_derive = {path = "../to_shmem_derive"}
|
to_shmem_derive = {path = "../to_shmem_derive"}
|
||||||
time = "0.1"
|
time = "0.1"
|
||||||
uluru = "0.3"
|
uluru = "0.4"
|
||||||
unicode-bidi = "0.3"
|
unicode-bidi = "0.3"
|
||||||
unicode-segmentation = "1.0"
|
unicode-segmentation = "1.0"
|
||||||
void = "1.0.2"
|
void = "1.0.2"
|
||||||
|
|
|
@ -16,8 +16,8 @@ use crate::properties::animated_properties::AnimatedProperty;
|
||||||
use crate::properties::longhands::animation_direction::computed_value::single_value::T as AnimationDirection;
|
use crate::properties::longhands::animation_direction::computed_value::single_value::T as AnimationDirection;
|
||||||
use crate::properties::longhands::animation_play_state::computed_value::single_value::T as AnimationPlayState;
|
use crate::properties::longhands::animation_play_state::computed_value::single_value::T as AnimationPlayState;
|
||||||
use crate::properties::{self, CascadeMode, ComputedValues, LonghandId};
|
use crate::properties::{self, CascadeMode, ComputedValues, LonghandId};
|
||||||
use crate::rule_tree::CascadeLevel;
|
|
||||||
use crate::stylesheets::keyframes_rule::{KeyframesAnimation, KeyframesStep, KeyframesStepValue};
|
use crate::stylesheets::keyframes_rule::{KeyframesAnimation, KeyframesStep, KeyframesStepValue};
|
||||||
|
use crate::stylesheets::Origin;
|
||||||
use crate::timer::Timer;
|
use crate::timer::Timer;
|
||||||
use crate::values::computed::box_::TransitionProperty;
|
use crate::values::computed::box_::TransitionProperty;
|
||||||
use crate::values::computed::Time;
|
use crate::values::computed::Time;
|
||||||
|
@ -491,7 +491,7 @@ where
|
||||||
guard
|
guard
|
||||||
.normal_declaration_iter()
|
.normal_declaration_iter()
|
||||||
.filter(|declaration| declaration.is_animatable())
|
.filter(|declaration| declaration.is_animatable())
|
||||||
.map(|decl| (decl, CascadeLevel::Animations))
|
.map(|decl| (decl, Origin::Author))
|
||||||
};
|
};
|
||||||
|
|
||||||
// This currently ignores visited styles, which seems acceptable,
|
// This currently ignores visited styles, which seems acceptable,
|
||||||
|
|
|
@ -5,11 +5,10 @@
|
||||||
//! Applicable declarations management.
|
//! Applicable declarations management.
|
||||||
|
|
||||||
use crate::properties::PropertyDeclarationBlock;
|
use crate::properties::PropertyDeclarationBlock;
|
||||||
use crate::rule_tree::{CascadeLevel, ShadowCascadeOrder, StyleSource};
|
use crate::rule_tree::{CascadeLevel, StyleSource};
|
||||||
use crate::shared_lock::Locked;
|
use crate::shared_lock::Locked;
|
||||||
use servo_arc::Arc;
|
use servo_arc::Arc;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::fmt::{self, Debug};
|
|
||||||
|
|
||||||
/// List of applicable declarations. This is a transient structure that shuttles
|
/// List of applicable declarations. This is a transient structure that shuttles
|
||||||
/// declarations between selector matching and inserting into the rule tree, and
|
/// declarations between selector matching and inserting into the rule tree, and
|
||||||
|
@ -31,64 +30,29 @@ const SOURCE_ORDER_BITS: usize = 24;
|
||||||
const SOURCE_ORDER_MAX: u32 = (1 << SOURCE_ORDER_BITS) - 1;
|
const SOURCE_ORDER_MAX: u32 = (1 << SOURCE_ORDER_BITS) - 1;
|
||||||
const SOURCE_ORDER_MASK: u32 = SOURCE_ORDER_MAX << SOURCE_ORDER_SHIFT;
|
const SOURCE_ORDER_MASK: u32 = SOURCE_ORDER_MAX << SOURCE_ORDER_SHIFT;
|
||||||
|
|
||||||
/// We store up-to-15 shadow order levels.
|
/// We pack the cascade level in a single byte, see CascadeLevel::to_byte_lossy
|
||||||
///
|
/// for the different trade-offs there.
|
||||||
/// You'd need an element slotted across 16 components with ::slotted rules to
|
const CASCADE_LEVEL_SHIFT: usize = SOURCE_ORDER_BITS;
|
||||||
/// trigger this as of this writing, which looks... Unlikely.
|
|
||||||
const SHADOW_CASCADE_ORDER_SHIFT: usize = SOURCE_ORDER_BITS;
|
|
||||||
const SHADOW_CASCADE_ORDER_BITS: usize = 4;
|
|
||||||
const SHADOW_CASCADE_ORDER_MAX: u8 = (1 << SHADOW_CASCADE_ORDER_BITS) - 1;
|
|
||||||
const SHADOW_CASCADE_ORDER_MASK: u32 =
|
|
||||||
(SHADOW_CASCADE_ORDER_MAX as u32) << SHADOW_CASCADE_ORDER_SHIFT;
|
|
||||||
|
|
||||||
const CASCADE_LEVEL_SHIFT: usize = SOURCE_ORDER_BITS + SHADOW_CASCADE_ORDER_BITS;
|
|
||||||
const CASCADE_LEVEL_BITS: usize = 4;
|
|
||||||
const CASCADE_LEVEL_MAX: u8 = (1 << CASCADE_LEVEL_BITS) - 1;
|
|
||||||
const CASCADE_LEVEL_MASK: u32 = (CASCADE_LEVEL_MAX as u32) << CASCADE_LEVEL_SHIFT;
|
|
||||||
|
|
||||||
/// Stores the source order of a block, the cascade level it belongs to, and the
|
/// Stores the source order of a block, the cascade level it belongs to, and the
|
||||||
/// counter needed to handle Shadow DOM cascade order properly.
|
/// counter needed to handle Shadow DOM cascade order properly.
|
||||||
#[derive(Clone, Copy, Eq, MallocSizeOf, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq)]
|
||||||
struct ApplicableDeclarationBits(u32);
|
struct ApplicableDeclarationBits(u32);
|
||||||
|
|
||||||
impl ApplicableDeclarationBits {
|
impl ApplicableDeclarationBits {
|
||||||
fn new(
|
fn new(source_order: u32, cascade_level: CascadeLevel) -> Self {
|
||||||
source_order: u32,
|
Self(
|
||||||
cascade_level: CascadeLevel,
|
(source_order & SOURCE_ORDER_MASK) |
|
||||||
shadow_cascade_order: ShadowCascadeOrder,
|
((cascade_level.to_byte_lossy() as u32) << CASCADE_LEVEL_SHIFT),
|
||||||
) -> Self {
|
)
|
||||||
debug_assert!(
|
|
||||||
cascade_level as u8 <= CASCADE_LEVEL_MAX,
|
|
||||||
"Gotta find more bits!"
|
|
||||||
);
|
|
||||||
let mut bits = ::std::cmp::min(source_order, SOURCE_ORDER_MAX);
|
|
||||||
bits |= ((shadow_cascade_order & SHADOW_CASCADE_ORDER_MAX) as u32) <<
|
|
||||||
SHADOW_CASCADE_ORDER_SHIFT;
|
|
||||||
bits |= (cascade_level as u8 as u32) << CASCADE_LEVEL_SHIFT;
|
|
||||||
ApplicableDeclarationBits(bits)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn source_order(&self) -> u32 {
|
fn source_order(&self) -> u32 {
|
||||||
(self.0 & SOURCE_ORDER_MASK) >> SOURCE_ORDER_SHIFT
|
self.0 & SOURCE_ORDER_MASK
|
||||||
}
|
|
||||||
|
|
||||||
fn shadow_cascade_order(&self) -> ShadowCascadeOrder {
|
|
||||||
((self.0 & SHADOW_CASCADE_ORDER_MASK) >> SHADOW_CASCADE_ORDER_SHIFT) as ShadowCascadeOrder
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn level(&self) -> CascadeLevel {
|
fn level(&self) -> CascadeLevel {
|
||||||
let byte = ((self.0 & CASCADE_LEVEL_MASK) >> CASCADE_LEVEL_SHIFT) as u8;
|
CascadeLevel::from_byte((self.0 >> CASCADE_LEVEL_SHIFT) as u8)
|
||||||
unsafe { CascadeLevel::from_byte(byte) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for ApplicableDeclarationBits {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
f.debug_struct("ApplicableDeclarationBits")
|
|
||||||
.field("source_order", &self.source_order())
|
|
||||||
.field("shadow_cascade_order", &self.shadow_cascade_order())
|
|
||||||
.field("level", &self.level())
|
|
||||||
.finish()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,23 +83,17 @@ impl ApplicableDeclarationBlock {
|
||||||
) -> Self {
|
) -> Self {
|
||||||
ApplicableDeclarationBlock {
|
ApplicableDeclarationBlock {
|
||||||
source: StyleSource::from_declarations(declarations),
|
source: StyleSource::from_declarations(declarations),
|
||||||
bits: ApplicableDeclarationBits::new(0, level, 0),
|
bits: ApplicableDeclarationBits::new(0, level),
|
||||||
specificity: 0,
|
specificity: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs an applicable declaration block from the given components
|
/// Constructs an applicable declaration block from the given components
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(
|
pub fn new(source: StyleSource, order: u32, level: CascadeLevel, specificity: u32) -> Self {
|
||||||
source: StyleSource,
|
|
||||||
order: u32,
|
|
||||||
level: CascadeLevel,
|
|
||||||
specificity: u32,
|
|
||||||
shadow_cascade_order: ShadowCascadeOrder,
|
|
||||||
) -> Self {
|
|
||||||
ApplicableDeclarationBlock {
|
ApplicableDeclarationBlock {
|
||||||
source,
|
source,
|
||||||
bits: ApplicableDeclarationBits::new(order, level, shadow_cascade_order),
|
bits: ApplicableDeclarationBits::new(order, level),
|
||||||
specificity,
|
specificity,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,9 +113,8 @@ impl ApplicableDeclarationBlock {
|
||||||
/// Convenience method to consume self and return the right thing for the
|
/// Convenience method to consume self and return the right thing for the
|
||||||
/// rule tree to iterate over.
|
/// rule tree to iterate over.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn for_rule_tree(self) -> (StyleSource, CascadeLevel, ShadowCascadeOrder) {
|
pub fn for_rule_tree(self) -> (StyleSource, CascadeLevel) {
|
||||||
let level = self.level();
|
let level = self.level();
|
||||||
let cascade_order = self.bits.shadow_cascade_order();
|
(self.source, level)
|
||||||
(self.source, level, cascade_order)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -306,8 +306,7 @@ fn parse_declaration_value_block<'i, 't>(
|
||||||
) -> Result<(TokenSerializationType, TokenSerializationType), ParseError<'i>> {
|
) -> Result<(TokenSerializationType, TokenSerializationType), ParseError<'i>> {
|
||||||
let mut token_start = input.position();
|
let mut token_start = input.position();
|
||||||
let mut token = match input.next_including_whitespace_and_comments() {
|
let mut token = match input.next_including_whitespace_and_comments() {
|
||||||
// FIXME: remove clone() when borrows are non-lexical
|
Ok(token) => token,
|
||||||
Ok(token) => token.clone(),
|
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
return Ok((
|
return Ok((
|
||||||
TokenSerializationType::nothing(),
|
TokenSerializationType::nothing(),
|
||||||
|
@ -335,8 +334,9 @@ fn parse_declaration_value_block<'i, 't>(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
let last_token_type = match token {
|
let last_token_type = match *token {
|
||||||
Token::Comment(_) => {
|
Token::Comment(_) => {
|
||||||
|
let serialization_type = token.serialization_type();
|
||||||
let token_slice = input.slice_from(token_start);
|
let token_slice = input.slice_from(token_start);
|
||||||
if !token_slice.ends_with("*/") {
|
if !token_slice.ends_with("*/") {
|
||||||
missing_closing_characters.push_str(if token_slice.ends_with('*') {
|
missing_closing_characters.push_str(if token_slice.ends_with('*') {
|
||||||
|
@ -345,14 +345,14 @@ fn parse_declaration_value_block<'i, 't>(
|
||||||
"*/"
|
"*/"
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
token.serialization_type()
|
serialization_type
|
||||||
},
|
},
|
||||||
Token::BadUrl(u) => {
|
Token::BadUrl(ref u) => {
|
||||||
let e = StyleParseErrorKind::BadUrlInDeclarationValueBlock(u);
|
let e = StyleParseErrorKind::BadUrlInDeclarationValueBlock(u.clone());
|
||||||
return Err(input.new_custom_error(e));
|
return Err(input.new_custom_error(e));
|
||||||
},
|
},
|
||||||
Token::BadString(s) => {
|
Token::BadString(ref s) => {
|
||||||
let e = StyleParseErrorKind::BadStringInDeclarationValueBlock(s);
|
let e = StyleParseErrorKind::BadStringInDeclarationValueBlock(s.clone());
|
||||||
return Err(input.new_custom_error(e));
|
return Err(input.new_custom_error(e));
|
||||||
},
|
},
|
||||||
Token::CloseParenthesis => {
|
Token::CloseParenthesis => {
|
||||||
|
@ -401,13 +401,14 @@ fn parse_declaration_value_block<'i, 't>(
|
||||||
Token::CloseSquareBracket.serialization_type()
|
Token::CloseSquareBracket.serialization_type()
|
||||||
},
|
},
|
||||||
Token::QuotedString(_) => {
|
Token::QuotedString(_) => {
|
||||||
|
let serialization_type = token.serialization_type();
|
||||||
let token_slice = input.slice_from(token_start);
|
let token_slice = input.slice_from(token_start);
|
||||||
let quote = &token_slice[..1];
|
let quote = &token_slice[..1];
|
||||||
debug_assert!(matches!(quote, "\"" | "'"));
|
debug_assert!(matches!(quote, "\"" | "'"));
|
||||||
if !(token_slice.ends_with(quote) && token_slice.len() > 1) {
|
if !(token_slice.ends_with(quote) && token_slice.len() > 1) {
|
||||||
missing_closing_characters.push_str(quote)
|
missing_closing_characters.push_str(quote)
|
||||||
}
|
}
|
||||||
token.serialization_type()
|
serialization_type
|
||||||
},
|
},
|
||||||
Token::Ident(ref value) |
|
Token::Ident(ref value) |
|
||||||
Token::AtKeyword(ref value) |
|
Token::AtKeyword(ref value) |
|
||||||
|
@ -417,6 +418,8 @@ fn parse_declaration_value_block<'i, 't>(
|
||||||
Token::Dimension {
|
Token::Dimension {
|
||||||
unit: ref value, ..
|
unit: ref value, ..
|
||||||
} => {
|
} => {
|
||||||
|
let serialization_type = token.serialization_type();
|
||||||
|
let is_unquoted_url = matches!(token, Token::UnquotedUrl(_));
|
||||||
if value.ends_with("<EFBFBD>") && input.slice_from(token_start).ends_with("\\") {
|
if value.ends_with("<EFBFBD>") && input.slice_from(token_start).ends_with("\\") {
|
||||||
// Unescaped backslash at EOF in these contexts is interpreted as U+FFFD
|
// Unescaped backslash at EOF in these contexts is interpreted as U+FFFD
|
||||||
// Check the value in case the final backslash was itself escaped.
|
// Check the value in case the final backslash was itself escaped.
|
||||||
|
@ -424,18 +427,17 @@ fn parse_declaration_value_block<'i, 't>(
|
||||||
// (Unescaped U+FFFD would also work, but removing the backslash is annoying.)
|
// (Unescaped U+FFFD would also work, but removing the backslash is annoying.)
|
||||||
missing_closing_characters.push_str("<EFBFBD>")
|
missing_closing_characters.push_str("<EFBFBD>")
|
||||||
}
|
}
|
||||||
if matches!(token, Token::UnquotedUrl(_)) {
|
if is_unquoted_url {
|
||||||
check_closed!(")");
|
check_closed!(")");
|
||||||
}
|
}
|
||||||
token.serialization_type()
|
serialization_type
|
||||||
},
|
},
|
||||||
_ => token.serialization_type(),
|
_ => token.serialization_type(),
|
||||||
};
|
};
|
||||||
|
|
||||||
token_start = input.position();
|
token_start = input.position();
|
||||||
token = match input.next_including_whitespace_and_comments() {
|
token = match input.next_including_whitespace_and_comments() {
|
||||||
// FIXME: remove clone() when borrows are non-lexical
|
Ok(token) => token,
|
||||||
Ok(token) => token.clone(),
|
|
||||||
Err(..) => return Ok((first_token_type, last_token_type)),
|
Err(..) => return Ok((first_token_type, last_token_type)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -888,15 +890,12 @@ fn substitute_block<'i>(
|
||||||
let mut set_position_at_next_iteration = false;
|
let mut set_position_at_next_iteration = false;
|
||||||
loop {
|
loop {
|
||||||
let before_this_token = input.position();
|
let before_this_token = input.position();
|
||||||
// FIXME: remove clone() when borrows are non-lexical
|
let next = input.next_including_whitespace_and_comments();
|
||||||
let next = input
|
|
||||||
.next_including_whitespace_and_comments()
|
|
||||||
.map(|t| t.clone());
|
|
||||||
if set_position_at_next_iteration {
|
if set_position_at_next_iteration {
|
||||||
*position = (
|
*position = (
|
||||||
before_this_token,
|
before_this_token,
|
||||||
match next {
|
match next {
|
||||||
Ok(ref token) => token.serialization_type(),
|
Ok(token) => token.serialization_type(),
|
||||||
Err(_) => TokenSerializationType::nothing(),
|
Err(_) => TokenSerializationType::nothing(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -331,7 +331,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The ShadowRoot trait.
|
/// The ShadowRoot trait.
|
||||||
pub trait TShadowRoot: Sized + Copy + Clone + PartialEq {
|
pub trait TShadowRoot: Sized + Copy + Clone + Debug + PartialEq {
|
||||||
/// The concrete node type.
|
/// The concrete node type.
|
||||||
type ConcreteNode: TNode<ConcreteShadowRoot = Self>;
|
type ConcreteNode: TNode<ConcreteShadowRoot = Self>;
|
||||||
|
|
||||||
|
@ -523,6 +523,9 @@ pub trait TElement:
|
||||||
/// Returns whether this element has a `part` attribute.
|
/// Returns whether this element has a `part` attribute.
|
||||||
fn has_part_attr(&self) -> bool;
|
fn has_part_attr(&self) -> bool;
|
||||||
|
|
||||||
|
/// Returns whether this element exports any part from its shadow tree.
|
||||||
|
fn exports_any_part(&self) -> bool;
|
||||||
|
|
||||||
/// The ID for this element.
|
/// The ID for this element.
|
||||||
fn id(&self) -> Option<&WeakAtom>;
|
fn id(&self) -> Option<&WeakAtom>;
|
||||||
|
|
||||||
|
|
|
@ -172,7 +172,11 @@ where
|
||||||
};
|
};
|
||||||
|
|
||||||
for selector in self.selector_list.0.iter() {
|
for selector in self.selector_list.0.iter() {
|
||||||
target_vector.push(Invalidation::new(selector, 0))
|
target_vector.push(Invalidation::new(
|
||||||
|
selector,
|
||||||
|
self.matching_context.current_host.clone(),
|
||||||
|
0,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
false
|
false
|
||||||
|
|
|
@ -237,7 +237,13 @@ impl Device {
|
||||||
/// used for viewport unit resolution.
|
/// used for viewport unit resolution.
|
||||||
pub fn au_viewport_size_for_viewport_unit_resolution(&self) -> Size2D<Au> {
|
pub fn au_viewport_size_for_viewport_unit_resolution(&self) -> Size2D<Au> {
|
||||||
self.used_viewport_size.store(true, Ordering::Relaxed);
|
self.used_viewport_size.store(true, Ordering::Relaxed);
|
||||||
self.au_viewport_size()
|
|
||||||
|
let pc = match self.pres_context() {
|
||||||
|
Some(pc) => pc,
|
||||||
|
None => return Size2D::new(Au(0), Au(0)),
|
||||||
|
};
|
||||||
|
let size = &pc.mSizeForViewportUnits;
|
||||||
|
Size2D::new(Au(size.width), Au(size.height))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether we ever looked up the viewport size of the Device.
|
/// Returns whether we ever looked up the viewport size of the Device.
|
||||||
|
@ -268,13 +274,7 @@ impl Device {
|
||||||
if doc.mIsBeingUsedAsImage() {
|
if doc.mIsBeingUsedAsImage() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
let document_color_use = static_prefs::pref!("browser.display.document_color_use");
|
self.pref_sheet_prefs().mUseDocumentColors
|
||||||
let prefs = self.pref_sheet_prefs();
|
|
||||||
match document_color_use {
|
|
||||||
1 => true,
|
|
||||||
2 => prefs.mIsChrome,
|
|
||||||
_ => !prefs.mUseAccessibilityTheme,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the default background color.
|
/// Returns the default background color.
|
||||||
|
|
|
@ -140,6 +140,12 @@ impl PseudoElement {
|
||||||
*self == PseudoElement::FieldsetContent
|
*self == PseudoElement::FieldsetContent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether this pseudo-element is the ::-moz-color-swatch pseudo.
|
||||||
|
#[inline]
|
||||||
|
pub fn is_color_swatch(&self) -> bool {
|
||||||
|
*self == PseudoElement::MozColorSwatch
|
||||||
|
}
|
||||||
|
|
||||||
/// Whether this pseudo-element is lazily-cascaded.
|
/// Whether this pseudo-element is lazily-cascaded.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_lazy(&self) -> bool {
|
pub fn is_lazy(&self) -> bool {
|
||||||
|
|
|
@ -132,7 +132,7 @@ PRELUDE = '''
|
||||||
RULE_TEMPLATE = '''
|
RULE_TEMPLATE = '''
|
||||||
("{atom}") => {{{{
|
("{atom}") => {{{{
|
||||||
#[allow(unsafe_code)] #[allow(unused_unsafe)]
|
#[allow(unsafe_code)] #[allow(unused_unsafe)]
|
||||||
unsafe {{ $crate::string_cache::Atom::from_index({index}) }}
|
unsafe {{ $crate::string_cache::Atom::from_index_unchecked({index}) }}
|
||||||
}}}};
|
}}}};
|
||||||
'''[1:]
|
'''[1:]
|
||||||
|
|
||||||
|
|
|
@ -193,6 +193,16 @@ impl ElementSnapshot for GeckoElementSnapshot {
|
||||||
snapshot_helpers::has_class_or_part(name, CaseSensitivity::CaseSensitive, attr)
|
snapshot_helpers::has_class_or_part(name, CaseSensitivity::CaseSensitive, attr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn exported_part(&self, name: &Atom) -> Option<Atom> {
|
||||||
|
snapshot_helpers::exported_part(&*self.mAttrs, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn imported_part(&self, name: &Atom) -> Option<Atom> {
|
||||||
|
snapshot_helpers::imported_part(&*self.mAttrs, name)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
|
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
|
||||||
if !self.has_any(Flags::MaybeClass) {
|
if !self.has_any(Flags::MaybeClass) {
|
||||||
|
|
|
@ -82,6 +82,32 @@ pub fn get_id(attrs: &[structs::AttrArray_InternalAttr]) -> Option<&WeakAtom> {
|
||||||
Some(unsafe { get_id_from_attr(find_attr(attrs, &atom!("id"))?) })
|
Some(unsafe { get_id_from_attr(find_attr(attrs, &atom!("id"))?) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(super) fn exported_part(
|
||||||
|
attrs: &[structs::AttrArray_InternalAttr],
|
||||||
|
name: &Atom,
|
||||||
|
) -> Option<Atom> {
|
||||||
|
let attr = find_attr(attrs, &atom!("exportparts"))?;
|
||||||
|
let atom = unsafe { bindings::Gecko_Element_ExportedPart(attr, name.as_ptr()) };
|
||||||
|
if atom.is_null() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(unsafe { Atom::from_raw(atom) })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(super) fn imported_part(
|
||||||
|
attrs: &[structs::AttrArray_InternalAttr],
|
||||||
|
name: &Atom,
|
||||||
|
) -> Option<Atom> {
|
||||||
|
let attr = find_attr(attrs, &atom!("exportparts"))?;
|
||||||
|
let atom = unsafe { bindings::Gecko_Element_ImportedPart(attr, name.as_ptr()) };
|
||||||
|
if atom.is_null() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(unsafe { Atom::from_raw(atom) })
|
||||||
|
}
|
||||||
|
|
||||||
/// Given a class or part name, a case sensitivity, and an array of attributes,
|
/// Given a class or part name, a case sensitivity, and an array of attributes,
|
||||||
/// returns whether the attribute has that name.
|
/// returns whether the attribute has that name.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
|
|
@ -144,6 +144,13 @@ impl<'ld> TDocument for GeckoDocument<'ld> {
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct GeckoShadowRoot<'lr>(pub &'lr structs::ShadowRoot);
|
pub struct GeckoShadowRoot<'lr>(pub &'lr structs::ShadowRoot);
|
||||||
|
|
||||||
|
impl<'ln> fmt::Debug for GeckoShadowRoot<'ln> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
// TODO(emilio): Maybe print the host or something?
|
||||||
|
write!(f, "<shadow-root> ({:#x})", self.as_node().opaque().0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'lr> PartialEq for GeckoShadowRoot<'lr> {
|
impl<'lr> PartialEq for GeckoShadowRoot<'lr> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
@ -232,8 +239,8 @@ impl<'ln> fmt::Debug for GeckoNode<'ln> {
|
||||||
return write!(f, "<document> ({:#x})", self.opaque().0);
|
return write!(f, "<document> ({:#x})", self.opaque().0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.is_shadow_root() {
|
if let Some(sr) = self.as_shadow_root() {
|
||||||
return write!(f, "<shadow-root> ({:#x})", self.opaque().0);
|
return sr.fmt(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(f, "<non-text node> ({:#x})", self.opaque().0)
|
write!(f, "<non-text node> ({:#x})", self.opaque().0)
|
||||||
|
@ -300,7 +307,10 @@ impl<'ln> GeckoNode<'ln> {
|
||||||
fn flattened_tree_parent_is_parent(&self) -> bool {
|
fn flattened_tree_parent_is_parent(&self) -> bool {
|
||||||
use crate::gecko_bindings::structs::*;
|
use crate::gecko_bindings::structs::*;
|
||||||
let flags = self.flags();
|
let flags = self.flags();
|
||||||
if flags & (NODE_MAY_BE_IN_BINDING_MNGR as u32 | NODE_IS_IN_SHADOW_TREE as u32) != 0 {
|
|
||||||
|
// FIXME(emilio): The shadow tree condition seems it shouldn't be needed
|
||||||
|
// anymore, if we check for slots.
|
||||||
|
if self.is_in_shadow_tree() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -758,13 +768,6 @@ impl<'le> GeckoElement<'le> {
|
||||||
data.damage |= damage;
|
data.damage |= damage;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This logic is duplicated in Gecko's nsIContent::IsRootOfAnonymousSubtree.
|
|
||||||
#[inline]
|
|
||||||
fn is_root_of_anonymous_subtree(&self) -> bool {
|
|
||||||
use crate::gecko_bindings::structs::NODE_IS_ANONYMOUS_ROOT;
|
|
||||||
self.flags() & (NODE_IS_ANONYMOUS_ROOT as u32) != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This logic is duplicated in Gecko's nsIContent::IsRootOfNativeAnonymousSubtree.
|
/// This logic is duplicated in Gecko's nsIContent::IsRootOfNativeAnonymousSubtree.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_root_of_native_anonymous_subtree(&self) -> bool {
|
fn is_root_of_native_anonymous_subtree(&self) -> bool {
|
||||||
|
@ -772,11 +775,6 @@ impl<'le> GeckoElement<'le> {
|
||||||
return self.flags() & (NODE_IS_NATIVE_ANONYMOUS_ROOT as u32) != 0;
|
return self.flags() & (NODE_IS_NATIVE_ANONYMOUS_ROOT as u32) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn is_in_anonymous_subtree(&self) -> bool {
|
|
||||||
unsafe { bindings::Gecko_IsInAnonymousSubtree(self.0) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if this node is the shadow root of an use-element shadow tree.
|
/// Returns true if this node is the shadow root of an use-element shadow tree.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_root_of_use_element_shadow_tree(&self) -> bool {
|
fn is_root_of_use_element_shadow_tree(&self) -> bool {
|
||||||
|
@ -1025,7 +1023,7 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
// StyleChildrenIterator::IsNeeded does, except that it might return
|
// StyleChildrenIterator::IsNeeded does, except that it might return
|
||||||
// true if we used to (but no longer) have anonymous content from
|
// true if we used to (but no longer) have anonymous content from
|
||||||
// ::before/::after, or nsIAnonymousContentCreators.
|
// ::before/::after, or nsIAnonymousContentCreators.
|
||||||
if self.is_in_anonymous_subtree() ||
|
if self.is_in_native_anonymous_subtree() ||
|
||||||
self.is_html_slot_element() ||
|
self.is_html_slot_element() ||
|
||||||
self.shadow_root().is_some() ||
|
self.shadow_root().is_some() ||
|
||||||
self.may_have_anonymous_children()
|
self.may_have_anonymous_children()
|
||||||
|
@ -1250,6 +1248,11 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
.get_bool_flag(nsINode_BooleanFlag::ElementHasPart)
|
.get_bool_flag(nsINode_BooleanFlag::ElementHasPart)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn exports_any_part(&self) -> bool {
|
||||||
|
snapshot_helpers::find_attr(self.attrs(), &atom!("exportparts")).is_some()
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME(emilio): we should probably just return a reference to the Atom.
|
// FIXME(emilio): we should probably just return a reference to the Atom.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn id(&self) -> Option<&WeakAtom> {
|
fn id(&self) -> Option<&WeakAtom> {
|
||||||
|
@ -2192,7 +2195,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_link(&self) -> bool {
|
fn is_link(&self) -> bool {
|
||||||
self.state()
|
self.state()
|
||||||
.intersects(NonTSPseudoClass::AnyLink.state_flag())
|
.intersects(ElementState::IN_VISITED_OR_UNVISITED_STATE)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -2219,6 +2222,16 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
||||||
snapshot_helpers::has_class_or_part(name, CaseSensitivity::CaseSensitive, attr)
|
snapshot_helpers::has_class_or_part(name, CaseSensitivity::CaseSensitive, attr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn exported_part(&self, name: &Atom) -> Option<Atom> {
|
||||||
|
snapshot_helpers::exported_part(self.attrs(), name)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn imported_part(&self, name: &Atom) -> Option<Atom> {
|
||||||
|
snapshot_helpers::imported_part(self.attrs(), name)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
|
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
|
||||||
let attr = match self.get_class_attr() {
|
let attr = match self.get_class_attr() {
|
||||||
|
@ -2241,7 +2254,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn ignores_nth_child_selectors(&self) -> bool {
|
fn ignores_nth_child_selectors(&self) -> bool {
|
||||||
self.is_root_of_anonymous_subtree()
|
self.is_root_of_native_anonymous_subtree()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ use std::fmt::{self, Write};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::iter::Cloned;
|
use std::iter::Cloned;
|
||||||
use std::mem::{self, ManuallyDrop};
|
use std::mem::{self, ManuallyDrop};
|
||||||
|
use std::num::NonZeroUsize;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::{slice, str};
|
use std::{slice, str};
|
||||||
use style_traits::SpecifiedValueInfo;
|
use style_traits::SpecifiedValueInfo;
|
||||||
|
@ -48,13 +49,18 @@ macro_rules! local_name {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A handle to a Gecko atom.
|
/// A handle to a Gecko atom. This is a type that can represent either:
|
||||||
|
///
|
||||||
|
/// * A strong reference to a dynamic atom (an `nsAtom` pointer), in which case
|
||||||
|
/// the `usize` just holds the pointer value.
|
||||||
|
///
|
||||||
|
/// * A byte offset from `gGkAtoms` to the `nsStaticAtom` object (shifted to
|
||||||
|
/// the left one bit, and with the lower bit set to `1` to differentiate it
|
||||||
|
/// from the above), so `(offset << 1 | 1)`.
|
||||||
///
|
///
|
||||||
/// This is either a strong reference to a dynamic atom (an nsAtom pointer),
|
|
||||||
/// or an offset from gGkAtoms to the nsStaticAtom object.
|
|
||||||
#[derive(Eq, PartialEq)]
|
#[derive(Eq, PartialEq)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct Atom(usize);
|
pub struct Atom(NonZeroUsize);
|
||||||
|
|
||||||
/// An atom *without* a strong reference.
|
/// An atom *without* a strong reference.
|
||||||
///
|
///
|
||||||
|
@ -86,7 +92,7 @@ fn static_atoms() -> &'static [nsStaticAtom; STATIC_ATOM_COUNT] {
|
||||||
fn valid_static_atom_addr(addr: usize) -> bool {
|
fn valid_static_atom_addr(addr: usize) -> bool {
|
||||||
unsafe {
|
unsafe {
|
||||||
let atoms = static_atoms();
|
let atoms = static_atoms();
|
||||||
let start = atoms.get_unchecked(0) as *const _;
|
let start = atoms.as_ptr();
|
||||||
let end = atoms.get_unchecked(STATIC_ATOM_COUNT) as *const _;
|
let end = atoms.get_unchecked(STATIC_ATOM_COUNT) as *const _;
|
||||||
let in_range = addr >= start as usize && addr < end as usize;
|
let in_range = addr >= start as usize && addr < end as usize;
|
||||||
let aligned = addr % mem::align_of::<nsStaticAtom>() == 0;
|
let aligned = addr % mem::align_of::<nsStaticAtom>() == 0;
|
||||||
|
@ -101,9 +107,9 @@ impl Deref for Atom {
|
||||||
fn deref(&self) -> &WeakAtom {
|
fn deref(&self) -> &WeakAtom {
|
||||||
unsafe {
|
unsafe {
|
||||||
let addr = if self.is_static() {
|
let addr = if self.is_static() {
|
||||||
(&gGkAtoms as *const _ as usize) + (self.0 >> 1)
|
(&gGkAtoms as *const _ as usize) + (self.0.get() >> 1)
|
||||||
} else {
|
} else {
|
||||||
self.0
|
self.0.get()
|
||||||
};
|
};
|
||||||
debug_assert!(!self.is_static() || valid_static_atom_addr(addr));
|
debug_assert!(!self.is_static() || valid_static_atom_addr(addr));
|
||||||
WeakAtom::new(addr as *const nsAtom)
|
WeakAtom::new(addr as *const nsAtom)
|
||||||
|
@ -341,29 +347,29 @@ impl fmt::Display for WeakAtom {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn make_handle(ptr: *const nsAtom) -> usize {
|
unsafe fn make_handle(ptr: *const nsAtom) -> NonZeroUsize {
|
||||||
debug_assert!(!ptr.is_null());
|
debug_assert!(!ptr.is_null());
|
||||||
if !WeakAtom::new(ptr).is_static() {
|
if !WeakAtom::new(ptr).is_static() {
|
||||||
ptr as usize
|
NonZeroUsize::new_unchecked(ptr as usize)
|
||||||
} else {
|
} else {
|
||||||
make_static_handle(ptr as *mut nsStaticAtom)
|
make_static_handle(ptr as *mut nsStaticAtom)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn make_static_handle(ptr: *const nsStaticAtom) -> usize {
|
unsafe fn make_static_handle(ptr: *const nsStaticAtom) -> NonZeroUsize {
|
||||||
// FIXME(heycam): Use offset_from once it's stabilized.
|
// FIXME(heycam): Use offset_from once it's stabilized.
|
||||||
// https://github.com/rust-lang/rust/issues/41079
|
// https://github.com/rust-lang/rust/issues/41079
|
||||||
debug_assert!(valid_static_atom_addr(ptr as usize));
|
debug_assert!(valid_static_atom_addr(ptr as usize));
|
||||||
let base = &gGkAtoms as *const _;
|
let base = &gGkAtoms as *const _;
|
||||||
let offset = ptr as usize - base as usize;
|
let offset = ptr as usize - base as usize;
|
||||||
(offset << 1) | 1
|
NonZeroUsize::new_unchecked((offset << 1) | 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Atom {
|
impl Atom {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_static(&self) -> bool {
|
fn is_static(&self) -> bool {
|
||||||
self.0 & 1 == 1
|
self.0.get() & 1 == 1
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execute a callback with the atom represented by `ptr`.
|
/// Execute a callback with the atom represented by `ptr`.
|
||||||
|
@ -378,17 +384,17 @@ impl Atom {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a static atom from its index in the static atom table, without
|
/// Creates a static atom from its index in the static atom table, without
|
||||||
/// checking in release builds.
|
/// checking.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn from_index(index: u16) -> Self {
|
pub const unsafe fn from_index_unchecked(index: u16) -> Self {
|
||||||
let ptr = static_atoms().get_unchecked(index as usize) as *const _;
|
// FIXME(emilio): No support for debug_assert! in const fn for now. Note
|
||||||
let handle = make_static_handle(ptr);
|
// that violating this invariant will debug-assert in the `Deref` impl
|
||||||
let atom = Atom(handle);
|
// though.
|
||||||
debug_assert!(valid_static_atom_addr(ptr as usize));
|
//
|
||||||
debug_assert!(atom.is_static());
|
// debug_assert!((index as usize) < STATIC_ATOM_COUNT);
|
||||||
debug_assert!((*atom).is_static());
|
let offset =
|
||||||
debug_assert!(handle == make_handle(atom.as_ptr()));
|
(index as usize) * std::mem::size_of::<nsStaticAtom>() + kGkAtomsArrayOffset as usize;
|
||||||
atom
|
Atom(NonZeroUsize::new_unchecked((offset << 1) | 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an atom from an atom pointer.
|
/// Creates an atom from an atom pointer.
|
||||||
|
|
|
@ -79,7 +79,13 @@ where
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
self_invalidations.push(Invalidation::new(&dependency.selector, 0));
|
// We pass `None` as a scope, as document state selectors aren't
|
||||||
|
// affected by the current scope.
|
||||||
|
self_invalidations.push(Invalidation::new(
|
||||||
|
&dependency.selector,
|
||||||
|
/* scope = */ None,
|
||||||
|
0,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,12 @@ pub trait ElementSnapshot: Sized {
|
||||||
/// called if `has_attrs()` returns true.
|
/// called if `has_attrs()` returns true.
|
||||||
fn is_part(&self, name: &Atom) -> bool;
|
fn is_part(&self, name: &Atom) -> bool;
|
||||||
|
|
||||||
|
/// See Element::exported_part.
|
||||||
|
fn exported_part(&self, name: &Atom) -> Option<Atom>;
|
||||||
|
|
||||||
|
/// See Element::imported_part.
|
||||||
|
fn imported_part(&self, name: &Atom) -> Option<Atom>;
|
||||||
|
|
||||||
/// A callback that should be called for each class of the snapshot. Should
|
/// A callback that should be called for each class of the snapshot. Should
|
||||||
/// only be called if `has_attrs()` returns true.
|
/// only be called if `has_attrs()` returns true.
|
||||||
fn each_class<F>(&self, _: F)
|
fn each_class<F>(&self, _: F)
|
||||||
|
@ -270,7 +276,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_link(&self) -> bool {
|
fn is_link(&self) -> bool {
|
||||||
self.element.is_link()
|
match self.snapshot().and_then(|s| s.state()) {
|
||||||
|
Some(state) => state.intersects(ElementState::IN_VISITED_OR_UNVISITED_STATE),
|
||||||
|
None => self.element.is_link(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn opaque(&self) -> OpaqueElement {
|
fn opaque(&self) -> OpaqueElement {
|
||||||
|
@ -362,6 +371,20 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn exported_part(&self, name: &Atom) -> Option<Atom> {
|
||||||
|
match self.snapshot() {
|
||||||
|
Some(snapshot) if snapshot.has_attrs() => snapshot.exported_part(name),
|
||||||
|
_ => self.element.exported_part(name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn imported_part(&self, name: &Atom) -> Option<Atom> {
|
||||||
|
match self.snapshot() {
|
||||||
|
Some(snapshot) if snapshot.has_attrs() => snapshot.imported_part(name),
|
||||||
|
_ => self.element.imported_part(name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
|
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
|
||||||
match self.snapshot() {
|
match self.snapshot() {
|
||||||
Some(snapshot) if snapshot.has_attrs() => snapshot.has_class(name, case_sensitivity),
|
Some(snapshot) if snapshot.has_attrs() => snapshot.has_class(name, case_sensitivity),
|
||||||
|
|
|
@ -11,6 +11,7 @@ use crate::selector_parser::SelectorImpl;
|
||||||
use selectors::matching::matches_compound_selector_from;
|
use selectors::matching::matches_compound_selector_from;
|
||||||
use selectors::matching::{CompoundSelectorMatchingResult, MatchingContext};
|
use selectors::matching::{CompoundSelectorMatchingResult, MatchingContext};
|
||||||
use selectors::parser::{Combinator, Component, Selector};
|
use selectors::parser::{Combinator, Component, Selector};
|
||||||
|
use selectors::OpaqueElement;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
@ -127,6 +128,12 @@ enum InvalidationKind {
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Invalidation<'a> {
|
pub struct Invalidation<'a> {
|
||||||
selector: &'a Selector<SelectorImpl>,
|
selector: &'a Selector<SelectorImpl>,
|
||||||
|
/// The right shadow host from where the rule came from, if any.
|
||||||
|
///
|
||||||
|
/// This is needed to ensure that we match the selector with the right
|
||||||
|
/// state, as whether some selectors like :host and ::part() match depends
|
||||||
|
/// on it.
|
||||||
|
scope: Option<OpaqueElement>,
|
||||||
/// The offset of the selector pointing to a compound selector.
|
/// The offset of the selector pointing to a compound selector.
|
||||||
///
|
///
|
||||||
/// This order is a "parse order" offset, that is, zero is the leftmost part
|
/// This order is a "parse order" offset, that is, zero is the leftmost part
|
||||||
|
@ -143,9 +150,14 @@ pub struct Invalidation<'a> {
|
||||||
|
|
||||||
impl<'a> Invalidation<'a> {
|
impl<'a> Invalidation<'a> {
|
||||||
/// Create a new invalidation for a given selector and offset.
|
/// Create a new invalidation for a given selector and offset.
|
||||||
pub fn new(selector: &'a Selector<SelectorImpl>, offset: usize) -> Self {
|
pub fn new(
|
||||||
|
selector: &'a Selector<SelectorImpl>,
|
||||||
|
scope: Option<OpaqueElement>,
|
||||||
|
offset: usize,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
selector,
|
selector,
|
||||||
|
scope,
|
||||||
offset,
|
offset,
|
||||||
matched_by_any_previous: false,
|
matched_by_any_previous: false,
|
||||||
}
|
}
|
||||||
|
@ -471,21 +483,25 @@ where
|
||||||
any_descendant
|
any_descendant
|
||||||
}
|
}
|
||||||
|
|
||||||
fn invalidate_parts(&mut self, invalidations: &[Invalidation<'b>]) -> bool {
|
fn invalidate_parts_in_shadow_tree(
|
||||||
if invalidations.is_empty() {
|
&mut self,
|
||||||
return false;
|
shadow: <E::ConcreteNode as TNode>::ConcreteShadowRoot,
|
||||||
}
|
invalidations: &[Invalidation<'b>],
|
||||||
|
) -> bool {
|
||||||
let shadow = match self.element.shadow_root() {
|
debug_assert!(!invalidations.is_empty());
|
||||||
Some(s) => s,
|
|
||||||
None => return false,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut any = false;
|
let mut any = false;
|
||||||
let mut sibling_invalidations = InvalidationVector::new();
|
let mut sibling_invalidations = InvalidationVector::new();
|
||||||
for element in shadow.parts() {
|
|
||||||
|
for node in shadow.as_node().dom_descendants() {
|
||||||
|
let element = match node.as_element() {
|
||||||
|
Some(e) => e,
|
||||||
|
None => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
if element.has_part_attr() {
|
||||||
any |= self.invalidate_child(
|
any |= self.invalidate_child(
|
||||||
*element,
|
element,
|
||||||
invalidations,
|
invalidations,
|
||||||
&mut sibling_invalidations,
|
&mut sibling_invalidations,
|
||||||
DescendantInvalidationKind::Part,
|
DescendantInvalidationKind::Part,
|
||||||
|
@ -497,9 +513,30 @@ where
|
||||||
sibling_invalidations
|
sibling_invalidations
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(shadow) = element.shadow_root() {
|
||||||
|
if element.exports_any_part() {
|
||||||
|
any |= self.invalidate_parts_in_shadow_tree(shadow, invalidations)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
any
|
any
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn invalidate_parts(&mut self, invalidations: &[Invalidation<'b>]) -> bool {
|
||||||
|
if invalidations.is_empty() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let shadow = match self.element.shadow_root() {
|
||||||
|
Some(s) => s,
|
||||||
|
None => return false,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.invalidate_parts_in_shadow_tree(shadow, invalidations)
|
||||||
|
}
|
||||||
|
|
||||||
fn invalidate_slotted_elements(&mut self, invalidations: &[Invalidation<'b>]) -> bool {
|
fn invalidate_slotted_elements(&mut self, invalidations: &[Invalidation<'b>]) -> bool {
|
||||||
if invalidations.is_empty() {
|
if invalidations.is_empty() {
|
||||||
return false;
|
return false;
|
||||||
|
@ -721,12 +758,17 @@ where
|
||||||
self.element, invalidation, invalidation_kind
|
self.element, invalidation, invalidation_kind
|
||||||
);
|
);
|
||||||
|
|
||||||
let matching_result = matches_compound_selector_from(
|
let matching_result = {
|
||||||
|
let context = self.processor.matching_context();
|
||||||
|
context.current_host = invalidation.scope;
|
||||||
|
|
||||||
|
matches_compound_selector_from(
|
||||||
&invalidation.selector,
|
&invalidation.selector,
|
||||||
invalidation.offset,
|
invalidation.offset,
|
||||||
self.processor.matching_context(),
|
context,
|
||||||
&self.element,
|
&self.element,
|
||||||
);
|
)
|
||||||
|
};
|
||||||
|
|
||||||
let mut invalidated_self = false;
|
let mut invalidated_self = false;
|
||||||
let mut matched = false;
|
let mut matched = false;
|
||||||
|
@ -809,6 +851,7 @@ where
|
||||||
|
|
||||||
let next_invalidation = Invalidation {
|
let next_invalidation = Invalidation {
|
||||||
selector: invalidation.selector,
|
selector: invalidation.selector,
|
||||||
|
scope: invalidation.scope,
|
||||||
offset: next_combinator_offset + 1,
|
offset: next_combinator_offset + 1,
|
||||||
matched_by_any_previous: false,
|
matched_by_any_previous: false,
|
||||||
};
|
};
|
||||||
|
|
|
@ -158,7 +158,11 @@ where
|
||||||
// If we the visited state changed, we force a restyle here. Matching
|
// If we the visited state changed, we force a restyle here. Matching
|
||||||
// doesn't depend on the actual visited state at all, so we can't look
|
// doesn't depend on the actual visited state at all, so we can't look
|
||||||
// at matching results to decide what to do for this case.
|
// at matching results to decide what to do for this case.
|
||||||
if state_changes.intersects(ElementState::IN_VISITED_OR_UNVISITED_STATE) {
|
//
|
||||||
|
// TODO(emilio): This piece of code should be removed when
|
||||||
|
// layout.css.always-repaint-on-unvisited is true, since we cannot get
|
||||||
|
// into this situation in that case.
|
||||||
|
if state_changes.contains(ElementState::IN_VISITED_OR_UNVISITED_STATE) {
|
||||||
trace!(" > visitedness change, force subtree restyle");
|
trace!(" > visitedness change, force subtree restyle");
|
||||||
// We can't just return here because there may also be attribute
|
// We can't just return here because there may also be attribute
|
||||||
// changes as well that imply additional hints for siblings.
|
// changes as well that imply additional hints for siblings.
|
||||||
|
@ -453,6 +457,7 @@ where
|
||||||
|
|
||||||
let invalidation = Invalidation::new(
|
let invalidation = Invalidation::new(
|
||||||
&dependency.selector,
|
&dependency.selector,
|
||||||
|
self.matching_context.current_host.clone(),
|
||||||
dependency.selector.len() - dependency.selector_offset + 1,
|
dependency.selector.len() - dependency.selector_offset + 1,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -137,12 +137,12 @@ trait PrivateMatchMethods: TElement {
|
||||||
if replacements.contains(RestyleHint::RESTYLE_STYLE_ATTRIBUTE) {
|
if replacements.contains(RestyleHint::RESTYLE_STYLE_ATTRIBUTE) {
|
||||||
let style_attribute = self.style_attribute();
|
let style_attribute = self.style_attribute();
|
||||||
result |= replace_rule_node(
|
result |= replace_rule_node(
|
||||||
CascadeLevel::StyleAttributeNormal,
|
CascadeLevel::same_tree_author_normal(),
|
||||||
style_attribute,
|
style_attribute,
|
||||||
primary_rules,
|
primary_rules,
|
||||||
);
|
);
|
||||||
result |= replace_rule_node(
|
result |= replace_rule_node(
|
||||||
CascadeLevel::StyleAttributeImportant,
|
CascadeLevel::same_tree_author_important(),
|
||||||
style_attribute,
|
style_attribute,
|
||||||
primary_rules,
|
primary_rules,
|
||||||
);
|
);
|
||||||
|
|
|
@ -15,7 +15,7 @@ use crate::properties::{LonghandId, LonghandIdSet, CSSWideKeyword};
|
||||||
use crate::properties::{PropertyDeclaration, PropertyDeclarationId, DeclarationImportanceIterator};
|
use crate::properties::{PropertyDeclaration, PropertyDeclarationId, DeclarationImportanceIterator};
|
||||||
use crate::properties::CASCADE_PROPERTY;
|
use crate::properties::CASCADE_PROPERTY;
|
||||||
use crate::rule_cache::{RuleCache, RuleCacheConditions};
|
use crate::rule_cache::{RuleCache, RuleCacheConditions};
|
||||||
use crate::rule_tree::{CascadeLevel, StrongRuleNode};
|
use crate::rule_tree::StrongRuleNode;
|
||||||
use crate::selector_parser::PseudoElement;
|
use crate::selector_parser::PseudoElement;
|
||||||
use crate::stylesheets::{Origin, PerOrigin};
|
use crate::stylesheets::{Origin, PerOrigin};
|
||||||
use servo_arc::Arc;
|
use servo_arc::Arc;
|
||||||
|
@ -134,11 +134,15 @@ where
|
||||||
let restriction = pseudo.and_then(|p| p.property_restriction());
|
let restriction = pseudo.and_then(|p| p.property_restriction());
|
||||||
let iter_declarations = || {
|
let iter_declarations = || {
|
||||||
rule_node.self_and_ancestors().flat_map(|node| {
|
rule_node.self_and_ancestors().flat_map(|node| {
|
||||||
let cascade_level = node.cascade_level();
|
let origin = node.cascade_level().origin();
|
||||||
let node_importance = node.importance();
|
let node_importance = node.importance();
|
||||||
|
let guard = match origin {
|
||||||
|
Origin::Author => guards.author,
|
||||||
|
Origin::User | Origin::UserAgent => guards.ua_or_user,
|
||||||
|
};
|
||||||
let declarations = match node.style_source() {
|
let declarations = match node.style_source() {
|
||||||
Some(source) => source
|
Some(source) => source
|
||||||
.read(cascade_level.guard(guards))
|
.read(guard)
|
||||||
.declaration_importance_iter(),
|
.declaration_importance_iter(),
|
||||||
None => DeclarationImportanceIterator::new(&[], &empty),
|
None => DeclarationImportanceIterator::new(&[], &empty),
|
||||||
};
|
};
|
||||||
|
@ -153,14 +157,14 @@ where
|
||||||
// longhands are only allowed if they have our
|
// longhands are only allowed if they have our
|
||||||
// restriction flag set.
|
// restriction flag set.
|
||||||
if let PropertyDeclarationId::Longhand(id) = declaration.id() {
|
if let PropertyDeclarationId::Longhand(id) = declaration.id() {
|
||||||
if !id.flags().contains(restriction) && cascade_level.origin() != Origin::UserAgent {
|
if !id.flags().contains(restriction) && origin != Origin::UserAgent {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if declaration_importance == node_importance {
|
if declaration_importance == node_importance {
|
||||||
Some((declaration, cascade_level))
|
Some((declaration, origin))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -223,7 +227,7 @@ pub fn apply_declarations<'a, E, F, I>(
|
||||||
where
|
where
|
||||||
E: TElement,
|
E: TElement,
|
||||||
F: Fn() -> I,
|
F: Fn() -> I,
|
||||||
I: Iterator<Item = (&'a PropertyDeclaration, CascadeLevel)>,
|
I: Iterator<Item = (&'a PropertyDeclaration, Origin)>,
|
||||||
{
|
{
|
||||||
debug_assert!(layout_parent_style.is_none() || parent_style.is_some());
|
debug_assert!(layout_parent_style.is_none() || parent_style.is_some());
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
|
@ -242,17 +246,17 @@ where
|
||||||
|
|
||||||
let inherited_style = parent_style.unwrap_or(device.default_computed_values());
|
let inherited_style = parent_style.unwrap_or(device.default_computed_values());
|
||||||
|
|
||||||
let mut declarations = SmallVec::<[(&_, CascadeLevel); 32]>::new();
|
let mut declarations = SmallVec::<[(&_, Origin); 32]>::new();
|
||||||
let custom_properties = {
|
let custom_properties = {
|
||||||
let mut builder = CustomPropertiesBuilder::new(
|
let mut builder = CustomPropertiesBuilder::new(
|
||||||
inherited_style.custom_properties(),
|
inherited_style.custom_properties(),
|
||||||
device.environment(),
|
device.environment(),
|
||||||
);
|
);
|
||||||
|
|
||||||
for (declaration, cascade_level) in iter_declarations() {
|
for (declaration, origin) in iter_declarations() {
|
||||||
declarations.push((declaration, cascade_level));
|
declarations.push((declaration, origin));
|
||||||
if let PropertyDeclaration::Custom(ref declaration) = *declaration {
|
if let PropertyDeclaration::Custom(ref declaration) = *declaration {
|
||||||
builder.cascade(declaration, cascade_level.origin());
|
builder.cascade(declaration, origin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,7 +336,7 @@ where
|
||||||
fn should_ignore_declaration_when_ignoring_document_colors(
|
fn should_ignore_declaration_when_ignoring_document_colors(
|
||||||
device: &Device,
|
device: &Device,
|
||||||
longhand_id: LonghandId,
|
longhand_id: LonghandId,
|
||||||
cascade_level: CascadeLevel,
|
origin: Origin,
|
||||||
pseudo: Option<&PseudoElement>,
|
pseudo: Option<&PseudoElement>,
|
||||||
declaration: &mut Cow<PropertyDeclaration>,
|
declaration: &mut Cow<PropertyDeclaration>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
@ -340,22 +344,15 @@ fn should_ignore_declaration_when_ignoring_document_colors(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let is_ua_or_user_rule =
|
let is_ua_or_user_rule = matches!(origin, Origin::User | Origin::UserAgent);
|
||||||
matches!(cascade_level.origin(), Origin::User | Origin::UserAgent);
|
|
||||||
if is_ua_or_user_rule {
|
if is_ua_or_user_rule {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let is_style_attribute = matches!(
|
// Don't override background-color on ::-moz-color-swatch. It is set as an
|
||||||
cascade_level,
|
// author style (via the style attribute), but it's pretty important for it
|
||||||
CascadeLevel::StyleAttributeNormal | CascadeLevel::StyleAttributeImportant
|
// to show up for obvious reasons :)
|
||||||
);
|
if pseudo.map_or(false, |p| p.is_color_swatch()) && longhand_id == LonghandId::BackgroundColor {
|
||||||
|
|
||||||
// Don't override colors on pseudo-element's style attributes. The
|
|
||||||
// background-color on ::-moz-color-swatch is an example. Those are set
|
|
||||||
// as an author style (via the style attribute), but it's pretty
|
|
||||||
// important for it to show up for obvious reasons :)
|
|
||||||
if pseudo.is_some() && is_style_attribute {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,7 +449,7 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> {
|
||||||
declarations: I,
|
declarations: I,
|
||||||
) where
|
) where
|
||||||
Phase: CascadePhase,
|
Phase: CascadePhase,
|
||||||
I: Iterator<Item = (&'decls PropertyDeclaration, CascadeLevel)>,
|
I: Iterator<Item = (&'decls PropertyDeclaration, Origin)>,
|
||||||
{
|
{
|
||||||
let apply_reset = apply_reset == ApplyResetProperties::Yes;
|
let apply_reset = apply_reset == ApplyResetProperties::Yes;
|
||||||
|
|
||||||
|
@ -465,9 +462,8 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> {
|
||||||
|
|
||||||
let ignore_colors = !self.context.builder.device.use_document_colors();
|
let ignore_colors = !self.context.builder.device.use_document_colors();
|
||||||
|
|
||||||
for (declaration, cascade_level) in declarations {
|
for (declaration, origin) in declarations {
|
||||||
let declaration_id = declaration.id();
|
let declaration_id = declaration.id();
|
||||||
let origin = cascade_level.origin();
|
|
||||||
let longhand_id = match declaration_id {
|
let longhand_id = match declaration_id {
|
||||||
PropertyDeclarationId::Longhand(id) => id,
|
PropertyDeclarationId::Longhand(id) => id,
|
||||||
PropertyDeclarationId::Custom(..) => continue,
|
PropertyDeclarationId::Custom(..) => continue,
|
||||||
|
@ -515,7 +511,7 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> {
|
||||||
let should_ignore = should_ignore_declaration_when_ignoring_document_colors(
|
let should_ignore = should_ignore_declaration_when_ignoring_document_colors(
|
||||||
self.context.builder.device,
|
self.context.builder.device,
|
||||||
longhand_id,
|
longhand_id,
|
||||||
cascade_level,
|
origin,
|
||||||
self.context.builder.pseudo,
|
self.context.builder.pseudo,
|
||||||
&mut declaration,
|
&mut declaration,
|
||||||
);
|
);
|
||||||
|
|
|
@ -257,10 +257,12 @@ class Longhand(object):
|
||||||
def type():
|
def type():
|
||||||
return "longhand"
|
return "longhand"
|
||||||
|
|
||||||
# For a given logical property return all the physical
|
# For a given logical property return all the physical property names
|
||||||
# property names corresponding to it.
|
# corresponding to it.
|
||||||
def all_physical_mapped_properties(self):
|
def all_physical_mapped_properties(self, data):
|
||||||
assert self.logical
|
if not self.logical:
|
||||||
|
return []
|
||||||
|
|
||||||
candidates = [s for s in LOGICAL_SIDES + LOGICAL_SIZES + LOGICAL_CORNERS
|
candidates = [s for s in LOGICAL_SIDES + LOGICAL_SIZES + LOGICAL_CORNERS
|
||||||
if s in self.name] + [s for s in LOGICAL_AXES if self.name.endswith(s)]
|
if s in self.name] + [s for s in LOGICAL_AXES if self.name.endswith(s)]
|
||||||
assert(len(candidates) == 1)
|
assert(len(candidates) == 1)
|
||||||
|
@ -270,7 +272,7 @@ class Longhand(object):
|
||||||
else PHYSICAL_SIZES if logical_side in LOGICAL_SIZES \
|
else PHYSICAL_SIZES if logical_side in LOGICAL_SIZES \
|
||||||
else PHYSICAL_AXES if logical_side in LOGICAL_AXES \
|
else PHYSICAL_AXES if logical_side in LOGICAL_AXES \
|
||||||
else LOGICAL_CORNERS
|
else LOGICAL_CORNERS
|
||||||
return [to_phys(self.name, logical_side, physical_side)
|
return [data.longhands_by_name[to_phys(self.name, logical_side, physical_side)]
|
||||||
for physical_side in physical]
|
for physical_side in physical]
|
||||||
|
|
||||||
def experimental(self, engine):
|
def experimental(self, engine):
|
||||||
|
|
|
@ -46,7 +46,7 @@ use crate::rule_tree::StrongRuleNode;
|
||||||
use crate::selector_parser::PseudoElement;
|
use crate::selector_parser::PseudoElement;
|
||||||
use servo_arc::{Arc, RawOffsetArc, UniqueArc};
|
use servo_arc::{Arc, RawOffsetArc, UniqueArc};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::mem::{forget, zeroed, ManuallyDrop};
|
use std::mem::{forget, MaybeUninit};
|
||||||
use std::{cmp, ops, ptr};
|
use std::{cmp, ops, ptr};
|
||||||
use crate::values::{self, CustomIdent, Either, KeyframesName, None_};
|
use crate::values::{self, CustomIdent, Either, KeyframesName, None_};
|
||||||
use crate::values::computed::{Percentage, TransitionProperty};
|
use crate::values::computed::{Percentage, TransitionProperty};
|
||||||
|
@ -218,7 +218,7 @@ impl ComputedValuesInner {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut arc = UniqueArc::<ComputedValues>::new_uninit();
|
let mut arc = UniqueArc::<ComputedValues>::new_uninit();
|
||||||
bindings::Gecko_ComputedStyle_Init(
|
bindings::Gecko_ComputedStyle_Init(
|
||||||
&mut (*arc.as_mut_ptr()).0,
|
arc.as_mut_ptr() as *mut _,
|
||||||
&self,
|
&self,
|
||||||
pseudo_ty,
|
pseudo_ty,
|
||||||
);
|
);
|
||||||
|
@ -621,14 +621,17 @@ def set_gecko_property(ffi_name, expr):
|
||||||
impl ${style_struct.gecko_struct_name} {
|
impl ${style_struct.gecko_struct_name} {
|
||||||
#[allow(dead_code, unused_variables)]
|
#[allow(dead_code, unused_variables)]
|
||||||
pub fn default(document: &structs::Document) -> Arc<Self> {
|
pub fn default(document: &structs::Document) -> Arc<Self> {
|
||||||
let mut result = Arc::new(${style_struct.gecko_struct_name} { gecko: ManuallyDrop::new(unsafe { zeroed() }) });
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
let mut result = UniqueArc::<Self>::new_uninit();
|
||||||
|
// FIXME(bug 1595895): Zero the memory to keep valgrind happy, but
|
||||||
|
// these looks like Valgrind false-positives at a quick glance.
|
||||||
|
ptr::write_bytes::<Self>(result.as_mut_ptr(), 0, 1);
|
||||||
Gecko_Construct_Default_${style_struct.gecko_ffi_name}(
|
Gecko_Construct_Default_${style_struct.gecko_ffi_name}(
|
||||||
&mut *Arc::get_mut(&mut result).unwrap().gecko,
|
result.as_mut_ptr() as *mut _,
|
||||||
document,
|
document,
|
||||||
);
|
);
|
||||||
|
UniqueArc::assume_init(result).shareable()
|
||||||
}
|
}
|
||||||
result
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Drop for ${style_struct.gecko_struct_name} {
|
impl Drop for ${style_struct.gecko_struct_name} {
|
||||||
|
@ -641,9 +644,12 @@ impl Drop for ${style_struct.gecko_struct_name} {
|
||||||
impl Clone for ${style_struct.gecko_struct_name} {
|
impl Clone for ${style_struct.gecko_struct_name} {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut result = ${style_struct.gecko_struct_name} { gecko: ManuallyDrop::new(zeroed()) };
|
let mut result = MaybeUninit::<Self>::uninit();
|
||||||
Gecko_CopyConstruct_${style_struct.gecko_ffi_name}(&mut *result.gecko, &*self.gecko);
|
// FIXME(bug 1595895): Zero the memory to keep valgrind happy, but
|
||||||
result
|
// these looks like Valgrind false-positives at a quick glance.
|
||||||
|
ptr::write_bytes::<Self>(result.as_mut_ptr(), 0, 1);
|
||||||
|
Gecko_CopyConstruct_${style_struct.gecko_ffi_name}(result.as_mut_ptr() as *mut _, &*self.gecko);
|
||||||
|
result.assume_init()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@ ${helpers.single_keyword(
|
||||||
"mixed upright sideways",
|
"mixed upright sideways",
|
||||||
engines="gecko",
|
engines="gecko",
|
||||||
gecko_aliases="sideways-right=sideways",
|
gecko_aliases="sideways-right=sideways",
|
||||||
|
gecko_enum_prefix="StyleTextOrientation",
|
||||||
animation_value_type="none",
|
animation_value_type="none",
|
||||||
spec="https://drafts.csswg.org/css-writing-modes/#propdef-text-orientation",
|
spec="https://drafts.csswg.org/css-writing-modes/#propdef-text-orientation",
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -25,6 +25,7 @@ ${helpers.single_keyword(
|
||||||
engines="gecko",
|
engines="gecko",
|
||||||
animation_value_type="discrete",
|
animation_value_type="discrete",
|
||||||
spec="https://www.w3.org/TR/SVG/text.html#TextAnchorProperty",
|
spec="https://www.w3.org/TR/SVG/text.html#TextAnchorProperty",
|
||||||
|
gecko_enum_prefix="StyleTextAnchor",
|
||||||
)}
|
)}
|
||||||
|
|
||||||
// Section 11 - Painting: Filling, Stroking and Marker Symbols
|
// Section 11 - Painting: Filling, Stroking and Marker Symbols
|
||||||
|
@ -80,6 +81,7 @@ ${helpers.single_keyword(
|
||||||
engines="gecko",
|
engines="gecko",
|
||||||
animation_value_type="discrete",
|
animation_value_type="discrete",
|
||||||
spec="https://www.w3.org/TR/SVG11/painting.html#ShapeRenderingProperty",
|
spec="https://www.w3.org/TR/SVG11/painting.html#ShapeRenderingProperty",
|
||||||
|
gecko_enum_prefix = "StyleShapeRendering",
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${helpers.predefined_type(
|
${helpers.predefined_type(
|
||||||
|
@ -107,6 +109,7 @@ ${helpers.single_keyword(
|
||||||
engines="gecko",
|
engines="gecko",
|
||||||
animation_value_type="discrete",
|
animation_value_type="discrete",
|
||||||
spec="https://www.w3.org/TR/SVG11/painting.html#StrokeLinecapProperty",
|
spec="https://www.w3.org/TR/SVG11/painting.html#StrokeLinecapProperty",
|
||||||
|
gecko_enum_prefix = "StyleStrokeLinecap",
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${helpers.single_keyword(
|
${helpers.single_keyword(
|
||||||
|
|
|
@ -331,6 +331,7 @@ ${helpers.single_keyword(
|
||||||
engines="gecko",
|
engines="gecko",
|
||||||
animation_value_type="discrete",
|
animation_value_type="discrete",
|
||||||
spec="https://drafts.csswg.org/css-images/#propdef-object-fit",
|
spec="https://drafts.csswg.org/css-images/#propdef-object-fit",
|
||||||
|
gecko_enum_prefix = "StyleObjectFit",
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${helpers.predefined_type(
|
${helpers.predefined_type(
|
||||||
|
|
|
@ -15,6 +15,7 @@ ${helpers.single_keyword(
|
||||||
"ime-mode",
|
"ime-mode",
|
||||||
"auto normal active disabled inactive",
|
"auto normal active disabled inactive",
|
||||||
engines="gecko",
|
engines="gecko",
|
||||||
|
gecko_enum_prefix="StyleImeMode",
|
||||||
gecko_ffi_name="mIMEMode",
|
gecko_ffi_name="mIMEMode",
|
||||||
animation_value_type="discrete",
|
animation_value_type="discrete",
|
||||||
spec="https://drafts.csswg.org/css-ui/#input-method-editor",
|
spec="https://drafts.csswg.org/css-ui/#input-method-editor",
|
||||||
|
@ -58,7 +59,7 @@ ${helpers.single_keyword(
|
||||||
"none default menu tooltip sheet",
|
"none default menu tooltip sheet",
|
||||||
engines="gecko",
|
engines="gecko",
|
||||||
gecko_ffi_name="mWindowShadow",
|
gecko_ffi_name="mWindowShadow",
|
||||||
gecko_constant_prefix="NS_STYLE_WINDOW_SHADOW",
|
gecko_enum_prefix="StyleWindowShadow",
|
||||||
animation_value_type="discrete",
|
animation_value_type="discrete",
|
||||||
enabled_in="chrome",
|
enabled_in="chrome",
|
||||||
spec="None (Nonstandard internal property)",
|
spec="None (Nonstandard internal property)",
|
||||||
|
|
|
@ -64,16 +64,6 @@ ${helpers.single_keyword(
|
||||||
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-pack)",
|
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-pack)",
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${helpers.single_keyword(
|
|
||||||
"-moz-stack-sizing",
|
|
||||||
"stretch-to-fit ignore ignore-horizontal ignore-vertical",
|
|
||||||
engines="gecko",
|
|
||||||
gecko_ffi_name="mStackSizing",
|
|
||||||
gecko_enum_prefix="StyleStackSizing",
|
|
||||||
animation_value_type="discrete",
|
|
||||||
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-stack-sizing)",
|
|
||||||
)}
|
|
||||||
|
|
||||||
${helpers.predefined_type(
|
${helpers.predefined_type(
|
||||||
"-moz-box-ordinal-group",
|
"-moz-box-ordinal-group",
|
||||||
"Integer",
|
"Integer",
|
||||||
|
|
|
@ -1651,13 +1651,25 @@ impl UnparsedValue {
|
||||||
shorthands::${shorthand.ident}::parse_value(&context, input)
|
shorthands::${shorthand.ident}::parse_value(&context, input)
|
||||||
.map(|longhands| {
|
.map(|longhands| {
|
||||||
match longhand_id {
|
match longhand_id {
|
||||||
|
<% seen = set() %>
|
||||||
% for property in shorthand.sub_properties:
|
% for property in shorthand.sub_properties:
|
||||||
LonghandId::${property.camel_case} => {
|
// When animating logical properties, we end up
|
||||||
PropertyDeclaration::${property.camel_case}(
|
// physicalizing the value during the animation, but
|
||||||
|
// the value still comes from the logical shorthand.
|
||||||
|
//
|
||||||
|
// So we need to handle the physical properties too.
|
||||||
|
% for prop in [property] + property.all_physical_mapped_properties(data):
|
||||||
|
% if prop.camel_case not in seen:
|
||||||
|
LonghandId::${prop.camel_case} => {
|
||||||
|
PropertyDeclaration::${prop.camel_case}(
|
||||||
longhands.${property.ident}
|
longhands.${property.ident}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
<% seen.add(prop.camel_case) %>
|
||||||
|
% endif
|
||||||
% endfor
|
% endfor
|
||||||
|
% endfor
|
||||||
|
<% del seen %>
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -1801,8 +1813,8 @@ pub enum CountedUnknownProperty {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CountedUnknownProperty {
|
impl CountedUnknownProperty {
|
||||||
/// Parse the counted unknown property.
|
/// Parse the counted unknown property, for testing purposes only.
|
||||||
pub fn parse_for_test(property_name: &str) -> Option<Self> {
|
pub fn parse_for_testing(property_name: &str) -> Option<Self> {
|
||||||
ascii_case_insensitive_phf_map! {
|
ascii_case_insensitive_phf_map! {
|
||||||
unknown_id -> CountedUnknownProperty = {
|
unknown_id -> CountedUnknownProperty = {
|
||||||
% for property in data.counted_unknown_properties:
|
% for property in data.counted_unknown_properties:
|
||||||
|
@ -1814,6 +1826,7 @@ impl CountedUnknownProperty {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the underlying index, used for use counter.
|
/// Returns the underlying index, used for use counter.
|
||||||
|
#[inline]
|
||||||
pub fn bit(self) -> usize {
|
pub fn bit(self) -> usize {
|
||||||
self as usize
|
self as usize
|
||||||
}
|
}
|
||||||
|
@ -1830,9 +1843,16 @@ impl PropertyId {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a given property from the string `s`.
|
/// Returns a given property from the given name, _regardless of whether it
|
||||||
|
/// is enabled or not_, or Err(()) for unknown properties.
|
||||||
///
|
///
|
||||||
/// Returns Err(()) for unknown properties.
|
/// Do not use for non-testing purposes.
|
||||||
|
pub fn parse_unchecked_for_testing(name: &str) -> Result<Self, ()> {
|
||||||
|
Self::parse_unchecked(name, None)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a given property from the given name, _regardless of whether it
|
||||||
|
/// is enabled or not_, or Err(()) for unknown properties.
|
||||||
fn parse_unchecked(
|
fn parse_unchecked(
|
||||||
property_name: &str,
|
property_name: &str,
|
||||||
use_counters: Option< &UseCounters>,
|
use_counters: Option< &UseCounters>,
|
||||||
|
@ -2176,14 +2196,12 @@ impl PropertyDeclaration {
|
||||||
let mut ret = self.clone();
|
let mut ret = self.clone();
|
||||||
|
|
||||||
% for prop in data.longhands:
|
% for prop in data.longhands:
|
||||||
% if prop.logical:
|
% for physical_property in prop.all_physical_mapped_properties(data):
|
||||||
% for physical_property in prop.all_physical_mapped_properties():
|
% if physical_property.specified_type() != prop.specified_type():
|
||||||
% if data.longhands_by_name[physical_property].specified_type() != prop.specified_type():
|
|
||||||
<% raise "Logical property %s should share specified value with physical property %s" % \
|
<% raise "Logical property %s should share specified value with physical property %s" % \
|
||||||
(prop.name, physical_property) %>
|
(prop.name, physical_property.name) %>
|
||||||
% endif
|
% endif
|
||||||
% endfor
|
% endfor
|
||||||
% endif
|
|
||||||
% endfor
|
% endfor
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
|
@ -464,11 +464,13 @@ ${helpers.two_properties_shorthand(
|
||||||
};
|
};
|
||||||
|
|
||||||
// Make sure that the initial value matches the values for the
|
// Make sure that the initial value matches the values for the
|
||||||
// longhands, just for general sanity.
|
// longhands, just for general sanity. `zoom: 1` and `zoom: 0` are
|
||||||
|
// ignored, see [1][2]. They are just hack for the "has layout" mode on
|
||||||
|
// IE.
|
||||||
//
|
//
|
||||||
// FIXME: Should we just do this for the "normal" case? Seems weird
|
// [1]: https://bugs.webkit.org/show_bug.cgi?id=18467
|
||||||
// either way, so maybe not?
|
// [2]: https://bugzilla.mozilla.org/show_bug.cgi?id=1593009
|
||||||
Ok(if zoom.get() == 1.0 {
|
Ok(if zoom.get() == 1.0 || zoom.get() == 0.0 {
|
||||||
expanded! {
|
expanded! {
|
||||||
transform: Transform::none(),
|
transform: Transform::none(),
|
||||||
transform_origin: TransformOrigin::initial_value(),
|
transform_origin: TransformOrigin::initial_value(),
|
||||||
|
|
|
@ -181,8 +181,18 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ToCss for LonghandsToSerialize<'a> {
|
impl<'a> ToCss for LonghandsToSerialize<'a> {
|
||||||
|
// Return the shortest possible serialization of the `grid-${kind}-[start/end]` values.
|
||||||
|
// This function exploits the opportunities to omit the end value per this spec text:
|
||||||
|
//
|
||||||
|
// https://drafts.csswg.org/css-grid/#propdef-grid-column
|
||||||
|
// "When the second value is omitted, if the first value is a <custom-ident>,
|
||||||
|
// the grid-row-end/grid-column-end longhand is also set to that <custom-ident>;
|
||||||
|
// otherwise, it is set to auto."
|
||||||
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write {
|
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write {
|
||||||
self.grid_${kind}_start.to_css(dest)?;
|
self.grid_${kind}_start.to_css(dest)?;
|
||||||
|
if self.grid_${kind}_start.can_omit(self.grid_${kind}_end) {
|
||||||
|
return Ok(()); // the end value is redundant
|
||||||
|
}
|
||||||
dest.write_str(" / ")?;
|
dest.write_str(" / ")?;
|
||||||
self.grid_${kind}_end.to_css(dest)
|
self.grid_${kind}_end.to_css(dest)
|
||||||
}
|
}
|
||||||
|
@ -247,14 +257,39 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ToCss for LonghandsToSerialize<'a> {
|
impl<'a> ToCss for LonghandsToSerialize<'a> {
|
||||||
|
// Return the shortest possible serialization of the `grid-[column/row]-[start/end]` values.
|
||||||
|
// This function exploits the opportunities to omit trailing values per this spec text:
|
||||||
|
//
|
||||||
|
// https://drafts.csswg.org/css-grid/#propdef-grid-area
|
||||||
|
// "If four <grid-line> values are specified, grid-row-start is set to the first value,
|
||||||
|
// grid-column-start is set to the second value, grid-row-end is set to the third value,
|
||||||
|
// and grid-column-end is set to the fourth value.
|
||||||
|
//
|
||||||
|
// When grid-column-end is omitted, if grid-column-start is a <custom-ident>,
|
||||||
|
// grid-column-end is set to that <custom-ident>; otherwise, it is set to auto.
|
||||||
|
//
|
||||||
|
// When grid-row-end is omitted, if grid-row-start is a <custom-ident>, grid-row-end is
|
||||||
|
// set to that <custom-ident>; otherwise, it is set to auto.
|
||||||
|
//
|
||||||
|
// When grid-column-start is omitted, if grid-row-start is a <custom-ident>, all four
|
||||||
|
// longhands are set to that value. Otherwise, it is set to auto."
|
||||||
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write {
|
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write {
|
||||||
self.grid_row_start.to_css(dest)?;
|
self.grid_row_start.to_css(dest)?;
|
||||||
|
let mut trailing_values = 3;
|
||||||
|
if self.grid_column_start.can_omit(self.grid_column_end) {
|
||||||
|
trailing_values -= 1;
|
||||||
|
if self.grid_row_start.can_omit(self.grid_row_end) {
|
||||||
|
trailing_values -= 1;
|
||||||
|
if self.grid_row_start.can_omit(self.grid_column_start) {
|
||||||
|
trailing_values -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
let values = [&self.grid_column_start, &self.grid_row_end, &self.grid_column_end];
|
let values = [&self.grid_column_start, &self.grid_row_end, &self.grid_column_end];
|
||||||
for value in &values {
|
for value in values.iter().take(trailing_values) {
|
||||||
dest.write_str(" / ")?;
|
dest.write_str(" / ")?;
|
||||||
value.to_css(dest)?;
|
value.to_css(dest)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -301,27 +336,37 @@
|
||||||
% endfor
|
% endfor
|
||||||
|
|
||||||
let first_line_names = input.try(parse_line_names).unwrap_or_default();
|
let first_line_names = input.try(parse_line_names).unwrap_or_default();
|
||||||
if let Ok(mut string) = input.try(|i| i.expect_string().map(|s| s.as_ref().to_owned().into())) {
|
if let Ok(string) = input.try(|i| i.expect_string().map(|s| s.as_ref().to_owned().into())) {
|
||||||
let mut strings = vec![];
|
let mut strings = vec![];
|
||||||
let mut values = vec![];
|
let mut values = vec![];
|
||||||
let mut line_names = vec![];
|
let mut line_names = vec![];
|
||||||
let mut names = first_line_names;
|
line_names.push(first_line_names);
|
||||||
loop {
|
|
||||||
line_names.push(names);
|
|
||||||
strings.push(string);
|
strings.push(string);
|
||||||
|
loop {
|
||||||
let size = input.try(|i| TrackSize::parse(context, i)).unwrap_or_default();
|
let size = input.try(|i| TrackSize::parse(context, i)).unwrap_or_default();
|
||||||
values.push(TrackListValue::TrackSize(size));
|
values.push(TrackListValue::TrackSize(size));
|
||||||
names = input.try(parse_line_names).unwrap_or_default();
|
let mut names = input.try(parse_line_names).unwrap_or_default();
|
||||||
if let Ok(v) = input.try(parse_line_names) {
|
let more_names = input.try(parse_line_names);
|
||||||
|
|
||||||
|
match input.try(|i| i.expect_string().map(|s| s.as_ref().to_owned().into())) {
|
||||||
|
Ok(string) => {
|
||||||
|
strings.push(string);
|
||||||
|
if let Ok(v) = more_names {
|
||||||
|
// We got `[names] [more_names] "string"` - merge the two name lists.
|
||||||
let mut names_vec = names.into_vec();
|
let mut names_vec = names.into_vec();
|
||||||
names_vec.extend(v.into_iter());
|
names_vec.extend(v.into_iter());
|
||||||
names = names_vec.into();
|
names = names_vec.into();
|
||||||
}
|
}
|
||||||
|
line_names.push(names);
|
||||||
string = match input.try(|i| i.expect_string().map(|s| s.as_ref().to_owned().into())) {
|
},
|
||||||
Ok(s) => s,
|
Err(e) => {
|
||||||
_ => { // only the named area determines whether we should bail out
|
if more_names.is_ok() {
|
||||||
line_names.push(names.into());
|
// We've parsed `"string" [names] [more_names]` but then failed to parse another `"string"`.
|
||||||
|
// The grammar doesn't allow two trailing `<line-names>` so this is an invalid value.
|
||||||
|
return Err(e.into());
|
||||||
|
}
|
||||||
|
// only the named area determines whether we should bail out
|
||||||
|
line_names.push(names);
|
||||||
break
|
break
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -350,7 +395,7 @@
|
||||||
|
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
GenericGridTemplateComponent::None
|
GridTemplateComponent::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
|
@ -399,6 +444,9 @@
|
||||||
W: Write {
|
W: Write {
|
||||||
match *template_areas {
|
match *template_areas {
|
||||||
GridTemplateAreas::None => {
|
GridTemplateAreas::None => {
|
||||||
|
if template_rows.is_initial() && template_columns.is_initial() {
|
||||||
|
return GridTemplateComponent::default().to_css(dest);
|
||||||
|
}
|
||||||
template_rows.to_css(dest)?;
|
template_rows.to_css(dest)?;
|
||||||
dest.write_str(" / ")?;
|
dest.write_str(" / ")?;
|
||||||
template_columns.to_css(dest)
|
template_columns.to_css(dest)
|
||||||
|
@ -455,9 +503,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
string.to_css(dest)?;
|
string.to_css(dest)?;
|
||||||
|
|
||||||
|
// If the track size is the initial value then it's redundant here.
|
||||||
|
if !value.is_initial() {
|
||||||
dest.write_str(" ")?;
|
dest.write_str(" ")?;
|
||||||
value.to_css(dest)?;
|
value.to_css(dest)?;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(names) = names_iter.next() {
|
if let Some(names) = names_iter.next() {
|
||||||
concat_serialize_idents(" [", "]", names, " ", dest)?;
|
concat_serialize_idents(" [", "]", names, " ", dest)?;
|
||||||
|
@ -503,8 +555,8 @@
|
||||||
context: &ParserContext,
|
context: &ParserContext,
|
||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
) -> Result<Longhands, ParseError<'i>> {
|
) -> Result<Longhands, ParseError<'i>> {
|
||||||
let mut temp_rows = GridTemplateComponent::None;
|
let mut temp_rows = GridTemplateComponent::default();
|
||||||
let mut temp_cols = GridTemplateComponent::None;
|
let mut temp_cols = GridTemplateComponent::default();
|
||||||
let mut temp_areas = GridTemplateAreas::None;
|
let mut temp_areas = GridTemplateAreas::None;
|
||||||
let mut auto_rows = ImplicitGridTracks::default();
|
let mut auto_rows = ImplicitGridTracks::default();
|
||||||
let mut auto_cols = ImplicitGridTracks::default();
|
let mut auto_cols = ImplicitGridTracks::default();
|
||||||
|
@ -577,8 +629,8 @@
|
||||||
impl<'a> ToCss for LonghandsToSerialize<'a> {
|
impl<'a> ToCss for LonghandsToSerialize<'a> {
|
||||||
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write {
|
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write {
|
||||||
if *self.grid_template_areas != GridTemplateAreas::None ||
|
if *self.grid_template_areas != GridTemplateAreas::None ||
|
||||||
(*self.grid_template_rows != GridTemplateComponent::None &&
|
(!self.grid_template_rows.is_initial() &&
|
||||||
*self.grid_template_columns != GridTemplateComponent::None) ||
|
!self.grid_template_columns.is_initial()) ||
|
||||||
self.is_grid_template() {
|
self.is_grid_template() {
|
||||||
return super::grid_template::serialize_grid_template(self.grid_template_rows,
|
return super::grid_template::serialize_grid_template(self.grid_template_rows,
|
||||||
self.grid_template_columns,
|
self.grid_template_columns,
|
||||||
|
@ -588,7 +640,7 @@
|
||||||
if self.grid_auto_flow.autoflow == AutoFlow::Column {
|
if self.grid_auto_flow.autoflow == AutoFlow::Column {
|
||||||
// It should fail to serialize if other branch of the if condition's values are set.
|
// It should fail to serialize if other branch of the if condition's values are set.
|
||||||
if !self.grid_auto_rows.is_initial() ||
|
if !self.grid_auto_rows.is_initial() ||
|
||||||
*self.grid_template_columns != GridTemplateComponent::None {
|
!self.grid_template_columns.is_initial() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -612,7 +664,7 @@
|
||||||
} else {
|
} else {
|
||||||
// It should fail to serialize if other branch of the if condition's values are set.
|
// It should fail to serialize if other branch of the if condition's values are set.
|
||||||
if !self.grid_auto_columns.is_initial() ||
|
if !self.grid_auto_columns.is_initial() ||
|
||||||
*self.grid_template_rows != GridTemplateComponent::None {
|
!self.grid_template_rows.is_initial() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,9 +26,7 @@ pub struct RuleCacheConditions {
|
||||||
impl RuleCacheConditions {
|
impl RuleCacheConditions {
|
||||||
/// Sets the style as depending in the font-size value.
|
/// Sets the style as depending in the font-size value.
|
||||||
pub fn set_font_size_dependency(&mut self, font_size: NonNegativeLength) {
|
pub fn set_font_size_dependency(&mut self, font_size: NonNegativeLength) {
|
||||||
if let Some(f) = &self.font_size {
|
debug_assert!(self.font_size.map_or(true, |f| f == font_size));
|
||||||
debug_assert_eq!(*f, font_size);
|
|
||||||
}
|
|
||||||
self.font_size = Some(font_size);
|
self.font_size = Some(font_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ use crate::selector_parser::PseudoElement;
|
||||||
use crate::shared_lock::Locked;
|
use crate::shared_lock::Locked;
|
||||||
use crate::stylesheets::Origin;
|
use crate::stylesheets::Origin;
|
||||||
use crate::stylist::{AuthorStylesEnabled, Rule, RuleInclusion, Stylist};
|
use crate::stylist::{AuthorStylesEnabled, Rule, RuleInclusion, Stylist};
|
||||||
|
use crate::Atom;
|
||||||
use selectors::matching::{ElementSelectorFlags, MatchingContext, MatchingMode};
|
use selectors::matching::{ElementSelectorFlags, MatchingContext, MatchingMode};
|
||||||
use servo_arc::ArcBorrow;
|
use servo_arc::ArcBorrow;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
@ -79,7 +80,6 @@ where
|
||||||
rules: &'a mut ApplicableDeclarationList,
|
rules: &'a mut ApplicableDeclarationList,
|
||||||
context: &'a mut MatchingContext<'b, E::Impl>,
|
context: &'a mut MatchingContext<'b, E::Impl>,
|
||||||
flags_setter: &'a mut F,
|
flags_setter: &'a mut F,
|
||||||
shadow_cascade_order: ShadowCascadeOrder,
|
|
||||||
matches_user_and_author_rules: bool,
|
matches_user_and_author_rules: bool,
|
||||||
matches_document_author_rules: bool,
|
matches_document_author_rules: bool,
|
||||||
}
|
}
|
||||||
|
@ -132,7 +132,6 @@ where
|
||||||
context,
|
context,
|
||||||
flags_setter,
|
flags_setter,
|
||||||
rules,
|
rules,
|
||||||
shadow_cascade_order: 0,
|
|
||||||
matches_user_and_author_rules,
|
matches_user_and_author_rules,
|
||||||
matches_document_author_rules: matches_user_and_author_rules,
|
matches_document_author_rules: matches_user_and_author_rules,
|
||||||
}
|
}
|
||||||
|
@ -142,7 +141,7 @@ where
|
||||||
let cascade_level = match origin {
|
let cascade_level = match origin {
|
||||||
Origin::UserAgent => CascadeLevel::UANormal,
|
Origin::UserAgent => CascadeLevel::UANormal,
|
||||||
Origin::User => CascadeLevel::UserNormal,
|
Origin::User => CascadeLevel::UserNormal,
|
||||||
Origin::Author => CascadeLevel::SameTreeAuthorNormal,
|
Origin::Author => CascadeLevel::same_tree_author_normal(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let cascade_data = self.stylist.cascade_data().borrow_for_origin(origin);
|
let cascade_data = self.stylist.cascade_data().borrow_for_origin(origin);
|
||||||
|
@ -198,7 +197,6 @@ where
|
||||||
) {
|
) {
|
||||||
debug_assert!(shadow_host.shadow_root().is_some());
|
debug_assert!(shadow_host.shadow_root().is_some());
|
||||||
self.collect_rules_internal(Some(shadow_host), map, cascade_level);
|
self.collect_rules_internal(Some(shadow_host), map, cascade_level);
|
||||||
self.shadow_cascade_order += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -212,7 +210,6 @@ where
|
||||||
let rule_hash_target = self.rule_hash_target;
|
let rule_hash_target = self.rule_hash_target;
|
||||||
let rules = &mut self.rules;
|
let rules = &mut self.rules;
|
||||||
let flags_setter = &mut self.flags_setter;
|
let flags_setter = &mut self.flags_setter;
|
||||||
let shadow_cascade_order = self.shadow_cascade_order;
|
|
||||||
let start = rules.len();
|
let start = rules.len();
|
||||||
self.context.with_shadow_host(shadow_host, |context| {
|
self.context.with_shadow_host(shadow_host, |context| {
|
||||||
map.get_all_matching_rules(
|
map.get_all_matching_rules(
|
||||||
|
@ -222,16 +219,18 @@ where
|
||||||
context,
|
context,
|
||||||
flags_setter,
|
flags_setter,
|
||||||
cascade_level,
|
cascade_level,
|
||||||
shadow_cascade_order,
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
sort_rules_from(rules, start);
|
sort_rules_from(rules, start);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Collects the rules for the ::slotted pseudo-element.
|
/// Collects the rules for the ::slotted pseudo-element and the :host
|
||||||
fn collect_slotted_rules(&mut self) {
|
/// pseudo-class.
|
||||||
|
fn collect_host_and_slotted_rules(&mut self) {
|
||||||
let mut slots = SmallVec::<[_; 3]>::new();
|
let mut slots = SmallVec::<[_; 3]>::new();
|
||||||
let mut current = self.rule_hash_target.assigned_slot();
|
let mut current = self.rule_hash_target.assigned_slot();
|
||||||
|
let mut shadow_cascade_order = ShadowCascadeOrder::for_outermost_shadow_tree();
|
||||||
|
|
||||||
while let Some(slot) = current {
|
while let Some(slot) = current {
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
self.matches_user_and_author_rules,
|
self.matches_user_and_author_rules,
|
||||||
|
@ -239,11 +238,16 @@ where
|
||||||
);
|
);
|
||||||
slots.push(slot);
|
slots.push(slot);
|
||||||
current = slot.assigned_slot();
|
current = slot.assigned_slot();
|
||||||
|
shadow_cascade_order.dec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.collect_host_rules(shadow_cascade_order);
|
||||||
|
|
||||||
// Match slotted rules in reverse order, so that the outer slotted rules
|
// Match slotted rules in reverse order, so that the outer slotted rules
|
||||||
// come before the inner rules (and thus have less priority).
|
// come before the inner rules (and thus have less priority).
|
||||||
for slot in slots.iter().rev() {
|
for slot in slots.iter().rev() {
|
||||||
|
shadow_cascade_order.inc();
|
||||||
|
|
||||||
let shadow = slot.containing_shadow().unwrap();
|
let shadow = slot.containing_shadow().unwrap();
|
||||||
let data = match shadow.style_data() {
|
let data = match shadow.style_data() {
|
||||||
Some(d) => d,
|
Some(d) => d,
|
||||||
|
@ -253,10 +257,13 @@ where
|
||||||
Some(r) => r,
|
Some(r) => r,
|
||||||
None => continue,
|
None => continue,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.collect_rules_in_shadow_tree(
|
self.collect_rules_in_shadow_tree(
|
||||||
shadow.host(),
|
shadow.host(),
|
||||||
slotted_rules,
|
slotted_rules,
|
||||||
CascadeLevel::InnerShadowNormal,
|
CascadeLevel::AuthorNormal {
|
||||||
|
shadow_cascade_order,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -277,12 +284,12 @@ where
|
||||||
let cascade_data = containing_shadow.style_data();
|
let cascade_data = containing_shadow.style_data();
|
||||||
let host = containing_shadow.host();
|
let host = containing_shadow.host();
|
||||||
if let Some(map) = cascade_data.and_then(|data| data.normal_rules(self.pseudo_element)) {
|
if let Some(map) = cascade_data.and_then(|data| data.normal_rules(self.pseudo_element)) {
|
||||||
self.collect_rules_in_shadow_tree(host, map, CascadeLevel::SameTreeAuthorNormal);
|
self.collect_rules_in_shadow_tree(host, map, CascadeLevel::same_tree_author_normal());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Collects the rules for the :host pseudo-class.
|
/// Collects the rules for the :host pseudo-class.
|
||||||
fn collect_host_rules(&mut self) {
|
fn collect_host_rules(&mut self, shadow_cascade_order: ShadowCascadeOrder) {
|
||||||
let shadow = match self.rule_hash_target.shadow_root() {
|
let shadow = match self.rule_hash_target.shadow_root() {
|
||||||
Some(s) => s,
|
Some(s) => s,
|
||||||
None => return,
|
None => return,
|
||||||
|
@ -307,7 +314,9 @@ where
|
||||||
self.collect_rules_in_shadow_tree(
|
self.collect_rules_in_shadow_tree(
|
||||||
rule_hash_target,
|
rule_hash_target,
|
||||||
host_rules,
|
host_rules,
|
||||||
CascadeLevel::InnerShadowNormal,
|
CascadeLevel::AuthorNormal {
|
||||||
|
shadow_cascade_order,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,14 +333,23 @@ where
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let shadow = match self.rule_hash_target.containing_shadow() {
|
let mut inner_shadow = match self.rule_hash_target.containing_shadow() {
|
||||||
Some(s) => s,
|
Some(s) => s,
|
||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
let host = shadow.host();
|
let mut shadow_cascade_order = ShadowCascadeOrder::for_innermost_containing_tree();
|
||||||
let containing_shadow = host.containing_shadow();
|
|
||||||
let part_rules = match containing_shadow {
|
let mut parts = SmallVec::<[Atom; 3]>::new();
|
||||||
|
self.rule_hash_target.each_part(|p| parts.push(p.clone()));
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if parts.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let outer_shadow = inner_shadow.host().containing_shadow();
|
||||||
|
let part_rules = match outer_shadow {
|
||||||
Some(shadow) => shadow
|
Some(shadow) => shadow
|
||||||
.style_data()
|
.style_data()
|
||||||
.and_then(|data| data.part_rules(self.pseudo_element)),
|
.and_then(|data| data.part_rules(self.pseudo_element)),
|
||||||
|
@ -342,24 +360,17 @@ where
|
||||||
.part_rules(self.pseudo_element),
|
.part_rules(self.pseudo_element),
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO(emilio): SameTreeAuthorNormal is a bit of a lie here, we may
|
|
||||||
// need an OuterTreeAuthorNormal cascade level or such, and change the
|
|
||||||
// cascade order, if we allow to forward parts to even outer trees.
|
|
||||||
//
|
|
||||||
// Though the current thing kinda works because we apply them after
|
|
||||||
// the outer tree, so as long as we don't allow forwarding we're
|
|
||||||
// good.
|
|
||||||
if let Some(part_rules) = part_rules {
|
if let Some(part_rules) = part_rules {
|
||||||
let containing_host = containing_shadow.map(|s| s.host());
|
let containing_host = outer_shadow.map(|s| s.host());
|
||||||
let element = self.element;
|
let element = self.element;
|
||||||
let rule_hash_target = self.rule_hash_target;
|
|
||||||
let rules = &mut self.rules;
|
let rules = &mut self.rules;
|
||||||
let flags_setter = &mut self.flags_setter;
|
let flags_setter = &mut self.flags_setter;
|
||||||
let shadow_cascade_order = self.shadow_cascade_order;
|
let cascade_level = CascadeLevel::AuthorNormal {
|
||||||
let cascade_level = CascadeLevel::SameTreeAuthorNormal;
|
shadow_cascade_order,
|
||||||
|
};
|
||||||
let start = rules.len();
|
let start = rules.len();
|
||||||
self.context.with_shadow_host(containing_host, |context| {
|
self.context.with_shadow_host(containing_host, |context| {
|
||||||
rule_hash_target.each_part(|p| {
|
for p in &parts {
|
||||||
if let Some(part_rules) = part_rules.get(p) {
|
if let Some(part_rules) = part_rules.get(p) {
|
||||||
SelectorMap::get_matching_rules(
|
SelectorMap::get_matching_rules(
|
||||||
element,
|
element,
|
||||||
|
@ -368,24 +379,43 @@ where
|
||||||
context,
|
context,
|
||||||
flags_setter,
|
flags_setter,
|
||||||
cascade_level,
|
cascade_level,
|
||||||
shadow_cascade_order,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
sort_rules_from(rules, start);
|
sort_rules_from(rules, start);
|
||||||
|
shadow_cascade_order.inc();
|
||||||
|
}
|
||||||
|
|
||||||
|
let inner_shadow_host = inner_shadow.host();
|
||||||
|
|
||||||
|
inner_shadow = match outer_shadow {
|
||||||
|
Some(s) => s,
|
||||||
|
None => break, // Nowhere to export to.
|
||||||
|
};
|
||||||
|
|
||||||
|
parts.retain(|part| {
|
||||||
|
let exported_part = match inner_shadow_host.exported_part(part) {
|
||||||
|
Some(part) => part,
|
||||||
|
None => return false,
|
||||||
|
};
|
||||||
|
std::mem::replace(part, exported_part);
|
||||||
|
true
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_style_attribute_and_animation_rules(&mut self) {
|
fn collect_style_attribute(&mut self) {
|
||||||
if let Some(sa) = self.style_attribute {
|
if let Some(sa) = self.style_attribute {
|
||||||
self.rules
|
self.rules
|
||||||
.push(ApplicableDeclarationBlock::from_declarations(
|
.push(ApplicableDeclarationBlock::from_declarations(
|
||||||
sa.clone_arc(),
|
sa.clone_arc(),
|
||||||
CascadeLevel::StyleAttributeNormal,
|
CascadeLevel::same_tree_author_normal(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect_animation_rules(&mut self) {
|
||||||
if let Some(so) = self.smil_override {
|
if let Some(so) = self.smil_override {
|
||||||
self.rules
|
self.rules
|
||||||
.push(ApplicableDeclarationBlock::from_declarations(
|
.push(ApplicableDeclarationBlock::from_declarations(
|
||||||
|
@ -431,11 +461,11 @@ where
|
||||||
if self.stylist.author_styles_enabled() == AuthorStylesEnabled::No {
|
if self.stylist.author_styles_enabled() == AuthorStylesEnabled::No {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.collect_host_rules();
|
self.collect_host_and_slotted_rules();
|
||||||
self.collect_slotted_rules();
|
|
||||||
self.collect_normal_rules_from_containing_shadow_tree();
|
self.collect_normal_rules_from_containing_shadow_tree();
|
||||||
self.collect_document_author_rules();
|
self.collect_document_author_rules();
|
||||||
|
self.collect_style_attribute();
|
||||||
self.collect_part_rules();
|
self.collect_part_rules();
|
||||||
self.collect_style_attribute_and_animation_rules();
|
self.collect_animation_rules();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -169,15 +169,60 @@ const FREE_LIST_SENTINEL: *mut RuleNode = 0x01 as *mut RuleNode;
|
||||||
/// another thread is currently adding an entry). We spin if we find this value.
|
/// another thread is currently adding an entry). We spin if we find this value.
|
||||||
const FREE_LIST_LOCKED: *mut RuleNode = 0x02 as *mut RuleNode;
|
const FREE_LIST_LOCKED: *mut RuleNode = 0x02 as *mut RuleNode;
|
||||||
|
|
||||||
/// A counter to track how many inner shadow roots rules deep we are.
|
/// A counter to track how many shadow root rules deep we are. This is used to
|
||||||
///
|
/// handle:
|
||||||
/// This is used to handle:
|
|
||||||
///
|
///
|
||||||
/// https://drafts.csswg.org/css-scoping/#shadow-cascading
|
/// https://drafts.csswg.org/css-scoping/#shadow-cascading
|
||||||
///
|
///
|
||||||
/// In particular, it'd be `0` for the innermost shadow host, `1` for the next,
|
/// See the static functions for the meaning of different values.
|
||||||
/// and so on.
|
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Ord, PartialEq, PartialOrd)]
|
||||||
pub type ShadowCascadeOrder = u8;
|
pub struct ShadowCascadeOrder(i8);
|
||||||
|
|
||||||
|
impl ShadowCascadeOrder {
|
||||||
|
/// A level for the outermost shadow tree (the shadow tree we own, and the
|
||||||
|
/// ones from the slots we're slotted in).
|
||||||
|
#[inline]
|
||||||
|
pub fn for_outermost_shadow_tree() -> Self {
|
||||||
|
Self(-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A level for the element's tree.
|
||||||
|
#[inline]
|
||||||
|
fn for_same_tree() -> Self {
|
||||||
|
Self(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A level for the innermost containing tree (the one closest to the
|
||||||
|
/// element).
|
||||||
|
#[inline]
|
||||||
|
pub fn for_innermost_containing_tree() -> Self {
|
||||||
|
Self(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decrement the level, moving inwards. We should only move inwards if
|
||||||
|
/// we're traversing slots.
|
||||||
|
#[inline]
|
||||||
|
pub fn dec(&mut self) {
|
||||||
|
debug_assert!(self.0 < 0);
|
||||||
|
self.0 = self.0.saturating_sub(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The level, moving inwards. We should only move inwards if we're
|
||||||
|
/// traversing slots.
|
||||||
|
#[inline]
|
||||||
|
pub fn inc(&mut self) {
|
||||||
|
debug_assert_ne!(self.0, -1);
|
||||||
|
self.0 = self.0.saturating_add(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Neg for ShadowCascadeOrder {
|
||||||
|
type Output = Self;
|
||||||
|
#[inline]
|
||||||
|
fn neg(self) -> Self {
|
||||||
|
Self(self.0.neg())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl RuleTree {
|
impl RuleTree {
|
||||||
/// Construct a new rule tree.
|
/// Construct a new rule tree.
|
||||||
|
@ -215,26 +260,20 @@ impl RuleTree {
|
||||||
guards: &StylesheetGuards,
|
guards: &StylesheetGuards,
|
||||||
) -> StrongRuleNode
|
) -> StrongRuleNode
|
||||||
where
|
where
|
||||||
I: Iterator<Item = (StyleSource, CascadeLevel, ShadowCascadeOrder)>,
|
I: Iterator<Item = (StyleSource, CascadeLevel)>,
|
||||||
{
|
{
|
||||||
use self::CascadeLevel::*;
|
use self::CascadeLevel::*;
|
||||||
let mut current = self.root.clone();
|
let mut current = self.root.clone();
|
||||||
let mut last_level = current.get().level;
|
|
||||||
|
|
||||||
let mut found_important = false;
|
let mut found_important = false;
|
||||||
let mut important_style_attr = None;
|
|
||||||
|
|
||||||
let mut important_same_tree = SmallVec::<[StyleSource; 4]>::new();
|
let mut important_author = SmallVec::<[(StyleSource, ShadowCascadeOrder); 4]>::new();
|
||||||
let mut important_inner_shadow = SmallVec::<[SmallVec<[StyleSource; 4]>; 4]>::new();
|
|
||||||
important_inner_shadow.push(SmallVec::new());
|
|
||||||
|
|
||||||
let mut important_user = SmallVec::<[StyleSource; 4]>::new();
|
let mut important_user = SmallVec::<[StyleSource; 4]>::new();
|
||||||
let mut important_ua = SmallVec::<[StyleSource; 4]>::new();
|
let mut important_ua = SmallVec::<[StyleSource; 4]>::new();
|
||||||
let mut transition = None;
|
let mut transition = None;
|
||||||
|
|
||||||
let mut last_cascade_order = 0;
|
for (source, level) in iter {
|
||||||
for (source, level, shadow_cascade_order) in iter {
|
|
||||||
debug_assert!(level >= last_level, "Not really ordered");
|
|
||||||
debug_assert!(!level.is_important(), "Important levels handled internally");
|
debug_assert!(!level.is_important(), "Important levels handled internally");
|
||||||
let any_important = {
|
let any_important = {
|
||||||
let pdb = source.read(level.guard(guards));
|
let pdb = source.read(level.guard(guards));
|
||||||
|
@ -244,29 +283,13 @@ impl RuleTree {
|
||||||
if any_important {
|
if any_important {
|
||||||
found_important = true;
|
found_important = true;
|
||||||
match level {
|
match level {
|
||||||
InnerShadowNormal => {
|
AuthorNormal {
|
||||||
debug_assert!(
|
shadow_cascade_order,
|
||||||
shadow_cascade_order >= last_cascade_order,
|
} => {
|
||||||
"Not really ordered"
|
important_author.push((source.clone(), shadow_cascade_order));
|
||||||
);
|
|
||||||
if shadow_cascade_order > last_cascade_order &&
|
|
||||||
!important_inner_shadow.last().unwrap().is_empty()
|
|
||||||
{
|
|
||||||
last_cascade_order = shadow_cascade_order;
|
|
||||||
important_inner_shadow.push(SmallVec::new());
|
|
||||||
}
|
|
||||||
important_inner_shadow
|
|
||||||
.last_mut()
|
|
||||||
.unwrap()
|
|
||||||
.push(source.clone())
|
|
||||||
},
|
},
|
||||||
SameTreeAuthorNormal => important_same_tree.push(source.clone()),
|
|
||||||
UANormal => important_ua.push(source.clone()),
|
UANormal => important_ua.push(source.clone()),
|
||||||
UserNormal => important_user.push(source.clone()),
|
UserNormal => important_user.push(source.clone()),
|
||||||
StyleAttributeNormal => {
|
|
||||||
debug_assert!(important_style_attr.is_none());
|
|
||||||
important_style_attr = Some(source.clone());
|
|
||||||
},
|
|
||||||
_ => {},
|
_ => {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -290,7 +313,6 @@ impl RuleTree {
|
||||||
} else {
|
} else {
|
||||||
current = current.ensure_child(self.root.downgrade(), source, level);
|
current = current.ensure_child(self.root.downgrade(), source, level);
|
||||||
}
|
}
|
||||||
last_level = level;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Early-return in the common case of no !important declarations.
|
// Early-return in the common case of no !important declarations.
|
||||||
|
@ -298,23 +320,39 @@ impl RuleTree {
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Insert important declarations, in order of increasing importance,
|
// Insert important declarations, in order of increasing importance,
|
||||||
// followed by any transition rule.
|
// followed by any transition rule.
|
||||||
//
|
//
|
||||||
|
// Inner shadow wins over same-tree, which wins over outer-shadow.
|
||||||
for source in important_same_tree.drain() {
|
//
|
||||||
current = current.ensure_child(self.root.downgrade(), source, SameTreeAuthorImportant);
|
// We negate the shadow cascade order to preserve the right PartialOrd
|
||||||
|
// behavior.
|
||||||
|
if !important_author.is_empty() &&
|
||||||
|
important_author.first().unwrap().1 != important_author.last().unwrap().1
|
||||||
|
{
|
||||||
|
// We only need to sort if the important rules come from
|
||||||
|
// different trees, but we need this sort to be stable.
|
||||||
|
//
|
||||||
|
// FIXME(emilio): This could maybe be smarter, probably by chunking
|
||||||
|
// the important rules while inserting, and iterating the outer
|
||||||
|
// chunks in reverse order.
|
||||||
|
//
|
||||||
|
// That is, if we have rules with levels like: -1 -1 -1 0 0 0 1 1 1,
|
||||||
|
// we're really only sorting the chunks, while keeping elements
|
||||||
|
// inside the same chunk already sorted. Seems like we could try to
|
||||||
|
// keep a SmallVec-of-SmallVecs with the chunks and just iterate the
|
||||||
|
// outer in reverse.
|
||||||
|
important_author.sort_by_key(|&(_, order)| -order);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(source) = important_style_attr {
|
for (source, shadow_cascade_order) in important_author.drain() {
|
||||||
current = current.ensure_child(self.root.downgrade(), source, StyleAttributeImportant);
|
current = current.ensure_child(
|
||||||
}
|
self.root.downgrade(),
|
||||||
|
source,
|
||||||
for mut list in important_inner_shadow.drain().rev() {
|
AuthorImportant {
|
||||||
for source in list.drain() {
|
shadow_cascade_order: -shadow_cascade_order,
|
||||||
current = current.ensure_child(self.root.downgrade(), source, InnerShadowImportant);
|
},
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for source in important_user.drain() {
|
for source in important_user.drain() {
|
||||||
|
@ -359,11 +397,8 @@ impl RuleTree {
|
||||||
I: Iterator<Item = (StyleSource, CascadeLevel)>,
|
I: Iterator<Item = (StyleSource, CascadeLevel)>,
|
||||||
{
|
{
|
||||||
let mut current = from;
|
let mut current = from;
|
||||||
let mut last_level = current.get().level;
|
|
||||||
for (source, level) in iter {
|
for (source, level) in iter {
|
||||||
debug_assert!(last_level <= level, "Not really ordered");
|
|
||||||
current = current.ensure_child(self.root.downgrade(), source, level);
|
current = current.ensure_child(self.root.downgrade(), source, level);
|
||||||
last_level = level;
|
|
||||||
}
|
}
|
||||||
current
|
current
|
||||||
}
|
}
|
||||||
|
@ -439,7 +474,6 @@ impl RuleTree {
|
||||||
guards: &StylesheetGuards,
|
guards: &StylesheetGuards,
|
||||||
important_rules_changed: &mut bool,
|
important_rules_changed: &mut bool,
|
||||||
) -> Option<StrongRuleNode> {
|
) -> Option<StrongRuleNode> {
|
||||||
debug_assert!(level.is_unique_per_element());
|
|
||||||
// TODO(emilio): Being smarter with lifetimes we could avoid a bit of
|
// TODO(emilio): Being smarter with lifetimes we could avoid a bit of
|
||||||
// the refcount churn.
|
// the refcount churn.
|
||||||
let mut current = path.clone();
|
let mut current = path.clone();
|
||||||
|
@ -468,7 +502,11 @@ impl RuleTree {
|
||||||
if current.get().level == level {
|
if current.get().level == level {
|
||||||
*important_rules_changed |= level.is_important();
|
*important_rules_changed |= level.is_important();
|
||||||
|
|
||||||
if let Some(pdb) = pdb {
|
let current_decls = current.get().source.as_ref().unwrap().as_declarations();
|
||||||
|
|
||||||
|
// If the only rule at the level we're replacing is exactly the
|
||||||
|
// same as `pdb`, we're done, and `path` is still valid.
|
||||||
|
if let (Some(ref pdb), Some(ref current_decls)) = (pdb, current_decls) {
|
||||||
// If the only rule at the level we're replacing is exactly the
|
// If the only rule at the level we're replacing is exactly the
|
||||||
// same as `pdb`, we're done, and `path` is still valid.
|
// same as `pdb`, we're done, and `path` is still valid.
|
||||||
//
|
//
|
||||||
|
@ -478,25 +516,17 @@ impl RuleTree {
|
||||||
// also equally valid. This is less likely, and would require an
|
// also equally valid. This is less likely, and would require an
|
||||||
// in-place mutation of the source, which is, at best, fiddly,
|
// in-place mutation of the source, which is, at best, fiddly,
|
||||||
// so let's skip it for now.
|
// so let's skip it for now.
|
||||||
let current_decls = current
|
let is_here_already = ArcBorrow::ptr_eq(pdb, current_decls);
|
||||||
.get()
|
|
||||||
.source
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.as_declarations()
|
|
||||||
.expect("Replacing non-declarations style?");
|
|
||||||
let is_here_already = ArcBorrow::ptr_eq(&pdb, ¤t_decls);
|
|
||||||
if is_here_already {
|
if is_here_already {
|
||||||
debug!("Picking the fast path in rule replacement");
|
debug!("Picking the fast path in rule replacement");
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if current_decls.is_some() {
|
||||||
current = current.parent().unwrap().clone();
|
current = current.parent().unwrap().clone();
|
||||||
}
|
}
|
||||||
debug_assert!(
|
}
|
||||||
current.get().level != level,
|
|
||||||
"Multiple rules should've been replaced?"
|
|
||||||
);
|
|
||||||
|
|
||||||
// Insert the rule if it's relevant at this level in the cascade.
|
// Insert the rule if it's relevant at this level in the cascade.
|
||||||
//
|
//
|
||||||
|
@ -611,61 +641,127 @@ const RULE_TREE_GC_INTERVAL: usize = 300;
|
||||||
/// tree may affect an element connected to the document or an "outer" shadow
|
/// tree may affect an element connected to the document or an "outer" shadow
|
||||||
/// tree.
|
/// tree.
|
||||||
///
|
///
|
||||||
/// We need to differentiate between rules from the same tree and "inner" shadow
|
|
||||||
/// trees in order to be able to find the right position for the style attribute
|
|
||||||
/// easily. Otherwise we wouldn't be able to avoid selector-matching when a
|
|
||||||
/// style attribute is added or removed.
|
|
||||||
///
|
|
||||||
/// [1]: https://drafts.csswg.org/css-cascade/#cascade-origin
|
/// [1]: https://drafts.csswg.org/css-cascade/#cascade-origin
|
||||||
/// [2]: https://drafts.csswg.org/css-cascade/#preshint
|
/// [2]: https://drafts.csswg.org/css-cascade/#preshint
|
||||||
/// [3]: https://html.spec.whatwg.org/multipage/#presentational-hints
|
/// [3]: https://html.spec.whatwg.org/multipage/#presentational-hints
|
||||||
/// [4]: https://drafts.csswg.org/css-scoping/#shadow-cascading
|
/// [4]: https://drafts.csswg.org/css-scoping/#shadow-cascading
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd)]
|
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, PartialOrd)]
|
||||||
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
|
|
||||||
pub enum CascadeLevel {
|
pub enum CascadeLevel {
|
||||||
/// Normal User-Agent rules.
|
/// Normal User-Agent rules.
|
||||||
UANormal = 0,
|
UANormal,
|
||||||
/// User normal rules.
|
/// User normal rules.
|
||||||
UserNormal,
|
UserNormal,
|
||||||
/// Presentational hints.
|
/// Presentational hints.
|
||||||
PresHints,
|
PresHints,
|
||||||
/// Shadow DOM styles from "inner" shadow trees.
|
/// Shadow DOM styles from author styles.
|
||||||
|
AuthorNormal {
|
||||||
|
/// The order in the shadow tree hierarchy. This number is relative to
|
||||||
|
/// the tree of the element, and thus the only invariants that need to
|
||||||
|
/// be preserved is:
|
||||||
///
|
///
|
||||||
/// See above for why this is needed instead of merging InnerShadowNormal,
|
/// * Zero is the same tree as the element that matched the rule. This
|
||||||
/// SameTreeAuthorNormal and StyleAttributeNormal inside something like
|
/// is important so that we can optimize style attribute insertions.
|
||||||
/// AuthorNormal.
|
///
|
||||||
InnerShadowNormal,
|
/// * The levels are ordered in accordance with
|
||||||
/// Author normal rules from the same tree the element is in.
|
/// https://drafts.csswg.org/css-scoping/#shadow-cascading
|
||||||
SameTreeAuthorNormal,
|
shadow_cascade_order: ShadowCascadeOrder,
|
||||||
/// Style attribute normal rules.
|
},
|
||||||
StyleAttributeNormal,
|
|
||||||
/// SVG SMIL animations.
|
/// SVG SMIL animations.
|
||||||
SMILOverride,
|
SMILOverride,
|
||||||
/// CSS animations and script-generated animations.
|
/// CSS animations and script-generated animations.
|
||||||
Animations,
|
Animations,
|
||||||
/// Author-supplied important rules from the same tree the element came
|
/// Author-supplied important rules.
|
||||||
/// from.
|
AuthorImportant {
|
||||||
SameTreeAuthorImportant,
|
/// The order in the shadow tree hierarchy, inverted, so that PartialOrd
|
||||||
/// Style attribute important rules.
|
/// does the right thing.
|
||||||
StyleAttributeImportant,
|
shadow_cascade_order: ShadowCascadeOrder,
|
||||||
/// Shadow DOM important rules.
|
},
|
||||||
InnerShadowImportant,
|
|
||||||
/// User important rules.
|
/// User important rules.
|
||||||
UserImportant,
|
UserImportant,
|
||||||
/// User-agent important rules.
|
/// User-agent important rules.
|
||||||
UAImportant,
|
UAImportant,
|
||||||
/// Transitions
|
/// Transitions
|
||||||
///
|
|
||||||
/// NB: If this changes from being last, change from_byte below.
|
|
||||||
Transitions,
|
Transitions,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CascadeLevel {
|
impl CascadeLevel {
|
||||||
/// Converts a raw byte to a CascadeLevel.
|
/// Pack this cascade level in a single byte.
|
||||||
pub unsafe fn from_byte(byte: u8) -> Self {
|
///
|
||||||
debug_assert!(byte <= CascadeLevel::Transitions as u8);
|
/// We have 10 levels, which we can represent with 4 bits, and then a
|
||||||
mem::transmute(byte)
|
/// cascade order optionally, which we can clamp to three bits max, and
|
||||||
|
/// represent with a fourth bit for the sign.
|
||||||
|
///
|
||||||
|
/// So this creates: SOOODDDD
|
||||||
|
///
|
||||||
|
/// Where `S` is the sign of the order (one if negative, 0 otherwise), `O`
|
||||||
|
/// is the absolute value of the order, and `D`s are the discriminant.
|
||||||
|
#[inline]
|
||||||
|
pub fn to_byte_lossy(&self) -> u8 {
|
||||||
|
let (discriminant, order) = match *self {
|
||||||
|
Self::UANormal => (0, 0),
|
||||||
|
Self::UserNormal => (1, 0),
|
||||||
|
Self::PresHints => (2, 0),
|
||||||
|
Self::AuthorNormal {
|
||||||
|
shadow_cascade_order,
|
||||||
|
} => (3, shadow_cascade_order.0),
|
||||||
|
Self::SMILOverride => (4, 0),
|
||||||
|
Self::Animations => (5, 0),
|
||||||
|
Self::AuthorImportant {
|
||||||
|
shadow_cascade_order,
|
||||||
|
} => (6, shadow_cascade_order.0),
|
||||||
|
Self::UserImportant => (7, 0),
|
||||||
|
Self::UAImportant => (8, 0),
|
||||||
|
Self::Transitions => (9, 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
debug_assert_eq!(discriminant & 0xf, discriminant);
|
||||||
|
if order == 0 {
|
||||||
|
return discriminant;
|
||||||
|
}
|
||||||
|
|
||||||
|
let negative = order < 0;
|
||||||
|
let value = std::cmp::min(order.abs() as u8, 0b111);
|
||||||
|
(negative as u8) << 7 | value << 4 | discriminant
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert back from the single-byte representation of the cascade level
|
||||||
|
/// explained above.
|
||||||
|
#[inline]
|
||||||
|
pub fn from_byte(b: u8) -> Self {
|
||||||
|
let order = {
|
||||||
|
let abs = ((b & 0b01110000) >> 4) as i8;
|
||||||
|
let negative = b & 0b10000000 != 0;
|
||||||
|
if negative {
|
||||||
|
-abs
|
||||||
|
} else {
|
||||||
|
abs
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let discriminant = b & 0xf;
|
||||||
|
let level = match discriminant {
|
||||||
|
0 => Self::UANormal,
|
||||||
|
1 => Self::UserNormal,
|
||||||
|
2 => Self::PresHints,
|
||||||
|
3 => {
|
||||||
|
return Self::AuthorNormal {
|
||||||
|
shadow_cascade_order: ShadowCascadeOrder(order),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
4 => Self::SMILOverride,
|
||||||
|
5 => Self::Animations,
|
||||||
|
6 => {
|
||||||
|
return Self::AuthorImportant {
|
||||||
|
shadow_cascade_order: ShadowCascadeOrder(order),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
7 => Self::UserImportant,
|
||||||
|
8 => Self::UAImportant,
|
||||||
|
9 => Self::Transitions,
|
||||||
|
_ => unreachable!("Didn't expect {} as a discriminant", discriminant),
|
||||||
|
};
|
||||||
|
debug_assert_eq!(order, 0, "Didn't expect an order value for {:?}", level);
|
||||||
|
level
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Select a lock guard for this level
|
/// Select a lock guard for this level
|
||||||
|
@ -679,16 +775,21 @@ impl CascadeLevel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether this cascade level is unique per element, in which case
|
/// Returns the cascade level for author important declarations from the
|
||||||
/// we can replace the path in the cascade without fear.
|
/// same tree as the element.
|
||||||
pub fn is_unique_per_element(&self) -> bool {
|
#[inline]
|
||||||
match *self {
|
pub fn same_tree_author_important() -> Self {
|
||||||
CascadeLevel::Transitions |
|
CascadeLevel::AuthorImportant {
|
||||||
CascadeLevel::Animations |
|
shadow_cascade_order: ShadowCascadeOrder::for_same_tree(),
|
||||||
CascadeLevel::SMILOverride |
|
}
|
||||||
CascadeLevel::StyleAttributeNormal |
|
}
|
||||||
CascadeLevel::StyleAttributeImportant => true,
|
|
||||||
_ => false,
|
/// Returns the cascade level for author normal declarations from the same
|
||||||
|
/// tree as the element.
|
||||||
|
#[inline]
|
||||||
|
pub fn same_tree_author_normal() -> Self {
|
||||||
|
CascadeLevel::AuthorNormal {
|
||||||
|
shadow_cascade_order: ShadowCascadeOrder::for_same_tree(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -697,9 +798,7 @@ impl CascadeLevel {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_important(&self) -> bool {
|
pub fn is_important(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
CascadeLevel::SameTreeAuthorImportant |
|
CascadeLevel::AuthorImportant { .. } |
|
||||||
CascadeLevel::InnerShadowImportant |
|
|
||||||
CascadeLevel::StyleAttributeImportant |
|
|
||||||
CascadeLevel::UserImportant |
|
CascadeLevel::UserImportant |
|
||||||
CascadeLevel::UAImportant => true,
|
CascadeLevel::UAImportant => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
|
@ -724,14 +823,10 @@ impl CascadeLevel {
|
||||||
CascadeLevel::UAImportant | CascadeLevel::UANormal => Origin::UserAgent,
|
CascadeLevel::UAImportant | CascadeLevel::UANormal => Origin::UserAgent,
|
||||||
CascadeLevel::UserImportant | CascadeLevel::UserNormal => Origin::User,
|
CascadeLevel::UserImportant | CascadeLevel::UserNormal => Origin::User,
|
||||||
CascadeLevel::PresHints |
|
CascadeLevel::PresHints |
|
||||||
CascadeLevel::InnerShadowNormal |
|
CascadeLevel::AuthorNormal { .. } |
|
||||||
CascadeLevel::SameTreeAuthorNormal |
|
CascadeLevel::AuthorImportant { .. } |
|
||||||
CascadeLevel::StyleAttributeNormal |
|
|
||||||
CascadeLevel::SMILOverride |
|
CascadeLevel::SMILOverride |
|
||||||
CascadeLevel::Animations |
|
CascadeLevel::Animations |
|
||||||
CascadeLevel::SameTreeAuthorImportant |
|
|
||||||
CascadeLevel::StyleAttributeImportant |
|
|
||||||
CascadeLevel::InnerShadowImportant |
|
|
||||||
CascadeLevel::Transitions => Origin::Author,
|
CascadeLevel::Transitions => Origin::Author,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1146,6 +1241,15 @@ impl StrongRuleNode {
|
||||||
) -> StrongRuleNode {
|
) -> StrongRuleNode {
|
||||||
use parking_lot::RwLockUpgradableReadGuard;
|
use parking_lot::RwLockUpgradableReadGuard;
|
||||||
|
|
||||||
|
debug_assert!(
|
||||||
|
self.get().level <= level,
|
||||||
|
"Should be ordered (instead {:?} > {:?}), from {:?} and {:?}",
|
||||||
|
self.get().level,
|
||||||
|
level,
|
||||||
|
self.get().source,
|
||||||
|
source,
|
||||||
|
);
|
||||||
|
|
||||||
let key = ChildKey(level, source.key());
|
let key = ChildKey(level, source.key());
|
||||||
|
|
||||||
let read_guard = self.get().children.upgradable_read();
|
let read_guard = self.get().children.upgradable_read();
|
||||||
|
@ -1448,14 +1552,24 @@ impl StrongRuleNode {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
match node.cascade_level() {
|
let is_author = node.cascade_level().origin() == Origin::Author;
|
||||||
// Non-author rules:
|
|
||||||
CascadeLevel::UANormal |
|
|
||||||
CascadeLevel::UAImportant |
|
|
||||||
CascadeLevel::UserNormal |
|
|
||||||
CascadeLevel::UserImportant => {
|
|
||||||
for (id, declaration) in longhands {
|
for (id, declaration) in longhands {
|
||||||
if properties.contains(id) {
|
if !properties.contains(id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_author {
|
||||||
|
if !author_colors_allowed {
|
||||||
|
// FIXME(emilio): this looks wrong, this should
|
||||||
|
// do: if color is not transparent, then return
|
||||||
|
// true, or something.
|
||||||
|
if let PropertyDeclaration::BackgroundColor(ref color) = *declaration {
|
||||||
|
return *color == Color::transparent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// This property was set by a non-author rule.
|
// This property was set by a non-author rule.
|
||||||
// Stop looking for it in this element's rule
|
// Stop looking for it in this element's rule
|
||||||
// nodes.
|
// nodes.
|
||||||
|
@ -1464,41 +1578,12 @@ impl StrongRuleNode {
|
||||||
// However, if it is inherited, then it might be
|
// However, if it is inherited, then it might be
|
||||||
// inherited from an author rule from an
|
// inherited from an author rule from an
|
||||||
// ancestor element's rule nodes.
|
// ancestor element's rule nodes.
|
||||||
if declaration.get_css_wide_keyword() ==
|
if declaration.get_css_wide_keyword() == Some(CSSWideKeyword::Inherit) {
|
||||||
Some(CSSWideKeyword::Inherit)
|
|
||||||
{
|
|
||||||
have_explicit_ua_inherit = true;
|
have_explicit_ua_inherit = true;
|
||||||
inherited_properties.insert(id);
|
inherited_properties.insert(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
// Author rules:
|
|
||||||
CascadeLevel::PresHints |
|
|
||||||
CascadeLevel::SameTreeAuthorNormal |
|
|
||||||
CascadeLevel::InnerShadowNormal |
|
|
||||||
CascadeLevel::StyleAttributeNormal |
|
|
||||||
CascadeLevel::SMILOverride |
|
|
||||||
CascadeLevel::Animations |
|
|
||||||
CascadeLevel::SameTreeAuthorImportant |
|
|
||||||
CascadeLevel::InnerShadowImportant |
|
|
||||||
CascadeLevel::StyleAttributeImportant |
|
|
||||||
CascadeLevel::Transitions => {
|
|
||||||
for (id, declaration) in longhands {
|
|
||||||
if properties.contains(id) {
|
|
||||||
if !author_colors_allowed {
|
|
||||||
if let PropertyDeclaration::BackgroundColor(ref color) =
|
|
||||||
*declaration
|
|
||||||
{
|
|
||||||
return *color == Color::transparent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !have_explicit_ua_inherit {
|
if !have_explicit_ua_inherit {
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -10,7 +10,7 @@ use crate::context::QuirksMode;
|
||||||
use crate::dom::TElement;
|
use crate::dom::TElement;
|
||||||
use crate::hash::map as hash_map;
|
use crate::hash::map as hash_map;
|
||||||
use crate::hash::{HashMap, HashSet};
|
use crate::hash::{HashMap, HashSet};
|
||||||
use crate::rule_tree::{CascadeLevel, ShadowCascadeOrder};
|
use crate::rule_tree::CascadeLevel;
|
||||||
use crate::selector_parser::SelectorImpl;
|
use crate::selector_parser::SelectorImpl;
|
||||||
use crate::stylist::Rule;
|
use crate::stylist::Rule;
|
||||||
use crate::{Atom, LocalName, Namespace, WeakAtom};
|
use crate::{Atom, LocalName, Namespace, WeakAtom};
|
||||||
|
@ -171,7 +171,6 @@ impl SelectorMap<Rule> {
|
||||||
context: &mut MatchingContext<E::Impl>,
|
context: &mut MatchingContext<E::Impl>,
|
||||||
flags_setter: &mut F,
|
flags_setter: &mut F,
|
||||||
cascade_level: CascadeLevel,
|
cascade_level: CascadeLevel,
|
||||||
shadow_cascade_order: ShadowCascadeOrder,
|
|
||||||
) where
|
) where
|
||||||
E: TElement,
|
E: TElement,
|
||||||
F: FnMut(&E, ElementSelectorFlags),
|
F: FnMut(&E, ElementSelectorFlags),
|
||||||
|
@ -190,7 +189,6 @@ impl SelectorMap<Rule> {
|
||||||
context,
|
context,
|
||||||
flags_setter,
|
flags_setter,
|
||||||
cascade_level,
|
cascade_level,
|
||||||
shadow_cascade_order,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,7 +201,6 @@ impl SelectorMap<Rule> {
|
||||||
context,
|
context,
|
||||||
flags_setter,
|
flags_setter,
|
||||||
cascade_level,
|
cascade_level,
|
||||||
shadow_cascade_order,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -217,7 +214,6 @@ impl SelectorMap<Rule> {
|
||||||
context,
|
context,
|
||||||
flags_setter,
|
flags_setter,
|
||||||
cascade_level,
|
cascade_level,
|
||||||
shadow_cascade_order,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -230,7 +226,6 @@ impl SelectorMap<Rule> {
|
||||||
context,
|
context,
|
||||||
flags_setter,
|
flags_setter,
|
||||||
cascade_level,
|
cascade_level,
|
||||||
shadow_cascade_order,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,7 +237,6 @@ impl SelectorMap<Rule> {
|
||||||
context,
|
context,
|
||||||
flags_setter,
|
flags_setter,
|
||||||
cascade_level,
|
cascade_level,
|
||||||
shadow_cascade_order,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,7 +247,6 @@ impl SelectorMap<Rule> {
|
||||||
context,
|
context,
|
||||||
flags_setter,
|
flags_setter,
|
||||||
cascade_level,
|
cascade_level,
|
||||||
shadow_cascade_order,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,7 +258,6 @@ impl SelectorMap<Rule> {
|
||||||
context: &mut MatchingContext<E::Impl>,
|
context: &mut MatchingContext<E::Impl>,
|
||||||
flags_setter: &mut F,
|
flags_setter: &mut F,
|
||||||
cascade_level: CascadeLevel,
|
cascade_level: CascadeLevel,
|
||||||
shadow_cascade_order: ShadowCascadeOrder,
|
|
||||||
) where
|
) where
|
||||||
E: TElement,
|
E: TElement,
|
||||||
F: FnMut(&E, ElementSelectorFlags),
|
F: FnMut(&E, ElementSelectorFlags),
|
||||||
|
@ -279,9 +271,7 @@ impl SelectorMap<Rule> {
|
||||||
context,
|
context,
|
||||||
flags_setter,
|
flags_setter,
|
||||||
) {
|
) {
|
||||||
matching_rules.push(
|
matching_rules.push(rule.to_applicable_declaration_block(cascade_level));
|
||||||
rule.to_applicable_declaration_block(cascade_level, shadow_cascade_order),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -173,6 +173,12 @@ impl PseudoElement {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether this pseudo-element is the ::-moz-color-swatch pseudo.
|
||||||
|
#[inline]
|
||||||
|
pub fn is_color_swatch(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
/// Whether this pseudo-element is eagerly-cascaded.
|
/// Whether this pseudo-element is eagerly-cascaded.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_eager(&self) -> bool {
|
pub fn is_eager(&self) -> bool {
|
||||||
|
@ -694,6 +700,14 @@ impl ElementSnapshot for ServoElementSnapshot {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn exported_part(&self, _: &Atom) -> Option<Atom> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn imported_part(&self, _: &Atom) -> Option<Atom> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
|
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
|
||||||
self.get_attr(&ns!(), &local_name!("class"))
|
self.get_attr(&ns!(), &local_name!("class"))
|
||||||
.map_or(false, |v| {
|
.map_or(false, |v| {
|
||||||
|
|
|
@ -63,9 +63,7 @@ where
|
||||||
{
|
{
|
||||||
use crate::Atom;
|
use crate::Atom;
|
||||||
|
|
||||||
// FIXME(emilio): This should be an actual static.
|
const SPECIAL_HTML_ELEMENTS: [Atom; 16] = [
|
||||||
lazy_static! {
|
|
||||||
static ref SPECIAL_HTML_ELEMENTS: [Atom; 16] = [
|
|
||||||
atom!("br"),
|
atom!("br"),
|
||||||
atom!("wbr"),
|
atom!("wbr"),
|
||||||
atom!("meter"),
|
atom!("meter"),
|
||||||
|
@ -83,15 +81,13 @@ where
|
||||||
atom!("textarea"),
|
atom!("textarea"),
|
||||||
atom!("select"),
|
atom!("select"),
|
||||||
];
|
];
|
||||||
}
|
|
||||||
|
|
||||||
// https://drafts.csswg.org/css-display/#unbox-svg
|
// https://drafts.csswg.org/css-display/#unbox-svg
|
||||||
//
|
//
|
||||||
// There's a note about "Unknown elements", but there's not a good way to
|
// There's a note about "Unknown elements", but there's not a good way to
|
||||||
// know what that means, or to get that information from here, and no other
|
// know what that means, or to get that information from here, and no other
|
||||||
// UA implements this either.
|
// UA implements this either.
|
||||||
lazy_static! {
|
const SPECIAL_SVG_ELEMENTS: [Atom; 6] = [
|
||||||
static ref SPECIAL_SVG_ELEMENTS: [Atom; 6] = [
|
|
||||||
atom!("svg"),
|
atom!("svg"),
|
||||||
atom!("a"),
|
atom!("a"),
|
||||||
atom!("g"),
|
atom!("g"),
|
||||||
|
@ -99,7 +95,6 @@ where
|
||||||
atom!("tspan"),
|
atom!("tspan"),
|
||||||
atom!("textPath"),
|
atom!("textPath"),
|
||||||
];
|
];
|
||||||
}
|
|
||||||
|
|
||||||
// https://drafts.csswg.org/css-display/#unbox-html
|
// https://drafts.csswg.org/css-display/#unbox-html
|
||||||
if element.is_html_element() {
|
if element.is_html_element() {
|
||||||
|
|
|
@ -124,6 +124,7 @@ impl StylesheetContents {
|
||||||
url_data: UrlExtraData,
|
url_data: UrlExtraData,
|
||||||
quirks_mode: QuirksMode,
|
quirks_mode: QuirksMode,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
debug_assert!(rules.is_static());
|
||||||
Self {
|
Self {
|
||||||
rules,
|
rules,
|
||||||
origin,
|
origin,
|
||||||
|
@ -144,6 +145,9 @@ impl StylesheetContents {
|
||||||
/// Measure heap usage.
|
/// Measure heap usage.
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
pub fn size_of(&self, guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize {
|
pub fn size_of(&self, guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize {
|
||||||
|
if self.rules.is_static() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
// Measurement of other fields may be added later.
|
// Measurement of other fields may be added later.
|
||||||
self.rules.unconditional_shallow_size_of(ops) +
|
self.rules.unconditional_shallow_size_of(ops) +
|
||||||
self.rules.read_with(guard).size_of(guard, ops)
|
self.rules.read_with(guard).size_of(guard, ops)
|
||||||
|
|
|
@ -178,8 +178,7 @@ impl SupportsCondition {
|
||||||
while input.try(Parser::expect_whitespace).is_ok() {}
|
while input.try(Parser::expect_whitespace).is_ok() {}
|
||||||
let pos = input.position();
|
let pos = input.position();
|
||||||
let location = input.current_source_location();
|
let location = input.current_source_location();
|
||||||
// FIXME: remove clone() when lifetimes are non-lexical
|
match *input.next()? {
|
||||||
match input.next()?.clone() {
|
|
||||||
Token::ParenthesisBlock => {
|
Token::ParenthesisBlock => {
|
||||||
let nested =
|
let nested =
|
||||||
input.try(|input| input.parse_nested_block(parse_condition_or_declaration));
|
input.try(|input| input.parse_nested_block(parse_condition_or_declaration));
|
||||||
|
@ -187,7 +186,8 @@ impl SupportsCondition {
|
||||||
return nested;
|
return nested;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Token::Function(ident) => {
|
Token::Function(ref ident) => {
|
||||||
|
let ident = ident.clone();
|
||||||
let nested = input.try(|input| {
|
let nested = input.try(|input| {
|
||||||
input.parse_nested_block(|input| {
|
input.parse_nested_block(|input| {
|
||||||
SupportsCondition::parse_functional(&ident, input)
|
SupportsCondition::parse_functional(&ident, input)
|
||||||
|
@ -197,7 +197,7 @@ impl SupportsCondition {
|
||||||
return nested;
|
return nested;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
t => return Err(location.new_unexpected_token_error(t)),
|
ref t => return Err(location.new_unexpected_token_error(t.clone())),
|
||||||
}
|
}
|
||||||
input.parse_nested_block(consume_any_value)?;
|
input.parse_nested_block(consume_any_value)?;
|
||||||
Ok(SupportsCondition::FutureSyntax(
|
Ok(SupportsCondition::FutureSyntax(
|
||||||
|
|
|
@ -18,7 +18,7 @@ use crate::properties::{self, CascadeMode, ComputedValues};
|
||||||
use crate::properties::{AnimationRules, PropertyDeclarationBlock};
|
use crate::properties::{AnimationRules, PropertyDeclarationBlock};
|
||||||
use crate::rule_cache::{RuleCache, RuleCacheConditions};
|
use crate::rule_cache::{RuleCache, RuleCacheConditions};
|
||||||
use crate::rule_collector::{containing_shadow_ignoring_svg_use, RuleCollector};
|
use crate::rule_collector::{containing_shadow_ignoring_svg_use, RuleCollector};
|
||||||
use crate::rule_tree::{CascadeLevel, RuleTree, ShadowCascadeOrder, StrongRuleNode, StyleSource};
|
use crate::rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource};
|
||||||
use crate::selector_map::{PrecomputedHashMap, PrecomputedHashSet, SelectorMap, SelectorMapEntry};
|
use crate::selector_map::{PrecomputedHashMap, PrecomputedHashSet, SelectorMap, SelectorMapEntry};
|
||||||
use crate::selector_parser::{PerPseudoElementMap, PseudoElement, SelectorImpl, SnapshotMap};
|
use crate::selector_parser::{PerPseudoElementMap, PseudoElement, SelectorImpl, SnapshotMap};
|
||||||
use crate::shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
|
use crate::shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
|
||||||
|
@ -1322,16 +1322,17 @@ impl Stylist {
|
||||||
let iter_declarations = || {
|
let iter_declarations = || {
|
||||||
block
|
block
|
||||||
.declaration_importance_iter()
|
.declaration_importance_iter()
|
||||||
.map(|(declaration, importance)| {
|
.map(|(declaration, _)| (declaration, Origin::Author))
|
||||||
debug_assert!(!importance.important());
|
|
||||||
(declaration, CascadeLevel::StyleAttributeNormal)
|
|
||||||
})
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let metrics = get_metrics_provider_for_product();
|
let metrics = get_metrics_provider_for_product();
|
||||||
|
|
||||||
// We don't bother inserting these declarations in the rule tree, since
|
// We don't bother inserting these declarations in the rule tree, since
|
||||||
// it'd be quite useless and slow.
|
// it'd be quite useless and slow.
|
||||||
|
//
|
||||||
|
// TODO(emilio): Now that we fixed bug 1493420, we should consider
|
||||||
|
// reversing this as it shouldn't be slow anymore, and should avoid
|
||||||
|
// generating two instantiations of apply_declarations.
|
||||||
properties::apply_declarations::<E, _, _>(
|
properties::apply_declarations::<E, _, _>(
|
||||||
&self.device,
|
&self.device,
|
||||||
/* pseudo = */ None,
|
/* pseudo = */ None,
|
||||||
|
@ -1987,7 +1988,6 @@ impl CascadeData {
|
||||||
self.rules_source_order,
|
self.rules_source_order,
|
||||||
CascadeLevel::UANormal,
|
CascadeLevel::UANormal,
|
||||||
selector.specificity(),
|
selector.specificity(),
|
||||||
0,
|
|
||||||
));
|
));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -2323,16 +2323,9 @@ impl Rule {
|
||||||
pub fn to_applicable_declaration_block(
|
pub fn to_applicable_declaration_block(
|
||||||
&self,
|
&self,
|
||||||
level: CascadeLevel,
|
level: CascadeLevel,
|
||||||
shadow_cascade_order: ShadowCascadeOrder,
|
|
||||||
) -> ApplicableDeclarationBlock {
|
) -> ApplicableDeclarationBlock {
|
||||||
let source = StyleSource::from_rule(self.style_rule.clone());
|
let source = StyleSource::from_rule(self.style_rule.clone());
|
||||||
ApplicableDeclarationBlock::new(
|
ApplicableDeclarationBlock::new(source, self.source_order, level, self.specificity())
|
||||||
source,
|
|
||||||
self.source_order,
|
|
||||||
level,
|
|
||||||
self.specificity(),
|
|
||||||
shadow_cascade_order,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new Rule.
|
/// Creates a new Rule.
|
||||||
|
|
|
@ -1249,7 +1249,11 @@ impl Animate for ComputedRotate {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(&Rotate::None, &Rotate::None) => Ok(Rotate::None),
|
(&Rotate::None, &Rotate::None) => Ok(Rotate::None),
|
||||||
(&Rotate::Rotate3D(fx, fy, fz, fa), &Rotate::None) => {
|
(&Rotate::Rotate3D(fx, fy, fz, fa), &Rotate::None) => {
|
||||||
// No need to normalize `none`, so animate angle directly.
|
// We always normalize direction vector for rotate3d() first, so we should also
|
||||||
|
// apply the same rule for rotate property. In other words, we promote none into
|
||||||
|
// a 3d rotate, and normalize both direction vector first, and then do
|
||||||
|
// interpolation.
|
||||||
|
let (fx, fy, fz, fa) = transform::get_normalized_vector_and_angle(fx, fy, fz, fa);
|
||||||
Ok(Rotate::Rotate3D(
|
Ok(Rotate::Rotate3D(
|
||||||
fx,
|
fx,
|
||||||
fy,
|
fy,
|
||||||
|
@ -1258,7 +1262,8 @@ impl Animate for ComputedRotate {
|
||||||
))
|
))
|
||||||
},
|
},
|
||||||
(&Rotate::None, &Rotate::Rotate3D(tx, ty, tz, ta)) => {
|
(&Rotate::None, &Rotate::Rotate3D(tx, ty, tz, ta)) => {
|
||||||
// No need to normalize `none`, so animate angle directly.
|
// Normalize direction vector first.
|
||||||
|
let (tx, ty, tz, ta) = transform::get_normalized_vector_and_angle(tx, ty, tz, ta);
|
||||||
Ok(Rotate::Rotate3D(
|
Ok(Rotate::Rotate3D(
|
||||||
tx,
|
tx,
|
||||||
ty,
|
ty,
|
||||||
|
@ -1368,8 +1373,7 @@ impl ComputedTranslate {
|
||||||
LengthPercentage::zero(),
|
LengthPercentage::zero(),
|
||||||
Length::zero(),
|
Length::zero(),
|
||||||
),
|
),
|
||||||
Translate::Translate3D(tx, ty, tz) => (tx, ty, tz),
|
Translate::Translate(tx, ty, tz) => (tx, ty, tz),
|
||||||
Translate::Translate(tx, ty) => (tx, ty, Length::zero()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1379,19 +1383,12 @@ impl Animate for ComputedTranslate {
|
||||||
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
|
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(&Translate::None, &Translate::None) => Ok(Translate::None),
|
(&Translate::None, &Translate::None) => Ok(Translate::None),
|
||||||
(&Translate::Translate3D(_, ..), _) | (_, &Translate::Translate3D(_, ..)) => {
|
|
||||||
let (from, to) = (self.resolve(), other.resolve());
|
|
||||||
Ok(Translate::Translate3D(
|
|
||||||
from.0.animate(&to.0, procedure)?,
|
|
||||||
from.1.animate(&to.1, procedure)?,
|
|
||||||
from.2.animate(&to.2, procedure)?,
|
|
||||||
))
|
|
||||||
},
|
|
||||||
(&Translate::Translate(_, ..), _) | (_, &Translate::Translate(_, ..)) => {
|
(&Translate::Translate(_, ..), _) | (_, &Translate::Translate(_, ..)) => {
|
||||||
let (from, to) = (self.resolve(), other.resolve());
|
let (from, to) = (self.resolve(), other.resolve());
|
||||||
Ok(Translate::Translate(
|
Ok(Translate::Translate(
|
||||||
from.0.animate(&to.0, procedure)?,
|
from.0.animate(&to.0, procedure)?,
|
||||||
from.1.animate(&to.1, procedure)?,
|
from.1.animate(&to.1, procedure)?,
|
||||||
|
from.2.animate(&to.2, procedure)?,
|
||||||
))
|
))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -1417,8 +1414,7 @@ impl ComputedScale {
|
||||||
// Unspecified scales default to 1
|
// Unspecified scales default to 1
|
||||||
match *self {
|
match *self {
|
||||||
Scale::None => (1.0, 1.0, 1.0),
|
Scale::None => (1.0, 1.0, 1.0),
|
||||||
Scale::Scale3D(sx, sy, sz) => (sx, sy, sz),
|
Scale::Scale(sx, sy, sz) => (sx, sy, sz),
|
||||||
Scale::Scale(sx, sy) => (sx, sy, 1.),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1428,7 +1424,7 @@ impl Animate for ComputedScale {
|
||||||
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
|
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(&Scale::None, &Scale::None) => Ok(Scale::None),
|
(&Scale::None, &Scale::None) => Ok(Scale::None),
|
||||||
(&Scale::Scale3D(_, ..), _) | (_, &Scale::Scale3D(_, ..)) => {
|
(&Scale::Scale(_, ..), _) | (_, &Scale::Scale(_, ..)) => {
|
||||||
let (from, to) = (self.resolve(), other.resolve());
|
let (from, to) = (self.resolve(), other.resolve());
|
||||||
// For transform lists, we add by appending to the list of
|
// For transform lists, we add by appending to the list of
|
||||||
// transform functions. However, ComputedScale cannot be
|
// transform functions. However, ComputedScale cannot be
|
||||||
|
@ -1436,24 +1432,12 @@ impl Animate for ComputedScale {
|
||||||
// result here.
|
// result here.
|
||||||
if procedure == Procedure::Add {
|
if procedure == Procedure::Add {
|
||||||
// scale(x1,y1,z1)*scale(x2,y2,z2) = scale(x1*x2, y1*y2, z1*z2)
|
// scale(x1,y1,z1)*scale(x2,y2,z2) = scale(x1*x2, y1*y2, z1*z2)
|
||||||
return Ok(Scale::Scale3D(from.0 * to.0, from.1 * to.1, from.2 * to.2));
|
return Ok(Scale::Scale(from.0 * to.0, from.1 * to.1, from.2 * to.2));
|
||||||
}
|
|
||||||
Ok(Scale::Scale3D(
|
|
||||||
animate_multiplicative_factor(from.0, to.0, procedure)?,
|
|
||||||
animate_multiplicative_factor(from.1, to.1, procedure)?,
|
|
||||||
animate_multiplicative_factor(from.2, to.2, procedure)?,
|
|
||||||
))
|
|
||||||
},
|
|
||||||
(&Scale::Scale(_, ..), _) | (_, &Scale::Scale(_, ..)) => {
|
|
||||||
let (from, to) = (self.resolve(), other.resolve());
|
|
||||||
// As with Scale3D, addition needs special handling.
|
|
||||||
if procedure == Procedure::Add {
|
|
||||||
// scale(x1,y1)*scale(x2,y2) = scale(x1*x2, y1*y2)
|
|
||||||
return Ok(Scale::Scale(from.0 * to.0, from.1 * to.1));
|
|
||||||
}
|
}
|
||||||
Ok(Scale::Scale(
|
Ok(Scale::Scale(
|
||||||
animate_multiplicative_factor(from.0, to.0, procedure)?,
|
animate_multiplicative_factor(from.0, to.0, procedure)?,
|
||||||
animate_multiplicative_factor(from.1, to.1, procedure)?,
|
animate_multiplicative_factor(from.1, to.1, procedure)?,
|
||||||
|
animate_multiplicative_factor(from.2, to.2, procedure)?,
|
||||||
))
|
))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ pub use self::GenericGridLine as GridLine;
|
||||||
|
|
||||||
impl<Integer> GridLine<Integer>
|
impl<Integer> GridLine<Integer>
|
||||||
where
|
where
|
||||||
Integer: Zero,
|
Integer: PartialEq + Zero,
|
||||||
{
|
{
|
||||||
/// The `auto` value.
|
/// The `auto` value.
|
||||||
pub fn auto() -> Self {
|
pub fn auto() -> Self {
|
||||||
|
@ -73,11 +73,27 @@ where
|
||||||
pub fn is_auto(&self) -> bool {
|
pub fn is_auto(&self) -> bool {
|
||||||
self.ident == atom!("") && self.line_num.is_zero() && !self.is_span
|
self.ident == atom!("") && self.line_num.is_zero() && !self.is_span
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check whether this `<grid-line>` represents a `<custom-ident>` value.
|
||||||
|
pub fn is_ident_only(&self) -> bool {
|
||||||
|
self.ident != atom!("") && self.line_num.is_zero() && !self.is_span
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if `self` makes `other` omittable according to the rules at:
|
||||||
|
/// https://drafts.csswg.org/css-grid/#propdef-grid-column
|
||||||
|
/// https://drafts.csswg.org/css-grid/#propdef-grid-area
|
||||||
|
pub fn can_omit(&self, other: &Self) -> bool {
|
||||||
|
if self.is_ident_only() {
|
||||||
|
self == other
|
||||||
|
} else {
|
||||||
|
other.is_auto()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Integer> ToCss for GridLine<Integer>
|
impl<Integer> ToCss for GridLine<Integer>
|
||||||
where
|
where
|
||||||
Integer: ToCss + Zero,
|
Integer: ToCss + PartialEq + Zero,
|
||||||
{
|
{
|
||||||
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||||
where
|
where
|
||||||
|
@ -261,6 +277,19 @@ pub enum GenericTrackSize<L> {
|
||||||
pub use self::GenericTrackSize as TrackSize;
|
pub use self::GenericTrackSize as TrackSize;
|
||||||
|
|
||||||
impl<L> TrackSize<L> {
|
impl<L> TrackSize<L> {
|
||||||
|
/// The initial value.
|
||||||
|
const INITIAL_VALUE: Self = TrackSize::Breadth(TrackBreadth::Auto);
|
||||||
|
|
||||||
|
/// Returns the initial value.
|
||||||
|
pub const fn initial_value() -> Self {
|
||||||
|
Self::INITIAL_VALUE
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if `self` is the initial value.
|
||||||
|
pub fn is_initial(&self) -> bool {
|
||||||
|
matches!(*self, TrackSize::Breadth(TrackBreadth::Auto)) // FIXME: can't use Self::INITIAL_VALUE here yet: https://github.com/rust-lang/rust/issues/66585
|
||||||
|
}
|
||||||
|
|
||||||
/// Check whether this is a `<fixed-size>`
|
/// Check whether this is a `<fixed-size>`
|
||||||
///
|
///
|
||||||
/// <https://drafts.csswg.org/css-grid/#typedef-fixed-size>
|
/// <https://drafts.csswg.org/css-grid/#typedef-fixed-size>
|
||||||
|
@ -286,17 +315,9 @@ impl<L> TrackSize<L> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<L: PartialEq> TrackSize<L> {
|
|
||||||
/// Return true if it is `auto`.
|
|
||||||
#[inline]
|
|
||||||
pub fn is_auto(&self) -> bool {
|
|
||||||
*self == TrackSize::Breadth(TrackBreadth::Auto)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<L> Default for TrackSize<L> {
|
impl<L> Default for TrackSize<L> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
TrackSize::Breadth(TrackBreadth::Auto)
|
Self::initial_value()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -513,9 +534,27 @@ pub enum GenericTrackListValue<LengthPercentage, Integer> {
|
||||||
pub use self::GenericTrackListValue as TrackListValue;
|
pub use self::GenericTrackListValue as TrackListValue;
|
||||||
|
|
||||||
impl<L, I> TrackListValue<L, I> {
|
impl<L, I> TrackListValue<L, I> {
|
||||||
|
// FIXME: can't use TrackSize::initial_value() here b/c rustc error "is not yet stable as a const fn"
|
||||||
|
const INITIAL_VALUE: Self = TrackListValue::TrackSize(TrackSize::Breadth(TrackBreadth::Auto));
|
||||||
|
|
||||||
fn is_repeat(&self) -> bool {
|
fn is_repeat(&self) -> bool {
|
||||||
matches!(*self, TrackListValue::TrackRepeat(..))
|
matches!(*self, TrackListValue::TrackRepeat(..))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if `self` is the initial value.
|
||||||
|
pub fn is_initial(&self) -> bool {
|
||||||
|
matches!(
|
||||||
|
*self,
|
||||||
|
TrackListValue::TrackSize(TrackSize::Breadth(TrackBreadth::Auto))
|
||||||
|
) // FIXME: can't use Self::INITIAL_VALUE here yet: https://github.com/rust-lang/rust/issues/66585
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<L, I> Default for TrackListValue<L, I> {
|
||||||
|
#[inline]
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::INITIAL_VALUE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A grid `<track-list>` type.
|
/// A grid `<track-list>` type.
|
||||||
|
@ -755,6 +794,9 @@ pub enum GenericGridTemplateComponent<L, I> {
|
||||||
pub use self::GenericGridTemplateComponent as GridTemplateComponent;
|
pub use self::GenericGridTemplateComponent as GridTemplateComponent;
|
||||||
|
|
||||||
impl<L, I> GridTemplateComponent<L, I> {
|
impl<L, I> GridTemplateComponent<L, I> {
|
||||||
|
/// The initial value.
|
||||||
|
const INITIAL_VALUE: Self = Self::None;
|
||||||
|
|
||||||
/// Returns length of the <track-list>s <track-size>
|
/// Returns length of the <track-list>s <track-size>
|
||||||
pub fn track_list_len(&self) -> usize {
|
pub fn track_list_len(&self) -> usize {
|
||||||
match *self {
|
match *self {
|
||||||
|
@ -762,4 +804,16 @@ impl<L, I> GridTemplateComponent<L, I> {
|
||||||
_ => 0,
|
_ => 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if `self` is the initial value.
|
||||||
|
pub fn is_initial(&self) -> bool {
|
||||||
|
matches!(*self, Self::None) // FIXME: can't use Self::INITIAL_VALUE here yet: https://github.com/rust-lang/rust/issues/66585
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<L, I> Default for GridTemplateComponent<L, I> {
|
||||||
|
#[inline]
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::INITIAL_VALUE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -700,40 +700,52 @@ where
|
||||||
pub enum GenericScale<Number> {
|
pub enum GenericScale<Number> {
|
||||||
/// 'none'
|
/// 'none'
|
||||||
None,
|
None,
|
||||||
/// '<number>{1,2}'
|
/// '<number>{1,3}'
|
||||||
Scale(Number, Number),
|
Scale(Number, Number, Number),
|
||||||
/// '<number>{3}'
|
|
||||||
Scale3D(Number, Number, Number),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use self::GenericScale as Scale;
|
pub use self::GenericScale as Scale;
|
||||||
|
|
||||||
impl<Number: ToCss + PartialEq> ToCss for Scale<Number> {
|
impl<Number> ToCss for Scale<Number>
|
||||||
|
where
|
||||||
|
Number: ToCss + PartialEq + Copy,
|
||||||
|
f32: From<Number>,
|
||||||
|
{
|
||||||
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||||
where
|
where
|
||||||
W: fmt::Write,
|
W: fmt::Write,
|
||||||
|
f32: From<Number>,
|
||||||
{
|
{
|
||||||
match *self {
|
match *self {
|
||||||
Scale::None => dest.write_str("none"),
|
Scale::None => dest.write_str("none"),
|
||||||
Scale::Scale(ref x, ref y) => {
|
Scale::Scale(ref x, ref y, ref z) => {
|
||||||
x.to_css(dest)?;
|
x.to_css(dest)?;
|
||||||
if x != y {
|
|
||||||
|
let is_3d = f32::from(*z) != 1.0;
|
||||||
|
if is_3d || x != y {
|
||||||
dest.write_char(' ')?;
|
dest.write_char(' ')?;
|
||||||
y.to_css(dest)?;
|
y.to_css(dest)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if is_3d {
|
||||||
|
dest.write_char(' ')?;
|
||||||
|
z.to_css(dest)?;
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
Scale::Scale3D(ref x, ref y, ref z) => {
|
|
||||||
x.to_css(dest)?;
|
|
||||||
dest.write_char(' ')?;
|
|
||||||
y.to_css(dest)?;
|
|
||||||
dest.write_char(' ')?;
|
|
||||||
z.to_css(dest)
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn y_axis_and_z_axis_are_zero<LengthPercentage: Zero, Length: Zero>(
|
||||||
|
_: &LengthPercentage,
|
||||||
|
y: &LengthPercentage,
|
||||||
|
z: &Length,
|
||||||
|
) -> bool {
|
||||||
|
y.is_zero() && z.is_zero()
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
Clone,
|
Clone,
|
||||||
Debug,
|
Debug,
|
||||||
|
@ -755,25 +767,24 @@ impl<Number: ToCss + PartialEq> ToCss for Scale<Number> {
|
||||||
/// or two values (per usual, if the second value is 0px, the default, it must
|
/// or two values (per usual, if the second value is 0px, the default, it must
|
||||||
/// be omitted when serializing).
|
/// be omitted when serializing).
|
||||||
///
|
///
|
||||||
/// If a 3d translation is specified, all three values must be serialized.
|
/// If a 3d translation is specified and the value can be expressed as 2d, we treat as 2d and
|
||||||
///
|
/// serialize accoringly. Otherwise, we serialize all three values.
|
||||||
/// We don't omit the 3rd component even if it is 0px for now, and the
|
/// https://github.com/w3c/csswg-drafts/issues/3305
|
||||||
/// related spec issue is https://github.com/w3c/csswg-drafts/issues/3305
|
|
||||||
///
|
///
|
||||||
/// <https://drafts.csswg.org/css-transforms-2/#individual-transforms>
|
/// <https://drafts.csswg.org/css-transforms-2/#individual-transforms>
|
||||||
pub enum GenericTranslate<LengthPercentage, Length>
|
pub enum GenericTranslate<LengthPercentage, Length>
|
||||||
where
|
where
|
||||||
LengthPercentage: Zero,
|
LengthPercentage: Zero,
|
||||||
|
Length: Zero,
|
||||||
{
|
{
|
||||||
/// 'none'
|
/// 'none'
|
||||||
None,
|
None,
|
||||||
/// '<length-percentage>' or '<length-percentage> <length-percentage>'
|
/// <length-percentage> [ <length-percentage> <length>? ]?
|
||||||
Translate(
|
Translate(
|
||||||
LengthPercentage,
|
LengthPercentage,
|
||||||
#[css(skip_if = "Zero::is_zero")] LengthPercentage,
|
#[css(contextual_skip_if = "y_axis_and_z_axis_are_zero")] LengthPercentage,
|
||||||
|
#[css(skip_if = "Zero::is_zero")] Length,
|
||||||
),
|
),
|
||||||
/// '<length-percentage> <length-percentage> <length>'
|
|
||||||
Translate3D(LengthPercentage, LengthPercentage, Length),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use self::GenericTranslate as Translate;
|
pub use self::GenericTranslate as Translate;
|
||||||
|
|
|
@ -208,24 +208,34 @@ impl Angle {
|
||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
allow_unitless_zero: AllowUnitlessZeroAngle,
|
allow_unitless_zero: AllowUnitlessZeroAngle,
|
||||||
) -> Result<Self, ParseError<'i>> {
|
) -> Result<Self, ParseError<'i>> {
|
||||||
// FIXME: remove clone() when lifetimes are non-lexical
|
let t = input.next()?;
|
||||||
let token = input.next()?.clone();
|
match *t {
|
||||||
match token {
|
|
||||||
Token::Dimension {
|
Token::Dimension {
|
||||||
value, ref unit, ..
|
value, ref unit, ..
|
||||||
} => {
|
} => {
|
||||||
Angle::parse_dimension(value, unit, /* from_calc = */ false)
|
match Angle::parse_dimension(value, unit, /* from_calc = */ false) {
|
||||||
|
Ok(angle) => Ok(angle),
|
||||||
|
Err(()) => {
|
||||||
|
let t = t.clone();
|
||||||
|
Err(input.new_unexpected_token_error(t))
|
||||||
|
},
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Token::Number { value, .. } if value == 0. => match allow_unitless_zero {
|
Token::Number { value, .. } if value == 0. => match allow_unitless_zero {
|
||||||
AllowUnitlessZeroAngle::Yes => Ok(Angle::zero()),
|
AllowUnitlessZeroAngle::Yes => Ok(Angle::zero()),
|
||||||
AllowUnitlessZeroAngle::No => Err(()),
|
AllowUnitlessZeroAngle::No => {
|
||||||
|
let t = t.clone();
|
||||||
|
Err(input.new_unexpected_token_error(t))
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
|
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
|
||||||
return input.parse_nested_block(|i| CalcNode::parse_angle(context, i));
|
return input.parse_nested_block(|i| CalcNode::parse_angle(context, i));
|
||||||
},
|
},
|
||||||
_ => Err(()),
|
ref t => {
|
||||||
|
let t = t.clone();
|
||||||
|
Err(input.new_unexpected_token_error(t))
|
||||||
|
},
|
||||||
}
|
}
|
||||||
.map_err(|()| input.new_unexpected_token_error(token.clone()))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -109,8 +109,6 @@ pub enum DisplayInside {
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
MozGridLine,
|
MozGridLine,
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
MozStack,
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
MozDeck,
|
MozDeck,
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
MozGroupbox,
|
MozGroupbox,
|
||||||
|
@ -243,8 +241,6 @@ impl Display {
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
pub const MozGridLine: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozGridLine);
|
pub const MozGridLine: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozGridLine);
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
pub const MozStack: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozStack);
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
pub const MozDeck: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozDeck);
|
pub const MozDeck: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozDeck);
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
pub const MozGroupbox: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozGroupbox);
|
pub const MozGroupbox: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozGroupbox);
|
||||||
|
@ -669,8 +665,6 @@ impl Parse for Display {
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
"-moz-grid-line" if moz_display_values_enabled(context) => Display::MozGridLine,
|
"-moz-grid-line" if moz_display_values_enabled(context) => Display::MozGridLine,
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
"-moz-stack" if moz_display_values_enabled(context) => Display::MozStack,
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
"-moz-deck" if moz_display_values_enabled(context) => Display::MozDeck,
|
"-moz-deck" if moz_display_values_enabled(context) => Display::MozDeck,
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
"-moz-groupbox" if moz_display_values_enabled(context) => Display::MozGroupbox,
|
"-moz-groupbox" if moz_display_values_enabled(context) => Display::MozGroupbox,
|
||||||
|
@ -1157,7 +1151,9 @@ fn change_bits_for_longhand(longhand: LonghandId) -> WillChangeBits {
|
||||||
LonghandId::Opacity => WillChangeBits::OPACITY,
|
LonghandId::Opacity => WillChangeBits::OPACITY,
|
||||||
LonghandId::Transform => WillChangeBits::TRANSFORM,
|
LonghandId::Transform => WillChangeBits::TRANSFORM,
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
LonghandId::Translate | LonghandId::Rotate | LonghandId::Scale => WillChangeBits::TRANSFORM,
|
LonghandId::Translate | LonghandId::Rotate | LonghandId::Scale | LonghandId::OffsetPath => {
|
||||||
|
WillChangeBits::TRANSFORM
|
||||||
|
},
|
||||||
_ => WillChangeBits::empty(),
|
_ => WillChangeBits::empty(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -163,9 +163,8 @@ impl CalcNode {
|
||||||
expected_unit: CalcUnit,
|
expected_unit: CalcUnit,
|
||||||
) -> Result<Self, ParseError<'i>> {
|
) -> Result<Self, ParseError<'i>> {
|
||||||
let location = input.current_source_location();
|
let location = input.current_source_location();
|
||||||
// FIXME: remove early returns when lifetimes are non-lexical
|
|
||||||
match (input.next()?, expected_unit) {
|
match (input.next()?, expected_unit) {
|
||||||
(&Token::Number { value, .. }, _) => return Ok(CalcNode::Number(value)),
|
(&Token::Number { value, .. }, _) => Ok(CalcNode::Number(value)),
|
||||||
(
|
(
|
||||||
&Token::Dimension {
|
&Token::Dimension {
|
||||||
value, ref unit, ..
|
value, ref unit, ..
|
||||||
|
@ -177,24 +176,18 @@ impl CalcNode {
|
||||||
value, ref unit, ..
|
value, ref unit, ..
|
||||||
},
|
},
|
||||||
CalcUnit::LengthPercentage,
|
CalcUnit::LengthPercentage,
|
||||||
) => {
|
) => NoCalcLength::parse_dimension(context, value, unit)
|
||||||
return NoCalcLength::parse_dimension(context, value, unit)
|
|
||||||
.map(CalcNode::Length)
|
.map(CalcNode::Length)
|
||||||
.map_err(|()| {
|
.map_err(|()| location.new_custom_error(StyleParseErrorKind::UnspecifiedError)),
|
||||||
location.new_custom_error(StyleParseErrorKind::UnspecifiedError)
|
|
||||||
});
|
|
||||||
},
|
|
||||||
(
|
(
|
||||||
&Token::Dimension {
|
&Token::Dimension {
|
||||||
value, ref unit, ..
|
value, ref unit, ..
|
||||||
},
|
},
|
||||||
CalcUnit::Angle,
|
CalcUnit::Angle,
|
||||||
) => {
|
) => {
|
||||||
return Angle::parse_dimension(value, unit, /* from_calc = */ true)
|
Angle::parse_dimension(value, unit, /* from_calc = */ true)
|
||||||
.map(CalcNode::Angle)
|
.map(CalcNode::Angle)
|
||||||
.map_err(|()| {
|
.map_err(|()| location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
|
||||||
location.new_custom_error(StyleParseErrorKind::UnspecifiedError)
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
(
|
(
|
||||||
&Token::Dimension {
|
&Token::Dimension {
|
||||||
|
@ -202,21 +195,22 @@ impl CalcNode {
|
||||||
},
|
},
|
||||||
CalcUnit::Time,
|
CalcUnit::Time,
|
||||||
) => {
|
) => {
|
||||||
return Time::parse_dimension(value, unit, /* from_calc = */ true)
|
Time::parse_dimension(value, unit, /* from_calc = */ true)
|
||||||
.map(CalcNode::Time)
|
.map(CalcNode::Time)
|
||||||
.map_err(|()| {
|
.map_err(|()| location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
|
||||||
location.new_custom_error(StyleParseErrorKind::UnspecifiedError)
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
(&Token::Percentage { unit_value, .. }, CalcUnit::LengthPercentage) |
|
(&Token::Percentage { unit_value, .. }, CalcUnit::LengthPercentage) |
|
||||||
(&Token::Percentage { unit_value, .. }, CalcUnit::Percentage) => {
|
(&Token::Percentage { unit_value, .. }, CalcUnit::Percentage) => {
|
||||||
return Ok(CalcNode::Percentage(unit_value));
|
Ok(CalcNode::Percentage(unit_value))
|
||||||
},
|
},
|
||||||
(&Token::ParenthesisBlock, _) => {},
|
(&Token::ParenthesisBlock, _) => {
|
||||||
(&Token::Function(ref name), _) if name.eq_ignore_ascii_case("calc") => {},
|
|
||||||
(t, _) => return Err(location.new_unexpected_token_error(t.clone())),
|
|
||||||
}
|
|
||||||
input.parse_nested_block(|i| CalcNode::parse(context, i, expected_unit))
|
input.parse_nested_block(|i| CalcNode::parse(context, i, expected_unit))
|
||||||
|
},
|
||||||
|
(&Token::Function(ref name), _) if name.eq_ignore_ascii_case("calc") => {
|
||||||
|
input.parse_nested_block(|i| CalcNode::parse(context, i, expected_unit))
|
||||||
|
},
|
||||||
|
(t, _) => Err(location.new_unexpected_token_error(t.clone())),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a top-level `calc` expression, with all nested sub-expressions.
|
/// Parse a top-level `calc` expression, with all nested sub-expressions.
|
||||||
|
@ -236,8 +230,7 @@ impl CalcNode {
|
||||||
if input.is_exhausted() {
|
if input.is_exhausted() {
|
||||||
break; // allow trailing whitespace
|
break; // allow trailing whitespace
|
||||||
}
|
}
|
||||||
// FIXME: remove clone() when lifetimes are non-lexical
|
match *input.next()? {
|
||||||
match input.next()?.clone() {
|
|
||||||
Token::Delim('+') => {
|
Token::Delim('+') => {
|
||||||
let rhs = Self::parse_product(context, input, expected_unit)?;
|
let rhs = Self::parse_product(context, input, expected_unit)?;
|
||||||
let new_root = CalcNode::Sum(Box::new(root), Box::new(rhs));
|
let new_root = CalcNode::Sum(Box::new(root), Box::new(rhs));
|
||||||
|
@ -248,7 +241,10 @@ impl CalcNode {
|
||||||
let new_root = CalcNode::Sub(Box::new(root), Box::new(rhs));
|
let new_root = CalcNode::Sub(Box::new(root), Box::new(rhs));
|
||||||
root = new_root;
|
root = new_root;
|
||||||
},
|
},
|
||||||
t => return Err(input.new_unexpected_token_error(t)),
|
ref t => {
|
||||||
|
let t = t.clone();
|
||||||
|
return Err(input.new_unexpected_token_error(t));
|
||||||
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
|
|
|
@ -36,9 +36,6 @@ pub enum Color {
|
||||||
/// A system color
|
/// A system color
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
System(SystemColor),
|
System(SystemColor),
|
||||||
/// A special color keyword value used in Gecko
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
Special(gecko::SpecialColorKeyword),
|
|
||||||
/// Quirksmode-only rule for inheriting color from the body
|
/// Quirksmode-only rule for inheriting color from the body
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
InheritFromBodyQuirk,
|
InheritFromBodyQuirk,
|
||||||
|
@ -143,6 +140,8 @@ pub enum SystemColor {
|
||||||
Windowframe,
|
Windowframe,
|
||||||
Windowtext,
|
Windowtext,
|
||||||
MozButtondefault,
|
MozButtondefault,
|
||||||
|
MozDefaultColor,
|
||||||
|
MozDefaultBackgroundColor,
|
||||||
MozDialog,
|
MozDialog,
|
||||||
MozDialogtext,
|
MozDialogtext,
|
||||||
/// Used to highlight valid regions to drop something onto.
|
/// Used to highlight valid regions to drop something onto.
|
||||||
|
@ -231,6 +230,10 @@ pub enum SystemColor {
|
||||||
/// colors.
|
/// colors.
|
||||||
MozNativehyperlinktext,
|
MozNativehyperlinktext,
|
||||||
|
|
||||||
|
MozHyperlinktext,
|
||||||
|
MozActivehyperlinktext,
|
||||||
|
MozVisitedhyperlinktext,
|
||||||
|
|
||||||
/// Combobox widgets
|
/// Combobox widgets
|
||||||
MozComboboxtext,
|
MozComboboxtext,
|
||||||
MozCombobox,
|
MozCombobox,
|
||||||
|
@ -246,24 +249,20 @@ impl SystemColor {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn compute(&self, cx: &Context) -> ComputedColor {
|
fn compute(&self, cx: &Context) -> ComputedColor {
|
||||||
use crate::gecko_bindings::bindings;
|
use crate::gecko_bindings::bindings;
|
||||||
unsafe {
|
|
||||||
convert_nscolor_to_computedcolor(bindings::Gecko_GetLookAndFeelSystemColor(
|
|
||||||
*self as i32,
|
|
||||||
cx.device().document(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
let prefs = cx.device().pref_sheet_prefs();
|
||||||
mod gecko {
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, ToCss, ToShmem)]
|
convert_nscolor_to_computedcolor(match *self {
|
||||||
pub enum SpecialColorKeyword {
|
SystemColor::MozDefaultColor => prefs.mDefaultColor,
|
||||||
MozDefaultColor,
|
SystemColor::MozDefaultBackgroundColor => prefs.mDefaultBackgroundColor,
|
||||||
MozDefaultBackgroundColor,
|
SystemColor::MozHyperlinktext => prefs.mLinkColor,
|
||||||
MozHyperlinktext,
|
SystemColor::MozActivehyperlinktext => prefs.mActiveLinkColor,
|
||||||
MozActivehyperlinktext,
|
SystemColor::MozVisitedhyperlinktext => prefs.mVisitedLinkColor,
|
||||||
MozVisitedhyperlinktext,
|
|
||||||
|
_ => unsafe {
|
||||||
|
bindings::Gecko_GetLookAndFeelSystemColor(*self as i32, cx.device().document())
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -364,10 +363,6 @@ impl Parse for Color {
|
||||||
if let Ok(system) = input.try(|i| SystemColor::parse(context, i)) {
|
if let Ok(system) = input.try(|i| SystemColor::parse(context, i)) {
|
||||||
return Ok(Color::System(system));
|
return Ok(Color::System(system));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(c) = input.try(gecko::SpecialColorKeyword::parse) {
|
|
||||||
return Ok(Color::Special(c));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match e.kind {
|
match e.kind {
|
||||||
|
@ -401,8 +396,6 @@ impl ToCss for Color {
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
Color::System(system) => system.to_css(dest),
|
Color::System(system) => system.to_css(dest),
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
Color::Special(special) => special.to_css(dest),
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
Color::InheritFromBodyQuirk => Ok(()),
|
Color::InheritFromBodyQuirk => Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -553,18 +546,6 @@ impl Color {
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
Color::System(system) => system.compute(_context?),
|
Color::System(system) => system.compute(_context?),
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
Color::Special(special) => {
|
|
||||||
use self::gecko::SpecialColorKeyword as Keyword;
|
|
||||||
let prefs = _context?.device().pref_sheet_prefs();
|
|
||||||
convert_nscolor_to_computedcolor(match special {
|
|
||||||
Keyword::MozDefaultColor => prefs.mDefaultColor,
|
|
||||||
Keyword::MozDefaultBackgroundColor => prefs.mDefaultBackgroundColor,
|
|
||||||
Keyword::MozHyperlinktext => prefs.mLinkColor,
|
|
||||||
Keyword::MozActivehyperlinktext => prefs.mActiveLinkColor,
|
|
||||||
Keyword::MozVisitedhyperlinktext => prefs.mVisitedLinkColor,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
Color::InheritFromBodyQuirk => {
|
Color::InheritFromBodyQuirk => {
|
||||||
ComputedColor::rgba(_context?.device().body_text_color())
|
ComputedColor::rgba(_context?.device().body_text_color())
|
||||||
},
|
},
|
||||||
|
|
|
@ -63,7 +63,10 @@ fn parse_counters<'i, 't>(
|
||||||
let location = input.current_source_location();
|
let location = input.current_source_location();
|
||||||
let name = match input.next() {
|
let name = match input.next() {
|
||||||
Ok(&Token::Ident(ref ident)) => CustomIdent::from_ident(location, ident, &["none"])?,
|
Ok(&Token::Ident(ref ident)) => CustomIdent::from_ident(location, ident, &["none"])?,
|
||||||
Ok(t) => return Err(location.new_unexpected_token_error(t.clone())),
|
Ok(t) => {
|
||||||
|
let t = t.clone();
|
||||||
|
return Err(location.new_unexpected_token_error(t));
|
||||||
|
},
|
||||||
Err(_) => break,
|
Err(_) => break,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -147,57 +150,60 @@ impl Parse for Content {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// FIXME: remove clone() when lifetimes are non-lexical
|
match input.next() {
|
||||||
match input.next().map(|t| t.clone()) {
|
Ok(&Token::QuotedString(ref value)) => {
|
||||||
Ok(Token::QuotedString(ref value)) => {
|
|
||||||
content.push(generics::ContentItem::String(
|
content.push(generics::ContentItem::String(
|
||||||
value.as_ref().to_owned().into_boxed_str(),
|
value.as_ref().to_owned().into_boxed_str(),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
Ok(Token::Function(ref name)) => {
|
Ok(&Token::Function(ref name)) => {
|
||||||
let result = match_ignore_ascii_case! { &name,
|
let result = match_ignore_ascii_case! { &name,
|
||||||
"counter" => Some(input.parse_nested_block(|input| {
|
"counter" => input.parse_nested_block(|input| {
|
||||||
let location = input.current_source_location();
|
let location = input.current_source_location();
|
||||||
let name = CustomIdent::from_ident(location, input.expect_ident()?, &[])?;
|
let name = CustomIdent::from_ident(location, input.expect_ident()?, &[])?;
|
||||||
let style = Content::parse_counter_style(context, input);
|
let style = Content::parse_counter_style(context, input);
|
||||||
Ok(generics::ContentItem::Counter(name, style))
|
Ok(generics::ContentItem::Counter(name, style))
|
||||||
})),
|
}),
|
||||||
"counters" => Some(input.parse_nested_block(|input| {
|
"counters" => input.parse_nested_block(|input| {
|
||||||
let location = input.current_source_location();
|
let location = input.current_source_location();
|
||||||
let name = CustomIdent::from_ident(location, input.expect_ident()?, &[])?;
|
let name = CustomIdent::from_ident(location, input.expect_ident()?, &[])?;
|
||||||
input.expect_comma()?;
|
input.expect_comma()?;
|
||||||
let separator = input.expect_string()?.as_ref().to_owned().into_boxed_str();
|
let separator = input.expect_string()?.as_ref().to_owned().into_boxed_str();
|
||||||
let style = Content::parse_counter_style(context, input);
|
let style = Content::parse_counter_style(context, input);
|
||||||
Ok(generics::ContentItem::Counters(name, separator, style))
|
Ok(generics::ContentItem::Counters(name, separator, style))
|
||||||
})),
|
}),
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
"attr" => Some(input.parse_nested_block(|input| {
|
"attr" => input.parse_nested_block(|input| {
|
||||||
Ok(generics::ContentItem::Attr(Attr::parse_function(context, input)?))
|
Ok(generics::ContentItem::Attr(Attr::parse_function(context, input)?))
|
||||||
})),
|
}),
|
||||||
_ => None
|
_ => {
|
||||||
};
|
let name = name.clone();
|
||||||
match result {
|
|
||||||
Some(result) => content.push(result?),
|
|
||||||
None => {
|
|
||||||
return Err(input.new_custom_error(
|
return Err(input.new_custom_error(
|
||||||
StyleParseErrorKind::UnexpectedFunction(name.clone()),
|
StyleParseErrorKind::UnexpectedFunction(name),
|
||||||
));
|
))
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
}?;
|
||||||
|
content.push(result);
|
||||||
},
|
},
|
||||||
Ok(Token::Ident(ref ident)) => {
|
Ok(&Token::Ident(ref ident)) => {
|
||||||
content.push(match_ignore_ascii_case! { &ident,
|
content.push(match_ignore_ascii_case! { &ident,
|
||||||
"open-quote" => generics::ContentItem::OpenQuote,
|
"open-quote" => generics::ContentItem::OpenQuote,
|
||||||
"close-quote" => generics::ContentItem::CloseQuote,
|
"close-quote" => generics::ContentItem::CloseQuote,
|
||||||
"no-open-quote" => generics::ContentItem::NoOpenQuote,
|
"no-open-quote" => generics::ContentItem::NoOpenQuote,
|
||||||
"no-close-quote" => generics::ContentItem::NoCloseQuote,
|
"no-close-quote" => generics::ContentItem::NoCloseQuote,
|
||||||
_ => return Err(input.new_custom_error(
|
_ =>{
|
||||||
SelectorParseErrorKind::UnexpectedIdent(ident.clone())
|
let ident = ident.clone();
|
||||||
))
|
return Err(input.new_custom_error(
|
||||||
|
SelectorParseErrorKind::UnexpectedIdent(ident)
|
||||||
|
));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
Err(_) => break,
|
Err(_) => break,
|
||||||
Ok(t) => return Err(input.new_unexpected_token_error(t)),
|
Ok(t) => {
|
||||||
|
let t = t.clone();
|
||||||
|
return Err(input.new_unexpected_token_error(t));
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if content.is_empty() {
|
if content.is_empty() {
|
||||||
|
|
|
@ -1212,15 +1212,15 @@ impl Parse for FontVariantAlternates {
|
||||||
parsed_alternates |= $flag;
|
parsed_alternates |= $flag;
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
while let Ok(_) = input.try(|input| {
|
while let Ok(_) = input.try(|input| match *input.next()? {
|
||||||
// FIXME: remove clone() when lifetimes are non-lexical
|
|
||||||
match input.next()?.clone() {
|
|
||||||
Token::Ident(ref value) if value.eq_ignore_ascii_case("historical-forms") => {
|
Token::Ident(ref value) if value.eq_ignore_ascii_case("historical-forms") => {
|
||||||
check_if_parsed!(input, VariantAlternatesParsingFlags::HISTORICAL_FORMS);
|
check_if_parsed!(input, VariantAlternatesParsingFlags::HISTORICAL_FORMS);
|
||||||
alternates.push(VariantAlternates::HistoricalForms);
|
alternates.push(VariantAlternates::HistoricalForms);
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
Token::Function(ref name) => input.parse_nested_block(|i| {
|
Token::Function(ref name) => {
|
||||||
|
let name = name.clone();
|
||||||
|
input.parse_nested_block(|i| {
|
||||||
match_ignore_ascii_case! { &name,
|
match_ignore_ascii_case! { &name,
|
||||||
"swash" => {
|
"swash" => {
|
||||||
check_if_parsed!(i, VariantAlternatesParsingFlags::SWASH);
|
check_if_parsed!(i, VariantAlternatesParsingFlags::SWASH);
|
||||||
|
@ -1270,9 +1270,9 @@ impl Parse for FontVariantAlternates {
|
||||||
},
|
},
|
||||||
_ => return Err(i.new_custom_error(StyleParseErrorKind::UnspecifiedError)),
|
_ => return Err(i.new_custom_error(StyleParseErrorKind::UnspecifiedError)),
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
|
},
|
||||||
_ => Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)),
|
_ => Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)),
|
||||||
}
|
|
||||||
}) {}
|
}) {}
|
||||||
|
|
||||||
if parsed_alternates.is_empty() {
|
if parsed_alternates.is_empty() {
|
||||||
|
|
|
@ -102,8 +102,8 @@ impl Parse for ImplicitGridTracks<TrackSize<LengthPercentage>> {
|
||||||
) -> Result<Self, ParseError<'i>> {
|
) -> Result<Self, ParseError<'i>> {
|
||||||
use style_traits::{Separator, Space};
|
use style_traits::{Separator, Space};
|
||||||
let track_sizes = Space::parse(input, |i| TrackSize::parse(context, i))?;
|
let track_sizes = Space::parse(input, |i| TrackSize::parse(context, i))?;
|
||||||
if track_sizes.len() == 1 && track_sizes[0].is_auto() {
|
if track_sizes.len() == 1 && track_sizes[0].is_initial() {
|
||||||
//`auto`, which is the initial value, is always represented by an empty slice.
|
// A single track with the initial value is always represented by an empty slice.
|
||||||
return Ok(Default::default());
|
return Ok(Default::default());
|
||||||
}
|
}
|
||||||
return Ok(ImplicitGridTracks(track_sizes.into()));
|
return Ok(ImplicitGridTracks(track_sizes.into()));
|
||||||
|
|
|
@ -192,62 +192,57 @@ impl Parse for Gradient {
|
||||||
Radial,
|
Radial,
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: remove clone() when lifetimes are non-lexical
|
let func = input.expect_function()?;
|
||||||
let func = input.expect_function()?.clone();
|
let (shape, repeating, mut compat_mode) = match_ignore_ascii_case! { &func,
|
||||||
let result = match_ignore_ascii_case! { &func,
|
|
||||||
"linear-gradient" => {
|
"linear-gradient" => {
|
||||||
Some((Shape::Linear, false, GradientCompatMode::Modern))
|
(Shape::Linear, false, GradientCompatMode::Modern)
|
||||||
},
|
},
|
||||||
"-webkit-linear-gradient" => {
|
"-webkit-linear-gradient" => {
|
||||||
Some((Shape::Linear, false, GradientCompatMode::WebKit))
|
(Shape::Linear, false, GradientCompatMode::WebKit)
|
||||||
},
|
},
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
"-moz-linear-gradient" => {
|
"-moz-linear-gradient" => {
|
||||||
Some((Shape::Linear, false, GradientCompatMode::Moz))
|
(Shape::Linear, false, GradientCompatMode::Moz)
|
||||||
},
|
},
|
||||||
"repeating-linear-gradient" => {
|
"repeating-linear-gradient" => {
|
||||||
Some((Shape::Linear, true, GradientCompatMode::Modern))
|
(Shape::Linear, true, GradientCompatMode::Modern)
|
||||||
},
|
},
|
||||||
"-webkit-repeating-linear-gradient" => {
|
"-webkit-repeating-linear-gradient" => {
|
||||||
Some((Shape::Linear, true, GradientCompatMode::WebKit))
|
(Shape::Linear, true, GradientCompatMode::WebKit)
|
||||||
},
|
},
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
"-moz-repeating-linear-gradient" => {
|
"-moz-repeating-linear-gradient" => {
|
||||||
Some((Shape::Linear, true, GradientCompatMode::Moz))
|
(Shape::Linear, true, GradientCompatMode::Moz)
|
||||||
},
|
},
|
||||||
"radial-gradient" => {
|
"radial-gradient" => {
|
||||||
Some((Shape::Radial, false, GradientCompatMode::Modern))
|
(Shape::Radial, false, GradientCompatMode::Modern)
|
||||||
},
|
},
|
||||||
"-webkit-radial-gradient" => {
|
"-webkit-radial-gradient" => {
|
||||||
Some((Shape::Radial, false, GradientCompatMode::WebKit))
|
(Shape::Radial, false, GradientCompatMode::WebKit)
|
||||||
},
|
},
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
"-moz-radial-gradient" => {
|
"-moz-radial-gradient" => {
|
||||||
Some((Shape::Radial, false, GradientCompatMode::Moz))
|
(Shape::Radial, false, GradientCompatMode::Moz)
|
||||||
},
|
},
|
||||||
"repeating-radial-gradient" => {
|
"repeating-radial-gradient" => {
|
||||||
Some((Shape::Radial, true, GradientCompatMode::Modern))
|
(Shape::Radial, true, GradientCompatMode::Modern)
|
||||||
},
|
},
|
||||||
"-webkit-repeating-radial-gradient" => {
|
"-webkit-repeating-radial-gradient" => {
|
||||||
Some((Shape::Radial, true, GradientCompatMode::WebKit))
|
(Shape::Radial, true, GradientCompatMode::WebKit)
|
||||||
},
|
},
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
"-moz-repeating-radial-gradient" => {
|
"-moz-repeating-radial-gradient" => {
|
||||||
Some((Shape::Radial, true, GradientCompatMode::Moz))
|
(Shape::Radial, true, GradientCompatMode::Moz)
|
||||||
},
|
},
|
||||||
"-webkit-gradient" => {
|
"-webkit-gradient" => {
|
||||||
return input.parse_nested_block(|i| {
|
return input.parse_nested_block(|i| {
|
||||||
Self::parse_webkit_gradient_argument(context, i)
|
Self::parse_webkit_gradient_argument(context, i)
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
_ => None,
|
_ => {
|
||||||
};
|
let func = func.clone();
|
||||||
|
|
||||||
let (shape, repeating, mut compat_mode) = match result {
|
|
||||||
Some(result) => result,
|
|
||||||
None => {
|
|
||||||
return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedFunction(func)));
|
return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedFunction(func)));
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let (kind, items) = input.parse_nested_block(|i| {
|
let (kind, items) = input.parse_nested_block(|i| {
|
||||||
|
|
|
@ -587,39 +587,34 @@ impl Length {
|
||||||
num_context: AllowedNumericType,
|
num_context: AllowedNumericType,
|
||||||
allow_quirks: AllowQuirks,
|
allow_quirks: AllowQuirks,
|
||||||
) -> Result<Self, ParseError<'i>> {
|
) -> Result<Self, ParseError<'i>> {
|
||||||
// FIXME: remove early returns when lifetimes are non-lexical
|
|
||||||
{
|
|
||||||
let location = input.current_source_location();
|
let location = input.current_source_location();
|
||||||
let token = input.next()?;
|
let token = input.next()?;
|
||||||
match *token {
|
match *token {
|
||||||
Token::Dimension {
|
Token::Dimension {
|
||||||
value, ref unit, ..
|
value, ref unit, ..
|
||||||
} if num_context.is_ok(context.parsing_mode, value) => {
|
} if num_context.is_ok(context.parsing_mode, value) => {
|
||||||
return NoCalcLength::parse_dimension(context, value, unit)
|
NoCalcLength::parse_dimension(context, value, unit)
|
||||||
.map(Length::NoCalc)
|
.map(Length::NoCalc)
|
||||||
.map_err(|()| location.new_unexpected_token_error(token.clone()));
|
.map_err(|()| location.new_unexpected_token_error(token.clone()))
|
||||||
},
|
},
|
||||||
Token::Number { value, .. } if num_context.is_ok(context.parsing_mode, value) => {
|
Token::Number { value, .. } if num_context.is_ok(context.parsing_mode, value) => {
|
||||||
if value != 0. &&
|
if value != 0. &&
|
||||||
!context.parsing_mode.allows_unitless_lengths() &&
|
!context.parsing_mode.allows_unitless_lengths() &&
|
||||||
!allow_quirks.allowed(context.quirks_mode)
|
!allow_quirks.allowed(context.quirks_mode)
|
||||||
{
|
{
|
||||||
return Err(
|
return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||||
location.new_custom_error(StyleParseErrorKind::UnspecifiedError)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return Ok(Length::NoCalc(NoCalcLength::Absolute(AbsoluteLength::Px(
|
Ok(Length::NoCalc(NoCalcLength::Absolute(AbsoluteLength::Px(
|
||||||
value,
|
value,
|
||||||
))));
|
))))
|
||||||
},
|
},
|
||||||
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {},
|
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => input
|
||||||
ref token => return Err(location.new_unexpected_token_error(token.clone())),
|
.parse_nested_block(|input| {
|
||||||
}
|
|
||||||
}
|
|
||||||
input.parse_nested_block(|input| {
|
|
||||||
CalcNode::parse_length(context, input, num_context)
|
CalcNode::parse_length(context, input, num_context)
|
||||||
.map(|calc| Length::Calc(Box::new(calc)))
|
.map(|calc| Length::Calc(Box::new(calc)))
|
||||||
})
|
}),
|
||||||
|
ref token => return Err(location.new_unexpected_token_error(token.clone())),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a non-negative length
|
/// Parse a non-negative length
|
||||||
|
@ -809,8 +804,6 @@ impl LengthPercentage {
|
||||||
num_context: AllowedNumericType,
|
num_context: AllowedNumericType,
|
||||||
allow_quirks: AllowQuirks,
|
allow_quirks: AllowQuirks,
|
||||||
) -> Result<Self, ParseError<'i>> {
|
) -> Result<Self, ParseError<'i>> {
|
||||||
// FIXME: remove early returns when lifetimes are non-lexical
|
|
||||||
{
|
|
||||||
let location = input.current_source_location();
|
let location = input.current_source_location();
|
||||||
let token = input.next()?;
|
let token = input.next()?;
|
||||||
match *token {
|
match *token {
|
||||||
|
@ -838,15 +831,14 @@ impl LengthPercentage {
|
||||||
return Ok(LengthPercentage::Length(NoCalcLength::from_px(value)));
|
return Ok(LengthPercentage::Length(NoCalcLength::from_px(value)));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {},
|
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
|
||||||
_ => return Err(location.new_unexpected_token_error(token.clone())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let calc = input.parse_nested_block(|i| {
|
let calc = input.parse_nested_block(|i| {
|
||||||
CalcNode::parse_length_or_percentage(context, i, num_context)
|
CalcNode::parse_length_or_percentage(context, i, num_context)
|
||||||
})?;
|
})?;
|
||||||
Ok(LengthPercentage::Calc(Box::new(calc)))
|
Ok(LengthPercentage::Calc(Box::new(calc)))
|
||||||
|
},
|
||||||
|
_ => return Err(location.new_unexpected_token_error(token.clone())),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses allowing the unitless length quirk.
|
/// Parses allowing the unitless length quirk.
|
||||||
|
|
|
@ -136,24 +136,22 @@ fn parse_number_with_clamping_mode<'i, 't>(
|
||||||
clamping_mode: AllowedNumericType,
|
clamping_mode: AllowedNumericType,
|
||||||
) -> Result<Number, ParseError<'i>> {
|
) -> Result<Number, ParseError<'i>> {
|
||||||
let location = input.current_source_location();
|
let location = input.current_source_location();
|
||||||
// FIXME: remove early returns when lifetimes are non-lexical
|
|
||||||
match *input.next()? {
|
match *input.next()? {
|
||||||
Token::Number { value, .. } if clamping_mode.is_ok(context.parsing_mode, value) => {
|
Token::Number { value, .. } if clamping_mode.is_ok(context.parsing_mode, value) => {
|
||||||
return Ok(Number {
|
Ok(Number {
|
||||||
value: value.min(f32::MAX).max(f32::MIN),
|
value: value.min(f32::MAX).max(f32::MIN),
|
||||||
calc_clamping_mode: None,
|
calc_clamping_mode: None,
|
||||||
});
|
})
|
||||||
},
|
},
|
||||||
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {},
|
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
|
||||||
ref t => return Err(location.new_unexpected_token_error(t.clone())),
|
|
||||||
}
|
|
||||||
|
|
||||||
let result = input.parse_nested_block(|i| CalcNode::parse_number(context, i))?;
|
let result = input.parse_nested_block(|i| CalcNode::parse_number(context, i))?;
|
||||||
|
|
||||||
Ok(Number {
|
Ok(Number {
|
||||||
value: result.min(f32::MAX).max(f32::MIN),
|
value: result.min(f32::MAX).max(f32::MIN),
|
||||||
calc_clamping_mode: Some(clamping_mode),
|
calc_clamping_mode: Some(clamping_mode),
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
ref t => Err(location.new_unexpected_token_error(t.clone())),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A CSS `<number>` specified value.
|
/// A CSS `<number>` specified value.
|
||||||
|
@ -540,19 +538,16 @@ impl Parse for Integer {
|
||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
) -> Result<Self, ParseError<'i>> {
|
) -> Result<Self, ParseError<'i>> {
|
||||||
let location = input.current_source_location();
|
let location = input.current_source_location();
|
||||||
|
|
||||||
// FIXME: remove early returns when lifetimes are non-lexical
|
|
||||||
match *input.next()? {
|
match *input.next()? {
|
||||||
Token::Number {
|
Token::Number {
|
||||||
int_value: Some(v), ..
|
int_value: Some(v), ..
|
||||||
} => return Ok(Integer::new(v)),
|
} => Ok(Integer::new(v)),
|
||||||
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {},
|
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
|
||||||
ref t => return Err(location.new_unexpected_token_error(t.clone())),
|
|
||||||
}
|
|
||||||
|
|
||||||
let result = input.parse_nested_block(|i| CalcNode::parse_integer(context, i))?;
|
let result = input.parse_nested_block(|i| CalcNode::parse_integer(context, i))?;
|
||||||
|
|
||||||
Ok(Integer::from_calc(result))
|
Ok(Integer::from_calc(result))
|
||||||
|
},
|
||||||
|
ref t => Err(location.new_unexpected_token_error(t.clone())),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,11 +16,24 @@ use style_traits::{ParseError, StyleParseErrorKind};
|
||||||
/// The specified value of `offset-path`.
|
/// The specified value of `offset-path`.
|
||||||
pub type OffsetPath = GenericOffsetPath<Angle>;
|
pub type OffsetPath = GenericOffsetPath<Angle>;
|
||||||
|
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
fn is_ray_enabled() -> bool {
|
||||||
|
static_prefs::pref!("layout.css.motion-path-ray.enabled")
|
||||||
|
}
|
||||||
|
#[cfg(feature = "servo")]
|
||||||
|
fn is_ray_enabled() -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
impl Parse for RayFunction<Angle> {
|
impl Parse for RayFunction<Angle> {
|
||||||
fn parse<'i, 't>(
|
fn parse<'i, 't>(
|
||||||
context: &ParserContext,
|
context: &ParserContext,
|
||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
) -> Result<Self, ParseError<'i>> {
|
) -> Result<Self, ParseError<'i>> {
|
||||||
|
if !is_ray_enabled() {
|
||||||
|
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||||
|
}
|
||||||
|
|
||||||
let mut angle = None;
|
let mut angle = None;
|
||||||
let mut size = None;
|
let mut size = None;
|
||||||
let mut contain = false;
|
let mut contain = false;
|
||||||
|
|
|
@ -111,18 +111,15 @@ impl Percentage {
|
||||||
num_context: AllowedNumericType,
|
num_context: AllowedNumericType,
|
||||||
) -> Result<Self, ParseError<'i>> {
|
) -> Result<Self, ParseError<'i>> {
|
||||||
let location = input.current_source_location();
|
let location = input.current_source_location();
|
||||||
// FIXME: remove early returns when lifetimes are non-lexical
|
|
||||||
match *input.next()? {
|
match *input.next()? {
|
||||||
Token::Percentage { unit_value, .. }
|
Token::Percentage { unit_value, .. }
|
||||||
if num_context.is_ok(context.parsing_mode, unit_value) =>
|
if num_context.is_ok(context.parsing_mode, unit_value) =>
|
||||||
{
|
{
|
||||||
return Ok(Percentage::new(unit_value));
|
Ok(Percentage::new(unit_value))
|
||||||
}
|
},
|
||||||
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {},
|
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
|
||||||
ref t => return Err(location.new_unexpected_token_error(t.clone())),
|
let result =
|
||||||
}
|
input.parse_nested_block(|i| CalcNode::parse_percentage(context, i))?;
|
||||||
|
|
||||||
let result = input.parse_nested_block(|i| CalcNode::parse_percentage(context, i))?;
|
|
||||||
|
|
||||||
// TODO(emilio): -moz-image-rect is the only thing that uses
|
// TODO(emilio): -moz-image-rect is the only thing that uses
|
||||||
// the clamping mode... I guess we could disallow it...
|
// the clamping mode... I guess we could disallow it...
|
||||||
|
@ -130,6 +127,9 @@ impl Percentage {
|
||||||
value: result,
|
value: result,
|
||||||
calc_clamping_mode: Some(num_context),
|
calc_clamping_mode: Some(num_context),
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
ref t => Err(location.new_unexpected_token_error(t.clone())),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses a percentage token, but rejects it if it's negative.
|
/// Parses a percentage token, but rejects it if it's negative.
|
||||||
|
|
|
@ -83,28 +83,26 @@ impl Time {
|
||||||
use style_traits::ParsingMode;
|
use style_traits::ParsingMode;
|
||||||
|
|
||||||
let location = input.current_source_location();
|
let location = input.current_source_location();
|
||||||
// FIXME: remove early returns when lifetimes are non-lexical
|
match *input.next()? {
|
||||||
match input.next() {
|
|
||||||
// Note that we generally pass ParserContext to is_ok() to check
|
// Note that we generally pass ParserContext to is_ok() to check
|
||||||
// that the ParserMode of the ParserContext allows all numeric
|
// that the ParserMode of the ParserContext allows all numeric
|
||||||
// values for SMIL regardless of clamping_mode, but in this Time
|
// values for SMIL regardless of clamping_mode, but in this Time
|
||||||
// value case, the value does not animate for SMIL at all, so we use
|
// value case, the value does not animate for SMIL at all, so we use
|
||||||
// ParsingMode::DEFAULT directly.
|
// ParsingMode::DEFAULT directly.
|
||||||
Ok(&Token::Dimension {
|
Token::Dimension {
|
||||||
value, ref unit, ..
|
value, ref unit, ..
|
||||||
}) if clamping_mode.is_ok(ParsingMode::DEFAULT, value) => {
|
} if clamping_mode.is_ok(ParsingMode::DEFAULT, value) => {
|
||||||
return Time::parse_dimension(value, unit, /* from_calc = */ false).map_err(|()| {
|
Time::parse_dimension(value, unit, /* from_calc = */ false)
|
||||||
location.new_custom_error(StyleParseErrorKind::UnspecifiedError)
|
.map_err(|()| location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
|
||||||
});
|
|
||||||
},
|
},
|
||||||
Ok(&Token::Function(ref name)) if name.eq_ignore_ascii_case("calc") => {},
|
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
|
||||||
Ok(t) => return Err(location.new_unexpected_token_error(t.clone())),
|
|
||||||
Err(e) => return Err(e.into()),
|
|
||||||
}
|
|
||||||
match input.parse_nested_block(|i| CalcNode::parse_time(context, i)) {
|
match input.parse_nested_block(|i| CalcNode::parse_time(context, i)) {
|
||||||
Ok(time) if clamping_mode.is_ok(ParsingMode::DEFAULT, time.seconds) => Ok(time),
|
Ok(time) if clamping_mode.is_ok(ParsingMode::DEFAULT, time.seconds) => Ok(time),
|
||||||
_ => Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)),
|
_ => Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)),
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
ref t => return Err(location.new_unexpected_token_error(t.clone())),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses a non-negative time value.
|
/// Parses a non-negative time value.
|
||||||
|
|
|
@ -12,7 +12,9 @@ use crate::values::generics::transform::{Matrix, Matrix3D};
|
||||||
use crate::values::specified::position::{
|
use crate::values::specified::position::{
|
||||||
HorizontalPositionKeyword, Side, VerticalPositionKeyword,
|
HorizontalPositionKeyword, Side, VerticalPositionKeyword,
|
||||||
};
|
};
|
||||||
use crate::values::specified::{self, Angle, Integer, Length, LengthPercentage, Number};
|
use crate::values::specified::{
|
||||||
|
self, Angle, Integer, Length, LengthPercentage, Number, NumberOrPercentage,
|
||||||
|
};
|
||||||
use crate::Zero;
|
use crate::Zero;
|
||||||
use cssparser::Parser;
|
use cssparser::Parser;
|
||||||
use style_traits::{ParseError, StyleParseErrorKind};
|
use style_traits::{ParseError, StyleParseErrorKind};
|
||||||
|
@ -163,32 +165,32 @@ impl Transform {
|
||||||
Ok(generic::TransformOperation::Translate3D(tx, ty, tz))
|
Ok(generic::TransformOperation::Translate3D(tx, ty, tz))
|
||||||
},
|
},
|
||||||
"scale" => {
|
"scale" => {
|
||||||
let sx = Number::parse(context, input)?;
|
let sx = NumberOrPercentage::parse(context, input)?.to_number();
|
||||||
if input.try(|input| input.expect_comma()).is_ok() {
|
if input.try(|input| input.expect_comma()).is_ok() {
|
||||||
let sy = Number::parse(context, input)?;
|
let sy = NumberOrPercentage::parse(context, input)?.to_number();
|
||||||
Ok(generic::TransformOperation::Scale(sx, sy))
|
Ok(generic::TransformOperation::Scale(sx, sy))
|
||||||
} else {
|
} else {
|
||||||
Ok(generic::TransformOperation::Scale(sx, sx))
|
Ok(generic::TransformOperation::Scale(sx, sx))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"scalex" => {
|
"scalex" => {
|
||||||
let sx = Number::parse(context, input)?;
|
let sx = NumberOrPercentage::parse(context, input)?.to_number();
|
||||||
Ok(generic::TransformOperation::ScaleX(sx))
|
Ok(generic::TransformOperation::ScaleX(sx))
|
||||||
},
|
},
|
||||||
"scaley" => {
|
"scaley" => {
|
||||||
let sy = Number::parse(context, input)?;
|
let sy = NumberOrPercentage::parse(context, input)?.to_number();
|
||||||
Ok(generic::TransformOperation::ScaleY(sy))
|
Ok(generic::TransformOperation::ScaleY(sy))
|
||||||
},
|
},
|
||||||
"scalez" => {
|
"scalez" => {
|
||||||
let sz = Number::parse(context, input)?;
|
let sz = NumberOrPercentage::parse(context, input)?.to_number();
|
||||||
Ok(generic::TransformOperation::ScaleZ(sz))
|
Ok(generic::TransformOperation::ScaleZ(sz))
|
||||||
},
|
},
|
||||||
"scale3d" => {
|
"scale3d" => {
|
||||||
let sx = Number::parse(context, input)?;
|
let sx = NumberOrPercentage::parse(context, input)?.to_number();
|
||||||
input.expect_comma()?;
|
input.expect_comma()?;
|
||||||
let sy = Number::parse(context, input)?;
|
let sy = NumberOrPercentage::parse(context, input)?.to_number();
|
||||||
input.expect_comma()?;
|
input.expect_comma()?;
|
||||||
let sz = Number::parse(context, input)?;
|
let sz = NumberOrPercentage::parse(context, input)?.to_number();
|
||||||
Ok(generic::TransformOperation::Scale3D(sx, sy, sz))
|
Ok(generic::TransformOperation::Scale3D(sx, sy, sz))
|
||||||
},
|
},
|
||||||
"rotate" => {
|
"rotate" => {
|
||||||
|
@ -421,17 +423,22 @@ impl Parse for Translate {
|
||||||
if let Ok(ty) = input.try(|i| specified::LengthPercentage::parse(context, i)) {
|
if let Ok(ty) = input.try(|i| specified::LengthPercentage::parse(context, i)) {
|
||||||
if let Ok(tz) = input.try(|i| specified::Length::parse(context, i)) {
|
if let Ok(tz) = input.try(|i| specified::Length::parse(context, i)) {
|
||||||
// 'translate: <length-percentage> <length-percentage> <length>'
|
// 'translate: <length-percentage> <length-percentage> <length>'
|
||||||
return Ok(generic::Translate::Translate3D(tx, ty, tz));
|
return Ok(generic::Translate::Translate(tx, ty, tz));
|
||||||
}
|
}
|
||||||
|
|
||||||
// translate: <length-percentage> <length-percentage>'
|
// translate: <length-percentage> <length-percentage>'
|
||||||
return Ok(generic::Translate::Translate(tx, ty));
|
return Ok(generic::Translate::Translate(
|
||||||
|
tx,
|
||||||
|
ty,
|
||||||
|
specified::Length::zero(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 'translate: <length-percentage> '
|
// 'translate: <length-percentage> '
|
||||||
Ok(generic::Translate::Translate(
|
Ok(generic::Translate::Translate(
|
||||||
tx,
|
tx,
|
||||||
specified::LengthPercentage::zero(),
|
specified::LengthPercentage::zero(),
|
||||||
|
specified::Length::zero(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -440,6 +447,9 @@ impl Parse for Translate {
|
||||||
pub type Scale = generic::Scale<Number>;
|
pub type Scale = generic::Scale<Number>;
|
||||||
|
|
||||||
impl Parse for Scale {
|
impl Parse for Scale {
|
||||||
|
/// Scale accepts <number> | <percentage>, so we parse it as NumberOrPercentage,
|
||||||
|
/// and then convert into an Number if it's a Percentage.
|
||||||
|
/// https://github.com/w3c/csswg-drafts/pull/4396
|
||||||
fn parse<'i, 't>(
|
fn parse<'i, 't>(
|
||||||
context: &ParserContext,
|
context: &ParserContext,
|
||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
|
@ -448,18 +458,19 @@ impl Parse for Scale {
|
||||||
return Ok(generic::Scale::None);
|
return Ok(generic::Scale::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
let sx = Number::parse(context, input)?;
|
let sx = NumberOrPercentage::parse(context, input)?.to_number();
|
||||||
if let Ok(sy) = input.try(|i| Number::parse(context, i)) {
|
if let Ok(sy) = input.try(|i| NumberOrPercentage::parse(context, i)) {
|
||||||
if let Ok(sz) = input.try(|i| Number::parse(context, i)) {
|
let sy = sy.to_number();
|
||||||
|
if let Ok(sz) = input.try(|i| NumberOrPercentage::parse(context, i)) {
|
||||||
// 'scale: <number> <number> <number>'
|
// 'scale: <number> <number> <number>'
|
||||||
return Ok(generic::Scale::Scale3D(sx, sy, sz));
|
return Ok(generic::Scale::Scale(sx, sy, sz.to_number()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 'scale: <number> <number>'
|
// 'scale: <number> <number>'
|
||||||
return Ok(generic::Scale::Scale(sx, sy));
|
return Ok(generic::Scale::Scale(sx, sy, Number::new(1.0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 'scale: <number>'
|
// 'scale: <number>'
|
||||||
Ok(generic::Scale::Scale(sx, sx))
|
Ok(generic::Scale::Scale(sx, sx, Number::new(1.0)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ gecko = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
app_units = "0.7"
|
app_units = "0.7"
|
||||||
cssparser = "0.27.1"
|
cssparser = "0.27"
|
||||||
bitflags = "1.0"
|
bitflags = "1.0"
|
||||||
euclid = "0.20"
|
euclid = "0.20"
|
||||||
lazy_static = "1"
|
lazy_static = "1"
|
||||||
|
|
|
@ -14,7 +14,7 @@ servo = ["cssparser/serde", "string_cache"]
|
||||||
gecko = []
|
gecko = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cssparser = "0.27.1"
|
cssparser = "0.27"
|
||||||
servo_arc = { path = "../servo_arc" }
|
servo_arc = { path = "../servo_arc" }
|
||||||
smallbitvec = "2.1.1"
|
smallbitvec = "2.1.1"
|
||||||
smallvec = "0.6.6"
|
smallvec = "0.6.6"
|
||||||
|
|
|
@ -11,7 +11,7 @@ doctest = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
app_units = "0.7"
|
app_units = "0.7"
|
||||||
cssparser = "0.27.1"
|
cssparser = "0.27"
|
||||||
euclid = "0.20"
|
euclid = "0.20"
|
||||||
html5ever = "0.25"
|
html5ever = "0.25"
|
||||||
rayon = "1"
|
rayon = "1"
|
||||||
|
|
|
@ -95,9 +95,6 @@
|
||||||
[CSS Transitions: property <rotate> from [1 0 0 0deg\] to [0 1 0 10deg\] at (-1) should be [0 1 0 -10deg\]]
|
[CSS Transitions: property <rotate> from [1 0 0 0deg\] to [0 1 0 10deg\] at (-1) should be [0 1 0 -10deg\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <rotate> from [none\] to [7 -8 9 400grad\] at (1) should be [0.5 -0.57 0.65 400grad\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <rotate> from [0 1 0 100deg\] to [0 1 0 -100deg\] at (0.25) should be [0 1 0 50deg\]]
|
[CSS Animations: property <rotate> from [0 1 0 100deg\] to [0 1 0 -100deg\] at (0.25) should be [0 1 0 50deg\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -821,9 +818,6 @@
|
||||||
[Web Animations: property <rotate> from [100deg\] to [-100deg\] at (0) should be [100deg\]]
|
[Web Animations: property <rotate> from [100deg\] to [-100deg\] at (0) should be [100deg\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions: property <rotate> from [none\] to [7 -8 9 400grad\] at (1) should be [0.5 -0.57 0.65 400grad\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <rotate> from [1 0 0 0deg\] to [0 1 0 10deg\] at (1) should be [0 1 0 10deg\]]
|
[CSS Animations: property <rotate> from [1 0 0 0deg\] to [0 1 0 10deg\] at (1) should be [0 1 0 10deg\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -98,9 +98,6 @@
|
||||||
[CSS Transitions: property <scale> from [2 30 400\] to [10 110 1200\] at (2) should be [18 190 2000\]]
|
[CSS Transitions: property <scale> from [2 30 400\] to [10 110 1200\] at (2) should be [18 190 2000\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <scale> from [2 0.5 1\] to [inherit\] at (0) should be [2 0.5\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <scale> from [none\] to [4 3 2\] at (2) should be [7 5 3\]]
|
[CSS Transitions with transition: all: property <scale> from [none\] to [4 3 2\] at (2) should be [7 5 3\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -251,9 +248,6 @@
|
||||||
[Web Animations: property <scale> from [-10 5\] to [10 -5\] at (1) should be [10 -5\]]
|
[Web Animations: property <scale> from [-10 5\] to [10 -5\] at (1) should be [10 -5\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions: property <scale> from [inherit\] to [2 0.5 1\] at (1) should be [2 0.5\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions: property <scale> from [unset\] to [1.5 1\] at (2) should be [2 1\]]
|
[CSS Transitions: property <scale> from [unset\] to [1.5 1\] at (2) should be [2 1\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -272,9 +266,6 @@
|
||||||
[CSS Transitions with transition: all: property <scale> from [initial\] to [2 0.5 1\] at (2) should be [3 0\]]
|
[CSS Transitions with transition: all: property <scale> from [initial\] to [2 0.5 1\] at (2) should be [3 0\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <scale> from [-10 5 1\] to [1\] at (1) should be [1\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions: property <scale> from [-10 5\] to [10 -5\] at (0.75) should be [5 -2.5\]]
|
[CSS Transitions: property <scale> from [-10 5\] to [10 -5\] at (0.75) should be [5 -2.5\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -311,9 +302,6 @@
|
||||||
[Web Animations: property <scale> from [2 0.5 1\] to [inherit\] at (2) should be [-1 1.5 3\]]
|
[Web Animations: property <scale> from [2 0.5 1\] to [inherit\] at (2) should be [-1 1.5 3\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <scale> from [initial\] to [inherit\] at (0) should be [1\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <scale> from [none\] to [none\] at (0.125) should be [none\]]
|
[CSS Animations: property <scale> from [none\] to [none\] at (0.125) should be [none\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -347,9 +335,6 @@
|
||||||
[CSS Transitions with transition: all: property <scale> from neutral to [1.5 1\] at (2) should be [1.9 1\]]
|
[CSS Transitions with transition: all: property <scale> from neutral to [1.5 1\] at (2) should be [1.9 1\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <scale> from [none\] to [4 3 2\] at (0) should be [1\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <scale> from [initial\] to [inherit\] at (1) should be [0.5 1 2\]]
|
[CSS Animations: property <scale> from [initial\] to [inherit\] at (1) should be [0.5 1 2\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -359,27 +344,15 @@
|
||||||
[Web Animations: property <scale> from [2 30 400\] to [10 110 1200\] at (-1) should be [-6 -50 -400\]]
|
[Web Animations: property <scale> from [2 30 400\] to [10 110 1200\] at (-1) should be [-6 -50 -400\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions: property <scale> from [26 17 9\] to [2 1\] at (1) should be [2 1\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions: property <scale> from [inherit\] to [2 0.5 1\] at (0.25) should be [0.875 0.875 1.75\]]
|
[CSS Transitions: property <scale> from [inherit\] to [2 0.5 1\] at (0.25) should be [0.875 0.875 1.75\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <scale> from [-10 5 1\] to [1\] at (0) should be [-10 5\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <scale> from neutral to [1.5 1\] at (0.25) should be [1.2 1\]]
|
[CSS Animations: property <scale> from neutral to [1.5 1\] at (0.25) should be [1.2 1\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions: property <scale> from [-10 5 1\] to [1\] at (1) should be [1\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <scale> from [1\] to [10 -5 0\] at (0.25) should be [3.25 -0.5 0.75\]]
|
[CSS Transitions with transition: all: property <scale> from [1\] to [10 -5 0\] at (0.25) should be [3.25 -0.5 0.75\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions: property <scale> from [2 0.5 1\] to [initial\] at (0) should be [2 0.5\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions: property <scale> from [none\] to [4 3 2\] at (0.875) should be [3.625 2.75 1.875\]]
|
[CSS Transitions: property <scale> from [none\] to [4 3 2\] at (0.875) should be [3.625 2.75 1.875\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -479,9 +452,6 @@
|
||||||
[Web Animations: property <scale> from [2 0.5 1\] to [inherit\] at (-1) should be [3.5 0 0\]]
|
[Web Animations: property <scale> from [2 0.5 1\] to [inherit\] at (-1) should be [3.5 0 0\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions: property <scale> from [initial\] to [2 0.5 1\] at (1) should be [2 0.5\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Web Animations: property <scale> from [-10 5 1\] to [1\] at (0.75) should be [-1.75 2\]]
|
[Web Animations: property <scale> from [-10 5 1\] to [1\] at (0.75) should be [-1.75 2\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -515,9 +485,6 @@
|
||||||
[CSS Transitions with transition: all: property <scale> from [none\] to [4 3 2\] at (0.125) should be [1.375 1.25 1.125\]]
|
[CSS Transitions with transition: all: property <scale> from [none\] to [4 3 2\] at (0.125) should be [1.375 1.25 1.125\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions: property <scale> from [2 0.5 1\] to [initial\] at (1) should be [1\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <scale> from [initial\] to [inherit\] at (0.75) should be [0.625 1 1.75\]]
|
[CSS Transitions with transition: all: property <scale> from [initial\] to [inherit\] at (0.75) should be [0.625 1 1.75\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -533,9 +500,6 @@
|
||||||
[CSS Transitions with transition: all: property <scale> from [26 17 9\] to [2 1\] at (-1) should be [50 33 17\]]
|
[CSS Transitions with transition: all: property <scale> from [26 17 9\] to [2 1\] at (-1) should be [50 33 17\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions: property <scale> from [1\] to [10 -5 0\] at (0) should be [1\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Web Animations: property <scale> from [unset\] to [1.5 1\] at (0.75) should be [1.375 1\]]
|
[Web Animations: property <scale> from [unset\] to [1.5 1\] at (0.75) should be [1.375 1\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -581,15 +545,6 @@
|
||||||
[Web Animations: property <scale> from [1\] to [10 -5 0\] at (2) should be [19 -11 -1\]]
|
[Web Animations: property <scale> from [1\] to [10 -5 0\] at (2) should be [19 -11 -1\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <scale> from [inherit\] to [initial\] at (1) should be [1\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <scale> from [2 0.5 1\] to [initial\] at (1) should be [1\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <scale> from [initial\] to [2 0.5 1\] at (0) should be [1\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Web Animations: property <scale> from [inherit\] to [initial\] at (1) should be [1\]]
|
[Web Animations: property <scale> from [inherit\] to [initial\] at (1) should be [1\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -605,9 +560,6 @@
|
||||||
[CSS Animations: property <scale> from [2 0.5 1\] to [inherit\] at (-1) should be [3.5 0 0\]]
|
[CSS Animations: property <scale> from [2 0.5 1\] to [inherit\] at (-1) should be [3.5 0 0\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <scale> from [initial\] to [2 0.5 1\] at (1) should be [2 0.5\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <scale> from neutral to [1.5 1\] at (0.75) should be [1.4 1\]]
|
[CSS Animations: property <scale> from neutral to [1.5 1\] at (0.75) should be [1.4 1\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -629,9 +581,6 @@
|
||||||
[CSS Transitions: property <scale> from [2 0.5 1\] to [initial\] at (-1) should be [3 0\]]
|
[CSS Transitions: property <scale> from [2 0.5 1\] to [initial\] at (-1) should be [3 0\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions: property <scale> from [initial\] to [inherit\] at (0) should be [1\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Web Animations: property <scale> from [inherit\] to [initial\] at (0) should be [0.5 1 2\]]
|
[Web Animations: property <scale> from [inherit\] to [initial\] at (0) should be [0.5 1 2\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -698,9 +647,6 @@
|
||||||
[Web Animations: property <scale> from [none\] to [4 3 2\] at (0) should be [1\]]
|
[Web Animations: property <scale> from [none\] to [4 3 2\] at (0) should be [1\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions: property <scale> from [-10 5 1\] to [1\] at (0) should be [-10 5\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Web Animations: property <scale> from [2 0.5 1\] to [inherit\] at (0) should be [2 0.5\]]
|
[Web Animations: property <scale> from [2 0.5 1\] to [inherit\] at (0) should be [2 0.5\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -752,9 +698,6 @@
|
||||||
[Web Animations: property <scale> from [unset\] to [1.5 1\] at (1) should be [1.5 1\]]
|
[Web Animations: property <scale> from [unset\] to [1.5 1\] at (1) should be [1.5 1\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions: property <scale> from [inherit\] to [initial\] at (1) should be [1\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Web Animations: property <scale> from [2 0.5 1\] to [inherit\] at (0.25) should be [1.625 0.625 1.25\]]
|
[Web Animations: property <scale> from [2 0.5 1\] to [inherit\] at (0.25) should be [1.625 0.625 1.25\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -791,9 +734,6 @@
|
||||||
[CSS Animations: property <scale> from [initial\] to [inherit\] at (0.75) should be [0.625 1 1.75\]]
|
[CSS Animations: property <scale> from [initial\] to [inherit\] at (0.75) should be [0.625 1 1.75\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <scale> from [1\] to [10 -5 0\] at (0) should be [1\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions: property <scale> from [26 17 9\] to [2 1\] at (2) should be [-22 -15 -7\]]
|
[CSS Transitions: property <scale> from [26 17 9\] to [2 1\] at (2) should be [-22 -15 -7\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -809,9 +749,6 @@
|
||||||
[CSS Transitions with transition: all: property <scale> from [initial\] to [inherit\] at (0.25) should be [0.875 1 1.25\]]
|
[CSS Transitions with transition: all: property <scale> from [initial\] to [inherit\] at (0.25) should be [0.875 1 1.25\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions: property <scale> from [none\] to [4 3 2\] at (0) should be [1\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <scale> from [unset\] to [1.5 1\] at (2) should be [2 1\]]
|
[CSS Animations: property <scale> from [unset\] to [1.5 1\] at (2) should be [2 1\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -827,9 +764,6 @@
|
||||||
[CSS Transitions with transition: all: property <scale> from [2 0.5 1\] to [inherit\] at (-1) should be [3.5 0 0\]]
|
[CSS Transitions with transition: all: property <scale> from [2 0.5 1\] to [inherit\] at (-1) should be [3.5 0 0\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <scale> from [26 17 9\] to [2 1\] at (1) should be [2 1\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <scale> from [initial\] to [inherit\] at (0.25) should be [0.875 1 1.25\]]
|
[CSS Animations: property <scale> from [initial\] to [inherit\] at (0.25) should be [0.875 1 1.25\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -908,9 +842,6 @@
|
||||||
[CSS Animations: property <scale> from neutral to [1.5 1\] at (1) should be [1.5 1\]]
|
[CSS Animations: property <scale> from neutral to [1.5 1\] at (1) should be [1.5 1\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions: property <scale> from [2 0.5 1\] to [inherit\] at (0) should be [2 0.5\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <scale> from [2 0.5 1\] to [initial\] at (0.25) should be [1.75 0.6251\]]
|
[CSS Transitions with transition: all: property <scale> from [2 0.5 1\] to [initial\] at (0.25) should be [1.75 0.6251\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -944,9 +875,6 @@
|
||||||
[CSS Transitions with transition: all: property <scale> from neutral to [1.5 1\] at (0.25) should be [1.2 1\]]
|
[CSS Transitions with transition: all: property <scale> from neutral to [1.5 1\] at (0.25) should be [1.2 1\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <scale> from [inherit\] to [2 0.5 1\] at (1) should be [2 0.5\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions: property <scale> from [inherit\] to [2 0.5 1\] at (0.75) should be [1.625 0.625 1.25\]]
|
[CSS Transitions: property <scale> from [inherit\] to [2 0.5 1\] at (0.75) should be [1.625 0.625 1.25\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -977,9 +905,6 @@
|
||||||
[CSS Transitions with transition: all: property <scale> from [initial\] to [inherit\] at (-1) should be [1.5 1 0\]]
|
[CSS Transitions with transition: all: property <scale> from [initial\] to [inherit\] at (-1) should be [1.5 1 0\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <scale> from [2 0.5 1\] to [initial\] at (0) should be [2 0.5\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <scale> from neutral to [1.5 1\] at (-1) should be [0.7 1\]]
|
[CSS Animations: property <scale> from neutral to [1.5 1\] at (-1) should be [0.7 1\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -1001,9 +926,6 @@
|
||||||
[CSS Transitions: property <scale> from [1\] to [10 -5 0\] at (0.75) should be [7.75 -3.5 0.25\]]
|
[CSS Transitions: property <scale> from [1\] to [10 -5 0\] at (0.75) should be [7.75 -3.5 0.25\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions: property <scale> from [initial\] to [2 0.5 1\] at (0) should be [1\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <scale> from [2 30 400\] to [10 110 1200\] at (2) should be [18 190 2000\]]
|
[CSS Animations: property <scale> from [2 30 400\] to [10 110 1200\] at (2) should be [18 190 2000\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -74,15 +74,6 @@
|
||||||
[translate interpolation]
|
[translate interpolation]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions: property <translate> from [480px 400px 320px\] to [240% 160%\] at (1) should be [240% 160%\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <translate> from [200px 100px 400px\] to [initial\] at (1) should be [0px\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions: property <translate> from [none\] to [8px 80% 800px\] at (0) should be [0px\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <translate> from [-100px -50px\] to [100px 50px\] at (2) should be [300px 150px\]]
|
[CSS Transitions with transition: all: property <translate> from [-100px -50px\] to [100px 50px\] at (2) should be [300px 150px\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -125,9 +116,6 @@
|
||||||
[CSS Transitions: property <translate> from [200px 100px 400px\] to [initial\] at (-1) should be [400px 200px 800px\]]
|
[CSS Transitions: property <translate> from [200px 100px 400px\] to [initial\] at (-1) should be [400px 200px 800px\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <translate> from [-100px -50px 100px\] to [0px\] at (1) should be [0px\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <translate> from [200px 100px 200px\] to [inherit\] at (2) should be [0px 300px 400px\]]
|
[CSS Animations: property <translate> from [200px 100px 200px\] to [inherit\] at (2) should be [0px 300px 400px\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -161,9 +149,6 @@
|
||||||
[CSS Transitions with transition: all: property <translate> from [unset\] to [20px\] at (0.75) should be [15px\]]
|
[CSS Transitions with transition: all: property <translate> from [unset\] to [20px\] at (0.75) should be [15px\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <translate> from [480px 400px 320px\] to [240% 160%\] at (1) should be [240% 160%\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <translate> from [200px 100px 400px\] to [initial\] at (0) should be [200px 100px 400px\]]
|
[CSS Animations: property <translate> from [200px 100px 400px\] to [initial\] at (0) should be [200px 100px 400px\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -173,15 +158,9 @@
|
||||||
[Web Animations: property <translate> from [inherit\] to [initial\] at (0) should be [100px 200px 300px\]]
|
[Web Animations: property <translate> from [inherit\] to [initial\] at (0) should be [100px 200px 300px\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions: property <translate> from [0px\] to [-100px -50px 100px\] at (0) should be [0px\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <translate> from [-100%\] to [100%\] at (0) should be [-100%\]]
|
[CSS Animations: property <translate> from [-100%\] to [100%\] at (0) should be [-100%\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions: property <translate> from [inherit\] to [initial\] at (1) should be [0px\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Web Animations: property <translate> from [-100px -50px\] to [100px 50px\] at (0.25) should be [-50px -25px\]]
|
[Web Animations: property <translate> from [-100px -50px\] to [100px 50px\] at (0.25) should be [-50px -25px\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -245,9 +224,6 @@
|
||||||
[CSS Animations: property <translate> from [220px 240px 260px\] to [300px 400px 500px\] at (0.125) should be [230px 260px 290px\]]
|
[CSS Animations: property <translate> from [220px 240px 260px\] to [300px 400px 500px\] at (0.125) should be [230px 260px 290px\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <translate> from [initial\] to [200px 100px 200px\] at (0) should be [0px\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Web Animations: property <translate> from [-100px\] to [100px\] at (-1) should be [-300px\]]
|
[Web Animations: property <translate> from [-100px\] to [100px\] at (-1) should be [-300px\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -341,9 +317,6 @@
|
||||||
[CSS Transitions: property <translate> from [200px 100px 200px\] to [inherit\] at (2) should be [0px 300px 400px\]]
|
[CSS Transitions: property <translate> from [200px 100px 200px\] to [inherit\] at (2) should be [0px 300px 400px\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <translate> from [initial\] to [inherit\] at (0) should be [0px\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Web Animations: property <translate> from [none\] to [8px 80% 800px\] at (1) should be [8px 80% 800px\]]
|
[Web Animations: property <translate> from [none\] to [8px 80% 800px\] at (1) should be [8px 80% 800px\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -437,9 +410,6 @@
|
||||||
[Web Animations: property <translate> from [-100px -50px 100px\] to [0px\] at (-1) should be [-200px -100px 200px\]]
|
[Web Animations: property <translate> from [-100px -50px 100px\] to [0px\] at (-1) should be [-200px -100px 200px\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <translate> from [0px\] to [-100px -50px 100px\] at (0) should be [0px\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <translate> from [-100px -50px\] to [100px 50px\] at (0.75) should be [50px 25px\]]
|
[CSS Transitions with transition: all: property <translate> from [-100px -50px\] to [100px 50px\] at (0.75) should be [50px 25px\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -527,9 +497,6 @@
|
||||||
[CSS Animations: property <translate> from neutral to [20px\] at (2) should be [30px\]]
|
[CSS Animations: property <translate> from neutral to [20px\] at (2) should be [30px\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions: property <translate> from [-100px -50px 100px\] to [0px\] at (1) should be [0px\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions: property <translate> from [-100px -50px\] to [100px 50px\] at (2) should be [300px 150px\]]
|
[CSS Transitions: property <translate> from [-100px -50px\] to [100px 50px\] at (2) should be [300px 150px\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -635,9 +602,6 @@
|
||||||
[Web Animations: property <translate> from [inherit\] to [initial\] at (-1) should be [200px 400px 600px\]]
|
[Web Animations: property <translate> from [inherit\] to [initial\] at (-1) should be [200px 400px 600px\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <translate> from [none\] to [8px 80% 800px\] at (0) should be [0px\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <translate> from [0px\] to [-100px -50px 100px\] at (0.75) should be [-75px -37.5px 75px\]]
|
[CSS Animations: property <translate> from [0px\] to [-100px -50px 100px\] at (0.75) should be [-75px -37.5px 75px\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -764,9 +728,6 @@
|
||||||
[Web Animations: property <translate> from [480px 400px 320px\] to [240% 160%\] at (0.875) should be [calc(210% + 60px) calc(140% + 50px) 40px\]]
|
[Web Animations: property <translate> from [480px 400px 320px\] to [240% 160%\] at (0.875) should be [calc(210% + 60px) calc(140% + 50px) 40px\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions with transition: all: property <translate> from [inherit\] to [initial\] at (1) should be [0px\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Transitions: property <translate> from [480px 400px 320px\] to [240% 160%\] at (0.125) should be [calc(420px + 30%) calc(350px + 20%) 280px\]]
|
[CSS Transitions: property <translate> from [480px 400px 320px\] to [240% 160%\] at (0.125) should be [calc(420px + 30%) calc(350px + 20%) 280px\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -788,9 +749,6 @@
|
||||||
[CSS Animations: property <translate> from [200px 100px 200px\] to [inherit\] at (0.75) should be [125px 175px 275px\]]
|
[CSS Animations: property <translate> from [200px 100px 200px\] to [inherit\] at (0.75) should be [125px 175px 275px\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions: property <translate> from [initial\] to [200px 100px 200px\] at (0) should be [0px\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <translate> from [none\] to [8px 80% 800px\] at (0.125) should be [1px 10% 100px\]]
|
[CSS Animations: property <translate> from [none\] to [8px 80% 800px\] at (0.125) should be [1px 10% 100px\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -1037,9 +995,6 @@
|
||||||
[CSS Transitions with transition: all: property <translate> from [none\] to [8px 80% 800px\] at (2) should be [16px 160% 1600px\]]
|
[CSS Transitions with transition: all: property <translate> from [none\] to [8px 80% 800px\] at (2) should be [16px 160% 1600px\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions: property <translate> from [initial\] to [inherit\] at (0) should be [0px\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <translate> from neutral to [20px\] at (0.75) should be [17.5px\]]
|
[CSS Animations: property <translate> from neutral to [20px\] at (0.75) should be [17.5px\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -1064,9 +1019,6 @@
|
||||||
[Web Animations: property <translate> from [220px 240px 260px\] to [300px 400px 500px\] at (1) should be [300px 400px 500px\]]
|
[Web Animations: property <translate> from [220px 240px 260px\] to [300px 400px 500px\] at (1) should be [300px 400px 500px\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Transitions: property <translate> from [200px 100px 400px\] to [initial\] at (1) should be [0px\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSS Animations: property <translate> from [200px 100px 400px\] to [initial\] at (0.25) should be [150px 75px 300px\]]
|
[CSS Animations: property <translate> from [200px 100px 400px\] to [initial\] at (0.25) should be [150px 75px 300px\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
[scale-parsing-valid.html]
|
|
||||||
[e.style['scale'\] = "100 200 1" should set the property value]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[e.style['scale'\] = "100 100 1" should set the property value]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -8,12 +8,3 @@
|
||||||
[e.style['translate'\] = "100px calc(10px - 10%)" should set the property value]
|
[e.style['translate'\] = "100px calc(10px - 10%)" should set the property value]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[e.style['translate'\] = "100px 200px 0px" should set the property value]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[e.style['translate'\] = "100px 0px 0px" should set the property value]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[e.style['translate'\] = "1px 2px 0" should set the property value]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
[transform-scale-percent-001.html]
|
||||||
|
expected: FAIL
|
Loading…
Add table
Add a link
Reference in a new issue