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