bug 703100 - pt 2.5 - adapt Android/FT2 font code to work with gfxShapedWord caches. r=roc
authorJonathan Kew <jfkthame@gmail.com>
Tue, 06 Dec 2011 12:39:19 +0000
changeset 85102 e053ff76503dc6f96de659d3bab88de46075ea48
parent 85101 561d067101078fa0b209de589c5d1ea57ac7e140
child 85103 102dff1e0bb54afa509dccbda5700f8db3673174
push id805
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 18:17:35 +0000
treeherdermozilla-aurora@6fb3bf232436 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs703100
milestone12.0a1
bug 703100 - pt 2.5 - adapt Android/FT2 font code to work with gfxShapedWord caches. r=roc
gfx/thebes/gfxFT2Fonts.cpp
gfx/thebes/gfxFT2Fonts.h
gfx/thebes/gfxFont.cpp
gfx/thebes/gfxFont.h
--- a/gfx/thebes/gfxFT2Fonts.cpp
+++ b/gfx/thebes/gfxFT2Fonts.cpp
@@ -420,79 +420,78 @@ gfxFT2FontGroup::WhichSystemFontSupports
 
 #endif // !ANDROID
 
 /**
  * gfxFT2Font
  */
 
 bool
-gfxFT2Font::InitTextRun(gfxContext *aContext,
-                        gfxTextRun *aTextRun,
-                        const PRUnichar *aString,
-                        PRUint32 aRunStart,
-                        PRUint32 aRunLength,
-                        PRInt32 aRunScript,
-                        bool aPreferPlatformShaping)
+gfxFT2Font::ShapeWord(gfxContext *aContext,
+                      gfxShapedWord *aShapedWord,
+                      const PRUnichar *aString,
+                      bool aPreferPlatformShaping)
 {
     bool ok = false;
 
 #ifdef MOZ_GRAPHITE
     if (FontCanSupportGraphite()) {
         if (gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
             if (!mGraphiteShaper) {
                 mGraphiteShaper = new gfxGraphiteShaper(this);
             }
-            ok = mGraphiteShaper->InitTextRun(aContext, aTextRun, aString,
-                                              aRunStart, aRunLength,
-                                              aRunScript);
+            ok = mGraphiteShaper->ShapeWord(aContext, aShapedWord, aString);
         }
     }
 #endif
 
-    if (!ok && gfxPlatform::GetPlatform()->UseHarfBuzzForScript(aRunScript)) {
+    if (!ok && gfxPlatform::GetPlatform()->UseHarfBuzzForScript(aShapedWord->Script())) {
         if (!mHarfBuzzShaper) {
             gfxFT2LockedFace face(this);
             mFUnitsConvFactor = face.XScale();
 
             mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
         }
-        ok = mHarfBuzzShaper->InitTextRun(aContext, aTextRun, aString,
-                                          aRunStart, aRunLength, aRunScript);
+        ok = mHarfBuzzShaper->ShapeWord(aContext, aShapedWord, aString);
     }
 
     if (!ok) {
-        AddRange(aTextRun, aString, aRunStart, aRunLength);
+        AddRange(aShapedWord, aString);
     }
 
-    aTextRun->AdjustAdvancesForSyntheticBold(aContext, aRunStart, aRunLength);
+    if (IsSyntheticBold()) {
+        float synBoldOffset =
+            GetSyntheticBoldOffset() * CalcXScale(aContext);
+        aShapedWord->AdjustAdvancesForSyntheticBold(synBoldOffset);
+    }
 
     return true;
 }
 
 void
-gfxFT2Font::AddRange(gfxTextRun *aTextRun, const PRUnichar *str, PRUint32 offset, PRUint32 len)
+gfxFT2Font::AddRange(gfxShapedWord *aShapedWord, const PRUnichar *str)
 {
-    const PRUint32 appUnitsPerDevUnit = aTextRun->GetAppUnitsPerDevUnit();
+    const PRUint32 appUnitsPerDevUnit = aShapedWord->AppUnitsPerDevUnit();
     // we'll pass this in/figure it out dynamically, but at this point there can be only one face.
     gfxFT2LockedFace faceLock(this);
     FT_Face face = faceLock.get();
 
-    gfxTextRun::CompressedGlyph g;
+    gfxShapedWord::CompressedGlyph g;
 
     const gfxFT2Font::CachedGlyphData *cgd = nsnull, *cgdNext = nsnull;
 
     FT_UInt spaceGlyph = GetSpaceGlyph();
 
+    PRUint32 len = aShapedWord->Length();
     for (PRUint32 i = 0; i < len; i++) {
-        PRUint32 ch = str[offset + i];
+        PRUnichar ch = str[i];
 
         if (ch == 0) {
             // treat this null byte as a missing glyph, don't create a glyph for it
-            aTextRun->SetMissingGlyph(offset + i, 0);
+            aShapedWord->SetMissingGlyph(i, 0, this);
             continue;
         }
 
         NS_ASSERTION(!gfxFontGroup::IsInvalidChar(ch), "Invalid char detected");
 
         if (cgdNext) {
             cgd = cgdNext;
             cgdNext = nsnull;
@@ -503,22 +502,22 @@ gfxFT2Font::AddRange(gfxTextRun *aTextRu
         FT_UInt gid = cgd->glyphIndex;
         PRInt32 advance = 0;
 
         if (gid == 0) {
             advance = -1; // trigger the missing glyphs case below
         } else {
             // find next character and its glyph -- in case they exist
             // and exist in the current font face -- to compute kerning
-            PRUint32 chNext = 0;
+            PRUnichar chNext = 0;
             FT_UInt gidNext = 0;
             FT_Pos lsbDeltaNext = 0;
 
             if (FT_HAS_KERNING(face) && i + 1 < len) {
-                chNext = str[offset + i + 1];
+                chNext = str[i + 1];
                 if (chNext != 0) {
                     cgdNext = GetGlyphDataForChar(chNext);
                     gidNext = cgdNext->glyphIndex;
                     if (gidNext && gidNext != spaceGlyph)
                         lsbDeltaNext = cgdNext->lsbDelta;
                 }
             }
 
@@ -536,37 +535,33 @@ gfxFT2Font::AddRange(gfxTextRun *aTextRu
                 }
             }
 
             // convert 26.6 fixed point to app units
             // round rather than truncate to nearest pixel
             // because these advances are often scaled
             advance = ((advance * appUnitsPerDevUnit + 32) >> 6);
         }
-#ifdef DEBUG_thebes_2
-        printf(" gid=%d, advance=%d (%s)\n", gid, advance,
-               NS_LossyConvertUTF16toASCII(font->GetName()).get());
-#endif
 
         if (advance >= 0 &&
-            gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance) &&
-            gfxTextRun::CompressedGlyph::IsSimpleGlyphID(gid)) {
-            aTextRun->SetSimpleGlyph(offset + i, g.SetSimpleGlyph(advance, gid));
+            gfxShapedWord::CompressedGlyph::IsSimpleAdvance(advance) &&
+            gfxShapedWord::CompressedGlyph::IsSimpleGlyphID(gid)) {
+            aShapedWord->SetSimpleGlyph(i, g.SetSimpleGlyph(advance, gid));
         } else if (gid == 0) {
             // gid = 0 only happens when the glyph is missing from the font
-            aTextRun->SetMissingGlyph(offset + i, ch);
+            aShapedWord->SetMissingGlyph(i, ch, this);
         } else {
             gfxTextRun::DetailedGlyph details;
             details.mGlyphID = gid;
             NS_ASSERTION(details.mGlyphID == gid, "Seriously weird glyph ID detected!");
             details.mAdvance = advance;
             details.mXOffset = 0;
             details.mYOffset = 0;
-            g.SetComplex(aTextRun->IsClusterStart(offset + i), true, 1);
-            aTextRun->SetGlyphs(offset + i, g, &details);
+            g.SetComplex(aShapedWord->IsClusterStart(i), true, 1);
+            aShapedWord->SetGlyphs(i, g, &details);
         }
     }
 }
 
 gfxFT2Font::gfxFT2Font(cairo_scaled_font_t *aCairoFont,
                        FT2FontEntry *aFontEntry,
                        const gfxFontStyle *aFontStyle,
                        bool aNeedsBold)
--- a/gfx/thebes/gfxFT2Fonts.h
+++ b/gfx/thebes/gfxFT2Fonts.h
@@ -92,27 +92,24 @@ public: // new functions
             // this is a new entry, fill it
             FillGlyphDataForChar(ch, &entry->mData);
         }
 
         return &entry->mData;
     }
 
 protected:
-    virtual bool InitTextRun(gfxContext *aContext,
-                               gfxTextRun *aTextRun,
-                               const PRUnichar *aString,
-                               PRUint32 aRunStart,
-                               PRUint32 aRunLength,
-                               PRInt32 aRunScript,
-                               bool aPreferPlatformShaping = false);
+    virtual bool ShapeWord(gfxContext *aContext,
+                           gfxShapedWord *aShapedWord,
+                           const PRUnichar *aString,
+                           bool aPreferPlatformShaping = false);
 
     void FillGlyphDataForChar(PRUint32 ch, CachedGlyphData *gd);
 
-    void AddRange(gfxTextRun *aTextRun, const PRUnichar *str, PRUint32 offset, PRUint32 len);
+    void AddRange(gfxShapedWord *aShapedWord, const PRUnichar *str);
 
     typedef nsBaseHashtableET<nsUint32HashKey, CachedGlyphData> CharGlyphMapEntryType;
     typedef nsTHashtable<CharGlyphMapEntryType> CharGlyphMap;
     CharGlyphMap mCharGlyphCache;
 };
 
 #ifndef ANDROID // not needed on Android, uses the standard gfxFontGroup directly
 class THEBES_API gfxFT2FontGroup : public gfxFontGroup {
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -1192,18 +1192,18 @@ struct GlyphBufferAzure {
 };
 
 // Bug 674909. When synthetic bolding text by drawing twice, need to
 // render using a pixel offset in device pixels, otherwise text
 // doesn't appear bolded, it appears as if a bad text shadow exists
 // when a non-identity transform exists.  Use an offset factor so that
 // the second draw occurs at a constant offset in device pixels.
 
-static double
-CalcXScale(gfxContext *aContext)
+double
+gfxFont::CalcXScale(gfxContext *aContext)
 {
     // determine magnitude of a 1px x offset in device space
     gfxSize t = aContext->UserToDevice(gfxSize(1.0, 0.0));
     if (t.width == 1.0 && t.height == 0.0) {
         // short-circuit the most common case to avoid sqrt() and division
         return 1.0;
     }
 
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -1518,16 +1518,25 @@ protected:
 
     // Helper to calculate various derived metrics from the results of
     // InitMetricsFromSfntTables or equivalent platform code
     void CalculateDerivedMetrics(Metrics& aMetrics);
 
     // some fonts have bad metrics, this method sanitize them.
     // if this font has bad underline offset, aIsBadUnderlineFont should be true.
     void SanitizeMetrics(gfxFont::Metrics *aMetrics, bool aIsBadUnderlineFont);
+
+    // Bug 674909. When synthetic bolding text by drawing twice, need to
+    // render using a pixel offset in device pixels, otherwise text
+    // doesn't appear bolded, it appears as if a bad text shadow exists
+    // when a non-identity transform exists.  Use an offset factor so that
+    // the second draw occurs at a constant offset in device pixels.
+    // This helper calculates the scale factor we need to apply to the
+    // synthetic-bold offset.
+    static double CalcXScale(gfxContext *aContext);
 };
 
 // proportion of ascent used for x-height, if unable to read value from font
 #define DEFAULT_XHEIGHT_FACTOR 0.56f
 
 /*
  * gfxShapedWord stores a list of zero or more glyphs for each character. For each
  * glyph we store the glyph ID, the advance, and possibly an xoffset and yoffset.