// 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/fpdf_font/include/cpdf_font.h" #include "core/fpdfapi/fpdf_font/cpdf_truetypefont.h" #include "core/fpdfapi/fpdf_font/cpdf_type1font.h" #include "core/fpdfapi/fpdf_font/cpdf_type3font.h" #include "core/fpdfapi/fpdf_font/font_int.h" #include "core/fpdfapi/fpdf_font/include/cpdf_fontencoding.h" #include "core/fpdfapi/fpdf_page/pageint.h" #include "core/fpdfapi/fpdf_parser/include/cpdf_array.h" #include "core/fpdfapi/fpdf_parser/include/cpdf_dictionary.h" #include "core/fpdfapi/fpdf_parser/include/cpdf_document.h" #include "core/fpdfapi/fpdf_parser/include/cpdf_name.h" #include "core/fpdfapi/fpdf_parser/include/cpdf_stream_acc.h" #include "core/fpdfapi/include/cpdf_modulemgr.h" #include "core/include/fxge/fx_freetype.h" namespace { const uint8_t ChineseFontNames[][5] = {{0xCB, 0xCE, 0xCC, 0xE5, 0x00}, {0xBF, 0xAC, 0xCC, 0xE5, 0x00}, {0xBA, 0xDA, 0xCC, 0xE5, 0x00}, {0xB7, 0xC2, 0xCB, 0xCE, 0x00}, {0xD0, 0xC2, 0xCB, 0xCE, 0x00}}; FX_BOOL GetPredefinedEncoding(int& basemap, const CFX_ByteString& value) { if (value == "WinAnsiEncoding") basemap = PDFFONT_ENCODING_WINANSI; else if (value == "MacRomanEncoding") basemap = PDFFONT_ENCODING_MACROMAN; else if (value == "MacExpertEncoding") basemap = PDFFONT_ENCODING_MACEXPERT; else if (value == "PDFDocEncoding") basemap = PDFFONT_ENCODING_PDFDOC; else return FALSE; return TRUE; } } // namespace CPDF_Font::CPDF_Font() : m_pFontFile(nullptr), m_pFontDict(nullptr), m_pToUnicodeMap(nullptr), m_bToUnicodeLoaded(FALSE), m_Flags(0), m_StemV(0), m_Ascent(0), m_Descent(0), m_ItalicAngle(0) {} CPDF_Font::~CPDF_Font() { delete m_pToUnicodeMap; m_pToUnicodeMap = NULL; if (m_pFontFile) { m_pDocument->GetPageData()->ReleaseFontFileStreamAcc( const_cast(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; } FX_BOOL CPDF_Font::IsUnicodeCompatible() const { return FALSE; } int CPDF_Font::CountChar(const FX_CHAR* pString, int size) const { return size; } int CPDF_Font::GetCharSize(FX_DWORD charcode) const { return 1; } int CPDF_Font::GlyphFromCharCode(FX_DWORD charcode, FX_BOOL* pVertGlyph) { ASSERT(false); return 0; } int CPDF_Font::GlyphFromCharCodeExt(FX_DWORD charcode) { return GlyphFromCharCode(charcode); } FX_BOOL CPDF_Font::IsVertWriting() const { FX_BOOL bVertWriting = FALSE; const CPDF_CIDFont* pCIDFont = AsCIDFont(); if (pCIDFont) { bVertWriting = pCIDFont->IsVertWriting(); } else { bVertWriting = m_Font.IsVertical(); } return bVertWriting; } int CPDF_Font::AppendChar(FX_CHAR* buf, FX_DWORD charcode) const { *buf = (FX_CHAR)charcode; return 1; } void CPDF_Font::AppendChar(CFX_ByteString& str, FX_DWORD charcode) const { char buf[4]; int len = AppendChar(buf, charcode); if (len == 1) { str += buf[0]; } else { str += CFX_ByteString(buf, len); } } CFX_WideString CPDF_Font::UnicodeFromCharCode(FX_DWORD charcode) const { if (!m_bToUnicodeLoaded) ((CPDF_Font*)this)->LoadUnicodeMap(); if (m_pToUnicodeMap) return m_pToUnicodeMap->Lookup(charcode); return CFX_WideString(); } FX_DWORD CPDF_Font::CharCodeFromUnicode(FX_WCHAR unicode) const { if (!m_bToUnicodeLoaded) ((CPDF_Font*)this)->LoadUnicodeMap(); if (m_pToUnicodeMap) return m_pToUnicodeMap->ReverseLookup(unicode); return 0; } void CPDF_Font::LoadFontDescriptor(CPDF_Dictionary* pFontDesc) { m_Flags = pFontDesc->GetIntegerBy("Flags", PDFFONT_NONSYMBOLIC); int ItalicAngle = 0; FX_BOOL bExistItalicAngle = FALSE; if (pFontDesc->KeyExist("ItalicAngle")) { ItalicAngle = pFontDesc->GetIntegerBy("ItalicAngle"); bExistItalicAngle = TRUE; } if (ItalicAngle < 0) { m_Flags |= PDFFONT_ITALIC; m_ItalicAngle = ItalicAngle; } FX_BOOL bExistStemV = FALSE; if (pFontDesc->KeyExist("StemV")) { m_StemV = pFontDesc->GetIntegerBy("StemV"); bExistStemV = TRUE; } FX_BOOL bExistAscent = FALSE; if (pFontDesc->KeyExist("Ascent")) { m_Ascent = pFontDesc->GetIntegerBy("Ascent"); bExistAscent = TRUE; } FX_BOOL bExistDescent = FALSE; if (pFontDesc->KeyExist("Descent")) { m_Descent = pFontDesc->GetIntegerBy("Descent"); bExistDescent = TRUE; } FX_BOOL bExistCapHeight = FALSE; if (pFontDesc->KeyExist("CapHeight")) { bExistCapHeight = TRUE; } if (bExistItalicAngle && bExistAscent && bExistCapHeight && bExistDescent && bExistStemV) { m_Flags |= PDFFONT_USEEXTERNATTR; } if (m_Descent > 10) { m_Descent = -m_Descent; } CPDF_Array* pBBox = pFontDesc->GetArrayBy("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); } CPDF_Stream* pFontFile = pFontDesc->GetStreamBy("FontFile"); if (!pFontFile) pFontFile = pFontDesc->GetStreamBy("FontFile2"); if (!pFontFile) pFontFile = pFontDesc->GetStreamBy("FontFile3"); if (!pFontFile) return; m_pFontFile = m_pDocument->LoadFontFile(pFontFile); if (!m_pFontFile) return; const uint8_t* pFontData = m_pFontFile->GetData(); FX_DWORD dwFontSize = m_pFontFile->GetSize(); if (!m_Font.LoadEmbedded(pFontData, dwFontSize)) { m_pDocument->GetPageData()->ReleaseFontFileStreamAcc( const_cast(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_Face face = m_Font.GetFace(); 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 { FX_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() { m_bToUnicodeLoaded = TRUE; CPDF_Stream* pStream = m_pFontDict->GetStreamBy("ToUnicode"); if (!pStream) { return; } m_pToUnicodeMap = new CPDF_ToUnicodeMap; m_pToUnicodeMap->Load(pStream); } int CPDF_Font::GetStringWidth(const FX_CHAR* pString, int size) { int offset = 0; int width = 0; while (offset < size) { FX_DWORD charcode = GetNextChar(pString, size, offset); width += GetCharWidthF(charcode); } return width; } CPDF_Font* CPDF_Font::GetStockFont(CPDF_Document* pDoc, const CFX_ByteStringC& name) { CFX_ByteString fontname(name); int font_id = PDF_GetStandardFontName(&fontname); if (font_id < 0) { return nullptr; } CPDF_FontGlobals* pFontGlobals = CPDF_ModuleMgr::Get()->GetPageModule()->GetFontGlobals(); CPDF_Font* pFont = pFontGlobals->Find(pDoc, font_id); if (pFont) { return pFont; } CPDF_Dictionary* pDict = new CPDF_Dictionary; pDict->SetAtName("Type", "Font"); pDict->SetAtName("Subtype", "Type1"); pDict->SetAtName("BaseFont", fontname); pDict->SetAtName("Encoding", "WinAnsiEncoding"); pFont = CPDF_Font::CreateFontF(NULL, pDict); pFontGlobals->Set(pDoc, font_id, pFont); return pFont; } CPDF_Font* CPDF_Font::CreateFontF(CPDF_Document* pDoc, CPDF_Dictionary* pFontDict) { CFX_ByteString type = pFontDict->GetStringBy("Subtype"); CPDF_Font* pFont; if (type == "TrueType") { { #if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ || \ _FXM_PLATFORM_ == _FXM_PLATFORM_LINUX_ || \ _FXM_PLATFORM_ == _FXM_PLATFORM_ANDROID_ || \ _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ CFX_ByteString basefont = pFontDict->GetStringBy("BaseFont"); CFX_ByteString tag = basefont.Left(4); int i; int count = sizeof(ChineseFontNames) / sizeof(ChineseFontNames[0]); for (i = 0; i < count; ++i) { if (tag == CFX_ByteString((const FX_CHAR*)ChineseFontNames[i])) { break; } } if (i < count) { CPDF_Dictionary* pFontDesc = pFontDict->GetDictBy("FontDescriptor"); if (!pFontDesc || !pFontDesc->KeyExist("FontFile2")) { pFont = new CPDF_CIDFont; pFont->m_pFontDict = pFontDict; pFont->m_pDocument = pDoc; pFont->m_BaseFont = pFontDict->GetStringBy("BaseFont"); if (!pFont->Load()) { delete pFont; return NULL; } return pFont; } } #endif } pFont = new CPDF_TrueTypeFont; } else if (type == "Type3") { pFont = new CPDF_Type3Font; } else if (type == "Type0") { pFont = new CPDF_CIDFont; } else { pFont = new CPDF_Type1Font; } pFont->m_pFontDict = pFontDict; pFont->m_pDocument = pDoc; pFont->m_BaseFont = pFontDict->GetStringBy("BaseFont"); if (!pFont->Load()) { delete pFont; return NULL; } return pFont; } FX_DWORD CPDF_Font::GetNextChar(const FX_CHAR* pString, int nStrLen, int& offset) const { if (offset < 0 || nStrLen < 1) { return 0; } uint8_t ch = offset < nStrLen ? pString[offset++] : pString[nStrLen - 1]; return static_cast(ch); } void CPDF_Font::LoadPDFEncoding(CPDF_Object* pEncoding, int& iBaseEncoding, CFX_ByteString*& pCharNames, FX_BOOL bEmbedded, FX_BOOL bTrueType) { if (!pEncoding) { if (m_BaseFont == "Symbol") { iBaseEncoding = bTrueType ? PDFFONT_ENCODING_MS_SYMBOL : PDFFONT_ENCODING_ADOBE_SYMBOL; } else if (!bEmbedded && iBaseEncoding == PDFFONT_ENCODING_BUILTIN) { iBaseEncoding = PDFFONT_ENCODING_WINANSI; } return; } if (pEncoding->IsName()) { if (iBaseEncoding == PDFFONT_ENCODING_ADOBE_SYMBOL || iBaseEncoding == PDFFONT_ENCODING_ZAPFDINGBATS) { return; } if ((m_Flags & PDFFONT_SYMBOLIC) && m_BaseFont == "Symbol") { if (!bTrueType) { iBaseEncoding = PDFFONT_ENCODING_ADOBE_SYMBOL; } return; } CFX_ByteString bsEncoding = pEncoding->GetString(); if (bsEncoding.Compare("MacExpertEncoding") == 0) { bsEncoding = "WinAnsiEncoding"; } GetPredefinedEncoding(iBaseEncoding, bsEncoding); return; } CPDF_Dictionary* pDict = pEncoding->AsDictionary(); if (!pDict) return; if (iBaseEncoding != PDFFONT_ENCODING_ADOBE_SYMBOL && iBaseEncoding != PDFFONT_ENCODING_ZAPFDINGBATS) { CFX_ByteString bsEncoding = pDict->GetStringBy("BaseEncoding"); if (bsEncoding.Compare("MacExpertEncoding") == 0 && bTrueType) { bsEncoding = "WinAnsiEncoding"; } GetPredefinedEncoding(iBaseEncoding, bsEncoding); } if ((!bEmbedded || bTrueType) && iBaseEncoding == PDFFONT_ENCODING_BUILTIN) { iBaseEncoding = PDFFONT_ENCODING_STANDARD; } CPDF_Array* pDiffs = pDict->GetArrayBy("Differences"); if (!pDiffs) { return; } pCharNames = new CFX_ByteString[256]; FX_DWORD cur_code = 0; for (FX_DWORD i = 0; i < pDiffs->GetCount(); i++) { CPDF_Object* pElement = pDiffs->GetElementValue(i); if (!pElement) continue; if (CPDF_Name* pName = pElement->AsName()) { if (cur_code < 256) pCharNames[cur_code] = pName->GetString(); cur_code++; } else { cur_code = pElement->GetInteger(); } } } FX_BOOL CPDF_Font::IsStandardFont() const { if (!IsType1Font()) return FALSE; if (m_pFontFile) return FALSE; if (AsType1Font()->GetBase14Font() < 0) return FALSE; return TRUE; } const FX_CHAR* CPDF_Font::GetAdobeCharName(int iBaseEncoding, const CFX_ByteString* pCharNames, int charcode) { ASSERT(charcode >= 0 && charcode < 256); if (charcode < 0 || charcode >= 256) return nullptr; const FX_CHAR* name = nullptr; if (pCharNames) name = pCharNames[charcode]; if ((!name || name[0] == 0) && iBaseEncoding) name = PDF_CharNameFromPredefinedCharSet(iBaseEncoding, charcode); return name && name[0] ? name : nullptr; }