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 "core/components_ng/common_napi_utils/common_napi_utils.h"
17
18 #include <cstddef>
19
20 #include "napi/native_api.h"
21 #include "napi/native_node_api.h"
22 #include "securec.h"
23
24 #include "base/json/json_util.h"
25 #include "core/common/card_scope.h"
26 #include "core/common/container.h"
27 #include "core/gestures/gesture_info.h"
28
29 namespace OHOS::Ace {
30 namespace {
31 constexpr uint32_t COLOR_ALPHA_OFFSET = 24;
32 constexpr uint32_t COLOR_ALPHA_VALUE = 0xFF000000;
33 constexpr uint32_t ERROR_COLOR_ID = -1;
34
35 enum class ResourceType : uint32_t {
36 COLOR = 10001,
37 FLOAT,
38 STRING,
39 PLURAL,
40 BOOLEAN,
41 INTARRAY,
42 INTEGER,
43 PATTERN,
44 STRARRAY,
45 MEDIA = 20000,
46 RAWFILE = 30000
47 };
48 } // namespace
49
NapiAsyncEvnet(napi_env env,napi_value callback)50 NapiAsyncEvnet::NapiAsyncEvnet(napi_env env, napi_value callback)
51 {
52 env_ = env;
53 napi_create_reference(env_, callback, 1, &ref_);
54 }
55
~NapiAsyncEvnet()56 NapiAsyncEvnet::~NapiAsyncEvnet()
57 {
58 napi_delete_reference(env_, ref_);
59 }
60
Call(int32_t argc,napi_value * argv)61 napi_value NapiAsyncEvnet::Call(int32_t argc, napi_value* argv)
62 {
63 napi_value result = nullptr;
64 napi_handle_scope scope;
65 napi_open_handle_scope(env_, &scope);
66 if (scope == nullptr) {
67 napi_close_handle_scope(env_, scope);
68 return result;
69 }
70 napi_value callback = nullptr;
71 napi_get_reference_value(env_, ref_, &callback);
72 napi_value undefined = nullptr;
73 napi_get_undefined(env_, &undefined);
74 napi_call_function(env_, undefined, callback, argc, argv, &result);
75 napi_close_handle_scope(env_, scope);
76 return result;
77 }
78
GetEnv()79 napi_env NapiAsyncEvnet::GetEnv()
80 {
81 return env_;
82 }
83
CreateInt32(napi_env env,int32_t code)84 napi_value CommonNapiUtils::CreateInt32(napi_env env, int32_t code)
85 {
86 napi_value value = nullptr;
87 if (napi_create_int32(env, code, &value) != napi_ok) {
88 return nullptr;
89 }
90 return value;
91 }
92
GetCInt32(napi_value value,napi_env env)93 int32_t CommonNapiUtils::GetCInt32(napi_value value, napi_env env)
94 {
95 int32_t num;
96 napi_get_value_int32(env, value, &num);
97 return num;
98 }
99
GetCInt64(napi_value value,napi_env env)100 int64_t CommonNapiUtils::GetCInt64(napi_value value, napi_env env)
101 {
102 int64_t num;
103 napi_get_value_int64(env, value, &num);
104 return num;
105 }
106
CreateBoolean(napi_env env,bool value)107 napi_value CommonNapiUtils::CreateBoolean(napi_env env, bool value)
108 {
109 napi_value jsValue = nullptr;
110 NAPI_CALL(env, napi_get_boolean(env, value, &jsValue));
111 return jsValue;
112 }
113
GetBool(napi_env env,napi_value value)114 bool CommonNapiUtils::GetBool(napi_env env, napi_value value)
115 {
116 bool boolValue = false;
117 napi_status ret = napi_get_value_bool(env, value, &boolValue);
118 if (ret == napi_ok) {
119 return boolValue;
120 }
121 return false;
122 }
123
CreateDouble(napi_env env,double value)124 napi_value CommonNapiUtils::CreateDouble(napi_env env, double value)
125 {
126 napi_value jsValue = nullptr;
127 NAPI_CALL(env, napi_create_double(env, value, &jsValue));
128 return jsValue;
129 }
130
GetDouble(napi_env env,napi_value value)131 double CommonNapiUtils::GetDouble(napi_env env, napi_value value)
132 {
133 double numberValue = 0;
134 napi_status ret = napi_get_value_double(env, value, &numberValue);
135 if (ret == napi_ok) {
136 return numberValue;
137 }
138 return 0;
139 }
140
GetCString(napi_value value,napi_env env,char * buffer,size_t bufSize)141 size_t CommonNapiUtils::GetCString(napi_value value, napi_env env, char* buffer, size_t bufSize)
142 {
143 size_t valueLength;
144 napi_get_value_string_utf8(env, value, buffer, bufSize, &valueLength);
145 return valueLength;
146 }
147
CreateStringUtf8(napi_env env,const std::string & str)148 napi_value CommonNapiUtils::CreateStringUtf8(napi_env env, const std::string& str)
149 {
150 napi_value value = nullptr;
151 if (napi_create_string_utf8(env, str.c_str(), strlen(str.c_str()), &value) != napi_ok) {
152 return nullptr;
153 }
154 return value;
155 }
156
GetStringFromValueUtf8(napi_env env,napi_value value)157 std::string CommonNapiUtils::GetStringFromValueUtf8(napi_env env, napi_value value)
158 {
159 static constexpr size_t max_length = 2048;
160 if (GetValueType(env, value) != napi_string) {
161 return {};
162 }
163
164 std::string result;
165 size_t stringLength = 0;
166 NAPI_CALL_BASE(env, napi_get_value_string_utf8(env, value, nullptr, 0, &stringLength), result);
167 if (stringLength == 0 || stringLength > max_length) {
168 return result;
169 }
170
171 auto deleter = [](char* s) { free(reinterpret_cast<void*>(s)); };
172 char* strTmp = static_cast<char*>(malloc(stringLength + 1));
173 if (strTmp == nullptr) {
174 return result;
175 }
176 std::unique_ptr<char, decltype(deleter)> str(strTmp, deleter);
177 if (memset_s(str.get(), stringLength + 1, 0, stringLength + 1) != EOK) {
178 return result;
179 }
180 size_t length = 0;
181 NAPI_CALL_BASE(env, napi_get_value_string_utf8(env, value, str.get(), stringLength + 1, &length), result);
182 if (length > 0) {
183 result.append(str.get(), length);
184 }
185 return result;
186 }
187
CreateNull(napi_env env)188 napi_value CommonNapiUtils::CreateNull(napi_env env)
189 {
190 napi_value jsNull = nullptr;
191 NAPI_CALL(env, napi_get_null(env, &jsNull));
192 return jsNull;
193 }
194
CreateUndefined(napi_env env)195 napi_value CommonNapiUtils::CreateUndefined(napi_env env)
196 {
197 napi_value undefined = nullptr;
198 NAPI_CALL(env, napi_get_undefined(env, &undefined));
199 return undefined;
200 }
201
GetValueType(napi_env env,napi_value value)202 napi_valuetype CommonNapiUtils::GetValueType(napi_env env, napi_value value)
203 {
204 if (value == nullptr) {
205 return napi_undefined;
206 }
207
208 napi_valuetype valueType = napi_undefined;
209 NAPI_CALL_BASE(env, napi_typeof(env, value, &valueType), napi_undefined);
210 return valueType;
211 }
212
CreateObject(napi_env env)213 napi_value CommonNapiUtils::CreateObject(napi_env env)
214 {
215 napi_value object = nullptr;
216 NAPI_CALL(env, napi_create_object(env, &object));
217 return object;
218 }
219
DefineProperties(napi_env env,napi_value object,const std::initializer_list<napi_property_descriptor> & properties)220 void CommonNapiUtils::DefineProperties(
221 napi_env env, napi_value object, const std::initializer_list<napi_property_descriptor>& properties)
222 {
223 napi_property_descriptor descriptors[properties.size()];
224 std::copy(properties.begin(), properties.end(), descriptors);
225
226 (void)napi_define_properties(env, object, properties.size(), descriptors);
227 }
228
DefineClass(napi_env env,napi_value exports,const std::initializer_list<napi_property_descriptor> & properties,const std::string & className)229 void CommonNapiUtils::DefineClass(napi_env env, napi_value exports,
230 const std::initializer_list<napi_property_descriptor>& properties, const std::string& className)
231 {
232 auto constructor = [](napi_env env, napi_callback_info info) -> napi_value {
233 napi_value thisVal = nullptr;
234 NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVal, nullptr));
235
236 return thisVal;
237 };
238
239 napi_value jsConstructor = nullptr;
240
241 napi_property_descriptor descriptors[properties.size()];
242 std::copy(properties.begin(), properties.end(), descriptors);
243
244 NAPI_CALL_RETURN_VOID(env, napi_define_class(env, className.c_str(), NAPI_AUTO_LENGTH, constructor, nullptr,
245 properties.size(), descriptors, &jsConstructor));
246
247 SetNamedProperty(env, exports, className, jsConstructor);
248 }
249
SetNamedProperty(napi_env env,napi_value object,const std::string & propertyName,napi_value value)250 void CommonNapiUtils::SetNamedProperty(
251 napi_env env, napi_value object, const std::string& propertyName, napi_value value)
252 {
253 if (GetValueType(env, object) != napi_object) {
254 return;
255 }
256
257 napi_set_named_property(env, object, propertyName.c_str(), value);
258 }
259
GetNamedProperty(napi_env env,napi_value object,const std::string & propertyName)260 napi_value CommonNapiUtils::GetNamedProperty(napi_env env, napi_value object, const std::string& propertyName)
261 {
262 if (GetValueType(env, object) != napi_object) {
263 return CreateUndefined(env);
264 }
265
266 napi_value value = nullptr;
267 NAPI_CALL(env, napi_get_named_property(env, object, propertyName.c_str(), &value));
268 return value;
269 }
270
HasNamedProperty(napi_env env,napi_value object,const std::string & propertyName)271 bool CommonNapiUtils::HasNamedProperty(napi_env env, napi_value object, const std::string& propertyName)
272 {
273 if (GetValueType(env, object) != napi_object) {
274 return false;
275 }
276
277 bool hasProperty = false;
278 NAPI_CALL_BASE(env, napi_has_named_property(env, object, propertyName.c_str(), &hasProperty), false);
279 return hasProperty;
280 }
281
GetPropertyNames(napi_env env,napi_value object,std::vector<std::string> & nameList)282 bool CommonNapiUtils::GetPropertyNames(napi_env env, napi_value object, std::vector<std::string>& nameList)
283 {
284 napi_value names = nullptr;
285 NAPI_CALL_BASE(env, napi_get_property_names(env, object, &names), false);
286 uint32_t length = 0;
287 NAPI_CALL_BASE(env, napi_get_array_length(env, names, &length), false);
288 for (uint32_t index = 0; index < length; ++index) {
289 napi_value name = nullptr;
290 if (napi_get_element(env, names, index, &name) != napi_ok) {
291 continue;
292 }
293 if (GetValueType(env, name) != napi_string) {
294 continue;
295 }
296 nameList.emplace_back(GetStringFromValueUtf8(env, name));
297 }
298 return true;
299 }
300
IsArray(napi_env env,napi_value value)301 bool CommonNapiUtils::IsArray(napi_env env, napi_value value)
302 {
303 bool isArray = false;
304 napi_status ret = napi_is_array(env, value, &isArray);
305 if (ret == napi_ok) {
306 return isArray;
307 }
308 return false;
309 }
310
CreateArray(napi_env env)311 napi_value CommonNapiUtils::CreateArray(napi_env env)
312 {
313 napi_value value = nullptr;
314 NAPI_CALL(env, napi_create_array(env, &value));
315 return value;
316 }
317
SetSelementToArray(napi_env env,napi_value array,int index,napi_value value)318 void CommonNapiUtils::SetSelementToArray(napi_env env, napi_value array, int index, napi_value value)
319 {
320 napi_set_element(env, array, index, value);
321 }
322
ColorAlphaAdapt(uint32_t origin)323 uint32_t ColorAlphaAdapt(uint32_t origin)
324 {
325 uint32_t result = origin;
326 if ((origin >> COLOR_ALPHA_OFFSET) == 0) {
327 result = origin | COLOR_ALPHA_VALUE;
328 }
329 return result;
330 }
331
GetThemeConstants(napi_env env,napi_value value)332 RefPtr<ThemeConstants> CommonNapiUtils::GetThemeConstants(napi_env env, napi_value value)
333 {
334 napi_value jsBundleName = CommonNapiUtils::GetNamedProperty(env, value, "bundleName");
335 napi_value jsModuleName = CommonNapiUtils::GetNamedProperty(env, value, "moduleName");
336 std::string bundleName = CommonNapiUtils::GetStringFromValueUtf8(env, jsBundleName);
337 std::string moduleName = CommonNapiUtils::GetStringFromValueUtf8(env, jsModuleName);
338
339 auto cardId = CardScope::CurrentId();
340 if (cardId != INVALID_CARD_ID) {
341 auto container = Container::Current();
342 auto weak = container->GetCardPipeline(cardId);
343 auto cardPipelineContext = weak.Upgrade();
344 CHECK_NULL_RETURN(cardPipelineContext, nullptr);
345 auto cardThemeManager = cardPipelineContext->GetThemeManager();
346 CHECK_NULL_RETURN(cardThemeManager, nullptr);
347 return cardThemeManager->GetThemeConstants(bundleName, moduleName);
348 }
349
350 auto container = Container::Current();
351 CHECK_NULL_RETURN(container, nullptr);
352 auto pipelineContext = container->GetPipelineContext();
353 CHECK_NULL_RETURN(pipelineContext, nullptr);
354 auto themeManager = pipelineContext->GetThemeManager();
355 CHECK_NULL_RETURN(themeManager, nullptr);
356 return themeManager->GetThemeConstants(bundleName, moduleName);
357 }
358
PutJsonValue(napi_env env,napi_value value,std::string & key)359 std::unique_ptr<JsonValue> CommonNapiUtils::PutJsonValue(napi_env env, napi_value value, std::string& key)
360 {
361 auto result = JsonUtil::Create(false);
362 napi_valuetype valueType = CommonNapiUtils::GetValueType(env, value);
363 switch (valueType) {
364 case napi_boolean: {
365 bool boolValue = CommonNapiUtils::GetBool(env, value);
366 result->Put(key.c_str(), boolValue);
367 break;
368 }
369 case napi_number: {
370 int32_t intValue = CommonNapiUtils::GetCInt32(value, env);
371 result->Put(key.c_str(), intValue);
372 break;
373 }
374 case napi_string: {
375 std::string stringValue = CommonNapiUtils::GetStringFromValueUtf8(env, value);
376 result->Put(key.c_str(), stringValue.c_str());
377 break;
378 }
379 default:
380 break;
381 }
382 return result;
383 }
384
ParseColorFromResource(napi_env env,napi_value value,Color & colorResult)385 bool CommonNapiUtils::ParseColorFromResource(napi_env env, napi_value value, Color& colorResult)
386 {
387 auto themeConstants = GetThemeConstants(env, value);
388 CHECK_NULL_RETURN(themeConstants, false);
389
390 napi_value jsColorId = CommonNapiUtils::GetNamedProperty(env, value, "id");
391 napi_value jsParams = CommonNapiUtils::GetNamedProperty(env, value, "params");
392 uint32_t colorId = CommonNapiUtils::GetCInt32(jsColorId, env);
393 if (!CommonNapiUtils::IsArray(env, jsParams)) {
394 return false;
395 }
396 if (colorId == ERROR_COLOR_ID) {
397 uint32_t length;
398 napi_get_array_length(env, jsParams, &length);
399 auto jsonArray = JsonUtil::CreateArray(false);
400 for (uint32_t i = 0; i < length; i++) {
401 napi_value elementValue;
402 napi_get_element(env, jsParams, i, &elementValue);
403 std::string key = std::to_string(i);
404 jsonArray->Put(key.c_str(), PutJsonValue(env, elementValue, key));
405 }
406 const char* jsonKey = std::to_string(0).c_str();
407 std::string colorName = jsonArray->GetValue(jsonKey)->GetValue(jsonKey)->ToString();
408 colorResult = themeConstants->GetColorByName(colorName);
409 return true;
410 }
411 napi_value jsType = GetNamedProperty(env, value, "type");
412 napi_valuetype valueType = GetValueType(env, jsType);
413 if (valueType != napi_null && valueType == napi_number &&
414 valueType == static_cast<uint32_t>(ResourceType::STRING)) {
415 auto value = themeConstants->GetString(CommonNapiUtils::GetCInt32(jsType, env));
416 return Color::ParseColorString(value, colorResult);
417 }
418 if (valueType != napi_null && valueType == napi_number &&
419 valueType == static_cast<uint32_t>(ResourceType::INTEGER)) {
420 auto value = themeConstants->GetInt(CommonNapiUtils::GetCInt32(jsType, env));
421 colorResult = Color(ColorAlphaAdapt(value));
422 return true;
423 }
424 colorResult = themeConstants->GetColor(colorId);
425 return true;
426 }
427
ParseColor(napi_env env,napi_value value,Color & result)428 bool CommonNapiUtils::ParseColor(napi_env env, napi_value value, Color& result)
429 {
430 napi_valuetype valueType = CommonNapiUtils::GetValueType(env, value);
431 if (valueType != napi_number && valueType != napi_string && valueType != napi_object) {
432 return false;
433 }
434 if (valueType == napi_number) {
435 int32_t colorId = CommonNapiUtils::GetCInt32(value, env);
436 result = Color(ColorAlphaAdapt((uint32_t)colorId));
437 return true;
438 }
439 if (valueType == napi_string) {
440 std::string colorString = CommonNapiUtils::GetStringFromValueUtf8(env, value);
441 return Color::ParseColorString(colorString, result);
442 }
443 return ParseColorFromResource(env, value, result);
444 }
445
GetDimensionResult(napi_env env,napi_value value,CalcDimension & result)446 bool CommonNapiUtils::GetDimensionResult(napi_env env, napi_value value, CalcDimension& result)
447 {
448 napi_valuetype valueType = GetValueType(env, value);
449 if (valueType == napi_number) {
450 double radius = GetDouble(env, value);
451 result = CalcDimension(radius, DimensionUnit::VP);
452 return true;
453 }
454 if (valueType == napi_string) {
455 std::string dimensionString = GetStringFromValueUtf8(env, value);
456 result = StringUtils::StringToCalcDimension(dimensionString, false, DimensionUnit::VP);
457 return true;
458 }
459 auto themeConstants = GetThemeConstants(env, value);
460 CHECK_NULL_RETURN(themeConstants, false);
461
462 napi_value jsDimensionId = GetNamedProperty(env, value, "id");
463 napi_value jsParams = GetNamedProperty(env, value, "params");
464 uint32_t dimensionId = GetCInt32(jsDimensionId, env);
465 if (!IsArray(env, jsParams)) {
466 return false;
467 }
468 if (dimensionId == ERROR_COLOR_ID) {
469 uint32_t length;
470 napi_get_array_length(env, jsParams, &length);
471 auto jsonArray = JsonUtil::CreateArray(false);
472 for (uint32_t i = 0; i < length; i++) {
473 napi_value elementValue;
474 napi_get_element(env, jsParams, i, &elementValue);
475 std::string key = std::to_string(i);
476 jsonArray->Put(key.c_str(), PutJsonValue(env, elementValue, key));
477 }
478 const char* jsonKey = std::to_string(0).c_str();
479 std::string dimensionName = jsonArray->GetValue(jsonKey)->GetValue(jsonKey)->ToString();
480 result = themeConstants->GetDimensionByName(dimensionName);
481 return true;
482 }
483
484 napi_value jsType = GetNamedProperty(env, value, "type");
485 napi_valuetype temp = GetValueType(env, jsType);
486 uint32_t type = GetCInt32(jsType, env);
487 if (temp != napi_null && temp == napi_number && type == static_cast<uint32_t>(ResourceType::STRING)) {
488 auto dimensionValue = themeConstants->GetString(dimensionId);
489 result = StringUtils::StringToCalcDimension(dimensionValue, false, DimensionUnit::VP);
490 return true;
491 }
492 if (temp != napi_null && temp == napi_number && type == static_cast<uint32_t>(ResourceType::INTEGER)) {
493 auto dimensionValue = std::to_string(themeConstants->GetInt(dimensionId));
494 result = StringUtils::StringToDimensionWithUnit(dimensionValue, DimensionUnit::VP);
495 return true;
496 }
497
498 result = themeConstants->GetDimension(dimensionId);
499 return true;
500 }
501 } // namespace OHOS::Ace
502