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 22 CPDF_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 30 CPDF_Type3Font::~CPDF_Type3Font() {} 31 32 bool CPDF_Type3Font::IsType3Font() const { 33 return true; 34 } 35 36 const CPDF_Type3Font* CPDF_Type3Font::AsType3Font() const { 37 return this; 38 } 39 40 CPDF_Type3Font* CPDF_Type3Font::AsType3Font() { 41 return this; 42 } 43 44 bool 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 80 void CPDF_Type3Font::CheckType3FontMetrics() { 81 CheckFontMetrics(); 82 } 83 84 CPDF_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 138 int 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 149 FX_RECT CPDF_Type3Font::GetCharBBox(uint32_t charcode) { 150 const CPDF_Type3Char* pChar = LoadChar(charcode); 151 return pChar ? pChar->m_BBox : FX_RECT(); 152 } 153