mirror of
https://github.com/servo/servo.git
synced 2025-06-16 04:14:29 +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(
|
state.add_display_item(DisplayItem::Rectangle(CommonDisplayItem::new(
|
||||||
base,
|
base,
|
||||||
webrender_api::RectangleDisplayItem {
|
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
|
// TODO(emilio): Allow changing more properties by ::selection
|
||||||
// Paint the text with the color as described in its styling.
|
// Paint the text with the color as described in its styling.
|
||||||
let text_color = if text_fragment.selected() {
|
let text_color = if text_fragment.selected() {
|
||||||
self.selected_style().get_color().color
|
self.selected_style().get_inherited_text().color
|
||||||
} else {
|
} else {
|
||||||
self.style().get_color().color
|
self.style().get_inherited_text().color
|
||||||
};
|
};
|
||||||
|
|
||||||
// Determine the orientation and cursor to use.
|
// Determine the orientation and cursor to use.
|
||||||
|
|
|
@ -1519,7 +1519,7 @@ impl Fragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn color(&self) -> Color {
|
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
|
/// 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)
|
.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> {
|
impl<'le> PartialEq for ServoLayoutElement<'le> {
|
||||||
|
@ -879,13 +887,19 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn local_name(&self) -> &LocalName {
|
fn has_local_name(&self, name: &LocalName) -> bool {
|
||||||
self.element.local_name()
|
self.element.local_name() == name
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn namespace(&self) -> &Namespace {
|
fn has_namespace(&self, ns: &Namespace) -> bool {
|
||||||
self.element.namespace()
|
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 {
|
fn is_pseudo_element(&self) -> bool {
|
||||||
|
@ -1266,8 +1280,8 @@ where
|
||||||
loop {
|
loop {
|
||||||
let next_node = if let Some(ref node) = current_node {
|
let next_node = if let Some(ref node) = current_node {
|
||||||
if let Some(element) = node.as_element() {
|
if let Some(element) = node.as_element() {
|
||||||
if element.local_name() == &local_name!("summary") &&
|
if element.has_local_name(&local_name!("summary")) &&
|
||||||
element.namespace() == &ns!(html)
|
element.has_namespace(&ns!(html))
|
||||||
{
|
{
|
||||||
self.current_node = None;
|
self.current_node = None;
|
||||||
return Some(node.clone());
|
return Some(node.clone());
|
||||||
|
@ -1286,8 +1300,10 @@ where
|
||||||
let node = self.current_node.clone();
|
let node = self.current_node.clone();
|
||||||
let node = node.and_then(|node| {
|
let node = node.and_then(|node| {
|
||||||
if node.is_element() &&
|
if node.is_element() &&
|
||||||
node.as_element().unwrap().local_name() == &local_name!("summary") &&
|
node.as_element()
|
||||||
node.as_element().unwrap().namespace() == &ns!(html)
|
.unwrap()
|
||||||
|
.has_local_name(&local_name!("summary")) &&
|
||||||
|
node.as_element().unwrap().has_namespace(&ns!(html))
|
||||||
{
|
{
|
||||||
unsafe { node.dangerous_next_sibling() }
|
unsafe { node.dangerous_next_sibling() }
|
||||||
} else {
|
} else {
|
||||||
|
@ -1437,13 +1453,19 @@ impl<'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn local_name(&self) -> &LocalName {
|
fn has_local_name(&self, name: &LocalName) -> bool {
|
||||||
self.element.local_name()
|
self.element.local_name() == name
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn namespace(&self) -> &Namespace {
|
fn has_namespace(&self, ns: &Namespace) -> bool {
|
||||||
self.element.namespace()
|
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(
|
fn match_pseudo_element(
|
||||||
|
|
|
@ -260,7 +260,7 @@ impl CanvasState {
|
||||||
|
|
||||||
match canvas_element.style() {
|
match canvas_element.style() {
|
||||||
Some(ref s) if canvas_element.has_css_layout_box() => {
|
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)),
|
_ => Ok(RGBA::new(0, 0, 0, 255)),
|
||||||
}
|
}
|
||||||
|
|
|
@ -2982,12 +2982,17 @@ impl<'a> SelectorsElement for DomRoot<Element> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn local_name(&self) -> &LocalName {
|
fn has_local_name(&self, local_name: &LocalName) -> bool {
|
||||||
Element::local_name(self)
|
Element::local_name(self) == local_name
|
||||||
}
|
}
|
||||||
|
|
||||||
fn namespace(&self) -> &Namespace {
|
fn has_namespace(&self, ns: &Namespace) -> bool {
|
||||||
Element::namespace(self)
|
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>(
|
fn match_non_ts_pseudo_class<F>(
|
||||||
|
|
|
@ -391,7 +391,7 @@ pub trait ThreadSafeLayoutElement:
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_details_summary_pseudo(&self) -> Option<Self> {
|
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))
|
Some(self.with_pseudo(PseudoElementType::DetailsSummary))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -400,8 +400,8 @@ pub trait ThreadSafeLayoutElement:
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_details_content_pseudo(&self) -> Option<Self> {
|
fn get_details_content_pseudo(&self) -> Option<Self> {
|
||||||
if self.local_name() == &local_name!("details") &&
|
if self.has_local_name(&local_name!("details")) &&
|
||||||
self.namespace() == &ns!(html) &&
|
self.has_namespace(&ns!(html)) &&
|
||||||
self.get_attr(&ns!(), &local_name!("open")).is_some()
|
self.get_attr(&ns!(), &local_name!("open")).is_some()
|
||||||
{
|
{
|
||||||
Some(self.with_pseudo(PseudoElementType::DetailsContent))
|
Some(self.with_pseudo(PseudoElementType::DetailsContent))
|
||||||
|
|
|
@ -596,7 +596,7 @@ where
|
||||||
&local_name.lower_name,
|
&local_name.lower_name,
|
||||||
)
|
)
|
||||||
.borrow();
|
.borrow();
|
||||||
element.local_name() == name
|
element.has_local_name(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determines whether the given element matches the given compound selector.
|
/// 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::LocalName(ref local_name) => matches_local_name(element, local_name),
|
||||||
Component::ExplicitUniversalType | Component::ExplicitAnyNamespace => true,
|
Component::ExplicitUniversalType | Component::ExplicitAnyNamespace => true,
|
||||||
Component::Namespace(_, ref url) | Component::DefaultNamespace(ref url) => {
|
Component::Namespace(_, ref url) | Component::DefaultNamespace(ref url) => {
|
||||||
element.namespace() == url.borrow()
|
element.has_namespace(&url.borrow())
|
||||||
},
|
},
|
||||||
Component::ExplicitNoNamespace => {
|
Component::ExplicitNoNamespace => {
|
||||||
let ns = crate::parser::namespace_empty_string::<E::Impl>();
|
let ns = crate::parser::namespace_empty_string::<E::Impl>();
|
||||||
element.namespace() == ns.borrow()
|
element.has_namespace(&ns.borrow())
|
||||||
},
|
},
|
||||||
Component::ID(ref id) => {
|
Component::ID(ref id) => {
|
||||||
element.has_id(id, context.shared.classes_and_ids_case_sensitivity())
|
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]
|
#[inline]
|
||||||
fn nth_child_index<E>(
|
fn nth_child_index<E>(
|
||||||
element: &E,
|
element: &E,
|
||||||
|
@ -924,7 +919,7 @@ where
|
||||||
let mut curr = element.clone();
|
let mut curr = element.clone();
|
||||||
while let Some(e) = curr.prev_sibling_element() {
|
while let Some(e) = curr.prev_sibling_element() {
|
||||||
curr = e;
|
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()) {
|
if let Some(i) = c.lookup(curr.opaque()) {
|
||||||
return i - index;
|
return i - index;
|
||||||
}
|
}
|
||||||
|
@ -945,7 +940,7 @@ where
|
||||||
};
|
};
|
||||||
while let Some(e) = next(curr) {
|
while let Some(e) = next(curr) {
|
||||||
curr = e;
|
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
|
// 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
|
// cache. We handle the indices-from-the-right case at the top of this
|
||||||
// function.
|
// function.
|
||||||
|
|
|
@ -62,10 +62,13 @@ pub trait Element: Sized + Clone + Debug {
|
||||||
|
|
||||||
fn is_html_element_in_html_document(&self) -> bool;
|
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
|
/// 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(
|
fn attr_matches(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
@ -12,6 +12,7 @@ path = "lib.rs"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
servo = ["serde"]
|
servo = ["serde"]
|
||||||
|
gecko_refcount_logging = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
nodrop = {version = "0.1.8"}
|
nodrop = {version = "0.1.8"}
|
||||||
|
|
|
@ -42,7 +42,7 @@ use std::fmt;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::iter::{ExactSizeIterator, Iterator};
|
use std::iter::{ExactSizeIterator, Iterator};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::mem;
|
use std::mem::{self, align_of, size_of};
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::os::raw::c_void;
|
use std::os::raw::c_void;
|
||||||
use std::process;
|
use std::process;
|
||||||
|
@ -90,6 +90,9 @@ const STATIC_REFCOUNT: usize = usize::MAX;
|
||||||
/// usage of PhantomData.
|
/// usage of PhantomData.
|
||||||
///
|
///
|
||||||
/// [`Arc`]: https://doc.rust-lang.org/stable/std/sync/struct.Arc.html
|
/// [`Arc`]: https://doc.rust-lang.org/stable/std/sync/struct.Arc.html
|
||||||
|
///
|
||||||
|
/// cbindgen:derive-eq=false
|
||||||
|
/// cbindgen:derive-neq=false
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct Arc<T: ?Sized> {
|
pub struct Arc<T: ?Sized> {
|
||||||
p: ptr::NonNull<ArcInner<T>>,
|
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`
|
/// Once the mutation is finished, you can call `.shareable()` and get a regular `Arc`
|
||||||
/// out of it.
|
/// 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;
|
/// # use servo_arc::UniqueArc;
|
||||||
/// let data = [1, 2, 3, 4, 5];
|
/// let data = [1, 2, 3, 4, 5];
|
||||||
/// let mut x = UniqueArc::new(data);
|
/// let mut x = UniqueArc::new(data);
|
||||||
|
@ -166,18 +172,35 @@ impl<T> Arc<T> {
|
||||||
/// Construct an `Arc<T>`
|
/// Construct an `Arc<T>`
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(data: T) -> Self {
|
pub fn new(data: T) -> Self {
|
||||||
let x = Box::new(ArcInner {
|
let ptr = Box::into_raw(Box::new(ArcInner {
|
||||||
count: atomic::AtomicUsize::new(1),
|
count: atomic::AtomicUsize::new(1),
|
||||||
data,
|
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 {
|
unsafe {
|
||||||
Arc {
|
Arc {
|
||||||
p: ptr::NonNull::new_unchecked(Box::into_raw(x)),
|
p: ptr::NonNull::new_unchecked(ptr),
|
||||||
phantom: PhantomData,
|
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
|
/// 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.
|
/// 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() }
|
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)]
|
#[inline(never)]
|
||||||
unsafe fn drop_slow(&mut self) {
|
unsafe fn drop_slow(&mut self) {
|
||||||
|
self.record_drop();
|
||||||
let _ = Box::from_raw(self.ptr());
|
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> {
|
impl<T: ?Sized> Clone for Arc<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
|
@ -609,7 +670,6 @@ impl<H, T> Arc<HeaderSlice<H, [T]>> {
|
||||||
F: FnOnce(Layout) -> *mut u8,
|
F: FnOnce(Layout) -> *mut u8,
|
||||||
I: Iterator<Item = T> + ExactSizeIterator,
|
I: Iterator<Item = T> + ExactSizeIterator,
|
||||||
{
|
{
|
||||||
use std::mem::{align_of, size_of};
|
|
||||||
assert_ne!(size_of::<T>(), 0, "Need to think about ZST");
|
assert_ne!(size_of::<T>(), 0, "Need to think about ZST");
|
||||||
|
|
||||||
let inner_align = align_of::<ArcInner<HeaderSlice<H, [T; 0]>>>();
|
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.
|
// Return the fat Arc.
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
size_of::<Self>(),
|
size_of::<Self>(),
|
||||||
|
@ -1248,11 +1317,18 @@ impl<A, B> ArcUnion<A, B> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the two values are pointer-equal.
|
/// Returns true if the two values are pointer-equal.
|
||||||
|
#[inline]
|
||||||
pub fn ptr_eq(this: &Self, other: &Self) -> bool {
|
pub fn ptr_eq(this: &Self, other: &Self) -> bool {
|
||||||
this.p == other.p
|
this.p == other.p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn ptr(&self) -> ptr::NonNull<()> {
|
||||||
|
self.p
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns an enum representing a borrow of either A or B.
|
/// Returns an enum representing a borrow of either A or B.
|
||||||
|
#[inline]
|
||||||
pub fn borrow(&self) -> ArcUnionBorrow<A, B> {
|
pub fn borrow(&self) -> ArcUnionBorrow<A, B> {
|
||||||
if self.is_first() {
|
if self.is_first() {
|
||||||
let ptr = self.p.as_ptr() as *const A;
|
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",
|
"cssparser/serde", "encoding_rs", "malloc_size_of/servo", "arrayvec/use_union",
|
||||||
"servo_url", "string_cache", "crossbeam-channel", "to_shmem/servo", "servo_arc/servo"]
|
"servo_url", "string_cache", "crossbeam-channel", "to_shmem/servo", "servo_arc/servo"]
|
||||||
gecko_debug = []
|
gecko_debug = []
|
||||||
|
gecko_refcount_logging = []
|
||||||
gecko_profiler = []
|
gecko_profiler = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
|
@ -19,7 +19,7 @@ thread_local! {
|
||||||
/// such that they can be reused across style traversals. StyleBloom is responsible
|
/// such that they can be reused across style traversals. StyleBloom is responsible
|
||||||
/// for ensuring that the bloom filter is zeroed when it is dropped.
|
/// for ensuring that the bloom filter is zeroed when it is dropped.
|
||||||
static BLOOM_KEY: Arc<AtomicRefCell<BloomFilter>> =
|
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
|
/// A struct that allows us to fast-reject deep descendant selectors avoiding
|
||||||
|
|
|
@ -882,6 +882,13 @@ pub trait TElement:
|
||||||
hints: &mut V,
|
hints: &mut V,
|
||||||
) where
|
) where
|
||||||
V: Push<ApplicableDeclarationBlock>;
|
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
|
/// TNode and TElement aren't Send because we want to be careful and explicit
|
||||||
|
|
|
@ -55,7 +55,7 @@ impl OneOrMoreSeparated for Source {
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub enum FontFaceSourceListComponent {
|
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),
|
Local(*mut crate::gecko_bindings::structs::nsAtom),
|
||||||
FormatHint {
|
FormatHint {
|
||||||
length: usize,
|
length: usize,
|
||||||
|
|
|
@ -122,11 +122,11 @@ impl nsStyleImage {
|
||||||
match image {
|
match image {
|
||||||
GenericImage::Gradient(boxed_gradient) => self.set_gradient(*boxed_gradient),
|
GenericImage::Gradient(boxed_gradient) => self.set_gradient(*boxed_gradient),
|
||||||
GenericImage::Url(ref url) => unsafe {
|
GenericImage::Url(ref url) => unsafe {
|
||||||
bindings::Gecko_SetLayerImageImageValue(self, url.url_value_ptr())
|
bindings::Gecko_SetLayerImageImageValue(self, url);
|
||||||
},
|
},
|
||||||
GenericImage::Rect(ref image_rect) => {
|
GenericImage::Rect(ref image_rect) => {
|
||||||
unsafe {
|
unsafe {
|
||||||
bindings::Gecko_SetLayerImageImageValue(self, image_rect.url.url_value_ptr());
|
bindings::Gecko_SetLayerImageImageValue(self, &image_rect.url);
|
||||||
bindings::Gecko_InitializeImageCropRect(self);
|
bindings::Gecko_InitializeImageCropRect(self);
|
||||||
|
|
||||||
// Set CropRect
|
// Set CropRect
|
||||||
|
@ -584,9 +584,10 @@ pub mod basic_shape {
|
||||||
|
|
||||||
impl<'a> From<&'a StyleShapeSource> for ClippingShape {
|
impl<'a> From<&'a StyleShapeSource> for ClippingShape {
|
||||||
fn from(other: &'a StyleShapeSource) -> Self {
|
fn from(other: &'a StyleShapeSource) -> Self {
|
||||||
use crate::values::generics::image::Image as GenericImage;
|
|
||||||
match other.mType {
|
match other.mType {
|
||||||
StyleShapeSourceType::Image => unsafe {
|
StyleShapeSourceType::Image => unsafe {
|
||||||
|
use crate::values::generics::image::Image as GenericImage;
|
||||||
|
|
||||||
let shape_image = &*other.__bindgen_anon_1.mShapeImage.as_ref().mPtr;
|
let shape_image = &*other.__bindgen_anon_1.mShapeImage.as_ref().mPtr;
|
||||||
let image = shape_image.into_image().expect("Cannot convert to Image");
|
let image = shape_image.into_image().expect("Cannot convert to Image");
|
||||||
match image {
|
match image {
|
||||||
|
|
|
@ -5,13 +5,11 @@
|
||||||
//! Common handling for the specified value CSS url() values.
|
//! Common handling for the specified value CSS url() values.
|
||||||
|
|
||||||
use crate::gecko_bindings::bindings;
|
use crate::gecko_bindings::bindings;
|
||||||
use crate::gecko_bindings::structs::root::mozilla::css::URLValue;
|
use crate::gecko_bindings::structs;
|
||||||
use crate::gecko_bindings::structs::root::mozilla::CORSMode;
|
use crate::gecko_bindings::structs::nsStyleImageRequest;
|
||||||
use crate::gecko_bindings::structs::root::nsStyleImageRequest;
|
|
||||||
use crate::gecko_bindings::sugar::ownership::{FFIArcHelpers, HasArcFFI};
|
|
||||||
use crate::gecko_bindings::sugar::refptr::RefPtr;
|
use crate::gecko_bindings::sugar::refptr::RefPtr;
|
||||||
use crate::parser::{Parse, ParserContext};
|
use crate::parser::{Parse, ParserContext};
|
||||||
use crate::stylesheets::UrlExtraData;
|
use crate::stylesheets::{CorsMode, UrlExtraData};
|
||||||
use crate::values::computed::{Context, ToComputedValue};
|
use crate::values::computed::{Context, ToComputedValue};
|
||||||
use cssparser::Parser;
|
use cssparser::Parser;
|
||||||
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
|
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
|
||||||
|
@ -27,25 +25,63 @@ use to_shmem::{SharedMemoryBuilder, ToShmem};
|
||||||
/// A CSS url() value for gecko.
|
/// A CSS url() value for gecko.
|
||||||
#[css(function = "url")]
|
#[css(function = "url")]
|
||||||
#[derive(Clone, Debug, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
|
#[derive(Clone, Debug, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
|
||||||
|
#[repr(C)]
|
||||||
pub struct CssUrl(pub Arc<CssUrlData>);
|
pub struct CssUrl(pub Arc<CssUrlData>);
|
||||||
|
|
||||||
/// Data shared between CssUrls.
|
/// 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 {
|
pub struct CssUrlData {
|
||||||
/// The URL in unresolved string form.
|
/// The URL in unresolved string form.
|
||||||
serialization: String,
|
serialization: crate::OwnedStr,
|
||||||
|
|
||||||
/// The URL extra data.
|
/// The URL extra data.
|
||||||
#[css(skip)]
|
#[css(skip)]
|
||||||
pub extra_data: UrlExtraData,
|
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 {
|
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.
|
/// 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 {
|
CssUrl(Arc::new(CssUrlData {
|
||||||
serialization: url,
|
serialization: url.into(),
|
||||||
extra_data: context.url_data.clone(),
|
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 {
|
impl Parse for CssUrl {
|
||||||
fn parse<'i, 't>(
|
fn parse<'i, 't>(
|
||||||
context: &ParserContext,
|
context: &ParserContext,
|
||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
) -> Result<Self, ParseError<'i>> {
|
) -> Result<Self, ParseError<'i>> {
|
||||||
let url = input.expect_url()?;
|
Self::parse_with_cors_mode(context, input, CorsMode::None)
|
||||||
Ok(Self::parse_from_string(url.as_ref().to_owned(), context))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)]
|
#[derive(Eq, Hash, PartialEq)]
|
||||||
struct CssUrlDataKey(*const CssUrlData);
|
struct LoadDataKey(*const LoadDataSource);
|
||||||
|
|
||||||
unsafe impl Sync for CssUrlDataKey {}
|
unsafe impl Sync for LoadDataKey {}
|
||||||
unsafe impl Send for CssUrlDataKey {}
|
unsafe impl Send for LoadDataKey {}
|
||||||
|
|
||||||
/// The source of a Gecko URLValue object for a SpecifiedUrl.
|
/// The load data for a given URL. This is mutable from C++, for now at least.
|
||||||
#[derive(Clone, Debug)]
|
#[repr(C)]
|
||||||
pub enum URLValueSource {
|
#[derive(Debug)]
|
||||||
/// A strong reference to a Gecko URLValue object.
|
pub struct LoadData {
|
||||||
URLValue(RefPtr<URLValue>),
|
resolved: RefPtr<structs::nsIURI>,
|
||||||
/// A CORSMode value used to lazily construct a Gecko URLValue object.
|
load_id: u64,
|
||||||
///
|
tried_to_resolve: bool,
|
||||||
/// The lazily created object will be stored in URL_VALUE_TABLE.
|
|
||||||
CORSMode(CORSMode),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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> {
|
fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> ManuallyDrop<Self> {
|
||||||
ManuallyDrop::new(match self {
|
ManuallyDrop::new(match self {
|
||||||
URLValueSource::URLValue(r) => URLValueSource::CORSMode(r.mCORSMode),
|
LoadDataSource::Owned(..) => LoadDataSource::Lazy,
|
||||||
URLValueSource::CORSMode(c) => URLValueSource::CORSMode(*c),
|
LoadDataSource::Lazy => LoadDataSource::Lazy,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A specified non-image `url()` value.
|
/// A specified non-image `url()` value.
|
||||||
#[derive(Clone, Debug, SpecifiedValueInfo, ToCss, ToShmem)]
|
pub type SpecifiedUrl = CssUrl;
|
||||||
pub struct SpecifiedUrl {
|
|
||||||
/// The specified url value.
|
|
||||||
pub url: CssUrl,
|
|
||||||
/// Gecko's URLValue so that we can reuse it while rematching a
|
|
||||||
/// property with this specified value.
|
|
||||||
///
|
|
||||||
/// Box this to avoid SpecifiedUrl getting bigger than two words,
|
|
||||||
/// and increasing the size of PropertyDeclaration.
|
|
||||||
#[css(skip)]
|
|
||||||
url_value: Box<URLValueSource>,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn make_url_value(url: &CssUrl, cors_mode: CORSMode) -> RefPtr<URLValue> {
|
/// Clears LOAD_DATA_TABLE. Entries in this table, which are for specified URL
|
||||||
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
|
|
||||||
/// values that come from shared memory style sheets, would otherwise persist
|
/// values that come from shared memory style sheets, would otherwise persist
|
||||||
/// until the end of the process and be reported as leaks.
|
/// until the end of the process and be reported as leaks.
|
||||||
pub fn shutdown() {
|
pub fn shutdown() {
|
||||||
URL_VALUE_TABLE.write().unwrap().clear();
|
LOAD_DATA_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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToComputedValue for SpecifiedUrl {
|
impl ToComputedValue for SpecifiedUrl {
|
||||||
|
@ -281,8 +260,8 @@ pub struct SpecifiedImageUrl(pub SpecifiedUrl);
|
||||||
|
|
||||||
impl SpecifiedImageUrl {
|
impl SpecifiedImageUrl {
|
||||||
/// Parse a URL from a string value that is a valid CSS token for a URL.
|
/// 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 {
|
||||||
SpecifiedImageUrl(SpecifiedUrl::parse_from_string(url, context))
|
SpecifiedImageUrl(SpecifiedUrl::parse_from_string(url, context, cors_mode))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Provides an alternate method for parsing that associates the URL
|
/// Provides an alternate method for parsing that associates the URL
|
||||||
|
@ -291,9 +270,11 @@ impl SpecifiedImageUrl {
|
||||||
context: &ParserContext,
|
context: &ParserContext,
|
||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
) -> Result<Self, ParseError<'i>> {
|
) -> Result<Self, ParseError<'i>> {
|
||||||
CssUrl::parse(context, input)
|
Ok(SpecifiedImageUrl(SpecifiedUrl::parse_with_cors_mode(
|
||||||
.map(SpecifiedUrl::from_css_url_with_cors_anonymous)
|
context,
|
||||||
.map(SpecifiedImageUrl)
|
input,
|
||||||
|
CorsMode::Anonymous,
|
||||||
|
)?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,10 +301,19 @@ impl ToComputedValue for SpecifiedImageUrl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_computed_url<W>(
|
/// The computed value of a CSS non-image `url()`.
|
||||||
url_value: &URLValue,
|
///
|
||||||
|
/// 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>,
|
dest: &mut CssWriter<W>,
|
||||||
get_url: unsafe extern "C" fn(*const URLValue, *mut nsCString),
|
|
||||||
) -> fmt::Result
|
) -> fmt::Result
|
||||||
where
|
where
|
||||||
W: Write,
|
W: Write,
|
||||||
|
@ -331,88 +321,48 @@ where
|
||||||
dest.write_str("url(")?;
|
dest.write_str("url(")?;
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut string = nsCString::new();
|
let mut string = nsCString::new();
|
||||||
get_url(url_value, &mut string);
|
function(self, &mut string);
|
||||||
string.as_str_unchecked().to_css(dest)?;
|
string.as_str_unchecked().to_css(dest)?;
|
||||||
}
|
}
|
||||||
dest.write_char(')')
|
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)]
|
|
||||||
pub struct ComputedUrl(pub SpecifiedUrl);
|
|
||||||
|
|
||||||
impl ToCss for ComputedUrl {
|
impl ToCss for ComputedUrl {
|
||||||
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||||
where
|
where
|
||||||
W: Write,
|
W: Write,
|
||||||
{
|
{
|
||||||
self.0
|
self.serialize_with(bindings::Gecko_GetComputedURLSpec, dest)
|
||||||
.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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The computed value of a CSS image `url()`.
|
/// The computed value of a CSS image `url()`.
|
||||||
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)]
|
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)]
|
||||||
|
#[repr(transparent)]
|
||||||
pub struct ComputedImageUrl(pub ComputedUrl);
|
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 {
|
impl ToCss for ComputedImageUrl {
|
||||||
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||||
where
|
where
|
||||||
W: Write,
|
W: Write,
|
||||||
{
|
{
|
||||||
(self.0).0.with_url_value(|r| {
|
self.0
|
||||||
serialize_computed_url(r, dest, bindings::Gecko_GetComputedImageURLSpec)
|
.serialize_with(bindings::Gecko_GetComputedImageURLSpec, dest)
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
/// A table mapping CssUrlData objects to their lazily created Gecko
|
/// A table mapping CssUrlData objects to their lazily created LoadData
|
||||||
/// URLValue objects.
|
/// objects.
|
||||||
static ref URL_VALUE_TABLE: RwLock<HashMap<CssUrlDataKey, RefPtr<URLValue>>> = {
|
static ref LOAD_DATA_TABLE: RwLock<HashMap<LoadDataKey, Box<LoadData>>> = {
|
||||||
Default::default()
|
Default::default()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -704,9 +704,8 @@ impl<'le> GeckoElement<'le> {
|
||||||
.map(GeckoElement)
|
.map(GeckoElement)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let binding_parent = unsafe { self.non_xul_xbl_binding_parent_raw_content().as_ref() }
|
let binding_parent =
|
||||||
.map(GeckoNode::from_content)
|
unsafe { self.non_xul_xbl_binding_parent().as_ref() }.map(GeckoElement);
|
||||||
.and_then(|n| n.as_element());
|
|
||||||
|
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
binding_parent ==
|
binding_parent ==
|
||||||
|
@ -721,11 +720,10 @@ impl<'le> GeckoElement<'le> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[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());
|
debug_assert!(!self.is_xul_element());
|
||||||
self.extended_slots().map_or(ptr::null_mut(), |slots| {
|
self.extended_slots()
|
||||||
slots._base.mBindingParent.raw::<nsIContent>()
|
.map_or(ptr::null_mut(), |slots| slots._base.mBindingParent.mRawPtr)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -1168,6 +1166,19 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
self.namespace_id() == structs::root::kNameSpaceID_XUL as i32
|
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.
|
/// Return the list of slotted nodes of this node.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn slotted_nodes(&self) -> &[Self::ConcreteNode] {
|
fn slotted_nodes(&self) -> &[Self::ConcreteNode] {
|
||||||
|
@ -1736,7 +1747,7 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
PropertyDeclaration::TextAlign(SpecifiedTextAlign::MozCenterOrInherit),
|
PropertyDeclaration::TextAlign(SpecifiedTextAlign::MozCenterOrInherit),
|
||||||
Importance::Normal,
|
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)
|
ApplicableDeclarationBlock::from_declarations(arc, ServoCascadeLevel::PresHints)
|
||||||
};
|
};
|
||||||
static ref TABLE_COLOR_RULE: ApplicableDeclarationBlock = {
|
static ref TABLE_COLOR_RULE: ApplicableDeclarationBlock = {
|
||||||
|
@ -1745,7 +1756,7 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
PropertyDeclaration::Color(SpecifiedColor(Color::InheritFromBodyQuirk.into())),
|
PropertyDeclaration::Color(SpecifiedColor(Color::InheritFromBodyQuirk.into())),
|
||||||
Importance::Normal,
|
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)
|
ApplicableDeclarationBlock::from_declarations(arc, ServoCascadeLevel::PresHints)
|
||||||
};
|
};
|
||||||
static ref MATHML_LANG_RULE: ApplicableDeclarationBlock = {
|
static ref MATHML_LANG_RULE: ApplicableDeclarationBlock = {
|
||||||
|
@ -1754,7 +1765,7 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
PropertyDeclaration::XLang(SpecifiedLang(atom!("x-math"))),
|
PropertyDeclaration::XLang(SpecifiedLang(atom!("x-math"))),
|
||||||
Importance::Normal,
|
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)
|
ApplicableDeclarationBlock::from_declarations(arc, ServoCascadeLevel::PresHints)
|
||||||
};
|
};
|
||||||
static ref SVG_TEXT_DISABLE_ZOOM_RULE: ApplicableDeclarationBlock = {
|
static ref SVG_TEXT_DISABLE_ZOOM_RULE: ApplicableDeclarationBlock = {
|
||||||
|
@ -1763,7 +1774,7 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
PropertyDeclaration::XTextZoom(SpecifiedZoom(false)),
|
PropertyDeclaration::XTextZoom(SpecifiedZoom(false)),
|
||||||
Importance::Normal,
|
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)
|
ApplicableDeclarationBlock::from_declarations(arc, ServoCascadeLevel::PresHints)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -2073,16 +2084,18 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn local_name(&self) -> &WeakAtom {
|
fn has_local_name(&self, name: &WeakAtom) -> bool {
|
||||||
unsafe { WeakAtom::new(self.as_node().node_info().mInner.mName) }
|
self.local_name() == name
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn namespace(&self) -> &WeakNamespace {
|
fn has_namespace(&self, ns: &WeakNamespace) -> bool {
|
||||||
unsafe {
|
self.namespace() == ns
|
||||||
let namespace_manager = structs::nsContentUtils_sNameSpaceManager;
|
|
||||||
WeakNamespace::new((*namespace_manager).mURIArray[self.namespace_id() as usize].mRawPtr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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>(
|
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.
|
/// Create a new RefPtr from a pointer obtained from FFI.
|
||||||
///
|
///
|
||||||
/// The pointer must be valid and non null.
|
|
||||||
///
|
|
||||||
/// This method calls addref() internally
|
/// This method calls addref() internally
|
||||||
pub unsafe fn new(ptr: *mut T) -> Self {
|
pub unsafe fn new(ptr: *mut T) -> Self {
|
||||||
debug_assert!(!ptr.is_null());
|
|
||||||
let ret = RefPtr {
|
let ret = RefPtr {
|
||||||
ptr: ptr,
|
ptr,
|
||||||
_marker: PhantomData,
|
_marker: PhantomData,
|
||||||
};
|
};
|
||||||
ret.addref();
|
ret.addref();
|
||||||
|
@ -97,18 +107,22 @@ impl<T: RefCounted> RefPtr<T> {
|
||||||
|
|
||||||
/// Addref the inner data, obviously leaky on its own.
|
/// Addref the inner data, obviously leaky on its own.
|
||||||
pub fn addref(&self) {
|
pub fn addref(&self) {
|
||||||
|
if !self.ptr.is_null() {
|
||||||
unsafe {
|
unsafe {
|
||||||
(*self.ptr).addref();
|
(*self.ptr).addref();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Release the inner data.
|
/// Release the inner data.
|
||||||
///
|
///
|
||||||
/// Call only when the data actually needs releasing.
|
/// Call only when the data actually needs releasing.
|
||||||
pub unsafe fn release(&self) {
|
pub unsafe fn release(&self) {
|
||||||
|
if !self.ptr.is_null() {
|
||||||
(*self.ptr).release();
|
(*self.ptr).release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: RefCounted> UniqueRefPtr<T> {
|
impl<T: RefCounted> UniqueRefPtr<T> {
|
||||||
/// Create a unique refptr from an already addrefed pointer obtained from
|
/// Create a unique refptr from an already addrefed pointer obtained from
|
||||||
|
@ -130,6 +144,7 @@ impl<T: RefCounted> UniqueRefPtr<T> {
|
||||||
impl<T: RefCounted> Deref for RefPtr<T> {
|
impl<T: RefCounted> Deref for RefPtr<T> {
|
||||||
type Target = T;
|
type Target = T;
|
||||||
fn deref(&self) -> &T {
|
fn deref(&self) -> &T {
|
||||||
|
debug_assert!(!self.ptr.is_null());
|
||||||
unsafe { &*self.ptr }
|
unsafe { &*self.ptr }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,7 +167,6 @@ impl<T: RefCounted> structs::RefPtr<T> {
|
||||||
///
|
///
|
||||||
/// Must be called on a valid, non-null structs::RefPtr<T>.
|
/// Must be called on a valid, non-null structs::RefPtr<T>.
|
||||||
pub unsafe fn to_safe(&self) -> RefPtr<T> {
|
pub unsafe fn to_safe(&self) -> RefPtr<T> {
|
||||||
debug_assert!(!self.mRawPtr.is_null());
|
|
||||||
let r = RefPtr {
|
let r = RefPtr {
|
||||||
ptr: self.mRawPtr,
|
ptr: self.mRawPtr,
|
||||||
_marker: PhantomData,
|
_marker: PhantomData,
|
||||||
|
@ -290,9 +304,9 @@ impl_threadsafe_refcount!(
|
||||||
bindings::Gecko_ReleaseURLExtraDataArbitraryThread
|
bindings::Gecko_ReleaseURLExtraDataArbitraryThread
|
||||||
);
|
);
|
||||||
impl_threadsafe_refcount!(
|
impl_threadsafe_refcount!(
|
||||||
structs::mozilla::css::URLValue,
|
structs::nsIURI,
|
||||||
bindings::Gecko_AddRefCSSURLValueArbitraryThread,
|
bindings::Gecko_AddRefnsIURIArbitraryThread,
|
||||||
bindings::Gecko_ReleaseCSSURLValueArbitraryThread
|
bindings::Gecko_ReleasensIURIArbitraryThread
|
||||||
);
|
);
|
||||||
impl_threadsafe_refcount!(
|
impl_threadsafe_refcount!(
|
||||||
structs::mozilla::css::GridTemplateAreasValue,
|
structs::mozilla::css::GridTemplateAreasValue,
|
||||||
|
|
|
@ -125,7 +125,7 @@ lazy_static! {
|
||||||
};
|
};
|
||||||
/// Global style data
|
/// Global style data
|
||||||
pub static ref GLOBAL_STYLE_DATA: GlobalStyleData = GlobalStyleData {
|
pub static ref GLOBAL_STYLE_DATA: GlobalStyleData = GlobalStyleData {
|
||||||
shared_lock: SharedRwLock::new(),
|
shared_lock: SharedRwLock::new_leaked(),
|
||||||
options: StyleSystemOptions::default(),
|
options: StyleSystemOptions::default(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -312,13 +312,24 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn local_name(&self) -> &<Self::Impl as ::selectors::SelectorImpl>::BorrowedLocalName {
|
fn has_local_name(
|
||||||
self.element.local_name()
|
&self,
|
||||||
|
local_name: &<Self::Impl as ::selectors::SelectorImpl>::BorrowedLocalName,
|
||||||
|
) -> bool {
|
||||||
|
self.element.has_local_name(local_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn namespace(&self) -> &<Self::Impl as ::selectors::SelectorImpl>::BorrowedNamespaceUrl {
|
fn has_namespace(
|
||||||
self.element.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(
|
fn attr_matches(
|
||||||
|
|
|
@ -718,7 +718,7 @@ pub trait MatchMethods: TElement {
|
||||||
let device = context.shared.stylist.device();
|
let device = context.shared.stylist.device();
|
||||||
|
|
||||||
// Needed for the "inherit from body" quirk.
|
// 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);
|
device.set_body_text_color(text_color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,6 @@ STYLE_STRUCT_LIST = [
|
||||||
"background",
|
"background",
|
||||||
"border",
|
"border",
|
||||||
"box",
|
"box",
|
||||||
"color",
|
|
||||||
"column",
|
"column",
|
||||||
"counters",
|
"counters",
|
||||||
"effects",
|
"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_SetListStyleImageNone;
|
||||||
use crate::gecko_bindings::bindings::Gecko_SetListStyleImageImageValue;
|
use crate::gecko_bindings::bindings::Gecko_SetListStyleImageImageValue;
|
||||||
use crate::gecko_bindings::bindings::Gecko_SetNullImageValue;
|
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;
|
||||||
use crate::gecko_bindings::structs::nsCSSPropertyID;
|
use crate::gecko_bindings::structs::nsCSSPropertyID;
|
||||||
use crate::gecko_bindings::structs::mozilla::PseudoStyleType;
|
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_bindings::sugar::refptr::RefPtr;
|
||||||
use crate::gecko::values::GeckoStyleCoordConvertible;
|
|
||||||
use crate::gecko::values::round_border_to_device_pixels;
|
use crate::gecko::values::round_border_to_device_pixels;
|
||||||
use crate::logical_geometry::WritingMode;
|
use crate::logical_geometry::WritingMode;
|
||||||
use crate::media_queries::Device;
|
use crate::media_queries::Device;
|
||||||
|
@ -52,11 +50,10 @@ use std::marker::PhantomData;
|
||||||
use std::mem::{forget, uninitialized, zeroed, ManuallyDrop};
|
use std::mem::{forget, uninitialized, zeroed, ManuallyDrop};
|
||||||
use std::{cmp, ops, ptr};
|
use std::{cmp, ops, ptr};
|
||||||
use crate::values::{self, CustomIdent, Either, KeyframesName, None_};
|
use crate::values::{self, CustomIdent, Either, KeyframesName, None_};
|
||||||
use crate::values::computed::{NonNegativeLength, Percentage, TransitionProperty};
|
use crate::values::computed::{Percentage, TransitionProperty};
|
||||||
use crate::values::computed::url::ComputedImageUrl;
|
use crate::values::computed::url::ComputedImageUrl;
|
||||||
use crate::values::computed::BorderStyle;
|
use crate::values::computed::BorderStyle;
|
||||||
use crate::values::computed::font::FontSize;
|
use crate::values::computed::font::FontSize;
|
||||||
use crate::values::computed::effects::Filter;
|
|
||||||
use crate::values::generics::column::ColumnCount;
|
use crate::values::generics::column::ColumnCount;
|
||||||
use crate::values::generics::transform::TransformStyle;
|
use crate::values::generics::transform::TransformStyle;
|
||||||
use crate::values::generics::url::UrlOrNone;
|
use crate::values::generics::url::UrlOrNone;
|
||||||
|
@ -278,7 +275,7 @@ impl ComputedValuesInner {
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub fn has_moz_binding(&self) -> bool {
|
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 {
|
unsafe {
|
||||||
bindings::Gecko_nsStyleSVGPaint_SetURLValue(
|
bindings::Gecko_nsStyleSVGPaint_SetURLValue(
|
||||||
paint,
|
paint,
|
||||||
url.url_value_ptr(),
|
&url
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -591,7 +588,6 @@ def set_gecko_property(ffi_name, expr):
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
|
pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
|
||||||
use crate::values::computed::url::ComputedUrl;
|
|
||||||
use crate::values::generics::svg::{SVGPaint, SVGPaintKind};
|
use crate::values::generics::svg::{SVGPaint, SVGPaintKind};
|
||||||
use self::structs::nsStyleSVGPaintType;
|
use self::structs::nsStyleSVGPaintType;
|
||||||
use self::structs::nsStyleSVGFallbackType;
|
use self::structs::nsStyleSVGFallbackType;
|
||||||
|
@ -613,8 +609,7 @@ def set_gecko_property(ffi_name, expr):
|
||||||
nsStyleSVGPaintType::eStyleSVGPaintType_ContextStroke => SVGPaintKind::ContextStroke,
|
nsStyleSVGPaintType::eStyleSVGPaintType_ContextStroke => SVGPaintKind::ContextStroke,
|
||||||
nsStyleSVGPaintType::eStyleSVGPaintType_Server => {
|
nsStyleSVGPaintType::eStyleSVGPaintType_Server => {
|
||||||
SVGPaintKind::PaintServer(unsafe {
|
SVGPaintKind::PaintServer(unsafe {
|
||||||
let url = RefPtr::new(*paint.mPaint.mPaintServer.as_ref());
|
paint.mPaint.mPaintServer.as_ref().clone()
|
||||||
ComputedUrl::from_url_value(url)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
nsStyleSVGPaintType::eStyleSVGPaintType_Color => {
|
nsStyleSVGPaintType::eStyleSVGPaintType_Color => {
|
||||||
|
@ -735,45 +730,6 @@ def set_gecko_property(ffi_name, expr):
|
||||||
}
|
}
|
||||||
</%def>
|
</%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)">
|
<%def name="impl_logical(name, **kwargs)">
|
||||||
${helpers.logical_setter(name)}
|
${helpers.logical_setter(name)}
|
||||||
</%def>
|
</%def>
|
||||||
|
@ -879,7 +835,6 @@ impl Clone for ${style_struct.gecko_struct_name} {
|
||||||
"SVGOpacity": impl_svg_opacity,
|
"SVGOpacity": impl_svg_opacity,
|
||||||
"SVGPaint": impl_svg_paint,
|
"SVGPaint": impl_svg_paint,
|
||||||
"SVGWidth": impl_svg_length,
|
"SVGWidth": impl_svg_length,
|
||||||
"url::UrlOrNone": impl_css_url,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def longhand_method(longhand):
|
def longhand_method(longhand):
|
||||||
|
@ -2164,8 +2119,7 @@ fn static_assert() {
|
||||||
animation-iteration-count animation-timing-function
|
animation-iteration-count animation-timing-function
|
||||||
clear transition-duration transition-delay
|
clear transition-duration transition-delay
|
||||||
transition-timing-function transition-property
|
transition-timing-function transition-property
|
||||||
transform-style -moz-binding shape-outside
|
transform-style shape-outside -webkit-line-clamp""" %>
|
||||||
-webkit-line-clamp""" %>
|
|
||||||
<%self:impl_trait style_struct_name="Box" skip_longhands="${skip_box_longhands}">
|
<%self:impl_trait style_struct_name="Box" skip_longhands="${skip_box_longhands}">
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_display(&mut self, v: longhands::display::computed_value::T) {
|
pub fn set_display(&mut self, v: longhands::display::computed_value::T) {
|
||||||
|
@ -2205,7 +2159,7 @@ fn static_assert() {
|
||||||
gecko_inexhaustive=True,
|
gecko_inexhaustive=True,
|
||||||
) %>
|
) %>
|
||||||
${impl_keyword('clear', 'mBreakType', clear_keyword)}
|
${impl_keyword('clear', 'mBreakType', clear_keyword)}
|
||||||
${impl_css_url('_moz_binding', 'mBinding')}
|
|
||||||
${impl_transition_time_value('delay', 'Delay')}
|
${impl_transition_time_value('delay', 'Delay')}
|
||||||
${impl_transition_time_value('duration', 'Duration')}
|
${impl_transition_time_value('duration', 'Duration')}
|
||||||
${impl_transition_timing_function()}
|
${impl_transition_timing_function()}
|
||||||
|
@ -2834,10 +2788,7 @@ fn static_assert() {
|
||||||
}
|
}
|
||||||
UrlOrNone::Url(ref url) => {
|
UrlOrNone::Url(ref url) => {
|
||||||
unsafe {
|
unsafe {
|
||||||
Gecko_SetListStyleImageImageValue(
|
Gecko_SetListStyleImageImageValue(&mut *self.gecko, url);
|
||||||
&mut *self.gecko,
|
|
||||||
url.url_value_ptr(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2973,8 +2924,7 @@ fn static_assert() {
|
||||||
${impl_simple_copy('_x_span', 'mSpan')}
|
${impl_simple_copy('_x_span', 'mSpan')}
|
||||||
</%self:impl_trait>
|
</%self:impl_trait>
|
||||||
|
|
||||||
<%self:impl_trait style_struct_name="Effects"
|
<%self:impl_trait style_struct_name="Effects" skip_longhands="clip">
|
||||||
skip_longhands="clip filter">
|
|
||||||
pub fn set_clip(&mut self, v: longhands::clip::computed_value::T) {
|
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_AUTO;
|
||||||
use crate::gecko_bindings::structs::NS_STYLE_CLIP_RECT;
|
use crate::gecko_bindings::structs::NS_STYLE_CLIP_RECT;
|
||||||
|
@ -3082,138 +3032,6 @@ fn static_assert() {
|
||||||
|
|
||||||
Either::First(ClipRect { top, right, bottom, left })
|
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>
|
||||||
|
|
||||||
<%self:impl_trait style_struct_name="InheritedBox">
|
<%self:impl_trait style_struct_name="InheritedBox">
|
||||||
|
@ -3537,9 +3355,6 @@ clip-path
|
||||||
}
|
}
|
||||||
</%self:impl_trait>
|
</%self:impl_trait>
|
||||||
|
|
||||||
<%self:impl_trait style_struct_name="Color">
|
|
||||||
</%self:impl_trait>
|
|
||||||
|
|
||||||
<%self:impl_trait style_struct_name="InheritedUI" skip_longhands="cursor">
|
<%self:impl_trait style_struct_name="InheritedUI" skip_longhands="cursor">
|
||||||
pub fn set_cursor(&mut self, v: longhands::cursor::computed_value::T) {
|
pub fn set_cursor(&mut self, v: longhands::cursor::computed_value::T) {
|
||||||
self.gecko.mCursor = v.keyword;
|
self.gecko.mCursor = v.keyword;
|
||||||
|
@ -3550,7 +3365,7 @@ clip-path
|
||||||
unsafe {
|
unsafe {
|
||||||
Gecko_SetCursorImageValue(
|
Gecko_SetCursorImageValue(
|
||||||
&mut self.gecko.mCursorImages[i],
|
&mut self.gecko.mCursorImages[i],
|
||||||
v.images[i].url.url_value_ptr(),
|
&v.images[i].url
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3769,7 +3584,7 @@ clip-path
|
||||||
unsafe {
|
unsafe {
|
||||||
bindings::Gecko_SetContentDataImageValue(
|
bindings::Gecko_SetContentDataImageValue(
|
||||||
&mut self.gecko.mContents[i],
|
&mut self.gecko.mContents[i],
|
||||||
url.url_value_ptr(),
|
url,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ use std::mem::{self, ManuallyDrop};
|
||||||
use crate::hash::FxHashMap;
|
use crate::hash::FxHashMap;
|
||||||
use super::ComputedValues;
|
use super::ComputedValues;
|
||||||
use crate::values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
|
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;
|
#[cfg(feature = "gecko")] use crate::values::computed::TransitionProperty;
|
||||||
use crate::values::computed::{ClipRect, Context};
|
use crate::values::computed::{ClipRect, Context};
|
||||||
use crate::values::computed::ToComputedValue;
|
use crate::values::computed::ToComputedValue;
|
||||||
|
|
|
@ -390,7 +390,7 @@ ${helpers.predefined_type(
|
||||||
"OffsetRotate",
|
"OffsetRotate",
|
||||||
"computed::OffsetRotate::auto()",
|
"computed::OffsetRotate::auto()",
|
||||||
products="gecko",
|
products="gecko",
|
||||||
animation_value_type="none",
|
animation_value_type="ComputedValue",
|
||||||
gecko_pref="layout.css.motion-path.enabled",
|
gecko_pref="layout.css.motion-path.enabled",
|
||||||
spec="https://drafts.fxtf.org/motion-1/#offset-rotate-property",
|
spec="https://drafts.fxtf.org/motion-1/#offset-rotate-property",
|
||||||
servo_restyle_damage="reflow_out_of_flow"
|
servo_restyle_damage="reflow_out_of_flow"
|
||||||
|
@ -644,7 +644,6 @@ ${helpers.predefined_type(
|
||||||
"basic_shape::FloatAreaShape",
|
"basic_shape::FloatAreaShape",
|
||||||
"generics::basic_shape::ShapeSource::None",
|
"generics::basic_shape::ShapeSource::None",
|
||||||
products="gecko",
|
products="gecko",
|
||||||
boxed=True,
|
|
||||||
animation_value_type="basic_shape::FloatAreaShape",
|
animation_value_type="basic_shape::FloatAreaShape",
|
||||||
flags="APPLIES_TO_FIRST_LETTER",
|
flags="APPLIES_TO_FIRST_LETTER",
|
||||||
spec="https://drafts.csswg.org/css-shapes/#shape-outside-property",
|
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",
|
"Filter",
|
||||||
None,
|
None,
|
||||||
vector=True,
|
vector=True,
|
||||||
|
simple_vector_bindings=True,
|
||||||
|
gecko_ffi_name="mFilters",
|
||||||
separator="Space",
|
separator="Space",
|
||||||
animation_value_type="AnimatedFilterList",
|
animation_value_type="AnimatedFilterList",
|
||||||
vector_animation_type="with_zero",
|
vector_animation_type="with_zero",
|
||||||
|
|
|
@ -6,6 +6,16 @@
|
||||||
<% from data import Keyword %>
|
<% from data import Keyword %>
|
||||||
<% data.new_style_struct("InheritedText", inherited=True, gecko_name="Text") %>
|
<% 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(
|
${helpers.predefined_type(
|
||||||
"line-height",
|
"line-height",
|
||||||
"LineHeight",
|
"LineHeight",
|
||||||
|
|
|
@ -2832,7 +2832,7 @@ impl ComputedValues {
|
||||||
/// style.resolve_color(style.get_border().clone_border_top_color());
|
/// style.resolve_color(style.get_border().clone_border_top_color());
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn resolve_color(&self, color: computed::Color) -> RGBA {
|
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;
|
use crate::applicable_declarations::ApplicableDeclarationList;
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
use crate::gecko::selector_parser::PseudoElement;
|
use crate::gecko::selector_parser::PseudoElement;
|
||||||
|
use crate::hash::{self, FxHashMap};
|
||||||
use crate::properties::{Importance, LonghandIdSet, PropertyDeclarationBlock};
|
use crate::properties::{Importance, LonghandIdSet, PropertyDeclarationBlock};
|
||||||
use crate::shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
|
use crate::shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
|
||||||
use crate::stylesheets::{Origin, StyleRule};
|
use crate::stylesheets::{Origin, StyleRule};
|
||||||
use crate::thread_state;
|
use crate::thread_state;
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
|
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
|
||||||
|
use parking_lot::RwLock;
|
||||||
use servo_arc::{Arc, ArcBorrow, ArcUnion, ArcUnionBorrow};
|
use servo_arc::{Arc, ArcBorrow, ArcUnion, ArcUnionBorrow};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
|
@ -81,13 +83,25 @@ impl MallocSizeOf for RuleTree {
|
||||||
|
|
||||||
while let Some(node) = stack.pop() {
|
while let Some(node) = stack.pop() {
|
||||||
n += unsafe { ops.malloc_size_of(node.ptr()) };
|
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
|
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
|
/// A style source for the rule node. It can either be a CSS style rule or a
|
||||||
/// declaration block.
|
/// declaration block.
|
||||||
///
|
///
|
||||||
|
@ -110,6 +124,11 @@ impl StyleSource {
|
||||||
StyleSource(ArcUnion::from_first(rule))
|
StyleSource(ArcUnion::from_first(rule))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn key(&self) -> ptr::NonNull<()> {
|
||||||
|
self.0.ptr()
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a StyleSource from a PropertyDeclarationBlock.
|
/// Creates a StyleSource from a PropertyDeclarationBlock.
|
||||||
pub fn from_declarations(decls: Arc<Locked<PropertyDeclarationBlock>>) -> Self {
|
pub fn from_declarations(decls: Arc<Locked<PropertyDeclarationBlock>>) -> Self {
|
||||||
StyleSource(ArcUnion::from_second(decls))
|
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
|
/// [3]: https://html.spec.whatwg.org/multipage/#presentational-hints
|
||||||
/// [4]: https://drafts.csswg.org/css-scoping/#shadow-cascading
|
/// [4]: https://drafts.csswg.org/css-scoping/#shadow-cascading
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd)]
|
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd)]
|
||||||
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
|
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
|
||||||
pub enum CascadeLevel {
|
pub enum CascadeLevel {
|
||||||
/// Normal User-Agent rules.
|
/// 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.
|
/// A node in the rule tree.
|
||||||
pub struct RuleNode {
|
pub struct RuleNode {
|
||||||
/// The root node. Only the root has no root pointer, for obvious reasons.
|
/// The root node. Only the root has no root pointer, for obvious reasons.
|
||||||
|
@ -732,15 +734,14 @@ pub struct RuleNode {
|
||||||
level: CascadeLevel,
|
level: CascadeLevel,
|
||||||
|
|
||||||
refcount: AtomicUsize,
|
refcount: AtomicUsize,
|
||||||
first_child: AtomicPtr<RuleNode>,
|
|
||||||
next_sibling: AtomicPtr<RuleNode>,
|
|
||||||
|
|
||||||
/// Previous sibling pointer for all non-root nodes.
|
/// Only used for the root, stores the number of free rule nodes that are
|
||||||
///
|
/// around.
|
||||||
/// For the root, stores the of RuleNodes we have added to the free list
|
free_count: AtomicUsize,
|
||||||
/// 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.)
|
/// The children of a given rule node. Children remove themselves from here
|
||||||
prev_sibling_or_free_count: PrevSiblingOrFreeCount,
|
/// when they go away.
|
||||||
|
children: RwLock<FxHashMap<ChildKey, WeakRuleNode>>,
|
||||||
|
|
||||||
/// The next item in the rule tree free list, that starts on the root node.
|
/// 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 {}
|
unsafe impl Send for RuleTree {}
|
||||||
|
|
||||||
// On Gecko builds, hook into the leak checking machinery.
|
// On Gecko builds, hook into the leak checking machinery.
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko_refcount_logging")]
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
mod gecko_leak_checking {
|
mod gecko_leak_checking {
|
||||||
use super::RuleNode;
|
use super::RuleNode;
|
||||||
use std::mem::size_of;
|
use std::mem::size_of;
|
||||||
|
@ -789,15 +789,13 @@ mod gecko_leak_checking {
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn log_new(_ptr: *const RuleNode) {
|
fn log_new(_ptr: *const RuleNode) {
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko_refcount_logging")]
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
gecko_leak_checking::log_ctor(_ptr);
|
gecko_leak_checking::log_ctor(_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn log_drop(_ptr: *const RuleNode) {
|
fn log_drop(_ptr: *const RuleNode) {
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko_refcount_logging")]
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
gecko_leak_checking::log_dtor(_ptr);
|
gecko_leak_checking::log_dtor(_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -815,9 +813,8 @@ impl RuleNode {
|
||||||
source: Some(source),
|
source: Some(source),
|
||||||
level: level,
|
level: level,
|
||||||
refcount: AtomicUsize::new(1),
|
refcount: AtomicUsize::new(1),
|
||||||
first_child: AtomicPtr::new(ptr::null_mut()),
|
children: Default::default(),
|
||||||
next_sibling: AtomicPtr::new(ptr::null_mut()),
|
free_count: AtomicUsize::new(0),
|
||||||
prev_sibling_or_free_count: PrevSiblingOrFreeCount::new(),
|
|
||||||
next_free: AtomicPtr::new(ptr::null_mut()),
|
next_free: AtomicPtr::new(ptr::null_mut()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -829,75 +826,39 @@ impl RuleNode {
|
||||||
source: None,
|
source: None,
|
||||||
level: CascadeLevel::UANormal,
|
level: CascadeLevel::UANormal,
|
||||||
refcount: AtomicUsize::new(1),
|
refcount: AtomicUsize::new(1),
|
||||||
first_child: AtomicPtr::new(ptr::null_mut()),
|
free_count: AtomicUsize::new(0),
|
||||||
next_sibling: AtomicPtr::new(ptr::null_mut()),
|
children: Default::default(),
|
||||||
prev_sibling_or_free_count: PrevSiblingOrFreeCount::new(),
|
|
||||||
next_free: AtomicPtr::new(FREE_LIST_SENTINEL),
|
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 {
|
fn is_root(&self) -> bool {
|
||||||
self.parent.is_none()
|
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 {
|
fn free_count(&self) -> &AtomicUsize {
|
||||||
debug_assert!(self.is_root());
|
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.
|
/// 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
|
/// 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) {
|
unsafe fn remove_from_child_list(&self) {
|
||||||
debug!(
|
debug!(
|
||||||
"Remove from child list: {:?}, parent: {:?}",
|
"Remove from child list: {:?}, parent: {:?}",
|
||||||
self as *const RuleNode,
|
self as *const RuleNode,
|
||||||
self.parent.as_ref().map(|p| p.ptr())
|
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);
|
if let Some(parent) = self.parent.as_ref() {
|
||||||
|
let weak = parent.get().children.write().remove(&self.key().unwrap());
|
||||||
// Store the `next` pointer as appropriate, either in the previous
|
assert_eq!(weak.unwrap().ptr() as *const _, self as *const _);
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -933,25 +894,13 @@ impl RuleNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = write!(writer, "\n");
|
let _ = write!(writer, "\n");
|
||||||
for child in self.iter_children() {
|
for (_, child) in self.children.read().iter() {
|
||||||
child
|
child
|
||||||
.upgrade()
|
.upgrade()
|
||||||
.get()
|
.get()
|
||||||
.dump(guards, writer, indent + INDENT_INCREMENT);
|
.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)]
|
#[derive(Clone)]
|
||||||
|
@ -975,22 +924,21 @@ impl StrongRuleNode {
|
||||||
fn new(n: Box<RuleNode>) -> Self {
|
fn new(n: Box<RuleNode>) -> Self {
|
||||||
debug_assert_eq!(n.parent.is_none(), !n.source.is_some());
|
debug_assert_eq!(n.parent.is_none(), !n.source.is_some());
|
||||||
|
|
||||||
let ptr = Box::into_raw(n);
|
// TODO(emilio): Use into_raw_non_null when it's stable.
|
||||||
log_new(ptr);
|
let ptr = unsafe { ptr::NonNull::new_unchecked(Box::into_raw(n)) };
|
||||||
|
log_new(ptr.as_ptr());
|
||||||
|
|
||||||
debug!("Creating rule node: {:p}", ptr);
|
debug!("Creating rule node: {:p}", ptr);
|
||||||
|
|
||||||
StrongRuleNode::from_ptr(ptr)
|
StrongRuleNode::from_ptr(ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_ptr(ptr: *mut RuleNode) -> Self {
|
fn from_ptr(p: ptr::NonNull<RuleNode>) -> Self {
|
||||||
StrongRuleNode {
|
StrongRuleNode { p }
|
||||||
p: ptr::NonNull::new(ptr).expect("Pointer must not be null"),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn downgrade(&self) -> WeakRuleNode {
|
fn downgrade(&self) -> WeakRuleNode {
|
||||||
WeakRuleNode::from_ptr(self.ptr())
|
WeakRuleNode::from_ptr(self.p)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the parent rule node of this rule node.
|
/// Get the parent rule node of this rule node.
|
||||||
|
@ -1004,80 +952,44 @@ impl StrongRuleNode {
|
||||||
source: StyleSource,
|
source: StyleSource,
|
||||||
level: CascadeLevel,
|
level: CascadeLevel,
|
||||||
) -> StrongRuleNode {
|
) -> StrongRuleNode {
|
||||||
let mut last = None;
|
use parking_lot::RwLockUpgradableReadGuard;
|
||||||
|
|
||||||
// NB: This is an iterator over _weak_ nodes.
|
let key = ChildKey(level, source.key());
|
||||||
//
|
|
||||||
// It's fine though, because nothing can make us GC while this happens,
|
let read_guard = self.get().children.upgradable_read();
|
||||||
// and this happens to be hot.
|
if let Some(child) = read_guard.get(&key) {
|
||||||
//
|
|
||||||
// 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();
|
return child.upgrade();
|
||||||
}
|
}
|
||||||
last = Some(child);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut node = Box::new(RuleNode::new(root, self.clone(), source.clone(), level));
|
match RwLockUpgradableReadGuard::upgrade(read_guard).entry(key) {
|
||||||
let new_ptr: *mut RuleNode = &mut *node;
|
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 {
|
vacant.insert(new_node.downgrade());
|
||||||
let next;
|
|
||||||
|
|
||||||
{
|
new_node
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Raw pointer to the RuleNode
|
/// Raw pointer to the RuleNode
|
||||||
|
#[inline]
|
||||||
pub fn ptr(&self) -> *mut RuleNode {
|
pub fn ptr(&self) -> *mut RuleNode {
|
||||||
self.p.as_ptr()
|
self.p.as_ptr()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get(&self) -> &RuleNode {
|
fn get(&self) -> &RuleNode {
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
let node = unsafe { &*self.ptr() };
|
let node = unsafe { &*self.p.as_ptr() };
|
||||||
assert!(node.refcount.load(Ordering::Relaxed) > 0);
|
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`
|
/// 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
|
/// Returns whether this node has any child, only intended for testing
|
||||||
/// purposes, and called on a single-threaded fashion only.
|
/// purposes, and called on a single-threaded fashion only.
|
||||||
pub unsafe fn has_children_for_testing(&self) -> bool {
|
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> {
|
unsafe fn pop_from_free_list(&self) -> Option<WeakRuleNode> {
|
||||||
// NB: This can run from the root node destructor, so we can't use
|
// NB: This can run from the root node destructor, so we can't use
|
||||||
// `get()`, since it asserts the refcount is bigger than zero.
|
// `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());
|
debug_assert!(me.is_root());
|
||||||
|
|
||||||
|
@ -1139,7 +1051,7 @@ impl StrongRuleNode {
|
||||||
same time?"
|
same time?"
|
||||||
);
|
);
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
current != self.ptr(),
|
current != self.p.as_ptr(),
|
||||||
"How did the root end up in the free list?"
|
"How did the root end up in the free list?"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1159,17 +1071,17 @@ impl StrongRuleNode {
|
||||||
current, next
|
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) {
|
unsafe fn assert_free_list_has_no_duplicates_or_null(&self) {
|
||||||
assert!(cfg!(debug_assertions), "This is an expensive check!");
|
assert!(cfg!(debug_assertions), "This is an expensive check!");
|
||||||
use crate::hash::FxHashSet;
|
use crate::hash::FxHashSet;
|
||||||
|
|
||||||
let me = &*self.ptr();
|
let me = &*self.p.as_ptr();
|
||||||
assert!(me.is_root());
|
assert!(me.is_root());
|
||||||
|
|
||||||
let mut current = self.ptr();
|
let mut current = self.p.as_ptr();
|
||||||
let mut seen = FxHashSet::default();
|
let mut seen = FxHashSet::default();
|
||||||
while current != FREE_LIST_SENTINEL {
|
while current != FREE_LIST_SENTINEL {
|
||||||
let next = (*current).next_free.load(Ordering::Relaxed);
|
let next = (*current).next_free.load(Ordering::Relaxed);
|
||||||
|
@ -1188,21 +1100,21 @@ impl StrongRuleNode {
|
||||||
|
|
||||||
// NB: This can run from the root node destructor, so we can't use
|
// NB: This can run from the root node destructor, so we can't use
|
||||||
// `get()`, since it asserts the refcount is bigger than zero.
|
// `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!");
|
debug_assert!(me.is_root(), "Can't call GC on a non-root node!");
|
||||||
|
|
||||||
while let Some(weak) = self.pop_from_free_list() {
|
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 {
|
if node.refcount.load(Ordering::Relaxed) != 0 {
|
||||||
// Nothing to do, the node is still alive.
|
// Nothing to do, the node is still alive.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("GC'ing {:?}", weak.ptr());
|
debug!("GC'ing {:?}", weak.p.as_ptr());
|
||||||
node.remove_from_child_list();
|
node.remove_from_child_list();
|
||||||
log_drop(weak.ptr());
|
log_drop(weak.p.as_ptr());
|
||||||
let _ = Box::from_raw(weak.ptr());
|
let _ = Box::from_raw(weak.p.as_ptr());
|
||||||
}
|
}
|
||||||
|
|
||||||
me.free_count().store(0, Ordering::Relaxed);
|
me.free_count().store(0, Ordering::Relaxed);
|
||||||
|
@ -1509,7 +1421,7 @@ impl Clone for StrongRuleNode {
|
||||||
);
|
);
|
||||||
debug_assert!(self.get().refcount.load(Ordering::Relaxed) > 0);
|
debug_assert!(self.get().refcount.load(Ordering::Relaxed) > 0);
|
||||||
self.get().refcount.fetch_add(1, Ordering::Relaxed);
|
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;
|
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() {
|
if node.parent.is_none() {
|
||||||
debug!("Dropping root node!");
|
debug!("Dropping root node!");
|
||||||
// The free list should be null by this point
|
// The free list should be null by this point
|
||||||
|
@ -1655,41 +1567,25 @@ impl Drop for StrongRuleNode {
|
||||||
|
|
||||||
impl<'a> From<&'a StrongRuleNode> for WeakRuleNode {
|
impl<'a> From<&'a StrongRuleNode> for WeakRuleNode {
|
||||||
fn from(node: &'a StrongRuleNode) -> Self {
|
fn from(node: &'a StrongRuleNode) -> Self {
|
||||||
WeakRuleNode::from_ptr(node.ptr())
|
WeakRuleNode::from_ptr(node.p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WeakRuleNode {
|
impl WeakRuleNode {
|
||||||
|
#[inline]
|
||||||
|
fn ptr(&self) -> *mut RuleNode {
|
||||||
|
self.p.as_ptr()
|
||||||
|
}
|
||||||
|
|
||||||
fn upgrade(&self) -> StrongRuleNode {
|
fn upgrade(&self) -> StrongRuleNode {
|
||||||
debug!("Upgrading weak node: {:p}", self.ptr());
|
debug!("Upgrading weak node: {:p}", self.ptr());
|
||||||
|
|
||||||
let node = unsafe { &*self.ptr() };
|
let node = unsafe { &*self.ptr() };
|
||||||
node.refcount.fetch_add(1, Ordering::Relaxed);
|
node.refcount.fetch_add(1, Ordering::Relaxed);
|
||||||
StrongRuleNode::from_ptr(self.ptr())
|
StrongRuleNode::from_ptr(self.p)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_ptr(ptr: *mut RuleNode) -> Self {
|
fn from_ptr(p: ptr::NonNull<RuleNode>) -> Self {
|
||||||
WeakRuleNode {
|
WeakRuleNode { p }
|
||||||
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
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,14 +5,12 @@
|
||||||
//! Common handling for the specified value CSS url() values.
|
//! Common handling for the specified value CSS url() values.
|
||||||
|
|
||||||
use crate::parser::{Parse, ParserContext};
|
use crate::parser::{Parse, ParserContext};
|
||||||
|
use crate::stylesheets::CorsMode;
|
||||||
|
use crate::values::computed::{Context, ToComputedValue};
|
||||||
use cssparser::Parser;
|
use cssparser::Parser;
|
||||||
|
use servo_arc::Arc;
|
||||||
use servo_url::ServoUrl;
|
use servo_url::ServoUrl;
|
||||||
use std::fmt::{self, Write};
|
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};
|
use style_traits::{CssWriter, ParseError, ToCss};
|
||||||
|
|
||||||
/// A CSS url() value for servo.
|
/// A CSS url() value for servo.
|
||||||
|
@ -44,7 +42,9 @@ pub struct CssUrl {
|
||||||
impl CssUrl {
|
impl CssUrl {
|
||||||
/// Try to parse a URL from a string value that is a valid CSS token for a
|
/// Try to parse a URL from a string value that is a valid CSS token for a
|
||||||
/// URL.
|
/// 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 serialization = Arc::new(url);
|
||||||
let resolved = context.url_data.join(&serialization).ok();
|
let resolved = context.url_data.join(&serialization).ok();
|
||||||
CssUrl {
|
CssUrl {
|
||||||
|
@ -121,7 +121,11 @@ impl Parse for CssUrl {
|
||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
) -> Result<Self, ParseError<'i>> {
|
) -> Result<Self, ParseError<'i>> {
|
||||||
let url = input.expect_url()?;
|
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).
|
/// Create a new read-only shared lock (gecko).
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
pub fn read_only() -> Self {
|
pub fn read_only() -> Self {
|
||||||
|
|
|
@ -485,8 +485,12 @@ type SharingCache<E> = SharingCacheBase<StyleSharingCandidate<E>>;
|
||||||
type TypelessSharingCache = SharingCacheBase<FakeCandidate>;
|
type TypelessSharingCache = SharingCacheBase<FakeCandidate>;
|
||||||
type StoredSharingCache = Arc<AtomicRefCell<TypelessSharingCache>>;
|
type StoredSharingCache = Arc<AtomicRefCell<TypelessSharingCache>>;
|
||||||
|
|
||||||
thread_local!(static SHARING_CACHE_KEY: StoredSharingCache =
|
thread_local! {
|
||||||
Arc::new(AtomicRefCell::new(TypelessSharingCache::default())));
|
// 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
|
/// An LRU cache of the last few nodes seen, so that we can aggressively try to
|
||||||
/// reuse their styles.
|
/// reuse their styles.
|
||||||
|
|
|
@ -63,9 +63,15 @@ pub use self::stylesheet::{StylesheetContents, StylesheetInDocument, UserAgentSt
|
||||||
pub use self::supports_rule::SupportsRule;
|
pub use self::supports_rule::SupportsRule;
|
||||||
pub use self::viewport_rule::ViewportRule;
|
pub use self::viewport_rule::ViewportRule;
|
||||||
|
|
||||||
/// Extra data that the backend may need to resolve url values.
|
/// The CORS mode used for a CSS load.
|
||||||
#[cfg(not(feature = "gecko"))]
|
#[repr(u8)]
|
||||||
pub type UrlExtraData = ::servo_url::ServoUrl;
|
#[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.
|
/// 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.
|
/// `from_ptr_ref` can work.
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
|
#[repr(C)]
|
||||||
pub struct UrlExtraData(usize);
|
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")]
|
#[cfg(feature = "gecko")]
|
||||||
impl Clone for UrlExtraData {
|
impl Clone for UrlExtraData {
|
||||||
fn clone(&self) -> 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::stylesheet::Namespaces;
|
||||||
use crate::stylesheets::supports_rule::SupportsCondition;
|
use crate::stylesheets::supports_rule::SupportsCondition;
|
||||||
use crate::stylesheets::viewport_rule;
|
use crate::stylesheets::viewport_rule;
|
||||||
|
use crate::stylesheets::{CorsMode, DocumentRule, FontFeatureValuesRule, KeyframesRule, MediaRule};
|
||||||
use crate::stylesheets::{CssRule, CssRuleType, CssRules, RulesMutateError, StylesheetLoader};
|
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::stylesheets::{NamespaceRule, PageRule, StyleRule, SupportsRule, ViewportRule};
|
||||||
use crate::values::computed::font::FamilyName;
|
use crate::values::computed::font::FamilyName;
|
||||||
use crate::values::{CssUrl, CustomIdent, KeyframesName};
|
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_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 = MediaList::parse(&self.context, input);
|
||||||
let media = Arc::new(self.shared_lock.wrap(media));
|
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`.
|
/// An animated value for a single `filter`.
|
||||||
#[cfg(feature = "gecko")]
|
#[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`.
|
/// An animated value for a single `filter`.
|
||||||
#[cfg(not(feature = "gecko"))]
|
#[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>;
|
GenericFilter<Angle, NonNegativeNumber, NonNegativeLength, SimpleShadow, ComputedUrl>;
|
||||||
|
|
||||||
/// A computed value for a single `filter`.
|
/// A computed value for a single `filter`.
|
||||||
#[cfg(not(feature = "gecko"))]
|
#[cfg(feature = "servo")]
|
||||||
pub type Filter =
|
pub type Filter =
|
||||||
GenericFilter<Angle, NonNegativeNumber, NonNegativeLength, Impossible, Impossible>;
|
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};
|
pub use crate::values::specified::list::{QuotePair, Quotes};
|
||||||
|
|
||||||
lazy_static! {
|
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![
|
vec![
|
||||||
QuotePair {
|
QuotePair {
|
||||||
opening: "\u{201c}".to_owned().into(),
|
opening: "\u{201c}".to_owned().into(),
|
||||||
|
|
|
@ -18,13 +18,25 @@ fn is_auto_zero_angle(auto: &bool, angle: &Angle) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A computed offset-rotate.
|
/// 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)]
|
#[repr(C)]
|
||||||
pub struct OffsetRotate {
|
pub struct OffsetRotate {
|
||||||
/// If auto is false, this is a fixed angle which indicates a
|
/// If auto is false, this is a fixed angle which indicates a
|
||||||
/// constant clockwise rotation transformation applied to it by this
|
/// constant clockwise rotation transformation applied to it by this
|
||||||
/// specified rotation angle. Otherwise, the angle will be added to
|
/// specified rotation angle. Otherwise, the angle will be added to
|
||||||
/// the angle of the direction in layout.
|
/// the angle of the direction in layout.
|
||||||
|
#[animation(constant)]
|
||||||
#[css(represents_keyword)]
|
#[css(represents_keyword)]
|
||||||
pub auto: bool,
|
pub auto: bool,
|
||||||
/// The angle value.
|
/// The angle value.
|
||||||
|
|
|
@ -34,8 +34,10 @@ pub struct GenericBoxShadow<Color, SizeLength, BlurShapeLength, ShapeLength> {
|
||||||
pub use self::GenericBoxShadow as BoxShadow;
|
pub use self::GenericBoxShadow as BoxShadow;
|
||||||
|
|
||||||
/// A generic value for a single `filter`.
|
/// A generic value for a single `filter`.
|
||||||
|
///
|
||||||
|
/// cbindgen:derive-tagged-enum-copy-constructor=true
|
||||||
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
|
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
|
||||||
#[animation(no_bound(Url))]
|
#[animation(no_bound(U))]
|
||||||
#[derive(
|
#[derive(
|
||||||
Clone,
|
Clone,
|
||||||
ComputeSquaredDistance,
|
ComputeSquaredDistance,
|
||||||
|
@ -49,7 +51,8 @@ pub use self::GenericBoxShadow as BoxShadow;
|
||||||
ToResolvedValue,
|
ToResolvedValue,
|
||||||
ToShmem,
|
ToShmem,
|
||||||
)]
|
)]
|
||||||
pub enum Filter<Angle, Factor, Length, DropShadow, Url> {
|
#[repr(C, u8)]
|
||||||
|
pub enum GenericFilter<Angle, Factor, Length, Shadow, U> {
|
||||||
/// `blur(<length>)`
|
/// `blur(<length>)`
|
||||||
#[css(function)]
|
#[css(function)]
|
||||||
Blur(Length),
|
Blur(Length),
|
||||||
|
@ -79,12 +82,14 @@ pub enum Filter<Angle, Factor, Length, DropShadow, Url> {
|
||||||
Sepia(Factor),
|
Sepia(Factor),
|
||||||
/// `drop-shadow(...)`
|
/// `drop-shadow(...)`
|
||||||
#[css(function)]
|
#[css(function)]
|
||||||
DropShadow(DropShadow),
|
DropShadow(Shadow),
|
||||||
/// `<url>`
|
/// `<url>`
|
||||||
#[animation(error)]
|
#[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.
|
/// 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
|
/// Contrary to the canonical order from the spec, the color is serialised
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
//! Generic types for url properties.
|
//! Generic types for url properties.
|
||||||
|
|
||||||
/// An image url or none, used for example in list-style-image
|
/// An image url or none, used for example in list-style-image
|
||||||
|
///
|
||||||
|
/// cbindgen:derive-tagged-enum-copy-constructor=true
|
||||||
#[derive(
|
#[derive(
|
||||||
Animate,
|
Animate,
|
||||||
Clone,
|
Clone,
|
||||||
|
@ -21,16 +23,27 @@
|
||||||
ToResolvedValue,
|
ToResolvedValue,
|
||||||
ToShmem,
|
ToShmem,
|
||||||
)]
|
)]
|
||||||
pub enum UrlOrNone<Url> {
|
#[repr(C, u8)]
|
||||||
|
pub enum GenericUrlOrNone<U> {
|
||||||
/// `none`
|
/// `none`
|
||||||
None,
|
None,
|
||||||
/// `A URL`
|
/// A URL.
|
||||||
Url(Url),
|
Url(U),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub use self::GenericUrlOrNone as UrlOrNone;
|
||||||
|
|
||||||
impl<Url> UrlOrNone<Url> {
|
impl<Url> UrlOrNone<Url> {
|
||||||
/// Initial "none" value for properties such as `list-style-image`
|
/// Initial "none" value for properties such as `list-style-image`
|
||||||
pub fn none() -> Self {
|
pub fn none() -> Self {
|
||||||
UrlOrNone::None
|
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")]
|
#[cfg(feature = "gecko")]
|
||||||
use crate::gecko_bindings::structs::nscolor;
|
use crate::gecko_bindings::structs::nscolor;
|
||||||
use crate::parser::{Parse, ParserContext};
|
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::computed::{Color as ComputedColor, Context, ToComputedValue};
|
||||||
use crate::values::generics::color::{Color as GenericColor, ColorOrAuto as GenericColorOrAuto};
|
use crate::values::generics::color::{Color as GenericColor, ColorOrAuto as GenericColorOrAuto};
|
||||||
use crate::values::specified::calc::CalcNode;
|
use crate::values::specified::calc::CalcNode;
|
||||||
|
@ -35,7 +33,6 @@ pub enum Color {
|
||||||
},
|
},
|
||||||
/// A complex color value from computed value
|
/// A complex color value from computed value
|
||||||
Complex(ComputedColor),
|
Complex(ComputedColor),
|
||||||
|
|
||||||
/// A system color
|
/// A system color
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
System(SystemColor),
|
System(SystemColor),
|
||||||
|
@ -47,6 +44,215 @@ pub enum Color {
|
||||||
InheritFromBodyQuirk,
|
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")]
|
#[cfg(feature = "gecko")]
|
||||||
mod gecko {
|
mod gecko {
|
||||||
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, ToCss, ToShmem)]
|
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, ToCss, ToShmem)]
|
||||||
|
@ -153,16 +359,14 @@ impl Parse for Color {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
{
|
{
|
||||||
if let Ok(ident) = input.expect_ident() {
|
if let Ok(system) = input.try(|i| SystemColor::parse(context, i)) {
|
||||||
if let Ok(system) = SystemColor::from_ident(ident) {
|
|
||||||
return Ok(Color::System(system));
|
return Ok(Color::System(system));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(c) = gecko::SpecialColorKeyword::from_ident(ident) {
|
if let Ok(c) = input.try(gecko::SpecialColorKeyword::parse) {
|
||||||
return Ok(Color::Special(c));
|
return Ok(Color::Special(c));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
match e.kind {
|
match e.kind {
|
||||||
ParseErrorKind::Basic(BasicParseErrorKind::UnexpectedToken(t)) => {
|
ParseErrorKind::Basic(BasicParseErrorKind::UnexpectedToken(t)) => {
|
||||||
|
@ -340,18 +544,16 @@ impl Color {
|
||||||
/// If `context` is `None`, and the specified color requires data from
|
/// If `context` is `None`, and the specified color requires data from
|
||||||
/// the context to resolve, then `None` is returned.
|
/// the context to resolve, then `None` is returned.
|
||||||
pub fn to_computed_color(&self, _context: Option<&Context>) -> Option<ComputedColor> {
|
pub fn to_computed_color(&self, _context: Option<&Context>) -> Option<ComputedColor> {
|
||||||
match *self {
|
Some(match *self {
|
||||||
Color::CurrentColor => Some(ComputedColor::currentcolor()),
|
Color::CurrentColor => ComputedColor::currentcolor(),
|
||||||
Color::Numeric { ref parsed, .. } => Some(ComputedColor::rgba(*parsed)),
|
Color::Numeric { ref parsed, .. } => ComputedColor::rgba(*parsed),
|
||||||
Color::Complex(ref complex) => Some(*complex),
|
Color::Complex(ref complex) => *complex,
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
Color::System(system) => _context
|
Color::System(system) => system.compute(_context?),
|
||||||
.map(|context| convert_nscolor_to_computedcolor(system.to_computed_value(context))),
|
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
Color::Special(special) => {
|
Color::Special(special) => {
|
||||||
use self::gecko::SpecialColorKeyword as Keyword;
|
use self::gecko::SpecialColorKeyword as Keyword;
|
||||||
_context.map(|context| {
|
let prefs = _context?.device().pref_sheet_prefs();
|
||||||
let prefs = context.device().pref_sheet_prefs();
|
|
||||||
convert_nscolor_to_computedcolor(match special {
|
convert_nscolor_to_computedcolor(match special {
|
||||||
Keyword::MozDefaultColor => prefs.mDefaultColor,
|
Keyword::MozDefaultColor => prefs.mDefaultColor,
|
||||||
Keyword::MozDefaultBackgroundColor => prefs.mDefaultBackgroundColor,
|
Keyword::MozDefaultBackgroundColor => prefs.mDefaultBackgroundColor,
|
||||||
|
@ -359,13 +561,12 @@ impl Color {
|
||||||
Keyword::MozActivehyperlinktext => prefs.mActiveLinkColor,
|
Keyword::MozActivehyperlinktext => prefs.mActiveLinkColor,
|
||||||
Keyword::MozVisitedhyperlinktext => prefs.mVisitedLinkColor,
|
Keyword::MozVisitedhyperlinktext => prefs.mVisitedLinkColor,
|
||||||
})
|
})
|
||||||
})
|
|
||||||
},
|
},
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
Color::InheritFromBodyQuirk => {
|
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 {
|
fn to_computed_value(&self, context: &Context) -> RGBA {
|
||||||
self.0
|
self.0
|
||||||
.to_computed_value(context)
|
.to_computed_value(context)
|
||||||
.to_rgba(context.builder.get_parent_color().clone_color())
|
.to_rgba(context.builder.get_parent_inherited_text().clone_color())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -18,7 +18,7 @@ use crate::values::specified::length::{Length, NonNegativeLength};
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
use crate::values::specified::url::SpecifiedUrl;
|
use crate::values::specified::url::SpecifiedUrl;
|
||||||
use crate::values::specified::{Angle, Number, NumberOrPercentage};
|
use crate::values::specified::{Angle, Number, NumberOrPercentage};
|
||||||
#[cfg(not(feature = "gecko"))]
|
#[cfg(feature = "servo")]
|
||||||
use crate::values::Impossible;
|
use crate::values::Impossible;
|
||||||
use crate::Zero;
|
use crate::Zero;
|
||||||
use cssparser::{self, BasicParseErrorKind, Parser, Token};
|
use cssparser::{self, BasicParseErrorKind, Parser, Token};
|
||||||
|
@ -30,11 +30,14 @@ pub type BoxShadow =
|
||||||
|
|
||||||
/// A specified value for a single `filter`.
|
/// A specified value for a single `filter`.
|
||||||
#[cfg(feature = "gecko")]
|
#[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`.
|
/// A specified value for a single `filter`.
|
||||||
#[cfg(not(feature = "gecko"))]
|
#[cfg(feature = "servo")]
|
||||||
pub type Filter = GenericFilter<Angle, Factor, NonNegativeLength, Impossible, Impossible>;
|
pub type SpecifiedFilter = GenericFilter<Angle, Factor, NonNegativeLength, Impossible, Impossible>;
|
||||||
|
|
||||||
|
pub use self::SpecifiedFilter as Filter;
|
||||||
|
|
||||||
/// A value for the `<factor>` parts in `Filter`.
|
/// A value for the `<factor>` parts in `Filter`.
|
||||||
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
|
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
|
||||||
|
|
|
@ -11,6 +11,7 @@ use crate::custom_properties::SpecifiedValue;
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
use crate::gecko_bindings::structs;
|
use crate::gecko_bindings::structs;
|
||||||
use crate::parser::{Parse, ParserContext};
|
use crate::parser::{Parse, ParserContext};
|
||||||
|
use crate::stylesheets::CorsMode;
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
use crate::values::computed::{Context, Position as ComputedPosition, ToComputedValue};
|
use crate::values::computed::{Context, Position as ComputedPosition, ToComputedValue};
|
||||||
use crate::values::generics::image::PaintWorklet;
|
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.try(|i| i.expect_function_matching("-moz-image-rect"))?;
|
||||||
input.parse_nested_block(|i| {
|
input.parse_nested_block(|i| {
|
||||||
let string = i.expect_url_or_string()?;
|
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()?;
|
i.expect_comma()?;
|
||||||
let top = NumberOrPercentage::parse_non_negative(context, i)?;
|
let top = NumberOrPercentage::parse_non_negative(context, i)?;
|
||||||
i.expect_comma()?;
|
i.expect_comma()?;
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
//! Common handling for the specified value CSS url() values.
|
//! 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")]
|
#[cfg(feature = "gecko")]
|
||||||
pub use crate::gecko::url::{SpecifiedImageUrl, SpecifiedUrl};
|
pub use crate::gecko::url::{SpecifiedImageUrl, SpecifiedUrl};
|
||||||
|
|
|
@ -40,7 +40,7 @@ impl<T> Deref for ArcSlice<T> {
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
// ThinArc doesn't support alignments greater than align_of::<u64>.
|
// ThinArc doesn't support alignments greater than align_of::<u64>.
|
||||||
static ref EMPTY_ARC_SLICE: ArcSlice<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))
|
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
|
/// Creates a value that can be passed via FFI, and forgets this value
|
||||||
/// altogether.
|
/// altogether.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -11,7 +11,7 @@ use style::error_reporting::{ContextualParseError, ParseErrorReporter};
|
||||||
use style::media_queries::MediaList;
|
use style::media_queries::MediaList;
|
||||||
use style::properties::{longhands, Importance, PropertyDeclaration, PropertyDeclarationBlock};
|
use style::properties::{longhands, Importance, PropertyDeclaration, PropertyDeclarationBlock};
|
||||||
use style::rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource};
|
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::stylesheets::{CssRule, Origin, Stylesheet};
|
||||||
use style::thread_state::{self, ThreadState};
|
use style::thread_state::{self, ThreadState};
|
||||||
use test::{self, Bencher};
|
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> {
|
impl<'a> AutoGCRuleTree<'a> {
|
||||||
fn new(r: &'a RuleTree) -> Self {
|
fn new(r: &'a RuleTree, lock: &'a SharedRwLock) -> Self {
|
||||||
AutoGCRuleTree(r)
|
AutoGCRuleTree(r, lock)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Drop for AutoGCRuleTree<'a> {
|
impl<'a> Drop for AutoGCRuleTree<'a> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
|
const DEBUG: bool = false;
|
||||||
unsafe {
|
unsafe {
|
||||||
self.0.gc();
|
self.0.gc();
|
||||||
|
if DEBUG {
|
||||||
|
let guard = self.1.read();
|
||||||
|
self.0.dump_stdout(&StylesheetGuards::same(&guard));
|
||||||
|
}
|
||||||
assert!(
|
assert!(
|
||||||
::std::thread::panicking() || !self.0.root().has_children_for_testing(),
|
::std::thread::panicking() || !self.0.root().has_children_for_testing(),
|
||||||
"No rule nodes other than the root shall remain!"
|
"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)> {
|
fn parse_rules(lock: &SharedRwLock, css: &str) -> Vec<(StyleSource, CascadeLevel)> {
|
||||||
let lock = SharedRwLock::new();
|
|
||||||
let media = Arc::new(lock.wrap(MediaList::empty()));
|
let media = Arc::new(lock.wrap(MediaList::empty()));
|
||||||
|
|
||||||
let s = Stylesheet::from_str(
|
let s = Stylesheet::from_str(
|
||||||
|
@ -58,7 +62,7 @@ fn parse_rules(css: &str) -> Vec<(StyleSource, CascadeLevel)> {
|
||||||
ServoUrl::parse("http://localhost").unwrap(),
|
ServoUrl::parse("http://localhost").unwrap(),
|
||||||
Origin::Author,
|
Origin::Author,
|
||||||
media,
|
media,
|
||||||
lock,
|
lock.clone(),
|
||||||
None,
|
None,
|
||||||
Some(&ErrorringErrorReporter),
|
Some(&ErrorringErrorReporter),
|
||||||
QuirksMode::NoQuirks,
|
QuirksMode::NoQuirks,
|
||||||
|
@ -105,15 +109,16 @@ fn test_insertion_style_attribute(
|
||||||
fn bench_insertion_basic(b: &mut Bencher) {
|
fn bench_insertion_basic(b: &mut Bencher) {
|
||||||
let r = RuleTree::new();
|
let r = RuleTree::new();
|
||||||
thread_state::initialize(ThreadState::SCRIPT);
|
thread_state::initialize(ThreadState::SCRIPT);
|
||||||
|
let lock = SharedRwLock::new();
|
||||||
let rules_matched = parse_rules(
|
let rules_matched = parse_rules(
|
||||||
|
&lock,
|
||||||
".foo { width: 200px; } \
|
".foo { width: 200px; } \
|
||||||
.bar { height: 500px; } \
|
.bar { height: 500px; } \
|
||||||
.baz { display: block; }",
|
.baz { display: block; }",
|
||||||
);
|
);
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let _gc = AutoGCRuleTree::new(&r);
|
let _gc = AutoGCRuleTree::new(&r, &lock);
|
||||||
|
|
||||||
for _ in 0..(4000 + 400) {
|
for _ in 0..(4000 + 400) {
|
||||||
test::black_box(test_insertion(&r, rules_matched.clone()));
|
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();
|
let r = RuleTree::new();
|
||||||
thread_state::initialize(ThreadState::SCRIPT);
|
thread_state::initialize(ThreadState::SCRIPT);
|
||||||
|
|
||||||
|
let lock = SharedRwLock::new();
|
||||||
let rules_matched = parse_rules(
|
let rules_matched = parse_rules(
|
||||||
|
&lock,
|
||||||
".foo { width: 200px; } \
|
".foo { width: 200px; } \
|
||||||
.bar { height: 500px; } \
|
.bar { height: 500px; } \
|
||||||
.baz { display: block; }",
|
.baz { display: block; }",
|
||||||
);
|
);
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let _gc = AutoGCRuleTree::new(&r);
|
let _gc = AutoGCRuleTree::new(&r, &lock);
|
||||||
|
|
||||||
test::black_box(test_insertion(&r, rules_matched.clone()));
|
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
|
// This test case tests a case where you style a bunch of siblings
|
||||||
// matching the same rules, with a different style attribute each
|
// matching the same rules, with a different style attribute each
|
||||||
// one.
|
// one.
|
||||||
|
let lock = SharedRwLock::new();
|
||||||
let rules_matched = parse_rules(
|
let rules_matched = parse_rules(
|
||||||
|
&lock,
|
||||||
".foo { width: 200px; } \
|
".foo { width: 200px; } \
|
||||||
.bar { height: 500px; } \
|
.bar { height: 500px; } \
|
||||||
.baz { display: block; }",
|
.baz { display: block; }",
|
||||||
);
|
);
|
||||||
|
|
||||||
let shared_lock = SharedRwLock::new();
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let _gc = AutoGCRuleTree::new(&r);
|
let _gc = AutoGCRuleTree::new(&r, &lock);
|
||||||
|
|
||||||
for _ in 0..(4000 + 400) {
|
for _ in 0..(4000 + 400) {
|
||||||
test::black_box(test_insertion_style_attribute(
|
test::black_box(test_insertion_style_attribute(&r, &rules_matched, &lock));
|
||||||
&r,
|
|
||||||
&rules_matched,
|
|
||||||
&shared_lock,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -172,14 +176,16 @@ fn bench_insertion_basic_parallel(b: &mut Bencher) {
|
||||||
let r = RuleTree::new();
|
let r = RuleTree::new();
|
||||||
thread_state::initialize(ThreadState::SCRIPT);
|
thread_state::initialize(ThreadState::SCRIPT);
|
||||||
|
|
||||||
|
let lock = SharedRwLock::new();
|
||||||
let rules_matched = parse_rules(
|
let rules_matched = parse_rules(
|
||||||
|
&lock,
|
||||||
".foo { width: 200px; } \
|
".foo { width: 200px; } \
|
||||||
.bar { height: 500px; } \
|
.bar { height: 500px; } \
|
||||||
.baz { display: block; }",
|
.baz { display: block; }",
|
||||||
);
|
);
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let _gc = AutoGCRuleTree::new(&r);
|
let _gc = AutoGCRuleTree::new(&r, &lock);
|
||||||
|
|
||||||
rayon::scope(|s| {
|
rayon::scope(|s| {
|
||||||
for _ in 0..4 {
|
for _ in 0..4 {
|
||||||
|
@ -203,32 +209,29 @@ fn bench_expensive_insertion_parallel(b: &mut Bencher) {
|
||||||
let r = RuleTree::new();
|
let r = RuleTree::new();
|
||||||
thread_state::initialize(ThreadState::SCRIPT);
|
thread_state::initialize(ThreadState::SCRIPT);
|
||||||
|
|
||||||
|
let lock = SharedRwLock::new();
|
||||||
let rules_matched = parse_rules(
|
let rules_matched = parse_rules(
|
||||||
|
&lock,
|
||||||
".foo { width: 200px; } \
|
".foo { width: 200px; } \
|
||||||
.bar { height: 500px; } \
|
.bar { height: 500px; } \
|
||||||
.baz { display: block; }",
|
.baz { display: block; }",
|
||||||
);
|
);
|
||||||
|
|
||||||
let shared_lock = SharedRwLock::new();
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let _gc = AutoGCRuleTree::new(&r);
|
let _gc = AutoGCRuleTree::new(&r, &lock);
|
||||||
|
|
||||||
rayon::scope(|s| {
|
rayon::scope(|s| {
|
||||||
for _ in 0..4 {
|
for _ in 0..4 {
|
||||||
s.spawn(|s| {
|
s.spawn(|s| {
|
||||||
for _ in 0..1000 {
|
for _ in 0..1000 {
|
||||||
test::black_box(test_insertion_style_attribute(
|
test::black_box(test_insertion_style_attribute(&r, &rules_matched, &lock));
|
||||||
&r,
|
|
||||||
&rules_matched,
|
|
||||||
&shared_lock,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
s.spawn(|_| {
|
s.spawn(|_| {
|
||||||
for _ in 0..100 {
|
for _ in 0..100 {
|
||||||
test::black_box(test_insertion_style_attribute(
|
test::black_box(test_insertion_style_attribute(
|
||||||
&r,
|
&r,
|
||||||
&rules_matched,
|
&rules_matched,
|
||||||
&shared_lock,
|
&lock,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue