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 <stdarg.h>
10
11 #include <algorithm>
12 #include <limits>
13 #include <memory>
14 #include <utility>
15
16 #include "build/build_config.h"
17 #include "core/fxcrt/fx_codepage.h"
18 #include "core/fxge/cfx_defaultrenderdevice.h"
19 #include "core/fxge/cfx_font.h"
20 #include "core/fxge/cfx_fontmgr.h"
21 #include "core/fxge/cfx_gemodule.h"
22 #include "core/fxge/cfx_glyphbitmap.h"
23 #include "core/fxge/cfx_path.h"
24 #include "core/fxge/cfx_substfont.h"
25 #include "core/fxge/dib/cfx_dibitmap.h"
26 #include "core/fxge/freetype/fx_freetype.h"
27 #include "core/fxge/scoped_font_transform.h"
28 #include "third_party/base/numerics/safe_math.h"
29
30 #if defined(_SKIA_SUPPORT_)
31 #include "third_party/skia/include/core/SkStream.h" // nogncheck
32 #include "third_party/skia/include/core/SkTypeface.h" // nogncheck
33
34 #if BUILDFLAG(IS_WIN)
35 #include "third_party/skia/include/core/SkFontMgr.h" // nogncheck
36 #include "third_party/skia/include/ports/SkFontMgr_empty.h" // nogncheck
37 #endif
38 #endif
39
40 #if BUILDFLAG(IS_APPLE)
41 #include "core/fxge/cfx_textrenderoptions.h"
42 #endif
43
44 namespace {
45
46 constexpr uint32_t kInvalidGlyphIndex = static_cast<uint32_t>(-1);
47
48 constexpr int kMaxGlyphDimension = 2048;
49
50 struct UniqueKeyGen {
51 void Generate(int count, ...);
52
53 int key_len_;
54 char key_[128];
55 };
56
Generate(int count,...)57 void UniqueKeyGen::Generate(int count, ...) {
58 va_list argList;
59 va_start(argList, count);
60 for (int i = 0; i < count; i++) {
61 int p = va_arg(argList, int);
62 reinterpret_cast<uint32_t*>(key_)[i] = p;
63 }
64 va_end(argList);
65 key_len_ = count * sizeof(uint32_t);
66 }
67
GenKey(UniqueKeyGen * pKeyGen,const CFX_Font * pFont,const CFX_Matrix & matrix,int dest_width,int anti_alias,bool bNative)68 void GenKey(UniqueKeyGen* pKeyGen,
69 const CFX_Font* pFont,
70 const CFX_Matrix& matrix,
71 int dest_width,
72 int anti_alias,
73 bool bNative) {
74 int nMatrixA = static_cast<int>(matrix.a * 10000);
75 int nMatrixB = static_cast<int>(matrix.b * 10000);
76 int nMatrixC = static_cast<int>(matrix.c * 10000);
77 int nMatrixD = static_cast<int>(matrix.d * 10000);
78
79 #if BUILDFLAG(IS_APPLE)
80 if (bNative) {
81 if (pFont->GetSubstFont()) {
82 pKeyGen->Generate(10, nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width,
83 anti_alias, pFont->GetSubstFont()->m_Weight,
84 pFont->GetSubstFont()->m_ItalicAngle,
85 pFont->IsVertical(), 3);
86 } else {
87 pKeyGen->Generate(7, nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width,
88 anti_alias, 3);
89 }
90 return;
91 }
92 #else
93 CHECK(!bNative);
94 #endif
95
96 if (pFont->GetSubstFont()) {
97 pKeyGen->Generate(9, nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width,
98 anti_alias, pFont->GetSubstFont()->m_Weight,
99 pFont->GetSubstFont()->m_ItalicAngle,
100 pFont->IsVertical());
101 } else {
102 pKeyGen->Generate(6, nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width,
103 anti_alias);
104 }
105 }
106
107 } // namespace
108
CFX_GlyphCache(RetainPtr<CFX_Face> face)109 CFX_GlyphCache::CFX_GlyphCache(RetainPtr<CFX_Face> face)
110 : m_Face(std::move(face)) {}
111
112 CFX_GlyphCache::~CFX_GlyphCache() = default;
113
RenderGlyph(const CFX_Font * pFont,uint32_t glyph_index,bool bFontStyle,const CFX_Matrix & matrix,int dest_width,int anti_alias)114 std::unique_ptr<CFX_GlyphBitmap> CFX_GlyphCache::RenderGlyph(
115 const CFX_Font* pFont,
116 uint32_t glyph_index,
117 bool bFontStyle,
118 const CFX_Matrix& matrix,
119 int dest_width,
120 int anti_alias) {
121 if (!GetFaceRec())
122 return nullptr;
123
124 FT_Matrix ft_matrix;
125 ft_matrix.xx = matrix.a / 64 * 65536;
126 ft_matrix.xy = matrix.c / 64 * 65536;
127 ft_matrix.yx = matrix.b / 64 * 65536;
128 ft_matrix.yy = matrix.d / 64 * 65536;
129 bool bUseCJKSubFont = false;
130 const CFX_SubstFont* pSubstFont = pFont->GetSubstFont();
131 if (pSubstFont) {
132 bUseCJKSubFont = pSubstFont->m_bSubstCJK && bFontStyle;
133 int angle;
134 if (bUseCJKSubFont)
135 angle = pSubstFont->m_bItalicCJK ? -15 : 0;
136 else
137 angle = pSubstFont->m_ItalicAngle;
138 if (angle) {
139 int skew = CFX_Font::GetSkewFromAngle(angle);
140 if (pFont->IsVertical())
141 ft_matrix.yx += ft_matrix.yy * skew / 100;
142 else
143 ft_matrix.xy -= ft_matrix.xx * skew / 100;
144 }
145 if (pSubstFont->IsBuiltInGenericFont()) {
146 pFont->AdjustMMParams(glyph_index, dest_width,
147 pFont->GetSubstFont()->m_Weight);
148 }
149 }
150
151 ScopedFontTransform scoped_transform(GetFace(), &ft_matrix);
152 int load_flags = FT_LOAD_NO_BITMAP | FT_LOAD_PEDANTIC;
153 if (!(GetFaceRec()->face_flags & FT_FACE_FLAG_SFNT))
154 load_flags |= FT_LOAD_NO_HINTING;
155 int error = FT_Load_Glyph(GetFaceRec(), glyph_index, load_flags);
156 if (error) {
157 // if an error is returned, try to reload glyphs without hinting.
158 if (load_flags & FT_LOAD_NO_HINTING)
159 return nullptr;
160
161 load_flags |= FT_LOAD_NO_HINTING;
162 load_flags &= ~FT_LOAD_PEDANTIC;
163 error = FT_Load_Glyph(GetFaceRec(), glyph_index, load_flags);
164 if (error)
165 return nullptr;
166 }
167
168 int weight;
169 if (bUseCJKSubFont)
170 weight = pSubstFont->m_WeightCJK;
171 else
172 weight = pSubstFont ? pSubstFont->m_Weight : 0;
173 if (pSubstFont && !pSubstFont->IsBuiltInGenericFont() && weight > 400) {
174 uint32_t index = (weight - 400) / 10;
175 pdfium::base::CheckedNumeric<signed long> level =
176 CFX_Font::GetWeightLevel(pSubstFont->m_Charset, index);
177 if (level.ValueOrDefault(-1) < 0)
178 return nullptr;
179
180 level = level *
181 (abs(static_cast<int>(ft_matrix.xx)) +
182 abs(static_cast<int>(ft_matrix.xy))) /
183 36655;
184 FT_Outline_Embolden(FXFT_Get_Glyph_Outline(GetFaceRec()),
185 level.ValueOrDefault(0));
186 }
187 FT_Library_SetLcdFilter(CFX_GEModule::Get()->GetFontMgr()->GetFTLibrary(),
188 FT_LCD_FILTER_DEFAULT);
189 error = FXFT_Render_Glyph(GetFaceRec(), anti_alias);
190 if (error)
191 return nullptr;
192
193 int bmwidth = FXFT_Get_Bitmap_Width(FXFT_Get_Glyph_Bitmap(GetFaceRec()));
194 int bmheight = FXFT_Get_Bitmap_Rows(FXFT_Get_Glyph_Bitmap(GetFaceRec()));
195 if (bmwidth > kMaxGlyphDimension || bmheight > kMaxGlyphDimension)
196 return nullptr;
197 int dib_width = bmwidth;
198 auto pGlyphBitmap =
199 std::make_unique<CFX_GlyphBitmap>(FXFT_Get_Glyph_BitmapLeft(GetFaceRec()),
200 FXFT_Get_Glyph_BitmapTop(GetFaceRec()));
201 pGlyphBitmap->GetBitmap()->Create(dib_width, bmheight,
202 anti_alias == FT_RENDER_MODE_MONO
203 ? FXDIB_Format::k1bppMask
204 : FXDIB_Format::k8bppMask);
205 int dest_pitch = pGlyphBitmap->GetBitmap()->GetPitch();
206 int src_pitch = FXFT_Get_Bitmap_Pitch(FXFT_Get_Glyph_Bitmap(GetFaceRec()));
207 uint8_t* pDestBuf = pGlyphBitmap->GetBitmap()->GetWritableBuffer().data();
208 uint8_t* pSrcBuf = static_cast<uint8_t*>(
209 FXFT_Get_Bitmap_Buffer(FXFT_Get_Glyph_Bitmap(GetFaceRec())));
210 if (anti_alias != FT_RENDER_MODE_MONO &&
211 FXFT_Get_Bitmap_PixelMode(FXFT_Get_Glyph_Bitmap(GetFaceRec())) ==
212 FT_PIXEL_MODE_MONO) {
213 int bytes = anti_alias == FT_RENDER_MODE_LCD ? 3 : 1;
214 for (int i = 0; i < bmheight; i++) {
215 for (int n = 0; n < bmwidth; n++) {
216 uint8_t data =
217 (pSrcBuf[i * src_pitch + n / 8] & (0x80 >> (n % 8))) ? 255 : 0;
218 for (int b = 0; b < bytes; b++)
219 pDestBuf[i * dest_pitch + n * bytes + b] = data;
220 }
221 }
222 } else {
223 memset(pDestBuf, 0, dest_pitch * bmheight);
224 int rowbytes = std::min(abs(src_pitch), dest_pitch);
225 for (int row = 0; row < bmheight; row++)
226 memcpy(pDestBuf + row * dest_pitch, pSrcBuf + row * src_pitch, rowbytes);
227 }
228 return pGlyphBitmap;
229 }
230
LoadGlyphPath(const CFX_Font * pFont,uint32_t glyph_index,int dest_width)231 const CFX_Path* CFX_GlyphCache::LoadGlyphPath(const CFX_Font* pFont,
232 uint32_t glyph_index,
233 int dest_width) {
234 if (!GetFaceRec() || glyph_index == kInvalidGlyphIndex)
235 return nullptr;
236
237 const auto* pSubstFont = pFont->GetSubstFont();
238 int weight = pSubstFont ? pSubstFont->m_Weight : 0;
239 int angle = pSubstFont ? pSubstFont->m_ItalicAngle : 0;
240 bool vertical = pSubstFont && pFont->IsVertical();
241 const PathMapKey key =
242 std::make_tuple(glyph_index, dest_width, weight, angle, vertical);
243 auto it = m_PathMap.find(key);
244 if (it != m_PathMap.end())
245 return it->second.get();
246
247 m_PathMap[key] = pFont->LoadGlyphPathImpl(glyph_index, dest_width);
248 return m_PathMap[key].get();
249 }
250
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)251 const CFX_GlyphBitmap* CFX_GlyphCache::LoadGlyphBitmap(
252 const CFX_Font* pFont,
253 uint32_t glyph_index,
254 bool bFontStyle,
255 const CFX_Matrix& matrix,
256 int dest_width,
257 int anti_alias,
258 CFX_TextRenderOptions* text_options) {
259 if (glyph_index == kInvalidGlyphIndex)
260 return nullptr;
261
262 UniqueKeyGen keygen;
263 #if BUILDFLAG(IS_APPLE)
264 const bool bNative = text_options->native_text;
265 #else
266 const bool bNative = false;
267 #endif
268 GenKey(&keygen, pFont, matrix, dest_width, anti_alias, bNative);
269 ByteString FaceGlyphsKey(keygen.key_, keygen.key_len_);
270
271 #if BUILDFLAG(IS_APPLE)
272 const bool bDoLookUp = !text_options->native_text ||
273 CFX_DefaultRenderDevice::SkiaIsDefaultRenderer();
274 #else
275 const bool bDoLookUp = true;
276 #endif
277 if (bDoLookUp) {
278 return LookUpGlyphBitmap(pFont, matrix, FaceGlyphsKey, glyph_index,
279 bFontStyle, dest_width, anti_alias);
280 }
281
282 #if BUILDFLAG(IS_APPLE)
283 DCHECK(!CFX_DefaultRenderDevice::SkiaIsDefaultRenderer());
284
285 std::unique_ptr<CFX_GlyphBitmap> pGlyphBitmap;
286 auto it = m_SizeMap.find(FaceGlyphsKey);
287 if (it != m_SizeMap.end()) {
288 SizeGlyphCache* pSizeCache = &(it->second);
289 auto it2 = pSizeCache->find(glyph_index);
290 if (it2 != pSizeCache->end())
291 return it2->second.get();
292
293 pGlyphBitmap = RenderGlyph_Nativetext(pFont, glyph_index, matrix,
294 dest_width, anti_alias);
295 if (pGlyphBitmap) {
296 CFX_GlyphBitmap* pResult = pGlyphBitmap.get();
297 (*pSizeCache)[glyph_index] = std::move(pGlyphBitmap);
298 return pResult;
299 }
300 } else {
301 pGlyphBitmap = RenderGlyph_Nativetext(pFont, glyph_index, matrix,
302 dest_width, anti_alias);
303 if (pGlyphBitmap) {
304 CFX_GlyphBitmap* pResult = pGlyphBitmap.get();
305
306 SizeGlyphCache cache;
307 cache[glyph_index] = std::move(pGlyphBitmap);
308
309 m_SizeMap[FaceGlyphsKey] = std::move(cache);
310 return pResult;
311 }
312 }
313 GenKey(&keygen, pFont, matrix, dest_width, anti_alias, /*bNative=*/false);
314 ByteString FaceGlyphsKey2(keygen.key_, keygen.key_len_);
315 text_options->native_text = false;
316 return LookUpGlyphBitmap(pFont, matrix, FaceGlyphsKey2, glyph_index,
317 bFontStyle, dest_width, anti_alias);
318 #endif // BUILDFLAG(IS_APPLE)
319 }
320
GetGlyphWidth(const CFX_Font * font,uint32_t glyph_index,int dest_width,int weight)321 int CFX_GlyphCache::GetGlyphWidth(const CFX_Font* font,
322 uint32_t glyph_index,
323 int dest_width,
324 int weight) {
325 const WidthMapKey key = std::make_tuple(glyph_index, dest_width, weight);
326 auto it = m_WidthMap.find(key);
327 if (it != m_WidthMap.end()) {
328 return it->second;
329 }
330
331 m_WidthMap[key] = font->GetGlyphWidthImpl(glyph_index, dest_width, weight);
332 return m_WidthMap[key];
333 }
334
335 #if defined(_SKIA_SUPPORT_)
GetDeviceCache(const CFX_Font * pFont)336 CFX_TypeFace* CFX_GlyphCache::GetDeviceCache(const CFX_Font* pFont) {
337 if (!m_pTypeface) {
338 pdfium::span<const uint8_t> span = pFont->GetFontSpan();
339 m_pTypeface = SkTypeface::MakeFromStream(
340 std::make_unique<SkMemoryStream>(span.data(), span.size()));
341 }
342 #if BUILDFLAG(IS_WIN)
343 if (!m_pTypeface) {
344 sk_sp<SkFontMgr> customMgr(SkFontMgr_New_Custom_Empty());
345 pdfium::span<const uint8_t> span = pFont->GetFontSpan();
346 m_pTypeface = customMgr->makeFromStream(
347 std::make_unique<SkMemoryStream>(span.data(), span.size()));
348 }
349 #endif // BUILDFLAG(IS_WIN)
350 return m_pTypeface.get();
351 }
352 #endif // defined(_SKIA_SUPPORT_)
353
LookUpGlyphBitmap(const CFX_Font * pFont,const CFX_Matrix & matrix,const ByteString & FaceGlyphsKey,uint32_t glyph_index,bool bFontStyle,int dest_width,int anti_alias)354 CFX_GlyphBitmap* CFX_GlyphCache::LookUpGlyphBitmap(
355 const CFX_Font* pFont,
356 const CFX_Matrix& matrix,
357 const ByteString& FaceGlyphsKey,
358 uint32_t glyph_index,
359 bool bFontStyle,
360 int dest_width,
361 int anti_alias) {
362 SizeGlyphCache* pSizeCache;
363 auto it = m_SizeMap.find(FaceGlyphsKey);
364 if (it == m_SizeMap.end()) {
365 m_SizeMap[FaceGlyphsKey] = SizeGlyphCache();
366 pSizeCache = &(m_SizeMap[FaceGlyphsKey]);
367 } else {
368 pSizeCache = &(it->second);
369 }
370
371 auto it2 = pSizeCache->find(glyph_index);
372 if (it2 != pSizeCache->end())
373 return it2->second.get();
374
375 std::unique_ptr<CFX_GlyphBitmap> pGlyphBitmap = RenderGlyph(
376 pFont, glyph_index, bFontStyle, matrix, dest_width, anti_alias);
377 CFX_GlyphBitmap* pResult = pGlyphBitmap.get();
378 (*pSizeCache)[glyph_index] = std::move(pGlyphBitmap);
379 return pResult;
380 }
381