Bug 1267909 - fix line heights to properly scale to requested size for color-bitmapped SFNTs. r=jfkthame a=gchang
authorLee Salzman <lsalzman@mozilla.com>
Wed, 10 May 2017 11:26:43 -0400
changeset 396304 7067d6a7dc74d854498ff5f45a45b74431e21160
parent 396303 7983fa68e19053f1b9a46d7b38f84916ba67716c
child 396305 adb9ebd81ba2a74931d9e932bfcc1d1f6aca9e17
push id1468
push userasasaki@mozilla.com
push dateMon, 05 Jun 2017 19:31:07 +0000
treeherdermozilla-release@0641fc6ee9d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjfkthame, gchang
bugs1267909
milestone54.0
Bug 1267909 - fix line heights to properly scale to requested size for color-bitmapped SFNTs. r=jfkthame a=gchang MozReview-Commit-ID: KJ0ixEj7ZiV
gfx/thebes/gfxFT2Utils.cpp
--- a/gfx/thebes/gfxFT2Utils.cpp
+++ b/gfx/thebes/gfxFT2Utils.cpp
@@ -5,16 +5,20 @@
 
 #include "gfxFT2FontBase.h"
 #include "gfxFT2Utils.h"
 #include "mozilla/Likely.h"
 #include FT_TRUETYPE_TAGS_H
 #include FT_TRUETYPE_TABLES_H
 #include <algorithm>
 
+#ifndef FT_FACE_FLAG_COLOR
+#define FT_FACE_FLAG_COLOR ( 1L << 14 )
+#endif
+
 #ifdef HAVE_FONTCONFIG_FCFREETYPE_H
 #include <fontconfig/fcfreetype.h>
 #endif
 
 #include "prlink.h"
 
 // aScale is intended for a 16.16 x/y_scale of an FT_Size_Metrics
 static inline FT_Long
@@ -48,17 +52,17 @@ gfxFT2LockedFace::GetMetrics(gfxFont::Me
                              uint32_t* aSpaceGlyph)
 {
     NS_PRECONDITION(aMetrics != nullptr, "aMetrics must not be NULL");
     NS_PRECONDITION(aSpaceGlyph != nullptr, "aSpaceGlyph must not be NULL");
 
     if (MOZ_UNLIKELY(!mFace)) {
         // No face.  This unfortunate situation might happen if the font
         // file is (re)moved at the wrong time.
-        const gfxFloat emHeight = mGfxFont->GetStyle()->size;
+        const gfxFloat emHeight = mGfxFont->GetAdjustedSize();
         aMetrics->emHeight = emHeight;
         aMetrics->maxAscent = aMetrics->emAscent = 0.8 * emHeight;
         aMetrics->maxDescent = aMetrics->emDescent = 0.2 * emHeight;
         aMetrics->maxHeight = emHeight;
         aMetrics->internalLeading = 0.0;
         aMetrics->externalLeading = 0.2 * emHeight;
         const gfxFloat spaceWidth = 0.5 * emHeight;
         aMetrics->spaceWidth = spaceWidth;
@@ -75,16 +79,21 @@ gfxFT2LockedFace::GetMetrics(gfxFont::Me
         aMetrics->strikeoutSize = underlineSize;
 
         *aSpaceGlyph = 0;
         return;
     }
 
     const FT_Size_Metrics& ftMetrics = mFace->size->metrics;
 
+    aMetrics->maxAscent = FLOAT_FROM_26_6(ftMetrics.ascender);
+    aMetrics->maxDescent = -FLOAT_FROM_26_6(ftMetrics.descender);
+    aMetrics->maxAdvance = FLOAT_FROM_26_6(ftMetrics.max_advance);
+    gfxFloat lineHeight = FLOAT_FROM_26_6(ftMetrics.height);
+
     gfxFloat emHeight;
     // Scale for vertical design metric conversion: pixels per design unit.
     // If this remains at 0.0, we can't use metrics from OS/2 etc.
     gfxFloat yScale = 0.0;
     if (FT_IS_SCALABLE(mFace)) {
         // Prefer FT_Size_Metrics::x_scale to x_ppem as x_ppem does not
         // have subpixel accuracy.
         //
@@ -98,29 +107,37 @@ gfxFT2LockedFace::GetMetrics(gfxFont::Me
         emHeight = ftMetrics.y_ppem;
         // FT_Face doc says units_per_EM and a bunch of following fields
         // are "only relevant to scalable outlines". If it's an sfnt,
         // we can get units_per_EM from the 'head' table instead; otherwise,
         // we don't have a unitsPerEm value so we can't compute/use yScale.
         const TT_Header* head =
             static_cast<TT_Header*>(FT_Get_Sfnt_Table(mFace, ft_sfnt_head));
         if (head) {
+            // Bug 1267909 - Even if the font is not explicitly scalable,
+            // if the face has color bitmaps, it should be treated as scalable
+            // and scaled to the desired size. Metrics based on y_ppem need
+            // to be rescaled for the adjusted size. This makes metrics agree
+            // with the scales we pass to Cairo for Fontconfig fonts.
+            if (mFace->face_flags & FT_FACE_FLAG_COLOR) {
+                emHeight = mGfxFont->GetAdjustedSize();
+                gfxFloat adjustScale = emHeight / ftMetrics.y_ppem;
+                aMetrics->maxAscent *= adjustScale;
+                aMetrics->maxDescent *= adjustScale;
+                aMetrics->maxAdvance *= adjustScale;
+                lineHeight *= adjustScale;
+            }
             gfxFloat emUnit = head->Units_Per_EM;
             yScale = emHeight / emUnit;
         }
     }
 
     TT_OS2 *os2 =
         static_cast<TT_OS2*>(FT_Get_Sfnt_Table(mFace, ft_sfnt_os2));
 
-    aMetrics->maxAscent = FLOAT_FROM_26_6(ftMetrics.ascender);
-    aMetrics->maxDescent = -FLOAT_FROM_26_6(ftMetrics.descender);
-    aMetrics->maxAdvance = FLOAT_FROM_26_6(ftMetrics.max_advance);
-
-    gfxFloat lineHeight;
     if (os2 && os2->sTypoAscender && yScale > 0.0) {
         aMetrics->emAscent = os2->sTypoAscender * yScale;
         aMetrics->emDescent = -os2->sTypoDescender * yScale;
         FT_Short typoHeight =
             os2->sTypoAscender - os2->sTypoDescender + os2->sTypoLineGap;
         lineHeight = typoHeight * yScale;
 
         // If the OS/2 fsSelection USE_TYPO_METRICS bit is set,
@@ -137,17 +154,16 @@ gfxFT2LockedFace::GetMetrics(gfxFont::Me
             aMetrics->maxAscent =
                 std::max(aMetrics->maxAscent, NS_round(aMetrics->emAscent));
             aMetrics->maxDescent =
                 std::max(aMetrics->maxDescent, NS_round(aMetrics->emDescent));
         }
     } else {
         aMetrics->emAscent = aMetrics->maxAscent;
         aMetrics->emDescent = aMetrics->maxDescent;
-        lineHeight = FLOAT_FROM_26_6(ftMetrics.height);
     }
 
     cairo_text_extents_t extents;
     *aSpaceGlyph = GetCharExtents(' ', &extents);
     if (*aSpaceGlyph) {
         aMetrics->spaceWidth = extents.x_advance;
     } else {
         aMetrics->spaceWidth = aMetrics->maxAdvance; // guess