| // 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/fxge/cfx_fontmgr.h" | |
| #include <memory> | |
| #include <utility> | |
| #include "core/fxge/cfx_fontmapper.h" | |
| #include "core/fxge/cfx_substfont.h" | |
| #include "core/fxge/cttfontdesc.h" | |
| #include "core/fxge/fontdata/chromefontdata/chromefontdata.h" | |
| #include "core/fxge/fx_font.h" | |
| #include "core/fxge/systemfontinfo_iface.h" | |
| #include "third_party/base/ptr_util.h" | |
| namespace { | |
| struct BuiltinFont { | |
| const uint8_t* m_pFontData; // Raw, POD struct. | |
| uint32_t m_dwSize; | |
| }; | |
| const BuiltinFont g_FoxitFonts[14] = { | |
| {g_FoxitFixedFontData, 17597}, | |
| {g_FoxitFixedBoldFontData, 18055}, | |
| {g_FoxitFixedBoldItalicFontData, 19151}, | |
| {g_FoxitFixedItalicFontData, 18746}, | |
| {g_FoxitSansFontData, 15025}, | |
| {g_FoxitSansBoldFontData, 16344}, | |
| {g_FoxitSansBoldItalicFontData, 16418}, | |
| {g_FoxitSansItalicFontData, 16339}, | |
| {g_FoxitSerifFontData, 19469}, | |
| {g_FoxitSerifBoldFontData, 19395}, | |
| {g_FoxitSerifBoldItalicFontData, 20733}, | |
| {g_FoxitSerifItalicFontData, 21227}, | |
| {g_FoxitSymbolFontData, 16729}, | |
| {g_FoxitDingbatsFontData, 29513}, | |
| }; | |
| const BuiltinFont g_MMFonts[2] = { | |
| {g_FoxitSerifMMFontData, 113417}, | |
| {g_FoxitSansMMFontData, 66919}, | |
| }; | |
| ByteString KeyNameFromFace(const ByteString& face_name, | |
| int weight, | |
| bool bItalic) { | |
| ByteString key(face_name); | |
| key += ','; | |
| key += ByteString::FormatInteger(weight); | |
| key += bItalic ? 'I' : 'N'; | |
| return key; | |
| } | |
| ByteString KeyNameFromSize(int ttc_size, uint32_t checksum) { | |
| return ByteString::Format("%d:%d", ttc_size, checksum); | |
| } | |
| int GetTTCIndex(const uint8_t* pFontData, | |
| uint32_t ttc_size, | |
| uint32_t font_offset) { | |
| const uint8_t* p = pFontData + 8; | |
| uint32_t nfont = GET_TT_LONG(p); | |
| uint32_t index; | |
| for (index = 0; index < nfont; index++) { | |
| p = pFontData + 12 + index * 4; | |
| if (GET_TT_LONG(p) == font_offset) | |
| break; | |
| } | |
| return index < nfont ? index : 0; | |
| } | |
| } // namespace | |
| CFX_FontMgr::CFX_FontMgr() | |
| : m_pBuiltinMapper(pdfium::MakeUnique<CFX_FontMapper>(this)) {} | |
| CFX_FontMgr::~CFX_FontMgr() = default; | |
| void CFX_FontMgr::InitFTLibrary() { | |
| if (m_FTLibrary) | |
| return; | |
| FXFT_LibraryRec* pLibrary = nullptr; | |
| FT_Init_FreeType(&pLibrary); | |
| m_FTLibrary.reset(pLibrary); | |
| m_FTLibrarySupportsHinting = | |
| SetLcdFilterMode() || FreeTypeVersionSupportsHinting(); | |
| } | |
| void CFX_FontMgr::SetSystemFontInfo( | |
| std::unique_ptr<SystemFontInfoIface> pFontInfo) { | |
| m_pBuiltinMapper->SetSystemFontInfo(std::move(pFontInfo)); | |
| } | |
| FXFT_FaceRec* CFX_FontMgr::FindSubstFont(const ByteString& face_name, | |
| bool bTrueType, | |
| uint32_t flags, | |
| int weight, | |
| int italic_angle, | |
| int CharsetCP, | |
| CFX_SubstFont* pSubstFont) { | |
| InitFTLibrary(); | |
| return m_pBuiltinMapper->FindSubstFont(face_name, bTrueType, flags, weight, | |
| italic_angle, CharsetCP, pSubstFont); | |
| } | |
| FXFT_FaceRec* CFX_FontMgr::GetCachedFace(const ByteString& face_name, | |
| int weight, | |
| bool bItalic, | |
| uint8_t** pFontData) { | |
| auto it = m_FaceMap.find(KeyNameFromFace(face_name, weight, bItalic)); | |
| if (it == m_FaceMap.end()) | |
| return nullptr; | |
| CTTFontDesc* pFontDesc = it->second.get(); | |
| *pFontData = pFontDesc->FontData(); | |
| pFontDesc->AddRef(); | |
| return pFontDesc->GetFace(0); | |
| } | |
| FXFT_FaceRec* CFX_FontMgr::AddCachedFace( | |
| const ByteString& face_name, | |
| int weight, | |
| bool bItalic, | |
| std::unique_ptr<uint8_t, FxFreeDeleter> pData, | |
| uint32_t size, | |
| int face_index) { | |
| InitFTLibrary(); | |
| FXFT_FaceRec* face = nullptr; | |
| int ret = FT_New_Memory_Face(m_FTLibrary.get(), pData.get(), size, face_index, | |
| &face); | |
| if (ret) | |
| return nullptr; | |
| ret = FT_Set_Pixel_Sizes(face, 64, 64); | |
| if (ret) | |
| return nullptr; | |
| auto pFontDesc = pdfium::MakeUnique<CTTFontDesc>(std::move(pData)); | |
| pFontDesc->SetFace(0, face); | |
| CTTFontDesc* pResult = pFontDesc.get(); | |
| m_FaceMap[KeyNameFromFace(face_name, weight, bItalic)] = std::move(pFontDesc); | |
| return pResult->GetFace(0); | |
| } | |
| FXFT_FaceRec* CFX_FontMgr::GetCachedTTCFace(int ttc_size, | |
| uint32_t checksum, | |
| int font_offset, | |
| uint8_t** pFontData) { | |
| auto it = m_FaceMap.find(KeyNameFromSize(ttc_size, checksum)); | |
| if (it == m_FaceMap.end()) | |
| return nullptr; | |
| CTTFontDesc* pFontDesc = it->second.get(); | |
| *pFontData = pFontDesc->FontData(); | |
| int face_index = GetTTCIndex(pFontDesc->FontData(), ttc_size, font_offset); | |
| if (!pFontDesc->GetFace(face_index)) { | |
| pFontDesc->SetFace(face_index, GetFixedFace({pFontDesc->FontData(), | |
| static_cast<size_t>(ttc_size)}, | |
| face_index)); | |
| } | |
| pFontDesc->AddRef(); | |
| return pFontDesc->GetFace(face_index); | |
| } | |
| FXFT_FaceRec* CFX_FontMgr::AddCachedTTCFace( | |
| int ttc_size, | |
| uint32_t checksum, | |
| std::unique_ptr<uint8_t, FxFreeDeleter> pData, | |
| uint32_t size, | |
| int font_offset) { | |
| int face_index = GetTTCIndex(pData.get(), ttc_size, font_offset); | |
| FXFT_FaceRec* face = | |
| GetFixedFace({pData.get(), static_cast<size_t>(ttc_size)}, face_index); | |
| auto pFontDesc = pdfium::MakeUnique<CTTFontDesc>(std::move(pData)); | |
| pFontDesc->SetFace(face_index, face); | |
| m_FaceMap[KeyNameFromSize(ttc_size, checksum)] = std::move(pFontDesc); | |
| return face; | |
| } | |
| FXFT_FaceRec* CFX_FontMgr::GetFixedFace(pdfium::span<const uint8_t> span, | |
| int face_index) { | |
| InitFTLibrary(); | |
| FXFT_FaceRec* face = nullptr; | |
| if (FT_New_Memory_Face(m_FTLibrary.get(), span.data(), span.size(), | |
| face_index, &face)) { | |
| return nullptr; | |
| } | |
| return FT_Set_Pixel_Sizes(face, 64, 64) ? nullptr : face; | |
| } | |
| void CFX_FontMgr::ReleaseFace(FXFT_FaceRec* face) { | |
| if (!face) | |
| return; | |
| bool bNeedFaceDone = true; | |
| for (auto it = m_FaceMap.begin(); it != m_FaceMap.end(); ++it) { | |
| CTTFontDesc::ReleaseStatus nRet = it->second->ReleaseFace(face); | |
| if (nRet == CTTFontDesc::kNotAppropriate) | |
| continue; | |
| bNeedFaceDone = false; | |
| if (nRet == CTTFontDesc::kReleased) | |
| m_FaceMap.erase(it); | |
| break; | |
| } | |
| if (bNeedFaceDone && !m_pBuiltinMapper->IsBuiltinFace(face)) | |
| FT_Done_Face(face); | |
| } | |
| // static | |
| Optional<pdfium::span<const uint8_t>> CFX_FontMgr::GetBuiltinFont( | |
| size_t index) { | |
| if (index < FX_ArraySize(g_FoxitFonts)) { | |
| return pdfium::make_span(g_FoxitFonts[index].m_pFontData, | |
| g_FoxitFonts[index].m_dwSize); | |
| } | |
| size_t mm_index = index - FX_ArraySize(g_FoxitFonts); | |
| if (mm_index < FX_ArraySize(g_MMFonts)) { | |
| return pdfium::make_span(g_MMFonts[mm_index].m_pFontData, | |
| g_MMFonts[mm_index].m_dwSize); | |
| } | |
| return {}; | |
| } | |
| bool CFX_FontMgr::FreeTypeVersionSupportsHinting() const { | |
| FT_Int major; | |
| FT_Int minor; | |
| FT_Int patch; | |
| FT_Library_Version(m_FTLibrary.get(), &major, &minor, &patch); | |
| // Freetype versions >= 2.8.1 support hinting even if subpixel rendering is | |
| // disabled. https://sourceforge.net/projects/freetype/files/freetype2/2.8.1/ | |
| return major > 2 || (major == 2 && minor > 8) || | |
| (major == 2 && minor == 8 && patch >= 1); | |
| } | |
| bool CFX_FontMgr::SetLcdFilterMode() const { | |
| return FT_Library_SetLcdFilter(m_FTLibrary.get(), FT_LCD_FILTER_DEFAULT) != | |
| FT_Err_Unimplemented_Feature; | |
| } |