| // Copyright 2016 The PDFium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com |
| |
| #include "core/fpdfapi/font/cpdf_type3font.h" |
| |
| #include <algorithm> |
| #include <iterator> |
| #include <type_traits> |
| #include <utility> |
| |
| #include "core/fpdfapi/font/cpdf_type3char.h" |
| #include "core/fpdfapi/parser/cpdf_array.h" |
| #include "core/fpdfapi/parser/cpdf_dictionary.h" |
| #include "core/fpdfapi/parser/cpdf_stream.h" |
| #include "core/fxcrt/autorestorer.h" |
| #include "core/fxcrt/fx_system.h" |
| #include "third_party/base/check.h" |
| |
| namespace { |
| |
| constexpr int kMaxType3FormLevel = 4; |
| |
| } // namespace |
| |
| CPDF_Type3Font::CPDF_Type3Font(CPDF_Document* pDocument, |
| RetainPtr<CPDF_Dictionary> pFontDict, |
| FormFactoryIface* pFormFactory) |
| : CPDF_SimpleFont(pDocument, std::move(pFontDict)), |
| m_pFormFactory(pFormFactory) { |
| DCHECK(GetDocument()); |
| } |
| |
| CPDF_Type3Font::~CPDF_Type3Font() = default; |
| |
| bool CPDF_Type3Font::IsType3Font() const { |
| return true; |
| } |
| |
| const CPDF_Type3Font* CPDF_Type3Font::AsType3Font() const { |
| return this; |
| } |
| |
| CPDF_Type3Font* CPDF_Type3Font::AsType3Font() { |
| return this; |
| } |
| |
| void CPDF_Type3Font::WillBeDestroyed() { |
| // Last reference to |this| may be through one of its CPDF_Type3Chars. |
| RetainPtr<CPDF_Font> protector(this); |
| for (const auto& item : m_CacheMap) { |
| if (item.second) |
| item.second->WillBeDestroyed(); |
| } |
| } |
| |
| bool CPDF_Type3Font::Load() { |
| m_pFontResources = m_pFontDict->GetMutableDictFor("Resources"); |
| RetainPtr<const CPDF_Array> pMatrix = m_pFontDict->GetArrayFor("FontMatrix"); |
| float xscale = 1.0f; |
| float yscale = 1.0f; |
| if (pMatrix) { |
| m_FontMatrix = pMatrix->GetMatrix(); |
| xscale = m_FontMatrix.a; |
| yscale = m_FontMatrix.d; |
| } |
| |
| RetainPtr<const CPDF_Array> pBBox = m_pFontDict->GetArrayFor("FontBBox"); |
| if (pBBox) { |
| CFX_FloatRect box( |
| pBBox->GetFloatAt(0) * xscale, pBBox->GetFloatAt(1) * yscale, |
| pBBox->GetFloatAt(2) * xscale, pBBox->GetFloatAt(3) * yscale); |
| CPDF_Type3Char::TextUnitRectToGlyphUnitRect(&box); |
| m_FontBBox = box.ToFxRect(); |
| } |
| |
| static constexpr size_t kCharLimit = std::extent<decltype(m_CharWidthL)>(); |
| int StartChar = m_pFontDict->GetIntegerFor("FirstChar"); |
| if (StartChar >= 0 && static_cast<size_t>(StartChar) < kCharLimit) { |
| RetainPtr<const CPDF_Array> pWidthArray = |
| m_pFontDict->GetArrayFor("Widths"); |
| if (pWidthArray) { |
| size_t count = std::min(pWidthArray->size(), kCharLimit); |
| count = std::min(count, kCharLimit - StartChar); |
| for (size_t i = 0; i < count; i++) { |
| m_CharWidthL[StartChar + i] = |
| FXSYS_roundf(CPDF_Type3Char::TextUnitToGlyphUnit( |
| pWidthArray->GetFloatAt(i) * xscale)); |
| } |
| } |
| } |
| m_pCharProcs = m_pFontDict->GetMutableDictFor("CharProcs"); |
| if (m_pFontDict->GetDirectObjectFor("Encoding")) |
| LoadPDFEncoding(false, false); |
| return true; |
| } |
| |
| void CPDF_Type3Font::LoadGlyphMap() {} |
| |
| void CPDF_Type3Font::CheckType3FontMetrics() { |
| CheckFontMetrics(); |
| } |
| |
| CPDF_Type3Char* CPDF_Type3Font::LoadChar(uint32_t charcode) { |
| if (m_CharLoadingDepth >= kMaxType3FormLevel) |
| return nullptr; |
| |
| auto it = m_CacheMap.find(charcode); |
| if (it != m_CacheMap.end()) |
| return it->second.get(); |
| |
| const char* name = GetAdobeCharName(m_BaseEncoding, m_CharNames, charcode); |
| if (!name) |
| return nullptr; |
| |
| if (!m_pCharProcs) |
| return nullptr; |
| |
| RetainPtr<CPDF_Stream> pStream = |
| ToStream(m_pCharProcs->GetMutableDirectObjectFor(name)); |
| if (!pStream) |
| return nullptr; |
| |
| std::unique_ptr<CPDF_Font::FormIface> pForm = m_pFormFactory->CreateForm( |
| m_pDocument, m_pFontResources ? m_pFontResources : m_pPageResources, |
| pStream); |
| |
| auto pNewChar = std::make_unique<CPDF_Type3Char>(); |
| |
| // This can trigger recursion into this method. The content of |m_CacheMap| |
| // can change as a result. Thus after it returns, check the cache again for |
| // a cache hit. |
| { |
| AutoRestorer<int> restorer(&m_CharLoadingDepth); |
| m_CharLoadingDepth++; |
| pForm->ParseContentForType3Char(pNewChar.get()); |
| } |
| it = m_CacheMap.find(charcode); |
| if (it != m_CacheMap.end()) |
| return it->second.get(); |
| |
| pNewChar->Transform(pForm.get(), m_FontMatrix); |
| if (pForm->HasPageObjects()) |
| pNewChar->SetForm(std::move(pForm)); |
| |
| CPDF_Type3Char* pCachedChar = pNewChar.get(); |
| m_CacheMap[charcode] = std::move(pNewChar); |
| return pCachedChar; |
| } |
| |
| int CPDF_Type3Font::GetCharWidthF(uint32_t charcode) { |
| if (charcode >= std::size(m_CharWidthL)) |
| charcode = 0; |
| |
| if (m_CharWidthL[charcode]) |
| return m_CharWidthL[charcode]; |
| |
| const CPDF_Type3Char* pChar = LoadChar(charcode); |
| return pChar ? pChar->width() : 0; |
| } |
| |
| FX_RECT CPDF_Type3Font::GetCharBBox(uint32_t charcode) { |
| FX_RECT ret; |
| const CPDF_Type3Char* pChar = LoadChar(charcode); |
| if (pChar) |
| ret = pChar->bbox(); |
| return ret; |
| } |