bug 603879 - part 2 - update harfbuzz integration to support arabic etc shaping. r=jdaggett a=blocking2.0
authorJonathan Kew <jfkthame@gmail.com>
Sat, 20 Nov 2010 17:49:12 +0000
changeset 57948 11ca3cd81864621a74efb90cf15398067f27e891
parent 57947 566c74963913f3b8792e6a334505d476b14055a7
child 57949 7cf596b44bafe52760e0c2758cbe5f77e3071a03
push idunknown
push userunknown
push dateunknown
reviewersjdaggett, blocking2.0
bugs603879
milestone2.0b8pre
bug 603879 - part 2 - update harfbuzz integration to support arabic etc shaping. r=jdaggett a=blocking2.0
gfx/thebes/gfxHarfBuzzShaper.cpp
gfx/thebes/gfxHarfBuzzShaper.h
gfx/thebes/gfxMacPlatformFontList.mm
gfx/thebes/gfxUnicodeProperties.cpp
modules/libpref/src/init/all.js
--- a/gfx/thebes/gfxHarfBuzzShaper.cpp
+++ b/gfx/thebes/gfxHarfBuzzShaper.cpp
@@ -200,22 +200,23 @@ struct HLongMetric {
 
 struct HMetrics {
     HLongMetric          metrics[1]; // actually numberOfHMetrics
 // the variable-length metrics[] array is immediately followed by:
 //  AutoSwap_PRUint16    leftSideBearing[];
 };
 
 void
-gfxHarfBuzzShaper::GetGlyphMetrics(gfxContext *aContext,
+gfxHarfBuzzShaper::GetGlyphAdvance(gfxContext *aContext,
                                    hb_codepoint_t glyph,
-                                   hb_glyph_metrics_t *metrics) const
+                                   hb_position_t *x_advance,
+                                   hb_position_t *y_advance) const
 {
     if (mUseHintedWidths) {
-        metrics->x_advance = mFont->GetHintedGlyphWidth(aContext, glyph);
+        *x_advance = mFont->GetHintedGlyphWidth(aContext, glyph);
         return;
     }
 
     // font did not implement GetHintedGlyphWidth, so get an unhinted value
     // directly from the font tables
 
     NS_ASSERTION((mNumLongMetrics > 0) && mHmtxTable != nsnull,
                  "font is lacking metrics, we shouldn't be here");
@@ -224,31 +225,30 @@ gfxHarfBuzzShaper::GetGlyphMetrics(gfxCo
         glyph = mNumLongMetrics - 1;
     }
 
     // glyph must be valid now, because we checked during initialization
     // that mNumLongMetrics is > 0, and that the hmtx table is large enough
     // to contain mNumLongMetrics records
     const HMetrics* hmtx =
         reinterpret_cast<const HMetrics*>(hb_blob_lock(mHmtxTable));
-    metrics->x_advance =
+    *x_advance =
         FloatToFixed(mFont->FUnitsToDevUnitsFactor() *
                      PRUint16(hmtx->metrics[glyph].advanceWidth));
     hb_blob_unlock(mHmtxTable);
-
-    // TODO: set additional metrics if/when harfbuzz needs them
 }
 
 static void
-HBGetGlyphMetrics(hb_font_t *font, hb_face_t *face, const void *user_data,
-                  hb_codepoint_t glyph, hb_glyph_metrics_t *metrics)
+HBGetGlyphAdvance(hb_font_t *font, hb_face_t *face, const void *user_data,
+                  hb_codepoint_t glyph,
+                  hb_position_t *x_advance, hb_position_t *y_advance)
 {
     const FontCallbackData *fcd =
         static_cast<const FontCallbackData*>(user_data);
-    fcd->mShaper->GetGlyphMetrics(fcd->mContext, glyph, metrics);
+    fcd->mShaper->GetGlyphAdvance(fcd->mContext, glyph, x_advance, y_advance);
 }
 
 static hb_bool_t
 HBGetContourPoint(hb_font_t *font, hb_face_t *face, const void *user_data,
                   unsigned int point_index, hb_codepoint_t glyph,
                   hb_position_t *x, hb_position_t *y)
 {
     /* not yet implemented - no support for used of hinted contour points
@@ -706,18 +706,18 @@ gfxHarfBuzzShaper::InitTextRun(gfxContex
     if (!mHBFace) {
         // set up the harfbuzz face etc the first time we use the font
 
         if (!sHBFontFuncs) {
             // static function callback pointers, initialized by the first
             // harfbuzz shaper used
             sHBFontFuncs = hb_font_funcs_copy(hb_font_funcs_create());
             hb_font_funcs_set_glyph_func(sHBFontFuncs, HBGetGlyph);
-            hb_font_funcs_set_glyph_metrics_func(sHBFontFuncs,
-                                                 HBGetGlyphMetrics);
+            hb_font_funcs_set_glyph_advance_func(sHBFontFuncs,
+                                                 HBGetGlyphAdvance);
             hb_font_funcs_set_contour_point_func(sHBFontFuncs,
                                                  HBGetContourPoint);
             hb_font_funcs_set_kerning_func(sHBFontFuncs, HBGetKerning);
 
             sHBUnicodeFuncs = hb_unicode_funcs_copy(hb_unicode_funcs_create());
             hb_unicode_funcs_set_mirroring_func(sHBUnicodeFuncs,
                                                 HBGetMirroring);
             hb_unicode_funcs_set_script_func(sHBUnicodeFuncs, HBGetScript);
--- a/gfx/thebes/gfxHarfBuzzShaper.h
+++ b/gfx/thebes/gfxHarfBuzzShaper.h
@@ -59,20 +59,21 @@ public:
 
     // get a given font table in harfbuzz blob form
     hb_blob_t * GetFontTable(hb_tag_t aTag) const;
 
     // map unicode character to glyph ID
     hb_codepoint_t GetGlyph(hb_codepoint_t unicode,
                             hb_codepoint_t variation_selector) const;
 
-    // get harfbuzz glyph metrics, in font design units
-    void GetGlyphMetrics(gfxContext *aContext,
+    // get harfbuzz glyph advance, in font design units
+    void GetGlyphAdvance(gfxContext *aContext,
                          hb_codepoint_t glyph,
-                         hb_glyph_metrics_t *metrics) const;
+                         hb_position_t *x_advance,
+                         hb_position_t *y_advance) const;
 
     hb_position_t GetKerning(PRUint16 aFirstGlyph,
                              PRUint16 aSecondGlyph) const;
 
 protected:
     // extract glyphs from HarfBuzz buffer and store into the gfxTextRun
     nsresult SetGlyphsFromRun(gfxContext *aContext,
                               gfxTextRun *aTextRun,
--- a/gfx/thebes/gfxMacPlatformFontList.mm
+++ b/gfx/thebes/gfxMacPlatformFontList.mm
@@ -188,17 +188,17 @@ enum eComplexScript {
 
 struct ScriptRange {
     eComplexScript   script;
     PRUint32         rangeStart;
     PRUint32         rangeEnd;
 };
 
 const ScriptRange gScriptsThatRequireShaping[] = {
-    { eComplexScriptArabic, 0x0600, 0x077F },   // Basic Arabic and Arabic Supplement
+    { eComplexScriptArabic, 0x0600, 0x077F },   // Basic Arabic, Syriac, Arabic Supplement
     { eComplexScriptIndic, 0x0900, 0x0D7F },     // Indic scripts - Devanagari, Bengali, ..., Malayalam
     { eComplexScriptTibetan, 0x0F00, 0x0FFF }     // Tibetan
     // Thai seems to be "renderable" without AAT morphing tables
     // xxx - Lao, Khmer?
 };
 
 nsresult
 MacOSFontEntry::ReadCMAP()
@@ -256,18 +256,20 @@ MacOSFontEntry::ReadCMAP()
                                     gScriptsThatRequireShaping[s].rangeEnd)) {
             PRBool omitRange = PR_TRUE;
 
             if (hasAATLayout) {
                 omitRange = PR_FALSE;
             } else if (whichScript == eComplexScriptArabic) {
                 // special-case for Arabic:
                 // even if there's no morph table, CoreText can shape Arabic
-                // using OpenType layout
-                if (hasOTLayout) {
+                // using OpenType layout; or if it's a downloaded font,
+                // assume the site knows what it's doing (as harfbuzz will
+                // be able to shape even though the font itself lacks tables)
+                if (hasOTLayout || (mIsUserFont && !mIsLocalUserFont)) {
                     // TODO: to be really thorough, we could check that the
                     // GSUB table actually supports the 'arab' script tag.
                     omitRange = PR_FALSE;
                 }
             }
 
             if (omitRange) {
                 mCharacterMap.ClearRange(gScriptsThatRequireShaping[s].rangeStart,
--- a/gfx/thebes/gfxUnicodeProperties.cpp
+++ b/gfx/thebes/gfxUnicodeProperties.cpp
@@ -147,28 +147,50 @@ gfxUnicodeProperties::GetScriptCode(PRUi
 
 // TODO: replace this with a properties file or similar;
 // expect this to evolve as harfbuzz shaping support matures.
 //
 // The "shaping level" of each script run, as returned by this
 // function, is compared to the gfx.font_rendering.harfbuzz.level
 // preference to decide whether to use the harfbuzz shaper.
 //
-// Currently, we only distinguish "simple" (level 1) scripts
-// and "the rest" (level 2), but may subdivide this further in
-// the future.
+// Currently, we only distinguish "simple" (level 1) scripts,
+// Arabic-style cursive scripts (level 2),
+// and "Indic or other complex scripts" (level 3),
+// but may subdivide this further in the future.
 PRInt32
 gfxUnicodeProperties::ScriptShapingLevel(PRInt32 aScriptCode)
 {
     switch (aScriptCode) {
-    case HB_SCRIPT_LATIN:
-    case HB_SCRIPT_CYRILLIC:
-    case HB_SCRIPT_HAN:
-    case HB_SCRIPT_HIRAGANA:
-    case HB_SCRIPT_KATAKANA:
-    case HB_SCRIPT_COMMON:
-    case HB_SCRIPT_INHERITED:
-    case HB_SCRIPT_UNKNOWN:
-        return 1; // level 1: common scripts that can use "generic" shaping
+    default:
+        return 1; // scripts not explicitly listed here are considered
+                  // level 1: default shaping behavior is adequate
+
+    case HB_SCRIPT_ARABIC:
+    case HB_SCRIPT_SYRIAC:
+    case HB_SCRIPT_NKO:
+        return 2; // level 2: bidi scripts with Arabic-style shaping
+
+    case HB_SCRIPT_HEBREW:
+    case HB_SCRIPT_HANGUL:
+    case HB_SCRIPT_BENGALI:
+    case HB_SCRIPT_DEVANAGARI:
+    case HB_SCRIPT_GUJARATI:
+    case HB_SCRIPT_GURMUKHI:
+    case HB_SCRIPT_KANNADA:
+    case HB_SCRIPT_MALAYALAM:
+    case HB_SCRIPT_ORIYA:
+    case HB_SCRIPT_TAMIL:
+    case HB_SCRIPT_TELUGU:
+    case HB_SCRIPT_KHMER:
+    case HB_SCRIPT_THAI:
+    case HB_SCRIPT_LAO:
+    case HB_SCRIPT_TIBETAN:
+    case HB_SCRIPT_NEW_TAI_LUE:
+    case HB_SCRIPT_TAI_LE:
+    case HB_SCRIPT_MONGOLIAN:
+    case HB_SCRIPT_MYANMAR:
+    case HB_SCRIPT_PHAGS_PA:
+    case HB_SCRIPT_BATAK:
+    case HB_SCRIPT_BRAHMI:
+        return 3; // scripts that require Indic or other "special" shaping
     }
-
-    return 2; // all others are considered level 2
 }
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -194,17 +194,17 @@ pref("gfx.3d_video.enabled", false);
 pref("gfx.downloadable_fonts.enabled", true);
 pref("gfx.downloadable_fonts.sanitize", true);
 #ifdef XP_MACOSX
 pref("gfx.downloadable_fonts.sanitize.preserve_otl_tables", false);
 #else
 pref("gfx.downloadable_fonts.sanitize.preserve_otl_tables", true);
 #endif
 
-pref("gfx.font_rendering.harfbuzz.level", 1);
+pref("gfx.font_rendering.harfbuzz.level", 2);
 
 #ifdef XP_WIN
 #ifndef WINCE
 pref("gfx.font_rendering.directwrite.enabled", false);
 #endif
 #endif
 
 pref("accessibility.browsewithcaret", false);