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