|
1 /*************************************************************************** |
|
2 * |
|
3 * Copyright (C) 1998-2002, 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(DirectoryEntry)); |
|
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 platformSpecificID) |
|
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->encodingSubtableHeaders[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[index])) { |
|
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 *) &cmIdRangeOffset[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 |