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();
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 }
1336 
UpdateFillColorIfForegroundColor()1337 void ImagePattern::UpdateFillColorIfForegroundColor()
1338 {
1339     auto frameNode = GetHost();
1340     CHECK_NULL_VOID(frameNode);
1341     auto renderContext = frameNode->GetRenderContext();
1342     CHECK_NULL_VOID(renderContext);
1343     if (renderContext->HasForegroundColor() || renderContext->HasForegroundColorStrategy()) {
1344         auto imageLayoutProperty = frameNode->GetLayoutProperty<ImageLayoutProperty>();
1345         auto imageSourceInfo = imageLayoutProperty->GetImageSourceInfo().value();
1346         if (imageSourceInfo.IsSvg()) {
1347             imageSourceInfo.SetFillColor(Color::FOREGROUND);
1348             imageLayoutProperty->UpdateImageSourceInfo(imageSourceInfo);
1349         }
1350         auto imageRenderProperty = frameNode->GetPaintProperty<ImageRenderProperty>();
1351         CHECK_NULL_VOID(imageRenderProperty);
1352         imageRenderProperty->UpdateSvgFillColor(Color::FOREGROUND);
1353     }
1354 }
1355 
DumpLayoutInfo()1356 void ImagePattern::DumpLayoutInfo()
1357 {
1358     auto layoutProp = GetLayoutProperty<ImageLayoutProperty>();
1359     CHECK_NULL_VOID(layoutProp);
1360     auto src = layoutProp->GetImageSourceInfo().value_or(ImageSourceInfo(""));
1361     DumpLog::GetInstance().AddDesc(std::string("url: ").append(src.ToString()));
1362 
1363     auto altSrc = layoutProp->GetAlt().value_or(ImageSourceInfo(""));
1364     DumpLog::GetInstance().AddDesc(std::string("altUrl: ").append(altSrc.ToString()));
1365 
1366     auto imageFit = layoutProp->GetImageFit().value_or(ImageFit::COVER);
1367     DumpLog::GetInstance().AddDesc(std::string("objectFit: ").append(GetImageFitStr(imageFit)));
1368 
1369     auto fitOriginalSize = layoutProp->GetFitOriginalSize().value_or(false);
1370     DumpLog::GetInstance().AddDesc(std::string("fitOriginalSize: ").append(fitOriginalSize ? "true" : "false"));
1371 
1372     const std::optional<SizeF>& sourceSize = layoutProp->GetSourceSize();
1373     if (sourceSize.has_value()) {
1374         DumpLog::GetInstance().AddDesc(std::string("sourceSize: ").append(sourceSize.value().ToString()));
1375     }
1376 
1377     bool autoResize = layoutProp->GetAutoResize().value_or(autoResizeDefault_);
1378     autoResize ? DumpLog::GetInstance().AddDesc("autoResize:true")
1379                        : DumpLog::GetInstance().AddDesc("autoResize:false");
1380 }
1381 
DumpRenderInfo()1382 void ImagePattern::DumpRenderInfo()
1383 {
1384     auto renderProp = GetPaintProperty<ImageRenderProperty>();
1385     CHECK_NULL_VOID(renderProp);
1386 
1387     auto imageRenderMode = renderProp->GetImageRenderMode().value_or(ImageRenderMode::ORIGINAL);
1388     DumpLog::GetInstance().AddDesc(
1389         std::string("renderMode: ").append((imageRenderMode == ImageRenderMode::ORIGINAL) ? "Original" : "Template"));
1390 
1391     auto imageRepeat = renderProp->GetImageRepeat().value_or(ImageRepeat::NO_REPEAT);
1392     DumpLog::GetInstance().AddDesc(std::string("objectRepeat: ").append(GetImageRepeatStr(imageRepeat)));
1393 
1394     auto imageColorFilter = renderProp->GetColorFilter();
1395     if (imageColorFilter.has_value()) {
1396         auto colorFilter = imageColorFilter.value();
1397         DumpLog::GetInstance().AddDesc(std::string("colorFilter: ").append(GetImageColorFilterStr(colorFilter)));
1398     }
1399 
1400     auto fillColor = renderProp->GetSvgFillColor();
1401     if (fillColor.has_value()) {
1402         auto color = fillColor.value();
1403         DumpLog::GetInstance().AddDesc(std::string("fillColor: ").append(color.ColorToString()));
1404     }
1405 
1406     DynamicRangeMode dynamicMode = DynamicRangeMode::STANDARD;
1407     if (renderProp->HasDynamicMode()) {
1408         dynamicMode = renderProp->GetDynamicMode().value_or(DynamicRangeMode::STANDARD);
1409         DumpLog::GetInstance().AddDesc(std::string("dynamicRangeMode: ").append(GetDynamicModeString(dynamicMode)));
1410     }
1411 
1412     auto matchTextDirection = renderProp->GetMatchTextDirection().value_or(false);
1413     matchTextDirection ? DumpLog::GetInstance().AddDesc("matchTextDirection:true")
1414                        : DumpLog::GetInstance().AddDesc("matchTextDirection:false");
1415 
1416     auto smoothEdge = renderProp->GetSmoothEdge();
1417     if (smoothEdge.has_value()) {
1418         DumpLog::GetInstance().AddDesc(std::string("edgeAntialiasing: ").append(std::to_string(smoothEdge.value())));
1419     }
1420 
1421     auto needBorderRadius = renderProp->GetNeedBorderRadius().value_or(false);
1422     needBorderRadius ? DumpLog::GetInstance().AddDesc("needBorderRadius:true")
1423                      : DumpLog::GetInstance().AddDesc("needBorderRadius:false");
1424 
1425     auto borderRadius = renderProp->GetBorderRadius().value_or(BorderRadiusProperty());
1426     DumpLog::GetInstance().AddDesc(borderRadius.ToString());
1427 
1428     if (renderProp && renderProp->HasImageResizableSlice() && renderProp->GetImageResizableSliceValue({}).Valid()) {
1429         DumpLog::GetInstance().AddDesc(
1430             std::string("resizable slice: ").append(renderProp->GetImageResizableSliceValue({}).ToString()));
1431     }
1432 }
1433 
DumpSvgInfo()1434 void ImagePattern::DumpSvgInfo()
1435 {
1436     auto imageLayoutProperty = GetLayoutProperty<ImageLayoutProperty>();
1437     CHECK_NULL_VOID(imageLayoutProperty);
1438     auto imageSourceInfo = imageLayoutProperty->GetImageSourceInfo();
1439     CHECK_NULL_VOID(imageSourceInfo);
1440     if (!imageSourceInfo->IsSvg()|| !loadingCtx_) {
1441         return;
1442     }
1443     auto imageObject = loadingCtx_->GetImageObject();
1444     CHECK_NULL_VOID(imageObject);
1445     DumpLog::GetInstance().AddDesc(
1446         std::string("Svg:").append(imageObject->GetDumpInfo()));
1447 }
1448 
DumpInfo()1449 void ImagePattern::DumpInfo()
1450 {
1451     DumpLayoutInfo();
1452     DumpRenderInfo();
1453 
1454     syncLoad_ ? DumpLog::GetInstance().AddDesc("syncLoad:true") : DumpLog::GetInstance().AddDesc("syncLoad:false");
1455 
1456     DumpLog::GetInstance().AddDesc("imageInterpolation:" + GetImageInterpolation(interpolation_));
1457     if (loadingCtx_) {
1458         auto currentLoadImageState = loadingCtx_->GetCurrentLoadingState();
1459         DumpLog::GetInstance().AddDesc(std::string("currentLoadImageState : ").append(currentLoadImageState));
1460         DumpLog::GetInstance().AddDesc(
1461             std::string("rawImageSize: ").append(loadingCtx_->GetOriginImageSize().ToString()));
1462         DumpLog::GetInstance().AddDesc(std::string("LoadErrorMsg: ").append(loadingCtx_->GetErrorMsg()));
1463     } else {
1464         DumpLog::GetInstance().AddDesc(std::string("imageLoadingContext: null"));
1465     }
1466 
1467     auto host = GetHost();
1468 if (host) {
1469         auto enDrage = host->IsDraggable();
1470         enDrage ? DumpLog::GetInstance().AddDesc("draggable:true") : DumpLog::GetInstance().AddDesc("draggable:false");
1471     }
1472     DumpLog::GetInstance().AddDesc(
1473         std::string("userOrientation: ").append(ConvertOrientationToString(userOrientation_)));
1474     DumpLog::GetInstance().AddDesc(
1475         std::string("selfOrientation: ").append(ConvertOrientationToString(selfOrientation_)));
1476     DumpLog::GetInstance().AddDesc(std::string("enableAnalyzer: ").append(isEnableAnalyzer_ ? "true" : "false"));
1477     DumpSvgInfo();
1478 }
1479 
DumpAdvanceInfo()1480 void ImagePattern::DumpAdvanceInfo()
1481 {
1482     auto layoutProp = GetLayoutProperty<ImageLayoutProperty>();
1483     CHECK_NULL_VOID(layoutProp);
1484     auto src = layoutProp->GetImageSourceInfo().value_or(ImageSourceInfo(""));
1485     DumpLog::GetInstance().AddDesc(std::string("url: ").append(layoutProp->GetImageSourceInfo()->ToString()));
1486     syncLoad_ ? DumpLog::GetInstance().AddDesc("syncLoad:true") : DumpLog::GetInstance().AddDesc("syncLoad:false");
1487     if (loadingCtx_) {
1488         auto currentLoadImageState = loadingCtx_->GetCurrentLoadingState();
1489         DumpLog::GetInstance().AddDesc(std::string("currentLoadImageState : ").append(currentLoadImageState));
1490     }
1491 }
1492 
UpdateDragEvent(const RefPtr<OHOS::Ace::DragEvent> & event)1493 void ImagePattern::UpdateDragEvent(const RefPtr<OHOS::Ace::DragEvent>& event)
1494 {
1495     RefPtr<UnifiedData> unifiedData = UdmfClient::GetInstance()->CreateUnifiedData();
1496     if (loadingCtx_ && image_ && loadingCtx_->GetSourceInfo().IsPixmap()) {
1497         auto pixelMap = image_->GetPixelMap();
1498         CHECK_NULL_VOID(pixelMap);
1499         std::vector<uint8_t> data;
1500         if (!pixelMap->GetPixelsVec(data)) {
1501             return;
1502         }
1503         PixelMapRecordDetails details = { pixelMap->GetWidth(), pixelMap->GetHeight(), pixelMap->GetPixelFormat(),
1504             pixelMap->GetAlphaType() };
1505         UdmfClient::GetInstance()->AddPixelMapRecord(unifiedData, data, details);
1506     } else if (loadingCtx_) {
1507         UdmfClient::GetInstance()->AddImageRecord(unifiedData, loadingCtx_->GetSourceInfo().GetSrc());
1508     }
1509     event->SetData(unifiedData);
1510 }
1511 
OnLanguageConfigurationUpdate()1512 void ImagePattern::OnLanguageConfigurationUpdate()
1513 {
1514     CHECK_NULL_VOID(loadingCtx_);
1515     auto&& src = loadingCtx_->GetSourceInfo();
1516     // Resource image needs to reload when Language changes
1517     if (src.GetSrcType() == SrcType::RESOURCE) {
1518         loadingCtx_.Reset();
1519     }
1520     OnConfigurationUpdate();
1521 }
1522 
OnColorConfigurationUpdate()1523 void ImagePattern::OnColorConfigurationUpdate()
1524 {
1525     OnConfigurationUpdate();
1526 }
1527 
OnDirectionConfigurationUpdate()1528 void ImagePattern::OnDirectionConfigurationUpdate()
1529 {
1530     OnConfigurationUpdate();
1531 }
1532 
OnIconConfigurationUpdate()1533 void ImagePattern::OnIconConfigurationUpdate()
1534 {
1535     OnConfigurationUpdate();
1536 }
1537 
OnConfigurationUpdate()1538 void ImagePattern::OnConfigurationUpdate()
1539 {
1540     CHECK_NULL_VOID(loadingCtx_);
1541     auto imageLayoutProperty = GetLayoutProperty<ImageLayoutProperty>();
1542     CHECK_NULL_VOID(imageLayoutProperty);
1543     auto src = imageLayoutProperty->GetImageSourceInfo().value_or(ImageSourceInfo(""));
1544     UpdateInternalResource(src);
1545 
1546     LoadImage(src, imageLayoutProperty->GetPropertyChangeFlag(),
1547         imageLayoutProperty->GetVisibility().value_or(VisibleType::VISIBLE));
1548     if (loadingCtx_->NeedAlt() && imageLayoutProperty->GetAlt()) {
1549         auto altImageSourceInfo = imageLayoutProperty->GetAlt().value_or(ImageSourceInfo(""));
1550         if (altLoadingCtx_ && altLoadingCtx_->GetSourceInfo() == altImageSourceInfo) {
1551             altLoadingCtx_.Reset();
1552         }
1553         LoadAltImage(altImageSourceInfo);
1554     }
1555 }
1556 
GetImageFitStr(ImageFit value)1557 std::string ImagePattern::GetImageFitStr(ImageFit value)
1558 {
1559     switch (value) {
1560         case ImageFit::CONTAIN:
1561             return "CONTAIN";
1562         case ImageFit::COVER:
1563             return "COVER";
1564         case ImageFit::FILL:
1565             return "FILL";
1566         case ImageFit::FITWIDTH:
1567             return "FITWIDTH";
1568         case ImageFit::FITHEIGHT:
1569             return "FITHEIGHT";
1570         case ImageFit::NONE:
1571             return "NONE";
1572         case ImageFit::SCALE_DOWN:
1573             return "SCALE_DOWN";
1574         case ImageFit::TOP_LEFT:
1575             return "TOP_LEFT";
1576         default:
1577             return "COVER";
1578     }
1579 }
1580 
GetImageRepeatStr(ImageRepeat value)1581 std::string ImagePattern::GetImageRepeatStr(ImageRepeat value)
1582 {
1583     switch (value) {
1584         case ImageRepeat::NO_REPEAT:
1585             return "NO_REPEAT";
1586         case ImageRepeat::REPEAT:
1587             return "REPEAT_XY";
1588         case ImageRepeat::REPEAT_X:
1589             return "REPEAT_X";
1590         case ImageRepeat::REPEAT_Y:
1591             return "REPEAT_Y";
1592         default:
1593             return "NO_REPEAT";
1594     }
1595 }
1596 
GetImageColorFilterStr(const std::vector<float> & colorFilter)1597 std::string ImagePattern::GetImageColorFilterStr(const std::vector<float>& colorFilter)
1598 {
1599     if (colorFilter.empty()) {
1600         return "";
1601     }
1602     std::string result = "[" + std::to_string(colorFilter[0]);
1603     for (uint32_t idx = 1; idx < colorFilter.size(); ++idx) {
1604         result += ", " + std::to_string(colorFilter[idx]);
1605     }
1606     return result + "]";
1607 }
1608 
EnableAnalyzer(bool value)1609 void ImagePattern::EnableAnalyzer(bool value)
1610 {
1611     isEnableAnalyzer_ = value;
1612     if (!isEnableAnalyzer_) {
1613         DestroyAnalyzerOverlay();
1614         return;
1615     }
1616 
1617     if (!imageAnalyzerManager_) {
1618         imageAnalyzerManager_ = std::make_shared<ImageAnalyzerManager>(GetHost(), ImageAnalyzerHolder::IMAGE);
1619     }
1620     RegisterVisibleAreaChange(false);
1621 }
1622 
1623 // As an example
SetImageAnalyzerConfig(const ImageAnalyzerConfig & config)1624 void ImagePattern::SetImageAnalyzerConfig(const ImageAnalyzerConfig &config)
1625 {
1626     if (!isEnableAnalyzer_) {
1627         return;
1628     }
1629 }
1630 
SetImageAnalyzerConfig(void * config)1631 void ImagePattern::SetImageAnalyzerConfig(void* config)
1632 {
1633     if (isEnableAnalyzer_) {
1634         CHECK_NULL_VOID(imageAnalyzerManager_);
1635         imageAnalyzerManager_->SetImageAnalyzerConfig(config);
1636     }
1637 }
1638 
SetImageAIOptions(void * options)1639 void ImagePattern::SetImageAIOptions(void* options)
1640 {
1641     if (!imageAnalyzerManager_) {
1642         imageAnalyzerManager_ = std::make_shared<ImageAnalyzerManager>(GetHost(), ImageAnalyzerHolder::IMAGE);
1643     }
1644     CHECK_NULL_VOID(imageAnalyzerManager_);
1645     imageAnalyzerManager_->SetImageAIOptions(options);
1646 }
1647 
IsSupportImageAnalyzerFeature()1648 bool ImagePattern::IsSupportImageAnalyzerFeature()
1649 {
1650     CHECK_NULL_RETURN(imageAnalyzerManager_, false);
1651     return isEnableAnalyzer_ && image_ && !loadingCtx_->GetSourceInfo().IsSvg() && loadingCtx_->GetFrameCount() <= 1 &&
1652         imageAnalyzerManager_->IsSupportImageAnalyzerFeature();
1653 }
1654 
CreateAnalyzerOverlay()1655 void ImagePattern::CreateAnalyzerOverlay()
1656 {
1657     CHECK_NULL_VOID(imageAnalyzerManager_);
1658     if (imageAnalyzerManager_->IsOverlayCreated()) {
1659         return;
1660     }
1661 
1662     CHECK_NULL_VOID(image_);
1663     auto pixelMap = image_->GetPixelMap();
1664     CHECK_NULL_VOID(pixelMap);
1665     imageAnalyzerManager_->CreateAnalyzerOverlay(pixelMap);
1666 }
1667 
UpdateAnalyzerOverlay()1668 void ImagePattern::UpdateAnalyzerOverlay()
1669 {
1670     CHECK_NULL_VOID(imageAnalyzerManager_);
1671     if (!IsSupportImageAnalyzerFeature() || !imageAnalyzerManager_->IsOverlayCreated()) {
1672         return;
1673     }
1674 
1675     CHECK_NULL_VOID(image_);
1676     auto pixelMap = image_->GetPixelMap();
1677     CHECK_NULL_VOID(pixelMap);
1678     imageAnalyzerManager_->UpdateAnalyzerOverlay(pixelMap);
1679 }
1680 
UpdateAnalyzerOverlayLayout()1681 void ImagePattern::UpdateAnalyzerOverlayLayout()
1682 {
1683     CHECK_NULL_VOID(imageAnalyzerManager_);
1684     imageAnalyzerManager_->UpdateAnalyzerOverlayLayout();
1685 }
1686 
DestroyAnalyzerOverlay()1687 void ImagePattern::DestroyAnalyzerOverlay()
1688 {
1689     CHECK_NULL_VOID(imageAnalyzerManager_);
1690     imageAnalyzerManager_->DestroyAnalyzerOverlay();
1691 }
1692 
ReleaseImageAnalyzer()1693 void ImagePattern::ReleaseImageAnalyzer()
1694 {
1695     CHECK_NULL_VOID(imageAnalyzerManager_);
1696     imageAnalyzerManager_->ReleaseImageAnalyzer();
1697 }
1698 
UpdateAnalyzerUIConfig(const RefPtr<NG::GeometryNode> & geometryNode)1699 void ImagePattern::UpdateAnalyzerUIConfig(const RefPtr<NG::GeometryNode>& geometryNode)
1700 {
1701     CHECK_NULL_VOID(imageAnalyzerManager_);
1702     imageAnalyzerManager_->UpdateAnalyzerUIConfig(geometryNode);
1703 }
1704 
AllowVisibleAreaCheck() const1705 bool ImagePattern::AllowVisibleAreaCheck() const
1706 {
1707     auto frameNode = GetHost();
1708     CHECK_NULL_RETURN(frameNode, false);
1709     RefPtr<FrameNode> parentUi = frameNode->GetAncestorNodeOfFrame(true);
1710     while (parentUi) {
1711         auto layoutProperty = parentUi->GetLayoutProperty();
1712         if (layoutProperty && layoutProperty->IsOverlayNode()) {
1713             return true;
1714         }
1715         parentUi = parentUi->GetAncestorNodeOfFrame(true);
1716     }
1717     return false;
1718 }
1719 
InitDefaultValue()1720 void ImagePattern::InitDefaultValue()
1721 {
1722     // add API version protection
1723     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
1724         autoResizeDefault_ = false;
1725         interpolationDefault_ = ImageInterpolation::LOW;
1726     }
1727     auto container = Container::Current();
1728     // If the default value is set to false, the ScenceBoard memory increases.
1729     // Therefore the default value is different in the ScenceBoard.
1730     if (container && container->IsScenceBoardWindow()) {
1731         autoResizeDefault_ = true;
1732         interpolationDefault_ = ImageInterpolation::NONE;
1733     }
1734 }
1735 
hasSceneChanged()1736 bool ImagePattern::hasSceneChanged()
1737 {
1738     auto imageLayoutProperty = GetLayoutProperty<ImageLayoutProperty>();
1739     CHECK_NULL_RETURN(imageLayoutProperty, false);
1740     auto src = imageLayoutProperty->GetImageSourceInfo().value_or(ImageSourceInfo(""));
1741     UpdateInternalResource(src);
1742     if (loadingCtx_ && loadingCtx_->GetSourceInfo() == src && srcRect_ == dstRect_) {
1743         return false;
1744     }
1745     return true;
1746 }
1747 
ImageAnimatorPattern()1748 void ImagePattern::ImageAnimatorPattern()
1749 {
1750     animator_ = CREATE_ANIMATOR();
1751     animator_->SetFillMode(FillMode::BACKWARDS);
1752     animator_->SetDuration(DEFAULT_DURATION);
1753     ResetFormAnimationFlag();
1754 }
1755 
CreatePictureAnimation(int32_t size)1756 RefPtr<PictureAnimation<int32_t>> ImagePattern::CreatePictureAnimation(int32_t size)
1757 {
1758     auto pictureAnimation = MakeRefPtr<PictureAnimation<int32_t>>();
1759     if (durationTotal_ > 0) {
1760         for (int32_t index = 0; index < size; ++index) {
1761             pictureAnimation->AddPicture(images_[index].duration / static_cast<float>(durationTotal_), index);
1762         }
1763         animator_->SetDuration(durationTotal_);
1764     } else {
1765         for (int32_t index = 0; index < size; ++index) {
1766             pictureAnimation->AddPicture(NORMALIZED_DURATION_MAX / static_cast<float>(size), index);
1767         }
1768     }
1769 
1770     pictureAnimation->AddListener([weak = WeakClaim(this)](int32_t index) {
1771         auto imageAnimator = weak.Upgrade();
1772         CHECK_NULL_VOID(imageAnimator);
1773         imageAnimator->SetShowingIndex(index);
1774     });
1775     return pictureAnimation;
1776 }
1777 
SetShowingIndex(int32_t index)1778 void ImagePattern::SetShowingIndex(int32_t index)
1779 {
1780     auto host = GetHost();
1781     CHECK_NULL_VOID(host);
1782     auto imageFrameNode = AceType::DynamicCast<FrameNode>(host->GetChildren().front());
1783     CHECK_NULL_VOID(imageFrameNode);
1784     auto imageLayoutProperty = imageFrameNode->GetLayoutProperty<ImageLayoutProperty>();
1785     CHECK_NULL_VOID(imageLayoutProperty);
1786     if (index >= static_cast<int32_t>(images_.size())) {
1787         TAG_LOGW(AceLogTag::ACE_IMAGE, "ImageAnimator update index error, index: %{public}d, size: %{public}zu",
1788             index, images_.size());
1789         return;
1790     }
1791     CHECK_NULL_VOID(images_[index].pixelMap);
1792     nowImageIndex_ = index;
1793     auto cacheImageIter = FindCacheImageNode(images_[index].pixelMap);
1794     if (IsShowingSrc(imageFrameNode, images_[index].pixelMap)) {
1795         ACE_SCOPED_TRACE("ImageAnimator same src %s, index %d", "PixelMap", index);
1796         UpdateShowingImageInfo(imageFrameNode, index);
1797     } else if (cacheImageIter == cacheImages_.end()) {
1798         ACE_SCOPED_TRACE("ImageAnimator no cache found, src %s, index %d", "PixelMap", index);
1799         UpdateShowingImageInfo(imageFrameNode, index);
1800     } else if (cacheImageIter->isLoaded) {
1801         ACE_SCOPED_TRACE("ImageAnimator useCache src %s, index %d", "PixelMap", index);
1802         auto cacheImageNode = cacheImageIter->imageNode;
1803         host->RemoveChild(imageFrameNode);
1804         host->AddChild(cacheImageNode, DEFAULT_NODE_SLOT, true);
1805         host->RebuildRenderContextTree();
1806         cacheImages_.erase(cacheImageIter);
1807         CacheImageStruct newCacheImageStruct(imageFrameNode);
1808         newCacheImageStruct.isLoaded = true;
1809         cacheImages_.emplace_back(newCacheImageStruct);
1810         UpdateShowingImageInfo(cacheImageNode, index);
1811     } else {
1812         UpdateShowingImageInfo(imageFrameNode, index);
1813         // wait for cache image loading
1814         ACE_SCOPED_TRACE("ImageAnimator waitForCache src %s, index %d", "PixelMap", index);
1815     }
1816     // update cache images
1817     CHECK_NULL_VOID(cacheImages_.size());
1818     int32_t nextIndex = GetNextIndex(index);
1819     for (auto& cacheImage : cacheImages_) {
1820         UpdateCacheImageInfo(cacheImage, nextIndex);
1821         nextIndex = GetNextIndex(nextIndex);
1822     }
1823     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1824 }
1825 
UpdateShowingImageInfo(const RefPtr<FrameNode> & imageFrameNode,int32_t index)1826 void ImagePattern::UpdateShowingImageInfo(const RefPtr<FrameNode>& imageFrameNode, int32_t index)
1827 {
1828     auto host = GetHost();
1829     CHECK_NULL_VOID(host);
1830     auto layoutProperty = host->GetLayoutProperty<ImageLayoutProperty>();
1831     CHECK_NULL_VOID(layoutProperty);
1832     auto imageLayoutProperty = imageFrameNode->GetLayoutProperty<ImageLayoutProperty>();
1833     CHECK_NULL_VOID(imageLayoutProperty);
1834 
1835     imageLayoutProperty->UpdateImageSourceInfo(ImageSourceInfo(images_[index].pixelMap));
1836     SetColorFilter(imageFrameNode);
1837     SetImageFit(imageFrameNode);
1838     //use the size of first pixelmap when no size is set
1839     auto &&layoutConstraint = layoutProperty->GetCalcLayoutConstraint();
1840     if (!layoutConstraint || !layoutConstraint->selfIdealSize.has_value()) {
1841         CalcSize realSize = {
1842             CalcLength(images_[0].pixelMap->GetWidth()), CalcLength(images_[0].pixelMap->GetHeight()) };
1843         imageLayoutProperty->UpdateUserDefinedIdealSize(realSize);
1844         imageLayoutProperty->UpdateMeasureType(MeasureType::MATCH_CONTENT);
1845         imageFrameNode->MarkModifyDone();
1846         imageFrameNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1847         return;
1848     }
1849     MarginProperty margin;
1850     margin.SetEdges(CalcLength(0.0));
1851     imageLayoutProperty->UpdateMargin(margin);
1852     imageLayoutProperty->ClearUserDefinedIdealSize(true, true);
1853     imageLayoutProperty->UpdateMeasureType(MeasureType::MATCH_PARENT);
1854     imageFrameNode->MarkModifyDone();
1855     imageFrameNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1856 }
1857 
UpdateCacheImageInfo(CacheImageStruct & cacheImage,int32_t index)1858 void ImagePattern::UpdateCacheImageInfo(CacheImageStruct& cacheImage, int32_t index)
1859 {
1860     if (index >= static_cast<int32_t>(images_.size())) {
1861         TAG_LOGW(AceLogTag::ACE_IMAGE, "PrepareImageInfo index error, index: %{public}d, size: %{public}zu",
1862             index, images_.size());
1863         return;
1864     }
1865     auto host = GetHost();
1866     CHECK_NULL_VOID(host);
1867     auto layoutProperty = host->GetLayoutProperty<ImageLayoutProperty>();
1868     CHECK_NULL_VOID(layoutProperty);
1869     auto imageLayoutProperty = cacheImage.imageNode->GetLayoutProperty<ImageLayoutProperty>();
1870     CHECK_NULL_VOID(imageLayoutProperty);
1871     CHECK_NULL_VOID(images_[index].pixelMap);
1872     // pixelmap
1873     if (imageLayoutProperty->HasImageSourceInfo()) {
1874         auto preSrc = imageLayoutProperty->GetImageSourceInfoValue().GetPixmap();
1875         if (preSrc != images_[index].pixelMap) {
1876             // need to cache newImage
1877             imageLayoutProperty->UpdateImageSourceInfo(ImageSourceInfo(images_[index].pixelMap));
1878             cacheImage.index = index;
1879             cacheImage.isLoaded = false;
1880         }
1881     }
1882     SetColorFilter(cacheImage.imageNode);
1883     SetImageFit(cacheImage.imageNode);
1884     //use the size of first pixelmap when no size is set
1885     auto &&layoutConstraint = layoutProperty->GetCalcLayoutConstraint();
1886     if (!layoutConstraint || !layoutConstraint->selfIdealSize.has_value()) {
1887         CalcSize realSize = {
1888             CalcLength(images_[0].pixelMap->GetWidth()), CalcLength(images_[0].pixelMap->GetHeight()) };
1889         imageLayoutProperty->UpdateUserDefinedIdealSize(realSize);
1890         cacheImage.imageNode->MarkModifyDone();
1891         return;
1892     }
1893     auto hostSize = host->GetGeometryNode()->GetPaddingSize();
1894     if (!hostSize.IsPositive()) {
1895         // if imageNode size is nonPositive, no pixelMap will be generated. Wait for size.
1896         return;
1897     }
1898     imageLayoutProperty->UpdateUserDefinedIdealSize(
1899         CalcSize(CalcLength(hostSize.Width()), CalcLength(hostSize.Height())));
1900     cacheImage.imageNode->MarkModifyDone();
1901 }
1902 
FindCacheImageNode(const RefPtr<PixelMap> & src)1903 std::list<ImagePattern::CacheImageStruct>::iterator ImagePattern::FindCacheImageNode(const RefPtr<PixelMap>& src)
1904 {
1905     for (auto iter = cacheImages_.begin(); iter != cacheImages_.end(); ++iter) {
1906         if (IsShowingSrc(iter->imageNode, src)) {
1907             return iter;
1908         }
1909     }
1910     return cacheImages_.end();
1911 }
1912 
GenerateCachedImages()1913 void ImagePattern::GenerateCachedImages()
1914 {
1915     CHECK_NULL_VOID(images_.size());
1916     auto averageShowTime = static_cast<uint32_t>(animator_->GetDuration()) / images_.size();
1917     size_t cacheImageNum = averageShowTime >= CRITICAL_TIME ? 1 : 2;
1918     cacheImageNum = std::min(images_.size() - 1, cacheImageNum);
1919     if (cacheImages_.size() > cacheImageNum) {
1920         cacheImages_.resize(cacheImageNum);
1921         return;
1922     }
1923     while (cacheImages_.size() < cacheImageNum) {
1924         auto imageNode = FrameNode::CreateFrameNode(V2::IMAGE_ETS_TAG, -1, AceType::MakeRefPtr<ImagePattern>());
1925         auto imageLayoutProperty = imageNode->GetLayoutProperty();
1926         imageLayoutProperty->UpdateMeasureType(MeasureType::MATCH_PARENT);
1927         imageLayoutProperty->UpdateAlignment(Alignment::TOP_LEFT);
1928         AddImageLoadSuccessEvent(imageNode);
1929         cacheImages_.emplace_back(CacheImageStruct(imageNode));
1930     }
1931 }
1932 
AdaptSelfSize()1933 void ImagePattern::AdaptSelfSize()
1934 {
1935     auto host = GetHost();
1936     CHECK_NULL_VOID(host);
1937     const auto& layoutProperty = host->GetLayoutProperty();
1938     CHECK_NULL_VOID(layoutProperty);
1939     if (layoutProperty->GetCalcLayoutConstraint() && layoutProperty->GetCalcLayoutConstraint()->selfIdealSize &&
1940         layoutProperty->GetCalcLayoutConstraint()->selfIdealSize->IsValid()) {
1941         return;
1942     }
1943     if (images_.empty()) {
1944         return;
1945     }
1946     CHECK_NULL_VOID(images_[0].pixelMap);
1947     hasSizeChanged = true;
1948     CalcSize realSize = {
1949         CalcLength(images_[0].pixelMap->GetWidth()), CalcLength(images_[0].pixelMap->GetHeight()) };
1950 
1951     const auto& layoutConstraint = layoutProperty->GetCalcLayoutConstraint();
1952     if (!layoutConstraint || !layoutConstraint->selfIdealSize) {
1953         layoutProperty->UpdateUserDefinedIdealSize(realSize);
1954         return;
1955     }
1956     if (!layoutConstraint->selfIdealSize->Width()) {
1957         layoutProperty->UpdateUserDefinedIdealSize(CalcSize(CalcLength(images_[0].pixelMap->GetWidth()), std::nullopt));
1958         return;
1959     }
1960     layoutProperty->UpdateUserDefinedIdealSize(CalcSize(std::nullopt, CalcLength(images_[0].pixelMap->GetHeight())));
1961 }
1962 
GetNextIndex(int32_t preIndex)1963 int32_t ImagePattern::GetNextIndex(int32_t preIndex)
1964 {
1965     return (preIndex + 1) % static_cast<int32_t>(images_.size());
1966 }
1967 
AddImageLoadSuccessEvent(const RefPtr<FrameNode> & imageFrameNode)1968 void ImagePattern::AddImageLoadSuccessEvent(const RefPtr<FrameNode>& imageFrameNode)
1969 {
1970     CHECK_NULL_VOID(imageFrameNode);
1971     auto eventHub = imageFrameNode->GetEventHub<ImageEventHub>();
1972     eventHub->SetOnComplete(
1973         [weakImage = WeakPtr<FrameNode>(imageFrameNode), weak = WeakClaim(this)](const LoadImageSuccessEvent& info) {
1974             if (info.GetLoadingStatus() != 1) {
1975                 // status 1 means load success. Only need loadSuccess event.
1976                 return;
1977             }
1978             auto pattern = weak.Upgrade();
1979             CHECK_NULL_VOID(pattern);
1980             auto cacheImageNode = weakImage.Upgrade();
1981             CHECK_NULL_VOID(cacheImageNode);
1982             auto imageAnimator = pattern->GetHost();
1983             CHECK_NULL_VOID(imageAnimator);
1984             auto cacheLayoutProperty = cacheImageNode->GetLayoutProperty<ImageLayoutProperty>();
1985             auto cacheSrc = cacheLayoutProperty->GetImageSourceInfoValue(ImageSourceInfo()).GetSrc();
1986             ACE_SCOPED_TRACE("ImageAnimator cache succeed. src %s", cacheSrc.c_str());
1987             auto iter = std::find_if(pattern->cacheImages_.begin(), pattern->cacheImages_.end(),
1988                 [&cacheImageNode](const CacheImageStruct& other) { return other.imageNode == cacheImageNode; });
1989             if (iter == pattern->cacheImages_.end()) {
1990                 return;
1991             }
1992             iter->isLoaded = true;
1993             if (pattern->nowImageIndex_ >= static_cast<int32_t>(pattern->images_.size())) {
1994                 TAG_LOGW(AceLogTag::ACE_IMAGE, "ImageAnimator showImage index is invalid");
1995                 return;
1996             }
1997             if (pattern->nowImageIndex_ == iter->index &&
1998                 IsShowingSrc(cacheImageNode, pattern->images_[pattern->nowImageIndex_].pixelMap)) {
1999                 pattern->SetShowingIndex(pattern->nowImageIndex_);
2000             }
2001         });
2002 }
2003 
IsShowingSrc(const RefPtr<FrameNode> & imageFrameNode,const RefPtr<PixelMap> & src)2004 bool ImagePattern::IsShowingSrc(const RefPtr<FrameNode>& imageFrameNode, const RefPtr<PixelMap>& src)
2005 {
2006     auto imageLayoutProperty = imageFrameNode->GetLayoutProperty<ImageLayoutProperty>();
2007     return imageLayoutProperty->HasImageSourceInfo()
2008         && imageLayoutProperty->GetImageSourceInfoValue().GetPixmap() == src;
2009 }
2010 
IsFormRender()2011 bool ImagePattern::IsFormRender()
2012 {
2013     auto pipeline = PipelineBase::GetCurrentContext();
2014     CHECK_NULL_RETURN(pipeline, false);
2015     return pipeline->IsFormRender();
2016 }
2017 
UpdateFormDurationByRemainder()2018 void ImagePattern::UpdateFormDurationByRemainder()
2019 {
2020     if (IsFormRender()) {
2021         if (!isFormAnimationStart_) {
2022             formAnimationRemainder_ =
2023                 DEFAULT_DURATION - (GetMicroTickCount() - formAnimationStartTime_) / MICROSEC_TO_MILLISEC;
2024         }
2025         if ((formAnimationRemainder_ > 0) && (animator_->GetDuration() > formAnimationRemainder_)) {
2026             animator_->SetDuration(formAnimationRemainder_);
2027         }
2028         if (formAnimationRemainder_ <= 0) {
2029             isFormAnimationEnd_ = true;
2030         }
2031     }
2032 }
2033 
ResetFormAnimationStartTime()2034 void ImagePattern::ResetFormAnimationStartTime()
2035 {
2036     if (isFormAnimationStart_) {
2037         isFormAnimationStart_ = false;
2038         formAnimationStartTime_ = GetMicroTickCount();
2039     }
2040 }
2041 
ResetFormAnimationFlag()2042 void ImagePattern::ResetFormAnimationFlag()
2043 {
2044     if (IsFormRender()) {
2045         formAnimationRemainder_ = DEFAULT_DURATION;
2046         isFormAnimationStart_ = true;
2047         isFormAnimationEnd_ = false;
2048     }
2049 }
2050 
SetIteration(int32_t iteration)2051 void ImagePattern::SetIteration(int32_t iteration)
2052 {
2053     if (iteration < -1) {
2054         return;
2055     }
2056     if (IsFormRender()) {
2057         iteration = DEFAULT_ITERATIONS;
2058     }
2059     animator_->SetIteration(iteration);
2060 }
2061 
SetDuration(int32_t duration)2062 void ImagePattern::SetDuration(int32_t duration)
2063 {
2064     if (duration < 0) {
2065         return;
2066     }
2067     int32_t finalDuration = durationTotal_ > 0 ? durationTotal_ : duration;
2068     if (IsFormRender()) {
2069         finalDuration = finalDuration < DEFAULT_DURATION ? finalDuration : DEFAULT_DURATION;
2070     }
2071     if (animator_->GetDuration() == finalDuration) {
2072         animator_->RemoveRepeatListener(repeatCallbackId_);
2073         return;
2074     }
2075     if (animator_->GetStatus() == Animator::Status::IDLE || animator_->GetStatus() == Animator::Status::STOPPED) {
2076         animator_->SetDuration(finalDuration);
2077         animator_->RemoveRepeatListener(repeatCallbackId_);
2078         return;
2079     }
2080     // if animator is running or paused, duration will work next time
2081     animator_->RemoveRepeatListener(repeatCallbackId_);
2082     repeatCallbackId_ = animator_->AddRepeatListener([weak = WeakClaim(this), finalDuration]() {
2083         auto imageAnimator = weak.Upgrade();
2084         CHECK_NULL_VOID(imageAnimator);
2085         imageAnimator->animator_->SetDuration(finalDuration);
2086     });
2087 }
2088 
SetOnProgressCallback(std::function<void (const uint32_t & dlNow,const uint32_t & dlTotal)> && onProgress)2089 void ImagePattern::SetOnProgressCallback(
2090     std::function<void(const uint32_t& dlNow, const uint32_t& dlTotal)>&& onProgress)
2091 {
2092     onProgressCallback_ = onProgress;
2093 }
2094 
OnSensitiveStyleChange(bool isSensitive)2095 void ImagePattern::OnSensitiveStyleChange(bool isSensitive)
2096 {
2097     auto host = GetHost();
2098     CHECK_NULL_VOID(host);
2099     auto privacySensitive = host->IsPrivacySensitive();
2100     if (isSensitive && privacySensitive) {
2101         isSensitive_ = true;
2102         auto renderContext = host->GetRenderContext();
2103         CHECK_NULL_VOID(renderContext);
2104         CalcDimension radius;
2105         radius.SetValue(IMAGE_SENSITIVE_RADIUS);
2106         Color color = Color::FromARGB(13, 255, 255, 255);
2107         EffectOption option = { radius, IMAGE_SENSITIVE_SATURATION, IMAGE_SENSITIVE_BRIGHTNESS, color };
2108         if (renderContext->GetBackBlurRadius().has_value()) {
2109             renderContext->UpdateBackBlurRadius(Dimension());
2110         }
2111         if (renderContext->GetBackBlurStyle().has_value()) {
2112             renderContext->UpdateBackBlurStyle(std::nullopt);
2113         }
2114         renderContext->UpdateBackgroundEffect(option);
2115     } else {
2116         isSensitive_ = false;
2117     }
2118     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
2119 }
2120 
ResetImageProperties()2121 void ImagePattern::ResetImageProperties()
2122 {
2123     SetCopyOption(CopyOptions::None);
2124     OnImageModifyDone();
2125 }
2126 
ResetImage()2127 void ImagePattern::ResetImage()
2128 {
2129     image_ = nullptr;
2130     imageQuality_ = AIImageQuality::NONE;
2131     isImageQualityChange_ = false;
2132     loadingCtx_.Reset();
2133     auto host = GetHost();
2134     CHECK_NULL_VOID(host);
2135     if (!altImage_) {
2136         auto rsRenderContext = host->GetRenderContext();
2137         CHECK_NULL_VOID(rsRenderContext);
2138         rsRenderContext->ClearDrawCommands();
2139     }
2140 }
2141 
ResetAltImage()2142 void ImagePattern::ResetAltImage()
2143 {
2144     altImage_ = nullptr;
2145     altLoadingCtx_.Reset();
2146     if (!image_) {
2147         auto host = GetHost();
2148         CHECK_NULL_VOID(host);
2149         auto rsRenderContext = host->GetRenderContext();
2150         CHECK_NULL_VOID(rsRenderContext);
2151         rsRenderContext->ClearDrawCommands();
2152     }
2153 }
2154 
ResetImageAndAlt()2155 void ImagePattern::ResetImageAndAlt()
2156 {
2157     image_ = nullptr;
2158     loadingCtx_ = nullptr;
2159     srcRect_.Reset();
2160     dstRect_.Reset();
2161     altLoadingCtx_ = nullptr;
2162     altImage_ = nullptr;
2163     altDstRect_.reset();
2164     altSrcRect_.reset();
2165     auto frameNode = GetHost();
2166     CHECK_NULL_VOID(frameNode);
2167     auto rsRenderContext = frameNode->GetRenderContext();
2168     CHECK_NULL_VOID(rsRenderContext);
2169     rsRenderContext->ClearDrawCommands();
2170     CloseSelectOverlay();
2171     DestroyAnalyzerOverlay();
2172     frameNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2173 }
2174 
ResetPictureSize()2175 void ImagePattern::ResetPictureSize()
2176 {
2177     auto host = GetHost();
2178     CHECK_NULL_VOID(host);
2179     const auto& layoutProperty = host->GetLayoutProperty();
2180     CHECK_NULL_VOID(layoutProperty);
2181     layoutProperty->ClearUserDefinedIdealSize(true, true);
2182     hasSizeChanged = false;
2183 }
2184 
SetColorFilter(const RefPtr<FrameNode> & imageFrameNode)2185 void ImagePattern::SetColorFilter(const RefPtr<FrameNode>& imageFrameNode)
2186 {
2187     auto host = GetHost();
2188     CHECK_NULL_VOID(host);
2189     auto renderProperty = host->GetPaintProperty<ImageRenderProperty>();
2190     CHECK_NULL_VOID(renderProperty);
2191     auto imageRenderProperty = imageFrameNode->GetPaintProperty<ImageRenderProperty>();
2192     CHECK_NULL_VOID(imageRenderProperty);
2193     if (renderProperty->HasColorFilter()) {
2194         imageRenderProperty->UpdateColorFilter(renderProperty->GetColorFilter().value());
2195     }
2196     if (renderProperty->HasDrawingColorFilter()) {
2197         imageRenderProperty->UpdateDrawingColorFilter(renderProperty->GetDrawingColorFilter().value());
2198     }
2199 }
2200 
SetImageFit(const RefPtr<FrameNode> & imageFrameNode)2201 void ImagePattern::SetImageFit(const RefPtr<FrameNode>& imageFrameNode)
2202 {
2203     auto host = GetHost();
2204     CHECK_NULL_VOID(host);
2205     auto layoutProperty = host->GetLayoutProperty<ImageLayoutProperty>();
2206     CHECK_NULL_VOID(layoutProperty);
2207     auto renderProperty = host->GetPaintProperty<ImageRenderProperty>();
2208     CHECK_NULL_VOID(renderProperty);
2209     auto imageLayoutProperty = imageFrameNode->GetLayoutProperty<ImageLayoutProperty>();
2210     CHECK_NULL_VOID(imageLayoutProperty);
2211     auto imageRenderProperty = imageFrameNode->GetPaintProperty<ImageRenderProperty>();
2212     CHECK_NULL_VOID(imageRenderProperty);
2213     if (renderProperty->HasImageFit()) {
2214         imageRenderProperty->UpdateImageFit(renderProperty->GetImageFit().value());
2215     }
2216     if (layoutProperty->HasImageFit()) {
2217         imageLayoutProperty->UpdateImageFit(layoutProperty->GetImageFit().value());
2218     }
2219 }
2220 
SetObscured()2221 void ImagePattern::SetObscured()
2222 {
2223     auto host = GetHost();
2224     CHECK_NULL_VOID(host);
2225     auto imageFrameNode = AceType::DynamicCast<FrameNode>(host->GetChildren().front());
2226     CHECK_NULL_VOID(imageFrameNode);
2227     auto obscuredReasons = host->GetRenderContext()->GetObscured().value_or(std::vector<ObscuredReasons>());
2228     const auto& castRenderContext = imageFrameNode->GetRenderContext();
2229     if (castRenderContext) {
2230         castRenderContext->UpdateObscured(obscuredReasons);
2231     }
2232     imageFrameNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2233     host->GetRenderContext()->ResetObscured();
2234     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2235 }
2236 
TriggerVisibleAreaChangeForChild(const RefPtr<UINode> & node,bool visible,double ratio)2237 void ImagePattern::TriggerVisibleAreaChangeForChild(const RefPtr<UINode>& node, bool visible, double ratio)
2238 {
2239     for (const auto& childNode : node->GetChildren()) {
2240         if (AceType::InstanceOf<FrameNode>(childNode)) {
2241             auto frame = AceType::DynamicCast<FrameNode>(childNode);
2242             if (!frame || !frame->GetEventHub<EventHub>()) {
2243                 continue;
2244             }
2245             auto callback = frame->GetEventHub<EventHub>()->GetVisibleAreaCallback(true).callback;
2246             if (callback) {
2247                 callback(visible, ratio);
2248             }
2249         }
2250         TriggerVisibleAreaChangeForChild(childNode, visible, ratio);
2251     }
2252 }
2253 } // namespace OHOS::Ace::NG
2254