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