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