1f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)/***************************************************************************
2f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*
3f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*   Copyright (C) 1998-2002, International Business Machines
4f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*   Corporation and others.  All Rights Reserved.
5f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*
6f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)************************************************************************/
7f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
8f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include <stdio.h>
9f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
10f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "LETypes.h"
11f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "FontObject.h"
12f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "LESwaps.h"
13f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
14f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)FontObject::FontObject(char *fileName)
15f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)  : directory(NULL), numTables(0), searchRange(0),entrySelector(0),
16f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    cmapTable(NULL), cmSegCount(0), cmSearchRange(0), cmEntrySelector(0),
17f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    cmEndCodes(NULL), cmStartCodes(NULL), cmIdDelta(0), cmIdRangeOffset(0),
18f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    headTable(NULL), hmtxTable(NULL), numGlyphs(0), numOfLongHorMetrics(0), file(NULL)
19f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles){
20f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    file = fopen(fileName, "rb");
21f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
22f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (file == NULL) {
23f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        printf("?? Couldn't open %s", fileName);
24f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return;
25f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
26f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
27f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    SFNTDirectory tempDir;
28f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
29f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    fread(&tempDir, sizeof tempDir, 1, file);
30f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
31f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    numTables       = SWAPW(tempDir.numTables);
32f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    searchRange     = SWAPW(tempDir.searchRange) >> 4;
33f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    entrySelector   = SWAPW(tempDir.entrySelector);
34f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    rangeShift      = SWAPW(tempDir.rangeShift) >> 4;
35f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
36f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    int dirSize = sizeof tempDir + ((numTables - ANY_NUMBER) * sizeof(DirectoryEntry));
37f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
38f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    directory = (SFNTDirectory *) new char[dirSize];
39f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
40f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    fseek(file, 0L, SEEK_SET);
41f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    fread(directory, sizeof(char), dirSize, file);
42f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
43f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    initUnicodeCMAP();
44f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
45f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
46f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)FontObject::~FontObject()
47f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles){
48f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    fclose(file);
49f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    delete[] directory;
50f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    delete[] cmapTable;
51f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    delete[] headTable;
52f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    delete[] hmtxTable;
53f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
54f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
55f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)void FontObject::deleteTable(void *table)
56f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles){
57f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    delete[] (char *) table;
58f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
59f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
60f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)DirectoryEntry *FontObject::findTable(LETag tag)
61f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles){
62f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    le_uint16 table = 0;
63f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    le_uint16 probe = 1 << entrySelector;
64f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
65f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (SWAPL(directory->tableDirectory[rangeShift].tag) <= tag) {
66f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        table = rangeShift;
67f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
68f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
69f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    while (probe > (1 << 0)) {
70f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        probe >>= 1;
71f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
72f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if (SWAPL(directory->tableDirectory[table + probe].tag) <= tag) {
73f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            table += probe;
74f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
75f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
76f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
77f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (SWAPL(directory->tableDirectory[table].tag) == tag) {
78f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return &directory->tableDirectory[table];
79f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
80f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
81f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    return NULL;
82f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
83f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
84f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)void *FontObject::readTable(LETag tag, le_uint32 *length)
85f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles){
86f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    DirectoryEntry *entry = findTable(tag);
87f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
88f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (entry == NULL) {
89f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        *length = 0;
90f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return NULL;
91f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
92f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
93f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    *length = SWAPL(entry->length);
94f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
95f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    void *table = new char[*length];
96f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
97f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    fseek(file, SWAPL(entry->offset), SEEK_SET);
98f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    fread(table, sizeof(char), *length, file);
99f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
100f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    return table;
101f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
102f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
103f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)CMAPEncodingSubtable *FontObject::findCMAP(le_uint16 platformID, le_uint16 platformSpecificID)
104f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles){
105f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    LETag cmapTag = 0x636D6170; // 'cmap'
106f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
107f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (cmapTable == NULL) {
108f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        le_uint32 length;
109f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
110f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        cmapTable = (CMAPTable *) readTable(cmapTag, &length);
111f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
112f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
113f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (cmapTable != NULL) {
114f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        le_uint16 i;
115f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        le_uint16 nSubtables = SWAPW(cmapTable->numberSubtables);
116f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
117f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
118f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        for (i = 0; i < nSubtables; i += 1) {
119f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            CMAPEncodingSubtableHeader *esh = &cmapTable->encodingSubtableHeaders[i];
120f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
121f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            if (SWAPW(esh->platformID) == platformID &&
122f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                SWAPW(esh->platformSpecificID) == platformSpecificID) {
123f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                return (CMAPEncodingSubtable *) ((char *) cmapTable + SWAPL(esh->encodingOffset));
124f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            }
125f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
126f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
127f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
128f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    return NULL;
129f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
130f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
131f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)void FontObject::initUnicodeCMAP()
132f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles){
133f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    CMAPEncodingSubtable *encodingSubtable = findCMAP(3, 1);
134f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
135f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (encodingSubtable == 0 ||
136f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        SWAPW(encodingSubtable->format) != 4) {
137f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        printf("Can't find unicode 'cmap'");
138f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return;
139f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
140f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
141f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    CMAPFormat4Encoding *header = (CMAPFormat4Encoding *) encodingSubtable;
142f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
143f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    cmSegCount = SWAPW(header->segCountX2) / 2;
144f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    cmSearchRange = SWAPW(header->searchRange);
145f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    cmEntrySelector = SWAPW(header->entrySelector);
146f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    cmRangeShift = SWAPW(header->rangeShift) / 2;
147f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    cmEndCodes = &header->endCodes[0];
148f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    cmStartCodes = &header->endCodes[cmSegCount + 1]; // + 1 for reservedPad...
149f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    cmIdDelta = &cmStartCodes[cmSegCount];
150f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    cmIdRangeOffset = &cmIdDelta[cmSegCount];
151f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
152f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
153f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)LEGlyphID FontObject::unicodeToGlyph(LEUnicode32 unicode32)
154f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles){
155f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (unicode32 >= 0x10000) {
156f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return 0;
157f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
158f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
159f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    LEUnicode16 unicode = (LEUnicode16) unicode32;
160f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    le_uint16 index = 0;
161f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    le_uint16 probe = 1 << cmEntrySelector;
162f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    LEGlyphID result = 0;
163f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
164f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (SWAPW(cmStartCodes[cmRangeShift]) <= unicode) {
165f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        index = cmRangeShift;
166f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
167f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
168f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    while (probe > (1 << 0)) {
169f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        probe >>= 1;
170f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
171f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if (SWAPW(cmStartCodes[index + probe]) <= unicode) {
172f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            index += probe;
173f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
174f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
175f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
176f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (unicode >= SWAPW(cmStartCodes[index]) && unicode <= SWAPW(cmEndCodes[index])) {
177f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if (cmIdRangeOffset[index] == 0) {
178f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            result = (LEGlyphID) unicode;
179f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        } else {
180f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            le_uint16 offset = unicode - SWAPW(cmStartCodes[index]);
181f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            le_uint16 rangeOffset = SWAPW(cmIdRangeOffset[index]);
182f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            le_uint16 *glyphIndexTable = (le_uint16 *) ((char *) &cmIdRangeOffset[index] + rangeOffset);
183f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
184f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            result = SWAPW(glyphIndexTable[offset]);
185f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
186f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
187f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        result += SWAPW(cmIdDelta[index]);
188f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    } else {
189f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        result = 0;
190f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
191f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
192f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    return result;
193f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
194f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
195f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)le_uint16 FontObject::getUnitsPerEM()
196f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles){
197f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (headTable == NULL) {
198f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        LETag headTag = 0x68656164; // 'head'
199f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        le_uint32 length;
200f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
201f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        headTable = (HEADTable *) readTable(headTag, &length);
202f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
203f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
204f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    return SWAPW(headTable->unitsPerEm);
205f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
206f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
207f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)le_uint16 FontObject::getGlyphAdvance(LEGlyphID glyph)
208f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles){
209f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (hmtxTable == NULL) {
210f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        LETag maxpTag = 0x6D617870; // 'maxp'
211f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        LETag hheaTag = 0x68686561; // 'hhea'
212f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        LETag hmtxTag = 0x686D7478; // 'hmtx'
213f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        le_uint32 length;
214f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        HHEATable *hheaTable;
215f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        MAXPTable *maxpTable = (MAXPTable *) readTable(maxpTag, &length);
216f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
217f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        numGlyphs = SWAPW(maxpTable->numGlyphs);
218f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        deleteTable(maxpTable);
219f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
220f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        hheaTable = (HHEATable *) readTable(hheaTag, &length);
221f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        numOfLongHorMetrics = SWAPW(hheaTable->numOfLongHorMetrics);
222f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        deleteTable(hheaTable);
223f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
224f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        hmtxTable = (HMTXTable *) readTable(hmtxTag, &length);
225f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
226f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
227f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    le_uint16 index = glyph;
228f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
229f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (glyph >= numGlyphs) {
230f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return 0;
231f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
232f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
233f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (glyph >= numOfLongHorMetrics) {
234f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        index = numOfLongHorMetrics - 1;
235f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
236f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
237f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    return SWAPW(hmtxTable->hMetrics[index].advanceWidth);
238f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
239f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
240f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
241