1 /*
2 * Copyright (c) 2024 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 "js_typeface.h"
17
18 #include "native_value.h"
19
20 #include "js_drawing_utils.h"
21 #ifdef ROSEN_OHOS
22 #include "tool_napi/js_tool.h"
23 #endif
24
25 namespace OHOS::Rosen {
26 namespace Drawing {
27 thread_local napi_ref JsTypeface::constructor_ = nullptr;
28 const std::string CLASS_NAME = "Typeface";
29 const std::string G_SYSTEM_FONT_DIR = "/system/fonts";
Init(napi_env env,napi_value exportObj)30 napi_value JsTypeface::Init(napi_env env, napi_value exportObj)
31 {
32 napi_property_descriptor properties[] = {
33 DECLARE_NAPI_FUNCTION("getFamilyName", JsTypeface::GetFamilyName),
34 DECLARE_NAPI_STATIC_FUNCTION("makeFromFile", JsTypeface::MakeFromFile),
35 DECLARE_NAPI_STATIC_FUNCTION("makeFromRawFile", JsTypeface::MakeFromRawFile),
36 };
37
38 napi_value constructor = nullptr;
39 napi_status status = napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor, nullptr,
40 sizeof(properties) / sizeof(properties[0]), properties, &constructor);
41 if (status != napi_ok) {
42 ROSEN_LOGE("Failed to define Typeface class");
43 return nullptr;
44 }
45
46 status = napi_create_reference(env, constructor, 1, &constructor_);
47 if (status != napi_ok) {
48 ROSEN_LOGE("Failed to create reference of constructor");
49 return nullptr;
50 }
51
52 status = napi_set_named_property(env, exportObj, CLASS_NAME.c_str(), constructor);
53 if (status != napi_ok) {
54 ROSEN_LOGE("Failed to set constructor");
55 return nullptr;
56 }
57
58 return exportObj;
59 }
60
Constructor(napi_env env,napi_callback_info info)61 napi_value JsTypeface::Constructor(napi_env env, napi_callback_info info)
62 {
63 size_t argCount = 0;
64 napi_value jsThis = nullptr;
65 napi_status status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr);
66 if (status != napi_ok) {
67 ROSEN_LOGE("failed to napi_get_cb_info");
68 return nullptr;
69 }
70
71 JsTypeface *jsTypeface = new JsTypeface(JsTypeface::GetZhCnTypeface());
72
73 status = napi_wrap(env, jsThis, jsTypeface, JsTypeface::Destructor, nullptr, nullptr);
74 if (status != napi_ok) {
75 delete jsTypeface;
76 ROSEN_LOGE("Failed to wrap native instance");
77 return nullptr;
78 }
79 return jsThis;
80 }
81
Destructor(napi_env env,void * nativeObject,void * finalize)82 void JsTypeface::Destructor(napi_env env, void *nativeObject, void *finalize)
83 {
84 (void)finalize;
85 if (nativeObject != nullptr) {
86 JsTypeface *napi = reinterpret_cast<JsTypeface *>(nativeObject);
87 delete napi;
88 }
89 }
90
~JsTypeface()91 JsTypeface::~JsTypeface()
92 {
93 m_typeface = nullptr;
94 }
95
CreateJsTypeface(napi_env env,const std::shared_ptr<Typeface> typeface)96 napi_value JsTypeface::CreateJsTypeface(napi_env env, const std::shared_ptr<Typeface> typeface)
97 {
98 napi_value constructor = nullptr;
99 napi_status status = napi_get_reference_value(env, constructor_, &constructor);
100 if (status != napi_ok) {
101 ROSEN_LOGE("JsTypeface::CreateJsTypeface get reference value failed!");
102 return nullptr;
103 }
104 napi_value result = nullptr;
105 napi_create_object(env, &result);
106 if (result == nullptr) {
107 ROSEN_LOGE("JsTypeface::CreateJsTypeface create object failed!");
108 return nullptr;
109 }
110 JsTypeface* jsTypeface = new JsTypeface(typeface);
111 status = napi_wrap(env, result, jsTypeface, JsTypeface::Destructor, nullptr, nullptr);
112 if (status != napi_ok) {
113 delete jsTypeface;
114 ROSEN_LOGE("JsTypeface::CreateJsTypeface failed to wrap native instance");
115 return nullptr;
116 }
117 napi_property_descriptor resultFuncs[] = {
118 DECLARE_NAPI_FUNCTION("getFamilyName", JsTypeface::GetFamilyName),
119 };
120 napi_define_properties(env, result, sizeof(resultFuncs) / sizeof(resultFuncs[0]), resultFuncs);
121 return result;
122 }
123
LoadZhCnTypeface()124 std::shared_ptr<Typeface> LoadZhCnTypeface()
125 {
126 std::shared_ptr<Typeface> typeface = Typeface::MakeFromFile(JsTypeface::ZH_CN_TTF);
127 if (typeface == nullptr) {
128 typeface = Typeface::MakeDefault();
129 }
130 return typeface;
131 }
132
GetZhCnTypeface()133 std::shared_ptr<Typeface> JsTypeface::GetZhCnTypeface()
134 {
135 static std::shared_ptr<Typeface> zhCnTypeface = LoadZhCnTypeface();
136 return zhCnTypeface;
137 }
138
GetTypeface()139 std::shared_ptr<Typeface> JsTypeface::GetTypeface()
140 {
141 return m_typeface;
142 }
143
GetFamilyName(napi_env env,napi_callback_info info)144 napi_value JsTypeface::GetFamilyName(napi_env env, napi_callback_info info)
145 {
146 JsTypeface* me = CheckParamsAndGetThis<JsTypeface>(env, info);
147 return (me != nullptr) ? me->OnGetFamilyName(env, info) : nullptr;
148 }
149
OnGetFamilyName(napi_env env,napi_callback_info info)150 napi_value JsTypeface::OnGetFamilyName(napi_env env, napi_callback_info info)
151 {
152 if (m_typeface == nullptr) {
153 ROSEN_LOGE("[NAPI]typeface is null");
154 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
155 }
156
157 auto name = m_typeface->GetFamilyName();
158 return GetStringAndConvertToJsValue(env, name);
159 }
160
ConvertTypefaceToJsValue(napi_env env,JsTypeface * typeface)161 napi_value JsTypeface::ConvertTypefaceToJsValue(napi_env env, JsTypeface* typeface)
162 {
163 napi_value jsObj = nullptr;
164 napi_create_object(env, &jsObj);
165 if (jsObj == nullptr) {
166 ROSEN_LOGE("JsTypeface::ConvertTypefaceToJsValue Create Typeface failed!");
167 return nullptr;
168 }
169 napi_status status = napi_wrap(env, jsObj, typeface, JsTypeface::Destructor, nullptr, nullptr);
170 if (status != napi_ok) {
171 ROSEN_LOGE("JsTypeface::ConvertTypefaceToJsValue failed to wrap native instance");
172 return nullptr;
173 }
174 napi_property_descriptor resultFuncs[] = {
175 DECLARE_NAPI_FUNCTION("getFamilyName", JsTypeface::GetFamilyName),
176 };
177 napi_define_properties(env, jsObj, sizeof(resultFuncs) / sizeof(resultFuncs[0]), resultFuncs);
178 return jsObj;
179 }
180
MakeFromFile(napi_env env,napi_callback_info info)181 napi_value JsTypeface::MakeFromFile(napi_env env, napi_callback_info info)
182 {
183 size_t argc = ARGC_ONE;
184 napi_value argv[ARGC_ONE] = {nullptr};
185 CHECK_PARAM_NUMBER_WITH_OPTIONAL_PARAMS(argv, argc, ARGC_ONE, ARGC_ONE);
186
187 std::string text = "";
188 GET_JSVALUE_PARAM(ARGC_ZERO, text);
189
190 auto rawTypeface = Typeface::MakeFromFile(text.c_str());
191 if (rawTypeface == nullptr) {
192 ROSEN_LOGE("JsTypeface::MakeFromFile create rawTypeface failed!");
193 return nullptr;
194 }
195 auto typeface = new JsTypeface(rawTypeface);
196 std::string pathStr(text);
197 if (pathStr.substr(0, G_SYSTEM_FONT_DIR.length()) != G_SYSTEM_FONT_DIR &&
198 Drawing::Typeface::GetTypefaceRegisterCallBack() != nullptr) {
199 bool ret = Drawing::Typeface::GetTypefaceRegisterCallBack()(rawTypeface);
200 if (!ret) {
201 delete typeface;
202 ROSEN_LOGE("JsTypeface::MakeFromFile MakeRegister Typeface failed!");
203 return nullptr;
204 }
205 }
206
207 napi_value jsObj = ConvertTypefaceToJsValue(env, typeface);
208 if (jsObj == nullptr) {
209 delete typeface;
210 ROSEN_LOGE("JsTypeface::MakeFromFile Convert typeface to napivalue failed!");
211 return nullptr;
212 }
213 return jsObj;
214 }
215
MakeFromRawFile(napi_env env,napi_callback_info info)216 napi_value JsTypeface::MakeFromRawFile(napi_env env, napi_callback_info info)
217 {
218 #ifdef ROSEN_OHOS
219 size_t argc = ARGC_ONE;
220 napi_value argv[ARGC_ONE] = {nullptr};
221 CHECK_PARAM_NUMBER_WITH_OPTIONAL_PARAMS(argv, argc, ARGC_ONE, ARGC_ONE);
222
223 std::unique_ptr<uint8_t[]> rawFileArrayBuffer;
224 size_t rawFileArrayBufferSize = 0;
225 ResourceInfo resourceInfo;
226 if (!JsTool::GetResourceInfo(env, argv[ARGC_ZERO], resourceInfo) ||
227 !JsTool::GetResourceRawFileDataBuffer(std::move(rawFileArrayBuffer), rawFileArrayBufferSize, resourceInfo)) {
228 ROSEN_LOGE("JsTypeface::MakeFromRawFile get rawfilebuffer failed!");
229 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
230 }
231
232 auto memory_stream = std::make_unique<MemoryStream>((rawFileArrayBuffer.get()), rawFileArrayBufferSize, true);
233 auto rawTypeface = Typeface::MakeFromStream(std::move(memory_stream));
234 if (rawTypeface == nullptr) {
235 ROSEN_LOGE("JsTypeface::MakeFromRawFile Create rawTypeface failed!");
236 return nullptr;
237 }
238 auto typeface = new JsTypeface(rawTypeface);
239 if (Drawing::Typeface::GetTypefaceRegisterCallBack() != nullptr) {
240 bool ret = Drawing::Typeface::GetTypefaceRegisterCallBack()(rawTypeface);
241 if (!ret) {
242 delete typeface;
243 ROSEN_LOGE("JsTypeface::MakeFromRawFile MakeRegister Typeface failed!");
244 return nullptr;
245 }
246 }
247
248 napi_value jsObj = ConvertTypefaceToJsValue(env, typeface);
249 if (jsObj == nullptr) {
250 delete typeface;
251 ROSEN_LOGE("JsTypeface::MakeFromRawFile Convert typeface to napivalue failed!");
252 return nullptr;
253 }
254 return jsObj;
255 #else
256 return nullptr;
257 #endif
258 }
259 } // namespace Drawing
260 } // namespace OHOS::Rosen