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 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 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 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 88 CFX_FaceCache::~CFX_FaceCache() { 89 #if defined _SKIA_SUPPORT_ || _SKIA_SUPPORT_PATHS_ 90 SkSafeUnref(m_pTypeface); 91 #endif 92 } 93 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 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 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_ 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_ 367 void CFX_FaceCache::InitPlatform() {} 368 #endif 369 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