xref: /aosp_15_r20/external/pdfium/core/fpdfapi/page/cpdf_docpagedata.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
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()) {
402     return it->second;
403   }
404 
405   auto pAccessor = pdfium::MakeRetain<CPDF_StreamAcc>(pProfileStream);
406   pAccessor->LoadAllDataFiltered();
407 
408   ByteString bsDigest = pAccessor->ComputeDigest();
409   auto hash_it = m_HashProfileMap.find(bsDigest);
410   if (hash_it != m_HashProfileMap.end()) {
411     auto it_copied_stream = m_IccProfileMap.find(hash_it->second);
412     if (it_copied_stream != m_IccProfileMap.end()) {
413       return it_copied_stream->second;
414     }
415   }
416   auto pProfile =
417       pdfium::MakeRetain<CPDF_IccProfile>(pProfileStream, pAccessor->GetSpan());
418   m_IccProfileMap[pProfileStream] = pProfile;
419   m_HashProfileMap[bsDigest] = std::move(pProfileStream);
420   return pProfile;
421 }
422 
GetFontFileStreamAcc(RetainPtr<const CPDF_Stream> pFontStream)423 RetainPtr<CPDF_StreamAcc> CPDF_DocPageData::GetFontFileStreamAcc(
424     RetainPtr<const CPDF_Stream> pFontStream) {
425   DCHECK(pFontStream);
426   auto it = m_FontFileMap.find(pFontStream);
427   if (it != m_FontFileMap.end())
428     return it->second;
429 
430   RetainPtr<const CPDF_Dictionary> pFontDict = pFontStream->GetDict();
431   int32_t len1 = pFontDict->GetIntegerFor("Length1");
432   int32_t len2 = pFontDict->GetIntegerFor("Length2");
433   int32_t len3 = pFontDict->GetIntegerFor("Length3");
434   uint32_t org_size = 0;
435   if (len1 >= 0 && len2 >= 0 && len3 >= 0) {
436     FX_SAFE_UINT32 safe_org_size = len1;
437     safe_org_size += len2;
438     safe_org_size += len3;
439     org_size = safe_org_size.ValueOrDefault(0);
440   }
441 
442   auto pFontAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pFontStream);
443   pFontAcc->LoadAllDataFilteredWithEstimatedSize(org_size);
444   m_FontFileMap[std::move(pFontStream)] = pFontAcc;
445   return pFontAcc;
446 }
447 
MaybePurgeFontFileStreamAcc(RetainPtr<CPDF_StreamAcc> && pStreamAcc)448 void CPDF_DocPageData::MaybePurgeFontFileStreamAcc(
449     RetainPtr<CPDF_StreamAcc>&& pStreamAcc) {
450   if (!pStreamAcc)
451     return;
452 
453   RetainPtr<const CPDF_Stream> pFontStream = pStreamAcc->GetStream();
454   if (!pFontStream)
455     return;
456 
457   pStreamAcc.Reset();  // Drop moved caller's reference.
458   auto it = m_FontFileMap.find(std::move(pFontStream));
459   if (it != m_FontFileMap.end() && it->second->HasOneRef())
460     m_FontFileMap.erase(it);
461 }
462 
CreateForm(CPDF_Document * pDocument,RetainPtr<CPDF_Dictionary> pPageResources,RetainPtr<CPDF_Stream> pFormStream)463 std::unique_ptr<CPDF_Font::FormIface> CPDF_DocPageData::CreateForm(
464     CPDF_Document* pDocument,
465     RetainPtr<CPDF_Dictionary> pPageResources,
466     RetainPtr<CPDF_Stream> pFormStream) {
467   return std::make_unique<CPDF_Form>(pDocument, std::move(pPageResources),
468                                      std::move(pFormStream));
469 }
470 
AddStandardFont(const ByteString & fontName,const CPDF_FontEncoding * pEncoding)471 RetainPtr<CPDF_Font> CPDF_DocPageData::AddStandardFont(
472     const ByteString& fontName,
473     const CPDF_FontEncoding* pEncoding) {
474   ByteString mutable_name(fontName);
475   absl::optional<CFX_FontMapper::StandardFont> font_id =
476       CFX_FontMapper::GetStandardFontName(&mutable_name);
477   if (!font_id.has_value())
478     return nullptr;
479   return GetStandardFont(mutable_name, pEncoding);
480 }
481 
AddFont(std::unique_ptr<CFX_Font> pFont,FX_Charset charset)482 RetainPtr<CPDF_Font> CPDF_DocPageData::AddFont(std::unique_ptr<CFX_Font> pFont,
483                                                FX_Charset charset) {
484   if (!pFont)
485     return nullptr;
486 
487   const bool bCJK = FX_CharSetIsCJK(charset);
488   ByteString basefont = pFont->GetFamilyName();
489   basefont.Replace(" ", "");
490   int flags =
491       CalculateFlags(pFont->IsBold(), pFont->IsItalic(), pFont->IsFixedWidth(),
492                      false, false, charset == FX_Charset::kSymbol);
493 
494   auto pBaseDict = GetDocument()->NewIndirect<CPDF_Dictionary>();
495   pBaseDict->SetNewFor<CPDF_Name>("Type", "Font");
496 
497   auto pEncoding = std::make_unique<CFX_UnicodeEncoding>(pFont.get());
498   RetainPtr<CPDF_Dictionary> pFontDict = pBaseDict;
499   if (!bCJK) {
500     auto pWidths = pdfium::MakeRetain<CPDF_Array>();
501     for (int charcode = 32; charcode < 128; charcode++) {
502       int glyph_index = pEncoding->GlyphFromCharCode(charcode);
503       int char_width = pFont->GetGlyphWidth(glyph_index);
504       pWidths->AppendNew<CPDF_Number>(char_width);
505     }
506     if (charset == FX_Charset::kANSI || charset == FX_Charset::kDefault ||
507         charset == FX_Charset::kSymbol) {
508       pBaseDict->SetNewFor<CPDF_Name>("Encoding",
509                                       pdfium::font_encodings::kWinAnsiEncoding);
510       for (int charcode = 128; charcode <= 255; charcode++) {
511         int glyph_index = pEncoding->GlyphFromCharCode(charcode);
512         int char_width = pFont->GetGlyphWidth(glyph_index);
513         pWidths->AppendNew<CPDF_Number>(char_width);
514       }
515     } else {
516       size_t i = CalculateEncodingDict(charset, pBaseDict.Get());
517       if (i < std::size(kFX_CharsetUnicodes)) {
518         const uint16_t* pUnicodes = kFX_CharsetUnicodes[i].m_pUnicodes;
519         for (int j = 0; j < 128; j++) {
520           int glyph_index = pEncoding->GlyphFromCharCode(pUnicodes[j]);
521           int char_width = pFont->GetGlyphWidth(glyph_index);
522           pWidths->AppendNew<CPDF_Number>(char_width);
523         }
524       }
525     }
526     ProcessNonbCJK(pBaseDict, pFont->IsBold(), pFont->IsItalic(), basefont,
527                    std::move(pWidths));
528   } else {
529     pFontDict = ProcessbCJK(
530         pBaseDict, charset, basefont,
531         [&pFont, &pEncoding](wchar_t start, wchar_t end, CPDF_Array* widthArr) {
532           InsertWidthArray1(pFont.get(), pEncoding.get(), start, end, widthArr);
533         });
534   }
535   int italicangle = pFont->GetSubstFontItalicAngle();
536   FX_RECT bbox = pFont->GetBBox().value_or(FX_RECT());
537   auto pBBox = pdfium::MakeRetain<CPDF_Array>();
538   pBBox->AppendNew<CPDF_Number>(bbox.left);
539   pBBox->AppendNew<CPDF_Number>(bbox.bottom);
540   pBBox->AppendNew<CPDF_Number>(bbox.right);
541   pBBox->AppendNew<CPDF_Number>(bbox.top);
542   int32_t nStemV = 0;
543   if (pFont->GetSubstFont()) {
544     nStemV = pFont->GetSubstFont()->m_Weight / 5;
545   } else {
546     static const char stem_chars[] = {'i', 'I', '!', '1'};
547     const size_t count = std::size(stem_chars);
548     uint32_t glyph = pEncoding->GlyphFromCharCode(stem_chars[0]);
549     nStemV = pFont->GetGlyphWidth(glyph);
550     for (size_t i = 1; i < count; i++) {
551       glyph = pEncoding->GlyphFromCharCode(stem_chars[i]);
552       int width = pFont->GetGlyphWidth(glyph);
553       if (width > 0 && width < nStemV)
554         nStemV = width;
555     }
556   }
557   RetainPtr<CPDF_Dictionary> pFontDesc = CalculateFontDesc(
558       GetDocument(), basefont, flags, italicangle, pFont->GetAscent(),
559       pFont->GetDescent(), std::move(pBBox), nStemV);
560   uint32_t new_objnum = GetDocument()->AddIndirectObject(std::move(pFontDesc));
561   pFontDict->SetNewFor<CPDF_Reference>("FontDescriptor", GetDocument(),
562                                        new_objnum);
563   return GetFont(pBaseDict);
564 }
565 
566 #if BUILDFLAG(IS_WIN)
AddWindowsFont(LOGFONTA * pLogFont)567 RetainPtr<CPDF_Font> CPDF_DocPageData::AddWindowsFont(LOGFONTA* pLogFont) {
568   pLogFont->lfHeight = -1000;
569   pLogFont->lfWidth = 0;
570   HGDIOBJ hFont = CreateFontIndirectA(pLogFont);
571   HDC hDC = CreateCompatibleDC(nullptr);
572   hFont = SelectObject(hDC, hFont);
573   int tm_size = GetOutlineTextMetrics(hDC, 0, nullptr);
574   if (tm_size == 0) {
575     hFont = SelectObject(hDC, hFont);
576     DeleteObject(hFont);
577     DeleteDC(hDC);
578     return nullptr;
579   }
580 
581   LPBYTE tm_buf = FX_Alloc(BYTE, tm_size);
582   OUTLINETEXTMETRIC* ptm = reinterpret_cast<OUTLINETEXTMETRIC*>(tm_buf);
583   GetOutlineTextMetrics(hDC, tm_size, ptm);
584   int flags = CalculateFlags(
585       false, pLogFont->lfItalic != 0,
586       (pLogFont->lfPitchAndFamily & 3) == FIXED_PITCH,
587       (pLogFont->lfPitchAndFamily & 0xf8) == FF_ROMAN,
588       (pLogFont->lfPitchAndFamily & 0xf8) == FF_SCRIPT,
589       pLogFont->lfCharSet == static_cast<int>(FX_Charset::kSymbol));
590 
591   const FX_Charset eCharset = FX_GetCharsetFromInt(pLogFont->lfCharSet);
592   const bool bCJK = FX_CharSetIsCJK(eCharset);
593   ByteString basefont;
594   if (bCJK)
595     basefont = GetPSNameFromTT(hDC);
596 
597   if (basefont.IsEmpty())
598     basefont = pLogFont->lfFaceName;
599 
600   int italicangle = ptm->otmItalicAngle / 10;
601   int ascend = ptm->otmrcFontBox.top;
602   int descend = ptm->otmrcFontBox.bottom;
603   int capheight = ptm->otmsCapEmHeight;
604   int bbox[4] = {ptm->otmrcFontBox.left, ptm->otmrcFontBox.bottom,
605                  ptm->otmrcFontBox.right, ptm->otmrcFontBox.top};
606   FX_Free(tm_buf);
607   basefont.Replace(" ", "");
608   auto pBaseDict = GetDocument()->NewIndirect<CPDF_Dictionary>();
609   pBaseDict->SetNewFor<CPDF_Name>("Type", "Font");
610   RetainPtr<CPDF_Dictionary> pFontDict = pBaseDict;
611   if (!bCJK) {
612     if (eCharset == FX_Charset::kANSI || eCharset == FX_Charset::kDefault ||
613         eCharset == FX_Charset::kSymbol) {
614       pBaseDict->SetNewFor<CPDF_Name>("Encoding",
615                                       pdfium::font_encodings::kWinAnsiEncoding);
616     } else {
617       CalculateEncodingDict(eCharset, pBaseDict.Get());
618     }
619     int char_widths[224];
620     GetCharWidth(hDC, 32, 255, char_widths);
621     auto pWidths = pdfium::MakeRetain<CPDF_Array>();
622     for (size_t i = 0; i < 224; i++)
623       pWidths->AppendNew<CPDF_Number>(char_widths[i]);
624     ProcessNonbCJK(pBaseDict, pLogFont->lfWeight > FW_MEDIUM,
625                    pLogFont->lfItalic != 0, basefont, std::move(pWidths));
626   } else {
627     pFontDict =
628         ProcessbCJK(pBaseDict, eCharset, basefont,
629                     [&hDC](wchar_t start, wchar_t end, CPDF_Array* widthArr) {
630                       InsertWidthArray(hDC, start, end, widthArr);
631                     });
632   }
633   auto pBBox = pdfium::MakeRetain<CPDF_Array>();
634   for (int i = 0; i < 4; i++)
635     pBBox->AppendNew<CPDF_Number>(bbox[i]);
636   RetainPtr<CPDF_Dictionary> pFontDesc =
637       CalculateFontDesc(GetDocument(), basefont, flags, italicangle, ascend,
638                         descend, std::move(pBBox), pLogFont->lfWeight / 5);
639   pFontDesc->SetNewFor<CPDF_Number>("CapHeight", capheight);
640   GetDocument()->AddIndirectObject(pFontDesc);
641   pFontDict->SetFor("FontDescriptor", pFontDesc->MakeReference(GetDocument()));
642   hFont = SelectObject(hDC, hFont);
643   DeleteObject(hFont);
644   DeleteDC(hDC);
645   return GetFont(std::move(pBaseDict));
646 }
647 #endif  //  BUILDFLAG(IS_WIN)
648 
CalculateEncodingDict(FX_Charset charset,CPDF_Dictionary * pBaseDict)649 size_t CPDF_DocPageData::CalculateEncodingDict(FX_Charset charset,
650                                                CPDF_Dictionary* pBaseDict) {
651   size_t i;
652   for (i = 0; i < std::size(kFX_CharsetUnicodes); ++i) {
653     if (kFX_CharsetUnicodes[i].m_Charset == charset)
654       break;
655   }
656   if (i == std::size(kFX_CharsetUnicodes))
657     return i;
658 
659   auto pEncodingDict = GetDocument()->NewIndirect<CPDF_Dictionary>();
660   pEncodingDict->SetNewFor<CPDF_Name>("BaseEncoding",
661                                       pdfium::font_encodings::kWinAnsiEncoding);
662 
663   auto pArray = pEncodingDict->SetNewFor<CPDF_Array>("Differences");
664   pArray->AppendNew<CPDF_Number>(128);
665 
666   const uint16_t* pUnicodes = kFX_CharsetUnicodes[i].m_pUnicodes;
667   for (int j = 0; j < 128; j++) {
668     ByteString name = AdobeNameFromUnicode(pUnicodes[j]);
669     pArray->AppendNew<CPDF_Name>(name.IsEmpty() ? ".notdef" : name);
670   }
671   pBaseDict->SetNewFor<CPDF_Reference>("Encoding", GetDocument(),
672                                        pEncodingDict->GetObjNum());
673   return i;
674 }
675 
ProcessbCJK(RetainPtr<CPDF_Dictionary> pBaseDict,FX_Charset charset,ByteString basefont,std::function<void (wchar_t,wchar_t,CPDF_Array *)> Insert)676 RetainPtr<CPDF_Dictionary> CPDF_DocPageData::ProcessbCJK(
677     RetainPtr<CPDF_Dictionary> pBaseDict,
678     FX_Charset charset,
679     ByteString basefont,
680     std::function<void(wchar_t, wchar_t, CPDF_Array*)> Insert) {
681   auto pFontDict = GetDocument()->NewIndirect<CPDF_Dictionary>();
682   ByteString cmap;
683   ByteString ordering;
684   int supplement = 0;
685   auto pWidthArray = pFontDict->SetNewFor<CPDF_Array>("W");
686   switch (charset) {
687     case FX_Charset::kChineseTraditional:
688       cmap = "ETenms-B5-H";
689       ordering = "CNS1";
690       supplement = 4;
691       pWidthArray->AppendNew<CPDF_Number>(1);
692       Insert(0x20, 0x7e, pWidthArray.Get());
693       break;
694     case FX_Charset::kChineseSimplified:
695       cmap = "GBK-EUC-H";
696       ordering = "GB1";
697       supplement = 2;
698       pWidthArray->AppendNew<CPDF_Number>(7716);
699       Insert(0x20, 0x20, pWidthArray.Get());
700       pWidthArray->AppendNew<CPDF_Number>(814);
701       Insert(0x21, 0x7e, pWidthArray.Get());
702       break;
703     case FX_Charset::kHangul:
704       cmap = "KSCms-UHC-H";
705       ordering = "Korea1";
706       supplement = 2;
707       pWidthArray->AppendNew<CPDF_Number>(1);
708       Insert(0x20, 0x7e, pWidthArray.Get());
709       break;
710     case FX_Charset::kShiftJIS:
711       cmap = "90ms-RKSJ-H";
712       ordering = "Japan1";
713       supplement = 5;
714       pWidthArray->AppendNew<CPDF_Number>(231);
715       Insert(0x20, 0x7d, pWidthArray.Get());
716       pWidthArray->AppendNew<CPDF_Number>(326);
717       Insert(0xa0, 0xa0, pWidthArray.Get());
718       pWidthArray->AppendNew<CPDF_Number>(327);
719       Insert(0xa1, 0xdf, pWidthArray.Get());
720       pWidthArray->AppendNew<CPDF_Number>(631);
721       Insert(0x7e, 0x7e, pWidthArray.Get());
722       break;
723     default:
724       break;
725   }
726   pBaseDict->SetNewFor<CPDF_Name>("Subtype", "Type0");
727   pBaseDict->SetNewFor<CPDF_Name>("BaseFont", basefont);
728   pBaseDict->SetNewFor<CPDF_Name>("Encoding", cmap);
729   pFontDict->SetNewFor<CPDF_Name>("Type", "Font");
730   pFontDict->SetNewFor<CPDF_Name>("Subtype", "CIDFontType2");
731   pFontDict->SetNewFor<CPDF_Name>("BaseFont", basefont);
732 
733   auto pCIDSysInfo = pFontDict->SetNewFor<CPDF_Dictionary>("CIDSystemInfo");
734   pCIDSysInfo->SetNewFor<CPDF_String>("Registry", "Adobe", false);
735   pCIDSysInfo->SetNewFor<CPDF_String>("Ordering", ordering, false);
736   pCIDSysInfo->SetNewFor<CPDF_Number>("Supplement", supplement);
737 
738   auto pArray = pBaseDict->SetNewFor<CPDF_Array>("DescendantFonts");
739   pArray->AppendNew<CPDF_Reference>(GetDocument(), pFontDict->GetObjNum());
740   return pFontDict;
741 }
742