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