Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
cfx_cttgsubtable.cpp
Go to the documentation of this file.
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
18namespace {
19
20bool 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
30CFX_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
57
58bool 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
73uint32_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
83absl::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
101absl::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
124int 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
154uint8_t CFX_CTTGSUBTable::GetUInt8(const uint8_t*& p) const {
155 uint8_t ret = p[0];
156 p += 1;
157 return ret;
158}
159
160int16_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
166uint16_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
172int32_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
178uint32_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
184void 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
192void 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
202CFX_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
215CFX_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
226void 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
236DataVector<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
247void 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
255CFX_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
272CFX_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
297CFX_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
320CFX_CTTGSUBTable::FeatureRecord::FeatureRecord() = default;
321
322CFX_CTTGSUBTable::FeatureRecord::~FeatureRecord() = default;
323
324CFX_CTTGSUBTable::RangeRecord::RangeRecord() = default;
325
326CFX_CTTGSUBTable::SubTable::SubTable() = default;
327
328CFX_CTTGSUBTable::SubTable::SubTable(SubTable&& that) noexcept = default;
329
330CFX_CTTGSUBTable::SubTable& CFX_CTTGSUBTable::SubTable::operator=(
331 SubTable&& that) noexcept = default;
332
333CFX_CTTGSUBTable::SubTable::~SubTable() = default;
334
335CFX_CTTGSUBTable::Lookup::Lookup() = default;
336
337CFX_CTTGSUBTable::Lookup::Lookup(Lookup&& that) noexcept = default;
338
339CFX_CTTGSUBTable::Lookup& CFX_CTTGSUBTable::Lookup::operator=(
340 Lookup&& that) noexcept = default;
341
342CFX_CTTGSUBTable::Lookup::~Lookup() = default;
uint32_t GetVerticalGlyph(uint32_t glyphnum) const
CFX_CTTGSUBTable(pdfium::span< const uint8_t > gsub)
static constexpr uint32_t MakeTag(char c1, char c2, char c3, char c4)