/src/mozilla-central/gfx/2d/SFNTData.cpp
Line | Count | Source (jump to first uncovered line) |
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 "SFNTData.h" |
8 | | |
9 | | #include <algorithm> |
10 | | |
11 | | #include "BigEndianInts.h" |
12 | | #include "Logging.h" |
13 | | #include "mozilla/HashFunctions.h" |
14 | | #include "SFNTNameTable.h" |
15 | | |
16 | | namespace mozilla { |
17 | | namespace gfx { |
18 | | |
19 | 0 | #define TRUETYPE_TAG(a, b, c, d) ((a) << 24 | (b) << 16 | (c) << 8 | (d)) |
20 | | |
21 | | #pragma pack(push, 1) |
22 | | |
23 | | struct TTCHeader |
24 | | { |
25 | | BigEndianUint32 ttcTag; // Always 'ttcf' |
26 | | BigEndianUint32 version; // Fixed, 0x00010000 |
27 | | BigEndianUint32 numFonts; |
28 | | }; |
29 | | |
30 | | struct OffsetTable |
31 | | { |
32 | | BigEndianUint32 sfntVersion; // Fixed, 0x00010000 for version 1.0. |
33 | | BigEndianUint16 numTables; |
34 | | BigEndianUint16 searchRange; // (Maximum power of 2 <= numTables) x 16. |
35 | | BigEndianUint16 entrySelector; // Log2(maximum power of 2 <= numTables). |
36 | | BigEndianUint16 rangeShift; // NumTables x 16-searchRange. |
37 | | }; |
38 | | |
39 | | struct TableDirEntry |
40 | | { |
41 | | BigEndianUint32 tag; // 4 -byte identifier. |
42 | | BigEndianUint32 checkSum; // CheckSum for this table. |
43 | | BigEndianUint32 offset; // Offset from beginning of TrueType font file. |
44 | | BigEndianUint32 length; // Length of this table. |
45 | | |
46 | | friend bool operator<(const TableDirEntry& lhs, const uint32_t aTag) |
47 | 0 | { |
48 | 0 | return lhs.tag < aTag; |
49 | 0 | } |
50 | | }; |
51 | | |
52 | | #pragma pack(pop) |
53 | | |
54 | | class SFNTData::Font |
55 | | { |
56 | | public: |
57 | | Font(const OffsetTable *aOffsetTable, const uint8_t *aFontData, |
58 | | uint32_t aDataLength) |
59 | | : mFontData(aFontData) |
60 | | , mFirstDirEntry(reinterpret_cast<const TableDirEntry*>(aOffsetTable + 1)) |
61 | | , mEndOfDirEntries(mFirstDirEntry + aOffsetTable->numTables) |
62 | | , mDataLength(aDataLength) |
63 | 0 | { |
64 | 0 | } |
65 | | |
66 | | bool GetU16FullName(mozilla::u16string& aU16FullName) |
67 | 0 | { |
68 | 0 | const TableDirEntry* dirEntry = |
69 | 0 | GetDirEntry(TRUETYPE_TAG('n', 'a', 'm', 'e')); |
70 | 0 | if (!dirEntry) { |
71 | 0 | gfxWarning() << "Name table entry not found."; |
72 | 0 | return false; |
73 | 0 | } |
74 | 0 |
|
75 | 0 | UniquePtr<SFNTNameTable> nameTable = |
76 | 0 | SFNTNameTable::Create((mFontData + dirEntry->offset), dirEntry->length); |
77 | 0 | if (!nameTable) { |
78 | 0 | return false; |
79 | 0 | } |
80 | 0 | |
81 | 0 | return nameTable->GetU16FullName(aU16FullName); |
82 | 0 | } |
83 | | |
84 | | private: |
85 | | |
86 | | const TableDirEntry* |
87 | | GetDirEntry(const uint32_t aTag) |
88 | 0 | { |
89 | 0 | const TableDirEntry* foundDirEntry = |
90 | 0 | std::lower_bound(mFirstDirEntry, mEndOfDirEntries, aTag); |
91 | 0 |
|
92 | 0 | if (foundDirEntry == mEndOfDirEntries || foundDirEntry->tag != aTag) { |
93 | 0 | gfxWarning() << "Font data does not contain tag."; |
94 | 0 | return nullptr; |
95 | 0 | } |
96 | 0 |
|
97 | 0 | if (mDataLength < (foundDirEntry->offset + foundDirEntry->length)) { |
98 | 0 | gfxWarning() << "Font data too short to contain table."; |
99 | 0 | return nullptr; |
100 | 0 | } |
101 | 0 |
|
102 | 0 | return foundDirEntry; |
103 | 0 | } |
104 | | |
105 | | const uint8_t *mFontData; |
106 | | const TableDirEntry *mFirstDirEntry; |
107 | | const TableDirEntry *mEndOfDirEntries; |
108 | | uint32_t mDataLength; |
109 | | }; |
110 | | |
111 | | /* static */ |
112 | | UniquePtr<SFNTData> |
113 | | SFNTData::Create(const uint8_t *aFontData, uint32_t aDataLength) |
114 | 0 | { |
115 | 0 | MOZ_ASSERT(aFontData); |
116 | 0 |
|
117 | 0 | // Check to see if this is a font collection. |
118 | 0 | if (aDataLength < sizeof(TTCHeader)) { |
119 | 0 | gfxWarning() << "Font data too short."; |
120 | 0 | return nullptr; |
121 | 0 | } |
122 | 0 |
|
123 | 0 | const TTCHeader *ttcHeader = reinterpret_cast<const TTCHeader*>(aFontData); |
124 | 0 | if (ttcHeader->ttcTag == TRUETYPE_TAG('t', 't', 'c', 'f')) { |
125 | 0 | uint32_t numFonts = ttcHeader->numFonts; |
126 | 0 | if (aDataLength < sizeof(TTCHeader) + (numFonts * sizeof(BigEndianUint32))) { |
127 | 0 | gfxWarning() << "Font data too short to contain full TTC Header."; |
128 | 0 | return nullptr; |
129 | 0 | } |
130 | 0 |
|
131 | 0 | UniquePtr<SFNTData> sfntData(new SFNTData); |
132 | 0 | const BigEndianUint32* offset = |
133 | 0 | reinterpret_cast<const BigEndianUint32*>(aFontData + sizeof(TTCHeader)); |
134 | 0 | const BigEndianUint32* endOfOffsets = offset + numFonts; |
135 | 0 | while (offset != endOfOffsets) { |
136 | 0 | if (!sfntData->AddFont(aFontData, aDataLength, *offset)) { |
137 | 0 | return nullptr; |
138 | 0 | } |
139 | 0 | ++offset; |
140 | 0 | } |
141 | 0 |
|
142 | 0 | return sfntData; |
143 | 0 | } |
144 | 0 | |
145 | 0 | UniquePtr<SFNTData> sfntData(new SFNTData); |
146 | 0 | if (!sfntData->AddFont(aFontData, aDataLength, 0)) { |
147 | 0 | return nullptr; |
148 | 0 | } |
149 | 0 | |
150 | 0 | return sfntData; |
151 | 0 | } |
152 | | |
153 | | /* static */ |
154 | | uint64_t |
155 | | SFNTData::GetUniqueKey(const uint8_t *aFontData, uint32_t aDataLength, |
156 | | uint32_t aVarDataSize, const void* aVarData) |
157 | 0 | { |
158 | 0 | uint64_t hash; |
159 | 0 | UniquePtr<SFNTData> sfntData = SFNTData::Create(aFontData, aDataLength); |
160 | 0 | mozilla::u16string firstName; |
161 | 0 | if (sfntData && sfntData->GetU16FullName(0, firstName)) { |
162 | 0 | hash = HashString(firstName.c_str(), firstName.length()); |
163 | 0 | } else { |
164 | 0 | gfxWarning() << "Failed to get name from font data hashing whole font."; |
165 | 0 | hash = HashString(aFontData, aDataLength); |
166 | 0 | } |
167 | 0 |
|
168 | 0 | if (aVarDataSize) { |
169 | 0 | hash = AddToHash(hash, HashBytes(aVarData, aVarDataSize)); |
170 | 0 | } |
171 | 0 |
|
172 | 0 | return hash << 32 | aDataLength;; |
173 | 0 | } |
174 | | |
175 | | SFNTData::~SFNTData() |
176 | 0 | { |
177 | 0 | for (size_t i = 0; i < mFonts.length(); ++i) { |
178 | 0 | delete mFonts[i]; |
179 | 0 | } |
180 | 0 | } |
181 | | |
182 | | bool |
183 | | SFNTData::GetU16FullName(uint32_t aIndex, mozilla::u16string& aU16FullName) |
184 | 0 | { |
185 | 0 | if (aIndex >= mFonts.length()) { |
186 | 0 | gfxWarning() << "aIndex to font data too high."; |
187 | 0 | return false; |
188 | 0 | } |
189 | 0 |
|
190 | 0 | return mFonts[aIndex]->GetU16FullName(aU16FullName); |
191 | 0 | } |
192 | | |
193 | | bool |
194 | | SFNTData::GetU16FullNames(Vector<mozilla::u16string>& aU16FullNames) |
195 | 0 | { |
196 | 0 | bool fontFound = false; |
197 | 0 | for (size_t i = 0; i < mFonts.length(); ++i) { |
198 | 0 | mozilla::u16string name; |
199 | 0 | if (mFonts[i]->GetU16FullName(name)) { |
200 | 0 | fontFound = true; |
201 | 0 | } |
202 | 0 | if (!aU16FullNames.append(std::move(name))) { |
203 | 0 | return false; |
204 | 0 | } |
205 | 0 | } |
206 | 0 |
|
207 | 0 | return fontFound; |
208 | 0 | } |
209 | | |
210 | | bool |
211 | | SFNTData::GetIndexForU16Name(const mozilla::u16string& aU16FullName, |
212 | | uint32_t* aIndex, size_t aTruncatedLen) |
213 | 0 | { |
214 | 0 | for (size_t i = 0; i < mFonts.length(); ++i) { |
215 | 0 | mozilla::u16string name; |
216 | 0 | if (!mFonts[i]->GetU16FullName(name)) { |
217 | 0 | continue; |
218 | 0 | } |
219 | 0 | |
220 | 0 | if (aTruncatedLen) { |
221 | 0 | MOZ_ASSERT(aU16FullName.length() <= aTruncatedLen); |
222 | 0 | name = name.substr(0, aTruncatedLen); |
223 | 0 | } |
224 | 0 |
|
225 | 0 | if (name == aU16FullName) { |
226 | 0 | *aIndex = i; |
227 | 0 | return true; |
228 | 0 | } |
229 | 0 | } |
230 | 0 |
|
231 | 0 | return false; |
232 | 0 | } |
233 | | |
234 | | bool |
235 | | SFNTData::AddFont(const uint8_t *aFontData, uint32_t aDataLength, |
236 | | uint32_t aOffset) |
237 | 0 | { |
238 | 0 | uint32_t remainingLength = aDataLength - aOffset; |
239 | 0 | if (remainingLength < sizeof(OffsetTable)) { |
240 | 0 | gfxWarning() << "Font data too short to contain OffsetTable " << aOffset; |
241 | 0 | return false; |
242 | 0 | } |
243 | 0 |
|
244 | 0 | const OffsetTable *offsetTable = |
245 | 0 | reinterpret_cast<const OffsetTable*>(aFontData + aOffset); |
246 | 0 | if (remainingLength < |
247 | 0 | sizeof(OffsetTable) + (offsetTable->numTables * sizeof(TableDirEntry))) { |
248 | 0 | gfxWarning() << "Font data too short to contain tables."; |
249 | 0 | return false; |
250 | 0 | } |
251 | 0 |
|
252 | 0 | return mFonts.append(new Font(offsetTable, aFontData, aDataLength)); |
253 | 0 | } |
254 | | |
255 | | } // gfx |
256 | | } // mozilla |