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