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