| | 41 | |
|---|
| | 42 | static inline USHORT readBigEndianWord(const BYTE* word) { return (word[0] << 8) | word[1]; } |
|---|
| | 43 | |
|---|
| | 44 | static CFStringRef getPostScriptName(CFStringRef faceName, HDC dc) |
|---|
| | 45 | { |
|---|
| | 46 | const DWORD cMaxNameTableSize = 1024 * 1024; |
|---|
| | 47 | |
|---|
| | 48 | static HashMap<String, RetainPtr<CFStringRef> > nameMap; |
|---|
| | 49 | |
|---|
| | 50 | // Check our hash first. |
|---|
| | 51 | String faceString(faceName); |
|---|
| | 52 | RetainPtr<CFStringRef> result = nameMap.get(faceString); |
|---|
| | 53 | if (result) |
|---|
| | 54 | return result.get(); |
|---|
| | 55 | |
|---|
| | 56 | // We need to obtain the PostScript name from the name table and use it instead,. |
|---|
| | 57 | DWORD bufferSize = GetFontData(dc, 'eman', 0, NULL, 0); // "name" backwards |
|---|
| | 58 | if (bufferSize == 0 || bufferSize == GDI_ERROR || bufferSize > cMaxNameTableSize) |
|---|
| | 59 | return NULL; |
|---|
| | 60 | |
|---|
| | 61 | Vector<BYTE> bufferVector(bufferSize); |
|---|
| | 62 | BYTE* buffer = bufferVector.data(); |
|---|
| | 63 | if (GetFontData(dc, 'eman', 0, buffer, bufferSize) == GDI_ERROR) |
|---|
| | 64 | return NULL; |
|---|
| | 65 | |
|---|
| | 66 | if (bufferSize < 6) |
|---|
| | 67 | return NULL; |
|---|
| | 68 | |
|---|
| | 69 | USHORT numberOfRecords = readBigEndianWord(buffer + 2); |
|---|
| | 70 | UINT stringsOffset = readBigEndianWord(buffer + 4); |
|---|
| | 71 | if (bufferSize < stringsOffset) |
|---|
| | 72 | return NULL; |
|---|
| | 73 | |
|---|
| | 74 | BYTE* strings = buffer + stringsOffset; |
|---|
| | 75 | |
|---|
| | 76 | // Now walk each name record looking for a Mac or Windows PostScript name. |
|---|
| | 77 | UINT offset = 6; |
|---|
| | 78 | for (int i = 0; i < numberOfRecords; i++) { |
|---|
| | 79 | if (bufferSize < offset + 12) |
|---|
| | 80 | return NULL; |
|---|
| | 81 | |
|---|
| | 82 | USHORT platformID = readBigEndianWord(buffer + offset); |
|---|
| | 83 | USHORT encodingID = readBigEndianWord(buffer + offset + 2); |
|---|
| | 84 | USHORT languageID = readBigEndianWord(buffer + offset + 4); |
|---|
| | 85 | USHORT nameID = readBigEndianWord(buffer + offset + 6); |
|---|
| | 86 | USHORT length = readBigEndianWord(buffer + offset + 8); |
|---|
| | 87 | USHORT nameOffset = readBigEndianWord(buffer + offset + 10); |
|---|
| | 88 | |
|---|
| | 89 | if (platformID == 3 && encodingID == 1 && languageID == 0x409 && nameID == 6) { |
|---|
| | 90 | // This is a Windows PostScript name and is therefore UTF-16. |
|---|
| | 91 | // Pass Big Endian as the encoding. |
|---|
| | 92 | if (bufferSize < stringsOffset + nameOffset + length) |
|---|
| | 93 | return NULL; |
|---|
| | 94 | result.adoptCF(CFStringCreateWithBytes(NULL, strings + nameOffset, length, kCFStringEncodingUTF16BE, false)); |
|---|
| | 95 | break; |
|---|
| | 96 | } else if (platformID == 1 && encodingID == 0 && languageID == 0 && nameID == 6) { |
|---|
| | 97 | // This is a Mac PostScript name and is therefore ASCII. |
|---|
| | 98 | // See http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html |
|---|
| | 99 | if (bufferSize < stringsOffset + nameOffset + length) |
|---|
| | 100 | return NULL; |
|---|
| | 101 | result.adoptCF(CFStringCreateWithBytes(NULL, strings + nameOffset, length, kCFStringEncodingASCII, false)); |
|---|
| | 102 | break; |
|---|
| | 103 | } |
|---|
| | 104 | |
|---|
| | 105 | offset += 12; |
|---|
| | 106 | } |
|---|
| | 107 | |
|---|
| | 108 | if (result) |
|---|
| | 109 | nameMap.set(faceString, result); |
|---|
| | 110 | return result.get(); |
|---|
| | 111 | } |
|---|
| 105 | | CFStringRef cfName = CFStringCreateWithCharacters(NULL, (const UniChar*)faceName, wcslen(faceName)); |
|---|
| 106 | | m_cgFont = CGFontCreateWithFontName(cfName); |
|---|
| 107 | | ASSERT(m_cgFont); |
|---|
| 108 | | CFRelease(cfName); |
|---|
| 109 | | |
|---|
| | 181 | // Try the face name first. Windows may end up localizing this name, and CG doesn't know about |
|---|
| | 182 | // the localization. If the create fails, we'll try the PostScript name. |
|---|
| | 183 | RetainPtr<CFStringRef> fullName(AdoptCF, CFStringCreateWithCharacters(NULL, (const UniChar*)faceName, wcslen(faceName))); |
|---|
| | 184 | m_cgFont = CGFontCreateWithFontName(fullName.get()); |
|---|
| | 185 | if (!m_cgFont) { |
|---|
| | 186 | CFStringRef postScriptName = getPostScriptName(fullName.get(), hdc); |
|---|
| | 187 | if (postScriptName) { |
|---|
| | 188 | m_cgFont = CGFontCreateWithFontName(postScriptName); |
|---|
| | 189 | ASSERT(m_cgFont); |
|---|
| | 190 | } |
|---|
| | 191 | } |
|---|