blob: 35579b1b5862494c7a19d68992c2a3a0a2f6fa54 [file] [log] [blame]
// 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;
}