gfx/thebes/gfxFontUtils.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/thebes/gfxFontUtils.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1455 @@
     1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#ifdef MOZ_LOGGING
    1.10 +#define FORCE_PR_LOG /* Allow logging in the release build */
    1.11 +#include "prlog.h"
    1.12 +#endif
    1.13 +
    1.14 +#include "mozilla/ArrayUtils.h"
    1.15 +
    1.16 +#include "gfxFontUtils.h"
    1.17 +
    1.18 +#include "nsServiceManagerUtils.h"
    1.19 +
    1.20 +#include "mozilla/dom/EncodingUtils.h"
    1.21 +#include "mozilla/Preferences.h"
    1.22 +#include "mozilla/Services.h"
    1.23 +
    1.24 +#include "nsCOMPtr.h"
    1.25 +#include "nsIUUIDGenerator.h"
    1.26 +#include "nsIUnicodeDecoder.h"
    1.27 +
    1.28 +#include "harfbuzz/hb.h"
    1.29 +
    1.30 +#include "plbase64.h"
    1.31 +#include "prlog.h"
    1.32 +
    1.33 +#ifdef PR_LOGGING
    1.34 +
    1.35 +#define LOG(log, args) PR_LOG(gfxPlatform::GetLog(log), \
    1.36 +                               PR_LOG_DEBUG, args)
    1.37 +
    1.38 +#endif // PR_LOGGING
    1.39 +
    1.40 +#define UNICODE_BMP_LIMIT 0x10000
    1.41 +
    1.42 +using namespace mozilla;
    1.43 +
    1.44 +#pragma pack(1)
    1.45 +
    1.46 +typedef struct {
    1.47 +    AutoSwap_PRUint16 format;
    1.48 +    AutoSwap_PRUint16 reserved;
    1.49 +    AutoSwap_PRUint32 length;
    1.50 +    AutoSwap_PRUint32 language;
    1.51 +    AutoSwap_PRUint32 numGroups;
    1.52 +} Format12CmapHeader;
    1.53 +
    1.54 +typedef struct {
    1.55 +    AutoSwap_PRUint32 startCharCode;
    1.56 +    AutoSwap_PRUint32 endCharCode;
    1.57 +    AutoSwap_PRUint32 startGlyphId;
    1.58 +} Format12Group;
    1.59 +
    1.60 +#pragma pack()
    1.61 +
    1.62 +#if PR_LOGGING
    1.63 +void
    1.64 +gfxSparseBitSet::Dump(const char* aPrefix, eGfxLog aWhichLog) const
    1.65 +{
    1.66 +    NS_ASSERTION(mBlocks.DebugGetHeader(), "mHdr is null, this is bad");
    1.67 +    uint32_t b, numBlocks = mBlocks.Length();
    1.68 +
    1.69 +    for (b = 0; b < numBlocks; b++) {
    1.70 +        Block *block = mBlocks[b];
    1.71 +        if (!block) continue;
    1.72 +        char outStr[256];
    1.73 +        int index = 0;
    1.74 +        index += sprintf(&outStr[index], "%s u+%6.6x [", aPrefix, (b << BLOCK_INDEX_SHIFT));
    1.75 +        for (int i = 0; i < 32; i += 4) {
    1.76 +            for (int j = i; j < i + 4; j++) {
    1.77 +                uint8_t bits = block->mBits[j];
    1.78 +                uint8_t flip1 = ((bits & 0xaa) >> 1) | ((bits & 0x55) << 1);
    1.79 +                uint8_t flip2 = ((flip1 & 0xcc) >> 2) | ((flip1 & 0x33) << 2);
    1.80 +                uint8_t flipped = ((flip2 & 0xf0) >> 4) | ((flip2 & 0x0f) << 4);
    1.81 +
    1.82 +                index += sprintf(&outStr[index], "%2.2x", flipped);
    1.83 +            }
    1.84 +            if (i + 4 != 32) index += sprintf(&outStr[index], " ");
    1.85 +        }
    1.86 +        index += sprintf(&outStr[index], "]");
    1.87 +        LOG(aWhichLog, ("%s", outStr));
    1.88 +    }
    1.89 +}
    1.90 +#endif
    1.91 +
    1.92 +
    1.93 +nsresult
    1.94 +gfxFontUtils::ReadCMAPTableFormat12(const uint8_t *aBuf, uint32_t aLength,
    1.95 +                                    gfxSparseBitSet& aCharacterMap) 
    1.96 +{
    1.97 +    // Ensure table is large enough that we can safely read the header
    1.98 +    NS_ENSURE_TRUE(aLength >= sizeof(Format12CmapHeader),
    1.99 +                    NS_ERROR_GFX_CMAP_MALFORMED);
   1.100 +
   1.101 +    // Sanity-check header fields
   1.102 +    const Format12CmapHeader *cmap12 =
   1.103 +        reinterpret_cast<const Format12CmapHeader*>(aBuf);
   1.104 +    NS_ENSURE_TRUE(uint16_t(cmap12->format) == 12, 
   1.105 +                   NS_ERROR_GFX_CMAP_MALFORMED);
   1.106 +    NS_ENSURE_TRUE(uint16_t(cmap12->reserved) == 0, 
   1.107 +                   NS_ERROR_GFX_CMAP_MALFORMED);
   1.108 +
   1.109 +    uint32_t tablelen = cmap12->length;
   1.110 +    NS_ENSURE_TRUE(tablelen >= sizeof(Format12CmapHeader) &&
   1.111 +                   tablelen <= aLength, NS_ERROR_GFX_CMAP_MALFORMED);
   1.112 +
   1.113 +    NS_ENSURE_TRUE(cmap12->language == 0, NS_ERROR_GFX_CMAP_MALFORMED);
   1.114 +
   1.115 +    // Check that the table is large enough for the group array
   1.116 +    const uint32_t numGroups = cmap12->numGroups;
   1.117 +    NS_ENSURE_TRUE((tablelen - sizeof(Format12CmapHeader)) /
   1.118 +                       sizeof(Format12Group) >= numGroups,
   1.119 +                   NS_ERROR_GFX_CMAP_MALFORMED);
   1.120 +
   1.121 +    // The array of groups immediately follows the subtable header.
   1.122 +    const Format12Group *group =
   1.123 +        reinterpret_cast<const Format12Group*>(aBuf + sizeof(Format12CmapHeader));
   1.124 +
   1.125 +    // Check that groups are in correct order and do not overlap,
   1.126 +    // and record character coverage in aCharacterMap.
   1.127 +    uint32_t prevEndCharCode = 0;
   1.128 +    for (uint32_t i = 0; i < numGroups; i++, group++) {
   1.129 +        uint32_t startCharCode = group->startCharCode;
   1.130 +        const uint32_t endCharCode = group->endCharCode;
   1.131 +        NS_ENSURE_TRUE((prevEndCharCode < startCharCode || i == 0) &&
   1.132 +                       startCharCode <= endCharCode &&
   1.133 +                       endCharCode <= CMAP_MAX_CODEPOINT, 
   1.134 +                       NS_ERROR_GFX_CMAP_MALFORMED);
   1.135 +        // don't include a character that maps to glyph ID 0 (.notdef)
   1.136 +        if (group->startGlyphId == 0) {
   1.137 +            startCharCode++;
   1.138 +        }
   1.139 +        if (startCharCode <= endCharCode) {
   1.140 +            aCharacterMap.SetRange(startCharCode, endCharCode);
   1.141 +        }
   1.142 +        prevEndCharCode = endCharCode;
   1.143 +    }
   1.144 +
   1.145 +    aCharacterMap.Compact();
   1.146 +
   1.147 +    return NS_OK;
   1.148 +}
   1.149 +
   1.150 +nsresult 
   1.151 +gfxFontUtils::ReadCMAPTableFormat4(const uint8_t *aBuf, uint32_t aLength,
   1.152 +                                   gfxSparseBitSet& aCharacterMap)
   1.153 +{
   1.154 +    enum {
   1.155 +        OffsetFormat = 0,
   1.156 +        OffsetLength = 2,
   1.157 +        OffsetLanguage = 4,
   1.158 +        OffsetSegCountX2 = 6
   1.159 +    };
   1.160 +
   1.161 +    NS_ENSURE_TRUE(ReadShortAt(aBuf, OffsetFormat) == 4, 
   1.162 +                   NS_ERROR_GFX_CMAP_MALFORMED);
   1.163 +    uint16_t tablelen = ReadShortAt(aBuf, OffsetLength);
   1.164 +    NS_ENSURE_TRUE(tablelen <= aLength, NS_ERROR_GFX_CMAP_MALFORMED);
   1.165 +    NS_ENSURE_TRUE(tablelen > 16, NS_ERROR_GFX_CMAP_MALFORMED);
   1.166 +    
   1.167 +    // This field should normally (except for Mac platform subtables) be zero according to
   1.168 +    // the OT spec, but some buggy fonts have lang = 1 (which would be English for MacOS).
   1.169 +    // E.g. Arial Narrow Bold, v. 1.1 (Tiger), Arial Unicode MS (see bug 530614).
   1.170 +    // So accept either zero or one here; the error should be harmless.
   1.171 +    NS_ENSURE_TRUE((ReadShortAt(aBuf, OffsetLanguage) & 0xfffe) == 0, 
   1.172 +                   NS_ERROR_GFX_CMAP_MALFORMED);
   1.173 +
   1.174 +    uint16_t segCountX2 = ReadShortAt(aBuf, OffsetSegCountX2);
   1.175 +    NS_ENSURE_TRUE(tablelen >= 16 + (segCountX2 * 4), 
   1.176 +                   NS_ERROR_GFX_CMAP_MALFORMED);
   1.177 +
   1.178 +    const uint16_t segCount = segCountX2 / 2;
   1.179 +
   1.180 +    const uint16_t *endCounts = reinterpret_cast<const uint16_t*>(aBuf + 14);
   1.181 +    const uint16_t *startCounts = endCounts + 1 /* skip one uint16_t for reservedPad */ + segCount;
   1.182 +    const uint16_t *idDeltas = startCounts + segCount;
   1.183 +    const uint16_t *idRangeOffsets = idDeltas + segCount;
   1.184 +    uint16_t prevEndCount = 0;
   1.185 +    for (uint16_t i = 0; i < segCount; i++) {
   1.186 +        const uint16_t endCount = ReadShortAt16(endCounts, i);
   1.187 +        const uint16_t startCount = ReadShortAt16(startCounts, i);
   1.188 +        const uint16_t idRangeOffset = ReadShortAt16(idRangeOffsets, i);
   1.189 +
   1.190 +        // sanity-check range
   1.191 +        // This permits ranges to overlap by 1 character, which is strictly
   1.192 +        // incorrect but occurs in Baskerville on OS X 10.7 (see bug 689087),
   1.193 +        // and appears to be harmless in practice
   1.194 +        NS_ENSURE_TRUE(startCount >= prevEndCount && startCount <= endCount,
   1.195 +                       NS_ERROR_GFX_CMAP_MALFORMED);
   1.196 +        prevEndCount = endCount;
   1.197 +
   1.198 +        if (idRangeOffset == 0) {
   1.199 +            // figure out if there's a code in the range that would map to
   1.200 +            // glyph ID 0 (.notdef); if so, we need to skip setting that
   1.201 +            // character code in the map
   1.202 +            const uint16_t skipCode = 65536 - ReadShortAt16(idDeltas, i);
   1.203 +            if (startCount < skipCode) {
   1.204 +                aCharacterMap.SetRange(startCount,
   1.205 +                                       std::min<uint16_t>(skipCode - 1,
   1.206 +                                                          endCount));
   1.207 +            }
   1.208 +            if (skipCode < endCount) {
   1.209 +                aCharacterMap.SetRange(std::max<uint16_t>(startCount,
   1.210 +                                                          skipCode + 1),
   1.211 +                                       endCount);
   1.212 +            }
   1.213 +        } else {
   1.214 +            // const uint16_t idDelta = ReadShortAt16(idDeltas, i); // Unused: self-documenting.
   1.215 +            for (uint32_t c = startCount; c <= endCount; ++c) {
   1.216 +                if (c == 0xFFFF)
   1.217 +                    break;
   1.218 +
   1.219 +                const uint16_t *gdata = (idRangeOffset/2 
   1.220 +                                         + (c - startCount)
   1.221 +                                         + &idRangeOffsets[i]);
   1.222 +
   1.223 +                NS_ENSURE_TRUE((uint8_t*)gdata > aBuf && 
   1.224 +                               (uint8_t*)gdata < aBuf + aLength, 
   1.225 +                               NS_ERROR_GFX_CMAP_MALFORMED);
   1.226 +
   1.227 +                // make sure we have a glyph
   1.228 +                if (*gdata != 0) {
   1.229 +                    // The glyph index at this point is:
   1.230 +                    uint16_t glyph = ReadShortAt16(idDeltas, i) + *gdata;
   1.231 +                    if (glyph) {
   1.232 +                        aCharacterMap.set(c);
   1.233 +                    }
   1.234 +                }
   1.235 +            }
   1.236 +        }
   1.237 +    }
   1.238 +
   1.239 +    aCharacterMap.Compact();
   1.240 +
   1.241 +    return NS_OK;
   1.242 +}
   1.243 +
   1.244 +nsresult
   1.245 +gfxFontUtils::ReadCMAPTableFormat14(const uint8_t *aBuf, uint32_t aLength,
   1.246 +                                    uint8_t*& aTable)
   1.247 +{
   1.248 +    enum {
   1.249 +        OffsetFormat = 0,
   1.250 +        OffsetTableLength = 2,
   1.251 +        OffsetNumVarSelectorRecords = 6,
   1.252 +        OffsetVarSelectorRecords = 10,
   1.253 +
   1.254 +        SizeOfVarSelectorRecord = 11,
   1.255 +        VSRecOffsetVarSelector = 0,
   1.256 +        VSRecOffsetDefUVSOffset = 3,
   1.257 +        VSRecOffsetNonDefUVSOffset = 7,
   1.258 +
   1.259 +        SizeOfDefUVSTable = 4,
   1.260 +        DefUVSOffsetStartUnicodeValue = 0,
   1.261 +        DefUVSOffsetAdditionalCount = 3,
   1.262 +
   1.263 +        SizeOfNonDefUVSTable = 5,
   1.264 +        NonDefUVSOffsetUnicodeValue = 0,
   1.265 +        NonDefUVSOffsetGlyphID = 3
   1.266 +    };
   1.267 +    NS_ENSURE_TRUE(aLength >= OffsetVarSelectorRecords,
   1.268 +                   NS_ERROR_GFX_CMAP_MALFORMED);
   1.269 +
   1.270 +    NS_ENSURE_TRUE(ReadShortAt(aBuf, OffsetFormat) == 14, 
   1.271 +                   NS_ERROR_GFX_CMAP_MALFORMED);
   1.272 +
   1.273 +    uint32_t tablelen = ReadLongAt(aBuf, OffsetTableLength);
   1.274 +    NS_ENSURE_TRUE(tablelen <= aLength, NS_ERROR_GFX_CMAP_MALFORMED);
   1.275 +    NS_ENSURE_TRUE(tablelen >= OffsetVarSelectorRecords,
   1.276 +                   NS_ERROR_GFX_CMAP_MALFORMED);
   1.277 +
   1.278 +    const uint32_t numVarSelectorRecords = ReadLongAt(aBuf, OffsetNumVarSelectorRecords);
   1.279 +    NS_ENSURE_TRUE((tablelen - OffsetVarSelectorRecords) /
   1.280 +                   SizeOfVarSelectorRecord >= numVarSelectorRecords,
   1.281 +                   NS_ERROR_GFX_CMAP_MALFORMED);
   1.282 +
   1.283 +    const uint8_t *records = aBuf + OffsetVarSelectorRecords;
   1.284 +    for (uint32_t i = 0; i < numVarSelectorRecords; 
   1.285 +         i++, records += SizeOfVarSelectorRecord) {
   1.286 +        const uint32_t varSelector = ReadUint24At(records, VSRecOffsetVarSelector);
   1.287 +        const uint32_t defUVSOffset = ReadLongAt(records, VSRecOffsetDefUVSOffset);
   1.288 +        const uint32_t nonDefUVSOffset = ReadLongAt(records, VSRecOffsetNonDefUVSOffset);
   1.289 +        NS_ENSURE_TRUE(varSelector <= CMAP_MAX_CODEPOINT &&
   1.290 +                       defUVSOffset <= tablelen - 4 &&
   1.291 +                       nonDefUVSOffset <= tablelen - 4, 
   1.292 +                       NS_ERROR_GFX_CMAP_MALFORMED);
   1.293 +
   1.294 +        if (defUVSOffset) {
   1.295 +            const uint32_t numUnicodeValueRanges = ReadLongAt(aBuf, defUVSOffset);
   1.296 +            NS_ENSURE_TRUE((tablelen - defUVSOffset) /
   1.297 +                           SizeOfDefUVSTable >= numUnicodeValueRanges,
   1.298 +                           NS_ERROR_GFX_CMAP_MALFORMED);
   1.299 +            const uint8_t *tables = aBuf + defUVSOffset + 4;
   1.300 +            uint32_t prevEndUnicode = 0;
   1.301 +            for (uint32_t j = 0; j < numUnicodeValueRanges; j++, tables += SizeOfDefUVSTable) {
   1.302 +                const uint32_t startUnicode = ReadUint24At(tables, DefUVSOffsetStartUnicodeValue);
   1.303 +                const uint32_t endUnicode = startUnicode + tables[DefUVSOffsetAdditionalCount];
   1.304 +                NS_ENSURE_TRUE((prevEndUnicode < startUnicode || j == 0) &&
   1.305 +                               endUnicode <= CMAP_MAX_CODEPOINT, 
   1.306 +                               NS_ERROR_GFX_CMAP_MALFORMED);
   1.307 +                prevEndUnicode = endUnicode;
   1.308 +            }
   1.309 +        }
   1.310 +
   1.311 +        if (nonDefUVSOffset) {
   1.312 +            const uint32_t numUVSMappings = ReadLongAt(aBuf, nonDefUVSOffset);
   1.313 +            NS_ENSURE_TRUE((tablelen - nonDefUVSOffset) /
   1.314 +                           SizeOfNonDefUVSTable >= numUVSMappings,
   1.315 +                           NS_ERROR_GFX_CMAP_MALFORMED);
   1.316 +            const uint8_t *tables = aBuf + nonDefUVSOffset + 4;
   1.317 +            uint32_t prevUnicode = 0;
   1.318 +            for (uint32_t j = 0; j < numUVSMappings; j++, tables += SizeOfNonDefUVSTable) {
   1.319 +                const uint32_t unicodeValue = ReadUint24At(tables, NonDefUVSOffsetUnicodeValue);
   1.320 +                NS_ENSURE_TRUE((prevUnicode < unicodeValue || j == 0) &&
   1.321 +                               unicodeValue <= CMAP_MAX_CODEPOINT, 
   1.322 +                               NS_ERROR_GFX_CMAP_MALFORMED);
   1.323 +                prevUnicode = unicodeValue;
   1.324 +            }
   1.325 +        }
   1.326 +    }
   1.327 +
   1.328 +    aTable = new uint8_t[tablelen];
   1.329 +    memcpy(aTable, aBuf, tablelen);
   1.330 +
   1.331 +    return NS_OK;
   1.332 +}
   1.333 +
   1.334 +// Windows requires fonts to have a format-4 cmap with a Microsoft ID (3).  On the Mac, fonts either have
   1.335 +// a format-4 cmap with Microsoft platform/encoding id or they have one with a platformID == Unicode (0)
   1.336 +// For fonts with two format-4 tables, the first one (Unicode platform) is preferred on the Mac.
   1.337 +
   1.338 +#if defined(XP_MACOSX)
   1.339 +    #define acceptableFormat4(p,e,k) (((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDMicrosoft && !(k)) || \
   1.340 +                                      ((p) == PLATFORM_ID_UNICODE))
   1.341 +
   1.342 +    #define acceptableUCS4Encoding(p, e, k) \
   1.343 +        (((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDUCS4ForMicrosoftPlatform) && (k) != 12 || \
   1.344 +         ((p) == PLATFORM_ID_UNICODE   && \
   1.345 +          ((e) == EncodingIDDefaultForUnicodePlatform || (e) >= EncodingIDUCS4ForUnicodePlatform)))
   1.346 +#else
   1.347 +    #define acceptableFormat4(p,e,k) ((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDMicrosoft)
   1.348 +
   1.349 +    #define acceptableUCS4Encoding(p, e, k) \
   1.350 +        ((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDUCS4ForMicrosoftPlatform)
   1.351 +#endif
   1.352 +
   1.353 +#define acceptablePlatform(p) ((p) == PLATFORM_ID_UNICODE || (p) == PLATFORM_ID_MICROSOFT)
   1.354 +#define isSymbol(p,e)         ((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDSymbol)
   1.355 +#define isUVSEncoding(p, e)   ((p) == PLATFORM_ID_UNICODE && (e) == EncodingIDUVSForUnicodePlatform)
   1.356 +
   1.357 +uint32_t
   1.358 +gfxFontUtils::FindPreferredSubtable(const uint8_t *aBuf, uint32_t aBufLength,
   1.359 +                                    uint32_t *aTableOffset,
   1.360 +                                    uint32_t *aUVSTableOffset,
   1.361 +                                    bool *aSymbolEncoding)
   1.362 +{
   1.363 +    enum {
   1.364 +        OffsetVersion = 0,
   1.365 +        OffsetNumTables = 2,
   1.366 +        SizeOfHeader = 4,
   1.367 +
   1.368 +        TableOffsetPlatformID = 0,
   1.369 +        TableOffsetEncodingID = 2,
   1.370 +        TableOffsetOffset = 4,
   1.371 +        SizeOfTable = 8,
   1.372 +
   1.373 +        SubtableOffsetFormat = 0
   1.374 +    };
   1.375 +    enum {
   1.376 +        EncodingIDSymbol = 0,
   1.377 +        EncodingIDMicrosoft = 1,
   1.378 +        EncodingIDDefaultForUnicodePlatform = 0,
   1.379 +        EncodingIDUCS4ForUnicodePlatform = 3,
   1.380 +        EncodingIDUVSForUnicodePlatform = 5,
   1.381 +        EncodingIDUCS4ForMicrosoftPlatform = 10
   1.382 +    };
   1.383 +
   1.384 +    if (aUVSTableOffset) {
   1.385 +        *aUVSTableOffset = 0;
   1.386 +    }
   1.387 +
   1.388 +    if (!aBuf || aBufLength < SizeOfHeader) {
   1.389 +        // cmap table is missing, or too small to contain header fields!
   1.390 +        return 0;
   1.391 +    }
   1.392 +
   1.393 +    // uint16_t version = ReadShortAt(aBuf, OffsetVersion); // Unused: self-documenting.
   1.394 +    uint16_t numTables = ReadShortAt(aBuf, OffsetNumTables);
   1.395 +    if (aBufLength < uint32_t(SizeOfHeader + numTables * SizeOfTable)) {
   1.396 +        return 0;
   1.397 +    }
   1.398 +
   1.399 +    // save the format we want here
   1.400 +    uint32_t keepFormat = 0;
   1.401 +
   1.402 +    const uint8_t *table = aBuf + SizeOfHeader;
   1.403 +    for (uint16_t i = 0; i < numTables; ++i, table += SizeOfTable) {
   1.404 +        const uint16_t platformID = ReadShortAt(table, TableOffsetPlatformID);
   1.405 +        if (!acceptablePlatform(platformID))
   1.406 +            continue;
   1.407 +
   1.408 +        const uint16_t encodingID = ReadShortAt(table, TableOffsetEncodingID);
   1.409 +        const uint32_t offset = ReadLongAt(table, TableOffsetOffset);
   1.410 +        if (aBufLength - 2 < offset) {
   1.411 +            // this subtable is not valid - beyond end of buffer
   1.412 +            return 0;
   1.413 +        }
   1.414 +
   1.415 +        const uint8_t *subtable = aBuf + offset;
   1.416 +        const uint16_t format = ReadShortAt(subtable, SubtableOffsetFormat);
   1.417 +
   1.418 +        if (isSymbol(platformID, encodingID)) {
   1.419 +            keepFormat = format;
   1.420 +            *aTableOffset = offset;
   1.421 +            *aSymbolEncoding = true;
   1.422 +            break;
   1.423 +        } else if (format == 4 && acceptableFormat4(platformID, encodingID, keepFormat)) {
   1.424 +            keepFormat = format;
   1.425 +            *aTableOffset = offset;
   1.426 +            *aSymbolEncoding = false;
   1.427 +        } else if (format == 12 && acceptableUCS4Encoding(platformID, encodingID, keepFormat)) {
   1.428 +            keepFormat = format;
   1.429 +            *aTableOffset = offset;
   1.430 +            *aSymbolEncoding = false;
   1.431 +            if (platformID > PLATFORM_ID_UNICODE || !aUVSTableOffset || *aUVSTableOffset) {
   1.432 +                break; // we don't want to try anything else when this format is available.
   1.433 +            }
   1.434 +        } else if (format == 14 && isUVSEncoding(platformID, encodingID) && aUVSTableOffset) {
   1.435 +            *aUVSTableOffset = offset;
   1.436 +            if (keepFormat == 12) {
   1.437 +                break;
   1.438 +            }
   1.439 +        }
   1.440 +    }
   1.441 +
   1.442 +    return keepFormat;
   1.443 +}
   1.444 +
   1.445 +nsresult
   1.446 +gfxFontUtils::ReadCMAP(const uint8_t *aBuf, uint32_t aBufLength,
   1.447 +                       gfxSparseBitSet& aCharacterMap,
   1.448 +                       uint32_t& aUVSOffset,
   1.449 +                       bool& aUnicodeFont, bool& aSymbolFont)
   1.450 +{
   1.451 +    uint32_t offset;
   1.452 +    bool     symbol;
   1.453 +    uint32_t format = FindPreferredSubtable(aBuf, aBufLength,
   1.454 +                                            &offset, &aUVSOffset, &symbol);
   1.455 +
   1.456 +    if (format == 4) {
   1.457 +        if (symbol) {
   1.458 +            aUnicodeFont = false;
   1.459 +            aSymbolFont = true;
   1.460 +        } else {
   1.461 +            aUnicodeFont = true;
   1.462 +            aSymbolFont = false;
   1.463 +        }
   1.464 +        return ReadCMAPTableFormat4(aBuf + offset, aBufLength - offset,
   1.465 +                                    aCharacterMap);
   1.466 +    }
   1.467 +
   1.468 +    if (format == 12) {
   1.469 +        aUnicodeFont = true;
   1.470 +        aSymbolFont = false;
   1.471 +        return ReadCMAPTableFormat12(aBuf + offset, aBufLength - offset,
   1.472 +                                     aCharacterMap);
   1.473 +    }
   1.474 +
   1.475 +    return NS_ERROR_FAILURE;
   1.476 +}
   1.477 +
   1.478 +#pragma pack(1)
   1.479 +
   1.480 +typedef struct {
   1.481 +    AutoSwap_PRUint16 format;
   1.482 +    AutoSwap_PRUint16 length;
   1.483 +    AutoSwap_PRUint16 language;
   1.484 +    AutoSwap_PRUint16 segCountX2;
   1.485 +    AutoSwap_PRUint16 searchRange;
   1.486 +    AutoSwap_PRUint16 entrySelector;
   1.487 +    AutoSwap_PRUint16 rangeShift;
   1.488 +
   1.489 +    AutoSwap_PRUint16 arrays[1];
   1.490 +} Format4Cmap;
   1.491 +
   1.492 +typedef struct {
   1.493 +    AutoSwap_PRUint16 format;
   1.494 +    AutoSwap_PRUint32 length;
   1.495 +    AutoSwap_PRUint32 numVarSelectorRecords;
   1.496 +
   1.497 +    typedef struct {
   1.498 +        AutoSwap_PRUint24 varSelector;
   1.499 +        AutoSwap_PRUint32 defaultUVSOffset;
   1.500 +        AutoSwap_PRUint32 nonDefaultUVSOffset;
   1.501 +    } VarSelectorRecord;
   1.502 +
   1.503 +    VarSelectorRecord varSelectorRecords[1];
   1.504 +} Format14Cmap;
   1.505 +
   1.506 +typedef struct {
   1.507 +    AutoSwap_PRUint32 numUVSMappings;
   1.508 +
   1.509 +    typedef struct {
   1.510 +        AutoSwap_PRUint24 unicodeValue;
   1.511 +        AutoSwap_PRUint16 glyphID;
   1.512 +    } UVSMapping;
   1.513 +
   1.514 +    UVSMapping uvsMappings[1];
   1.515 +} NonDefUVSTable;
   1.516 +
   1.517 +#pragma pack()
   1.518 +
   1.519 +uint32_t
   1.520 +gfxFontUtils::MapCharToGlyphFormat4(const uint8_t *aBuf, char16_t aCh)
   1.521 +{
   1.522 +    const Format4Cmap *cmap4 = reinterpret_cast<const Format4Cmap*>(aBuf);
   1.523 +    uint16_t segCount;
   1.524 +    const AutoSwap_PRUint16 *endCodes;
   1.525 +    const AutoSwap_PRUint16 *startCodes;
   1.526 +    const AutoSwap_PRUint16 *idDelta;
   1.527 +    const AutoSwap_PRUint16 *idRangeOffset;
   1.528 +    uint16_t probe;
   1.529 +    uint16_t rangeShiftOver2;
   1.530 +    uint16_t index;
   1.531 +
   1.532 +    segCount = (uint16_t)(cmap4->segCountX2) / 2;
   1.533 +
   1.534 +    endCodes = &cmap4->arrays[0];
   1.535 +    startCodes = &cmap4->arrays[segCount + 1]; // +1 for reserved word between arrays
   1.536 +    idDelta = &startCodes[segCount];
   1.537 +    idRangeOffset = &idDelta[segCount];
   1.538 +
   1.539 +    probe = 1 << (uint16_t)(cmap4->entrySelector);
   1.540 +    rangeShiftOver2 = (uint16_t)(cmap4->rangeShift) / 2;
   1.541 +
   1.542 +    if ((uint16_t)(startCodes[rangeShiftOver2]) <= aCh) {
   1.543 +        index = rangeShiftOver2;
   1.544 +    } else {
   1.545 +        index = 0;
   1.546 +    }
   1.547 +
   1.548 +    while (probe > 1) {
   1.549 +        probe >>= 1;
   1.550 +        if ((uint16_t)(startCodes[index + probe]) <= aCh) {
   1.551 +            index += probe;
   1.552 +        }
   1.553 +    }
   1.554 +
   1.555 +    if (aCh >= (uint16_t)(startCodes[index]) && aCh <= (uint16_t)(endCodes[index])) {
   1.556 +        uint16_t result;
   1.557 +        if ((uint16_t)(idRangeOffset[index]) == 0) {
   1.558 +            result = aCh;
   1.559 +        } else {
   1.560 +            uint16_t offset = aCh - (uint16_t)(startCodes[index]);
   1.561 +            const AutoSwap_PRUint16 *glyphIndexTable =
   1.562 +                (const AutoSwap_PRUint16*)((const char*)&idRangeOffset[index] +
   1.563 +                                           (uint16_t)(idRangeOffset[index]));
   1.564 +            result = glyphIndexTable[offset];
   1.565 +        }
   1.566 +
   1.567 +        // note that this is unsigned 16-bit arithmetic, and may wrap around
   1.568 +        result += (uint16_t)(idDelta[index]);
   1.569 +        return result;
   1.570 +    }
   1.571 +
   1.572 +    return 0;
   1.573 +}
   1.574 +
   1.575 +uint32_t
   1.576 +gfxFontUtils::MapCharToGlyphFormat12(const uint8_t *aBuf, uint32_t aCh)
   1.577 +{
   1.578 +    const Format12CmapHeader *cmap12 =
   1.579 +        reinterpret_cast<const Format12CmapHeader*>(aBuf);
   1.580 +
   1.581 +    // We know that numGroups is within range for the subtable size
   1.582 +    // because it was checked by ReadCMAPTableFormat12.
   1.583 +    uint32_t numGroups = cmap12->numGroups;
   1.584 +
   1.585 +    // The array of groups immediately follows the subtable header.
   1.586 +    const Format12Group *groups =
   1.587 +        reinterpret_cast<const Format12Group*>(aBuf + sizeof(Format12CmapHeader));
   1.588 +
   1.589 +    // For most efficient binary search, we want to work on a range that
   1.590 +    // is a power of 2 so that we can always halve it by shifting.
   1.591 +    // So we find the largest power of 2 that is <= numGroups.
   1.592 +    // We will offset this range by rangeOffset so as to reach the end
   1.593 +    // of the table, provided that doesn't put us beyond the target
   1.594 +    // value from the outset.
   1.595 +    uint32_t powerOf2 = mozilla::FindHighestBit(numGroups);
   1.596 +    uint32_t rangeOffset = numGroups - powerOf2;
   1.597 +    uint32_t range = 0;
   1.598 +    uint32_t startCharCode;
   1.599 +
   1.600 +    if (groups[rangeOffset].startCharCode <= aCh) {
   1.601 +        range = rangeOffset;
   1.602 +    }
   1.603 +
   1.604 +    // Repeatedly halve the size of the range until we find the target group
   1.605 +    while (powerOf2 > 1) {
   1.606 +        powerOf2 >>= 1;
   1.607 +        if (groups[range + powerOf2].startCharCode <= aCh) {
   1.608 +            range += powerOf2;
   1.609 +        }
   1.610 +    }
   1.611 +
   1.612 +    // Check if the character is actually present in the range and return
   1.613 +    // the corresponding glyph ID
   1.614 +    startCharCode = groups[range].startCharCode;
   1.615 +    if (startCharCode <= aCh && groups[range].endCharCode >= aCh) {
   1.616 +        return groups[range].startGlyphId + aCh - startCharCode;
   1.617 +    }
   1.618 +
   1.619 +    // Else it's not present, so return the .notdef glyph
   1.620 +    return 0;
   1.621 +}
   1.622 +
   1.623 +uint16_t
   1.624 +gfxFontUtils::MapUVSToGlyphFormat14(const uint8_t *aBuf, uint32_t aCh, uint32_t aVS)
   1.625 +{
   1.626 +    const Format14Cmap *cmap14 = reinterpret_cast<const Format14Cmap*>(aBuf);
   1.627 +
   1.628 +    // binary search in varSelectorRecords
   1.629 +    uint32_t min = 0;
   1.630 +    uint32_t max = cmap14->numVarSelectorRecords;
   1.631 +    uint32_t nonDefUVSOffset = 0;
   1.632 +    while (min < max) {
   1.633 +        uint32_t index = (min + max) >> 1;
   1.634 +        uint32_t varSelector = cmap14->varSelectorRecords[index].varSelector;
   1.635 +        if (aVS == varSelector) {
   1.636 +            nonDefUVSOffset = cmap14->varSelectorRecords[index].nonDefaultUVSOffset;
   1.637 +            break;
   1.638 +        }
   1.639 +        if (aVS < varSelector) {
   1.640 +            max = index;
   1.641 +        } else {
   1.642 +            min = index + 1;
   1.643 +        }
   1.644 +    }
   1.645 +    if (!nonDefUVSOffset) {
   1.646 +        return 0;
   1.647 +    }
   1.648 +
   1.649 +    const NonDefUVSTable *table = reinterpret_cast<const NonDefUVSTable*>
   1.650 +                                      (aBuf + nonDefUVSOffset);
   1.651 +
   1.652 +    // binary search in uvsMappings
   1.653 +    min = 0;
   1.654 +    max = table->numUVSMappings;
   1.655 +    while (min < max) {
   1.656 +        uint32_t index = (min + max) >> 1;
   1.657 +        uint32_t unicodeValue = table->uvsMappings[index].unicodeValue;
   1.658 +        if (aCh == unicodeValue) {
   1.659 +            return table->uvsMappings[index].glyphID;
   1.660 +        }
   1.661 +        if (aCh < unicodeValue) {
   1.662 +            max = index;
   1.663 +        } else {
   1.664 +            min = index + 1;
   1.665 +        }
   1.666 +    }
   1.667 +
   1.668 +    return 0;
   1.669 +}
   1.670 +
   1.671 +uint32_t
   1.672 +gfxFontUtils::MapCharToGlyph(const uint8_t *aCmapBuf, uint32_t aBufLength,
   1.673 +                             uint32_t aUnicode, uint32_t aVarSelector)
   1.674 +{
   1.675 +    uint32_t offset, uvsOffset;
   1.676 +    bool     symbol;
   1.677 +    uint32_t format = FindPreferredSubtable(aCmapBuf, aBufLength, &offset,
   1.678 +                                            &uvsOffset, &symbol);
   1.679 +
   1.680 +    uint32_t gid;
   1.681 +    switch (format) {
   1.682 +    case 4:
   1.683 +        gid = aUnicode < UNICODE_BMP_LIMIT ?
   1.684 +            MapCharToGlyphFormat4(aCmapBuf + offset, char16_t(aUnicode)) : 0;
   1.685 +        break;
   1.686 +    case 12:
   1.687 +        gid = MapCharToGlyphFormat12(aCmapBuf + offset, aUnicode);
   1.688 +        break;
   1.689 +    default:
   1.690 +        NS_WARNING("unsupported cmap format, glyphs will be missing");
   1.691 +        gid = 0;
   1.692 +    }
   1.693 +
   1.694 +    if (aVarSelector && uvsOffset && gid) {
   1.695 +        uint32_t varGID =
   1.696 +            gfxFontUtils::MapUVSToGlyphFormat14(aCmapBuf + uvsOffset,
   1.697 +                                                aUnicode, aVarSelector);
   1.698 +        if (!varGID) {
   1.699 +            aUnicode = gfxFontUtils::GetUVSFallback(aUnicode, aVarSelector);
   1.700 +            if (aUnicode) {
   1.701 +                switch (format) {
   1.702 +                case 4:
   1.703 +                    if (aUnicode < UNICODE_BMP_LIMIT) {
   1.704 +                        varGID = MapCharToGlyphFormat4(aCmapBuf + offset,
   1.705 +                                                       char16_t(aUnicode));
   1.706 +                    }
   1.707 +                    break;
   1.708 +                case 12:
   1.709 +                    varGID = MapCharToGlyphFormat12(aCmapBuf + offset,
   1.710 +                                                    aUnicode);
   1.711 +                    break;
   1.712 +                }
   1.713 +            }
   1.714 +        }
   1.715 +        if (varGID) {
   1.716 +            gid = varGID;
   1.717 +        }
   1.718 +
   1.719 +        // else the variation sequence was not supported, use default mapping
   1.720 +        // of the character code alone
   1.721 +    }
   1.722 +
   1.723 +    return gid;
   1.724 +}
   1.725 +
   1.726 +void gfxFontUtils::GetPrefsFontList(const char *aPrefName, nsTArray<nsString>& aFontList)
   1.727 +{
   1.728 +    const char16_t kComma = char16_t(',');
   1.729 +    
   1.730 +    aFontList.Clear();
   1.731 +    
   1.732 +    // get the list of single-face font families
   1.733 +    nsAdoptingString fontlistValue = Preferences::GetString(aPrefName);
   1.734 +    if (!fontlistValue) {
   1.735 +        return;
   1.736 +    }
   1.737 +
   1.738 +    // append each font name to the list
   1.739 +    nsAutoString fontname;
   1.740 +    const char16_t *p, *p_end;
   1.741 +    fontlistValue.BeginReading(p);
   1.742 +    fontlistValue.EndReading(p_end);
   1.743 +
   1.744 +     while (p < p_end) {
   1.745 +        const char16_t *nameStart = p;
   1.746 +        while (++p != p_end && *p != kComma)
   1.747 +        /* nothing */ ;
   1.748 +
   1.749 +        // pull out a single name and clean out leading/trailing whitespace        
   1.750 +        fontname = Substring(nameStart, p);
   1.751 +        fontname.CompressWhitespace(true, true);
   1.752 +        
   1.753 +        // append it to the list
   1.754 +        aFontList.AppendElement(fontname);
   1.755 +        ++p;
   1.756 +    }
   1.757 +
   1.758 +}
   1.759 +
   1.760 +// produce a unique font name that is (1) a valid Postscript name and (2) less
   1.761 +// than 31 characters in length.  Using AddFontMemResourceEx on Windows fails 
   1.762 +// for names longer than 30 characters in length.
   1.763 +
   1.764 +#define MAX_B64_LEN 32
   1.765 +
   1.766 +nsresult gfxFontUtils::MakeUniqueUserFontName(nsAString& aName)
   1.767 +{
   1.768 +    nsCOMPtr<nsIUUIDGenerator> uuidgen =
   1.769 +      do_GetService("@mozilla.org/uuid-generator;1");
   1.770 +    NS_ENSURE_TRUE(uuidgen, NS_ERROR_OUT_OF_MEMORY);
   1.771 +
   1.772 +    nsID guid;
   1.773 +
   1.774 +    NS_ASSERTION(sizeof(guid) * 2 <= MAX_B64_LEN, "size of nsID has changed!");
   1.775 +
   1.776 +    nsresult rv = uuidgen->GenerateUUIDInPlace(&guid);
   1.777 +    NS_ENSURE_SUCCESS(rv, rv);
   1.778 +
   1.779 +    char guidB64[MAX_B64_LEN] = {0};
   1.780 +
   1.781 +    if (!PL_Base64Encode(reinterpret_cast<char*>(&guid), sizeof(guid), guidB64))
   1.782 +        return NS_ERROR_FAILURE;
   1.783 +
   1.784 +    // all b64 characters except for '/' are allowed in Postscript names, so convert / ==> -
   1.785 +    char *p;
   1.786 +    for (p = guidB64; *p; p++) {
   1.787 +        if (*p == '/')
   1.788 +            *p = '-';
   1.789 +    }
   1.790 +
   1.791 +    aName.Assign(NS_LITERAL_STRING("uf"));
   1.792 +    aName.AppendASCII(guidB64);
   1.793 +    return NS_OK;
   1.794 +}
   1.795 +
   1.796 +
   1.797 +// TrueType/OpenType table handling code
   1.798 +
   1.799 +// need byte aligned structs
   1.800 +#pragma pack(1)
   1.801 +
   1.802 +// name table stores set of name record structures, followed by
   1.803 +// large block containing all the strings.  name record offset and length
   1.804 +// indicates the offset and length within that block.
   1.805 +// http://www.microsoft.com/typography/otspec/name.htm
   1.806 +struct NameRecordData {
   1.807 +    uint32_t  offset;
   1.808 +    uint32_t  length;
   1.809 +};
   1.810 +
   1.811 +#pragma pack()
   1.812 +
   1.813 +static bool
   1.814 +IsValidSFNTVersion(uint32_t version)
   1.815 +{
   1.816 +    // normally 0x00010000, CFF-style OT fonts == 'OTTO' and Apple TT fonts = 'true'
   1.817 +    // 'typ1' is also possible for old Type 1 fonts in a SFNT container but not supported
   1.818 +    return version == 0x10000 ||
   1.819 +           version == TRUETYPE_TAG('O','T','T','O') ||
   1.820 +           version == TRUETYPE_TAG('t','r','u','e');
   1.821 +}
   1.822 +
   1.823 +// copy and swap UTF-16 values, assume no surrogate pairs, can be in place
   1.824 +static void
   1.825 +CopySwapUTF16(const uint16_t *aInBuf, uint16_t *aOutBuf, uint32_t aLen)
   1.826 +{
   1.827 +    const uint16_t *end = aInBuf + aLen;
   1.828 +    while (aInBuf < end) {
   1.829 +        uint16_t value = *aInBuf;
   1.830 +        *aOutBuf = (value >> 8) | (value & 0xff) << 8;
   1.831 +        aOutBuf++;
   1.832 +        aInBuf++;
   1.833 +    }
   1.834 +}
   1.835 +
   1.836 +gfxUserFontType
   1.837 +gfxFontUtils::DetermineFontDataType(const uint8_t *aFontData, uint32_t aFontDataLength)
   1.838 +{
   1.839 +    // test for OpenType font data
   1.840 +    // problem: EOT-Lite with 0x10000 length will look like TrueType!
   1.841 +    if (aFontDataLength >= sizeof(SFNTHeader)) {
   1.842 +        const SFNTHeader *sfntHeader = reinterpret_cast<const SFNTHeader*>(aFontData);
   1.843 +        uint32_t sfntVersion = sfntHeader->sfntVersion;
   1.844 +        if (IsValidSFNTVersion(sfntVersion)) {
   1.845 +            return GFX_USERFONT_OPENTYPE;
   1.846 +        }
   1.847 +    }
   1.848 +    
   1.849 +    // test for WOFF
   1.850 +    if (aFontDataLength >= sizeof(AutoSwap_PRUint32)) {
   1.851 +        const AutoSwap_PRUint32 *version = 
   1.852 +            reinterpret_cast<const AutoSwap_PRUint32*>(aFontData);
   1.853 +        if (uint32_t(*version) == TRUETYPE_TAG('w','O','F','F')) {
   1.854 +            return GFX_USERFONT_WOFF;
   1.855 +        }
   1.856 +    }
   1.857 +    
   1.858 +    // tests for other formats here
   1.859 +    
   1.860 +    return GFX_USERFONT_UNKNOWN;
   1.861 +}
   1.862 +
   1.863 +nsresult
   1.864 +gfxFontUtils::RenameFont(const nsAString& aName, const uint8_t *aFontData, 
   1.865 +                         uint32_t aFontDataLength, FallibleTArray<uint8_t> *aNewFont)
   1.866 +{
   1.867 +    NS_ASSERTION(aNewFont, "null font data array");
   1.868 +    
   1.869 +    uint64_t dataLength(aFontDataLength);
   1.870 +
   1.871 +    // new name table
   1.872 +    static const uint32_t neededNameIDs[] = {NAME_ID_FAMILY, 
   1.873 +                                             NAME_ID_STYLE,
   1.874 +                                             NAME_ID_UNIQUE,
   1.875 +                                             NAME_ID_FULL,
   1.876 +                                             NAME_ID_POSTSCRIPT};
   1.877 +
   1.878 +    // calculate new name table size
   1.879 +    uint16_t nameCount = ArrayLength(neededNameIDs);
   1.880 +
   1.881 +    // leave room for null-terminator
   1.882 +    uint16_t nameStrLength = (aName.Length() + 1) * sizeof(char16_t); 
   1.883 +
   1.884 +    // round name table size up to 4-byte multiple
   1.885 +    uint32_t nameTableSize = (sizeof(NameHeader) +
   1.886 +                              sizeof(NameRecord) * nameCount +
   1.887 +                              nameStrLength +
   1.888 +                              3) & ~3;
   1.889 +                              
   1.890 +    if (dataLength + nameTableSize > UINT32_MAX)
   1.891 +        return NS_ERROR_FAILURE;
   1.892 +        
   1.893 +    // bug 505386 - need to handle unpadded font length
   1.894 +    uint32_t paddedFontDataSize = (aFontDataLength + 3) & ~3;
   1.895 +    uint32_t adjFontDataSize = paddedFontDataSize + nameTableSize;
   1.896 +
   1.897 +    // create new buffer: old font data plus new name table
   1.898 +    if (!aNewFont->AppendElements(adjFontDataSize))
   1.899 +        return NS_ERROR_OUT_OF_MEMORY;
   1.900 +
   1.901 +    // copy the old font data
   1.902 +    uint8_t *newFontData = reinterpret_cast<uint8_t*>(aNewFont->Elements());
   1.903 +    
   1.904 +    // null the last four bytes in case the font length is not a multiple of 4
   1.905 +    memset(newFontData + aFontDataLength, 0, paddedFontDataSize - aFontDataLength);
   1.906 +
   1.907 +    // copy font data
   1.908 +    memcpy(newFontData, aFontData, aFontDataLength);
   1.909 +    
   1.910 +    // null out the last 4 bytes for checksum calculations
   1.911 +    memset(newFontData + adjFontDataSize - 4, 0, 4);
   1.912 +    
   1.913 +    NameHeader *nameHeader = reinterpret_cast<NameHeader*>(newFontData +
   1.914 +                                                            paddedFontDataSize);
   1.915 +    
   1.916 +    // -- name header
   1.917 +    nameHeader->format = 0;
   1.918 +    nameHeader->count = nameCount;
   1.919 +    nameHeader->stringOffset = sizeof(NameHeader) + nameCount * sizeof(NameRecord);
   1.920 +    
   1.921 +    // -- name records
   1.922 +    uint32_t i;
   1.923 +    NameRecord *nameRecord = reinterpret_cast<NameRecord*>(nameHeader + 1);
   1.924 +    
   1.925 +    for (i = 0; i < nameCount; i++, nameRecord++) {
   1.926 +        nameRecord->platformID = PLATFORM_ID_MICROSOFT;
   1.927 +        nameRecord->encodingID = ENCODING_ID_MICROSOFT_UNICODEBMP;
   1.928 +        nameRecord->languageID = LANG_ID_MICROSOFT_EN_US;
   1.929 +        nameRecord->nameID = neededNameIDs[i];
   1.930 +        nameRecord->offset = 0;
   1.931 +        nameRecord->length = nameStrLength;
   1.932 +    }
   1.933 +    
   1.934 +    // -- string data, located after the name records, stored in big-endian form
   1.935 +    char16_t *strData = reinterpret_cast<char16_t*>(nameRecord);
   1.936 +
   1.937 +    mozilla::NativeEndian::copyAndSwapToBigEndian(strData,
   1.938 +                                                  aName.BeginReading(),
   1.939 +                                                  aName.Length());
   1.940 +    strData[aName.Length()] = 0; // add null termination
   1.941 +    
   1.942 +    // adjust name table header to point to the new name table
   1.943 +    SFNTHeader *sfntHeader = reinterpret_cast<SFNTHeader*>(newFontData);
   1.944 +
   1.945 +    // table directory entries begin immediately following SFNT header
   1.946 +    TableDirEntry *dirEntry = 
   1.947 +        reinterpret_cast<TableDirEntry*>(newFontData + sizeof(SFNTHeader));
   1.948 +
   1.949 +    uint32_t numTables = sfntHeader->numTables;
   1.950 +    
   1.951 +    for (i = 0; i < numTables; i++, dirEntry++) {
   1.952 +        if (dirEntry->tag == TRUETYPE_TAG('n','a','m','e')) {
   1.953 +            break;
   1.954 +        }
   1.955 +    }
   1.956 +    
   1.957 +    // function only called if font validates, so this should always be true
   1.958 +    NS_ASSERTION(i < numTables, "attempt to rename font with no name table");
   1.959 +
   1.960 +    // note: dirEntry now points to name record
   1.961 +    
   1.962 +    // recalculate name table checksum
   1.963 +    uint32_t checkSum = 0;
   1.964 +    AutoSwap_PRUint32 *nameData = reinterpret_cast<AutoSwap_PRUint32*> (nameHeader);
   1.965 +    AutoSwap_PRUint32 *nameDataEnd = nameData + (nameTableSize >> 2);
   1.966 +    
   1.967 +    while (nameData < nameDataEnd)
   1.968 +        checkSum = checkSum + *nameData++;
   1.969 +    
   1.970 +    // adjust name table entry to point to new name table
   1.971 +    dirEntry->offset = paddedFontDataSize;
   1.972 +    dirEntry->length = nameTableSize;
   1.973 +    dirEntry->checkSum = checkSum;
   1.974 +    
   1.975 +    // fix up checksums
   1.976 +    uint32_t checksum = 0;
   1.977 +    
   1.978 +    // checksum for font = (checksum of header) + (checksum of tables)
   1.979 +    uint32_t headerLen = sizeof(SFNTHeader) + sizeof(TableDirEntry) * numTables;
   1.980 +    const AutoSwap_PRUint32 *headerData = 
   1.981 +        reinterpret_cast<const AutoSwap_PRUint32*>(newFontData);
   1.982 +
   1.983 +    // header length is in bytes, checksum calculated in longwords
   1.984 +    for (i = 0; i < (headerLen >> 2); i++, headerData++) {
   1.985 +        checksum += *headerData;
   1.986 +    }
   1.987 +    
   1.988 +    uint32_t headOffset = 0;
   1.989 +    dirEntry = reinterpret_cast<TableDirEntry*>(newFontData + sizeof(SFNTHeader));
   1.990 +
   1.991 +    for (i = 0; i < numTables; i++, dirEntry++) {
   1.992 +        if (dirEntry->tag == TRUETYPE_TAG('h','e','a','d')) {
   1.993 +            headOffset = dirEntry->offset;
   1.994 +        }
   1.995 +        checksum += dirEntry->checkSum;
   1.996 +    }
   1.997 +    
   1.998 +    NS_ASSERTION(headOffset != 0, "no head table for font");
   1.999 +    
  1.1000 +    HeadTable *headData = reinterpret_cast<HeadTable*>(newFontData + headOffset);
  1.1001 +
  1.1002 +    headData->checkSumAdjustment = HeadTable::HEAD_CHECKSUM_CALC_CONST - checksum;
  1.1003 +
  1.1004 +    return NS_OK;
  1.1005 +}
  1.1006 +
  1.1007 +// This is only called after the basic validity of the downloaded sfnt
  1.1008 +// data has been checked, so it should never fail to find the name table
  1.1009 +// (though it might fail to read it, if memory isn't available);
  1.1010 +// other checks here are just for extra paranoia.
  1.1011 +nsresult
  1.1012 +gfxFontUtils::GetFullNameFromSFNT(const uint8_t* aFontData, uint32_t aLength,
  1.1013 +                                  nsAString& aFullName)
  1.1014 +{
  1.1015 +    aFullName.AssignLiteral("(MISSING NAME)"); // should always get replaced
  1.1016 +
  1.1017 +    NS_ENSURE_TRUE(aLength >= sizeof(SFNTHeader), NS_ERROR_UNEXPECTED);
  1.1018 +    const SFNTHeader *sfntHeader =
  1.1019 +        reinterpret_cast<const SFNTHeader*>(aFontData);
  1.1020 +    const TableDirEntry *dirEntry =
  1.1021 +        reinterpret_cast<const TableDirEntry*>(aFontData + sizeof(SFNTHeader));
  1.1022 +    uint32_t numTables = sfntHeader->numTables;
  1.1023 +    NS_ENSURE_TRUE(aLength >=
  1.1024 +                   sizeof(SFNTHeader) + numTables * sizeof(TableDirEntry),
  1.1025 +                   NS_ERROR_UNEXPECTED);
  1.1026 +    bool foundName = false;
  1.1027 +    for (uint32_t i = 0; i < numTables; i++, dirEntry++) {
  1.1028 +        if (dirEntry->tag == TRUETYPE_TAG('n','a','m','e')) {
  1.1029 +            foundName = true;
  1.1030 +            break;
  1.1031 +        }
  1.1032 +    }
  1.1033 +    
  1.1034 +    // should never fail, as we're only called after font validation succeeded
  1.1035 +    NS_ENSURE_TRUE(foundName, NS_ERROR_NOT_AVAILABLE);
  1.1036 +
  1.1037 +    uint32_t len = dirEntry->length;
  1.1038 +    NS_ENSURE_TRUE(aLength > len && aLength - len >= dirEntry->offset,
  1.1039 +                   NS_ERROR_UNEXPECTED);
  1.1040 +
  1.1041 +    hb_blob_t *nameBlob =
  1.1042 +        hb_blob_create((const char*)aFontData + dirEntry->offset, len,
  1.1043 +                       HB_MEMORY_MODE_READONLY, nullptr, nullptr);
  1.1044 +    nsresult rv = GetFullNameFromTable(nameBlob, aFullName);
  1.1045 +    hb_blob_destroy(nameBlob);
  1.1046 +
  1.1047 +    return rv;
  1.1048 +}
  1.1049 +
  1.1050 +nsresult
  1.1051 +gfxFontUtils::GetFullNameFromTable(hb_blob_t *aNameTable,
  1.1052 +                                   nsAString& aFullName)
  1.1053 +{
  1.1054 +    nsAutoString name;
  1.1055 +    nsresult rv =
  1.1056 +        gfxFontUtils::ReadCanonicalName(aNameTable,
  1.1057 +                                        gfxFontUtils::NAME_ID_FULL,
  1.1058 +                                        name);
  1.1059 +    if (NS_SUCCEEDED(rv) && !name.IsEmpty()) {
  1.1060 +        aFullName = name;
  1.1061 +        return NS_OK;
  1.1062 +    }
  1.1063 +    rv = gfxFontUtils::ReadCanonicalName(aNameTable,
  1.1064 +                                         gfxFontUtils::NAME_ID_FAMILY,
  1.1065 +                                         name);
  1.1066 +    if (NS_SUCCEEDED(rv) && !name.IsEmpty()) {
  1.1067 +        nsAutoString styleName;
  1.1068 +        rv = gfxFontUtils::ReadCanonicalName(aNameTable,
  1.1069 +                                             gfxFontUtils::NAME_ID_STYLE,
  1.1070 +                                             styleName);
  1.1071 +        if (NS_SUCCEEDED(rv) && !styleName.IsEmpty()) {
  1.1072 +            name.AppendLiteral(" ");
  1.1073 +            name.Append(styleName);
  1.1074 +            aFullName = name;
  1.1075 +        }
  1.1076 +        return NS_OK;
  1.1077 +    }
  1.1078 +
  1.1079 +    return NS_ERROR_NOT_AVAILABLE;
  1.1080 +}
  1.1081 +
  1.1082 +nsresult
  1.1083 +gfxFontUtils::GetFamilyNameFromTable(hb_blob_t *aNameTable,
  1.1084 +                                     nsAString& aFullName)
  1.1085 +{
  1.1086 +    nsAutoString name;
  1.1087 +    nsresult rv =
  1.1088 +        gfxFontUtils::ReadCanonicalName(aNameTable,
  1.1089 +                                        gfxFontUtils::NAME_ID_FAMILY,
  1.1090 +                                        name);
  1.1091 +    if (NS_SUCCEEDED(rv) && !name.IsEmpty()) {
  1.1092 +        aFullName = name;
  1.1093 +        return NS_OK;
  1.1094 +    }
  1.1095 +    return NS_ERROR_NOT_AVAILABLE;
  1.1096 +}
  1.1097 +
  1.1098 +enum {
  1.1099 +#if defined(XP_MACOSX)
  1.1100 +    CANONICAL_LANG_ID = gfxFontUtils::LANG_ID_MAC_ENGLISH,
  1.1101 +    PLATFORM_ID       = gfxFontUtils::PLATFORM_ID_MAC
  1.1102 +#else
  1.1103 +    CANONICAL_LANG_ID = gfxFontUtils::LANG_ID_MICROSOFT_EN_US,
  1.1104 +    PLATFORM_ID       = gfxFontUtils::PLATFORM_ID_MICROSOFT
  1.1105 +#endif
  1.1106 +};    
  1.1107 +
  1.1108 +nsresult
  1.1109 +gfxFontUtils::ReadNames(const char *aNameData, uint32_t aDataLen,
  1.1110 +                        uint32_t aNameID, int32_t aPlatformID,
  1.1111 +                        nsTArray<nsString>& aNames)
  1.1112 +{
  1.1113 +    return ReadNames(aNameData, aDataLen, aNameID, LANG_ALL,
  1.1114 +                     aPlatformID, aNames);
  1.1115 +}
  1.1116 +
  1.1117 +nsresult
  1.1118 +gfxFontUtils::ReadCanonicalName(hb_blob_t *aNameTable, uint32_t aNameID,
  1.1119 +                                nsString& aName)
  1.1120 +{
  1.1121 +    uint32_t nameTableLen;
  1.1122 +    const char *nameTable = hb_blob_get_data(aNameTable, &nameTableLen);
  1.1123 +    return ReadCanonicalName(nameTable, nameTableLen, aNameID, aName);
  1.1124 +}
  1.1125 +
  1.1126 +nsresult
  1.1127 +gfxFontUtils::ReadCanonicalName(const char *aNameData, uint32_t aDataLen,
  1.1128 +                                uint32_t aNameID, nsString& aName)
  1.1129 +{
  1.1130 +    nsresult rv;
  1.1131 +    
  1.1132 +    nsTArray<nsString> names;
  1.1133 +    
  1.1134 +    // first, look for the English name (this will succeed 99% of the time)
  1.1135 +    rv = ReadNames(aNameData, aDataLen, aNameID, CANONICAL_LANG_ID, 
  1.1136 +                   PLATFORM_ID, names);
  1.1137 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1138 +        
  1.1139 +    // otherwise, grab names for all languages
  1.1140 +    if (names.Length() == 0) {
  1.1141 +        rv = ReadNames(aNameData, aDataLen, aNameID, LANG_ALL,
  1.1142 +                       PLATFORM_ID, names);
  1.1143 +        NS_ENSURE_SUCCESS(rv, rv);
  1.1144 +    }
  1.1145 +    
  1.1146 +#if defined(XP_MACOSX)
  1.1147 +    // may be dealing with font that only has Microsoft name entries
  1.1148 +    if (names.Length() == 0) {
  1.1149 +        rv = ReadNames(aNameData, aDataLen, aNameID, LANG_ID_MICROSOFT_EN_US,
  1.1150 +                       PLATFORM_ID_MICROSOFT, names);
  1.1151 +        NS_ENSURE_SUCCESS(rv, rv);
  1.1152 +        
  1.1153 +        // getting really desperate now, take anything!
  1.1154 +        if (names.Length() == 0) {
  1.1155 +            rv = ReadNames(aNameData, aDataLen, aNameID, LANG_ALL,
  1.1156 +                           PLATFORM_ID_MICROSOFT, names);
  1.1157 +            NS_ENSURE_SUCCESS(rv, rv);
  1.1158 +        }
  1.1159 +    }
  1.1160 +#endif
  1.1161 +
  1.1162 +    // return the first name (99.9% of the time names will
  1.1163 +    // contain a single English name)
  1.1164 +    if (names.Length()) {
  1.1165 +        aName.Assign(names[0]);
  1.1166 +        return NS_OK;
  1.1167 +    }
  1.1168 +        
  1.1169 +    return NS_ERROR_FAILURE;
  1.1170 +}
  1.1171 +
  1.1172 +// Charsets to use for decoding Mac platform font names.
  1.1173 +// This table is sorted by {encoding, language}, with the wildcard "ANY" being
  1.1174 +// greater than any defined values for each field; we use a binary search on both
  1.1175 +// fields, and fall back to matching only encoding if necessary
  1.1176 +
  1.1177 +// Some "redundant" entries for specific combinations are included such as
  1.1178 +// encoding=roman, lang=english, in order that common entries will be found
  1.1179 +// on the first search.
  1.1180 +
  1.1181 +#define ANY 0xffff
  1.1182 +const gfxFontUtils::MacFontNameCharsetMapping gfxFontUtils::gMacFontNameCharsets[] =
  1.1183 +{
  1.1184 +    { ENCODING_ID_MAC_ROMAN,        LANG_ID_MAC_ENGLISH,      "macintosh"       },
  1.1185 +    { ENCODING_ID_MAC_ROMAN,        LANG_ID_MAC_ICELANDIC,    "x-mac-icelandic" },
  1.1186 +    { ENCODING_ID_MAC_ROMAN,        LANG_ID_MAC_TURKISH,      "x-mac-turkish"   },
  1.1187 +    { ENCODING_ID_MAC_ROMAN,        LANG_ID_MAC_POLISH,       "x-mac-ce"        },
  1.1188 +    { ENCODING_ID_MAC_ROMAN,        LANG_ID_MAC_ROMANIAN,     "x-mac-romanian"  },
  1.1189 +    { ENCODING_ID_MAC_ROMAN,        LANG_ID_MAC_CZECH,        "x-mac-ce"        },
  1.1190 +    { ENCODING_ID_MAC_ROMAN,        LANG_ID_MAC_SLOVAK,       "x-mac-ce"        },
  1.1191 +    { ENCODING_ID_MAC_ROMAN,        ANY,                      "macintosh"       },
  1.1192 +    { ENCODING_ID_MAC_JAPANESE,     LANG_ID_MAC_JAPANESE,     "Shift_JIS"       },
  1.1193 +    { ENCODING_ID_MAC_JAPANESE,     ANY,                      "Shift_JIS"       },
  1.1194 +    { ENCODING_ID_MAC_TRAD_CHINESE, LANG_ID_MAC_TRAD_CHINESE, "Big5"            },
  1.1195 +    { ENCODING_ID_MAC_TRAD_CHINESE, ANY,                      "Big5"            },
  1.1196 +    { ENCODING_ID_MAC_KOREAN,       LANG_ID_MAC_KOREAN,       "EUC-KR"          },
  1.1197 +    { ENCODING_ID_MAC_KOREAN,       ANY,                      "EUC-KR"          },
  1.1198 +    { ENCODING_ID_MAC_ARABIC,       LANG_ID_MAC_ARABIC,       "x-mac-arabic"    },
  1.1199 +    { ENCODING_ID_MAC_ARABIC,       LANG_ID_MAC_URDU,         "x-mac-farsi"     },
  1.1200 +    { ENCODING_ID_MAC_ARABIC,       LANG_ID_MAC_FARSI,        "x-mac-farsi"     },
  1.1201 +    { ENCODING_ID_MAC_ARABIC,       ANY,                      "x-mac-arabic"    },
  1.1202 +    { ENCODING_ID_MAC_HEBREW,       LANG_ID_MAC_HEBREW,       "x-mac-hebrew"    },
  1.1203 +    { ENCODING_ID_MAC_HEBREW,       ANY,                      "x-mac-hebrew"    },
  1.1204 +    { ENCODING_ID_MAC_GREEK,        ANY,                      "x-mac-greek"     },
  1.1205 +    { ENCODING_ID_MAC_CYRILLIC,     ANY,                      "x-mac-cyrillic"  },
  1.1206 +    { ENCODING_ID_MAC_DEVANAGARI,   ANY,                      "x-mac-devanagari"},
  1.1207 +    { ENCODING_ID_MAC_GURMUKHI,     ANY,                      "x-mac-gurmukhi"  },
  1.1208 +    { ENCODING_ID_MAC_GUJARATI,     ANY,                      "x-mac-gujarati"  },
  1.1209 +    { ENCODING_ID_MAC_SIMP_CHINESE, LANG_ID_MAC_SIMP_CHINESE, "GB2312"          },
  1.1210 +    { ENCODING_ID_MAC_SIMP_CHINESE, ANY,                      "GB2312"          }
  1.1211 +};
  1.1212 +
  1.1213 +const char* gfxFontUtils::gISOFontNameCharsets[] = 
  1.1214 +{
  1.1215 +    /* 0 */ "us-ascii"   ,
  1.1216 +    /* 1 */ nullptr       , /* spec says "ISO 10646" but does not specify encoding form! */
  1.1217 +    /* 2 */ "ISO-8859-1"
  1.1218 +};
  1.1219 +
  1.1220 +const char* gfxFontUtils::gMSFontNameCharsets[] =
  1.1221 +{
  1.1222 +    /* [0] ENCODING_ID_MICROSOFT_SYMBOL */      ""          ,
  1.1223 +    /* [1] ENCODING_ID_MICROSOFT_UNICODEBMP */  ""          ,
  1.1224 +    /* [2] ENCODING_ID_MICROSOFT_SHIFTJIS */    "Shift_JIS" ,
  1.1225 +    /* [3] ENCODING_ID_MICROSOFT_PRC */         nullptr      ,
  1.1226 +    /* [4] ENCODING_ID_MICROSOFT_BIG5 */        "Big5"      ,
  1.1227 +    /* [5] ENCODING_ID_MICROSOFT_WANSUNG */     nullptr      ,
  1.1228 +    /* [6] ENCODING_ID_MICROSOFT_JOHAB */       "x-johab"   ,
  1.1229 +    /* [7] reserved */                          nullptr      ,
  1.1230 +    /* [8] reserved */                          nullptr      ,
  1.1231 +    /* [9] reserved */                          nullptr      ,
  1.1232 +    /*[10] ENCODING_ID_MICROSOFT_UNICODEFULL */ ""
  1.1233 +};
  1.1234 +
  1.1235 +// Return the name of the charset we should use to decode a font name
  1.1236 +// given the name table attributes.
  1.1237 +// Special return values:
  1.1238 +//    ""       charset is UTF16BE, no need for a converter
  1.1239 +//    nullptr   unknown charset, do not attempt conversion
  1.1240 +const char*
  1.1241 +gfxFontUtils::GetCharsetForFontName(uint16_t aPlatform, uint16_t aScript, uint16_t aLanguage)
  1.1242 +{
  1.1243 +    switch (aPlatform)
  1.1244 +    {
  1.1245 +    case PLATFORM_ID_UNICODE:
  1.1246 +        return "";
  1.1247 +
  1.1248 +    case PLATFORM_ID_MAC:
  1.1249 +        {
  1.1250 +            uint32_t lo = 0, hi = ArrayLength(gMacFontNameCharsets);
  1.1251 +            MacFontNameCharsetMapping searchValue = { aScript, aLanguage, nullptr };
  1.1252 +            for (uint32_t i = 0; i < 2; ++i) {
  1.1253 +                // binary search; if not found, set language to ANY and try again
  1.1254 +                while (lo < hi) {
  1.1255 +                    uint32_t mid = (lo + hi) / 2;
  1.1256 +                    const MacFontNameCharsetMapping& entry = gMacFontNameCharsets[mid];
  1.1257 +                    if (entry < searchValue) {
  1.1258 +                        lo = mid + 1;
  1.1259 +                        continue;
  1.1260 +                    }
  1.1261 +                    if (searchValue < entry) {
  1.1262 +                        hi = mid;
  1.1263 +                        continue;
  1.1264 +                    }
  1.1265 +                    // found a match
  1.1266 +                    return entry.mCharsetName;
  1.1267 +                }
  1.1268 +
  1.1269 +                // no match, so reset high bound for search and re-try
  1.1270 +                hi = ArrayLength(gMacFontNameCharsets);
  1.1271 +                searchValue.mLanguage = ANY;
  1.1272 +            }
  1.1273 +        }
  1.1274 +        break;
  1.1275 +
  1.1276 +    case PLATFORM_ID_ISO:
  1.1277 +        if (aScript < ArrayLength(gISOFontNameCharsets)) {
  1.1278 +            return gISOFontNameCharsets[aScript];
  1.1279 +        }
  1.1280 +        break;
  1.1281 +
  1.1282 +    case PLATFORM_ID_MICROSOFT:
  1.1283 +        if (aScript < ArrayLength(gMSFontNameCharsets)) {
  1.1284 +            return gMSFontNameCharsets[aScript];
  1.1285 +        }
  1.1286 +        break;
  1.1287 +    }
  1.1288 +
  1.1289 +    return nullptr;
  1.1290 +}
  1.1291 +
  1.1292 +// convert a raw name from the name table to an nsString, if possible;
  1.1293 +// return value indicates whether conversion succeeded
  1.1294 +bool
  1.1295 +gfxFontUtils::DecodeFontName(const char *aNameData, int32_t aByteLen, 
  1.1296 +                             uint32_t aPlatformCode, uint32_t aScriptCode,
  1.1297 +                             uint32_t aLangCode, nsAString& aName)
  1.1298 +{
  1.1299 +    if (aByteLen <= 0) {
  1.1300 +        NS_WARNING("empty font name");
  1.1301 +        aName.SetLength(0);
  1.1302 +        return true;
  1.1303 +    }
  1.1304 +
  1.1305 +    const char *csName = GetCharsetForFontName(aPlatformCode, aScriptCode, aLangCode);
  1.1306 +
  1.1307 +    if (!csName) {
  1.1308 +        // nullptr -> unknown charset
  1.1309 +#ifdef DEBUG
  1.1310 +        char warnBuf[128];
  1.1311 +        if (aByteLen > 64)
  1.1312 +            aByteLen = 64;
  1.1313 +        sprintf(warnBuf, "skipping font name, unknown charset %d:%d:%d for <%.*s>",
  1.1314 +                aPlatformCode, aScriptCode, aLangCode, aByteLen, aNameData);
  1.1315 +        NS_WARNING(warnBuf);
  1.1316 +#endif
  1.1317 +        return false;
  1.1318 +    }
  1.1319 +
  1.1320 +    if (csName[0] == 0) {
  1.1321 +        // empty charset name: data is utf16be, no need to instantiate a converter
  1.1322 +        uint32_t strLen = aByteLen / 2;
  1.1323 +#ifdef IS_LITTLE_ENDIAN
  1.1324 +        aName.SetLength(strLen);
  1.1325 +        CopySwapUTF16(reinterpret_cast<const uint16_t*>(aNameData),
  1.1326 +                      reinterpret_cast<uint16_t*>(aName.BeginWriting()), strLen);
  1.1327 +#else
  1.1328 +        aName.Assign(reinterpret_cast<const char16_t*>(aNameData), strLen);
  1.1329 +#endif    
  1.1330 +        return true;
  1.1331 +    }
  1.1332 +
  1.1333 +    nsCOMPtr<nsIUnicodeDecoder> decoder =
  1.1334 +        mozilla::dom::EncodingUtils::DecoderForEncoding(csName);
  1.1335 +    if (!decoder) {
  1.1336 +        NS_WARNING("failed to get the decoder for a font name string");
  1.1337 +        return false;
  1.1338 +    }
  1.1339 +
  1.1340 +    int32_t destLength;
  1.1341 +    nsresult rv = decoder->GetMaxLength(aNameData, aByteLen, &destLength);
  1.1342 +    if (NS_FAILED(rv)) {
  1.1343 +        NS_WARNING("decoder->GetMaxLength failed, invalid font name?");
  1.1344 +        return false;
  1.1345 +    }
  1.1346 +
  1.1347 +    // make space for the converted string
  1.1348 +    aName.SetLength(destLength);
  1.1349 +    rv = decoder->Convert(aNameData, &aByteLen,
  1.1350 +                          aName.BeginWriting(), &destLength);
  1.1351 +    if (NS_FAILED(rv)) {
  1.1352 +        NS_WARNING("decoder->Convert failed, invalid font name?");
  1.1353 +        return false;
  1.1354 +    }
  1.1355 +    aName.Truncate(destLength); // set the actual length
  1.1356 +
  1.1357 +    return true;
  1.1358 +}
  1.1359 +
  1.1360 +nsresult
  1.1361 +gfxFontUtils::ReadNames(const char *aNameData, uint32_t aDataLen,
  1.1362 +                        uint32_t aNameID,
  1.1363 +                        int32_t aLangID, int32_t aPlatformID,
  1.1364 +                        nsTArray<nsString>& aNames)
  1.1365 +{
  1.1366 +    NS_ASSERTION(aDataLen != 0, "null name table");
  1.1367 +
  1.1368 +    if (!aDataLen) {
  1.1369 +        return NS_ERROR_FAILURE;
  1.1370 +    }
  1.1371 +
  1.1372 +    // -- name table data
  1.1373 +    const NameHeader *nameHeader = reinterpret_cast<const NameHeader*>(aNameData);
  1.1374 +
  1.1375 +    uint32_t nameCount = nameHeader->count;
  1.1376 +
  1.1377 +    // -- sanity check the number of name records
  1.1378 +    if (uint64_t(nameCount) * sizeof(NameRecord) > aDataLen) {
  1.1379 +        NS_WARNING("invalid font (name table data)");
  1.1380 +        return NS_ERROR_FAILURE;
  1.1381 +    }
  1.1382 +
  1.1383 +    // -- iterate through name records
  1.1384 +    const NameRecord *nameRecord
  1.1385 +        = reinterpret_cast<const NameRecord*>(aNameData + sizeof(NameHeader));
  1.1386 +    uint64_t nameStringsBase = uint64_t(nameHeader->stringOffset);
  1.1387 +
  1.1388 +    uint32_t i;
  1.1389 +    for (i = 0; i < nameCount; i++, nameRecord++) {
  1.1390 +        uint32_t platformID;
  1.1391 +
  1.1392 +        // skip over unwanted nameID's
  1.1393 +        if (uint32_t(nameRecord->nameID) != aNameID)
  1.1394 +            continue;
  1.1395 +
  1.1396 +        // skip over unwanted platform data
  1.1397 +        platformID = nameRecord->platformID;
  1.1398 +        if (aPlatformID != PLATFORM_ALL
  1.1399 +            && uint32_t(nameRecord->platformID) != PLATFORM_ID)
  1.1400 +            continue;
  1.1401 +
  1.1402 +        // skip over unwanted languages
  1.1403 +        if (aLangID != LANG_ALL
  1.1404 +              && uint32_t(nameRecord->languageID) != uint32_t(aLangID))
  1.1405 +            continue;
  1.1406 +
  1.1407 +        // add name to names array
  1.1408 +
  1.1409 +        // -- calculate string location
  1.1410 +        uint32_t namelen = nameRecord->length;
  1.1411 +        uint32_t nameoff = nameRecord->offset;  // offset from base of string storage
  1.1412 +
  1.1413 +        if (nameStringsBase + uint64_t(nameoff) + uint64_t(namelen)
  1.1414 +                > aDataLen) {
  1.1415 +            NS_WARNING("invalid font (name table strings)");
  1.1416 +            return NS_ERROR_FAILURE;
  1.1417 +        }
  1.1418 +
  1.1419 +        // -- decode if necessary and make nsString
  1.1420 +        nsAutoString name;
  1.1421 +
  1.1422 +        DecodeFontName(aNameData + nameStringsBase + nameoff, namelen,
  1.1423 +                       platformID, uint32_t(nameRecord->encodingID),
  1.1424 +                       uint32_t(nameRecord->languageID), name);
  1.1425 +
  1.1426 +        uint32_t k, numNames;
  1.1427 +        bool foundName = false;
  1.1428 +
  1.1429 +        numNames = aNames.Length();
  1.1430 +        for (k = 0; k < numNames; k++) {
  1.1431 +            if (name.Equals(aNames[k])) {
  1.1432 +                foundName = true;
  1.1433 +                break;
  1.1434 +            }
  1.1435 +        }
  1.1436 +
  1.1437 +        if (!foundName)
  1.1438 +            aNames.AppendElement(name);
  1.1439 +
  1.1440 +    }
  1.1441 +
  1.1442 +    return NS_OK;
  1.1443 +}
  1.1444 +
  1.1445 +#ifdef XP_WIN
  1.1446 +
  1.1447 +/* static */
  1.1448 +bool
  1.1449 +gfxFontUtils::IsCffFont(const uint8_t* aFontData)
  1.1450 +{
  1.1451 +    // this is only called after aFontData has passed basic validation,
  1.1452 +    // so we know there is enough data present to allow us to read the version!
  1.1453 +    const SFNTHeader *sfntHeader = reinterpret_cast<const SFNTHeader*>(aFontData);
  1.1454 +    return (sfntHeader->sfntVersion == TRUETYPE_TAG('O','T','T','O'));
  1.1455 +}
  1.1456 +
  1.1457 +#endif
  1.1458 +

mercurial