Home | History | Annotate | Download | only in fxge
      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 
     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 
     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 
     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 
     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 
    114 CFX_FolderFontInfo::CFX_FolderFontInfo() {}
    115 
    116 CFX_FolderFontInfo::~CFX_FolderFontInfo() {}
    117 
    118 void CFX_FolderFontInfo::AddPath(const ByteString& path) {
    119   m_PathList.push_back(path);
    120 }
    121 
    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 
    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 
    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 
    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 
    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 
    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 
    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
    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 
    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 
    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 
    374 void CFX_FolderFontInfo::DeleteFont(void* hFont) {}
    375 
    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 
    383 bool CFX_FolderFontInfo::GetFontCharset(void* hFont, int* charset) {
    384   return false;
    385 }
    386 
    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