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_folderfontinfo.h" 8 9 #include <limits> 10 #include <utility> 11 12 #include "core/fxcrt/fx_codepage.h" 13 #include "core/fxcrt/fx_stream.h" 14 #include "core/fxge/cfx_fontmapper.h" 15 #include "core/fxge/fx_font.h" 16 #include "third_party/base/ptr_util.h" 17 #include "third_party/base/stl_util.h" 18 19 #define CHARSET_FLAG_ANSI (1 << 0) 20 #define CHARSET_FLAG_SYMBOL (1 << 1) 21 #define CHARSET_FLAG_SHIFTJIS (1 << 2) 22 #define CHARSET_FLAG_BIG5 (1 << 3) 23 #define CHARSET_FLAG_GB (1 << 4) 24 #define CHARSET_FLAG_KOREAN (1 << 5) 25 26 namespace { 27 28 const struct { 29 const char* m_pName; 30 const char* m_pSubstName; 31 } Base14Substs[] = { 32 {"Courier", "Courier New"}, 33 {"Courier-Bold", "Courier New Bold"}, 34 {"Courier-BoldOblique", "Courier New Bold Italic"}, 35 {"Courier-Oblique", "Courier New Italic"}, 36 {"Helvetica", "Arial"}, 37 {"Helvetica-Bold", "Arial Bold"}, 38 {"Helvetica-BoldOblique", "Arial Bold Italic"}, 39 {"Helvetica-Oblique", "Arial Italic"}, 40 {"Times-Roman", "Times New Roman"}, 41 {"Times-Bold", "Times New Roman Bold"}, 42 {"Times-BoldItalic", "Times New Roman Bold Italic"}, 43 {"Times-Italic", "Times New Roman Italic"}, 44 }; 45 46 ByteString FPDF_ReadStringFromFile(FILE* pFile, uint32_t size) { 47 ByteString buffer; 48 if (!fread(buffer.GetBuffer(size), size, 1, pFile)) 49 return ByteString(); 50 buffer.ReleaseBuffer(size); 51 return buffer; 52 } 53 54 ByteString FPDF_LoadTableFromTT(FILE* pFile, 55 const uint8_t* pTables, 56 uint32_t nTables, 57 uint32_t tag, 58 uint32_t fileSize) { 59 for (uint32_t i = 0; i < nTables; i++) { 60 const uint8_t* p = pTables + i * 16; 61 if (GET_TT_LONG(p) == tag) { 62 uint32_t offset = GET_TT_LONG(p + 8); 63 uint32_t size = GET_TT_LONG(p + 12); 64 if (offset > std::numeric_limits<uint32_t>::max() - size || 65 offset + size > fileSize || fseek(pFile, offset, SEEK_SET) < 0) { 66 return ByteString(); 67 } 68 return FPDF_ReadStringFromFile(pFile, size); 69 } 70 } 71 return ByteString(); 72 } 73 74 uint32_t GetCharset(int charset) { 75 switch (charset) { 76 case FX_CHARSET_ShiftJIS: 77 return CHARSET_FLAG_SHIFTJIS; 78 case FX_CHARSET_ChineseSimplified: 79 return CHARSET_FLAG_GB; 80 case FX_CHARSET_ChineseTraditional: 81 return CHARSET_FLAG_BIG5; 82 case FX_CHARSET_Hangul: 83 return CHARSET_FLAG_KOREAN; 84 case FX_CHARSET_Symbol: 85 return CHARSET_FLAG_SYMBOL; 86 case FX_CHARSET_ANSI: 87 return CHARSET_FLAG_ANSI; 88 default: 89 break; 90 } 91 return 0; 92 } 93 94 int32_t GetSimilarValue(int weight, 95 bool bItalic, 96 int pitch_family, 97 uint32_t style) { 98 int32_t iSimilarValue = 0; 99 if (FontStyleIsBold(style) == (weight > 400)) 100 iSimilarValue += 16; 101 if (FontStyleIsItalic(style) == bItalic) 102 iSimilarValue += 16; 103 if (FontStyleIsSerif(style) == FontFamilyIsRoman(pitch_family)) 104 iSimilarValue += 16; 105 if (FontStyleIsScript(style) == FontFamilyIsScript(pitch_family)) 106 iSimilarValue += 8; 107 if (FontStyleIsFixedPitch(style) == FontFamilyIsFixedPitch(pitch_family)) 108 iSimilarValue += 8; 109 return iSimilarValue; 110 } 111 112 } // namespace 113 114 CFX_FolderFontInfo::CFX_FolderFontInfo() {} 115 116 CFX_FolderFontInfo::~CFX_FolderFontInfo() {} 117 118 void CFX_FolderFontInfo::AddPath(const ByteString& path) { 119 m_PathList.push_back(path); 120 } 121 122 bool CFX_FolderFontInfo::EnumFontList(CFX_FontMapper* pMapper) { 123 m_pMapper = pMapper; 124 for (const auto& path : m_PathList) 125 ScanPath(path); 126 return true; 127 } 128 129 void CFX_FolderFontInfo::ScanPath(const ByteString& path) { 130 FX_FileHandle* handle = FX_OpenFolder(path.c_str()); 131 if (!handle) 132 return; 133 134 ByteString filename; 135 bool bFolder; 136 while (FX_GetNextFile(handle, &filename, &bFolder)) { 137 if (bFolder) { 138 if (filename == "." || filename == "..") 139 continue; 140 } else { 141 ByteString ext = filename.Right(4); 142 ext.MakeUpper(); 143 if (ext != ".TTF" && ext != ".OTF" && ext != ".TTC") 144 continue; 145 } 146 147 ByteString fullpath = path; 148 #if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_ 149 fullpath += "\\"; 150 #else 151 fullpath += "/"; 152 #endif 153 154 fullpath += filename; 155 bFolder ? ScanPath(fullpath) : ScanFile(fullpath); 156 } 157 FX_CloseFolder(handle); 158 } 159 160 void CFX_FolderFontInfo::ScanFile(const ByteString& path) { 161 FILE* pFile = fopen(path.c_str(), "rb"); 162 if (!pFile) 163 return; 164 165 fseek(pFile, 0, SEEK_END); 166 167 uint32_t filesize = ftell(pFile); 168 uint8_t buffer[16]; 169 fseek(pFile, 0, SEEK_SET); 170 171 size_t readCnt = fread(buffer, 12, 1, pFile); 172 if (readCnt != 1) { 173 fclose(pFile); 174 return; 175 } 176 177 if (GET_TT_LONG(buffer) == kTableTTCF) { 178 uint32_t nFaces = GET_TT_LONG(buffer + 8); 179 if (nFaces > std::numeric_limits<uint32_t>::max() / 4) { 180 fclose(pFile); 181 return; 182 } 183 uint32_t face_bytes = nFaces * 4; 184 uint8_t* offsets = FX_Alloc(uint8_t, face_bytes); 185 readCnt = fread(offsets, 1, face_bytes, pFile); 186 if (readCnt != face_bytes) { 187 FX_Free(offsets); 188 fclose(pFile); 189 return; 190 } 191 for (uint32_t i = 0; i < nFaces; i++) { 192 uint8_t* p = offsets + i * 4; 193 ReportFace(path, pFile, filesize, GET_TT_LONG(p)); 194 } 195 FX_Free(offsets); 196 } else { 197 ReportFace(path, pFile, filesize, 0); 198 } 199 fclose(pFile); 200 } 201 202 void CFX_FolderFontInfo::ReportFace(const ByteString& path, 203 FILE* pFile, 204 uint32_t filesize, 205 uint32_t offset) { 206 char buffer[16]; 207 if (fseek(pFile, offset, SEEK_SET) < 0 || !fread(buffer, 12, 1, pFile)) 208 return; 209 210 uint32_t nTables = GET_TT_SHORT(buffer + 4); 211 ByteString tables = FPDF_ReadStringFromFile(pFile, nTables * 16); 212 if (tables.IsEmpty()) 213 return; 214 215 ByteString names = FPDF_LoadTableFromTT(pFile, tables.raw_str(), nTables, 216 0x6e616d65, filesize); 217 if (names.IsEmpty()) 218 return; 219 220 ByteString facename = GetNameFromTT(names.raw_str(), names.GetLength(), 1); 221 if (facename.IsEmpty()) 222 return; 223 224 ByteString style = GetNameFromTT(names.raw_str(), names.GetLength(), 2); 225 if (style != "Regular") 226 facename += " " + style; 227 228 if (pdfium::ContainsKey(m_FontList, facename)) 229 return; 230 231 auto pInfo = pdfium::MakeUnique<FontFaceInfo>(path, facename, tables, offset, 232 filesize); 233 ByteString os2 = FPDF_LoadTableFromTT(pFile, tables.raw_str(), nTables, 234 0x4f532f32, filesize); 235 if (os2.GetLength() >= 86) { 236 const uint8_t* p = os2.raw_str() + 78; 237 uint32_t codepages = GET_TT_LONG(p); 238 if (codepages & (1 << 17)) { 239 m_pMapper->AddInstalledFont(facename, FX_CHARSET_ShiftJIS); 240 pInfo->m_Charsets |= CHARSET_FLAG_SHIFTJIS; 241 } 242 if (codepages & (1 << 18)) { 243 m_pMapper->AddInstalledFont(facename, FX_CHARSET_ChineseSimplified); 244 pInfo->m_Charsets |= CHARSET_FLAG_GB; 245 } 246 if (codepages & (1 << 20)) { 247 m_pMapper->AddInstalledFont(facename, FX_CHARSET_ChineseTraditional); 248 pInfo->m_Charsets |= CHARSET_FLAG_BIG5; 249 } 250 if ((codepages & (1 << 19)) || (codepages & (1 << 21))) { 251 m_pMapper->AddInstalledFont(facename, FX_CHARSET_Hangul); 252 pInfo->m_Charsets |= CHARSET_FLAG_KOREAN; 253 } 254 if (codepages & (1 << 31)) { 255 m_pMapper->AddInstalledFont(facename, FX_CHARSET_Symbol); 256 pInfo->m_Charsets |= CHARSET_FLAG_SYMBOL; 257 } 258 } 259 m_pMapper->AddInstalledFont(facename, FX_CHARSET_ANSI); 260 pInfo->m_Charsets |= CHARSET_FLAG_ANSI; 261 pInfo->m_Styles = 0; 262 if (style.Contains("Bold")) 263 pInfo->m_Styles |= FXFONT_BOLD; 264 if (style.Contains("Italic") || style.Contains("Oblique")) 265 pInfo->m_Styles |= FXFONT_ITALIC; 266 if (facename.Contains("Serif")) 267 pInfo->m_Styles |= FXFONT_SERIF; 268 269 m_FontList[facename] = std::move(pInfo); 270 } 271 272 void* CFX_FolderFontInfo::GetSubstFont(const ByteString& face) { 273 for (size_t iBaseFont = 0; iBaseFont < FX_ArraySize(Base14Substs); 274 iBaseFont++) { 275 if (face == Base14Substs[iBaseFont].m_pName) 276 return GetFont(Base14Substs[iBaseFont].m_pSubstName); 277 } 278 return nullptr; 279 } 280 281 void* CFX_FolderFontInfo::FindFont(int weight, 282 bool bItalic, 283 int charset, 284 int pitch_family, 285 const char* family, 286 bool bMatchName) { 287 FontFaceInfo* pFind = nullptr; 288 if (charset == FX_CHARSET_ANSI && FontFamilyIsFixedPitch(pitch_family)) 289 return GetFont("Courier New"); 290 291 uint32_t charset_flag = GetCharset(charset); 292 int32_t iBestSimilar = 0; 293 for (const auto& it : m_FontList) { 294 const ByteString& bsName = it.first; 295 FontFaceInfo* pFont = it.second.get(); 296 if (!(pFont->m_Charsets & charset_flag) && charset != FX_CHARSET_Default) 297 continue; 298 299 if (bMatchName && !bsName.Contains(family)) 300 continue; 301 302 int32_t iSimilarValue = 303 GetSimilarValue(weight, bItalic, pitch_family, pFont->m_Styles); 304 if (iSimilarValue > iBestSimilar) { 305 iBestSimilar = iSimilarValue; 306 pFind = pFont; 307 } 308 } 309 return pFind; 310 } 311 312 void* CFX_FolderFontInfo::MapFont(int weight, 313 bool bItalic, 314 int charset, 315 int pitch_family, 316 const char* family) { 317 return nullptr; 318 } 319 320 #ifdef PDF_ENABLE_XFA 321 void* CFX_FolderFontInfo::MapFontByUnicode(uint32_t dwUnicode, 322 int weight, 323 bool bItalic, 324 int pitch_family) { 325 return nullptr; 326 } 327 #endif // PDF_ENABLE_XFA 328 329 void* CFX_FolderFontInfo::GetFont(const char* face) { 330 auto it = m_FontList.find(face); 331 return it != m_FontList.end() ? it->second.get() : nullptr; 332 } 333 334 uint32_t CFX_FolderFontInfo::GetFontData(void* hFont, 335 uint32_t table, 336 uint8_t* buffer, 337 uint32_t size) { 338 if (!hFont) 339 return 0; 340 341 const FontFaceInfo* pFont = static_cast<FontFaceInfo*>(hFont); 342 uint32_t datasize = 0; 343 uint32_t offset = 0; 344 if (table == 0) { 345 datasize = pFont->m_FontOffset ? 0 : pFont->m_FileSize; 346 } else if (table == kTableTTCF) { 347 datasize = pFont->m_FontOffset ? pFont->m_FileSize : 0; 348 } else { 349 uint32_t nTables = pFont->m_FontTables.GetLength() / 16; 350 for (uint32_t i = 0; i < nTables; i++) { 351 const uint8_t* p = pFont->m_FontTables.raw_str() + i * 16; 352 if (GET_TT_LONG(p) == table) { 353 offset = GET_TT_LONG(p + 8); 354 datasize = GET_TT_LONG(p + 12); 355 } 356 } 357 } 358 359 if (!datasize || size < datasize) 360 return datasize; 361 362 FILE* pFile = fopen(pFont->m_FilePath.c_str(), "rb"); 363 if (!pFile) 364 return 0; 365 366 if (fseek(pFile, offset, SEEK_SET) < 0 || 367 fread(buffer, datasize, 1, pFile) != 1) { 368 datasize = 0; 369 } 370 fclose(pFile); 371 return datasize; 372 } 373 374 void CFX_FolderFontInfo::DeleteFont(void* hFont) {} 375 376 bool CFX_FolderFontInfo::GetFaceName(void* hFont, ByteString* name) { 377 if (!hFont) 378 return false; 379 *name = static_cast<FontFaceInfo*>(hFont)->m_FaceName; 380 return true; 381 } 382 383 bool CFX_FolderFontInfo::GetFontCharset(void* hFont, int* charset) { 384 return false; 385 } 386 387 CFX_FolderFontInfo::FontFaceInfo::FontFaceInfo(ByteString filePath, 388 ByteString faceName, 389 ByteString fontTables, 390 uint32_t fontOffset, 391 uint32_t fileSize) 392 : m_FilePath(filePath), 393 m_FaceName(faceName), 394 m_FontTables(fontTables), 395 m_FontOffset(fontOffset), 396 m_FileSize(fileSize), 397 m_Styles(0), 398 m_Charsets(0) {} 399