From 89fba41e1dcf4b868c3a4bfbe04ac5fdd2bdc68c Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Tue, 17 Apr 2018 21:18:37 +1000 Subject: [PATCH 01/26] style: Support calc in cursor. Bug: 1453258 Reviewed-by: emilio MozReview-Commit-ID: 1ZzxkYboWZg --- components/style/values/computed/pointing.rs | 141 ++---------------- components/style/values/generics/pointing.rs | 64 ++++++++ components/style/values/specified/pointing.rs | 96 +++++++----- 3 files changed, 135 insertions(+), 166 deletions(-) diff --git a/components/style/values/computed/pointing.rs b/components/style/values/computed/pointing.rs index a0102c12070..a89db9104c3 100644 --- a/components/style/values/computed/pointing.rs +++ b/components/style/values/computed/pointing.rs @@ -6,137 +6,16 @@ //! //! https://drafts.csswg.org/css-ui/#pointing-keyboard -use cssparser::Parser; -use parser::{Parse, ParserContext}; -use selectors::parser::SelectorParseErrorKind; -#[cfg(feature = "gecko")] -use std::fmt::{self, Write}; -#[cfg(feature = "gecko")] -use style_traits::{CssWriter, ToCss}; -use style_traits::ParseError; -use style_traits::cursor::CursorKind; +use values::computed::Number; use values::computed::color::Color; -use values::generics::pointing::CaretColor as GenericCaretColor; -#[cfg(feature = "gecko")] -use values::specified::url::SpecifiedImageUrl; - -/// The computed value for the `cursor` property. -/// -/// https://drafts.csswg.org/css-ui/#cursor -pub use values::specified::pointing::Cursor; -#[cfg(feature = "gecko")] -pub use values::specified::pointing::CursorImage; - -impl Cursor { - /// Set `cursor` to `auto` - #[cfg(feature = "servo")] - #[inline] - pub fn auto() -> 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/generics/pointing.rs b/components/style/values/generics/pointing.rs index 7e55c4a5a75..f84e70b7bfa 100644 --- a/components/style/values/generics/pointing.rs +++ b/components/style/values/generics/pointing.rs @@ -4,6 +4,10 @@ //! 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)] @@ -13,3 +17,63 @@ pub enum CaretColor { /// The keyword `auto`. Auto, } + +/// A generic value for the `cursor` property. +/// +/// https://drafts.csswg.org/css-ui/#cursor +#[derive(Clone, Debug, MallocSizeOf, PartialEq, 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, 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/specified/pointing.rs b/components/style/values/specified/pointing.rs index d8da1305efb..cf718a1fd9d 100644 --- a/components/style/values/specified/pointing.rs +++ b/components/style/values/specified/pointing.rs @@ -8,44 +8,15 @@ use cssparser::Parser; use parser::{Parse, ParserContext}; -use style_traits::ParseError; +use style_traits::{ParseError, StyleParseErrorKind}; use style_traits::cursor::CursorKind; -use values::generics::pointing::CaretColor as GenericCaretColor; +use values::generics::pointing as generics; +use values::specified::Number; use values::specified::color::Color; -#[cfg(feature = "gecko")] use values::specified::url::SpecifiedImageUrl; -/// The specified value for the `cursor` property. -/// -/// https://drafts.csswg.org/css-ui/#cursor -#[cfg(feature = "servo")] -#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] -pub struct Cursor(pub CursorKind); - -/// The specified value for the `cursor` property. -/// -/// https://drafts.csswg.org/css-ui/#cursor -#[cfg(feature = "gecko")] -#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue)] -pub struct Cursor { - /// The parsed images for the cursor. - pub images: Box<[CursorImage]>, - /// The kind of the cursor [default | help | ...]. - pub keyword: CursorKind, -} - -/// The specified value for the `image cursors`. -#[cfg(feature = "gecko")] -#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue)] -pub struct CursorImage { - /// The url to parse images from. - pub url: SpecifiedImageUrl, - /// The and coordinates. - pub hotspot: Option<(f32, f32)>, -} - /// A specified value for the `caret-color` property. -pub type CaretColor = GenericCaretColor; +pub type CaretColor = generics::CaretColor; impl Parse for CaretColor { fn parse<'i, 't>( @@ -53,8 +24,63 @@ impl Parse for CaretColor { input: &mut Parser<'i, 't>, ) -> Result> { if input.try(|i| i.expect_ident_matching("auto")).is_ok() { - return Ok(GenericCaretColor::Auto); + return Ok(generics::CaretColor::Auto); } - Ok(GenericCaretColor::Color(Color::parse(context, input)?)) + Ok(generics::CaretColor::Color(Color::parse(context, input)?)) + } +} + +/// A specified value for the `cursor` property. +pub type Cursor = generics::Cursor; + +/// A specified value for item of `image cursors`. +pub type CursorImage = generics::CursorImage; + +impl Parse for Cursor { + /// cursor: [ [ ]?]# [auto | default | ...] + fn parse<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result> { + let mut images = vec![]; + loop { + match input.try(|input| CursorImage::parse(context, input)) { + Ok(image) => images.push(image), + Err(_) => break, + } + input.expect_comma()?; + } + Ok(Self { + images: images.into_boxed_slice(), + keyword: CursorKind::parse(context, input)?, + }) + } +} + +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(StyleParseErrorKind::UnspecifiedError) + }) + } +} + +impl Parse for CursorImage { + fn parse<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result> { + Ok(Self { + url: SpecifiedImageUrl::parse(context, input)?, + hotspot: match input.try(|input| Number::parse(context, input)) { + Ok(number) => Some((number, Number::parse(context, input)?)), + Err(_) => None, + }, + }) } } From cbbefebdba37885315cbb5c5676545369607d5c2 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Fri, 20 Apr 2018 15:48:18 -0700 Subject: [PATCH 02/26] servo_arc: ArcUnion. Bug: 1455784 Reviewed-by: Manishearth MozReview-Commit-ID: Jxp2A7cj6CV --- components/servo_arc/lib.rs | 136 +++++++++++++++++++++++++++++++++++- 1 file changed, 134 insertions(+), 2 deletions(-) diff --git a/components/servo_arc/lib.rs b/components/servo_arc/lib.rs index 04a76c64291..b84ba879350 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(Eq, Debug, 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) } } From 48558e313a018aded1c3985857fefa7ffb11eb76 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Fri, 20 Apr 2018 16:28:33 -0700 Subject: [PATCH 03/26] style: Update StyleSource to use ArcUnion. Bug: 1455784 Reviewed-by: Manishearth MozReview-Commit-ID: AT4sud9goGV --- components/style/applicable_declarations.rs | 2 +- .../style/properties/properties.mako.rs | 2 +- components/style/rule_cache.rs | 22 +-- components/style/rule_tree/mod.rs | 158 ++++++++---------- components/style/stylist.rs | 6 +- ports/geckolib/glue.rs | 14 +- ports/geckolib/tests/size_of.rs | 4 +- 7 files changed, 99 insertions(+), 109 deletions(-) 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/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index 1042a5d1a4d..1f9c3b49513 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -3424,7 +3424,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/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/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/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 04d5a22cd40..f368032eb83 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -137,7 +137,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}; @@ -3123,8 +3123,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 +3141,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/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. From b91ae6b1f9155bd4f17c5403a520568bdf6cac1e Mon Sep 17 00:00:00 2001 From: Brad Werth Date: Thu, 8 Feb 2018 11:00:56 -0800 Subject: [PATCH 04/26] style: support shape-margin. Bug: 1265342 Reviewed-by: xidorn MozReview-Commit-ID: 99pLZsFA9mj --- components/style/properties/longhand/box.mako.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) 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", From 276fb7e04b49e8f420f2c9bc1677256037dbe8b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Tue, 24 Apr 2018 15:41:40 +0200 Subject: [PATCH 05/26] style: Unify MediaList and ServoMediaList. Bug: 1456471 Reviewed-by: xidorn MozReview-Commit-ID: KFWxoohpGlb --- components/style/gecko/data.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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)) } From 7fe7b2ffb16e6a54d04355b3615fc6683ef2c331 Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Thu, 26 Apr 2018 09:01:02 +1000 Subject: [PATCH 06/26] style: Add a ValueInfo trait for exposing types needed by devtools. Most of types just derive it using proc_macro directly. Some of value types need manual impl. In my current plan, this new trait will be used in bug 1434130 to expose values as well. Bug: 1455576 Reviewed-by: emilio MozReview-Commit-ID: LI7fy45VkRw --- components/style/gecko/url.rs | 8 ++- components/style/gecko_string_cache/mod.rs | 3 + components/style/macros.rs | 5 +- components/style/properties/helpers.mako.rs | 35 +++++++-- .../helpers/animated_properties.mako.rs | 4 +- .../style/properties/longhand/font.mako.rs | 3 +- .../style/properties/properties.mako.rs | 34 ++++++++- components/style/values/computed/length.rs | 3 +- .../style/values/generics/background.rs | 4 +- .../style/values/generics/basic_shape.rs | 34 +++++---- components/style/values/generics/border.rs | 19 ++--- components/style/values/generics/box.rs | 12 ++-- components/style/values/generics/column.rs | 5 +- components/style/values/generics/counters.rs | 9 ++- components/style/values/generics/effects.rs | 11 +-- components/style/values/generics/flex.rs | 5 +- components/style/values/generics/font.rs | 20 ++++-- components/style/values/generics/gecko.rs | 3 +- components/style/values/generics/grid.rs | 31 +++++--- components/style/values/generics/image.rs | 5 +- components/style/values/generics/mod.rs | 13 ++-- components/style/values/generics/pointing.rs | 11 +-- components/style/values/generics/position.rs | 8 +-- components/style/values/generics/rect.rs | 4 +- components/style/values/generics/size.rs | 6 +- components/style/values/generics/svg.rs | 26 +++---- components/style/values/generics/text.rs | 15 ++-- components/style/values/generics/transform.rs | 31 ++++---- components/style/values/generics/url.rs | 5 +- components/style/values/mod.rs | 10 +-- components/style/values/specified/align.rs | 26 ++++--- components/style/values/specified/angle.rs | 4 +- .../style/values/specified/background.rs | 6 +- components/style/values/specified/border.rs | 8 ++- components/style/values/specified/box.rs | 27 ++++--- components/style/values/specified/calc.rs | 4 +- components/style/values/specified/color.rs | 11 ++- components/style/values/specified/counters.rs | 6 +- components/style/values/specified/effects.rs | 2 +- components/style/values/specified/font.rs | 59 +++++++++------ components/style/values/specified/grid.rs | 2 +- components/style/values/specified/image.rs | 7 +- .../style/values/specified/inherited_box.rs | 2 +- components/style/values/specified/length.rs | 16 +++-- components/style/values/specified/list.rs | 6 +- components/style/values/specified/mod.rs | 20 ++++-- components/style/values/specified/outline.rs | 4 +- .../style/values/specified/percentage.rs | 4 +- components/style/values/specified/position.rs | 21 +++--- components/style/values/specified/svg.rs | 6 +- components/style/values/specified/table.rs | 3 +- components/style/values/specified/text.rs | 30 ++++---- components/style/values/specified/time.rs | 4 +- .../style/values/specified/transform.rs | 8 ++- components/style/values/specified/ui.rs | 3 +- components/style_derive/animate.rs | 2 +- components/style_derive/cg.rs | 11 ++- .../style_derive/compute_squared_distance.rs | 2 +- components/style_derive/lib.rs | 7 ++ components/style_derive/parse.rs | 2 +- .../style_derive/specified_value_info.rs | 68 ++++++++++++++++++ components/style_derive/to_animated_zero.rs | 2 +- components/style_derive/to_css.rs | 22 +++--- components/style_traits/cursor.rs | 4 +- components/style_traits/lib.rs | 2 + .../style_traits/specified_value_info.rs | 71 +++++++++++++++++++ 66 files changed, 615 insertions(+), 249 deletions(-) create mode 100644 components/style_derive/specified_value_info.rs create mode 100644 components/style_traits/specified_value_info.rs diff --git a/components/style/gecko/url.rs b/components/style/gecko/url.rs index 1b5bc424e4d..a0ecfc7b381 100644 --- a/components/style/gecko/url.rs +++ b/components/style/gecko/url.rs @@ -15,7 +15,7 @@ use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use parser::{Parse, ParserContext}; use servo_arc::{Arc, RawOffsetArc}; use std::mem; -use style_traits::ParseError; +use style_traits::{ParseError, SpecifiedValueInfo}; /// A CSS url() value for gecko. #[css(function = "url")] @@ -120,8 +120,10 @@ impl MallocSizeOf for CssUrl { } } +impl SpecifiedValueInfo 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 +181,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..3c5bb762e1f 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,7 +408,7 @@ } #[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), System(SystemFont), @@ -558,7 +558,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 +570,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)} @@ -634,7 +635,7 @@ #[allow(unused_imports)] use style_traits::{ParseError, StyleParseErrorKind}; #[allow(unused_imports)] - use style_traits::{CssWriter, ToCss}; + use style_traits::{CssWriter, SpecifiedValueInfo, ToCss}; pub struct Longhands { % for sub_property in shorthand.sub_properties: @@ -742,6 +743,26 @@ }) } + <% + sub_properties_for_value_info = shorthand.sub_properties + if shorthand.name == "border": + # border-image subproperties are simply reset by border + # shorthand, so border cannot accept values of them. + # XXX We may want a better mechanism for this, but this + # is probably fine for now. + sub_properties_for_value_info = [ + subprop for subprop in shorthand.sub_properties + if not subprop.name.startswith("border-image") + ] + %> + impl SpecifiedValueInfo for Longhands { + const SUPPORTED_TYPES: u8 = 0 + % for subprop in sub_properties_for_value_info: + | ::SUPPORTED_TYPES + % endfor + ; + } + ${caller.body()} } % endif diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index e2d15139128..059d5a51c1b 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::{ParseError, SpecifiedValueInfo}; use super::ComputedValues; use values::{CSSFloat, CustomIdent, Either}; use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero}; @@ -172,6 +172,8 @@ impl From for TransitionProperty { } } +impl SpecifiedValueInfo for TransitionProperty {} + /// 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/font.mako.rs b/components/style/properties/longhand/font.mako.rs index 0477a2cd0d5..3cd10daf96b 100644 --- a/components/style/properties/longhand/font.mako.rs +++ b/components/style/properties/longhand/font.mako.rs @@ -296,7 +296,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)}, diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index 1f9c3b49513..da1bbb9f149 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, 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,24 @@ 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] + } } impl From for NonCustomPropertyId { @@ -1713,6 +1732,19 @@ 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 non_custom_id: NonCustomPropertyId = match *self { + PropertyId::Custom(_) => return false, + PropertyId::Shorthand(id) => id.into(), + PropertyId::Longhand(id) => id.into(), + PropertyId::ShorthandAlias(id, _) => id.into(), + PropertyId::LonghandAlias(id, _) => id.into(), + }; + non_custom_id.supported_types() & ty != 0 + } } /// A declaration using a CSS-wide keyword. 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 { /// ` ` Explicit { diff --git a/components/style/values/generics/basic_shape.rs b/components/style/values/generics/basic_shape.rs index 0da3b53f2c8..80375ad8ffa 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,8 @@ pub enum BasicShape { /// #[allow(missing_docs)] -#[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, ToComputedValue)] +#[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, + SpecifiedValueInfo, ToComputedValue)] pub struct InsetRect { pub rect: Rect, pub round: Option>, @@ -74,8 +78,8 @@ pub struct InsetRect { /// #[allow(missing_docs)] -#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, - ToComputedValue)] +#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, + PartialEq, SpecifiedValueInfo, ToComputedValue)] pub struct Circle { pub position: Position, pub radius: ShapeRadius, @@ -83,8 +87,8 @@ pub struct Circle { /// #[allow(missing_docs)] -#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, - ToComputedValue)] +#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, + PartialEq, SpecifiedValueInfo, ToComputedValue)] pub struct Ellipse { pub position: Position, pub semiaxis_x: ShapeRadius, @@ -93,8 +97,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 +110,8 @@ pub enum ShapeRadius { /// A generic type for representing the `polygon()` function /// /// -#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue)] pub struct Polygon { /// The filling rule for a polygon. pub fill: FillRule, @@ -120,7 +125,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..79c8713bfba 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,7 +22,8 @@ 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, @@ -30,8 +32,8 @@ pub struct BorderImageSlice { } /// 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 +44,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 +59,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..037834abf6e 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,7 +57,8 @@ 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)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue)] pub struct Counters(Box<[(CustomIdent, I)]>); impl Default for Counters { diff --git a/components/style/values/generics/effects.rs b/components/style/values/generics/effects.rs index e306699eeb2..136f45635c1 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, @@ -23,8 +24,8 @@ pub struct BoxShadow { /// 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 +67,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..738a40a7844 100644 --- a/components/style/values/generics/font.rs +++ b/components/style/values/generics/font.rs @@ -11,11 +11,12 @@ 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, ParseError, 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 +46,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 +71,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 +108,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,9 +181,13 @@ where } } +impl SpecifiedValueInfo for KeywordInfo { + const SUPPORTED_TYPES: u8 = ::SUPPORTED_TYPES; +} + /// CSS font keywords #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, - ToAnimatedValue, ToAnimatedZero)] + ToAnimatedValue, ToAnimatedZero, SpecifiedValueInfo)] #[allow(missing_docs)] pub enum KeywordSize { XXSmall, 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..d805fb5e0d0 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), @@ -343,7 +346,8 @@ where /// The initial argument of the `repeat` function. /// /// -#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] +#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue, ToCss)] pub enum RepeatCount { /// A positive integer. This is allowed only for `` and `` Number(Integer), @@ -378,7 +382,8 @@ 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)] 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 +469,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), @@ -475,7 +481,8 @@ pub enum TrackListValue { /// The type of a `` as determined during parsing. /// /// -#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue)] +#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue)] pub enum TrackListType { /// [``](https://drafts.csswg.org/css-grid/#typedef-auto-track-list) /// @@ -497,7 +504,7 @@ 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). /// @@ -569,7 +576,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 +680,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..4501f94433f 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), @@ -164,7 +164,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..f47b2f29b89 100644 --- a/components/style/values/generics/mod.rs +++ b/components/style/values/generics/mod.rs @@ -79,7 +79,8 @@ impl SymbolsType { /// Since wherever is used, 'none' is a valid value as /// well, we combine them into one type to make code simpler. #[cfg_attr(feature = "gecko", derive(MallocSizeOf))] -#[derive(Clone, Debug, Eq, PartialEq, ToComputedValue, ToCss)] +#[derive(Clone, Debug, Eq, PartialEq, SpecifiedValueInfo, ToComputedValue, + ToCss)] pub enum CounterStyleOrNone { /// `none` None, @@ -139,12 +140,14 @@ impl Parse for CounterStyleOrNone { /// 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 f84e70b7bfa..9d9ec031225 100644 --- a/components/style/values/generics/pointing.rs +++ b/components/style/values/generics/pointing.rs @@ -9,8 +9,9 @@ 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), @@ -21,7 +22,8 @@ pub enum CaretColor { /// A generic value for the `cursor` property. /// /// https://drafts.csswg.org/css-ui/#cursor -#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue)] pub struct Cursor { /// The parsed images for the cursor. pub images: Box<[Image]>, @@ -54,7 +56,8 @@ impl ToCss for Cursor { } /// A generic value for item of `image cursors`. -#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue)] pub struct CursorImage { /// The url to parse images from. pub url: ImageUrl, 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..2c671541ea4 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, @@ -157,7 +159,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 +264,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 +558,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 +572,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 +588,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 +605,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..a61b774bdbf 100644 --- a/components/style/values/mod.rs +++ b/components/style/values/mod.rs @@ -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, ToComputedValue, SpecifiedValueInfo)] pub enum KeyframesName { /// Ident(CustomIdent), diff --git a/components/style/values/specified/align.rs b/components/style/values/specified/align.rs index 7b9b003a50c..a92ca52c8b4 100644 --- a/components/style/values/specified/align.rs +++ b/components/style/values/specified/align.rs @@ -16,7 +16,7 @@ bitflags! { /// Constants shared by multiple CSS Box Alignment properties /// /// These constants match Gecko's `NS_STYLE_ALIGN_*` constants. - #[derive(MallocSizeOf, ToComputedValue)] + #[derive(MallocSizeOf, SpecifiedValueInfo, ToComputedValue)] pub struct AlignFlags: u8 { // Enumeration stored in the lower 5 bits: /// 'auto' @@ -135,7 +135,8 @@ pub enum AxisDirection { /// Shared value for the `align-content` and `justify-content` properties. /// /// -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue, ToCss)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] pub struct ContentDistribution { primary: AlignFlags, @@ -232,7 +233,8 @@ impl ContentDistribution { /// Value for the `align-content` property. /// /// -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue, ToCss)] pub struct AlignContent(pub ContentDistribution); impl Parse for AlignContent { @@ -264,7 +266,8 @@ impl From for u16 { /// Value for the `justify-content` property. /// /// -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue, ToCss)] pub struct JustifyContent(pub ContentDistribution); impl Parse for JustifyContent { @@ -294,7 +297,8 @@ impl From for u16 { } /// -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue, ToCss)] pub struct SelfAlignment(pub AlignFlags); impl SelfAlignment { @@ -344,7 +348,8 @@ impl SelfAlignment { /// The specified value of the align-self property. /// /// -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue, ToCss)] pub struct AlignSelf(pub SelfAlignment); impl Parse for AlignSelf { @@ -374,7 +379,8 @@ impl From for u8 { /// The specified value of the justify-self property. /// /// -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue, ToCss)] pub struct JustifySelf(pub SelfAlignment); impl Parse for JustifySelf { @@ -404,7 +410,8 @@ impl From for u8 { /// Value of the `align-items` property /// /// -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue, ToCss)] pub struct AlignItems(pub AlignFlags); impl AlignItems { @@ -443,7 +450,8 @@ impl Parse for AlignItems { /// Value of the `justify-items` property /// /// -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToCss)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToCss)] pub struct JustifyItems(pub AlignFlags); impl JustifyItems { diff --git a/components/style/values/specified/angle.rs b/components/style/values/specified/angle.rs index 3f49862e406..040ea9d9a7c 100644 --- a/components/style/values/specified/angle.rs +++ b/components/style/values/specified/angle.rs @@ -7,7 +7,7 @@ use cssparser::{Parser, Token}; use parser::{Parse, ParserContext}; use std::fmt::{self, Write}; -use style_traits::{CssWriter, ParseError, ToCss}; +use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, ToCss}; use values::CSSFloat; use values::computed::{Context, ToComputedValue}; use values::computed::angle::Angle as ComputedAngle; @@ -203,3 +203,5 @@ impl Angle { }.map_err(|()| input.new_unexpected_token_error(token.clone())) } } + +impl SpecifiedValueInfo for Angle {} diff --git a/components/style/values/specified/background.rs b/components/style/values/specified/background.rs index 88dbe8a158f..b9feb8b8e27 100644 --- a/components/style/values/specified/background.rs +++ b/components/style/values/specified/background.rs @@ -48,7 +48,8 @@ impl BackgroundSize { } /// One of the keywords for `background-repeat`. -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToComputedValue, ToCss)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, + SpecifiedValueInfo, ToComputedValue, ToCss)] #[allow(missing_docs)] pub enum BackgroundRepeatKeyword { Repeat, @@ -60,7 +61,8 @@ pub enum BackgroundRepeatKeyword { /// The specified value for the `background-repeat` property. /// /// https://drafts.csswg.org/css-backgrounds/#the-background-repeat -#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss)] +#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToCss)] pub enum BackgroundRepeat { /// `repeat-x` RepeatX, diff --git a/components/style/values/specified/border.rs b/components/style/values/specified/border.rs index 4b24b6bb6c4..0713ed99eb9 100644 --- a/components/style/values/specified/border.rs +++ b/components/style/values/specified/border.rs @@ -20,7 +20,7 @@ use values::specified::{AllowQuirks, Number, NumberOrPercentage}; use values::specified::length::{Length, LengthOrPercentage, NonNegativeLength}; /// A specified value for a single side of the `border-width` property. -#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)] pub enum BorderSideWidth { /// `thin` Thin, @@ -189,7 +189,8 @@ impl Parse for BorderSpacing { /// A single border-image-repeat keyword. #[allow(missing_docs)] #[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 BorderImageRepeatKeyword { Stretch, Repeat, @@ -200,7 +201,8 @@ pub enum BorderImageRepeatKeyword { /// The specified value for the `border-image-repeat` property. /// /// https://drafts.csswg.org/css-backgrounds/#the-border-image-repeat -#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue)] +#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue)] pub struct BorderImageRepeat(pub BorderImageRepeatKeyword, pub BorderImageRepeatKeyword); impl ToCss for BorderImageRepeat { diff --git a/components/style/values/specified/box.rs b/components/style/values/specified/box.rs index 0609b6d8607..e26d82c8f67 100644 --- a/components/style/values/specified/box.rs +++ b/components/style/values/specified/box.rs @@ -9,9 +9,8 @@ use cssparser::Parser; use parser::{Parse, ParserContext}; use selectors::parser::SelectorParseErrorKind; use std::fmt::{self, Write}; -use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; -use values::CustomIdent; -use values::KeyframesName; +use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, StyleParseErrorKind, ToCss}; +use values::{CustomIdent, KeyframesName}; use values::generics::box_::AnimationIterationCount as GenericAnimationIterationCount; use values::generics::box_::Perspective as GenericPerspective; use values::generics::box_::VerticalAlign as GenericVerticalAlign; @@ -19,7 +18,8 @@ use values::specified::{AllowQuirks, Number}; use values::specified::length::{LengthOrPercentage, NonNegativeLength}; #[allow(missing_docs)] -#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, ToComputedValue, ToCss)] +#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, + SpecifiedValueInfo, ToComputedValue, ToCss)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] /// Defines an elementโ€™s display type, which consists of /// the two basic qualities of how an element generates boxes @@ -296,7 +296,8 @@ impl AnimationIterationCount { } /// A value for the `animation-name` property. -#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToComputedValue)] +#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue)] pub struct AnimationName(pub Option); impl AnimationName { @@ -339,7 +340,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 +350,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 +360,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 @@ -488,6 +493,8 @@ impl Parse for TouchAction { } } +impl SpecifiedValueInfo for TouchAction {} + #[cfg(feature = "gecko")] impl_bitflags_conversions!(TouchAction); @@ -598,6 +605,8 @@ impl Parse for Contain { } } +impl SpecifiedValueInfo for Contain {} + /// A specified value for the `perspective` property. pub type Perspective = GenericPerspective; 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 /// ``, ``, `(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..86442070ca1 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))] +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..620ba3fee82 100644 --- a/components/style_derive/parse.rs +++ b/components/style_derive/parse.rs @@ -19,7 +19,7 @@ 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()); 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..be3e00f994b --- /dev/null +++ b/components/style_derive/specified_value_info.rs @@ -0,0 +1,68 @@ +/* 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}; +use to_css::{CssFieldAttrs, CssInputAttrs, CssVariantAttrs}; + +pub fn derive(mut input: DeriveInput) -> Tokens { + let attrs = cg::parse_input_attrs::(&input); + let mut types_value = quote!(0); + // If the whole value is wrapped in a function, value types of its + // fields should not be propagated. + if attrs.function.is_none() { + 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 attrs = cg::parse_variant_attrs::(&v); + if attrs.function.is_none() { + derive_struct_fields(&v.fields, &mut types_value); + } + } + } + Data::Struct(ref s) => { + derive_struct_fields(&s.fields, &mut types_value) + } + Data::Union(_) => unreachable!("union is not supported"), + } + } + + 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 derive_struct_fields(fields: &Fields, supports_body: &mut Tokens) { + let fields = match *fields { + Fields::Unit => return, + Fields::Named(ref fields) => fields.named.iter(), + Fields::Unnamed(ref fields) => fields.unnamed.iter(), + }; + supports_body.append_all(fields.map(|field| { + let attrs = cg::parse_field_attrs::(field); + if attrs.skip { + return quote!(); + } + let ty = &field.ty; + quote! { + | <#ty as ::style_traits::SpecifiedValueInfo>::SUPPORTED_TYPES + } + })); +} 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..148599586ed 100644 --- a/components/style_derive/to_css.rs +++ b/components/style_derive/to_css.rs @@ -75,7 +75,7 @@ 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.dimension { @@ -207,12 +207,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)] @@ -227,10 +227,10 @@ pub struct CssVariantAttrs { #[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/cursor.rs b/components/style_traits/cursor.rs index 3ffd2814382..fb529496206 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, SpecifiedValueInfo, ToCss}; macro_rules! define_cursor { ( @@ -57,6 +57,8 @@ macro_rules! define_cursor { } } } + + impl SpecifiedValueInfo for CursorKind {} } } diff --git a/components/style_traits/lib.rs b/components/style_traits/lib.rs index 3b7304b1aa7..bf7a9b59cd9 100644 --- a/components/style_traits/lib.rs +++ b/components/style_traits/lib.rs @@ -73,11 +73,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, 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..d6bc5011483 --- /dev/null +++ b/components/style_traits/specified_value_info.rs @@ -0,0 +1,71 @@ +/* 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; + +/// 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; +} + +/// Information of values of a given specified value type. +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; +} + +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 {} + +impl SpecifiedValueInfo for Box { + const SUPPORTED_TYPES: u8 = T::SUPPORTED_TYPES; +} + +impl SpecifiedValueInfo for [T] { + const SUPPORTED_TYPES: u8 = T::SUPPORTED_TYPES; +} + +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; + } + } +} +impl_generic_specified_value_info!(Option); +impl_generic_specified_value_info!(Vec); +impl_generic_specified_value_info!(Arc); +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; +} From 14b05bead741376797365f3669fa765d9ad878c7 Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Thu, 26 Apr 2018 09:01:02 +1000 Subject: [PATCH 07/26] style: Use Servo side data to back InspectorUtils::CssPropertySupportsType. The only difference in the final result is "all" shorthand, for which the original result is wrong because "all" shorthand doesn't accept any value other than the CSS-wide keywords. Bug: 1455576 Reviewed-by: emilio MozReview-Commit-ID: BmT7kGwC0ZQ --- ports/geckolib/glue.rs | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index f368032eb83..855771dfb82 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -164,7 +164,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}; @@ -974,6 +974,35 @@ 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 = 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; + // 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 extern "C" fn Servo_Property_IsAnimatable(property: nsCSSPropertyID) -> bool { use style::properties::animated_properties; From 29d5c47023451b58f861529c50e3bf42eaa64a12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Thu, 26 Apr 2018 19:11:35 +0200 Subject: [PATCH 08/26] style: followup: Skip a rustest that depends on include order and isn't super-useful. Bug: 1457026 Reviewed-by: bholley MozReview-Commit-ID: 3lwAyl8aztW --- ports/geckolib/tests/build.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) 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(); From 146be22ada5e44bed2e30646cde7828288fd4c3a Mon Sep 17 00:00:00 2001 From: sotaro Date: Fri, 27 Apr 2018 16:48:39 +0900 Subject: [PATCH 09/26] style: Forward webrender error log to gfxCriticalNote. Bug: 1456350 Reviewed-by: bholley --- ports/geckolib/Cargo.toml | 1 - ports/geckolib/glue.rs | 10 ---------- ports/geckolib/lib.rs | 1 - ports/geckolib/tests/lib.rs | 1 - 4 files changed, 13 deletions(-) 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 855771dfb82..d6d6b3d026b 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -4,7 +4,6 @@ use cssparser::{ParseErrorKind, Parser, ParserInput, SourceLocation}; use cssparser::ToCss as ParserToCss; -use env_logger::Builder; use malloc_size_of::MallocSizeOfOps; use nsstring::nsCString; use selectors::{NthIndexCache, SelectorList}; @@ -12,7 +11,6 @@ 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::fmt::Write; use std::iter; use std::mem; @@ -184,14 +182,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); 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/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; From 361046d4facdd1daccba36034ac192c5aaf26151 Mon Sep 17 00:00:00 2001 From: Gerald Squelart Date: Fri, 27 Apr 2018 11:31:25 +1000 Subject: [PATCH 10/26] style: Remove "layout.css.text-combine-upright.enabled" pref. Shipped since Firefox 48, other browsers have similar impls, and the related spec has been in CR since a while ago. The syntax of this property as implemented should be considered to be pretty stable, so we can remove this pref. Bug: 1417761 Reviewed-by: xidorn MozReview-Commit-ID: H7lDsdbUamD --- components/style/properties/longhand/inherited_text.mako.rs | 1 - 1 file changed, 1 deletion(-) 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 From 6e3fa68f46da5b0403d27b426ef92dc5003f7de7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Sat, 28 Apr 2018 09:41:48 +0200 Subject: [PATCH 11/26] style: Fix serialization order of the outline shorthand. This is going to be tested in https://github.com/w3c/web-platform-tests/pull/10700. Bug: 1457652 Reviewed-by: xidorn MozReview-Commit-ID: 7Oi1it70YFw --- components/style/properties/shorthand/outline.mako.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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}; From 3b9c40dd14670baeb9e5d0d255edf8b2243ac605 Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Sun, 29 Apr 2018 09:03:31 +1000 Subject: [PATCH 12/26] style: Skip system font variant for ToCss in font subproperties. System font keywords are not a valid value for those properties. The newly-added #[css(skip)] would be reused by deriving algorithm of SpecifiedValueInfo to skip them as well. Bug: 1434130 Reviewed-by: emilio MozReview-Commit-ID: EmnhkaA9RR5 --- components/style/properties/helpers.mako.rs | 1 + components/style/properties/longhand/font.mako.rs | 5 +++++ components/style/values/specified/font.rs | 13 +++++++++++++ components/style_derive/to_css.rs | 4 ++++ 4 files changed, 23 insertions(+) diff --git a/components/style/properties/helpers.mako.rs b/components/style/properties/helpers.mako.rs index 3c5bb762e1f..2aa93bbb7d3 100644 --- a/components/style/properties/helpers.mako.rs +++ b/components/style/properties/helpers.mako.rs @@ -411,6 +411,7 @@ #[derive(Clone, Copy, Debug, Eq, PartialEq, SpecifiedValueInfo, ToCss)] pub enum SpecifiedValue { Keyword(computed_value::T), + #[css(skip)] System(SystemFont), } diff --git a/components/style/properties/longhand/font.mako.rs b/components/style/properties/longhand/font.mako.rs index 3cd10daf96b..112b4b4de54 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}; diff --git a/components/style/values/specified/font.rs b/components/style/values/specified/font.rs index 3ecc04fcca2..aa41fecaf15 100644 --- a/components/style/values/specified/font.rs +++ b/components/style/values/specified/font.rs @@ -86,6 +86,7 @@ pub enum FontWeight { /// Lighter variant Lighter, /// System font variant. + #[css(skip)] System(SystemFont), } @@ -338,6 +339,7 @@ impl SpecifiedFontStyle { #[allow(missing_docs)] pub enum FontStyle { Specified(SpecifiedFontStyle), + #[css(skip)] System(SystemFont), } @@ -384,6 +386,7 @@ impl Parse for FontStyle { pub enum FontStretch { Stretch(Percentage), Keyword(FontStretchKeyword), + #[css(skip)] System(SystemFont), } @@ -525,6 +528,7 @@ pub enum FontSize { /// font-size: larger Larger, /// Derived from a specified system font. + #[css(skip)] System(SystemFont), } @@ -541,6 +545,7 @@ pub enum FontFamily { #[css(comma)] Values(#[css(iterable)] FontFamilyList), /// System font + #[css(skip)] System(SystemFont), } @@ -632,6 +637,7 @@ pub enum FontSizeAdjust { /// Number variant Number(Number), /// system font + #[css(skip)] System(SystemFont), } @@ -1136,6 +1142,7 @@ pub enum FontVariantAlternates { /// Use alternative glyph from value Value(VariantAlternatesList), /// Use system font glyph + #[css(skip)] System(SystemFont), } @@ -1389,6 +1396,7 @@ pub enum FontVariantEastAsian { /// Value variant with `variant-east-asian` Value(VariantEastAsian), /// System font variant + #[css(skip)] System(SystemFont), } @@ -1617,6 +1625,7 @@ pub enum FontVariantLigatures { /// Value variant with `variant-ligatures` Value(VariantLigatures), /// System font variant + #[css(skip)] System(SystemFont), } @@ -1847,6 +1856,7 @@ pub enum FontVariantNumeric { /// Value variant with `variant-numeric` Value(VariantNumeric), /// System font + #[css(skip)] System(SystemFont), } @@ -1954,6 +1964,7 @@ pub enum FontFeatureSettings { /// Value of `FontSettings` Value(SpecifiedFontFeatureSettings), /// System font + #[css(skip)] System(SystemFont), } @@ -2104,6 +2115,7 @@ pub enum FontLanguageOverride { /// the language system implied by the language of the element Override(Box), /// Use system font + #[css(skip)] System(SystemFont), } @@ -2186,6 +2198,7 @@ pub enum FontVariationSettings { /// Value of `FontSettings` Value(SpecifiedFontVariationSettings), /// System font + #[css(skip)] System(SystemFont), } diff --git a/components/style_derive/to_css.rs b/components/style_derive/to_css.rs index 148599586ed..722107da0cd 100644 --- a/components/style_derive/to_css.rs +++ b/components/style_derive/to_css.rs @@ -78,6 +78,9 @@ fn derive_variant_arm( 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!( @@ -223,6 +226,7 @@ pub struct CssVariantAttrs { pub dimension: bool, pub keyword: Option, pub aliases: Option, + pub skip: bool, } #[darling(attributes(css), default)] From 26c3aeda97cdb03e0bfd59270439399a664650ff Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Sun, 29 Apr 2018 09:03:31 +1000 Subject: [PATCH 13/26] style: Add collect_values function to SpecifiedValueInfo trait for collecting possible values. This is the basic structure of the stuff. Following patches will fill the gap between Gecko and Servo on value generating, and finally hook it into InspectorUtils. Bug: 1434130 Reviewed-by: emilio MozReview-Commit-ID: KNLAfFBiY6e --- .../style/properties/properties.mako.rs | 57 +++++++++--- .../style_derive/specified_value_info.rs | 88 +++++++++++++++---- components/style_traits/lib.rs | 2 +- .../style_traits/specified_value_info.rs | 26 ++++++ ports/geckolib/glue.rs | 66 +++++++++----- 5 files changed, 192 insertions(+), 47 deletions(-) diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index da1bbb9f149..a1d2ee9d085 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -42,7 +42,7 @@ 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}; +use style_traits::{CssWriter, KeywordsCollectFn, ParseError, ParsingMode}; use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss}; use stylesheets::{CssRuleType, Origin, UrlExtraData}; #[cfg(feature = "servo")] use values::Either; @@ -560,6 +560,25 @@ impl NonCustomPropertyId { ]; 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 { @@ -743,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, @@ -1711,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] @@ -1736,14 +1768,19 @@ impl PropertyId { /// 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 non_custom_id: NonCustomPropertyId = match *self { - PropertyId::Custom(_) => return false, - PropertyId::Shorthand(id) => id.into(), - PropertyId::Longhand(id) => id.into(), - PropertyId::ShorthandAlias(id, _) => id.into(), - PropertyId::LonghandAlias(id, _) => id.into(), - }; - non_custom_id.supported_types() & ty != 0 + 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); } } diff --git a/components/style_derive/specified_value_info.rs b/components/style_derive/specified_value_info.rs index be3e00f994b..e5e9ac328da 100644 --- a/components/style_derive/specified_value_info.rs +++ b/components/style_derive/specified_value_info.rs @@ -4,15 +4,21 @@ use cg; use quote::Tokens; -use syn::{Data, DeriveInput, Fields}; +use syn::{Data, DeriveInput, Fields, Type}; use to_css::{CssFieldAttrs, CssInputAttrs, CssVariantAttrs}; pub fn derive(mut input: DeriveInput) -> Tokens { let attrs = cg::parse_input_attrs::(&input); - let mut types_value = quote!(0); - // If the whole value is wrapped in a function, value types of its - // fields should not be propagated. - if attrs.function.is_none() { + 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) = 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( @@ -26,18 +32,55 @@ pub fn derive(mut input: DeriveInput) -> Tokens { Data::Enum(ref e) => { for v in e.variants.iter() { let attrs = cg::parse_variant_attrs::(&v); - if attrs.function.is_none() { - derive_struct_fields(&v.fields, &mut types_value); + if attrs.skip { + continue; + } + if let Some(aliases) = attrs.aliases { + for alias in aliases.split(",") { + values.push(alias.to_string()); + } + } + if let Some(keyword) = attrs.keyword { + values.push(keyword); + continue; + } + let variant_name = || cg::to_css_identifier(v.ident.as_ref()); + if let Some(function) = 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) => { - derive_struct_fields(&s.fields, &mut types_value) + if !derive_struct_fields(&s.fields, &mut types, &mut values) { + values.push(input_name()); + } } Data::Union(_) => unreachable!("union is not supported"), } } + 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); + })); + + 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! { @@ -45,24 +88,37 @@ pub fn derive(mut input: DeriveInput) -> Tokens { #where_clause { const SUPPORTED_TYPES: u8 = #types_value; + + fn collect_completion_keywords(_f: &mut FnMut(&[&'static str])) { + #nested_collects + #append_values + } } } } -fn derive_struct_fields(fields: &Fields, supports_body: &mut Tokens) { +/// 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, + Fields::Unit => return false, Fields::Named(ref fields) => fields.named.iter(), Fields::Unnamed(ref fields) => fields.unnamed.iter(), }; - supports_body.append_all(fields.map(|field| { + types.extend(fields.filter_map(|field| { let attrs = cg::parse_field_attrs::(field); - if attrs.skip { - return quote!(); + if let Some(if_empty) = attrs.if_empty { + values.push(if_empty); } - let ty = &field.ty; - quote! { - | <#ty as ::style_traits::SpecifiedValueInfo>::SUPPORTED_TYPES + if !attrs.skip { + Some(&field.ty) + } else { + None } })); + true } diff --git a/components/style_traits/lib.rs b/components/style_traits/lib.rs index bf7a9b59cd9..8d4e0846cc9 100644 --- a/components/style_traits/lib.rs +++ b/components/style_traits/lib.rs @@ -79,7 +79,7 @@ pub mod values; #[macro_use] pub mod viewport; -pub use specified_value_info::{CssType, SpecifiedValueInfo}; +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 index d6bc5011483..55690ebea5c 100644 --- a/components/style_traits/specified_value_info.rs +++ b/components/style_traits/specified_value_info.rs @@ -23,6 +23,9 @@ pub mod CssType { 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. pub trait SpecifiedValueInfo { /// Supported CssTypes by the given value type. @@ -30,6 +33,15 @@ pub trait SpecifiedValueInfo { /// 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 {} @@ -44,16 +56,25 @@ impl SpecifiedValueInfo for String {} 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); + } } } } @@ -68,4 +89,9 @@ where 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/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index d6d6b3d026b..07d3615d13d 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -5,12 +5,13 @@ use cssparser::{ParseErrorKind, Parser, ParserInput, SourceLocation}; use cssparser::ToCss as ParserToCss; 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::collections::BTreeSet; use std::fmt::Write; use std::iter; use std::mem; @@ -928,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() } @@ -970,16 +987,7 @@ pub unsafe extern "C" fn Servo_Property_SupportsType( ty: u32, 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); // 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 @@ -993,6 +1001,24 @@ pub unsafe extern "C" fn Servo_Property_SupportsType( 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 result = result.as_mut().unwrap(); + bindings::Gecko_ResizeTArrayForStrings(result, values.len() as u32); + for (src, dest) in 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; From eb554044dbd984ed77c4f7bc089e90118ad55857 Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Sun, 29 Apr 2018 09:03:31 +1000 Subject: [PATCH 14/26] style: Add SequenceWriter::item_str for writing str items. This will be used in the next patch for font-variant bitflag types. Bug: 1434130 Reviewed-by: emilio MozReview-Commit-ID: 2IvcsnYBNqA --- components/style_traits/values.rs | 35 +++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 9 deletions(-) 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. From 54d8863e608ea07b5c7da047c95d48cca033d9f1 Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Sun, 29 Apr 2018 09:03:31 +1000 Subject: [PATCH 15/26] style: Use unified lists to impl several bitflag font-variant properties. This also changes their ToCss impl to use SequenceWriter instead of checking has_value manually. SpecifiedValueInfo for those types are also implemented in this patch. Bug: 1434130 Reviewed-by: emilio MozReview-Commit-ID: 23h2VWS417H --- components/style/values/specified/font.rs | 505 ++++++++++------------ 1 file changed, 227 insertions(+), 278 deletions(-) diff --git a/components/style/values/specified/font.rs b/components/style/values/specified/font.rs index aa41fecaf15..7f971f36fcf 100644 --- a/components/style/values/specified/font.rs +++ b/components/style/values/specified/font.rs @@ -1275,33 +1275,84 @@ impl Parse for FontVariantAlternates { } } -bitflags! { - #[derive(MallocSizeOf)] - /// Vairants for east asian variant - pub struct VariantEastAsian: u16 { - /// None of the features - const NORMAL = 0; - /// Enables rendering of JIS78 forms (OpenType feature: jp78) - const JIS78 = 0x01; - /// Enables rendering of JIS83 forms (OpenType feature: jp83). - const JIS83 = 0x02; - /// Enables rendering of JIS90 forms (OpenType feature: jp90). - const JIS90 = 0x04; - /// Enables rendering of JIS2004 forms (OpenType feature: jp04). - const JIS04 = 0x08; - /// Enables rendering of simplified forms (OpenType feature: smpl). - const SIMPLIFIED = 0x10; - /// Enables rendering of traditional forms (OpenType feature: trad). - const TRADITIONAL = 0x20; - /// Enables rendering of full-width variants (OpenType feature: fwid). - const FULL_WIDTH = 0x40; - /// Enables rendering of proportionally-spaced variants (OpenType feature: pwid). - const PROPORTIONAL_WIDTH = 0x80; - /// Enables display of ruby variant glyphs (OpenType feature: ruby). - const RUBY = 0x100; +macro_rules! impl_variant_east_asian { + { + $( + $(#[$($meta:tt)+])* + $ident:ident / $css:expr => $gecko:ident = $value:expr, + )+ + } => { + bitflags! { + #[derive(MallocSizeOf)] + /// Vairants for east asian variant + pub struct VariantEastAsian: u16 { + /// None of the features + const NORMAL = 0; + $( + $(#[$($meta)+])* + const $ident = $value; + )+ + } + } + + impl ToCss for VariantEastAsian { + fn to_css(&self, dest: &mut CssWriter) -> fmt::Result + where + W: Write, + { + if self.is_empty() { + return dest.write_str("normal"); + } + + let mut writer = SequenceWriter::new(dest, " "); + $( + if self.intersects(VariantEastAsian::$ident) { + writer.raw_item($css)?; + } + )+ + Ok(()) + } + } + + /// Asserts that all variant-east-asian matches its NS_FONT_VARIANT_EAST_ASIAN_* value. + #[cfg(feature = "gecko")] + #[inline] + pub fn assert_variant_east_asian_matches() { + use gecko_bindings::structs; + $( + debug_assert_eq!(structs::$gecko as u16, VariantEastAsian::$ident.bits()); + )+ + } + + impl SpecifiedValueInfo for VariantEastAsian { + fn collect_completion_keywords(f: KeywordsCollectFn) { + f(&["normal", $($css,)+]); + } + } } } +impl_variant_east_asian! { + /// Enables rendering of JIS78 forms (OpenType feature: jp78) + JIS78 / "jis78" => NS_FONT_VARIANT_EAST_ASIAN_JIS78 = 0x01, + /// Enables rendering of JIS83 forms (OpenType feature: jp83). + JIS83 / "jis83" => NS_FONT_VARIANT_EAST_ASIAN_JIS83 = 0x02, + /// Enables rendering of JIS90 forms (OpenType feature: jp90). + JIS90 / "jis90" => NS_FONT_VARIANT_EAST_ASIAN_JIS90 = 0x04, + /// Enables rendering of JIS2004 forms (OpenType feature: jp04). + JIS04 / "jis04" => NS_FONT_VARIANT_EAST_ASIAN_JIS04 = 0x08, + /// Enables rendering of simplified forms (OpenType feature: smpl). + SIMPLIFIED / "simplified" => NS_FONT_VARIANT_EAST_ASIAN_SIMPLIFIED = 0x10, + /// Enables rendering of traditional forms (OpenType feature: trad). + TRADITIONAL / "traditional" => NS_FONT_VARIANT_EAST_ASIAN_TRADITIONAL = 0x20, + /// Enables rendering of full-width variants (OpenType feature: fwid). + FULL_WIDTH / "full-width" => NS_FONT_VARIANT_EAST_ASIAN_FULL_WIDTH = 0x40, + /// Enables rendering of proportionally-spaced variants (OpenType feature: pwid). + PROPORTIONAL_WIDTH / "proportional-width" => NS_FONT_VARIANT_EAST_ASIAN_PROP_WIDTH = 0x80, + /// Enables display of ruby variant glyphs (OpenType feature: ruby). + RUBY / "ruby" => NS_FONT_VARIANT_EAST_ASIAN_RUBY = 0x100, +} + #[cfg(feature = "gecko")] impl VariantEastAsian { /// Obtain a specified value from a Gecko keyword value @@ -1317,78 +1368,9 @@ impl VariantEastAsian { } } -impl ToCss for VariantEastAsian { - fn to_css(&self, dest: &mut CssWriter) -> fmt::Result - where - W: Write, - { - if self.is_empty() { - return dest.write_str("normal"); - } - - let mut has_any = false; - - macro_rules! write_value { - ($ident:path => $str:expr) => { - if self.intersects($ident) { - if has_any { - dest.write_str(" ")?; - } - has_any = true; - dest.write_str($str)?; - } - }; - } - - write_value!(VariantEastAsian::JIS78 => "jis78"); - write_value!(VariantEastAsian::JIS83 => "jis83"); - write_value!(VariantEastAsian::JIS90 => "jis90"); - write_value!(VariantEastAsian::JIS04 => "jis04"); - write_value!(VariantEastAsian::SIMPLIFIED => "simplified"); - write_value!(VariantEastAsian::TRADITIONAL => "traditional"); - write_value!(VariantEastAsian::FULL_WIDTH => "full-width"); - write_value!(VariantEastAsian::PROPORTIONAL_WIDTH => "proportional-width"); - write_value!(VariantEastAsian::RUBY => "ruby"); - - debug_assert!(has_any); - Ok(()) - } -} - #[cfg(feature = "gecko")] impl_gecko_keyword_conversions!(VariantEastAsian, u16); -impl SpecifiedValueInfo for VariantEastAsian {} - -/// Asserts that all variant-east-asian matches its NS_FONT_VARIANT_EAST_ASIAN_* value. -#[cfg(feature = "gecko")] -#[inline] -pub fn assert_variant_east_asian_matches() { - use gecko_bindings::structs; - - macro_rules! check_variant_east_asian { - ( $( $a:ident => $b:path),*, ) => { - if cfg!(debug_assertions) { - $( - assert_eq!(structs::$a as u16, $b.bits()); - )* - } - } - } - - check_variant_east_asian! { - NS_FONT_VARIANT_EAST_ASIAN_FULL_WIDTH => VariantEastAsian::FULL_WIDTH, - NS_FONT_VARIANT_EAST_ASIAN_JIS04 => VariantEastAsian::JIS04, - NS_FONT_VARIANT_EAST_ASIAN_JIS78 => VariantEastAsian::JIS78, - NS_FONT_VARIANT_EAST_ASIAN_JIS83 => VariantEastAsian::JIS83, - NS_FONT_VARIANT_EAST_ASIAN_JIS90 => VariantEastAsian::JIS90, - NS_FONT_VARIANT_EAST_ASIAN_PROP_WIDTH => VariantEastAsian::PROPORTIONAL_WIDTH, - NS_FONT_VARIANT_EAST_ASIAN_RUBY => VariantEastAsian::RUBY, - NS_FONT_VARIANT_EAST_ASIAN_SIMPLIFIED => VariantEastAsian::SIMPLIFIED, - NS_FONT_VARIANT_EAST_ASIAN_TRADITIONAL => VariantEastAsian::TRADITIONAL, - } -} - #[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[derive(Clone, Debug, PartialEq, SpecifiedValueInfo, ToCss)] /// Allows control of glyph substitution and sizing in East Asian text. @@ -1500,34 +1482,88 @@ impl Parse for FontVariantEastAsian { } } -bitflags! { - #[derive(MallocSizeOf)] - /// Variants of ligatures - pub struct VariantLigatures: u16 { - /// Specifies that common default features are enabled - const NORMAL = 0; - /// Specifies that all types of ligatures and contextual forms - /// covered by this property are explicitly disabled - const NONE = 0x01; - /// Enables display of common ligatures - const COMMON_LIGATURES = 0x02; - /// Disables display of common ligatures - const NO_COMMON_LIGATURES = 0x04; - /// Enables display of discretionary ligatures - const DISCRETIONARY_LIGATURES = 0x08; - /// Disables display of discretionary ligatures - const NO_DISCRETIONARY_LIGATURES = 0x10; - /// Enables display of historical ligatures - const HISTORICAL_LIGATURES = 0x20; - /// Disables display of historical ligatures - const NO_HISTORICAL_LIGATURES = 0x40; - /// Enables display of contextual alternates - const CONTEXTUAL = 0x80; - /// Disables display of contextual alternates - const NO_CONTEXTUAL = 0x100; +macro_rules! impl_variant_ligatures { + { + $( + $(#[$($meta:tt)+])* + $ident:ident / $css:expr => $gecko:ident = $value:expr, + )+ + } => { + bitflags! { + #[derive(MallocSizeOf)] + /// Variants of ligatures + pub struct VariantLigatures: u16 { + /// Specifies that common default features are enabled + const NORMAL = 0; + $( + $(#[$($meta)+])* + const $ident = $value; + )+ + } + } + + impl ToCss for VariantLigatures { + fn to_css(&self, dest: &mut CssWriter) -> fmt::Result + where + W: Write, + { + if self.is_empty() { + return dest.write_str("normal"); + } + if self.contains(VariantLigatures::NONE) { + return dest.write_str("none"); + } + + let mut writer = SequenceWriter::new(dest, " "); + $( + if self.intersects(VariantLigatures::$ident) { + writer.raw_item($css)?; + } + )+ + Ok(()) + } + } + + /// Asserts that all variant-east-asian matches its NS_FONT_VARIANT_EAST_ASIAN_* value. + #[cfg(feature = "gecko")] + #[inline] + pub fn assert_variant_ligatures_matches() { + use gecko_bindings::structs; + $( + debug_assert_eq!(structs::$gecko as u16, VariantLigatures::$ident.bits()); + )+ + } + + impl SpecifiedValueInfo for VariantLigatures { + fn collect_completion_keywords(f: KeywordsCollectFn) { + f(&["normal", $($css,)+]); + } + } } } +impl_variant_ligatures! { + /// Specifies that all types of ligatures and contextual forms + /// covered by this property are explicitly disabled + NONE / "none" => NS_FONT_VARIANT_LIGATURES_NONE = 0x01, + /// Enables display of common ligatures + COMMON_LIGATURES / "common-ligatures" => NS_FONT_VARIANT_LIGATURES_COMMON = 0x02, + /// Disables display of common ligatures + NO_COMMON_LIGATURES / "no-common-ligatures" => NS_FONT_VARIANT_LIGATURES_NO_COMMON = 0x04, + /// Enables display of discretionary ligatures + DISCRETIONARY_LIGATURES / "discretionary-ligatures" => NS_FONT_VARIANT_LIGATURES_DISCRETIONARY = 0x08, + /// Disables display of discretionary ligatures + NO_DISCRETIONARY_LIGATURES / "no-discretionary-ligatures" => NS_FONT_VARIANT_LIGATURES_NO_DISCRETIONARY = 0x10, + /// Enables display of historical ligatures + HISTORICAL_LIGATURES / "historical-ligatures" => NS_FONT_VARIANT_LIGATURES_HISTORICAL = 0x20, + /// Disables display of historical ligatures + NO_HISTORICAL_LIGATURES / "no-historical-ligatures" => NS_FONT_VARIANT_LIGATURES_NO_HISTORICAL = 0x40, + /// Enables display of contextual alternates + CONTEXTUAL / "contextual" => NS_FONT_VARIANT_LIGATURES_CONTEXTUAL = 0x80, + /// Disables display of contextual alternates + NO_CONTEXTUAL / "no-contextual" => NS_FONT_VARIANT_LIGATURES_NO_CONTEXTUAL = 0x100, +} + #[cfg(feature = "gecko")] impl VariantLigatures { /// Obtain a specified value from a Gecko keyword value @@ -1543,80 +1579,9 @@ impl VariantLigatures { } } -impl ToCss for VariantLigatures { - fn to_css(&self, dest: &mut CssWriter) -> fmt::Result - where - W: Write, - { - if self.is_empty() { - return dest.write_str("normal"); - } - if self.contains(VariantLigatures::NONE) { - return dest.write_str("none"); - } - - let mut has_any = false; - - macro_rules! write_value { - ($ident:path => $str:expr) => { - if self.intersects($ident) { - if has_any { - dest.write_str(" ")?; - } - has_any = true; - dest.write_str($str)?; - } - }; - } - - write_value!(VariantLigatures::COMMON_LIGATURES => "common-ligatures"); - write_value!(VariantLigatures::NO_COMMON_LIGATURES => "no-common-ligatures"); - write_value!(VariantLigatures::DISCRETIONARY_LIGATURES => "discretionary-ligatures"); - write_value!(VariantLigatures::NO_DISCRETIONARY_LIGATURES => "no-discretionary-ligatures"); - write_value!(VariantLigatures::HISTORICAL_LIGATURES => "historical-ligatures"); - write_value!(VariantLigatures::NO_HISTORICAL_LIGATURES => "no-historical-ligatures"); - write_value!(VariantLigatures::CONTEXTUAL => "contextual"); - write_value!(VariantLigatures::NO_CONTEXTUAL => "no-contextual"); - - debug_assert!(has_any); - Ok(()) - } -} - -impl SpecifiedValueInfo for VariantLigatures {} - #[cfg(feature = "gecko")] impl_gecko_keyword_conversions!(VariantLigatures, u16); -/// Asserts that all variant-east-asian matches its NS_FONT_VARIANT_EAST_ASIAN_* value. -#[cfg(feature = "gecko")] -#[inline] -pub fn assert_variant_ligatures_matches() { - use gecko_bindings::structs; - - macro_rules! check_variant_ligatures { - ( $( $a:ident => $b:path),*, ) => { - if cfg!(debug_assertions) { - $( - assert_eq!(structs::$a as u16, $b.bits()); - )* - } - } - } - - check_variant_ligatures! { - NS_FONT_VARIANT_LIGATURES_NONE => VariantLigatures::NONE, - NS_FONT_VARIANT_LIGATURES_COMMON => VariantLigatures::COMMON_LIGATURES, - NS_FONT_VARIANT_LIGATURES_NO_COMMON => VariantLigatures::NO_COMMON_LIGATURES, - NS_FONT_VARIANT_LIGATURES_DISCRETIONARY => VariantLigatures::DISCRETIONARY_LIGATURES, - NS_FONT_VARIANT_LIGATURES_NO_DISCRETIONARY => VariantLigatures::NO_DISCRETIONARY_LIGATURES, - NS_FONT_VARIANT_LIGATURES_HISTORICAL => VariantLigatures::HISTORICAL_LIGATURES, - NS_FONT_VARIANT_LIGATURES_NO_HISTORICAL => VariantLigatures::NO_HISTORICAL_LIGATURES, - NS_FONT_VARIANT_LIGATURES_CONTEXTUAL => VariantLigatures::CONTEXTUAL, - NS_FONT_VARIANT_LIGATURES_NO_CONTEXTUAL => VariantLigatures::NO_CONTEXTUAL, - } -} - #[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[derive(Clone, Debug, PartialEq, SpecifiedValueInfo, ToCss)] /// Ligatures and contextual forms are ways of combining glyphs @@ -1739,31 +1704,82 @@ impl Parse for FontVariantLigatures { } } -bitflags! { - #[derive(MallocSizeOf)] - /// Vairants of numeric values - pub struct VariantNumeric: u8 { - /// None of other variants are enabled. - const NORMAL = 0; - /// Enables display of lining numerals. - const LINING_NUMS = 0x01; - /// Enables display of old-style numerals. - const OLDSTYLE_NUMS = 0x02; - /// Enables display of proportional numerals. - const PROPORTIONAL_NUMS = 0x04; - /// Enables display of tabular numerals. - const TABULAR_NUMS = 0x08; - /// Enables display of lining diagonal fractions. - const DIAGONAL_FRACTIONS = 0x10; - /// Enables display of lining stacked fractions. - const STACKED_FRACTIONS = 0x20; - /// Enables display of letter forms used with ordinal numbers. - const ORDINAL = 0x80; - /// Enables display of slashed zeros. - const SLASHED_ZERO = 0x40; +macro_rules! impl_variant_numeric { + { + $( + $(#[$($meta:tt)+])* + $ident:ident / $css:expr => $gecko:ident = $value:expr, + )+ + } => { + bitflags! { + #[derive(MallocSizeOf)] + /// Vairants of numeric values + pub struct VariantNumeric: u8 { + /// None of other variants are enabled. + const NORMAL = 0; + $( + $(#[$($meta)+])* + const $ident = $value; + )+ + } + } + + impl ToCss for VariantNumeric { + fn to_css(&self, dest: &mut CssWriter) -> fmt::Result + where + W: Write, + { + if self.is_empty() { + return dest.write_str("normal"); + } + + let mut writer = SequenceWriter::new(dest, " "); + $( + if self.intersects(VariantNumeric::$ident) { + writer.raw_item($css)?; + } + )+ + Ok(()) + } + } + + /// Asserts that all variant-east-asian matches its NS_FONT_VARIANT_EAST_ASIAN_* value. + #[cfg(feature = "gecko")] + #[inline] + pub fn assert_variant_numeric_matches() { + use gecko_bindings::structs; + $( + debug_assert_eq!(structs::$gecko as u8, VariantNumeric::$ident.bits()); + )+ + } + + impl SpecifiedValueInfo for VariantNumeric { + fn collect_completion_keywords(f: KeywordsCollectFn) { + f(&["normal", $($css,)+]); + } + } } } +impl_variant_numeric! { + /// Enables display of lining numerals. + LINING_NUMS / "lining-nums" => NS_FONT_VARIANT_NUMERIC_LINING = 0x01, + /// Enables display of old-style numerals. + OLDSTYLE_NUMS / "oldstyle-nums" => NS_FONT_VARIANT_NUMERIC_OLDSTYLE = 0x02, + /// Enables display of proportional numerals. + PROPORTIONAL_NUMS / "proportional-nums" => NS_FONT_VARIANT_NUMERIC_PROPORTIONAL = 0x04, + /// Enables display of tabular numerals. + TABULAR_NUMS / "tabular-nums" => NS_FONT_VARIANT_NUMERIC_TABULAR = 0x08, + /// Enables display of lining diagonal fractions. + DIAGONAL_FRACTIONS / "diagonal-fractions" => NS_FONT_VARIANT_NUMERIC_DIAGONAL_FRACTIONS = 0x10, + /// Enables display of lining stacked fractions. + STACKED_FRACTIONS / "stacked-fractions" => NS_FONT_VARIANT_NUMERIC_STACKED_FRACTIONS = 0x20, + /// Enables display of letter forms used with ordinal numbers. + ORDINAL / "ordinal" => NS_FONT_VARIANT_NUMERIC_ORDINAL = 0x80, + /// Enables display of slashed zeros. + SLASHED_ZERO / "slashed-zero" => NS_FONT_VARIANT_NUMERIC_SLASHZERO = 0x40, +} + #[cfg(feature = "gecko")] impl VariantNumeric { /// Obtain a specified value from a Gecko keyword value @@ -1779,76 +1795,9 @@ impl VariantNumeric { } } -impl ToCss for VariantNumeric { - fn to_css(&self, dest: &mut CssWriter) -> fmt::Result - where - W: Write, - { - if self.is_empty() { - return dest.write_str("normal"); - } - - let mut has_any = false; - - macro_rules! write_value { - ($ident:path => $str:expr) => { - if self.intersects($ident) { - if has_any { - dest.write_str(" ")?; - } - has_any = true; - dest.write_str($str)?; - } - }; - } - - write_value!(VariantNumeric::LINING_NUMS => "lining-nums"); - write_value!(VariantNumeric::OLDSTYLE_NUMS => "oldstyle-nums"); - write_value!(VariantNumeric::PROPORTIONAL_NUMS => "proportional-nums"); - write_value!(VariantNumeric::TABULAR_NUMS => "tabular-nums"); - write_value!(VariantNumeric::DIAGONAL_FRACTIONS => "diagonal-fractions"); - write_value!(VariantNumeric::STACKED_FRACTIONS => "stacked-fractions"); - write_value!(VariantNumeric::SLASHED_ZERO => "slashed-zero"); - write_value!(VariantNumeric::ORDINAL => "ordinal"); - - debug_assert!(has_any); - Ok(()) - } -} - -impl SpecifiedValueInfo for VariantNumeric {} - #[cfg(feature = "gecko")] impl_gecko_keyword_conversions!(VariantNumeric, u8); -/// Asserts that all variant-east-asian matches its NS_FONT_VARIANT_EAST_ASIAN_* value. -#[cfg(feature = "gecko")] -#[inline] -pub fn assert_variant_numeric_matches() { - use gecko_bindings::structs; - - macro_rules! check_variant_numeric { - ( $( $a:ident => $b:path),*, ) => { - if cfg!(debug_assertions) { - $( - assert_eq!(structs::$a as u8, $b.bits()); - )* - } - } - } - - check_variant_numeric! { - NS_FONT_VARIANT_NUMERIC_LINING => VariantNumeric::LINING_NUMS, - NS_FONT_VARIANT_NUMERIC_OLDSTYLE => VariantNumeric::OLDSTYLE_NUMS, - NS_FONT_VARIANT_NUMERIC_PROPORTIONAL => VariantNumeric::PROPORTIONAL_NUMS, - NS_FONT_VARIANT_NUMERIC_TABULAR => VariantNumeric::TABULAR_NUMS, - NS_FONT_VARIANT_NUMERIC_DIAGONAL_FRACTIONS => VariantNumeric::DIAGONAL_FRACTIONS, - NS_FONT_VARIANT_NUMERIC_STACKED_FRACTIONS => VariantNumeric::STACKED_FRACTIONS, - NS_FONT_VARIANT_NUMERIC_SLASHZERO => VariantNumeric::SLASHED_ZERO, - NS_FONT_VARIANT_NUMERIC_ORDINAL => VariantNumeric::ORDINAL, - } -} - #[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[derive(Clone, Debug, PartialEq, SpecifiedValueInfo, ToCss)] /// Specifies control over numerical forms. From e50847666c5f3ec6ec1f47270a007a89f9fdc8fd Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Sun, 29 Apr 2018 09:03:31 +1000 Subject: [PATCH 16/26] style: Derive ToCss for values::generics::font::KeywordSize. Bug: 1434130 Reviewed-by: emilio MozReview-Commit-ID: 9ek3PcqYiU3 --- components/style/values/generics/font.rs | 29 ++++-------------------- 1 file changed, 4 insertions(+), 25 deletions(-) diff --git a/components/style/values/generics/font.rs b/components/style/values/generics/font.rs index 738a40a7844..8fb5e5245dd 100644 --- a/components/style/values/generics/font.rs +++ b/components/style/values/generics/font.rs @@ -187,18 +187,21 @@ impl SpecifiedValueInfo for KeywordInfo { /// CSS font keywords #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, - ToAnimatedValue, ToAnimatedZero, SpecifiedValueInfo)] + 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, } @@ -216,30 +219,6 @@ 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 From 185e4ce61da3a561f7c456d6adbf9b709290e9f6 Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Sun, 29 Apr 2018 09:03:31 +1000 Subject: [PATCH 17/26] style: Allow shorthands to specify their own impl of SpecifiedValueInfo and manual impl it for font and border. Bug: 1434130 Reviewed-by: emilio MozReview-Commit-ID: 3B9OfkWU0Eq --- components/style/properties/helpers.mako.rs | 32 ++++++------------- .../style/properties/shorthand/border.mako.rs | 12 +++++++ .../style/properties/shorthand/font.mako.rs | 24 ++++++++++++++ 3 files changed, 46 insertions(+), 22 deletions(-) diff --git a/components/style/properties/helpers.mako.rs b/components/style/properties/helpers.mako.rs index 2aa93bbb7d3..017996f87b5 100644 --- a/components/style/properties/helpers.mako.rs +++ b/components/style/properties/helpers.mako.rs @@ -619,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} @@ -636,8 +641,11 @@ #[allow(unused_imports)] use style_traits::{ParseError, StyleParseErrorKind}; #[allow(unused_imports)] - use style_traits::{CssWriter, SpecifiedValueInfo, 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}: @@ -744,26 +752,6 @@ }) } - <% - sub_properties_for_value_info = shorthand.sub_properties - if shorthand.name == "border": - # border-image subproperties are simply reset by border - # shorthand, so border cannot accept values of them. - # XXX We may want a better mechanism for this, but this - # is probably fine for now. - sub_properties_for_value_info = [ - subprop for subprop in shorthand.sub_properties - if not subprop.name.startswith("border-image") - ] - %> - impl SpecifiedValueInfo for Longhands { - const SUPPORTED_TYPES: u8 = 0 - % for subprop in sub_properties_for_value_info: - | ::SUPPORTED_TYPES - % endfor - ; - } - ${caller.body()} } % endif 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" From 43bb6364f65fb5e781ca8890f7561df43834807a Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Sun, 29 Apr 2018 09:03:31 +1000 Subject: [PATCH 18/26] style: Have Parse derive respect #[css(skip)] on variant as well and derive Parse for KeywordSize. Bug: 1434130 Reviewed-by: emilio MozReview-Commit-ID: evSvk1RQGe --- components/style/values/generics/font.rs | 5 +++-- components/style/values/specified/font.rs | 15 --------------- components/style_derive/parse.rs | 4 ++++ 3 files changed, 7 insertions(+), 17 deletions(-) diff --git a/components/style/values/generics/font.rs b/components/style/values/generics/font.rs index 8fb5e5245dd..d48a0a36bbc 100644 --- a/components/style/values/generics/font.rs +++ b/components/style/values/generics/font.rs @@ -186,8 +186,9 @@ impl SpecifiedValueInfo for KeywordInfo { } /// CSS font keywords -#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, - SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, ToCss)] +#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, + Parse, PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, + ToCss)] #[allow(missing_docs)] pub enum KeywordSize { #[css(keyword = "xx-small")] diff --git a/components/style/values/specified/font.rs b/components/style/values/specified/font.rs index 7f971f36fcf..fedf748d54f 100644 --- a/components/style/values/specified/font.rs +++ b/components/style/values/specified/font.rs @@ -715,21 +715,6 @@ impl KeywordInfo { } } -impl KeywordSize { - /// Parses a keyword size. - pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result> { - try_match_ident_ignore_ascii_case! { input, - "xx-small" => Ok(KeywordSize::XXSmall), - "x-small" => Ok(KeywordSize::XSmall), - "small" => Ok(KeywordSize::Small), - "medium" => Ok(KeywordSize::Medium), - "large" => Ok(KeywordSize::Large), - "x-large" => Ok(KeywordSize::XLarge), - "xx-large" => Ok(KeywordSize::XXLarge), - } - } -} - /// This is the ratio applied for font-size: larger /// and smaller by both Firefox and Chrome const LARGER_FONT_SIZE_RATIO: f32 = 1.2; diff --git a/components/style_derive/parse.rs b/components/style_derive/parse.rs index 620ba3fee82..7727d6b89bb 100644 --- a/components/style_derive/parse.rs +++ b/components/style_derive/parse.rs @@ -20,6 +20,10 @@ pub fn derive(input: DeriveInput) -> Tokens { ); 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()), ); From 5437c96402ff6ce322b1be5c392a1c9c60e3ce70 Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Sun, 29 Apr 2018 09:03:31 +1000 Subject: [PATCH 19/26] style: Have TextAlign derive ToCss and unship char value from it. Bug: 1434130 Reviewed-by: emilio MozReview-Commit-ID: CXDnyqzjQkq --- components/style/values/specified/text.rs | 25 ++++++++--------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/components/style/values/specified/text.rs b/components/style/values/specified/text.rs index d2ce18dcf3f..4bae78fc8f0 100644 --- a/components/style/values/specified/text.rs +++ b/components/style/values/specified/text.rs @@ -355,13 +355,17 @@ impl Parse for TextDecorationLine { } 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, SpecifiedValueInfo, ToComputedValue, ToCss)] #[allow(missing_docs)] pub enum TextAlignKeyword { $( + $(#[$($meta)+])* $name = $discriminant, )+ } @@ -392,6 +396,7 @@ define_text_align_keyword! { MozCenter => 6, MozLeft => 7, MozRight => 8, + #[css(skip)] Char => 10, } @@ -418,7 +423,7 @@ impl TextAlignKeyword { /// Specified value of text-align property. #[cfg_attr(feature = "gecko", derive(MallocSizeOf))] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, SpecifiedValueInfo)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, SpecifiedValueInfo, ToCss)] pub enum TextAlign { /// Keyword value of text-align property. Keyword(TextAlignKeyword), @@ -430,6 +435,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, } @@ -454,21 +460,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")] From 20398491cc5562cc1abe593b651a98a7ccdc2103 Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Sun, 29 Apr 2018 09:03:31 +1000 Subject: [PATCH 20/26] style: Use unified list for TextDecorationLine and implement its SpecifiedValueInfo. Bug: 1434130 Reviewed-by: emilio MozReview-Commit-ID: 2sCnK1AecFk --- components/style/values/computed/text.rs | 33 +--- components/style/values/specified/text.rs | 201 ++++++++++++---------- 2 files changed, 112 insertions(+), 122 deletions(-) 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/specified/text.rs b/components/style/values/specified/text.rs index 4bae78fc8f0..70947ac0826 100644 --- a/components/style/values/specified/text.rs +++ b/components/style/values/specified/text.rs @@ -9,7 +9,9 @@ use parser::{Parse, ParserContext}; use properties::longhands::writing_mode::computed_value::T as SpecifiedWritingMode; use selectors::parser::SelectorParseErrorKind; use std::fmt::{self, Write}; -use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; +use style_traits::{CssWriter, KeywordsCollectFn, ParseError}; +use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss}; +use style_traits::values::SequenceWriter; use unicode_segmentation::UnicodeSegmentation; use values::computed::{Context, ToComputedValue}; use values::computed::text::LineHeight as ComputedLineHeight; @@ -251,32 +253,117 @@ impl ToComputedValue for TextOverflow { } } -bitflags! { - #[derive(MallocSizeOf, SpecifiedValueInfo, ToComputedValue)] - /// Specified keyword values for the text-decoration-line property. - pub struct TextDecorationLine: u8 { - /// No text decoration line is specified - const NONE = 0; - /// Underline - const UNDERLINE = 0x01; - /// Overline - const OVERLINE = 0x02; - /// Line through - const LINE_THROUGH = 0x04; - /// Blink - const BLINK = 0x08; - #[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; +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,72 +375,6 @@ 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 { ($( $(#[$($meta:tt)+])* From 0021c70c0867498e6e38627aadaffb6c36a0844f Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Sun, 29 Apr 2018 09:03:31 +1000 Subject: [PATCH 21/26] style: Handle keywords for color values. Bug: 1434130 Reviewed-by: emilio MozReview-Commit-ID: 5GvIHSeQuCX --- components/style/values/specified/color.rs | 11 ++++++++++- ports/geckolib/glue.rs | 13 +++++++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/components/style/values/specified/color.rs b/components/style/values/specified/color.rs index 32e0316f654..3066c5b8c2a 100644 --- a/components/style/values/specified/color.rs +++ b/components/style/values/specified/color.rs @@ -14,7 +14,7 @@ use parser::{Parse, ParserContext}; use properties::longhands::system_colors::SystemColor; use std::fmt::{self, Write}; use std::io::Write as IoWrite; -use style_traits::{CssType, CssWriter, ParseError, StyleParseErrorKind}; +use style_traits::{CssType, CssWriter, KeywordsCollectFn, ParseError, StyleParseErrorKind}; use style_traits::{SpecifiedValueInfo, ToCss, ValueParseErrorKind}; use super::AllowQuirks; use values::computed::{Color as ComputedColor, Context, ToComputedValue}; @@ -429,6 +429,15 @@ impl From for RGBAColor { impl SpecifiedValueInfo for Color { const SUPPORTED_TYPES: u8 = CssType::COLOR; + + fn collect_completion_keywords(f: KeywordsCollectFn) { + // We are not going to insert all the color names here. Caller and + // devtools should take care of them. XXX Actually, transparent + // should probably be handled that way as well. + // XXX `currentColor` should really be `currentcolor`. But let's + // keep it consistent with the old system for now. + f(&["rgb", "rgba", "hsl", "hsla", "currentColor", "transparent"]); + } } /// Specified value for the "color" property, which resolves the `currentcolor` diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 07d3615d13d..e602401c954 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -1012,9 +1012,18 @@ pub unsafe extern "C" fn Servo_Property_GetCSSValuesForProperty( 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(); - bindings::Gecko_ResizeTArrayForStrings(result, values.len() as u32); - for (src, dest) in values.iter().zip(result.iter_mut()) { + 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(); } } From 0f7f9eebc07fa173487acdefeb8b55ce4b8bef22 Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Sun, 29 Apr 2018 09:03:31 +1000 Subject: [PATCH 22/26] style: Add some attributes for SpecifiedValueInfo to help deriving more from types. Bug: 1434130 Reviewed-by: emilio MozReview-Commit-ID: IyohSTbUO31 --- .../style/values/generics/basic_shape.rs | 4 + components/style/values/generics/border.rs | 1 + components/style/values/generics/counters.rs | 2 +- components/style/values/generics/effects.rs | 1 + components/style/values/generics/grid.rs | 10 ++- components/style/values/generics/image.rs | 1 + components/style/values/generics/transform.rs | 8 +- components/style/values/specified/box.rs | 13 ++- components/style/values/specified/font.rs | 2 + .../style/values/specified/inherited_box.rs | 1 + components/style/values/specified/list.rs | 3 +- components/style/values/specified/mod.rs | 7 +- components/style/values/specified/position.rs | 1 + .../style/values/specified/transform.rs | 6 +- components/style_derive/lib.rs | 2 +- .../style_derive/specified_value_info.rs | 81 ++++++++++++++++--- .../style_traits/specified_value_info.rs | 30 +++++++ 17 files changed, 137 insertions(+), 36 deletions(-) diff --git a/components/style/values/generics/basic_shape.rs b/components/style/values/generics/basic_shape.rs index 80375ad8ffa..3bad738c1e6 100644 --- a/components/style/values/generics/basic_shape.rs +++ b/components/style/values/generics/basic_shape.rs @@ -69,6 +69,7 @@ pub enum BasicShape { /// #[allow(missing_docs)] +#[css(function = "inset")] #[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] pub struct InsetRect { @@ -78,6 +79,7 @@ pub struct InsetRect { /// #[allow(missing_docs)] +#[css(function)] #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] pub struct Circle { @@ -87,6 +89,7 @@ pub struct Circle { /// #[allow(missing_docs)] +#[css(function)] #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] pub struct Ellipse { @@ -110,6 +113,7 @@ pub enum ShapeRadius { /// A generic type for representing the `polygon()` function /// /// +#[css(function)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] pub struct Polygon { diff --git a/components/style/values/generics/border.rs b/components/style/values/generics/border.rs index 79c8713bfba..6230a1cf36a 100644 --- a/components/style/values/generics/border.rs +++ b/components/style/values/generics/border.rs @@ -28,6 +28,7 @@ pub struct BorderImageSlice { /// The offsets. pub offsets: Rect, /// Whether to fill the middle part. + #[value_info(represents_keyword)] pub fill: bool, } diff --git a/components/style/values/generics/counters.rs b/components/style/values/generics/counters.rs index 037834abf6e..7373cd8e947 100644 --- a/components/style/values/generics/counters.rs +++ b/components/style/values/generics/counters.rs @@ -59,7 +59,7 @@ impl Deref for CounterReset { /// Keyword `none` is represented by an empty vector. #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] -pub struct Counters(Box<[(CustomIdent, I)]>); +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 136f45635c1..7a76cdeb7bc 100644 --- a/components/style/values/generics/effects.rs +++ b/components/style/values/generics/effects.rs @@ -19,6 +19,7 @@ pub struct BoxShadow { pub spread: ShapeLength, /// Whether this is an inset box shadow. #[animation(constant)] + #[value_info(represents_keyword)] pub inset: bool, } diff --git a/components/style/values/generics/grid.rs b/components/style/values/generics/grid.rs index d805fb5e0d0..b9ec85ace22 100644 --- a/components/style/values/generics/grid.rs +++ b/components/style/values/generics/grid.rs @@ -198,10 +198,12 @@ pub enum TrackSize { /// and a flexible `` /// /// + #[css(function)] Minmax(TrackBreadth, TrackBreadth), /// A `fit-content` function. /// /// + #[css(function)] FitContent(L), } @@ -346,8 +348,7 @@ where /// The initial argument of the `repeat` function. /// /// -#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, - ToComputedValue, ToCss)] +#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] pub enum RepeatCount { /// A positive integer. This is allowed only for `` and `` Number(Integer), @@ -384,6 +385,7 @@ impl Parse for RepeatCount { /// values in its computed form. #[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, @@ -481,8 +483,7 @@ pub enum TrackListValue { /// The type of a `` as determined during parsing. /// /// -#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, - ToComputedValue)] +#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue)] pub enum TrackListType { /// [``](https://drafts.csswg.org/css-grid/#typedef-auto-track-list) /// @@ -510,6 +511,7 @@ pub struct TrackList { /// /// 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>, diff --git a/components/style/values/generics/image.rs b/components/style/values/generics/image.rs index 4501f94433f..5017559e00c 100644 --- a/components/style/values/generics/image.rs +++ b/components/style/values/generics/image.rs @@ -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. /// diff --git a/components/style/values/generics/transform.rs b/components/style/values/generics/transform.rs index 2c671541ea4..ecd40f5a55c 100644 --- a/components/style/values/generics/transform.rs +++ b/components/style/values/generics/transform.rs @@ -80,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), @@ -95,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)] @@ -103,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, diff --git a/components/style/values/specified/box.rs b/components/style/values/specified/box.rs index e26d82c8f67..ab2872d26c3 100644 --- a/components/style/values/specified/box.rs +++ b/components/style/values/specified/box.rs @@ -9,7 +9,7 @@ use cssparser::Parser; use parser::{Parse, ParserContext}; use selectors::parser::SelectorParseErrorKind; use std::fmt::{self, Write}; -use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, StyleParseErrorKind, ToCss}; +use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; use values::{CustomIdent, KeyframesName}; use values::generics::box_::AnimationIterationCount as GenericAnimationIterationCount; use values::generics::box_::Perspective as GenericPerspective; @@ -298,6 +298,7 @@ impl AnimationIterationCount { /// A value for the `animation-name` property. #[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] +#[value_info(other_values = "none")] pub struct AnimationName(pub Option); impl AnimationName { @@ -420,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; @@ -493,8 +495,6 @@ impl Parse for TouchAction { } } -impl SpecifiedValueInfo for TouchAction {} - #[cfg(feature = "gecko")] impl_bitflags_conversions!(TouchAction); @@ -522,7 +522,8 @@ pub fn assert_touch_action_matches() { } bitflags! { - #[derive(MallocSizeOf, ToComputedValue)] + #[derive(MallocSizeOf, ToComputedValue, SpecifiedValueInfo)] + #[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 @@ -605,8 +606,6 @@ impl Parse for Contain { } } -impl SpecifiedValueInfo for Contain {} - /// A specified value for the `perspective` property. pub type Perspective = GenericPerspective; diff --git a/components/style/values/specified/font.rs b/components/style/values/specified/font.rs index fedf748d54f..13ca2280997 100644 --- a/components/style/values/specified/font.rs +++ b/components/style/values/specified/font.rs @@ -1945,9 +1945,11 @@ pub struct FontSynthesis { /// If a `font-weight` is requested that the font family does not contain, /// the user agent may synthesize the requested weight from the weights /// that do exist in the font family. + #[value_info(represents_keyword)] pub weight: bool, /// If a font-style is requested that the font family does not contain, /// the user agent may synthesize the requested style from the normal face in the font family. + #[value_info(represents_keyword)] pub style: bool, } diff --git a/components/style/values/specified/inherited_box.rs b/components/style/values/specified/inherited_box.rs index da8da7614be..c7756f974f2 100644 --- a/components/style/values/specified/inherited_box.rs +++ b/components/style/values/specified/inherited_box.rs @@ -21,6 +21,7 @@ pub struct ImageOrientation { pub angle: Option, /// Whether or not "flip" was specified + #[value_info(other_values = "flip,from-image")] pub flipped: bool, } diff --git a/components/style/values/specified/list.rs b/components/style/values/specified/list.rs index 89e4afda6fc..ae61bb1ae9c 100644 --- a/components/style/values/specified/list.rs +++ b/components/style/values/specified/list.rs @@ -78,9 +78,10 @@ impl Parse for ListStyleType { /// /// FIXME(emilio): It's a shame that this allocates all the time it's computed, /// probably should just be refcounted. +/// FIXME This can probably derive ToCss. #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] -pub struct Quotes(pub Box<[(Box, Box)]>); +pub struct Quotes(#[css(if_empty = "none")] pub Box<[(Box, Box)]>); impl ToCss for Quotes { fn to_css(&self, dest: &mut CssWriter) -> fmt::Result diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index 9b4edfac413..3f89dae0053 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -570,6 +570,7 @@ pub type GridTemplateComponent = GenericGridTemplateComponent, , , ) used by clip and image-region +#[css(function = "rect")] pub struct ClipRect { /// ( | ) pub top: Option, @@ -757,7 +758,9 @@ impl AllowQuirks { /// An attr(...) rule /// /// `[namespace? `|`]? ident` -#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue)] +#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue)] +#[css(function)] pub struct Attr { /// Optional namespace prefix and URL. pub namespace: Option<(Prefix, Namespace)>, @@ -852,5 +855,3 @@ impl ToCss for Attr { dest.write_str(")") } } - -impl SpecifiedValueInfo for Attr {} diff --git a/components/style/values/specified/position.rs b/components/style/values/specified/position.rs index cb4b4aeb45b..0f2669f0a02 100644 --- a/components/style/values/specified/position.rs +++ b/components/style/values/specified/position.rs @@ -431,6 +431,7 @@ pub struct GridAutoFlow { /// Specifiy how auto-placement algorithm fills each `row` or `column` in turn pub autoflow: AutoFlow, /// Specify use `dense` packing algorithm or not + #[value_info(represents_keyword)] pub dense: bool, } diff --git a/components/style/values/specified/transform.rs b/components/style/values/specified/transform.rs index b66e5744f39..835d505836c 100644 --- a/components/style/values/specified/transform.rs +++ b/components/style/values/specified/transform.rs @@ -7,7 +7,7 @@ use cssparser::Parser; use parser::{Parse, ParserContext}; use selectors::parser::SelectorParseErrorKind; -use style_traits::{CssType, ParseError, SpecifiedValueInfo, StyleParseErrorKind}; +use style_traits::{ParseError, StyleParseErrorKind}; use values::computed::{Context, LengthOrPercentage as ComputedLengthOrPercentage}; use values::computed::{Percentage as ComputedPercentage, ToComputedValue}; use values::computed::transform::TimingFunction as ComputedTimingFunction; @@ -246,10 +246,6 @@ pub enum OriginComponent { /// A specified timing function. pub type TimingFunction = generic::TimingFunction; -impl SpecifiedValueInfo for TimingFunction { - const SUPPORTED_TYPES: u8 = CssType::TIMING_FUNCTION; -} - impl Parse for TransformOrigin { fn parse<'i, 't>( context: &ParserContext, diff --git a/components/style_derive/lib.rs b/components/style_derive/lib.rs index 86442070ca1..88f0bbadfb1 100644 --- a/components/style_derive/lib.rs +++ b/components/style_derive/lib.rs @@ -64,7 +64,7 @@ pub fn derive_to_css(stream: TokenStream) -> TokenStream { to_css::derive(input).into() } -#[proc_macro_derive(SpecifiedValueInfo, attributes(css))] +#[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/specified_value_info.rs b/components/style_derive/specified_value_info.rs index e5e9ac328da..7168ec2509f 100644 --- a/components/style_derive/specified_value_info.rs +++ b/components/style_derive/specified_value_info.rs @@ -4,17 +4,17 @@ use cg; use quote::Tokens; -use syn::{Data, DeriveInput, Fields, Type}; +use syn::{Data, DeriveInput, Fields, Ident,Type}; use to_css::{CssFieldAttrs, CssInputAttrs, CssVariantAttrs}; pub fn derive(mut input: DeriveInput) -> Tokens { - let attrs = cg::parse_input_attrs::(&input); + 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) = attrs.function { + 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. @@ -31,21 +31,32 @@ pub fn derive(mut input: DeriveInput) -> Tokens { match input.data { Data::Enum(ref e) => { for v in e.variants.iter() { - let attrs = cg::parse_variant_attrs::(&v); - if attrs.skip { + 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) = attrs.aliases { + if let Some(aliases) = css_attrs.aliases { for alias in aliases.split(",") { values.push(alias.to_string()); } } - if let Some(keyword) = attrs.keyword { + 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; } - let variant_name = || cg::to_css_identifier(v.ident.as_ref()); - if let Some(function) = attrs.function { + 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) { @@ -63,6 +74,13 @@ pub fn derive(mut input: DeriveInput) -> Tokens { } } + 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 @@ -73,6 +91,12 @@ pub fn derive(mut input: DeriveInput) -> Tokens { <#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 { @@ -110,11 +134,23 @@ fn derive_struct_fields<'a>( Fields::Unnamed(ref fields) => fields.unnamed.iter(), }; types.extend(fields.filter_map(|field| { - let attrs = cg::parse_field_attrs::(field); - if let Some(if_empty) = attrs.if_empty { + 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 !attrs.skip { + if !css_attrs.skip { Some(&field.ty) } else { None @@ -122,3 +158,24 @@ fn derive_struct_fields<'a>( })); 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_traits/specified_value_info.rs b/components/style_traits/specified_value_info.rs index 55690ebea5c..122091fc8e9 100644 --- a/components/style_traits/specified_value_info.rs +++ b/components/style_traits/specified_value_info.rs @@ -27,6 +27,36 @@ pub mod CssType { 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. /// From 07de715bb584784b0d66341b074008e08b6057b6 Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Sun, 29 Apr 2018 09:03:31 +1000 Subject: [PATCH 23/26] style: Manually implement collect_completion_keywords for some types. Bug: 1434130 Reviewed-by: emilio MozReview-Commit-ID: 6T35uylxgho --- components/style/gecko/url.rs | 6 +- .../helpers/animated_properties.mako.rs | 11 +- components/style/values/generics/font.rs | 9 +- components/style/values/generics/mod.rs | 22 ++- components/style/values/specified/align.rs | 161 ++++++++++++++++-- components/style/values/specified/image.rs | 23 ++- components/style_traits/cursor.rs | 11 +- 7 files changed, 209 insertions(+), 34 deletions(-) diff --git a/components/style/gecko/url.rs b/components/style/gecko/url.rs index a0ecfc7b381..bca7e10883a 100644 --- a/components/style/gecko/url.rs +++ b/components/style/gecko/url.rs @@ -15,11 +15,11 @@ use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use parser::{Parse, ParserContext}; use servo_arc::{Arc, RawOffsetArc}; use std::mem; -use style_traits::{ParseError, SpecifiedValueInfo}; +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. /// @@ -120,8 +120,6 @@ impl MallocSizeOf for CssUrl { } } -impl SpecifiedValueInfo for CssUrl {} - /// A specified url() value for general usage. #[derive(Clone, Debug, SpecifiedValueInfo, ToComputedValue, ToCss)] pub struct SpecifiedUrl { diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index 059d5a51c1b..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, SpecifiedValueInfo}; +use style_traits::{KeywordsCollectFn, ParseError, SpecifiedValueInfo}; use super::ComputedValues; use values::{CSSFloat, CustomIdent, Either}; use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero}; @@ -172,7 +172,14 @@ impl From for TransitionProperty { } } -impl SpecifiedValueInfo 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")] diff --git a/components/style/values/generics/font.rs b/components/style/values/generics/font.rs index d48a0a36bbc..d4e55af6a61 100644 --- a/components/style/values/generics/font.rs +++ b/components/style/values/generics/font.rs @@ -11,7 +11,8 @@ use num_traits::One; use parser::{Parse, ParserContext}; use std::fmt::{self, Write}; use std::io::Cursor; -use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, 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 @@ -181,8 +182,10 @@ where } } -impl SpecifiedValueInfo for KeywordInfo { - const SUPPORTED_TYPES: u8 = ::SUPPORTED_TYPES; +impl SpecifiedValueInfo for KeywordInfo { + fn collect_completion_keywords(f: KeywordsCollectFn) { + ::collect_completion_keywords(f); + } } /// CSS font keywords diff --git a/components/style/values/generics/mod.rs b/components/style/values/generics/mod.rs index f47b2f29b89..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; @@ -79,8 +80,7 @@ impl SymbolsType { /// Since wherever is used, 'none' is a valid value as /// well, we combine them into one type to make code simpler. #[cfg_attr(feature = "gecko", derive(MallocSizeOf))] -#[derive(Clone, Debug, Eq, PartialEq, SpecifiedValueInfo, ToComputedValue, - ToCss)] +#[derive(Clone, Debug, Eq, PartialEq, ToComputedValue, ToCss)] pub enum CounterStyleOrNone { /// `none` None, @@ -138,6 +138,22 @@ 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, diff --git a/components/style/values/specified/align.rs b/components/style/values/specified/align.rs index a92ca52c8b4..731844bcb52 100644 --- a/components/style/values/specified/align.rs +++ b/components/style/values/specified/align.rs @@ -10,13 +10,13 @@ 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 /// /// These constants match Gecko's `NS_STYLE_ALIGN_*` constants. - #[derive(MallocSizeOf, SpecifiedValueInfo, ToComputedValue)] + #[derive(MallocSizeOf, ToComputedValue)] pub struct AlignFlags: u8 { // Enumeration stored in the lower 5 bits: /// 'auto' @@ -135,8 +135,7 @@ pub enum AxisDirection { /// Shared value for the `align-content` and `justify-content` properties. /// /// -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, - ToComputedValue, ToCss)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] pub struct ContentDistribution { primary: AlignFlags, @@ -192,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()); @@ -228,13 +230,25 @@ 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. /// /// -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, - ToComputedValue, ToCss)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] pub struct AlignContent(pub ContentDistribution); impl Parse for AlignContent { @@ -242,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, @@ -249,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 { @@ -266,8 +288,7 @@ impl From for u16 { /// Value for the `justify-content` property. /// /// -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, - ToComputedValue, ToCss)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] pub struct JustifyContent(pub ContentDistribution); impl Parse for JustifyContent { @@ -275,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, @@ -282,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 { @@ -297,8 +326,7 @@ impl From for u16 { } /// -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, - ToComputedValue, ToCss)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] pub struct SelfAlignment(pub AlignFlags); impl SelfAlignment { @@ -323,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 @@ -343,13 +374,19 @@ 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. /// /// -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, - ToComputedValue, ToCss)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] pub struct AlignSelf(pub SelfAlignment); impl Parse for AlignSelf { @@ -357,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, @@ -364,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))) @@ -379,8 +424,7 @@ impl From for u8 { /// The specified value of the justify-self property. /// /// -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, - ToComputedValue, ToCss)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] pub struct JustifySelf(pub SelfAlignment); impl Parse for JustifySelf { @@ -388,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, @@ -395,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))) @@ -410,8 +462,7 @@ impl From for u8 { /// Value of the `align-items` property /// /// -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, - ToComputedValue, ToCss)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] pub struct AlignItems(pub AlignFlags); impl AlignItems { @@ -429,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)); @@ -447,11 +501,19 @@ 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 /// /// -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, - ToCss)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToCss)] pub struct JustifyItems(pub AlignFlags); impl JustifyItems { @@ -473,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 @@ -500,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), @@ -511,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" => { @@ -534,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), @@ -546,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, @@ -574,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, @@ -586,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) @@ -601,3 +722,7 @@ fn parse_legacy<'i, 't>(input: &mut Parser<'i, 't>) -> Result Date: Sun, 29 Apr 2018 02:41:36 +0200 Subject: [PATCH 24/26] style: cherry-pick some changes from m-c that had got lost. --- components/style/values/computed/percentage.rs | 5 +++-- components/style/values/generics/font.rs | 5 +++-- components/style/values/specified/font.rs | 6 ++++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/components/style/values/computed/percentage.rs b/components/style/values/computed/percentage.rs index 7ca504d2aff..653532aea6c 100644 --- a/components/style/values/computed/percentage.rs +++ b/components/style/values/computed/percentage.rs @@ -12,8 +12,9 @@ use values::generics::NonNegative; /// A computed percentage. #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] -#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, Default, MallocSizeOf, PartialEq, - PartialOrd, ToAnimatedZero, ToComputedValue)] +#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, Default, + MallocSizeOf, PartialEq, PartialOrd, SpecifiedValueInfo, + ToAnimatedZero, ToComputedValue)] pub struct Percentage(pub CSSFloat); impl Percentage { diff --git a/components/style/values/generics/font.rs b/components/style/values/generics/font.rs index d4e55af6a61..f5e62e0ab5f 100644 --- a/components/style/values/generics/font.rs +++ b/components/style/values/generics/font.rs @@ -227,13 +227,14 @@ impl Default for KeywordSize { /// /// 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/specified/font.rs b/components/style/values/specified/font.rs index 13ca2280997..17ff3af6382 100644 --- a/components/style/values/specified/font.rs +++ b/components/style/values/specified/font.rs @@ -15,14 +15,16 @@ use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use parser::{Parse, ParserContext}; use properties::longhands::system_font::SystemFont; use std::fmt::{self, Write}; -use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; +use style_traits::{CssWriter, KeywordsCollectFn, ParseError}; +use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss}; +use style_traits::values::SequenceWriter; use values::CustomIdent; use values::computed::{Angle as ComputedAngle, Percentage as ComputedPercentage}; use values::computed::{font as computed, Context, Length, NonNegativeLength, ToComputedValue}; use values::computed::font::{FamilyName, FontFamilyList, FontStyleAngle, SingleFontFamily}; use values::generics::NonNegative; -use values::generics::font::{KeywordSize, VariationValue}; use values::generics::font::{self as generics, FeatureTagValue, FontSettings, FontTag}; +use values::generics::font::{KeywordSize, VariationValue}; use values::specified::{AllowQuirks, Angle, Integer, LengthOrPercentage, NoCalcLength, Number, Percentage}; use values::specified::length::{FontBaseSize, AU_PER_PT, AU_PER_PX}; From 292f899631f0faa43192e23748117987c8964c3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Sun, 29 Apr 2018 03:02:21 +0200 Subject: [PATCH 25/26] style: Fix tidy issues and Servo build. --- Cargo.lock | 2 +- components/layout/display_list/builder.rs | 8 ++--- components/servo_arc/lib.rs | 2 +- .../style/properties/longhand/font.mako.rs | 2 +- components/style/servo/url.rs | 2 +- components/style/values/generics/image.rs | 2 ++ components/style/values/mod.rs | 4 +-- components/style/values/specified/box.rs | 2 +- components/style/values/specified/font.rs | 2 +- .../style_derive/specified_value_info.rs | 4 +-- components/style_traits/Cargo.toml | 5 +-- components/style_traits/lib.rs | 1 + .../style_traits/specified_value_info.rs | 7 ++++ tests/unit/style/properties/serialization.rs | 36 ------------------- tests/unit/style/rule_tree/bench.rs | 9 ++--- 15 files changed, 32 insertions(+), 56 deletions(-) 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 b84ba879350..e2063c79a9c 100644 --- a/components/servo_arc/lib.rs +++ b/components/servo_arc/lib.rs @@ -925,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, Debug, PartialEq)] +#[derive(Debug, Eq, PartialEq)] pub struct ArcBorrow<'a, T: 'a>(&'a T); impl<'a, T> Copy for ArcBorrow<'a, T> {} diff --git a/components/style/properties/longhand/font.mako.rs b/components/style/properties/longhand/font.mako.rs index 112b4b4de54..7309aca8a38 100644 --- a/components/style/properties/longhand/font.mako.rs +++ b/components/style/properties/longhand/font.mako.rs @@ -450,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/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/values/generics/image.rs b/components/style/values/generics/image.rs index 5017559e00c..2da4d290039 100644 --- a/components/style/values/generics/image.rs +++ b/components/style/values/generics/image.rs @@ -145,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 diff --git a/components/style/values/mod.rs b/components/style/values/mod.rs index a61b774bdbf..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 @@ -162,7 +162,7 @@ impl ToCss for CustomIdent { } /// -#[derive(Clone, Debug, MallocSizeOf, ToComputedValue, SpecifiedValueInfo)] +#[derive(Clone, Debug, MallocSizeOf, SpecifiedValueInfo, ToComputedValue)] pub enum KeyframesName { /// Ident(CustomIdent), diff --git a/components/style/values/specified/box.rs b/components/style/values/specified/box.rs index ab2872d26c3..f56d6afd430 100644 --- a/components/style/values/specified/box.rs +++ b/components/style/values/specified/box.rs @@ -522,7 +522,7 @@ pub fn assert_touch_action_matches() { } bitflags! { - #[derive(MallocSizeOf, ToComputedValue, SpecifiedValueInfo)] + #[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 { diff --git a/components/style/values/specified/font.rs b/components/style/values/specified/font.rs index 17ff3af6382..8ec4354ab7a 100644 --- a/components/style/values/specified/font.rs +++ b/components/style/values/specified/font.rs @@ -23,8 +23,8 @@ use values::computed::{Angle as ComputedAngle, Percentage as ComputedPercentage} use values::computed::{font as computed, Context, Length, NonNegativeLength, ToComputedValue}; use values::computed::font::{FamilyName, FontFamilyList, FontStyleAngle, SingleFontFamily}; use values::generics::NonNegative; -use values::generics::font::{self as generics, FeatureTagValue, FontSettings, FontTag}; use values::generics::font::{KeywordSize, VariationValue}; +use values::generics::font::{self as generics, FeatureTagValue, FontSettings, FontTag}; use values::specified::{AllowQuirks, Angle, Integer, LengthOrPercentage, NoCalcLength, Number, Percentage}; use values::specified::length::{FontBaseSize, AU_PER_PT, AU_PER_PX}; diff --git a/components/style_derive/specified_value_info.rs b/components/style_derive/specified_value_info.rs index 7168ec2509f..11ad7a0d1b4 100644 --- a/components/style_derive/specified_value_info.rs +++ b/components/style_derive/specified_value_info.rs @@ -4,7 +4,7 @@ use cg; use quote::Tokens; -use syn::{Data, DeriveInput, Fields, Ident,Type}; +use syn::{Data, DeriveInput, Fields, Ident, Type}; use to_css::{CssFieldAttrs, CssInputAttrs, CssVariantAttrs}; pub fn derive(mut input: DeriveInput) -> Tokens { @@ -101,7 +101,7 @@ pub fn derive(mut input: DeriveInput) -> Tokens { quote!() } else { let mut value_list = quote!(); - value_list.append_separated(values.iter(), quote!(,)); + value_list.append_separated(values.iter(), quote! { , }); quote! { _f(&[#value_list]); } }; 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/lib.rs b/components/style_traits/lib.rs index 8d4e0846cc9..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; diff --git a/components/style_traits/specified_value_info.rs b/components/style_traits/specified_value_info.rs index 122091fc8e9..28e1eef25e6 100644 --- a/components/style_traits/specified_value_info.rs +++ b/components/style_traits/specified_value_info.rs @@ -6,6 +6,7 @@ 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 @@ -84,6 +85,11 @@ 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) { @@ -111,6 +117,7 @@ macro_rules! impl_generic_specified_value_info { 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) 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 From e00ca62c153e68ab3713f62e08f71c818068b9f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Sun, 29 Apr 2018 07:03:06 +0200 Subject: [PATCH 26/26] Update test expectations. --- tests/wpt/metadata/css/cssom/shorthand-values.html.ini | 3 --- 1 file changed, 3 deletions(-) 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