blob: 24bb2bb625664fe70e577c338220b4b85a67880e [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/span.h"
#include "core/fxcrt/to_underlying.h"
#include "core/fxge/cfx_font.h"
#include "core/fxge/cfx_gemodule.h"
#include "core/fxge/cfx_glyphbitmap.h"
#include "core/fxge/cfx_path.h"
#include "core/fxge/cfx_substfont.h"
#include "core/fxge/fx_font.h"
#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* font,
const CFX_Matrix& matrix,
int dest_width,
FontAntiAliasingMode 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::span<uint32_t, pdfium::dynamic_extent>(key_);
for (const auto& arg : args) {
key_span.front() = arg;
key_span = key_span.subspan<1u>();
}
key_len_ = args.size();
}
pdfium::span<const uint8_t> UniqueKeyGen::span() const {
return pdfium::as_bytes(pdfium::span(key_).first(key_len_));
}
UniqueKeyGen::UniqueKeyGen(const CFX_Font* font,
const CFX_Matrix& matrix,
int dest_width,
FontAntiAliasingMode 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 (font->GetSubstFont()) {
Initialize({nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width,
fxcrt::to_underlying(anti_alias),
font->GetSubstFont()->weight_,
font->GetSubstFont()->italic_angle_, font->IsVertical(), 3});
} else {
Initialize({nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width,
fxcrt::to_underlying(anti_alias), 3});
}
return;
}
#endif
CHECK(!bNative);
if (font->GetSubstFont()) {
Initialize({nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width,
fxcrt::to_underlying(anti_alias), font->GetSubstFont()->weight_,
font->GetSubstFont()->italic_angle_, font->IsVertical()});
} else {
Initialize({nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width,
fxcrt::to_underlying(anti_alias)});
}
}
} // namespace
CFX_GlyphCache::CFX_GlyphCache(RetainPtr<CFX_Face> face)
: face_(std::move(face)) {}
CFX_GlyphCache::~CFX_GlyphCache() = default;
std::unique_ptr<CFX_GlyphBitmap> CFX_GlyphCache::RenderGlyph(
uint32_t glyph_index,
bool font_style,
bool is_vertical,
const CFX_Matrix& matrix,
int dest_width,
FontAntiAliasingMode anti_alias,
const CFX_SubstFont* subst_font) {
if (!face_) {
return nullptr;
}
return face_->RenderGlyph(glyph_index, font_style, is_vertical, matrix,
dest_width, anti_alias, subst_font);
}
const CFX_Path* CFX_GlyphCache::LoadGlyphPath(const CFX_Font* font,
uint32_t glyph_index,
int dest_width) {
if (!face_ || glyph_index == kInvalidGlyphIndex) {
return nullptr;
}
const auto* pSubstFont = font->GetSubstFont();
int weight = pSubstFont ? pSubstFont->weight_ : 0;
int angle = pSubstFont ? pSubstFont->italic_angle_ : 0;
bool vertical = pSubstFont && font->IsVertical();
const PathMapKey key =
std::make_tuple(glyph_index, dest_width, weight, angle, vertical);
auto it = path_map_.find(key);
if (it != path_map_.end()) {
return it->second.get();
}
path_map_[key] = font->LoadGlyphPathImpl(glyph_index, dest_width);
return path_map_[key].get();
}
const CFX_GlyphBitmap* CFX_GlyphCache::LoadGlyphBitmap(
const CFX_Font* font,
uint32_t glyph_index,
bool bFontStyle,
const CFX_Matrix& matrix,
int dest_width,
FontAntiAliasingMode 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(font, matrix, dest_width, anti_alias, bNative);
auto FaceGlyphsKey = ByteString(ByteStringView(keygen.span()));
#if BUILDFLAG(IS_APPLE)
bool bDoLookUp = !text_options->native_text;
#if defined(PDF_USE_SKIA)
bDoLookUp = bDoLookUp || CFX_GEModule::Get()->UseSkiaRenderer();
#endif // defined(PDF_USE_SKIA)
#else // BUILDFLAG(IS_APPLE)
const bool bDoLookUp = true;
#endif // BUILDFLAG(IS_APPLE)
if (bDoLookUp) {
return LookUpGlyphBitmap(font, matrix, FaceGlyphsKey, glyph_index,
bFontStyle, dest_width, anti_alias);
}
#if BUILDFLAG(IS_APPLE)
#if defined(PDF_USE_SKIA)
DCHECK(!CFX_GEModule::Get()->UseSkiaRenderer());
#endif // defined(PDF_USE_SKIA)
auto it = size_map_.find(FaceGlyphsKey);
if (it != size_map_.end()) {
SizeToGlyphMap& size_glyph_cache = it->second;
auto size_glyph_it = size_glyph_cache.find(glyph_index);
if (size_glyph_it != size_glyph_cache.end()) {
return size_glyph_it->second.get();
}
}
UniqueKeyGen keygen2(font, matrix, dest_width, anti_alias,
/*bNative=*/false);
auto FaceGlyphsKey2 = ByteString(ByteStringView(keygen2.span()));
text_options->native_text = false;
return LookUpGlyphBitmap(font, 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 = width_map_.find(key);
if (it != width_map_.end()) {
return it->second;
}
width_map_[key] = font->GetGlyphWidthImpl(glyph_index, dest_width, weight);
return width_map_[key];
}
CFX_GlyphBitmap* CFX_GlyphCache::LookUpGlyphBitmap(
const CFX_Font* font,
const CFX_Matrix& matrix,
const ByteString& FaceGlyphsKey,
uint32_t glyph_index,
bool bFontStyle,
int dest_width,
FontAntiAliasingMode anti_alias) {
SizeToGlyphMap* pSizeCache;
auto it = size_map_.find(FaceGlyphsKey);
if (it == size_map_.end()) {
size_map_[FaceGlyphsKey] = SizeToGlyphMap();
pSizeCache = &(size_map_[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(glyph_index, bFontStyle, font->IsVertical(), matrix,
dest_width, anti_alias, font->GetSubstFont());
CFX_GlyphBitmap* pResult = pGlyphBitmap.get();
(*pSizeCache)[glyph_index] = std::move(pGlyphBitmap);
return pResult;
}