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 *   Copyright (C) 1998-2014, International Business Machines
      6 *   Corporation and others.  All Rights Reserved.
      7 *
      8 ************************************************************************/
      9 
     10 #include "layout/LETypes.h"
     11 #include "layout/LESwaps.h"
     12 
     13 #include "sfnt.h"
     14 #include "cmaps.h"
     15 #include <stdio.h>
     16 
     17 #define SWAPU16(code) ((LEUnicode16) SWAPW(code))
     18 #define SWAPU32(code) ((LEUnicode32) SWAPL(code))
     19 
     20 //
     21 // Finds the high bit by binary searching
     22 // through the bits in value.
     23 //
     24 le_int8 highBit(le_uint32 value)
     25 {
     26     le_uint8 bit = 0;
     27 
     28     if (value >= 1 << 16) {
     29         value >>= 16;
     30         bit += 16;
     31     }
     32 
     33     if (value >= 1 << 8) {
     34         value >>= 8;
     35         bit += 8;
     36     }
     37 
     38     if (value >= 1 << 4) {
     39         value >>= 4;
     40         bit += 4;
     41     }
     42 
     43     if (value >= 1 << 2) {
     44         value >>= 2;
     45         bit += 2;
     46     }
     47 
     48     if (value >= 1 << 1) {
     49         value >>= 1;
     50         bit += 1;
     51     }
     52 
     53     return bit;
     54 }
     55 
     56 CMAPMapper *CMAPMapper::createUnicodeMapper(const CMAPTable *cmap)
     57 {
     58     le_uint16 i;
     59     le_uint16 nSubtables = SWAPW(cmap->numberSubtables);
     60     const CMAPEncodingSubtable *subtable = NULL;
     61     le_bool found = FALSE;
     62     le_uint16 foundPlatformID = 0xFFFF;
     63     le_uint16 foundPlatformSpecificID = 0xFFFF;
     64     le_uint32 foundOffset = 0;
     65     le_uint16 foundTable = 0xFFFF;
     66     // first pass, look for MS table. (preferred?)
     67     for (i = 0; i < nSubtables && !found; i += 1) {
     68         const CMAPEncodingSubtableHeader *esh = &cmap->encodingSubtableHeaders[i];
     69 
     70         le_uint16 platformID = SWAPW(esh->platformID);
     71         le_uint16 platformSpecificID = SWAPW(esh->platformSpecificID);
     72         if (platformID == 3) { // microsoft
     73           switch (platformSpecificID) {
     74             case 1: // Unicode BMP (UCS-2)
     75             case 10: // Unicode UCS-4
     76                 foundOffset = SWAPL(esh->encodingOffset);
     77                 foundPlatformID = platformID;
     78                 foundPlatformSpecificID = platformSpecificID;
     79                 found = TRUE;
     80                 foundTable = i;
     81                 break;
     82 
     83                 //default:
     84               //              printf("%s:%d: microsoft (3) platform specific ID %d (wanted 1 or 10) for subtable %d/%d\n", __FILE__, __LINE__, (SWAPW(esh->platformSpecificID)), i, nSubtables);
     85             }
     86         } else {
     87           //printf("%s:%d: platform  ID %d (wanted 3, microsoft) for subtable %d/%d\n", __FILE__, __LINE__, (SWAPW(esh->platformID)), i, nSubtables);
     88         }
     89     }
     90 
     91     // second pass, allow non MS table
     92     // first pass, look for MS table. (preferred?)
     93       for (i = 0; i < nSubtables && !found; i += 1) {
     94         const CMAPEncodingSubtableHeader *esh = &cmap->encodingSubtableHeaders[i];
     95         le_uint16 platformID = SWAPW(esh->platformID);
     96         le_uint16 platformSpecificID = SWAPW(esh->platformSpecificID);
     97         //printf("%s:%d: table %d/%d has platform:specific %d:%d\n", __FILE__, __LINE__, i, nSubtables, platformID, platformSpecificID);
     98         switch(platformID) {
     99         case 0: // Unicode platform
    100           switch(platformSpecificID) {
    101           case 0:
    102           case 1:
    103           case 2:
    104           case 3:
    105             foundOffset = SWAPL(esh->encodingOffset);
    106             foundPlatformID = platformID;
    107             foundPlatformSpecificID = platformSpecificID;
    108             foundTable = i;
    109             found = TRUE;
    110             break;
    111 
    112           default: printf("Error: table %d (psid %d) is unknown. Skipping.\n", i, platformSpecificID); break;
    113           }
    114           break;
    115 
    116           //default:
    117           //printf("Skipping platform id %d\n", platformID);
    118         }
    119     }
    120 
    121 
    122     if (found)
    123     {
    124       subtable = (const CMAPEncodingSubtable *) ((const char *) cmap + foundOffset);
    125       //printf("%s:%d: using subtable #%d/%d type %d:%d\n", __FILE__, __LINE__, foundTable, nSubtables, foundPlatformID, foundPlatformSpecificID);
    126       (void)foundPlatformID;   // Suppress unused variable compiler warnings.
    127       (void)foundTable;
    128       (void)foundPlatformSpecificID;
    129     } else {
    130       printf("%s:%d: could not find subtable.\n", __FILE__, __LINE__);
    131       return NULL;
    132     }
    133 
    134     le_uint16 tableFormat = SWAPW(subtable->format);
    135     //printf("%s:%d: table format %d\n", __FILE__, __LINE__, tableFormat);
    136 
    137     switch (tableFormat) {
    138     case 4:
    139         return new CMAPFormat4Mapper(cmap, (const CMAPFormat4Encoding *) subtable);
    140 
    141     case 12:
    142     {
    143         const CMAPFormat12Encoding *encoding = (const CMAPFormat12Encoding *) subtable;
    144 
    145         return new CMAPGroupMapper(cmap, encoding->groups, SWAPL(encoding->nGroups));
    146     }
    147 
    148     default:
    149         break;
    150     }
    151 
    152     printf("%s:%d: Unknown format %x.\n", __FILE__, __LINE__, (SWAPW(subtable->format)));
    153     return NULL;
    154 }
    155 
    156 CMAPFormat4Mapper::CMAPFormat4Mapper(const CMAPTable *cmap, const CMAPFormat4Encoding *header)
    157     : CMAPMapper(cmap)
    158 {
    159     le_uint16 segCount = SWAPW(header->segCountX2) / 2;
    160 
    161     fEntrySelector = SWAPW(header->entrySelector);
    162     fRangeShift = SWAPW(header->rangeShift) / 2;
    163     fEndCodes = &header->endCodes[0];
    164     fStartCodes = &header->endCodes[segCount + 1]; // + 1 for reservedPad...
    165     fIdDelta = &fStartCodes[segCount];
    166     fIdRangeOffset = &fIdDelta[segCount];
    167 }
    168 
    169 LEGlyphID CMAPFormat4Mapper::unicodeToGlyph(LEUnicode32 unicode32) const
    170 {
    171     if (unicode32 >= 0x10000) {
    172         return 0;
    173     }
    174 
    175     LEUnicode16 unicode = (LEUnicode16) unicode32;
    176     le_uint16 index = 0;
    177     le_uint16 probe = 1 << fEntrySelector;
    178     TTGlyphID result = 0;
    179 
    180     if (SWAPU16(fStartCodes[fRangeShift]) <= unicode) {
    181         index = fRangeShift;
    182     }
    183 
    184     while (probe > (1 << 0)) {
    185         probe >>= 1;
    186 
    187         if (SWAPU16(fStartCodes[index + probe]) <= unicode) {
    188             index += probe;
    189         }
    190     }
    191 
    192     if (unicode >= SWAPU16(fStartCodes[index]) && unicode <= SWAPU16(fEndCodes[index])) {
    193         if (fIdRangeOffset[index] == 0) {
    194             result = (TTGlyphID) unicode;
    195         } else {
    196             le_uint16 offset = unicode - SWAPU16(fStartCodes[index]);
    197             le_uint16 rangeOffset = SWAPW(fIdRangeOffset[index]);
    198             le_uint16 *glyphIndexTable = (le_uint16 *) ((char *) &fIdRangeOffset[index] + rangeOffset);
    199 
    200             result = SWAPW(glyphIndexTable[offset]);
    201         }
    202 
    203         result += SWAPW(fIdDelta[index]);
    204     } else {
    205         result = 0;
    206     }
    207 
    208     return LE_SET_GLYPH(0, result);
    209 }
    210 
    211 CMAPFormat4Mapper::~CMAPFormat4Mapper()
    212 {
    213     // parent destructor does it all
    214 }
    215 
    216 CMAPGroupMapper::CMAPGroupMapper(const CMAPTable *cmap, const CMAPGroup *groups, le_uint32 nGroups)
    217     : CMAPMapper(cmap), fGroups(groups)
    218 {
    219     le_uint8 bit = highBit(nGroups);
    220     fPower = 1 << bit;
    221     fRangeOffset = nGroups - fPower;
    222 }
    223 
    224 LEGlyphID CMAPGroupMapper::unicodeToGlyph(LEUnicode32 unicode32) const
    225 {
    226     le_int32 probe = fPower;
    227     le_int32 range = 0;
    228 
    229     if (SWAPU32(fGroups[fRangeOffset].startCharCode) <= unicode32) {
    230         range = fRangeOffset;
    231     }
    232 
    233     while (probe > (1 << 0)) {
    234         probe >>= 1;
    235 
    236         if (SWAPU32(fGroups[range + probe].startCharCode) <= unicode32) {
    237             range += probe;
    238         }
    239     }
    240 
    241     if (SWAPU32(fGroups[range].startCharCode) <= unicode32 && SWAPU32(fGroups[range].endCharCode) >= unicode32) {
    242         return (LEGlyphID) (SWAPU32(fGroups[range].startGlyphCode) + unicode32 - SWAPU32(fGroups[range].startCharCode));
    243     }
    244 
    245     return 0;
    246 }
    247 
    248 CMAPGroupMapper::~CMAPGroupMapper()
    249 {
    250     // parent destructor does it all
    251 }
    252 
    253