mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Auto merge of #23503 - emilio:gecko-sync, r=emilio
style: sync changes from mozilla-central See each individual commit for details. This also cherry-picks #23463 with a few fixes that were needed in Gecko-only code. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/23503) <!-- Reviewable:end -->
This commit is contained in:
commit
fe8aad7227
47 changed files with 897 additions and 915 deletions
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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)),
|
||||
}
|
||||
|
|
|
@ -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>(
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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())
|
||||
|
@ -897,11 +897,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,
|
||||
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -12,6 +12,7 @@ path = "lib.rs"
|
|||
|
||||
[features]
|
||||
servo = ["serde"]
|
||||
gecko_refcount_logging = []
|
||||
|
||||
[dependencies]
|
||||
nodrop = {version = "0.1.8"}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
struct LoadDataKey(*const LoadDataSource);
|
||||
|
||||
unsafe impl Sync for CssUrlDataKey {}
|
||||
unsafe impl Send for CssUrlDataKey {}
|
||||
unsafe impl Sync for LoadDataKey {}
|
||||
unsafe impl Send for LoadDataKey {}
|
||||
|
||||
/// 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),
|
||||
/// 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 {
|
||||
impl Drop for LoadData {
|
||||
fn drop(&mut self) {
|
||||
if self.load_id != 0 {
|
||||
unsafe {
|
||||
bindings::Gecko_LoadData_DeregisterLoad(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for LoadData {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
resolved: RefPtr::null(),
|
||||
load_id: 0,
|
||||
tried_to_resolve: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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,
|
||||
}
|
||||
|
||||
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 => {},
|
||||
}
|
||||
|
||||
let key = LoadDataKey(self);
|
||||
|
||||
{
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
impl ToShmem for LoadDataSource {
|
||||
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),
|
||||
LoadDataSource::Owned(..) => LoadDataSource::Lazy,
|
||||
LoadDataSource::Lazy => LoadDataSource::Lazy,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// 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>,
|
||||
}
|
||||
pub type SpecifiedUrl = CssUrl;
|
||||
|
||||
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 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 }
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// 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)
|
||||
}
|
||||
}
|
||||
|
||||
/// Clears URL_VALUE_TABLE. Entries in this table, which are for specified URL
|
||||
/// 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 ComputedUrl {
|
||||
fn serialize_with<W>(
|
||||
&self,
|
||||
function: unsafe extern "C" fn(*const Self, *mut nsCString),
|
||||
dest: &mut CssWriter<W>,
|
||||
) -> fmt::Result
|
||||
where
|
||||
W: Write,
|
||||
{
|
||||
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 ToCss for ComputedUrl {
|
||||
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||
where
|
||||
W: Write,
|
||||
{
|
||||
self.0
|
||||
.with_url_value(|r| serialize_computed_url(r, dest, bindings::Gecko_GetComputedURLSpec))
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
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()
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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>(
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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(),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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 namespace(&self) -> &<Self::Impl as ::selectors::SelectorImpl>::BorrowedNamespaceUrl {
|
||||
self.element.namespace()
|
||||
fn has_namespace(
|
||||
&self,
|
||||
ns: &<Self::Impl as ::selectors::SelectorImpl>::BorrowedNamespaceUrl,
|
||||
) -> bool {
|
||||
self.element.has_namespace(ns)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_same_type(&self, other: &Self) -> bool {
|
||||
self.element.is_same_type(&other.element)
|
||||
}
|
||||
|
||||
fn attr_matches(
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,6 @@ STYLE_STRUCT_LIST = [
|
|||
"background",
|
||||
"border",
|
||||
"box",
|
||||
"color",
|
||||
"column",
|
||||
"counters",
|
||||
"effects",
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
|
@ -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",
|
||||
|
|
|
@ -6,6 +6,16 @@
|
|||
<% from data import Keyword %>
|
||||
<% 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",
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 key(&self) -> Option<ChildKey> {
|
||||
Some(ChildKey(self.level, self.source.as_ref()?.key()))
|
||||
}
|
||||
|
||||
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 prev_sibling(&self) -> &AtomicPtr<RuleNode> {
|
||||
debug_assert!(!self.is_root());
|
||||
unsafe { self.prev_sibling_or_free_count.as_prev_sibling() }
|
||||
}
|
||||
|
||||
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;
|
||||
use parking_lot::RwLockUpgradableReadGuard;
|
||||
|
||||
// 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 key = ChildKey(level, source.key());
|
||||
|
||||
let read_guard = self.get().children.upgradable_read();
|
||||
if let Some(child) = read_guard.get(&key) {
|
||||
return child.upgrade();
|
||||
}
|
||||
|
||||
let mut node = Box::new(RuleNode::new(root, self.clone(), source.clone(), level));
|
||||
let new_ptr: *mut RuleNode = &mut *node;
|
||||
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,
|
||||
)));
|
||||
|
||||
loop {
|
||||
let next;
|
||||
vacant.insert(new_node.downgrade());
|
||||
|
||||
{
|
||||
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,
|
||||
};
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
return StrongRuleNode::new(node);
|
||||
}
|
||||
|
||||
// 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())
|
||||
StrongRuleNode::from_ptr(self.p)
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
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 }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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>;
|
||||
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(system) = input.try(|i| SystemColor::parse(context, i)) {
|
||||
return Ok(Color::System(system));
|
||||
}
|
||||
|
||||
if let Ok(c) = gecko::SpecialColorKeyword::from_ident(ident) {
|
||||
return Ok(Color::Special(c));
|
||||
}
|
||||
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]
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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()?;
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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,
|
||||
));
|
||||
}
|
||||
})
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue