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