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