diff --git a/Cargo.lock b/Cargo.lock index c6002808308..6e5c91f372a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -997,7 +997,6 @@ dependencies = [ "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cssparser 0.23.2 (registry+https://github.com/rust-lang/crates.io-index)", "cstr 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "malloc_size_of 0.0.1", @@ -3123,6 +3122,7 @@ dependencies = [ "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "servo_arc 0.1.1", "servo_atoms 0.0.1", + "servo_url 0.0.1", "webrender_api 0.57.2 (git+https://github.com/servo/webrender)", ] diff --git a/components/layout/display_list/builder.rs b/components/layout/display_list/builder.rs index 141bbb52b80..65b12137c68 100644 --- a/components/layout/display_list/builder.rs +++ b/components/layout/display_list/builder.rs @@ -66,9 +66,9 @@ use style::servo::restyle_damage::ServoRestyleDamage; use style::values::{Either, RGBA}; use style::values::computed::Gradient; use style::values::computed::effects::SimpleShadow; -use style::values::computed::pointing::Cursor; use style::values::generics::background::BackgroundSize; use style::values::generics::image::{GradientKind, Image, PaintWorklet}; +use style::values::generics::pointing::Cursor; use style_traits::CSSPixel; use style_traits::ToCss; use style_traits::cursor::CursorKind; @@ -2952,11 +2952,11 @@ impl ComputedValuesCursorUtility for ComputedValues { fn get_cursor(&self, default_cursor: CursorKind) -> Option { match ( self.get_pointing().pointer_events, - self.get_pointing().cursor, + &self.get_pointing().cursor, ) { (PointerEvents::None, _) => None, - (PointerEvents::Auto, Cursor(CursorKind::Auto)) => Some(default_cursor), - (PointerEvents::Auto, Cursor(cursor)) => Some(cursor), + (PointerEvents::Auto, &Cursor { keyword: CursorKind::Auto, .. }) => Some(default_cursor), + (PointerEvents::Auto, &Cursor { keyword, .. }) => Some(keyword), } } } diff --git a/components/servo_arc/lib.rs b/components/servo_arc/lib.rs index 04a76c64291..e2063c79a9c 100644 --- a/components/servo_arc/lib.rs +++ b/components/servo_arc/lib.rs @@ -39,6 +39,7 @@ use std::convert::From; use std::fmt; use std::hash::{Hash, Hasher}; use std::iter::{ExactSizeIterator, Iterator}; +use std::marker::PhantomData; use std::mem; use std::ops::{Deref, DerefMut}; use std::os::raw::c_void; @@ -924,7 +925,7 @@ impl Arc { /// /// ArcBorrow lets us deal with borrows of known-refcounted objects /// without needing to worry about how they're actually stored. -#[derive(Eq, PartialEq)] +#[derive(Debug, Eq, PartialEq)] pub struct ArcBorrow<'a, T: 'a>(&'a T); impl<'a, T> Copy for ArcBorrow<'a, T> {} @@ -951,6 +952,10 @@ impl<'a, T> ArcBorrow<'a, T> { ArcBorrow(r) } + pub fn ptr_eq(this: &Self, other: &Self) -> bool { + this.0 as *const T == other.0 as *const T + } + #[inline] pub fn with_arc(&self, f: F) -> U where @@ -971,6 +976,13 @@ impl<'a, T> ArcBorrow<'a, T> { // Forward the result. result } + + /// Similar to deref, but uses the lifetime |a| rather than the lifetime of + /// self, which is incompatible with the signature of the Deref trait. + #[inline] + pub fn get(&self) -> &'a T { + self.0 + } } impl<'a, T> Deref for ArcBorrow<'a, T> { @@ -978,7 +990,127 @@ impl<'a, T> Deref for ArcBorrow<'a, T> { #[inline] fn deref(&self) -> &T { - &*self.0 + self.0 + } +} + +/// A tagged union that can represent Arc or Arc while only consuming a +/// single word. The type is also NonZero, and thus can be stored in an Option +/// without increasing size. +/// +/// This could probably be extended to support four types if necessary. +pub struct ArcUnion { + p: NonZeroPtrMut<()>, + phantom_a: PhantomData<&'static A>, + phantom_b: PhantomData<&'static B>, +} + +impl PartialEq for ArcUnion { + fn eq(&self, other: &Self) -> bool { + use ArcUnionBorrow::*; + match (self.borrow(), other.borrow()) { + (First(x), First(y)) => x == y, + (Second(x), Second(y)) => x == y, + (_, _) => false, + } + } +} + +#[derive(Debug)] +pub enum ArcUnionBorrow<'a, A: 'static, B: 'static> { + First(ArcBorrow<'a, A>), + Second(ArcBorrow<'a, B>), +} + +impl ArcUnion { + fn new(ptr: *mut ()) -> Self { + ArcUnion { + p: NonZeroPtrMut::new(ptr), + phantom_a: PhantomData, + phantom_b: PhantomData, + } + } + + /// Returns true if the two values are pointer-equal. + pub fn ptr_eq(this: &Self, other: &Self) -> bool { + this.p == other.p + } + + /// Returns an enum representing a borrow of either A or B. + pub fn borrow(&self) -> ArcUnionBorrow { + if self.is_first() { + let ptr = self.p.ptr() as *const A; + let borrow = unsafe { ArcBorrow::from_ref(&*ptr) }; + ArcUnionBorrow::First(borrow) + } else { + let ptr = ((self.p.ptr() as usize) & !0x1) as *const B; + let borrow = unsafe { ArcBorrow::from_ref(&*ptr) }; + ArcUnionBorrow::Second(borrow) + } + } + + /// Creates an ArcUnion from an instance of the first type. + pub fn from_first(other: Arc) -> Self { + Self::new(Arc::into_raw(other) as *mut _) + } + + /// Creates an ArcUnion from an instance of the second type. + pub fn from_second(other: Arc) -> Self { + Self::new(((Arc::into_raw(other) as usize) | 0x1) as *mut _) + } + + /// Returns true if this ArcUnion contains the first type. + pub fn is_first(&self) -> bool { + self.p.ptr() as usize & 0x1 == 0 + } + + /// Returns true if this ArcUnion contains the second type. + pub fn is_second(&self) -> bool { + !self.is_first() + } + + /// Returns a borrow of the first type if applicable, otherwise None. + pub fn as_first(&self) -> Option> { + match self.borrow() { + ArcUnionBorrow::First(x) => Some(x), + ArcUnionBorrow::Second(_) => None, + } + } + + /// Returns a borrow of the second type if applicable, otherwise None. + pub fn as_second(&self) -> Option> { + match self.borrow() { + ArcUnionBorrow::First(_) => None, + ArcUnionBorrow::Second(x) => Some(x), + } + } +} + +impl Clone for ArcUnion { + fn clone(&self) -> Self { + match self.borrow() { + ArcUnionBorrow::First(x) => ArcUnion::from_first(x.clone_arc()), + ArcUnionBorrow::Second(x) => ArcUnion::from_second(x.clone_arc()), + } + } +} + +impl Drop for ArcUnion { + fn drop(&mut self) { + match self.borrow() { + ArcUnionBorrow::First(x) => unsafe { + let _ = Arc::from_raw(&*x); + }, + ArcUnionBorrow::Second(x) => unsafe { + let _ = Arc::from_raw(&*x); + }, + } + } +} + +impl fmt::Debug for ArcUnion { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.borrow(), f) } } diff --git a/components/style/applicable_declarations.rs b/components/style/applicable_declarations.rs index d4674fa1bc7..a1476917fcb 100644 --- a/components/style/applicable_declarations.rs +++ b/components/style/applicable_declarations.rs @@ -116,7 +116,7 @@ impl ApplicableDeclarationBlock { level: CascadeLevel, ) -> Self { ApplicableDeclarationBlock { - source: StyleSource::Declarations(declarations), + source: StyleSource::from_declarations(declarations), bits: ApplicableDeclarationBits::new(0, level, 0), specificity: 0, } diff --git a/components/style/gecko/data.rs b/components/style/gecko/data.rs index 331b07ea551..567a9b7f6ca 100644 --- a/components/style/gecko/data.rs +++ b/components/style/gecko/data.rs @@ -94,15 +94,15 @@ impl StylesheetInDocument for GeckoStyleSheet { } fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> { - use gecko_bindings::structs::ServoMediaList; + use gecko_bindings::structs::mozilla::dom::MediaList as DomMediaList; use std::mem; unsafe { - let servo_media_list = self.raw()._base.mMedia.mRawPtr as *const ServoMediaList; - if servo_media_list.is_null() { + let dom_media_list = self.raw()._base.mMedia.mRawPtr as *const DomMediaList; + if dom_media_list.is_null() { return None; } - let raw_list = &*(*servo_media_list).mRawList.mRawPtr; + let raw_list = &*(*dom_media_list).mRawList.mRawPtr; let list = Locked::::as_arc(mem::transmute(&raw_list)); Some(list.read_with(guard)) } diff --git a/components/style/gecko/url.rs b/components/style/gecko/url.rs index 1b5bc424e4d..bca7e10883a 100644 --- a/components/style/gecko/url.rs +++ b/components/style/gecko/url.rs @@ -19,7 +19,7 @@ use style_traits::ParseError; /// A CSS url() value for gecko. #[css(function = "url")] -#[derive(Clone, Debug, PartialEq, ToCss)] +#[derive(Clone, Debug, PartialEq, SpecifiedValueInfo, ToCss)] pub struct CssUrl { /// The URL in unresolved string form. /// @@ -121,7 +121,7 @@ impl MallocSizeOf for CssUrl { } /// A specified url() value for general usage. -#[derive(Clone, Debug, ToComputedValue, ToCss)] +#[derive(Clone, Debug, SpecifiedValueInfo, ToComputedValue, ToCss)] pub struct SpecifiedUrl { /// The specified url value. pub url: CssUrl, @@ -179,7 +179,7 @@ impl MallocSizeOf for SpecifiedUrl { /// A specified url() value for image. /// /// This exists so that we can construct `ImageValue` and reuse it. -#[derive(Clone, Debug, ToComputedValue, ToCss)] +#[derive(Clone, Debug, SpecifiedValueInfo, ToComputedValue, ToCss)] pub struct SpecifiedImageUrl { /// The specified url value. pub url: CssUrl, diff --git a/components/style/gecko_string_cache/mod.rs b/components/style/gecko_string_cache/mod.rs index ead705fa231..297599e2080 100644 --- a/components/style/gecko_string_cache/mod.rs +++ b/components/style/gecko_string_cache/mod.rs @@ -20,6 +20,7 @@ use std::fmt::{self, Write}; use std::hash::{Hash, Hasher}; use std::iter::Cloned; use std::ops::Deref; +use style_traits::SpecifiedValueInfo; #[macro_use] #[allow(improper_ctypes, non_camel_case_types, missing_docs)] @@ -415,3 +416,5 @@ impl From for Atom { } malloc_size_of_is_0!(Atom); + +impl SpecifiedValueInfo for Atom {} diff --git a/components/style/macros.rs b/components/style/macros.rs index f8f4759c148..671ba35b8bc 100644 --- a/components/style/macros.rs +++ b/components/style/macros.rs @@ -68,8 +68,9 @@ macro_rules! try_match_ident_ignore_ascii_case { macro_rules! define_keyword_type { ($name:ident, $css:expr) => { #[allow(missing_docs)] - #[derive(Animate, Clone, ComputeSquaredDistance, Copy, MallocSizeOf, PartialEq, - ToAnimatedValue, ToAnimatedZero, ToComputedValue, ToCss)] + #[derive(Animate, Clone, ComputeSquaredDistance, Copy, MallocSizeOf, + PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, + ToComputedValue, ToCss)] pub struct $name; impl fmt::Debug for $name { diff --git a/components/style/properties/helpers.mako.rs b/components/style/properties/helpers.mako.rs index 90e070d03c4..017996f87b5 100644 --- a/components/style/properties/helpers.mako.rs +++ b/components/style/properties/helpers.mako.rs @@ -164,7 +164,7 @@ % if separator == "Comma": #[css(comma)] % endif - #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] + #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)] pub struct SpecifiedValue( % if not allow_empty: #[css(iterable)] @@ -396,8 +396,8 @@ pub mod computed_value { #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] - #[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse)] - #[derive(PartialEq, ToCss)] + #[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, + PartialEq, SpecifiedValueInfo, ToCss)] pub enum T { % for value in keyword.values_for(product): ${to_camel_case(value)}, @@ -408,9 +408,10 @@ } #[cfg_attr(feature = "gecko", derive(MallocSizeOf))] - #[derive(Clone, Copy, Debug, Eq, PartialEq, ToCss)] + #[derive(Clone, Copy, Debug, Eq, PartialEq, SpecifiedValueInfo, ToCss)] pub enum SpecifiedValue { Keyword(computed_value::T), + #[css(skip)] System(SystemFont), } @@ -558,7 +559,8 @@ % if extra_specified: #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] - #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToCss)] + #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, + SpecifiedValueInfo, ToCss)] pub enum SpecifiedValue { ${variants(keyword.values_for(product) + extra_specified.split(), bool(extra_specified))} } @@ -569,7 +571,7 @@ #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToCss)] % if not extra_specified: - #[derive(Parse, ToComputedValue)] + #[derive(Parse, SpecifiedValueInfo, ToComputedValue)] % endif pub enum T { ${variants(data.longhands_by_name[name].keyword.values_for(product), not extra_specified)} @@ -617,9 +619,14 @@ % endif -<%def name="shorthand(name, sub_properties, derive_serialize=False, **kwargs)"> +<%def name="shorthand(name, sub_properties, derive_serialize=False, + derive_value_info=True, **kwargs)"> <% shorthand = data.declare_shorthand(name, sub_properties.split(), **kwargs) + # mako doesn't accept non-string value in parameters with <% %> form, so + # we have to workaround it this way. + if not isinstance(derive_value_info, bool): + derive_value_info = eval(derive_value_info) %> % if shorthand: /// ${shorthand.spec} @@ -634,8 +641,11 @@ #[allow(unused_imports)] use style_traits::{ParseError, StyleParseErrorKind}; #[allow(unused_imports)] - use style_traits::{CssWriter, ToCss}; + use style_traits::{CssWriter, KeywordsCollectFn, SpecifiedValueInfo, ToCss}; + % if derive_value_info: + #[derive(SpecifiedValueInfo)] + % endif pub struct Longhands { % for sub_property in shorthand.sub_properties: pub ${sub_property.ident}: diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index e2d15139128..57a8ed99880 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -27,7 +27,7 @@ use smallvec::SmallVec; use std::{cmp, ptr}; use std::mem::{self, ManuallyDrop}; #[cfg(feature = "gecko")] use hash::FnvHashMap; -use style_traits::ParseError; +use style_traits::{KeywordsCollectFn, ParseError, SpecifiedValueInfo}; use super::ComputedValues; use values::{CSSFloat, CustomIdent, Either}; use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero}; @@ -172,6 +172,15 @@ impl From for TransitionProperty { } } +impl SpecifiedValueInfo for TransitionProperty { + fn collect_completion_keywords(f: KeywordsCollectFn) { + // `transition-property` can actually accept all properties and + // arbitrary identifiers, but `all` is a special one we'd like + // to list. + f(&["all"]); + } +} + /// Returns true if this nsCSSPropertyID is one of the transitionable properties. #[cfg(feature = "gecko")] pub fn nscsspropertyid_is_transitionable(property: nsCSSPropertyID) -> bool { diff --git a/components/style/properties/longhand/box.mako.rs b/components/style/properties/longhand/box.mako.rs index 806afcbd1b6..026a3ca7936 100644 --- a/components/style/properties/longhand/box.mako.rs +++ b/components/style/properties/longhand/box.mako.rs @@ -660,9 +660,21 @@ ${helpers.predefined_type( products="gecko", gecko_pref="layout.css.shape-outside.enabled", animation_value_type="ComputedValue", + flags="APPLIES_TO_FIRST_LETTER", spec="https://drafts.csswg.org/css-shapes/#shape-image-threshold-property", )} +${helpers.predefined_type( + "shape-margin", + "NonNegativeLengthOrPercentage", + "computed::NonNegativeLengthOrPercentage::zero()", + products="gecko", + gecko_pref="layout.css.shape-outside.enabled", + animation_value_type="NonNegativeLengthOrPercentage", + flags="APPLIES_TO_FIRST_LETTER", + spec="https://drafts.csswg.org/css-shapes/#shape-margin-property", +)} + ${helpers.predefined_type( "shape-outside", "basic_shape::FloatAreaShape", diff --git a/components/style/properties/longhand/font.mako.rs b/components/style/properties/longhand/font.mako.rs index 0477a2cd0d5..7309aca8a38 100644 --- a/components/style/properties/longhand/font.mako.rs +++ b/components/style/properties/longhand/font.mako.rs @@ -274,6 +274,11 @@ ${helpers.predefined_type("-x-text-zoom", //! detects that a value has a system font, it will resolve it, and //! cache it on the ComputedValues. After this, it can be just fetched //! whenever a font longhand on the same element needs the system font. + //! + //! When a longhand property is holding a SystemFont, it's serialized + //! to an empty string as if its value comes from a shorthand with + //! variable reference. We may want to improve this behavior at some + //! point. See also https://github.com/w3c/csswg-drafts/issues/1586. use app_units::Au; use cssparser::{Parser, ToCss}; @@ -296,7 +301,8 @@ ${helpers.predefined_type("-x-text-zoom", kw_cast = """font_variant_caps font_kerning font_variant_position font_optical_sizing""".split() %> - #[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToCss)] + #[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, + SpecifiedValueInfo, ToCss)] pub enum SystemFont { % for font in system_fonts: ${to_camel_case(font)}, @@ -444,7 +450,7 @@ ${helpers.predefined_type("-x-text-zoom", // 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, ToCss)] + #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, SpecifiedValueInfo, ToCss)] #[cfg_attr(feature = "servo", derive(MallocSizeOf))] /// void enum for system font, can never exist pub enum SystemFont {} diff --git a/components/style/properties/longhand/inherited_text.mako.rs b/components/style/properties/longhand/inherited_text.mako.rs index abf1054675c..975d7eabe26 100644 --- a/components/style/properties/longhand/inherited_text.mako.rs +++ b/components/style/properties/longhand/inherited_text.mako.rs @@ -292,7 +292,6 @@ ${helpers.single_keyword("ruby-position", "over under", ${helpers.single_keyword("text-combine-upright", "none all", products="gecko", animation_value_type="discrete", - gecko_pref="layout.css.text-combine-upright.enabled", spec="https://drafts.csswg.org/css-writing-modes-3/#text-combine-upright")} // SVG 1.1: Section 11 - Painting: Filling, Stroking and Marker Symbols diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index 1042a5d1a4d..a1d2ee9d085 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -42,7 +42,8 @@ use selector_parser::PseudoElement; use selectors::parser::SelectorParseErrorKind; #[cfg(feature = "servo")] use servo_config::prefs::PREFS; use shared_lock::StylesheetGuards; -use style_traits::{CssWriter, ParseError, ParsingMode, StyleParseErrorKind, ToCss}; +use style_traits::{CssWriter, KeywordsCollectFn, ParseError, ParsingMode}; +use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss}; use stylesheets::{CssRuleType, Origin, UrlExtraData}; #[cfg(feature = "servo")] use values::Either; use values::generics::text::LineHeight; @@ -541,6 +542,43 @@ impl NonCustomPropertyId { false } + + /// The supported types of this property. The return value should be + /// style_traits::CssType when it can become a bitflags type. + fn supported_types(&self) -> u8 { + const SUPPORTED_TYPES: [u8; ${len(data.longhands) + len(data.shorthands)}] = [ + % for prop in data.longhands: + <${prop.specified_type()} as SpecifiedValueInfo>::SUPPORTED_TYPES, + % endfor + % for prop in data.shorthands: + % if prop.name == "all": + 0, // 'all' accepts no value other than CSS-wide keywords + % else: + ::SUPPORTED_TYPES, + % endif + % endfor + ]; + SUPPORTED_TYPES[self.0] + } + + /// See PropertyId::collect_property_completion_keywords. + fn collect_property_completion_keywords(&self, f: KeywordsCollectFn) { + const COLLECT_FUNCTIONS: [&Fn(KeywordsCollectFn); + ${len(data.longhands) + len(data.shorthands)}] = [ + % for prop in data.longhands: + &<${prop.specified_type()} as SpecifiedValueInfo>::collect_completion_keywords, + % endfor + % for prop in data.shorthands: + % if prop.name == "all": + &|_f| {}, // 'all' accepts no value other than CSS-wide keywords + % else: + &:: + collect_completion_keywords, + % endif + % endfor + ]; + COLLECT_FUNCTIONS[self.0](f); + } } impl From for NonCustomPropertyId { @@ -724,7 +762,8 @@ impl LonghandIdSet { } /// An enum to represent a CSS Wide keyword. -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToCss)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToCss)] pub enum CSSWideKeyword { /// The `initial` keyword. Initial, @@ -1692,6 +1731,18 @@ impl PropertyId { }) } + /// Returns non-alias NonCustomPropertyId corresponding to this + /// property id. + fn non_custom_non_alias_id(&self) -> Option { + Some(match *self { + PropertyId::Custom(_) => return None, + PropertyId::Shorthand(id) => id.into(), + PropertyId::Longhand(id) => id.into(), + PropertyId::ShorthandAlias(id, _) => id.into(), + PropertyId::LonghandAlias(id, _) => id.into(), + }) + } + /// Whether the property is enabled for all content regardless of the /// stylesheet it was declared on (that is, in practice only checks prefs). #[inline] @@ -1713,6 +1764,24 @@ impl PropertyId { }; id.allowed_in(context) } + + /// Whether the property supports the given CSS type. + /// `ty` should a bitflags of constants in style_traits::CssType. + pub fn supports_type(&self, ty: u8) -> bool { + let id = self.non_custom_non_alias_id(); + id.map_or(0, |id| id.supported_types()) & ty != 0 + } + + /// Collect supported starting word of values of this property. + /// + /// See style_traits::SpecifiedValueInfo::collect_completion_keywords for more + /// details. + pub fn collect_property_completion_keywords(&self, f: KeywordsCollectFn) { + if let Some(id) = self.non_custom_non_alias_id() { + id.collect_property_completion_keywords(f); + } + CSSWideKeyword::collect_completion_keywords(f); + } } /// A declaration using a CSS-wide keyword. @@ -3424,7 +3493,7 @@ where let source = node.style_source(); let declarations = if source.is_some() { - source.read(cascade_level.guard(guards)).declaration_importance_iter() + source.as_ref().unwrap().read(cascade_level.guard(guards)).declaration_importance_iter() } else { // The root node has no style source. DeclarationImportanceIterator::new(&[], &empty) diff --git a/components/style/properties/shorthand/border.mako.rs b/components/style/properties/shorthand/border.mako.rs index 2a675a2c523..056096353bc 100644 --- a/components/style/properties/shorthand/border.mako.rs +++ b/components/style/properties/shorthand/border.mako.rs @@ -140,6 +140,7 @@ pub fn parse_border<'i, 't>( for prop in ['color', 'style', 'width'])} ${' '.join('border-image-%s' % name for name in ['outset', 'repeat', 'slice', 'source', 'width'])}" + derive_value_info="False" spec="https://drafts.csswg.org/css-backgrounds/#border"> pub fn parse_value<'i, 't>( @@ -202,6 +203,17 @@ pub fn parse_border<'i, 't>( } } + // Just use the same as border-left. The border shorthand can't accept + // any value that the sub-shorthand couldn't. + <% + border_left = "<::properties::shorthands::border_left::Longhands as SpecifiedValueInfo>" + %> + impl SpecifiedValueInfo for Longhands { + const SUPPORTED_TYPES: u8 = ${border_left}::SUPPORTED_TYPES; + fn collect_completion_keywords(f: KeywordsCollectFn) { + ${border_left}::collect_completion_keywords(f); + } + } <%helpers:shorthand name="border-radius" sub_properties="${' '.join( diff --git a/components/style/properties/shorthand/font.mako.rs b/components/style/properties/shorthand/font.mako.rs index 5e14fd6ab50..a53f899851c 100644 --- a/components/style/properties/shorthand/font.mako.rs +++ b/components/style/properties/shorthand/font.mako.rs @@ -19,6 +19,7 @@ ${'font-language-override' if product == 'gecko' else ''} ${'font-feature-settings' if product == 'gecko' else ''} ${'font-variation-settings' if product == 'gecko' else ''}" + derive_value_info="False" spec="https://drafts.csswg.org/css-fonts-3/#propdef-font"> use parser::Parse; use properties::longhands::{font_family, font_style, font_weight, font_stretch}; @@ -258,6 +259,29 @@ } % endif } + + <% + subprops_for_value_info = ["font_style", "font_weight", "font_stretch", + "font_variant_caps", "font_size", "font_family"] + subprops_for_value_info = [ + "".format(p) + for p in subprops_for_value_info + ] + %> + impl SpecifiedValueInfo for Longhands { + const SUPPORTED_TYPES: u8 = 0 + % for p in subprops_for_value_info: + | ${p}::SUPPORTED_TYPES + % endfor + ; + + fn collect_completion_keywords(f: KeywordsCollectFn) { + % for p in subprops_for_value_info: + ${p}::collect_completion_keywords(f); + % endfor + ::collect_completion_keywords(f); + } + } <%helpers:shorthand name="font-variant" diff --git a/components/style/properties/shorthand/outline.mako.rs b/components/style/properties/shorthand/outline.mako.rs index d2f04466629..14b935f3bfd 100644 --- a/components/style/properties/shorthand/outline.mako.rs +++ b/components/style/properties/shorthand/outline.mako.rs @@ -5,7 +5,7 @@ <%namespace name="helpers" file="/helpers.mako.rs" /> <%helpers:shorthand name="outline" - sub_properties="outline-width outline-style outline-color" + sub_properties="outline-color outline-style outline-width" derive_serialize="True" spec="https://drafts.csswg.org/css-ui/#propdef-outline"> use properties::longhands::{outline_color, outline_width, outline_style}; diff --git a/components/style/rule_cache.rs b/components/style/rule_cache.rs index 9e413659e0e..214b104b5a0 100644 --- a/components/style/rule_cache.rs +++ b/components/style/rule_cache.rs @@ -8,7 +8,7 @@ use fnv::FnvHashMap; use logical_geometry::WritingMode; use properties::{ComputedValues, StyleBuilder}; -use rule_tree::{StrongRuleNode, StyleSource}; +use rule_tree::StrongRuleNode; use selector_parser::PseudoElement; use servo_arc::Arc; use shared_lock::StylesheetGuards; @@ -97,16 +97,18 @@ impl RuleCache { mut rule_node: Option<&'r StrongRuleNode>, ) -> Option<&'r StrongRuleNode> { while let Some(node) = rule_node { - match *node.style_source() { - StyleSource::Declarations(ref decls) => { - let cascade_level = node.cascade_level(); - let decls = decls.read_with(cascade_level.guard(guards)); - if decls.contains_any_reset() { - break; - } + match node.style_source() { + Some(s) => match s.as_declarations() { + Some(decls) => { + let cascade_level = node.cascade_level(); + let decls = decls.read_with(cascade_level.guard(guards)); + if decls.contains_any_reset() { + break; + } + }, + None => break, }, - StyleSource::None => {}, - StyleSource::Style(_) => break, + None => {}, } rule_node = node.parent(); } diff --git a/components/style/rule_tree/mod.rs b/components/style/rule_tree/mod.rs index 1527a743de5..2ce403a666d 100644 --- a/components/style/rule_tree/mod.rs +++ b/components/style/rule_tree/mod.rs @@ -12,7 +12,7 @@ use gecko::selector_parser::PseudoElement; #[cfg(feature = "gecko")] use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use properties::{Importance, LonghandIdSet, PropertyDeclarationBlock}; -use servo_arc::{Arc, ArcBorrow, NonZeroPtrMut}; +use servo_arc::{Arc, ArcBorrow, ArcUnion, ArcUnionBorrow, NonZeroPtrMut}; use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards}; use smallvec::SmallVec; use std::io::{self, Write}; @@ -89,40 +89,27 @@ impl MallocSizeOf for RuleTree { /// more debuggability, and also the ability of show those selectors to /// devtools. #[derive(Clone, Debug)] -pub enum StyleSource { - /// A style rule stable pointer. - Style(Arc>), - /// A declaration block stable pointer. - Declarations(Arc>), - /// Indicates no style source. Used to save an Option wrapper around the stylesource in - /// RuleNode - None, -} +pub struct StyleSource(ArcUnion, Locked>); impl PartialEq for StyleSource { fn eq(&self, other: &Self) -> bool { - self.ptr_equals(other) + ArcUnion::ptr_eq(&self.0, &other.0) } } impl StyleSource { - #[inline] - fn ptr_equals(&self, other: &Self) -> bool { - use self::StyleSource::*; - match (self, other) { - (&Style(ref one), &Style(ref other)) => Arc::ptr_eq(one, other), - (&Declarations(ref one), &Declarations(ref other)) => Arc::ptr_eq(one, other), - (&None, _) | (_, &None) => { - panic!("Should not check for equality between null StyleSource objects") - }, - _ => false, - } + /// Creates a StyleSource from a StyleRule. + pub fn from_rule(rule: Arc>) -> Self { + StyleSource(ArcUnion::from_first(rule)) + } + + /// Creates a StyleSource from a PropertyDeclarationBlock. + pub fn from_declarations(decls: Arc>) -> Self { + StyleSource(ArcUnion::from_second(decls)) } fn dump(&self, guard: &SharedRwLockReadGuard, writer: &mut W) { - use self::StyleSource::*; - - if let Style(ref rule) = *self { + if let Some(ref rule) = self.0.as_first() { let rule = rule.read_with(guard); let _ = write!(writer, "{:?}", rule.selectors); } @@ -134,20 +121,31 @@ impl StyleSource { /// underlying property declaration block. #[inline] pub fn read<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a PropertyDeclarationBlock { - let block = match *self { - StyleSource::Style(ref rule) => &rule.read_with(guard).block, - StyleSource::Declarations(ref block) => block, - StyleSource::None => panic!("Cannot call read on StyleSource::None"), + let block: &Locked = match self.0.borrow() { + ArcUnionBorrow::First(ref rule) => &rule.get().read_with(guard).block, + ArcUnionBorrow::Second(ref block) => block.get(), }; block.read_with(guard) } - /// Indicates if this StyleSource has a value - pub fn is_some(&self) -> bool { - match *self { - StyleSource::None => false, - _ => true, - } + /// Indicates if this StyleSource is a style rule. + pub fn is_rule(&self) -> bool { + self.0.is_first() + } + + /// Indicates if this StyleSource is a PropertyDeclarationBlock. + pub fn is_declarations(&self) -> bool { + self.0.is_second() + } + + /// Returns the style rule if applicable, otherwise None. + pub fn as_rule(&self) -> Option>> { + self.0.as_first() + } + + /// Returns the declaration block if applicable, otherwise None. + pub fn as_declarations(&self) -> Option>> { + self.0.as_second() } } @@ -248,11 +246,12 @@ impl RuleTree { last_cascade_order = shadow_cascade_order; important_inner_shadow.push(SmallVec::new()); } - important_inner_shadow.last_mut().unwrap().push(source.clone()) - } - SameTreeAuthorNormal => { - important_same_tree.push(source.clone()) + important_inner_shadow + .last_mut() + .unwrap() + .push(source.clone()) }, + SameTreeAuthorNormal => important_same_tree.push(source.clone()), UANormal => important_ua.push(source.clone()), UserNormal => important_user.push(source.clone()), StyleAttributeNormal => { @@ -391,7 +390,10 @@ impl RuleTree { // First walk up until the first less-or-equally specific rule. let mut children = SmallVec::<[_; 10]>::new(); while current.get().level > level { - children.push((current.get().source.clone(), current.get().level)); + children.push(( + current.get().source.as_ref().unwrap().clone(), + current.get().level, + )); current = current.parent().unwrap().clone(); } @@ -418,13 +420,14 @@ impl RuleTree { // also equally valid. This is less likely, and would require an // in-place mutation of the source, which is, at best, fiddly, // so let's skip it for now. - let is_here_already = match current.get().source { - StyleSource::Declarations(ref already_here) => { - pdb.with_arc(|arc| Arc::ptr_eq(arc, already_here)) - }, - _ => unreachable!("Replacing non-declarations style?"), - }; - + let current_decls = current + .get() + .source + .as_ref() + .unwrap() + .as_declarations() + .expect("Replacing non-declarations style?"); + let is_here_already = ArcBorrow::ptr_eq(&pdb, ¤t_decls); if is_here_already { debug!("Picking the fast path in rule replacement"); return None; @@ -447,7 +450,7 @@ impl RuleTree { if pdb.read_with(level.guard(guards)).any_important() { current = current.ensure_child( self.root.downgrade(), - StyleSource::Declarations(pdb.clone_arc()), + StyleSource::from_declarations(pdb.clone_arc()), level, ); } @@ -455,7 +458,7 @@ impl RuleTree { if pdb.read_with(level.guard(guards)).any_normal() { current = current.ensure_child( self.root.downgrade(), - StyleSource::Declarations(pdb.clone_arc()), + StyleSource::from_declarations(pdb.clone_arc()), level, ); } @@ -491,7 +494,10 @@ impl RuleTree { let mut children = SmallVec::<[_; 10]>::new(); for node in iter { if !node.cascade_level().is_animation() { - children.push((node.get().source.clone(), node.cascade_level())); + children.push(( + node.get().source.as_ref().unwrap().clone(), + node.cascade_level(), + )); } last = node; } @@ -689,7 +695,9 @@ pub struct RuleNode { /// The actual style source, either coming from a selector in a StyleRule, /// or a raw property declaration block (like the style attribute). - source: StyleSource, + /// + /// None for the root node. + source: Option, /// The cascade level this rule is positioned at. level: CascadeLevel, @@ -775,7 +783,7 @@ impl RuleNode { RuleNode { root: Some(root), parent: Some(parent), - source: source, + source: Some(source), level: level, refcount: AtomicUsize::new(1), first_child: AtomicPtr::new(ptr::null_mut()), @@ -789,7 +797,7 @@ impl RuleNode { RuleNode { root: None, parent: None, - source: StyleSource::None, + source: None, level: CascadeLevel::UANormal, refcount: AtomicUsize::new(1), first_child: AtomicPtr::new(ptr::null_mut()), @@ -884,7 +892,10 @@ impl RuleNode { } if self.source.is_some() { - self.source.dump(self.level.guard(guards), writer); + self.source + .as_ref() + .unwrap() + .dump(self.level.guard(guards), writer); } else { if indent != 0 { warn!("How has this happened?"); @@ -986,7 +997,7 @@ impl StrongRuleNode { // WeakRuleNode, and implementing this on WeakRuleNode itself... for child in self.get().iter_children() { let child_node = unsafe { &*child.ptr() }; - if child_node.level == level && child_node.source.ptr_equals(&source) { + if child_node.level == level && child_node.source.as_ref().unwrap() == &source { return child.upgrade(); } last = Some(child); @@ -1026,7 +1037,7 @@ impl StrongRuleNode { // we accessed `last`. next = WeakRuleNode::from_ptr(existing); - if unsafe { &*next.ptr() }.source.ptr_equals(&source) { + if unsafe { &*next.ptr() }.source.as_ref().unwrap() == &source { // That node happens to be for the same style source, use // that, and let node fall out of scope. return next.upgrade(); @@ -1054,8 +1065,8 @@ impl StrongRuleNode { /// Get the style source corresponding to this rule node. May return `None` /// if it's the root node, which means that the node hasn't matched any /// rules. - pub fn style_source(&self) -> &StyleSource { - &self.get().source + pub fn style_source(&self) -> Option<&StyleSource> { + self.get().source.as_ref() } /// The cascade level for this node @@ -1317,6 +1328,8 @@ impl StrongRuleNode { let source = node.style_source(); let declarations = if source.is_some() { source + .as_ref() + .unwrap() .read(node.cascade_level().guard(guards)) .declaration_importance_iter() } else { @@ -1444,7 +1457,7 @@ impl StrongRuleNode { .take_while(|node| node.cascade_level() > CascadeLevel::Animations); let mut result = (LonghandIdSet::new(), false); for node in iter { - let style = node.style_source(); + let style = node.style_source().unwrap(); for (decl, important) in style .read(node.cascade_level().guard(guards)) .declaration_importance_iter() @@ -1464,33 +1477,6 @@ impl StrongRuleNode { } result } - - /// Returns PropertyDeclarationBlock for this node. - /// This function must be called only for animation level node. - fn get_animation_style(&self) -> &Arc> { - debug_assert!( - self.cascade_level().is_animation(), - "The cascade level should be an animation level" - ); - match *self.style_source() { - StyleSource::Declarations(ref block) => block, - StyleSource::Style(_) => unreachable!("animating style should not be a style rule"), - StyleSource::None => unreachable!("animating style should not be none"), - } - } - - /// Returns SMIL override declaration block if exists. - pub fn get_smil_animation_rule(&self) -> Option<&Arc>> { - if cfg!(feature = "servo") { - // Servo has no knowledge of a SMIL rule, so just avoid looking for it. - return None; - } - - self.self_and_ancestors() - .take_while(|node| node.cascade_level() >= CascadeLevel::SMILOverride) - .find(|node| node.cascade_level() == CascadeLevel::SMILOverride) - .map(|node| node.get_animation_style()) - } } /// An iterator over a rule node and its ancestors. diff --git a/components/style/servo/url.rs b/components/style/servo/url.rs index b5eba690d36..c0867122ae3 100644 --- a/components/style/servo/url.rs +++ b/components/style/servo/url.rs @@ -23,7 +23,7 @@ use values::computed::{Context, ToComputedValue}; /// /// However, this approach is still not necessarily optimal: See /// -#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)] +#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize, SpecifiedValueInfo)] 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/stylist.rs b/components/style/stylist.rs index ccd668b0bed..a76a461b73f 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -1523,7 +1523,7 @@ impl Stylist { // just avoid allocating it and calling `apply_declarations` directly, // maybe... let rule_node = self.rule_tree.insert_ordered_rules(iter::once(( - StyleSource::Declarations(declarations), + StyleSource::from_declarations(declarations), CascadeLevel::StyleAttributeNormal, ))); @@ -2177,7 +2177,7 @@ impl CascadeData { .expect("Expected precomputed declarations for the UA level") .get_or_insert_with(&pseudo.canonical(), Vec::new) .push(ApplicableDeclarationBlock::new( - StyleSource::Style(locked.clone()), + StyleSource::from_rule(locked.clone()), self.rules_source_order, CascadeLevel::UANormal, selector.specificity(), @@ -2480,7 +2480,7 @@ impl Rule { level: CascadeLevel, shadow_cascade_order: ShadowCascadeOrder, ) -> ApplicableDeclarationBlock { - let source = StyleSource::Style(self.style_rule.clone()); + let source = StyleSource::from_rule(self.style_rule.clone()); ApplicableDeclarationBlock::new(source, self.source_order, level, self.specificity(), shadow_cascade_order) } diff --git a/components/style/values/computed/length.rs b/components/style/values/computed/length.rs index fd63ec7e666..beb33553d7f 100644 --- a/components/style/values/computed/length.rs +++ b/components/style/values/computed/length.rs @@ -916,7 +916,8 @@ pub type NonNegativeLengthOrPercentageOrNormal = Either Self { - Cursor(CursorKind::Auto) - } - - /// Set `cursor` to `auto` - #[cfg(feature = "gecko")] - #[inline] - pub fn auto() -> Self { - Self { - images: vec![].into_boxed_slice(), - keyword: CursorKind::Auto, - } - } -} - -impl Parse for Cursor { - /// cursor: [auto | default | ...] - #[cfg(feature = "servo")] - fn parse<'i, 't>( - context: &ParserContext, - input: &mut Parser<'i, 't>, - ) -> Result> { - Ok(Cursor(CursorKind::parse(context, input)?)) - } - - /// cursor: [ [ ]?]# [auto | default | ...] - #[cfg(feature = "gecko")] - fn parse<'i, 't>( - context: &ParserContext, - input: &mut Parser<'i, 't>, - ) -> Result> { - let mut images = vec![]; - loop { - match input.try(|input| CursorImage::parse_image(context, input)) { - Ok(image) => images.push(image), - Err(_) => break, - } - input.expect_comma()?; - } - Ok(Self { - images: images.into_boxed_slice(), - keyword: CursorKind::parse(context, input)?, - }) - } -} - -#[cfg(feature = "gecko")] -impl ToCss for Cursor { - fn to_css(&self, dest: &mut CssWriter) -> fmt::Result - where - W: Write, - { - for url in &*self.images { - url.to_css(dest)?; - dest.write_str(", ")?; - } - self.keyword.to_css(dest) - } -} - -impl Parse for CursorKind { - fn parse<'i, 't>( - _context: &ParserContext, - input: &mut Parser<'i, 't>, - ) -> Result> { - let location = input.current_source_location(); - let ident = input.expect_ident()?; - CursorKind::from_css_keyword(&ident).map_err(|_| { - location.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone())) - }) - } -} - -#[cfg(feature = "gecko")] -impl CursorImage { - fn parse_image<'i, 't>( - context: &ParserContext, - input: &mut Parser<'i, 't>, - ) -> Result> { - Ok(Self { - url: SpecifiedImageUrl::parse(context, input)?, - // FIXME(emilio): Should use Number::parse to handle calc() correctly. - hotspot: match input.try(|input| input.expect_number()) { - Ok(number) => Some((number, input.expect_number()?)), - Err(_) => None, - }, - }) - } -} - -#[cfg(feature = "gecko")] -impl ToCss for CursorImage { - fn to_css(&self, dest: &mut CssWriter) -> fmt::Result - where - W: Write, - { - self.url.to_css(dest)?; - if let Some((x, y)) = self.hotspot { - dest.write_str(" ")?; - x.to_css(dest)?; - dest.write_str(" ")?; - y.to_css(dest)?; - } - Ok(()) - } -} +use values::computed::url::ComputedImageUrl; +use values::generics::pointing as generics; /// A computed value for the `caret-color` property. -pub type CaretColor = GenericCaretColor; +pub type CaretColor = generics::CaretColor; + +/// A computed value for the `cursor` property. +pub type Cursor = generics::Cursor; + +/// A computed value for item of `image cursors`. +pub type CursorImage = generics::CursorImage; diff --git a/components/style/values/computed/text.rs b/components/style/values/computed/text.rs index 7afb774effc..f2bcf11fe62 100644 --- a/components/style/values/computed/text.rs +++ b/components/style/values/computed/text.rs @@ -15,8 +15,7 @@ use values::generics::text::InitialLetter as GenericInitialLetter; use values::generics::text::LineHeight as GenericLineHeight; use values::generics::text::MozTabSize as GenericMozTabSize; use values::generics::text::Spacing; -use values::specified::text::{TextDecorationLine, TextEmphasisFillMode}; -use values::specified::text::{TextEmphasisShapeKeyword, TextOverflowSide}; +use values::specified::text::{TextEmphasisFillMode, TextEmphasisShapeKeyword, TextOverflowSide}; pub use values::specified::TextAlignKeyword as TextAlign; pub use values::specified::TextEmphasisPosition; @@ -79,36 +78,6 @@ impl ToCss for TextOverflow { } } -impl ToCss for TextDecorationLine { - fn to_css(&self, dest: &mut CssWriter) -> fmt::Result - where - W: Write, - { - let mut has_any = false; - - macro_rules! write_value { - ($line:path => $css:expr) => { - if self.contains($line) { - if has_any { - dest.write_str(" ")?; - } - dest.write_str($css)?; - has_any = true; - } - }; - } - write_value!(TextDecorationLine::UNDERLINE => "underline"); - write_value!(TextDecorationLine::OVERLINE => "overline"); - write_value!(TextDecorationLine::LINE_THROUGH => "line-through"); - write_value!(TextDecorationLine::BLINK => "blink"); - if !has_any { - dest.write_str("none")?; - } - - Ok(()) - } -} - /// A struct that represents the _used_ value of the text-decoration property. /// /// FIXME(emilio): This is done at style resolution time, though probably should diff --git a/components/style/values/generics/background.rs b/components/style/values/generics/background.rs index 91c6f4ef06c..ad42fcfb555 100644 --- a/components/style/values/generics/background.rs +++ b/components/style/values/generics/background.rs @@ -5,8 +5,8 @@ //! Generic types for CSS values related to backgrounds. /// A generic value for the `background-size` property. -#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, - ToComputedValue, ToCss)] +#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, + PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] pub enum BackgroundSize { /// ` ` Explicit { diff --git a/components/style/values/generics/basic_shape.rs b/components/style/values/generics/basic_shape.rs index 0da3b53f2c8..3bad738c1e6 100644 --- a/components/style/values/generics/basic_shape.rs +++ b/components/style/values/generics/basic_shape.rs @@ -18,7 +18,8 @@ pub type ClippingShape = ShapeSource #[allow(missing_docs)] -#[derive(Animate, Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] +#[derive(Animate, Clone, Copy, Debug, MallocSizeOf, PartialEq, + SpecifiedValueInfo, ToComputedValue, ToCss)] pub enum GeometryBox { FillBox, StrokeBox, @@ -32,7 +33,8 @@ pub type FloatAreaShape = ShapeSource { #[animation(error)] ImageOrUrl(ImageOrUrl), @@ -55,8 +58,8 @@ pub enum ShapeSource { } #[allow(missing_docs)] -#[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, ToComputedValue, - ToCss)] +#[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, + SpecifiedValueInfo, ToComputedValue, ToCss)] pub enum BasicShape { Inset(#[css(field_bound)] InsetRect), Circle(#[css(field_bound)] Circle), @@ -66,7 +69,9 @@ pub enum BasicShape { /// #[allow(missing_docs)] -#[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, ToComputedValue)] +#[css(function = "inset")] +#[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, + SpecifiedValueInfo, ToComputedValue)] pub struct InsetRect { pub rect: Rect, pub round: Option>, @@ -74,8 +79,9 @@ pub struct InsetRect { /// #[allow(missing_docs)] -#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, - ToComputedValue)] +#[css(function)] +#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, + PartialEq, SpecifiedValueInfo, ToComputedValue)] pub struct Circle { pub position: Position, pub radius: ShapeRadius, @@ -83,8 +89,9 @@ pub struct Circle { /// #[allow(missing_docs)] -#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, - ToComputedValue)] +#[css(function)] +#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, + PartialEq, SpecifiedValueInfo, ToComputedValue)] pub struct Ellipse { pub position: Position, pub semiaxis_x: ShapeRadius, @@ -93,8 +100,8 @@ pub struct Ellipse { /// #[allow(missing_docs)] -#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, - ToComputedValue, ToCss)] +#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, + PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] pub enum ShapeRadius { Length(LengthOrPercentage), #[animation(error)] @@ -106,7 +113,9 @@ pub enum ShapeRadius { /// A generic type for representing the `polygon()` function /// /// -#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue)] +#[css(function)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue)] pub struct Polygon { /// The filling rule for a polygon. pub fill: FillRule, @@ -120,7 +129,8 @@ pub struct Polygon { // says that it can also be `inherit` #[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, + SpecifiedValueInfo, ToComputedValue, ToCss)] pub enum FillRule { Nonzero, Evenodd, diff --git a/components/style/values/generics/border.rs b/components/style/values/generics/border.rs index e4442ffdc51..6230a1cf36a 100644 --- a/components/style/values/generics/border.rs +++ b/components/style/values/generics/border.rs @@ -10,7 +10,8 @@ use values::generics::rect::Rect; use values::generics::size::Size; /// A generic value for a single side of a `border-image-width` property. -#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] +#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue, ToCss)] pub enum BorderImageSideWidth { /// `` Length(LengthOrPercentage), @@ -21,17 +22,19 @@ pub enum BorderImageSideWidth { } /// A generic value for the `border-image-slice` property. -#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue)] +#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue)] pub struct BorderImageSlice { /// The offsets. pub offsets: Rect, /// Whether to fill the middle part. + #[value_info(represents_keyword)] pub fill: bool, } /// A generic value for the `border-*-radius` longhand properties. -#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, - ToComputedValue, ToCss)] +#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, + PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] pub struct BorderCornerRadius(#[css(field_bound)] pub Size); impl BorderCornerRadius { @@ -42,8 +45,9 @@ impl BorderCornerRadius { } /// A generic value for the `border-spacing` property. -#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, - ToAnimatedValue, ToAnimatedZero, ToComputedValue, ToCss)] +#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, + PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, + ToComputedValue, ToCss)] pub struct BorderSpacing(#[css(field_bound)] pub Size); impl BorderSpacing { @@ -56,8 +60,8 @@ impl BorderSpacing { /// A generic value for `border-radius`, `outline-radius` and `inset()`. /// /// -#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, - ToComputedValue)] +#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, + PartialEq, SpecifiedValueInfo, ToComputedValue)] pub struct BorderRadius { /// The top left radius. pub top_left: BorderCornerRadius, diff --git a/components/style/values/generics/box.rs b/components/style/values/generics/box.rs index 3c780ea9899..ea79e98eefb 100644 --- a/components/style/values/generics/box.rs +++ b/components/style/values/generics/box.rs @@ -7,8 +7,8 @@ use values::animated::ToAnimatedZero; /// A generic value for the `vertical-align` property. -#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, - ToComputedValue, ToCss)] +#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, + PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] pub enum VerticalAlign { /// `baseline` Baseline, @@ -48,7 +48,8 @@ impl ToAnimatedZero for VerticalAlign { } /// https://drafts.csswg.org/css-animations/#animation-iteration-count -#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue, ToCss)] pub enum AnimationIterationCount { /// A `` value. Number(Number), @@ -57,8 +58,9 @@ pub enum AnimationIterationCount { } /// A generic value for the `perspective` property. -#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, - ToAnimatedValue, ToAnimatedZero, ToComputedValue, ToCss)] +#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, + PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, + ToComputedValue, ToCss)] pub enum Perspective { /// A non-negative length. Length(NonNegativeLength), diff --git a/components/style/values/generics/column.rs b/components/style/values/generics/column.rs index 936349b8786..1d76f6cb552 100644 --- a/components/style/values/generics/column.rs +++ b/components/style/values/generics/column.rs @@ -5,8 +5,9 @@ //! Generic types for the column properties. /// A generic type for `column-count` values. -#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, - ToAnimatedValue, ToAnimatedZero, ToComputedValue, ToCss)] +#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, + PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, + ToComputedValue, ToCss)] pub enum ColumnCount { /// A positive integer. Integer(PositiveInteger), diff --git a/components/style/values/generics/counters.rs b/components/style/values/generics/counters.rs index e47a120b1d5..7373cd8e947 100644 --- a/components/style/values/generics/counters.rs +++ b/components/style/values/generics/counters.rs @@ -11,7 +11,8 @@ use style_traits::{CssWriter, ToCss}; use values::CustomIdent; /// A generic value for the `counter-increment` property. -#[derive(Clone, Debug, Default, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] +#[derive(Clone, Debug, Default, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue, ToCss)] pub struct CounterIncrement(Counters); impl CounterIncrement { @@ -32,7 +33,8 @@ impl Deref for CounterIncrement { } /// A generic value for the `counter-reset` property. -#[derive(Clone, Debug, Default, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] +#[derive(Clone, Debug, Default, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue, ToCss)] pub struct CounterReset(Counters); impl CounterReset { @@ -55,8 +57,9 @@ impl Deref for CounterReset { /// A generic value for lists of counters. /// /// Keyword `none` is represented by an empty vector. -#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue)] -pub struct Counters(Box<[(CustomIdent, I)]>); +#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue)] +pub struct Counters(#[css(if_empty = "none")] Box<[(CustomIdent, I)]>); impl Default for Counters { #[inline] diff --git a/components/style/values/generics/effects.rs b/components/style/values/generics/effects.rs index e306699eeb2..7a76cdeb7bc 100644 --- a/components/style/values/generics/effects.rs +++ b/components/style/values/generics/effects.rs @@ -10,7 +10,8 @@ use style_traits::values::{CssWriter, SequenceWriter, ToCss}; use values::specified::url::SpecifiedUrl; /// A generic value for a single `box-shadow`. -#[derive(Animate, Clone, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, ToAnimatedZero)] +#[derive(Animate, Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToAnimatedValue, ToAnimatedZero)] pub struct BoxShadow { /// The base shadow. pub base: SimpleShadow, @@ -18,13 +19,14 @@ pub struct BoxShadow { pub spread: ShapeLength, /// Whether this is an inset box shadow. #[animation(constant)] + #[value_info(represents_keyword)] pub inset: bool, } /// A generic value for a single `filter`. #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] -#[derive(Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, - ToComputedValue, ToCss)] +#[derive(Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, + SpecifiedValueInfo, ToAnimatedValue, ToComputedValue, ToCss)] pub enum Filter { /// `blur()` #[css(function)] @@ -66,8 +68,8 @@ pub enum Filter { /// /// Contrary to the canonical order from the spec, the color is serialised /// first, like in Gecko and Webkit. -#[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, - ToAnimatedZero, ToCss)] +#[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, + SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, ToCss)] pub struct SimpleShadow { /// Color. pub color: Color, diff --git a/components/style/values/generics/flex.rs b/components/style/values/generics/flex.rs index e1747410f12..1ab53233c44 100644 --- a/components/style/values/generics/flex.rs +++ b/components/style/values/generics/flex.rs @@ -6,8 +6,9 @@ /// A generic value for the `flex-basis` property. #[cfg_attr(feature = "servo", derive(MallocSizeOf))] -#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, PartialEq, ToAnimatedValue, - ToAnimatedZero, ToComputedValue, ToCss)] +#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, PartialEq, + SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, ToComputedValue, + ToCss)] pub enum FlexBasis { /// `content` Content, diff --git a/components/style/values/generics/font.rs b/components/style/values/generics/font.rs index cbcd64502c4..f5e62e0ab5f 100644 --- a/components/style/values/generics/font.rs +++ b/components/style/values/generics/font.rs @@ -11,11 +11,13 @@ use num_traits::One; use parser::{Parse, ParserContext}; use std::fmt::{self, Write}; use std::io::Cursor; -use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; +use style_traits::{CssWriter, KeywordsCollectFn, ParseError}; +use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss}; use values::distance::{ComputeSquaredDistance, SquaredDistance}; /// https://drafts.csswg.org/css-fonts-4/#feature-tag-value -#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue)] +#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue)] pub struct FeatureTagValue { /// A four-character tag, packed into a u32 (one byte per character). pub tag: FontTag, @@ -45,7 +47,8 @@ where /// Variation setting for a single feature, see: /// /// https://drafts.csswg.org/css-fonts-4/#font-variation-settings-def -#[derive(Animate, Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] +#[derive(Animate, Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue, ToCss)] pub struct VariationValue { /// A four-character tag, packed into a u32 (one byte per character). #[animation(constant)] @@ -69,7 +72,8 @@ where /// A value both for font-variation-settings and font-feature-settings. #[css(comma)] -#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] +#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue, ToCss)] pub struct FontSettings(#[css(if_empty = "normal", iterable)] pub Box<[T]>); impl FontSettings { @@ -105,7 +109,8 @@ impl Parse for FontSettings { /// https://drafts.csswg.org/css-fonts-4/#font-variation-settings-def /// https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-feature-settings /// -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue)] pub struct FontTag(pub u32); impl ToCss for FontTag { @@ -177,20 +182,30 @@ where } } +impl SpecifiedValueInfo for KeywordInfo { + fn collect_completion_keywords(f: KeywordsCollectFn) { + ::collect_completion_keywords(f); + } +} + /// CSS font keywords -#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, - ToAnimatedValue, ToAnimatedZero)] +#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, + Parse, PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, + ToCss)] #[allow(missing_docs)] pub enum KeywordSize { + #[css(keyword = "xx-small")] XXSmall, XSmall, Small, Medium, Large, XLarge, + #[css(keyword = "xx-large")] XXLarge, // This is not a real font keyword and will not parse // HTML font-size 7 corresponds to this value + #[css(skip)] XXXLarge, } @@ -208,41 +223,18 @@ impl Default for KeywordSize { } } -impl ToCss for KeywordSize { - fn to_css(&self, dest: &mut CssWriter) -> fmt::Result - where - W: Write, - { - dest.write_str(match *self { - KeywordSize::XXSmall => "xx-small", - KeywordSize::XSmall => "x-small", - KeywordSize::Small => "small", - KeywordSize::Medium => "medium", - KeywordSize::Large => "large", - KeywordSize::XLarge => "x-large", - KeywordSize::XXLarge => "xx-large", - KeywordSize::XXXLarge => { - debug_assert!( - false, - "We should never serialize specified values set via HTML presentation attributes" - ); - "-servo-xxx-large" - }, - }) - } -} - /// A generic value for the `font-style` property. /// /// https://drafts.csswg.org/css-fonts-4/#font-style-prop #[allow(missing_docs)] -#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, - PartialEq, ToAnimatedValue, ToAnimatedZero)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] +#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, + PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero)] pub enum FontStyle { #[animation(error)] Normal, #[animation(error)] Italic, + #[value_info(starts_with_keyword)] Oblique(Angle), } diff --git a/components/style/values/generics/gecko.rs b/components/style/values/generics/gecko.rs index 1591afbfd97..72a8b71d073 100644 --- a/components/style/values/generics/gecko.rs +++ b/components/style/values/generics/gecko.rs @@ -7,7 +7,8 @@ /// A generic value for scroll snap points. #[cfg_attr(feature = "gecko", derive(MallocSizeOf))] -#[derive(Clone, Copy, Debug, PartialEq, ToComputedValue, ToCss)] +#[derive(Clone, Copy, Debug, PartialEq, SpecifiedValueInfo, ToComputedValue, + ToCss)] pub enum ScrollSnapPoint { /// `none` None, diff --git a/components/style/values/generics/grid.rs b/components/style/values/generics/grid.rs index eae06fe58b4..b9ec85ace22 100644 --- a/components/style/values/generics/grid.rs +++ b/components/style/values/generics/grid.rs @@ -18,7 +18,8 @@ use values::specified::grid::parse_line_names; /// A `` type. /// /// -#[derive(Clone, Debug, Default, MallocSizeOf, PartialEq, ToComputedValue)] +#[derive(Clone, Debug, Default, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue)] pub struct GridLine { /// Flag to check whether it's a `span` keyword. pub is_span: bool, @@ -148,7 +149,8 @@ impl Parse for GridLine { #[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, + SpecifiedValueInfo, ToComputedValue, ToCss)] pub enum TrackKeyword { Auto, MaxContent, @@ -159,7 +161,8 @@ pub enum TrackKeyword { /// avoid re-implementing it for the computed type. /// /// -#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue, ToCss)] pub enum TrackBreadth { /// The generic type is almost always a non-negative `` Breadth(L), @@ -187,7 +190,7 @@ impl TrackBreadth { /// generic only to avoid code bloat. It only takes `` /// /// -#[derive(Clone, Debug, MallocSizeOf, PartialEq)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo)] pub enum TrackSize { /// A flexible `` Breadth(TrackBreadth), @@ -195,10 +198,12 @@ pub enum TrackSize { /// and a flexible `` /// /// + #[css(function)] Minmax(TrackBreadth, TrackBreadth), /// A `fit-content` function. /// /// + #[css(function)] FitContent(L), } @@ -378,7 +383,9 @@ impl Parse for RepeatCount { /// /// It can also hold `repeat()` function parameters, which expands into the respective /// values in its computed form. -#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue)] +#[css(function = "repeat")] pub struct TrackRepeat { /// The number of times for the value to be repeated (could also be `auto-fit` or `auto-fill`) pub count: RepeatCount, @@ -464,7 +471,8 @@ impl TrackRepeat { } /// Track list values. Can be or -#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue, ToCss)] pub enum TrackListValue { /// A value. TrackSize(TrackSize), @@ -497,12 +505,13 @@ pub enum TrackListType { /// A grid `` type. /// /// -#[derive(Clone, Debug, MallocSizeOf, PartialEq)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo)] pub struct TrackList { /// The type of this `` (auto, explicit or general). /// /// In order to avoid parsing the same value multiple times, this does a single traversal /// and arrives at the type of value it has parsed (or bails out gracefully with an error). + #[css(skip)] pub list_type: TrackListType, /// A vector of ` | ` values. pub values: Vec>, @@ -569,7 +578,8 @@ impl ToCss for TrackList { /// /// `subgrid [ | repeat( | auto-fill, +) ]+` /// Old spec: https://www.w3.org/TR/2015/WD-css-grid-1-20150917/#typedef-line-name-list -#[derive(Clone, Debug, Default, MallocSizeOf, PartialEq, ToComputedValue)] +#[derive(Clone, Debug, Default, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue)] pub struct LineNameList { /// The optional `` pub names: Box<[Box<[CustomIdent]>]>, @@ -672,7 +682,8 @@ impl ToCss for LineNameList { /// Variants for ` | ` /// Subgrid deferred to Level 2 spec due to lack of implementation. /// But it's implemented in gecko, so we have to as well. -#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue, ToCss)] pub enum GridTemplateComponent { /// `none` value. None, diff --git a/components/style/values/generics/image.rs b/components/style/values/generics/image.rs index 2cbb8b14112..2da4d290039 100644 --- a/components/style/values/generics/image.rs +++ b/components/style/values/generics/image.rs @@ -16,7 +16,7 @@ use values::serialize_atom_identifier; /// An [image]. /// /// [image]: https://drafts.csswg.org/css-images/#image-values -#[derive(Clone, MallocSizeOf, PartialEq, ToComputedValue)] +#[derive(Clone, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] pub enum Image { /// A `` image. Url(ImageUrl), @@ -26,6 +26,7 @@ pub enum Image { /// A `-moz-image-rect` image. Also fairly large and rare. Rect(Box), /// A `-moz-element(# )` + #[css(function = "-moz-element")] Element(Atom), /// A paint worklet image. /// @@ -144,6 +145,8 @@ pub struct PaintWorklet { pub arguments: Vec>, } +impl ::style_traits::SpecifiedValueInfo for PaintWorklet { } + impl ToCss for PaintWorklet { fn to_css(&self, dest: &mut CssWriter) -> fmt::Result where @@ -164,7 +167,8 @@ impl ToCss for PaintWorklet { /// `-moz-image-rect(, top, right, bottom, left);` #[allow(missing_docs)] #[css(comma, function)] -#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue, ToCss)] pub struct MozImageRect { pub url: MozImageRectUrl, pub top: NumberOrPercentage, diff --git a/components/style/values/generics/mod.rs b/components/style/values/generics/mod.rs index 03df2c69278..59d9748ea5b 100644 --- a/components/style/values/generics/mod.rs +++ b/components/style/values/generics/mod.rs @@ -8,7 +8,8 @@ use counter_style::{parse_counter_style_name, Symbols}; use cssparser::Parser; use parser::{Parse, ParserContext}; -use style_traits::{ParseError, StyleParseErrorKind}; +use style_traits::{KeywordsCollectFn, ParseError}; +use style_traits::{SpecifiedValueInfo, StyleParseErrorKind}; use super::CustomIdent; pub mod background; @@ -137,14 +138,32 @@ impl Parse for CounterStyleOrNone { } } +impl SpecifiedValueInfo for CounterStyleOrNone { + fn collect_completion_keywords(f: KeywordsCollectFn) { + // XXX The best approach for implementing this is probably + // having a CounterStyleName type wrapping CustomIdent, and + // put the predefined list for that type in counter_style mod. + // But that's a non-trivial change itself, so we use a simpler + // approach here. + macro_rules! predefined { + ($($name:expr,)+) => { + f(&["none", "symbols", $($name,)+]); + } + } + include!("../../counter_style/predefined.rs"); + } +} + /// A wrapper of Non-negative values. #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] -#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, - PartialOrd, ToAnimatedZero, ToComputedValue, ToCss)] +#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, + PartialEq, PartialOrd, SpecifiedValueInfo, ToAnimatedZero, + ToComputedValue, ToCss)] pub struct NonNegative(pub T); /// A wrapper of greater-than-or-equal-to-one values. #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] -#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, - PartialOrd, ToAnimatedZero, ToComputedValue, ToCss)] +#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, + PartialEq, PartialOrd, SpecifiedValueInfo, ToAnimatedZero, + ToComputedValue, ToCss)] pub struct GreaterThanOrEqualToOne(pub T); diff --git a/components/style/values/generics/pointing.rs b/components/style/values/generics/pointing.rs index 7e55c4a5a75..9d9ec031225 100644 --- a/components/style/values/generics/pointing.rs +++ b/components/style/values/generics/pointing.rs @@ -4,12 +4,79 @@ //! Generic values for pointing properties. +use std::fmt::{self, Write}; +use style_traits::{CssWriter, ToCss}; +use style_traits::cursor::CursorKind; + /// A generic value for the `caret-color` property. -#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, - ToAnimatedValue, ToAnimatedZero, ToComputedValue, ToCss)] +#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, + PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, + ToComputedValue, ToCss)] pub enum CaretColor { /// An explicit color. Color(Color), /// The keyword `auto`. Auto, } + +/// A generic value for the `cursor` property. +/// +/// https://drafts.csswg.org/css-ui/#cursor +#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue)] +pub struct Cursor { + /// The parsed images for the cursor. + pub images: Box<[Image]>, + /// The kind of the cursor [default | help | ...]. + pub keyword: CursorKind, +} + +impl Cursor { + /// Set `cursor` to `auto` + #[inline] + pub fn auto() -> Self { + Self { + images: vec![].into_boxed_slice(), + keyword: CursorKind::Auto, + } + } +} + +impl ToCss for Cursor { + fn to_css(&self, dest: &mut CssWriter) -> fmt::Result + where + W: Write, + { + for image in &*self.images { + image.to_css(dest)?; + dest.write_str(", ")?; + } + self.keyword.to_css(dest) + } +} + +/// A generic value for item of `image cursors`. +#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue)] +pub struct CursorImage { + /// The url to parse images from. + pub url: ImageUrl, + /// The and coordinates. + pub hotspot: Option<(Number, Number)>, +} + +impl ToCss for CursorImage { + fn to_css(&self, dest: &mut CssWriter) -> fmt::Result + where + W: Write, + { + self.url.to_css(dest)?; + if let Some((ref x, ref y)) = self.hotspot { + dest.write_str(" ")?; + x.to_css(dest)?; + dest.write_str(" ")?; + y.to_css(dest)?; + } + Ok(()) + } +} diff --git a/components/style/values/generics/position.rs b/components/style/values/generics/position.rs index aef2d233fd5..67c167c41ab 100644 --- a/components/style/values/generics/position.rs +++ b/components/style/values/generics/position.rs @@ -6,8 +6,8 @@ //! [`position`](https://drafts.csswg.org/css-backgrounds-3/#position) /// A generic type for representing a CSS [position](https://drafts.csswg.org/css-values/#position). -#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, - ToAnimatedZero, ToComputedValue)] +#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, + PartialEq, SpecifiedValueInfo, ToAnimatedZero, ToComputedValue)] pub struct Position { /// The horizontal component of position. pub horizontal: H, @@ -26,8 +26,8 @@ impl Position { } /// A generic value for the `z-index` property. -#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, - ToAnimatedZero, ToComputedValue, ToCss)] +#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, + PartialEq, SpecifiedValueInfo, ToAnimatedZero, ToComputedValue, ToCss)] pub enum ZIndex { /// An integer value. Integer(Integer), diff --git a/components/style/values/generics/rect.rs b/components/style/values/generics/rect.rs index f45ac32ba91..fb67e48a395 100644 --- a/components/style/values/generics/rect.rs +++ b/components/style/values/generics/rect.rs @@ -11,8 +11,8 @@ use style_traits::{CssWriter, ParseError, ToCss}; /// A CSS value made of four components, where its `ToCss` impl will try to /// serialize as few components as possible, like for example in `border-width`. -#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, - ToComputedValue)] +#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, + PartialEq, SpecifiedValueInfo, ToComputedValue)] pub struct Rect(pub T, pub T, pub T, pub T); impl Rect { diff --git a/components/style/values/generics/size.rs b/components/style/values/generics/size.rs index e3632c1075d..ad93b94e65e 100644 --- a/components/style/values/generics/size.rs +++ b/components/style/values/generics/size.rs @@ -8,7 +8,7 @@ use cssparser::Parser; use euclid::Size2D; use parser::ParserContext; use std::fmt::{self, Write}; -use style_traits::{CssWriter, ParseError, ToCss}; +use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, ToCss}; use values::animated::ToAnimatedValue; /// A generic size, for `border-*-radius` longhand properties, or @@ -93,3 +93,7 @@ where )) } } + +impl SpecifiedValueInfo for Size { + const SUPPORTED_TYPES: u8 = L::SUPPORTED_TYPES; +} diff --git a/components/style/values/generics/svg.rs b/components/style/values/generics/svg.rs index 7bc4c6b61eb..9246175068c 100644 --- a/components/style/values/generics/svg.rs +++ b/components/style/values/generics/svg.rs @@ -16,8 +16,8 @@ use values::distance::{ComputeSquaredDistance, SquaredDistance}; /// /// #[animation(no_bound(UrlPaintServer))] -#[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, - ToComputedValue, ToCss)] +#[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, + SpecifiedValueInfo, ToAnimatedValue, ToComputedValue, ToCss)] pub struct SVGPaint { /// The paint source pub kind: SVGPaintKind, @@ -31,8 +31,9 @@ pub struct SVGPaint { /// to have a fallback, Gecko lets the context /// properties have a fallback as well. #[animation(no_bound(UrlPaintServer))] -#[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, - ToAnimatedZero, ToComputedValue, ToCss)] +#[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, + SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, ToComputedValue, + ToCss)] pub enum SVGPaintKind { /// `none` #[animation(error)] @@ -112,8 +113,8 @@ impl Parse for SVGPaint | | for svg which allow unitless length. /// -#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, ToAnimatedZero, - ToComputedValue, ToCss)] +#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToAnimatedValue, ToAnimatedZero, ToComputedValue, ToCss)] pub enum SvgLengthOrPercentageOrNumber { /// | LengthOrPercentage(LengthOrPercentage), @@ -190,8 +191,9 @@ impl Parse } /// An SVG length value supports `context-value` in addition to length. -#[derive(Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, - ToAnimatedZero, ToComputedValue, ToCss)] +#[derive(Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, + SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, ToComputedValue, + ToCss)] pub enum SVGLength { /// ` | | ` Length(LengthType), @@ -200,8 +202,8 @@ pub enum SVGLength { } /// Generic value for stroke-dasharray. -#[derive(Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, - ToComputedValue, ToCss)] +#[derive(Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, + SpecifiedValueInfo, ToAnimatedValue, ToComputedValue, ToCss)] pub enum SVGStrokeDashArray { /// `[ | | ]#` #[css(comma)] @@ -216,8 +218,8 @@ pub enum SVGStrokeDashArray { /// An SVG opacity value accepts `context-{fill,stroke}-opacity` in /// addition to opacity value. -#[derive(Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, ToAnimatedZero, - ToComputedValue, ToCss)] +#[derive(Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, + SpecifiedValueInfo, ToAnimatedZero, ToComputedValue, ToCss)] pub enum SVGOpacity { /// `` Opacity(OpacityType), diff --git a/components/style/values/generics/text.rs b/components/style/values/generics/text.rs index 28a0adc385a..6cc5caaac77 100644 --- a/components/style/values/generics/text.rs +++ b/components/style/values/generics/text.rs @@ -12,7 +12,8 @@ use values::animated::{Animate, Procedure, ToAnimatedZero}; use values::distance::{ComputeSquaredDistance, SquaredDistance}; /// A generic value for the `initial-letter` property. -#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] +#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue, ToCss)] pub enum InitialLetter { /// `normal` Normal, @@ -29,7 +30,8 @@ impl InitialLetter { } /// A generic spacing value for the `letter-spacing` and `word-spacing` properties. -#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] +#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue, ToCss)] pub enum Spacing { /// `normal` Normal, @@ -110,8 +112,8 @@ where } /// A generic value for the `line-height` property. -#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, - ToAnimatedValue, ToCss)] +#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, + PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToCss)] pub enum LineHeight { /// `normal` Normal, @@ -140,8 +142,9 @@ impl LineHeight { } /// A generic value for the `-moz-tab-size` property. -#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, - ToAnimatedValue, ToAnimatedZero, ToComputedValue, ToCss)] +#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, + PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, + ToComputedValue, ToCss)] pub enum MozTabSize { /// A number. Number(Number), diff --git a/components/style/values/generics/transform.rs b/components/style/values/generics/transform.rs index 7c82eea5e1c..ecd40f5a55c 100644 --- a/components/style/values/generics/transform.rs +++ b/components/style/values/generics/transform.rs @@ -15,7 +15,8 @@ use values::specified::length::LengthOrPercentage as SpecifiedLengthOrPercentage /// A generic 2D transformation matrix. #[allow(missing_docs)] -#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] +#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue, ToCss)] #[css(comma, function)] pub struct Matrix { pub a: T, @@ -29,7 +30,8 @@ pub struct Matrix { #[allow(missing_docs)] #[cfg_attr(rustfmt, rustfmt_skip)] #[css(comma, function = "matrix3d")] -#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] +#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue, ToCss)] pub struct Matrix3D { pub m11: T, pub m12: T, pub m13: T, pub m14: T, pub m21: T, pub m22: T, pub m23: T, pub m24: T, @@ -64,8 +66,8 @@ impl> From> for Transform3D { } /// A generic transform origin. -#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, - ToAnimatedZero, ToComputedValue, ToCss)] +#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, + PartialEq, SpecifiedValueInfo, ToAnimatedZero, ToComputedValue, ToCss)] pub struct TransformOrigin { /// The horizontal origin. pub horizontal: H, @@ -78,7 +80,9 @@ pub struct TransformOrigin { /// A generic timing function. /// /// -#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss)] +#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToCss)] +#[value_info(ty = "TIMING_FUNCTION")] pub enum TimingFunction { /// `linear | ease | ease-in | ease-out | ease-in-out` Keyword(TimingKeyword), @@ -93,6 +97,7 @@ pub enum TimingFunction { }, /// `step-start | step-end | steps(, [ start | end ]?)` #[css(comma, function)] + #[value_info(other_values = "step-start,step-end")] Steps(Integer, #[css(skip_if = "is_end")] StepPosition), /// `frames()` #[css(comma, function)] @@ -101,7 +106,8 @@ pub enum TimingFunction { #[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, + SpecifiedValueInfo, ToComputedValue, ToCss)] pub enum TimingKeyword { Linear, Ease, @@ -157,7 +163,8 @@ impl TimingKeyword { } } -#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue, ToCss)] /// A single operation in the list of a `transform` value pub enum TransformOperation { /// Represents a 2D 2x3 matrix. @@ -261,7 +268,8 @@ pub enum TransformOperation }, } -#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue, ToCss)] /// A value of the `transform` property pub struct Transform(#[css(if_empty = "none", iterable)] pub Vec); @@ -554,8 +562,8 @@ pub fn get_normalized_vector_and_angle( } } -#[derive(Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, ToAnimatedZero, - ToComputedValue, ToCss)] +#[derive(Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, + SpecifiedValueInfo, ToAnimatedZero, ToComputedValue, ToCss)] /// A value of the `Rotate` property /// /// @@ -568,8 +576,8 @@ pub enum Rotate { Rotate3D(Number, Number, Number, Angle), } -#[derive(Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, ToAnimatedZero, - ToComputedValue, ToCss)] +#[derive(Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, + SpecifiedValueInfo, ToAnimatedZero, ToComputedValue, ToCss)] /// A value of the `Scale` property /// /// @@ -584,8 +592,8 @@ pub enum Scale { Scale3D(Number, Number, Number), } -#[derive(Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, ToAnimatedZero, - ToComputedValue, ToCss)] +#[derive(Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, + SpecifiedValueInfo, ToAnimatedZero, ToComputedValue, ToCss)] /// A value of the `Translate` property /// /// @@ -601,7 +609,8 @@ pub enum Translate { } #[allow(missing_docs)] -#[derive(Clone, Copy, Debug, MallocSizeOf, Parse, PartialEq, ToComputedValue, ToCss)] +#[derive(Clone, Copy, Debug, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, + ToComputedValue, ToCss)] pub enum TransformStyle { #[cfg(feature = "servo")] Auto, diff --git a/components/style/values/generics/url.rs b/components/style/values/generics/url.rs index a05c28b1f46..5da74a7b087 100644 --- a/components/style/values/generics/url.rs +++ b/components/style/values/generics/url.rs @@ -9,8 +9,9 @@ use parser::{Parse, ParserContext}; use style_traits::ParseError; /// An image url or none, used for example in list-style-image -#[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, - ToAnimatedZero, ToComputedValue, ToCss)] +#[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, + SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, ToComputedValue, + ToCss)] pub enum UrlOrNone { /// `none` None, diff --git a/components/style/values/mod.rs b/components/style/values/mod.rs index 2f4104a08b0..f02242e78d1 100644 --- a/components/style/values/mod.rs +++ b/components/style/values/mod.rs @@ -71,7 +71,7 @@ where /// Convenience void type to disable some properties and values through types. #[cfg_attr(feature = "servo", derive(Deserialize, MallocSizeOf, Serialize))] -#[derive(Clone, Copy, Debug, PartialEq, ToAnimatedValue, ToComputedValue, ToCss)] +#[derive(Clone, Copy, Debug, PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToComputedValue, ToCss)] pub enum Impossible {} // FIXME(nox): This should be derived but the derive code cannot cope @@ -93,8 +93,9 @@ impl Parse for Impossible { } /// A struct representing one of two kinds of values. -#[derive(Animate, Clone, ComputeSquaredDistance, Copy, MallocSizeOf, PartialEq, ToAnimatedValue, - ToAnimatedZero, ToComputedValue, ToCss)] +#[derive(Animate, Clone, ComputeSquaredDistance, Copy, MallocSizeOf, PartialEq, + SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, ToComputedValue, + ToCss)] pub enum Either { /// The first value. First(A), @@ -125,7 +126,8 @@ impl Parse for Either { } /// -#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToComputedValue)] +#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue)] pub struct CustomIdent(pub Atom); impl CustomIdent { @@ -160,7 +162,7 @@ impl ToCss for CustomIdent { } /// -#[derive(Clone, Debug, MallocSizeOf, ToComputedValue)] +#[derive(Clone, Debug, MallocSizeOf, SpecifiedValueInfo, ToComputedValue)] pub enum KeyframesName { /// Ident(CustomIdent), diff --git a/components/style/values/specified/align.rs b/components/style/values/specified/align.rs index 7b9b003a50c..731844bcb52 100644 --- a/components/style/values/specified/align.rs +++ b/components/style/values/specified/align.rs @@ -10,7 +10,7 @@ use cssparser::Parser; use gecko_bindings::structs; use parser::{Parse, ParserContext}; use std::fmt::{self, Write}; -use style_traits::{CssWriter, ParseError, ToCss}; +use style_traits::{CssWriter, KeywordsCollectFn, ParseError, SpecifiedValueInfo, ToCss}; bitflags! { /// Constants shared by multiple CSS Box Alignment properties @@ -191,6 +191,9 @@ impl ContentDistribution { input: &mut Parser<'i, 't>, axis: AxisDirection, ) -> Result> { + // NOTE Please also update the `list_keywords` function below + // when this function is updated. + // Try to parse normal first if input.try(|i| i.expect_ident_matching("normal")).is_ok() { return Ok(ContentDistribution::normal()); @@ -227,6 +230,19 @@ impl ContentDistribution { content_position | overflow_position, )) } + + fn list_keywords(f: KeywordsCollectFn, axis: AxisDirection) { + f(&["normal"]); + if axis == AxisDirection::Block { + list_baseline_keywords(f); + } + list_content_distribution_keywords(f); + list_overflow_position_keywords(f); + f(&["start", "end", "flex-start", "flex-end", "center"]); + if axis == AxisDirection::Inline { + f(&["left", "right"]); + } + } } /// Value for the `align-content` property. @@ -240,6 +256,8 @@ impl Parse for AlignContent { _: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result> { + // NOTE Please also update `impl SpecifiedValueInfo` below when + // this function is updated. Ok(AlignContent(ContentDistribution::parse( input, AxisDirection::Block, @@ -247,6 +265,12 @@ impl Parse for AlignContent { } } +impl SpecifiedValueInfo for AlignContent { + fn collect_completion_keywords(f: KeywordsCollectFn) { + ContentDistribution::list_keywords(f, AxisDirection::Block); + } +} + #[cfg(feature = "gecko")] impl From for AlignContent { fn from(bits: u16) -> Self { @@ -272,6 +296,8 @@ impl Parse for JustifyContent { _: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result> { + // NOTE Please also update `impl SpecifiedValueInfo` below when + // this function is updated. Ok(JustifyContent(ContentDistribution::parse( input, AxisDirection::Inline, @@ -279,6 +305,12 @@ impl Parse for JustifyContent { } } +impl SpecifiedValueInfo for JustifyContent { + fn collect_completion_keywords(f: KeywordsCollectFn) { + ContentDistribution::list_keywords(f, AxisDirection::Inline); + } +} + #[cfg(feature = "gecko")] impl From for JustifyContent { fn from(bits: u16) -> Self { @@ -319,6 +351,9 @@ impl SelfAlignment { input: &mut Parser<'i, 't>, axis: AxisDirection, ) -> Result> { + // NOTE Please also update the `list_keywords` function below + // when this function is updated. + // // // It's weird that this accepts , but not @@ -339,6 +374,13 @@ impl SelfAlignment { let self_position = parse_self_position(input, axis)?; Ok(SelfAlignment(overflow_position | self_position)) } + + fn list_keywords(f: KeywordsCollectFn, axis: AxisDirection) { + list_baseline_keywords(f); + list_auto_normal_stretch(f); + list_overflow_position_keywords(f); + list_self_position_keywords(f, axis); + } } /// The specified value of the align-self property. @@ -352,6 +394,8 @@ impl Parse for AlignSelf { _: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result> { + // NOTE Please also update `impl SpecifiedValueInfo` below when + // this function is updated. Ok(AlignSelf(SelfAlignment::parse( input, AxisDirection::Block, @@ -359,6 +403,12 @@ impl Parse for AlignSelf { } } +impl SpecifiedValueInfo for AlignSelf { + fn collect_completion_keywords(f: KeywordsCollectFn) { + SelfAlignment::list_keywords(f, AxisDirection::Block); + } +} + impl From for AlignSelf { fn from(bits: u8) -> Self { AlignSelf(SelfAlignment(AlignFlags::from_bits_truncate(bits))) @@ -382,6 +432,8 @@ impl Parse for JustifySelf { _: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result> { + // NOTE Please also update `impl SpecifiedValueInfo` below when + // this function is updated. Ok(JustifySelf(SelfAlignment::parse( input, AxisDirection::Inline, @@ -389,6 +441,12 @@ impl Parse for JustifySelf { } } +impl SpecifiedValueInfo for JustifySelf { + fn collect_completion_keywords(f: KeywordsCollectFn) { + SelfAlignment::list_keywords(f, AxisDirection::Inline); + } +} + impl From for JustifySelf { fn from(bits: u8) -> Self { JustifySelf(SelfAlignment(AlignFlags::from_bits_truncate(bits))) @@ -422,6 +480,9 @@ impl Parse for AlignItems { _: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result> { + // NOTE Please also update `impl SpecifiedValueInfo` below when + // this function is updated. + // if let Ok(baseline) = input.try(parse_baseline) { return Ok(AlignItems(baseline)); @@ -440,6 +501,15 @@ impl Parse for AlignItems { } } +impl SpecifiedValueInfo for AlignItems { + fn collect_completion_keywords(f: KeywordsCollectFn) { + list_baseline_keywords(f); + list_normal_stretch(f); + list_overflow_position_keywords(f); + list_self_position_keywords(f, AxisDirection::Block); + } +} + /// Value of the `justify-items` property /// /// @@ -465,6 +535,9 @@ impl Parse for JustifyItems { _: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result> { + // NOTE Please also update `impl SpecifiedValueInfo` below when + // this function is updated. + // // // It's weird that this accepts , but not @@ -492,10 +565,22 @@ impl Parse for JustifyItems { } } +impl SpecifiedValueInfo for JustifyItems { + fn collect_completion_keywords(f: KeywordsCollectFn) { + list_baseline_keywords(f); + list_normal_stretch(f); + list_legacy_keywords(f); + list_overflow_position_keywords(f); + list_self_position_keywords(f, AxisDirection::Inline); + } +} + // auto | normal | stretch fn parse_auto_normal_stretch<'i, 't>( input: &mut Parser<'i, 't>, ) -> Result> { + // NOTE Please also update the `list_auto_normal_stretch` function + // below when this function is updated. try_match_ident_ignore_ascii_case! { input, "auto" => Ok(AlignFlags::AUTO), "normal" => Ok(AlignFlags::NORMAL), @@ -503,16 +588,28 @@ fn parse_auto_normal_stretch<'i, 't>( } } +fn list_auto_normal_stretch(f: KeywordsCollectFn) { + f(&["auto", "normal", "stretch"]); +} + // normal | stretch fn parse_normal_stretch<'i, 't>(input: &mut Parser<'i, 't>) -> Result> { + // NOTE Please also update the `list_normal_stretch` function below + // when this function is updated. try_match_ident_ignore_ascii_case! { input, "normal" => Ok(AlignFlags::NORMAL), "stretch" => Ok(AlignFlags::STRETCH), } } +fn list_normal_stretch(f: KeywordsCollectFn) { + f(&["normal", "stretch"]); +} + // fn parse_baseline<'i, 't>(input: &mut Parser<'i, 't>) -> Result> { + // NOTE Please also update the `list_baseline_keywords` function + // below when this function is updated. try_match_ident_ignore_ascii_case! { input, "baseline" => Ok(AlignFlags::BASELINE), "first" => { @@ -526,10 +623,16 @@ fn parse_baseline<'i, 't>(input: &mut Parser<'i, 't>) -> Result fn parse_content_distribution<'i, 't>( input: &mut Parser<'i, 't>, ) -> Result> { + // NOTE Please also update the `list_content_distribution_keywords` + // function below when this function is updated. try_match_ident_ignore_ascii_case! { input, "stretch" => Ok(AlignFlags::STRETCH), "space-between" => Ok(AlignFlags::SPACE_BETWEEN), @@ -538,21 +641,33 @@ fn parse_content_distribution<'i, 't>( } } +fn list_content_distribution_keywords(f: KeywordsCollectFn) { + f(&["stretch", "space-between", "space-around", "space-evenly"]); +} + // fn parse_overflow_position<'i, 't>( input: &mut Parser<'i, 't>, ) -> Result> { + // NOTE Please also update the `list_overflow_position_keywords` + // function below when this function is updated. try_match_ident_ignore_ascii_case! { input, "safe" => Ok(AlignFlags::SAFE), "unsafe" => Ok(AlignFlags::UNSAFE), } } +fn list_overflow_position_keywords(f: KeywordsCollectFn) { + f(&["safe", "unsafe"]); +} + // | left | right in the inline axis. fn parse_self_position<'i, 't>( input: &mut Parser<'i, 't>, axis: AxisDirection, ) -> Result> { + // NOTE Please also update the `list_self_position_keywords` + // function below when this function is updated. Ok(try_match_ident_ignore_ascii_case! { input, "start" => AlignFlags::START, "end" => AlignFlags::END, @@ -566,9 +681,21 @@ fn parse_self_position<'i, 't>( }) } +fn list_self_position_keywords(f: KeywordsCollectFn, axis: AxisDirection) { + f(&[ + "start", "end", "flex-start", "flex-end", + "center", "self-start", "self-end", + ]); + if axis == AxisDirection::Inline { + f(&["left", "right"]); + } +} + fn parse_left_right_center<'i, 't>( input: &mut Parser<'i, 't>, ) -> Result> { + // NOTE Please also update the `list_legacy_keywords` function below + // when this function is updated. Ok(try_match_ident_ignore_ascii_case! { input, "left" => AlignFlags::LEFT, "right" => AlignFlags::RIGHT, @@ -578,6 +705,8 @@ fn parse_left_right_center<'i, 't>( // legacy | [ legacy && [ left | right | center ] ] fn parse_legacy<'i, 't>(input: &mut Parser<'i, 't>) -> Result> { + // NOTE Please also update the `list_legacy_keywords` function below + // when this function is updated. let flags = try_match_ident_ignore_ascii_case! { input, "legacy" => { let flags = input.try(parse_left_right_center) @@ -593,3 +722,7 @@ fn parse_legacy<'i, 't>(input: &mut Parser<'i, 't>) -> Result); impl AnimationName { @@ -339,7 +341,8 @@ impl Parse for AnimationName { #[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, + SpecifiedValueInfo, ToComputedValue, ToCss)] pub enum ScrollSnapType { None, Mandatory, @@ -348,7 +351,8 @@ pub enum ScrollSnapType { #[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, + SpecifiedValueInfo, ToComputedValue, ToCss)] pub enum OverscrollBehavior { Auto, Contain, @@ -357,13 +361,15 @@ pub enum OverscrollBehavior { #[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, + SpecifiedValueInfo, ToComputedValue, ToCss)] pub enum OverflowClipBox { PaddingBox, ContentBox, } -#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue, ToCss)] /// Provides a rendering hint to the user agent, /// stating what kinds of changes the author expects /// to perform on the element @@ -415,8 +421,9 @@ impl Parse for WillChange { bitflags! { #[cfg_attr(feature = "gecko", derive(MallocSizeOf))] - #[derive(ToComputedValue)] + #[derive(SpecifiedValueInfo, ToComputedValue)] /// These constants match Gecko's `NS_STYLE_TOUCH_ACTION_*` constants. + #[value_info(other_values = "auto,none,manipulation,pan-x,pan-y")] pub struct TouchAction: u8 { /// `none` variant const TOUCH_ACTION_NONE = 1 << 0; @@ -515,7 +522,8 @@ pub fn assert_touch_action_matches() { } bitflags! { - #[derive(MallocSizeOf, ToComputedValue)] + #[derive(MallocSizeOf, SpecifiedValueInfo, ToComputedValue)] + #[value_info(other_values = "none,strict,layout,style,paint")] /// Constants for contain: https://drafts.csswg.org/css-contain/#contain-property pub struct Contain: u8 { /// `layout` variant, turns on layout containment diff --git a/components/style/values/specified/calc.rs b/components/style/values/specified/calc.rs index 45aa3b27145..06c1dba2955 100644 --- a/components/style/values/specified/calc.rs +++ b/components/style/values/specified/calc.rs @@ -9,7 +9,7 @@ use cssparser::{AngleOrNumber, NumberOrPercentage, Parser, Token}; use parser::ParserContext; use std::fmt::{self, Write}; -use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; +use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, StyleParseErrorKind, ToCss}; use style_traits::values::specified::AllowedNumericType; use values::{CSSFloat, CSSInteger}; use values::computed; @@ -150,6 +150,8 @@ impl ToCss for CalcLengthOrPercentage { } } +impl SpecifiedValueInfo for CalcLengthOrPercentage {} + impl CalcNode { /// Tries to parse a single element in the expression, that is, a /// ``, ``, `text - /// a red text decoration - const COLOR_OVERRIDE = 0x10; +macro_rules! impl_text_decoration_line { + { + $( + $(#[$($meta:tt)+])* + $ident:ident / $css:expr => $value:expr, + )+ + } => { + bitflags! { + #[derive(MallocSizeOf, ToComputedValue)] + /// Specified keyword values for the text-decoration-line property. + pub struct TextDecorationLine: u8 { + /// No text decoration line is specified + const NONE = 0; + $( + $(#[$($meta)+])* + const $ident = $value; + )+ + #[cfg(feature = "gecko")] + /// Only set by presentation attributes + /// + /// Setting this will mean that text-decorations use the color + /// specified by `color` in quirks mode. + /// + /// For example, this gives text + /// a red text decoration + const COLOR_OVERRIDE = 0x10; + } + } + + impl Parse for TextDecorationLine { + /// none | [ underline || overline || line-through || blink ] + fn parse<'i, 't>( + _context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result> { + let mut result = TextDecorationLine::NONE; + if input + .try(|input| input.expect_ident_matching("none")) + .is_ok() + { + return Ok(result); + } + + loop { + let result = input.try(|input| { + let ident = input.expect_ident().map_err(|_| ())?; + match_ignore_ascii_case! { ident, + $( + $css => { + if result.contains(TextDecorationLine::$ident) { + Err(()) + } else { + result.insert(TextDecorationLine::$ident); + Ok(()) + } + } + )+ + _ => Err(()), + } + }); + if result.is_err() { + break; + } + } + + if !result.is_empty() { + Ok(result) + } else { + Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) + } + } + } + + impl ToCss for TextDecorationLine { + fn to_css(&self, dest: &mut CssWriter) -> fmt::Result + where + W: Write, + { + if self.is_empty() { + return dest.write_str("none"); + } + + let mut writer = SequenceWriter::new(dest, " "); + $( + if self.contains(TextDecorationLine::$ident) { + writer.raw_item($css)?; + } + )+ + Ok(()) + } + } + + impl SpecifiedValueInfo for TextDecorationLine { + fn collect_completion_keywords(f: KeywordsCollectFn) { + f(&["none", $($css,)+]); + } + } } } +impl_text_decoration_line! { + /// Underline + UNDERLINE / "underline" => 1 << 0, + /// Overline + OVERLINE / "overline" => 1 << 1, + /// Line through + LINE_THROUGH / "line-through" => 1 << 2, + /// Blink + BLINK / "blink" => 1 << 3, +} + #[cfg(feature = "gecko")] impl_bitflags_conversions!(TextDecorationLine); @@ -288,79 +375,18 @@ impl TextDecorationLine { } } -impl Parse for TextDecorationLine { - /// none | [ underline || overline || line-through || blink ] - fn parse<'i, 't>( - _context: &ParserContext, - input: &mut Parser<'i, 't>, - ) -> Result> { - let mut result = TextDecorationLine::NONE; - if input - .try(|input| input.expect_ident_matching("none")) - .is_ok() - { - return Ok(result); - } - - loop { - let result = input.try(|input| { - let ident = input.expect_ident().map_err(|_| ())?; - match_ignore_ascii_case! { ident, - "underline" => { - if result.contains(TextDecorationLine::UNDERLINE) { - Err(()) - } else { - result.insert(TextDecorationLine::UNDERLINE); - Ok(()) - } - } - "overline" => { - if result.contains(TextDecorationLine::OVERLINE) { - Err(()) - } else { - result.insert(TextDecorationLine::OVERLINE); - Ok(()) - } - } - "line-through" => { - if result.contains(TextDecorationLine::LINE_THROUGH) { - Err(()) - } else { - result.insert(TextDecorationLine::LINE_THROUGH); - Ok(()) - } - } - "blink" => { - if result.contains(TextDecorationLine::BLINK) { - Err(()) - } else { - result.insert(TextDecorationLine::BLINK); - Ok(()) - } - } - _ => Err(()), - } - }); - if result.is_err() { - break; - } - } - - if !result.is_empty() { - Ok(result) - } else { - Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) - } - } -} - macro_rules! define_text_align_keyword { - ($($name: ident => $discriminant: expr,)+) => { + ($( + $(#[$($meta:tt)+])* + $name: ident => $discriminant: expr, + )+) => { /// Specified value of text-align keyword value. - #[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, ToComputedValue, ToCss)] + #[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, + SpecifiedValueInfo, ToComputedValue, ToCss)] #[allow(missing_docs)] pub enum TextAlignKeyword { $( + $(#[$($meta)+])* $name = $discriminant, )+ } @@ -391,6 +417,7 @@ define_text_align_keyword! { MozCenter => 6, MozLeft => 7, MozRight => 8, + #[css(skip)] Char => 10, } @@ -417,7 +444,7 @@ impl TextAlignKeyword { /// Specified value of text-align property. #[cfg_attr(feature = "gecko", derive(MallocSizeOf))] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, SpecifiedValueInfo, ToCss)] pub enum TextAlign { /// Keyword value of text-align property. Keyword(TextAlignKeyword), @@ -429,6 +456,7 @@ pub enum TextAlign { /// only set directly on the elements and it has a different handling /// unlike other values. #[cfg(feature = "gecko")] + #[css(skip)] MozCenterOrInherit, } @@ -453,21 +481,6 @@ impl Parse for TextAlign { } } -impl ToCss for TextAlign { - fn to_css(&self, dest: &mut CssWriter) -> fmt::Result - where - W: Write, - { - match *self { - TextAlign::Keyword(key) => key.to_css(dest), - #[cfg(feature = "gecko")] - TextAlign::MatchParent => dest.write_str("match-parent"), - #[cfg(feature = "gecko")] - TextAlign::MozCenterOrInherit => Ok(()), - } - } -} - impl TextAlign { /// Convert an enumerated value coming from Gecko to a `TextAlign`. #[cfg(feature = "gecko")] @@ -534,7 +547,7 @@ impl ToComputedValue for TextAlign { } /// Specified value of text-emphasis-style property. -#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)] pub enum TextEmphasisStyle { /// Keyword(TextEmphasisKeywordValue), @@ -545,7 +558,7 @@ pub enum TextEmphasisStyle { } /// Keyword value for the text-emphasis-style property -#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)] pub enum TextEmphasisKeywordValue { /// Fill(TextEmphasisFillMode), @@ -574,7 +587,8 @@ impl TextEmphasisKeywordValue { } /// Fill mode for the text-emphasis-style property -#[derive(Clone, Copy, Debug, MallocSizeOf, Parse, PartialEq, ToCss)] +#[derive(Clone, Copy, Debug, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, + ToCss)] pub enum TextEmphasisFillMode { /// `filled` Filled, @@ -583,7 +597,8 @@ pub enum TextEmphasisFillMode { } /// Shape keyword for the text-emphasis-style property -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToCss)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, + SpecifiedValueInfo, ToCss)] pub enum TextEmphasisShapeKeyword { /// `dot` Dot, @@ -709,7 +724,8 @@ impl Parse for TextEmphasisStyle { } /// The allowed horizontal values for the `text-emphasis-position` property. -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToComputedValue, ToCss)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, + SpecifiedValueInfo, ToComputedValue, ToCss)] pub enum TextEmphasisHorizontalWritingModeValue { /// Draw marks over the text in horizontal writing mode. Over, @@ -718,7 +734,8 @@ pub enum TextEmphasisHorizontalWritingModeValue { } /// The allowed vertical values for the `text-emphasis-position` property. -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToComputedValue, ToCss)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, + SpecifiedValueInfo, ToComputedValue, ToCss)] pub enum TextEmphasisVerticalWritingModeValue { /// Draws marks to the right of the text in vertical writing mode. Right, @@ -727,7 +744,8 @@ pub enum TextEmphasisVerticalWritingModeValue { } /// Specified value of `text-emphasis-position` property. -#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue, ToCss)] pub struct TextEmphasisPosition( pub TextEmphasisHorizontalWritingModeValue, pub TextEmphasisVerticalWritingModeValue, diff --git a/components/style/values/specified/time.rs b/components/style/values/specified/time.rs index 7fa5c0a52a4..107c45b2d48 100644 --- a/components/style/values/specified/time.rs +++ b/components/style/values/specified/time.rs @@ -7,7 +7,7 @@ use cssparser::{Parser, Token}; use parser::{Parse, ParserContext}; use std::fmt::{self, Write}; -use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; +use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, StyleParseErrorKind, ToCss}; use style_traits::values::specified::AllowedNumericType; use values::CSSFloat; use values::computed::{Context, ToComputedValue}; @@ -165,3 +165,5 @@ impl ToCss for Time { Ok(()) } } + +impl SpecifiedValueInfo for Time {} diff --git a/components/style/values/specified/transform.rs b/components/style/values/specified/transform.rs index 4f4ef1c73df..835d505836c 100644 --- a/components/style/values/specified/transform.rs +++ b/components/style/values/specified/transform.rs @@ -233,7 +233,7 @@ impl Parse for Transform { } /// The specified value of a component of a CSS ``. -#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)] pub enum OriginComponent { /// `center` Center, diff --git a/components/style/values/specified/ui.rs b/components/style/values/specified/ui.rs index b86bab0d81e..fc7ef048082 100644 --- a/components/style/values/specified/ui.rs +++ b/components/style/values/specified/ui.rs @@ -10,7 +10,8 @@ use std::fmt::{self, Write}; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; /// Specified value of `-moz-force-broken-image-icon` -#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue)] +#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue)] pub struct MozForceBrokenImageIcon(pub bool); impl MozForceBrokenImageIcon { diff --git a/components/style_derive/animate.rs b/components/style_derive/animate.rs index e54f1819c99..d591e3db108 100644 --- a/components/style_derive/animate.rs +++ b/components/style_derive/animate.rs @@ -68,7 +68,7 @@ pub fn derive(mut input: DeriveInput) -> Tokens { } fn derive_variant_arm(variant: &VariantInfo) -> Result { - let variant_attrs = cg::parse_variant_attrs::(&variant.ast()); + let variant_attrs = cg::parse_variant_attrs_from_ast::(&variant.ast()); if variant_attrs.error { return Err(()); } diff --git a/components/style_derive/cg.rs b/components/style_derive/cg.rs index ff391c79180..b370a5c55d4 100644 --- a/components/style_derive/cg.rs +++ b/components/style_derive/cg.rs @@ -188,7 +188,7 @@ where } } -pub fn parse_variant_attrs(variant: &VariantAst) -> A +pub fn parse_variant_attrs_from_ast(variant: &VariantAst) -> A where A: FromVariant, { @@ -198,7 +198,14 @@ where fields: variant.fields.clone(), discriminant: variant.discriminant.clone(), }; - match A::from_variant(&v) { + parse_variant_attrs(&v) +} + +pub fn parse_variant_attrs(variant: &Variant) -> A +where + A: FromVariant +{ + match A::from_variant(variant) { Ok(attrs) => attrs, Err(e) => panic!("failed to parse variant attributes: {}", e), } diff --git a/components/style_derive/compute_squared_distance.rs b/components/style_derive/compute_squared_distance.rs index 07408bbcddb..5b414206cda 100644 --- a/components/style_derive/compute_squared_distance.rs +++ b/components/style_derive/compute_squared_distance.rs @@ -26,7 +26,7 @@ pub fn derive(mut input: DeriveInput) -> Tokens { let mut append_error_clause = s.variants().len() > 1; let match_body = s.variants().iter().fold(quote!(), |body, variant| { - let attrs = cg::parse_variant_attrs::(&variant.ast()); + let attrs = cg::parse_variant_attrs_from_ast::(&variant.ast()); if attrs.error { append_error_clause = true; return body; diff --git a/components/style_derive/lib.rs b/components/style_derive/lib.rs index e9d799fe9a9..88f0bbadfb1 100644 --- a/components/style_derive/lib.rs +++ b/components/style_derive/lib.rs @@ -16,6 +16,7 @@ mod animate; mod cg; mod compute_squared_distance; mod parse; +mod specified_value_info; mod to_animated_value; mod to_animated_zero; mod to_computed_value; @@ -62,3 +63,9 @@ pub fn derive_to_css(stream: TokenStream) -> TokenStream { let input = syn::parse(stream).unwrap(); to_css::derive(input).into() } + +#[proc_macro_derive(SpecifiedValueInfo, attributes(css, value_info))] +pub fn derive_specified_value_info(stream: TokenStream) -> TokenStream { + let input = syn::parse(stream).unwrap(); + specified_value_info::derive(input).into() +} diff --git a/components/style_derive/parse.rs b/components/style_derive/parse.rs index fb429a05599..7727d6b89bb 100644 --- a/components/style_derive/parse.rs +++ b/components/style_derive/parse.rs @@ -19,7 +19,11 @@ pub fn derive(input: DeriveInput) -> Tokens { "Parse is only supported for single-variant enums for now" ); - let variant_attrs = cg::parse_variant_attrs::(&variant.ast()); + let variant_attrs = cg::parse_variant_attrs_from_ast::(&variant.ast()); + if variant_attrs.skip { + return match_body; + } + let identifier = cg::to_css_identifier( &variant_attrs.keyword.unwrap_or(variant.ast().ident.as_ref().into()), ); diff --git a/components/style_derive/specified_value_info.rs b/components/style_derive/specified_value_info.rs new file mode 100644 index 00000000000..11ad7a0d1b4 --- /dev/null +++ b/components/style_derive/specified_value_info.rs @@ -0,0 +1,181 @@ +/* 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/. */ + +use cg; +use quote::Tokens; +use syn::{Data, DeriveInput, Fields, Ident, Type}; +use to_css::{CssFieldAttrs, CssInputAttrs, CssVariantAttrs}; + +pub fn derive(mut input: DeriveInput) -> Tokens { + let css_attrs = cg::parse_input_attrs::(&input); + let mut types = vec![]; + let mut values = vec![]; + + let input_ident = input.ident; + let input_name = || cg::to_css_identifier(input_ident.as_ref()); + if let Some(function) = css_attrs.function { + values.push(function.explicit().unwrap_or_else(input_name)); + // If the whole value is wrapped in a function, value types of + // its fields should not be propagated. + } else { + let mut where_clause = input.generics.where_clause.take(); + for param in input.generics.type_params() { + cg::add_predicate( + &mut where_clause, + parse_quote!(#param: ::style_traits::SpecifiedValueInfo), + ); + } + input.generics.where_clause = where_clause; + + match input.data { + Data::Enum(ref e) => { + for v in e.variants.iter() { + let css_attrs = cg::parse_variant_attrs::(&v); + let info_attrs = cg::parse_variant_attrs::(&v); + if css_attrs.skip { + continue; + } + if let Some(aliases) = css_attrs.aliases { + for alias in aliases.split(",") { + values.push(alias.to_string()); + } + } + if let Some(other_values) = info_attrs.other_values { + for value in other_values.split(",") { + values.push(value.to_string()); + } + } + let ident = &v.ident; + let variant_name = || cg::to_css_identifier(ident.as_ref()); + if info_attrs.starts_with_keyword { + values.push(variant_name()); + continue; + } + if let Some(keyword) = css_attrs.keyword { + values.push(keyword); + continue; + } + if let Some(function) = css_attrs.function { + values.push(function.explicit().unwrap_or_else(variant_name)); + } else { + if !derive_struct_fields(&v.fields, &mut types, &mut values) { + values.push(variant_name()); + } + } + } + } + Data::Struct(ref s) => { + if !derive_struct_fields(&s.fields, &mut types, &mut values) { + values.push(input_name()); + } + } + Data::Union(_) => unreachable!("union is not supported"), + } + } + + let info_attrs = cg::parse_input_attrs::(&input); + if let Some(other_values) = info_attrs.other_values { + for value in other_values.split(",") { + values.push(value.to_string()); + } + } + + let mut types_value = quote!(0); + types_value.append_all(types.iter().map(|ty| quote! { + | <#ty as ::style_traits::SpecifiedValueInfo>::SUPPORTED_TYPES + })); + + let mut nested_collects = quote!(); + nested_collects.append_all(types.iter().map(|ty| quote! { + <#ty as ::style_traits::SpecifiedValueInfo>::collect_completion_keywords(_f); + })); + + if let Some(ty) = info_attrs.ty { + types_value.append_all(quote! { + | ::style_traits::CssType::#ty + }); + } + + let append_values = if values.is_empty() { + quote!() + } else { + let mut value_list = quote!(); + value_list.append_separated(values.iter(), quote! { , }); + quote! { _f(&[#value_list]); } + }; + + let name = &input.ident; + let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); + quote! { + impl #impl_generics ::style_traits::SpecifiedValueInfo for #name #ty_generics + #where_clause + { + const SUPPORTED_TYPES: u8 = #types_value; + + fn collect_completion_keywords(_f: &mut FnMut(&[&'static str])) { + #nested_collects + #append_values + } + } + } +} + +/// Derive from the given fields. Return false if the fields is a Unit, +/// true otherwise. +fn derive_struct_fields<'a>( + fields: &'a Fields, + types: &mut Vec<&'a Type>, + values: &mut Vec, +) -> bool { + let fields = match *fields { + Fields::Unit => return false, + Fields::Named(ref fields) => fields.named.iter(), + Fields::Unnamed(ref fields) => fields.unnamed.iter(), + }; + types.extend(fields.filter_map(|field| { + let info_attrs = cg::parse_field_attrs::(field); + if let Some(other_values) = info_attrs.other_values { + for value in other_values.split(",") { + values.push(value.to_string()); + } + } + if info_attrs.represents_keyword { + let ident = field.ident.as_ref() + .expect("only named field should use represents_keyword"); + values.push(cg::to_css_identifier(ident.as_ref())); + return None; + } + let css_attrs = cg::parse_field_attrs::(field); + if let Some(if_empty) = css_attrs.if_empty { + values.push(if_empty); + } + if !css_attrs.skip { + Some(&field.ty) + } else { + None + } + })); + true +} + +#[darling(attributes(value_info), default)] +#[derive(Default, FromDeriveInput)] +struct ValueInfoInputAttrs { + ty: Option, + other_values: Option, +} + +#[darling(attributes(value_info), default)] +#[derive(Default, FromVariant)] +struct ValueInfoVariantAttrs { + starts_with_keyword: bool, + other_values: Option, +} + +#[darling(attributes(value_info), default)] +#[derive(Default, FromField)] +struct ValueInfoFieldAttrs { + represents_keyword: bool, + other_values: Option, +} diff --git a/components/style_derive/to_animated_zero.rs b/components/style_derive/to_animated_zero.rs index 9ee786f7ec8..00ddbd2cea6 100644 --- a/components/style_derive/to_animated_zero.rs +++ b/components/style_derive/to_animated_zero.rs @@ -22,7 +22,7 @@ pub fn derive(mut input: syn::DeriveInput) -> quote::Tokens { } let to_body = synstructure::Structure::new(&input).each_variant(|variant| { - let attrs = cg::parse_variant_attrs::(&variant.ast()); + let attrs = cg::parse_variant_attrs_from_ast::(&variant.ast()); if attrs.error { return Some(quote! { Err(()) }); } diff --git a/components/style_derive/to_css.rs b/components/style_derive/to_css.rs index 4f8841810c1..722107da0cd 100644 --- a/components/style_derive/to_css.rs +++ b/components/style_derive/to_css.rs @@ -75,9 +75,12 @@ fn derive_variant_arm( let bindings = variant.bindings(); let identifier = cg::to_css_identifier(variant.ast().ident.as_ref()); let ast = variant.ast(); - let variant_attrs = cg::parse_variant_attrs::(&ast); + let variant_attrs = cg::parse_variant_attrs_from_ast::(&ast); let separator = if variant_attrs.comma { ", " } else { " " }; + if variant_attrs.skip { + return quote!(Ok(())); + } if variant_attrs.dimension { assert_eq!(bindings.len(), 1); assert!( @@ -207,12 +210,12 @@ fn derive_single_field_expr( #[darling(attributes(css), default)] #[derive(Default, FromDeriveInput)] -struct CssInputAttrs { - derive_debug: bool, +pub struct CssInputAttrs { + pub derive_debug: bool, // Here because structs variants are also their whole type definition. - function: Option>, + pub function: Option>, // Here because structs variants are also their whole type definition. - comma: bool, + pub comma: bool, } #[darling(attributes(css), default)] @@ -223,14 +226,15 @@ pub struct CssVariantAttrs { pub dimension: bool, pub keyword: Option, pub aliases: Option, + pub skip: bool, } #[darling(attributes(css), default)] #[derive(Default, FromField)] -struct CssFieldAttrs { - if_empty: Option, - field_bound: bool, - iterable: bool, - skip: bool, - skip_if: Option, +pub struct CssFieldAttrs { + pub if_empty: Option, + pub field_bound: bool, + pub iterable: bool, + pub skip: bool, + pub skip_if: Option, } diff --git a/components/style_traits/Cargo.toml b/components/style_traits/Cargo.toml index a2fafc6e978..67a6c851dce 100644 --- a/components/style_traits/Cargo.toml +++ b/components/style_traits/Cargo.toml @@ -10,7 +10,7 @@ name = "style_traits" path = "lib.rs" [features] -servo = ["serde", "servo_atoms", "cssparser/serde", "webrender_api"] +servo = ["serde", "servo_atoms", "cssparser/serde", "webrender_api", "servo_url"] gecko = [] [dependencies] @@ -24,4 +24,5 @@ selectors = { path = "../selectors" } serde = {version = "1.0", optional = true} webrender_api = {git = "https://github.com/servo/webrender", optional = true} servo_atoms = {path = "../atoms", optional = true} -servo_arc = {path = "../servo_arc" } +servo_arc = { path = "../servo_arc" } +servo_url = { path = "../url", optional = true } diff --git a/components/style_traits/cursor.rs b/components/style_traits/cursor.rs index 3ffd2814382..c8d410ce23b 100644 --- a/components/style_traits/cursor.rs +++ b/components/style_traits/cursor.rs @@ -4,7 +4,7 @@ //! A list of common mouse cursors per CSS3-UI ยง 8.1.1. -use super::{CssWriter, ToCss}; +use super::{CssWriter, KeywordsCollectFn, SpecifiedValueInfo, ToCss}; macro_rules! define_cursor { ( @@ -57,6 +57,15 @@ macro_rules! define_cursor { } } } + + impl SpecifiedValueInfo for CursorKind { + fn collect_completion_keywords(f: KeywordsCollectFn) { + f(&[ + $($c_css,)+ + $($g_css,)+ + ]); + } + } } } diff --git a/components/style_traits/lib.rs b/components/style_traits/lib.rs index 3b7304b1aa7..f232b157cf9 100644 --- a/components/style_traits/lib.rs +++ b/components/style_traits/lib.rs @@ -22,6 +22,7 @@ extern crate selectors; #[cfg(feature = "servo")] extern crate webrender_api; extern crate servo_arc; #[cfg(feature = "servo")] extern crate servo_atoms; +#[cfg(feature = "servo")] extern crate servo_url; #[cfg(feature = "servo")] pub use webrender_api::DevicePixel; @@ -73,11 +74,13 @@ pub enum CSSPixel {} // / desktop_zoom => CSSPixel pub mod cursor; +pub mod specified_value_info; #[macro_use] pub mod values; #[macro_use] pub mod viewport; +pub use specified_value_info::{CssType, KeywordsCollectFn, SpecifiedValueInfo}; pub use values::{Comma, CommaWithSpace, CssWriter, OneOrMoreSeparated, Separator, Space, ToCss}; /// The error type for all CSS parsing routines. diff --git a/components/style_traits/specified_value_info.rs b/components/style_traits/specified_value_info.rs new file mode 100644 index 00000000000..28e1eef25e6 --- /dev/null +++ b/components/style_traits/specified_value_info.rs @@ -0,0 +1,134 @@ +/* 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/. */ + +//! Value information for devtools. + +use servo_arc::Arc; +use std::ops::Range; +use std::sync::Arc as StdArc; + +/// Type of value that a property supports. This is used by Gecko's +/// devtools to make sense about value it parses, and types listed +/// here should match TYPE_* constants in InspectorUtils.webidl. +/// +/// XXX This should really be a bitflags rather than a namespace mod, +/// but currently we cannot use bitflags in const. +#[allow(non_snake_case)] +pub mod CssType { + /// + pub const COLOR: u8 = 1 << 0; + /// + pub const GRADIENT: u8 = 1 << 1; + /// + pub const TIMING_FUNCTION: u8 = 1 << 2; +} + +/// See SpecifiedValueInfo::collect_completion_keywords. +pub type KeywordsCollectFn<'a> = &'a mut FnMut(&[&'static str]); + +/// Information of values of a given specified value type. +/// +/// This trait is derivable with `#[derive(SpecifiedValueInfo)]`. +/// +/// The algorithm traverses the type definition. For `SUPPORTED_TYPES`, +/// it puts an or'ed value of `SUPPORTED_TYPES` of all types it finds. +/// For `collect_completion_keywords`, it recursively invokes this +/// method on types found, and lists all keyword values and function +/// names following the same rule as `ToCss` in that method. +/// +/// Some attributes of `ToCss` can affect the behavior, specifically: +/// * If `#[css(function)]` is found, the content inside the annotated +/// variant (or the whole type) isn't traversed, only the function +/// name is listed in `collect_completion_keywords`. +/// * If `#[css(skip)]` is found, the content inside the variant or +/// field is ignored. +/// * Values listed in `#[css(if_empty)]`, `#[css(aliases)]`, and +/// `#[css(keyword)]` are added into `collect_completion_keywords`. +/// +/// In addition to `css` attributes, it also has `value_info` helper +/// attributes, including: +/// * `#[value_info(ty = "TYPE")]` can be used to specify a constant +/// from `CssType` to `SUPPORTED_TYPES`. +/// * `#[value_info(other_values = "value1,value2")]` can be used to +/// add other values related to a field, variant, or the type itself +/// into `collect_completion_keywords`. +/// * `#[value_info(starts_with_keyword)]` can be used on variants to +/// add the name of a non-unit variant (serialized like `ToCss`) into +/// `collect_completion_keywords`. +/// * `#[value_info(represents_keyword)]` can be used on fields into +/// `collect_completion_keywords`. +pub trait SpecifiedValueInfo { + /// Supported CssTypes by the given value type. + /// + /// XXX This should be typed CssType when that becomes a bitflags. + /// Currently we cannot do so since bitflags cannot be used in constant. + const SUPPORTED_TYPES: u8 = 0; + + /// Collect value starting words for the given specified value type. + /// This includes keyword and function names which can appear at the + /// beginning of a value of this type. + /// + /// Caller should pass in a callback function to accept the list of + /// values. The callback function can be called multiple times, and + /// some values passed to the callback may be duplicate. + fn collect_completion_keywords(_f: KeywordsCollectFn) {} +} + +impl SpecifiedValueInfo for bool {} +impl SpecifiedValueInfo for f32 {} +impl SpecifiedValueInfo for i8 {} +impl SpecifiedValueInfo for i32 {} +impl SpecifiedValueInfo for u8 {} +impl SpecifiedValueInfo for u16 {} +impl SpecifiedValueInfo for u32 {} +impl SpecifiedValueInfo for str {} +impl SpecifiedValueInfo for String {} + +#[cfg(feature = "servo")] +impl SpecifiedValueInfo for ::servo_atoms::Atom {} +#[cfg(feature = "servo")] +impl SpecifiedValueInfo for ::servo_url::ServoUrl {} + +impl SpecifiedValueInfo for Box { + const SUPPORTED_TYPES: u8 = T::SUPPORTED_TYPES; + fn collect_completion_keywords(f: KeywordsCollectFn) { + T::collect_completion_keywords(f); + } +} + +impl SpecifiedValueInfo for [T] { + const SUPPORTED_TYPES: u8 = T::SUPPORTED_TYPES; + fn collect_completion_keywords(f: KeywordsCollectFn) { + T::collect_completion_keywords(f); + } +} + +macro_rules! impl_generic_specified_value_info { + ($ty:ident<$param:ident>) => { + impl<$param: SpecifiedValueInfo> SpecifiedValueInfo for $ty<$param> { + const SUPPORTED_TYPES: u8 = $param::SUPPORTED_TYPES; + fn collect_completion_keywords(f: KeywordsCollectFn) { + $param::collect_completion_keywords(f); + } + } + } +} +impl_generic_specified_value_info!(Option); +impl_generic_specified_value_info!(Vec); +impl_generic_specified_value_info!(Arc); +impl_generic_specified_value_info!(StdArc); +impl_generic_specified_value_info!(Range); + +impl SpecifiedValueInfo for (T1, T2) +where + T1: SpecifiedValueInfo, + T2: SpecifiedValueInfo, +{ + const SUPPORTED_TYPES: u8 = T1::SUPPORTED_TYPES | T2::SUPPORTED_TYPES; + + fn collect_completion_keywords(f: KeywordsCollectFn) { + T1::collect_completion_keywords(f); + T2::collect_completion_keywords(f); + } +} diff --git a/components/style_traits/values.rs b/components/style_traits/values.rs index d6bd05b7b40..481eb1aff6d 100644 --- a/components/style_traits/values.rs +++ b/components/style_traits/values.rs @@ -173,16 +173,10 @@ where Self { inner, separator } } - /// Serialises a CSS value, writing any separator as necessary. - /// - /// The separator is never written before any `item` produces any output, - /// and is written in subsequent calls only if the `item` produces some - /// output on its own again. This lets us handle `Option` fields by - /// just not printing anything on `None`. #[inline] - pub fn item(&mut self, item: &T) -> fmt::Result + fn write_item(&mut self, f: F) -> fmt::Result where - T: ToCss, + F: FnOnce(&mut CssWriter<'b, W>) -> fmt::Result { let old_prefix = self.inner.prefix; if old_prefix.is_none() { @@ -191,7 +185,7 @@ where // to write the separator next time we produce output again. self.inner.prefix = Some(self.separator); } - item.to_css(&mut self.inner)?; + f(self.inner)?; match (old_prefix, self.inner.prefix) { (_, None) => { // This call produced output and cleaned up after itself. @@ -213,6 +207,29 @@ where } Ok(()) } + + /// Serialises a CSS value, writing any separator as necessary. + /// + /// The separator is never written before any `item` produces any output, + /// and is written in subsequent calls only if the `item` produces some + /// output on its own again. This lets us handle `Option` fields by + /// just not printing anything on `None`. + #[inline] + pub fn item(&mut self, item: &T) -> fmt::Result + where + T: ToCss, + { + self.write_item(|inner| item.to_css(inner)) + } + + /// Writes a string as-is (i.e. not escaped or wrapped in quotes) + /// with any separator as necessary. + /// + /// See SequenceWriter::item. + #[inline] + pub fn raw_item(&mut self, item: &str) -> fmt::Result { + self.write_item(|inner| inner.write_str(item)) + } } /// A wrapper type that implements `ToCss` by printing its inner field. diff --git a/ports/geckolib/Cargo.toml b/ports/geckolib/Cargo.toml index a22080ce1c8..8703128ab03 100644 --- a/ports/geckolib/Cargo.toml +++ b/ports/geckolib/Cargo.toml @@ -17,7 +17,6 @@ gecko_debug = ["style/gecko_debug"] atomic_refcell = "0.1" cssparser = "0.23.0" cstr = "0.1.2" -env_logger = {version = "0.5", default-features = false} # disable `regex` to reduce code size libc = "0.2" log = {version = "0.4", features = ["release_max_level_info"]} malloc_size_of = {path = "../../components/malloc_size_of"} diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 04d5a22cd40..e602401c954 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -4,15 +4,14 @@ use cssparser::{ParseErrorKind, Parser, ParserInput, SourceLocation}; use cssparser::ToCss as ParserToCss; -use env_logger::Builder; use malloc_size_of::MallocSizeOfOps; -use nsstring::nsCString; +use nsstring::{nsCString, nsStringRepr}; use selectors::{NthIndexCache, SelectorList}; use selectors::matching::{MatchingContext, MatchingMode, matches_selector}; use servo_arc::{Arc, ArcBorrow, RawOffsetArc}; use smallvec::SmallVec; use std::cell::RefCell; -use std::env; +use std::collections::BTreeSet; use std::fmt::Write; use std::iter; use std::mem; @@ -137,7 +136,7 @@ use style::properties::{parse_one_declaration_into, parse_style_attribute}; use style::properties::animated_properties::AnimationValue; use style::properties::animated_properties::compare_property_priority; use style::rule_cache::RuleCacheConditions; -use style::rule_tree::{CascadeLevel, StrongRuleNode, StyleSource}; +use style::rule_tree::{CascadeLevel, StrongRuleNode}; use style::selector_parser::{PseudoElementCascadeType, SelectorImpl}; use style::shared_lock::{SharedRwLockReadGuard, StylesheetGuards, ToCssWithGuard, Locked}; use style::string_cache::{Atom, WeakAtom}; @@ -164,7 +163,7 @@ use style::values::generics::rect::Rect; use style::values::specified; use style::values::specified::gecko::{IntersectionObserverRootMargin, PixelOrPercentage}; use style::values::specified::source_size_list::SourceSizeList; -use style_traits::{CssWriter, ParsingMode, StyleParseErrorKind, ToCss}; +use style_traits::{CssType, CssWriter, ParsingMode, StyleParseErrorKind, ToCss}; use super::error_reporter::ErrorReporter; use super::stylesheet_loader::{AsyncStylesheetParser, StylesheetLoader}; @@ -184,14 +183,6 @@ static mut DUMMY_URL_DATA: *mut URLExtraData = 0 as *mut URLExtraData; pub extern "C" fn Servo_Initialize(dummy_url_data: *mut URLExtraData) { use style::gecko_bindings::sugar::origin_flags; - // Initialize logging. - let mut builder = Builder::new(); - let default_level = if cfg!(debug_assertions) { "warn" } else { "error" }; - match env::var("RUST_LOG") { - Ok(v) => builder.parse(&v).init(), - _ => builder.parse(default_level).init(), - }; - // Pretend that we're a Servo Layout thread, to make some assertions happy. thread_state::initialize(thread_state::ThreadState::LAYOUT); @@ -938,20 +929,36 @@ pub extern "C" fn Servo_ComputedValues_ExtractAnimationValue( } } +macro_rules! parse_enabled_property_name { + ($prop_name:ident, $found:ident, $default:expr) => {{ + let prop_name = $prop_name.as_ref().unwrap().as_str_unchecked(); + // XXX This can be simplified once Option::filter is stable. + let prop_id = PropertyId::parse(prop_name).ok().and_then(|p| { + if p.enabled_for_all_content() { + Some(p) + } else { + None + } + }); + match prop_id { + Some(p) => { + *$found = true; + p + } + None => { + *$found = false; + return $default; + } + } + }} +} + #[no_mangle] pub unsafe extern "C" fn Servo_Property_IsShorthand( prop_name: *const nsACString, found: *mut bool ) -> bool { - let prop_id = PropertyId::parse(prop_name.as_ref().unwrap().as_str_unchecked()); - let prop_id = match prop_id { - Ok(ref p) if p.enabled_for_all_content() => p, - _ => { - *found = false; - return false; - } - }; - *found = true; + let prop_id = parse_enabled_property_name!(prop_name, found, false); prop_id.is_shorthand() } @@ -974,6 +981,53 @@ pub unsafe extern "C" fn Servo_Property_IsInherited( longhand_id.inherited() } +#[no_mangle] +pub unsafe extern "C" fn Servo_Property_SupportsType( + prop_name: *const nsACString, + ty: u32, + found: *mut bool, +) -> bool { + let prop_id = parse_enabled_property_name!(prop_name, found, false); + // This should match the constants in InspectorUtils. + // (Let's don't bother importing InspectorUtilsBinding into bindings + // because it is not used anywhere else, and issue here would be + // caught by the property-db test anyway.) + let ty = match ty { + 1 => CssType::COLOR, + 2 => CssType::GRADIENT, + 3 => CssType::TIMING_FUNCTION, + _ => unreachable!("unknown CSS type {}", ty), + }; + prop_id.supports_type(ty) +} + +#[no_mangle] +pub unsafe extern "C" fn Servo_Property_GetCSSValuesForProperty( + prop_name: *const nsACString, + found: *mut bool, + result: *mut nsTArray, +) { + let prop_id = parse_enabled_property_name!(prop_name, found, ()); + // Use B-tree set for unique and sorted result. + let mut values = BTreeSet::<&'static str>::new(); + prop_id.collect_property_completion_keywords(&mut |list| values.extend(list.iter())); + + let mut extras = vec![]; + if values.contains("transparent") { + // This is a special value devtools use to avoid inserting the + // long list of color keywords. We need to prepend it to values. + extras.push("COLOR"); + } + + let result = result.as_mut().unwrap(); + let len = extras.len() + values.len(); + bindings::Gecko_ResizeTArrayForStrings(result, len as u32); + + for (src, dest) in extras.iter().chain(values.iter()).zip(result.iter_mut()) { + dest.write_str(src).unwrap(); + } +} + #[no_mangle] pub extern "C" fn Servo_Property_IsAnimatable(property: nsCSSPropertyID) -> bool { use style::properties::animated_properties; @@ -3123,8 +3177,8 @@ pub extern "C" fn Servo_ComputedValues_GetStyleRuleList( let mut result = SmallVec::<[_; 10]>::new(); for node in rule_node.self_and_ancestors() { - let style_rule = match *node.style_source() { - StyleSource::Style(ref rule) => rule, + let style_rule = match node.style_source().and_then(|x| x.as_rule()) { + Some(rule) => rule, _ => continue, }; @@ -3141,9 +3195,11 @@ pub extern "C" fn Servo_ComputedValues_GetStyleRuleList( unsafe { rules.set_len(result.len() as u32) }; for (ref src, ref mut dest) in result.into_iter().zip(rules.iter_mut()) { - src.with_raw_offset_arc(|arc| { - **dest = *Locked::::arc_as_borrowed(arc); - }) + src.with_arc(|a| { + a.with_raw_offset_arc(|arc| { + **dest = *Locked::::arc_as_borrowed(arc); + }) + }); } } diff --git a/ports/geckolib/lib.rs b/ports/geckolib/lib.rs index d48a096df64..79150f62bf7 100644 --- a/ports/geckolib/lib.rs +++ b/ports/geckolib/lib.rs @@ -5,7 +5,6 @@ extern crate cssparser; #[macro_use] extern crate cstr; -extern crate env_logger; extern crate libc; #[macro_use] extern crate log; extern crate malloc_size_of; diff --git a/ports/geckolib/tests/build.rs b/ports/geckolib/tests/build.rs index 7feb9d10405..8de7326b574 100644 --- a/ports/geckolib/tests/build.rs +++ b/ports/geckolib/tests/build.rs @@ -49,7 +49,16 @@ fn main() { // Which is not a problem, but would cause this to not compile. // // Skip this until libclang is updated there. - if &cap[1] == "InvalidateStyleForDocStateChanges" { + // + // Also skip Servo_Element_IsDisplayContents because we + // forward-declare it in Element.h without the type bindgen uses + // to replace it by a reference, and it depends on the include + // order in ServoBindings.h. We have the same problem for + // ComputedStyle_{AddRef / Release}, we just don't hit it + // because they're included later... + if &cap[1] == "InvalidateStyleForDocStateChanges" || + &cap[1] == "Element_IsDisplayContents" + { continue; } w.write_all(format!(" [ Servo_{0}, bindings::Servo_{0} ];\n", &cap[1]).as_bytes()).unwrap(); diff --git a/ports/geckolib/tests/lib.rs b/ports/geckolib/tests/lib.rs index 6fc2b36029c..9981611d17a 100644 --- a/ports/geckolib/tests/lib.rs +++ b/ports/geckolib/tests/lib.rs @@ -14,7 +14,6 @@ extern crate atomic_refcell; extern crate cssparser; #[macro_use] extern crate cstr; -extern crate env_logger; extern crate geckoservo; #[macro_use] extern crate log; extern crate malloc_size_of; diff --git a/ports/geckolib/tests/size_of.rs b/ports/geckolib/tests/size_of.rs index 9691c4cd385..8905650dc2a 100644 --- a/ports/geckolib/tests/size_of.rs +++ b/ports/geckolib/tests/size_of.rs @@ -35,8 +35,8 @@ size_of_test!(test_size_of_element_data, ElementData, 24); size_of_test!(test_size_of_property_declaration, style::properties::PropertyDeclaration, 32); -size_of_test!(test_size_of_application_declaration_block, ApplicableDeclarationBlock, 24); -size_of_test!(test_size_of_rule_node, RuleNode, 80); +size_of_test!(test_size_of_application_declaration_block, ApplicableDeclarationBlock, 16); +size_of_test!(test_size_of_rule_node, RuleNode, 72); // This is huge, but we allocate it on the stack and then never move it, // we only pass `&mut SourcePropertyDeclaration` references around. diff --git a/tests/unit/style/properties/serialization.rs b/tests/unit/style/properties/serialization.rs index 369100aa686..e274d8a2a6a 100644 --- a/tests/unit/style/properties/serialization.rs +++ b/tests/unit/style/properties/serialization.rs @@ -487,42 +487,6 @@ mod shorthand_serialization { } } - mod outline { - use style::values::specified::outline::OutlineStyle; - use super::*; - - #[test] - fn outline_should_show_all_properties_when_set() { - let mut properties = Vec::new(); - - let width = BorderSideWidth::Length(Length::from_px(4f32)); - let style = OutlineStyle::Other(BorderStyle::Solid); - let color = RGBA::new(255, 0, 0, 255).into(); - - properties.push(PropertyDeclaration::OutlineWidth(width)); - properties.push(PropertyDeclaration::OutlineStyle(style)); - properties.push(PropertyDeclaration::OutlineColor(color)); - - let serialization = shorthand_properties_to_string(properties); - assert_eq!(serialization, "outline: 4px solid rgb(255, 0, 0);"); - } - - #[test] - fn outline_should_serialize_correctly_when_style_is_auto() { - let mut properties = Vec::new(); - - let width = BorderSideWidth::Length(Length::from_px(4f32)); - let style = OutlineStyle::Auto; - let color = RGBA::new(255, 0, 0, 255).into(); - properties.push(PropertyDeclaration::OutlineWidth(width)); - properties.push(PropertyDeclaration::OutlineStyle(style)); - properties.push(PropertyDeclaration::OutlineColor(color)); - - let serialization = shorthand_properties_to_string(properties); - assert_eq!(serialization, "outline: 4px auto rgb(255, 0, 0);"); - } - } - mod background { use super::*; diff --git a/tests/unit/style/rule_tree/bench.rs b/tests/unit/style/rule_tree/bench.rs index edc3b70daf4..54af9d39532 100644 --- a/tests/unit/style/rule_tree/bench.rs +++ b/tests/unit/style/rule_tree/bench.rs @@ -62,11 +62,12 @@ fn parse_rules(css: &str) -> Vec<(StyleSource, CascadeLevel)> { let rules = s.contents.rules.read_with(&guard); rules.0.iter().filter_map(|rule| { match *rule { - CssRule::Style(ref style_rule) => Some(style_rule), + CssRule::Style(ref style_rule) => Some(( + StyleSource::from_rule(style_rule.clone()), + CascadeLevel::UserNormal, + )), _ => None, } - }).cloned().map(StyleSource::Style).map(|s| { - (s, CascadeLevel::UserNormal) }).collect() } @@ -78,7 +79,7 @@ fn test_insertion_style_attribute(rule_tree: &RuleTree, rules: &[(StyleSource, C shared_lock: &SharedRwLock) -> StrongRuleNode { let mut rules = rules.to_vec(); - rules.push((StyleSource::Declarations(Arc::new(shared_lock.wrap(PropertyDeclarationBlock::with_one( + rules.push((StyleSource::from_declarations(Arc::new(shared_lock.wrap(PropertyDeclarationBlock::with_one( PropertyDeclaration::Display( longhands::display::SpecifiedValue::Block), Importance::Normal diff --git a/tests/wpt/metadata/css/cssom/shorthand-values.html.ini b/tests/wpt/metadata/css/cssom/shorthand-values.html.ini index cb0502d1dcd..e0b5a48bdb5 100644 --- a/tests/wpt/metadata/css/cssom/shorthand-values.html.ini +++ b/tests/wpt/metadata/css/cssom/shorthand-values.html.ini @@ -26,9 +26,6 @@ [The serialization of border: solid; border-style: dotted should be canonical.] expected: FAIL - [The serialization of outline-width: 2px; outline-style: dotted; outline-color: blue; should be canonical.] - expected: FAIL - [The serialization of list-style-type: circle; list-style-position: inside; list-style-image: initial; should be canonical.] expected: FAIL