d03ee710f0fef3283465faa802f7794b8b67b032
[platform/upstream/harfbuzz.git] / src / hb-icu-le / cmaps.cpp
1 /***************************************************************************
2 *
3 *   Copyright (C) 1998-2003, International Business Machines
4 *   Corporation and others.  All Rights Reserved.
5 *
6 ************************************************************************/
7
8 #include "layout/LETypes.h"
9 #include "layout/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 //
21 static inline 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
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
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
117 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
159 CMAPFormat4Mapper::~CMAPFormat4Mapper()
160 {
161     // parent destructor does it all
162 }
163
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
172 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
196 CMAPGroupMapper::~CMAPGroupMapper()
197 {
198     // parent destructor does it all
199 }
200