• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2025 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/network/download_manager.h"
22 #include "core/common/ace_engine_ext.h"
23 #include "core/common/ai/image_analyzer_manager.h"
24 #include "core/common/udmf/udmf_client.h"
25 #include "core/components/common/layout/constants.h"
26 #include "core/components/image/image_theme.h"
27 #include "core/components/text/text_theme.h"
28 #include "core/components/theme/icon_theme.h"
29 #include "core/components_ng/image_provider/image_utils.h"
30 #include "core/components_ng/pattern/image/image_content_modifier.h"
31 #include "core/components_ng/pattern/image/image_dfx.h"
32 #include "core/components_ng/pattern/image/image_layout_property.h"
33 #include "core/components_ng/pattern/image/image_paint_method.h"
34 #include "core/components_ng/property/border_property.h"
35 #include "core/components_ng/render/drawing.h"
36 #include "core/pipeline_ng/pipeline_context.h"
37 
38 namespace OHOS::Ace::NG {
39 namespace {
40 constexpr int32_t DEFAULT_DURATION = 1000; // ms
41 constexpr uint32_t CRITICAL_TIME = 50;     // ms. If show time of image is less than this, use more cacheImages.
42 constexpr int64_t MICROSEC_TO_MILLISEC = 1000;
43 constexpr int32_t DEFAULT_ITERATIONS = 1;
44 constexpr int32_t MEMORY_LEVEL_CRITICAL_STATUS = 2;
45 
GetImageInterpolation(ImageInterpolation interpolation)46 std::string GetImageInterpolation(ImageInterpolation interpolation)
47 {
48     switch (interpolation) {
49         case ImageInterpolation::LOW:
50             return "LOW";
51         case ImageInterpolation::MEDIUM:
52             return "MEDIUM";
53         case ImageInterpolation::HIGH:
54             return "HIGH";
55         default:
56             return "NONE";
57     }
58 }
59 
GetDynamicModeString(DynamicRangeMode dynamicMode)60 std::string GetDynamicModeString(DynamicRangeMode dynamicMode)
61 {
62     switch (dynamicMode) {
63         case DynamicRangeMode::HIGH:
64             return "HIGH";
65         case DynamicRangeMode::CONSTRAINT:
66             return "CONSTRAINT";
67         case DynamicRangeMode::STANDARD:
68             return "STANDARD";
69         default:
70             return "STANDARD";
71     }
72 }
73 
ConvertOrientationToString(ImageRotateOrientation orientation)74 std::string ConvertOrientationToString(ImageRotateOrientation orientation)
75 {
76     switch (orientation) {
77         case ImageRotateOrientation::UP:
78             return "UP";
79         case ImageRotateOrientation::RIGHT:
80             return "RIGHT";
81         case ImageRotateOrientation::DOWN:
82             return "DOWN";
83         case ImageRotateOrientation::LEFT:
84             return "LEFT";
85         case ImageRotateOrientation::AUTO:
86             return "AUTO";
87         default:
88             return "UP";
89     }
90 }
91 } // namespace
92 
93 constexpr float BOX_EPSILON = 0.5f;
94 constexpr float IMAGE_SENSITIVE_RADIUS = 80.0f;
95 constexpr double IMAGE_SENSITIVE_SATURATION = 1.0;
96 constexpr double IMAGE_SENSITIVE_BRIGHTNESS = 1.08;
97 constexpr uint32_t MAX_SRC_LENGTH = 100; // prevent the Base64 image format from too long.
98 
ImagePattern()99 ImagePattern::ImagePattern()
100 {
101     InitDefaultValue();
102     ImageAnimatorPattern();
103 }
104 
~ImagePattern()105 ImagePattern::~ImagePattern()
106 {
107     if (isEnableAnalyzer_) {
108         ReleaseImageAnalyzer();
109     }
110 }
111 
CreateDataReadyCallback()112 DataReadyNotifyTask ImagePattern::CreateDataReadyCallback()
113 {
114     return [weak = WeakClaim(this)](const ImageSourceInfo& sourceInfo) {
115         auto pattern = weak.Upgrade();
116         CHECK_NULL_VOID(pattern);
117         pattern->isOrientationChange_ = false;
118         auto imageLayoutProperty = pattern->GetLayoutProperty<ImageLayoutProperty>();
119         CHECK_NULL_VOID(imageLayoutProperty);
120         auto currentSourceInfo = imageLayoutProperty->GetImageSourceInfo().value_or(ImageSourceInfo(""));
121         if (currentSourceInfo != sourceInfo) {
122             TAG_LOGW(AceLogTag::ACE_IMAGE,
123                 "sourceInfo does not match, ignore current callback. %{public}s."
124                 "current: %{private}s vs callback's: %{private}s",
125                 pattern->imageDfxConfig_.ToStringWithoutSrc().c_str(), currentSourceInfo.ToString().c_str(),
126                 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,
144                 "sourceInfo does not match, ignore current callback. %{public}s."
145                 "current: %{private}s vs callback's: %{private}s",
146                 pattern->imageDfxConfig_.ToStringWithoutSrc().c_str(), currentSourceInfo.ToString().c_str(),
147                 sourceInfo.ToString().c_str());
148             return;
149         }
150         pattern->OnImageLoadSuccess();
151     };
152 }
153 
CreateLoadFailCallback()154 LoadFailNotifyTask ImagePattern::CreateLoadFailCallback()
155 {
156     return [weak = WeakClaim(this)](const ImageSourceInfo& sourceInfo, const std::string& errorMsg) {
157         auto pattern = weak.Upgrade();
158         CHECK_NULL_VOID(pattern);
159         pattern->isOrientationChange_ = false;
160         auto imageLayoutProperty = pattern->GetLayoutProperty<ImageLayoutProperty>();
161         CHECK_NULL_VOID(imageLayoutProperty);
162         auto currentSourceInfo = imageLayoutProperty->GetImageSourceInfo().value_or(ImageSourceInfo(""));
163         if (currentSourceInfo != sourceInfo) {
164             TAG_LOGW(AceLogTag::ACE_IMAGE,
165                 "sourceInfo does not match, ignore current callback. %{public}s."
166                 "current: %{private}s vs callback's: %{private}s",
167                 pattern->imageDfxConfig_.ToStringWithoutSrc().c_str(), currentSourceInfo.ToString().c_str(),
168                 sourceInfo.ToString().c_str());
169             return;
170         }
171         if (!currentSourceInfo.IsFromReset()) {
172             pattern->OnImageLoadFail(errorMsg);
173         }
174     };
175 }
176 
CreateCompleteCallBackInDataReady()177 OnCompleteInDataReadyNotifyTask ImagePattern::CreateCompleteCallBackInDataReady()
178 {
179     return [weak = WeakClaim(this)](const ImageSourceInfo& sourceInfo) {
180         auto pattern = weak.Upgrade();
181         CHECK_NULL_VOID(pattern);
182         auto imageLayoutProperty = pattern->GetLayoutProperty<ImageLayoutProperty>();
183         CHECK_NULL_VOID(imageLayoutProperty);
184         auto currentSourceInfo = imageLayoutProperty->GetImageSourceInfo().value_or(ImageSourceInfo(""));
185         if (currentSourceInfo != sourceInfo) {
186             TAG_LOGW(AceLogTag::ACE_IMAGE,
187                 "sourceInfo does not match, ignore current callback. %{public}s."
188                 "current: %{private}s vs callback's: %{private}s",
189                 pattern->imageDfxConfig_.ToStringWithoutSrc().c_str(), currentSourceInfo.ToString().c_str(),
190                 sourceInfo.ToString().c_str());
191             return;
192         }
193         pattern->OnCompleteInDataReady();
194     };
195 }
196 
OnCompleteInDataReady()197 void ImagePattern::OnCompleteInDataReady()
198 {
199     auto host = GetHost();
200     CHECK_NULL_VOID(host);
201     const auto& geometryNode = host->GetGeometryNode();
202     CHECK_NULL_VOID(geometryNode);
203     auto imageEventHub = GetEventHub<ImageEventHub>();
204     CHECK_NULL_VOID(imageEventHub);
205     CHECK_NULL_VOID(loadingCtx_);
206     LoadImageSuccessEvent event(loadingCtx_->GetImageSize().Width(), loadingCtx_->GetImageSize().Height(),
207         geometryNode->GetFrameSize().Width(), geometryNode->GetFrameSize().Height(), 0,
208         geometryNode->GetContentSize().Width(), geometryNode->GetContentSize().Height(),
209         geometryNode->GetContentOffset().GetX(), geometryNode->GetContentOffset().GetY());
210     imageEventHub->FireCompleteEvent(event);
211 }
212 
TriggerFirstVisibleAreaChange()213 void ImagePattern::TriggerFirstVisibleAreaChange()
214 {
215     if (isComponentSnapshotNode_) {
216         OnVisibleAreaChange(true);
217         return;
218     }
219     auto host = GetHost();
220     CHECK_NULL_VOID(host);
221     RectF frameRect;
222     RectF visibleInnerRect;
223     RectF visibleRect;
224     host->GetVisibleRectWithClip(visibleRect, visibleInnerRect, frameRect);
225     bool visible = GreatNotEqual(visibleInnerRect.Width(), 0.0) && GreatNotEqual(visibleInnerRect.Height(), 0.0);
226     ACE_SCOPED_TRACE("TriggerFirstVisibleAreaChange [%d]-%s", visible, imageDfxConfig_.ToStringWithSrc().c_str());
227     if (SystemProperties::GetDebugEnabled()) {
228         TAG_LOGD(AceLogTag::ACE_IMAGE, "TriggerFirstVisibleAreaChange [%{public}d]-%{public}s", visible,
229             imageDfxConfig_.ToStringWithSrc().c_str());
230     }
231     OnVisibleAreaChange(visible);
232 }
233 
PrepareAnimation(const RefPtr<CanvasImage> & image)234 void ImagePattern::PrepareAnimation(const RefPtr<CanvasImage>& image)
235 {
236     if (image->IsStatic()) {
237         return;
238     }
239     SetRedrawCallback(image);
240     SetOnFinishCallback(image);
241     RegisterVisibleAreaChange();
242     TriggerFirstVisibleAreaChange();
243 }
244 
SetOnFinishCallback(const RefPtr<CanvasImage> & image)245 void ImagePattern::SetOnFinishCallback(const RefPtr<CanvasImage>& image)
246 {
247     CHECK_NULL_VOID(image);
248     image->SetOnFinishCallback([weak = WeakPtr(GetHost())] {
249         auto imageNode = weak.Upgrade();
250         CHECK_NULL_VOID(imageNode);
251         auto eventHub = imageNode->GetEventHub<ImageEventHub>();
252         if (eventHub) {
253             eventHub->FireFinishEvent();
254         }
255     });
256 }
257 
SetRedrawCallback(const RefPtr<CanvasImage> & image)258 void ImagePattern::SetRedrawCallback(const RefPtr<CanvasImage>& image)
259 {
260     CHECK_NULL_VOID(image);
261     // set animation flush function for svg / gif
262     image->SetRedrawCallback([weak = WeakPtr(GetHost())] {
263         auto imageNode = weak.Upgrade();
264         CHECK_NULL_VOID(imageNode);
265         imageNode->MarkNeedRenderOnly();
266     });
267 }
268 
RegisterVisibleAreaChange(bool isCalcClip)269 void ImagePattern::RegisterVisibleAreaChange(bool isCalcClip)
270 {
271     auto pipeline = GetContext();
272     // register to onVisibleAreaChange
273     CHECK_NULL_VOID(pipeline);
274     auto callback = [weak = WeakClaim(this)](bool visible, double ratio) {
275         auto self = weak.Upgrade();
276         CHECK_NULL_VOID(self);
277         self->OnVisibleAreaChange(visible, ratio);
278     };
279     auto host = GetHost();
280     CHECK_NULL_VOID(host);
281     // add visibleAreaChangeNode(inner callback)
282     std::vector<double> ratioList = { 0.0 };
283     pipeline->AddVisibleAreaChangeNode(host, ratioList, callback, false, isCalcClip);
284 }
285 
CheckHandles(SelectHandleInfo & handleInfo)286 void ImagePattern::CheckHandles(SelectHandleInfo& handleInfo)
287 {
288     auto host = GetHost();
289     CHECK_NULL_VOID(host);
290     auto renderContext = host->GetRenderContext();
291     CHECK_NULL_VOID(renderContext);
292     if (!renderContext->GetClipEdge().value_or(true)) {
293         return;
294     }
295     // use global offset.
296     const auto& geometryNode = host->GetGeometryNode();
297     auto contentRect = geometryNode->GetContentRect();
298     RectF visibleContentRect(contentRect.GetOffset() + parentGlobalOffset_, contentRect.GetSize());
299     auto parent = host->GetAncestorNodeOfFrame(true);
300     visibleContentRect = GetVisibleContentRect(parent, visibleContentRect);
301     auto paintRect = handleInfo.paintRect;
302     PointF bottomPoint = { paintRect.Left(), paintRect.Bottom() - BOX_EPSILON };
303     PointF topPoint = { paintRect.Left(), paintRect.Top() + BOX_EPSILON };
304     handleInfo.isShow = visibleContentRect.IsInRegion(bottomPoint) && visibleContentRect.IsInRegion(topPoint);
305 }
306 
CalAndUpdateSelectOverlay()307 void ImagePattern::CalAndUpdateSelectOverlay()
308 {
309     auto host = GetHost();
310     CHECK_NULL_VOID(host);
311     auto rect = host->GetTransformRectRelativeToWindow();
312     SelectOverlayInfo info;
313     const auto& geometryNode = host->GetGeometryNode();
314     CHECK_NULL_VOID(geometryNode);
315     SizeF handleSize = { SelectHandleInfo::GetDefaultLineWidth().ConvertToPx(),
316         geometryNode->GetContentSize().Height() };
317     info.firstHandle.paintRect = RectF(rect.GetOffset(), handleSize);
318     CheckHandles(info.firstHandle);
319     OffsetF offset(rect.Width() - handleSize.Width(), rect.Height() - handleSize.Height());
320     info.secondHandle.paintRect = RectF(rect.GetOffset() + offset, handleSize);
321     CheckHandles(info.secondHandle);
322     selectOverlay_->UpdateFirstAndSecondHandleInfo(info.firstHandle, info.secondHandle);
323 }
324 
GetParentGlobalOffset() const325 OffsetF ImagePattern::GetParentGlobalOffset() const
326 {
327     auto host = GetHost();
328     CHECK_NULL_RETURN(host, {});
329     auto pipeline = host->GetContext();
330     CHECK_NULL_RETURN(pipeline, {});
331     auto rootOffset = pipeline->GetRootRect().GetOffset();
332     return host->GetPaintRectOffset(false, true) - rootOffset;
333 }
334 
OnAreaChangedInner()335 void ImagePattern::OnAreaChangedInner()
336 {
337     if (selectOverlay_ && !selectOverlay_->IsClosed()) {
338         auto parentGlobalOffset = GetParentGlobalOffset();
339         if (parentGlobalOffset != parentGlobalOffset_) {
340             parentGlobalOffset_ = parentGlobalOffset;
341             CalAndUpdateSelectOverlay();
342         }
343     }
344 }
345 
RemoveAreaChangeInner()346 void ImagePattern::RemoveAreaChangeInner()
347 {
348     auto pipeline = GetContext();
349     CHECK_NULL_VOID(pipeline);
350     auto host = GetHost();
351     CHECK_NULL_VOID(host);
352     auto eventHub = host->GetEventHub<ImageEventHub>();
353     CHECK_NULL_VOID(eventHub);
354     if (eventHub->HasOnAreaChanged()) {
355         return;
356     }
357     pipeline->RemoveOnAreaChangeNode(host->GetId());
358 }
359 
CalcImageContentPaintSize(const RefPtr<GeometryNode> & geometryNode)360 RectF ImagePattern::CalcImageContentPaintSize(const RefPtr<GeometryNode>& geometryNode)
361 {
362     RectF paintSize;
363     auto imageRenderProperty = GetPaintProperty<ImageRenderProperty>();
364     CHECK_NULL_RETURN(imageRenderProperty, paintSize);
365     ImageRepeat repeat = imageRenderProperty->GetImageRepeat().value_or(ImageRepeat::NO_REPEAT);
366     bool imageRepeatX = repeat == ImageRepeat::REPEAT || repeat == ImageRepeat::REPEAT_X;
367     bool imageRepeatY = repeat == ImageRepeat::REPEAT || repeat == ImageRepeat::REPEAT_Y;
368 
369     if (loadingCtx_->GetSourceInfo().IsSvg()) {
370         const float invalidValue = -1;
371         paintSize.SetWidth(dstRect_.IsValid() ? dstRect_.Width() : invalidValue);
372         paintSize.SetHeight(dstRect_.IsValid() ? dstRect_.Height() : invalidValue);
373         paintSize.SetLeft(
374             dstRect_.IsValid() ? dstRect_.GetX() + geometryNode->GetContentOffset().GetX() : invalidValue);
375         paintSize.SetTop(dstRect_.IsValid() ? dstRect_.GetY() + geometryNode->GetContentOffset().GetY() : invalidValue);
376     } else {
377         paintSize.SetWidth(imageRepeatX ? geometryNode->GetContentSize().Width() : dstRect_.Width());
378         paintSize.SetHeight(imageRepeatY ? geometryNode->GetContentSize().Height() : dstRect_.Height());
379         paintSize.SetLeft((imageRepeatX ? 0 : dstRect_.GetX()) + geometryNode->GetContentOffset().GetX());
380         paintSize.SetTop((imageRepeatY ? 0 : dstRect_.GetY()) + geometryNode->GetContentOffset().GetY());
381     }
382     return paintSize;
383 }
384 
ClearAltData()385 void ImagePattern::ClearAltData()
386 {
387     altLoadingCtx_ = nullptr;
388     altImage_ = nullptr;
389     altDstRect_.reset();
390     altSrcRect_.reset();
391 }
392 
ApplyAIModificationsToImage()393 void ImagePattern::ApplyAIModificationsToImage()
394 {
395     auto host = GetHost();
396     CHECK_NULL_VOID(host);
397     const auto& geometryNode = host->GetGeometryNode();
398     CHECK_NULL_VOID(geometryNode);
399     if (IsSupportImageAnalyzerFeature()) {
400         if (isPixelMapChanged_) {
401             UpdateAnalyzerOverlay();
402         }
403         UpdateAnalyzerUIConfig(geometryNode);
404         auto context = host->GetContext();
405         CHECK_NULL_VOID(context);
406         auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
407         uiTaskExecutor.PostTask(
408             [weak = WeakClaim(this)] {
409                 auto pattern = weak.Upgrade();
410                 CHECK_NULL_VOID(pattern);
411                 ContainerScope scope(pattern->GetHostInstanceId());
412                 pattern->CreateAnalyzerOverlay();
413             },
414             "ArkUIImageCreateAnalyzerOverlay");
415     }
416 }
417 
OnImageLoadSuccess()418 void ImagePattern::OnImageLoadSuccess()
419 {
420     CHECK_NULL_VOID(loadingCtx_);
421     auto host = GetHost();
422     CHECK_NULL_VOID(host);
423     const auto& geometryNode = host->GetGeometryNode();
424     CHECK_NULL_VOID(geometryNode);
425 
426     image_ = loadingCtx_->MoveCanvasImage();
427     if (!image_) {
428         TAG_LOGW(AceLogTag::ACE_IMAGE, "%{public}s, %{private}s OnImageLoadSuccess but Canvas image is null.",
429             imageDfxConfig_.ToStringWithoutSrc().c_str(), imageDfxConfig_.imageSrc_.c_str());
430         return;
431     }
432     srcRect_ = loadingCtx_->GetSrcRect();
433     dstRect_ = loadingCtx_->GetDstRect();
434     auto srcInfo = loadingCtx_->GetSourceInfo();
435     auto frameCount = loadingCtx_->GetFrameCount();
436 
437     image_->SetImageDfxConfig(imageDfxConfig_);
438     RectF paintRect = CalcImageContentPaintSize(geometryNode);
439     LoadImageSuccessEvent event(loadingCtx_->GetImageSize().Width(), loadingCtx_->GetImageSize().Height(),
440         geometryNode->GetFrameSize().Width(), geometryNode->GetFrameSize().Height(), 1, paintRect.Width(),
441         paintRect.Height(), paintRect.GetX(), paintRect.GetY());
442 
443     SetImagePaintConfig(image_, srcRect_, dstRect_, srcInfo, frameCount);
444     if (srcInfo.IsSvg()) {
445         UpdateSvgSmoothEdgeValue();
446     }
447     PrepareAnimation(image_);
448     if (enableDrag_) {
449         EnableDrag();
450     }
451     ClearAltData();
452     auto eventHub = GetEventHub<ImageEventHub>();
453     if (eventHub) {
454         eventHub->FireCompleteEvent(event);
455     }
456 
457     ApplyAIModificationsToImage();
458 
459     ACE_SCOPED_TRACE("OnImageLoadSuccess %s", imageDfxConfig_.ToStringWithSrc().c_str());
460     if (SystemProperties::GetDebugEnabled()) {
461         TAG_LOGI(AceLogTag::ACE_IMAGE, "ImageLoadSuccess %{public}s", imageDfxConfig_.ToStringWithSrc().c_str());
462     }
463     host->MarkNeedRenderOnly();
464 }
465 
CheckIfNeedLayout()466 bool ImagePattern::CheckIfNeedLayout()
467 {
468     auto host = GetHost();
469     CHECK_NULL_RETURN(host, true);
470     CHECK_NULL_RETURN(host->GetGeometryNode()->GetContent(), true);
471     const auto& props = DynamicCast<ImageLayoutProperty>(host->GetLayoutProperty());
472     CHECK_NULL_RETURN(props, true);
473     const auto& layoutConstraint = props->GetCalcLayoutConstraint();
474     CHECK_NULL_RETURN(layoutConstraint, true);
475     return !(layoutConstraint->selfIdealSize && layoutConstraint->selfIdealSize->IsValid());
476 }
477 
OnImageDataReady()478 void ImagePattern::OnImageDataReady()
479 {
480     CHECK_NULL_VOID(loadingCtx_);
481     auto host = GetHost();
482     CHECK_NULL_VOID(host);
483     const auto& geometryNode = host->GetGeometryNode();
484     CHECK_NULL_VOID(geometryNode);
485     // update rotate orientation before decoding
486     UpdateOrientation();
487 
488     if (CheckIfNeedLayout()) {
489         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
490         return;
491     }
492 
493     // 1. If PropertyChangeFlag contains PROPERTY_UPDATE_MEASURE,
494     //    the image will be decoded after layout.
495     // 2. The image node in imageAnimator will not be decoded after layout, decode directly.
496     auto layoutProp = host->GetLayoutProperty<ImageLayoutProperty>();
497     CHECK_NULL_VOID(layoutProp);
498     if (!((layoutProp->GetPropertyChangeFlag() & PROPERTY_UPDATE_MEASURE) == PROPERTY_UPDATE_MEASURE) ||
499         isImageAnimator_) {
500         StartDecoding(geometryNode->GetContentSize());
501     }
502 }
503 
504 // Update the necessary rotate orientation for drawing and measuring.
UpdateOrientation()505 void ImagePattern::UpdateOrientation()
506 {
507     auto imageObj = loadingCtx_->GetImageObject();
508     CHECK_NULL_VOID(imageObj);
509     if (imageObj->GetFrameCount() > 1) {
510         imageObj->SetOrientation(ImageRotateOrientation::UP);
511         return;
512     }
513     imageObj->SetUserOrientation(userOrientation_);
514     auto selfOrientation_ = imageObj->GetOrientation();
515     if (userOrientation_ == ImageRotateOrientation::UP) {
516         joinOrientation_ = ImageRotateOrientation::UP;
517         return;
518     }
519     if (userOrientation_ == ImageRotateOrientation::AUTO) {
520         joinOrientation_ = selfOrientation_;
521     } else {
522         joinOrientation_ = userOrientation_;
523     }
524     // update image object orientation before decoding
525     imageObj->SetOrientation(joinOrientation_);
526 }
527 
OnImageLoadFail(const std::string & errorMsg)528 void ImagePattern::OnImageLoadFail(const std::string& errorMsg)
529 {
530     auto host = GetHost();
531     CHECK_NULL_VOID(host);
532     const auto& geometryNode = host->GetGeometryNode();
533     auto imageEventHub = GetEventHub<ImageEventHub>();
534     CHECK_NULL_VOID(imageEventHub);
535     LoadImageFailEvent event(geometryNode->GetFrameSize().Width(), geometryNode->GetFrameSize().Height(), errorMsg);
536     imageEventHub->FireErrorEvent(event);
537 }
538 
SetExternalDecodeFormat(PixelFormat externalDecodeFormat)539 void ImagePattern::SetExternalDecodeFormat(PixelFormat externalDecodeFormat)
540 {
541     isImageReloadNeeded_ = isImageReloadNeeded_ | (externalDecodeFormat_ != externalDecodeFormat);
542     switch (externalDecodeFormat) {
543         case PixelFormat::NV21:
544         case PixelFormat::RGBA_8888:
545         case PixelFormat::RGBA_1010102:
546         case PixelFormat::YCBCR_P010:
547         case PixelFormat::YCRCB_P010:
548             externalDecodeFormat_ = externalDecodeFormat;
549             break;
550         default:
551             externalDecodeFormat_ = PixelFormat::UNKNOWN;
552     }
553 }
554 
StartDecoding(const SizeF & dstSize)555 void ImagePattern::StartDecoding(const SizeF& dstSize)
556 {
557     // if layout size has not decided yet, resize target can not be calculated
558     auto host = GetHost();
559     CHECK_NULL_VOID(host);
560     if (!host->GetGeometryNode()->GetContent()) {
561         return;
562     }
563 
564     ACE_SCOPED_TRACE("StartDecoding imageInfo: [%d-%d-%s]", imageDfxConfig_.nodeId_,
565         static_cast<int32_t>(imageDfxConfig_.accessibilityId_), imageDfxConfig_.imageSrc_.c_str());
566 
567     const auto& props = DynamicCast<ImageLayoutProperty>(host->GetLayoutProperty());
568     CHECK_NULL_VOID(props);
569     bool autoResize = props->GetAutoResize().value_or(autoResizeDefault_);
570 
571     ImageFit imageFit = props->GetImageFit().value_or(ImageFit::COVER);
572     const std::optional<SizeF>& sourceSize = props->GetSourceSize();
573     auto renderProp = host->GetPaintProperty<ImageRenderProperty>();
574     bool hasValidSlice = renderProp && (renderProp->HasImageResizableSlice() || renderProp->HasImageResizableLattice());
575     bool isHdrDecoderNeed = renderProp && renderProp->HasDynamicMode();
576 
577     if (loadingCtx_) {
578         loadingCtx_->SetIsHdrDecoderNeed(isHdrDecoderNeed);
579         loadingCtx_->SetImageQuality(GetImageQuality());
580         loadingCtx_->SetPhotoDecodeFormat(GetExternalDecodeFormat());
581         loadingCtx_->MakeCanvasImageIfNeed(dstSize, autoResize, imageFit, sourceSize, hasValidSlice);
582     }
583     if (altLoadingCtx_) {
584         altLoadingCtx_->SetIsHdrDecoderNeed(isHdrDecoderNeed);
585         altLoadingCtx_->SetImageQuality(GetImageQuality());
586         altLoadingCtx_->SetPhotoDecodeFormat(GetExternalDecodeFormat());
587         altLoadingCtx_->MakeCanvasImageIfNeed(dstSize, autoResize, imageFit, sourceSize, hasValidSlice);
588     }
589 }
590 
UpdateSvgSmoothEdgeValue()591 void ImagePattern::UpdateSvgSmoothEdgeValue()
592 {
593     auto renderProp = GetPaintProperty<ImageRenderProperty>();
594     CHECK_NULL_VOID(renderProp);
595     renderProp->UpdateSmoothEdge(std::max(smoothEdge_, renderProp->GetSmoothEdge().value_or(0.0f)));
596 }
597 
SetImagePaintConfig(const RefPtr<CanvasImage> & canvasImage,const RectF & srcRect,const RectF & dstRect,const ImageSourceInfo & sourceInfo,int32_t frameCount)598 void ImagePattern::SetImagePaintConfig(const RefPtr<CanvasImage>& canvasImage, const RectF& srcRect,
599     const RectF& dstRect, const ImageSourceInfo& sourceInfo, int32_t frameCount)
600 {
601     auto layoutProps = GetLayoutProperty<ImageLayoutProperty>();
602     CHECK_NULL_VOID(layoutProps);
603 
604     ImagePaintConfig config {
605         .srcRect_ = srcRect,
606         .dstRect_ = dstRect,
607     };
608     config.imageFit_ = layoutProps->GetImageFit().value_or(ImageFit::COVER);
609     config.isSvg_ = sourceInfo.IsSvg();
610     config.frameCount_ = frameCount;
611     config.orientation_ = joinOrientation_;
612     canvasImage->SetPaintConfig(config);
613 }
614 
CreateNodePaintMethod()615 RefPtr<NodePaintMethod> ImagePattern::CreateNodePaintMethod()
616 {
617     CreateModifier();
618     bool sensitive = false;
619     if (isSensitive_) {
620         auto host = GetHost();
621         CHECK_NULL_RETURN(host, nullptr);
622         sensitive = host->IsPrivacySensitive();
623     }
624     ImagePaintMethodConfig imagePaintMethodConfig { .sensitive = sensitive,
625         .selected = isSelected_,
626         .imageOverlayModifier = overlayMod_,
627         .imageContentModifier = contentMod_,
628         .interpolation = interpolationDefault_ };
629     // Callback function executed after the graphics rendering is complete.
630     auto drawCompleteCallback = [weakPattern = WeakClaim(this)](const RenderedImageInfo& renderedImageInfo) {
631         auto pattern = weakPattern.Upgrade();
632         CHECK_NULL_VOID(pattern);
633         // Mark the rendering as successful on the instance.
634         pattern->SetRenderedImageInfo(std::move(renderedImageInfo));
635     };
636     if (image_) {
637         image_->SetDrawCompleteCallback(std::move(drawCompleteCallback));
638         return MakeRefPtr<ImagePaintMethod>(image_, imagePaintMethodConfig);
639     }
640     if (altImage_ && altDstRect_ && altSrcRect_) {
641         altImage_->SetDrawCompleteCallback(std::move(drawCompleteCallback));
642         return MakeRefPtr<ImagePaintMethod>(altImage_, imagePaintMethodConfig);
643     }
644     CreateObscuredImage();
645     if (obscuredImage_) {
646         obscuredImage_->SetDrawCompleteCallback(std::move(drawCompleteCallback));
647         return MakeRefPtr<ImagePaintMethod>(obscuredImage_, imagePaintMethodConfig);
648     }
649     return MakeRefPtr<ImagePaintMethod>(nullptr, imagePaintMethodConfig);
650 }
651 
CreateModifier()652 void ImagePattern::CreateModifier()
653 {
654     if (!contentMod_) {
655         contentMod_ = MakeRefPtr<ImageContentModifier>(WeakClaim(this));
656     }
657     if (!overlayMod_) {
658         overlayMod_ = MakeRefPtr<ImageOverlayModifier>(selectedColor_);
659     }
660 }
661 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)662 bool ImagePattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
663 {
664     if (!isLayouted_ && GetIsAnimation()) {
665         isLayouted_ = true;
666         if (images_.size()) {
667             int32_t nextIndex = GetNextIndex(nowImageIndex_);
668             for (auto& cacheImage : cacheImages_) {
669                 UpdateCacheImageInfo(cacheImage, nextIndex);
670                 nextIndex = GetNextIndex(nextIndex);
671             }
672         }
673         return false;
674     }
675 
676     if (config.skipMeasure || dirty->SkipMeasureContent()) {
677         return false;
678     }
679 
680     if (imageType_ == ImageType::PIXELMAP_DRAWABLE) {
681         return true;
682     }
683 
684     const auto& dstSize = dirty->GetGeometryNode()->GetContentSize();
685     StartDecoding(dstSize);
686     if (loadingCtx_) {
687         auto renderProp = GetPaintProperty<ImageRenderProperty>();
688         if (renderProp && (renderProp->HasImageResizableSlice() || renderProp->HasImageResizableLattice()) && image_) {
689             loadingCtx_->ResizableCalcDstSize();
690             SetImagePaintConfig(image_, loadingCtx_->GetSrcRect(), loadingCtx_->GetDstRect(), loadingCtx_->GetSrc(),
691                 loadingCtx_->GetFrameCount());
692         }
693     }
694 
695     if (altLoadingCtx_) {
696         auto renderProp = GetPaintProperty<ImageRenderProperty>();
697         if (renderProp && (renderProp->HasImageResizableSlice() || renderProp->HasImageResizableLattice()) &&
698             altImage_) {
699             altLoadingCtx_->ResizableCalcDstSize();
700             SetImagePaintConfig(altImage_, altLoadingCtx_->GetSrcRect(), altLoadingCtx_->GetDstRect(),
701                 altLoadingCtx_->GetSrc(), altLoadingCtx_->GetFrameCount());
702         }
703     }
704 
705     if (IsSupportImageAnalyzerFeature()) {
706         UpdateAnalyzerUIConfig(dirty->GetGeometryNode());
707     }
708 
709     return image_ || altImage_;
710 }
711 
CreateObscuredImage()712 void ImagePattern::CreateObscuredImage()
713 {
714     auto props = GetLayoutProperty<ImageLayoutProperty>();
715     CHECK_NULL_VOID(props);
716     auto layoutConstraint = props->GetLayoutConstraint();
717     CHECK_NULL_VOID(layoutConstraint);
718     auto host = GetHost();
719     CHECK_NULL_VOID(host);
720     auto sourceInfo = props->GetImageSourceInfo().value_or(ImageSourceInfo(""));
721     auto reasons = host->GetRenderContext()->GetObscured().value_or(std::vector<ObscuredReasons>());
722     if (reasons.size() && layoutConstraint->selfIdealSize.IsValid()) {
723         if (!obscuredImage_) {
724             obscuredImage_ = MakeRefPtr<ObscuredImage>();
725             SetImagePaintConfig(obscuredImage_, srcRect_, dstRect_, sourceInfo);
726         }
727     }
728 }
729 
LoadImage(const ImageSourceInfo & src,const PropertyChangeFlag & propertyChangeFlag,VisibleType visibleType)730 void ImagePattern::LoadImage(
731     const ImageSourceInfo& src, const PropertyChangeFlag& propertyChangeFlag, VisibleType visibleType)
732 {
733     if (loadingCtx_) {
734         auto srcKey = src.GetKey();
735         auto loadKey = loadingCtx_->GetSourceInfo().GetKey();
736         isPixelMapChanged_ = srcKey != loadKey;
737     }
738     LoadNotifier loadNotifier(CreateDataReadyCallback(), CreateLoadSuccessCallback(), CreateLoadFailCallback());
739     loadNotifier.onDataReadyComplete_ = CreateCompleteCallBackInDataReady();
740 
741     auto host = GetHost();
742 
743     imageDfxConfig_ = {
744         .nodeId_ = host->GetId(),
745         .accessibilityId_ = host->GetAccessibilityId(),
746         .imageSrc_ = src.ToString().substr(0, MAX_SRC_LENGTH),
747         .isTrimMemRecycle_ = host->IsTrimMemRecycle(),
748     };
749 
750     loadingCtx_ = AceType::MakeRefPtr<ImageLoadingContext>(src, std::move(loadNotifier), syncLoad_, imageDfxConfig_);
751 
752     if (SystemProperties::GetDebugEnabled()) {
753         TAG_LOGI(AceLogTag::ACE_IMAGE, "load image, %{private}s", imageDfxConfig_.ToStringWithSrc().c_str());
754     }
755 
756     if (onProgressCallback_) {
757         loadingCtx_->SetOnProgressCallback(std::move(onProgressCallback_));
758     }
759     if (!((propertyChangeFlag & PROPERTY_UPDATE_LAYOUT) == PROPERTY_UPDATE_LAYOUT) ||
760         visibleType == VisibleType::GONE) {
761         loadingCtx_->FinishMearuse();
762     }
763     // Before loading new image data, reset the render success status to `false`.
764     renderedImageInfo_.renderSuccess = false;
765     // Reset the reload flag before loading the image to ensure a fresh state.
766     isImageReloadNeeded_ = false;
767     loadingCtx_->LoadImageData();
768 }
769 
LoadAltImage(const ImageSourceInfo & altImageSourceInfo)770 void ImagePattern::LoadAltImage(const ImageSourceInfo& altImageSourceInfo)
771 {
772     CHECK_NULL_VOID(GetNeedLoadAlt());
773     LoadNotifier altLoadNotifier(CreateDataReadyCallbackForAlt(), CreateLoadSuccessCallbackForAlt(), nullptr);
774     if (!altLoadingCtx_ || altLoadingCtx_->GetSourceInfo() != altImageSourceInfo ||
775         (altLoadingCtx_ && altImageSourceInfo.IsSvg())) {
776         auto host = GetHost();
777 
778         altImageDfxConfig_ = {
779             .nodeId_ = host->GetId(),
780             .accessibilityId_ = host->GetAccessibilityId(),
781             .imageSrc_ = altImageSourceInfo.ToString().substr(0, MAX_SRC_LENGTH),
782         };
783 
784         altLoadingCtx_ = AceType::MakeRefPtr<ImageLoadingContext>(
785             altImageSourceInfo, std::move(altLoadNotifier), false, altImageDfxConfig_);
786         altLoadingCtx_->LoadImageData();
787     }
788 }
789 
LoadImageDataIfNeed()790 void ImagePattern::LoadImageDataIfNeed()
791 {
792     auto imageLayoutProperty = GetLayoutProperty<ImageLayoutProperty>();
793     CHECK_NULL_VOID(imageLayoutProperty);
794     auto src = imageLayoutProperty->GetImageSourceInfo().value_or(ImageSourceInfo(""));
795     UpdateInternalResource(src);
796 
797     if (!loadingCtx_ || loadingCtx_->GetSourceInfo() != src || isImageReloadNeeded_ || isOrientationChange_) {
798         LoadImage(src, imageLayoutProperty->GetPropertyChangeFlag(),
799             imageLayoutProperty->GetVisibility().value_or(VisibleType::VISIBLE));
800     } else if (IsSupportImageAnalyzerFeature()) {
801         auto host = GetHost();
802         CHECK_NULL_VOID(host);
803         auto context = host->GetContext();
804         CHECK_NULL_VOID(context);
805         auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
806         uiTaskExecutor.PostTask(
807             [weak = WeakClaim(this)] {
808                 auto pattern = weak.Upgrade();
809                 CHECK_NULL_VOID(pattern);
810                 ContainerScope scope(pattern->GetHostInstanceId());
811                 pattern->CreateAnalyzerOverlay();
812                 auto host = pattern->GetHost();
813                 pattern->UpdateAnalyzerUIConfig(host->GetGeometryNode());
814             },
815             "ArkUIImageUpdateAnalyzerUIConfig");
816     }
817     if (loadingCtx_->NeedAlt() && imageLayoutProperty->GetAlt()) {
818         auto altImageSourceInfo = imageLayoutProperty->GetAlt().value_or(ImageSourceInfo(""));
819         LoadAltImage(altImageSourceInfo);
820     }
821 }
822 
UpdateGestureAndDragWhenModify()823 void ImagePattern::UpdateGestureAndDragWhenModify()
824 {
825     // remove long press and mouse events
826     auto host = GetHost();
827     CHECK_NULL_VOID(host);
828 
829     auto gestureHub = host->GetOrCreateGestureEventHub();
830     if (longPressEvent_) {
831         gestureHub->SetLongPressEvent(nullptr);
832         longPressEvent_ = nullptr;
833     }
834 
835     if (clickEvent_) {
836         gestureHub->RemoveClickEvent(clickEvent_);
837         clickEvent_ = nullptr;
838     }
839 
840     if (mouseEvent_) {
841         auto inputHub = host->GetOrCreateInputEventHub();
842         inputHub->RemoveOnMouseEvent(mouseEvent_);
843         mouseEvent_ = nullptr;
844     }
845 
846     enableDrag_ = host->IsDraggable();
847 
848     if (host->IsDraggable()) {
849         EnableDrag();
850     }
851 }
852 
OnModifyDone()853 void ImagePattern::OnModifyDone()
854 {
855     switch (imageType_) {
856         case ImageType::BASE:
857             OnImageModifyDone();
858             break;
859         case ImageType::ANIMATED_DRAWABLE:
860             OnAnimatedModifyDone();
861             break;
862         case ImageType::PIXELMAP_DRAWABLE:
863             OnPixelMapDrawableModifyDone();
864             break;
865         default:
866             break;
867     }
868 
869     InitOnKeyEvent();
870 }
871 
InitOnKeyEvent()872 void ImagePattern::InitOnKeyEvent()
873 {
874     if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_FOURTEEN) || keyEventCallback_) {
875         return;
876     }
877 
878     auto host = GetHost();
879     CHECK_NULL_VOID(host);
880     auto hub = host->GetEventHub<EventHub>();
881     CHECK_NULL_VOID(hub);
882     auto focusHub = hub->GetOrCreateFocusHub();
883     CHECK_NULL_VOID(focusHub);
884     keyEventCallback_ = [weak = WeakClaim(this)](const KeyEvent& event) -> bool {
885         auto pattern = weak.Upgrade();
886         CHECK_NULL_RETURN(pattern, false);
887         pattern->OnKeyEvent();
888         return false;
889     };
890     focusHub->SetOnKeyEventInternal(std::move(keyEventCallback_));
891 }
892 
OnKeyEvent()893 void ImagePattern::OnKeyEvent()
894 {
895     auto host = GetHost();
896     CHECK_NULL_VOID(host);
897     auto focusHub = host->GetFocusHub();
898     CHECK_NULL_VOID(focusHub);
899     focusHub->PaintFocusState(true);
900     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
901 }
902 
OnAnimatedModifyDone()903 void ImagePattern::OnAnimatedModifyDone()
904 {
905     auto host = GetHost();
906     CHECK_NULL_VOID(host);
907     Pattern::OnModifyDone();
908     auto size = static_cast<int32_t>(images_.size());
909     if (size <= 0) {
910         TAG_LOGW(AceLogTag::ACE_IMAGE, "image size is less than 0.");
911         return;
912     }
913     GenerateCachedImages();
914     auto index = nowImageIndex_;
915     if ((status_ == Animator::Status::IDLE || status_ == Animator::Status::STOPPED) && !firstUpdateEvent_) {
916         index = 0;
917     }
918 
919     if (imagesChangedFlag_) {
920         animator_->ClearInterpolators();
921         animator_->AddInterpolator(CreatePictureAnimation(size));
922         AdaptSelfSize();
923         imagesChangedFlag_ = false;
924     }
925     if (firstUpdateEvent_) {
926         firstUpdateEvent_ = false;
927         auto imageFrameNode = AceType::DynamicCast<FrameNode>(host->GetChildren().front());
928         AddImageLoadSuccessEvent(imageFrameNode);
929     }
930     UpdateFormDurationByRemainder();
931     SetObscured();
932     if (isSrcUndefined_) {
933         return;
934     }
935     ControlAnimation(index);
936 }
937 
ControlAnimation(int32_t index)938 void ImagePattern::ControlAnimation(int32_t index)
939 {
940     auto host = GetHost();
941     CHECK_NULL_VOID(host);
942     if (!host->IsOnMainTree()) {
943         return;
944     }
945     if (!animator_->HasScheduler()) {
946         auto context = host->GetContextRefPtr();
947         if (context) {
948             animator_->AttachScheduler(context);
949         } else {
950             TAG_LOGW(AceLogTag::ACE_IMAGE, "pipelineContext is null.");
951         }
952     }
953     switch (status_) {
954         case Animator::Status::IDLE:
955             animator_->Cancel();
956             ResetFormAnimationFlag();
957             SetShowingIndex(index);
958             break;
959         case Animator::Status::PAUSED:
960             animator_->Pause();
961             ResetFormAnimationFlag();
962             break;
963         case Animator::Status::STOPPED:
964             animator_->Finish();
965             ResetFormAnimationFlag();
966             break;
967         default:
968             ResetFormAnimationStartTime();
969             if (isFormAnimationEnd_) {
970                 ResetFormAnimationFlag();
971                 return;
972             }
973             if (host->IsVisible()) {
974                 animator_->Forward();
975             } else {
976                 animator_->Pause();
977             }
978     }
979 }
980 
OnImageModifyDone()981 void ImagePattern::OnImageModifyDone()
982 {
983     Pattern::OnModifyDone();
984     LoadImageDataIfNeed();
985     UpdateGestureAndDragWhenModify();
986     CHECK_EQUAL_VOID(CheckImagePrivacyForCopyOption(), true);
987     CloseSelectOverlay();
988     UpdateOffsetForImageAnalyzerOverlay();
989     SetFrameOffsetForOverlayNode();
990 }
991 
OnPixelMapDrawableModifyDone()992 void ImagePattern::OnPixelMapDrawableModifyDone()
993 {
994     Pattern::OnModifyDone();
995     UpdateGestureAndDragWhenModify();
996     CHECK_EQUAL_VOID(CheckImagePrivacyForCopyOption(), true);
997     CloseSelectOverlay();
998     UpdateOffsetForImageAnalyzerOverlay();
999     SetFrameOffsetForOverlayNode();
1000     // Data loading is not managed by image. Therefore, during component
1001     // attribute initilizationm, the dirty node mark of image needs to
1002     // be registered withe Drawable. Drawable triggers drawing again after
1003     // data loading is complete.
1004     RegisterDrawableRedrawCallback();
1005 }
1006 
RegisterDrawableRedrawCallback()1007 void ImagePattern::RegisterDrawableRedrawCallback()
1008 {
1009     if (isRegisterRedrawCallback_) {
1010         return;
1011     }
1012     CHECK_NULL_VOID(drawable_);
1013     drawable_->RegisterRedrawCallback([weak = WeakClaim(this)] {
1014         auto pattern = weak.Upgrade();
1015         CHECK_NULL_VOID(pattern);
1016         auto context = pattern->GetContext();
1017         CHECK_NULL_VOID(context);
1018         auto taskExecutor = context->GetTaskExecutor();
1019         CHECK_NULL_VOID(taskExecutor);
1020         taskExecutor->PostTask(
1021             [weak = weak] {
1022                 auto pattern = weak.Upgrade();
1023                 CHECK_NULL_VOID(pattern);
1024                 pattern->Validate();
1025             },
1026             TaskExecutor::TaskType::UI, "ArkUIImageDrawableMarkRender");
1027     });
1028     isRegisterRedrawCallback_ = true;
1029 }
1030 
Validate()1031 void ImagePattern::Validate()
1032 {
1033     auto host = GetHost();
1034     CHECK_NULL_VOID(host);
1035     ACE_SCOPED_TRACE("[Drawable][%d] validate callback", host->GetId());
1036     // first mark dirty render
1037     host->MarkNeedRenderOnly();
1038     CHECK_NULL_VOID(contentMod_);
1039     // because drawable is not a drawing attribute of the
1040     // content modifier, redrawing cannot be trigged when
1041     // drawable validates the content modifier. Therefore
1042     // count attribute in the modifier needs to be used to
1043     // forcibly refresh the content modifier.
1044     contentMod_->SetContentChange();
1045 }
1046 
CreatePaintConfig()1047 ImagePaintConfig ImagePattern::CreatePaintConfig()
1048 {
1049     ImagePaintConfig config;
1050     auto lp = GetLayoutProperty<ImageLayoutProperty>();
1051     CHECK_NULL_RETURN(lp, config);
1052     config.imageFit_ = lp->GetImageFit().value_or(ImageFit::COVER);
1053     return config;
1054 }
1055 
DrawDrawable(RSCanvas & canvas)1056 void ImagePattern::DrawDrawable(RSCanvas& canvas)
1057 {
1058     auto host = GetHost();
1059     CHECK_NULL_VOID(host);
1060     ACE_SCOPED_TRACE("[Drawable][%d] draw to canvas", host->GetId());
1061     CHECK_NULL_VOID(drawable_);
1062     auto config = CreatePaintConfig();
1063     drawable_->Draw(canvas, config);
1064 }
1065 
GetImageSizeForMeasure()1066 std::optional<SizeF> ImagePattern::GetImageSizeForMeasure()
1067 {
1068     if ((!loadingCtx_ || !loadingCtx_->GetImageSize().IsPositive()) &&
1069         (!altLoadingCtx_ || !altLoadingCtx_->GetImageSize().IsPositive())) {
1070         return std::nullopt;
1071     }
1072     auto rawImageSize = SizeF(-1.0, -1.0);
1073     if (loadingCtx_) {
1074         rawImageSize = loadingCtx_->GetImageSize();
1075     }
1076     if (rawImageSize.IsNegative() && altLoadingCtx_) {
1077         rawImageSize = altLoadingCtx_->GetImageSize();
1078     }
1079     return std::make_optional<SizeF>(rawImageSize.Width(), rawImageSize.Height());
1080 }
1081 
FinishMeasureForOnComplete()1082 void ImagePattern::FinishMeasureForOnComplete()
1083 {
1084     CHECK_NULL_VOID(loadingCtx_);
1085     loadingCtx_->FinishMearuse();
1086     loadingCtx_->CallbackAfterMeasureIfNeed();
1087 }
1088 
CheckImagePrivacyForCopyOption()1089 bool ImagePattern::CheckImagePrivacyForCopyOption()
1090 {
1091     if (copyOption_ == CopyOptions::None) {
1092         return false;
1093     }
1094     auto host = GetHost();
1095     CHECK_NULL_RETURN(host, false);
1096     bool hasObscured = false;
1097     if (host->GetRenderContext()->GetObscured().has_value()) {
1098         auto obscuredReasons = host->GetRenderContext()->GetObscured().value();
1099         hasObscured = std::any_of(obscuredReasons.begin(), obscuredReasons.end(),
1100             [](const auto& reason) { return reason == ObscuredReasons::PLACEHOLDER; });
1101     }
1102     if (!hasObscured) {
1103         InitCopy();
1104         return true;
1105     }
1106     return false;
1107 }
1108 
UpdateOffsetForImageAnalyzerOverlay()1109 void ImagePattern::UpdateOffsetForImageAnalyzerOverlay()
1110 {
1111     if (imageAnalyzerManager_ && imageAnalyzerManager_->IsOverlayCreated()) {
1112         if (!IsSupportImageAnalyzerFeature()) {
1113             DestroyAnalyzerOverlay();
1114         } else {
1115             UpdateAnalyzerOverlayLayout();
1116         }
1117     }
1118 }
1119 
1120 // SetUsingContentRectForRenderFrame is set for image paint
SetFrameOffsetForOverlayNode()1121 void ImagePattern::SetFrameOffsetForOverlayNode()
1122 {
1123     auto host = GetHost();
1124     CHECK_NULL_VOID(host);
1125     auto overlayNode = host->GetOverlayNode();
1126     if (overlayNode) {
1127         auto layoutProperty = host->GetLayoutProperty();
1128         CHECK_NULL_VOID(layoutProperty);
1129         auto padding = layoutProperty->CreatePaddingAndBorder();
1130         auto renderContext = overlayNode->GetRenderContext();
1131         if (renderContext) {
1132             renderContext->SetRenderFrameOffset({ -padding.Offset().GetX(), -padding.Offset().GetY() });
1133         }
1134     }
1135 }
1136 
CreateDataReadyCallbackForAlt()1137 DataReadyNotifyTask ImagePattern::CreateDataReadyCallbackForAlt()
1138 {
1139     return [weak = WeakClaim(this)](const ImageSourceInfo& sourceInfo) {
1140         auto pattern = weak.Upgrade();
1141         CHECK_NULL_VOID(pattern);
1142         CHECK_NULL_VOID(pattern->altLoadingCtx_);
1143         auto imageLayoutProperty = pattern->GetLayoutProperty<ImageLayoutProperty>();
1144         CHECK_NULL_VOID(imageLayoutProperty);
1145         auto currentAltSourceInfo = imageLayoutProperty->GetAlt().value_or(ImageSourceInfo(""));
1146         if (currentAltSourceInfo != sourceInfo) {
1147             TAG_LOGW(AceLogTag::ACE_IMAGE,
1148                 "alt image sourceInfo does not match, ignore current callback. %{public}s. current: %{private}s vs "
1149                 "callback's: %{private}s",
1150                 pattern->imageDfxConfig_.ToStringWithoutSrc().c_str(), currentAltSourceInfo.ToString().c_str(),
1151                 sourceInfo.ToString().c_str());
1152             return;
1153         }
1154         auto host = pattern->GetHost();
1155         CHECK_NULL_VOID(host);
1156         if (!host->IsActive()) {
1157             return;
1158         }
1159         const auto& geometryNode = host->GetGeometryNode();
1160         CHECK_NULL_VOID(geometryNode);
1161         if (!geometryNode->GetContent()) {
1162             host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1163             return;
1164         }
1165 
1166         // calculate params for [altLoadingCtx] to do [MakeCanvasImage] if component size is already settled
1167         pattern->altLoadingCtx_->MakeCanvasImageIfNeed(
1168             geometryNode->GetContentSize(), true, imageLayoutProperty->GetImageFit().value_or(ImageFit::COVER));
1169     };
1170 }
1171 
CreateLoadSuccessCallbackForAlt()1172 LoadSuccessNotifyTask ImagePattern::CreateLoadSuccessCallbackForAlt()
1173 {
1174     return [weak = WeakClaim(this)](const ImageSourceInfo& sourceInfo) {
1175         auto pattern = weak.Upgrade();
1176         CHECK_NULL_VOID(pattern);
1177         CHECK_NULL_VOID(pattern->altLoadingCtx_);
1178         auto layoutProps = pattern->GetLayoutProperty<ImageLayoutProperty>();
1179         auto currentAltSrc = layoutProps->GetAlt().value_or(ImageSourceInfo(""));
1180         if (currentAltSrc != sourceInfo) {
1181             TAG_LOGW(AceLogTag::ACE_IMAGE,
1182                 "alt image sourceInfo does not match, ignore current callback. %{public}s. current: %{private}s vs "
1183                 "callback's: %{private}s",
1184                 pattern->imageDfxConfig_.ToStringWithoutSrc().c_str(), currentAltSrc.ToString().c_str(),
1185                 sourceInfo.ToString().c_str());
1186             return;
1187         }
1188         pattern->altImage_ = pattern->altLoadingCtx_->MoveCanvasImage();
1189         CHECK_NULL_VOID(pattern->altImage_);
1190         pattern->altImage_->SetImageDfxConfig(pattern->altImageDfxConfig_);
1191         pattern->altSrcRect_ = std::make_unique<RectF>(pattern->altLoadingCtx_->GetSrcRect());
1192         pattern->altDstRect_ = std::make_unique<RectF>(pattern->altLoadingCtx_->GetDstRect());
1193         pattern->SetImagePaintConfig(pattern->altImage_, *pattern->altSrcRect_, *pattern->altDstRect_,
1194             pattern->altLoadingCtx_->GetSourceInfo(), pattern->altLoadingCtx_->GetFrameCount());
1195 
1196         pattern->PrepareAnimation(pattern->altImage_);
1197 
1198         auto host = pattern->GetHost();
1199         CHECK_NULL_VOID(host);
1200         host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1201     };
1202 }
1203 
UpdateInternalResource(ImageSourceInfo & sourceInfo)1204 void ImagePattern::UpdateInternalResource(ImageSourceInfo& sourceInfo)
1205 {
1206     if (!sourceInfo.IsInternalResource()) {
1207         return;
1208     }
1209 
1210     auto pipeline = GetHost()->GetContext();
1211     CHECK_NULL_VOID(pipeline);
1212     auto iconTheme = pipeline->GetTheme<IconTheme>();
1213     CHECK_NULL_VOID(iconTheme);
1214     auto iconPath = iconTheme->GetIconPath(sourceInfo.GetResourceId());
1215     if (!iconPath.empty()) {
1216         sourceInfo.SetSrc(iconPath, sourceInfo.GetFillColor());
1217         auto imageLayoutProperty = GetLayoutProperty<ImageLayoutProperty>();
1218         CHECK_NULL_VOID(imageLayoutProperty);
1219         imageLayoutProperty->UpdateImageSourceInfo(sourceInfo);
1220     }
1221 }
1222 
RecycleImageData()1223 bool ImagePattern::RecycleImageData()
1224 {
1225     // when image component is [onShow] , [no cache], do not clean image data
1226     bool isDataNoCache = (!loadingCtx_ || (loadingCtx_->GetSourceInfo().GetSrcType() == SrcType::NETWORK &&
1227                                               SystemProperties::GetDownloadByNetworkEnabled() &&
1228                                               DownloadManager::GetInstance()->IsContains(
1229                                                   loadingCtx_->GetSourceInfo().GetSrc()) == false));
1230     if (isShow_ || isDataNoCache) {
1231         return false;
1232     }
1233     auto frameNode = GetHost();
1234     if (!frameNode) {
1235         return false;
1236     }
1237     frameNode->SetTrimMemRecycle(true);
1238     loadingCtx_ = nullptr;
1239     auto rsRenderContext = frameNode->GetRenderContext();
1240     if (!rsRenderContext) {
1241         return false;
1242     }
1243     TAG_LOGI(AceLogTag::ACE_IMAGE, "%{public}s, %{private}s recycleImageData.",
1244         imageDfxConfig_.ToStringWithoutSrc().c_str(), imageDfxConfig_.imageSrc_.c_str());
1245     rsRenderContext->RemoveContentModifier(contentMod_);
1246     contentMod_ = nullptr;
1247     image_ = nullptr;
1248     altLoadingCtx_ = nullptr;
1249     altImage_ = nullptr;
1250     ACE_SCOPED_TRACE("OnRecycleImageData imageInfo: [%s]", imageDfxConfig_.ToStringWithSrc().c_str());
1251     return true;
1252 }
1253 
OnNotifyMemoryLevel(int32_t level)1254 void ImagePattern::OnNotifyMemoryLevel(int32_t level)
1255 {
1256     // when image component is [onShow], do not clean image data
1257     if (isShow_ || level < MEMORY_LEVEL_CRITICAL_STATUS) {
1258         return;
1259     }
1260     auto frameNode = GetHost();
1261     CHECK_NULL_VOID(frameNode);
1262     frameNode->SetTrimMemRecycle(false);
1263     auto rsRenderContext = frameNode->GetRenderContext();
1264     CHECK_NULL_VOID(rsRenderContext);
1265     TAG_LOGI(AceLogTag::ACE_IMAGE, "%{public}s, %{private}s OnNotifyMemoryLevel %{public}d.",
1266         imageDfxConfig_.ToStringWithoutSrc().c_str(), imageDfxConfig_.imageSrc_.c_str(), level);
1267     rsRenderContext->RemoveContentModifier(contentMod_);
1268     contentMod_ = nullptr;
1269     loadingCtx_ = nullptr;
1270     image_ = nullptr;
1271     altLoadingCtx_ = nullptr;
1272     altImage_ = nullptr;
1273 }
1274 
1275 // when recycle image component, release the pixelmap resource
OnRecycle()1276 void ImagePattern::OnRecycle()
1277 {
1278     TAG_LOGI(AceLogTag::ACE_IMAGE, "OnRecycle. %{public}s", imageDfxConfig_.ToStringWithoutSrc().c_str());
1279     loadingCtx_ = nullptr;
1280     image_ = nullptr;
1281     altLoadingCtx_ = nullptr;
1282     altImage_ = nullptr;
1283 
1284     auto frameNode = GetHost();
1285     CHECK_NULL_VOID(frameNode);
1286     auto rsRenderContext = frameNode->GetRenderContext();
1287     CHECK_NULL_VOID(rsRenderContext);
1288     rsRenderContext->RemoveContentModifier(contentMod_);
1289     UnregisterWindowStateChangedCallback();
1290     frameNode->SetTrimMemRecycle(false);
1291 }
1292 
OnReuse()1293 void ImagePattern::OnReuse()
1294 {
1295     RegisterWindowStateChangedCallback();
1296     auto renderProp = GetPaintProperty<ImageRenderProperty>();
1297     CHECK_NULL_VOID(renderProp);
1298     renderProp->UpdateNeedBorderRadius(needBorderRadius_);
1299     auto imageLayoutProperty = GetLayoutProperty<ImageLayoutProperty>();
1300     CHECK_NULL_VOID(imageLayoutProperty);
1301     LoadImageDataIfNeed();
1302 }
1303 
RegisterWindowStateChangedCallback()1304 void ImagePattern::RegisterWindowStateChangedCallback()
1305 {
1306     auto host = GetHost();
1307     CHECK_NULL_VOID(host);
1308     auto pipeline = host->GetContext();
1309     CHECK_NULL_VOID(pipeline);
1310     pipeline->AddWindowStateChangedCallback(host->GetId());
1311 }
1312 
UnregisterWindowStateChangedCallback()1313 void ImagePattern::UnregisterWindowStateChangedCallback()
1314 {
1315     auto host = GetHost();
1316     CHECK_NULL_VOID(host);
1317     auto pipeline = host->GetContext();
1318     CHECK_NULL_VOID(pipeline);
1319     pipeline->RemoveWindowStateChangedCallback(host->GetId());
1320 }
1321 
OnWindowHide()1322 void ImagePattern::OnWindowHide()
1323 {
1324     isShow_ = false;
1325 }
1326 
OnWindowShow()1327 void ImagePattern::OnWindowShow()
1328 {
1329     TAG_LOGW(AceLogTag::ACE_IMAGE, "OnWindowShow. %{public}s, isImageReloadNeeded_ = %{public}d",
1330         imageDfxConfig_.ToStringWithoutSrc().c_str(), isImageReloadNeeded_);
1331     isShow_ = true;
1332     auto host = GetHost();
1333     CHECK_NULL_VOID(host);
1334     if (!host->IsTrimMemRecycle()) {
1335         LoadImageDataIfNeed();
1336     }
1337 }
1338 
OnVisibleChange(bool visible)1339 void ImagePattern::OnVisibleChange(bool visible)
1340 {
1341     if (!visible) {
1342         TAG_LOGD(AceLogTag::ACE_IMAGE, "OnInVisible. %{public}s", imageDfxConfig_.ToStringWithoutSrc().c_str());
1343         CloseSelectOverlay();
1344     }
1345 }
1346 
OnVisibleAreaChange(bool visible,double ratio)1347 void ImagePattern::OnVisibleAreaChange(bool visible, double ratio)
1348 {
1349     ACE_SCOPED_TRACE(
1350         "OnVisibleAreaChange visible: [%d], imageInfo: %s", visible, imageDfxConfig_.ToStringWithSrc().c_str());
1351     if (SystemProperties::GetDebugEnabled()) {
1352         TAG_LOGI(AceLogTag::ACE_IMAGE, "OnVisibleAreaChange visible:%{public}d, %{public}s", visible,
1353             imageDfxConfig_.ToStringWithoutSrc().c_str());
1354     }
1355     if (!visible) {
1356         CloseSelectOverlay();
1357     }
1358     // control pixelMap List
1359     if (GetIsAnimation() && !animator_->IsStopped() && animator_->HasScheduler()) {
1360         if (visible) {
1361             animator_->Forward();
1362         } else {
1363             animator_->Pause();
1364         }
1365     }
1366     // control svg / gif animation
1367     if (image_) {
1368         image_->ControlAnimation(visible);
1369     } else if (altImage_) {
1370         altImage_->ControlAnimation(visible);
1371     }
1372 
1373     if (isEnableAnalyzer_) {
1374         auto host = GetHost();
1375         CHECK_NULL_VOID(host);
1376         auto overlayNode = host->GetOverlayNode();
1377         CHECK_NULL_VOID(overlayNode);
1378         TriggerVisibleAreaChangeForChild(overlayNode, visible, ratio);
1379     }
1380 }
1381 
OnAttachToFrameNode()1382 void ImagePattern::OnAttachToFrameNode()
1383 {
1384     auto host = GetHost();
1385     CHECK_NULL_VOID(host);
1386     auto renderCtx = host->GetRenderContext();
1387     CHECK_NULL_VOID(renderCtx);
1388     auto pipeline = host->GetContext();
1389     CHECK_NULL_VOID(pipeline);
1390     if (GetIsAnimation()) {
1391         renderCtx->SetClipToFrame(true);
1392     } else {
1393         renderCtx->SetClipToBounds(false);
1394         renderCtx->SetUsingContentRectForRenderFrame(true);
1395 
1396         // register image frame node to pipeline context to receive memory level notification and window state change
1397         // notification
1398         pipeline->AddNodesToNotifyMemoryLevel(host->GetId());
1399         pipeline->AddWindowStateChangedCallback(host->GetId());
1400     }
1401     auto textTheme = pipeline->GetTheme<TextTheme>();
1402     CHECK_NULL_VOID(textTheme);
1403     selectedColor_ = textTheme->GetSelectedColor();
1404     auto imageTheme = pipeline->GetTheme<ImageTheme>();
1405     CHECK_NULL_VOID(imageTheme);
1406     smoothEdge_ = imageTheme->GetMinEdgeAntialiasing();
1407 }
1408 
OnDetachFromFrameNode(FrameNode * frameNode)1409 void ImagePattern::OnDetachFromFrameNode(FrameNode* frameNode)
1410 {
1411     CloseSelectOverlay();
1412 
1413     auto id = frameNode->GetId();
1414     auto pipeline = AceType::DynamicCast<PipelineContext>(PipelineBase::GetCurrentContext());
1415     CHECK_NULL_VOID(pipeline);
1416     pipeline->RemoveWindowStateChangedCallback(id);
1417     pipeline->RemoveNodesToNotifyMemoryLevel(id);
1418 }
1419 
OnDetachFromMainTree()1420 void ImagePattern::OnDetachFromMainTree()
1421 {
1422     if (isNeedReset_) {
1423         ResetImageAndAlt();
1424         isNeedReset_ = false;
1425     }
1426     if (GetIsAnimation() && !animator_->IsStopped() && animator_->HasScheduler()) {
1427         animator_->Stop();
1428     }
1429 }
1430 
EnableDrag()1431 void ImagePattern::EnableDrag()
1432 {
1433     auto host = GetHost();
1434     CHECK_NULL_VOID(host);
1435     auto dragStart = [weak = WeakClaim(this)](const RefPtr<OHOS::Ace::DragEvent>& event, const std::string&
1436                          /* extraParams */) -> DragDropInfo {
1437         DragDropInfo info;
1438         auto imagePattern = weak.Upgrade();
1439         CHECK_NULL_RETURN(imagePattern && imagePattern->loadingCtx_, info);
1440         AceEngineExt::GetInstance().DragStartExt();
1441         imagePattern->UpdateDragEvent(event);
1442         info.extraInfo = imagePattern->loadingCtx_->GetSourceInfo().GetSrc();
1443         return info;
1444     };
1445     auto eventHub = host->GetEventHub<EventHub>();
1446     CHECK_NULL_VOID(eventHub);
1447     eventHub->SetDefaultOnDragStart(std::move(dragStart));
1448 }
1449 
BetweenSelectedPosition(const Offset & globalOffset)1450 bool ImagePattern::BetweenSelectedPosition(const Offset& globalOffset)
1451 {
1452     auto host = GetHost();
1453     CHECK_NULL_RETURN(host, false);
1454     auto globalRect = host->GetTransformRectRelativeToWindow();
1455     return globalRect.IsInRegion(PointF { globalOffset.GetX(), globalOffset.GetY() });
1456 }
1457 
BeforeCreatePaintWrapper()1458 void ImagePattern::BeforeCreatePaintWrapper()
1459 {
1460     auto host = GetHost();
1461     CHECK_NULL_VOID(host);
1462     host->GetRenderContext()->MarkContentChanged(true);
1463 }
1464 
InitCopy()1465 void ImagePattern::InitCopy()
1466 {
1467     if (longPressEvent_ && mouseEvent_ && clickEvent_) {
1468         return;
1469     }
1470     auto longPressTask = [weak = WeakClaim(this)](GestureEvent& info) {
1471         auto pattern = weak.Upgrade();
1472         CHECK_NULL_VOID(pattern);
1473         pattern->OpenSelectOverlay();
1474     };
1475     longPressEvent_ = MakeRefPtr<LongPressEvent>(std::move(longPressTask));
1476 
1477     auto host = GetHost();
1478     CHECK_NULL_VOID(host);
1479     auto gestureHub = host->GetOrCreateGestureEventHub();
1480     gestureHub->SetLongPressEvent(longPressEvent_);
1481 
1482     auto mouseTask = [weak = WeakClaim(this)](MouseInfo& info) {
1483         if (info.GetButton() == MouseButton::RIGHT_BUTTON && info.GetAction() == MouseAction::PRESS) {
1484             auto pattern = weak.Upgrade();
1485             CHECK_NULL_VOID(pattern);
1486             pattern->OpenSelectOverlay();
1487         }
1488     };
1489     mouseEvent_ = MakeRefPtr<InputEvent>(std::move(mouseTask));
1490     auto inputHub = host->GetOrCreateInputEventHub();
1491     CHECK_NULL_VOID(inputHub);
1492     inputHub->AddOnMouseEvent(mouseEvent_);
1493 
1494     // close overlay on click
1495     clickEvent_ = MakeRefPtr<ClickEvent>([weak = WeakClaim(this)](GestureEvent& callback) {
1496         auto pattern = weak.Upgrade();
1497         CHECK_NULL_VOID(pattern);
1498         pattern->CloseSelectOverlay();
1499     });
1500     gestureHub->AddClickEvent(clickEvent_);
1501 }
1502 
OpenSelectOverlay()1503 void ImagePattern::OpenSelectOverlay()
1504 {
1505     auto host = GetHost();
1506     CHECK_NULL_VOID(host);
1507     const auto& geometryNode = host->GetGeometryNode();
1508     CHECK_NULL_VOID(geometryNode);
1509     auto rect = host->GetTransformRectRelativeToWindow();
1510     SelectOverlayInfo info;
1511     SizeF handleSize = { SelectHandleInfo::GetDefaultLineWidth().ConvertToPx(),
1512         geometryNode->GetContentSize().Height() };
1513     info.firstHandle.paintRect = RectF(rect.GetOffset(), handleSize);
1514     OffsetF offset(rect.Width() - handleSize.Width(), rect.Height() - handleSize.Height());
1515     info.secondHandle.paintRect = RectF(rect.GetOffset() + offset, handleSize);
1516     info.menuInfo.menuIsShow = true;
1517     info.menuInfo.showCut = false;
1518     info.menuInfo.showPaste = false;
1519     info.menuCallback.onCopy = [weak = WeakClaim(this)]() {
1520         auto pattern = weak.Upgrade();
1521         CHECK_NULL_VOID(pattern);
1522         pattern->HandleCopy();
1523         pattern->CloseSelectOverlay();
1524     };
1525     info.onHandleMoveDone = [weak = WeakClaim(this), firstRect = info.firstHandle.paintRect,
1526                                 secondRect = info.secondHandle.paintRect](const RectF&, bool isFirst) {
1527         // reset handle position
1528         auto pattern = weak.Upgrade();
1529         CHECK_NULL_VOID(pattern && pattern->selectOverlay_);
1530         SelectHandleInfo info;
1531         if (isFirst) {
1532             info.paintRect = firstRect;
1533             pattern->selectOverlay_->UpdateFirstSelectHandleInfo(info);
1534         } else {
1535             info.paintRect = secondRect;
1536             pattern->selectOverlay_->UpdateSecondSelectHandleInfo(info);
1537         }
1538     };
1539     info.onClose = [weak = WeakClaim(this)](bool closedByGlobalEvent) {
1540         if (closedByGlobalEvent) {
1541             auto pattern = weak.Upgrade();
1542             CHECK_NULL_VOID(pattern);
1543             pattern->CloseSelectOverlay();
1544         }
1545     };
1546 
1547     auto pipeline = host->GetContext();
1548     CHECK_NULL_VOID(pipeline);
1549     selectOverlay_ = pipeline->GetSelectOverlayManager()->CreateAndShowSelectOverlay(info, WeakClaim(this));
1550     isSelected_ = true;
1551     CHECK_NULL_VOID(selectOverlay_);
1552     pipeline->AddOnAreaChangeNode(host->GetId());
1553     // paint selected mask effect
1554     host->MarkNeedRenderOnly();
1555 }
1556 
CloseSelectOverlay()1557 void ImagePattern::CloseSelectOverlay()
1558 {
1559     if (!selectOverlay_) {
1560         return;
1561     }
1562     if (!selectOverlay_->IsClosed()) {
1563         selectOverlay_->Close();
1564     }
1565     isSelected_ = false;
1566     // remove selected mask effect
1567     auto host = GetHost();
1568     CHECK_NULL_VOID(host);
1569     RemoveAreaChangeInner();
1570     host->MarkNeedRenderOnly();
1571 }
1572 
HandleCopy()1573 void ImagePattern::HandleCopy()
1574 {
1575     CHECK_NULL_VOID(image_);
1576     if (!clipboard_) {
1577         auto host = GetHost();
1578         CHECK_NULL_VOID(host);
1579         auto pipeline = host->GetContext();
1580         CHECK_NULL_VOID(pipeline);
1581         clipboard_ = ClipboardProxy::GetInstance()->GetClipboard(pipeline->GetTaskExecutor());
1582     }
1583     auto pixmap = image_->GetPixelMap();
1584     if (pixmap) {
1585         clipboard_->SetPixelMapData(pixmap, copyOption_);
1586     } else {
1587         auto host = GetHost();
1588         CHECK_NULL_VOID(host);
1589         clipboard_->SetData(loadingCtx_->GetSourceInfo().GetSrc());
1590     }
1591 }
1592 
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const1593 void ImagePattern::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
1594 {
1595     /* no fixed attr below, just return */
1596     if (filter.IsFastFilter()) {
1597         return;
1598     }
1599     static const char* COPY_OPTIONS[] = { "CopyOptions.None", "CopyOptions.InApp", "CopyOptions.Local",
1600         "CopyOptions.Distributed" };
1601     json->PutExtAttr("copyOption", COPY_OPTIONS[static_cast<int32_t>(copyOption_)], filter);
1602 
1603     json->PutExtAttr("syncLoad", syncLoad_ ? "true" : "false", filter);
1604     json->PutExtAttr("draggable", enableDrag_ ? "true" : "false", filter);
1605     json->PutExtAttr("enableAnalyzer", isEnableAnalyzer_ ? "true" : "false", filter);
1606     auto renderProp = GetPaintProperty<ImageRenderProperty>();
1607     CHECK_NULL_VOID(renderProp);
1608     DynamicRangeMode dynamicMode = DynamicRangeMode::STANDARD;
1609     if (renderProp->HasDynamicMode()) {
1610         dynamicMode = renderProp->GetDynamicMode().value_or(DynamicRangeMode::STANDARD);
1611     }
1612     json->PutExtAttr("dynamicRangeMode", GetDynamicModeString(dynamicMode).c_str(), filter);
1613     json->PutExtAttr("orientation", std::to_string(static_cast<int>(userOrientation_)).c_str(), filter);
1614     Matrix4 defaultMatrixValue = Matrix4(1.0f, 0, 0, 0, 0, 1.0f, 0, 0, 0, 0, 1.0f, 0, 0, 0, 0, 1.0f);
1615     Matrix4 matrixValue = renderProp->HasImageMatrix() ? renderProp->GetImageMatrixValue() : defaultMatrixValue;
1616     json->PutExtAttr("imageMatrix", matrixValue.ToString().c_str(), filter);
1617 }
1618 
DumpLayoutInfo()1619 void ImagePattern::DumpLayoutInfo()
1620 {
1621     DumpLog::GetInstance().AddDesc("---- Image Component Layout Dump ----");
1622     auto layoutProp = GetLayoutProperty<ImageLayoutProperty>();
1623     CHECK_NULL_VOID(layoutProp);
1624 
1625     DumpImageSourceInfo(layoutProp);
1626     DumpAltSourceInfo(layoutProp);
1627     DumpImageFit(layoutProp);
1628     DumpFitOriginalSize(layoutProp);
1629     DumpSourceSize(layoutProp);
1630     DumpAutoResize(layoutProp);
1631 }
1632 
DumpImageSourceInfo(const RefPtr<OHOS::Ace::NG::ImageLayoutProperty> & layoutProp)1633 void ImagePattern::DumpImageSourceInfo(const RefPtr<OHOS::Ace::NG::ImageLayoutProperty>& layoutProp)
1634 {
1635     auto src = layoutProp->GetImageSourceInfo().value_or(ImageSourceInfo(""));
1636     DumpLog::GetInstance().AddDesc(std::string("url: ").append(src.ToString()));
1637     DumpLog::GetInstance().AddDesc(
1638         std::string("SrcType: ").append(std::to_string(static_cast<int32_t>(src.GetSrcType()))));
1639     DumpLog::GetInstance().AddDesc(
1640         std::string("AbilityName: ").append(std::to_string(static_cast<int32_t>(Container::CurrentColorMode()))));
1641     DumpLog::GetInstance().AddDesc(std::string("BundleName: ").append(src.GetBundleName()));
1642     DumpLog::GetInstance().AddDesc(std::string("ModuleName: ").append(src.GetModuleName()));
1643     DumpLog::GetInstance().AddDesc(
1644         std::string("ColorMode: ").append(std::to_string(static_cast<int32_t>(Container::CurrentColorMode()))));
1645     DumpLog::GetInstance().AddDesc(
1646         std::string("LocalColorMode: ").append(std::to_string(static_cast<int32_t>(src.GetLocalColorMode()))));
1647 }
1648 
DumpAltSourceInfo(const RefPtr<OHOS::Ace::NG::ImageLayoutProperty> & layoutProp)1649 inline void ImagePattern::DumpAltSourceInfo(const RefPtr<OHOS::Ace::NG::ImageLayoutProperty>& layoutProp)
1650 {
1651     auto altSrc = layoutProp->GetAlt().value_or(ImageSourceInfo(""));
1652     DumpLog::GetInstance().AddDesc(std::string("altUrl: ").append(altSrc.ToString()));
1653 }
1654 
DumpImageFit(const RefPtr<OHOS::Ace::NG::ImageLayoutProperty> & layoutProp)1655 inline void ImagePattern::DumpImageFit(const RefPtr<OHOS::Ace::NG::ImageLayoutProperty>& layoutProp)
1656 {
1657     auto imageFit = layoutProp->GetImageFit().value_or(ImageFit::COVER);
1658     DumpLog::GetInstance().AddDesc(std::string("objectFit: ").append(GetImageFitStr(imageFit)));
1659 }
1660 
DumpFitOriginalSize(const RefPtr<OHOS::Ace::NG::ImageLayoutProperty> & layoutProp)1661 inline void ImagePattern::DumpFitOriginalSize(const RefPtr<OHOS::Ace::NG::ImageLayoutProperty>& layoutProp)
1662 {
1663     auto fitOriginalSize = layoutProp->GetFitOriginalSize().value_or(false);
1664     DumpLog::GetInstance().AddDesc(std::string("fitOriginalSize: ").append(fitOriginalSize ? "true" : "false"));
1665 }
1666 
DumpSourceSize(const RefPtr<OHOS::Ace::NG::ImageLayoutProperty> & layoutProp)1667 inline void ImagePattern::DumpSourceSize(const RefPtr<OHOS::Ace::NG::ImageLayoutProperty>& layoutProp)
1668 {
1669     const std::optional<SizeF>& sourceSize = layoutProp->GetSourceSize();
1670     if (sourceSize.has_value()) {
1671         DumpLog::GetInstance().AddDesc(std::string("sourceSize: ").append(sourceSize.value().ToString()));
1672     }
1673 }
1674 
DumpAutoResize(const RefPtr<OHOS::Ace::NG::ImageLayoutProperty> & layoutProp)1675 inline void ImagePattern::DumpAutoResize(const RefPtr<OHOS::Ace::NG::ImageLayoutProperty>& layoutProp)
1676 {
1677     bool autoResize = layoutProp->GetAutoResize().value_or(autoResizeDefault_);
1678     autoResize ? DumpLog::GetInstance().AddDesc("autoResize:true") : DumpLog::GetInstance().AddDesc("autoResize:false");
1679 }
1680 
DumpRenderInfo()1681 void ImagePattern::DumpRenderInfo()
1682 {
1683     DumpLog::GetInstance().AddDesc("---- Image Component Render Dump ----");
1684     auto renderProp = GetPaintProperty<ImageRenderProperty>();
1685     CHECK_NULL_VOID(renderProp);
1686 
1687     DumpRenderMode(renderProp);
1688     DumpImageRepeat(renderProp);
1689     DumpImageColorFilter(renderProp);
1690     DumpFillColor(renderProp);
1691     DumpDynamicRangeMode(renderProp);
1692     DumpMatchTextDirection(renderProp);
1693     DumpSmoothEdge(renderProp);
1694     DumpBorderRadiusProperties(renderProp);
1695     DumpResizable(renderProp);
1696 }
1697 
DumpRenderMode(const RefPtr<OHOS::Ace::NG::ImageRenderProperty> & renderProp)1698 inline void ImagePattern::DumpRenderMode(const RefPtr<OHOS::Ace::NG::ImageRenderProperty>& renderProp)
1699 {
1700     auto imageRenderMode = renderProp->GetImageRenderMode().value_or(ImageRenderMode::ORIGINAL);
1701     DumpLog::GetInstance().AddDesc(
1702         std::string("renderMode: ").append((imageRenderMode == ImageRenderMode::ORIGINAL) ? "Original" : "Template"));
1703 }
1704 
DumpImageRepeat(const RefPtr<OHOS::Ace::NG::ImageRenderProperty> & renderProp)1705 inline void ImagePattern::DumpImageRepeat(const RefPtr<OHOS::Ace::NG::ImageRenderProperty>& renderProp)
1706 {
1707     auto imageRepeat = renderProp->GetImageRepeat().value_or(ImageRepeat::NO_REPEAT);
1708     DumpLog::GetInstance().AddDesc(std::string("objectRepeat: ").append(GetImageRepeatStr(imageRepeat)));
1709 }
1710 
DumpImageColorFilter(const RefPtr<OHOS::Ace::NG::ImageRenderProperty> & renderProp)1711 inline void ImagePattern::DumpImageColorFilter(const RefPtr<OHOS::Ace::NG::ImageRenderProperty>& renderProp)
1712 {
1713     auto imageColorFilter = renderProp->GetColorFilter();
1714     if (imageColorFilter.has_value()) {
1715         auto colorFilter = imageColorFilter.value();
1716         DumpLog::GetInstance().AddDesc(std::string("colorFilter: ").append(GetImageColorFilterStr(colorFilter)));
1717     }
1718 }
1719 
DumpFillColor(const RefPtr<OHOS::Ace::NG::ImageRenderProperty> & renderProp)1720 inline void ImagePattern::DumpFillColor(const RefPtr<OHOS::Ace::NG::ImageRenderProperty>& renderProp)
1721 {
1722     auto fillColor = renderProp->GetSvgFillColor();
1723     if (fillColor.has_value()) {
1724         auto color = fillColor.value();
1725         DumpLog::GetInstance().AddDesc(std::string("fillColor: ").append(color.ColorToString()));
1726     } else {
1727         DumpLog::GetInstance().AddDesc("fillColor: Null");
1728     }
1729 }
1730 
DumpDynamicRangeMode(const RefPtr<OHOS::Ace::NG::ImageRenderProperty> & renderProp)1731 inline void ImagePattern::DumpDynamicRangeMode(const RefPtr<OHOS::Ace::NG::ImageRenderProperty>& renderProp)
1732 {
1733     DynamicRangeMode dynamicMode = DynamicRangeMode::STANDARD;
1734     if (renderProp->HasDynamicMode()) {
1735         dynamicMode = renderProp->GetDynamicMode().value_or(DynamicRangeMode::STANDARD);
1736         DumpLog::GetInstance().AddDesc(std::string("dynamicRangeMode: ").append(GetDynamicModeString(dynamicMode)));
1737     }
1738 }
1739 
DumpMatchTextDirection(const RefPtr<OHOS::Ace::NG::ImageRenderProperty> & renderProp)1740 inline void ImagePattern::DumpMatchTextDirection(const RefPtr<OHOS::Ace::NG::ImageRenderProperty>& renderProp)
1741 {
1742     auto matchTextDirection = renderProp->GetMatchTextDirection().value_or(false);
1743     matchTextDirection ? DumpLog::GetInstance().AddDesc("matchTextDirection:true")
1744                        : DumpLog::GetInstance().AddDesc("matchTextDirection:false");
1745 }
1746 
DumpSmoothEdge(const RefPtr<OHOS::Ace::NG::ImageRenderProperty> & renderProp)1747 inline void ImagePattern::DumpSmoothEdge(const RefPtr<OHOS::Ace::NG::ImageRenderProperty>& renderProp)
1748 {
1749     auto smoothEdge = renderProp->GetSmoothEdge();
1750     if (smoothEdge.has_value()) {
1751         DumpLog::GetInstance().AddDesc(std::string("edgeAntialiasing: ").append(std::to_string(smoothEdge.value())));
1752     }
1753 }
1754 
DumpResizable(const RefPtr<OHOS::Ace::NG::ImageRenderProperty> & renderProp)1755 inline void ImagePattern::DumpResizable(const RefPtr<OHOS::Ace::NG::ImageRenderProperty>& renderProp)
1756 {
1757     if (renderProp->HasImageResizableSlice() && renderProp->GetImageResizableSliceValue({}).Valid()) {
1758         DumpLog::GetInstance().AddDesc(
1759             std::string("resizable slice: ").append(renderProp->GetImageResizableSliceValue({}).ToString()));
1760     } else {
1761         DumpLog::GetInstance().AddDesc(std::string("resizableSlice: Slice is null"));
1762     }
1763 
1764     auto resizableLattice = renderProp->GetImageResizableLatticeValue(nullptr);
1765     DumpLog::GetInstance().AddDesc(
1766         "resizableLattice:" + (resizableLattice ? resizableLattice->DumpToString() : "Lattice is null"));
1767 }
1768 
DumpBorderRadiusProperties(const RefPtr<OHOS::Ace::NG::ImageRenderProperty> & renderProp)1769 void ImagePattern::DumpBorderRadiusProperties(const RefPtr<OHOS::Ace::NG::ImageRenderProperty>& renderProp)
1770 {
1771     auto needBorderRadius = renderProp->GetNeedBorderRadius().value_or(false);
1772     needBorderRadius ? DumpLog::GetInstance().AddDesc("needBorderRadius:true")
1773                      : DumpLog::GetInstance().AddDesc("needBorderRadius:false");
1774 
1775     auto borderRadius = renderProp->GetBorderRadius().value_or(BorderRadiusProperty());
1776     DumpLog::GetInstance().AddDesc("ImageBorderRadius:" + borderRadius.ToString());
1777 
1778     auto host = GetHost();
1779     CHECK_NULL_VOID(host);
1780     auto renderContext = host->GetRenderContext();
1781     CHECK_NULL_VOID(renderContext);
1782     if (renderContext->HasBorderRadius()) {
1783         DumpLog::GetInstance().AddDesc(
1784             "borderRadius:" + renderContext->GetBorderRadiusValue(BorderRadiusProperty()).ToString());
1785     } else {
1786         DumpLog::GetInstance().AddDesc("borderRadius: null");
1787     }
1788 }
1789 
DumpInterpolation(const RefPtr<OHOS::Ace::NG::ImageRenderProperty> & renderProp)1790 void ImagePattern::DumpInterpolation(const RefPtr<OHOS::Ace::NG::ImageRenderProperty>& renderProp)
1791 {
1792     auto imageInterpolation = renderProp->GetImageInterpolation().value_or(interpolationDefault_);
1793     DumpLog::GetInstance().AddDesc("imageInterpolation:" + GetImageInterpolation(imageInterpolation));
1794 }
1795 
DumpSvgInfo()1796 void ImagePattern::DumpSvgInfo()
1797 {
1798     DumpLog::GetInstance().AddDesc("---- SVG Related Dump ----");
1799     DumpLog::GetInstance().AddDesc("Your SVG related log description here");
1800     auto imageLayoutProperty = GetLayoutProperty<ImageLayoutProperty>();
1801     CHECK_NULL_VOID(imageLayoutProperty);
1802     auto imageSourceInfo = imageLayoutProperty->GetImageSourceInfo();
1803     CHECK_NULL_VOID(imageSourceInfo);
1804     if (!imageSourceInfo->IsSvg() || !loadingCtx_) {
1805         return;
1806     }
1807     auto imageObject = loadingCtx_->GetImageObject();
1808     CHECK_NULL_VOID(imageObject);
1809     DumpLog::GetInstance().AddDesc(std::string("Svg:").append(imageObject->GetDumpInfo()));
1810 }
1811 
DumpOtherInfo()1812 void ImagePattern::DumpOtherInfo()
1813 {
1814     DumpLog::GetInstance().AddDesc("---- Image Component (Excluding Layout and Drawing) Other Info Dump ----");
1815     DumpLog::GetInstance().AddDesc(renderedImageInfo_.ToString());
1816     syncLoad_ ? DumpLog::GetInstance().AddDesc("syncLoad:true") : DumpLog::GetInstance().AddDesc("syncLoad:false");
1817 
1818     if (loadingCtx_) {
1819         auto currentLoadImageState = loadingCtx_->GetCurrentLoadingState();
1820         DumpLog::GetInstance().AddDesc(std::string("currentLoadImageState : ").append(currentLoadImageState));
1821         DumpLog::GetInstance().AddDesc(
1822             std::string("rawImageSize: ").append(loadingCtx_->GetOriginImageSize().ToString()));
1823         DumpLog::GetInstance().AddDesc(std::string("LoadErrorMsg: ").append(loadingCtx_->GetErrorMsg()));
1824     } else {
1825         DumpLog::GetInstance().AddDesc(std::string("imageLoadingContext: null"));
1826     }
1827 
1828     enableDrag_ ? DumpLog::GetInstance().AddDesc("draggable:true") : DumpLog::GetInstance().AddDesc("draggable:false");
1829     DumpLog::GetInstance().AddDesc(
1830         std::string("userOrientation: ").append(ConvertOrientationToString(userOrientation_)));
1831     DumpLog::GetInstance().AddDesc(
1832         std::string("selfOrientation: ").append(ConvertOrientationToString(selfOrientation_)));
1833     DumpLog::GetInstance().AddDesc(std::string("enableAnalyzer: ").append(isEnableAnalyzer_ ? "true" : "false"));
1834 }
1835 
DumpInfo()1836 void ImagePattern::DumpInfo()
1837 {
1838     DumpLayoutInfo();
1839     DumpRenderInfo();
1840     DumpSvgInfo();
1841     DumpOtherInfo();
1842 }
1843 
DumpAdvanceInfo()1844 void ImagePattern::DumpAdvanceInfo()
1845 {
1846     auto layoutProp = GetLayoutProperty<ImageLayoutProperty>();
1847     CHECK_NULL_VOID(layoutProp);
1848     auto src = layoutProp->GetImageSourceInfo().value_or(ImageSourceInfo(""));
1849     DumpLog::GetInstance().AddDesc(std::string("url: ").append(src.ToString()));
1850     syncLoad_ ? DumpLog::GetInstance().AddDesc("syncLoad:true") : DumpLog::GetInstance().AddDesc("syncLoad:false");
1851     if (loadingCtx_) {
1852         auto currentLoadImageState = loadingCtx_->GetCurrentLoadingState();
1853         DumpLog::GetInstance().AddDesc(std::string("currentLoadImageState : ").append(currentLoadImageState));
1854     }
1855 }
1856 
UpdateDragEvent(const RefPtr<OHOS::Ace::DragEvent> & event)1857 void ImagePattern::UpdateDragEvent(const RefPtr<OHOS::Ace::DragEvent>& event)
1858 {
1859     RefPtr<UnifiedData> unifiedData = UdmfClient::GetInstance()->CreateUnifiedData();
1860     if (loadingCtx_ && image_ && loadingCtx_->GetSourceInfo().IsPixmap()) {
1861         auto pixelMap = image_->GetPixelMap();
1862         CHECK_NULL_VOID(pixelMap);
1863         std::vector<uint8_t> data;
1864         if (!pixelMap->GetPixelsVec(data)) {
1865             return;
1866         }
1867         PixelMapRecordDetails details = { pixelMap->GetWidth(), pixelMap->GetHeight(), pixelMap->GetPixelFormat(),
1868             pixelMap->GetAlphaType() };
1869         UdmfClient::GetInstance()->AddPixelMapRecord(unifiedData, data, details);
1870     } else if (loadingCtx_) {
1871         UdmfClient::GetInstance()->AddImageRecord(unifiedData, loadingCtx_->GetSourceInfo().GetSrc());
1872     }
1873     event->SetData(unifiedData);
1874 }
1875 
OnLanguageConfigurationUpdate()1876 void ImagePattern::OnLanguageConfigurationUpdate()
1877 {
1878     CHECK_NULL_VOID(loadingCtx_);
1879     auto&& src = loadingCtx_->GetSourceInfo();
1880     // Resource image needs to reload when Language changes
1881     if (src.GetSrcType() == SrcType::RESOURCE) {
1882         loadingCtx_.Reset();
1883     }
1884     OnConfigurationUpdate();
1885 }
1886 
OnColorConfigurationUpdate()1887 void ImagePattern::OnColorConfigurationUpdate()
1888 {
1889     OnConfigurationUpdate();
1890 }
1891 
OnDirectionConfigurationUpdate()1892 void ImagePattern::OnDirectionConfigurationUpdate()
1893 {
1894     OnConfigurationUpdate();
1895 }
1896 
OnIconConfigurationUpdate()1897 void ImagePattern::OnIconConfigurationUpdate()
1898 {
1899     OnConfigurationUpdate();
1900 }
1901 
OnConfigurationUpdate()1902 void ImagePattern::OnConfigurationUpdate()
1903 {
1904     TAG_LOGD(AceLogTag::ACE_IMAGE, "OnConfigurationUpdate, %{public}s-%{public}d",
1905         imageDfxConfig_.ToStringWithoutSrc().c_str(), loadingCtx_ ? 1 : 0);
1906     CHECK_NULL_VOID(loadingCtx_);
1907     auto imageLayoutProperty = GetLayoutProperty<ImageLayoutProperty>();
1908     auto src = imageLayoutProperty->GetImageSourceInfo().value_or(ImageSourceInfo(""));
1909     UpdateInternalResource(src);
1910 
1911     LoadImage(src, imageLayoutProperty->GetPropertyChangeFlag(),
1912         imageLayoutProperty->GetVisibility().value_or(VisibleType::VISIBLE));
1913     if (loadingCtx_->NeedAlt() && imageLayoutProperty->GetAlt()) {
1914         auto altImageSourceInfo = imageLayoutProperty->GetAlt().value_or(ImageSourceInfo(""));
1915         if (altLoadingCtx_ && altLoadingCtx_->GetSourceInfo() == altImageSourceInfo) {
1916             altLoadingCtx_.Reset();
1917         }
1918         LoadAltImage(altImageSourceInfo);
1919     }
1920 }
1921 
GetImageFitStr(ImageFit value)1922 std::string ImagePattern::GetImageFitStr(ImageFit value)
1923 {
1924     switch (value) {
1925         case ImageFit::CONTAIN:
1926             return "CONTAIN";
1927         case ImageFit::COVER:
1928             return "COVER";
1929         case ImageFit::FILL:
1930             return "FILL";
1931         case ImageFit::FITWIDTH:
1932             return "FITWIDTH";
1933         case ImageFit::FITHEIGHT:
1934             return "FITHEIGHT";
1935         case ImageFit::NONE:
1936             return "NONE";
1937         case ImageFit::SCALE_DOWN:
1938             return "SCALE_DOWN";
1939         case ImageFit::TOP_LEFT:
1940             return "TOP_LEFT";
1941         default:
1942             return "COVER";
1943     }
1944 }
1945 
GetImageRepeatStr(ImageRepeat value)1946 std::string ImagePattern::GetImageRepeatStr(ImageRepeat value)
1947 {
1948     switch (value) {
1949         case ImageRepeat::NO_REPEAT:
1950             return "NO_REPEAT";
1951         case ImageRepeat::REPEAT:
1952             return "REPEAT_XY";
1953         case ImageRepeat::REPEAT_X:
1954             return "REPEAT_X";
1955         case ImageRepeat::REPEAT_Y:
1956             return "REPEAT_Y";
1957         default:
1958             return "NO_REPEAT";
1959     }
1960 }
1961 
GetImageColorFilterStr(const std::vector<float> & colorFilter)1962 std::string ImagePattern::GetImageColorFilterStr(const std::vector<float>& colorFilter)
1963 {
1964     if (colorFilter.empty()) {
1965         return "";
1966     }
1967     std::string result = "[" + std::to_string(colorFilter[0]);
1968     for (uint32_t idx = 1; idx < colorFilter.size(); ++idx) {
1969         result += ", " + std::to_string(colorFilter[idx]);
1970     }
1971     return result + "]";
1972 }
1973 
EnableAnalyzer(bool value)1974 void ImagePattern::EnableAnalyzer(bool value)
1975 {
1976     isEnableAnalyzer_ = value;
1977     if (!isEnableAnalyzer_) {
1978         DestroyAnalyzerOverlay();
1979         return;
1980     }
1981 
1982     if (!imageAnalyzerManager_) {
1983         imageAnalyzerManager_ = std::make_shared<ImageAnalyzerManager>(GetHost(), ImageAnalyzerHolder::IMAGE);
1984     }
1985     RegisterVisibleAreaChange(true);
1986 }
1987 
1988 // As an example
SetImageAnalyzerConfig(const ImageAnalyzerConfig & config)1989 void ImagePattern::SetImageAnalyzerConfig(const ImageAnalyzerConfig& config)
1990 {
1991     if (!isEnableAnalyzer_) {
1992         return;
1993     }
1994 }
1995 
SetImageAnalyzerConfig(void * config)1996 void ImagePattern::SetImageAnalyzerConfig(void* config)
1997 {
1998     if (isEnableAnalyzer_) {
1999         CHECK_NULL_VOID(imageAnalyzerManager_);
2000         imageAnalyzerManager_->SetImageAnalyzerConfig(config);
2001     }
2002 }
2003 
SetImageAIOptions(void * options)2004 void ImagePattern::SetImageAIOptions(void* options)
2005 {
2006     if (!imageAnalyzerManager_) {
2007         imageAnalyzerManager_ = std::make_shared<ImageAnalyzerManager>(GetHost(), ImageAnalyzerHolder::IMAGE);
2008     }
2009     CHECK_NULL_VOID(imageAnalyzerManager_);
2010     imageAnalyzerManager_->SetImageAIOptions(options);
2011 }
2012 
IsSupportImageAnalyzerFeature()2013 bool ImagePattern::IsSupportImageAnalyzerFeature()
2014 {
2015     CHECK_NULL_RETURN(imageAnalyzerManager_, false);
2016     return isEnableAnalyzer_ && image_ && !loadingCtx_->GetSourceInfo().IsSvg() && loadingCtx_->GetFrameCount() <= 1 &&
2017            imageAnalyzerManager_->IsSupportImageAnalyzerFeature();
2018 }
2019 
CreateAnalyzerOverlay()2020 void ImagePattern::CreateAnalyzerOverlay()
2021 {
2022     CHECK_NULL_VOID(imageAnalyzerManager_);
2023     if (imageAnalyzerManager_->IsOverlayCreated()) {
2024         return;
2025     }
2026 
2027     CHECK_NULL_VOID(image_);
2028     auto pixelMap = image_->GetPixelMap();
2029     CHECK_NULL_VOID(pixelMap);
2030     imageAnalyzerManager_->CreateAnalyzerOverlay(pixelMap);
2031 }
2032 
UpdateAnalyzerOverlay()2033 void ImagePattern::UpdateAnalyzerOverlay()
2034 {
2035     CHECK_NULL_VOID(imageAnalyzerManager_);
2036     if (!IsSupportImageAnalyzerFeature() || !imageAnalyzerManager_->IsOverlayCreated()) {
2037         return;
2038     }
2039 
2040     CHECK_NULL_VOID(image_);
2041     auto pixelMap = image_->GetPixelMap();
2042     CHECK_NULL_VOID(pixelMap);
2043     imageAnalyzerManager_->UpdateAnalyzerOverlay(pixelMap);
2044 }
2045 
UpdateAnalyzerOverlayLayout()2046 void ImagePattern::UpdateAnalyzerOverlayLayout()
2047 {
2048     CHECK_NULL_VOID(imageAnalyzerManager_);
2049     imageAnalyzerManager_->UpdateAnalyzerOverlayLayout();
2050 }
2051 
DestroyAnalyzerOverlay()2052 void ImagePattern::DestroyAnalyzerOverlay()
2053 {
2054     CHECK_NULL_VOID(imageAnalyzerManager_);
2055     imageAnalyzerManager_->DestroyAnalyzerOverlay();
2056 }
2057 
ReleaseImageAnalyzer()2058 void ImagePattern::ReleaseImageAnalyzer()
2059 {
2060     CHECK_NULL_VOID(imageAnalyzerManager_);
2061     imageAnalyzerManager_->ReleaseImageAnalyzer();
2062 }
2063 
UpdateAnalyzerUIConfig(const RefPtr<NG::GeometryNode> & geometryNode)2064 void ImagePattern::UpdateAnalyzerUIConfig(const RefPtr<NG::GeometryNode>& geometryNode)
2065 {
2066     CHECK_NULL_VOID(imageAnalyzerManager_);
2067     imageAnalyzerManager_->UpdateAnalyzerUIConfig(geometryNode);
2068 }
2069 
AllowVisibleAreaCheck() const2070 bool ImagePattern::AllowVisibleAreaCheck() const
2071 {
2072     auto frameNode = GetHost();
2073     CHECK_NULL_RETURN(frameNode, false);
2074     RefPtr<FrameNode> parentUi = frameNode->GetAncestorNodeOfFrame(true);
2075     while (parentUi) {
2076         auto layoutProperty = parentUi->GetLayoutProperty();
2077         if (layoutProperty && layoutProperty->IsOverlayNode()) {
2078             return true;
2079         }
2080         parentUi = parentUi->GetAncestorNodeOfFrame(true);
2081     }
2082     return false;
2083 }
2084 
InitDefaultValue()2085 void ImagePattern::InitDefaultValue()
2086 {
2087     // add API version protection
2088     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
2089         autoResizeDefault_ = false;
2090         interpolationDefault_ = ImageInterpolation::LOW;
2091     }
2092     auto container = Container::Current();
2093     // If the default value is set to false, the ScenceBoard memory increases.
2094     // Therefore the default value is different in the ScenceBoard.
2095     if (container && container->IsScenceBoardWindow()) {
2096         autoResizeDefault_ = true;
2097         interpolationDefault_ = ImageInterpolation::NONE;
2098     }
2099 }
2100 
hasSceneChanged()2101 bool ImagePattern::hasSceneChanged()
2102 {
2103     auto imageLayoutProperty = GetLayoutProperty<ImageLayoutProperty>();
2104     CHECK_NULL_RETURN(imageLayoutProperty, false);
2105     auto src = imageLayoutProperty->GetImageSourceInfo().value_or(ImageSourceInfo(""));
2106     UpdateInternalResource(src);
2107     return true;
2108 }
2109 
ImageAnimatorPattern()2110 void ImagePattern::ImageAnimatorPattern()
2111 {
2112     animator_ = CREATE_ANIMATOR();
2113     animator_->SetFillMode(FillMode::BACKWARDS);
2114     animator_->SetDuration(DEFAULT_DURATION);
2115     ResetFormAnimationFlag();
2116 }
2117 
CreatePictureAnimation(int32_t size)2118 RefPtr<PictureAnimation<int32_t>> ImagePattern::CreatePictureAnimation(int32_t size)
2119 {
2120     auto pictureAnimation = MakeRefPtr<PictureAnimation<int32_t>>();
2121     if (durationTotal_ > 0) {
2122         for (int32_t index = 0; index < size; ++index) {
2123             pictureAnimation->AddPicture(images_[index].duration / static_cast<float>(durationTotal_), index);
2124         }
2125         animator_->SetDuration(durationTotal_);
2126     } else {
2127         for (int32_t index = 0; index < size; ++index) {
2128             pictureAnimation->AddPicture(NORMALIZED_DURATION_MAX / static_cast<float>(size), index);
2129         }
2130     }
2131 
2132     pictureAnimation->AddListener([weak = WeakClaim(this)](int32_t index) {
2133         auto imageAnimator = weak.Upgrade();
2134         CHECK_NULL_VOID(imageAnimator);
2135         imageAnimator->SetShowingIndex(index);
2136     });
2137     return pictureAnimation;
2138 }
2139 
SetShowingIndex(int32_t index)2140 void ImagePattern::SetShowingIndex(int32_t index)
2141 {
2142     auto host = GetHost();
2143     CHECK_NULL_VOID(host);
2144     auto imageFrameNode = AceType::DynamicCast<FrameNode>(host->GetChildren().front());
2145     CHECK_NULL_VOID(imageFrameNode);
2146     auto imageLayoutProperty = imageFrameNode->GetLayoutProperty<ImageLayoutProperty>();
2147     CHECK_NULL_VOID(imageLayoutProperty);
2148     if (index >= static_cast<int32_t>(images_.size())) {
2149         TAG_LOGW(AceLogTag::ACE_IMAGE, "ImageAnimator update index error, index: %{public}d, size: %{public}zu", index,
2150             images_.size());
2151         return;
2152     }
2153     CHECK_NULL_VOID(images_[index].pixelMap);
2154     nowImageIndex_ = index;
2155     auto cacheImageIter = FindCacheImageNode(images_[index].pixelMap);
2156     if (IsShowingSrc(imageFrameNode, images_[index].pixelMap)) {
2157         ACE_SCOPED_TRACE("ImageAnimator same src %s, index %d", "PixelMap", index);
2158         UpdateShowingImageInfo(imageFrameNode, index);
2159     } else if (cacheImageIter == cacheImages_.end()) {
2160         ACE_SCOPED_TRACE("ImageAnimator no cache found, src %s, index %d", "PixelMap", index);
2161         UpdateShowingImageInfo(imageFrameNode, index);
2162     } else if (cacheImageIter->isLoaded) {
2163         ACE_SCOPED_TRACE("ImageAnimator useCache src %s, index %d", "PixelMap", index);
2164         auto cacheImageNode = cacheImageIter->imageNode;
2165         host->RemoveChild(imageFrameNode);
2166         host->AddChild(cacheImageNode, DEFAULT_NODE_SLOT, true);
2167         host->RebuildRenderContextTree();
2168         cacheImages_.erase(cacheImageIter);
2169         CacheImageStruct newCacheImageStruct(imageFrameNode);
2170         newCacheImageStruct.isLoaded = true;
2171         cacheImages_.emplace_back(newCacheImageStruct);
2172         UpdateShowingImageInfo(cacheImageNode, index);
2173     } else {
2174         UpdateShowingImageInfo(imageFrameNode, index);
2175         // wait for cache image loading
2176         ACE_SCOPED_TRACE("ImageAnimator waitForCache src %s, index %d", "PixelMap", index);
2177     }
2178     // update cache images
2179     CHECK_NULL_VOID(cacheImages_.size());
2180     int32_t nextIndex = GetNextIndex(index);
2181     for (auto& cacheImage : cacheImages_) {
2182         UpdateCacheImageInfo(cacheImage, nextIndex);
2183         nextIndex = GetNextIndex(nextIndex);
2184     }
2185     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
2186 }
2187 
UpdateShowingImageInfo(const RefPtr<FrameNode> & imageFrameNode,int32_t index)2188 void ImagePattern::UpdateShowingImageInfo(const RefPtr<FrameNode>& imageFrameNode, int32_t index)
2189 {
2190     auto host = GetHost();
2191     CHECK_NULL_VOID(host);
2192     auto layoutProperty = host->GetLayoutProperty<ImageLayoutProperty>();
2193     CHECK_NULL_VOID(layoutProperty);
2194     auto imageLayoutProperty = imageFrameNode->GetLayoutProperty<ImageLayoutProperty>();
2195     CHECK_NULL_VOID(imageLayoutProperty);
2196 
2197     imageLayoutProperty->UpdateImageSourceInfo(ImageSourceInfo(images_[index].pixelMap));
2198     SetColorFilter(imageFrameNode);
2199     SetImageFit(imageFrameNode);
2200     // use the size of first pixelmap when no size is set
2201     auto&& layoutConstraint = layoutProperty->GetCalcLayoutConstraint();
2202     if (!layoutConstraint || !layoutConstraint->selfIdealSize.has_value()) {
2203         CalcSize realSize = { CalcLength(images_[0].pixelMap->GetWidth()),
2204             CalcLength(images_[0].pixelMap->GetHeight()) };
2205         imageLayoutProperty->UpdateUserDefinedIdealSize(realSize);
2206         imageLayoutProperty->UpdateMeasureType(MeasureType::MATCH_CONTENT);
2207         imageFrameNode->MarkModifyDone();
2208         imageFrameNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
2209         return;
2210     }
2211     MarginProperty margin;
2212     margin.SetEdges(CalcLength(0.0));
2213     imageLayoutProperty->UpdateMargin(margin);
2214     imageLayoutProperty->ClearUserDefinedIdealSize(true, true);
2215     imageLayoutProperty->UpdateMeasureType(MeasureType::MATCH_PARENT);
2216     imageFrameNode->MarkModifyDone();
2217     imageFrameNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
2218 }
2219 
UpdateCacheImageInfo(CacheImageStruct & cacheImage,int32_t index)2220 void ImagePattern::UpdateCacheImageInfo(CacheImageStruct& cacheImage, int32_t index)
2221 {
2222     if (index >= static_cast<int32_t>(images_.size())) {
2223         TAG_LOGW(AceLogTag::ACE_IMAGE, "PrepareImageInfo index error, index: %{public}d, size: %{public}zu", index,
2224             images_.size());
2225         return;
2226     }
2227     auto host = GetHost();
2228     CHECK_NULL_VOID(host);
2229     auto layoutProperty = host->GetLayoutProperty<ImageLayoutProperty>();
2230     CHECK_NULL_VOID(layoutProperty);
2231     auto imageLayoutProperty = cacheImage.imageNode->GetLayoutProperty<ImageLayoutProperty>();
2232     CHECK_NULL_VOID(imageLayoutProperty);
2233     CHECK_NULL_VOID(images_[index].pixelMap);
2234     // pixelmap
2235     if (imageLayoutProperty->HasImageSourceInfo()) {
2236         auto preSrc = imageLayoutProperty->GetImageSourceInfoValue().GetPixmap();
2237         if (preSrc != images_[index].pixelMap) {
2238             // need to cache newImage
2239             imageLayoutProperty->UpdateImageSourceInfo(ImageSourceInfo(images_[index].pixelMap));
2240             cacheImage.index = index;
2241             cacheImage.isLoaded = false;
2242         }
2243     }
2244     SetColorFilter(cacheImage.imageNode);
2245     SetImageFit(cacheImage.imageNode);
2246     // use the size of first pixelmap when no size is set
2247     auto&& layoutConstraint = layoutProperty->GetCalcLayoutConstraint();
2248     if (!layoutConstraint || !layoutConstraint->selfIdealSize.has_value()) {
2249         CalcSize realSize = { CalcLength(images_[0].pixelMap->GetWidth()),
2250             CalcLength(images_[0].pixelMap->GetHeight()) };
2251         imageLayoutProperty->UpdateUserDefinedIdealSize(realSize);
2252         cacheImage.imageNode->MarkModifyDone();
2253         return;
2254     }
2255     auto hostSize = host->GetGeometryNode()->GetPaddingSize();
2256     if (!hostSize.IsPositive()) {
2257         // if imageNode size is nonPositive, no pixelMap will be generated. Wait for size.
2258         return;
2259     }
2260     imageLayoutProperty->UpdateUserDefinedIdealSize(
2261         CalcSize(CalcLength(hostSize.Width()), CalcLength(hostSize.Height())));
2262     cacheImage.imageNode->MarkModifyDone();
2263 }
2264 
FindCacheImageNode(const RefPtr<PixelMap> & src)2265 std::list<ImagePattern::CacheImageStruct>::iterator ImagePattern::FindCacheImageNode(const RefPtr<PixelMap>& src)
2266 {
2267     for (auto iter = cacheImages_.begin(); iter != cacheImages_.end(); ++iter) {
2268         if (IsShowingSrc(iter->imageNode, src)) {
2269             return iter;
2270         }
2271     }
2272     return cacheImages_.end();
2273 }
2274 
GenerateCachedImages()2275 void ImagePattern::GenerateCachedImages()
2276 {
2277     CHECK_NULL_VOID(images_.size());
2278     auto averageShowTime = static_cast<uint32_t>(animator_->GetDuration()) / images_.size();
2279     size_t cacheImageNum = averageShowTime >= CRITICAL_TIME ? 1 : 2;
2280     cacheImageNum = std::min(images_.size() - 1, cacheImageNum);
2281     if (cacheImages_.size() > cacheImageNum) {
2282         cacheImages_.resize(cacheImageNum);
2283         return;
2284     }
2285     while (cacheImages_.size() < cacheImageNum) {
2286         auto imageNode = FrameNode::CreateFrameNode(V2::IMAGE_ETS_TAG, -1, AceType::MakeRefPtr<ImagePattern>());
2287         auto imageLayoutProperty = imageNode->GetLayoutProperty();
2288         imageLayoutProperty->UpdateMeasureType(MeasureType::MATCH_PARENT);
2289         imageLayoutProperty->UpdateAlignment(Alignment::TOP_LEFT);
2290         AddImageLoadSuccessEvent(imageNode);
2291         cacheImages_.emplace_back(CacheImageStruct(imageNode));
2292     }
2293 }
2294 
AdaptSelfSize()2295 void ImagePattern::AdaptSelfSize()
2296 {
2297     auto host = GetHost();
2298     CHECK_NULL_VOID(host);
2299     const auto& layoutProperty = host->GetLayoutProperty();
2300     CHECK_NULL_VOID(layoutProperty);
2301     if (layoutProperty->GetCalcLayoutConstraint() && layoutProperty->GetCalcLayoutConstraint()->selfIdealSize &&
2302         layoutProperty->GetCalcLayoutConstraint()->selfIdealSize->IsValid()) {
2303         return;
2304     }
2305     if (images_.empty()) {
2306         return;
2307     }
2308     CHECK_NULL_VOID(images_[0].pixelMap);
2309     hasSizeChanged = true;
2310     CalcSize realSize = { CalcLength(images_[0].pixelMap->GetWidth()), CalcLength(images_[0].pixelMap->GetHeight()) };
2311 
2312     const auto& layoutConstraint = layoutProperty->GetCalcLayoutConstraint();
2313     if (!layoutConstraint || !layoutConstraint->selfIdealSize) {
2314         layoutProperty->UpdateUserDefinedIdealSize(realSize);
2315         return;
2316     }
2317     if (!layoutConstraint->selfIdealSize->Width()) {
2318         layoutProperty->UpdateUserDefinedIdealSize(CalcSize(CalcLength(images_[0].pixelMap->GetWidth()), std::nullopt));
2319         return;
2320     }
2321     layoutProperty->UpdateUserDefinedIdealSize(CalcSize(std::nullopt, CalcLength(images_[0].pixelMap->GetHeight())));
2322 }
2323 
GetNextIndex(int32_t preIndex)2324 int32_t ImagePattern::GetNextIndex(int32_t preIndex)
2325 {
2326     return (preIndex + 1) % static_cast<int32_t>(images_.size());
2327 }
2328 
AddImageLoadSuccessEvent(const RefPtr<FrameNode> & imageFrameNode)2329 void ImagePattern::AddImageLoadSuccessEvent(const RefPtr<FrameNode>& imageFrameNode)
2330 {
2331     CHECK_NULL_VOID(imageFrameNode);
2332     auto eventHub = imageFrameNode->GetEventHub<ImageEventHub>();
2333     eventHub->SetOnComplete(
2334         [weakImage = WeakPtr<FrameNode>(imageFrameNode), weak = WeakClaim(this)](const LoadImageSuccessEvent& info) {
2335             if (info.GetLoadingStatus() != 1) {
2336                 // status 1 means load success. Only need loadSuccess event.
2337                 return;
2338             }
2339             auto pattern = weak.Upgrade();
2340             CHECK_NULL_VOID(pattern);
2341             auto cacheImageNode = weakImage.Upgrade();
2342             CHECK_NULL_VOID(cacheImageNode);
2343             auto imageAnimator = pattern->GetHost();
2344             CHECK_NULL_VOID(imageAnimator);
2345             auto cacheLayoutProperty = cacheImageNode->GetLayoutProperty<ImageLayoutProperty>();
2346             auto cacheSrc = cacheLayoutProperty->GetImageSourceInfoValue(ImageSourceInfo()).GetSrc();
2347             ACE_SCOPED_TRACE("ImageAnimator cache succeed. src %s", cacheSrc.c_str());
2348             auto iter = std::find_if(pattern->cacheImages_.begin(), pattern->cacheImages_.end(),
2349                 [&cacheImageNode](const CacheImageStruct& other) { return other.imageNode == cacheImageNode; });
2350             if (iter == pattern->cacheImages_.end()) {
2351                 return;
2352             }
2353             iter->isLoaded = true;
2354             if (pattern->nowImageIndex_ >= static_cast<int32_t>(pattern->images_.size())) {
2355                 TAG_LOGW(AceLogTag::ACE_IMAGE, "ImageAnimator showImage index is invalid");
2356                 return;
2357             }
2358             if (pattern->nowImageIndex_ == iter->index &&
2359                 IsShowingSrc(cacheImageNode, pattern->images_[pattern->nowImageIndex_].pixelMap)) {
2360                 pattern->SetShowingIndex(pattern->nowImageIndex_);
2361             }
2362         });
2363 }
2364 
IsShowingSrc(const RefPtr<FrameNode> & imageFrameNode,const RefPtr<PixelMap> & src)2365 bool ImagePattern::IsShowingSrc(const RefPtr<FrameNode>& imageFrameNode, const RefPtr<PixelMap>& src)
2366 {
2367     auto imageLayoutProperty = imageFrameNode->GetLayoutProperty<ImageLayoutProperty>();
2368     return imageLayoutProperty->HasImageSourceInfo() &&
2369            imageLayoutProperty->GetImageSourceInfoValue().GetPixmap() == src;
2370 }
2371 
IsFormRender()2372 bool ImagePattern::IsFormRender()
2373 {
2374     auto pipeline = PipelineBase::GetCurrentContext();
2375     CHECK_NULL_RETURN(pipeline, false);
2376 
2377     auto container = Container::Current();
2378     bool isDynamicComponent =
2379         container && container->IsDynamicRender() && container->GetUIContentType() == UIContentType::DYNAMIC_COMPONENT;
2380     return pipeline->IsFormRender() && !isDynamicComponent;
2381 }
2382 
UpdateFormDurationByRemainder()2383 void ImagePattern::UpdateFormDurationByRemainder()
2384 {
2385     if (IsFormRender()) {
2386         if (!isFormAnimationStart_) {
2387             formAnimationRemainder_ =
2388                 DEFAULT_DURATION - (GetMicroTickCount() - formAnimationStartTime_) / MICROSEC_TO_MILLISEC;
2389         }
2390         if ((formAnimationRemainder_ > 0) && (animator_->GetDuration() > formAnimationRemainder_)) {
2391             animator_->SetDuration(formAnimationRemainder_);
2392         }
2393         if (formAnimationRemainder_ <= 0) {
2394             isFormAnimationEnd_ = true;
2395         }
2396     }
2397 }
2398 
ResetFormAnimationStartTime()2399 void ImagePattern::ResetFormAnimationStartTime()
2400 {
2401     if (isFormAnimationStart_) {
2402         isFormAnimationStart_ = false;
2403         formAnimationStartTime_ = GetMicroTickCount();
2404     }
2405 }
2406 
ResetFormAnimationFlag()2407 void ImagePattern::ResetFormAnimationFlag()
2408 {
2409     if (IsFormRender()) {
2410         formAnimationRemainder_ = DEFAULT_DURATION;
2411         isFormAnimationStart_ = true;
2412         isFormAnimationEnd_ = false;
2413     }
2414 }
2415 
SetIteration(int32_t iteration)2416 void ImagePattern::SetIteration(int32_t iteration)
2417 {
2418     if (iteration < -1) {
2419         return;
2420     }
2421     if (IsFormRender()) {
2422         iteration = DEFAULT_ITERATIONS;
2423     }
2424     animator_->SetIteration(iteration);
2425 }
2426 
SetDuration(int32_t duration)2427 void ImagePattern::SetDuration(int32_t duration)
2428 {
2429     if (duration < 0) {
2430         return;
2431     }
2432     int32_t finalDuration = durationTotal_ > 0 ? durationTotal_ : duration;
2433     if (IsFormRender()) {
2434         finalDuration = finalDuration < DEFAULT_DURATION ? finalDuration : DEFAULT_DURATION;
2435     }
2436     if (animator_->GetDuration() == finalDuration) {
2437         animator_->RemoveRepeatListener(repeatCallbackId_);
2438         return;
2439     }
2440     if (animator_->GetStatus() == Animator::Status::IDLE || animator_->GetStatus() == Animator::Status::STOPPED) {
2441         animator_->SetDuration(finalDuration);
2442         animator_->RemoveRepeatListener(repeatCallbackId_);
2443         return;
2444     }
2445     // if animator is running or paused, duration will work next time
2446     animator_->RemoveRepeatListener(repeatCallbackId_);
2447     repeatCallbackId_ = animator_->AddRepeatListener([weak = WeakClaim(this), finalDuration]() {
2448         auto imageAnimator = weak.Upgrade();
2449         CHECK_NULL_VOID(imageAnimator);
2450         imageAnimator->animator_->SetDuration(finalDuration);
2451     });
2452 }
2453 
SetOnProgressCallback(std::function<void (const uint32_t & dlNow,const uint32_t & dlTotal)> && onProgress)2454 void ImagePattern::SetOnProgressCallback(
2455     std::function<void(const uint32_t& dlNow, const uint32_t& dlTotal)>&& onProgress)
2456 {
2457     onProgressCallback_ = onProgress;
2458 }
2459 
OnSensitiveStyleChange(bool isSensitive)2460 void ImagePattern::OnSensitiveStyleChange(bool isSensitive)
2461 {
2462     auto host = GetHost();
2463     CHECK_NULL_VOID(host);
2464     auto privacySensitive = host->IsPrivacySensitive();
2465     if (isSensitive && privacySensitive) {
2466         isSensitive_ = true;
2467         auto renderContext = host->GetRenderContext();
2468         CHECK_NULL_VOID(renderContext);
2469         CalcDimension radius;
2470         radius.SetValue(IMAGE_SENSITIVE_RADIUS);
2471         Color color = Color::FromARGB(13, 255, 255, 255);
2472         EffectOption option = { radius, IMAGE_SENSITIVE_SATURATION, IMAGE_SENSITIVE_BRIGHTNESS, color };
2473         if (renderContext->GetBackBlurRadius().has_value()) {
2474             renderContext->UpdateBackBlurRadius(Dimension());
2475         }
2476         if (renderContext->GetBackBlurStyle().has_value()) {
2477             renderContext->UpdateBackBlurStyle(std::nullopt);
2478         }
2479         renderContext->UpdateBackgroundEffect(option);
2480     } else {
2481         isSensitive_ = false;
2482     }
2483     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
2484 }
2485 
ResetImageProperties()2486 void ImagePattern::ResetImageProperties()
2487 {
2488     SetCopyOption(CopyOptions::None);
2489     OnImageModifyDone();
2490 }
2491 
ResetImage()2492 void ImagePattern::ResetImage()
2493 {
2494     image_ = nullptr;
2495     imageQuality_ = AIImageQuality::NONE;
2496     isImageReloadNeeded_ = false;
2497     loadingCtx_.Reset();
2498     auto host = GetHost();
2499     CHECK_NULL_VOID(host);
2500     if (!altImage_) {
2501         auto rsRenderContext = host->GetRenderContext();
2502         CHECK_NULL_VOID(rsRenderContext);
2503         TAG_LOGI(AceLogTag::ACE_IMAGE, "%{public}s, %{private}s ResetImage.",
2504             imageDfxConfig_.ToStringWithoutSrc().c_str(), imageDfxConfig_.imageSrc_.c_str());
2505         rsRenderContext->RemoveContentModifier(contentMod_);
2506         contentMod_ = nullptr;
2507     }
2508     host->SetTrimMemRecycle(false);
2509 }
2510 
ResetAltImage()2511 void ImagePattern::ResetAltImage()
2512 {
2513     altImage_ = nullptr;
2514     altLoadingCtx_.Reset();
2515     if (!image_) {
2516         auto host = GetHost();
2517         CHECK_NULL_VOID(host);
2518         auto rsRenderContext = host->GetRenderContext();
2519         CHECK_NULL_VOID(rsRenderContext);
2520         TAG_LOGI(AceLogTag::ACE_IMAGE, "%{public}s, %{private}s ResetAltImage.",
2521             imageDfxConfig_.ToStringWithoutSrc().c_str(), imageDfxConfig_.imageSrc_.c_str());
2522         rsRenderContext->RemoveContentModifier(contentMod_);
2523         contentMod_ = nullptr;
2524     }
2525 }
2526 
ResetImageAndAlt()2527 void ImagePattern::ResetImageAndAlt()
2528 {
2529     TAG_LOGI(AceLogTag::ACE_IMAGE, "%{public}s, %{private}s reseting Image and Alt.",
2530         imageDfxConfig_.ToStringWithoutSrc().c_str(), imageDfxConfig_.imageSrc_.c_str());
2531     auto frameNode = GetHost();
2532     CHECK_NULL_VOID(frameNode);
2533     if (frameNode->IsInDestroying() && frameNode->IsOnMainTree()) {
2534         isNeedReset_ = true;
2535         return;
2536     }
2537     image_ = nullptr;
2538     loadingCtx_ = nullptr;
2539     srcRect_.Reset();
2540     dstRect_.Reset();
2541     altLoadingCtx_ = nullptr;
2542     altImage_ = nullptr;
2543     altDstRect_.reset();
2544     altSrcRect_.reset();
2545     auto rsRenderContext = frameNode->GetRenderContext();
2546     CHECK_NULL_VOID(rsRenderContext);
2547     rsRenderContext->RemoveContentModifier(contentMod_);
2548     contentMod_ = nullptr;
2549     CloseSelectOverlay();
2550     DestroyAnalyzerOverlay();
2551     frameNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2552     frameNode->SetTrimMemRecycle(false);
2553 }
2554 
ResetPictureSize()2555 void ImagePattern::ResetPictureSize()
2556 {
2557     auto host = GetHost();
2558     CHECK_NULL_VOID(host);
2559     const auto& layoutProperty = host->GetLayoutProperty();
2560     CHECK_NULL_VOID(layoutProperty);
2561     layoutProperty->ClearUserDefinedIdealSize(true, true);
2562     hasSizeChanged = false;
2563 }
2564 
SetColorFilter(const RefPtr<FrameNode> & imageFrameNode)2565 void ImagePattern::SetColorFilter(const RefPtr<FrameNode>& imageFrameNode)
2566 {
2567     auto host = GetHost();
2568     CHECK_NULL_VOID(host);
2569     auto renderProperty = host->GetPaintProperty<ImageRenderProperty>();
2570     CHECK_NULL_VOID(renderProperty);
2571     auto imageRenderProperty = imageFrameNode->GetPaintProperty<ImageRenderProperty>();
2572     CHECK_NULL_VOID(imageRenderProperty);
2573     if (renderProperty->HasColorFilter()) {
2574         imageRenderProperty->UpdateColorFilter(renderProperty->GetColorFilter().value());
2575     }
2576     if (renderProperty->HasDrawingColorFilter()) {
2577         imageRenderProperty->UpdateDrawingColorFilter(renderProperty->GetDrawingColorFilter().value());
2578     }
2579 }
2580 
SetImageFit(const RefPtr<FrameNode> & imageFrameNode)2581 void ImagePattern::SetImageFit(const RefPtr<FrameNode>& imageFrameNode)
2582 {
2583     auto host = GetHost();
2584     CHECK_NULL_VOID(host);
2585     auto layoutProperty = host->GetLayoutProperty<ImageLayoutProperty>();
2586     CHECK_NULL_VOID(layoutProperty);
2587     auto renderProperty = host->GetPaintProperty<ImageRenderProperty>();
2588     CHECK_NULL_VOID(renderProperty);
2589     auto imageLayoutProperty = imageFrameNode->GetLayoutProperty<ImageLayoutProperty>();
2590     CHECK_NULL_VOID(imageLayoutProperty);
2591     auto imageRenderProperty = imageFrameNode->GetPaintProperty<ImageRenderProperty>();
2592     CHECK_NULL_VOID(imageRenderProperty);
2593     if (renderProperty->HasImageFit()) {
2594         imageRenderProperty->UpdateImageFit(renderProperty->GetImageFit().value());
2595     }
2596     if (layoutProperty->HasImageFit()) {
2597         imageLayoutProperty->UpdateImageFit(layoutProperty->GetImageFit().value());
2598     }
2599 }
2600 
SetObscured()2601 void ImagePattern::SetObscured()
2602 {
2603     auto host = GetHost();
2604     CHECK_NULL_VOID(host);
2605     auto imageFrameNode = AceType::DynamicCast<FrameNode>(host->GetChildren().front());
2606     CHECK_NULL_VOID(imageFrameNode);
2607     auto obscuredReasons = host->GetRenderContext()->GetObscured().value_or(std::vector<ObscuredReasons>());
2608     const auto& castRenderContext = imageFrameNode->GetRenderContext();
2609     if (castRenderContext) {
2610         castRenderContext->UpdateObscured(obscuredReasons);
2611     }
2612     imageFrameNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2613     host->GetRenderContext()->ResetObscured();
2614     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2615 }
2616 
TriggerVisibleAreaChangeForChild(const RefPtr<UINode> & node,bool visible,double ratio)2617 void ImagePattern::TriggerVisibleAreaChangeForChild(const RefPtr<UINode>& node, bool visible, double ratio)
2618 {
2619     for (const auto& childNode : node->GetChildren()) {
2620         if (AceType::InstanceOf<FrameNode>(childNode)) {
2621             auto frame = AceType::DynamicCast<FrameNode>(childNode);
2622             if (!frame || !frame->GetEventHub<EventHub>()) {
2623                 continue;
2624             }
2625             auto callback = frame->GetEventHub<EventHub>()->GetVisibleAreaCallback(true).callback;
2626             if (callback) {
2627                 callback(visible, ratio);
2628             }
2629         }
2630         TriggerVisibleAreaChangeForChild(childNode, visible, ratio);
2631     }
2632 }
2633 
DumpInfo(std::unique_ptr<JsonValue> & json)2634 void ImagePattern::DumpInfo(std::unique_ptr<JsonValue>& json)
2635 {
2636     DumpLayoutInfo(json);
2637     DumpRenderInfo(json);
2638     json->Put("syncLoad", syncLoad_);
2639     if (loadingCtx_) {
2640         auto currentLoadImageState = loadingCtx_->GetCurrentLoadingState();
2641         json->Put("currentLoadImageState", currentLoadImageState.c_str());
2642         json->Put("rawImageSize", loadingCtx_->GetImageSize().ToString().c_str());
2643         json->Put("LoadErrorMsg", loadingCtx_->GetErrorMsg().c_str());
2644     } else {
2645         json->Put("imageLoadingContext", "null");
2646     }
2647 
2648     json->Put("draggable", enableDrag_);
2649     json->Put("enableAnalyzer", isEnableAnalyzer_);
2650 }
2651 
DumpSimplifyInfo(std::unique_ptr<JsonValue> & json)2652 void ImagePattern::DumpSimplifyInfo(std::unique_ptr<JsonValue>& json)
2653 {
2654     DumpInfo(json);
2655 }
2656 
DumpLayoutInfo(std::unique_ptr<JsonValue> & json)2657 void ImagePattern::DumpLayoutInfo(std::unique_ptr<JsonValue>& json)
2658 {
2659     auto layoutProp = GetLayoutProperty<ImageLayoutProperty>();
2660     CHECK_NULL_VOID(layoutProp);
2661     auto src = layoutProp->GetImageSourceInfo().value_or(ImageSourceInfo(""));
2662     json->Put("url", src.ToString().c_str());
2663     auto altSrc = layoutProp->GetAlt().value_or(ImageSourceInfo(""));
2664     json->Put("altUrl", altSrc.ToString().c_str());
2665     auto imageFit = layoutProp->GetImageFit().value_or(ImageFit::COVER);
2666     json->Put("objectFit", GetImageFitStr(imageFit).c_str());
2667     auto fitOriginalSize = layoutProp->GetFitOriginalSize().value_or(false);
2668     json->Put("fitOriginalSize", fitOriginalSize);
2669     const std::optional<SizeF>& sourceSize = layoutProp->GetSourceSize();
2670     if (sourceSize.has_value()) {
2671         json->Put("sourceSize", sourceSize.value().ToString().c_str());
2672     }
2673     bool autoResize = layoutProp->GetAutoResize().value_or(autoResizeDefault_);
2674     json->Put("autoResize", autoResize);
2675 }
2676 
DumpRenderInfo(std::unique_ptr<JsonValue> & json)2677 void ImagePattern::DumpRenderInfo(std::unique_ptr<JsonValue>& json)
2678 {
2679     auto renderProp = GetPaintProperty<ImageRenderProperty>();
2680     CHECK_NULL_VOID(renderProp);
2681     auto imageRenderMode = renderProp->GetImageRenderMode().value_or(ImageRenderMode::ORIGINAL);
2682     json->Put("renderMode", (imageRenderMode == ImageRenderMode::ORIGINAL) ? "Original" : "Template");
2683     auto imageRepeat = renderProp->GetImageRepeat().value_or(ImageRepeat::NO_REPEAT);
2684     json->Put("objectRepeat", GetImageRepeatStr(imageRepeat).c_str());
2685     auto imageColorFilter = renderProp->GetColorFilter();
2686     if (imageColorFilter.has_value()) {
2687         auto colorFilter = imageColorFilter.value();
2688         json->Put("colorFilter", GetImageColorFilterStr(colorFilter).c_str());
2689     }
2690     auto fillColor = renderProp->GetSvgFillColor();
2691     if (fillColor.has_value()) {
2692         auto color = fillColor.value();
2693         json->Put("fillColor", color.ColorToString().c_str());
2694     }
2695     DynamicRangeMode dynamicMode = DynamicRangeMode::STANDARD;
2696     if (renderProp->HasDynamicMode()) {
2697         dynamicMode = renderProp->GetDynamicMode().value_or(DynamicRangeMode::STANDARD);
2698         json->Put("dynamicRangeMode", GetDynamicModeString(dynamicMode).c_str());
2699     }
2700     auto matchTextDirection = renderProp->GetMatchTextDirection().value_or(false);
2701     json->Put("matchTextDirection", matchTextDirection);
2702     auto smoothEdge = renderProp->GetSmoothEdge();
2703     if (smoothEdge.has_value()) {
2704         json->Put("edgeAntialiasing", smoothEdge.value());
2705     }
2706     auto needBorderRadius = renderProp->GetNeedBorderRadius().value_or(false);
2707     json->Put("needBorderRadius", needBorderRadius);
2708     if (renderProp && renderProp->HasImageResizableSlice() && renderProp->GetImageResizableSliceValue({}).Valid()) {
2709         json->Put("resizable slice", renderProp->GetImageResizableSliceValue({}).ToString().c_str());
2710     }
2711     auto imageInterpolation = renderProp->GetImageInterpolation().value_or(interpolationDefault_);
2712     json->Put("imageInterpolation", GetImageInterpolation(imageInterpolation).c_str());
2713 }
2714 
DumpAdvanceInfo(std::unique_ptr<JsonValue> & json)2715 void ImagePattern::DumpAdvanceInfo(std::unique_ptr<JsonValue>& json)
2716 {
2717     auto layoutProp = GetLayoutProperty<ImageLayoutProperty>();
2718     CHECK_NULL_VOID(layoutProp);
2719     auto src = layoutProp->GetImageSourceInfo().value_or(ImageSourceInfo(""));
2720     json->Put("url", src.ToString().c_str());
2721     json->Put("syncLoad", syncLoad_);
2722     if (loadingCtx_) {
2723         auto currentLoadImageState = loadingCtx_->GetCurrentLoadingState();
2724         json->Put("currentLoadImageState", currentLoadImageState.c_str());
2725     }
2726 }
2727 
AddPixelMapToUiManager()2728 void ImagePattern::AddPixelMapToUiManager()
2729 {
2730     CHECK_NULL_VOID(image_);
2731     auto pixmap = image_->GetPixelMap();
2732     CHECK_NULL_VOID(pixmap);
2733     auto host = GetHost();
2734     CHECK_NULL_VOID(host);
2735     auto pipeline = host->GetContext();
2736     CHECK_NULL_VOID(pipeline);
2737     pipeline->AddPixelMap(host->GetId(), pixmap);
2738 }
2739 
GetFocusPattern() const2740 FocusPattern ImagePattern::GetFocusPattern() const
2741 {
2742     if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_FOURTEEN)) {
2743         return { FocusType::NODE, false, FocusStyleType::OUTER_BORDER };
2744     } else {
2745         return { FocusType::NODE, false };
2746     }
2747 }
2748 
OnActive()2749 void ImagePattern::OnActive()
2750 {
2751     if (status_ == Animator::Status::RUNNING && animator_->GetStatus() != Animator::Status::RUNNING) {
2752         auto host = GetHost();
2753         CHECK_NULL_VOID(host);
2754         if (!animator_->HasScheduler()) {
2755             auto context = host->GetContextRefPtr();
2756             if (context) {
2757                 animator_->AttachScheduler(context);
2758             } else {
2759                 TAG_LOGW(AceLogTag::ACE_IMAGE, "pipelineContext is null.");
2760             }
2761         }
2762         animator_->Forward();
2763     }
2764 }
2765 } // namespace OHOS::Ace::NG
2766