• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "ext_napi_utils.h"
17 #include <memory>
18 #include <cstddef>
19 
20 #include "napi/native_api.h"
21 #include "napi/native_node_api.h"
22 #include "securec.h"
23 #include "frameworks/base/json/json_util.h"
24 #include "frameworks/core/common/card_scope.h"
25 #include "frameworks/core/common/container.h"
26 
27 namespace OHOS::Ace {
28 namespace {
29 constexpr uint32_t COLOR_ALPHA_OFFSET = 24;
30 constexpr uint32_t COLOR_ALPHA_VALUE = 0xFF000000;
31 constexpr uint32_t ERROR_COLOR_ID = -1;
32 
33 enum class ResourceType : uint32_t {
34     COLOR = 10001,
35     FLOAT,
36     STRING,
37     PLURAL,
38     BOOLEAN,
39     INTARRAY,
40     INTEGER,
41     PATTERN,
42     STRARRAY,
43     MEDIA = 20000,
44     RAWFILE = 30000
45 };
46 } // namespace
NapiAsyncEvent(napi_env env,napi_value callback)47 NapiAsyncEvent::NapiAsyncEvent(napi_env env, napi_value callback)
48 {
49     env_ = env;
50     napi_create_reference(env_, callback, 1, &ref_);
51 }
52 
~NapiAsyncEvent()53 NapiAsyncEvent::~NapiAsyncEvent()
54 {
55     napi_delete_reference(env_, ref_);
56 }
57 
Call(int32_t argc,napi_value * argv)58 napi_value NapiAsyncEvent::Call(int32_t argc, napi_value* argv)
59 {
60     napi_value result = nullptr;
61     napi_handle_scope scope;
62     napi_open_handle_scope(env_, &scope);
63     if (scope == nullptr) {
64         napi_close_handle_scope(env_, scope);
65         return result;
66     }
67     napi_value callback = nullptr;
68     napi_get_reference_value(env_, ref_, &callback);
69     napi_value undefined = nullptr;
70     napi_get_undefined(env_, &undefined);
71     napi_call_function(env_, undefined, callback, argc, argv, &result);
72     napi_close_handle_scope(env_, scope);
73     return result;
74 }
75 
GetEnv()76 napi_env NapiAsyncEvent::GetEnv()
77 {
78     return env_;
79 }
80 
CreateInt32(napi_env env,int32_t code)81 napi_value ExtNapiUtils::CreateInt32(napi_env env, int32_t code)
82 {
83     napi_value value = nullptr;
84     if (napi_create_int32(env, code, &value) != napi_ok) {
85         return nullptr;
86     }
87     return value;
88 }
89 
GetCInt32(napi_env env,napi_value value)90 int32_t ExtNapiUtils::GetCInt32(napi_env env, napi_value value)
91 {
92     int32_t num = 0;
93     napi_get_value_int32(env, value, &num);
94     return num;
95 }
96 
GetCInt64(napi_env env,napi_value value)97 int64_t ExtNapiUtils::GetCInt64(napi_env env, napi_value value)
98 {
99     int64_t num = 0;
100     napi_get_value_int64(env, value, &num);
101     return num;
102 }
103 
CreateNull(napi_env env)104 napi_value ExtNapiUtils::CreateNull(napi_env env)
105 {
106     napi_value jsNull = nullptr;
107     NAPI_CALL(env, napi_get_null(env, &jsNull));
108     return jsNull;
109 }
110 
CreateObject(napi_env env)111 napi_value ExtNapiUtils::CreateObject(napi_env env)
112 {
113     napi_value object = nullptr;
114     NAPI_CALL(env, napi_create_object(env, &object));
115     return object;
116 }
117 
CreateDouble(napi_env env,double value)118 napi_value ExtNapiUtils::CreateDouble(napi_env env, double value)
119 {
120     napi_value jsValue = nullptr;
121     NAPI_CALL(env, napi_create_double(env, value, &jsValue));
122     return jsValue;
123 }
124 
CreateFunction(napi_env env,const char * utf8name,size_t length,napi_callback cb,void * data)125 napi_value ExtNapiUtils::CreateFunction(napi_env env,
126                                         const char* utf8name, size_t length,
127                                         napi_callback cb,
128                                         void* data)
129 {
130     napi_value jsfuncValue = nullptr;
131     napi_create_function(env, utf8name, length, cb, data, &jsfuncValue);
132     return jsfuncValue;
133 }
134 
GetBool(napi_env env,napi_value value)135 bool ExtNapiUtils::GetBool(napi_env env, napi_value value)
136 {
137     bool boolValue = false;
138     napi_status ret = napi_get_value_bool(env, value, &boolValue);
139     if (ret == napi_ok) {
140         return boolValue;
141     }
142     return false;
143 }
144 
GetValueType(napi_env env,napi_value value)145 napi_valuetype ExtNapiUtils::GetValueType(napi_env env, napi_value value)
146 {
147     if (value == nullptr) {
148         return napi_undefined;
149     }
150 
151     napi_valuetype valueType = napi_undefined;
152     NAPI_CALL_BASE(env, napi_typeof(env, value, &valueType), napi_undefined);
153     return valueType;
154 }
155 
GetStringFromValueUtf8(napi_env env,napi_value value)156 std::string ExtNapiUtils::GetStringFromValueUtf8(napi_env env, napi_value value)
157 {
158     static constexpr size_t max_length = 2048;
159     if (GetValueType(env, value) != napi_string) {
160         return {};
161     }
162 
163     std::string result;
164     size_t stringLength = 0;
165     NAPI_CALL_BASE(env, napi_get_value_string_utf8(env, value, nullptr, 0, &stringLength), result);
166     if (stringLength == 0 || stringLength > max_length) {
167         return result;
168     }
169 
170     auto deleter = [](char* s) { free(reinterpret_cast<void*>(s)); };
171     char* strTmp = static_cast<char*>(malloc(stringLength + 1));
172     if (strTmp == nullptr) {
173         return result;
174     }
175     std::unique_ptr<char, decltype(deleter)> str(strTmp, deleter);
176     if (memset_s(str.get(), stringLength + 1, 0, stringLength + 1) != EOK) {
177         return result;
178     }
179     size_t length = 0;
180     NAPI_CALL_BASE(env, napi_get_value_string_utf8(env, value, str.get(), stringLength + 1, &length), result);
181     if (length > 0) {
182         result.append(str.get(), length);
183     }
184     return result;
185 }
186 
CheckTypeForNapiValue(napi_env env,napi_value param,napi_valuetype expectType)187 bool ExtNapiUtils::CheckTypeForNapiValue(napi_env env, napi_value param, napi_valuetype expectType)
188 {
189     napi_valuetype valueType = napi_undefined;
190 
191     if (napi_typeof(env, param, &valueType) != napi_ok) {
192         return false;
193     }
194 
195     return valueType == expectType;
196 }
197 
ParseLengthMetrics(napi_env env,napi_value param,CalcDimension & result)198 bool ExtNapiUtils::ParseLengthMetrics(napi_env env, napi_value param, CalcDimension& result)
199 {
200     if (CheckTypeForNapiValue(env, param, napi_object)) {
201         napi_value jsValue = GetNamedProperty(env, param, "value");
202         napi_value jsUnit = GetNamedProperty(env, param, "unit");
203         double value = 0;
204         int32_t unit = static_cast<int32_t>(DimensionUnit::VP);
205         if (CheckTypeForNapiValue(env, jsValue, napi_number) && CheckTypeForNapiValue(env, jsUnit, napi_number) &&
206             napi_get_value_double(env, jsValue, &value) == napi_ok &&
207             napi_get_value_int32(env, jsUnit, &unit) == napi_ok && GreatOrEqual(value, 0.0f)) {
208             result = CalcDimension(value, static_cast<DimensionUnit>(unit));
209             return true;
210         }
211     }
212     return false;
213 }
214 
GetNamedProperty(napi_env env,napi_value object,const std::string & propertyName)215 napi_value ExtNapiUtils::GetNamedProperty(napi_env env, napi_value object, const std::string& propertyName)
216 {
217     if (GetValueType(env, object) != napi_object) {
218         return CreateUndefined(env);
219     }
220 
221     napi_value value = nullptr;
222     NAPI_CALL(env, napi_get_named_property(env, object, propertyName.c_str(), &value));
223     return value;
224 }
225 
IsArray(napi_env env,napi_value value)226 bool ExtNapiUtils::IsArray(napi_env env, napi_value value)
227 {
228     bool isArray = false;
229     napi_status ret = napi_is_array(env, value, &isArray);
230     if (ret == napi_ok) {
231         return isArray;
232     }
233     return false;
234 }
235 
CreateUndefined(napi_env env)236 napi_value ExtNapiUtils::CreateUndefined(napi_env env)
237 {
238     napi_value undefined = nullptr;
239     NAPI_CALL(env, napi_get_undefined(env, &undefined));
240     return undefined;
241 }
242 
ColorAlphaAdapt(uint32_t origin)243 uint32_t ColorAlphaAdapt(uint32_t origin)
244 {
245     uint32_t result = origin;
246     if ((origin >> COLOR_ALPHA_OFFSET) == 0) {
247         result = origin | COLOR_ALPHA_VALUE;
248     }
249     return result;
250 }
251 
GetThemeConstants(napi_env env,napi_value value)252 RefPtr<ThemeConstants> ExtNapiUtils::GetThemeConstants(napi_env env, napi_value value)
253 {
254     napi_value jsBundleName = ExtNapiUtils::GetNamedProperty(env, value, "bundleName");
255     napi_value jsModuleName = ExtNapiUtils::GetNamedProperty(env, value, "moduleName");
256     std::string bundleName = ExtNapiUtils::GetStringFromValueUtf8(env, jsBundleName);
257     std::string moduleName = ExtNapiUtils::GetStringFromValueUtf8(env, jsModuleName);
258 
259     auto cardId = CardScope::CurrentId();
260     if (cardId != INVALID_CARD_ID) {
261         auto container = Container::Current();
262         auto weak = container->GetCardPipeline(cardId);
263         auto cardPipelineContext = weak.Upgrade();
264         CHECK_NULL_RETURN(cardPipelineContext, nullptr);
265         auto cardThemeManager = cardPipelineContext->GetThemeManager();
266         CHECK_NULL_RETURN(cardThemeManager, nullptr);
267         return cardThemeManager->GetThemeConstants(bundleName, moduleName);
268     }
269 
270     auto container = Container::CurrentSafely();
271     CHECK_NULL_RETURN(container, nullptr);
272     auto pipelineContext = container->GetPipelineContext();
273     CHECK_NULL_RETURN(pipelineContext, nullptr);
274     auto themeManager = pipelineContext->GetThemeManager();
275     CHECK_NULL_RETURN(themeManager, nullptr);
276     return themeManager->GetThemeConstants(bundleName, moduleName);
277 }
278 
ParseColor(napi_env env,napi_value value,Color & result)279 bool ExtNapiUtils::ParseColor(napi_env env, napi_value value, Color& result)
280 {
281     napi_valuetype valueType = ExtNapiUtils::GetValueType(env, value);
282     if (valueType != napi_number && valueType != napi_string && valueType != napi_object) {
283         return false;
284     }
285     if (valueType == napi_number) {
286         int32_t colorId = ExtNapiUtils::GetCInt32(env, value);
287         result = Color(ColorAlphaAdapt(static_cast<uint32_t>(colorId)));
288         return true;
289     }
290     if (valueType == napi_string) {
291         std::string colorString = ExtNapiUtils::GetStringFromValueUtf8(env, value);
292         return Color::ParseColorString(colorString, result);
293     }
294     return ParseColorFromResource(env, value, result);
295 }
296 
ParseColorFromResource(napi_env env,napi_value value,Color & colorResult)297 bool ExtNapiUtils::ParseColorFromResource(napi_env env, napi_value value, Color& colorResult)
298 {
299     auto themeConstants = GetThemeConstants(env, value);
300     CHECK_NULL_RETURN(themeConstants, false);
301 
302     napi_value jsColorId = ExtNapiUtils::GetNamedProperty(env, value, "id");
303     napi_value jsParams = ExtNapiUtils::GetNamedProperty(env, value, "params");
304     uint32_t colorId = static_cast<uint32_t>(ExtNapiUtils::GetCInt32(env, jsColorId));
305     if (!ExtNapiUtils::IsArray(env, jsParams)) {
306         return false;
307     }
308     if (colorId == ERROR_COLOR_ID) {
309         uint32_t length;
310         napi_get_array_length(env, jsParams, &length);
311         auto jsonArray = JsonUtil::CreateArray(true);
312         for (uint32_t i = 0; i < length; i++) {
313             napi_value elementValue;
314             napi_get_element(env, jsParams, i, &elementValue);
315             std::string key = std::to_string(i);
316             jsonArray->Put(key.c_str(), PutJsonValue(env, elementValue, key));
317         }
318         std::string strKey = std::to_string(0);
319         std::string colorName = jsonArray->GetValue(strKey.c_str())->GetValue(strKey.c_str())->ToString();
320         colorResult = themeConstants->GetColorByName(colorName);
321         return true;
322     }
323     napi_value jsType = GetNamedProperty(env, value, "type");
324     napi_valuetype valueType = GetValueType(env, jsType);
325     if (valueType != napi_null && valueType == napi_number &&
326         static_cast<uint32_t>(valueType) == static_cast<uint32_t>(ResourceType::STRING)) {
327         auto value = themeConstants->GetString(ExtNapiUtils::GetCInt32(env, jsType));
328         return Color::ParseColorString(value, colorResult);
329     }
330     if (valueType != napi_null && valueType == napi_number &&
331         static_cast<uint32_t>(valueType) == static_cast<uint32_t>(ResourceType::INTEGER)) {
332         auto value = themeConstants->GetInt(ExtNapiUtils::GetCInt32(env, jsType));
333         colorResult = Color(ColorAlphaAdapt(value));
334         return true;
335     }
336     colorResult = themeConstants->GetColor(colorId);
337     return true;
338 }
339 
SetNamedProperty(napi_env env,napi_value object,const std::string & propertyName,napi_value value)340 void ExtNapiUtils::SetNamedProperty(napi_env env, napi_value object, const std::string& propertyName, napi_value value)
341 {
342     if (GetValueType(env, object) != napi_object) {
343         return;
344     }
345 
346     napi_set_named_property(env, object, propertyName.c_str(), value);
347 }
348 
PutJsonValue(napi_env env,napi_value value,std::string & key)349 std::unique_ptr<JsonValue> ExtNapiUtils::PutJsonValue(napi_env env, napi_value value, std::string& key)
350 {
351     auto result = JsonUtil::Create(true);
352     napi_valuetype valueType = ExtNapiUtils::GetValueType(env, value);
353     switch (valueType) {
354         case napi_boolean: {
355             bool boolValue = ExtNapiUtils::GetBool(env, value);
356             result->Put(key.c_str(), boolValue);
357             break;
358         }
359         case napi_number: {
360             int32_t intValue = ExtNapiUtils::GetCInt32(env, value);
361             result->Put(key.c_str(), intValue);
362             break;
363         }
364         case napi_string: {
365             std::string stringValue = ExtNapiUtils::GetStringFromValueUtf8(env, value);
366             result->Put(key.c_str(), stringValue.c_str());
367             break;
368         }
369         default:
370             break;
371     }
372     return result;
373 }
374 
ParseColorMetrics(napi_env env,napi_value param,Color & result)375 bool ExtNapiUtils::ParseColorMetrics(napi_env env, napi_value param, Color& result)
376 {
377     if (CheckTypeForNapiValue(env, param, napi_object)) {
378         napi_value jsToNumeric = GetNamedProperty(env, param, "toNumeric");
379         napi_value jsColor;
380         uint32_t colorVal = 0;
381         if (CheckTypeForNapiValue(env, jsToNumeric, napi_function) &&
382             napi_call_function(env, param, jsToNumeric, 0, nullptr, &jsColor) == napi_ok &&
383             CheckTypeForNapiValue(env, jsColor, napi_number) &&
384             napi_get_value_uint32(env, jsColor, &colorVal) == napi_ok) {
385             result.SetValue(colorVal);
386             return true;
387         }
388     }
389     return false;
390 }
391 } // namespace OHOS::Ace
392