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