1 // Copyright 2014 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
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "core/fpdfapi/page/cpdf_docpagedata.h"
8
9 #include <algorithm>
10 #include <memory>
11 #include <set>
12 #include <utility>
13 #include <vector>
14
15 #include "build/build_config.h"
16 #include "core/fpdfapi/font/cpdf_type1font.h"
17 #include "core/fpdfapi/page/cpdf_form.h"
18 #include "core/fpdfapi/page/cpdf_iccprofile.h"
19 #include "core/fpdfapi/page/cpdf_image.h"
20 #include "core/fpdfapi/page/cpdf_pagemodule.h"
21 #include "core/fpdfapi/page/cpdf_pattern.h"
22 #include "core/fpdfapi/page/cpdf_shadingpattern.h"
23 #include "core/fpdfapi/page/cpdf_tilingpattern.h"
24 #include "core/fpdfapi/parser/cpdf_array.h"
25 #include "core/fpdfapi/parser/cpdf_dictionary.h"
26 #include "core/fpdfapi/parser/cpdf_name.h"
27 #include "core/fpdfapi/parser/cpdf_number.h"
28 #include "core/fpdfapi/parser/cpdf_reference.h"
29 #include "core/fpdfapi/parser/cpdf_stream.h"
30 #include "core/fpdfapi/parser/cpdf_stream_acc.h"
31 #include "core/fpdfapi/parser/cpdf_string.h"
32 #include "core/fxcrt/fx_codepage.h"
33 #include "core/fxcrt/fx_safe_types.h"
34 #include "core/fxge/cfx_font.h"
35 #include "core/fxge/cfx_fontmapper.h"
36 #include "core/fxge/cfx_substfont.h"
37 #include "core/fxge/cfx_unicodeencoding.h"
38 #include "core/fxge/fx_font.h"
39 #include "third_party/base/ptr_util.h"
40 #include "third_party/base/stl_util.h"
41
42 namespace {
43
InsertWidthArrayImpl(std::vector<int> widths,CPDF_Array * pWidthArray)44 void InsertWidthArrayImpl(std::vector<int> widths, CPDF_Array* pWidthArray) {
45 size_t i;
46 for (i = 1; i < widths.size(); i++) {
47 if (widths[i] != widths[0])
48 break;
49 }
50 if (i == widths.size()) {
51 int first = pWidthArray->GetIntegerAt(pWidthArray->size() - 1);
52 pWidthArray->AddNew<CPDF_Number>(first + static_cast<int>(widths.size()) -
53 1);
54 pWidthArray->AddNew<CPDF_Number>(widths[0]);
55 return;
56 }
57 CPDF_Array* pWidthArray1 = pWidthArray->AddNew<CPDF_Array>();
58 for (int w : widths)
59 pWidthArray1->AddNew<CPDF_Number>(w);
60 }
61
62 #if defined(OS_WIN)
InsertWidthArray(HDC hDC,int start,int end,CPDF_Array * pWidthArray)63 void InsertWidthArray(HDC hDC, int start, int end, CPDF_Array* pWidthArray) {
64 std::vector<int> widths(end - start + 1);
65 GetCharWidth(hDC, start, end, widths.data());
66 InsertWidthArrayImpl(std::move(widths), pWidthArray);
67 }
68
GetPSNameFromTT(HDC hDC)69 ByteString GetPSNameFromTT(HDC hDC) {
70 ByteString result;
71 DWORD size = ::GetFontData(hDC, 'eman', 0, nullptr, 0);
72 if (size != GDI_ERROR) {
73 LPBYTE buffer = FX_Alloc(BYTE, size);
74 ::GetFontData(hDC, 'eman', 0, buffer, size);
75 result = GetNameFromTT({buffer, size}, 6);
76 FX_Free(buffer);
77 }
78 return result;
79 }
80 #endif // defined(OS_WIN)
81
InsertWidthArray1(CFX_Font * pFont,CFX_UnicodeEncoding * pEncoding,wchar_t start,wchar_t end,CPDF_Array * pWidthArray)82 void InsertWidthArray1(CFX_Font* pFont,
83 CFX_UnicodeEncoding* pEncoding,
84 wchar_t start,
85 wchar_t end,
86 CPDF_Array* pWidthArray) {
87 std::vector<int> widths(end - start + 1);
88 for (size_t i = 0; i < widths.size(); ++i) {
89 int glyph_index = pEncoding->GlyphFromCharCode(start + i);
90 widths[i] = pFont->GetGlyphWidth(glyph_index);
91 }
92 InsertWidthArrayImpl(std::move(widths), pWidthArray);
93 }
94
CalculateFlags(bool bold,bool italic,bool fixedPitch,bool serif,bool script,bool symbolic)95 int CalculateFlags(bool bold,
96 bool italic,
97 bool fixedPitch,
98 bool serif,
99 bool script,
100 bool symbolic) {
101 int flags = 0;
102 if (bold)
103 flags |= FXFONT_FORCE_BOLD;
104 if (italic)
105 flags |= FXFONT_ITALIC;
106 if (fixedPitch)
107 flags |= FXFONT_FIXED_PITCH;
108 if (serif)
109 flags |= FXFONT_SERIF;
110 if (script)
111 flags |= FXFONT_SCRIPT;
112 if (symbolic)
113 flags |= FXFONT_SYMBOLIC;
114 else
115 flags |= FXFONT_NONSYMBOLIC;
116 return flags;
117 }
118
ProcessNonbCJK(CPDF_Dictionary * pBaseDict,bool bold,bool italic,ByteString basefont,RetainPtr<CPDF_Array> pWidths)119 void ProcessNonbCJK(CPDF_Dictionary* pBaseDict,
120 bool bold,
121 bool italic,
122 ByteString basefont,
123 RetainPtr<CPDF_Array> pWidths) {
124 if (bold && italic)
125 basefont += ",BoldItalic";
126 else if (bold)
127 basefont += ",Bold";
128 else if (italic)
129 basefont += ",Italic";
130 pBaseDict->SetNewFor<CPDF_Name>("Subtype", "TrueType");
131 pBaseDict->SetNewFor<CPDF_Name>("BaseFont", basefont);
132 pBaseDict->SetNewFor<CPDF_Number>("FirstChar", 32);
133 pBaseDict->SetNewFor<CPDF_Number>("LastChar", 255);
134 pBaseDict->SetFor("Widths", pWidths);
135 }
136
CalculateFontDesc(CPDF_Document * pDoc,ByteString basefont,int flags,int italicangle,int ascend,int descend,RetainPtr<CPDF_Array> bbox,int32_t stemV)137 RetainPtr<CPDF_Dictionary> CalculateFontDesc(CPDF_Document* pDoc,
138 ByteString basefont,
139 int flags,
140 int italicangle,
141 int ascend,
142 int descend,
143 RetainPtr<CPDF_Array> bbox,
144 int32_t stemV) {
145 auto pFontDesc = pDoc->New<CPDF_Dictionary>();
146 pFontDesc->SetNewFor<CPDF_Name>("Type", "FontDescriptor");
147 pFontDesc->SetNewFor<CPDF_Name>("FontName", basefont);
148 pFontDesc->SetNewFor<CPDF_Number>("Flags", flags);
149 pFontDesc->SetFor("FontBBox", bbox);
150 pFontDesc->SetNewFor<CPDF_Number>("ItalicAngle", italicangle);
151 pFontDesc->SetNewFor<CPDF_Number>("Ascent", ascend);
152 pFontDesc->SetNewFor<CPDF_Number>("Descent", descend);
153 pFontDesc->SetNewFor<CPDF_Number>("StemV", stemV);
154 return pFontDesc;
155 }
156
157 } // namespace
158
159 // static
FromDocument(const CPDF_Document * pDoc)160 CPDF_DocPageData* CPDF_DocPageData::FromDocument(const CPDF_Document* pDoc) {
161 return static_cast<CPDF_DocPageData*>(pDoc->GetPageData());
162 }
163
164 CPDF_DocPageData::CPDF_DocPageData() = default;
165
~CPDF_DocPageData()166 CPDF_DocPageData::~CPDF_DocPageData() {
167 for (auto& it : m_FontMap) {
168 if (it.second)
169 it.second->WillBeDestroyed();
170 }
171 }
172
ClearStockFont()173 void CPDF_DocPageData::ClearStockFont() {
174 CPDF_PageModule::GetInstance()->ClearStockFont(GetDocument());
175 }
176
GetFont(CPDF_Dictionary * pFontDict)177 RetainPtr<CPDF_Font> CPDF_DocPageData::GetFont(CPDF_Dictionary* pFontDict) {
178 if (!pFontDict)
179 return nullptr;
180
181 auto it = m_FontMap.find(pFontDict);
182 if (it != m_FontMap.end() && it->second)
183 return pdfium::WrapRetain(it->second.Get());
184
185 RetainPtr<CPDF_Font> pFont =
186 CPDF_Font::Create(GetDocument(), pFontDict, this);
187 if (!pFont)
188 return nullptr;
189
190 m_FontMap[pFontDict].Reset(pFont.Get());
191 return pFont;
192 }
193
GetStandardFont(const ByteString & fontName,const CPDF_FontEncoding * pEncoding)194 RetainPtr<CPDF_Font> CPDF_DocPageData::GetStandardFont(
195 const ByteString& fontName,
196 const CPDF_FontEncoding* pEncoding) {
197 if (fontName.IsEmpty())
198 return nullptr;
199
200 for (auto& it : m_FontMap) {
201 CPDF_Font* pFont = it.second.Get();
202 if (!pFont)
203 continue;
204 if (pFont->GetBaseFontName() != fontName)
205 continue;
206 if (pFont->IsEmbedded())
207 continue;
208 if (!pFont->IsType1Font())
209 continue;
210 if (pFont->GetFontDict()->KeyExist("Widths"))
211 continue;
212
213 CPDF_Type1Font* pT1Font = pFont->AsType1Font();
214 if (pEncoding && !pT1Font->GetEncoding()->IsIdentical(pEncoding))
215 continue;
216
217 return pdfium::WrapRetain(pFont);
218 }
219
220 CPDF_Dictionary* pDict = GetDocument()->NewIndirect<CPDF_Dictionary>();
221 pDict->SetNewFor<CPDF_Name>("Type", "Font");
222 pDict->SetNewFor<CPDF_Name>("Subtype", "Type1");
223 pDict->SetNewFor<CPDF_Name>("BaseFont", fontName);
224 if (pEncoding) {
225 pDict->SetFor("Encoding",
226 pEncoding->Realize(GetDocument()->GetByteStringPool()));
227 }
228
229 // Note: NULL FormFactoryIface OK since known Type1 font from above.
230 RetainPtr<CPDF_Font> pFont = CPDF_Font::Create(GetDocument(), pDict, nullptr);
231 if (!pFont)
232 return nullptr;
233
234 m_FontMap[pDict].Reset(pFont.Get());
235 return pFont;
236 }
237
GetColorSpace(const CPDF_Object * pCSObj,const CPDF_Dictionary * pResources)238 RetainPtr<CPDF_ColorSpace> CPDF_DocPageData::GetColorSpace(
239 const CPDF_Object* pCSObj,
240 const CPDF_Dictionary* pResources) {
241 std::set<const CPDF_Object*> visited;
242 return GetColorSpaceGuarded(pCSObj, pResources, &visited);
243 }
244
GetColorSpaceGuarded(const CPDF_Object * pCSObj,const CPDF_Dictionary * pResources,std::set<const CPDF_Object * > * pVisited)245 RetainPtr<CPDF_ColorSpace> CPDF_DocPageData::GetColorSpaceGuarded(
246 const CPDF_Object* pCSObj,
247 const CPDF_Dictionary* pResources,
248 std::set<const CPDF_Object*>* pVisited) {
249 std::set<const CPDF_Object*> visitedLocal;
250 return GetColorSpaceInternal(pCSObj, pResources, pVisited, &visitedLocal);
251 }
252
GetColorSpaceInternal(const CPDF_Object * pCSObj,const CPDF_Dictionary * pResources,std::set<const CPDF_Object * > * pVisited,std::set<const CPDF_Object * > * pVisitedInternal)253 RetainPtr<CPDF_ColorSpace> CPDF_DocPageData::GetColorSpaceInternal(
254 const CPDF_Object* pCSObj,
255 const CPDF_Dictionary* pResources,
256 std::set<const CPDF_Object*>* pVisited,
257 std::set<const CPDF_Object*>* pVisitedInternal) {
258 if (!pCSObj)
259 return nullptr;
260
261 if (pdfium::ContainsKey(*pVisitedInternal, pCSObj))
262 return nullptr;
263
264 pdfium::ScopedSetInsertion<const CPDF_Object*> insertion(pVisitedInternal,
265 pCSObj);
266
267 if (pCSObj->IsName()) {
268 ByteString name = pCSObj->GetString();
269 RetainPtr<CPDF_ColorSpace> pCS = CPDF_ColorSpace::ColorspaceFromName(name);
270 if (!pCS && pResources) {
271 const CPDF_Dictionary* pList = pResources->GetDictFor("ColorSpace");
272 if (pList) {
273 return GetColorSpaceInternal(pList->GetDirectObjectFor(name), nullptr,
274 pVisited, pVisitedInternal);
275 }
276 }
277 if (!pCS || !pResources)
278 return pCS;
279
280 const CPDF_Dictionary* pColorSpaces = pResources->GetDictFor("ColorSpace");
281 if (!pColorSpaces)
282 return pCS;
283
284 const CPDF_Object* pDefaultCS = nullptr;
285 switch (pCS->GetFamily()) {
286 case PDFCS_DEVICERGB:
287 pDefaultCS = pColorSpaces->GetDirectObjectFor("DefaultRGB");
288 break;
289 case PDFCS_DEVICEGRAY:
290 pDefaultCS = pColorSpaces->GetDirectObjectFor("DefaultGray");
291 break;
292 case PDFCS_DEVICECMYK:
293 pDefaultCS = pColorSpaces->GetDirectObjectFor("DefaultCMYK");
294 break;
295 }
296 if (!pDefaultCS)
297 return pCS;
298
299 return GetColorSpaceInternal(pDefaultCS, nullptr, pVisited,
300 pVisitedInternal);
301 }
302
303 const CPDF_Array* pArray = pCSObj->AsArray();
304 if (!pArray || pArray->IsEmpty())
305 return nullptr;
306
307 if (pArray->size() == 1) {
308 return GetColorSpaceInternal(pArray->GetDirectObjectAt(0), pResources,
309 pVisited, pVisitedInternal);
310 }
311
312 auto it = m_ColorSpaceMap.find(pCSObj);
313 if (it != m_ColorSpaceMap.end() && it->second)
314 return pdfium::WrapRetain(it->second.Get());
315
316 RetainPtr<CPDF_ColorSpace> pCS =
317 CPDF_ColorSpace::Load(GetDocument(), pArray, pVisited);
318 if (!pCS)
319 return nullptr;
320
321 m_ColorSpaceMap[pCSObj].Reset(pCS.Get());
322 return pCS;
323 }
324
GetPattern(CPDF_Object * pPatternObj,bool bShading,const CFX_Matrix & matrix)325 RetainPtr<CPDF_Pattern> CPDF_DocPageData::GetPattern(CPDF_Object* pPatternObj,
326 bool bShading,
327 const CFX_Matrix& matrix) {
328 if (!pPatternObj)
329 return nullptr;
330
331 auto it = m_PatternMap.find(pPatternObj);
332 if (it != m_PatternMap.end() && it->second)
333 return pdfium::WrapRetain(it->second.Get());
334
335 RetainPtr<CPDF_Pattern> pPattern;
336 if (bShading) {
337 pPattern = pdfium::MakeRetain<CPDF_ShadingPattern>(
338 GetDocument(), pPatternObj, true, matrix);
339 } else {
340 CPDF_Dictionary* pDict = pPatternObj->GetDict();
341 if (!pDict)
342 return nullptr;
343
344 int type = pDict->GetIntegerFor("PatternType");
345 if (type == CPDF_Pattern::kTiling) {
346 pPattern = pdfium::MakeRetain<CPDF_TilingPattern>(GetDocument(),
347 pPatternObj, matrix);
348 } else if (type == CPDF_Pattern::kShading) {
349 pPattern = pdfium::MakeRetain<CPDF_ShadingPattern>(
350 GetDocument(), pPatternObj, false, matrix);
351 } else {
352 return nullptr;
353 }
354 }
355
356 m_PatternMap[pPatternObj].Reset(pPattern.Get());
357 return pPattern;
358 }
359
GetImage(uint32_t dwStreamObjNum)360 RetainPtr<CPDF_Image> CPDF_DocPageData::GetImage(uint32_t dwStreamObjNum) {
361 ASSERT(dwStreamObjNum);
362 auto it = m_ImageMap.find(dwStreamObjNum);
363 if (it != m_ImageMap.end())
364 return it->second;
365
366 auto pImage = pdfium::MakeRetain<CPDF_Image>(GetDocument(), dwStreamObjNum);
367 m_ImageMap[dwStreamObjNum] = pImage;
368 return pImage;
369 }
370
MaybePurgeImage(uint32_t dwStreamObjNum)371 void CPDF_DocPageData::MaybePurgeImage(uint32_t dwStreamObjNum) {
372 ASSERT(dwStreamObjNum);
373 auto it = m_ImageMap.find(dwStreamObjNum);
374 if (it != m_ImageMap.end() && it->second->HasOneRef())
375 m_ImageMap.erase(it);
376 }
377
GetIccProfile(const CPDF_Stream * pProfileStream)378 RetainPtr<CPDF_IccProfile> CPDF_DocPageData::GetIccProfile(
379 const CPDF_Stream* pProfileStream) {
380 if (!pProfileStream)
381 return nullptr;
382
383 auto it = m_IccProfileMap.find(pProfileStream);
384 if (it != m_IccProfileMap.end() && it->second)
385 return pdfium::WrapRetain(it->second.Get());
386
387 auto pAccessor = pdfium::MakeRetain<CPDF_StreamAcc>(pProfileStream);
388 pAccessor->LoadAllDataFiltered();
389
390 ByteString bsDigest = pAccessor->ComputeDigest();
391 auto hash_it = m_HashProfileMap.find(bsDigest);
392 if (hash_it != m_HashProfileMap.end()) {
393 auto it_copied_stream = m_IccProfileMap.find(hash_it->second.Get());
394 if (it_copied_stream != m_IccProfileMap.end() && it_copied_stream->second)
395 return pdfium::WrapRetain(it_copied_stream->second.Get());
396 }
397 auto pProfile =
398 pdfium::MakeRetain<CPDF_IccProfile>(pProfileStream, pAccessor->GetSpan());
399 m_IccProfileMap[pProfileStream].Reset(pProfile.Get());
400 m_HashProfileMap[bsDigest].Reset(pProfileStream);
401 return pProfile;
402 }
403
GetFontFileStreamAcc(const CPDF_Stream * pFontStream)404 RetainPtr<CPDF_StreamAcc> CPDF_DocPageData::GetFontFileStreamAcc(
405 const CPDF_Stream* pFontStream) {
406 ASSERT(pFontStream);
407 auto it = m_FontFileMap.find(pFontStream);
408 if (it != m_FontFileMap.end())
409 return it->second;
410
411 const CPDF_Dictionary* pFontDict = pFontStream->GetDict();
412 int32_t len1 = pFontDict->GetIntegerFor("Length1");
413 int32_t len2 = pFontDict->GetIntegerFor("Length2");
414 int32_t len3 = pFontDict->GetIntegerFor("Length3");
415 uint32_t org_size = 0;
416 if (len1 >= 0 && len2 >= 0 && len3 >= 0) {
417 FX_SAFE_UINT32 safe_org_size = len1;
418 safe_org_size += len2;
419 safe_org_size += len3;
420 org_size = safe_org_size.ValueOrDefault(0);
421 }
422
423 auto pFontAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pFontStream);
424 pFontAcc->LoadAllDataFilteredWithEstimatedSize(org_size);
425 m_FontFileMap[pFontStream] = pFontAcc;
426 return pFontAcc;
427 }
428
MaybePurgeFontFileStreamAcc(const CPDF_Stream * pFontStream)429 void CPDF_DocPageData::MaybePurgeFontFileStreamAcc(
430 const CPDF_Stream* pFontStream) {
431 if (!pFontStream)
432 return;
433
434 auto it = m_FontFileMap.find(pFontStream);
435 if (it != m_FontFileMap.end() && it->second->HasOneRef())
436 m_FontFileMap.erase(it);
437 }
438
CreateForm(CPDF_Document * pDocument,CPDF_Dictionary * pPageResources,CPDF_Stream * pFormStream)439 std::unique_ptr<CPDF_Font::FormIface> CPDF_DocPageData::CreateForm(
440 CPDF_Document* pDocument,
441 CPDF_Dictionary* pPageResources,
442 CPDF_Stream* pFormStream) {
443 return pdfium::MakeUnique<CPDF_Form>(pDocument, pPageResources, pFormStream);
444 }
445
AddStandardFont(const ByteString & fontName,const CPDF_FontEncoding * pEncoding)446 RetainPtr<CPDF_Font> CPDF_DocPageData::AddStandardFont(
447 const ByteString& fontName,
448 const CPDF_FontEncoding* pEncoding) {
449 ByteString mutable_name(fontName);
450 if (!CFX_FontMapper::GetStandardFontName(&mutable_name))
451 return nullptr;
452 return GetStandardFont(mutable_name, pEncoding);
453 }
454
AddFont(std::unique_ptr<CFX_Font> pFont,int charset)455 RetainPtr<CPDF_Font> CPDF_DocPageData::AddFont(std::unique_ptr<CFX_Font> pFont,
456 int charset) {
457 if (!pFont)
458 return nullptr;
459
460 const bool bCJK = FX_CharSetIsCJK(charset);
461 ByteString basefont = pFont->GetFamilyName();
462 basefont.Replace(" ", "");
463 int flags =
464 CalculateFlags(pFont->IsBold(), pFont->IsItalic(), pFont->IsFixedWidth(),
465 false, false, charset == FX_CHARSET_Symbol);
466
467 CPDF_Dictionary* pBaseDict = GetDocument()->NewIndirect<CPDF_Dictionary>();
468 pBaseDict->SetNewFor<CPDF_Name>("Type", "Font");
469 auto pEncoding = pdfium::MakeUnique<CFX_UnicodeEncoding>(pFont.get());
470 CPDF_Dictionary* pFontDict = pBaseDict;
471 if (!bCJK) {
472 auto pWidths = pdfium::MakeRetain<CPDF_Array>();
473 for (int charcode = 32; charcode < 128; charcode++) {
474 int glyph_index = pEncoding->GlyphFromCharCode(charcode);
475 int char_width = pFont->GetGlyphWidth(glyph_index);
476 pWidths->AddNew<CPDF_Number>(char_width);
477 }
478 if (charset == FX_CHARSET_ANSI || charset == FX_CHARSET_Default ||
479 charset == FX_CHARSET_Symbol) {
480 pBaseDict->SetNewFor<CPDF_Name>("Encoding", "WinAnsiEncoding");
481 for (int charcode = 128; charcode <= 255; charcode++) {
482 int glyph_index = pEncoding->GlyphFromCharCode(charcode);
483 int char_width = pFont->GetGlyphWidth(glyph_index);
484 pWidths->AddNew<CPDF_Number>(char_width);
485 }
486 } else {
487 size_t i = CalculateEncodingDict(charset, pBaseDict);
488 if (i < FX_ArraySize(g_FX_CharsetUnicodes)) {
489 const uint16_t* pUnicodes = g_FX_CharsetUnicodes[i].m_pUnicodes;
490 for (int j = 0; j < 128; j++) {
491 int glyph_index = pEncoding->GlyphFromCharCode(pUnicodes[j]);
492 int char_width = pFont->GetGlyphWidth(glyph_index);
493 pWidths->AddNew<CPDF_Number>(char_width);
494 }
495 }
496 }
497 ProcessNonbCJK(pBaseDict, pFont->IsBold(), pFont->IsItalic(), basefont,
498 std::move(pWidths));
499 } else {
500 pFontDict = ProcessbCJK(
501 pBaseDict, charset, basefont,
502 [&pFont, &pEncoding](wchar_t start, wchar_t end, CPDF_Array* widthArr) {
503 InsertWidthArray1(pFont.get(), pEncoding.get(), start, end, widthArr);
504 });
505 }
506 int italicangle = pFont->GetSubstFontItalicAngle();
507 FX_RECT bbox;
508 pFont->GetBBox(&bbox);
509 auto pBBox = pdfium::MakeRetain<CPDF_Array>();
510 pBBox->AddNew<CPDF_Number>(bbox.left);
511 pBBox->AddNew<CPDF_Number>(bbox.bottom);
512 pBBox->AddNew<CPDF_Number>(bbox.right);
513 pBBox->AddNew<CPDF_Number>(bbox.top);
514 int32_t nStemV = 0;
515 if (pFont->GetSubstFont()) {
516 nStemV = pFont->GetSubstFont()->m_Weight / 5;
517 } else {
518 static const char stem_chars[] = {'i', 'I', '!', '1'};
519 const size_t count = FX_ArraySize(stem_chars);
520 uint32_t glyph = pEncoding->GlyphFromCharCode(stem_chars[0]);
521 nStemV = pFont->GetGlyphWidth(glyph);
522 for (size_t i = 1; i < count; i++) {
523 glyph = pEncoding->GlyphFromCharCode(stem_chars[i]);
524 int width = pFont->GetGlyphWidth(glyph);
525 if (width > 0 && width < nStemV)
526 nStemV = width;
527 }
528 }
529 CPDF_Dictionary* pFontDesc =
530 ToDictionary(GetDocument()->AddIndirectObject(CalculateFontDesc(
531 GetDocument(), basefont, flags, italicangle, pFont->GetAscent(),
532 pFont->GetDescent(), std::move(pBBox), nStemV)));
533 pFontDict->SetNewFor<CPDF_Reference>("FontDescriptor", GetDocument(),
534 pFontDesc->GetObjNum());
535 return GetFont(pBaseDict);
536 }
537
538 #if defined(OS_WIN)
AddWindowsFont(LOGFONTA * pLogFont)539 RetainPtr<CPDF_Font> CPDF_DocPageData::AddWindowsFont(LOGFONTA* pLogFont) {
540 pLogFont->lfHeight = -1000;
541 pLogFont->lfWidth = 0;
542 HGDIOBJ hFont = CreateFontIndirectA(pLogFont);
543 HDC hDC = CreateCompatibleDC(nullptr);
544 hFont = SelectObject(hDC, hFont);
545 int tm_size = GetOutlineTextMetrics(hDC, 0, nullptr);
546 if (tm_size == 0) {
547 hFont = SelectObject(hDC, hFont);
548 DeleteObject(hFont);
549 DeleteDC(hDC);
550 return nullptr;
551 }
552
553 LPBYTE tm_buf = FX_Alloc(BYTE, tm_size);
554 OUTLINETEXTMETRIC* ptm = reinterpret_cast<OUTLINETEXTMETRIC*>(tm_buf);
555 GetOutlineTextMetrics(hDC, tm_size, ptm);
556 int flags = CalculateFlags(false, pLogFont->lfItalic != 0,
557 (pLogFont->lfPitchAndFamily & 3) == FIXED_PITCH,
558 (pLogFont->lfPitchAndFamily & 0xf8) == FF_ROMAN,
559 (pLogFont->lfPitchAndFamily & 0xf8) == FF_SCRIPT,
560 pLogFont->lfCharSet == FX_CHARSET_Symbol);
561
562 const bool bCJK = FX_CharSetIsCJK(pLogFont->lfCharSet);
563 ByteString basefont;
564 if (bCJK)
565 basefont = GetPSNameFromTT(hDC);
566
567 if (basefont.IsEmpty())
568 basefont = pLogFont->lfFaceName;
569
570 int italicangle = ptm->otmItalicAngle / 10;
571 int ascend = ptm->otmrcFontBox.top;
572 int descend = ptm->otmrcFontBox.bottom;
573 int capheight = ptm->otmsCapEmHeight;
574 int bbox[4] = {ptm->otmrcFontBox.left, ptm->otmrcFontBox.bottom,
575 ptm->otmrcFontBox.right, ptm->otmrcFontBox.top};
576 FX_Free(tm_buf);
577 basefont.Replace(" ", "");
578 CPDF_Dictionary* pBaseDict = GetDocument()->NewIndirect<CPDF_Dictionary>();
579 pBaseDict->SetNewFor<CPDF_Name>("Type", "Font");
580 CPDF_Dictionary* pFontDict = pBaseDict;
581 if (!bCJK) {
582 if (pLogFont->lfCharSet == FX_CHARSET_ANSI ||
583 pLogFont->lfCharSet == FX_CHARSET_Default ||
584 pLogFont->lfCharSet == FX_CHARSET_Symbol) {
585 pBaseDict->SetNewFor<CPDF_Name>("Encoding", "WinAnsiEncoding");
586 } else {
587 CalculateEncodingDict(pLogFont->lfCharSet, pBaseDict);
588 }
589 int char_widths[224];
590 GetCharWidth(hDC, 32, 255, char_widths);
591 auto pWidths = pdfium::MakeRetain<CPDF_Array>();
592 for (size_t i = 0; i < 224; i++)
593 pWidths->AddNew<CPDF_Number>(char_widths[i]);
594 ProcessNonbCJK(pBaseDict, pLogFont->lfWeight > FW_MEDIUM,
595 pLogFont->lfItalic != 0, basefont, std::move(pWidths));
596 } else {
597 pFontDict =
598 ProcessbCJK(pBaseDict, pLogFont->lfCharSet, basefont,
599 [&hDC](wchar_t start, wchar_t end, CPDF_Array* widthArr) {
600 InsertWidthArray(hDC, start, end, widthArr);
601 });
602 }
603 auto pBBox = pdfium::MakeRetain<CPDF_Array>();
604 for (int i = 0; i < 4; i++)
605 pBBox->AddNew<CPDF_Number>(bbox[i]);
606 RetainPtr<CPDF_Dictionary> pFontDesc =
607 CalculateFontDesc(GetDocument(), basefont, flags, italicangle, ascend,
608 descend, std::move(pBBox), pLogFont->lfWeight / 5);
609 pFontDesc->SetNewFor<CPDF_Number>("CapHeight", capheight);
610 pFontDict->SetFor("FontDescriptor",
611 GetDocument()
612 ->AddIndirectObject(std::move(pFontDesc))
613 ->MakeReference(GetDocument()));
614 hFont = SelectObject(hDC, hFont);
615 DeleteObject(hFont);
616 DeleteDC(hDC);
617 return GetFont(pBaseDict);
618 }
619 #endif // defined(OS_WIN)
620
CalculateEncodingDict(int charset,CPDF_Dictionary * pBaseDict)621 size_t CPDF_DocPageData::CalculateEncodingDict(int charset,
622 CPDF_Dictionary* pBaseDict) {
623 size_t i;
624 for (i = 0; i < FX_ArraySize(g_FX_CharsetUnicodes); ++i) {
625 if (g_FX_CharsetUnicodes[i].m_Charset == charset)
626 break;
627 }
628 if (i == FX_ArraySize(g_FX_CharsetUnicodes))
629 return i;
630
631 CPDF_Dictionary* pEncodingDict =
632 GetDocument()->NewIndirect<CPDF_Dictionary>();
633 pEncodingDict->SetNewFor<CPDF_Name>("BaseEncoding", "WinAnsiEncoding");
634
635 CPDF_Array* pArray = pEncodingDict->SetNewFor<CPDF_Array>("Differences");
636 pArray->AddNew<CPDF_Number>(128);
637
638 const uint16_t* pUnicodes = g_FX_CharsetUnicodes[i].m_pUnicodes;
639 for (int j = 0; j < 128; j++) {
640 ByteString name = PDF_AdobeNameFromUnicode(pUnicodes[j]);
641 pArray->AddNew<CPDF_Name>(name.IsEmpty() ? ".notdef" : name);
642 }
643 pBaseDict->SetNewFor<CPDF_Reference>("Encoding", GetDocument(),
644 pEncodingDict->GetObjNum());
645 return i;
646 }
647
ProcessbCJK(CPDF_Dictionary * pBaseDict,int charset,ByteString basefont,std::function<void (wchar_t,wchar_t,CPDF_Array *)> Insert)648 CPDF_Dictionary* CPDF_DocPageData::ProcessbCJK(
649 CPDF_Dictionary* pBaseDict,
650 int charset,
651 ByteString basefont,
652 std::function<void(wchar_t, wchar_t, CPDF_Array*)> Insert) {
653 CPDF_Dictionary* pFontDict = GetDocument()->NewIndirect<CPDF_Dictionary>();
654 ByteString cmap;
655 ByteString ordering;
656 int supplement = 0;
657 CPDF_Array* pWidthArray = pFontDict->SetNewFor<CPDF_Array>("W");
658 switch (charset) {
659 case FX_CHARSET_ChineseTraditional:
660 cmap = "ETenms-B5-H";
661 ordering = "CNS1";
662 supplement = 4;
663 pWidthArray->AddNew<CPDF_Number>(1);
664 Insert(0x20, 0x7e, pWidthArray);
665 break;
666 case FX_CHARSET_ChineseSimplified:
667 cmap = "GBK-EUC-H";
668 ordering = "GB1";
669 supplement = 2;
670 pWidthArray->AddNew<CPDF_Number>(7716);
671 Insert(0x20, 0x20, pWidthArray);
672 pWidthArray->AddNew<CPDF_Number>(814);
673 Insert(0x21, 0x7e, pWidthArray);
674 break;
675 case FX_CHARSET_Hangul:
676 cmap = "KSCms-UHC-H";
677 ordering = "Korea1";
678 supplement = 2;
679 pWidthArray->AddNew<CPDF_Number>(1);
680 Insert(0x20, 0x7e, pWidthArray);
681 break;
682 case FX_CHARSET_ShiftJIS:
683 cmap = "90ms-RKSJ-H";
684 ordering = "Japan1";
685 supplement = 5;
686 pWidthArray->AddNew<CPDF_Number>(231);
687 Insert(0x20, 0x7d, pWidthArray);
688 pWidthArray->AddNew<CPDF_Number>(326);
689 Insert(0xa0, 0xa0, pWidthArray);
690 pWidthArray->AddNew<CPDF_Number>(327);
691 Insert(0xa1, 0xdf, pWidthArray);
692 pWidthArray->AddNew<CPDF_Number>(631);
693 Insert(0x7e, 0x7e, pWidthArray);
694 break;
695 }
696 pBaseDict->SetNewFor<CPDF_Name>("Subtype", "Type0");
697 pBaseDict->SetNewFor<CPDF_Name>("BaseFont", basefont);
698 pBaseDict->SetNewFor<CPDF_Name>("Encoding", cmap);
699 pFontDict->SetNewFor<CPDF_Name>("Type", "Font");
700 pFontDict->SetNewFor<CPDF_Name>("Subtype", "CIDFontType2");
701 pFontDict->SetNewFor<CPDF_Name>("BaseFont", basefont);
702
703 CPDF_Dictionary* pCIDSysInfo =
704 pFontDict->SetNewFor<CPDF_Dictionary>("CIDSystemInfo");
705 pCIDSysInfo->SetNewFor<CPDF_String>("Registry", "Adobe", false);
706 pCIDSysInfo->SetNewFor<CPDF_String>("Ordering", ordering, false);
707 pCIDSysInfo->SetNewFor<CPDF_Number>("Supplement", supplement);
708
709 CPDF_Array* pArray = pBaseDict->SetNewFor<CPDF_Array>("DescendantFonts");
710 pArray->AddNew<CPDF_Reference>(GetDocument(), pFontDict->GetObjNum());
711 return pFontDict;
712 }
713