Bug 1267909 - fix line heights to properly scale to requested size for color-bitmapped SFNTs. r=jfkthame
authorLee Salzman <lsalzman@mozilla.com>
Wed, 10 May 2017 11:26:43 -0400
changeset 405684 75cf7bb24193488a1f9ee9fb8fa5b2582ffd3091
parent 405683 7f151e6ae1954ca72aa64575ad39682a89656fdd
child 405685 590b949a5e4ae9239e453a6c63a968faa5e8ca44
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjfkthame
bugs1267909
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1267909 - fix line heights to properly scale to requested size for color-bitmapped SFNTs. r=jfkthame 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