sl@0: /*************************************************************************** sl@0: * sl@0: * Copyright (C) 1998-2002, International Business Machines sl@0: * Corporation and others. All Rights Reserved. sl@0: * sl@0: ************************************************************************/ sl@0: sl@0: #include sl@0: sl@0: #include "LETypes.h" sl@0: #include "FontObject.h" sl@0: #include "LESwaps.h" sl@0: sl@0: FontObject::FontObject(char *fileName) sl@0: : directory(NULL), numTables(0), searchRange(0),entrySelector(0), sl@0: cmapTable(NULL), cmSegCount(0), cmSearchRange(0), cmEntrySelector(0), sl@0: cmEndCodes(NULL), cmStartCodes(NULL), cmIdDelta(0), cmIdRangeOffset(0), sl@0: headTable(NULL), hmtxTable(NULL), numGlyphs(0), numOfLongHorMetrics(0), file(NULL) sl@0: { sl@0: file = fopen(fileName, "rb"); sl@0: sl@0: if (file == NULL) { sl@0: printf("?? Couldn't open %s", fileName); sl@0: return; sl@0: } sl@0: sl@0: SFNTDirectory tempDir; sl@0: sl@0: fread(&tempDir, sizeof tempDir, 1, file); sl@0: sl@0: numTables = SWAPW(tempDir.numTables); sl@0: searchRange = SWAPW(tempDir.searchRange) >> 4; sl@0: entrySelector = SWAPW(tempDir.entrySelector); sl@0: rangeShift = SWAPW(tempDir.rangeShift) >> 4; sl@0: sl@0: int dirSize = sizeof tempDir + ((numTables - ANY_NUMBER) * sizeof(DirectoryEntry)); sl@0: sl@0: directory = (SFNTDirectory *) new char[dirSize]; sl@0: sl@0: fseek(file, 0L, SEEK_SET); sl@0: fread(directory, sizeof(char), dirSize, file); sl@0: sl@0: initUnicodeCMAP(); sl@0: } sl@0: sl@0: FontObject::~FontObject() sl@0: { sl@0: fclose(file); sl@0: delete[] directory; sl@0: delete[] cmapTable; sl@0: delete[] headTable; sl@0: delete[] hmtxTable; sl@0: } sl@0: sl@0: void FontObject::deleteTable(void *table) sl@0: { sl@0: delete[] (char *) table; sl@0: } sl@0: sl@0: DirectoryEntry *FontObject::findTable(LETag tag) sl@0: { sl@0: le_uint16 table = 0; sl@0: le_uint16 probe = 1 << entrySelector; sl@0: sl@0: if (SWAPL(directory->tableDirectory[rangeShift].tag) <= tag) { sl@0: table = rangeShift; sl@0: } sl@0: sl@0: while (probe > (1 << 0)) { sl@0: probe >>= 1; sl@0: sl@0: if (SWAPL(directory->tableDirectory[table + probe].tag) <= tag) { sl@0: table += probe; sl@0: } sl@0: } sl@0: sl@0: if (SWAPL(directory->tableDirectory[table].tag) == tag) { sl@0: return &directory->tableDirectory[table]; sl@0: } sl@0: sl@0: return NULL; sl@0: } sl@0: sl@0: void *FontObject::readTable(LETag tag, le_uint32 *length) sl@0: { sl@0: DirectoryEntry *entry = findTable(tag); sl@0: sl@0: if (entry == NULL) { sl@0: *length = 0; sl@0: return NULL; sl@0: } sl@0: sl@0: *length = SWAPL(entry->length); sl@0: sl@0: void *table = new char[*length]; sl@0: sl@0: fseek(file, SWAPL(entry->offset), SEEK_SET); sl@0: fread(table, sizeof(char), *length, file); sl@0: sl@0: return table; sl@0: } sl@0: sl@0: CMAPEncodingSubtable *FontObject::findCMAP(le_uint16 platformID, le_uint16 platformSpecificID) sl@0: { sl@0: LETag cmapTag = 0x636D6170; // 'cmap' sl@0: sl@0: if (cmapTable == NULL) { sl@0: le_uint32 length; sl@0: sl@0: cmapTable = (CMAPTable *) readTable(cmapTag, &length); sl@0: } sl@0: sl@0: if (cmapTable != NULL) { sl@0: le_uint16 i; sl@0: le_uint16 nSubtables = SWAPW(cmapTable->numberSubtables); sl@0: sl@0: sl@0: for (i = 0; i < nSubtables; i += 1) { sl@0: CMAPEncodingSubtableHeader *esh = &cmapTable->encodingSubtableHeaders[i]; sl@0: sl@0: if (SWAPW(esh->platformID) == platformID && sl@0: SWAPW(esh->platformSpecificID) == platformSpecificID) { sl@0: return (CMAPEncodingSubtable *) ((char *) cmapTable + SWAPL(esh->encodingOffset)); sl@0: } sl@0: } sl@0: } sl@0: sl@0: return NULL; sl@0: } sl@0: sl@0: void FontObject::initUnicodeCMAP() sl@0: { sl@0: CMAPEncodingSubtable *encodingSubtable = findCMAP(3, 1); sl@0: sl@0: if (encodingSubtable == 0 || sl@0: SWAPW(encodingSubtable->format) != 4) { sl@0: printf("Can't find unicode 'cmap'"); sl@0: return; sl@0: } sl@0: sl@0: CMAPFormat4Encoding *header = (CMAPFormat4Encoding *) encodingSubtable; sl@0: sl@0: cmSegCount = SWAPW(header->segCountX2) / 2; sl@0: cmSearchRange = SWAPW(header->searchRange); sl@0: cmEntrySelector = SWAPW(header->entrySelector); sl@0: cmRangeShift = SWAPW(header->rangeShift) / 2; sl@0: cmEndCodes = &header->endCodes[0]; sl@0: cmStartCodes = &header->endCodes[cmSegCount + 1]; // + 1 for reservedPad... sl@0: cmIdDelta = &cmStartCodes[cmSegCount]; sl@0: cmIdRangeOffset = &cmIdDelta[cmSegCount]; sl@0: } sl@0: sl@0: LEGlyphID FontObject::unicodeToGlyph(LEUnicode32 unicode32) sl@0: { sl@0: if (unicode32 >= 0x10000) { sl@0: return 0; sl@0: } sl@0: sl@0: LEUnicode16 unicode = (LEUnicode16) unicode32; sl@0: le_uint16 index = 0; sl@0: le_uint16 probe = 1 << cmEntrySelector; sl@0: LEGlyphID result = 0; sl@0: sl@0: if (SWAPW(cmStartCodes[cmRangeShift]) <= unicode) { sl@0: index = cmRangeShift; sl@0: } sl@0: sl@0: while (probe > (1 << 0)) { sl@0: probe >>= 1; sl@0: sl@0: if (SWAPW(cmStartCodes[index + probe]) <= unicode) { sl@0: index += probe; sl@0: } sl@0: } sl@0: sl@0: if (unicode >= SWAPW(cmStartCodes[index]) && unicode <= SWAPW(cmEndCodes[index])) { sl@0: if (cmIdRangeOffset[index] == 0) { sl@0: result = (LEGlyphID) unicode; sl@0: } else { sl@0: le_uint16 offset = unicode - SWAPW(cmStartCodes[index]); sl@0: le_uint16 rangeOffset = SWAPW(cmIdRangeOffset[index]); sl@0: le_uint16 *glyphIndexTable = (le_uint16 *) ((char *) &cmIdRangeOffset[index] + rangeOffset); sl@0: sl@0: result = SWAPW(glyphIndexTable[offset]); sl@0: } sl@0: sl@0: result += SWAPW(cmIdDelta[index]); sl@0: } else { sl@0: result = 0; sl@0: } sl@0: sl@0: return result; sl@0: } sl@0: sl@0: le_uint16 FontObject::getUnitsPerEM() sl@0: { sl@0: if (headTable == NULL) { sl@0: LETag headTag = 0x68656164; // 'head' sl@0: le_uint32 length; sl@0: sl@0: headTable = (HEADTable *) readTable(headTag, &length); sl@0: } sl@0: sl@0: return SWAPW(headTable->unitsPerEm); sl@0: } sl@0: sl@0: le_uint16 FontObject::getGlyphAdvance(LEGlyphID glyph) sl@0: { sl@0: if (hmtxTable == NULL) { sl@0: LETag maxpTag = 0x6D617870; // 'maxp' sl@0: LETag hheaTag = 0x68686561; // 'hhea' sl@0: LETag hmtxTag = 0x686D7478; // 'hmtx' sl@0: le_uint32 length; sl@0: HHEATable *hheaTable; sl@0: MAXPTable *maxpTable = (MAXPTable *) readTable(maxpTag, &length); sl@0: sl@0: numGlyphs = SWAPW(maxpTable->numGlyphs); sl@0: deleteTable(maxpTable); sl@0: sl@0: hheaTable = (HHEATable *) readTable(hheaTag, &length); sl@0: numOfLongHorMetrics = SWAPW(hheaTable->numOfLongHorMetrics); sl@0: deleteTable(hheaTable); sl@0: sl@0: hmtxTable = (HMTXTable *) readTable(hmtxTag, &length); sl@0: } sl@0: sl@0: le_uint16 index = glyph; sl@0: sl@0: if (glyph >= numGlyphs) { sl@0: return 0; sl@0: } sl@0: sl@0: if (glyph >= numOfLongHorMetrics) { sl@0: index = numOfLongHorMetrics - 1; sl@0: } sl@0: sl@0: return SWAPW(hmtxTable->hMetrics[index].advanceWidth); sl@0: } sl@0: sl@0: