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