diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2017-06-07 08:55:08 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-06-07 08:55:08 -0700 |
commit | 738483742c32f6de680b13be31ffc552059b39b9 (patch) | |
tree | 058ec0acdb2b6df5679394c967e982abdc039f8b | |
parent | 7e273d6c9b86d6ffbf216e84ae7326976888e5ef (diff) | |
parent | 45e8b0e8c7a7958c688fbbfcdd056592a9958ca5 (diff) | |
download | servo-738483742c32f6de680b13be31ffc552059b39b9.tar.gz servo-738483742c32f6de680b13be31ffc552059b39b9.zip |
Auto merge of #17209 - servo:derive-all-the-things, r=emilio
Introduce more generics and more deriving
<!-- Reviewable:start -->
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/17209)
<!-- Reviewable:end -->
20 files changed, 153 insertions, 323 deletions
diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index fa2bac3f618..efefebcfe16 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -3894,18 +3894,18 @@ fn static_assert() { } pub fn set_initial_letter(&mut self, v: longhands::initial_letter::computed_value::T) { - use properties::longhands::initial_letter::computed_value::T; + use values::generics::text::InitialLetter; match v { - T::Normal => { + InitialLetter::Normal => { self.gecko.mInitialLetterSize = 0.; self.gecko.mInitialLetterSink = 0; }, - T::Specified(size, sink) => { - self.gecko.mInitialLetterSize = size.get(); + InitialLetter::Specified(size, sink) => { + self.gecko.mInitialLetterSize = size; if let Some(sink) = sink { - self.gecko.mInitialLetterSink = sink.value(); + self.gecko.mInitialLetterSink = sink; } else { - self.gecko.mInitialLetterSink = size.get().floor() as i32; + self.gecko.mInitialLetterSink = size.floor() as i32; } } } diff --git a/components/style/properties/longhand/box.mako.rs b/components/style/properties/longhand/box.mako.rs index 2bf0c1b17f3..0b358609ab7 100644 --- a/components/style/properties/longhand/box.mako.rs +++ b/components/style/properties/longhand/box.mako.rs @@ -545,8 +545,6 @@ ${helpers.predefined_type("animation-timing-function", extra_prefixes="moz webkit" spec="https://drafts.csswg.org/css-animations/#propdef-animation-iteration-count", allowed_in_keyframe_block="False"> - use std::fmt; - use style_traits::ToCss; use values::computed::ComputedValueAsSpecified; pub mod computed_value { @@ -554,8 +552,8 @@ ${helpers.predefined_type("animation-timing-function", } // https://drafts.csswg.org/css-animations/#animation-iteration-count - #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] + #[derive(Debug, Clone, PartialEq, ToCss)] pub enum SpecifiedValue { Number(f32), Infinite, @@ -576,15 +574,6 @@ ${helpers.predefined_type("animation-timing-function", } } - impl ToCss for SpecifiedValue { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - SpecifiedValue::Number(n) => write!(dest, "{}", n), - SpecifiedValue::Infinite => dest.write_str("infinite"), - } - } - } - no_viewport_percentage!(SpecifiedValue); #[inline] diff --git a/components/style/properties/longhand/font.mako.rs b/components/style/properties/longhand/font.mako.rs index 2c491a1630a..51963a7dbb0 100644 --- a/components/style/properties/longhand/font.mako.rs +++ b/components/style/properties/longhand/font.mako.rs @@ -1039,28 +1039,15 @@ ${helpers.single_keyword_system("font-variant-caps", pub mod computed_value { use properties::animated_properties::Animatable; - use std::fmt; - use style_traits::ToCss; use values::CSSFloat; - #[derive(Copy, Clone, Debug, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] + #[derive(Copy, Clone, Debug, PartialEq, ToCss)] pub enum T { None, Number(CSSFloat), } - impl ToCss for T { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result - where W: fmt::Write, - { - match *self { - T::None => dest.write_str("none"), - T::Number(number) => number.to_css(dest), - } - } - } - impl T { pub fn from_gecko_adjust(gecko: f32) -> Self { if gecko == -1.0 { @@ -2214,9 +2201,7 @@ ${helpers.single_keyword("-moz-math-variant", use app_units::Au; use cssparser::Parser; use properties::longhands; - use std::fmt; use std::hash::{Hash, Hasher}; - use style_traits::ToCss; use values::computed::{ToComputedValue, Context}; <% system_fonts = """caption icon menu message-box small-caption status-bar @@ -2230,23 +2215,13 @@ ${helpers.single_keyword("-moz-math-variant", kw_cast = """font_style font_variant_caps font_stretch font_kerning font_variant_position""".split() %> - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] + #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, ToCss)] pub enum SystemFont { % for font in system_fonts: ${to_camel_case(font)}, % endfor } - impl ToCss for SystemFont { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - dest.write_str(match *self { - % for font in system_fonts: - SystemFont::${to_camel_case(font)} => "${font}", - % endfor - }) - } - } - // ComputedValues are compared at times // so we need these impls. We don't want to // add Eq to Number (which contains a float) diff --git a/components/style/properties/longhand/text.mako.rs b/components/style/properties/longhand/text.mako.rs index 0b4257b67f6..d636ed3cb64 100644 --- a/components/style/properties/longhand/text.mako.rs +++ b/components/style/properties/longhand/text.mako.rs @@ -287,72 +287,11 @@ ${helpers.predefined_type( ignored_when_colors_disabled=True, spec="https://drafts.csswg.org/css-text-decor/#propdef-text-decoration-color")} -<%helpers:longhand name="initial-letter" - animation_value_type="none" - products="gecko" - spec="https://drafts.csswg.org/css-inline/#sizing-drop-initials"> - use std::fmt; - use style_traits::ToCss; - use values::computed::ComputedValueAsSpecified; - use values::specified::{Number, Integer}; - - impl ComputedValueAsSpecified for SpecifiedValue {} - no_viewport_percentage!(SpecifiedValue); - - #[derive(PartialEq, Clone, Debug)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub enum SpecifiedValue { - Normal, - Specified(Number, Option<Integer>) - } - - pub mod computed_value { - pub use super::SpecifiedValue as T; - } - - impl ToCss for SpecifiedValue { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - SpecifiedValue::Normal => try!(dest.write_str("normal")), - SpecifiedValue::Specified(size, sink) => { - try!(size.to_css(dest)); - if let Some(sink) = sink { - try!(dest.write_str(" ")); - try!(sink.to_css(dest)); - } - } - }; - - Ok(()) - } - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T::Normal - } - - #[inline] - pub fn get_initial_specified_value() -> SpecifiedValue { - SpecifiedValue::Normal - } - - /// normal | <number> <integer>? - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { - if input.try(|input| input.expect_ident_matching("normal")).is_ok() { - return Ok(SpecifiedValue::Normal); - } - - let size = try!(Number::parse_at_least_one(context, input)); - - match input.try(|input| Integer::parse(context, input)) { - Ok(number) => { - if number.value() < 1 { - return Err(()); - } - Ok(SpecifiedValue::Specified(size, Some(number))) - } - Err(()) => Ok(SpecifiedValue::Specified(size, None)), - } - } -</%helpers:longhand> +${helpers.predefined_type( + "initial-letter", + "InitialLetter", + "computed::InitialLetter::normal()", + initial_specified_value="specified::InitialLetter::normal()", + animation_value_type="none", + products="gecko", + spec="https://drafts.csswg.org/css-inline/#sizing-drop-initials")} diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index 1ec0dee0ef7..1a4af56d9cc 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -450,8 +450,8 @@ impl PropertyDeclarationIdSet { % endfor /// An enum to represent a CSS Wide keyword. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] +#[derive(Copy, Clone, Debug, Eq, PartialEq, ToCss)] pub enum CSSWideKeyword { /// The `initial` keyword. Initial, @@ -483,12 +483,6 @@ impl CSSWideKeyword { } } -impl ToCss for CSSWideKeyword { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - dest.write_str(self.to_str()) - } -} - impl Parse for CSSWideKeyword { fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { let ident = input.expect_ident()?; @@ -628,8 +622,8 @@ impl LonghandId { } /// An identifier for a given shorthand property. -#[derive(Clone, Copy, Eq, PartialEq, Debug)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] +#[derive(Clone, Copy, Debug, Eq, PartialEq, ToCss)] pub enum ShorthandId { % for property in data.shorthands: /// ${property.name} @@ -637,14 +631,6 @@ pub enum ShorthandId { % endfor } -impl ToCss for ShorthandId { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result - where W: fmt::Write, - { - dest.write_str(self.name()) - } -} - impl ShorthandId { /// Get the name for this shorthand property. pub fn name(&self) -> &'static str { diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 1fbaa17c87f..1547cf29424 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -42,7 +42,7 @@ pub use self::length::{CalcLengthOrPercentage, Length, LengthOrNumber, LengthOrP pub use self::length::{LengthOrPercentageOrAutoOrContent, LengthOrPercentageOrNone, LengthOrNone}; pub use self::length::{MaxLength, MozLength}; pub use self::position::Position; -pub use self::text::{LetterSpacing, LineHeight, WordSpacing}; +pub use self::text::{InitialLetter, LetterSpacing, LineHeight, WordSpacing}; pub use self::transform::{TimingFunction, TransformOrigin}; pub mod background; diff --git a/components/style/values/computed/text.rs b/components/style/values/computed/text.rs index d45242015c4..857a985d851 100644 --- a/components/style/values/computed/text.rs +++ b/components/style/values/computed/text.rs @@ -6,9 +6,14 @@ use app_units::Au; use properties::animated_properties::Animatable; -use values::CSSFloat; +use values::{CSSInteger, CSSFloat}; use values::computed::length::{Length, LengthOrPercentage}; -use values::generics::text::{LineHeight as GenericLineHeight, Spacing}; +use values::generics::text::InitialLetter as GenericInitialLetter; +use values::generics::text::LineHeight as GenericLineHeight; +use values::generics::text::Spacing; + +/// A computed value for the `initial-letter` property. +pub type InitialLetter = GenericInitialLetter<CSSFloat, CSSInteger>; /// A computed value for the `letter-spacing` property. pub type LetterSpacing = Spacing<Length>; diff --git a/components/style/values/generics/background.rs b/components/style/values/generics/background.rs index af8cef23a38..aa24454ef6d 100644 --- a/components/style/values/generics/background.rs +++ b/components/style/values/generics/background.rs @@ -4,11 +4,8 @@ //! Generic types for CSS values related to backgrounds. -use std::fmt; -use style_traits::ToCss; - /// A generic value for the `background-size` property. -#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)] +#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue, ToCss)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub enum BackgroundSize<LengthOrPercentageOrAuto> { /// `<width> <height>` @@ -32,21 +29,3 @@ impl<L> From<L> for BackgroundSize<L> BackgroundSize::Explicit { width: value.clone(), height: value } } } - -impl<L> ToCss for BackgroundSize<L> - where L: ToCss -{ - fn to_css<W>(&self, dest: &mut W) -> fmt::Result - where W: fmt::Write - { - match *self { - BackgroundSize::Explicit { ref width, ref height } => { - width.to_css(dest)?; - dest.write_str(" ")?; - height.to_css(dest) - }, - BackgroundSize::Cover => dest.write_str("cover"), - BackgroundSize::Contain => dest.write_str("contain"), - } - } -} diff --git a/components/style/values/generics/basic_shape.rs b/components/style/values/generics/basic_shape.rs index b2d402dd38f..cd8e315f3b3 100644 --- a/components/style/values/generics/basic_shape.rs +++ b/components/style/values/generics/basic_shape.rs @@ -19,7 +19,7 @@ pub type ClippingShape<BasicShape> = ShapeSource<BasicShape, GeometryBox>; /// https://drafts.fxtf.org/css-masking-1/#typedef-geometry-box #[allow(missing_docs)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] -#[derive(Clone, Copy, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq, ToCss)] pub enum GeometryBox { FillBox, StrokeBox, @@ -142,17 +142,6 @@ impl<B: ToCss, T: ToCss> ToCss for ShapeSource<B, T> { } } -impl ToCss for GeometryBox { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - GeometryBox::FillBox => dest.write_str("fill-box"), - GeometryBox::StrokeBox => dest.write_str("stroke-box"), - GeometryBox::ViewBox => dest.write_str("view-box"), - GeometryBox::ShapeBox(s) => s.to_css(dest), - } - } -} - impl<L> ToCss for InsetRect<L> where L: ToCss + PartialEq { diff --git a/components/style/values/generics/border.rs b/components/style/values/generics/border.rs index f1384e580e3..5d8c9032e6a 100644 --- a/components/style/values/generics/border.rs +++ b/components/style/values/generics/border.rs @@ -11,7 +11,7 @@ use values::generics::rect::Rect; /// A generic value for a single side of a `border-image-width` property. #[cfg_attr(feature = "servo", derive(HeapSizeOf))] -#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)] +#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue, ToCss)] pub enum BorderImageSideWidth<LengthOrPercentage, Number> { /// `<length-or-percentage>` Length(LengthOrPercentage), @@ -52,20 +52,6 @@ pub struct BorderRadius<LengthOrPercentage> { /// A generic value for `border-*-radius` longhand properties. pub struct BorderCornerRadius<L>(pub Size2D<L>); -impl<L, N> ToCss for BorderImageSideWidth<L, N> - where L: ToCss, N: ToCss, -{ - fn to_css<W>(&self, dest: &mut W) -> fmt::Result - where W: fmt::Write - { - match *self { - BorderImageSideWidth::Length(ref length) => length.to_css(dest), - BorderImageSideWidth::Number(ref number) => number.to_css(dest), - BorderImageSideWidth::Auto => dest.write_str("auto"), - } - } -} - impl<N> From<N> for BorderImageSlice<N> where N: Clone, { diff --git a/components/style/values/generics/grid.rs b/components/style/values/generics/grid.rs index 73640a91e49..3775bb30597 100644 --- a/components/style/values/generics/grid.rs +++ b/components/style/values/generics/grid.rs @@ -329,8 +329,8 @@ pub fn concat_serialize_idents<W>(prefix: &str, suffix: &str, /// The initial argument of the `repeat` function. /// /// https://drafts.csswg.org/css-grid/#typedef-track-repeat -#[derive(Clone, Copy, PartialEq, Debug)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] +#[derive(Clone, Copy, Debug, PartialEq, ToCss)] pub enum RepeatCount { /// A positive integer. This is allowed only for `<track-repeat>` and `<fixed-repeat>` Number(Integer), @@ -340,16 +340,6 @@ pub enum RepeatCount { AutoFit, } -impl ToCss for RepeatCount { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - RepeatCount::Number(ref c) => c.to_css(dest), - RepeatCount::AutoFill => dest.write_str("auto-fill"), - RepeatCount::AutoFit => dest.write_str("auto-fit"), - } - } -} - impl Parse for RepeatCount { fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { if let Ok(i) = input.try(|i| Integer::parse(context, i)) { diff --git a/components/style/values/generics/mod.rs b/components/style/values/generics/mod.rs index ef88d7c342c..40d3f4e46df 100644 --- a/components/style/values/generics/mod.rs +++ b/components/style/values/generics/mod.rs @@ -182,8 +182,8 @@ impl<T: Parse> Parse for FontSettingTag<T> { /// A font settings value for font-variation-settings or font-feature-settings -#[derive(Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] +#[derive(Clone, Debug, Eq, PartialEq, ToCss)] pub enum FontSettings<T> { /// No settings (default) Normal, @@ -191,15 +191,6 @@ pub enum FontSettings<T> { Tag(Vec<FontSettingTag<T>>) } -impl<T: ToCss> ToCss for FontSettings<T> { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - FontSettings::Normal => dest.write_str("normal"), - FontSettings::Tag(ref ftvs) => ftvs.to_css(dest) - } - } -} - impl<T: Parse> Parse for FontSettings<T> { /// https://www.w3.org/TR/css-fonts-3/#propdef-font-feature-settings fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { @@ -290,8 +281,8 @@ pub struct SVGPaint<ColorType> { /// Whereas the spec only allows PaintServer /// to have a fallback, Gecko lets the context /// properties have a fallback as well. -#[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] +#[derive(Clone, Debug, PartialEq, ToCss)] pub enum SVGPaintKind<ColorType> { /// `none` None, @@ -378,18 +369,6 @@ impl<ColorType: Parse> Parse for SVGPaint<ColorType> { } } -impl<ColorType: ToCss> ToCss for SVGPaintKind<ColorType> { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - SVGPaintKind::None => dest.write_str("none"), - SVGPaintKind::ContextStroke => dest.write_str("context-stroke"), - SVGPaintKind::ContextFill => dest.write_str("context-fill"), - SVGPaintKind::Color(ref color) => color.to_css(dest), - SVGPaintKind::PaintServer(ref server) => server.to_css(dest), - } - } -} - impl<ColorType: ToCss> ToCss for SVGPaint<ColorType> { fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { self.kind.to_css(dest)?; diff --git a/components/style/values/generics/text.rs b/components/style/values/generics/text.rs index 2ba5ae4af98..5a5a10bb9d9 100644 --- a/components/style/values/generics/text.rs +++ b/components/style/values/generics/text.rs @@ -11,9 +11,50 @@ use properties::animated_properties::Animatable; use std::fmt; use style_traits::ToCss; -/// A generic spacing value for the `letter-spacing` and `word-spacing` properties.alloc +/// A generic value for the `initial-letter` property. #[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)] +pub enum InitialLetter<Number, Integer> { + /// `normal` + Normal, + /// `<number> <integer>?` + Specified(Number, Option<Integer>), +} + +impl<N, I> InitialLetter<N, I> { + /// Returns `normal`. + #[inline] + pub fn normal() -> Self { + InitialLetter::Normal + } +} + +impl<N, I> ToCss for InitialLetter<N, I> +where + N: ToCss, + I: ToCss, +{ + fn to_css<W>(&self, dest: &mut W) -> fmt::Result + where + W: fmt::Write, + { + match *self { + InitialLetter::Normal => dest.write_str("normal"), + InitialLetter::Specified(ref size, ref sink) => { + size.to_css(dest)?; + if let Some(ref sink) = *sink { + dest.write_str(" ")?; + sink.to_css(dest)?; + } + Ok(()) + }, + } + } +} + +/// A generic spacing value for the `letter-spacing` and `word-spacing` properties. +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue, ToCss)] pub enum Spacing<Value> { /// `normal` Normal, @@ -76,22 +117,9 @@ impl<Value> Animatable for Spacing<Value> } } -impl<Value> ToCss for Spacing<Value> - where Value: ToCss, -{ - fn to_css<W>(&self, dest: &mut W) -> fmt::Result - where W: fmt::Write - { - match *self { - Spacing::Normal => dest.write_str("normal"), - Spacing::Value(ref value) => value.to_css(dest), - } - } -} - /// A generic value for the `line-height` property. #[cfg_attr(feature = "servo", derive(HeapSizeOf))] -#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq)] +#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToCss)] pub enum LineHeight<Number, LengthOrPercentage> { /// `normal` Normal, @@ -111,19 +139,3 @@ impl<N, L> LineHeight<N, L> { LineHeight::Normal } } - -impl<N, L> ToCss for LineHeight<N, L> - where N: ToCss, L: ToCss, -{ - fn to_css<W>(&self, dest: &mut W) -> fmt::Result - where W: fmt::Write, - { - match *self { - LineHeight::Normal => dest.write_str("normal"), - #[cfg(feature = "gecko")] - LineHeight::MozBlockHeight => dest.write_str("-moz-block-height"), - LineHeight::Number(ref number) => number.to_css(dest), - LineHeight::Length(ref value) => value.to_css(dest), - } - } -} diff --git a/components/style/values/specified/border.rs b/components/style/values/specified/border.rs index b931ef36245..53260bc8e33 100644 --- a/components/style/values/specified/border.rs +++ b/components/style/values/specified/border.rs @@ -7,8 +7,6 @@ use app_units::Au; use cssparser::Parser; use parser::{Parse, ParserContext}; -use std::fmt; -use style_traits::ToCss; use values::computed::{Context, ToComputedValue}; use values::generics::border::BorderCornerRadius as GenericBorderCornerRadius; use values::generics::border::BorderImageSideWidth as GenericBorderImageSideWidth; @@ -20,7 +18,7 @@ use values::specified::length::{Length, LengthOrPercentage}; /// A specified value for a single side of the `border-width` property. #[cfg_attr(feature = "servo", derive(HeapSizeOf))] -#[derive(Clone, Debug, HasViewportPercentage, PartialEq)] +#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToCss)] pub enum BorderSideWidth { /// `thin` Thin, @@ -73,17 +71,6 @@ impl Parse for BorderSideWidth { } } -impl ToCss for BorderSideWidth { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - BorderSideWidth::Thin => dest.write_str("thin"), - BorderSideWidth::Medium => dest.write_str("medium"), - BorderSideWidth::Thick => dest.write_str("thick"), - BorderSideWidth::Length(ref length) => length.to_css(dest) - } - } -} - impl ToComputedValue for BorderSideWidth { type ComputedValue = Au; diff --git a/components/style/values/specified/length.rs b/components/style/values/specified/length.rs index 61335ee0e55..e7b49ee9392 100644 --- a/components/style/values/specified/length.rs +++ b/components/style/values/specified/length.rs @@ -894,9 +894,9 @@ impl LengthOrPercentage { } /// Either a `<length>`, a `<percentage>`, or the `auto` keyword. -#[derive(Clone, Debug, HasViewportPercentage, PartialEq)] -#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[allow(missing_docs)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToCss)] pub enum LengthOrPercentageOrAuto { Length(NoCalcLength), Percentage(Percentage), @@ -918,17 +918,6 @@ impl From<Percentage> for LengthOrPercentageOrAuto { } } -impl ToCss for LengthOrPercentageOrAuto { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - LengthOrPercentageOrAuto::Length(ref length) => length.to_css(dest), - LengthOrPercentageOrAuto::Percentage(percentage) => percentage.to_css(dest), - LengthOrPercentageOrAuto::Auto => dest.write_str("auto"), - LengthOrPercentageOrAuto::Calc(ref calc) => calc.to_css(dest), - } - } -} - impl LengthOrPercentageOrAuto { fn parse_internal(context: &ParserContext, input: &mut Parser, @@ -1012,8 +1001,8 @@ impl LengthOrPercentageOrAuto { } /// Either a `<length>`, a `<percentage>`, or the `none` keyword. -#[derive(Clone, Debug, HasViewportPercentage, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] +#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToCss)] #[allow(missing_docs)] pub enum LengthOrPercentageOrNone { Length(NoCalcLength), @@ -1022,16 +1011,6 @@ pub enum LengthOrPercentageOrNone { None, } -impl ToCss for LengthOrPercentageOrNone { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - LengthOrPercentageOrNone::Length(ref length) => length.to_css(dest), - LengthOrPercentageOrNone::Percentage(ref percentage) => percentage.to_css(dest), - LengthOrPercentageOrNone::Calc(ref calc) => calc.to_css(dest), - LengthOrPercentageOrNone::None => dest.write_str("none"), - } - } -} impl LengthOrPercentageOrNone { fn parse_internal(context: &ParserContext, input: &mut Parser, @@ -1099,8 +1078,8 @@ pub type LengthOrAuto = Either<Length, Auto>; /// Either a `<length>` or a `<percentage>` or the `auto` keyword or the /// `content` keyword. -#[derive(Clone, Debug, HasViewportPercentage, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] +#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToCss)] pub enum LengthOrPercentageOrAutoOrContent { /// A `<length>`. Length(NoCalcLength), @@ -1156,18 +1135,6 @@ impl LengthOrPercentageOrAutoOrContent { } } -impl ToCss for LengthOrPercentageOrAutoOrContent { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - LengthOrPercentageOrAutoOrContent::Length(ref len) => len.to_css(dest), - LengthOrPercentageOrAutoOrContent::Percentage(perc) => perc.to_css(dest), - LengthOrPercentageOrAutoOrContent::Auto => dest.write_str("auto"), - LengthOrPercentageOrAutoOrContent::Content => dest.write_str("content"), - LengthOrPercentageOrAutoOrContent::Calc(ref calc) => calc.to_css(dest), - } - } -} - /// Either a `<length>` or a `<number>`. pub type LengthOrNumber = Either<Length, Number>; diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index d7046451336..59ff135c303 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -45,7 +45,7 @@ pub use self::length::{Percentage, LengthOrNone, LengthOrNumber, LengthOrPercent pub use self::length::{LengthOrPercentageOrNone, LengthOrPercentageOrAutoOrContent, NoCalcLength}; pub use self::length::{MaxLength, MozLength}; pub use self::position::{Position, PositionComponent}; -pub use self::text::{LetterSpacing, LineHeight, WordSpacing}; +pub use self::text::{InitialLetter, LetterSpacing, LineHeight, WordSpacing}; pub use self::transform::{TimingFunction, TransformOrigin}; pub use super::generics::grid::GridLine; diff --git a/components/style/values/specified/text.rs b/components/style/values/specified/text.rs index cc517ad4abb..2d277e143ee 100644 --- a/components/style/values/specified/text.rs +++ b/components/style/values/specified/text.rs @@ -9,10 +9,15 @@ use parser::{Parse, ParserContext}; use std::ascii::AsciiExt; use values::computed::{Context, ToComputedValue}; use values::computed::text::LineHeight as ComputedLineHeight; -use values::generics::text::{LineHeight as GenericLineHeight, Spacing}; -use values::specified::{AllowQuirks, Number}; +use values::generics::text::InitialLetter as GenericInitialLetter; +use values::generics::text::LineHeight as GenericLineHeight; +use values::generics::text::Spacing; +use values::specified::{AllowQuirks, Integer, Number}; use values::specified::length::{FontRelativeLength, Length, LengthOrPercentage, NoCalcLength}; +/// A specified type for the `initial-letter` property. +pub type InitialLetter = GenericInitialLetter<Number, Integer>; + /// A specified value for the `letter-spacing` property. pub type LetterSpacing = Spacing<Length>; @@ -22,6 +27,17 @@ pub type WordSpacing = Spacing<LengthOrPercentage>; /// A specified value for the `line-height` property. pub type LineHeight = GenericLineHeight<Number, LengthOrPercentage>; +impl Parse for InitialLetter { + fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { + if input.try(|i| i.expect_ident_matching("normal")).is_ok() { + return Ok(GenericInitialLetter::Normal); + } + let size = Number::parse_at_least_one(context, input)?; + let sink = input.try(|i| Integer::parse_positive(context, i)).ok(); + Ok(GenericInitialLetter::Specified(size, sink)) + } +} + impl Parse for LetterSpacing { fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { Spacing::parse_with(context, input, |c, i| { diff --git a/components/style/values/specified/transform.rs b/components/style/values/specified/transform.rs index f41539fc5b2..e0e5b1c2d6f 100644 --- a/components/style/values/specified/transform.rs +++ b/components/style/values/specified/transform.rs @@ -7,8 +7,6 @@ use cssparser::Parser; use euclid::Point2D; use parser::{Parse, ParserContext}; -use std::fmt; -use style_traits::ToCss; use values::computed::{LengthOrPercentage as ComputedLengthOrPercentage, Context, ToComputedValue}; use values::computed::transform::TimingFunction as ComputedTimingFunction; use values::generics::transform::{StepPosition, TimingFunction as GenericTimingFunction}; @@ -22,7 +20,7 @@ pub type TransformOrigin = GenericTransformOrigin<OriginComponent<X>, OriginComp /// The specified value of a component of a CSS `<transform-origin>`. #[cfg_attr(feature = "servo", derive(HeapSizeOf))] -#[derive(Clone, Debug, HasViewportPercentage, PartialEq)] +#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToCss)] pub enum OriginComponent<S> { /// `center` Center, @@ -99,20 +97,6 @@ impl<S> Parse for OriginComponent<S> } } -impl<S: ToCss> ToCss for OriginComponent<S> - where S: ToCss, -{ - fn to_css<W>(&self, dest: &mut W) -> fmt::Result - where W: fmt::Write, - { - match *self { - OriginComponent::Center => dest.write_str("center"), - OriginComponent::Length(ref lop) => lop.to_css(dest), - OriginComponent::Side(ref keyword) => keyword.to_css(dest), - } - } -} - impl<S> ToComputedValue for OriginComponent<S> where S: Side, { diff --git a/components/style_derive/to_css.rs b/components/style_derive/to_css.rs index 774add083fa..f85fe1ce418 100644 --- a/components/style_derive/to_css.rs +++ b/components/style_derive/to_css.rs @@ -15,9 +15,12 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { } let style = synstructure::BindStyle::Ref.into(); - let match_body = synstructure::each_variant(&input, &style, |bindings, _| { + let match_body = synstructure::each_variant(&input, &style, |bindings, variant| { if bindings.is_empty() { - panic!("unit variants are not yet supported"); + let identifier = to_css_identifier(variant.ident.as_ref()); + return Some(quote! { + ::std::fmt::Write::write_str(dest, #identifier) + }); } let (first, rest) = bindings.split_first().expect("unit variants are not yet supported"); where_clause.predicates.push(where_predicate(first.field.ty.clone())); @@ -28,7 +31,7 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { where_clause.predicates.push(where_predicate(binding.field.ty.clone())); expr = quote! { #expr?; - dest.write_str(" ")?; + ::std::fmt::Write::write_str(dest, " ")?; ::style_traits::ToCss::to_css(#binding, dest) }; } @@ -68,3 +71,40 @@ fn where_predicate(ty: syn::Ty) -> syn::WherePredicate { )], }) } + +/// Transforms "FooBar" to "foo-bar". +/// +/// If the first Camel segment is "Moz"" or "Webkit", the result string +/// is prepended with "-". +fn to_css_identifier(mut camel_case: &str) -> String { + let mut first = true; + let mut result = String::with_capacity(camel_case.len()); + while let Some(segment) = split_camel_segment(&mut camel_case) { + if first { + match segment { + "Moz" | "Webkit" => first = false, + _ => {}, + } + } + if !first { + result.push_str("-"); + } + first = false; + result.push_str(&segment.to_lowercase()); + } + result +} + +/// Given "FooBar", returns "Foo" and sets `camel_case` to "Bar". +fn split_camel_segment<'input>(camel_case: &mut &'input str) -> Option<&'input str> { + let index = match camel_case.chars().next() { + None => return None, + Some(ch) => ch.len_utf8(), + }; + let end_position = camel_case[index..] + .find(char::is_uppercase) + .map_or(camel_case.len(), |pos| index + pos); + let result = &camel_case[..end_position]; + *camel_case = &camel_case[end_position..]; + Some(result) +} diff --git a/components/style_traits/values.rs b/components/style_traits/values.rs index aaff1a998ea..7c73f7bd4cf 100644 --- a/components/style_traits/values.rs +++ b/components/style_traits/values.rs @@ -8,8 +8,15 @@ use app_units::Au; use cssparser::UnicodeRange; use std::fmt; -/// The real `ToCss` trait can't be implemented for types in crates that don't -/// depend on each other. +/// Serialises a value according to its CSS representation. +/// +/// This trait is derivable with `#[derive(ToCss)]`, with the following behaviour: +/// * unit variants get serialised as the `snake-case` representation +/// of their name; +/// * unit variants whose name starts with "Moz" or "Webkit" are prepended +/// with a "-"; +/// * variants with fields get serialised as the space-separated serialisations +/// of their fields. pub trait ToCss { /// Serialize `self` in CSS syntax, writing to `dest`. fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write; |