diff --git a/components/style/gecko/media_queries.rs b/components/style/gecko/media_queries.rs index 1dd6e5aa06c..95a4ec2e42a 100644 --- a/components/style/gecko/media_queries.rs +++ b/components/style/gecko/media_queries.rs @@ -20,7 +20,6 @@ use gecko_bindings::structs::{nsPresContext, RawGeckoPresContextOwned}; use media_queries::MediaType; use parser::ParserContext; use properties::ComputedValues; -use properties::longhands::font_size; use servo_arc::Arc; use std::fmt::{self, Write}; use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicUsize, Ordering}; @@ -32,6 +31,7 @@ use style_traits::viewport::ViewportConstraints; use stylesheets::Origin; use values::{CSSFloat, CustomIdent, serialize_dimension}; use values::computed::{self, ToComputedValue}; +use values::computed::font::FontSize; use values::specified::Length; /// The `Device` in Gecko wraps a pres context, has a default values computed, @@ -75,7 +75,7 @@ impl Device { pres_context: pres_context, default_values: ComputedValues::default_values(unsafe { &*pres_context }), // FIXME(bz): Seems dubious? - root_font_size: AtomicIsize::new(font_size::get_initial_value().size().0 as isize), + root_font_size: AtomicIsize::new(FontSize::medium().size().0 as isize), body_text_color: AtomicUsize::new(unsafe { &*pres_context }.mDefaultColor as usize), used_root_font_size: AtomicBool::new(false), used_viewport_size: AtomicBool::new(false), diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index b79fd2aebb7..03d7cc46915 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -59,6 +59,7 @@ use std::mem::{forget, uninitialized, transmute, zeroed}; use std::{cmp, ops, ptr}; use values::{self, Auto, CustomIdent, Either, KeyframesName, None_}; use values::computed::{NonNegativeLength, ToComputedValue, Percentage}; +use values::computed::font::FontSize; use values::computed::effects::{BoxShadow, Filter, SimpleShadow}; use computed_values::border_style; @@ -2088,7 +2089,7 @@ fn static_assert() { self.gecko.mFont.size = device.unzoom_text(Au(self.gecko.mFont.size)).0; } - pub fn set_font_size(&mut self, v: longhands::font_size::computed_value::T) { + pub fn set_font_size(&mut self, v: FontSize) { use values::specified::font::KeywordSize; self.gecko.mSize = v.size().0; self.gecko.mScriptUnconstrainedSize = v.size().0; @@ -2114,7 +2115,7 @@ fn static_assert() { /// Set font size, taking into account scriptminsize and scriptlevel /// Returns Some(size) if we have to recompute the script unconstrained size - pub fn apply_font_size(&mut self, v: longhands::font_size::computed_value::T, + pub fn apply_font_size(&mut self, v: FontSize, parent: &Self, device: &Device) -> Option { let (adjusted_size, adjusted_unconstrained_size) = @@ -2297,7 +2298,7 @@ fn static_assert() { self.fixup_font_min_size(device); } - pub fn clone_font_size(&self) -> longhands::font_size::computed_value::T { + pub fn clone_font_size(&self) -> FontSize { use values::computed::font::KeywordInfo; use values::specified::font::KeywordSize; let size = Au(self.gecko.mSize).into(); @@ -2311,14 +2312,14 @@ fn static_assert() { structs::NS_STYLE_FONT_SIZE_XXLARGE => KeywordSize::XXLarge, structs::NS_STYLE_FONT_SIZE_XXXLARGE => KeywordSize::XXXLarge, structs::NS_STYLE_FONT_SIZE_NO_KEYWORD => { - return longhands::font_size::computed_value::T { + return FontSize { size: size, keyword_info: None, } } _ => unreachable!("mFontSizeKeyword should be an absolute keyword or NO_KEYWORD") }; - longhands::font_size::computed_value::T { + FontSize { size: size, keyword_info: Some(KeywordInfo { kw: kw, diff --git a/components/style/properties/helpers.mako.rs b/components/style/properties/helpers.mako.rs index 6b05d8087fd..1d4358bb120 100644 --- a/components/style/properties/helpers.mako.rs +++ b/components/style/properties/helpers.mako.rs @@ -356,7 +356,7 @@ let computed = specified_value.to_computed_value(context); % endif % if property.ident == "font_size": - longhands::font_size::cascade_specified_font_size( + specified::FontSize::cascade_specified_font_size( context, &specified_value, computed, @@ -373,7 +373,7 @@ % endif CSSWideKeyword::Initial => { % if property.ident == "font_size": - longhands::font_size::cascade_initial_font_size(context); + computed::FontSize::cascade_initial_font_size(context); % else: context.builder.reset_${property.ident}(); % endif @@ -386,7 +386,7 @@ context.rule_cache_conditions.borrow_mut().set_uncacheable(); % endif % if property.ident == "font_size": - longhands::font_size::cascade_inherit_font_size(context); + computed::FontSize::cascade_inherit_font_size(context); % else: context.builder.inherit_${property.ident}(); % endif diff --git a/components/style/properties/longhand/font.mako.rs b/components/style/properties/longhand/font.mako.rs index a2986c74d25..c9e2a4fff48 100644 --- a/components/style/properties/longhand/font.mako.rs +++ b/components/style/properties/longhand/font.mako.rs @@ -624,137 +624,14 @@ ${helpers.predefined_type("font-weight", flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", spec="https://drafts.csswg.org/css-fonts/#propdef-font-weight")} -<%helpers:longhand name="font-size" animation_value_type="NonNegativeLength" - flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER" - allow_quirks="True" spec="https://drafts.csswg.org/css-fonts/#propdef-font-size"> - use app_units::Au; - use values::specified::AllowQuirks; - use values::specified::length::FontBaseSize; - use values::specified::font::{FONT_MEDIUM_PX, KeywordSize}; - use values::computed::font::{KeywordInfo}; - - pub mod computed_value { - use values::computed::font; - pub type T = font::FontSize; - } - - pub use values::specified::font::FontSize as SpecifiedValue; - - #[inline] - #[allow(missing_docs)] - pub fn get_initial_value() -> computed_value::T { - computed_value::T { - size: Au::from_px(FONT_MEDIUM_PX).into(), - keyword_info: Some(KeywordInfo::medium()) - } - } - - #[inline] - pub fn get_initial_specified_value() -> SpecifiedValue { - SpecifiedValue::Keyword(KeywordInfo::medium()) - } - - - /// | | | - pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) - -> Result> { - parse_quirky(context, input, AllowQuirks::No) - } - - /// Parses a font-size, with quirks. - pub fn parse_quirky<'i, 't>(context: &ParserContext, - input: &mut Parser<'i, 't>, - allow_quirks: AllowQuirks) - -> Result> { - use self::specified::LengthOrPercentage; - if let Ok(lop) = input.try(|i| LengthOrPercentage::parse_non_negative_quirky(context, i, allow_quirks)) { - return Ok(SpecifiedValue::Length(lop)) - } - - if let Ok(kw) = input.try(KeywordSize::parse) { - return Ok(SpecifiedValue::Keyword(kw.into())) - } - - try_match_ident_ignore_ascii_case! { input, - "smaller" => Ok(SpecifiedValue::Smaller), - "larger" => Ok(SpecifiedValue::Larger), - } - } - - #[allow(unused_mut)] - pub fn cascade_specified_font_size(context: &mut Context, - specified_value: &SpecifiedValue, - mut computed: computed_value::T) { - // we could use clone_language and clone_font_family() here but that's - // expensive. Do it only in gecko mode for now. - % if product == "gecko": - // if the language or generic changed, we need to recalculate - // the font size from the stored font-size origin information. - if context.builder.get_font().gecko().mLanguage.mRawPtr != - context.builder.get_parent_font().gecko().mLanguage.mRawPtr || - context.builder.get_font().gecko().mGenericID != - context.builder.get_parent_font().gecko().mGenericID { - if let Some(info) = computed.keyword_info { - computed.size = info.to_computed_value(context); - } - } - % endif - - let device = context.builder.device; - let mut font = context.builder.take_font(); - let parent_unconstrained = { - let parent_font = context.builder.get_parent_font(); - font.apply_font_size(computed, parent_font, device) - }; - context.builder.put_font(font); - - if let Some(parent) = parent_unconstrained { - let new_unconstrained = - specified_value - .to_computed_value_against(context, FontBaseSize::Custom(Au::from(parent))); - context.builder - .mutate_font() - .apply_unconstrained_font_size(new_unconstrained.size); - } - } - - /// FIXME(emilio): This is very complex. Also, it should move to - /// StyleBuilder. - pub fn cascade_inherit_font_size(context: &mut Context) { - // If inheriting, we must recompute font-size in case of language - // changes using the font_size_keyword. We also need to do this to - // handle mathml scriptlevel changes - let kw_inherited_size = context.builder.get_parent_font() - .clone_font_size() - .keyword_info.map(|info| { - SpecifiedValue::Keyword(info).to_computed_value(context).size - }); - let mut font = context.builder.take_font(); - font.inherit_font_size_from(context.builder.get_parent_font(), - kw_inherited_size, - context.builder.device); - context.builder.put_font(font); - } - - /// Cascade the initial value for the `font-size` property. - /// - /// FIXME(emilio): This is the only function that is outside of the - /// `StyleBuilder`, and should really move inside! - /// - /// Can we move the font stuff there? - pub fn cascade_initial_font_size(context: &mut Context) { - // font-size's default ("medium") does not always - // compute to the same value and depends on the font - let computed = - longhands::font_size::get_initial_specified_value() - .to_computed_value(context); - context.builder.mutate_font().set_font_size(computed); - % if product == "gecko": - let device = context.builder.device; - context.builder.mutate_font().fixup_font_min_size(device); - % endif - } - +${helpers.predefined_type("font-size", + "FontSize", + initial_value="computed::FontSize::medium()", + initial_specified_value="specified::FontSize::medium()", + animation_value_type="NonNegativeLength", + allow_quirks=True, + flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", + spec="https://drafts.csswg.org/css-fonts/#propdef-font-size")} <%helpers:longhand products="gecko" name="font-size-adjust" animation_value_type="longhands::font_size_adjust::computed_value::T" @@ -2051,6 +1928,7 @@ ${helpers.predefined_type("-x-text-zoom", use gecko_bindings::bindings; use gecko_bindings::structs::{LookAndFeel_FontID, nsFont}; use std::mem; + use values::computed::font::FontSize; let id = match *self { % for font in system_fonts: @@ -2076,7 +1954,7 @@ ${helpers.predefined_type("-x-text-zoom", unsafe { system.fontlist.mFontlist.mBasePtr.to_safe() } ) ), - font_size: longhands::font_size::computed_value::T { + font_size: FontSize { size: Au(system.size).into(), keyword_info: None }, diff --git a/components/style/properties/shorthand/font.mako.rs b/components/style/properties/shorthand/font.mako.rs index b06f03a74e2..33eded1e5a0 100644 --- a/components/style/properties/shorthand/font.mako.rs +++ b/components/style/properties/shorthand/font.mako.rs @@ -20,10 +20,11 @@ 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, font_variant_caps}; + use properties::longhands::font_variant_caps; #[cfg(feature = "gecko")] use properties::longhands::system_font::SystemFont; use values::specified::text::LineHeight; + use values::specified::FontSize; <% gecko_sub_properties = "kerning language_override size_adjust \ @@ -50,7 +51,11 @@ if let Ok(sys) = input.try(SystemFont::parse) { return Ok(expanded! { % for name in SYSTEM_FONT_LONGHANDS: - ${name}: ${name}::SpecifiedValue::system_font(sys), + % if name == "font_size": + ${name}: FontSize::system_font(sys), + % else: + ${name}: ${name}::SpecifiedValue::system_font(sys), + % endif % endfor // line-height is just reset to initial line_height: LineHeight::normal(), @@ -89,27 +94,38 @@ continue } } - size = Some(font_size::parse(context, input)?); + size = Some(FontSize::parse(context, input)?); break } - #[inline] - fn count(opt: &Option) -> u8 { - if opt.is_some() { 1 } else { 0 } - } - if size.is_none() || - (count(&style) + count(&weight) + count(&variant_caps) + count(&stretch) + nb_normals) > 4 { - return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) - } + + let size = match size { + Some(s) => s, + None => { + return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) + } + }; + let line_height = if input.try(|input| input.expect_delim('/')).is_ok() { Some(LineHeight::parse(context, input)?) } else { None }; + + #[inline] + fn count(opt: &Option) -> u8 { + if opt.is_some() { 1 } else { 0 } + } + + if (count(&style) + count(&weight) + count(&variant_caps) + count(&stretch) + nb_normals) > 4 { + return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) + } + let family = FontFamily::parse(input)?; Ok(expanded! { - % for name in "style weight stretch size variant_caps".split(): + % for name in "style weight stretch variant_caps".split(): font_${name}: unwrap_or_initial!(font_${name}, ${name}), % endfor + font_size: size, line_height: line_height.unwrap_or(LineHeight::normal()), font_family: family, % if product == "gecko": diff --git a/components/style/servo/media_queries.rs b/components/style/servo/media_queries.rs index e5c57b4d703..902e70932e2 100644 --- a/components/style/servo/media_queries.rs +++ b/components/style/servo/media_queries.rs @@ -11,13 +11,13 @@ use euclid::{ScaleFactor, Size2D, TypedSize2D}; use media_queries::MediaType; use parser::ParserContext; use properties::ComputedValues; -use properties::longhands::font_size; use selectors::parser::SelectorParseErrorKind; use std::fmt; use std::sync::atomic::{AtomicBool, AtomicIsize, Ordering}; use style_traits::{CSSPixel, DevicePixel, ToCss, ParseError}; use style_traits::viewport::ViewportConstraints; use values::computed::{self, ToComputedValue}; +use values::computed::font::FontSize; use values::specified; /// A device is a structure that represents the current media a given document @@ -64,7 +64,7 @@ impl Device { viewport_size, device_pixel_ratio, // FIXME(bz): Seems dubious? - root_font_size: AtomicIsize::new(font_size::get_initial_value().size().0 as isize), + root_font_size: AtomicIsize::new(FontSize::medium().size().0 as isize), used_root_font_size: AtomicBool::new(false), used_viewport_units: AtomicBool::new(false), } diff --git a/components/style/values/computed/font.rs b/components/style/values/computed/font.rs index 016f0fa6781..7758ab9ab50 100644 --- a/components/style/values/computed/font.rs +++ b/components/style/values/computed/font.rs @@ -139,6 +139,50 @@ impl FontSize { pub fn size(self) -> Au { self.size.into() } + + #[inline] + /// Get default value of font size. + pub fn medium() -> Self { + Self { + size: Au::from_px(specified::FONT_MEDIUM_PX).into(), + keyword_info: Some(KeywordInfo::medium()) + } + } + + /// FIXME(emilio): This is very complex. Also, it should move to + /// StyleBuilder. + pub fn cascade_inherit_font_size(context: &mut Context) { + // If inheriting, we must recompute font-size in case of language + // changes using the font_size_keyword. We also need to do this to + // handle mathml scriptlevel changes + let kw_inherited_size = context.builder.get_parent_font() + .clone_font_size() + .keyword_info.map(|info| { + specified::FontSize::Keyword(info).to_computed_value(context).size + }); + let mut font = context.builder.take_font(); + font.inherit_font_size_from(context.builder.get_parent_font(), + kw_inherited_size, + context.builder.device); + context.builder.put_font(font); + } + + /// Cascade the initial value for the `font-size` property. + /// + /// FIXME(emilio): This is the only function that is outside of the + /// `StyleBuilder`, and should really move inside! + /// + /// Can we move the font stuff there? + pub fn cascade_initial_font_size(context: &mut Context) { + // font-size's default ("medium") does not always + // compute to the same value and depends on the font + let computed = specified::FontSize::medium().to_computed_value(context); + context.builder.mutate_font().set_font_size(computed); + #[cfg(feature = "gecko")] { + let device = context.builder.device; + context.builder.mutate_font().fixup_font_min_size(device); + } + } } impl ToCss for FontSize { diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index c6b33d58748..1f46f7791a1 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -36,7 +36,7 @@ pub use self::angle::Angle; pub use self::background::{BackgroundSize, BackgroundRepeat}; pub use self::border::{BorderImageSlice, BorderImageWidth, BorderImageSideWidth}; pub use self::border::{BorderRadius, BorderCornerRadius, BorderSpacing}; -pub use self::font::{FontWeight, MozScriptLevel, MozScriptMinSize, XTextZoom}; +pub use self::font::{FontSize, FontWeight, MozScriptLevel, MozScriptMinSize, XTextZoom}; pub use self::box_::{AnimationIterationCount, AnimationName, ScrollSnapType, VerticalAlign}; pub use self::color::{Color, ColorPropertyValue, RGBAColor}; pub use self::effects::{BoxShadow, Filter, SimpleShadow}; diff --git a/components/style/values/specified/font.rs b/components/style/values/specified/font.rs index f9cdbf79251..45b97ee9a5d 100644 --- a/components/style/values/specified/font.rs +++ b/components/style/values/specified/font.rs @@ -13,7 +13,7 @@ use properties::longhands::system_font::SystemFont; use std::fmt; use style_traits::{ToCss, StyleParseErrorKind, ParseError}; use values::computed::{font as computed, Context, Length, NonNegativeLength, ToComputedValue}; -use values::specified::{LengthOrPercentage, NoCalcLength}; +use values::specified::{AllowQuirks, LengthOrPercentage, NoCalcLength}; use values::specified::length::{AU_PER_PT, AU_PER_PX, FontBaseSize}; const DEFAULT_SCRIPT_MIN_SIZE_PT: u32 = 8; @@ -466,6 +466,78 @@ impl FontSize { None } } + + #[inline] + /// Get initial value for specified font size. + pub fn medium() -> Self { + FontSize::Keyword(computed::KeywordInfo::medium()) + } + + /// Parses a font-size, with quirks. + pub fn parse_quirky<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + allow_quirks: AllowQuirks + ) -> Result> { + if let Ok(lop) = input.try(|i| LengthOrPercentage::parse_non_negative_quirky(context, i, allow_quirks)) { + return Ok(FontSize::Length(lop)) + } + + if let Ok(kw) = input.try(KeywordSize::parse) { + return Ok(FontSize::Keyword(kw.into())) + } + + try_match_ident_ignore_ascii_case! { input, + "smaller" => Ok(FontSize::Smaller), + "larger" => Ok(FontSize::Larger), + } + } + + #[allow(unused_mut)] + /// Cascade `font-size` with specified value + pub fn cascade_specified_font_size( + context: &mut Context, + specified_value: &FontSize, + mut computed: computed::FontSize + ) { + // we could use clone_language and clone_font_family() here but that's + // expensive. Do it only in gecko mode for now. + #[cfg(feature = "gecko")] { + // if the language or generic changed, we need to recalculate + // the font size from the stored font-size origin information. + if context.builder.get_font().gecko().mLanguage.mRawPtr != + context.builder.get_parent_font().gecko().mLanguage.mRawPtr || + context.builder.get_font().gecko().mGenericID != + context.builder.get_parent_font().gecko().mGenericID { + if let Some(info) = computed.keyword_info { + computed.size = info.to_computed_value(context); + } + } + } + + let device = context.builder.device; + let mut font = context.builder.take_font(); + let parent_unconstrained = { + let parent_font = context.builder.get_parent_font(); + font.apply_font_size(computed, parent_font, device) + }; + context.builder.put_font(font); + + if let Some(parent) = parent_unconstrained { + let new_unconstrained = + specified_value.to_computed_value_against(context, FontBaseSize::Custom(Au::from(parent))); + context.builder + .mutate_font() + .apply_unconstrained_font_size(new_unconstrained.size); + } + } +} + +impl Parse for FontSize { + /// | | | + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { + FontSize::parse_quirky(context, input, AllowQuirks::No) + } } #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue)] diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index ffe4d7ba59b..7cab5c17248 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -30,7 +30,7 @@ pub use self::align::{AlignItems, AlignJustifyContent, AlignJustifySelf, Justify pub use self::background::{BackgroundRepeat, BackgroundSize}; pub use self::border::{BorderCornerRadius, BorderImageSlice, BorderImageWidth}; pub use self::border::{BorderImageSideWidth, BorderRadius, BorderSideWidth, BorderSpacing}; -pub use self::font::{FontWeight, MozScriptLevel, MozScriptMinSize, XTextZoom}; +pub use self::font::{FontSize, FontWeight, MozScriptLevel, MozScriptMinSize, XTextZoom}; pub use self::box_::{AnimationIterationCount, AnimationName, ScrollSnapType, VerticalAlign}; pub use self::color::{Color, ColorPropertyValue, RGBAColor}; pub use self::effects::{BoxShadow, Filter, SimpleShadow};