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