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