| // Copyright 2016 PDFium Authors. All rights reserved. |
| // 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_font.h" |
| |
| #include <limits> |
| #include <memory> |
| #include <utility> |
| #include <vector> |
| |
| #include "build/build_config.h" |
| #include "core/fpdfapi/font/cpdf_cidfont.h" |
| #include "core/fpdfapi/font/cpdf_fontencoding.h" |
| #include "core/fpdfapi/font/cpdf_fontglobals.h" |
| #include "core/fpdfapi/font/cpdf_tounicodemap.h" |
| #include "core/fpdfapi/font/cpdf_truetypefont.h" |
| #include "core/fpdfapi/font/cpdf_type1font.h" |
| #include "core/fpdfapi/font/cpdf_type3font.h" |
| #include "core/fpdfapi/parser/cpdf_array.h" |
| #include "core/fpdfapi/parser/cpdf_dictionary.h" |
| #include "core/fpdfapi/parser/cpdf_document.h" |
| #include "core/fpdfapi/parser/cpdf_name.h" |
| #include "core/fpdfapi/parser/cpdf_stream.h" |
| #include "core/fpdfapi/parser/cpdf_stream_acc.h" |
| #include "core/fxcrt/fx_codepage.h" |
| #include "core/fxcrt/fx_safe_types.h" |
| #include "core/fxcrt/stl_util.h" |
| #include "core/fxge/cfx_fontmapper.h" |
| #include "core/fxge/fx_font.h" |
| #include "core/fxge/fx_freetype.h" |
| #include "third_party/base/check.h" |
| #include "third_party/base/cxx17_backports.h" |
| #include "third_party/base/numerics/ranges.h" |
| |
| namespace { |
| |
| constexpr size_t kChineseFontNameSize = 4; |
| const uint8_t kChineseFontNames[][kChineseFontNameSize] = { |
| {0xCB, 0xCE, 0xCC, 0xE5}, |
| {0xBF, 0xAC, 0xCC, 0xE5}, |
| {0xBA, 0xDA, 0xCC, 0xE5}, |
| {0xB7, 0xC2, 0xCB, 0xCE}, |
| {0xD0, 0xC2, 0xCB, 0xCE}}; |
| |
| } // namespace |
| |
| CPDF_Font::CPDF_Font(CPDF_Document* pDocument, CPDF_Dictionary* pFontDict) |
| : m_pDocument(pDocument), |
| m_pFontDict(pFontDict), |
| m_BaseFontName(pFontDict->GetStringFor("BaseFont")) {} |
| |
| CPDF_Font::~CPDF_Font() { |
| if (m_pFontFile) { |
| auto* pPageData = m_pDocument->GetPageData(); |
| if (pPageData) { |
| pPageData->MaybePurgeFontFileStreamAcc( |
| m_pFontFile->GetStream()->AsStream()); |
| } |
| } |
| } |
| |
| bool CPDF_Font::IsType1Font() const { |
| return false; |
| } |
| |
| bool CPDF_Font::IsTrueTypeFont() const { |
| return false; |
| } |
| |
| bool CPDF_Font::IsType3Font() const { |
| return false; |
| } |
| |
| bool CPDF_Font::IsCIDFont() const { |
| return false; |
| } |
| |
| const CPDF_Type1Font* CPDF_Font::AsType1Font() const { |
| return nullptr; |
| } |
| |
| CPDF_Type1Font* CPDF_Font::AsType1Font() { |
| return nullptr; |
| } |
| |
| const CPDF_TrueTypeFont* CPDF_Font::AsTrueTypeFont() const { |
| return nullptr; |
| } |
| |
| CPDF_TrueTypeFont* CPDF_Font::AsTrueTypeFont() { |
| return nullptr; |
| } |
| |
| const CPDF_Type3Font* CPDF_Font::AsType3Font() const { |
| return nullptr; |
| } |
| |
| CPDF_Type3Font* CPDF_Font::AsType3Font() { |
| return nullptr; |
| } |
| |
| const CPDF_CIDFont* CPDF_Font::AsCIDFont() const { |
| return nullptr; |
| } |
| |
| CPDF_CIDFont* CPDF_Font::AsCIDFont() { |
| return nullptr; |
| } |
| |
| bool CPDF_Font::IsUnicodeCompatible() const { |
| return false; |
| } |
| |
| size_t CPDF_Font::CountChar(ByteStringView pString) const { |
| return pString.GetLength(); |
| } |
| |
| #if defined(OS_APPLE) |
| int CPDF_Font::GlyphFromCharCodeExt(uint32_t charcode) { |
| return GlyphFromCharCode(charcode, nullptr); |
| } |
| #endif |
| |
| void CPDF_Font::WillBeDestroyed() {} |
| |
| bool CPDF_Font::IsVertWriting() const { |
| const CPDF_CIDFont* pCIDFont = AsCIDFont(); |
| return pCIDFont ? pCIDFont->IsVertWriting() : m_Font.IsVertical(); |
| } |
| |
| int CPDF_Font::AppendChar(char* buf, uint32_t charcode) const { |
| *buf = static_cast<char>(charcode); |
| return 1; |
| } |
| |
| void CPDF_Font::AppendChar(ByteString* str, uint32_t charcode) const { |
| char buf[4]; |
| int len = AppendChar(buf, charcode); |
| *str += ByteStringView(buf, len); |
| } |
| |
| WideString CPDF_Font::UnicodeFromCharCode(uint32_t charcode) const { |
| if (!m_bToUnicodeLoaded) |
| LoadUnicodeMap(); |
| |
| return m_pToUnicodeMap ? m_pToUnicodeMap->Lookup(charcode) : WideString(); |
| } |
| |
| uint32_t CPDF_Font::CharCodeFromUnicode(wchar_t unicode) const { |
| if (!m_bToUnicodeLoaded) |
| LoadUnicodeMap(); |
| |
| return m_pToUnicodeMap ? m_pToUnicodeMap->ReverseLookup(unicode) : 0; |
| } |
| |
| bool CPDF_Font::HasFontWidths() const { |
| return true; |
| } |
| |
| void CPDF_Font::LoadFontDescriptor(const CPDF_Dictionary* pFontDesc) { |
| m_Flags = pFontDesc->GetIntegerFor("Flags", FXFONT_NONSYMBOLIC); |
| int ItalicAngle = 0; |
| bool bExistItalicAngle = false; |
| if (pFontDesc->KeyExist("ItalicAngle")) { |
| ItalicAngle = pFontDesc->GetIntegerFor("ItalicAngle"); |
| bExistItalicAngle = true; |
| } |
| if (ItalicAngle < 0) { |
| m_Flags |= FXFONT_ITALIC; |
| m_ItalicAngle = ItalicAngle; |
| } |
| bool bExistStemV = false; |
| if (pFontDesc->KeyExist("StemV")) { |
| m_StemV = pFontDesc->GetIntegerFor("StemV"); |
| bExistStemV = true; |
| } |
| bool bExistAscent = false; |
| if (pFontDesc->KeyExist("Ascent")) { |
| m_Ascent = pFontDesc->GetIntegerFor("Ascent"); |
| bExistAscent = true; |
| } |
| bool bExistDescent = false; |
| if (pFontDesc->KeyExist("Descent")) { |
| m_Descent = pFontDesc->GetIntegerFor("Descent"); |
| bExistDescent = true; |
| } |
| bool bExistCapHeight = false; |
| if (pFontDesc->KeyExist("CapHeight")) |
| bExistCapHeight = true; |
| if (bExistItalicAngle && bExistAscent && bExistCapHeight && bExistDescent && |
| bExistStemV) { |
| m_Flags |= FXFONT_USEEXTERNATTR; |
| } |
| if (m_Descent > 10) |
| m_Descent = -m_Descent; |
| const CPDF_Array* pBBox = pFontDesc->GetArrayFor("FontBBox"); |
| if (pBBox) { |
| m_FontBBox.left = pBBox->GetIntegerAt(0); |
| m_FontBBox.bottom = pBBox->GetIntegerAt(1); |
| m_FontBBox.right = pBBox->GetIntegerAt(2); |
| m_FontBBox.top = pBBox->GetIntegerAt(3); |
| } |
| |
| const CPDF_Stream* pFontFile = pFontDesc->GetStreamFor("FontFile"); |
| if (!pFontFile) |
| pFontFile = pFontDesc->GetStreamFor("FontFile2"); |
| if (!pFontFile) |
| pFontFile = pFontDesc->GetStreamFor("FontFile3"); |
| if (!pFontFile) |
| return; |
| |
| auto* pData = m_pDocument->GetPageData(); |
| m_pFontFile = pData->GetFontFileStreamAcc(pFontFile); |
| if (!m_pFontFile) |
| return; |
| |
| if (!m_Font.LoadEmbedded(m_pFontFile->GetSpan(), IsVertWriting())) { |
| pData->MaybePurgeFontFileStreamAcc(m_pFontFile->GetStream()->AsStream()); |
| m_pFontFile = nullptr; |
| } |
| } |
| |
| void CPDF_Font::CheckFontMetrics() { |
| if (m_FontBBox.top == 0 && m_FontBBox.bottom == 0 && m_FontBBox.left == 0 && |
| m_FontBBox.right == 0) { |
| FXFT_FaceRec* face = m_Font.GetFaceRec(); |
| if (face) { |
| m_FontBBox.left = TT2PDF(FXFT_Get_Face_xMin(face), face); |
| m_FontBBox.bottom = TT2PDF(FXFT_Get_Face_yMin(face), face); |
| m_FontBBox.right = TT2PDF(FXFT_Get_Face_xMax(face), face); |
| m_FontBBox.top = TT2PDF(FXFT_Get_Face_yMax(face), face); |
| m_Ascent = TT2PDF(FXFT_Get_Face_Ascender(face), face); |
| m_Descent = TT2PDF(FXFT_Get_Face_Descender(face), face); |
| } else { |
| bool bFirst = true; |
| for (int i = 0; i < 256; i++) { |
| FX_RECT rect = GetCharBBox(i); |
| if (rect.left == rect.right) { |
| continue; |
| } |
| if (bFirst) { |
| m_FontBBox = rect; |
| bFirst = false; |
| } else { |
| if (m_FontBBox.top < rect.top) { |
| m_FontBBox.top = rect.top; |
| } |
| if (m_FontBBox.right < rect.right) { |
| m_FontBBox.right = rect.right; |
| } |
| if (m_FontBBox.left > rect.left) { |
| m_FontBBox.left = rect.left; |
| } |
| if (m_FontBBox.bottom > rect.bottom) { |
| m_FontBBox.bottom = rect.bottom; |
| } |
| } |
| } |
| } |
| } |
| if (m_Ascent == 0 && m_Descent == 0) { |
| FX_RECT rect = GetCharBBox('A'); |
| m_Ascent = rect.bottom == rect.top ? m_FontBBox.top : rect.top; |
| rect = GetCharBBox('g'); |
| m_Descent = rect.bottom == rect.top ? m_FontBBox.bottom : rect.bottom; |
| } |
| } |
| |
| void CPDF_Font::LoadUnicodeMap() const { |
| m_bToUnicodeLoaded = true; |
| const CPDF_Stream* pStream = m_pFontDict->GetStreamFor("ToUnicode"); |
| if (!pStream) |
| return; |
| |
| m_pToUnicodeMap = std::make_unique<CPDF_ToUnicodeMap>(pStream); |
| } |
| |
| int CPDF_Font::GetStringWidth(ByteStringView pString) { |
| size_t offset = 0; |
| int width = 0; |
| while (offset < pString.GetLength()) |
| width += GetCharWidthF(GetNextChar(pString, &offset)); |
| return width; |
| } |
| |
| // static |
| RetainPtr<CPDF_Font> CPDF_Font::GetStockFont(CPDF_Document* pDoc, |
| ByteStringView name) { |
| ByteString fontname(name); |
| Optional<CFX_FontMapper::StandardFont> font_id = |
| CFX_FontMapper::GetStandardFontName(&fontname); |
| if (!font_id.has_value()) |
| return nullptr; |
| |
| auto* pFontGlobals = CPDF_FontGlobals::GetInstance(); |
| RetainPtr<CPDF_Font> pFont = pFontGlobals->Find(pDoc, font_id.value()); |
| if (pFont) |
| return pFont; |
| |
| auto pDict = pDoc->New<CPDF_Dictionary>(); |
| pDict->SetNewFor<CPDF_Name>("Type", "Font"); |
| pDict->SetNewFor<CPDF_Name>("Subtype", "Type1"); |
| pDict->SetNewFor<CPDF_Name>("BaseFont", fontname); |
| pDict->SetNewFor<CPDF_Name>("Encoding", "WinAnsiEncoding"); |
| pFont = CPDF_Font::Create(nullptr, pDict.Get(), nullptr); |
| pFontGlobals->Set(pDoc, font_id.value(), pFont); |
| return pFont; |
| } |
| |
| // static |
| RetainPtr<CPDF_Font> CPDF_Font::Create(CPDF_Document* pDoc, |
| CPDF_Dictionary* pFontDict, |
| FormFactoryIface* pFactory) { |
| ByteString type = pFontDict->GetStringFor("Subtype"); |
| RetainPtr<CPDF_Font> pFont; |
| if (type == "TrueType") { |
| ByteString tag = pFontDict->GetStringFor("BaseFont").First(4); |
| for (size_t i = 0; i < pdfium::size(kChineseFontNames); ++i) { |
| if (tag == ByteString(kChineseFontNames[i], kChineseFontNameSize)) { |
| const CPDF_Dictionary* pFontDesc = |
| pFontDict->GetDictFor("FontDescriptor"); |
| if (!pFontDesc || !pFontDesc->KeyExist("FontFile2")) |
| pFont = pdfium::MakeRetain<CPDF_CIDFont>(pDoc, pFontDict); |
| break; |
| } |
| } |
| if (!pFont) |
| pFont = pdfium::MakeRetain<CPDF_TrueTypeFont>(pDoc, pFontDict); |
| } else if (type == "Type3") { |
| pFont = pdfium::MakeRetain<CPDF_Type3Font>(pDoc, pFontDict, pFactory); |
| } else if (type == "Type0") { |
| pFont = pdfium::MakeRetain<CPDF_CIDFont>(pDoc, pFontDict); |
| } else { |
| pFont = pdfium::MakeRetain<CPDF_Type1Font>(pDoc, pFontDict); |
| } |
| if (!pFont->Load()) |
| return nullptr; |
| |
| return pFont; |
| } |
| |
| uint32_t CPDF_Font::GetNextChar(ByteStringView pString, size_t* pOffset) const { |
| if (pString.IsEmpty()) |
| return 0; |
| |
| size_t& offset = *pOffset; |
| return offset < pString.GetLength() ? pString[offset++] : pString.Back(); |
| } |
| |
| bool CPDF_Font::IsStandardFont() const { |
| if (!IsType1Font()) |
| return false; |
| if (m_pFontFile) |
| return false; |
| return AsType1Font()->IsBase14Font(); |
| } |
| |
| // static |
| const char* CPDF_Font::GetAdobeCharName( |
| int iBaseEncoding, |
| const std::vector<ByteString>& charnames, |
| uint32_t charcode) { |
| if (charcode >= 256) |
| return nullptr; |
| |
| if (!charnames.empty() && !charnames[charcode].IsEmpty()) |
| return charnames[charcode].c_str(); |
| |
| const char* name = nullptr; |
| if (iBaseEncoding) |
| name = PDF_CharNameFromPredefinedCharSet(iBaseEncoding, charcode); |
| if (!name) |
| return nullptr; |
| |
| DCHECK(name[0]); |
| return name; |
| } |
| |
| uint32_t CPDF_Font::FallbackFontFromCharcode(uint32_t charcode) { |
| if (m_FontFallbacks.empty()) { |
| m_FontFallbacks.push_back(std::make_unique<CFX_Font>()); |
| FX_SAFE_INT32 safeWeight = m_StemV; |
| safeWeight *= 5; |
| m_FontFallbacks[0]->LoadSubst("Arial", IsTrueTypeFont(), m_Flags, |
| safeWeight.ValueOrDefault(FXFONT_FW_NORMAL), |
| m_ItalicAngle, FX_CodePage::kDefANSI, |
| IsVertWriting()); |
| } |
| return 0; |
| } |
| |
| int CPDF_Font::FallbackGlyphFromCharcode(int fallbackFont, uint32_t charcode) { |
| if (!fxcrt::IndexInBounds(m_FontFallbacks, fallbackFont)) |
| return -1; |
| |
| WideString str = UnicodeFromCharCode(charcode); |
| uint32_t unicode = !str.IsEmpty() ? str[0] : charcode; |
| int glyph = |
| FT_Get_Char_Index(m_FontFallbacks[fallbackFont]->GetFaceRec(), unicode); |
| if (glyph == 0) |
| return -1; |
| |
| return glyph; |
| } |
| |
| CFX_Font* CPDF_Font::GetFontFallback(int position) { |
| if (position < 0 || static_cast<size_t>(position) >= m_FontFallbacks.size()) |
| return nullptr; |
| return m_FontFallbacks[position].get(); |
| } |
| |
| // static |
| int CPDF_Font::TT2PDF(int m, FXFT_FaceRec* face) { |
| int upm = FXFT_Get_Face_UnitsPerEM(face); |
| if (upm == 0) |
| return m; |
| |
| return static_cast<int>( |
| pdfium::clamp((m * 1000.0 + upm / 2) / upm, |
| static_cast<double>(std::numeric_limits<int>::min()), |
| static_cast<double>(std::numeric_limits<int>::max()))); |
| } |
| |
| // static |
| bool CPDF_Font::FT_UseTTCharmap(FXFT_FaceRec* face, |
| int platform_id, |
| int encoding_id) { |
| auto** pCharMap = FXFT_Get_Face_Charmaps(face); |
| for (int i = 0; i < FXFT_Get_Face_CharmapCount(face); i++) { |
| if (FXFT_Get_Charmap_PlatformID(pCharMap[i]) == platform_id && |
| FXFT_Get_Charmap_EncodingID(pCharMap[i]) == encoding_id) { |
| FT_Set_Charmap(face, pCharMap[i]); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| int CPDF_Font::GetFontWeight() const { |
| FX_SAFE_INT32 safeStemV(m_StemV); |
| if (m_StemV < 140) |
| safeStemV *= 5; |
| else |
| safeStemV = safeStemV * 4 + 140; |
| return safeStemV.ValueOrDefault(FXFONT_FW_NORMAL); |
| } |