/* ******************************************************************************* * * Copyright (C) 1999-2001, International Business Machines * Corporation and others. All Rights Reserved. * ******************************************************************************* * file name: PortableFontInstance.cpp * * created on: 11/22/1999 * created by: Eric R. Mader */ #include #include "LETypes.h" #include "LEFontInstance.h" #include "LESwaps.h" #include "PortableFontInstance.h" #include "sfnt.h" PortableFontInstance::PortableFontInstance(char *fileName, float pointSize, PFIErrorCode &status) : fFile(NULL), fUnitsPerEM(0), fPointSize(pointSize), fDirectory(NULL), fCMAPMapper(NULL), fHMTXTable(NULL), fNumGlyphs(0), fNumLongHorMetrics(0) { le_uint32 length; if (LE_FAILURE(status)) { return; } // open the font file fFile = fopen(fileName, "rb"); if (fFile == NULL) { status = PFI_FONT_FILE_NOT_FOUND_ERROR; return; } // read in the directory SFNTDirectory tempDir; fread(&tempDir, sizeof tempDir, 1, fFile); le_int32 dirSize = sizeof tempDir + ((SWAPW(tempDir.numTables) - ANY_NUMBER) * sizeof(DirectoryEntry)); const LETag headTag = 0x68656164; // 'head' const HEADTable *headTable = NULL; fDirectory = (const SFNTDirectory *) new char[dirSize]; if (fDirectory == NULL) { status = PFI_OUT_OF_MEMORY_ERROR; goto error_exit; } fseek(fFile, 0L, SEEK_SET); fread((void *) fDirectory, sizeof(char), dirSize, fFile); // read unitsPerEm from 'head' table headTable = (const HEADTable *) readTable(headTag, &length); if (headTable == NULL) { status = PFI_MISSING_FONT_TABLE_ERROR; goto error_exit; } fUnitsPerEM = (float) SWAPW(headTable->unitsPerEm); deleteTable(headTable); fCMAPMapper = findUnicodeMapper(); if (fCMAPMapper == NULL) { status = PFI_MISSING_FONT_TABLE_ERROR; goto error_exit; } return; error_exit: fclose(fFile); fFile = NULL; return; } PortableFontInstance::~PortableFontInstance() { if (fFile != NULL) { fclose(fFile); deleteTable(fHMTXTable); delete fCMAPMapper; } }; void PortableFontInstance::deleteTable(const void *table) const { delete[] (char *) table; } const DirectoryEntry *PortableFontInstance::findTable(LETag tag) const { if (fDirectory != NULL) { le_uint16 table = 0; le_uint16 probe = 1 << SWAPW(fDirectory->entrySelector); le_uint16 rangeShift = SWAPW(fDirectory->rangeShift) >> 4; if (SWAPL(fDirectory->tableDirectory[rangeShift].tag) <= tag) { table = rangeShift; } while (probe > (1 << 0)) { probe >>= 1; if (SWAPL(fDirectory->tableDirectory[table + probe].tag) <= tag) { table += probe; } } if (SWAPL(fDirectory->tableDirectory[table].tag) == tag) { return &fDirectory->tableDirectory[table]; } } return NULL; } const void *PortableFontInstance::readTable(LETag tag, le_uint32 *length) const { const DirectoryEntry *entry = findTable(tag); if (entry == NULL) { *length = 0; return NULL; } *length = SWAPL(entry->length); void *table = new char[*length]; if (table != NULL) { fseek(fFile, SWAPL(entry->offset), SEEK_SET); fread(table, sizeof(char), *length, fFile); } return table; } CMAPMapper *PortableFontInstance::findUnicodeMapper() { le_uint32 length; LETag cmapTag = 0x636D6170; // 'cmap' const CMAPTable *cmap = (CMAPTable *) readTable(cmapTag, &length); if (cmap == NULL) { return NULL; } return CMAPMapper::createUnicodeMapper(cmap); } void PortableFontInstance::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, const LECharMapper *mapper, LEGlyphID glyphs[]) const { le_int32 i, out = 0, dir = 1; if (reverse) { out = count - 1; dir = -1; } for (i = offset; i < offset + count; i += 1, out += dir) { LEUnicode16 high = chars[i]; LEUnicode32 code = high; if (i < offset + count - 1 && high >= 0xD800 && high <= 0xDBFF) { LEUnicode16 low = chars[i + 1]; if (low >= 0xDC00 && low <= 0xDFFF) { code = (high - 0xD800) * 0x400 + low - 0xDC00 + 0x10000; } } glyphs[out] = mapCharToGlyph(code, mapper); if (code >= 0x10000) { i += 1; glyphs[out += dir] = 0xFFFF; } } } LEGlyphID PortableFontInstance::mapCharToGlyph(LEUnicode32 ch, const LECharMapper *mapper) const { LEUnicode32 mappedChar = mapper->mapChar(ch); if (mappedChar == 0xFFFF || mappedChar == 0xFFFE) { return 0xFFFF; } if (mappedChar == 0x200C || mappedChar == 0x200D) { return 1; } if (fCMAPMapper == NULL) { return 0; } return fCMAPMapper->unicodeToGlyph(mappedChar); } void PortableFontInstance::getGlyphAdvance(LEGlyphID glyph, LEPoint &advance) const { if (fHMTXTable == NULL) { LETag maxpTag = 0x6D617870; // 'maxp' LETag hheaTag = 0x68686561; // 'hhea' LETag hmtxTag = 0x686D7478; // 'hmtx' le_uint32 length; const HHEATable *hheaTable; const MAXPTable *maxpTable = (MAXPTable *) readTable(maxpTag, &length); PortableFontInstance *realThis = (PortableFontInstance *) this; if (maxpTable != NULL) { realThis->fNumGlyphs = SWAPW(maxpTable->numGlyphs); deleteTable(maxpTable); } hheaTable = (HHEATable *) readTable(hheaTag, &length); if (hheaTable != NULL) { realThis->fNumLongHorMetrics = SWAPW(hheaTable->numOfLongHorMetrics); deleteTable((void *) hheaTable); } realThis->fHMTXTable = (const HMTXTable *) readTable(hmtxTag, &length); } le_uint16 index = glyph; if (glyph >= fNumGlyphs || fHMTXTable == NULL) { advance.fX = advance.fY = 0; return; } if (glyph >= fNumLongHorMetrics) { index = fNumLongHorMetrics - 1; } advance.fX = xUnitsToPoints(SWAPW(fHMTXTable->hMetrics[index].advanceWidth)); advance.fY = 0; } le_bool PortableFontInstance::getGlyphPoint(LEGlyphID glyph, le_int32 pointNumber, LEPoint &point) const { #if 0 hsFixedPoint2 pt; le_bool result; result = fFontInstance->getGlyphPoint(glyph, pointNumber, pt); if (result) { point.fX = xUnitsToPoints(pt.fX); point.fY = yUnitsToPoints(pt.fY); } return result; #else return false; #endif } void PortableFontInstance::transformFunits(float xFunits, float yFunits, LEPoint &pixels) const { pixels.fX = xUnitsToPoints(xFunits); pixels.fY = yUnitsToPoints(yFunits); }