• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 PDFium Authors. All rights reserved.
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 <algorithm>
6 #include <limits>
7 #include <map>
8 #include <memory>
9 #include <utility>
10 #include <vector>
11 
12 #include "core/fpdfapi/font/cpdf_font.h"
13 #include "core/fpdfapi/font/cpdf_type1font.h"
14 #include "core/fpdfapi/page/cpdf_docpagedata.h"
15 #include "core/fpdfapi/page/cpdf_textobject.h"
16 #include "core/fpdfapi/page/cpdf_textstate.h"
17 #include "core/fpdfapi/parser/cpdf_array.h"
18 #include "core/fpdfapi/parser/cpdf_dictionary.h"
19 #include "core/fpdfapi/parser/cpdf_document.h"
20 #include "core/fpdfapi/parser/cpdf_name.h"
21 #include "core/fpdfapi/parser/cpdf_number.h"
22 #include "core/fpdfapi/parser/cpdf_reference.h"
23 #include "core/fpdfapi/parser/cpdf_stream.h"
24 #include "core/fpdfapi/parser/cpdf_string.h"
25 #include "core/fpdftext/cpdf_textpage.h"
26 #include "core/fxcrt/fx_extension.h"
27 #include "core/fxge/cfx_fontmgr.h"
28 #include "core/fxge/fx_font.h"
29 #include "fpdfsdk/cpdfsdk_helpers.h"
30 #include "public/fpdf_edit.h"
31 #include "third_party/base/ptr_util.h"
32 
33 // These checks are here because core/ and public/ cannot depend on each other.
34 static_assert(static_cast<int>(TextRenderingMode::MODE_UNKNOWN) ==
35                   FPDF_TEXTRENDERMODE_UNKNOWN,
36               "TextRenderingMode::MODE_UNKNOWN value mismatch");
37 static_assert(static_cast<int>(TextRenderingMode::MODE_FILL) ==
38                   FPDF_TEXTRENDERMODE_FILL,
39               "TextRenderingMode::MODE_FILL value mismatch");
40 static_assert(static_cast<int>(TextRenderingMode::MODE_STROKE) ==
41                   FPDF_TEXTRENDERMODE_STROKE,
42               "TextRenderingMode::MODE_STROKE value mismatch");
43 static_assert(static_cast<int>(TextRenderingMode::MODE_FILL_STROKE) ==
44                   FPDF_TEXTRENDERMODE_FILL_STROKE,
45               "TextRenderingMode::MODE_FILL_STROKE value mismatch");
46 static_assert(static_cast<int>(TextRenderingMode::MODE_INVISIBLE) ==
47                   FPDF_TEXTRENDERMODE_INVISIBLE,
48               "TextRenderingMode::MODE_INVISIBLE value mismatch");
49 static_assert(static_cast<int>(TextRenderingMode::MODE_FILL_CLIP) ==
50                   FPDF_TEXTRENDERMODE_FILL_CLIP,
51               "TextRenderingMode::MODE_FILL_CLIP value mismatch");
52 static_assert(static_cast<int>(TextRenderingMode::MODE_STROKE_CLIP) ==
53                   FPDF_TEXTRENDERMODE_STROKE_CLIP,
54               "TextRenderingMode::MODE_STROKE_CLIP value mismatch");
55 static_assert(static_cast<int>(TextRenderingMode::MODE_FILL_STROKE_CLIP) ==
56                   FPDF_TEXTRENDERMODE_FILL_STROKE_CLIP,
57               "TextRenderingMode::MODE_FILL_STROKE_CLIP value mismatch");
58 static_assert(static_cast<int>(TextRenderingMode::MODE_CLIP) ==
59                   FPDF_TEXTRENDERMODE_CLIP,
60               "TextRenderingMode::MODE_CLIP value mismatch");
61 static_assert(static_cast<int>(TextRenderingMode::MODE_LAST) ==
62                   FPDF_TEXTRENDERMODE_LAST,
63               "TextRenderingMode::MODE_LAST value mismatch");
64 
65 namespace {
66 
LoadFontDesc(CPDF_Document * pDoc,const ByteString & font_name,CFX_Font * pFont,pdfium::span<const uint8_t> span,int font_type)67 CPDF_Dictionary* LoadFontDesc(CPDF_Document* pDoc,
68                               const ByteString& font_name,
69                               CFX_Font* pFont,
70                               pdfium::span<const uint8_t> span,
71                               int font_type) {
72   CPDF_Dictionary* pFontDesc = pDoc->NewIndirect<CPDF_Dictionary>();
73   pFontDesc->SetNewFor<CPDF_Name>("Type", "FontDescriptor");
74   pFontDesc->SetNewFor<CPDF_Name>("FontName", font_name);
75   int flags = 0;
76   if (FXFT_Is_Face_fixedwidth(pFont->GetFaceRec()))
77     flags |= FXFONT_FIXED_PITCH;
78   if (font_name.Contains("Serif"))
79     flags |= FXFONT_SERIF;
80   if (FXFT_Is_Face_Italic(pFont->GetFaceRec()))
81     flags |= FXFONT_ITALIC;
82   if (FXFT_Is_Face_Bold(pFont->GetFaceRec()))
83     flags |= FXFONT_FORCE_BOLD;
84 
85   // TODO(npm): How do I know if a  font is symbolic, script, allcap, smallcap
86   flags |= FXFONT_NONSYMBOLIC;
87 
88   pFontDesc->SetNewFor<CPDF_Number>("Flags", flags);
89   FX_RECT bbox;
90   pFont->GetBBox(&bbox);
91   pFontDesc->SetRectFor("FontBBox", CFX_FloatRect(bbox));
92 
93   // TODO(npm): calculate italic angle correctly
94   pFontDesc->SetNewFor<CPDF_Number>("ItalicAngle", pFont->IsItalic() ? -12 : 0);
95 
96   pFontDesc->SetNewFor<CPDF_Number>("Ascent", pFont->GetAscent());
97   pFontDesc->SetNewFor<CPDF_Number>("Descent", pFont->GetDescent());
98 
99   // TODO(npm): calculate the capheight, stemV correctly
100   pFontDesc->SetNewFor<CPDF_Number>("CapHeight", pFont->GetAscent());
101   pFontDesc->SetNewFor<CPDF_Number>("StemV", pFont->IsBold() ? 120 : 70);
102 
103   CPDF_Stream* pStream = pDoc->NewIndirect<CPDF_Stream>();
104   pStream->SetData(span);
105   // TODO(npm): Lengths for Type1 fonts.
106   if (font_type == FPDF_FONT_TRUETYPE) {
107     pStream->GetDict()->SetNewFor<CPDF_Number>("Length1",
108                                                static_cast<int>(span.size()));
109   }
110   ByteString fontFile = font_type == FPDF_FONT_TYPE1 ? "FontFile" : "FontFile2";
111   pFontDesc->SetNewFor<CPDF_Reference>(fontFile, pDoc, pStream->GetObjNum());
112   return pFontDesc;
113 }
114 
115 const char ToUnicodeStart[] =
116     "/CIDInit /ProcSet findresource begin\n"
117     "12 dict begin\n"
118     "begincmap\n"
119     "/CIDSystemInfo\n"
120     "<</Registry (Adobe)\n"
121     "/Ordering (Identity)\n"
122     "/Supplement 0\n"
123     ">> def\n"
124     "/CMapName /Adobe-Identity-H def\n"
125     "CMapType 2 def\n"
126     "1 begincodespacerange\n"
127     "<0000> <FFFFF>\n"
128     "endcodespacerange\n";
129 
130 const char ToUnicodeEnd[] =
131     "endcmap\n"
132     "CMapName currentdict /CMap defineresource pop\n"
133     "end\n"
134     "end\n";
135 
AddCharcode(std::ostringstream * pBuffer,uint32_t number)136 void AddCharcode(std::ostringstream* pBuffer, uint32_t number) {
137   ASSERT(number <= 0xFFFF);
138   *pBuffer << "<";
139   char ans[4];
140   FXSYS_IntToFourHexChars(number, ans);
141   for (size_t i = 0; i < 4; ++i)
142     *pBuffer << ans[i];
143   *pBuffer << ">";
144 }
145 
146 // PDF spec 1.7 Section 5.9.2: "Unicode character sequences as expressed in
147 // UTF-16BE encoding." See https://en.wikipedia.org/wiki/UTF-16#Description
AddUnicode(std::ostringstream * pBuffer,uint32_t unicode)148 void AddUnicode(std::ostringstream* pBuffer, uint32_t unicode) {
149   if (unicode >= 0xD800 && unicode <= 0xDFFF)
150     unicode = 0;
151 
152   char ans[8];
153   *pBuffer << "<";
154   size_t numChars = FXSYS_ToUTF16BE(unicode, ans);
155   for (size_t i = 0; i < numChars; ++i)
156     *pBuffer << ans[i];
157   *pBuffer << ">";
158 }
159 
160 // Loads the charcode to unicode mapping into a stream
LoadUnicode(CPDF_Document * pDoc,const std::map<uint32_t,uint32_t> & to_unicode)161 CPDF_Stream* LoadUnicode(CPDF_Document* pDoc,
162                          const std::map<uint32_t, uint32_t>& to_unicode) {
163   // A map charcode->unicode
164   std::map<uint32_t, uint32_t> char_to_uni;
165   // A map <char_start, char_end> to vector v of unicode characters of size (end
166   // - start + 1). This abbreviates: start->v[0], start+1->v[1], etc. PDF spec
167   // 1.7 Section 5.9.2 says that only the last byte of the unicode may change.
168   std::map<std::pair<uint32_t, uint32_t>, std::vector<uint32_t>>
169       map_range_vector;
170   // A map <start, end> -> unicode
171   // This abbreviates: start->unicode, start+1->unicode+1, etc.
172   // PDF spec 1.7 Section 5.9.2 says that only the last byte of the unicode may
173   // change.
174   std::map<std::pair<uint32_t, uint32_t>, uint32_t> map_range;
175 
176   // Calculate the maps
177   for (auto iter = to_unicode.begin(); iter != to_unicode.end(); ++iter) {
178     uint32_t firstCharcode = iter->first;
179     uint32_t firstUnicode = iter->second;
180     if (std::next(iter) == to_unicode.end() ||
181         firstCharcode + 1 != std::next(iter)->first) {
182       char_to_uni[firstCharcode] = firstUnicode;
183       continue;
184     }
185     ++iter;
186     uint32_t curCharcode = iter->first;
187     uint32_t curUnicode = iter->second;
188     if (curCharcode % 256 == 0) {
189       char_to_uni[firstCharcode] = firstUnicode;
190       char_to_uni[curCharcode] = curUnicode;
191       continue;
192     }
193     const size_t maxExtra = 255 - (curCharcode % 256);
194     auto next_it = std::next(iter);
195     if (firstUnicode + 1 != curUnicode) {
196       // Consecutive charcodes mapping to non-consecutive unicodes
197       std::vector<uint32_t> unicodes;
198       unicodes.push_back(firstUnicode);
199       unicodes.push_back(curUnicode);
200       for (size_t i = 0; i < maxExtra; ++i) {
201         if (next_it == to_unicode.end() || curCharcode + 1 != next_it->first)
202           break;
203         ++iter;
204         ++curCharcode;
205         unicodes.push_back(iter->second);
206         next_it = std::next(iter);
207       }
208       ASSERT(iter->first - firstCharcode + 1 == unicodes.size());
209       map_range_vector[std::make_pair(firstCharcode, iter->first)] = unicodes;
210       continue;
211     }
212     // Consecutive charcodes mapping to consecutive unicodes
213     for (size_t i = 0; i < maxExtra; ++i) {
214       if (next_it == to_unicode.end() || curCharcode + 1 != next_it->first ||
215           curUnicode + 1 != next_it->second) {
216         break;
217       }
218       ++iter;
219       ++curCharcode;
220       ++curUnicode;
221       next_it = std::next(iter);
222     }
223     map_range[std::make_pair(firstCharcode, curCharcode)] = firstUnicode;
224   }
225   std::ostringstream buffer;
226   buffer << ToUnicodeStart;
227   // Add maps to buffer
228   buffer << static_cast<uint32_t>(char_to_uni.size()) << " beginbfchar\n";
229   for (const auto& iter : char_to_uni) {
230     AddCharcode(&buffer, iter.first);
231     buffer << " ";
232     AddUnicode(&buffer, iter.second);
233     buffer << "\n";
234   }
235   buffer << "endbfchar\n"
236          << static_cast<uint32_t>(map_range_vector.size() + map_range.size())
237          << " beginbfrange\n";
238   for (const auto& iter : map_range_vector) {
239     const std::pair<uint32_t, uint32_t>& charcodeRange = iter.first;
240     AddCharcode(&buffer, charcodeRange.first);
241     buffer << " ";
242     AddCharcode(&buffer, charcodeRange.second);
243     buffer << " [";
244     const std::vector<uint32_t>& unicodes = iter.second;
245     for (size_t i = 0; i < unicodes.size(); ++i) {
246       uint32_t uni = unicodes[i];
247       AddUnicode(&buffer, uni);
248       if (i != unicodes.size() - 1)
249         buffer << " ";
250     }
251     buffer << "]\n";
252   }
253   for (const auto& iter : map_range) {
254     const std::pair<uint32_t, uint32_t>& charcodeRange = iter.first;
255     AddCharcode(&buffer, charcodeRange.first);
256     buffer << " ";
257     AddCharcode(&buffer, charcodeRange.second);
258     buffer << " ";
259     AddUnicode(&buffer, iter.second);
260     buffer << "\n";
261   }
262   buffer << "endbfrange\n";
263   buffer << ToUnicodeEnd;
264   // TODO(npm): Encrypt / Compress?
265   CPDF_Stream* stream = pDoc->NewIndirect<CPDF_Stream>();
266   stream->SetDataFromStringstream(&buffer);
267   return stream;
268 }
269 
LoadSimpleFont(CPDF_Document * pDoc,std::unique_ptr<CFX_Font> pFont,pdfium::span<const uint8_t> span,int font_type)270 RetainPtr<CPDF_Font> LoadSimpleFont(CPDF_Document* pDoc,
271                                     std::unique_ptr<CFX_Font> pFont,
272                                     pdfium::span<const uint8_t> span,
273                                     int font_type) {
274   CPDF_Dictionary* pFontDict = pDoc->NewIndirect<CPDF_Dictionary>();
275   pFontDict->SetNewFor<CPDF_Name>("Type", "Font");
276   pFontDict->SetNewFor<CPDF_Name>(
277       "Subtype", font_type == FPDF_FONT_TYPE1 ? "Type1" : "TrueType");
278   ByteString name = pFont->GetBaseFontName(font_type == FPDF_FONT_TYPE1);
279   if (name.IsEmpty())
280     name = CFX_Font::kUntitledFontName;
281   pFontDict->SetNewFor<CPDF_Name>("BaseFont", name);
282 
283   uint32_t dwGlyphIndex;
284   uint32_t dwCurrentChar =
285       FT_Get_First_Char(pFont->GetFaceRec(), &dwGlyphIndex);
286   static constexpr uint32_t kMaxSimpleFontChar = 0xFF;
287   if (dwCurrentChar > kMaxSimpleFontChar || dwGlyphIndex == 0)
288     return nullptr;
289   pFontDict->SetNewFor<CPDF_Number>("FirstChar",
290                                     static_cast<int>(dwCurrentChar));
291   CPDF_Array* widthsArray = pDoc->NewIndirect<CPDF_Array>();
292   while (true) {
293     uint32_t width =
294         std::min(pFont->GetGlyphWidth(dwGlyphIndex),
295                  static_cast<uint32_t>(std::numeric_limits<int>::max()));
296     widthsArray->AddNew<CPDF_Number>(static_cast<int>(width));
297     uint32_t nextChar =
298         FT_Get_Next_Char(pFont->GetFaceRec(), dwCurrentChar, &dwGlyphIndex);
299     // Simple fonts have 1-byte charcodes only.
300     if (nextChar > kMaxSimpleFontChar || dwGlyphIndex == 0)
301       break;
302     for (uint32_t i = dwCurrentChar + 1; i < nextChar; i++)
303       widthsArray->AddNew<CPDF_Number>(0);
304     dwCurrentChar = nextChar;
305   }
306   pFontDict->SetNewFor<CPDF_Number>("LastChar",
307                                     static_cast<int>(dwCurrentChar));
308   pFontDict->SetNewFor<CPDF_Reference>("Widths", pDoc,
309                                        widthsArray->GetObjNum());
310   CPDF_Dictionary* pFontDesc =
311       LoadFontDesc(pDoc, name, pFont.get(), span, font_type);
312 
313   pFontDict->SetNewFor<CPDF_Reference>("FontDescriptor", pDoc,
314                                        pFontDesc->GetObjNum());
315   return CPDF_DocPageData::FromDocument(pDoc)->GetFont(pFontDict);
316 }
317 
LoadCompositeFont(CPDF_Document * pDoc,std::unique_ptr<CFX_Font> pFont,pdfium::span<const uint8_t> span,int font_type)318 RetainPtr<CPDF_Font> LoadCompositeFont(CPDF_Document* pDoc,
319                                        std::unique_ptr<CFX_Font> pFont,
320                                        pdfium::span<const uint8_t> span,
321                                        int font_type) {
322   CPDF_Dictionary* pFontDict = pDoc->NewIndirect<CPDF_Dictionary>();
323   pFontDict->SetNewFor<CPDF_Name>("Type", "Font");
324   pFontDict->SetNewFor<CPDF_Name>("Subtype", "Type0");
325   // TODO(npm): Get the correct encoding, if it's not identity.
326   ByteString encoding = "Identity-H";
327   pFontDict->SetNewFor<CPDF_Name>("Encoding", encoding);
328   ByteString name = pFont->GetBaseFontName(font_type == FPDF_FONT_TYPE1);
329   if (name.IsEmpty())
330     name = CFX_Font::kUntitledFontName;
331   pFontDict->SetNewFor<CPDF_Name>(
332       "BaseFont", font_type == FPDF_FONT_TYPE1 ? name + "-" + encoding : name);
333 
334   CPDF_Dictionary* pCIDFont = pDoc->NewIndirect<CPDF_Dictionary>();
335   pCIDFont->SetNewFor<CPDF_Name>("Type", "Font");
336   pCIDFont->SetNewFor<CPDF_Name>("Subtype", font_type == FPDF_FONT_TYPE1
337                                                 ? "CIDFontType0"
338                                                 : "CIDFontType2");
339   pCIDFont->SetNewFor<CPDF_Name>("BaseFont", name);
340 
341   // TODO(npm): Maybe use FT_Get_CID_Registry_Ordering_Supplement to get the
342   // CIDSystemInfo
343   CPDF_Dictionary* pCIDSystemInfo = pDoc->NewIndirect<CPDF_Dictionary>();
344   pCIDSystemInfo->SetNewFor<CPDF_String>("Registry", "Adobe", false);
345   pCIDSystemInfo->SetNewFor<CPDF_String>("Ordering", "Identity", false);
346   pCIDSystemInfo->SetNewFor<CPDF_Number>("Supplement", 0);
347   pCIDFont->SetNewFor<CPDF_Reference>("CIDSystemInfo", pDoc,
348                                       pCIDSystemInfo->GetObjNum());
349 
350   CPDF_Dictionary* pFontDesc =
351       LoadFontDesc(pDoc, name, pFont.get(), span, font_type);
352   pCIDFont->SetNewFor<CPDF_Reference>("FontDescriptor", pDoc,
353                                       pFontDesc->GetObjNum());
354 
355   uint32_t dwGlyphIndex;
356   uint32_t dwCurrentChar =
357       FT_Get_First_Char(pFont->GetFaceRec(), &dwGlyphIndex);
358   static constexpr uint32_t kMaxUnicode = 0x10FFFF;
359   // If it doesn't have a single char, just fail
360   if (dwGlyphIndex == 0 || dwCurrentChar > kMaxUnicode)
361     return nullptr;
362 
363   std::map<uint32_t, uint32_t> to_unicode;
364   std::map<uint32_t, uint32_t> widths;
365   while (true) {
366     if (dwCurrentChar > kMaxUnicode)
367       break;
368 
369     if (!pdfium::ContainsKey(widths, dwGlyphIndex))
370       widths[dwGlyphIndex] = pFont->GetGlyphWidth(dwGlyphIndex);
371     to_unicode[dwGlyphIndex] = dwCurrentChar;
372     dwCurrentChar =
373         FT_Get_Next_Char(pFont->GetFaceRec(), dwCurrentChar, &dwGlyphIndex);
374     if (dwGlyphIndex == 0)
375       break;
376   }
377   CPDF_Array* widthsArray = pDoc->NewIndirect<CPDF_Array>();
378   for (auto it = widths.begin(); it != widths.end(); ++it) {
379     int ch = it->first;
380     int w = it->second;
381     if (std::next(it) == widths.end()) {
382       // Only one char left, use format c [w]
383       auto oneW = pdfium::MakeRetain<CPDF_Array>();
384       oneW->AddNew<CPDF_Number>(w);
385       widthsArray->AddNew<CPDF_Number>(ch);
386       widthsArray->Add(oneW);
387       break;
388     }
389     ++it;
390     int next_ch = it->first;
391     int next_w = it->second;
392     if (next_ch == ch + 1 && next_w == w) {
393       // The array can have a group c_first c_last w: all CIDs in the range from
394       // c_first to c_last will have width w
395       widthsArray->AddNew<CPDF_Number>(ch);
396       ch = next_ch;
397       while (true) {
398         auto next_it = std::next(it);
399         if (next_it == widths.end() || next_it->first != it->first + 1 ||
400             next_it->second != it->second) {
401           break;
402         }
403         ++it;
404         ch = it->first;
405       }
406       widthsArray->AddNew<CPDF_Number>(ch);
407       widthsArray->AddNew<CPDF_Number>(w);
408       continue;
409     }
410     // Otherwise we can have a group of the form c [w1 w2 ...]: c has width
411     // w1, c+1 has width w2, etc.
412     widthsArray->AddNew<CPDF_Number>(ch);
413     auto curWidthArray = pdfium::MakeRetain<CPDF_Array>();
414     curWidthArray->AddNew<CPDF_Number>(w);
415     curWidthArray->AddNew<CPDF_Number>(next_w);
416     while (true) {
417       auto next_it = std::next(it);
418       if (next_it == widths.end() || next_it->first != it->first + 1)
419         break;
420       ++it;
421       curWidthArray->AddNew<CPDF_Number>(static_cast<int>(it->second));
422     }
423     widthsArray->Add(curWidthArray);
424   }
425   pCIDFont->SetNewFor<CPDF_Reference>("W", pDoc, widthsArray->GetObjNum());
426 
427   // TODO(npm): Support vertical writing
428 
429   auto* pDescendant = pFontDict->SetNewFor<CPDF_Array>("DescendantFonts");
430   pDescendant->AddNew<CPDF_Reference>(pDoc, pCIDFont->GetObjNum());
431 
432   CPDF_Stream* toUnicodeStream = LoadUnicode(pDoc, to_unicode);
433   pFontDict->SetNewFor<CPDF_Reference>("ToUnicode", pDoc,
434                                        toUnicodeStream->GetObjNum());
435   return CPDF_DocPageData::FromDocument(pDoc)->GetFont(pFontDict);
436 }
437 
CPDFTextObjectFromFPDFPageObject(FPDF_PAGEOBJECT page_object)438 CPDF_TextObject* CPDFTextObjectFromFPDFPageObject(FPDF_PAGEOBJECT page_object) {
439   auto* obj = CPDFPageObjectFromFPDFPageObject(page_object);
440   return obj ? obj->AsText() : nullptr;
441 }
442 
443 }  // namespace
444 
445 FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV
FPDFPageObj_NewTextObj(FPDF_DOCUMENT document,FPDF_BYTESTRING font,float font_size)446 FPDFPageObj_NewTextObj(FPDF_DOCUMENT document,
447                        FPDF_BYTESTRING font,
448                        float font_size) {
449   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
450   if (!pDoc)
451     return nullptr;
452 
453   RetainPtr<CPDF_Font> pFont =
454       CPDF_Font::GetStockFont(pDoc, ByteStringView(font));
455   if (!pFont)
456     return nullptr;
457 
458   auto pTextObj = pdfium::MakeUnique<CPDF_TextObject>();
459   pTextObj->m_TextState.SetFont(pFont);
460   pTextObj->m_TextState.SetFontSize(font_size);
461   pTextObj->DefaultStates();
462 
463   // Caller takes ownership.
464   return FPDFPageObjectFromCPDFPageObject(pTextObj.release());
465 }
466 
467 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFText_SetText(FPDF_PAGEOBJECT text_object,FPDF_WIDESTRING text)468 FPDFText_SetText(FPDF_PAGEOBJECT text_object, FPDF_WIDESTRING text) {
469   CPDF_TextObject* pTextObj = CPDFTextObjectFromFPDFPageObject(text_object);
470   if (!pTextObj)
471     return false;
472 
473   WideString encodedText = WideStringFromFPDFWideString(text);
474   ByteString byteText;
475   for (wchar_t wc : encodedText) {
476     pTextObj->GetFont()->AppendChar(
477         &byteText, pTextObj->GetFont()->CharCodeFromUnicode(wc));
478   }
479   pTextObj->SetText(byteText);
480   return true;
481 }
482 
FPDFText_LoadFont(FPDF_DOCUMENT document,const uint8_t * data,uint32_t size,int font_type,FPDF_BOOL cid)483 FPDF_EXPORT FPDF_FONT FPDF_CALLCONV FPDFText_LoadFont(FPDF_DOCUMENT document,
484                                                       const uint8_t* data,
485                                                       uint32_t size,
486                                                       int font_type,
487                                                       FPDF_BOOL cid) {
488   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
489   if (!pDoc || !data || size == 0 ||
490       (font_type != FPDF_FONT_TYPE1 && font_type != FPDF_FONT_TRUETYPE)) {
491     return nullptr;
492   }
493 
494   auto span = pdfium::make_span(data, size);
495   auto pFont = pdfium::MakeUnique<CFX_Font>();
496 
497   // TODO(npm): Maybe use FT_Get_X11_Font_Format to check format? Otherwise, we
498   // are allowing giving any font that can be loaded on freetype and setting it
499   // as any font type.
500   if (!pFont->LoadEmbedded(span, false))
501     return nullptr;
502 
503   // Caller takes ownership.
504   return FPDFFontFromCPDFFont(
505       cid ? LoadCompositeFont(pDoc, std::move(pFont), span, font_type).Leak()
506           : LoadSimpleFont(pDoc, std::move(pFont), span, font_type).Leak());
507 }
508 
509 FPDF_EXPORT FPDF_FONT FPDF_CALLCONV
FPDFText_LoadStandardFont(FPDF_DOCUMENT document,FPDF_BYTESTRING font)510 FPDFText_LoadStandardFont(FPDF_DOCUMENT document, FPDF_BYTESTRING font) {
511   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
512   if (!pDoc)
513     return nullptr;
514 
515   // Caller takes ownership.
516   return FPDFFontFromCPDFFont(
517       CPDF_Font::GetStockFont(pDoc, ByteStringView(font)).Leak());
518 }
519 
FPDFTextObj_GetMatrix(FPDF_PAGEOBJECT text,FS_MATRIX * matrix)520 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFTextObj_GetMatrix(FPDF_PAGEOBJECT text,
521                                                           FS_MATRIX* matrix) {
522   if (!matrix)
523     return false;
524 
525   CPDF_TextObject* pTextObj = CPDFTextObjectFromFPDFPageObject(text);
526   if (!pTextObj)
527     return false;
528 
529   *matrix = FSMatrixFromCFXMatrix(pTextObj->GetTextMatrix());
530   return true;
531 }
532 
FPDFTextObj_GetFontSize(FPDF_PAGEOBJECT text)533 FPDF_EXPORT float FPDF_CALLCONV FPDFTextObj_GetFontSize(FPDF_PAGEOBJECT text) {
534   CPDF_TextObject* pTextObj = CPDFTextObjectFromFPDFPageObject(text);
535   return pTextObj ? pTextObj->GetFontSize() : 0.0f;
536 }
537 
538 FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDFTextObj_GetFontName(FPDF_PAGEOBJECT text,void * buffer,unsigned long length)539 FPDFTextObj_GetFontName(FPDF_PAGEOBJECT text,
540                         void* buffer,
541                         unsigned long length) {
542   CPDF_TextObject* pTextObj = CPDFTextObjectFromFPDFPageObject(text);
543   if (!pTextObj)
544     return 0;
545 
546   RetainPtr<CPDF_Font> pPdfFont = pTextObj->GetFont();
547   CFX_Font* pFont = pPdfFont->GetFont();
548   ByteString name = pFont->GetFamilyName();
549   unsigned long dwStringLen = name.GetLength() + 1;
550   if (buffer && length >= dwStringLen)
551     memcpy(buffer, name.c_str(), dwStringLen);
552 
553   return dwStringLen;
554 }
555 
556 FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDFTextObj_GetText(FPDF_PAGEOBJECT text_object,FPDF_TEXTPAGE text_page,void * buffer,unsigned long length)557 FPDFTextObj_GetText(FPDF_PAGEOBJECT text_object,
558                     FPDF_TEXTPAGE text_page,
559                     void* buffer,
560                     unsigned long length) {
561   CPDF_TextObject* pTextObj = CPDFTextObjectFromFPDFPageObject(text_object);
562   if (!pTextObj)
563     return 0;
564 
565   CPDF_TextPage* pTextPage = CPDFTextPageFromFPDFTextPage(text_page);
566   if (!pTextPage)
567     return 0;
568 
569   WideString text = pTextPage->GetTextByObject(pTextObj);
570   return Utf16EncodeMaybeCopyAndReturnLength(text, buffer, length);
571 }
572 
FPDFFont_Close(FPDF_FONT font)573 FPDF_EXPORT void FPDF_CALLCONV FPDFFont_Close(FPDF_FONT font) {
574   // Take back ownership from caller and release.
575   RetainPtr<CPDF_Font>().Unleak(CPDFFontFromFPDFFont(font));
576 }
577 
578 FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV
FPDFPageObj_CreateTextObj(FPDF_DOCUMENT document,FPDF_FONT font,float font_size)579 FPDFPageObj_CreateTextObj(FPDF_DOCUMENT document,
580                           FPDF_FONT font,
581                           float font_size) {
582   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
583   CPDF_Font* pFont = CPDFFontFromFPDFFont(font);
584   if (!pDoc || !pFont)
585     return nullptr;
586 
587   auto pTextObj = pdfium::MakeUnique<CPDF_TextObject>();
588   pTextObj->m_TextState.SetFont(
589       CPDF_DocPageData::FromDocument(pDoc)->GetFont(pFont->GetFontDict()));
590   pTextObj->m_TextState.SetFontSize(font_size);
591   pTextObj->DefaultStates();
592   return FPDFPageObjectFromCPDFPageObject(pTextObj.release());
593 }
594 
595 FPDF_EXPORT FPDF_TEXT_RENDERMODE FPDF_CALLCONV
FPDFTextObj_GetTextRenderMode(FPDF_PAGEOBJECT text)596 FPDFTextObj_GetTextRenderMode(FPDF_PAGEOBJECT text) {
597   CPDF_TextObject* pTextObj = CPDFTextObjectFromFPDFPageObject(text);
598   if (!pTextObj)
599     return FPDF_TEXTRENDERMODE_UNKNOWN;
600   return static_cast<FPDF_TEXT_RENDERMODE>(pTextObj->m_TextState.GetTextMode());
601 }
602 
603 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFTextObj_SetTextRenderMode(FPDF_PAGEOBJECT text,FPDF_TEXT_RENDERMODE render_mode)604 FPDFTextObj_SetTextRenderMode(FPDF_PAGEOBJECT text,
605                               FPDF_TEXT_RENDERMODE render_mode) {
606   if (render_mode <= FPDF_TEXTRENDERMODE_UNKNOWN ||
607       render_mode > FPDF_TEXTRENDERMODE_LAST) {
608     return false;
609   }
610 
611   CPDF_TextObject* pTextObj = CPDFTextObjectFromFPDFPageObject(text);
612   if (!pTextObj)
613     return false;
614 
615   pTextObj->m_TextState.SetTextMode(
616       static_cast<TextRenderingMode>(render_mode));
617   return true;
618 }
619