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