OSDN Git Service

Add Harfbuzz support for system fallback fonts
authorRussell Brenner <russellbrenner@google.com>
Wed, 10 Aug 2011 00:16:42 +0000 (17:16 -0700)
committerRussell Brenner <russellbrenner@google.com>
Tue, 16 Aug 2011 21:22:10 +0000 (14:22 -0700)
When Skia resorts to fallback fonts for non-latin characters, it
retains the font ID of originally requested font, concealing the
fact that a fallback was invoked. Harfbuzz needs to know the fallback
font ID to read the correct GSUB/GPOS tables from the fallback font
file so that these complex languages can be properly rendered.

This change uses the script recognized by Harfbuzz as a means to
surmise the fallback font that would be used by Skia and then injects
that font file as a replacement for the originally requested font.

Bug: 5087744
Change-Id: I3a3469bcd589ee796c9b5a828fb47d40ecb38738

Source/WebCore/platform/graphics/android/FontAndroid.cpp
Source/WebCore/platform/graphics/android/FontPlatformData.h
Source/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp

index b56e37c..332e571 100644 (file)
@@ -427,6 +427,7 @@ public:
 
 private:
     void setupFontForScriptRun();
+    void setupComplexFont(const char* fontName, const FontPlatformData& platformData);
     HB_FontRec* allocHarfbuzzFont();
     void deleteGlyphArrays();
     void createGlyphArrays(int);
@@ -465,6 +466,7 @@ private:
                       // each word break we accumulate error. This is the
                       // number of pixels that we are behind so far.
     unsigned m_letterSpacing; // pixels to be added after each glyph.
+    FontPlatformData* m_complexPlatformData;
 };
 
 
@@ -479,6 +481,7 @@ TextRunWalker::TextRunWalker(const TextRun& run, unsigned startingX, const Font*
     , m_padPerWordBreak(0)
     , m_padError(0)
     , m_letterSpacing(0)
+    , m_complexPlatformData(0)
 {
     // Do not use |run| inside this constructor. Use |m_run| instead.
 
@@ -507,6 +510,7 @@ TextRunWalker::~TextRunWalker()
     fastFree(m_item.font);
     deleteGlyphArrays();
     delete[] m_item.log_clusters;
+    delete m_complexPlatformData;
 }
 
 bool TextRunWalker::isWordBreak(unsigned index, bool isRTL)
@@ -620,15 +624,48 @@ void TextRunWalker::setWordAndLetterSpacing(int wordSpacingAdjustment,
     setLetterSpacingAdjustment(letterSpacingAdjustment);
 }
 
+void TextRunWalker::setupComplexFont(const char* filename,
+                                     const FontPlatformData& platformData)
+{
+    delete m_complexPlatformData;
+
+    SkTypeface* typeface = SkTypeface::CreateFromFile(filename);
+    m_complexPlatformData = new FontPlatformData(platformData, typeface);
+    SkSafeUnref(typeface);
+    m_item.face = m_complexPlatformData->harfbuzzFace();
+    m_item.font->userData = m_complexPlatformData;
+}
+
 void TextRunWalker::setupFontForScriptRun()
 {
-    const FontData* fontData = m_font->glyphDataForCharacter(
-        m_item.string[m_item.item.pos], false).fontData;
+    const FontData* fontData = m_font->glyphDataForCharacter(m_run[0], false).fontData;
     const FontPlatformData& platformData =
         fontData->fontDataForCharacter(' ')->platformData();
-    m_item.face = platformData.harfbuzzFace();
-    void* opaquePlatformData = const_cast<FontPlatformData*>(&platformData);
-    m_item.font->userData = opaquePlatformData;
+
+    if (m_item.item.script == HB_Script_Devanagari) {
+        setupComplexFont("/system/fonts/Lohit_Hindi.ttf", platformData);
+    } else if (m_item.item.script == HB_Script_Thai) {
+        setupComplexFont("/system/fonts/DroidSansThai.ttf", platformData);
+    } else if (m_item.item.script == HB_Script_Arabic) {
+        setupComplexFont("/system/fonts/DroidNaskh-Regular.ttf", platformData);
+    } else if (m_item.item.script == HB_Script_Hebrew) {
+        switch (platformData.typeface()->style()) {
+            case SkTypeface::kBold:
+            case SkTypeface::kBoldItalic:
+                setupComplexFont("/system/fonts/DroidSansHebrew-Bold.ttf", platformData);
+                break;
+            case SkTypeface::kNormal:
+            case SkTypeface::kItalic:
+            default:
+                setupComplexFont("/system/fonts/DroidSansHebrew-Regular.ttf", platformData);
+                break;
+        }
+    } else {
+        // HB_Script_Common; includes Ethiopic
+        m_item.face = platformData.harfbuzzFace();
+        void* opaquePlatformData = const_cast<FontPlatformData*>(&platformData);
+        m_item.font->userData = opaquePlatformData;
+    }
 }
 
 HB_FontRec* TextRunWalker::allocHarfbuzzFont()
index 3313aca..56ce6e9 100644 (file)
@@ -55,6 +55,7 @@ public:
     FontPlatformData(SkTypeface*, float textSize, bool fakeBold, bool fakeItalic);
     FontPlatformData(const FontPlatformData& src, float textSize);
     FontPlatformData(float size, bool syntheticBold, bool syntheticOblique);
+    FontPlatformData(const FontPlatformData& src, SkTypeface* typeface);
 
     ~FontPlatformData();
 
@@ -87,6 +88,7 @@ public:
 #endif
 
     HB_FaceRec_* harfbuzzFace() const;
+    SkTypeface* typeface() const { return mTypeface; }
 
 private:
     class RefCountedHarfbuzzFace : public RefCounted<RefCountedHarfbuzzFace> {
index 337a94d..1c3c5d9 100644 (file)
@@ -127,6 +127,17 @@ FontPlatformData::FontPlatformData(float size, bool bold, bool oblique)
     trace(5);
 }
 
+FontPlatformData::FontPlatformData(const FontPlatformData& src, SkTypeface* tf)
+    : mTypeface(tf), mTextSize(src.mTextSize), mFakeBold(src.mFakeBold), mFakeItalic(src.mFakeItalic)
+{
+    if (hashTableDeletedFontValue() != mTypeface) {
+        SkSafeRef(mTypeface);
+    }
+
+    inc_count();
+    trace(6);
+}
+
 FontPlatformData::~FontPlatformData()
 {
     dec_count();