author | Xidorn Quan <me@upsuper.org> |
Sun, 29 Apr 2018 09:03:31 +1000 | |
changeset 416183 | b9e4fda9a50f2cc7ab722df3e9549a9b4e653970 |
parent 416182 | 83df94ad2416a8f603acdbdc9fccdfccea90ffba |
child 416184 | 1baf959951783147c5d1a0321eb6577a0f6c1e09 |
push id | 33918 |
push user | nerli@mozilla.com |
push date | Sun, 29 Apr 2018 09:47:13 +0000 |
treeherder | mozilla-central@afbec7f03bd8 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | emilio |
bugs | 1434130 |
milestone | 61.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/servo/components/style/values/generics/basic_shape.rs +++ b/servo/components/style/values/generics/basic_shape.rs @@ -64,34 +64,37 @@ pub enum BasicShape<H, V, LengthOrPercen Inset(#[css(field_bound)] InsetRect<LengthOrPercentage>), Circle(#[css(field_bound)] Circle<H, V, LengthOrPercentage>), Ellipse(#[css(field_bound)] Ellipse<H, V, LengthOrPercentage>), Polygon(Polygon<LengthOrPercentage>), } /// <https://drafts.csswg.org/css-shapes/#funcdef-inset> #[allow(missing_docs)] +#[css(function = "inset")] #[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] pub struct InsetRect<LengthOrPercentage> { pub rect: Rect<LengthOrPercentage>, pub round: Option<BorderRadius<LengthOrPercentage>>, } /// <https://drafts.csswg.org/css-shapes/#funcdef-circle> #[allow(missing_docs)] +#[css(function)] #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] pub struct Circle<H, V, LengthOrPercentage> { pub position: Position<H, V>, pub radius: ShapeRadius<LengthOrPercentage>, } /// <https://drafts.csswg.org/css-shapes/#funcdef-ellipse> #[allow(missing_docs)] +#[css(function)] #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] pub struct Ellipse<H, V, LengthOrPercentage> { pub position: Position<H, V>, pub semiaxis_x: ShapeRadius<LengthOrPercentage>, pub semiaxis_y: ShapeRadius<LengthOrPercentage>, } @@ -105,16 +108,17 @@ pub enum ShapeRadius<LengthOrPercentage> ClosestSide, #[animation(error)] FarthestSide, } /// A generic type for representing the `polygon()` function /// /// <https://drafts.csswg.org/css-shapes/#funcdef-polygon> +#[css(function)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] pub struct Polygon<LengthOrPercentage> { /// The filling rule for a polygon. pub fill: FillRule, /// A collection of (x, y) coordinates to draw the polygon. pub coordinates: Vec<(LengthOrPercentage, LengthOrPercentage)>, }
--- a/servo/components/style/values/generics/border.rs +++ b/servo/components/style/values/generics/border.rs @@ -23,16 +23,17 @@ pub enum BorderImageSideWidth<LengthOrPe /// A generic value for the `border-image-slice` property. #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] pub struct BorderImageSlice<NumberOrPercentage> { /// The offsets. pub offsets: Rect<NumberOrPercentage>, /// Whether to fill the middle part. + #[value_info(represents_keyword)] pub fill: bool, } /// A generic value for the `border-*-radius` longhand properties. #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] pub struct BorderCornerRadius<L>(#[css(field_bound)] pub Size<L>);
--- a/servo/components/style/values/generics/counters.rs +++ b/servo/components/style/values/generics/counters.rs @@ -54,17 +54,17 @@ impl<I> Deref for CounterReset<I> { } } /// A generic value for lists of counters. /// /// Keyword `none` is represented by an empty vector. #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] -pub struct Counters<I>(Box<[(CustomIdent, I)]>); +pub struct Counters<I>(#[css(if_empty = "none")] Box<[(CustomIdent, I)]>); impl<I> Default for Counters<I> { #[inline] fn default() -> Self { Counters(vec![].into_boxed_slice()) } }
--- a/servo/components/style/values/generics/effects.rs +++ b/servo/components/style/values/generics/effects.rs @@ -14,16 +14,17 @@ use values::specified::url::SpecifiedUrl ToAnimatedValue, ToAnimatedZero)] pub struct BoxShadow<Color, SizeLength, BlurShapeLength, ShapeLength> { /// The base shadow. pub base: SimpleShadow<Color, SizeLength, BlurShapeLength>, /// The spread radius. pub spread: ShapeLength, /// Whether this is an inset box shadow. #[animation(constant)] + #[value_info(represents_keyword)] pub inset: bool, } /// A generic value for a single `filter`. #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[derive(Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToComputedValue, ToCss)] pub enum Filter<Angle, Factor, Length, DropShadow> {
--- a/servo/components/style/values/generics/font.rs +++ b/servo/components/style/values/generics/font.rs @@ -226,10 +226,11 @@ impl Default for KeywordSize { #[allow(missing_docs)] #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero)] pub enum FontStyle<Angle> { #[animation(error)] Normal, #[animation(error)] Italic, + #[value_info(starts_with_keyword)] Oblique(Angle), }
--- a/servo/components/style/values/generics/grid.rs +++ b/servo/components/style/values/generics/grid.rs @@ -193,20 +193,22 @@ impl<L> TrackBreadth<L> { #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo)] pub enum TrackSize<L> { /// A flexible `<track-breadth>` Breadth(TrackBreadth<L>), /// A `minmax` function for a range over an inflexible `<track-breadth>` /// and a flexible `<track-breadth>` /// /// <https://drafts.csswg.org/css-grid/#valdef-grid-template-columns-minmax> + #[css(function)] Minmax(TrackBreadth<L>, TrackBreadth<L>), /// A `fit-content` function. /// /// <https://drafts.csswg.org/css-grid/#valdef-grid-template-columns-fit-content> + #[css(function)] FitContent(L), } impl<L> TrackSize<L> { /// Check whether this is a `<fixed-size>` /// /// <https://drafts.csswg.org/css-grid/#typedef-fixed-size> pub fn is_fixed(&self) -> bool { @@ -341,18 +343,17 @@ where } Ok(()) } /// The initial argument of the `repeat` function. /// /// <https://drafts.csswg.org/css-grid/#typedef-track-repeat> -#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, - ToComputedValue, ToCss)] +#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)] pub enum RepeatCount<Integer> { /// A positive integer. This is allowed only for `<track-repeat>` and `<fixed-repeat>` Number(Integer), /// An `<auto-fill>` keyword allowed only for `<auto-repeat>` AutoFill, /// An `<auto-fit>` keyword allowed only for `<auto-repeat>` AutoFit, } @@ -379,16 +380,17 @@ impl Parse for RepeatCount<specified::In } /// The structure containing `<line-names>` and `<track-size>` values. /// /// It can also hold `repeat()` function parameters, which expands into the respective /// values in its computed form. #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] +#[css(function = "repeat")] pub struct TrackRepeat<L, I> { /// The number of times for the value to be repeated (could also be `auto-fit` or `auto-fill`) pub count: RepeatCount<I>, /// `<line-names>` accompanying `<track_size>` values. /// /// If there's no `<line-names>`, then it's represented by an empty vector. /// For N `<track-size>` values, there will be N+1 `<line-names>`, and so this vector's /// length is always one value more than that of the `<track-size>`. @@ -476,18 +478,17 @@ pub enum TrackListValue<LengthOrPercenta TrackSize(TrackSize<LengthOrPercentage>), /// A <track-repeat> value. TrackRepeat(TrackRepeat<LengthOrPercentage, Integer>), } /// The type of a `<track-list>` as determined during parsing. /// /// <https://drafts.csswg.org/css-grid/#typedef-track-list> -#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, - ToComputedValue)] +#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue)] pub enum TrackListType { /// [`<auto-track-list>`](https://drafts.csswg.org/css-grid/#typedef-auto-track-list) /// /// If this type exists, then the value at the index in `line_names` field in `TrackList` /// has the `<line-names>?` list that comes before `<auto-repeat>`. If it's a specified value, /// then the `repeat()` function (that follows the line names list) is also at the given index /// in `values` field. On the contrary, if it's a computed value, then the `repeat()` function /// is in the `auto_repeat` field. @@ -505,16 +506,17 @@ pub enum TrackListType { /// /// <https://drafts.csswg.org/css-grid/#typedef-track-list> #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo)] pub struct TrackList<LengthOrPercentage, Integer> { /// The type of this `<track-list>` (auto, explicit or general). /// /// In order to avoid parsing the same value multiple times, this does a single traversal /// and arrives at the type of value it has parsed (or bails out gracefully with an error). + #[css(skip)] pub list_type: TrackListType, /// A vector of `<track-size> | <track-repeat>` values. pub values: Vec<TrackListValue<LengthOrPercentage, Integer>>, /// `<line-names>` accompanying `<track-size> | <track-repeat>` values. /// /// If there's no `<line-names>`, then it's represented by an empty vector. /// For N values, there will be N+1 `<line-names>`, and so this vector's /// length is always one value more than that of the `<track-size>`.
--- a/servo/components/style/values/generics/image.rs +++ b/servo/components/style/values/generics/image.rs @@ -21,16 +21,17 @@ pub enum Image<Gradient, MozImageRect, I /// A `<url()>` image. Url(ImageUrl), /// A `<gradient>` image. Gradients are rather large, and not nearly as /// common as urls, so we box them here to keep the size of this enum sane. Gradient(Box<Gradient>), /// A `-moz-image-rect` image. Also fairly large and rare. Rect(Box<MozImageRect>), /// A `-moz-element(# <element-id>)` + #[css(function = "-moz-element")] Element(Atom), /// A paint worklet image. /// <https://drafts.css-houdini.org/css-paint-api/> #[cfg(feature = "servo")] PaintWorklet(PaintWorklet), } /// A CSS gradient.
--- a/servo/components/style/values/generics/transform.rs +++ b/servo/components/style/values/generics/transform.rs @@ -75,40 +75,44 @@ pub struct TransformOrigin<H, V, Depth> pub vertical: V, /// The depth. pub depth: Depth, } /// A generic timing function. /// /// <https://drafts.csswg.org/css-timing-1/#single-timing-function-production> -#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss)] +#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToCss)] +#[value_info(ty = "TIMING_FUNCTION")] pub enum TimingFunction<Integer, Number> { /// `linear | ease | ease-in | ease-out | ease-in-out` Keyword(TimingKeyword), /// `cubic-bezier(<number>, <number>, <number>, <number>)` #[allow(missing_docs)] #[css(comma, function)] CubicBezier { x1: Number, y1: Number, x2: Number, y2: Number, }, /// `step-start | step-end | steps(<integer>, [ start | end ]?)` #[css(comma, function)] + #[value_info(other_values = "step-start,step-end")] Steps(Integer, #[css(skip_if = "is_end")] StepPosition), /// `frames(<integer>)` #[css(comma, function)] Frames(Integer), } #[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, EaseIn, EaseOut, EaseInOut, }
--- a/servo/components/style/values/specified/box.rs +++ b/servo/components/style/values/specified/box.rs @@ -4,17 +4,17 @@ //! Specified types for box properties. use Atom; 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; use values::generics::box_::VerticalAlign as GenericVerticalAlign; use values::specified::{AllowQuirks, Number}; use values::specified::length::{LengthOrPercentage, NonNegativeLength}; #[allow(missing_docs)] @@ -293,16 +293,17 @@ impl AnimationIterationCount { pub fn one() -> Self { GenericAnimationIterationCount::Number(Number::new(1.0)) } } /// 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<KeyframesName>); impl AnimationName { /// Get the name of the animation as an `Atom`. pub fn as_atom(&self) -> Option<&Atom> { self.0.as_ref().map(|n| n.as_atom()) } @@ -415,18 +416,19 @@ impl Parse for WillChange { Ok(WillChange::AnimateableFeatures( custom_idents.into_boxed_slice(), )) } } 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; /// `auto` variant const TOUCH_ACTION_AUTO = 1 << 1; /// `pan-x` variant const TOUCH_ACTION_PAN_X = 1 << 2; /// `pan-y` variant @@ -488,18 +490,16 @@ impl Parse for TouchAction { } else { Ok(TouchAction::TOUCH_ACTION_PAN_Y) } }, } } } -impl SpecifiedValueInfo for TouchAction {} - #[cfg(feature = "gecko")] impl_bitflags_conversions!(TouchAction); /// Asserts that all touch-action matches its NS_STYLE_TOUCH_ACTION_* value. #[cfg(feature = "gecko")] #[inline] pub fn assert_touch_action_matches() { use gecko_bindings::structs; @@ -517,17 +517,18 @@ pub fn assert_touch_action_matches() { NS_STYLE_TOUCH_ACTION_AUTO => TouchAction::TOUCH_ACTION_AUTO, NS_STYLE_TOUCH_ACTION_PAN_X => TouchAction::TOUCH_ACTION_PAN_X, NS_STYLE_TOUCH_ACTION_PAN_Y => TouchAction::TOUCH_ACTION_PAN_Y, NS_STYLE_TOUCH_ACTION_MANIPULATION => TouchAction::TOUCH_ACTION_MANIPULATION, } } 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 const LAYOUT = 0x01; /// `style` variant, turns on style containment const STYLE = 0x02; /// `paint` variant, turns on paint containment const PAINT = 0x04; @@ -600,18 +601,16 @@ impl Parse for Contain { if !result.is_empty() { Ok(result) } else { Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) } } } -impl SpecifiedValueInfo for Contain {} - /// A specified value for the `perspective` property. pub type Perspective = GenericPerspective<NonNegativeLength>; impl Parse for Perspective { fn parse<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<Self, ParseError<'i>> {
--- a/servo/components/style/values/specified/font.rs +++ b/servo/components/style/values/specified/font.rs @@ -1942,19 +1942,21 @@ impl Parse for FontFeatureSettings { #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] /// Whether user agents are allowed to synthesize bold or oblique font faces /// when a font family lacks bold or italic faces 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, } impl FontSynthesis { #[inline] /// Get the default value of font-synthesis pub fn get_initial_value() -> Self { FontSynthesis {
--- a/servo/components/style/values/specified/inherited_box.rs +++ b/servo/components/style/values/specified/inherited_box.rs @@ -16,16 +16,17 @@ use values::specified::Angle; /// The specified value of the `image-orientation` property. /// https://drafts.csswg.org/css-images/#propdef-image-orientation #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo)] pub struct ImageOrientation { /// The angle specified, if any pub angle: Option<Angle>, /// Whether or not "flip" was specified + #[value_info(other_values = "flip,from-image")] pub flipped: bool, } impl ToCss for ImageOrientation { fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: Write, {
--- a/servo/components/style/values/specified/list.rs +++ b/servo/components/style/values/specified/list.rs @@ -73,19 +73,20 @@ impl Parse for ListStyleType { )) } } /// Specified and computed `quote` property. /// /// 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<str>, Box<str>)]>); +pub struct Quotes(#[css(if_empty = "none")] pub Box<[(Box<str>, Box<str>)]>); impl ToCss for Quotes { fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: Write, { let mut iter = self.0.iter();
--- a/servo/components/style/values/specified/mod.rs +++ b/servo/components/style/values/specified/mod.rs @@ -565,16 +565,17 @@ pub type TrackList = GenericTrackList<Le /// The specified value of a `<grid-line>`. pub type GridLine = GenericGridLine<Integer>; /// `<grid-template-rows> | <grid-template-columns>` pub type GridTemplateComponent = GenericGridTemplateComponent<LengthOrPercentage, Integer>; #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo)] /// rect(<top>, <left>, <bottom>, <right>) used by clip and image-region +#[css(function = "rect")] pub struct ClipRect { /// <top> (<length> | <auto>) pub top: Option<Length>, /// <right> (<length> | <auto>) pub right: Option<Length>, /// <bottom> (<length> | <auto>) pub bottom: Option<Length>, /// <left> (<length> | <auto>) @@ -752,17 +753,19 @@ impl AllowQuirks { pub fn allowed(self, quirks_mode: QuirksMode) -> bool { self == AllowQuirks::Yes && quirks_mode == QuirksMode::Quirks } } /// 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)>, /// Attribute name pub attribute: Atom, } impl Parse for Attr { @@ -847,10 +850,8 @@ impl ToCss for Attr { if let Some((ref prefix, ref _url)) = self.namespace { serialize_atom_identifier(prefix, dest)?; dest.write_str("|")?; } serialize_atom_identifier(&self.attribute, dest)?; dest.write_str(")") } } - -impl SpecifiedValueInfo for Attr {}
--- a/servo/components/style/values/specified/position.rs +++ b/servo/components/style/values/specified/position.rs @@ -426,16 +426,17 @@ pub enum AutoFlow { #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] /// Controls how the auto-placement algorithm works /// specifying exactly how auto-placed items get flowed into the grid 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, } impl GridAutoFlow { #[inline] /// Get default `grid-auto-flow` as `row` pub fn row() -> GridAutoFlow { GridAutoFlow {
--- a/servo/components/style/values/specified/transform.rs +++ b/servo/components/style/values/specified/transform.rs @@ -2,17 +2,17 @@ * 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/. */ //! Specified types for CSS values that are related to transformations. 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; use values::generics::transform as generic; use values::generics::transform::{Matrix, Matrix3D, StepPosition, TimingKeyword}; use values::specified::{self, Angle, Integer, Length, LengthOrPercentage, Number}; use values::specified::position::{Side, X, Y}; @@ -241,20 +241,16 @@ pub enum OriginComponent<S> { Length(LengthOrPercentage), /// `<side>` Side(S), } /// A specified timing function. pub type TimingFunction = generic::TimingFunction<Integer, Number>; -impl SpecifiedValueInfo for TimingFunction { - const SUPPORTED_TYPES: u8 = CssType::TIMING_FUNCTION; -} - impl Parse for TransformOrigin { fn parse<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<Self, ParseError<'i>> { let parse_depth = |input: &mut Parser| { input .try(|i| Length::parse(context, i))
--- a/servo/components/style_derive/lib.rs +++ b/servo/components/style_derive/lib.rs @@ -59,13 +59,13 @@ pub fn derive_to_computed_value(stream: } #[proc_macro_derive(ToCss, attributes(css))] 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))] +#[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() }
--- a/servo/components/style_derive/specified_value_info.rs +++ b/servo/components/style_derive/specified_value_info.rs @@ -1,56 +1,67 @@ /* 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, 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::<CssInputAttrs>(&input); + let css_attrs = cg::parse_input_attrs::<CssInputAttrs>(&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. } else { let mut where_clause = input.generics.where_clause.take(); for param in input.generics.type_params() { cg::add_predicate( &mut where_clause, parse_quote!(#param: ::style_traits::SpecifiedValueInfo), ); } input.generics.where_clause = where_clause; match input.data { Data::Enum(ref e) => { for v in e.variants.iter() { - let attrs = cg::parse_variant_attrs::<CssVariantAttrs>(&v); - if attrs.skip { + let css_attrs = cg::parse_variant_attrs::<CssVariantAttrs>(&v); + let info_attrs = cg::parse_variant_attrs::<ValueInfoVariantAttrs>(&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) { values.push(variant_name()); } } } } @@ -58,26 +69,39 @@ pub fn derive(mut input: DeriveInput) -> if !derive_struct_fields(&s.fields, &mut types, &mut values) { values.push(input_name()); } } Data::Union(_) => unreachable!("union is not supported"), } } + let info_attrs = cg::parse_input_attrs::<ValueInfoInputAttrs>(&input); + if let Some(other_values) = info_attrs.other_values { + for value in other_values.split(",") { + values.push(value.to_string()); + } + } + let mut types_value = quote!(0); types_value.append_all(types.iter().map(|ty| quote! { | <#ty as ::style_traits::SpecifiedValueInfo>::SUPPORTED_TYPES })); let mut nested_collects = quote!(); nested_collects.append_all(types.iter().map(|ty| quote! { <#ty as ::style_traits::SpecifiedValueInfo>::collect_completion_keywords(_f); })); + if let Some(ty) = info_attrs.ty { + types_value.append_all(quote! { + | ::style_traits::CssType::#ty + }); + } + let append_values = if values.is_empty() { quote!() } else { let mut value_list = quote!(); value_list.append_separated(values.iter(), quote!(,)); quote! { _f(&[#value_list]); } }; @@ -105,20 +129,53 @@ fn derive_struct_fields<'a>( values: &mut Vec<String>, ) -> bool { let fields = match *fields { Fields::Unit => return false, Fields::Named(ref fields) => fields.named.iter(), Fields::Unnamed(ref fields) => fields.unnamed.iter(), }; types.extend(fields.filter_map(|field| { - let attrs = cg::parse_field_attrs::<CssFieldAttrs>(field); - if let Some(if_empty) = attrs.if_empty { + let info_attrs = cg::parse_field_attrs::<ValueInfoFieldAttrs>(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::<CssFieldAttrs>(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 } })); true } + +#[darling(attributes(value_info), default)] +#[derive(Default, FromDeriveInput)] +struct ValueInfoInputAttrs { + ty: Option<Ident>, + other_values: Option<String>, +} + +#[darling(attributes(value_info), default)] +#[derive(Default, FromVariant)] +struct ValueInfoVariantAttrs { + starts_with_keyword: bool, + other_values: Option<String>, +} + +#[darling(attributes(value_info), default)] +#[derive(Default, FromField)] +struct ValueInfoFieldAttrs { + represents_keyword: bool, + other_values: Option<String>, +}
--- a/servo/components/style_traits/specified_value_info.rs +++ b/servo/components/style_traits/specified_value_info.rs @@ -22,16 +22,46 @@ pub mod CssType { /// <timing-function> pub const TIMING_FUNCTION: u8 = 1 << 2; } /// See SpecifiedValueInfo::collect_completion_keywords. pub type KeywordsCollectFn<'a> = &'a mut FnMut(&[&'static str]); /// Information of values of a given specified value type. +/// +/// This trait is derivable with `#[derive(SpecifiedValueInfo)]`. +/// +/// The algorithm traverses the type definition. For `SUPPORTED_TYPES`, +/// it puts an or'ed value of `SUPPORTED_TYPES` of all types it finds. +/// For `collect_completion_keywords`, it recursively invokes this +/// method on types found, and lists all keyword values and function +/// names following the same rule as `ToCss` in that method. +/// +/// Some attributes of `ToCss` can affect the behavior, specifically: +/// * If `#[css(function)]` is found, the content inside the annotated +/// variant (or the whole type) isn't traversed, only the function +/// name is listed in `collect_completion_keywords`. +/// * If `#[css(skip)]` is found, the content inside the variant or +/// field is ignored. +/// * Values listed in `#[css(if_empty)]`, `#[css(aliases)]`, and +/// `#[css(keyword)]` are added into `collect_completion_keywords`. +/// +/// In addition to `css` attributes, it also has `value_info` helper +/// attributes, including: +/// * `#[value_info(ty = "TYPE")]` can be used to specify a constant +/// from `CssType` to `SUPPORTED_TYPES`. +/// * `#[value_info(other_values = "value1,value2")]` can be used to +/// add other values related to a field, variant, or the type itself +/// into `collect_completion_keywords`. +/// * `#[value_info(starts_with_keyword)]` can be used on variants to +/// add the name of a non-unit variant (serialized like `ToCss`) into +/// `collect_completion_keywords`. +/// * `#[value_info(represents_keyword)]` can be used on fields into +/// `collect_completion_keywords`. pub trait SpecifiedValueInfo { /// Supported CssTypes by the given value type. /// /// XXX This should be typed CssType when that becomes a bitflags. /// Currently we cannot do so since bitflags cannot be used in constant. const SUPPORTED_TYPES: u8 = 0; /// Collect value starting words for the given specified value type.