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