blob: 2ac32b82a33ed4fadc641e201d0d67013a1697a8 [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,
Ryan Harrison275e2602017-09-18 14:23:18 -040031 const ByteString& font_name,
Nicolas Penad03ca422017-03-06 13:54:33 -050032 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;
Ryan Harrison12db7512017-08-23 10:39:35 -040042 if (font_name.Contains("Serif"))
Nicolas Penad03ca422017-03-06 13:54:33 -050043 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);
Ryan Harrison275e2602017-09-18 14:23:18 -040074 ByteString fontFile = font_type == FPDF_FONT_TYPE1 ? "FontFile" : "FontFile2";
Nicolas Penad03ca422017-03-06 13:54:33 -050075 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"
Nicolas Penab48912f2017-05-17 14:45:52 -040091 "<0000> <FFFFF>\n"
92 "endcodespacerange\n";
93
94const char ToUnicodeEnd[] =
95 "endcmap\n"
96 "CMapName currentdict /CMap defineresource pop\n"
97 "end\n"
98 "end\n";
Nicolas Penaf45ade32017-05-03 10:23:49 -040099
Henrique Nakashima0ba3c6d2017-07-05 16:21:17 -0400100void AddCharcode(std::ostringstream* pBuffer, uint32_t number) {
Nicolas Pena54b91662017-05-05 16:49:30 -0400101 ASSERT(number <= 0xFFFF);
Nicolas Penaf45ade32017-05-03 10:23:49 -0400102 *pBuffer << "<";
103 char ans[4];
Nicolas Pena54b91662017-05-05 16:49:30 -0400104 FXSYS_IntToFourHexChars(number, ans);
Nicolas Penaf45ade32017-05-03 10:23:49 -0400105 for (size_t i = 0; i < 4; ++i)
Henrique Nakashima0ba3c6d2017-07-05 16:21:17 -0400106 *pBuffer << ans[i];
Nicolas Penaf45ade32017-05-03 10:23:49 -0400107 *pBuffer << ">";
108}
109
Nicolas Pena54b91662017-05-05 16:49:30 -0400110// PDF spec 1.7 Section 5.9.2: "Unicode character sequences as expressed in
111// UTF-16BE encoding." See https://en.wikipedia.org/wiki/UTF-16#Description
Henrique Nakashima0ba3c6d2017-07-05 16:21:17 -0400112void AddUnicode(std::ostringstream* pBuffer, uint32_t unicode) {
Nicolas Pena217644c2017-07-06 10:53:01 -0400113 if (unicode >= 0xD800 && unicode <= 0xDFFF)
114 unicode = 0;
115
Nicolas Pena54b91662017-05-05 16:49:30 -0400116 char ans[8];
117 *pBuffer << "<";
118 size_t numChars = FXSYS_ToUTF16BE(unicode, ans);
119 for (size_t i = 0; i < numChars; ++i)
Henrique Nakashima0ba3c6d2017-07-05 16:21:17 -0400120 *pBuffer << ans[i];
Nicolas Pena54b91662017-05-05 16:49:30 -0400121 *pBuffer << ">";
122}
123
Nicolas Penaf45ade32017-05-03 10:23:49 -0400124// Loads the charcode to unicode mapping into a stream
125CPDF_Stream* LoadUnicode(CPDF_Document* pDoc,
126 const std::map<uint32_t, uint32_t>& to_unicode) {
Nicolas Penaf45ade32017-05-03 10:23:49 -0400127 // A map charcode->unicode
128 std::map<uint32_t, uint32_t> char_to_uni;
129 // A map <char_start, char_end> to vector v of unicode characters of size (end
130 // - start + 1). This abbreviates: start->v[0], start+1->v[1], etc. PDF spec
131 // 1.7 Section 5.9.2 says that only the last byte of the unicode may change.
132 std::map<std::pair<uint32_t, uint32_t>, std::vector<uint32_t>>
133 map_range_vector;
134 // A map <start, end> -> unicode
135 // This abbreviates: start->unicode, start+1->unicode+1, etc.
136 // PDF spec 1.7 Section 5.9.2 says that only the last byte of the unicode may
137 // change.
138 std::map<std::pair<uint32_t, uint32_t>, uint32_t> map_range;
139
140 // Calculate the maps
141 for (auto iter = to_unicode.begin(); iter != to_unicode.end(); ++iter) {
142 uint32_t firstCharcode = iter->first;
143 uint32_t firstUnicode = iter->second;
144 if (std::next(iter) == to_unicode.end() ||
145 firstCharcode + 1 != std::next(iter)->first) {
146 char_to_uni[firstCharcode] = firstUnicode;
147 continue;
148 }
149 ++iter;
150 uint32_t curCharcode = iter->first;
151 uint32_t curUnicode = iter->second;
152 if (curCharcode % 256 == 0) {
153 char_to_uni[firstCharcode] = firstUnicode;
154 char_to_uni[curCharcode] = curUnicode;
155 continue;
156 }
157 const size_t maxExtra = 255 - (curCharcode % 256);
158 auto next_it = std::next(iter);
159 if (firstUnicode + 1 != curUnicode) {
160 // Consecutive charcodes mapping to non-consecutive unicodes
161 std::vector<uint32_t> unicodes;
162 unicodes.push_back(firstUnicode);
163 unicodes.push_back(curUnicode);
164 for (size_t i = 0; i < maxExtra; ++i) {
165 if (next_it == to_unicode.end() || curCharcode + 1 != next_it->first)
166 break;
167 ++iter;
168 ++curCharcode;
169 unicodes.push_back(iter->second);
170 next_it = std::next(iter);
171 }
172 ASSERT(iter->first - firstCharcode + 1 == unicodes.size());
173 map_range_vector[std::make_pair(firstCharcode, iter->first)] = unicodes;
174 continue;
175 }
176 // Consecutive charcodes mapping to consecutive unicodes
177 for (size_t i = 0; i < maxExtra; ++i) {
178 if (next_it == to_unicode.end() || curCharcode + 1 != next_it->first ||
179 curUnicode + 1 != next_it->second) {
180 break;
181 }
182 ++iter;
183 ++curCharcode;
184 ++curUnicode;
185 next_it = std::next(iter);
186 }
187 map_range[std::make_pair(firstCharcode, curCharcode)] = firstUnicode;
188 }
Henrique Nakashima0ba3c6d2017-07-05 16:21:17 -0400189 std::ostringstream buffer;
Nicolas Penab48912f2017-05-17 14:45:52 -0400190 buffer << ToUnicodeStart;
Nicolas Penaf45ade32017-05-03 10:23:49 -0400191 // Add maps to buffer
192 buffer << static_cast<uint32_t>(char_to_uni.size()) << " beginbfchar\n";
Nicolas Pena54b91662017-05-05 16:49:30 -0400193 for (const auto& iter : char_to_uni) {
194 AddCharcode(&buffer, iter.first);
Nicolas Penaf45ade32017-05-03 10:23:49 -0400195 buffer << " ";
Nicolas Pena54b91662017-05-05 16:49:30 -0400196 AddUnicode(&buffer, iter.second);
Nicolas Penaf45ade32017-05-03 10:23:49 -0400197 buffer << "\n";
198 }
199 buffer << "endbfchar\n"
200 << static_cast<uint32_t>(map_range_vector.size() + map_range.size())
201 << " beginbfrange\n";
Nicolas Pena54b91662017-05-05 16:49:30 -0400202 for (const auto& iter : map_range_vector) {
Nicolas Penaf45ade32017-05-03 10:23:49 -0400203 const std::pair<uint32_t, uint32_t>& charcodeRange = iter.first;
Nicolas Pena54b91662017-05-05 16:49:30 -0400204 AddCharcode(&buffer, charcodeRange.first);
Nicolas Penaf45ade32017-05-03 10:23:49 -0400205 buffer << " ";
Nicolas Pena54b91662017-05-05 16:49:30 -0400206 AddCharcode(&buffer, charcodeRange.second);
Nicolas Penaf45ade32017-05-03 10:23:49 -0400207 buffer << " [";
208 const std::vector<uint32_t>& unicodes = iter.second;
209 for (size_t i = 0; i < unicodes.size(); ++i) {
210 uint32_t uni = unicodes[i];
Nicolas Pena54b91662017-05-05 16:49:30 -0400211 AddUnicode(&buffer, uni);
Nicolas Penaf45ade32017-05-03 10:23:49 -0400212 if (i != unicodes.size() - 1)
213 buffer << " ";
214 }
215 buffer << "]\n";
216 }
Nicolas Pena54b91662017-05-05 16:49:30 -0400217 for (const auto& iter : map_range) {
Nicolas Penaf45ade32017-05-03 10:23:49 -0400218 const std::pair<uint32_t, uint32_t>& charcodeRange = iter.first;
Nicolas Pena54b91662017-05-05 16:49:30 -0400219 AddCharcode(&buffer, charcodeRange.first);
Nicolas Penaf45ade32017-05-03 10:23:49 -0400220 buffer << " ";
Nicolas Pena54b91662017-05-05 16:49:30 -0400221 AddCharcode(&buffer, charcodeRange.second);
Nicolas Penaf45ade32017-05-03 10:23:49 -0400222 buffer << " ";
Nicolas Pena54b91662017-05-05 16:49:30 -0400223 AddUnicode(&buffer, iter.second);
Nicolas Penaf45ade32017-05-03 10:23:49 -0400224 buffer << "\n";
225 }
Nicolas Penab48912f2017-05-17 14:45:52 -0400226 buffer << "endbfrange\n";
227 buffer << ToUnicodeEnd;
Nicolas Penaf45ade32017-05-03 10:23:49 -0400228 // TODO(npm): Encrypt / Compress?
Henrique Nakashima0ba3c6d2017-07-05 16:21:17 -0400229 CPDF_Stream* stream = pDoc->NewIndirect<CPDF_Stream>();
230 stream->SetData(&buffer);
231 return stream;
Nicolas Penaf45ade32017-05-03 10:23:49 -0400232}
233
Nicolas Penab83d8702017-06-09 17:55:51 -0400234const uint32_t kMaxSimpleFontChar = 0xFF;
235
Nicolas Penad03ca422017-03-06 13:54:33 -0500236void* LoadSimpleFont(CPDF_Document* pDoc,
237 std::unique_ptr<CFX_Font> pFont,
238 const uint8_t* data,
239 uint32_t size,
240 int font_type) {
241 CPDF_Dictionary* fontDict = pDoc->NewIndirect<CPDF_Dictionary>();
242 fontDict->SetNewFor<CPDF_Name>("Type", "Font");
243 fontDict->SetNewFor<CPDF_Name>(
244 "Subtype", font_type == FPDF_FONT_TYPE1 ? "Type1" : "TrueType");
Ryan Harrison275e2602017-09-18 14:23:18 -0400245 ByteString name = pFont->GetFaceName();
Nicolas Penad03ca422017-03-06 13:54:33 -0500246 if (name.IsEmpty())
247 name = "Unnamed";
248 fontDict->SetNewFor<CPDF_Name>("BaseFont", name);
249
250 uint32_t glyphIndex;
Nicolas Penab83d8702017-06-09 17:55:51 -0400251 uint32_t currentChar = FXFT_Get_First_Char(pFont->GetFace(), &glyphIndex);
252 if (currentChar > kMaxSimpleFontChar || glyphIndex == 0)
253 return nullptr;
254 fontDict->SetNewFor<CPDF_Number>("FirstChar", static_cast<int>(currentChar));
Nicolas Penad03ca422017-03-06 13:54:33 -0500255 CPDF_Array* widthsArray = pDoc->NewIndirect<CPDF_Array>();
256 while (true) {
Nicolas Penaf45ade32017-05-03 10:23:49 -0400257 widthsArray->AddNew<CPDF_Number>(pFont->GetGlyphWidth(glyphIndex));
Nicolas Penab83d8702017-06-09 17:55:51 -0400258 uint32_t nextChar =
Nicolas Penad03ca422017-03-06 13:54:33 -0500259 FXFT_Get_Next_Char(pFont->GetFace(), currentChar, &glyphIndex);
260 // Simple fonts have 1-byte charcodes only.
Nicolas Penab83d8702017-06-09 17:55:51 -0400261 if (nextChar > kMaxSimpleFontChar || glyphIndex == 0)
Nicolas Penad03ca422017-03-06 13:54:33 -0500262 break;
Nicolas Penab83d8702017-06-09 17:55:51 -0400263 for (uint32_t i = currentChar + 1; i < nextChar; i++)
Nicolas Penad03ca422017-03-06 13:54:33 -0500264 widthsArray->AddNew<CPDF_Number>(0);
265 currentChar = nextChar;
266 }
Nicolas Penab83d8702017-06-09 17:55:51 -0400267 fontDict->SetNewFor<CPDF_Number>("LastChar", static_cast<int>(currentChar));
Nicolas Penad03ca422017-03-06 13:54:33 -0500268 fontDict->SetNewFor<CPDF_Reference>("Widths", pDoc, widthsArray->GetObjNum());
269 CPDF_Dictionary* fontDesc =
270 LoadFontDesc(pDoc, name, pFont.get(), data, size, font_type);
271
272 fontDict->SetNewFor<CPDF_Reference>("FontDescriptor", pDoc,
273 fontDesc->GetObjNum());
274 return pDoc->LoadFont(fontDict);
275}
276
Nicolas Penab83d8702017-06-09 17:55:51 -0400277const uint32_t kMaxUnicode = 0x10FFFF;
278
Nicolas Penad03ca422017-03-06 13:54:33 -0500279void* LoadCompositeFont(CPDF_Document* pDoc,
280 std::unique_ptr<CFX_Font> pFont,
281 const uint8_t* data,
282 uint32_t size,
283 int font_type) {
284 CPDF_Dictionary* fontDict = pDoc->NewIndirect<CPDF_Dictionary>();
285 fontDict->SetNewFor<CPDF_Name>("Type", "Font");
286 fontDict->SetNewFor<CPDF_Name>("Subtype", "Type0");
287 // TODO(npm): Get the correct encoding, if it's not identity.
Ryan Harrison275e2602017-09-18 14:23:18 -0400288 ByteString encoding = "Identity-H";
Nicolas Penad03ca422017-03-06 13:54:33 -0500289 fontDict->SetNewFor<CPDF_Name>("Encoding", encoding);
Ryan Harrison275e2602017-09-18 14:23:18 -0400290 ByteString name = pFont->GetFaceName();
Nicolas Penad03ca422017-03-06 13:54:33 -0500291 if (name.IsEmpty())
292 name = "Unnamed";
293 fontDict->SetNewFor<CPDF_Name>(
294 "BaseFont", font_type == FPDF_FONT_TYPE1 ? name + "-" + encoding : name);
295
296 CPDF_Dictionary* pCIDFont = pDoc->NewIndirect<CPDF_Dictionary>();
297 pCIDFont->SetNewFor<CPDF_Name>("Type", "Font");
298 pCIDFont->SetNewFor<CPDF_Name>("Subtype", font_type == FPDF_FONT_TYPE1
299 ? "CIDFontType0"
300 : "CIDFontType2");
301 pCIDFont->SetNewFor<CPDF_Name>("BaseFont", name);
302
303 // TODO(npm): Maybe use FT_Get_CID_Registry_Ordering_Supplement to get the
304 // CIDSystemInfo
305 CPDF_Dictionary* pCIDSystemInfo = pDoc->NewIndirect<CPDF_Dictionary>();
306 pCIDSystemInfo->SetNewFor<CPDF_Name>("Registry", "Adobe");
307 pCIDSystemInfo->SetNewFor<CPDF_Name>("Ordering", "Identity");
308 pCIDSystemInfo->SetNewFor<CPDF_Number>("Supplement", 0);
309 pCIDFont->SetNewFor<CPDF_Reference>("CIDSystemInfo", pDoc,
310 pCIDSystemInfo->GetObjNum());
311
312 CPDF_Dictionary* fontDesc =
313 LoadFontDesc(pDoc, name, pFont.get(), data, size, font_type);
314 pCIDFont->SetNewFor<CPDF_Reference>("FontDescriptor", pDoc,
315 fontDesc->GetObjNum());
316
317 uint32_t glyphIndex;
Nicolas Penab83d8702017-06-09 17:55:51 -0400318 uint32_t currentChar = FXFT_Get_First_Char(pFont->GetFace(), &glyphIndex);
Nicolas Penaf45ade32017-05-03 10:23:49 -0400319 // If it doesn't have a single char, just fail
Nicolas Penab83d8702017-06-09 17:55:51 -0400320 if (glyphIndex == 0 || currentChar > kMaxUnicode)
Nicolas Penaf45ade32017-05-03 10:23:49 -0400321 return nullptr;
322
323 std::map<uint32_t, uint32_t> to_unicode;
324 std::map<uint32_t, uint32_t> widths;
Nicolas Penad03ca422017-03-06 13:54:33 -0500325 while (true) {
Nicolas Penab83d8702017-06-09 17:55:51 -0400326 if (currentChar > kMaxUnicode)
Nicolas Penafb71fbb2017-05-23 13:16:09 -0400327 break;
328
Nicolas Penaf45ade32017-05-03 10:23:49 -0400329 widths[glyphIndex] = pFont->GetGlyphWidth(glyphIndex);
330 to_unicode[glyphIndex] = currentChar;
331 currentChar =
Nicolas Penad03ca422017-03-06 13:54:33 -0500332 FXFT_Get_Next_Char(pFont->GetFace(), currentChar, &glyphIndex);
Nicolas Penaf45ade32017-05-03 10:23:49 -0400333 if (glyphIndex == 0)
334 break;
335 }
336 CPDF_Array* widthsArray = pDoc->NewIndirect<CPDF_Array>();
337 for (auto it = widths.begin(); it != widths.end(); ++it) {
338 int ch = it->first;
339 int w = it->second;
340 if (std::next(it) == widths.end()) {
Nicolas Penad03ca422017-03-06 13:54:33 -0500341 // Only one char left, use format c [w]
342 auto oneW = pdfium::MakeUnique<CPDF_Array>();
Nicolas Penaf45ade32017-05-03 10:23:49 -0400343 oneW->AddNew<CPDF_Number>(w);
344 widthsArray->AddNew<CPDF_Number>(ch);
Nicolas Penad03ca422017-03-06 13:54:33 -0500345 widthsArray->Add(std::move(oneW));
346 break;
347 }
Nicolas Penaf45ade32017-05-03 10:23:49 -0400348 ++it;
349 int next_ch = it->first;
350 int next_w = it->second;
351 if (next_ch == ch + 1 && next_w == w) {
Nicolas Penad03ca422017-03-06 13:54:33 -0500352 // The array can have a group c_first c_last w: all CIDs in the range from
353 // c_first to c_last will have width w
Nicolas Penaf45ade32017-05-03 10:23:49 -0400354 widthsArray->AddNew<CPDF_Number>(ch);
355 ch = next_ch;
Nicolas Penad03ca422017-03-06 13:54:33 -0500356 while (true) {
Nicolas Penaf45ade32017-05-03 10:23:49 -0400357 auto next_it = std::next(it);
358 if (next_it == widths.end() || next_it->first != it->first + 1 ||
359 next_it->second != it->second) {
Nicolas Penad03ca422017-03-06 13:54:33 -0500360 break;
Nicolas Penaf45ade32017-05-03 10:23:49 -0400361 }
362 ++it;
363 ch = it->first;
Nicolas Penad03ca422017-03-06 13:54:33 -0500364 }
Nicolas Penaf45ade32017-05-03 10:23:49 -0400365 widthsArray->AddNew<CPDF_Number>(ch);
366 widthsArray->AddNew<CPDF_Number>(w);
367 continue;
Nicolas Penad03ca422017-03-06 13:54:33 -0500368 }
Nicolas Penaf45ade32017-05-03 10:23:49 -0400369 // Otherwise we can have a group of the form c [w1 w2 ...]: c has width
370 // w1, c+1 has width w2, etc.
371 widthsArray->AddNew<CPDF_Number>(ch);
372 auto curWidthArray = pdfium::MakeUnique<CPDF_Array>();
373 curWidthArray->AddNew<CPDF_Number>(w);
374 curWidthArray->AddNew<CPDF_Number>(next_w);
375 while (true) {
376 auto next_it = std::next(it);
377 if (next_it == widths.end() || next_it->first != it->first + 1)
378 break;
379 ++it;
380 curWidthArray->AddNew<CPDF_Number>(static_cast<int>(it->second));
381 }
382 widthsArray->Add(std::move(curWidthArray));
Nicolas Penad03ca422017-03-06 13:54:33 -0500383 }
384 pCIDFont->SetNewFor<CPDF_Reference>("W", pDoc, widthsArray->GetObjNum());
385 // TODO(npm): Support vertical writing
386
387 auto pDescendant = pdfium::MakeUnique<CPDF_Array>();
388 pDescendant->AddNew<CPDF_Reference>(pDoc, pCIDFont->GetObjNum());
389 fontDict->SetFor("DescendantFonts", std::move(pDescendant));
Nicolas Penaf45ade32017-05-03 10:23:49 -0400390 CPDF_Stream* toUnicodeStream = LoadUnicode(pDoc, to_unicode);
391 fontDict->SetNewFor<CPDF_Reference>("ToUnicode", pDoc,
392 toUnicodeStream->GetObjNum());
Nicolas Penad03ca422017-03-06 13:54:33 -0500393 return pDoc->LoadFont(fontDict);
394}
395
396} // namespace
397
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400398FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV
399FPDFPageObj_NewTextObj(FPDF_DOCUMENT document,
400 FPDF_BYTESTRING font,
401 float font_size) {
Nicolas Pena49058402017-02-14 18:26:20 -0500402 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
403 if (!pDoc)
404 return nullptr;
405
Ryan Harrison275e2602017-09-18 14:23:18 -0400406 CPDF_Font* pFont = CPDF_Font::GetStockFont(pDoc, ByteStringView(font));
Nicolas Pena49058402017-02-14 18:26:20 -0500407 if (!pFont)
408 return nullptr;
409
Tom Sepezfe91c6c2017-05-16 15:33:20 -0700410 auto pTextObj = pdfium::MakeUnique<CPDF_TextObject>();
Nicolas Pena49058402017-02-14 18:26:20 -0500411 pTextObj->m_TextState.SetFont(pFont);
412 pTextObj->m_TextState.SetFontSize(font_size);
413 pTextObj->DefaultStates();
Tom Sepezfe91c6c2017-05-16 15:33:20 -0700414 return pTextObj.release(); // Caller takes ownership.
Nicolas Pena49058402017-02-14 18:26:20 -0500415}
416
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400417FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
418FPDFText_SetText(FPDF_PAGEOBJECT text_object, FPDF_WIDESTRING text) {
Nicolas Pena54b91662017-05-05 16:49:30 -0400419 auto* pTextObj = static_cast<CPDF_TextObject*>(text_object);
420 if (!pTextObj)
Nicolas Pena49058402017-02-14 18:26:20 -0500421 return false;
422
Ryan Harrison275e2602017-09-18 14:23:18 -0400423 FX_STRSIZE len = WideString::WStringLength(text);
424 WideString encodedText = WideString::FromUTF16LE(text, len);
425 ByteString byteText;
Nicolas Penaf45ade32017-05-03 10:23:49 -0400426 for (wchar_t wc : encodedText) {
427 pTextObj->GetFont()->AppendChar(
428 &byteText, pTextObj->GetFont()->CharCodeFromUnicode(wc));
Nicolas Penab3161852017-05-02 14:12:50 -0400429 }
430 pTextObj->SetText(byteText);
Nicolas Pena49058402017-02-14 18:26:20 -0500431 return true;
Nicolas Penabe90aae2017-02-27 10:41:41 -0500432}
433
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400434FPDF_EXPORT FPDF_FONT FPDF_CALLCONV FPDFText_LoadFont(FPDF_DOCUMENT document,
435 const uint8_t* data,
436 uint32_t size,
437 int font_type,
438 FPDF_BOOL cid) {
Nicolas Penabe90aae2017-02-27 10:41:41 -0500439 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
Nicolas Penad03ca422017-03-06 13:54:33 -0500440 if (!pDoc || !data || size == 0 ||
441 (font_type != FPDF_FONT_TYPE1 && font_type != FPDF_FONT_TRUETYPE)) {
Nicolas Penabe90aae2017-02-27 10:41:41 -0500442 return nullptr;
Nicolas Penad03ca422017-03-06 13:54:33 -0500443 }
Nicolas Penabe90aae2017-02-27 10:41:41 -0500444
445 auto pFont = pdfium::MakeUnique<CFX_Font>();
446
Nicolas Penad03ca422017-03-06 13:54:33 -0500447 // TODO(npm): Maybe use FT_Get_X11_Font_Format to check format? Otherwise, we
448 // are allowing giving any font that can be loaded on freetype and setting it
449 // as any font type.
Nicolas Penabe90aae2017-02-27 10:41:41 -0500450 if (!pFont->LoadEmbedded(data, size))
451 return nullptr;
452
Nicolas Penad03ca422017-03-06 13:54:33 -0500453 return cid ? LoadCompositeFont(pDoc, std::move(pFont), data, size, font_type)
454 : LoadSimpleFont(pDoc, std::move(pFont), data, size, font_type);
Nicolas Penabe90aae2017-02-27 10:41:41 -0500455}
Nicolas Penab3161852017-05-02 14:12:50 -0400456
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400457FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
458FPDFText_SetFillColor(FPDF_PAGEOBJECT text_object,
459 unsigned int R,
460 unsigned int G,
461 unsigned int B,
462 unsigned int A) {
wileyrya864e9fb2017-05-26 11:38:14 -0500463 return FPDFPageObj_SetFillColor(text_object, R, G, B, A);
464}
465
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400466FPDF_EXPORT void FPDF_CALLCONV FPDFFont_Close(FPDF_FONT font) {
Nicolas Pena54b91662017-05-05 16:49:30 -0400467 CPDF_Font* pFont = static_cast<CPDF_Font*>(font);
468 if (!pFont)
Nicolas Penab3161852017-05-02 14:12:50 -0400469 return;
470
Lei Zhangb8a8c432017-05-04 14:10:50 -0700471 CPDF_Document* pDoc = pFont->GetDocument();
472 if (!pDoc)
473 return;
474
475 CPDF_DocPageData* pPageData = pDoc->GetPageData();
476 if (!pPageData->IsForceClear())
477 pPageData->ReleaseFont(pFont->GetFontDict());
Nicolas Penab3161852017-05-02 14:12:50 -0400478}
479
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400480FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV
Nicolas Penab3161852017-05-02 14:12:50 -0400481FPDFPageObj_CreateTextObj(FPDF_DOCUMENT document,
482 FPDF_FONT font,
483 float font_size) {
484 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
Nicolas Pena54b91662017-05-05 16:49:30 -0400485 CPDF_Font* pFont = static_cast<CPDF_Font*>(font);
486 if (!pDoc || !pFont)
Nicolas Penab3161852017-05-02 14:12:50 -0400487 return nullptr;
488
Nicolas Penab3161852017-05-02 14:12:50 -0400489 auto pTextObj = pdfium::MakeUnique<CPDF_TextObject>();
490 pTextObj->m_TextState.SetFont(pDoc->LoadFont(pFont->GetFontDict()));
491 pTextObj->m_TextState.SetFontSize(font_size);
492 pTextObj->DefaultStates();
493 return pTextObj.release();
494}