xref: /aosp_15_r20/external/pdfium/core/fpdfapi/font/cfx_cttgsubtable.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1 // Copyright 2014 The PDFium Authors
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/cfx_cttgsubtable.h"
8 
9 #include <stdint.h>
10 
11 #include <utility>
12 
13 #include "core/fxcrt/data_vector.h"
14 #include "core/fxcrt/fx_system.h"
15 #include "core/fxcrt/stl_util.h"
16 #include "core/fxge/cfx_fontmapper.h"
17 
18 namespace {
19 
IsVerticalFeatureTag(uint32_t tag)20 bool IsVerticalFeatureTag(uint32_t tag) {
21   static constexpr uint32_t kTags[] = {
22       CFX_FontMapper::MakeTag('v', 'r', 't', '2'),
23       CFX_FontMapper::MakeTag('v', 'e', 'r', 't'),
24   };
25   return tag == kTags[0] || tag == kTags[1];
26 }
27 
28 }  // namespace
29 
CFX_CTTGSUBTable(pdfium::span<const uint8_t> gsub)30 CFX_CTTGSUBTable::CFX_CTTGSUBTable(pdfium::span<const uint8_t> gsub) {
31   if (!LoadGSUBTable(gsub))
32     return;
33 
34   for (const auto& script : script_list_) {
35     for (const auto& record : script) {
36       for (uint16_t index : record) {
37         if (IsVerticalFeatureTag(feature_list_[index].feature_tag)) {
38           feature_set_.insert(index);
39         }
40       }
41     }
42   }
43   if (!feature_set_.empty()) {
44     return;
45   }
46 
47   int i = 0;
48   for (const FeatureRecord& feature : feature_list_) {
49     if (IsVerticalFeatureTag(feature.feature_tag)) {
50       feature_set_.insert(i);
51     }
52     ++i;
53   }
54 }
55 
56 CFX_CTTGSUBTable::~CFX_CTTGSUBTable() = default;
57 
LoadGSUBTable(pdfium::span<const uint8_t> gsub)58 bool CFX_CTTGSUBTable::LoadGSUBTable(pdfium::span<const uint8_t> gsub) {
59   if (FXSYS_UINT32_GET_MSBFIRST(gsub) != 0x00010000)
60     return false;
61 
62   auto scriptlist_span = gsub.subspan(4, 2);
63   auto featurelist_span = gsub.subspan(6, 2);
64   auto lookuplist_span = gsub.subspan(8, 2);
65   size_t scriptlist_index = FXSYS_UINT16_GET_MSBFIRST(scriptlist_span);
66   size_t featurelist_index = FXSYS_UINT16_GET_MSBFIRST(featurelist_span);
67   size_t lookuplist_index = FXSYS_UINT16_GET_MSBFIRST(lookuplist_span);
68   Parse(gsub.subspan(scriptlist_index), gsub.subspan(featurelist_index),
69         gsub.subspan(lookuplist_index));
70   return true;
71 }
72 
GetVerticalGlyph(uint32_t glyphnum) const73 uint32_t CFX_CTTGSUBTable::GetVerticalGlyph(uint32_t glyphnum) const {
74   for (uint32_t item : feature_set_) {
75     absl::optional<uint32_t> result =
76         GetVerticalGlyphSub(feature_list_[item], glyphnum);
77     if (result.has_value())
78       return result.value();
79   }
80   return 0;
81 }
82 
GetVerticalGlyphSub(const FeatureRecord & feature,uint32_t glyphnum) const83 absl::optional<uint32_t> CFX_CTTGSUBTable::GetVerticalGlyphSub(
84     const FeatureRecord& feature,
85     uint32_t glyphnum) const {
86   for (int index : feature.lookup_list_indices) {
87     if (!fxcrt::IndexInBounds(lookup_list_, index)) {
88       continue;
89     }
90     if (lookup_list_[index].lookup_type != 1) {
91       continue;
92     }
93     absl::optional<uint32_t> result =
94         GetVerticalGlyphSub2(lookup_list_[index], glyphnum);
95     if (result.has_value())
96       return result.value();
97   }
98   return absl::nullopt;
99 }
100 
GetVerticalGlyphSub2(const Lookup & lookup,uint32_t glyphnum) const101 absl::optional<uint32_t> CFX_CTTGSUBTable::GetVerticalGlyphSub2(
102     const Lookup& lookup,
103     uint32_t glyphnum) const {
104   for (const auto& sub_table : lookup.sub_tables) {
105     if (absl::holds_alternative<absl::monostate>(sub_table.table_data)) {
106       continue;
107     }
108     int index = GetCoverageIndex(sub_table.coverage, glyphnum);
109     if (absl::holds_alternative<int16_t>(sub_table.table_data)) {
110       if (index >= 0) {
111         return glyphnum + absl::get<int16_t>(sub_table.table_data);
112       }
113     } else {
114       const auto& substitutes =
115           absl::get<DataVector<uint16_t>>(sub_table.table_data);
116       if (fxcrt::IndexInBounds(substitutes, index)) {
117         return substitutes[index];
118       }
119     }
120   }
121   return absl::nullopt;
122 }
123 
GetCoverageIndex(const CoverageFormat & coverage,uint32_t g) const124 int CFX_CTTGSUBTable::GetCoverageIndex(const CoverageFormat& coverage,
125                                        uint32_t g) const {
126   if (absl::holds_alternative<absl::monostate>(coverage)) {
127     return -1;
128   }
129 
130   if (absl::holds_alternative<DataVector<uint16_t>>(coverage)) {
131     int i = 0;
132     const auto& glyph_array = absl::get<DataVector<uint16_t>>(coverage);
133     for (const auto& glyph : glyph_array) {
134       if (static_cast<uint32_t>(glyph) == g) {
135         return i;
136       }
137       ++i;
138     }
139     return -1;
140   }
141 
142   const auto& range_records = absl::get<std::vector<RangeRecord>>(coverage);
143   for (const auto& range_rec : range_records) {
144     uint32_t s = range_rec.start;
145     uint32_t e = range_rec.end;
146     uint32_t si = range_rec.start_coverage_index;
147     if (s <= g && g <= e) {
148       return si + g - s;
149     }
150   }
151   return -1;
152 }
153 
GetUInt8(const uint8_t * & p) const154 uint8_t CFX_CTTGSUBTable::GetUInt8(const uint8_t*& p) const {
155   uint8_t ret = p[0];
156   p += 1;
157   return ret;
158 }
159 
GetInt16(const uint8_t * & p) const160 int16_t CFX_CTTGSUBTable::GetInt16(const uint8_t*& p) const {
161   uint16_t ret = FXSYS_UINT16_GET_MSBFIRST(p);
162   p += 2;
163   return *reinterpret_cast<int16_t*>(&ret);
164 }
165 
GetUInt16(const uint8_t * & p) const166 uint16_t CFX_CTTGSUBTable::GetUInt16(const uint8_t*& p) const {
167   uint16_t ret = FXSYS_UINT16_GET_MSBFIRST(p);
168   p += 2;
169   return ret;
170 }
171 
GetInt32(const uint8_t * & p) const172 int32_t CFX_CTTGSUBTable::GetInt32(const uint8_t*& p) const {
173   uint32_t ret = FXSYS_UINT32_GET_MSBFIRST(p);
174   p += 4;
175   return *reinterpret_cast<int32_t*>(&ret);
176 }
177 
GetUInt32(const uint8_t * & p) const178 uint32_t CFX_CTTGSUBTable::GetUInt32(const uint8_t*& p) const {
179   uint32_t ret = FXSYS_UINT32_GET_MSBFIRST(p);
180   p += 4;
181   return ret;
182 }
183 
Parse(pdfium::span<const uint8_t> scriptlist,pdfium::span<const uint8_t> featurelist,pdfium::span<const uint8_t> lookuplist)184 void CFX_CTTGSUBTable::Parse(pdfium::span<const uint8_t> scriptlist,
185                              pdfium::span<const uint8_t> featurelist,
186                              pdfium::span<const uint8_t> lookuplist) {
187   ParseScriptList(scriptlist);
188   ParseFeatureList(featurelist);
189   ParseLookupList(lookuplist);
190 }
191 
ParseScriptList(pdfium::span<const uint8_t> raw)192 void CFX_CTTGSUBTable::ParseScriptList(pdfium::span<const uint8_t> raw) {
193   const uint8_t* sp = raw.data();
194   script_list_ = std::vector<ScriptRecord>(GetUInt16(sp));
195   for (auto& script : script_list_) {
196     // Skip over "ScriptTag" field.
197     sp += 4;
198     script = ParseScript(&raw[GetUInt16(sp)]);
199   }
200 }
201 
ParseScript(const uint8_t * raw)202 CFX_CTTGSUBTable::ScriptRecord CFX_CTTGSUBTable::ParseScript(
203     const uint8_t* raw) {
204   // Skip over "DefaultLangSys" field.
205   const uint8_t* sp = raw + 2;
206   ScriptRecord result(GetUInt16(sp));
207   for (auto& record : result) {
208     // Skip over "LangSysTag" field.
209     sp += 4;
210     record = ParseLangSys(&raw[GetUInt16(sp)]);
211   }
212   return result;
213 }
214 
ParseLangSys(const uint8_t * raw)215 CFX_CTTGSUBTable::FeatureIndices CFX_CTTGSUBTable::ParseLangSys(
216     const uint8_t* raw) {
217   // Skip over "LookupOrder" and "ReqFeatureIndex" fields.
218   const uint8_t* sp = raw + 4;
219   FeatureIndices result(GetUInt16(sp));
220   for (auto& element : result) {
221     element = GetUInt16(sp);
222   }
223   return result;
224 }
225 
ParseFeatureList(pdfium::span<const uint8_t> raw)226 void CFX_CTTGSUBTable::ParseFeatureList(pdfium::span<const uint8_t> raw) {
227   const uint8_t* sp = raw.data();
228   feature_list_ = std::vector<FeatureRecord>(GetUInt16(sp));
229   for (auto& record : feature_list_) {
230     record.feature_tag = GetUInt32(sp);
231     record.lookup_list_indices =
232         ParseFeatureLookupListIndices(&raw[GetUInt16(sp)]);
233   }
234 }
235 
ParseFeatureLookupListIndices(const uint8_t * raw)236 DataVector<uint16_t> CFX_CTTGSUBTable::ParseFeatureLookupListIndices(
237     const uint8_t* raw) {
238   // Skip over "FeatureParams" field.
239   const uint8_t* sp = raw + 2;
240   DataVector<uint16_t> result(GetUInt16(sp));
241   for (auto& index : result) {
242     index = GetUInt16(sp);
243   }
244   return result;
245 }
246 
ParseLookupList(pdfium::span<const uint8_t> raw)247 void CFX_CTTGSUBTable::ParseLookupList(pdfium::span<const uint8_t> raw) {
248   const uint8_t* sp = raw.data();
249   lookup_list_ = std::vector<Lookup>(GetUInt16(sp));
250   for (auto& lookup : lookup_list_) {
251     lookup = ParseLookup(&raw[GetUInt16(sp)]);
252   }
253 }
254 
ParseLookup(const uint8_t * raw)255 CFX_CTTGSUBTable::Lookup CFX_CTTGSUBTable::ParseLookup(const uint8_t* raw) {
256   const uint8_t* sp = raw;
257   CFX_CTTGSUBTable::Lookup result;
258   result.lookup_type = GetUInt16(sp);
259   // Skip over "LookupFlag" field.
260   sp += 2;
261   result.sub_tables = Lookup::SubTables(GetUInt16(sp));
262   if (result.lookup_type != 1) {
263     return result;
264   }
265 
266   for (auto& sub_table : result.sub_tables) {
267     sub_table = ParseSingleSubst(&raw[GetUInt16(sp)]);
268   }
269   return result;
270 }
271 
ParseCoverage(const uint8_t * raw)272 CFX_CTTGSUBTable::CoverageFormat CFX_CTTGSUBTable::ParseCoverage(
273     const uint8_t* raw) {
274   const uint8_t* sp = raw;
275   uint16_t format = GetUInt16(sp);
276   if (format != 1 && format != 2) {
277     return absl::monostate();
278   }
279 
280   if (format == 1) {
281     DataVector<uint16_t> glyph_array(GetUInt16(sp));
282     for (auto& glyph : glyph_array) {
283       glyph = GetUInt16(sp);
284     }
285     return glyph_array;
286   }
287 
288   std::vector<RangeRecord> range_records(GetUInt16(sp));
289   for (auto& range_rec : range_records) {
290     range_rec.start = GetUInt16(sp);
291     range_rec.end = GetUInt16(sp);
292     range_rec.start_coverage_index = GetUInt16(sp);
293   }
294   return range_records;
295 }
296 
ParseSingleSubst(const uint8_t * raw)297 CFX_CTTGSUBTable::SubTable CFX_CTTGSUBTable::ParseSingleSubst(
298     const uint8_t* raw) {
299   const uint8_t* sp = raw;
300   uint16_t format = GetUInt16(sp);
301   SubTable rec;
302   if (format != 1 && format != 2) {
303     return rec;
304   }
305 
306   uint16_t offset = GetUInt16(sp);
307   rec.coverage = ParseCoverage(&raw[offset]);
308   if (format == 1) {
309     rec.table_data = GetInt16(sp);
310   } else {
311     DataVector<uint16_t> table_data(GetUInt16(sp));
312     for (auto& substitute : table_data) {
313       substitute = GetUInt16(sp);
314     }
315     rec.table_data = std::move(table_data);
316   }
317   return rec;
318 }
319 
320 CFX_CTTGSUBTable::FeatureRecord::FeatureRecord() = default;
321 
322 CFX_CTTGSUBTable::FeatureRecord::~FeatureRecord() = default;
323 
324 CFX_CTTGSUBTable::RangeRecord::RangeRecord() = default;
325 
326 CFX_CTTGSUBTable::SubTable::SubTable() = default;
327 
328 CFX_CTTGSUBTable::SubTable::SubTable(SubTable&& that) noexcept = default;
329 
330 CFX_CTTGSUBTable::SubTable& CFX_CTTGSUBTable::SubTable::operator=(
331     SubTable&& that) noexcept = default;
332 
333 CFX_CTTGSUBTable::SubTable::~SubTable() = default;
334 
335 CFX_CTTGSUBTable::Lookup::Lookup() = default;
336 
337 CFX_CTTGSUBTable::Lookup::Lookup(Lookup&& that) noexcept = default;
338 
339 CFX_CTTGSUBTable::Lookup& CFX_CTTGSUBTable::Lookup::operator=(
340     Lookup&& that) noexcept = default;
341 
342 CFX_CTTGSUBTable::Lookup::~Lookup() = default;
343