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 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 48 FontObject::~FontObject() 49 { 50 fclose(file); 51 delete[] directory; 52 delete[] cmapTable; 53 delete[] headTable; 54 delete[] hmtxTable; 55 } 56 57 void FontObject::deleteTable(void *table) 58 { 59 delete[] (char *) table; 60 } 61 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 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 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 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 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 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 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