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