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