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