1 /*
2 * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "core/image/image_source_info.h"
17 #define NAPI_VERSION 8
18
19 #include <array>
20 #include <cstdint>
21
22 #include "base/geometry/dimension_offset.h"
23 #include "base/geometry/matrix4.h"
24 #include "base/geometry/ng/rect_t.h"
25 #include "base/geometry/ng/vector.h"
26 #include "base/log/dump_log.h"
27 #include "base/utils/utils.h"
28 #include "core/common/ai/image_analyzer_mgr.h"
29 #include "core/common/frontend.h"
30 #include "core/components/common/layout/constants.h"
31 #include "core/components/image/image_theme.h"
32 #include "core/components/theme/icon_theme.h"
33 #include "core/components_ng/base/view_stack_processor.h"
34 #include "core/components_ng/event/event_hub.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/pattern/image/image_pattern.h"
38 #include "core/components_ng/property/measure_property.h"
39 #include "core/pipeline_ng/pipeline_context.h"
40 #include "frameworks/bridge/common/utils/engine_helper.h"
41 #if defined(PIXEL_MAP_SUPPORTED) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
42 #include "foundation/multimedia/image_framework/interfaces/kits/js/common/include/pixel_map_napi.h"
43 #endif
44 #include "core/common/ace_engine_ext.h"
45 #include "core/common/udmf/udmf_client.h"
46
47 namespace OHOS::Ace::NG {
ConvertPixmapNapi(const RefPtr<PixelMap> & pixelMap)48 napi_value ConvertPixmapNapi(const RefPtr<PixelMap>& pixelMap)
49 {
50 #if defined(PIXEL_MAP_SUPPORTED) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
51 auto engine = EngineHelper::GetCurrentEngine();
52 CHECK_NULL_RETURN(engine, {});
53 NativeEngine* nativeEngine = engine->GetNativeEngine();
54 auto* env = reinterpret_cast<napi_env>(nativeEngine);
55 napi_value napiValue = OHOS::Media::PixelMapNapi::CreatePixelMap(env, pixelMap->GetPixelMapSharedPtr());
56 return napiValue;
57 #else
58 return nullptr;
59 #endif
60 }
61
CreateDataReadyCallback()62 DataReadyNotifyTask ImagePattern::CreateDataReadyCallback()
63 {
64 return [weak = WeakClaim(this)](const ImageSourceInfo& sourceInfo) {
65 auto pattern = weak.Upgrade();
66 CHECK_NULL_VOID(pattern);
67 auto imageLayoutProperty = pattern->GetLayoutProperty<ImageLayoutProperty>();
68 CHECK_NULL_VOID(imageLayoutProperty);
69 auto currentSourceInfo = imageLayoutProperty->GetImageSourceInfo().value_or(ImageSourceInfo(""));
70 if (currentSourceInfo != sourceInfo) {
71 TAG_LOGW(AceLogTag::ACE_IMAGE,
72 "sourceInfo does not match, ignore current callback. "
73 "current: %{public}s vs callback's: %{public}s",
74 currentSourceInfo.ToString().c_str(), sourceInfo.ToString().c_str());
75 return;
76 }
77 pattern->OnImageDataReady();
78 };
79 }
80
CreateLoadSuccessCallback()81 LoadSuccessNotifyTask ImagePattern::CreateLoadSuccessCallback()
82 {
83 return [weak = WeakClaim(this)](const ImageSourceInfo& sourceInfo) {
84 auto pattern = weak.Upgrade();
85 CHECK_NULL_VOID(pattern);
86 auto imageLayoutProperty = pattern->GetLayoutProperty<ImageLayoutProperty>();
87 CHECK_NULL_VOID(imageLayoutProperty);
88 auto currentSourceInfo = imageLayoutProperty->GetImageSourceInfo().value_or(ImageSourceInfo(""));
89 if (currentSourceInfo != sourceInfo) {
90 TAG_LOGW(AceLogTag::ACE_IMAGE,
91 "sourceInfo does not match, ignore current callback. "
92 "current: %{public}s vs callback's: %{public}s",
93 currentSourceInfo.ToString().c_str(), sourceInfo.ToString().c_str());
94 return;
95 }
96 pattern->OnImageLoadSuccess();
97 };
98 }
99
CreateLoadFailCallback()100 LoadFailNotifyTask ImagePattern::CreateLoadFailCallback()
101 {
102 return [weak = WeakClaim(this)](const ImageSourceInfo& sourceInfo, const std::string& errorMsg) {
103 auto pattern = weak.Upgrade();
104 CHECK_NULL_VOID(pattern);
105 auto imageLayoutProperty = pattern->GetLayoutProperty<ImageLayoutProperty>();
106 CHECK_NULL_VOID(imageLayoutProperty);
107 auto currentSourceInfo = imageLayoutProperty->GetImageSourceInfo().value_or(ImageSourceInfo(""));
108 if (currentSourceInfo != sourceInfo) {
109 TAG_LOGW(AceLogTag::ACE_IMAGE,
110 "sourceInfo does not match, ignore current callback. "
111 "current: %{public}s vs callback's: %{public}s",
112 currentSourceInfo.ToString().c_str(), sourceInfo.ToString().c_str());
113 return;
114 }
115 pattern->OnImageLoadFail(errorMsg);
116 };
117 }
118
PrepareAnimation(const RefPtr<CanvasImage> & image)119 void ImagePattern::PrepareAnimation(const RefPtr<CanvasImage>& image)
120 {
121 if (image->IsStatic()) {
122 return;
123 }
124 SetRedrawCallback(image);
125 RegisterVisibleAreaChange();
126 auto layoutProps = GetLayoutProperty<LayoutProperty>();
127 CHECK_NULL_VOID(layoutProps);
128 // pause animation if prop is initially set to invisible
129 if (layoutProps->GetVisibility().value_or(VisibleType::VISIBLE) != VisibleType::VISIBLE) {
130 image->ControlAnimation(false);
131 }
132 }
133
SetRedrawCallback(const RefPtr<CanvasImage> & image)134 void ImagePattern::SetRedrawCallback(const RefPtr<CanvasImage>& image)
135 {
136 CHECK_NULL_VOID(image);
137 // set animation flush function for svg / gif
138 image->SetRedrawCallback([weak = WeakPtr(GetHost())] {
139 auto imageNode = weak.Upgrade();
140 CHECK_NULL_VOID(imageNode);
141 imageNode->MarkNeedRenderOnly();
142 });
143 }
144
RegisterVisibleAreaChange()145 void ImagePattern::RegisterVisibleAreaChange()
146 {
147 auto pipeline = PipelineContext::GetCurrentContext();
148 // register to onVisibleAreaChange
149 CHECK_NULL_VOID(pipeline);
150 auto callback = [weak = WeakClaim(this)](bool visible, double ratio) {
151 auto self = weak.Upgrade();
152 CHECK_NULL_VOID(self);
153 self->OnVisibleChange(visible);
154 };
155 auto host = GetHost();
156 CHECK_NULL_VOID(host);
157 // add visibleAreaChangeNode(inner callback)
158 pipeline->AddVisibleAreaChangeNode(host, 0.0f, callback, false);
159 }
160
CalcImageContentPaintSize(const RefPtr<GeometryNode> & geometryNode)161 RectF ImagePattern::CalcImageContentPaintSize(const RefPtr<GeometryNode>& geometryNode)
162 {
163 RectF paintSize;
164 auto imageRenderProperty = GetPaintProperty<ImageRenderProperty>();
165 CHECK_NULL_RETURN(imageRenderProperty, paintSize);
166 ImageRepeat repeat = imageRenderProperty->GetImageRepeat().value_or(ImageRepeat::NO_REPEAT);
167 bool imageRepeatX = repeat == ImageRepeat::REPEAT || repeat == ImageRepeat::REPEAT_X;
168 bool imageRepeatY = repeat == ImageRepeat::REPEAT || repeat == ImageRepeat::REPEAT_Y;
169
170 if (loadingCtx_->GetSourceInfo().IsSvg()) {
171 const float invalidValue = -1;
172 paintSize.SetWidth(dstRect_.IsValid() ? dstRect_.Width() : invalidValue);
173 paintSize.SetHeight(dstRect_.IsValid() ? dstRect_.Height() : invalidValue);
174 paintSize.SetLeft(
175 dstRect_.IsValid() ? dstRect_.GetX() + geometryNode->GetContentOffset().GetX() : invalidValue);
176 paintSize.SetTop(dstRect_.IsValid() ? dstRect_.GetY() + geometryNode->GetContentOffset().GetY() : invalidValue);
177 } else {
178 paintSize.SetWidth(imageRepeatX ? geometryNode->GetContentSize().Width() : dstRect_.Width());
179 paintSize.SetHeight(imageRepeatY ? geometryNode->GetContentSize().Height() : dstRect_.Height());
180 paintSize.SetLeft((imageRepeatX ? 0 : dstRect_.GetX()) + geometryNode->GetContentOffset().GetX());
181 paintSize.SetTop((imageRepeatY ? 0 : dstRect_.GetY()) + geometryNode->GetContentOffset().GetY());
182 }
183 return paintSize;
184 }
185
OnImageLoadSuccess()186 void ImagePattern::OnImageLoadSuccess()
187 {
188 CHECK_NULL_VOID(loadingCtx_);
189 auto host = GetHost();
190 CHECK_NULL_VOID(host);
191 const auto& geometryNode = host->GetGeometryNode();
192 CHECK_NULL_VOID(geometryNode);
193
194 image_ = loadingCtx_->MoveCanvasImage();
195 srcRect_ = loadingCtx_->GetSrcRect();
196 dstRect_ = loadingCtx_->GetDstRect();
197
198 RectF paintRect = CalcImageContentPaintSize(geometryNode);
199 LoadImageSuccessEvent event(loadingCtx_->GetImageSize().Width(), loadingCtx_->GetImageSize().Height(),
200 geometryNode->GetFrameSize().Width(), geometryNode->GetFrameSize().Height(), 1, paintRect.Width(),
201 paintRect.Height(), paintRect.GetX(), paintRect.GetY());
202 auto eventHub = GetEventHub<ImageEventHub>();
203 if (eventHub) {
204 eventHub->FireCompleteEvent(event);
205 }
206
207 SetImagePaintConfig(image_, srcRect_, dstRect_, loadingCtx_->GetSourceInfo(), loadingCtx_->GetFrameCount());
208 PrepareAnimation(image_);
209 if (host->IsDraggable()) {
210 EnableDrag();
211 }
212 // clear alt data
213 altLoadingCtx_ = nullptr;
214 altImage_ = nullptr;
215 altDstRect_.reset();
216 altSrcRect_.reset();
217
218 if (!IsSupportImageAnalyzerFeature() && isAnalyzerOverlayBuild_) {
219 DeleteAnalyzerOverlay();
220 }
221 UpdateAnalyzerOverlay();
222
223 auto currentContext = PipelineContext::GetCurrentContext();
224 CHECK_NULL_VOID(currentContext);
225 int32_t instanceID = currentContext->GetInstanceId();
226 auto context = host->GetContext();
227 CHECK_NULL_VOID(context);
228 auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
229 uiTaskExecutor.PostTask([weak = WeakClaim(this), instanceID] {
230 ContainerScope scope(instanceID);
231 auto pattern = weak.Upgrade();
232 CHECK_NULL_VOID(pattern);
233 pattern->CreateAnalyzerOverlay();
234 });
235 host->MarkNeedRenderOnly();
236 }
237
OnImageDataReady()238 void ImagePattern::OnImageDataReady()
239 {
240 CHECK_NULL_VOID(loadingCtx_);
241 auto host = GetHost();
242 CHECK_NULL_VOID(host);
243 const auto& geometryNode = host->GetGeometryNode();
244 CHECK_NULL_VOID(geometryNode);
245 auto imageEventHub = GetEventHub<ImageEventHub>();
246 CHECK_NULL_VOID(imageEventHub);
247 LoadImageSuccessEvent event(loadingCtx_->GetImageSize().Width(), loadingCtx_->GetImageSize().Height(),
248 geometryNode->GetFrameSize().Width(), geometryNode->GetFrameSize().Height(), 0,
249 geometryNode->GetContentSize().Width(), geometryNode->GetContentSize().Height(),
250 geometryNode->GetContentOffset().GetX(), geometryNode->GetContentOffset().GetY());
251 imageEventHub->FireCompleteEvent(event);
252
253 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
254 }
255
OnImageLoadFail(const std::string & errorMsg)256 void ImagePattern::OnImageLoadFail(const std::string& errorMsg)
257 {
258 auto host = GetHost();
259 CHECK_NULL_VOID(host);
260 const auto& geometryNode = host->GetGeometryNode();
261 auto imageEventHub = GetEventHub<ImageEventHub>();
262 CHECK_NULL_VOID(imageEventHub);
263 LoadImageFailEvent event(geometryNode->GetFrameSize().Width(), geometryNode->GetFrameSize().Height(), errorMsg);
264 imageEventHub->FireErrorEvent(event);
265 }
266
SetImagePaintConfig(const RefPtr<CanvasImage> & canvasImage,const RectF & srcRect,const RectF & dstRect,const ImageSourceInfo & sourceInfo,int32_t frameCount)267 void ImagePattern::SetImagePaintConfig(const RefPtr<CanvasImage>& canvasImage, const RectF& srcRect,
268 const RectF& dstRect, const ImageSourceInfo& sourceInfo, int32_t frameCount)
269 {
270 auto layoutProps = GetLayoutProperty<ImageLayoutProperty>();
271 CHECK_NULL_VOID(layoutProps);
272
273 ImagePaintConfig config {
274 .srcRect_ = srcRect,
275 .dstRect_ = dstRect,
276 };
277 config.imageFit_ = layoutProps->GetImageFit().value_or(ImageFit::COVER);
278 config.isSvg_ = sourceInfo.IsSvg();
279 config.frameCount_ = frameCount;
280 config.sourceInfo_ = sourceInfo;
281 auto host = GetHost();
282 if (!host) {
283 canvasImage->SetPaintConfig(config);
284 return;
285 }
286 auto renderContext = host->GetRenderContext();
287 if (!renderContext || !renderContext->HasBorderRadius()) {
288 canvasImage->SetPaintConfig(config);
289 return;
290 }
291
292 auto renderProps = host->GetPaintProperty<ImageRenderProperty>();
293 if (renderProps) {
294 renderProps->UpdateNeedBorderRadius(true);
295 }
296 canvasImage->SetPaintConfig(config);
297 }
298
CreateNodePaintMethod()299 RefPtr<NodePaintMethod> ImagePattern::CreateNodePaintMethod()
300 {
301 if (image_) {
302 return MakeRefPtr<ImagePaintMethod>(image_, selectOverlay_, interpolationDefault_);
303 }
304 if (altImage_ && altDstRect_ && altSrcRect_) {
305 return MakeRefPtr<ImagePaintMethod>(altImage_, selectOverlay_, interpolationDefault_);
306 }
307 CreateObscuredImage();
308 if (obscuredImage_) {
309 return MakeRefPtr<ImagePaintMethod>(obscuredImage_, selectOverlay_, interpolationDefault_);
310 }
311 return nullptr;
312 }
313
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)314 bool ImagePattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
315 {
316 if (config.skipMeasure || dirty->SkipMeasureContent()) {
317 return false;
318 }
319
320 if (loadingCtx_) {
321 auto renderProp = GetPaintProperty<ImageRenderProperty>();
322 if (renderProp && renderProp->HasImageResizableSlice() && image_) {
323 loadingCtx_->ResizableCalcDstSize();
324 SetImagePaintConfig(image_, loadingCtx_->GetSrcRect(), loadingCtx_->GetDstRect(), loadingCtx_->GetSrc(),
325 loadingCtx_->GetFrameCount());
326 }
327 }
328
329 if (altLoadingCtx_) {
330 auto renderProp = GetPaintProperty<ImageRenderProperty>();
331 if (renderProp && renderProp->HasImageResizableSlice() && altImage_) {
332 altLoadingCtx_->ResizableCalcDstSize();
333 SetImagePaintConfig(altImage_, altLoadingCtx_->GetSrcRect(), altLoadingCtx_->GetDstRect(),
334 altLoadingCtx_->GetSrc(), altLoadingCtx_->GetFrameCount());
335 }
336 }
337
338 if (IsSupportImageAnalyzerFeature()) {
339 UpdateAnalyzerUIConfig(dirty->GetGeometryNode());
340 }
341
342 return image_ || altImage_;
343 }
344
CreateObscuredImage()345 void ImagePattern::CreateObscuredImage()
346 {
347 auto props = GetLayoutProperty<ImageLayoutProperty>();
348 CHECK_NULL_VOID(props);
349 auto layoutConstraint = props->GetLayoutConstraint();
350 CHECK_NULL_VOID(layoutConstraint);
351 auto host = GetHost();
352 CHECK_NULL_VOID(host);
353 auto sourceInfo = props->GetImageSourceInfo().value_or(ImageSourceInfo(""));
354 auto reasons = host->GetRenderContext()->GetObscured().value_or(std::vector<ObscuredReasons>());
355 if (reasons.size() && layoutConstraint->selfIdealSize.IsValid()) {
356 if (!obscuredImage_) {
357 obscuredImage_ = MakeRefPtr<ObscuredImage>();
358 SetImagePaintConfig(obscuredImage_, srcRect_, dstRect_, sourceInfo);
359 }
360 }
361 }
362
LoadImage(const ImageSourceInfo & src)363 void ImagePattern::LoadImage(const ImageSourceInfo& src)
364 {
365 LoadNotifier loadNotifier(CreateDataReadyCallback(), CreateLoadSuccessCallback(), CreateLoadFailCallback());
366
367 loadingCtx_ = AceType::MakeRefPtr<ImageLoadingContext>(src, std::move(loadNotifier), syncLoad_);
368 if (SystemProperties::GetDebugEnabled()) {
369 TAG_LOGI(AceLogTag::ACE_IMAGE, "start loading image %{public}s", src.ToString().c_str());
370 }
371 loadingCtx_->LoadImageData();
372 }
373
LoadAltImage(const ImageSourceInfo & altImageSourceInfo)374 void ImagePattern::LoadAltImage(const ImageSourceInfo& altImageSourceInfo)
375 {
376 LoadNotifier altLoadNotifier(CreateDataReadyCallbackForAlt(), CreateLoadSuccessCallbackForAlt(), nullptr);
377 if (!altLoadingCtx_ || altLoadingCtx_->GetSourceInfo() != altImageSourceInfo ||
378 (altLoadingCtx_ && altImageSourceInfo.IsSvg())) {
379 altLoadingCtx_ = AceType::MakeRefPtr<ImageLoadingContext>(altImageSourceInfo, std::move(altLoadNotifier));
380 altLoadingCtx_->LoadImageData();
381 }
382 }
383
LoadImageDataIfNeed()384 void ImagePattern::LoadImageDataIfNeed()
385 {
386 auto imageLayoutProperty = GetLayoutProperty<ImageLayoutProperty>();
387 CHECK_NULL_VOID(imageLayoutProperty);
388 auto src = imageLayoutProperty->GetImageSourceInfo().value_or(ImageSourceInfo(""));
389 UpdateInternalResource(src);
390
391 if (!loadingCtx_ || loadingCtx_->GetSourceInfo() != src) {
392 LoadImage(src);
393 } else {
394 auto currentContext = PipelineContext::GetCurrentContext();
395 CHECK_NULL_VOID(currentContext);
396 int32_t instanceID = currentContext->GetInstanceId();
397 auto host = GetHost();
398 CHECK_NULL_VOID(host);
399 auto context = host->GetContext();
400 CHECK_NULL_VOID(context);
401 auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
402 uiTaskExecutor.PostTask([weak = WeakClaim(this), instanceID] {
403 ContainerScope scope(instanceID);
404 auto pattern = weak.Upgrade();
405 CHECK_NULL_VOID(pattern);
406 pattern->CreateAnalyzerOverlay();
407 if (pattern->IsSupportImageAnalyzerFeature()) {
408 auto host = pattern->GetHost();
409 pattern->UpdateAnalyzerUIConfig(host->GetGeometryNode());
410 }
411 });
412 }
413 if (loadingCtx_->NeedAlt() && imageLayoutProperty->GetAlt()) {
414 auto altImageSourceInfo = imageLayoutProperty->GetAlt().value_or(ImageSourceInfo(""));
415 LoadAltImage(altImageSourceInfo);
416 }
417 }
418
UpdateGestureAndDragWhenModify()419 void ImagePattern::UpdateGestureAndDragWhenModify()
420 {
421 // remove long press and mouse events
422 auto host = GetHost();
423 CHECK_NULL_VOID(host);
424
425 auto gestureHub = host->GetOrCreateGestureEventHub();
426 if (longPressEvent_) {
427 gestureHub->SetLongPressEvent(nullptr);
428 longPressEvent_ = nullptr;
429 }
430
431 if (clickEvent_) {
432 gestureHub->RemoveClickEvent(clickEvent_);
433 clickEvent_ = nullptr;
434 }
435
436 if (mouseEvent_) {
437 auto inputHub = host->GetOrCreateInputEventHub();
438 inputHub->RemoveOnMouseEvent(mouseEvent_);
439 mouseEvent_ = nullptr;
440 }
441
442 if (host->IsDraggable()) {
443 EnableDrag();
444 }
445 }
446
OnModifyDone()447 void ImagePattern::OnModifyDone()
448 {
449 Pattern::OnModifyDone();
450 LoadImageDataIfNeed();
451
452 if (copyOption_ != CopyOptions::None) {
453 auto host = GetHost();
454 CHECK_NULL_VOID(host);
455 bool hasObscured = false;
456 if (host->GetRenderContext()->GetObscured().has_value()) {
457 auto obscuredReasons = host->GetRenderContext()->GetObscured().value();
458 hasObscured = std::any_of(obscuredReasons.begin(), obscuredReasons.end(),
459 [](const auto& reason) { return reason == ObscuredReasons::PLACEHOLDER; });
460 }
461 if (!hasObscured) {
462 InitCopy();
463 return;
464 }
465 }
466
467 CloseSelectOverlay();
468
469 auto host = GetHost();
470 CHECK_NULL_VOID(host);
471
472 UpdateGestureAndDragWhenModify();
473
474 if (isAnalyzerOverlayBuild_) {
475 if (!IsSupportImageAnalyzerFeature()) {
476 DeleteAnalyzerOverlay();
477 } else {
478 UpdateAnalyzerOverlayLayout();
479 }
480 }
481
482 // SetUsingContentRectForRenderFrame is set for image paint
483 auto overlayNode = host->GetOverlayNode();
484 if (overlayNode) {
485 auto layoutProperty = host->GetLayoutProperty();
486 CHECK_NULL_VOID(layoutProperty);
487 auto padding = layoutProperty->CreatePaddingAndBorder();
488 auto renderContext = overlayNode->GetRenderContext();
489 if (renderContext) {
490 renderContext->SetRenderFrameOffset({-padding.Offset().GetX(), -padding.Offset().GetY()});
491 }
492 }
493 }
494
CreateDataReadyCallbackForAlt()495 DataReadyNotifyTask ImagePattern::CreateDataReadyCallbackForAlt()
496 {
497 return [weak = WeakClaim(this)](const ImageSourceInfo& sourceInfo) {
498 auto pattern = weak.Upgrade();
499 CHECK_NULL_VOID(pattern);
500 auto imageLayoutProperty = pattern->GetLayoutProperty<ImageLayoutProperty>();
501 CHECK_NULL_VOID(imageLayoutProperty);
502 auto currentAltSourceInfo = imageLayoutProperty->GetAlt().value_or(ImageSourceInfo(""));
503 if (currentAltSourceInfo != sourceInfo) {
504 TAG_LOGW(AceLogTag::ACE_IMAGE,
505 "alt image sourceInfo does not match, ignore current callback. "
506 "current: %{public}s vs callback's: %{public}s",
507 currentAltSourceInfo.ToString().c_str(), sourceInfo.ToString().c_str());
508 return;
509 }
510 auto host = pattern->GetHost();
511 CHECK_NULL_VOID(host);
512 if (!host->IsActive()) {
513 return;
514 }
515 const auto& geometryNode = host->GetGeometryNode();
516 CHECK_NULL_VOID(geometryNode);
517 if (!geometryNode->GetContent()) {
518 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
519 return;
520 }
521
522 // calculate params for [altLoadingCtx] to do [MakeCanvasImage] if component size is already settled
523 pattern->altLoadingCtx_->MakeCanvasImageIfNeed(
524 geometryNode->GetContentSize(), true, imageLayoutProperty->GetImageFit().value_or(ImageFit::COVER));
525 };
526 }
527
CreateLoadSuccessCallbackForAlt()528 LoadSuccessNotifyTask ImagePattern::CreateLoadSuccessCallbackForAlt()
529 {
530 return [weak = WeakClaim(this)](const ImageSourceInfo& sourceInfo) {
531 auto pattern = weak.Upgrade();
532 CHECK_NULL_VOID(pattern);
533 CHECK_NULL_VOID(pattern->altLoadingCtx_);
534 auto layoutProps = pattern->GetLayoutProperty<ImageLayoutProperty>();
535 auto currentAltSrc = layoutProps->GetAlt().value_or(ImageSourceInfo(""));
536 if (currentAltSrc != sourceInfo) {
537 TAG_LOGW(AceLogTag::ACE_IMAGE,
538 "alt image sourceInfo does not match, ignore current callback. "
539 "current: %{public}s vs callback's: %{public}s",
540 currentAltSrc.ToString().c_str(), sourceInfo.ToString().c_str());
541 return;
542 }
543 pattern->altImage_ = pattern->altLoadingCtx_->MoveCanvasImage();
544 pattern->altSrcRect_ = std::make_unique<RectF>(pattern->altLoadingCtx_->GetSrcRect());
545 pattern->altDstRect_ = std::make_unique<RectF>(pattern->altLoadingCtx_->GetDstRect());
546 pattern->SetImagePaintConfig(pattern->altImage_, *pattern->altSrcRect_, *pattern->altDstRect_,
547 pattern->altLoadingCtx_->GetSourceInfo(), pattern->altLoadingCtx_->GetFrameCount());
548
549 pattern->PrepareAnimation(pattern->altImage_);
550
551 auto host = pattern->GetHost();
552 CHECK_NULL_VOID(host);
553 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
554 };
555 }
556
UpdateInternalResource(ImageSourceInfo & sourceInfo)557 void ImagePattern::UpdateInternalResource(ImageSourceInfo& sourceInfo)
558 {
559 if (!sourceInfo.IsInternalResource()) {
560 return;
561 }
562
563 auto pipeline = PipelineBase::GetCurrentContext();
564 CHECK_NULL_VOID(pipeline);
565 auto iconTheme = pipeline->GetTheme<IconTheme>();
566 CHECK_NULL_VOID(iconTheme);
567 auto iconPath = iconTheme->GetIconPath(sourceInfo.GetResourceId());
568 if (!iconPath.empty()) {
569 sourceInfo.SetSrc(iconPath, sourceInfo.GetFillColor());
570 auto imageLayoutProperty = GetLayoutProperty<ImageLayoutProperty>();
571 CHECK_NULL_VOID(imageLayoutProperty);
572 imageLayoutProperty->UpdateImageSourceInfo(sourceInfo);
573 }
574 }
575
OnNotifyMemoryLevel(int32_t level)576 void ImagePattern::OnNotifyMemoryLevel(int32_t level)
577 {
578 // TODO: do different data cleaning operation according to level
579 // when image component is [onShow], do not clean image data
580 // TODO: use [isActive_] to determine image data management
581 if (isShow_) {
582 return;
583 }
584
585 // clean image data
586 loadingCtx_ = nullptr;
587 image_ = nullptr;
588 altLoadingCtx_ = nullptr;
589 altImage_ = nullptr;
590
591 // clean rs node to release the sk_sp<SkImage> held by it
592 // TODO: release PixelMap resource when use PixelMap resource to draw image
593 auto frameNode = GetHost();
594 CHECK_NULL_VOID(frameNode);
595 auto rsRenderContext = frameNode->GetRenderContext();
596 CHECK_NULL_VOID(rsRenderContext);
597 rsRenderContext->ClearDrawCommands();
598 auto pipeline = PipelineContext::GetCurrentContext();
599 CHECK_NULL_VOID(pipeline);
600 pipeline->FlushMessages();
601 }
602
603 // when recycle image component, release the pixelmap resource
OnRecycle()604 void ImagePattern::OnRecycle()
605 {
606 loadingCtx_ = nullptr;
607 image_ = nullptr;
608 altLoadingCtx_ = nullptr;
609 altImage_ = nullptr;
610
611 auto frameNode = GetHost();
612 CHECK_NULL_VOID(frameNode);
613 auto rsRenderContext = frameNode->GetRenderContext();
614 CHECK_NULL_VOID(rsRenderContext);
615 rsRenderContext->ClearDrawCommands();
616 UnregisterWindowStateChangedCallback();
617 }
618
OnReuse()619 void ImagePattern::OnReuse()
620 {
621 RegisterWindowStateChangedCallback();
622 LoadImageDataIfNeed();
623 }
624
RegisterWindowStateChangedCallback()625 void ImagePattern::RegisterWindowStateChangedCallback()
626 {
627 auto host = GetHost();
628 CHECK_NULL_VOID(host);
629 auto pipeline = PipelineContext::GetCurrentContext();
630 CHECK_NULL_VOID(pipeline);
631 pipeline->AddWindowStateChangedCallback(host->GetId());
632 }
633
UnregisterWindowStateChangedCallback()634 void ImagePattern::UnregisterWindowStateChangedCallback()
635 {
636 auto host = GetHost();
637 CHECK_NULL_VOID(host);
638 auto pipeline = PipelineContext::GetCurrentContext();
639 CHECK_NULL_VOID(pipeline);
640 pipeline->RemoveWindowStateChangedCallback(host->GetId());
641 }
642
OnWindowHide()643 void ImagePattern::OnWindowHide()
644 {
645 isShow_ = false;
646 }
647
OnWindowShow()648 void ImagePattern::OnWindowShow()
649 {
650 isShow_ = true;
651 LoadImageDataIfNeed();
652 }
653
OnVisibleChange(bool visible)654 void ImagePattern::OnVisibleChange(bool visible)
655 {
656 if (!visible) {
657 CloseSelectOverlay();
658 }
659 // control svg / gif animation
660 if (image_) {
661 image_->ControlAnimation(visible);
662 } else if (altImage_) {
663 altImage_->ControlAnimation(visible);
664 }
665 }
666
OnAttachToFrameNode()667 void ImagePattern::OnAttachToFrameNode()
668 {
669 auto host = GetHost();
670 CHECK_NULL_VOID(host);
671 auto renderCtx = host->GetRenderContext();
672 renderCtx->SetClipToBounds(false);
673 renderCtx->SetUsingContentRectForRenderFrame(true);
674
675 // register image frame node to pipeline context to receive memory level notification and window state change
676 // notification
677 auto pipeline = PipelineContext::GetCurrentContext();
678 CHECK_NULL_VOID(pipeline);
679 pipeline->AddNodesToNotifyMemoryLevel(host->GetId());
680 pipeline->AddWindowStateChangedCallback(host->GetId());
681 }
682
OnDetachFromFrameNode(FrameNode * frameNode)683 void ImagePattern::OnDetachFromFrameNode(FrameNode* frameNode)
684 {
685 CloseSelectOverlay();
686
687 auto id = frameNode->GetId();
688 auto pipeline = AceType::DynamicCast<PipelineContext>(PipelineBase::GetCurrentContext());
689 CHECK_NULL_VOID(pipeline);
690 pipeline->RemoveWindowStateChangedCallback(id);
691 pipeline->RemoveNodesToNotifyMemoryLevel(id);
692 }
693
EnableDrag()694 void ImagePattern::EnableDrag()
695 {
696 auto host = GetHost();
697 CHECK_NULL_VOID(host);
698 auto dragStart = [weak = WeakClaim(this)](const RefPtr<OHOS::Ace::DragEvent>& event, const std::string&
699 /* extraParams */) -> DragDropInfo {
700 DragDropInfo info;
701 auto imagePattern = weak.Upgrade();
702 CHECK_NULL_RETURN(imagePattern && imagePattern->loadingCtx_, info);
703 AceEngineExt::GetInstance().DragStartExt();
704 imagePattern->UpdateDragEvent(event);
705 info.extraInfo = imagePattern->loadingCtx_->GetSourceInfo().GetSrc();
706 return info;
707 };
708 auto eventHub = host->GetEventHub<EventHub>();
709 CHECK_NULL_VOID(eventHub);
710 if (!eventHub->HasOnDragStart()) {
711 eventHub->SetOnDragStart(std::move(dragStart));
712 }
713 }
714
BetweenSelectedPosition(const Offset & globalOffset)715 bool ImagePattern::BetweenSelectedPosition(const Offset& globalOffset)
716 {
717 auto host = GetHost();
718 CHECK_NULL_RETURN(host, false);
719 auto globalRect = host->GetTransformRectRelativeToWindow();
720 return globalRect.IsInRegion(PointF { globalOffset.GetX(), globalOffset.GetY() });
721 }
722
BeforeCreatePaintWrapper()723 void ImagePattern::BeforeCreatePaintWrapper()
724 {
725 auto host = GetHost();
726 CHECK_NULL_VOID(host);
727 host->GetRenderContext()->MarkContentChanged(true);
728 }
729
InitCopy()730 void ImagePattern::InitCopy()
731 {
732 if (longPressEvent_ && mouseEvent_ && clickEvent_) {
733 return;
734 }
735 auto longPressTask = [weak = WeakClaim(this)](GestureEvent& info) {
736 auto pattern = weak.Upgrade();
737 CHECK_NULL_VOID(pattern);
738 pattern->OpenSelectOverlay();
739 };
740 longPressEvent_ = MakeRefPtr<LongPressEvent>(std::move(longPressTask));
741
742 auto host = GetHost();
743 CHECK_NULL_VOID(host);
744 auto gestureHub = host->GetOrCreateGestureEventHub();
745 gestureHub->SetLongPressEvent(longPressEvent_);
746
747 auto mouseTask = [weak = WeakClaim(this)](MouseInfo& info) {
748 if (info.GetButton() == MouseButton::RIGHT_BUTTON && info.GetAction() == MouseAction::PRESS) {
749 auto pattern = weak.Upgrade();
750 CHECK_NULL_VOID(pattern);
751 pattern->OpenSelectOverlay();
752 }
753 };
754 mouseEvent_ = MakeRefPtr<InputEvent>(std::move(mouseTask));
755 auto inputHub = host->GetOrCreateInputEventHub();
756 CHECK_NULL_VOID(inputHub);
757 inputHub->AddOnMouseEvent(mouseEvent_);
758
759 // close overlay on click
760 clickEvent_ = MakeRefPtr<ClickEvent>([weak = WeakClaim(this)](GestureEvent& callback) {
761 auto pattern = weak.Upgrade();
762 CHECK_NULL_VOID(pattern);
763 pattern->CloseSelectOverlay();
764 });
765 gestureHub->AddClickEvent(clickEvent_);
766 }
767
OpenSelectOverlay()768 void ImagePattern::OpenSelectOverlay()
769 {
770 auto host = GetHost();
771 CHECK_NULL_VOID(host);
772 auto rect = host->GetTransformRectRelativeToWindow();
773 SelectOverlayInfo info;
774 SizeF handleSize = { SelectHandleInfo::GetDefaultLineWidth().ConvertToPx(), info.singleLineHeight };
775 info.firstHandle.paintRect = RectF(rect.GetOffset(), handleSize);
776 OffsetF offset(rect.Width() - handleSize.Width(), rect.Height() - handleSize.Height());
777 info.secondHandle.paintRect = RectF(rect.GetOffset() + offset, handleSize);
778 info.menuInfo.menuIsShow = true;
779 info.menuInfo.showCut = false;
780 info.menuInfo.showPaste = false;
781 info.menuCallback.onCopy = [weak = WeakClaim(this)]() {
782 auto pattern = weak.Upgrade();
783 CHECK_NULL_VOID(pattern);
784 pattern->HandleCopy();
785 pattern->CloseSelectOverlay();
786 };
787 info.onHandleMoveDone = [weak = WeakClaim(this), firstRect = info.firstHandle.paintRect,
788 secondRect = info.secondHandle.paintRect](const RectF&, bool isFirst) {
789 // reset handle position
790 auto pattern = weak.Upgrade();
791 CHECK_NULL_VOID(pattern && pattern->selectOverlay_);
792 SelectHandleInfo info;
793 if (isFirst) {
794 info.paintRect = firstRect;
795 pattern->selectOverlay_->UpdateFirstSelectHandleInfo(info);
796 } else {
797 info.paintRect = secondRect;
798 pattern->selectOverlay_->UpdateSecondSelectHandleInfo(info);
799 }
800 };
801 info.onClose = [weak = WeakClaim(this)](bool closedByGlobalEvent) {
802 if (closedByGlobalEvent) {
803 auto pattern = weak.Upgrade();
804 CHECK_NULL_VOID(pattern);
805 pattern->CloseSelectOverlay();
806 }
807 };
808
809 CloseSelectOverlay();
810 auto pipeline = PipelineContext::GetCurrentContext();
811 CHECK_NULL_VOID(pipeline);
812 selectOverlay_ = pipeline->GetSelectOverlayManager()->CreateAndShowSelectOverlay(info, WeakClaim(this));
813
814 // paint selected mask effect
815 host->MarkNeedRenderOnly();
816 }
817
CloseSelectOverlay()818 void ImagePattern::CloseSelectOverlay()
819 {
820 if (!selectOverlay_) {
821 return;
822 }
823 if (!selectOverlay_->IsClosed()) {
824 selectOverlay_->Close();
825 }
826 selectOverlay_ = nullptr;
827 // remove selected mask effect
828 auto host = GetHost();
829 CHECK_NULL_VOID(host);
830 host->MarkNeedRenderOnly();
831 }
832
HandleCopy()833 void ImagePattern::HandleCopy()
834 {
835 CHECK_NULL_VOID(image_);
836 if (!clipboard_) {
837 auto pipeline = PipelineContext::GetCurrentContext();
838 CHECK_NULL_VOID(pipeline);
839 clipboard_ = ClipboardProxy::GetInstance()->GetClipboard(pipeline->GetTaskExecutor());
840 }
841 auto pixmap = image_->GetPixelMap();
842 if (pixmap) {
843 clipboard_->SetPixelMapData(pixmap, copyOption_);
844 } else {
845 auto host = GetHost();
846 CHECK_NULL_VOID(host);
847 clipboard_->SetData(loadingCtx_->GetSourceInfo().GetSrc());
848 }
849 }
850
ToJsonValue(std::unique_ptr<JsonValue> & json) const851 void ImagePattern::ToJsonValue(std::unique_ptr<JsonValue>& json) const
852 {
853 static const char* COPY_OPTIONS[] = { "CopyOptions.None", "CopyOptions.InApp", "CopyOptions.Local",
854 "CopyOptions.Distributed" };
855 json->Put("copyOption", COPY_OPTIONS[static_cast<int32_t>(copyOption_)]);
856
857 json->Put("syncLoad", syncLoad_ ? "true" : "false");
858 auto host = GetHost();
859 CHECK_NULL_VOID(host);
860 json->Put("draggable", host->IsDraggable() ? "true" : "false");
861 json->Put("enableAnalyzer", isEnableAnalyzer_ ? "true" : "false");
862 }
863
UpdateFillColorIfForegroundColor()864 void ImagePattern::UpdateFillColorIfForegroundColor()
865 {
866 auto frameNode = GetHost();
867 CHECK_NULL_VOID(frameNode);
868 auto renderContext = frameNode->GetRenderContext();
869 CHECK_NULL_VOID(renderContext);
870 if (renderContext->HasForegroundColor() || renderContext->HasForegroundColorStrategy()) {
871 auto imageLayoutProperty = frameNode->GetLayoutProperty<ImageLayoutProperty>();
872 auto imageSourceInfo = imageLayoutProperty->GetImageSourceInfo().value();
873 if (imageSourceInfo.IsSvg()) {
874 imageSourceInfo.SetFillColor(Color::FOREGROUND);
875 imageLayoutProperty->UpdateImageSourceInfo(imageSourceInfo);
876 }
877 auto imageRenderProperty = frameNode->GetPaintProperty<ImageRenderProperty>();
878 CHECK_NULL_VOID(imageRenderProperty);
879 imageRenderProperty->UpdateSvgFillColor(Color::FOREGROUND);
880 }
881 }
882
DumpInfo()883 void ImagePattern::DumpInfo()
884 {
885 auto layoutProp = GetLayoutProperty<ImageLayoutProperty>();
886 CHECK_NULL_VOID(layoutProp);
887 auto src = layoutProp->GetImageSourceInfo().value_or(ImageSourceInfo(""));
888 DumpLog::GetInstance().AddDesc(std::string("url: ").append(src.ToString()));
889 syncLoad_ ? DumpLog::GetInstance().AddDesc("syncLoad:true") : DumpLog::GetInstance().AddDesc("syncLoad:false");
890 DumpLog::GetInstance().AddDesc("imageInterpolation:" + GetImageInterpolation());
891 if (loadingCtx_) {
892 auto currentLoadImageState = loadingCtx_->GetCurrentLoadingState();
893 DumpLog::GetInstance().AddDesc(std::string("currentLoadImageState : ").append(currentLoadImageState));
894 DumpLog::GetInstance().AddDesc(std::string("rawImageSize: ").append(loadingCtx_->GetImageSize().ToString()));
895 }
896 auto imageRenderProperty = GetPaintProperty<ImageRenderProperty>();
897 if (imageRenderProperty && imageRenderProperty->HasImageResizableSlice() &&
898 imageRenderProperty->GetImageResizableSliceValue({}).Valid()) {
899 DumpLog::GetInstance().AddDesc(
900 std::string("reslzable slice: ").append(imageRenderProperty->GetImageResizableSliceValue({}).ToString()));
901 }
902 DumpLog::GetInstance().AddDesc(std::string("enableAnalyzer: ").append(isEnableAnalyzer_ ? "true" : "false"));
903 }
904
DumpAdvanceInfo()905 void ImagePattern::DumpAdvanceInfo()
906 {
907 auto layoutProp = GetLayoutProperty<ImageLayoutProperty>();
908 CHECK_NULL_VOID(layoutProp);
909 auto src = layoutProp->GetImageSourceInfo().value_or(ImageSourceInfo(""));
910 DumpLog::GetInstance().AddDesc(std::string("url: ").append(src.ToString()));
911 syncLoad_ ? DumpLog::GetInstance().AddDesc("syncLoad:true") : DumpLog::GetInstance().AddDesc("syncLoad:false");
912 if (loadingCtx_) {
913 auto currentLoadImageState = loadingCtx_->GetCurrentLoadingState();
914 DumpLog::GetInstance().AddDesc(std::string("currentLoadImageState : ").append(currentLoadImageState));
915 }
916 }
917
UpdateDragEvent(const RefPtr<OHOS::Ace::DragEvent> & event)918 void ImagePattern::UpdateDragEvent(const RefPtr<OHOS::Ace::DragEvent>& event)
919 {
920 RefPtr<UnifiedData> unifiedData = UdmfClient::GetInstance()->CreateUnifiedData();
921 CHECK_NULL_VOID(loadingCtx_ && image_);
922 if (loadingCtx_->GetSourceInfo().IsPixmap()) {
923 auto pixelMap = image_->GetPixelMap();
924 CHECK_NULL_VOID(pixelMap);
925 const uint8_t* pixels = pixelMap->GetPixels();
926 CHECK_NULL_VOID(pixels);
927 int32_t length = pixelMap->GetByteCount();
928 std::vector<uint8_t> data(pixels, pixels + length);
929 PixelMapRecordDetails details = { pixelMap->GetWidth(), pixelMap->GetHeight(), pixelMap->GetPixelFormat(),
930 pixelMap->GetAlphaType() };
931 UdmfClient::GetInstance()->AddPixelMapRecord(unifiedData, data, details);
932 } else {
933 UdmfClient::GetInstance()->AddImageRecord(unifiedData, loadingCtx_->GetSourceInfo().GetSrc());
934 }
935 event->SetData(unifiedData);
936 }
937
OnLanguageConfigurationUpdate()938 void ImagePattern::OnLanguageConfigurationUpdate()
939 {
940 CHECK_NULL_VOID(loadingCtx_);
941 auto&& src = loadingCtx_->GetSourceInfo();
942 // Resource image needs to reload when Language changes
943 if (src.GetSrcType() == SrcType::RESOURCE) {
944 loadingCtx_.Reset();
945 }
946 }
947
OnColorConfigurationUpdate()948 void ImagePattern::OnColorConfigurationUpdate()
949 {
950 OnConfigurationUpdate();
951 }
952
OnIconConfigurationUpdate()953 void ImagePattern::OnIconConfigurationUpdate()
954 {
955 OnConfigurationUpdate();
956 }
957
OnConfigurationUpdate()958 void ImagePattern::OnConfigurationUpdate()
959 {
960 CHECK_NULL_VOID(loadingCtx_);
961
962 auto imageLayoutProperty = GetLayoutProperty<ImageLayoutProperty>();
963 CHECK_NULL_VOID(imageLayoutProperty);
964 auto src = imageLayoutProperty->GetImageSourceInfo().value_or(ImageSourceInfo(""));
965 UpdateInternalResource(src);
966 src.SetIsConfigurationChange(true);
967
968 LoadImage(src);
969 if (loadingCtx_->NeedAlt() && imageLayoutProperty->GetAlt()) {
970 auto altImageSourceInfo = imageLayoutProperty->GetAlt().value_or(ImageSourceInfo(""));
971 if (altLoadingCtx_ && altLoadingCtx_->GetSourceInfo() == altImageSourceInfo) {
972 altLoadingCtx_.Reset();
973 }
974 altImageSourceInfo.SetIsConfigurationChange(true);
975 LoadAltImage(altImageSourceInfo);
976 }
977 }
978
SetImageAnalyzerConfig(const ImageAnalyzerConfig & config)979 void ImagePattern::SetImageAnalyzerConfig(const ImageAnalyzerConfig& config)
980 {
981 if (!isEnableAnalyzer_) {
982 return;
983 }
984 analyzerConfig_ = config;
985 if (IsSupportImageAnalyzerFeature() && isAnalyzerOverlayBuild_) {
986 ImageAnalyzerMgr::GetInstance().UpdateConfig(&overlayData_, &analyzerConfig_);
987 }
988 }
989
CreateAnalyzerOverlay()990 void ImagePattern::CreateAnalyzerOverlay()
991 {
992 if (!IsSupportImageAnalyzerFeature() || isAnalyzerOverlayBuild_) {
993 return;
994 }
995
996 auto pixelMap = image_->GetPixelMap();
997 CHECK_NULL_VOID(pixelMap);
998 napi_value pixelmapNapiVal = ConvertPixmapNapi(pixelMap);
999 auto frameNode = GetHost();
1000 auto overlayNode = frameNode->GetOverlayNode();
1001
1002 auto layoutProps = GetLayoutProperty<ImageLayoutProperty>();
1003 CHECK_NULL_VOID(layoutProps);
1004 analyzerUIConfig_.imageFit = layoutProps->GetImageFit().value_or(ImageFit::COVER);
1005 auto buildNodeFunction = [this, &pixelmapNapiVal]() -> RefPtr<UINode> {
1006 ScopedViewStackProcessor builderViewStackProcessor;
1007 ImageAnalyzerMgr::GetInstance().BuildNodeFunc(
1008 pixelmapNapiVal, &analyzerConfig_, &analyzerUIConfig_, &overlayData_);
1009 auto customNode = ViewStackProcessor::GetInstance()->Finish();
1010 return customNode;
1011 };
1012 overlayNode = AceType::DynamicCast<FrameNode>(buildNodeFunction());
1013 CHECK_NULL_VOID(overlayNode);
1014 frameNode->SetOverlayNode(overlayNode);
1015 overlayNode->SetParent(AceType::WeakClaim(AceType::RawPtr(frameNode)));
1016 overlayNode->SetActive(true);
1017 isAnalyzerOverlayBuild_ = true;
1018
1019 UpdateAnalyzerOverlayLayout();
1020 auto renderContext = overlayNode->GetRenderContext();
1021 CHECK_NULL_VOID(renderContext);
1022 renderContext->UpdateZIndex(INT32_MAX);
1023 auto focusHub = overlayNode->GetOrCreateFocusHub();
1024 CHECK_NULL_VOID(focusHub);
1025 focusHub->SetFocusable(false);
1026 overlayNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1027 }
1028
UpdateAnalyzerOverlay()1029 void ImagePattern::UpdateAnalyzerOverlay()
1030 {
1031 if (!IsSupportImageAnalyzerFeature() || !isAnalyzerOverlayBuild_) {
1032 return;
1033 }
1034
1035 auto imageLayoutProperty = GetLayoutProperty<ImageLayoutProperty>();
1036 CHECK_NULL_VOID(imageLayoutProperty);
1037 auto src = imageLayoutProperty->GetImageSourceInfo().value_or(ImageSourceInfo(""));
1038 UpdateInternalResource(src);
1039 if (loadingCtx_ && loadingCtx_->GetSourceInfo() == src && srcRect_ == dstRect_) {
1040 return;
1041 }
1042
1043 auto pixelMap = image_->GetPixelMap();
1044 CHECK_NULL_VOID(pixelMap);
1045 napi_value pixelmapNapiVal = ConvertPixmapNapi(pixelMap);
1046 auto frameNode = GetHost();
1047 auto overlayNode = frameNode->GetOverlayNode();
1048 ImageAnalyzerMgr::GetInstance().UpdateImage(&overlayData_, pixelmapNapiVal, &analyzerConfig_, &analyzerUIConfig_);
1049 overlayNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1050 }
1051
DeleteAnalyzerOverlay()1052 void ImagePattern::DeleteAnalyzerOverlay()
1053 {
1054 auto frameNode = GetHost();
1055 CHECK_NULL_VOID(frameNode);
1056 auto overlayNode = frameNode->GetOverlayNode();
1057 isAnalyzerOverlayBuild_ = false;
1058 if (!overlayNode) {
1059 return;
1060 }
1061 RefPtr<FrameNode> node;
1062 frameNode->SetOverlayNode(node);
1063 }
1064
IsSupportImageAnalyzerFeature()1065 bool ImagePattern::IsSupportImageAnalyzerFeature()
1066 {
1067 auto eventHub = GetEventHub<EventHub>();
1068 bool isEnabled = true;
1069 if (eventHub) {
1070 isEnabled = eventHub->IsEnabled();
1071 }
1072
1073 bool hasObscured = false;
1074 auto host = GetHost();
1075 CHECK_NULL_RETURN(host, false);
1076 if (host->GetRenderContext()->GetObscured().has_value()) {
1077 auto obscuredReasons = host->GetRenderContext()->GetObscured().value();
1078 hasObscured = std::any_of(obscuredReasons.begin(), obscuredReasons.end(),
1079 [](const auto& reason) { return reason == ObscuredReasons::PLACEHOLDER; });
1080 }
1081
1082 auto imageRenderProperty = GetPaintProperty<ImageRenderProperty>();
1083 CHECK_NULL_RETURN(imageRenderProperty, false);
1084 ImageRepeat repeat = imageRenderProperty->GetImageRepeat().value_or(ImageRepeat::NO_REPEAT);
1085
1086 return isEnabled && !hasObscured && isEnableAnalyzer_ &&
1087 ImageAnalyzerMgr::GetInstance().IsImageAnalyzerSupported() && image_ &&
1088 !loadingCtx_->GetSourceInfo().IsSvg() && repeat == ImageRepeat::NO_REPEAT &&
1089 loadingCtx_->GetFrameCount() == 1;
1090 }
1091
UpdateAnalyzerUIConfig(const RefPtr<GeometryNode> & geometryNode)1092 void ImagePattern::UpdateAnalyzerUIConfig(const RefPtr<GeometryNode>& geometryNode)
1093 {
1094 bool isUIConfigUpdate = false;
1095 CHECK_NULL_VOID(geometryNode);
1096 if (analyzerUIConfig_.contentWidth != geometryNode->GetContentSize().Width() ||
1097 analyzerUIConfig_.contentHeight != geometryNode->GetContentSize().Height()) {
1098 analyzerUIConfig_.contentWidth = geometryNode->GetContentSize().Width();
1099 analyzerUIConfig_.contentHeight = geometryNode->GetContentSize().Height();
1100 isUIConfigUpdate = true;
1101 }
1102
1103 auto layoutProps = GetLayoutProperty<ImageLayoutProperty>();
1104 CHECK_NULL_VOID(layoutProps);
1105 if (analyzerUIConfig_.imageFit != layoutProps->GetImageFit().value_or(ImageFit::COVER)) {
1106 analyzerUIConfig_.imageFit = layoutProps->GetImageFit().value_or(ImageFit::COVER);
1107 isUIConfigUpdate = true;
1108 }
1109
1110 auto frameNode = GetHost();
1111 CHECK_NULL_VOID(frameNode);
1112 auto renderContext = frameNode->GetRenderContext();
1113 CHECK_NULL_VOID(renderContext);
1114
1115 auto localCenter = renderContext->GetTransformCenterValue(DimensionOffset(0.5_pct, 0.5_pct));
1116 auto localScale = renderContext->GetTransformScaleValue(VectorF(1.0f, 1.0f));
1117 Matrix4 localScaleMat = Matrix4::CreateTranslate(localCenter.GetX().Value(), localCenter.GetY().Value(), 0) *
1118 Matrix4::CreateScale(localScale.x, localScale.y, 1.0f) *
1119 Matrix4::CreateTranslate(-localCenter.GetX().Value(), -localCenter.GetY().Value(), 0);
1120
1121 auto transformMat = renderContext->GetTransformMatrixValue(Matrix4::CreateIdentity());
1122 VectorF transCenter(transformMat.Get(0, 3), transformMat.Get(1, 3));
1123 Matrix4 transScaleMat = Matrix4::CreateTranslate(transCenter.x, transCenter.y, 0) *
1124 Matrix4::CreateScale(transformMat.GetScaleX(), transformMat.GetScaleY(), 1.0f) *
1125 Matrix4::CreateTranslate(-transCenter.x, -transCenter.y, 0);
1126 Matrix4 scaleMat = localScaleMat * transScaleMat;
1127 if (!(analyzerUIConfig_.transformMat == scaleMat)) {
1128 analyzerUIConfig_.transformMat = scaleMat;
1129 isUIConfigUpdate = true;
1130 }
1131
1132 if (isUIConfigUpdate) {
1133 ImageAnalyzerMgr::GetInstance().UpdateInnerConfig(&overlayData_, &analyzerUIConfig_);
1134 }
1135 }
1136
UpdateAnalyzerOverlayLayout()1137 void ImagePattern::UpdateAnalyzerOverlayLayout()
1138 {
1139 auto host = GetHost();
1140 CHECK_NULL_VOID(host);
1141 auto layoutProperty = host->GetLayoutProperty();
1142 CHECK_NULL_VOID(layoutProperty);
1143 auto padding = layoutProperty->CreatePaddingAndBorder();
1144 auto overlayNode = host->GetOverlayNode();
1145 CHECK_NULL_VOID(overlayNode);
1146 auto overlayLayoutProperty = overlayNode->GetLayoutProperty();
1147 CHECK_NULL_VOID(overlayLayoutProperty);
1148 overlayLayoutProperty->UpdateMeasureType(MeasureType::MATCH_PARENT);
1149 overlayLayoutProperty->UpdateAlignment(Alignment::TOP_LEFT);
1150 overlayLayoutProperty->SetOverlayOffset(Dimension(padding.Offset().GetX()), Dimension(padding.Offset().GetY()));
1151 overlayNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1152
1153 auto renderContext = overlayNode->GetRenderContext();
1154 if (renderContext) {
1155 renderContext->SetRenderFrameOffset({-padding.Offset().GetX(), -padding.Offset().GetY()});
1156 }
1157 }
1158
InitDefaultValue()1159 void ImagePattern::InitDefaultValue()
1160 {
1161 // add API version protection
1162 if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
1163 autoResizeDefault_ = false;
1164 interpolationDefault_ = ImageInterpolation::LOW;
1165 }
1166 auto container = Container::Current();
1167 // If the default value is set to false, the ScenceBoard memory increases.
1168 // Therefore the default value is different in the ScenceBoard.
1169 if (container && container->IsScenceBoardWindow()) {
1170 autoResizeDefault_ = true;
1171 interpolationDefault_ = ImageInterpolation::NONE;
1172 }
1173 }
1174 } // namespace OHOS::Ace::NG
1175