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