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