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