LCOV - code coverage report
Current view: top level - gfx/thebes - gfxFontUtils.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 23 686 3.4 %
Date: 2017-07-14 16:53:18 Functions: 3 43 7.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "mozilla/ArrayUtils.h"
       7             : #include "mozilla/BinarySearch.h"
       8             : 
       9             : #include "gfxFontUtils.h"
      10             : 
      11             : #include "nsServiceManagerUtils.h"
      12             : 
      13             : #include "mozilla/Preferences.h"
      14             : #include "mozilla/Services.h"
      15             : #include "mozilla/BinarySearch.h"
      16             : #include "mozilla/Sprintf.h"
      17             : 
      18             : #include "nsCOMPtr.h"
      19             : #include "nsIUUIDGenerator.h"
      20             : #include "mozilla/Encoding.h"
      21             : 
      22             : #include "harfbuzz/hb.h"
      23             : 
      24             : #include "plbase64.h"
      25             : #include "mozilla/Logging.h"
      26             : 
      27             : #ifdef XP_MACOSX
      28             : #include <CoreFoundation/CoreFoundation.h>
      29             : #endif
      30             : 
      31             : #define LOG(log, args) MOZ_LOG(gfxPlatform::GetLog(log), \
      32             :                                LogLevel::Debug, args)
      33             : 
      34             : #define UNICODE_BMP_LIMIT 0x10000
      35             : 
      36             : using namespace mozilla;
      37             : 
      38             : #pragma pack(1)
      39             : 
      40             : typedef struct {
      41             :     AutoSwap_PRUint16 format;
      42             :     AutoSwap_PRUint16 reserved;
      43             :     AutoSwap_PRUint32 length;
      44             :     AutoSwap_PRUint32 language;
      45             :     AutoSwap_PRUint32 startCharCode;
      46             :     AutoSwap_PRUint32 numChars;
      47             : } Format10CmapHeader;
      48             : 
      49             : typedef struct {
      50             :     AutoSwap_PRUint16 format;
      51             :     AutoSwap_PRUint16 reserved;
      52             :     AutoSwap_PRUint32 length;
      53             :     AutoSwap_PRUint32 language;
      54             :     AutoSwap_PRUint32 numGroups;
      55             : } Format12CmapHeader;
      56             : 
      57             : typedef struct {
      58             :     AutoSwap_PRUint32 startCharCode;
      59             :     AutoSwap_PRUint32 endCharCode;
      60             :     AutoSwap_PRUint32 startGlyphId;
      61             : } Format12Group;
      62             : 
      63             : #pragma pack()
      64             : 
      65             : void
      66           0 : gfxSparseBitSet::Dump(const char* aPrefix, eGfxLog aWhichLog) const
      67             : {
      68           0 :     NS_ASSERTION(mBlocks.DebugGetHeader(), "mHdr is null, this is bad");
      69           0 :     uint32_t b, numBlocks = mBlocks.Length();
      70             : 
      71           0 :     for (b = 0; b < numBlocks; b++) {
      72           0 :         Block *block = mBlocks[b].get();
      73           0 :         if (!block) {
      74           0 :             continue;
      75             :         }
      76           0 :         const int BUFSIZE = 256;
      77             :         char outStr[BUFSIZE];
      78           0 :         int index = 0;
      79           0 :         index += snprintf(&outStr[index], BUFSIZE - index, "%s u+%6.6x [", aPrefix, (b << BLOCK_INDEX_SHIFT));
      80           0 :         for (int i = 0; i < 32; i += 4) {
      81           0 :             for (int j = i; j < i + 4; j++) {
      82           0 :                 uint8_t bits = block->mBits[j];
      83           0 :                 uint8_t flip1 = ((bits & 0xaa) >> 1) | ((bits & 0x55) << 1);
      84           0 :                 uint8_t flip2 = ((flip1 & 0xcc) >> 2) | ((flip1 & 0x33) << 2);
      85           0 :                 uint8_t flipped = ((flip2 & 0xf0) >> 4) | ((flip2 & 0x0f) << 4);
      86             : 
      87           0 :                 index += snprintf(&outStr[index], BUFSIZE - index, "%2.2x", flipped);
      88             :             }
      89           0 :             if (i + 4 != 32) index += snprintf(&outStr[index], BUFSIZE - index, " ");
      90             :         }
      91           0 :         index += snprintf(&outStr[index], BUFSIZE - index, "]");
      92           0 :         LOG(aWhichLog, ("%s", outStr));
      93             :     }
      94           0 : }
      95             : 
      96             : nsresult
      97           0 : gfxFontUtils::ReadCMAPTableFormat10(const uint8_t *aBuf, uint32_t aLength,
      98             :                                     gfxSparseBitSet& aCharacterMap)
      99             : {
     100             :     // Ensure table is large enough that we can safely read the header
     101           0 :     NS_ENSURE_TRUE(aLength >= sizeof(Format10CmapHeader),
     102             :                     NS_ERROR_GFX_CMAP_MALFORMED);
     103             : 
     104             :     // Sanity-check header fields
     105             :     const Format10CmapHeader *cmap10 =
     106           0 :         reinterpret_cast<const Format10CmapHeader*>(aBuf);
     107           0 :     NS_ENSURE_TRUE(uint16_t(cmap10->format) == 10,
     108             :                    NS_ERROR_GFX_CMAP_MALFORMED);
     109           0 :     NS_ENSURE_TRUE(uint16_t(cmap10->reserved) == 0,
     110             :                    NS_ERROR_GFX_CMAP_MALFORMED);
     111             : 
     112           0 :     uint32_t tablelen = cmap10->length;
     113           0 :     NS_ENSURE_TRUE(tablelen >= sizeof(Format10CmapHeader) &&
     114             :                    tablelen <= aLength, NS_ERROR_GFX_CMAP_MALFORMED);
     115             : 
     116           0 :     NS_ENSURE_TRUE(cmap10->language == 0, NS_ERROR_GFX_CMAP_MALFORMED);
     117             : 
     118           0 :     uint32_t numChars = cmap10->numChars;
     119           0 :     NS_ENSURE_TRUE(tablelen == sizeof(Format10CmapHeader) +
     120             :                    numChars * sizeof(uint16_t), NS_ERROR_GFX_CMAP_MALFORMED);
     121             : 
     122           0 :     uint32_t charCode = cmap10->startCharCode;
     123           0 :     NS_ENSURE_TRUE(charCode <= CMAP_MAX_CODEPOINT &&
     124             :                    charCode + numChars <= CMAP_MAX_CODEPOINT,
     125             :                    NS_ERROR_GFX_CMAP_MALFORMED);
     126             : 
     127             :     // glyphs[] array immediately follows the subtable header
     128             :     const AutoSwap_PRUint16 *glyphs =
     129           0 :         reinterpret_cast<const AutoSwap_PRUint16 *>(cmap10 + 1);
     130             : 
     131           0 :     for (uint32_t i = 0; i < numChars; ++i) {
     132           0 :         if (uint16_t(*glyphs) != 0) {
     133           0 :             aCharacterMap.set(charCode);
     134             :         }
     135           0 :         ++charCode;
     136           0 :         ++glyphs;
     137             :     }
     138             : 
     139           0 :     aCharacterMap.Compact();
     140             : 
     141           0 :     return NS_OK;
     142             : }
     143             : 
     144             : nsresult
     145           0 : gfxFontUtils::ReadCMAPTableFormat12or13(const uint8_t *aBuf, uint32_t aLength,
     146             :                                         gfxSparseBitSet& aCharacterMap)
     147             : {
     148             :     // Format 13 has the same structure as format 12, the only difference is
     149             :     // the interpretation of the glyphID field. So we can share the code here
     150             :     // that reads the table and just records character coverage.
     151             : 
     152             :     // Ensure table is large enough that we can safely read the header
     153           0 :     NS_ENSURE_TRUE(aLength >= sizeof(Format12CmapHeader),
     154             :                     NS_ERROR_GFX_CMAP_MALFORMED);
     155             : 
     156             :     // Sanity-check header fields
     157             :     const Format12CmapHeader *cmap12 =
     158           0 :         reinterpret_cast<const Format12CmapHeader*>(aBuf);
     159           0 :     NS_ENSURE_TRUE(uint16_t(cmap12->format) == 12 ||
     160             :                    uint16_t(cmap12->format) == 13,
     161             :                    NS_ERROR_GFX_CMAP_MALFORMED);
     162           0 :     NS_ENSURE_TRUE(uint16_t(cmap12->reserved) == 0,
     163             :                    NS_ERROR_GFX_CMAP_MALFORMED);
     164             : 
     165           0 :     uint32_t tablelen = cmap12->length;
     166           0 :     NS_ENSURE_TRUE(tablelen >= sizeof(Format12CmapHeader) &&
     167             :                    tablelen <= aLength, NS_ERROR_GFX_CMAP_MALFORMED);
     168             : 
     169           0 :     NS_ENSURE_TRUE(cmap12->language == 0, NS_ERROR_GFX_CMAP_MALFORMED);
     170             : 
     171             :     // Check that the table is large enough for the group array
     172           0 :     const uint32_t numGroups = cmap12->numGroups;
     173           0 :     NS_ENSURE_TRUE((tablelen - sizeof(Format12CmapHeader)) /
     174             :                        sizeof(Format12Group) >= numGroups,
     175             :                    NS_ERROR_GFX_CMAP_MALFORMED);
     176             : 
     177             :     // The array of groups immediately follows the subtable header.
     178             :     const Format12Group *group =
     179           0 :         reinterpret_cast<const Format12Group*>(aBuf + sizeof(Format12CmapHeader));
     180             : 
     181             :     // Check that groups are in correct order and do not overlap,
     182             :     // and record character coverage in aCharacterMap.
     183           0 :     uint32_t prevEndCharCode = 0;
     184           0 :     for (uint32_t i = 0; i < numGroups; i++, group++) {
     185           0 :         uint32_t startCharCode = group->startCharCode;
     186           0 :         const uint32_t endCharCode = group->endCharCode;
     187           0 :         NS_ENSURE_TRUE((prevEndCharCode < startCharCode || i == 0) &&
     188             :                        startCharCode <= endCharCode &&
     189             :                        endCharCode <= CMAP_MAX_CODEPOINT, 
     190             :                        NS_ERROR_GFX_CMAP_MALFORMED);
     191             :         // don't include a character that maps to glyph ID 0 (.notdef)
     192           0 :         if (group->startGlyphId == 0) {
     193           0 :             startCharCode++;
     194             :         }
     195           0 :         if (startCharCode <= endCharCode) {
     196           0 :             aCharacterMap.SetRange(startCharCode, endCharCode);
     197             :         }
     198           0 :         prevEndCharCode = endCharCode;
     199             :     }
     200             : 
     201           0 :     aCharacterMap.Compact();
     202             : 
     203           0 :     return NS_OK;
     204             : }
     205             : 
     206             : nsresult 
     207           0 : gfxFontUtils::ReadCMAPTableFormat4(const uint8_t *aBuf, uint32_t aLength,
     208             :                                    gfxSparseBitSet& aCharacterMap)
     209             : {
     210             :     enum {
     211             :         OffsetFormat = 0,
     212             :         OffsetLength = 2,
     213             :         OffsetLanguage = 4,
     214             :         OffsetSegCountX2 = 6
     215             :     };
     216             : 
     217           0 :     NS_ENSURE_TRUE(ReadShortAt(aBuf, OffsetFormat) == 4, 
     218             :                    NS_ERROR_GFX_CMAP_MALFORMED);
     219           0 :     uint16_t tablelen = ReadShortAt(aBuf, OffsetLength);
     220           0 :     NS_ENSURE_TRUE(tablelen <= aLength, NS_ERROR_GFX_CMAP_MALFORMED);
     221           0 :     NS_ENSURE_TRUE(tablelen > 16, NS_ERROR_GFX_CMAP_MALFORMED);
     222             :     
     223             :     // This field should normally (except for Mac platform subtables) be zero according to
     224             :     // the OT spec, but some buggy fonts have lang = 1 (which would be English for MacOS).
     225             :     // E.g. Arial Narrow Bold, v. 1.1 (Tiger), Arial Unicode MS (see bug 530614).
     226             :     // So accept either zero or one here; the error should be harmless.
     227           0 :     NS_ENSURE_TRUE((ReadShortAt(aBuf, OffsetLanguage) & 0xfffe) == 0, 
     228             :                    NS_ERROR_GFX_CMAP_MALFORMED);
     229             : 
     230           0 :     uint16_t segCountX2 = ReadShortAt(aBuf, OffsetSegCountX2);
     231           0 :     NS_ENSURE_TRUE(tablelen >= 16 + (segCountX2 * 4), 
     232             :                    NS_ERROR_GFX_CMAP_MALFORMED);
     233             : 
     234           0 :     const uint16_t segCount = segCountX2 / 2;
     235             : 
     236           0 :     const uint16_t *endCounts = reinterpret_cast<const uint16_t*>(aBuf + 14);
     237           0 :     const uint16_t *startCounts = endCounts + 1 /* skip one uint16_t for reservedPad */ + segCount;
     238           0 :     const uint16_t *idDeltas = startCounts + segCount;
     239           0 :     const uint16_t *idRangeOffsets = idDeltas + segCount;
     240           0 :     uint16_t prevEndCount = 0;
     241           0 :     for (uint16_t i = 0; i < segCount; i++) {
     242           0 :         const uint16_t endCount = ReadShortAt16(endCounts, i);
     243           0 :         const uint16_t startCount = ReadShortAt16(startCounts, i);
     244           0 :         const uint16_t idRangeOffset = ReadShortAt16(idRangeOffsets, i);
     245             : 
     246             :         // sanity-check range
     247             :         // This permits ranges to overlap by 1 character, which is strictly
     248             :         // incorrect but occurs in Baskerville on OS X 10.7 (see bug 689087),
     249             :         // and appears to be harmless in practice
     250           0 :         NS_ENSURE_TRUE(startCount >= prevEndCount && startCount <= endCount,
     251             :                        NS_ERROR_GFX_CMAP_MALFORMED);
     252           0 :         prevEndCount = endCount;
     253             : 
     254           0 :         if (idRangeOffset == 0) {
     255             :             // figure out if there's a code in the range that would map to
     256             :             // glyph ID 0 (.notdef); if so, we need to skip setting that
     257             :             // character code in the map
     258           0 :             const uint16_t skipCode = 65536 - ReadShortAt16(idDeltas, i);
     259           0 :             if (startCount < skipCode) {
     260           0 :                 aCharacterMap.SetRange(startCount,
     261           0 :                                        std::min<uint16_t>(skipCode - 1,
     262           0 :                                                           endCount));
     263             :             }
     264           0 :             if (skipCode < endCount) {
     265           0 :                 aCharacterMap.SetRange(std::max<uint16_t>(startCount,
     266           0 :                                                           skipCode + 1),
     267           0 :                                        endCount);
     268             :             }
     269             :         } else {
     270             :             // const uint16_t idDelta = ReadShortAt16(idDeltas, i); // Unused: self-documenting.
     271           0 :             for (uint32_t c = startCount; c <= endCount; ++c) {
     272           0 :                 if (c == 0xFFFF)
     273           0 :                     break;
     274             : 
     275           0 :                 const uint16_t *gdata = (idRangeOffset/2 
     276           0 :                                          + (c - startCount)
     277           0 :                                          + &idRangeOffsets[i]);
     278             : 
     279           0 :                 NS_ENSURE_TRUE((uint8_t*)gdata > aBuf && 
     280             :                                (uint8_t*)gdata < aBuf + aLength, 
     281             :                                NS_ERROR_GFX_CMAP_MALFORMED);
     282             : 
     283             :                 // make sure we have a glyph
     284           0 :                 if (*gdata != 0) {
     285             :                     // The glyph index at this point is:
     286           0 :                     uint16_t glyph = ReadShortAt16(idDeltas, i) + *gdata;
     287           0 :                     if (glyph) {
     288           0 :                         aCharacterMap.set(c);
     289             :                     }
     290             :                 }
     291             :             }
     292             :         }
     293             :     }
     294             : 
     295           0 :     aCharacterMap.Compact();
     296             : 
     297           0 :     return NS_OK;
     298             : }
     299             : 
     300             : nsresult
     301           0 : gfxFontUtils::ReadCMAPTableFormat14(const uint8_t *aBuf, uint32_t aLength,
     302             :                                     UniquePtr<uint8_t[]>& aTable)
     303             : {
     304             :     enum {
     305             :         OffsetFormat = 0,
     306             :         OffsetTableLength = 2,
     307             :         OffsetNumVarSelectorRecords = 6,
     308             :         OffsetVarSelectorRecords = 10,
     309             : 
     310             :         SizeOfVarSelectorRecord = 11,
     311             :         VSRecOffsetVarSelector = 0,
     312             :         VSRecOffsetDefUVSOffset = 3,
     313             :         VSRecOffsetNonDefUVSOffset = 7,
     314             : 
     315             :         SizeOfDefUVSTable = 4,
     316             :         DefUVSOffsetStartUnicodeValue = 0,
     317             :         DefUVSOffsetAdditionalCount = 3,
     318             : 
     319             :         SizeOfNonDefUVSTable = 5,
     320             :         NonDefUVSOffsetUnicodeValue = 0,
     321             :         NonDefUVSOffsetGlyphID = 3
     322             :     };
     323           0 :     NS_ENSURE_TRUE(aLength >= OffsetVarSelectorRecords,
     324             :                    NS_ERROR_GFX_CMAP_MALFORMED);
     325             : 
     326           0 :     NS_ENSURE_TRUE(ReadShortAt(aBuf, OffsetFormat) == 14, 
     327             :                    NS_ERROR_GFX_CMAP_MALFORMED);
     328             : 
     329           0 :     uint32_t tablelen = ReadLongAt(aBuf, OffsetTableLength);
     330           0 :     NS_ENSURE_TRUE(tablelen <= aLength, NS_ERROR_GFX_CMAP_MALFORMED);
     331           0 :     NS_ENSURE_TRUE(tablelen >= OffsetVarSelectorRecords,
     332             :                    NS_ERROR_GFX_CMAP_MALFORMED);
     333             : 
     334           0 :     const uint32_t numVarSelectorRecords = ReadLongAt(aBuf, OffsetNumVarSelectorRecords);
     335           0 :     NS_ENSURE_TRUE((tablelen - OffsetVarSelectorRecords) /
     336             :                    SizeOfVarSelectorRecord >= numVarSelectorRecords,
     337             :                    NS_ERROR_GFX_CMAP_MALFORMED);
     338             : 
     339           0 :     const uint8_t *records = aBuf + OffsetVarSelectorRecords;
     340           0 :     for (uint32_t i = 0; i < numVarSelectorRecords; 
     341           0 :          i++, records += SizeOfVarSelectorRecord) {
     342           0 :         const uint32_t varSelector = ReadUint24At(records, VSRecOffsetVarSelector);
     343           0 :         const uint32_t defUVSOffset = ReadLongAt(records, VSRecOffsetDefUVSOffset);
     344           0 :         const uint32_t nonDefUVSOffset = ReadLongAt(records, VSRecOffsetNonDefUVSOffset);
     345           0 :         NS_ENSURE_TRUE(varSelector <= CMAP_MAX_CODEPOINT &&
     346             :                        defUVSOffset <= tablelen - 4 &&
     347             :                        nonDefUVSOffset <= tablelen - 4, 
     348             :                        NS_ERROR_GFX_CMAP_MALFORMED);
     349             : 
     350           0 :         if (defUVSOffset) {
     351           0 :             const uint32_t numUnicodeValueRanges = ReadLongAt(aBuf, defUVSOffset);
     352           0 :             NS_ENSURE_TRUE((tablelen - defUVSOffset) /
     353             :                            SizeOfDefUVSTable >= numUnicodeValueRanges,
     354             :                            NS_ERROR_GFX_CMAP_MALFORMED);
     355           0 :             const uint8_t *tables = aBuf + defUVSOffset + 4;
     356           0 :             uint32_t prevEndUnicode = 0;
     357           0 :             for (uint32_t j = 0; j < numUnicodeValueRanges; j++, tables += SizeOfDefUVSTable) {
     358           0 :                 const uint32_t startUnicode = ReadUint24At(tables, DefUVSOffsetStartUnicodeValue);
     359           0 :                 const uint32_t endUnicode = startUnicode + tables[DefUVSOffsetAdditionalCount];
     360           0 :                 NS_ENSURE_TRUE((prevEndUnicode < startUnicode || j == 0) &&
     361             :                                endUnicode <= CMAP_MAX_CODEPOINT, 
     362             :                                NS_ERROR_GFX_CMAP_MALFORMED);
     363           0 :                 prevEndUnicode = endUnicode;
     364             :             }
     365             :         }
     366             : 
     367           0 :         if (nonDefUVSOffset) {
     368           0 :             const uint32_t numUVSMappings = ReadLongAt(aBuf, nonDefUVSOffset);
     369           0 :             NS_ENSURE_TRUE((tablelen - nonDefUVSOffset) /
     370             :                            SizeOfNonDefUVSTable >= numUVSMappings,
     371             :                            NS_ERROR_GFX_CMAP_MALFORMED);
     372           0 :             const uint8_t *tables = aBuf + nonDefUVSOffset + 4;
     373           0 :             uint32_t prevUnicode = 0;
     374           0 :             for (uint32_t j = 0; j < numUVSMappings; j++, tables += SizeOfNonDefUVSTable) {
     375           0 :                 const uint32_t unicodeValue = ReadUint24At(tables, NonDefUVSOffsetUnicodeValue);
     376           0 :                 NS_ENSURE_TRUE((prevUnicode < unicodeValue || j == 0) &&
     377             :                                unicodeValue <= CMAP_MAX_CODEPOINT, 
     378             :                                NS_ERROR_GFX_CMAP_MALFORMED);
     379           0 :                 prevUnicode = unicodeValue;
     380             :             }
     381             :         }
     382             :     }
     383             : 
     384           0 :     aTable = MakeUnique<uint8_t[]>(tablelen);
     385           0 :     memcpy(aTable.get(), aBuf, tablelen);
     386             : 
     387           0 :     return NS_OK;
     388             : }
     389             : 
     390             : // For fonts with two format-4 tables, the first one (Unicode platform) is preferred on the Mac;
     391             : // on other platforms we allow the Microsoft-platform subtable to replace it.
     392             : 
     393             : #if defined(XP_MACOSX)
     394             :     #define acceptableFormat4(p,e,k) (((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDMicrosoft && !(k)) || \
     395             :                                       ((p) == PLATFORM_ID_UNICODE))
     396             : 
     397             :     #define acceptableUCS4Encoding(p, e, k) \
     398             :         (((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDUCS4ForMicrosoftPlatform) && (k) != 12 || \
     399             :          ((p) == PLATFORM_ID_UNICODE   && \
     400             :           ((e) != EncodingIDUVSForUnicodePlatform)))
     401             : #else
     402             :     #define acceptableFormat4(p,e,k) (((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDMicrosoft) || \
     403             :                                       ((p) == PLATFORM_ID_UNICODE))
     404             : 
     405             :     #define acceptableUCS4Encoding(p, e, k) \
     406             :         ((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDUCS4ForMicrosoftPlatform)
     407             : #endif
     408             : 
     409             : #define acceptablePlatform(p) ((p) == PLATFORM_ID_UNICODE || (p) == PLATFORM_ID_MICROSOFT)
     410             : #define isSymbol(p,e)         ((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDSymbol)
     411             : #define isUVSEncoding(p, e)   ((p) == PLATFORM_ID_UNICODE && (e) == EncodingIDUVSForUnicodePlatform)
     412             : 
     413             : uint32_t
     414           0 : gfxFontUtils::FindPreferredSubtable(const uint8_t *aBuf, uint32_t aBufLength,
     415             :                                     uint32_t *aTableOffset,
     416             :                                     uint32_t *aUVSTableOffset,
     417             :                                     bool *aSymbolEncoding)
     418             : {
     419             :     enum {
     420             :         OffsetVersion = 0,
     421             :         OffsetNumTables = 2,
     422             :         SizeOfHeader = 4,
     423             : 
     424             :         TableOffsetPlatformID = 0,
     425             :         TableOffsetEncodingID = 2,
     426             :         TableOffsetOffset = 4,
     427             :         SizeOfTable = 8,
     428             : 
     429             :         SubtableOffsetFormat = 0
     430             :     };
     431             :     enum {
     432             :         EncodingIDSymbol = 0,
     433             :         EncodingIDMicrosoft = 1,
     434             :         EncodingIDDefaultForUnicodePlatform = 0,
     435             :         EncodingIDUCS4ForUnicodePlatform = 3,
     436             :         EncodingIDUVSForUnicodePlatform = 5,
     437             :         EncodingIDUCS4ForMicrosoftPlatform = 10
     438             :     };
     439             : 
     440           0 :     if (aUVSTableOffset) {
     441           0 :         *aUVSTableOffset = 0;
     442             :     }
     443             : 
     444           0 :     if (!aBuf || aBufLength < SizeOfHeader) {
     445             :         // cmap table is missing, or too small to contain header fields!
     446           0 :         return 0;
     447             :     }
     448             : 
     449             :     // uint16_t version = ReadShortAt(aBuf, OffsetVersion); // Unused: self-documenting.
     450           0 :     uint16_t numTables = ReadShortAt(aBuf, OffsetNumTables);
     451           0 :     if (aBufLength < uint32_t(SizeOfHeader + numTables * SizeOfTable)) {
     452           0 :         return 0;
     453             :     }
     454             : 
     455             :     // save the format we want here
     456           0 :     uint32_t keepFormat = 0;
     457             : 
     458           0 :     const uint8_t *table = aBuf + SizeOfHeader;
     459           0 :     for (uint16_t i = 0; i < numTables; ++i, table += SizeOfTable) {
     460           0 :         const uint16_t platformID = ReadShortAt(table, TableOffsetPlatformID);
     461           0 :         if (!acceptablePlatform(platformID))
     462           0 :             continue;
     463             : 
     464           0 :         const uint16_t encodingID = ReadShortAt(table, TableOffsetEncodingID);
     465           0 :         const uint32_t offset = ReadLongAt(table, TableOffsetOffset);
     466           0 :         if (aBufLength - 2 < offset) {
     467             :             // this subtable is not valid - beyond end of buffer
     468           0 :             return 0;
     469             :         }
     470             : 
     471           0 :         const uint8_t *subtable = aBuf + offset;
     472           0 :         const uint16_t format = ReadShortAt(subtable, SubtableOffsetFormat);
     473             : 
     474           0 :         if (isSymbol(platformID, encodingID)) {
     475           0 :             keepFormat = format;
     476           0 :             *aTableOffset = offset;
     477           0 :             *aSymbolEncoding = true;
     478           0 :             break;
     479           0 :         } else if (format == 4 && acceptableFormat4(platformID, encodingID, keepFormat)) {
     480           0 :             keepFormat = format;
     481           0 :             *aTableOffset = offset;
     482           0 :             *aSymbolEncoding = false;
     483           0 :         } else if ((format == 10 || format == 12 || format == 13) &&
     484           0 :                    acceptableUCS4Encoding(platformID, encodingID, keepFormat)) {
     485           0 :             keepFormat = format;
     486           0 :             *aTableOffset = offset;
     487           0 :             *aSymbolEncoding = false;
     488           0 :             if (platformID > PLATFORM_ID_UNICODE || !aUVSTableOffset || *aUVSTableOffset) {
     489             :                 break; // we don't want to try anything else when this format is available.
     490             :             }
     491           0 :         } else if (format == 14 && isUVSEncoding(platformID, encodingID) && aUVSTableOffset) {
     492           0 :             *aUVSTableOffset = offset;
     493           0 :             if (keepFormat == 10 || keepFormat == 12) {
     494             :                 break;
     495             :             }
     496             :         }
     497             :     }
     498             : 
     499           0 :     return keepFormat;
     500             : }
     501             : 
     502             : nsresult
     503           0 : gfxFontUtils::ReadCMAP(const uint8_t *aBuf, uint32_t aBufLength,
     504             :                        gfxSparseBitSet& aCharacterMap,
     505             :                        uint32_t& aUVSOffset,
     506             :                        bool& aUnicodeFont, bool& aSymbolFont)
     507             : {
     508             :     uint32_t offset;
     509             :     bool     symbol;
     510             :     uint32_t format = FindPreferredSubtable(aBuf, aBufLength,
     511           0 :                                             &offset, &aUVSOffset, &symbol);
     512             : 
     513           0 :     switch (format) {
     514             :     case 4:
     515           0 :         if (symbol) {
     516           0 :             aUnicodeFont = false;
     517           0 :             aSymbolFont = true;
     518             :         } else {
     519           0 :             aUnicodeFont = true;
     520           0 :             aSymbolFont = false;
     521             :         }
     522           0 :         return ReadCMAPTableFormat4(aBuf + offset, aBufLength - offset,
     523           0 :                                     aCharacterMap);
     524             : 
     525             :     case 10:
     526           0 :         aUnicodeFont = true;
     527           0 :         aSymbolFont = false;
     528           0 :         return ReadCMAPTableFormat10(aBuf + offset, aBufLength - offset,
     529           0 :                                      aCharacterMap);
     530             : 
     531             :     case 12:
     532             :     case 13:
     533           0 :         aUnicodeFont = true;
     534           0 :         aSymbolFont = false;
     535           0 :         return ReadCMAPTableFormat12or13(aBuf + offset, aBufLength - offset,
     536           0 :                                          aCharacterMap);
     537             : 
     538             :     default:
     539           0 :         break;
     540             :     }
     541             : 
     542           0 :     return NS_ERROR_FAILURE;
     543             : }
     544             : 
     545             : #pragma pack(1)
     546             : 
     547             : typedef struct {
     548             :     AutoSwap_PRUint16 format;
     549             :     AutoSwap_PRUint16 length;
     550             :     AutoSwap_PRUint16 language;
     551             :     AutoSwap_PRUint16 segCountX2;
     552             :     AutoSwap_PRUint16 searchRange;
     553             :     AutoSwap_PRUint16 entrySelector;
     554             :     AutoSwap_PRUint16 rangeShift;
     555             : 
     556             :     AutoSwap_PRUint16 arrays[1];
     557             : } Format4Cmap;
     558             : 
     559             : typedef struct {
     560             :     AutoSwap_PRUint16 format;
     561             :     AutoSwap_PRUint32 length;
     562             :     AutoSwap_PRUint32 numVarSelectorRecords;
     563             : 
     564             :     typedef struct {
     565             :         AutoSwap_PRUint24 varSelector;
     566             :         AutoSwap_PRUint32 defaultUVSOffset;
     567             :         AutoSwap_PRUint32 nonDefaultUVSOffset;
     568             :     } VarSelectorRecord;
     569             : 
     570             :     VarSelectorRecord varSelectorRecords[1];
     571             : } Format14Cmap;
     572             : 
     573             : typedef struct {
     574             :     AutoSwap_PRUint32 numUVSMappings;
     575             : 
     576             :     typedef struct {
     577             :         AutoSwap_PRUint24 unicodeValue;
     578             :         AutoSwap_PRUint16 glyphID;
     579             :     } UVSMapping;
     580             : 
     581             :     UVSMapping uvsMappings[1];
     582             : } NonDefUVSTable;
     583             : 
     584             : #pragma pack()
     585             : 
     586             : uint32_t
     587           0 : gfxFontUtils::MapCharToGlyphFormat4(const uint8_t *aBuf, char16_t aCh)
     588             : {
     589           0 :     const Format4Cmap *cmap4 = reinterpret_cast<const Format4Cmap*>(aBuf);
     590             :     uint16_t segCount;
     591             :     const AutoSwap_PRUint16 *endCodes;
     592             :     const AutoSwap_PRUint16 *startCodes;
     593             :     const AutoSwap_PRUint16 *idDelta;
     594             :     const AutoSwap_PRUint16 *idRangeOffset;
     595             :     uint16_t probe;
     596             :     uint16_t rangeShiftOver2;
     597             :     uint16_t index;
     598             : 
     599           0 :     segCount = (uint16_t)(cmap4->segCountX2) / 2;
     600             : 
     601           0 :     endCodes = &cmap4->arrays[0];
     602           0 :     startCodes = &cmap4->arrays[segCount + 1]; // +1 for reserved word between arrays
     603           0 :     idDelta = &startCodes[segCount];
     604           0 :     idRangeOffset = &idDelta[segCount];
     605             : 
     606           0 :     probe = 1 << (uint16_t)(cmap4->entrySelector);
     607           0 :     rangeShiftOver2 = (uint16_t)(cmap4->rangeShift) / 2;
     608             : 
     609           0 :     if ((uint16_t)(startCodes[rangeShiftOver2]) <= aCh) {
     610           0 :         index = rangeShiftOver2;
     611             :     } else {
     612           0 :         index = 0;
     613             :     }
     614             : 
     615           0 :     while (probe > 1) {
     616           0 :         probe >>= 1;
     617           0 :         if ((uint16_t)(startCodes[index + probe]) <= aCh) {
     618           0 :             index += probe;
     619             :         }
     620             :     }
     621             : 
     622           0 :     if (aCh >= (uint16_t)(startCodes[index]) && aCh <= (uint16_t)(endCodes[index])) {
     623             :         uint16_t result;
     624           0 :         if ((uint16_t)(idRangeOffset[index]) == 0) {
     625           0 :             result = aCh;
     626             :         } else {
     627           0 :             uint16_t offset = aCh - (uint16_t)(startCodes[index]);
     628             :             const AutoSwap_PRUint16 *glyphIndexTable =
     629           0 :                 (const AutoSwap_PRUint16*)((const char*)&idRangeOffset[index] +
     630           0 :                                            (uint16_t)(idRangeOffset[index]));
     631           0 :             result = glyphIndexTable[offset];
     632             :         }
     633             : 
     634             :         // note that this is unsigned 16-bit arithmetic, and may wrap around
     635           0 :         result += (uint16_t)(idDelta[index]);
     636           0 :         return result;
     637             :     }
     638             : 
     639           0 :     return 0;
     640             : }
     641             : 
     642             : uint32_t
     643           0 : gfxFontUtils::MapCharToGlyphFormat10(const uint8_t *aBuf, uint32_t aCh)
     644             : {
     645             :     const Format10CmapHeader *cmap10 =
     646           0 :         reinterpret_cast<const Format10CmapHeader*>(aBuf);
     647             : 
     648           0 :     uint32_t startChar = cmap10->startCharCode;
     649           0 :     uint32_t numChars = cmap10->numChars;
     650             : 
     651           0 :     if (aCh < startChar || aCh >= startChar + numChars) {
     652           0 :         return 0;
     653             :     }
     654             : 
     655             :     const AutoSwap_PRUint16 *glyphs =
     656           0 :         reinterpret_cast<const AutoSwap_PRUint16 *>(cmap10 + 1);
     657             : 
     658           0 :     uint16_t glyph = glyphs[aCh - startChar];
     659           0 :     return glyph;
     660             : }
     661             : 
     662             : uint32_t
     663           0 : gfxFontUtils::MapCharToGlyphFormat12or13(const uint8_t *aBuf, uint32_t aCh)
     664             : {
     665             :     // The only difference between formats 12 and 13 is the interpretation of
     666             :     // the glyphId field. So the code here uses the same "Format12" structures,
     667             :     // etc., to handle both subtable formats.
     668             : 
     669             :     const Format12CmapHeader *cmap12 =
     670           0 :         reinterpret_cast<const Format12CmapHeader*>(aBuf);
     671             : 
     672             :     // We know that numGroups is within range for the subtable size
     673             :     // because it was checked by ReadCMAPTableFormat12or13.
     674           0 :     uint32_t numGroups = cmap12->numGroups;
     675             : 
     676             :     // The array of groups immediately follows the subtable header.
     677             :     const Format12Group *groups =
     678           0 :         reinterpret_cast<const Format12Group*>(aBuf + sizeof(Format12CmapHeader));
     679             : 
     680             :     // For most efficient binary search, we want to work on a range that
     681             :     // is a power of 2 so that we can always halve it by shifting.
     682             :     // So we find the largest power of 2 that is <= numGroups.
     683             :     // We will offset this range by rangeOffset so as to reach the end
     684             :     // of the table, provided that doesn't put us beyond the target
     685             :     // value from the outset.
     686           0 :     uint32_t powerOf2 = mozilla::FindHighestBit(numGroups);
     687           0 :     uint32_t rangeOffset = numGroups - powerOf2;
     688           0 :     uint32_t range = 0;
     689             :     uint32_t startCharCode;
     690             : 
     691           0 :     if (groups[rangeOffset].startCharCode <= aCh) {
     692           0 :         range = rangeOffset;
     693             :     }
     694             : 
     695             :     // Repeatedly halve the size of the range until we find the target group
     696           0 :     while (powerOf2 > 1) {
     697           0 :         powerOf2 >>= 1;
     698           0 :         if (groups[range + powerOf2].startCharCode <= aCh) {
     699           0 :             range += powerOf2;
     700             :         }
     701             :     }
     702             : 
     703             :     // Check if the character is actually present in the range and return
     704             :     // the corresponding glyph ID. Here is where formats 12 and 13 interpret
     705             :     // the startGlyphId (12) or glyphId (13) field differently
     706           0 :     startCharCode = groups[range].startCharCode;
     707           0 :     if (startCharCode <= aCh && groups[range].endCharCode >= aCh) {
     708           0 :         return uint16_t(cmap12->format) == 12
     709           0 :                ? uint16_t(groups[range].startGlyphId) + aCh - startCharCode
     710           0 :                : uint16_t(groups[range].startGlyphId);
     711             :     }
     712             : 
     713             :     // Else it's not present, so return the .notdef glyph
     714           0 :     return 0;
     715             : }
     716             : 
     717             : namespace {
     718             : 
     719             : struct Format14CmapWrapper
     720             : {
     721             :     const Format14Cmap& mCmap14;
     722           0 :     explicit Format14CmapWrapper(const Format14Cmap& cmap14) : mCmap14(cmap14) {}
     723           0 :     uint32_t operator[](size_t index) const {
     724           0 :         return mCmap14.varSelectorRecords[index].varSelector;
     725             :     }
     726             : };
     727             : 
     728             : struct NonDefUVSTableWrapper
     729             : {
     730             :     const NonDefUVSTable& mTable;
     731           0 :     explicit NonDefUVSTableWrapper(const NonDefUVSTable& table) : mTable(table) {}
     732           0 :     uint32_t operator[](size_t index) const {
     733           0 :         return mTable.uvsMappings[index].unicodeValue;
     734             :     }
     735             : };
     736             : 
     737             : } // namespace
     738             : 
     739             : uint16_t
     740           0 : gfxFontUtils::MapUVSToGlyphFormat14(const uint8_t *aBuf, uint32_t aCh, uint32_t aVS)
     741             : {
     742             :     using mozilla::BinarySearch;
     743           0 :     const Format14Cmap *cmap14 = reinterpret_cast<const Format14Cmap*>(aBuf);
     744             : 
     745             :     size_t index;
     746           0 :     if (!BinarySearch(Format14CmapWrapper(*cmap14),
     747           0 :                       0, cmap14->numVarSelectorRecords, aVS, &index)) {
     748           0 :         return 0;
     749             :     }
     750             : 
     751           0 :     const uint32_t nonDefUVSOffset = cmap14->varSelectorRecords[index].nonDefaultUVSOffset;
     752           0 :     if (!nonDefUVSOffset) {
     753           0 :         return 0;
     754             :     }
     755             : 
     756             :     const NonDefUVSTable *table = reinterpret_cast<const NonDefUVSTable*>
     757           0 :                                       (aBuf + nonDefUVSOffset);
     758             : 
     759           0 :     if (BinarySearch(NonDefUVSTableWrapper(*table), 0, table->numUVSMappings,
     760           0 :                      aCh, &index)) {
     761           0 :         return table->uvsMappings[index].glyphID;
     762             :     }
     763             : 
     764           0 :     return 0;
     765             : }
     766             : 
     767             : uint32_t
     768           0 : gfxFontUtils::MapCharToGlyph(const uint8_t *aCmapBuf, uint32_t aBufLength,
     769             :                              uint32_t aUnicode, uint32_t aVarSelector)
     770             : {
     771             :     uint32_t offset, uvsOffset;
     772             :     bool     symbol;
     773             :     uint32_t format = FindPreferredSubtable(aCmapBuf, aBufLength, &offset,
     774           0 :                                             &uvsOffset, &symbol);
     775             : 
     776             :     uint32_t gid;
     777           0 :     switch (format) {
     778             :     case 4:
     779           0 :         gid = aUnicode < UNICODE_BMP_LIMIT ?
     780           0 :             MapCharToGlyphFormat4(aCmapBuf + offset, char16_t(aUnicode)) : 0;
     781           0 :         break;
     782             :     case 10:
     783           0 :         gid = MapCharToGlyphFormat10(aCmapBuf + offset, aUnicode);
     784           0 :         break;
     785             :     case 12:
     786             :     case 13:
     787           0 :         gid = MapCharToGlyphFormat12or13(aCmapBuf + offset, aUnicode);
     788           0 :         break;
     789             :     default:
     790           0 :         NS_WARNING("unsupported cmap format, glyphs will be missing");
     791           0 :         gid = 0;
     792             :     }
     793             : 
     794           0 :     if (aVarSelector && uvsOffset && gid) {
     795             :         uint32_t varGID =
     796           0 :             gfxFontUtils::MapUVSToGlyphFormat14(aCmapBuf + uvsOffset,
     797           0 :                                                 aUnicode, aVarSelector);
     798           0 :         if (!varGID) {
     799           0 :             aUnicode = gfxFontUtils::GetUVSFallback(aUnicode, aVarSelector);
     800           0 :             if (aUnicode) {
     801           0 :                 switch (format) {
     802             :                 case 4:
     803           0 :                     if (aUnicode < UNICODE_BMP_LIMIT) {
     804           0 :                         varGID = MapCharToGlyphFormat4(aCmapBuf + offset,
     805           0 :                                                        char16_t(aUnicode));
     806             :                     }
     807           0 :                     break;
     808             :                 case 10:
     809           0 :                     varGID = MapCharToGlyphFormat10(aCmapBuf + offset,
     810           0 :                                                     aUnicode);
     811           0 :                     break;
     812             :                 case 12:
     813             :                 case 13:
     814           0 :                     varGID = MapCharToGlyphFormat12or13(aCmapBuf + offset,
     815           0 :                                                         aUnicode);
     816           0 :                     break;
     817             :                 }
     818             :             }
     819             :         }
     820           0 :         if (varGID) {
     821           0 :             gid = varGID;
     822             :         }
     823             : 
     824             :         // else the variation sequence was not supported, use default mapping
     825             :         // of the character code alone
     826             :     }
     827             : 
     828           0 :     return gid;
     829             : }
     830             : 
     831           3 : void gfxFontUtils::ParseFontList(const nsAString& aFamilyList,
     832             :                                  nsTArray<nsString>& aFontList)
     833             : {
     834           3 :     const char16_t kComma = char16_t(',');
     835             :     
     836             :     // append each font name to the list
     837           6 :     nsAutoString fontname;
     838             :     const char16_t *p, *p_end;
     839           3 :     aFamilyList.BeginReading(p);
     840           3 :     aFamilyList.EndReading(p_end);
     841             : 
     842         135 :      while (p < p_end) {
     843          66 :         const char16_t *nameStart = p;
     844         606 :         while (++p != p_end && *p != kComma)
     845             :         /* nothing */ ;
     846             : 
     847             :         // pull out a single name and clean out leading/trailing whitespace        
     848          66 :         fontname = Substring(nameStart, p);
     849          66 :         fontname.CompressWhitespace(true, true);
     850             :         
     851             :         // append it to the list if it's not empty
     852          66 :         if (!fontname.IsEmpty()) {
     853          66 :             aFontList.AppendElement(fontname);
     854             :         }
     855          66 :         ++p;
     856             :     }
     857           3 : }
     858             : 
     859           6 : void gfxFontUtils::AppendPrefsFontList(const char *aPrefName,
     860             :                                        nsTArray<nsString>& aFontList)
     861             : {
     862             :     // get the list of single-face font families
     863           9 :     nsAdoptingString fontlistValue = Preferences::GetString(aPrefName);
     864           6 :     if (!fontlistValue) {
     865           3 :         return;
     866             :     }
     867             : 
     868           3 :     ParseFontList(fontlistValue, aFontList);
     869             : }
     870             : 
     871           6 : void gfxFontUtils::GetPrefsFontList(const char *aPrefName,
     872             :                                     nsTArray<nsString>& aFontList)
     873             : {
     874           6 :     aFontList.Clear();
     875           6 :     AppendPrefsFontList(aPrefName, aFontList);
     876           6 : }
     877             : 
     878             : // produce a unique font name that is (1) a valid Postscript name and (2) less
     879             : // than 31 characters in length.  Using AddFontMemResourceEx on Windows fails 
     880             : // for names longer than 30 characters in length.
     881             : 
     882             : #define MAX_B64_LEN 32
     883             : 
     884           0 : nsresult gfxFontUtils::MakeUniqueUserFontName(nsAString& aName)
     885             : {
     886             :     nsCOMPtr<nsIUUIDGenerator> uuidgen =
     887           0 :       do_GetService("@mozilla.org/uuid-generator;1");
     888           0 :     NS_ENSURE_TRUE(uuidgen, NS_ERROR_OUT_OF_MEMORY);
     889             : 
     890             :     nsID guid;
     891             : 
     892             :     NS_ASSERTION(sizeof(guid) * 2 <= MAX_B64_LEN, "size of nsID has changed!");
     893             : 
     894           0 :     nsresult rv = uuidgen->GenerateUUIDInPlace(&guid);
     895           0 :     NS_ENSURE_SUCCESS(rv, rv);
     896             : 
     897           0 :     char guidB64[MAX_B64_LEN] = {0};
     898             : 
     899           0 :     if (!PL_Base64Encode(reinterpret_cast<char*>(&guid), sizeof(guid), guidB64))
     900           0 :         return NS_ERROR_FAILURE;
     901             : 
     902             :     // all b64 characters except for '/' are allowed in Postscript names, so convert / ==> -
     903             :     char *p;
     904           0 :     for (p = guidB64; *p; p++) {
     905           0 :         if (*p == '/')
     906           0 :             *p = '-';
     907             :     }
     908             : 
     909           0 :     aName.AssignLiteral(u"uf");
     910           0 :     aName.AppendASCII(guidB64);
     911           0 :     return NS_OK;
     912             : }
     913             : 
     914             : 
     915             : // TrueType/OpenType table handling code
     916             : 
     917             : // need byte aligned structs
     918             : #pragma pack(1)
     919             : 
     920             : // name table stores set of name record structures, followed by
     921             : // large block containing all the strings.  name record offset and length
     922             : // indicates the offset and length within that block.
     923             : // http://www.microsoft.com/typography/otspec/name.htm
     924             : struct NameRecordData {
     925             :     uint32_t  offset;
     926             :     uint32_t  length;
     927             : };
     928             : 
     929             : #pragma pack()
     930             : 
     931             : static bool
     932           0 : IsValidSFNTVersion(uint32_t version)
     933             : {
     934             :     // normally 0x00010000, CFF-style OT fonts == 'OTTO' and Apple TT fonts = 'true'
     935             :     // 'typ1' is also possible for old Type 1 fonts in a SFNT container but not supported
     936           0 :     return version == 0x10000 ||
     937           0 :            version == TRUETYPE_TAG('O','T','T','O') ||
     938           0 :            version == TRUETYPE_TAG('t','r','u','e');
     939             : }
     940             : 
     941             : // Copy and swap UTF-16 values, assume no surrogate pairs, can be in place.
     942             : // aInBuf and aOutBuf are NOT necessarily 16-bit-aligned, so we should avoid
     943             : // accessing them directly as uint16_t* values.
     944             : // aLen is count of UTF-16 values, so the byte buffers are twice that.
     945             : static void
     946           0 : CopySwapUTF16(const char* aInBuf, char* aOutBuf, uint32_t aLen)
     947             : {
     948           0 :     const char* end = aInBuf + aLen * 2;
     949           0 :     while (aInBuf < end) {
     950           0 :         uint8_t b0 = *aInBuf++;
     951           0 :         *aOutBuf++ = *aInBuf++;
     952           0 :         *aOutBuf++ = b0;
     953             :     }
     954           0 : }
     955             : 
     956             : gfxUserFontType
     957           0 : gfxFontUtils::DetermineFontDataType(const uint8_t *aFontData, uint32_t aFontDataLength)
     958             : {
     959             :     // test for OpenType font data
     960             :     // problem: EOT-Lite with 0x10000 length will look like TrueType!
     961           0 :     if (aFontDataLength >= sizeof(SFNTHeader)) {
     962           0 :         const SFNTHeader *sfntHeader = reinterpret_cast<const SFNTHeader*>(aFontData);
     963           0 :         uint32_t sfntVersion = sfntHeader->sfntVersion;
     964           0 :         if (IsValidSFNTVersion(sfntVersion)) {
     965           0 :             return GFX_USERFONT_OPENTYPE;
     966             :         }
     967             :     }
     968             :     
     969             :     // test for WOFF
     970           0 :     if (aFontDataLength >= sizeof(AutoSwap_PRUint32)) {
     971             :         const AutoSwap_PRUint32 *version = 
     972           0 :             reinterpret_cast<const AutoSwap_PRUint32*>(aFontData);
     973           0 :         if (uint32_t(*version) == TRUETYPE_TAG('w','O','F','F')) {
     974           0 :             return GFX_USERFONT_WOFF;
     975             :         }
     976           0 :         if (Preferences::GetBool(GFX_PREF_WOFF2_ENABLED) &&
     977           0 :             uint32_t(*version) == TRUETYPE_TAG('w','O','F','2')) {
     978           0 :             return GFX_USERFONT_WOFF2;
     979             :         }
     980             :     }
     981             :     
     982             :     // tests for other formats here
     983             :     
     984           0 :     return GFX_USERFONT_UNKNOWN;
     985             : }
     986             : 
     987             : static int
     988           0 : DirEntryCmp(const void* aKey, const void* aItem)
     989             : {
     990           0 :     int32_t tag = *static_cast<const int32_t*>(aKey);
     991           0 :     const TableDirEntry* entry = static_cast<const TableDirEntry*>(aItem);
     992           0 :     return tag - int32_t(entry->tag);
     993             : }
     994             : 
     995             : /* static */
     996             : TableDirEntry*
     997           0 : gfxFontUtils::FindTableDirEntry(const void* aFontData, uint32_t aTableTag)
     998             : {
     999             :     const SFNTHeader* header =
    1000           0 :         reinterpret_cast<const SFNTHeader*>(aFontData);
    1001             :     const TableDirEntry* dir =
    1002           0 :         reinterpret_cast<const TableDirEntry*>(header + 1);
    1003             :     return static_cast<TableDirEntry*>
    1004           0 :         (bsearch(&aTableTag, dir, uint16_t(header->numTables),
    1005           0 :                  sizeof(TableDirEntry), DirEntryCmp));
    1006             : }
    1007             : 
    1008             : /* static */
    1009             : hb_blob_t*
    1010           0 : gfxFontUtils::GetTableFromFontData(const void* aFontData, uint32_t aTableTag)
    1011             : {
    1012           0 :     const TableDirEntry* dir = FindTableDirEntry(aFontData, aTableTag);
    1013           0 :     if (dir) {
    1014           0 :         return hb_blob_create(reinterpret_cast<const char*>(aFontData) +
    1015           0 :                                   dir->offset, dir->length,
    1016           0 :                               HB_MEMORY_MODE_READONLY, nullptr, nullptr);
    1017             : 
    1018             :     }
    1019           0 :     return nullptr;
    1020             : }
    1021             : 
    1022             : nsresult
    1023           0 : gfxFontUtils::RenameFont(const nsAString& aName, const uint8_t *aFontData, 
    1024             :                          uint32_t aFontDataLength, FallibleTArray<uint8_t> *aNewFont)
    1025             : {
    1026           0 :     NS_ASSERTION(aNewFont, "null font data array");
    1027             :     
    1028           0 :     uint64_t dataLength(aFontDataLength);
    1029             : 
    1030             :     // new name table
    1031             :     static const uint32_t neededNameIDs[] = {NAME_ID_FAMILY, 
    1032             :                                              NAME_ID_STYLE,
    1033             :                                              NAME_ID_UNIQUE,
    1034             :                                              NAME_ID_FULL,
    1035             :                                              NAME_ID_POSTSCRIPT};
    1036             : 
    1037             :     // calculate new name table size
    1038           0 :     uint16_t nameCount = ArrayLength(neededNameIDs);
    1039             : 
    1040             :     // leave room for null-terminator
    1041           0 :     uint32_t nameStrLength = (aName.Length() + 1) * sizeof(char16_t);
    1042           0 :     if (nameStrLength > 65535) {
    1043             :         // The name length _in bytes_ must fit in an unsigned short field;
    1044             :         // therefore, a name longer than this cannot be used.
    1045           0 :         return NS_ERROR_FAILURE;
    1046             :     }
    1047             : 
    1048             :     // round name table size up to 4-byte multiple
    1049             :     uint32_t nameTableSize = (sizeof(NameHeader) +
    1050           0 :                               sizeof(NameRecord) * nameCount +
    1051           0 :                               nameStrLength +
    1052           0 :                               3) & ~3;
    1053             :                               
    1054           0 :     if (dataLength + nameTableSize > UINT32_MAX)
    1055           0 :         return NS_ERROR_FAILURE;
    1056             :         
    1057             :     // bug 505386 - need to handle unpadded font length
    1058           0 :     uint32_t paddedFontDataSize = (aFontDataLength + 3) & ~3;
    1059           0 :     uint32_t adjFontDataSize = paddedFontDataSize + nameTableSize;
    1060             : 
    1061             :     // create new buffer: old font data plus new name table
    1062           0 :     if (!aNewFont->AppendElements(adjFontDataSize, fallible))
    1063           0 :         return NS_ERROR_OUT_OF_MEMORY;
    1064             : 
    1065             :     // copy the old font data
    1066           0 :     uint8_t *newFontData = reinterpret_cast<uint8_t*>(aNewFont->Elements());
    1067             :     
    1068             :     // null the last four bytes in case the font length is not a multiple of 4
    1069           0 :     memset(newFontData + aFontDataLength, 0, paddedFontDataSize - aFontDataLength);
    1070             : 
    1071             :     // copy font data
    1072           0 :     memcpy(newFontData, aFontData, aFontDataLength);
    1073             :     
    1074             :     // null out the last 4 bytes for checksum calculations
    1075           0 :     memset(newFontData + adjFontDataSize - 4, 0, 4);
    1076             :     
    1077           0 :     NameHeader *nameHeader = reinterpret_cast<NameHeader*>(newFontData +
    1078           0 :                                                             paddedFontDataSize);
    1079             :     
    1080             :     // -- name header
    1081           0 :     nameHeader->format = 0;
    1082           0 :     nameHeader->count = nameCount;
    1083           0 :     nameHeader->stringOffset = sizeof(NameHeader) + nameCount * sizeof(NameRecord);
    1084             :     
    1085             :     // -- name records
    1086             :     uint32_t i;
    1087           0 :     NameRecord *nameRecord = reinterpret_cast<NameRecord*>(nameHeader + 1);
    1088             :     
    1089           0 :     for (i = 0; i < nameCount; i++, nameRecord++) {
    1090           0 :         nameRecord->platformID = PLATFORM_ID_MICROSOFT;
    1091           0 :         nameRecord->encodingID = ENCODING_ID_MICROSOFT_UNICODEBMP;
    1092           0 :         nameRecord->languageID = LANG_ID_MICROSOFT_EN_US;
    1093           0 :         nameRecord->nameID = neededNameIDs[i];
    1094           0 :         nameRecord->offset = 0;
    1095           0 :         nameRecord->length = nameStrLength;
    1096             :     }
    1097             :     
    1098             :     // -- string data, located after the name records, stored in big-endian form
    1099           0 :     char16_t *strData = reinterpret_cast<char16_t*>(nameRecord);
    1100             : 
    1101           0 :     mozilla::NativeEndian::copyAndSwapToBigEndian(strData,
    1102             :                                                   aName.BeginReading(),
    1103           0 :                                                   aName.Length());
    1104           0 :     strData[aName.Length()] = 0; // add null termination
    1105             :     
    1106             :     // adjust name table header to point to the new name table
    1107           0 :     SFNTHeader *sfntHeader = reinterpret_cast<SFNTHeader*>(newFontData);
    1108             : 
    1109             :     // table directory entries begin immediately following SFNT header
    1110             :     TableDirEntry *dirEntry =
    1111           0 :         FindTableDirEntry(newFontData, TRUETYPE_TAG('n','a','m','e'));
    1112             :     // function only called if font validates, so this should always be true
    1113           0 :     MOZ_ASSERT(dirEntry, "attempt to rename font with no name table");
    1114             : 
    1115           0 :     uint32_t numTables = sfntHeader->numTables;
    1116             :     
    1117             :     // note: dirEntry now points to 'name' table record
    1118             :     
    1119             :     // recalculate name table checksum
    1120           0 :     uint32_t checkSum = 0;
    1121           0 :     AutoSwap_PRUint32 *nameData = reinterpret_cast<AutoSwap_PRUint32*> (nameHeader);
    1122           0 :     AutoSwap_PRUint32 *nameDataEnd = nameData + (nameTableSize >> 2);
    1123             :     
    1124           0 :     while (nameData < nameDataEnd)
    1125           0 :         checkSum = checkSum + *nameData++;
    1126             :     
    1127             :     // adjust name table entry to point to new name table
    1128           0 :     dirEntry->offset = paddedFontDataSize;
    1129           0 :     dirEntry->length = nameTableSize;
    1130           0 :     dirEntry->checkSum = checkSum;
    1131             :     
    1132             :     // fix up checksums
    1133           0 :     uint32_t checksum = 0;
    1134             :     
    1135             :     // checksum for font = (checksum of header) + (checksum of tables)
    1136           0 :     uint32_t headerLen = sizeof(SFNTHeader) + sizeof(TableDirEntry) * numTables;
    1137             :     const AutoSwap_PRUint32 *headerData = 
    1138           0 :         reinterpret_cast<const AutoSwap_PRUint32*>(newFontData);
    1139             : 
    1140             :     // header length is in bytes, checksum calculated in longwords
    1141           0 :     for (i = 0; i < (headerLen >> 2); i++, headerData++) {
    1142           0 :         checksum += *headerData;
    1143             :     }
    1144             :     
    1145           0 :     uint32_t headOffset = 0;
    1146           0 :     dirEntry = reinterpret_cast<TableDirEntry*>(newFontData + sizeof(SFNTHeader));
    1147             : 
    1148           0 :     for (i = 0; i < numTables; i++, dirEntry++) {
    1149           0 :         if (dirEntry->tag == TRUETYPE_TAG('h','e','a','d')) {
    1150           0 :             headOffset = dirEntry->offset;
    1151             :         }
    1152           0 :         checksum += dirEntry->checkSum;
    1153             :     }
    1154             :     
    1155           0 :     NS_ASSERTION(headOffset != 0, "no head table for font");
    1156             :     
    1157           0 :     HeadTable *headData = reinterpret_cast<HeadTable*>(newFontData + headOffset);
    1158             : 
    1159           0 :     headData->checkSumAdjustment = HeadTable::HEAD_CHECKSUM_CALC_CONST - checksum;
    1160             : 
    1161           0 :     return NS_OK;
    1162             : }
    1163             : 
    1164             : // This is only called after the basic validity of the downloaded sfnt
    1165             : // data has been checked, so it should never fail to find the name table
    1166             : // (though it might fail to read it, if memory isn't available);
    1167             : // other checks here are just for extra paranoia.
    1168             : nsresult
    1169           0 : gfxFontUtils::GetFullNameFromSFNT(const uint8_t* aFontData, uint32_t aLength,
    1170             :                                   nsAString& aFullName)
    1171             : {
    1172           0 :     aFullName.AssignLiteral("(MISSING NAME)"); // should always get replaced
    1173             : 
    1174             :     const TableDirEntry *dirEntry =
    1175           0 :         FindTableDirEntry(aFontData, TRUETYPE_TAG('n','a','m','e'));
    1176             :     
    1177             :     // should never fail, as we're only called after font validation succeeded
    1178           0 :     NS_ENSURE_TRUE(dirEntry, NS_ERROR_NOT_AVAILABLE);
    1179             : 
    1180           0 :     uint32_t len = dirEntry->length;
    1181           0 :     NS_ENSURE_TRUE(aLength > len && aLength - len >= dirEntry->offset,
    1182             :                    NS_ERROR_UNEXPECTED);
    1183             : 
    1184             :     hb_blob_t *nameBlob =
    1185           0 :         hb_blob_create((const char*)aFontData + dirEntry->offset, len,
    1186           0 :                        HB_MEMORY_MODE_READONLY, nullptr, nullptr);
    1187           0 :     nsresult rv = GetFullNameFromTable(nameBlob, aFullName);
    1188           0 :     hb_blob_destroy(nameBlob);
    1189             : 
    1190           0 :     return rv;
    1191             : }
    1192             : 
    1193             : nsresult
    1194           0 : gfxFontUtils::GetFullNameFromTable(hb_blob_t *aNameTable,
    1195             :                                    nsAString& aFullName)
    1196             : {
    1197           0 :     nsAutoString name;
    1198             :     nsresult rv =
    1199             :         gfxFontUtils::ReadCanonicalName(aNameTable,
    1200             :                                         gfxFontUtils::NAME_ID_FULL,
    1201           0 :                                         name);
    1202           0 :     if (NS_SUCCEEDED(rv) && !name.IsEmpty()) {
    1203           0 :         aFullName = name;
    1204           0 :         return NS_OK;
    1205             :     }
    1206             :     rv = gfxFontUtils::ReadCanonicalName(aNameTable,
    1207             :                                          gfxFontUtils::NAME_ID_FAMILY,
    1208           0 :                                          name);
    1209           0 :     if (NS_SUCCEEDED(rv) && !name.IsEmpty()) {
    1210           0 :         nsAutoString styleName;
    1211             :         rv = gfxFontUtils::ReadCanonicalName(aNameTable,
    1212             :                                              gfxFontUtils::NAME_ID_STYLE,
    1213           0 :                                              styleName);
    1214           0 :         if (NS_SUCCEEDED(rv) && !styleName.IsEmpty()) {
    1215           0 :             name.Append(' ');
    1216           0 :             name.Append(styleName);
    1217           0 :             aFullName = name;
    1218             :         }
    1219           0 :         return NS_OK;
    1220             :     }
    1221             : 
    1222           0 :     return NS_ERROR_NOT_AVAILABLE;
    1223             : }
    1224             : 
    1225             : nsresult
    1226           0 : gfxFontUtils::GetFamilyNameFromTable(hb_blob_t *aNameTable,
    1227             :                                      nsAString& aFullName)
    1228             : {
    1229           0 :     nsAutoString name;
    1230             :     nsresult rv =
    1231             :         gfxFontUtils::ReadCanonicalName(aNameTable,
    1232             :                                         gfxFontUtils::NAME_ID_FAMILY,
    1233           0 :                                         name);
    1234           0 :     if (NS_SUCCEEDED(rv) && !name.IsEmpty()) {
    1235           0 :         aFullName = name;
    1236           0 :         return NS_OK;
    1237             :     }
    1238           0 :     return NS_ERROR_NOT_AVAILABLE;
    1239             : }
    1240             : 
    1241             : enum {
    1242             : #if defined(XP_MACOSX)
    1243             :     CANONICAL_LANG_ID = gfxFontUtils::LANG_ID_MAC_ENGLISH,
    1244             :     PLATFORM_ID       = gfxFontUtils::PLATFORM_ID_MAC
    1245             : #else
    1246             :     CANONICAL_LANG_ID = gfxFontUtils::LANG_ID_MICROSOFT_EN_US,
    1247             :     PLATFORM_ID       = gfxFontUtils::PLATFORM_ID_MICROSOFT
    1248             : #endif
    1249             : };    
    1250             : 
    1251             : nsresult
    1252           0 : gfxFontUtils::ReadNames(const char *aNameData, uint32_t aDataLen,
    1253             :                         uint32_t aNameID, int32_t aPlatformID,
    1254             :                         nsTArray<nsString>& aNames)
    1255             : {
    1256             :     return ReadNames(aNameData, aDataLen, aNameID, LANG_ALL,
    1257           0 :                      aPlatformID, aNames);
    1258             : }
    1259             : 
    1260             : nsresult
    1261           0 : gfxFontUtils::ReadCanonicalName(hb_blob_t *aNameTable, uint32_t aNameID,
    1262             :                                 nsString& aName)
    1263             : {
    1264             :     uint32_t nameTableLen;
    1265           0 :     const char *nameTable = hb_blob_get_data(aNameTable, &nameTableLen);
    1266           0 :     return ReadCanonicalName(nameTable, nameTableLen, aNameID, aName);
    1267             : }
    1268             : 
    1269             : nsresult
    1270           0 : gfxFontUtils::ReadCanonicalName(const char *aNameData, uint32_t aDataLen,
    1271             :                                 uint32_t aNameID, nsString& aName)
    1272             : {
    1273             :     nsresult rv;
    1274             :     
    1275           0 :     nsTArray<nsString> names;
    1276             :     
    1277             :     // first, look for the English name (this will succeed 99% of the time)
    1278             :     rv = ReadNames(aNameData, aDataLen, aNameID, CANONICAL_LANG_ID, 
    1279           0 :                    PLATFORM_ID, names);
    1280           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1281             :         
    1282             :     // otherwise, grab names for all languages
    1283           0 :     if (names.Length() == 0) {
    1284             :         rv = ReadNames(aNameData, aDataLen, aNameID, LANG_ALL,
    1285           0 :                        PLATFORM_ID, names);
    1286           0 :         NS_ENSURE_SUCCESS(rv, rv);
    1287             :     }
    1288             :     
    1289             : #if defined(XP_MACOSX)
    1290             :     // may be dealing with font that only has Microsoft name entries
    1291             :     if (names.Length() == 0) {
    1292             :         rv = ReadNames(aNameData, aDataLen, aNameID, LANG_ID_MICROSOFT_EN_US,
    1293             :                        PLATFORM_ID_MICROSOFT, names);
    1294             :         NS_ENSURE_SUCCESS(rv, rv);
    1295             :         
    1296             :         // getting really desperate now, take anything!
    1297             :         if (names.Length() == 0) {
    1298             :             rv = ReadNames(aNameData, aDataLen, aNameID, LANG_ALL,
    1299             :                            PLATFORM_ID_MICROSOFT, names);
    1300             :             NS_ENSURE_SUCCESS(rv, rv);
    1301             :         }
    1302             :     }
    1303             : #endif
    1304             : 
    1305             :     // return the first name (99.9% of the time names will
    1306             :     // contain a single English name)
    1307           0 :     if (names.Length()) {
    1308           0 :         aName.Assign(names[0]);
    1309           0 :         return NS_OK;
    1310             :     }
    1311             :         
    1312           0 :     return NS_ERROR_FAILURE;
    1313             : }
    1314             : 
    1315             : // Charsets to use for decoding Mac platform font names.
    1316             : // This table is sorted by {encoding, language}, with the wildcard "ANY" being
    1317             : // greater than any defined values for each field; we use a binary search on both
    1318             : // fields, and fall back to matching only encoding if necessary
    1319             : 
    1320             : // Some "redundant" entries for specific combinations are included such as
    1321             : // encoding=roman, lang=english, in order that common entries will be found
    1322             : // on the first search.
    1323             : 
    1324             : #define ANY 0xffff
    1325             : const gfxFontUtils::MacFontNameCharsetMapping gfxFontUtils::gMacFontNameCharsets[] =
    1326             : {
    1327             :     { ENCODING_ID_MAC_ROMAN,        LANG_ID_MAC_ENGLISH,      "macintosh"       },
    1328             :     { ENCODING_ID_MAC_ROMAN,        LANG_ID_MAC_ICELANDIC,    "x-mac-icelandic" },
    1329             :     { ENCODING_ID_MAC_ROMAN,        LANG_ID_MAC_TURKISH,      "x-mac-turkish"   },
    1330             :     { ENCODING_ID_MAC_ROMAN,        LANG_ID_MAC_POLISH,       "x-mac-ce"        },
    1331             :     { ENCODING_ID_MAC_ROMAN,        LANG_ID_MAC_ROMANIAN,     "x-mac-romanian"  },
    1332             :     { ENCODING_ID_MAC_ROMAN,        LANG_ID_MAC_CZECH,        "x-mac-ce"        },
    1333             :     { ENCODING_ID_MAC_ROMAN,        LANG_ID_MAC_SLOVAK,       "x-mac-ce"        },
    1334             :     { ENCODING_ID_MAC_ROMAN,        ANY,                      "macintosh"       },
    1335             :     { ENCODING_ID_MAC_JAPANESE,     LANG_ID_MAC_JAPANESE,     "Shift_JIS"       },
    1336             :     { ENCODING_ID_MAC_JAPANESE,     ANY,                      "Shift_JIS"       },
    1337             :     { ENCODING_ID_MAC_TRAD_CHINESE, LANG_ID_MAC_TRAD_CHINESE, "Big5"            },
    1338             :     { ENCODING_ID_MAC_TRAD_CHINESE, ANY,                      "Big5"            },
    1339             :     { ENCODING_ID_MAC_KOREAN,       LANG_ID_MAC_KOREAN,       "EUC-KR"          },
    1340             :     { ENCODING_ID_MAC_KOREAN,       ANY,                      "EUC-KR"          },
    1341             :     { ENCODING_ID_MAC_ARABIC,       LANG_ID_MAC_ARABIC,       "x-mac-arabic"    },
    1342             :     { ENCODING_ID_MAC_ARABIC,       LANG_ID_MAC_URDU,         "x-mac-farsi"     },
    1343             :     { ENCODING_ID_MAC_ARABIC,       LANG_ID_MAC_FARSI,        "x-mac-farsi"     },
    1344             :     { ENCODING_ID_MAC_ARABIC,       ANY,                      "x-mac-arabic"    },
    1345             :     { ENCODING_ID_MAC_HEBREW,       LANG_ID_MAC_HEBREW,       "x-mac-hebrew"    },
    1346             :     { ENCODING_ID_MAC_HEBREW,       ANY,                      "x-mac-hebrew"    },
    1347             :     { ENCODING_ID_MAC_GREEK,        ANY,                      "x-mac-greek"     },
    1348             :     { ENCODING_ID_MAC_CYRILLIC,     ANY,                      "x-mac-cyrillic"  },
    1349             :     { ENCODING_ID_MAC_DEVANAGARI,   ANY,                      "x-mac-devanagari"},
    1350             :     { ENCODING_ID_MAC_GURMUKHI,     ANY,                      "x-mac-gurmukhi"  },
    1351             :     { ENCODING_ID_MAC_GUJARATI,     ANY,                      "x-mac-gujarati"  },
    1352             :     { ENCODING_ID_MAC_SIMP_CHINESE, LANG_ID_MAC_SIMP_CHINESE, "gb18030"         },
    1353             :     { ENCODING_ID_MAC_SIMP_CHINESE, ANY,                      "gb18030"         }
    1354             : };
    1355             : 
    1356             : const char* gfxFontUtils::gISOFontNameCharsets[] = 
    1357             : {
    1358             :     /* 0 */ "windows-1252", /* US-ASCII */
    1359             :     /* 1 */ nullptr       , /* spec says "ISO 10646" but does not specify encoding form! */
    1360             :     /* 2 */ "windows-1252"  /* ISO-8859-1 */
    1361             : };
    1362             : 
    1363             : const char* gfxFontUtils::gMSFontNameCharsets[] =
    1364             : {
    1365             :     /* [0] ENCODING_ID_MICROSOFT_SYMBOL */      ""          ,
    1366             :     /* [1] ENCODING_ID_MICROSOFT_UNICODEBMP */  ""          ,
    1367             :     /* [2] ENCODING_ID_MICROSOFT_SHIFTJIS */    "Shift_JIS" ,
    1368             :     /* [3] ENCODING_ID_MICROSOFT_PRC */         nullptr      ,
    1369             :     /* [4] ENCODING_ID_MICROSOFT_BIG5 */        "Big5"      ,
    1370             :     /* [5] ENCODING_ID_MICROSOFT_WANSUNG */     nullptr      ,
    1371             :     /* [6] ENCODING_ID_MICROSOFT_JOHAB */       nullptr      ,
    1372             :     /* [7] reserved */                          nullptr      ,
    1373             :     /* [8] reserved */                          nullptr      ,
    1374             :     /* [9] reserved */                          nullptr      ,
    1375             :     /*[10] ENCODING_ID_MICROSOFT_UNICODEFULL */ ""
    1376             : };
    1377             : 
    1378             : struct MacCharsetMappingComparator
    1379             : {
    1380             :     typedef gfxFontUtils::MacFontNameCharsetMapping MacFontNameCharsetMapping;
    1381             :     const MacFontNameCharsetMapping& mSearchValue;
    1382           0 :     explicit MacCharsetMappingComparator(const MacFontNameCharsetMapping& aSearchValue)
    1383           0 :       : mSearchValue(aSearchValue) {}
    1384           0 :     int operator()(const MacFontNameCharsetMapping& aEntry) const {
    1385           0 :         if (mSearchValue < aEntry) {
    1386           0 :             return -1;
    1387             :         }
    1388           0 :         if (aEntry < mSearchValue) {
    1389           0 :             return 1;
    1390             :         }
    1391           0 :         return 0;
    1392             :     }
    1393             : };
    1394             : 
    1395             : // Return the name of the charset we should use to decode a font name
    1396             : // given the name table attributes.
    1397             : // Special return values:
    1398             : //    ""       charset is UTF16BE, no need for a converter
    1399             : //    nullptr   unknown charset, do not attempt conversion
    1400             : const char*
    1401           0 : gfxFontUtils::GetCharsetForFontName(uint16_t aPlatform, uint16_t aScript, uint16_t aLanguage)
    1402             : {
    1403           0 :     switch (aPlatform)
    1404             :     {
    1405             :     case PLATFORM_ID_UNICODE:
    1406           0 :         return "";
    1407             : 
    1408             :     case PLATFORM_ID_MAC:
    1409             :         {
    1410           0 :             MacFontNameCharsetMapping searchValue = { aScript, aLanguage, nullptr };
    1411           0 :             for (uint32_t i = 0; i < 2; ++i) {
    1412             :                 size_t idx;
    1413           0 :                 if (BinarySearchIf(gMacFontNameCharsets, 0, ArrayLength(gMacFontNameCharsets),
    1414           0 :                                             MacCharsetMappingComparator(searchValue), &idx)) {
    1415           0 :                     return gMacFontNameCharsets[idx].mCharsetName;
    1416             :                 }
    1417             : 
    1418             :                 // no match, so try again finding one in any language
    1419           0 :                 searchValue.mLanguage = ANY;
    1420             :             }
    1421             :         }
    1422           0 :         break;
    1423             : 
    1424             :     case PLATFORM_ID_ISO:
    1425           0 :         if (aScript < ArrayLength(gISOFontNameCharsets)) {
    1426           0 :             return gISOFontNameCharsets[aScript];
    1427             :         }
    1428           0 :         break;
    1429             : 
    1430             :     case PLATFORM_ID_MICROSOFT:
    1431           0 :         if (aScript < ArrayLength(gMSFontNameCharsets)) {
    1432           0 :             return gMSFontNameCharsets[aScript];
    1433             :         }
    1434           0 :         break;
    1435             :     }
    1436             : 
    1437           0 :     return nullptr;
    1438             : }
    1439             : 
    1440             : template<int N>
    1441             : static bool
    1442           0 : StartsWith(const nsACString& string, const char (&prefix)[N])
    1443             : {
    1444           0 :   if (N - 1 > string.Length()) {
    1445           0 :     return false;
    1446             :   }
    1447           0 :   return memcmp(string.Data(), prefix, N - 1) == 0;
    1448             : }
    1449             : 
    1450             : // convert a raw name from the name table to an nsString, if possible;
    1451             : // return value indicates whether conversion succeeded
    1452             : bool
    1453           0 : gfxFontUtils::DecodeFontName(const char *aNameData, int32_t aByteLen, 
    1454             :                              uint32_t aPlatformCode, uint32_t aScriptCode,
    1455             :                              uint32_t aLangCode, nsAString& aName)
    1456             : {
    1457           0 :     if (aByteLen <= 0) {
    1458           0 :         NS_WARNING("empty font name");
    1459           0 :         aName.SetLength(0);
    1460           0 :         return true;
    1461             :     }
    1462             : 
    1463           0 :     const char *csName = GetCharsetForFontName(aPlatformCode, aScriptCode, aLangCode);
    1464             : 
    1465           0 :     if (!csName) {
    1466             :         // nullptr -> unknown charset
    1467             : #ifdef DEBUG
    1468             :         char warnBuf[128];
    1469           0 :         if (aByteLen > 64)
    1470           0 :             aByteLen = 64;
    1471             :         SprintfLiteral(warnBuf, "skipping font name, unknown charset %d:%d:%d for <%.*s>",
    1472           0 :                        aPlatformCode, aScriptCode, aLangCode, aByteLen, aNameData);
    1473           0 :         NS_WARNING(warnBuf);
    1474             : #endif
    1475           0 :         return false;
    1476             :     }
    1477             : 
    1478           0 :     if (csName[0] == 0) {
    1479             :         // empty charset name: data is utf16be, no need to instantiate a converter
    1480           0 :         uint32_t strLen = aByteLen / 2;
    1481           0 :         aName.SetLength(strLen);
    1482             : #ifdef IS_LITTLE_ENDIAN
    1483           0 :         CopySwapUTF16(aNameData, reinterpret_cast<char*>(aName.BeginWriting()),
    1484           0 :                       strLen);
    1485             : #else
    1486             :         memcpy(aName.BeginWriting(), aNameData, strLen * 2);
    1487             : #endif
    1488           0 :         return true;
    1489             :     }
    1490             : 
    1491           0 :     nsDependentCString encodingName(csName);
    1492           0 :     if (StartsWith(encodingName, "x-mac-") &&
    1493           0 :         !encodingName.EqualsLiteral("x-mac-cyrillic")) {
    1494             : #ifdef XP_MACOSX
    1495             :         // Special case for macOS only: support legacy Mac encodings
    1496             :         // that aren't part of the Encoding Standard.
    1497             :         if (aPlatformCode == PLATFORM_ID_MAC) {
    1498             :             CFStringRef str =
    1499             :                 CFStringCreateWithBytes(kCFAllocatorDefault,
    1500             :                                         (const UInt8*)aNameData, aByteLen,
    1501             :                                         aScriptCode, false);
    1502             :             if (str) {
    1503             :                 CFIndex length = CFStringGetLength(str);
    1504             :                 aName.SetLength(length);
    1505             :                 CFStringGetCharacters(str, CFRangeMake(0, length),
    1506             :                                       (UniChar*)aName.BeginWriting());
    1507             :                 CFRelease(str);
    1508             :                 return true;
    1509             :             }
    1510             :         }
    1511             : #endif
    1512           0 :         NS_WARNING("failed to get the decoder for a font name string");
    1513           0 :         return false;
    1514             :     }
    1515             : 
    1516           0 :     auto encoding = Encoding::ForName(encodingName);
    1517           0 :     auto rv = encoding->DecodeWithoutBOMHandling(
    1518           0 :       AsBytes(MakeSpan(aNameData, aByteLen)), aName);
    1519           0 :     return NS_SUCCEEDED(rv);
    1520             : }
    1521             : 
    1522             : nsresult
    1523           0 : gfxFontUtils::ReadNames(const char *aNameData, uint32_t aDataLen,
    1524             :                         uint32_t aNameID,
    1525             :                         int32_t aLangID, int32_t aPlatformID,
    1526             :                         nsTArray<nsString>& aNames)
    1527             : {
    1528           0 :     NS_ASSERTION(aDataLen != 0, "null name table");
    1529             : 
    1530           0 :     if (!aDataLen) {
    1531           0 :         return NS_ERROR_FAILURE;
    1532             :     }
    1533             : 
    1534             :     // -- name table data
    1535           0 :     const NameHeader *nameHeader = reinterpret_cast<const NameHeader*>(aNameData);
    1536             : 
    1537           0 :     uint32_t nameCount = nameHeader->count;
    1538             : 
    1539             :     // -- sanity check the number of name records
    1540           0 :     if (uint64_t(nameCount) * sizeof(NameRecord) > aDataLen) {
    1541           0 :         NS_WARNING("invalid font (name table data)");
    1542           0 :         return NS_ERROR_FAILURE;
    1543             :     }
    1544             : 
    1545             :     // -- iterate through name records
    1546             :     const NameRecord *nameRecord
    1547           0 :         = reinterpret_cast<const NameRecord*>(aNameData + sizeof(NameHeader));
    1548           0 :     uint64_t nameStringsBase = uint64_t(nameHeader->stringOffset);
    1549             : 
    1550             :     uint32_t i;
    1551           0 :     for (i = 0; i < nameCount; i++, nameRecord++) {
    1552             :         uint32_t platformID;
    1553             : 
    1554             :         // skip over unwanted nameID's
    1555           0 :         if (uint32_t(nameRecord->nameID) != aNameID) {
    1556           0 :             continue;
    1557             :         }
    1558             : 
    1559             :         // skip over unwanted platform data
    1560           0 :         platformID = nameRecord->platformID;
    1561           0 :         if (aPlatformID != PLATFORM_ALL &&
    1562           0 :             platformID != uint32_t(aPlatformID)) {
    1563           0 :             continue;
    1564             :         }
    1565             : 
    1566             :         // skip over unwanted languages
    1567           0 :         if (aLangID != LANG_ALL &&
    1568           0 :             uint32_t(nameRecord->languageID) != uint32_t(aLangID)) {
    1569           0 :             continue;
    1570             :         }
    1571             : 
    1572             :         // add name to names array
    1573             : 
    1574             :         // -- calculate string location
    1575           0 :         uint32_t namelen = nameRecord->length;
    1576           0 :         uint32_t nameoff = nameRecord->offset;  // offset from base of string storage
    1577             : 
    1578           0 :         if (nameStringsBase + uint64_t(nameoff) + uint64_t(namelen)
    1579           0 :                 > aDataLen) {
    1580           0 :             NS_WARNING("invalid font (name table strings)");
    1581           0 :             return NS_ERROR_FAILURE;
    1582             :         }
    1583             : 
    1584             :         // -- decode if necessary and make nsString
    1585           0 :         nsAutoString name;
    1586             : 
    1587           0 :         DecodeFontName(aNameData + nameStringsBase + nameoff, namelen,
    1588             :                        platformID, uint32_t(nameRecord->encodingID),
    1589           0 :                        uint32_t(nameRecord->languageID), name);
    1590             : 
    1591             :         uint32_t k, numNames;
    1592           0 :         bool foundName = false;
    1593             : 
    1594           0 :         numNames = aNames.Length();
    1595           0 :         for (k = 0; k < numNames; k++) {
    1596           0 :             if (name.Equals(aNames[k])) {
    1597           0 :                 foundName = true;
    1598           0 :                 break;
    1599             :             }
    1600             :         }
    1601             : 
    1602           0 :         if (!foundName)
    1603           0 :             aNames.AppendElement(name);
    1604             : 
    1605             :     }
    1606             : 
    1607           0 :     return NS_OK;
    1608             : }
    1609             : 
    1610             : #pragma pack(1)
    1611             : 
    1612             : struct COLRBaseGlyphRecord {
    1613             :     AutoSwap_PRUint16    glyphId;
    1614             :     AutoSwap_PRUint16    firstLayerIndex;
    1615             :     AutoSwap_PRUint16    numLayers;
    1616             : };
    1617             : 
    1618             : struct COLRLayerRecord {
    1619             :     AutoSwap_PRUint16    glyphId;
    1620             :     AutoSwap_PRUint16    paletteEntryIndex;
    1621             : };
    1622             : 
    1623             : struct CPALColorRecord {
    1624             :     uint8_t              blue;
    1625             :     uint8_t              green;
    1626             :     uint8_t              red;
    1627             :     uint8_t              alpha;
    1628             : };
    1629             : 
    1630             : #pragma pack()
    1631             : 
    1632             : bool
    1633           0 : gfxFontUtils::ValidateColorGlyphs(hb_blob_t* aCOLR, hb_blob_t* aCPAL)
    1634             : {
    1635             :     unsigned int colrLength;
    1636             :     const COLRHeader* colr =
    1637           0 :         reinterpret_cast<const COLRHeader*>(hb_blob_get_data(aCOLR, &colrLength));
    1638             :     unsigned int cpalLength;
    1639             :     const CPALHeaderVersion0* cpal =
    1640           0 :         reinterpret_cast<const CPALHeaderVersion0*>(hb_blob_get_data(aCPAL, &cpalLength));
    1641             : 
    1642           0 :     if (!colr || !cpal || !colrLength || !cpalLength) {
    1643           0 :         return false;
    1644             :     }
    1645             : 
    1646           0 :     if (uint16_t(colr->version) != 0 || uint16_t(cpal->version) != 0) {
    1647             :         // We only support version 0 headers.
    1648           0 :         return false;
    1649             :     }
    1650             : 
    1651           0 :     const uint32_t offsetBaseGlyphRecord = colr->offsetBaseGlyphRecord;
    1652           0 :     const uint16_t numBaseGlyphRecord = colr->numBaseGlyphRecord;
    1653           0 :     const uint32_t offsetLayerRecord = colr->offsetLayerRecord;
    1654           0 :     const uint16_t numLayerRecords = colr->numLayerRecords;
    1655             : 
    1656           0 :     const uint32_t offsetFirstColorRecord = cpal->offsetFirstColorRecord;
    1657           0 :     const uint16_t numColorRecords = cpal->numColorRecords;
    1658           0 :     const uint32_t numPaletteEntries = cpal->numPaletteEntries;
    1659             : 
    1660           0 :     if (offsetBaseGlyphRecord >= colrLength) {
    1661           0 :         return false;
    1662             :     }
    1663             : 
    1664           0 :     if (offsetLayerRecord >= colrLength) {
    1665           0 :         return false;
    1666             :     }
    1667             : 
    1668           0 :     if (offsetFirstColorRecord >= cpalLength) {
    1669           0 :         return false;
    1670             :     }
    1671             : 
    1672           0 :     if (!numPaletteEntries) {
    1673           0 :         return false;
    1674             :     }
    1675             : 
    1676           0 :     if (sizeof(COLRBaseGlyphRecord) * numBaseGlyphRecord >
    1677           0 :             colrLength - offsetBaseGlyphRecord) {
    1678             :         // COLR base glyph record will be overflow
    1679           0 :         return false;
    1680             :     }
    1681             : 
    1682           0 :     if (sizeof(COLRLayerRecord) * numLayerRecords >
    1683           0 :             colrLength - offsetLayerRecord) {
    1684             :         // COLR layer record will be overflow
    1685           0 :         return false;
    1686             :     }
    1687             : 
    1688           0 :     if (sizeof(CPALColorRecord) * numColorRecords >
    1689           0 :             cpalLength - offsetFirstColorRecord) {
    1690             :         // CPAL color record will be overflow
    1691           0 :         return false;
    1692             :     }
    1693             : 
    1694           0 :     if (numPaletteEntries * uint16_t(cpal->numPalettes) != numColorRecords ) {
    1695             :         // palette of CPAL color record will be overflow.
    1696           0 :         return false;
    1697             :     }
    1698             : 
    1699           0 :     uint16_t lastGlyphId = 0;
    1700             :     const COLRBaseGlyphRecord* baseGlyph =
    1701           0 :         reinterpret_cast<const COLRBaseGlyphRecord*>(
    1702           0 :             reinterpret_cast<const uint8_t*>(colr) + offsetBaseGlyphRecord);
    1703             : 
    1704           0 :     for (uint16_t i = 0; i < numBaseGlyphRecord; i++, baseGlyph++) {
    1705           0 :         const uint32_t firstLayerIndex = baseGlyph->firstLayerIndex;
    1706           0 :         const uint16_t numLayers = baseGlyph->numLayers;
    1707           0 :         const uint16_t glyphId = baseGlyph->glyphId;
    1708             : 
    1709           0 :         if (lastGlyphId && lastGlyphId >= glyphId) {
    1710             :             // glyphId must be sorted
    1711           0 :             return false;
    1712             :         }
    1713           0 :         lastGlyphId = glyphId;
    1714             : 
    1715           0 :         if (!numLayers) {
    1716             :             // no layer
    1717           0 :             return false;
    1718             :         }
    1719           0 :         if (firstLayerIndex + numLayers > numLayerRecords) {
    1720             :             // layer length of target glyph is overflow
    1721           0 :             return false;
    1722             :         }
    1723             :     }
    1724             : 
    1725             :     const COLRLayerRecord* layer =
    1726           0 :         reinterpret_cast<const COLRLayerRecord*>(
    1727           0 :             reinterpret_cast<const uint8_t*>(colr) + offsetLayerRecord);
    1728             : 
    1729           0 :     for (uint16_t i = 0; i < numLayerRecords; i++, layer++) {
    1730           0 :         if (uint16_t(layer->paletteEntryIndex) >= numPaletteEntries &&
    1731           0 :             uint16_t(layer->paletteEntryIndex) != 0xFFFF) {
    1732             :             // CPAL palette entry record is overflow
    1733           0 :             return false;
    1734             :         }
    1735             :     }
    1736             : 
    1737           0 :     return true;
    1738             : }
    1739             : 
    1740             : static int
    1741           0 : CompareBaseGlyph(const void* key, const void* data)
    1742             : {
    1743           0 :     uint32_t glyphId = (uint32_t)(uintptr_t)key;
    1744             :     const COLRBaseGlyphRecord* baseGlyph =
    1745           0 :         reinterpret_cast<const COLRBaseGlyphRecord*>(data);
    1746           0 :     uint32_t baseGlyphId = uint16_t(baseGlyph->glyphId);
    1747             : 
    1748           0 :     if (baseGlyphId == glyphId) {
    1749           0 :         return 0;
    1750             :     }
    1751             : 
    1752           0 :     return baseGlyphId > glyphId ? -1 : 1;
    1753             : }
    1754             : 
    1755             : static
    1756             : COLRBaseGlyphRecord*
    1757           0 : LookForBaseGlyphRecord(const COLRHeader* aCOLR, uint32_t aGlyphId)
    1758             : {
    1759             :     const uint8_t* baseGlyphRecords =
    1760             :         reinterpret_cast<const uint8_t*>(aCOLR) +
    1761           0 :         uint32_t(aCOLR->offsetBaseGlyphRecord);
    1762             :     // BaseGlyphRecord is sorted by glyphId
    1763             :     return reinterpret_cast<COLRBaseGlyphRecord*>(
    1764           0 :                bsearch((void*)(uintptr_t)aGlyphId,
    1765             :                        baseGlyphRecords,
    1766           0 :                        uint16_t(aCOLR->numBaseGlyphRecord),
    1767             :                        sizeof(COLRBaseGlyphRecord),
    1768           0 :                        CompareBaseGlyph));
    1769             : }
    1770             : 
    1771             : bool
    1772           0 : gfxFontUtils::GetColorGlyphLayers(hb_blob_t* aCOLR,
    1773             :                                   hb_blob_t* aCPAL,
    1774             :                                   uint32_t aGlyphId,
    1775             :                                   const mozilla::gfx::Color& aDefaultColor,
    1776             :                                   nsTArray<uint16_t>& aGlyphs,
    1777             :                                   nsTArray<mozilla::gfx::Color>& aColors)
    1778             : {
    1779             :     unsigned int blobLength;
    1780             :     const COLRHeader* colr =
    1781             :         reinterpret_cast<const COLRHeader*>(hb_blob_get_data(aCOLR,
    1782           0 :                                                              &blobLength));
    1783           0 :     MOZ_ASSERT(colr, "Cannot get COLR raw data");
    1784           0 :     MOZ_ASSERT(blobLength, "Found COLR data, but length is 0");
    1785             : 
    1786           0 :     COLRBaseGlyphRecord* baseGlyph = LookForBaseGlyphRecord(colr, aGlyphId);
    1787           0 :     if (!baseGlyph) {
    1788           0 :         return false;
    1789             :     }
    1790             : 
    1791             :     const CPALHeaderVersion0* cpal =
    1792             :         reinterpret_cast<const CPALHeaderVersion0*>(
    1793           0 :             hb_blob_get_data(aCPAL, &blobLength));
    1794           0 :     MOZ_ASSERT(cpal, "Cannot get CPAL raw data");
    1795           0 :     MOZ_ASSERT(blobLength, "Found CPAL data, but length is 0");
    1796             : 
    1797             :     const COLRLayerRecord* layer =
    1798             :         reinterpret_cast<const COLRLayerRecord*>(
    1799             :             reinterpret_cast<const uint8_t*>(colr) +
    1800           0 :             uint32_t(colr->offsetLayerRecord) +
    1801           0 :             sizeof(COLRLayerRecord) * uint16_t(baseGlyph->firstLayerIndex));
    1802           0 :     const uint16_t numLayers = baseGlyph->numLayers;
    1803           0 :     const uint32_t offsetFirstColorRecord = cpal->offsetFirstColorRecord;
    1804             : 
    1805           0 :     for (uint16_t layerIndex = 0; layerIndex < numLayers; layerIndex++) {
    1806           0 :         aGlyphs.AppendElement(uint16_t(layer->glyphId));
    1807           0 :         if (uint16_t(layer->paletteEntryIndex) == 0xFFFF) {
    1808           0 :             aColors.AppendElement(aDefaultColor);
    1809             :         } else {
    1810             :             const CPALColorRecord* color =
    1811             :                 reinterpret_cast<const CPALColorRecord*>(
    1812             :                     reinterpret_cast<const uint8_t*>(cpal) +
    1813             :                     offsetFirstColorRecord +
    1814           0 :                     sizeof(CPALColorRecord) * uint16_t(layer->paletteEntryIndex));
    1815           0 :             aColors.AppendElement(mozilla::gfx::Color(color->red / 255.0,
    1816           0 :                                                       color->green / 255.0,
    1817           0 :                                                       color->blue / 255.0,
    1818           0 :                                                       color->alpha / 255.0));
    1819             :         }
    1820           0 :         layer++;
    1821             :     }
    1822           0 :     return true;
    1823             : }
    1824             : 
    1825             : #ifdef XP_WIN
    1826             : 
    1827             : /* static */
    1828             : bool
    1829             : gfxFontUtils::IsCffFont(const uint8_t* aFontData)
    1830             : {
    1831             :     // this is only called after aFontData has passed basic validation,
    1832             :     // so we know there is enough data present to allow us to read the version!
    1833             :     const SFNTHeader *sfntHeader = reinterpret_cast<const SFNTHeader*>(aFontData);
    1834             :     return (sfntHeader->sfntVersion == TRUETYPE_TAG('O','T','T','O'));
    1835             : }
    1836             : 
    1837             : #endif
    1838             : 
    1839             : #undef acceptablePlatform
    1840             : #undef isSymbol
    1841             : #undef isUVSEncoding
    1842             : #undef LOG
    1843             : #undef LOG_ENABLED

Generated by: LCOV version 1.13