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