Chromium Code Reviews| Index: core/fxge/ge/cfx_folderfontinfo.cpp |
| diff --git a/core/fxge/ge/cfx_folderfontinfo.cpp b/core/fxge/ge/cfx_folderfontinfo.cpp |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..bc8f2c3efeef93d4e4e6e5a4b491d00a318f26ce |
| --- /dev/null |
| +++ b/core/fxge/ge/cfx_folderfontinfo.cpp |
| @@ -0,0 +1,389 @@ |
| +// Copyright 2016 PDFium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com |
| + |
| +#include <algorithm> |
|
Lei Zhang
2016/07/26 23:19:56
Include What You Use (IWYU) goes both ways. Includ
npm_g
2016/07/27 17:02:19
Done.
|
| +#include <limits> |
| +#include <utility> |
| +#include <vector> |
| + |
| +#include "core/fxge/include/fx_font.h" |
| + |
| +#include "core/fxge/fontdata/chromefontdata/chromefontdata.h" |
| +#include "core/fxge/include/fx_freetype.h" |
| +#include "core/fxge/include/fx_ge.h" |
| +#include "third_party/base/stl_util.h" |
| + |
| +namespace { |
| + |
| +const struct { |
| + const FX_CHAR* m_pName; |
| + const FX_CHAR* m_pSubstName; |
| +} Base14Substs[] = { |
| + {"Courier", "Courier New"}, |
| + {"Courier-Bold", "Courier New Bold"}, |
| + {"Courier-BoldOblique", "Courier New Bold Italic"}, |
| + {"Courier-Oblique", "Courier New Italic"}, |
| + {"Helvetica", "Arial"}, |
| + {"Helvetica-Bold", "Arial Bold"}, |
| + {"Helvetica-BoldOblique", "Arial Bold Italic"}, |
| + {"Helvetica-Oblique", "Arial Italic"}, |
| + {"Times-Roman", "Times New Roman"}, |
| + {"Times-Bold", "Times New Roman Bold"}, |
| + {"Times-BoldItalic", "Times New Roman Bold Italic"}, |
| + {"Times-Italic", "Times New Roman Italic"}, |
| +}; |
| + |
| +const uint32_t kTableTTCF = FXDWORD_GET_MSBFIRST("ttcf"); |
| + |
| +CFX_ByteString FPDF_ReadStringFromFile(FXSYS_FILE* pFile, uint32_t size) { |
| + CFX_ByteString buffer; |
| + if (!FXSYS_fread(buffer.GetBuffer(size), size, 1, pFile)) { |
|
dsinclair
2016/07/27 14:17:39
nit: no {}'s on single line body.
npm_g
2016/07/27 17:02:19
Done.
|
| + return CFX_ByteString(); |
| + } |
| + buffer.ReleaseBuffer(size); |
| + return buffer; |
| +} |
| + |
| +CFX_ByteString FPDF_LoadTableFromTT(FXSYS_FILE* pFile, |
| + const uint8_t* pTables, |
| + uint32_t nTables, |
| + uint32_t tag) { |
| + for (uint32_t i = 0; i < nTables; i++) { |
| + const uint8_t* p = pTables + i * 16; |
| + if (GET_TT_LONG(p) == tag) { |
| + uint32_t offset = GET_TT_LONG(p + 8); |
| + uint32_t size = GET_TT_LONG(p + 12); |
| + FXSYS_fseek(pFile, offset, FXSYS_SEEK_SET); |
| + return FPDF_ReadStringFromFile(pFile, size); |
| + } |
| + } |
| + return CFX_ByteString(); |
| +} |
| + |
| +uint32_t GetCharset(int charset) { |
| + switch (charset) { |
| + case FXFONT_SHIFTJIS_CHARSET: |
| + return CHARSET_FLAG_SHIFTJIS; |
| + case FXFONT_GB2312_CHARSET: |
| + return CHARSET_FLAG_GB; |
| + case FXFONT_CHINESEBIG5_CHARSET: |
| + return CHARSET_FLAG_BIG5; |
| + case FXFONT_HANGEUL_CHARSET: |
| + return CHARSET_FLAG_KOREAN; |
| + case FXFONT_SYMBOL_CHARSET: |
| + return CHARSET_FLAG_SYMBOL; |
| + case FXFONT_ANSI_CHARSET: |
| + return CHARSET_FLAG_ANSI; |
| + default: |
| + break; |
| + } |
| + return 0; |
| +} |
| + |
| +int32_t GetSimilarValue(int weight, |
| + FX_BOOL bItalic, |
| + int pitch_family, |
| + uint32_t style) { |
| + int32_t iSimilarValue = 0; |
| + if (!!(style & FXFONT_BOLD) == (weight > 400)) { |
| + iSimilarValue += 16; |
| + } |
|
dsinclair
2016/07/27 14:17:39
nit: ditto
npm_g
2016/07/27 17:02:19
Done.
|
| + if (!!(style & FXFONT_ITALIC) == bItalic) { |
| + iSimilarValue += 16; |
| + } |
| + if (!!(style & FXFONT_SERIF) == !!(pitch_family & FXFONT_FF_ROMAN)) { |
| + iSimilarValue += 16; |
| + } |
| + if (!!(style & FXFONT_SCRIPT) == !!(pitch_family & FXFONT_FF_SCRIPT)) { |
| + iSimilarValue += 8; |
| + } |
| + if (!!(style & FXFONT_FIXED_PITCH) == |
| + !!(pitch_family & FXFONT_FF_FIXEDPITCH)) { |
|
dsinclair
2016/07/27 14:17:39
This one can keep the {}'s as the if () is split o
npm_g
2016/07/27 17:02:19
Done.
|
| + iSimilarValue += 8; |
| + } |
| + return iSimilarValue; |
| +} |
| + |
| +} // namespace |
| + |
| +CFX_FolderFontInfo::CFX_FolderFontInfo() {} |
| + |
| +CFX_FolderFontInfo::~CFX_FolderFontInfo() { |
| + for (const auto& pair : m_FontList) { |
| + delete pair.second; |
| + } |
| +} |
| + |
| +void CFX_FolderFontInfo::AddPath(const CFX_ByteStringC& path) { |
| + m_PathList.push_back(CFX_ByteString(path)); |
| +} |
| + |
| +FX_BOOL CFX_FolderFontInfo::EnumFontList(CFX_FontMapper* pMapper) { |
| + m_pMapper = pMapper; |
| + for (const auto& path : m_PathList) |
| + ScanPath(path); |
| + return TRUE; |
| +} |
| +void CFX_FolderFontInfo::ScanPath(const CFX_ByteString& path) { |
|
dsinclair
2016/07/27 14:17:39
nit: blank line before.
npm_g
2016/07/27 17:02:19
Done.
|
| + void* handle = FX_OpenFolder(path.c_str()); |
| + if (!handle) |
| + return; |
| + |
| + CFX_ByteString filename; |
| + FX_BOOL bFolder; |
| + while (FX_GetNextFile(handle, filename, bFolder)) { |
| + if (bFolder) { |
| + if (filename == "." || filename == "..") |
| + continue; |
| + } else { |
| + CFX_ByteString ext = filename.Right(4); |
| + ext.MakeUpper(); |
| + if (ext != ".TTF" && ext != ".OTF" && ext != ".TTC") |
| + continue; |
| + } |
| + |
| + CFX_ByteString fullpath = path; |
| +#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ |
| + fullpath += "\\"; |
| +#else |
| + fullpath += "/"; |
| +#endif |
| + |
| + fullpath += filename; |
| + bFolder ? ScanPath(fullpath) : ScanFile(fullpath); |
| + } |
| + FX_CloseFolder(handle); |
| +} |
| + |
| +void CFX_FolderFontInfo::ScanFile(const CFX_ByteString& path) { |
| + FXSYS_FILE* pFile = FXSYS_fopen(path.c_str(), "rb"); |
| + if (!pFile) |
| + return; |
| + |
| + FXSYS_fseek(pFile, 0, FXSYS_SEEK_END); |
| + |
| + uint32_t filesize = FXSYS_ftell(pFile); |
| + uint8_t buffer[16]; |
| + FXSYS_fseek(pFile, 0, FXSYS_SEEK_SET); |
| + |
| + size_t readCnt = FXSYS_fread(buffer, 12, 1, pFile); |
| + if (readCnt != 1) { |
| + FXSYS_fclose(pFile); |
| + return; |
| + } |
| + |
| + if (GET_TT_LONG(buffer) == kTableTTCF) { |
| + uint32_t nFaces = GET_TT_LONG(buffer + 8); |
| + if (nFaces > std::numeric_limits<uint32_t>::max() / 4) { |
| + FXSYS_fclose(pFile); |
| + return; |
| + } |
| + uint32_t face_bytes = nFaces * 4; |
| + uint8_t* offsets = FX_Alloc(uint8_t, face_bytes); |
| + readCnt = FXSYS_fread(offsets, 1, face_bytes, pFile); |
| + if (readCnt != face_bytes) { |
| + FX_Free(offsets); |
| + FXSYS_fclose(pFile); |
| + return; |
| + } |
| + for (uint32_t i = 0; i < nFaces; i++) { |
| + uint8_t* p = offsets + i * 4; |
| + ReportFace(path, pFile, filesize, GET_TT_LONG(p)); |
| + } |
| + FX_Free(offsets); |
| + } else { |
| + ReportFace(path, pFile, filesize, 0); |
| + } |
| + FXSYS_fclose(pFile); |
| +} |
| +void CFX_FolderFontInfo::ReportFace(const CFX_ByteString& path, |
|
dsinclair
2016/07/27 14:17:39
ditto
npm_g
2016/07/27 17:02:19
Done.
|
| + FXSYS_FILE* pFile, |
| + uint32_t filesize, |
| + uint32_t offset) { |
| + FXSYS_fseek(pFile, offset, FXSYS_SEEK_SET); |
| + char buffer[16]; |
| + if (!FXSYS_fread(buffer, 12, 1, pFile)) |
| + return; |
| + |
| + uint32_t nTables = GET_TT_SHORT(buffer + 4); |
| + CFX_ByteString tables = FPDF_ReadStringFromFile(pFile, nTables * 16); |
| + if (tables.IsEmpty()) |
| + return; |
| + |
| + CFX_ByteString names = |
| + FPDF_LoadTableFromTT(pFile, tables.raw_str(), nTables, 0x6e616d65); |
| + if (names.IsEmpty()) |
| + return; |
| + |
| + CFX_ByteString facename = |
| + GetNameFromTT(names.raw_str(), names.GetLength(), 1); |
| + if (facename.IsEmpty()) |
| + return; |
| + |
| + CFX_ByteString style = GetNameFromTT(names.raw_str(), names.GetLength(), 2); |
| + if (style != "Regular") |
| + facename += " " + style; |
| + |
| + if (pdfium::ContainsKey(m_FontList, facename)) |
| + return; |
| + |
| + CFX_FontFaceInfo* pInfo = |
| + new CFX_FontFaceInfo(path, facename, tables, offset, filesize); |
| + CFX_ByteString os2 = |
| + FPDF_LoadTableFromTT(pFile, tables.raw_str(), nTables, 0x4f532f32); |
| + if (os2.GetLength() >= 86) { |
| + const uint8_t* p = os2.raw_str() + 78; |
| + uint32_t codepages = GET_TT_LONG(p); |
| + if (codepages & (1 << 17)) { |
| + m_pMapper->AddInstalledFont(facename, FXFONT_SHIFTJIS_CHARSET); |
| + pInfo->m_Charsets |= CHARSET_FLAG_SHIFTJIS; |
| + } |
| + if (codepages & (1 << 18)) { |
| + m_pMapper->AddInstalledFont(facename, FXFONT_GB2312_CHARSET); |
| + pInfo->m_Charsets |= CHARSET_FLAG_GB; |
| + } |
| + if (codepages & (1 << 20)) { |
| + m_pMapper->AddInstalledFont(facename, FXFONT_CHINESEBIG5_CHARSET); |
| + pInfo->m_Charsets |= CHARSET_FLAG_BIG5; |
| + } |
| + if ((codepages & (1 << 19)) || (codepages & (1 << 21))) { |
| + m_pMapper->AddInstalledFont(facename, FXFONT_HANGEUL_CHARSET); |
| + pInfo->m_Charsets |= CHARSET_FLAG_KOREAN; |
| + } |
| + if (codepages & (1 << 31)) { |
| + m_pMapper->AddInstalledFont(facename, FXFONT_SYMBOL_CHARSET); |
| + pInfo->m_Charsets |= CHARSET_FLAG_SYMBOL; |
| + } |
| + } |
| + m_pMapper->AddInstalledFont(facename, FXFONT_ANSI_CHARSET); |
| + pInfo->m_Charsets |= CHARSET_FLAG_ANSI; |
| + pInfo->m_Styles = 0; |
| + if (style.Find("Bold") > -1) |
| + pInfo->m_Styles |= FXFONT_BOLD; |
| + if (style.Find("Italic") > -1 || style.Find("Oblique") > -1) |
| + pInfo->m_Styles |= FXFONT_ITALIC; |
| + if (facename.Find("Serif") > -1) |
| + pInfo->m_Styles |= FXFONT_SERIF; |
| + |
| + m_FontList[facename] = pInfo; |
| +} |
| + |
| +void* CFX_FolderFontInfo::GetSubstFont(const CFX_ByteString& face) { |
| + for (size_t iBaseFont = 0; iBaseFont < FX_ArraySize(Base14Substs); |
| + iBaseFont++) { |
| + if (face == Base14Substs[iBaseFont].m_pName) |
| + return GetFont(Base14Substs[iBaseFont].m_pSubstName); |
| + } |
| + return nullptr; |
| +} |
| + |
| +void* CFX_FolderFontInfo::FindFont(int weight, |
| + FX_BOOL bItalic, |
| + int charset, |
| + int pitch_family, |
| + const FX_CHAR* family, |
| + FX_BOOL bMatchName) { |
| + CFX_FontFaceInfo* pFind = nullptr; |
| + if (charset == FXFONT_ANSI_CHARSET && (pitch_family & FXFONT_FF_FIXEDPITCH)) { |
| + return GetFont("Courier New"); |
|
dsinclair
2016/07/27 14:17:39
nit: {}'s
npm_g
2016/07/27 17:02:19
Done.
|
| + } |
| + uint32_t charset_flag = GetCharset(charset); |
| + int32_t iBestSimilar = 0; |
| + for (const auto& it : m_FontList) { |
| + const CFX_ByteString& bsName = it.first; |
| + CFX_FontFaceInfo* pFont = it.second; |
| + if (!(pFont->m_Charsets & charset_flag) && |
| + charset != FXFONT_DEFAULT_CHARSET) { |
| + continue; |
| + } |
| + int32_t index = bsName.Find(family); |
| + if (bMatchName && index < 0) { |
| + continue; |
| + } |
|
dsinclair
2016/07/27 14:17:39
ditto
npm_g
2016/07/27 17:02:19
Done.
|
| + int32_t iSimilarValue = |
| + GetSimilarValue(weight, bItalic, pitch_family, pFont->m_Styles); |
| + if (iSimilarValue > iBestSimilar) { |
| + iBestSimilar = iSimilarValue; |
| + pFind = pFont; |
| + } |
| + } |
| + return pFind; |
| +} |
| +void* CFX_FolderFontInfo::MapFont(int weight, |
|
dsinclair
2016/07/27 14:17:39
nit: blank before
npm_g
2016/07/27 17:02:19
Done.
|
| + FX_BOOL bItalic, |
| + int charset, |
| + int pitch_family, |
| + const FX_CHAR* family, |
| + int& iExact) { |
| + return nullptr; |
| +} |
| + |
| +#ifdef PDF_ENABLE_XFA |
| +void* CFX_FolderFontInfo::MapFontByUnicode(uint32_t dwUnicode, |
| + int weight, |
| + FX_BOOL bItalic, |
| + int pitch_family) { |
| + return nullptr; |
| +} |
| +#endif // PDF_ENABLE_XFA |
| + |
| +void* CFX_FolderFontInfo::GetFont(const FX_CHAR* face) { |
| + auto it = m_FontList.find(face); |
| + return it != m_FontList.end() ? it->second : nullptr; |
| +} |
| + |
| +uint32_t CFX_FolderFontInfo::GetFontData(void* hFont, |
| + uint32_t table, |
| + uint8_t* buffer, |
| + uint32_t size) { |
| + if (!hFont) |
| + return 0; |
| + |
| + const CFX_FontFaceInfo* pFont = static_cast<CFX_FontFaceInfo*>(hFont); |
| + uint32_t datasize = 0; |
| + uint32_t offset = 0; |
| + if (table == 0) { |
| + datasize = pFont->m_FontOffset ? 0 : pFont->m_FileSize; |
| + } else if (table == kTableTTCF) { |
| + datasize = pFont->m_FontOffset ? pFont->m_FileSize : 0; |
| + } else { |
| + uint32_t nTables = pFont->m_FontTables.GetLength() / 16; |
| + for (uint32_t i = 0; i < nTables; i++) { |
| + const uint8_t* p = pFont->m_FontTables.raw_str() + i * 16; |
| + if (GET_TT_LONG(p) == table) { |
| + offset = GET_TT_LONG(p + 8); |
| + datasize = GET_TT_LONG(p + 12); |
| + } |
| + } |
| + } |
| + |
| + if (!datasize || size < datasize) |
| + return datasize; |
| + |
| + FXSYS_FILE* pFile = FXSYS_fopen(pFont->m_FilePath.c_str(), "rb"); |
| + if (!pFile) |
| + return 0; |
| + |
| + if (FXSYS_fseek(pFile, offset, FXSYS_SEEK_SET) < 0 || |
| + FXSYS_fread(buffer, datasize, 1, pFile) != 1) { |
| + datasize = 0; |
| + } |
| + FXSYS_fclose(pFile); |
| + return datasize; |
| +} |
| + |
| +void CFX_FolderFontInfo::DeleteFont(void* hFont) {} |
| +FX_BOOL CFX_FolderFontInfo::GetFaceName(void* hFont, CFX_ByteString& name) { |
| + if (!hFont) { |
| + return FALSE; |
| + } |
|
dsinclair
2016/07/27 14:17:39
nit: {}'s
|
| + CFX_FontFaceInfo* pFont = (CFX_FontFaceInfo*)hFont; |
| + name = pFont->m_FaceName; |
| + return TRUE; |
| +} |
| +FX_BOOL CFX_FolderFontInfo::GetFontCharset(void* hFont, int& charset) { |
|
dsinclair
2016/07/27 14:17:39
nit: blank before
|
| + return FALSE; |
| +} |