1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "ttgsubtable.h"
8
9 #include <memory>
10
11 #include "core/include/fxge/fx_freetype.h"
12 #include "core/include/fxge/fx_ge.h"
13 #include "third_party/base/stl_util.h"
14
CFX_GlyphMap()15 CFX_GlyphMap::CFX_GlyphMap() {}
~CFX_GlyphMap()16 CFX_GlyphMap::~CFX_GlyphMap() {}
17 extern "C" {
_CompareInt(const void * p1,const void * p2)18 static int _CompareInt(const void* p1, const void* p2) {
19 return (*(FX_DWORD*)p1) - (*(FX_DWORD*)p2);
20 }
21 };
22 struct _IntPair {
23 int32_t key;
24 int32_t value;
25 };
SetAt(int key,int value)26 void CFX_GlyphMap::SetAt(int key, int value) {
27 FX_DWORD count = m_Buffer.GetSize() / sizeof(_IntPair);
28 _IntPair* buf = (_IntPair*)m_Buffer.GetBuffer();
29 _IntPair pair = {key, value};
30 if (count == 0 || key > buf[count - 1].key) {
31 m_Buffer.AppendBlock(&pair, sizeof(_IntPair));
32 return;
33 }
34 int low = 0, high = count - 1;
35 while (low <= high) {
36 int mid = (low + high) / 2;
37 if (buf[mid].key < key) {
38 low = mid + 1;
39 } else if (buf[mid].key > key) {
40 high = mid - 1;
41 } else {
42 buf[mid].value = value;
43 return;
44 }
45 }
46 m_Buffer.InsertBlock(low * sizeof(_IntPair), &pair, sizeof(_IntPair));
47 }
Lookup(int key,int & value)48 FX_BOOL CFX_GlyphMap::Lookup(int key, int& value) {
49 void* pResult = FXSYS_bsearch(&key, m_Buffer.GetBuffer(),
50 m_Buffer.GetSize() / sizeof(_IntPair),
51 sizeof(_IntPair), _CompareInt);
52 if (!pResult) {
53 return FALSE;
54 }
55 value = ((FX_DWORD*)pResult)[1];
56 return TRUE;
57 }
LoadGSUBTable(FT_Bytes gsub)58 bool CFX_CTTGSUBTable::LoadGSUBTable(FT_Bytes gsub) {
59 header.Version = gsub[0] << 24 | gsub[1] << 16 | gsub[2] << 8 | gsub[3];
60 if (header.Version != 0x00010000) {
61 return false;
62 }
63 header.ScriptList = gsub[4] << 8 | gsub[5];
64 header.FeatureList = gsub[6] << 8 | gsub[7];
65 header.LookupList = gsub[8] << 8 | gsub[9];
66 return Parse(&gsub[header.ScriptList], &gsub[header.FeatureList],
67 &gsub[header.LookupList]);
68 }
GetVerticalGlyph(uint32_t glyphnum,uint32_t * vglyphnum)69 bool CFX_CTTGSUBTable::GetVerticalGlyph(uint32_t glyphnum,
70 uint32_t* vglyphnum) {
71 uint32_t tag[] = {
72 (uint8_t)'v' << 24 | (uint8_t)'r' << 16 | (uint8_t)'t' << 8 |
73 (uint8_t)'2',
74 (uint8_t)'v' << 24 | (uint8_t)'e' << 16 | (uint8_t)'r' << 8 |
75 (uint8_t)'t',
76 };
77 if (!m_bFeautureMapLoad) {
78 for (int i = 0; i < ScriptList.ScriptCount; i++) {
79 for (int j = 0; j < (ScriptList.ScriptRecord + i)->Script.LangSysCount;
80 ++j) {
81 for (int k = 0;
82 k < ((ScriptList.ScriptRecord + i)->Script.LangSysRecord + j)
83 ->LangSys.FeatureCount;
84 ++k) {
85 FX_DWORD index =
86 *(((ScriptList.ScriptRecord + i)->Script.LangSysRecord + j)
87 ->LangSys.FeatureIndex +
88 k);
89 if (FeatureList.FeatureRecord[index].FeatureTag == tag[0] ||
90 FeatureList.FeatureRecord[index].FeatureTag == tag[1]) {
91 if (!pdfium::ContainsKey(m_featureMap, index)) {
92 m_featureMap[index] = index;
93 }
94 }
95 }
96 }
97 }
98 if (m_featureMap.empty()) {
99 for (int i = 0; i < FeatureList.FeatureCount; i++) {
100 if (FeatureList.FeatureRecord[i].FeatureTag == tag[0] ||
101 FeatureList.FeatureRecord[i].FeatureTag == tag[1]) {
102 m_featureMap[i] = i;
103 }
104 }
105 }
106 m_bFeautureMapLoad = TRUE;
107 }
108 for (const auto& pair : m_featureMap) {
109 if (GetVerticalGlyphSub(glyphnum, vglyphnum,
110 &FeatureList.FeatureRecord[pair.second].Feature)) {
111 return true;
112 }
113 }
114 return false;
115 }
GetVerticalGlyphSub(uint32_t glyphnum,uint32_t * vglyphnum,struct TFeature * Feature)116 bool CFX_CTTGSUBTable::GetVerticalGlyphSub(uint32_t glyphnum,
117 uint32_t* vglyphnum,
118 struct TFeature* Feature) {
119 for (int i = 0; i < Feature->LookupCount; i++) {
120 int index = Feature->LookupListIndex[i];
121 if (index < 0 || LookupList.LookupCount < index) {
122 continue;
123 }
124 if (LookupList.Lookup[index].LookupType == 1) {
125 if (GetVerticalGlyphSub2(glyphnum, vglyphnum,
126 &LookupList.Lookup[index])) {
127 return true;
128 }
129 }
130 }
131 return false;
132 }
GetVerticalGlyphSub2(uint32_t glyphnum,uint32_t * vglyphnum,struct TLookup * Lookup)133 bool CFX_CTTGSUBTable::GetVerticalGlyphSub2(uint32_t glyphnum,
134 uint32_t* vglyphnum,
135 struct TLookup* Lookup) {
136 for (int i = 0; i < Lookup->SubTableCount; i++) {
137 switch (Lookup->SubTable[i]->SubstFormat) {
138 case 1: {
139 TSingleSubstFormat1* tbl1 = (TSingleSubstFormat1*)Lookup->SubTable[i];
140 if (GetCoverageIndex(tbl1->Coverage, glyphnum) >= 0) {
141 *vglyphnum = glyphnum + tbl1->DeltaGlyphID;
142 return true;
143 }
144 break;
145 }
146 case 2: {
147 TSingleSubstFormat2* tbl2 = (TSingleSubstFormat2*)Lookup->SubTable[i];
148 int index = -1;
149 index = GetCoverageIndex(tbl2->Coverage, glyphnum);
150 if (0 <= index && index < tbl2->GlyphCount) {
151 *vglyphnum = tbl2->Substitute[index];
152 return true;
153 }
154 break;
155 }
156 }
157 }
158 return false;
159 }
GetCoverageIndex(struct TCoverageFormatBase * Coverage,uint32_t g)160 int CFX_CTTGSUBTable::GetCoverageIndex(struct TCoverageFormatBase* Coverage,
161 uint32_t g) {
162 int i = 0;
163 if (!Coverage) {
164 return -1;
165 }
166 switch (Coverage->CoverageFormat) {
167 case 1: {
168 TCoverageFormat1* c1 = (TCoverageFormat1*)Coverage;
169 for (i = 0; i < c1->GlyphCount; i++) {
170 if ((uint32_t)c1->GlyphArray[i] == g) {
171 return i;
172 }
173 }
174 return -1;
175 }
176 case 2: {
177 TCoverageFormat2* c2 = (TCoverageFormat2*)Coverage;
178 for (i = 0; i < c2->RangeCount; i++) {
179 uint32_t s = c2->RangeRecord[i].Start;
180 uint32_t e = c2->RangeRecord[i].End;
181 uint32_t si = c2->RangeRecord[i].StartCoverageIndex;
182 if (s <= g && g <= e) {
183 return si + g - s;
184 }
185 }
186 return -1;
187 }
188 }
189 return -1;
190 }
Parse(FT_Bytes scriptlist,FT_Bytes featurelist,FT_Bytes lookuplist)191 bool CFX_CTTGSUBTable::Parse(FT_Bytes scriptlist,
192 FT_Bytes featurelist,
193 FT_Bytes lookuplist) {
194 ParseScriptList(scriptlist, &ScriptList);
195 ParseFeatureList(featurelist, &FeatureList);
196 ParseLookupList(lookuplist, &LookupList);
197 return true;
198 }
ParseScriptList(FT_Bytes raw,struct TScriptList * rec)199 void CFX_CTTGSUBTable::ParseScriptList(FT_Bytes raw, struct TScriptList* rec) {
200 int i;
201 FT_Bytes sp = raw;
202 rec->ScriptCount = GetUInt16(sp);
203 if (rec->ScriptCount <= 0) {
204 return;
205 }
206 rec->ScriptRecord = new struct TScriptRecord[rec->ScriptCount];
207 for (i = 0; i < rec->ScriptCount; i++) {
208 rec->ScriptRecord[i].ScriptTag = GetUInt32(sp);
209 uint16_t offset = GetUInt16(sp);
210 ParseScript(&raw[offset], &rec->ScriptRecord[i].Script);
211 }
212 }
ParseScript(FT_Bytes raw,struct TScript * rec)213 void CFX_CTTGSUBTable::ParseScript(FT_Bytes raw, struct TScript* rec) {
214 int i;
215 FT_Bytes sp = raw;
216 rec->DefaultLangSys = GetUInt16(sp);
217 rec->LangSysCount = GetUInt16(sp);
218 if (rec->LangSysCount <= 0) {
219 return;
220 }
221 rec->LangSysRecord = new struct TLangSysRecord[rec->LangSysCount];
222 for (i = 0; i < rec->LangSysCount; i++) {
223 rec->LangSysRecord[i].LangSysTag = GetUInt32(sp);
224 uint16_t offset = GetUInt16(sp);
225 ParseLangSys(&raw[offset], &rec->LangSysRecord[i].LangSys);
226 }
227 }
ParseLangSys(FT_Bytes raw,struct TLangSys * rec)228 void CFX_CTTGSUBTable::ParseLangSys(FT_Bytes raw, struct TLangSys* rec) {
229 FT_Bytes sp = raw;
230 rec->LookupOrder = GetUInt16(sp);
231 rec->ReqFeatureIndex = GetUInt16(sp);
232 rec->FeatureCount = GetUInt16(sp);
233 if (rec->FeatureCount <= 0) {
234 return;
235 }
236 rec->FeatureIndex = new uint16_t[rec->FeatureCount];
237 FXSYS_memset(rec->FeatureIndex, 0, sizeof(uint16_t) * rec->FeatureCount);
238 for (int i = 0; i < rec->FeatureCount; ++i) {
239 rec->FeatureIndex[i] = GetUInt16(sp);
240 }
241 }
ParseFeatureList(FT_Bytes raw,TFeatureList * rec)242 void CFX_CTTGSUBTable::ParseFeatureList(FT_Bytes raw, TFeatureList* rec) {
243 int i;
244 FT_Bytes sp = raw;
245 rec->FeatureCount = GetUInt16(sp);
246 if (rec->FeatureCount <= 0) {
247 return;
248 }
249 rec->FeatureRecord = new struct TFeatureRecord[rec->FeatureCount];
250 for (i = 0; i < rec->FeatureCount; i++) {
251 rec->FeatureRecord[i].FeatureTag = GetUInt32(sp);
252 uint16_t offset = GetUInt16(sp);
253 ParseFeature(&raw[offset], &rec->FeatureRecord[i].Feature);
254 }
255 }
ParseFeature(FT_Bytes raw,TFeature * rec)256 void CFX_CTTGSUBTable::ParseFeature(FT_Bytes raw, TFeature* rec) {
257 int i;
258 FT_Bytes sp = raw;
259 rec->FeatureParams = GetUInt16(sp);
260 rec->LookupCount = GetUInt16(sp);
261 if (rec->LookupCount <= 0) {
262 return;
263 }
264 rec->LookupListIndex = new uint16_t[rec->LookupCount];
265 for (i = 0; i < rec->LookupCount; i++) {
266 rec->LookupListIndex[i] = GetUInt16(sp);
267 }
268 }
ParseLookupList(FT_Bytes raw,TLookupList * rec)269 void CFX_CTTGSUBTable::ParseLookupList(FT_Bytes raw, TLookupList* rec) {
270 int i;
271 FT_Bytes sp = raw;
272 rec->LookupCount = GetUInt16(sp);
273 if (rec->LookupCount <= 0) {
274 return;
275 }
276 rec->Lookup = new struct TLookup[rec->LookupCount];
277 for (i = 0; i < rec->LookupCount; i++) {
278 uint16_t offset = GetUInt16(sp);
279 ParseLookup(&raw[offset], &rec->Lookup[i]);
280 }
281 }
ParseLookup(FT_Bytes raw,TLookup * rec)282 void CFX_CTTGSUBTable::ParseLookup(FT_Bytes raw, TLookup* rec) {
283 int i;
284 FT_Bytes sp = raw;
285 rec->LookupType = GetUInt16(sp);
286 rec->LookupFlag = GetUInt16(sp);
287 rec->SubTableCount = GetUInt16(sp);
288 if (rec->SubTableCount <= 0) {
289 return;
290 }
291 rec->SubTable = new struct TSubTableBase*[rec->SubTableCount];
292 for (i = 0; i < rec->SubTableCount; i++) {
293 rec->SubTable[i] = NULL;
294 }
295 if (rec->LookupType != 1) {
296 return;
297 }
298 for (i = 0; i < rec->SubTableCount; i++) {
299 uint16_t offset = GetUInt16(sp);
300 ParseSingleSubst(&raw[offset], &rec->SubTable[i]);
301 }
302 }
ParseCoverage(FT_Bytes raw,TCoverageFormatBase ** rec)303 void CFX_CTTGSUBTable::ParseCoverage(FT_Bytes raw, TCoverageFormatBase** rec) {
304 FT_Bytes sp = raw;
305 uint16_t Format = GetUInt16(sp);
306 switch (Format) {
307 case 1:
308 *rec = new TCoverageFormat1();
309 ParseCoverageFormat1(raw, (TCoverageFormat1*)*rec);
310 break;
311 case 2:
312 *rec = new TCoverageFormat2();
313 ParseCoverageFormat2(raw, (TCoverageFormat2*)*rec);
314 break;
315 }
316 }
ParseCoverageFormat1(FT_Bytes raw,TCoverageFormat1 * rec)317 void CFX_CTTGSUBTable::ParseCoverageFormat1(FT_Bytes raw,
318 TCoverageFormat1* rec) {
319 int i;
320 FT_Bytes sp = raw;
321 GetUInt16(sp);
322 rec->GlyphCount = GetUInt16(sp);
323 if (rec->GlyphCount <= 0) {
324 return;
325 }
326 rec->GlyphArray = new uint16_t[rec->GlyphCount];
327 for (i = 0; i < rec->GlyphCount; i++) {
328 rec->GlyphArray[i] = GetUInt16(sp);
329 }
330 }
ParseCoverageFormat2(FT_Bytes raw,TCoverageFormat2 * rec)331 void CFX_CTTGSUBTable::ParseCoverageFormat2(FT_Bytes raw,
332 TCoverageFormat2* rec) {
333 int i;
334 FT_Bytes sp = raw;
335 GetUInt16(sp);
336 rec->RangeCount = GetUInt16(sp);
337 if (rec->RangeCount <= 0) {
338 return;
339 }
340 rec->RangeRecord = new TRangeRecord[rec->RangeCount];
341 for (i = 0; i < rec->RangeCount; i++) {
342 rec->RangeRecord[i].Start = GetUInt16(sp);
343 rec->RangeRecord[i].End = GetUInt16(sp);
344 rec->RangeRecord[i].StartCoverageIndex = GetUInt16(sp);
345 }
346 }
ParseSingleSubst(FT_Bytes raw,TSubTableBase ** rec)347 void CFX_CTTGSUBTable::ParseSingleSubst(FT_Bytes raw, TSubTableBase** rec) {
348 FT_Bytes sp = raw;
349 uint16_t Format = GetUInt16(sp);
350 switch (Format) {
351 case 1:
352 *rec = new TSingleSubstFormat1();
353 ParseSingleSubstFormat1(raw, (TSingleSubstFormat1*)*rec);
354 break;
355 case 2:
356 *rec = new TSingleSubstFormat2();
357 ParseSingleSubstFormat2(raw, (TSingleSubstFormat2*)*rec);
358 break;
359 }
360 }
ParseSingleSubstFormat1(FT_Bytes raw,TSingleSubstFormat1 * rec)361 void CFX_CTTGSUBTable::ParseSingleSubstFormat1(FT_Bytes raw,
362 TSingleSubstFormat1* rec) {
363 FT_Bytes sp = raw;
364 GetUInt16(sp);
365 uint16_t offset = GetUInt16(sp);
366 ParseCoverage(&raw[offset], &rec->Coverage);
367 rec->DeltaGlyphID = GetInt16(sp);
368 }
ParseSingleSubstFormat2(FT_Bytes raw,TSingleSubstFormat2 * rec)369 void CFX_CTTGSUBTable::ParseSingleSubstFormat2(FT_Bytes raw,
370 TSingleSubstFormat2* rec) {
371 int i;
372 FT_Bytes sp = raw;
373 GetUInt16(sp);
374 uint16_t offset = GetUInt16(sp);
375 ParseCoverage(&raw[offset], &rec->Coverage);
376 rec->GlyphCount = GetUInt16(sp);
377 if (rec->GlyphCount <= 0) {
378 return;
379 }
380 rec->Substitute = new uint16_t[rec->GlyphCount];
381 for (i = 0; i < rec->GlyphCount; i++) {
382 rec->Substitute[i] = GetUInt16(sp);
383 }
384 }
GetVerticalGlyph(FX_DWORD glyphnum,FX_DWORD * vglyphnum)385 FX_BOOL CFX_GSUBTable::GetVerticalGlyph(FX_DWORD glyphnum,
386 FX_DWORD* vglyphnum) {
387 return m_GsubImp.GetVerticalGlyph(glyphnum, vglyphnum);
388 }
389 // static
Create(CFX_Font * pFont)390 IFX_GSUBTable* IFX_GSUBTable::Create(CFX_Font* pFont) {
391 if (!pFont) {
392 return NULL;
393 }
394 if (!pFont->GetSubData()) {
395 unsigned long length = 0;
396 int error = FXFT_Load_Sfnt_Table(
397 pFont->GetFace(), FT_MAKE_TAG('G', 'S', 'U', 'B'), 0, NULL, &length);
398 if (!error) {
399 pFont->SetSubData(FX_Alloc(uint8_t, length));
400 }
401 if (!pFont->GetSubData()) {
402 return NULL;
403 }
404 }
405 int error =
406 FXFT_Load_Sfnt_Table(pFont->GetFace(), FT_MAKE_TAG('G', 'S', 'U', 'B'), 0,
407 pFont->GetSubData(), NULL);
408 if (!error && pFont->GetSubData()) {
409 std::unique_ptr<CFX_GSUBTable> pGsubTable(new CFX_GSUBTable);
410 if (pGsubTable->m_GsubImp.LoadGSUBTable((FT_Bytes)pFont->GetSubData())) {
411 return pGsubTable.release();
412 }
413 }
414 return NULL;
415 }
416