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