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