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