Use generics for the line-height property

This commit is contained in:
Anthony Ramine 2017-05-31 12:48:06 +02:00
parent cf71a0cd96
commit 5c6987a50d
12 changed files with 234 additions and 213 deletions

View file

@ -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
}
}

View file

@ -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"),
}
}

View file

@ -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]

View file

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

View file

@ -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
}
}

View file

@ -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 {

View file

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

View file

@ -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<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(()),
}
}
}

View file

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

View file

@ -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<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),
}
}
}

View file

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

View file

@ -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<Number, LengthOrPercentage>;
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)
))
}
}
}
}