Home | History | Annotate | Download | only in leperf
      1 /*
      2  *******************************************************************************
      3  *
      4  *   Copyright (C) 1999-2013, International Business Machines
      5  *   Corporation and others.  All Rights Reserved.
      6  *
      7  *******************************************************************************
      8  *   file name:  PortableFontInstance.cpp
      9  *
     10  *   created on: 11/22/1999
     11  *   created by: Eric R. Mader
     12  */
     13 
     14 #include <stdio.h>
     15 
     16 #include "layout/LETypes.h"
     17 #include "layout/LEFontInstance.h"
     18 #include "layout/LESwaps.h"
     19 
     20 #include "PortableFontInstance.h"
     21 
     22 //#include "letest.h"
     23 #include "sfnt.h"
     24 
     25 #include <string.h>
     26 #include <stdio.h>
     27 
     28 #if 0
     29 static const char *letagToStr(LETag tag, char *str) {
     30   str[0]= 0xFF & (tag>>24);
     31   str[1]= 0xFF & (tag>>16);
     32   str[2]= 0xFF & (tag>>8);
     33   str[3]= 0xFF & (tag>>0);
     34   str[4]= 0;
     35   return str;
     36 }
     37 #endif
     38 
     39 //
     40 // Finds the high bit by binary searching
     41 // through the bits in n.
     42 //
     43 le_int8 PortableFontInstance::highBit(le_int32 value)
     44 {
     45     if (value <= 0) {
     46         return -32;
     47     }
     48 
     49     le_uint8 bit = 0;
     50 
     51     if (value >= 1 << 16) {
     52         value >>= 16;
     53         bit += 16;
     54     }
     55 
     56     if (value >= 1 << 8) {
     57         value >>= 8;
     58         bit += 8;
     59     }
     60 
     61     if (value >= 1 << 4) {
     62         value >>= 4;
     63         bit += 4;
     64     }
     65 
     66     if (value >= 1 << 2) {
     67         value >>= 2;
     68         bit += 2;
     69     }
     70 
     71     if (value >= 1 << 1) {
     72         value >>= 1;
     73         bit += 1;
     74     }
     75 
     76     return bit;
     77 }
     78 
     79 PortableFontInstance::PortableFontInstance(const char *fileName, float pointSize, LEErrorCode &status)
     80     : fFile(NULL), fPointSize(pointSize), fUnitsPerEM(0), fFontChecksum(0), fAscent(0), fDescent(0), fLeading(0),
     81       fDirectory(NULL), fNAMETable(NULL), fNameCount(0), fNameStringOffset(0), fCMAPMapper(NULL), fHMTXTable(NULL), fNumGlyphs(0), fNumLongHorMetrics(0)
     82 {
     83     if (LE_FAILURE(status)) {
     84         return;
     85     }
     86 
     87     // open the font file
     88     fFile = fopen(fileName, "rb");
     89     //printf("Open Font: %s\n", fileName);
     90 
     91     if (fFile == NULL) {
     92         printf("%s:%d: %s: FNF\n", __FILE__, __LINE__, fileName);
     93         status = LE_FONT_FILE_NOT_FOUND_ERROR;
     94         return;
     95     }
     96 
     97     // read in the directory
     98     SFNTDirectory tempDir;
     99 
    100     fread(&tempDir, sizeof tempDir, 1, fFile);
    101 
    102     le_int32 dirSize = sizeof tempDir + ((SWAPW(tempDir.numTables) - ANY_NUMBER) * sizeof(DirectoryEntry));
    103     const LETag headTag = LE_HEAD_TABLE_TAG;
    104     const LETag hheaTag = LE_HHEA_TABLE_TAG;
    105     const HEADTable *headTable = NULL;
    106     const HHEATable *hheaTable = NULL;
    107 //  const NAMETable *nameTable = NULL;
    108     le_uint16 numTables = 0;
    109 
    110     fDirectory = (const SFNTDirectory *) LE_NEW_ARRAY(char, dirSize);
    111 
    112     if (fDirectory == NULL) {
    113         printf("%s:%d: %s: malloc err\n", __FILE__, __LINE__, fileName);
    114         status = LE_MEMORY_ALLOCATION_ERROR;
    115         goto error_exit;
    116     }
    117 
    118     fseek(fFile, 0L, SEEK_SET);
    119     fread((void *) fDirectory, sizeof(char), dirSize, fFile);
    120 
    121     //
    122     // We calculate these numbers 'cause some fonts
    123     // have bogus values for them in the directory header.
    124     //
    125     numTables = SWAPW(fDirectory->numTables);
    126     fDirPower = 1 << highBit(numTables);
    127     fDirExtra = numTables - fDirPower;
    128 
    129     // read unitsPerEm from 'head' table
    130     headTable = (const HEADTable *) readFontTable(headTag);
    131 
    132     if (headTable == NULL) {
    133         status = LE_MISSING_FONT_TABLE_ERROR;
    134         printf("%s:%d: %s: missing head table\n", __FILE__, __LINE__, fileName);
    135         goto error_exit;
    136     }
    137 
    138     fUnitsPerEM   = SWAPW(headTable->unitsPerEm);
    139     fFontChecksum = SWAPL(headTable->checksumAdjustment);
    140     freeFontTable(headTable);
    141 
    142     //nameTable = (NAMETable *) readFontTable(nameTag);
    143 
    144     //if (nameTable == NULL) {
    145     //    status = LE_MISSING_FONT_TABLE_ERROR;
    146     //    goto error_exit;
    147     //}
    148 
    149     //fFontVersionString = findName(nameTable, NAME_VERSION_STRING, PLATFORM_MACINTOSH, MACINTOSH_ROMAN, MACINTOSH_ENGLISH);
    150 
    151     //if (fFontVersionString == NULL) {
    152     //    status = LE_MISSING_FONT_TABLE_ERROR;
    153     //    goto error_exit;
    154     //}
    155 
    156     //freeFontTable(nameTable);
    157 
    158     hheaTable = (HHEATable *) readFontTable(hheaTag);
    159 
    160     if (hheaTable == NULL) {
    161         printf("%s:%d: %s: missing hhea table\n", __FILE__, __LINE__, fileName);
    162         status = LE_MISSING_FONT_TABLE_ERROR;
    163         goto error_exit;
    164     }
    165 
    166     fAscent  = (le_int32) yUnitsToPoints((float) SWAPW(hheaTable->ascent));
    167     fDescent = (le_int32) yUnitsToPoints((float) SWAPW(hheaTable->descent));
    168     fLeading = (le_int32) yUnitsToPoints((float) SWAPW(hheaTable->lineGap));
    169 
    170     fNumLongHorMetrics = SWAPW(hheaTable->numOfLongHorMetrics);
    171 
    172     freeFontTable((void *) hheaTable);
    173 
    174     fCMAPMapper = findUnicodeMapper();
    175 
    176     if (fCMAPMapper == NULL) {
    177         printf("%s:%d: %s: can't load cmap\n", __FILE__, __LINE__, fileName);
    178         status = LE_MISSING_FONT_TABLE_ERROR;
    179         goto error_exit;
    180     }
    181 
    182     return;
    183 
    184 error_exit:
    185     fclose(fFile);
    186     fFile = NULL;
    187     return;
    188 }
    189 
    190 PortableFontInstance::~PortableFontInstance()
    191 {
    192     if (fFile != NULL) {
    193         fclose(fFile);
    194 
    195         freeFontTable(fHMTXTable);
    196         freeFontTable(fNAMETable);
    197 
    198         delete fCMAPMapper;
    199 
    200         LE_DELETE_ARRAY(fDirectory);
    201     }
    202 }
    203 
    204 const DirectoryEntry *PortableFontInstance::findTable(LETag tag) const
    205 {
    206     if (fDirectory != NULL) {
    207         le_uint16 table = 0;
    208         le_uint16 probe = fDirPower;
    209 
    210         if (SWAPL(fDirectory->tableDirectory[fDirExtra].tag) <= tag) {
    211             table = fDirExtra;
    212         }
    213 
    214         while (probe > (1 << 0)) {
    215             probe >>= 1;
    216 
    217             if (SWAPL(fDirectory->tableDirectory[table + probe].tag) <= tag) {
    218                 table += probe;
    219             }
    220         }
    221 
    222         if (SWAPL(fDirectory->tableDirectory[table].tag) == tag) {
    223             return &fDirectory->tableDirectory[table];
    224         }
    225     }
    226 
    227     return NULL;
    228 }
    229 
    230 const void *PortableFontInstance::readTable(LETag tag, le_uint32 *length) const
    231 {
    232     const DirectoryEntry *entry = findTable(tag);
    233 
    234     if (entry == NULL) {
    235         *length = 0;
    236         return NULL;
    237     }
    238 
    239     *length = SWAPL(entry->length);
    240 
    241     void *table = LE_NEW_ARRAY(char, *length);
    242 
    243     if (table != NULL) {
    244         fseek(fFile, SWAPL(entry->offset), SEEK_SET);
    245         fread(table, sizeof(char), *length, fFile);
    246     }
    247 
    248     return table;
    249 }
    250 
    251 const void *PortableFontInstance::getFontTable(LETag tableTag) const
    252 {
    253   size_t ignored;
    254   return getFontTable(tableTag, ignored);
    255 }
    256 
    257 const void *PortableFontInstance::getFontTable(LETag tableTag, size_t &length) const
    258 {
    259   return FontTableCache::find(tableTag, length);
    260 }
    261 
    262 const void *PortableFontInstance::readFontTable(LETag tableTag, size_t &length) const
    263 {
    264     le_uint32 len;
    265 
    266     const void *data= readTable(tableTag, &len);
    267     length = len;
    268     //char tag5[5];
    269     //printf("Read %s, result %p #%d\n", letagToStr(tableTag,tag5), data,len);
    270     return data;
    271 }
    272 
    273 CMAPMapper *PortableFontInstance::findUnicodeMapper()
    274 {
    275     LETag cmapTag = LE_CMAP_TABLE_TAG;
    276     const CMAPTable *cmap = (CMAPTable *) readFontTable(cmapTag);
    277 
    278     if (cmap == NULL) {
    279         return NULL;
    280     }
    281 
    282     return CMAPMapper::createUnicodeMapper(cmap);
    283 }
    284 
    285 const char *PortableFontInstance::getNameString(le_uint16 nameID, le_uint16 platformID, le_uint16 encodingID, le_uint16 languageID) const
    286 {
    287     if (fNAMETable == NULL) {
    288         LETag nameTag = LE_NAME_TABLE_TAG;
    289         PortableFontInstance *realThis = (PortableFontInstance *) this;
    290 
    291         realThis->fNAMETable = (const NAMETable *) readFontTable(nameTag);
    292 
    293         if (realThis->fNAMETable != NULL) {
    294             realThis->fNameCount        = SWAPW(realThis->fNAMETable->count);
    295             realThis->fNameStringOffset = SWAPW(realThis->fNAMETable->stringOffset);
    296         }
    297     }
    298 
    299     for(le_int32 i = 0; i < fNameCount; i += 1) {
    300         const NameRecord *nameRecord = &fNAMETable->nameRecords[i];
    301 
    302         if (SWAPW(nameRecord->platformID) == platformID && SWAPW(nameRecord->encodingID) == encodingID &&
    303             SWAPW(nameRecord->languageID) == languageID && SWAPW(nameRecord->nameID) == nameID) {
    304             char *name = ((char *) fNAMETable) + fNameStringOffset + SWAPW(nameRecord->offset);
    305             le_uint16 length = SWAPW(nameRecord->length);
    306             char *result = LE_NEW_ARRAY(char, length + 2);
    307 
    308             LE_ARRAY_COPY(result, name, length);
    309             result[length] = result[length + 1] = 0;
    310 
    311             return result;
    312         }
    313     }
    314 
    315     return NULL;
    316 }
    317 
    318 const LEUnicode16 *PortableFontInstance::getUnicodeNameString(le_uint16 nameID, le_uint16 platformID, le_uint16 encodingID, le_uint16 languageID) const
    319 {
    320     if (fNAMETable == NULL) {
    321         LETag nameTag = LE_NAME_TABLE_TAG;
    322         PortableFontInstance *realThis = (PortableFontInstance *) this;
    323 
    324         realThis->fNAMETable = (const NAMETable *) readFontTable(nameTag);
    325 
    326         if (realThis->fNAMETable != NULL) {
    327             realThis->fNameCount        = SWAPW(realThis->fNAMETable->count);
    328             realThis->fNameStringOffset = SWAPW(realThis->fNAMETable->stringOffset);
    329         }
    330     }
    331 
    332     for(le_int32 i = 0; i < fNameCount; i += 1) {
    333         const NameRecord *nameRecord = &fNAMETable->nameRecords[i];
    334 
    335         if (SWAPW(nameRecord->platformID) == platformID && SWAPW(nameRecord->encodingID) == encodingID &&
    336             SWAPW(nameRecord->languageID) == languageID && SWAPW(nameRecord->nameID) == nameID) {
    337             LEUnicode16 *name = (LEUnicode16 *) (((char *) fNAMETable) + fNameStringOffset + SWAPW(nameRecord->offset));
    338             le_uint16 length = SWAPW(nameRecord->length) / 2;
    339             LEUnicode16 *result = LE_NEW_ARRAY(LEUnicode16, length + 2);
    340 
    341             for (le_int32 c = 0; c < length; c += 1) {
    342                 result[c] = SWAPW(name[c]);
    343             }
    344 
    345             result[length] = 0;
    346 
    347             return result;
    348         }
    349     }
    350 
    351     return NULL;
    352 }
    353 
    354 void PortableFontInstance::deleteNameString(const char *name) const
    355 {
    356     LE_DELETE_ARRAY(name);
    357 }
    358 
    359 void PortableFontInstance::deleteNameString(const LEUnicode16 *name) const
    360 {
    361     LE_DELETE_ARRAY(name);
    362 }
    363 
    364 void PortableFontInstance::getGlyphAdvance(LEGlyphID glyph, LEPoint &advance) const
    365 {
    366     TTGlyphID ttGlyph = (TTGlyphID) LE_GET_GLYPH(glyph);
    367 
    368     if (fHMTXTable == NULL) {
    369         LETag maxpTag = LE_MAXP_TABLE_TAG;
    370         LETag hmtxTag = LE_HMTX_TABLE_TAG;
    371         const MAXPTable *maxpTable = (MAXPTable *) readFontTable(maxpTag);
    372         PortableFontInstance *realThis = (PortableFontInstance *) this;
    373 
    374         if (maxpTable != NULL) {
    375             realThis->fNumGlyphs = SWAPW(maxpTable->numGlyphs);
    376             freeFontTable(maxpTable);
    377         }
    378 
    379         realThis->fHMTXTable = (const HMTXTable *) readFontTable(hmtxTag);
    380     }
    381 
    382     le_uint16 index = ttGlyph;
    383 
    384     if (ttGlyph >= fNumGlyphs || fHMTXTable == NULL) {
    385         advance.fX = advance.fY = 0;
    386         return;
    387     }
    388 
    389     if (ttGlyph >= fNumLongHorMetrics) {
    390         index = fNumLongHorMetrics - 1;
    391     }
    392 
    393     advance.fX = xUnitsToPoints(SWAPW(fHMTXTable->hMetrics[index].advanceWidth));
    394     advance.fY = 0;
    395 }
    396 
    397 le_bool PortableFontInstance::getGlyphPoint(LEGlyphID /*glyph*/, le_int32 /*pointNumber*/, LEPoint &/*point*/) const
    398 {
    399     return FALSE;
    400 }
    401 
    402 le_int32 PortableFontInstance::getUnitsPerEM() const
    403 {
    404     return fUnitsPerEM;
    405 }
    406 
    407 le_uint32 PortableFontInstance::getFontChecksum() const
    408 {
    409     return fFontChecksum;
    410 }
    411 
    412 le_uint32 PortableFontInstance::getRawChecksum() const
    413 {
    414   // how big is it?
    415   //  fseek(fFile, 0L, SEEK_END);
    416   //  long size = ftell(fFile);
    417   le_int32 chksum = 0;
    418   // now, calculate
    419   fseek(fFile, 0L, SEEK_SET);
    420   int r;
    421   int count =0;
    422   while((r = fgetc(fFile)) != EOF) {
    423     chksum += r;
    424     count ++;
    425   }
    426   return (le_uint32) chksum; // cast to signed
    427 }
    428 
    429 le_int32 PortableFontInstance::getAscent() const
    430 {
    431     return fAscent;
    432 }
    433 
    434 le_int32 PortableFontInstance::getDescent() const
    435 {
    436     return fDescent;
    437 }
    438 
    439 le_int32 PortableFontInstance::getLeading() const
    440 {
    441     return fLeading;
    442 }
    443 
    444 // We really want to inherit this method from the superclass, but some compilers
    445 // issue a warning if we don't implement it...
    446 LEGlyphID PortableFontInstance::mapCharToGlyph(LEUnicode32 ch, const LECharMapper *mapper, le_bool filterZeroWidth) const
    447 {
    448     return LEFontInstance::mapCharToGlyph(ch, mapper, filterZeroWidth);
    449 }
    450 
    451 // We really want to inherit this method from the superclass, but some compilers
    452 // issue a warning if we don't implement it...
    453 LEGlyphID PortableFontInstance::mapCharToGlyph(LEUnicode32 ch, const LECharMapper *mapper) const
    454 {
    455     return LEFontInstance::mapCharToGlyph(ch, mapper);
    456 }
    457 
    458 LEGlyphID PortableFontInstance::mapCharToGlyph(LEUnicode32 ch) const
    459 {
    460     return fCMAPMapper->unicodeToGlyph(ch);
    461 }
    462 
    463 float PortableFontInstance::getXPixelsPerEm() const
    464 {
    465     return fPointSize;
    466 }
    467 
    468 float PortableFontInstance::getYPixelsPerEm() const
    469 {
    470     return fPointSize;
    471 }
    472 
    473 float PortableFontInstance::getScaleFactorX() const
    474 {
    475     return 1.0;
    476 }
    477 
    478 float PortableFontInstance::getScaleFactorY() const
    479 {
    480     return 1.0;
    481 }
    482