diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 3a73bbce97e..f9e23bd50e0 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -478,7 +478,10 @@ impl LayoutElementHelpers for LayoutJS { if let Some(font_size) = font_size { hints.push(from_declaration( shared_lock, - PropertyDeclaration::FontSize(font_size::SpecifiedValue(font_size.into())))) + PropertyDeclaration::FontSize( + font_size::SpecifiedValue::from_html_size(font_size as u8) + ) + )) } let cellspacing = if let Some(this) = self.downcast::() { diff --git a/components/script/dom/htmlfontelement.rs b/components/script/dom/htmlfontelement.rs index 8644544cdfe..4e6b96a9c7e 100644 --- a/components/script/dom/htmlfontelement.rs +++ b/components/script/dom/htmlfontelement.rs @@ -18,7 +18,6 @@ use html5ever_atoms::LocalName; use servo_atoms::Atom; use style::attr::AttrValue; use style::str::{HTML_SPACE_CHARACTERS, read_numbers}; -use style::values::specified; #[dom_struct] pub struct HTMLFontElement { @@ -62,8 +61,7 @@ impl HTMLFontElementMethods for HTMLFontElement { // https://html.spec.whatwg.org/multipage/#dom-font-size fn SetSize(&self, value: DOMString) { let element = self.upcast::(); - let length = parse_length(&value); - element.set_attribute(&local_name!("size"), AttrValue::Length(value.into(), length)); + element.set_attribute(&local_name!("size"), parse_size(&value)); } } @@ -76,10 +74,7 @@ impl VirtualMethods for HTMLFontElement { match name { &local_name!("face") => AttrValue::from_atomic(value.into()), &local_name!("color") => AttrValue::from_legacy_color(value.into()), - &local_name!("size") => { - let length = parse_length(&value); - AttrValue::Length(value.into(), length) - }, + &local_name!("size") => parse_size(&value), _ => self.super_type().unwrap().parse_plain_attribute(name, value), } } @@ -88,7 +83,7 @@ impl VirtualMethods for HTMLFontElement { pub trait HTMLFontElementLayoutHelpers { fn get_color(&self) -> Option; fn get_face(&self) -> Option; - fn get_size(&self) -> Option; + fn get_size(&self) -> Option; } impl HTMLFontElementLayoutHelpers for LayoutJS { @@ -113,18 +108,21 @@ impl HTMLFontElementLayoutHelpers for LayoutJS { } #[allow(unsafe_code)] - fn get_size(&self) -> Option { - unsafe { + fn get_size(&self) -> Option { + let size = unsafe { (*self.upcast::().unsafe_get()) .get_attr_for_layout(&ns!(), &local_name!("size")) - .and_then(AttrValue::as_length) - .cloned() + }; + match size { + Some(&AttrValue::UInt(_, s)) => Some(s), + _ => None, } } } /// https://html.spec.whatwg.org/multipage/#rules-for-parsing-a-legacy-font-size -fn parse_length(mut input: &str) -> Option { +fn parse_size(mut input: &str) -> AttrValue { + let original_input = input; // Steps 1 & 2 are not relevant // Step 3 @@ -138,7 +136,7 @@ fn parse_length(mut input: &str) -> Option { let mut input_chars = input.chars().peekable(); let parse_mode = match input_chars.peek() { // Step 4 - None => return None, + None => return AttrValue::String(original_input.into()), // Step 5 Some(&'+') => { @@ -155,7 +153,7 @@ fn parse_length(mut input: &str) -> Option { // Steps 6, 7, 8 let mut value = match read_numbers(input_chars) { (Some(v), _) if v >= 0 => v, - _ => return None, + _ => return AttrValue::String(original_input.into()), }; // Step 9 @@ -166,5 +164,5 @@ fn parse_length(mut input: &str) -> Option { } // Steps 10, 11, 12 - Some(specified::Length::from_font_size_int(value as u8)) + AttrValue::UInt(original_input.into(), value as u32) } diff --git a/components/style/properties/longhand/font.mako.rs b/components/style/properties/longhand/font.mako.rs index a62da429065..49b3557c8cb 100644 --- a/components/style/properties/longhand/font.mako.rs +++ b/components/style/properties/longhand/font.mako.rs @@ -400,24 +400,129 @@ ${helpers.single_keyword("font-variant-caps", impl ToCss for SpecifiedValue { fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - self.0.to_css(dest) + match *self { + SpecifiedValue::Length(ref lop) => lop.to_css(dest), + SpecifiedValue::Keyword(kw) => kw.to_css(dest), + SpecifiedValue::Smaller => dest.write_str("smaller"), + SpecifiedValue::Larger => dest.write_str("larger"), + } } } impl HasViewportPercentage for SpecifiedValue { fn has_viewport_percentage(&self) -> bool { - return self.0.has_viewport_percentage() + match *self { + SpecifiedValue::Length(ref lop) => lop.has_viewport_percentage(), + _ => false + } } } #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct SpecifiedValue(pub specified::LengthOrPercentage); + pub enum SpecifiedValue { + Length(specified::LengthOrPercentage), + Keyword(KeywordSize), + Smaller, + Larger, + } + pub mod computed_value { use app_units::Au; pub type T = Au; } + /// CSS font keywords + #[derive(Debug, Copy, Clone, PartialEq)] + #[cfg_attr(feature = "servo", derive(HeapSizeOf))] + pub enum KeywordSize { + XXSmall = 0, + XSmall = 1, + Small = 2, + Medium = 3, + Large = 4, + XLarge = 5, + XXLarge = 6, + // This is not a real font keyword and will not parse + // HTML font-size 7 corresponds to this value + XXXLarge = 7, + } + + pub use self::KeywordSize::*; + + impl KeywordSize { + pub fn parse(input: &mut Parser) -> Result { + Ok(match_ignore_ascii_case! {&*input.expect_ident()?, + "xx-small" => XXSmall, + "x-small" => XSmall, + "small" => Small, + "medium" => Medium, + "large" => Large, + "x-large" => XLarge, + "xx-large" => XXLarge, + _ => return Err(()) + }) + } + } + + impl ToCss for KeywordSize { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + dest.write_str(match *self { + XXSmall => "xx-small", + XSmall => "x-small", + Small => "small", + Medium => "medium", + Large => "large", + XLarge => "x-large", + XXLarge => "xx-large", + XXXLarge => unreachable!("We should never serialize \ + specified values set via + HTML presentation attributes"), + }) + } + } + + impl ToComputedValue for KeywordSize { + type ComputedValue = Au; + #[inline] + fn to_computed_value(&self, _: &Context) -> computed_value::T { + // https://drafts.csswg.org/css-fonts-3/#font-size-prop + use values::FONT_MEDIUM_PX; + match *self { + XXSmall => Au::from_px(FONT_MEDIUM_PX) * 3 / 5, + XSmall => Au::from_px(FONT_MEDIUM_PX) * 3 / 4, + Small => Au::from_px(FONT_MEDIUM_PX) * 8 / 9, + Medium => Au::from_px(FONT_MEDIUM_PX), + Large => Au::from_px(FONT_MEDIUM_PX) * 6 / 5, + XLarge => Au::from_px(FONT_MEDIUM_PX) * 3 / 2, + XXLarge => Au::from_px(FONT_MEDIUM_PX) * 2, + XXXLarge => Au::from_px(FONT_MEDIUM_PX) * 3, + } + } + + #[inline] + fn from_computed_value(_: &computed_value::T) -> Self { + unreachable!() + } + } + + impl SpecifiedValue { + /// https://html.spec.whatwg.org/multipage/#rules-for-parsing-a-legacy-font-size + pub fn from_html_size(size: u8) -> Self { + SpecifiedValue::Keyword(match size { + // If value is less than 1, let it be 1. + 0 | 1 => XSmall, + 2 => Small, + 3 => Medium, + 4 => Large, + 5 => XLarge, + 6 => XXLarge, + // If value is greater than 7, let it be 7. + _ => XXXLarge, + }) + } + } + #[inline] #[allow(missing_docs)] pub fn get_initial_value() -> computed_value::T { @@ -426,7 +531,7 @@ ${helpers.single_keyword("font-variant-caps", #[inline] pub fn get_initial_specified_value() -> SpecifiedValue { - SpecifiedValue(specified::LengthOrPercentage::Length(NoCalcLength::medium())) + SpecifiedValue::Keyword(Medium) } impl ToComputedValue for SpecifiedValue { @@ -434,45 +539,61 @@ ${helpers.single_keyword("font-variant-caps", #[inline] fn to_computed_value(&self, context: &Context) -> computed_value::T { - match self.0 { - LengthOrPercentage::Length(NoCalcLength::FontRelative(value)) => { + use values::specified::length::FontRelativeLength; + match *self { + SpecifiedValue::Length(LengthOrPercentage::Length( + NoCalcLength::FontRelative(value))) => { value.to_computed_value(context, /* use inherited */ true) } - LengthOrPercentage::Length(NoCalcLength::ServoCharacterWidth(value)) => { + SpecifiedValue::Length(LengthOrPercentage::Length( + NoCalcLength::ServoCharacterWidth(value))) => { value.to_computed_value(context.inherited_style().get_font().clone_font_size()) } - LengthOrPercentage::Length(ref l) => { + SpecifiedValue::Length(LengthOrPercentage::Length(ref l)) => { l.to_computed_value(context) } - LengthOrPercentage::Percentage(Percentage(value)) => { + SpecifiedValue::Length(LengthOrPercentage::Percentage(Percentage(value))) => { context.inherited_style().get_font().clone_font_size().scale_by(value) } - LengthOrPercentage::Calc(ref calc) => { + SpecifiedValue::Length(LengthOrPercentage::Calc(ref calc)) => { let calc = calc.to_computed_value(context); calc.length() + context.inherited_style().get_font().clone_font_size() .scale_by(calc.percentage()) } + SpecifiedValue::Keyword(ref key) => { + key.to_computed_value(context) + } + SpecifiedValue::Smaller => { + FontRelativeLength::Em(0.85).to_computed_value(context, + /* use_inherited */ true) + } + SpecifiedValue::Larger => { + FontRelativeLength::Em(1.2).to_computed_value(context, + /* use_inherited */ true) + } } } #[inline] fn from_computed_value(computed: &computed_value::T) -> Self { - SpecifiedValue(LengthOrPercentage::Length( + SpecifiedValue::Length(LengthOrPercentage::Length( ToComputedValue::from_computed_value(computed) )) } } /// | | | - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { - use values::specified::{Length, LengthOrPercentage}; - - input.try(specified::LengthOrPercentage::parse_non_negative) - .or_else(|()| { - let ident = try!(input.expect_ident()); - NoCalcLength::from_str(&ident as &str) - .ok_or(()) - .map(specified::LengthOrPercentage::Length) - }).map(SpecifiedValue) + pub fn parse(_: &ParserContext, input: &mut Parser) -> Result { + if let Ok(lop) = input.try(specified::LengthOrPercentage::parse_non_negative) { + Ok(SpecifiedValue::Length(lop)) + } else if let Ok(kw) = input.try(KeywordSize::parse) { + Ok(SpecifiedValue::Keyword(kw)) + } else { + match_ignore_ascii_case! {&*input.expect_ident()?, + "smaller" => Ok(SpecifiedValue::Smaller), + "larger" => Ok(SpecifiedValue::Larger), + _ => Err(()) + } + } } diff --git a/components/style/values/specified/length.rs b/components/style/values/specified/length.rs index d530680660a..bffae92c4ff 100644 --- a/components/style/values/specified/length.rs +++ b/components/style/values/specified/length.rs @@ -276,38 +276,6 @@ impl Mul for NoCalcLength { } impl NoCalcLength { - /// https://drafts.csswg.org/css-fonts-3/#font-size-prop - pub fn from_str(s: &str) -> Option { - Some(match_ignore_ascii_case! { s, - "xx-small" => NoCalcLength::Absolute(Au::from_px(FONT_MEDIUM_PX) * 3 / 5), - "x-small" => NoCalcLength::Absolute(Au::from_px(FONT_MEDIUM_PX) * 3 / 4), - "small" => NoCalcLength::Absolute(Au::from_px(FONT_MEDIUM_PX) * 8 / 9), - "medium" => NoCalcLength::Absolute(Au::from_px(FONT_MEDIUM_PX)), - "large" => NoCalcLength::Absolute(Au::from_px(FONT_MEDIUM_PX) * 6 / 5), - "x-large" => NoCalcLength::Absolute(Au::from_px(FONT_MEDIUM_PX) * 3 / 2), - "xx-large" => NoCalcLength::Absolute(Au::from_px(FONT_MEDIUM_PX) * 2), - - // https://github.com/servo/servo/issues/3423#issuecomment-56321664 - "smaller" => NoCalcLength::FontRelative(FontRelativeLength::Em(0.85)), - "larger" => NoCalcLength::FontRelative(FontRelativeLength::Em(1.2)), - _ => return None - }) - } - - /// https://drafts.csswg.org/css-fonts-3/#font-size-prop - pub fn from_font_size_int(i: u8) -> Self { - let au = match i { - 0 | 1 => Au::from_px(FONT_MEDIUM_PX) * 3 / 4, - 2 => Au::from_px(FONT_MEDIUM_PX) * 8 / 9, - 3 => Au::from_px(FONT_MEDIUM_PX), - 4 => Au::from_px(FONT_MEDIUM_PX) * 6 / 5, - 5 => Au::from_px(FONT_MEDIUM_PX) * 3 / 2, - 6 => Au::from_px(FONT_MEDIUM_PX) * 2, - _ => Au::from_px(FONT_MEDIUM_PX) * 3, - }; - NoCalcLength::Absolute(au) - } - /// Parse a given absolute or relative dimension. pub fn parse_dimension(value: CSSFloat, unit: &str) -> Result { match_ignore_ascii_case! { unit, @@ -444,21 +412,11 @@ impl Length { Length::NoCalc(NoCalcLength::zero()) } - /// https://drafts.csswg.org/css-fonts-3/#font-size-prop - pub fn from_str(s: &str) -> Option { - NoCalcLength::from_str(s).map(Length::NoCalc) - } - /// Parse a given absolute or relative dimension. pub fn parse_dimension(value: CSSFloat, unit: &str) -> Result { NoCalcLength::parse_dimension(value, unit).map(Length::NoCalc) } - /// https://drafts.csswg.org/css-fonts-3/#font-size-prop - pub fn from_font_size_int(i: u8) -> Self { - Length::NoCalc(NoCalcLength::from_font_size_int(i)) - } - #[inline] fn parse_internal(input: &mut Parser, context: AllowedNumericType) -> Result { match try!(input.next()) { diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 177a6c076e8..253e724a363 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -1111,7 +1111,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetKeywordValue(declarations: value: i32) { use style::properties::{PropertyDeclaration, LonghandId}; use style::properties::longhands; - use style::values::specified::{BorderStyle, NoCalcLength}; + use style::values::specified::BorderStyle; let declarations = Locked::::as_arc(&declarations); let long = get_longhand_from_id!(property); @@ -1127,7 +1127,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetKeywordValue(declarations: Clear => longhands::clear::SpecifiedValue::from_gecko_keyword(value), FontSize => { // We rely on Gecko passing in font-size values (0...7) here. - longhands::font_size::SpecifiedValue(NoCalcLength::from_font_size_int(value as u8).into()) + longhands::font_size::SpecifiedValue::from_html_size(value as u8) }, ListStyleType => longhands::list_style_type::SpecifiedValue::from_gecko_keyword(value), WhiteSpace => longhands::white_space::SpecifiedValue::from_gecko_keyword(value), diff --git a/tests/wpt/metadata/cssom/serialize-values.html.ini b/tests/wpt/metadata/cssom/serialize-values.html.ini index 1cfe7497be5..6fe7f6507d9 100644 --- a/tests/wpt/metadata/cssom/serialize-values.html.ini +++ b/tests/wpt/metadata/cssom/serialize-values.html.ini @@ -27,33 +27,6 @@ [font-family: Arial] expected: FAIL - [font-size: xx-small] - expected: FAIL - - [font-size: x-small] - expected: FAIL - - [font-size: small] - expected: FAIL - - [font-size: medium] - expected: FAIL - - [font-size: large] - expected: FAIL - - [font-size: x-large] - expected: FAIL - - [font-size: xx-large] - expected: FAIL - - [font-size: larger] - expected: FAIL - - [font-size: smaller] - expected: FAIL - [list-style-type: decimal-leading-zero] expected: FAIL