bug 973380 - fix font metrics initialization for non-scalable fonts in the gfxFT2Fonts backend. r=karlt
authorJonathan Kew <jkew@mozilla.com>
Mon, 17 Feb 2014 07:45:57 +0000
changeset 169458 8112ba0e9eb62bd6e4a280828a29b07cd09d679b
parent 169457 b98808ff6c8954cd2ae74e6378f49ac48b1f7a97
child 169459 0a69d9510a54b59b0b958c889669ec0a2ad37d1f
child 169470 364f8691ea511992c24441ba27d2fbf6783b0684
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewerskarlt
bugs973380
milestone30.0a1
bug 973380 - fix font metrics initialization for non-scalable fonts in the gfxFT2Fonts backend. r=karlt
gfx/thebes/gfxFT2Utils.cpp
--- a/gfx/thebes/gfxFT2Utils.cpp
+++ b/gfx/thebes/gfxFT2Utils.cpp
@@ -76,44 +76,51 @@ gfxFT2LockedFace::GetMetrics(gfxFont::Me
 
         return;
     }
 
     const FT_Size_Metrics& ftMetrics = mFace->size->metrics;
 
     gfxFloat emHeight;
     // Scale for vertical design metric conversion: pixels per design unit.
-    gfxFloat yScale;
+    // 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.
         //
         // FT_Size_Metrics::y_scale is in 16.16 fixed point format.  Its
         // (fractional) value is a factor that converts vertical metrics from
         // design units to units of 1/64 pixels, so that the result may be
         // interpreted as pixels in 26.6 fixed point format.
         yScale = FLOAT_FROM_26_6(FLOAT_FROM_16_16(ftMetrics.y_scale));
         emHeight = mFace->units_per_EM * yScale;
     } else { // Not scalable.
-        // FT_Size_Metrics doc says x_scale is "only relevant for scalable
-        // font formats".
-        gfxFloat emUnit = mFace->units_per_EM;
-        emHeight = ftMetrics.y_ppem;
-        yScale = emHeight / emUnit;
+        // 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) {
+            gfxFloat emUnit = head->Units_Per_EM;
+            emHeight = ftMetrics.y_ppem;
+            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) {
+    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;
 
         // maxAscent/maxDescent get used for frame heights, and some fonts
         // don't have the HHEA table ascent/descent set (bug 279032).
@@ -145,17 +152,17 @@ gfxFT2LockedFace::GetMetrics(gfxFont::Me
     // Prefering a measured x over sxHeight because sxHeight doesn't consider
     // hinting, but maybe the x extents are not quite right in some fancy
     // script fonts.  CSS 2.1 suggests possibly using the height of an "o",
     // which would have a more consistent glyph across fonts.
     if (GetCharExtents('x', &extents) && extents.y_bearing < 0.0) {
         aMetrics->xHeight = -extents.y_bearing;
         aMetrics->aveCharWidth = extents.x_advance;
     } else {
-        if (os2 && os2->sxHeight) {
+        if (os2 && os2->sxHeight && yScale > 0.0) {
             aMetrics->xHeight = os2->sxHeight * yScale;
         } else {
             // CSS 2.1, section 4.3.2 Lengths: "In the cases where it is
             // impossible or impractical to determine the x-height, a value of
             // 0.5em should be used."
             aMetrics->xHeight = 0.5 * emHeight;
         }
         aMetrics->aveCharWidth = 0.0; // updated below
@@ -190,33 +197,33 @@ gfxFT2LockedFace::GetMetrics(gfxFont::Me
     // of the PostScript metric, but in the PostScript table of OpenType
     // fonts the metric is "the top of the underline"
     // (http://www.microsoft.com/typography/otspec/post.htm), and FreeType
     // (up to version 2.3.7) doesn't make any adjustment.
     //
     // Therefore get the underline position directly from the table
     // ourselves when this table exists.  Use FreeType's metrics for
     // other (including older PostScript) fonts.
-    if (mFace->underline_position && mFace->underline_thickness) {
+    if (mFace->underline_position && mFace->underline_thickness && yScale > 0.0) {
         aMetrics->underlineSize = mFace->underline_thickness * yScale;
         TT_Postscript *post = static_cast<TT_Postscript*>
             (FT_Get_Sfnt_Table(mFace, ft_sfnt_post));
         if (post && post->underlinePosition) {
             aMetrics->underlineOffset = post->underlinePosition * yScale;
         } else {
             aMetrics->underlineOffset = mFace->underline_position * yScale
                 + 0.5 * aMetrics->underlineSize;
         }
     } else { // No underline info.
         // Imitate Pango.
         aMetrics->underlineSize = emHeight / 14.0;
         aMetrics->underlineOffset = -aMetrics->underlineSize;
     }
 
-    if (os2 && os2->yStrikeoutSize && os2->yStrikeoutPosition) {
+    if (os2 && os2->yStrikeoutSize && os2->yStrikeoutPosition && yScale > 0.0) {
         aMetrics->strikeoutSize = os2->yStrikeoutSize * yScale;
         aMetrics->strikeoutOffset = os2->yStrikeoutPosition * yScale;
     } else { // No strikeout info.
         aMetrics->strikeoutSize = aMetrics->underlineSize;
         // Use OpenType spec's suggested position for Roman font.
         aMetrics->strikeoutOffset = emHeight * 409.0 / 2048.0
             + 0.5 * aMetrics->strikeoutSize;
     }