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