1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "font_parser.h"
17
18 #include <codecvt>
19 #include <iomanip>
20 #include <securec.h>
21
22 #include "font_config.h"
23 #include "texgine/utils/exlog.h"
24
25 namespace OHOS {
26 namespace Rosen {
27 namespace TextEngine {
28 #define SUCCESSED 0
29 #define FAILED 1
30
31 #define FONT_CONFIG_FILE "/system/fonts/visibility_list.json"
32
33 #define HALF(a) ((a) / 2)
34
35 // "weight" and "italic" will assigned value 0 and 1, -1 used to exclude unassigned
FontDescriptor()36 FontParser::FontDescriptor::FontDescriptor(): path(""), postScriptName(""), fullName(""),
37 fontFamily(""), fontSubfamily(""), weight(-1), width(0), italic(-1), monoSpace(0), symbolic(0)
38 {
39 }
40
FontParser()41 FontParser::FontParser()
42 {
43 data_ = nullptr;
44 length_ = 0;
45 FontConfig fontConfig(FONT_CONFIG_FILE);
46 fontSet_ = fontConfig.GetFontSet();
47 }
48
ProcessCmapTable(const struct CmapTables * cmapTable,FontParser::FontDescriptor & fontDescriptor)49 void FontParser::ProcessCmapTable(const struct CmapTables* cmapTable, FontParser::FontDescriptor& fontDescriptor)
50 {
51 for (auto i = 0; i < cmapTable->numTables.Get(); ++i) {
52 const auto& record = cmapTable->encodingRecords[i];
53 FontParser::PlatformId platformId = static_cast<FontParser::PlatformId>(record.platformID.Get());
54 FontParser::EncodingIdWin encodingId = static_cast<FontParser::EncodingIdWin>(record.encodingID.Get());
55 if (platformId == FontParser::PlatformId::WINDOWS && encodingId == FontParser::EncodingIdWin::SYMBOL) {
56 fontDescriptor.symbolic = true;
57 break;
58 }
59 }
60 }
61
GetStringFromNameId(FontParser::NameId nameId,const std::string & nameString,FontParser::FontDescriptor & fontDescriptor)62 void FontParser::GetStringFromNameId(FontParser::NameId nameId, const std::string& nameString,
63 FontParser::FontDescriptor& fontDescriptor)
64 {
65 switch (nameId) {
66 case FontParser::NameId::FONT_FAMILY: {
67 if (fontDescriptor.fontFamily.size() == 0) {
68 fontDescriptor.fontFamily = nameString;
69 }
70 break;
71 }
72 case FontParser::NameId::FONT_SUBFAMILY: {
73 if (fontDescriptor.fontSubfamily.size() == 0) {
74 fontDescriptor.fontSubfamily = nameString;
75 }
76 break;
77 }
78 case FontParser::NameId::FULL_NAME: {
79 if (fontDescriptor.fullName.size() == 0) {
80 fontDescriptor.fullName = nameString;
81 }
82 break;
83 }
84 case FontParser::NameId::POSTSCRIPT_NAME: {
85 if (fontDescriptor.postScriptName.size() == 0) {
86 fontDescriptor.postScriptName = nameString;
87 }
88 break;
89 }
90 default: {
91 break;
92 }
93 }
94 }
95
ProcessNameTable(const struct NameTable * nameTable,FontParser::FontDescriptor & fontDescriptor) const96 int FontParser::ProcessNameTable(const struct NameTable* nameTable, FontParser::FontDescriptor& fontDescriptor) const
97 {
98 auto count = nameTable->count.Get();
99 auto storageOffset = nameTable->storageOffset.Get();
100 auto stringStorage = data_ + storageOffset;
101 for (int i = 0; i < count; ++i) {
102 if (nameTable->nameRecord[i].stringOffset.Get() == 0 || nameTable->nameRecord[i].length.Get() == 0) {
103 continue;
104 }
105 FontParser::NameId nameId = static_cast<FontParser::NameId>(nameTable->nameRecord[i].nameId.Get());
106 FontParser::PlatformId platformId =
107 static_cast<FontParser::PlatformId>(nameTable->nameRecord[i].platformId.Get());
108 auto len = nameTable->nameRecord[i].length.Get();
109 auto stringOffset = nameTable->nameRecord[i].stringOffset.Get();
110 const char* data = stringStorage + stringOffset;
111 if (platformId == FontParser::PlatformId::MACINTOSH) {
112 std::string nameString(data, len);
113 GetStringFromNameId(nameId, nameString, fontDescriptor);
114 } else if (platformId == FontParser::PlatformId::WINDOWS) {
115 char* buffer = new (std::nothrow) char[len]();
116 if (buffer == nullptr) {
117 return FAILED;
118 }
119 if (memcpy_s(buffer, len, data, len) != EOK) {
120 LOGSO_FUNC_LINE(ERROR) << "memcpy failed";
121 delete[] buffer;
122 return FAILED;
123 }
124 const char16_t* strPtr = reinterpret_cast<const char16_t*>(buffer);
125 const std::u16string u16str(strPtr, strPtr + HALF(len));
126 std::wstring_convert<std::codecvt_utf16<char16_t>, char16_t> converter;
127 const std::string name = converter.to_bytes(u16str);
128 std::vector<char> vec(name.begin(), name.end());
129 vec.erase(std::remove(vec.begin(), vec.end(), '\0'), vec.end());
130 std::string nameString = std::string(vec.begin(), vec.end());
131 GetStringFromNameId(nameId, nameString, fontDescriptor);
132 delete[] buffer;
133 }
134 }
135
136 return SUCCESSED;
137 }
138
ProcessPostTable(const struct PostTable * postTable,FontParser::FontDescriptor & fontDescriptor)139 void FontParser::ProcessPostTable(const struct PostTable* postTable, FontParser::FontDescriptor& fontDescriptor)
140 {
141 if (postTable->italicAngle.Get() != 0) {
142 fontDescriptor.italic = 1; // means support italics
143 } else {
144 fontDescriptor.italic = 0;
145 }
146 if (postTable->isFixedPitch.Get() == 1) {
147 fontDescriptor.monoSpace = true;
148 }
149 }
150
ParseCmapTable(sk_sp<SkTypeface> typeface,FontParser::FontDescriptor & fontDescriptor)151 int FontParser::ParseCmapTable(sk_sp<SkTypeface> typeface, FontParser::FontDescriptor& fontDescriptor)
152 {
153 auto tag = HB_TAG('c', 'm', 'a', 'p');
154 auto size = typeface->getTableSize(tag);
155 if (size <= 0) {
156 LOGSO_FUNC_LINE(ERROR) << "haven't cmap";
157 return FAILED;
158 }
159 std::unique_ptr<char[]> tableData = nullptr;
160 tableData = std::make_unique<char[]>(size);
161 auto retTableData = typeface->getTableData(tag, 0, size, tableData.get());
162 if (size != retTableData) {
163 LOGSO_FUNC_LINE(ERROR) <<"get table data failed size: " << size << ", ret: " << retTableData;
164 return FAILED;
165 }
166 hb_blob_t* hblob = nullptr;
167 hblob = hb_blob_create(
168 reinterpret_cast<const char*>(tableData.get()), size, HB_MEMORY_MODE_WRITABLE, tableData.get(), nullptr);
169 if (hblob == nullptr) {
170 LOGSO_FUNC_LINE(ERROR) << "hblob is nullptr";
171 return FAILED;
172 }
173 data_ = hb_blob_get_data(hblob, nullptr);
174 length_ = hb_blob_get_length(hblob);
175 auto parseCmap = std::make_shared<CmapTableParser>(data_, length_);
176 auto cmapTable = parseCmap->Parse(data_, length_);
177 ProcessCmapTable(cmapTable, fontDescriptor);
178
179 return SUCCESSED;
180 }
181
ParseNameTable(sk_sp<SkTypeface> typeface,FontParser::FontDescriptor & fontDescriptor)182 int FontParser::ParseNameTable(sk_sp<SkTypeface> typeface, FontParser::FontDescriptor& fontDescriptor)
183 {
184 auto tag = HB_TAG('n', 'a', 'm', 'e');
185 auto size = typeface->getTableSize(tag);
186 if (size <= 0) {
187 LOGSO_FUNC_LINE(ERROR) << "haven't name";
188 return FAILED;
189 }
190 std::unique_ptr<char[]> tableData = nullptr;
191 tableData = std::make_unique<char[]>(size);
192 auto retTableData = typeface->getTableData(tag, 0, size, tableData.get());
193 if (size != retTableData) {
194 LOGSO_FUNC_LINE(ERROR) <<"get table data failed size: " << size << ", ret: " << retTableData;
195 return FAILED;
196 }
197 hb_blob_t* hblob = nullptr;
198 hblob = hb_blob_create(
199 reinterpret_cast<const char*>(tableData.get()), size, HB_MEMORY_MODE_WRITABLE, tableData.get(), nullptr);
200 if (hblob == nullptr) {
201 LOGSO_FUNC_LINE(ERROR) << "hblob is nullptr";
202 return FAILED;
203 }
204 data_ = hb_blob_get_data(hblob, nullptr);
205 length_ = hb_blob_get_length(hblob);
206 auto parseName = std::make_shared<NameTableParser>(data_, length_);
207 auto nameTable = parseName->Parse(data_, length_);
208 int ret = ProcessNameTable(nameTable, fontDescriptor);
209 if (ret != SUCCESSED) {
210 LOGSO_FUNC_LINE(ERROR) << "process name table failed";
211 return FAILED;
212 }
213
214 return SUCCESSED;
215 }
216
ParsePostTable(sk_sp<SkTypeface> typeface,FontParser::FontDescriptor & fontDescriptor)217 int FontParser::ParsePostTable(sk_sp<SkTypeface> typeface, FontParser::FontDescriptor& fontDescriptor)
218 {
219 auto tag = HB_TAG('p', 'o', 's', 't');
220 auto size = typeface->getTableSize(tag);
221 if (size <= 0) {
222 LOGSO_FUNC_LINE(ERROR) << "haven't post";
223 return FAILED;
224 }
225 std::unique_ptr<char[]> tableData = nullptr;
226 tableData = std::make_unique<char[]>(size);
227 auto retTableData = typeface->getTableData(tag, 0, size, tableData.get());
228 if (size != retTableData) {
229 LOGSO_FUNC_LINE(ERROR) <<"get table data failed size: " << size << ", ret: " << retTableData;
230 return FAILED;
231 }
232 hb_blob_t* hblob = nullptr;
233 hblob = hb_blob_create(
234 reinterpret_cast<const char*>(tableData.get()), size, HB_MEMORY_MODE_WRITABLE, tableData.get(), nullptr);
235 if (hblob == nullptr) {
236 LOGSO_FUNC_LINE(ERROR) << "hblob is nullptr";
237 return FAILED;
238 }
239 data_ = hb_blob_get_data(hblob, nullptr);
240 length_ = hb_blob_get_length(hblob);
241 auto parsePost = std::make_shared<PostTableParser>(data_, length_);
242 auto postTable = parsePost->Parse(data_, length_);
243 ProcessPostTable(postTable, fontDescriptor);
244
245 return SUCCESSED;
246 }
247
ParseTable(sk_sp<SkTypeface> typeface,FontParser::FontDescriptor & fontDescriptor)248 int FontParser::ParseTable(sk_sp<SkTypeface> typeface, FontParser::FontDescriptor& fontDescriptor)
249 {
250 if (ParseCmapTable(typeface, fontDescriptor) != SUCCESSED) {
251 LOGSO_FUNC_LINE(ERROR) << "parse cmap failed";
252 return FAILED;
253 }
254 if (ParseNameTable(typeface, fontDescriptor) != SUCCESSED) {
255 LOGSO_FUNC_LINE(ERROR) << "parse name failed";
256 return FAILED;
257 }
258 if (ParsePostTable(typeface, fontDescriptor) != SUCCESSED) {
259 LOGSO_FUNC_LINE(ERROR) << "parse post failed";
260 return FAILED;
261 }
262
263 return SUCCESSED;
264 }
265
SetFontDescriptor()266 int FontParser::SetFontDescriptor()
267 {
268 for (unsigned int i = 0; i < fontSet_.size(); ++i) {
269 FontParser::FontDescriptor fontDescriptor;
270 fontDescriptor.path = fontSet_[i];
271 const char* path = fontSet_[i].c_str();
272 auto typeface = SkTypeface::MakeFromFile(path);
273 if (typeface == nullptr) {
274 LOGSO_FUNC_LINE(ERROR) << "typeface is nullptr, can not parse: " << fontDescriptor.path;
275 continue;
276 }
277 auto fontStyle = typeface->fontStyle();
278 fontDescriptor.weight = fontStyle.weight();
279 fontDescriptor.width = fontStyle.width();
280 if (ParseTable(typeface, fontDescriptor) != SUCCESSED) {
281 LOGSO_FUNC_LINE(ERROR) << "parse table failed";
282 return FAILED;
283 }
284 visibilityFonts_.emplace_back(fontDescriptor);
285 }
286
287 return SUCCESSED;
288 }
289
GetVisibilityFonts()290 std::vector<FontParser::FontDescriptor> FontParser::GetVisibilityFonts()
291 {
292 if (SetFontDescriptor() != SUCCESSED) {
293 LOGSO_FUNC_LINE(ERROR) << "set visibility font descriptor failed";
294 }
295
296 return visibilityFonts_;
297 }
298 } // namespace TextEngine
299 } // namespace Rosen
300 } // namespace OHOS
301