1 // Copyright 2014 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 <array>
8 #include <iterator>
9 #include <memory>
10 #include <utility>
11
12 #include "build/build_config.h"
13 #include "core/fxcrt/check.h"
14 #include "core/fxcrt/compiler_specific.h"
15 #include "core/fxcrt/fx_codepage.h"
16 #include "core/fxcrt/stl_util.h"
17 #include "core/fxge/cfx_folderfontinfo.h"
18 #include "core/fxge/cfx_fontmgr.h"
19 #include "core/fxge/cfx_gemodule.h"
20 #include "core/fxge/fx_font.h"
21 #include "core/fxge/systemfontinfo_iface.h"
22
23 #if !BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CHROMEOS) && !defined(OS_ASMJS)
24 #error "Included on the wrong platform"
25 #endif
26
27 namespace {
28
29 enum JpFontFamilyRowIndex : uint8_t {
30 kJpFontPGothic,
31 kJpFontGothic,
32 kJpFontPMincho,
33 kJpFontMincho,
34 };
35
36 constexpr size_t kJpFontFamilyColumnCount = 5;
37 using JpFontFamilyRow = std::array<const char*, kJpFontFamilyColumnCount>;
38 constexpr auto kJpFontTable = fxcrt::ToArray<const JpFontFamilyRow>({
39 {{"MS PGothic", "TakaoPGothic", "VL PGothic", "IPAPGothic", "VL Gothic"}},
40 {{"MS Gothic", "TakaoGothic", "VL Gothic", "IPAGothic", "Kochi Gothic"}},
41 {{"MS PMincho", "TakaoPMincho", "IPAPMincho", "VL Gothic", "Kochi Mincho"}},
42 {{"MS Mincho", "TakaoMincho", "IPAMincho", "VL Gothic", "Kochi Mincho"}},
43 });
44
45 const char* const kGbFontList[] = {
46 "AR PL UMing CN Light",
47 "WenQuanYi Micro Hei",
48 "AR PL UKai CN",
49 };
50
51 const char* const kB5FontList[] = {
52 "AR PL UMing TW Light",
53 "WenQuanYi Micro Hei",
54 "AR PL UKai TW",
55 };
56
57 const char* const kHGFontList[] = {
58 "UnDotum",
59 };
60
GetJapanesePreference(const ByteString & face,int weight,int pitch_family)61 JpFontFamilyRowIndex GetJapanesePreference(const ByteString& face,
62 int weight,
63 int pitch_family) {
64 if (face.Contains("Gothic") ||
65 face.Contains("\x83\x53\x83\x56\x83\x62\x83\x4e")) {
66 if (face.Contains("PGothic") ||
67 face.Contains("\x82\x6f\x83\x53\x83\x56\x83\x62\x83\x4e")) {
68 return kJpFontPGothic;
69 }
70 return kJpFontGothic;
71 }
72 if (face.Contains("Mincho") || face.Contains("\x96\xbe\x92\xa9")) {
73 if (face.Contains("PMincho") || face.Contains("\x82\x6f\x96\xbe\x92\xa9")) {
74 return kJpFontPMincho;
75 }
76 return kJpFontMincho;
77 }
78 if (!FontFamilyIsRoman(pitch_family) && weight > 400)
79 return kJpFontPGothic;
80
81 return kJpFontPMincho;
82 }
83
84 class CFX_LinuxFontInfo final : public CFX_FolderFontInfo {
85 public:
86 CFX_LinuxFontInfo() = default;
87 ~CFX_LinuxFontInfo() override = default;
88
89 // CFX_FolderFontInfo:
90 void* MapFont(int weight,
91 bool bItalic,
92 FX_Charset charset,
93 int pitch_family,
94 const ByteString& face) override;
95
96 bool ParseFontCfg(const char** pUserPaths);
97 };
98
MapFont(int weight,bool bItalic,FX_Charset charset,int pitch_family,const ByteString & face)99 void* CFX_LinuxFontInfo::MapFont(int weight,
100 bool bItalic,
101 FX_Charset charset,
102 int pitch_family,
103 const ByteString& face) {
104 void* font = GetSubstFont(face);
105 if (font)
106 return font;
107
108 bool bCJK = true;
109 switch (charset) {
110 case FX_Charset::kShiftJIS: {
111 JpFontFamilyRowIndex index =
112 GetJapanesePreference(face, weight, pitch_family);
113 for (const char* name : kJpFontTable[index]) {
114 auto it = m_FontList.find(name);
115 if (it != m_FontList.end())
116 return it->second.get();
117 }
118 break;
119 }
120 case FX_Charset::kChineseSimplified: {
121 for (const char* name : kGbFontList) {
122 auto it = m_FontList.find(name);
123 if (it != m_FontList.end())
124 return it->second.get();
125 }
126 break;
127 }
128 case FX_Charset::kChineseTraditional: {
129 for (const char* name : kB5FontList) {
130 auto it = m_FontList.find(name);
131 if (it != m_FontList.end())
132 return it->second.get();
133 }
134 break;
135 }
136 case FX_Charset::kHangul: {
137 for (const char* name : kHGFontList) {
138 auto it = m_FontList.find(name);
139 if (it != m_FontList.end())
140 return it->second.get();
141 }
142 break;
143 }
144 default:
145 bCJK = false;
146 break;
147 }
148 return FindFont(weight, bItalic, charset, pitch_family, face, !bCJK);
149 }
150
ParseFontCfg(const char ** pUserPaths)151 bool CFX_LinuxFontInfo::ParseFontCfg(const char** pUserPaths) {
152 if (!pUserPaths)
153 return false;
154
155 // SAFETY: nullptr-terminated array required from caller.
156 UNSAFE_BUFFERS({
157 for (const char** pPath = pUserPaths; *pPath; ++pPath) {
158 AddPath(*pPath);
159 }
160 });
161 return true;
162 }
163
164 } // namespace
165
166 class CLinuxPlatform : public CFX_GEModule::PlatformIface {
167 public:
168 CLinuxPlatform() = default;
169 ~CLinuxPlatform() override = default;
170
Init()171 void Init() override {}
172
CreateDefaultSystemFontInfo()173 std::unique_ptr<SystemFontInfoIface> CreateDefaultSystemFontInfo() override {
174 auto pInfo = std::make_unique<CFX_LinuxFontInfo>();
175 if (!pInfo->ParseFontCfg(CFX_GEModule::Get()->GetUserFontPaths())) {
176 pInfo->AddPath("/usr/share/fonts");
177 pInfo->AddPath("/usr/share/X11/fonts/Type1");
178 pInfo->AddPath("/usr/share/X11/fonts/TTF");
179 pInfo->AddPath("/usr/local/share/fonts");
180 }
181 return pInfo;
182 }
183 };
184
185 // static
186 std::unique_ptr<CFX_GEModule::PlatformIface>
Create()187 CFX_GEModule::PlatformIface::Create() {
188 return std::make_unique<CLinuxPlatform>();
189 }
190