Bug 1466332 - patch 3 - Update StyleDistance function to more closely follow CSS4 Fonts algorithm. r=jwatt
authorJonathan Kew <jkew@mozilla.com>
Sun, 03 Jun 2018 21:33:53 +0100
changeset 475219 fa5724780fe76d6ccbbd08d978342a1db6a43d49
parent 475218 68e78883a0312d5e1be05b8c2319b33653640467
child 475334 55d9a9d86fb685e1252ea8afe2588919a8434bf7
child 475355 a71f125a6d73fa6aace10cfe16d8e4b888303f9a
push id9374
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:43:20 +0000
treeherdermozilla-beta@160e085dfb0b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwatt
bugs1466332
milestone62.0a1
first release with
nightly linux32
fa5724780fe7 / 62.0a1 / 20180604100129 / files
nightly linux64
fa5724780fe7 / 62.0a1 / 20180604100129 / files
nightly mac
fa5724780fe7 / 62.0a1 / 20180604100129 / files
nightly win32
fa5724780fe7 / 62.0a1 / 20180604100129 / files
nightly win64
fa5724780fe7 / 62.0a1 / 20180604100129 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1466332 - patch 3 - Update StyleDistance function to more closely follow CSS4 Fonts algorithm. r=jwatt
gfx/thebes/gfxFontEntry.cpp
--- a/gfx/thebes/gfxFontEntry.cpp
+++ b/gfx/thebes/gfxFontEntry.cpp
@@ -1381,71 +1381,166 @@ gfxFontFamily::FindFontForStyle(const gf
     }
     return nullptr;
 }
 
 // style distance ==> [0,500]
 static inline double
 StyleDistance(const gfxFontEntry* aFontEntry, FontSlantStyle aTargetStyle)
 {
-    FontSlantStyle minStyle = aFontEntry->SlantStyle().Min();
+    const FontSlantStyle minStyle = aFontEntry->SlantStyle().Min();
     if (aTargetStyle == minStyle) {
         return 0.0; // styles match exactly ==> 0
     }
 
-    // Compare oblique angles to see how closely they match.
-    // The range of angles is [-90.0 .. 90.0], although in practice values
-    // are unlikely to get anywhere near the extremes.
-    // The style 'italic' is treated as having the same angle as the default
-    // for 'oblique', but with a constant added to the distance to reflect
-    // distinction.
+    // bias added to angle difference when searching in the non-preferred
+    // direction from a target angle
+    const double kReverse = 100.0;
 
-    double extraDistance = 0.0;
-    const double kReverseDistance = 100.0;
+    // bias added when we've crossed from positive to negative angles or
+    // vice versa
+    const double kNegate = 200.0;
 
-    double target;
     if (aTargetStyle.IsNormal()) {
-        target = 0.0;
-        extraDistance = 300.0;
-    } else if (aTargetStyle.IsOblique()) {
-        target = aTargetStyle.ObliqueAngle();
-    } else {
-        target = FontSlantStyle::Oblique().ObliqueAngle();
-        extraDistance = 200.0;
+        if (minStyle.IsOblique()) {
+            // to distinguish oblique 0deg from normal, we add 1.0 to the angle
+            const double minAngle = minStyle.ObliqueAngle();
+            if (minAngle >= 0.0) {
+                return 1.0 + minAngle;
+            }
+            const FontSlantStyle maxStyle = aFontEntry->SlantStyle().Max();
+            const double maxAngle = maxStyle.ObliqueAngle();
+            if (maxAngle >= 0.0) {
+                // [min,max] range includes 0.0, so just return our minimum
+                return 1.0;
+            }
+            // negative oblique is even worse than italic
+            return kNegate - maxAngle;
+        }
+        // must be italic, which is worse than any non-negative oblique;
+        // treat as a match in the wrong search direction
+        MOZ_ASSERT(minStyle.IsItalic());
+        return kReverse;
+    }
+
+    const double kDefaultAngle = FontSlantStyle::Oblique().ObliqueAngle();
+
+    if (aTargetStyle.IsItalic()) {
+        if (minStyle.IsOblique()) {
+            const double minAngle = minStyle.ObliqueAngle();
+            if (minAngle >= kDefaultAngle) {
+                return 1.0 + (minAngle - kDefaultAngle);
+            }
+            const FontSlantStyle maxStyle = aFontEntry->SlantStyle().Max();
+            const double maxAngle = maxStyle.ObliqueAngle();
+            if (maxAngle >= kDefaultAngle) {
+                return 1.0;
+            }
+            if (maxAngle > 0.0) {
+                // wrong direction but still > 0, add bias of 100
+                return kReverse + (kDefaultAngle - maxAngle);
+            }
+            // negative oblique angle, add bias of 300
+            return kReverse + kNegate + (kDefaultAngle - maxAngle);
+        }
+        // normal is worse than oblique > 0, but better than oblique <= 0
+        MOZ_ASSERT(minStyle.IsNormal());
+        return kNegate;
     }
 
-    FontSlantStyle maxStyle = aFontEntry->SlantStyle().Max();
-
-    double minAngle, maxAngle;
-    // There can only be a range of styles if it's oblique
-    if (minStyle.IsNormal()) {
-        minAngle = maxAngle = 0.0;
-        extraDistance = 300.0;
-    } else if (minStyle.IsOblique()) {
-        MOZ_ASSERT(maxStyle.IsOblique());
-        minAngle = minStyle.ObliqueAngle();
-        maxAngle = maxStyle.ObliqueAngle();
-    } else {
-        minAngle = maxAngle = FontSlantStyle::Oblique().ObliqueAngle();
-        extraDistance = 200.0;
+    // target is oblique <angle>: four different cases depending on
+    // the value of the <angle>, which determines the preferred direction
+    // of search
+    const double targetAngle = aTargetStyle.ObliqueAngle();
+    if (targetAngle >= kDefaultAngle) {
+        if (minStyle.IsOblique()) {
+            const double minAngle = minStyle.ObliqueAngle();
+            if (minAngle >= targetAngle) {
+                return minAngle - targetAngle;
+            }
+            const FontSlantStyle maxStyle = aFontEntry->SlantStyle().Max();
+            const double maxAngle = maxStyle.ObliqueAngle();
+            if (maxAngle >= targetAngle) {
+                return 0.0;
+            }
+            if (maxAngle > 0.0) {
+                return kReverse + (targetAngle - maxAngle);
+            }
+            return kReverse + kNegate + (targetAngle - maxAngle);
+        }
+        if (minStyle.IsItalic()) {
+            return kReverse + kNegate;
+        }
+        return kReverse + kNegate + 1.0;
     }
 
-    double distance = 0.0;
-    if (target < minAngle || target > maxAngle) {
-        if (target > 0.0) {
-            distance = minAngle - target;
-        } else {
-            distance = target - maxAngle;
+    if (targetAngle <= -kDefaultAngle) {
+        if (minStyle.IsOblique()) {
+            const FontSlantStyle maxStyle = aFontEntry->SlantStyle().Max();
+            const double maxAngle = maxStyle.ObliqueAngle();
+            if (maxAngle <= targetAngle) {
+                return targetAngle - maxAngle;
+            }
+            const double minAngle = minStyle.ObliqueAngle();
+            if (minAngle <= targetAngle) {
+                return 0.0;
+            }
+            if (minAngle < 0.0) {
+                return kReverse + (minAngle - targetAngle);
+            }
+            return kReverse + kNegate + (minAngle - targetAngle);
         }
-    }
-    if (distance < 0.0) {
-        distance = kReverseDistance - distance;
+        if (minStyle.IsItalic()) {
+            return kReverse + kNegate;
+        }
+        return kReverse + kNegate + 1.0;
     }
 
-    return distance + extraDistance;
+    if (targetAngle >= 0.0) {
+        if (minStyle.IsOblique()) {
+            const double minAngle = minStyle.ObliqueAngle();
+            if (minAngle > targetAngle) {
+                return kReverse + (minAngle - targetAngle);
+            }
+            const FontSlantStyle maxStyle = aFontEntry->SlantStyle().Max();
+            const double maxAngle = maxStyle.ObliqueAngle();
+            if (maxAngle >= targetAngle) {
+                return 0.0;
+            }
+            if (maxAngle > 0.0) {
+                return targetAngle - maxAngle;
+            }
+            return kReverse + kNegate + (targetAngle - maxAngle);
+        }
+        if (minStyle.IsItalic()) {
+            return kReverse + kNegate - 2.0;
+        }
+        return kReverse + kNegate - 1.0;
+    }
+
+    // last case: (targetAngle < 0.0 && targetAngle > kDefaultAngle)
+    if (minStyle.IsOblique()) {
+        const FontSlantStyle maxStyle = aFontEntry->SlantStyle().Max();
+        const double maxAngle = maxStyle.ObliqueAngle();
+        if (maxAngle < targetAngle) {
+            return kReverse + (targetAngle - maxAngle);
+        }
+        const double minAngle = minStyle.ObliqueAngle();
+        if (minAngle <= targetAngle) {
+            return 0.0;
+        }
+        if (minAngle < 0.0) {
+            return minAngle - targetAngle;
+        }
+        return kReverse + kNegate + (minAngle - targetAngle);
+    }
+    if (minStyle.IsItalic()) {
+        return kReverse + kNegate - 2.0;
+    }
+    return kReverse + kNegate - 1.0;
 }
 
 // stretch distance ==> [0,2000]
 static inline double
 StretchDistance(const gfxFontEntry* aFontEntry, FontStretch aTargetStretch)
 {
     const double kReverseDistance = 1000.0;