]>
Commit | Line | Data |
---|---|---|
b75a7d8f A |
1 | /* |
2 | ******************************************************************************* | |
3 | * | |
57a6839d | 4 | * Copyright (C) 1999-2013, International Business Machines |
b75a7d8f A |
5 | * Corporation and others. All Rights Reserved. |
6 | * | |
7 | ******************************************************************************* | |
8 | * file name: PortableFontInstance.cpp | |
9 | * | |
10 | * created on: 11/22/1999 | |
11 | * created by: Eric R. Mader | |
12 | */ | |
13 | ||
14 | #include <stdio.h> | |
15 | ||
16 | #include "layout/LETypes.h" | |
17 | #include "layout/LEFontInstance.h" | |
18 | #include "layout/LESwaps.h" | |
19 | ||
20 | #include "PortableFontInstance.h" | |
21 | ||
57a6839d | 22 | //#include "letest.h" |
b75a7d8f A |
23 | #include "sfnt.h" |
24 | ||
25 | #include <string.h> | |
57a6839d A |
26 | #include <stdio.h> |
27 | ||
28 | #if 0 | |
29 | static const char *letagToStr(LETag tag, char *str) { | |
30 | str[0]= 0xFF & (tag>>24); | |
31 | str[1]= 0xFF & (tag>>16); | |
32 | str[2]= 0xFF & (tag>>8); | |
33 | str[3]= 0xFF & (tag>>0); | |
34 | str[4]= 0; | |
35 | return str; | |
36 | } | |
37 | #endif | |
b75a7d8f A |
38 | |
39 | // | |
40 | // Finds the high bit by binary searching | |
41 | // through the bits in n. | |
42 | // | |
43 | le_int8 PortableFontInstance::highBit(le_int32 value) | |
44 | { | |
45 | if (value <= 0) { | |
46 | return -32; | |
47 | } | |
48 | ||
49 | le_uint8 bit = 0; | |
50 | ||
51 | if (value >= 1 << 16) { | |
52 | value >>= 16; | |
53 | bit += 16; | |
54 | } | |
55 | ||
56 | if (value >= 1 << 8) { | |
57 | value >>= 8; | |
58 | bit += 8; | |
59 | } | |
60 | ||
61 | if (value >= 1 << 4) { | |
62 | value >>= 4; | |
63 | bit += 4; | |
64 | } | |
65 | ||
66 | if (value >= 1 << 2) { | |
67 | value >>= 2; | |
68 | bit += 2; | |
69 | } | |
70 | ||
71 | if (value >= 1 << 1) { | |
72 | value >>= 1; | |
73 | bit += 1; | |
74 | } | |
75 | ||
76 | return bit; | |
77 | } | |
78 | ||
73c04bcf A |
79 | PortableFontInstance::PortableFontInstance(const char *fileName, float pointSize, LEErrorCode &status) |
80 | : fFile(NULL), fPointSize(pointSize), fUnitsPerEM(0), fFontChecksum(0), fAscent(0), fDescent(0), fLeading(0), | |
81 | fDirectory(NULL), fNAMETable(NULL), fNameCount(0), fNameStringOffset(0), fCMAPMapper(NULL), fHMTXTable(NULL), fNumGlyphs(0), fNumLongHorMetrics(0) | |
b75a7d8f A |
82 | { |
83 | if (LE_FAILURE(status)) { | |
84 | return; | |
85 | } | |
86 | ||
87 | // open the font file | |
88 | fFile = fopen(fileName, "rb"); | |
57a6839d | 89 | //printf("Open Font: %s\n", fileName); |
b75a7d8f A |
90 | |
91 | if (fFile == NULL) { | |
57a6839d | 92 | printf("%s:%d: %s: FNF\n", __FILE__, __LINE__, fileName); |
b75a7d8f A |
93 | status = LE_FONT_FILE_NOT_FOUND_ERROR; |
94 | return; | |
95 | } | |
96 | ||
97 | // read in the directory | |
98 | SFNTDirectory tempDir; | |
99 | ||
100 | fread(&tempDir, sizeof tempDir, 1, fFile); | |
101 | ||
102 | le_int32 dirSize = sizeof tempDir + ((SWAPW(tempDir.numTables) - ANY_NUMBER) * sizeof(DirectoryEntry)); | |
103 | const LETag headTag = LE_HEAD_TABLE_TAG; | |
104 | const LETag hheaTag = LE_HHEA_TABLE_TAG; | |
105 | const HEADTable *headTable = NULL; | |
106 | const HHEATable *hheaTable = NULL; | |
73c04bcf | 107 | // const NAMETable *nameTable = NULL; |
b75a7d8f A |
108 | le_uint16 numTables = 0; |
109 | ||
57a6839d | 110 | fDirectory = (const SFNTDirectory *) LE_NEW_ARRAY(char, dirSize); |
b75a7d8f A |
111 | |
112 | if (fDirectory == NULL) { | |
57a6839d | 113 | printf("%s:%d: %s: malloc err\n", __FILE__, __LINE__, fileName); |
b75a7d8f A |
114 | status = LE_MEMORY_ALLOCATION_ERROR; |
115 | goto error_exit; | |
116 | } | |
117 | ||
118 | fseek(fFile, 0L, SEEK_SET); | |
119 | fread((void *) fDirectory, sizeof(char), dirSize, fFile); | |
120 | ||
121 | // | |
122 | // We calculate these numbers 'cause some fonts | |
123 | // have bogus values for them in the directory header. | |
124 | // | |
125 | numTables = SWAPW(fDirectory->numTables); | |
126 | fDirPower = 1 << highBit(numTables); | |
127 | fDirExtra = numTables - fDirPower; | |
128 | ||
129 | // read unitsPerEm from 'head' table | |
130 | headTable = (const HEADTable *) readFontTable(headTag); | |
131 | ||
132 | if (headTable == NULL) { | |
133 | status = LE_MISSING_FONT_TABLE_ERROR; | |
57a6839d | 134 | printf("%s:%d: %s: missing head table\n", __FILE__, __LINE__, fileName); |
b75a7d8f A |
135 | goto error_exit; |
136 | } | |
137 | ||
73c04bcf A |
138 | fUnitsPerEM = SWAPW(headTable->unitsPerEm); |
139 | fFontChecksum = SWAPL(headTable->checksumAdjustment); | |
46f4442e | 140 | freeFontTable(headTable); |
b75a7d8f | 141 | |
73c04bcf A |
142 | //nameTable = (NAMETable *) readFontTable(nameTag); |
143 | ||
144 | //if (nameTable == NULL) { | |
145 | // status = LE_MISSING_FONT_TABLE_ERROR; | |
146 | // goto error_exit; | |
147 | //} | |
148 | ||
149 | //fFontVersionString = findName(nameTable, NAME_VERSION_STRING, PLATFORM_MACINTOSH, MACINTOSH_ROMAN, MACINTOSH_ENGLISH); | |
150 | ||
151 | //if (fFontVersionString == NULL) { | |
152 | // status = LE_MISSING_FONT_TABLE_ERROR; | |
153 | // goto error_exit; | |
154 | //} | |
155 | ||
46f4442e | 156 | //freeFontTable(nameTable); |
73c04bcf | 157 | |
b75a7d8f A |
158 | hheaTable = (HHEATable *) readFontTable(hheaTag); |
159 | ||
160 | if (hheaTable == NULL) { | |
57a6839d | 161 | printf("%s:%d: %s: missing hhea table\n", __FILE__, __LINE__, fileName); |
b75a7d8f A |
162 | status = LE_MISSING_FONT_TABLE_ERROR; |
163 | goto error_exit; | |
164 | } | |
165 | ||
166 | fAscent = (le_int32) yUnitsToPoints((float) SWAPW(hheaTable->ascent)); | |
167 | fDescent = (le_int32) yUnitsToPoints((float) SWAPW(hheaTable->descent)); | |
168 | fLeading = (le_int32) yUnitsToPoints((float) SWAPW(hheaTable->lineGap)); | |
169 | ||
170 | fNumLongHorMetrics = SWAPW(hheaTable->numOfLongHorMetrics); | |
171 | ||
46f4442e | 172 | freeFontTable((void *) hheaTable); |
b75a7d8f A |
173 | |
174 | fCMAPMapper = findUnicodeMapper(); | |
175 | ||
176 | if (fCMAPMapper == NULL) { | |
57a6839d | 177 | printf("%s:%d: %s: can't load cmap\n", __FILE__, __LINE__, fileName); |
b75a7d8f A |
178 | status = LE_MISSING_FONT_TABLE_ERROR; |
179 | goto error_exit; | |
180 | } | |
181 | ||
182 | return; | |
183 | ||
184 | error_exit: | |
185 | fclose(fFile); | |
186 | fFile = NULL; | |
187 | return; | |
188 | } | |
189 | ||
190 | PortableFontInstance::~PortableFontInstance() | |
191 | { | |
192 | if (fFile != NULL) { | |
193 | fclose(fFile); | |
194 | ||
46f4442e A |
195 | freeFontTable(fHMTXTable); |
196 | freeFontTable(fNAMETable); | |
b75a7d8f A |
197 | |
198 | delete fCMAPMapper; | |
199 | ||
57a6839d | 200 | LE_DELETE_ARRAY(fDirectory); |
b75a7d8f | 201 | } |
73c04bcf | 202 | } |
b75a7d8f | 203 | |
b75a7d8f A |
204 | const DirectoryEntry *PortableFontInstance::findTable(LETag tag) const |
205 | { | |
206 | if (fDirectory != NULL) { | |
207 | le_uint16 table = 0; | |
208 | le_uint16 probe = fDirPower; | |
209 | ||
210 | if (SWAPL(fDirectory->tableDirectory[fDirExtra].tag) <= tag) { | |
211 | table = fDirExtra; | |
212 | } | |
213 | ||
214 | while (probe > (1 << 0)) { | |
215 | probe >>= 1; | |
216 | ||
217 | if (SWAPL(fDirectory->tableDirectory[table + probe].tag) <= tag) { | |
218 | table += probe; | |
219 | } | |
220 | } | |
221 | ||
222 | if (SWAPL(fDirectory->tableDirectory[table].tag) == tag) { | |
223 | return &fDirectory->tableDirectory[table]; | |
224 | } | |
225 | } | |
226 | ||
227 | return NULL; | |
228 | } | |
229 | ||
230 | const void *PortableFontInstance::readTable(LETag tag, le_uint32 *length) const | |
231 | { | |
232 | const DirectoryEntry *entry = findTable(tag); | |
233 | ||
234 | if (entry == NULL) { | |
235 | *length = 0; | |
236 | return NULL; | |
237 | } | |
238 | ||
239 | *length = SWAPL(entry->length); | |
240 | ||
57a6839d | 241 | void *table = LE_NEW_ARRAY(char, *length); |
b75a7d8f A |
242 | |
243 | if (table != NULL) { | |
244 | fseek(fFile, SWAPL(entry->offset), SEEK_SET); | |
245 | fread(table, sizeof(char), *length, fFile); | |
246 | } | |
247 | ||
248 | return table; | |
249 | } | |
250 | ||
251 | const void *PortableFontInstance::getFontTable(LETag tableTag) const | |
252 | { | |
57a6839d A |
253 | size_t ignored; |
254 | return getFontTable(tableTag, ignored); | |
b75a7d8f A |
255 | } |
256 | ||
57a6839d A |
257 | const void *PortableFontInstance::getFontTable(LETag tableTag, size_t &length) const |
258 | { | |
259 | return FontTableCache::find(tableTag, length); | |
260 | } | |
261 | ||
262 | const void *PortableFontInstance::readFontTable(LETag tableTag, size_t &length) const | |
b75a7d8f A |
263 | { |
264 | le_uint32 len; | |
265 | ||
57a6839d A |
266 | const void *data= readTable(tableTag, &len); |
267 | length = len; | |
268 | //char tag5[5]; | |
269 | //printf("Read %s, result %p #%d\n", letagToStr(tableTag,tag5), data,len); | |
270 | return data; | |
b75a7d8f A |
271 | } |
272 | ||
273 | CMAPMapper *PortableFontInstance::findUnicodeMapper() | |
274 | { | |
275 | LETag cmapTag = LE_CMAP_TABLE_TAG; | |
276 | const CMAPTable *cmap = (CMAPTable *) readFontTable(cmapTag); | |
277 | ||
278 | if (cmap == NULL) { | |
279 | return NULL; | |
280 | } | |
281 | ||
282 | return CMAPMapper::createUnicodeMapper(cmap); | |
283 | } | |
284 | ||
73c04bcf A |
285 | const char *PortableFontInstance::getNameString(le_uint16 nameID, le_uint16 platformID, le_uint16 encodingID, le_uint16 languageID) const |
286 | { | |
287 | if (fNAMETable == NULL) { | |
288 | LETag nameTag = LE_NAME_TABLE_TAG; | |
289 | PortableFontInstance *realThis = (PortableFontInstance *) this; | |
290 | ||
291 | realThis->fNAMETable = (const NAMETable *) readFontTable(nameTag); | |
292 | ||
293 | if (realThis->fNAMETable != NULL) { | |
294 | realThis->fNameCount = SWAPW(realThis->fNAMETable->count); | |
295 | realThis->fNameStringOffset = SWAPW(realThis->fNAMETable->stringOffset); | |
296 | } | |
297 | } | |
298 | ||
299 | for(le_int32 i = 0; i < fNameCount; i += 1) { | |
300 | const NameRecord *nameRecord = &fNAMETable->nameRecords[i]; | |
301 | ||
46f4442e | 302 | if (SWAPW(nameRecord->platformID) == platformID && SWAPW(nameRecord->encodingID) == encodingID && |
73c04bcf A |
303 | SWAPW(nameRecord->languageID) == languageID && SWAPW(nameRecord->nameID) == nameID) { |
304 | char *name = ((char *) fNAMETable) + fNameStringOffset + SWAPW(nameRecord->offset); | |
305 | le_uint16 length = SWAPW(nameRecord->length); | |
57a6839d | 306 | char *result = LE_NEW_ARRAY(char, length + 2); |
73c04bcf | 307 | |
57a6839d | 308 | LE_ARRAY_COPY(result, name, length); |
73c04bcf A |
309 | result[length] = result[length + 1] = 0; |
310 | ||
311 | return result; | |
312 | } | |
313 | } | |
314 | ||
315 | return NULL; | |
316 | } | |
317 | ||
46f4442e A |
318 | const LEUnicode16 *PortableFontInstance::getUnicodeNameString(le_uint16 nameID, le_uint16 platformID, le_uint16 encodingID, le_uint16 languageID) const |
319 | { | |
320 | if (fNAMETable == NULL) { | |
321 | LETag nameTag = LE_NAME_TABLE_TAG; | |
322 | PortableFontInstance *realThis = (PortableFontInstance *) this; | |
323 | ||
324 | realThis->fNAMETable = (const NAMETable *) readFontTable(nameTag); | |
325 | ||
326 | if (realThis->fNAMETable != NULL) { | |
327 | realThis->fNameCount = SWAPW(realThis->fNAMETable->count); | |
328 | realThis->fNameStringOffset = SWAPW(realThis->fNAMETable->stringOffset); | |
329 | } | |
330 | } | |
331 | ||
332 | for(le_int32 i = 0; i < fNameCount; i += 1) { | |
333 | const NameRecord *nameRecord = &fNAMETable->nameRecords[i]; | |
334 | ||
335 | if (SWAPW(nameRecord->platformID) == platformID && SWAPW(nameRecord->encodingID) == encodingID && | |
336 | SWAPW(nameRecord->languageID) == languageID && SWAPW(nameRecord->nameID) == nameID) { | |
337 | LEUnicode16 *name = (LEUnicode16 *) (((char *) fNAMETable) + fNameStringOffset + SWAPW(nameRecord->offset)); | |
338 | le_uint16 length = SWAPW(nameRecord->length) / 2; | |
57a6839d | 339 | LEUnicode16 *result = LE_NEW_ARRAY(LEUnicode16, length + 2); |
46f4442e A |
340 | |
341 | for (le_int32 c = 0; c < length; c += 1) { | |
342 | result[c] = SWAPW(name[c]); | |
343 | } | |
344 | ||
345 | result[length] = 0; | |
346 | ||
347 | return result; | |
348 | } | |
349 | } | |
350 | ||
351 | return NULL; | |
352 | } | |
353 | ||
73c04bcf A |
354 | void PortableFontInstance::deleteNameString(const char *name) const |
355 | { | |
57a6839d | 356 | LE_DELETE_ARRAY(name); |
73c04bcf | 357 | } |
b75a7d8f | 358 | |
46f4442e A |
359 | void PortableFontInstance::deleteNameString(const LEUnicode16 *name) const |
360 | { | |
57a6839d | 361 | LE_DELETE_ARRAY(name); |
46f4442e A |
362 | } |
363 | ||
b75a7d8f A |
364 | void PortableFontInstance::getGlyphAdvance(LEGlyphID glyph, LEPoint &advance) const |
365 | { | |
366 | TTGlyphID ttGlyph = (TTGlyphID) LE_GET_GLYPH(glyph); | |
367 | ||
368 | if (fHMTXTable == NULL) { | |
369 | LETag maxpTag = LE_MAXP_TABLE_TAG; | |
370 | LETag hmtxTag = LE_HMTX_TABLE_TAG; | |
371 | const MAXPTable *maxpTable = (MAXPTable *) readFontTable(maxpTag); | |
372 | PortableFontInstance *realThis = (PortableFontInstance *) this; | |
373 | ||
374 | if (maxpTable != NULL) { | |
375 | realThis->fNumGlyphs = SWAPW(maxpTable->numGlyphs); | |
46f4442e | 376 | freeFontTable(maxpTable); |
b75a7d8f A |
377 | } |
378 | ||
379 | realThis->fHMTXTable = (const HMTXTable *) readFontTable(hmtxTag); | |
380 | } | |
381 | ||
382 | le_uint16 index = ttGlyph; | |
383 | ||
384 | if (ttGlyph >= fNumGlyphs || fHMTXTable == NULL) { | |
385 | advance.fX = advance.fY = 0; | |
386 | return; | |
387 | } | |
388 | ||
389 | if (ttGlyph >= fNumLongHorMetrics) { | |
390 | index = fNumLongHorMetrics - 1; | |
391 | } | |
392 | ||
393 | advance.fX = xUnitsToPoints(SWAPW(fHMTXTable->hMetrics[index].advanceWidth)); | |
394 | advance.fY = 0; | |
395 | } | |
396 | ||
73c04bcf | 397 | le_bool PortableFontInstance::getGlyphPoint(LEGlyphID /*glyph*/, le_int32 /*pointNumber*/, LEPoint &/*point*/) const |
b75a7d8f | 398 | { |
374ca955 | 399 | return FALSE; |
b75a7d8f A |
400 | } |
401 | ||
73c04bcf A |
402 | le_int32 PortableFontInstance::getUnitsPerEM() const |
403 | { | |
404 | return fUnitsPerEM; | |
405 | } | |
406 | ||
407 | le_uint32 PortableFontInstance::getFontChecksum() const | |
408 | { | |
409 | return fFontChecksum; | |
410 | } | |
411 | ||
57a6839d A |
412 | le_uint32 PortableFontInstance::getRawChecksum() const |
413 | { | |
414 | // how big is it? | |
415 | // fseek(fFile, 0L, SEEK_END); | |
416 | // long size = ftell(fFile); | |
417 | le_int32 chksum = 0; | |
418 | // now, calculate | |
419 | fseek(fFile, 0L, SEEK_SET); | |
420 | int r; | |
421 | int count =0; | |
422 | while((r = fgetc(fFile)) != EOF) { | |
423 | chksum += r; | |
424 | count ++; | |
425 | } | |
426 | return (le_uint32) chksum; // cast to signed | |
427 | } | |
428 | ||
73c04bcf A |
429 | le_int32 PortableFontInstance::getAscent() const |
430 | { | |
431 | return fAscent; | |
432 | } | |
433 | ||
434 | le_int32 PortableFontInstance::getDescent() const | |
435 | { | |
436 | return fDescent; | |
437 | } | |
438 | ||
439 | le_int32 PortableFontInstance::getLeading() const | |
440 | { | |
441 | return fLeading; | |
442 | } | |
443 | ||
444 | // We really want to inherit this method from the superclass, but some compilers | |
445 | // issue a warning if we don't implement it... | |
446 | LEGlyphID PortableFontInstance::mapCharToGlyph(LEUnicode32 ch, const LECharMapper *mapper, le_bool filterZeroWidth) const | |
447 | { | |
448 | return LEFontInstance::mapCharToGlyph(ch, mapper, filterZeroWidth); | |
449 | } | |
450 | ||
451 | // We really want to inherit this method from the superclass, but some compilers | |
452 | // issue a warning if we don't implement it... | |
453 | LEGlyphID PortableFontInstance::mapCharToGlyph(LEUnicode32 ch, const LECharMapper *mapper) const | |
454 | { | |
455 | return LEFontInstance::mapCharToGlyph(ch, mapper); | |
456 | } | |
457 | ||
458 | LEGlyphID PortableFontInstance::mapCharToGlyph(LEUnicode32 ch) const | |
459 | { | |
460 | return fCMAPMapper->unicodeToGlyph(ch); | |
461 | } | |
462 | ||
463 | float PortableFontInstance::getXPixelsPerEm() const | |
464 | { | |
465 | return fPointSize; | |
466 | } | |
467 | ||
468 | float PortableFontInstance::getYPixelsPerEm() const | |
469 | { | |
470 | return fPointSize; | |
471 | } | |
472 | ||
473 | float PortableFontInstance::getScaleFactorX() const | |
474 | { | |
475 | return 1.0; | |
476 | } | |
477 | ||
478 | float PortableFontInstance::getScaleFactorY() const | |
479 | { | |
480 | return 1.0; | |
481 | } |