Bug 1065002 pt 1.3 - Add an Orientation parameter to gfxFont::GetMetrics and dispatch to horizontal or vertical as needed. r=jdaggett
authorJonathan Kew <jkew@mozilla.com>
Tue, 30 Sep 2014 07:38:26 +0100
changeset 207845 c9c0762bbe7806eae5d25208c74438c54fa0b9e9
parent 207844 adbf88894825a28a5af5a2a3d7cc2efd3321aa46
child 207846 cb0565ea109193fa56778c1e47e23ce2e3b55725
push id49793
push userjkew@mozilla.com
push dateTue, 30 Sep 2014 06:39:12 +0000
treeherdermozilla-inbound@cb0565ea1091 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdaggett
bugs1065002
milestone35.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 1065002 pt 1.3 - Add an Orientation parameter to gfxFont::GetMetrics and dispatch to horizontal or vertical as needed. r=jdaggett
dom/canvas/CanvasRenderingContext2D.cpp
gfx/src/nsFontMetrics.cpp
gfx/thebes/gfxFont.cpp
gfx/thebes/gfxFont.h
gfx/thebes/gfxGlyphExtents.cpp
gfx/thebes/gfxGlyphExtents.h
gfx/thebes/gfxPangoFonts.cpp
gfx/thebes/gfxTextRun.cpp
layout/generic/nsTextFrame.cpp
layout/style/nsRuleNode.cpp
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -3438,17 +3438,17 @@ CanvasRenderingContext2D::DrawOrMeasureT
     anchorX = 1;
   }
 
   processor.mPt.x -= anchorX * totalWidth;
 
   // offset pt.y based on text baseline
   processor.mFontgrp->UpdateUserFonts(); // ensure user font generation is current
   const gfxFont::Metrics& fontMetrics =
-    processor.mFontgrp->GetFirstValidFont()->GetMetrics();
+    processor.mFontgrp->GetFirstValidFont()->GetMetrics(gfxFont::eHorizontal); // XXX vertical?
 
   gfxFloat anchorY;
 
   switch (state.textBaseline)
   {
   case TextBaseline::HANGING:
       // fall through; best we can do with the information available
   case TextBaseline::TOP:
--- a/gfx/src/nsFontMetrics.cpp
+++ b/gfx/src/nsFontMetrics.cpp
@@ -142,17 +142,17 @@ nsFontMetrics::Destroy()
 }
 
 // XXXTODO get rid of this macro
 #define ROUND_TO_TWIPS(x) (nscoord)floor(((x) * mP2A) + 0.5)
 #define CEIL_TO_TWIPS(x) (nscoord)ceil((x) * mP2A)
 
 const gfxFont::Metrics& nsFontMetrics::GetMetrics() const
 {
-    return mFontGroup->GetFirstValidFont()->GetMetrics();
+    return mFontGroup->GetFirstValidFont()->GetMetrics(gfxFont::eHorizontal); // XXX vertical?
 }
 
 nscoord
 nsFontMetrics::XHeight()
 {
     return ROUND_TO_TWIPS(GetMetrics().xHeight);
 }
 
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -653,17 +653,17 @@ gfxShapedText::SetMissingGlyph(uint32_t 
     DetailedGlyph *details = AllocateDetailedGlyphs(aIndex, 1);
 
     details->mGlyphID = aChar;
     if (IsDefaultIgnorable(aChar)) {
         // Setting advance width to zero will prevent drawing the hexbox
         details->mAdvance = 0;
     } else {
         gfxFloat width =
-            std::max(aFont->GetMetrics().aveCharWidth,
+            std::max(aFont->GetMetrics(gfxFont::eHorizontal).aveCharWidth,
                      gfxFontMissingGlyphs::GetDesiredMinWidth(aChar,
                          mAppUnitsPerDevUnit));
         details->mAdvance = uint32_t(width * mAppUnitsPerDevUnit);
     }
     details->mXOffset = 0;
     details->mYOffset = 0;
     GetCharacterGlyphs()[aIndex].SetMissing(1);
 }
@@ -783,17 +783,17 @@ gfxFont::GetGlyphHAdvance(gfxContext *aC
 {
     if (!SetupCairoFont(aCtx)) {
         return 0;
     }
     if (ProvidesGlyphWidths()) {
         return GetGlyphWidth(aCtx, aGID) / 65536.0;
     }
     if (mFUnitsConvFactor == 0.0f) {
-        GetMetrics();
+        GetMetrics(eHorizontal);
     }
     NS_ASSERTION(mFUnitsConvFactor > 0.0f,
                  "missing font unit conversion factor");
     if (!mHarfBuzzShaper) {
         mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
     }
     gfxHarfBuzzShaper* shaper =
         static_cast<gfxHarfBuzzShaper*>(mHarfBuzzShaper.get());
@@ -1775,17 +1775,17 @@ gfxFont::DrawGlyphs(gfxShapedText       
                             double glyphX = aPt->x;
                             if (aRunParams.isRTL) {
                                 glyphX -= advance;
                             }
                             gfxPoint pt(ToDeviceUnits(glyphX, aRunParams.devPerApp),
                                         ToDeviceUnits(aPt->y, aRunParams.devPerApp));
                             gfxFloat advanceDevUnits =
                                 ToDeviceUnits(advance, aRunParams.devPerApp);
-                            gfxFloat height = GetMetrics().maxAscent;
+                            gfxFloat height = GetMetrics(eHorizontal).maxAscent;
                             gfxRect glyphRect(pt.x, pt.y - height,
                                               advanceDevUnits, height);
 
                             // If there's a fake-italic skew in effect as part
                             // of the drawTarget's transform, we need to remove
                             // this before drawing the hexbox. (Bug 983985)
                             Matrix oldMat;
                             if (aFontParams.passedInvMatrix) {
@@ -2054,17 +2054,19 @@ gfxFont::Measure(gfxTextRun *aTextRun,
             return mNonAAFont->Measure(aTextRun, aStart, aEnd,
                                        TIGHT_HINTED_OUTLINE_EXTENTS,
                                        aRefContext, aSpacing);
         }
     }
 
     const int32_t appUnitsPerDevUnit = aTextRun->GetAppUnitsPerDevUnit();
     // Current position in appunits
-    const gfxFont::Metrics& fontMetrics = GetMetrics();
+    gfxFont::Orientation orientation =
+        aTextRun->IsVertical() ? gfxFont::eVertical : gfxFont::eHorizontal;
+    const gfxFont::Metrics& fontMetrics = GetMetrics(orientation);
 
     RunMetrics metrics;
     metrics.mAscent = fontMetrics.maxAscent*appUnitsPerDevUnit;
     metrics.mDescent = fontMetrics.maxDescent*appUnitsPerDevUnit;
     if (aStart == aEnd) {
         // exit now before we look at aSpacing[0], which is undefined
         metrics.mBoundingBox = gfxRect(0, -metrics.mAscent, 0, metrics.mAscent + metrics.mDescent);
         return metrics;
@@ -2098,16 +2100,17 @@ gfxFont::Measure(gfxTextRun *aTextRun,
                 uint16_t extentsWidth = extents->GetContainedGlyphWidthAppUnits(glyphIndex);
                 if (extentsWidth != gfxGlyphExtents::INVALID_WIDTH &&
                     aBoundingBoxType == LOOSE_INK_EXTENTS) {
                     UnionRange(x, &advanceMin, &advanceMax);
                     UnionRange(x + direction*extentsWidth, &advanceMin, &advanceMax);
                 } else {
                     gfxRect glyphRect;
                     if (!extents->GetTightGlyphExtentsAppUnits(this,
+                            orientation,
                             aRefContext, glyphIndex, &glyphRect)) {
                         glyphRect = gfxRect(0, metrics.mBoundingBox.Y(),
                             advance, metrics.mBoundingBox.Height());
                     }
                     if (isRTL) {
                         glyphRect -= gfxPoint(advance, 0);
                     }
                     glyphRect += gfxPoint(x, 0);
@@ -2125,16 +2128,17 @@ gfxFont::Measure(gfxTextRun *aTextRun,
                 uint32_t j;
                 for (j = 0; j < glyphCount; ++j, ++details) {
                     uint32_t glyphIndex = details->mGlyphID;
                     gfxPoint glyphPt(x + details->mXOffset, details->mYOffset);
                     double advance = details->mAdvance;
                     gfxRect glyphRect;
                     if (glyphData->IsMissing() || !extents ||
                         !extents->GetTightGlyphExtentsAppUnits(this,
+                                orientation,
                                 aRefContext, glyphIndex, &glyphRect)) {
                         // We might have failed to get glyph extents due to
                         // OOM or something
                         glyphRect = gfxRect(0, -metrics.mAscent,
                             advance, metrics.mAscent + metrics.mDescent);
                     }
                     if (isRTL) {
                         glyphRect -= gfxPoint(advance, 0);
@@ -2932,17 +2936,18 @@ gfxFont::GetOrCreateGlyphExtents(int32_t
         // Initialize the extents of a space glyph, assuming that spaces don't
         // render anything!
         glyphExtents->SetContainedGlyphWidthAppUnits(GetSpaceGlyph(), 0);
     }
     return glyphExtents;
 }
 
 void
-gfxFont::SetupGlyphExtents(gfxContext *aContext, uint32_t aGlyphID, bool aNeedTight,
+gfxFont::SetupGlyphExtents(gfxContext *aContext, Orientation aOrientation, 
+                           uint32_t aGlyphID, bool aNeedTight,
                            gfxGlyphExtents *aExtents)
 {
     gfxContextMatrixAutoSaveRestore matrixRestore(aContext);
     aContext->SetMatrix(gfxMatrix());
 
     gfxRect svgBounds;
     if (mFontEntry->TryGetSVGData(this) && mFontEntry->HasSVGGlyph(aGlyphID) &&
         mFontEntry->GetSVGGlyphExtents(aContext, aGlyphID, &svgBounds)) {
@@ -2957,17 +2962,17 @@ gfxFont::SetupGlyphExtents(gfxContext *a
 
     cairo_glyph_t glyph;
     glyph.index = aGlyphID;
     glyph.x = 0;
     glyph.y = 0;
     cairo_text_extents_t extents;
     cairo_glyph_extents(aContext->GetCairo(), &glyph, 1, &extents);
 
-    const Metrics& fontMetrics = GetMetrics();
+    const Metrics& fontMetrics = GetMetrics(aOrientation);
     int32_t appUnitsPerDevUnit = aExtents->GetAppUnitsPerDevUnit();
     if (!aNeedTight && extents.x_bearing >= 0 &&
         extents.y_bearing >= -fontMetrics.maxAscent &&
         extents.height + extents.y_bearing <= fontMetrics.maxDescent) {
         uint32_t appUnitsWidth =
             uint32_t(ceil((extents.x_bearing + extents.width)*appUnitsPerDevUnit));
         if (appUnitsWidth < gfxGlyphExtents::INVALID_WIDTH) {
             aExtents->SetContainedGlyphWidthAppUnits(aGlyphID, uint16_t(appUnitsWidth));
@@ -3363,18 +3368,18 @@ gfxFont::SynthesizeSpaceWidth(uint32_t a
     switch (aCh) {
     case 0x2000:                                 // en quad
     case 0x2002: return GetAdjustedSize() / 2;   // en space
     case 0x2001:                                 // em quad
     case 0x2003: return GetAdjustedSize();       // em space
     case 0x2004: return GetAdjustedSize() / 3;   // three-per-em space
     case 0x2005: return GetAdjustedSize() / 4;   // four-per-em space
     case 0x2006: return GetAdjustedSize() / 6;   // six-per-em space
-    case 0x2007: return GetMetrics().zeroOrAveCharWidth; // figure space
-    case 0x2008: return GetMetrics().spaceWidth; // punctuation space 
+    case 0x2007: return GetMetrics(eHorizontal).zeroOrAveCharWidth; // figure space
+    case 0x2008: return GetMetrics(eHorizontal).spaceWidth; // punctuation space
     case 0x2009: return GetAdjustedSize() / 5;   // thin space
     case 0x200a: return GetAdjustedSize() / 10;  // hair space
     case 0x202f: return GetAdjustedSize() / 5;   // narrow no-break space
     default: return -1.0;
     }
 }
 
 void
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -1437,19 +1437,30 @@ public:
 
         gfxFloat aveCharWidth;
         gfxFloat spaceWidth;
         gfxFloat zeroOrAveCharWidth;  // width of '0', or if there is
                                       // no '0' glyph in this font,
                                       // equal to .aveCharWidth
     };
 
-    const Metrics& GetMetrics()
+    enum Orientation {
+        eHorizontal,
+        eVertical
+    };
+
+    const Metrics& GetMetrics(Orientation aOrientation)
     {
-        return GetHorizontalMetrics();
+        if (aOrientation == eHorizontal) {
+            return GetHorizontalMetrics();
+        }
+        if (!mVerticalMetrics) {
+            mVerticalMetrics = CreateVerticalMetrics();
+        }
+        return *mVerticalMetrics;
     }
 
     /**
      * We let layout specify spacing on either side of any
      * character. We need to specify both before and after
      * spacing so that substring measurement can do the right things.
      * These values are in appunits. They're always an integral number of
      * appunits, but we specify them in floats in case very large spacing
@@ -1557,17 +1568,18 @@ public:
     nsExpirationState *GetExpirationState() { return &mExpirationState; }
 
     // Get the glyphID of a space
     virtual uint32_t GetSpaceGlyph() = 0;
 
     gfxGlyphExtents *GetOrCreateGlyphExtents(int32_t aAppUnitsPerDevUnit);
 
     // You need to call SetupCairoFont on the aCR just before calling this
-    virtual void SetupGlyphExtents(gfxContext *aContext, uint32_t aGlyphID,
+    virtual void SetupGlyphExtents(gfxContext *aContext,
+                                   Orientation aOrientation, uint32_t aGlyphID,
                                    bool aNeedTight, gfxGlyphExtents *aExtents);
 
     // This is called by the default Draw() implementation above.
     virtual bool SetupCairoFont(gfxContext *aContext) = 0;
 
     virtual bool AllowSubpixelAA() { return true; }
 
     bool IsSyntheticBold() { return mApplySyntheticBold; }
--- a/gfx/thebes/gfxGlyphExtents.cpp
+++ b/gfx/thebes/gfxGlyphExtents.cpp
@@ -31,30 +31,32 @@ gfxGlyphExtents::~gfxGlyphExtents()
         mContainedGlyphWidths.SizeOfExcludingThis(&FontCacheMallocSizeOf);
     gGlyphExtentsCount++;
 #endif
     MOZ_COUNT_DTOR(gfxGlyphExtents);
 }
 
 bool
 gfxGlyphExtents::GetTightGlyphExtentsAppUnits(gfxFont *aFont,
+    gfxFont::Orientation aOrientation,
     gfxContext *aContext, uint32_t aGlyphID, gfxRect *aExtents)
 {
     HashEntry *entry = mTightGlyphExtents.GetEntry(aGlyphID);
     if (!entry) {
         if (!aContext) {
             NS_WARNING("Could not get glyph extents (no aContext)");
             return false;
         }
 
         if (aFont->SetupCairoFont(aContext)) {
 #ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
             ++gGlyphExtentsSetupLazyTight;
 #endif
-            aFont->SetupGlyphExtents(aContext, aGlyphID, true, this);
+            aFont->SetupGlyphExtents(aContext, aOrientation, aGlyphID, true,
+                                     this);
             entry = mTightGlyphExtents.GetEntry(aGlyphID);
         }
         if (!entry) {
             NS_WARNING("Could not get glyph extents");
             return false;
         }
     }
 
--- a/gfx/thebes/gfxGlyphExtents.h
+++ b/gfx/thebes/gfxGlyphExtents.h
@@ -1,23 +1,23 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_GLYPHEXTENTS_H
 #define GFX_GLYPHEXTENTS_H
 
+#include "gfxFont.h"
 #include "nsTHashtable.h"
 #include "nsHashKeys.h"
 #include "nsTArray.h"
 #include "mozilla/MemoryReporting.h"
 
 class gfxContext;
-class gfxFont;
 struct gfxRect;
 
 /**
  * This stores glyph bounds information for a particular gfxFont, at
  * a particular appunits-per-dev-pixel ratio (because the compressed glyph
  * width array is stored in appunits).
  * 
  * We store a hashtable from glyph IDs to float bounding rects. For the
@@ -57,18 +57,19 @@ public:
 
     bool IsGlyphKnownWithTightExtents(uint32_t aGlyphID) const {
         return mTightGlyphExtents.GetEntry(aGlyphID) != nullptr;
     }
 
     // Get glyph extents; a rectangle relative to the left baseline origin
     // Returns true on success. Can fail on OOM or when aContext is null
     // and extents were not (successfully) prefetched.
-    bool GetTightGlyphExtentsAppUnits(gfxFont *aFont, gfxContext *aContext,
-            uint32_t aGlyphID, gfxRect *aExtents);
+    bool GetTightGlyphExtentsAppUnits(gfxFont *aFont,
+            gfxFont::Orientation aOrientation,
+            gfxContext *aContext, uint32_t aGlyphID, gfxRect *aExtents);
 
     void SetContainedGlyphWidthAppUnits(uint32_t aGlyphID, uint16_t aWidth) {
         mContainedGlyphWidths.Set(aGlyphID, aWidth);
     }
     void SetTightGlyphExtents(uint32_t aGlyphID, const gfxRect& aExtentsAppUnits);
 
     int32_t GetAppUnitsPerDevUnit() { return mAppUnitsPerDevUnit; }
 
--- a/gfx/thebes/gfxPangoFonts.cpp
+++ b/gfx/thebes/gfxPangoFonts.cpp
@@ -1856,17 +1856,18 @@ gfxPangoFontGroup::GetBaseFontSet()
     nsAutoRef<FcPattern> pattern;
     nsRefPtr<gfxFcFontSet> fontSet =
         MakeFontSet(mPangoLanguage, mSizeAdjustFactor, &pattern);
 
     double size = GetPixelSize(pattern);
     if (size != 0.0 && mStyle.sizeAdjust != 0.0) {
         gfxFcFont *font = fontSet->GetFontAt(0, GetStyle());
         if (font) {
-            const gfxFont::Metrics& metrics = font->GetMetrics();
+            const gfxFont::Metrics& metrics =
+                font->GetMetrics(gfxFont::eHorizontal); // XXX vertical?
 
             // The factor of 0.1 ensures that xHeight is sane so fonts don't
             // become huge.  Strictly ">" ensures that xHeight and emHeight are
             // not both zero.
             if (metrics.xHeight > 0.1 * metrics.emHeight) {
                 mSizeAdjustFactor =
                     mStyle.sizeAdjust * metrics.emHeight / metrics.xHeight;
 
--- a/gfx/thebes/gfxTextRun.cpp
+++ b/gfx/thebes/gfxTextRun.cpp
@@ -1259,18 +1259,22 @@ gfxTextRun::SetSpaceGlyphIfSimple(gfxFon
                                   uint32_t aCharIndex, char16_t aSpaceChar,
                                   uint16_t aOrientation)
 {
     uint32_t spaceGlyph = aFont->GetSpaceGlyph();
     if (!spaceGlyph || !CompressedGlyph::IsSimpleGlyphID(spaceGlyph)) {
         return false;
     }
 
+    gfxFont::Orientation fontOrientation =
+        (aOrientation & gfxTextRunFactory::TEXT_ORIENT_VERTICAL_UPRIGHT) ?
+            gfxFont::eVertical : gfxFont::eHorizontal;
     uint32_t spaceWidthAppUnits =
-        NS_lroundf(aFont->GetMetrics().spaceWidth * mAppUnitsPerDevUnit);
+        NS_lroundf(aFont->GetMetrics(fontOrientation).spaceWidth *
+                   mAppUnitsPerDevUnit);
     if (!CompressedGlyph::IsSimpleAdvance(spaceWidthAppUnits)) {
         return false;
     }
 
     AddGlyphRun(aFont, gfxTextRange::kFontGroup, aCharIndex, false,
                 aOrientation);
     CompressedGlyph g;
     g.SetSimpleGlyph(spaceWidthAppUnits, spaceGlyph);
@@ -1301,33 +1305,36 @@ gfxTextRun::FetchGlyphExtents(gfxContext
         uint32_t end = i + 1 < runCount ?
             mGlyphRuns[i + 1].mCharacterOffset : GetLength();
         bool fontIsSetup = false;
         uint32_t j;
         gfxGlyphExtents *extents = font->GetOrCreateGlyphExtents(mAppUnitsPerDevUnit);
   
         for (j = start; j < end; ++j) {
             const gfxTextRun::CompressedGlyph *glyphData = &charGlyphs[j];
+            gfxFont::Orientation orientation =
+                IsVertical() ? gfxFont::eVertical : gfxFont::eHorizontal;
             if (glyphData->IsSimpleGlyph()) {
                 // If we're in speed mode, don't set up glyph extents here; we'll
                 // just return "optimistic" glyph bounds later
                 if (needsGlyphExtents) {
                     uint32_t glyphIndex = glyphData->GetSimpleGlyph();
                     if (!extents->IsGlyphKnown(glyphIndex)) {
                         if (!fontIsSetup) {
                             if (!font->SetupCairoFont(aRefContext)) {
                                 NS_WARNING("failed to set up font for glyph extents");
                                 break;
                             }
                             fontIsSetup = true;
                         }
 #ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
                         ++gGlyphExtentsSetupEagerSimple;
 #endif
-                        font->SetupGlyphExtents(aRefContext, glyphIndex, false, extents);
+                        font->SetupGlyphExtents(aRefContext, orientation,
+                                                glyphIndex, false, extents);
                     }
                 }
             } else if (!glyphData->IsMissing()) {
                 uint32_t glyphCount = glyphData->GetGlyphCount();
                 if (glyphCount == 0) {
                     continue;
                 }
                 const gfxTextRun::DetailedGlyph *details = GetDetailedGlyphs(j);
@@ -1342,17 +1349,18 @@ gfxTextRun::FetchGlyphExtents(gfxContext
                                 NS_WARNING("failed to set up font for glyph extents");
                                 break;
                             }
                             fontIsSetup = true;
                         }
 #ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
                         ++gGlyphExtentsSetupEagerTight;
 #endif
-                        font->SetupGlyphExtents(aRefContext, glyphIndex, true, extents);
+                        font->SetupGlyphExtents(aRefContext, orientation,
+                                                glyphIndex, true, extents);
                     }
                 }
             }
         }
     }
 }
 
 
@@ -2469,26 +2477,29 @@ gfxFontGroup::GetUnderlineOffset()
         for (uint32_t i = 0; i < len; i++) {
             FamilyFace& ff = mFonts[i];
             if (!ff.IsUserFont() && ff.Family() &&
                 ff.Family()->IsBadUnderlineFamily()) {
                 nsRefPtr<gfxFont> font = GetFontAt(i);
                 if (!font) {
                     continue;
                 }
-                gfxFloat bad = font->GetMetrics().underlineOffset;
+                gfxFloat bad = font->GetMetrics(gfxFont::eHorizontal).
+                                         underlineOffset;
                 gfxFloat first =
-                    GetFirstValidFont()->GetMetrics().underlineOffset;
+                    GetFirstValidFont()->GetMetrics(gfxFont::eHorizontal).
+                                             underlineOffset;
                 mUnderlineOffset = std::min(first, bad);
                 return mUnderlineOffset;
             }
         }
 
         // no bad underline fonts, use the first valid font's metric
-        mUnderlineOffset = GetFirstValidFont()->GetMetrics().underlineOffset;
+        mUnderlineOffset = GetFirstValidFont()->
+            GetMetrics(gfxFont::eHorizontal).underlineOffset;
     }
 
     return mUnderlineOffset;
 }
 
 already_AddRefed<gfxFont>
 gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh,
                               int32_t aRunScript, gfxFont *aPrevMatchedFont,
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -1793,17 +1793,17 @@ GetHyphenTextRun(gfxTextRun* aTextRun, g
 static gfxFont::Metrics
 GetFirstFontMetrics(gfxFontGroup* aFontGroup)
 {
   if (!aFontGroup)
     return gfxFont::Metrics();
   gfxFont* font = aFontGroup->GetFirstValidFont();
   if (!font)
     return gfxFont::Metrics();
-  return font->GetMetrics();
+  return font->GetMetrics(gfxFont::eHorizontal); // XXX vertical
 }
 
 PR_STATIC_ASSERT(NS_STYLE_WHITESPACE_NORMAL == 0);
 PR_STATIC_ASSERT(NS_STYLE_WHITESPACE_PRE == 1);
 PR_STATIC_ASSERT(NS_STYLE_WHITESPACE_NOWRAP == 2);
 PR_STATIC_ASSERT(NS_STYLE_WHITESPACE_PRE_WRAP == 3);
 PR_STATIC_ASSERT(NS_STYLE_WHITESPACE_PRE_LINE == 4);
 PR_STATIC_ASSERT(NS_STYLE_WHITESPACE_PRE_SPACE == 5);
@@ -5667,17 +5667,18 @@ nsTextFrame::PaintTextSelectionDecoratio
       }
     }
     sdptr = sdptr->mNext;
   }
 
   gfxFont* firstFont = aProvider.GetFontGroup()->GetFirstValidFont();
   if (!firstFont)
     return; // OOM
-  gfxFont::Metrics decorationMetrics(firstFont->GetMetrics());
+  gfxFont::Metrics
+    decorationMetrics(firstFont->GetMetrics(gfxFont::eHorizontal)); // XXX vertical?
   decorationMetrics.underlineOffset =
     aProvider.GetFontGroup()->GetUnderlineOffset();
 
   gfxFloat startXOffset = aTextBaselinePt.x - aFramePt.x;
   SelectionIterator iterator(selectedChars, aContentOffset, aContentLength,
                              aProvider, mTextRun, startXOffset);
   gfxFloat xOffset, hyphenWidth;
   uint32_t offset, length;
@@ -6348,17 +6349,18 @@ nsTextFrame::CombineSelectionUnderlineRe
 
   nsRefPtr<nsFontMetrics> fm;
   nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm),
                                         GetFontSizeInflation());
   gfxFontGroup* fontGroup = fm->GetThebesFontGroup();
   gfxFont* firstFont = fontGroup->GetFirstValidFont();
   if (!firstFont)
     return false; // OOM
-  const gfxFont::Metrics& metrics = firstFont->GetMetrics();
+  const gfxFont::Metrics& metrics =
+    firstFont->GetMetrics(gfxFont::eHorizontal); // XXX vertical?
   gfxFloat underlineOffset = fontGroup->GetUnderlineOffset();
   gfxFloat ascent = aPresContext->AppUnitsToGfxUnits(mAscent);
   gfxFloat descentLimit =
     ComputeDescentLimitForSelectionUnderline(aPresContext, this, metrics);
 
   SelectionDetails *details = GetSelectionDetails();
   for (SelectionDetails *sd = details; sd; sd = sd->mNext) {
     if (sd->mStart == sd->mEnd || !(sd->mType & SelectionTypesWithDecorations))
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -495,18 +495,19 @@ static nscoord CalcLengthWith(const nsCS
         GetMetricsFor(aPresContext, aStyleContext, styleFont,
                       aFontSize, aUseUserFontSet);
       return ScaleCoordRound(aValue, float(fm->XHeight()));
     }
     case eCSSUnit_Char: {
       nsRefPtr<nsFontMetrics> fm =
         GetMetricsFor(aPresContext, aStyleContext, styleFont,
                       aFontSize, aUseUserFontSet);
-      gfxFloat zeroWidth = (fm->GetThebesFontGroup()->GetFirstValidFont()
-                            ->GetMetrics().zeroOrAveCharWidth);
+      gfxFloat zeroWidth =
+        fm->GetThebesFontGroup()->GetFirstValidFont()->
+          GetMetrics(gfxFont::eHorizontal).zeroOrAveCharWidth; // XXX vertical?
 
       return ScaleCoordRound(aValue, ceil(aPresContext->AppUnitsPerDevPixel() *
                                           zeroWidth));
     }
     default:
       NS_NOTREACHED("unexpected unit");
       break;
   }