1 /*
2  * Copyright (c) 2021-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 "bridge/declarative_frontend/jsview/js_utils.h"
17 
18 #include "scope_manager/native_scope_manager.h"
19 #include "base/image/drawing_lattice.h"
20 
21 #if !defined(PREVIEW)
22 #include <dlfcn.h>
23 #endif
24 #if !defined(WINDOWS_PLATFORM)
25 #include <regex.h>
26 #endif
27 
28 #ifdef PIXEL_MAP_SUPPORTED
29 #include "pixel_map.h"
30 #include "pixel_map_napi.h"
31 #endif
32 #include "napi/native_node_api.h"
33 
34 #include "base/image/pixel_map.h"
35 #include "base/log/ace_trace.h"
36 #include "base/want/want_wrap.h"
37 #include "bridge/common/utils/engine_helper.h"
38 #include "bridge/declarative_frontend/engine/js_converter.h"
39 #include "frameworks/bridge/common/utils/engine_helper.h"
40 #include "frameworks/bridge/declarative_frontend/engine/js_ref_ptr.h"
41 #include "frameworks/bridge/declarative_frontend/jsview/js_view_abstract.h"
42 #include "frameworks/bridge/declarative_frontend/view_stack_processor.h"
43 #include "frameworks/bridge/js_frontend/engine/common/js_engine.h"
44 
45 namespace OHOS::Ace::Framework {
46 namespace {
47 #if defined(WINDOWS_PLATFORM)
48 constexpr char CHECK_REGEX_VALID[] = "__checkRegexValid__";
49 #endif
50 } // namespace
51 
52 namespace {
UnwrapNapiValue(const JSRef<JSVal> & obj)53 void* UnwrapNapiValue(const JSRef<JSVal>& obj)
54 {
55 #ifdef ENABLE_ROSEN_BACKEND
56     if (!obj->IsObject()) {
57         LOGE("info[0] is not an object when try CreateFromNapiValue");
58         return nullptr;
59     }
60     auto engine = EngineHelper::GetCurrentEngine();
61     CHECK_NULL_RETURN(engine, nullptr);
62     auto nativeEngine = engine->GetNativeEngine();
63     CHECK_NULL_RETURN(nativeEngine, nullptr);
64 #ifdef USE_ARK_ENGINE
65     panda::Local<JsiValue> value = obj.Get().GetLocalHandle();
66 #endif
67     JSValueWrapper valueWrapper = value;
68 
69     ScopeRAII scope(reinterpret_cast<napi_env>(nativeEngine));
70     napi_value napiValue = nativeEngine->ValueToNapiValue(valueWrapper);
71     auto env = reinterpret_cast<napi_env>(nativeEngine);
72     napi_valuetype valueType = napi_undefined;
73     napi_typeof(env, napiValue, &valueType);
74     if (valueType != napi_object) {
75         LOGE("napiValue is not napi_object");
76         return nullptr;
77     }
78     void* objectNapi = nullptr;
79     napi_unwrap(env, napiValue, &objectNapi);
80     return objectNapi;
81 #else
82     return nullptr;
83 #endif
84 }
85 } // namespace
86 
87 #if !defined(PREVIEW)
CreatePixelMapFromNapiValue(const JSRef<JSVal> & obj,NativeEngine * localNativeEngine)88 RefPtr<PixelMap> CreatePixelMapFromNapiValue(const JSRef<JSVal>& obj, NativeEngine* localNativeEngine)
89 {
90     if (!obj->IsObject()) {
91         return nullptr;
92     }
93     NativeEngine* nativeEngine = nullptr;
94     if (localNativeEngine != nullptr) {
95         nativeEngine = localNativeEngine;
96     } else {
97         auto engine = EngineHelper::GetCurrentEngineSafely();
98         if (!engine) {
99             return nullptr;
100         }
101         nativeEngine = engine->GetNativeEngine();
102     }
103     if (nativeEngine == nullptr) {
104         return nullptr;
105     }
106 #ifdef USE_ARK_ENGINE
107     panda::Local<JsiValue> value = obj.Get().GetLocalHandle();
108 #endif
109     JSValueWrapper valueWrapper = value;
110 
111     ScopeRAII scope(reinterpret_cast<napi_env>(nativeEngine));
112     napi_value napiValue = nativeEngine->ValueToNapiValue(valueWrapper);
113 
114     PixelMapNapiEntry pixelMapNapiEntry = JsEngine::GetPixelMapNapiEntry();
115     if (!pixelMapNapiEntry) {
116         return nullptr;
117     }
118 
119     void* pixmapPtrAddr = pixelMapNapiEntry(reinterpret_cast<napi_env>(nativeEngine), napiValue);
120     if (pixmapPtrAddr == nullptr) {
121         return nullptr;
122     }
123     return PixelMap::CreatePixelMap(pixmapPtrAddr);
124 }
125 
GetPixelMapListFromAnimatedDrawable(JSRef<JSVal> obj,std::vector<RefPtr<PixelMap>> & pixelMaps,int32_t & duration,int32_t & iterations)126 bool GetPixelMapListFromAnimatedDrawable(JSRef<JSVal> obj, std::vector<RefPtr<PixelMap>>& pixelMaps,
127     int32_t& duration, int32_t& iterations)
128 {
129     return PixelMap::GetPxielMapListFromAnimatedDrawable(UnwrapNapiValue(obj), pixelMaps, duration, iterations);
130 }
131 
GetDrawablePixmap(JSRef<JSVal> obj)132 RefPtr<PixelMap> GetDrawablePixmap(JSRef<JSVal> obj)
133 {
134     return PixelMap::GetFromDrawable(UnwrapNapiValue(obj));
135 }
136 
CreateRSNodeFromNapiValue(JSRef<JSVal> obj)137 const std::shared_ptr<Rosen::RSNode> CreateRSNodeFromNapiValue(JSRef<JSVal> obj)
138 {
139     auto nodePtr = static_cast<std::shared_ptr<Rosen::RSNode>*>(UnwrapNapiValue(obj));
140     if (nodePtr == nullptr) {
141         return nullptr;
142     }
143     return *nodePtr;
144 }
145 
CreateWantWrapFromNapiValue(JSRef<JSVal> obj)146 RefPtr<OHOS::Ace::WantWrap> CreateWantWrapFromNapiValue(JSRef<JSVal> obj)
147 {
148     if (!obj->IsObject()) {
149         LOGE("invalid object when try CreateWantWrapFromNapiValue");
150         return nullptr;
151     }
152     auto engine = EngineHelper::GetCurrentEngine();
153     CHECK_NULL_RETURN(engine, nullptr);
154 
155     NativeEngine* nativeEngine = engine->GetNativeEngine();
156     CHECK_NULL_RETURN(nativeEngine, nullptr);
157 
158 #ifdef USE_ARK_ENGINE
159     panda::Local<JsiValue> value = obj.Get().GetLocalHandle();
160 #endif
161     JSValueWrapper valueWrapper = value;
162     ScopeRAII scope(reinterpret_cast<napi_env>(nativeEngine));
163     napi_value nativeValue = nativeEngine->ValueToNapiValue(valueWrapper);
164     return WantWrap::CreateWantWrap(reinterpret_cast<napi_env>(nativeEngine), nativeValue);
165 }
166 #endif
167 
CreateRSEffectFromNapiValue(JSRef<JSVal> obj)168 const Rosen::VisualEffect* CreateRSEffectFromNapiValue(JSRef<JSVal> obj)
169 {
170     auto visualEffectPtr = static_cast<Rosen::VisualEffect*>(UnwrapNapiValue(obj));
171     return visualEffectPtr;
172 }
173 
CreateRSFilterFromNapiValue(JSRef<JSVal> obj)174 const Rosen::Filter* CreateRSFilterFromNapiValue(JSRef<JSVal> obj)
175 {
176     auto filterPtr = static_cast<Rosen::Filter*>(UnwrapNapiValue(obj));
177     return filterPtr;
178 }
179 
CreateRSBrightnessBlenderFromNapiValue(JSRef<JSVal> obj)180 const Rosen::BrightnessBlender* CreateRSBrightnessBlenderFromNapiValue(JSRef<JSVal> obj)
181 {
182     auto blenderPtr = static_cast<Rosen::BrightnessBlender*>(UnwrapNapiValue(obj));
183     return blenderPtr;
184 }
185 
CreateDrawingColorFilter(JSRef<JSVal> obj)186 RefPtr<DrawingColorFilter> CreateDrawingColorFilter(JSRef<JSVal> obj)
187 {
188     return DrawingColorFilter::CreateDrawingColorFilter(UnwrapNapiValue(obj));
189 }
190 
CreateDrawingLattice(JSRef<JSVal> obj)191 RefPtr<DrawingLattice> CreateDrawingLattice(JSRef<JSVal> obj)
192 {
193     return DrawingLattice::CreateDrawingLattice(UnwrapNapiValue(obj));
194 }
195 
HandleDifferentRadius(JsiRef<JSVal> args)196 std::optional<NG::BorderRadiusProperty> HandleDifferentRadius(JsiRef<JSVal> args)
197 {
198     std::optional<NG::BorderRadiusProperty> prop = std::nullopt;
199     if (!args->IsObject()) {
200         return prop;
201     }
202 
203     std::optional<CalcDimension> radiusTopLeft;
204     std::optional<CalcDimension> radiusTopRight;
205     std::optional<CalcDimension> radiusBottomLeft;
206     std::optional<CalcDimension> radiusBottomRight;
207     JSRef<JSObject> object = JSRef<JSObject>::Cast(args);
208     CalcDimension topLeft;
209     if (JSViewAbstract::ParseJsDimensionVp(object->GetProperty("topLeft"), topLeft)) {
210         radiusTopLeft = topLeft;
211     }
212     CalcDimension topRight;
213     if (JSViewAbstract::ParseJsDimensionVp(object->GetProperty("topRight"), topRight)) {
214         radiusTopRight = topRight;
215     }
216     CalcDimension bottomLeft;
217     if (JSViewAbstract::ParseJsDimensionVp(object->GetProperty("bottomLeft"), bottomLeft)) {
218         radiusBottomLeft = bottomLeft;
219     }
220     CalcDimension bottomRight;
221     if (JSViewAbstract::ParseJsDimensionVp(object->GetProperty("bottomRight"), bottomRight)) {
222         radiusBottomRight = bottomRight;
223     }
224     if (!radiusTopLeft.has_value() && !radiusTopRight.has_value() && !radiusBottomLeft.has_value() &&
225         !radiusBottomRight.has_value()) {
226         return prop;
227     }
228     NG::BorderRadiusProperty borderRadius;
229     if (radiusTopLeft.has_value()) {
230         borderRadius.radiusTopLeft = radiusTopLeft;
231     }
232     if (radiusTopRight.has_value()) {
233         borderRadius.radiusTopRight = radiusTopRight;
234     }
235     if (radiusBottomLeft.has_value()) {
236         borderRadius.radiusBottomLeft = radiusBottomLeft;
237     }
238     if (radiusBottomRight.has_value()) {
239         borderRadius.radiusBottomRight = radiusBottomRight;
240     }
241     borderRadius.multiValued = true;
242     prop = borderRadius;
243 
244     return prop;
245 }
246 
ParseBorderRadiusAttr(JsiRef<JSVal> args)247 std::optional<NG::BorderRadiusProperty> ParseBorderRadiusAttr(JsiRef<JSVal> args)
248 {
249     std::optional<NG::BorderRadiusProperty> prop = std::nullopt;
250     CalcDimension radiusDim;
251     if (!args->IsObject() && !args->IsNumber() && !args->IsString()) {
252         return prop;
253     }
254     if (JSViewAbstract::ParseJsDimensionVpNG(args, radiusDim)) {
255         NG::BorderRadiusProperty borderRadius;
256         borderRadius.SetRadius(radiusDim);
257         borderRadius.multiValued = false;
258         prop = borderRadius;
259     } else if (args->IsObject()) {
260         prop = HandleDifferentRadius(args);
261     }
262     return prop;
263 }
264 
265 // When the api version >= 11, it is disable event version.
IsDisableEventVersion()266 bool IsDisableEventVersion()
267 {
268     return Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN);
269 }
270 
ParseTextShadowFromShadowObject(const JSRef<JSVal> & shadowObject,std::vector<Shadow> & shadows)271 void ParseTextShadowFromShadowObject(const JSRef<JSVal>& shadowObject, std::vector<Shadow>& shadows)
272 {
273     if (!shadowObject->IsNumber() && !shadowObject->IsObject() && !shadowObject->IsArray()) {
274         return;
275     }
276     if (!shadowObject->IsArray()) {
277         Shadow shadow;
278         if (!JSViewAbstract::ParseShadowProps(shadowObject, shadow)) {
279             return;
280         }
281         shadows.push_back(shadow);
282         return;
283     }
284     JSRef<JSArray> params = JSRef<JSArray>::Cast(shadowObject);
285     auto shadowLength = params->Length();
286     for (size_t i = 0; i < shadowLength; ++i) {
287         auto shadowJsVal = params->GetValueAt(i);
288         Shadow shadow;
289         if (!JSViewAbstract::ParseShadowProps(shadowJsVal, shadow)) {
290             continue;
291         }
292         shadows.push_back(shadow);
293     }
294 }
295 
296 #ifdef PIXEL_MAP_SUPPORTED
ConvertPixmap(const RefPtr<PixelMap> & pixelMap)297 JSRef<JSVal> ConvertPixmap(const RefPtr<PixelMap>& pixelMap)
298 {
299     ContainerScope scope(Container::CurrentIdSafely());
300     auto engine = EngineHelper::GetCurrentEngine();
301     CHECK_NULL_RETURN(engine, {});
302     NativeEngine* nativeEngine = engine->GetNativeEngine();
303     auto* env = reinterpret_cast<napi_env>(nativeEngine);
304     napi_value napiValue = OHOS::Media::PixelMapNapi::CreatePixelMap(env, pixelMap->GetPixelMapSharedPtr());
305     return JsConverter::ConvertNapiValueToJsVal(napiValue);
306 }
307 #endif
308 
309 #ifdef PIXEL_MAP_SUPPORTED
ConvertPixmapNapi(const RefPtr<PixelMap> & pixelMap)310 napi_value ConvertPixmapNapi(const RefPtr<PixelMap>& pixelMap)
311 {
312     auto engine = EngineHelper::GetCurrentEngine();
313     CHECK_NULL_RETURN(engine, {});
314     NativeEngine* nativeEngine = engine->GetNativeEngine();
315     auto* env = reinterpret_cast<napi_env>(nativeEngine);
316     napi_value napiValue = OHOS::Media::PixelMapNapi::CreatePixelMap(env, pixelMap->GetPixelMapSharedPtr());
317     return napiValue;
318 }
319 #endif
320 
IsDrawable(const JSRef<JSVal> & jsValue)321 bool IsDrawable(const JSRef<JSVal>& jsValue)
322 {
323     if (!jsValue->IsObject()) {
324         return false;
325     }
326     JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(jsValue);
327     if (jsObj->IsUndefined()) {
328         return false;
329     }
330 
331     // if jsObject has function getPixelMap, it's a DrawableDescriptor object
332     JSRef<JSVal> func = jsObj->GetProperty("getPixelMap");
333     return (!func->IsNull() && func->IsFunction());
334 }
335 
CheckRegexValid(const std::string & pattern)336 bool CheckRegexValid(const std::string& pattern)
337 {
338 #if !defined(WINDOWS_PLATFORM)
339     regex_t regex;
340     // compile regex
341     const char* patternPtr = pattern.c_str();
342     int32_t ret = regcomp(&regex, patternPtr, REG_EXTENDED);
343     if (ret != 0) {
344         regfree(&regex);
345         return false;
346     }
347     regfree(&regex);
348     return true;
349 #else
350     auto engine = EngineHelper::GetCurrentEngine();
351     CHECK_NULL_RETURN(engine, false);
352     NativeEngine* nativeEngine = engine->GetNativeEngine();
353     CHECK_NULL_RETURN(nativeEngine, false);
354     auto env = reinterpret_cast<napi_env>(nativeEngine);
355     napi_value global;
356     napi_status ret = napi_get_global(env, &global);
357     if (ret != napi_ok) {
358         return false;
359     }
360     napi_value checkRegexValid;
361     ret = napi_get_named_property(env, global, CHECK_REGEX_VALID, &checkRegexValid);
362     if (ret != napi_ok) {
363         return false;
364     }
365     // create napi string
366     napi_value argv[1];
367     napi_create_string_utf8(env, pattern.c_str(), pattern.length(), &argv[0]);
368     napi_value result;
369     napi_call_function(env, nullptr, checkRegexValid, 1, argv, &result);
370     bool isValid = false;
371     napi_get_value_bool(env, result, &isValid);
372     return isValid;
373 #endif
374 }
375 
GetCurrentEnv()376 napi_env GetCurrentEnv()
377 {
378     auto engine = EngineHelper::GetCurrentEngine();
379     if (!engine) {
380         return nullptr;
381     }
382     NativeEngine* nativeEngine = engine->GetNativeEngine();
383     if (!nativeEngine) {
384         return nullptr;
385     }
386     return reinterpret_cast<napi_env>(nativeEngine);
387 }
388 } // namespace OHOS::Ace::Framework
389