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