diff --git a/components/layout/text.rs b/components/layout/text.rs index 8b0d3c707ea..969e5f0786b 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}; @@ -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/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 7d9db1fd399..61210eff8a5 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -3637,30 +3637,27 @@ 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"), } } 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 { - 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 { - 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/inherited_text.mako.rs b/components/style/properties/longhand/inherited_text.mako.rs index 7b58342a397..25e1ce946eb 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(&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 | | | - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { - 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(&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.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 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/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/mod.rs b/components/style/values/computed/mod.rs index 5931d0e2fb5..a0cf56e13d0 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -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::LineHeight; 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..388b13f302e --- /dev/null +++ b/components/style/values/computed/text.rs @@ -0,0 +1,51 @@ +/* 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::generics::text::LineHeight as GenericLineHeight; + +/// A computed value for the `line-height` property. +pub type LineHeight = GenericLineHeight; + +impl Animatable for LineHeight { + #[inline] + fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result { + 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 { + 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/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..611c9940cf4 --- /dev/null +++ b/components/style/values/generics/text.rs @@ -0,0 +1,47 @@ +/* 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 std::fmt; +use style_traits::ToCss; + +/// A generic value for the `line-height` property. +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq)] +pub enum LineHeight { + /// `normal` + Normal, + /// `-moz-block-height` + #[cfg(feature = "gecko")] + MozBlockHeight, + /// `` + Number(Number), + /// `` + Length(LengthOrPercentage), +} + +impl LineHeight { + /// Returns `normal`. + #[inline] + pub fn normal() -> Self { + LineHeight::Normal + } +} + +impl ToCss for LineHeight + where N: ToCss, L: ToCss, +{ + fn to_css(&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/mod.rs b/components/style/values/specified/mod.rs index 7eb637315d3..b397de791b0 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -44,6 +44,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::LineHeight; pub use self::transform::TransformOrigin; #[cfg(feature = "gecko")] @@ -58,6 +59,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. diff --git a/components/style/values/specified/text.rs b/components/style/values/specified/text.rs new file mode 100644 index 00000000000..bca8467cfd9 --- /dev/null +++ b/components/style/values/specified/text.rs @@ -0,0 +1,97 @@ +/* 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; +use values::specified::Number; +use values::specified::length::{FontRelativeLength, Length, LengthOrPercentage, NoCalcLength}; + +/// A specified value for the `line-height` property. +pub type LineHeight = GenericLineHeight; + +impl Parse for LineHeight { + fn parse(context: &ParserContext, input: &mut Parser) -> Result { + 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) + )) + } + } + } +}