b=385263 make line heights integer r=roc
authorKarl Tomlinson <karlt+@karlt.net>
Sat, 27 Sep 2008 12:22:20 +1200
changeset 19808 406819ca370c
parent 19807 25ca781361ed
child 19809 60bd0ee88c78
push id2456
push userktomlinson@mozilla.com
push date2008-09-27 00:22 +0000
treeherdermozilla-central@406819ca370c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs385263
milestone1.9.1b1pre
b=385263 make line heights integer r=roc
gfx/thebes/src/gfxPangoFonts.cpp
--- a/gfx/thebes/src/gfxPangoFonts.cpp
+++ b/gfx/thebes/src/gfxPangoFonts.cpp
@@ -1238,34 +1238,35 @@ LockedFTFace::GetMetrics(gfxFont::Metric
         aMetrics->superscriptOffset = aMetrics->xHeight;
         aMetrics->subscriptOffset = aMetrics->xHeight;
 
         return;
     }
 
     const FT_Size_Metrics& ftMetrics = mFace->size->metrics;
 
+    gfxFloat emHeight;
     // Scale for vertical design metric conversion: pixels per design unit.
     gfxFloat yScale;
     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));
-        aMetrics->emHeight = mFace->units_per_EM * yScale;
+        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;
-        aMetrics->emHeight = ftMetrics.y_ppem;
-        yScale = aMetrics->emHeight / emUnit;
+        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);
@@ -1312,17 +1313,17 @@ LockedFTFace::GetMetrics(gfxFont::Metric
         aMetrics->aveCharWidth = extents.x_advance;
     } else {
         if (os2 && os2->sxHeight) {
             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 * aMetrics->emHeight;
+            aMetrics->xHeight = 0.5 * emHeight;
         }
         aMetrics->aveCharWidth = 0.0; // updated below
     }
     // aveCharWidth is used for the width of text input elements so be
     // liberal rather than conservative in the estimate.
     if (os2 && os2->xAvgCharWidth) {
         // Round to pixels as this is compared with maxAdvance to guess
         // whether this is a fixed width font.
@@ -1363,27 +1364,27 @@ LockedFTFace::GetMetrics(gfxFont::Metric
         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 = aMetrics->emHeight / 14.0;
+        aMetrics->underlineSize = emHeight / 14.0;
         aMetrics->underlineOffset = -aMetrics->underlineSize;
     }
 
     if (os2 && os2->yStrikeoutSize && os2->yStrikeoutPosition) {
         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 = aMetrics->emHeight * 409.0 / 2048.0
+        aMetrics->strikeoutOffset = emHeight * 409.0 / 2048.0
             + 0.5 * aMetrics->strikeoutSize;
     }
     SnapLineToPixels(aMetrics->strikeoutOffset, aMetrics->strikeoutSize);
 
     if (os2 && os2->ySuperscriptYOffset) {
         gfxFloat val = ScaleRoundDesignUnits(os2->ySuperscriptYOffset,
                                              ftMetrics.y_scale);
         aMetrics->superscriptOffset = PR_MAX(1.0, val);
@@ -1398,26 +1399,40 @@ LockedFTFace::GetMetrics(gfxFont::Metric
         val = fabs(val);
         aMetrics->subscriptOffset = PR_MAX(1.0, val);
     } else {
         aMetrics->subscriptOffset = aMetrics->xHeight;
     }
 
     aMetrics->maxHeight = aMetrics->maxAscent + aMetrics->maxDescent;
 
+    // Make the line height an integer number of pixels so that lines will be
+    // equally spaced (rather than just being snapped to pixels, some up and
+    // some down).  Layout calculates line height from the emHeight +
+    // internalLeading + externalLeading, but first each of these is rounded
+    // to layout units.  To ensure that the result is an integer number of
+    // pixels, round each of the components to pixels.
+    aMetrics->emHeight = NS_floor(emHeight + 0.5);
+
+    // maxHeight will normally be an integer, but round anyway in case
+    // FreeType is configured differently.
+    aMetrics->internalLeading =
+        NS_floor(aMetrics->maxHeight - aMetrics->emHeight + 0.5);
+
+    // Text input boxes currently don't work well with lineHeight
+    // significantly less than maxHeight (with Verdana, for example).
+    lineHeight = NS_floor(PR_MAX(lineHeight, aMetrics->maxHeight) + 0.5);
+    aMetrics->externalLeading =
+        lineHeight - aMetrics->internalLeading - aMetrics->emHeight;
+
     // Ensure emAscent + emDescent == emHeight
     gfxFloat sum = aMetrics->emAscent + aMetrics->emDescent;
     aMetrics->emAscent = sum > 0.0 ?
         aMetrics->emAscent * aMetrics->emHeight / sum : 0.0;
     aMetrics->emDescent = aMetrics->emHeight - aMetrics->emAscent;
-
-    aMetrics->internalLeading = aMetrics->maxHeight - aMetrics->emHeight;
-    // Text input boxes currently don't work well with lineHeight < maxHeight
-    // (with Verdana, for example).
-    aMetrics->externalLeading = PR_MAX(lineHeight - aMetrics->maxHeight, 0);
 }
 
 const gfxFont::Metrics&
 gfxFcFont::GetMetrics()
 {
     if (mHasMetrics)
         return mMetrics;