1 // Copyright 2016 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/font/cpdf_type3font.h"
8 
9 #include <algorithm>
10 #include <type_traits>
11 #include <utility>
12 
13 #include "core/fpdfapi/font/cpdf_type3char.h"
14 #include "core/fpdfapi/parser/cpdf_array.h"
15 #include "core/fpdfapi/parser/cpdf_dictionary.h"
16 #include "core/fpdfapi/parser/cpdf_stream.h"
17 #include "core/fxcrt/autorestorer.h"
18 #include "core/fxcrt/fx_system.h"
19 #include "third_party/base/stl_util.h"
20 
21 namespace {
22 
23 constexpr int kMaxType3FormLevel = 4;
24 
25 }  // namespace
26 
CPDF_Type3Font(CPDF_Document * pDocument,CPDF_Dictionary * pFontDict,FormFactoryIface * pFormFactory)27 CPDF_Type3Font::CPDF_Type3Font(CPDF_Document* pDocument,
28                                CPDF_Dictionary* pFontDict,
29                                FormFactoryIface* pFormFactory)
30     : CPDF_SimpleFont(pDocument, pFontDict), m_pFormFactory(pFormFactory) {
31   ASSERT(GetDocument());
32 }
33 
34 CPDF_Type3Font::~CPDF_Type3Font() = default;
35 
IsType3Font() const36 bool CPDF_Type3Font::IsType3Font() const {
37   return true;
38 }
39 
AsType3Font() const40 const CPDF_Type3Font* CPDF_Type3Font::AsType3Font() const {
41   return this;
42 }
43 
AsType3Font()44 CPDF_Type3Font* CPDF_Type3Font::AsType3Font() {
45   return this;
46 }
47 
WillBeDestroyed()48 void CPDF_Type3Font::WillBeDestroyed() {
49   // Last reference to |this| may be through one of its CPDF_Type3Chars.
50   RetainPtr<CPDF_Font> protector(this);
51   for (const auto& item : m_CacheMap) {
52     if (item.second)
53       item.second->WillBeDestroyed();
54   }
55 }
56 
Load()57 bool CPDF_Type3Font::Load() {
58   m_pFontResources.Reset(m_pFontDict->GetDictFor("Resources"));
59   const CPDF_Array* pMatrix = m_pFontDict->GetArrayFor("FontMatrix");
60   float xscale = 1.0f;
61   float yscale = 1.0f;
62   if (pMatrix) {
63     m_FontMatrix = pMatrix->GetMatrix();
64     xscale = m_FontMatrix.a;
65     yscale = m_FontMatrix.d;
66   }
67 
68   const CPDF_Array* pBBox = m_pFontDict->GetArrayFor("FontBBox");
69   if (pBBox) {
70     CFX_FloatRect box(
71         pBBox->GetNumberAt(0) * xscale, pBBox->GetNumberAt(1) * yscale,
72         pBBox->GetNumberAt(2) * xscale, pBBox->GetNumberAt(3) * yscale);
73     CPDF_Type3Char::TextUnitRectToGlyphUnitRect(&box);
74     m_FontBBox = box.ToFxRect();
75   }
76 
77   static constexpr size_t kCharLimit = std::extent<decltype(m_CharWidthL)>();
78   int StartChar = m_pFontDict->GetIntegerFor("FirstChar");
79   if (StartChar >= 0 && static_cast<size_t>(StartChar) < kCharLimit) {
80     const CPDF_Array* pWidthArray = m_pFontDict->GetArrayFor("Widths");
81     if (pWidthArray) {
82       size_t count = std::min(pWidthArray->size(), kCharLimit);
83       count = std::min(count, kCharLimit - StartChar);
84       for (size_t i = 0; i < count; i++) {
85         m_CharWidthL[StartChar + i] =
86             FXSYS_roundf(CPDF_Type3Char::TextUnitToGlyphUnit(
87                 pWidthArray->GetNumberAt(i) * xscale));
88       }
89     }
90   }
91   m_pCharProcs.Reset(m_pFontDict->GetDictFor("CharProcs"));
92   if (m_pFontDict->GetDirectObjectFor("Encoding"))
93     LoadPDFEncoding(false, false);
94   return true;
95 }
96 
LoadGlyphMap()97 void CPDF_Type3Font::LoadGlyphMap() {}
98 
CheckType3FontMetrics()99 void CPDF_Type3Font::CheckType3FontMetrics() {
100   CheckFontMetrics();
101 }
102 
LoadChar(uint32_t charcode)103 CPDF_Type3Char* CPDF_Type3Font::LoadChar(uint32_t charcode) {
104   if (m_CharLoadingDepth >= kMaxType3FormLevel)
105     return nullptr;
106 
107   auto it = m_CacheMap.find(charcode);
108   if (it != m_CacheMap.end())
109     return it->second.get();
110 
111   const char* name = GetAdobeCharName(m_BaseEncoding, m_CharNames, charcode);
112   if (!name)
113     return nullptr;
114 
115   if (!m_pCharProcs)
116     return nullptr;
117 
118   CPDF_Stream* pStream = ToStream(m_pCharProcs->GetDirectObjectFor(name));
119   if (!pStream)
120     return nullptr;
121 
122   std::unique_ptr<CPDF_Font::FormIface> pForm = m_pFormFactory->CreateForm(
123       m_pDocument.Get(),
124       m_pFontResources ? m_pFontResources.Get() : m_pPageResources.Get(),
125       pStream);
126 
127   auto pNewChar = std::make_unique<CPDF_Type3Char>();
128 
129   // This can trigger recursion into this method. The content of |m_CacheMap|
130   // can change as a result. Thus after it returns, check the cache again for
131   // a cache hit.
132   {
133     AutoRestorer<int> restorer(&m_CharLoadingDepth);
134     m_CharLoadingDepth++;
135     pForm->ParseContentForType3Char(pNewChar.get());
136   }
137   it = m_CacheMap.find(charcode);
138   if (it != m_CacheMap.end())
139     return it->second.get();
140 
141   pNewChar->Transform(pForm.get(), m_FontMatrix);
142   if (pForm->HasPageObjects())
143     pNewChar->SetForm(std::move(pForm));
144 
145   CPDF_Type3Char* pCachedChar = pNewChar.get();
146   m_CacheMap[charcode] = std::move(pNewChar);
147   return pCachedChar;
148 }
149 
GetCharWidthF(uint32_t charcode)150 int CPDF_Type3Font::GetCharWidthF(uint32_t charcode) {
151   if (charcode >= pdfium::size(m_CharWidthL))
152     charcode = 0;
153 
154   if (m_CharWidthL[charcode])
155     return m_CharWidthL[charcode];
156 
157   const CPDF_Type3Char* pChar = LoadChar(charcode);
158   return pChar ? pChar->width() : 0;
159 }
160 
GetCharBBox(uint32_t charcode)161 FX_RECT CPDF_Type3Font::GetCharBBox(uint32_t charcode) {
162   FX_RECT ret;
163   const CPDF_Type3Char* pChar = LoadChar(charcode);
164   if (pChar)
165     ret = pChar->bbox();
166   return ret;
167 }
168