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