Skip to content
Permalink
Browse files

Refactor style::values::specified::Length to store length by kind (ab…

…solute, font-relative or character width)
  • Loading branch information...
luniv committed Mar 5, 2015
1 parent 00785ec commit 41786c4cb45b68add23902896a4cb4c81c09019d
Showing with 105 additions and 75 deletions.
  1. +6 −6 components/style/legacy.rs
  2. +17 −21 components/style/properties.mako.rs
  3. +82 −48 components/style/values.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)))));
@@ -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<SpecifiedBoxShadow, ()> {
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<SpecifiedTextShadow,()> {
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<Au>,
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,
}
@@ -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<W>(&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<W>(&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<Length, ()> {
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)
}
}
}

0 comments on commit 41786c4

Please sign in to comment.
You can’t perform that action at this time.