diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2017-06-02 01:53:55 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-06-02 01:53:55 -0700 |
commit | 028908ee269a680464d079ba4f6e9e8ef5b41749 (patch) | |
tree | 598bdf69738d2b6b74ba6a63800656cb32f183c5 | |
parent | cf71a0cd96e9add582ee597eea7ef99e9fd79ad7 (diff) | |
parent | e58f5419510f01ba9f291eb95eb2ac4b4cc4e6a4 (diff) | |
download | servo-028908ee269a680464d079ba4f6e9e8ef5b41749.tar.gz servo-028908ee269a680464d079ba4f6e9e8ef5b41749.zip |
Auto merge of #17122 - servo:derive-all-the-things, r=emilio
Continue to slim down the code for CSS properties
<!-- 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/17122)
<!-- Reviewable:end -->
26 files changed, 546 insertions, 594 deletions
diff --git a/components/layout/text.rs b/components/layout/text.rs index 8b0d3c707ea..10093f251b8 100644 --- a/components/layout/text.rs +++ b/components/layout/text.rs @@ -23,11 +23,12 @@ use std::borrow::ToOwned; use std::collections::LinkedList; use std::mem; use std::sync::Arc; -use style::computed_values::{line_height, text_rendering, text_transform}; +use style::computed_values::{text_rendering, text_transform}; use style::computed_values::{word_break, white_space}; use style::logical_geometry::{LogicalSize, WritingMode}; use style::properties::ServoComputedValues; use style::properties::style_structs; +use style::values::generics::text::LineHeight; use unicode_bidi as bidi; use unicode_script::{Script, get_script}; @@ -165,8 +166,8 @@ impl TextRunScanner { white_space::T::pre_line => CompressionMode::CompressWhitespace, }; text_transform = inherited_text_style.text_transform; - letter_spacing = inherited_text_style.letter_spacing.0; - word_spacing = inherited_text_style.word_spacing.0 + letter_spacing = inherited_text_style.letter_spacing; + word_spacing = inherited_text_style.word_spacing.value() .map(|lop| lop.to_hash_key()) .unwrap_or((Au(0), NotNaN::new(0.0).unwrap())); text_rendering = inherited_text_style.text_rendering; @@ -288,8 +289,8 @@ impl TextRunScanner { // example, `finally` with a wide `letter-spacing` renders as `f i n a l l y` and not // `fi n a l l y`. let mut flags = ShapingFlags::empty(); - match letter_spacing { - Some(Au(0)) | None => {} + match letter_spacing.value() { + Some(&Au(0)) | None => {} Some(_) => flags.insert(IGNORE_LIGATURES_SHAPING_FLAG), } if text_rendering == text_rendering::T::optimizespeed { @@ -300,7 +301,7 @@ impl TextRunScanner { flags.insert(KEEP_ALL_FLAG); } let options = ShapingOptions { - letter_spacing: letter_spacing, + letter_spacing: letter_spacing.value().cloned(), word_spacing: word_spacing, script: Script::Common, flags: flags, @@ -447,9 +448,9 @@ pub fn font_metrics_for_style(font_context: &mut FontContext, font_style: ::Styl pub fn line_height_from_style(style: &ServoComputedValues, metrics: &FontMetrics) -> Au { let font_size = style.get_font().font_size; match style.get_inheritedtext().line_height { - line_height::T::Normal => metrics.line_gap, - line_height::T::Number(l) => font_size.scale_by(l), - line_height::T::Length(l) => l + LineHeight::Normal => metrics.line_gap, + LineHeight::Number(l) => font_size.scale_by(l), + LineHeight::Length(l) => l } } diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index d7f3b89ba2f..be708113def 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -646,7 +646,7 @@ impl LayoutElementHelpers for LayoutJS<Element> { }; if let Some(border) = border { - let width_value = specified::BorderWidth::from_length(specified::Length::from_px(border as f32)); + let width_value = specified::BorderSideWidth::Length(specified::Length::from_px(border as f32)); hints.push(from_declaration( shared_lock, PropertyDeclaration::BorderTopWidth(width_value.clone()))); diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 7d9db1fd399..c041e23c049 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -998,17 +998,17 @@ fn static_assert() { } pub fn set_border_image_width(&mut self, v: longhands::border_image_width::computed_value::T) { - use values::generics::border::BorderImageWidthSide; + use values::generics::border::BorderImageSideWidth; % for side in SIDES: match v.${side.index} { - BorderImageWidthSide::Auto => { + BorderImageSideWidth::Auto => { self.gecko.mBorderImageWidth.data_at_mut(${side.index}).set_value(CoordDataValue::Auto) }, - BorderImageWidthSide::Length(l) => { + BorderImageSideWidth::Length(l) => { l.to_gecko_style_coord(&mut self.gecko.mBorderImageWidth.data_at_mut(${side.index})) }, - BorderImageWidthSide::Number(n) => { + BorderImageSideWidth::Number(n) => { self.gecko.mBorderImageWidth.data_at_mut(${side.index}).set_value(CoordDataValue::Factor(n)) }, } @@ -3637,65 +3637,64 @@ fn static_assert() { } pub fn set_line_height(&mut self, v: longhands::line_height::computed_value::T) { - use properties::longhands::line_height::computed_value::T; + use values::generics::text::LineHeight; // FIXME: Align binary representations and ditch |match| for cast + static_asserts let en = match v { - T::Normal => CoordDataValue::Normal, - T::Length(val) => CoordDataValue::Coord(val.0), - T::Number(val) => CoordDataValue::Factor(val), - T::MozBlockHeight => + LineHeight::Normal => CoordDataValue::Normal, + LineHeight::Length(val) => CoordDataValue::Coord(val.0), + LineHeight::Number(val) => CoordDataValue::Factor(val), + LineHeight::MozBlockHeight => CoordDataValue::Enumerated(structs::NS_STYLE_LINE_HEIGHT_BLOCK_HEIGHT), }; self.gecko.mLineHeight.set_value(en); } pub fn clone_line_height(&self) -> longhands::line_height::computed_value::T { - use properties::longhands::line_height::computed_value::T; + use values::generics::text::LineHeight; return match self.gecko.mLineHeight.as_value() { - CoordDataValue::Normal => T::Normal, - CoordDataValue::Coord(coord) => T::Length(Au(coord)), - CoordDataValue::Factor(n) => T::Number(n), + CoordDataValue::Normal => LineHeight::Normal, + CoordDataValue::Coord(coord) => LineHeight::Length(Au(coord)), + CoordDataValue::Factor(n) => LineHeight::Number(n), CoordDataValue::Enumerated(val) if val == structs::NS_STYLE_LINE_HEIGHT_BLOCK_HEIGHT => - T::MozBlockHeight, - _ => { - debug_assert!(false); - T::MozBlockHeight - } + LineHeight::MozBlockHeight, + _ => panic!("this should not happen"), } } <%call expr="impl_coord_copy('line_height', 'mLineHeight')"></%call> pub fn set_letter_spacing(&mut self, v: longhands::letter_spacing::computed_value::T) { - match v.0 { - Some(au) => self.gecko.mLetterSpacing.set(au), - None => self.gecko.mLetterSpacing.set_value(CoordDataValue::Normal) + use values::generics::text::Spacing; + match v { + Spacing::Value(value) => self.gecko.mLetterSpacing.set(value), + Spacing::Normal => self.gecko.mLetterSpacing.set_value(CoordDataValue::Normal) } } pub fn clone_letter_spacing(&self) -> longhands::letter_spacing::computed_value::T { - use properties::longhands::letter_spacing::computed_value::T; + use values::generics::text::Spacing; debug_assert!( matches!(self.gecko.mLetterSpacing.as_value(), CoordDataValue::Normal | CoordDataValue::Coord(_)), "Unexpected computed value for letter-spacing"); - T(Au::from_gecko_style_coord(&self.gecko.mLetterSpacing)) + Au::from_gecko_style_coord(&self.gecko.mLetterSpacing).map_or(Spacing::Normal, Spacing::Value) } <%call expr="impl_coord_copy('letter_spacing', 'mLetterSpacing')"></%call> pub fn set_word_spacing(&mut self, v: longhands::word_spacing::computed_value::T) { - match v.0 { - Some(lop) => self.gecko.mWordSpacing.set(lop), + use values::generics::text::Spacing; + match v { + Spacing::Value(lop) => self.gecko.mWordSpacing.set(lop), // https://drafts.csswg.org/css-text-3/#valdef-word-spacing-normal - None => self.gecko.mWordSpacing.set_value(CoordDataValue::Coord(0)), + Spacing::Normal => self.gecko.mWordSpacing.set_value(CoordDataValue::Coord(0)), } } pub fn clone_word_spacing(&self) -> longhands::word_spacing::computed_value::T { - use properties::longhands::word_spacing::computed_value::T; use values::computed::LengthOrPercentage; + use values::generics::text::Spacing; debug_assert!( matches!(self.gecko.mWordSpacing.as_value(), CoordDataValue::Normal | @@ -3703,7 +3702,7 @@ fn static_assert() { CoordDataValue::Percent(_) | CoordDataValue::Calc(_)), "Unexpected computed value for word-spacing"); - T(LengthOrPercentage::from_gecko_style_coord(&self.gecko.mWordSpacing)) + LengthOrPercentage::from_gecko_style_coord(&self.gecko.mWordSpacing).map_or(Spacing::Normal, Spacing::Value) } <%call expr="impl_coord_copy('word_spacing', 'mWordSpacing')"></%call> diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index 267c33acf0a..b61e5554864 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -18,7 +18,6 @@ use properties::longhands; use properties::longhands::background_size::computed_value::T as BackgroundSizeList; use properties::longhands::font_weight::computed_value::T as FontWeight; use properties::longhands::font_stretch::computed_value::T as FontStretch; -use properties::longhands::line_height::computed_value::T as LineHeight; use properties::longhands::text_shadow::computed_value::T as TextShadowList; use properties::longhands::text_shadow::computed_value::TextShadow; use properties::longhands::box_shadow::computed_value::T as BoxShadowList; @@ -1300,43 +1299,6 @@ impl Animatable for MaxLength { } } -/// https://drafts.csswg.org/css-transitions/#animtype-number -/// https://drafts.csswg.org/css-transitions/#animtype-length -impl Animatable for LineHeight { - #[inline] - fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> { - match (*self, *other) { - (LineHeight::Length(ref this), - LineHeight::Length(ref other)) => { - this.add_weighted(other, self_portion, other_portion).map(LineHeight::Length) - } - (LineHeight::Number(ref this), - LineHeight::Number(ref other)) => { - this.add_weighted(other, self_portion, other_portion).map(LineHeight::Number) - } - (LineHeight::Normal, LineHeight::Normal) => { - Ok(LineHeight::Normal) - } - _ => Err(()), - } - } - - #[inline] - fn compute_distance(&self, other: &Self) -> Result<f64, ()> { - match (*self, *other) { - (LineHeight::Length(ref this), - LineHeight::Length(ref other)) => { - this.compute_distance(other) - }, - (LineHeight::Number(ref this), - LineHeight::Number(ref other)) => { - this.compute_distance(other) - }, - _ => Err(()), - } - } -} - /// http://dev.w3.org/csswg/css-transitions/#animtype-font-weight impl Animatable for FontWeight { #[inline] diff --git a/components/style/properties/longhand/border.mako.rs b/components/style/properties/longhand/border.mako.rs index dccbb1edfa2..f2eae0dfe42 100644 --- a/components/style/properties/longhand/border.mako.rs +++ b/components/style/properties/longhand/border.mako.rs @@ -32,7 +32,9 @@ spec=maybe_logical_spec(side, "style"), animation_value_type="none", logical=side[1])} - ${helpers.predefined_type("border-%s-width" % side[0], "BorderWidth", "Au::from_px(3)", + ${helpers.predefined_type("border-%s-width" % side[0], + "BorderSideWidth", + "Au::from_px(3)", computed_type="::app_units::Au", alias=maybe_moz_logical_alias(product, side, "-moz-border-%s-width"), spec=maybe_logical_spec(side, "width"), @@ -287,8 +289,8 @@ ${helpers.predefined_type("border-image-outset", "LengthOrNumberRect", </%helpers:longhand> ${helpers.predefined_type("border-image-width", "BorderImageWidth", - initial_value="computed::BorderImageWidthSide::one().into()", - initial_specified_value="specified::BorderImageWidthSide::one().into()", + initial_value="computed::BorderImageSideWidth::one().into()", + initial_specified_value="specified::BorderImageSideWidth::one().into()", spec="https://drafts.csswg.org/css-backgrounds/#border-image-width", animation_value_type="none", boxed=True)} diff --git a/components/style/properties/longhand/column.mako.rs b/components/style/properties/longhand/column.mako.rs index dee3bbef627..2c99a7f1dc3 100644 --- a/components/style/properties/longhand/column.mako.rs +++ b/components/style/properties/longhand/column.mako.rs @@ -40,11 +40,15 @@ ${helpers.single_keyword("column-fill", "balance auto", extra_prefixes="moz", products="gecko", animation_value_type="discrete", spec="https://drafts.csswg.org/css-multicol/#propdef-column-fill")} -${helpers.predefined_type("column-rule-width", "BorderWidth", "Au::from_px(3)", - initial_specified_value="specified::BorderWidth::Medium", - products="gecko", computed_type="::app_units::Au", +${helpers.predefined_type("column-rule-width", + "BorderSideWidth", + "Au::from_px(3)", + initial_specified_value="specified::BorderSideWidth::Medium", + computed_type="::app_units::Au", + products="gecko", spec="https://drafts.csswg.org/css-multicol/#propdef-column-rule-width", - animation_value_type="ComputedValue", extra_prefixes="moz")} + animation_value_type="ComputedValue", + extra_prefixes="moz")} // https://drafts.csswg.org/css-multicol-1/#crc ${helpers.predefined_type("column-rule-color", "CSSColor", diff --git a/components/style/properties/longhand/inherited_text.mako.rs b/components/style/properties/longhand/inherited_text.mako.rs index 7b58342a397..8b1dafb5cd4 100644 --- a/components/style/properties/longhand/inherited_text.mako.rs +++ b/components/style/properties/longhand/inherited_text.mako.rs @@ -6,148 +6,11 @@ <% from data import Keyword %> <% data.new_style_struct("InheritedText", inherited=True, gecko_name="Text") %> -<%helpers:longhand name="line-height" animation_value_type="ComputedValue" - spec="https://drafts.csswg.org/css2/visudet.html#propdef-line-height"> - use std::fmt; - use style_traits::ToCss; - - #[derive(Clone, Debug, HasViewportPercentage, PartialEq)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub enum SpecifiedValue { - Normal, - % if product == "gecko": - MozBlockHeight, - % endif - Number(specified::Number), - LengthOrPercentage(specified::LengthOrPercentage), - } - - impl ToCss for SpecifiedValue { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - SpecifiedValue::Normal => dest.write_str("normal"), - % if product == "gecko": - SpecifiedValue::MozBlockHeight => dest.write_str("-moz-block-height"), - % endif - SpecifiedValue::LengthOrPercentage(ref value) => value.to_css(dest), - SpecifiedValue::Number(number) => number.to_css(dest), - } - } - } - /// normal | <number> | <length> | <percentage> - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { - use cssparser::Token; - use std::ascii::AsciiExt; - - // We try to parse as a Number first because, for 'line-height', we want - // "0" to be parsed as a plain Number rather than a Length (0px); this - // matches the behaviour of all major browsers - if let Ok(number) = input.try(|i| specified::Number::parse_non_negative(context, i)) { - return Ok(SpecifiedValue::Number(number)) - } - - if let Ok(lop) = input.try(|i| specified::LengthOrPercentage::parse_non_negative(context, i)) { - return Ok(SpecifiedValue::LengthOrPercentage(lop)) - } - - - match try!(input.next()) { - Token::Ident(ref value) if value.eq_ignore_ascii_case("normal") => { - Ok(SpecifiedValue::Normal) - } - % if product == "gecko": - Token::Ident(ref value) if value.eq_ignore_ascii_case("-moz-block-height") => { - Ok(SpecifiedValue::MozBlockHeight) - } - % endif - _ => Err(()), - } - } - pub mod computed_value { - use app_units::Au; - use values::CSSFloat; - #[derive(PartialEq, Copy, Clone, Debug)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub enum T { - Normal, - % if product == "gecko": - MozBlockHeight, - % endif - Length(Au), - Number(CSSFloat), - } - } - impl ToCss for computed_value::T { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - computed_value::T::Normal => dest.write_str("normal"), - % if product == "gecko": - computed_value::T::MozBlockHeight => dest.write_str("-moz-block-height"), - % endif - computed_value::T::Length(length) => length.to_css(dest), - computed_value::T::Number(number) => write!(dest, "{}", number), - } - } - } - #[inline] - pub fn get_initial_value() -> computed_value::T { computed_value::T::Normal } - - #[inline] - pub fn get_initial_specified_value() -> SpecifiedValue { - SpecifiedValue::Normal - } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - #[inline] - fn to_computed_value(&self, context: &Context) -> computed_value::T { - match *self { - SpecifiedValue::Normal => computed_value::T::Normal, - % if product == "gecko": - SpecifiedValue::MozBlockHeight => computed_value::T::MozBlockHeight, - % endif - SpecifiedValue::Number(value) => computed_value::T::Number(value.to_computed_value(context)), - SpecifiedValue::LengthOrPercentage(ref value) => { - match *value { - specified::LengthOrPercentage::Length(ref value) => - computed_value::T::Length(value.to_computed_value(context)), - specified::LengthOrPercentage::Percentage(specified::Percentage(value)) => { - let fr = specified::Length::NoCalc(specified::NoCalcLength::FontRelative( - specified::FontRelativeLength::Em(value))); - computed_value::T::Length(fr.to_computed_value(context)) - }, - specified::LengthOrPercentage::Calc(ref calc) => { - let calc = calc.to_computed_value(context); - let fr = specified::FontRelativeLength::Em(calc.percentage()); - let fr = specified::Length::NoCalc(specified::NoCalcLength::FontRelative(fr)); - let length = calc.unclamped_length(); - computed_value::T::Length(calc.clamping_mode.clamp(length + fr.to_computed_value(context))) - } - } - } - } - } - - #[inline] - fn from_computed_value(computed: &computed_value::T) -> Self { - match *computed { - computed_value::T::Normal => SpecifiedValue::Normal, - % if product == "gecko": - computed_value::T::MozBlockHeight => SpecifiedValue::MozBlockHeight, - % endif - computed_value::T::Number(ref value) => { - SpecifiedValue::Number(specified::Number::from_computed_value(value)) - }, - computed_value::T::Length(au) => { - SpecifiedValue::LengthOrPercentage(specified::LengthOrPercentage::Length( - ToComputedValue::from_computed_value(&au) - )) - } - } - } - } -</%helpers:longhand> +${helpers.predefined_type("line-height", + "LineHeight", + "computed::LineHeight::normal()", + animation_value_type="ComputedValue", + spec="https://drafts.csswg.org/css2/visudet.html#propdef-line-height")} // CSS Text Module Level 3 @@ -395,157 +258,17 @@ ${helpers.single_keyword("text-align-last", % endif </%helpers:longhand> -<%helpers:longhand name="letter-spacing" animation_value_type="ComputedValue" - spec="https://drafts.csswg.org/css-text/#propdef-letter-spacing"> - use std::fmt; - use style_traits::ToCss; - use values::specified::AllowQuirks; - - #[derive(Clone, Debug, HasViewportPercentage, PartialEq)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub enum SpecifiedValue { - Normal, - Specified(specified::Length), - } - - impl ToCss for SpecifiedValue { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - SpecifiedValue::Normal => dest.write_str("normal"), - SpecifiedValue::Specified(ref l) => l.to_css(dest), - } - } - } - - pub mod computed_value { - use app_units::Au; - use properties::animated_properties::Animatable; - - #[derive(Debug, Clone, PartialEq)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct T(pub Option<Au>); - - ${helpers.impl_animatable_for_option_tuple('Au(0)')} - } - - impl ToCss for computed_value::T { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match self.0 { - None => dest.write_str("normal"), - Some(l) => l.to_css(dest), - } - } - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T(None) - } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - #[inline] - fn to_computed_value(&self, context: &Context) -> computed_value::T { - match *self { - SpecifiedValue::Normal => computed_value::T(None), - SpecifiedValue::Specified(ref l) => - computed_value::T(Some(l.to_computed_value(context))) - } - } - - #[inline] - fn from_computed_value(computed: &computed_value::T) -> Self { - computed.0.map(|ref au| { - SpecifiedValue::Specified(ToComputedValue::from_computed_value(au)) - }).unwrap_or(SpecifiedValue::Normal) - } - } - - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { - if input.try(|input| input.expect_ident_matching("normal")).is_ok() { - Ok(SpecifiedValue::Normal) - } else { - specified::Length::parse_quirky(context, input, AllowQuirks::Yes).map(SpecifiedValue::Specified) - } - } -</%helpers:longhand> - -<%helpers:longhand name="word-spacing" animation_value_type="ComputedValue" - spec="https://drafts.csswg.org/css-text/#propdef-word-spacing"> - use std::fmt; - use style_traits::ToCss; - use values::specified::AllowQuirks; - - #[derive(Clone, Debug, HasViewportPercentage, PartialEq)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub enum SpecifiedValue { - Normal, - Specified(specified::LengthOrPercentage), - } - - impl ToCss for SpecifiedValue { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - SpecifiedValue::Normal => dest.write_str("normal"), - SpecifiedValue::Specified(ref l) => l.to_css(dest), - } - } - } - - pub mod computed_value { - use properties::animated_properties::Animatable; - use values::computed::LengthOrPercentage; - #[derive(Debug, Clone, PartialEq)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct T(pub Option<LengthOrPercentage>); - - ${helpers.impl_animatable_for_option_tuple('LengthOrPercentage::zero()')} - } - - impl ToCss for computed_value::T { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match self.0 { - None => dest.write_str("normal"), - Some(l) => l.to_css(dest), - } - } - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T(None) - } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - #[inline] - fn to_computed_value(&self, context: &Context) -> computed_value::T { - match *self { - SpecifiedValue::Normal => computed_value::T(None), - SpecifiedValue::Specified(ref l) => - computed_value::T(Some(l.to_computed_value(context))), - } - } - - #[inline] - fn from_computed_value(computed: &computed_value::T) -> Self { - computed.0.map(|ref lop| { - SpecifiedValue::Specified(ToComputedValue::from_computed_value(lop)) - }).unwrap_or(SpecifiedValue::Normal) - } - } +${helpers.predefined_type("letter-spacing", + "LetterSpacing", + "computed::LetterSpacing::normal()", + animation_value_type="ComputedValue", + spec="https://drafts.csswg.org/css-text/#propdef-letter-spacing")} - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { - if input.try(|input| input.expect_ident_matching("normal")).is_ok() { - Ok(SpecifiedValue::Normal) - } else { - specified::LengthOrPercentage::parse_quirky(context, input, AllowQuirks::Yes) - .map(SpecifiedValue::Specified) - } - } -</%helpers:longhand> +${helpers.predefined_type("word-spacing", + "WordSpacing", + "computed::WordSpacing::normal()", + animation_value_type="ComputedValue", + spec="https://drafts.csswg.org/css-text/#propdef-word-spacing")} <%helpers:longhand name="-servo-text-decorations-in-effect" derived_from="display text-decoration" @@ -1149,13 +872,15 @@ ${helpers.predefined_type( ignored_when_colors_disabled=True, spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke-color")} -${helpers.predefined_type("-webkit-text-stroke-width", "BorderWidth", "Au::from_px(0)", - initial_specified_value="specified::BorderWidth::from_length(specified::Length::zero())", - computed_type="::app_units::Au", products="gecko", +${helpers.predefined_type("-webkit-text-stroke-width", + "BorderSideWidth", + "Au::from_px(0)", + initial_specified_value="specified::BorderSideWidth::Length(specified::Length::zero())", + computed_type="::app_units::Au", + products="gecko", spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke-width", animation_value_type="none")} - // CSS Ruby Layout Module Level 1 // https://drafts.csswg.org/css-ruby/ ${helpers.single_keyword("ruby-align", "space-around start center space-between", diff --git a/components/style/properties/longhand/outline.mako.rs b/components/style/properties/longhand/outline.mako.rs index 0cccccaf310..1640953e305 100644 --- a/components/style/properties/longhand/outline.mako.rs +++ b/components/style/properties/longhand/outline.mako.rs @@ -61,50 +61,13 @@ ${helpers.predefined_type("outline-color", "CSSColor", "computed::CSSColor::Curr } </%helpers:longhand> -<%helpers:longhand name="outline-width" animation_value_type="ComputedValue" - spec="https://drafts.csswg.org/css-ui/#propdef-outline-width"> - use std::fmt; - use style_traits::ToCss; - - impl ToCss for SpecifiedValue { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - self.0.to_css(dest) - } - } - - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { - specified::parse_border_width(context, input).map(SpecifiedValue) - } - - #[derive(Clone, Debug, HasViewportPercentage, PartialEq)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct SpecifiedValue(pub specified::Length); - - pub mod computed_value { - use app_units::Au; - pub type T = Au; - } - - pub use super::border_top_width::get_initial_value; - #[inline] - pub fn get_initial_specified_value() -> SpecifiedValue { - SpecifiedValue(specified::Length::NoCalc(specified::NoCalcLength::medium())) - } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - #[inline] - fn to_computed_value(&self, context: &Context) -> computed_value::T { - self.0.to_computed_value(context) - } - - #[inline] - fn from_computed_value(computed: &computed_value::T) -> Self { - SpecifiedValue(ToComputedValue::from_computed_value(computed)) - } - } -</%helpers:longhand> +${helpers.predefined_type("outline-width", + "BorderSideWidth", + "Au::from_px(3)", + initial_specified_value="specified::BorderSideWidth::Medium", + computed_type="::app_units::Au", + animation_value_type="ComputedValue", + spec="https://drafts.csswg.org/css-ui/#propdef-outline-width")} // The -moz-outline-radius-* properties are non-standard and not on a standards track. // TODO: Should they animate? diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index 526e18a6d6b..4114b2f2b22 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -38,8 +38,9 @@ use shared_lock::StylesheetGuards; use style_traits::{HasViewportPercentage, ToCss}; use stylesheets::{CssRuleType, MallocSizeOf, MallocSizeOfFn, Origin, UrlExtraData}; #[cfg(feature = "servo")] use values::Either; -use values::specified::Color; +use values::generics::text::LineHeight; use values::computed; +use values::specified::Color; use cascade_info::CascadeInfo; use rule_tree::{CascadeLevel, StrongRuleNode}; use style_adjuster::StyleAdjuster; @@ -1262,11 +1263,9 @@ impl PropertyDeclaration { } /// Is it the default value of line-height? - /// - /// (using match because it generates less code than) pub fn is_default_line_height(&self) -> bool { match *self { - PropertyDeclaration::LineHeight(longhands::line_height::SpecifiedValue::Normal) => true, + PropertyDeclaration::LineHeight(LineHeight::Normal) => true, _ => false } } diff --git a/components/style/properties/shorthand/border.mako.rs b/components/style/properties/shorthand/border.mako.rs index e2576891b06..c84549a544f 100644 --- a/components/style/properties/shorthand/border.mako.rs +++ b/components/style/properties/shorthand/border.mako.rs @@ -18,11 +18,11 @@ ${helpers.four_sides_shorthand("border-style", "border-%s-style", for side in PHYSICAL_SIDES)}" spec="https://drafts.csswg.org/css-backgrounds/#border-width"> use values::generics::rect::Rect; - use values::specified::{AllowQuirks, BorderWidth}; + use values::specified::{AllowQuirks, BorderSideWidth}; pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { let rect = Rect::parse_with(context, input, |_, i| { - BorderWidth::parse_quirky(context, i, AllowQuirks::Yes) + BorderSideWidth::parse_quirky(context, i, AllowQuirks::Yes) })?; Ok(expanded! { border_top_width: rect.0, @@ -46,8 +46,8 @@ ${helpers.four_sides_shorthand("border-style", "border-%s-style", pub fn parse_border(context: &ParserContext, input: &mut Parser) -> Result<(specified::CSSColor, specified::BorderStyle, - specified::BorderWidth), ()> { - use values::specified::{CSSColor, BorderStyle, BorderWidth}; + specified::BorderSideWidth), ()> { + use values::specified::{CSSColor, BorderStyle, BorderSideWidth}; let _unused = context; let mut color = None; let mut style = None; @@ -69,7 +69,7 @@ pub fn parse_border(context: &ParserContext, input: &mut Parser) } } if width.is_none() { - if let Ok(value) = input.try(|i| BorderWidth::parse(context, i)) { + if let Ok(value) = input.try(|i| BorderSideWidth::parse(context, i)) { width = Some(value); any = true; continue @@ -80,7 +80,7 @@ pub fn parse_border(context: &ParserContext, input: &mut Parser) if any { Ok((color.unwrap_or_else(|| CSSColor::currentcolor()), style.unwrap_or(BorderStyle::none), - width.unwrap_or(BorderWidth::Medium))) + width.unwrap_or(BorderSideWidth::Medium))) } else { Err(()) } diff --git a/components/style/properties/shorthand/font.mako.rs b/components/style/properties/shorthand/font.mako.rs index 4e3569c7ffa..bcee6228f22 100644 --- a/components/style/properties/shorthand/font.mako.rs +++ b/components/style/properties/shorthand/font.mako.rs @@ -18,10 +18,12 @@ ${'font-language-override' if product == 'gecko' or data.testing else ''} ${'font-feature-settings' if product == 'gecko' or data.testing else ''}" spec="https://drafts.csswg.org/css-fonts-3/#propdef-font"> + use parser::Parse; use properties::longhands::{font_family, font_style, font_weight, font_stretch}; - use properties::longhands::{font_size, line_height, font_variant_caps}; + use properties::longhands::{font_size, font_variant_caps}; #[cfg(feature = "gecko")] use properties::longhands::system_font::SystemFont; + use values::specified::text::LineHeight; <% gecko_sub_properties = "kerning language_override size_adjust \ @@ -50,7 +52,7 @@ ${name}: ${name}::SpecifiedValue::system_font(sys), % endfor // line-height is just reset to initial - line_height: line_height::get_initial_specified_value(), + line_height: LineHeight::normal(), }) } % endif @@ -98,7 +100,7 @@ return Err(()) } let line_height = if input.try(|input| input.expect_delim('/')).is_ok() { - Some(try!(line_height::parse(context, input))) + Some(try!(LineHeight::parse(context, input))) } else { None }; @@ -107,7 +109,7 @@ % for name in "style weight stretch size variant_caps".split(): font_${name}: unwrap_or_initial!(font_${name}, ${name}), % endfor - line_height: unwrap_or_initial!(line_height), + line_height: line_height.unwrap_or(LineHeight::normal()), font_family: family, % if product == "gecko" or data.testing: % for name in gecko_sub_properties: @@ -169,12 +171,9 @@ self.font_size.to_css(dest)?; - match *self.line_height { - line_height::SpecifiedValue::Normal => {}, - _ => { - dest.write_str("/")?; - self.line_height.to_css(dest)?; - } + if *self.line_height != LineHeight::normal() { + dest.write_str("/")?; + self.line_height.to_css(dest)?; } dest.write_str(" ")?; @@ -197,7 +196,7 @@ all = false; } % endfor - if self.line_height != &line_height::get_initial_specified_value() { + if self.line_height != &LineHeight::normal() { all = false } if all { diff --git a/components/style/values/computed/border.rs b/components/style/values/computed/border.rs index 00408b302eb..e4073601c10 100644 --- a/components/style/values/computed/border.rs +++ b/components/style/values/computed/border.rs @@ -7,16 +7,16 @@ use values::computed::{Number, NumberOrPercentage}; use values::computed::length::LengthOrPercentage; use values::generics::border::BorderCornerRadius as GenericBorderCornerRadius; +use values::generics::border::BorderImageSideWidth as GenericBorderImageSideWidth; use values::generics::border::BorderImageSlice as GenericBorderImageSlice; -use values::generics::border::BorderImageWidthSide as GenericBorderImageWidthSide; use values::generics::border::BorderRadius as GenericBorderRadius; use values::generics::rect::Rect; /// A computed value for the `border-image-width` property. -pub type BorderImageWidth = Rect<BorderImageWidthSide>; +pub type BorderImageWidth = Rect<BorderImageSideWidth>; /// A computed value for a single side of a `border-image-width` property. -pub type BorderImageWidthSide = GenericBorderImageWidthSide<LengthOrPercentage, Number>; +pub type BorderImageSideWidth = GenericBorderImageSideWidth<LengthOrPercentage, Number>; /// A computed value for the `border-image-slice` property. pub type BorderImageSlice = GenericBorderImageSlice<NumberOrPercentage>; @@ -27,10 +27,10 @@ pub type BorderRadius = GenericBorderRadius<LengthOrPercentage>; /// A computed value for the `border-*-radius` longhand properties. pub type BorderCornerRadius = GenericBorderCornerRadius<LengthOrPercentage>; -impl BorderImageWidthSide { +impl BorderImageSideWidth { /// Returns `1`. #[inline] pub fn one() -> Self { - GenericBorderImageWidthSide::Number(1.) + GenericBorderImageSideWidth::Number(1.) } } diff --git a/components/style/values/computed/length.rs b/components/style/values/computed/length.rs index 1ed038941a7..e5b35428bef 100644 --- a/components/style/values/computed/length.rs +++ b/components/style/values/computed/length.rs @@ -222,6 +222,13 @@ pub enum LengthOrPercentage { Calc(CalcLengthOrPercentage), } +impl From<Au> for LengthOrPercentage { + #[inline] + fn from(length: Au) -> Self { + LengthOrPercentage::Length(length) + } +} + impl LengthOrPercentage { #[inline] #[allow(missing_docs)] diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 5931d0e2fb5..039c3763567 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -24,7 +24,7 @@ use super::specified; pub use app_units::Au; pub use cssparser::Color as CSSColor; pub use self::background::BackgroundSize; -pub use self::border::{BorderImageSlice, BorderImageWidth, BorderImageWidthSide}; +pub use self::border::{BorderImageSlice, BorderImageWidth, BorderImageSideWidth}; pub use self::border::{BorderRadius, BorderCornerRadius}; pub use self::image::{Gradient, GradientItem, ImageLayer, LineDirection, Image, ImageRect}; pub use self::rect::LengthOrNumberRect; @@ -38,6 +38,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::transform::TransformOrigin; pub mod background; @@ -47,6 +48,7 @@ pub mod image; pub mod length; pub mod position; pub mod rect; +pub mod text; pub mod transform; /// A `Context` is all the data a specified value could ever need to compute diff --git a/components/style/values/computed/text.rs b/components/style/values/computed/text.rs new file mode 100644 index 00000000000..d45242015c4 --- /dev/null +++ b/components/style/values/computed/text.rs @@ -0,0 +1,58 @@ +/* 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/. */ + +//! Computed types for text properties. + +use app_units::Au; +use properties::animated_properties::Animatable; +use values::CSSFloat; +use values::computed::length::{Length, LengthOrPercentage}; +use values::generics::text::{LineHeight as GenericLineHeight, Spacing}; + +/// A computed value for the `letter-spacing` property. +pub type LetterSpacing = Spacing<Length>; + +/// A computed value for the `word-spacing` property. +pub type WordSpacing = Spacing<LengthOrPercentage>; + +/// A computed value for the `line-height` property. +pub type LineHeight = GenericLineHeight<CSSFloat, Au>; + +impl Animatable for LineHeight { + #[inline] + fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> { + match (*self, *other) { + (GenericLineHeight::Length(ref this), GenericLineHeight::Length(ref other)) => { + this.add_weighted(other, self_portion, other_portion).map(GenericLineHeight::Length) + }, + (GenericLineHeight::Number(ref this), GenericLineHeight::Number(ref other)) => { + this.add_weighted(other, self_portion, other_portion).map(GenericLineHeight::Number) + }, + (GenericLineHeight::Normal, GenericLineHeight::Normal) => { + Ok(GenericLineHeight::Normal) + }, + #[cfg(feature = "gecko")] + (GenericLineHeight::MozBlockHeight, GenericLineHeight::MozBlockHeight) => { + Ok(GenericLineHeight::MozBlockHeight) + }, + _ => Err(()), + } + } + + #[inline] + fn compute_distance(&self, other: &Self) -> Result<f64, ()> { + match (*self, *other) { + (GenericLineHeight::Length(ref this), GenericLineHeight::Length(ref other)) => { + this.compute_distance(other) + }, + (GenericLineHeight::Number(ref this), GenericLineHeight::Number(ref other)) => { + this.compute_distance(other) + }, + (GenericLineHeight::Normal, GenericLineHeight::Normal) => Ok(0.), + #[cfg(feature = "gecko")] + (GenericLineHeight::MozBlockHeight, GenericLineHeight::MozBlockHeight) => Ok(0.), + _ => Err(()), + } + } +} diff --git a/components/style/values/generics/border.rs b/components/style/values/generics/border.rs index 6bfc5234b3d..f1384e580e3 100644 --- a/components/style/values/generics/border.rs +++ b/components/style/values/generics/border.rs @@ -12,7 +12,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)] -pub enum BorderImageWidthSide<LengthOrPercentage, Number> { +pub enum BorderImageSideWidth<LengthOrPercentage, Number> { /// `<length-or-percentage>` Length(LengthOrPercentage), /// `<number>` @@ -52,16 +52,16 @@ pub struct BorderRadius<LengthOrPercentage> { /// A generic value for `border-*-radius` longhand properties. pub struct BorderCornerRadius<L>(pub Size2D<L>); -impl<L, N> ToCss for BorderImageWidthSide<L, N> +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 { - BorderImageWidthSide::Length(ref length) => length.to_css(dest), - BorderImageWidthSide::Number(ref number) => number.to_css(dest), - BorderImageWidthSide::Auto => dest.write_str("auto"), + BorderImageSideWidth::Length(ref length) => length.to_css(dest), + BorderImageSideWidth::Number(ref number) => number.to_css(dest), + BorderImageSideWidth::Auto => dest.write_str("auto"), } } } diff --git a/components/style/values/generics/mod.rs b/components/style/values/generics/mod.rs index 441941d4b2e..7cbadffe10a 100644 --- a/components/style/values/generics/mod.rs +++ b/components/style/values/generics/mod.rs @@ -19,6 +19,7 @@ pub mod grid; pub mod image; pub mod position; pub mod rect; +pub mod text; pub mod transform; // https://drafts.csswg.org/css-counter-styles/#typedef-symbols-type diff --git a/components/style/values/generics/text.rs b/components/style/values/generics/text.rs new file mode 100644 index 00000000000..2ba5ae4af98 --- /dev/null +++ b/components/style/values/generics/text.rs @@ -0,0 +1,129 @@ +/* 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/. */ + +//! Generic types for text properties. + +use app_units::Au; +use cssparser::Parser; +use parser::ParserContext; +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 +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)] +pub enum Spacing<Value> { + /// `normal` + Normal, + /// `<value>` + Value(Value), +} + +impl<Value> Spacing<Value> { + /// Returns `normal`. + #[inline] + pub fn normal() -> Self { + Spacing::Normal + } + + /// Parses. + #[inline] + pub fn parse_with<F>( + context: &ParserContext, + input: &mut Parser, + parse: F) + -> Result<Self, ()> + where F: FnOnce(&ParserContext, &mut Parser) -> Result<Value, ()> + { + if input.try(|i| i.expect_ident_matching("normal")).is_ok() { + return Ok(Spacing::Normal); + } + parse(context, input).map(Spacing::Value) + } + + /// Returns the spacing value, if not `normal`. + #[inline] + pub fn value(&self) -> Option<&Value> { + match *self { + Spacing::Normal => None, + Spacing::Value(ref value) => Some(value), + } + } +} + +impl<Value> Animatable for Spacing<Value> + where Value: Animatable + From<Au>, +{ + #[inline] + fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> { + if let (&Spacing::Normal, &Spacing::Normal) = (self, other) { + return Ok(Spacing::Normal); + } + let zero = Value::from(Au(0)); + let this = self.value().unwrap_or(&zero); + let other = other.value().unwrap_or(&zero); + this.add_weighted(other, self_portion, other_portion).map(Spacing::Value) + } + + #[inline] + fn compute_distance(&self, other: &Self) -> Result<f64, ()> { + let zero = Value::from(Au(0)); + let this = self.value().unwrap_or(&zero); + let other = other.value().unwrap_or(&zero); + this.compute_distance(other) + } +} + +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)] +pub enum LineHeight<Number, LengthOrPercentage> { + /// `normal` + Normal, + /// `-moz-block-height` + #[cfg(feature = "gecko")] + MozBlockHeight, + /// `<number>` + Number(Number), + /// `<length-or-percentage>` + Length(LengthOrPercentage), +} + +impl<N, L> LineHeight<N, L> { + /// Returns `normal`. + #[inline] + pub fn normal() -> Self { + 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 26b7974732f..b931ef36245 100644 --- a/components/style/values/specified/border.rs +++ b/components/style/values/specified/border.rs @@ -4,21 +4,39 @@ //! Specified types for CSS values related to borders. +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; use values::generics::border::BorderImageSlice as GenericBorderImageSlice; -use values::generics::border::BorderImageWidthSide as GenericBorderImageWidthSide; use values::generics::border::BorderRadius as GenericBorderRadius; use values::generics::rect::Rect; -use values::specified::{Number, NumberOrPercentage}; -use values::specified::length::LengthOrPercentage; +use values::specified::{AllowQuirks, Number, NumberOrPercentage}; +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)] +pub enum BorderSideWidth { + /// `thin` + Thin, + /// `medium` + Medium, + /// `thick` + Thick, + /// `<length>` + Length(Length), +} /// A specified value for the `border-image-width` property. -pub type BorderImageWidth = Rect<BorderImageWidthSide>; +pub type BorderImageWidth = Rect<BorderImageSideWidth>; /// A specified value for a single side of a `border-image-width` property. -pub type BorderImageWidthSide = GenericBorderImageWidthSide<LengthOrPercentage, Number>; +pub type BorderImageSideWidth = GenericBorderImageSideWidth<LengthOrPercentage, Number>; /// A specified value for the `border-image-slice` property. pub type BorderImageSlice = GenericBorderImageSlice<NumberOrPercentage>; @@ -29,26 +47,85 @@ pub type BorderRadius = GenericBorderRadius<LengthOrPercentage>; /// A specified value for the `border-*-radius` longhand properties. pub type BorderCornerRadius = GenericBorderCornerRadius<LengthOrPercentage>; -impl BorderImageWidthSide { +impl BorderSideWidth { + /// Parses, with quirks. + pub fn parse_quirky( + context: &ParserContext, + input: &mut Parser, + allow_quirks: AllowQuirks) + -> Result<Self, ()> + { + if let Ok(length) = input.try(|i| Length::parse_non_negative_quirky(context, i, allow_quirks)) { + return Ok(BorderSideWidth::Length(length)); + } + match_ignore_ascii_case! { &input.expect_ident()?, + "thin" => Ok(BorderSideWidth::Thin), + "medium" => Ok(BorderSideWidth::Medium), + "thick" => Ok(BorderSideWidth::Thick), + _ => Err(()) + } + } +} + +impl Parse for BorderSideWidth { + fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { + Self::parse_quirky(context, input, AllowQuirks::No) + } +} + +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; + + #[inline] + fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { + // We choose the pixel length of the keyword values the same as both spec and gecko. + // Spec: https://drafts.csswg.org/css-backgrounds-3/#line-width + // Gecko: https://bugzilla.mozilla.org/show_bug.cgi?id=1312155#c0 + match *self { + BorderSideWidth::Thin => Length::from_px(1.).to_computed_value(context), + BorderSideWidth::Medium => Length::from_px(3.).to_computed_value(context), + BorderSideWidth::Thick => Length::from_px(5.).to_computed_value(context), + BorderSideWidth::Length(ref length) => length.to_computed_value(context) + } + } + + #[inline] + fn from_computed_value(computed: &Self::ComputedValue) -> Self { + BorderSideWidth::Length(ToComputedValue::from_computed_value(computed)) + } +} + +impl BorderImageSideWidth { /// Returns `1`. #[inline] pub fn one() -> Self { - GenericBorderImageWidthSide::Number(Number::new(1.)) + GenericBorderImageSideWidth::Number(Number::new(1.)) } } -impl Parse for BorderImageWidthSide { +impl Parse for BorderImageSideWidth { fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { if input.try(|i| i.expect_ident_matching("auto")).is_ok() { - return Ok(GenericBorderImageWidthSide::Auto); + return Ok(GenericBorderImageSideWidth::Auto); } if let Ok(len) = input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) { - return Ok(GenericBorderImageWidthSide::Length(len)); + return Ok(GenericBorderImageSideWidth::Length(len)); } let num = Number::parse_non_negative(context, input)?; - Ok(GenericBorderImageWidthSide::Number(num)) + Ok(GenericBorderImageSideWidth::Number(num)) } } diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index 7eb637315d3..cc8855b15de 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -7,7 +7,6 @@ //! TODO(emilio): Enhance docs. use Namespace; -use app_units::Au; use context::QuirksMode; use cssparser::{self, Parser, Token, serialize_identifier}; use itoa; @@ -32,7 +31,7 @@ use values::specified::calc::CalcNode; pub use self::align::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems}; pub use self::background::BackgroundSize; pub use self::border::{BorderCornerRadius, BorderImageSlice, BorderImageWidth}; -pub use self::border::{BorderImageWidthSide, BorderRadius}; +pub use self::border::{BorderImageSideWidth, BorderRadius, BorderSideWidth}; pub use self::color::Color; pub use self::rect::LengthOrNumberRect; pub use super::generics::grid::GridLine; @@ -44,6 +43,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::transform::TransformOrigin; #[cfg(feature = "gecko")] @@ -58,6 +58,7 @@ pub mod image; pub mod length; pub mod position; pub mod rect; +pub mod text; pub mod transform; /// Common handling for the specified value CSS url() values. @@ -432,92 +433,6 @@ impl Angle { } } -#[allow(missing_docs)] -pub fn parse_border_width(context: &ParserContext, input: &mut Parser) -> Result<Length, ()> { - input.try(|i| Length::parse_non_negative(context, i)).or_else(|()| { - match_ignore_ascii_case! { &try!(input.expect_ident()), - "thin" => Ok(Length::from_px(1.)), - "medium" => Ok(Length::from_px(3.)), - "thick" => Ok(Length::from_px(5.)), - _ => Err(()) - } - }) -} - -#[derive(Clone, Debug, HasViewportPercentage, PartialEq)] -#[cfg_attr(feature = "servo", derive(HeapSizeOf))] -#[allow(missing_docs)] -pub enum BorderWidth { - Thin, - Medium, - Thick, - Width(Length), -} - -impl Parse for BorderWidth { - fn parse(context: &ParserContext, input: &mut Parser) -> Result<BorderWidth, ()> { - Self::parse_quirky(context, input, AllowQuirks::No) - } -} - -impl BorderWidth { - /// Parses a border width, allowing quirks. - pub fn parse_quirky(context: &ParserContext, - input: &mut Parser, - allow_quirks: AllowQuirks) - -> Result<BorderWidth, ()> { - match input.try(|i| Length::parse_non_negative_quirky(context, i, allow_quirks)) { - Ok(length) => Ok(BorderWidth::Width(length)), - Err(_) => match_ignore_ascii_case! { &try!(input.expect_ident()), - "thin" => Ok(BorderWidth::Thin), - "medium" => Ok(BorderWidth::Medium), - "thick" => Ok(BorderWidth::Thick), - _ => Err(()) - } - } - } -} - -impl BorderWidth { - #[allow(missing_docs)] - pub fn from_length(length: Length) -> Self { - BorderWidth::Width(length) - } -} - -impl ToCss for BorderWidth { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - BorderWidth::Thin => dest.write_str("thin"), - BorderWidth::Medium => dest.write_str("medium"), - BorderWidth::Thick => dest.write_str("thick"), - BorderWidth::Width(ref length) => length.to_css(dest) - } - } -} - -impl ToComputedValue for BorderWidth { - type ComputedValue = Au; - - #[inline] - fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { - // We choose the pixel length of the keyword values the same as both spec and gecko. - // Spec: https://drafts.csswg.org/css-backgrounds-3/#line-width - // Gecko: https://bugzilla.mozilla.org/show_bug.cgi?id=1312155#c0 - match *self { - BorderWidth::Thin => Length::from_px(1.).to_computed_value(context), - BorderWidth::Medium => Length::from_px(3.).to_computed_value(context), - BorderWidth::Thick => Length::from_px(5.).to_computed_value(context), - BorderWidth::Width(ref length) => length.to_computed_value(context) - } - } - - #[inline] - fn from_computed_value(computed: &Self::ComputedValue) -> Self { - BorderWidth::Width(ToComputedValue::from_computed_value(computed)) - } -} - // The integer values here correspond to the border conflict resolution rules in CSS 2.1 § // 17.6.2.1. Higher values override lower values. define_numbered_css_keyword_enum! { BorderStyle: diff --git a/components/style/values/specified/text.rs b/components/style/values/specified/text.rs new file mode 100644 index 00000000000..cc517ad4abb --- /dev/null +++ b/components/style/values/specified/text.rs @@ -0,0 +1,119 @@ +/* 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/. */ + +//! Specified types for text properties. + +use cssparser::Parser; +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::specified::length::{FontRelativeLength, Length, LengthOrPercentage, NoCalcLength}; + +/// A specified value for the `letter-spacing` property. +pub type LetterSpacing = Spacing<Length>; + +/// A specified value for the `word-spacing` property. +pub type WordSpacing = Spacing<LengthOrPercentage>; + +/// A specified value for the `line-height` property. +pub type LineHeight = GenericLineHeight<Number, LengthOrPercentage>; + +impl Parse for LetterSpacing { + fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { + Spacing::parse_with(context, input, |c, i| { + Length::parse_quirky(c, i, AllowQuirks::Yes) + }) + } +} + +impl Parse for WordSpacing { + fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { + Spacing::parse_with(context, input, |c, i| { + LengthOrPercentage::parse_quirky(c, i, AllowQuirks::Yes) + }) + } +} + +impl Parse for LineHeight { + fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { + if let Ok(number) = input.try(|i| Number::parse_non_negative(context, i)) { + return Ok(GenericLineHeight::Number(number)) + } + if let Ok(lop) = input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) { + return Ok(GenericLineHeight::Length(lop)) + } + match &input.expect_ident()? { + ident if ident.eq_ignore_ascii_case("normal") => { + Ok(GenericLineHeight::Normal) + }, + #[cfg(feature = "gecko")] + ident if ident.eq_ignore_ascii_case("-moz-block-height") => { + Ok(GenericLineHeight::MozBlockHeight) + }, + _ => Err(()), + } + } +} + +impl ToComputedValue for LineHeight { + type ComputedValue = ComputedLineHeight; + + #[inline] + fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { + match *self { + GenericLineHeight::Normal => { + GenericLineHeight::Normal + }, + #[cfg(feature = "gecko")] + GenericLineHeight::MozBlockHeight => { + GenericLineHeight::MozBlockHeight + }, + GenericLineHeight::Number(number) => { + GenericLineHeight::Number(number.to_computed_value(context)) + }, + GenericLineHeight::Length(LengthOrPercentage::Length(ref length)) => { + GenericLineHeight::Length(length.to_computed_value(context)) + }, + GenericLineHeight::Length(LengthOrPercentage::Percentage(p)) => { + let font_relative_length = + Length::NoCalc(NoCalcLength::FontRelative(FontRelativeLength::Em(p.0))); + GenericLineHeight::Length(font_relative_length.to_computed_value(context)) + }, + GenericLineHeight::Length(LengthOrPercentage::Calc(ref calc)) => { + let computed_calc = calc.to_computed_value(context); + let font_relative_length = + Length::NoCalc(NoCalcLength::FontRelative(FontRelativeLength::Em(computed_calc.percentage()))); + let absolute_length = computed_calc.unclamped_length(); + let computed_length = computed_calc.clamping_mode.clamp( + absolute_length + font_relative_length.to_computed_value(context) + ); + GenericLineHeight::Length(computed_length) + }, + } + } + + #[inline] + fn from_computed_value(computed: &Self::ComputedValue) -> Self { + match *computed { + GenericLineHeight::Normal => { + GenericLineHeight::Normal + }, + #[cfg(feature = "gecko")] + GenericLineHeight::MozBlockHeight => { + GenericLineHeight::MozBlockHeight + }, + GenericLineHeight::Number(ref number) => { + GenericLineHeight::Number(Number::from_computed_value(number)) + }, + GenericLineHeight::Length(ref length) => { + GenericLineHeight::Length(LengthOrPercentage::Length( + NoCalcLength::from_computed_value(length) + )) + } + } + } +} diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index dbe09dec669..636b6a868a5 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -1946,7 +1946,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetPixelValue(declarations: use style::properties::longhands::border_spacing::SpecifiedValue as BorderSpacing; use style::properties::longhands::height::SpecifiedValue as Height; use style::properties::longhands::width::SpecifiedValue as Width; - use style::values::specified::BorderWidth; + use style::values::specified::BorderSideWidth; use style::values::specified::MozLength; use style::values::specified::length::{NoCalcLength, LengthOrPercentage}; @@ -1956,10 +1956,10 @@ pub extern "C" fn Servo_DeclarationBlock_SetPixelValue(declarations: let prop = match_wrap_declared! { long, Height => Height(MozLength::LengthOrPercentageOrAuto(nocalc.into())), Width => Width(MozLength::LengthOrPercentageOrAuto(nocalc.into())), - BorderTopWidth => BorderWidth::Width(nocalc.into()), - BorderRightWidth => BorderWidth::Width(nocalc.into()), - BorderBottomWidth => BorderWidth::Width(nocalc.into()), - BorderLeftWidth => BorderWidth::Width(nocalc.into()), + BorderTopWidth => BorderSideWidth::Length(nocalc.into()), + BorderRightWidth => BorderSideWidth::Length(nocalc.into()), + BorderBottomWidth => BorderSideWidth::Length(nocalc.into()), + BorderLeftWidth => BorderSideWidth::Length(nocalc.into()), MarginTop => nocalc.into(), MarginRight => nocalc.into(), MarginBottom => nocalc.into(), diff --git a/tests/unit/style/parsing/inherited_text.rs b/tests/unit/style/parsing/inherited_text.rs index af0ec0ee5d1..5c578def660 100644 --- a/tests/unit/style/parsing/inherited_text.rs +++ b/tests/unit/style/parsing/inherited_text.rs @@ -3,27 +3,27 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use parsing::parse; +use style::values::generics::text::Spacing; #[test] fn negative_letter_spacing_should_parse_properly() { use style::properties::longhands::letter_spacing; - use style::properties::longhands::letter_spacing::SpecifiedValue; use style::values::specified::length::{Length, NoCalcLength, FontRelativeLength}; let negative_value = parse_longhand!(letter_spacing, "-0.5em"); - let expected = SpecifiedValue::Specified(Length::NoCalc(NoCalcLength::FontRelative(FontRelativeLength::Em(-0.5)))); + let expected = Spacing::Value(Length::NoCalc(NoCalcLength::FontRelative(FontRelativeLength::Em(-0.5)))); assert_eq!(negative_value, expected); } #[test] fn negative_word_spacing_should_parse_properly() { use style::properties::longhands::word_spacing; - use style::properties::longhands::word_spacing::SpecifiedValue; use style::values::specified::length::{NoCalcLength, LengthOrPercentage, FontRelativeLength}; let negative_value = parse_longhand!(word_spacing, "-0.5em"); - let expected = SpecifiedValue::Specified(LengthOrPercentage::Length(NoCalcLength::FontRelative( - FontRelativeLength::Em(-0.5)))); + let expected = Spacing::Value(LengthOrPercentage::Length( + NoCalcLength::FontRelative(FontRelativeLength::Em(-0.5)) + )); assert_eq!(negative_value, expected); } diff --git a/tests/unit/style/properties/serialization.rs b/tests/unit/style/properties/serialization.rs index cee52e5385f..e8009794a5a 100644 --- a/tests/unit/style/properties/serialization.rs +++ b/tests/unit/style/properties/serialization.rs @@ -9,7 +9,7 @@ use style::properties::longhands::outline_color::computed_value::T as ComputedCo use style::properties::parse_property_declaration_list; use style::values::{RGBA, Auto}; use style::values::CustomIdent; -use style::values::specified::{BorderStyle, BorderWidth, CSSColor, Length, LengthOrPercentage}; +use style::values::specified::{BorderStyle, BorderSideWidth, CSSColor, Length, LengthOrPercentage}; use style::values::specified::{LengthOrPercentageOrAuto, LengthOrPercentageOrAutoOrContent}; use style::values::specified::{NoCalcLength, PositionComponent}; use style::values::specified::position::Y; @@ -221,8 +221,8 @@ mod shorthand_serialization { properties.push(PropertyDeclaration::BorderBottomStyle(solid.clone())); properties.push(PropertyDeclaration::BorderLeftStyle(solid.clone())); - let px_30 = BorderWidth::from_length(Length::from_px(30f32)); - let px_10 = BorderWidth::from_length(Length::from_px(10f32)); + let px_30 = BorderSideWidth::Length(Length::from_px(30f32)); + let px_10 = BorderSideWidth::Length(Length::from_px(10f32)); properties.push(PropertyDeclaration::BorderTopWidth(px_30.clone())); properties.push(PropertyDeclaration::BorderRightWidth(px_30.clone())); @@ -255,7 +255,7 @@ mod shorthand_serialization { properties.push(PropertyDeclaration::BorderBottomStyle(solid.clone())); properties.push(PropertyDeclaration::BorderLeftStyle(solid.clone())); - let px_30 = BorderWidth::from_length(Length::from_px(30f32)); + let px_30 = BorderSideWidth::Length(Length::from_px(30f32)); properties.push(PropertyDeclaration::BorderTopWidth(px_30.clone())); properties.push(PropertyDeclaration::BorderRightWidth(px_30.clone())); @@ -295,11 +295,11 @@ mod shorthand_serialization { fn border_width_should_serialize_correctly() { let mut properties = Vec::new(); - let top_px = BorderWidth::from_length(Length::from_px(10f32)); - let bottom_px = BorderWidth::from_length(Length::from_px(10f32)); + let top_px = BorderSideWidth::Length(Length::from_px(10f32)); + let bottom_px = BorderSideWidth::Length(Length::from_px(10f32)); - let right_px = BorderWidth::from_length(Length::from_px(15f32)); - let left_px = BorderWidth::from_length(Length::from_px(15f32)); + let right_px = BorderSideWidth::Length(Length::from_px(15f32)); + let left_px = BorderSideWidth::Length(Length::from_px(15f32)); properties.push(PropertyDeclaration::BorderTopWidth(top_px)); properties.push(PropertyDeclaration::BorderRightWidth(right_px)); @@ -314,10 +314,10 @@ mod shorthand_serialization { fn border_width_with_keywords_should_serialize_correctly() { let mut properties = Vec::new(); - let top_px = BorderWidth::Thin; - let right_px = BorderWidth::Medium; - let bottom_px = BorderWidth::Thick; - let left_px = BorderWidth::from_length(Length::from_px(15f32)); + let top_px = BorderSideWidth::Thin; + let right_px = BorderSideWidth::Medium; + let bottom_px = BorderSideWidth::Thick; + let left_px = BorderSideWidth::Length(Length::from_px(15f32)); properties.push(PropertyDeclaration::BorderTopWidth(top_px)); properties.push(PropertyDeclaration::BorderRightWidth(right_px)); @@ -403,7 +403,7 @@ mod shorthand_serialization { fn directional_border_should_show_all_properties_when_values_are_set() { let mut properties = Vec::new(); - let width = BorderWidth::from_length(Length::from_px(4f32)); + let width = BorderSideWidth::Length(Length::from_px(4f32)); let style = BorderStyle::solid; let color = CSSColor { parsed: ComputedColor::RGBA(RGBA::new(255, 0, 0, 255)), @@ -418,8 +418,8 @@ mod shorthand_serialization { assert_eq!(serialization, "border-top: 4px solid rgb(255, 0, 0);"); } - fn get_border_property_values() -> (BorderWidth, BorderStyle, CSSColor) { - (BorderWidth::from_length(Length::from_px(4f32)), + fn get_border_property_values() -> (BorderSideWidth, BorderStyle, CSSColor) { + (BorderSideWidth::Length(Length::from_px(4f32)), BorderStyle::solid, CSSColor::currentcolor()) } @@ -523,7 +523,6 @@ mod shorthand_serialization { } mod outline { - use style::properties::longhands::outline_width::SpecifiedValue as WidthContainer; use style::values::Either; use super::*; @@ -531,7 +530,7 @@ mod shorthand_serialization { fn outline_should_show_all_properties_when_set() { let mut properties = Vec::new(); - let width = WidthContainer(Length::from_px(4f32)); + let width = BorderSideWidth::Length(Length::from_px(4f32)); let style = Either::Second(BorderStyle::solid); let color = CSSColor { parsed: ComputedColor::RGBA(RGBA::new(255, 0, 0, 255)), @@ -550,7 +549,7 @@ mod shorthand_serialization { fn outline_should_serialize_correctly_when_style_is_auto() { let mut properties = Vec::new(); - let width = WidthContainer(Length::from_px(4f32)); + let width = BorderSideWidth::Length(Length::from_px(4f32)); let style = Either::First(Auto); let color = CSSColor { parsed: ComputedColor::RGBA(RGBA::new(255, 0, 0, 255)), diff --git a/tests/unit/style/properties/viewport.rs b/tests/unit/style/properties/viewport.rs index ce4f879224e..205370da8f4 100644 --- a/tests/unit/style/properties/viewport.rs +++ b/tests/unit/style/properties/viewport.rs @@ -4,22 +4,22 @@ use app_units::Au; use style::properties::PropertyDeclaration; -use style::properties::longhands::border_top_width; use style::values::specified::{AbsoluteLength, Length, NoCalcLength, ViewportPercentageLength}; +use style::values::specified::border::BorderSideWidth; use style_traits::HasViewportPercentage; #[test] fn has_viewport_percentage_for_specified_value() { //TODO: test all specified value with a HasViewportPercentage impl let pvw = PropertyDeclaration::BorderTopWidth( - border_top_width::SpecifiedValue::from_length( + BorderSideWidth::Length( Length::NoCalc(NoCalcLength::ViewportPercentage(ViewportPercentageLength::Vw(100.))) ) ); assert!(pvw.has_viewport_percentage()); let pabs = PropertyDeclaration::BorderTopWidth( - border_top_width::SpecifiedValue::from_length( + BorderSideWidth::Length( Length::NoCalc(NoCalcLength::Absolute(AbsoluteLength::Px(Au(100).to_f32_px()))) ) ); diff --git a/tests/wpt/metadata/cssom/serialize-values.html.ini b/tests/wpt/metadata/cssom/serialize-values.html.ini index 720be83c21e..f4bf4377b00 100644 --- a/tests/wpt/metadata/cssom/serialize-values.html.ini +++ b/tests/wpt/metadata/cssom/serialize-values.html.ini @@ -45,15 +45,6 @@ [outline-color: invert] expected: FAIL - [outline-width: thin] - expected: FAIL - - [outline-width: medium] - expected: FAIL - - [outline-width: thick] - expected: FAIL - [page-break-after: auto] expected: FAIL |