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