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
FPDF_ReadStringFromFile(FILE * pFile,uint32_t size)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
FPDF_LoadTableFromTT(FILE * pFile,const uint8_t * pTables,uint32_t nTables,uint32_t tag,uint32_t fileSize)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
GetCharset(int charset)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
GetSimilarValue(int weight,bool bItalic,int pitch_family,uint32_t style)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
CFX_FolderFontInfo()114 CFX_FolderFontInfo::CFX_FolderFontInfo() {}
115
~CFX_FolderFontInfo()116 CFX_FolderFontInfo::~CFX_FolderFontInfo() {}
117
AddPath(const ByteString & path)118 void CFX_FolderFontInfo::AddPath(const ByteString& path) {
119 m_PathList.push_back(path);
120 }
121
EnumFontList(CFX_FontMapper * pMapper)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
ScanPath(const ByteString & path)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
ScanFile(const ByteString & path)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
ReportFace(const ByteString & path,FILE * pFile,uint32_t filesize,uint32_t offset)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
GetSubstFont(const ByteString & face)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
FindFont(int weight,bool bItalic,int charset,int pitch_family,const char * family,bool bMatchName)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
MapFont(int weight,bool bItalic,int charset,int pitch_family,const char * family)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
MapFontByUnicode(uint32_t dwUnicode,int weight,bool bItalic,int pitch_family)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
GetFont(const char * face)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
GetFontData(void * hFont,uint32_t table,uint8_t * buffer,uint32_t size)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
DeleteFont(void * hFont)374 void CFX_FolderFontInfo::DeleteFont(void* hFont) {}
375
GetFaceName(void * hFont,ByteString * name)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
GetFontCharset(void * hFont,int * charset)383 bool CFX_FolderFontInfo::GetFontCharset(void* hFont, int* charset) {
384 return false;
385 }
386
FontFaceInfo(ByteString filePath,ByteString faceName,ByteString fontTables,uint32_t fontOffset,uint32_t fileSize)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