bug 33032 - synthesize various Unicode space characters rather than showing missing glyphs. r=jdaggett
authorJonathan Kew <jfkthame@gmail.com>
Mon, 02 May 2011 10:01:55 +0100
changeset 68839 9b312736f4ca324c33bae7788a0dc001b3e0dea2
parent 68838 b7d79acc2930633c3379d8f956aa13a9eb308f63
child 68840 24966d9165554515f2b0a1118af80e8b320b99d6
push idunknown
push userunknown
push dateunknown
reviewersjdaggett
bugs33032
milestone6.0a1
first release with
nightly win64
9b312736f4ca / 6.0a1 / 20110502030213 / files
nightly linux32
nightly linux64
nightly mac
nightly win32
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly win64
bug 33032 - synthesize various Unicode space characters rather than showing missing glyphs. r=jdaggett
gfx/thebes/gfxFont.cpp
gfx/thebes/gfxFont.h
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -1812,16 +1812,39 @@ gfxFont::SanitizeMetrics(gfxFont::Metric
     }
 
     // If overline is larger than the ascent, the line should be resized.
     if (aMetrics->underlineSize > aMetrics->maxAscent) {
         aMetrics->underlineSize = aMetrics->maxAscent;
     }
 }
 
+gfxFloat
+gfxFont::SynthesizeSpaceWidth(PRUint32 aCh)
+{
+    // return an appropriate width for various Unicode space characters
+    // that we "fake" if they're not actually present in the font;
+    // returns negative value if the char is not a known space.
+    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 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;
+    }
+}
+
 gfxGlyphExtents::~gfxGlyphExtents()
 {
 #ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
     gGlyphExtentsWidthsTotalSize += mContainedGlyphWidths.ComputeSize();
     gGlyphExtentsCount++;
 #endif
     MOZ_COUNT_DTOR(gfxGlyphExtents);
 }
@@ -2468,25 +2491,46 @@ gfxFontGroup::InitScriptRun(gfxContext *
                                                   aRunScript)) {
                 // glyph layout failed! treat as missing glyphs
                 matchedFont = nsnull;
             }
         }
         if (!matchedFont) {
             for (PRUint32 index = runStart; index < runStart + matchedLength; index++) {
                 // Record the char code so we can draw a box with the Unicode value
-                if (NS_IS_HIGH_SURROGATE(aString[index]) &&
+                PRUint32 ch = aString[index];
+                if (NS_IS_HIGH_SURROGATE(ch) &&
                     index + 1 < aScriptRunEnd &&
                     NS_IS_LOW_SURROGATE(aString[index+1])) {
                     aTextRun->SetMissingGlyph(index,
                                               SURROGATE_TO_UCS4(aString[index],
                                                                 aString[index+1]));
                     index++;
                 } else {
-                    aTextRun->SetMissingGlyph(index, aString[index]);
+                    gfxFloat wid = mainFont->SynthesizeSpaceWidth(ch);
+                    if (wid >= 0.0) {
+                        nscoord advance =
+                            aTextRun->GetAppUnitsPerDevUnit() * NS_floor(wid + 0.5);
+                        gfxTextRun::CompressedGlyph g;
+                        if (gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance)) {
+                            aTextRun->SetSimpleGlyph(index,
+                                                     g.SetSimpleGlyph(advance,
+                                                         mainFont->GetSpaceGlyph()));
+                        } else {
+                            gfxTextRun::DetailedGlyph detailedGlyph;
+                            detailedGlyph.mGlyphID = mainFont->GetSpaceGlyph();
+                            detailedGlyph.mAdvance = advance;
+                            detailedGlyph.mXOffset = detailedGlyph.mYOffset = 0;
+                            g.SetComplex(PR_TRUE, PR_TRUE, 1);
+                            aTextRun->SetGlyphs(index,
+                                                g, &detailedGlyph);
+                        }
+                    } else {
+                        aTextRun->SetMissingGlyph(index, ch);
+                    }
                 }
             }
         }
 
         runStart += matchedLength;
     }
 
     // It's possible for CoreText to omit glyph runs if it decides they contain
@@ -2543,16 +2587,25 @@ gfxFontGroup::FindFontForChar(PRUint32 a
 
     // 3. use fallback fonts
     // -- before searching for something else check the font used for the previous character
     if (!selectedFont && aPrevMatchedFont && aPrevMatchedFont->HasCharacter(aCh)) {
         selectedFont = aPrevMatchedFont;
         return selectedFont.forget();
     }
 
+    // for known "space" characters, don't do a full system-fallback search;
+    // we'll synthesize appropriate-width spaces instead of missing-glyph boxes
+    if (gfxUnicodeProperties::GetGeneralCategory(aCh) ==
+            HB_CATEGORY_SPACE_SEPARATOR &&
+        GetFontAt(0)->SynthesizeSpaceWidth(aCh) >= 0.0)
+    {
+        return nsnull;
+    }
+
     // -- otherwise look for other stuff
     if (!selectedFont) {
         selectedFont = WhichSystemFontSupportsChar(aCh);
         return selectedFont.forget();
     }
 
     return nsnull;
 }
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -1019,16 +1019,18 @@ public:
     }
 
     // The return value is interpreted as a horizontal advance in 16.16 fixed
     // point format.
     virtual PRInt32 GetGlyphWidth(gfxContext *aCtx, PRUint16 aGID) {
         return -1;
     }
 
+    gfxFloat SynthesizeSpaceWidth(PRUint32 aCh);
+
     // Font metrics
     struct Metrics {
         gfxFloat xHeight;
         gfxFloat superscriptOffset;
         gfxFloat subscriptOffset;
         gfxFloat strikeoutSize;
         gfxFloat strikeoutOffset;
         gfxFloat underlineSize;