diff --git a/Cargo.lock b/Cargo.lock index ea625f81909..8164783500d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -942,6 +942,17 @@ dependencies = [ "deny_public_fields 0.0.1", ] +[[package]] +name = "derive_common" +version = "0.0.1" +dependencies = [ + "darling 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "derive_more" version = "0.13.0" @@ -3646,6 +3657,8 @@ dependencies = [ "servo_arc 0.1.1", "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "thin-slice 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "to_shmem 0.0.1", + "to_shmem_derive 0.0.1", ] [[package]] @@ -3992,6 +4005,8 @@ dependencies = [ "malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", "servo_rand 0.0.1", + "to_shmem 0.0.1", + "to_shmem_derive 0.0.1", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4240,6 +4255,8 @@ dependencies = [ "style_traits 0.0.1", "thin-slice 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "to_shmem 0.0.1", + "to_shmem_derive 0.0.1", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "uluru 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-bidi 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4253,6 +4270,7 @@ name = "style_derive" version = "0.0.1" dependencies = [ "darling 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "derive_common 0.0.1", "proc-macro2 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4297,6 +4315,8 @@ dependencies = [ "servo_arc 0.1.1", "servo_atoms 0.0.1", "servo_url 0.0.1", + "to_shmem 0.0.1", + "to_shmem_derive 0.0.1", "webrender_api 0.60.0 (git+https://github.com/servo/webrender)", ] @@ -4435,6 +4455,31 @@ dependencies = [ "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "to_shmem" +version = "0.0.1" +dependencies = [ + "cssparser 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", + "servo_arc 0.1.1", + "smallbitvec 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "thin-slice 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "to_shmem_derive" +version = "0.0.1" +dependencies = [ + "darling 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "derive_common 0.0.1", + "proc-macro2 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "tokio" version = "0.1.8" diff --git a/components/derive_common/Cargo.toml b/components/derive_common/Cargo.toml new file mode 100644 index 00000000000..2a4fac64405 --- /dev/null +++ b/components/derive_common/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "derive_common" +version = "0.0.1" +authors = ["The Servo Project Developers"] +license = "MPL-2.0" +publish = false + +[lib] +path = "lib.rs" + +[dependencies] +darling = "0.8" +proc-macro2 = "0.4" +quote = "0.6" +syn = { version = "0.15", features = ["visit"] } +synstructure = "0.10" diff --git a/components/style_derive/cg.rs b/components/derive_common/cg.rs similarity index 99% rename from components/style_derive/cg.rs rename to components/derive_common/cg.rs index a5f15a0358e..7a8fbc24403 100644 --- a/components/style_derive/cg.rs +++ b/components/derive_common/cg.rs @@ -32,8 +32,8 @@ use synstructure::{self, BindStyle, BindingInfo, VariantAst, VariantInfo}; pub fn propagate_clauses_to_output_type( where_clause: &mut Option, generics: &syn::Generics, - trait_path: Path, - trait_output: Ident, + trait_path: &Path, + trait_output: &Ident, ) { let where_clause = match *where_clause { Some(ref mut clause) => clause, @@ -104,7 +104,7 @@ where }) } -pub fn fmap_trait_output(input: &DeriveInput, trait_path: &Path, trait_output: Ident) -> Path { +pub fn fmap_trait_output(input: &DeriveInput, trait_path: &Path, trait_output: &Ident) -> Path { let segment = PathSegment { ident: input.ident.clone(), arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments { diff --git a/components/derive_common/lib.rs b/components/derive_common/lib.rs new file mode 100644 index 00000000000..14415351449 --- /dev/null +++ b/components/derive_common/lib.rs @@ -0,0 +1,13 @@ +/* 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/. */ + +extern crate darling; +extern crate proc_macro2; +#[macro_use] +extern crate quote; +#[macro_use] +extern crate syn; +extern crate synstructure; + +pub mod cg; diff --git a/components/gfx/font.rs b/components/gfx/font.rs index cd9513a3f43..35ce19621ac 100644 --- a/components/gfx/font.rs +++ b/components/gfx/font.rs @@ -26,7 +26,7 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; use style::computed_values::{font_stretch, font_style, font_variant_caps, font_weight}; use style::properties::style_structs::Font as FontStyleStruct; -use style::values::computed::font::SingleFontFamily; +use style::values::computed::font::{GenericFontFamily, SingleFontFamily}; use unicode_script::Script; macro_rules! ot_tag { @@ -564,9 +564,14 @@ impl<'a> From<&'a SingleFontFamily> for FontFamilyName { FontFamilyName::Specific(family_name.name.clone()) }, - SingleFontFamily::Generic(ref generic_name) => { - FontFamilyName::Generic(generic_name.clone()) - }, + SingleFontFamily::Generic(generic) => FontFamilyName::Generic(match generic { + GenericFontFamily::None => panic!("Shouldn't appear in style"), + GenericFontFamily::Serif => atom!("serif"), + GenericFontFamily::SansSerif => atom!("sans-serif"), + GenericFontFamily::Monospace => atom!("monospace"), + GenericFontFamily::Cursive => atom!("cursive"), + GenericFontFamily::Fantasy => atom!("fantasy"), + }), } } } diff --git a/components/gfx/tests/font_context.rs b/components/gfx/tests/font_context.rs index 3a3f73671ac..4752a5fb3b3 100644 --- a/components/gfx/tests/font_context.rs +++ b/components/gfx/tests/font_context.rs @@ -20,7 +20,7 @@ use std::rc::Rc; use style::properties::longhands::font_variant_caps::computed_value::T as FontVariantCaps; use style::properties::style_structs::Font as FontStyleStruct; use style::values::computed::font::{ - FamilyName, FamilyNameSyntax, FontFamily, FontFamilyList, FontSize, + FamilyName, FontFamily, FontFamilyList, FontFamilyNameSyntax, FontSize, }; use style::values::computed::font::{FontStretch, FontWeight, SingleFontFamily}; use style::values::generics::font::FontStyle; @@ -114,7 +114,7 @@ fn font_family(names: Vec<&str>) -> FontFamily { .map(|name| { SingleFontFamily::FamilyName(FamilyName { name: Atom::from(name), - syntax: FamilyNameSyntax::Quoted, + syntax: FontFamilyNameSyntax::Quoted, }) }) .collect(); diff --git a/components/layout/multicol.rs b/components/layout/multicol.rs index f8ddfa8200c..46ccbc64653 100644 --- a/components/layout/multicol.rs +++ b/components/layout/multicol.rs @@ -19,9 +19,10 @@ use std::fmt; use std::sync::Arc; use style::logical_geometry::LogicalSize; use style::properties::ComputedValues; -use style::values::computed::length::{MaxSize, NonNegativeLengthOrAuto, Size}; +use style::values::computed::length::{ + MaxSize, NonNegativeLengthOrAuto, NonNegativeLengthPercentageOrNormal, Size, +}; use style::values::generics::column::ColumnCount; -use style::values::Either; #[allow(unsafe_code)] unsafe impl crate::flow::HasBaseFlow for MulticolFlow {} @@ -106,8 +107,10 @@ impl Flow for MulticolFlow { { let style = &self.block_flow.fragment.style; let column_gap = match style.get_position().column_gap { - Either::First(len) => len.0.to_pixel_length(content_inline_size).into(), - Either::Second(_normal) => { + NonNegativeLengthPercentageOrNormal::LengthPercentage(len) => { + len.0.to_pixel_length(content_inline_size).into() + }, + NonNegativeLengthPercentageOrNormal::Normal => { self.block_flow.fragment.style.get_font().font_size.size() }, }; diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index eb48c22865b..6da5d92fdb1 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -643,6 +643,7 @@ impl LayoutElementHelpers for LayoutDom { }; if let Some(font_family) = font_family { + // FIXME(emilio): This in Gecko parses a whole family list. hints.push(from_declaration( shared_lock, PropertyDeclaration::FontFamily(font_family::SpecifiedValue::Values( diff --git a/components/selectors/Cargo.toml b/components/selectors/Cargo.toml index bb8e5d7f81b..ed34c9084d2 100644 --- a/components/selectors/Cargo.toml +++ b/components/selectors/Cargo.toml @@ -31,6 +31,8 @@ precomputed-hash = "0.1" servo_arc = { version = "0.1", path = "../servo_arc" } smallvec = "0.6" thin-slice = "0.1.0" +to_shmem = { path = "../to_shmem" } +to_shmem_derive = { path = "../to_shmem_derive" } [build-dependencies] phf_codegen = "0.7.18" diff --git a/components/selectors/attr.rs b/components/selectors/attr.rs index 36d31e11345..96abbe1c132 100644 --- a/components/selectors/attr.rs +++ b/components/selectors/attr.rs @@ -6,11 +6,15 @@ use crate::parser::SelectorImpl; use cssparser::ToCss; use std::fmt; -#[derive(Clone, Eq, PartialEq)] +#[derive(Clone, Eq, PartialEq, ToShmem)] +#[shmem(no_bounds)] pub struct AttrSelectorWithOptionalNamespace { + #[shmem(field_bound)] pub namespace: Option>, + #[shmem(field_bound)] pub local_name: Impl::LocalName, pub local_name_lower: Impl::LocalName, + #[shmem(field_bound)] pub operation: ParsedAttrSelectorOperation, pub never_matches: bool, } @@ -24,7 +28,7 @@ impl AttrSelectorWithOptionalNamespace { } } -#[derive(Clone, Eq, PartialEq)] +#[derive(Clone, Eq, PartialEq, ToShmem)] pub enum NamespaceConstraint { Any, @@ -32,7 +36,7 @@ pub enum NamespaceConstraint { Specific(NamespaceUrl), } -#[derive(Clone, Eq, PartialEq)] +#[derive(Clone, Eq, PartialEq, ToShmem)] pub enum ParsedAttrSelectorOperation { Exists, WithValue { @@ -72,7 +76,7 @@ impl AttrSelectorOperation { } } -#[derive(Clone, Copy, Eq, PartialEq)] +#[derive(Clone, Copy, Eq, PartialEq, ToShmem)] pub enum AttrSelectorOperator { Equal, Includes, @@ -132,7 +136,7 @@ impl AttrSelectorOperator { /// The definition of whitespace per CSS Selectors Level 3 ยง 4. pub static SELECTOR_WHITESPACE: &'static [char] = &[' ', '\t', '\n', '\r', '\x0C']; -#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, ToShmem)] pub enum ParsedCaseSensitivity { // 's' was specified. ExplicitCaseSensitive, diff --git a/components/selectors/builder.rs b/components/selectors/builder.rs index 80e8457cfc8..72404de1084 100644 --- a/components/selectors/builder.rs +++ b/components/selectors/builder.rs @@ -199,7 +199,7 @@ pub const HAS_SLOTTED_BIT: u32 = 1 << 31; /// We use ten bits for each specificity kind (id, class, element), and the two /// high bits for the pseudo and slotted flags. -#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, ToShmem)] pub struct SpecificityAndFlags(pub u32); impl SpecificityAndFlags { diff --git a/components/selectors/lib.rs b/components/selectors/lib.rs index 1d9bf58edb3..e8d8062dff7 100644 --- a/components/selectors/lib.rs +++ b/components/selectors/lib.rs @@ -21,6 +21,9 @@ extern crate precomputed_hash; extern crate servo_arc; extern crate smallvec; extern crate thin_slice; +extern crate to_shmem; +#[macro_use] +extern crate to_shmem_derive; pub mod attr; pub mod bloom; diff --git a/components/selectors/parser.rs b/components/selectors/parser.rs index 488628cd712..0515eaca193 100644 --- a/components/selectors/parser.rs +++ b/components/selectors/parser.rs @@ -221,8 +221,11 @@ pub trait Parser<'i> { } } -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct SelectorList(pub SmallVec<[Selector; 1]>); +#[derive(Clone, Debug, Eq, PartialEq, ToShmem)] +#[shmem(no_bounds)] +pub struct SelectorList( + #[shmem(field_bound)] pub SmallVec<[Selector; 1]>, +); impl SelectorList { /// Parse a comma-separated list of Selectors. @@ -507,8 +510,11 @@ pub fn namespace_empty_string() -> Impl::NamespaceUrl { /// /// This reordering doesn't change the semantics of selector matching, and we /// handle it in to_css to make it invisible to serialization. -#[derive(Clone, Eq, PartialEq)] -pub struct Selector(ThinArc>); +#[derive(Clone, Eq, PartialEq, ToShmem)] +#[shmem(no_bounds)] +pub struct Selector( + #[shmem(field_bound)] ThinArc>, +); impl Selector { #[inline] @@ -776,7 +782,7 @@ impl<'a, Impl: SelectorImpl> Iterator for AncestorIter<'a, Impl> { } } -#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, ToShmem)] pub enum Combinator { Child, // > Descendant, // space @@ -824,22 +830,27 @@ impl Combinator { /// optimal packing and cache performance, see [1]. /// /// [1] https://bugzilla.mozilla.org/show_bug.cgi?id=1357973 -#[derive(Clone, Eq, PartialEq)] +#[derive(Clone, Eq, PartialEq, ToShmem)] +#[shmem(no_bounds)] pub enum Component { Combinator(Combinator), ExplicitAnyNamespace, ExplicitNoNamespace, - DefaultNamespace(Impl::NamespaceUrl), - Namespace(Impl::NamespacePrefix, Impl::NamespaceUrl), + DefaultNamespace(#[shmem(field_bound)] Impl::NamespaceUrl), + Namespace( + #[shmem(field_bound)] Impl::NamespacePrefix, + #[shmem(field_bound)] Impl::NamespaceUrl, + ), ExplicitUniversalType, LocalName(LocalName), - ID(Impl::Identifier), - Class(Impl::ClassName), + ID(#[shmem(field_bound)] Impl::Identifier), + Class(#[shmem(field_bound)] Impl::ClassName), AttributeInNoNamespaceExists { + #[shmem(field_bound)] local_name: Impl::LocalName, local_name_lower: Impl::LocalName, }, @@ -847,6 +858,7 @@ pub enum Component { AttributeInNoNamespace { local_name: Impl::LocalName, operator: AttrSelectorOperator, + #[shmem(field_bound)] value: Impl::AttrValue, case_sensitivity: ParsedCaseSensitivity, never_matches: bool, @@ -878,7 +890,7 @@ pub enum Component { FirstOfType, LastOfType, OnlyOfType, - NonTSPseudoClass(Impl::NonTSPseudoClass), + NonTSPseudoClass(#[shmem(field_bound)] Impl::NonTSPseudoClass), /// The ::slotted() pseudo-element (which isn't actually a pseudo-element, /// and probably should be a pseudo-class): /// @@ -902,7 +914,7 @@ pub enum Component { /// /// See https://github.com/w3c/csswg-drafts/issues/2158 Host(Option>), - PseudoElement(Impl::PseudoElement), + PseudoElement(#[shmem(field_bound)] Impl::PseudoElement), } impl Component { @@ -957,8 +969,10 @@ impl Component { } } -#[derive(Clone, Eq, PartialEq)] +#[derive(Clone, Eq, PartialEq, ToShmem)] +#[shmem(no_bounds)] pub struct LocalName { + #[shmem(field_bound)] pub name: Impl::LocalName, pub lower_name: Impl::LocalName, } diff --git a/components/servo_arc/lib.rs b/components/servo_arc/lib.rs index a18c63a1e5a..f4a929e23f8 100644 --- a/components/servo_arc/lib.rs +++ b/components/servo_arc/lib.rs @@ -16,6 +16,8 @@ //! * We can add methods to support our custom use cases [1]. //! * We have support for dynamically-sized types (see from_header_and_iter). //! * We have support for thin arcs to unsized types (see ThinArc). +//! * We have support for references to static data, which don't do any +//! refcounting. //! //! [1]: https://bugzilla.mozilla.org/show_bug.cgi?id=1360883 @@ -32,6 +34,7 @@ use nodrop::NoDrop; #[cfg(feature = "servo")] use serde::{Deserialize, Serialize}; use stable_deref_trait::{CloneStableDeref, StableDeref}; +use std::alloc::Layout; use std::borrow; use std::cmp::Ordering; use std::convert::From; @@ -74,6 +77,10 @@ macro_rules! offset_of { /// necessarily) at _exactly_ `MAX_REFCOUNT + 1` references. const MAX_REFCOUNT: usize = (isize::MAX) as usize; +/// Special refcount value that means the data is not reference counted, +/// and that the `Arc` is really acting as a read-only static reference. +const STATIC_REFCOUNT: usize = usize::MAX; + /// An atomically reference counted shared pointer /// /// See the documentation for [`Arc`] in the standard library. Unlike the @@ -194,6 +201,32 @@ impl Arc { } } + /// Create a new static Arc (one that won't reference count the object) + /// and place it in the allocation provided by the specified `alloc` + /// function. + /// + /// `alloc` must return a pointer into a static allocation suitable for + /// storing data with the `Layout` passed into it. The pointer returned by + /// `alloc` will not be freed. + #[inline] + pub unsafe fn new_static(alloc: F, data: T) -> Arc + where + F: FnOnce(Layout) -> *mut u8, + { + let ptr = alloc(Layout::new::>()) as *mut ArcInner; + + let x = ArcInner { + count: atomic::AtomicUsize::new(STATIC_REFCOUNT), + data, + }; + + ptr::write(ptr, x); + + Arc { + p: ptr::NonNull::new_unchecked(ptr), + } + } + /// Produce a pointer to the data that can be converted back /// to an Arc. This is basically an `&Arc`, without the extra indirection. /// It has the benefits of an `&T` but also knows about the underlying refcount @@ -225,8 +258,14 @@ impl Arc { /// Returns the address on the heap of the Arc itself -- not the T within it -- for memory /// reporting. + /// + /// If this is a static reference, this returns null. pub fn heap_ptr(&self) -> *const c_void { - self.p.as_ptr() as *const ArcInner as *const c_void + if self.inner().count.load(Relaxed) == STATIC_REFCOUNT { + ptr::null() + } else { + self.p.as_ptr() as *const ArcInner as *const c_void + } } } @@ -262,30 +301,34 @@ impl Arc { impl Clone for Arc { #[inline] fn clone(&self) -> Self { - // Using a relaxed ordering is alright here, as knowledge of the - // original reference prevents other threads from erroneously deleting - // the object. - // - // As explained in the [Boost documentation][1], Increasing the - // reference counter can always be done with memory_order_relaxed: New - // references to an object can only be formed from an existing - // reference, and passing an existing reference from one thread to - // another must already provide any required synchronization. - // - // [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html) - let old_size = self.inner().count.fetch_add(1, Relaxed); + // Using a relaxed ordering to check for STATIC_REFCOUNT is safe, since + // `count` never changes between STATIC_REFCOUNT and other values. + if self.inner().count.load(Relaxed) != STATIC_REFCOUNT { + // Using a relaxed ordering is alright here, as knowledge of the + // original reference prevents other threads from erroneously deleting + // the object. + // + // As explained in the [Boost documentation][1], Increasing the + // reference counter can always be done with memory_order_relaxed: New + // references to an object can only be formed from an existing + // reference, and passing an existing reference from one thread to + // another must already provide any required synchronization. + // + // [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html) + let old_size = self.inner().count.fetch_add(1, Relaxed); - // However we need to guard against massive refcounts in case someone - // is `mem::forget`ing Arcs. If we don't do this the count can overflow - // and users will use-after free. We racily saturate to `isize::MAX` on - // the assumption that there aren't ~2 billion threads incrementing - // the reference count at once. This branch will never be taken in - // any realistic program. - // - // We abort because such a program is incredibly degenerate, and we - // don't care to support it. - if old_size > MAX_REFCOUNT { - process::abort(); + // However we need to guard against massive refcounts in case someone + // is `mem::forget`ing Arcs. If we don't do this the count can overflow + // and users will use-after free. We racily saturate to `isize::MAX` on + // the assumption that there aren't ~2 billion threads incrementing + // the reference count at once. This branch will never be taken in + // any realistic program. + // + // We abort because such a program is incredibly degenerate, and we + // don't care to support it. + if old_size > MAX_REFCOUNT { + process::abort(); + } } unsafe { @@ -351,7 +394,8 @@ impl Arc { } } - /// Whether or not the `Arc` is uniquely owned (is the refcount 1?) + /// Whether or not the `Arc` is uniquely owned (is the refcount 1?) and not + /// a static reference. #[inline] pub fn is_unique(&self) -> bool { // See the extensive discussion in [1] for why this needs to be Acquire. @@ -364,6 +408,12 @@ impl Arc { impl Drop for Arc { #[inline] fn drop(&mut self) { + // Using a relaxed ordering to check for STATIC_REFCOUNT is safe, since + // `count` never changes between STATIC_REFCOUNT and other values. + if self.inner().count.load(Relaxed) == STATIC_REFCOUNT { + return; + } + // Because `fetch_sub` is already atomic, we do not need to synchronize // with other threads unless we are going to delete the object. if self.inner().count.fetch_sub(1, Release) != 1 { @@ -528,10 +578,20 @@ fn divide_rounding_up(dividend: usize, divisor: usize) -> usize { impl Arc> { /// Creates an Arc for a HeaderSlice using the given header struct and - /// iterator to generate the slice. The resulting Arc will be fat. + /// iterator to generate the slice. + /// + /// `is_static` indicates whether to create a static Arc. + /// + /// `alloc` is used to get a pointer to the memory into which the + /// dynamically sized ArcInner> value will be + /// written. If `is_static` is true, then `alloc` must return a + /// pointer into some static memory allocation. If it is false, + /// then `alloc` must return an allocation that can be dellocated + /// by calling Box::from_raw::>> on it. #[inline] - pub fn from_header_and_iter(header: H, mut items: I) -> Self + fn from_header_and_iter_alloc(alloc: F, header: H, mut items: I, is_static: bool) -> Self where + F: FnOnce(Layout) -> *mut u8, I: Iterator + ExactSizeIterator, { use std::mem::size_of; @@ -565,22 +625,20 @@ impl Arc> { let ptr: *mut ArcInner>; unsafe { - // Allocate the buffer. We use Vec because the underlying allocation - // machinery isn't available in stable Rust. - // - // To avoid alignment issues, we allocate words rather than bytes, - // rounding up to the nearest word size. - let buffer = if mem::align_of::() <= mem::align_of::() { - Self::allocate_buffer::(size) + // Allocate the buffer. + let layout = if mem::align_of::() <= mem::align_of::() { + Layout::from_size_align_unchecked(size, mem::align_of::()) } else if mem::align_of::() <= mem::align_of::() { // On 32-bit platforms may have 8 byte alignment while usize has 4 byte aligment. // Use u64 to avoid over-alignment. // This branch will compile away in optimized builds. - Self::allocate_buffer::(size) + Layout::from_size_align_unchecked(size, mem::align_of::()) } else { panic!("Over-aligned type not handled"); }; + let buffer = alloc(layout); + // Synthesize the fat pointer. We do this by claiming we have a direct // pointer to a [T], and then changing the type of the borrow. The key // point here is that the length portion of the fat pointer applies @@ -594,7 +652,12 @@ impl Arc> { // // Note that any panics here (i.e. from the iterator) are safe, since // we'll just leak the uninitialized memory. - ptr::write(&mut ((*ptr).count), atomic::AtomicUsize::new(1)); + let count = if is_static { + atomic::AtomicUsize::new(STATIC_REFCOUNT) + } else { + atomic::AtomicUsize::new(1) + }; + ptr::write(&mut ((*ptr).count), count); ptr::write(&mut ((*ptr).data.header), header); let mut current: *mut T = &mut (*ptr).data.slice[0]; for _ in 0..num_items { @@ -628,8 +691,37 @@ impl Arc> { } } + /// Creates an Arc for a HeaderSlice using the given header struct and + /// iterator to generate the slice. The resulting Arc will be fat. + #[inline] + pub fn from_header_and_iter(header: H, items: I) -> Self + where + I: Iterator + ExactSizeIterator, + { + Arc::from_header_and_iter_alloc( + |layout| { + // align will only ever be align_of::() or align_of::() + let align = layout.align(); + unsafe { + if align == mem::align_of::() { + Self::allocate_buffer::(layout.size()) + } else { + assert_eq!(align, mem::align_of::()); + Self::allocate_buffer::(layout.size()) + } + } + }, + header, + items, + /* is_static = */ false, + ) + } + #[inline] unsafe fn allocate_buffer(size: usize) -> *mut u8 { + // We use Vec because the underlying allocation machinery isn't + // available in stable Rust. To avoid alignment issues, we allocate + // words rather than bytes, rounding up to the nearest word size. let words_to_allocate = divide_rounding_up(size, mem::size_of::()); let mut vec = Vec::::with_capacity(words_to_allocate); vec.set_len(words_to_allocate); @@ -730,11 +822,37 @@ impl ThinArc { Arc::into_thin(Arc::from_header_and_iter(header, items)) } + /// Create a static `ThinArc` for a HeaderSlice using the given header + /// struct and iterator to generate the slice, placing it in the allocation + /// provided by the specified `alloc` function. + /// + /// `alloc` must return a pointer into a static allocation suitable for + /// storing data with the `Layout` passed into it. The pointer returned by + /// `alloc` will not be freed. + pub unsafe fn static_from_header_and_iter(alloc: F, header: H, items: I) -> Self + where + F: FnOnce(Layout) -> *mut u8, + I: Iterator + ExactSizeIterator, + { + let header = HeaderWithLength::new(header, items.len()); + Arc::into_thin(Arc::from_header_and_iter_alloc( + alloc, header, items, /* is_static = */ true, + )) + } + /// Returns the address on the heap of the ThinArc itself -- not the T /// within it -- for memory reporting. + /// + /// If this is a static ThinArc, this returns null. #[inline] pub fn heap_ptr(&self) -> *const c_void { - self.ptr as *const ArcInner as *const c_void + let is_static = + ThinArc::with_arc(self, |a| a.inner().count.load(Relaxed) == STATIC_REFCOUNT); + if is_static { + ptr::null() + } else { + self.ptr as *const ArcInner as *const c_void + } } } diff --git a/components/style/Cargo.toml b/components/style/Cargo.toml index 86aaa8079a4..0bc745015fd 100644 --- a/components/style/Cargo.toml +++ b/components/style/Cargo.toml @@ -20,7 +20,7 @@ gecko = ["style_traits/gecko", "fallible/known_system_malloc"] use_bindgen = ["bindgen", "regex", "toml"] servo = ["serde", "style_traits/servo", "servo_atoms", "servo_config", "html5ever", "cssparser/serde", "encoding_rs", "malloc_size_of/servo", "arrayvec/use_union", - "servo_url", "string_cache", "crossbeam-channel"] + "servo_url", "string_cache", "crossbeam-channel", "to_shmem/servo", "servo_arc/servo"] gecko_debug = [] [dependencies] @@ -68,6 +68,8 @@ style_derive = {path = "../style_derive"} style_traits = {path = "../style_traits"} servo_url = {path = "../url", optional = true} thin-slice = "0.1.0" +to_shmem = {path = "../to_shmem"} +to_shmem_derive = {path = "../to_shmem_derive"} time = "0.1" uluru = "0.3" unicode-bidi = "0.3" diff --git a/components/style/build_gecko.rs b/components/style/build_gecko.rs index 4866909899c..e51ba6bfa3f 100644 --- a/components/style/build_gecko.rs +++ b/components/style/build_gecko.rs @@ -339,8 +339,6 @@ mod bindings { } fn setup_logging() -> bool { - use log; - struct BuildLogger { file: Option>, filter: String, diff --git a/components/style/cbindgen.toml b/components/style/cbindgen.toml deleted file mode 100644 index cd910f0be9b..00000000000 --- a/components/style/cbindgen.toml +++ /dev/null @@ -1,239 +0,0 @@ -header = """/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. */""" -autogen_warning = """/* DO NOT MODIFY THIS MANUALLY! This file was generated using cbindgen. - * To generate this file: - * 1. Get the latest cbindgen using `cargo install --force cbindgen` - * a. Alternatively, you can clone `https://github.com/eqrion/cbindgen` and use a tagged release - * 2. Run `rustup run nightly cbindgen toolkit/library/rust/ --lockfile Cargo.lock --crate style -o layout/style/ServoStyleConsts.h` - */ -#include "nsCoord.h" -#include "Units.h" -#include "mozilla/gfx/Types.h" -class nsAtom; -namespace mozilla { - class WritingMode; - enum HalfCorner : uint8_t; - enum LogicalSide : uint8_t; - namespace css { - struct URLValue; - } - - // Work-around weird cbindgen renaming. - typedef css::URLValue StyleURLValue; - typedef nsAtom StylensAtom; -} -""" -include_guard = "mozilla_ServoStyleConsts_h" -include_version = true -braces = "SameLine" -line_length = 80 -tab_width = 2 -language = "C++" -namespaces = ["mozilla"] - -[parse] -parse_deps = true -include = ["cssparser", "style_traits"] - -[struct] -derive_eq = true -derive_neq = true - -[macro_expansion] -bitflags = true - -[enum] -derive_helper_methods = true -derive_const_casts = true -cast_assert_name = "MOZ_ASSERT" - -[export] -prefix = "Style" -include = [ - "Appearance", - "BreakBetween", - "BreakWithin", - "BorderStyle", - "OutlineStyle", - "ComputedFontStretchRange", - "ComputedFontStyleDescriptor", - "ComputedFontWeightRange", - "ComputedTimingFunction", - "CursorKind", - "Display", - "DisplayMode", - "PrefersColorScheme", - "ExtremumLength", - "FillRule", - "FontDisplay", - "FontFaceSourceListComponent", - "FontLanguageOverride", - "OverflowWrap", - "TimingFunction", - "PathCommand", - "UnicodeRange", - "UserSelect", - "Float", - "OverscrollBehavior", - "ScrollSnapAlign", - "ScrollSnapType", - "OverflowAnchor", - "OverflowClipBox", - "Resize", - "Overflow", - "LengthPercentage", - "LetterSpacing", - "NonNegativeLengthPercentage", - "LengthPercentageOrAuto", - "LineHeight", - "NonNegativeLengthPercentageOrAuto", - "Rect", - "IntersectionObserverRootMargin", - "Size", - "MaxSize", - "FlexBasis", - "Position", - "BackgroundSize", - "BorderImageSlice", - "BorderSpacing", - "BorderRadius", - "NonNegativeLengthOrNumberRect", - "Perspective", - "ZIndex", - "TransformOrigin", - "WordBreak", - "Contain", - "RestyleHint", - "TouchAction", - "WillChangeBits", - "TextDecorationLine", - "MozListReversed", - "Owned", - "OwnedOrNull", - "Strong", -] -item_types = ["enums", "structs", "typedefs"] - -[export.body] -"CSSPixelLength" = """ - inline nscoord ToAppUnits() const; - inline bool IsZero() const; -""" - -"LengthPercentage" = """ - // Defined in nsStyleCoord.h - static constexpr inline StyleLengthPercentage Zero(); - static inline StyleLengthPercentage FromAppUnits(nscoord); - static inline StyleLengthPercentage FromPixels(CSSCoord); - static inline StyleLengthPercentage FromPercentage(float); - inline CSSCoord LengthInCSSPixels() const; - inline float Percentage() const; - inline bool HasPercent() const; - inline bool ConvertsToLength() const; - inline nscoord ToLength() const; - inline bool ConvertsToPercentage() const; - inline bool HasLengthAndPercentage() const; - inline float ToPercentage() const; - inline bool IsDefinitelyZero() const; - inline CSSCoord ResolveToCSSPixels(CSSCoord aPercentageBasisInCSSPixels) const; - template inline CSSCoord ResolveToCSSPixelsWith(T aPercentageGetter) const; - template - inline nscoord Resolve(T aPercentageGetter, U aPercentRoundingFunction) const; - template - inline nscoord Resolve(nscoord aPercentageBasis, T aPercentRoundingFunction) const; - template inline nscoord Resolve(T aPercentageGetter) const; - inline nscoord Resolve(nscoord aPercentageBasis) const; -""" - -"GenericLengthPercentageOrAuto" = """ - inline bool ConvertsToLength() const; - inline nscoord ToLength() const; - inline bool ConvertsToPercentage() const; - inline float ToPercentage() const; - inline bool HasPercent() const; - inline bool HasLengthAndPercentage() const; -""" - -"GenericSize" = """ - inline bool ConvertsToLength() const; - inline nscoord ToLength() const; - inline bool ConvertsToPercentage() const; - inline float ToPercentage() const; - inline bool HasPercent() const; - inline bool HasLengthAndPercentage() const; - inline bool BehavesLikeInitialValueOnBlockAxis() const; -""" - -"GenericFlexBasis" = """ - inline bool IsAuto() const; -""" - -"GenericMaxSize" = """ - inline bool ConvertsToLength() const; - inline nscoord ToLength() const; - inline bool ConvertsToPercentage() const; - inline float ToPercentage() const; - inline bool HasPercent() const; - inline bool HasLengthAndPercentage() const; - inline bool BehavesLikeInitialValueOnBlockAxis() const; -""" - -"GenericPosition" = """ - inline bool DependsOnPositioningAreaSize() const; - static inline StyleGenericPosition FromPercentage(float); -""" - -"GenericBackgroundSize" = """ - bool IsInitialValue() const; -""" - -"Rect" = """ - // Defined in nsStyleCoord.h - template inline bool All(Predicate) const; - template inline bool Any(Predicate) const; - - // Defined in WritingModes.h - inline const T& Get(mozilla::Side) const; - inline const T& Get(mozilla::WritingMode, mozilla::LogicalSide) const; - inline const T& GetIStart(mozilla::WritingMode) const; - inline const T& GetBStart(mozilla::WritingMode) const; - inline const T& GetIEnd(mozilla::WritingMode) const; - inline const T& GetBEnd(mozilla::WritingMode) const; -""" - -"GenericBorderRadius" = """ - inline const StyleLengthPercentage& Get(mozilla::HalfCorner) const; -""" - -"RestyleHint" = """ - static inline StyleRestyleHint RestyleSubtree(); - static inline StyleRestyleHint RecascadeSubtree(); - static inline StyleRestyleHint ForAnimations(); -""" - -# TODO(emilio): Add hooks to cbindgen to be able to generate MOZ_MUST_USE_TYPE -# or MOZ_MUST_USE on the functions. -"Owned" = """ - UniquePtr Consume() { - UniquePtr ret(ptr); - ptr = nullptr; - return ret; - } -""" - -"OwnedOrNull" = """ - UniquePtr Consume() { - UniquePtr ret(ptr); - ptr = nullptr; - return ret; - } -""" - -"Strong" = """ - already_AddRefed Consume() { - already_AddRefed ret(const_cast(ptr)); - ptr = nullptr; - return ret; - } -""" diff --git a/components/style/counter_style/mod.rs b/components/style/counter_style/mod.rs index 0daa0632739..77de5f52d2b 100644 --- a/components/style/counter_style/mod.rs +++ b/components/style/counter_style/mod.rs @@ -164,7 +164,7 @@ macro_rules! counter_style_descriptors { $( #[$doc: meta] $name: tt $ident: ident / $setter: ident [$checker: tt]: $ty: ty, )+ ) => { /// An @counter-style rule - #[derive(Clone, Debug)] + #[derive(Clone, Debug, ToShmem)] pub struct CounterStyleRuleData { name: CustomIdent, generation: Wrapping, @@ -337,7 +337,7 @@ impl CounterStyleRuleData { } /// -#[derive(Clone, Debug)] +#[derive(Clone, Debug, ToShmem)] pub enum System { /// 'cyclic' Cyclic, @@ -410,7 +410,7 @@ impl ToCss for System { /// #[cfg_attr(feature = "gecko", derive(MallocSizeOf))] -#[derive(Clone, Debug, Eq, PartialEq, ToComputedValue, ToCss)] +#[derive(Clone, Debug, Eq, PartialEq, ToComputedValue, ToCss, ToShmem)] pub enum Symbol { /// String(String), @@ -447,7 +447,7 @@ impl Symbol { } /// -#[derive(Clone, Debug, ToCss)] +#[derive(Clone, Debug, ToCss, ToShmem)] pub struct Negative(pub Symbol, pub Option); impl Parse for Negative { @@ -465,11 +465,11 @@ impl Parse for Negative { /// /// /// Empty Vec represents 'auto' -#[derive(Clone, Debug)] +#[derive(Clone, Debug, ToShmem)] pub struct Ranges(pub Vec>); /// A bound found in `Ranges`. -#[derive(Clone, Copy, Debug, ToCss)] +#[derive(Clone, Copy, Debug, ToCss, ToShmem)] pub enum CounterBound { /// An integer bound. Integer(Integer), @@ -548,7 +548,7 @@ where } /// -#[derive(Clone, Debug, ToCss)] +#[derive(Clone, Debug, ToCss, ToShmem)] pub struct Pad(pub Integer, pub Symbol); impl Parse for Pad { @@ -564,7 +564,7 @@ impl Parse for Pad { } /// -#[derive(Clone, Debug, ToCss)] +#[derive(Clone, Debug, ToCss, ToShmem)] pub struct Fallback(pub CustomIdent); impl Parse for Fallback { @@ -578,7 +578,7 @@ impl Parse for Fallback { /// #[cfg_attr(feature = "gecko", derive(MallocSizeOf))] -#[derive(Clone, Debug, Eq, PartialEq, ToComputedValue, ToCss)] +#[derive(Clone, Debug, Eq, PartialEq, ToComputedValue, ToCss, ToShmem)] pub struct Symbols(#[css(iterable)] pub Vec); impl Parse for Symbols { @@ -602,7 +602,7 @@ impl Parse for Symbols { } /// -#[derive(Clone, Debug, ToCss)] +#[derive(Clone, Debug, ToCss, ToShmem)] pub struct AdditiveSymbols(pub Vec); impl Parse for AdditiveSymbols { @@ -623,7 +623,7 @@ impl Parse for AdditiveSymbols { } /// && -#[derive(Clone, Debug, ToCss)] +#[derive(Clone, Debug, ToCss, ToShmem)] pub struct AdditiveTuple { /// pub weight: Integer, @@ -651,7 +651,7 @@ impl Parse for AdditiveTuple { } /// -#[derive(Clone, Debug, ToCss)] +#[derive(Clone, Debug, ToCss, ToShmem)] pub enum SpeakAs { /// auto Auto, diff --git a/components/style/custom_properties.rs b/components/style/custom_properties.rs index 0dbd611820d..639d32a97a9 100644 --- a/components/style/custom_properties.rs +++ b/components/style/custom_properties.rs @@ -96,7 +96,7 @@ pub fn parse_name(s: &str) -> Result<&str, ()> { /// /// We preserve the original CSS for serialization, and also the variable /// references to other custom property names. -#[derive(Clone, Debug, MallocSizeOf, PartialEq)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem)] pub struct VariableValue { css: String, diff --git a/components/style/dom.rs b/components/style/dom.rs index 28798e280b6..967b978bad4 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -642,15 +642,6 @@ pub trait TElement: self.unset_dirty_descendants(); } - /// Clear all element flags related to dirtiness. - /// - /// In Gecko, this corresponds to the regular dirty descendants bit, the - /// animation-only dirty descendants bit, the lazy frame construction bit, - /// and the lazy frame construction descendants bit. - unsafe fn clear_dirty_bits(&self) { - self.unset_dirty_descendants(); - } - /// Returns true if this element is a visited link. /// /// Servo doesn't support visited styles yet. @@ -825,11 +816,15 @@ pub trait TElement: Self: 'a, F: FnMut(&'a CascadeData, QuirksMode, Option), { + use rule_collector::containing_shadow_ignoring_svg_use; + let mut doc_rules_apply = !self.each_xbl_cascade_data(|data, quirks_mode| { f(data, quirks_mode, None); }); - if let Some(shadow) = self.containing_shadow() { + // Use the same rules to look for the containing host as we do for rule + // collection. + if let Some(shadow) = containing_shadow_ignoring_svg_use(*self) { doc_rules_apply = false; if let Some(data) = shadow.style_data() { f( diff --git a/components/style/error_reporting.rs b/components/style/error_reporting.rs index c58964c057a..04677c26041 100644 --- a/components/style/error_reporting.rs +++ b/components/style/error_reporting.rs @@ -6,8 +6,10 @@ #![deny(missing_docs)] +use crate::selector_parser::SelectorImpl; use crate::stylesheets::UrlExtraData; use cssparser::{BasicParseErrorKind, ParseErrorKind, SourceLocation, Token}; +use selectors::SelectorList; use std::fmt; use style_traits::ParseError; @@ -15,7 +17,11 @@ use style_traits::ParseError; #[derive(Debug)] pub enum ContextualParseError<'a> { /// A property declaration was not recognized. - UnsupportedPropertyDeclaration(&'a str, ParseError<'a>), + UnsupportedPropertyDeclaration( + &'a str, + ParseError<'a>, + Option<&'a SelectorList>, + ), /// A font face descriptor was not recognized. UnsupportedFontFaceDescriptor(&'a str, ParseError<'a>), /// A font feature values descriptor was not recognized. @@ -121,7 +127,7 @@ impl<'a> fmt::Display for ContextualParseError<'a> { } match *self { - ContextualParseError::UnsupportedPropertyDeclaration(decl, ref err) => { + ContextualParseError::UnsupportedPropertyDeclaration(decl, ref err, _selectors) => { write!(f, "Unsupported property declaration: '{}', ", decl)?; parse_error_to_str(err, f) }, diff --git a/components/style/font_face.rs b/components/style/font_face.rs index 12ebe3b9864..655c8846f76 100644 --- a/components/style/font_face.rs +++ b/components/style/font_face.rs @@ -34,7 +34,7 @@ use style_traits::{StyleParseErrorKind, ToCss}; /// A source for a font-face rule. #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] -#[derive(Clone, Debug, Eq, PartialEq, ToCss)] +#[derive(Clone, Debug, Eq, PartialEq, ToCss, ToShmem)] pub enum Source { /// A `url()` source. Url(UrlSource), @@ -68,7 +68,7 @@ pub enum FontFaceSourceListComponent { /// /// #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, ToShmem)] pub struct UrlSource { /// The specified url. pub url: SpecifiedUrl, @@ -101,7 +101,9 @@ impl ToCss for UrlSource { /// on whether and when it is downloaded and ready to use. #[allow(missing_docs)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToComputedValue, ToCss)] +#[derive( + Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToComputedValue, ToCss, ToShmem, +)] #[repr(u8)] pub enum FontDisplay { Auto, @@ -144,7 +146,7 @@ macro_rules! impl_range { /// The font-weight descriptor: /// /// https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-weight -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, ToShmem)] pub struct FontWeightRange(pub AbsoluteFontWeight, pub AbsoluteFontWeight); impl_range!(FontWeightRange, AbsoluteFontWeight); @@ -176,7 +178,7 @@ impl FontWeightRange { /// The font-stretch descriptor: /// /// https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-stretch -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, ToShmem)] pub struct FontStretchRange(pub FontStretch, pub FontStretch); impl_range!(FontStretchRange, FontStretch); @@ -205,7 +207,7 @@ impl FontStretchRange { /// The font-style descriptor: /// /// https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-style -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, ToShmem)] #[allow(missing_docs)] pub enum FontStyle { Normal, @@ -435,7 +437,7 @@ macro_rules! font_face_descriptors_common { /// Data inside a `@font-face` rule. /// /// - #[derive(Clone, Debug, PartialEq)] + #[derive(Clone, Debug, PartialEq, ToShmem)] pub struct FontFaceRuleData { $( #[$doc] diff --git a/components/style/font_metrics.rs b/components/style/font_metrics.rs index 15b5fd453e8..8e69118ade4 100644 --- a/components/style/font_metrics.rs +++ b/components/style/font_metrics.rs @@ -43,7 +43,11 @@ pub trait FontMetricsProvider { } /// Get default size of a given language and generic family. - fn get_size(&self, font_name: &Atom, font_family: u8) -> Au; + fn get_size( + &self, + font_name: &Atom, + font_family: crate::values::computed::font::GenericFontFamily, + ) -> Au; /// Construct from a shared style context fn create_from(context: &SharedStyleContext) -> Self @@ -66,7 +70,7 @@ impl FontMetricsProvider for ServoMetricsProvider { ServoMetricsProvider } - fn get_size(&self, _font_name: &Atom, _font_family: u8) -> Au { + fn get_size(&self, _: &Atom, _: crate::values::computed::font::GenericFontFamily) -> Au { unreachable!("Dummy provider should never be used to compute font size") } } diff --git a/components/style/gecko/boxed_types.rs b/components/style/gecko/boxed_types.rs new file mode 100644 index 00000000000..857f99e1489 --- /dev/null +++ b/components/style/gecko/boxed_types.rs @@ -0,0 +1,21 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//! FFI implementations for types listed in ServoBoxedTypeList.h. + +use crate::gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI}; +use to_shmem::SharedMemoryBuilder; + +// TODO(heycam): The FFI impls for most of the types in ServoBoxedTypeList.h are spread across +// various files at the moment, but should probably all move here, and use macros to define +// them more succinctly, like we do in arc_types.rs. + +#[cfg(feature = "gecko")] +unsafe impl HasFFI for SharedMemoryBuilder { + type FFIType = crate::gecko_bindings::bindings::RawServoSharedMemoryBuilder; +} +#[cfg(feature = "gecko")] +unsafe impl HasSimpleFFI for SharedMemoryBuilder {} +#[cfg(feature = "gecko")] +unsafe impl HasBoxFFI for SharedMemoryBuilder {} diff --git a/components/style/gecko/conversions.rs b/components/style/gecko/conversions.rs index 356636fc6bb..43438438a40 100644 --- a/components/style/gecko/conversions.rs +++ b/components/style/gecko/conversions.rs @@ -123,14 +123,11 @@ impl nsStyleImage { match image { GenericImage::Gradient(boxed_gradient) => self.set_gradient(*boxed_gradient), GenericImage::Url(ref url) => unsafe { - bindings::Gecko_SetLayerImageImageValue(self, (url.0).0.url_value.get()); + bindings::Gecko_SetLayerImageImageValue(self, url.url_value_ptr()) }, GenericImage::Rect(ref image_rect) => { unsafe { - bindings::Gecko_SetLayerImageImageValue( - self, - (image_rect.url.0).0.url_value.get(), - ); + bindings::Gecko_SetLayerImageImageValue(self, image_rect.url.url_value_ptr()); bindings::Gecko_InitializeImageCropRect(self); // Set CropRect @@ -421,10 +418,8 @@ impl nsStyleImage { use self::structs::NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE as CLOSEST_SIDE; use self::structs::NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER as FARTHEST_CORNER; use self::structs::NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE as FARTHEST_SIDE; - use crate::values::computed::image::LineDirection; use crate::values::computed::position::Position; - use crate::values::computed::Length; - use crate::values::generics::image::{Circle, ColorStop, CompatMode, Ellipse}; + use crate::values::generics::image::{Circle, ColorStop, Ellipse}; use crate::values::generics::image::{EndingShape, GradientKind, ShapeExtent}; let gecko_gradient = bindings::Gecko_GetGradientImageValue(self) @@ -837,8 +832,7 @@ impl TrackSize { /// Return TrackSize from given two nsStyleCoord pub fn from_gecko_style_coords(gecko_min: &T, gecko_max: &T) -> Self { use crate::gecko_bindings::structs::root::nsStyleUnit; - use crate::values::computed::length::LengthPercentage; - use crate::values::generics::grid::{TrackBreadth, TrackSize}; + use crate::values::generics::grid::TrackBreadth; if gecko_min.unit() == nsStyleUnit::eStyleUnit_None { debug_assert!( @@ -865,8 +859,6 @@ impl TrackSize { /// Save TrackSize to given gecko fields. pub fn to_gecko_style_coords(&self, gecko_min: &mut T, gecko_max: &mut T) { - use crate::values::generics::grid::TrackSize; - match *self { TrackSize::FitContent(ref lop) => { // Gecko sets min value to None and max value to the actual value in fit-content @@ -896,8 +888,6 @@ impl TrackListValue { /// Save TrackSize to given gecko fields. pub fn to_gecko_style_coords(&self, gecko_min: &mut T, gecko_max: &mut T) { - use crate::values::generics::grid::TrackListValue; - match *self { TrackListValue::TrackSize(ref size) => size.to_gecko_style_coords(gecko_min, gecko_max), _ => unreachable!("Should only transform from track-size computed values"), @@ -921,8 +911,6 @@ where pub fn from_gecko_rect( sides: &crate::gecko_bindings::structs::nsStyleSides, ) -> Option> { - use crate::values::generics::rect::Rect; - Some(Rect::new( T::from_gecko_style_coord(&sides.data_at(0)).expect("coord[0] cound not convert"), T::from_gecko_style_coord(&sides.data_at(1)).expect("coord[1] cound not convert"), diff --git a/components/style/gecko/media_features.rs b/components/style/gecko/media_features.rs index 12417d38ef0..4b94571c8ef 100644 --- a/components/style/gecko/media_features.rs +++ b/components/style/gecko/media_features.rs @@ -127,10 +127,6 @@ fn eval_device_aspect_ratio( } /// https://compat.spec.whatwg.org/#css-media-queries-webkit-device-pixel-ratio -/// -/// FIXME(emilio): This should be an alias of `resolution`, according to the -/// spec, and also according to the code in Chromium. Unify with -/// `eval_resolution`. fn eval_device_pixel_ratio( device: &Device, query_value: Option, diff --git a/components/style/gecko/media_queries.rs b/components/style/gecko/media_queries.rs index 4c04d9573e5..b39e748ce2b 100644 --- a/components/style/gecko/media_queries.rs +++ b/components/style/gecko/media_queries.rs @@ -169,6 +169,7 @@ impl Device { self.document() .mPresShell .as_ref()? + ._base .mPresContext .mRawPtr .as_ref() diff --git a/components/style/gecko/mod.rs b/components/style/gecko/mod.rs index 1051f84fc52..fb332dcce6e 100644 --- a/components/style/gecko/mod.rs +++ b/components/style/gecko/mod.rs @@ -8,6 +8,7 @@ mod non_ts_pseudo_class_list; pub mod arc_types; +pub mod boxed_types; pub mod conversions; pub mod data; pub mod media_features; diff --git a/components/style/gecko/pseudo_element_definition.mako.rs b/components/style/gecko/pseudo_element_definition.mako.rs index e2dffcbdd74..a752d84c481 100644 --- a/components/style/gecko/pseudo_element_definition.mako.rs +++ b/components/style/gecko/pseudo_element_definition.mako.rs @@ -3,7 +3,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ /// Gecko's pseudo-element definition. -#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq)] +#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToShmem)] pub enum PseudoElement { % for pseudo in PSEUDOS: /// ${pseudo.value} diff --git a/components/style/gecko/selector_parser.rs b/components/style/gecko/selector_parser.rs index b00cb4f909e..41de05c33b9 100644 --- a/components/style/gecko/selector_parser.rs +++ b/components/style/gecko/selector_parser.rs @@ -44,7 +44,7 @@ pub type Lang = Atom; macro_rules! pseudo_class_name { ([$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*]) => { /// Our representation of a non tree-structural pseudo-class. - #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)] + #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToShmem)] pub enum NonTSPseudoClass { $( #[doc = $css] diff --git a/components/style/gecko/url.rs b/components/style/gecko/url.rs index df5f1137532..2da16043779 100644 --- a/components/style/gecko/url.rs +++ b/components/style/gecko/url.rs @@ -17,16 +17,20 @@ use cssparser::Parser; use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use nsstring::nsCString; use servo_arc::Arc; +use std::collections::HashMap; use std::fmt::{self, Write}; +use std::mem::ManuallyDrop; +use std::sync::RwLock; use style_traits::{CssWriter, ParseError, ToCss}; +use to_shmem::{SharedMemoryBuilder, ToShmem}; /// A CSS url() value for gecko. #[css(function = "url")] -#[derive(Clone, Debug, PartialEq, SpecifiedValueInfo, ToCss)] +#[derive(Clone, Debug, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)] pub struct CssUrl(pub Arc); /// Data shared between CssUrls. -#[derive(Clone, Debug, PartialEq, SpecifiedValueInfo, ToCss)] +#[derive(Clone, Debug, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)] pub struct CssUrlData { /// The URL in unresolved string form. serialization: String, @@ -81,6 +85,20 @@ impl CssUrlData { } } +#[cfg(debug_assertions)] +impl Drop for CssUrlData { + fn drop(&mut self) { + assert!( + !URL_VALUE_TABLE + .read() + .unwrap() + .contains_key(&CssUrlDataKey(self as *mut _ as *const _)), + "All CssUrlData objects used as keys in URL_VALUE_TABLE should be \ + from shared memory style sheets, and so should never be dropped", + ); + } +} + impl Parse for CssUrl { fn parse<'i, 't>( context: &ParserContext, @@ -104,15 +122,54 @@ impl MallocSizeOf for CssUrl { } } +/// A key type for URL_VALUE_TABLE. +#[derive(Eq, Hash, PartialEq)] +struct CssUrlDataKey(*const CssUrlData); + +unsafe impl Sync for CssUrlDataKey {} +unsafe impl Send for CssUrlDataKey {} + +/// The source of a Gecko URLValue object for a SpecifiedUrl. +#[derive(Clone, Debug)] +pub enum URLValueSource { + /// A strong reference to a Gecko URLValue object. + URLValue(RefPtr), + /// A CORSMode value used to lazily construct a Gecko URLValue object. + /// + /// The lazily created object will be stored in URL_VALUE_TABLE. + CORSMode(CORSMode), +} + +impl ToShmem for URLValueSource { + fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> ManuallyDrop { + ManuallyDrop::new(match self { + URLValueSource::URLValue(r) => URLValueSource::CORSMode(r.mCORSMode), + URLValueSource::CORSMode(c) => URLValueSource::CORSMode(*c), + }) + } +} + /// A specified non-image `url()` value. -#[derive(Clone, Debug, SpecifiedValueInfo, ToCss)] +#[derive(Clone, Debug, SpecifiedValueInfo, ToCss, ToShmem)] pub struct SpecifiedUrl { /// The specified url value. pub url: CssUrl, /// Gecko's URLValue so that we can reuse it while rematching a /// property with this specified value. + /// + /// Box this to avoid SpecifiedUrl getting bigger than two words, + /// and increasing the size of PropertyDeclaration. #[css(skip)] - pub url_value: RefPtr, + url_value: Box, +} + +fn make_url_value(url: &CssUrl, cors_mode: CORSMode) -> RefPtr { + 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 { @@ -122,12 +179,7 @@ impl SpecifiedUrl { } fn from_css_url_with_cors(url: CssUrl, cors: CORSMode) -> Self { - let url_value = unsafe { - let ptr = bindings::Gecko_URLValue_Create(url.0.clone().into_strong(), cors); - // We do not expect Gecko_URLValue_Create returns null. - debug_assert!(!ptr.is_null()); - RefPtr::from_addrefed(ptr) - }; + let url_value = Box::new(URLValueSource::URLValue(make_url_value(&url, cors))); Self { url, url_value } } @@ -140,6 +192,45 @@ impl SpecifiedUrl { use crate::gecko_bindings::structs::root::mozilla::CORSMode_CORS_ANONYMOUS; Self::from_css_url_with_cors(url, CORSMode_CORS_ANONYMOUS) } + + fn with_url_value(&self, f: F) -> T + where + F: FnOnce(&RefPtr) -> 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 { + 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 +/// until the end of the process and be reported as leaks. +pub fn shutdown() { + URL_VALUE_TABLE.write().unwrap().clear(); } impl Parse for SpecifiedUrl { @@ -165,7 +256,7 @@ impl MallocSizeOf for SpecifiedUrl { // 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.get()) }; + n += unsafe { bindings::Gecko_URLValue_SizeOfIncludingThis(self.url_value_ptr()) }; n } } @@ -185,7 +276,7 @@ impl ToComputedValue for SpecifiedUrl { } /// A specified image `url()` value. -#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)] +#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)] pub struct SpecifiedImageUrl(pub SpecifiedUrl); impl SpecifiedImageUrl { @@ -258,7 +349,8 @@ impl ToCss for ComputedUrl { where W: Write, { - serialize_computed_url(&self.0.url_value, dest, bindings::Gecko_GetComputedURLSpec) + self.0 + .with_url_value(|r| serialize_computed_url(r, dest, bindings::Gecko_GetComputedURLSpec)) } } @@ -267,12 +359,20 @@ impl ComputedUrl { pub unsafe fn from_url_value(url_value: RefPtr) -> Self { let css_url = &*url_value.mCssUrl.mRawPtr; let url = CssUrl(CssUrlData::as_arc(&css_url).clone_arc()); - ComputedUrl(SpecifiedUrl { url, url_value }) + 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 { + 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.get() + self.0.url_value_ptr() } } @@ -285,11 +385,9 @@ impl ToCss for ComputedImageUrl { where W: Write, { - serialize_computed_url( - &(self.0).0.url_value, - dest, - bindings::Gecko_GetComputedImageURLSpec, - ) + (self.0).0.with_url_value(|r| { + serialize_computed_url(r, dest, bindings::Gecko_GetComputedImageURLSpec) + }) } } @@ -299,11 +397,27 @@ impl ComputedImageUrl { let url_value = image_request.mImageValue.to_safe(); let css_url = &*url_value.mCssUrl.mRawPtr; let url = CssUrl(CssUrlData::as_arc(&css_url).clone_arc()); - ComputedImageUrl(SpecifiedImageUrl(SpecifiedUrl { url, url_value })) + ComputedImageUrl(SpecifiedImageUrl(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 { + (self.0).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).0.url_value.get() + (self.0).0.url_value_ptr() } } + +lazy_static! { + /// A table mapping CssUrlData objects to their lazily created Gecko + /// URLValue objects. + static ref URL_VALUE_TABLE: RwLock>> = { + Default::default() + }; +} diff --git a/components/style/gecko/values.rs b/components/style/gecko/values.rs index 6b3e7a676e0..8b05e1520b4 100644 --- a/components/style/gecko/values.rs +++ b/components/style/gecko/values.rs @@ -18,7 +18,7 @@ use crate::values::generics::gecko::ScrollSnapPoint; use crate::values::generics::grid::{TrackBreadth, TrackKeyword}; use crate::values::generics::length::LengthPercentageOrAuto; use crate::values::generics::{CounterStyleOrNone, NonNegative}; -use crate::values::{Auto, Either, None_, Normal}; +use crate::values::Either; use crate::{Atom, Zero}; use app_units::Au; use cssparser::RGBA; @@ -44,23 +44,6 @@ impl nsStyleCoord { } } -impl GeckoStyleCoordConvertible - for Either -{ - fn to_gecko_style_coord(&self, coord: &mut T) { - match *self { - Either::First(ref v) => v.to_gecko_style_coord(coord), - Either::Second(ref v) => v.to_gecko_style_coord(coord), - } - } - - fn from_gecko_style_coord(coord: &T) -> Option { - A::from_gecko_style_coord(coord) - .map(Either::First) - .or_else(|| B::from_gecko_style_coord(coord).map(Either::Second)) - } -} - impl GeckoStyleCoordConvertible for NonNegative where Inner: GeckoStyleCoordConvertible, @@ -265,48 +248,6 @@ impl GeckoStyleCoordConvertible for Angle { } } -impl GeckoStyleCoordConvertible for Auto { - fn to_gecko_style_coord(&self, coord: &mut T) { - coord.set_value(CoordDataValue::Auto) - } - - fn from_gecko_style_coord(coord: &T) -> Option { - if let CoordDataValue::Auto = coord.as_value() { - Some(Auto) - } else { - None - } - } -} - -impl GeckoStyleCoordConvertible for None_ { - fn to_gecko_style_coord(&self, coord: &mut T) { - coord.set_value(CoordDataValue::None) - } - - fn from_gecko_style_coord(coord: &T) -> Option { - if let CoordDataValue::None = coord.as_value() { - Some(None_) - } else { - None - } - } -} - -impl GeckoStyleCoordConvertible for Normal { - fn to_gecko_style_coord(&self, coord: &mut T) { - coord.set_value(CoordDataValue::Normal) - } - - fn from_gecko_style_coord(coord: &T) -> Option { - if let CoordDataValue::Normal = coord.as_value() { - Some(Normal) - } else { - None - } - } -} - impl GeckoStyleCoordConvertible for ScrollSnapPoint { fn to_gecko_style_coord(&self, coord: &mut T) { match self.repeated() { @@ -317,7 +258,6 @@ impl GeckoStyleCoordConvertible for ScrollSnapPoint { fn from_gecko_style_coord(coord: &T) -> Option { use crate::gecko_bindings::structs::root::nsStyleUnit; - use crate::values::generics::gecko::ScrollSnapPoint; Some(match coord.unit() { nsStyleUnit::eStyleUnit_None => ScrollSnapPoint::None, diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index 46eaa427b3a..0fa354fb139 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -69,6 +69,7 @@ use crate::selector_parser::{AttrValue, HorizontalDirection, Lang}; use crate::shared_lock::Locked; use crate::string_cache::{Atom, Namespace, WeakAtom, WeakNamespace}; use crate::stylist::CascadeData; +use crate::values::computed::font::GenericFontFamily; use crate::values::specified::length::FontBaseSize; use crate::CaseSensitivityExt; use app_units::Au; @@ -985,7 +986,6 @@ fn get_animation_rule( element: &GeckoElement, cascade_level: CascadeLevel, ) -> Option>> { - use crate::gecko_bindings::sugar::ownership::HasSimpleFFI; use crate::properties::longhands::ANIMATABLE_PROPERTY_COUNT; // There's a very rough correlation between the number of effects @@ -1041,7 +1041,7 @@ impl FontMetricsProvider for GeckoFontMetricsProvider { GeckoFontMetricsProvider::new() } - fn get_size(&self, font_name: &Atom, font_family: u8) -> Au { + fn get_size(&self, font_name: &Atom, font_family: GenericFontFamily) -> Au { let mut cache = self.font_size_cache.borrow_mut(); if let Some(sizes) = cache.iter().find(|el| el.0 == *font_name) { return sizes.1.size_for_generic(font_family); @@ -1100,16 +1100,17 @@ impl FontMetricsProvider for GeckoFontMetricsProvider { } impl structs::FontSizePrefs { - fn size_for_generic(&self, font_family: u8) -> Au { + fn size_for_generic(&self, font_family: GenericFontFamily) -> Au { Au(match font_family { - structs::kPresContext_DefaultVariableFont_ID => self.mDefaultVariableSize, - structs::kPresContext_DefaultFixedFont_ID => self.mDefaultFixedSize, - structs::kGenericFont_serif => self.mDefaultSerifSize, - structs::kGenericFont_sans_serif => self.mDefaultSansSerifSize, - structs::kGenericFont_monospace => self.mDefaultMonospaceSize, - structs::kGenericFont_cursive => self.mDefaultCursiveSize, - structs::kGenericFont_fantasy => self.mDefaultFantasySize, - _ => unreachable!("Unknown generic ID"), + GenericFontFamily::None => self.mDefaultVariableSize, + GenericFontFamily::Serif => self.mDefaultSerifSize, + GenericFontFamily::SansSerif => self.mDefaultSansSerifSize, + GenericFontFamily::Monospace => self.mDefaultMonospaceSize, + GenericFontFamily::Cursive => self.mDefaultCursiveSize, + GenericFontFamily::Fantasy => self.mDefaultFantasySize, + GenericFontFamily::MozEmoji => unreachable!( + "Should never get here, since this doesn't (yet) appear on font family" + ), }) } } @@ -1422,16 +1423,6 @@ impl<'le> TElement for GeckoElement<'le> { ) } - #[inline] - unsafe fn clear_dirty_bits(&self) { - self.unset_flags( - ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO as u32 | - ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO as u32 | - NODE_DESCENDANTS_NEED_FRAMES as u32 | - NODE_NEEDS_FRAME as u32, - ) - } - fn is_visited_link(&self) -> bool { self.state().intersects(ElementState::IN_VISITED_STATE) } diff --git a/components/style/gecko_bindings/sugar/mod.rs b/components/style/gecko_bindings/sugar/mod.rs index 642b5ad203a..de981bd289a 100644 --- a/components/style/gecko_bindings/sugar/mod.rs +++ b/components/style/gecko_bindings/sugar/mod.rs @@ -15,4 +15,3 @@ mod ns_t_array; pub mod origin_flags; pub mod ownership; pub mod refptr; -mod style_complex_color; diff --git a/components/style/gecko_bindings/sugar/ownership.rs b/components/style/gecko_bindings/sugar/ownership.rs index 04fbf2e55c8..5170b7dbc5a 100644 --- a/components/style/gecko_bindings/sugar/ownership.rs +++ b/components/style/gecko_bindings/sugar/ownership.rs @@ -65,6 +65,14 @@ pub unsafe trait HasBoxFFI: HasSimpleFFI { fn into_ffi(self: Box) -> Owned { unsafe { transmute(self) } } + + /// Drops an owned FFI pointer. This conceptually takes the + /// Owned, except it's a bit of a paint to do that without + /// much benefit. + #[inline] + unsafe fn drop_ffi(ptr: *mut Self::FFIType) { + let _ = Box::from_raw(ptr as *mut Self); + } } /// Helper trait for conversions between FFI Strong/Borrowed types and Arcs @@ -268,14 +276,6 @@ pub struct Owned { } impl Owned { - /// Gets this `Owned` type as a `Box`. - pub fn into_box(self) -> Box - where - ServoType: HasBoxFFI, - { - unsafe { transmute(self) } - } - /// Converts this instance to a (non-null) instance of `OwnedOrNull`. pub fn maybe(self) -> OwnedOrNull { unsafe { transmute(self) } diff --git a/components/style/gecko_bindings/sugar/style_complex_color.rs b/components/style/gecko_bindings/sugar/style_complex_color.rs deleted file mode 100644 index aec334969d4..00000000000 --- a/components/style/gecko_bindings/sugar/style_complex_color.rs +++ /dev/null @@ -1,111 +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/. */ - -//! Rust helpers to interact with Gecko's StyleComplexColor. - -use crate::gecko::values::{convert_nscolor_to_rgba, convert_rgba_to_nscolor}; -use crate::gecko_bindings::structs::StyleComplexColor; -use crate::gecko_bindings::structs::StyleComplexColor_Tag as Tag; -use crate::values::computed::{Color as ComputedColor, ColorOrAuto, RGBAColor as ComputedRGBA}; -use crate::values::generics::color::{ - Color as GenericColor, ColorOrAuto as GenericColorOrAuto, ComplexColorRatios, -}; - -impl StyleComplexColor { - /// Create a `StyleComplexColor` value that represents `currentColor`. - pub fn current_color() -> Self { - StyleComplexColor { - mColor: 0, - mBgRatio: 0., - mFgRatio: 1., - mTag: Tag::eForeground, - } - } - - /// Create a `StyleComplexColor` value that represents `auto`. - pub fn auto() -> Self { - StyleComplexColor { - mColor: 0, - mBgRatio: 0., - mFgRatio: 1., - mTag: Tag::eAuto, - } - } -} - -impl From for StyleComplexColor { - fn from(other: ComputedRGBA) -> Self { - StyleComplexColor { - mColor: convert_rgba_to_nscolor(&other), - mBgRatio: 1., - mFgRatio: 0., - mTag: Tag::eNumeric, - } - } -} - -impl From for StyleComplexColor { - fn from(other: ComputedColor) -> Self { - match other { - GenericColor::Numeric(color) => color.into(), - GenericColor::Foreground => Self::current_color(), - GenericColor::Complex(color, ratios) => { - debug_assert!(ratios != ComplexColorRatios::NUMERIC); - debug_assert!(ratios != ComplexColorRatios::FOREGROUND); - StyleComplexColor { - mColor: convert_rgba_to_nscolor(&color).into(), - mBgRatio: ratios.bg, - mFgRatio: ratios.fg, - mTag: Tag::eComplex, - } - }, - } - } -} - -impl From for ComputedColor { - fn from(other: StyleComplexColor) -> Self { - match other.mTag { - Tag::eNumeric => { - debug_assert!(other.mBgRatio == 1. && other.mFgRatio == 0.); - GenericColor::Numeric(convert_nscolor_to_rgba(other.mColor)) - }, - Tag::eForeground => { - debug_assert!(other.mBgRatio == 0. && other.mFgRatio == 1.); - GenericColor::Foreground - }, - Tag::eComplex => { - debug_assert!(other.mBgRatio != 1. || other.mFgRatio != 0.); - debug_assert!(other.mBgRatio != 0. || other.mFgRatio != 1.); - GenericColor::Complex( - convert_nscolor_to_rgba(other.mColor), - ComplexColorRatios { - bg: other.mBgRatio, - fg: other.mFgRatio, - }, - ) - }, - Tag::eAuto => unreachable!("Unsupport StyleComplexColor with tag eAuto"), - } - } -} - -impl From for StyleComplexColor { - fn from(other: ColorOrAuto) -> Self { - match other { - GenericColorOrAuto::Color(color) => color.into(), - GenericColorOrAuto::Auto => StyleComplexColor::auto(), - } - } -} - -impl From for ColorOrAuto { - fn from(other: StyleComplexColor) -> Self { - if other.mTag != Tag::eAuto { - GenericColorOrAuto::Color(other.into()) - } else { - GenericColorOrAuto::Auto - } - } -} diff --git a/components/style/gecko_string_cache/mod.rs b/components/style/gecko_string_cache/mod.rs index 9c33f25d9b8..d71d192166a 100644 --- a/components/style/gecko_string_cache/mod.rs +++ b/components/style/gecko_string_cache/mod.rs @@ -25,9 +25,11 @@ use std::char::{self, DecodeUtf16}; use std::fmt::{self, Write}; use std::hash::{Hash, Hasher}; use std::iter::Cloned; +use std::mem::{self, ManuallyDrop}; use std::ops::Deref; -use std::{mem, slice, str}; +use std::{slice, str}; use style_traits::SpecifiedValueInfo; +use to_shmem::{SharedMemoryBuilder, ToShmem}; #[macro_use] #[allow(improper_ctypes, non_camel_case_types, missing_docs)] @@ -122,6 +124,18 @@ impl Borrow for Atom { } } +impl ToShmem for Atom { + fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> ManuallyDrop { + assert!( + self.is_static(), + "ToShmem failed for Atom: must be a static atom: {}", + self + ); + + ManuallyDrop::new(Atom(self.0)) + } +} + impl Eq for WeakAtom {} impl PartialEq for WeakAtom { #[inline] diff --git a/components/style/gecko_string_cache/namespace.rs b/components/style/gecko_string_cache/namespace.rs index 725e1da2169..33883e66941 100644 --- a/components/style/gecko_string_cache/namespace.rs +++ b/components/style/gecko_string_cache/namespace.rs @@ -24,7 +24,7 @@ macro_rules! ns { } /// A Gecko namespace is just a wrapped atom. -#[derive(Clone, Debug, Default, Eq, Hash, MallocSizeOf, PartialEq)] +#[derive(Clone, Debug, Default, Eq, Hash, MallocSizeOf, PartialEq, ToShmem)] pub struct Namespace(pub Atom); impl PrecomputedHash for Namespace { diff --git a/components/style/invalidation/element/invalidator.rs b/components/style/invalidation/element/invalidator.rs index 7ed97c0b197..371c0771183 100644 --- a/components/style/invalidation/element/invalidator.rs +++ b/components/style/invalidation/element/invalidator.rs @@ -750,8 +750,19 @@ where // // Note that we'll also restyle the pseudo-element because // it would match this invalidation. - if self.processor.invalidates_on_eager_pseudo_element() && pseudo.is_eager() { - invalidated_self = true; + if self.processor.invalidates_on_eager_pseudo_element() { + if pseudo.is_eager() { + invalidated_self = true; + } + // If we start or stop matching some marker rules, and + // don't have a marker, then we need to restyle the + // element to potentially create one. + // + // Same caveats as for other eager pseudos apply, this + // could be more fine-grained. + if pseudo.is_marker() && self.element.marker_pseudo_element().is_none() { + invalidated_self = true; + } } } diff --git a/components/style/lib.rs b/components/style/lib.rs index 37b464afb47..bd33dbeafe4 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -99,6 +99,9 @@ extern crate style_traits; #[cfg(feature = "gecko")] extern crate thin_slice; extern crate time; +extern crate to_shmem; +#[macro_use] +extern crate to_shmem_derive; extern crate uluru; extern crate unicode_bidi; #[allow(unused_extern_crates)] diff --git a/components/style/macros.rs b/components/style/macros.rs index fb189837181..22f1966071b 100644 --- a/components/style/macros.rs +++ b/components/style/macros.rs @@ -80,6 +80,8 @@ macro_rules! define_keyword_type { ToAnimatedZero, ToComputedValue, ToCss, + ToResolvedValue, + ToShmem, )] pub struct $name; diff --git a/components/style/matching.rs b/components/style/matching.rs index b1240443dea..583e41ad82e 100644 --- a/components/style/matching.rs +++ b/components/style/matching.rs @@ -471,7 +471,7 @@ trait PrivateMatchMethods: TElement { debug!("accumulate_damage_for: {:?}", self); debug_assert!(!shared_context .traversal_flags - .contains(TraversalFlags::Forgetful)); + .contains(TraversalFlags::FinalAnimationTraversal)); let difference = self.compute_style_difference(old_values, new_values, pseudo); @@ -723,11 +723,11 @@ pub trait MatchMethods: TElement { } } - // Don't accumulate damage if we're in a forgetful traversal. + // Don't accumulate damage if we're in the final animation traversal. if context .shared .traversal_flags - .contains(TraversalFlags::Forgetful) + .contains(TraversalFlags::FinalAnimationTraversal) { return ChildCascadeRequirement::MustCascadeChildren; } diff --git a/components/style/media_queries/media_condition.rs b/components/style/media_queries/media_condition.rs index 7fed56bee85..19e20105819 100644 --- a/components/style/media_queries/media_condition.rs +++ b/components/style/media_queries/media_condition.rs @@ -14,7 +14,7 @@ use std::fmt::{self, Write}; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; /// A binary `and` or `or` operator. -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToCss)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToCss, ToShmem)] #[allow(missing_docs)] pub enum Operator { And, @@ -29,7 +29,7 @@ enum AllowOr { } /// Represents a media condition. -#[derive(Clone, Debug, MallocSizeOf, PartialEq)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem)] pub enum MediaCondition { /// A simple media feature expression, implicitly parenthesized. Feature(MediaFeatureExpression), diff --git a/components/style/media_queries/media_feature_expression.rs b/components/style/media_queries/media_feature_expression.rs index 6a9db93e889..3f8eefbfab5 100644 --- a/components/style/media_queries/media_feature_expression.rs +++ b/components/style/media_queries/media_feature_expression.rs @@ -17,7 +17,6 @@ use crate::parser::{Parse, ParserContext}; #[cfg(feature = "servo")] use crate::servo::media_queries::MEDIA_FEATURES; use crate::str::{starts_with_ignore_ascii_case, string_as_ascii_lowercase}; -use crate::stylesheets::Origin; use crate::values::computed::{self, ToComputedValue}; use crate::values::specified::{Integer, Length, Number, Resolution}; use crate::values::{serialize_atom_identifier, CSSFloat}; @@ -28,7 +27,7 @@ use std::fmt::{self, Write}; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; /// An aspect ratio, with a numerator and denominator. -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToShmem)] pub struct AspectRatio(pub u32, pub u32); impl ToCss for AspectRatio { @@ -52,7 +51,7 @@ impl PartialOrd for AspectRatio { } /// The kind of matching that should be performed on a media feature value. -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToShmem)] pub enum Range { /// At least the specified value. Min, @@ -61,7 +60,7 @@ pub enum Range { } /// The operator that was specified in this media feature. -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToShmem)] pub enum Operator { /// = Equal, @@ -94,7 +93,7 @@ impl ToCss for Operator { /// /// Ranged media features are not allowed with operations (that'd make no /// sense). -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToShmem)] pub enum RangeOrOperator { /// A `Range`. Range(Range), @@ -152,7 +151,7 @@ impl RangeOrOperator { /// A feature expression contains a reference to the media feature, the value /// the media query contained, and the range to evaluate. -#[derive(Clone, Debug, MallocSizeOf)] +#[derive(Clone, Debug, MallocSizeOf, ToShmem)] pub struct MediaFeatureExpression { feature_index: usize, value: Option, @@ -290,7 +289,7 @@ impl MediaFeatureExpression { let mut requirements = ParsingRequirements::empty(); - if context.chrome_rules_enabled() || context.stylesheet_origin == Origin::UserAgent { + if context.in_ua_or_chrome_sheet() { requirements.insert(ParsingRequirements::CHROME_AND_UA_ONLY); } @@ -468,7 +467,7 @@ impl MediaFeatureExpression { /// If the first, this would need to store the relevant values. /// /// See: https://github.com/w3c/csswg-drafts/issues/1968 -#[derive(Clone, Debug, MallocSizeOf, PartialEq)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem)] pub enum MediaExpressionValue { /// A length. Length(Length), diff --git a/components/style/media_queries/media_list.rs b/components/style/media_queries/media_list.rs index 0acf4f1bdf9..5d150f7db99 100644 --- a/components/style/media_queries/media_list.rs +++ b/components/style/media_queries/media_list.rs @@ -15,7 +15,7 @@ use cssparser::{ParserInput, Token}; /// A type that encapsulates a media query list. #[css(comma, derive_debug)] -#[derive(Clone, MallocSizeOf, ToCss)] +#[derive(Clone, MallocSizeOf, ToCss, ToShmem)] pub struct MediaList { /// The list of media queries. #[css(iterable)] diff --git a/components/style/media_queries/media_query.rs b/components/style/media_queries/media_query.rs index f61ac6191fb..1768053dbce 100644 --- a/components/style/media_queries/media_query.rs +++ b/components/style/media_queries/media_query.rs @@ -16,7 +16,7 @@ use std::fmt::{self, Write}; use style_traits::{CssWriter, ParseError, ToCss}; /// -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToCss)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToCss, ToShmem)] pub enum Qualifier { /// Hide a media query from legacy UAs: /// @@ -27,7 +27,7 @@ pub enum Qualifier { } /// -#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)] +#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToShmem)] pub struct MediaType(pub CustomIdent); impl MediaType { @@ -58,7 +58,7 @@ impl MediaType { /// A [media query][mq]. /// /// [mq]: https://drafts.csswg.org/mediaqueries/ -#[derive(Clone, Debug, MallocSizeOf, PartialEq)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem)] pub struct MediaQuery { /// The qualifier for this query. pub qualifier: Option, @@ -151,7 +151,7 @@ impl MediaQuery { } /// -#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)] +#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToShmem)] pub enum MediaQueryType { /// A media type that matches every device. All, diff --git a/components/style/parser.rs b/components/style/parser.rs index 6e9d4496cd7..f3190f7f72b 100644 --- a/components/style/parser.rs +++ b/components/style/parser.rs @@ -146,10 +146,23 @@ impl<'a> ParserContext<'a> { error_reporter.report_error(self.url_data, location, error) } + /// Whether we're in a user-agent stylesheet. + #[inline] + pub fn in_ua_sheet(&self) -> bool { + self.stylesheet_origin == Origin::UserAgent + } + /// Returns whether chrome-only rules should be parsed. + #[inline] pub fn chrome_rules_enabled(&self) -> bool { self.url_data.is_chrome() || self.stylesheet_origin == Origin::User } + + /// Whether we're in a user-agent stylesheet or chrome rules are enabled. + #[inline] + pub fn in_ua_or_chrome_sheet(&self) -> bool { + self.in_ua_sheet() || self.chrome_rules_enabled() + } } /// A trait to abstract parsing of a specified value given a `ParserContext` and diff --git a/components/style/properties/cascade.rs b/components/style/properties/cascade.rs index 7d4c8c6275c..1b76aefdd74 100644 --- a/components/style/properties/cascade.rs +++ b/components/style/properties/cascade.rs @@ -683,6 +683,7 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> { #[cfg(feature = "gecko")] fn recompute_default_font_family_type_if_needed(&mut self) { use crate::gecko_bindings::{bindings, structs}; + use crate::values::computed::font::GenericFontFamily; if !self.seen.contains(LonghandId::XLang) && !self.seen.contains(LonghandId::FontFamily) { @@ -697,7 +698,7 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> { // System fonts are all right, and should have the default font type // set to none already, so bail out early. if font.mFont.systemFont { - debug_assert_eq!(font.mFont.fontlist.mDefaultFontType, structs::FontFamilyType::eFamily_none); + debug_assert_eq!(font.mFont.fontlist.mDefaultFontType, GenericFontFamily::None); return; } @@ -717,11 +718,11 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> { !use_document_fonts && matches!( font.mGenericID, - structs::kGenericFont_NONE | - structs::kGenericFont_fantasy | - structs::kGenericFont_cursive + GenericFontFamily::None | + GenericFontFamily::Fantasy | + GenericFontFamily::Cursive ) && - default_font_type != structs::FontFamilyType::eFamily_none; + default_font_type != GenericFontFamily::None; if !prioritize_user_fonts && default_font_type == font.mFont.fontlist.mDefaultFontType { // Nothing to do. diff --git a/components/style/properties/data.py b/components/style/properties/data.py index 52cdcf15d22..407cc5fcdb0 100644 --- a/components/style/properties/data.py +++ b/components/style/properties/data.py @@ -341,6 +341,8 @@ class Longhand(object): "SVGOpacity", "SVGPaintOrder", "ScrollSnapAlign", + "ScrollSnapAxis", + "ScrollSnapStrictness", "ScrollSnapType", "TextAlign", "TextDecorationLine", diff --git a/components/style/properties/declaration_block.rs b/components/style/properties/declaration_block.rs index e4396e764a4..42fc833e4b9 100644 --- a/components/style/properties/declaration_block.rs +++ b/components/style/properties/declaration_block.rs @@ -25,6 +25,8 @@ use style_traits::{CssWriter, ParseError, ParsingMode, StyleParseErrorKind, ToCs use crate::stylesheets::{CssRuleType, Origin, UrlExtraData}; use super::*; use crate::values::computed::Context; +use crate::selector_parser::SelectorImpl; +use selectors::SelectorList; /// The animation rules. /// @@ -88,7 +90,7 @@ impl Importance { /// Overridden declarations are skipped. #[cfg_attr(feature = "gecko", derive(MallocSizeOf))] -#[derive(Clone)] +#[derive(Clone, ToShmem)] pub struct PropertyDeclarationBlock { /// The group of declarations, along with their importance. /// @@ -1211,7 +1213,7 @@ pub fn parse_style_attribute( ); let mut input = ParserInput::new(input); - parse_property_declaration_list(&context, &mut Parser::new(&mut input)) + parse_property_declaration_list(&context, &mut Parser::new(&mut input), None) } /// Parse a given property declaration. Can result in multiple @@ -1248,6 +1250,7 @@ pub fn parse_one_declaration_into( let error = ContextualParseError::UnsupportedPropertyDeclaration( parser.slice_from(start_position), err, + None ); context.log_css_error(location, error); }) @@ -1312,6 +1315,7 @@ impl<'a, 'b, 'i> DeclarationParser<'i> for PropertyDeclarationParser<'a, 'b> { pub fn parse_property_declaration_list( context: &ParserContext, input: &mut Parser, + selectors: Option<&SelectorList> ) -> PropertyDeclarationBlock { let mut declarations = SourcePropertyDeclaration::new(); let mut block = PropertyDeclarationBlock::new(); @@ -1338,7 +1342,7 @@ pub fn parse_property_declaration_list( } let location = error.location; - let error = ContextualParseError::UnsupportedPropertyDeclaration(slice, error); + let error = ContextualParseError::UnsupportedPropertyDeclaration(slice, error, selectors); context.log_css_error(location, error); } } diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 7c5f4a94c01..81e1ee4307d 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -40,8 +40,6 @@ use crate::gecko_bindings::structs::nsCSSPropertyID; use crate::gecko_bindings::structs::mozilla::PseudoStyleType; use crate::gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordData, CoordDataMut}; use crate::gecko_bindings::sugar::refptr::RefPtr; -use crate::gecko::values::convert_nscolor_to_rgba; -use crate::gecko::values::convert_rgba_to_nscolor; use crate::gecko::values::GeckoStyleCoordConvertible; use crate::gecko::values::round_border_to_device_pixels; use crate::logical_geometry::WritingMode; @@ -397,34 +395,6 @@ def set_gecko_property(ffi_name, expr): } -<%def name="impl_color_setter(ident, gecko_ffi_name)"> - #[allow(unreachable_code)] - #[allow(non_snake_case)] - pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) { - ${set_gecko_property(gecko_ffi_name, "v.into()")} - } - - -<%def name="impl_color_copy(ident, gecko_ffi_name)"> - #[allow(non_snake_case)] - pub fn copy_${ident}_from(&mut self, other: &Self) { - let color = ${get_gecko_property(gecko_ffi_name, self_param = "other")}; - ${set_gecko_property(gecko_ffi_name, "color")}; - } - - #[allow(non_snake_case)] - pub fn reset_${ident}(&mut self, other: &Self) { - self.copy_${ident}_from(other) - } - - -<%def name="impl_color_clone(ident, gecko_ffi_name)"> - #[allow(non_snake_case)] - pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T { - ${get_gecko_property(gecko_ffi_name)}.into() - } - - <%def name="impl_keyword(ident, gecko_ffi_name, keyword, cast_type='u8', **kwargs)"> <%call expr="impl_keyword_setter(ident, gecko_ffi_name, keyword, cast_type, **kwargs)"> <%call expr="impl_simple_copy(ident, gecko_ffi_name, **kwargs)"> @@ -449,24 +419,6 @@ def set_gecko_property(ffi_name, expr): } -<%def name="impl_color(ident, gecko_ffi_name)"> -<%call expr="impl_color_setter(ident, gecko_ffi_name)"> -<%call expr="impl_color_copy(ident, gecko_ffi_name)"> -<%call expr="impl_color_clone(ident, gecko_ffi_name)"> - - -<%def name="impl_rgba_color(ident, gecko_ffi_name)"> - #[allow(non_snake_case)] - pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) { - ${set_gecko_property(gecko_ffi_name, "convert_rgba_to_nscolor(&v)")} - } - <%call expr="impl_simple_copy(ident, gecko_ffi_name)"> - #[allow(non_snake_case)] - pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T { - convert_nscolor_to_rgba(${get_gecko_property(gecko_ffi_name)}) - } - - <%def name="impl_svg_length(ident, gecko_ffi_name)"> // When context-value is used on an SVG length, the corresponding flag is // set on mContextFlags, and the length field is set to the initial value. @@ -826,7 +778,7 @@ def set_gecko_property(ffi_name, expr): 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.0.url_value.clone()) + self.gecko.${gecko_ffi_name}.set_move(url.clone_url_value()) } UrlOrNone::None => { unsafe { @@ -1238,18 +1190,7 @@ impl Clone for ${style_struct.gecko_struct_name} { # Types used with predefined_type()-defined properties that we can auto-generate. predefined_types = { - "Color": impl_color, - "ColorOrAuto": impl_color, - "length::LengthOrAuto": impl_style_coord, - "length::LengthOrNormal": impl_style_coord, - "length::NonNegativeLengthOrAuto": impl_style_coord, - "length::NonNegativeLengthPercentageOrNormal": impl_style_coord, - "Length": impl_absolute_length, - "LengthOrNormal": impl_style_coord, - "LengthPercentageOrAuto": impl_style_coord, - "MozListReversed": impl_simple, "MozScriptMinSize": impl_absolute_length, - "RGBAColor": impl_rgba_color, "SVGLength": impl_svg_length, "SVGOpacity": impl_svg_opacity, "SVGPaint": impl_svg_paint, @@ -1379,7 +1320,7 @@ fn static_assert() { self.gecko.mBorderStyle[${side.index}] } - <% impl_color("border_%s_color" % side.ident, "mBorder%sColor" % side.name) %> + <% impl_simple("border_%s_color" % side.ident, "mBorder%sColor" % side.name) %> <% impl_non_negative_length("border_%s_width" % side.ident, "mComputedBorder.%s" % side.ident, @@ -1984,18 +1925,20 @@ fn static_assert() { <% impl_font_settings("font_variation_settings", "gfxFontVariation", "VariationValue", "f32", "f32") %> pub fn set_font_family(&mut self, v: longhands::font_family::computed_value::T) { - use crate::gecko_bindings::structs::FontFamilyType; + use crate::values::computed::font::GenericFontFamily; let is_system_font = v.is_system_font; self.gecko.mFont.systemFont = is_system_font; self.gecko.mGenericID = if is_system_font { - structs::kGenericFont_NONE + GenericFontFamily::None } else { - v.families.single_generic().unwrap_or(structs::kGenericFont_NONE) + v.families.single_generic().unwrap_or(GenericFontFamily::None) }; - self.gecko.mFont.fontlist.mFontlist.mBasePtr.set_move(v.families.0.clone()); + self.gecko.mFont.fontlist.mFontlist.mBasePtr.set_move( + v.families.shared_font_list().clone() + ); // Fixed-up if needed in Cascade::fixup_font_stuff. - self.gecko.mFont.fontlist.mDefaultFontType = FontFamilyType::eFamily_none; + self.gecko.mFont.fontlist.mDefaultFontType = GenericFontFamily::None; } pub fn copy_font_family_from(&mut self, other: &Self) { @@ -2009,36 +1952,16 @@ fn static_assert() { } pub fn clone_font_family(&self) -> longhands::font_family::computed_value::T { - use crate::gecko_bindings::structs::FontFamilyType; use crate::values::computed::font::{FontFamily, SingleFontFamily, FontFamilyList}; let fontlist = &self.gecko.mFont.fontlist; let shared_fontlist = unsafe { fontlist.mFontlist.mBasePtr.to_safe() }; let families = if shared_fontlist.mNames.is_empty() { - let default = fontlist.mDefaultFontType; - let default = match default { - FontFamilyType::eFamily_serif => { - SingleFontFamily::Generic(atom!("serif")) - } - _ => { - // This can break with some combinations of user prefs, see - // bug 1442195 for example. It doesn't really matter in this - // case... - // - // FIXME(emilio): Probably should be storing the whole - // default font name instead though. - debug_assert_eq!( - default, - FontFamilyType::eFamily_sans_serif, - "Default generic should be serif or sans-serif" - ); - SingleFontFamily::Generic(atom!("sans-serif")) - } - }; + let default = SingleFontFamily::Generic(fontlist.mDefaultFontType); FontFamilyList::new(Box::new([default])) } else { - FontFamilyList(shared_fontlist) + FontFamilyList::SharedFontList(shared_fontlist) }; FontFamily { @@ -3781,7 +3704,7 @@ fn static_assert() { }, Url(ref url) => { unsafe { - bindings::Gecko_nsStyleFilter_SetURLValue(gecko_filter, url.0.url_value.get()); + bindings::Gecko_nsStyleFilter_SetURLValue(gecko_filter, url.url_value_ptr()); } }, } @@ -4162,7 +4085,7 @@ fn set_style_svg_path( % if ident == "clip_path": ShapeSource::ImageOrUrl(ref url) => { unsafe { - bindings::Gecko_StyleShapeSource_SetURLValue(${ident}, url.0.url_value.get()) + bindings::Gecko_StyleShapeSource_SetURLValue(${ident}, url.url_value_ptr()) } } % elif ident == "shape_outside": @@ -4404,23 +4327,10 @@ clip-path } -<%self:impl_trait style_struct_name="Color" - skip_longhands="*"> - pub fn set_color(&mut self, v: longhands::color::computed_value::T) { - let result = convert_rgba_to_nscolor(&v); - ${set_gecko_property("mColor", "result")} - } - - <%call expr="impl_simple_copy('color', 'mColor')"> - - pub fn clone_color(&self) -> longhands::color::computed_value::T { - let color = ${get_gecko_property("mColor")} as u32; - convert_nscolor_to_rgba(color) - } +<%self:impl_trait style_struct_name="Color"> -<%self:impl_trait style_struct_name="InheritedUI" - skip_longhands="cursor scrollbar-color"> +<%self:impl_trait style_struct_name="InheritedUI" skip_longhands="cursor"> pub fn set_cursor(&mut self, v: longhands::cursor::computed_value::T) { self.gecko.mCursor = v.keyword; unsafe { @@ -4482,48 +4392,6 @@ clip-path longhands::cursor::computed_value::T { images, keyword } } - - pub fn set_scrollbar_color(&mut self, v: longhands::scrollbar_color::computed_value::T) { - use crate::gecko_bindings::structs::StyleComplexColor; - use crate::values::generics::ui::ScrollbarColor; - match v { - ScrollbarColor::Auto => { - self.gecko.mScrollbarFaceColor = StyleComplexColor::auto(); - self.gecko.mScrollbarTrackColor = StyleComplexColor::auto(); - } - ScrollbarColor::Colors { thumb, track } => { - self.gecko.mScrollbarFaceColor = thumb.into(); - self.gecko.mScrollbarTrackColor = track.into(); - } - } - } - - pub fn copy_scrollbar_color_from(&mut self, other: &Self) { - self.gecko.mScrollbarFaceColor = other.gecko.mScrollbarFaceColor; - self.gecko.mScrollbarTrackColor = other.gecko.mScrollbarTrackColor; - } - - pub fn reset_scrollbar_color(&mut self, other: &Self) { - self.copy_scrollbar_color_from(other); - } - - pub fn clone_scrollbar_color(&self) -> longhands::scrollbar_color::computed_value::T { - use crate::gecko_bindings::structs::StyleComplexColor_Tag as Tag; - use crate::values::generics::ui::ScrollbarColor; - debug_assert!( - (self.gecko.mScrollbarFaceColor.mTag == Tag::eAuto) == - (self.gecko.mScrollbarTrackColor.mTag == Tag::eAuto), - "Whether the two colors are `auto` should match", - ); - if self.gecko.mScrollbarFaceColor.mTag == Tag::eAuto { - ScrollbarColor::Auto - } else { - ScrollbarColor::Colors { - thumb: self.gecko.mScrollbarFaceColor.into(), - track: self.gecko.mScrollbarTrackColor.into(), - } - } - } <%self:impl_trait style_struct_name="Column" diff --git a/components/style/properties/helpers.mako.rs b/components/style/properties/helpers.mako.rs index b48f0afbf00..8310d537f36 100644 --- a/components/style/properties/helpers.mako.rs +++ b/components/style/properties/helpers.mako.rs @@ -105,7 +105,7 @@ #[allow(unused_imports)] use crate::values::{computed, specified}; #[allow(unused_imports)] - use crate::values::{Auto, Either, None_, Normal}; + use crate::values::{Auto, Either, None_}; ${caller.body()} } @@ -128,8 +128,15 @@ % if separator == "Comma": #[css(comma)] % endif - #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, - ToCss)] + #[derive( + Clone, + Debug, + MallocSizeOf, + PartialEq, + ToAnimatedValue, + ToResolvedValue, + ToCss, + )] pub struct List( % if not allow_empty: #[css(iterable)] @@ -205,7 +212,7 @@ % if separator == "Comma": #[css(comma)] % endif - #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)] + #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)] pub struct SpecifiedValue( % if not allow_empty: #[css(iterable)] @@ -285,7 +292,7 @@ #[allow(unused_imports)] use crate::properties::{UnparsedValue, ShorthandId}; #[allow(unused_imports)] - use crate::values::{Auto, Either, None_, Normal}; + use crate::values::{Auto, Either, None_}; #[allow(unused_imports)] use crate::error_reporting::ParseErrorReporter; #[allow(unused_imports)] @@ -425,8 +432,20 @@ pub mod computed_value { #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] - #[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, - PartialEq, SpecifiedValueInfo, ToCss)] + #[derive( + Clone, + Copy, + Debug, + Eq, + Hash, + MallocSizeOf, + Parse, + PartialEq, + SpecifiedValueInfo, + ToCss, + ToResolvedValue, + ToShmem, + )] pub enum T { % for value in keyword.values_for(product): ${to_camel_case(value)}, @@ -437,7 +456,7 @@ } #[cfg_attr(feature = "gecko", derive(MallocSizeOf))] - #[derive(Clone, Copy, Debug, Eq, PartialEq, SpecifiedValueInfo, ToCss)] + #[derive(Clone, Copy, Debug, Eq, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)] pub enum SpecifiedValue { Keyword(computed_value::T), #[css(skip)] @@ -588,8 +607,18 @@ % if extra_specified: #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] - #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, - SpecifiedValueInfo, ToCss)] + #[derive( + Clone, + Copy, + Debug, + Eq, + MallocSizeOf, + Parse, + PartialEq, + SpecifiedValueInfo, + ToCss, + ToShmem, + )] pub enum SpecifiedValue { ${variants(keyword.values_for(product) + extra_specified.split(), bool(extra_specified))} } @@ -598,9 +627,9 @@ % endif pub mod computed_value { #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] - #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToCss)] + #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToCss, ToResolvedValue)] % if not extra_specified: - #[derive(Parse, SpecifiedValueInfo, ToComputedValue)] + #[derive(Parse, SpecifiedValueInfo, ToComputedValue, ToShmem)] % endif pub enum T { ${variants(data.longhands_by_name[name].keyword.values_for(product), not extra_specified)} diff --git a/components/style/properties/longhands/background.mako.rs b/components/style/properties/longhands/background.mako.rs index c6a25be53c1..42344a18cb9 100644 --- a/components/style/properties/longhands/background.mako.rs +++ b/components/style/properties/longhands/background.mako.rs @@ -9,7 +9,7 @@ ${helpers.predefined_type( "background-color", "Color", - "computed_value::T::transparent()", + "computed::Color::transparent()", initial_specified_value="SpecifiedValue::transparent()", spec="https://drafts.csswg.org/css-backgrounds/#background-color", animation_value_type="AnimatedColor", diff --git a/components/style/properties/longhands/box.mako.rs b/components/style/properties/longhands/box.mako.rs index dcfcb343040..397393ed3d8 100644 --- a/components/style/properties/longhands/box.mako.rs +++ b/components/style/properties/longhands/box.mako.rs @@ -427,18 +427,14 @@ ${helpers.predefined_type( animation_value_type="discrete", )} -% for axis in ["x", "y"]: - ${helpers.predefined_type( - "scroll-snap-type-" + axis, - "ScrollSnapType", - "computed::ScrollSnapType::None", - products="gecko", - needs_context=False, - gecko_pref="layout.css.scroll-snap.enabled", - spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-type-x)", - animation_value_type="discrete", - )} -% endfor +${helpers.predefined_type( + "scroll-snap-type", + "ScrollSnapType", + "computed::ScrollSnapType::none()", + products="gecko", + spec="https://drafts.csswg.org/css-scroll-snap-1/#scroll-snap-type", + animation_value_type="discrete", +)} % for axis in ["x", "y"]: ${helpers.predefined_type( diff --git a/components/style/properties/longhands/color.mako.rs b/components/style/properties/longhands/color.mako.rs index 487814935aa..b367f2bbd86 100644 --- a/components/style/properties/longhands/color.mako.rs +++ b/components/style/properties/longhands/color.mako.rs @@ -67,6 +67,7 @@ pub mod system_colors { 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; @@ -75,6 +76,8 @@ pub mod system_colors { // 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(&self, dest: &mut CssWriter) -> fmt::Result where diff --git a/components/style/properties/longhands/font.mako.rs b/components/style/properties/longhands/font.mako.rs index 88369ab9f21..c1d3d8fcc6c 100644 --- a/components/style/properties/longhands/font.mako.rs +++ b/components/style/properties/longhands/font.mako.rs @@ -326,7 +326,7 @@ ${helpers.predefined_type( use app_units::Au; use cssparser::{Parser, ToCss}; - use crate::gecko_bindings::structs::FontFamilyType; + use crate::values::computed::font::GenericFontFamily; use crate::properties::longhands; use std::fmt; use std::hash::{Hash, Hasher}; @@ -346,7 +346,7 @@ ${helpers.predefined_type( font_optical_sizing""".split() %> #[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, - SpecifiedValueInfo, ToCss)] + SpecifiedValueInfo, ToCss, ToShmem)] pub enum SystemFont { % for font in system_fonts: ${to_camel_case(font)}, @@ -406,9 +406,9 @@ ${helpers.predefined_type( let font_style = FontStyle::from_gecko(system.style); let ret = ComputedSystemFont { font_family: FontFamily { - families: FontFamilyList(unsafe { - system.fontlist.mFontlist.mBasePtr.to_safe() - }), + families: FontFamilyList::SharedFontList( + unsafe { system.fontlist.mFontlist.mBasePtr.to_safe() } + ), is_system_font: true, }, font_size: FontSize { @@ -466,7 +466,7 @@ ${helpers.predefined_type( pub ${name}: longhands::${name}::computed_value::T, % endfor pub system_font: SystemFont, - pub default_font_type: FontFamilyType, + pub default_font_type: GenericFontFamily, } impl SystemFont { @@ -495,8 +495,7 @@ ${helpers.predefined_type( // a lot of code with `if product == gecko` conditionals, we have a // dummy system font module that does nothing - #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, SpecifiedValueInfo, ToCss)] - #[cfg_attr(feature = "servo", derive(MallocSizeOf))] + #[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)] /// void enum for system font, can never exist pub enum SystemFont {} impl SystemFont { @@ -521,9 +520,9 @@ ${helpers.single_keyword( ${helpers.predefined_type( "-moz-font-smoothing-background-color", - "RGBAColor", - "RGBA::transparent()", - animation_value_type="AnimatedRGBA", + "color::MozFontSmoothingBackgroundColor", + "computed::color::MozFontSmoothingBackgroundColor::transparent()", + animation_value_type="none", products="gecko", gecko_ffi_name="mFont.fontSmoothingBackgroundColor", enabled_in="chrome", diff --git a/components/style/properties/longhands/inherited_ui.mako.rs b/components/style/properties/longhands/inherited_ui.mako.rs index 94709e1a681..07264372995 100644 --- a/components/style/properties/longhands/inherited_ui.mako.rs +++ b/components/style/properties/longhands/inherited_ui.mako.rs @@ -63,6 +63,7 @@ ${helpers.predefined_type( "generics::color::ColorOrAuto::Auto", spec="https://drafts.csswg.org/css-ui/#caret-color", animation_value_type="AnimatedCaretColor", + boxed=True, ignored_when_colors_disabled=True, products="gecko", )} diff --git a/components/style/properties/longhands/position.mako.rs b/components/style/properties/longhands/position.mako.rs index 725f0862a99..096349f4b1c 100644 --- a/components/style/properties/longhands/position.mako.rs +++ b/components/style/properties/longhands/position.mako.rs @@ -372,7 +372,7 @@ ${helpers.predefined_type( ${helpers.predefined_type( "column-gap", "length::NonNegativeLengthPercentageOrNormal", - "Either::Second(Normal)", + "computed::length::NonNegativeLengthPercentageOrNormal::normal()", alias="grid-column-gap" if product == "gecko" else "", extra_prefixes="moz", servo_pref="layout.columns.enabled", @@ -385,7 +385,7 @@ ${helpers.predefined_type( ${helpers.predefined_type( "row-gap", "length::NonNegativeLengthPercentageOrNormal", - "Either::Second(Normal)", + "computed::length::NonNegativeLengthPercentageOrNormal::normal()", alias="grid-row-gap", products="gecko", spec="https://drafts.csswg.org/css-align-3/#propdef-row-gap", diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index c9bc2bd8e2f..5f44a259641 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -36,9 +36,10 @@ use selectors::parser::SelectorParseErrorKind; #[cfg(feature = "servo")] use servo_config::prefs; use style_traits::{CssWriter, KeywordsCollectFn, ParseError, ParsingMode}; use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss}; +use to_shmem::impl_trivial_to_shmem; use crate::stylesheets::{CssRuleType, Origin, UrlExtraData}; use crate::values::generics::text::LineHeight; -use crate::values::computed; +use crate::values::{computed, resolved}; use crate::values::computed::NonNegativeLength; use crate::values::serialize_atom_name; use crate::rule_tree::StrongRuleNode; @@ -256,6 +257,7 @@ pub mod shorthands { %> /// Servo's representation for a property declaration. +#[derive(ToShmem)] #[repr(u16)] pub enum PropertyDeclaration { % for variant in variants: @@ -741,11 +743,13 @@ static ${name}: LonghandIdSet = LonghandIdSet { /// A set of longhand properties -#[derive(Clone, Debug, Default, MallocSizeOf, PartialEq)] +#[derive(Clone, Copy, Debug, Default, MallocSizeOf, PartialEq)] pub struct LonghandIdSet { storage: [u32; (${len(data.longhands)} - 1 + 32) / 32] } +impl_trivial_to_shmem!(LonghandIdSet); + /// An iterator over a set of longhand ids. pub struct LonghandIdSetIterator<'a> { longhands: &'a LonghandIdSet, @@ -893,7 +897,7 @@ impl LonghandIdSet { /// An enum to represent a CSS Wide keyword. #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, - ToCss)] + ToCss, ToShmem)] pub enum CSSWideKeyword { /// The `initial` keyword. Initial, @@ -993,7 +997,7 @@ pub enum LogicalGroup { } /// An identifier for a given longhand property. -#[derive(Clone, Copy, Eq, Hash, MallocSizeOf, PartialEq)] +#[derive(Clone, Copy, Eq, Hash, MallocSizeOf, PartialEq, ToShmem)] #[repr(u16)] pub enum LonghandId { % for i, property in enumerate(data.longhands): @@ -1266,49 +1270,12 @@ impl LonghandId { LonghandId::FontStyle | LonghandId::FontFamily | - // Needed to resolve currentcolor at computed value time properly. - // - // FIXME(emilio): All the properties should be moved to currentcolor - // as a computed-value (and thus resolving it at used-value time). - // - // This would allow this property to go away from this list. - LonghandId::Color | - - // FIXME(emilio): There's no reason for this afaict, nuke it. - LonghandId::TextDecorationLine | - // Needed to properly compute the writing mode, to resolve logical // properties, and similar stuff. LonghandId::WritingMode | LonghandId::Direction ) } - - /// Whether computed values of this property lossily convert any complex - /// colors into RGBA colors. - /// - /// In Gecko, there are some properties still that compute currentcolor - /// down to an RGBA color at computed value time, instead of as - /// `StyleComplexColor`s. For these properties, we must return `false`, - /// so that we correctly avoid caching style data in the rule tree. - pub fn stores_complex_colors_lossily(&self) -> bool { - % if product == "gecko": - matches!(*self, - % for property in data.longhands: - % if property.predefined_type == "RGBAColor": - LonghandId::${property.camel_case} | - % endif - % endfor - LonghandId::BackgroundImage | - LonghandId::BorderImageSource | - LonghandId::BoxShadow | - LonghandId::MaskImage | - LonghandId::TextShadow - ) - % else: - false - % endif - } } /// An iterator over all the property ids that are enabled for a given @@ -1335,7 +1302,7 @@ where } /// An identifier for a given shorthand property. -#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToShmem)] #[repr(u16)] pub enum ShorthandId { % for i, property in enumerate(data.shorthands): @@ -1533,7 +1500,7 @@ impl ShorthandId { } /// An unparsed property value that contains `var()` functions. -#[derive(Debug, Eq, PartialEq)] +#[derive(Debug, Eq, PartialEq, ToShmem)] pub struct UnparsedValue { /// The css serialization for this value. css: String, @@ -1954,7 +1921,7 @@ impl PropertyId { /// A declaration using a CSS-wide keyword. #[cfg_attr(feature = "gecko", derive(MallocSizeOf))] -#[derive(Clone, PartialEq, ToCss)] +#[derive(Clone, PartialEq, ToCss, ToShmem)] pub struct WideKeywordDeclaration { #[css(skip)] id: LonghandId, @@ -1963,7 +1930,7 @@ pub struct WideKeywordDeclaration { /// An unparsed declaration that contains `var()` functions. #[cfg_attr(feature = "gecko", derive(MallocSizeOf))] -#[derive(Clone, PartialEq, ToCss)] +#[derive(Clone, PartialEq, ToCss, ToShmem)] pub struct VariableDeclaration { #[css(skip)] id: LonghandId, @@ -1973,7 +1940,7 @@ pub struct VariableDeclaration { /// A custom property declaration value is either an unparsed value or a CSS /// wide-keyword. -#[derive(Clone, PartialEq, ToCss)] +#[derive(Clone, PartialEq, ToCss, ToShmem)] pub enum CustomDeclarationValue { /// A value. Value(Arc), @@ -1983,7 +1950,7 @@ pub enum CustomDeclarationValue { /// A custom property declaration with the property name and the declared value. #[cfg_attr(feature = "gecko", derive(MallocSizeOf))] -#[derive(Clone, PartialEq, ToCss)] +#[derive(Clone, PartialEq, ToCss, ToShmem)] pub struct CustomDeclaration { /// The name of the custom property. #[css(skip)] @@ -2845,19 +2812,19 @@ impl ComputedValues { where W: Write, { + use crate::values::resolved::ToResolvedValue; + + let context = resolved::Context { + style: self, + }; + // TODO(emilio): Is it worth to merge branches here just like // PropertyDeclaration::to_css does? - // - // We'd need to get a concept of ~resolved value, which may not be worth - // it. match property_id { % for prop in data.longhands: LonghandId::${prop.camel_case} => { let value = self.clone_${prop.ident}(); - % if prop.predefined_type == "Color": - let value = self.resolve_color(value); - % endif - value.to_css(dest) + value.to_resolved_value(&context).to_css(dest) } % endfor } diff --git a/components/style/properties/shorthands/box.mako.rs b/components/style/properties/shorthands/box.mako.rs index 0acb72b6bb9..5c03dba8529 100644 --- a/components/style/properties/shorthands/box.mako.rs +++ b/components/style/properties/shorthands/box.mako.rs @@ -303,36 +303,6 @@ macro_rules! try_parse_one { } -<%helpers:shorthand name="scroll-snap-type" products="gecko" - gecko_pref="layout.css.scroll-snap.enabled" - sub_properties="scroll-snap-type-x scroll-snap-type-y" - spec="https://drafts.csswg.org/css-scroll-snap/#propdef-scroll-snap-type"> - use crate::properties::longhands::scroll_snap_type_x; - - pub fn parse_value<'i, 't>( - context: &ParserContext, - input: &mut Parser<'i, 't>, - ) -> Result> { - let result = scroll_snap_type_x::parse(context, input)?; - Ok(expanded! { - scroll_snap_type_x: result, - scroll_snap_type_y: result, - }) - } - - impl<'a> ToCss for LonghandsToSerialize<'a> { - // Serializes into the single keyword value if both scroll-snap-type-x and scroll-snap-type-y are same. - // Otherwise into an empty string. This is done to match Gecko's behaviour. - fn to_css(&self, dest: &mut CssWriter) -> fmt::Result where W: fmt::Write { - if self.scroll_snap_type_x == self.scroll_snap_type_y { - self.scroll_snap_type_x.to_css(dest) - } else { - Ok(()) - } - } - } - - ${helpers.two_properties_shorthand( "overscroll-behavior", "overscroll-behavior-x", diff --git a/components/style/rule_tree/mod.rs b/components/style/rule_tree/mod.rs index f165e1f455f..d653b6be99d 100644 --- a/components/style/rule_tree/mod.rs +++ b/components/style/rule_tree/mod.rs @@ -75,8 +75,15 @@ impl Drop for RuleTree { #[cfg(feature = "gecko")] impl MallocSizeOf for RuleTree { fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { - let mut n = unsafe { ops.malloc_size_of(self.root.ptr()) }; - n += self.root.get().size_of(ops); + let mut n = 0; + let mut stack = SmallVec::<[_; 32]>::new(); + stack.push(self.root.downgrade()); + + while let Some(node) = stack.pop() { + n += unsafe { ops.malloc_size_of(node.ptr()) }; + stack.extend(unsafe { (*node.ptr()).iter_children() }); + } + n } } @@ -947,18 +954,6 @@ impl RuleNode { } } -#[cfg(feature = "gecko")] -impl MallocSizeOf for RuleNode { - fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { - let mut n = 0; - for child in self.iter_children() { - n += unsafe { ops.malloc_size_of(child.ptr()) }; - n += unsafe { (*child.ptr()).size_of(ops) }; - } - n - } -} - #[derive(Clone)] struct WeakRuleNode { p: ptr::NonNull, @@ -1239,7 +1234,7 @@ impl StrongRuleNode { use crate::gecko_bindings::structs::NS_AUTHOR_SPECIFIED_BACKGROUND; use crate::gecko_bindings::structs::NS_AUTHOR_SPECIFIED_BORDER; use crate::gecko_bindings::structs::NS_AUTHOR_SPECIFIED_PADDING; - use crate::properties::{CSSWideKeyword, LonghandId, LonghandIdSet}; + use crate::properties::{CSSWideKeyword, LonghandId}; use crate::properties::{PropertyDeclaration, PropertyDeclarationId}; use crate::values::specified::Color; use std::borrow::Cow; diff --git a/components/style/selector_parser.rs b/components/style/selector_parser.rs index 827c6dea284..a8b5c3bc33e 100644 --- a/components/style/selector_parser.rs +++ b/components/style/selector_parser.rs @@ -177,7 +177,7 @@ impl PerPseudoElementMap { /// Values for the :dir() pseudo class /// /// "ltr" and "rtl" values are normalized to lowercase. -#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)] +#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToShmem)] pub struct Direction(pub Atom); /// Horizontal values for the :dir() pseudo class diff --git a/components/style/servo/selector_parser.rs b/components/style/servo/selector_parser.rs index 229f7dccdd2..d839654a65a 100644 --- a/components/style/servo/selector_parser.rs +++ b/components/style/servo/selector_parser.rs @@ -29,8 +29,7 @@ use style_traits::{ParseError, StyleParseErrorKind}; /// A pseudo-element, both public and private. /// /// NB: If you add to this list, be sure to update `each_simple_pseudo_element` too. -#[derive(Clone, Debug, Eq, Hash, PartialEq)] -#[cfg_attr(feature = "servo", derive(MallocSizeOf))] +#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToShmem)] #[allow(missing_docs)] #[repr(usize)] pub enum PseudoElement { @@ -265,8 +264,7 @@ pub type Lang = Box; /// A non tree-structural pseudo-class. /// See https://drafts.csswg.org/selectors-4/#structural-pseudos -#[derive(Clone, Debug, Eq, Hash, PartialEq)] -#[cfg_attr(feature = "servo", derive(MallocSizeOf))] +#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToShmem)] #[allow(missing_docs)] pub enum NonTSPseudoClass { Active, diff --git a/components/style/servo/url.rs b/components/style/servo/url.rs index 26608de2e29..fd7726289be 100644 --- a/components/style/servo/url.rs +++ b/components/style/servo/url.rs @@ -12,7 +12,7 @@ use std::fmt::{self, Write}; // nonzero optimization is important in keeping the size of SpecifiedUrl below // the threshold. use crate::values::computed::{Context, ToComputedValue}; -use std::sync::Arc; +use servo_arc::Arc; use style_traits::{CssWriter, ParseError, ToCss}; /// A CSS url() value for servo. @@ -26,7 +26,7 @@ use style_traits::{CssWriter, ParseError, ToCss}; /// /// TODO(emilio): This should be shrunk by making CssUrl a wrapper type of an /// arc, and keep the serialization in that Arc. See gecko/url.rs for example. -#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize, SpecifiedValueInfo)] +#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize, SpecifiedValueInfo, ToShmem)] pub struct CssUrl { /// The original URI. This might be optional since we may insert computed /// values of images into the cascade directly, and we don't bother to diff --git a/components/style/shared_lock.rs b/components/style/shared_lock.rs index 09bfa163503..073c696fa3d 100644 --- a/components/style/shared_lock.rs +++ b/components/style/shared_lock.rs @@ -15,8 +15,10 @@ use std::cell::UnsafeCell; use std::fmt; #[cfg(feature = "servo")] use std::mem; +use std::mem::ManuallyDrop; #[cfg(feature = "gecko")] use std::ptr; +use to_shmem::{SharedMemoryBuilder, ToShmem}; /// A shared read/write lock that can protect multiple objects. /// @@ -28,6 +30,10 @@ use std::ptr; /// Servo needs the blocking behavior for its unsynchronized animation setup, /// but that may not be web-compatible and may need to be changed (at which /// point Servo could use AtomicRefCell too). +/// +/// Gecko also needs the ability to have "read only" SharedRwLocks, which are +/// used for objects stored in (read only) shared memory. Attempting to acquire +/// write access to objects protected by a read only SharedRwLock will panic. #[derive(Clone)] #[cfg_attr(feature = "servo", derive(MallocSizeOf))] pub struct SharedRwLock { @@ -36,7 +42,7 @@ pub struct SharedRwLock { arc: Arc>, #[cfg(feature = "gecko")] - cell: Arc>, + cell: Option>>, } #[cfg(feature = "gecko")] @@ -61,10 +67,16 @@ impl SharedRwLock { #[cfg(feature = "gecko")] pub fn new() -> Self { SharedRwLock { - cell: Arc::new(AtomicRefCell::new(SomethingZeroSizedButTyped)), + cell: Some(Arc::new(AtomicRefCell::new(SomethingZeroSizedButTyped))), } } + /// Create a new read-only shared lock (gecko). + #[cfg(feature = "gecko")] + pub fn read_only() -> Self { + SharedRwLock { cell: None } + } + /// Wrap the given data to make its access protected by this lock. pub fn wrap(&self, data: T) -> Locked { Locked { @@ -83,7 +95,7 @@ impl SharedRwLock { /// Obtain the lock for reading (gecko). #[cfg(feature = "gecko")] pub fn read(&self) -> SharedRwLockReadGuard { - SharedRwLockReadGuard(self.cell.borrow()) + SharedRwLockReadGuard(self.cell.as_ref().map(|cell| cell.borrow())) } /// Obtain the lock for writing (servo). @@ -96,16 +108,16 @@ impl SharedRwLock { /// Obtain the lock for writing (gecko). #[cfg(feature = "gecko")] pub fn write(&self) -> SharedRwLockWriteGuard { - SharedRwLockWriteGuard(self.cell.borrow_mut()) + SharedRwLockWriteGuard(self.cell.as_ref().unwrap().borrow_mut()) } } /// Proof that a shared lock was obtained for reading (servo). #[cfg(feature = "servo")] pub struct SharedRwLockReadGuard<'a>(&'a SharedRwLock); -/// Proof that a shared lock was obtained for writing (gecko). +/// Proof that a shared lock was obtained for reading (gecko). #[cfg(feature = "gecko")] -pub struct SharedRwLockReadGuard<'a>(AtomicRef<'a, SomethingZeroSizedButTyped>); +pub struct SharedRwLockReadGuard<'a>(Option>); #[cfg(feature = "servo")] impl<'a> Drop for SharedRwLockReadGuard<'a> { fn drop(&mut self) { @@ -149,22 +161,41 @@ impl fmt::Debug for Locked { } impl Locked { + #[cfg(feature = "gecko")] + #[inline] + fn is_read_only_lock(&self) -> bool { + self.shared_lock.cell.is_none() + } + #[cfg(feature = "servo")] fn same_lock_as(&self, lock: &SharedRwLock) -> bool { Arc::ptr_eq(&self.shared_lock.arc, &lock.arc) } #[cfg(feature = "gecko")] - fn same_lock_as(&self, derefed_guard: &SomethingZeroSizedButTyped) -> bool { - ptr::eq(self.shared_lock.cell.as_ptr(), derefed_guard) + fn same_lock_as(&self, derefed_guard: Option<&SomethingZeroSizedButTyped>) -> bool { + ptr::eq( + self.shared_lock + .cell + .as_ref() + .map(|cell| cell.as_ptr()) + .unwrap_or(ptr::null_mut()), + derefed_guard + .map(|guard| guard as *const _ as *mut _) + .unwrap_or(ptr::null_mut()), + ) } /// Access the data for reading. pub fn read_with<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a T { + #[cfg(feature = "gecko")] assert!( - self.same_lock_as(&guard.0), + self.is_read_only_lock() || self.same_lock_as(guard.0.as_ref().map(|r| &**r)), "Locked::read_with called with a guard from an unrelated SharedRwLock" ); + #[cfg(not(feature = "gecko"))] + assert!(self.same_lock_as(&guard.0)); + let ptr = self.data.get(); // Unsafe: @@ -185,10 +216,14 @@ impl Locked { /// Access the data for writing. pub fn write_with<'a>(&'a self, guard: &'a mut SharedRwLockWriteGuard) -> &'a mut T { + #[cfg(feature = "gecko")] assert!( - self.same_lock_as(&guard.0), - "Locked::write_with called with a guard from an unrelated SharedRwLock" + !self.is_read_only_lock() && self.same_lock_as(Some(&guard.0)), + "Locked::write_with called with a guard from a read only or unrelated SharedRwLock" ); + #[cfg(not(feature = "gecko"))] + assert!(self.same_lock_as(&guard.0)); + let ptr = self.data.get(); // Unsafe: @@ -203,6 +238,26 @@ impl Locked { } } +#[cfg(feature = "gecko")] +impl ToShmem for Locked { + fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> ManuallyDrop { + let guard = self.shared_lock.read(); + ManuallyDrop::new(Locked { + shared_lock: SharedRwLock::read_only(), + data: UnsafeCell::new(ManuallyDrop::into_inner( + self.read_with(&guard).to_shmem(builder), + )), + }) + } +} + +#[cfg(feature = "servo")] +impl ToShmem for Locked { + fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> ManuallyDrop { + panic!("ToShmem not supported in Servo currently") + } +} + #[allow(dead_code)] mod compile_time_assert { use super::{SharedRwLockReadGuard, SharedRwLockWriteGuard}; diff --git a/components/style/style_adjuster.rs b/components/style/style_adjuster.rs index 070a2299969..63af60e16ab 100644 --- a/components/style/style_adjuster.rs +++ b/components/style/style_adjuster.rs @@ -723,52 +723,6 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> { } } - /// For HTML elements with 'display:list-item' we add a default 'counter-increment:list-item' - /// unless 'counter-increment' already has a value for 'list-item'. - /// - /// https://drafts.csswg.org/css-lists-3/#declaring-a-list-item - #[cfg(feature = "gecko")] - fn adjust_for_list_item(&mut self, element: Option) - where - E: TElement, - { - use crate::properties::longhands::counter_increment::computed_value::T as ComputedIncrement; - use crate::values::generics::counters::CounterPair; - use crate::values::specified::list::MozListReversed; - use crate::values::CustomIdent; - - if self.style.get_box().clone_display() != Display::ListItem { - return; - } - if self.style.pseudo.is_some() { - return; - } - if !element.map_or(false, |e| e.is_html_element()) { - return; - } - // Note that we map
  • to 'counter-set: list-item INTEGER; - // counter-increment: list-item 0;' so we'll return here unless the author - // explicitly specified something else. - let increments = self.style.get_counters().clone_counter_increment(); - if increments.iter().any(|i| i.name.0 == atom!("list-item")) { - return; - } - - let reversed = self.style.get_list().clone__moz_list_reversed() == MozListReversed::True; - let increment = if reversed { -1 } else { 1 }; - let list_increment = CounterPair { - name: CustomIdent(atom!("list-item")), - value: increment, - }; - let increments = increments - .iter() - .cloned() - .chain(std::iter::once(list_increment)); - self.style - .mutate_counters() - .set_counter_increment(ComputedIncrement::new(increments.collect())); - } - /// Adjusts the style to account for various fixups that don't fit naturally /// into the cascade. /// @@ -833,7 +787,6 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> { #[cfg(feature = "gecko")] { self.adjust_for_appearance(element); - self.adjust_for_list_item(element); } self.set_bits(); } diff --git a/components/style/stylesheet_set.rs b/components/style/stylesheet_set.rs index 35060a959d6..409978c3a9e 100644 --- a/components/style/stylesheet_set.rs +++ b/components/style/stylesheet_set.rs @@ -211,8 +211,6 @@ where type Item = (&'a S, SheetRebuildKind); fn next(&mut self) -> Option { - use std::mem; - loop { let potential_sheet = self.iter.next()?; diff --git a/components/style/stylesheets/document_rule.rs b/components/style/stylesheets/document_rule.rs index c73b96bcd9d..8dd4306c179 100644 --- a/components/style/stylesheets/document_rule.rs +++ b/components/style/stylesheets/document_rule.rs @@ -20,7 +20,7 @@ use servo_arc::Arc; use std::fmt::{self, Write}; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; -#[derive(Debug)] +#[derive(Debug, ToShmem)] /// A @-moz-document rule pub struct DocumentRule { /// The parsed condition @@ -72,7 +72,7 @@ impl DeepCloneWithLock for DocumentRule { } /// The kind of media document that the rule will match. -#[derive(Clone, Copy, Debug, Parse, PartialEq, ToCss)] +#[derive(Clone, Copy, Debug, Parse, PartialEq, ToCss, ToShmem)] #[allow(missing_docs)] pub enum MediaDocumentKind { All, @@ -82,7 +82,7 @@ pub enum MediaDocumentKind { } /// A matching function for a `@document` rule's condition. -#[derive(Clone, Debug, ToCss)] +#[derive(Clone, Debug, ToCss, ToShmem)] pub enum DocumentMatchingFunction { /// Exact URL matching function. It evaluates to true whenever the /// URL of the document being styled is exactly the URL given. @@ -216,7 +216,7 @@ impl DocumentMatchingFunction { /// URL matching functions, and the condition evaluates to true whenever any /// one of those functions evaluates to true. #[css(comma)] -#[derive(Clone, Debug, ToCss)] +#[derive(Clone, Debug, ToCss, ToShmem)] pub struct DocumentCondition(#[css(iterable)] Vec); impl DocumentCondition { diff --git a/components/style/stylesheets/font_feature_values_rule.rs b/components/style/stylesheets/font_feature_values_rule.rs index a93ed43d475..74900f96baf 100644 --- a/components/style/stylesheets/font_feature_values_rule.rs +++ b/components/style/stylesheets/font_feature_values_rule.rs @@ -30,7 +30,7 @@ use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; /// - `SingleValue` is to keep just one unsigned integer value. /// - `PairValues` is to keep one or two unsigned integer values. /// - `VectorValues` is to keep a list of unsigned integer values. -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, ToShmem)] pub struct FFVDeclaration { /// An `` for declaration name. pub name: Atom, @@ -58,7 +58,7 @@ pub trait ToGeckoFontFeatureValues { } /// A @font-feature-values block declaration value that keeps one value. -#[derive(Clone, Debug, PartialEq, ToCss)] +#[derive(Clone, Debug, PartialEq, ToCss, ToShmem)] pub struct SingleValue(pub u32); impl Parse for SingleValue { @@ -87,7 +87,7 @@ impl ToGeckoFontFeatureValues for SingleValue { } /// A @font-feature-values block declaration value that keeps one or two values. -#[derive(Clone, Debug, PartialEq, ToCss)] +#[derive(Clone, Debug, PartialEq, ToCss, ToShmem)] pub struct PairValues(pub u32, pub Option); impl Parse for PairValues { @@ -131,7 +131,7 @@ impl ToGeckoFontFeatureValues for PairValues { } /// A @font-feature-values block declaration value that keeps a list of values. -#[derive(Clone, Debug, PartialEq, ToCss)] +#[derive(Clone, Debug, PartialEq, ToCss, ToShmem)] pub struct VectorValues(#[css(iterable)] pub Vec); impl Parse for VectorValues { @@ -225,7 +225,7 @@ macro_rules! font_feature_values_blocks { /// The [`@font-feature-values`][font-feature-values] at-rule. /// /// [font-feature-values]: https://drafts.csswg.org/css-fonts-3/#at-font-feature-values-rule - #[derive(Clone, Debug, PartialEq)] + #[derive(Clone, Debug, PartialEq, ToShmem)] pub struct FontFeatureValuesRule { /// Font family list for @font-feature-values rule. /// Family names cannot contain generic families. FamilyName diff --git a/components/style/stylesheets/import_rule.rs b/components/style/stylesheets/import_rule.rs index 357f0476281..ca82dcb864b 100644 --- a/components/style/stylesheets/import_rule.rs +++ b/components/style/stylesheets/import_rule.rs @@ -15,7 +15,9 @@ use crate::stylesheets::{CssRule, Origin, StylesheetInDocument}; use crate::values::CssUrl; use cssparser::SourceLocation; use std::fmt::{self, Write}; +use std::mem::ManuallyDrop; use style_traits::{CssWriter, ToCss}; +use to_shmem::{SharedMemoryBuilder, ToShmem}; /// With asynchronous stylesheet parsing, we can't synchronously create a /// GeckoStyleSheet. So we use this placeholder instead. @@ -180,6 +182,12 @@ pub struct ImportRule { pub source_location: SourceLocation, } +impl ToShmem for ImportRule { + fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> ManuallyDrop { + panic!("ToShmem failed for ImportRule: cannot handle imported style sheets") + } +} + impl DeepCloneWithLock for ImportRule { fn deep_clone_with_lock( &self, diff --git a/components/style/stylesheets/keyframes_rule.rs b/components/style/stylesheets/keyframes_rule.rs index 662bc9ae481..9efd7f39ccc 100644 --- a/components/style/stylesheets/keyframes_rule.rs +++ b/components/style/stylesheets/keyframes_rule.rs @@ -26,7 +26,7 @@ use style_traits::{CssWriter, ParseError, ParsingMode, StyleParseErrorKind, ToCs /// A [`@keyframes`][keyframes] rule. /// /// [keyframes]: https://drafts.csswg.org/css-animations/#keyframes -#[derive(Debug)] +#[derive(Debug, ToShmem)] pub struct KeyframesRule { /// The name of the current animation. pub name: KeyframesName, @@ -99,7 +99,7 @@ impl DeepCloneWithLock for KeyframesRule { /// A number from 0 to 1, indicating the percentage of the animation when this /// keyframe should run. -#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd)] +#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd, ToShmem)] pub struct KeyframePercentage(pub f32); impl ::std::cmp::Ord for KeyframePercentage { @@ -150,7 +150,7 @@ impl KeyframePercentage { /// A keyframes selector is a list of percentages or from/to symbols, which are /// converted at parse time to percentages. #[css(comma)] -#[derive(Clone, Debug, Eq, PartialEq, ToCss)] +#[derive(Clone, Debug, Eq, PartialEq, ToCss, ToShmem)] pub struct KeyframeSelector(#[css(iterable)] Vec); impl KeyframeSelector { @@ -174,7 +174,7 @@ impl KeyframeSelector { } /// A keyframe. -#[derive(Debug)] +#[derive(Debug, ToShmem)] pub struct Keyframe { /// The selector this keyframe was specified from. pub selector: KeyframeSelector, diff --git a/components/style/stylesheets/media_rule.rs b/components/style/stylesheets/media_rule.rs index 4266b4c2c10..ea7441a5c09 100644 --- a/components/style/stylesheets/media_rule.rs +++ b/components/style/stylesheets/media_rule.rs @@ -21,7 +21,7 @@ use style_traits::{CssWriter, ToCss}; /// An [`@media`][media] urle. /// /// [media]: https://drafts.csswg.org/css-conditional/#at-ruledef-media -#[derive(Debug)] +#[derive(Debug, ToShmem)] pub struct MediaRule { /// The list of media queries used by this media rule. pub media_queries: Arc>, diff --git a/components/style/stylesheets/mod.rs b/components/style/stylesheets/mod.rs index 58922187db2..16842021e8d 100644 --- a/components/style/stylesheets/mod.rs +++ b/components/style/stylesheets/mod.rs @@ -23,6 +23,10 @@ mod stylesheet; pub mod supports_rule; pub mod viewport_rule; +#[cfg(feature = "gecko")] +use crate::gecko_bindings::sugar::refptr::RefCounted; +#[cfg(feature = "gecko")] +use crate::gecko_bindings::{bindings, structs}; use crate::parser::ParserContext; use crate::shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked}; use crate::shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard}; @@ -32,7 +36,11 @@ use cssparser::{parse_one_rule, Parser, ParserInput}; use malloc_size_of::{MallocSizeOfOps, MallocUnconditionalShallowSizeOf}; use servo_arc::Arc; use std::fmt; +#[cfg(feature = "gecko")] +use std::mem::{self, ManuallyDrop}; use style_traits::ParsingMode; +#[cfg(feature = "gecko")] +use to_shmem::{SharedMemoryBuilder, ToShmem}; pub use self::counter_style_rule::CounterStyleRule; pub use self::document_rule::DocumentRule; @@ -60,18 +68,76 @@ pub use self::viewport_rule::ViewportRule; pub type UrlExtraData = ::servo_url::ServoUrl; /// Extra data that the backend may need to resolve url values. +/// +/// If the usize's lowest bit is 0, then this is a strong reference to a +/// structs::URLExtraData object. +/// +/// Otherwise, shifting the usize's bits the right by one gives the +/// UserAgentStyleSheetID value corresponding to the style sheet whose +/// URLExtraData this is, which is stored in URLExtraData_sShared. We don't +/// hold a strong reference to that object from here, but we rely on that +/// array's objects being held alive until shutdown. +/// +/// We use this packed representation rather than an enum so that +/// `from_ptr_ref` can work. #[cfg(feature = "gecko")] -#[derive(Clone, PartialEq)] -pub struct UrlExtraData( - pub crate::gecko_bindings::sugar::refptr::RefPtr, -); +#[derive(PartialEq)] +pub struct UrlExtraData(usize); + +#[cfg(feature = "gecko")] +impl Clone for UrlExtraData { + fn clone(&self) -> UrlExtraData { + UrlExtraData::new(self.ptr()) + } +} + +#[cfg(feature = "gecko")] +impl Drop for UrlExtraData { + fn drop(&mut self) { + // No need to release when we have an index into URLExtraData_sShared. + if self.0 & 1 == 0 { + unsafe { + self.as_ref().release(); + } + } + } +} + +#[cfg(feature = "gecko")] +impl ToShmem for UrlExtraData { + fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> ManuallyDrop { + if self.0 & 1 == 0 { + let shared_extra_datas = unsafe { &structs::URLExtraData_sShared }; + let self_ptr = self.as_ref() as *const _ as *mut _; + let sheet_id = shared_extra_datas + .iter() + .position(|r| r.mRawPtr == self_ptr) + .expect( + "ToShmem failed for UrlExtraData: expected sheet's URLExtraData to be in \ + URLExtraData::sShared", + ); + ManuallyDrop::new(UrlExtraData((sheet_id << 1) | 1)) + } else { + ManuallyDrop::new(UrlExtraData(self.0)) + } + } +} #[cfg(feature = "gecko")] impl UrlExtraData { + /// Create a new UrlExtraData wrapping a pointer to the specified Gecko + /// URLExtraData object. + pub fn new(ptr: *mut structs::URLExtraData) -> UrlExtraData { + unsafe { + (*ptr).addref(); + } + UrlExtraData(ptr as usize) + } + /// True if this URL scheme is chrome. #[inline] pub fn is_chrome(&self) -> bool { - self.0.mIsChrome + self.as_ref().mIsChrome } /// Create a reference to this `UrlExtraData` from a reference to pointer. @@ -80,16 +146,30 @@ impl UrlExtraData { /// /// This method doesn't touch refcount. #[inline] - pub unsafe fn from_ptr_ref(ptr: &*mut crate::gecko_bindings::structs::URLExtraData) -> &Self { - ::std::mem::transmute(ptr) + pub unsafe fn from_ptr_ref(ptr: &*mut structs::URLExtraData) -> &Self { + mem::transmute(ptr) + } + + /// Returns a pointer to the Gecko URLExtraData object. + pub fn ptr(&self) -> *mut structs::URLExtraData { + if self.0 & 1 == 0 { + self.0 as *mut structs::URLExtraData + } else { + unsafe { + let sheet_id = self.0 >> 1; + structs::URLExtraData_sShared[sheet_id].mRawPtr + } + } + } + + fn as_ref(&self) -> &structs::URLExtraData { + unsafe { &*(self.ptr() as *const structs::URLExtraData) } } } #[cfg(feature = "gecko")] impl fmt::Debug for UrlExtraData { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - use crate::gecko_bindings::{bindings, structs}; - struct DebugURI(*mut structs::nsIURI); impl fmt::Debug for DebugURI { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { @@ -105,10 +185,13 @@ impl fmt::Debug for UrlExtraData { formatter .debug_struct("URLExtraData") .field("is_chrome", &self.is_chrome()) - .field("base", &DebugURI(self.0.mBaseURI.raw::())) + .field( + "base", + &DebugURI(self.as_ref().mBaseURI.raw::()), + ) .field( "referrer", - &DebugURI(self.0.mReferrer.raw::()), + &DebugURI(self.as_ref().mReferrer.raw::()), ) .finish() } @@ -122,7 +205,7 @@ impl Eq for UrlExtraData {} /// A CSS rule. /// /// TODO(emilio): Lots of spec links should be around. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, ToShmem)] #[allow(missing_docs)] pub enum CssRule { // No Charset here, CSSCharsetRule has been removed from CSSOM diff --git a/components/style/stylesheets/namespace_rule.rs b/components/style/stylesheets/namespace_rule.rs index ea20cfe1a05..81a92f1c300 100644 --- a/components/style/stylesheets/namespace_rule.rs +++ b/components/style/stylesheets/namespace_rule.rs @@ -11,7 +11,7 @@ use cssparser::SourceLocation; use std::fmt::{self, Write}; /// A `@namespace` rule. -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, ToShmem)] #[allow(missing_docs)] pub struct NamespaceRule { /// The namespace prefix, and `None` if it's the default Namespace diff --git a/components/style/stylesheets/origin.rs b/components/style/stylesheets/origin.rs index fc89260abd2..783b8f26a8b 100644 --- a/components/style/stylesheets/origin.rs +++ b/components/style/stylesheets/origin.rs @@ -10,7 +10,7 @@ use std::ops::BitOrAssign; /// Each style rule has an origin, which determines where it enters the cascade. /// /// -#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, ToShmem)] #[repr(u8)] #[cfg_attr(feature = "servo", derive(MallocSizeOf))] pub enum Origin { diff --git a/components/style/stylesheets/page_rule.rs b/components/style/stylesheets/page_rule.rs index ccb689c1699..3edf562258f 100644 --- a/components/style/stylesheets/page_rule.rs +++ b/components/style/stylesheets/page_rule.rs @@ -25,7 +25,7 @@ use std::fmt::{self, Write}; /// /// [page]: https://drafts.csswg.org/css2/page.html#page-box /// [page-selectors]: https://drafts.csswg.org/css2/page.html#page-selectors -#[derive(Debug)] +#[derive(Debug, ToShmem)] pub struct PageRule { /// The declaration block this page rule contains. pub block: Arc>, diff --git a/components/style/stylesheets/rule_list.rs b/components/style/stylesheets/rule_list.rs index c4bf0007bb6..ee2b5347c1e 100644 --- a/components/style/stylesheets/rule_list.rs +++ b/components/style/stylesheets/rule_list.rs @@ -17,7 +17,7 @@ use servo_arc::{Arc, RawOffsetArc}; use std::fmt::{self, Write}; /// A list of CSS rules. -#[derive(Debug)] +#[derive(Debug, ToShmem)] pub struct CssRules(pub Vec); impl CssRules { diff --git a/components/style/stylesheets/rule_parser.rs b/components/style/stylesheets/rule_parser.rs index a780ebce250..a3ec24174ed 100644 --- a/components/style/stylesheets/rule_parser.rs +++ b/components/style/stylesheets/rule_parser.rs @@ -133,7 +133,7 @@ pub enum State { Body = 4, } -#[derive(Clone, Debug, MallocSizeOf)] +#[derive(Clone, Debug, MallocSizeOf, ToShmem)] /// Vendor prefix. pub enum VendorPrefix { /// -moz prefix. @@ -548,7 +548,7 @@ impl<'a, 'b, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'b> { self.namespaces, ); - let declarations = parse_property_declaration_list(&context, input); + let declarations = parse_property_declaration_list(&context, input, None); Ok(CssRule::Page(Arc::new(self.shared_lock.wrap(PageRule { block: Arc::new(self.shared_lock.wrap(declarations)), source_location, @@ -596,7 +596,7 @@ impl<'a, 'b, 'i> QualifiedRuleParser<'i> for NestedRuleParser<'a, 'b> { let context = ParserContext::new_with_rule_type(self.context, CssRuleType::Style, self.namespaces); - let declarations = parse_property_declaration_list(&context, input); + let declarations = parse_property_declaration_list(&context, input, Some(&selectors)); let block = Arc::new(self.shared_lock.wrap(declarations)); Ok(CssRule::Style(Arc::new(self.shared_lock.wrap(StyleRule { selectors, diff --git a/components/style/stylesheets/style_rule.rs b/components/style/stylesheets/style_rule.rs index f762d154ad8..905e067f730 100644 --- a/components/style/stylesheets/style_rule.rs +++ b/components/style/stylesheets/style_rule.rs @@ -19,7 +19,7 @@ use servo_arc::Arc; use std::fmt::{self, Write}; /// A style rule, with selectors and declarations. -#[derive(Debug)] +#[derive(Debug, ToShmem)] pub struct StyleRule { /// The list of selectors in this rule. pub selectors: SelectorList, diff --git a/components/style/stylesheets/stylesheet.rs b/components/style/stylesheets/stylesheet.rs index 77fa008612d..5b8c8753248 100644 --- a/components/style/stylesheets/stylesheet.rs +++ b/components/style/stylesheets/stylesheet.rs @@ -107,6 +107,34 @@ impl StylesheetContents { } } + /// Creates a new StylesheetContents with the specified pre-parsed rules, + /// origin, URL data, and quirks mode. + /// + /// Since the rules have already been parsed, and the intention is that + /// this function is used for read only User Agent style sheets, an empty + /// namespace map is used, and the source map and source URLs are set to + /// None. + /// + /// An empty namespace map should be fine, as it is only used for parsing, + /// not serialization of existing selectors. Since UA sheets are read only, + /// we should never need the namespace map. + pub fn from_shared_data( + rules: Arc>, + origin: Origin, + url_data: UrlExtraData, + quirks_mode: QuirksMode, + ) -> Self { + Self { + rules, + origin, + url_data: RwLock::new(url_data), + namespaces: RwLock::new(Namespaces::default()), + quirks_mode, + source_map_url: RwLock::new(None), + source_url: RwLock::new(None), + } + } + /// Returns a reference to the list of rules. #[inline] pub fn rules<'a, 'b: 'a>(&'a self, guard: &'b SharedRwLockReadGuard) -> &'a [CssRule] { diff --git a/components/style/stylesheets/supports_rule.rs b/components/style/stylesheets/supports_rule.rs index 45f6f97812d..a22acad1aa0 100644 --- a/components/style/stylesheets/supports_rule.rs +++ b/components/style/stylesheets/supports_rule.rs @@ -26,7 +26,7 @@ use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; /// An [`@supports`][supports] rule. /// /// [supports]: https://drafts.csswg.org/css-conditional-3/#at-supports -#[derive(Debug)] +#[derive(Debug, ToShmem)] pub struct SupportsRule { /// The parsed condition pub condition: SupportsCondition, @@ -76,7 +76,7 @@ impl DeepCloneWithLock for SupportsRule { /// An @supports condition /// /// -#[derive(Clone, Debug)] +#[derive(Clone, Debug, ToShmem)] pub enum SupportsCondition { /// `not (condition)` Not(Box), @@ -223,8 +223,7 @@ impl SupportsCondition { #[cfg(feature = "gecko")] fn eval_moz_bool_pref(name: &CStr, cx: &ParserContext) -> bool { use crate::gecko_bindings::bindings; - use crate::stylesheets::Origin; - if cx.stylesheet_origin != Origin::UserAgent && !cx.chrome_rules_enabled() { + if !cx.in_ua_or_chrome_sheet() { return false; } unsafe { bindings::Gecko_GetBoolPrefValue(name.as_ptr()) } @@ -306,7 +305,7 @@ impl ToCss for SupportsCondition { } } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, ToShmem)] /// A possibly-invalid CSS selector. pub struct RawSelector(pub String); @@ -368,7 +367,7 @@ impl RawSelector { } } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, ToShmem)] /// A possibly-invalid property declaration pub struct Declaration(pub String); diff --git a/components/style/stylesheets/viewport_rule.rs b/components/style/stylesheets/viewport_rule.rs index 02be35261db..e845930bfbd 100644 --- a/components/style/stylesheets/viewport_rule.rs +++ b/components/style/stylesheets/viewport_rule.rs @@ -80,7 +80,7 @@ macro_rules! declare_viewport_descriptor_inner { [ ] $number_of_variants: expr ) => { - #[derive(Clone, Debug, PartialEq)] + #[derive(Clone, Debug, PartialEq, ToShmem)] #[cfg_attr(feature = "servo", derive(MallocSizeOf))] #[allow(missing_docs)] pub enum ViewportDescriptor { @@ -147,7 +147,7 @@ trait FromMeta: Sized { /// * http://dev.w3.org/csswg/css-device-adapt/#extend-to-zoom #[allow(missing_docs)] #[cfg_attr(feature = "servo", derive(MallocSizeOf))] -#[derive(Clone, Debug, PartialEq, ToCss)] +#[derive(Clone, Debug, PartialEq, ToCss, ToShmem)] pub enum ViewportLength { Specified(NonNegativeLengthPercentageOrAuto), ExtendToZoom, @@ -225,7 +225,7 @@ struct ViewportRuleParser<'a, 'b: 'a> { context: &'a ParserContext<'b>, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, ToShmem)] #[cfg_attr(feature = "servo", derive(MallocSizeOf))] #[allow(missing_docs)] pub struct ViewportDescriptorDeclaration { @@ -335,7 +335,7 @@ impl<'a, 'b, 'i> DeclarationParser<'i> for ViewportRuleParser<'a, 'b> { } /// A `@viewport` rule. -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, ToShmem)] #[cfg_attr(feature = "servo", derive(MallocSizeOf))] pub struct ViewportRule { /// The declarations contained in this @viewport rule. diff --git a/components/style/stylist.rs b/components/style/stylist.rs index 982440004ec..ece14e9896f 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -129,6 +129,9 @@ impl UserAgentCascadeDataCache { } fn expire_unused(&mut self) { + // is_unique() returns false for static references, but we never have + // static references to UserAgentCascadeDatas. If we did, it may not + // make sense to put them in the cache in the first place. self.entries.retain(|e| !e.is_unique()) } diff --git a/components/style/traversal.rs b/components/style/traversal.rs index d5a9a5c5033..8bc57ada8b7 100644 --- a/components/style/traversal.rs +++ b/components/style/traversal.rs @@ -307,8 +307,6 @@ pub fn resolve_style( where E: TElement, { - use crate::style_resolver::StyleResolverForElement; - debug_assert!( rule_inclusion == RuleInclusion::DefaultOnly || pseudo.map_or(false, |p| p.is_before_or_after()) || @@ -406,7 +404,6 @@ pub fn recalc_style_at( D: DomTraversal, F: FnMut(E::ConcreteNode), { - use crate::traversal_flags::TraversalFlags; use std::cmp; let flags = context.shared.traversal_flags; @@ -538,12 +535,6 @@ pub fn recalc_style_at( debug_assert!(!element.has_animation_only_dirty_descendants()); } - debug_assert!( - flags.for_animation_only() || - !flags.contains(TraversalFlags::ClearDirtyBits) || - !element.has_animation_only_dirty_descendants(), - "Should have cleared animation bits already" - ); clear_state_after_traversing(element, data, flags); } @@ -551,27 +542,11 @@ fn clear_state_after_traversing(element: E, data: &mut ElementData, flags: Tr where E: TElement, { - // If we are in a forgetful traversal, drop the existing restyle - // data here, since we won't need to perform a post-traversal to pick up - // any change hints. - if flags.contains(TraversalFlags::Forgetful) { + if flags.intersects(TraversalFlags::FinalAnimationTraversal) { + debug_assert!(flags.for_animation_only()); data.clear_restyle_flags_and_damage(); - } - - // Clear dirty bits as appropriate. - if flags.for_animation_only() { - if flags.intersects( - TraversalFlags::ClearDirtyBits | TraversalFlags::ClearAnimationOnlyDirtyDescendants, - ) { - unsafe { - element.unset_animation_only_dirty_descendants(); - } - } - } else if flags.contains(TraversalFlags::ClearDirtyBits) { - // The animation traversal happens first, so we don't need to guard against - // clearing the animation bit on the regular traversal. unsafe { - element.clear_dirty_bits(); + element.unset_animation_only_dirty_descendants(); } } } diff --git a/components/style/traversal_flags.rs b/components/style/traversal_flags.rs index a9a2acbf555..0987230ed02 100644 --- a/components/style/traversal_flags.rs +++ b/components/style/traversal_flags.rs @@ -16,15 +16,9 @@ bitflags! { /// Traverse and update all elements with CSS animations since /// @keyframes rules may have changed. Triggered by CSS rule changes. const ForCSSRuleChanges = 1 << 1; - /// A forgetful traversal ignores the previous state of the frame tree, and - /// thus does not compute damage or maintain other state describing the styles - /// pre-traversal. A forgetful traversal is usually the right thing if you - /// aren't going to do a post-traversal. - const Forgetful = 1 << 3; - /// Clears all the dirty bits on the elements traversed. - const ClearDirtyBits = 1 << 5; - /// Clears the animation-only dirty descendants bit in the subtree. - const ClearAnimationOnlyDirtyDescendants = 1 << 6; + /// The final animation-only traversal, which shouldn't really care about other + /// style changes anymore. + const FinalAnimationTraversal = 1 << 2; /// Allows the traversal to run in parallel if there are sufficient cores on /// the machine. const ParallelTraversal = 1 << 7; @@ -58,10 +52,7 @@ pub fn assert_traversal_flags_match() { check_traversal_flags! { ServoTraversalFlags_AnimationOnly => TraversalFlags::AnimationOnly, ServoTraversalFlags_ForCSSRuleChanges => TraversalFlags::ForCSSRuleChanges, - ServoTraversalFlags_Forgetful => TraversalFlags::Forgetful, - ServoTraversalFlags_ClearDirtyBits => TraversalFlags::ClearDirtyBits, - ServoTraversalFlags_ClearAnimationOnlyDirtyDescendants => - TraversalFlags::ClearAnimationOnlyDirtyDescendants, + ServoTraversalFlags_FinalAnimationTraversal => TraversalFlags::FinalAnimationTraversal, ServoTraversalFlags_ParallelTraversal => TraversalFlags::ParallelTraversal, ServoTraversalFlags_FlushThrottledAnimations => TraversalFlags::FlushThrottledAnimations, } diff --git a/components/style/values/animated/color.rs b/components/style/values/animated/color.rs index c8d5213b49b..14b1d0c539c 100644 --- a/components/style/values/animated/color.rs +++ b/components/style/values/animated/color.rs @@ -100,8 +100,8 @@ impl Color { fn effective_intermediate_rgba(&self) -> RGBA { match *self { GenericColor::Numeric(color) => color, - GenericColor::Foreground => RGBA::transparent(), - GenericColor::Complex(color, ratios) => RGBA { + GenericColor::CurrentColor => RGBA::transparent(), + GenericColor::Complex { color, ratios } => RGBA { alpha: color.alpha * ratios.bg, ..color.clone() }, @@ -111,8 +111,8 @@ impl Color { fn effective_ratios(&self) -> ComplexColorRatios { match *self { GenericColor::Numeric(..) => ComplexColorRatios::NUMERIC, - GenericColor::Foreground => ComplexColorRatios::FOREGROUND, - GenericColor::Complex(.., ratios) => ratios, + GenericColor::CurrentColor => ComplexColorRatios::CURRENT_COLOR, + GenericColor::Complex { ratios, .. } => ratios, } } } @@ -128,18 +128,18 @@ impl Animate for Color { Ok(match (*self, *other, procedure) { // Any interpolation of currentcolor with currentcolor returns currentcolor. - (Foreground, Foreground, Procedure::Interpolate { .. }) => Foreground, + (CurrentColor, CurrentColor, Procedure::Interpolate { .. }) => CurrentColor, // Animating two numeric colors. (Numeric(c1), Numeric(c2), _) => Numeric(c1.animate(&c2, procedure)?), // Combinations of numeric color and currentcolor - (Foreground, Numeric(color), _) => Self::with_ratios( + (CurrentColor, Numeric(color), _) => Self::with_ratios( color, ComplexColorRatios { bg: other_weight as f32, fg: this_weight as f32, }, ), - (Numeric(color), Foreground, _) => Self::with_ratios( + (Numeric(color), CurrentColor, _) => Self::with_ratios( color, ComplexColorRatios { bg: this_weight as f32, @@ -148,7 +148,7 @@ impl Animate for Color { ), // Any other animation of currentcolor with currentcolor. - (Foreground, Foreground, _) => Self::with_ratios( + (CurrentColor, CurrentColor, _) => Self::with_ratios( RGBA::transparent(), ComplexColorRatios { bg: 0., @@ -162,8 +162,8 @@ impl Animate for Color { fn scaled_rgba(color: &Color) -> RGBA { match *color { GenericColor::Numeric(color) => color, - GenericColor::Foreground => RGBA::transparent(), - GenericColor::Complex(color, ratios) => RGBA { + GenericColor::CurrentColor => RGBA::transparent(), + GenericColor::Complex { color, ratios } => RGBA { red: color.red * ratios.bg, green: color.green * ratios.bg, blue: color.blue * ratios.bg, @@ -236,9 +236,9 @@ impl ComputeSquaredDistance for Color { // All comments from the Animate impl also applies here. Ok(match (*self, *other) { - (Foreground, Foreground) => SquaredDistance::from_sqrt(0.), + (CurrentColor, CurrentColor) => SquaredDistance::from_sqrt(0.), (Numeric(c1), Numeric(c2)) => c1.compute_squared_distance(&c2)?, - (Foreground, Numeric(color)) | (Numeric(color), Foreground) => { + (CurrentColor, Numeric(color)) | (Numeric(color), CurrentColor) => { // `computed_squared_distance` is symmetric. color.compute_squared_distance(&RGBA::transparent())? + SquaredDistance::from_sqrt(1.) diff --git a/components/style/values/computed/align.rs b/components/style/values/computed/align.rs index 739b70c765a..ea6088db5d5 100644 --- a/components/style/values/computed/align.rs +++ b/components/style/values/computed/align.rs @@ -33,7 +33,7 @@ pub use super::specified::{AlignSelf, JustifySelf}; /// sucks :(. /// /// See the discussion in https://bugzil.la/1384542. -#[derive(Clone, Copy, Debug, Eq, PartialEq, ToCss)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, ToCss, ToResolvedValue)] pub struct JustifyItems { /// The specified value for the property. Can contain the bare `legacy` /// keyword. diff --git a/components/style/values/computed/angle.rs b/components/style/values/computed/angle.rs index 76e44575dfb..cdbc0006941 100644 --- a/components/style/values/computed/angle.rs +++ b/components/style/values/computed/angle.rs @@ -14,7 +14,18 @@ use style_traits::{CssWriter, ToCss}; /// A computed angle in degrees. #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] -#[derive(Add, Animate, Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd, ToAnimatedZero)] +#[derive( + Add, + Animate, + Clone, + Copy, + Debug, + MallocSizeOf, + PartialEq, + PartialOrd, + ToAnimatedZero, + ToResolvedValue, +)] pub struct Angle(CSSFloat); impl ToCss for Angle { diff --git a/components/style/values/computed/box.rs b/components/style/values/computed/box.rs index decba9f342f..4cd16b1cd9e 100644 --- a/components/style/values/computed/box.rs +++ b/components/style/values/computed/box.rs @@ -14,8 +14,10 @@ use crate::values::specified::box_ as specified; pub use crate::values::specified::box_::{AnimationName, Appearance, BreakBetween, BreakWithin}; pub use crate::values::specified::box_::{Clear as SpecifiedClear, Float as SpecifiedFloat}; pub use crate::values::specified::box_::{Contain, Display, Overflow}; -pub use crate::values::specified::box_::{OverflowAnchor, OverflowClipBox}; -pub use crate::values::specified::box_::{OverscrollBehavior, ScrollSnapAlign, ScrollSnapType}; +pub use crate::values::specified::box_::{OverflowAnchor, OverflowClipBox, OverscrollBehavior}; +pub use crate::values::specified::box_::{ + ScrollSnapAlign, ScrollSnapAxis, ScrollSnapStrictness, ScrollSnapType, +}; pub use crate::values::specified::box_::{TouchAction, TransitionProperty, WillChange}; /// A computed value for the `vertical-align` property. @@ -49,6 +51,7 @@ pub type Perspective = GenericPerspective; PartialEq, SpecifiedValueInfo, ToCss, + ToResolvedValue, )] #[repr(u8)] /// A computed value for the `float` property. @@ -118,6 +121,7 @@ impl ToComputedValue for SpecifiedFloat { PartialEq, SpecifiedValueInfo, ToCss, + ToResolvedValue, )] /// A computed value for the `clear` property. pub enum Clear { @@ -178,7 +182,7 @@ impl ToComputedValue for SpecifiedClear { /// A computed value for the `resize` property. #[allow(missing_docs)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] -#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, ToCss)] +#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, ToCss, ToResolvedValue)] #[repr(u8)] pub enum Resize { None, diff --git a/components/style/values/computed/color.rs b/components/style/values/computed/color.rs index 6795b399888..6098ea4590e 100644 --- a/components/style/values/computed/color.rs +++ b/components/style/values/computed/color.rs @@ -11,14 +11,14 @@ use cssparser::{Color as CSSParserColor, RGBA}; use std::fmt; use style_traits::{CssWriter, ToCss}; -/// Computed value type for the specified RGBAColor. -pub type RGBAColor = RGBA; - /// The computed value of the `color` property. pub type ColorPropertyValue = RGBA; +/// The computed value of `-moz-font-smoothing-background-color`. +pub type MozFontSmoothingBackgroundColor = RGBA; + /// A computed value for ``. -pub type Color = GenericColor; +pub type Color = GenericColor; impl Color { /// Returns a complex color value representing transparent. @@ -33,8 +33,8 @@ impl Color { // Common cases that the complex color is either pure numeric // color or pure currentcolor. GenericColor::Numeric(color) => return color, - GenericColor::Foreground => return fg_color, - GenericColor::Complex(color, ratios) => (color, ratios), + GenericColor::CurrentColor => return fg_color, + GenericColor::Complex { color, ratios } => (color, ratios), }; // For the more complicated case that the alpha value differs, @@ -76,7 +76,7 @@ impl ToCss for Color { { match *self { GenericColor::Numeric(color) => color.to_css(dest), - GenericColor::Foreground => CSSParserColor::CurrentColor.to_css(dest), + GenericColor::CurrentColor => CSSParserColor::CurrentColor.to_css(dest), _ => Ok(()), } } diff --git a/components/style/values/computed/font.rs b/components/style/values/computed/font.rs index c78eb9df2e3..407a547013f 100644 --- a/components/style/values/computed/font.rs +++ b/components/style/values/computed/font.rs @@ -24,9 +24,13 @@ use cssparser::{serialize_identifier, CssStringWriter, Parser}; use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use std::fmt::{self, Write}; use std::hash::{Hash, Hasher}; +#[cfg(feature = "gecko")] +use std::mem::{self, ManuallyDrop}; #[cfg(feature = "servo")] use std::slice; use style_traits::{CssWriter, ParseError, ToCss}; +#[cfg(feature = "gecko")] +use to_shmem::{SharedMemoryBuilder, ToShmem}; pub use crate::values::computed::Length as MozScriptMinSize; pub use crate::values::specified::font::{FontSynthesis, MozScriptSizeMultiplier}; @@ -37,7 +41,9 @@ pub use crate::values::specified::font::{XLang, XTextZoom}; /// https://drafts.csswg.org/css-fonts-4/#propdef-font-weight /// /// This is effectively just a `Number`. -#[derive(Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, ToCss)] +#[derive( + Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToResolvedValue, +)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] pub struct FontWeight(pub Number); @@ -71,6 +77,7 @@ impl ToAnimatedValue for FontWeight { PartialEq, ToAnimatedZero, ToCss, + ToResolvedValue, )] /// The computed value of font-size pub struct FontSize { @@ -154,10 +161,6 @@ impl FontSize { } } -/// XXXManishearth it might be better to -/// animate this as computed, however this complicates -/// clamping and might not be the right thing to do. -/// We should figure it out. impl ToAnimatedValue for FontSize { type AnimatedValue = NonNegativeLength; @@ -175,8 +178,8 @@ impl ToAnimatedValue for FontSize { } } -#[derive(Clone, Debug, Eq, Hash, PartialEq)] -#[cfg_attr(feature = "servo", derive(MallocSizeOf))] +#[derive(Clone, Debug, Eq, PartialEq, ToResolvedValue)] +#[cfg_attr(feature = "servo", derive(Hash, MallocSizeOf))] /// Specifies a prioritized list of font family names or generic family names. pub struct FontFamily { /// The actual list of family names. @@ -190,7 +193,9 @@ impl FontFamily { /// Get default font family as `serif` which is a generic font-family pub fn serif() -> Self { FontFamily { - families: FontFamilyList::new(Box::new([SingleFontFamily::Generic(atom!("serif"))])), + families: FontFamilyList::new(Box::new([SingleFontFamily::Generic( + GenericFontFamily::Serif, + )])), is_system_font: false, } } @@ -202,9 +207,8 @@ impl MallocSizeOf for FontFamily { // SharedFontList objects are generally shared from the pointer // stored in the specified value. So only count this if the // SharedFontList is unshared. - unsafe { - bindings::Gecko_SharedFontList_SizeOfIncludingThisIfUnshared(self.families.0.get()) - } + let shared_font_list = self.families.shared_font_list().get(); + unsafe { bindings::Gecko_SharedFontList_SizeOfIncludingThisIfUnshared(shared_font_list) } } } @@ -223,14 +227,14 @@ impl ToCss for FontFamily { } } -#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq)] +#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToResolvedValue, ToShmem)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] /// The name of a font family of choice pub struct FamilyName { /// Name of the font family pub name: Atom, /// Syntax of the font family - pub syntax: FamilyNameSyntax, + pub syntax: FontFamilyNameSyntax, } impl ToCss for FamilyName { @@ -239,12 +243,12 @@ impl ToCss for FamilyName { W: fmt::Write, { match self.syntax { - FamilyNameSyntax::Quoted => { + FontFamilyNameSyntax::Quoted => { dest.write_char('"')?; write!(CssStringWriter::new(dest), "{}", self.name)?; dest.write_char('"') }, - FamilyNameSyntax::Identifiers => { + FontFamilyNameSyntax::Identifiers => { let mut first = true; for ident in self.name.to_string().split(' ') { if first { @@ -266,11 +270,12 @@ impl ToCss for FamilyName { } } -#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToResolvedValue, ToShmem)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] /// Font family names must either be given quoted as strings, /// or unquoted as a sequence of one or more identifiers. -pub enum FamilyNameSyntax { +#[repr(u8)] +pub enum FontFamilyNameSyntax { /// The family name was specified in a quoted form, e.g. "Font Name" /// or 'Font Name'. Quoted, @@ -280,85 +285,59 @@ pub enum FamilyNameSyntax { Identifiers, } -#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq)] -#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] +#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToCss, ToResolvedValue, ToShmem)] +#[cfg_attr(feature = "servo", derive(Deserialize, Serialize, Hash))] /// A set of faces that vary in weight, width or slope. pub enum SingleFontFamily { /// The name of a font family of choice. FamilyName(FamilyName), /// Generic family name. - Generic(Atom), + Generic(GenericFontFamily), +} + +/// A generic font-family name. +/// +/// The order here is important, if you change it make sure that +/// `gfxPlatformFontList.h`s ranged array and `gfxFontFamilyList`'s +/// sSingleGenerics are updated as well. +#[derive( + Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, Parse, ToCss, ToResolvedValue, ToShmem, +)] +#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] +#[repr(u8)] +#[allow(missing_docs)] +pub enum GenericFontFamily { + /// No generic family specified, only for internal usage. + #[css(skip)] + None, + Serif, + SansSerif, + #[parse(aliases = "-moz-fixed")] + Monospace, + Cursive, + Fantasy, + /// An internal value for emoji font selection. + #[css(skip)] + #[cfg(feature = "gecko")] + MozEmoji, } impl SingleFontFamily { - #[inline] - /// Get font family name as Atom - pub fn atom(&self) -> &Atom { - match *self { - SingleFontFamily::FamilyName(ref family_name) => &family_name.name, - SingleFontFamily::Generic(ref name) => name, - } - } - - #[inline] - #[cfg(not(feature = "gecko"))] // Gecko can't borrow atoms as UTF-8. - /// Get font family name - pub fn name(&self) -> &str { - self.atom() - } - - #[cfg(not(feature = "gecko"))] // Gecko can't borrow atoms as UTF-8. - /// Get the corresponding font-family with Atom - pub fn from_atom(input: Atom) -> SingleFontFamily { - match input { - atom!("serif") | - atom!("sans-serif") | - atom!("cursive") | - atom!("fantasy") | - atom!("monospace") => return SingleFontFamily::Generic(input), - _ => {}, - } - match_ignore_ascii_case! { &input, - "serif" => return SingleFontFamily::Generic(atom!("serif")), - "sans-serif" => return SingleFontFamily::Generic(atom!("sans-serif")), - "cursive" => return SingleFontFamily::Generic(atom!("cursive")), - "fantasy" => return SingleFontFamily::Generic(atom!("fantasy")), - "monospace" => return SingleFontFamily::Generic(atom!("monospace")), - _ => {} - } - - // We don't know if it's quoted or not. So we set it to - // quoted by default. - SingleFontFamily::FamilyName(FamilyName { - name: input, - syntax: FamilyNameSyntax::Quoted, - }) - } - - /// Parse a font-family value + /// Parse a font-family value. pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result> { if let Ok(value) = input.try(|i| i.expect_string_cloned()) { return Ok(SingleFontFamily::FamilyName(FamilyName { name: Atom::from(&*value), - syntax: FamilyNameSyntax::Quoted, + syntax: FontFamilyNameSyntax::Quoted, })); } - let first_ident = input.expect_ident()?.clone(); - // FIXME(bholley): The fast thing to do here would be to look up the - // string (as lowercase) in the static atoms table. We don't have an - // API to do that yet though, so we do the simple thing for now. - let mut css_wide_keyword = false; - match_ignore_ascii_case! { &first_ident, - "serif" => return Ok(SingleFontFamily::Generic(atom!("serif"))), - "sans-serif" => return Ok(SingleFontFamily::Generic(atom!("sans-serif"))), - "cursive" => return Ok(SingleFontFamily::Generic(atom!("cursive"))), - "fantasy" => return Ok(SingleFontFamily::Generic(atom!("fantasy"))), - "monospace" => return Ok(SingleFontFamily::Generic(atom!("monospace"))), - - #[cfg(feature = "gecko")] - "-moz-fixed" => return Ok(SingleFontFamily::Generic(atom!("-moz-fixed"))), + let first_ident = input.expect_ident_cloned()?; + if let Ok(generic) = GenericFontFamily::from_ident(&first_ident) { + return Ok(SingleFontFamily::Generic(generic)); + } + let reserved = match_ignore_ascii_case! { &first_ident, // https://drafts.csswg.org/css-fonts/#propdef-font-family // "Font family names that happen to be the same as a keyword value // (`inherit`, `serif`, `sans-serif`, `monospace`, `fantasy`, and `cursive`) @@ -366,18 +345,15 @@ impl SingleFontFamily { // The keywords โ€˜initialโ€™ and โ€˜defaultโ€™ are reserved for future use // and must also be quoted when used as font names. // UAs must not consider these keywords as matching the type." - "inherit" => css_wide_keyword = true, - "initial" => css_wide_keyword = true, - "unset" => css_wide_keyword = true, - "default" => css_wide_keyword = true, - _ => {} - } + "inherit" | "initial" | "unset" | "revert" | "default" => true, + _ => false, + }; let mut value = first_ident.as_ref().to_owned(); // These keywords are not allowed by themselves. // The only way this value can be valid with with another keyword. - if css_wide_keyword { + if reserved { let ident = input.expect_ident()?; value.push(' '); value.push_str(&ident); @@ -391,9 +367,9 @@ impl SingleFontFamily { // `font-family: \ a\ \ b\ \ c\ ;`, it is tricky to serialize them // as identifiers correctly. Just mark them quoted so we don't need // to worry about them in serialization code. - FamilyNameSyntax::Quoted + FontFamilyNameSyntax::Quoted } else { - FamilyNameSyntax::Identifiers + FontFamilyNameSyntax::Identifiers }; Ok(SingleFontFamily::FamilyName(FamilyName { name: Atom::from(value), @@ -401,134 +377,97 @@ impl SingleFontFamily { })) } - #[cfg(feature = "gecko")] - /// Return the generic ID for a given generic font name - pub fn generic(name: &Atom) -> (structs::FontFamilyType, u8) { - use crate::gecko_bindings::structs::FontFamilyType; - if *name == atom!("serif") { - (FontFamilyType::eFamily_serif, structs::kGenericFont_serif) - } else if *name == atom!("sans-serif") { - ( - FontFamilyType::eFamily_sans_serif, - structs::kGenericFont_sans_serif, - ) - } else if *name == atom!("cursive") { - ( - FontFamilyType::eFamily_cursive, - structs::kGenericFont_cursive, - ) - } else if *name == atom!("fantasy") { - ( - FontFamilyType::eFamily_fantasy, - structs::kGenericFont_fantasy, - ) - } else if *name == atom!("monospace") { - ( - FontFamilyType::eFamily_monospace, - structs::kGenericFont_monospace, - ) - } else if *name == atom!("-moz-fixed") { - ( - FontFamilyType::eFamily_moz_fixed, - structs::kGenericFont_moz_fixed, - ) - } else { - panic!("Unknown generic {}", name); + #[cfg(feature = "servo")] + /// Get the corresponding font-family with Atom + pub fn from_atom(input: Atom) -> SingleFontFamily { + match input { + atom!("serif") => return SingleFontFamily::Generic(GenericFontFamily::Serif), + atom!("sans-serif") => return SingleFontFamily::Generic(GenericFontFamily::SansSerif), + atom!("cursive") => return SingleFontFamily::Generic(GenericFontFamily::Cursive), + atom!("fantasy") => return SingleFontFamily::Generic(GenericFontFamily::Fantasy), + atom!("monospace") => return SingleFontFamily::Generic(GenericFontFamily::Monospace), + _ => {}, } + + match_ignore_ascii_case! { &input, + "serif" => return SingleFontFamily::Generic(GenericFontFamily::Serif), + "sans-serif" => return SingleFontFamily::Generic(GenericFontFamily::SansSerif), + "cursive" => return SingleFontFamily::Generic(GenericFontFamily::Cursive), + "fantasy" => return SingleFontFamily::Generic(GenericFontFamily::Fantasy), + "monospace" => return SingleFontFamily::Generic(GenericFontFamily::Monospace), + _ => {} + } + + // We don't know if it's quoted or not. So we set it to + // quoted by default. + SingleFontFamily::FamilyName(FamilyName { + name: input, + syntax: FontFamilyNameSyntax::Quoted, + }) } #[cfg(feature = "gecko")] /// Get the corresponding font-family with family name fn from_font_family_name(family: &structs::FontFamilyName) -> SingleFontFamily { - use crate::gecko_bindings::structs::FontFamilyType; - - match family.mType { - FontFamilyType::eFamily_sans_serif => SingleFontFamily::Generic(atom!("sans-serif")), - FontFamilyType::eFamily_serif => SingleFontFamily::Generic(atom!("serif")), - FontFamilyType::eFamily_monospace => SingleFontFamily::Generic(atom!("monospace")), - FontFamilyType::eFamily_cursive => SingleFontFamily::Generic(atom!("cursive")), - FontFamilyType::eFamily_fantasy => SingleFontFamily::Generic(atom!("fantasy")), - FontFamilyType::eFamily_moz_fixed => SingleFontFamily::Generic(atom!("-moz-fixed")), - FontFamilyType::eFamily_named => { - let name = unsafe { Atom::from_raw(family.mName.mRawPtr) }; - SingleFontFamily::FamilyName(FamilyName { - name, - syntax: FamilyNameSyntax::Identifiers, - }) - }, - FontFamilyType::eFamily_named_quoted => { - let name = unsafe { Atom::from_raw(family.mName.mRawPtr) }; - SingleFontFamily::FamilyName(FamilyName { - name, - syntax: FamilyNameSyntax::Quoted, - }) - }, - _ => panic!("Found unexpected font FontFamilyType"), - } - } -} - -impl ToCss for SingleFontFamily { - fn to_css(&self, dest: &mut CssWriter) -> fmt::Result - where - W: fmt::Write, - { - match *self { - SingleFontFamily::FamilyName(ref name) => name.to_css(dest), - - // All generic values accepted by the parser are known to not require escaping. - SingleFontFamily::Generic(ref name) => { - #[cfg(feature = "gecko")] - { - // We should treat -moz-fixed as monospace - if name == &atom!("-moz-fixed") { - return dest.write_str("monospace"); - } - } - - write!(dest, "{}", name) - }, + if family.mName.mRawPtr.is_null() { + debug_assert_ne!(family.mGeneric, GenericFontFamily::None); + return SingleFontFamily::Generic(family.mGeneric); } + let name = unsafe { Atom::from_raw(family.mName.mRawPtr) }; + SingleFontFamily::FamilyName(FamilyName { + name, + syntax: family.mSyntax, + }) } } #[cfg(feature = "servo")] -#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq)] +#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToResolvedValue, ToShmem)] /// A list of SingleFontFamily pub struct FontFamilyList(Box<[SingleFontFamily]>); #[cfg(feature = "gecko")] #[derive(Clone, Debug)] /// A list of SingleFontFamily -pub struct FontFamilyList(pub RefPtr); +pub enum FontFamilyList { + /// A strong reference to a Gecko SharedFontList object. + SharedFontList(RefPtr), + /// A font-family generic ID. + Generic(GenericFontFamily), +} #[cfg(feature = "gecko")] -impl Hash for FontFamilyList { - fn hash(&self, state: &mut H) - where - H: Hasher, - { - use crate::string_cache::WeakAtom; - - for name in self.0.mNames.iter() { - name.mType.hash(state); - if !name.mName.mRawPtr.is_null() { - unsafe { - WeakAtom::new(name.mName.mRawPtr).hash(state); - } - } - } +impl ToShmem for FontFamilyList { + fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> ManuallyDrop { + // In practice, the only SharedFontList objects we create from shared + // style sheets are ones with a single generic entry. + ManuallyDrop::new(match *self { + FontFamilyList::SharedFontList(ref r) => { + assert!( + r.mNames.len() == 1 && r.mNames[0].mName.mRawPtr.is_null(), + "ToShmem failed for FontFamilyList: cannot handle non-generic families", + ); + FontFamilyList::Generic(r.mNames[0].mGeneric) + }, + FontFamilyList::Generic(t) => FontFamilyList::Generic(t), + }) } } #[cfg(feature = "gecko")] impl PartialEq for FontFamilyList { fn eq(&self, other: &FontFamilyList) -> bool { - if self.0.mNames.len() != other.0.mNames.len() { + let self_list = self.shared_font_list(); + let other_list = other.shared_font_list(); + + if self_list.mNames.len() != other_list.mNames.len() { return false; } - for (a, b) in self.0.mNames.iter().zip(other.0.mNames.iter()) { - if a.mType != b.mType || a.mName.mRawPtr != b.mName.mRawPtr { + for (a, b) in self_list.mNames.iter().zip(other_list.mNames.iter()) { + if a.mSyntax != b.mSyntax || + a.mName.mRawPtr != b.mName.mRawPtr || + a.mGeneric != b.mGeneric + { return false; } } @@ -540,14 +479,14 @@ impl PartialEq for FontFamilyList { impl Eq for FontFamilyList {} impl FontFamilyList { - #[cfg(feature = "servo")] /// Return FontFamilyList with a vector of SingleFontFamily + #[cfg(feature = "servo")] pub fn new(families: Box<[SingleFontFamily]>) -> FontFamilyList { FontFamilyList(families) } - #[cfg(feature = "gecko")] /// Return FontFamilyList with a vector of SingleFontFamily + #[cfg(feature = "gecko")] pub fn new(families: Box<[SingleFontFamily]>) -> FontFamilyList { let fontlist; let names; @@ -559,58 +498,69 @@ impl FontFamilyList { for family in families.iter() { match *family { - SingleFontFamily::FamilyName(ref f) => { - let quoted = matches!(f.syntax, FamilyNameSyntax::Quoted); - unsafe { - bindings::Gecko_nsTArray_FontFamilyName_AppendNamed( - names, - f.name.as_ptr(), - quoted, - ); - } + SingleFontFamily::FamilyName(ref f) => unsafe { + bindings::Gecko_nsTArray_FontFamilyName_AppendNamed( + names, + f.name.as_ptr(), + f.syntax, + ); }, - SingleFontFamily::Generic(ref name) => { - let (family_type, _generic) = SingleFontFamily::generic(name); - unsafe { - bindings::Gecko_nsTArray_FontFamilyName_AppendGeneric(names, family_type); - } + SingleFontFamily::Generic(family) => unsafe { + bindings::Gecko_nsTArray_FontFamilyName_AppendGeneric(names, family); }, } } - FontFamilyList(unsafe { RefPtr::from_addrefed(fontlist) }) + FontFamilyList::SharedFontList(unsafe { RefPtr::from_addrefed(fontlist) }) } - #[cfg(feature = "servo")] /// Return iterator of SingleFontFamily + #[cfg(feature = "servo")] pub fn iter(&self) -> slice::Iter { self.0.iter() } - #[cfg(feature = "gecko")] /// Return iterator of SingleFontFamily + #[cfg(feature = "gecko")] pub fn iter(&self) -> FontFamilyNameIter { FontFamilyNameIter { - names: &self.0.mNames, + names: &self.shared_font_list().mNames, cur: 0, } } - #[cfg(feature = "gecko")] /// Return the generic ID if it is a single generic font - pub fn single_generic(&self) -> Option { + pub fn single_generic(&self) -> Option { let mut iter = self.iter(); - if let Some(SingleFontFamily::Generic(ref name)) = iter.next() { + if let Some(SingleFontFamily::Generic(f)) = iter.next() { if iter.next().is_none() { - return Some(SingleFontFamily::generic(name).1); + return Some(f.clone()); } } None } + + /// Return a reference to the Gecko SharedFontList. + #[cfg(feature = "gecko")] + pub fn shared_font_list(&self) -> &RefPtr { + match *self { + FontFamilyList::SharedFontList(ref r) => r, + FontFamilyList::Generic(t) => { + unsafe { + // TODO(heycam): Should really add StaticRefPtr sugar. + let index = t as usize; + mem::transmute::< + &structs::StaticRefPtr, + &RefPtr, + >(&structs::SharedFontList_sSingleGenerics[index]) + } + }, + } + } } -#[cfg(feature = "gecko")] /// Iterator of FontFamily +#[cfg(feature = "gecko")] pub struct FontFamilyNameIter<'a> { names: &'a structs::nsTArray, cur: usize, @@ -631,8 +581,18 @@ impl<'a> Iterator for FontFamilyNameIter<'a> { } } -#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, ToCss)] /// Preserve the readability of text when font fallback occurs +#[derive( + Animate, + Clone, + ComputeSquaredDistance, + Copy, + Debug, + MallocSizeOf, + PartialEq, + ToCss, + ToResolvedValue, +)] pub enum FontSizeAdjust { #[animation(error)] /// None variant @@ -713,7 +673,7 @@ pub type FontVariationSettings = FontSettings>; /// OpenType "language system" tag, so we should be able to compute /// it and store it as a 32-bit integer /// (see http://www.microsoft.com/typography/otspec/languagetags.htm). -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToResolvedValue)] #[repr(C)] pub struct FontLanguageOverride(pub u32); @@ -819,7 +779,7 @@ impl ToComputedValue for specified::MozScriptLevel { /// A wrapper over an `Angle`, that handles clamping to the appropriate range /// for `font-style` animation. -#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss)] +#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToResolvedValue)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] pub struct FontStyleAngle(pub Angle); @@ -916,7 +876,9 @@ impl ToCss for FontStyle { /// A value for the font-stretch property per: /// /// https://drafts.csswg.org/css-fonts-4/#propdef-font-stretch -#[derive(Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, ToCss)] +#[derive( + Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToResolvedValue, +)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] pub struct FontStretch(pub NonNegativePercentage); diff --git a/components/style/values/computed/image.rs b/components/style/values/computed/image.rs index a77da59dda3..4070e51815a 100644 --- a/components/style/values/computed/image.rs +++ b/components/style/values/computed/image.rs @@ -36,7 +36,7 @@ pub type GradientKind = generic::GradientKind; /// A computed gradient line direction. -#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq)] +#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToResolvedValue)] pub enum LineDirection { /// An angle. Angle(Angle), diff --git a/components/style/values/computed/length.rs b/components/style/values/computed/length.rs index 1262e4dd1d5..f43befbbaf0 100644 --- a/components/style/values/computed/length.rs +++ b/components/style/values/computed/length.rs @@ -10,12 +10,12 @@ use crate::values::computed::NonNegativeNumber; use crate::values::distance::{ComputeSquaredDistance, SquaredDistance}; use crate::values::generics::length as generics; use crate::values::generics::length::{ - GenericLengthOrNumber, MaxSize as GenericMaxSize, Size as GenericSize, + GenericLengthOrNumber, GenericLengthPercentageOrNormal, GenericMaxSize, GenericSize, }; use crate::values::generics::NonNegative; use crate::values::specified::length::ViewportPercentageLength; use crate::values::specified::length::{AbsoluteLength, FontBaseSize, FontRelativeLength}; -use crate::values::{specified, CSSFloat, Either, Normal}; +use crate::values::{specified, CSSFloat}; use crate::Zero; use app_units::Au; use ordered_float::NotNan; @@ -75,7 +75,7 @@ impl ToComputedValue for specified::Length { /// /// https://drafts.csswg.org/css-values-4/#typedef-length-percentage #[allow(missing_docs)] -#[derive(Clone, Copy, Debug, MallocSizeOf, ToAnimatedZero)] +#[derive(Clone, Copy, Debug, MallocSizeOf, ToAnimatedZero, ToResolvedValue)] #[repr(C)] pub struct LengthPercentage { length: Length, @@ -608,6 +608,8 @@ impl Size { PartialOrd, ToAnimatedValue, ToAnimatedZero, + ToResolvedValue, + ToShmem, )] #[repr(C)] pub struct CSSPixelLength(CSSFloat); @@ -709,9 +711,6 @@ pub type NonNegativeLengthOrAuto = generics::GenericLengthPercentageOrAuto` or a `` value. pub type LengthOrNumber = GenericLengthOrNumber; -/// Either a computed `` or the `normal` keyword. -pub type LengthOrNormal = Either; - /// A wrapper of Length, whose value must be >= 0. pub type NonNegativeLength = NonNegative; @@ -782,11 +781,9 @@ impl From for Au { } } -/// Either a computed NonNegativeLength or the `normal` keyword. -pub type NonNegativeLengthOrNormal = Either; - /// Either a computed NonNegativeLengthPercentage or the `normal` keyword. -pub type NonNegativeLengthPercentageOrNormal = Either; +pub type NonNegativeLengthPercentageOrNormal = + GenericLengthPercentageOrNormal; /// Either a non-negative `` or a ``. pub type NonNegativeLengthOrNumber = GenericLengthOrNumber; @@ -809,6 +806,8 @@ pub type NonNegativeLengthOrNumber = GenericLengthOrNumber for CSSFloat { } #[allow(missing_docs)] -#[derive(Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, ToCss)] +#[derive( + Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToResolvedValue, +)] #[repr(C, u8)] pub enum NumberOrPercentage { Percentage(Percentage), diff --git a/components/style/values/computed/percentage.rs b/components/style/values/computed/percentage.rs index 4f39a7a7274..c22f8ed5683 100644 --- a/components/style/values/computed/percentage.rs +++ b/components/style/values/computed/percentage.rs @@ -27,6 +27,8 @@ use style_traits::{CssWriter, ToCss}; ToAnimatedValue, ToAnimatedZero, ToComputedValue, + ToResolvedValue, + ToShmem, )] #[repr(C)] pub struct Percentage(pub CSSFloat); diff --git a/components/style/values/computed/text.rs b/components/style/values/computed/text.rs index db56a16a82d..2fdb1e48c4f 100644 --- a/components/style/values/computed/text.rs +++ b/components/style/values/computed/text.rs @@ -37,6 +37,7 @@ pub type InitialLetter = GenericInitialLetter; PartialEq, ToAnimatedValue, ToAnimatedZero, + ToResolvedValue, )] pub struct LetterSpacing(pub Length); @@ -102,7 +103,7 @@ impl ToComputedValue for specified::WordSpacing { /// A computed value for the `line-height` property. pub type LineHeight = GenericLineHeight; -#[derive(Clone, Debug, MallocSizeOf, PartialEq)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToResolvedValue)] /// text-overflow. /// When the specified value only has one side, that's the "second" /// side, and the sides are logical, so "second" means "end". The @@ -155,7 +156,7 @@ impl ToCss for TextOverflow { /// and similar stuff when we implement it. /// /// FIXME(emilio): Also, should be just a bitfield instead of three bytes. -#[derive(Clone, Copy, Debug, Default, MallocSizeOf, PartialEq)] +#[derive(Clone, Copy, Debug, Default, MallocSizeOf, PartialEq, ToResolvedValue)] pub struct TextDecorationsInEffect { /// Whether an underline is in effect. pub underline: bool, @@ -193,7 +194,7 @@ impl TextDecorationsInEffect { } /// computed value for the text-emphasis-style property -#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss, ToResolvedValue)] pub enum TextEmphasisStyle { /// Keyword value for the text-emphasis-style property (`filled` `open`) Keyword(TextEmphasisKeywordValue), @@ -204,7 +205,7 @@ pub enum TextEmphasisStyle { } /// Keyword value for the text-emphasis-style property -#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss, ToResolvedValue)] pub struct TextEmphasisKeywordValue { /// fill for the text-emphasis-style property pub fill: TextEmphasisFillMode, diff --git a/components/style/values/computed/time.rs b/components/style/values/computed/time.rs index be16a5939bb..5681f6fab5e 100644 --- a/components/style/values/computed/time.rs +++ b/components/style/values/computed/time.rs @@ -9,7 +9,7 @@ use std::fmt::{self, Write}; use style_traits::{CssWriter, ToCss}; /// A computed `