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