1/* 2 ****************************************************************************** * 3 * 4 * Copyright (C) 1999-2003, International Business Machines 5 * Corporation and others. All Rights Reserved. 6 * 7 ****************************************************************************** * 8 * file name: cmaps.cpp 9 * 10 * created on: ??/??/2001 11 * created by: Eric R. Mader 12 */ 13 14#include "layout/LETypes.h" 15#include "layout/LESwaps.h" 16 17#include "sfnt.h" 18#include "cmaps.h" 19 20#define SWAPU16(code) ((LEUnicode16) SWAPW(code)) 21#define SWAPU32(code) ((LEUnicode32) SWAPL(code)) 22 23// 24// Finds the high bit by binary searching 25// through the bits in value. 26// 27le_uint8 highBit(le_uint32 value) 28{ 29 le_uint8 bit = 0; 30 31 if (value >= 1 << 16) { 32 value >>= 16; 33 bit += 16; 34 } 35 36 if (value >= 1 << 8) { 37 value >>= 8; 38 bit += 8; 39 } 40 41 if (value >= 1 << 4) { 42 value >>= 4; 43 bit += 4; 44 } 45 46 if (value >= 1 << 2) { 47 value >>= 2; 48 bit += 2; 49 } 50 51 if (value >= 1 << 1) { 52 value >>= 1; 53 bit += 1; 54 } 55 56 return bit; 57} 58 59CMAPMapper *CMAPMapper::createUnicodeMapper(const CMAPTable *cmap) 60{ 61 le_uint16 i; 62 le_uint16 nSubtables = SWAPW(cmap->numberSubtables); 63 const CMAPEncodingSubtable *subtable = NULL; 64 le_uint32 offset1 = 0, offset10 = 0; 65 66 for (i = 0; i < nSubtables; i += 1) { 67 const CMAPEncodingSubtableHeader *esh = &cmap->encodingSubtableHeaders[i]; 68 69 if (SWAPW(esh->platformID) == 3) { 70 switch (SWAPW(esh->platformSpecificID)) { 71 case 1: 72 offset1 = SWAPL(esh->encodingOffset); 73 break; 74 75 case 10: 76 offset10 = SWAPL(esh->encodingOffset); 77 break; 78 } 79 } 80 } 81 82 83 if (offset10 != 0) 84 { 85 subtable = (const CMAPEncodingSubtable *) ((const char *) cmap + offset10); 86 } else if (offset1 != 0) { 87 subtable = (const CMAPEncodingSubtable *) ((const char *) cmap + offset1); 88 } else { 89 return NULL; 90 } 91 92 switch (SWAPW(subtable->format)) { 93 case 4: 94 return new CMAPFormat4Mapper(cmap, (const CMAPFormat4Encoding *) subtable); 95 96 case 12: 97 { 98 const CMAPFormat12Encoding *encoding = (const CMAPFormat12Encoding *) subtable; 99 100 return new CMAPGroupMapper(cmap, encoding->groups, SWAPL(encoding->nGroups)); 101 } 102 103 default: 104 break; 105 } 106 107 return NULL; 108} 109 110CMAPFormat4Mapper::CMAPFormat4Mapper(const CMAPTable *cmap, const CMAPFormat4Encoding *header) 111 : CMAPMapper(cmap) 112{ 113 le_uint16 segCount = SWAPW(header->segCountX2) / 2; 114 115 fEntrySelector = SWAPW(header->entrySelector); 116 fRangeShift = SWAPW(header->rangeShift) / 2; 117 fEndCodes = &header->endCodes[0]; 118 fStartCodes = &header->endCodes[segCount + 1]; // + 1 for reservedPad... 119 fIdDelta = &fStartCodes[segCount]; 120 fIdRangeOffset = &fIdDelta[segCount]; 121} 122 123LEGlyphID CMAPFormat4Mapper::unicodeToGlyph(LEUnicode32 unicode32) const 124{ 125 if (unicode32 >= 0x10000) { 126 return 0; 127 } 128 129 LEUnicode16 unicode = (LEUnicode16) unicode32; 130 le_uint16 index = 0; 131 le_uint16 probe = 1 << fEntrySelector; 132 TTGlyphID result = 0; 133 134 if (SWAPU16(fStartCodes[fRangeShift]) <= unicode) { 135 index = fRangeShift; 136 } 137 138 while (probe > (1 << 0)) { 139 probe >>= 1; 140 141 if (SWAPU16(fStartCodes[index + probe]) <= unicode) { 142 index += probe; 143 } 144 } 145 146 if (unicode >= SWAPU16(fStartCodes[index]) && unicode <= SWAPU16(fEndCodes[index])) { 147 if (fIdRangeOffset[index] == 0) { 148 result = (TTGlyphID) unicode; 149 } else { 150 le_uint16 offset = unicode - SWAPU16(fStartCodes[index]); 151 le_uint16 rangeOffset = SWAPW(fIdRangeOffset[index]); 152 le_uint16 *glyphIndexTable = (le_uint16 *) ((char *) &fIdRangeOffset[index] + rangeOffset); 153 154 result = SWAPW(glyphIndexTable[offset]); 155 } 156 157 result += SWAPW(fIdDelta[index]); 158 } else { 159 result = 0; 160 } 161 162 return LE_SET_GLYPH(0, result); 163} 164 165CMAPFormat4Mapper::~CMAPFormat4Mapper() 166{ 167 // parent destructor does it all 168} 169 170CMAPGroupMapper::CMAPGroupMapper(const CMAPTable *cmap, const CMAPGroup *groups, le_uint32 nGroups) 171 : CMAPMapper(cmap), fGroups(groups) 172{ 173 le_uint8 bit = highBit(nGroups); 174 fPower = 1 << bit; 175 fRangeOffset = nGroups - fPower; 176} 177 178LEGlyphID CMAPGroupMapper::unicodeToGlyph(LEUnicode32 unicode32) const 179{ 180 le_int32 probe = fPower; 181 le_int32 range = 0; 182 183 if (SWAPU32(fGroups[fRangeOffset].startCharCode) <= unicode32) { 184 range = fRangeOffset; 185 } 186 187 while (probe > (1 << 0)) { 188 probe >>= 1; 189 190 if (SWAPU32(fGroups[range + probe].startCharCode) <= unicode32) { 191 range += probe; 192 } 193 } 194 195 if (SWAPU32(fGroups[range].startCharCode) <= unicode32 && SWAPU32(fGroups[range].endCharCode) >= unicode32) { 196 return (LEGlyphID) (SWAPU32(fGroups[range].startGlyphCode) + unicode32 - SWAPU32(fGroups[range].startCharCode)); 197 } 198 199 return 0; 200} 201 202CMAPGroupMapper::~CMAPGroupMapper() 203{ 204 // parent destructor does it all 205} 206 207