• 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 <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 
49 namespace {
50 
InsertWidthArrayImpl(std::vector<int> widths,CPDF_Array * pWidthArray)51 void 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)
InsertWidthArray(HDC hDC,int start,int end,CPDF_Array * pWidthArray)70 void 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 
GetPSNameFromTT(HDC hDC)76 ByteString 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 
InsertWidthArray1(CFX_Font * pFont,CFX_UnicodeEncoding * pEncoding,wchar_t start,wchar_t end,CPDF_Array * pWidthArray)88 void 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 
CalculateFlags(bool bold,bool italic,bool fixedPitch,bool serif,bool script,bool symbolic)101 int 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 
ProcessNonbCJK(RetainPtr<CPDF_Dictionary> pBaseDict,bool bold,bool italic,ByteString basefont,RetainPtr<CPDF_Array> pWidths)125 void 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 
CalculateFontDesc(CPDF_Document * pDoc,ByteString basefont,int flags,int italicangle,int ascend,int descend,RetainPtr<CPDF_Array> bbox,int32_t stemV)143 RetainPtr<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
FromDocument(const CPDF_Document * pDoc)166 CPDF_DocPageData* CPDF_DocPageData::FromDocument(const CPDF_Document* pDoc) {
167   return static_cast<CPDF_DocPageData*>(pDoc->GetPageData());
168 }
169 
170 CPDF_DocPageData::CPDF_DocPageData() = default;
171 
~CPDF_DocPageData()172 CPDF_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 
HashIccProfileKey(DataVector<uint8_t> digest,uint32_t components)181 CPDF_DocPageData::HashIccProfileKey::HashIccProfileKey(
182     DataVector<uint8_t> digest,
183     uint32_t components)
184     : digest(std::move(digest)), components(components) {}
185 
186 CPDF_DocPageData::HashIccProfileKey::HashIccProfileKey(
187     const HashIccProfileKey& that) = default;
188 
189 CPDF_DocPageData::HashIccProfileKey::~HashIccProfileKey() = default;
190 
operator <(const HashIccProfileKey & other) const191 bool 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 
ClearStockFont()199 void CPDF_DocPageData::ClearStockFont() {
200   CPDF_FontGlobals::GetInstance()->Clear(GetDocument());
201 }
202 
GetFont(RetainPtr<CPDF_Dictionary> pFontDict)203 RetainPtr<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 
GetStandardFont(const ByteString & fontName,const CPDF_FontEncoding * pEncoding)221 RetainPtr<CPDF_Font> CPDF_DocPageData::GetStandardFont(
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 
GetColorSpace(const CPDF_Object * pCSObj,const CPDF_Dictionary * pResources)265 RetainPtr<CPDF_ColorSpace> CPDF_DocPageData::GetColorSpace(
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 
GetColorSpaceGuarded(const CPDF_Object * pCSObj,const CPDF_Dictionary * pResources,std::set<const CPDF_Object * > * pVisited)272 RetainPtr<CPDF_ColorSpace> CPDF_DocPageData::GetColorSpaceGuarded(
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 
GetColorSpaceInternal(const CPDF_Object * pCSObj,const CPDF_Dictionary * pResources,std::set<const CPDF_Object * > * pVisited,std::set<const CPDF_Object * > * pVisitedInternal)280 RetainPtr<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()) {
314       case CPDF_ColorSpace::Family::kDeviceRGB:
315         pDefaultCS = pColorSpaces->GetDirectObjectFor("DefaultRGB");
316         break;
317       case CPDF_ColorSpace::Family::kDeviceGray:
318         pDefaultCS = pColorSpaces->GetDirectObjectFor("DefaultGray");
319         break;
320       case CPDF_ColorSpace::Family::kDeviceCMYK:
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 
346   RetainPtr<CPDF_ColorSpace> pCS =
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 
GetPattern(RetainPtr<CPDF_Object> pPatternObj,const CFX_Matrix & matrix)355 RetainPtr<CPDF_Pattern> CPDF_DocPageData::GetPattern(
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")) {
366     case CPDF_Pattern::kTiling:
367       pattern = pdfium::MakeRetain<CPDF_TilingPattern>(GetDocument(),
368                                                        pPatternObj, matrix);
369       break;
370     case CPDF_Pattern::kShading:
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 
GetShading(RetainPtr<CPDF_Object> pPatternObj,const CFX_Matrix & matrix)381 RetainPtr<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 
GetImage(uint32_t dwStreamObjNum)396 RetainPtr<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 
MaybePurgeImage(uint32_t dwStreamObjNum)407 void 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 
GetIccProfile(RetainPtr<const CPDF_Stream> pProfileStream)414 RetainPtr<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");
428   CHECK(fxcodec::IccTransform::IsValidIccComponents(expected_components));
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 
GetFontFileStreamAcc(RetainPtr<const CPDF_Stream> pFontStream)449 RetainPtr<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 
MaybePurgeFontFileStreamAcc(RetainPtr<CPDF_StreamAcc> && pStreamAcc)474 void 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 
CreateForm(CPDF_Document * pDocument,RetainPtr<CPDF_Dictionary> pPageResources,RetainPtr<CPDF_Stream> pFormStream)489 std::unique_ptr<CPDF_Font::FormIface> CPDF_DocPageData::CreateForm(
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 
AddStandardFont(const ByteString & fontName,const CPDF_FontEncoding * pEncoding)497 RetainPtr<CPDF_Font> CPDF_DocPageData::AddStandardFont(
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 
AddFont(std::unique_ptr<CFX_Font> pFont,FX_Charset charset)508 RetainPtr<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",
535                                       pdfium::font_encodings::kWinAnsiEncoding);
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)
AddWindowsFont(LOGFONTA * pLogFont)595 RetainPtr<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 
CalculateEncodingDict(FX_Charset charset,CPDF_Dictionary * pBaseDict)679 size_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",
691                                       pdfium::font_encodings::kWinAnsiEncoding);
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 
ProcessbCJK(RetainPtr<CPDF_Dictionary> pBaseDict,FX_Charset charset,ByteString basefont,std::function<void (wchar_t,wchar_t,CPDF_Array *)> Insert)706 RetainPtr<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) {
717     case FX_Charset::kChineseTraditional:
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;
724     case FX_Charset::kChineseSimplified:
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;
733     case FX_Charset::kHangul:
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;
740     case FX_Charset::kShiftJIS:
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 }
772