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