12e5b6d6dSopenharmony_ci/***************************************************************************
22e5b6d6dSopenharmony_ci*
32e5b6d6dSopenharmony_ci*   © 2016 and later: Unicode, Inc. and others.
42e5b6d6dSopenharmony_ci*   License & terms of use: http://www.unicode.org/copyright.html
52e5b6d6dSopenharmony_ci*
62e5b6d6dSopenharmony_ci****************************************************************************/
72e5b6d6dSopenharmony_ci/***************************************************************************
82e5b6d6dSopenharmony_ci*
92e5b6d6dSopenharmony_ci*   Copyright (C) 1998-2013, International Business Machines
102e5b6d6dSopenharmony_ci*   Corporation and others.  All Rights Reserved.
112e5b6d6dSopenharmony_ci*
122e5b6d6dSopenharmony_ci************************************************************************/
132e5b6d6dSopenharmony_ci
142e5b6d6dSopenharmony_ci#include <stdio.h>
152e5b6d6dSopenharmony_ci
162e5b6d6dSopenharmony_ci#include "LETypes.h"
172e5b6d6dSopenharmony_ci#include "FontObject.h"
182e5b6d6dSopenharmony_ci#include "LESwaps.h"
192e5b6d6dSopenharmony_ci
202e5b6d6dSopenharmony_ciFontObject::FontObject(char *fileName)
212e5b6d6dSopenharmony_ci  : directory(NULL), numTables(0), searchRange(0),entrySelector(0),
222e5b6d6dSopenharmony_ci    cmapTable(NULL), cmSegCount(0), cmSearchRange(0), cmEntrySelector(0),
232e5b6d6dSopenharmony_ci    cmEndCodes(NULL), cmStartCodes(NULL), cmIdDelta(0), cmIdRangeOffset(0),
242e5b6d6dSopenharmony_ci    headTable(NULL), hmtxTable(NULL), numGlyphs(0), numOfLongHorMetrics(0), file(NULL)
252e5b6d6dSopenharmony_ci{
262e5b6d6dSopenharmony_ci    file = fopen(fileName, "rb");
272e5b6d6dSopenharmony_ci
282e5b6d6dSopenharmony_ci    if (file == NULL) {
292e5b6d6dSopenharmony_ci        printf("?? Couldn't open %s", fileName);
302e5b6d6dSopenharmony_ci        return;
312e5b6d6dSopenharmony_ci    }
322e5b6d6dSopenharmony_ci
332e5b6d6dSopenharmony_ci    SFNTDirectory tempDir;
342e5b6d6dSopenharmony_ci
352e5b6d6dSopenharmony_ci    fread(&tempDir, sizeof tempDir, 1, file);
362e5b6d6dSopenharmony_ci
372e5b6d6dSopenharmony_ci    numTables       = SWAPW(tempDir.numTables);
382e5b6d6dSopenharmony_ci    searchRange     = SWAPW(tempDir.searchRange) >> 4;
392e5b6d6dSopenharmony_ci    entrySelector   = SWAPW(tempDir.entrySelector);
402e5b6d6dSopenharmony_ci    rangeShift      = SWAPW(tempDir.rangeShift) >> 4;
412e5b6d6dSopenharmony_ci
422e5b6d6dSopenharmony_ci    int dirSize = sizeof tempDir + ((numTables - ANY_NUMBER) * sizeof(DirectoryEntry));
432e5b6d6dSopenharmony_ci
442e5b6d6dSopenharmony_ci    directory = (SFNTDirectory *) new char[dirSize];
452e5b6d6dSopenharmony_ci
462e5b6d6dSopenharmony_ci    fseek(file, 0L, SEEK_SET);
472e5b6d6dSopenharmony_ci    fread(directory, sizeof(char), dirSize, file);
482e5b6d6dSopenharmony_ci
492e5b6d6dSopenharmony_ci    initUnicodeCMAP();
502e5b6d6dSopenharmony_ci}
512e5b6d6dSopenharmony_ci
522e5b6d6dSopenharmony_ciFontObject::~FontObject()
532e5b6d6dSopenharmony_ci{
542e5b6d6dSopenharmony_ci    fclose(file);
552e5b6d6dSopenharmony_ci    delete[] directory;
562e5b6d6dSopenharmony_ci    delete[] cmapTable;
572e5b6d6dSopenharmony_ci    delete[] headTable;
582e5b6d6dSopenharmony_ci    delete[] hmtxTable;
592e5b6d6dSopenharmony_ci}
602e5b6d6dSopenharmony_ci
612e5b6d6dSopenharmony_civoid FontObject::deleteTable(void *table)
622e5b6d6dSopenharmony_ci{
632e5b6d6dSopenharmony_ci    delete[] (char *) table;
642e5b6d6dSopenharmony_ci}
652e5b6d6dSopenharmony_ci
662e5b6d6dSopenharmony_ciDirectoryEntry *FontObject::findTable(LETag tag)
672e5b6d6dSopenharmony_ci{
682e5b6d6dSopenharmony_ci    le_uint16 table = 0;
692e5b6d6dSopenharmony_ci    le_uint16 probe = 1 << entrySelector;
702e5b6d6dSopenharmony_ci
712e5b6d6dSopenharmony_ci    if (SWAPL(directory->tableDirectory[rangeShift].tag) <= tag) {
722e5b6d6dSopenharmony_ci        table = rangeShift;
732e5b6d6dSopenharmony_ci    }
742e5b6d6dSopenharmony_ci
752e5b6d6dSopenharmony_ci    while (probe > (1 << 0)) {
762e5b6d6dSopenharmony_ci        probe >>= 1;
772e5b6d6dSopenharmony_ci
782e5b6d6dSopenharmony_ci        if (SWAPL(directory->tableDirectory[table + probe].tag) <= tag) {
792e5b6d6dSopenharmony_ci            table += probe;
802e5b6d6dSopenharmony_ci        }
812e5b6d6dSopenharmony_ci    }
822e5b6d6dSopenharmony_ci
832e5b6d6dSopenharmony_ci    if (SWAPL(directory->tableDirectory[table].tag) == tag) {
842e5b6d6dSopenharmony_ci        return &directory->tableDirectory[table];
852e5b6d6dSopenharmony_ci    }
862e5b6d6dSopenharmony_ci
872e5b6d6dSopenharmony_ci    return NULL;
882e5b6d6dSopenharmony_ci}
892e5b6d6dSopenharmony_ci
902e5b6d6dSopenharmony_civoid *FontObject::readTable(LETag tag, le_uint32 *length)
912e5b6d6dSopenharmony_ci{
922e5b6d6dSopenharmony_ci    DirectoryEntry *entry = findTable(tag);
932e5b6d6dSopenharmony_ci
942e5b6d6dSopenharmony_ci    if (entry == NULL) {
952e5b6d6dSopenharmony_ci        *length = 0;
962e5b6d6dSopenharmony_ci        return NULL;
972e5b6d6dSopenharmony_ci    }
982e5b6d6dSopenharmony_ci
992e5b6d6dSopenharmony_ci    *length = SWAPL(entry->length);
1002e5b6d6dSopenharmony_ci
1012e5b6d6dSopenharmony_ci    void *table = new char[*length];
1022e5b6d6dSopenharmony_ci
1032e5b6d6dSopenharmony_ci    fseek(file, SWAPL(entry->offset), SEEK_SET);
1042e5b6d6dSopenharmony_ci    fread(table, sizeof(char), *length, file);
1052e5b6d6dSopenharmony_ci
1062e5b6d6dSopenharmony_ci    return table;
1072e5b6d6dSopenharmony_ci}
1082e5b6d6dSopenharmony_ci
1092e5b6d6dSopenharmony_ciCMAPEncodingSubtable *FontObject::findCMAP(le_uint16 platformID, le_uint16 platformSpecificID)
1102e5b6d6dSopenharmony_ci{
1112e5b6d6dSopenharmony_ci    LETag cmapTag = 0x636D6170; // 'cmap'
1122e5b6d6dSopenharmony_ci
1132e5b6d6dSopenharmony_ci    if (cmapTable == NULL) {
1142e5b6d6dSopenharmony_ci        le_uint32 length;
1152e5b6d6dSopenharmony_ci
1162e5b6d6dSopenharmony_ci        cmapTable = (CMAPTable *) readTable(cmapTag, &length);
1172e5b6d6dSopenharmony_ci    }
1182e5b6d6dSopenharmony_ci
1192e5b6d6dSopenharmony_ci    if (cmapTable != NULL) {
1202e5b6d6dSopenharmony_ci        le_uint16 i;
1212e5b6d6dSopenharmony_ci        le_uint16 nSubtables = SWAPW(cmapTable->numberSubtables);
1222e5b6d6dSopenharmony_ci
1232e5b6d6dSopenharmony_ci
1242e5b6d6dSopenharmony_ci        for (i = 0; i < nSubtables; i += 1) {
1252e5b6d6dSopenharmony_ci            CMAPEncodingSubtableHeader *esh = &cmapTable->encodingSubtableHeaders[i];
1262e5b6d6dSopenharmony_ci
1272e5b6d6dSopenharmony_ci            if (SWAPW(esh->platformID) == platformID &&
1282e5b6d6dSopenharmony_ci                SWAPW(esh->platformSpecificID) == platformSpecificID) {
1292e5b6d6dSopenharmony_ci                return (CMAPEncodingSubtable *) ((char *) cmapTable + SWAPL(esh->encodingOffset));
1302e5b6d6dSopenharmony_ci            }
1312e5b6d6dSopenharmony_ci        }
1322e5b6d6dSopenharmony_ci    }
1332e5b6d6dSopenharmony_ci
1342e5b6d6dSopenharmony_ci    return NULL;
1352e5b6d6dSopenharmony_ci}
1362e5b6d6dSopenharmony_ci
1372e5b6d6dSopenharmony_civoid FontObject::initUnicodeCMAP()
1382e5b6d6dSopenharmony_ci{
1392e5b6d6dSopenharmony_ci    CMAPEncodingSubtable *encodingSubtable = findCMAP(3, 1);
1402e5b6d6dSopenharmony_ci
1412e5b6d6dSopenharmony_ci    if (encodingSubtable == 0 ||
1422e5b6d6dSopenharmony_ci        SWAPW(encodingSubtable->format) != 4) {
1432e5b6d6dSopenharmony_ci        printf("Can't find unicode 'cmap'");
1442e5b6d6dSopenharmony_ci        return;
1452e5b6d6dSopenharmony_ci    }
1462e5b6d6dSopenharmony_ci
1472e5b6d6dSopenharmony_ci    CMAPFormat4Encoding *header = (CMAPFormat4Encoding *) encodingSubtable;
1482e5b6d6dSopenharmony_ci
1492e5b6d6dSopenharmony_ci    cmSegCount = SWAPW(header->segCountX2) / 2;
1502e5b6d6dSopenharmony_ci    cmSearchRange = SWAPW(header->searchRange);
1512e5b6d6dSopenharmony_ci    cmEntrySelector = SWAPW(header->entrySelector);
1522e5b6d6dSopenharmony_ci    cmRangeShift = SWAPW(header->rangeShift) / 2;
1532e5b6d6dSopenharmony_ci    cmEndCodes = &header->endCodes[0];
1542e5b6d6dSopenharmony_ci    cmStartCodes = &header->endCodes[cmSegCount + 1]; // + 1 for reservedPad...
1552e5b6d6dSopenharmony_ci    cmIdDelta = &cmStartCodes[cmSegCount];
1562e5b6d6dSopenharmony_ci    cmIdRangeOffset = &cmIdDelta[cmSegCount];
1572e5b6d6dSopenharmony_ci}
1582e5b6d6dSopenharmony_ci
1592e5b6d6dSopenharmony_ciLEGlyphID FontObject::unicodeToGlyph(LEUnicode32 unicode32)
1602e5b6d6dSopenharmony_ci{
1612e5b6d6dSopenharmony_ci    if (unicode32 >= 0x10000) {
1622e5b6d6dSopenharmony_ci        return 0;
1632e5b6d6dSopenharmony_ci    }
1642e5b6d6dSopenharmony_ci
1652e5b6d6dSopenharmony_ci    LEUnicode16 unicode = (LEUnicode16) unicode32;
1662e5b6d6dSopenharmony_ci    le_uint16 index = 0;
1672e5b6d6dSopenharmony_ci    le_uint16 probe = 1 << cmEntrySelector;
1682e5b6d6dSopenharmony_ci    LEGlyphID result = 0;
1692e5b6d6dSopenharmony_ci
1702e5b6d6dSopenharmony_ci    if (SWAPW(cmStartCodes[cmRangeShift]) <= unicode) {
1712e5b6d6dSopenharmony_ci        index = cmRangeShift;
1722e5b6d6dSopenharmony_ci    }
1732e5b6d6dSopenharmony_ci
1742e5b6d6dSopenharmony_ci    while (probe > (1 << 0)) {
1752e5b6d6dSopenharmony_ci        probe >>= 1;
1762e5b6d6dSopenharmony_ci
1772e5b6d6dSopenharmony_ci        if (SWAPW(cmStartCodes[index + probe]) <= unicode) {
1782e5b6d6dSopenharmony_ci            index += probe;
1792e5b6d6dSopenharmony_ci        }
1802e5b6d6dSopenharmony_ci    }
1812e5b6d6dSopenharmony_ci
1822e5b6d6dSopenharmony_ci    if (unicode >= SWAPW(cmStartCodes[index]) && unicode <= SWAPW(cmEndCodes[index])) {
1832e5b6d6dSopenharmony_ci        if (cmIdRangeOffset[index] == 0) {
1842e5b6d6dSopenharmony_ci            result = (LEGlyphID) unicode;
1852e5b6d6dSopenharmony_ci        } else {
1862e5b6d6dSopenharmony_ci            le_uint16 offset = unicode - SWAPW(cmStartCodes[index]);
1872e5b6d6dSopenharmony_ci            le_uint16 rangeOffset = SWAPW(cmIdRangeOffset[index]);
1882e5b6d6dSopenharmony_ci            le_uint16 *glyphIndexTable = (le_uint16 *) ((char *) &cmIdRangeOffset[index] + rangeOffset);
1892e5b6d6dSopenharmony_ci
1902e5b6d6dSopenharmony_ci            result = SWAPW(glyphIndexTable[offset]);
1912e5b6d6dSopenharmony_ci        }
1922e5b6d6dSopenharmony_ci
1932e5b6d6dSopenharmony_ci        result += SWAPW(cmIdDelta[index]);
1942e5b6d6dSopenharmony_ci    } else {
1952e5b6d6dSopenharmony_ci        result = 0;
1962e5b6d6dSopenharmony_ci    }
1972e5b6d6dSopenharmony_ci
1982e5b6d6dSopenharmony_ci    return result;
1992e5b6d6dSopenharmony_ci}
2002e5b6d6dSopenharmony_ci
2012e5b6d6dSopenharmony_cile_uint16 FontObject::getUnitsPerEM()
2022e5b6d6dSopenharmony_ci{
2032e5b6d6dSopenharmony_ci    if (headTable == NULL) {
2042e5b6d6dSopenharmony_ci        LETag headTag = 0x68656164; // 'head'
2052e5b6d6dSopenharmony_ci        le_uint32 length;
2062e5b6d6dSopenharmony_ci
2072e5b6d6dSopenharmony_ci        headTable = (HEADTable *) readTable(headTag, &length);
2082e5b6d6dSopenharmony_ci    }
2092e5b6d6dSopenharmony_ci
2102e5b6d6dSopenharmony_ci    return SWAPW(headTable->unitsPerEm);
2112e5b6d6dSopenharmony_ci}
2122e5b6d6dSopenharmony_ci
2132e5b6d6dSopenharmony_cile_uint16 FontObject::getGlyphAdvance(LEGlyphID glyph)
2142e5b6d6dSopenharmony_ci{
2152e5b6d6dSopenharmony_ci    if (hmtxTable == NULL) {
2162e5b6d6dSopenharmony_ci        LETag maxpTag = 0x6D617870; // 'maxp'
2172e5b6d6dSopenharmony_ci        LETag hheaTag = 0x68686561; // 'hhea'
2182e5b6d6dSopenharmony_ci        LETag hmtxTag = 0x686D7478; // 'hmtx'
2192e5b6d6dSopenharmony_ci        le_uint32 length;
2202e5b6d6dSopenharmony_ci        HHEATable *hheaTable;
2212e5b6d6dSopenharmony_ci        MAXPTable *maxpTable = (MAXPTable *) readTable(maxpTag, &length);
2222e5b6d6dSopenharmony_ci
2232e5b6d6dSopenharmony_ci        numGlyphs = SWAPW(maxpTable->numGlyphs);
2242e5b6d6dSopenharmony_ci        deleteTable(maxpTable);
2252e5b6d6dSopenharmony_ci
2262e5b6d6dSopenharmony_ci        hheaTable = (HHEATable *) readTable(hheaTag, &length);
2272e5b6d6dSopenharmony_ci        numOfLongHorMetrics = SWAPW(hheaTable->numOfLongHorMetrics);
2282e5b6d6dSopenharmony_ci        deleteTable(hheaTable);
2292e5b6d6dSopenharmony_ci
2302e5b6d6dSopenharmony_ci        hmtxTable = (HMTXTable *) readTable(hmtxTag, &length);
2312e5b6d6dSopenharmony_ci    }
2322e5b6d6dSopenharmony_ci
2332e5b6d6dSopenharmony_ci    le_uint16 index = glyph;
2342e5b6d6dSopenharmony_ci
2352e5b6d6dSopenharmony_ci    if (glyph >= numGlyphs) {
2362e5b6d6dSopenharmony_ci        return 0;
2372e5b6d6dSopenharmony_ci    }
2382e5b6d6dSopenharmony_ci
2392e5b6d6dSopenharmony_ci    if (glyph >= numOfLongHorMetrics) {
2402e5b6d6dSopenharmony_ci        index = numOfLongHorMetrics - 1;
2412e5b6d6dSopenharmony_ci    }
2422e5b6d6dSopenharmony_ci
2432e5b6d6dSopenharmony_ci    return SWAPW(hmtxTable->hMetrics[index].advanceWidth);
2442e5b6d6dSopenharmony_ci}
2452e5b6d6dSopenharmony_ci
2462e5b6d6dSopenharmony_ci
247