| // 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/fxge/cfx_glyphcache.h" | 
 |  | 
 | #include <initializer_list> | 
 | #include <memory> | 
 | #include <utility> | 
 |  | 
 | #include "build/build_config.h" | 
 | #include "core/fxcrt/fx_codepage.h" | 
 | #include "core/fxcrt/fx_memcpy_wrappers.h" | 
 | #include "core/fxcrt/span.h" | 
 | #include "core/fxge/cfx_defaultrenderdevice.h" | 
 | #include "core/fxge/cfx_font.h" | 
 | #include "core/fxge/cfx_glyphbitmap.h" | 
 | #include "core/fxge/cfx_path.h" | 
 | #include "core/fxge/cfx_substfont.h" | 
 |  | 
 | #if defined(PDF_USE_SKIA) | 
 | #include "third_party/skia/include/core/SkStream.h"  // nogncheck | 
 | #include "third_party/skia/include/core/SkTypeface.h"  // nogncheck | 
 | #include "third_party/skia/include/core/SkFontMgr.h"  // nogncheck | 
 | #include "third_party/skia/include/ports/SkFontMgr_empty.h"  // nogncheck | 
 |  | 
 | #if BUILDFLAG(IS_WIN) | 
 | #include "third_party/skia/include/ports/SkTypeface_win.h"  // nogncheck | 
 | #elif BUILDFLAG(IS_APPLE) | 
 | #include "third_party/skia/include/ports/SkFontMgr_mac_ct.h"  // nogncheck | 
 | #endif | 
 |  | 
 | #endif | 
 |  | 
 | #if BUILDFLAG(IS_APPLE) | 
 | #include "core/fxge/cfx_textrenderoptions.h" | 
 | #endif | 
 |  | 
 | namespace { | 
 |  | 
 | constexpr uint32_t kInvalidGlyphIndex = static_cast<uint32_t>(-1); | 
 |  | 
 | class UniqueKeyGen { | 
 |  public: | 
 |   UniqueKeyGen(const CFX_Font* pFont, | 
 |                const CFX_Matrix& matrix, | 
 |                int dest_width, | 
 |                int anti_alias, | 
 |                bool bNative); | 
 |  | 
 |   pdfium::span<const uint8_t> span() const; | 
 |  | 
 |  private: | 
 |   void Initialize(std::initializer_list<const int> args); | 
 |  | 
 |   size_t key_len_; | 
 |   uint32_t key_[32]; | 
 | }; | 
 |  | 
 | void UniqueKeyGen::Initialize(std::initializer_list<const int32_t> args) { | 
 |   auto key_span = pdfium::make_span(key_); | 
 |   for (const auto& arg : args) { | 
 |     key_span.front() = arg; | 
 |     key_span = key_span.subspan(1); | 
 |   } | 
 |   key_len_ = args.size(); | 
 | } | 
 |  | 
 | pdfium::span<const uint8_t> UniqueKeyGen::span() const { | 
 |   return pdfium::as_bytes(pdfium::make_span(key_).first(key_len_)); | 
 | } | 
 |  | 
 | UniqueKeyGen::UniqueKeyGen(const CFX_Font* pFont, | 
 |                            const CFX_Matrix& matrix, | 
 |                            int dest_width, | 
 |                            int anti_alias, | 
 |                            bool bNative) { | 
 |   int nMatrixA = static_cast<int>(matrix.a * 10000); | 
 |   int nMatrixB = static_cast<int>(matrix.b * 10000); | 
 |   int nMatrixC = static_cast<int>(matrix.c * 10000); | 
 |   int nMatrixD = static_cast<int>(matrix.d * 10000); | 
 |  | 
 | #if BUILDFLAG(IS_APPLE) | 
 |   if (bNative) { | 
 |     if (pFont->GetSubstFont()) { | 
 |       Initialize({nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width, | 
 |                   anti_alias, pFont->GetSubstFont()->m_Weight, | 
 |                   pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical(), | 
 |                   3}); | 
 |     } else { | 
 |       Initialize( | 
 |           {nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width, anti_alias, 3}); | 
 |     } | 
 |     return; | 
 |   } | 
 | #endif | 
 |  | 
 |   CHECK(!bNative); | 
 |   if (pFont->GetSubstFont()) { | 
 |     Initialize({nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width, anti_alias, | 
 |                 pFont->GetSubstFont()->m_Weight, | 
 |                 pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical()}); | 
 |   } else { | 
 |     Initialize( | 
 |         {nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width, anti_alias}); | 
 |   } | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | CFX_GlyphCache::CFX_GlyphCache(RetainPtr<CFX_Face> face) | 
 |     : m_Face(std::move(face)) {} | 
 |  | 
 | CFX_GlyphCache::~CFX_GlyphCache() = default; | 
 |  | 
 | std::unique_ptr<CFX_GlyphBitmap> CFX_GlyphCache::RenderGlyph( | 
 |     const CFX_Font* pFont, | 
 |     uint32_t glyph_index, | 
 |     bool bFontStyle, | 
 |     const CFX_Matrix& matrix, | 
 |     int dest_width, | 
 |     int anti_alias) { | 
 |   if (!m_Face) { | 
 |     return nullptr; | 
 |   } | 
 |  | 
 |   return m_Face->RenderGlyph(pFont, glyph_index, bFontStyle, matrix, dest_width, | 
 |                              anti_alias); | 
 | } | 
 |  | 
 | const CFX_Path* CFX_GlyphCache::LoadGlyphPath(const CFX_Font* pFont, | 
 |                                               uint32_t glyph_index, | 
 |                                               int dest_width) { | 
 |   if (!GetFace() || glyph_index == kInvalidGlyphIndex) { | 
 |     return nullptr; | 
 |   } | 
 |  | 
 |   const auto* pSubstFont = pFont->GetSubstFont(); | 
 |   int weight = pSubstFont ? pSubstFont->m_Weight : 0; | 
 |   int angle = pSubstFont ? pSubstFont->m_ItalicAngle : 0; | 
 |   bool vertical = pSubstFont && pFont->IsVertical(); | 
 |   const PathMapKey key = | 
 |       std::make_tuple(glyph_index, dest_width, weight, angle, vertical); | 
 |   auto it = m_PathMap.find(key); | 
 |   if (it != m_PathMap.end()) | 
 |     return it->second.get(); | 
 |  | 
 |   m_PathMap[key] = pFont->LoadGlyphPathImpl(glyph_index, dest_width); | 
 |   return m_PathMap[key].get(); | 
 | } | 
 |  | 
 | const CFX_GlyphBitmap* CFX_GlyphCache::LoadGlyphBitmap( | 
 |     const CFX_Font* pFont, | 
 |     uint32_t glyph_index, | 
 |     bool bFontStyle, | 
 |     const CFX_Matrix& matrix, | 
 |     int dest_width, | 
 |     int anti_alias, | 
 |     CFX_TextRenderOptions* text_options) { | 
 |   if (glyph_index == kInvalidGlyphIndex) | 
 |     return nullptr; | 
 |  | 
 | #if BUILDFLAG(IS_APPLE) | 
 |   const bool bNative = text_options->native_text; | 
 | #else | 
 |   const bool bNative = false; | 
 | #endif | 
 |   UniqueKeyGen keygen(pFont, matrix, dest_width, anti_alias, bNative); | 
 |   auto FaceGlyphsKey = ByteString(ByteStringView(keygen.span())); | 
 |  | 
 | #if BUILDFLAG(IS_APPLE) | 
 |   const bool bDoLookUp = | 
 |       !text_options->native_text || CFX_DefaultRenderDevice::UseSkiaRenderer(); | 
 | #else | 
 |   const bool bDoLookUp = true; | 
 | #endif | 
 |   if (bDoLookUp) { | 
 |     return LookUpGlyphBitmap(pFont, matrix, FaceGlyphsKey, glyph_index, | 
 |                              bFontStyle, dest_width, anti_alias); | 
 |   } | 
 |  | 
 | #if BUILDFLAG(IS_APPLE) | 
 |   DCHECK(!CFX_DefaultRenderDevice::UseSkiaRenderer()); | 
 |  | 
 |   std::unique_ptr<CFX_GlyphBitmap> pGlyphBitmap; | 
 |   auto it = m_SizeMap.find(FaceGlyphsKey); | 
 |   if (it != m_SizeMap.end()) { | 
 |     SizeGlyphCache* pSizeCache = &(it->second); | 
 |     auto it2 = pSizeCache->find(glyph_index); | 
 |     if (it2 != pSizeCache->end()) | 
 |       return it2->second.get(); | 
 |  | 
 |     pGlyphBitmap = RenderGlyph_Nativetext(pFont, glyph_index, matrix, | 
 |                                           dest_width, anti_alias); | 
 |     if (pGlyphBitmap) { | 
 |       CFX_GlyphBitmap* pResult = pGlyphBitmap.get(); | 
 |       (*pSizeCache)[glyph_index] = std::move(pGlyphBitmap); | 
 |       return pResult; | 
 |     } | 
 |   } else { | 
 |     pGlyphBitmap = RenderGlyph_Nativetext(pFont, glyph_index, matrix, | 
 |                                           dest_width, anti_alias); | 
 |     if (pGlyphBitmap) { | 
 |       CFX_GlyphBitmap* pResult = pGlyphBitmap.get(); | 
 |  | 
 |       SizeGlyphCache cache; | 
 |       cache[glyph_index] = std::move(pGlyphBitmap); | 
 |  | 
 |       m_SizeMap[FaceGlyphsKey] = std::move(cache); | 
 |       return pResult; | 
 |     } | 
 |   } | 
 |   UniqueKeyGen keygen2(pFont, matrix, dest_width, anti_alias, | 
 |                        /*bNative=*/false); | 
 |   auto FaceGlyphsKey2 = ByteString(ByteStringView(keygen2.span())); | 
 |   text_options->native_text = false; | 
 |   return LookUpGlyphBitmap(pFont, matrix, FaceGlyphsKey2, glyph_index, | 
 |                            bFontStyle, dest_width, anti_alias); | 
 | #endif  // BUILDFLAG(IS_APPLE) | 
 | } | 
 |  | 
 | int CFX_GlyphCache::GetGlyphWidth(const CFX_Font* font, | 
 |                                   uint32_t glyph_index, | 
 |                                   int dest_width, | 
 |                                   int weight) { | 
 |   const WidthMapKey key = std::make_tuple(glyph_index, dest_width, weight); | 
 |   auto it = m_WidthMap.find(key); | 
 |   if (it != m_WidthMap.end()) { | 
 |     return it->second; | 
 |   } | 
 |  | 
 |   m_WidthMap[key] = font->GetGlyphWidthImpl(glyph_index, dest_width, weight); | 
 |   return m_WidthMap[key]; | 
 | } | 
 |  | 
 | #if defined(PDF_USE_SKIA) | 
 |  | 
 | namespace { | 
 | // A singleton SkFontMgr which can be used to decode raw font data or | 
 | // otherwise get access to system fonts. | 
 | SkFontMgr* g_fontmgr = nullptr; | 
 | }  // namespace | 
 |  | 
 | // static | 
 | void CFX_GlyphCache::InitializeGlobals() { | 
 |   CHECK(!g_fontmgr); | 
 | #if BUILDFLAG(IS_WIN) | 
 |   g_fontmgr = SkFontMgr_New_DirectWrite().release(); | 
 | #elif BUILDFLAG(IS_APPLE) | 
 |   g_fontmgr = SkFontMgr_New_CoreText(nullptr).release(); | 
 | #else | 
 |   // This is a SkFontMgr which will use FreeType to decode font data. | 
 |   g_fontmgr = SkFontMgr_New_Custom_Empty().release(); | 
 | #endif | 
 | } | 
 |  | 
 | // static | 
 | void CFX_GlyphCache::DestroyGlobals() { | 
 |   CHECK(g_fontmgr); | 
 |   delete g_fontmgr; | 
 |   g_fontmgr = nullptr; | 
 | } | 
 |  | 
 | CFX_TypeFace* CFX_GlyphCache::GetDeviceCache(const CFX_Font* pFont) { | 
 |   if (!m_pTypeface && g_fontmgr) { | 
 |     pdfium::span<const uint8_t> span = pFont->GetFontSpan(); | 
 |     m_pTypeface = g_fontmgr->makeFromStream( | 
 |         std::make_unique<SkMemoryStream>(span.data(), span.size())); | 
 |   } | 
 | #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) | 
 |   // If DirectWrite or CoreText didn't work, try FreeType. | 
 |   if (!m_pTypeface) { | 
 |     sk_sp<SkFontMgr> freetype_mgr = SkFontMgr_New_Custom_Empty(); | 
 |     pdfium::span<const uint8_t> span = pFont->GetFontSpan(); | 
 |     m_pTypeface = freetype_mgr->makeFromStream( | 
 |         std::make_unique<SkMemoryStream>(span.data(), span.size())); | 
 |   } | 
 | #endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) | 
 |   return m_pTypeface.get(); | 
 | } | 
 | #endif  // defined(PDF_USE_SKIA) | 
 |  | 
 | CFX_GlyphBitmap* CFX_GlyphCache::LookUpGlyphBitmap( | 
 |     const CFX_Font* pFont, | 
 |     const CFX_Matrix& matrix, | 
 |     const ByteString& FaceGlyphsKey, | 
 |     uint32_t glyph_index, | 
 |     bool bFontStyle, | 
 |     int dest_width, | 
 |     int anti_alias) { | 
 |   SizeGlyphCache* pSizeCache; | 
 |   auto it = m_SizeMap.find(FaceGlyphsKey); | 
 |   if (it == m_SizeMap.end()) { | 
 |     m_SizeMap[FaceGlyphsKey] = SizeGlyphCache(); | 
 |     pSizeCache = &(m_SizeMap[FaceGlyphsKey]); | 
 |   } else { | 
 |     pSizeCache = &(it->second); | 
 |   } | 
 |  | 
 |   auto it2 = pSizeCache->find(glyph_index); | 
 |   if (it2 != pSizeCache->end()) | 
 |     return it2->second.get(); | 
 |  | 
 |   std::unique_ptr<CFX_GlyphBitmap> pGlyphBitmap = RenderGlyph( | 
 |       pFont, glyph_index, bFontStyle, matrix, dest_width, anti_alias); | 
 |   CFX_GlyphBitmap* pResult = pGlyphBitmap.get(); | 
 |   (*pSizeCache)[glyph_index] = std::move(pGlyphBitmap); | 
 |   return pResult; | 
 | } |