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