Bug 1320665 - Add support for 'cmap' subtable format 13. r=jrmuizel
authorJonathan Kew <jkew@mozilla.com>
Tue, 13 Dec 2016 12:15:24 +0000
changeset 449582 e92988d277ae11130bf5e6774bc0c1bbaf1521b4
parent 449581 3360b8d2f04bc8439c101c3fa892eecd7465e073
child 449583 27a902904b474b0e1d2b613afd033ab01f5e47c4
push id38613
push userbmo:till@tillschneidereit.net
push dateWed, 14 Dec 2016 16:03:56 +0000
reviewersjrmuizel
bugs1320665
milestone53.0a1
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