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