1 // Copyright 2016 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "core/fxge/cfx_glyphcache.h"
8
9 #include <initializer_list>
10 #include <memory>
11 #include <utility>
12
13 #include "build/build_config.h"
14 #include "core/fxcrt/fx_codepage.h"
15 #include "core/fxcrt/fx_memcpy_wrappers.h"
16 #include "core/fxcrt/span.h"
17 #include "core/fxge/cfx_defaultrenderdevice.h"
18 #include "core/fxge/cfx_font.h"
19 #include "core/fxge/cfx_glyphbitmap.h"
20 #include "core/fxge/cfx_path.h"
21 #include "core/fxge/cfx_substfont.h"
22
23 #if defined(PDF_USE_SKIA)
24 #include "third_party/skia/include/core/SkStream.h" // nogncheck
25 #include "third_party/skia/include/core/SkTypeface.h" // nogncheck
26 #include "third_party/skia/include/core/SkFontMgr.h" // nogncheck
27 #include "third_party/skia/include/ports/SkFontMgr_empty.h" // nogncheck
28
29 #if BUILDFLAG(IS_WIN)
30 #include "third_party/skia/include/ports/SkTypeface_win.h" // nogncheck
31 #elif BUILDFLAG(IS_APPLE)
32 #include "third_party/skia/include/ports/SkFontMgr_mac_ct.h" // nogncheck
33 #endif
34
35 #endif
36
37 #if BUILDFLAG(IS_APPLE)
38 #include "core/fxge/cfx_textrenderoptions.h"
39 #endif
40
41 namespace {
42
43 constexpr uint32_t kInvalidGlyphIndex = static_cast<uint32_t>(-1);
44
45 class UniqueKeyGen {
46 public:
47 UniqueKeyGen(const CFX_Font* pFont,
48 const CFX_Matrix& matrix,
49 int dest_width,
50 int anti_alias,
51 bool bNative);
52
53 pdfium::span<const uint8_t> span() const;
54
55 private:
56 void Initialize(std::initializer_list<const int> args);
57
58 size_t key_len_;
59 uint32_t key_[32];
60 };
61
Initialize(std::initializer_list<const int32_t> args)62 void UniqueKeyGen::Initialize(std::initializer_list<const int32_t> args) {
63 auto key_span = pdfium::make_span(key_);
64 for (const auto& arg : args) {
65 key_span.front() = arg;
66 key_span = key_span.subspan(1);
67 }
68 key_len_ = args.size();
69 }
70
span() const71 pdfium::span<const uint8_t> UniqueKeyGen::span() const {
72 return pdfium::as_bytes(pdfium::make_span(key_).first(key_len_));
73 }
74
UniqueKeyGen(const CFX_Font * pFont,const CFX_Matrix & matrix,int dest_width,int anti_alias,bool bNative)75 UniqueKeyGen::UniqueKeyGen(const CFX_Font* pFont,
76 const CFX_Matrix& matrix,
77 int dest_width,
78 int anti_alias,
79 bool bNative) {
80 int nMatrixA = static_cast<int>(matrix.a * 10000);
81 int nMatrixB = static_cast<int>(matrix.b * 10000);
82 int nMatrixC = static_cast<int>(matrix.c * 10000);
83 int nMatrixD = static_cast<int>(matrix.d * 10000);
84
85 #if BUILDFLAG(IS_APPLE)
86 if (bNative) {
87 if (pFont->GetSubstFont()) {
88 Initialize({nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width,
89 anti_alias, pFont->GetSubstFont()->m_Weight,
90 pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical(),
91 3});
92 } else {
93 Initialize(
94 {nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width, anti_alias, 3});
95 }
96 return;
97 }
98 #endif
99
100 CHECK(!bNative);
101 if (pFont->GetSubstFont()) {
102 Initialize({nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width, anti_alias,
103 pFont->GetSubstFont()->m_Weight,
104 pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical()});
105 } else {
106 Initialize(
107 {nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width, anti_alias});
108 }
109 }
110
111 } // namespace
112
CFX_GlyphCache(RetainPtr<CFX_Face> face)113 CFX_GlyphCache::CFX_GlyphCache(RetainPtr<CFX_Face> face)
114 : m_Face(std::move(face)) {}
115
116 CFX_GlyphCache::~CFX_GlyphCache() = default;
117
RenderGlyph(const CFX_Font * pFont,uint32_t glyph_index,bool bFontStyle,const CFX_Matrix & matrix,int dest_width,int anti_alias)118 std::unique_ptr<CFX_GlyphBitmap> CFX_GlyphCache::RenderGlyph(
119 const CFX_Font* pFont,
120 uint32_t glyph_index,
121 bool bFontStyle,
122 const CFX_Matrix& matrix,
123 int dest_width,
124 int anti_alias) {
125 if (!m_Face) {
126 return nullptr;
127 }
128
129 return m_Face->RenderGlyph(pFont, glyph_index, bFontStyle, matrix, dest_width,
130 anti_alias);
131 }
132
LoadGlyphPath(const CFX_Font * pFont,uint32_t glyph_index,int dest_width)133 const CFX_Path* CFX_GlyphCache::LoadGlyphPath(const CFX_Font* pFont,
134 uint32_t glyph_index,
135 int dest_width) {
136 if (!GetFace() || glyph_index == kInvalidGlyphIndex) {
137 return nullptr;
138 }
139
140 const auto* pSubstFont = pFont->GetSubstFont();
141 int weight = pSubstFont ? pSubstFont->m_Weight : 0;
142 int angle = pSubstFont ? pSubstFont->m_ItalicAngle : 0;
143 bool vertical = pSubstFont && pFont->IsVertical();
144 const PathMapKey key =
145 std::make_tuple(glyph_index, dest_width, weight, angle, vertical);
146 auto it = m_PathMap.find(key);
147 if (it != m_PathMap.end())
148 return it->second.get();
149
150 m_PathMap[key] = pFont->LoadGlyphPathImpl(glyph_index, dest_width);
151 return m_PathMap[key].get();
152 }
153
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)154 const CFX_GlyphBitmap* CFX_GlyphCache::LoadGlyphBitmap(
155 const CFX_Font* pFont,
156 uint32_t glyph_index,
157 bool bFontStyle,
158 const CFX_Matrix& matrix,
159 int dest_width,
160 int anti_alias,
161 CFX_TextRenderOptions* text_options) {
162 if (glyph_index == kInvalidGlyphIndex)
163 return nullptr;
164
165 #if BUILDFLAG(IS_APPLE)
166 const bool bNative = text_options->native_text;
167 #else
168 const bool bNative = false;
169 #endif
170 UniqueKeyGen keygen(pFont, matrix, dest_width, anti_alias, bNative);
171 auto FaceGlyphsKey = ByteString(ByteStringView(keygen.span()));
172
173 #if BUILDFLAG(IS_APPLE)
174 const bool bDoLookUp =
175 !text_options->native_text || CFX_DefaultRenderDevice::UseSkiaRenderer();
176 #else
177 const bool bDoLookUp = true;
178 #endif
179 if (bDoLookUp) {
180 return LookUpGlyphBitmap(pFont, matrix, FaceGlyphsKey, glyph_index,
181 bFontStyle, dest_width, anti_alias);
182 }
183
184 #if BUILDFLAG(IS_APPLE)
185 DCHECK(!CFX_DefaultRenderDevice::UseSkiaRenderer());
186
187 std::unique_ptr<CFX_GlyphBitmap> pGlyphBitmap;
188 auto it = m_SizeMap.find(FaceGlyphsKey);
189 if (it != m_SizeMap.end()) {
190 SizeGlyphCache* pSizeCache = &(it->second);
191 auto it2 = pSizeCache->find(glyph_index);
192 if (it2 != pSizeCache->end())
193 return it2->second.get();
194
195 pGlyphBitmap = RenderGlyph_Nativetext(pFont, glyph_index, matrix,
196 dest_width, anti_alias);
197 if (pGlyphBitmap) {
198 CFX_GlyphBitmap* pResult = pGlyphBitmap.get();
199 (*pSizeCache)[glyph_index] = std::move(pGlyphBitmap);
200 return pResult;
201 }
202 } else {
203 pGlyphBitmap = RenderGlyph_Nativetext(pFont, glyph_index, matrix,
204 dest_width, anti_alias);
205 if (pGlyphBitmap) {
206 CFX_GlyphBitmap* pResult = pGlyphBitmap.get();
207
208 SizeGlyphCache cache;
209 cache[glyph_index] = std::move(pGlyphBitmap);
210
211 m_SizeMap[FaceGlyphsKey] = std::move(cache);
212 return pResult;
213 }
214 }
215 UniqueKeyGen keygen2(pFont, matrix, dest_width, anti_alias,
216 /*bNative=*/false);
217 auto FaceGlyphsKey2 = ByteString(ByteStringView(keygen2.span()));
218 text_options->native_text = false;
219 return LookUpGlyphBitmap(pFont, matrix, FaceGlyphsKey2, glyph_index,
220 bFontStyle, dest_width, anti_alias);
221 #endif // BUILDFLAG(IS_APPLE)
222 }
223
GetGlyphWidth(const CFX_Font * font,uint32_t glyph_index,int dest_width,int weight)224 int CFX_GlyphCache::GetGlyphWidth(const CFX_Font* font,
225 uint32_t glyph_index,
226 int dest_width,
227 int weight) {
228 const WidthMapKey key = std::make_tuple(glyph_index, dest_width, weight);
229 auto it = m_WidthMap.find(key);
230 if (it != m_WidthMap.end()) {
231 return it->second;
232 }
233
234 m_WidthMap[key] = font->GetGlyphWidthImpl(glyph_index, dest_width, weight);
235 return m_WidthMap[key];
236 }
237
238 #if defined(PDF_USE_SKIA)
239
240 namespace {
241 // A singleton SkFontMgr which can be used to decode raw font data or
242 // otherwise get access to system fonts.
243 SkFontMgr* g_fontmgr = nullptr;
244 } // namespace
245
246 // static
InitializeGlobals()247 void CFX_GlyphCache::InitializeGlobals() {
248 CHECK(!g_fontmgr);
249 #if BUILDFLAG(IS_WIN)
250 g_fontmgr = SkFontMgr_New_DirectWrite().release();
251 #elif BUILDFLAG(IS_APPLE)
252 g_fontmgr = SkFontMgr_New_CoreText(nullptr).release();
253 #else
254 // This is a SkFontMgr which will use FreeType to decode font data.
255 g_fontmgr = SkFontMgr_New_Custom_Empty().release();
256 #endif
257 }
258
259 // static
DestroyGlobals()260 void CFX_GlyphCache::DestroyGlobals() {
261 CHECK(g_fontmgr);
262 delete g_fontmgr;
263 g_fontmgr = nullptr;
264 }
265
GetDeviceCache(const CFX_Font * pFont)266 CFX_TypeFace* CFX_GlyphCache::GetDeviceCache(const CFX_Font* pFont) {
267 if (!m_pTypeface && g_fontmgr) {
268 pdfium::span<const uint8_t> span = pFont->GetFontSpan();
269 m_pTypeface = g_fontmgr->makeFromStream(
270 std::make_unique<SkMemoryStream>(span.data(), span.size()));
271 }
272 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE)
273 // If DirectWrite or CoreText didn't work, try FreeType.
274 if (!m_pTypeface) {
275 sk_sp<SkFontMgr> freetype_mgr = SkFontMgr_New_Custom_Empty();
276 pdfium::span<const uint8_t> span = pFont->GetFontSpan();
277 m_pTypeface = freetype_mgr->makeFromStream(
278 std::make_unique<SkMemoryStream>(span.data(), span.size()));
279 }
280 #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE)
281 return m_pTypeface.get();
282 }
283 #endif // defined(PDF_USE_SKIA)
284
LookUpGlyphBitmap(const CFX_Font * pFont,const CFX_Matrix & matrix,const ByteString & FaceGlyphsKey,uint32_t glyph_index,bool bFontStyle,int dest_width,int anti_alias)285 CFX_GlyphBitmap* CFX_GlyphCache::LookUpGlyphBitmap(
286 const CFX_Font* pFont,
287 const CFX_Matrix& matrix,
288 const ByteString& FaceGlyphsKey,
289 uint32_t glyph_index,
290 bool bFontStyle,
291 int dest_width,
292 int anti_alias) {
293 SizeGlyphCache* pSizeCache;
294 auto it = m_SizeMap.find(FaceGlyphsKey);
295 if (it == m_SizeMap.end()) {
296 m_SizeMap[FaceGlyphsKey] = SizeGlyphCache();
297 pSizeCache = &(m_SizeMap[FaceGlyphsKey]);
298 } else {
299 pSizeCache = &(it->second);
300 }
301
302 auto it2 = pSizeCache->find(glyph_index);
303 if (it2 != pSizeCache->end())
304 return it2->second.get();
305
306 std::unique_ptr<CFX_GlyphBitmap> pGlyphBitmap = RenderGlyph(
307 pFont, glyph_index, bFontStyle, matrix, dest_width, anti_alias);
308 CFX_GlyphBitmap* pResult = pGlyphBitmap.get();
309 (*pSizeCache)[glyph_index] = std::move(pGlyphBitmap);
310 return pResult;
311 }
312