Bug 1320665 - Add support for 'cmap' subtable format 13. r=jrmuizel
☠☠ backed out by 6dfee6a56324 ☠ ☠
authorJonathan Kew <jkew@mozilla.com>
Tue, 13 Dec 2016 16:16:57 +0000
changeset 357873 59bdf1eb5d2d34e4acf52df73802e91f1351c3af
parent 357872 1ba830898e8c2536b5ee8f6259d2687b7a38a312
child 357874 b2bac083c74e01ca19486e3e2466c6fcb0c4f423
push idunknown
push userunknown
push dateunknown
reviewersjrmuizel
bugs1320665
milestone53.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1320665 - Add support for 'cmap' subtable format 13. r=jrmuizel
gfx/thebes/gfxFontUtils.cpp
gfx/thebes/gfxFontUtils.h
gfx/thebes/gfxHarfBuzzShaper.cpp
--- a/gfx/thebes/gfxFontUtils.cpp
+++ b/gfx/thebes/gfxFontUtils.cpp
@@ -134,29 +134,34 @@ gfxFontUtils::ReadCMAPTableFormat10(cons
     }
 
     aCharacterMap.Compact();
 
     return NS_OK;
 }
 
 nsresult
-gfxFontUtils::ReadCMAPTableFormat12(const uint8_t *aBuf, uint32_t aLength,
-                                    gfxSparseBitSet& aCharacterMap) 
+gfxFontUtils::ReadCMAPTableFormat12or13(const uint8_t *aBuf, uint32_t aLength,
+                                        gfxSparseBitSet& aCharacterMap)
 {
+    // Format 13 has the same structure as format 12, the only difference is
+    // the interpretation of the glyphID field. So we can share the code here
+    // that reads the table and just records character coverage.
+
     // Ensure table is large enough that we can safely read the header
     NS_ENSURE_TRUE(aLength >= sizeof(Format12CmapHeader),
                     NS_ERROR_GFX_CMAP_MALFORMED);
 
     // Sanity-check header fields
     const Format12CmapHeader *cmap12 =
         reinterpret_cast<const Format12CmapHeader*>(aBuf);
-    NS_ENSURE_TRUE(uint16_t(cmap12->format) == 12, 
+    NS_ENSURE_TRUE(uint16_t(cmap12->format) == 12 ||
+                   uint16_t(cmap12->format) == 13,
                    NS_ERROR_GFX_CMAP_MALFORMED);
-    NS_ENSURE_TRUE(uint16_t(cmap12->reserved) == 0, 
+    NS_ENSURE_TRUE(uint16_t(cmap12->reserved) == 0,
                    NS_ERROR_GFX_CMAP_MALFORMED);
 
     uint32_t tablelen = cmap12->length;
     NS_ENSURE_TRUE(tablelen >= sizeof(Format12CmapHeader) &&
                    tablelen <= aLength, NS_ERROR_GFX_CMAP_MALFORMED);
 
     NS_ENSURE_TRUE(cmap12->language == 0, NS_ERROR_GFX_CMAP_MALFORMED);
 
@@ -467,17 +472,17 @@ gfxFontUtils::FindPreferredSubtable(cons
             keepFormat = format;
             *aTableOffset = offset;
             *aSymbolEncoding = true;
             break;
         } else if (format == 4 && acceptableFormat4(platformID, encodingID, keepFormat)) {
             keepFormat = format;
             *aTableOffset = offset;
             *aSymbolEncoding = false;
-        } else if ((format == 10 || format == 12) &&
+        } else if ((format == 10 || format == 12 || format == 13) &&
                    acceptableUCS4Encoding(platformID, encodingID, keepFormat)) {
             keepFormat = format;
             *aTableOffset = offset;
             *aSymbolEncoding = false;
             if (platformID > PLATFORM_ID_UNICODE || !aUVSTableOffset || *aUVSTableOffset) {
                 break; // we don't want to try anything else when this format is available.
             }
         } else if (format == 14 && isUVSEncoding(platformID, encodingID) && aUVSTableOffset) {
@@ -516,20 +521,21 @@ gfxFontUtils::ReadCMAP(const uint8_t *aB
 
     case 10:
         aUnicodeFont = true;
         aSymbolFont = false;
         return ReadCMAPTableFormat10(aBuf + offset, aBufLength - offset,
                                      aCharacterMap);
 
     case 12:
+    case 13:
         aUnicodeFont = true;
         aSymbolFont = false;
-        return ReadCMAPTableFormat12(aBuf + offset, aBufLength - offset,
-                                     aCharacterMap);
+        return ReadCMAPTableFormat12or13(aBuf + offset, aBufLength - offset,
+                                         aCharacterMap);
 
     default:
         break;
     }
 
     return NS_ERROR_FAILURE;
 }
 
@@ -646,23 +652,27 @@ gfxFontUtils::MapCharToGlyphFormat10(con
     const AutoSwap_PRUint16 *glyphs =
         reinterpret_cast<const AutoSwap_PRUint16 *>(cmap10 + 1);
 
     uint16_t glyph = glyphs[aCh - startChar];
     return glyph;
 }
 
 uint32_t
-gfxFontUtils::MapCharToGlyphFormat12(const uint8_t *aBuf, uint32_t aCh)
+gfxFontUtils::MapCharToGlyphFormat12or13(const uint8_t *aBuf, uint32_t aCh)
 {
+    // The only difference between formats 12 and 13 is the interpretation of
+    // the glyphId field. So the code here uses the same "Format12" structures,
+    // etc., to handle both subtable formats.
+
     const Format12CmapHeader *cmap12 =
         reinterpret_cast<const Format12CmapHeader*>(aBuf);
 
     // We know that numGroups is within range for the subtable size
-    // because it was checked by ReadCMAPTableFormat12.
+    // because it was checked by ReadCMAPTableFormat12or13.
     uint32_t numGroups = cmap12->numGroups;
 
     // The array of groups immediately follows the subtable header.
     const Format12Group *groups =
         reinterpret_cast<const Format12Group*>(aBuf + sizeof(Format12CmapHeader));
 
     // For most efficient binary search, we want to work on a range that
     // is a power of 2 so that we can always halve it by shifting.
@@ -683,20 +693,23 @@ gfxFontUtils::MapCharToGlyphFormat12(con
     while (powerOf2 > 1) {
         powerOf2 >>= 1;
         if (groups[range + powerOf2].startCharCode <= aCh) {
             range += powerOf2;
         }
     }
 
     // Check if the character is actually present in the range and return
-    // the corresponding glyph ID
+    // the corresponding glyph ID. Here is where formats 12 and 13 interpret
+    // the startGlyphId (12) or glyphId (13) field differently
     startCharCode = groups[range].startCharCode;
     if (startCharCode <= aCh && groups[range].endCharCode >= aCh) {
-        return groups[range].startGlyphId + aCh - startCharCode;
+        return uint16_t(cmap12->format) == 12
+               ? uint16_t(groups[range].startGlyphId) + aCh - startCharCode
+               : uint16_t(groups[range].startGlyphId);
     }
 
     // Else it's not present, so return the .notdef glyph
     return 0;
 }
 
 namespace {
 
@@ -762,17 +775,18 @@ gfxFontUtils::MapCharToGlyph(const uint8
     case 4:
         gid = aUnicode < UNICODE_BMP_LIMIT ?
             MapCharToGlyphFormat4(aCmapBuf + offset, char16_t(aUnicode)) : 0;
         break;
     case 10:
         gid = MapCharToGlyphFormat10(aCmapBuf + offset, aUnicode);
         break;
     case 12:
-        gid = MapCharToGlyphFormat12(aCmapBuf + offset, aUnicode);
+    case 13:
+        gid = MapCharToGlyphFormat12or13(aCmapBuf + offset, aUnicode);
         break;
     default:
         NS_WARNING("unsupported cmap format, glyphs will be missing");
         gid = 0;
     }
 
     if (aVarSelector && uvsOffset && gid) {
         uint32_t varGID =
@@ -788,18 +802,19 @@ gfxFontUtils::MapCharToGlyph(const uint8
                                                        char16_t(aUnicode));
                     }
                     break;
                 case 10:
                     varGID = MapCharToGlyphFormat10(aCmapBuf + offset,
                                                     aUnicode);
                     break;
                 case 12:
-                    varGID = MapCharToGlyphFormat12(aCmapBuf + offset,
-                                                    aUnicode);
+                case 13:
+                    varGID = MapCharToGlyphFormat12or13(aCmapBuf + offset,
+                                                        aUnicode);
                     break;
                 }
             }
         }
         if (varGID) {
             gid = varGID;
         }
 
--- a/gfx/thebes/gfxFontUtils.h
+++ b/gfx/thebes/gfxFontUtils.h
@@ -776,18 +776,18 @@ public:
                 (aBuf[aIndex + 2] << 8) | (aBuf[aIndex + 3]));
     }
 
     static nsresult
     ReadCMAPTableFormat10(const uint8_t *aBuf, uint32_t aLength,
                           gfxSparseBitSet& aCharacterMap);
 
     static nsresult
-    ReadCMAPTableFormat12(const uint8_t *aBuf, uint32_t aLength, 
-                          gfxSparseBitSet& aCharacterMap);
+    ReadCMAPTableFormat12or13(const uint8_t *aBuf, uint32_t aLength, 
+                              gfxSparseBitSet& aCharacterMap);
 
     static nsresult 
     ReadCMAPTableFormat4(const uint8_t *aBuf, uint32_t aLength, 
                          gfxSparseBitSet& aCharacterMap);
 
     static nsresult
     ReadCMAPTableFormat14(const uint8_t *aBuf, uint32_t aLength, 
                           mozilla::UniquePtr<uint8_t[]>& aTable);
@@ -805,17 +805,17 @@ public:
 
     static uint32_t
     MapCharToGlyphFormat4(const uint8_t *aBuf, char16_t aCh);
 
     static uint32_t
     MapCharToGlyphFormat10(const uint8_t *aBuf, uint32_t aCh);
 
     static uint32_t
-    MapCharToGlyphFormat12(const uint8_t *aBuf, uint32_t aCh);
+    MapCharToGlyphFormat12or13(const uint8_t *aBuf, uint32_t aCh);
 
     static uint16_t
     MapUVSToGlyphFormat14(const uint8_t *aBuf, uint32_t aCh, uint32_t aVS);
 
     // sCJKCompatSVSTable is a 'cmap' format 14 subtable that maps
     // <char + var-selector> pairs to the corresponding Unicode
     // compatibility ideograph codepoints.
     static MOZ_ALWAYS_INLINE uint32_t
--- a/gfx/thebes/gfxHarfBuzzShaper.cpp
+++ b/gfx/thebes/gfxHarfBuzzShaper.cpp
@@ -126,18 +126,20 @@ gfxHarfBuzzShaper::GetNominalGlyph(hb_co
                 gfxFontUtils::MapCharToGlyphFormat4(data + mSubtableOffset,
                                                     unicode) : 0;
             break;
         case 10:
             gid = gfxFontUtils::MapCharToGlyphFormat10(data + mSubtableOffset,
                                                        unicode);
             break;
         case 12:
-            gid = gfxFontUtils::MapCharToGlyphFormat12(data + mSubtableOffset,
-                                                       unicode);
+        case 13:
+            gid =
+                gfxFontUtils::MapCharToGlyphFormat12or13(data + mSubtableOffset,
+                                                         unicode);
             break;
         default:
             NS_WARNING("unsupported cmap format, glyphs will be missing");
             break;
         }
     }
 
     if (!gid) {
@@ -185,18 +187,20 @@ gfxHarfBuzzShaper::GetVariationGlyph(hb_
                                                            compat);
             }
             break;
         case 10:
             return gfxFontUtils::MapCharToGlyphFormat10(data + mSubtableOffset,
                                                         compat);
             break;
         case 12:
-            return gfxFontUtils::MapCharToGlyphFormat12(data + mSubtableOffset,
-                                                        compat);
+        case 13:
+            return
+                gfxFontUtils::MapCharToGlyphFormat12or13(data + mSubtableOffset,
+                                                         compat);
             break;
         }
     }
 
     return 0;
 }
 
 static int