--- a/servo/components/style/values/specified/length.rs
+++ b/servo/components/style/values/specified/length.rs
@@ -96,78 +96,122 @@ impl FontBaseSize {
match *self {
FontBaseSize::Custom(size) => size,
FontBaseSize::CurrentStyle => context.style().get_font().clone_font_size().0,
FontBaseSize::InheritedStyle => context.style().get_parent_font().clone_font_size().0,
}
}
}
+/// Font reference size type.
+#[derive(Clone, Copy, Debug, PartialEq)]
+enum FontReferenceSize {
+ /// Represented as the normal font referent size.
+ Full(Au),
+ /// Represented as the case in which we cannot determine the size, so assumes 0.5em.
+ Half(Au),
+}
+
impl FontRelativeLength {
- /// Computes the font-relative length. We use the base_size
- /// flag to pass a different size for computing font-size and unconstrained font-size
+ /// Computes the font-relative length.
pub fn to_computed_value(&self, context: &Context, base_size: FontBaseSize) -> Au {
+ let (reference_size, length) = self.reference_font_size_and_length(context, base_size);
+ match reference_size {
+ FontReferenceSize::Full(au) => au.scale_by(length),
+ FontReferenceSize::Half(au) => au.scale_by(0.5 * length),
+ }
+ }
+
+ /// Computes the font-relative length, but as pixel value.
+ pub fn to_px(&self, context: &Context, base_size: FontBaseSize) -> CSSFloat {
+ use std::f32;
+ let (reference_size, length) = self.reference_font_size_and_length(context, base_size);
+ let pixel = match reference_size {
+ FontReferenceSize::Full(size) => length * size.to_f32_px(),
+ FontReferenceSize::Half(size) => length * 0.5 * size.to_f32_px(),
+ };
+ pixel.min(f32::MAX).max(f32::MIN)
+ }
+
+ /// Return reference font size. We use the base_size flag to pass a different size
+ /// for computing font-size and unconstrained font-size.
+ fn reference_font_size_and_length(
+ &self,
+ context: &Context,
+ base_size: FontBaseSize,
+ ) -> (FontReferenceSize, CSSFloat) {
fn query_font_metrics(context: &Context, reference_font_size: Au) -> FontMetricsQueryResult {
context.font_metrics_provider.query(context.style().get_font(),
reference_font_size,
context.style().writing_mode,
context.in_media_query,
context.device())
}
let reference_font_size = base_size.resolve(context);
match *self {
- FontRelativeLength::Em(length) => reference_font_size.scale_by(length),
+ FontRelativeLength::Em(length) => {
+ (FontReferenceSize::Full(reference_font_size), length)
+ },
FontRelativeLength::Ex(length) => {
- match query_font_metrics(context, reference_font_size) {
- FontMetricsQueryResult::Available(metrics) => metrics.x_height.scale_by(length),
+ let reference_size = match query_font_metrics(context, reference_font_size) {
+ FontMetricsQueryResult::Available(metrics) => {
+ FontReferenceSize::Full(metrics.x_height)
+ },
// https://drafts.csswg.org/css-values/#ex
//
// In the cases where it is impossible or impractical to
// determine the x-height, a value of 0.5em must be
// assumed.
//
- FontMetricsQueryResult::NotAvailable => reference_font_size.scale_by(0.5 * length),
- }
+ FontMetricsQueryResult::NotAvailable => {
+ FontReferenceSize::Half(reference_font_size)
+ },
+ };
+ (reference_size, length)
},
FontRelativeLength::Ch(length) => {
- match query_font_metrics(context, reference_font_size) {
- FontMetricsQueryResult::Available(metrics) => metrics.zero_advance_measure.scale_by(length),
+ let reference_size = match query_font_metrics(context, reference_font_size) {
+ FontMetricsQueryResult::Available(metrics) => {
+ FontReferenceSize::Full(metrics.zero_advance_measure)
+ },
// https://drafts.csswg.org/css-values/#ch
//
// In the cases where it is impossible or impractical to
// determine the measure of the “0” glyph, it must be
// assumed to be 0.5em wide by 1em tall. Thus, the ch
// unit falls back to 0.5em in the general case, and to
// 1em when it would be typeset upright (i.e.
// writing-mode is vertical-rl or vertical-lr and
// text-orientation is upright).
//
FontMetricsQueryResult::NotAvailable => {
if context.style().writing_mode.is_vertical() {
- reference_font_size.scale_by(length)
+ FontReferenceSize::Full(reference_font_size)
} else {
- reference_font_size.scale_by(0.5 * length)
+ FontReferenceSize::Half(reference_font_size)
}
}
- }
+ };
+ (reference_size, length)
}
FontRelativeLength::Rem(length) => {
// https://drafts.csswg.org/css-values/#rem:
//
// When specified on the font-size property of the root
// element, the rem units refer to the property’s initial
// value.
//
- if context.is_root_element {
- reference_font_size.scale_by(length)
+ let reference_size = if context.is_root_element {
+ FontReferenceSize::Full(reference_font_size)
} else {
- context.device().root_font_size().scale_by(length)
- }
+ FontReferenceSize::Full(context.device().root_font_size())
+ };
+ (reference_size, length)
}
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// A viewport-relative length.