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 241