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