• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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