--- 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.