LCOV - code coverage report
Current view: top level - gfx/2d - SFNTNameTable.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 13 113 11.5 %
Date: 2017-07-14 16:53:18 Functions: 0 12 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "SFNTNameTable.h"
       8             : 
       9             : #include "BigEndianInts.h"
      10             : #include "Logging.h"
      11             : #include "mozilla/Move.h"
      12             : 
      13             : #if defined(XP_MACOSX)
      14             : #include <CoreFoundation/CoreFoundation.h>
      15             : #endif
      16             : 
      17             : namespace mozilla {
      18             : namespace gfx {
      19             : 
      20           3 : static const BigEndianUint16 FORMAT_0 = 0;
      21             : 
      22           3 : static const BigEndianUint16 NAME_ID_FAMILY = 1;
      23           3 : static const BigEndianUint16 NAME_ID_STYLE = 2;
      24           3 : static const BigEndianUint16 NAME_ID_FULL = 4;
      25             : 
      26           3 : static const BigEndianUint16 PLATFORM_ID_UNICODE = 0;
      27           3 : static const BigEndianUint16 PLATFORM_ID_MAC = 1;
      28           3 : static const BigEndianUint16 PLATFORM_ID_MICROSOFT = 3;
      29             : 
      30           3 : static const BigEndianUint16 ENCODING_ID_MICROSOFT_SYMBOL = 0;
      31           3 : static const BigEndianUint16 ENCODING_ID_MICROSOFT_UNICODEBMP = 1;
      32           3 : static const BigEndianUint16 ENCODING_ID_MICROSOFT_UNICODEFULL = 10;
      33             : 
      34           3 : static const BigEndianUint16 ENCODING_ID_MAC_ROMAN = 0;
      35             : 
      36           3 : static const BigEndianUint16 LANG_ID_MAC_ENGLISH = 0;
      37             : 
      38           3 : static const BigEndianUint16 LANG_ID_MICROSOFT_EN_US = 0x0409;
      39             : 
      40             : #pragma pack(push, 1)
      41             : 
      42             : // Name table has a header, followed by name records, followed by string data.
      43             : struct NameHeader
      44             : {
      45             :   BigEndianUint16 format;       // Format selector (=0).
      46             :   BigEndianUint16 count;        // Number of name records.
      47             :   BigEndianUint16 stringOffset; // Offset to string storage from start of table.
      48             : };
      49             : 
      50             : struct NameRecord
      51             : {
      52             :   BigEndianUint16 platformID;
      53             :   BigEndianUint16 encodingID; // Platform-specific encoding ID
      54             :   BigEndianUint16 languageID;
      55             :   BigEndianUint16 nameID;
      56             :   BigEndianUint16 length;     // String length in bytes.
      57             :   BigEndianUint16 offset;     // String offset from start of storage in bytes.
      58             : };
      59             : 
      60             : #pragma pack(pop)
      61             : 
      62             : enum ENameDecoder : int
      63             : {
      64             :   eNameDecoderUTF16,
      65             : #if defined(XP_MACOSX)
      66             :   eNameDecoderMacRoman,
      67             : #endif
      68             :   eNameDecoderNone
      69             : };
      70             : 
      71             : /* static */
      72             : UniquePtr<SFNTNameTable>
      73           0 : SFNTNameTable::Create(const uint8_t *aNameData, uint32_t aDataLength)
      74             : {
      75           0 :   MOZ_ASSERT(aNameData);
      76             : 
      77           0 :   if (aDataLength < sizeof(NameHeader)) {
      78           0 :     gfxWarning() << "Name data too short to contain NameHeader.";
      79           0 :     return nullptr;
      80             :   }
      81             : 
      82           0 :   const NameHeader *nameHeader = reinterpret_cast<const NameHeader*>(aNameData);
      83           0 :   if (nameHeader->format != FORMAT_0) {
      84           0 :     gfxWarning() << "Only Name Table Format 0 is supported.";
      85           0 :     return nullptr;
      86             :   }
      87             : 
      88           0 :   uint16_t stringOffset = nameHeader->stringOffset;
      89             : 
      90           0 :   if (stringOffset !=
      91           0 :       sizeof(NameHeader) + (nameHeader->count * sizeof(NameRecord))) {
      92           0 :     gfxWarning() << "Name table string offset is incorrect.";
      93           0 :     return nullptr;
      94             :   }
      95             : 
      96           0 :   if (aDataLength < stringOffset) {
      97           0 :     gfxWarning() << "Name data too short to contain name records.";
      98           0 :     return nullptr;
      99             :   }
     100             : 
     101             :   return UniquePtr<SFNTNameTable>(
     102           0 :     new SFNTNameTable(nameHeader, aNameData, aDataLength));
     103             : }
     104             : 
     105           0 : SFNTNameTable::SFNTNameTable(const NameHeader *aNameHeader,
     106           0 :                              const uint8_t *aNameData, uint32_t aDataLength)
     107             :   : mFirstRecord(reinterpret_cast<const NameRecord*>(aNameData
     108           0 :                                                      + sizeof(NameHeader)))
     109           0 :   , mEndOfRecords(mFirstRecord + aNameHeader->count)
     110           0 :   , mStringData(aNameData + aNameHeader->stringOffset)
     111           0 :   , mStringDataLength(aDataLength - aNameHeader->stringOffset)
     112             : {
     113           0 :   MOZ_ASSERT(reinterpret_cast<const uint8_t*>(aNameHeader) == aNameData);
     114           0 : }
     115             : 
     116             : static bool
     117           0 : IsUTF16Encoding(const NameRecord *aNameRecord)
     118             : {
     119           0 :   if (aNameRecord->platformID == PLATFORM_ID_MICROSOFT &&
     120           0 :       (aNameRecord->encodingID == ENCODING_ID_MICROSOFT_UNICODEBMP ||
     121           0 :        aNameRecord->encodingID == ENCODING_ID_MICROSOFT_SYMBOL)) {
     122           0 :     return true;
     123             :   }
     124             : 
     125           0 :   if (aNameRecord->platformID == PLATFORM_ID_UNICODE) {
     126           0 :     return true;
     127             :   }
     128             : 
     129           0 :   return false;
     130             : }
     131             : 
     132             : #if defined(XP_MACOSX)
     133             : static bool
     134             : IsMacRomanEncoding(const NameRecord *aNameRecord)
     135             : {
     136             :   if (aNameRecord->platformID == PLATFORM_ID_MAC &&
     137             :       aNameRecord->encodingID == ENCODING_ID_MAC_ROMAN) {
     138             :     return true;
     139             :   }
     140             : 
     141             :   return false;
     142             : }
     143             : #endif
     144             : 
     145             : static NameRecordMatchers*
     146           0 : CreateCanonicalMatchers(const BigEndianUint16& aNameID)
     147             : {
     148             :   // For Windows, we return only Microsoft platform name record
     149             :   // matchers. On Mac, we return matchers for both Microsoft platform
     150             :   // records and Mac platform records.
     151           0 :   NameRecordMatchers *matchers = new NameRecordMatchers();
     152             : 
     153             : #if defined(XP_MACOSX)
     154             :   // First, look for the English name.
     155             :   if (!matchers->append(
     156             :     [=](const NameRecord *aNameRecord) {
     157             :         if (aNameRecord->nameID == aNameID &&
     158             :             aNameRecord->languageID == LANG_ID_MAC_ENGLISH &&
     159             :             aNameRecord->platformID == PLATFORM_ID_MAC &&
     160             :             IsMacRomanEncoding(aNameRecord)) {
     161             :           return eNameDecoderMacRoman;
     162             :         } else  {
     163             :           return eNameDecoderNone;
     164             :         }
     165             :     })) {
     166             :     MOZ_CRASH();
     167             :   }
     168             : 
     169             :   // Second, look for all languages.
     170             :   if (!matchers->append(
     171             :     [=](const NameRecord *aNameRecord) {
     172             :         if (aNameRecord->nameID == aNameID &&
     173             :             aNameRecord->platformID == PLATFORM_ID_MAC &&
     174             :             IsMacRomanEncoding(aNameRecord)) {
     175             :           return eNameDecoderMacRoman;
     176             :         } else  {
     177             :           return eNameDecoderNone;
     178             :         }
     179             :     })) {
     180             :     MOZ_CRASH();
     181             :   }
     182             : #endif /* defined(XP_MACOSX) */
     183             : 
     184             :   // First, look for the English name (this will normally succeed).
     185           0 :   if (!matchers->append(
     186           0 :     [=](const NameRecord *aNameRecord) {
     187           0 :         if (aNameRecord->nameID == aNameID &&
     188           0 :             aNameRecord->languageID == LANG_ID_MICROSOFT_EN_US &&
     189           0 :             aNameRecord->platformID == PLATFORM_ID_MICROSOFT &&
     190           0 :             IsUTF16Encoding(aNameRecord)) {
     191           0 :           return eNameDecoderUTF16;
     192             :         } else {
     193           0 :           return eNameDecoderNone;
     194             :         }
     195             :     })) {
     196           0 :     MOZ_CRASH();
     197             :   }
     198             : 
     199             :   // Second, look for all languages.
     200           0 :   if (!matchers->append(
     201           0 :     [=](const NameRecord *aNameRecord) {
     202           0 :         if (aNameRecord->nameID == aNameID &&
     203           0 :             aNameRecord->platformID == PLATFORM_ID_MICROSOFT &&
     204           0 :             IsUTF16Encoding(aNameRecord)) {
     205           0 :           return eNameDecoderUTF16;
     206             :         } else {
     207           0 :           return eNameDecoderNone;
     208             :         }
     209             :     })) {
     210           0 :     MOZ_CRASH();
     211             :   }
     212             : 
     213           0 :   return matchers;
     214             : }
     215             : 
     216             : static const NameRecordMatchers&
     217           0 : FullNameMatchers()
     218             : {
     219             :   static const NameRecordMatchers *sFullNameMatchers =
     220           0 :     CreateCanonicalMatchers(NAME_ID_FULL);
     221           0 :   return *sFullNameMatchers;
     222             : }
     223             : 
     224             : static const NameRecordMatchers&
     225           0 : FamilyMatchers()
     226             : {
     227             :   static const NameRecordMatchers *sFamilyMatchers =
     228           0 :     CreateCanonicalMatchers(NAME_ID_FAMILY);
     229           0 :   return *sFamilyMatchers;
     230             : }
     231             : 
     232             : static const NameRecordMatchers&
     233           0 : StyleMatchers()
     234             : {
     235             :   static const NameRecordMatchers *sStyleMatchers =
     236           0 :     CreateCanonicalMatchers(NAME_ID_STYLE);
     237           0 :   return *sStyleMatchers;
     238             : }
     239             : 
     240             : bool
     241           0 : SFNTNameTable::GetU16FullName(mozilla::u16string& aU16FullName)
     242             : {
     243           0 :   if (ReadU16Name(FullNameMatchers(), aU16FullName)) {
     244           0 :     return true;
     245             :   }
     246             : 
     247             :   // If the full name record doesn't exist create the name from the family space
     248             :   // concatenated with the style.
     249           0 :   mozilla::u16string familyName;
     250           0 :   if (!ReadU16Name(FamilyMatchers(), familyName)) {
     251           0 :     return false;
     252             :   }
     253             : 
     254           0 :   mozilla::u16string styleName;
     255           0 :   if (!ReadU16Name(StyleMatchers(), styleName)) {
     256           0 :     return false;
     257             :   }
     258             : 
     259           0 :   aU16FullName.assign(Move(familyName));
     260           0 :   aU16FullName.append(u" ");
     261           0 :   aU16FullName.append(styleName);
     262           0 :   return true;
     263             : }
     264             : 
     265             : bool
     266           0 : SFNTNameTable::ReadU16Name(const NameRecordMatchers& aMatchers,
     267             :                            mozilla::u16string& aU16Name)
     268             : {
     269           0 :   MOZ_ASSERT(!aMatchers.empty());
     270             : 
     271           0 :   for (size_t i = 0; i < aMatchers.length(); ++i) {
     272           0 :     const NameRecord* record = mFirstRecord;
     273           0 :     while (record != mEndOfRecords) {
     274           0 :       switch (aMatchers[i](record)) {
     275             :         case eNameDecoderUTF16:
     276           0 :           return ReadU16NameFromU16Record(record, aU16Name);
     277             : #if defined(XP_MACOSX)
     278             :         case eNameDecoderMacRoman:
     279             :           return ReadU16NameFromMacRomanRecord(record, aU16Name);
     280             : #endif
     281             :         case eNameDecoderNone:
     282           0 :           break;
     283             :         default:
     284           0 :           MOZ_CRASH("Invalid matcher encoding type");
     285             :           break;
     286             :       }
     287           0 :       ++record;
     288             :     }
     289             :   }
     290             : 
     291           0 :   return false;
     292             : }
     293             : 
     294             : bool
     295           0 : SFNTNameTable::ReadU16NameFromU16Record(const NameRecord *aNameRecord,
     296             :                                         mozilla::u16string& aU16Name)
     297             : {
     298           0 :   uint32_t offset = aNameRecord->offset;
     299           0 :   uint32_t length = aNameRecord->length;
     300           0 :   if (mStringDataLength < offset + length) {
     301           0 :     gfxWarning() << "Name data too short to contain name string.";
     302           0 :     return false;
     303             :   }
     304             : 
     305           0 :   const uint8_t *startOfName = mStringData + offset;
     306           0 :   size_t actualLength = length / sizeof(char16_t);
     307           0 :   UniquePtr<char16_t[]> nameData(new char16_t[actualLength]);
     308           0 :   NativeEndian::copyAndSwapFromBigEndian(nameData.get(), startOfName,
     309           0 :                                          actualLength);
     310             : 
     311           0 :   aU16Name.assign(nameData.get(), actualLength);
     312           0 :   return true;
     313             : }
     314             : 
     315             : #if defined(XP_MACOSX)
     316             : bool
     317             : SFNTNameTable::ReadU16NameFromMacRomanRecord(const NameRecord *aNameRecord,
     318             :                                              mozilla::u16string& aU16Name)
     319             : {
     320             :   uint32_t offset = aNameRecord->offset;
     321             :   uint32_t length = aNameRecord->length;
     322             :   if (mStringDataLength < offset + length) {
     323             :     gfxWarning() << "Name data too short to contain name string.";
     324             :     return false;
     325             :   }
     326             :   if (length > INT_MAX) {
     327             :     gfxWarning() << "Name record too long to decode.";
     328             :     return false;
     329             :   }
     330             : 
     331             :   // pointer to the Mac Roman encoded string in the name record
     332             :   const uint8_t *encodedStr = mStringData + offset;
     333             : 
     334             :   CFStringRef cfString;
     335             :   cfString = CFStringCreateWithBytesNoCopy(kCFAllocatorDefault, encodedStr,
     336             :                                            length, kCFStringEncodingMacRoman,
     337             :                                            false, kCFAllocatorNull);
     338             : 
     339             :   // length (in UTF-16 code pairs) of the decoded string
     340             :   CFIndex decodedLength = CFStringGetLength(cfString);
     341             : 
     342             :   // temporary buffer
     343             :   UniquePtr<UniChar[]> u16Buffer = MakeUnique<UniChar[]>(decodedLength);
     344             : 
     345             :   CFStringGetCharacters(cfString, CFRangeMake(0, decodedLength),
     346             :                         u16Buffer.get());
     347             : 
     348             :   CFRelease(cfString);
     349             : 
     350             :   aU16Name.assign(reinterpret_cast<char16_t*>(u16Buffer.get()), decodedLength);
     351             : 
     352             :   return true;
     353             : }
     354             : #endif
     355             : 
     356             : } // gfx
     357             : } // mozilla

Generated by: LCOV version 1.13