• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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