blob: cfb44f513d435c3eaf3e048167656e5b7c17259d [file] [log] [blame]
Nicolas Pena49058402017-02-14 18:26:20 -05001// 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
Nicolas Penaf45ade32017-05-03 10:23:49 -04005#include <map>
Nicolas Penad03ca422017-03-06 13:54:33 -05006#include <memory>
Nicolas Penabe90aae2017-02-27 10:41:41 -05007#include <utility>
Nicolas Penaf45ade32017-05-03 10:23:49 -04008#include <vector>
Nicolas Pena49058402017-02-14 18:26:20 -05009
10#include "core/fpdfapi/cpdf_modulemgr.h"
11#include "core/fpdfapi/font/cpdf_font.h"
Nicolas Penabe90aae2017-02-27 10:41:41 -050012#include "core/fpdfapi/font/cpdf_type1font.h"
Nicolas Penab3161852017-05-02 14:12:50 -040013#include "core/fpdfapi/page/cpdf_docpagedata.h"
Nicolas Pena49058402017-02-14 18:26:20 -050014#include "core/fpdfapi/page/cpdf_textobject.h"
Nicolas Penabe90aae2017-02-27 10:41:41 -050015#include "core/fpdfapi/parser/cpdf_array.h"
16#include "core/fpdfapi/parser/cpdf_dictionary.h"
17#include "core/fpdfapi/parser/cpdf_document.h"
18#include "core/fpdfapi/parser/cpdf_name.h"
19#include "core/fpdfapi/parser/cpdf_number.h"
20#include "core/fpdfapi/parser/cpdf_reference.h"
21#include "core/fpdfapi/parser/cpdf_stream.h"
22#include "core/fxge/cfx_fontmgr.h"
23#include "core/fxge/fx_font.h"
Nicolas Pena49058402017-02-14 18:26:20 -050024#include "fpdfsdk/fsdk_define.h"
Nicolas Penabe90aae2017-02-27 10:41:41 -050025#include "public/fpdf_edit.h"
Nicolas Pena49058402017-02-14 18:26:20 -050026
Nicolas Penad03ca422017-03-06 13:54:33 -050027namespace {
28
29CPDF_Dictionary* LoadFontDesc(CPDF_Document* pDoc,
30 const CFX_ByteString& font_name,
31 CFX_Font* pFont,
32 const uint8_t* data,
33 uint32_t size,
34 int font_type) {
35 CPDF_Dictionary* fontDesc = pDoc->NewIndirect<CPDF_Dictionary>();
36 fontDesc->SetNewFor<CPDF_Name>("Type", "FontDescriptor");
37 fontDesc->SetNewFor<CPDF_Name>("FontName", font_name);
38 int flags = 0;
39 if (FXFT_Is_Face_fixedwidth(pFont->GetFace()))
40 flags |= FXFONT_FIXED_PITCH;
41 if (font_name.Find("Serif") > -1)
42 flags |= FXFONT_SERIF;
43 if (FXFT_Is_Face_Italic(pFont->GetFace()))
44 flags |= FXFONT_ITALIC;
45 if (FXFT_Is_Face_Bold(pFont->GetFace()))
46 flags |= FXFONT_BOLD;
47
48 // TODO(npm): How do I know if a font is symbolic, script, allcap, smallcap
49 flags |= FXFONT_NONSYMBOLIC;
50
51 fontDesc->SetNewFor<CPDF_Number>("Flags", flags);
52 FX_RECT bbox;
53 pFont->GetBBox(bbox);
54 auto pBBox = pdfium::MakeUnique<CPDF_Array>();
55 pBBox->AddNew<CPDF_Number>(bbox.left);
56 pBBox->AddNew<CPDF_Number>(bbox.bottom);
57 pBBox->AddNew<CPDF_Number>(bbox.right);
58 pBBox->AddNew<CPDF_Number>(bbox.top);
59 fontDesc->SetFor("FontBBox", std::move(pBBox));
60
61 // TODO(npm): calculate italic angle correctly
62 fontDesc->SetNewFor<CPDF_Number>("ItalicAngle", pFont->IsItalic() ? -12 : 0);
63
64 fontDesc->SetNewFor<CPDF_Number>("Ascent", pFont->GetAscent());
65 fontDesc->SetNewFor<CPDF_Number>("Descent", pFont->GetDescent());
66
67 // TODO(npm): calculate the capheight, stemV correctly
68 fontDesc->SetNewFor<CPDF_Number>("CapHeight", pFont->GetAscent());
69 fontDesc->SetNewFor<CPDF_Number>("StemV", pFont->IsBold() ? 120 : 70);
70
71 CPDF_Stream* pStream = pDoc->NewIndirect<CPDF_Stream>();
72 pStream->SetData(data, size);
73 CFX_ByteString fontFile =
74 font_type == FPDF_FONT_TYPE1 ? "FontFile" : "FontFile2";
75 fontDesc->SetNewFor<CPDF_Reference>(fontFile, pDoc, pStream->GetObjNum());
76 return fontDesc;
77}
78
Nicolas Penaf45ade32017-05-03 10:23:49 -040079const char ToUnicodeStart[] =
80 "/CIDInit /ProcSet findresource begin\n"
81 "12 dict begin\n"
82 "begincmap\n"
83 "/CIDSystemInfo\n"
84 "<</Registry (Adobe)\n"
85 "/Ordering (Identity)\n"
86 "/Supplement 0\n"
87 ">> def\n"
88 "/CMapName /Adobe-Identity-H def\n"
89 "CMapType 2 def\n"
90 "1 begincodespacerange\n"
91 "<0000> <FFFFF>\n";
92
93const char hex[] = "0123456789ABCDEF";
94
95void AddNum(CFX_ByteTextBuf* pBuffer, uint32_t number) {
96 *pBuffer << "<";
97 char ans[4];
98 for (size_t i = 0; i < 4; ++i) {
99 ans[3 - i] = hex[number % 16];
100 number /= 16;
101 }
102 for (size_t i = 0; i < 4; ++i)
103 pBuffer->AppendChar(ans[i]);
104 *pBuffer << ">";
105}
106
107// Loads the charcode to unicode mapping into a stream
108CPDF_Stream* LoadUnicode(CPDF_Document* pDoc,
109 const std::map<uint32_t, uint32_t>& to_unicode) {
110 CFX_ByteTextBuf buffer;
111 buffer << ToUnicodeStart;
112 // A map charcode->unicode
113 std::map<uint32_t, uint32_t> char_to_uni;
114 // A map <char_start, char_end> to vector v of unicode characters of size (end
115 // - start + 1). This abbreviates: start->v[0], start+1->v[1], etc. PDF spec
116 // 1.7 Section 5.9.2 says that only the last byte of the unicode may change.
117 std::map<std::pair<uint32_t, uint32_t>, std::vector<uint32_t>>
118 map_range_vector;
119 // A map <start, end> -> unicode
120 // This abbreviates: start->unicode, start+1->unicode+1, etc.
121 // PDF spec 1.7 Section 5.9.2 says that only the last byte of the unicode may
122 // change.
123 std::map<std::pair<uint32_t, uint32_t>, uint32_t> map_range;
124
125 // Calculate the maps
126 for (auto iter = to_unicode.begin(); iter != to_unicode.end(); ++iter) {
127 uint32_t firstCharcode = iter->first;
128 uint32_t firstUnicode = iter->second;
129 if (std::next(iter) == to_unicode.end() ||
130 firstCharcode + 1 != std::next(iter)->first) {
131 char_to_uni[firstCharcode] = firstUnicode;
132 continue;
133 }
134 ++iter;
135 uint32_t curCharcode = iter->first;
136 uint32_t curUnicode = iter->second;
137 if (curCharcode % 256 == 0) {
138 char_to_uni[firstCharcode] = firstUnicode;
139 char_to_uni[curCharcode] = curUnicode;
140 continue;
141 }
142 const size_t maxExtra = 255 - (curCharcode % 256);
143 auto next_it = std::next(iter);
144 if (firstUnicode + 1 != curUnicode) {
145 // Consecutive charcodes mapping to non-consecutive unicodes
146 std::vector<uint32_t> unicodes;
147 unicodes.push_back(firstUnicode);
148 unicodes.push_back(curUnicode);
149 for (size_t i = 0; i < maxExtra; ++i) {
150 if (next_it == to_unicode.end() || curCharcode + 1 != next_it->first)
151 break;
152 ++iter;
153 ++curCharcode;
154 unicodes.push_back(iter->second);
155 next_it = std::next(iter);
156 }
157 ASSERT(iter->first - firstCharcode + 1 == unicodes.size());
158 map_range_vector[std::make_pair(firstCharcode, iter->first)] = unicodes;
159 continue;
160 }
161 // Consecutive charcodes mapping to consecutive unicodes
162 for (size_t i = 0; i < maxExtra; ++i) {
163 if (next_it == to_unicode.end() || curCharcode + 1 != next_it->first ||
164 curUnicode + 1 != next_it->second) {
165 break;
166 }
167 ++iter;
168 ++curCharcode;
169 ++curUnicode;
170 next_it = std::next(iter);
171 }
172 map_range[std::make_pair(firstCharcode, curCharcode)] = firstUnicode;
173 }
174 // Add maps to buffer
175 buffer << static_cast<uint32_t>(char_to_uni.size()) << " beginbfchar\n";
176 for (auto iter : char_to_uni) {
177 AddNum(&buffer, iter.first);
178 buffer << " ";
179 AddNum(&buffer, iter.second);
180 buffer << "\n";
181 }
182 buffer << "endbfchar\n"
183 << static_cast<uint32_t>(map_range_vector.size() + map_range.size())
184 << " beginbfrange\n";
185 for (auto iter : map_range_vector) {
186 const std::pair<uint32_t, uint32_t>& charcodeRange = iter.first;
187 AddNum(&buffer, charcodeRange.first);
188 buffer << " ";
189 AddNum(&buffer, charcodeRange.second);
190 buffer << " [";
191 const std::vector<uint32_t>& unicodes = iter.second;
192 for (size_t i = 0; i < unicodes.size(); ++i) {
193 uint32_t uni = unicodes[i];
194 AddNum(&buffer, uni);
195 if (i != unicodes.size() - 1)
196 buffer << " ";
197 }
198 buffer << "]\n";
199 }
200 for (auto iter : map_range) {
201 const std::pair<uint32_t, uint32_t>& charcodeRange = iter.first;
202 AddNum(&buffer, charcodeRange.first);
203 buffer << " ";
204 AddNum(&buffer, charcodeRange.second);
205 buffer << " ";
206 AddNum(&buffer, iter.second);
207 buffer << "\n";
208 }
209 // TODO(npm): Encrypt / Compress?
210 uint32_t bufferSize = buffer.GetSize();
211 auto pDict = pdfium::MakeUnique<CPDF_Dictionary>();
212 pDict->SetNewFor<CPDF_Number>("Length", static_cast<int>(bufferSize));
213 return pDoc->NewIndirect<CPDF_Stream>(buffer.DetachBuffer(), bufferSize,
214 std::move(pDict));
215}
216
Nicolas Penad03ca422017-03-06 13:54:33 -0500217void* LoadSimpleFont(CPDF_Document* pDoc,
218 std::unique_ptr<CFX_Font> pFont,
219 const uint8_t* data,
220 uint32_t size,
221 int font_type) {
222 CPDF_Dictionary* fontDict = pDoc->NewIndirect<CPDF_Dictionary>();
223 fontDict->SetNewFor<CPDF_Name>("Type", "Font");
224 fontDict->SetNewFor<CPDF_Name>(
225 "Subtype", font_type == FPDF_FONT_TYPE1 ? "Type1" : "TrueType");
226 CFX_ByteString name = pFont->GetFaceName();
227 if (name.IsEmpty())
228 name = "Unnamed";
229 fontDict->SetNewFor<CPDF_Name>("BaseFont", name);
230
231 uint32_t glyphIndex;
232 int currentChar = FXFT_Get_First_Char(pFont->GetFace(), &glyphIndex);
233 fontDict->SetNewFor<CPDF_Number>("FirstChar", currentChar);
234 CPDF_Array* widthsArray = pDoc->NewIndirect<CPDF_Array>();
235 while (true) {
Nicolas Penaf45ade32017-05-03 10:23:49 -0400236 widthsArray->AddNew<CPDF_Number>(pFont->GetGlyphWidth(glyphIndex));
Nicolas Penad03ca422017-03-06 13:54:33 -0500237 int nextChar =
238 FXFT_Get_Next_Char(pFont->GetFace(), currentChar, &glyphIndex);
239 // Simple fonts have 1-byte charcodes only.
240 if (nextChar > 0xff || glyphIndex == 0)
241 break;
242 for (int i = currentChar + 1; i < nextChar; i++)
243 widthsArray->AddNew<CPDF_Number>(0);
244 currentChar = nextChar;
245 }
246 fontDict->SetNewFor<CPDF_Number>("LastChar", currentChar);
247 fontDict->SetNewFor<CPDF_Reference>("Widths", pDoc, widthsArray->GetObjNum());
248 CPDF_Dictionary* fontDesc =
249 LoadFontDesc(pDoc, name, pFont.get(), data, size, font_type);
250
251 fontDict->SetNewFor<CPDF_Reference>("FontDescriptor", pDoc,
252 fontDesc->GetObjNum());
253 return pDoc->LoadFont(fontDict);
254}
255
256void* LoadCompositeFont(CPDF_Document* pDoc,
257 std::unique_ptr<CFX_Font> pFont,
258 const uint8_t* data,
259 uint32_t size,
260 int font_type) {
261 CPDF_Dictionary* fontDict = pDoc->NewIndirect<CPDF_Dictionary>();
262 fontDict->SetNewFor<CPDF_Name>("Type", "Font");
263 fontDict->SetNewFor<CPDF_Name>("Subtype", "Type0");
264 // TODO(npm): Get the correct encoding, if it's not identity.
265 CFX_ByteString encoding = "Identity-H";
266 fontDict->SetNewFor<CPDF_Name>("Encoding", encoding);
267 CFX_ByteString name = pFont->GetFaceName();
268 if (name.IsEmpty())
269 name = "Unnamed";
270 fontDict->SetNewFor<CPDF_Name>(
271 "BaseFont", font_type == FPDF_FONT_TYPE1 ? name + "-" + encoding : name);
272
273 CPDF_Dictionary* pCIDFont = pDoc->NewIndirect<CPDF_Dictionary>();
274 pCIDFont->SetNewFor<CPDF_Name>("Type", "Font");
275 pCIDFont->SetNewFor<CPDF_Name>("Subtype", font_type == FPDF_FONT_TYPE1
276 ? "CIDFontType0"
277 : "CIDFontType2");
278 pCIDFont->SetNewFor<CPDF_Name>("BaseFont", name);
279
280 // TODO(npm): Maybe use FT_Get_CID_Registry_Ordering_Supplement to get the
281 // CIDSystemInfo
282 CPDF_Dictionary* pCIDSystemInfo = pDoc->NewIndirect<CPDF_Dictionary>();
283 pCIDSystemInfo->SetNewFor<CPDF_Name>("Registry", "Adobe");
284 pCIDSystemInfo->SetNewFor<CPDF_Name>("Ordering", "Identity");
285 pCIDSystemInfo->SetNewFor<CPDF_Number>("Supplement", 0);
286 pCIDFont->SetNewFor<CPDF_Reference>("CIDSystemInfo", pDoc,
287 pCIDSystemInfo->GetObjNum());
288
289 CPDF_Dictionary* fontDesc =
290 LoadFontDesc(pDoc, name, pFont.get(), data, size, font_type);
291 pCIDFont->SetNewFor<CPDF_Reference>("FontDescriptor", pDoc,
292 fontDesc->GetObjNum());
293
294 uint32_t glyphIndex;
295 int currentChar = FXFT_Get_First_Char(pFont->GetFace(), &glyphIndex);
Nicolas Penaf45ade32017-05-03 10:23:49 -0400296 // If it doesn't have a single char, just fail
297 if (glyphIndex == 0)
298 return nullptr;
299
300 std::map<uint32_t, uint32_t> to_unicode;
301 std::map<uint32_t, uint32_t> widths;
Nicolas Penad03ca422017-03-06 13:54:33 -0500302 while (true) {
Nicolas Penaf45ade32017-05-03 10:23:49 -0400303 widths[glyphIndex] = pFont->GetGlyphWidth(glyphIndex);
304 to_unicode[glyphIndex] = currentChar;
305 currentChar =
Nicolas Penad03ca422017-03-06 13:54:33 -0500306 FXFT_Get_Next_Char(pFont->GetFace(), currentChar, &glyphIndex);
Nicolas Penaf45ade32017-05-03 10:23:49 -0400307 if (glyphIndex == 0)
308 break;
309 }
310 CPDF_Array* widthsArray = pDoc->NewIndirect<CPDF_Array>();
311 for (auto it = widths.begin(); it != widths.end(); ++it) {
312 int ch = it->first;
313 int w = it->second;
314 if (std::next(it) == widths.end()) {
Nicolas Penad03ca422017-03-06 13:54:33 -0500315 // Only one char left, use format c [w]
316 auto oneW = pdfium::MakeUnique<CPDF_Array>();
Nicolas Penaf45ade32017-05-03 10:23:49 -0400317 oneW->AddNew<CPDF_Number>(w);
318 widthsArray->AddNew<CPDF_Number>(ch);
Nicolas Penad03ca422017-03-06 13:54:33 -0500319 widthsArray->Add(std::move(oneW));
320 break;
321 }
Nicolas Penaf45ade32017-05-03 10:23:49 -0400322 ++it;
323 int next_ch = it->first;
324 int next_w = it->second;
325 if (next_ch == ch + 1 && next_w == w) {
Nicolas Penad03ca422017-03-06 13:54:33 -0500326 // The array can have a group c_first c_last w: all CIDs in the range from
327 // c_first to c_last will have width w
Nicolas Penaf45ade32017-05-03 10:23:49 -0400328 widthsArray->AddNew<CPDF_Number>(ch);
329 ch = next_ch;
Nicolas Penad03ca422017-03-06 13:54:33 -0500330 while (true) {
Nicolas Penaf45ade32017-05-03 10:23:49 -0400331 auto next_it = std::next(it);
332 if (next_it == widths.end() || next_it->first != it->first + 1 ||
333 next_it->second != it->second) {
Nicolas Penad03ca422017-03-06 13:54:33 -0500334 break;
Nicolas Penaf45ade32017-05-03 10:23:49 -0400335 }
336 ++it;
337 ch = it->first;
Nicolas Penad03ca422017-03-06 13:54:33 -0500338 }
Nicolas Penaf45ade32017-05-03 10:23:49 -0400339 widthsArray->AddNew<CPDF_Number>(ch);
340 widthsArray->AddNew<CPDF_Number>(w);
341 continue;
Nicolas Penad03ca422017-03-06 13:54:33 -0500342 }
Nicolas Penaf45ade32017-05-03 10:23:49 -0400343 // Otherwise we can have a group of the form c [w1 w2 ...]: c has width
344 // w1, c+1 has width w2, etc.
345 widthsArray->AddNew<CPDF_Number>(ch);
346 auto curWidthArray = pdfium::MakeUnique<CPDF_Array>();
347 curWidthArray->AddNew<CPDF_Number>(w);
348 curWidthArray->AddNew<CPDF_Number>(next_w);
349 while (true) {
350 auto next_it = std::next(it);
351 if (next_it == widths.end() || next_it->first != it->first + 1)
352 break;
353 ++it;
354 curWidthArray->AddNew<CPDF_Number>(static_cast<int>(it->second));
355 }
356 widthsArray->Add(std::move(curWidthArray));
Nicolas Penad03ca422017-03-06 13:54:33 -0500357 }
358 pCIDFont->SetNewFor<CPDF_Reference>("W", pDoc, widthsArray->GetObjNum());
359 // TODO(npm): Support vertical writing
360
361 auto pDescendant = pdfium::MakeUnique<CPDF_Array>();
362 pDescendant->AddNew<CPDF_Reference>(pDoc, pCIDFont->GetObjNum());
363 fontDict->SetFor("DescendantFonts", std::move(pDescendant));
Nicolas Penaf45ade32017-05-03 10:23:49 -0400364 CPDF_Stream* toUnicodeStream = LoadUnicode(pDoc, to_unicode);
365 fontDict->SetNewFor<CPDF_Reference>("ToUnicode", pDoc,
366 toUnicodeStream->GetObjNum());
Nicolas Penad03ca422017-03-06 13:54:33 -0500367 return pDoc->LoadFont(fontDict);
368}
369
370} // namespace
371
Nicolas Pena49058402017-02-14 18:26:20 -0500372DLLEXPORT FPDF_PAGEOBJECT STDCALL FPDFPageObj_NewTextObj(FPDF_DOCUMENT document,
373 FPDF_BYTESTRING font,
374 float font_size) {
375 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
376 if (!pDoc)
377 return nullptr;
378
379 CPDF_Font* pFont = CPDF_Font::GetStockFont(pDoc, CFX_ByteStringC(font));
380 if (!pFont)
381 return nullptr;
382
383 CPDF_TextObject* pTextObj = new CPDF_TextObject;
384 pTextObj->m_TextState.SetFont(pFont);
385 pTextObj->m_TextState.SetFontSize(font_size);
386 pTextObj->DefaultStates();
387 return pTextObj;
388}
389
390DLLEXPORT FPDF_BOOL STDCALL FPDFText_SetText(FPDF_PAGEOBJECT text_object,
Nicolas Penab3161852017-05-02 14:12:50 -0400391 FPDF_WIDESTRING text) {
Nicolas Pena49058402017-02-14 18:26:20 -0500392 if (!text_object)
393 return false;
394
Lei Zhang375c2762017-03-10 14:37:14 -0800395 auto* pTextObj = reinterpret_cast<CPDF_TextObject*>(text_object);
Nicolas Penab3161852017-05-02 14:12:50 -0400396 FX_STRSIZE len = CFX_WideString::WStringLength(text);
397 CFX_WideString encodedText = CFX_WideString::FromUTF16LE(text, len);
398 CFX_ByteString byteText;
Nicolas Penaf45ade32017-05-03 10:23:49 -0400399 for (wchar_t wc : encodedText) {
400 pTextObj->GetFont()->AppendChar(
401 &byteText, pTextObj->GetFont()->CharCodeFromUnicode(wc));
Nicolas Penab3161852017-05-02 14:12:50 -0400402 }
403 pTextObj->SetText(byteText);
Nicolas Pena49058402017-02-14 18:26:20 -0500404 return true;
Nicolas Penabe90aae2017-02-27 10:41:41 -0500405}
406
Nicolas Penad03ca422017-03-06 13:54:33 -0500407DLLEXPORT FPDF_FONT STDCALL FPDFText_LoadFont(FPDF_DOCUMENT document,
408 const uint8_t* data,
409 uint32_t size,
410 int font_type,
411 FPDF_BOOL cid) {
Nicolas Penabe90aae2017-02-27 10:41:41 -0500412 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
Nicolas Penad03ca422017-03-06 13:54:33 -0500413 if (!pDoc || !data || size == 0 ||
414 (font_type != FPDF_FONT_TYPE1 && font_type != FPDF_FONT_TRUETYPE)) {
Nicolas Penabe90aae2017-02-27 10:41:41 -0500415 return nullptr;
Nicolas Penad03ca422017-03-06 13:54:33 -0500416 }
Nicolas Penabe90aae2017-02-27 10:41:41 -0500417
418 auto pFont = pdfium::MakeUnique<CFX_Font>();
419
Nicolas Penad03ca422017-03-06 13:54:33 -0500420 // TODO(npm): Maybe use FT_Get_X11_Font_Format to check format? Otherwise, we
421 // are allowing giving any font that can be loaded on freetype and setting it
422 // as any font type.
Nicolas Penabe90aae2017-02-27 10:41:41 -0500423 if (!pFont->LoadEmbedded(data, size))
424 return nullptr;
425
Nicolas Penad03ca422017-03-06 13:54:33 -0500426 return cid ? LoadCompositeFont(pDoc, std::move(pFont), data, size, font_type)
427 : LoadSimpleFont(pDoc, std::move(pFont), data, size, font_type);
Nicolas Penabe90aae2017-02-27 10:41:41 -0500428}
Nicolas Penab3161852017-05-02 14:12:50 -0400429
430DLLEXPORT void STDCALL FPDFFont_Close(FPDF_FONT font) {
431 if (!font)
432 return;
433
434 CPDF_Font* cpdf_font = reinterpret_cast<CPDF_Font*>(font);
435 CPDF_Document* pDoc = cpdf_font->m_pDocument;
436 CPDF_DocPageData* pPageData = pDoc ? pDoc->GetPageData() : nullptr;
437 if (pPageData && !pPageData->IsForceClear())
438 pPageData->ReleaseFont(cpdf_font->GetFontDict());
439}
440
441DLLEXPORT FPDF_PAGEOBJECT STDCALL
442FPDFPageObj_CreateTextObj(FPDF_DOCUMENT document,
443 FPDF_FONT font,
444 float font_size) {
445 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
446 if (!pDoc || !font)
447 return nullptr;
448
449 CPDF_Font* pFont = reinterpret_cast<CPDF_Font*>(font);
450
451 auto pTextObj = pdfium::MakeUnique<CPDF_TextObject>();
452 pTextObj->m_TextState.SetFont(pDoc->LoadFont(pFont->GetFontDict()));
453 pTextObj->m_TextState.SetFontSize(font_size);
454 pTextObj->DefaultStates();
455 return pTextObj.release();
456}