From e72058c4cc5a229897bd123b2b25695566f004ca Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Thu, 7 Oct 2010 08:59:16 +0100 Subject: [PATCH] bug 580863 part 2 - scale glyph metrics correctly when initializing CFF fonts on OS X 10.6. r=jdaggett a=blocking-betaN --- gfx/thebes/gfxMacFont.cpp | 31 +++++++++++++++++++++------- gfx/thebes/gfxMacFont.h | 6 +++--- gfx/thebes/gfxMacPlatformFontList.h | 4 ++++ gfx/thebes/gfxMacPlatformFontList.mm | 27 ++++++++++++++++++++++-- 4 files changed, 56 insertions(+), 12 deletions(-) diff --git a/gfx/thebes/gfxMacFont.cpp b/gfx/thebes/gfxMacFont.cpp index 1a614bda912..7a9936d2694 100644 --- a/gfx/thebes/gfxMacFont.cpp +++ b/gfx/thebes/gfxMacFont.cpp @@ -268,6 +268,16 @@ gfxMacFont::InitMetrics() mAdjustedSize = PR_MAX(mStyle.size, 1.0f); mFUnitsConvFactor = mAdjustedSize / upem; + // For CFF fonts, when scaling values read from CGFont* APIs, we need to + // use CG's idea of unitsPerEm, which may differ from the "true" value in + // the head table of the font (see bug 580863) + gfxFloat cgConvFactor; + if (static_cast(mFontEntry.get())->IsCFF()) { + cgConvFactor = mAdjustedSize / ::CGFontGetUnitsPerEm(mCGFont); + } else { + cgConvFactor = mFUnitsConvFactor; + } + // Try to read 'sfnt' metrics; for local, non-sfnt fonts ONLY, fall back to // platform APIs. The InitMetrics...() functions will set mIsValid on success. if (!InitMetricsFromSfntTables(mMetrics) && @@ -279,7 +289,7 @@ gfxMacFont::InitMetrics() } if (mMetrics.xHeight == 0.0) { - mMetrics.xHeight = ::CGFontGetXHeight(mCGFont) * mFUnitsConvFactor; + mMetrics.xHeight = ::CGFontGetXHeight(mCGFont) * cgConvFactor; } if (mStyle.sizeAdjust != 0.0 && mStyle.size > 0.0 && @@ -288,6 +298,11 @@ gfxMacFont::InitMetrics() gfxFloat aspect = mMetrics.xHeight / mStyle.size; mAdjustedSize = mStyle.GetAdjustedSize(aspect); mFUnitsConvFactor = mAdjustedSize / upem; + if (static_cast(mFontEntry.get())->IsCFF()) { + cgConvFactor = mAdjustedSize / ::CGFontGetUnitsPerEm(mCGFont); + } else { + cgConvFactor = mFUnitsConvFactor; + } mMetrics.xHeight = 0.0; if (!InitMetricsFromSfntTables(mMetrics) && (!mFontEntry->IsUserFont() || mFontEntry->IsLocalUserFont())) { @@ -299,7 +314,7 @@ gfxMacFont::InitMetrics() return; } if (mMetrics.xHeight == 0.0) { - mMetrics.xHeight = ::CGFontGetXHeight(mCGFont) * mFUnitsConvFactor; + mMetrics.xHeight = ::CGFontGetXHeight(mCGFont) * cgConvFactor; } } @@ -317,7 +332,8 @@ gfxMacFont::InitMetrics() PRUint32 glyphID; if (mMetrics.aveCharWidth <= 0) { - mMetrics.aveCharWidth = GetCharWidth(cmap, 'x', &glyphID); + mMetrics.aveCharWidth = GetCharWidth(cmap, 'x', &glyphID, + cgConvFactor); if (glyphID == 0) { // we didn't find 'x', so use maxAdvance rather than zero mMetrics.aveCharWidth = mMetrics.maxAdvance; @@ -326,14 +342,15 @@ gfxMacFont::InitMetrics() mMetrics.aveCharWidth += mSyntheticBoldOffset; mMetrics.maxAdvance += mSyntheticBoldOffset; - mMetrics.spaceWidth = GetCharWidth(cmap, ' ', &glyphID); + mMetrics.spaceWidth = GetCharWidth(cmap, ' ', &glyphID, cgConvFactor); if (glyphID == 0) { // no space glyph?! mMetrics.spaceWidth = mMetrics.aveCharWidth; } mSpaceGlyph = glyphID; - mMetrics.zeroOrAveCharWidth = GetCharWidth(cmap, '0', &glyphID); + mMetrics.zeroOrAveCharWidth = GetCharWidth(cmap, '0', &glyphID, + cgConvFactor); if (glyphID == 0) { mMetrics.zeroOrAveCharWidth = mMetrics.aveCharWidth; } @@ -360,7 +377,7 @@ gfxMacFont::InitMetrics() gfxFloat gfxMacFont::GetCharWidth(CFDataRef aCmap, PRUnichar aUniChar, - PRUint32 *aGlyphID) + PRUint32 *aGlyphID, gfxFloat aConvFactor) { CGGlyph glyph = 0; @@ -377,7 +394,7 @@ gfxMacFont::GetCharWidth(CFDataRef aCmap, PRUnichar aUniChar, if (glyph) { int advance; if (::CGFontGetGlyphAdvances(mCGFont, &glyph, 1, &advance)) { - return advance * mFUnitsConvFactor; + return advance * aConvFactor; } } diff --git a/gfx/thebes/gfxMacFont.h b/gfx/thebes/gfxMacFont.h index cf9703650d5..b1320c980f1 100644 --- a/gfx/thebes/gfxMacFont.h +++ b/gfx/thebes/gfxMacFont.h @@ -85,10 +85,10 @@ protected: void InitMetrics(); void InitMetricsFromATSMetrics(); - // Get width and glyph ID for a character; requires that - // mFUnitsConvFactor has been set before this is called + // Get width and glyph ID for a character; uses aConvFactor + // to convert font units as returned by CG to actual dimensions gfxFloat GetCharWidth(CFDataRef aCmap, PRUnichar aUniChar, - PRUint32 *aGlyphID); + PRUint32 *aGlyphID, gfxFloat aConvFactor); static void DestroyBlobFunc(void* aUserData); diff --git a/gfx/thebes/gfxMacPlatformFontList.h b/gfx/thebes/gfxMacPlatformFontList.h index b16148847fa..51f91581750 100644 --- a/gfx/thebes/gfxMacPlatformFontList.h +++ b/gfx/thebes/gfxMacPlatformFontList.h @@ -70,6 +70,8 @@ public: virtual nsresult GetFontTable(PRUint32 aTableTag, nsTArray& aBuffer); + PRBool IsCFF(); + protected: // for use with data fonts MacOSFontEntry(const nsAString& aPostscriptName, ATSFontRef aFontRef, @@ -81,6 +83,8 @@ protected: ATSFontRef mATSFontRef; PRPackedBool mATSFontRefInitialized; PRPackedBool mRequiresAAT; + PRPackedBool mIsCFF; + PRPackedBool mIsCFFInitialized; }; class gfxMacPlatformFontList : public gfxPlatformFontList { diff --git a/gfx/thebes/gfxMacPlatformFontList.mm b/gfx/thebes/gfxMacPlatformFontList.mm index 0d6609ee792..dc1800143a6 100644 --- a/gfx/thebes/gfxMacPlatformFontList.mm +++ b/gfx/thebes/gfxMacPlatformFontList.mm @@ -137,7 +137,9 @@ MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName, : gfxFontEntry(aPostscriptName, aFamily, aIsStandardFace), mATSFontRef(0), mATSFontRefInitialized(PR_FALSE), - mRequiresAAT(PR_FALSE) + mRequiresAAT(PR_FALSE), + mIsCFF(PR_FALSE), + mIsCFFInitialized(PR_FALSE) { mWeight = aWeight; } @@ -148,7 +150,8 @@ MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName, ATSFontRef aFon : gfxFontEntry(aPostscriptName), mATSFontRef(aFontRef), mATSFontRefInitialized(PR_TRUE), - mRequiresAAT(PR_FALSE) + mRequiresAAT(PR_FALSE), + mIsCFFInitialized(PR_FALSE) { // xxx - stretch is basically ignored for now @@ -313,6 +316,26 @@ MacOSFontEntry::CreateFontInstance(const gfxFontStyle *aFontStyle, PRBool aNeeds return new gfxMacFont(this, aFontStyle, aNeedsBold); } +PRBool +MacOSFontEntry::IsCFF() +{ + if (!mIsCFFInitialized) { + mIsCFFInitialized = PR_TRUE; + ATSFontRef fontRef = GetFontRef(); + if (fontRef != (ATSFontRef)kATSUInvalidFontID) { + ByteCount dataLength; + OSStatus status = ::ATSFontGetTable(fontRef, + TRUETYPE_TAG('C','F','F',' '), + 0, 0, 0, &dataLength); + if (status == noErr && dataLength > 0) { + mIsCFF = PR_TRUE; + } + } + } + + return mIsCFF; +} + /* gfxMacFontFamily */ #pragma mark-