blob: f4e1d66bc1484bc11aebc0ae9f27e73da977be07 [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 Penad03ca422017-03-06 13:54:33 -05005#include <memory>
Nicolas Penabe90aae2017-02-27 10:41:41 -05006#include <utility>
Nicolas Pena49058402017-02-14 18:26:20 -05007
8#include "core/fpdfapi/cpdf_modulemgr.h"
9#include "core/fpdfapi/font/cpdf_font.h"
Nicolas Penabe90aae2017-02-27 10:41:41 -050010#include "core/fpdfapi/font/cpdf_type1font.h"
Nicolas Penab3161852017-05-02 14:12:50 -040011#include "core/fpdfapi/page/cpdf_docpagedata.h"
Nicolas Pena49058402017-02-14 18:26:20 -050012#include "core/fpdfapi/page/cpdf_textobject.h"
Nicolas Penabe90aae2017-02-27 10:41:41 -050013#include "core/fpdfapi/parser/cpdf_array.h"
14#include "core/fpdfapi/parser/cpdf_dictionary.h"
15#include "core/fpdfapi/parser/cpdf_document.h"
16#include "core/fpdfapi/parser/cpdf_name.h"
17#include "core/fpdfapi/parser/cpdf_number.h"
18#include "core/fpdfapi/parser/cpdf_reference.h"
19#include "core/fpdfapi/parser/cpdf_stream.h"
20#include "core/fxge/cfx_fontmgr.h"
21#include "core/fxge/fx_font.h"
Nicolas Pena49058402017-02-14 18:26:20 -050022#include "fpdfsdk/fsdk_define.h"
Nicolas Penabe90aae2017-02-27 10:41:41 -050023#include "public/fpdf_edit.h"
Nicolas Pena49058402017-02-14 18:26:20 -050024
Nicolas Penad03ca422017-03-06 13:54:33 -050025namespace {
26
27CPDF_Dictionary* LoadFontDesc(CPDF_Document* pDoc,
28 const CFX_ByteString& font_name,
29 CFX_Font* pFont,
30 const uint8_t* data,
31 uint32_t size,
32 int font_type) {
33 CPDF_Dictionary* fontDesc = pDoc->NewIndirect<CPDF_Dictionary>();
34 fontDesc->SetNewFor<CPDF_Name>("Type", "FontDescriptor");
35 fontDesc->SetNewFor<CPDF_Name>("FontName", font_name);
36 int flags = 0;
37 if (FXFT_Is_Face_fixedwidth(pFont->GetFace()))
38 flags |= FXFONT_FIXED_PITCH;
39 if (font_name.Find("Serif") > -1)
40 flags |= FXFONT_SERIF;
41 if (FXFT_Is_Face_Italic(pFont->GetFace()))
42 flags |= FXFONT_ITALIC;
43 if (FXFT_Is_Face_Bold(pFont->GetFace()))
44 flags |= FXFONT_BOLD;
45
46 // TODO(npm): How do I know if a font is symbolic, script, allcap, smallcap
47 flags |= FXFONT_NONSYMBOLIC;
48
49 fontDesc->SetNewFor<CPDF_Number>("Flags", flags);
50 FX_RECT bbox;
51 pFont->GetBBox(bbox);
52 auto pBBox = pdfium::MakeUnique<CPDF_Array>();
53 pBBox->AddNew<CPDF_Number>(bbox.left);
54 pBBox->AddNew<CPDF_Number>(bbox.bottom);
55 pBBox->AddNew<CPDF_Number>(bbox.right);
56 pBBox->AddNew<CPDF_Number>(bbox.top);
57 fontDesc->SetFor("FontBBox", std::move(pBBox));
58
59 // TODO(npm): calculate italic angle correctly
60 fontDesc->SetNewFor<CPDF_Number>("ItalicAngle", pFont->IsItalic() ? -12 : 0);
61
62 fontDesc->SetNewFor<CPDF_Number>("Ascent", pFont->GetAscent());
63 fontDesc->SetNewFor<CPDF_Number>("Descent", pFont->GetDescent());
64
65 // TODO(npm): calculate the capheight, stemV correctly
66 fontDesc->SetNewFor<CPDF_Number>("CapHeight", pFont->GetAscent());
67 fontDesc->SetNewFor<CPDF_Number>("StemV", pFont->IsBold() ? 120 : 70);
68
69 CPDF_Stream* pStream = pDoc->NewIndirect<CPDF_Stream>();
70 pStream->SetData(data, size);
71 CFX_ByteString fontFile =
72 font_type == FPDF_FONT_TYPE1 ? "FontFile" : "FontFile2";
73 fontDesc->SetNewFor<CPDF_Reference>(fontFile, pDoc, pStream->GetObjNum());
74 return fontDesc;
75}
76
77void* LoadSimpleFont(CPDF_Document* pDoc,
78 std::unique_ptr<CFX_Font> pFont,
79 const uint8_t* data,
80 uint32_t size,
81 int font_type) {
82 CPDF_Dictionary* fontDict = pDoc->NewIndirect<CPDF_Dictionary>();
83 fontDict->SetNewFor<CPDF_Name>("Type", "Font");
84 fontDict->SetNewFor<CPDF_Name>(
85 "Subtype", font_type == FPDF_FONT_TYPE1 ? "Type1" : "TrueType");
86 CFX_ByteString name = pFont->GetFaceName();
87 if (name.IsEmpty())
88 name = "Unnamed";
89 fontDict->SetNewFor<CPDF_Name>("BaseFont", name);
90
91 uint32_t glyphIndex;
92 int currentChar = FXFT_Get_First_Char(pFont->GetFace(), &glyphIndex);
93 fontDict->SetNewFor<CPDF_Number>("FirstChar", currentChar);
94 CPDF_Array* widthsArray = pDoc->NewIndirect<CPDF_Array>();
95 while (true) {
96 int width = pFont->GetGlyphWidth(glyphIndex);
97 widthsArray->AddNew<CPDF_Number>(width);
98 int nextChar =
99 FXFT_Get_Next_Char(pFont->GetFace(), currentChar, &glyphIndex);
100 // Simple fonts have 1-byte charcodes only.
101 if (nextChar > 0xff || glyphIndex == 0)
102 break;
103 for (int i = currentChar + 1; i < nextChar; i++)
104 widthsArray->AddNew<CPDF_Number>(0);
105 currentChar = nextChar;
106 }
107 fontDict->SetNewFor<CPDF_Number>("LastChar", currentChar);
108 fontDict->SetNewFor<CPDF_Reference>("Widths", pDoc, widthsArray->GetObjNum());
109 CPDF_Dictionary* fontDesc =
110 LoadFontDesc(pDoc, name, pFont.get(), data, size, font_type);
111
112 fontDict->SetNewFor<CPDF_Reference>("FontDescriptor", pDoc,
113 fontDesc->GetObjNum());
114 return pDoc->LoadFont(fontDict);
115}
116
117void* LoadCompositeFont(CPDF_Document* pDoc,
118 std::unique_ptr<CFX_Font> pFont,
119 const uint8_t* data,
120 uint32_t size,
121 int font_type) {
122 CPDF_Dictionary* fontDict = pDoc->NewIndirect<CPDF_Dictionary>();
123 fontDict->SetNewFor<CPDF_Name>("Type", "Font");
124 fontDict->SetNewFor<CPDF_Name>("Subtype", "Type0");
125 // TODO(npm): Get the correct encoding, if it's not identity.
126 CFX_ByteString encoding = "Identity-H";
127 fontDict->SetNewFor<CPDF_Name>("Encoding", encoding);
128 CFX_ByteString name = pFont->GetFaceName();
129 if (name.IsEmpty())
130 name = "Unnamed";
131 fontDict->SetNewFor<CPDF_Name>(
132 "BaseFont", font_type == FPDF_FONT_TYPE1 ? name + "-" + encoding : name);
133
134 CPDF_Dictionary* pCIDFont = pDoc->NewIndirect<CPDF_Dictionary>();
135 pCIDFont->SetNewFor<CPDF_Name>("Type", "Font");
136 pCIDFont->SetNewFor<CPDF_Name>("Subtype", font_type == FPDF_FONT_TYPE1
137 ? "CIDFontType0"
138 : "CIDFontType2");
139 pCIDFont->SetNewFor<CPDF_Name>("BaseFont", name);
140
141 // TODO(npm): Maybe use FT_Get_CID_Registry_Ordering_Supplement to get the
142 // CIDSystemInfo
143 CPDF_Dictionary* pCIDSystemInfo = pDoc->NewIndirect<CPDF_Dictionary>();
144 pCIDSystemInfo->SetNewFor<CPDF_Name>("Registry", "Adobe");
145 pCIDSystemInfo->SetNewFor<CPDF_Name>("Ordering", "Identity");
146 pCIDSystemInfo->SetNewFor<CPDF_Number>("Supplement", 0);
147 pCIDFont->SetNewFor<CPDF_Reference>("CIDSystemInfo", pDoc,
148 pCIDSystemInfo->GetObjNum());
149
150 CPDF_Dictionary* fontDesc =
151 LoadFontDesc(pDoc, name, pFont.get(), data, size, font_type);
152 pCIDFont->SetNewFor<CPDF_Reference>("FontDescriptor", pDoc,
153 fontDesc->GetObjNum());
154
155 uint32_t glyphIndex;
156 int currentChar = FXFT_Get_First_Char(pFont->GetFace(), &glyphIndex);
157 CPDF_Array* widthsArray = pDoc->NewIndirect<CPDF_Array>();
158 while (true) {
159 int width = pFont->GetGlyphWidth(glyphIndex);
160 int nextChar =
161 FXFT_Get_Next_Char(pFont->GetFace(), currentChar, &glyphIndex);
162 if (glyphIndex == 0) {
163 // Only one char left, use format c [w]
164 auto oneW = pdfium::MakeUnique<CPDF_Array>();
165 oneW->AddNew<CPDF_Number>(width);
166 widthsArray->AddNew<CPDF_Number>(currentChar);
167 widthsArray->Add(std::move(oneW));
168 break;
169 }
170 int nextWidth = pFont->GetGlyphWidth(glyphIndex);
171 if (nextChar == currentChar + 1 && nextWidth == width) {
172 // The array can have a group c_first c_last w: all CIDs in the range from
173 // c_first to c_last will have width w
174 widthsArray->AddNew<CPDF_Number>(currentChar);
175 currentChar = nextChar;
176 while (true) {
177 nextChar =
178 FXFT_Get_Next_Char(pFont->GetFace(), currentChar, &glyphIndex);
179 if (glyphIndex == 0)
180 break;
181 nextWidth = pFont->GetGlyphWidth(glyphIndex);
182 if (nextChar != currentChar + 1 || nextWidth != width)
183 break;
184 currentChar = nextChar;
185 }
186 widthsArray->AddNew<CPDF_Number>(currentChar);
187 widthsArray->AddNew<CPDF_Number>(width);
188 } else {
189 // Otherwise we can have a group of the form c [w1 w2 ...]: c has width
190 // w1, c+1 has width w2, etc.
191 widthsArray->AddNew<CPDF_Number>(currentChar);
192 auto curWidthArray = pdfium::MakeUnique<CPDF_Array>();
193 curWidthArray->AddNew<CPDF_Number>(width);
194 while (nextChar == currentChar + 1) {
195 curWidthArray->AddNew<CPDF_Number>(nextWidth);
196 currentChar = nextChar;
197 nextChar =
198 FXFT_Get_Next_Char(pFont->GetFace(), currentChar, &glyphIndex);
199 if (glyphIndex == 0)
200 break;
201 nextWidth = pFont->GetGlyphWidth(glyphIndex);
202 }
203 widthsArray->Add(std::move(curWidthArray));
204 }
205 if (glyphIndex == 0)
206 break;
207 currentChar = nextChar;
208 }
209 pCIDFont->SetNewFor<CPDF_Reference>("W", pDoc, widthsArray->GetObjNum());
210 // TODO(npm): Support vertical writing
211
212 auto pDescendant = pdfium::MakeUnique<CPDF_Array>();
213 pDescendant->AddNew<CPDF_Reference>(pDoc, pCIDFont->GetObjNum());
214 fontDict->SetFor("DescendantFonts", std::move(pDescendant));
215 // TODO(npm): do we need a ToUnicode?
216 return pDoc->LoadFont(fontDict);
217}
218
219} // namespace
220
Nicolas Pena49058402017-02-14 18:26:20 -0500221DLLEXPORT FPDF_PAGEOBJECT STDCALL FPDFPageObj_NewTextObj(FPDF_DOCUMENT document,
222 FPDF_BYTESTRING font,
223 float font_size) {
224 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
225 if (!pDoc)
226 return nullptr;
227
228 CPDF_Font* pFont = CPDF_Font::GetStockFont(pDoc, CFX_ByteStringC(font));
229 if (!pFont)
230 return nullptr;
231
232 CPDF_TextObject* pTextObj = new CPDF_TextObject;
233 pTextObj->m_TextState.SetFont(pFont);
234 pTextObj->m_TextState.SetFontSize(font_size);
235 pTextObj->DefaultStates();
236 return pTextObj;
237}
238
239DLLEXPORT FPDF_BOOL STDCALL FPDFText_SetText(FPDF_PAGEOBJECT text_object,
Nicolas Penab3161852017-05-02 14:12:50 -0400240 FPDF_WIDESTRING text) {
Nicolas Pena49058402017-02-14 18:26:20 -0500241 if (!text_object)
242 return false;
243
Lei Zhang375c2762017-03-10 14:37:14 -0800244 auto* pTextObj = reinterpret_cast<CPDF_TextObject*>(text_object);
Nicolas Penab3161852017-05-02 14:12:50 -0400245 FX_STRSIZE len = CFX_WideString::WStringLength(text);
246 CFX_WideString encodedText = CFX_WideString::FromUTF16LE(text, len);
247 CFX_ByteString byteText;
248 for (int i = 0; i < encodedText.GetLength(); ++i) {
249 uint32_t charcode =
250 pTextObj->GetFont()->CharCodeFromUnicode(encodedText[i]);
251 pTextObj->GetFont()->AppendChar(&byteText, charcode);
252 }
253 pTextObj->SetText(byteText);
Nicolas Pena49058402017-02-14 18:26:20 -0500254 return true;
Nicolas Penabe90aae2017-02-27 10:41:41 -0500255}
256
Nicolas Penad03ca422017-03-06 13:54:33 -0500257DLLEXPORT FPDF_FONT STDCALL FPDFText_LoadFont(FPDF_DOCUMENT document,
258 const uint8_t* data,
259 uint32_t size,
260 int font_type,
261 FPDF_BOOL cid) {
Nicolas Penabe90aae2017-02-27 10:41:41 -0500262 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
Nicolas Penad03ca422017-03-06 13:54:33 -0500263 if (!pDoc || !data || size == 0 ||
264 (font_type != FPDF_FONT_TYPE1 && font_type != FPDF_FONT_TRUETYPE)) {
Nicolas Penabe90aae2017-02-27 10:41:41 -0500265 return nullptr;
Nicolas Penad03ca422017-03-06 13:54:33 -0500266 }
Nicolas Penabe90aae2017-02-27 10:41:41 -0500267
268 auto pFont = pdfium::MakeUnique<CFX_Font>();
269
Nicolas Penad03ca422017-03-06 13:54:33 -0500270 // TODO(npm): Maybe use FT_Get_X11_Font_Format to check format? Otherwise, we
271 // are allowing giving any font that can be loaded on freetype and setting it
272 // as any font type.
Nicolas Penabe90aae2017-02-27 10:41:41 -0500273 if (!pFont->LoadEmbedded(data, size))
274 return nullptr;
275
Nicolas Penad03ca422017-03-06 13:54:33 -0500276 return cid ? LoadCompositeFont(pDoc, std::move(pFont), data, size, font_type)
277 : LoadSimpleFont(pDoc, std::move(pFont), data, size, font_type);
Nicolas Penabe90aae2017-02-27 10:41:41 -0500278}
Nicolas Penab3161852017-05-02 14:12:50 -0400279
280DLLEXPORT void STDCALL FPDFFont_Close(FPDF_FONT font) {
281 if (!font)
282 return;
283
284 CPDF_Font* cpdf_font = reinterpret_cast<CPDF_Font*>(font);
285 CPDF_Document* pDoc = cpdf_font->m_pDocument;
286 CPDF_DocPageData* pPageData = pDoc ? pDoc->GetPageData() : nullptr;
287 if (pPageData && !pPageData->IsForceClear())
288 pPageData->ReleaseFont(cpdf_font->GetFontDict());
289}
290
291DLLEXPORT FPDF_PAGEOBJECT STDCALL
292FPDFPageObj_CreateTextObj(FPDF_DOCUMENT document,
293 FPDF_FONT font,
294 float font_size) {
295 CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
296 if (!pDoc || !font)
297 return nullptr;
298
299 CPDF_Font* pFont = reinterpret_cast<CPDF_Font*>(font);
300
301 auto pTextObj = pdfium::MakeUnique<CPDF_TextObject>();
302 pTextObj->m_TextState.SetFont(pDoc->LoadFont(pFont->GetFontDict()));
303 pTextObj->m_TextState.SetFontSize(font_size);
304 pTextObj->DefaultStates();
305 return pTextObj.release();
306}