diff --git a/components/style/legacy.rs b/components/style/legacy.rs index c7d974d1094..d1451ae6bc4 100644 --- a/components/style/legacy.rs +++ b/components/style/legacy.rs @@ -119,7 +119,7 @@ impl PresentationalHintSynthesis for Stylist { *shareable = false } LengthOrPercentageOrAuto::Length(length) => { - let width_value = specified::LengthOrPercentageOrAuto::Length(specified::Length::Au(length)); + let width_value = specified::LengthOrPercentageOrAuto::Length(specified::Length::Absolute(length)); matching_rules_list.vec_push(from_declaration( PropertyDeclaration::Width(SpecifiedValue(width_value)))); *shareable = false @@ -160,9 +160,9 @@ impl PresentationalHintSynthesis for Stylist { // FIXME(pcwalton): More use of atoms, please! let value = match element.get_attr(&ns!(""), &atom!("type")) { Some("text") | Some("password") => { - specified::Length::ServoCharacterWidth(value) + specified::Length::ServoCharacterWidth(specified::CharacterWidth(value)) } - _ => specified::Length::Au(Au::from_px(value as int)), + _ => specified::Length::Absolute(Au::from_px(value as int)), }; matching_rules_list.vec_push(from_declaration( PropertyDeclaration::Width(SpecifiedValue( @@ -180,7 +180,7 @@ impl PresentationalHintSynthesis for Stylist { // scrollbar size into consideration (but we don't have a scrollbar yet!) // // https://html.spec.whatwg.org/multipage/rendering.html#textarea-effective-width - let value = specified::Length::ServoCharacterWidth(value); + let value = specified::Length::ServoCharacterWidth(specified::CharacterWidth(value)); matching_rules_list.vec_push(from_declaration( PropertyDeclaration::Width(SpecifiedValue( specified::LengthOrPercentageOrAuto::Length(value))))); @@ -193,7 +193,7 @@ impl PresentationalHintSynthesis for Stylist { // TODO(mttr) This should take scrollbar size into consideration. // // https://html.spec.whatwg.org/multipage/rendering.html#textarea-effective-height - let value = specified::Length::Em(value as CSSFloat); + let value = specified::Length::FontRelative(specified::FontRelativeLength::Em(value as CSSFloat)); matching_rules_list.vec_push(from_declaration( PropertyDeclaration::Height(SpecifiedValue( longhands::height::SpecifiedValue( @@ -241,7 +241,7 @@ impl PresentationalHintSynthesis for Stylist { match element.get_unsigned_integer_attribute(UnsignedIntegerAttribute::Border) { None => {} Some(length) => { - let width_value = specified::Length::Au(Au::from_px(length as int)); + let width_value = specified::Length::Absolute(Au::from_px(length as int)); matching_rules_list.vec_push(from_declaration( PropertyDeclaration::BorderTopWidth(SpecifiedValue( longhands::border_top_width::SpecifiedValue(width_value))))); diff --git a/components/style/properties.mako.rs b/components/style/properties.mako.rs index 183f95553f2..2975f33dbd7 100644 --- a/components/style/properties.mako.rs +++ b/components/style/properties.mako.rs @@ -566,7 +566,7 @@ pub mod longhands { SpecifiedValue::Number(value) => computed_value::T::Number(value), SpecifiedValue::Percentage(value) => { computed_value::T::Length( - specified::Length::Em(value).to_computed_value(context)) + specified::Length::FontRelative(specified::FontRelativeLength::Em(value)).to_computed_value(context)) } } } @@ -1475,21 +1475,21 @@ pub mod longhands { input.try(specified::LengthOrPercentage::parse_non_negative) .map(|value| match value { specified::LengthOrPercentage::Length(value) => value, - specified::LengthOrPercentage::Percentage(value) => specified::Length::Em(value) + specified::LengthOrPercentage::Percentage(value) => specified::Length::FontRelative(specified::FontRelativeLength::Em(value)) }) .or_else(|()| { match_ignore_ascii_case! { try!(input.expect_ident()), - "xx-small" => Ok(specified::Length::Au(Au::from_px(MEDIUM_PX) * 3 / 5)), - "x-small" => Ok(specified::Length::Au(Au::from_px(MEDIUM_PX) * 3 / 4)), - "small" => Ok(specified::Length::Au(Au::from_px(MEDIUM_PX) * 8 / 9)), - "medium" => Ok(specified::Length::Au(Au::from_px(MEDIUM_PX))), - "large" => Ok(specified::Length::Au(Au::from_px(MEDIUM_PX) * 6 / 5)), - "x-large" => Ok(specified::Length::Au(Au::from_px(MEDIUM_PX) * 3 / 2)), - "xx-large" => Ok(specified::Length::Au(Au::from_px(MEDIUM_PX) * 2)), + "xx-small" => Ok(specified::Length::Absolute(Au::from_px(MEDIUM_PX) * 3 / 5)), + "x-small" => Ok(specified::Length::Absolute(Au::from_px(MEDIUM_PX) * 3 / 4)), + "small" => Ok(specified::Length::Absolute(Au::from_px(MEDIUM_PX) * 8 / 9)), + "medium" => Ok(specified::Length::Absolute(Au::from_px(MEDIUM_PX))), + "large" => Ok(specified::Length::Absolute(Au::from_px(MEDIUM_PX) * 6 / 5)), + "x-large" => Ok(specified::Length::Absolute(Au::from_px(MEDIUM_PX) * 3 / 2)), + "xx-large" => Ok(specified::Length::Absolute(Au::from_px(MEDIUM_PX) * 2)), // https://github.com/servo/servo/issues/3423#issuecomment-56321664 - "smaller" => Ok(specified::Length::Em(0.85)), - "larger" => Ok(specified::Length::Em(1.2)) + "smaller" => Ok(specified::Length::FontRelative(specified::FontRelativeLength::Em(0.85))), + "larger" => Ok(specified::Length::FontRelative(specified::FontRelativeLength::Em(1.2))) _ => Err(()) } @@ -2038,7 +2038,7 @@ pub mod longhands { pub fn parse_one_box_shadow(input: &mut Parser) -> Result { use util::geometry::Au; - let mut lengths = [specified::Length::Au(Au(0)); 4]; + let mut lengths = [specified::Length::Absolute(Au(0)); 4]; let mut lengths_parsed = false; let mut color = None; let mut inset = false; @@ -2208,10 +2208,10 @@ pub mod longhands { })); if sides.len() == 4 { Ok(Some(SpecifiedClipRect { - top: sides[0].unwrap_or(Length::Au(Au(0))), + top: sides[0].unwrap_or(Length::Absolute(Au(0))), right: sides[1], bottom: sides[2], - left: sides[3].unwrap_or(Length::Au(Au(0))), + left: sides[3].unwrap_or(Length::Absolute(Au(0))), })) } else { Err(()) @@ -2317,7 +2317,7 @@ pub mod longhands { fn parse_one_text_shadow(input: &mut Parser) -> Result { use util::geometry::Au; - let mut lengths = [specified::Length::Au(Au(0)); 3]; + let mut lengths = [specified::Length::Absolute(Au(0)); 3]; let mut lengths_parsed = false; let mut color = None; @@ -2857,7 +2857,7 @@ pub mod shorthands { fn parse_one_set_of_border_radii(mut input: &mut Parser) -> Result<[LengthOrPercentage; 4], ()> { let mut count = 0; - let mut values = [LengthOrPercentage::Length(Length::Au(Au(0))); 4]; + let mut values = [LengthOrPercentage::Length(Length::Absolute(Au(0))); 4]; while count < 4 { if let Ok(value) = input.try(LengthOrPercentage::parse) { values[count] = value; @@ -3773,11 +3773,7 @@ pub fn cascade(viewport_size: Size2D, match *declaration { PropertyDeclaration::FontSize(ref value) => { context.font_size = match *value { - DeclaredValue::SpecifiedValue(ref specified_value) => { - specified_value.0.to_computed_value_with_font_size( - context.inherited_font_size, context.root_font_size - ) - } + DeclaredValue::SpecifiedValue(ref specified_value) => specified_value.0.to_computed_value(&context), DeclaredValue::Initial => longhands::font_size::get_initial_value(), DeclaredValue::Inherit => context.inherited_font_size, } diff --git a/components/style/values.rs b/components/style/values.rs index ae1e4bc2600..c53f2ec86c0 100644 --- a/components/style/values.rs +++ b/components/style/values.rs @@ -114,17 +114,70 @@ pub mod specified { } #[derive(Clone, PartialEq, Copy)] - pub enum Length { - Au(Au), // application units + pub enum FontRelativeLength { Em(CSSFloat), Ex(CSSFloat), - Rem(CSSFloat), + Ch(CSSFloat), + Rem(CSSFloat) + } + impl fmt::Debug for FontRelativeLength { + #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt_to_css(f) } + } + + impl ToCss for FontRelativeLength { + fn to_css(&self, dest: &mut W) -> text_writer::Result where W: TextWriter { + match self { + &FontRelativeLength::Em(length) => write!(dest, "{}em", length), + &FontRelativeLength::Ex(length) => write!(dest, "{}ex", length), + &FontRelativeLength::Ch(length) => write!(dest, "{}ch", length), + &FontRelativeLength::Rem(length) => write!(dest, "{}rem", length) + } + } + } + + impl FontRelativeLength { + pub fn to_computed_value(&self, + reference_font_size: Au, + root_font_size: Au) + -> Au + { + match self { + &FontRelativeLength::Em(length) => reference_font_size.scale_by(length), + &FontRelativeLength::Ex(length) => { + let x_height = 0.5; // TODO: find that from the font + reference_font_size.scale_by(length * x_height) + }, + &FontRelativeLength::Ch(_) => unimplemented!(), + &FontRelativeLength::Rem(length) => root_font_size.scale_by(length) + } + } + } + + #[derive(Clone, PartialEq, Copy)] + pub struct CharacterWidth(pub i32); + + impl CharacterWidth { + pub fn to_computed_value(&self, reference_font_size: Au) -> Au { + // This applies the *converting a character width to pixels* algorithm as specified + // in HTML5 § 14.5.4. + // + // TODO(pcwalton): Find these from the font. + let average_advance = reference_font_size.scale_by(0.5); + let max_advance = reference_font_size; + average_advance.scale_by(self.0 as CSSFloat - 1.0) + max_advance + } + } + + #[derive(Clone, PartialEq, Copy)] + pub enum Length { + Absolute(Au), // application units + FontRelative(FontRelativeLength), /// HTML5 "character width", as defined in HTML5 § 14.5.4. /// /// This cannot be specified by the user directly and is only generated by /// `Stylist::synthesize_rules_for_legacy_attributes()`. - ServoCharacterWidth(i32), + ServoCharacterWidth(CharacterWidth), } impl fmt::Debug for Length { @@ -134,41 +187,14 @@ pub mod specified { impl ToCss for Length { fn to_css(&self, dest: &mut W) -> text_writer::Result where W: TextWriter { match self { - &Length::Au(length) => write!(dest, "{}px", length.to_subpx()), - &Length::Em(length) => write!(dest, "{}em", length), - &Length::Ex(length) => write!(dest, "{}ex", length), - &Length::Rem(length) => write!(dest, "{}rem", length), + &Length::Absolute(length) => write!(dest, "{}px", length.to_subpx()), + &Length::FontRelative(length) => length.to_css(dest), &Length::ServoCharacterWidth(_) => panic!("internal CSS values should never be serialized"), } } } - impl Length { - pub fn to_computed_value_with_font_size(&self, reference_font_size: Au, root_font_size: Au) - -> Au { - match *self { - Length::Au(value) => value, - Length::Em(value) => reference_font_size.scale_by(value), - Length::Ex(value) => { - let x_height = 0.5; // TODO: find that from the font - reference_font_size.scale_by(value * x_height) - }, - Length::Rem(value) => root_font_size.scale_by(value), - Length::ServoCharacterWidth(value) => { - // This applies the *converting a character width to pixels* algorithm as specified - // in HTML5 § 14.5.4. - // - // TODO(pcwalton): Find these from the font. - let average_advance = reference_font_size.scale_by(0.5); - let max_advance = reference_font_size; - average_advance.scale_by(value as CSSFloat - 1.0) + max_advance - } - } - } - } - - const AU_PER_PX: CSSFloat = 60.; const AU_PER_IN: CSSFloat = AU_PER_PX * 96.; const AU_PER_CM: CSSFloat = AU_PER_IN / 2.54; @@ -182,7 +208,7 @@ pub mod specified { Token::Dimension(ref value, ref unit) if negative_ok || value.value >= 0. => { Length::parse_dimension(value.value, unit) } - Token::Number(ref value) if value.value == 0. => Ok(Length::Au(Au(0))), + Token::Number(ref value) if value.value == 0. => Ok(Length::Absolute(Au(0))), _ => Err(()) } } @@ -196,20 +222,22 @@ pub mod specified { pub fn parse_dimension(value: CSSFloat, unit: &str) -> Result { match_ignore_ascii_case! { unit, "px" => Ok(Length::from_px(value)), - "in" => Ok(Length::Au(Au((value * AU_PER_IN) as i32))), - "cm" => Ok(Length::Au(Au((value * AU_PER_CM) as i32))), - "mm" => Ok(Length::Au(Au((value * AU_PER_MM) as i32))), - "pt" => Ok(Length::Au(Au((value * AU_PER_PT) as i32))), - "pc" => Ok(Length::Au(Au((value * AU_PER_PC) as i32))), - "em" => Ok(Length::Em(value)), - "ex" => Ok(Length::Ex(value)), - "rem" => Ok(Length::Rem(value)) + "in" => Ok(Length::Absolute(Au((value * AU_PER_IN) as i32))), + "cm" => Ok(Length::Absolute(Au((value * AU_PER_CM) as i32))), + "mm" => Ok(Length::Absolute(Au((value * AU_PER_MM) as i32))), + "pt" => Ok(Length::Absolute(Au((value * AU_PER_PT) as i32))), + "pc" => Ok(Length::Absolute(Au((value * AU_PER_PC) as i32))), + // font-relative + "em" => Ok(Length::FontRelative(FontRelativeLength::Em(value))), + "ex" => Ok(Length::FontRelative(FontRelativeLength::Ex(value))), + "ch" => Err(()), + "rem" => Ok(Length::FontRelative(FontRelativeLength::Rem(value))), _ => Err(()) } } #[inline] pub fn from_px(px_value: CSSFloat) -> Length { - Length::Au(Au((px_value * AU_PER_PX) as i32)) + Length::Absolute(Au((px_value * AU_PER_PX) as i32)) } } @@ -245,7 +273,7 @@ pub mod specified { Ok(LengthOrPercentage::Percentage(value.unit_value)) } Token::Number(ref value) if value.value == 0. => { - Ok(LengthOrPercentage::Length(Length::Au(Au(0)))) + Ok(LengthOrPercentage::Length(Length::Absolute(Au(0)))) } _ => Err(()) } @@ -294,7 +322,7 @@ pub mod specified { Ok(LengthOrPercentageOrAuto::Percentage(value.unit_value)) } Token::Number(ref value) if value.value == 0. => { - Ok(LengthOrPercentageOrAuto::Length(Length::Au(Au(0)))) + Ok(LengthOrPercentageOrAuto::Length(Length::Absolute(Au(0)))) } Token::Ident(ref value) if value.eq_ignore_ascii_case("auto") => { Ok(LengthOrPercentageOrAuto::Auto) @@ -345,7 +373,7 @@ pub mod specified { Ok(LengthOrPercentageOrNone::Percentage(value.unit_value)) } Token::Number(ref value) if value.value == 0. => { - Ok(LengthOrPercentageOrNone::Length(Length::Au(Au(0)))) + Ok(LengthOrPercentageOrNone::Length(Length::Absolute(Au(0)))) } Token::Ident(ref value) if value.eq_ignore_ascii_case("none") => { Ok(LengthOrPercentageOrNone::None) @@ -386,7 +414,7 @@ pub mod specified { Ok(PositionComponent::Percentage(value.unit_value)) } Token::Number(ref value) if value.value == 0. => { - Ok(PositionComponent::Length(Length::Au(Au(0)))) + Ok(PositionComponent::Length(Length::Absolute(Au(0)))) } Token::Ident(value) => { match_ignore_ascii_case! { value, @@ -736,7 +764,13 @@ pub mod computed { #[inline] fn to_computed_value(&self, context: &Context) -> Au { - self.to_computed_value_with_font_size(context.font_size, context.root_font_size) + match self { + &specified::Length::Absolute(length) => length, + &specified::Length::FontRelative(length) => + length.to_computed_value(context.font_size, context.root_font_size), + &specified::Length::ServoCharacterWidth(length) => + length.to_computed_value(context.font_size) + } } }