Bug 495455. Always get correct bounding boxes for text rendered with user fonts, since they are likely to be using unusually-sized glyphs. Mac/Windows only at the moment. r=jdaggett
authorRobert O'Callahan <robert@ocallahan.org>
Wed, 24 Jun 2009 21:04:20 +1200
changeset 29527 97f8d01a55853d2ef83bc2162190a00704f34469
parent 29526 59b6f57cd825c28358f9bc71e486161566a3c7eb
child 29528 68e92b91778382cff966d73fac263d1f7ca0e44c
push id7687
push userrocallahan@mozilla.com
push dateWed, 24 Jun 2009 09:31:47 +0000
treeherdermozilla-central@9fd2fb3a0c9f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdaggett
bugs495455
milestone1.9.2a1pre
Bug 495455. Always get correct bounding boxes for text rendered with user fonts, since they are likely to be using unusually-sized glyphs. Mac/Windows only at the moment. r=jdaggett
gfx/thebes/public/gfxFont.h
gfx/thebes/public/gfxWindowsFonts.h
gfx/thebes/src/gfxFont.cpp
gfx/thebes/src/gfxPangoFonts.cpp
gfx/thebes/src/gfxQuartzFontCache.mm
gfx/thebes/src/gfxUserFontSet.cpp
gfx/thebes/src/gfxWindowsFonts.cpp
--- a/gfx/thebes/public/gfxFont.h
+++ b/gfx/thebes/public/gfxFont.h
@@ -155,36 +155,38 @@ struct THEBES_API gfxFontStyle {
 
 class gfxFontEntry {
 public:
     THEBES_INLINE_DECL_REFCOUNTING(gfxFontEntry)
 
     gfxFontEntry(const nsAString& aName) : 
         mName(aName), mItalic(PR_FALSE), mFixedPitch(PR_FALSE),
         mIsProxy(PR_FALSE), mIsValid(PR_TRUE), 
-        mIsBadUnderlineFont(PR_FALSE),
+        mIsBadUnderlineFont(PR_FALSE), mIsUserFont(PR_FALSE),
         mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
         mCmapInitialized(PR_FALSE), mUserFontData(nsnull)
     { }
 
     gfxFontEntry(const gfxFontEntry& aEntry) : 
         mName(aEntry.mName), mItalic(aEntry.mItalic), 
         mFixedPitch(aEntry.mFixedPitch), mIsProxy(aEntry.mIsProxy), 
         mIsValid(aEntry.mIsValid), mIsBadUnderlineFont(aEntry.mIsBadUnderlineFont),
+        mIsUserFont(aEntry.mIsUserFont),
         mWeight(aEntry.mWeight), mCmapInitialized(aEntry.mCmapInitialized),
         mCharacterMap(aEntry.mCharacterMap), mUserFontData(aEntry.mUserFontData)
     { }
 
     virtual ~gfxFontEntry();
 
     // unique name for the face, *not* the family
     const nsString& Name() const { return mName; }
 
     PRInt32 Weight() { return mWeight; }
 
+    PRBool IsUserFont() { return mIsUserFont; }
     PRBool IsFixedPitch() { return mFixedPitch; }
     PRBool IsItalic() { return mItalic; }
     PRBool IsBold() { return mWeight >= 600; } // bold == weights 600 and above
 
     inline PRBool HasCharacter(PRUint32 ch) {
         if (mCharacterMap.test(ch))
             return PR_TRUE;
             
@@ -193,21 +195,20 @@ public:
 
     virtual PRBool TestCharacterMap(PRUint32 aCh);
     virtual nsresult ReadCMAP() { return 0; }
 
     nsString         mName;
 
     PRPackedBool     mItalic      : 1;
     PRPackedBool     mFixedPitch  : 1;
-
     PRPackedBool     mIsProxy     : 1;
     PRPackedBool     mIsValid     : 1;
-
     PRPackedBool     mIsBadUnderlineFont : 1;
+    PRPackedBool     mIsUserFont  : 1;
 
     PRUint16         mWeight;
     PRUint16         mStretch;
 
     PRPackedBool     mCmapInitialized;
     gfxSparseBitSet  mCharacterMap;
     gfxUserFontData* mUserFontData;
 };
--- a/gfx/thebes/public/gfxWindowsFonts.h
+++ b/gfx/thebes/public/gfxWindowsFonts.h
@@ -109,36 +109,36 @@ private:
 
 class FontEntry : public gfxFontEntry
 {
 public:
     FontEntry(const nsAString& aFaceName, gfxWindowsFontType aFontType,
               PRBool aItalic, PRUint16 aWeight, gfxUserFontData *aUserFontData) : 
         gfxFontEntry(aFaceName), mFontType(aFontType),
         mForceGDI(PR_FALSE), mUnknownCMAP(PR_FALSE),
-        mUnicodeFont(PR_FALSE), mSymbolFont(PR_FALSE), mUserFont(PR_FALSE),
+        mUnicodeFont(PR_FALSE), mSymbolFont(PR_FALSE),
         mCharset(0), mUnicodeRanges(0)
     {
         mUserFontData = aUserFontData;
         mItalic = aItalic;
         mWeight = aWeight;
         if (IsType1())
             mForceGDI = PR_TRUE;
+        mIsUserFont = aUserFontData != nsnull;
     }
 
     FontEntry(const FontEntry& aFontEntry) :
         gfxFontEntry(aFontEntry),
         mWindowsFamily(aFontEntry.mWindowsFamily),
         mWindowsPitch(aFontEntry.mWindowsPitch),
         mFontType(aFontEntry.mFontType),
         mForceGDI(aFontEntry.mForceGDI),
         mUnknownCMAP(aFontEntry.mUnknownCMAP),
         mUnicodeFont(aFontEntry.mUnicodeFont),
         mSymbolFont(aFontEntry.mSymbolFont),
-        mUserFont(aFontEntry.mUserFont),
         mCharset(aFontEntry.mCharset),
         mUnicodeRanges(aFontEntry.mUnicodeRanges)
     {
 
     }
     static void InitializeFontEmbeddingProcs();
 
     // create a font entry from downloaded font data
@@ -288,17 +288,16 @@ public:
     PRUint8 mWindowsFamily;
     PRUint8 mWindowsPitch;
 
     gfxWindowsFontType mFontType;
     PRPackedBool mForceGDI    : 1;
     PRPackedBool mUnknownCMAP : 1;
     PRPackedBool mUnicodeFont : 1;
     PRPackedBool mSymbolFont  : 1;
-    PRPackedBool mUserFont    : 1;
 
     std::bitset<256> mCharset;
     std::bitset<128> mUnicodeRanges;
 };
 
 /**********************************************************************
  *
  * class gfxWindowsFont
--- a/gfx/thebes/src/gfxFont.cpp
+++ b/gfx/thebes/src/gfxFont.cpp
@@ -488,20 +488,38 @@ GetAdvanceForGlyphs(gfxTextRun *aTextRun
 
 static void
 UnionRange(gfxFloat aX, gfxFloat* aDestMin, gfxFloat* aDestMax)
 {
     *aDestMin = PR_MIN(*aDestMin, aX);
     *aDestMax = PR_MAX(*aDestMax, aX);
 }
 
+// We get precise glyph extents if the textrun creator requested them, or
+// if the font is a user font --- in which case the author may be relying
+// on overflowing glyphs.
+static PRBool
+NeedsGlyphExtents(gfxFont *aFont, gfxTextRun *aTextRun)
+{
+    return (aTextRun->GetFlags() & gfxTextRunFactory::TEXT_NEED_BOUNDING_BOX) ||
+        aFont->GetFontEntry()->IsUserFont();
+}
+
 static PRBool
 NeedsGlyphExtents(gfxTextRun *aTextRun)
 {
-    return (aTextRun->GetFlags() & gfxTextRunFactory::TEXT_NEED_BOUNDING_BOX) != 0;
+    if (aTextRun->GetFlags() & gfxTextRunFactory::TEXT_NEED_BOUNDING_BOX)
+        return PR_TRUE;
+    PRUint32 numRuns;
+    const gfxTextRun::GlyphRun *glyphRuns = aTextRun->GetGlyphRuns(&numRuns);
+    for (PRUint32 i = 0; i < numRuns; ++i) {
+        if (glyphRuns[i].mFont->GetFontEntry()->IsUserFont())
+            return PR_TRUE;
+    }
+    return PR_FALSE;
 }
 
 gfxFont::RunMetrics
 gfxFont::Measure(gfxTextRun *aTextRun,
                  PRUint32 aStart, PRUint32 aEnd,
                  BoundingBoxType aBoundingBoxType, gfxContext *aRefContext,
                  Spacing *aSpacing)
 {
@@ -517,34 +535,35 @@ gfxFont::Measure(gfxTextRun *aTextRun,
         metrics.mBoundingBox = gfxRect(0, -metrics.mAscent, 0, metrics.mAscent + metrics.mDescent);
         return metrics;
     }
 
     gfxFloat advanceMin = 0, advanceMax = 0;
     const gfxTextRun::CompressedGlyph *charGlyphs = aTextRun->GetCharacterGlyphs();
     PRBool isRTL = aTextRun->IsRightToLeft();
     double direction = aTextRun->GetDirection();
+    PRBool needsGlyphExtents = NeedsGlyphExtents(this, aTextRun);
     gfxGlyphExtents *extents =
         (aBoundingBoxType == LOOSE_INK_EXTENTS &&
-            !NeedsGlyphExtents(aTextRun) &&
+            !needsGlyphExtents &&
             !aTextRun->HasDetailedGlyphs()) ? nsnull
         : GetOrCreateGlyphExtents(aTextRun->GetAppUnitsPerDevUnit());
     double x = 0;
     if (aSpacing) {
         x += direction*aSpacing[0].mBefore;
     }
     PRUint32 i;
     for (i = aStart; i < aEnd; ++i) {
         const gfxTextRun::CompressedGlyph *glyphData = &charGlyphs[i];
         if (glyphData->IsSimpleGlyph()) {
             double advance = glyphData->GetSimpleAdvance();
             // Only get the real glyph horizontal extent if we were asked
             // for the tight bounding box or we're in quality mode
-            if ((aBoundingBoxType != LOOSE_INK_EXTENTS ||
-                 NeedsGlyphExtents(aTextRun)) && extents) {
+            if ((aBoundingBoxType != LOOSE_INK_EXTENTS || needsGlyphExtents) &&
+                extents) {
                 PRUint32 glyphIndex = glyphData->GetSimpleGlyph();
                 PRUint16 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;
@@ -2488,17 +2507,18 @@ gfxTextRun::SetSpaceGlyph(gfxFont *aFont
     CompressedGlyph g;
     g.SetSimpleGlyph(spaceWidthAppUnits, spaceGlyph);
     SetSimpleGlyph(aCharIndex, g);
 }
 
 void
 gfxTextRun::FetchGlyphExtents(gfxContext *aRefContext)
 {
-    if (!NeedsGlyphExtents(this) && !mDetailedGlyphs)
+    PRBool needsGlyphExtents = NeedsGlyphExtents(this);
+    if (!needsGlyphExtents && !mDetailedGlyphs)
         return;
 
     PRUint32 i;
     CompressedGlyph *charGlyphs = mCharacterGlyphs;
     for (i = 0; i < mGlyphRuns.Length(); ++i) {
         gfxFont *font = mGlyphRuns[i].mFont;
         PRUint32 start = mGlyphRuns[i].mCharacterOffset;
         PRUint32 end = i + 1 < mGlyphRuns.Length()
@@ -2507,17 +2527,17 @@ gfxTextRun::FetchGlyphExtents(gfxContext
         PRUint32 j;
         gfxGlyphExtents *extents = font->GetOrCreateGlyphExtents(mAppUnitsPerDevUnit);
   
         for (j = start; j < end; ++j) {
             const gfxTextRun::CompressedGlyph *glyphData = &charGlyphs[j];
             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(this)) {
+                if (needsGlyphExtents) {
                     PRUint32 glyphIndex = glyphData->GetSimpleGlyph();
                     if (!extents->IsGlyphKnown(glyphIndex)) {
                         if (!fontIsSetup) {
                             font->SetupCairoFont(aRefContext);
                              fontIsSetup = PR_TRUE;
                         }
 #ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
                         ++gGlyphExtentsSetupEagerSimple;
--- a/gfx/thebes/src/gfxPangoFonts.cpp
+++ b/gfx/thebes/src/gfxPangoFonts.cpp
@@ -187,16 +187,17 @@ public:
 protected:
     gfxFcFontEntry(const gfxProxyFontEntry &aProxyEntry)
         // store the family name
         : gfxFontEntry(aProxyEntry.mFamily->Name())
     {
         mItalic = aProxyEntry.mItalic;
         mWeight = aProxyEntry.mWeight;
         mStretch = aProxyEntry.mStretch;
+        mIsUserFont = PR_TRUE;
     }
 
     // Helper function to change a pattern so that it matches the CSS style
     // descriptors and so gets properly sorted in font selection.  This also
     // avoids synthetic style effects being added by the renderer when the
     // style of the font itself does not match the descriptor provided by the
     // author.
     void AdjustPatternToCSS(FcPattern *aPattern);
--- a/gfx/thebes/src/gfxQuartzFontCache.mm
+++ b/gfx/thebes/src/gfxQuartzFontCache.mm
@@ -157,17 +157,18 @@ MacOSFontEntry::MacOSFontEntry(const nsA
 {
     // xxx - stretch is basically ignored for now
 
     mUserFontData = aUserFontData;
     mWeight = aWeight;
     mStretch = aStretch;
     mFixedPitch = PR_FALSE; // xxx - do we need this for downloaded fonts?
     mItalic = (aItalicStyle & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0;
-    
+    mIsUserFont = aUserFontData != nsnull;
+
     mTraits = (mItalic ? NSItalicFontMask : NSUnitalicFontMask) |
               (mFixedPitch ? NSFixedPitchFontMask : 0) |
               (mWeight >= 600 ? NSBoldFontMask : NSUnboldFontMask);
 }
 
 ATSFontRef
 MacOSFontEntry::GetFontRef() 
 {
--- a/gfx/thebes/src/gfxUserFontSet.cpp
+++ b/gfx/thebes/src/gfxUserFontSet.cpp
@@ -67,16 +67,17 @@ gfxProxyFontEntry::gfxProxyFontEntry(con
       mFamily(aFamily)
 {
     mIsProxy = PR_TRUE;
     mSrcList = aFontFaceSrcList;
     mSrcIndex = 0;
     mWeight = aWeight;
     mStretch = aStretch;
     mItalic = (aItalicStyle & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0;
+    mIsUserFont = PR_TRUE;
 }
 
 gfxProxyFontEntry::~gfxProxyFontEntry()
 {
 
 }
 
 
--- a/gfx/thebes/src/gfxWindowsFonts.cpp
+++ b/gfx/thebes/src/gfxWindowsFonts.cpp
@@ -578,17 +578,16 @@ FontEntry::LoadFont(const gfxProxyFontEn
     FontEntry *fe = FontEntry::CreateFontEntry(uniqueName, 
         gfxWindowsFontType(isCFF ? GFX_FONT_TYPE_PS_OPENTYPE : GFX_FONT_TYPE_TRUETYPE) /*type*/, 
         PRUint32(aProxyEntry.mItalic ? FONT_STYLE_ITALIC : FONT_STYLE_NORMAL), 
         w, winUserFontData);
 
     if (!fe)
         return fe;
 
-    fe->mUserFont = PR_TRUE;
     if (isCFF)
         fe->mForceGDI = PR_TRUE;
  
     return fe;
 }
 
 class AutoReleaseDC {
 public:
@@ -730,17 +729,17 @@ FontEntry::LoadLocalFont(const gfxProxyF
     FontEntry *fe = FontEntry::CreateFontEntry(aFullname, 
         gfxWindowsFontType(isCFF ? GFX_FONT_TYPE_PS_OPENTYPE : GFX_FONT_TYPE_TRUETYPE) /*type*/, 
         PRUint32(aProxyEntry.mItalic ? FONT_STYLE_ITALIC : FONT_STYLE_NORMAL), 
         w, nsnull);
         
     if (!fe)
         return fe;
 
-    fe->mUserFont = PR_TRUE;
+    fe->mIsUserFont = PR_TRUE;
     return fe;
 }
 
 void
 FontEntry::FillLogFont(LOGFONTW *aLogFont, const nsAString& aName,
                        gfxWindowsFontType aFontType, PRBool aItalic,
                        PRUint16 aWeight, gfxFloat aSize)
 {
@@ -1059,17 +1058,17 @@ gfxWindowsFont::FillLogFont(gfxFloat aSi
     FontEntry *fe = GetFontEntry();
     PRBool isItalic;
 
     isItalic = (GetStyle()->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE));
     PRUint16 weight = fe->Weight();
 
     // if user font, disable italics/bold if defined to be italics/bold face
     // this avoids unwanted synthetic italics/bold
-    if (fe->mUserFont) {
+    if (fe->mIsUserFont) {
         if (fe->IsItalic())
             isItalic = PR_FALSE; // avoid synthetic italic
         if (fe->IsBold())
             weight = 400; // avoid synthetic bold
     }
 
     FontEntry::FillLogFont(&mLogFont, fe->Name(),  fe->mFontType, isItalic, 
                            weight, aSize);