blob: 3deae7ea20f794f0ab543cd7fcb322342276de61 [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"
Nicolas Pena54b91662017-05-05 16:49:30 -040022#include "core/fxcrt/fx_extension.h"
Nicolas Penabe90aae2017-02-27 10:41:41 -050023#include "core/fxge/cfx_fontmgr.h"
24#include "core/fxge/fx_font.h"
Nicolas Pena49058402017-02-14 18:26:20 -050025#include "fpdfsdk/fsdk_define.h"
Nicolas Penabe90aae2017-02-27 10:41:41 -050026#include "public/fpdf_edit.h"
Nicolas Pena49058402017-02-14 18:26:20 -050027
Nicolas Penad03ca422017-03-06 13:54:33 -050028namespace {
29
30CPDF_Dictionary* LoadFontDesc(CPDF_Document* pDoc,
31 const CFX_ByteString& font_name,
32 CFX_Font* pFont,
33 const uint8_t* data,
34 uint32_t size,
35 int font_type) {
36 CPDF_Dictionary* fontDesc = pDoc->NewIndirect<CPDF_Dictionary>();
37 fontDesc->SetNewFor<CPDF_Name>("Type", "FontDescriptor");
38 fontDesc->SetNewFor<CPDF_Name>("FontName", font_name);
39 int flags = 0;
40 if (FXFT_Is_Face_fixedwidth(pFont->GetFace()))
41 flags |= FXFONT_FIXED_PITCH;
42 if (font_name.Find("Serif") > -1)
43 flags |= FXFONT_SERIF;
44 if (FXFT_Is_Face_Italic(pFont->GetFace()))
45 flags |= FXFONT_ITALIC;
46 if (FXFT_Is_Face_Bold(pFont->GetFace()))
47 flags |= FXFONT_BOLD;
48
49 // TODO(npm): How do I know if a font is symbolic, script, allcap, smallcap
50 flags |= FXFONT_NONSYMBOLIC;
51
52 fontDesc->SetNewFor<CPDF_Number>("Flags", flags);
53 FX_RECT bbox;
54 pFont->GetBBox(bbox);
55 auto pBBox = pdfium::MakeUnique<CPDF_Array>();
56 pBBox->AddNew<CPDF_Number>(bbox.left);
57 pBBox->AddNew<CPDF_Number>(bbox.bottom);
58 pBBox->AddNew<CPDF_Number>(bbox.right);
59 pBBox->AddNew<CPDF_Number>(bbox.top);
60 fontDesc->SetFor("FontBBox", std::move(pBBox));
61
62 // TODO(npm): calculate italic angle correctly
63 fontDesc->SetNewFor<CPDF_Number>("ItalicAngle", pFont->IsItalic() ? -12 : 0);
64
65 fontDesc->SetNewFor<CPDF_Number>("Ascent", pFont->GetAscent());
66 fontDesc->SetNewFor<CPDF_Number>("Descent", pFont->GetDescent());
67
68 // TODO(npm): calculate the capheight, stemV correctly
69 fontDesc->SetNewFor<CPDF_Number>("CapHeight", pFont->GetAscent());
70 fontDesc->SetNewFor<CPDF_Number>("StemV", pFont->IsBold() ? 120 : 70);
71
72 CPDF_Stream* pStream = pDoc->NewIndirect<CPDF_Stream>();
73 pStream->SetData(data, size);
74 CFX_ByteString fontFile =
75 font_type == FPDF_FONT_TYPE1 ? "FontFile" : "FontFile2";
76 fontDesc->SetNewFor<CPDF_Reference>(fontFile, pDoc, pStream->GetObjNum());
77 return fontDesc;
78}
79
Nicolas Penaf45ade32017-05-03 10:23:49 -040080const char ToUnicodeStart[] =
81 "/CIDInit /ProcSet findresource begin\n"
82 "12 dict begin\n"
83 "begincmap\n"
84 "/CIDSystemInfo\n"
85 "<</Registry (Adobe)\n"
86 "/Ordering (Identity)\n"
87 "/Supplement 0\n"
88 ">> def\n"
89 "/CMapName /Adobe-Identity-H def\n"
90 "CMapType 2 def\n"
91 "1 begincodespacerange\n"
Nicolas Penab48912f2017-05-17 14:45:52 -040092 "<0000> <FFFFF>\n"
93 "endcodespacerange\n";
94
95const char ToUnicodeEnd[] =
96 "endcmap\n"
97 "CMapName currentdict /CMap defineresource pop\n"
98 "end\n"
99 "end\n";
Nicolas Penaf45ade32017-05-03 10:23:49 -0400100
Nicolas Pena54b91662017-05-05 16:49:30 -0400101void AddCharcode(CFX_ByteTextBuf* pBuffer, uint32_t number) {
102 ASSERT(number <= 0xFFFF);
Nicolas Penaf45ade32017-05-03 10:23:49 -0400103 *pBuffer << "<";
104 char ans[4];
Nicolas Pena54b91662017-05-05 16:49:30 -0400105 FXSYS_IntToFourHexChars(number, ans);
Nicolas Penaf45ade32017-05-03 10:23:49 -0400106 for (size_t i = 0; i < 4; ++i)
107 pBuffer->AppendChar(ans[i]);
108 *pBuffer << ">";
109}
110
Nicolas Pena54b91662017-05-05 16:49:30 -0400111// PDF spec 1.7 Section 5.9.2: "Unicode character sequences as expressed in
112// UTF-16BE encoding." See https://en.wikipedia.org/wiki/UTF-16#Description
113void AddUnicode(CFX_ByteTextBuf* pBuffer, uint32_t unicode) {
114 char ans[8];
115 *pBuffer << "<";
116 size_t numChars = FXSYS_ToUTF16BE(unicode, ans);
117 for (size_t i = 0; i < numChars; ++i)
118 pBuffer->AppendChar(ans[i]);
119 *pBuffer << ">";
120}
121
Nicolas Penaf45ade32017-05-03 10:23:49 -0400122// Loads the charcode to unicode mapping into a stream
123CPDF_Stream* LoadUnicode(CPDF_Document* pDoc,
124 const std::map<uint32_t, uint32_t>& to_unicode) {
Nicolas Penaf45ade32017-05-03 10:23:49 -0400125 // A map charcode->unicode
126 std::map<uint32_t, uint32_t> char_to_uni;
127 // A map <char_start, char_end> to vector v of unicode characters of size (end
128 // - start + 1). This abbreviates: start->v[0], start+1->v[1], etc. PDF spec
129 // 1.7 Section 5.9.2 says that only the last byte of the unicode may change.
130 std::map<std::pair<uint32_t, uint32_t>, std::vector<uint32_t>>
131 map_range_vector;
132 // A map <start, end> -> unicode
133 // This abbreviates: start->unicode, start+1->unicode+1, etc.
134 // PDF spec 1.7 Section 5.9.2 says that only the last byte of the unicode may
135 // change.
136 std::map<std::pair<uint32_t, uint32_t>, uint32_t> map_range;
137
138 // Calculate the maps
139 for (auto iter = to_unicode.begin(); iter != to_unicode.end(); ++iter) {
140 uint32_t firstCharcode = iter->first;
141 uint32_t firstUnicode = iter->second;
142 if (std::next(iter) == to_unicode.end() ||
143 firstCharcode + 1 != std::next(iter)->first) {
144 char_to_uni[firstCharcode] = firstUnicode;
145 continue;
146 }
147 ++iter;
148 uint32_t curCharcode = iter->first;
149 uint32_t curUnicode = iter->second;
150 if (curCharcode % 256 == 0) {
151 char_to_uni[firstCharcode] = firstUnicode;
152 char_to_uni[curCharcode] = curUnicode;
153 continue;
154 }
155 const size_t maxExtra = 255 - (curCharcode % 256);
156 auto next_it = std::next(iter);
157 if (firstUnicode + 1 != curUnicode) {
158 // Consecutive charcodes mapping to non-consecutive unicodes
159 std::vector<uint32_t> unicodes;
160 unicodes.push_back(firstUnicode);
161 unicodes.push_back(curUnicode);
162 for (size_t i = 0; i < maxExtra; ++i) {
163 if (next_it == to_unicode.end() || curCharcode + 1 != next_it->first)
164 break;
165 ++iter;
166 ++curCharcode;
167 unicodes.push_back(iter->second);
168 next_it = std::next(iter);
169 }
170 ASSERT(iter->first - firstCharcode + 1 == unicodes.size());
171 map_range_vector[std::make_pair(firstCharcode, iter->first)] = unicodes;
172 continue;
173 }
174 // Consecutive charcodes mapping to consecutive unicodes
175 for (size_t i = 0; i < maxExtra; ++i) {
176 if (next_it == to_unicode.end() || curCharcode + 1 != next_it->first ||
177 curUnicode + 1 != next_it->second) {
178 break;
179 }
180 ++iter;
181 ++curCharcode;
182 ++curUnicode;
183 next_it = std::next(iter);
184 }
185 map_range[std::make_pair(firstCharcode, curCharcode)] = firstUnicode;
186 }
Nicolas Penab48912f2017-05-17 14:45:52 -0400187 CFX_ByteTextBuf buffer;
188 buffer << ToUnicodeStart;
Nicolas Penaf45ade32017-05-03 10:23:49 -0400189 // Add maps to buffer
190 buffer << static_cast<uint32_t>(char_to_uni.size()) << " beginbfchar\n";
Nicolas Pena54b91662017-05-05 16:49:30 -0400191 for (const auto& iter : char_to_uni) {
192 AddCharcode(&buffer, iter.first);
Nicolas Penaf45ade32017-05-03 10:23:49 -0400193 buffer << " ";
Nicolas Pena54b91662017-05-05 16:49:30 -0400194 AddUnicode(&buffer, iter.second);
Nicolas Penaf45ade32017-05-03 10:23:49 -0400195 buffer << "\n";
196 }
197 buffer << "endbfchar\n"
198 << static_cast<uint32_t>(map_range_vector.size() + map_range.size())
199 << " beginbfrange\n";
Nicolas Pena54b91662017-05-05 16:49:30 -0400200 for (const auto& iter : map_range_vector) {
Nicolas Penaf45ade32017-05-03 10:23:49 -0400201 const std::pair<uint32_t, uint32_t>& charcodeRange = iter.first;
Nicolas Pena54b91662017-05-05 16:49:30 -0400202 AddCharcode(&buffer, charcodeRange.first);
Nicolas Penaf45ade32017-05-03 10:23:49 -0400203 buffer << " ";
Nicolas Pena54b91662017-05-05 16:49:30 -0400204 AddCharcode(&buffer, charcodeRange.second);
Nicolas Penaf45ade32017-05-03 10:23:49 -0400205 buffer << " [";
206 const std::vector<uint32_t>& unicodes = iter.second;
207 for (size_t i = 0; i < unicodes.size(); ++i) {
208 uint32_t uni = unicodes[i];
Nicolas Pena54b91662017-05-05 16:49:30 -0400209 AddUnicode(&buffer, uni);
Nicolas Penaf45ade32017-05-03 10:23:49 -0400210 if (i != unicodes.size() - 1)
211 buffer << " ";
212 }
213 buffer << "]\n";
214 }
Nicolas Pena54b91662017-05-05 16:49:30 -0400215 for (const auto& iter : map_range) {
Nicolas Penaf45ade32017-05-03 10:23:49 -0400216 const std::pair<uint32_t, uint32_t>& charcodeRange = iter.first;
Nicolas Pena54b91662017-05-05 16:49:30 -0400217 AddCharcode(&buffer, charcodeRange.first);
Nicolas Penaf45ade32017-05-03 10:23:49 -0400218 buffer << " ";
Nicolas Pena54b91662017-05-05 16:49:30 -0400219 AddCharcode(&buffer, charcodeRange.second);
Nicolas Penaf45ade32017-05-03 10:23:49 -0400220 buffer << " ";
Nicolas Pena54b91662017-05-05 16:49:30 -0400221 AddUnicode(&buffer, iter.second);
Nicolas Penaf45ade32017-05-03 10:23:49 -0400222 buffer << "\n";
223 }
Nicolas Penab48912f2017-05-17 14:45:52 -0400224 buffer << "endbfrange\n";
225 buffer << ToUnicodeEnd;
Nicolas Penaf45ade32017-05-03 10:23:49 -0400226 // TODO(npm): Encrypt / Compress?
227 uint32_t bufferSize = buffer.GetSize();
228 auto pDict = pdfium::MakeUnique<CPDF_Dictionary>();
229 pDict->SetNewFor<CPDF_Number>("Length", static_cast<int>(bufferSize));
230 return pDoc->NewIndirect<CPDF_Stream>(buffer.DetachBuffer(), bufferSize,
231 std::move(pDict));
232}
233
Nicolas Penad03ca422017-03-06 13:54:33 -0500234void* LoadSimpleFont(CPDF_Document* pDoc,
235 std::unique_ptr<CFX_Font> pFont,
236 const uint8_t* data,
237 uint32_t size,
238 int font_type) {
239 CPDF_Dictionary* fontDict = pDoc->NewIndirect<CPDF_Dictionary>();
240 fontDict->SetNewFor<CPDF_Name>("Type", "Font");
241 fontDict->SetNewFor<CPDF_Name>(
242 "Subtype", font_type == FPDF_FONT_TYPE1 ? "Type1" : "TrueType");
243 CFX_ByteString name = pFont->GetFaceName();
244 if (name.IsEmpty())
245 name = "Unnamed";
246 fontDict->SetNewFor<CPDF_Name>("BaseFont", name);
247
248 uint32_t glyphIndex;
249 int currentChar = FXFT_Get_First_Char(pFont->GetFace(), &glyphIndex);
250 fontDict->SetNewFor<CPDF_Number>("FirstChar", currentChar);
251 CPDF_Array* widthsArray = pDoc->NewIndirect<CPDF_Array>();
252 while (true) {
Nicolas Penaf45ade32017-05-03 10:23:49 -0400253 widthsArray->AddNew<CPDF_Number>(pFont->GetGlyphWidth(glyphIndex));
Nicolas Penad03ca422017-03-06 13:54:33 -0500254 int nextChar =
255 FXFT_Get_Next_Char(pFont->GetFace(), currentChar, &glyphIndex);
256 // Simple fonts have 1-byte charcodes only.
257 if (nextChar > 0xff || glyphIndex == 0)
258 break;
259 for (int i = currentChar + 1; i < nextChar; i++)
260 widthsArray->AddNew<CPDF_Number>(0);
261 currentChar = nextChar;
262 }
263 fontDict->SetNewFor<CPDF_Number>("LastChar", currentChar);
264 fontDict->SetNewFor<CPDF_Reference>("Widths", pDoc, widthsArray->GetObjNum());
265 CPDF_Dictionary* fontDesc =
266 LoadFontDesc(pDoc, name, pFont.get(), data, size, font_type);
267
268 fontDict->SetNewFor<CPDF_Reference>("FontDescriptor", pDoc,
269 fontDesc->GetObjNum());
270 return pDoc->LoadFont(fontDict);
271}
272
273void* LoadCompositeFont(CPDF_Document* pDoc,
274 std::unique_ptr<CFX_Font> pFont,
275 const uint8_t* data,
276 uint32_t size,
277 int font_type) {
278 CPDF_Dictionary* fontDict = pDoc->NewIndirect<CPDF_Dictionary>();
279 fontDict->SetNewFor<CPDF_Name>("Type", "Font");
280 fontDict->SetNewFor<CPDF_Name>("Subtype", "Type0");
281 // TODO(npm): Get the correct encoding, if it's not identity.
282 CFX_ByteString encoding = "Identity-H";
283 fontDict->SetNewFor<CPDF_Name>("Encoding", encoding);
284 CFX_ByteString name = pFont->GetFaceName();
285 if (name.IsEmpty())
286 name = "Unnamed";
287 fontDict->SetNewFor<CPDF_Name>(
288 "BaseFont", font_type == FPDF_FONT_TYPE1 ? name + "-" + encoding : name);
289
290 CPDF_Dictionary* pCIDFont = pDoc->NewIndirect<CPDF_Dictionary>();
291 pCIDFont->SetNewFor<CPDF_Name>("Type", "Font");
292 pCIDFont->SetNewFor<CPDF_Name>("Subtype", font_type == FPDF_FONT_TYPE1
293 ? "CIDFontType0"
294 : "CIDFontType2");
295 pCIDFont->SetNewFor<CPDF_Name>("BaseFont", name);
296
297 // TODO(npm): Maybe use FT_Get_CID_Registry_Ordering_Supplement to get the
298 // CIDSystemInfo
299 CPDF_Dictionary* pCIDSystemInfo = pDoc->NewIndirect<CPDF_Dictionary>();
300 pCIDSystemInfo->SetNewFor<CPDF_Name>("Registry", "Adobe");
301 pCIDSystemInfo->SetNewFor<CPDF_Name>("Ordering", "Identity");
302 pCIDSystemInfo->SetNewFor<CPDF_Number>("Supplement", 0);
303 pCIDFont->SetNewFor<CPDF_Reference>("CIDSystemInfo", pDoc,
304 pCIDSystemInfo->GetObjNum());
305
306 CPDF_Dictionary* fontDesc =
307 LoadFontDesc(pDoc, name, pFont.get(), data, size, font_type);
308 pCIDFont->SetNewFor<CPDF_Reference>("FontDescriptor", pDoc,
309 fontDesc->GetObjNum());
310
311 uint32_t glyphIndex;
312 int currentChar = FXFT_Get_First_Char(pFont->GetFace(), &glyphIndex);
Nicolas Penaf45ade32017-05-03 10:23:49 -0400313 // If it doesn't have a single char, just fail
314 if (glyphIndex == 0)
315 return nullptr;
316
317 std::map<uint32_t, uint32_t> to_unicode;
318 std::map<uint32_t, uint32_t> widths;
Nicolas Penad03ca422017-03-06 13:54:33 -0500319 while (true) {
Nicolas Penafb71fbb2017-05-23 13:16:09 -0400320 if (currentChar > 0x10FFFF)
321 break;
322
Nicolas Penaf45ade32017-05-03 10:23:49 -0400323 widths[glyphIndex] = pFont->GetGlyphWidth(glyphIndex);
324 to_unicode[glyphIndex] = currentChar;
325 currentChar =
Nicolas Penad03ca422017-03-06 13:54:33 -0500326 FXFT_Get_Next_Char(pFont->GetFace(), currentChar, &glyphIndex);
Nicolas Penaf45ade32017-05-03 10:23:49 -0400327 if (glyphIndex == 0)
328 break;
329 }
330 CPDF_Array* widthsArray = pDoc->NewIndirect<CPDF_Array>();
331 for (auto it = widths.begin(); it != widths.end(); ++it) {
332 int ch = it->first;
333 int w = it->second;
334 if (std::next(it) == widths.end()) {
Nicolas Penad03ca422017-03-06 13:54:33 -0500335 // Only one char left, use format c [w]
336 auto oneW = pdfium::MakeUnique<CPDF_Array>();
Nicolas Penaf45ade32017-05-03 10:23:49 -0400337 oneW->AddNew<CPDF_Number>(w);
338 widthsArray->AddNew<CPDF_Number>(ch);
Nicolas Penad03ca422017-03-06 13:54:33 -0500339 widthsArray->Add(std::move(oneW));
340 break;
341 }
Nicolas Penaf45ade32017-05-03 10:23:49 -0400342 ++it;
343 int next_ch = it->first;
344 int next_w = it->second;
345 if (next_ch == ch + 1 && next_w == w) {
Nicolas Penad03ca422017-03-06 13:54:33 -0500346 // The array can have a group c_first c_last w: all CIDs in the range from
347 // c_first to c_last will have width w
Nicolas Penaf45ade32017-05-03 10:23:49 -0400348 widthsArray->AddNew<CPDF_Number>(ch);
349 ch = next_ch;
Nicolas Penad03ca422017-03-06 13:54:33 -0500350 while (true) {
Nicolas Penaf45ade32017-05-03 10:23:49 -0400351 auto next_it = std::next(it);
352 if (next_it == widths.end() || next_it->first != it->first + 1 ||
353 next_it->second != it->second) {
Nicolas Penad03ca422017-03-06 13:54:33 -0500354 break;
Nicolas Penaf45ade32017-05-03 10:23:49 -0400355 }
356 ++it;
357 ch = it->first;
Nicolas Penad03ca422017-03-06 13:54:33 -0500358 }
Nicolas Penaf45ade32017-05-03 10:23:49 -0400359 widthsArray->AddNew<CPDF_Number>(ch);
360 widthsArray->AddNew<CPDF_Number>(w);
361 continue;
Nicolas Penad03ca422017-03-06 13:54:33 -0500362 }
Nicolas Penaf45ade32017-05-03 10:23:49 -0400363 // Otherwise we can have a group of the form c [w1 w2 ...]: c has width
364 // w1, c+1 has width w2, etc.
365 widthsArray->AddNew<CPDF_Number>(ch);
366 auto curWidthArray = pdfium::MakeUnique<CPDF_Array>();
367 curWidthArray->AddNew<CPDF_Number>(w);
368 curWidthArray->AddNew<CPDF_Number>(next_w);
369 while (true) {
370 auto next_it = std::next(it);
371 if (next_it == widths.end() || next_it->first != it->first + 1)
372 break;
373 ++it;
374 curWidthArray->AddNew<CPDF_Number>(static_cast<int>(it->second));
375 }
376 widthsArray->Add(std::move(curWidthArray));
Nicolas Penad03ca422017-03-06 13:54:33 -0500377 }
378 pCIDFont->SetNewFor<CPDF_Reference>("W", pDoc, widthsArray->GetObjNum());
379 // TODO(npm): Support vertical writing
380
381 auto pDescendant = pdfium::MakeUnique<CPDF_Array>();
382 pDescendant->AddNew<CPDF_Reference>(pDoc, pCIDFont->GetObjNum());
383 fontDict->SetFor("DescendantFonts", std::move(pDescendant));
Nicolas Penaf45ade32017-05-03 10:23:49 -0400384 CPDF_Stream* toUnicodeStream = LoadUnicode(pDoc, to_unicode);
385 fontDict->SetNewFor<CPDF_Reference>("ToUnicode", pDoc,
386 toUnicodeStream->GetObjNum());
Nicolas Penad03ca422017-03-06 13:54:33 -0500387 return pDoc->LoadFont(fontDict);
388}
389
390} // namespace
391
Nicolas Pena49058402017-02-14 18:26:20 -0500392DLLEXPORT FPDF_PAGEOBJECT STDCALL FPDFPageObj_NewTextObj(FPDF_DOCUMENT document,
393 FPDF_BYTESTRING font,
394 float font_size) {
395 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
396 if (!pDoc)
397 return nullptr;
398
399 CPDF_Font* pFont = CPDF_Font::GetStockFont(pDoc, CFX_ByteStringC(font));
400 if (!pFont)
401 return nullptr;
402
Tom Sepezfe91c6c2017-05-16 15:33:20 -0700403 auto pTextObj = pdfium::MakeUnique<CPDF_TextObject>();
Nicolas Pena49058402017-02-14 18:26:20 -0500404 pTextObj->m_TextState.SetFont(pFont);
405 pTextObj->m_TextState.SetFontSize(font_size);
406 pTextObj->DefaultStates();
Tom Sepezfe91c6c2017-05-16 15:33:20 -0700407 return pTextObj.release(); // Caller takes ownership.
Nicolas Pena49058402017-02-14 18:26:20 -0500408}
409
410DLLEXPORT FPDF_BOOL STDCALL FPDFText_SetText(FPDF_PAGEOBJECT text_object,
Nicolas Penab3161852017-05-02 14:12:50 -0400411 FPDF_WIDESTRING text) {
Nicolas Pena54b91662017-05-05 16:49:30 -0400412 auto* pTextObj = static_cast<CPDF_TextObject*>(text_object);
413 if (!pTextObj)
Nicolas Pena49058402017-02-14 18:26:20 -0500414 return false;
415
Nicolas Penab3161852017-05-02 14:12:50 -0400416 FX_STRSIZE len = CFX_WideString::WStringLength(text);
417 CFX_WideString encodedText = CFX_WideString::FromUTF16LE(text, len);
418 CFX_ByteString byteText;
Nicolas Penaf45ade32017-05-03 10:23:49 -0400419 for (wchar_t wc : encodedText) {
420 pTextObj->GetFont()->AppendChar(
421 &byteText, pTextObj->GetFont()->CharCodeFromUnicode(wc));
Nicolas Penab3161852017-05-02 14:12:50 -0400422 }
423 pTextObj->SetText(byteText);
Nicolas Pena49058402017-02-14 18:26:20 -0500424 return true;
Nicolas Penabe90aae2017-02-27 10:41:41 -0500425}
426
Nicolas Penad03ca422017-03-06 13:54:33 -0500427DLLEXPORT FPDF_FONT STDCALL FPDFText_LoadFont(FPDF_DOCUMENT document,
428 const uint8_t* data,
429 uint32_t size,
430 int font_type,
431 FPDF_BOOL cid) {
Nicolas Penabe90aae2017-02-27 10:41:41 -0500432 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
Nicolas Penad03ca422017-03-06 13:54:33 -0500433 if (!pDoc || !data || size == 0 ||
434 (font_type != FPDF_FONT_TYPE1 && font_type != FPDF_FONT_TRUETYPE)) {
Nicolas Penabe90aae2017-02-27 10:41:41 -0500435 return nullptr;
Nicolas Penad03ca422017-03-06 13:54:33 -0500436 }
Nicolas Penabe90aae2017-02-27 10:41:41 -0500437
438 auto pFont = pdfium::MakeUnique<CFX_Font>();
439
Nicolas Penad03ca422017-03-06 13:54:33 -0500440 // TODO(npm): Maybe use FT_Get_X11_Font_Format to check format? Otherwise, we
441 // are allowing giving any font that can be loaded on freetype and setting it
442 // as any font type.
Nicolas Penabe90aae2017-02-27 10:41:41 -0500443 if (!pFont->LoadEmbedded(data, size))
444 return nullptr;
445
Nicolas Penad03ca422017-03-06 13:54:33 -0500446 return cid ? LoadCompositeFont(pDoc, std::move(pFont), data, size, font_type)
447 : LoadSimpleFont(pDoc, std::move(pFont), data, size, font_type);
Nicolas Penabe90aae2017-02-27 10:41:41 -0500448}
Nicolas Penab3161852017-05-02 14:12:50 -0400449
wileyrya864e9fb2017-05-26 11:38:14 -0500450DLLEXPORT FPDF_BOOL STDCALL FPDFText_SetFillColor(FPDF_PAGEOBJECT text_object,
451 unsigned int R,
452 unsigned int G,
453 unsigned int B,
454 unsigned int A) {
455 return FPDFPageObj_SetFillColor(text_object, R, G, B, A);
456}
457
Nicolas Penab3161852017-05-02 14:12:50 -0400458DLLEXPORT void STDCALL FPDFFont_Close(FPDF_FONT font) {
Nicolas Pena54b91662017-05-05 16:49:30 -0400459 CPDF_Font* pFont = static_cast<CPDF_Font*>(font);
460 if (!pFont)
Nicolas Penab3161852017-05-02 14:12:50 -0400461 return;
462
Lei Zhangb8a8c432017-05-04 14:10:50 -0700463 CPDF_Document* pDoc = pFont->GetDocument();
464 if (!pDoc)
465 return;
466
467 CPDF_DocPageData* pPageData = pDoc->GetPageData();
468 if (!pPageData->IsForceClear())
469 pPageData->ReleaseFont(pFont->GetFontDict());
Nicolas Penab3161852017-05-02 14:12:50 -0400470}
471
472DLLEXPORT FPDF_PAGEOBJECT STDCALL
473FPDFPageObj_CreateTextObj(FPDF_DOCUMENT document,
474 FPDF_FONT font,
475 float font_size) {
476 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
Nicolas Pena54b91662017-05-05 16:49:30 -0400477 CPDF_Font* pFont = static_cast<CPDF_Font*>(font);
478 if (!pDoc || !pFont)
Nicolas Penab3161852017-05-02 14:12:50 -0400479 return nullptr;
480
Nicolas Penab3161852017-05-02 14:12:50 -0400481 auto pTextObj = pdfium::MakeUnique<CPDF_TextObject>();
482 pTextObj->m_TextState.SetFont(pDoc->LoadFont(pFont->GetFontDict()));
483 pTextObj->m_TextState.SetFontSize(font_size);
484 pTextObj->DefaultStates();
485 return pTextObj.release();
486}