• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *******************************************************************************
3  *
4  *   Copyright (C) 1999-2008, International Business Machines
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 
22 #include "letest.h"
23 #include "sfnt.h"
24 
25 #include <string.h>
26 
27 //
28 // Finds the high bit by binary searching
29 // through the bits in n.
30 //
highBit(le_int32 value)31 le_int8 PortableFontInstance::highBit(le_int32 value)
32 {
33     if (value <= 0) {
34         return -32;
35     }
36 
37     le_uint8 bit = 0;
38 
39     if (value >= 1 << 16) {
40         value >>= 16;
41         bit += 16;
42     }
43 
44     if (value >= 1 << 8) {
45         value >>= 8;
46         bit += 8;
47     }
48 
49     if (value >= 1 << 4) {
50         value >>= 4;
51         bit += 4;
52     }
53 
54     if (value >= 1 << 2) {
55         value >>= 2;
56         bit += 2;
57     }
58 
59     if (value >= 1 << 1) {
60         value >>= 1;
61         bit += 1;
62     }
63 
64     return bit;
65 }
66 
PortableFontInstance(const char * fileName,float pointSize,LEErrorCode & status)67 PortableFontInstance::PortableFontInstance(const char *fileName, float pointSize, LEErrorCode &status)
68     : fFile(NULL), fPointSize(pointSize), fUnitsPerEM(0), fFontChecksum(0), fAscent(0), fDescent(0), fLeading(0),
69       fDirectory(NULL), fNAMETable(NULL), fNameCount(0), fNameStringOffset(0), fCMAPMapper(NULL), fHMTXTable(NULL), fNumGlyphs(0), fNumLongHorMetrics(0)
70 {
71     if (LE_FAILURE(status)) {
72         return;
73     }
74 
75     // open the font file
76     fFile = fopen(fileName, "rb");
77 
78     if (fFile == NULL) {
79         status = LE_FONT_FILE_NOT_FOUND_ERROR;
80         return;
81     }
82 
83     // read in the directory
84     SFNTDirectory tempDir;
85 
86     fread(&tempDir, sizeof tempDir, 1, fFile);
87 
88     le_int32 dirSize = sizeof tempDir + ((SWAPW(tempDir.numTables) - ANY_NUMBER) * sizeof(DirectoryEntry));
89     const LETag headTag = LE_HEAD_TABLE_TAG;
90     const LETag hheaTag = LE_HHEA_TABLE_TAG;
91     const HEADTable *headTable = NULL;
92     const HHEATable *hheaTable = NULL;
93 //  const NAMETable *nameTable = NULL;
94     le_uint16 numTables = 0;
95 
96     fDirectory = (const SFNTDirectory *) NEW_ARRAY(char, dirSize);
97 
98     if (fDirectory == NULL) {
99         status = LE_MEMORY_ALLOCATION_ERROR;
100         goto error_exit;
101     }
102 
103     fseek(fFile, 0L, SEEK_SET);
104     fread((void *) fDirectory, sizeof(char), dirSize, fFile);
105 
106     //
107     // We calculate these numbers 'cause some fonts
108     // have bogus values for them in the directory header.
109     //
110     numTables = SWAPW(fDirectory->numTables);
111     fDirPower = 1 << highBit(numTables);
112     fDirExtra = numTables - fDirPower;
113 
114     // read unitsPerEm from 'head' table
115     headTable = (const HEADTable *) readFontTable(headTag);
116 
117     if (headTable == NULL) {
118         status = LE_MISSING_FONT_TABLE_ERROR;
119         goto error_exit;
120     }
121 
122     fUnitsPerEM   = SWAPW(headTable->unitsPerEm);
123     fFontChecksum = SWAPL(headTable->checksumAdjustment);
124     freeFontTable(headTable);
125 
126     //nameTable = (NAMETable *) readFontTable(nameTag);
127 
128     //if (nameTable == NULL) {
129     //    status = LE_MISSING_FONT_TABLE_ERROR;
130     //    goto error_exit;
131     //}
132 
133     //fFontVersionString = findName(nameTable, NAME_VERSION_STRING, PLATFORM_MACINTOSH, MACINTOSH_ROMAN, MACINTOSH_ENGLISH);
134 
135     //if (fFontVersionString == NULL) {
136     //    status = LE_MISSING_FONT_TABLE_ERROR;
137     //    goto error_exit;
138     //}
139 
140     //freeFontTable(nameTable);
141 
142     hheaTable = (HHEATable *) readFontTable(hheaTag);
143 
144     if (hheaTable == NULL) {
145         status = LE_MISSING_FONT_TABLE_ERROR;
146         goto error_exit;
147     }
148 
149     fAscent  = (le_int32) yUnitsToPoints((float) SWAPW(hheaTable->ascent));
150     fDescent = (le_int32) yUnitsToPoints((float) SWAPW(hheaTable->descent));
151     fLeading = (le_int32) yUnitsToPoints((float) SWAPW(hheaTable->lineGap));
152 
153     fNumLongHorMetrics = SWAPW(hheaTable->numOfLongHorMetrics);
154 
155     freeFontTable((void *) hheaTable);
156 
157     fCMAPMapper = findUnicodeMapper();
158 
159     if (fCMAPMapper == NULL) {
160         status = LE_MISSING_FONT_TABLE_ERROR;
161         goto error_exit;
162     }
163 
164     return;
165 
166 error_exit:
167     fclose(fFile);
168     fFile = NULL;
169     return;
170 }
171 
~PortableFontInstance()172 PortableFontInstance::~PortableFontInstance()
173 {
174     if (fFile != NULL) {
175         fclose(fFile);
176 
177         freeFontTable(fHMTXTable);
178         freeFontTable(fNAMETable);
179 
180         delete fCMAPMapper;
181 
182         DELETE_ARRAY(fDirectory);
183     }
184 }
185 
findTable(LETag tag) const186 const DirectoryEntry *PortableFontInstance::findTable(LETag tag) const
187 {
188     if (fDirectory != NULL) {
189         le_uint16 table = 0;
190         le_uint16 probe = fDirPower;
191 
192         if (SWAPL(fDirectory->tableDirectory[fDirExtra].tag) <= tag) {
193             table = fDirExtra;
194         }
195 
196         while (probe > (1 << 0)) {
197             probe >>= 1;
198 
199             if (SWAPL(fDirectory->tableDirectory[table + probe].tag) <= tag) {
200                 table += probe;
201             }
202         }
203 
204         if (SWAPL(fDirectory->tableDirectory[table].tag) == tag) {
205             return &fDirectory->tableDirectory[table];
206         }
207     }
208 
209     return NULL;
210 }
211 
readTable(LETag tag,le_uint32 * length) const212 const void *PortableFontInstance::readTable(LETag tag, le_uint32 *length) const
213 {
214     const DirectoryEntry *entry = findTable(tag);
215 
216     if (entry == NULL) {
217         *length = 0;
218         return NULL;
219     }
220 
221     *length = SWAPL(entry->length);
222 
223     void *table = NEW_ARRAY(char, *length);
224 
225     if (table != NULL) {
226         fseek(fFile, SWAPL(entry->offset), SEEK_SET);
227         fread(table, sizeof(char), *length, fFile);
228     }
229 
230     return table;
231 }
232 
getFontTable(LETag tableTag) const233 const void *PortableFontInstance::getFontTable(LETag tableTag) const
234 {
235     return FontTableCache::find(tableTag);
236 }
237 
readFontTable(LETag tableTag) const238 const void *PortableFontInstance::readFontTable(LETag tableTag) const
239 {
240     le_uint32 len;
241 
242     return readTable(tableTag, &len);
243 }
244 
findUnicodeMapper()245 CMAPMapper *PortableFontInstance::findUnicodeMapper()
246 {
247     LETag cmapTag = LE_CMAP_TABLE_TAG;
248     const CMAPTable *cmap = (CMAPTable *) readFontTable(cmapTag);
249 
250     if (cmap == NULL) {
251         return NULL;
252     }
253 
254     return CMAPMapper::createUnicodeMapper(cmap);
255 }
256 
getNameString(le_uint16 nameID,le_uint16 platformID,le_uint16 encodingID,le_uint16 languageID) const257 const char *PortableFontInstance::getNameString(le_uint16 nameID, le_uint16 platformID, le_uint16 encodingID, le_uint16 languageID) const
258 {
259     if (fNAMETable == NULL) {
260         LETag nameTag = LE_NAME_TABLE_TAG;
261         PortableFontInstance *realThis = (PortableFontInstance *) this;
262 
263         realThis->fNAMETable = (const NAMETable *) readFontTable(nameTag);
264 
265         if (realThis->fNAMETable != NULL) {
266             realThis->fNameCount        = SWAPW(realThis->fNAMETable->count);
267             realThis->fNameStringOffset = SWAPW(realThis->fNAMETable->stringOffset);
268         }
269     }
270 
271     for(le_int32 i = 0; i < fNameCount; i += 1) {
272         const NameRecord *nameRecord = &fNAMETable->nameRecords[i];
273 
274         if (SWAPW(nameRecord->platformID) == platformID && SWAPW(nameRecord->encodingID) == encodingID &&
275             SWAPW(nameRecord->languageID) == languageID && SWAPW(nameRecord->nameID) == nameID) {
276             char *name = ((char *) fNAMETable) + fNameStringOffset + SWAPW(nameRecord->offset);
277             le_uint16 length = SWAPW(nameRecord->length);
278             char *result = NEW_ARRAY(char, length + 2);
279 
280             ARRAY_COPY(result, name, length);
281             result[length] = result[length + 1] = 0;
282 
283             return result;
284         }
285     }
286 
287     return NULL;
288 }
289 
getUnicodeNameString(le_uint16 nameID,le_uint16 platformID,le_uint16 encodingID,le_uint16 languageID) const290 const LEUnicode16 *PortableFontInstance::getUnicodeNameString(le_uint16 nameID, le_uint16 platformID, le_uint16 encodingID, le_uint16 languageID) const
291 {
292     if (fNAMETable == NULL) {
293         LETag nameTag = LE_NAME_TABLE_TAG;
294         PortableFontInstance *realThis = (PortableFontInstance *) this;
295 
296         realThis->fNAMETable = (const NAMETable *) readFontTable(nameTag);
297 
298         if (realThis->fNAMETable != NULL) {
299             realThis->fNameCount        = SWAPW(realThis->fNAMETable->count);
300             realThis->fNameStringOffset = SWAPW(realThis->fNAMETable->stringOffset);
301         }
302     }
303 
304     for(le_int32 i = 0; i < fNameCount; i += 1) {
305         const NameRecord *nameRecord = &fNAMETable->nameRecords[i];
306 
307         if (SWAPW(nameRecord->platformID) == platformID && SWAPW(nameRecord->encodingID) == encodingID &&
308             SWAPW(nameRecord->languageID) == languageID && SWAPW(nameRecord->nameID) == nameID) {
309             LEUnicode16 *name = (LEUnicode16 *) (((char *) fNAMETable) + fNameStringOffset + SWAPW(nameRecord->offset));
310             le_uint16 length = SWAPW(nameRecord->length) / 2;
311             LEUnicode16 *result = NEW_ARRAY(LEUnicode16, length + 2);
312 
313             for (le_int32 c = 0; c < length; c += 1) {
314                 result[c] = SWAPW(name[c]);
315             }
316 
317             result[length] = 0;
318 
319             return result;
320         }
321     }
322 
323     return NULL;
324 }
325 
deleteNameString(const char * name) const326 void PortableFontInstance::deleteNameString(const char *name) const
327 {
328     DELETE_ARRAY(name);
329 }
330 
deleteNameString(const LEUnicode16 * name) const331 void PortableFontInstance::deleteNameString(const LEUnicode16 *name) const
332 {
333     DELETE_ARRAY(name);
334 }
335 
getGlyphAdvance(LEGlyphID glyph,LEPoint & advance) const336 void PortableFontInstance::getGlyphAdvance(LEGlyphID glyph, LEPoint &advance) const
337 {
338     TTGlyphID ttGlyph = (TTGlyphID) LE_GET_GLYPH(glyph);
339 
340     if (fHMTXTable == NULL) {
341         LETag maxpTag = LE_MAXP_TABLE_TAG;
342         LETag hmtxTag = LE_HMTX_TABLE_TAG;
343         const MAXPTable *maxpTable = (MAXPTable *) readFontTable(maxpTag);
344         PortableFontInstance *realThis = (PortableFontInstance *) this;
345 
346         if (maxpTable != NULL) {
347             realThis->fNumGlyphs = SWAPW(maxpTable->numGlyphs);
348             freeFontTable(maxpTable);
349         }
350 
351         realThis->fHMTXTable = (const HMTXTable *) readFontTable(hmtxTag);
352     }
353 
354     le_uint16 index = ttGlyph;
355 
356     if (ttGlyph >= fNumGlyphs || fHMTXTable == NULL) {
357         advance.fX = advance.fY = 0;
358         return;
359     }
360 
361     if (ttGlyph >= fNumLongHorMetrics) {
362         index = fNumLongHorMetrics - 1;
363     }
364 
365     advance.fX = xUnitsToPoints(SWAPW(fHMTXTable->hMetrics[index].advanceWidth));
366     advance.fY = 0;
367 }
368 
getGlyphPoint(LEGlyphID,le_int32,LEPoint &) const369 le_bool PortableFontInstance::getGlyphPoint(LEGlyphID /*glyph*/, le_int32 /*pointNumber*/, LEPoint &/*point*/) const
370 {
371     return FALSE;
372 }
373 
getUnitsPerEM() const374 le_int32 PortableFontInstance::getUnitsPerEM() const
375 {
376     return fUnitsPerEM;
377 }
378 
getFontChecksum() const379 le_uint32 PortableFontInstance::getFontChecksum() const
380 {
381     return fFontChecksum;
382 }
383 
getAscent() const384 le_int32 PortableFontInstance::getAscent() const
385 {
386     return fAscent;
387 }
388 
getDescent() const389 le_int32 PortableFontInstance::getDescent() const
390 {
391     return fDescent;
392 }
393 
getLeading() const394 le_int32 PortableFontInstance::getLeading() const
395 {
396     return fLeading;
397 }
398 
399 // We really want to inherit this method from the superclass, but some compilers
400 // issue a warning if we don't implement it...
mapCharToGlyph(LEUnicode32 ch,const LECharMapper * mapper,le_bool filterZeroWidth) const401 LEGlyphID PortableFontInstance::mapCharToGlyph(LEUnicode32 ch, const LECharMapper *mapper, le_bool filterZeroWidth) const
402 {
403     return LEFontInstance::mapCharToGlyph(ch, mapper, filterZeroWidth);
404 }
405 
406 // We really want to inherit this method from the superclass, but some compilers
407 // issue a warning if we don't implement it...
mapCharToGlyph(LEUnicode32 ch,const LECharMapper * mapper) const408 LEGlyphID PortableFontInstance::mapCharToGlyph(LEUnicode32 ch, const LECharMapper *mapper) const
409 {
410     return LEFontInstance::mapCharToGlyph(ch, mapper);
411 }
412 
mapCharToGlyph(LEUnicode32 ch) const413 LEGlyphID PortableFontInstance::mapCharToGlyph(LEUnicode32 ch) const
414 {
415     return fCMAPMapper->unicodeToGlyph(ch);
416 }
417 
getXPixelsPerEm() const418 float PortableFontInstance::getXPixelsPerEm() const
419 {
420     return fPointSize;
421 }
422 
getYPixelsPerEm() const423 float PortableFontInstance::getYPixelsPerEm() const
424 {
425     return fPointSize;
426 }
427 
getScaleFactorX() const428 float PortableFontInstance::getScaleFactorX() const
429 {
430     return 1.0;
431 }
432 
getScaleFactorY() const433 float PortableFontInstance::getScaleFactorY() const
434 {
435     return 1.0;
436 }
437