1 // Copyright 2017 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 #include <map>
6 #include <memory>
7 #include <sstream>
8 #include <utility>
9 #include <vector>
10
11 #include "core/fpdfapi/font/cpdf_cidfont.h"
12 #include "core/fpdfapi/font/cpdf_font.h"
13 #include "core/fpdfapi/page/cpdf_docpagedata.h"
14 #include "core/fpdfapi/page/cpdf_textobject.h"
15 #include "core/fpdfapi/page/cpdf_textstate.h"
16 #include "core/fpdfapi/parser/cpdf_array.h"
17 #include "core/fpdfapi/parser/cpdf_dictionary.h"
18 #include "core/fpdfapi/parser/cpdf_document.h"
19 #include "core/fpdfapi/parser/cpdf_name.h"
20 #include "core/fpdfapi/parser/cpdf_number.h"
21 #include "core/fpdfapi/parser/cpdf_reference.h"
22 #include "core/fpdfapi/parser/cpdf_stream.h"
23 #include "core/fpdfapi/parser/cpdf_string.h"
24 #include "core/fpdfapi/render/charposlist.h"
25 #include "core/fpdfapi/render/cpdf_pagerendercontext.h"
26 #include "core/fpdfapi/render/cpdf_rendercontext.h"
27 #include "core/fpdfapi/render/cpdf_renderstatus.h"
28 #include "core/fpdfapi/render/cpdf_textrenderer.h"
29 #include "core/fpdftext/cpdf_textpage.h"
30 #include "core/fxcrt/check.h"
31 #include "core/fxcrt/check_op.h"
32 #include "core/fxcrt/compiler_specific.h"
33 #include "core/fxcrt/containers/contains.h"
34 #include "core/fxcrt/fx_extension.h"
35 #include "core/fxcrt/fx_memcpy_wrappers.h"
36 #include "core/fxcrt/fx_string_wrappers.h"
37 #include "core/fxcrt/numerics/safe_conversions.h"
38 #include "core/fxcrt/span_util.h"
39 #include "core/fxcrt/stl_util.h"
40 #include "core/fxcrt/utf16.h"
41 #include "core/fxge/cfx_defaultrenderdevice.h"
42 #include "core/fxge/cfx_fontmgr.h"
43 #include "core/fxge/dib/cfx_dibitmap.h"
44 #include "core/fxge/fx_font.h"
45 #include "core/fxge/text_char_pos.h"
46 #include "fpdfsdk/cpdfsdk_helpers.h"
47 #include "public/fpdf_edit.h"
48
49 // These checks are here because core/ and public/ cannot depend on each other.
50 static_assert(static_cast<int>(TextRenderingMode::MODE_UNKNOWN) ==
51 FPDF_TEXTRENDERMODE_UNKNOWN,
52 "TextRenderingMode::MODE_UNKNOWN value mismatch");
53 static_assert(static_cast<int>(TextRenderingMode::MODE_FILL) ==
54 FPDF_TEXTRENDERMODE_FILL,
55 "TextRenderingMode::MODE_FILL value mismatch");
56 static_assert(static_cast<int>(TextRenderingMode::MODE_STROKE) ==
57 FPDF_TEXTRENDERMODE_STROKE,
58 "TextRenderingMode::MODE_STROKE value mismatch");
59 static_assert(static_cast<int>(TextRenderingMode::MODE_FILL_STROKE) ==
60 FPDF_TEXTRENDERMODE_FILL_STROKE,
61 "TextRenderingMode::MODE_FILL_STROKE value mismatch");
62 static_assert(static_cast<int>(TextRenderingMode::MODE_INVISIBLE) ==
63 FPDF_TEXTRENDERMODE_INVISIBLE,
64 "TextRenderingMode::MODE_INVISIBLE value mismatch");
65 static_assert(static_cast<int>(TextRenderingMode::MODE_FILL_CLIP) ==
66 FPDF_TEXTRENDERMODE_FILL_CLIP,
67 "TextRenderingMode::MODE_FILL_CLIP value mismatch");
68 static_assert(static_cast<int>(TextRenderingMode::MODE_STROKE_CLIP) ==
69 FPDF_TEXTRENDERMODE_STROKE_CLIP,
70 "TextRenderingMode::MODE_STROKE_CLIP value mismatch");
71 static_assert(static_cast<int>(TextRenderingMode::MODE_FILL_STROKE_CLIP) ==
72 FPDF_TEXTRENDERMODE_FILL_STROKE_CLIP,
73 "TextRenderingMode::MODE_FILL_STROKE_CLIP value mismatch");
74 static_assert(static_cast<int>(TextRenderingMode::MODE_CLIP) ==
75 FPDF_TEXTRENDERMODE_CLIP,
76 "TextRenderingMode::MODE_CLIP value mismatch");
77 static_assert(static_cast<int>(TextRenderingMode::MODE_LAST) ==
78 FPDF_TEXTRENDERMODE_LAST,
79 "TextRenderingMode::MODE_LAST value mismatch");
80
81 namespace {
82
BaseFontNameForType(const CFX_Font * font,int font_type)83 ByteString BaseFontNameForType(const CFX_Font* font, int font_type) {
84 ByteString name = font_type == FPDF_FONT_TYPE1 ? font->GetPsName()
85 : font->GetBaseFontName();
86 return name.IsEmpty() ? CFX_Font::kUntitledFontName : name;
87 }
88
CreateCompositeFontDict(CPDF_Document * doc,const CFX_Font * font,int font_type,const ByteString & name)89 RetainPtr<CPDF_Dictionary> CreateCompositeFontDict(CPDF_Document* doc,
90 const CFX_Font* font,
91 int font_type,
92 const ByteString& name) {
93 auto font_dict = doc->NewIndirect<CPDF_Dictionary>();
94 font_dict->SetNewFor<CPDF_Name>("Type", "Font");
95 font_dict->SetNewFor<CPDF_Name>("Subtype", "Type0");
96 // TODO(npm): Get the correct encoding, if it's not identity.
97 ByteString encoding = "Identity-H";
98 font_dict->SetNewFor<CPDF_Name>("Encoding", encoding);
99 font_dict->SetNewFor<CPDF_Name>(
100 "BaseFont", font_type == FPDF_FONT_TYPE1 ? name + "-" + encoding : name);
101 return font_dict;
102 }
103
CreateCidFontDict(CPDF_Document * doc,int font_type,const ByteString & name)104 RetainPtr<CPDF_Dictionary> CreateCidFontDict(CPDF_Document* doc,
105 int font_type,
106 const ByteString& name) {
107 auto cid_font_dict = doc->NewIndirect<CPDF_Dictionary>();
108 cid_font_dict->SetNewFor<CPDF_Name>("Type", "Font");
109 cid_font_dict->SetNewFor<CPDF_Name>("Subtype", font_type == FPDF_FONT_TYPE1
110 ? "CIDFontType0"
111 : "CIDFontType2");
112 cid_font_dict->SetNewFor<CPDF_Name>("BaseFont", name);
113
114 // TODO(npm): Maybe use FT_Get_CID_Registry_Ordering_Supplement to get the
115 // CIDSystemInfo
116 auto cid_system_info_dict = doc->NewIndirect<CPDF_Dictionary>();
117 cid_system_info_dict->SetNewFor<CPDF_String>("Registry", "Adobe");
118 cid_system_info_dict->SetNewFor<CPDF_String>("Ordering", "Identity");
119 cid_system_info_dict->SetNewFor<CPDF_Number>("Supplement", 0);
120 cid_font_dict->SetNewFor<CPDF_Reference>("CIDSystemInfo", doc,
121 cid_system_info_dict->GetObjNum());
122 return cid_font_dict;
123 }
124
LoadFontDesc(CPDF_Document * doc,const ByteString & font_name,CFX_Font * font,pdfium::span<const uint8_t> font_data,int font_type)125 RetainPtr<CPDF_Dictionary> LoadFontDesc(CPDF_Document* doc,
126 const ByteString& font_name,
127 CFX_Font* font,
128 pdfium::span<const uint8_t> font_data,
129 int font_type) {
130 auto font_descriptor_dict = doc->NewIndirect<CPDF_Dictionary>();
131 font_descriptor_dict->SetNewFor<CPDF_Name>("Type", "FontDescriptor");
132 font_descriptor_dict->SetNewFor<CPDF_Name>("FontName", font_name);
133 int flags = 0;
134 if (font->GetFace()->IsFixedWidth()) {
135 flags |= FXFONT_FIXED_PITCH;
136 }
137 if (font_name.Contains("Serif"))
138 flags |= FXFONT_SERIF;
139 if (font->GetFace()->IsItalic()) {
140 flags |= FXFONT_ITALIC;
141 }
142 if (font->GetFace()->IsBold()) {
143 flags |= FXFONT_FORCE_BOLD;
144 }
145
146 // TODO(npm): How do I know if a font is symbolic, script, allcap, smallcap?
147 flags |= FXFONT_NONSYMBOLIC;
148
149 font_descriptor_dict->SetNewFor<CPDF_Number>("Flags", flags);
150 FX_RECT bbox = font->GetBBox().value_or(FX_RECT());
151 font_descriptor_dict->SetRectFor("FontBBox", CFX_FloatRect(bbox));
152
153 // TODO(npm): calculate italic angle correctly
154 font_descriptor_dict->SetNewFor<CPDF_Number>("ItalicAngle",
155 font->IsItalic() ? -12 : 0);
156
157 font_descriptor_dict->SetNewFor<CPDF_Number>("Ascent", font->GetAscent());
158 font_descriptor_dict->SetNewFor<CPDF_Number>("Descent", font->GetDescent());
159
160 // TODO(npm): calculate the capheight, stemV correctly
161 font_descriptor_dict->SetNewFor<CPDF_Number>("CapHeight", font->GetAscent());
162 font_descriptor_dict->SetNewFor<CPDF_Number>("StemV",
163 font->IsBold() ? 120 : 70);
164
165 auto stream = doc->NewIndirect<CPDF_Stream>(font_data);
166 // TODO(npm): Lengths for Type1 fonts.
167 if (font_type == FPDF_FONT_TRUETYPE) {
168 stream->GetMutableDict()->SetNewFor<CPDF_Number>(
169 "Length1", pdfium::checked_cast<int>(font_data.size()));
170 }
171 ByteString font_file_key =
172 font_type == FPDF_FONT_TYPE1 ? "FontFile" : "FontFile2";
173 font_descriptor_dict->SetNewFor<CPDF_Reference>(font_file_key, doc,
174 stream->GetObjNum());
175 return font_descriptor_dict;
176 }
177
CreateWidthsArray(CPDF_Document * doc,const std::map<uint32_t,uint32_t> & widths)178 RetainPtr<CPDF_Array> CreateWidthsArray(
179 CPDF_Document* doc,
180 const std::map<uint32_t, uint32_t>& widths) {
181 auto widths_array = doc->NewIndirect<CPDF_Array>();
182 for (auto it = widths.begin(); it != widths.end(); ++it) {
183 int ch = it->first;
184 int w = it->second;
185 if (std::next(it) == widths.end()) {
186 // Only one char left, use format c [w]
187 auto single_w_array = pdfium::MakeRetain<CPDF_Array>();
188 single_w_array->AppendNew<CPDF_Number>(w);
189 widths_array->AppendNew<CPDF_Number>(ch);
190 widths_array->Append(std::move(single_w_array));
191 break;
192 }
193 ++it;
194 int next_ch = it->first;
195 int next_w = it->second;
196 if (next_ch == ch + 1 && next_w == w) {
197 // The array can have a group c_first c_last w: all CIDs in the range from
198 // c_first to c_last will have width w
199 widths_array->AppendNew<CPDF_Number>(ch);
200 ch = next_ch;
201 while (true) {
202 auto next_it = std::next(it);
203 if (next_it == widths.end() || next_it->first != it->first + 1 ||
204 next_it->second != it->second) {
205 break;
206 }
207 ++it;
208 ch = it->first;
209 }
210 widths_array->AppendNew<CPDF_Number>(ch);
211 widths_array->AppendNew<CPDF_Number>(w);
212 continue;
213 }
214 // Otherwise we can have a group of the form c [w1 w2 ...]: c has width
215 // w1, c+1 has width w2, etc.
216 widths_array->AppendNew<CPDF_Number>(ch);
217 auto current_width_array = pdfium::MakeRetain<CPDF_Array>();
218 current_width_array->AppendNew<CPDF_Number>(w);
219 current_width_array->AppendNew<CPDF_Number>(next_w);
220 while (true) {
221 auto next_it = std::next(it);
222 if (next_it == widths.end() || next_it->first != it->first + 1) {
223 break;
224 }
225 ++it;
226 current_width_array->AppendNew<CPDF_Number>(static_cast<int>(it->second));
227 }
228 widths_array->Append(std::move(current_width_array));
229 }
230 return widths_array;
231 }
232
233 const char kToUnicodeStart[] =
234 "/CIDInit /ProcSet findresource begin\n"
235 "12 dict begin\n"
236 "begincmap\n"
237 "/CIDSystemInfo\n"
238 "<</Registry (Adobe)\n"
239 "/Ordering (Identity)\n"
240 "/Supplement 0\n"
241 ">> def\n"
242 "/CMapName /Adobe-Identity-H def\n"
243 "/CMapType 2 def\n"
244 "1 begincodespacerange\n"
245 "<0000> <FFFF>\n"
246 "endcodespacerange\n";
247
248 const char kToUnicodeEnd[] =
249 "endcmap\n"
250 "CMapName currentdict /CMap defineresource pop\n"
251 "end\n"
252 "end\n";
253
AddCharcode(fxcrt::ostringstream & buffer,uint32_t number)254 void AddCharcode(fxcrt::ostringstream& buffer, uint32_t number) {
255 CHECK_LE(number, 0xFFFF);
256 buffer << "<";
257 char ans[4];
258 FXSYS_IntToFourHexChars(number, ans);
259 for (char c : ans) {
260 buffer << c;
261 }
262 buffer << ">";
263 }
264
265 // PDF spec 1.7 Section 5.9.2: "Unicode character sequences as expressed in
266 // UTF-16BE encoding." See https://en.wikipedia.org/wiki/UTF-16#Description
AddUnicode(fxcrt::ostringstream & buffer,uint32_t unicode)267 void AddUnicode(fxcrt::ostringstream& buffer, uint32_t unicode) {
268 if (pdfium::IsHighSurrogate(unicode) || pdfium::IsLowSurrogate(unicode)) {
269 unicode = 0;
270 }
271
272 char ans[8];
273 size_t char_count = FXSYS_ToUTF16BE(unicode, ans);
274 buffer << "<";
275 CHECK_LE(char_count, std::size(ans));
276 auto ans_span = pdfium::make_span(ans).first(char_count);
277 for (char c : ans_span) {
278 buffer << c;
279 }
280 buffer << ">";
281 }
282
283 // Loads the charcode to unicode mapping into a stream
LoadUnicode(CPDF_Document * doc,const std::multimap<uint32_t,uint32_t> & to_unicode)284 RetainPtr<CPDF_Stream> LoadUnicode(
285 CPDF_Document* doc,
286 const std::multimap<uint32_t, uint32_t>& to_unicode) {
287 // A map charcode->unicode
288 std::map<uint32_t, uint32_t> char_to_uni;
289 // A map <char_start, char_end> to vector v of unicode characters of size (end
290 // - start + 1). This abbreviates: start->v[0], start+1->v[1], etc. PDF spec
291 // 1.7 Section 5.9.2 says that only the last byte of the unicode may change.
292 std::map<std::pair<uint32_t, uint32_t>, std::vector<uint32_t>>
293 map_range_vector;
294 // A map <start, end> -> unicode
295 // This abbreviates: start->unicode, start+1->unicode+1, etc.
296 // PDF spec 1.7 Section 5.9.2 says that only the last byte of the unicode may
297 // change.
298 std::map<std::pair<uint32_t, uint32_t>, uint32_t> map_range;
299
300 // Calculate the maps
301 for (auto it = to_unicode.begin(); it != to_unicode.end(); ++it) {
302 uint32_t first_charcode = it->first;
303 uint32_t first_unicode = it->second;
304 {
305 auto next_it = std::next(it);
306 if (next_it == to_unicode.end() || first_charcode + 1 != next_it->first) {
307 char_to_uni[first_charcode] = first_unicode;
308 continue;
309 }
310 }
311 ++it;
312 uint32_t current_charcode = it->first;
313 uint32_t current_unicode = it->second;
314 if (current_charcode % 256 == 0) {
315 char_to_uni[first_charcode] = first_unicode;
316 char_to_uni[current_charcode] = current_unicode;
317 continue;
318 }
319 const size_t max_extra = 255 - (current_charcode % 256);
320 auto next_it = std::next(it);
321 if (first_unicode + 1 != current_unicode) {
322 // Consecutive charcodes mapping to non-consecutive unicodes
323 std::vector<uint32_t> unicodes = {first_unicode, current_unicode};
324 for (size_t i = 0; i < max_extra; ++i) {
325 if (next_it == to_unicode.end() ||
326 current_charcode + 1 != next_it->first) {
327 break;
328 }
329 ++it;
330 ++current_charcode;
331 unicodes.push_back(it->second);
332 next_it = std::next(it);
333 }
334 CHECK_EQ(it->first - first_charcode + 1, unicodes.size());
335 map_range_vector[std::make_pair(first_charcode, it->first)] = unicodes;
336 continue;
337 }
338 // Consecutive charcodes mapping to consecutive unicodes
339 for (size_t i = 0; i < max_extra; ++i) {
340 if (next_it == to_unicode.end() ||
341 current_charcode + 1 != next_it->first ||
342 current_unicode + 1 != next_it->second) {
343 break;
344 }
345 ++it;
346 ++current_charcode;
347 ++current_unicode;
348 next_it = std::next(it);
349 }
350 map_range[std::make_pair(first_charcode, current_charcode)] = first_unicode;
351 }
352
353 fxcrt::ostringstream buffer;
354 buffer << kToUnicodeStart;
355 // Add maps to buffer
356 buffer << static_cast<uint32_t>(char_to_uni.size()) << " beginbfchar\n";
357 for (const auto& it : char_to_uni) {
358 AddCharcode(buffer, it.first);
359 buffer << " ";
360 AddUnicode(buffer, it.second);
361 buffer << "\n";
362 }
363 buffer << "endbfchar\n"
364 << static_cast<uint32_t>(map_range_vector.size() + map_range.size())
365 << " beginbfrange\n";
366 for (const auto& it : map_range_vector) {
367 const std::pair<uint32_t, uint32_t>& charcode_range = it.first;
368 AddCharcode(buffer, charcode_range.first);
369 buffer << " ";
370 AddCharcode(buffer, charcode_range.second);
371 buffer << " [";
372 const std::vector<uint32_t>& unicodes = it.second;
373 for (size_t i = 0; i < unicodes.size(); ++i) {
374 AddUnicode(buffer, unicodes[i]);
375 if (i != unicodes.size() - 1)
376 buffer << " ";
377 }
378 buffer << "]\n";
379 }
380 for (const auto& it : map_range) {
381 const std::pair<uint32_t, uint32_t>& charcode_range = it.first;
382 AddCharcode(buffer, charcode_range.first);
383 buffer << " ";
384 AddCharcode(buffer, charcode_range.second);
385 buffer << " ";
386 AddUnicode(buffer, it.second);
387 buffer << "\n";
388 }
389 buffer << "endbfrange\n";
390 buffer << kToUnicodeEnd;
391 auto stream = doc->NewIndirect<CPDF_Stream>(&buffer);
392 return stream;
393 }
394
CreateDescendantFontsArray(CPDF_Document * doc,CPDF_Dictionary * font_dict,uint32_t cid_font_dict_obj_num)395 void CreateDescendantFontsArray(CPDF_Document* doc,
396 CPDF_Dictionary* font_dict,
397 uint32_t cid_font_dict_obj_num) {
398 auto descendant_fonts_dict =
399 font_dict->SetNewFor<CPDF_Array>("DescendantFonts");
400 descendant_fonts_dict->AppendNew<CPDF_Reference>(doc, cid_font_dict_obj_num);
401 }
402
LoadSimpleFont(CPDF_Document * doc,std::unique_ptr<CFX_Font> font,pdfium::span<const uint8_t> font_data,int font_type)403 RetainPtr<CPDF_Font> LoadSimpleFont(CPDF_Document* doc,
404 std::unique_ptr<CFX_Font> font,
405 pdfium::span<const uint8_t> font_data,
406 int font_type) {
407 // If it doesn't have a single char, just fail.
408 RetainPtr<CFX_Face> face = font->GetFace();
409 if (face->GetGlyphCount() <= 0) {
410 return nullptr;
411 }
412
413 // Simple fonts have 1-byte charcodes only.
414 static constexpr uint32_t kMaxSimpleFontChar = 0xFF;
415 auto char_codes_and_indices =
416 face->GetCharCodesAndIndices(kMaxSimpleFontChar);
417 if (char_codes_and_indices.empty()) {
418 return nullptr;
419 }
420
421 auto font_dict = doc->NewIndirect<CPDF_Dictionary>();
422 font_dict->SetNewFor<CPDF_Name>("Type", "Font");
423 font_dict->SetNewFor<CPDF_Name>(
424 "Subtype", font_type == FPDF_FONT_TYPE1 ? "Type1" : "TrueType");
425 const ByteString name = BaseFontNameForType(font.get(), font_type);
426 font_dict->SetNewFor<CPDF_Name>("BaseFont", name);
427
428 font_dict->SetNewFor<CPDF_Number>(
429 "FirstChar", static_cast<int>(char_codes_and_indices[0].char_code));
430 auto widths_array = doc->NewIndirect<CPDF_Array>();
431 for (size_t i = 0; i < char_codes_and_indices.size(); ++i) {
432 widths_array->AppendNew<CPDF_Number>(
433 font->GetGlyphWidth(char_codes_and_indices[i].glyph_index));
434 if (i > 0 && i < char_codes_and_indices.size() - 1) {
435 for (uint32_t j = char_codes_and_indices[i - 1].char_code + 1;
436 j < char_codes_and_indices[i].char_code; ++j) {
437 widths_array->AppendNew<CPDF_Number>(0);
438 }
439 }
440 }
441 font_dict->SetNewFor<CPDF_Number>(
442 "LastChar", static_cast<int>(char_codes_and_indices.back().char_code));
443 font_dict->SetNewFor<CPDF_Reference>("Widths", doc,
444 widths_array->GetObjNum());
445 RetainPtr<CPDF_Dictionary> font_descriptor_dict =
446 LoadFontDesc(doc, name, font.get(), font_data, font_type);
447
448 font_dict->SetNewFor<CPDF_Reference>("FontDescriptor", doc,
449 font_descriptor_dict->GetObjNum());
450 return CPDF_DocPageData::FromDocument(doc)->GetFont(std::move(font_dict));
451 }
452
LoadCompositeFont(CPDF_Document * doc,std::unique_ptr<CFX_Font> font,pdfium::span<const uint8_t> font_data,int font_type)453 RetainPtr<CPDF_Font> LoadCompositeFont(CPDF_Document* doc,
454 std::unique_ptr<CFX_Font> font,
455 pdfium::span<const uint8_t> font_data,
456 int font_type) {
457 // If it doesn't have a single char, just fail.
458 RetainPtr<CFX_Face> face = font->GetFace();
459 if (face->GetGlyphCount() <= 0) {
460 return nullptr;
461 }
462
463 auto char_codes_and_indices =
464 face->GetCharCodesAndIndices(pdfium::kMaximumSupplementaryCodePoint);
465 if (char_codes_and_indices.empty()) {
466 return nullptr;
467 }
468
469 const ByteString name = BaseFontNameForType(font.get(), font_type);
470 RetainPtr<CPDF_Dictionary> font_dict =
471 CreateCompositeFontDict(doc, font.get(), font_type, name);
472
473 RetainPtr<CPDF_Dictionary> cid_font_dict =
474 CreateCidFontDict(doc, font_type, name);
475
476 RetainPtr<CPDF_Dictionary> font_descriptor_dict =
477 LoadFontDesc(doc, name, font.get(), font_data, font_type);
478 cid_font_dict->SetNewFor<CPDF_Reference>("FontDescriptor", doc,
479 font_descriptor_dict->GetObjNum());
480
481 std::multimap<uint32_t, uint32_t> to_unicode;
482 std::map<uint32_t, uint32_t> widths;
483 for (const auto& item : char_codes_and_indices) {
484 if (!pdfium::Contains(widths, item.glyph_index)) {
485 widths[item.glyph_index] = font->GetGlyphWidth(item.glyph_index);
486 }
487 to_unicode.emplace(item.glyph_index, item.char_code);
488 }
489 RetainPtr<CPDF_Array> widths_array = CreateWidthsArray(doc, widths);
490 cid_font_dict->SetNewFor<CPDF_Reference>("W", doc, widths_array->GetObjNum());
491
492 // TODO(npm): Support vertical writing
493
494 CreateDescendantFontsArray(doc, font_dict.Get(), cid_font_dict->GetObjNum());
495
496 RetainPtr<CPDF_Stream> to_unicode_stream = LoadUnicode(doc, to_unicode);
497 font_dict->SetNewFor<CPDF_Reference>("ToUnicode", doc,
498 to_unicode_stream->GetObjNum());
499 return CPDF_DocPageData::FromDocument(doc)->GetFont(font_dict);
500 }
501
LoadCustomCompositeFont(CPDF_Document * doc,std::unique_ptr<CFX_Font> font,pdfium::span<const uint8_t> font_span,const char * to_unicode_cmap,pdfium::span<const uint8_t> cid_to_gid_map_span)502 RetainPtr<CPDF_Font> LoadCustomCompositeFont(
503 CPDF_Document* doc,
504 std::unique_ptr<CFX_Font> font,
505 pdfium::span<const uint8_t> font_span,
506 const char* to_unicode_cmap,
507 pdfium::span<const uint8_t> cid_to_gid_map_span) {
508 // If it doesn't have a single char, just fail.
509 RetainPtr<CFX_Face> face = font->GetFace();
510 if (face->GetGlyphCount() <= 0) {
511 return nullptr;
512 }
513
514 auto char_codes_and_indices =
515 face->GetCharCodesAndIndices(pdfium::kMaximumSupplementaryCodePoint);
516 if (char_codes_and_indices.empty()) {
517 return nullptr;
518 }
519
520 const ByteString name = BaseFontNameForType(font.get(), FPDF_FONT_TRUETYPE);
521 RetainPtr<CPDF_Dictionary> font_dict =
522 CreateCompositeFontDict(doc, font.get(), FPDF_FONT_TRUETYPE, name);
523
524 RetainPtr<CPDF_Dictionary> cid_font_dict =
525 CreateCidFontDict(doc, FPDF_FONT_TRUETYPE, name);
526
527 RetainPtr<CPDF_Dictionary> font_descriptor =
528 LoadFontDesc(doc, name, font.get(), font_span, FPDF_FONT_TRUETYPE);
529 cid_font_dict->SetNewFor<CPDF_Reference>("FontDescriptor", doc,
530 font_descriptor->GetObjNum());
531
532 std::map<uint32_t, uint32_t> widths;
533 for (const auto& item : char_codes_and_indices) {
534 if (!pdfium::Contains(widths, item.glyph_index)) {
535 widths[item.glyph_index] = font->GetGlyphWidth(item.glyph_index);
536 }
537 }
538 RetainPtr<CPDF_Array> widths_array = CreateWidthsArray(doc, widths);
539 cid_font_dict->SetNewFor<CPDF_Reference>("W", doc, widths_array->GetObjNum());
540
541 auto cid_to_gid_map = doc->NewIndirect<CPDF_Stream>(cid_to_gid_map_span);
542 cid_font_dict->SetNewFor<CPDF_Reference>("CIDToGIDMap", doc,
543 cid_to_gid_map->GetObjNum());
544
545 CreateDescendantFontsArray(doc, font_dict, cid_font_dict->GetObjNum());
546
547 auto to_unicode_stream = doc->NewIndirect<CPDF_Stream>(
548 ByteStringView(to_unicode_cmap).unsigned_span());
549 font_dict->SetNewFor<CPDF_Reference>("ToUnicode", doc,
550 to_unicode_stream->GetObjNum());
551 return CPDF_DocPageData::FromDocument(doc)->GetFont(font_dict);
552 }
553
CPDFTextObjectFromFPDFPageObject(FPDF_PAGEOBJECT page_object)554 CPDF_TextObject* CPDFTextObjectFromFPDFPageObject(FPDF_PAGEOBJECT page_object) {
555 auto* obj = CPDFPageObjectFromFPDFPageObject(page_object);
556 return obj ? obj->AsText() : nullptr;
557 }
558
FPDFGlyphPathFromCFXPath(const CFX_Path * path)559 FPDF_GLYPHPATH FPDFGlyphPathFromCFXPath(const CFX_Path* path) {
560 return reinterpret_cast<FPDF_GLYPHPATH>(path);
561 }
CFXPathFromFPDFGlyphPath(FPDF_GLYPHPATH path)562 const CFX_Path* CFXPathFromFPDFGlyphPath(FPDF_GLYPHPATH path) {
563 return reinterpret_cast<const CFX_Path*>(path);
564 }
565
566 } // namespace
567
568 FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV
FPDFPageObj_NewTextObj(FPDF_DOCUMENT document,FPDF_BYTESTRING font,float font_size)569 FPDFPageObj_NewTextObj(FPDF_DOCUMENT document,
570 FPDF_BYTESTRING font,
571 float font_size) {
572 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
573 if (!pDoc)
574 return nullptr;
575
576 RetainPtr<CPDF_Font> pFont =
577 CPDF_Font::GetStockFont(pDoc, ByteStringView(font));
578 if (!pFont)
579 return nullptr;
580
581 auto pTextObj = std::make_unique<CPDF_TextObject>();
582 pTextObj->mutable_text_state().SetFont(std::move(pFont));
583 pTextObj->mutable_text_state().SetFontSize(font_size);
584 pTextObj->SetDefaultStates();
585
586 // Caller takes ownership.
587 return FPDFPageObjectFromCPDFPageObject(pTextObj.release());
588 }
589
590 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFText_SetText(FPDF_PAGEOBJECT text_object,FPDF_WIDESTRING text)591 FPDFText_SetText(FPDF_PAGEOBJECT text_object, FPDF_WIDESTRING text) {
592 CPDF_TextObject* pTextObj = CPDFTextObjectFromFPDFPageObject(text_object);
593 if (!pTextObj) {
594 return false;
595 }
596 // SAFETY: required from caller.
597 WideString encodedText = UNSAFE_BUFFERS(WideStringFromFPDFWideString(text));
598 ByteString byteText;
599 for (wchar_t wc : encodedText) {
600 pTextObj->GetFont()->AppendChar(
601 &byteText, pTextObj->GetFont()->CharCodeFromUnicode(wc));
602 }
603 pTextObj->SetText(byteText);
604 return true;
605 }
606
607 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFText_SetCharcodes(FPDF_PAGEOBJECT text_object,const uint32_t * charcodes,size_t count)608 FPDFText_SetCharcodes(FPDF_PAGEOBJECT text_object,
609 const uint32_t* charcodes,
610 size_t count) {
611 CPDF_TextObject* pTextObj = CPDFTextObjectFromFPDFPageObject(text_object);
612 if (!pTextObj)
613 return false;
614
615 if (!charcodes && count)
616 return false;
617
618 ByteString byte_text;
619 if (charcodes) {
620 for (size_t i = 0; i < count; ++i) {
621 pTextObj->GetFont()->AppendChar(&byte_text, UNSAFE_TODO(charcodes[i]));
622 }
623 }
624 pTextObj->SetText(byte_text);
625 return true;
626 }
627
FPDFText_LoadFont(FPDF_DOCUMENT document,const uint8_t * data,uint32_t size,int font_type,FPDF_BOOL cid)628 FPDF_EXPORT FPDF_FONT FPDF_CALLCONV FPDFText_LoadFont(FPDF_DOCUMENT document,
629 const uint8_t* data,
630 uint32_t size,
631 int font_type,
632 FPDF_BOOL cid) {
633 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
634 if (!pDoc || !data || size == 0 ||
635 (font_type != FPDF_FONT_TYPE1 && font_type != FPDF_FONT_TRUETYPE)) {
636 return nullptr;
637 }
638 // SAFETY: required from caller.
639 auto span = UNSAFE_BUFFERS(pdfium::make_span(data, size));
640 auto pFont = std::make_unique<CFX_Font>();
641
642 // TODO(npm): Maybe use FT_Get_X11_Font_Format to check format? Otherwise, we
643 // are allowing giving any font that can be loaded on freetype and setting it
644 // as any font type.
645 if (!pFont->LoadEmbedded(span, /*force_vertical=*/false, /*object_tag=*/0))
646 return nullptr;
647
648 // Caller takes ownership.
649 return FPDFFontFromCPDFFont(
650 cid ? LoadCompositeFont(pDoc, std::move(pFont), span, font_type).Leak()
651 : LoadSimpleFont(pDoc, std::move(pFont), span, font_type).Leak());
652 }
653
654 FPDF_EXPORT FPDF_FONT FPDF_CALLCONV
FPDFText_LoadStandardFont(FPDF_DOCUMENT document,FPDF_BYTESTRING font)655 FPDFText_LoadStandardFont(FPDF_DOCUMENT document, FPDF_BYTESTRING font) {
656 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
657 if (!pDoc)
658 return nullptr;
659
660 // Caller takes ownership.
661 return FPDFFontFromCPDFFont(
662 CPDF_Font::GetStockFont(pDoc, ByteStringView(font)).Leak());
663 }
664
665 FPDF_EXPORT FPDF_FONT FPDF_CALLCONV
FPDFText_LoadCidType2Font(FPDF_DOCUMENT document,const uint8_t * font_data,uint32_t font_data_size,FPDF_BYTESTRING to_unicode_cmap,const uint8_t * cid_to_gid_map_data,uint32_t cid_to_gid_map_data_size)666 FPDFText_LoadCidType2Font(FPDF_DOCUMENT document,
667 const uint8_t* font_data,
668 uint32_t font_data_size,
669 FPDF_BYTESTRING to_unicode_cmap,
670 const uint8_t* cid_to_gid_map_data,
671 uint32_t cid_to_gid_map_data_size) {
672 CPDF_Document* doc = CPDFDocumentFromFPDFDocument(document);
673 if (!doc || !font_data || font_data_size == 0 || !to_unicode_cmap ||
674 strlen(to_unicode_cmap) == 0 || !cid_to_gid_map_data ||
675 cid_to_gid_map_data_size == 0) {
676 return nullptr;
677 }
678 // SAFETY: required from caller.
679 auto font_span = UNSAFE_BUFFERS(pdfium::make_span(font_data, font_data_size));
680 auto font = std::make_unique<CFX_Font>();
681
682 // TODO(thestig): Consider checking the font format. See similar comment in
683 // FPDFText_LoadFont() above.
684 if (!font->LoadEmbedded(font_span, /*force_vertical=*/false,
685 /*object_tag=*/0)) {
686 return nullptr;
687 }
688
689 // Caller takes ownership of result.
690 // SAFETY: caller ensures `cid_to_gid_map_data` points to at least
691 // `cid_to_gid_map_data_size` entries.
692 return FPDFFontFromCPDFFont(
693 LoadCustomCompositeFont(
694 doc, std::move(font), font_span, to_unicode_cmap,
695 UNSAFE_BUFFERS(
696 pdfium::make_span(cid_to_gid_map_data, cid_to_gid_map_data_size)))
697 .Leak());
698 }
699
700 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFTextObj_GetFontSize(FPDF_PAGEOBJECT text,float * size)701 FPDFTextObj_GetFontSize(FPDF_PAGEOBJECT text, float* size) {
702 if (!size)
703 return false;
704
705 CPDF_TextObject* pTextObj = CPDFTextObjectFromFPDFPageObject(text);
706 if (!pTextObj)
707 return false;
708
709 *size = pTextObj->GetFontSize();
710 return true;
711 }
712
713 FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDFTextObj_GetText(FPDF_PAGEOBJECT text_object,FPDF_TEXTPAGE text_page,FPDF_WCHAR * buffer,unsigned long length)714 FPDFTextObj_GetText(FPDF_PAGEOBJECT text_object,
715 FPDF_TEXTPAGE text_page,
716 FPDF_WCHAR* buffer,
717 unsigned long length) {
718 CPDF_TextObject* pTextObj = CPDFTextObjectFromFPDFPageObject(text_object);
719 if (!pTextObj)
720 return 0;
721
722 CPDF_TextPage* pTextPage = CPDFTextPageFromFPDFTextPage(text_page);
723 if (!pTextPage)
724 return 0;
725
726 // SAFETY: required from caller.
727 return Utf16EncodeMaybeCopyAndReturnLength(
728 pTextPage->GetTextByObject(pTextObj),
729 UNSAFE_BUFFERS(SpanFromFPDFApiArgs(buffer, length)));
730 }
731
732 FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV
FPDFTextObj_GetRenderedBitmap(FPDF_DOCUMENT document,FPDF_PAGE page,FPDF_PAGEOBJECT text_object,float scale)733 FPDFTextObj_GetRenderedBitmap(FPDF_DOCUMENT document,
734 FPDF_PAGE page,
735 FPDF_PAGEOBJECT text_object,
736 float scale) {
737 CPDF_Document* doc = CPDFDocumentFromFPDFDocument(document);
738 if (!doc)
739 return nullptr;
740
741 CPDF_Page* optional_page = CPDFPageFromFPDFPage(page);
742 if (optional_page && optional_page->GetDocument() != doc)
743 return nullptr;
744
745 CPDF_TextObject* text = CPDFTextObjectFromFPDFPageObject(text_object);
746 if (!text)
747 return nullptr;
748
749 if (scale <= 0)
750 return nullptr;
751
752 const CFX_Matrix scale_matrix(scale, 0, 0, scale, 0, 0);
753 const CFX_FloatRect& text_rect = text->GetRect();
754 const CFX_FloatRect scaled_text_rect = scale_matrix.TransformRect(text_rect);
755
756 // `rect` has to use integer values. Round up as needed.
757 const FX_RECT rect = scaled_text_rect.GetOuterRect();
758 if (rect.IsEmpty())
759 return nullptr;
760
761 // TODO(crbug.com/42271020): Consider adding support for
762 // `FXDIB_Format::kBgraPremul`
763 auto result_bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
764 if (!result_bitmap->Create(rect.Width(), rect.Height(),
765 FXDIB_Format::kBgra)) {
766 return nullptr;
767 }
768
769 auto render_context = std::make_unique<CPDF_PageRenderContext>();
770 CPDF_PageRenderContext* render_context_ptr = render_context.get();
771 CPDF_Page::RenderContextClearer clearer(optional_page);
772 if (optional_page)
773 optional_page->SetRenderContext(std::move(render_context));
774
775 RetainPtr<CPDF_Dictionary> page_resources =
776 optional_page ? optional_page->GetMutablePageResources() : nullptr;
777
778 auto device = std::make_unique<CFX_DefaultRenderDevice>();
779 CFX_DefaultRenderDevice* device_ptr = device.get();
780 render_context_ptr->m_pDevice = std::move(device);
781 render_context_ptr->m_pContext = std::make_unique<CPDF_RenderContext>(
782 doc, std::move(page_resources), /*pPageCache=*/nullptr);
783
784 device_ptr->Attach(result_bitmap);
785
786 CFX_Matrix device_matrix(rect.Width(), 0, 0, rect.Height(), 0, 0);
787 CPDF_RenderStatus status(render_context_ptr->m_pContext.get(), device_ptr);
788 status.SetDeviceMatrix(device_matrix);
789 status.Initialize(nullptr, nullptr);
790
791 // Need to flip the rendering and also move it to fit within `result_bitmap`.
792 CFX_Matrix render_matrix(1, 0, 0, -1, -text_rect.left, text_rect.top);
793 render_matrix *= scale_matrix;
794 status.RenderSingleObject(text, render_matrix);
795
796 CHECK(!result_bitmap->IsPremultiplied());
797
798 // Caller takes ownership.
799 return FPDFBitmapFromCFXDIBitmap(result_bitmap.Leak());
800 }
801
FPDFFont_Close(FPDF_FONT font)802 FPDF_EXPORT void FPDF_CALLCONV FPDFFont_Close(FPDF_FONT font) {
803 // Take back ownership from caller and release.
804 RetainPtr<CPDF_Font>().Unleak(CPDFFontFromFPDFFont(font));
805 }
806
807 FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV
FPDFPageObj_CreateTextObj(FPDF_DOCUMENT document,FPDF_FONT font,float font_size)808 FPDFPageObj_CreateTextObj(FPDF_DOCUMENT document,
809 FPDF_FONT font,
810 float font_size) {
811 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
812 CPDF_Font* pFont = CPDFFontFromFPDFFont(font);
813 if (!pDoc || !pFont)
814 return nullptr;
815
816 auto pTextObj = std::make_unique<CPDF_TextObject>();
817 pTextObj->mutable_text_state().SetFont(
818 CPDF_DocPageData::FromDocument(pDoc)->GetFont(
819 pFont->GetMutableFontDict()));
820 pTextObj->mutable_text_state().SetFontSize(font_size);
821 pTextObj->SetDefaultStates();
822 return FPDFPageObjectFromCPDFPageObject(pTextObj.release());
823 }
824
825 FPDF_EXPORT FPDF_TEXT_RENDERMODE FPDF_CALLCONV
FPDFTextObj_GetTextRenderMode(FPDF_PAGEOBJECT text)826 FPDFTextObj_GetTextRenderMode(FPDF_PAGEOBJECT text) {
827 CPDF_TextObject* pTextObj = CPDFTextObjectFromFPDFPageObject(text);
828 if (!pTextObj)
829 return FPDF_TEXTRENDERMODE_UNKNOWN;
830 return static_cast<FPDF_TEXT_RENDERMODE>(pTextObj->GetTextRenderMode());
831 }
832
833 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFTextObj_SetTextRenderMode(FPDF_PAGEOBJECT text,FPDF_TEXT_RENDERMODE render_mode)834 FPDFTextObj_SetTextRenderMode(FPDF_PAGEOBJECT text,
835 FPDF_TEXT_RENDERMODE render_mode) {
836 if (render_mode <= FPDF_TEXTRENDERMODE_UNKNOWN ||
837 render_mode > FPDF_TEXTRENDERMODE_LAST) {
838 return false;
839 }
840
841 CPDF_TextObject* pTextObj = CPDFTextObjectFromFPDFPageObject(text);
842 if (!pTextObj)
843 return false;
844
845 pTextObj->SetTextRenderMode(static_cast<TextRenderingMode>(render_mode));
846 return true;
847 }
848
FPDFTextObj_GetFont(FPDF_PAGEOBJECT text)849 FPDF_EXPORT FPDF_FONT FPDF_CALLCONV FPDFTextObj_GetFont(FPDF_PAGEOBJECT text) {
850 CPDF_TextObject* pTextObj = CPDFTextObjectFromFPDFPageObject(text);
851 if (!pTextObj)
852 return nullptr;
853
854 // Unretained reference in public API. NOLINTNEXTLINE
855 return FPDFFontFromCPDFFont(pTextObj->GetFont());
856 }
857
FPDFFont_GetBaseFontName(FPDF_FONT font,char * buffer,size_t length)858 FPDF_EXPORT size_t FPDF_CALLCONV FPDFFont_GetBaseFontName(FPDF_FONT font,
859 char* buffer,
860 size_t length) {
861 auto* cfont = CPDFFontFromFPDFFont(font);
862 if (!cfont) {
863 return 0;
864 }
865
866 // SAFETY: required from caller.
867 auto result_span = UNSAFE_BUFFERS(SpanFromFPDFApiArgs(buffer, length));
868 ByteString name = cfont->GetBaseFontName();
869 pdfium::span<const char> name_span = name.span_with_terminator();
870 fxcrt::try_spancpy(result_span, name_span);
871 return name_span.size();
872 }
873
FPDFFont_GetFamilyName(FPDF_FONT font,char * buffer,size_t length)874 FPDF_EXPORT size_t FPDF_CALLCONV FPDFFont_GetFamilyName(FPDF_FONT font,
875 char* buffer,
876 size_t length) {
877 auto* cfont = CPDFFontFromFPDFFont(font);
878 if (!cfont) {
879 return 0;
880 }
881
882 // SAFETY: required from caller.
883 auto result_span = UNSAFE_BUFFERS(SpanFromFPDFApiArgs(buffer, length));
884 ByteString name = cfont->GetFont()->GetFamilyName();
885 pdfium::span<const char> name_span = name.span_with_terminator();
886 fxcrt::try_spancpy(result_span, name_span);
887 return name_span.size();
888 }
889
FPDFFont_GetFontData(FPDF_FONT font,uint8_t * buffer,size_t buflen,size_t * out_buflen)890 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetFontData(FPDF_FONT font,
891 uint8_t* buffer,
892 size_t buflen,
893 size_t* out_buflen) {
894 auto* cfont = CPDFFontFromFPDFFont(font);
895 if (!cfont || !out_buflen)
896 return false;
897
898 // SAFETY: required from caller.
899 auto result_span = UNSAFE_BUFFERS(SpanFromFPDFApiArgs(buffer, buflen));
900 pdfium::span<const uint8_t> data = cfont->GetFont()->GetFontSpan();
901 fxcrt::try_spancpy(result_span, data);
902 *out_buflen = data.size();
903 return true;
904 }
905
FPDFFont_GetIsEmbedded(FPDF_FONT font)906 FPDF_EXPORT int FPDF_CALLCONV FPDFFont_GetIsEmbedded(FPDF_FONT font) {
907 auto* cfont = CPDFFontFromFPDFFont(font);
908 if (!cfont)
909 return -1;
910 return cfont->IsEmbedded() ? 1 : 0;
911 }
912
FPDFFont_GetFlags(FPDF_FONT font)913 FPDF_EXPORT int FPDF_CALLCONV FPDFFont_GetFlags(FPDF_FONT font) {
914 auto* pFont = CPDFFontFromFPDFFont(font);
915 if (!pFont)
916 return -1;
917
918 // Return only flags from ISO 32000-1:2008, table 123.
919 return pFont->GetFontFlags() & 0x7ffff;
920 }
921
FPDFFont_GetWeight(FPDF_FONT font)922 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetWeight(FPDF_FONT font) {
923 auto* pFont = CPDFFontFromFPDFFont(font);
924 return pFont ? pFont->GetFontWeight() : -1;
925 }
926
FPDFFont_GetItalicAngle(FPDF_FONT font,int * angle)927 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetItalicAngle(FPDF_FONT font,
928 int* angle) {
929 auto* pFont = CPDFFontFromFPDFFont(font);
930 if (!pFont || !angle)
931 return false;
932
933 *angle = pFont->GetItalicAngle();
934 return true;
935 }
936
FPDFFont_GetAscent(FPDF_FONT font,float font_size,float * ascent)937 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetAscent(FPDF_FONT font,
938 float font_size,
939 float* ascent) {
940 auto* pFont = CPDFFontFromFPDFFont(font);
941 if (!pFont || !ascent)
942 return false;
943
944 *ascent = pFont->GetTypeAscent() * font_size / 1000.f;
945 return true;
946 }
947
FPDFFont_GetDescent(FPDF_FONT font,float font_size,float * descent)948 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetDescent(FPDF_FONT font,
949 float font_size,
950 float* descent) {
951 auto* pFont = CPDFFontFromFPDFFont(font);
952 if (!pFont || !descent)
953 return false;
954
955 *descent = pFont->GetTypeDescent() * font_size / 1000.f;
956 return true;
957 }
958
FPDFFont_GetGlyphWidth(FPDF_FONT font,uint32_t glyph,float font_size,float * width)959 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetGlyphWidth(FPDF_FONT font,
960 uint32_t glyph,
961 float font_size,
962 float* width) {
963 auto* pFont = CPDFFontFromFPDFFont(font);
964 if (!pFont || !width)
965 return false;
966
967 uint32_t charcode = pFont->CharCodeFromUnicode(static_cast<wchar_t>(glyph));
968
969 CPDF_CIDFont* pCIDFont = pFont->AsCIDFont();
970 if (pCIDFont && pCIDFont->IsVertWriting()) {
971 uint16_t cid = pCIDFont->CIDFromCharCode(charcode);
972 *width = pCIDFont->GetVertWidth(cid) * font_size / 1000.f;
973 } else {
974 *width = pFont->GetCharWidthF(charcode) * font_size / 1000.f;
975 }
976
977 return true;
978 }
979
980 FPDF_EXPORT FPDF_GLYPHPATH FPDF_CALLCONV
FPDFFont_GetGlyphPath(FPDF_FONT font,uint32_t glyph,float font_size)981 FPDFFont_GetGlyphPath(FPDF_FONT font, uint32_t glyph, float font_size) {
982 auto* pFont = CPDFFontFromFPDFFont(font);
983 if (!pFont)
984 return nullptr;
985
986 if (!pdfium::IsValueInRangeForNumericType<wchar_t>(glyph)) {
987 return nullptr;
988 }
989
990 uint32_t charcode = pFont->CharCodeFromUnicode(static_cast<wchar_t>(glyph));
991 std::vector<TextCharPos> pos =
992 GetCharPosList(pdfium::span_from_ref(charcode),
993 pdfium::span<const float>(), pFont, font_size);
994 if (pos.empty())
995 return nullptr;
996
997 CFX_Font* pCfxFont;
998 if (pos[0].m_FallbackFontPosition == -1) {
999 pCfxFont = pFont->GetFont();
1000 DCHECK(pCfxFont); // Never null.
1001 } else {
1002 pCfxFont = pFont->GetFontFallback(pos[0].m_FallbackFontPosition);
1003 if (!pCfxFont)
1004 return nullptr;
1005 }
1006
1007 const CFX_Path* pPath =
1008 pCfxFont->LoadGlyphPath(pos[0].m_GlyphIndex, pos[0].m_FontCharWidth);
1009
1010 return FPDFGlyphPathFromCFXPath(pPath);
1011 }
1012
1013 FPDF_EXPORT int FPDF_CALLCONV
FPDFGlyphPath_CountGlyphSegments(FPDF_GLYPHPATH glyphpath)1014 FPDFGlyphPath_CountGlyphSegments(FPDF_GLYPHPATH glyphpath) {
1015 auto* pPath = CFXPathFromFPDFGlyphPath(glyphpath);
1016 if (!pPath)
1017 return -1;
1018
1019 return fxcrt::CollectionSize<int>(pPath->GetPoints());
1020 }
1021
1022 FPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV
FPDFGlyphPath_GetGlyphPathSegment(FPDF_GLYPHPATH glyphpath,int index)1023 FPDFGlyphPath_GetGlyphPathSegment(FPDF_GLYPHPATH glyphpath, int index) {
1024 auto* pPath = CFXPathFromFPDFGlyphPath(glyphpath);
1025 if (!pPath)
1026 return nullptr;
1027
1028 pdfium::span<const CFX_Path::Point> points = pPath->GetPoints();
1029 if (!fxcrt::IndexInBounds(points, index))
1030 return nullptr;
1031
1032 return FPDFPathSegmentFromFXPathPoint(&points[index]);
1033 }
1034