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/components_ng/pattern/image/image_pattern.h"
17
18 #include <array>
19
20 #include "base/geometry/ng/rect_t.h"
21 #include "base/log/dump_log.h"
22 #include "base/utils/utils.h"
23 #include "core/components/common/layout/constants.h"
24 #include "core/components/image/image_theme.h"
25 #include "core/components/theme/icon_theme.h"
26 #include "core/components_ng/pattern/image/image_layout_property.h"
27 #include "core/components_ng/pattern/image/image_paint_method.h"
28 #include "core/pipeline_ng/pipeline_context.h"
29
30 #ifdef ENABLE_DRAG_FRAMEWORK
31 #include "core/common/ace_engine_ext.h"
32 #include "core/common/udmf/udmf_client.h"
33 #endif
34
35 namespace OHOS::Ace::NG {
36
CreateDataReadyCallback()37 DataReadyNotifyTask ImagePattern::CreateDataReadyCallback()
38 {
39 return [weak = WeakClaim(this)](const ImageSourceInfo& sourceInfo) {
40 auto pattern = weak.Upgrade();
41 CHECK_NULL_VOID(pattern);
42 auto imageLayoutProperty = pattern->GetLayoutProperty<ImageLayoutProperty>();
43 CHECK_NULL_VOID(imageLayoutProperty);
44 auto currentSourceInfo = imageLayoutProperty->GetImageSourceInfo().value_or(ImageSourceInfo(""));
45 if (currentSourceInfo != sourceInfo) {
46 LOGW("sourceInfo does not match, ignore current callback. current: %{public}s vs callback's: %{public}s",
47 currentSourceInfo.ToString().c_str(), sourceInfo.ToString().c_str());
48 return;
49 }
50 LOGD("Image Data Ready %{private}s", sourceInfo.ToString().c_str());
51 pattern->OnImageDataReady();
52 };
53 }
54
CreateLoadSuccessCallback()55 LoadSuccessNotifyTask ImagePattern::CreateLoadSuccessCallback()
56 {
57 return [weak = WeakClaim(this)](const ImageSourceInfo& sourceInfo) {
58 auto pattern = weak.Upgrade();
59 CHECK_NULL_VOID(pattern);
60 auto imageLayoutProperty = pattern->GetLayoutProperty<ImageLayoutProperty>();
61 CHECK_NULL_VOID(imageLayoutProperty);
62 auto currentSourceInfo = imageLayoutProperty->GetImageSourceInfo().value_or(ImageSourceInfo(""));
63 if (currentSourceInfo != sourceInfo) {
64 LOGW("sourceInfo does not match, ignore current callback. current: %{public}s vs callback's: %{public}s",
65 currentSourceInfo.ToString().c_str(), sourceInfo.ToString().c_str());
66 return;
67 }
68 LOGI("Image Load Success %{public}s", sourceInfo.ToString().c_str());
69 pattern->OnImageLoadSuccess();
70 };
71 }
72
CreateLoadFailCallback()73 LoadFailNotifyTask ImagePattern::CreateLoadFailCallback()
74 {
75 return [weak = WeakClaim(this)](const ImageSourceInfo& sourceInfo) {
76 auto pattern = weak.Upgrade();
77 CHECK_NULL_VOID(pattern);
78 auto imageLayoutProperty = pattern->GetLayoutProperty<ImageLayoutProperty>();
79 CHECK_NULL_VOID(imageLayoutProperty);
80 auto currentSourceInfo = imageLayoutProperty->GetImageSourceInfo().value_or(ImageSourceInfo(""));
81 if (currentSourceInfo != sourceInfo) {
82 LOGW("sourceInfo does not match, ignore current callback. current: %{public}s vs callback's: %{public}s",
83 currentSourceInfo.ToString().c_str(), sourceInfo.ToString().c_str());
84 return;
85 }
86 pattern->OnImageLoadFail();
87 };
88 }
89
PrepareAnimation(const RefPtr<CanvasImage> & image)90 void ImagePattern::PrepareAnimation(const RefPtr<CanvasImage>& image)
91 {
92 if (image->IsStatic()) {
93 return;
94 }
95 SetRedrawCallback(image);
96 RegisterVisibleAreaChange();
97 auto layoutProps = GetLayoutProperty<LayoutProperty>();
98 CHECK_NULL_VOID(layoutProps);
99 // pause animation if prop is initially set to invisible
100 if (layoutProps->GetVisibility().value_or(VisibleType::VISIBLE) != VisibleType::VISIBLE) {
101 image->ControlAnimation(false);
102 }
103 }
104
SetRedrawCallback(const RefPtr<CanvasImage> & image)105 void ImagePattern::SetRedrawCallback(const RefPtr<CanvasImage>& image)
106 {
107 CHECK_NULL_VOID_NOLOG(image);
108 // set animation flush function for svg / gif
109 image->SetRedrawCallback([weak = WeakPtr(GetHost())] {
110 auto imageNode = weak.Upgrade();
111 CHECK_NULL_VOID(imageNode);
112 imageNode->MarkNeedRenderOnly();
113 });
114 }
115
RegisterVisibleAreaChange()116 void ImagePattern::RegisterVisibleAreaChange()
117 {
118 auto pipeline = PipelineContext::GetCurrentContext();
119 // register to onVisibleAreaChange
120 CHECK_NULL_VOID(pipeline);
121 auto callback = [weak = WeakClaim(this)](bool visible, double ratio) {
122 auto self = weak.Upgrade();
123 CHECK_NULL_VOID(self);
124 LOGD("current image visible ratio = %f", ratio);
125 self->OnVisibleChange(visible);
126 };
127 auto host = GetHost();
128 CHECK_NULL_VOID(host);
129 // add visibleAreaChangeNode(inner callback)
130 pipeline->AddVisibleAreaChangeNode(host, 0.0f, callback, false);
131 }
132
CalcImageContentPaintSize(const RefPtr<GeometryNode> & geometryNode)133 RectF ImagePattern::CalcImageContentPaintSize(const RefPtr<GeometryNode>& geometryNode)
134 {
135 RectF paintSize;
136 auto imageRenderProperty = GetPaintProperty<ImageRenderProperty>();
137 CHECK_NULL_RETURN(imageRenderProperty, paintSize);
138 ImageRepeat repeat = imageRenderProperty->GetImageRepeat().value_or(ImageRepeat::NO_REPEAT);
139 bool imageRepeatX = repeat == ImageRepeat::REPEAT || repeat == ImageRepeat::REPEAT_X;
140 bool imageRepeatY = repeat == ImageRepeat::REPEAT || repeat == ImageRepeat::REPEAT_Y;
141
142 if (loadingCtx_->GetSourceInfo().IsSvg()) {
143 const float invalidValue = -1;
144 paintSize.SetWidth(dstRect_.IsValid() ? dstRect_.Width() : invalidValue);
145 paintSize.SetHeight(dstRect_.IsValid() ? dstRect_.Height() : invalidValue);
146 paintSize.SetLeft(
147 dstRect_.IsValid() ? dstRect_.GetX() + geometryNode->GetContentOffset().GetX() : invalidValue);
148 paintSize.SetTop(dstRect_.IsValid() ? dstRect_.GetY() + geometryNode->GetContentOffset().GetY() : invalidValue);
149 } else {
150 paintSize.SetWidth(imageRepeatX ? geometryNode->GetContentSize().Width() : dstRect_.Width());
151 paintSize.SetHeight(imageRepeatY ? geometryNode->GetContentSize().Height() : dstRect_.Height());
152 paintSize.SetLeft((imageRepeatX ? 0 : dstRect_.GetX()) + geometryNode->GetContentOffset().GetX());
153 paintSize.SetTop((imageRepeatY ? 0 : dstRect_.GetY()) + geometryNode->GetContentOffset().GetY());
154 }
155 return paintSize;
156 }
157
OnImageLoadSuccess()158 void ImagePattern::OnImageLoadSuccess()
159 {
160 auto host = GetHost();
161 CHECK_NULL_VOID(host);
162 const auto& geometryNode = host->GetGeometryNode();
163 CHECK_NULL_VOID(geometryNode);
164
165 image_ = loadingCtx_->MoveCanvasImage();
166 srcRect_ = loadingCtx_->GetSrcRect();
167 dstRect_ = loadingCtx_->GetDstRect();
168
169 RectF paintRect = CalcImageContentPaintSize(geometryNode);
170 LoadImageSuccessEvent event(loadingCtx_->GetImageSize().Width(), loadingCtx_->GetImageSize().Height(),
171 geometryNode->GetFrameSize().Width(), geometryNode->GetFrameSize().Height(), 1, paintRect.Width(),
172 paintRect.Height(), paintRect.GetX(), paintRect.GetY());
173 auto eventHub = GetEventHub<ImageEventHub>();
174 if (eventHub) {
175 eventHub->FireCompleteEvent(event);
176 }
177
178 SetImagePaintConfig(image_, srcRect_, dstRect_, loadingCtx_->GetSourceInfo().IsSvg());
179 PrepareAnimation(image_);
180 if (host->IsDraggable()) {
181 EnableDrag();
182 }
183 // clear alt data
184 altLoadingCtx_ = nullptr;
185 altImage_ = nullptr;
186 altDstRect_.reset();
187 altSrcRect_.reset();
188
189 host->MarkNeedRenderOnly();
190 }
191
OnImageDataReady()192 void ImagePattern::OnImageDataReady()
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 LoadImageSuccessEvent event(loadingCtx_->GetImageSize().Width(), loadingCtx_->GetImageSize().Height(),
201 geometryNode->GetFrameSize().Width(), geometryNode->GetFrameSize().Height(), 0,
202 geometryNode->GetContentSize().Width(), geometryNode->GetContentSize().Height(),
203 geometryNode->GetContentOffset().GetX(), geometryNode->GetContentOffset().GetY());
204 imageEventHub->FireCompleteEvent(event);
205
206 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
207 }
208
OnImageLoadFail()209 void ImagePattern::OnImageLoadFail()
210 {
211 auto host = GetHost();
212 CHECK_NULL_VOID(host);
213 const auto& geometryNode = host->GetGeometryNode();
214 auto imageEventHub = GetEventHub<ImageEventHub>();
215 CHECK_NULL_VOID(imageEventHub);
216 LoadImageFailEvent loadImageFailEvent_(
217 geometryNode->GetFrameSize().Width(), geometryNode->GetFrameSize().Height(), "");
218 // TODO: remove errorMsg in fail event
219 imageEventHub->FireErrorEvent(std::move(loadImageFailEvent_));
220 }
221
SetImagePaintConfig(const RefPtr<CanvasImage> & canvasImage,const RectF & srcRect,const RectF & dstRect,bool isSvg)222 void ImagePattern::SetImagePaintConfig(
223 const RefPtr<CanvasImage>& canvasImage, const RectF& srcRect, const RectF& dstRect, bool isSvg)
224 {
225 auto layoutProps = GetLayoutProperty<ImageLayoutProperty>();
226 CHECK_NULL_VOID(layoutProps);
227
228 ImagePaintConfig config {
229 .srcRect_ = srcRect,
230 .dstRect_ = dstRect,
231 };
232 config.imageFit_ = layoutProps->GetImageFit().value_or(ImageFit::COVER);
233 config.isSvg_ = isSvg;
234
235 canvasImage->SetPaintConfig(config);
236 }
237
CreateNodePaintMethod()238 RefPtr<NodePaintMethod> ImagePattern::CreateNodePaintMethod()
239 {
240 if (image_) {
241 return MakeRefPtr<ImagePaintMethod>(image_, selectOverlay_);
242 }
243 if (altImage_ && altDstRect_ && altSrcRect_) {
244 return MakeRefPtr<ImagePaintMethod>(altImage_, selectOverlay_);
245 }
246 CreateObscuredImage();
247 if (obscuredImage_) {
248 return MakeRefPtr<ImagePaintMethod>(obscuredImage_, selectOverlay_);
249 }
250 return nullptr;
251 }
252
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)253 bool ImagePattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
254 {
255 if (config.skipMeasure || dirty->SkipMeasureContent()) {
256 return false;
257 }
258 return image_;
259 }
260
CreateObscuredImage()261 void ImagePattern::CreateObscuredImage()
262 {
263 auto props = GetLayoutProperty<ImageLayoutProperty>();
264 CHECK_NULL_VOID(props);
265 auto layoutConstraint = props->GetLayoutConstraint();
266 CHECK_NULL_VOID_NOLOG(layoutConstraint);
267 auto host = GetHost();
268 CHECK_NULL_VOID(host);
269 auto sourceInfo = props->GetImageSourceInfo().value_or(ImageSourceInfo(""));
270 auto reasons = host->GetRenderContext()->GetObscured().value_or(std::vector<ObscuredReasons>());
271 if (reasons.size() && layoutConstraint->selfIdealSize.IsValid()) {
272 if (!obscuredImage_) {
273 obscuredImage_ = MakeRefPtr<ObscuredImage>();
274 SetImagePaintConfig(obscuredImage_, srcRect_, dstRect_, sourceInfo.IsSvg());
275 }
276 }
277 }
278
LoadImageDataIfNeed()279 void ImagePattern::LoadImageDataIfNeed()
280 {
281 auto imageLayoutProperty = GetLayoutProperty<ImageLayoutProperty>();
282 CHECK_NULL_VOID(imageLayoutProperty);
283 auto imageRenderProperty = GetPaintProperty<ImageRenderProperty>();
284 CHECK_NULL_VOID(imageRenderProperty);
285 auto src = imageLayoutProperty->GetImageSourceInfo().value_or(ImageSourceInfo(""));
286 UpdateInternalResource(src);
287
288 if (!loadingCtx_ || loadingCtx_->GetSourceInfo() != src) {
289 LoadNotifier loadNotifier(CreateDataReadyCallback(), CreateLoadSuccessCallback(), CreateLoadFailCallback());
290
291 loadingCtx_ = AceType::MakeRefPtr<ImageLoadingContext>(src, std::move(loadNotifier), syncLoad_);
292 LOGI("start loading image %{public}s", src.ToString().c_str());
293 loadingCtx_->LoadImageData();
294 }
295 if (loadingCtx_->NeedAlt() && imageLayoutProperty->GetAlt()) {
296 auto altImageSourceInfo = imageLayoutProperty->GetAlt().value_or(ImageSourceInfo(""));
297 LoadNotifier altLoadNotifier(CreateDataReadyCallbackForAlt(), CreateLoadSuccessCallbackForAlt(), nullptr);
298 if (!altLoadingCtx_ || altLoadingCtx_->GetSourceInfo() != altImageSourceInfo ||
299 (altLoadingCtx_ && altImageSourceInfo.IsSvg())) {
300 altLoadingCtx_ = AceType::MakeRefPtr<ImageLoadingContext>(altImageSourceInfo, std::move(altLoadNotifier));
301 altLoadingCtx_->LoadImageData();
302 }
303 }
304 }
305
OnModifyDone()306 void ImagePattern::OnModifyDone()
307 {
308 Pattern::OnModifyDone();
309 LoadImageDataIfNeed();
310
311 if (copyOption_ != CopyOptions::None) {
312 auto host = GetHost();
313 CHECK_NULL_VOID(host);
314 bool hasObscured = false;
315 if (host->GetRenderContext()->GetObscured().has_value()) {
316 auto obscuredReasons = host->GetRenderContext()->GetObscured().value();
317 hasObscured = std::any_of(obscuredReasons.begin(), obscuredReasons.end(),
318 [](const auto& reason) { return reason == ObscuredReasons::PLACEHOLDER; });
319 }
320 if (!hasObscured) {
321 InitCopy();
322 return;
323 }
324 }
325
326 CloseSelectOverlay();
327 // remove long press and mouse events
328 auto host = GetHost();
329 CHECK_NULL_VOID(host);
330
331 auto gestureHub = host->GetOrCreateGestureEventHub();
332 gestureHub->SetLongPressEvent(nullptr);
333 longPressEvent_ = nullptr;
334
335 gestureHub->RemoveClickEvent(clickEvent_);
336 clickEvent_ = nullptr;
337
338 auto inputHub = host->GetOrCreateInputEventHub();
339 inputHub->RemoveOnMouseEvent(mouseEvent_);
340 mouseEvent_ = nullptr;
341 }
342
CreateDataReadyCallbackForAlt()343 DataReadyNotifyTask ImagePattern::CreateDataReadyCallbackForAlt()
344 {
345 return [weak = WeakClaim(this)](const ImageSourceInfo& sourceInfo) {
346 auto pattern = weak.Upgrade();
347 CHECK_NULL_VOID(pattern);
348 auto imageLayoutProperty = pattern->GetLayoutProperty<ImageLayoutProperty>();
349 CHECK_NULL_VOID(imageLayoutProperty);
350 auto currentAltSourceInfo = imageLayoutProperty->GetAlt().value_or(ImageSourceInfo(""));
351 if (currentAltSourceInfo != sourceInfo) {
352 LOGW("alt image sourceInfo does not match, ignore current callback. current: %{public}s vs callback's: "
353 "%{public}s",
354 currentAltSourceInfo.ToString().c_str(), sourceInfo.ToString().c_str());
355 return;
356 }
357 auto host = pattern->GetHost();
358 CHECK_NULL_VOID(host);
359 if (!host->IsActive()) {
360 return;
361 }
362 const auto& geometryNode = host->GetGeometryNode();
363 CHECK_NULL_VOID(geometryNode);
364 if (!geometryNode->GetContent()) {
365 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
366 return;
367 }
368
369 // calculate params for [altLoadingCtx] to do [MakeCanvasImage] if component size is already settled
370 pattern->altLoadingCtx_->MakeCanvasImageIfNeed(
371 geometryNode->GetContentSize(), true, imageLayoutProperty->GetImageFit().value_or(ImageFit::COVER));
372 };
373 }
374
CreateLoadSuccessCallbackForAlt()375 LoadSuccessNotifyTask ImagePattern::CreateLoadSuccessCallbackForAlt()
376 {
377 return [weak = WeakClaim(this)](const ImageSourceInfo& sourceInfo) {
378 auto pattern = weak.Upgrade();
379 CHECK_NULL_VOID(pattern);
380 CHECK_NULL_VOID(pattern->altLoadingCtx_);
381 auto layoutProps = pattern->GetLayoutProperty<ImageLayoutProperty>();
382 auto currentAltSrc = layoutProps->GetAlt().value_or(ImageSourceInfo(""));
383 if (currentAltSrc != sourceInfo) {
384 LOGW("alt image sourceInfo does not match, ignore current callback. current: %{public}s vs callback's: "
385 "%{public}s",
386 currentAltSrc.ToString().c_str(), sourceInfo.ToString().c_str());
387 return;
388 }
389 pattern->altImage_ = pattern->altLoadingCtx_->MoveCanvasImage();
390 pattern->altSrcRect_ = std::make_unique<RectF>(pattern->altLoadingCtx_->GetSrcRect());
391 pattern->altDstRect_ = std::make_unique<RectF>(pattern->altLoadingCtx_->GetDstRect());
392 pattern->SetImagePaintConfig(pattern->altImage_, *pattern->altSrcRect_, *pattern->altDstRect_,
393 pattern->altLoadingCtx_->GetSourceInfo().IsSvg());
394
395 pattern->PrepareAnimation(pattern->altImage_);
396
397 auto host = pattern->GetHost();
398 CHECK_NULL_VOID(host);
399 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
400 };
401 }
402
UpdateInternalResource(ImageSourceInfo & sourceInfo)403 void ImagePattern::UpdateInternalResource(ImageSourceInfo& sourceInfo)
404 {
405 if (!sourceInfo.IsInternalResource()) {
406 return;
407 }
408
409 auto pipeline = PipelineBase::GetCurrentContext();
410 CHECK_NULL_VOID(pipeline);
411 auto iconTheme = pipeline->GetTheme<IconTheme>();
412 CHECK_NULL_VOID(iconTheme);
413 auto iconPath = iconTheme->GetIconPath(sourceInfo.GetResourceId());
414 if (!iconPath.empty()) {
415 sourceInfo.SetSrc(iconPath, sourceInfo.GetFillColor());
416 auto imageLayoutProperty = GetLayoutProperty<ImageLayoutProperty>();
417 CHECK_NULL_VOID(imageLayoutProperty);
418 imageLayoutProperty->UpdateImageSourceInfo(sourceInfo);
419 }
420 }
421
OnNotifyMemoryLevel(int32_t level)422 void ImagePattern::OnNotifyMemoryLevel(int32_t level)
423 {
424 LOGI("Receive Memory level notification, level: %{public}d", level);
425 // TODO: do different data cleaning operation according to level
426 // when image component is [onShow], do not clean image data
427 // TODO: use [isActive_] to determine image data management
428 if (isShow_) {
429 return;
430 }
431
432 // clean image data
433 loadingCtx_ = nullptr;
434 image_ = nullptr;
435 altLoadingCtx_ = nullptr;
436 altImage_ = nullptr;
437
438 // clean rs node to release the sk_sp<SkImage> held by it
439 // TODO: release PixelMap resource when use PixelMap resource to draw image
440 auto frameNode = GetHost();
441 CHECK_NULL_VOID(frameNode);
442 auto rsRenderContext = frameNode->GetRenderContext();
443 CHECK_NULL_VOID(rsRenderContext);
444 rsRenderContext->ClearDrawCommands();
445 auto pipeline = PipelineContext::GetCurrentContext();
446 CHECK_NULL_VOID(pipeline);
447 pipeline->FlushMessages();
448 }
449
OnWindowHide()450 void ImagePattern::OnWindowHide()
451 {
452 isShow_ = false;
453 }
454
OnWindowShow()455 void ImagePattern::OnWindowShow()
456 {
457 isShow_ = true;
458 LoadImageDataIfNeed();
459 }
460
OnVisibleChange(bool visible)461 void ImagePattern::OnVisibleChange(bool visible)
462 {
463 if (!visible) {
464 CloseSelectOverlay();
465 }
466 // control svg / gif animation
467 if (image_) {
468 image_->ControlAnimation(visible);
469 } else if (altImage_) {
470 altImage_->ControlAnimation(visible);
471 }
472 }
473
OnAttachToFrameNode()474 void ImagePattern::OnAttachToFrameNode()
475 {
476 auto host = GetHost();
477 CHECK_NULL_VOID(host);
478 auto renderCtx = host->GetRenderContext();
479 renderCtx->SetClipToBounds(false);
480 renderCtx->SetUsingContentRectForRenderFrame(true);
481
482 // register image frame node to pipeline context to receive memory level notification and window state change
483 // notification
484 auto pipeline = PipelineContext::GetCurrentContext();
485 CHECK_NULL_VOID(pipeline);
486 pipeline->AddNodesToNotifyMemoryLevel(host->GetId());
487 pipeline->AddWindowStateChangedCallback(host->GetId());
488 // set draggable for framenode
489 auto theme = pipeline->GetTheme<ImageTheme>();
490 CHECK_NULL_VOID_NOLOG(theme);
491 auto draggable = theme->GetDraggable();
492 if (draggable && !host->IsDraggable()) {
493 auto gestureHub = host->GetOrCreateGestureEventHub();
494 CHECK_NULL_VOID(gestureHub);
495 gestureHub->InitDragDropEvent();
496 }
497 host->SetDraggable(draggable);
498 }
499
OnDetachFromFrameNode(FrameNode * frameNode)500 void ImagePattern::OnDetachFromFrameNode(FrameNode* frameNode)
501 {
502 CloseSelectOverlay();
503
504 auto id = frameNode->GetId();
505 auto pipeline = AceType::DynamicCast<PipelineContext>(PipelineBase::GetCurrentContext());
506 CHECK_NULL_VOID_NOLOG(pipeline);
507 pipeline->RemoveWindowStateChangedCallback(id);
508 pipeline->RemoveNodesToNotifyMemoryLevel(id);
509 }
510
EnableDrag()511 void ImagePattern::EnableDrag()
512 {
513 auto host = GetHost();
514 CHECK_NULL_VOID(host);
515 auto dragStart = [weak = WeakClaim(this)](const RefPtr<OHOS::Ace::DragEvent>& event,
516 const std::string& /*extraParams*/) -> DragDropInfo {
517 DragDropInfo info;
518 auto imagePattern = weak.Upgrade();
519 CHECK_NULL_RETURN(imagePattern && imagePattern->loadingCtx_, info);
520
521 #ifdef ENABLE_DRAG_FRAMEWORK
522 AceEngineExt::GetInstance().DragStartExt();
523 #endif
524 imagePattern->UpdateDragEvent(event);
525 info.extraInfo = imagePattern->loadingCtx_->GetSourceInfo().GetSrc();
526 return info;
527 };
528 auto eventHub = host->GetEventHub<EventHub>();
529 CHECK_NULL_VOID(eventHub);
530 if (!eventHub->HasOnDragStart()) {
531 eventHub->SetOnDragStart(std::move(dragStart));
532 }
533 }
534
BetweenSelectedPosition(const Offset & globalOffset)535 bool ImagePattern::BetweenSelectedPosition(const Offset& globalOffset)
536 {
537 auto host = GetHost();
538 CHECK_NULL_RETURN(host, false);
539 auto globalRect = host->GetTransformRectRelativeToWindow();
540 return globalRect.IsInRegion(PointF { globalOffset.GetX(), globalOffset.GetY() });
541 }
542
BeforeCreatePaintWrapper()543 void ImagePattern::BeforeCreatePaintWrapper()
544 {
545 auto host = GetHost();
546 CHECK_NULL_VOID(host);
547 host->GetRenderContext()->MarkContentChanged(true);
548 }
549
InitCopy()550 void ImagePattern::InitCopy()
551 {
552 if (longPressEvent_ && mouseEvent_ && clickEvent_) {
553 return;
554 }
555 auto longPressTask = [weak = WeakClaim(this)](GestureEvent& info) {
556 auto pattern = weak.Upgrade();
557 CHECK_NULL_VOID(pattern);
558 pattern->OpenSelectOverlay();
559 };
560 longPressEvent_ = MakeRefPtr<LongPressEvent>(std::move(longPressTask));
561
562 auto host = GetHost();
563 CHECK_NULL_VOID(host);
564 auto gestureHub = host->GetOrCreateGestureEventHub();
565 gestureHub->SetLongPressEvent(longPressEvent_);
566
567 auto mouseTask = [weak = WeakClaim(this)](MouseInfo& info) {
568 if (info.GetButton() == MouseButton::RIGHT_BUTTON && info.GetAction() == MouseAction::PRESS) {
569 auto pattern = weak.Upgrade();
570 CHECK_NULL_VOID_NOLOG(pattern);
571 pattern->OpenSelectOverlay();
572 }
573 };
574 mouseEvent_ = MakeRefPtr<InputEvent>(std::move(mouseTask));
575 auto inputHub = host->GetOrCreateInputEventHub();
576 CHECK_NULL_VOID(inputHub);
577 inputHub->AddOnMouseEvent(mouseEvent_);
578
579 // close overlay on click
580 clickEvent_ = MakeRefPtr<ClickEvent>([weak = WeakClaim(this)](GestureEvent& callback) {
581 auto pattern = weak.Upgrade();
582 CHECK_NULL_VOID(pattern);
583 pattern->CloseSelectOverlay();
584 });
585 gestureHub->AddClickEvent(clickEvent_);
586 }
587
OpenSelectOverlay()588 void ImagePattern::OpenSelectOverlay()
589 {
590 auto host = GetHost();
591 CHECK_NULL_VOID(host);
592 auto rect = host->GetTransformRectRelativeToWindow();
593 SelectOverlayInfo info;
594 SizeF handleSize = { SelectHandleInfo::GetDefaultLineWidth().ConvertToPx(), info.singleLineHeight };
595 info.firstHandle.paintRect = RectF(rect.GetOffset(), handleSize);
596 OffsetF offset(rect.Width() - handleSize.Width(), rect.Height() - handleSize.Height());
597 info.secondHandle.paintRect = RectF(rect.GetOffset() + offset, handleSize);
598 info.menuInfo.menuIsShow = true;
599 info.menuInfo.showCut = false;
600 info.menuInfo.showPaste = false;
601 info.menuCallback.onCopy = [weak = WeakClaim(this)]() {
602 auto pattern = weak.Upgrade();
603 CHECK_NULL_VOID(pattern);
604 pattern->HandleCopy();
605 pattern->CloseSelectOverlay();
606 };
607 info.onHandleMoveDone = [weak = WeakClaim(this), firstRect = info.firstHandle.paintRect,
608 secondRect = info.secondHandle.paintRect](const RectF&, bool isFirst) {
609 // reset handle position
610 auto pattern = weak.Upgrade();
611 CHECK_NULL_VOID(pattern && pattern->selectOverlay_);
612 SelectHandleInfo info;
613 if (isFirst) {
614 info.paintRect = firstRect;
615 pattern->selectOverlay_->UpdateFirstSelectHandleInfo(info);
616 } else {
617 info.paintRect = secondRect;
618 pattern->selectOverlay_->UpdateSecondSelectHandleInfo(info);
619 }
620 };
621 info.onClose = [weak = WeakClaim(this)](bool closedByGlobalEvent) {
622 if (closedByGlobalEvent) {
623 auto pattern = weak.Upgrade();
624 CHECK_NULL_VOID(pattern);
625 pattern->CloseSelectOverlay();
626 }
627 };
628
629 CloseSelectOverlay();
630 auto pipeline = PipelineContext::GetCurrentContext();
631 CHECK_NULL_VOID(pipeline);
632 LOGI("Opening select overlay");
633 selectOverlay_ = pipeline->GetSelectOverlayManager()->CreateAndShowSelectOverlay(info, WeakClaim(this));
634
635 // paint selected mask effect
636 host->MarkNeedRenderOnly();
637 }
638
CloseSelectOverlay()639 void ImagePattern::CloseSelectOverlay()
640 {
641 if (!selectOverlay_) {
642 return;
643 }
644 if (!selectOverlay_->IsClosed()) {
645 LOGI("closing select overlay");
646 selectOverlay_->Close();
647 }
648 selectOverlay_ = nullptr;
649 // remove selected mask effect
650 auto host = GetHost();
651 CHECK_NULL_VOID(host);
652 host->MarkNeedRenderOnly();
653 }
654
HandleCopy()655 void ImagePattern::HandleCopy()
656 {
657 CHECK_NULL_VOID(image_);
658 if (!clipboard_) {
659 auto pipeline = PipelineContext::GetCurrentContext();
660 CHECK_NULL_VOID(pipeline);
661 clipboard_ = ClipboardProxy::GetInstance()->GetClipboard(pipeline->GetTaskExecutor());
662 }
663 auto pixmap = image_->GetPixelMap();
664 if (pixmap) {
665 clipboard_->SetPixelMapData(pixmap, copyOption_);
666 } else {
667 auto host = GetHost();
668 CHECK_NULL_VOID(host);
669 clipboard_->SetData(loadingCtx_->GetSourceInfo().GetSrc());
670 }
671 }
672
ToJsonValue(std::unique_ptr<JsonValue> & json) const673 void ImagePattern::ToJsonValue(std::unique_ptr<JsonValue>& json) const
674 {
675 static const char* COPY_OPTIONS[] = { "CopyOptions.None", "CopyOptions.InApp", "CopyOptions.Local",
676 "CopyOptions.Distributed" };
677 json->Put("copyOption", COPY_OPTIONS[static_cast<int32_t>(copyOption_)]);
678
679 json->Put("syncLoad", syncLoad_ ? "true" : "false");
680 auto host = GetHost();
681 CHECK_NULL_VOID(host);
682 json->Put("draggable", host->IsDraggable() ? "true" : "false");
683 }
684
UpdateFillColorIfForegroundColor()685 void ImagePattern::UpdateFillColorIfForegroundColor()
686 {
687 auto frameNode = GetHost();
688 CHECK_NULL_VOID(frameNode);
689 auto renderContext = frameNode->GetRenderContext();
690 CHECK_NULL_VOID(renderContext);
691 if (renderContext->HasForegroundColor() || renderContext->HasForegroundColorStrategy()) {
692 auto imageLayoutProperty = frameNode->GetLayoutProperty<ImageLayoutProperty>();
693 auto imageSourceInfo = imageLayoutProperty->GetImageSourceInfo().value();
694 if (imageSourceInfo.IsSvg()) {
695 imageSourceInfo.SetFillColor(Color::FOREGROUND);
696 imageLayoutProperty->UpdateImageSourceInfo(imageSourceInfo);
697 }
698 auto imageRenderProperty = frameNode->GetPaintProperty<ImageRenderProperty>();
699 CHECK_NULL_VOID(imageRenderProperty);
700 imageRenderProperty->UpdateSvgFillColor(Color::FOREGROUND);
701 }
702 }
703
DumpInfo()704 void ImagePattern::DumpInfo()
705 {
706 auto layoutProp = GetLayoutProperty<ImageLayoutProperty>();
707 CHECK_NULL_VOID(layoutProp);
708 if (layoutProp->GetImageSourceInfo().has_value()) {
709 DumpLog::GetInstance().AddDesc(std::string("url: ").append(layoutProp->GetImageSourceInfo()->ToString()));
710 }
711 }
712
UpdateDragEvent(const RefPtr<OHOS::Ace::DragEvent> & event)713 void ImagePattern::UpdateDragEvent(const RefPtr<OHOS::Ace::DragEvent>& event)
714 {
715 #ifdef ENABLE_DRAG_FRAMEWORK
716 RefPtr<UnifiedData> unifiedData = UdmfClient::GetInstance()->CreateUnifiedData();
717 CHECK_NULL_VOID(loadingCtx_ && image_);
718 if (loadingCtx_->GetSourceInfo().IsPixmap()) {
719 auto pixelMap = image_->GetPixelMap();
720 CHECK_NULL_VOID(pixelMap);
721 const uint8_t* pixels = pixelMap->GetPixels();
722 CHECK_NULL_VOID(pixels);
723 int32_t length = pixelMap->GetByteCount();
724 std::vector<uint8_t> data(pixels, pixels + length);
725 UdmfClient::GetInstance()->AddPixelMapRecord(unifiedData, data);
726 } else {
727 UdmfClient::GetInstance()->AddImageRecord(unifiedData, loadingCtx_->GetSourceInfo().GetSrc());
728 }
729 event->SetData(unifiedData);
730 #endif
731 }
732
OnLanguageConfigurationUpdate()733 void ImagePattern::OnLanguageConfigurationUpdate()
734 {
735 CHECK_NULL_VOID_NOLOG(loadingCtx_);
736 auto&& src = loadingCtx_->GetSourceInfo();
737 // Resource image needs to reload when Language changes
738 if (src.GetSrcType() == SrcType::RESOURCE) {
739 loadingCtx_.Reset();
740 }
741 }
742 } // namespace OHOS::Ace::NG
743