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