aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/style/properties/gecko.mako.rs7
-rw-r--r--components/style/properties/longhand/font.mako.rs383
-rw-r--r--components/style/values/computed/font.rs61
-rw-r--r--components/style/values/computed/mod.rs1
-rw-r--r--components/style/values/mod.rs3
-rw-r--r--components/style/values/specified/font.rs355
-rw-r--r--components/style/values/specified/length.rs8
-rw-r--r--components/style/values/specified/mod.rs1
8 files changed, 430 insertions, 389 deletions
diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs
index 6114267e236..a0490db4e1d 100644
--- a/components/style/properties/gecko.mako.rs
+++ b/components/style/properties/gecko.mako.rs
@@ -2161,7 +2161,7 @@ fn static_assert() {
}
pub fn set_font_size(&mut self, v: longhands::font_size::computed_value::T) {
- use self::longhands::font_size::KeywordSize;
+ use values::specified::font::KeywordSize;
self.gecko.mSize = v.size().0;
self.gecko.mScriptUnconstrainedSize = v.size().0;
if let Some(info) = v.info {
@@ -2370,7 +2370,8 @@ fn static_assert() {
}
pub fn clone_font_size(&self) -> longhands::font_size::computed_value::T {
- use self::longhands::font_size::KeywordSize;
+ use values::computed::font::KeywordInfo;
+ use values::specified::font::KeywordSize;
let size = Au(self.gecko.mSize).into();
let kw = match self.gecko.mFontSizeKeyword as u32 {
structs::NS_STYLE_FONT_SIZE_XXSMALL => KeywordSize::XXSmall,
@@ -2391,7 +2392,7 @@ fn static_assert() {
};
longhands::font_size::computed_value::T {
size: size,
- info: Some(longhands::font_size::computed_value::KeywordInfo {
+ info: Some(KeywordInfo {
kw: kw,
factor: self.gecko.mFontSizeFactor,
offset: Au(self.gecko.mFontSizeOffset).into()
diff --git a/components/style/properties/longhand/font.mako.rs b/components/style/properties/longhand/font.mako.rs
index 9d3ceba8d74..455ea5dd14b 100644
--- a/components/style/properties/longhand/font.mako.rs
+++ b/components/style/properties/longhand/font.mako.rs
@@ -600,363 +600,23 @@ ${helpers.single_keyword_system("font-variant-caps",
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 properties::longhands::system_font::SystemFont;
- use std::fmt;
- use style_traits::ToCss;
- use values::FONT_MEDIUM_PX;
- use values::computed::NonNegativeLength;
- use values::specified::{AllowQuirks, LengthOrPercentage, NoCalcLength};
+ use values::specified::AllowQuirks;
use values::specified::length::FontBaseSize;
-
- impl ToCss for SpecifiedValue {
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- 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"),
- SpecifiedValue::System(sys) => sys.to_css(dest),
- }
- }
- }
-
- #[derive(Clone, Debug, PartialEq)]
- #[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
- #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
- pub enum SpecifiedValue {
- Length(specified::LengthOrPercentage),
- /// A keyword value, along with a ratio and absolute offset.
- /// The ratio in any specified keyword value
- /// will be 1 (with offset 0), but we cascade keywordness even
- /// after font-relative (percent and em) values
- /// have been applied, which is where the ratio
- /// comes in. The offset comes in if we cascaded a calc value,
- /// where the font-relative portion (em and percentage) will
- /// go into the ratio, and the remaining units all computed together
- /// will go into the offset.
- /// See bug 1355707.
- Keyword(KeywordSize, f32, NonNegativeLength),
- Smaller,
- Larger,
- System(SystemFont)
- }
-
- impl From<specified::LengthOrPercentage> for SpecifiedValue {
- fn from(other: specified::LengthOrPercentage) -> Self {
- SpecifiedValue::Length(other)
- }
- }
+ use values::specified::font::{FONT_MEDIUM_PX, KeywordSize};
pub mod computed_value {
- use app_units::Au;
- use std::fmt;
- use style_traits::ToCss;
- use values::computed::NonNegativeLength;
-
- #[derive(Copy, Clone, PartialEq, Debug)]
- #[derive(ToAnimatedValue, Animate, ToAnimatedZero, ComputeSquaredDistance)]
- #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
- pub struct T {
- pub size: NonNegativeLength,
- pub info: Option<KeywordInfo>,
- }
-
- #[derive(Copy, Clone, PartialEq, Debug)]
- #[derive(ToAnimatedValue, Animate, ToAnimatedZero, ComputeSquaredDistance)]
- #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
- pub struct KeywordInfo {
- pub kw: super::KeywordSize,
- pub factor: f32,
- pub offset: NonNegativeLength,
- }
-
- impl KeywordInfo {
- /// Given a parent keyword info (self), apply an additional factor/offset to it
- pub fn compose(self, factor: f32, offset: NonNegativeLength) -> Self {
- KeywordInfo {
- kw: self.kw,
- factor: self.factor * factor,
- offset: self.offset.scale_by(factor) + offset,
- }
- }
- }
-
- impl T {
- pub fn size(self) -> Au {
- self.size.into()
- }
- }
-
- impl ToCss for T {
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- self.size.to_css(dest)
- }
- }
+ use values::computed::font;
+ pub type T = font::FontSize;
}
- /// CSS font keywords
- #[derive(Clone, Copy, Debug, PartialEq)]
- #[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
- #[derive(ToAnimatedValue, Animate, ToAnimatedZero, ComputeSquaredDistance)]
- #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
- pub enum KeywordSize {
- XXSmall = 1, // This is to enable the NonZero optimization
- // which simplifies the representation of Option<KeywordSize>
- // in bindgen
- XSmall,
- Small,
- Medium,
- Large,
- XLarge,
- XXLarge,
- // This is not a real font keyword and will not parse
- // HTML font-size 7 corresponds to this value
- XXXLarge,
- }
-
- pub use self::KeywordSize::*;
-
- impl KeywordSize {
- pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
- try_match_ident_ignore_ascii_case! { input.expect_ident()?,
- "xx-small" => Ok(XXSmall),
- "x-small" => Ok(XSmall),
- "small" => Ok(Small),
- "medium" => Ok(Medium),
- "large" => Ok(Large),
- "x-large" => Ok(XLarge),
- "xx-large" => Ok(XXLarge),
- }
- }
-
- pub fn html_size(&self) -> u8 {
- match *self {
- KeywordSize::XXSmall => 0,
- KeywordSize::XSmall => 1,
- KeywordSize::Small => 2,
- KeywordSize::Medium => 3,
- KeywordSize::Large => 4,
- KeywordSize::XLarge => 5,
- KeywordSize::XXLarge => 6,
- KeywordSize::XXXLarge => 7,
- }
- }
- }
-
- impl Default for KeywordSize {
- fn default() -> Self {
- Medium
- }
- }
-
- impl ToCss for KeywordSize {
- fn to_css<W>(&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"),
- })
- }
- }
-
- % if product == "servo":
- impl ToComputedValue for KeywordSize {
- type ComputedValue = NonNegativeLength;
- #[inline]
- fn to_computed_value(&self, _: &Context) -> NonNegativeLength {
- // 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,
- }.into()
- }
-
- #[inline]
- fn from_computed_value(_: &NonNegativeLength) -> Self {
- unreachable!()
- }
- }
- % else:
- impl ToComputedValue for KeywordSize {
- type ComputedValue = NonNegativeLength;
- #[inline]
- fn to_computed_value(&self, cx: &Context) -> NonNegativeLength {
- use gecko_bindings::structs::nsIAtom;
- use values::specified::length::au_to_int_px;
- // Data from nsRuleNode.cpp in Gecko
- // Mapping from base size and HTML size to pixels
- // The first index is (base_size - 9), the second is the
- // HTML size. "0" is CSS keyword xx-small, not HTML size 0,
- // since HTML size 0 is the same as 1.
- //
- // xxs xs s m l xl xxl -
- // - 0/1 2 3 4 5 6 7
- static FONT_SIZE_MAPPING: [[i32; 8]; 8] = [
- [9, 9, 9, 9, 11, 14, 18, 27],
- [9, 9, 9, 10, 12, 15, 20, 30],
- [9, 9, 10, 11, 13, 17, 22, 33],
- [9, 9, 10, 12, 14, 18, 24, 36],
- [9, 10, 12, 13, 16, 20, 26, 39],
- [9, 10, 12, 14, 17, 21, 28, 42],
- [9, 10, 13, 15, 18, 23, 30, 45],
- [9, 10, 13, 16, 18, 24, 32, 48]
- ];
-
- static FONT_SIZE_FACTORS: [i32; 8] = [60, 75, 89, 100, 120, 150, 200, 300];
-
- // XXXManishearth handle quirks mode
-
- let ref gecko_font = cx.style().get_font().gecko();
- let base_size = unsafe { Atom::with(gecko_font.mLanguage.raw::<nsIAtom>(), |atom| {
- cx.font_metrics_provider.get_size(atom, gecko_font.mGenericID).0
- }) };
-
- let base_size_px = au_to_int_px(base_size as f32);
- let html_size = self.html_size() as usize;
- if base_size_px >= 9 && base_size_px <= 16 {
- NonNegativeLength::new(FONT_SIZE_MAPPING[(base_size_px - 9) as usize][html_size] as f32)
- } else {
- Au(FONT_SIZE_FACTORS[html_size] * base_size / 100).into()
- }
- }
-
- #[inline]
- fn from_computed_value(_: &NonNegativeLength) -> Self {
- unreachable!()
- }
- }
- % endif
-
- /// This is the ratio applied for font-size: larger
- /// and smaller by both Firefox and Chrome
- const LARGER_FONT_SIZE_RATIO: f32 = 1.2;
-
- 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,
- }, 1., Au(0).into())
- }
-
- /// Compute it against a given base font size
- pub fn to_computed_value_against(
- &self,
- context: &Context,
- base_size: FontBaseSize,
- ) -> computed_value::T {
- use values::specified::length::FontRelativeLength;
- let compose_keyword = |factor| {
- context.style().get_parent_font()
- .clone_font_size().info
- .map(|i| i.compose(factor, Au(0).into()))
- };
- let mut info = None;
- let size = match *self {
- SpecifiedValue::Length(LengthOrPercentage::Length(
- NoCalcLength::FontRelative(value))) => {
- if let FontRelativeLength::Em(em) = value {
- // If the parent font was keyword-derived, this is too.
- // Tack the em unit onto the factor
- info = compose_keyword(em);
- }
- value.to_computed_value(context, base_size).into()
- }
- SpecifiedValue::Length(LengthOrPercentage::Length(
- NoCalcLength::ServoCharacterWidth(value))) => {
- value.to_computed_value(base_size.resolve(context)).into()
- }
- SpecifiedValue::Length(LengthOrPercentage::Length(
- NoCalcLength::Absolute(ref l))) => {
- context.maybe_zoom_text(l.to_computed_value(context).into())
- }
- SpecifiedValue::Length(LengthOrPercentage::Length(ref l)) => {
- l.to_computed_value(context).into()
- }
- SpecifiedValue::Length(LengthOrPercentage::Percentage(pc)) => {
- // If the parent font was keyword-derived, this is too.
- // Tack the % onto the factor
- info = compose_keyword(pc.0);
- base_size.resolve(context).scale_by(pc.0).into()
- }
- SpecifiedValue::Length(LengthOrPercentage::Calc(ref calc)) => {
- let parent = context.style().get_parent_font().clone_font_size();
- // if we contain em/% units and the parent was keyword derived, this is too
- // Extract the ratio/offset and compose it
- if (calc.em.is_some() || calc.percentage.is_some()) && parent.info.is_some() {
- let ratio = calc.em.unwrap_or(0.) + calc.percentage.map_or(0., |pc| pc.0);
- // Compute it, but shave off the font-relative part (em, %)
- // This will mean that other font-relative units like ex and ch will be computed against
- // the old font even when the font changes. There's no particular "right answer" for what
- // to do here -- Gecko recascades as if the font had changed, we instead track the changes
- // and reapply, which means that we carry over old computed ex/ch values whilst Gecko
- // recomputes new ones. This is enough of an edge case to not really matter.
- let abs = calc.to_computed_value_zoomed(context, FontBaseSize::Custom(Au(0).into()))
- .length_component().into();
- info = parent.info.map(|i| i.compose(ratio, abs));
- }
- let calc = calc.to_computed_value_zoomed(context, base_size);
- calc.to_used_value(Some(base_size.resolve(context))).unwrap().into()
- }
- SpecifiedValue::Keyword(key, fraction, offset) => {
- // As a specified keyword, this is keyword derived
- info = Some(computed_value::KeywordInfo {
- kw: key,
- factor: fraction,
- offset: offset,
- });
- let key_len = key.to_computed_value(context).scale_by(fraction) + offset;
- context.maybe_zoom_text(key_len).into()
- }
- SpecifiedValue::Smaller => {
- info = compose_keyword(1. / LARGER_FONT_SIZE_RATIO);
- FontRelativeLength::Em(1. / LARGER_FONT_SIZE_RATIO)
- .to_computed_value(context, base_size).into()
- }
- SpecifiedValue::Larger => {
- info = compose_keyword(LARGER_FONT_SIZE_RATIO);
- FontRelativeLength::Em(LARGER_FONT_SIZE_RATIO)
- .to_computed_value(context, base_size).into()
- }
-
- SpecifiedValue::System(_) => {
- <%self:nongecko_unreachable>
- context.cached_system_font.as_ref().unwrap().font_size.size
- </%self:nongecko_unreachable>
- }
- };
- computed_value::T { size, info }
- }
- }
+ 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(),
- info: Some(computed_value::KeywordInfo {
+ info: Some(::values::computed::font::KeywordInfo {
kw: KeywordSize::Medium,
factor: 1.,
offset: Au(0).into(),
@@ -966,26 +626,10 @@ ${helpers.single_keyword_system("font-variant-caps",
#[inline]
pub fn get_initial_specified_value() -> SpecifiedValue {
- SpecifiedValue::Keyword(Medium, 1., Au(0).into())
+ SpecifiedValue::Keyword(KeywordSize::Medium, 1., Au(0).into())
}
- impl ToComputedValue for SpecifiedValue {
- type ComputedValue = computed_value::T;
-
- #[inline]
- fn to_computed_value(&self, context: &Context) -> computed_value::T {
- self.to_computed_value_against(context, FontBaseSize::InheritedStyle)
- }
-
- #[inline]
- fn from_computed_value(computed: &computed_value::T) -> Self {
- SpecifiedValue::Length(LengthOrPercentage::Length(
- ToComputedValue::from_computed_value(&computed.size.0)
- ))
- }
- }
-
/// <length> | <percentage> | <absolute-size> | <relative-size>
pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
@@ -1012,19 +656,6 @@ ${helpers.single_keyword_system("font-variant-caps",
}
}
- impl SpecifiedValue {
- pub fn system_font(f: SystemFont) -> Self {
- SpecifiedValue::System(f)
- }
- pub fn get_system(&self) -> Option<SystemFont> {
- if let SpecifiedValue::System(s) = *self {
- Some(s)
- } else {
- None
- }
- }
- }
-
#[allow(unused_mut)]
pub fn cascade_specified_font_size(context: &mut Context,
specified_value: &SpecifiedValue,
diff --git a/components/style/values/computed/font.rs b/components/style/values/computed/font.rs
new file mode 100644
index 00000000000..62110779d61
--- /dev/null
+++ b/components/style/values/computed/font.rs
@@ -0,0 +1,61 @@
+/* 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 values for font properties
+
+use app_units::Au;
+use std::fmt;
+use style_traits::ToCss;
+use values::computed::NonNegativeLength;
+use values::specified::font as specified;
+
+#[derive(Copy, Clone, PartialEq, Debug)]
+#[derive(ToAnimatedValue, Animate, ToAnimatedZero, ComputeSquaredDistance)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+#[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
+/// The computed value of font-size
+pub struct FontSize {
+ /// The size.
+ pub size: NonNegativeLength,
+ /// If derived from a keyword, the keyword and additional transformations applied to it
+ pub info: Option<KeywordInfo>,
+}
+
+#[derive(Copy, Clone, PartialEq, Debug)]
+#[derive(ToAnimatedValue, Animate, ToAnimatedZero, ComputeSquaredDistance)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+#[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
+/// Additional information for keyword-derived font sizes.
+pub struct KeywordInfo {
+ /// The keyword used
+ pub kw: specified::KeywordSize,
+ /// A factor to be multiplied by the computed size of the keyword
+ pub factor: f32,
+ /// An additional Au offset to add to the kw*factor in the case of calcs
+ pub offset: NonNegativeLength,
+}
+
+impl KeywordInfo {
+ /// Given a parent keyword info (self), apply an additional factor/offset to it
+ pub fn compose(self, factor: f32, offset: NonNegativeLength) -> Self {
+ KeywordInfo {
+ kw: self.kw,
+ factor: self.factor * factor,
+ offset: self.offset.scale_by(factor) + offset,
+ }
+ }
+}
+
+impl FontSize {
+ /// The actual computed font size.
+ pub fn size(self) -> Au {
+ self.size.into()
+ }
+}
+
+impl ToCss for FontSize {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ self.size.to_css(dest)
+ }
+}
diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs
index 1c8a478f205..d7f6ddc5af9 100644
--- a/components/style/values/computed/mod.rs
+++ b/components/style/values/computed/mod.rs
@@ -67,6 +67,7 @@ pub mod box_;
pub mod color;
pub mod effects;
pub mod flex;
+pub mod font;
pub mod image;
#[cfg(feature = "gecko")]
pub mod gecko;
diff --git a/components/style/values/mod.rs b/components/style/values/mod.rs
index 2a0483ca630..15978aa04a3 100644
--- a/components/style/values/mod.rs
+++ b/components/style/values/mod.rs
@@ -29,9 +29,6 @@ pub type CSSFloat = f32;
/// A CSS integer value.
pub type CSSInteger = i32;
-/// The default font size.
-pub const FONT_MEDIUM_PX: i32 = 16;
-
define_keyword_type!(None_, "none");
define_keyword_type!(Auto, "auto");
define_keyword_type!(Normal, "normal");
diff --git a/components/style/values/specified/font.rs b/components/style/values/specified/font.rs
new file mode 100644
index 00000000000..af0d5df149b
--- /dev/null
+++ b/components/style/values/specified/font.rs
@@ -0,0 +1,355 @@
+/* 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 values for font properties
+
+#[cfg(feature = "gecko")]
+use Atom;
+use app_units::Au;
+use cssparser::Parser;
+use properties::longhands::system_font::SystemFont;
+use std::fmt;
+use style_traits::{ToCss, ParseError};
+use values::computed::{font as computed, Context, NonNegativeLength, ToComputedValue};
+use values::specified::{LengthOrPercentage, NoCalcLength};
+use values::specified::length::FontBaseSize;
+
+#[derive(Clone, Debug, PartialEq)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+#[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
+/// A specified font-size value
+pub enum FontSize {
+ /// A length; e.g. 10px.
+ Length(LengthOrPercentage),
+ /// A keyword value, along with a ratio and absolute offset.
+ /// The ratio in any specified keyword value
+ /// will be 1 (with offset 0), but we cascade keywordness even
+ /// after font-relative (percent and em) values
+ /// have been applied, which is where the ratio
+ /// comes in. The offset comes in if we cascaded a calc value,
+ /// where the font-relative portion (em and percentage) will
+ /// go into the ratio, and the remaining units all computed together
+ /// will go into the offset.
+ /// See bug 1355707.
+ Keyword(KeywordSize, f32, NonNegativeLength),
+ /// font-size: smaller
+ Smaller,
+ /// font-size: larger
+ Larger,
+ /// Derived from a specified system font.
+ System(SystemFont)
+}
+
+impl ToCss for FontSize {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ match *self {
+ FontSize::Length(ref lop) => lop.to_css(dest),
+ FontSize::Keyword(kw, _, _) => kw.to_css(dest),
+ FontSize::Smaller => dest.write_str("smaller"),
+ FontSize::Larger => dest.write_str("larger"),
+ FontSize::System(sys) => sys.to_css(dest),
+ }
+ }
+}
+
+impl From<LengthOrPercentage> for FontSize {
+ fn from(other: LengthOrPercentage) -> Self {
+ FontSize::Length(other)
+ }
+}
+
+/// CSS font keywords
+#[derive(Clone, Copy, Debug, PartialEq)]
+#[derive(ToAnimatedValue, Animate, ToAnimatedZero, ComputeSquaredDistance)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+#[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
+#[allow(missing_docs)]
+pub enum KeywordSize {
+ XXSmall = 1, // This is to enable the NonZero optimization
+ // which simplifies the representation of Option<KeywordSize>
+ // in bindgen
+ XSmall,
+ Small,
+ Medium,
+ Large,
+ XLarge,
+ XXLarge,
+ // This is not a real font keyword and will not parse
+ // HTML font-size 7 corresponds to this value
+ XXXLarge,
+}
+
+impl KeywordSize {
+ /// Parse a keyword size
+ pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
+ try_match_ident_ignore_ascii_case! { input.expect_ident()?,
+ "xx-small" => Ok(KeywordSize::XXSmall),
+ "x-small" => Ok(KeywordSize::XSmall),
+ "small" => Ok(KeywordSize::Small),
+ "medium" => Ok(KeywordSize::Medium),
+ "large" => Ok(KeywordSize::Large),
+ "x-large" => Ok(KeywordSize::XLarge),
+ "xx-large" => Ok(KeywordSize::XXLarge),
+ }
+ }
+
+ /// Convert to an HTML <font size> value
+ pub fn html_size(&self) -> u8 {
+ match *self {
+ KeywordSize::XXSmall => 0,
+ KeywordSize::XSmall => 1,
+ KeywordSize::Small => 2,
+ KeywordSize::Medium => 3,
+ KeywordSize::Large => 4,
+ KeywordSize::XLarge => 5,
+ KeywordSize::XXLarge => 6,
+ KeywordSize::XXXLarge => 7,
+ }
+ }
+}
+
+impl Default for KeywordSize {
+ fn default() -> Self {
+ KeywordSize::Medium
+ }
+}
+
+impl ToCss for KeywordSize {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ dest.write_str(match *self {
+ KeywordSize::XXSmall => "xx-small",
+ KeywordSize::XSmall => "x-small",
+ KeywordSize::Small => "small",
+ KeywordSize::Medium => "medium",
+ KeywordSize::Large => "large",
+ KeywordSize::XLarge => "x-large",
+ KeywordSize::XXLarge => "xx-large",
+ KeywordSize::XXXLarge => unreachable!("We should never serialize \
+ specified values set via
+ HTML presentation attributes"),
+ })
+ }
+}
+
+/// This is the ratio applied for font-size: larger
+/// and smaller by both Firefox and Chrome
+const LARGER_FONT_SIZE_RATIO: f32 = 1.2;
+
+/// The default font size.
+pub const FONT_MEDIUM_PX: i32 = 16;
+
+#[cfg(feature = "servo")]
+impl ToComputedValue for KeywordSize {
+ type ComputedValue = NonNegativeLength;
+ #[inline]
+ fn to_computed_value(&self, _: &Context) -> NonNegativeLength {
+ // https://drafts.csswg.org/css-fonts-3/#font-size-prop
+ match *self {
+ KeywordSize::XXSmall => Au::from_px(FONT_MEDIUM_PX) * 3 / 5,
+ KeywordSize::XSmall => Au::from_px(FONT_MEDIUM_PX) * 3 / 4,
+ KeywordSize::Small => Au::from_px(FONT_MEDIUM_PX) * 8 / 9,
+ KeywordSize::Medium => Au::from_px(FONT_MEDIUM_PX),
+ KeywordSize::Large => Au::from_px(FONT_MEDIUM_PX) * 6 / 5,
+ KeywordSize::XLarge => Au::from_px(FONT_MEDIUM_PX) * 3 / 2,
+ KeywordSize::XXLarge => Au::from_px(FONT_MEDIUM_PX) * 2,
+ KeywordSize::XXXLarge => Au::from_px(FONT_MEDIUM_PX) * 3,
+ }.into()
+ }
+
+ #[inline]
+ fn from_computed_value(_: &NonNegativeLength) -> Self {
+ unreachable!()
+ }
+}
+
+#[cfg(feature = "gecko")]
+impl ToComputedValue for KeywordSize {
+ type ComputedValue = NonNegativeLength;
+ #[inline]
+ fn to_computed_value(&self, cx: &Context) -> NonNegativeLength {
+ use gecko_bindings::structs::nsIAtom;
+ use values::specified::length::au_to_int_px;
+ // Data from nsRuleNode.cpp in Gecko
+ // Mapping from base size and HTML size to pixels
+ // The first index is (base_size - 9), the second is the
+ // HTML size. "0" is CSS keyword xx-small, not HTML size 0,
+ // since HTML size 0 is the same as 1.
+ //
+ // xxs xs s m l xl xxl -
+ // - 0/1 2 3 4 5 6 7
+ static FONT_SIZE_MAPPING: [[i32; 8]; 8] = [
+ [9, 9, 9, 9, 11, 14, 18, 27],
+ [9, 9, 9, 10, 12, 15, 20, 30],
+ [9, 9, 10, 11, 13, 17, 22, 33],
+ [9, 9, 10, 12, 14, 18, 24, 36],
+ [9, 10, 12, 13, 16, 20, 26, 39],
+ [9, 10, 12, 14, 17, 21, 28, 42],
+ [9, 10, 13, 15, 18, 23, 30, 45],
+ [9, 10, 13, 16, 18, 24, 32, 48]
+ ];
+
+ static FONT_SIZE_FACTORS: [i32; 8] = [60, 75, 89, 100, 120, 150, 200, 300];
+
+ // XXXManishearth handle quirks mode (bug 1401322)
+
+ let ref gecko_font = cx.style().get_font().gecko();
+ let base_size = unsafe { Atom::with(gecko_font.mLanguage.raw::<nsIAtom>(), |atom| {
+ cx.font_metrics_provider.get_size(atom, gecko_font.mGenericID).0
+ }) };
+
+ let base_size_px = au_to_int_px(base_size as f32);
+ let html_size = self.html_size() as usize;
+ if base_size_px >= 9 && base_size_px <= 16 {
+ Au::from_px(FONT_SIZE_MAPPING[(base_size_px - 9) as usize][html_size]).into()
+ } else {
+ Au(FONT_SIZE_FACTORS[html_size] * base_size / 100).into()
+ }
+ }
+
+ #[inline]
+ fn from_computed_value(_: &NonNegativeLength) -> Self {
+ unreachable!()
+ }
+}
+
+impl FontSize {
+ /// https://html.spec.whatwg.org/multipage/#rules-for-parsing-a-legacy-font-size
+ pub fn from_html_size(size: u8) -> Self {
+ FontSize::Keyword(match size {
+ // If value is less than 1, let it be 1.
+ 0 | 1 => KeywordSize::XSmall,
+ 2 => KeywordSize::Small,
+ 3 => KeywordSize::Medium,
+ 4 => KeywordSize::Large,
+ 5 => KeywordSize::XLarge,
+ 6 => KeywordSize::XXLarge,
+ // If value is greater than 7, let it be 7.
+ _ => KeywordSize::XXXLarge,
+ }, 1., Au(0).into())
+ }
+
+ /// Compute it against a given base font size
+ pub fn to_computed_value_against(
+ &self,
+ context: &Context,
+ base_size: FontBaseSize,
+ ) -> computed::FontSize {
+ use values::specified::length::FontRelativeLength;
+
+ let compose_keyword = |factor| {
+ context.style().get_parent_font()
+ .clone_font_size().info
+ .map(|i| i.compose(factor, Au(0).into()))
+ };
+ let mut info = None;
+ let size = match *self {
+ FontSize::Length(LengthOrPercentage::Length(
+ NoCalcLength::FontRelative(value))) => {
+ if let FontRelativeLength::Em(em) = value {
+ // If the parent font was keyword-derived, this is too.
+ // Tack the em unit onto the factor
+ info = compose_keyword(em);
+ }
+ value.to_computed_value(context, base_size).into()
+ }
+ FontSize::Length(LengthOrPercentage::Length(
+ NoCalcLength::ServoCharacterWidth(value))) => {
+ value.to_computed_value(base_size.resolve(context)).into()
+ }
+ FontSize::Length(LengthOrPercentage::Length(
+ NoCalcLength::Absolute(ref l))) => {
+ context.maybe_zoom_text(l.to_computed_value(context).into())
+ }
+ FontSize::Length(LengthOrPercentage::Length(ref l)) => {
+ l.to_computed_value(context).into()
+ }
+ FontSize::Length(LengthOrPercentage::Percentage(pc)) => {
+ // If the parent font was keyword-derived, this is too.
+ // Tack the % onto the factor
+ info = compose_keyword(pc.0);
+ base_size.resolve(context).scale_by(pc.0).into()
+ }
+ FontSize::Length(LengthOrPercentage::Calc(ref calc)) => {
+ let parent = context.style().get_parent_font().clone_font_size();
+ // if we contain em/% units and the parent was keyword derived, this is too
+ // Extract the ratio/offset and compose it
+ if (calc.em.is_some() || calc.percentage.is_some()) && parent.info.is_some() {
+ let ratio = calc.em.unwrap_or(0.) + calc.percentage.map_or(0., |pc| pc.0);
+ // Compute it, but shave off the font-relative part (em, %)
+ // This will mean that other font-relative units like ex and ch will be computed against
+ // the old font even when the font changes. There's no particular "right answer" for what
+ // to do here -- Gecko recascades as if the font had changed, we instead track the changes
+ // and reapply, which means that we carry over old computed ex/ch values whilst Gecko
+ // recomputes new ones. This is enough of an edge case to not really matter.
+ let abs = calc.to_computed_value_zoomed(context, FontBaseSize::Custom(Au(0).into()))
+ .length_component().into();
+ info = parent.info.map(|i| i.compose(ratio, abs));
+ }
+ let calc = calc.to_computed_value_zoomed(context, base_size);
+ calc.to_used_value(Some(base_size.resolve(context))).unwrap().into()
+ }
+ FontSize::Keyword(key, fraction, offset) => {
+ // As a specified keyword, this is keyword derived
+ info = Some(computed::KeywordInfo {
+ kw: key,
+ factor: fraction,
+ offset: offset,
+ });
+ context.maybe_zoom_text(key.to_computed_value(context).scale_by(fraction) + offset)
+ }
+ FontSize::Smaller => {
+ info = compose_keyword(1. / LARGER_FONT_SIZE_RATIO);
+ FontRelativeLength::Em(1. / LARGER_FONT_SIZE_RATIO)
+ .to_computed_value(context, base_size).into()
+ }
+ FontSize::Larger => {
+ info = compose_keyword(LARGER_FONT_SIZE_RATIO);
+ FontRelativeLength::Em(LARGER_FONT_SIZE_RATIO)
+ .to_computed_value(context, base_size).into()
+ }
+
+ FontSize::System(_) => {
+ #[cfg(feature = "servo")] {
+ unreachable!()
+ }
+ #[cfg(feature = "gecko")] {
+ context.cached_system_font.as_ref().unwrap().font_size.size
+ }
+ }
+ };
+ computed::FontSize { size, info }
+ }
+}
+
+impl ToComputedValue for FontSize {
+ type ComputedValue = computed::FontSize;
+
+ #[inline]
+ fn to_computed_value(&self, context: &Context) -> computed::FontSize {
+ self.to_computed_value_against(context, FontBaseSize::InheritedStyle)
+ }
+
+ #[inline]
+ fn from_computed_value(computed: &computed::FontSize) -> Self {
+ FontSize::Length(LengthOrPercentage::Length(
+ ToComputedValue::from_computed_value(&computed.size.0)
+ ))
+ }
+}
+
+impl FontSize {
+ /// Construct a system font value.
+ pub fn system_font(f: SystemFont) -> Self {
+ FontSize::System(f)
+ }
+
+ /// Obtain the system font, if any
+ pub fn get_system(&self) -> Option<SystemFont> {
+ if let FontSize::System(s) = *self {
+ Some(s)
+ } else {
+ None
+ }
+ }
+}
diff --git a/components/style/values/specified/length.rs b/components/style/values/specified/length.rs
index 257781f62ae..7d1ff581a79 100644
--- a/components/style/values/specified/length.rs
+++ b/components/style/values/specified/length.rs
@@ -18,7 +18,7 @@ use style_traits::{ToCss, ParseError, StyleParseError};
use style_traits::values::specified::AllowedNumericType;
use stylesheets::CssRuleType;
use super::{AllowQuirks, Number, ToComputedValue, Percentage};
-use values::{Auto, CSSFloat, Either, FONT_MEDIUM_PX, None_, Normal};
+use values::{Auto, CSSFloat, Either, None_, Normal};
use values::{ExtremumLength, serialize_dimension};
use values::computed::{self, CSSPixelLength, Context};
use values::generics::NonNegative;
@@ -571,12 +571,6 @@ impl NoCalcLength {
}
}
- #[inline]
- /// Returns a `medium` length.
- pub fn medium() -> NoCalcLength {
- NoCalcLength::Absolute(AbsoluteLength::Px(FONT_MEDIUM_PX as f32))
- }
-
/// Get an absolute length from a px value.
#[inline]
pub fn from_px(px_value: CSSFloat) -> NoCalcLength {
diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs
index 856aecca90a..1add4928007 100644
--- a/components/style/values/specified/mod.rs
+++ b/components/style/values/specified/mod.rs
@@ -65,6 +65,7 @@ pub mod calc;
pub mod color;
pub mod effects;
pub mod flex;
+pub mod font;
#[cfg(feature = "gecko")]
pub mod gecko;
pub mod grid;