[librsvg: 2/3] (#558): Compute cascaded font-size values correctly for relative units



commit f1db361e346cc58e40be5fd836ead7a1454e924d
Author: Federico Mena Quintero <federico gnome org>
Date:   Fri Feb 14 20:51:52 2020 -0600

    (#558): Compute cascaded font-size values correctly for relative units
    
    We were ignoring Em and Ex as cases that need to be derived from the
    parent element's computed font-size.
    
    Fixes https://gitlab.gnome.org/GNOME/librsvg/issues/558

 rsvg_internals/src/font_props.rs | 88 ++++++++++++++++++++++++++++++++++------
 1 file changed, 75 insertions(+), 13 deletions(-)
---
diff --git a/rsvg_internals/src/font_props.rs b/rsvg_internals/src/font_props.rs
index 1feab115..6a0a300b 100644
--- a/rsvg_internals/src/font_props.rs
+++ b/rsvg_internals/src/font_props.rs
@@ -34,22 +34,44 @@ impl FontSizeSpec {
     pub fn compute(&self, v: &ComputedValues) -> Self {
         let compute_points = |p| 12.0 * 1.2f64.powf(p) / POINTS_PER_INCH;
 
-        let size = v.font_size.0.value();
+        let parent = v.font_size.0.value();
 
+        // The parent must already have resolved to an absolute unit
+        assert!(
+            parent.unit != LengthUnit::Percent
+                && parent.unit != LengthUnit::Em
+                && parent.unit != LengthUnit::Ex
+        );
+
+        use FontSizeSpec::*;
+
+        #[rustfmt::skip]
         let new_size = match self {
-            FontSizeSpec::Smaller => Length::<Both>::new(size.length / 1.2, size.unit),
-            FontSizeSpec::Larger => Length::<Both>::new(size.length * 1.2, size.unit),
-            FontSizeSpec::XXSmall => Length::<Both>::new(compute_points(-3.0), LengthUnit::In),
-            FontSizeSpec::XSmall => Length::<Both>::new(compute_points(-2.0), LengthUnit::In),
-            FontSizeSpec::Small => Length::<Both>::new(compute_points(-1.0), LengthUnit::In),
-            FontSizeSpec::Medium => Length::<Both>::new(compute_points(0.0), LengthUnit::In),
-            FontSizeSpec::Large => Length::<Both>::new(compute_points(1.0), LengthUnit::In),
-            FontSizeSpec::XLarge => Length::<Both>::new(compute_points(2.0), LengthUnit::In),
-            FontSizeSpec::XXLarge => Length::<Both>::new(compute_points(3.0), LengthUnit::In),
-            FontSizeSpec::Value(s) if s.unit == LengthUnit::Percent => {
-                Length::<Both>::new(size.length * s.length, size.unit)
+            Smaller => Length::<Both>::new(parent.length / 1.2,  parent.unit),
+            Larger  => Length::<Both>::new(parent.length * 1.2,  parent.unit),
+            XXSmall => Length::<Both>::new(compute_points(-3.0), LengthUnit::In),
+            XSmall  => Length::<Both>::new(compute_points(-2.0), LengthUnit::In),
+            Small   => Length::<Both>::new(compute_points(-1.0), LengthUnit::In),
+            Medium  => Length::<Both>::new(compute_points(0.0),  LengthUnit::In),
+            Large   => Length::<Both>::new(compute_points(1.0),  LengthUnit::In),
+            XLarge  => Length::<Both>::new(compute_points(2.0),  LengthUnit::In),
+            XXLarge => Length::<Both>::new(compute_points(3.0),  LengthUnit::In),
+
+            Value(s) if s.unit == LengthUnit::Percent => {
+                Length::<Both>::new(parent.length * s.length, parent.unit)
             }
-            FontSizeSpec::Value(s) => *s,
+
+            Value(s) if s.unit == LengthUnit::Em => {
+                Length::<Both>::new(parent.length * s.length, parent.unit)
+            }
+
+            Value(s) if s.unit == LengthUnit::Ex => {
+                // FIXME: it would be nice to know the actual Ex-height
+                // of the font.
+                Length::<Both>::new(parent.length * s.length / 2.0, parent.unit)
+            }
+
+            Value(s) => *s,
         };
 
         FontSizeSpec::Value(new_size)
@@ -209,11 +231,51 @@ impl Parse for SingleFontFamily {
 mod tests {
     use super::*;
 
+    use crate::property_defs::FontSize;
+    use crate::property_macros::Property;
+
     #[test]
     fn detects_invalid_invalid_font_size() {
         assert!(FontSizeSpec::parse_str("furlong").is_err());
     }
 
+    #[test]
+    fn computes_parent_relative_font_size() {
+        let mut values = ComputedValues::default();
+        values.font_size = FontSize::parse_str("10px").unwrap();
+
+        assert_eq!(
+            FontSize::parse_str("150%").unwrap().compute(&values),
+            FontSize::parse_str("15px").unwrap()
+        );
+
+        assert_eq!(
+            FontSize::parse_str("1.5em").unwrap().compute(&values),
+            FontSize::parse_str("15px").unwrap()
+        );
+
+        assert_eq!(
+            FontSize::parse_str("1ex").unwrap().compute(&values),
+            FontSize::parse_str("5px").unwrap()
+        );
+
+        let smaller = FontSize::parse_str("smaller").unwrap().compute(&values).0;
+        if let FontSizeSpec::Value(v) = smaller {
+            assert!(v.length < 10.0);
+            assert_eq!(v.unit, LengthUnit::Px);
+        } else {
+            unreachable!();
+        }
+
+        let larger = FontSize::parse_str("larger").unwrap().compute(&values).0;
+        if let FontSizeSpec::Value(v) = larger {
+            assert!(v.length > 10.0);
+            assert_eq!(v.unit, LengthUnit::Px);
+        } else {
+            unreachable!();
+        }
+    }
+
     #[test]
     fn parses_font_weight() {
         assert_eq!(


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]