• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-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 "core/image/image_source_info.h"
17 #define NAPI_VERSION 8
18 
19 #include <array>
20 #include <cstdint>
21 
22 #include "base/geometry/dimension_offset.h"
23 #include "base/geometry/matrix4.h"
24 #include "base/geometry/ng/rect_t.h"
25 #include "base/geometry/ng/vector.h"
26 #include "base/log/dump_log.h"
27 #include "base/utils/utils.h"
28 #include "core/common/ai/image_analyzer_mgr.h"
29 #include "core/common/frontend.h"
30 #include "core/components/common/layout/constants.h"
31 #include "core/components/image/image_theme.h"
32 #include "core/components/theme/icon_theme.h"
33 #include "core/components_ng/base/view_stack_processor.h"
34 #include "core/components_ng/event/event_hub.h"
35 #include "core/components_ng/pattern/image/image_layout_property.h"
36 #include "core/components_ng/pattern/image/image_paint_method.h"
37 #include "core/components_ng/pattern/image/image_pattern.h"
38 #include "core/components_ng/property/measure_property.h"
39 #include "core/pipeline_ng/pipeline_context.h"
40 #include "frameworks/bridge/common/utils/engine_helper.h"
41 #if defined(PIXEL_MAP_SUPPORTED) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
42 #include "foundation/multimedia/image_framework/interfaces/kits/js/common/include/pixel_map_napi.h"
43 #endif
44 #include "core/common/ace_engine_ext.h"
45 #include "core/common/udmf/udmf_client.h"
46 
47 namespace OHOS::Ace::NG {
ConvertPixmapNapi(const RefPtr<PixelMap> & pixelMap)48 napi_value ConvertPixmapNapi(const RefPtr<PixelMap>& pixelMap)
49 {
50 #if defined(PIXEL_MAP_SUPPORTED) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
51     auto engine = EngineHelper::GetCurrentEngine();
52     CHECK_NULL_RETURN(engine, {});
53     NativeEngine* nativeEngine = engine->GetNativeEngine();
54     auto* env = reinterpret_cast<napi_env>(nativeEngine);
55     napi_value napiValue = OHOS::Media::PixelMapNapi::CreatePixelMap(env, pixelMap->GetPixelMapSharedPtr());
56     return napiValue;
57 #else
58     return nullptr;
59 #endif
60 }
61 
CreateDataReadyCallback()62 DataReadyNotifyTask ImagePattern::CreateDataReadyCallback()
63 {
64     return [weak = WeakClaim(this)](const ImageSourceInfo& sourceInfo) {
65         auto pattern = weak.Upgrade();
66         CHECK_NULL_VOID(pattern);
67         auto imageLayoutProperty = pattern->GetLayoutProperty<ImageLayoutProperty>();
68         CHECK_NULL_VOID(imageLayoutProperty);
69         auto currentSourceInfo = imageLayoutProperty->GetImageSourceInfo().value_or(ImageSourceInfo(""));
70         if (currentSourceInfo != sourceInfo) {
71             TAG_LOGW(AceLogTag::ACE_IMAGE,
72                 "sourceInfo does not match, ignore current callback. "
73                 "current: %{public}s vs callback's: %{public}s",
74                 currentSourceInfo.ToString().c_str(), sourceInfo.ToString().c_str());
75             return;
76         }
77         pattern->OnImageDataReady();
78     };
79 }
80 
CreateLoadSuccessCallback()81 LoadSuccessNotifyTask ImagePattern::CreateLoadSuccessCallback()
82 {
83     return [weak = WeakClaim(this)](const ImageSourceInfo& sourceInfo) {
84         auto pattern = weak.Upgrade();
85         CHECK_NULL_VOID(pattern);
86         auto imageLayoutProperty = pattern->GetLayoutProperty<ImageLayoutProperty>();
87         CHECK_NULL_VOID(imageLayoutProperty);
88         auto currentSourceInfo = imageLayoutProperty->GetImageSourceInfo().value_or(ImageSourceInfo(""));
89         if (currentSourceInfo != sourceInfo) {
90             TAG_LOGW(AceLogTag::ACE_IMAGE,
91                 "sourceInfo does not match, ignore current callback. "
92                 "current: %{public}s vs callback's: %{public}s",
93                 currentSourceInfo.ToString().c_str(), sourceInfo.ToString().c_str());
94             return;
95         }
96         pattern->OnImageLoadSuccess();
97     };
98 }
99 
CreateLoadFailCallback()100 LoadFailNotifyTask ImagePattern::CreateLoadFailCallback()
101 {
102     return [weak = WeakClaim(this)](const ImageSourceInfo& sourceInfo, const std::string& errorMsg) {
103         auto pattern = weak.Upgrade();
104         CHECK_NULL_VOID(pattern);
105         auto imageLayoutProperty = pattern->GetLayoutProperty<ImageLayoutProperty>();
106         CHECK_NULL_VOID(imageLayoutProperty);
107         auto currentSourceInfo = imageLayoutProperty->GetImageSourceInfo().value_or(ImageSourceInfo(""));
108         if (currentSourceInfo != sourceInfo) {
109             TAG_LOGW(AceLogTag::ACE_IMAGE,
110                 "sourceInfo does not match, ignore current callback. "
111                 "current: %{public}s vs callback's: %{public}s",
112                 currentSourceInfo.ToString().c_str(), sourceInfo.ToString().c_str());
113             return;
114         }
115         pattern->OnImageLoadFail(errorMsg);
116     };
117 }
118 
PrepareAnimation(const RefPtr<CanvasImage> & image)119 void ImagePattern::PrepareAnimation(const RefPtr<CanvasImage>& image)
120 {
121     if (image->IsStatic()) {
122         return;
123     }
124     SetRedrawCallback(image);
125     RegisterVisibleAreaChange();
126     auto layoutProps = GetLayoutProperty<LayoutProperty>();
127     CHECK_NULL_VOID(layoutProps);
128     // pause animation if prop is initially set to invisible
129     if (layoutProps->GetVisibility().value_or(VisibleType::VISIBLE) != VisibleType::VISIBLE) {
130         image->ControlAnimation(false);
131     }
132 }
133 
SetRedrawCallback(const RefPtr<CanvasImage> & image)134 void ImagePattern::SetRedrawCallback(const RefPtr<CanvasImage>& image)
135 {
136     CHECK_NULL_VOID(image);
137     // set animation flush function for svg / gif
138     image->SetRedrawCallback([weak = WeakPtr(GetHost())] {
139         auto imageNode = weak.Upgrade();
140         CHECK_NULL_VOID(imageNode);
141         imageNode->MarkNeedRenderOnly();
142     });
143 }
144 
RegisterVisibleAreaChange()145 void ImagePattern::RegisterVisibleAreaChange()
146 {
147     auto pipeline = PipelineContext::GetCurrentContext();
148     // register to onVisibleAreaChange
149     CHECK_NULL_VOID(pipeline);
150     auto callback = [weak = WeakClaim(this)](bool visible, double ratio) {
151         auto self = weak.Upgrade();
152         CHECK_NULL_VOID(self);
153         self->OnVisibleChange(visible);
154     };
155     auto host = GetHost();
156     CHECK_NULL_VOID(host);
157     // add visibleAreaChangeNode(inner callback)
158     pipeline->AddVisibleAreaChangeNode(host, 0.0f, callback, false);
159 }
160 
CalcImageContentPaintSize(const RefPtr<GeometryNode> & geometryNode)161 RectF ImagePattern::CalcImageContentPaintSize(const RefPtr<GeometryNode>& geometryNode)
162 {
163     RectF paintSize;
164     auto imageRenderProperty = GetPaintProperty<ImageRenderProperty>();
165     CHECK_NULL_RETURN(imageRenderProperty, paintSize);
166     ImageRepeat repeat = imageRenderProperty->GetImageRepeat().value_or(ImageRepeat::NO_REPEAT);
167     bool imageRepeatX = repeat == ImageRepeat::REPEAT || repeat == ImageRepeat::REPEAT_X;
168     bool imageRepeatY = repeat == ImageRepeat::REPEAT || repeat == ImageRepeat::REPEAT_Y;
169 
170     if (loadingCtx_->GetSourceInfo().IsSvg()) {
171         const float invalidValue = -1;
172         paintSize.SetWidth(dstRect_.IsValid() ? dstRect_.Width() : invalidValue);
173         paintSize.SetHeight(dstRect_.IsValid() ? dstRect_.Height() : invalidValue);
174         paintSize.SetLeft(
175             dstRect_.IsValid() ? dstRect_.GetX() + geometryNode->GetContentOffset().GetX() : invalidValue);
176         paintSize.SetTop(dstRect_.IsValid() ? dstRect_.GetY() + geometryNode->GetContentOffset().GetY() : invalidValue);
177     } else {
178         paintSize.SetWidth(imageRepeatX ? geometryNode->GetContentSize().Width() : dstRect_.Width());
179         paintSize.SetHeight(imageRepeatY ? geometryNode->GetContentSize().Height() : dstRect_.Height());
180         paintSize.SetLeft((imageRepeatX ? 0 : dstRect_.GetX()) + geometryNode->GetContentOffset().GetX());
181         paintSize.SetTop((imageRepeatY ? 0 : dstRect_.GetY()) + geometryNode->GetContentOffset().GetY());
182     }
183     return paintSize;
184 }
185 
OnImageLoadSuccess()186 void ImagePattern::OnImageLoadSuccess()
187 {
188     CHECK_NULL_VOID(loadingCtx_);
189     auto host = GetHost();
190     CHECK_NULL_VOID(host);
191     const auto& geometryNode = host->GetGeometryNode();
192     CHECK_NULL_VOID(geometryNode);
193 
194     image_ = loadingCtx_->MoveCanvasImage();
195     srcRect_ = loadingCtx_->GetSrcRect();
196     dstRect_ = loadingCtx_->GetDstRect();
197 
198     RectF paintRect = CalcImageContentPaintSize(geometryNode);
199     LoadImageSuccessEvent event(loadingCtx_->GetImageSize().Width(), loadingCtx_->GetImageSize().Height(),
200         geometryNode->GetFrameSize().Width(), geometryNode->GetFrameSize().Height(), 1, paintRect.Width(),
201         paintRect.Height(), paintRect.GetX(), paintRect.GetY());
202     auto eventHub = GetEventHub<ImageEventHub>();
203     if (eventHub) {
204         eventHub->FireCompleteEvent(event);
205     }
206 
207     SetImagePaintConfig(image_, srcRect_, dstRect_, loadingCtx_->GetSourceInfo(), loadingCtx_->GetFrameCount());
208     PrepareAnimation(image_);
209     if (host->IsDraggable()) {
210         EnableDrag();
211     }
212     // clear alt data
213     altLoadingCtx_ = nullptr;
214     altImage_ = nullptr;
215     altDstRect_.reset();
216     altSrcRect_.reset();
217 
218     if (!IsSupportImageAnalyzerFeature() && isAnalyzerOverlayBuild_) {
219         DeleteAnalyzerOverlay();
220     }
221     UpdateAnalyzerOverlay();
222 
223     auto currentContext = PipelineContext::GetCurrentContext();
224     CHECK_NULL_VOID(currentContext);
225     int32_t instanceID = currentContext->GetInstanceId();
226     auto context = host->GetContext();
227     CHECK_NULL_VOID(context);
228     auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
229     uiTaskExecutor.PostTask([weak = WeakClaim(this), instanceID] {
230         ContainerScope scope(instanceID);
231         auto pattern = weak.Upgrade();
232         CHECK_NULL_VOID(pattern);
233         pattern->CreateAnalyzerOverlay();
234     });
235     host->MarkNeedRenderOnly();
236 }
237 
OnImageDataReady()238 void ImagePattern::OnImageDataReady()
239 {
240     CHECK_NULL_VOID(loadingCtx_);
241     auto host = GetHost();
242     CHECK_NULL_VOID(host);
243     const auto& geometryNode = host->GetGeometryNode();
244     CHECK_NULL_VOID(geometryNode);
245     auto imageEventHub = GetEventHub<ImageEventHub>();
246     CHECK_NULL_VOID(imageEventHub);
247     LoadImageSuccessEvent event(loadingCtx_->GetImageSize().Width(), loadingCtx_->GetImageSize().Height(),
248         geometryNode->GetFrameSize().Width(), geometryNode->GetFrameSize().Height(), 0,
249         geometryNode->GetContentSize().Width(), geometryNode->GetContentSize().Height(),
250         geometryNode->GetContentOffset().GetX(), geometryNode->GetContentOffset().GetY());
251     imageEventHub->FireCompleteEvent(event);
252 
253     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
254 }
255 
OnImageLoadFail(const std::string & errorMsg)256 void ImagePattern::OnImageLoadFail(const std::string& errorMsg)
257 {
258     auto host = GetHost();
259     CHECK_NULL_VOID(host);
260     const auto& geometryNode = host->GetGeometryNode();
261     auto imageEventHub = GetEventHub<ImageEventHub>();
262     CHECK_NULL_VOID(imageEventHub);
263     LoadImageFailEvent event(geometryNode->GetFrameSize().Width(), geometryNode->GetFrameSize().Height(), errorMsg);
264     imageEventHub->FireErrorEvent(event);
265 }
266 
SetImagePaintConfig(const RefPtr<CanvasImage> & canvasImage,const RectF & srcRect,const RectF & dstRect,const ImageSourceInfo & sourceInfo,int32_t frameCount)267 void ImagePattern::SetImagePaintConfig(const RefPtr<CanvasImage>& canvasImage, const RectF& srcRect,
268     const RectF& dstRect, const ImageSourceInfo& sourceInfo, int32_t frameCount)
269 {
270     auto layoutProps = GetLayoutProperty<ImageLayoutProperty>();
271     CHECK_NULL_VOID(layoutProps);
272 
273     ImagePaintConfig config {
274         .srcRect_ = srcRect,
275         .dstRect_ = dstRect,
276     };
277     config.imageFit_ = layoutProps->GetImageFit().value_or(ImageFit::COVER);
278     config.isSvg_ = sourceInfo.IsSvg();
279     config.frameCount_ = frameCount;
280     config.sourceInfo_ = sourceInfo;
281     auto host = GetHost();
282     if (!host) {
283         canvasImage->SetPaintConfig(config);
284         return;
285     }
286     auto renderContext = host->GetRenderContext();
287     if (!renderContext || !renderContext->HasBorderRadius()) {
288         canvasImage->SetPaintConfig(config);
289         return;
290     }
291 
292     auto renderProps = host->GetPaintProperty<ImageRenderProperty>();
293     if (renderProps) {
294         renderProps->UpdateNeedBorderRadius(true);
295     }
296     canvasImage->SetPaintConfig(config);
297 }
298 
CreateNodePaintMethod()299 RefPtr<NodePaintMethod> ImagePattern::CreateNodePaintMethod()
300 {
301     if (image_) {
302         return MakeRefPtr<ImagePaintMethod>(image_, selectOverlay_, interpolationDefault_);
303     }
304     if (altImage_ && altDstRect_ && altSrcRect_) {
305         return MakeRefPtr<ImagePaintMethod>(altImage_, selectOverlay_, interpolationDefault_);
306     }
307     CreateObscuredImage();
308     if (obscuredImage_) {
309         return MakeRefPtr<ImagePaintMethod>(obscuredImage_, selectOverlay_, interpolationDefault_);
310     }
311     return nullptr;
312 }
313 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)314 bool ImagePattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
315 {
316     if (config.skipMeasure || dirty->SkipMeasureContent()) {
317         return false;
318     }
319 
320     if (loadingCtx_) {
321         auto renderProp = GetPaintProperty<ImageRenderProperty>();
322         if (renderProp && renderProp->HasImageResizableSlice() && image_) {
323             loadingCtx_->ResizableCalcDstSize();
324             SetImagePaintConfig(image_, loadingCtx_->GetSrcRect(), loadingCtx_->GetDstRect(), loadingCtx_->GetSrc(),
325                 loadingCtx_->GetFrameCount());
326         }
327     }
328 
329     if (altLoadingCtx_) {
330         auto renderProp = GetPaintProperty<ImageRenderProperty>();
331         if (renderProp && renderProp->HasImageResizableSlice() && altImage_) {
332             altLoadingCtx_->ResizableCalcDstSize();
333             SetImagePaintConfig(altImage_, altLoadingCtx_->GetSrcRect(), altLoadingCtx_->GetDstRect(),
334                 altLoadingCtx_->GetSrc(), altLoadingCtx_->GetFrameCount());
335         }
336     }
337 
338     if (IsSupportImageAnalyzerFeature()) {
339         UpdateAnalyzerUIConfig(dirty->GetGeometryNode());
340     }
341 
342     return image_ || altImage_;
343 }
344 
CreateObscuredImage()345 void ImagePattern::CreateObscuredImage()
346 {
347     auto props = GetLayoutProperty<ImageLayoutProperty>();
348     CHECK_NULL_VOID(props);
349     auto layoutConstraint = props->GetLayoutConstraint();
350     CHECK_NULL_VOID(layoutConstraint);
351     auto host = GetHost();
352     CHECK_NULL_VOID(host);
353     auto sourceInfo = props->GetImageSourceInfo().value_or(ImageSourceInfo(""));
354     auto reasons = host->GetRenderContext()->GetObscured().value_or(std::vector<ObscuredReasons>());
355     if (reasons.size() && layoutConstraint->selfIdealSize.IsValid()) {
356         if (!obscuredImage_) {
357             obscuredImage_ = MakeRefPtr<ObscuredImage>();
358             SetImagePaintConfig(obscuredImage_, srcRect_, dstRect_, sourceInfo);
359         }
360     }
361 }
362 
LoadImage(const ImageSourceInfo & src)363 void ImagePattern::LoadImage(const ImageSourceInfo& src)
364 {
365     LoadNotifier loadNotifier(CreateDataReadyCallback(), CreateLoadSuccessCallback(), CreateLoadFailCallback());
366 
367     loadingCtx_ = AceType::MakeRefPtr<ImageLoadingContext>(src, std::move(loadNotifier), syncLoad_);
368     if (SystemProperties::GetDebugEnabled()) {
369         TAG_LOGI(AceLogTag::ACE_IMAGE, "start loading image %{public}s", src.ToString().c_str());
370     }
371     loadingCtx_->LoadImageData();
372 }
373 
LoadAltImage(const ImageSourceInfo & altImageSourceInfo)374 void ImagePattern::LoadAltImage(const ImageSourceInfo& altImageSourceInfo)
375 {
376     LoadNotifier altLoadNotifier(CreateDataReadyCallbackForAlt(), CreateLoadSuccessCallbackForAlt(), nullptr);
377     if (!altLoadingCtx_ || altLoadingCtx_->GetSourceInfo() != altImageSourceInfo ||
378         (altLoadingCtx_ && altImageSourceInfo.IsSvg())) {
379         altLoadingCtx_ = AceType::MakeRefPtr<ImageLoadingContext>(altImageSourceInfo, std::move(altLoadNotifier));
380         altLoadingCtx_->LoadImageData();
381     }
382 }
383 
LoadImageDataIfNeed()384 void ImagePattern::LoadImageDataIfNeed()
385 {
386     auto imageLayoutProperty = GetLayoutProperty<ImageLayoutProperty>();
387     CHECK_NULL_VOID(imageLayoutProperty);
388     auto src = imageLayoutProperty->GetImageSourceInfo().value_or(ImageSourceInfo(""));
389     UpdateInternalResource(src);
390 
391     if (!loadingCtx_ || loadingCtx_->GetSourceInfo() != src) {
392         LoadImage(src);
393     } else {
394         auto currentContext = PipelineContext::GetCurrentContext();
395         CHECK_NULL_VOID(currentContext);
396         int32_t instanceID = currentContext->GetInstanceId();
397         auto host = GetHost();
398         CHECK_NULL_VOID(host);
399         auto context = host->GetContext();
400         CHECK_NULL_VOID(context);
401         auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
402         uiTaskExecutor.PostTask([weak = WeakClaim(this), instanceID] {
403             ContainerScope scope(instanceID);
404             auto pattern = weak.Upgrade();
405             CHECK_NULL_VOID(pattern);
406             pattern->CreateAnalyzerOverlay();
407             if (pattern->IsSupportImageAnalyzerFeature()) {
408                 auto host = pattern->GetHost();
409                 pattern->UpdateAnalyzerUIConfig(host->GetGeometryNode());
410             }
411         });
412     }
413     if (loadingCtx_->NeedAlt() && imageLayoutProperty->GetAlt()) {
414         auto altImageSourceInfo = imageLayoutProperty->GetAlt().value_or(ImageSourceInfo(""));
415         LoadAltImage(altImageSourceInfo);
416     }
417 }
418 
UpdateGestureAndDragWhenModify()419 void ImagePattern::UpdateGestureAndDragWhenModify()
420 {
421     // remove long press and mouse events
422     auto host = GetHost();
423     CHECK_NULL_VOID(host);
424 
425     auto gestureHub = host->GetOrCreateGestureEventHub();
426     if (longPressEvent_) {
427         gestureHub->SetLongPressEvent(nullptr);
428         longPressEvent_ = nullptr;
429     }
430 
431     if (clickEvent_) {
432         gestureHub->RemoveClickEvent(clickEvent_);
433         clickEvent_ = nullptr;
434     }
435 
436     if (mouseEvent_) {
437         auto inputHub = host->GetOrCreateInputEventHub();
438         inputHub->RemoveOnMouseEvent(mouseEvent_);
439         mouseEvent_ = nullptr;
440     }
441 
442     if (host->IsDraggable()) {
443         EnableDrag();
444     }
445 }
446 
OnModifyDone()447 void ImagePattern::OnModifyDone()
448 {
449     Pattern::OnModifyDone();
450     LoadImageDataIfNeed();
451 
452     if (copyOption_ != CopyOptions::None) {
453         auto host = GetHost();
454         CHECK_NULL_VOID(host);
455         bool hasObscured = false;
456         if (host->GetRenderContext()->GetObscured().has_value()) {
457             auto obscuredReasons = host->GetRenderContext()->GetObscured().value();
458             hasObscured = std::any_of(obscuredReasons.begin(), obscuredReasons.end(),
459                 [](const auto& reason) { return reason == ObscuredReasons::PLACEHOLDER; });
460         }
461         if (!hasObscured) {
462             InitCopy();
463             return;
464         }
465     }
466 
467     CloseSelectOverlay();
468 
469     auto host = GetHost();
470     CHECK_NULL_VOID(host);
471 
472     UpdateGestureAndDragWhenModify();
473 
474     if (isAnalyzerOverlayBuild_) {
475         if (!IsSupportImageAnalyzerFeature()) {
476             DeleteAnalyzerOverlay();
477         } else {
478             UpdateAnalyzerOverlayLayout();
479         }
480     }
481 
482     // SetUsingContentRectForRenderFrame is set for image paint
483     auto overlayNode = host->GetOverlayNode();
484     if (overlayNode) {
485         auto layoutProperty = host->GetLayoutProperty();
486         CHECK_NULL_VOID(layoutProperty);
487         auto padding = layoutProperty->CreatePaddingAndBorder();
488         auto renderContext = overlayNode->GetRenderContext();
489         if (renderContext) {
490             renderContext->SetRenderFrameOffset({-padding.Offset().GetX(), -padding.Offset().GetY()});
491         }
492     }
493 }
494 
CreateDataReadyCallbackForAlt()495 DataReadyNotifyTask ImagePattern::CreateDataReadyCallbackForAlt()
496 {
497     return [weak = WeakClaim(this)](const ImageSourceInfo& sourceInfo) {
498         auto pattern = weak.Upgrade();
499         CHECK_NULL_VOID(pattern);
500         auto imageLayoutProperty = pattern->GetLayoutProperty<ImageLayoutProperty>();
501         CHECK_NULL_VOID(imageLayoutProperty);
502         auto currentAltSourceInfo = imageLayoutProperty->GetAlt().value_or(ImageSourceInfo(""));
503         if (currentAltSourceInfo != sourceInfo) {
504             TAG_LOGW(AceLogTag::ACE_IMAGE,
505                 "alt image sourceInfo does not match, ignore current callback. "
506                 "current: %{public}s vs callback's: %{public}s",
507                 currentAltSourceInfo.ToString().c_str(), sourceInfo.ToString().c_str());
508             return;
509         }
510         auto host = pattern->GetHost();
511         CHECK_NULL_VOID(host);
512         if (!host->IsActive()) {
513             return;
514         }
515         const auto& geometryNode = host->GetGeometryNode();
516         CHECK_NULL_VOID(geometryNode);
517         if (!geometryNode->GetContent()) {
518             host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
519             return;
520         }
521 
522         // calculate params for [altLoadingCtx] to do [MakeCanvasImage] if component size is already settled
523         pattern->altLoadingCtx_->MakeCanvasImageIfNeed(
524             geometryNode->GetContentSize(), true, imageLayoutProperty->GetImageFit().value_or(ImageFit::COVER));
525     };
526 }
527 
CreateLoadSuccessCallbackForAlt()528 LoadSuccessNotifyTask ImagePattern::CreateLoadSuccessCallbackForAlt()
529 {
530     return [weak = WeakClaim(this)](const ImageSourceInfo& sourceInfo) {
531         auto pattern = weak.Upgrade();
532         CHECK_NULL_VOID(pattern);
533         CHECK_NULL_VOID(pattern->altLoadingCtx_);
534         auto layoutProps = pattern->GetLayoutProperty<ImageLayoutProperty>();
535         auto currentAltSrc = layoutProps->GetAlt().value_or(ImageSourceInfo(""));
536         if (currentAltSrc != sourceInfo) {
537             TAG_LOGW(AceLogTag::ACE_IMAGE,
538                 "alt image sourceInfo does not match, ignore current callback. "
539                 "current: %{public}s vs callback's: %{public}s",
540                 currentAltSrc.ToString().c_str(), sourceInfo.ToString().c_str());
541             return;
542         }
543         pattern->altImage_ = pattern->altLoadingCtx_->MoveCanvasImage();
544         pattern->altSrcRect_ = std::make_unique<RectF>(pattern->altLoadingCtx_->GetSrcRect());
545         pattern->altDstRect_ = std::make_unique<RectF>(pattern->altLoadingCtx_->GetDstRect());
546         pattern->SetImagePaintConfig(pattern->altImage_, *pattern->altSrcRect_, *pattern->altDstRect_,
547             pattern->altLoadingCtx_->GetSourceInfo(), pattern->altLoadingCtx_->GetFrameCount());
548 
549         pattern->PrepareAnimation(pattern->altImage_);
550 
551         auto host = pattern->GetHost();
552         CHECK_NULL_VOID(host);
553         host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
554     };
555 }
556 
UpdateInternalResource(ImageSourceInfo & sourceInfo)557 void ImagePattern::UpdateInternalResource(ImageSourceInfo& sourceInfo)
558 {
559     if (!sourceInfo.IsInternalResource()) {
560         return;
561     }
562 
563     auto pipeline = PipelineBase::GetCurrentContext();
564     CHECK_NULL_VOID(pipeline);
565     auto iconTheme = pipeline->GetTheme<IconTheme>();
566     CHECK_NULL_VOID(iconTheme);
567     auto iconPath = iconTheme->GetIconPath(sourceInfo.GetResourceId());
568     if (!iconPath.empty()) {
569         sourceInfo.SetSrc(iconPath, sourceInfo.GetFillColor());
570         auto imageLayoutProperty = GetLayoutProperty<ImageLayoutProperty>();
571         CHECK_NULL_VOID(imageLayoutProperty);
572         imageLayoutProperty->UpdateImageSourceInfo(sourceInfo);
573     }
574 }
575 
OnNotifyMemoryLevel(int32_t level)576 void ImagePattern::OnNotifyMemoryLevel(int32_t level)
577 {
578     // TODO: do different data cleaning operation according to level
579     // when image component is [onShow], do not clean image data
580     // TODO: use [isActive_] to determine image data management
581     if (isShow_) {
582         return;
583     }
584 
585     // clean image data
586     loadingCtx_ = nullptr;
587     image_ = nullptr;
588     altLoadingCtx_ = nullptr;
589     altImage_ = nullptr;
590 
591     // clean rs node to release the sk_sp<SkImage> held by it
592     // TODO: release PixelMap resource when use PixelMap resource to draw image
593     auto frameNode = GetHost();
594     CHECK_NULL_VOID(frameNode);
595     auto rsRenderContext = frameNode->GetRenderContext();
596     CHECK_NULL_VOID(rsRenderContext);
597     rsRenderContext->ClearDrawCommands();
598     auto pipeline = PipelineContext::GetCurrentContext();
599     CHECK_NULL_VOID(pipeline);
600     pipeline->FlushMessages();
601 }
602 
603 // when recycle image component, release the pixelmap resource
OnRecycle()604 void ImagePattern::OnRecycle()
605 {
606     loadingCtx_ = nullptr;
607     image_ = nullptr;
608     altLoadingCtx_ = nullptr;
609     altImage_ = nullptr;
610 
611     auto frameNode = GetHost();
612     CHECK_NULL_VOID(frameNode);
613     auto rsRenderContext = frameNode->GetRenderContext();
614     CHECK_NULL_VOID(rsRenderContext);
615     rsRenderContext->ClearDrawCommands();
616     UnregisterWindowStateChangedCallback();
617 }
618 
OnReuse()619 void ImagePattern::OnReuse()
620 {
621     RegisterWindowStateChangedCallback();
622     LoadImageDataIfNeed();
623 }
624 
RegisterWindowStateChangedCallback()625 void ImagePattern::RegisterWindowStateChangedCallback()
626 {
627     auto host = GetHost();
628     CHECK_NULL_VOID(host);
629     auto pipeline = PipelineContext::GetCurrentContext();
630     CHECK_NULL_VOID(pipeline);
631     pipeline->AddWindowStateChangedCallback(host->GetId());
632 }
633 
UnregisterWindowStateChangedCallback()634 void ImagePattern::UnregisterWindowStateChangedCallback()
635 {
636     auto host = GetHost();
637     CHECK_NULL_VOID(host);
638     auto pipeline = PipelineContext::GetCurrentContext();
639     CHECK_NULL_VOID(pipeline);
640     pipeline->RemoveWindowStateChangedCallback(host->GetId());
641 }
642 
OnWindowHide()643 void ImagePattern::OnWindowHide()
644 {
645     isShow_ = false;
646 }
647 
OnWindowShow()648 void ImagePattern::OnWindowShow()
649 {
650     isShow_ = true;
651     LoadImageDataIfNeed();
652 }
653 
OnVisibleChange(bool visible)654 void ImagePattern::OnVisibleChange(bool visible)
655 {
656     if (!visible) {
657         CloseSelectOverlay();
658     }
659     // control svg / gif animation
660     if (image_) {
661         image_->ControlAnimation(visible);
662     } else if (altImage_) {
663         altImage_->ControlAnimation(visible);
664     }
665 }
666 
OnAttachToFrameNode()667 void ImagePattern::OnAttachToFrameNode()
668 {
669     auto host = GetHost();
670     CHECK_NULL_VOID(host);
671     auto renderCtx = host->GetRenderContext();
672     renderCtx->SetClipToBounds(false);
673     renderCtx->SetUsingContentRectForRenderFrame(true);
674 
675     // register image frame node to pipeline context to receive memory level notification and window state change
676     // notification
677     auto pipeline = PipelineContext::GetCurrentContext();
678     CHECK_NULL_VOID(pipeline);
679     pipeline->AddNodesToNotifyMemoryLevel(host->GetId());
680     pipeline->AddWindowStateChangedCallback(host->GetId());
681 }
682 
OnDetachFromFrameNode(FrameNode * frameNode)683 void ImagePattern::OnDetachFromFrameNode(FrameNode* frameNode)
684 {
685     CloseSelectOverlay();
686 
687     auto id = frameNode->GetId();
688     auto pipeline = AceType::DynamicCast<PipelineContext>(PipelineBase::GetCurrentContext());
689     CHECK_NULL_VOID(pipeline);
690     pipeline->RemoveWindowStateChangedCallback(id);
691     pipeline->RemoveNodesToNotifyMemoryLevel(id);
692 }
693 
EnableDrag()694 void ImagePattern::EnableDrag()
695 {
696     auto host = GetHost();
697     CHECK_NULL_VOID(host);
698     auto dragStart = [weak = WeakClaim(this)](const RefPtr<OHOS::Ace::DragEvent>& event, const std::string&
699                          /* extraParams */) -> DragDropInfo {
700         DragDropInfo info;
701         auto imagePattern = weak.Upgrade();
702         CHECK_NULL_RETURN(imagePattern && imagePattern->loadingCtx_, info);
703         AceEngineExt::GetInstance().DragStartExt();
704         imagePattern->UpdateDragEvent(event);
705         info.extraInfo = imagePattern->loadingCtx_->GetSourceInfo().GetSrc();
706         return info;
707     };
708     auto eventHub = host->GetEventHub<EventHub>();
709     CHECK_NULL_VOID(eventHub);
710     if (!eventHub->HasOnDragStart()) {
711         eventHub->SetOnDragStart(std::move(dragStart));
712     }
713 }
714 
BetweenSelectedPosition(const Offset & globalOffset)715 bool ImagePattern::BetweenSelectedPosition(const Offset& globalOffset)
716 {
717     auto host = GetHost();
718     CHECK_NULL_RETURN(host, false);
719     auto globalRect = host->GetTransformRectRelativeToWindow();
720     return globalRect.IsInRegion(PointF { globalOffset.GetX(), globalOffset.GetY() });
721 }
722 
BeforeCreatePaintWrapper()723 void ImagePattern::BeforeCreatePaintWrapper()
724 {
725     auto host = GetHost();
726     CHECK_NULL_VOID(host);
727     host->GetRenderContext()->MarkContentChanged(true);
728 }
729 
InitCopy()730 void ImagePattern::InitCopy()
731 {
732     if (longPressEvent_ && mouseEvent_ && clickEvent_) {
733         return;
734     }
735     auto longPressTask = [weak = WeakClaim(this)](GestureEvent& info) {
736         auto pattern = weak.Upgrade();
737         CHECK_NULL_VOID(pattern);
738         pattern->OpenSelectOverlay();
739     };
740     longPressEvent_ = MakeRefPtr<LongPressEvent>(std::move(longPressTask));
741 
742     auto host = GetHost();
743     CHECK_NULL_VOID(host);
744     auto gestureHub = host->GetOrCreateGestureEventHub();
745     gestureHub->SetLongPressEvent(longPressEvent_);
746 
747     auto mouseTask = [weak = WeakClaim(this)](MouseInfo& info) {
748         if (info.GetButton() == MouseButton::RIGHT_BUTTON && info.GetAction() == MouseAction::PRESS) {
749             auto pattern = weak.Upgrade();
750             CHECK_NULL_VOID(pattern);
751             pattern->OpenSelectOverlay();
752         }
753     };
754     mouseEvent_ = MakeRefPtr<InputEvent>(std::move(mouseTask));
755     auto inputHub = host->GetOrCreateInputEventHub();
756     CHECK_NULL_VOID(inputHub);
757     inputHub->AddOnMouseEvent(mouseEvent_);
758 
759     // close overlay on click
760     clickEvent_ = MakeRefPtr<ClickEvent>([weak = WeakClaim(this)](GestureEvent& callback) {
761         auto pattern = weak.Upgrade();
762         CHECK_NULL_VOID(pattern);
763         pattern->CloseSelectOverlay();
764     });
765     gestureHub->AddClickEvent(clickEvent_);
766 }
767 
OpenSelectOverlay()768 void ImagePattern::OpenSelectOverlay()
769 {
770     auto host = GetHost();
771     CHECK_NULL_VOID(host);
772     auto rect = host->GetTransformRectRelativeToWindow();
773     SelectOverlayInfo info;
774     SizeF handleSize = { SelectHandleInfo::GetDefaultLineWidth().ConvertToPx(), info.singleLineHeight };
775     info.firstHandle.paintRect = RectF(rect.GetOffset(), handleSize);
776     OffsetF offset(rect.Width() - handleSize.Width(), rect.Height() - handleSize.Height());
777     info.secondHandle.paintRect = RectF(rect.GetOffset() + offset, handleSize);
778     info.menuInfo.menuIsShow = true;
779     info.menuInfo.showCut = false;
780     info.menuInfo.showPaste = false;
781     info.menuCallback.onCopy = [weak = WeakClaim(this)]() {
782         auto pattern = weak.Upgrade();
783         CHECK_NULL_VOID(pattern);
784         pattern->HandleCopy();
785         pattern->CloseSelectOverlay();
786     };
787     info.onHandleMoveDone = [weak = WeakClaim(this), firstRect = info.firstHandle.paintRect,
788                                 secondRect = info.secondHandle.paintRect](const RectF&, bool isFirst) {
789         // reset handle position
790         auto pattern = weak.Upgrade();
791         CHECK_NULL_VOID(pattern && pattern->selectOverlay_);
792         SelectHandleInfo info;
793         if (isFirst) {
794             info.paintRect = firstRect;
795             pattern->selectOverlay_->UpdateFirstSelectHandleInfo(info);
796         } else {
797             info.paintRect = secondRect;
798             pattern->selectOverlay_->UpdateSecondSelectHandleInfo(info);
799         }
800     };
801     info.onClose = [weak = WeakClaim(this)](bool closedByGlobalEvent) {
802         if (closedByGlobalEvent) {
803             auto pattern = weak.Upgrade();
804             CHECK_NULL_VOID(pattern);
805             pattern->CloseSelectOverlay();
806         }
807     };
808 
809     CloseSelectOverlay();
810     auto pipeline = PipelineContext::GetCurrentContext();
811     CHECK_NULL_VOID(pipeline);
812     selectOverlay_ = pipeline->GetSelectOverlayManager()->CreateAndShowSelectOverlay(info, WeakClaim(this));
813 
814     // paint selected mask effect
815     host->MarkNeedRenderOnly();
816 }
817 
CloseSelectOverlay()818 void ImagePattern::CloseSelectOverlay()
819 {
820     if (!selectOverlay_) {
821         return;
822     }
823     if (!selectOverlay_->IsClosed()) {
824         selectOverlay_->Close();
825     }
826     selectOverlay_ = nullptr;
827     // remove selected mask effect
828     auto host = GetHost();
829     CHECK_NULL_VOID(host);
830     host->MarkNeedRenderOnly();
831 }
832 
HandleCopy()833 void ImagePattern::HandleCopy()
834 {
835     CHECK_NULL_VOID(image_);
836     if (!clipboard_) {
837         auto pipeline = PipelineContext::GetCurrentContext();
838         CHECK_NULL_VOID(pipeline);
839         clipboard_ = ClipboardProxy::GetInstance()->GetClipboard(pipeline->GetTaskExecutor());
840     }
841     auto pixmap = image_->GetPixelMap();
842     if (pixmap) {
843         clipboard_->SetPixelMapData(pixmap, copyOption_);
844     } else {
845         auto host = GetHost();
846         CHECK_NULL_VOID(host);
847         clipboard_->SetData(loadingCtx_->GetSourceInfo().GetSrc());
848     }
849 }
850 
ToJsonValue(std::unique_ptr<JsonValue> & json) const851 void ImagePattern::ToJsonValue(std::unique_ptr<JsonValue>& json) const
852 {
853     static const char* COPY_OPTIONS[] = { "CopyOptions.None", "CopyOptions.InApp", "CopyOptions.Local",
854         "CopyOptions.Distributed" };
855     json->Put("copyOption", COPY_OPTIONS[static_cast<int32_t>(copyOption_)]);
856 
857     json->Put("syncLoad", syncLoad_ ? "true" : "false");
858     auto host = GetHost();
859     CHECK_NULL_VOID(host);
860     json->Put("draggable", host->IsDraggable() ? "true" : "false");
861     json->Put("enableAnalyzer", isEnableAnalyzer_ ? "true" : "false");
862 }
863 
UpdateFillColorIfForegroundColor()864 void ImagePattern::UpdateFillColorIfForegroundColor()
865 {
866     auto frameNode = GetHost();
867     CHECK_NULL_VOID(frameNode);
868     auto renderContext = frameNode->GetRenderContext();
869     CHECK_NULL_VOID(renderContext);
870     if (renderContext->HasForegroundColor() || renderContext->HasForegroundColorStrategy()) {
871         auto imageLayoutProperty = frameNode->GetLayoutProperty<ImageLayoutProperty>();
872         auto imageSourceInfo = imageLayoutProperty->GetImageSourceInfo().value();
873         if (imageSourceInfo.IsSvg()) {
874             imageSourceInfo.SetFillColor(Color::FOREGROUND);
875             imageLayoutProperty->UpdateImageSourceInfo(imageSourceInfo);
876         }
877         auto imageRenderProperty = frameNode->GetPaintProperty<ImageRenderProperty>();
878         CHECK_NULL_VOID(imageRenderProperty);
879         imageRenderProperty->UpdateSvgFillColor(Color::FOREGROUND);
880     }
881 }
882 
DumpInfo()883 void ImagePattern::DumpInfo()
884 {
885     auto layoutProp = GetLayoutProperty<ImageLayoutProperty>();
886     CHECK_NULL_VOID(layoutProp);
887     auto src = layoutProp->GetImageSourceInfo().value_or(ImageSourceInfo(""));
888     DumpLog::GetInstance().AddDesc(std::string("url: ").append(src.ToString()));
889     syncLoad_ ? DumpLog::GetInstance().AddDesc("syncLoad:true") : DumpLog::GetInstance().AddDesc("syncLoad:false");
890     DumpLog::GetInstance().AddDesc("imageInterpolation:" + GetImageInterpolation());
891     if (loadingCtx_) {
892         auto currentLoadImageState = loadingCtx_->GetCurrentLoadingState();
893         DumpLog::GetInstance().AddDesc(std::string("currentLoadImageState : ").append(currentLoadImageState));
894         DumpLog::GetInstance().AddDesc(std::string("rawImageSize: ").append(loadingCtx_->GetImageSize().ToString()));
895     }
896     auto imageRenderProperty = GetPaintProperty<ImageRenderProperty>();
897     if (imageRenderProperty && imageRenderProperty->HasImageResizableSlice() &&
898         imageRenderProperty->GetImageResizableSliceValue({}).Valid()) {
899         DumpLog::GetInstance().AddDesc(
900             std::string("reslzable slice: ").append(imageRenderProperty->GetImageResizableSliceValue({}).ToString()));
901     }
902     DumpLog::GetInstance().AddDesc(std::string("enableAnalyzer: ").append(isEnableAnalyzer_ ? "true" : "false"));
903 }
904 
DumpAdvanceInfo()905 void ImagePattern::DumpAdvanceInfo()
906 {
907     auto layoutProp = GetLayoutProperty<ImageLayoutProperty>();
908     CHECK_NULL_VOID(layoutProp);
909     auto src = layoutProp->GetImageSourceInfo().value_or(ImageSourceInfo(""));
910     DumpLog::GetInstance().AddDesc(std::string("url: ").append(src.ToString()));
911     syncLoad_ ? DumpLog::GetInstance().AddDesc("syncLoad:true") : DumpLog::GetInstance().AddDesc("syncLoad:false");
912     if (loadingCtx_) {
913         auto currentLoadImageState = loadingCtx_->GetCurrentLoadingState();
914         DumpLog::GetInstance().AddDesc(std::string("currentLoadImageState : ").append(currentLoadImageState));
915     }
916 }
917 
UpdateDragEvent(const RefPtr<OHOS::Ace::DragEvent> & event)918 void ImagePattern::UpdateDragEvent(const RefPtr<OHOS::Ace::DragEvent>& event)
919 {
920     RefPtr<UnifiedData> unifiedData = UdmfClient::GetInstance()->CreateUnifiedData();
921     CHECK_NULL_VOID(loadingCtx_ && image_);
922     if (loadingCtx_->GetSourceInfo().IsPixmap()) {
923         auto pixelMap = image_->GetPixelMap();
924         CHECK_NULL_VOID(pixelMap);
925         const uint8_t* pixels = pixelMap->GetPixels();
926         CHECK_NULL_VOID(pixels);
927         int32_t length = pixelMap->GetByteCount();
928         std::vector<uint8_t> data(pixels, pixels + length);
929         PixelMapRecordDetails details = { pixelMap->GetWidth(), pixelMap->GetHeight(), pixelMap->GetPixelFormat(),
930             pixelMap->GetAlphaType() };
931         UdmfClient::GetInstance()->AddPixelMapRecord(unifiedData, data, details);
932     } else {
933         UdmfClient::GetInstance()->AddImageRecord(unifiedData, loadingCtx_->GetSourceInfo().GetSrc());
934     }
935     event->SetData(unifiedData);
936 }
937 
OnLanguageConfigurationUpdate()938 void ImagePattern::OnLanguageConfigurationUpdate()
939 {
940     CHECK_NULL_VOID(loadingCtx_);
941     auto&& src = loadingCtx_->GetSourceInfo();
942     // Resource image needs to reload when Language changes
943     if (src.GetSrcType() == SrcType::RESOURCE) {
944         loadingCtx_.Reset();
945     }
946 }
947 
OnColorConfigurationUpdate()948 void ImagePattern::OnColorConfigurationUpdate()
949 {
950     OnConfigurationUpdate();
951 }
952 
OnIconConfigurationUpdate()953 void ImagePattern::OnIconConfigurationUpdate()
954 {
955     OnConfigurationUpdate();
956 }
957 
OnConfigurationUpdate()958 void ImagePattern::OnConfigurationUpdate()
959 {
960     CHECK_NULL_VOID(loadingCtx_);
961 
962     auto imageLayoutProperty = GetLayoutProperty<ImageLayoutProperty>();
963     CHECK_NULL_VOID(imageLayoutProperty);
964     auto src = imageLayoutProperty->GetImageSourceInfo().value_or(ImageSourceInfo(""));
965     UpdateInternalResource(src);
966     src.SetIsConfigurationChange(true);
967 
968     LoadImage(src);
969     if (loadingCtx_->NeedAlt() && imageLayoutProperty->GetAlt()) {
970         auto altImageSourceInfo = imageLayoutProperty->GetAlt().value_or(ImageSourceInfo(""));
971         if (altLoadingCtx_ && altLoadingCtx_->GetSourceInfo() == altImageSourceInfo) {
972             altLoadingCtx_.Reset();
973         }
974         altImageSourceInfo.SetIsConfigurationChange(true);
975         LoadAltImage(altImageSourceInfo);
976     }
977 }
978 
SetImageAnalyzerConfig(const ImageAnalyzerConfig & config)979 void ImagePattern::SetImageAnalyzerConfig(const ImageAnalyzerConfig& config)
980 {
981     if (!isEnableAnalyzer_) {
982         return;
983     }
984     analyzerConfig_ = config;
985     if (IsSupportImageAnalyzerFeature() && isAnalyzerOverlayBuild_) {
986         ImageAnalyzerMgr::GetInstance().UpdateConfig(&overlayData_, &analyzerConfig_);
987     }
988 }
989 
CreateAnalyzerOverlay()990 void ImagePattern::CreateAnalyzerOverlay()
991 {
992     if (!IsSupportImageAnalyzerFeature() || isAnalyzerOverlayBuild_) {
993         return;
994     }
995 
996     auto pixelMap = image_->GetPixelMap();
997     CHECK_NULL_VOID(pixelMap);
998     napi_value pixelmapNapiVal = ConvertPixmapNapi(pixelMap);
999     auto frameNode = GetHost();
1000     auto overlayNode = frameNode->GetOverlayNode();
1001 
1002     auto layoutProps = GetLayoutProperty<ImageLayoutProperty>();
1003     CHECK_NULL_VOID(layoutProps);
1004     analyzerUIConfig_.imageFit = layoutProps->GetImageFit().value_or(ImageFit::COVER);
1005     auto buildNodeFunction = [this, &pixelmapNapiVal]() -> RefPtr<UINode> {
1006         ScopedViewStackProcessor builderViewStackProcessor;
1007         ImageAnalyzerMgr::GetInstance().BuildNodeFunc(
1008             pixelmapNapiVal, &analyzerConfig_, &analyzerUIConfig_, &overlayData_);
1009         auto customNode = ViewStackProcessor::GetInstance()->Finish();
1010         return customNode;
1011     };
1012     overlayNode = AceType::DynamicCast<FrameNode>(buildNodeFunction());
1013     CHECK_NULL_VOID(overlayNode);
1014     frameNode->SetOverlayNode(overlayNode);
1015     overlayNode->SetParent(AceType::WeakClaim(AceType::RawPtr(frameNode)));
1016     overlayNode->SetActive(true);
1017     isAnalyzerOverlayBuild_ = true;
1018 
1019     UpdateAnalyzerOverlayLayout();
1020     auto renderContext = overlayNode->GetRenderContext();
1021     CHECK_NULL_VOID(renderContext);
1022     renderContext->UpdateZIndex(INT32_MAX);
1023     auto focusHub = overlayNode->GetOrCreateFocusHub();
1024     CHECK_NULL_VOID(focusHub);
1025     focusHub->SetFocusable(false);
1026     overlayNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1027 }
1028 
UpdateAnalyzerOverlay()1029 void ImagePattern::UpdateAnalyzerOverlay()
1030 {
1031     if (!IsSupportImageAnalyzerFeature() || !isAnalyzerOverlayBuild_) {
1032         return;
1033     }
1034 
1035     auto imageLayoutProperty = GetLayoutProperty<ImageLayoutProperty>();
1036     CHECK_NULL_VOID(imageLayoutProperty);
1037     auto src = imageLayoutProperty->GetImageSourceInfo().value_or(ImageSourceInfo(""));
1038     UpdateInternalResource(src);
1039     if (loadingCtx_ && loadingCtx_->GetSourceInfo() == src && srcRect_ == dstRect_) {
1040         return;
1041     }
1042 
1043     auto pixelMap = image_->GetPixelMap();
1044     CHECK_NULL_VOID(pixelMap);
1045     napi_value pixelmapNapiVal = ConvertPixmapNapi(pixelMap);
1046     auto frameNode = GetHost();
1047     auto overlayNode = frameNode->GetOverlayNode();
1048     ImageAnalyzerMgr::GetInstance().UpdateImage(&overlayData_, pixelmapNapiVal, &analyzerConfig_, &analyzerUIConfig_);
1049     overlayNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1050 }
1051 
DeleteAnalyzerOverlay()1052 void ImagePattern::DeleteAnalyzerOverlay()
1053 {
1054     auto frameNode = GetHost();
1055     CHECK_NULL_VOID(frameNode);
1056     auto overlayNode = frameNode->GetOverlayNode();
1057     isAnalyzerOverlayBuild_ = false;
1058     if (!overlayNode) {
1059         return;
1060     }
1061     RefPtr<FrameNode> node;
1062     frameNode->SetOverlayNode(node);
1063 }
1064 
IsSupportImageAnalyzerFeature()1065 bool ImagePattern::IsSupportImageAnalyzerFeature()
1066 {
1067     auto eventHub = GetEventHub<EventHub>();
1068     bool isEnabled = true;
1069     if (eventHub) {
1070         isEnabled = eventHub->IsEnabled();
1071     }
1072 
1073     bool hasObscured = false;
1074     auto host = GetHost();
1075     CHECK_NULL_RETURN(host, false);
1076     if (host->GetRenderContext()->GetObscured().has_value()) {
1077         auto obscuredReasons = host->GetRenderContext()->GetObscured().value();
1078         hasObscured = std::any_of(obscuredReasons.begin(), obscuredReasons.end(),
1079             [](const auto& reason) { return reason == ObscuredReasons::PLACEHOLDER; });
1080     }
1081 
1082     auto imageRenderProperty = GetPaintProperty<ImageRenderProperty>();
1083     CHECK_NULL_RETURN(imageRenderProperty, false);
1084     ImageRepeat repeat = imageRenderProperty->GetImageRepeat().value_or(ImageRepeat::NO_REPEAT);
1085 
1086     return isEnabled && !hasObscured && isEnableAnalyzer_ &&
1087            ImageAnalyzerMgr::GetInstance().IsImageAnalyzerSupported() && image_ &&
1088            !loadingCtx_->GetSourceInfo().IsSvg() && repeat == ImageRepeat::NO_REPEAT &&
1089            loadingCtx_->GetFrameCount() == 1;
1090 }
1091 
UpdateAnalyzerUIConfig(const RefPtr<GeometryNode> & geometryNode)1092 void ImagePattern::UpdateAnalyzerUIConfig(const RefPtr<GeometryNode>& geometryNode)
1093 {
1094     bool isUIConfigUpdate = false;
1095     CHECK_NULL_VOID(geometryNode);
1096     if (analyzerUIConfig_.contentWidth != geometryNode->GetContentSize().Width() ||
1097         analyzerUIConfig_.contentHeight != geometryNode->GetContentSize().Height()) {
1098         analyzerUIConfig_.contentWidth = geometryNode->GetContentSize().Width();
1099         analyzerUIConfig_.contentHeight = geometryNode->GetContentSize().Height();
1100         isUIConfigUpdate = true;
1101     }
1102 
1103     auto layoutProps = GetLayoutProperty<ImageLayoutProperty>();
1104     CHECK_NULL_VOID(layoutProps);
1105     if (analyzerUIConfig_.imageFit != layoutProps->GetImageFit().value_or(ImageFit::COVER)) {
1106         analyzerUIConfig_.imageFit = layoutProps->GetImageFit().value_or(ImageFit::COVER);
1107         isUIConfigUpdate = true;
1108     }
1109 
1110     auto frameNode = GetHost();
1111     CHECK_NULL_VOID(frameNode);
1112     auto renderContext = frameNode->GetRenderContext();
1113     CHECK_NULL_VOID(renderContext);
1114 
1115     auto localCenter = renderContext->GetTransformCenterValue(DimensionOffset(0.5_pct, 0.5_pct));
1116     auto localScale = renderContext->GetTransformScaleValue(VectorF(1.0f, 1.0f));
1117     Matrix4 localScaleMat = Matrix4::CreateTranslate(localCenter.GetX().Value(), localCenter.GetY().Value(), 0) *
1118                             Matrix4::CreateScale(localScale.x, localScale.y, 1.0f) *
1119                             Matrix4::CreateTranslate(-localCenter.GetX().Value(), -localCenter.GetY().Value(), 0);
1120 
1121     auto transformMat = renderContext->GetTransformMatrixValue(Matrix4::CreateIdentity());
1122     VectorF transCenter(transformMat.Get(0, 3), transformMat.Get(1, 3));
1123     Matrix4 transScaleMat = Matrix4::CreateTranslate(transCenter.x, transCenter.y, 0) *
1124                             Matrix4::CreateScale(transformMat.GetScaleX(), transformMat.GetScaleY(), 1.0f) *
1125                             Matrix4::CreateTranslate(-transCenter.x, -transCenter.y, 0);
1126     Matrix4 scaleMat = localScaleMat * transScaleMat;
1127     if (!(analyzerUIConfig_.transformMat == scaleMat)) {
1128         analyzerUIConfig_.transformMat = scaleMat;
1129         isUIConfigUpdate = true;
1130     }
1131 
1132     if (isUIConfigUpdate) {
1133         ImageAnalyzerMgr::GetInstance().UpdateInnerConfig(&overlayData_, &analyzerUIConfig_);
1134     }
1135 }
1136 
UpdateAnalyzerOverlayLayout()1137 void ImagePattern::UpdateAnalyzerOverlayLayout()
1138 {
1139     auto host = GetHost();
1140     CHECK_NULL_VOID(host);
1141     auto layoutProperty = host->GetLayoutProperty();
1142     CHECK_NULL_VOID(layoutProperty);
1143     auto padding = layoutProperty->CreatePaddingAndBorder();
1144     auto overlayNode = host->GetOverlayNode();
1145     CHECK_NULL_VOID(overlayNode);
1146     auto overlayLayoutProperty = overlayNode->GetLayoutProperty();
1147     CHECK_NULL_VOID(overlayLayoutProperty);
1148     overlayLayoutProperty->UpdateMeasureType(MeasureType::MATCH_PARENT);
1149     overlayLayoutProperty->UpdateAlignment(Alignment::TOP_LEFT);
1150     overlayLayoutProperty->SetOverlayOffset(Dimension(padding.Offset().GetX()), Dimension(padding.Offset().GetY()));
1151     overlayNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1152 
1153     auto renderContext = overlayNode->GetRenderContext();
1154     if (renderContext) {
1155         renderContext->SetRenderFrameOffset({-padding.Offset().GetX(), -padding.Offset().GetY()});
1156     }
1157 }
1158 
InitDefaultValue()1159 void ImagePattern::InitDefaultValue()
1160 {
1161     // add API version protection
1162     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
1163         autoResizeDefault_ = false;
1164         interpolationDefault_ = ImageInterpolation::LOW;
1165     }
1166     auto container = Container::Current();
1167     // If the default value is set to false, the ScenceBoard memory increases.
1168     // Therefore the default value is different in the ScenceBoard.
1169     if (container && container->IsScenceBoardWindow()) {
1170         autoResizeDefault_ = true;
1171         interpolationDefault_ = ImageInterpolation::NONE;
1172     }
1173 }
1174 } // namespace OHOS::Ace::NG
1175