1 /*
2 * Copyright (c) 2021-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 "bridge/declarative_frontend/jsview/js_image.h"
17
18 #include <cstdint>
19 #include <memory>
20 #include <vector>
21 #if !defined(PREVIEW)
22 #include <dlfcn.h>
23 #endif
24
25 #include "interfaces/inner_api/ace/ai/image_analyzer.h"
26 #if !defined(PREVIEW) && defined(OHOS_PLATFORM)
27 #include "interfaces/inner_api/ui_session/ui_session_manager.h"
28 #endif
29
30 #include "base/geometry/ng/vector.h"
31 #include "base/image/drawing_color_filter.h"
32 #include "base/image/drawing_lattice.h"
33 #include "base/image/pixel_map.h"
34 #include "base/log/ace_scoring_log.h"
35 #include "base/log/ace_trace.h"
36 #include "base/utils/utils.h"
37 #include "bridge/common/utils/engine_helper.h"
38 #include "bridge/declarative_frontend/engine/functions/js_drag_function.h"
39 #include "bridge/declarative_frontend/engine/js_ref_ptr.h"
40 #include "bridge/declarative_frontend/engine/js_types.h"
41 #include "bridge/declarative_frontend/engine/jsi/js_ui_index.h"
42 #include "bridge/declarative_frontend/jsview/models/image_model_impl.h"
43 #include "core/common/container.h"
44 #include "core/components/common/layout/constants.h"
45 #include "core/components/image/image_event.h"
46 #include "core/components/image/image_theme.h"
47 #include "core/components_ng/base/view_abstract_model.h"
48 #include "core/components_ng/base/view_stack_processor.h"
49 #include "core/components_ng/event/gesture_event_hub.h"
50 #include "core/components_ng/pattern/image/image_model.h"
51 #include "core/components_ng/pattern/image/image_model_ng.h"
52 #include "core/image/image_source_info.h"
53
54 namespace {
55 const std::vector<float> DEFAULT_COLORFILTER_MATRIX = { 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0 };
56 constexpr float CEIL_SMOOTHEDGE_VALUE = 1.333f;
57 constexpr float FLOOR_SMOOTHEDGE_VALUE = 0.334f;
58 constexpr float DEFAULT_SMOOTHEDGE_VALUE = 0.0f;
59 } // namespace
60
61 namespace OHOS::Ace {
62
63 namespace {
CreateSourceInfo(const std::shared_ptr<std::string> & srcRef,RefPtr<PixelMap> & pixmap,const std::string & bundleName,const std::string & moduleName)64 ImageSourceInfo CreateSourceInfo(const std::shared_ptr<std::string>& srcRef, RefPtr<PixelMap>& pixmap,
65 const std::string& bundleName, const std::string& moduleName)
66 {
67 #if defined(PIXEL_MAP_SUPPORTED)
68 if (pixmap) {
69 return ImageSourceInfo(pixmap);
70 }
71 #endif
72 return { srcRef, bundleName, moduleName };
73 }
74 } // namespace
75
76 std::unique_ptr<ImageModel> ImageModel::instance_ = nullptr;
77 std::mutex ImageModel::mutex_;
78
GetInstance()79 ImageModel* __attribute__((optnone)) ImageModel::GetInstance()
80 {
81 if (!instance_) {
82 std::lock_guard<std::mutex> lock(mutex_);
83 if (!instance_) {
84 #ifdef NG_BUILD
85 instance_.reset(new NG::ImageModelNG());
86 #else
87 if (Container::IsCurrentUseNewPipeline()) {
88 instance_.reset(new NG::ImageModelNG());
89 } else {
90 instance_.reset(new Framework::ImageModelImpl());
91 }
92 #endif
93 }
94 }
95 return instance_.get();
96 }
97
98 } // namespace OHOS::Ace
99
100 namespace OHOS::Ace::Framework {
101
LoadImageSuccEventToJSValue(const LoadImageSuccessEvent & eventInfo)102 JSRef<JSVal> LoadImageSuccEventToJSValue(const LoadImageSuccessEvent& eventInfo)
103 {
104 JSRef<JSObject> obj = JSRef<JSObject>::New();
105 obj->SetProperty("width", eventInfo.GetWidth());
106 obj->SetProperty("height", eventInfo.GetHeight());
107 obj->SetProperty("componentWidth", eventInfo.GetComponentWidth());
108 obj->SetProperty("componentHeight", eventInfo.GetComponentHeight());
109 obj->SetProperty("loadingStatus", eventInfo.GetLoadingStatus());
110 obj->SetProperty("contentWidth", eventInfo.GetContentWidth());
111 obj->SetProperty("contentHeight", eventInfo.GetContentHeight());
112 obj->SetProperty("contentOffsetX", eventInfo.GetContentOffsetX());
113 obj->SetProperty("contentOffsetY", eventInfo.GetContentOffsetY());
114 return JSRef<JSVal>::Cast(obj);
115 }
116
LoadImageFailEventToJSValue(const LoadImageFailEvent & eventInfo)117 JSRef<JSVal> LoadImageFailEventToJSValue(const LoadImageFailEvent& eventInfo)
118 {
119 JSRef<JSObject> obj = JSRef<JSObject>::New();
120 obj->SetProperty("componentWidth", eventInfo.GetComponentWidth());
121 obj->SetProperty("componentHeight", eventInfo.GetComponentHeight());
122 obj->SetProperty("message", eventInfo.GetErrorMessage());
123 return JSRef<JSVal>::Cast(obj);
124 }
125
SetAlt(const JSCallbackInfo & args)126 void JSImage::SetAlt(const JSCallbackInfo& args)
127 {
128 if (ImageModel::GetInstance()->GetIsAnimation()) {
129 return;
130 }
131 if (args.Length() < 1) {
132 return;
133 }
134
135 auto context = PipelineBase::GetCurrentContext();
136 CHECK_NULL_VOID(context);
137 bool isCard = context->IsFormRender();
138
139 std::string src;
140 bool srcValid = false;
141 if (args[0]->IsString()) {
142 src = args[0]->ToString();
143 } else {
144 srcValid = ParseJsMedia(args[0], src);
145 }
146 if (ImageSourceInfo::ResolveURIType(src) == SrcType::NETWORK) {
147 return;
148 }
149 int32_t resId = 0;
150 if (args[0]->IsObject()) {
151 JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(args[0]);
152 JSRef<JSVal> tmp = jsObj->GetProperty("id");
153 if (!tmp->IsNull() && tmp->IsNumber()) {
154 resId = tmp->ToNumber<int32_t>();
155 }
156 }
157 std::string bundleName;
158 std::string moduleName;
159 GetJsMediaBundleInfo(args[0], bundleName, moduleName);
160 RefPtr<PixelMap> pixmap = nullptr;
161
162 // input is Drawable
163 if (!srcValid && !isCard) {
164 #if defined(PIXEL_MAP_SUPPORTED)
165 pixmap = CreatePixelMapFromNapiValue(args[0]);
166 #endif
167 }
168 auto srcRef = std::make_shared<std::string>(src);
169 auto srcInfo = CreateSourceInfo(srcRef, pixmap, bundleName, moduleName);
170 srcInfo.SetIsUriPureNumber((resId == -1));
171 ImageModel::GetInstance()->SetAlt(srcInfo);
172 }
173
SetObjectFit(const JSCallbackInfo & args)174 void JSImage::SetObjectFit(const JSCallbackInfo& args)
175 {
176 if (args.Length() < 1) {
177 ImageModel::GetInstance()->SetImageFit(ImageFit::COVER);
178 return;
179 }
180 int32_t parseRes = static_cast<int32_t>(ImageFit::COVER);
181 ParseJsInteger(args[0], parseRes);
182 if (parseRes < static_cast<int32_t>(ImageFit::FILL) || parseRes > static_cast<int32_t>(ImageFit::BOTTOM_END)) {
183 parseRes = static_cast<int32_t>(ImageFit::COVER);
184 }
185 auto fit = static_cast<ImageFit>(parseRes);
186 ImageModel::GetInstance()->SetImageFit(fit);
187 }
188
SetMatchTextDirection(bool value)189 void JSImage::SetMatchTextDirection(bool value)
190 {
191 if (ImageModel::GetInstance()->GetIsAnimation()) {
192 return;
193 }
194 ImageModel::GetInstance()->SetMatchTextDirection(value);
195 }
196
SetFitOriginalSize(bool value)197 void JSImage::SetFitOriginalSize(bool value)
198 {
199 if (ImageModel::GetInstance()->GetIsAnimation()) {
200 return;
201 }
202 ImageModel::GetInstance()->SetFitOriginSize(value);
203 }
204
SetBorder(const Border & border)205 void JSImage::SetBorder(const Border& border)
206 {
207 ImageModel::GetInstance()->SetBorder(border);
208 }
209
OnComplete(const JSCallbackInfo & args)210 void JSImage::OnComplete(const JSCallbackInfo& args)
211 {
212 if (args[0]->IsFunction()) {
213 auto jsLoadSuccFunc = AceType::MakeRefPtr<JsEventFunction<LoadImageSuccessEvent, 1>>(
214 JSRef<JSFunc>::Cast(args[0]), LoadImageSuccEventToJSValue);
215
216 auto onComplete = [execCtx = args.GetExecutionContext(), func = std::move(jsLoadSuccFunc)](
217 const LoadImageSuccessEvent& info) {
218 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
219 ACE_SCORING_EVENT("Image.onComplete");
220 func->Execute(info);
221 #if !defined(PREVIEW) && defined(OHOS_PLATFORM)
222 UiSessionManager::GetInstance().ReportComponentChangeEvent("event", "Image.onComplete");
223 #endif
224 };
225 ImageModel::GetInstance()->SetOnComplete(std::move(onComplete));
226 }
227 }
228
OnError(const JSCallbackInfo & args)229 void JSImage::OnError(const JSCallbackInfo& args)
230 {
231 if (args[0]->IsFunction()) {
232 auto jsLoadFailFunc = AceType::MakeRefPtr<JsEventFunction<LoadImageFailEvent, 1>>(
233 JSRef<JSFunc>::Cast(args[0]), LoadImageFailEventToJSValue);
234 auto onError = [execCtx = args.GetExecutionContext(), func = std::move(jsLoadFailFunc)](
235 const LoadImageFailEvent& info) {
236 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
237 ACE_SCORING_EVENT("Image.onError");
238 func->Execute(info);
239 #if !defined(PREVIEW) && defined(OHOS_PLATFORM)
240 UiSessionManager::GetInstance().ReportComponentChangeEvent("event", "Image.onError");
241 #endif
242 };
243
244 ImageModel::GetInstance()->SetOnError(onError);
245 }
246 }
247
OnFinish(const JSCallbackInfo & info)248 void JSImage::OnFinish(const JSCallbackInfo& info)
249 {
250 auto tmpInfo = info[0];
251 if (!tmpInfo->IsFunction()) {
252 return;
253 }
254 RefPtr<JsFunction> jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(tmpInfo));
255 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
256 auto onFinish = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode]() {
257 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
258 ACE_SCORING_EVENT("Image.onFinish");
259 PipelineContext::SetCallBackNode(node);
260 func->Execute();
261 };
262 ImageModel::GetInstance()->SetSvgAnimatorFinishEvent(onFinish);
263 }
264
Create(const JSCallbackInfo & info)265 void JSImage::Create(const JSCallbackInfo& info)
266 {
267 if (info.Length() < 1) {
268 return;
269 }
270 CreateImage(info);
271 }
272
CheckIsCard()273 bool JSImage::CheckIsCard()
274 {
275 auto container = Container::Current();
276 if (!container) {
277 TAG_LOGE(AceLogTag::ACE_IMAGE, "Container is null in CreateImage.");
278 return false;
279 }
280 return container->IsFormRender() && !container->IsDynamicRender();
281 }
282
CheckResetImage(const JSCallbackInfo & info)283 bool JSImage::CheckResetImage(const JSCallbackInfo& info)
284 {
285 int32_t parseRes = -1;
286 if (info.Length() < 1 || !ParseJsInteger(info[0], parseRes)) {
287 return false;
288 }
289 ImageModel::GetInstance()->ResetImage();
290 return true;
291 }
292
CreateImage(const JSCallbackInfo & info,bool isImageSpan)293 void JSImage::CreateImage(const JSCallbackInfo& info, bool isImageSpan)
294 {
295 if (CheckResetImage(info)) {
296 return;
297 }
298 bool isCard = CheckIsCard();
299
300 // Interim programme
301 std::string bundleName;
302 std::string moduleName;
303 std::string src;
304 auto imageInfo = info[0];
305 int32_t resId = 0;
306 bool srcValid = ParseJsMediaWithBundleName(imageInfo, src, bundleName, moduleName, resId);
307 if (isCard && imageInfo->IsString()) {
308 SrcType srcType = ImageSourceInfo::ResolveURIType(src);
309 bool notSupport = (srcType == SrcType::NETWORK || srcType == SrcType::FILE || srcType == SrcType::DATA_ABILITY);
310 if (notSupport) {
311 src.clear();
312 }
313 }
314 RefPtr<PixelMap> pixmap = nullptr;
315
316 // input is PixelMap / Drawable
317 if (!srcValid && !isCard) {
318 #if defined(PIXEL_MAP_SUPPORTED)
319 std::vector<RefPtr<PixelMap>> pixelMaps;
320 int32_t duration = -1;
321 int32_t iterations = 1;
322 if (IsDrawable(imageInfo)) {
323 if (GetPixelMapListFromAnimatedDrawable(imageInfo, pixelMaps, duration, iterations)) {
324 CreateImageAnimation(pixelMaps, duration, iterations);
325 return;
326 }
327 pixmap = GetDrawablePixmap(imageInfo);
328 } else {
329 pixmap = CreatePixelMapFromNapiValue(imageInfo);
330 }
331 #endif
332 }
333 ImageInfoConfig imageInfoConfig(
334 std::make_shared<std::string>(src), bundleName, moduleName, (resId == -1), isImageSpan);
335 ImageModel::GetInstance()->Create(imageInfoConfig, pixmap);
336
337 if (info.Length() > 1) {
338 ParseImageAIOptions(info[1]);
339 }
340 }
341
ParseImageAIOptions(const JSRef<JSVal> & jsValue)342 void JSImage::ParseImageAIOptions(const JSRef<JSVal>& jsValue)
343 {
344 if (!jsValue->IsObject()) {
345 return;
346 }
347 auto engine = EngineHelper::GetCurrentEngine();
348 CHECK_NULL_VOID(engine);
349 NativeEngine* nativeEngine = engine->GetNativeEngine();
350 panda::Local<JsiValue> value = jsValue.Get().GetLocalHandle();
351 JSValueWrapper valueWrapper = value;
352 ScopeRAII scope(reinterpret_cast<napi_env>(nativeEngine));
353 napi_value optionsValue = nativeEngine->ValueToNapiValue(valueWrapper);
354 ImageModel::GetInstance()->SetImageAIOptions(optionsValue);
355 }
356
IsDrawable(const JSRef<JSVal> & jsValue)357 bool JSImage::IsDrawable(const JSRef<JSVal>& jsValue)
358 {
359 if (!jsValue->IsObject()) {
360 return false;
361 }
362 JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(jsValue);
363 if (jsObj->IsUndefined()) {
364 return false;
365 }
366
367 // if jsObject has function getPixelMap, it's a DrawableDescriptor object
368 JSRef<JSVal> func = jsObj->GetProperty("getPixelMap");
369 return (!func->IsNull() && func->IsFunction());
370 }
371
JsBorder(const JSCallbackInfo & info)372 void JSImage::JsBorder(const JSCallbackInfo& info)
373 {
374 if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_FOURTEEN)) {
375 JSViewAbstract::JsBorder(info);
376 ImageModel::GetInstance()->SetBackBorder();
377 return;
378 }
379 // handles generic property logic.
380 JSViewAbstract::JsBorder(info);
381 // handles the image component separately, aiming to extract and set the borderRadius property
382 if (!info[0]->IsObject()) {
383 CalcDimension borderRadius;
384 ImageModel::GetInstance()->SetBorderRadius(borderRadius);
385 return;
386 }
387 JSRef<JSObject> object = JSRef<JSObject>::Cast(info[0]);
388
389 auto valueRadius = object->GetProperty(static_cast<int32_t>(ArkUIIndex::RADIUS));
390 if (!valueRadius->IsUndefined()) {
391 ParseBorderRadius(valueRadius);
392 }
393 }
394
ParseBorderRadius(const JSRef<JSVal> & args)395 void JSImage::ParseBorderRadius(const JSRef<JSVal>& args)
396 {
397 CalcDimension borderRadius;
398 if (ParseJsDimensionVp(args, borderRadius)) {
399 ViewAbstractModel::GetInstance()->SetBorderRadius(borderRadius);
400 ImageModel::GetInstance()->SetBorderRadius(borderRadius);
401 } else if (args->IsObject()) {
402 JSRef<JSObject> object = JSRef<JSObject>::Cast(args);
403 CalcDimension topLeft;
404 CalcDimension topRight;
405 CalcDimension bottomLeft;
406 CalcDimension bottomRight;
407 if (ParseAllBorderRadiuses(object, topLeft, topRight, bottomLeft, bottomRight)) {
408 ImageModel::GetInstance()->SetBorderRadius(
409 GetLocalizedBorderRadius(topLeft, topRight, bottomLeft, bottomRight));
410 ViewAbstractModel::GetInstance()->SetBorderRadius(
411 GetLocalizedBorderRadius(topLeft, topRight, bottomLeft, bottomRight));
412 return;
413 }
414 ImageModel::GetInstance()->SetBorderRadius(topLeft, topRight, bottomLeft, bottomRight);
415 ViewAbstractModel::GetInstance()->SetBorderRadius(topLeft, topRight, bottomLeft, bottomRight);
416 }
417 }
418
ParseResizableSlice(const JSRef<JSObject> & resizableObject)419 void JSImage::ParseResizableSlice(const JSRef<JSObject>& resizableObject)
420 {
421 ImageResizableSlice sliceResult;
422 if (resizableObject->IsEmpty()) {
423 ImageModel::GetInstance()->SetResizableSlice(sliceResult);
424 return;
425 }
426 auto sliceValue = resizableObject->GetProperty("slice");
427 if (!sliceValue->IsObject()) {
428 ImageModel::GetInstance()->SetResizableSlice(sliceResult);
429 return;
430 }
431 JSRef<JSObject> sliceObj = JSRef<JSObject>::Cast(sliceValue);
432 if (sliceObj->IsEmpty()) {
433 ImageModel::GetInstance()->SetResizableSlice(sliceResult);
434 return;
435 }
436 UpdateSliceResult(sliceObj, sliceResult);
437
438 ImageModel::GetInstance()->SetResizableSlice(sliceResult);
439 }
440
ParseResizableLattice(const JSRef<JSObject> & resizableObject)441 void JSImage::ParseResizableLattice(const JSRef<JSObject>& resizableObject)
442 {
443 auto latticeValue = resizableObject->GetProperty("lattice");
444 if (latticeValue->IsUndefined() || latticeValue->IsNull()) {
445 ImageModel::GetInstance()->ResetResizableLattice();
446 }
447 CHECK_NULL_VOID(latticeValue->IsObject());
448 auto drawingLattice = CreateDrawingLattice(latticeValue);
449 if (drawingLattice) {
450 ImageModel::GetInstance()->SetResizableLattice(drawingLattice);
451 } else {
452 ImageModel::GetInstance()->ResetResizableLattice();
453 }
454 }
455
JsImageResizable(const JSCallbackInfo & info)456 void JSImage::JsImageResizable(const JSCallbackInfo& info)
457 {
458 if (ImageModel::GetInstance()->GetIsAnimation()) {
459 return;
460 }
461 auto infoObj = info[0];
462 if (!infoObj->IsObject()) {
463 ImageModel::GetInstance()->SetResizableSlice(ImageResizableSlice());
464 return;
465 }
466 JSRef<JSObject> resizableObject = JSRef<JSObject>::Cast(infoObj);
467 ParseResizableSlice(resizableObject);
468 ParseResizableLattice(resizableObject);
469 }
470
UpdateSliceResult(const JSRef<JSObject> & sliceObj,ImageResizableSlice & sliceResult)471 void JSImage::UpdateSliceResult(const JSRef<JSObject>& sliceObj, ImageResizableSlice& sliceResult)
472 {
473 // creatge a array has 4 elements for paresing sliceSize
474 static std::array<int32_t, 4> keys = { static_cast<int32_t>(ArkUIIndex::LEFT),
475 static_cast<int32_t>(ArkUIIndex::RIGHT), static_cast<int32_t>(ArkUIIndex::TOP),
476 static_cast<int32_t>(ArkUIIndex::BOTTOM) };
477 for (uint32_t i = 0; i < keys.size(); i++) {
478 auto sliceSize = sliceObj->GetProperty(keys.at(i));
479 CalcDimension sliceDimension;
480 if (!ParseJsDimensionVp(sliceSize, sliceDimension)) {
481 continue;
482 }
483 if (!sliceDimension.IsValid()) {
484 continue;
485 }
486 switch (static_cast<BorderImageDirection>(i)) {
487 case BorderImageDirection::LEFT:
488 sliceResult.left = sliceDimension;
489 break;
490 case BorderImageDirection::RIGHT:
491 sliceResult.right = sliceDimension;
492 break;
493 case BorderImageDirection::TOP:
494 sliceResult.top = sliceDimension;
495 break;
496 case BorderImageDirection::BOTTOM:
497 sliceResult.bottom = sliceDimension;
498 break;
499 default:
500 break;
501 }
502 }
503 ImageModel::GetInstance()->SetResizableSlice(sliceResult);
504 }
505
JsBorderRadius(const JSCallbackInfo & info)506 void JSImage::JsBorderRadius(const JSCallbackInfo& info)
507 {
508 if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_FOURTEEN)) {
509 JSViewAbstract::JsBorderRadius(info);
510 ImageModel::GetInstance()->SetBackBorder();
511 return;
512 }
513 static std::vector<JSCallbackInfoType> checkList { JSCallbackInfoType::STRING, JSCallbackInfoType::NUMBER,
514 JSCallbackInfoType::OBJECT };
515 auto jsVal = info[0];
516 if (!CheckJSCallbackInfo("JsBorderRadius", jsVal, checkList)) {
517 ViewAbstractModel::GetInstance()->SetBorderRadius(Dimension {});
518 ImageModel::GetInstance()->SetBorderRadius(Dimension {});
519 return;
520 }
521 ParseBorderRadius(jsVal);
522 }
523
SetSourceSize(const JSCallbackInfo & info)524 void JSImage::SetSourceSize(const JSCallbackInfo& info)
525 {
526 if (ImageModel::GetInstance()->GetIsAnimation()) {
527 return;
528 }
529 ImageModel::GetInstance()->SetImageSourceSize(JSViewAbstract::ParseSize(info));
530 }
531
SetImageFill(const JSCallbackInfo & info)532 void JSImage::SetImageFill(const JSCallbackInfo& info)
533 {
534 if (ImageModel::GetInstance()->GetIsAnimation()) {
535 return;
536 }
537 if (info.Length() < 1) {
538 return;
539 }
540
541 Color color;
542 if (!ParseJsColor(info[0], color)) {
543 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
544 return;
545 }
546 auto pipelineContext = PipelineBase::GetCurrentContext();
547 CHECK_NULL_VOID(pipelineContext);
548 auto theme = pipelineContext->GetTheme<ImageTheme>();
549 CHECK_NULL_VOID(theme);
550 color = theme->GetFillColor();
551 }
552 ImageModel::GetInstance()->SetImageFill(color);
553 }
554
SetImageRenderMode(const JSCallbackInfo & info)555 void JSImage::SetImageRenderMode(const JSCallbackInfo& info)
556 {
557 if (ImageModel::GetInstance()->GetIsAnimation()) {
558 return;
559 }
560 if (info.Length() < 1) {
561 ImageModel::GetInstance()->SetImageRenderMode(ImageRenderMode::ORIGINAL);
562 return;
563 }
564 auto jsImageRenderMode = info[0];
565 if (jsImageRenderMode->IsNumber()) {
566 auto renderMode = static_cast<ImageRenderMode>(jsImageRenderMode->ToNumber<int32_t>());
567 if (renderMode < ImageRenderMode::ORIGINAL || renderMode > ImageRenderMode::TEMPLATE) {
568 renderMode = ImageRenderMode::ORIGINAL;
569 }
570 ImageModel::GetInstance()->SetImageRenderMode(renderMode);
571 } else {
572 ImageModel::GetInstance()->SetImageRenderMode(ImageRenderMode::ORIGINAL);
573 }
574 }
575
SetImageInterpolation(int32_t imageInterpolation)576 void JSImage::SetImageInterpolation(int32_t imageInterpolation)
577 {
578 if (ImageModel::GetInstance()->GetIsAnimation()) {
579 return;
580 }
581 auto interpolation = static_cast<ImageInterpolation>(imageInterpolation);
582 if (interpolation < ImageInterpolation::NONE || interpolation > ImageInterpolation::HIGH) {
583 interpolation = ImageInterpolation::NONE;
584 }
585 ImageModel::GetInstance()->SetImageInterpolation(interpolation);
586 }
587
SetImageRepeat(int32_t imageRepeat)588 void JSImage::SetImageRepeat(int32_t imageRepeat)
589 {
590 auto repeat = static_cast<ImageRepeat>(imageRepeat);
591 if (repeat < ImageRepeat::NO_REPEAT || repeat > ImageRepeat::REPEAT) {
592 repeat = ImageRepeat::NO_REPEAT;
593 }
594 ImageModel::GetInstance()->SetImageRepeat(repeat);
595 }
596
JsTransition(const JSCallbackInfo & info)597 void JSImage::JsTransition(const JSCallbackInfo& info)
598 {
599 if (ImageModel::GetInstance()->IsSrcSvgImage()) {
600 JSViewAbstract::JsTransition(info);
601 } else {
602 JSViewAbstract::JsTransitionPassThrough(info);
603 }
604 }
605
JsOpacity(const JSCallbackInfo & info)606 void JSImage::JsOpacity(const JSCallbackInfo& info)
607 {
608 if (ImageModel::GetInstance()->IsSrcSvgImage()) {
609 JSViewAbstract::JsOpacity(info);
610 } else {
611 JSViewAbstract::JsOpacityPassThrough(info);
612 }
613 }
614
JsBlur(const JSCallbackInfo & info)615 void JSImage::JsBlur(const JSCallbackInfo& info)
616 {
617 // only flutter runs special image blur
618 #ifdef ENABLE_ROSEN_BACKEND
619 JSViewAbstract::JsBlur(info);
620 #else
621 if (info.Length() < 1) {
622 return;
623 }
624 double blur = 0.0;
625 if (ParseJsDouble(info[0], blur)) {
626 ImageModel::GetInstance()->SetBlur(blur);
627 }
628 #endif
629 }
630
SetAutoResize(bool autoResize)631 void JSImage::SetAutoResize(bool autoResize)
632 {
633 if (ImageModel::GetInstance()->GetIsAnimation()) {
634 return;
635 }
636 ImageModel::GetInstance()->SetAutoResize(autoResize);
637 }
638
SetSyncLoad(const JSCallbackInfo & info)639 void JSImage::SetSyncLoad(const JSCallbackInfo& info)
640 {
641 if (ImageModel::GetInstance()->GetIsAnimation()) {
642 return;
643 }
644 if (info.Length() < 1) {
645 return;
646 }
647 auto tmpInfo = info[0];
648 if (!tmpInfo->IsBoolean()) {
649 return;
650 }
651 ImageModel::GetInstance()->SetSyncMode(tmpInfo->ToBoolean());
652 }
653
ConstructorCallback(const JSCallbackInfo & args)654 void JSColorFilter::ConstructorCallback(const JSCallbackInfo& args)
655 {
656 if (args.Length() < 1) {
657 return;
658 }
659 auto tmpInfo = args[0];
660 if (!tmpInfo->IsArray()) {
661 return;
662 }
663 JSRef<JSArray> array = JSRef<JSArray>::Cast(tmpInfo);
664 if (array->Length() != COLOR_FILTER_MATRIX_SIZE) {
665 return;
666 }
667 auto jscolorfilter = Referenced::MakeRefPtr<JSColorFilter>();
668 if (jscolorfilter == nullptr) {
669 return;
670 }
671 std::vector<float> colorfilter;
672 for (size_t i = 0; i < array->Length(); i++) {
673 JSRef<JSVal> value = array->GetValueAt(i);
674 if (value->IsNumber()) {
675 colorfilter.emplace_back(value->ToNumber<float>());
676 }
677 }
678 if (colorfilter.size() != COLOR_FILTER_MATRIX_SIZE) {
679 return;
680 }
681 jscolorfilter->SetColorFilterMatrix(std::move(colorfilter));
682 jscolorfilter->IncRefCount();
683 args.SetReturnValue(Referenced::RawPtr(jscolorfilter));
684 }
685
DestructorCallback(JSColorFilter * obj)686 void JSColorFilter::DestructorCallback(JSColorFilter* obj)
687 {
688 if (obj != nullptr) {
689 obj->DecRefCount();
690 }
691 }
692
SetColorFilter(const JSCallbackInfo & info)693 void JSImage::SetColorFilter(const JSCallbackInfo& info)
694 {
695 if (info.Length() != 1) {
696 ImageModel::GetInstance()->SetColorFilterMatrix(DEFAULT_COLORFILTER_MATRIX);
697 return;
698 }
699 auto tmpInfo = info[0];
700 if (!tmpInfo->IsArray() && !tmpInfo->IsObject()) {
701 ImageModel::GetInstance()->SetColorFilterMatrix(DEFAULT_COLORFILTER_MATRIX);
702 return;
703 }
704 if (tmpInfo->IsObject() && !tmpInfo->IsArray()) {
705 auto drawingColorFilter = CreateDrawingColorFilter(tmpInfo);
706 if (drawingColorFilter) {
707 ImageModel::GetInstance()->SetDrawingColorFilter(drawingColorFilter);
708 return;
709 }
710 JSColorFilter* colorFilter;
711 if (!tmpInfo->IsUndefined() && !tmpInfo->IsNull()) {
712 colorFilter = JSRef<JSObject>::Cast(tmpInfo)->Unwrap<JSColorFilter>();
713 } else {
714 ImageModel::GetInstance()->SetColorFilterMatrix(DEFAULT_COLORFILTER_MATRIX);
715 return;
716 }
717 if (colorFilter && colorFilter->GetColorFilterMatrix().size() == COLOR_FILTER_MATRIX_SIZE) {
718 ImageModel::GetInstance()->SetColorFilterMatrix(colorFilter->GetColorFilterMatrix());
719 return;
720 }
721 ImageModel::GetInstance()->SetColorFilterMatrix(DEFAULT_COLORFILTER_MATRIX);
722 return;
723 }
724 JSRef<JSArray> array = JSRef<JSArray>::Cast(tmpInfo);
725 if (array->Length() != COLOR_FILTER_MATRIX_SIZE) {
726 ImageModel::GetInstance()->SetColorFilterMatrix(DEFAULT_COLORFILTER_MATRIX);
727 return;
728 }
729 std::vector<float> colorfilter;
730 for (size_t i = 0; i < array->Length(); i++) {
731 JSRef<JSVal> value = array->GetValueAt(i);
732 if (value->IsNumber()) {
733 colorfilter.emplace_back(value->ToNumber<float>());
734 } else {
735 ImageModel::GetInstance()->SetColorFilterMatrix(DEFAULT_COLORFILTER_MATRIX);
736 return;
737 }
738 }
739 ImageModel::GetInstance()->SetColorFilterMatrix(colorfilter);
740 }
741
SetSmoothEdge(const JSCallbackInfo & info)742 void JSImage::SetSmoothEdge(const JSCallbackInfo& info)
743 {
744 if (info.Length() != 1) {
745 ImageModel::GetInstance()->SetSmoothEdge(DEFAULT_SMOOTHEDGE_VALUE);
746 return;
747 }
748 double parseRes = DEFAULT_SMOOTHEDGE_VALUE;
749 ParseJsDouble(info[0], parseRes);
750 // Effective range : (FLOOR_SMOOTHEDGE_VALUE, CEIL_SMOOTHEDGE_VALUE]
751 // otherwise: DEFAULT_SMOOTHEDGE_VALUE
752 if (GreatNotEqual(parseRes, CEIL_SMOOTHEDGE_VALUE) || LessNotEqual(parseRes, FLOOR_SMOOTHEDGE_VALUE)) {
753 parseRes = DEFAULT_SMOOTHEDGE_VALUE;
754 }
755 ImageModel::GetInstance()->SetSmoothEdge(static_cast<float>(parseRes));
756 }
757
SetDynamicRangeMode(const JSCallbackInfo & info)758 void JSImage::SetDynamicRangeMode(const JSCallbackInfo& info)
759 {
760 if (info.Length() < 1) {
761 ImageModel::GetInstance()->SetDynamicRangeMode(DynamicRangeMode::STANDARD);
762 return;
763 }
764 int32_t parseRes = static_cast<int32_t>(DynamicRangeMode::STANDARD);
765 ParseJsInteger(info[0], parseRes);
766 if (parseRes < static_cast<int32_t>(DynamicRangeMode::HIGH) ||
767 parseRes > static_cast<int32_t>(DynamicRangeMode::STANDARD)) {
768 parseRes = static_cast<int32_t>(DynamicRangeMode::STANDARD);
769 }
770 DynamicRangeMode dynamicRangeMode = static_cast<DynamicRangeMode>(parseRes);
771 ImageModel::GetInstance()->SetDynamicRangeMode(dynamicRangeMode);
772 }
773
SetEnhancedImageQuality(const JSCallbackInfo & info)774 void JSImage::SetEnhancedImageQuality(const JSCallbackInfo& info)
775 {
776 if (info.Length() < 1) {
777 ImageModel::GetInstance()->SetEnhancedImageQuality(AIImageQuality::LOW);
778 return;
779 }
780 int32_t parseRes = static_cast<int32_t>(AIImageQuality::LOW);
781 ParseJsInteger(info[0], parseRes);
782 if (parseRes < static_cast<int32_t>(AIImageQuality::LOW) || parseRes > static_cast<int32_t>(AIImageQuality::HIGH)) {
783 parseRes = static_cast<int32_t>(AIImageQuality::LOW);
784 }
785 AIImageQuality resolutionQuality = static_cast<AIImageQuality>(parseRes);
786 ImageModel::GetInstance()->SetEnhancedImageQuality(resolutionQuality);
787 }
788
SetOrientation(const JSCallbackInfo & info)789 void JSImage::SetOrientation(const JSCallbackInfo& info)
790 {
791 if (info.Length() < 1) {
792 ImageModel::GetInstance()->SetOrientation(ImageRotateOrientation::UP);
793 return;
794 }
795 int32_t parseRes = 0;
796 ParseJsInteger(info[0], parseRes);
797 if (parseRes < static_cast<int>(ImageRotateOrientation::AUTO) ||
798 parseRes > static_cast<int>(ImageRotateOrientation::LEFT)) {
799 parseRes = static_cast<int>(ImageRotateOrientation::UP);
800 }
801 auto res = static_cast<ImageRotateOrientation>(parseRes);
802 ImageModel::GetInstance()->SetOrientation(res);
803 }
804
CreateImageAnimation(std::vector<RefPtr<PixelMap>> & pixelMaps,int32_t duration,int32_t iterations)805 void JSImage::CreateImageAnimation(std::vector<RefPtr<PixelMap>>& pixelMaps, int32_t duration, int32_t iterations)
806 {
807 std::vector<ImageProperties> imageList;
808 for (int i = 0; i < static_cast<int32_t>(pixelMaps.size()); i++) {
809 ImageProperties image;
810 image.pixelMap = pixelMaps[i];
811 imageList.push_back(image);
812 }
813 ImageModel::GetInstance()->CreateAnimation(imageList, duration, iterations);
814 }
815
JSBind(BindingTarget globalObj)816 void JSImage::JSBind(BindingTarget globalObj)
817 {
818 JSClass<JSImage>::Declare("Image");
819 MethodOptions opt = MethodOptions::NONE;
820 JSClass<JSImage>::StaticMethod("create", &JSImage::Create, opt);
821 JSClass<JSImage>::StaticMethod("alt", &JSImage::SetAlt, opt);
822 JSClass<JSImage>::StaticMethod("objectFit", &JSImage::SetObjectFit, opt);
823 JSClass<JSImage>::StaticMethod("matchTextDirection", &JSImage::SetMatchTextDirection, opt);
824 JSClass<JSImage>::StaticMethod("fitOriginalSize", &JSImage::SetFitOriginalSize, opt);
825 JSClass<JSImage>::StaticMethod("sourceSize", &JSImage::SetSourceSize, opt);
826 JSClass<JSImage>::StaticMethod("fillColor", &JSImage::SetImageFill, opt);
827 JSClass<JSImage>::StaticMethod("renderMode", &JSImage::SetImageRenderMode, opt);
828 JSClass<JSImage>::StaticMethod("objectRepeat", &JSImage::SetImageRepeat, opt);
829 JSClass<JSImage>::StaticMethod("interpolation", &JSImage::SetImageInterpolation, opt);
830 JSClass<JSImage>::StaticMethod("colorFilter", &JSImage::SetColorFilter, opt);
831 JSClass<JSImage>::StaticMethod("edgeAntialiasing", &JSImage::SetSmoothEdge, opt);
832 JSClass<JSImage>::StaticMethod("dynamicRangeMode", &JSImage::SetDynamicRangeMode, opt);
833 JSClass<JSImage>::StaticMethod("enhancedImageQuality", &JSImage::SetEnhancedImageQuality, opt);
834 JSClass<JSImage>::StaticMethod("orientation", &JSImage::SetOrientation, opt);
835
836 JSClass<JSImage>::StaticMethod("border", &JSImage::JsBorder);
837 JSClass<JSImage>::StaticMethod("borderRadius", &JSImage::JsBorderRadius);
838 JSClass<JSImage>::StaticMethod("onAttach", &JSInteractableView::JsOnAttach);
839 JSClass<JSImage>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
840 JSClass<JSImage>::StaticMethod("onDetach", &JSInteractableView::JsOnDetach);
841 JSClass<JSImage>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
842 JSClass<JSImage>::StaticMethod("autoResize", &JSImage::SetAutoResize);
843 JSClass<JSImage>::StaticMethod("resizable", &JSImage::JsImageResizable);
844
845 JSClass<JSImage>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
846 JSClass<JSImage>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
847 JSClass<JSImage>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
848 JSClass<JSImage>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
849 JSClass<JSImage>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
850 JSClass<JSImage>::StaticMethod("onComplete", &JSImage::OnComplete);
851 JSClass<JSImage>::StaticMethod("onError", &JSImage::OnError);
852 JSClass<JSImage>::StaticMethod("onFinish", &JSImage::OnFinish);
853 JSClass<JSImage>::StaticMethod("syncLoad", &JSImage::SetSyncLoad);
854 JSClass<JSImage>::StaticMethod("remoteMessage", &JSInteractableView::JsCommonRemoteMessage);
855 JSClass<JSImage>::StaticMethod("draggable", &JSImage::JsSetDraggable);
856 JSClass<JSImage>::StaticMethod("onDragStart", &JSImage::JsOnDragStart);
857 JSClass<JSImage>::StaticMethod("copyOption", &JSImage::SetCopyOption);
858 JSClass<JSImage>::StaticMethod("enableAnalyzer", &JSImage::EnableAnalyzer);
859 JSClass<JSImage>::StaticMethod("analyzerConfig", &JSImage::AnalyzerConfig);
860
861 // override method
862 JSClass<JSImage>::StaticMethod("opacity", &JSImage::JsOpacity);
863 JSClass<JSImage>::StaticMethod("blur", &JSImage::JsBlur);
864 JSClass<JSImage>::StaticMethod("transition", &JSImage::JsTransition);
865 JSClass<JSImage>::StaticMethod("pointLight", &JSViewAbstract::JsPointLight, opt);
866 JSClass<JSImage>::InheritAndBind<JSViewAbstract>(globalObj);
867
868 JSClass<JSColorFilter>::Declare("ColorFilter");
869 JSClass<JSColorFilter>::Bind(globalObj, JSColorFilter::ConstructorCallback, JSColorFilter::DestructorCallback);
870 }
871
JsSetDraggable(bool draggable)872 void JSImage::JsSetDraggable(bool draggable)
873 {
874 ImageModel::GetInstance()->SetDraggable(draggable);
875 }
876
JsOnDragStart(const JSCallbackInfo & info)877 void JSImage::JsOnDragStart(const JSCallbackInfo& info)
878 {
879 if (info.Length() != 1 || !info[0]->IsFunction()) {
880 return;
881 }
882 RefPtr<JsDragFunction> jsOnDragStartFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
883 WeakPtr<NG::FrameNode> frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
884 auto onDragStartId = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragStartFunc), node = frameNode](
885 const RefPtr<DragEvent>& info, const std::string& extraParams) -> NG::DragDropBaseInfo {
886 NG::DragDropBaseInfo itemInfo;
887 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, itemInfo);
888 PipelineContext::SetCallBackNode(node);
889 auto ret = func->Execute(info, extraParams);
890 if (!ret->IsObject()) {
891 return itemInfo;
892 }
893 if (ParseAndUpdateDragItemInfo(ret, itemInfo)) {
894 return itemInfo;
895 }
896
897 auto builderObj = JSRef<JSObject>::Cast(ret);
898 #if defined(PIXEL_MAP_SUPPORTED)
899 auto pixmap = builderObj->GetProperty("pixelMap");
900 itemInfo.pixelMap = CreatePixelMapFromNapiValue(pixmap);
901 #endif
902 auto extraInfo = builderObj->GetProperty("extraInfo");
903 ParseJsString(extraInfo, itemInfo.extraInfo);
904 ParseAndUpdateDragItemInfo(builderObj->GetProperty("builder"), itemInfo);
905 return itemInfo;
906 };
907 ImageModel::GetInstance()->SetOnDragStart(std::move(onDragStartId));
908 }
909
SetCopyOption(const JSCallbackInfo & info)910 void JSImage::SetCopyOption(const JSCallbackInfo& info)
911 {
912 if (ImageModel::GetInstance()->GetIsAnimation()) {
913 return;
914 }
915 auto copyOptions = CopyOptions::None;
916 if (info[0]->IsNumber()) {
917 auto enumNumber = info[0]->ToNumber<int>();
918 copyOptions = static_cast<CopyOptions>(enumNumber);
919 if (copyOptions < CopyOptions::None || copyOptions > CopyOptions::Distributed) {
920 copyOptions = CopyOptions::None;
921 }
922 }
923 ImageModel::GetInstance()->SetCopyOption(copyOptions);
924 }
925
EnableAnalyzer(bool isEnableAnalyzer)926 void JSImage::EnableAnalyzer(bool isEnableAnalyzer)
927 {
928 if (ImageModel::GetInstance()->GetIsAnimation()) {
929 return;
930 }
931 ImageModel::GetInstance()->EnableAnalyzer(isEnableAnalyzer);
932 }
933
AnalyzerConfig(const JSCallbackInfo & info)934 void JSImage::AnalyzerConfig(const JSCallbackInfo& info)
935 {
936 auto configParams = info[0];
937 if (configParams->IsNull() || !configParams->IsObject()) {
938 return;
939 }
940 auto engine = EngineHelper::GetCurrentEngine();
941 CHECK_NULL_VOID(engine);
942 NativeEngine* nativeEngine = engine->GetNativeEngine();
943 CHECK_NULL_VOID(nativeEngine);
944 panda::Local<JsiValue> value = configParams.Get().GetLocalHandle();
945 JSValueWrapper valueWrapper = value;
946 ScopeRAII scope(reinterpret_cast<napi_env>(nativeEngine));
947 napi_value nativeValue = nativeEngine->ValueToNapiValue(valueWrapper);
948 ImageModel::GetInstance()->SetImageAnalyzerConfig(nativeValue);
949
950 // As an example, the function is not in effect.
951 auto paramObject = JSRef<JSObject>::Cast(configParams);
952 JSRef<JSVal> typeVal = paramObject->GetProperty("types");
953 ImageAnalyzerConfig analyzerConfig;
954 if (typeVal->IsArray()) {
955 auto array = JSRef<JSArray>::Cast(typeVal);
956 std::set<ImageAnalyzerType> types;
957 for (size_t i = 0; i < array->Length(); ++i) {
958 if (!array->GetValueAt(i)->IsNumber()) {
959 continue;
960 }
961 int value = array->GetValueAt(i)->ToNumber<int>();
962 ImageAnalyzerType type = static_cast<ImageAnalyzerType>(value);
963 if (type != ImageAnalyzerType::SUBJECT && type != ImageAnalyzerType::TEXT) {
964 continue;
965 }
966 types.insert(type);
967 }
968 analyzerConfig.types = std::move(types);
969 }
970 ImageModel::GetInstance()->SetImageAnalyzerConfig(analyzerConfig);
971 }
972
973 } // namespace OHOS::Ace::Framework
974