OLD | NEW |
(Empty) | |
| 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(DirectoryE
ntry)); |
| 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 platf
ormSpecificID) |
| 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->encodingSubtableHeader
s[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[ind
ex])) { |
| 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 *) &cmIdRangeOffse
t[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 |
OLD | NEW |