ICU-3.13.tar.gz
[apple/icu.git] / icuSources / test / letest / FontObject.cpp
CommitLineData
b75a7d8f
A
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
14FontObject::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
46FontObject::~FontObject()
47{
48 fclose(file);
49 delete[] directory;
50 delete[] cmapTable;
51 delete[] headTable;
52 delete[] hmtxTable;
53}
54
55void FontObject::deleteTable(void *table)
56{
57 delete[] (char *) table;
58}
59
60DirectoryEntry *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
84void *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
103CMAPEncodingSubtable *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
131void 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
153LEGlyphID 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
195le_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
207le_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