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 <utility>
11
12 #include "core/fpdfapi/font/cpdf_type3char.h"
13 #include "core/fpdfapi/page/cpdf_form.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/fx_system.h"
18 #include "third_party/base/stl_util.h"
19
20 namespace {
21
22 constexpr int kMaxType3FormLevel = 4;
23
24 } // namespace
25
CPDF_Type3Font()26 CPDF_Type3Font::CPDF_Type3Font() {
27 memset(m_CharWidthL, 0, sizeof(m_CharWidthL));
28 }
29
~CPDF_Type3Font()30 CPDF_Type3Font::~CPDF_Type3Font() {}
31
IsType3Font() const32 bool CPDF_Type3Font::IsType3Font() const {
33 return true;
34 }
35
AsType3Font() const36 const CPDF_Type3Font* CPDF_Type3Font::AsType3Font() const {
37 return this;
38 }
39
AsType3Font()40 CPDF_Type3Font* CPDF_Type3Font::AsType3Font() {
41 return this;
42 }
43
Load()44 bool CPDF_Type3Font::Load() {
45 m_pFontResources = m_pFontDict->GetDictFor("Resources");
46 CPDF_Array* pMatrix = m_pFontDict->GetArrayFor("FontMatrix");
47 float xscale = 1.0f;
48 float yscale = 1.0f;
49 if (pMatrix) {
50 m_FontMatrix = pMatrix->GetMatrix();
51 xscale = m_FontMatrix.a;
52 yscale = m_FontMatrix.d;
53 }
54
55 CPDF_Array* pBBox = m_pFontDict->GetArrayFor("FontBBox");
56 if (pBBox) {
57 CFX_FloatRect box(
58 pBBox->GetNumberAt(0) * xscale, pBBox->GetNumberAt(1) * yscale,
59 pBBox->GetNumberAt(2) * xscale, pBBox->GetNumberAt(3) * yscale);
60 CPDF_Type3Char::TextUnitRectToGlyphUnitRect(&box);
61 m_FontBBox = box.ToFxRect();
62 }
63
64 static constexpr size_t kCharLimit = FX_ArraySize(m_CharWidthL);
65 int StartChar = m_pFontDict->GetIntegerFor("FirstChar");
66 if (StartChar >= 0 && static_cast<size_t>(StartChar) < kCharLimit) {
67 CPDF_Array* pWidthArray = m_pFontDict->GetArrayFor("Widths");
68 if (pWidthArray) {
69 size_t count = std::min(pWidthArray->GetCount(), kCharLimit);
70 count = std::min(count, kCharLimit - StartChar);
71 for (size_t i = 0; i < count; i++) {
72 m_CharWidthL[StartChar + i] =
73 FXSYS_round(CPDF_Type3Char::TextUnitToGlyphUnit(
74 pWidthArray->GetNumberAt(i) * xscale));
75 }
76 }
77 }
78 m_pCharProcs = m_pFontDict->GetDictFor("CharProcs");
79 CPDF_Object* pEncoding = m_pFontDict->GetDirectObjectFor("Encoding");
80 if (pEncoding)
81 LoadPDFEncoding(pEncoding, m_BaseEncoding, &m_CharNames, false, false);
82 return true;
83 }
84
LoadGlyphMap()85 void CPDF_Type3Font::LoadGlyphMap() {}
86
CheckType3FontMetrics()87 void CPDF_Type3Font::CheckType3FontMetrics() {
88 CheckFontMetrics();
89 }
90
LoadChar(uint32_t charcode)91 CPDF_Type3Char* CPDF_Type3Font::LoadChar(uint32_t charcode) {
92 if (m_CharLoadingDepth >= kMaxType3FormLevel)
93 return nullptr;
94
95 auto it = m_CacheMap.find(charcode);
96 if (it != m_CacheMap.end())
97 return it->second.get();
98
99 const char* name = GetAdobeCharName(m_BaseEncoding, m_CharNames, charcode);
100 if (!name)
101 return nullptr;
102
103 CPDF_Stream* pStream =
104 ToStream(m_pCharProcs ? m_pCharProcs->GetDirectObjectFor(name) : nullptr);
105 if (!pStream)
106 return nullptr;
107
108 auto pNewChar =
109 pdfium::MakeUnique<CPDF_Type3Char>(pdfium::MakeUnique<CPDF_Form>(
110 m_pDocument.Get(),
111 m_pFontResources ? m_pFontResources.Get() : m_pPageResources.Get(),
112 pStream, nullptr));
113
114 // This can trigger recursion into this method. The content of |m_CacheMap|
115 // can change as a result. Thus after it returns, check the cache again for
116 // a cache hit.
117 m_CharLoadingDepth++;
118 pNewChar->form()->ParseContentWithParams(nullptr, nullptr, pNewChar.get(), 0);
119 m_CharLoadingDepth--;
120 it = m_CacheMap.find(charcode);
121 if (it != m_CacheMap.end())
122 return it->second.get();
123
124 pNewChar->Transform(m_FontMatrix);
125 m_CacheMap[charcode] = std::move(pNewChar);
126 CPDF_Type3Char* pCachedChar = m_CacheMap[charcode].get();
127 if (pCachedChar->form()->GetPageObjectList()->empty())
128 pCachedChar->ResetForm();
129 return pCachedChar;
130 }
131
GetCharWidthF(uint32_t charcode)132 int CPDF_Type3Font::GetCharWidthF(uint32_t charcode) {
133 if (charcode >= FX_ArraySize(m_CharWidthL))
134 charcode = 0;
135
136 if (m_CharWidthL[charcode])
137 return m_CharWidthL[charcode];
138
139 const CPDF_Type3Char* pChar = LoadChar(charcode);
140 return pChar ? pChar->width() : 0;
141 }
142
GetCharBBox(uint32_t charcode)143 FX_RECT CPDF_Type3Font::GetCharBBox(uint32_t charcode) {
144 FX_RECT ret;
145 const CPDF_Type3Char* pChar = LoadChar(charcode);
146 if (pChar)
147 ret = pChar->bbox();
148 return ret;
149 }
150