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