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