• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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