• 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_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