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 "frameworks/bridge/declarative_frontend/jsview/js_image.h"
17 #include <cstdint>
18 #include <memory>
19 #include <vector>
20 #include "core/components_ng/base/view_abstract_model.h"
21 #if !defined(PREVIEW) && defined(OHOS_PLATFORM)
22 #include "interfaces/inner_api/ui_session/ui_session_manager.h"
23 #endif
24 #include "base/utils/utils.h"
25 
26 #if !defined(PREVIEW)
27 #include <dlfcn.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 "bridge/common/utils/engine_helper.h"
37 #include "bridge/declarative_frontend/engine/functions/js_drag_function.h"
38 #include "bridge/declarative_frontend/engine/js_ref_ptr.h"
39 #include "bridge/declarative_frontend/engine/js_types.h"
40 #include "bridge/declarative_frontend/engine/jsi/js_ui_index.h"
41 #include "bridge/declarative_frontend/jsview/models/image_model_impl.h"
42 #include "core/common/container.h"
43 #include "core/components/image/image_event.h"
44 #include "core/components/image/image_theme.h"
45 #include "core/components_ng/base/view_stack_processor.h"
46 #include "core/components_ng/event/gesture_event_hub.h"
47 #include "core/components_ng/pattern/image/image_model.h"
48 #include "core/components_ng/pattern/image/image_model_ng.h"
49 #include "core/image/image_source_info.h"
50 #include "interfaces/inner_api/ace/ai/image_analyzer.h"
51 
52 namespace {
53     const std::vector<float> DEFAULT_COLORFILTER_MATRIX = {
54         1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0
55     };
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 }
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 = 2;
181     ParseJsInteger(args[0], parseRes);
182     if (parseRes < static_cast<int32_t>(ImageFit::FILL) || parseRes > static_cast<int32_t>(ImageFit::BOTTOM_END)) {
183         parseRes = 2;
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     bool isCard = CheckIsCard();
296 
297     // Interim programme
298     std::string bundleName;
299     std::string moduleName;
300     std::string src;
301     auto imageInfo = info[0];
302     int32_t resId = 0;
303     bool srcValid = ParseJsMediaWithBundleName(imageInfo, src, bundleName, moduleName, resId);
304     if (!srcValid && CheckResetImage(info)) {
305         return;
306     }
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     );
336     ImageModel::GetInstance()->Create(imageInfoConfig, pixmap);
337 
338     if (info.Length() > 1) {
339         auto options = info[1];
340         if (!options->IsObject()) {
341             return;
342         }
343         auto engine = EngineHelper::GetCurrentEngine();
344         CHECK_NULL_VOID(engine);
345         NativeEngine* nativeEngine = engine->GetNativeEngine();
346         panda::Local<JsiValue> value = options.Get().GetLocalHandle();
347         JSValueWrapper valueWrapper = value;
348         ScopeRAII scope(reinterpret_cast<napi_env>(nativeEngine));
349         napi_value optionsValue = nativeEngine->ValueToNapiValue(valueWrapper);
350         ImageModel::GetInstance()->SetImageAIOptions(optionsValue);
351     }
352 }
353 
IsDrawable(const JSRef<JSVal>& jsValue)354 bool JSImage::IsDrawable(const JSRef<JSVal>& jsValue)
355 {
356     if (!jsValue->IsObject()) {
357         return false;
358     }
359     JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(jsValue);
360     if (jsObj->IsUndefined()) {
361         return false;
362     }
363 
364     // if jsObject has function getPixelMap, it's a DrawableDescriptor object
365     JSRef<JSVal> func = jsObj->GetProperty("getPixelMap");
366     return (!func->IsNull() && func->IsFunction());
367 }
368 
JsBorder(const JSCallbackInfo& info)369 void JSImage::JsBorder(const JSCallbackInfo& info)
370 {
371     if (Container::LessThanAPIVersion(PlatformVersion::VERSION_FOURTEEN)) {
372         JSViewAbstract::JsBorder(info);
373         ImageModel::GetInstance()->SetBackBorder();
374         return;
375     }
376     // handles generic property logic.
377     JSViewAbstract::JsBorder(info);
378     // handles the image component separately, aiming to extract and set the borderRadius property
379     if (!info[0]->IsObject()) {
380         CalcDimension borderRadius;
381         ImageModel::GetInstance()->SetBorderRadius(borderRadius);
382         return;
383     }
384     JSRef<JSObject> object = JSRef<JSObject>::Cast(info[0]);
385 
386     auto valueRadius = object->GetProperty(static_cast<int32_t>(ArkUIIndex::RADIUS));
387     if (!valueRadius->IsUndefined()) {
388         ParseBorderRadius(valueRadius);
389     }
390 }
391 
ParseBorderRadius(const JSRef<JSVal>& args)392 void JSImage::ParseBorderRadius(const JSRef<JSVal>& args)
393 {
394     CalcDimension borderRadius;
395     if (ParseJsDimensionVp(args, borderRadius)) {
396         ViewAbstractModel::GetInstance()->SetBorderRadius(borderRadius);
397         ImageModel::GetInstance()->SetBorderRadius(borderRadius);
398     } else if (args->IsObject()) {
399         JSRef<JSObject> object = JSRef<JSObject>::Cast(args);
400         CalcDimension topLeft;
401         CalcDimension topRight;
402         CalcDimension bottomLeft;
403         CalcDimension bottomRight;
404         if (ParseAllBorderRadiuses(object, topLeft, topRight, bottomLeft, bottomRight)) {
405             ImageModel::GetInstance()->SetBorderRadius(
406                 GetLocalizedBorderRadius(topLeft, topRight, bottomLeft, bottomRight));
407             ViewAbstractModel::GetInstance()->SetBorderRadius(
408                 GetLocalizedBorderRadius(topLeft, topRight, bottomLeft, bottomRight));
409             return;
410         }
411         ImageModel::GetInstance()->SetBorderRadius(topLeft, topRight, bottomLeft, bottomRight);
412         ViewAbstractModel::GetInstance()->SetBorderRadius(topLeft, topRight, bottomLeft, bottomRight);
413     }
414 }
415 
ParseResizableSlice(const JSRef<JSObject>& resizableObject)416 void JSImage::ParseResizableSlice(const JSRef<JSObject>& resizableObject)
417 {
418     ImageResizableSlice sliceResult;
419     if (resizableObject->IsEmpty()) {
420         ImageModel::GetInstance()->SetResizableSlice(sliceResult);
421         return;
422     }
423     auto sliceValue = resizableObject->GetProperty("slice");
424     if (!sliceValue->IsObject()) {
425         ImageModel::GetInstance()->SetResizableSlice(sliceResult);
426         return;
427     }
428     JSRef<JSObject> sliceObj = JSRef<JSObject>::Cast(sliceValue);
429     if (sliceObj->IsEmpty()) {
430         ImageModel::GetInstance()->SetResizableSlice(sliceResult);
431         return;
432     }
433     UpdateSliceResult(sliceObj, sliceResult);
434 
435     ImageModel::GetInstance()->SetResizableSlice(sliceResult);
436 }
437 
ParseResizableLattice(const JSRef<JSObject>& resizableObject)438 void JSImage::ParseResizableLattice(const JSRef<JSObject>& resizableObject)
439 {
440     auto latticeValue = resizableObject->GetProperty("lattice");
441     if (latticeValue->IsUndefined() || latticeValue->IsNull()) {
442         ImageModel::GetInstance()->ResetResizableLattice();
443     }
444     CHECK_NULL_VOID(latticeValue->IsObject());
445     auto drawingLattice = CreateDrawingLattice(latticeValue);
446     if (drawingLattice) {
447         ImageModel::GetInstance()->SetResizableLattice(drawingLattice);
448     } else {
449         ImageModel::GetInstance()->ResetResizableLattice();
450     }
451 }
452 
JsImageResizable(const JSCallbackInfo& info)453 void JSImage::JsImageResizable(const JSCallbackInfo& info)
454 {
455     if (ImageModel::GetInstance()->GetIsAnimation()) {
456         return;
457     }
458     auto infoObj = info[0];
459     if (!infoObj->IsObject()) {
460         ImageModel::GetInstance()->SetResizableSlice(ImageResizableSlice());
461         return;
462     }
463     JSRef<JSObject> resizableObject = JSRef<JSObject>::Cast(infoObj);
464     ParseResizableSlice(resizableObject);
465     ParseResizableLattice(resizableObject);
466 }
467 
UpdateSliceResult(const JSRef<JSObject>& sliceObj, ImageResizableSlice& sliceResult)468 void JSImage::UpdateSliceResult(const JSRef<JSObject>& sliceObj, ImageResizableSlice& sliceResult)
469 {
470     // creatge a array has 4 elements for paresing sliceSize
471     static std::array<int32_t, 4> keys = {
472         static_cast<int32_t>(ArkUIIndex::LEFT), static_cast<int32_t>(ArkUIIndex::RIGHT),
473         static_cast<int32_t>(ArkUIIndex::TOP), static_cast<int32_t>(ArkUIIndex::BOTTOM)};
474     for (uint32_t i = 0; i < keys.size(); i++) {
475         auto sliceSize = sliceObj->GetProperty(keys.at(i));
476         CalcDimension sliceDimension;
477         if (!ParseJsDimensionVp(sliceSize, sliceDimension)) {
478             continue;
479         }
480         if (!sliceDimension.IsValid()) {
481             continue;
482         }
483         switch (static_cast<BorderImageDirection>(i)) {
484             case BorderImageDirection::LEFT:
485                 sliceResult.left = sliceDimension;
486                 break;
487             case BorderImageDirection::RIGHT:
488                 sliceResult.right = sliceDimension;
489                 break;
490             case BorderImageDirection::TOP:
491                 sliceResult.top = sliceDimension;
492                 break;
493             case BorderImageDirection::BOTTOM:
494                 sliceResult.bottom = sliceDimension;
495                 break;
496             default:
497                 break;
498         }
499     }
500     ImageModel::GetInstance()->SetResizableSlice(sliceResult);
501 }
502 
JsBorderRadius(const JSCallbackInfo& info)503 void JSImage::JsBorderRadius(const JSCallbackInfo& info)
504 {
505     if (Container::LessThanAPIVersion(PlatformVersion::VERSION_FOURTEEN)) {
506         JSViewAbstract::JsBorderRadius(info);
507         ImageModel::GetInstance()->SetBackBorder();
508         return;
509     }
510     static std::vector<JSCallbackInfoType> checkList { JSCallbackInfoType::STRING, JSCallbackInfoType::NUMBER,
511         JSCallbackInfoType::OBJECT };
512     auto jsVal = info[0];
513     if (!CheckJSCallbackInfo("JsBorderRadius", jsVal, checkList)) {
514         ViewAbstractModel::GetInstance()->SetBorderRadius(Dimension {});
515         ImageModel::GetInstance()->SetBorderRadius(Dimension {});
516         return;
517     }
518     ParseBorderRadius(jsVal);
519 }
520 
SetSourceSize(const JSCallbackInfo& info)521 void JSImage::SetSourceSize(const JSCallbackInfo& info)
522 {
523     if (ImageModel::GetInstance()->GetIsAnimation()) {
524         return;
525     }
526     ImageModel::GetInstance()->SetImageSourceSize(JSViewAbstract::ParseSize(info));
527 }
528 
SetImageFill(const JSCallbackInfo& info)529 void JSImage::SetImageFill(const JSCallbackInfo& info)
530 {
531     if (ImageModel::GetInstance()->GetIsAnimation()) {
532         return;
533     }
534     if (info.Length() < 1) {
535         return;
536     }
537 
538     Color color;
539     if (!ParseJsColor(info[0], color)) {
540         if (Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
541             return;
542         }
543         auto pipelineContext = PipelineBase::GetCurrentContext();
544         CHECK_NULL_VOID(pipelineContext);
545         auto theme = pipelineContext->GetTheme<ImageTheme>();
546         CHECK_NULL_VOID(theme);
547         color = theme->GetFillColor();
548     }
549     ImageModel::GetInstance()->SetImageFill(color);
550 }
551 
SetImageRenderMode(const JSCallbackInfo& info)552 void JSImage::SetImageRenderMode(const JSCallbackInfo& info)
553 {
554     if (ImageModel::GetInstance()->GetIsAnimation()) {
555         return;
556     }
557     if (info.Length() < 1) {
558         ImageModel::GetInstance()->SetImageRenderMode(ImageRenderMode::ORIGINAL);
559         return;
560     }
561     auto jsImageRenderMode = info[0];
562     if (jsImageRenderMode->IsNumber()) {
563         auto renderMode = static_cast<ImageRenderMode>(jsImageRenderMode->ToNumber<int32_t>());
564         if (renderMode < ImageRenderMode::ORIGINAL || renderMode > ImageRenderMode::TEMPLATE) {
565             renderMode = ImageRenderMode::ORIGINAL;
566         }
567         ImageModel::GetInstance()->SetImageRenderMode(renderMode);
568     } else {
569         ImageModel::GetInstance()->SetImageRenderMode(ImageRenderMode::ORIGINAL);
570     }
571 }
572 
SetImageInterpolation(int32_t imageInterpolation)573 void JSImage::SetImageInterpolation(int32_t imageInterpolation)
574 {
575     if (ImageModel::GetInstance()->GetIsAnimation()) {
576         return;
577     }
578     auto interpolation = static_cast<ImageInterpolation>(imageInterpolation);
579     if (interpolation < ImageInterpolation::NONE || interpolation > ImageInterpolation::HIGH) {
580         interpolation = ImageInterpolation::NONE;
581     }
582     ImageModel::GetInstance()->SetImageInterpolation(interpolation);
583 }
584 
SetImageRepeat(int32_t imageRepeat)585 void JSImage::SetImageRepeat(int32_t imageRepeat)
586 {
587     auto repeat = static_cast<ImageRepeat>(imageRepeat);
588     if (repeat < ImageRepeat::NO_REPEAT || repeat > ImageRepeat::REPEAT) {
589         repeat = ImageRepeat::NO_REPEAT;
590     }
591     ImageModel::GetInstance()->SetImageRepeat(repeat);
592 }
593 
JsTransition(const JSCallbackInfo& info)594 void JSImage::JsTransition(const JSCallbackInfo& info)
595 {
596     if (ImageModel::GetInstance()->IsSrcSvgImage()) {
597         JSViewAbstract::JsTransition(info);
598     } else {
599         JSViewAbstract::JsTransitionPassThrough(info);
600     }
601 }
602 
JsOpacity(const JSCallbackInfo& info)603 void JSImage::JsOpacity(const JSCallbackInfo& info)
604 {
605     if (ImageModel::GetInstance()->IsSrcSvgImage()) {
606         JSViewAbstract::JsOpacity(info);
607     } else {
608         JSViewAbstract::JsOpacityPassThrough(info);
609     }
610 }
611 
JsBlur(const JSCallbackInfo& info)612 void JSImage::JsBlur(const JSCallbackInfo& info)
613 {
614 // only flutter runs special image blur
615 #ifdef ENABLE_ROSEN_BACKEND
616     JSViewAbstract::JsBlur(info);
617 #else
618     if (info.Length() < 1) {
619         return;
620     }
621     double blur = 0.0;
622     if (ParseJsDouble(info[0], blur)) {
623         ImageModel::GetInstance()->SetBlur(blur);
624     }
625 #endif
626 }
627 
SetAutoResize(bool autoResize)628 void JSImage::SetAutoResize(bool autoResize)
629 {
630     if (ImageModel::GetInstance()->GetIsAnimation()) {
631         return;
632     }
633     ImageModel::GetInstance()->SetAutoResize(autoResize);
634 }
635 
SetSyncLoad(const JSCallbackInfo& info)636 void JSImage::SetSyncLoad(const JSCallbackInfo& info)
637 {
638     if (ImageModel::GetInstance()->GetIsAnimation()) {
639         return;
640     }
641     if (info.Length() < 1) {
642         return;
643     }
644     auto tmpInfo = info[0];
645     if (!tmpInfo->IsBoolean()) {
646         return;
647     }
648     ImageModel::GetInstance()->SetSyncMode(tmpInfo->ToBoolean());
649 }
650 
ConstructorCallback(const JSCallbackInfo& args)651 void JSColorFilter::ConstructorCallback(const JSCallbackInfo& args)
652 {
653     if (args.Length() < 1) {
654         return;
655     }
656     auto tmpInfo = args[0];
657     if (!tmpInfo->IsArray()) {
658         return;
659     }
660     JSRef<JSArray> array = JSRef<JSArray>::Cast(tmpInfo);
661     if (array->Length() != COLOR_FILTER_MATRIX_SIZE) {
662         return;
663     }
664     auto jscolorfilter = Referenced::MakeRefPtr<JSColorFilter>();
665     if (jscolorfilter == nullptr) {
666         return;
667     }
668     std::vector<float> colorfilter;
669     for (size_t i = 0; i < array->Length(); i++) {
670         JSRef<JSVal> value = array->GetValueAt(i);
671         if (value->IsNumber()) {
672             colorfilter.emplace_back(value->ToNumber<float>());
673         }
674     }
675     if (colorfilter.size() != COLOR_FILTER_MATRIX_SIZE) {
676         return;
677     }
678     jscolorfilter->SetColorFilterMatrix(std::move(colorfilter));
679     jscolorfilter->IncRefCount();
680     args.SetReturnValue(Referenced::RawPtr(jscolorfilter));
681 }
682 
DestructorCallback(JSColorFilter* obj)683 void JSColorFilter::DestructorCallback(JSColorFilter* obj)
684 {
685     if (obj != nullptr) {
686         obj->DecRefCount();
687     }
688 }
689 
SetColorFilter(const JSCallbackInfo& info)690 void JSImage::SetColorFilter(const JSCallbackInfo& info)
691 {
692     if (info.Length() != 1) {
693         ImageModel::GetInstance()->SetColorFilterMatrix(DEFAULT_COLORFILTER_MATRIX);
694         return;
695     }
696     auto tmpInfo = info[0];
697     if (!tmpInfo->IsArray() && !tmpInfo->IsObject()) {
698         ImageModel::GetInstance()->SetColorFilterMatrix(DEFAULT_COLORFILTER_MATRIX);
699         return;
700     }
701     if (tmpInfo->IsObject() && !tmpInfo->IsArray()) {
702         auto drawingColorFilter = CreateDrawingColorFilter(tmpInfo);
703         if (drawingColorFilter) {
704             ImageModel::GetInstance()->SetDrawingColorFilter(drawingColorFilter);
705             return;
706         }
707         JSColorFilter* colorFilter;
708         if (!tmpInfo->IsUndefined() && !tmpInfo->IsNull()) {
709             colorFilter = JSRef<JSObject>::Cast(tmpInfo)->Unwrap<JSColorFilter>();
710         } else {
711             ImageModel::GetInstance()->SetColorFilterMatrix(DEFAULT_COLORFILTER_MATRIX);
712             return;
713         }
714         if (colorFilter && colorFilter->GetColorFilterMatrix().size() == COLOR_FILTER_MATRIX_SIZE) {
715             ImageModel::GetInstance()->SetColorFilterMatrix(colorFilter->GetColorFilterMatrix());
716             return;
717         }
718         ImageModel::GetInstance()->SetColorFilterMatrix(DEFAULT_COLORFILTER_MATRIX);
719         return;
720     }
721     JSRef<JSArray> array = JSRef<JSArray>::Cast(tmpInfo);
722     if (array->Length() != COLOR_FILTER_MATRIX_SIZE) {
723         ImageModel::GetInstance()->SetColorFilterMatrix(DEFAULT_COLORFILTER_MATRIX);
724         return;
725     }
726     std::vector<float> colorfilter;
727     for (size_t i = 0; i < array->Length(); i++) {
728         JSRef<JSVal> value = array->GetValueAt(i);
729         if (value->IsNumber()) {
730             colorfilter.emplace_back(value->ToNumber<float>());
731         } else {
732             ImageModel::GetInstance()->SetColorFilterMatrix(DEFAULT_COLORFILTER_MATRIX);
733             return;
734         }
735     }
736     ImageModel::GetInstance()->SetColorFilterMatrix(colorfilter);
737 }
738 
SetSmoothEdge(const JSCallbackInfo& info)739 void JSImage::SetSmoothEdge(const JSCallbackInfo& info)
740 {
741     if (info.Length() != 1) {
742         ImageModel::GetInstance()->SetSmoothEdge(DEFAULT_SMOOTHEDGE_VALUE);
743         return;
744     }
745     double parseRes = DEFAULT_SMOOTHEDGE_VALUE;
746     ParseJsDouble(info[0], parseRes);
747     // Effective range : (FLOOR_SMOOTHEDGE_VALUE, CEIL_SMOOTHEDGE_VALUE]
748     // otherwise: DEFAULT_SMOOTHEDGE_VALUE
749     if (GreatNotEqual(parseRes, CEIL_SMOOTHEDGE_VALUE) || LessNotEqual(parseRes, FLOOR_SMOOTHEDGE_VALUE)) {
750         parseRes = DEFAULT_SMOOTHEDGE_VALUE;
751     }
752     ImageModel::GetInstance()->SetSmoothEdge(static_cast<float>(parseRes));
753 }
754 
SetDynamicRangeMode(const JSCallbackInfo& info)755 void JSImage::SetDynamicRangeMode(const JSCallbackInfo& info)
756 {
757     if (info.Length() < 1) {
758         ImageModel::GetInstance()->SetDynamicRangeMode(DynamicRangeMode::STANDARD);
759         return;
760     }
761     int32_t parseRes = static_cast<int32_t>(DynamicRangeMode::STANDARD);
762     ParseJsInteger(info[0], parseRes);
763     if (parseRes < static_cast<int32_t>(DynamicRangeMode::HIGH) ||
764         parseRes > static_cast<int32_t>(DynamicRangeMode::STANDARD)) {
765         parseRes = static_cast<int32_t>(DynamicRangeMode::STANDARD);
766     }
767     DynamicRangeMode dynamicRangeMode = static_cast<DynamicRangeMode>(parseRes);
768     ImageModel::GetInstance()->SetDynamicRangeMode(dynamicRangeMode);
769 }
770 
SetEnhancedImageQuality(const JSCallbackInfo& info)771 void JSImage::SetEnhancedImageQuality(const JSCallbackInfo& info)
772 {
773     if (info.Length() < 1) {
774         ImageModel::GetInstance()->SetEnhancedImageQuality(AIImageQuality::LOW);
775         return;
776     }
777     int32_t parseRes = static_cast<int32_t>(AIImageQuality::LOW);
778     ParseJsInteger(info[0], parseRes);
779     if (parseRes < static_cast<int32_t>(AIImageQuality::LOW) ||
780         parseRes > static_cast<int32_t>(AIImageQuality::HIGH)) {
781         parseRes = static_cast<int32_t>(AIImageQuality::LOW);
782     }
783     AIImageQuality resolutionQuality  = static_cast<AIImageQuality>(parseRes);
784     ImageModel::GetInstance()->SetEnhancedImageQuality(resolutionQuality);
785 }
786 
CreateImageAnimation(std::vector<RefPtr<PixelMap>>& pixelMaps, int32_t duration, int32_t iterations)787 void JSImage::CreateImageAnimation(std::vector<RefPtr<PixelMap>>& pixelMaps, int32_t duration, int32_t iterations)
788 {
789     std::vector<ImageProperties> imageList;
790     for (int i = 0; i < static_cast<int32_t>(pixelMaps.size()); i++) {
791         ImageProperties image;
792         image.pixelMap = pixelMaps[i];
793         imageList.push_back(image);
794     }
795     ImageModel::GetInstance()->CreateAnimation(imageList, duration, iterations);
796 }
797 
JSBind(BindingTarget globalObj)798 void JSImage::JSBind(BindingTarget globalObj)
799 {
800     JSClass<JSImage>::Declare("Image");
801     MethodOptions opt = MethodOptions::NONE;
802     JSClass<JSImage>::StaticMethod("create", &JSImage::Create, opt);
803     JSClass<JSImage>::StaticMethod("alt", &JSImage::SetAlt, opt);
804     JSClass<JSImage>::StaticMethod("objectFit", &JSImage::SetObjectFit, opt);
805     JSClass<JSImage>::StaticMethod("matchTextDirection", &JSImage::SetMatchTextDirection, opt);
806     JSClass<JSImage>::StaticMethod("fitOriginalSize", &JSImage::SetFitOriginalSize, opt);
807     JSClass<JSImage>::StaticMethod("sourceSize", &JSImage::SetSourceSize, opt);
808     JSClass<JSImage>::StaticMethod("fillColor", &JSImage::SetImageFill, opt);
809     JSClass<JSImage>::StaticMethod("renderMode", &JSImage::SetImageRenderMode, opt);
810     JSClass<JSImage>::StaticMethod("objectRepeat", &JSImage::SetImageRepeat, opt);
811     JSClass<JSImage>::StaticMethod("interpolation", &JSImage::SetImageInterpolation, opt);
812     JSClass<JSImage>::StaticMethod("colorFilter", &JSImage::SetColorFilter, opt);
813     JSClass<JSImage>::StaticMethod("edgeAntialiasing", &JSImage::SetSmoothEdge, opt);
814     JSClass<JSImage>::StaticMethod("dynamicRangeMode", &JSImage::SetDynamicRangeMode, opt);
815     JSClass<JSImage>::StaticMethod("enhancedImageQuality", &JSImage::SetEnhancedImageQuality, opt);
816 
817     JSClass<JSImage>::StaticMethod("border", &JSImage::JsBorder);
818     JSClass<JSImage>::StaticMethod("borderRadius", &JSImage::JsBorderRadius);
819     JSClass<JSImage>::StaticMethod("onAttach", &JSInteractableView::JsOnAttach);
820     JSClass<JSImage>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
821     JSClass<JSImage>::StaticMethod("onDetach", &JSInteractableView::JsOnDetach);
822     JSClass<JSImage>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
823     JSClass<JSImage>::StaticMethod("autoResize", &JSImage::SetAutoResize);
824     JSClass<JSImage>::StaticMethod("resizable", &JSImage::JsImageResizable);
825 
826     JSClass<JSImage>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
827     JSClass<JSImage>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
828     JSClass<JSImage>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
829     JSClass<JSImage>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
830     JSClass<JSImage>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
831     JSClass<JSImage>::StaticMethod("onComplete", &JSImage::OnComplete);
832     JSClass<JSImage>::StaticMethod("onError", &JSImage::OnError);
833     JSClass<JSImage>::StaticMethod("onFinish", &JSImage::OnFinish);
834     JSClass<JSImage>::StaticMethod("syncLoad", &JSImage::SetSyncLoad);
835     JSClass<JSImage>::StaticMethod("remoteMessage", &JSInteractableView::JsCommonRemoteMessage);
836     JSClass<JSImage>::StaticMethod("draggable", &JSImage::JsSetDraggable);
837     JSClass<JSImage>::StaticMethod("onDragStart", &JSImage::JsOnDragStart);
838     JSClass<JSImage>::StaticMethod("copyOption", &JSImage::SetCopyOption);
839     JSClass<JSImage>::StaticMethod("enableAnalyzer", &JSImage::EnableAnalyzer);
840     JSClass<JSImage>::StaticMethod("analyzerConfig", &JSImage::AnalyzerConfig);
841 
842     // override method
843     JSClass<JSImage>::StaticMethod("opacity", &JSImage::JsOpacity);
844     JSClass<JSImage>::StaticMethod("blur", &JSImage::JsBlur);
845     JSClass<JSImage>::StaticMethod("transition", &JSImage::JsTransition);
846     JSClass<JSImage>::StaticMethod("pointLight", &JSViewAbstract::JsPointLight, opt);
847     JSClass<JSImage>::InheritAndBind<JSViewAbstract>(globalObj);
848 
849     JSClass<JSColorFilter>::Declare("ColorFilter");
850     JSClass<JSColorFilter>::Bind(globalObj, JSColorFilter::ConstructorCallback, JSColorFilter::DestructorCallback);
851 }
852 
JsSetDraggable(const JSCallbackInfo& info)853 void JSImage::JsSetDraggable(const JSCallbackInfo& info)
854 {
855     bool draggable = Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_FOURTEEN);
856     if (info.Length() > 0 && info[0]->IsBoolean()) {
857         draggable = info[0]->ToBoolean();
858     }
859     ImageModel::GetInstance()->SetDraggable(draggable);
860 }
861 
JsOnDragStart(const JSCallbackInfo& info)862 void JSImage::JsOnDragStart(const JSCallbackInfo& info)
863 {
864     if (info.Length() != 1 || !info[0]->IsFunction()) {
865         return;
866     }
867     RefPtr<JsDragFunction> jsOnDragStartFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
868     WeakPtr<NG::FrameNode> frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
869     auto onDragStartId = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragStartFunc), node = frameNode](
870                              const RefPtr<DragEvent>& info, const std::string& extraParams) -> NG::DragDropBaseInfo {
871         NG::DragDropBaseInfo itemInfo;
872         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, itemInfo);
873         PipelineContext::SetCallBackNode(node);
874         auto ret = func->Execute(info, extraParams);
875         if (!ret->IsObject()) {
876             return itemInfo;
877         }
878         if (ParseAndUpdateDragItemInfo(ret, itemInfo)) {
879             return itemInfo;
880         }
881 
882         auto builderObj = JSRef<JSObject>::Cast(ret);
883 #if defined(PIXEL_MAP_SUPPORTED)
884         auto pixmap = builderObj->GetProperty("pixelMap");
885         itemInfo.pixelMap = CreatePixelMapFromNapiValue(pixmap);
886 #endif
887         auto extraInfo = builderObj->GetProperty("extraInfo");
888         ParseJsString(extraInfo, itemInfo.extraInfo);
889         ParseAndUpdateDragItemInfo(builderObj->GetProperty("builder"), itemInfo);
890         return itemInfo;
891     };
892     ImageModel::GetInstance()->SetOnDragStart(std::move(onDragStartId));
893 }
894 
SetCopyOption(const JSCallbackInfo& info)895 void JSImage::SetCopyOption(const JSCallbackInfo& info)
896 {
897     if (ImageModel::GetInstance()->GetIsAnimation()) {
898         return;
899     }
900     auto copyOptions = CopyOptions::None;
901     if (info[0]->IsNumber()) {
902         auto enumNumber = info[0]->ToNumber<int>();
903         copyOptions = static_cast<CopyOptions>(enumNumber);
904         if (copyOptions < CopyOptions::None || copyOptions > CopyOptions::Distributed) {
905             copyOptions = CopyOptions::None;
906         }
907     }
908     ImageModel::GetInstance()->SetCopyOption(copyOptions);
909 }
910 
EnableAnalyzer(bool isEnableAnalyzer)911 void JSImage::EnableAnalyzer(bool isEnableAnalyzer)
912 {
913     if (ImageModel::GetInstance()->GetIsAnimation()) {
914         return;
915     }
916     ImageModel::GetInstance()->EnableAnalyzer(isEnableAnalyzer);
917 }
918 
AnalyzerConfig(const JSCallbackInfo &info)919 void JSImage::AnalyzerConfig(const JSCallbackInfo &info)
920 {
921     auto configParams = info[0];
922     if (configParams->IsNull() || !configParams->IsObject()) {
923         return;
924     }
925     auto engine = EngineHelper::GetCurrentEngine();
926     CHECK_NULL_VOID(engine);
927     NativeEngine* nativeEngine = engine->GetNativeEngine();
928     CHECK_NULL_VOID(nativeEngine);
929     panda::Local<JsiValue> value = configParams.Get().GetLocalHandle();
930     JSValueWrapper valueWrapper = value;
931     ScopeRAII scope(reinterpret_cast<napi_env>(nativeEngine));
932     napi_value nativeValue = nativeEngine->ValueToNapiValue(valueWrapper);
933     ImageModel::GetInstance()->SetImageAnalyzerConfig(nativeValue);
934 
935     // As an example, the function is not in effect.
936     auto paramObject = JSRef<JSObject>::Cast(configParams);
937     JSRef<JSVal> typeVal = paramObject->GetProperty("types");
938     ImageAnalyzerConfig analyzerConfig;
939     if (typeVal->IsArray()) {
940         auto array = JSRef<JSArray>::Cast(typeVal);
941         std::set<ImageAnalyzerType> types;
942         for (size_t i = 0; i < array->Length(); ++i) {
943             if (!array->GetValueAt(i)->IsNumber()) {
944                 continue;
945             }
946             int value = array->GetValueAt(i)->ToNumber<int>();
947             ImageAnalyzerType type = static_cast<ImageAnalyzerType>(value);
948             if (type != ImageAnalyzerType::SUBJECT && type != ImageAnalyzerType::TEXT) {
949                 continue;
950             }
951             types.insert(type);
952         }
953         analyzerConfig.types = std::move(types);
954     }
955     ImageModel::GetInstance()->SetImageAnalyzerConfig(analyzerConfig);
956 }
957 
958 } // namespace OHOS::Ace::Framework
959