• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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/text_overlay/render_text_overlay.h"
17 
18 #include "core/animation/scheduler.h"
19 #include "core/components/container_modal/container_modal_constants.h"
20 #include "core/components/focus_collaboration/render_focus_collaboration.h"
21 #include "core/components/stack/stack_element.h"
22 #ifdef WEB_SUPPORTED
23 #include "core/components/web/render_web.h"
24 #endif
25 
26 namespace OHOS::Ace {
27 namespace {
28 
29 const Offset DOT1_OFFSET = Offset(-0.790737726, -1.290737726);
30 const Offset DOT2_OFFSET = Offset(-0.623475836, -1.290737726);
31 const Offset DOT3_OFFSET = Offset(-0.790737726, -0.123475836);
32 const Offset DOT4_OFFSET = Offset(0.790737726, 1.290737726);
33 const Offset END_POINT = DOT1_POSITION + DOT1_OFFSET;
34 constexpr Dimension TOOL_BAR_HEIGHT = 40.0_vp;
35 constexpr Dimension HANDLE_HOTZONE_DIAMETER = 20.0_vp;
36 constexpr Dimension MORE_BUTTON_SIZE = 40.0_vp;
37 constexpr Dimension ANIMATION_OFFSET_X = 16.0_vp;
38 constexpr double DEFAULT_SPACING = 10.0;
39 constexpr double FIFTY_PERCENT = 0.5;
40 constexpr double ROTATE_DEGREE = -45.0;
41 constexpr double CLIP_WIDTH = 1.0;
42 constexpr double OPACITY_KEYFRAME = 250.0 / 350.0; // Clip and translate animation is 350ms, opacity animation is 250ms.
43 constexpr float KEYFRAME_PERCENT_THIRTY = 0.33f;
44 constexpr float KEYFRAME_BEGINNING = 0.0f;
45 constexpr float KEYFRAME_ENDING = 1.0f;
46 constexpr int32_t MORE_ANIMATION_DURATION = 300; // Duration of more icon animation.
47 constexpr int32_t ANIMATION_DURATION = 350;      // Duration of clip and translate animation
48 
49 } // namespace
50 
RenderTextOverlay()51 RenderTextOverlay::RenderTextOverlay()
52 {
53     clickDetector_ = AceType::MakeRefPtr<ClickRecognizer>();
54     clickDetector_->SetOnClick([weak = AceType::WeakClaim(this)](const ClickInfo& clickInfo) {
55         auto overlay = weak.Upgrade();
56         if (overlay) {
57             overlay->HandleClick(clickInfo.GetLocalLocation());
58         }
59     });
60 
61     dragDetector_ = AceType::MakeRefPtr<DragRecognizer>(Axis::FREE);
62     dragDetector_->SetOnDragStart([weak = AceType::WeakClaim(this)](const DragStartInfo& startInfo) {
63         auto overlay = weak.Upgrade();
64         if (overlay) {
65             overlay->HandleDragStart(startInfo.GetLocalLocation());
66         }
67     });
68 
69     dragDetector_->SetOnDragUpdate([weak = AceType::WeakClaim(this)](const DragUpdateInfo& updateInfo) {
70         auto overlay = weak.Upgrade();
71         if (overlay) {
72             overlay->HandleDragUpdateAndEnd(updateInfo.GetLocalLocation());
73         }
74     });
75 
76     dragDetector_->SetOnDragEnd([weak = AceType::WeakClaim(this)](const DragEndInfo& endInfo) {
77         auto overlay = weak.Upgrade();
78         if (overlay) {
79             overlay->HandleDragUpdateAndEnd(endInfo.GetLocalLocation());
80             overlay->isDragging_ = false;
81         }
82     });
83 
84     touchDetector_ = AceType::MakeRefPtr<RawRecognizer>();
85     touchDetector_->SetOnTouchDown([weak = AceType::WeakClaim(this)](const TouchEventInfo& info) {
86         auto overlay = weak.Upgrade();
87         if (overlay) {
88             overlay->showMagnifier_ = true;
89             auto startOffset = info.GetTouches().front().GetLocalLocation();
90             if (overlay->startHandleRegion_.ContainsInRegion(startOffset.GetX(), startOffset.GetY())) {
91                 overlay->isTouchStartDrag_ = true;
92                 overlay->isTouchEndDrag_ = false;
93             } else {
94                 overlay->isTouchStartDrag_ = false;
95                 overlay->isTouchEndDrag_ =
96                     overlay->endHandleRegion_.ContainsInRegion(startOffset.GetX(), startOffset.GetY());
97             }
98         }
99     });
100 
101     touchDetector_->SetOnTouchUp([weak = AceType::WeakClaim(this)](const TouchEventInfo&) {
102         auto overlay = weak.Upgrade();
103         if (overlay) {
104             overlay->showMagnifier_ = false;
105         }
106     });
107 }
108 
~RenderTextOverlay()109 RenderTextOverlay::~RenderTextOverlay()
110 {
111     auto renderTextField = weakTextField_.Upgrade();
112     if (renderTextField) {
113         renderTextField->SetIsOverlayShowed(false, needStartTwinkling_);
114     }
115     auto spOverlayComponent = overlayComponent_.Upgrade();
116     if (spOverlayComponent) {
117         RemoveBackendEvent(spOverlayComponent);
118     }
119     auto context = GetContext().Upgrade();
120     if (context) {
121         auto textOverlayManager = context->GetTextOverlayManager();
122         if (textOverlayManager) {
123             textOverlayManager->ClearTextOverlayRect();
124         }
125     }
126 }
127 
Update(const RefPtr<Component> & component)128 void RenderTextOverlay::Update(const RefPtr<Component>& component)
129 {
130     auto overlay = AceType::DynamicCast<TextOverlayComponent>(component);
131     if (!overlay) {
132         return;
133     }
134     overlayComponent_ = overlay;
135     overlay->SetPopOverlay([weak = WeakClaim(this)]() {
136         auto overlay = weak.Upgrade();
137         if (overlay) {
138             overlay->needCloseKeyboard_ = false;
139             overlay->PopOverlay();
140         }
141     });
142     onFocusChange_ = overlay->GetOnFocusChange();
143     onCut_ = overlay->GetOnCut();
144     onCopy_ = overlay->GetOnCopy();
145     onPaste_ = overlay->GetOnPaste();
146     onCopyAll_ = overlay->GetOnCopyAll();
147     startHandleOffset_ = overlay->GetStartHandleOffset();
148     endHandleOffset_ = overlay->GetEndHandleOffset();
149     mouseOffset_ = overlay->GetMouseOffset();
150     onStartHandleMove_ = overlay->GetOnStartHandleMove();
151     onEndHandleMove_ = overlay->GetOnEndHandleMove();
152     isSingleHandle_ = overlay->GetIsSingleHandle() || (startHandleOffset_ == endHandleOffset_);
153     lineHeight_ = overlay->GetLineHeight();
154     startHandleHeight_ = overlay->GetStartHandleHeight();
155     endHandleHeight_ = overlay->GetEndHandleHeight();
156     handleDiameter_ = overlay->GetHandleDiameter();
157     menuSpacingWithHandle_ = handleDiameter_;
158     handleDiameterInner_ = overlay->GetHandleDiameterInner();
159     handleRadius_ = handleDiameter_ / 2.0;
160     handleRadiusInner_ = handleDiameterInner_ / 2.0;
161     menuSpacingWithText_ = overlay->GetMenuSpacingWithText();
162     handleColor_ = overlay->GetHandleColor();
163     handleColorInner_ = overlay->GetHandleColorInner();
164     clipRect_ = overlay->GetClipRect();
165     textDirection_ = overlay->GetTextDirection();
166     realTextDirection_ = overlay->GetRealTextDirection();
167     isUsingMouse_ = overlay->GetIsUsingMouse();
168     needClipRect_ = overlay->GetNeedCilpRect();
169     BindBackendEvent(overlay);
170     UpdateWeakTextField(overlay);
171     UpdateWeakText(overlay);
172     UpdateWeakImage(overlay);
173 #ifdef WEB_SUPPORTED
174     UpdateWeakWeb(overlay);
175 #endif
176     MarkNeedLayout();
177 }
178 
BindBackendEvent(const RefPtr<TextOverlayComponent> & overlay)179 void RenderTextOverlay::BindBackendEvent(const RefPtr<TextOverlayComponent>& overlay)
180 {
181     auto context = context_.Upgrade();
182     if (context && context->GetIsDeclarative() && !isUsingMouse_) {
183         BindBackendEventV2(overlay);
184     } else {
185         BackEndEventManager<void()>::GetInstance().BindBackendEvent(
186             overlay->GetCutButtonMarker(), [weak = WeakClaim(this)]() {
187                 auto overlay = weak.Upgrade();
188                 if (overlay) {
189                     overlay->HandleCut();
190                 }
191             });
192 
193         BackEndEventManager<void()>::GetInstance().BindBackendEvent(
194             overlay->GetCopyButtonMarker(), [weak = WeakClaim(this)]() {
195                 auto overlay = weak.Upgrade();
196                 if (overlay) {
197                     overlay->HandleCopy();
198                 }
199             });
200 
201         BackEndEventManager<void()>::GetInstance().BindBackendEvent(
202             overlay->GetPasteButtonMarker(), [weak = WeakClaim(this)]() {
203                 auto overlay = weak.Upgrade();
204                 if (overlay) {
205                     overlay->HandlePaste();
206                 }
207             });
208 
209         BackEndEventManager<void()>::GetInstance().BindBackendEvent(
210             overlay->GetCopyAllButtonMarker(), [weak = WeakClaim(this)]() {
211                 auto overlay = weak.Upgrade();
212                 if (overlay) {
213                     overlay->HandleCopyAll();
214                 }
215             });
216         BackEndEventManager<void()>::GetInstance().BindBackendEvent(
217             overlay->GetMoreButtonMarker(), [weak = WeakClaim(this)]() {
218                 auto overlay = weak.Upgrade();
219                 if (overlay) {
220                     overlay->HandleMoreButtonClick();
221                 }
222             });
223     }
224 }
225 
BindBackendEventV2(const RefPtr<TextOverlayComponent> & overlay)226 void RenderTextOverlay::BindBackendEventV2(const RefPtr<TextOverlayComponent>& overlay)
227 {
228     BackEndEventManager<void(const ClickInfo& info)>::GetInstance().BindBackendEvent(
229         overlay->GetCutButtonMarker(), [weak = WeakClaim(this)](const ClickInfo& info) {
230             auto overlay = weak.Upgrade();
231             if (overlay) {
232                 overlay->HandleCut();
233             }
234         });
235 
236     BackEndEventManager<void(const ClickInfo& info)>::GetInstance().BindBackendEvent(
237         overlay->GetCopyButtonMarker(), [weak = WeakClaim(this)](const ClickInfo& info) {
238             auto overlay = weak.Upgrade();
239             if (overlay) {
240                 overlay->HandleCopy();
241             }
242         });
243 
244     BackEndEventManager<void(const ClickInfo& info)>::GetInstance().BindBackendEvent(
245         overlay->GetPasteButtonMarker(), [weak = WeakClaim(this)](const ClickInfo& info) {
246             auto overlay = weak.Upgrade();
247             if (overlay) {
248                 overlay->HandlePaste();
249             }
250         });
251 
252     BackEndEventManager<void(const ClickInfo& info)>::GetInstance().BindBackendEvent(
253         overlay->GetCopyAllButtonMarker(), [weak = WeakClaim(this)](const ClickInfo& info) {
254             auto overlay = weak.Upgrade();
255             if (overlay) {
256                 overlay->HandleCopyAll();
257             }
258         });
259     BackEndEventManager<void(const ClickInfo& info)>::GetInstance().BindBackendEvent(
260         overlay->GetMoreButtonMarker(), [weak = WeakClaim(this)](const ClickInfo& info) {
261             auto overlay = weak.Upgrade();
262             if (overlay) {
263                 overlay->HandleMoreButtonClick();
264             }
265         });
266 }
267 
RemoveBackendEvent(const RefPtr<TextOverlayComponent> & overlay)268 void RenderTextOverlay::RemoveBackendEvent(const RefPtr<TextOverlayComponent>& overlay)
269 {
270     auto context = context_.Upgrade();
271     if (context && context->GetIsDeclarative() && !isUsingMouse_) {
272         BackEndEventManager<void(const ClickInfo& info)>::GetInstance().RemoveBackEndEvent(
273             overlay->GetCutButtonMarker());
274         BackEndEventManager<void(const ClickInfo& info)>::GetInstance().RemoveBackEndEvent(
275             overlay->GetCopyButtonMarker());
276         BackEndEventManager<void(const ClickInfo& info)>::GetInstance().RemoveBackEndEvent(
277             overlay->GetPasteButtonMarker());
278         BackEndEventManager<void(const ClickInfo& info)>::GetInstance().RemoveBackEndEvent(
279             overlay->GetCopyAllButtonMarker());
280         BackEndEventManager<void(const ClickInfo& info)>::GetInstance().RemoveBackEndEvent(
281             overlay->GetMoreButtonMarker());
282     } else {
283         BackEndEventManager<void()>::GetInstance().RemoveBackEndEvent(overlay->GetCutButtonMarker());
284         BackEndEventManager<void()>::GetInstance().RemoveBackEndEvent(overlay->GetCopyButtonMarker());
285         BackEndEventManager<void()>::GetInstance().RemoveBackEndEvent(overlay->GetPasteButtonMarker());
286         BackEndEventManager<void()>::GetInstance().RemoveBackEndEvent(overlay->GetCopyAllButtonMarker());
287         BackEndEventManager<void()>::GetInstance().RemoveBackEndEvent(overlay->GetMoreButtonMarker());
288     }
289 }
290 
UpdateWeakTextField(const RefPtr<TextOverlayComponent> & overlay)291 void RenderTextOverlay::UpdateWeakTextField(const RefPtr<TextOverlayComponent>& overlay)
292 {
293     if (!overlay) {
294         return;
295     }
296     weakTextField_ = overlay->GetWeakTextField();
297     auto renderTextField = weakTextField_.Upgrade();
298     if (!renderTextField) {
299         return;
300     }
301     auto callback = [weak = WeakClaim(this)](const OverlayShowOption& option) {
302         auto overlay = weak.Upgrade();
303         if (!overlay) {
304             return;
305         }
306         if (option.updateOverlayType == UpdateOverlayType::CLICK ||
307             option.updateOverlayType == UpdateOverlayType::LONG_PRESS) {
308             overlay->childRightBoundary_ = 0.0;
309         }
310         overlay->SetVisible(true);
311         overlay->showOption_ = option;
312         overlay->startHandleOffset_ = option.startHandleOffset;
313         overlay->endHandleOffset_ = option.endHandleOffset;
314         overlay->isSingleHandle_ = option.isSingleHandle;
315         if (option.updateOverlayType == UpdateOverlayType::CLICK) {
316             if (overlay->onRebuild_) {
317                 overlay->hasMenu_ = false;
318                 overlay->onRebuild_(true, false, false, false, false);
319             }
320         } else if (option.updateOverlayType == UpdateOverlayType::LONG_PRESS) {
321             if (overlay->onRebuild_) {
322                 overlay->hasMenu_ = false;
323                 overlay->onRebuild_(false, true, false, true, false);
324             }
325         }
326     };
327     renderTextField->SetUpdateHandlePosition(callback);
328 
329     auto callbackDiameter = [weak = WeakClaim(this)](const double& value) {
330         auto overlay = weak.Upgrade();
331         if (!overlay) {
332             LOGE("UpdateWeakTextField error, overlay is nullptr");
333             return;
334         }
335 
336         overlay->SetVisible(true);
337         if (overlay->onRebuild_) {
338             overlay->onRebuild_(overlay->isSingleHandle_, !overlay->isSingleHandle_, overlay->hasMenu_,
339                 !overlay->isSingleHandle_, false);
340         }
341         overlay->handleDiameter_ = Dimension(value, DimensionUnit::VP);
342         overlay->handleRadius_ = overlay->handleDiameter_ * FIFTY_PERCENT;
343     };
344     renderTextField->SetUpdateHandleDiameter(callbackDiameter);
345 
346     auto callbackDiameterInner = [weak = WeakClaim(this)](const double& value) {
347         auto overlay = weak.Upgrade();
348         if (!overlay) {
349             LOGE("UpdateWeakTextField error, overlay is nullptr");
350             return;
351         }
352 
353         overlay->SetVisible(true);
354         if (overlay->onRebuild_) {
355             overlay->onRebuild_(overlay->isSingleHandle_, !overlay->isSingleHandle_, overlay->hasMenu_,
356                 !overlay->isSingleHandle_, false);
357         }
358         overlay->handleDiameterInner_ = Dimension(value, DimensionUnit::VP);
359         overlay->handleRadiusInner_ = overlay->handleDiameterInner_ * FIFTY_PERCENT;
360     };
361     renderTextField->SetUpdateHandleDiameterInner(callbackDiameterInner);
362 
363     auto onValueChange = [weak = WeakClaim(this)] {
364         auto overlay = weak.Upgrade();
365         if (overlay) {
366             overlay->needCloseKeyboard_ = false;
367             overlay->PopOverlay();
368         }
369     };
370     renderTextField->SetOnValueChange(onValueChange);
371 
372     auto onKeyboardClose = [weak = WeakClaim(this)](bool forceCloseKeyboard) {
373         auto overlay = weak.Upgrade();
374         if (overlay) {
375             overlay->needCloseKeyboard_ = !forceCloseKeyboard;
376             overlay->needStartTwinkling_ = !forceCloseKeyboard;
377             overlay->PopOverlay();
378         }
379     };
380     renderTextField->SetOnKeyboardClose(onKeyboardClose);
381 
382     auto onClipRectChanged = [weak = WeakClaim(this)](const Rect& clipRect) {
383         auto overlay = weak.Upgrade();
384         if (overlay && (overlay->clipRect_ != clipRect)) {
385             overlay->clipRect_ = clipRect;
386             overlay->MarkNeedLayout();
387         }
388     };
389     renderTextField->SetOnClipRectChanged(onClipRectChanged);
390 }
391 
UpdateWeakText(const RefPtr<TextOverlayComponent> & overlay)392 void RenderTextOverlay::UpdateWeakText(const RefPtr<TextOverlayComponent>& overlay)
393 {
394     if (!overlay) {
395         return;
396     }
397     weakText_ = overlay->GetWeakText();
398     auto renderText = weakText_.Upgrade();
399     if (!renderText) {
400         return;
401     }
402     auto callback = [weak = WeakClaim(this)](const OverlayShowOption& option) {
403         auto overlay = weak.Upgrade();
404         if (!overlay) {
405             return;
406         }
407         if (option.updateOverlayType == UpdateOverlayType::CLICK ||
408             option.updateOverlayType == UpdateOverlayType::LONG_PRESS) {
409             overlay->childRightBoundary_ = 0.0;
410         }
411         overlay->SetVisible(true);
412         overlay->showOption_ = option;
413         overlay->startHandleOffset_ = option.startHandleOffset;
414         overlay->endHandleOffset_ = option.endHandleOffset;
415         overlay->isSingleHandle_ = option.isSingleHandle;
416         if (option.updateOverlayType == UpdateOverlayType::CLICK) {
417             if (overlay->onRebuild_) {
418                 overlay->hasMenu_ = false;
419                 overlay->onRebuild_(true, false, false, false, false);
420             }
421         } else if (option.updateOverlayType == UpdateOverlayType::LONG_PRESS) {
422             if (overlay->onRebuild_) {
423                 overlay->hasMenu_ = false;
424                 overlay->onRebuild_(false, true, false, true, false);
425             }
426         }
427     };
428     renderText->SetUpdateHandlePosition(callback);
429 
430     auto callbackDiameter = [weak = WeakClaim(this)](const double& value) {
431         auto overlay = weak.Upgrade();
432         if (!overlay) {
433             LOGE("UpdateWeakText error, overlay is nullptr");
434             return;
435         }
436 
437         overlay->SetVisible(true);
438         if (overlay->onRebuild_) {
439             overlay->onRebuild_(overlay->isSingleHandle_, !overlay->isSingleHandle_, overlay->hasMenu_,
440                 !overlay->isSingleHandle_, false);
441         }
442         overlay->handleDiameter_ = Dimension(value, DimensionUnit::VP);
443         overlay->handleRadius_ = overlay->handleDiameter_ * FIFTY_PERCENT;
444     };
445     renderText->SetUpdateHandleDiameter(callbackDiameter);
446 
447     auto callbackDiameterInner = [weak = WeakClaim(this)](const double& value) {
448         auto overlay = weak.Upgrade();
449         if (!overlay) {
450             LOGE("UpdateWeakText error, overlay is nullptr");
451             return;
452         }
453 
454         overlay->SetVisible(true);
455         if (overlay->onRebuild_) {
456             overlay->onRebuild_(overlay->isSingleHandle_, !overlay->isSingleHandle_, overlay->hasMenu_,
457                 !overlay->isSingleHandle_, false);
458         }
459         overlay->handleDiameterInner_ = Dimension(value, DimensionUnit::VP);
460         overlay->handleRadiusInner_ = overlay->handleDiameterInner_ * FIFTY_PERCENT;
461     };
462     renderText->SetUpdateHandleDiameterInner(callbackDiameterInner);
463 
464     auto onClipRectChanged = [weak = WeakClaim(this)](const Rect& clipRect) {
465         auto overlay = weak.Upgrade();
466         if (overlay && (overlay->clipRect_ != clipRect)) {
467             overlay->clipRect_ = clipRect;
468             overlay->MarkNeedLayout();
469         }
470     };
471     renderText->SetOnClipRectChanged(onClipRectChanged);
472 }
473 
UpdateWeakImage(const RefPtr<TextOverlayComponent> & overlay)474 void RenderTextOverlay::UpdateWeakImage(const RefPtr<TextOverlayComponent>& overlay)
475 {
476     if (!overlay) {
477         return;
478     }
479     weakImage_ = overlay->GetWeakImage();
480     auto renderImage = weakImage_.Upgrade();
481     if (!renderImage) {
482         return;
483     }
484     auto callback = [weak = WeakClaim(this)](const OverlayShowOption& option) {
485         auto overlay = weak.Upgrade();
486         if (!overlay) {
487             return;
488         }
489         if (option.updateOverlayType == UpdateOverlayType::CLICK ||
490             option.updateOverlayType == UpdateOverlayType::LONG_PRESS) {
491             overlay->childRightBoundary_ = 0.0;
492         }
493         overlay->SetVisible(true);
494         overlay->showOption_ = option;
495         overlay->startHandleOffset_ = option.startHandleOffset;
496         overlay->endHandleOffset_ = option.endHandleOffset;
497         overlay->isSingleHandle_ = option.isSingleHandle;
498         if (option.updateOverlayType == UpdateOverlayType::CLICK) {
499             if (overlay->onRebuild_) {
500                 overlay->hasMenu_ = false;
501                 overlay->onRebuild_(true, false, false, false, false);
502             }
503         } else if (option.updateOverlayType == UpdateOverlayType::LONG_PRESS) {
504             if (overlay->onRebuild_) {
505                 overlay->hasMenu_ = false;
506                 overlay->onRebuild_(false, true, false, true, false);
507             }
508         }
509     };
510     renderImage->SetUpdateHandlePosition(callback);
511 }
512 
513 #ifdef WEB_SUPPORTED
UpdateWeakWeb(const RefPtr<TextOverlayComponent> & overlay)514 void RenderTextOverlay::UpdateWeakWeb(const RefPtr<TextOverlayComponent>& overlay)
515 {
516     if (!overlay) {
517         return;
518     }
519     weakWeb_ = overlay->GetWeakWeb();
520     auto web = weakWeb_.Upgrade();
521     if (!touchDetector_ || !web) {
522         return;
523     }
524     isUsedByWeb_ = true;
525     auto callback = [weak = WeakClaim(this)](const OverlayShowOption& option, float startHeight, float endHeight) {
526         auto overlay = weak.Upgrade();
527         if (!overlay) {
528             return;
529         }
530         overlay->startHandleOffset_ = option.startHandleOffset;
531         overlay->endHandleOffset_ = option.endHandleOffset;
532         overlay->isSingleHandle_ = option.isSingleHandle;
533         overlay->showOption_.showMenu = option.showMenu;
534         overlay->showOption_.showStartHandle = option.showStartHandle;
535         overlay->showOption_.showEndHandle = option.showEndHandle;
536         overlay->startHandleHeight_ = startHeight;
537         overlay->endHandleHeight_ = endHeight;
538         overlay->lineHeight_ = startHeight;
539         overlay->MarkNeedLayout();
540     };
541     web->SetUpdateHandlePosition(callback);
542     showOption_.showMenu = web->TextOverlayMenuShouldShow();
543     showOption_.showStartHandle = web->GetShowStartTouchHandle();
544     showOption_.showEndHandle = web->GetShowEndTouchHandle();
545 
546     clickDetector_->SetOnClick([weak = AceType::WeakClaim(this)](const ClickInfo& clickInfo) {});
547     touchDetector_->SetOnTouchDown([weak = AceType::WeakClaim(this), weakWeb = weakWeb_](const TouchEventInfo& info) {
548         auto overlay = weak.Upgrade();
549         if (overlay) {
550             overlay->showMagnifier_ = true;
551             auto startOffset = info.GetTouches().front().GetLocalLocation();
552             if (overlay->startHandleRegion_.ContainsInRegion(startOffset.GetX(), startOffset.GetY())) {
553                 overlay->isTouchStartDrag_ = true;
554                 overlay->isTouchEndDrag_ = false;
555             } else {
556                 overlay->isTouchStartDrag_ = false;
557                 overlay->isTouchEndDrag_ =
558                     overlay->endHandleRegion_.ContainsInRegion(startOffset.GetX(), startOffset.GetY());
559             }
560             auto web = weakWeb.Upgrade();
561             if (web) {
562                 web->HandleTouchDown(info, true);
563             }
564         }
565     });
566 
567     touchDetector_->SetOnTouchMove([weak = AceType::WeakClaim(this), weakWeb = weakWeb_](const TouchEventInfo& info) {
568         auto overlay = weak.Upgrade();
569         if (overlay) {
570             auto web = weakWeb.Upgrade();
571             if (web) {
572                 web->HandleTouchMove(info, true);
573             }
574         }
575     });
576 
577     touchDetector_->SetOnTouchUp([weak = AceType::WeakClaim(this), weakWeb = weakWeb_](const TouchEventInfo& info) {
578         auto overlay = weak.Upgrade();
579         if (overlay) {
580             overlay->showMagnifier_ = false;
581             auto web = weakWeb.Upgrade();
582             if (web) {
583                 web->HandleTouchUp(info, true);
584             }
585             overlay->MarkNeedLayout();
586         }
587     });
588 }
589 #endif
590 
PerformLayout()591 void RenderTextOverlay::PerformLayout()
592 {
593     double handleRadius = NormalizeToPx(handleRadius_);
594     startHandleCenter_ = Offset(-handleRadius, handleRadius);
595     endHandleCenter_ = Offset(handleRadius, handleRadius);
596 
597     if (!GetChildren().empty()) {
598         const auto& child = GetChildren().front();
599         if (child) {
600             child->Layout(GetLayoutParam());
601             child->SetPosition(ComputeChildPosition(child));
602             if (NearZero(childRightBoundary_)) {
603                 childRightBoundary_ = child->GetPosition().GetX() + child->GetLayoutSize().Width();
604             } else {
605                 child->SetPosition(
606                     Offset(childRightBoundary_ - child->GetLayoutSize().Width(), child->GetPosition().GetY()));
607             }
608         } else {
609             LOGE("child is null");
610             return;
611         }
612         SetLayoutSize(GetLayoutParam().GetMaxSize());
613 
614         // If child size is changed, refresh animation, when there is tool bar only.
615         if (HasToolBarOnly()) {
616             double horizonOffsetForAnimation = child->GetLayoutSize().Width() - NormalizeToPx(MORE_BUTTON_SIZE);
617             if (!NearEqual(horizonOffsetForAnimation, horizonOffsetForAnimation_)) {
618                 horizonOffsetForAnimation_ = horizonOffsetForAnimation;
619                 isAnimationInited_ = false;
620             }
621         }
622         if (child && renderClip_) {
623             renderClip_->SetShadowBoxOffset(Offset(
624                 std::max(
625                     child->GetLayoutSize().Width() - horizonOffsetForAnimation_ - NormalizeToPx(MORE_BUTTON_SIZE), 0.0),
626                 0.0));
627         }
628 
629         if (textDirection_ == TextDirection::RTL) {
630             moreButtonPosition_ = child->GetGlobalOffset();
631         } else {
632             moreButtonPosition_ = child->GetGlobalOffset() + Offset(child->GetLayoutSize().Width(), 0.0);
633         }
634     }
635 
636     // Compute touch region of handle.
637     double hotZoneDiameter = NormalizeToPx(HANDLE_HOTZONE_DIAMETER);
638     double hotZoneRadius = hotZoneDiameter / 2.0;
639     if (isSingleHandle_) {
640         startHandleRegion_ = TouchRegion(startHandleOffset_ + Offset(-hotZoneRadius, 0.0),
641             startHandleOffset_ + Offset(hotZoneRadius, hotZoneDiameter));
642     } else {
643         startHandleRegion_ = TouchRegion(
644             startHandleOffset_ + Offset(-hotZoneRadius, -startHandleHeight_.value_or(lineHeight_) - hotZoneDiameter),
645             startHandleOffset_ + Offset(hotZoneRadius, -startHandleHeight_.value_or(lineHeight_)));
646         endHandleRegion_ = TouchRegion(
647             endHandleOffset_ + Offset(-hotZoneRadius, 0.0), endHandleOffset_ + Offset(hotZoneRadius, hotZoneDiameter));
648     }
649 
650     InitAnimation();
651 
652     auto context = GetContext().Upgrade();
653     if (!context) {
654         return;
655     }
656     if (!GetChildren().empty()) {
657         const auto& child = GetChildren().front();
658         if (!child) {
659             LOGE("child is null");
660             return;
661         }
662         Rect textOverlayRect(child->GetGlobalOffset(), child->GetLayoutSize());
663         auto startHandleOffset = startHandleOffset_ + Offset(-hotZoneRadius, -lineHeight_ - hotZoneDiameter);
664         auto startHandlebottomRightPoint = startHandleOffset_ + Offset(hotZoneRadius, -lineHeight_);
665         Rect startHandleRect(startHandleOffset.GetX(), startHandleOffset.GetY(),
666             startHandlebottomRightPoint.GetX() - startHandleOffset.GetX(),
667             startHandlebottomRightPoint.GetY() - startHandleOffset.GetY());
668         auto endHandleOffset = endHandleOffset_ + Offset(-hotZoneRadius, 0.0);
669         auto endHandlebottomRightPoint = endHandleOffset_ + Offset(hotZoneRadius, hotZoneDiameter);
670         Rect endHandleRect(endHandleOffset.GetX(), endHandleOffset.GetY(),
671             endHandlebottomRightPoint.GetX() - endHandleOffset.GetX(),
672             endHandlebottomRightPoint.GetY() - endHandleOffset.GetY());
673         auto textOverlayManager = context->GetTextOverlayManager();
674         if (textOverlayManager) {
675             textOverlayManager->ClearTextOverlayRect();
676             auto isContainerModal = context->GetWindowModal() == WindowModal::CONTAINER_MODAL &&
677                                     context->GetWindowManager()->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING;
678             if (isContainerModal) {
679                 textOverlayManager->SetCoordinateOffset(
680                     Offset((CONTAINER_BORDER_WIDTH.ConvertToPx() + CONTENT_PADDING.ConvertToPx()),
681                         CONTAINER_TITLE_HEIGHT.ConvertToPx()));
682             }
683             textOverlayManager->AddTextOverlayRect(textOverlayRect);
684             textOverlayManager->AddTextOverlayRect(startHandleRect);
685             textOverlayManager->AddTextOverlayRect(endHandleRect);
686         }
687     } else {
688         auto textOverlayManager = context->GetTextOverlayManager();
689         if (textOverlayManager) {
690             textOverlayManager->ClearTextOverlayRect();
691         }
692     }
693 }
694 
ComputeChildPosition(const RefPtr<RenderNode> & child)695 Offset RenderTextOverlay::ComputeChildPosition(const RefPtr<RenderNode>& child)
696 {
697     // Adjust position of overlay.
698     Offset startHandleOffset = startHandleOffset_;
699     Offset endHandleOffset = endHandleOffset_;
700     if (needClipRect_) {
701         startHandleOffset.SetX(std::clamp(startHandleOffset.GetX(), clipRect_.Left(), clipRect_.Right()));
702         startHandleOffset.SetY(std::clamp(startHandleOffset.GetY(), clipRect_.Top(), clipRect_.Bottom()));
703         endHandleOffset.SetX(std::clamp(endHandleOffset.GetX(), clipRect_.Left(), clipRect_.Right()));
704         endHandleOffset.SetY(std::clamp(endHandleOffset.GetY(), clipRect_.Top(), clipRect_.Bottom()));
705 
706         if (!NearEqual(startHandleOffset.GetY(), endHandleOffset.GetY())) {
707             startHandleOffset.SetX(clipRect_.Left());
708             endHandleOffset.SetX(clipRect_.Right());
709         }
710     }
711     // Calculate the spacing with text and handle, menu is fixed up the handle and text.
712     double menuSpacingWithText = NormalizeToPx(menuSpacingWithText_);
713     double menuSpacingWithHandle = NormalizeToPx(menuSpacingWithHandle_);
714     double menuSpacing = isSingleHandle_ ? menuSpacingWithText : menuSpacingWithHandle + menuSpacingWithText;
715 
716     Offset childPosition;
717     if (isUsingMouse_) {
718         auto context = GetContext().Upgrade();
719         auto isContainerModal = context->GetWindowModal() == WindowModal::CONTAINER_MODAL &&
720                                 context->GetWindowManager()->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING;
721         if (isContainerModal) {
722             childPosition =
723                 mouseOffset_ - Offset((CONTAINER_BORDER_WIDTH.ConvertToPx() + CONTENT_PADDING.ConvertToPx()),
724                                       CONTAINER_TITLE_HEIGHT.ConvertToPx());
725         } else {
726             childPosition = mouseOffset_;
727         }
728         if (GreatOrEqual(
729             childPosition.GetX() + child->GetLayoutSize().Width(), GetLayoutParam().GetMaxSize().Width()) &&
730             GreatOrEqual(childPosition.GetX(), child->GetLayoutSize().Width())) {
731             childPosition.SetX(childPosition.GetX() - child->GetLayoutSize().Width());
732         }
733         if (GreatOrEqual(
734             childPosition.GetY() + child->GetLayoutSize().Height(), GetLayoutParam().GetMaxSize().Height()) &&
735             GreatOrEqual(childPosition.GetY(), child->GetLayoutSize().Height())) {
736             childPosition.SetY(childPosition.GetY() - child->GetLayoutSize().Height());
737         }
738     } else {
739         childPosition =
740             Offset((startHandleOffset.GetX() + endHandleOffset.GetX() - child->GetLayoutSize().Width()) / 2.0,
741                 startHandleOffset.GetY() - lineHeight_ - menuSpacing - NormalizeToPx(TOOL_BAR_HEIGHT));
742         // Adjust position of overlay.
743         if (LessOrEqual(childPosition.GetX(), 0.0)) {
744             childPosition.SetX(DEFAULT_SPACING);
745         } else if (GreatOrEqual(
746             childPosition.GetX() + child->GetLayoutSize().Width(), GetLayoutParam().GetMaxSize().Width())) {
747             childPosition.SetX(
748                 GetLayoutParam().GetMaxSize().Width() - child->GetLayoutSize().Width() - DEFAULT_SPACING);
749         }
750         if (LessNotEqual(childPosition.GetY(), NormalizeToPx(TOOL_BAR_HEIGHT))) {
751             childPosition.SetY(endHandleOffset_.GetY() + menuSpacingWithHandle + menuSpacingWithText);
752         }
753     }
754 
755     return childPosition;
756 }
757 
InitAnimation()758 void RenderTextOverlay::InitAnimation()
759 {
760     if (isAnimationInited_) {
761         return;
762     }
763     isAnimationInited_ = true;
764 
765     // Create tween option for in.
766     // Add offset animation for outer tween.
767     auto xCurveIn = AceType::MakeRefPtr<CurveAnimation<float>>(horizonOffsetForAnimation_, 0.0f, Curves::FRICTION);
768     tweenOptionIn_.SetPropertyAnimationFloat(PropertyAnimatableType::PROPERTY_OFFSET_X, xCurveIn);
769 
770     // Add opacity animation for outer tween.
771     auto opacityKeyframeInFirst = AceType::MakeRefPtr<Keyframe<float>>(0.0f, 0.0f);
772     auto opacityKeyframeInSecond = AceType::MakeRefPtr<Keyframe<float>>(OPACITY_KEYFRAME, 1.0f);
773     opacityKeyframeInSecond->SetCurve(Curves::SHARP);
774     auto opacityKeyframeInThird = AceType::MakeRefPtr<Keyframe<float>>(1.0f, 1.0f);
775     auto opacityAnimationIn = AceType::MakeRefPtr<KeyframeAnimation<float>>();
776     opacityAnimationIn->AddKeyframe(opacityKeyframeInFirst);
777     opacityAnimationIn->AddKeyframe(opacityKeyframeInSecond);
778     opacityAnimationIn->AddKeyframe(opacityKeyframeInThird);
779     tweenOptionIn_.SetOpacityAnimation(opacityAnimationIn);
780     tweenOptionIn_.SetDuration(ANIMATION_DURATION);
781     tweenOptionIn_.SetFillMode(FillMode::FORWARDS);
782 
783     // Add translate animation for inner tween.
784     auto xTranslateIn = AceType::MakeRefPtr<CurveAnimation<DimensionOffset>>(
785         DimensionOffset(ANIMATION_OFFSET_X, 0.0_vp), DimensionOffset(0.0_vp, 0.0_vp), Curves::FRICTION);
786     innerTweenOptionIn_.SetTranslateAnimations(AnimationType::TRANSLATE_X, xTranslateIn);
787     innerTweenOptionIn_.SetDuration(ANIMATION_DURATION);
788     innerTweenOptionIn_.SetFillMode(FillMode::FORWARDS);
789 
790     // Create tween option for out.
791     // Add offset animation for outer tween.
792     auto xCurveOut = AceType::MakeRefPtr<CurveAnimation<float>>(0.0f, horizonOffsetForAnimation_, Curves::FRICTION);
793     tweenOptionOut_.SetPropertyAnimationFloat(PropertyAnimatableType::PROPERTY_OFFSET_X, xCurveOut);
794 
795     // Add opacity animation for outer tween.
796     auto opacityKeyframeOutFirst = AceType::MakeRefPtr<Keyframe<float>>(0.0f, 1.0f);
797     auto opacityKeyframeOutSecond = AceType::MakeRefPtr<Keyframe<float>>(OPACITY_KEYFRAME, 0.0f);
798     opacityKeyframeOutSecond->SetCurve(Curves::SHARP);
799     auto opacityKeyframeOutThird = AceType::MakeRefPtr<Keyframe<float>>(1.0f, 0.0f);
800     auto opacityAnimationOut = AceType::MakeRefPtr<KeyframeAnimation<float>>();
801     opacityAnimationOut->AddKeyframe(opacityKeyframeOutFirst);
802     opacityAnimationOut->AddKeyframe(opacityKeyframeOutSecond);
803     opacityAnimationOut->AddKeyframe(opacityKeyframeOutThird);
804     tweenOptionOut_.SetOpacityAnimation(opacityAnimationOut);
805     tweenOptionOut_.SetDuration(ANIMATION_DURATION);
806     tweenOptionOut_.SetFillMode(FillMode::FORWARDS);
807 
808     // Create translate animation for inner tween.
809     auto xTranslateOut = AceType::MakeRefPtr<CurveAnimation<DimensionOffset>>(
810         DimensionOffset(0.0_vp, 0.0_vp), DimensionOffset(ANIMATION_OFFSET_X, 0.0_vp), Curves::FRICTION);
811     innerTweenOptionOut_.SetTranslateAnimations(AnimationType::TRANSLATE_X, xTranslateOut);
812     innerTweenOptionOut_.SetDuration(ANIMATION_DURATION);
813     innerTweenOptionOut_.SetFillMode(FillMode::FORWARDS);
814 }
815 
TouchTest(const Point & globalPoint,const Point & parentLocalPoint,const TouchRestrict & touchRestrict,TouchTestResult & result)816 bool RenderTextOverlay::TouchTest(const Point& globalPoint, const Point& parentLocalPoint,
817     const TouchRestrict& touchRestrict, TouchTestResult& result)
818 {
819     if (GetDisableTouchEvent() || disabled_ || !isAnimationStopped_) {
820         return false;
821     }
822     const auto localPoint = parentLocalPoint - GetPaintRect().GetOffset();
823     if (!isSingleHandle_ || showOption_.showMenu) {
824         for (auto iter = GetChildren().rbegin(); iter != GetChildren().rend(); ++iter) {
825             const auto& child = *iter;
826             auto childResult = result.size();
827             if (child->TouchTest(globalPoint, localPoint, touchRestrict, result)) {
828                 return true;
829             }
830             // here is to handle some cases when the touch test doesnt bubble up.
831             if (childResult != result.size()) {
832                 return true;
833             }
834         }
835     }
836     if (startHandleRegion_.ContainsInRegion(parentLocalPoint.GetX(), parentLocalPoint.GetY()) ||
837         endHandleRegion_.ContainsInRegion(parentLocalPoint.GetX(), parentLocalPoint.GetY())) {
838         const auto coordinateOffset = globalPoint - localPoint;
839         globalPoint_ = globalPoint;
840         OnTouchTestHit(coordinateOffset, touchRestrict, result);
841         return true;
842     }
843     if (globalPoint.GetSourceType() == SourceType::MOUSE) {
844         PopOverlay();
845         return true;
846     }
847     return false;
848 }
849 
OnTouchTestHit(const Offset & coordinateOffset,const TouchRestrict & touchRestrict,TouchTestResult & result)850 void RenderTextOverlay::OnTouchTestHit(
851     const Offset& coordinateOffset, const TouchRestrict& touchRestrict, TouchTestResult& result)
852 {
853     clickDetector_->SetCoordinateOffset(coordinateOffset);
854     result.emplace_back(clickDetector_);
855     dragDetector_->SetCoordinateOffset(coordinateOffset);
856     result.emplace_back(dragDetector_);
857     touchDetector_->SetCoordinateOffset(coordinateOffset);
858     result.emplace_back(touchDetector_);
859 }
860 
HandleMouseEvent(const MouseEvent & event)861 bool RenderTextOverlay::HandleMouseEvent(const MouseEvent& event)
862 {
863     if (event.button != MouseButton::LEFT_BUTTON && event.action == MouseAction::PRESS) {
864         PopOverlay();
865         return true;
866     }
867     return event.button == MouseButton::LEFT_BUTTON;
868 }
869 
HandleClick(const Offset & clickOffset)870 void RenderTextOverlay::HandleClick(const Offset& clickOffset)
871 {
872     if (isSingleHandle_ && startHandleRegion_.ContainsInRegion(clickOffset.GetX(), clickOffset.GetY())) {
873         childRightBoundary_ = 0.0;
874         showOption_.showMenu = true;
875         auto textField = weakTextField_.Upgrade();
876         if (textField) {
877             textField->SetIsOverlayShowed(true, false);
878         }
879         if (onRebuild_) {
880             OnFocusChange(RenderStatus::FOCUS);
881             onRebuild_(true, true, hasMenu_, true, false);
882         }
883     }
884 }
885 
HandleDragStart(const Offset & startOffset)886 void RenderTextOverlay::HandleDragStart(const Offset& startOffset)
887 {
888     childRightBoundary_ = 0.0;
889     showOption_.showMenu = true;
890     auto textField = weakTextField_.Upgrade();
891     auto text = weakText_.Upgrade();
892     if (!textField && !text) {
893         LOGE("TextField or text is nullptr");
894         return;
895     }
896 
897     // Mark start and end index
898     if (textField) {
899         startIndex_ = textField->GetEditingValue().selection.GetStart();
900         endIndex_ = textField->GetEditingValue().selection.GetEnd();
901         if (startHandleRegion_.ContainsInRegion(startOffset.GetX(), startOffset.GetY())) {
902             textField->SetInitIndex(endIndex_);
903         } else {
904             textField->SetInitIndex(startIndex_);
905         }
906     } else if (text) {
907         startIndex_ = text->GetTextSelect().GetStart();
908         endIndex_ = text->GetTextSelect().GetEnd();
909     }
910 
911     // Mark start or end flag and mark the index
912     if (startHandleRegion_.ContainsInRegion(startOffset.GetX(), startOffset.GetY())) {
913         isStartDrag_ = true;
914         isEndDrag_ = false;
915     } else {
916         isStartDrag_ = false;
917         isEndDrag_ = endHandleRegion_.ContainsInRegion(startOffset.GetX(), startOffset.GetY());
918     }
919 }
920 
HandleDragUpdateAndEnd(const Offset & offset)921 void RenderTextOverlay::HandleDragUpdateAndEnd(const Offset& offset)
922 {
923     childRightBoundary_ = 0.0;
924     if (isStartDrag_) {
925         auto startCallback = [weak = WeakClaim(this)](const Offset& startHandleOffset) {
926             auto overlay = weak.Upgrade();
927             if (overlay) {
928                 overlay->startHandleOffset_ = startHandleOffset;
929                 if (overlay->isSingleHandle_) {
930                     overlay->endHandleOffset_ = startHandleOffset;
931                 }
932                 overlay->MarkNeedLayout();
933             }
934         };
935         onStartHandleMove_(endIndex_, offset - Offset(0.0, lineHeight_), startCallback, isSingleHandle_);
936         isDragging_ = true;
937     } else if (isEndDrag_) {
938         auto endCallback = [weak = WeakClaim(this)](const Offset& endHandleOffset) {
939             auto overlay = weak.Upgrade();
940             if (overlay) {
941                 overlay->endHandleOffset_ = endHandleOffset;
942                 overlay->MarkNeedLayout();
943             }
944         };
945         onEndHandleMove_(startIndex_, offset - Offset(0.0, lineHeight_), endCallback);
946         isDragging_ = true;
947     }
948 }
949 
HandleCut()950 void RenderTextOverlay::HandleCut()
951 {
952     needCloseKeyboard_ = false;
953     if (onCut_) {
954         onCut_();
955     }
956     PopOverlay();
957 }
958 
HandleCopy()959 void RenderTextOverlay::HandleCopy()
960 {
961     needCloseKeyboard_ = false;
962     if (onCopy_) {
963         onCopy_();
964     }
965     PopOverlay();
966 }
967 
HandlePaste()968 void RenderTextOverlay::HandlePaste()
969 {
970     needCloseKeyboard_ = false;
971     if (onPaste_) {
972         onPaste_();
973     }
974     PopOverlay();
975 }
976 
HandleCopyAll()977 void RenderTextOverlay::HandleCopyAll()
978 {
979     needCloseKeyboard_ = false;
980     isSingleHandle_ = false;
981     childRightBoundary_ = 0.0;
982     auto callback = [weak = WeakClaim(this)](const Offset& startHandleOffset, const Offset& endHandleOffset) {
983         auto overlay = weak.Upgrade();
984         if (overlay) {
985             if (startHandleOffset == overlay->startHandleOffset_ && endHandleOffset == overlay->endHandleOffset_) {
986                 LOGI("selection region has not changed");
987                 return;
988             }
989             overlay->startHandleOffset_ = startHandleOffset;
990             overlay->endHandleOffset_ = endHandleOffset;
991             overlay->isSingleHandle_ = false;
992             if (startHandleOffset == endHandleOffset) {
993                 overlay->isSingleHandle_ = true;
994             }
995             if (overlay->onRebuild_) {
996                 overlay->onRebuild_(overlay->isSingleHandle_, true, overlay->hasMenu_, true, false);
997             }
998         }
999     };
1000     if (onCopyAll_) {
1001         onCopyAll_(callback);
1002     }
1003 }
1004 
HandleMoreButtonClick()1005 void RenderTextOverlay::HandleMoreButtonClick()
1006 {
1007     needCloseKeyboard_ = false;
1008     // Is animation is not stopped, do not handle click to start a new animation.
1009     if (!isAnimationStopped_) {
1010         return;
1011     }
1012     hasMenu_ = !hasMenu_;
1013     auto context = GetContext().Upgrade();
1014     if (context && context->GetIsDeclarative()) {
1015         onRebuild_(isSingleHandle_, true, true, true, false);
1016         return;
1017     }
1018     isAnimationStarted_ = false;
1019     isAnimationStopped_ = false;
1020     if (onRebuild_) {
1021         animateUntilPaint_ = hasMenu_;
1022         onRebuild_(isSingleHandle_, true, true, true, true);
1023     }
1024     if (!animateUntilPaint_) {
1025         startAnimation_(tweenOptionIn_, innerTweenOptionIn_, isSingleHandle_, true);
1026         StartMoreAnimation(reverse_);
1027     }
1028 }
1029 
OnPaintFinish()1030 void RenderTextOverlay::OnPaintFinish()
1031 {
1032     if (animateUntilPaint_) {
1033         animateUntilPaint_ = false;
1034         startAnimation_(tweenOptionOut_, innerTweenOptionOut_, isSingleHandle_, false);
1035         StartMoreAnimation(reverse_);
1036     }
1037 }
1038 
RestoreMoreButtonStyle()1039 void RenderTextOverlay::RestoreMoreButtonStyle()
1040 {
1041     if (!controller_) {
1042         return;
1043     }
1044     if (reverse_) {
1045         BuildAndStartMoreButtonAnimation();
1046         controller_->Finish();
1047     } else if (controller_->IsRunning()) {
1048         controller_->Finish();
1049     }
1050 }
1051 
StartMoreAnimation(bool reverse)1052 void RenderTextOverlay::StartMoreAnimation(bool reverse)
1053 {
1054     if (controller_ && controller_->IsRunning()) {
1055         reverse_ = !reverse_;
1056         controller_->Reverse();
1057         return;
1058     }
1059     BuildAndStartMoreButtonAnimation();
1060 }
1061 
BuildStrokeWidthAnimation(const RefPtr<KeyframeAnimation<Dimension>> & widthAnimation,const Dimension & from,const Dimension & to,bool reverse)1062 void RenderTextOverlay::BuildStrokeWidthAnimation(const RefPtr<KeyframeAnimation<Dimension>>& widthAnimation,
1063     const Dimension& from, const Dimension& to, bool reverse)
1064 {
1065     auto widthFrameStart = AceType::MakeRefPtr<Keyframe<Dimension>>(KEYFRAME_BEGINNING, from);
1066     auto widthFrameEnd = AceType::MakeRefPtr<Keyframe<Dimension>>(KEYFRAME_ENDING, to);
1067     widthAnimation->AddKeyframe(widthFrameStart);
1068     if (reverse) {
1069         widthFrameEnd->SetCurve(Curves::FRICTION);
1070     } else {
1071         auto widthFrameMid = AceType::MakeRefPtr<Keyframe<Dimension>>(KEYFRAME_PERCENT_THIRTY, to);
1072         widthFrameMid->SetCurve(Curves::FRICTION);
1073         widthFrameEnd->SetCurve(Curves::LINEAR);
1074         widthAnimation->AddKeyframe(widthFrameMid);
1075     }
1076     widthAnimation->AddKeyframe(widthFrameEnd);
1077     widthAnimation->AddListener([weakText = AceType::WeakClaim(this)](const Dimension& value) {
1078         auto overlay = weakText.Upgrade();
1079         if (overlay) {
1080             overlay->strokeWidth_ = value;
1081             overlay->clipWidth_ = std::clamp((CLIP_WIDTH - (value - STROKE_MIN_WIDTH).Value()), 0.0, CLIP_WIDTH);
1082             overlay->MarkNeedRender(true);
1083         }
1084     });
1085 }
1086 
BuildEndPointOffsetAnimation(const RefPtr<KeyframeAnimation<double>> & offsetAnimation,double from,double to,bool reverse)1087 void RenderTextOverlay::BuildEndPointOffsetAnimation(
1088     const RefPtr<KeyframeAnimation<double>>& offsetAnimation, double from, double to, bool reverse)
1089 {
1090     auto offsetFrameStart = AceType::MakeRefPtr<Keyframe<double>>(KEYFRAME_BEGINNING, from);
1091     auto offsetFrameEnd = AceType::MakeRefPtr<Keyframe<double>>(KEYFRAME_ENDING, to);
1092 
1093     offsetAnimation->AddKeyframe(offsetFrameStart);
1094     if (reverse) {
1095         offsetFrameEnd->SetCurve(Curves::FRICTION);
1096     } else {
1097         auto offsetFrameMid = AceType::MakeRefPtr<Keyframe<double>>(KEYFRAME_PERCENT_THIRTY, from);
1098         offsetFrameMid->SetCurve(Curves::LINEAR);
1099         offsetFrameEnd->SetCurve(Curves::FRICTION);
1100         offsetAnimation->AddKeyframe(offsetFrameMid);
1101     }
1102     offsetAnimation->AddKeyframe(offsetFrameEnd);
1103     offsetAnimation->AddListener([weakText = AceType::WeakClaim(this)](double value) {
1104         auto overlay = weakText.Upgrade();
1105         if (overlay) {
1106             overlay->ProcessEndPointAnimation(value);
1107             overlay->MarkNeedRender(true);
1108         }
1109     });
1110 }
1111 
BuildFrictionAnimation(const RefPtr<KeyframeAnimation<double>> & animation,double from,double to)1112 void RenderTextOverlay::BuildFrictionAnimation(
1113     const RefPtr<KeyframeAnimation<double>>& animation, double from, double to)
1114 {
1115     auto frameStart = AceType::MakeRefPtr<Keyframe<double>>(KEYFRAME_BEGINNING, from);
1116     auto frameEnd = AceType::MakeRefPtr<Keyframe<double>>(KEYFRAME_ENDING, to);
1117     frameEnd->SetCurve(Curves::FRICTION);
1118 
1119     animation->AddKeyframe(frameStart);
1120     animation->AddKeyframe(frameEnd);
1121     animation->AddListener([weakText = AceType::WeakClaim(this)](double value) {
1122         auto overlay = weakText.Upgrade();
1123         if (overlay) {
1124             overlay->ProcessFrictionAnimation(value);
1125             overlay->MarkNeedRender(true);
1126         }
1127     });
1128 }
1129 
ProcessFrictionAnimation(double value)1130 void RenderTextOverlay::ProcessFrictionAnimation(double value)
1131 {
1132     // calculate start point offset of dots
1133     dot1StartOffset_ = DOT1_OFFSET * value;
1134     dot2StartOffset_ = DOT2_OFFSET * value;
1135     dot3StartOffset_ = DOT3_OFFSET * value;
1136     dot4StartOffset_ = DOT4_OFFSET * value;
1137 
1138     // calculate rotate degree
1139     rotateDegree_ = ROTATE_DEGREE * value;
1140 }
1141 
ProcessEndPointAnimation(double value)1142 void RenderTextOverlay::ProcessEndPointAnimation(double value)
1143 {
1144     dot2Offset_ = (END_POINT - DOT2_POSITION - DOT2_OFFSET) * value;
1145     dot3Offset_ = (END_POINT - DOT3_POSITION - DOT3_OFFSET) * value;
1146     dot4Offset_ = (END_POINT - DOT4_POSITION - DOT4_OFFSET) * value;
1147 }
1148 
BuildAndStartMoreButtonAnimation()1149 void RenderTextOverlay::BuildAndStartMoreButtonAnimation()
1150 {
1151     if (!controller_) {
1152         controller_ = CREATE_ANIMATOR(GetContext());
1153     }
1154     controller_->ClearInterpolators();
1155     controller_->ClearAllListeners();
1156 
1157     RefPtr<KeyframeAnimation<Dimension>> strokeWidthAnimation = AceType::MakeRefPtr<KeyframeAnimation<Dimension>>();
1158     RefPtr<KeyframeAnimation<double>> startPointAnimation = AceType::MakeRefPtr<KeyframeAnimation<double>>();
1159     RefPtr<KeyframeAnimation<double>> endPointAnimation = AceType::MakeRefPtr<KeyframeAnimation<double>>();
1160     if (reverse_) {
1161         BuildStrokeWidthAnimation(strokeWidthAnimation, STROKE_MIN_WIDTH, STROKE_MAX_WIDTH, true);
1162         BuildFrictionAnimation(startPointAnimation, KEYFRAME_ENDING, KEYFRAME_BEGINNING);
1163         BuildEndPointOffsetAnimation(endPointAnimation, KEYFRAME_ENDING, KEYFRAME_BEGINNING, true);
1164     } else {
1165         BuildStrokeWidthAnimation(strokeWidthAnimation, STROKE_MAX_WIDTH, STROKE_MIN_WIDTH, false);
1166         BuildFrictionAnimation(startPointAnimation, KEYFRAME_BEGINNING, KEYFRAME_ENDING);
1167         BuildEndPointOffsetAnimation(endPointAnimation, KEYFRAME_BEGINNING, KEYFRAME_ENDING, false);
1168     }
1169 
1170     controller_->SetDuration(MORE_ANIMATION_DURATION);
1171     controller_->AddStopListener([more = AceType::WeakClaim(this)]() {
1172         auto textMore = more.Upgrade();
1173         if (textMore) {
1174             textMore->reverse_ = (!textMore->reverse_);
1175             textMore->renderMenu_->SetIsWattingForAnimationStart(false);
1176         }
1177     });
1178     controller_->AddStartListener([more = AceType::WeakClaim(this)]() {
1179         auto textMore = more.Upgrade();
1180         if (textMore) {
1181             textMore->reverse_ = (!textMore->reverse_);
1182             textMore->renderMenu_->SetIsWattingForAnimationStart(true);
1183         }
1184     });
1185     controller_->AddInterpolator(strokeWidthAnimation);
1186     controller_->AddInterpolator(startPointAnimation);
1187     controller_->AddInterpolator(endPointAnimation);
1188     controller_->Forward();
1189 }
1190 
PopOverlay()1191 void RenderTextOverlay::PopOverlay()
1192 {
1193     if (hasPoped_) {
1194         return;
1195     }
1196     auto textField = weakTextField_.Upgrade();
1197     if (!textField) {
1198         return;
1199     }
1200     auto stack = textField->GetStackElement().Upgrade();
1201     if (stack) {
1202         hasPoped_ = true;
1203         stack->PopTextOverlay();
1204     }
1205     textField->SetIsOverlayShowed(false, needStartTwinkling_);
1206     textField->SetTextOverlayPushed(false);
1207 }
1208 
OnFocusChange(RenderStatus renderStatus)1209 void RenderTextOverlay::OnFocusChange(RenderStatus renderStatus)
1210 {
1211     if (onFocusChange_) {
1212         onFocusChange_(renderStatus == RenderStatus::FOCUS, needCloseKeyboard_);
1213     }
1214 }
1215 
InitRenderChild(const RefPtr<RenderNode> & render)1216 void RenderTextOverlay::InitRenderChild(const RefPtr<RenderNode>& render)
1217 {
1218     if (!render) {
1219         return;
1220     }
1221 
1222     if (AceType::InstanceOf<RenderBox>(render)) {
1223         if (!renderBox_) {
1224             renderBox_ = AceType::DynamicCast<RenderBox>(render);
1225         }
1226     } else if (AceType::InstanceOf<RenderClip>(render)) {
1227         if (!renderClip_) {
1228             renderClip_ = AceType::DynamicCast<RenderClip>(render);
1229         }
1230     } else if (AceType::InstanceOf<RenderSelectPopup>(render)) {
1231         if (!renderMenu_) {
1232             renderMenu_ = AceType::DynamicCast<RenderSelectPopup>(render);
1233         }
1234     }
1235 
1236     for (const auto& child : render->GetChildren()) {
1237         InitRenderChild(child);
1238     }
1239 }
1240 
ResetRenderChild()1241 void RenderTextOverlay::ResetRenderChild()
1242 {
1243     renderBox_.Reset();
1244     renderClip_.Reset();
1245     renderMenu_.Reset();
1246 }
1247 
HasToolBarOnly() const1248 bool RenderTextOverlay::HasToolBarOnly() const
1249 {
1250     // Child of render overlay is focus collaboration.
1251     auto focusCollaboration = AceType::DynamicCast<RenderFocusCollaboration>(GetChildren().front());
1252     if (!focusCollaboration) {
1253         return false;
1254     }
1255     // Child of render focus collaboration is column.
1256     auto column = AceType::DynamicCast<RenderFlex>(focusCollaboration->GetChildren().front());
1257     if (!column) {
1258         return false;
1259     }
1260     // Column has two children at most, tool bar and menu, if there is only one, it must be tool bar.
1261     return column->GetChildren().size() == 1;
1262 }
1263 
SetOnRebuild(const std::function<void (bool,bool,bool,bool,bool)> & onRebuild)1264 void RenderTextOverlay::SetOnRebuild(const std::function<void(bool, bool, bool, bool, bool)>& onRebuild)
1265 {
1266     onRebuild_ = onRebuild;
1267 }
1268 
SetStartAnimationCallback(const StartAnimationCallback & callback)1269 void RenderTextOverlay::SetStartAnimationCallback(const StartAnimationCallback& callback)
1270 {
1271     startAnimation_ = callback;
1272 }
1273 
SetIsAnimationStarted(bool isAnimationStarted)1274 void RenderTextOverlay::SetIsAnimationStarted(bool isAnimationStarted)
1275 {
1276     isAnimationStarted_ = isAnimationStarted;
1277 }
1278 
IsAnimationStarted() const1279 bool RenderTextOverlay::IsAnimationStarted() const
1280 {
1281     return isAnimationStarted_;
1282 }
1283 
SetIsAnimationStopped(bool isAnimationStopped)1284 void RenderTextOverlay::SetIsAnimationStopped(bool isAnimationStopped)
1285 {
1286     isAnimationStopped_ = isAnimationStopped;
1287 }
1288 
GetHorizonOffsetForAnimation() const1289 double RenderTextOverlay::GetHorizonOffsetForAnimation() const
1290 {
1291     return horizonOffsetForAnimation_;
1292 }
1293 
1294 } // namespace OHOS::Ace
1295