• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_facecache.h"
8 
9 #include <algorithm>
10 #include <limits>
11 #include <memory>
12 
13 #include "core/fxge/cfx_fontmgr.h"
14 #include "core/fxge/cfx_gemodule.h"
15 #include "core/fxge/cfx_pathdata.h"
16 #include "core/fxge/cfx_substfont.h"
17 #include "core/fxge/fx_freetype.h"
18 #include "core/fxge/ge/fx_text_int.h"
19 #include "third_party/base/numerics/safe_math.h"
20 
21 #if defined _SKIA_SUPPORT_ || _SKIA_SUPPORT_PATHS_
22 #include "third_party/skia/include/core/SkStream.h"
23 #include "third_party/skia/include/core/SkTypeface.h"
24 #endif
25 
26 namespace {
27 
28 constexpr uint32_t kInvalidGlyphIndex = static_cast<uint32_t>(-1);
29 
GammaAdjust(uint8_t * pData,int nHeight,int src_pitch,const uint8_t * gammaTable)30 void GammaAdjust(uint8_t* pData,
31                  int nHeight,
32                  int src_pitch,
33                  const uint8_t* gammaTable) {
34   int count = nHeight * src_pitch;
35   for (int i = 0; i < count; i++)
36     pData[i] = gammaTable[pData[i]];
37 }
38 
ContrastAdjust(uint8_t * pDataIn,uint8_t * pDataOut,int nWidth,int nHeight,int nSrcRowBytes,int nDstRowBytes)39 void ContrastAdjust(uint8_t* pDataIn,
40                     uint8_t* pDataOut,
41                     int nWidth,
42                     int nHeight,
43                     int nSrcRowBytes,
44                     int nDstRowBytes) {
45   int col, row, temp;
46   int max = 0, min = 255;
47   FX_FLOAT rate;
48   for (row = 0; row < nHeight; row++) {
49     uint8_t* pRow = pDataIn + row * nSrcRowBytes;
50     for (col = 0; col < nWidth; col++) {
51       temp = *pRow++;
52       max = std::max(temp, max);
53       min = std::min(temp, min);
54     }
55   }
56   temp = max - min;
57   if (temp == 0 || temp == 255) {
58     int rowbytes = std::min(FXSYS_abs(nSrcRowBytes), nDstRowBytes);
59     for (row = 0; row < nHeight; row++) {
60       FXSYS_memcpy(pDataOut + row * nDstRowBytes, pDataIn + row * nSrcRowBytes,
61                    rowbytes);
62     }
63     return;
64   }
65   rate = 255.f / temp;
66   for (row = 0; row < nHeight; row++) {
67     uint8_t* pSrcRow = pDataIn + row * nSrcRowBytes;
68     uint8_t* pDstRow = pDataOut + row * nDstRowBytes;
69     for (col = 0; col < nWidth; col++) {
70       temp = static_cast<int>((*(pSrcRow++) - min) * rate + 0.5);
71       temp = std::min(temp, 255);
72       temp = std::max(temp, 0);
73       *pDstRow++ = (uint8_t)temp;
74     }
75   }
76 }
77 }  // namespace
78 
CFX_FaceCache(FXFT_Face face)79 CFX_FaceCache::CFX_FaceCache(FXFT_Face face)
80     : m_Face(face)
81 #if defined _SKIA_SUPPORT_ || _SKIA_SUPPORT_PATHS_
82       ,
83       m_pTypeface(nullptr)
84 #endif
85 {
86 }
87 
~CFX_FaceCache()88 CFX_FaceCache::~CFX_FaceCache() {
89 #if defined _SKIA_SUPPORT_ || _SKIA_SUPPORT_PATHS_
90   SkSafeUnref(m_pTypeface);
91 #endif
92 }
93 
RenderGlyph(const CFX_Font * pFont,uint32_t glyph_index,bool bFontStyle,const CFX_Matrix * pMatrix,int dest_width,int anti_alias)94 CFX_GlyphBitmap* CFX_FaceCache::RenderGlyph(const CFX_Font* pFont,
95                                             uint32_t glyph_index,
96                                             bool bFontStyle,
97                                             const CFX_Matrix* pMatrix,
98                                             int dest_width,
99                                             int anti_alias) {
100   if (!m_Face)
101     return nullptr;
102 
103   FXFT_Matrix ft_matrix;
104   ft_matrix.xx = (signed long)(pMatrix->a / 64 * 65536);
105   ft_matrix.xy = (signed long)(pMatrix->c / 64 * 65536);
106   ft_matrix.yx = (signed long)(pMatrix->b / 64 * 65536);
107   ft_matrix.yy = (signed long)(pMatrix->d / 64 * 65536);
108   bool bUseCJKSubFont = false;
109   const CFX_SubstFont* pSubstFont = pFont->GetSubstFont();
110   if (pSubstFont) {
111     bUseCJKSubFont = pSubstFont->m_bSubstCJK && bFontStyle;
112     int skew = 0;
113     if (bUseCJKSubFont)
114       skew = pSubstFont->m_bItalicCJK ? -15 : 0;
115     else
116       skew = pSubstFont->m_ItalicAngle;
117     if (skew) {
118       // |skew| is nonpositive so |-skew| is used as the index. We need to make
119       // sure |skew| != INT_MIN since -INT_MIN is undefined.
120       if (skew <= 0 && skew != std::numeric_limits<int>::min() &&
121           static_cast<size_t>(-skew) < CFX_Font::kAngleSkewArraySize) {
122         skew = -CFX_Font::s_AngleSkew[-skew];
123       } else {
124         skew = -58;
125       }
126       if (pFont->IsVertical())
127         ft_matrix.yx += ft_matrix.yy * skew / 100;
128       else
129         ft_matrix.xy -= ft_matrix.xx * skew / 100;
130     }
131     if (pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) {
132       pFont->AdjustMMParams(glyph_index, dest_width,
133                             pFont->GetSubstFont()->m_Weight);
134     }
135   }
136   ScopedFontTransform scoped_transform(m_Face, &ft_matrix);
137   int load_flags = (m_Face->face_flags & FT_FACE_FLAG_SFNT)
138                        ? FXFT_LOAD_NO_BITMAP
139                        : (FXFT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING);
140   int error = FXFT_Load_Glyph(m_Face, glyph_index, load_flags);
141   if (error) {
142     // if an error is returned, try to reload glyphs without hinting.
143     if (load_flags & FT_LOAD_NO_HINTING || load_flags & FT_LOAD_NO_SCALE)
144       return nullptr;
145 
146     load_flags |= FT_LOAD_NO_HINTING;
147     error = FXFT_Load_Glyph(m_Face, glyph_index, load_flags);
148 
149     if (error)
150       return nullptr;
151   }
152   int weight = 0;
153   if (bUseCJKSubFont)
154     weight = pSubstFont->m_WeightCJK;
155   else
156     weight = pSubstFont ? pSubstFont->m_Weight : 0;
157   if (pSubstFont && !(pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) &&
158       weight > 400) {
159     uint32_t index = (weight - 400) / 10;
160     if (index >= CFX_Font::kWeightPowArraySize)
161       return nullptr;
162     pdfium::base::CheckedNumeric<signed long> level = 0;
163     if (pSubstFont->m_Charset == FXFONT_SHIFTJIS_CHARSET)
164       level = CFX_Font::s_WeightPow_SHIFTJIS[index] * 2;
165     else
166       level = CFX_Font::s_WeightPow_11[index];
167 
168     level = level * (FXSYS_abs(static_cast<int>(ft_matrix.xx)) +
169                      FXSYS_abs(static_cast<int>(ft_matrix.xy))) /
170             36655;
171     FXFT_Outline_Embolden(FXFT_Get_Glyph_Outline(m_Face),
172                           level.ValueOrDefault(0));
173   }
174   FXFT_Library_SetLcdFilter(CFX_GEModule::Get()->GetFontMgr()->GetFTLibrary(),
175                             FT_LCD_FILTER_DEFAULT);
176   error = FXFT_Render_Glyph(m_Face, anti_alias);
177   if (error)
178     return nullptr;
179   int bmwidth = FXFT_Get_Bitmap_Width(FXFT_Get_Glyph_Bitmap(m_Face));
180   int bmheight = FXFT_Get_Bitmap_Rows(FXFT_Get_Glyph_Bitmap(m_Face));
181   if (bmwidth > 2048 || bmheight > 2048)
182     return nullptr;
183   int dib_width = bmwidth;
184   CFX_GlyphBitmap* pGlyphBitmap = new CFX_GlyphBitmap;
185   pGlyphBitmap->m_Bitmap.Create(
186       dib_width, bmheight,
187       anti_alias == FXFT_RENDER_MODE_MONO ? FXDIB_1bppMask : FXDIB_8bppMask);
188   pGlyphBitmap->m_Left = FXFT_Get_Glyph_BitmapLeft(m_Face);
189   pGlyphBitmap->m_Top = FXFT_Get_Glyph_BitmapTop(m_Face);
190   int dest_pitch = pGlyphBitmap->m_Bitmap.GetPitch();
191   int src_pitch = FXFT_Get_Bitmap_Pitch(FXFT_Get_Glyph_Bitmap(m_Face));
192   uint8_t* pDestBuf = pGlyphBitmap->m_Bitmap.GetBuffer();
193   uint8_t* pSrcBuf =
194       (uint8_t*)FXFT_Get_Bitmap_Buffer(FXFT_Get_Glyph_Bitmap(m_Face));
195   if (anti_alias != FXFT_RENDER_MODE_MONO &&
196       FXFT_Get_Bitmap_PixelMode(FXFT_Get_Glyph_Bitmap(m_Face)) ==
197           FXFT_PIXEL_MODE_MONO) {
198     int bytes = anti_alias == FXFT_RENDER_MODE_LCD ? 3 : 1;
199     for (int i = 0; i < bmheight; i++) {
200       for (int n = 0; n < bmwidth; n++) {
201         uint8_t data =
202             (pSrcBuf[i * src_pitch + n / 8] & (0x80 >> (n % 8))) ? 255 : 0;
203         for (int b = 0; b < bytes; b++)
204           pDestBuf[i * dest_pitch + n * bytes + b] = data;
205       }
206     }
207   } else {
208     FXSYS_memset(pDestBuf, 0, dest_pitch * bmheight);
209     if (anti_alias == FXFT_RENDER_MODE_MONO &&
210         FXFT_Get_Bitmap_PixelMode(FXFT_Get_Glyph_Bitmap(m_Face)) ==
211             FXFT_PIXEL_MODE_MONO) {
212       int rowbytes =
213           FXSYS_abs(src_pitch) > dest_pitch ? dest_pitch : FXSYS_abs(src_pitch);
214       for (int row = 0; row < bmheight; row++) {
215         FXSYS_memcpy(pDestBuf + row * dest_pitch, pSrcBuf + row * src_pitch,
216                      rowbytes);
217       }
218     } else {
219       ContrastAdjust(pSrcBuf, pDestBuf, bmwidth, bmheight, src_pitch,
220                      dest_pitch);
221       GammaAdjust(pDestBuf, bmheight, dest_pitch,
222                   CFX_GEModule::Get()->GetTextGammaTable());
223     }
224   }
225   return pGlyphBitmap;
226 }
227 
LoadGlyphPath(const CFX_Font * pFont,uint32_t glyph_index,int dest_width)228 const CFX_PathData* CFX_FaceCache::LoadGlyphPath(const CFX_Font* pFont,
229                                                  uint32_t glyph_index,
230                                                  int dest_width) {
231   if (!m_Face || glyph_index == kInvalidGlyphIndex || dest_width < 0)
232     return nullptr;
233 
234   uint32_t key = glyph_index;
235   auto* pSubstFont = pFont->GetSubstFont();
236   if (pSubstFont) {
237     if (pSubstFont->m_Weight < 0 || pSubstFont->m_ItalicAngle < 0)
238       return nullptr;
239     uint32_t weight = static_cast<uint32_t>(pSubstFont->m_Weight);
240     uint32_t angle = static_cast<uint32_t>(pSubstFont->m_ItalicAngle);
241     uint32_t key_modifier = (weight / 16) << 15;
242     key_modifier += (angle / 2) << 21;
243     key_modifier += (static_cast<uint32_t>(dest_width) / 16) << 25;
244     if (pFont->IsVertical())
245       key_modifier += 1U << 31;
246     key += key_modifier;
247   }
248   auto it = m_PathMap.find(key);
249   if (it != m_PathMap.end())
250     return it->second.get();
251 
252   CFX_PathData* pGlyphPath = pFont->LoadGlyphPathImpl(glyph_index, dest_width);
253   m_PathMap[key] = std::unique_ptr<CFX_PathData>(pGlyphPath);
254   return pGlyphPath;
255 }
256 
LoadGlyphBitmap(const CFX_Font * pFont,uint32_t glyph_index,bool bFontStyle,const CFX_Matrix * pMatrix,int dest_width,int anti_alias,int & text_flags)257 const CFX_GlyphBitmap* CFX_FaceCache::LoadGlyphBitmap(const CFX_Font* pFont,
258                                                       uint32_t glyph_index,
259                                                       bool bFontStyle,
260                                                       const CFX_Matrix* pMatrix,
261                                                       int dest_width,
262                                                       int anti_alias,
263                                                       int& text_flags) {
264   if (glyph_index == kInvalidGlyphIndex)
265     return nullptr;
266 
267   _CFX_UniqueKeyGen keygen;
268   int nMatrixA = static_cast<int>(pMatrix->a * 10000);
269   int nMatrixB = static_cast<int>(pMatrix->b * 10000);
270   int nMatrixC = static_cast<int>(pMatrix->c * 10000);
271   int nMatrixD = static_cast<int>(pMatrix->d * 10000);
272 #if _FXM_PLATFORM_ != _FXM_PLATFORM_APPLE_
273   if (pFont->GetSubstFont()) {
274     keygen.Generate(9, nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width,
275                     anti_alias, pFont->GetSubstFont()->m_Weight,
276                     pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical());
277   } else {
278     keygen.Generate(6, nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width,
279                     anti_alias);
280   }
281 #else
282   if (text_flags & FXTEXT_NO_NATIVETEXT) {
283     if (pFont->GetSubstFont()) {
284       keygen.Generate(9, nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width,
285                       anti_alias, pFont->GetSubstFont()->m_Weight,
286                       pFont->GetSubstFont()->m_ItalicAngle,
287                       pFont->IsVertical());
288     } else {
289       keygen.Generate(6, nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width,
290                       anti_alias);
291     }
292   } else {
293     if (pFont->GetSubstFont()) {
294       keygen.Generate(10, nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width,
295                       anti_alias, pFont->GetSubstFont()->m_Weight,
296                       pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical(),
297                       3);
298     } else {
299       keygen.Generate(7, nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width,
300                       anti_alias, 3);
301     }
302   }
303 #endif
304   CFX_ByteString FaceGlyphsKey(keygen.m_Key, keygen.m_KeyLen);
305 #if _FXM_PLATFORM_ != _FXM_PLATFORM_APPLE_ || defined _SKIA_SUPPORT_ || \
306     defined _SKIA_SUPPORT_PATHS_
307   return LookUpGlyphBitmap(pFont, pMatrix, FaceGlyphsKey, glyph_index,
308                            bFontStyle, dest_width, anti_alias);
309 #else
310   if (text_flags & FXTEXT_NO_NATIVETEXT) {
311     return LookUpGlyphBitmap(pFont, pMatrix, FaceGlyphsKey, glyph_index,
312                              bFontStyle, dest_width, anti_alias);
313   }
314   CFX_GlyphBitmap* pGlyphBitmap;
315   auto it = m_SizeMap.find(FaceGlyphsKey);
316   if (it != m_SizeMap.end()) {
317     CFX_SizeGlyphCache* pSizeCache = it->second.get();
318     auto it2 = pSizeCache->m_GlyphMap.find(glyph_index);
319     if (it2 != pSizeCache->m_GlyphMap.end())
320       return it2->second;
321 
322     pGlyphBitmap = RenderGlyph_Nativetext(pFont, glyph_index, pMatrix,
323                                           dest_width, anti_alias);
324     if (pGlyphBitmap) {
325       pSizeCache->m_GlyphMap[glyph_index] = pGlyphBitmap;
326       return pGlyphBitmap;
327     }
328   } else {
329     pGlyphBitmap = RenderGlyph_Nativetext(pFont, glyph_index, pMatrix,
330                                           dest_width, anti_alias);
331     if (pGlyphBitmap) {
332       CFX_SizeGlyphCache* pSizeCache = new CFX_SizeGlyphCache;
333       m_SizeMap[FaceGlyphsKey] =
334           std::unique_ptr<CFX_SizeGlyphCache>(pSizeCache);
335       pSizeCache->m_GlyphMap[glyph_index] = pGlyphBitmap;
336       return pGlyphBitmap;
337     }
338   }
339   if (pFont->GetSubstFont()) {
340     keygen.Generate(9, nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width,
341                     anti_alias, pFont->GetSubstFont()->m_Weight,
342                     pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical());
343   } else {
344     keygen.Generate(6, nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width,
345                     anti_alias);
346   }
347   CFX_ByteString FaceGlyphsKey2(keygen.m_Key, keygen.m_KeyLen);
348   text_flags |= FXTEXT_NO_NATIVETEXT;
349   return LookUpGlyphBitmap(pFont, pMatrix, FaceGlyphsKey2, glyph_index,
350                            bFontStyle, dest_width, anti_alias);
351 #endif
352 }
353 
354 #if defined _SKIA_SUPPORT_ || defined _SKIA_SUPPORT_PATHS_
GetDeviceCache(const CFX_Font * pFont)355 CFX_TypeFace* CFX_FaceCache::GetDeviceCache(const CFX_Font* pFont) {
356   if (!m_pTypeface) {
357     m_pTypeface =
358         SkTypeface::MakeFromStream(
359             new SkMemoryStream(pFont->GetFontData(), pFont->GetSize()))
360             .release();
361   }
362   return m_pTypeface;
363 }
364 #endif
365 
366 #if _FXM_PLATFORM_ != _FXM_PLATFORM_APPLE_
InitPlatform()367 void CFX_FaceCache::InitPlatform() {}
368 #endif
369 
LookUpGlyphBitmap(const CFX_Font * pFont,const CFX_Matrix * pMatrix,const CFX_ByteString & FaceGlyphsKey,uint32_t glyph_index,bool bFontStyle,int dest_width,int anti_alias)370 CFX_GlyphBitmap* CFX_FaceCache::LookUpGlyphBitmap(
371     const CFX_Font* pFont,
372     const CFX_Matrix* pMatrix,
373     const CFX_ByteString& FaceGlyphsKey,
374     uint32_t glyph_index,
375     bool bFontStyle,
376     int dest_width,
377     int anti_alias) {
378   CFX_SizeGlyphCache* pSizeCache;
379   auto it = m_SizeMap.find(FaceGlyphsKey);
380   if (it == m_SizeMap.end()) {
381     pSizeCache = new CFX_SizeGlyphCache;
382     m_SizeMap[FaceGlyphsKey] = std::unique_ptr<CFX_SizeGlyphCache>(pSizeCache);
383   } else {
384     pSizeCache = it->second.get();
385   }
386   auto it2 = pSizeCache->m_GlyphMap.find(glyph_index);
387   if (it2 != pSizeCache->m_GlyphMap.end())
388     return it2->second;
389 
390   CFX_GlyphBitmap* pGlyphBitmap = RenderGlyph(pFont, glyph_index, bFontStyle,
391                                               pMatrix, dest_width, anti_alias);
392   pSizeCache->m_GlyphMap[glyph_index] = pGlyphBitmap;
393   return pGlyphBitmap;
394 }
395