• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #define NAPI_VERSION 8
17 
18 #include "core/components_ng/pattern/image/image_pattern.h"
19 
20 #include "base/log/dump_log.h"
21 #include "base/utils/utils.h"
22 #include "core/common/ace_engine_ext.h"
23 #include "core/common/ai/image_analyzer_adapter.h"
24 #include "core/common/ai/image_analyzer_manager.h"
25 #include "core/common/container.h"
26 #include "core/common/frontend.h"
27 #include "core/common/udmf/udmf_client.h"
28 #include "core/components/common/layout/constants.h"
29 #include "core/components/image/image_theme.h"
30 #include "core/components/text/text_theme.h"
31 #include "core/components/theme/icon_theme.h"
32 #include "core/components_ng/base/inspector_filter.h"
33 #include "core/components_ng/base/view_stack_processor.h"
34 #include "core/components_ng/manager/select_overlay/select_overlay_manager.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/property/border_property.h"
38 #include "core/components_ng/property/measure_property.h"
39 #include "core/pipeline_ng/pipeline_context.h"
40 
41 namespace OHOS::Ace::NG {
42 namespace {
43 constexpr int32_t DEFAULT_DURATION = 1000; // ms
44 constexpr uint32_t CRITICAL_TIME = 50;      // ms. If show time of image is less than this, use more cacheImages.
45 constexpr int64_t MICROSEC_TO_MILLISEC = 1000;
46 constexpr int32_t DEFAULT_ITERATIONS = 1;
47 constexpr int32_t MEMORY_LEVEL_LOW_STATUS = 1;
48 
GetImageInterpolation(ImageInterpolation interpolation)49 std::string GetImageInterpolation(ImageInterpolation interpolation)
50 {
51     switch (interpolation) {
52         case ImageInterpolation::LOW:
53             return "LOW";
54         case ImageInterpolation::MEDIUM:
55             return "MEDIUM";
56         case ImageInterpolation::HIGH:
57             return "HIGH";
58         default:
59             return "NONE";
60     }
61 }
62 
GetDynamicModeString(DynamicRangeMode dynamicMode)63 std::string GetDynamicModeString(DynamicRangeMode dynamicMode)
64 {
65     switch (dynamicMode) {
66         case DynamicRangeMode::HIGH:
67             return "HIGH";
68         case DynamicRangeMode::CONSTRAINT:
69             return "CONSTRAINT";
70         case DynamicRangeMode::STANDARD:
71             return "STANDARD";
72         default:
73             return "STANDARD";
74     }
75 }
76 
ConvertOrientationToString(ImageRotateOrientation orientation)77 std::string ConvertOrientationToString(ImageRotateOrientation orientation)
78 {
79     switch (orientation) {
80         case ImageRotateOrientation::UP:
81             return "UP";
82         case ImageRotateOrientation::RIGHT:
83             return "RIGHT";
84         case ImageRotateOrientation::DOWN:
85             return "DOWN";
86         case ImageRotateOrientation::LEFT:
87             return "LEFT";
88         case ImageRotateOrientation::AUTO:
89             return "AUTO";
90         default:
91             return "UP";
92     }
93 }
94 } // namespace
95 
96 constexpr float BOX_EPSILON = 0.5f;
97 constexpr float IMAGE_SENSITIVE_RADIUS = 80.0f;
98 constexpr double IMAGE_SENSITIVE_SATURATION = 1.0;
99 constexpr double IMAGE_SENSITIVE_BRIGHTNESS = 1.08;
100 
ImagePattern()101 ImagePattern::ImagePattern()
102 {
103     InitDefaultValue();
104     ImageAnimatorPattern();
105 }
106 
~ImagePattern()107 ImagePattern::~ImagePattern()
108 {
109     if (isEnableAnalyzer_) {
110         ReleaseImageAnalyzer();
111     }
112 }
113 
CreateDataReadyCallback()114 DataReadyNotifyTask ImagePattern::CreateDataReadyCallback()
115 {
116     return [weak = WeakClaim(this)](const ImageSourceInfo& sourceInfo) {
117         auto pattern = weak.Upgrade();
118         CHECK_NULL_VOID(pattern);
119         pattern->isOrientationChange_ = false;
120         auto imageLayoutProperty = pattern->GetLayoutProperty<ImageLayoutProperty>();
121         CHECK_NULL_VOID(imageLayoutProperty);
122         auto currentSourceInfo = imageLayoutProperty->GetImageSourceInfo().value_or(ImageSourceInfo(""));
123         if (currentSourceInfo != sourceInfo) {
124             TAG_LOGW(AceLogTag::ACE_IMAGE, "sourceInfo does not match, ignore current callback. "
125                  "current: %{private}s vs callback's: %{private}s",
126                 currentSourceInfo.ToString().c_str(), sourceInfo.ToString().c_str());
127             return;
128         }
129         pattern->OnImageDataReady();
130     };
131 }
132 
CreateLoadSuccessCallback()133 LoadSuccessNotifyTask ImagePattern::CreateLoadSuccessCallback()
134 {
135     return [weak = WeakClaim(this)](const ImageSourceInfo& sourceInfo) {
136         auto pattern = weak.Upgrade();
137         CHECK_NULL_VOID(pattern);
138         pattern->isOrientationChange_ = false;
139         auto imageLayoutProperty = pattern->GetLayoutProperty<ImageLayoutProperty>();
140         CHECK_NULL_VOID(imageLayoutProperty);
141         auto currentSourceInfo = imageLayoutProperty->GetImageSourceInfo().value_or(ImageSourceInfo(""));
142         if (currentSourceInfo != sourceInfo) {
143             TAG_LOGW(AceLogTag::ACE_IMAGE, "sourceInfo does not match, ignore current callback. "
144                  "current: %{private}s vs callback's: %{private}s",
145                 currentSourceInfo.ToString().c_str(), sourceInfo.ToString().c_str());
146             return;
147         }
148         pattern->OnImageLoadSuccess();
149     };
150 }
151 
CreateLoadFailCallback()152 LoadFailNotifyTask ImagePattern::CreateLoadFailCallback()
153 {
154     return [weak = WeakClaim(this)](const ImageSourceInfo& sourceInfo, const std::string& errorMsg) {
155         auto pattern = weak.Upgrade();
156         CHECK_NULL_VOID(pattern);
157         pattern->isOrientationChange_ = false;
158         auto imageLayoutProperty = pattern->GetLayoutProperty<ImageLayoutProperty>();
159         CHECK_NULL_VOID(imageLayoutProperty);
160         auto currentSourceInfo = imageLayoutProperty->GetImageSourceInfo().value_or(ImageSourceInfo(""));
161         if (currentSourceInfo != sourceInfo) {
162             TAG_LOGW(AceLogTag::ACE_IMAGE, "sourceInfo does not match, ignore current callback. "
163                  "current: %{private}s vs callback's: %{private}s",
164                 currentSourceInfo.ToString().c_str(), sourceInfo.ToString().c_str());
165             return;
166         }
167         if (!currentSourceInfo.IsFromReset()) {
168             pattern->OnImageLoadFail(errorMsg);
169         }
170     };
171 }
172 
CreateCompleteCallBackInDataReady()173 OnCompleteInDataReadyNotifyTask ImagePattern::CreateCompleteCallBackInDataReady()
174 {
175     return [weak = WeakClaim(this)](const ImageSourceInfo& sourceInfo) {
176         auto pattern = weak.Upgrade();
177         CHECK_NULL_VOID(pattern);
178         auto imageLayoutProperty = pattern->GetLayoutProperty<ImageLayoutProperty>();
179         CHECK_NULL_VOID(imageLayoutProperty);
180         auto currentSourceInfo = imageLayoutProperty->GetImageSourceInfo().value_or(ImageSourceInfo(""));
181         if (currentSourceInfo != sourceInfo) {
182             TAG_LOGW(AceLogTag::ACE_IMAGE,
183                 "sourceInfo does not match, ignore current callback. "
184                 "current: %{private}s vs callback's: %{private}s",
185                 currentSourceInfo.ToString().c_str(), sourceInfo.ToString().c_str());
186             return;
187         }
188         pattern->OnCompleteInDataReady();
189     };
190 }
191 
OnCompleteInDataReady()192 void ImagePattern::OnCompleteInDataReady()
193 {
194     auto host = GetHost();
195     CHECK_NULL_VOID(host);
196     const auto& geometryNode = host->GetGeometryNode();
197     CHECK_NULL_VOID(geometryNode);
198     auto imageEventHub = GetEventHub<ImageEventHub>();
199     CHECK_NULL_VOID(imageEventHub);
200     CHECK_NULL_VOID(loadingCtx_);
201     LoadImageSuccessEvent event(loadingCtx_->GetImageSize().Width(), loadingCtx_->GetImageSize().Height(),
202         geometryNode->GetFrameSize().Width(), geometryNode->GetFrameSize().Height(), 0,
203         geometryNode->GetContentSize().Width(), geometryNode->GetContentSize().Height(),
204         geometryNode->GetContentOffset().GetX(), geometryNode->GetContentOffset().GetY());
205     imageEventHub->FireCompleteEvent(event);
206 }
207 
TriggerFirstVisibleAreaChange()208 void ImagePattern::TriggerFirstVisibleAreaChange()
209 {
210     if (isComponentSnapshotNode_) {
211         return;
212     }
213     auto host = GetHost();
214     CHECK_NULL_VOID(host);
215     RectF frameRect;
216     RectF visibleInnerRect;
217     RectF visibleRect;
218     host->GetVisibleRectWithClip(visibleRect, visibleInnerRect, frameRect);
219     OnVisibleAreaChange(GreatNotEqual(visibleInnerRect.Width(), 0.0) && GreatNotEqual(visibleInnerRect.Height(), 0.0));
220 }
221 
PrepareAnimation(const RefPtr<CanvasImage> & image)222 void ImagePattern::PrepareAnimation(const RefPtr<CanvasImage>& image)
223 {
224     if (image->IsStatic()) {
225         return;
226     }
227     RegisterVisibleAreaChange();
228     TriggerFirstVisibleAreaChange();
229     SetOnFinishCallback(image);
230     SetRedrawCallback(image);
231     // GIF images are not played by default, but depend on OnVisibleAreaChange callback.
232     image->ControlAnimation(gifAnimation_);
233 }
234 
SetOnFinishCallback(const RefPtr<CanvasImage> & image)235 void ImagePattern::SetOnFinishCallback(const RefPtr<CanvasImage>& image)
236 {
237     CHECK_NULL_VOID(image);
238     image->SetOnFinishCallback([weak = WeakPtr(GetHost())] {
239         auto imageNode = weak.Upgrade();
240         CHECK_NULL_VOID(imageNode);
241         auto eventHub = imageNode->GetEventHub<ImageEventHub>();
242         if (eventHub) {
243             eventHub->FireFinishEvent();
244         }
245     });
246 }
247 
SetRedrawCallback(const RefPtr<CanvasImage> & image)248 void ImagePattern::SetRedrawCallback(const RefPtr<CanvasImage>& image)
249 {
250     CHECK_NULL_VOID(image);
251     // set animation flush function for svg / gif
252     image->SetRedrawCallback([weak = WeakPtr(GetHost())] {
253         auto imageNode = weak.Upgrade();
254         CHECK_NULL_VOID(imageNode);
255         imageNode->MarkNeedRenderOnly();
256     });
257 }
258 
RegisterVisibleAreaChange(bool isCalcClip)259 void ImagePattern::RegisterVisibleAreaChange(bool isCalcClip)
260 {
261     auto pipeline = GetContext();
262     // register to onVisibleAreaChange
263     CHECK_NULL_VOID(pipeline);
264     auto callback = [weak = WeakClaim(this)](bool visible, double ratio) {
265         auto self = weak.Upgrade();
266         CHECK_NULL_VOID(self);
267         self->OnVisibleAreaChange(visible, ratio);
268     };
269     auto host = GetHost();
270     CHECK_NULL_VOID(host);
271     // add visibleAreaChangeNode(inner callback)
272     std::vector<double> ratioList = {0.0};
273     pipeline->AddVisibleAreaChangeNode(host, ratioList, callback, false, isCalcClip);
274 }
275 
CheckHandles(SelectHandleInfo & handleInfo)276 void ImagePattern::CheckHandles(SelectHandleInfo& handleInfo)
277 {
278     auto host = GetHost();
279     CHECK_NULL_VOID(host);
280     auto renderContext = host->GetRenderContext();
281     CHECK_NULL_VOID(renderContext);
282     if (!renderContext->GetClipEdge().value_or(true)) {
283         return;
284     }
285     // use global offset.
286     const auto& geometryNode = host->GetGeometryNode();
287     auto contentRect = geometryNode->GetContentRect();
288     RectF visibleContentRect(contentRect.GetOffset() + parentGlobalOffset_, contentRect.GetSize());
289     auto parent = host->GetAncestorNodeOfFrame(false);
290     visibleContentRect = GetVisibleContentRect(parent, visibleContentRect);
291     auto paintRect = handleInfo.paintRect;
292     PointF bottomPoint = { paintRect.Left(), paintRect.Bottom() - BOX_EPSILON };
293     PointF topPoint = { paintRect.Left(), paintRect.Top() + BOX_EPSILON };
294     handleInfo.isShow = visibleContentRect.IsInRegion(bottomPoint) && visibleContentRect.IsInRegion(topPoint);
295 }
296 
CalAndUpdateSelectOverlay()297 void ImagePattern::CalAndUpdateSelectOverlay()
298 {
299     auto host = GetHost();
300     CHECK_NULL_VOID(host);
301     auto rect = host->GetTransformRectRelativeToWindow();
302     SelectOverlayInfo info;
303     const auto& geometryNode = host->GetGeometryNode();
304     CHECK_NULL_VOID(geometryNode);
305     SizeF handleSize = {
306         SelectHandleInfo::GetDefaultLineWidth().ConvertToPx(),
307         geometryNode->GetContentSize().Height() };
308     info.firstHandle.paintRect = RectF(rect.GetOffset(), handleSize);
309     CheckHandles(info.firstHandle);
310     OffsetF offset(rect.Width() - handleSize.Width(), rect.Height() - handleSize.Height());
311     info.secondHandle.paintRect = RectF(rect.GetOffset() + offset, handleSize);
312     CheckHandles(info.secondHandle);
313     selectOverlay_->UpdateFirstAndSecondHandleInfo(info.firstHandle, info.secondHandle);
314 }
315 
GetParentGlobalOffset() const316 OffsetF ImagePattern::GetParentGlobalOffset() const
317 {
318     auto host = GetHost();
319     CHECK_NULL_RETURN(host, {});
320     auto pipeline = host->GetContext();
321     CHECK_NULL_RETURN(pipeline, {});
322     auto rootOffset = pipeline->GetRootRect().GetOffset();
323     return host->GetPaintRectOffset() - rootOffset;
324 }
325 
OnAreaChangedInner()326 void ImagePattern::OnAreaChangedInner()
327 {
328     if (selectOverlay_ && !selectOverlay_->IsClosed()) {
329         auto parentGlobalOffset = GetParentGlobalOffset();
330         if (parentGlobalOffset != parentGlobalOffset_) {
331             parentGlobalOffset_ = parentGlobalOffset;
332             CalAndUpdateSelectOverlay();
333         }
334     }
335 }
336 
RemoveAreaChangeInner()337 void ImagePattern::RemoveAreaChangeInner()
338 {
339     auto pipeline = GetContext();
340     CHECK_NULL_VOID(pipeline);
341     auto host = GetHost();
342     CHECK_NULL_VOID(host);
343     auto eventHub = host->GetEventHub<ImageEventHub>();
344     CHECK_NULL_VOID(eventHub);
345     if (eventHub->HasOnAreaChanged()) {
346         return;
347     }
348     pipeline->RemoveOnAreaChangeNode(host->GetId());
349 }
350 
CalcImageContentPaintSize(const RefPtr<GeometryNode> & geometryNode)351 RectF ImagePattern::CalcImageContentPaintSize(const RefPtr<GeometryNode>& geometryNode)
352 {
353     RectF paintSize;
354     auto imageRenderProperty = GetPaintProperty<ImageRenderProperty>();
355     CHECK_NULL_RETURN(imageRenderProperty, paintSize);
356     ImageRepeat repeat = imageRenderProperty->GetImageRepeat().value_or(ImageRepeat::NO_REPEAT);
357     bool imageRepeatX = repeat == ImageRepeat::REPEAT || repeat == ImageRepeat::REPEAT_X;
358     bool imageRepeatY = repeat == ImageRepeat::REPEAT || repeat == ImageRepeat::REPEAT_Y;
359 
360     if (loadingCtx_->GetSourceInfo().IsSvg()) {
361         const float invalidValue = -1;
362         paintSize.SetWidth(dstRect_.IsValid() ? dstRect_.Width() : invalidValue);
363         paintSize.SetHeight(dstRect_.IsValid() ? dstRect_.Height() : invalidValue);
364         paintSize.SetLeft(
365             dstRect_.IsValid() ? dstRect_.GetX() + geometryNode->GetContentOffset().GetX() : invalidValue);
366         paintSize.SetTop(dstRect_.IsValid() ? dstRect_.GetY() + geometryNode->GetContentOffset().GetY() : invalidValue);
367     } else {
368         paintSize.SetWidth(imageRepeatX ? geometryNode->GetContentSize().Width() : dstRect_.Width());
369         paintSize.SetHeight(imageRepeatY ? geometryNode->GetContentSize().Height() : dstRect_.Height());
370         paintSize.SetLeft((imageRepeatX ? 0 : dstRect_.GetX()) + geometryNode->GetContentOffset().GetX());
371         paintSize.SetTop((imageRepeatY ? 0 : dstRect_.GetY()) + geometryNode->GetContentOffset().GetY());
372     }
373     return paintSize;
374 }
375 
ClearAltData()376 void ImagePattern::ClearAltData()
377 {
378     altLoadingCtx_ = nullptr;
379     altImage_ = nullptr;
380     altDstRect_.reset();
381     altSrcRect_.reset();
382 }
383 
OnImageLoadSuccess()384 void ImagePattern::OnImageLoadSuccess()
385 {
386     CHECK_NULL_VOID(loadingCtx_);
387     auto host = GetHost();
388     CHECK_NULL_VOID(host);
389     const auto& geometryNode = host->GetGeometryNode();
390     CHECK_NULL_VOID(geometryNode);
391 
392     image_ = loadingCtx_->MoveCanvasImage();
393     CHECK_NULL_VOID(image_);
394     srcRect_ = loadingCtx_->GetSrcRect();
395     dstRect_ = loadingCtx_->GetDstRect();
396     auto srcInfo = loadingCtx_->GetSourceInfo();
397     auto frameCount = loadingCtx_->GetFrameCount();
398 
399     RectF paintRect = CalcImageContentPaintSize(geometryNode);
400     LoadImageSuccessEvent event(loadingCtx_->GetImageSize().Width(), loadingCtx_->GetImageSize().Height(),
401         geometryNode->GetFrameSize().Width(), geometryNode->GetFrameSize().Height(), 1, paintRect.Width(),
402         paintRect.Height(), paintRect.GetX(), paintRect.GetY());
403 
404     SetImagePaintConfig(image_, srcRect_, dstRect_, srcInfo, frameCount);
405     UpdateSvgSmoothEdgeValue();
406     PrepareAnimation(image_);
407     if (host->IsDraggable()) {
408         EnableDrag();
409     }
410     ClearAltData();
411 
412     auto eventHub = GetEventHub<ImageEventHub>();
413     if (eventHub) {
414         eventHub->FireCompleteEvent(event);
415     }
416 
417     if (IsSupportImageAnalyzerFeature()) {
418         if (isPixelMapChanged_) {
419             UpdateAnalyzerOverlay();
420         }
421         UpdateAnalyzerUIConfig(geometryNode);
422         auto context = host->GetContext();
423         CHECK_NULL_VOID(context);
424         auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
425         uiTaskExecutor.PostTask([weak = WeakClaim(this)] {
426             auto pattern = weak.Upgrade();
427             CHECK_NULL_VOID(pattern);
428             ContainerScope scope(pattern->GetHostInstanceId());
429             pattern->CreateAnalyzerOverlay();
430         }, "ArkUIImageCreateAnalyzerOverlay");
431     }
432     ACE_LAYOUT_SCOPED_TRACE(
433         "OnImageLoadSuccess[self:%d][src:%s]", host->GetId(), loadingCtx_->GetSourceInfo().ToString().c_str());
434     if (SystemProperties::GetDebugEnabled()) {
435         TAG_LOGD(AceLogTag::ACE_IMAGE,
436             "imageLoadSuccess src=%{private}s", loadingCtx_->GetSourceInfo().ToString().c_str());
437     }
438     host->MarkNeedRenderOnly();
439 }
440 
CheckIfNeedLayout()441 bool ImagePattern::CheckIfNeedLayout()
442 {
443     auto host = GetHost();
444     CHECK_NULL_RETURN(host, true);
445     CHECK_NULL_RETURN(host->GetGeometryNode()->GetContent(), true);
446     const auto& props = DynamicCast<ImageLayoutProperty>(host->GetLayoutProperty());
447     CHECK_NULL_RETURN(props, true);
448     const auto& layoutConstraint = props->GetCalcLayoutConstraint();
449     CHECK_NULL_RETURN(layoutConstraint, true);
450     return !(layoutConstraint->selfIdealSize && layoutConstraint->selfIdealSize->IsValid());
451 }
452 
OnImageDataReady()453 void ImagePattern::OnImageDataReady()
454 {
455     CHECK_NULL_VOID(loadingCtx_);
456     auto host = GetHost();
457     CHECK_NULL_VOID(host);
458     const auto& geometryNode = host->GetGeometryNode();
459     CHECK_NULL_VOID(geometryNode);
460     // update rotate orientation before decoding
461     UpdateOrientation();
462 
463     if (CheckIfNeedLayout()) {
464         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
465         return;
466     }
467 
468     // 1. If PropertyChangeFlag contains PROPERTY_UPDATE_MEASURE,
469     //    the image will be decoded after layout.
470     // 2. The image node in imageAnimator will not be decoded after layout, decode directly.
471     auto layoutProp = host->GetLayoutProperty<ImageLayoutProperty>();
472     CHECK_NULL_VOID(layoutProp);
473     if (!((layoutProp->GetPropertyChangeFlag() & PROPERTY_UPDATE_MEASURE) == PROPERTY_UPDATE_MEASURE) ||
474         isImageAnimator_) {
475         StartDecoding(geometryNode->GetContentSize());
476     }
477 }
478 
479 // Update the necessary rotate orientation for drawing and measuring.
UpdateOrientation()480 void ImagePattern::UpdateOrientation()
481 {
482     auto imageObj = loadingCtx_->GetImageObject();
483     CHECK_NULL_VOID(imageObj);
484     if (imageObj->GetFrameCount() > 1) {
485         imageObj->SetOrientation(ImageRotateOrientation::UP);
486         return;
487     }
488     imageObj->SetUserOrientation(userOrientation_);
489     auto selfOrientation_ = imageObj->GetOrientation();
490     if (userOrientation_ == ImageRotateOrientation::UP) {
491         joinOrientation_ = ImageRotateOrientation::UP;
492         return;
493     }
494     if (userOrientation_ == ImageRotateOrientation::AUTO) {
495         joinOrientation_ = selfOrientation_;
496     } else {
497         joinOrientation_ = userOrientation_;
498     }
499     // update image object orientation before decoding
500     imageObj->SetOrientation(joinOrientation_);
501 }
502 
OnImageLoadFail(const std::string & errorMsg)503 void ImagePattern::OnImageLoadFail(const std::string& errorMsg)
504 {
505     auto host = GetHost();
506     CHECK_NULL_VOID(host);
507     const auto& geometryNode = host->GetGeometryNode();
508     auto imageEventHub = GetEventHub<ImageEventHub>();
509     CHECK_NULL_VOID(imageEventHub);
510     LoadImageFailEvent event(
511         geometryNode->GetFrameSize().Width(), geometryNode->GetFrameSize().Height(), errorMsg);
512     imageEventHub->FireErrorEvent(event);
513 }
514 
SetExternalDecodeFormat(PixelFormat externalDecodeFormat)515 void ImagePattern::SetExternalDecodeFormat(PixelFormat externalDecodeFormat)
516 {
517     isImageReloadNeeded_ = isImageReloadNeeded_ | (externalDecodeFormat_ != externalDecodeFormat);
518     switch (externalDecodeFormat) {
519         case PixelFormat::NV21:
520         case PixelFormat::RGBA_8888:
521         case PixelFormat::RGBA_1010102:
522         case PixelFormat::YCBCR_P010:
523         case PixelFormat::YCRCB_P010:
524             externalDecodeFormat_ = externalDecodeFormat;
525             break;
526         default:
527             externalDecodeFormat_ = PixelFormat::UNKNOWN;
528     }
529 }
530 
StartDecoding(const SizeF & dstSize)531 void ImagePattern::StartDecoding(const SizeF& dstSize)
532 {
533     // if layout size has not decided yet, resize target can not be calculated
534     auto host = GetHost();
535     CHECK_NULL_VOID(host);
536     if (!host->GetGeometryNode()->GetContent()) {
537         return;
538     }
539 
540     const auto& props = DynamicCast<ImageLayoutProperty>(host->GetLayoutProperty());
541     CHECK_NULL_VOID(props);
542     bool autoResize = props->GetAutoResize().value_or(autoResizeDefault_);
543 
544     ImageFit imageFit = props->GetImageFit().value_or(ImageFit::COVER);
545     const std::optional<SizeF>& sourceSize = props->GetSourceSize();
546     auto renderProp = host->GetPaintProperty<ImageRenderProperty>();
547     bool hasValidSlice = renderProp && (renderProp->HasImageResizableSlice() || renderProp->HasImageResizableLattice());
548     DynamicRangeMode dynamicMode = DynamicRangeMode::STANDARD;
549     bool isHdrDecoderNeed = false;
550     if (renderProp && renderProp->HasDynamicMode()) {
551         isHdrDecoderNeed = true;
552         dynamicMode = renderProp->GetDynamicMode().value_or(DynamicRangeMode::STANDARD);
553     }
554 
555     if (loadingCtx_) {
556         loadingCtx_->SetIsHdrDecoderNeed(isHdrDecoderNeed);
557         loadingCtx_->SetDynamicRangeMode(dynamicMode);
558         loadingCtx_->SetImageQuality(GetImageQuality());
559         loadingCtx_->MakeCanvasImageIfNeed(dstSize, autoResize, imageFit, sourceSize, hasValidSlice);
560     }
561     if (altLoadingCtx_) {
562         altLoadingCtx_->MakeCanvasImageIfNeed(dstSize, autoResize, imageFit, sourceSize, hasValidSlice);
563     }
564 }
565 
UpdateSvgSmoothEdgeValue()566 void ImagePattern::UpdateSvgSmoothEdgeValue()
567 {
568     auto host = GetHost();
569     CHECK_NULL_VOID(host);
570     auto pipeline = host->GetContext();
571     CHECK_NULL_VOID(pipeline);
572     auto theme = pipeline->GetTheme<ImageTheme>();
573     CHECK_NULL_VOID(theme);
574     auto renderProp = GetPaintProperty<ImageRenderProperty>();
575     CHECK_NULL_VOID(renderProp);
576     renderProp->UpdateSmoothEdge(std::max(theme->GetMinEdgeAntialiasing(), renderProp->GetSmoothEdge().value_or(0.0f)));
577 }
578 
SetImagePaintConfig(const RefPtr<CanvasImage> & canvasImage,const RectF & srcRect,const RectF & dstRect,const ImageSourceInfo & sourceInfo,int32_t frameCount)579 void ImagePattern::SetImagePaintConfig(const RefPtr<CanvasImage>& canvasImage, const RectF& srcRect,
580     const RectF& dstRect, const ImageSourceInfo& sourceInfo, int32_t frameCount)
581 {
582     auto layoutProps = GetLayoutProperty<ImageLayoutProperty>();
583     CHECK_NULL_VOID(layoutProps);
584 
585     ImagePaintConfig config {
586         .srcRect_ = srcRect,
587         .dstRect_ = dstRect,
588     };
589     config.imageFit_ = layoutProps->GetImageFit().value_or(ImageFit::COVER);
590     config.isSvg_ = sourceInfo.IsSvg();
591     config.frameCount_ = frameCount;
592     config.sourceInfo_ = sourceInfo;
593     config.orientation_ = joinOrientation_;
594     canvasImage->SetPaintConfig(config);
595 }
596 
CreateNodePaintMethod()597 RefPtr<NodePaintMethod> ImagePattern::CreateNodePaintMethod()
598 {
599     bool sensitive = false;
600     if (isSensitive_) {
601         auto host = GetHost();
602         CHECK_NULL_RETURN(host, nullptr);
603         sensitive = host->IsPrivacySensitive();
604     }
605     if (!overlayMod_) {
606         overlayMod_ = MakeRefPtr<ImageOverlayModifier>(selectedColor_);
607     }
608     if (image_) {
609         return MakeRefPtr<ImagePaintMethod>(image_, isSelected_, overlayMod_, sensitive, interpolationDefault_);
610     }
611     if (altImage_ && altDstRect_ && altSrcRect_) {
612         return MakeRefPtr<ImagePaintMethod>(altImage_, isSelected_, overlayMod_, sensitive, interpolationDefault_);
613     }
614     CreateObscuredImage();
615     if (obscuredImage_) {
616         return MakeRefPtr<ImagePaintMethod>(
617             obscuredImage_, isSelected_, overlayMod_, sensitive, interpolationDefault_);
618     }
619     return MakeRefPtr<ImagePaintMethod>(nullptr, isSelected_, overlayMod_, sensitive, interpolationDefault_);
620 }
621 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)622 bool ImagePattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
623 {
624     if (!isLayouted_ && GetIsAnimation()) {
625         isLayouted_ = true;
626         if (images_.size()) {
627             int32_t nextIndex = GetNextIndex(nowImageIndex_);
628             for (auto& cacheImage : cacheImages_) {
629                 UpdateCacheImageInfo(cacheImage, nextIndex);
630                 nextIndex = GetNextIndex(nextIndex);
631             }
632         }
633         return false;
634     }
635 
636     if (config.skipMeasure || dirty->SkipMeasureContent()) {
637         return false;
638     }
639 
640     const auto& dstSize = dirty->GetGeometryNode()->GetContentSize();
641     StartDecoding(dstSize);
642 
643     if (loadingCtx_) {
644         auto renderProp = GetPaintProperty<ImageRenderProperty>();
645         if (renderProp && (renderProp->HasImageResizableSlice() || renderProp->HasImageResizableLattice()) && image_) {
646             loadingCtx_->ResizableCalcDstSize();
647             SetImagePaintConfig(image_, loadingCtx_->GetSrcRect(), loadingCtx_->GetDstRect(), loadingCtx_->GetSrc(),
648                 loadingCtx_->GetFrameCount());
649         }
650     }
651 
652     if (altLoadingCtx_) {
653         auto renderProp = GetPaintProperty<ImageRenderProperty>();
654         if (renderProp && (renderProp->HasImageResizableSlice() || renderProp->HasImageResizableLattice()) &&
655             altImage_) {
656             altLoadingCtx_->ResizableCalcDstSize();
657             SetImagePaintConfig(altImage_, altLoadingCtx_->GetSrcRect(), altLoadingCtx_->GetDstRect(),
658                 altLoadingCtx_->GetSrc(), altLoadingCtx_->GetFrameCount());
659         }
660     }
661 
662     if (IsSupportImageAnalyzerFeature()) {
663         UpdateAnalyzerUIConfig(dirty->GetGeometryNode());
664     }
665 
666     return image_ || altImage_;
667 }
668 
CreateObscuredImage()669 void ImagePattern::CreateObscuredImage()
670 {
671     auto props = GetLayoutProperty<ImageLayoutProperty>();
672     CHECK_NULL_VOID(props);
673     auto layoutConstraint = props->GetLayoutConstraint();
674     CHECK_NULL_VOID(layoutConstraint);
675     auto host = GetHost();
676     CHECK_NULL_VOID(host);
677     auto sourceInfo = props->GetImageSourceInfo().value_or(ImageSourceInfo(""));
678     auto reasons = host->GetRenderContext()->GetObscured().value_or(std::vector<ObscuredReasons>());
679     if (reasons.size() && layoutConstraint->selfIdealSize.IsValid()) {
680         if (!obscuredImage_) {
681             obscuredImage_ = MakeRefPtr<ObscuredImage>();
682             SetImagePaintConfig(obscuredImage_, srcRect_, dstRect_, sourceInfo);
683         }
684     }
685 }
686 
LoadImage(const ImageSourceInfo & src,const PropertyChangeFlag & propertyChangeFlag,VisibleType visibleType)687 void ImagePattern::LoadImage(
688     const ImageSourceInfo& src, const PropertyChangeFlag& propertyChangeFlag, VisibleType visibleType)
689 {
690     if (loadingCtx_) {
691         auto srcKey = src.GetKey();
692         auto loadKey = loadingCtx_->GetSourceInfo().GetKey();
693         isPixelMapChanged_ = srcKey != loadKey;
694     }
695     LoadNotifier loadNotifier(CreateDataReadyCallback(), CreateLoadSuccessCallback(), CreateLoadFailCallback());
696     loadNotifier.onDataReadyComplete_ = CreateCompleteCallBackInDataReady();
697 
698     loadingCtx_ = AceType::MakeRefPtr<ImageLoadingContext>(src, std::move(loadNotifier), syncLoad_);
699     if (SystemProperties::GetDebugEnabled()) {
700         TAG_LOGD(AceLogTag::ACE_IMAGE, "start loading image %{public}s", src.ToString().c_str());
701     }
702     loadingCtx_->SetLoadInVipChannel(GetLoadInVipChannel());
703     loadingCtx_->SetNodeId(GetHost()->GetId());
704     if (onProgressCallback_) {
705         loadingCtx_->SetOnProgressCallback(std::move(onProgressCallback_));
706     }
707     if (!((propertyChangeFlag & PROPERTY_UPDATE_MEASURE) == PROPERTY_UPDATE_MEASURE) ||
708         visibleType == VisibleType::GONE) {
709         loadingCtx_->FinishMearuse();
710     }
711     loadingCtx_->LoadImageData();
712 }
713 
LoadAltImage(const ImageSourceInfo & altImageSourceInfo)714 void ImagePattern::LoadAltImage(const ImageSourceInfo& altImageSourceInfo)
715 {
716     CHECK_NULL_VOID(GetNeedLoadAlt());
717     LoadNotifier altLoadNotifier(CreateDataReadyCallbackForAlt(), CreateLoadSuccessCallbackForAlt(), nullptr);
718     if (!altLoadingCtx_ || altLoadingCtx_->GetSourceInfo() != altImageSourceInfo ||
719         (altLoadingCtx_ && altImageSourceInfo.IsSvg())) {
720         altLoadingCtx_ = AceType::MakeRefPtr<ImageLoadingContext>(altImageSourceInfo, std::move(altLoadNotifier));
721         altLoadingCtx_->LoadImageData();
722     }
723 }
724 
LoadImageDataIfNeed()725 void ImagePattern::LoadImageDataIfNeed()
726 {
727     auto imageLayoutProperty = GetLayoutProperty<ImageLayoutProperty>();
728     CHECK_NULL_VOID(imageLayoutProperty);
729     auto imageRenderProperty = GetPaintProperty<ImageRenderProperty>();
730     CHECK_NULL_VOID(imageRenderProperty);
731     auto src = imageLayoutProperty->GetImageSourceInfo().value_or(ImageSourceInfo(""));
732     UpdateInternalResource(src);
733     std::optional<Color> svgFillColorOpt = std::nullopt;
734     if (src.IsSvg()) {
735         svgFillColorOpt = src.GetFillColor();
736     }
737 
738     if (!loadingCtx_ || loadingCtx_->GetSourceInfo() != src || isImageQualityChange_ || isOrientationChange_) {
739         LoadImage(src, imageLayoutProperty->GetPropertyChangeFlag(),
740             imageLayoutProperty->GetVisibility().value_or(VisibleType::VISIBLE));
741     } else if (IsSupportImageAnalyzerFeature()) {
742         auto host = GetHost();
743         CHECK_NULL_VOID(host);
744         auto context = host->GetContext();
745         CHECK_NULL_VOID(context);
746         auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
747         uiTaskExecutor.PostTask([weak = WeakClaim(this)] {
748             auto pattern = weak.Upgrade();
749             CHECK_NULL_VOID(pattern);
750             ContainerScope scope(pattern->GetHostInstanceId());
751             pattern->CreateAnalyzerOverlay();
752             auto host = pattern->GetHost();
753             pattern->UpdateAnalyzerUIConfig(host->GetGeometryNode());
754         }, "ArkUIImageUpdateAnalyzerUIConfig");
755     }
756     if (loadingCtx_->NeedAlt() && imageLayoutProperty->GetAlt()) {
757         auto altImageSourceInfo = imageLayoutProperty->GetAlt().value_or(ImageSourceInfo(""));
758         LoadAltImage(altImageSourceInfo);
759     }
760 }
761 
UpdateGestureAndDragWhenModify()762 void ImagePattern::UpdateGestureAndDragWhenModify()
763 {
764     // remove long press and mouse events
765     auto host = GetHost();
766     CHECK_NULL_VOID(host);
767 
768     auto gestureHub = host->GetOrCreateGestureEventHub();
769     if (longPressEvent_) {
770         gestureHub->SetLongPressEvent(nullptr);
771         longPressEvent_ = nullptr;
772     }
773 
774     if (clickEvent_) {
775         gestureHub->RemoveClickEvent(clickEvent_);
776         clickEvent_ = nullptr;
777     }
778 
779     if (mouseEvent_) {
780         auto inputHub = host->GetOrCreateInputEventHub();
781         inputHub->RemoveOnMouseEvent(mouseEvent_);
782         mouseEvent_ = nullptr;
783     }
784 
785     if (host->IsDraggable()) {
786         EnableDrag();
787     }
788 }
789 
OnModifyDone()790 void ImagePattern::OnModifyDone()
791 {
792     switch (imageType_) {
793         case ImageType::BASE:
794             OnImageModifyDone();
795             break;
796         case ImageType::ANIMATION:
797             OnAnimatedModifyDone();
798             break;
799         default:
800             break;
801     }
802 }
803 
OnAnimatedModifyDone()804 void ImagePattern::OnAnimatedModifyDone()
805 {
806     auto host = GetHost();
807     CHECK_NULL_VOID(host);
808     Pattern::OnModifyDone();
809     auto size = static_cast<int32_t>(images_.size());
810     if (size <= 0) {
811         TAG_LOGW(AceLogTag::ACE_IMAGE, "image size is less than 0.");
812         return;
813     }
814     GenerateCachedImages();
815     auto index = nowImageIndex_;
816     if ((status_ == Animator::Status::IDLE || status_ == Animator::Status::STOPPED) && !firstUpdateEvent_) {
817         index = 0;
818     }
819 
820     if (imagesChangedFlag_) {
821         animator_->ClearInterpolators();
822         animator_->AddInterpolator(CreatePictureAnimation(size));
823         AdaptSelfSize();
824         imagesChangedFlag_ = false;
825     }
826     if (firstUpdateEvent_) {
827         firstUpdateEvent_ = false;
828         auto imageFrameNode = AceType::DynamicCast<FrameNode>(host->GetChildren().front());
829         AddImageLoadSuccessEvent(imageFrameNode);
830     }
831     UpdateFormDurationByRemainder();
832     SetObscured();
833     if (isSrcUndefined_) {
834         return;
835     }
836     ControlAnimation(index);
837 }
838 
ControlAnimation(int32_t index)839 void ImagePattern::ControlAnimation(int32_t index)
840 {
841     if (!animator_->HasScheduler()) {
842         auto context = PipelineContext::GetCurrentContext();
843         if (context) {
844             animator_->AttachScheduler(context);
845         } else {
846             TAG_LOGW(AceLogTag::ACE_IMAGE, "pipelineContext is null.");
847         }
848     }
849     switch (status_) {
850         case Animator::Status::IDLE:
851             animator_->Cancel();
852             ResetFormAnimationFlag();
853             SetShowingIndex(index);
854             break;
855         case Animator::Status::PAUSED:
856             animator_->Pause();
857             ResetFormAnimationFlag();
858             break;
859         case Animator::Status::STOPPED:
860             animator_->Finish();
861             ResetFormAnimationFlag();
862             break;
863         default:
864             ResetFormAnimationStartTime();
865             if (isFormAnimationEnd_) {
866                 ResetFormAnimationFlag();
867                 return;
868             }
869             auto host = GetHost();
870             CHECK_NULL_VOID(host);
871             if (host->IsVisible()) {
872                 animator_->Forward();
873             } else {
874                 animator_->Pause();
875             }
876     }
877 }
878 
OnImageModifyDone()879 void ImagePattern::OnImageModifyDone()
880 {
881     Pattern::OnModifyDone();
882     LoadImageDataIfNeed();
883     UpdateGestureAndDragWhenModify();
884 
885     if (copyOption_ != CopyOptions::None) {
886         auto host = GetHost();
887         CHECK_NULL_VOID(host);
888         bool hasObscured = false;
889         if (host->GetRenderContext()->GetObscured().has_value()) {
890             auto obscuredReasons = host->GetRenderContext()->GetObscured().value();
891             hasObscured = std::any_of(obscuredReasons.begin(), obscuredReasons.end(),
892                 [](const auto& reason) { return reason == ObscuredReasons::PLACEHOLDER; });
893         }
894         if (!hasObscured) {
895             InitCopy();
896             return;
897         }
898     }
899 
900     CloseSelectOverlay();
901 
902     auto host = GetHost();
903     CHECK_NULL_VOID(host);
904 
905     if (imageAnalyzerManager_ && imageAnalyzerManager_->IsOverlayCreated()) {
906         if (!IsSupportImageAnalyzerFeature()) {
907             DestroyAnalyzerOverlay();
908         } else {
909             UpdateAnalyzerOverlayLayout();
910         }
911     }
912 
913     // SetUsingContentRectForRenderFrame is set for image paint
914     auto overlayNode = host->GetOverlayNode();
915     if (overlayNode) {
916         auto layoutProperty = host->GetLayoutProperty();
917         CHECK_NULL_VOID(layoutProperty);
918         auto padding = layoutProperty->CreatePaddingAndBorder();
919         auto renderContext = overlayNode->GetRenderContext();
920         if (renderContext) {
921             renderContext->SetRenderFrameOffset({-padding.Offset().GetX(), -padding.Offset().GetY()});
922         }
923     }
924 }
925 
CreateDataReadyCallbackForAlt()926 DataReadyNotifyTask ImagePattern::CreateDataReadyCallbackForAlt()
927 {
928     return [weak = WeakClaim(this)](const ImageSourceInfo& sourceInfo) {
929         auto pattern = weak.Upgrade();
930         CHECK_NULL_VOID(pattern);
931         CHECK_NULL_VOID(pattern->altLoadingCtx_);
932         auto imageLayoutProperty = pattern->GetLayoutProperty<ImageLayoutProperty>();
933         CHECK_NULL_VOID(imageLayoutProperty);
934         auto currentAltSourceInfo = imageLayoutProperty->GetAlt().value_or(ImageSourceInfo(""));
935         if (currentAltSourceInfo != sourceInfo) {
936             TAG_LOGW(AceLogTag::ACE_IMAGE, "alt image sourceInfo does not match, ignore current callback. "
937                  "current: %{private}s vs callback's: %{private}s",
938                 currentAltSourceInfo.ToString().c_str(), sourceInfo.ToString().c_str());
939             return;
940         }
941         auto host = pattern->GetHost();
942         CHECK_NULL_VOID(host);
943         if (!host->IsActive()) {
944             return;
945         }
946         const auto& geometryNode = host->GetGeometryNode();
947         CHECK_NULL_VOID(geometryNode);
948         if (!geometryNode->GetContent()) {
949             host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
950             return;
951         }
952 
953         // calculate params for [altLoadingCtx] to do [MakeCanvasImage] if component size is already settled
954         pattern->altLoadingCtx_->MakeCanvasImageIfNeed(
955             geometryNode->GetContentSize(), true, imageLayoutProperty->GetImageFit().value_or(ImageFit::COVER));
956     };
957 }
958 
CreateLoadSuccessCallbackForAlt()959 LoadSuccessNotifyTask ImagePattern::CreateLoadSuccessCallbackForAlt()
960 {
961     return [weak = WeakClaim(this)](const ImageSourceInfo& sourceInfo) {
962         auto pattern = weak.Upgrade();
963         CHECK_NULL_VOID(pattern);
964         CHECK_NULL_VOID(pattern->altLoadingCtx_);
965         auto layoutProps = pattern->GetLayoutProperty<ImageLayoutProperty>();
966         auto currentAltSrc = layoutProps->GetAlt().value_or(ImageSourceInfo(""));
967         if (currentAltSrc != sourceInfo) {
968             TAG_LOGW(AceLogTag::ACE_IMAGE, "alt image sourceInfo does not match, ignore current callback. "
969                  "current: %{private}s vs callback's: %{private}s",
970                 currentAltSrc.ToString().c_str(), sourceInfo.ToString().c_str());
971             return;
972         }
973         pattern->altImage_ = pattern->altLoadingCtx_->MoveCanvasImage();
974         CHECK_NULL_VOID(pattern->altImage_);
975         pattern->altSrcRect_ = std::make_unique<RectF>(pattern->altLoadingCtx_->GetSrcRect());
976         pattern->altDstRect_ = std::make_unique<RectF>(pattern->altLoadingCtx_->GetDstRect());
977         pattern->SetImagePaintConfig(pattern->altImage_, *pattern->altSrcRect_, *pattern->altDstRect_,
978             pattern->altLoadingCtx_->GetSourceInfo(), pattern->altLoadingCtx_->GetFrameCount());
979 
980         pattern->PrepareAnimation(pattern->altImage_);
981 
982         auto host = pattern->GetHost();
983         CHECK_NULL_VOID(host);
984         host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
985     };
986 }
987 
UpdateInternalResource(ImageSourceInfo & sourceInfo)988 void ImagePattern::UpdateInternalResource(ImageSourceInfo& sourceInfo)
989 {
990     if (!sourceInfo.IsInternalResource()) {
991         return;
992     }
993 
994     auto pipeline = GetHost()->GetContext();
995     CHECK_NULL_VOID(pipeline);
996     auto iconTheme = pipeline->GetTheme<IconTheme>();
997     CHECK_NULL_VOID(iconTheme);
998     auto iconPath = iconTheme->GetIconPath(sourceInfo.GetResourceId());
999     if (!iconPath.empty()) {
1000         sourceInfo.SetSrc(iconPath, sourceInfo.GetFillColor());
1001         auto imageLayoutProperty = GetLayoutProperty<ImageLayoutProperty>();
1002         CHECK_NULL_VOID(imageLayoutProperty);
1003         imageLayoutProperty->UpdateImageSourceInfo(sourceInfo);
1004     }
1005 }
1006 
OnNotifyMemoryLevel(int32_t level)1007 void ImagePattern::OnNotifyMemoryLevel(int32_t level)
1008 {
1009     // when image component is [onShow], do not clean image data
1010     if (isShow_ || level <= static_cast<int32_t>(MEMORY_LEVEL_LOW_STATUS)) {
1011         return;
1012     }
1013     // clean image data
1014     loadingCtx_ = nullptr;
1015     image_ = nullptr;
1016     altLoadingCtx_ = nullptr;
1017     altImage_ = nullptr;
1018 }
1019 
1020 // when recycle image component, release the pixelmap resource
OnRecycle()1021 void ImagePattern::OnRecycle()
1022 {
1023     loadingCtx_ = nullptr;
1024     image_ = nullptr;
1025     altLoadingCtx_ = nullptr;
1026     altImage_ = nullptr;
1027 
1028     auto frameNode = GetHost();
1029     CHECK_NULL_VOID(frameNode);
1030     auto rsRenderContext = frameNode->GetRenderContext();
1031     CHECK_NULL_VOID(rsRenderContext);
1032     rsRenderContext->ClearDrawCommands();
1033     UnregisterWindowStateChangedCallback();
1034 }
1035 
OnReuse()1036 void ImagePattern::OnReuse()
1037 {
1038     RegisterWindowStateChangedCallback();
1039     auto renderProp = GetPaintProperty<ImageRenderProperty>();
1040     CHECK_NULL_VOID(renderProp);
1041     renderProp->UpdateNeedBorderRadius(needBorderRadius_);
1042     LoadImageDataIfNeed();
1043 }
1044 
RegisterWindowStateChangedCallback()1045 void ImagePattern::RegisterWindowStateChangedCallback()
1046 {
1047     auto host = GetHost();
1048     CHECK_NULL_VOID(host);
1049     auto pipeline = host->GetContext();
1050     CHECK_NULL_VOID(pipeline);
1051     pipeline->AddWindowStateChangedCallback(host->GetId());
1052 }
1053 
UnregisterWindowStateChangedCallback()1054 void ImagePattern::UnregisterWindowStateChangedCallback()
1055 {
1056     auto host = GetHost();
1057     CHECK_NULL_VOID(host);
1058     auto pipeline = host->GetContext();
1059     CHECK_NULL_VOID(pipeline);
1060     pipeline->RemoveWindowStateChangedCallback(host->GetId());
1061 }
1062 
OnWindowHide()1063 void ImagePattern::OnWindowHide()
1064 {
1065     isShow_ = false;
1066 }
1067 
OnWindowShow()1068 void ImagePattern::OnWindowShow()
1069 {
1070     isShow_ = true;
1071     LoadImageDataIfNeed();
1072 }
1073 
OnVisibleChange(bool visible)1074 void ImagePattern::OnVisibleChange(bool visible)
1075 {
1076     if (!visible) {
1077         CloseSelectOverlay();
1078     }
1079 }
1080 
OnVisibleAreaChange(bool visible,double ratio)1081 void ImagePattern::OnVisibleAreaChange(bool visible, double ratio)
1082 {
1083     if (SystemProperties::GetDebugEnabled()) {
1084         TAG_LOGD(AceLogTag::ACE_IMAGE, "OnVisibleAreaChange visible:%{public}d", (int)visible);
1085     }
1086     if (!visible) {
1087         CloseSelectOverlay();
1088     }
1089     // control pixelMap List
1090     if (GetIsAnimation() && !animator_->IsStopped()) {
1091         if (visible) {
1092             animator_->Forward();
1093         } else {
1094             animator_->Pause();
1095         }
1096     }
1097     gifAnimation_ = visible;
1098     // control svg / gif animation
1099     if (image_) {
1100         image_->ControlAnimation(visible);
1101     } else if (altImage_) {
1102         altImage_->ControlAnimation(visible);
1103     }
1104 
1105     if (isEnableAnalyzer_) {
1106         auto host = GetHost();
1107         CHECK_NULL_VOID(host);
1108         auto overlayNode = host->GetOverlayNode();
1109         CHECK_NULL_VOID(overlayNode);
1110         TriggerVisibleAreaChangeForChild(overlayNode, visible, ratio);
1111     }
1112 }
1113 
OnAttachToFrameNode()1114 void ImagePattern::OnAttachToFrameNode()
1115 {
1116     auto host = GetHost();
1117     CHECK_NULL_VOID(host);
1118     auto renderCtx = host->GetRenderContext();
1119     CHECK_NULL_VOID(renderCtx);
1120     auto pipeline = host->GetContext();
1121     CHECK_NULL_VOID(pipeline);
1122     if (GetIsAnimation()) {
1123         renderCtx->SetClipToFrame(true);
1124     } else {
1125         renderCtx->SetClipToBounds(false);
1126         renderCtx->SetUsingContentRectForRenderFrame(true);
1127 
1128         // register image frame node to pipeline context to receive memory level notification and window state change
1129         // notification
1130         pipeline->AddNodesToNotifyMemoryLevel(host->GetId());
1131         pipeline->AddWindowStateChangedCallback(host->GetId());
1132     }
1133     auto theme = pipeline->GetTheme<TextTheme>();
1134     CHECK_NULL_VOID(theme);
1135     selectedColor_ = theme->GetSelectedColor();
1136 }
1137 
OnDetachFromFrameNode(FrameNode * frameNode)1138 void ImagePattern::OnDetachFromFrameNode(FrameNode* frameNode)
1139 {
1140     CloseSelectOverlay();
1141 
1142     auto id = frameNode->GetId();
1143     auto pipeline = AceType::DynamicCast<PipelineContext>(PipelineBase::GetCurrentContext());
1144     CHECK_NULL_VOID(pipeline);
1145     pipeline->RemoveWindowStateChangedCallback(id);
1146     pipeline->RemoveNodesToNotifyMemoryLevel(id);
1147 }
1148 
EnableDrag()1149 void ImagePattern::EnableDrag()
1150 {
1151     auto host = GetHost();
1152     CHECK_NULL_VOID(host);
1153     auto dragStart = [weak = WeakClaim(this)](const RefPtr<OHOS::Ace::DragEvent>& event,
1154                          const std::string& /*extraParams*/) -> DragDropInfo {
1155         DragDropInfo info;
1156         auto imagePattern = weak.Upgrade();
1157         CHECK_NULL_RETURN(imagePattern && imagePattern->loadingCtx_, info);
1158         AceEngineExt::GetInstance().DragStartExt();
1159         imagePattern->UpdateDragEvent(event);
1160         info.extraInfo = imagePattern->loadingCtx_->GetSourceInfo().GetSrc();
1161         return info;
1162     };
1163     auto eventHub = host->GetEventHub<EventHub>();
1164     CHECK_NULL_VOID(eventHub);
1165     eventHub->SetDefaultOnDragStart(std::move(dragStart));
1166 }
1167 
BetweenSelectedPosition(const Offset & globalOffset)1168 bool ImagePattern::BetweenSelectedPosition(const Offset& globalOffset)
1169 {
1170     auto host = GetHost();
1171     CHECK_NULL_RETURN(host, false);
1172     auto globalRect = host->GetTransformRectRelativeToWindow();
1173     return globalRect.IsInRegion(PointF { globalOffset.GetX(), globalOffset.GetY() });
1174 }
1175 
BeforeCreatePaintWrapper()1176 void ImagePattern::BeforeCreatePaintWrapper()
1177 {
1178     auto host = GetHost();
1179     CHECK_NULL_VOID(host);
1180     host->GetRenderContext()->MarkContentChanged(true);
1181 }
1182 
InitCopy()1183 void ImagePattern::InitCopy()
1184 {
1185     if (longPressEvent_ && mouseEvent_ && clickEvent_) {
1186         return;
1187     }
1188     auto longPressTask = [weak = WeakClaim(this)](GestureEvent& info) {
1189         auto pattern = weak.Upgrade();
1190         CHECK_NULL_VOID(pattern);
1191         pattern->OpenSelectOverlay();
1192     };
1193     longPressEvent_ = MakeRefPtr<LongPressEvent>(std::move(longPressTask));
1194 
1195     auto host = GetHost();
1196     CHECK_NULL_VOID(host);
1197     auto gestureHub = host->GetOrCreateGestureEventHub();
1198     gestureHub->SetLongPressEvent(longPressEvent_);
1199 
1200     auto mouseTask = [weak = WeakClaim(this)](MouseInfo& info) {
1201         if (info.GetButton() == MouseButton::RIGHT_BUTTON && info.GetAction() == MouseAction::PRESS) {
1202             auto pattern = weak.Upgrade();
1203             CHECK_NULL_VOID(pattern);
1204             pattern->OpenSelectOverlay();
1205         }
1206     };
1207     mouseEvent_ = MakeRefPtr<InputEvent>(std::move(mouseTask));
1208     auto inputHub = host->GetOrCreateInputEventHub();
1209     CHECK_NULL_VOID(inputHub);
1210     inputHub->AddOnMouseEvent(mouseEvent_);
1211 
1212     // close overlay on click
1213     clickEvent_ = MakeRefPtr<ClickEvent>([weak = WeakClaim(this)](GestureEvent& callback) {
1214         auto pattern = weak.Upgrade();
1215         CHECK_NULL_VOID(pattern);
1216         pattern->CloseSelectOverlay();
1217     });
1218     gestureHub->AddClickEvent(clickEvent_);
1219 }
1220 
OpenSelectOverlay()1221 void ImagePattern::OpenSelectOverlay()
1222 {
1223     auto host = GetHost();
1224     CHECK_NULL_VOID(host);
1225     const auto& geometryNode = host->GetGeometryNode();
1226     CHECK_NULL_VOID(geometryNode);
1227     auto rect = host->GetTransformRectRelativeToWindow();
1228     SelectOverlayInfo info;
1229     SizeF handleSize = {
1230         SelectHandleInfo::GetDefaultLineWidth().ConvertToPx(),
1231         geometryNode->GetContentSize().Height() };
1232     info.firstHandle.paintRect = RectF(rect.GetOffset(), handleSize);
1233     OffsetF offset(rect.Width() - handleSize.Width(), rect.Height() - handleSize.Height());
1234     info.secondHandle.paintRect = RectF(rect.GetOffset() + offset, handleSize);
1235     info.menuInfo.menuIsShow = true;
1236     info.menuInfo.showCut = false;
1237     info.menuInfo.showPaste = false;
1238     info.menuCallback.onCopy = [weak = WeakClaim(this)]() {
1239         auto pattern = weak.Upgrade();
1240         CHECK_NULL_VOID(pattern);
1241         pattern->HandleCopy();
1242         pattern->CloseSelectOverlay();
1243     };
1244     info.onHandleMoveDone = [weak = WeakClaim(this), firstRect = info.firstHandle.paintRect,
1245                                 secondRect = info.secondHandle.paintRect](const RectF&, bool isFirst) {
1246         // reset handle position
1247         auto pattern = weak.Upgrade();
1248         CHECK_NULL_VOID(pattern && pattern->selectOverlay_);
1249         SelectHandleInfo info;
1250         if (isFirst) {
1251             info.paintRect = firstRect;
1252             pattern->selectOverlay_->UpdateFirstSelectHandleInfo(info);
1253         } else {
1254             info.paintRect = secondRect;
1255             pattern->selectOverlay_->UpdateSecondSelectHandleInfo(info);
1256         }
1257     };
1258     info.onClose = [weak = WeakClaim(this)](bool closedByGlobalEvent) {
1259         if (closedByGlobalEvent) {
1260             auto pattern = weak.Upgrade();
1261             CHECK_NULL_VOID(pattern);
1262             pattern->CloseSelectOverlay();
1263         }
1264     };
1265 
1266     auto pipeline = host->GetContext();
1267     CHECK_NULL_VOID(pipeline);
1268     selectOverlay_ = pipeline->GetSelectOverlayManager()->CreateAndShowSelectOverlay(info, WeakClaim(this));
1269     isSelected_ = true;
1270     CHECK_NULL_VOID(selectOverlay_);
1271     pipeline->AddOnAreaChangeNode(host->GetId());
1272     // paint selected mask effect
1273     host->MarkNeedRenderOnly();
1274 }
1275 
CloseSelectOverlay()1276 void ImagePattern::CloseSelectOverlay()
1277 {
1278     if (!selectOverlay_) {
1279         return;
1280     }
1281     if (!selectOverlay_->IsClosed()) {
1282         selectOverlay_->Close();
1283     }
1284     isSelected_ = false;
1285     // remove selected mask effect
1286     auto host = GetHost();
1287     CHECK_NULL_VOID(host);
1288     RemoveAreaChangeInner();
1289     host->MarkNeedRenderOnly();
1290 }
1291 
HandleCopy()1292 void ImagePattern::HandleCopy()
1293 {
1294     CHECK_NULL_VOID(image_);
1295     if (!clipboard_) {
1296         auto host = GetHost();
1297         CHECK_NULL_VOID(host);
1298         auto pipeline = host->GetContext();
1299         CHECK_NULL_VOID(pipeline);
1300         clipboard_ = ClipboardProxy::GetInstance()->GetClipboard(pipeline->GetTaskExecutor());
1301     }
1302     auto pixmap = image_->GetPixelMap();
1303     if (pixmap) {
1304         clipboard_->SetPixelMapData(pixmap, copyOption_);
1305     } else {
1306         auto host = GetHost();
1307         CHECK_NULL_VOID(host);
1308         clipboard_->SetData(loadingCtx_->GetSourceInfo().GetSrc());
1309     }
1310 }
1311 
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const1312 void ImagePattern::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
1313 {
1314     /* no fixed attr below, just return */
1315     if (filter.IsFastFilter()) {
1316         return;
1317     }
1318     static const char* COPY_OPTIONS[] = { "CopyOptions.None", "CopyOptions.InApp", "CopyOptions.Local",
1319         "CopyOptions.Distributed" };
1320     json->PutExtAttr("copyOption", COPY_OPTIONS[static_cast<int32_t>(copyOption_)], filter);
1321 
1322     json->PutExtAttr("syncLoad", syncLoad_ ? "true" : "false", filter);
1323     auto host = GetHost();
1324     CHECK_NULL_VOID(host);
1325     json->PutExtAttr("draggable", host->IsDraggable() ? "true" : "false", filter);
1326     json->PutExtAttr("enableAnalyzer", isEnableAnalyzer_ ? "true" : "false", filter);
1327     auto renderProp = GetPaintProperty<ImageRenderProperty>();
1328     CHECK_NULL_VOID(renderProp);
1329     DynamicRangeMode dynamicMode = DynamicRangeMode::STANDARD;
1330     if (renderProp->HasDynamicMode()) {
1331         dynamicMode = renderProp->GetDynamicMode().value_or(DynamicRangeMode::STANDARD);
1332     }
1333     json->PutExtAttr("dynamicRangeMode", GetDynamicModeString(dynamicMode).c_str(), filter);
1334     json->PutExtAttr("orientation", std::to_string(static_cast<int>(userOrientation_)).c_str(), filter);
1335     Matrix4 defaultMatrixValue = Matrix4(
1336         1.0f, 0, 0, 0,
1337         0, 1.0f, 0, 0,
1338         0, 0, 1.0f, 0,
1339         0, 0, 0, 1.0f);
1340     Matrix4 matrixValue = renderProp->HasImageMatrix() ? renderProp->GetImageMatrixValue() : defaultMatrixValue;
1341     json->PutExtAttr("imageMatrix", matrixValue.ToString().c_str(), filter);
1342 }
1343 
UpdateFillColorIfForegroundColor()1344 void ImagePattern::UpdateFillColorIfForegroundColor()
1345 {
1346     auto frameNode = GetHost();
1347     CHECK_NULL_VOID(frameNode);
1348     auto renderContext = frameNode->GetRenderContext();
1349     CHECK_NULL_VOID(renderContext);
1350     if (renderContext->HasForegroundColor() || renderContext->HasForegroundColorStrategy()) {
1351         auto imageLayoutProperty = frameNode->GetLayoutProperty<ImageLayoutProperty>();
1352         auto imageSourceInfo = imageLayoutProperty->GetImageSourceInfo().value();
1353         if (imageSourceInfo.IsSvg()) {
1354             imageSourceInfo.SetFillColor(Color::FOREGROUND);
1355             imageLayoutProperty->UpdateImageSourceInfo(imageSourceInfo);
1356         }
1357         auto imageRenderProperty = frameNode->GetPaintProperty<ImageRenderProperty>();
1358         CHECK_NULL_VOID(imageRenderProperty);
1359         imageRenderProperty->UpdateSvgFillColor(Color::FOREGROUND);
1360     }
1361 }
1362 
DumpLayoutInfo()1363 void ImagePattern::DumpLayoutInfo()
1364 {
1365     auto layoutProp = GetLayoutProperty<ImageLayoutProperty>();
1366     CHECK_NULL_VOID(layoutProp);
1367     auto src = layoutProp->GetImageSourceInfo().value_or(ImageSourceInfo(""));
1368     DumpLog::GetInstance().AddDesc(std::string("url: ").append(src.ToString()));
1369 
1370     auto altSrc = layoutProp->GetAlt().value_or(ImageSourceInfo(""));
1371     DumpLog::GetInstance().AddDesc(std::string("altUrl: ").append(altSrc.ToString()));
1372 
1373     auto imageFit = layoutProp->GetImageFit().value_or(ImageFit::COVER);
1374     DumpLog::GetInstance().AddDesc(std::string("objectFit: ").append(GetImageFitStr(imageFit)));
1375 
1376     auto fitOriginalSize = layoutProp->GetFitOriginalSize().value_or(false);
1377     DumpLog::GetInstance().AddDesc(std::string("fitOriginalSize: ").append(fitOriginalSize ? "true" : "false"));
1378 
1379     const std::optional<SizeF>& sourceSize = layoutProp->GetSourceSize();
1380     if (sourceSize.has_value()) {
1381         DumpLog::GetInstance().AddDesc(std::string("sourceSize: ").append(sourceSize.value().ToString()));
1382     }
1383 
1384     bool autoResize = layoutProp->GetAutoResize().value_or(autoResizeDefault_);
1385     autoResize ? DumpLog::GetInstance().AddDesc("autoResize:true")
1386                        : DumpLog::GetInstance().AddDesc("autoResize:false");
1387 }
1388 
DumpRenderInfo()1389 void ImagePattern::DumpRenderInfo()
1390 {
1391     auto renderProp = GetPaintProperty<ImageRenderProperty>();
1392     CHECK_NULL_VOID(renderProp);
1393 
1394     auto imageRenderMode = renderProp->GetImageRenderMode().value_or(ImageRenderMode::ORIGINAL);
1395     DumpLog::GetInstance().AddDesc(
1396         std::string("renderMode: ").append((imageRenderMode == ImageRenderMode::ORIGINAL) ? "Original" : "Template"));
1397 
1398     auto imageRepeat = renderProp->GetImageRepeat().value_or(ImageRepeat::NO_REPEAT);
1399     DumpLog::GetInstance().AddDesc(std::string("objectRepeat: ").append(GetImageRepeatStr(imageRepeat)));
1400 
1401     auto imageColorFilter = renderProp->GetColorFilter();
1402     if (imageColorFilter.has_value()) {
1403         auto colorFilter = imageColorFilter.value();
1404         DumpLog::GetInstance().AddDesc(std::string("colorFilter: ").append(GetImageColorFilterStr(colorFilter)));
1405     }
1406 
1407     auto fillColor = renderProp->GetSvgFillColor();
1408     if (fillColor.has_value()) {
1409         auto color = fillColor.value();
1410         DumpLog::GetInstance().AddDesc(std::string("fillColor: ").append(color.ColorToString()));
1411     } else {
1412         DumpLog::GetInstance().AddDesc("fillColor: Null");
1413     }
1414 
1415     DynamicRangeMode dynamicMode = DynamicRangeMode::STANDARD;
1416     if (renderProp->HasDynamicMode()) {
1417         dynamicMode = renderProp->GetDynamicMode().value_or(DynamicRangeMode::STANDARD);
1418         DumpLog::GetInstance().AddDesc(std::string("dynamicRangeMode: ").append(GetDynamicModeString(dynamicMode)));
1419     }
1420 
1421     auto matchTextDirection = renderProp->GetMatchTextDirection().value_or(false);
1422     matchTextDirection ? DumpLog::GetInstance().AddDesc("matchTextDirection:true")
1423                        : DumpLog::GetInstance().AddDesc("matchTextDirection:false");
1424 
1425     auto smoothEdge = renderProp->GetSmoothEdge();
1426     if (smoothEdge.has_value()) {
1427         DumpLog::GetInstance().AddDesc(std::string("edgeAntialiasing: ").append(std::to_string(smoothEdge.value())));
1428     }
1429 
1430     auto needBorderRadius = renderProp->GetNeedBorderRadius().value_or(false);
1431     needBorderRadius ? DumpLog::GetInstance().AddDesc("needBorderRadius:true")
1432                      : DumpLog::GetInstance().AddDesc("needBorderRadius:false");
1433 
1434     auto borderRadius = renderProp->GetBorderRadius().value_or(BorderRadiusProperty());
1435     DumpLog::GetInstance().AddDesc(borderRadius.ToString());
1436 
1437     if (renderProp && renderProp->HasImageResizableSlice() && renderProp->GetImageResizableSliceValue({}).Valid()) {
1438         DumpLog::GetInstance().AddDesc(
1439             std::string("resizable slice: ").append(renderProp->GetImageResizableSliceValue({}).ToString()));
1440     }
1441 }
1442 
DumpSvgInfo()1443 void ImagePattern::DumpSvgInfo()
1444 {
1445     auto imageLayoutProperty = GetLayoutProperty<ImageLayoutProperty>();
1446     CHECK_NULL_VOID(imageLayoutProperty);
1447     auto imageSourceInfo = imageLayoutProperty->GetImageSourceInfo();
1448     CHECK_NULL_VOID(imageSourceInfo);
1449     if (!imageSourceInfo->IsSvg()|| !loadingCtx_) {
1450         return;
1451     }
1452     auto imageObject = loadingCtx_->GetImageObject();
1453     CHECK_NULL_VOID(imageObject);
1454     DumpLog::GetInstance().AddDesc(
1455         std::string("Svg:").append(imageObject->GetDumpInfo()));
1456 }
1457 
DumpInfo()1458 void ImagePattern::DumpInfo()
1459 {
1460     DumpLayoutInfo();
1461     DumpRenderInfo();
1462 
1463     syncLoad_ ? DumpLog::GetInstance().AddDesc("syncLoad:true") : DumpLog::GetInstance().AddDesc("syncLoad:false");
1464 
1465     DumpLog::GetInstance().AddDesc("imageInterpolation:" + GetImageInterpolation(interpolation_));
1466     if (loadingCtx_) {
1467         auto currentLoadImageState = loadingCtx_->GetCurrentLoadingState();
1468         DumpLog::GetInstance().AddDesc(std::string("currentLoadImageState : ").append(currentLoadImageState));
1469         DumpLog::GetInstance().AddDesc(
1470             std::string("rawImageSize: ").append(loadingCtx_->GetOriginImageSize().ToString()));
1471         DumpLog::GetInstance().AddDesc(std::string("LoadErrorMsg: ").append(loadingCtx_->GetErrorMsg()));
1472     } else {
1473         DumpLog::GetInstance().AddDesc(std::string("imageLoadingContext: null"));
1474     }
1475 
1476     auto host = GetHost();
1477 if (host) {
1478         auto enDrage = host->IsDraggable();
1479         enDrage ? DumpLog::GetInstance().AddDesc("draggable:true") : DumpLog::GetInstance().AddDesc("draggable:false");
1480     }
1481     DumpLog::GetInstance().AddDesc(
1482         std::string("userOrientation: ").append(ConvertOrientationToString(userOrientation_)));
1483     DumpLog::GetInstance().AddDesc(
1484         std::string("selfOrientation: ").append(ConvertOrientationToString(selfOrientation_)));
1485     DumpLog::GetInstance().AddDesc(std::string("enableAnalyzer: ").append(isEnableAnalyzer_ ? "true" : "false"));
1486     DumpSvgInfo();
1487 }
1488 
DumpAdvanceInfo()1489 void ImagePattern::DumpAdvanceInfo()
1490 {
1491     auto layoutProp = GetLayoutProperty<ImageLayoutProperty>();
1492     CHECK_NULL_VOID(layoutProp);
1493     auto src = layoutProp->GetImageSourceInfo().value_or(ImageSourceInfo(""));
1494     DumpLog::GetInstance().AddDesc(std::string("url: ").append(layoutProp->GetImageSourceInfo()->ToString()));
1495     syncLoad_ ? DumpLog::GetInstance().AddDesc("syncLoad:true") : DumpLog::GetInstance().AddDesc("syncLoad:false");
1496     if (loadingCtx_) {
1497         auto currentLoadImageState = loadingCtx_->GetCurrentLoadingState();
1498         DumpLog::GetInstance().AddDesc(std::string("currentLoadImageState : ").append(currentLoadImageState));
1499     }
1500 }
1501 
UpdateDragEvent(const RefPtr<OHOS::Ace::DragEvent> & event)1502 void ImagePattern::UpdateDragEvent(const RefPtr<OHOS::Ace::DragEvent>& event)
1503 {
1504     RefPtr<UnifiedData> unifiedData = UdmfClient::GetInstance()->CreateUnifiedData();
1505     if (loadingCtx_ && image_ && loadingCtx_->GetSourceInfo().IsPixmap()) {
1506         auto pixelMap = image_->GetPixelMap();
1507         CHECK_NULL_VOID(pixelMap);
1508         std::vector<uint8_t> data;
1509         if (!pixelMap->GetPixelsVec(data)) {
1510             return;
1511         }
1512         PixelMapRecordDetails details = { pixelMap->GetWidth(), pixelMap->GetHeight(), pixelMap->GetPixelFormat(),
1513             pixelMap->GetAlphaType() };
1514         UdmfClient::GetInstance()->AddPixelMapRecord(unifiedData, data, details);
1515     } else if (loadingCtx_) {
1516         UdmfClient::GetInstance()->AddImageRecord(unifiedData, loadingCtx_->GetSourceInfo().GetSrc());
1517     }
1518     event->SetData(unifiedData);
1519 }
1520 
OnLanguageConfigurationUpdate()1521 void ImagePattern::OnLanguageConfigurationUpdate()
1522 {
1523     CHECK_NULL_VOID(loadingCtx_);
1524     auto&& src = loadingCtx_->GetSourceInfo();
1525     // Resource image needs to reload when Language changes
1526     if (src.GetSrcType() == SrcType::RESOURCE) {
1527         loadingCtx_.Reset();
1528     }
1529     OnConfigurationUpdate();
1530 }
1531 
OnColorConfigurationUpdate()1532 void ImagePattern::OnColorConfigurationUpdate()
1533 {
1534     OnConfigurationUpdate();
1535 }
1536 
OnDirectionConfigurationUpdate()1537 void ImagePattern::OnDirectionConfigurationUpdate()
1538 {
1539     OnConfigurationUpdate();
1540 }
1541 
OnIconConfigurationUpdate()1542 void ImagePattern::OnIconConfigurationUpdate()
1543 {
1544     OnConfigurationUpdate();
1545 }
1546 
OnConfigurationUpdate()1547 void ImagePattern::OnConfigurationUpdate()
1548 {
1549     CHECK_NULL_VOID(loadingCtx_);
1550     auto imageLayoutProperty = GetLayoutProperty<ImageLayoutProperty>();
1551     CHECK_NULL_VOID(imageLayoutProperty);
1552     auto src = imageLayoutProperty->GetImageSourceInfo().value_or(ImageSourceInfo(""));
1553     UpdateInternalResource(src);
1554 
1555     LoadImage(src, imageLayoutProperty->GetPropertyChangeFlag(),
1556         imageLayoutProperty->GetVisibility().value_or(VisibleType::VISIBLE));
1557     if (loadingCtx_->NeedAlt() && imageLayoutProperty->GetAlt()) {
1558         auto altImageSourceInfo = imageLayoutProperty->GetAlt().value_or(ImageSourceInfo(""));
1559         if (altLoadingCtx_ && altLoadingCtx_->GetSourceInfo() == altImageSourceInfo) {
1560             altLoadingCtx_.Reset();
1561         }
1562         LoadAltImage(altImageSourceInfo);
1563     }
1564 }
1565 
GetImageFitStr(ImageFit value)1566 std::string ImagePattern::GetImageFitStr(ImageFit value)
1567 {
1568     switch (value) {
1569         case ImageFit::CONTAIN:
1570             return "CONTAIN";
1571         case ImageFit::COVER:
1572             return "COVER";
1573         case ImageFit::FILL:
1574             return "FILL";
1575         case ImageFit::FITWIDTH:
1576             return "FITWIDTH";
1577         case ImageFit::FITHEIGHT:
1578             return "FITHEIGHT";
1579         case ImageFit::NONE:
1580             return "NONE";
1581         case ImageFit::SCALE_DOWN:
1582             return "SCALE_DOWN";
1583         case ImageFit::TOP_LEFT:
1584             return "TOP_LEFT";
1585         default:
1586             return "COVER";
1587     }
1588 }
1589 
GetImageRepeatStr(ImageRepeat value)1590 std::string ImagePattern::GetImageRepeatStr(ImageRepeat value)
1591 {
1592     switch (value) {
1593         case ImageRepeat::NO_REPEAT:
1594             return "NO_REPEAT";
1595         case ImageRepeat::REPEAT:
1596             return "REPEAT_XY";
1597         case ImageRepeat::REPEAT_X:
1598             return "REPEAT_X";
1599         case ImageRepeat::REPEAT_Y:
1600             return "REPEAT_Y";
1601         default:
1602             return "NO_REPEAT";
1603     }
1604 }
1605 
GetImageColorFilterStr(const std::vector<float> & colorFilter)1606 std::string ImagePattern::GetImageColorFilterStr(const std::vector<float>& colorFilter)
1607 {
1608     if (colorFilter.empty()) {
1609         return "";
1610     }
1611     std::string result = "[" + std::to_string(colorFilter[0]);
1612     for (uint32_t idx = 1; idx < colorFilter.size(); ++idx) {
1613         result += ", " + std::to_string(colorFilter[idx]);
1614     }
1615     return result + "]";
1616 }
1617 
EnableAnalyzer(bool value)1618 void ImagePattern::EnableAnalyzer(bool value)
1619 {
1620     isEnableAnalyzer_ = value;
1621     if (!isEnableAnalyzer_) {
1622         DestroyAnalyzerOverlay();
1623         return;
1624     }
1625 
1626     if (!imageAnalyzerManager_) {
1627         imageAnalyzerManager_ = std::make_shared<ImageAnalyzerManager>(GetHost(), ImageAnalyzerHolder::IMAGE);
1628     }
1629     RegisterVisibleAreaChange(false);
1630 }
1631 
1632 // As an example
SetImageAnalyzerConfig(const ImageAnalyzerConfig & config)1633 void ImagePattern::SetImageAnalyzerConfig(const ImageAnalyzerConfig &config)
1634 {
1635     if (!isEnableAnalyzer_) {
1636         return;
1637     }
1638 }
1639 
SetImageAnalyzerConfig(void * config)1640 void ImagePattern::SetImageAnalyzerConfig(void* config)
1641 {
1642     if (isEnableAnalyzer_) {
1643         CHECK_NULL_VOID(imageAnalyzerManager_);
1644         imageAnalyzerManager_->SetImageAnalyzerConfig(config);
1645     }
1646 }
1647 
SetImageAIOptions(void * options)1648 void ImagePattern::SetImageAIOptions(void* options)
1649 {
1650     if (!imageAnalyzerManager_) {
1651         imageAnalyzerManager_ = std::make_shared<ImageAnalyzerManager>(GetHost(), ImageAnalyzerHolder::IMAGE);
1652     }
1653     CHECK_NULL_VOID(imageAnalyzerManager_);
1654     imageAnalyzerManager_->SetImageAIOptions(options);
1655 }
1656 
IsSupportImageAnalyzerFeature()1657 bool ImagePattern::IsSupportImageAnalyzerFeature()
1658 {
1659     CHECK_NULL_RETURN(imageAnalyzerManager_, false);
1660     return isEnableAnalyzer_ && image_ && !loadingCtx_->GetSourceInfo().IsSvg() && loadingCtx_->GetFrameCount() <= 1 &&
1661         imageAnalyzerManager_->IsSupportImageAnalyzerFeature();
1662 }
1663 
CreateAnalyzerOverlay()1664 void ImagePattern::CreateAnalyzerOverlay()
1665 {
1666     CHECK_NULL_VOID(imageAnalyzerManager_);
1667     if (imageAnalyzerManager_->IsOverlayCreated()) {
1668         return;
1669     }
1670 
1671     CHECK_NULL_VOID(image_);
1672     auto pixelMap = image_->GetPixelMap();
1673     CHECK_NULL_VOID(pixelMap);
1674     imageAnalyzerManager_->CreateAnalyzerOverlay(pixelMap);
1675 }
1676 
UpdateAnalyzerOverlay()1677 void ImagePattern::UpdateAnalyzerOverlay()
1678 {
1679     CHECK_NULL_VOID(imageAnalyzerManager_);
1680     if (!IsSupportImageAnalyzerFeature() || !imageAnalyzerManager_->IsOverlayCreated()) {
1681         return;
1682     }
1683 
1684     CHECK_NULL_VOID(image_);
1685     auto pixelMap = image_->GetPixelMap();
1686     CHECK_NULL_VOID(pixelMap);
1687     imageAnalyzerManager_->UpdateAnalyzerOverlay(pixelMap);
1688 }
1689 
UpdateAnalyzerOverlayLayout()1690 void ImagePattern::UpdateAnalyzerOverlayLayout()
1691 {
1692     CHECK_NULL_VOID(imageAnalyzerManager_);
1693     imageAnalyzerManager_->UpdateAnalyzerOverlayLayout();
1694 }
1695 
DestroyAnalyzerOverlay()1696 void ImagePattern::DestroyAnalyzerOverlay()
1697 {
1698     CHECK_NULL_VOID(imageAnalyzerManager_);
1699     imageAnalyzerManager_->DestroyAnalyzerOverlay();
1700 }
1701 
ReleaseImageAnalyzer()1702 void ImagePattern::ReleaseImageAnalyzer()
1703 {
1704     CHECK_NULL_VOID(imageAnalyzerManager_);
1705     imageAnalyzerManager_->ReleaseImageAnalyzer();
1706 }
1707 
UpdateAnalyzerUIConfig(const RefPtr<NG::GeometryNode> & geometryNode)1708 void ImagePattern::UpdateAnalyzerUIConfig(const RefPtr<NG::GeometryNode>& geometryNode)
1709 {
1710     CHECK_NULL_VOID(imageAnalyzerManager_);
1711     imageAnalyzerManager_->UpdateAnalyzerUIConfig(geometryNode);
1712 }
1713 
AllowVisibleAreaCheck() const1714 bool ImagePattern::AllowVisibleAreaCheck() const
1715 {
1716     auto frameNode = GetHost();
1717     CHECK_NULL_RETURN(frameNode, false);
1718     RefPtr<FrameNode> parentUi = frameNode->GetAncestorNodeOfFrame(true);
1719     while (parentUi) {
1720         auto layoutProperty = parentUi->GetLayoutProperty();
1721         if (layoutProperty && layoutProperty->IsOverlayNode()) {
1722             return true;
1723         }
1724         parentUi = parentUi->GetAncestorNodeOfFrame(true);
1725     }
1726     return false;
1727 }
1728 
InitDefaultValue()1729 void ImagePattern::InitDefaultValue()
1730 {
1731     // add API version protection
1732     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
1733         autoResizeDefault_ = false;
1734         interpolationDefault_ = ImageInterpolation::LOW;
1735     }
1736     auto container = Container::Current();
1737     // If the default value is set to false, the ScenceBoard memory increases.
1738     // Therefore the default value is different in the ScenceBoard.
1739     if (container && container->IsScenceBoardWindow()) {
1740         autoResizeDefault_ = true;
1741         interpolationDefault_ = ImageInterpolation::NONE;
1742     }
1743 }
1744 
hasSceneChanged()1745 bool ImagePattern::hasSceneChanged()
1746 {
1747     auto imageLayoutProperty = GetLayoutProperty<ImageLayoutProperty>();
1748     CHECK_NULL_RETURN(imageLayoutProperty, false);
1749     auto src = imageLayoutProperty->GetImageSourceInfo().value_or(ImageSourceInfo(""));
1750     UpdateInternalResource(src);
1751     if (loadingCtx_ && loadingCtx_->GetSourceInfo() == src && srcRect_ == dstRect_) {
1752         return false;
1753     }
1754     return true;
1755 }
1756 
ImageAnimatorPattern()1757 void ImagePattern::ImageAnimatorPattern()
1758 {
1759     animator_ = CREATE_ANIMATOR();
1760     animator_->SetFillMode(FillMode::BACKWARDS);
1761     animator_->SetDuration(DEFAULT_DURATION);
1762     ResetFormAnimationFlag();
1763 }
1764 
CreatePictureAnimation(int32_t size)1765 RefPtr<PictureAnimation<int32_t>> ImagePattern::CreatePictureAnimation(int32_t size)
1766 {
1767     auto pictureAnimation = MakeRefPtr<PictureAnimation<int32_t>>();
1768     if (durationTotal_ > 0) {
1769         for (int32_t index = 0; index < size; ++index) {
1770             pictureAnimation->AddPicture(images_[index].duration / static_cast<float>(durationTotal_), index);
1771         }
1772         animator_->SetDuration(durationTotal_);
1773     } else {
1774         for (int32_t index = 0; index < size; ++index) {
1775             pictureAnimation->AddPicture(NORMALIZED_DURATION_MAX / static_cast<float>(size), index);
1776         }
1777     }
1778 
1779     pictureAnimation->AddListener([weak = WeakClaim(this)](int32_t index) {
1780         auto imageAnimator = weak.Upgrade();
1781         CHECK_NULL_VOID(imageAnimator);
1782         imageAnimator->SetShowingIndex(index);
1783     });
1784     return pictureAnimation;
1785 }
1786 
SetShowingIndex(int32_t index)1787 void ImagePattern::SetShowingIndex(int32_t index)
1788 {
1789     auto host = GetHost();
1790     CHECK_NULL_VOID(host);
1791     auto imageFrameNode = AceType::DynamicCast<FrameNode>(host->GetChildren().front());
1792     CHECK_NULL_VOID(imageFrameNode);
1793     auto imageLayoutProperty = imageFrameNode->GetLayoutProperty<ImageLayoutProperty>();
1794     CHECK_NULL_VOID(imageLayoutProperty);
1795     if (index >= static_cast<int32_t>(images_.size())) {
1796         TAG_LOGW(AceLogTag::ACE_IMAGE, "ImageAnimator update index error, index: %{public}d, size: %{public}zu",
1797             index, images_.size());
1798         return;
1799     }
1800     CHECK_NULL_VOID(images_[index].pixelMap);
1801     nowImageIndex_ = index;
1802     auto cacheImageIter = FindCacheImageNode(images_[index].pixelMap);
1803     if (IsShowingSrc(imageFrameNode, images_[index].pixelMap)) {
1804         ACE_SCOPED_TRACE("ImageAnimator same src %s, index %d", "PixelMap", index);
1805         UpdateShowingImageInfo(imageFrameNode, index);
1806     } else if (cacheImageIter == cacheImages_.end()) {
1807         ACE_SCOPED_TRACE("ImageAnimator no cache found, src %s, index %d", "PixelMap", index);
1808         UpdateShowingImageInfo(imageFrameNode, index);
1809     } else if (cacheImageIter->isLoaded) {
1810         ACE_SCOPED_TRACE("ImageAnimator useCache src %s, index %d", "PixelMap", index);
1811         auto cacheImageNode = cacheImageIter->imageNode;
1812         host->RemoveChild(imageFrameNode);
1813         host->AddChild(cacheImageNode, DEFAULT_NODE_SLOT, true);
1814         host->RebuildRenderContextTree();
1815         cacheImages_.erase(cacheImageIter);
1816         CacheImageStruct newCacheImageStruct(imageFrameNode);
1817         newCacheImageStruct.isLoaded = true;
1818         cacheImages_.emplace_back(newCacheImageStruct);
1819         UpdateShowingImageInfo(cacheImageNode, index);
1820     } else {
1821         UpdateShowingImageInfo(imageFrameNode, index);
1822         // wait for cache image loading
1823         ACE_SCOPED_TRACE("ImageAnimator waitForCache src %s, index %d", "PixelMap", index);
1824     }
1825     // update cache images
1826     CHECK_NULL_VOID(cacheImages_.size());
1827     int32_t nextIndex = GetNextIndex(index);
1828     for (auto& cacheImage : cacheImages_) {
1829         UpdateCacheImageInfo(cacheImage, nextIndex);
1830         nextIndex = GetNextIndex(nextIndex);
1831     }
1832     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1833 }
1834 
UpdateShowingImageInfo(const RefPtr<FrameNode> & imageFrameNode,int32_t index)1835 void ImagePattern::UpdateShowingImageInfo(const RefPtr<FrameNode>& imageFrameNode, int32_t index)
1836 {
1837     auto host = GetHost();
1838     CHECK_NULL_VOID(host);
1839     auto layoutProperty = host->GetLayoutProperty<ImageLayoutProperty>();
1840     CHECK_NULL_VOID(layoutProperty);
1841     auto imageLayoutProperty = imageFrameNode->GetLayoutProperty<ImageLayoutProperty>();
1842     CHECK_NULL_VOID(imageLayoutProperty);
1843 
1844     imageLayoutProperty->UpdateImageSourceInfo(ImageSourceInfo(images_[index].pixelMap));
1845     SetColorFilter(imageFrameNode);
1846     SetImageFit(imageFrameNode);
1847     //use the size of first pixelmap when no size is set
1848     auto &&layoutConstraint = layoutProperty->GetCalcLayoutConstraint();
1849     if (!layoutConstraint || !layoutConstraint->selfIdealSize.has_value()) {
1850         CalcSize realSize = {
1851             CalcLength(images_[0].pixelMap->GetWidth()), CalcLength(images_[0].pixelMap->GetHeight()) };
1852         imageLayoutProperty->UpdateUserDefinedIdealSize(realSize);
1853         imageLayoutProperty->UpdateMeasureType(MeasureType::MATCH_CONTENT);
1854         imageFrameNode->MarkModifyDone();
1855         imageFrameNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1856         return;
1857     }
1858     MarginProperty margin;
1859     margin.SetEdges(CalcLength(0.0));
1860     imageLayoutProperty->UpdateMargin(margin);
1861     imageLayoutProperty->ClearUserDefinedIdealSize(true, true);
1862     imageLayoutProperty->UpdateMeasureType(MeasureType::MATCH_PARENT);
1863     imageFrameNode->MarkModifyDone();
1864     imageFrameNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1865 }
1866 
UpdateCacheImageInfo(CacheImageStruct & cacheImage,int32_t index)1867 void ImagePattern::UpdateCacheImageInfo(CacheImageStruct& cacheImage, int32_t index)
1868 {
1869     if (index >= static_cast<int32_t>(images_.size())) {
1870         TAG_LOGW(AceLogTag::ACE_IMAGE, "PrepareImageInfo index error, index: %{public}d, size: %{public}zu",
1871             index, images_.size());
1872         return;
1873     }
1874     auto host = GetHost();
1875     CHECK_NULL_VOID(host);
1876     auto layoutProperty = host->GetLayoutProperty<ImageLayoutProperty>();
1877     CHECK_NULL_VOID(layoutProperty);
1878     auto imageLayoutProperty = cacheImage.imageNode->GetLayoutProperty<ImageLayoutProperty>();
1879     CHECK_NULL_VOID(imageLayoutProperty);
1880     CHECK_NULL_VOID(images_[index].pixelMap);
1881     // pixelmap
1882     if (imageLayoutProperty->HasImageSourceInfo()) {
1883         auto preSrc = imageLayoutProperty->GetImageSourceInfoValue().GetPixmap();
1884         if (preSrc != images_[index].pixelMap) {
1885             // need to cache newImage
1886             imageLayoutProperty->UpdateImageSourceInfo(ImageSourceInfo(images_[index].pixelMap));
1887             cacheImage.index = index;
1888             cacheImage.isLoaded = false;
1889         }
1890     }
1891     SetColorFilter(cacheImage.imageNode);
1892     SetImageFit(cacheImage.imageNode);
1893     //use the size of first pixelmap when no size is set
1894     auto &&layoutConstraint = layoutProperty->GetCalcLayoutConstraint();
1895     if (!layoutConstraint || !layoutConstraint->selfIdealSize.has_value()) {
1896         CalcSize realSize = {
1897             CalcLength(images_[0].pixelMap->GetWidth()), CalcLength(images_[0].pixelMap->GetHeight()) };
1898         imageLayoutProperty->UpdateUserDefinedIdealSize(realSize);
1899         cacheImage.imageNode->MarkModifyDone();
1900         return;
1901     }
1902     auto hostSize = host->GetGeometryNode()->GetPaddingSize();
1903     if (!hostSize.IsPositive()) {
1904         // if imageNode size is nonPositive, no pixelMap will be generated. Wait for size.
1905         return;
1906     }
1907     imageLayoutProperty->UpdateUserDefinedIdealSize(
1908         CalcSize(CalcLength(hostSize.Width()), CalcLength(hostSize.Height())));
1909     cacheImage.imageNode->MarkModifyDone();
1910 }
1911 
FindCacheImageNode(const RefPtr<PixelMap> & src)1912 std::list<ImagePattern::CacheImageStruct>::iterator ImagePattern::FindCacheImageNode(const RefPtr<PixelMap>& src)
1913 {
1914     for (auto iter = cacheImages_.begin(); iter != cacheImages_.end(); ++iter) {
1915         if (IsShowingSrc(iter->imageNode, src)) {
1916             return iter;
1917         }
1918     }
1919     return cacheImages_.end();
1920 }
1921 
GenerateCachedImages()1922 void ImagePattern::GenerateCachedImages()
1923 {
1924     CHECK_NULL_VOID(images_.size());
1925     auto averageShowTime = static_cast<uint32_t>(animator_->GetDuration()) / images_.size();
1926     size_t cacheImageNum = averageShowTime >= CRITICAL_TIME ? 1 : 2;
1927     cacheImageNum = std::min(images_.size() - 1, cacheImageNum);
1928     if (cacheImages_.size() > cacheImageNum) {
1929         cacheImages_.resize(cacheImageNum);
1930         return;
1931     }
1932     while (cacheImages_.size() < cacheImageNum) {
1933         auto imageNode = FrameNode::CreateFrameNode(V2::IMAGE_ETS_TAG, -1, AceType::MakeRefPtr<ImagePattern>());
1934         auto imageLayoutProperty = imageNode->GetLayoutProperty();
1935         imageLayoutProperty->UpdateMeasureType(MeasureType::MATCH_PARENT);
1936         imageLayoutProperty->UpdateAlignment(Alignment::TOP_LEFT);
1937         AddImageLoadSuccessEvent(imageNode);
1938         cacheImages_.emplace_back(CacheImageStruct(imageNode));
1939     }
1940 }
1941 
AdaptSelfSize()1942 void ImagePattern::AdaptSelfSize()
1943 {
1944     auto host = GetHost();
1945     CHECK_NULL_VOID(host);
1946     const auto& layoutProperty = host->GetLayoutProperty();
1947     CHECK_NULL_VOID(layoutProperty);
1948     if (layoutProperty->GetCalcLayoutConstraint() && layoutProperty->GetCalcLayoutConstraint()->selfIdealSize &&
1949         layoutProperty->GetCalcLayoutConstraint()->selfIdealSize->IsValid()) {
1950         return;
1951     }
1952     if (images_.empty()) {
1953         return;
1954     }
1955     CHECK_NULL_VOID(images_[0].pixelMap);
1956     hasSizeChanged = true;
1957     CalcSize realSize = {
1958         CalcLength(images_[0].pixelMap->GetWidth()), CalcLength(images_[0].pixelMap->GetHeight()) };
1959 
1960     const auto& layoutConstraint = layoutProperty->GetCalcLayoutConstraint();
1961     if (!layoutConstraint || !layoutConstraint->selfIdealSize) {
1962         layoutProperty->UpdateUserDefinedIdealSize(realSize);
1963         return;
1964     }
1965     if (!layoutConstraint->selfIdealSize->Width()) {
1966         layoutProperty->UpdateUserDefinedIdealSize(CalcSize(CalcLength(images_[0].pixelMap->GetWidth()), std::nullopt));
1967         return;
1968     }
1969     layoutProperty->UpdateUserDefinedIdealSize(CalcSize(std::nullopt, CalcLength(images_[0].pixelMap->GetHeight())));
1970 }
1971 
GetNextIndex(int32_t preIndex)1972 int32_t ImagePattern::GetNextIndex(int32_t preIndex)
1973 {
1974     return (preIndex + 1) % static_cast<int32_t>(images_.size());
1975 }
1976 
AddImageLoadSuccessEvent(const RefPtr<FrameNode> & imageFrameNode)1977 void ImagePattern::AddImageLoadSuccessEvent(const RefPtr<FrameNode>& imageFrameNode)
1978 {
1979     CHECK_NULL_VOID(imageFrameNode);
1980     auto eventHub = imageFrameNode->GetEventHub<ImageEventHub>();
1981     eventHub->SetOnComplete(
1982         [weakImage = WeakPtr<FrameNode>(imageFrameNode), weak = WeakClaim(this)](const LoadImageSuccessEvent& info) {
1983             if (info.GetLoadingStatus() != 1) {
1984                 // status 1 means load success. Only need loadSuccess event.
1985                 return;
1986             }
1987             auto pattern = weak.Upgrade();
1988             CHECK_NULL_VOID(pattern);
1989             auto cacheImageNode = weakImage.Upgrade();
1990             CHECK_NULL_VOID(cacheImageNode);
1991             auto imageAnimator = pattern->GetHost();
1992             CHECK_NULL_VOID(imageAnimator);
1993             auto cacheLayoutProperty = cacheImageNode->GetLayoutProperty<ImageLayoutProperty>();
1994             auto cacheSrc = cacheLayoutProperty->GetImageSourceInfoValue(ImageSourceInfo()).GetSrc();
1995             ACE_SCOPED_TRACE("ImageAnimator cache succeed. src %s", cacheSrc.c_str());
1996             auto iter = std::find_if(pattern->cacheImages_.begin(), pattern->cacheImages_.end(),
1997                 [&cacheImageNode](const CacheImageStruct& other) { return other.imageNode == cacheImageNode; });
1998             if (iter == pattern->cacheImages_.end()) {
1999                 return;
2000             }
2001             iter->isLoaded = true;
2002             if (pattern->nowImageIndex_ >= static_cast<int32_t>(pattern->images_.size())) {
2003                 TAG_LOGW(AceLogTag::ACE_IMAGE, "ImageAnimator showImage index is invalid");
2004                 return;
2005             }
2006             if (pattern->nowImageIndex_ == iter->index &&
2007                 IsShowingSrc(cacheImageNode, pattern->images_[pattern->nowImageIndex_].pixelMap)) {
2008                 pattern->SetShowingIndex(pattern->nowImageIndex_);
2009             }
2010         });
2011 }
2012 
IsShowingSrc(const RefPtr<FrameNode> & imageFrameNode,const RefPtr<PixelMap> & src)2013 bool ImagePattern::IsShowingSrc(const RefPtr<FrameNode>& imageFrameNode, const RefPtr<PixelMap>& src)
2014 {
2015     auto imageLayoutProperty = imageFrameNode->GetLayoutProperty<ImageLayoutProperty>();
2016     return imageLayoutProperty->HasImageSourceInfo()
2017         && imageLayoutProperty->GetImageSourceInfoValue().GetPixmap() == src;
2018 }
2019 
IsFormRender()2020 bool ImagePattern::IsFormRender()
2021 {
2022     auto pipeline = PipelineBase::GetCurrentContext();
2023     CHECK_NULL_RETURN(pipeline, false);
2024     return pipeline->IsFormRender();
2025 }
2026 
UpdateFormDurationByRemainder()2027 void ImagePattern::UpdateFormDurationByRemainder()
2028 {
2029     if (IsFormRender()) {
2030         if (!isFormAnimationStart_) {
2031             formAnimationRemainder_ =
2032                 DEFAULT_DURATION - (GetMicroTickCount() - formAnimationStartTime_) / MICROSEC_TO_MILLISEC;
2033         }
2034         if ((formAnimationRemainder_ > 0) && (animator_->GetDuration() > formAnimationRemainder_)) {
2035             animator_->SetDuration(formAnimationRemainder_);
2036         }
2037         if (formAnimationRemainder_ <= 0) {
2038             isFormAnimationEnd_ = true;
2039         }
2040     }
2041 }
2042 
ResetFormAnimationStartTime()2043 void ImagePattern::ResetFormAnimationStartTime()
2044 {
2045     if (isFormAnimationStart_) {
2046         isFormAnimationStart_ = false;
2047         formAnimationStartTime_ = GetMicroTickCount();
2048     }
2049 }
2050 
ResetFormAnimationFlag()2051 void ImagePattern::ResetFormAnimationFlag()
2052 {
2053     if (IsFormRender()) {
2054         formAnimationRemainder_ = DEFAULT_DURATION;
2055         isFormAnimationStart_ = true;
2056         isFormAnimationEnd_ = false;
2057     }
2058 }
2059 
SetIteration(int32_t iteration)2060 void ImagePattern::SetIteration(int32_t iteration)
2061 {
2062     if (iteration < -1) {
2063         return;
2064     }
2065     if (IsFormRender()) {
2066         iteration = DEFAULT_ITERATIONS;
2067     }
2068     animator_->SetIteration(iteration);
2069 }
2070 
SetDuration(int32_t duration)2071 void ImagePattern::SetDuration(int32_t duration)
2072 {
2073     if (duration < 0) {
2074         return;
2075     }
2076     int32_t finalDuration = durationTotal_ > 0 ? durationTotal_ : duration;
2077     if (IsFormRender()) {
2078         finalDuration = finalDuration < DEFAULT_DURATION ? finalDuration : DEFAULT_DURATION;
2079     }
2080     if (animator_->GetDuration() == finalDuration) {
2081         animator_->RemoveRepeatListener(repeatCallbackId_);
2082         return;
2083     }
2084     if (animator_->GetStatus() == Animator::Status::IDLE || animator_->GetStatus() == Animator::Status::STOPPED) {
2085         animator_->SetDuration(finalDuration);
2086         animator_->RemoveRepeatListener(repeatCallbackId_);
2087         return;
2088     }
2089     // if animator is running or paused, duration will work next time
2090     animator_->RemoveRepeatListener(repeatCallbackId_);
2091     repeatCallbackId_ = animator_->AddRepeatListener([weak = WeakClaim(this), finalDuration]() {
2092         auto imageAnimator = weak.Upgrade();
2093         CHECK_NULL_VOID(imageAnimator);
2094         imageAnimator->animator_->SetDuration(finalDuration);
2095     });
2096 }
2097 
SetOnProgressCallback(std::function<void (const uint32_t & dlNow,const uint32_t & dlTotal)> && onProgress)2098 void ImagePattern::SetOnProgressCallback(
2099     std::function<void(const uint32_t& dlNow, const uint32_t& dlTotal)>&& onProgress)
2100 {
2101     onProgressCallback_ = onProgress;
2102 }
2103 
OnSensitiveStyleChange(bool isSensitive)2104 void ImagePattern::OnSensitiveStyleChange(bool isSensitive)
2105 {
2106     auto host = GetHost();
2107     CHECK_NULL_VOID(host);
2108     auto privacySensitive = host->IsPrivacySensitive();
2109     if (isSensitive && privacySensitive) {
2110         isSensitive_ = true;
2111         auto renderContext = host->GetRenderContext();
2112         CHECK_NULL_VOID(renderContext);
2113         CalcDimension radius;
2114         radius.SetValue(IMAGE_SENSITIVE_RADIUS);
2115         Color color = Color::FromARGB(13, 255, 255, 255);
2116         EffectOption option = { radius, IMAGE_SENSITIVE_SATURATION, IMAGE_SENSITIVE_BRIGHTNESS, color };
2117         if (renderContext->GetBackBlurRadius().has_value()) {
2118             renderContext->UpdateBackBlurRadius(Dimension());
2119         }
2120         if (renderContext->GetBackBlurStyle().has_value()) {
2121             renderContext->UpdateBackBlurStyle(std::nullopt);
2122         }
2123         renderContext->UpdateBackgroundEffect(option);
2124     } else {
2125         isSensitive_ = false;
2126     }
2127     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
2128 }
2129 
ResetImageProperties()2130 void ImagePattern::ResetImageProperties()
2131 {
2132     SetCopyOption(CopyOptions::None);
2133     OnImageModifyDone();
2134 }
2135 
ResetImage()2136 void ImagePattern::ResetImage()
2137 {
2138     image_ = nullptr;
2139     imageQuality_ = AIImageQuality::NONE;
2140     isImageQualityChange_ = false;
2141     loadingCtx_.Reset();
2142     auto host = GetHost();
2143     CHECK_NULL_VOID(host);
2144     if (!altImage_) {
2145         auto rsRenderContext = host->GetRenderContext();
2146         CHECK_NULL_VOID(rsRenderContext);
2147         rsRenderContext->ClearDrawCommands();
2148     }
2149 }
2150 
ResetAltImage()2151 void ImagePattern::ResetAltImage()
2152 {
2153     altImage_ = nullptr;
2154     altLoadingCtx_.Reset();
2155     if (!image_) {
2156         auto host = GetHost();
2157         CHECK_NULL_VOID(host);
2158         auto rsRenderContext = host->GetRenderContext();
2159         CHECK_NULL_VOID(rsRenderContext);
2160         rsRenderContext->ClearDrawCommands();
2161     }
2162 }
2163 
ResetImageAndAlt()2164 void ImagePattern::ResetImageAndAlt()
2165 {
2166     image_ = nullptr;
2167     loadingCtx_ = nullptr;
2168     srcRect_.Reset();
2169     dstRect_.Reset();
2170     altLoadingCtx_ = nullptr;
2171     altImage_ = nullptr;
2172     altDstRect_.reset();
2173     altSrcRect_.reset();
2174     auto frameNode = GetHost();
2175     CHECK_NULL_VOID(frameNode);
2176     auto rsRenderContext = frameNode->GetRenderContext();
2177     CHECK_NULL_VOID(rsRenderContext);
2178     rsRenderContext->ClearDrawCommands();
2179     CloseSelectOverlay();
2180     DestroyAnalyzerOverlay();
2181     frameNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2182 }
2183 
ResetPictureSize()2184 void ImagePattern::ResetPictureSize()
2185 {
2186     auto host = GetHost();
2187     CHECK_NULL_VOID(host);
2188     const auto& layoutProperty = host->GetLayoutProperty();
2189     CHECK_NULL_VOID(layoutProperty);
2190     layoutProperty->ClearUserDefinedIdealSize(true, true);
2191     hasSizeChanged = false;
2192 }
2193 
SetColorFilter(const RefPtr<FrameNode> & imageFrameNode)2194 void ImagePattern::SetColorFilter(const RefPtr<FrameNode>& imageFrameNode)
2195 {
2196     auto host = GetHost();
2197     CHECK_NULL_VOID(host);
2198     auto renderProperty = host->GetPaintProperty<ImageRenderProperty>();
2199     CHECK_NULL_VOID(renderProperty);
2200     auto imageRenderProperty = imageFrameNode->GetPaintProperty<ImageRenderProperty>();
2201     CHECK_NULL_VOID(imageRenderProperty);
2202     if (renderProperty->HasColorFilter()) {
2203         imageRenderProperty->UpdateColorFilter(renderProperty->GetColorFilter().value());
2204     }
2205     if (renderProperty->HasDrawingColorFilter()) {
2206         imageRenderProperty->UpdateDrawingColorFilter(renderProperty->GetDrawingColorFilter().value());
2207     }
2208 }
2209 
SetImageFit(const RefPtr<FrameNode> & imageFrameNode)2210 void ImagePattern::SetImageFit(const RefPtr<FrameNode>& imageFrameNode)
2211 {
2212     auto host = GetHost();
2213     CHECK_NULL_VOID(host);
2214     auto layoutProperty = host->GetLayoutProperty<ImageLayoutProperty>();
2215     CHECK_NULL_VOID(layoutProperty);
2216     auto renderProperty = host->GetPaintProperty<ImageRenderProperty>();
2217     CHECK_NULL_VOID(renderProperty);
2218     auto imageLayoutProperty = imageFrameNode->GetLayoutProperty<ImageLayoutProperty>();
2219     CHECK_NULL_VOID(imageLayoutProperty);
2220     auto imageRenderProperty = imageFrameNode->GetPaintProperty<ImageRenderProperty>();
2221     CHECK_NULL_VOID(imageRenderProperty);
2222     if (renderProperty->HasImageFit()) {
2223         imageRenderProperty->UpdateImageFit(renderProperty->GetImageFit().value());
2224     }
2225     if (layoutProperty->HasImageFit()) {
2226         imageLayoutProperty->UpdateImageFit(layoutProperty->GetImageFit().value());
2227     }
2228 }
2229 
SetObscured()2230 void ImagePattern::SetObscured()
2231 {
2232     auto host = GetHost();
2233     CHECK_NULL_VOID(host);
2234     auto imageFrameNode = AceType::DynamicCast<FrameNode>(host->GetChildren().front());
2235     CHECK_NULL_VOID(imageFrameNode);
2236     auto obscuredReasons = host->GetRenderContext()->GetObscured().value_or(std::vector<ObscuredReasons>());
2237     const auto& castRenderContext = imageFrameNode->GetRenderContext();
2238     if (castRenderContext) {
2239         castRenderContext->UpdateObscured(obscuredReasons);
2240     }
2241     imageFrameNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2242     host->GetRenderContext()->ResetObscured();
2243     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2244 }
2245 
TriggerVisibleAreaChangeForChild(const RefPtr<UINode> & node,bool visible,double ratio)2246 void ImagePattern::TriggerVisibleAreaChangeForChild(const RefPtr<UINode>& node, bool visible, double ratio)
2247 {
2248     for (const auto& childNode : node->GetChildren()) {
2249         if (AceType::InstanceOf<FrameNode>(childNode)) {
2250             auto frame = AceType::DynamicCast<FrameNode>(childNode);
2251             if (!frame || !frame->GetEventHub<EventHub>()) {
2252                 continue;
2253             }
2254             auto callback = frame->GetEventHub<EventHub>()->GetVisibleAreaCallback(true).callback;
2255             if (callback) {
2256                 callback(visible, ratio);
2257             }
2258         }
2259         TriggerVisibleAreaChangeForChild(childNode, visible, ratio);
2260     }
2261 }
2262 } // namespace OHOS::Ace::NG
2263