• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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/web/web_select_overlay.h"
17 
18 #include <algorithm>
19 #include <optional>
20 
21 #include "base/utils/utils.h"
22 #include "base/web/webview/arkweb_utils/arkweb_utils.h"
23 #include "core/components_ng/manager/select_content_overlay/select_content_overlay_manager.h"
24 #include "core/components_ng/manager/select_overlay/select_overlay_manager.h"
25 #include "core/components_ng/pattern/web/web_pattern.h"
26 #include "core/components_ng/pattern/web/view_data_common.h"
27 #include "core/components_ng/pattern/web/transitional_node_info.h"
28 #include "core/components/web/resource/web_delegate.h"
29 #include "core/components/text_overlay/text_overlay_theme.h"
30 #include "core/event/event_info_convertor.h"
31 #include "nweb_handler.h"
32 
33 namespace OHOS::Ace::NG {
34 constexpr Dimension SELECT_HANDLE_DEFAULT_HEIGHT = 16.0_vp;
35 constexpr float SELECT_MENE_HEIGHT = 140.0f;
36 constexpr int32_t HALF = 2;
37 const std::string ASK_CELIA_TAG = "askCelia";
38 
39 namespace {
40 struct InitStrategyTools {
41     RefPtr<PipelineContext> pipeline = nullptr;
42     RefPtr<TextOverlayTheme> theme = nullptr;
43     RefPtr<SafeAreaManager> safeAreaManager = nullptr;
44     RefPtr<GeometryNode> geometryNode = nullptr;
45 };
46 }
47 
RunQuickMenu(std::shared_ptr<OHOS::NWeb::NWebQuickMenuParams> params,std::shared_ptr<OHOS::NWeb::NWebQuickMenuCallback> callback)48 bool WebSelectOverlay::RunQuickMenu(std::shared_ptr<OHOS::NWeb::NWebQuickMenuParams> params,
49     std::shared_ptr<OHOS::NWeb::NWebQuickMenuCallback> callback)
50 {
51     needResetHandleReverse_ = false;
52     auto pattern = GetPattern<WebPattern>();
53     CHECK_NULL_RETURN(pattern, false);
54     auto pipeline = PipelineContext::GetCurrentContext();
55     CHECK_NULL_RETURN(pipeline, false);
56     CHECK_NULL_RETURN(params, false);
57     std::shared_ptr<OHOS::NWeb::NWebTouchHandleState> insertTouchHandle =
58         params->GetTouchHandleState(OHOS::NWeb::NWebTouchHandleState::TouchHandleType::INSERT_HANDLE);
59     std::shared_ptr<OHOS::NWeb::NWebTouchHandleState> beginTouchHandle =
60         params->GetTouchHandleState(OHOS::NWeb::NWebTouchHandleState::TouchHandleType::SELECTION_BEGIN_HANDLE);
61     std::shared_ptr<OHOS::NWeb::NWebTouchHandleState> endTouchHandle =
62         params->GetTouchHandleState(OHOS::NWeb::NWebTouchHandleState::TouchHandleType::SELECTION_END_HANDLE);
63     WebOverlayType overlayType = GetTouchHandleOverlayType(insertTouchHandle, beginTouchHandle, endTouchHandle);
64     if (overlayType == INVALID_OVERLAY) { return false; }
65     if (params->GetIsLongPressActived()) {
66         TAG_LOGI(AceLogTag::ACE_WEB, "ShowMagnifier");
67         pattern->ShowMagnifier(static_cast<int>(pattern->touchPointX), static_cast<int>(pattern->touchPointY));
68         return false;
69     }
70     if (overlayType == INSERT_OVERLAY && !IS_CALLING_FROM_M114()) {
71         CloseOverlay(false, CloseReason::CLOSE_REASON_CLICK_OUTSIDE);
72     }
73     selectTemporarilyHidden_ = false;
74     selectTemporarilyHiddenByScroll_ = false;
75     SelectOverlayInfo selectInfo;
76     selectInfo.isSingleHandle = (overlayType == INSERT_OVERLAY);
77     UpdateRunQuickMenuSelectInfo(selectInfo, params, insertTouchHandle, beginTouchHandle, endTouchHandle);
78     if (isQuickMenuMouseTrigger_) {
79         return false;
80     }
81     SetMenuOptions(selectInfo, params, callback);
82     SetComputeMenuOffset(selectInfo);
83     RegisterSelectOverlayEvent(selectInfo);
84     selectInfo.ancestorViewPort = pattern->GetViewPort();
85     if (selectInfo.isNewAvoid) {
86         ShowMenu();
87         selectInfo.menuInfo.menuIsShow = true;
88     }
89     dropParams_ = params;
90     selectMenuInfo_ = selectInfo.menuInfo;
91     insertHandle_ = insertTouchHandle;
92     startSelectionHandle_ = beginTouchHandle;
93     endSelectionHandle_ = endTouchHandle;
94     isShowHandle_ = true;
95     webSelectInfo_ = selectInfo;
96     auto host = pattern->GetHost();
97     CHECK_NULL_RETURN(host, false);
98     StartListenSelectOverlayParentScroll(host);
99     ProcessOverlay({ .animation = true });
100     SetTouchHandleExistState(true);
101     return true;
102 }
103 
OnTouchSelectionChanged(std::shared_ptr<OHOS::NWeb::NWebTouchHandleState> insertHandle,std::shared_ptr<OHOS::NWeb::NWebTouchHandleState> startSelectionHandle,std::shared_ptr<OHOS::NWeb::NWebTouchHandleState> endSelectionHandle)104 void WebSelectOverlay::OnTouchSelectionChanged(std::shared_ptr<OHOS::NWeb::NWebTouchHandleState> insertHandle,
105     std::shared_ptr<OHOS::NWeb::NWebTouchHandleState> startSelectionHandle,
106     std::shared_ptr<OHOS::NWeb::NWebTouchHandleState> endSelectionHandle)
107 {
108     needResetHandleReverse_ = false;
109     auto pattern = GetPattern<WebPattern>();
110     CHECK_NULL_VOID(pattern);
111     WebOverlayType overlayType = GetTouchHandleOverlayType(insertHandle, startSelectionHandle, endSelectionHandle);
112     if (overlayType == INVALID_OVERLAY) {
113         pattern->CloseSelectOverlay();
114         return;
115     }
116     auto pipeline = PipelineContext::GetCurrentContext();
117     CHECK_NULL_VOID(pipeline);
118     insertHandle_ = insertHandle;
119     startSelectionHandle_ = startSelectionHandle;
120     endSelectionHandle_ = endSelectionHandle;
121     if (selectTemporarilyHidden_ || selectTemporarilyHiddenByScroll_) {
122         TAG_LOGD(AceLogTag::ACE_WEB, "select menu temporarily hidden");
123         return;
124     }
125     if (!isShowHandle_) {
126         if (overlayType == INSERT_OVERLAY) {
127             if (IS_CALLING_FROM_M114()) {
128                 SelectOverlayInfo selectInfo;
129                 selectInfo.isSingleHandle = true;
130                 selectInfo.firstHandle.paintRect = ComputeTouchHandleRect(insertHandle_);
131                 CheckHandles(selectInfo.firstHandle, insertHandle_);
132                 selectInfo.secondHandle.isShow = false;
133                 selectInfo.menuInfo.menuDisable = true;
134                 selectInfo.menuInfo.menuIsShow = false;
135                 selectInfo.hitTestMode = HitTestMode::HTMDEFAULT;
136                 SetEditMenuOptions(selectInfo);
137                 RegisterSelectOverlayEvent(selectInfo);
138                 selectInfo.isHandleLineShow = false;
139                 isShowHandle_ = true;
140                 webSelectInfo_ = selectInfo;
141                 ProcessOverlay({ .animation = true });
142             } else {
143                 CloseOverlay(false, CloseReason::CLOSE_REASON_CLICK_OUTSIDE);
144             }
145             return;
146         }
147     } else {
148         if (overlayType == INSERT_OVERLAY) {
149             if (!selectOverlayDragging_) {
150                 UpdateTouchHandleForOverlay(true);
151             }
152         } else {
153             UpdateSelectHandleInfo();
154             if (!selectOverlayDragging_) {
155                 UpdateTouchHandleForOverlay(false);
156             }
157         }
158     }
159 }
160 
RegisterSelectOverlayEvent(SelectOverlayInfo & selectInfo)161 void WebSelectOverlay::RegisterSelectOverlayEvent(SelectOverlayInfo& selectInfo)
162 {
163     selectInfo.onClick = [weak = AceType::WeakClaim(this)](const GestureEvent& info, bool isFirst) {
164         auto overlay = weak.Upgrade();
165         CHECK_NULL_VOID(overlay);
166         overlay->OnOverlayClick(info, isFirst);
167     };
168 }
169 
SetEditMenuOptions(SelectOverlayInfo & selectInfo)170 void WebSelectOverlay::SetEditMenuOptions(SelectOverlayInfo& selectInfo)
171 {
172     auto pattern = GetPattern<WebPattern>();
173     CHECK_NULL_VOID(pattern);
174     if (pattern && !(pattern->onCreateMenuCallback_ && pattern->onMenuItemClick_)) {
175         selectInfo.menuOptionItems = pattern->menuOptionParam_;
176     }
177     if (pattern && pattern->onCreateMenuCallback_ && pattern->onMenuItemClick_) {
178         selectInfo.onCreateCallback.onCreateMenuCallback = pattern->onCreateMenuCallback_;
179         selectInfo.onCreateCallback.onMenuItemClick = pattern->onMenuItemClick_;
180         if (pattern->onPrepareMenuCallback_) {
181             selectInfo.onCreateCallback.onPrepareMenuCallback = pattern->onPrepareMenuCallback_;
182             selectInfo.menuInfo.hasOnPrepareMenuCallback = true;
183         }
184         auto textRange = [](int32_t& start, int32_t& end) {
185             start = -1;
186             end = -1;
187         };
188         selectInfo.onCreateCallback.textRangeCallback = textRange;
189     }
190 }
191 
IsSelectHandleReverse()192 bool WebSelectOverlay::IsSelectHandleReverse()
193 {
194     if (startSelectionHandle_->GetTouchHandleType() ==
195         OHOS::NWeb::NWebTouchHandleState::SELECTION_BEGIN_HANDLE &&
196         endSelectionHandle_->GetTouchHandleType() ==
197         OHOS::NWeb::NWebTouchHandleState::SELECTION_BEGIN_HANDLE) {
198         return true;
199     } else if (startSelectionHandle_->GetTouchHandleType() ==
200         OHOS::NWeb::NWebTouchHandleState::SELECTION_END_HANDLE &&
201         endSelectionHandle_->GetTouchHandleType() ==
202         OHOS::NWeb::NWebTouchHandleState::SELECTION_END_HANDLE) {
203         return true;
204     }
205     return false;
206 }
207 
UpdateSelectHandleInfo()208 void WebSelectOverlay::UpdateSelectHandleInfo()
209 {
210     bool needReverse = IsSelectHandleReverse();
211     SelectHandleInfo handleInfo;
212     if (!needReverse) {
213         if (!isCurrentStartHandleDragging_) {
214             handleInfo.paintRect = ComputeTouchHandleRect(startSelectionHandle_);
215             CheckHandles(handleInfo, startSelectionHandle_);
216             webSelectInfo_.firstHandle = handleInfo;
217             UpdateFirstHandleOffset();
218         } else {
219             handleInfo.paintRect = ComputeTouchHandleRect(endSelectionHandle_);
220             CheckHandles(handleInfo, endSelectionHandle_);
221             webSelectInfo_.secondHandle = handleInfo;
222             UpdateSecondHandleOffset();
223         }
224     } else {
225         if (!isCurrentStartHandleDragging_) {
226             handleInfo.paintRect = ComputeTouchHandleRect(endSelectionHandle_);
227             CheckHandles(handleInfo, endSelectionHandle_);
228             webSelectInfo_.firstHandle = handleInfo;
229             UpdateFirstHandleOffset();
230         } else {
231             handleInfo.paintRect = ComputeTouchHandleRect(startSelectionHandle_);
232             CheckHandles(handleInfo, startSelectionHandle_);
233             webSelectInfo_.secondHandle = handleInfo;
234             UpdateSecondHandleOffset();
235         }
236     }
237 }
238 
OnSelectHandleStart(const GestureEvent & event,bool isFirst)239 void WebSelectOverlay::OnSelectHandleStart(const GestureEvent& event, bool isFirst)
240 {
241 }
242 
ChangeHandleHeight(const GestureEvent & event,bool isFirst)243 RectF WebSelectOverlay::ChangeHandleHeight(const GestureEvent& event, bool isFirst)
244 {
245     auto touchOffset = event.GetLocalLocation();
246     auto handle = isFirst ? webSelectInfo_.firstHandle : webSelectInfo_.secondHandle;
247     auto handleHeight = SELECT_HANDLE_DEFAULT_HEIGHT.ConvertToPx();
248     handleHeight = std::min(static_cast<float>(handleHeight), handle.paintRect.Height());
249     bool isTouchHandleCircle = isFirst ?
250         LessNotEqual(touchOffset.GetY(), handle.paintRect.Top()) :
251         GreatNotEqual(touchOffset.GetY(), handle.paintRect.Bottom());
252     if (isFirst) {
253         if (!isTouchHandleCircle) {
254             handle.paintRect.SetTop(static_cast<float>(touchOffset.GetY()) - handleHeight / HALF);
255         }
256         handle.paintRect.SetHeight(handleHeight);
257         webSelectInfo_.firstHandle = handle;
258         webSelectInfo_.firstHandle.isCircleShow = false;
259         UpdateFirstHandleOffset();
260     } else {
261         auto handleOffsetY = isTouchHandleCircle
262                             ? handle.paintRect.Bottom() - handleHeight
263                             : static_cast<float>(touchOffset.GetY()) - handleHeight / HALF;
264         handle.paintRect.SetTop(handleOffsetY);
265         handle.paintRect.SetHeight(handleHeight);
266         webSelectInfo_.secondHandle = handle;
267         webSelectInfo_.secondHandle.isCircleShow = false;
268         UpdateSecondHandleOffset();
269     }
270     return handle.paintRect;
271 }
272 
OnMagnifierHandleMove(const RectF & handleRect,bool isFirst)273 void WebSelectOverlay::OnMagnifierHandleMove(const RectF& handleRect, bool isFirst)
274 {
275     auto pattern = GetPattern<WebPattern>();
276     CHECK_NULL_VOID(pattern);
277     pattern->OnMagnifierHandleMove(handleRect, isFirst);
278 }
279 
UpdateTouchHandleForOverlay(bool fromOverlay)280 void WebSelectOverlay::UpdateTouchHandleForOverlay(bool fromOverlay)
281 {
282     auto pattern = GetPattern<WebPattern>();
283     CHECK_NULL_VOID(pattern);
284     WebOverlayType overlayType = GetTouchHandleOverlayType(insertHandle_, startSelectionHandle_, endSelectionHandle_);
285     if (overlayType == INVALID_OVERLAY) {
286         pattern->CloseSelectOverlay();
287         return;
288     }
289     SelectHandleInfo firstHandleInfo;
290     SelectHandleInfo secondHandleInfo;
291     if (overlayType == INSERT_OVERLAY) {
292         if (!fromOverlay) {
293             HideMenu(true);
294             webSelectInfo_.menuInfo.menuIsShow = false;
295         }
296         firstHandleInfo.paintRect = ComputeTouchHandleRect(insertHandle_);
297         CheckHandles(firstHandleInfo, insertHandle_);
298         firstHandleInfo.needLayout = true;
299         webSelectInfo_.firstHandle = firstHandleInfo;
300         if (SelectOverlayIsOn()) {
301             UpdateFirstHandleOffset();
302         } else {
303             ProcessOverlay({ .animation = true });
304             isShowHandle_ = true;
305         }
306     } else {
307         if (selectTemporarilyHidden_ || selectTemporarilyHiddenByScroll_) {
308             return;
309         }
310         firstHandleInfo.paintRect = ComputeTouchHandleRect(startSelectionHandle_);
311         secondHandleInfo.paintRect = ComputeTouchHandleRect(endSelectionHandle_);
312         CheckHandles(firstHandleInfo, startSelectionHandle_);
313         CheckHandles(secondHandleInfo, endSelectionHandle_);
314         webSelectInfo_.firstHandle = firstHandleInfo;
315         webSelectInfo_.secondHandle = secondHandleInfo;
316         if (firstHandleInfo.isShow || secondHandleInfo.isShow) {
317             webSelectInfo_.isNewAvoid = false;
318         }
319         webSelectInfo_.handleReverse = false;
320         if (SelectOverlayIsOn()) {
321             UpdateIsSelectAll();
322             UpdateAllHandlesOffset();
323         } else {
324             ProcessOverlay({ .animation = true });
325             isShowHandle_ = true;
326         }
327     }
328 }
329 
HideMagnifier()330 void WebSelectOverlay::HideMagnifier()
331 {
332     auto pattern = GetPattern<WebPattern>();
333     CHECK_NULL_VOID(pattern);
334     pattern->HideMagnifier();
335 }
336 
SetMenuOptions(SelectOverlayInfo & selectInfo,std::shared_ptr<OHOS::NWeb::NWebQuickMenuParams> params,std::shared_ptr<OHOS::NWeb::NWebQuickMenuCallback> callback)337 void WebSelectOverlay::SetMenuOptions(SelectOverlayInfo& selectInfo,
338     std::shared_ptr<OHOS::NWeb::NWebQuickMenuParams> params,
339     std::shared_ptr<OHOS::NWeb::NWebQuickMenuCallback> callback)
340 {
341     quickMenuCallback_ = callback;
342     auto pattern = GetPattern<WebPattern>();
343     CHECK_NULL_VOID(pattern);
344     auto delegate = pattern->delegate_;
345     CHECK_NULL_VOID(delegate);
346     auto copyOption = delegate->GetCopyOptionMode();
347     uint32_t flags = static_cast<uint32_t>(params->GetEditStateFlags());
348     if (!(flags & OHOS::NWeb::NWebQuickMenuParams::QM_EF_CAN_CUT) ||
349         copyOption == OHOS::NWeb::NWebPreference::CopyOptionMode::NONE) {
350         selectInfo.menuInfo.showCut = false;
351     } else {
352         selectInfo.menuInfo.showCut = true;
353     }
354     if (!(flags & OHOS::NWeb::NWebQuickMenuParams::QM_EF_CAN_COPY)) {
355         selectInfo.menuInfo.showCopy = false;
356     } else {
357         selectInfo.menuInfo.showCopy = true;
358     }
359     if (!(flags & OHOS::NWeb::NWebQuickMenuParams::QM_EF_CAN_PASTE)) {
360         selectInfo.menuInfo.showPaste = false;
361     } else {
362         selectInfo.menuInfo.showPaste = true;
363     }
364     if (!(flags & OHOS::NWeb::NWebQuickMenuParams::QM_EF_CAN_SELECT_ALL)) {
365         selectInfo.menuInfo.showCopyAll = false;
366     } else {
367         selectInfo.menuInfo.showCopyAll = true;
368     }
369     bool detectFlag = !isSelectAll_;
370 
371     auto value = GetSelectedText();
372     auto queryWord = std::regex_replace(value, std::regex("^\\s+|\\s+$"), "");
373     if (!queryWord.empty()) {
374         selectInfo.menuInfo.showSearch = true;
375         selectInfo.menuInfo.showTranslate = true;
376     } else {
377         selectInfo.menuInfo.showSearch = false;
378         selectInfo.menuInfo.showTranslate = false;
379     }
380     selectInfo.menuInfo.showAIWrite = !(!(flags & OHOS::NWeb::NWebQuickMenuParams::QM_EF_CAN_CUT) ||
381         (copyOption == OHOS::NWeb::NWebPreference::CopyOptionMode::NONE) || !pattern->IsShowAIWrite());
382     // should be the last
383     canShowAIMenu_ = (copyOption != OHOS::NWeb::NWebPreference::CopyOptionMode::NONE) &&
384                      (copyOption != OHOS::NWeb::NWebPreference::CopyOptionMode::IN_APP);
385     canShowAIMenu_ = canShowAIMenu_ && !(flags & OHOS::NWeb::NWebQuickMenuParams::QM_EF_CAN_CUT);
386     selectInfo.menuInfo.isAskCeliaEnabled = canShowAIMenu_;
387     DetectSelectedText(detectFlag ? value : std::string());
388 }
389 
HideHandleAndQuickMenuIfNecessary(bool hide,bool isScroll)390 void WebSelectOverlay::HideHandleAndQuickMenuIfNecessary(bool hide, bool isScroll)
391 {
392     WebOverlayType overlayType = GetTouchHandleOverlayType(insertHandle_, startSelectionHandle_, endSelectionHandle_);
393     TAG_LOGI(AceLogTag::ACE_WEB,
394         "HideHandleAndQuickMenuIfNecessary hide:%{public}d, overlayType:%{public}d, isScroll:%{public}d",
395         hide, overlayType, isScroll);
396     if (overlayType != SELECTION_OVERLAY) {
397         return;
398     }
399     SelectHandleInfo firstInfo;
400     SelectHandleInfo secondInfo;
401     if (!isScroll) {
402         selectTemporarilyHidden_ = hide;
403         if (selectTemporarilyHiddenByScroll_) {
404             return;
405         }
406     }
407     if (hide) {
408         HideMenu(true);
409         webSelectInfo_.menuInfo.menuIsShow = false;
410         firstInfo.isShow = false;
411         firstInfo.paintRect = ComputeTouchHandleRect(startSelectionHandle_);
412         secondInfo.isShow = false;
413         secondInfo.paintRect = ComputeTouchHandleRect(endSelectionHandle_);
414         webSelectInfo_.firstHandle = firstInfo;
415         webSelectInfo_.secondHandle = secondInfo;
416         UpdateAllHandlesOffset();
417     } else {
418         firstInfo.paintRect = ComputeTouchHandleRect(startSelectionHandle_);
419         secondInfo.paintRect = ComputeTouchHandleRect(endSelectionHandle_);
420         CheckHandles(firstInfo, startSelectionHandle_);
421         CheckHandles(secondInfo, endSelectionHandle_);
422         webSelectInfo_.firstHandle = firstInfo;
423         webSelectInfo_.secondHandle = secondInfo;
424         if (firstInfo.isShow || secondInfo.isShow) {
425             ShowMenu();
426             webSelectInfo_.menuInfo.menuIsShow = true;
427             webSelectInfo_.isNewAvoid = false;
428         } else if (dropParams_) {
429             bool isNewAvoid = false;
430             auto selectArea = ComputeClippedSelectionBounds(
431                 dropParams_, startSelectionHandle_, endSelectionHandle_, isNewAvoid);
432             webSelectInfo_.isNewAvoid = false;
433             webSelectInfo_.selectArea = selectArea;
434         }
435         UpdateAllHandlesOffset();
436     }
437 }
438 
OnParentScrollStartOrEndCallback(bool isEnd)439 void WebSelectOverlay::OnParentScrollStartOrEndCallback(bool isEnd)
440 {
441     if (webSelectInfo_.isSingleHandle && !isEnd)  {
442         webSelectInfo_.menuInfo.menuIsShow = false;
443         return;
444     }
445     selectTemporarilyHiddenByScroll_ = !isEnd;
446     if (selectTemporarilyHidden_) {
447         return;
448     }
449     HideHandleAndQuickMenuIfNecessary(selectTemporarilyHiddenByScroll_, true);
450 }
451 
StopListenSelectOverlayParentScroll(const RefPtr<FrameNode> & host)452 void WebSelectOverlay::StopListenSelectOverlayParentScroll(const RefPtr<FrameNode>& host)
453 {
454     CHECK_NULL_VOID(host);
455     auto context = host->GetContext();
456     CHECK_NULL_VOID(context);
457     auto manager = context->GetSelectOverlayManager();
458     CHECK_NULL_VOID(manager);
459     manager->RemoveScrollCallback(host->GetId());
460 }
461 
RegisterSelectOverlayParentScrollCallback(int32_t parentId,int32_t callbackId)462 void WebSelectOverlay::RegisterSelectOverlayParentScrollCallback(int32_t parentId, int32_t callbackId)
463 {
464     auto pattern = GetPattern<WebPattern>();
465     CHECK_NULL_VOID(pattern);
466     auto host = pattern->GetHost();
467     CHECK_NULL_VOID(host);
468     auto context = host->GetContext();
469     CHECK_NULL_VOID(context);
470     auto manager = context->GetSelectOverlayManager();
471     CHECK_NULL_VOID(manager);
472     auto scrollCallback = [weak = WeakClaim(this)](Axis axis, float offset, int32_t source) {
473         auto client = weak.Upgrade();
474         CHECK_NULL_VOID(client);
475         if (source == SCROLL_FROM_START) {
476             client->OnParentScrollStartOrEndCallback(false);
477         } else if (source == -1) {
478             client->OnParentScrollStartOrEndCallback(true);
479         }
480     };
481     manager->RegisterScrollCallback(parentId, callbackId, scrollCallback);
482 }
483 
StartListenSelectOverlayParentScroll(const RefPtr<FrameNode> & host)484 void WebSelectOverlay::StartListenSelectOverlayParentScroll(const RefPtr<FrameNode>& host)
485 {
486     if (!scrollableParentInfo_.hasParent) {
487         TAG_LOGI(AceLogTag::ACE_WEB, "has no scrollable parent");
488         return;
489     }
490     CHECK_NULL_VOID(host);
491     auto context = host->GetContext();
492     CHECK_NULL_VOID(context);
493     auto hostId = host->GetId();
494     if (!scrollableParentInfo_.parentIds.empty()) {
495         for (const auto& scrollId : scrollableParentInfo_.parentIds) {
496             RegisterSelectOverlayParentScrollCallback(scrollId, hostId);
497         }
498         return;
499     }
500     auto parent = host->GetParent();
501     while (parent && parent->GetTag() != V2::PAGE_ETS_TAG) {
502         auto parentNode = AceType::DynamicCast<FrameNode>(parent);
503         if (parentNode) {
504             auto pattern = parentNode->GetPattern<ScrollablePattern>();
505             if (pattern) {
506                 scrollableParentInfo_.parentIds.emplace_back(parentNode->GetId());
507                 RegisterSelectOverlayParentScrollCallback(parentNode->GetId(), hostId);
508             }
509         }
510         parent = parent->GetParent();
511     }
512     scrollableParentInfo_.hasParent = !scrollableParentInfo_.parentIds.empty();
513     TAG_LOGI(AceLogTag::ACE_WEB, "find scrollable parent %{public}d", scrollableParentInfo_.hasParent);
514 }
515 
UpdateRunQuickMenuSelectInfo(SelectOverlayInfo & selectInfo,std::shared_ptr<OHOS::NWeb::NWebQuickMenuParams> params,std::shared_ptr<OHOS::NWeb::NWebTouchHandleState> insertTouchHandle,std::shared_ptr<OHOS::NWeb::NWebTouchHandleState> beginTouchHandle,std::shared_ptr<OHOS::NWeb::NWebTouchHandleState> endTouchHandle)516 void WebSelectOverlay::UpdateRunQuickMenuSelectInfo(SelectOverlayInfo& selectInfo,
517     std::shared_ptr<OHOS::NWeb::NWebQuickMenuParams> params,
518     std::shared_ptr<OHOS::NWeb::NWebTouchHandleState> insertTouchHandle,
519     std::shared_ptr<OHOS::NWeb::NWebTouchHandleState> beginTouchHandle,
520     std::shared_ptr<OHOS::NWeb::NWebTouchHandleState> endTouchHandle)
521 {
522     selectInfo.hitTestMode = HitTestMode::HTMDEFAULT;
523     isQuickMenuMouseTrigger_ = false;
524     auto pattern = GetPattern<WebPattern>();
525     if (selectInfo.isSingleHandle) {
526         selectInfo.firstHandle.paintRect = ComputeTouchHandleRect(insertTouchHandle);
527         CheckHandles(selectInfo.firstHandle, insertTouchHandle);
528         selectInfo.secondHandle.isShow = false;
529         if (!selectInfo.firstHandle .isShow) {
530             selectInfo.isNewAvoid = true;
531         }
532     } else {
533         selectInfo.firstHandle.paintRect = ComputeTouchHandleRect(beginTouchHandle);
534         selectInfo.secondHandle.paintRect = ComputeTouchHandleRect(endTouchHandle);
535         CheckHandles(selectInfo.firstHandle, beginTouchHandle);
536         CheckHandles(selectInfo.secondHandle, endTouchHandle);
537         QuickMenuIsNeedNewAvoid(selectInfo, params, beginTouchHandle, endTouchHandle);
538         if (pattern && !(pattern->onCreateMenuCallback_ && pattern->onMenuItemClick_)) {
539             selectInfo.menuOptionItems = pattern->menuOptionParam_;
540         }
541     }
542     selectInfo.menuInfo.menuIsShow = true;
543     selectInfo.handleReverse = false;
544     if (pattern && pattern->onCreateMenuCallback_ && pattern->onMenuItemClick_) {
545         selectInfo.onCreateCallback.onCreateMenuCallback = pattern->onCreateMenuCallback_;
546         selectInfo.onCreateCallback.onMenuItemClick = pattern->onMenuItemClick_;
547         if (pattern->onPrepareMenuCallback_) {
548             selectInfo.onCreateCallback.onPrepareMenuCallback = pattern->onPrepareMenuCallback_;
549             selectInfo.menuInfo.hasOnPrepareMenuCallback = true;
550         }
551         auto textRange = [](int32_t& start, int32_t& end) {
552             start = -1;
553             end = -1;
554         };
555         selectInfo.onCreateCallback.textRangeCallback = textRange;
556     }
557 }
558 
QuickMenuIsNeedNewAvoid(SelectOverlayInfo & selectInfo,std::shared_ptr<OHOS::NWeb::NWebQuickMenuParams> params,std::shared_ptr<OHOS::NWeb::NWebTouchHandleState> startHandle,std::shared_ptr<OHOS::NWeb::NWebTouchHandleState> endHandle)559 void WebSelectOverlay::QuickMenuIsNeedNewAvoid(
560     SelectOverlayInfo& selectInfo,
561     std::shared_ptr<OHOS::NWeb::NWebQuickMenuParams> params,
562     std::shared_ptr<OHOS::NWeb::NWebTouchHandleState> startHandle,
563     std::shared_ptr<OHOS::NWeb::NWebTouchHandleState> endHandle)
564 {
565     isQuickMenuMouseTrigger_ = false;
566     if (!selectInfo.firstHandle.isShow && !selectInfo.secondHandle.isShow) {
567         selectInfo.isNewAvoid = true;
568         if ((startHandle->GetEdgeHeight() == 0 && startHandle->GetTouchHandleId() == -1) &&
569             (endHandle->GetEdgeHeight() == 0 && endHandle->GetTouchHandleId() == -1)) {
570             isQuickMenuMouseTrigger_ = true;
571             selectInfo.selectArea = ComputeMouseClippedSelectionBounds(
572                 params->GetSelectX(), params->GetSelectY(), params->GetSelectWidth(), params->GetSelectXHeight());
573         } else {
574             selectInfo.selectArea =
575                 ComputeClippedSelectionBounds(params, startHandle, endHandle, selectInfo.isNewAvoid);
576         }
577     } else {
578         float selectX = params->GetSelectX();
579         float selectY = params->GetSelectY();
580         float selectWidth = params->GetSelectWidth();
581         float selectHeight = params->GetSelectXHeight();
582         selectInfo.selectArea = RectF(selectX, selectY, selectWidth, selectHeight);
583     }
584 }
585 
ComputeClippedSelectionBounds(std::shared_ptr<OHOS::NWeb::NWebQuickMenuParams> params,std::shared_ptr<OHOS::NWeb::NWebTouchHandleState> startHandle,std::shared_ptr<OHOS::NWeb::NWebTouchHandleState> endHandle,bool & isNewAvoid)586 RectF WebSelectOverlay::ComputeClippedSelectionBounds(
587     std::shared_ptr<OHOS::NWeb::NWebQuickMenuParams> params,
588     std::shared_ptr<OHOS::NWeb::NWebTouchHandleState> startHandle,
589     std::shared_ptr<OHOS::NWeb::NWebTouchHandleState> endHandle, bool& isNewAvoid)
590 {
591     auto pattern = GetPattern<WebPattern>();
592     CHECK_NULL_RETURN(pattern, RectF());
593     auto pipeline = PipelineBase::GetCurrentContext();
594     CHECK_NULL_RETURN(pipeline, RectF());
595     auto host = pattern->GetHost();
596     CHECK_NULL_RETURN(host, RectF());
597     float selectX = params->GetSelectX();
598     float selectY = params->GetSelectY();
599     float selectWidth = params->GetSelectWidth();
600     float selectHeight = params->GetSelectXHeight();
601     float viewPortX = static_cast<float>((startHandle->GetViewPortX() + endHandle->GetViewPortX())) / 2;
602     float viewPortY = static_cast<float>((startHandle->GetViewPortY() + endHandle->GetViewPortY())) / 2;
603     auto offset = pattern->GetCoordinatePoint().value_or(OffsetF());
604     RectF visibleRect;
605     RectF visibleInnerRect;
606     RectF frameRect;
607     host->GetVisibleRectWithClip(visibleRect, visibleInnerRect, frameRect);
608     auto visibleTop = visibleInnerRect.Top();
609     auto visibleBottom = GetBottomWithKeyboard(visibleInnerRect.Bottom());
610     isNewAvoid = true;
611     if (LessOrEqual(visibleBottom, selectY + viewPortY + offset.GetY()) ||
612         LessOrEqual(selectY + selectHeight + offset.GetY(), visibleTop)) {
613         isNewAvoid = false;
614         return RectF();
615     } else if (LessOrEqual(selectY + offset.GetY(), visibleTop) &&
616         LessOrEqual(visibleBottom, selectY + viewPortY + selectHeight + offset.GetY())) {
617         return RectF(offset.GetX(), offset.GetY(), pattern->drawSize_.Width(), pattern->drawSize_.Height());
618     }
619     auto theme = pipeline->GetTheme<TextOverlayTheme>();
620     float radius = theme ? theme->GetHandleHotZoneRadius().ConvertToPx() : 0.0;
621     if (LessOrEqual(visibleBottom, selectY + viewPortY + startHandle->GetEdgeHeight() + offset.GetY())) {
622         selectX = startHandle->GetX() + offset.GetX();
623         selectY = startHandle->GetY() + offset.GetY() - radius - startHandle->GetEdgeHeight() - SELECT_MENE_HEIGHT;
624         selectWidth = SelectHandleInfo::GetDefaultLineWidth().ConvertToPx();
625     } else if (LessOrEqual(selectY + selectHeight - endHandle->GetEdgeHeight() + offset.GetY(), visibleTop)) {
626         selectX = endHandle->GetX() + offset.GetX();
627         selectY = endHandle->GetY() + offset.GetY() + radius;
628         selectWidth = SelectHandleInfo::GetDefaultLineWidth().ConvertToPx();
629     } else {
630         selectX = selectX + viewPortX + offset.GetX();
631         selectY = selectY + viewPortY + offset.GetY() - SELECT_MENE_HEIGHT - radius;
632         if (selectY < offset.GetY())
633             selectY = offset.GetY();
634     }
635     return RectF(selectX, selectY, selectWidth, SELECT_MENE_HEIGHT);
636 }
637 
ComputeMouseClippedSelectionBounds(int32_t x,int32_t y,int32_t w,int32_t h)638 RectF WebSelectOverlay::ComputeMouseClippedSelectionBounds(int32_t x, int32_t y, int32_t w, int32_t h)
639 {
640     auto pattern = GetPattern<WebPattern>();
641     CHECK_NULL_RETURN(pattern, RectF());
642     auto offset = pattern->GetCoordinatePoint().value_or(OffsetF());
643     float selectX = offset.GetX() + x;
644     float selectY = offset.GetY();
645     float selectWidth = w;
646     float selectHeight = h;
647     if (LessOrEqual(pattern->GetHostFrameSize().value_or(SizeF()).Height(), y)) {
648         selectY += pattern->GetHostFrameSize().value_or(SizeF()).Height();
649     } else if (y + h <= 0) {
650         selectY -= h;
651     } else {
652         selectY += y;
653     }
654     return RectF(selectX, selectY, selectWidth, selectHeight);
655 }
656 
CheckHandles(SelectHandleInfo & handleInfo,const std::shared_ptr<OHOS::NWeb::NWebTouchHandleState> & handle)657 void WebSelectOverlay::CheckHandles(SelectHandleInfo& handleInfo,
658     const std::shared_ptr<OHOS::NWeb::NWebTouchHandleState>& handle)
659 {
660     auto pattern = GetPattern<WebPattern>();
661     CHECK_NULL_VOID(pattern);
662     CHECK_NULL_VOID(handle);
663     auto pipeline = PipelineBase::GetCurrentContext();
664     CHECK_NULL_VOID(pipeline);
665     int y = static_cast<int32_t>(handle->GetY() / pipeline->GetDipScale());
666     int edgeHeight = static_cast<int32_t>(handle->GetEdgeHeight() / pipeline->GetDipScale()) - 1;
667     if (handle->GetAlpha() <= 0 || y < edgeHeight) {
668         handleInfo.isShow = false;
669         return;
670     }
671     auto host = pattern->GetHost();
672     CHECK_NULL_VOID(host);
673     float viewPortY = handle->GetViewPortY();
674     RectF visibleRect;
675     RectF visibleInnerRect;
676     RectF frameRect;
677     host->GetVisibleRectWithClip(visibleRect, visibleInnerRect, frameRect);
678     visibleInnerRect.SetRect(visibleInnerRect.GetX(), visibleInnerRect.GetY() + viewPortY - 1,
679         visibleInnerRect.Width(), visibleInnerRect.Height() - viewPortY + 1);
680     auto paintRect = handleInfo.paintRect;
681     PointF bottomPoint = { paintRect.Left(), paintRect.Bottom() };
682     PointF topPoint = { paintRect.Left(), paintRect.Top() };
683     handleInfo.isShow = (visibleInnerRect.IsInRegion(bottomPoint) && visibleInnerRect.IsInRegion(topPoint));
684 }
685 
ComputeTouchHandleRect(std::shared_ptr<OHOS::NWeb::NWebTouchHandleState> touchHandle)686 RectF WebSelectOverlay::ComputeTouchHandleRect(std::shared_ptr<OHOS::NWeb::NWebTouchHandleState> touchHandle)
687 {
688     auto pattern = GetPattern<WebPattern>();
689     CHECK_NULL_RETURN(pattern, RectF());
690     CHECK_NULL_RETURN(touchHandle, RectF());
691     RectF paintRect;
692     auto offset = pattern->GetCoordinatePoint().value_or(OffsetF());
693     auto size = pattern->GetHostFrameSize().value_or(SizeF());
694     float edgeHeight = touchHandle->GetEdgeHeight();
695     float x = touchHandle->GetX();
696     float y = touchHandle->GetY();
697     if (x > size.Width()) {
698         x = offset.GetX() + size.Width();
699     } else {
700         x = x + offset.GetX();
701     }
702 
703     if (y < 0) {
704         y = offset.GetY();
705     } else if (y > size.Height()) {
706         y = offset.GetY() + size.Height();
707     } else {
708         float diff = 0;
709         auto pipeline = PipelineBase::GetCurrentContext();
710         if (pipeline) {
711             auto dipScale = pipeline->GetDipScale();
712             if (dipScale != 0) {
713                 diff = edgeHeight - static_cast<int32_t>(static_cast<int32_t>(edgeHeight / dipScale) * dipScale);
714             }
715         }
716         y = y + offset.GetY() - edgeHeight + diff;
717     }
718 
719     paintRect.SetOffset({ x, y });
720     paintRect.SetSize({ SelectHandleInfo::GetDefaultLineWidth().ConvertToPx(), edgeHeight });
721     return paintRect;
722 }
723 
GetTouchHandleOverlayType(std::shared_ptr<OHOS::NWeb::NWebTouchHandleState> insertHandle,std::shared_ptr<OHOS::NWeb::NWebTouchHandleState> startSelectionHandle,std::shared_ptr<OHOS::NWeb::NWebTouchHandleState> endSelectionHandle)724 WebOverlayType WebSelectOverlay::GetTouchHandleOverlayType(
725     std::shared_ptr<OHOS::NWeb::NWebTouchHandleState> insertHandle,
726     std::shared_ptr<OHOS::NWeb::NWebTouchHandleState> startSelectionHandle,
727     std::shared_ptr<OHOS::NWeb::NWebTouchHandleState> endSelectionHandle)
728 {
729     if (IsTouchHandleValid(insertHandle) && !IsTouchHandleValid(startSelectionHandle) &&
730         !IsTouchHandleValid(endSelectionHandle)) {
731         return INSERT_OVERLAY;
732     }
733 
734     if (!IsTouchHandleValid(insertHandle) && IsTouchHandleValid(startSelectionHandle) &&
735         IsTouchHandleValid(endSelectionHandle)) {
736         return SELECTION_OVERLAY;
737     }
738 
739     return INVALID_OVERLAY;
740 }
741 
RegisterSelectOverLayOnClose(SelectOverlayInfo & selectInfo)742 void WebSelectOverlay::RegisterSelectOverLayOnClose(SelectOverlayInfo& selectInfo)
743 {
744     selectInfo.onClose = [weak = AceType::WeakClaim(this)] (bool isGlobalTouchEvent) {
745         if (!isGlobalTouchEvent) {
746             return;
747         }
748         TAG_LOGI(AceLogTag::ACE_WEB, "globalTouchEvent, close web select overLayer.");
749         auto selectOverlay = weak.Upgrade();
750         CHECK_NULL_VOID(selectOverlay);
751         selectOverlay->CloseOverlay(false, CloseReason::CLOSE_REASON_CLICK_OUTSIDE);
752         selectOverlay->SelectCancel();
753     };
754 }
755 
SelectCancel()756 void WebSelectOverlay::SelectCancel()
757 {
758     CHECK_NULL_VOID(quickMenuCallback_);
759     quickMenuCallback_->Cancel();
760     isSelectAll_ = false;
761     insertHandle_ = nullptr;
762     startSelectionHandle_ = nullptr;
763     endSelectionHandle_ = nullptr;
764     quickMenuCallback_ = nullptr;
765 }
766 
UpdateClippedSelectionBounds(int32_t x,int32_t y,int32_t w,int32_t h)767 void WebSelectOverlay::UpdateClippedSelectionBounds(int32_t x, int32_t y, int32_t w, int32_t h)
768 {
769     webSelectInfo_.selectArea = ComputeMouseClippedSelectionBounds(x, y, w, h);
770 }
771 
ChangeVisibilityOfQuickMenu()772 void WebSelectOverlay::ChangeVisibilityOfQuickMenu()
773 {
774     WebOverlayType overlayType = GetTouchHandleOverlayType(insertHandle_, startSelectionHandle_, endSelectionHandle_);
775     if (overlayType == SELECTION_OVERLAY && !selectTemporarilyHidden_ && !selectTemporarilyHiddenByScroll_) {
776         bool isMenuShow = IsShowMenu();
777         if (isMenuShow) {
778             HideMenu(true);
779             SetMenuIsShow(false);
780             webSelectInfo_.menuInfo.menuIsShow = false;
781         } else {
782             ShowMenu();
783             SetMenuIsShow(true);
784             webSelectInfo_.menuInfo.menuIsShow = true;
785         }
786         TAG_LOGI(AceLogTag::ACE_WEB, "Current menu display status is %{public}d.", isMenuShow);
787     }
788 }
789 
PreProcessOverlay(const OverlayRequest & request)790 bool WebSelectOverlay::PreProcessOverlay(const OverlayRequest& request)
791 {
792     auto pattern = GetPattern<WebPattern>();
793     CHECK_NULL_RETURN(pattern, false);
794     auto pipeline = PipelineContext::GetCurrentContextSafely();
795     CHECK_NULL_RETURN(pipeline, false);
796     auto host = pattern->GetHost();
797     CHECK_NULL_RETURN(host, false);
798     SetEnableHandleLevel(true);
799     SetEnableSubWindowMenu(true);
800     SetMenuTranslateIsSupport(true);
801     SetIsSupportMenuSearch(true);
802     CheckEnableContainerModal();
803     pipeline->AddOnAreaChangeNode(host->GetId());
804     return true;
805 }
806 
CheckHandleVisible(const RectF & paintRect)807 bool WebSelectOverlay::CheckHandleVisible(const RectF& paintRect)
808 {
809     return true;
810 }
811 
GetFirstHandleInfo()812 std::optional<SelectHandleInfo> WebSelectOverlay::GetFirstHandleInfo()
813 {
814     if (webSelectInfo_.secondHandle.paintRect.IsEmpty() && !webSelectInfo_.secondHandle.isShow) {
815         webSelectInfo_.handleReverse = false;
816         needResetHandleReverse_ = true;
817     }
818     return webSelectInfo_.firstHandle;
819 }
820 
GetSecondHandleInfo()821 std::optional<SelectHandleInfo> WebSelectOverlay::GetSecondHandleInfo()
822 {
823     return webSelectInfo_.secondHandle;
824 }
825 
OnUpdateMenuInfo(SelectMenuInfo & menuInfo,SelectOverlayDirtyFlag dirtyFlag)826 void WebSelectOverlay::OnUpdateMenuInfo(SelectMenuInfo& menuInfo, SelectOverlayDirtyFlag dirtyFlag)
827 {
828     menuInfo = webSelectInfo_.menuInfo;
829 }
830 
GetSelectArea()831 RectF WebSelectOverlay::GetSelectArea()
832 {
833     return webSelectInfo_.selectArea;
834 }
835 
GetSelectedText()836 std::string WebSelectOverlay::GetSelectedText()
837 {
838     auto pattern = GetPattern<WebPattern>();
839     CHECK_NULL_RETURN(pattern, "");
840     return pattern->GetSelectInfo();
841 }
842 
IsTouchHandleValid(std::shared_ptr<OHOS::NWeb::NWebTouchHandleState> handle)843 bool WebSelectOverlay::IsTouchHandleValid(std::shared_ptr<OHOS::NWeb::NWebTouchHandleState> handle)
844 {
845     return (handle != nullptr) && (handle->IsEnable());
846 }
847 
OnMenuItemAction(OptionMenuActionId id,OptionMenuType type)848 void WebSelectOverlay::OnMenuItemAction(OptionMenuActionId id, OptionMenuType type)
849 {
850     TAG_LOGI(AceLogTag::ACE_WEB, "OnMenuItemAction menu option id %{public}d", id);
851     auto pattern = GetPattern<WebPattern>();
852     CHECK_NULL_VOID(pattern);
853     if (id == OptionMenuActionId::PASTE || id == OptionMenuActionId::CUT) {
854         isSelectAll_ = false;
855     }
856     if (!quickMenuCallback_) {
857         TAG_LOGE(AceLogTag::ACE_WEB, "OnMenuItemAction failed callback is null");
858         pattern->CloseSelectOverlay();
859         return;
860     }
861     switch (id) {
862         case OptionMenuActionId::COPY:
863             quickMenuCallback_->Continue(
864                 OHOS::NWeb::NWebQuickMenuParams::QM_EF_CAN_COPY, OHOS::NWeb::MenuEventFlags::EF_LEFT_MOUSE_BUTTON);
865             ChangeVisibilityOfQuickMenu();
866             break;
867         case OptionMenuActionId::CUT:
868             quickMenuCallback_->Continue(
869                 OHOS::NWeb::NWebQuickMenuParams::QM_EF_CAN_CUT, OHOS::NWeb::MenuEventFlags::EF_LEFT_MOUSE_BUTTON);
870             pattern->CloseSelectOverlay();
871             break;
872         case OptionMenuActionId::PASTE:
873             quickMenuCallback_->Continue(
874                 OHOS::NWeb::NWebQuickMenuParams::QM_EF_CAN_PASTE, OHOS::NWeb::MenuEventFlags::EF_LEFT_MOUSE_BUTTON);
875             pattern->CloseSelectOverlay();
876             break;
877         case OptionMenuActionId::SELECT_ALL:
878             quickMenuCallback_->Continue(OHOS::NWeb::NWebQuickMenuParams::QM_EF_CAN_SELECT_ALL,
879                 OHOS::NWeb::MenuEventFlags::EF_LEFT_MOUSE_BUTTON);
880             isSelectAll_ = true;
881             break;
882         case OptionMenuActionId::TRANSLATE:
883             HandleOnTranslate();
884             pattern->CloseSelectOverlay();
885             SelectCancel();
886             break;
887         case OptionMenuActionId::SEARCH:
888             HandleOnSearch();
889             pattern->CloseSelectOverlay();
890             SelectCancel();
891             break;
892         case OptionMenuActionId::AI_WRITE:
893             pattern->GetHandleInfo(webSelectInfo_);
894             pattern->HandleOnAIWrite();
895             SelectCancel();
896             break;
897         case OptionMenuActionId::DISAPPEAR:
898             pattern->CloseSelectOverlay();
899             SelectCancel();
900             break;
901         case OptionMenuActionId::AI_MENU_OPTION:
902             if (auto adapter = pattern->webDataDetectorAdapter_) {
903                 adapter->OnClickAISelectMenuOption(aiMenuType_, aiMenucontent_);
904             }
905             pattern->CloseSelectOverlay();
906             SelectCancel();
907             break;
908         case OptionMenuActionId::ASK_CELIA:
909             HandleOnAskCelia();
910             break;
911         default:
912             break;
913     }
914 }
915 
HandleOnAskCelia()916 void WebSelectOverlay::HandleOnAskCelia()
917 {
918     auto pattern = GetPattern<WebPattern>();
919     CHECK_NULL_VOID(pattern);
920     auto vectorStringFunc = pattern->textDetectResult_.menuOptionAndAction.find(ASK_CELIA_TAG);
921     if (vectorStringFunc == pattern->textDetectResult_.menuOptionAndAction.end() || vectorStringFunc->second.empty()) {
922         TAG_LOGE(AceLogTag::ACE_WEB, "HandleOnAskCelia failed no askCelia option.");
923     } else {
924         auto funcVariant = vectorStringFunc->second.begin()->second;
925         if (std::holds_alternative<std::function<void(int, std::string)>>(funcVariant)) {
926             auto func = std::get<std::function<void(int, std::string)>>(funcVariant);
927             if (func) {
928                 TAG_LOGI(AceLogTag::ACE_WEB, "HandleOnAskCelia execute.");
929                 func(true, GetSelectedText());
930             } else {
931                 TAG_LOGE(AceLogTag::ACE_WEB, "HandleOnAskCelia failed option is null.");
932             }
933         } else {
934             TAG_LOGE(AceLogTag::ACE_WEB, "HandleOnAskCelia failed option type error.");
935         }
936     }
937     pattern->CloseSelectOverlay();
938     SelectCancel();
939     return;
940 }
941 
OnMenuItemAction(OptionMenuActionId id,OptionMenuType type,const std::string & labelInfo)942 void WebSelectOverlay::OnMenuItemAction(OptionMenuActionId id, OptionMenuType type, const std::string& labelInfo)
943 {
944     OnMenuItemAction(id, type);
945 }
946 
OnHandleMove(const RectF & handleRect,bool isFirst)947 void WebSelectOverlay::OnHandleMove(const RectF& handleRect, bool isFirst)
948 {
949     auto pattern = GetPattern<WebPattern>();
950     CHECK_NULL_VOID(pattern);
951     auto pipeline = PipelineContext::GetCurrentContext();
952     CHECK_NULL_VOID(pipeline);
953     auto manager = pipeline->GetDragDropManager();
954     CHECK_NULL_VOID(manager);
955     if (pattern->isDragging_ || manager->IsDragged()) {
956         return;
957     }
958     TouchInfo touchPoint;
959     touchPoint.id = 0;
960     touchPoint.x = handleRect.GetX() - pattern->webOffset_.GetX();
961     touchPoint.y = handleRect.GetY() - pattern->webOffset_.GetY() + handleRect.Height() / HALF;
962     if (pattern->IsOverlayCreating()) {
963         pattern->UpdateImageOverlayTouchInfo(touchPoint.x, touchPoint.y, TouchType::MOVE);
964     } else {
965         std::vector<std::shared_ptr<OHOS::NWeb::NWebTouchPointInfo>> touch_point_infos;
966         std::shared_ptr<OHOS::NWeb::NWebTouchPointInfo> touch_point_info =
967             std::make_shared<NWebTouchPointInfoImpl>(touchPoint.id, touchPoint.x, touchPoint.y);
968         touch_point_infos.emplace_back(touch_point_info);
969         pattern->delegate_->HandleTouchMove(touch_point_infos, true);
970     }
971     OnMagnifierHandleMove(handleRect, isFirst);
972 }
973 
OnHandleMoveStart(const GestureEvent & event,bool isFirst)974 void WebSelectOverlay::OnHandleMoveStart(const GestureEvent& event, bool isFirst)
975 {
976     selectOverlayDragging_ = true;
977     isCurrentStartHandleDragging_ = isFirst;
978     auto pattern = GetPattern<WebPattern>();
979     CHECK_NULL_VOID(pattern);
980     auto delegate = pattern->delegate_;
981     CHECK_NULL_VOID(delegate);
982     RectF handleRect = ChangeHandleHeight(event, isFirst);
983     TouchInfo touchPoint;
984     touchPoint.id = 0;
985     touchPoint.x = handleRect.GetX() - pattern->webOffset_.GetX();
986     touchPoint.y = handleRect.GetY() - pattern->webOffset_.GetY() + handleRect.Height() / HALF;
987     pattern->PushOverlayInfo(touchPoint.x, touchPoint.y, touchPoint.id);
988     delegate->HandleTouchDown(touchPoint.id, touchPoint.x, touchPoint.y, true);
989     if (pattern->IsOverlayCreating()) {
990         pattern->UpdateImageOverlayTouchInfo(touchPoint.x, touchPoint.y, TouchType::DOWN);
991     }
992     aiMenuType_ = TextDataDetectType::INVALID;
993     webSelectInfo_.menuInfo.aiMenuOptionType = aiMenuType_;
994     webSelectInfo_.menuInfo.isAskCeliaEnabled = canShowAIMenu_;
995     pattern->WebOverlayRequestFocus();
996 }
997 
OnHandleMoveDone(const RectF & rect,bool isFirst)998 void WebSelectOverlay::OnHandleMoveDone(const RectF& rect, bool isFirst)
999 {
1000     HideMagnifier();
1001     isSelectAll_ = false;
1002     selectOverlayDragging_ = false;
1003     webSelectInfo_.menuInfo.showCopyAll = true;
1004     UpdateSelectMenuOptions();
1005     auto pattern = GetPattern<WebPattern>();
1006     CHECK_NULL_VOID(pattern);
1007     auto delegate = pattern->delegate_;
1008     CHECK_NULL_VOID(delegate);
1009     DetectSelectedText(GetSelectedText());
1010     TouchInfo touchPoint;
1011     touchPoint.id = 0;
1012     touchPoint.x = rect.GetX() - pattern->webOffset_.GetX();
1013     touchPoint.y = rect.GetY() - pattern->webOffset_.GetY() + rect.Height() / HALF;
1014     pattern->DelTouchOverlayInfoByTouchId(touchPoint.id);
1015     if (!pattern->IsOverlayCreating()) {
1016         delegate->HandleTouchUp(touchPoint.id, touchPoint.x, touchPoint.y, true);
1017     } else if (pattern->imageAnalyzerManager_) {
1018         pattern->UpdateImageOverlayTouchInfo(touchPoint.x, touchPoint.y, TouchType::UP);
1019         pattern->SetOverlayCreating(false);
1020         delegate->HandleTouchCancel();
1021     }
1022     UpdateTouchHandleForOverlay(true);
1023     if (!IsShowMenu()) {
1024         ChangeVisibilityOfQuickMenu();
1025     }
1026     if (startSelectionHandle_ && endSelectionHandle_) {
1027         auto offset = pattern->GetCoordinatePoint().value_or(OffsetF());
1028         auto size = pattern->GetHostFrameSize().value_or(SizeF());
1029         TAG_LOGI(AceLogTag::ACE_WEB, "OnSelectHandleDone offset(%{public}f,%{public}f) size(%{public}f,%{public}f)"
1030             "start(%{public}d,%{public}d) end(%{public}d,%{public}d)", offset.GetX(), offset.GetY(),
1031             size.Width(), size.Height(), startSelectionHandle_->GetX(), startSelectionHandle_->GetY(),
1032             endSelectionHandle_->GetX(), endSelectionHandle_->GetY());
1033     }
1034     WebOverlayType overlayType = GetTouchHandleOverlayType(insertHandle_, startSelectionHandle_, endSelectionHandle_);
1035     if (overlayType == SELECTION_OVERLAY && !pattern->IsSelectInfoValid()) {
1036         TAG_LOGI(AceLogTag::ACE_WEB, "Close handles and menu.");
1037         pattern->CloseSelectOverlay();
1038         SelectCancel();
1039     }
1040     UpdateSingleHandleVisible(true);
1041 }
1042 
OnCloseOverlay(OptionMenuType menuType,CloseReason reason,RefPtr<OverlayInfo> info)1043 void WebSelectOverlay::OnCloseOverlay(OptionMenuType menuType, CloseReason reason, RefPtr<OverlayInfo> info)
1044 {
1045     selectOverlayDragging_ = false;
1046     selectTemporarilyHidden_ = false;
1047     selectTemporarilyHiddenByScroll_ = false;
1048     isShowHandle_ = false;
1049     if (CloseReason::CLOSE_REASON_BACK_PRESSED == reason) {
1050         SelectCancel();
1051     }
1052     auto pattern = GetPattern<WebPattern>();
1053     CHECK_NULL_VOID(pattern);
1054     auto host = pattern->GetHost();
1055     CHECK_NULL_VOID(host);
1056     aiMenuType_ = TextDataDetectType::INVALID;
1057     webSelectInfo_.menuInfo.aiMenuOptionType = aiMenuType_;
1058     webSelectInfo_.menuInfo.isAskCeliaEnabled = canShowAIMenu_;
1059     StopListenSelectOverlayParentScroll(host);
1060     SetTouchHandleExistState(false);
1061 }
1062 
AfterCloseOverlay()1063 void WebSelectOverlay::AfterCloseOverlay()
1064 {
1065     selectOverlayDragging_ = false;
1066     isShowHandle_ = false;
1067 }
1068 
OnOverlayClick(const GestureEvent & event,bool isClickCaret)1069 void WebSelectOverlay::OnOverlayClick(const GestureEvent& event, bool isClickCaret)
1070 {
1071     auto pattern = GetPattern<WebPattern>();
1072     CHECK_NULL_VOID(pattern);
1073     auto host = pattern->GetHost();
1074     CHECK_NULL_VOID(host);
1075     auto focusHub = host->GetOrCreateFocusHub();
1076     CHECK_NULL_VOID(focusHub);
1077     auto delegate = pattern->delegate_;
1078     CHECK_NULL_VOID(delegate);
1079     if (!focusHub->IsFocusable() || event.GetSourceDevice() == SourceType::MOUSE) {
1080         return;
1081     }
1082     if (selectOverlayDragging_) {
1083         TAG_LOGI(AceLogTag::ACE_WEB, "HandleTouchClickEvent fail when handle dragging.");
1084         return;
1085     }
1086     if (!IsTouchHandleValid(insertHandle_)) {
1087         return;
1088     }
1089     auto globalLocation = event.GetGlobalLocation();
1090     TouchInfo touchPoint;
1091     touchPoint.id = 0;
1092     touchPoint.x = globalLocation.GetX() - pattern->webOffset_.GetX();
1093     touchPoint.y = globalLocation.GetY() - pattern->webOffset_.GetY();
1094     auto pipeline = host->GetContext();
1095     CHECK_NULL_VOID(pipeline);
1096     auto theme = pipeline->GetTheme<TextOverlayTheme>();
1097     CHECK_NULL_VOID(theme);
1098     float hotZone = theme->GetHandleHotZoneRadius().ConvertToPx();
1099     RectF edgeRect(insertHandle_->GetX() - hotZone / HALF,
1100                    insertHandle_->GetY() - insertHandle_->GetEdgeHeight(),
1101                    hotZone,
1102                    insertHandle_->GetEdgeHeight());
1103     bool isInRegion = edgeRect.IsInRegion({touchPoint.x, touchPoint.y});
1104     TAG_LOGI(AceLogTag::ACE_WEB, "point.x:%{public}f. y:%{public}f, isInRegion:%{public}d",
1105         touchPoint.x, touchPoint.y, isInRegion);
1106     TAG_LOGI(AceLogTag::ACE_WEB, "edgeRect:%{public}s", edgeRect.ToString().c_str());
1107     delegate->HandleTouchDown(touchPoint.id, touchPoint.x, touchPoint.y, !isInRegion);
1108     delegate->HandleTouchUp(touchPoint.id, touchPoint.x, touchPoint.y, !isInRegion);
1109 }
1110 
CheckTouchInHostNode(const PointF & touchPoint)1111 bool WebSelectOverlay::CheckTouchInHostNode(const PointF& touchPoint)
1112 {
1113     return true;
1114 }
1115 
OnHandleReverse(bool isReverse)1116 void WebSelectOverlay::OnHandleReverse(bool isReverse)
1117 {
1118     if (isReverse && needResetHandleReverse_) {
1119         TAG_LOGI(AceLogTag::ACE_WEB, "WebSelectOverlay should reset handleReverse.");
1120         auto manager = GetManager<SelectContentOverlayManager>();
1121         CHECK_NULL_VOID(manager);
1122         manager->MarkInfoChange(DIRTY_DOUBLE_HANDLE);
1123     } else {
1124         needResetHandleReverse_ = false;
1125     }
1126 }
1127 
OnHandleGlobalTouchEvent(SourceType sourceType,TouchType touchType,bool touchInside)1128 void WebSelectOverlay::OnHandleGlobalTouchEvent(SourceType sourceType, TouchType touchType, bool touchInside)
1129 {
1130     if (EventInfoConvertor::MatchCompatibleCondition() && IsMouseClickDown(sourceType, touchType)) {
1131         return;
1132     }
1133     if (IsMouseClickDown(sourceType, touchType) || IsTouchUp(sourceType, touchType)) {
1134         CloseOverlay(false, CloseReason::CLOSE_REASON_CLICK_OUTSIDE);
1135         SelectCancel();
1136     }
1137 }
1138 
OnUpdateSelectOverlayInfo(SelectOverlayInfo & selectInfo,int32_t requestCode)1139 void WebSelectOverlay::OnUpdateSelectOverlayInfo(SelectOverlayInfo &selectInfo, int32_t requestCode)
1140 {
1141     selectInfo.isNewAvoid = webSelectInfo_.isNewAvoid;
1142     selectInfo.isSingleHandle = webSelectInfo_.isSingleHandle;
1143     selectInfo.menuOptionItems = webSelectInfo_.menuOptionItems;
1144     selectInfo.handleReverse = webSelectInfo_.handleReverse;
1145     selectInfo.hitTestMode = webSelectInfo_.hitTestMode;
1146     selectInfo.onCreateCallback = webSelectInfo_.onCreateCallback;
1147     selectInfo.onClose = webSelectInfo_.onClose;
1148     selectInfo.onClick = webSelectInfo_.onClick;
1149     selectInfo.enableHandleLevel = true;
1150     selectInfo.enableSubWindowMenu = true;
1151     if (IS_CALLING_FROM_M114()) {
1152         selectInfo.isHandleLineShow = webSelectInfo_.isHandleLineShow;
1153     }
1154     selectInfo.computeMenuOffset = webSelectInfo_.computeMenuOffset;
1155 }
1156 
OnHandleMarkInfoChange(const std::shared_ptr<SelectOverlayInfo> info,SelectOverlayDirtyFlag flag)1157 void WebSelectOverlay::OnHandleMarkInfoChange(
1158     const std::shared_ptr<SelectOverlayInfo> info, SelectOverlayDirtyFlag flag)
1159 {
1160     auto manager = GetManager<SelectContentOverlayManager>();
1161     CHECK_NULL_VOID(manager);
1162     if ((flag & DIRTY_HANDLE_COLOR_FLAG) == DIRTY_HANDLE_COLOR_FLAG) {
1163         info->handlerColor = GetHandleColor();
1164         manager->MarkHandleDirtyNode(PROPERTY_UPDATE_RENDER);
1165     }
1166     if ((flag & DIRTY_FIRST_HANDLE) == DIRTY_FIRST_HANDLE || (flag & DIRTY_SECOND_HANDLE) == DIRTY_SECOND_HANDLE) {
1167         if (info->menuInfo.showShare != (IsSupportMenuShare() && AllowShare() && IsNeedMenuShare())) {
1168             info->menuInfo.showShare = !info->menuInfo.showShare;
1169             manager->NotifyUpdateToolBar(true);
1170         }
1171         if (info->menuInfo.aiMenuOptionType != aiMenuType_) {
1172             TAG_LOGI(AceLogTag::ACE_WEB, "WebSelectOverlay::OnHandleMarkInfoChange aiMenuOptionType change.");
1173             info->menuInfo.aiMenuOptionType = aiMenuType_;
1174             info->menuInfo.isAskCeliaEnabled = canShowAIMenu_ && (aiMenuType_ == TextDataDetectType::INVALID);
1175             manager->NotifyUpdateToolBar(true);
1176         }
1177     }
1178     if ((flag & DIRTY_DOUBLE_HANDLE) == DIRTY_DOUBLE_HANDLE) {
1179         if (needResetHandleReverse_) {
1180             TAG_LOGI(AceLogTag::ACE_WEB, "WebSelectOverlay OnHandleMarkInfoChange reset handleReverse.");
1181             info->handleReverse = webSelectInfo_.handleReverse;
1182             manager->MarkHandleDirtyNode(PROPERTY_UPDATE_RENDER);
1183             needResetHandleReverse_ = false;
1184         }
1185     }
1186 }
1187 
OnAfterSelectOverlayShow(bool isCreated)1188 void WebSelectOverlay::OnAfterSelectOverlayShow(bool isCreated)
1189 {
1190     if (needResetHandleReverse_) {
1191         OnHandleReverse(true);
1192         needResetHandleReverse_ = false;
1193     }
1194 }
1195 
UpdateSelectMenuOptions()1196 void WebSelectOverlay::UpdateSelectMenuOptions()
1197 {
1198     auto value = GetSelectedText();
1199     auto queryWord = std::regex_replace(value, std::regex("^\\s+|\\s+$"), "");
1200     if (isSelectAll_) {
1201         isSelectAll_ = false;
1202     }
1203     if (!queryWord.empty()) {
1204         webSelectInfo_.menuInfo.showSearch = true;
1205         webSelectInfo_.menuInfo.showTranslate = true;
1206     } else {
1207         webSelectInfo_.menuInfo.showSearch = false;
1208         webSelectInfo_.menuInfo.showTranslate = false;
1209     }
1210     TAG_LOGI(AceLogTag::ACE_WEB, "WebSelectInfo MenuInfo ShowSearch is %{public}d", webSelectInfo_.menuInfo.showSearch);
1211     TAG_LOGI(AceLogTag::ACE_WEB, "WebSelectInfo MenuInfo ShowTranslate is %{public}d",
1212         webSelectInfo_.menuInfo.showTranslate);
1213     auto manager = GetManager<SelectContentOverlayManager>();
1214     CHECK_NULL_VOID(manager);
1215     manager->MarkInfoChange(DIRTY_ALL_MENU_ITEM);
1216 }
1217 
DetectSelectedText(const std::string & text)1218 void WebSelectOverlay::DetectSelectedText(const std::string& text)
1219 {
1220     if (!canShowAIMenu_) {
1221         return;
1222     }
1223     auto pattern = GetPattern<WebPattern>();
1224     CHECK_NULL_VOID(pattern);
1225     auto adapter = pattern->webDataDetectorAdapter_;
1226     CHECK_NULL_VOID(adapter);
1227     aiMenuType_ = TextDataDetectType::INVALID;
1228     webSelectInfo_.menuInfo.aiMenuOptionType = aiMenuType_;
1229     adapter->DetectSelectedText(text);
1230 }
1231 
UpdateAISelectMenu(TextDataDetectType type,const std::string & content)1232 void WebSelectOverlay::UpdateAISelectMenu(TextDataDetectType type, const std::string& content)
1233 {
1234     TAG_LOGI(
1235         AceLogTag::ACE_WEB, "WebDataDetectorAdapter::UpdateAISelectMenu type: %{public}d", static_cast<int32_t>(type));
1236     aiMenuType_ = type;
1237     aiMenucontent_ = content;
1238     auto manager = GetManager<SelectContentOverlayManager>();
1239     CHECK_NULL_VOID(manager);
1240     webSelectInfo_.menuInfo.aiMenuOptionType = aiMenuType_;
1241     webSelectInfo_.menuInfo.isAskCeliaEnabled = canShowAIMenu_ && (aiMenuType_ == TextDataDetectType::INVALID);
1242     manager->MarkInfoChange(DIRTY_ALL_MENU_ITEM);
1243 }
1244 
UpdateIsSelectAll()1245 void WebSelectOverlay::UpdateIsSelectAll()
1246 {
1247     if (isSelectAll_) {
1248         isSelectAll_ = false;
1249     }
1250 }
1251 
UpdateSingleHandleVisible(bool isVisible)1252 void WebSelectOverlay::UpdateSingleHandleVisible(bool isVisible)
1253 {
1254     auto pattern = GetPattern<WebPattern>();
1255     CHECK_NULL_VOID(pattern);
1256     if (IsSingleHandle()) {
1257         pattern->UpdateSingleHandleVisible(isVisible);
1258     }
1259 }
1260 
IsSingleHandle()1261 bool WebSelectOverlay::IsSingleHandle()
1262 {
1263     WebOverlayType overlayType = GetTouchHandleOverlayType(insertHandle_, startSelectionHandle_, endSelectionHandle_);
1264     return overlayType == INSERT_OVERLAY;
1265 }
1266 
OnHandleIsHidden()1267 void WebSelectOverlay::OnHandleIsHidden()
1268 {
1269     auto pattern = GetPattern<WebPattern>();
1270     CHECK_NULL_VOID(pattern);
1271     pattern->UpdateSingleHandleVisible(false);
1272     SetTouchHandleExistState(false);
1273 }
1274 
SetTouchHandleExistState(bool touchHandleExist)1275 void WebSelectOverlay::SetTouchHandleExistState(bool touchHandleExist)
1276 {
1277     auto pattern = GetPattern<WebPattern>();
1278     CHECK_NULL_VOID(pattern);
1279     pattern->SetTouchHandleExistState(touchHandleExist);
1280 }
1281 
GetBottomWithKeyboard(double bottom)1282 double WebSelectOverlay::GetBottomWithKeyboard(double bottom)
1283 {
1284     auto pattern = GetPattern<WebPattern>();
1285     CHECK_NULL_RETURN(pattern, bottom);
1286     auto host = pattern->GetHost();
1287     CHECK_NULL_RETURN(host, bottom);
1288     auto pipeline = host->GetContext();
1289     CHECK_NULL_RETURN(pipeline, bottom);
1290     auto safeAreaManager = pipeline->GetSafeAreaManager();
1291     CHECK_NULL_RETURN(safeAreaManager, bottom);
1292     auto keyboardInset = safeAreaManager->GetKeyboardWebInset();
1293     auto keyboardPosition =
1294         GreatNotEqual(static_cast<double>(keyboardInset.Length()), 0.0f) ? keyboardInset.start : bottom;
1295     return GreatNotEqual(keyboardPosition, bottom) ? bottom : keyboardPosition;
1296 }
1297 
SetComputeMenuOffset(SelectOverlayInfo & info)1298 void WebSelectOverlay::SetComputeMenuOffset(SelectOverlayInfo &info)
1299 {
1300     info.computeMenuOffset = [weak = AceType::WeakClaim(this)](LayoutWrapper *layoutWrapper,
1301                                  OffsetF &menuOffset,
1302                                  const RectF &menuRect,
1303                                  OffsetF &windowOffset,
1304                                  std::shared_ptr<SelectOverlayInfo> &info) {
1305         auto overlay = weak.Upgrade();
1306         CHECK_NULL_RETURN(overlay, false);
1307         return overlay->ComputeMenuOffset(layoutWrapper, menuOffset, menuRect, windowOffset, info);
1308     };
1309 }
1310 
ComputeMenuOffset(LayoutWrapper * layoutWrapper,OffsetF & menuOffset,const RectF & menuRect,OffsetF & windowOffset,std::shared_ptr<SelectOverlayInfo> & info)1311 bool WebSelectOverlay::ComputeMenuOffset(LayoutWrapper *layoutWrapper, OffsetF &menuOffset, const RectF &menuRect,
1312     OffsetF &windowOffset, std::shared_ptr<SelectOverlayInfo> &info)
1313 {
1314     CHECK_NULL_RETURN(info, false);
1315     CHECK_NULL_RETURN(layoutWrapper, false);
1316     if (info->isSingleHandle || info->isNewAvoid) {
1317         return false;
1318     }
1319     MenuAvoidStrategyMember member;
1320     member.layoutWrapper = layoutWrapper;
1321     member.windowOffset = windowOffset;
1322     member.menuHeight = menuRect.Height();
1323     member.menuWidth = menuRect.Width();
1324     member.info = info;
1325     bool initSuccess = InitMenuAvoidStrategyMember(member);
1326     if (initSuccess) {
1327         MenuAvoidStrategy(menuOffset, member);
1328         return true;
1329     } else {
1330         return false;
1331     }
1332 }
1333 
InitMenuAvoidStrategyMember(MenuAvoidStrategyMember & member)1334 bool WebSelectOverlay::InitMenuAvoidStrategyMember(MenuAvoidStrategyMember& member)
1335 {
1336     InitStrategyTools tools;
1337     tools.pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
1338     CHECK_NULL_RETURN(tools.pipeline, false);
1339     tools.theme = tools.pipeline->GetTheme<TextOverlayTheme>();
1340     CHECK_NULL_RETURN(tools.theme, false);
1341     tools.safeAreaManager = tools.pipeline->GetSafeAreaManager();
1342     CHECK_NULL_RETURN(tools.safeAreaManager, false);
1343     tools.geometryNode = member.layoutWrapper->GetGeometryNode();
1344     CHECK_NULL_RETURN(tools.geometryNode, false);
1345 
1346     InitMenuAvoidStrategyAboutParam(member, tools);
1347     InitMenuAvoidStrategyAboutKeyboard(member, tools);
1348     InitMenuAvoidStrategyAboutTop(member, tools);
1349     InitMenuAvoidStrategyAboutBottom(member, tools);
1350     InitMenuAvoidStrategyAboutPosition(member, tools);
1351 
1352     return true;
1353 }
1354 
InitMenuAvoidStrategyAboutParam(MenuAvoidStrategyMember & member,InitStrategyTools & tools)1355 void WebSelectOverlay::InitMenuAvoidStrategyAboutParam(MenuAvoidStrategyMember& member, InitStrategyTools& tools)
1356 {
1357     auto& theme = tools.theme;
1358 
1359     member.defaultAvoidY = theme->GetDefaultMenuPositionY();
1360     member.avoidFromText = theme->GetMenuSpacingWithText().ConvertToPx() +
1361                                 theme->GetHandleDiameter().ConvertToPx() +
1362                                 theme->GetHandleDiameterStrokeWidth().ConvertToPx() / 2.0f;
1363 }
1364 
InitMenuAvoidStrategyAboutKeyboard(MenuAvoidStrategyMember & member,InitStrategyTools & tools)1365 void WebSelectOverlay::InitMenuAvoidStrategyAboutKeyboard(MenuAvoidStrategyMember& member, InitStrategyTools& tools)
1366 {
1367     auto& safeAreaManager = tools.safeAreaManager;
1368     auto keyboardInset = safeAreaManager->GetKeyboardInset().Combine(safeAreaManager->GetKeyboardWebInset());
1369 
1370     member.keyboardInsetStart = static_cast<double>(keyboardInset.start);
1371     member.keyboardHeight = static_cast<double>(keyboardInset.Length());
1372     member.hasKeyboard = GreatNotEqual(keyboardInset.Length(), 0.0f);
1373 }
1374 
InitMenuAvoidStrategyAboutTop(MenuAvoidStrategyMember & member,InitStrategyTools & tools)1375 void WebSelectOverlay::InitMenuAvoidStrategyAboutTop(MenuAvoidStrategyMember& member, InitStrategyTools& tools)
1376 {
1377     auto& info = member.info;
1378     SelectHandleInfo upHandle = info->handleReverse ? info->secondHandle : info->firstHandle;
1379     auto topArea = static_cast<double>(tools.safeAreaManager->GetSystemSafeArea().top_.Length());
1380     auto rootTop = static_cast<double>(tools.pipeline->GetRootRect().Top());
1381 
1382     member.upPaint = upHandle.GetPaintRect() - tools.geometryNode->GetFrameOffset() + member.windowOffset;
1383     member.topArea = GreatNotEqual(rootTop, topArea) ? rootTop : topArea;
1384     member.selectionTop = upHandle.isShow ? member.upPaint.Top() : member.topArea;
1385 }
1386 
InitMenuAvoidStrategyAboutBottom(MenuAvoidStrategyMember & member,InitStrategyTools & tools)1387 void WebSelectOverlay::InitMenuAvoidStrategyAboutBottom(MenuAvoidStrategyMember& member, InitStrategyTools& tools)
1388 {
1389     auto info = member.info;
1390     SelectHandleInfo downHandle = info->handleReverse ? info->firstHandle : info->secondHandle;
1391     auto downPaint = downHandle.GetPaintRect() - tools.geometryNode->GetFrameOffset() + member.windowOffset;
1392     auto handleBottom = static_cast<double>(downPaint.Bottom());
1393     bool hasKeyboard = member.hasKeyboard;
1394     auto frameHeight = tools.geometryNode->GetFrameRect().Height();
1395     auto keyboardStart = member.keyboardInsetStart;
1396     auto defaultY = member.defaultAvoidY;
1397 
1398     auto bottomArea = tools.safeAreaManager->GetSafeAreaWithoutProcess().bottom_.start;
1399     bottomArea = hasKeyboard ? keyboardStart - defaultY : bottomArea;
1400     bottomArea = GreatNotEqual(bottomArea, 0.0f) ? bottomArea : tools.pipeline->GetRootRect().Bottom();
1401     bottomArea = GreatNotEqual(bottomArea, frameHeight) ? frameHeight : bottomArea;
1402 
1403     auto handleIsShow = hasKeyboard ? (LessOrEqual(handleBottom, keyboardStart) ? true : false) : downHandle.isShow;
1404     auto selectionBottom = handleIsShow ? handleBottom : bottomArea;
1405     selectionBottom = NearEqual(selectionBottom, keyboardStart - defaultY) ? keyboardStart : selectionBottom;
1406 
1407     member.downPaint = downPaint;
1408     member.bottomArea = bottomArea;
1409     member.selectionBottom = selectionBottom;
1410 }
1411 
InitMenuAvoidStrategyAboutPosition(MenuAvoidStrategyMember & member,InitStrategyTools & tools)1412 void WebSelectOverlay::InitMenuAvoidStrategyAboutPosition(MenuAvoidStrategyMember& member, InitStrategyTools& tools)
1413 {
1414     auto selectArea = member.info->selectArea + member.windowOffset;
1415     auto defaultAvoidY = member.defaultAvoidY;
1416     auto midPosition = (member.selectionTop + member.selectionBottom - member.menuHeight) / 2.0f;
1417     auto avoidPositionY = member.bottomArea - member.menuHeight;
1418     avoidPositionY = GreatNotEqual(midPosition, avoidPositionY) ? avoidPositionY : midPosition;
1419 
1420     member.avoidPositionX = (selectArea.Left() + selectArea.Right() - member.menuWidth) / 2.0f;
1421     member.avoidPositionY = GreatNotEqual(avoidPositionY, defaultAvoidY) ? avoidPositionY : defaultAvoidY;
1422 }
1423 
MenuAvoidStrategy(OffsetF & menuOffset,MenuAvoidStrategyMember & member)1424 void WebSelectOverlay::MenuAvoidStrategy(OffsetF& menuOffset, MenuAvoidStrategyMember& member)
1425 {
1426     if (GreatNotEqual(menuOffset.GetY(), member.upPaint.Top())) {
1427         menuOffset.SetY(member.downPaint.Bottom() + member.avoidFromText);
1428     }
1429     double menuHeight = member.menuHeight;
1430     double menuTop = menuOffset.GetY();
1431     double menuBottom = menuTop + menuHeight;
1432     if (GreatNotEqual(menuBottom, member.bottomArea)) {
1433         menuOffset.SetY(member.avoidPositionY);
1434         menuTop = menuOffset.GetY();
1435         menuBottom = menuTop + menuHeight;
1436     }
1437     if (GreatNotEqual(member.upPaint.Top(), menuTop)) {
1438         double finalY = member.upPaint.Top() - member.avoidFromText - menuHeight;
1439         finalY = GreatNotEqual(menuTop, finalY) ? finalY : menuTop;
1440         menuOffset.SetY(finalY);
1441     } else if (GreatNotEqual(menuBottom, member.downPaint.Bottom())) {
1442         double finalY = member.downPaint.Bottom() + member.avoidFromText;
1443         finalY = GreatNotEqual(finalY, menuTop) ? finalY : menuTop;
1444         menuOffset.SetY(finalY);
1445     } else {
1446         menuOffset.SetY(member.avoidPositionY);
1447     }
1448     menuOffset.SetX(member.avoidPositionX);
1449 }
1450 } // namespace OHOS::Ace::NG
1451