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