• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************
2 *
3 *   © 2016 and later: Unicode, Inc. and others.
4 *   License & terms of use: http://www.unicode.org/copyright.html
5 *
6 ****************************************************************************/
7 /***************************************************************************
8 *
9 *   Copyright (C) 1998-2013, International Business Machines
10 *   Corporation and others.  All Rights Reserved.
11 *
12 ************************************************************************/
13 
14 #include <stdio.h>
15 
16 #include "layout/LETypes.h"
17 #include "FontObject.h"
18 #include "layout/LESwaps.h"
19 
20 using icu::LESwaps;
21 
FontObject(char * fileName)22 FontObject::FontObject(char *fileName)
23   : directory(nullptr), numTables(0), searchRange(0),entrySelector(0),
24     cmapTable(nullptr), cmSegCount(0), cmSearchRange(0), cmEntrySelector(0),
25     cmEndCodes(nullptr), cmStartCodes(nullptr), cmIdDelta(nullptr), cmIdRangeOffset(nullptr),
26     headTable(nullptr), hmtxTable(nullptr), numGlyphs(0), numOfLongHorMetrics(0), file(nullptr)
27 {
28     file = fopen(fileName, "rb");
29 
30     if (file == nullptr) {
31         printf("?? Couldn't open %s", fileName);
32         return;
33     }
34 
35     SFNTDirectory tempDir;
36 
37     fread(&tempDir, sizeof tempDir, 1, file);
38 
39     numTables       = SWAPW(tempDir.numTables);
40     searchRange     = SWAPW(tempDir.searchRange) >> 4;
41     entrySelector   = SWAPW(tempDir.entrySelector);
42     rangeShift      = SWAPW(tempDir.rangeShift) >> 4;
43 
44     int dirSize = sizeof tempDir + ((numTables - ANY_NUMBER) * sizeof(DirectoryEntry));
45 
46     directory = reinterpret_cast<SFNTDirectory*>(new char[dirSize]);
47 
48     fseek(file, 0L, SEEK_SET);
49     fread(directory, sizeof(char), dirSize, file);
50 
51     initUnicodeCMAP();
52 }
53 
~FontObject()54 FontObject::~FontObject()
55 {
56     fclose(file);
57     delete[] directory;
58     delete[] cmapTable;
59     delete[] headTable;
60     delete[] hmtxTable;
61 }
62 
deleteTable(void * table)63 void FontObject::deleteTable(void *table)
64 {
65     delete[] static_cast<char*>(table);
66 }
67 
findTable(LETag tag)68 DirectoryEntry *FontObject::findTable(LETag tag)
69 {
70     le_uint16 table = 0;
71     le_uint16 probe = 1 << entrySelector;
72 
73     if (SWAPL(directory->tableDirectory[rangeShift].tag) <= tag) {
74         table = rangeShift;
75     }
76 
77     while (probe > (1 << 0)) {
78         probe >>= 1;
79 
80         if (SWAPL(directory->tableDirectory[table + probe].tag) <= tag) {
81             table += probe;
82         }
83     }
84 
85     if (SWAPL(directory->tableDirectory[table].tag) == tag) {
86         return &directory->tableDirectory[table];
87     }
88 
89     return nullptr;
90 }
91 
readTable(LETag tag,le_uint32 * length)92 void *FontObject::readTable(LETag tag, le_uint32 *length)
93 {
94     DirectoryEntry *entry = findTable(tag);
95 
96     if (entry == nullptr) {
97         *length = 0;
98         return nullptr;
99     }
100 
101     *length = SWAPL(entry->length);
102 
103     void *table = new char[*length];
104 
105     fseek(file, SWAPL(entry->offset), SEEK_SET);
106     fread(table, sizeof(char), *length, file);
107 
108     return table;
109 }
110 
findCMAP(le_uint16 platformID,le_uint16 platformSpecificID)111 CMAPEncodingSubtable *FontObject::findCMAP(le_uint16 platformID, le_uint16 platformSpecificID)
112 {
113     LETag cmapTag = 0x636D6170; // 'cmap'
114 
115     if (cmapTable == nullptr) {
116         le_uint32 length;
117 
118         cmapTable = static_cast<CMAPTable*>(readTable(cmapTag, &length));
119     }
120 
121     if (cmapTable != nullptr) {
122         le_uint16 i;
123         le_uint16 nSubtables = SWAPW(cmapTable->numberSubtables);
124 
125 
126         for (i = 0; i < nSubtables; i += 1) {
127             CMAPEncodingSubtableHeader *esh = &cmapTable->encodingSubtableHeaders[i];
128 
129             if (SWAPW(esh->platformID) == platformID &&
130                 SWAPW(esh->platformSpecificID) == platformSpecificID) {
131                 return reinterpret_cast<CMAPEncodingSubtable*>(reinterpret_cast<char*>(cmapTable) + SWAPL(esh->encodingOffset));
132             }
133         }
134     }
135 
136     return nullptr;
137 }
138 
initUnicodeCMAP()139 void FontObject::initUnicodeCMAP()
140 {
141     CMAPEncodingSubtable *encodingSubtable = findCMAP(3, 1);
142 
143     if (encodingSubtable == nullptr ||
144         SWAPW(encodingSubtable->format) != 4) {
145         printf("Can't find unicode 'cmap'");
146         return;
147     }
148 
149     CMAPFormat4Encoding *header = (CMAPFormat4Encoding *) encodingSubtable;
150 
151     cmSegCount = SWAPW(header->segCountX2) / 2;
152     cmSearchRange = SWAPW(header->searchRange);
153     cmEntrySelector = SWAPW(header->entrySelector);
154     cmRangeShift = SWAPW(header->rangeShift) / 2;
155     cmEndCodes = &header->endCodes[0];
156     cmStartCodes = &header->endCodes[cmSegCount + 1]; // + 1 for reservedPad...
157     cmIdDelta = &cmStartCodes[cmSegCount];
158     cmIdRangeOffset = &cmIdDelta[cmSegCount];
159 }
160 
unicodeToGlyph(LEUnicode32 unicode32)161 LEGlyphID FontObject::unicodeToGlyph(LEUnicode32 unicode32)
162 {
163     if (unicode32 >= 0x10000) {
164         return 0;
165     }
166 
167     LEUnicode16 unicode = static_cast<LEUnicode16>(unicode32);
168     le_uint16 index = 0;
169     le_uint16 probe = 1 << cmEntrySelector;
170     LEGlyphID result = 0;
171 
172     if (SWAPW(cmStartCodes[cmRangeShift]) <= unicode) {
173         index = cmRangeShift;
174     }
175 
176     while (probe > (1 << 0)) {
177         probe >>= 1;
178 
179         if (SWAPW(cmStartCodes[index + probe]) <= unicode) {
180             index += probe;
181         }
182     }
183 
184     if (unicode >= SWAPW(cmStartCodes[index]) && unicode <= SWAPW(cmEndCodes[index])) {
185         if (cmIdRangeOffset[index] == 0) {
186             result = static_cast<LEGlyphID>(unicode);
187         } else {
188             le_uint16 offset = unicode - SWAPW(cmStartCodes[index]);
189             le_uint16 rangeOffset = SWAPW(cmIdRangeOffset[index]);
190             le_uint16* glyphIndexTable = reinterpret_cast<le_uint16*>(reinterpret_cast<char*>(&cmIdRangeOffset[index]) + rangeOffset);
191 
192             result = SWAPW(glyphIndexTable[offset]);
193         }
194 
195         result += SWAPW(cmIdDelta[index]);
196     } else {
197         result = 0;
198     }
199 
200     return result;
201 }
202 
getUnitsPerEM()203 le_uint16 FontObject::getUnitsPerEM()
204 {
205     if (headTable == nullptr) {
206         LETag headTag = 0x68656164; // 'head'
207         le_uint32 length;
208 
209         headTable = static_cast<HEADTable*>(readTable(headTag, &length));
210     }
211 
212     return SWAPW(headTable->unitsPerEm);
213 }
214 
getGlyphAdvance(LEGlyphID glyph)215 le_uint16 FontObject::getGlyphAdvance(LEGlyphID glyph)
216 {
217     if (hmtxTable == nullptr) {
218         LETag maxpTag = 0x6D617870; // 'maxp'
219         LETag hheaTag = 0x68686561; // 'hhea'
220         LETag hmtxTag = 0x686D7478; // 'hmtx'
221         le_uint32 length;
222         HHEATable *hheaTable;
223         MAXPTable* maxpTable = static_cast<MAXPTable*>(readTable(maxpTag, &length));
224 
225         numGlyphs = SWAPW(maxpTable->numGlyphs);
226         deleteTable(maxpTable);
227 
228         hheaTable = static_cast<HHEATable*>(readTable(hheaTag, &length));
229         numOfLongHorMetrics = SWAPW(hheaTable->numOfLongHorMetrics);
230         deleteTable(hheaTable);
231 
232         hmtxTable = static_cast<HMTXTable*>(readTable(hmtxTag, &length));
233     }
234 
235     le_uint16 index = glyph;
236 
237     if (glyph >= numGlyphs) {
238         return 0;
239     }
240 
241     if (glyph >= numOfLongHorMetrics) {
242         index = numOfLongHorMetrics - 1;
243     }
244 
245     return SWAPW(hmtxTable->hMetrics[index].advanceWidth);
246 }
247 
248 
249