aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/layout/display_list/builder.rs6
-rw-r--r--components/layout/fragment.rs2
-rw-r--r--components/layout_thread/dom_wrapper.rs46
-rw-r--r--components/script/dom/canvasrenderingcontext2d.rs2
-rw-r--r--components/script/dom/element.rs13
-rw-r--r--components/script_layout_interface/wrapper_traits.rs6
-rw-r--r--components/selectors/matching.rs15
-rw-r--r--components/selectors/tree.rs7
-rw-r--r--components/servo_arc/Cargo.toml1
-rw-r--r--components/servo_arc/lib.rs90
-rw-r--r--components/style/Cargo.toml1
-rw-r--r--components/style/bloom.rs2
-rw-r--r--components/style/dom.rs7
-rw-r--r--components/style/font_face.rs2
-rw-r--r--components/style/gecko/conversions.rs7
-rw-r--r--components/style/gecko/url.rs370
-rw-r--r--components/style/gecko/wrapper.rs49
-rw-r--r--components/style/gecko_bindings/sugar/refptr.rs36
-rw-r--r--components/style/global_style_data.rs2
-rw-r--r--components/style/invalidation/element/element_wrapper.rs19
-rw-r--r--components/style/matching.rs2
-rw-r--r--components/style/properties/build.py1
-rw-r--r--components/style/properties/gecko.mako.rs207
-rw-r--r--components/style/properties/helpers/animated_properties.mako.rs2
-rw-r--r--components/style/properties/longhands/box.mako.rs3
-rw-r--r--components/style/properties/longhands/color.mako.rs130
-rw-r--r--components/style/properties/longhands/effects.mako.rs2
-rw-r--r--components/style/properties/longhands/inherited_text.mako.rs10
-rw-r--r--components/style/properties/properties.mako.rs2
-rw-r--r--components/style/rule_tree/mod.rs292
-rw-r--r--components/style/servo/url.rs18
-rw-r--r--components/style/shared_lock.rs18
-rw-r--r--components/style/sharing/mod.rs8
-rw-r--r--components/style/stylesheets/mod.rs17
-rw-r--r--components/style/stylesheets/rule_parser.rs4
-rw-r--r--components/style/values/animated/effects.rs4
-rw-r--r--components/style/values/computed/effects.rs2
-rw-r--r--components/style/values/computed/list.rs2
-rw-r--r--components/style/values/computed/motion.rs14
-rw-r--r--components/style/values/generics/effects.rs13
-rw-r--r--components/style/values/generics/url.rs19
-rw-r--r--components/style/values/specified/color.rs259
-rw-r--r--components/style/values/specified/effects.rs11
-rw-r--r--components/style/values/specified/image.rs7
-rw-r--r--components/style/values/specified/url.rs2
-rw-r--r--components/style_traits/arc_slice.rs15
-rw-r--r--tests/unit/style/rule_tree/bench.rs55
47 files changed, 892 insertions, 910 deletions
diff --git a/components/layout/display_list/builder.rs b/components/layout/display_list/builder.rs
index cc2585c3043..08fad71b4ea 100644
--- a/components/layout/display_list/builder.rs
+++ b/components/layout/display_list/builder.rs
@@ -1489,7 +1489,7 @@ impl Fragment {
state.add_display_item(DisplayItem::Rectangle(CommonDisplayItem::new(
base,
webrender_api::RectangleDisplayItem {
- color: self.style().get_color().color.to_layout(),
+ color: self.style().get_inherited_text().color.to_layout(),
},
)));
}
@@ -1967,9 +1967,9 @@ impl Fragment {
// TODO(emilio): Allow changing more properties by ::selection
// Paint the text with the color as described in its styling.
let text_color = if text_fragment.selected() {
- self.selected_style().get_color().color
+ self.selected_style().get_inherited_text().color
} else {
- self.style().get_color().color
+ self.style().get_inherited_text().color
};
// Determine the orientation and cursor to use.
diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs
index d3e9dbb6779..72029fb2484 100644
--- a/components/layout/fragment.rs
+++ b/components/layout/fragment.rs
@@ -1519,7 +1519,7 @@ impl Fragment {
}
pub fn color(&self) -> Color {
- self.style().get_color().color
+ self.style().get_inherited_text().color
}
/// Returns the text decoration line of this fragment, according to the style of the nearest ancestor
diff --git a/components/layout_thread/dom_wrapper.rs b/components/layout_thread/dom_wrapper.rs
index d738ef1151f..a0c1a8b7a61 100644
--- a/components/layout_thread/dom_wrapper.rs
+++ b/components/layout_thread/dom_wrapper.rs
@@ -715,6 +715,14 @@ impl<'le> TElement for ServoLayoutElement<'le> {
.map(ServoShadowRoot::from_layout_js)
}
}
+
+ fn local_name(&self) -> &LocalName {
+ self.element.local_name()
+ }
+
+ fn namespace(&self) -> &Namespace {
+ self.element.namespace()
+ }
}
impl<'le> PartialEq for ServoLayoutElement<'le> {
@@ -879,13 +887,19 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
}
#[inline]
- fn local_name(&self) -> &LocalName {
- self.element.local_name()
+ fn has_local_name(&self, name: &LocalName) -> bool {
+ self.element.local_name() == name
}
#[inline]
- fn namespace(&self) -> &Namespace {
- self.element.namespace()
+ fn has_namespace(&self, ns: &Namespace) -> bool {
+ self.element.namespace() == ns
+ }
+
+ #[inline]
+ fn is_same_type(&self, other: &Self) -> bool {
+ self.element.local_name() == other.element.local_name() &&
+ self.element.namespace() == other.element.namespace()
}
fn is_pseudo_element(&self) -> bool {
@@ -1266,8 +1280,8 @@ where
loop {
let next_node = if let Some(ref node) = current_node {
if let Some(element) = node.as_element() {
- if element.local_name() == &local_name!("summary") &&
- element.namespace() == &ns!(html)
+ if element.has_local_name(&local_name!("summary")) &&
+ element.has_namespace(&ns!(html))
{
self.current_node = None;
return Some(node.clone());
@@ -1286,8 +1300,10 @@ where
let node = self.current_node.clone();
let node = node.and_then(|node| {
if node.is_element() &&
- node.as_element().unwrap().local_name() == &local_name!("summary") &&
- node.as_element().unwrap().namespace() == &ns!(html)
+ node.as_element()
+ .unwrap()
+ .has_local_name(&local_name!("summary")) &&
+ node.as_element().unwrap().has_namespace(&ns!(html))
{
unsafe { node.dangerous_next_sibling() }
} else {
@@ -1437,13 +1453,19 @@ impl<'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> {
}
#[inline]
- fn local_name(&self) -> &LocalName {
- self.element.local_name()
+ fn has_local_name(&self, name: &LocalName) -> bool {
+ self.element.local_name() == name
}
#[inline]
- fn namespace(&self) -> &Namespace {
- self.element.namespace()
+ fn has_namespace(&self, ns: &Namespace) -> bool {
+ self.element.namespace() == ns
+ }
+
+ #[inline]
+ fn is_same_type(&self, other: &Self) -> bool {
+ self.element.local_name() == other.element.local_name() &&
+ self.element.namespace() == other.element.namespace()
}
fn match_pseudo_element(
diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs
index 2a26a1c5752..039ff1039f9 100644
--- a/components/script/dom/canvasrenderingcontext2d.rs
+++ b/components/script/dom/canvasrenderingcontext2d.rs
@@ -260,7 +260,7 @@ impl CanvasState {
match canvas_element.style() {
Some(ref s) if canvas_element.has_css_layout_box() => {
- Ok(s.get_color().color)
+ Ok(s.get_inherited_text().color)
},
_ => Ok(RGBA::new(0, 0, 0, 255)),
}
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs
index 66560172517..764c7ce6051 100644
--- a/components/script/dom/element.rs
+++ b/components/script/dom/element.rs
@@ -2982,12 +2982,17 @@ impl<'a> SelectorsElement for DomRoot<Element> {
})
}
- fn local_name(&self) -> &LocalName {
- Element::local_name(self)
+ fn has_local_name(&self, local_name: &LocalName) -> bool {
+ Element::local_name(self) == local_name
}
- fn namespace(&self) -> &Namespace {
- Element::namespace(self)
+ fn has_namespace(&self, ns: &Namespace) -> bool {
+ Element::namespace(self) == ns
+ }
+
+ fn is_same_type(&self, other: &Self) -> bool {
+ Element::local_name(self) == Element::local_name(other) &&
+ Element::namespace(self) == Element::namespace(other)
}
fn match_non_ts_pseudo_class<F>(
diff --git a/components/script_layout_interface/wrapper_traits.rs b/components/script_layout_interface/wrapper_traits.rs
index 0e1df2ac4c8..ae559474d06 100644
--- a/components/script_layout_interface/wrapper_traits.rs
+++ b/components/script_layout_interface/wrapper_traits.rs
@@ -391,7 +391,7 @@ pub trait ThreadSafeLayoutElement:
#[inline]
fn get_details_summary_pseudo(&self) -> Option<Self> {
- if self.local_name() == &local_name!("details") && self.namespace() == &ns!(html) {
+ if self.has_local_name(&local_name!("details")) && self.has_namespace(&ns!(html)) {
Some(self.with_pseudo(PseudoElementType::DetailsSummary))
} else {
None
@@ -400,8 +400,8 @@ pub trait ThreadSafeLayoutElement:
#[inline]
fn get_details_content_pseudo(&self) -> Option<Self> {
- if self.local_name() == &local_name!("details") &&
- self.namespace() == &ns!(html) &&
+ if self.has_local_name(&local_name!("details")) &&
+ self.has_namespace(&ns!(html)) &&
self.get_attr(&ns!(), &local_name!("open")).is_some()
{
Some(self.with_pseudo(PseudoElementType::DetailsContent))
diff --git a/components/selectors/matching.rs b/components/selectors/matching.rs
index 6554f2f9cc4..45acc13e7e1 100644
--- a/components/selectors/matching.rs
+++ b/components/selectors/matching.rs
@@ -596,7 +596,7 @@ where
&local_name.lower_name,
)
.borrow();
- element.local_name() == name
+ element.has_local_name(name)
}
/// Determines whether the given element matches the given compound selector.
@@ -681,11 +681,11 @@ where
Component::LocalName(ref local_name) => matches_local_name(element, local_name),
Component::ExplicitUniversalType | Component::ExplicitAnyNamespace => true,
Component::Namespace(_, ref url) | Component::DefaultNamespace(ref url) => {
- element.namespace() == url.borrow()
+ element.has_namespace(&url.borrow())
},
Component::ExplicitNoNamespace => {
let ns = crate::parser::namespace_empty_string::<E::Impl>();
- element.namespace() == ns.borrow()
+ element.has_namespace(&ns.borrow())
},
Component::ID(ref id) => {
element.has_id(id, context.shared.classes_and_ids_case_sensitivity())
@@ -898,11 +898,6 @@ where
}
#[inline]
-fn same_type<E: Element>(a: &E, b: &E) -> bool {
- a.local_name() == b.local_name() && a.namespace() == b.namespace()
-}
-
-#[inline]
fn nth_child_index<E>(
element: &E,
is_of_type: bool,
@@ -924,7 +919,7 @@ where
let mut curr = element.clone();
while let Some(e) = curr.prev_sibling_element() {
curr = e;
- if !is_of_type || same_type(element, &curr) {
+ if !is_of_type || element.is_same_type(&curr) {
if let Some(i) = c.lookup(curr.opaque()) {
return i - index;
}
@@ -945,7 +940,7 @@ where
};
while let Some(e) = next(curr) {
curr = e;
- if !is_of_type || same_type(element, &curr) {
+ if !is_of_type || element.is_same_type(&curr) {
// If we're computing indices from the left, check each element in the
// cache. We handle the indices-from-the-right case at the top of this
// function.
diff --git a/components/selectors/tree.rs b/components/selectors/tree.rs
index 611e40d6027..f892abd4e94 100644
--- a/components/selectors/tree.rs
+++ b/components/selectors/tree.rs
@@ -62,10 +62,13 @@ pub trait Element: Sized + Clone + Debug {
fn is_html_element_in_html_document(&self) -> bool;
- fn local_name(&self) -> &<Self::Impl as SelectorImpl>::BorrowedLocalName;
+ fn has_local_name(&self, local_name: &<Self::Impl as SelectorImpl>::BorrowedLocalName) -> bool;
/// Empty string for no namespace
- fn namespace(&self) -> &<Self::Impl as SelectorImpl>::BorrowedNamespaceUrl;
+ fn has_namespace(&self, ns: &<Self::Impl as SelectorImpl>::BorrowedNamespaceUrl) -> bool;
+
+ /// Whether this element and the `other` element have the same local name and namespace.
+ fn is_same_type(&self, other: &Self) -> bool;
fn attr_matches(
&self,
diff --git a/components/servo_arc/Cargo.toml b/components/servo_arc/Cargo.toml
index 58f1ea8ef0b..3581210c2f1 100644
--- a/components/servo_arc/Cargo.toml
+++ b/components/servo_arc/Cargo.toml
@@ -12,6 +12,7 @@ path = "lib.rs"
[features]
servo = ["serde"]
+gecko_refcount_logging = []
[dependencies]
nodrop = {version = "0.1.8"}
diff --git a/components/servo_arc/lib.rs b/components/servo_arc/lib.rs
index 09f381c62df..aa79140e044 100644
--- a/components/servo_arc/lib.rs
+++ b/components/servo_arc/lib.rs
@@ -42,7 +42,7 @@ use std::fmt;
use std::hash::{Hash, Hasher};
use std::iter::{ExactSizeIterator, Iterator};
use std::marker::PhantomData;
-use std::mem;
+use std::mem::{self, align_of, size_of};
use std::ops::{Deref, DerefMut};
use std::os::raw::c_void;
use std::process;
@@ -90,6 +90,9 @@ const STATIC_REFCOUNT: usize = usize::MAX;
/// usage of PhantomData.
///
/// [`Arc`]: https://doc.rust-lang.org/stable/std/sync/struct.Arc.html
+///
+/// cbindgen:derive-eq=false
+/// cbindgen:derive-neq=false
#[repr(C)]
pub struct Arc<T: ?Sized> {
p: ptr::NonNull<ArcInner<T>>,
@@ -112,7 +115,10 @@ pub struct Arc<T: ?Sized> {
/// Once the mutation is finished, you can call `.shareable()` and get a regular `Arc`
/// out of it.
///
-/// ```rust
+/// Ignore the doctest below there's no way to skip building with refcount
+/// logging during doc tests (see rust-lang/rust#45599).
+///
+/// ```rust,ignore
/// # use servo_arc::UniqueArc;
/// let data = [1, 2, 3, 4, 5];
/// let mut x = UniqueArc::new(data);
@@ -166,18 +172,35 @@ impl<T> Arc<T> {
/// Construct an `Arc<T>`
#[inline]
pub fn new(data: T) -> Self {
- let x = Box::new(ArcInner {
+ let ptr = Box::into_raw(Box::new(ArcInner {
count: atomic::AtomicUsize::new(1),
data,
- });
+ }));
+
+ #[cfg(feature = "gecko_refcount_logging")]
+ unsafe {
+ // FIXME(emilio): Would be so amazing to have
+ // std::intrinsics::type_name() around, so that we could also report
+ // a real size.
+ NS_LogCtor(ptr as *const _, b"ServoArc\0".as_ptr() as *const _, 8);
+ }
+
unsafe {
Arc {
- p: ptr::NonNull::new_unchecked(Box::into_raw(x)),
+ p: ptr::NonNull::new_unchecked(ptr),
phantom: PhantomData,
}
}
}
+ /// Construct an intentionally-leaked arc.
+ #[inline]
+ pub fn new_leaked(data: T) -> Self {
+ let arc = Self::new(data);
+ arc.mark_as_intentionally_leaked();
+ arc
+ }
+
/// Convert the Arc<T> to a raw pointer, suitable for use across FFI
///
/// Note: This returns a pointer to the data T, which is offset in the allocation.
@@ -287,9 +310,33 @@ impl<T: ?Sized> Arc<T> {
unsafe { &*self.ptr() }
}
- // Non-inlined part of `drop`. Just invokes the destructor.
+ #[inline(always)]
+ fn record_drop(&self) {
+ #[cfg(feature = "gecko_refcount_logging")]
+ unsafe {
+ NS_LogDtor(
+ self.ptr() as *const _,
+ b"ServoArc\0".as_ptr() as *const _,
+ 8,
+ );
+ }
+ }
+
+ /// Marks this `Arc` as intentionally leaked for the purposes of refcount
+ /// logging.
+ ///
+ /// It's a logic error to call this more than once, but it's not unsafe, as
+ /// it'd just report negative leaks.
+ #[inline(always)]
+ pub fn mark_as_intentionally_leaked(&self) {
+ self.record_drop();
+ }
+
+ // Non-inlined part of `drop`. Just invokes the destructor and calls the
+ // refcount logging machinery if enabled.
#[inline(never)]
unsafe fn drop_slow(&mut self) {
+ self.record_drop();
let _ = Box::from_raw(self.ptr());
}
@@ -305,6 +352,20 @@ impl<T: ?Sized> Arc<T> {
}
}
+#[cfg(feature = "gecko_refcount_logging")]
+extern "C" {
+ fn NS_LogCtor(
+ aPtr: *const std::os::raw::c_void,
+ aTypeName: *const std::os::raw::c_char,
+ aSize: u32,
+ );
+ fn NS_LogDtor(
+ aPtr: *const std::os::raw::c_void,
+ aTypeName: *const std::os::raw::c_char,
+ aSize: u32,
+ );
+}
+
impl<T: ?Sized> Clone for Arc<T> {
#[inline]
fn clone(&self) -> Self {
@@ -609,7 +670,6 @@ impl<H, T> Arc<HeaderSlice<H, [T]>> {
F: FnOnce(Layout) -> *mut u8,
I: Iterator<Item = T> + ExactSizeIterator,
{
- use std::mem::{align_of, size_of};
assert_ne!(size_of::<T>(), 0, "Need to think about ZST");
let inner_align = align_of::<ArcInner<HeaderSlice<H, [T; 0]>>>();
@@ -697,6 +757,15 @@ impl<H, T> Arc<HeaderSlice<H, [T]>> {
);
}
+ #[cfg(feature = "gecko_refcount_logging")]
+ unsafe {
+ if !is_static {
+ // FIXME(emilio): Would be so amazing to have
+ // std::intrinsics::type_name() around.
+ NS_LogCtor(ptr as *const _, b"ServoArc\0".as_ptr() as *const _, 8)
+ }
+ }
+
// Return the fat Arc.
assert_eq!(
size_of::<Self>(),
@@ -1248,11 +1317,18 @@ impl<A, B> ArcUnion<A, B> {
}
/// Returns true if the two values are pointer-equal.
+ #[inline]
pub fn ptr_eq(this: &Self, other: &Self) -> bool {
this.p == other.p
}
+ #[inline]
+ pub fn ptr(&self) -> ptr::NonNull<()> {
+ self.p
+ }
+
/// Returns an enum representing a borrow of either A or B.
+ #[inline]
pub fn borrow(&self) -> ArcUnionBorrow<A, B> {
if self.is_first() {
let ptr = self.p.as_ptr() as *const A;
diff --git a/components/style/Cargo.toml b/components/style/Cargo.toml
index 4d5f3e2e94d..05798b83bcb 100644
--- a/components/style/Cargo.toml
+++ b/components/style/Cargo.toml
@@ -22,6 +22,7 @@ servo = ["serde", "style_traits/servo", "servo_atoms", "servo_config", "html5eve
"cssparser/serde", "encoding_rs", "malloc_size_of/servo", "arrayvec/use_union",
"servo_url", "string_cache", "crossbeam-channel", "to_shmem/servo", "servo_arc/servo"]
gecko_debug = []
+gecko_refcount_logging = []
gecko_profiler = []
[dependencies]
diff --git a/components/style/bloom.rs b/components/style/bloom.rs
index d75d548ff71..c730547986b 100644
--- a/components/style/bloom.rs
+++ b/components/style/bloom.rs
@@ -19,7 +19,7 @@ thread_local! {
/// such that they can be reused across style traversals. StyleBloom is responsible
/// for ensuring that the bloom filter is zeroed when it is dropped.
static BLOOM_KEY: Arc<AtomicRefCell<BloomFilter>> =
- Arc::new(AtomicRefCell::new(BloomFilter::new()));
+ Arc::new_leaked(AtomicRefCell::new(BloomFilter::new()));
}
/// A struct that allows us to fast-reject deep descendant selectors avoiding
diff --git a/components/style/dom.rs b/components/style/dom.rs
index 5ee8443b91d..04d6a79b384 100644
--- a/components/style/dom.rs
+++ b/components/style/dom.rs
@@ -882,6 +882,13 @@ pub trait TElement:
hints: &mut V,
) where
V: Push<ApplicableDeclarationBlock>;
+
+ /// Returns element's local name.
+ fn local_name(&self) -> &<SelectorImpl as selectors::parser::SelectorImpl>::BorrowedLocalName;
+
+ /// Returns element's namespace.
+ fn namespace(&self)
+ -> &<SelectorImpl as selectors::parser::SelectorImpl>::BorrowedNamespaceUrl;
}
/// TNode and TElement aren't Send because we want to be careful and explicit
diff --git a/components/style/font_face.rs b/components/style/font_face.rs
index 655c8846f76..c8e7e65785b 100644
--- a/components/style/font_face.rs
+++ b/components/style/font_face.rs
@@ -55,7 +55,7 @@ impl OneOrMoreSeparated for Source {
#[repr(u8)]
#[allow(missing_docs)]
pub enum FontFaceSourceListComponent {
- Url(*const crate::gecko_bindings::structs::mozilla::css::URLValue),
+ Url(*const crate::gecko::url::CssUrl),
Local(*mut crate::gecko_bindings::structs::nsAtom),
FormatHint {
length: usize,
diff --git a/components/style/gecko/conversions.rs b/components/style/gecko/conversions.rs
index 06e201bf2b5..0be8a81e66a 100644
--- a/components/style/gecko/conversions.rs
+++ b/components/style/gecko/conversions.rs
@@ -122,11 +122,11 @@ impl nsStyleImage {
match image {
GenericImage::Gradient(boxed_gradient) => self.set_gradient(*boxed_gradient),
GenericImage::Url(ref url) => unsafe {
- bindings::Gecko_SetLayerImageImageValue(self, url.url_value_ptr())
+ bindings::Gecko_SetLayerImageImageValue(self, url);
},
GenericImage::Rect(ref image_rect) => {
unsafe {
- bindings::Gecko_SetLayerImageImageValue(self, image_rect.url.url_value_ptr());
+ bindings::Gecko_SetLayerImageImageValue(self, &image_rect.url);
bindings::Gecko_InitializeImageCropRect(self);
// Set CropRect
@@ -584,9 +584,10 @@ pub mod basic_shape {
impl<'a> From<&'a StyleShapeSource> for ClippingShape {
fn from(other: &'a StyleShapeSource) -> Self {
- use crate::values::generics::image::Image as GenericImage;
match other.mType {
StyleShapeSourceType::Image => unsafe {
+ use crate::values::generics::image::Image as GenericImage;
+
let shape_image = &*other.__bindgen_anon_1.mShapeImage.as_ref().mPtr;
let image = shape_image.into_image().expect("Cannot convert to Image");
match image {
diff --git a/components/style/gecko/url.rs b/components/style/gecko/url.rs
index dbbb3399da7..3a53f639afe 100644
--- a/components/style/gecko/url.rs
+++ b/components/style/gecko/url.rs
@@ -5,13 +5,11 @@
//! Common handling for the specified value CSS url() values.
use crate::gecko_bindings::bindings;
-use crate::gecko_bindings::structs::root::mozilla::css::URLValue;
-use crate::gecko_bindings::structs::root::mozilla::CORSMode;
-use crate::gecko_bindings::structs::root::nsStyleImageRequest;
-use crate::gecko_bindings::sugar::ownership::{FFIArcHelpers, HasArcFFI};
+use crate::gecko_bindings::structs;
+use crate::gecko_bindings::structs::nsStyleImageRequest;
use crate::gecko_bindings::sugar::refptr::RefPtr;
use crate::parser::{Parse, ParserContext};
-use crate::stylesheets::UrlExtraData;
+use crate::stylesheets::{CorsMode, UrlExtraData};
use crate::values::computed::{Context, ToComputedValue};
use cssparser::Parser;
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
@@ -27,25 +25,63 @@ use to_shmem::{SharedMemoryBuilder, ToShmem};
/// A CSS url() value for gecko.
#[css(function = "url")]
#[derive(Clone, Debug, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
+#[repr(C)]
pub struct CssUrl(pub Arc<CssUrlData>);
/// Data shared between CssUrls.
-#[derive(Clone, Debug, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
+///
+/// cbindgen:derive-eq=false
+/// cbindgen:derive-neq=false
+#[derive(Debug, SpecifiedValueInfo, ToCss, ToShmem)]
+#[repr(C)]
pub struct CssUrlData {
/// The URL in unresolved string form.
- serialization: String,
+ serialization: crate::OwnedStr,
/// The URL extra data.
#[css(skip)]
pub extra_data: UrlExtraData,
+
+ /// The CORS mode that will be used for the load.
+ #[css(skip)]
+ cors_mode: CorsMode,
+
+ /// Data to trigger a load from Gecko. This is mutable in C++.
+ ///
+ /// TODO(emilio): Maybe we can eagerly resolve URLs and make this immutable?
+ #[css(skip)]
+ load_data: LoadDataSource,
+}
+
+impl PartialEq for CssUrlData {
+ fn eq(&self, other: &Self) -> bool {
+ self.serialization == other.serialization &&
+ self.extra_data == other.extra_data &&
+ self.cors_mode == other.cors_mode
+ }
}
impl CssUrl {
+ fn parse_with_cors_mode<'i, 't>(
+ context: &ParserContext,
+ input: &mut Parser<'i, 't>,
+ cors_mode: CorsMode,
+ ) -> Result<Self, ParseError<'i>> {
+ let url = input.expect_url()?;
+ Ok(Self::parse_from_string(
+ url.as_ref().to_owned(),
+ context,
+ cors_mode,
+ ))
+ }
+
/// Parse a URL from a string value that is a valid CSS token for a URL.
- pub fn parse_from_string(url: String, context: &ParserContext) -> Self {
+ pub fn parse_from_string(url: String, context: &ParserContext, cors_mode: CorsMode) -> Self {
CssUrl(Arc::new(CssUrlData {
- serialization: url,
+ serialization: url.into(),
extra_data: context.url_data.clone(),
+ cors_mode,
+ load_data: LoadDataSource::Owned(LoadData::default()),
}))
}
@@ -85,27 +121,12 @@ impl CssUrlData {
}
}
-#[cfg(debug_assertions)]
-impl Drop for CssUrlData {
- fn drop(&mut self) {
- assert!(
- !URL_VALUE_TABLE
- .read()
- .unwrap()
- .contains_key(&CssUrlDataKey(self as *mut _ as *const _)),
- "All CssUrlData objects used as keys in URL_VALUE_TABLE should be \
- from shared memory style sheets, and so should never be dropped",
- );
- }
-}
-
impl Parse for CssUrl {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
- let url = input.expect_url()?;
- Ok(Self::parse_from_string(url.as_ref().to_owned(), context))
+ Self::parse_with_cors_mode(context, input, CorsMode::None)
}
}
@@ -122,143 +143,101 @@ impl MallocSizeOf for CssUrl {
}
}
-/// A key type for URL_VALUE_TABLE.
+/// A key type for LOAD_DATA_TABLE.
#[derive(Eq, Hash, PartialEq)]
-struct CssUrlDataKey(*const CssUrlData);
-
-unsafe impl Sync for CssUrlDataKey {}
-unsafe impl Send for CssUrlDataKey {}
-
-/// The source of a Gecko URLValue object for a SpecifiedUrl.
-#[derive(Clone, Debug)]
-pub enum URLValueSource {
- /// A strong reference to a Gecko URLValue object.
- URLValue(RefPtr<URLValue>),
- /// A CORSMode value used to lazily construct a Gecko URLValue object.
- ///
- /// The lazily created object will be stored in URL_VALUE_TABLE.
- CORSMode(CORSMode),
+struct LoadDataKey(*const LoadDataSource);
+
+unsafe impl Sync for LoadDataKey {}
+unsafe impl Send for LoadDataKey {}
+
+/// The load data for a given URL. This is mutable from C++, for now at least.
+#[repr(C)]
+#[derive(Debug)]
+pub struct LoadData {
+ resolved: RefPtr<structs::nsIURI>,
+ load_id: u64,
+ tried_to_resolve: bool,
}
-impl ToShmem for URLValueSource {
- fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> ManuallyDrop<Self> {
- ManuallyDrop::new(match self {
- URLValueSource::URLValue(r) => URLValueSource::CORSMode(r.mCORSMode),
- URLValueSource::CORSMode(c) => URLValueSource::CORSMode(*c),
- })
+impl Drop for LoadData {
+ fn drop(&mut self) {
+ if self.load_id != 0 {
+ unsafe {
+ bindings::Gecko_LoadData_DeregisterLoad(self);
+ }
+ }
}
}
-/// A specified non-image `url()` value.
-#[derive(Clone, Debug, SpecifiedValueInfo, ToCss, ToShmem)]
-pub struct SpecifiedUrl {
- /// The specified url value.
- pub url: CssUrl,
- /// Gecko's URLValue so that we can reuse it while rematching a
- /// property with this specified value.
- ///
- /// Box this to avoid SpecifiedUrl getting bigger than two words,
- /// and increasing the size of PropertyDeclaration.
- #[css(skip)]
- url_value: Box<URLValueSource>,
-}
-
-fn make_url_value(url: &CssUrl, cors_mode: CORSMode) -> RefPtr<URLValue> {
- unsafe {
- let ptr = bindings::Gecko_URLValue_Create(url.0.clone().into_strong(), cors_mode);
- // We do not expect Gecko_URLValue_Create returns null.
- debug_assert!(!ptr.is_null());
- RefPtr::from_addrefed(ptr)
+impl Default for LoadData {
+ fn default() -> Self {
+ Self {
+ resolved: RefPtr::null(),
+ load_id: 0,
+ tried_to_resolve: false,
+ }
}
}
-impl SpecifiedUrl {
- /// Parse a URL from a string value.
- pub fn parse_from_string(url: String, context: &ParserContext) -> Self {
- Self::from_css_url(CssUrl::parse_from_string(url, context))
- }
-
- fn from_css_url_with_cors(url: CssUrl, cors: CORSMode) -> Self {
- let url_value = Box::new(URLValueSource::URLValue(make_url_value(&url, cors)));
- Self { url, url_value }
- }
+/// The data for a load, or a lazy-loaded, static member that will be stored in
+/// LOAD_DATA_TABLE, keyed by the memory location of this object, which is
+/// always in the heap because it's inside the CssUrlData object.
+///
+/// This type is meant not to be used from C++ so we don't derive helper
+/// methods.
+///
+/// cbindgen:derive-helper-methods=false
+#[derive(Debug)]
+#[repr(u8, C)]
+pub enum LoadDataSource {
+ /// An owned copy of the load data.
+ Owned(LoadData),
+ /// A lazily-resolved copy of it.
+ Lazy,
+}
- fn from_css_url(url: CssUrl) -> Self {
- use crate::gecko_bindings::structs::root::mozilla::CORSMode_CORS_NONE;
- Self::from_css_url_with_cors(url, CORSMode_CORS_NONE)
- }
+impl LoadDataSource {
+ /// Gets the load data associated with the source.
+ ///
+ /// This relies on the source on being in a stable location if lazy.
+ #[inline]
+ pub unsafe fn get(&self) -> *const LoadData {
+ match *self {
+ LoadDataSource::Owned(ref d) => return d,
+ LoadDataSource::Lazy => {},
+ }
- fn from_css_url_with_cors_anonymous(url: CssUrl) -> Self {
- use crate::gecko_bindings::structs::root::mozilla::CORSMode_CORS_ANONYMOUS;
- Self::from_css_url_with_cors(url, CORSMode_CORS_ANONYMOUS)
- }
+ let key = LoadDataKey(self);
- fn with_url_value<F, T>(&self, f: F) -> T
- where
- F: FnOnce(&RefPtr<URLValue>) -> T,
- {
- match *self.url_value {
- URLValueSource::URLValue(ref r) => f(r),
- URLValueSource::CORSMode(cors_mode) => {
- {
- let guard = URL_VALUE_TABLE.read().unwrap();
- if let Some(r) = guard.get(&(CssUrlDataKey(&*self.url.0 as *const _))) {
- return f(r);
- }
- }
- let mut guard = URL_VALUE_TABLE.write().unwrap();
- let r = guard
- .entry(CssUrlDataKey(&*self.url.0 as *const _))
- .or_insert_with(|| make_url_value(&self.url, cors_mode));
- f(r)
- },
+ {
+ let guard = LOAD_DATA_TABLE.read().unwrap();
+ if let Some(r) = guard.get(&key) {
+ return &**r;
+ }
}
+ let mut guard = LOAD_DATA_TABLE.write().unwrap();
+ let r = guard.entry(key).or_insert_with(Default::default);
+ &**r
}
+}
- /// Clone a new, strong reference to the Gecko URLValue.
- pub fn clone_url_value(&self) -> RefPtr<URLValue> {
- self.with_url_value(RefPtr::clone)
- }
-
- /// Get a raw pointer to the URLValue held by this SpecifiedUrl, for FFI.
- pub fn url_value_ptr(&self) -> *mut URLValue {
- self.with_url_value(RefPtr::get)
+impl ToShmem for LoadDataSource {
+ fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> ManuallyDrop<Self> {
+ ManuallyDrop::new(match self {
+ LoadDataSource::Owned(..) => LoadDataSource::Lazy,
+ LoadDataSource::Lazy => LoadDataSource::Lazy,
+ })
}
}
-/// Clears URL_VALUE_TABLE. Entries in this table, which are for specified URL
+/// A specified non-image `url()` value.
+pub type SpecifiedUrl = CssUrl;
+
+/// Clears LOAD_DATA_TABLE. Entries in this table, which are for specified URL
/// values that come from shared memory style sheets, would otherwise persist
/// until the end of the process and be reported as leaks.
pub fn shutdown() {
- URL_VALUE_TABLE.write().unwrap().clear();
-}
-
-impl Parse for SpecifiedUrl {
- fn parse<'i, 't>(
- context: &ParserContext,
- input: &mut Parser<'i, 't>,
- ) -> Result<Self, ParseError<'i>> {
- CssUrl::parse(context, input).map(Self::from_css_url)
- }
-}
-
-impl PartialEq for SpecifiedUrl {
- fn eq(&self, other: &Self) -> bool {
- self.url.eq(&other.url)
- }
-}
-
-impl Eq for SpecifiedUrl {}
-
-impl MallocSizeOf for SpecifiedUrl {
- fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
- let mut n = self.url.size_of(ops);
- // Although this is a RefPtr, this is the primary reference because
- // SpecifiedUrl is responsible for creating the url_value. So we
- // measure unconditionally here.
- n += unsafe { bindings::Gecko_URLValue_SizeOfIncludingThis(self.url_value_ptr()) };
- n
- }
+ LOAD_DATA_TABLE.write().unwrap().clear();
}
impl ToComputedValue for SpecifiedUrl {
@@ -281,8 +260,8 @@ pub struct SpecifiedImageUrl(pub SpecifiedUrl);
impl SpecifiedImageUrl {
/// Parse a URL from a string value that is a valid CSS token for a URL.
- pub fn parse_from_string(url: String, context: &ParserContext) -> Self {
- SpecifiedImageUrl(SpecifiedUrl::parse_from_string(url, context))
+ pub fn parse_from_string(url: String, context: &ParserContext, cors_mode: CorsMode) -> Self {
+ SpecifiedImageUrl(SpecifiedUrl::parse_from_string(url, context, cors_mode))
}
/// Provides an alternate method for parsing that associates the URL
@@ -291,9 +270,11 @@ impl SpecifiedImageUrl {
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
- CssUrl::parse(context, input)
- .map(SpecifiedUrl::from_css_url_with_cors_anonymous)
- .map(SpecifiedImageUrl)
+ Ok(SpecifiedImageUrl(SpecifiedUrl::parse_with_cors_mode(
+ context,
+ input,
+ CorsMode::Anonymous,
+ )?))
}
}
@@ -320,99 +301,68 @@ impl ToComputedValue for SpecifiedImageUrl {
}
}
-fn serialize_computed_url<W>(
- url_value: &URLValue,
- dest: &mut CssWriter<W>,
- get_url: unsafe extern "C" fn(*const URLValue, *mut nsCString),
-) -> fmt::Result
-where
- W: Write,
-{
- dest.write_str("url(")?;
- unsafe {
- let mut string = nsCString::new();
- get_url(url_value, &mut string);
- string.as_str_unchecked().to_css(dest)?;
- }
- dest.write_char(')')
-}
-
/// The computed value of a CSS non-image `url()`.
///
/// The only difference between specified and computed URLs is the
/// serialization.
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)]
+#[repr(C)]
pub struct ComputedUrl(pub SpecifiedUrl);
-impl ToCss for ComputedUrl {
- fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
+impl ComputedUrl {
+ fn serialize_with<W>(
+ &self,
+ function: unsafe extern "C" fn(*const Self, *mut nsCString),
+ dest: &mut CssWriter<W>,
+ ) -> fmt::Result
where
W: Write,
{
- self.0
- .with_url_value(|r| serialize_computed_url(r, dest, bindings::Gecko_GetComputedURLSpec))
+ dest.write_str("url(")?;
+ unsafe {
+ let mut string = nsCString::new();
+ function(self, &mut string);
+ string.as_str_unchecked().to_css(dest)?;
+ }
+ dest.write_char(')')
}
}
-impl ComputedUrl {
- /// Convert from RefPtr<URLValue> to ComputedUrl.
- pub unsafe fn from_url_value(url_value: RefPtr<URLValue>) -> Self {
- let css_url = &*url_value.mCssUrl.mRawPtr;
- let url = CssUrl(CssUrlData::as_arc(&css_url).clone_arc());
- ComputedUrl(SpecifiedUrl {
- url,
- url_value: Box::new(URLValueSource::URLValue(url_value)),
- })
- }
-
- /// Clone a new, strong reference to the Gecko URLValue.
- pub fn clone_url_value(&self) -> RefPtr<URLValue> {
- self.0.clone_url_value()
- }
-
- /// Get a raw pointer to the URLValue held by this ComputedUrl, for FFI.
- pub fn url_value_ptr(&self) -> *mut URLValue {
- self.0.url_value_ptr()
+impl ToCss for ComputedUrl {
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
+ where
+ W: Write,
+ {
+ self.serialize_with(bindings::Gecko_GetComputedURLSpec, dest)
}
}
/// The computed value of a CSS image `url()`.
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)]
+#[repr(transparent)]
pub struct ComputedImageUrl(pub ComputedUrl);
+impl ComputedImageUrl {
+ /// Convert from nsStyleImageRequest to ComputedImageUrl.
+ pub unsafe fn from_image_request(image_request: &nsStyleImageRequest) -> Self {
+ image_request.mImageURL.clone()
+ }
+}
+
impl ToCss for ComputedImageUrl {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
- (self.0).0.with_url_value(|r| {
- serialize_computed_url(r, dest, bindings::Gecko_GetComputedImageURLSpec)
- })
- }
-}
-
-impl ComputedImageUrl {
- /// Convert from nsStyleImageReques to ComputedImageUrl.
- pub unsafe fn from_image_request(image_request: &nsStyleImageRequest) -> Self {
- let url_value = image_request.mImageValue.to_safe();
- ComputedImageUrl(ComputedUrl::from_url_value(url_value))
- }
-
- /// Clone a new, strong reference to the Gecko URLValue.
- pub fn clone_url_value(&self) -> RefPtr<URLValue> {
- self.0.clone_url_value()
- }
-
- /// Get a raw pointer to the URLValue held by this ComputedImageUrl, for FFI.
- pub fn url_value_ptr(&self) -> *mut URLValue {
- self.0.url_value_ptr()
+ self.0
+ .serialize_with(bindings::Gecko_GetComputedImageURLSpec, dest)
}
}
lazy_static! {
- /// A table mapping CssUrlData objects to their lazily created Gecko
- /// URLValue objects.
- static ref URL_VALUE_TABLE: RwLock<HashMap<CssUrlDataKey, RefPtr<URLValue>>> = {
+ /// A table mapping CssUrlData objects to their lazily created LoadData
+ /// objects.
+ static ref LOAD_DATA_TABLE: RwLock<HashMap<LoadDataKey, Box<LoadData>>> = {
Default::default()
};
}
diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs
index a1443d1ad8d..3ce9e6fe6ab 100644
--- a/components/style/gecko/wrapper.rs
+++ b/components/style/gecko/wrapper.rs
@@ -704,9 +704,8 @@ impl<'le> GeckoElement<'le> {
.map(GeckoElement)
}
} else {
- let binding_parent = unsafe { self.non_xul_xbl_binding_parent_raw_content().as_ref() }
- .map(GeckoNode::from_content)
- .and_then(|n| n.as_element());
+ let binding_parent =
+ unsafe { self.non_xul_xbl_binding_parent().as_ref() }.map(GeckoElement);
debug_assert!(
binding_parent ==
@@ -721,11 +720,10 @@ impl<'le> GeckoElement<'le> {
}
#[inline]
- fn non_xul_xbl_binding_parent_raw_content(&self) -> *mut nsIContent {
+ fn non_xul_xbl_binding_parent(&self) -> *mut RawGeckoElement {
debug_assert!(!self.is_xul_element());
- self.extended_slots().map_or(ptr::null_mut(), |slots| {
- slots._base.mBindingParent.raw::<nsIContent>()
- })
+ self.extended_slots()
+ .map_or(ptr::null_mut(), |slots| slots._base.mBindingParent.mRawPtr)
}
#[inline]
@@ -1168,6 +1166,19 @@ impl<'le> TElement for GeckoElement<'le> {
self.namespace_id() == structs::root::kNameSpaceID_XUL as i32
}
+ #[inline]
+ fn local_name(&self) -> &WeakAtom {
+ unsafe { WeakAtom::new(self.as_node().node_info().mInner.mName) }
+ }
+
+ #[inline]
+ fn namespace(&self) -> &WeakNamespace {
+ unsafe {
+ let namespace_manager = structs::nsContentUtils_sNameSpaceManager;
+ WeakNamespace::new((*namespace_manager).mURIArray[self.namespace_id() as usize].mRawPtr)
+ }
+ }
+
/// Return the list of slotted nodes of this node.
#[inline]
fn slotted_nodes(&self) -> &[Self::ConcreteNode] {
@@ -1736,7 +1747,7 @@ impl<'le> TElement for GeckoElement<'le> {
PropertyDeclaration::TextAlign(SpecifiedTextAlign::MozCenterOrInherit),
Importance::Normal,
);
- let arc = Arc::new(global_style_data.shared_lock.wrap(pdb));
+ let arc = Arc::new_leaked(global_style_data.shared_lock.wrap(pdb));
ApplicableDeclarationBlock::from_declarations(arc, ServoCascadeLevel::PresHints)
};
static ref TABLE_COLOR_RULE: ApplicableDeclarationBlock = {
@@ -1745,7 +1756,7 @@ impl<'le> TElement for GeckoElement<'le> {
PropertyDeclaration::Color(SpecifiedColor(Color::InheritFromBodyQuirk.into())),
Importance::Normal,
);
- let arc = Arc::new(global_style_data.shared_lock.wrap(pdb));
+ let arc = Arc::new_leaked(global_style_data.shared_lock.wrap(pdb));
ApplicableDeclarationBlock::from_declarations(arc, ServoCascadeLevel::PresHints)
};
static ref MATHML_LANG_RULE: ApplicableDeclarationBlock = {
@@ -1754,7 +1765,7 @@ impl<'le> TElement for GeckoElement<'le> {
PropertyDeclaration::XLang(SpecifiedLang(atom!("x-math"))),
Importance::Normal,
);
- let arc = Arc::new(global_style_data.shared_lock.wrap(pdb));
+ let arc = Arc::new_leaked(global_style_data.shared_lock.wrap(pdb));
ApplicableDeclarationBlock::from_declarations(arc, ServoCascadeLevel::PresHints)
};
static ref SVG_TEXT_DISABLE_ZOOM_RULE: ApplicableDeclarationBlock = {
@@ -1763,7 +1774,7 @@ impl<'le> TElement for GeckoElement<'le> {
PropertyDeclaration::XTextZoom(SpecifiedZoom(false)),
Importance::Normal,
);
- let arc = Arc::new(global_style_data.shared_lock.wrap(pdb));
+ let arc = Arc::new_leaked(global_style_data.shared_lock.wrap(pdb));
ApplicableDeclarationBlock::from_declarations(arc, ServoCascadeLevel::PresHints)
};
};
@@ -2073,16 +2084,18 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
}
#[inline]
- fn local_name(&self) -> &WeakAtom {
- unsafe { WeakAtom::new(self.as_node().node_info().mInner.mName) }
+ fn has_local_name(&self, name: &WeakAtom) -> bool {
+ self.local_name() == name
}
#[inline]
- fn namespace(&self) -> &WeakNamespace {
- unsafe {
- let namespace_manager = structs::nsContentUtils_sNameSpaceManager;
- WeakNamespace::new((*namespace_manager).mURIArray[self.namespace_id() as usize].mRawPtr)
- }
+ fn has_namespace(&self, ns: &WeakNamespace) -> bool {
+ self.namespace() == ns
+ }
+
+ #[inline]
+ fn is_same_type(&self, other: &Self) -> bool {
+ self.local_name() == other.local_name() && self.namespace() == other.namespace()
}
fn match_non_ts_pseudo_class<F>(
diff --git a/components/style/gecko_bindings/sugar/refptr.rs b/components/style/gecko_bindings/sugar/refptr.rs
index 90cc5284bc4..c5246733976 100644
--- a/components/style/gecko_bindings/sugar/refptr.rs
+++ b/components/style/gecko_bindings/sugar/refptr.rs
@@ -63,15 +63,25 @@ impl<T: RefCounted> RefPtr<T> {
}
}
+ /// Returns whether the current pointer is null.
+ pub fn is_null(&self) -> bool {
+ self.ptr.is_null()
+ }
+
+ /// Returns a null pointer.
+ pub fn null() -> Self {
+ Self {
+ ptr: ptr::null_mut(),
+ _marker: PhantomData,
+ }
+ }
+
/// Create a new RefPtr from a pointer obtained from FFI.
///
- /// The pointer must be valid and non null.
- ///
/// This method calls addref() internally
pub unsafe fn new(ptr: *mut T) -> Self {
- debug_assert!(!ptr.is_null());
let ret = RefPtr {
- ptr: ptr,
+ ptr,
_marker: PhantomData,
};
ret.addref();
@@ -97,8 +107,10 @@ impl<T: RefCounted> RefPtr<T> {
/// Addref the inner data, obviously leaky on its own.
pub fn addref(&self) {
- unsafe {
- (*self.ptr).addref();
+ if !self.ptr.is_null() {
+ unsafe {
+ (*self.ptr).addref();
+ }
}
}
@@ -106,7 +118,9 @@ impl<T: RefCounted> RefPtr<T> {
///
/// Call only when the data actually needs releasing.
pub unsafe fn release(&self) {
- (*self.ptr).release();
+ if !self.ptr.is_null() {
+ (*self.ptr).release();
+ }
}
}
@@ -130,6 +144,7 @@ impl<T: RefCounted> UniqueRefPtr<T> {
impl<T: RefCounted> Deref for RefPtr<T> {
type Target = T;
fn deref(&self) -> &T {
+ debug_assert!(!self.ptr.is_null());
unsafe { &*self.ptr }
}
}
@@ -152,7 +167,6 @@ impl<T: RefCounted> structs::RefPtr<T> {
///
/// Must be called on a valid, non-null structs::RefPtr<T>.
pub unsafe fn to_safe(&self) -> RefPtr<T> {
- debug_assert!(!self.mRawPtr.is_null());
let r = RefPtr {
ptr: self.mRawPtr,
_marker: PhantomData,
@@ -290,9 +304,9 @@ impl_threadsafe_refcount!(
bindings::Gecko_ReleaseURLExtraDataArbitraryThread
);
impl_threadsafe_refcount!(
- structs::mozilla::css::URLValue,
- bindings::Gecko_AddRefCSSURLValueArbitraryThread,
- bindings::Gecko_ReleaseCSSURLValueArbitraryThread
+ structs::nsIURI,
+ bindings::Gecko_AddRefnsIURIArbitraryThread,
+ bindings::Gecko_ReleasensIURIArbitraryThread
);
impl_threadsafe_refcount!(
structs::mozilla::css::GridTemplateAreasValue,
diff --git a/components/style/global_style_data.rs b/components/style/global_style_data.rs
index 90936ff7172..e19cab37bfa 100644
--- a/components/style/global_style_data.rs
+++ b/components/style/global_style_data.rs
@@ -125,7 +125,7 @@ lazy_static! {
};
/// Global style data
pub static ref GLOBAL_STYLE_DATA: GlobalStyleData = GlobalStyleData {
- shared_lock: SharedRwLock::new(),
+ shared_lock: SharedRwLock::new_leaked(),
options: StyleSystemOptions::default(),
};
}
diff --git a/components/style/invalidation/element/element_wrapper.rs b/components/style/invalidation/element/element_wrapper.rs
index 91f0705853c..cb63e611348 100644
--- a/components/style/invalidation/element/element_wrapper.rs
+++ b/components/style/invalidation/element/element_wrapper.rs
@@ -312,13 +312,24 @@ where
}
#[inline]
- fn local_name(&self) -> &<Self::Impl as ::selectors::SelectorImpl>::BorrowedLocalName {
- self.element.local_name()
+ fn has_local_name(
+ &self,
+ local_name: &<Self::Impl as ::selectors::SelectorImpl>::BorrowedLocalName,
+ ) -> bool {
+ self.element.has_local_name(local_name)
+ }
+
+ #[inline]
+ fn has_namespace(
+ &self,
+ ns: &<Self::Impl as ::selectors::SelectorImpl>::BorrowedNamespaceUrl,
+ ) -> bool {
+ self.element.has_namespace(ns)
}
#[inline]
- fn namespace(&self) -> &<Self::Impl as ::selectors::SelectorImpl>::BorrowedNamespaceUrl {
- self.element.namespace()
+ fn is_same_type(&self, other: &Self) -> bool {
+ self.element.is_same_type(&other.element)
}
fn attr_matches(
diff --git a/components/style/matching.rs b/components/style/matching.rs
index 583e41ad82e..52d12037707 100644
--- a/components/style/matching.rs
+++ b/components/style/matching.rs
@@ -718,7 +718,7 @@ pub trait MatchMethods: TElement {
let device = context.shared.stylist.device();
// Needed for the "inherit from body" quirk.
- let text_color = new_primary_style.get_color().clone_color();
+ let text_color = new_primary_style.get_inherited_text().clone_color();
device.set_body_text_color(text_color);
}
}
diff --git a/components/style/properties/build.py b/components/style/properties/build.py
index 3cc2a60134e..1967ed3238a 100644
--- a/components/style/properties/build.py
+++ b/components/style/properties/build.py
@@ -25,7 +25,6 @@ STYLE_STRUCT_LIST = [
"background",
"border",
"box",
- "color",
"column",
"counters",
"effects",
diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs
index dd5bcf2febf..9f56c42cc2b 100644
--- a/components/style/properties/gecko.mako.rs
+++ b/components/style/properties/gecko.mako.rs
@@ -33,13 +33,11 @@ use crate::gecko_bindings::bindings::Gecko_nsStyleFont_CopyLangFrom;
use crate::gecko_bindings::bindings::Gecko_SetListStyleImageNone;
use crate::gecko_bindings::bindings::Gecko_SetListStyleImageImageValue;
use crate::gecko_bindings::bindings::Gecko_SetNullImageValue;
-use crate::gecko_bindings::bindings::{Gecko_ResetFilters, Gecko_CopyFiltersFrom};
use crate::gecko_bindings::structs;
use crate::gecko_bindings::structs::nsCSSPropertyID;
use crate::gecko_bindings::structs::mozilla::PseudoStyleType;
-use crate::gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordDataMut};
+use crate::gecko_bindings::sugar::ns_style_coord::CoordDataMut;
use crate::gecko_bindings::sugar::refptr::RefPtr;
-use crate::gecko::values::GeckoStyleCoordConvertible;
use crate::gecko::values::round_border_to_device_pixels;
use crate::logical_geometry::WritingMode;
use crate::media_queries::Device;
@@ -52,11 +50,10 @@ use std::marker::PhantomData;
use std::mem::{forget, uninitialized, zeroed, ManuallyDrop};
use std::{cmp, ops, ptr};
use crate::values::{self, CustomIdent, Either, KeyframesName, None_};
-use crate::values::computed::{NonNegativeLength, Percentage, TransitionProperty};
+use crate::values::computed::{Percentage, TransitionProperty};
use crate::values::computed::url::ComputedImageUrl;
use crate::values::computed::BorderStyle;
use crate::values::computed::font::FontSize;
-use crate::values::computed::effects::Filter;
use crate::values::generics::column::ColumnCount;
use crate::values::generics::transform::TransformStyle;
use crate::values::generics::url::UrlOrNone;
@@ -278,7 +275,7 @@ impl ComputedValuesInner {
#[allow(non_snake_case)]
pub fn has_moz_binding(&self) -> bool {
- !self.get_box().gecko.mBinding.mRawPtr.is_null()
+ !self.get_box().gecko.mBinding.is_none()
}
}
@@ -550,7 +547,7 @@ def set_gecko_property(ffi_name, expr):
unsafe {
bindings::Gecko_nsStyleSVGPaint_SetURLValue(
paint,
- url.url_value_ptr(),
+ &url
)
}
}
@@ -591,7 +588,6 @@ def set_gecko_property(ffi_name, expr):
#[allow(non_snake_case)]
pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
- use crate::values::computed::url::ComputedUrl;
use crate::values::generics::svg::{SVGPaint, SVGPaintKind};
use self::structs::nsStyleSVGPaintType;
use self::structs::nsStyleSVGFallbackType;
@@ -613,8 +609,7 @@ def set_gecko_property(ffi_name, expr):
nsStyleSVGPaintType::eStyleSVGPaintType_ContextStroke => SVGPaintKind::ContextStroke,
nsStyleSVGPaintType::eStyleSVGPaintType_Server => {
SVGPaintKind::PaintServer(unsafe {
- let url = RefPtr::new(*paint.mPaint.mPaintServer.as_ref());
- ComputedUrl::from_url_value(url)
+ paint.mPaint.mPaintServer.as_ref().clone()
})
}
nsStyleSVGPaintType::eStyleSVGPaintType_Color => {
@@ -735,45 +730,6 @@ def set_gecko_property(ffi_name, expr):
}
</%def>
-<%def name="impl_css_url(ident, gecko_ffi_name)">
- #[allow(non_snake_case)]
- pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
- match v {
- UrlOrNone::Url(ref url) => {
- self.gecko.${gecko_ffi_name}.set_move(url.clone_url_value())
- }
- UrlOrNone::None => {
- unsafe {
- self.gecko.${gecko_ffi_name}.clear();
- }
- }
- }
- }
- #[allow(non_snake_case)]
- pub fn copy_${ident}_from(&mut self, other: &Self) {
- unsafe {
- self.gecko.${gecko_ffi_name}.set(&other.gecko.${gecko_ffi_name});
- }
- }
- #[allow(non_snake_case)]
- pub fn reset_${ident}(&mut self, other: &Self) {
- self.copy_${ident}_from(other)
- }
-
- #[allow(non_snake_case)]
- pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
- use crate::values::computed::url::ComputedUrl;
-
- if self.gecko.${gecko_ffi_name}.mRawPtr.is_null() {
- return UrlOrNone::none()
- }
-
- UrlOrNone::Url(unsafe {
- ComputedUrl::from_url_value(self.gecko.${gecko_ffi_name}.to_safe())
- })
- }
-</%def>
-
<%def name="impl_logical(name, **kwargs)">
${helpers.logical_setter(name)}
</%def>
@@ -879,7 +835,6 @@ impl Clone for ${style_struct.gecko_struct_name} {
"SVGOpacity": impl_svg_opacity,
"SVGPaint": impl_svg_paint,
"SVGWidth": impl_svg_length,
- "url::UrlOrNone": impl_css_url,
}
def longhand_method(longhand):
@@ -2164,8 +2119,7 @@ fn static_assert() {
animation-iteration-count animation-timing-function
clear transition-duration transition-delay
transition-timing-function transition-property
- transform-style -moz-binding shape-outside
- -webkit-line-clamp""" %>
+ transform-style shape-outside -webkit-line-clamp""" %>
<%self:impl_trait style_struct_name="Box" skip_longhands="${skip_box_longhands}">
#[inline]
pub fn set_display(&mut self, v: longhands::display::computed_value::T) {
@@ -2205,7 +2159,7 @@ fn static_assert() {
gecko_inexhaustive=True,
) %>
${impl_keyword('clear', 'mBreakType', clear_keyword)}
- ${impl_css_url('_moz_binding', 'mBinding')}
+
${impl_transition_time_value('delay', 'Delay')}
${impl_transition_time_value('duration', 'Duration')}
${impl_transition_timing_function()}
@@ -2834,10 +2788,7 @@ fn static_assert() {
}
UrlOrNone::Url(ref url) => {
unsafe {
- Gecko_SetListStyleImageImageValue(
- &mut *self.gecko,
- url.url_value_ptr(),
- );
+ Gecko_SetListStyleImageImageValue(&mut *self.gecko, url);
}
}
}
@@ -2973,8 +2924,7 @@ fn static_assert() {
${impl_simple_copy('_x_span', 'mSpan')}
</%self:impl_trait>
-<%self:impl_trait style_struct_name="Effects"
- skip_longhands="clip filter">
+<%self:impl_trait style_struct_name="Effects" skip_longhands="clip">
pub fn set_clip(&mut self, v: longhands::clip::computed_value::T) {
use crate::gecko_bindings::structs::NS_STYLE_CLIP_AUTO;
use crate::gecko_bindings::structs::NS_STYLE_CLIP_RECT;
@@ -3082,138 +3032,6 @@ fn static_assert() {
Either::First(ClipRect { top, right, bottom, left })
}
-
- <%
- # This array is several filter function which has percentage or
- # number value for function of clone / set.
- # The setting / cloning process of other function(e.g. Blur / HueRotate) is
- # different from these function. So this array don't include such function.
- FILTER_FUNCTIONS = [ 'Brightness', 'Contrast', 'Grayscale', 'Invert',
- 'Opacity', 'Saturate', 'Sepia' ]
- %>
-
- pub fn set_filter<I>(&mut self, v: I)
- where
- I: IntoIterator<Item = Filter>,
- I::IntoIter: ExactSizeIterator,
- {
- use crate::values::generics::effects::Filter::*;
- use crate::gecko_bindings::structs::nsStyleFilter;
- use crate::gecko_bindings::structs::NS_STYLE_FILTER_BLUR;
- use crate::gecko_bindings::structs::NS_STYLE_FILTER_BRIGHTNESS;
- use crate::gecko_bindings::structs::NS_STYLE_FILTER_CONTRAST;
- use crate::gecko_bindings::structs::NS_STYLE_FILTER_GRAYSCALE;
- use crate::gecko_bindings::structs::NS_STYLE_FILTER_INVERT;
- use crate::gecko_bindings::structs::NS_STYLE_FILTER_OPACITY;
- use crate::gecko_bindings::structs::NS_STYLE_FILTER_SATURATE;
- use crate::gecko_bindings::structs::NS_STYLE_FILTER_SEPIA;
- use crate::gecko_bindings::structs::NS_STYLE_FILTER_HUE_ROTATE;
- use crate::gecko_bindings::structs::NS_STYLE_FILTER_DROP_SHADOW;
-
- fn fill_filter(m_type: u32, value: CoordDataValue, gecko_filter: &mut nsStyleFilter){
- gecko_filter.mType = m_type;
- gecko_filter.mFilterParameter.set_value(value);
- }
-
- let v = v.into_iter();
- unsafe {
- Gecko_ResetFilters(&mut *self.gecko, v.len());
- }
- debug_assert_eq!(v.len(), self.gecko.mFilters.len());
-
- for (servo, gecko_filter) in v.zip(self.gecko.mFilters.iter_mut()) {
- match servo {
- % for func in FILTER_FUNCTIONS:
- ${func}(factor) => fill_filter(NS_STYLE_FILTER_${func.upper()},
- CoordDataValue::Factor(factor.0),
- gecko_filter),
- % endfor
- Blur(length) => fill_filter(NS_STYLE_FILTER_BLUR,
- CoordDataValue::Coord(length.0.to_i32_au()),
- gecko_filter),
-
- HueRotate(angle) => fill_filter(NS_STYLE_FILTER_HUE_ROTATE,
- CoordDataValue::from(angle),
- gecko_filter),
-
- DropShadow(shadow) => {
- gecko_filter.mType = NS_STYLE_FILTER_DROP_SHADOW;
- unsafe {
- let ref mut union = gecko_filter.__bindgen_anon_1;
- ptr::write(union.mDropShadow.as_mut(), shadow);
- }
- },
- Url(ref url) => {
- unsafe {
- bindings::Gecko_nsStyleFilter_SetURLValue(gecko_filter, url.url_value_ptr());
- }
- },
- }
- }
- }
-
- pub fn copy_filter_from(&mut self, other: &Self) {
- unsafe {
- Gecko_CopyFiltersFrom(&other.gecko as *const _ as *mut _, &mut *self.gecko);
- }
- }
-
- pub fn reset_filter(&mut self, other: &Self) {
- self.copy_filter_from(other)
- }
-
- pub fn clone_filter(&self) -> longhands::filter::computed_value::T {
- use crate::values::generics::effects::Filter;
- use crate::values::computed::url::ComputedUrl;
- use crate::gecko_bindings::structs::NS_STYLE_FILTER_BLUR;
- use crate::gecko_bindings::structs::NS_STYLE_FILTER_BRIGHTNESS;
- use crate::gecko_bindings::structs::NS_STYLE_FILTER_CONTRAST;
- use crate::gecko_bindings::structs::NS_STYLE_FILTER_GRAYSCALE;
- use crate::gecko_bindings::structs::NS_STYLE_FILTER_INVERT;
- use crate::gecko_bindings::structs::NS_STYLE_FILTER_OPACITY;
- use crate::gecko_bindings::structs::NS_STYLE_FILTER_SATURATE;
- use crate::gecko_bindings::structs::NS_STYLE_FILTER_SEPIA;
- use crate::gecko_bindings::structs::NS_STYLE_FILTER_HUE_ROTATE;
- use crate::gecko_bindings::structs::NS_STYLE_FILTER_DROP_SHADOW;
- use crate::gecko_bindings::structs::NS_STYLE_FILTER_URL;
-
- longhands::filter::computed_value::List(self.gecko.mFilters.iter().map(|filter| {
- match filter.mType {
- % for func in FILTER_FUNCTIONS:
- NS_STYLE_FILTER_${func.upper()} => {
- Filter::${func}(
- GeckoStyleCoordConvertible::from_gecko_style_coord(
- &filter.mFilterParameter
- ).unwrap()
- )
- },
- % endfor
- NS_STYLE_FILTER_BLUR => {
- Filter::Blur(NonNegativeLength::from_gecko_style_coord(
- &filter.mFilterParameter
- ).unwrap())
- },
- NS_STYLE_FILTER_HUE_ROTATE => {
- Filter::HueRotate(GeckoStyleCoordConvertible::from_gecko_style_coord(
- &filter.mFilterParameter,
- ).unwrap())
- },
- NS_STYLE_FILTER_DROP_SHADOW => {
- Filter::DropShadow(unsafe {
- (*filter.__bindgen_anon_1.mDropShadow.as_ref()).clone()
- })
- },
- NS_STYLE_FILTER_URL => {
- Filter::Url(unsafe {
- let url = RefPtr::new(*filter.__bindgen_anon_1.mURL.as_ref());
- ComputedUrl::from_url_value(url)
- })
- }
- _ => unreachable!("Unknown filter function?"),
- }
- }).collect())
- }
-
</%self:impl_trait>
<%self:impl_trait style_struct_name="InheritedBox">
@@ -3537,9 +3355,6 @@ clip-path
}
</%self:impl_trait>
-<%self:impl_trait style_struct_name="Color">
-</%self:impl_trait>
-
<%self:impl_trait style_struct_name="InheritedUI" skip_longhands="cursor">
pub fn set_cursor(&mut self, v: longhands::cursor::computed_value::T) {
self.gecko.mCursor = v.keyword;
@@ -3550,7 +3365,7 @@ clip-path
unsafe {
Gecko_SetCursorImageValue(
&mut self.gecko.mCursorImages[i],
- v.images[i].url.url_value_ptr(),
+ &v.images[i].url
);
}
@@ -3769,7 +3584,7 @@ clip-path
unsafe {
bindings::Gecko_SetContentDataImageValue(
&mut self.gecko.mContents[i],
- url.url_value_ptr(),
+ url,
)
}
}
diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs
index d3b3ecd11e4..48f499c7ec3 100644
--- a/components/style/properties/helpers/animated_properties.mako.rs
+++ b/components/style/properties/helpers/animated_properties.mako.rs
@@ -22,7 +22,7 @@ use std::mem::{self, ManuallyDrop};
use crate::hash::FxHashMap;
use super::ComputedValues;
use crate::values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
-use crate::values::animated::effects::Filter as AnimatedFilter;
+use crate::values::animated::effects::AnimatedFilter;
#[cfg(feature = "gecko")] use crate::values::computed::TransitionProperty;
use crate::values::computed::{ClipRect, Context};
use crate::values::computed::ToComputedValue;
diff --git a/components/style/properties/longhands/box.mako.rs b/components/style/properties/longhands/box.mako.rs
index da9e5b2e767..f37d5968b24 100644
--- a/components/style/properties/longhands/box.mako.rs
+++ b/components/style/properties/longhands/box.mako.rs
@@ -390,7 +390,7 @@ ${helpers.predefined_type(
"OffsetRotate",
"computed::OffsetRotate::auto()",
products="gecko",
- animation_value_type="none",
+ animation_value_type="ComputedValue",
gecko_pref="layout.css.motion-path.enabled",
spec="https://drafts.fxtf.org/motion-1/#offset-rotate-property",
servo_restyle_damage="reflow_out_of_flow"
@@ -644,7 +644,6 @@ ${helpers.predefined_type(
"basic_shape::FloatAreaShape",
"generics::basic_shape::ShapeSource::None",
products="gecko",
- boxed=True,
animation_value_type="basic_shape::FloatAreaShape",
flags="APPLIES_TO_FIRST_LETTER",
spec="https://drafts.csswg.org/css-shapes/#shape-outside-property",
diff --git a/components/style/properties/longhands/color.mako.rs b/components/style/properties/longhands/color.mako.rs
deleted file mode 100644
index a83787dd48e..00000000000
--- a/components/style/properties/longhands/color.mako.rs
+++ /dev/null
@@ -1,130 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
-
-<%namespace name="helpers" file="/helpers.mako.rs" />
-
-<% data.new_style_struct("Color", inherited=True) %>
-
-<% from data import to_rust_ident %>
-
-${helpers.predefined_type(
- "color",
- "ColorPropertyValue",
- "::cssparser::RGBA::new(0, 0, 0, 255)",
- animation_value_type="AnimatedRGBA",
- flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
- ignored_when_colors_disabled="True",
- spec="https://drafts.csswg.org/css-color/#color",
-)}
-
-// FIXME(#15973): Add servo support for system colors
-//
-// FIXME(emilio): Move outside of mako.
-% if product == "gecko":
-pub mod system_colors {
- <%
- # These are actually parsed. See nsCSSProps::kColorKTable
- system_colors = """activeborder activecaption appworkspace background buttonface
- buttonhighlight buttonshadow buttontext captiontext graytext highlight
- highlighttext inactiveborder inactivecaption inactivecaptiontext
- infobackground infotext menu menutext scrollbar threeddarkshadow
- threedface threedhighlight threedlightshadow threedshadow window
- windowframe windowtext -moz-buttondefault -moz-buttonhoverface
- -moz-buttonhovertext -moz-cellhighlight -moz-cellhighlighttext
- -moz-eventreerow -moz-field -moz-fieldtext -moz-dialog -moz-dialogtext
- -moz-dragtargetzone -moz-gtk-info-bar-text -moz-html-cellhighlight
- -moz-html-cellhighlighttext -moz-mac-buttonactivetext
- -moz-gtk-buttonactivetext
- -moz-mac-chrome-active -moz-mac-chrome-inactive
- -moz-mac-defaultbuttontext -moz-mac-focusring -moz-mac-menuselect
- -moz-mac-menushadow -moz-mac-menutextdisable -moz-mac-menutextselect
- -moz-mac-disabledtoolbartext -moz-mac-secondaryhighlight
- -moz-mac-vibrancy-light -moz-mac-vibrancy-dark
- -moz-mac-vibrant-titlebar-light -moz-mac-vibrant-titlebar-dark
- -moz-mac-menupopup
- -moz-mac-menuitem -moz-mac-active-menuitem -moz-mac-source-list
- -moz-mac-source-list-selection -moz-mac-active-source-list-selection
- -moz-mac-tooltip
- -moz-menuhover -moz-menuhovertext -moz-menubartext -moz-menubarhovertext
- -moz-oddtreerow -moz-win-mediatext -moz-win-communicationstext
- -moz-win-accentcolor -moz-win-accentcolortext
- -moz-nativehyperlinktext -moz-comboboxtext -moz-combobox""".split()
-
- # These are not parsed but must be serialized
- # They are only ever set directly by Gecko
- extra_colors = """WindowBackground WindowForeground WidgetBackground WidgetForeground
- WidgetSelectBackground WidgetSelectForeground Widget3DHighlight Widget3DShadow
- TextBackground TextForeground TextSelectBackground TextSelectForeground
- TextSelectForegroundCustom TextSelectBackgroundDisabled TextSelectBackgroundAttention
- TextHighlightBackground TextHighlightForeground IMERawInputBackground
- IMERawInputForeground IMERawInputUnderline IMESelectedRawTextBackground
- IMESelectedRawTextForeground IMESelectedRawTextUnderline
- IMEConvertedTextBackground IMEConvertedTextForeground IMEConvertedTextUnderline
- IMESelectedConvertedTextBackground IMESelectedConvertedTextForeground
- IMESelectedConvertedTextUnderline SpellCheckerUnderline""".split()
- %>
- use crate::gecko_bindings::bindings::Gecko_GetLookAndFeelSystemColor;
- use crate::gecko_bindings::structs::root::mozilla::LookAndFeel_ColorID;
- use std::fmt::{self, Write};
- use style_traits::{CssWriter, ToCss};
- use to_shmem::impl_trivial_to_shmem;
- use crate::values::computed::{Context, ToComputedValue};
-
- pub type SystemColor = LookAndFeel_ColorID;
-
- // It's hard to implement MallocSizeOf for LookAndFeel_ColorID because it
- // is a bindgen type. So we implement it on the typedef instead.
- malloc_size_of_is_0!(SystemColor);
-
- impl_trivial_to_shmem!(SystemColor);
-
- impl ToCss for SystemColor {
- fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
- where
- W: Write,
- {
- let s = match *self {
- % for color in system_colors + extra_colors:
- LookAndFeel_ColorID::eColorID_${to_rust_ident(color)} => "${color}",
- % endfor
- LookAndFeel_ColorID::eColorID_LAST_COLOR => unreachable!(),
- };
- dest.write_str(s)
- }
- }
-
- impl ToComputedValue for SystemColor {
- type ComputedValue = u32; // nscolor
-
- #[inline]
- fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue {
- unsafe {
- Gecko_GetLookAndFeelSystemColor(
- *self as i32,
- cx.device().document(),
- )
- }
- }
-
- #[inline]
- fn from_computed_value(_: &Self::ComputedValue) -> Self {
- unreachable!()
- }
- }
-
- impl SystemColor {
- pub fn from_ident<'i, 't>(ident: &str) -> Result<Self, ()> {
- ascii_case_insensitive_phf_map! {
- color_name -> SystemColor = {
- % for color in system_colors:
- "${color}" => LookAndFeel_ColorID::eColorID_${to_rust_ident(color)},
- % endfor
- }
- }
-
- color_name(ident).cloned().ok_or(())
- }
- }
-}
-% endif
diff --git a/components/style/properties/longhands/effects.mako.rs b/components/style/properties/longhands/effects.mako.rs
index 9bb8adda32e..c50a0d18ca6 100644
--- a/components/style/properties/longhands/effects.mako.rs
+++ b/components/style/properties/longhands/effects.mako.rs
@@ -47,6 +47,8 @@ ${helpers.predefined_type(
"Filter",
None,
vector=True,
+ simple_vector_bindings=True,
+ gecko_ffi_name="mFilters",
separator="Space",
animation_value_type="AnimatedFilterList",
vector_animation_type="with_zero",
diff --git a/components/style/properties/longhands/inherited_text.mako.rs b/components/style/properties/longhands/inherited_text.mako.rs
index e8f56cf2cde..58331efa6bd 100644
--- a/components/style/properties/longhands/inherited_text.mako.rs
+++ b/components/style/properties/longhands/inherited_text.mako.rs
@@ -7,6 +7,16 @@
<% data.new_style_struct("InheritedText", inherited=True, gecko_name="Text") %>
${helpers.predefined_type(
+ "color",
+ "ColorPropertyValue",
+ "::cssparser::RGBA::new(0, 0, 0, 255)",
+ animation_value_type="AnimatedRGBA",
+ flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
+ ignored_when_colors_disabled="True",
+ spec="https://drafts.csswg.org/css-color/#color",
+)}
+
+${helpers.predefined_type(
"line-height",
"LineHeight",
"computed::LineHeight::normal()",
diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs
index 520b4a32b51..c2b390c89d9 100644
--- a/components/style/properties/properties.mako.rs
+++ b/components/style/properties/properties.mako.rs
@@ -2832,7 +2832,7 @@ impl ComputedValues {
/// style.resolve_color(style.get_border().clone_border_top_color());
#[inline]
pub fn resolve_color(&self, color: computed::Color) -> RGBA {
- color.to_rgba(self.get_color().clone_color())
+ color.to_rgba(self.get_inherited_text().clone_color())
}
}
diff --git a/components/style/rule_tree/mod.rs b/components/style/rule_tree/mod.rs
index d653b6be99d..34222103241 100644
--- a/components/style/rule_tree/mod.rs
+++ b/components/style/rule_tree/mod.rs
@@ -9,12 +9,14 @@
use crate::applicable_declarations::ApplicableDeclarationList;
#[cfg(feature = "gecko")]
use crate::gecko::selector_parser::PseudoElement;
+use crate::hash::{self, FxHashMap};
use crate::properties::{Importance, LonghandIdSet, PropertyDeclarationBlock};
use crate::shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
use crate::stylesheets::{Origin, StyleRule};
use crate::thread_state;
#[cfg(feature = "gecko")]
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
+use parking_lot::RwLock;
use servo_arc::{Arc, ArcBorrow, ArcUnion, ArcUnionBorrow};
use smallvec::SmallVec;
use std::io::{self, Write};
@@ -81,13 +83,25 @@ impl MallocSizeOf for RuleTree {
while let Some(node) = stack.pop() {
n += unsafe { ops.malloc_size_of(node.ptr()) };
- stack.extend(unsafe { (*node.ptr()).iter_children() });
+ stack.extend(unsafe {
+ (*node.ptr())
+ .children
+ .read()
+ .iter()
+ .map(|(_k, v)| v.clone())
+ });
}
n
}
}
+#[derive(Debug, Eq, Hash, PartialEq)]
+struct ChildKey(CascadeLevel, ptr::NonNull<()>);
+
+unsafe impl Send for ChildKey {}
+unsafe impl Sync for ChildKey {}
+
/// A style source for the rule node. It can either be a CSS style rule or a
/// declaration block.
///
@@ -110,6 +124,11 @@ impl StyleSource {
StyleSource(ArcUnion::from_first(rule))
}
+ #[inline]
+ fn key(&self) -> ptr::NonNull<()> {
+ self.0.ptr()
+ }
+
/// Creates a StyleSource from a PropertyDeclarationBlock.
pub fn from_declarations(decls: Arc<Locked<PropertyDeclarationBlock>>) -> Self {
StyleSource(ArcUnion::from_second(decls))
@@ -570,7 +589,7 @@ const RULE_TREE_GC_INTERVAL: usize = 300;
/// [3]: https://html.spec.whatwg.org/multipage/#presentational-hints
/// [4]: https://drafts.csswg.org/css-scoping/#shadow-cascading
#[repr(u8)]
-#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd)]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd)]
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
pub enum CascadeLevel {
/// Normal User-Agent rules.
@@ -697,23 +716,6 @@ impl CascadeLevel {
}
}
-// The root node never has siblings, but needs a free count. We use the same
-// storage for both to save memory.
-struct PrevSiblingOrFreeCount(AtomicPtr<RuleNode>);
-impl PrevSiblingOrFreeCount {
- fn new() -> Self {
- PrevSiblingOrFreeCount(AtomicPtr::new(ptr::null_mut()))
- }
-
- unsafe fn as_prev_sibling(&self) -> &AtomicPtr<RuleNode> {
- &self.0
- }
-
- unsafe fn as_free_count(&self) -> &AtomicUsize {
- mem::transmute(&self.0)
- }
-}
-
/// A node in the rule tree.
pub struct RuleNode {
/// The root node. Only the root has no root pointer, for obvious reasons.
@@ -732,15 +734,14 @@ pub struct RuleNode {
level: CascadeLevel,
refcount: AtomicUsize,
- first_child: AtomicPtr<RuleNode>,
- next_sibling: AtomicPtr<RuleNode>,
- /// Previous sibling pointer for all non-root nodes.
- ///
- /// For the root, stores the of RuleNodes we have added to the free list
- /// since the last GC. (We don't update this if we rescue a RuleNode from
- /// the free list. It's just used as a heuristic to decide when to run GC.)
- prev_sibling_or_free_count: PrevSiblingOrFreeCount,
+ /// Only used for the root, stores the number of free rule nodes that are
+ /// around.
+ free_count: AtomicUsize,
+
+ /// The children of a given rule node. Children remove themselves from here
+ /// when they go away.
+ children: RwLock<FxHashMap<ChildKey, WeakRuleNode>>,
/// The next item in the rule tree free list, that starts on the root node.
///
@@ -755,8 +756,7 @@ unsafe impl Sync for RuleTree {}
unsafe impl Send for RuleTree {}
// On Gecko builds, hook into the leak checking machinery.
-#[cfg(feature = "gecko")]
-#[cfg(debug_assertions)]
+#[cfg(feature = "gecko_refcount_logging")]
mod gecko_leak_checking {
use super::RuleNode;
use std::mem::size_of;
@@ -789,15 +789,13 @@ mod gecko_leak_checking {
#[inline(always)]
fn log_new(_ptr: *const RuleNode) {
- #[cfg(feature = "gecko")]
- #[cfg(debug_assertions)]
+ #[cfg(feature = "gecko_refcount_logging")]
gecko_leak_checking::log_ctor(_ptr);
}
#[inline(always)]
fn log_drop(_ptr: *const RuleNode) {
- #[cfg(feature = "gecko")]
- #[cfg(debug_assertions)]
+ #[cfg(feature = "gecko_refcount_logging")]
gecko_leak_checking::log_dtor(_ptr);
}
@@ -815,9 +813,8 @@ impl RuleNode {
source: Some(source),
level: level,
refcount: AtomicUsize::new(1),
- first_child: AtomicPtr::new(ptr::null_mut()),
- next_sibling: AtomicPtr::new(ptr::null_mut()),
- prev_sibling_or_free_count: PrevSiblingOrFreeCount::new(),
+ children: Default::default(),
+ free_count: AtomicUsize::new(0),
next_free: AtomicPtr::new(ptr::null_mut()),
}
}
@@ -829,75 +826,39 @@ impl RuleNode {
source: None,
level: CascadeLevel::UANormal,
refcount: AtomicUsize::new(1),
- first_child: AtomicPtr::new(ptr::null_mut()),
- next_sibling: AtomicPtr::new(ptr::null_mut()),
- prev_sibling_or_free_count: PrevSiblingOrFreeCount::new(),
+ free_count: AtomicUsize::new(0),
+ children: Default::default(),
next_free: AtomicPtr::new(FREE_LIST_SENTINEL),
}
}
- fn is_root(&self) -> bool {
- self.parent.is_none()
- }
-
- fn next_sibling(&self) -> Option<WeakRuleNode> {
- // We use acquire semantics here to ensure proper synchronization while
- // inserting in the child list.
- let ptr = self.next_sibling.load(Ordering::Acquire);
- if ptr.is_null() {
- None
- } else {
- Some(WeakRuleNode::from_ptr(ptr))
- }
+ fn key(&self) -> Option<ChildKey> {
+ Some(ChildKey(self.level, self.source.as_ref()?.key()))
}
- fn prev_sibling(&self) -> &AtomicPtr<RuleNode> {
- debug_assert!(!self.is_root());
- unsafe { self.prev_sibling_or_free_count.as_prev_sibling() }
+ fn is_root(&self) -> bool {
+ self.parent.is_none()
}
fn free_count(&self) -> &AtomicUsize {
debug_assert!(self.is_root());
- unsafe { self.prev_sibling_or_free_count.as_free_count() }
+ &self.free_count
}
/// Remove this rule node from the child list.
///
- /// This method doesn't use proper synchronization, and it's expected to be
- /// called in a single-threaded fashion, thus the unsafety.
- ///
/// This is expected to be called before freeing the node from the free
- /// list.
+ /// list, on the main thread.
unsafe fn remove_from_child_list(&self) {
debug!(
"Remove from child list: {:?}, parent: {:?}",
self as *const RuleNode,
self.parent.as_ref().map(|p| p.ptr())
);
- // NB: The other siblings we use in this function can also be dead, so
- // we can't use `get` here, since it asserts.
- let prev_sibling = self.prev_sibling().swap(ptr::null_mut(), Ordering::Relaxed);
-
- let next_sibling = self.next_sibling.swap(ptr::null_mut(), Ordering::Relaxed);
- // Store the `next` pointer as appropriate, either in the previous
- // sibling, or in the parent otherwise.
- if prev_sibling.is_null() {
- let parent = self.parent.as_ref().unwrap();
- parent
- .get()
- .first_child
- .store(next_sibling, Ordering::Relaxed);
- } else {
- let previous = &*prev_sibling;
- previous.next_sibling.store(next_sibling, Ordering::Relaxed);
- }
-
- // Store the previous sibling pointer in the next sibling if present,
- // otherwise we're done.
- if !next_sibling.is_null() {
- let next = &*next_sibling;
- next.prev_sibling().store(prev_sibling, Ordering::Relaxed);
+ if let Some(parent) = self.parent.as_ref() {
+ let weak = parent.get().children.write().remove(&self.key().unwrap());
+ assert_eq!(weak.unwrap().ptr() as *const _, self as *const _);
}
}
@@ -933,25 +894,13 @@ impl RuleNode {
}
let _ = write!(writer, "\n");
- for child in self.iter_children() {
+ for (_, child) in self.children.read().iter() {
child
.upgrade()
.get()
.dump(guards, writer, indent + INDENT_INCREMENT);
}
}
-
- fn iter_children(&self) -> RuleChildrenListIter {
- // See next_sibling to see why we need Acquire semantics here.
- let first_child = self.first_child.load(Ordering::Acquire);
- RuleChildrenListIter {
- current: if first_child.is_null() {
- None
- } else {
- Some(WeakRuleNode::from_ptr(first_child))
- },
- }
- }
}
#[derive(Clone)]
@@ -975,22 +924,21 @@ impl StrongRuleNode {
fn new(n: Box<RuleNode>) -> Self {
debug_assert_eq!(n.parent.is_none(), !n.source.is_some());
- let ptr = Box::into_raw(n);
- log_new(ptr);
+ // TODO(emilio): Use into_raw_non_null when it's stable.
+ let ptr = unsafe { ptr::NonNull::new_unchecked(Box::into_raw(n)) };
+ log_new(ptr.as_ptr());
debug!("Creating rule node: {:p}", ptr);
StrongRuleNode::from_ptr(ptr)
}
- fn from_ptr(ptr: *mut RuleNode) -> Self {
- StrongRuleNode {
- p: ptr::NonNull::new(ptr).expect("Pointer must not be null"),
- }
+ fn from_ptr(p: ptr::NonNull<RuleNode>) -> Self {
+ StrongRuleNode { p }
}
fn downgrade(&self) -> WeakRuleNode {
- WeakRuleNode::from_ptr(self.ptr())
+ WeakRuleNode::from_ptr(self.p)
}
/// Get the parent rule node of this rule node.
@@ -1004,80 +952,44 @@ impl StrongRuleNode {
source: StyleSource,
level: CascadeLevel,
) -> StrongRuleNode {
- let mut last = None;
-
- // NB: This is an iterator over _weak_ nodes.
- //
- // It's fine though, because nothing can make us GC while this happens,
- // and this happens to be hot.
- //
- // TODO(emilio): We could actually make this even less hot returning a
- // WeakRuleNode, and implementing this on WeakRuleNode itself...
- for child in self.get().iter_children() {
- let child_node = unsafe { &*child.ptr() };
- if child_node.level == level && child_node.source.as_ref().unwrap() == &source {
- return child.upgrade();
- }
- last = Some(child);
- }
-
- let mut node = Box::new(RuleNode::new(root, self.clone(), source.clone(), level));
- let new_ptr: *mut RuleNode = &mut *node;
+ use parking_lot::RwLockUpgradableReadGuard;
- loop {
- let next;
+ let key = ChildKey(level, source.key());
- {
- let last_node = last.as_ref().map(|l| unsafe { &*l.ptr() });
- let next_sibling_ptr = match last_node {
- Some(ref l) => &l.next_sibling,
- None => &self.get().first_child,
- };
+ let read_guard = self.get().children.upgradable_read();
+ if let Some(child) = read_guard.get(&key) {
+ return child.upgrade();
+ }
- // We use `AqcRel` semantics to ensure the initializing writes
- // in `node` are visible after the swap succeeds.
- let existing =
- next_sibling_ptr.compare_and_swap(ptr::null_mut(), new_ptr, Ordering::AcqRel);
-
- if existing.is_null() {
- // Now we know we're in the correct position in the child
- // list, we can set the back pointer, knowing that this will
- // only be accessed again in a single-threaded manner when
- // we're sweeping possibly dead nodes.
- if let Some(ref l) = last {
- node.prev_sibling().store(l.ptr(), Ordering::Relaxed);
- }
+ match RwLockUpgradableReadGuard::upgrade(read_guard).entry(key) {
+ hash::map::Entry::Occupied(ref occupied) => occupied.get().upgrade(),
+ hash::map::Entry::Vacant(vacant) => {
+ let new_node = StrongRuleNode::new(Box::new(RuleNode::new(
+ root,
+ self.clone(),
+ source.clone(),
+ level,
+ )));
- return StrongRuleNode::new(node);
- }
+ vacant.insert(new_node.downgrade());
- // Existing is not null: some thread inserted a child node since
- // we accessed `last`.
- next = WeakRuleNode::from_ptr(existing);
-
- if unsafe { &*next.ptr() }.source.as_ref().unwrap() == &source {
- // That node happens to be for the same style source, use
- // that, and let node fall out of scope.
- return next.upgrade();
- }
- }
-
- // Try again inserting after the new last child.
- last = Some(next);
+ new_node
+ },
}
}
/// Raw pointer to the RuleNode
+ #[inline]
pub fn ptr(&self) -> *mut RuleNode {
self.p.as_ptr()
}
fn get(&self) -> &RuleNode {
if cfg!(debug_assertions) {
- let node = unsafe { &*self.ptr() };
+ let node = unsafe { &*self.p.as_ptr() };
assert!(node.refcount.load(Ordering::Relaxed) > 0);
}
- unsafe { &*self.ptr() }
+ unsafe { &*self.p.as_ptr() }
}
/// Get the style source corresponding to this rule node. May return `None`
@@ -1107,13 +1019,13 @@ impl StrongRuleNode {
/// Returns whether this node has any child, only intended for testing
/// purposes, and called on a single-threaded fashion only.
pub unsafe fn has_children_for_testing(&self) -> bool {
- !self.get().first_child.load(Ordering::Relaxed).is_null()
+ !self.get().children.read().is_empty()
}
unsafe fn pop_from_free_list(&self) -> Option<WeakRuleNode> {
// NB: This can run from the root node destructor, so we can't use
// `get()`, since it asserts the refcount is bigger than zero.
- let me = &*self.ptr();
+ let me = &*self.p.as_ptr();
debug_assert!(me.is_root());
@@ -1139,7 +1051,7 @@ impl StrongRuleNode {
same time?"
);
debug_assert!(
- current != self.ptr(),
+ current != self.p.as_ptr(),
"How did the root end up in the free list?"
);
@@ -1159,17 +1071,17 @@ impl StrongRuleNode {
current, next
);
- Some(WeakRuleNode::from_ptr(current))
+ Some(WeakRuleNode::from_ptr(ptr::NonNull::new_unchecked(current)))
}
unsafe fn assert_free_list_has_no_duplicates_or_null(&self) {
assert!(cfg!(debug_assertions), "This is an expensive check!");
use crate::hash::FxHashSet;
- let me = &*self.ptr();
+ let me = &*self.p.as_ptr();
assert!(me.is_root());
- let mut current = self.ptr();
+ let mut current = self.p.as_ptr();
let mut seen = FxHashSet::default();
while current != FREE_LIST_SENTINEL {
let next = (*current).next_free.load(Ordering::Relaxed);
@@ -1188,21 +1100,21 @@ impl StrongRuleNode {
// NB: This can run from the root node destructor, so we can't use
// `get()`, since it asserts the refcount is bigger than zero.
- let me = &*self.ptr();
+ let me = &*self.p.as_ptr();
debug_assert!(me.is_root(), "Can't call GC on a non-root node!");
while let Some(weak) = self.pop_from_free_list() {
- let node = &*weak.ptr();
+ let node = &*weak.p.as_ptr();
if node.refcount.load(Ordering::Relaxed) != 0 {
// Nothing to do, the node is still alive.
continue;
}
- debug!("GC'ing {:?}", weak.ptr());
+ debug!("GC'ing {:?}", weak.p.as_ptr());
node.remove_from_child_list();
- log_drop(weak.ptr());
- let _ = Box::from_raw(weak.ptr());
+ log_drop(weak.p.as_ptr());
+ let _ = Box::from_raw(weak.p.as_ptr());
}
me.free_count().store(0, Ordering::Relaxed);
@@ -1509,7 +1421,7 @@ impl Clone for StrongRuleNode {
);
debug_assert!(self.get().refcount.load(Ordering::Relaxed) > 0);
self.get().refcount.fetch_add(1, Ordering::Relaxed);
- StrongRuleNode::from_ptr(self.ptr())
+ StrongRuleNode::from_ptr(self.p)
}
}
@@ -1537,7 +1449,7 @@ impl Drop for StrongRuleNode {
return;
}
- debug_assert_eq!(node.first_child.load(Ordering::Acquire), ptr::null_mut());
+ debug_assert!(node.children.read().is_empty());
if node.parent.is_none() {
debug!("Dropping root node!");
// The free list should be null by this point
@@ -1655,41 +1567,25 @@ impl Drop for StrongRuleNode {
impl<'a> From<&'a StrongRuleNode> for WeakRuleNode {
fn from(node: &'a StrongRuleNode) -> Self {
- WeakRuleNode::from_ptr(node.ptr())
+ WeakRuleNode::from_ptr(node.p)
}
}
impl WeakRuleNode {
+ #[inline]
+ fn ptr(&self) -> *mut RuleNode {
+ self.p.as_ptr()
+ }
+
fn upgrade(&self) -> StrongRuleNode {
debug!("Upgrading weak node: {:p}", self.ptr());
let node = unsafe { &*self.ptr() };
node.refcount.fetch_add(1, Ordering::Relaxed);
- StrongRuleNode::from_ptr(self.ptr())
- }
-
- fn from_ptr(ptr: *mut RuleNode) -> Self {
- WeakRuleNode {
- p: ptr::NonNull::new(ptr).expect("Pointer must not be null"),
- }
- }
-
- fn ptr(&self) -> *mut RuleNode {
- self.p.as_ptr()
+ StrongRuleNode::from_ptr(self.p)
}
-}
-struct RuleChildrenListIter {
- current: Option<WeakRuleNode>,
-}
-
-impl Iterator for RuleChildrenListIter {
- type Item = WeakRuleNode;
-
- fn next(&mut self) -> Option<Self::Item> {
- self.current.take().map(|current| {
- self.current = unsafe { &*current.ptr() }.next_sibling();
- current
- })
+ fn from_ptr(p: ptr::NonNull<RuleNode>) -> Self {
+ WeakRuleNode { p }
}
}
diff --git a/components/style/servo/url.rs b/components/style/servo/url.rs
index fd7726289be..8e011796e79 100644
--- a/components/style/servo/url.rs
+++ b/components/style/servo/url.rs
@@ -5,14 +5,12 @@
//! Common handling for the specified value CSS url() values.
use crate::parser::{Parse, ParserContext};
+use crate::stylesheets::CorsMode;
+use crate::values::computed::{Context, ToComputedValue};
use cssparser::Parser;
+use servo_arc::Arc;
use servo_url::ServoUrl;
use std::fmt::{self, Write};
-// Note: We use std::sync::Arc rather than servo_arc::Arc here because the
-// nonzero optimization is important in keeping the size of SpecifiedUrl below
-// the threshold.
-use crate::values::computed::{Context, ToComputedValue};
-use servo_arc::Arc;
use style_traits::{CssWriter, ParseError, ToCss};
/// A CSS url() value for servo.
@@ -44,7 +42,9 @@ pub struct CssUrl {
impl CssUrl {
/// Try to parse a URL from a string value that is a valid CSS token for a
/// URL.
- pub fn parse_from_string(url: String, context: &ParserContext) -> Self {
+ ///
+ /// FIXME(emilio): Should honor CorsMode.
+ pub fn parse_from_string(url: String, context: &ParserContext, _: CorsMode) -> Self {
let serialization = Arc::new(url);
let resolved = context.url_data.join(&serialization).ok();
CssUrl {
@@ -121,7 +121,11 @@ impl Parse for CssUrl {
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
let url = input.expect_url()?;
- Ok(Self::parse_from_string(url.as_ref().to_owned(), context))
+ Ok(Self::parse_from_string(
+ url.as_ref().to_owned(),
+ context,
+ CorsMode::None,
+ ))
}
}
diff --git a/components/style/shared_lock.rs b/components/style/shared_lock.rs
index 073c696fa3d..d46370952d3 100644
--- a/components/style/shared_lock.rs
+++ b/components/style/shared_lock.rs
@@ -71,6 +71,24 @@ impl SharedRwLock {
}
}
+ /// Create a new global shared lock (servo).
+ #[cfg(feature = "servo")]
+ pub fn new_leaked() -> Self {
+ SharedRwLock {
+ arc: Arc::new_leaked(RwLock::new(())),
+ }
+ }
+
+ /// Create a new global shared lock (gecko).
+ #[cfg(feature = "gecko")]
+ pub fn new_leaked() -> Self {
+ SharedRwLock {
+ cell: Some(Arc::new_leaked(AtomicRefCell::new(
+ SomethingZeroSizedButTyped,
+ ))),
+ }
+ }
+
/// Create a new read-only shared lock (gecko).
#[cfg(feature = "gecko")]
pub fn read_only() -> Self {
diff --git a/components/style/sharing/mod.rs b/components/style/sharing/mod.rs
index 3ce2a717dc8..5f5d1c6cab5 100644
--- a/components/style/sharing/mod.rs
+++ b/components/style/sharing/mod.rs
@@ -485,8 +485,12 @@ type SharingCache<E> = SharingCacheBase<StyleSharingCandidate<E>>;
type TypelessSharingCache = SharingCacheBase<FakeCandidate>;
type StoredSharingCache = Arc<AtomicRefCell<TypelessSharingCache>>;
-thread_local!(static SHARING_CACHE_KEY: StoredSharingCache =
- Arc::new(AtomicRefCell::new(TypelessSharingCache::default())));
+thread_local! {
+ // TODO(emilio): Looks like a few of these should just be Rc<RefCell<>> or
+ // something. No need for atomics in the thread-local code.
+ static SHARING_CACHE_KEY: StoredSharingCache =
+ Arc::new_leaked(AtomicRefCell::new(TypelessSharingCache::default()));
+}
/// An LRU cache of the last few nodes seen, so that we can aggressively try to
/// reuse their styles.
diff --git a/components/style/stylesheets/mod.rs b/components/style/stylesheets/mod.rs
index 16842021e8d..6f9c03abc5d 100644
--- a/components/style/stylesheets/mod.rs
+++ b/components/style/stylesheets/mod.rs
@@ -63,9 +63,15 @@ pub use self::stylesheet::{StylesheetContents, StylesheetInDocument, UserAgentSt
pub use self::supports_rule::SupportsRule;
pub use self::viewport_rule::ViewportRule;
-/// Extra data that the backend may need to resolve url values.
-#[cfg(not(feature = "gecko"))]
-pub type UrlExtraData = ::servo_url::ServoUrl;
+/// The CORS mode used for a CSS load.
+#[repr(u8)]
+#[derive(Clone, Copy, Debug, Eq, PartialEq, ToShmem)]
+pub enum CorsMode {
+ /// No CORS mode, so cross-origin loads can be done.
+ None,
+ /// Anonymous CORS request.
+ Anonymous,
+}
/// Extra data that the backend may need to resolve url values.
///
@@ -82,8 +88,13 @@ pub type UrlExtraData = ::servo_url::ServoUrl;
/// `from_ptr_ref` can work.
#[cfg(feature = "gecko")]
#[derive(PartialEq)]
+#[repr(C)]
pub struct UrlExtraData(usize);
+/// Extra data that the backend may need to resolve url values.
+#[cfg(not(feature = "gecko"))]
+pub type UrlExtraData = ::servo_url::ServoUrl;
+
#[cfg(feature = "gecko")]
impl Clone for UrlExtraData {
fn clone(&self) -> UrlExtraData {
diff --git a/components/style/stylesheets/rule_parser.rs b/components/style/stylesheets/rule_parser.rs
index a3ec24174ed..e7f3fb15f80 100644
--- a/components/style/stylesheets/rule_parser.rs
+++ b/components/style/stylesheets/rule_parser.rs
@@ -19,8 +19,8 @@ use crate::stylesheets::keyframes_rule::parse_keyframe_list;
use crate::stylesheets::stylesheet::Namespaces;
use crate::stylesheets::supports_rule::SupportsCondition;
use crate::stylesheets::viewport_rule;
+use crate::stylesheets::{CorsMode, DocumentRule, FontFeatureValuesRule, KeyframesRule, MediaRule};
use crate::stylesheets::{CssRule, CssRuleType, CssRules, RulesMutateError, StylesheetLoader};
-use crate::stylesheets::{DocumentRule, FontFeatureValuesRule, KeyframesRule, MediaRule};
use crate::stylesheets::{NamespaceRule, PageRule, StyleRule, SupportsRule, ViewportRule};
use crate::values::computed::font::FamilyName;
use crate::values::{CssUrl, CustomIdent, KeyframesName};
@@ -197,7 +197,7 @@ impl<'a, 'i> AtRuleParser<'i> for TopLevelRuleParser<'a> {
}
let url_string = input.expect_url_or_string()?.as_ref().to_owned();
- let url = CssUrl::parse_from_string(url_string, &self.context);
+ let url = CssUrl::parse_from_string(url_string, &self.context, CorsMode::None);
let media = MediaList::parse(&self.context, input);
let media = Arc::new(self.shared_lock.wrap(media));
diff --git a/components/style/values/animated/effects.rs b/components/style/values/animated/effects.rs
index 4c559cd4c30..49e751fec55 100644
--- a/components/style/values/animated/effects.rs
+++ b/components/style/values/animated/effects.rs
@@ -19,8 +19,8 @@ pub type AnimatedSimpleShadow = GenericSimpleShadow<Color, Length, Length>;
/// An animated value for a single `filter`.
#[cfg(feature = "gecko")]
-pub type Filter = GenericFilter<Angle, Number, Length, AnimatedSimpleShadow, ComputedUrl>;
+pub type AnimatedFilter = GenericFilter<Angle, Number, Length, AnimatedSimpleShadow, ComputedUrl>;
/// An animated value for a single `filter`.
#[cfg(not(feature = "gecko"))]
-pub type Filter = GenericFilter<Angle, Number, Length, Impossible, Impossible>;
+pub type AnimatedFilter = GenericFilter<Angle, Number, Length, Impossible, Impossible>;
diff --git a/components/style/values/computed/effects.rs b/components/style/values/computed/effects.rs
index d103f407a75..24ec689e49c 100644
--- a/components/style/values/computed/effects.rs
+++ b/components/style/values/computed/effects.rs
@@ -24,7 +24,7 @@ pub type Filter =
GenericFilter<Angle, NonNegativeNumber, NonNegativeLength, SimpleShadow, ComputedUrl>;
/// A computed value for a single `filter`.
-#[cfg(not(feature = "gecko"))]
+#[cfg(feature = "servo")]
pub type Filter =
GenericFilter<Angle, NonNegativeNumber, NonNegativeLength, Impossible, Impossible>;
diff --git a/components/style/values/computed/list.rs b/components/style/values/computed/list.rs
index 3536aa656fe..bdcf62ba2f8 100644
--- a/components/style/values/computed/list.rs
+++ b/components/style/values/computed/list.rs
@@ -10,7 +10,7 @@ pub use crate::values::specified::list::MozListReversed;
pub use crate::values::specified::list::{QuotePair, Quotes};
lazy_static! {
- static ref INITIAL_QUOTES: crate::ArcSlice<QuotePair> = crate::ArcSlice::from_iter(
+ static ref INITIAL_QUOTES: crate::ArcSlice<QuotePair> = crate::ArcSlice::from_iter_leaked(
vec![
QuotePair {
opening: "\u{201c}".to_owned().into(),
diff --git a/components/style/values/computed/motion.rs b/components/style/values/computed/motion.rs
index 932d8074262..e5f82f46558 100644
--- a/components/style/values/computed/motion.rs
+++ b/components/style/values/computed/motion.rs
@@ -18,13 +18,25 @@ fn is_auto_zero_angle(auto: &bool, angle: &Angle) -> bool {
}
/// A computed offset-rotate.
-#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToResolvedValue)]
+#[derive(
+ Animate,
+ Clone,
+ ComputeSquaredDistance,
+ Copy,
+ Debug,
+ MallocSizeOf,
+ PartialEq,
+ ToAnimatedZero,
+ ToCss,
+ ToResolvedValue,
+)]
#[repr(C)]
pub struct OffsetRotate {
/// If auto is false, this is a fixed angle which indicates a
/// constant clockwise rotation transformation applied to it by this
/// specified rotation angle. Otherwise, the angle will be added to
/// the angle of the direction in layout.
+ #[animation(constant)]
#[css(represents_keyword)]
pub auto: bool,
/// The angle value.
diff --git a/components/style/values/generics/effects.rs b/components/style/values/generics/effects.rs
index a27adc49e52..beca716e997 100644
--- a/components/style/values/generics/effects.rs
+++ b/components/style/values/generics/effects.rs
@@ -34,8 +34,10 @@ pub struct GenericBoxShadow<Color, SizeLength, BlurShapeLength, ShapeLength> {
pub use self::GenericBoxShadow as BoxShadow;
/// A generic value for a single `filter`.
+///
+/// cbindgen:derive-tagged-enum-copy-constructor=true
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
-#[animation(no_bound(Url))]
+#[animation(no_bound(U))]
#[derive(
Clone,
ComputeSquaredDistance,
@@ -49,7 +51,8 @@ pub use self::GenericBoxShadow as BoxShadow;
ToResolvedValue,
ToShmem,
)]
-pub enum Filter<Angle, Factor, Length, DropShadow, Url> {
+#[repr(C, u8)]
+pub enum GenericFilter<Angle, Factor, Length, Shadow, U> {
/// `blur(<length>)`
#[css(function)]
Blur(Length),
@@ -79,12 +82,14 @@ pub enum Filter<Angle, Factor, Length, DropShadow, Url> {
Sepia(Factor),
/// `drop-shadow(...)`
#[css(function)]
- DropShadow(DropShadow),
+ DropShadow(Shadow),
/// `<url>`
#[animation(error)]
- Url(Url),
+ Url(U),
}
+pub use self::GenericFilter as Filter;
+
/// A generic value for the `drop-shadow()` filter and the `text-shadow` property.
///
/// Contrary to the canonical order from the spec, the color is serialised
diff --git a/components/style/values/generics/url.rs b/components/style/values/generics/url.rs
index 9dbed038630..1f271033036 100644
--- a/components/style/values/generics/url.rs
+++ b/components/style/values/generics/url.rs
@@ -5,6 +5,8 @@
//! Generic types for url properties.
/// An image url or none, used for example in list-style-image
+///
+/// cbindgen:derive-tagged-enum-copy-constructor=true
#[derive(
Animate,
Clone,
@@ -21,16 +23,27 @@
ToResolvedValue,
ToShmem,
)]
-pub enum UrlOrNone<Url> {
+#[repr(C, u8)]
+pub enum GenericUrlOrNone<U> {
/// `none`
None,
- /// `A URL`
- Url(Url),
+ /// A URL.
+ Url(U),
}
+pub use self::GenericUrlOrNone as UrlOrNone;
+
impl<Url> UrlOrNone<Url> {
/// Initial "none" value for properties such as `list-style-image`
pub fn none() -> Self {
UrlOrNone::None
}
+
+ /// Returns whether the value is `none`.
+ pub fn is_none(&self) -> bool {
+ match *self {
+ UrlOrNone::None => true,
+ UrlOrNone::Url(..) => false,
+ }
+ }
}
diff --git a/components/style/values/specified/color.rs b/components/style/values/specified/color.rs
index 375a7d23d49..acad3383014 100644
--- a/components/style/values/specified/color.rs
+++ b/components/style/values/specified/color.rs
@@ -8,8 +8,6 @@ use super::AllowQuirks;
#[cfg(feature = "gecko")]
use crate::gecko_bindings::structs::nscolor;
use crate::parser::{Parse, ParserContext};
-#[cfg(feature = "gecko")]
-use crate::properties::longhands::system_colors::SystemColor;
use crate::values::computed::{Color as ComputedColor, Context, ToComputedValue};
use crate::values::generics::color::{Color as GenericColor, ColorOrAuto as GenericColorOrAuto};
use crate::values::specified::calc::CalcNode;
@@ -35,7 +33,6 @@ pub enum Color {
},
/// A complex color value from computed value
Complex(ComputedColor),
-
/// A system color
#[cfg(feature = "gecko")]
System(SystemColor),
@@ -47,6 +44,215 @@ pub enum Color {
InheritFromBodyQuirk,
}
+/// System colors.
+#[allow(missing_docs)]
+#[cfg(feature = "gecko")]
+#[derive(Clone, Copy, Debug, MallocSizeOf, Parse, PartialEq, ToCss, ToShmem)]
+#[repr(u8)]
+pub enum SystemColor {
+ #[css(skip)]
+ WindowBackground,
+ #[css(skip)]
+ WindowForeground,
+ #[css(skip)]
+ WidgetBackground,
+ #[css(skip)]
+ WidgetForeground,
+ #[css(skip)]
+ WidgetSelectBackground,
+ #[css(skip)]
+ WidgetSelectForeground,
+ #[css(skip)]
+ Widget3DHighlight,
+ #[css(skip)]
+ Widget3DShadow,
+ #[css(skip)]
+ TextBackground,
+ #[css(skip)]
+ TextForeground,
+ #[css(skip)]
+ TextSelectBackground,
+ #[css(skip)]
+ TextSelectForeground,
+ #[css(skip)]
+ TextSelectForegroundCustom,
+ #[css(skip)]
+ TextSelectBackgroundDisabled,
+ #[css(skip)]
+ TextSelectBackgroundAttention,
+ #[css(skip)]
+ TextHighlightBackground,
+ #[css(skip)]
+ TextHighlightForeground,
+ #[css(skip)]
+ IMERawInputBackground,
+ #[css(skip)]
+ IMERawInputForeground,
+ #[css(skip)]
+ IMERawInputUnderline,
+ #[css(skip)]
+ IMESelectedRawTextBackground,
+ #[css(skip)]
+ IMESelectedRawTextForeground,
+ #[css(skip)]
+ IMESelectedRawTextUnderline,
+ #[css(skip)]
+ IMEConvertedTextBackground,
+ #[css(skip)]
+ IMEConvertedTextForeground,
+ #[css(skip)]
+ IMEConvertedTextUnderline,
+ #[css(skip)]
+ IMESelectedConvertedTextBackground,
+ #[css(skip)]
+ IMESelectedConvertedTextForeground,
+ #[css(skip)]
+ IMESelectedConvertedTextUnderline,
+ #[css(skip)]
+ SpellCheckerUnderline,
+ Activeborder,
+ Activecaption,
+ Appworkspace,
+ Background,
+ Buttonface,
+ Buttonhighlight,
+ Buttonshadow,
+ Buttontext,
+ Captiontext,
+ Graytext,
+ Highlight,
+ Highlighttext,
+ Inactiveborder,
+ Inactivecaption,
+ Inactivecaptiontext,
+ Infobackground,
+ Infotext,
+ Menu,
+ Menutext,
+ Scrollbar,
+ Threeddarkshadow,
+ Threedface,
+ Threedhighlight,
+ Threedlightshadow,
+ Threedshadow,
+ Window,
+ Windowframe,
+ Windowtext,
+ MozButtondefault,
+ MozField,
+ MozFieldtext,
+ MozDialog,
+ MozDialogtext,
+ /// Used to highlight valid regions to drop something onto.
+ MozDragtargetzone,
+ /// Used for selected but not focused cell backgrounds.
+ MozCellhighlight,
+ /// Used for selected but not focused cell text.
+ MozCellhighlighttext,
+ /// Used for selected but not focused html cell backgrounds.
+ MozHtmlCellhighlight,
+ /// Used for selected but not focused html cell text.
+ MozHtmlCellhighlighttext,
+ /// Used to button text background when hovered.
+ MozButtonhoverface,
+ /// Used to button text color when hovered.
+ MozButtonhovertext,
+ /// Used for menu item backgrounds when hovered.
+ MozMenuhover,
+ /// Used for menu item text when hovered.
+ MozMenuhovertext,
+ /// Used for menubar item text.
+ MozMenubartext,
+ /// Used for menubar item text when hovered.
+ MozMenubarhovertext,
+
+ /// On platforms where these colors are the same as -moz-field, use
+ /// -moz-fieldtext as foreground color
+ MozEventreerow,
+ MozOddtreerow,
+
+ /// Used for button text when pressed.
+ #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
+ MozGtkButtonactivetext,
+
+ /// Used for button text when pressed.
+ MozMacButtonactivetext,
+ /// Background color of chrome toolbars in active windows.
+ MozMacChromeActive,
+ /// Background color of chrome toolbars in inactive windows.
+ MozMacChromeInactive,
+ /// Foreground color of default buttons.
+ MozMacDefaultbuttontext,
+ /// Ring color around text fields and lists.
+ MozMacFocusring,
+ /// Color used when mouse is over a menu item.
+ MozMacMenuselect,
+ /// Color used to do shadows on menu items.
+ MozMacMenushadow,
+ /// Color used to display text for disabled menu items.
+ MozMacMenutextdisable,
+ /// Color used to display text while mouse is over a menu item.
+ MozMacMenutextselect,
+ /// Text color of disabled text on toolbars.
+ MozMacDisabledtoolbartext,
+ /// Inactive light hightlight
+ MozMacSecondaryhighlight,
+
+ /// Font smoothing background colors needed by the Mac OS X theme, based on
+ /// -moz-appearance names.
+ MozMacVibrancyLight,
+ MozMacVibrancyDark,
+ MozMacVibrantTitlebarLight,
+ MozMacVibrantTitlebarDark,
+ MozMacMenupopup,
+ MozMacMenuitem,
+ MozMacActiveMenuitem,
+ MozMacSourceList,
+ MozMacSourceListSelection,
+ MozMacActiveSourceListSelection,
+ MozMacTooltip,
+
+ /// Accent color for title bar.
+ MozWinAccentcolor,
+ /// Color from drawing text over the accent color.
+ MozWinAccentcolortext,
+ /// Media rebar text.
+ MozWinMediatext,
+ /// Communications rebar text.
+ MozWinCommunicationstext,
+
+ /// Hyperlink color extracted from the system, not affected by the
+ /// browser.anchor_color user pref.
+ ///
+ /// There is no OS-specified safe background color for this text, but it is
+ /// used regularly within Windows and the Gnome DE on Dialog and Window
+ /// colors.
+ MozNativehyperlinktext,
+
+ /// Combobox widgets
+ MozComboboxtext,
+ MozCombobox,
+
+ MozGtkInfoBarText,
+
+ #[css(skip)]
+ End, // Just for array-indexing purposes.
+}
+
+#[cfg(feature = "gecko")]
+impl SystemColor {
+ #[inline]
+ fn compute(&self, cx: &Context) -> ComputedColor {
+ use crate::gecko_bindings::bindings;
+ unsafe {
+ convert_nscolor_to_computedcolor(bindings::Gecko_GetLookAndFeelSystemColor(
+ *self as i32,
+ cx.device().document(),
+ ))
+ }
+ }
+}
+
#[cfg(feature = "gecko")]
mod gecko {
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, ToCss, ToShmem)]
@@ -153,14 +359,12 @@ impl Parse for Color {
Err(e) => {
#[cfg(feature = "gecko")]
{
- if let Ok(ident) = input.expect_ident() {
- if let Ok(system) = SystemColor::from_ident(ident) {
- return Ok(Color::System(system));
- }
-
- if let Ok(c) = gecko::SpecialColorKeyword::from_ident(ident) {
- return Ok(Color::Special(c));
- }
+ if let Ok(system) = input.try(|i| SystemColor::parse(context, i)) {
+ return Ok(Color::System(system));
+ }
+
+ if let Ok(c) = input.try(gecko::SpecialColorKeyword::parse) {
+ return Ok(Color::Special(c));
}
}
@@ -340,32 +544,29 @@ impl Color {
/// If `context` is `None`, and the specified color requires data from
/// the context to resolve, then `None` is returned.
pub fn to_computed_color(&self, _context: Option<&Context>) -> Option<ComputedColor> {
- match *self {
- Color::CurrentColor => Some(ComputedColor::currentcolor()),
- Color::Numeric { ref parsed, .. } => Some(ComputedColor::rgba(*parsed)),
- Color::Complex(ref complex) => Some(*complex),
+ Some(match *self {
+ Color::CurrentColor => ComputedColor::currentcolor(),
+ Color::Numeric { ref parsed, .. } => ComputedColor::rgba(*parsed),
+ Color::Complex(ref complex) => *complex,
#[cfg(feature = "gecko")]
- Color::System(system) => _context
- .map(|context| convert_nscolor_to_computedcolor(system.to_computed_value(context))),
+ Color::System(system) => system.compute(_context?),
#[cfg(feature = "gecko")]
Color::Special(special) => {
use self::gecko::SpecialColorKeyword as Keyword;
- _context.map(|context| {
- 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,
- })
+ 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 => {
- _context.map(|context| ComputedColor::rgba(context.device().body_text_color()))
+ ComputedColor::rgba(_context?.device().body_text_color())
},
- }
+ })
}
}
@@ -443,7 +644,7 @@ impl ToComputedValue for ColorPropertyValue {
fn to_computed_value(&self, context: &Context) -> RGBA {
self.0
.to_computed_value(context)
- .to_rgba(context.builder.get_parent_color().clone_color())
+ .to_rgba(context.builder.get_parent_inherited_text().clone_color())
}
#[inline]
diff --git a/components/style/values/specified/effects.rs b/components/style/values/specified/effects.rs
index 3ffad2fa89c..25ef99a362e 100644
--- a/components/style/values/specified/effects.rs
+++ b/components/style/values/specified/effects.rs
@@ -18,7 +18,7 @@ use crate::values::specified::length::{Length, NonNegativeLength};
#[cfg(feature = "gecko")]
use crate::values::specified::url::SpecifiedUrl;
use crate::values::specified::{Angle, Number, NumberOrPercentage};
-#[cfg(not(feature = "gecko"))]
+#[cfg(feature = "servo")]
use crate::values::Impossible;
use crate::Zero;
use cssparser::{self, BasicParseErrorKind, Parser, Token};
@@ -30,11 +30,14 @@ pub type BoxShadow =
/// A specified value for a single `filter`.
#[cfg(feature = "gecko")]
-pub type Filter = GenericFilter<Angle, Factor, NonNegativeLength, SimpleShadow, SpecifiedUrl>;
+pub type SpecifiedFilter =
+ GenericFilter<Angle, Factor, NonNegativeLength, SimpleShadow, SpecifiedUrl>;
/// A specified value for a single `filter`.
-#[cfg(not(feature = "gecko"))]
-pub type Filter = GenericFilter<Angle, Factor, NonNegativeLength, Impossible, Impossible>;
+#[cfg(feature = "servo")]
+pub type SpecifiedFilter = GenericFilter<Angle, Factor, NonNegativeLength, Impossible, Impossible>;
+
+pub use self::SpecifiedFilter as Filter;
/// A value for the `<factor>` parts in `Filter`.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
diff --git a/components/style/values/specified/image.rs b/components/style/values/specified/image.rs
index ad2ecb18086..ca7f687bfea 100644
--- a/components/style/values/specified/image.rs
+++ b/components/style/values/specified/image.rs
@@ -11,6 +11,7 @@ use crate::custom_properties::SpecifiedValue;
#[cfg(feature = "gecko")]
use crate::gecko_bindings::structs;
use crate::parser::{Parse, ParserContext};
+use crate::stylesheets::CorsMode;
#[cfg(feature = "gecko")]
use crate::values::computed::{Context, Position as ComputedPosition, ToComputedValue};
use crate::values::generics::image::PaintWorklet;
@@ -1032,7 +1033,11 @@ impl Parse for MozImageRect {
input.try(|i| i.expect_function_matching("-moz-image-rect"))?;
input.parse_nested_block(|i| {
let string = i.expect_url_or_string()?;
- let url = SpecifiedImageUrl::parse_from_string(string.as_ref().to_owned(), context);
+ let url = SpecifiedImageUrl::parse_from_string(
+ string.as_ref().to_owned(),
+ context,
+ CorsMode::None,
+ );
i.expect_comma()?;
let top = NumberOrPercentage::parse_non_negative(context, i)?;
i.expect_comma()?;
diff --git a/components/style/values/specified/url.rs b/components/style/values/specified/url.rs
index ecf0eaae00c..b0a69b362d8 100644
--- a/components/style/values/specified/url.rs
+++ b/components/style/values/specified/url.rs
@@ -4,7 +4,7 @@
//! Common handling for the specified value CSS url() values.
-use crate::values::generics::url::UrlOrNone as GenericUrlOrNone;
+use crate::values::generics::url::GenericUrlOrNone;
#[cfg(feature = "gecko")]
pub use crate::gecko::url::{SpecifiedImageUrl, SpecifiedUrl};
diff --git a/components/style_traits/arc_slice.rs b/components/style_traits/arc_slice.rs
index 6a151e3dc5a..bbbac1a0757 100644
--- a/components/style_traits/arc_slice.rs
+++ b/components/style_traits/arc_slice.rs
@@ -40,7 +40,7 @@ impl<T> Deref for ArcSlice<T> {
lazy_static! {
// ThinArc doesn't support alignments greater than align_of::<u64>.
static ref EMPTY_ARC_SLICE: ArcSlice<u64> = {
- ArcSlice(ThinArc::from_header_and_iter(ARC_SLICE_CANARY, iter::empty()))
+ ArcSlice::from_iter_leaked(iter::empty())
};
}
@@ -74,6 +74,19 @@ impl<T> ArcSlice<T> {
ArcSlice(ThinArc::from_header_and_iter(ARC_SLICE_CANARY, items))
}
+ /// Creates an Arc for a slice using the given iterator to generate the
+ /// slice, and marks the arc as intentionally leaked from the refcount
+ /// logging point of view.
+ #[inline]
+ pub fn from_iter_leaked<I>(items: I) -> Self
+ where
+ I: Iterator<Item = T> + ExactSizeIterator,
+ {
+ let thin_arc = ThinArc::from_header_and_iter(ARC_SLICE_CANARY, items);
+ thin_arc.with_arc(|a| a.mark_as_intentionally_leaked());
+ ArcSlice(thin_arc)
+ }
+
/// Creates a value that can be passed via FFI, and forgets this value
/// altogether.
#[inline]
diff --git a/tests/unit/style/rule_tree/bench.rs b/tests/unit/style/rule_tree/bench.rs
index 52ebf2c1e2b..1c561a1f215 100644
--- a/tests/unit/style/rule_tree/bench.rs
+++ b/tests/unit/style/rule_tree/bench.rs
@@ -11,7 +11,7 @@ use style::error_reporting::{ContextualParseError, ParseErrorReporter};
use style::media_queries::MediaList;
use style::properties::{longhands, Importance, PropertyDeclaration, PropertyDeclarationBlock};
use style::rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource};
-use style::shared_lock::SharedRwLock;
+use style::shared_lock::{SharedRwLock, StylesheetGuards};
use style::stylesheets::{CssRule, Origin, Stylesheet};
use style::thread_state::{self, ThreadState};
use test::{self, Bencher};
@@ -29,18 +29,23 @@ impl ParseErrorReporter for ErrorringErrorReporter {
}
}
-struct AutoGCRuleTree<'a>(&'a RuleTree);
+struct AutoGCRuleTree<'a>(&'a RuleTree, &'a SharedRwLock);
impl<'a> AutoGCRuleTree<'a> {
- fn new(r: &'a RuleTree) -> Self {
- AutoGCRuleTree(r)
+ fn new(r: &'a RuleTree, lock: &'a SharedRwLock) -> Self {
+ AutoGCRuleTree(r, lock)
}
}
impl<'a> Drop for AutoGCRuleTree<'a> {
fn drop(&mut self) {
+ const DEBUG: bool = false;
unsafe {
self.0.gc();
+ if DEBUG {
+ let guard = self.1.read();
+ self.0.dump_stdout(&StylesheetGuards::same(&guard));
+ }
assert!(
::std::thread::panicking() || !self.0.root().has_children_for_testing(),
"No rule nodes other than the root shall remain!"
@@ -49,8 +54,7 @@ impl<'a> Drop for AutoGCRuleTree<'a> {
}
}
-fn parse_rules(css: &str) -> Vec<(StyleSource, CascadeLevel)> {
- let lock = SharedRwLock::new();
+fn parse_rules(lock: &SharedRwLock, css: &str) -> Vec<(StyleSource, CascadeLevel)> {
let media = Arc::new(lock.wrap(MediaList::empty()));
let s = Stylesheet::from_str(
@@ -58,7 +62,7 @@ fn parse_rules(css: &str) -> Vec<(StyleSource, CascadeLevel)> {
ServoUrl::parse("http://localhost").unwrap(),
Origin::Author,
media,
- lock,
+ lock.clone(),
None,
Some(&ErrorringErrorReporter),
QuirksMode::NoQuirks,
@@ -105,15 +109,16 @@ fn test_insertion_style_attribute(
fn bench_insertion_basic(b: &mut Bencher) {
let r = RuleTree::new();
thread_state::initialize(ThreadState::SCRIPT);
-
+ let lock = SharedRwLock::new();
let rules_matched = parse_rules(
+ &lock,
".foo { width: 200px; } \
.bar { height: 500px; } \
.baz { display: block; }",
);
b.iter(|| {
- let _gc = AutoGCRuleTree::new(&r);
+ let _gc = AutoGCRuleTree::new(&r, &lock);
for _ in 0..(4000 + 400) {
test::black_box(test_insertion(&r, rules_matched.clone()));
@@ -126,14 +131,16 @@ fn bench_insertion_basic_per_element(b: &mut Bencher) {
let r = RuleTree::new();
thread_state::initialize(ThreadState::SCRIPT);
+ let lock = SharedRwLock::new();
let rules_matched = parse_rules(
+ &lock,
".foo { width: 200px; } \
.bar { height: 500px; } \
.baz { display: block; }",
);
b.iter(|| {
- let _gc = AutoGCRuleTree::new(&r);
+ let _gc = AutoGCRuleTree::new(&r, &lock);
test::black_box(test_insertion(&r, rules_matched.clone()));
});
@@ -147,22 +154,19 @@ fn bench_expensive_insertion(b: &mut Bencher) {
// This test case tests a case where you style a bunch of siblings
// matching the same rules, with a different style attribute each
// one.
+ let lock = SharedRwLock::new();
let rules_matched = parse_rules(
+ &lock,
".foo { width: 200px; } \
.bar { height: 500px; } \
.baz { display: block; }",
);
- let shared_lock = SharedRwLock::new();
b.iter(|| {
- let _gc = AutoGCRuleTree::new(&r);
+ let _gc = AutoGCRuleTree::new(&r, &lock);
for _ in 0..(4000 + 400) {
- test::black_box(test_insertion_style_attribute(
- &r,
- &rules_matched,
- &shared_lock,
- ));
+ test::black_box(test_insertion_style_attribute(&r, &rules_matched, &lock));
}
});
}
@@ -172,14 +176,16 @@ fn bench_insertion_basic_parallel(b: &mut Bencher) {
let r = RuleTree::new();
thread_state::initialize(ThreadState::SCRIPT);
+ let lock = SharedRwLock::new();
let rules_matched = parse_rules(
+ &lock,
".foo { width: 200px; } \
.bar { height: 500px; } \
.baz { display: block; }",
);
b.iter(|| {
- let _gc = AutoGCRuleTree::new(&r);
+ let _gc = AutoGCRuleTree::new(&r, &lock);
rayon::scope(|s| {
for _ in 0..4 {
@@ -203,32 +209,29 @@ fn bench_expensive_insertion_parallel(b: &mut Bencher) {
let r = RuleTree::new();
thread_state::initialize(ThreadState::SCRIPT);
+ let lock = SharedRwLock::new();
let rules_matched = parse_rules(
+ &lock,
".foo { width: 200px; } \
.bar { height: 500px; } \
.baz { display: block; }",
);
- let shared_lock = SharedRwLock::new();
b.iter(|| {
- let _gc = AutoGCRuleTree::new(&r);
+ let _gc = AutoGCRuleTree::new(&r, &lock);
rayon::scope(|s| {
for _ in 0..4 {
s.spawn(|s| {
for _ in 0..1000 {
- test::black_box(test_insertion_style_attribute(
- &r,
- &rules_matched,
- &shared_lock,
- ));
+ test::black_box(test_insertion_style_attribute(&r, &rules_matched, &lock));
}
s.spawn(|_| {
for _ in 0..100 {
test::black_box(test_insertion_style_attribute(
&r,
&rules_matched,
- &shared_lock,
+ &lock,
));
}
})