• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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