Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
cfx_folderfontinfo.cpp
Go to the documentation of this file.
1// Copyright 2016 The PDFium Authors
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 <iterator>
10#include <limits>
11#include <utility>
12
13#include "build/build_config.h"
14#include "core/fxcrt/fx_codepage.h"
15#include "core/fxcrt/fx_extension.h"
16#include "core/fxcrt/fx_folder.h"
17#include "core/fxcrt/fx_memory_wrappers.h"
18#include "core/fxcrt/fx_safe_types.h"
19#include "core/fxcrt/fx_system.h"
20#include "core/fxge/cfx_fontmapper.h"
21#include "core/fxge/fx_font.h"
22#include "third_party/base/containers/contains.h"
23
24namespace {
25
26const struct {
27 const char* m_pName;
28 const char* m_pSubstName;
29} Base14Substs[] = {
30 {"Courier", "Courier New"},
31 {"Courier-Bold", "Courier New Bold"},
32 {"Courier-BoldOblique", "Courier New Bold Italic"},
33 {"Courier-Oblique", "Courier New Italic"},
34 {"Helvetica", "Arial"},
35 {"Helvetica-Bold", "Arial Bold"},
36 {"Helvetica-BoldOblique", "Arial Bold Italic"},
37 {"Helvetica-Oblique", "Arial Italic"},
38 {"Times-Roman", "Times New Roman"},
39 {"Times-Bold", "Times New Roman Bold"},
40 {"Times-BoldItalic", "Times New Roman Bold Italic"},
41 {"Times-Italic", "Times New Roman Italic"},
42};
43
44// Used with std::unique_ptr to automatically call fclose().
45struct FxFileCloser {
46 inline void operator()(FILE* h) const {
47 if (h)
48 fclose(h);
49 }
50};
51
52bool FindFamilyNameMatch(ByteStringView family_name,
53 const ByteString& installed_font_name) {
54 absl::optional<size_t> result = installed_font_name.Find(family_name, 0);
55 if (!result.has_value())
56 return false;
57
58 size_t next_index = result.value() + family_name.GetLength();
59 // Rule out the case that |family_name| is a substring of
60 // |installed_font_name| but their family names are actually different words.
61 // For example: "Univers" and "Universal" are not a match because they have
62 // different family names, but "Univers" and "Univers Bold" are a match.
63 if (installed_font_name.IsValidIndex(next_index) &&
64 FXSYS_IsLowerASCII(installed_font_name[next_index])) {
65 return false;
66 }
67
68 return true;
69}
70
71ByteString ReadStringFromFile(FILE* pFile, uint32_t size) {
72 ByteString result;
73 {
74 // Span's lifetime must end before ReleaseBuffer() below.
75 pdfium::span<char> buffer = result.GetBuffer(size);
76 if (!fread(buffer.data(), size, 1, pFile))
77 return ByteString();
78 }
79 result.ReleaseBuffer(size);
80 return result;
81}
82
83ByteString LoadTableFromTT(FILE* pFile,
84 const uint8_t* pTables,
85 uint32_t nTables,
86 uint32_t tag,
87 FX_FILESIZE fileSize) {
88 for (uint32_t i = 0; i < nTables; i++) {
89 const uint8_t* p = pTables + i * 16;
90 if (FXSYS_UINT32_GET_MSBFIRST(p) == tag) {
91 uint32_t offset = FXSYS_UINT32_GET_MSBFIRST(p + 8);
92 uint32_t size = FXSYS_UINT32_GET_MSBFIRST(p + 12);
93 if (offset > std::numeric_limits<uint32_t>::max() - size ||
94 static_cast<FX_FILESIZE>(offset + size) > fileSize ||
95 fseek(pFile, offset, SEEK_SET) < 0) {
96 return ByteString();
97 }
98 return ReadStringFromFile(pFile, size);
99 }
100 }
101 return ByteString();
102}
103
104uint32_t GetCharset(FX_Charset charset) {
105 switch (charset) {
109 return CHARSET_FLAG_GB;
111 return CHARSET_FLAG_BIG5;
113 return CHARSET_FLAG_KOREAN;
115 return CHARSET_FLAG_SYMBOL;
117 return CHARSET_FLAG_ANSI;
118 default:
119 break;
120 }
121 return 0;
122}
123
124int32_t GetSimilarValue(int weight,
125 bool bItalic,
126 int pitch_family,
127 uint32_t style,
128 bool bMatchName,
129 size_t familyNameLength,
130 size_t bsNameLength) {
131 int32_t iSimilarValue = 0;
132 if (bMatchName && (familyNameLength == bsNameLength))
133 iSimilarValue += 4;
134 if (FontStyleIsForceBold(style) == (weight > 400))
135 iSimilarValue += 16;
136 if (FontStyleIsItalic(style) == bItalic)
137 iSimilarValue += 16;
138 if (FontStyleIsSerif(style) == FontFamilyIsRoman(pitch_family))
139 iSimilarValue += 16;
140 if (FontStyleIsScript(style) == FontFamilyIsScript(pitch_family))
141 iSimilarValue += 8;
143 iSimilarValue += 8;
144 return iSimilarValue;
145}
146
147} // namespace
148
150
152
153void CFX_FolderFontInfo::AddPath(const ByteString& path) {
154 m_PathList.push_back(path);
155}
156
158 m_pMapper = pMapper;
159 for (const auto& path : m_PathList)
160 ScanPath(path);
161 return true;
162}
163
164void CFX_FolderFontInfo::ScanPath(const ByteString& path) {
165 std::unique_ptr<FX_Folder> handle = FX_Folder::OpenFolder(path);
166 if (!handle)
167 return;
168
169 ByteString filename;
170 bool bFolder;
171 while (handle->GetNextFile(&filename, &bFolder)) {
172 if (bFolder) {
173 if (filename == "." || filename == "..")
174 continue;
175 } else {
176 ByteString ext = filename.Last(4);
177 ext.MakeLower();
178 if (ext != ".ttf" && ext != ".ttc" && ext != ".otf")
179 continue;
180 }
181
182 ByteString fullpath = path;
183#if BUILDFLAG(IS_WIN)
184 fullpath += "\\";
185#else
186 fullpath += "/";
187#endif
188
189 fullpath += filename;
190 bFolder ? ScanPath(fullpath) : ScanFile(fullpath);
191 }
192}
193
194void CFX_FolderFontInfo::ScanFile(const ByteString& path) {
195 std::unique_ptr<FILE, FxFileCloser> pFile(fopen(path.c_str(), "rb"));
196 if (!pFile)
197 return;
198
199 fseek(pFile.get(), 0, SEEK_END);
200
201 FX_FILESIZE filesize = ftell(pFile.get());
202 uint8_t buffer[16];
203 fseek(pFile.get(), 0, SEEK_SET);
204
205 size_t readCnt = fread(buffer, 12, 1, pFile.get());
206 if (readCnt != 1)
207 return;
208
209 if (FXSYS_UINT32_GET_MSBFIRST(buffer) != kTableTTCF) {
210 ReportFace(path, pFile.get(), filesize, 0);
211 return;
212 }
213
214 uint32_t nFaces = FXSYS_UINT32_GET_MSBFIRST(buffer + 8);
215 FX_SAFE_SIZE_T safe_face_bytes = nFaces;
216 safe_face_bytes *= 4;
217 if (!safe_face_bytes.IsValid())
218 return;
219
220 const size_t face_bytes = safe_face_bytes.ValueOrDie();
221 std::unique_ptr<uint8_t, FxFreeDeleter> offsets(
222 FX_Alloc(uint8_t, face_bytes));
223 readCnt = fread(offsets.get(), 1, face_bytes, pFile.get());
224 if (readCnt != face_bytes)
225 return;
226
227 auto offsets_span = pdfium::make_span(offsets.get(), face_bytes);
228 for (uint32_t i = 0; i < nFaces; i++) {
229 ReportFace(path, pFile.get(), filesize,
230 FXSYS_UINT32_GET_MSBFIRST(&offsets_span[i * 4]));
231 }
232}
233
234void CFX_FolderFontInfo::ReportFace(const ByteString& path,
235 FILE* pFile,
236 FX_FILESIZE filesize,
237 uint32_t offset) {
238 char buffer[16];
239 if (fseek(pFile, offset, SEEK_SET) < 0 || !fread(buffer, 12, 1, pFile))
240 return;
241
242 uint32_t nTables = FXSYS_UINT16_GET_MSBFIRST(buffer + 4);
243 ByteString tables = ReadStringFromFile(pFile, nTables * 16);
244 if (tables.IsEmpty())
245 return;
246
247 static constexpr uint32_t kNameTag =
248 CFX_FontMapper::MakeTag('n', 'a', 'm', 'e');
249 ByteString names =
250 LoadTableFromTT(pFile, tables.raw_str(), nTables, kNameTag, filesize);
251 if (names.IsEmpty())
252 return;
253
254 ByteString facename = GetNameFromTT(names.raw_span(), 1);
255 if (facename.IsEmpty())
256 return;
257
258 ByteString style = GetNameFromTT(names.raw_span(), 2);
259 if (style != "Regular")
260 facename += " " + style;
261
262 if (pdfium::Contains(m_FontList, facename))
263 return;
264
265 auto pInfo =
266 std::make_unique<FontFaceInfo>(path, facename, tables, offset, filesize);
267 static constexpr uint32_t kOs2Tag =
268 CFX_FontMapper::MakeTag('O', 'S', '/', '2');
269 ByteString os2 =
270 LoadTableFromTT(pFile, tables.raw_str(), nTables, kOs2Tag, filesize);
271 if (os2.GetLength() >= 86) {
272 const uint8_t* p = os2.raw_str() + 78;
273 uint32_t codepages = FXSYS_UINT32_GET_MSBFIRST(p);
274 if (codepages & (1U << 17)) {
275 m_pMapper->AddInstalledFont(facename, FX_Charset::kShiftJIS);
276 pInfo->m_Charsets |= CHARSET_FLAG_SHIFTJIS;
277 }
278 if (codepages & (1U << 18)) {
279 m_pMapper->AddInstalledFont(facename, FX_Charset::kChineseSimplified);
280 pInfo->m_Charsets |= CHARSET_FLAG_GB;
281 }
282 if (codepages & (1U << 20)) {
283 m_pMapper->AddInstalledFont(facename, FX_Charset::kChineseTraditional);
284 pInfo->m_Charsets |= CHARSET_FLAG_BIG5;
285 }
286 if ((codepages & (1U << 19)) || (codepages & (1U << 21))) {
287 m_pMapper->AddInstalledFont(facename, FX_Charset::kHangul);
288 pInfo->m_Charsets |= CHARSET_FLAG_KOREAN;
289 }
290 if (codepages & (1U << 31)) {
291 m_pMapper->AddInstalledFont(facename, FX_Charset::kSymbol);
292 pInfo->m_Charsets |= CHARSET_FLAG_SYMBOL;
293 }
294 }
295 m_pMapper->AddInstalledFont(facename, FX_Charset::kANSI);
296 pInfo->m_Charsets |= CHARSET_FLAG_ANSI;
297 pInfo->m_Styles = 0;
298 if (style.Contains("Bold"))
299 pInfo->m_Styles |= FXFONT_FORCE_BOLD;
300 if (style.Contains("Italic") || style.Contains("Oblique"))
301 pInfo->m_Styles |= FXFONT_ITALIC;
302 if (facename.Contains("Serif"))
303 pInfo->m_Styles |= FXFONT_SERIF;
304
305 m_FontList[facename] = std::move(pInfo);
306}
307
308void* CFX_FolderFontInfo::GetSubstFont(const ByteString& face) {
309 for (size_t iBaseFont = 0; iBaseFont < std::size(Base14Substs); iBaseFont++) {
310 if (face == Base14Substs[iBaseFont].m_pName)
311 return GetFont(Base14Substs[iBaseFont].m_pSubstName);
312 }
313 return nullptr;
314}
315
316void* CFX_FolderFontInfo::FindFont(int weight,
317 bool bItalic,
318 FX_Charset charset,
319 int pitch_family,
320 const ByteString& family,
321 bool bMatchName) {
322 FontFaceInfo* pFind = nullptr;
323
324 ByteStringView bsFamily = family.AsStringView();
325 uint32_t charset_flag = GetCharset(charset);
326 int32_t iBestSimilar = 0;
327 for (const auto& it : m_FontList) {
328 const ByteString& bsName = it.first;
329 FontFaceInfo* pFont = it.second.get();
330 if (!(pFont->m_Charsets & charset_flag) && charset != FX_Charset::kDefault)
331 continue;
332
333 if (bMatchName && !FindFamilyNameMatch(bsFamily, bsName))
334 continue;
335
336 int32_t iSimilarValue =
337 GetSimilarValue(weight, bItalic, pitch_family, pFont->m_Styles,
338 bMatchName, bsFamily.GetLength(), bsName.GetLength());
339 if (iSimilarValue > iBestSimilar) {
340 iBestSimilar = iSimilarValue;
341 pFind = pFont;
342 }
343 }
344
345 if (pFind) {
346 return pFind;
347 }
348
349 if (charset == FX_Charset::kANSI && FontFamilyIsFixedPitch(pitch_family)) {
350 auto* courier_new = GetFont("Courier New");
351 if (courier_new)
352 return courier_new;
353 }
354
355 return nullptr;
356}
357
358void* CFX_FolderFontInfo::MapFont(int weight,
359 bool bItalic,
360 FX_Charset charset,
361 int pitch_family,
362 const ByteString& face) {
363 return nullptr;
364}
365
366void* CFX_FolderFontInfo::GetFont(const ByteString& face) {
367 auto it = m_FontList.find(face);
368 return it != m_FontList.end() ? it->second.get() : nullptr;
369}
370
372 uint32_t table,
373 pdfium::span<uint8_t> buffer) {
374 if (!hFont)
375 return 0;
376
377 const FontFaceInfo* pFont = static_cast<FontFaceInfo*>(hFont);
378 uint32_t datasize = 0;
379 uint32_t offset = 0;
380 if (table == 0) {
381 datasize = pFont->m_FontOffset ? 0 : pFont->m_FileSize;
382 } else if (table == kTableTTCF) {
383 datasize = pFont->m_FontOffset ? pFont->m_FileSize : 0;
384 } else {
385 size_t nTables = pFont->m_FontTables.GetLength() / 16;
386 for (size_t i = 0; i < nTables; i++) {
387 const uint8_t* p = pFont->m_FontTables.raw_str() + i * 16;
388 if (FXSYS_UINT32_GET_MSBFIRST(p) == table) {
389 offset = FXSYS_UINT32_GET_MSBFIRST(p + 8);
390 datasize = FXSYS_UINT32_GET_MSBFIRST(p + 12);
391 }
392 }
393 }
394
395 if (!datasize || buffer.size() < datasize)
396 return datasize;
397
398 std::unique_ptr<FILE, FxFileCloser> pFile(
399 fopen(pFont->m_FilePath.c_str(), "rb"));
400 if (!pFile)
401 return 0;
402
403 if (fseek(pFile.get(), offset, SEEK_SET) < 0 ||
404 fread(buffer.data(), datasize, 1, pFile.get()) != 1) {
405 return 0;
406 }
407 return datasize;
408}
409
410void CFX_FolderFontInfo::DeleteFont(void* hFont) {}
411
412bool CFX_FolderFontInfo::GetFaceName(void* hFont, ByteString* name) {
413 if (!hFont)
414 return false;
415 *name = static_cast<FontFaceInfo*>(hFont)->m_FaceName;
416 return true;
417}
418
419bool CFX_FolderFontInfo::GetFontCharset(void* hFont, FX_Charset* charset) {
420 return false;
421}
422
424 ByteString faceName,
425 ByteString fontTables,
426 uint32_t fontOffset,
427 uint32_t fileSize)
431 m_FontOffset(fontOffset),
432 m_FileSize(fileSize) {}
#define CHARSET_FLAG_SHIFTJIS
#define CHARSET_FLAG_ANSI
#define CHARSET_FLAG_BIG5
#define CHARSET_FLAG_SYMBOL
#define CHARSET_FLAG_GB
#define CHARSET_FLAG_KOREAN
FontFaceInfo(ByteString filePath, ByteString faceName, ByteString fontTables, uint32_t fontOffset, uint32_t fileSize)
~CFX_FolderFontInfo() override
void ScanFile(const ByteString &path)
bool GetFontCharset(void *hFont, FX_Charset *charset) override
size_t GetFontData(void *hFont, uint32_t table, pdfium::span< uint8_t > buffer) override
void * GetSubstFont(const ByteString &face)
void DeleteFont(void *hFont) override
void * FindFont(int weight, bool bItalic, FX_Charset charset, int pitch_family, const ByteString &family, bool bMatchName)
void ReportFace(const ByteString &path, FILE *pFile, FX_FILESIZE filesize, uint32_t offset)
bool GetFaceName(void *hFont, ByteString *name) override
void ScanPath(const ByteString &path)
void * MapFont(int weight, bool bItalic, FX_Charset charset, int pitch_family, const ByteString &face) override
void AddPath(const ByteString &path)
void * GetFont(const ByteString &face) override
bool EnumFontList(CFX_FontMapper *pMapper) override
static constexpr uint32_t MakeTag(char c1, char c2, char c3, char c4)
ByteString & operator+=(const ByteString &str)
const uint8_t * raw_str() const
Definition bytestring.h:80
bool operator==(const char *ptr) const
ByteString & operator+=(const char *str)
bool IsEmpty() const
Definition bytestring.h:119
bool operator!=(const char *ptr) const
Definition bytestring.h:130
FX_Charset
Definition fx_codepage.h:70
@ kChineseTraditional
@ kChineseSimplified
bool FontFamilyIsFixedPitch(uint32_t family)
Definition fx_font.h:84
bool FontStyleIsSerif(uint32_t style)
Definition fx_font.h:77
bool FontStyleIsFixedPitch(uint32_t style)
Definition fx_font.h:65
#define FXFONT_SERIF
Definition fx_font.h:29
bool FontFamilyIsScript(int32_t family)
Definition fx_font.h:90
#define FXFONT_ITALIC
Definition fx_font.h:33
bool FontFamilyIsRoman(uint32_t family)
Definition fx_font.h:87
bool FontStyleIsItalic(uint32_t style)
Definition fx_font.h:62
#define FXFONT_FORCE_BOLD
Definition fx_font.h:36
bool FontStyleIsScript(uint32_t style)
Definition fx_font.h:80
bool FontStyleIsForceBold(uint32_t style)
Definition fx_font.h:59
#define FX_FILESIZE
Definition fx_types.h:19
ByteString operator+(const char *str1, const ByteString &str2)
Definition bytestring.h:282
constexpr uint32_t kTableTTCF