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