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