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(®ex, patternPtr, REG_EXTENDED);
343 if (ret != 0) {
344 regfree(®ex);
345 return false;
346 }
347 regfree(®ex);
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