1 /*
2 * Copyright (c) 2024 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/text/base_text_select_overlay.h"
17
18 #include "base/utils/system_properties.h"
19 #include "core/common/ace_engine.h"
20 #include "core/common/ai/text_translation_adapter.h"
21 #include "core/common/share/text_share_adapter.h"
22 #include "core/components/select/select_theme.h"
23 #include "core/components/text_overlay/text_overlay_theme.h"
24 #include "core/components_ng/pattern/scrollable/nestable_scroll_container.h"
25 #include "core/components_ng/pattern/scrollable/scrollable_paint_property.h"
26 #include "core/components_ng/pattern/text_drag/text_drag_base.h"
27 #include "core/components_ng/pattern/text_field/text_field_manager.h"
28
29 namespace OHOS::Ace::NG {
30 namespace {
31 constexpr int32_t NO_NEED_RESTART_SINGLE_HANDLE = 100;
32 constexpr FrameNodeChangeInfoFlag AVOID_KEYBOARD_END_FALG = 1 << 8;
33 const char *SYSTEM_CAPABILITY_OF_SHARE = "SystemCapability.Collaboration.SystemShare";
34 } // namespace
ProcessOverlay(const OverlayRequest & request)35 void BaseTextSelectOverlay::ProcessOverlay(const OverlayRequest& request)
36 {
37 if (!IsEnableSelectionMenu()) {
38 TAG_LOGI(AceLogTag::ACE_TEXT, "The selectoverlay is not displayed cause enableSelectionMenu is false");
39 return;
40 }
41 UpdateTransformFlag();
42 if (!PreProcessOverlay(request) || AnimationUtils::IsImplicitAnimationOpen()) {
43 return;
44 }
45 isSuperFoldDisplayDevice_ = SystemProperties::IsSuperFoldDisplayDevice();
46 auto checkClipboard = [weak = WeakClaim(this), request](bool hasData) {
47 TAG_LOGI(AceLogTag::ACE_TEXT, "HasData callback from clipboard, data available ? %{public}d", hasData);
48 auto overlay = weak.Upgrade();
49 CHECK_NULL_VOID(overlay);
50 overlay->ShowSelectOverlay(request, hasData);
51 };
52 auto textBase = hostTextBase_.Upgrade();
53 CHECK_NULL_VOID(textBase);
54 auto clipboard = textBase->GetClipboard();
55 if (clipboard) {
56 auto mimeTypes = GetPasteMimeTypes();
57 if (!mimeTypes.empty()) {
58 clipboard->HasDataType(checkClipboard, mimeTypes);
59 return;
60 }
61 clipboard->HasData(checkClipboard);
62 } else {
63 checkClipboard(false);
64 }
65 }
66
ShowSelectOverlay(const OverlayRequest & request,bool hasClipboardData)67 void BaseTextSelectOverlay::ShowSelectOverlay(const OverlayRequest& request, bool hasClipboardData)
68 {
69 SetShowPaste(hasClipboardData);
70 SetMenuIsShow(request.menuIsShow);
71 SetIsShowHandleLine(!request.hideHandleLine);
72 latestReqeust_ = request;
73 if (!SelectOverlayIsOn() && enableHandleLevel_) {
74 auto firstLocalRect = GetHandleLocalPaintRect(DragHandleIndex::FIRST);
75 auto secondLocalRect = GetHandleLocalPaintRect(DragHandleIndex::SECOND);
76 CalcHandleLevelMode(firstLocalRect, secondLocalRect);
77 }
78 if (enableHandleLevel_) {
79 auto host = GetOwner();
80 CHECK_NULL_VOID(host);
81 host->RegisterNodeChangeListener();
82 RegisterScrollingListener(nullptr);
83 CheckAndUpdateHostGlobalPaintRect();
84 }
85 auto manager = SelectContentOverlayManager::GetOverlayManager(Claim(this));
86 CHECK_NULL_VOID(manager);
87 manager->Show(request.animation, request.requestCode);
88 }
89
ProcessOverlayOnAreaChanged(const OverlayRequest & request)90 void BaseTextSelectOverlay::ProcessOverlayOnAreaChanged(const OverlayRequest& request)
91 {
92 auto overlayRequest = request;
93 overlayRequest.requestCode = NO_NEED_RESTART_SINGLE_HANDLE;
94 ProcessOverlay(overlayRequest);
95 }
96
CheckRestartHiddenHandleTask(int32_t requestCode)97 bool BaseTextSelectOverlay::CheckRestartHiddenHandleTask(int32_t requestCode)
98 {
99 return requestCode != NO_NEED_RESTART_SINGLE_HANDLE;
100 }
101
IsShowMouseMenu()102 bool BaseTextSelectOverlay::IsShowMouseMenu()
103 {
104 auto overlayManager = GetManager<SelectContentOverlayManager>();
105 CHECK_NULL_RETURN(overlayManager, false);
106 return overlayManager->GetShowMenuType() == OptionMenuType::MOUSE_MENU;
107 }
108
IsCurrentMenuVisibile()109 bool BaseTextSelectOverlay::IsCurrentMenuVisibile()
110 {
111 auto overlayManager = GetManager<SelectContentOverlayManager>();
112 CHECK_NULL_RETURN(overlayManager, false);
113 return overlayManager->IsMenuShow();
114 }
115
IsHandleReverse()116 bool BaseTextSelectOverlay::IsHandleReverse()
117 {
118 auto overlayManager = GetManager<SelectContentOverlayManager>();
119 CHECK_NULL_RETURN(overlayManager, false);
120 return overlayManager->IsHandleReverse();
121 }
122
SelectOverlayIsOn()123 bool BaseTextSelectOverlay::SelectOverlayIsOn()
124 {
125 auto manager = GetManager<SelectContentOverlayManager>();
126 CHECK_NULL_RETURN(manager, false);
127 return manager->IsOpen();
128 }
129
SelectOverlayIsCreating()130 bool BaseTextSelectOverlay::SelectOverlayIsCreating()
131 {
132 auto manager = GetManager<SelectContentOverlayManager>();
133 CHECK_NULL_RETURN(manager, false);
134 return manager->IsCreating();
135 }
136
CloseOverlay(bool animation,CloseReason reason)137 void BaseTextSelectOverlay::CloseOverlay(bool animation, CloseReason reason)
138 {
139 auto overlayManager = GetManager<SelectContentOverlayManager>();
140 CHECK_NULL_VOID(overlayManager);
141 overlayManager->Close(GetOwnerId(), false, reason);
142 AfterCloseOverlay();
143 }
144
ToggleMenu()145 void BaseTextSelectOverlay::ToggleMenu()
146 {
147 auto manager = GetManager<SelectContentOverlayManager>();
148 CHECK_NULL_VOID(manager);
149 manager->ToggleOptionMenu();
150 UpdateOriginalMenuIsShow();
151 }
152
ShowMenu()153 void BaseTextSelectOverlay::ShowMenu()
154 {
155 auto manager = GetManager<SelectContentOverlayManager>();
156 CHECK_NULL_VOID(manager);
157 manager->ShowOptionMenu();
158 UpdateOriginalMenuIsShow();
159 }
160
HideMenu(bool noAnimation)161 void BaseTextSelectOverlay::HideMenu(bool noAnimation)
162 {
163 auto manager = GetManager<SelectContentOverlayManager>();
164 CHECK_NULL_VOID(manager);
165 manager->HideOptionMenu(noAnimation);
166 UpdateOriginalMenuIsShow();
167 }
168
DisableMenu()169 void BaseTextSelectOverlay::DisableMenu()
170 {
171 auto manager = GetManager<SelectContentOverlayManager>();
172 CHECK_NULL_VOID(manager);
173 manager->DisableMenu();
174 }
175
EnableMenu()176 void BaseTextSelectOverlay::EnableMenu()
177 {
178 auto manager = GetManager<SelectContentOverlayManager>();
179 CHECK_NULL_VOID(manager);
180 manager->EnableMenu();
181 }
182
UpdateAllHandlesOffset()183 void BaseTextSelectOverlay::UpdateAllHandlesOffset()
184 {
185 auto manager = GetManager<SelectContentOverlayManager>();
186 CHECK_NULL_VOID(manager);
187 manager->MarkInfoChange(DIRTY_DOUBLE_HANDLE | DIRTY_SELECT_AREA);
188 }
189
UpdateFirstHandleOffset()190 void BaseTextSelectOverlay::UpdateFirstHandleOffset()
191 {
192 auto manager = GetManager<SelectContentOverlayManager>();
193 CHECK_NULL_VOID(manager);
194 manager->MarkInfoChange(DIRTY_FIRST_HANDLE);
195 }
196
UpdateSecondHandleOffset()197 void BaseTextSelectOverlay::UpdateSecondHandleOffset()
198 {
199 auto manager = GetManager<SelectContentOverlayManager>();
200 CHECK_NULL_VOID(manager);
201 manager->MarkInfoChange(DIRTY_SECOND_HANDLE);
202 }
203
UpdateViewPort()204 void BaseTextSelectOverlay::UpdateViewPort()
205 {
206 auto manager = GetManager<SelectContentOverlayManager>();
207 CHECK_NULL_VOID(manager);
208 manager->MarkInfoChange(DIRTY_VIEWPORT);
209 }
210
GetOwner()211 RefPtr<FrameNode> BaseTextSelectOverlay::GetOwner()
212 {
213 auto pattern = GetPattern<Pattern>();
214 CHECK_NULL_RETURN(pattern, nullptr);
215 return pattern->GetHost();
216 }
217
OnHandleGlobalTouchEvent(SourceType sourceType,TouchType touchType,bool touchInside)218 void BaseTextSelectOverlay::OnHandleGlobalTouchEvent(SourceType sourceType, TouchType touchType, bool touchInside)
219 {
220 if (IsMouseClickDown(sourceType, touchType)) {
221 CloseOverlay(false, CloseReason::CLOSE_REASON_CLICK_OUTSIDE);
222 } else if (IsTouchUp(sourceType, touchType)) {
223 HideMenu(true);
224 }
225 }
226
CheckTouchInHostNode(const PointF & touchPoint)227 bool BaseTextSelectOverlay::CheckTouchInHostNode(const PointF& touchPoint)
228 {
229 auto host = GetOwner();
230 CHECK_NULL_RETURN(host, false);
231 auto geo = host->GetGeometryNode();
232 CHECK_NULL_RETURN(geo, false);
233 auto rect = RectF(OffsetF(0.0f, 0.0f), geo->GetFrameSize());
234 return rect.IsInRegion(touchPoint);
235 }
236
OnUpdateSelectOverlayInfo(SelectOverlayInfo & overlayInfo,int32_t requestCode)237 void BaseTextSelectOverlay::OnUpdateSelectOverlayInfo(SelectOverlayInfo& overlayInfo, int32_t requestCode)
238 {
239 overlayInfo.isSingleHandle = isSingleHandle_;
240 overlayInfo.isHandleLineShow = isShowHandleLine_;
241 overlayInfo.recreateOverlay = isUsingMouse_;
242 overlayInfo.rightClickOffset = mouseMenuOffset_;
243 overlayInfo.isUsingMouse = isUsingMouse_;
244 overlayInfo.isNewAvoid = true;
245 overlayInfo.hitTestMode = HitTestMode::HTMDEFAULT;
246 if (hasTransform_) {
247 overlayInfo.callerNodeInfo = {
248 .paintFrameRect = GetPaintRectWithTransform(),
249 .paintOffset = GetPaintRectOffsetWithTransform()
250 };
251 }
252 overlayInfo.ancestorViewPort = GetAncestorNodeViewPort();
253 overlayInfo.enableHandleLevel = enableHandleLevel_;
254 overlayInfo.handleLevelMode = handleLevelMode_;
255 if (enableHandleLevel_) {
256 overlayInfo.scale = GetHostScale();
257 }
258 overlayInfo.afterOnClick = [weak = WeakClaim(this)](const GestureEvent&, bool isFirst) {
259 auto overlay = weak.Upgrade();
260 CHECK_NULL_VOID(overlay);
261 overlay->UpdateOriginalMenuIsShow();
262 };
263 overlayInfo.enableSubWindowMenu = enableSubWindowMenu_;
264 }
265
GetVisibleRect(const RefPtr<FrameNode> & node,const RectF & visibleRect)266 RectF BaseTextSelectOverlay::GetVisibleRect(const RefPtr<FrameNode>& node, const RectF& visibleRect)
267 {
268 CHECK_NULL_RETURN(node, visibleRect);
269 auto parentNode = node->GetAncestorNodeOfFrame(true);
270 CHECK_NULL_RETURN(parentNode, visibleRect);
271 if (parentNode->GetTag() == V2::PAGE_ETS_TAG) {
272 return visibleRect;
273 }
274 auto intersectRect = visibleRect;
275 auto scrollablePattern = AceType::DynamicCast<NestableScrollContainer>(parentNode->GetPattern());
276 auto geometryNode = parentNode->GetGeometryNode();
277 if (scrollablePattern && geometryNode) {
278 RectF parentViewPort;
279 if (!GetFrameNodeContentRect(parentNode, parentViewPort)) {
280 return RectF(0, 0, 0, 0);
281 }
282 parentViewPort += parentNode->GetTransformRelativeOffset();
283 if (parentViewPort.IsIntersectWith(visibleRect)) {
284 intersectRect = parentViewPort.IntersectRectT(visibleRect);
285 } else {
286 return RectF(0, 0, 0, 0);
287 }
288 }
289 return GetVisibleRect(parentNode, intersectRect);
290 }
291
RemoveSelectionHoldCallback()292 void BaseTextSelectOverlay::RemoveSelectionHoldCallback()
293 {
294 auto overlayManager = SelectContentOverlayManager::GetOverlayManager();
295 CHECK_NULL_VOID(overlayManager);
296 overlayManager->RemoveHoldSelectionCallback(GetOwnerId());
297 }
298
SetSelectionHoldCallback()299 void BaseTextSelectOverlay::SetSelectionHoldCallback()
300 {
301 auto overlayManager = SelectContentOverlayManager::GetOverlayManager();
302 CHECK_NULL_VOID(overlayManager);
303 HoldSelectionInfo selectionInfo;
304 selectionInfo.resetSelectionCallback = [weak = WeakClaim(this)]() {
305 auto overlay = weak.Upgrade();
306 CHECK_NULL_VOID(overlay);
307 overlay->OnResetTextSelection();
308 };
309 selectionInfo.checkTouchInArea = [weak = WeakClaim(this), manager = WeakClaim(AceType::RawPtr(overlayManager))](
310 const PointF& point, bool passThrough) {
311 auto baseOverlay = weak.Upgrade();
312 CHECK_NULL_RETURN(baseOverlay, false);
313 auto overlayManager = manager.Upgrade();
314 CHECK_NULL_RETURN(overlayManager, false);
315 auto host = baseOverlay->GetOwner();
316 CHECK_NULL_RETURN(host, false);
317 auto localPoint = point;
318 overlayManager->ConvertPointRelativeToNode(host, localPoint, passThrough);
319 return baseOverlay->CheckTouchInHostNode(localPoint);
320 };
321 selectionInfo.eventFilter = [weak = WeakClaim(this)](SourceType sourceType, TouchType touchType) {
322 auto overlay = weak.Upgrade();
323 CHECK_NULL_RETURN(overlay, false);
324 return overlay->IsAcceptResetSelectionEvent(sourceType, touchType);
325 };
326 overlayManager->SetHoldSelectionCallback(GetOwnerId(), selectionInfo);
327 }
328
GetVisibleContentRect(bool isGlobal)329 RectF BaseTextSelectOverlay::GetVisibleContentRect(bool isGlobal)
330 {
331 RectF visibleContentRect;
332 auto pattern = GetPattern<Pattern>();
333 CHECK_NULL_RETURN(pattern, visibleContentRect);
334 auto host = pattern->GetHost();
335 CHECK_NULL_RETURN(host, visibleContentRect);
336 auto context = host->GetContext();
337 CHECK_NULL_RETURN(context, visibleContentRect);
338 auto geometryNode = host->GetGeometryNode();
339 CHECK_NULL_RETURN(geometryNode, visibleContentRect);
340 auto paintOffset = host->GetTransformRelativeOffset();
341 visibleContentRect = RectF(geometryNode->GetContentOffset() + paintOffset, geometryNode->GetContentSize());
342 if (enableHandleLevel_ && handleLevelMode_ == HandleLevelMode::EMBED && !isGlobal) {
343 return visibleContentRect;
344 }
345 return GetVisibleRect(pattern->GetHost(), visibleContentRect);
346 }
347
MergeSelectedBoxes(const std::vector<RectF> & boxes,const RectF & contentRect,const RectF & textRect,const OffsetF & paintOffset)348 RectF BaseTextSelectOverlay::MergeSelectedBoxes(
349 const std::vector<RectF>& boxes, const RectF& contentRect, const RectF& textRect, const OffsetF& paintOffset)
350 {
351 if (boxes.empty()) {
352 return RectF();
353 }
354 auto frontRect = boxes.front();
355 auto backRect = boxes.back();
356 float selectAreaRight = frontRect.Right();
357 float selectAreaLeft = frontRect.Left();
358 if (boxes.size() != 1) {
359 std::unordered_map<float, RectF> selectLineRect;
360 for (const auto& box : boxes) {
361 auto combineLineRect = box;
362 auto top = box.Top();
363 if (selectLineRect.find(top) == selectLineRect.end()) {
364 selectLineRect.insert({ top, combineLineRect });
365 } else {
366 combineLineRect = combineLineRect.CombineRectT(selectLineRect[top]);
367 selectLineRect.insert({ top, combineLineRect });
368 }
369 selectAreaRight = std::max(selectAreaRight, combineLineRect.Right());
370 selectAreaLeft = std::min(selectAreaLeft, combineLineRect.Left());
371 }
372 }
373 return { selectAreaLeft + textRect.GetX() + paintOffset.GetX(),
374 frontRect.GetY() + textRect.GetY() + paintOffset.GetY(), selectAreaRight - selectAreaLeft,
375 backRect.Bottom() - frontRect.Top() };
376 }
377
SetTransformPaintInfo(SelectHandleInfo & handleInfo,const RectF & localHandleRect)378 void BaseTextSelectOverlay::SetTransformPaintInfo(SelectHandleInfo& handleInfo, const RectF& localHandleRect)
379 {
380 CHECK_NULL_VOID(hasTransform_);
381 SelectHandlePaintInfo paintInfo;
382 auto left = localHandleRect.Left() + localHandleRect.Width() / 2.0f;
383 std::vector<OffsetF> points = { OffsetF(left, localHandleRect.Top()), OffsetF(left, localHandleRect.Bottom()) };
384 GetGlobalPointsWithTransform(points);
385 paintInfo.startPoint = points[0];
386 paintInfo.endPoint = points[1];
387 paintInfo.width = localHandleRect.Width();
388 handleInfo.paintInfo = paintInfo;
389 handleInfo.paintInfoConverter = [weak = WeakClaim(this)](const SelectHandlePaintInfo& paintInfo) {
390 auto overlay = weak.Upgrade();
391 CHECK_NULL_RETURN(overlay, RectF());
392 return overlay->ConvertPaintInfoToRect(paintInfo);
393 };
394 handleInfo.isPaintHandleWithPoints = true;
395 handleInfo.isShow =
396 CheckHandleIsVisibleWithTransform(paintInfo.startPoint, paintInfo.endPoint, localHandleRect.Width());
397 }
398
CheckHandleIsVisibleWithTransform(const OffsetF & startPoint,const OffsetF & endPoint,float epsilon)399 bool BaseTextSelectOverlay::CheckHandleIsVisibleWithTransform(
400 const OffsetF& startPoint, const OffsetF& endPoint, float epsilon)
401 {
402 auto pattern = GetPattern<Pattern>();
403 CHECK_NULL_RETURN(pattern, true);
404 auto host = pattern->GetHost();
405 CHECK_NULL_RETURN(host, true);
406 auto geometryNode = host->GetGeometryNode();
407 CHECK_NULL_RETURN(geometryNode, true);
408 auto contentRect = geometryNode->GetContentRect();
409 auto rectVertices = GetGlobalRectVertexWithTransform(contentRect, epsilon);
410 auto leftTop = rectVertices[0];
411 auto rightTop = rectVertices[1];
412 auto leftBottom = rectVertices[2];
413 auto rightBottom = rectVertices[3];
414 auto isStartPointInRect = IsPointInRect(startPoint, leftBottom, rightBottom, rightTop, leftTop);
415 auto isEndPointInRect = IsPointInRect(endPoint, leftBottom, rightBottom, rightTop, leftTop);
416 if (isStartPointInRect && isEndPointInRect) {
417 auto visibleContentRect = GetVisibleContentRectWithTransform(epsilon);
418 leftTop = OffsetF(visibleContentRect.Left(), visibleContentRect.Top());
419 rightTop = OffsetF(visibleContentRect.Right(), visibleContentRect.Top());
420 leftBottom = OffsetF(visibleContentRect.Left(), visibleContentRect.Bottom());
421 rightBottom = OffsetF(visibleContentRect.Right(), visibleContentRect.Bottom());
422 isStartPointInRect = IsPointInRect(startPoint, leftBottom, rightBottom, rightTop, leftTop);
423 isEndPointInRect = IsPointInRect(endPoint, leftBottom, rightBottom, rightTop, leftTop);
424 return isStartPointInRect && isEndPointInRect;
425 }
426 return false;
427 }
428
IsPointInRect(const OffsetF & point,const OffsetF & lb,const OffsetF & rb,const OffsetF & rt,const OffsetF & lt)429 bool BaseTextSelectOverlay::IsPointInRect(
430 const OffsetF& point, const OffsetF& lb, const OffsetF& rb, const OffsetF& rt, const OffsetF& lt)
431 {
432 auto crossProduct = [](const OffsetF& point, const OffsetF& point1, const OffsetF& point2) {
433 auto pointStart = OffsetF(point2.GetX() - point1.GetX(), point2.GetY() - point1.GetY());
434 auto pointEnd = OffsetF(point.GetX() - point1.GetX(), point.GetY() - point1.GetY());
435 return pointStart.GetX() * pointEnd.GetY() - pointEnd.GetX() * pointStart.GetY();
436 };
437 auto bottomProduct = crossProduct(point, lb, rb);
438 auto rightProduct = crossProduct(point, rb, rt);
439 auto topProduct = crossProduct(point, rt, lt);
440 auto leftProduct = crossProduct(point, lt, lb);
441 std::vector<float> productVector = { bottomProduct, rightProduct, topProduct, leftProduct };
442 auto minMax = std::minmax_element(productVector.begin(), productVector.end());
443 // 所用向量叉积方向一致(都为正数或者都为负数),表示点在矩形内. 最小值大于0或者最大值小于0.
444 return Positive(*minMax.first) || Negative(* minMax.second);
445 }
446
GetVisibleContentRectWithTransform(float epsilon)447 RectF BaseTextSelectOverlay::GetVisibleContentRectWithTransform(float epsilon)
448 {
449 RectF visibleContentRect;
450 auto pattern = GetPattern<Pattern>();
451 CHECK_NULL_RETURN(pattern, visibleContentRect);
452 auto host = pattern->GetHost();
453 CHECK_NULL_RETURN(host, visibleContentRect);
454 auto context = host->GetContext();
455 CHECK_NULL_RETURN(context, visibleContentRect);
456 auto geometryNode = host->GetGeometryNode();
457 CHECK_NULL_RETURN(geometryNode, visibleContentRect);
458 visibleContentRect = geometryNode->GetContentRect();
459 auto width = visibleContentRect.Width() + 2 * epsilon;
460 auto height = visibleContentRect.Height() + 2 * epsilon;
461 visibleContentRect.SetLeft(visibleContentRect.Left() - epsilon);
462 visibleContentRect.SetTop(visibleContentRect.Top() - epsilon);
463 visibleContentRect.SetWidth(width);
464 visibleContentRect.SetHeight(height);
465 GetGlobalRectWithTransform(visibleContentRect);
466 return GetVisibleRect(pattern->GetHost(), visibleContentRect);
467 }
468
GetGlobalPointsWithTransform(std::vector<OffsetF> & points)469 void BaseTextSelectOverlay::GetGlobalPointsWithTransform(std::vector<OffsetF>& points)
470 {
471 CHECK_NULL_VOID(hasTransform_);
472 auto pattern = GetPattern<Pattern>();
473 CHECK_NULL_VOID(pattern);
474 auto parent = pattern->GetHost();
475 std::vector<PointF> convertPoints;
476 auto pointConverter = [](const OffsetF& offset) { return PointF(offset.GetX(), offset.GetY()); };
477 std::transform(points.begin(), points.end(), std::back_inserter(convertPoints), pointConverter);
478 while (parent) {
479 if (parent->GetTag() == V2::WINDOW_SCENE_ETS_TAG) {
480 break;
481 }
482 auto renderContext = parent->GetRenderContext();
483 CHECK_NULL_VOID(renderContext);
484 auto paintOffset = renderContext->GetPaintRectWithoutTransform().GetOffset();
485 for (auto& pointElement : convertPoints) {
486 pointElement = pointElement + paintOffset;
487 renderContext->GetPointTransform(pointElement);
488 }
489 parent = parent->GetAncestorNodeOfFrame(true);
490 }
491 points.clear();
492 auto offsetConverter = [](const PointF& point) { return OffsetF(point.GetX(), point.GetY()); };
493 std::transform(convertPoints.begin(), convertPoints.end(), std::back_inserter(points), offsetConverter);
494 }
495
GetGlobalRectWithTransform(RectF & localRect)496 void BaseTextSelectOverlay::GetGlobalRectWithTransform(RectF& localRect)
497 {
498 CHECK_NULL_VOID(hasTransform_);
499 auto rectVertex = GetGlobalRectVertexWithTransform(localRect);
500 auto compareOffsetX = [](const OffsetF& offset1, const OffsetF& offset2) {
501 return LessNotEqual(offset1.GetX(), offset2.GetX());
502 };
503 auto minMaxX = std::minmax_element(rectVertex.begin(), rectVertex.end(), compareOffsetX);
504 auto compareOffsetY = [](const OffsetF& offset1, const OffsetF& offset2) {
505 return LessNotEqual(offset1.GetY(), offset2.GetY());
506 };
507 auto minMaxY = std::minmax_element(rectVertex.begin(), rectVertex.end(), compareOffsetY);
508 localRect.SetOffset(OffsetF(minMaxX.first->GetX(), minMaxY.first->GetY()));
509 localRect.SetSize(
510 SizeF(minMaxX.second->GetX() - minMaxX.first->GetX(), minMaxY.second->GetY() - minMaxY.first->GetY()));
511 }
512
GetGlobalRectVertexWithTransform(const RectF & rect,float extendValue)513 std::vector<OffsetF> BaseTextSelectOverlay::GetGlobalRectVertexWithTransform(const RectF& rect, float extendValue)
514 {
515 std::vector<OffsetF> rectVertices = {
516 OffsetF(rect.Left() - extendValue, rect.Top() - extendValue),
517 OffsetF(rect.Right() + extendValue, rect.Top() - extendValue),
518 OffsetF(rect.Left() - extendValue, rect.Bottom() + extendValue),
519 OffsetF(rect.Right() + extendValue, rect.Bottom() + extendValue)
520 };
521 GetGlobalPointsWithTransform(rectVertices);
522 return rectVertices;
523 }
524
GetLocalPointWithTransform(OffsetF & localPoint)525 void BaseTextSelectOverlay::GetLocalPointWithTransform(OffsetF& localPoint)
526 {
527 CHECK_NULL_VOID(hasTransform_);
528 std::vector<OffsetF> points = { localPoint };
529 GetLocalPointsWithTransform(points);
530 localPoint = points[0];
531 }
532
GetLocalPointsWithTransform(std::vector<OffsetF> & localPoints)533 void BaseTextSelectOverlay::GetLocalPointsWithTransform(std::vector<OffsetF>& localPoints)
534 {
535 CHECK_NULL_VOID(hasTransform_);
536 auto textPaintOffset = GetPaintRectOffsetWithTransform();
537 GetGlobalPointsWithTransform(localPoints);
538 for (auto& pointElement : localPoints) {
539 pointElement = pointElement - textPaintOffset;
540 }
541 }
542
GetPaintRectWithTransform()543 RectF BaseTextSelectOverlay::GetPaintRectWithTransform()
544 {
545 auto pattern = GetPattern<Pattern>();
546 CHECK_NULL_RETURN(pattern, RectF());
547 auto host = pattern->GetHost();
548 CHECK_NULL_RETURN(host, RectF());
549 auto geometryNode = host->GetGeometryNode();
550 CHECK_NULL_RETURN(geometryNode, RectF());
551 auto globalFrameRect = RectF(OffsetF(0.0f, 0.0f), geometryNode->GetFrameSize());
552 GetGlobalRectWithTransform(globalFrameRect);
553 return globalFrameRect;
554 }
555
GetPaintRectOffsetWithTransform()556 OffsetF BaseTextSelectOverlay::GetPaintRectOffsetWithTransform()
557 {
558 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
559 CHECK_NULL_RETURN(pipeline, OffsetF(0.0f, 0.0f));
560 auto globalFrameRect = GetPaintRectWithTransform();
561 return globalFrameRect.GetOffset() - pipeline->GetRootRect().GetOffset();
562 }
563
GetLocalRectWithTransform(RectF & rect)564 void BaseTextSelectOverlay::GetLocalRectWithTransform(RectF& rect)
565 {
566 CHECK_NULL_VOID(hasTransform_);
567 std::vector<OffsetF> localRectVertices = {
568 OffsetF(rect.Left(), rect.Top()),
569 OffsetF(rect.Right(), rect.Top()),
570 OffsetF(rect.Left(), rect.Bottom()),
571 OffsetF(rect.Right(), rect.Bottom())
572 };
573 GetLocalPointsWithTransform(localRectVertices);
574 auto compareOffsetX = [](const OffsetF& offset1, const OffsetF& offset2) {
575 return LessNotEqual(offset1.GetX(), offset2.GetX());
576 };
577 auto minMaxX = std::minmax_element(localRectVertices.begin(), localRectVertices.end(), compareOffsetX);
578 auto compareOffsetY = [](const OffsetF& offset1, const OffsetF& offset2) {
579 return LessNotEqual(offset1.GetY(), offset2.GetY());
580 };
581 auto minMaxY = std::minmax_element(localRectVertices.begin(), localRectVertices.end(), compareOffsetY);
582 rect.SetOffset(OffsetF(minMaxX.first->GetX(), minMaxY.first->GetY()));
583 rect.SetSize(SizeF(minMaxX.second->GetX() - minMaxX.first->GetX(), minMaxY.second->GetY() - minMaxY.first->GetY()));
584 }
585
RevertLocalPointWithTransform(OffsetF & point)586 void BaseTextSelectOverlay::RevertLocalPointWithTransform(OffsetF& point)
587 {
588 CHECK_NULL_VOID(hasTransform_);
589 auto pattern = GetPattern<Pattern>();
590 CHECK_NULL_VOID(pattern);
591 auto parent = pattern->GetHost();
592 CHECK_NULL_VOID(parent);
593 std::stack<RefPtr<FrameNode>> nodeStack;
594 while (parent) {
595 nodeStack.push(parent);
596 parent = parent->GetAncestorNodeOfFrame(true);
597 }
598 CHECK_NULL_VOID(!nodeStack.empty());
599 PointF localPoint(point.GetX(), point.GetY());
600 while (!nodeStack.empty()) {
601 parent = nodeStack.top();
602 CHECK_NULL_VOID(parent);
603 nodeStack.pop();
604 auto renderContext = parent->GetRenderContext();
605 CHECK_NULL_VOID(renderContext);
606 renderContext->GetPointWithRevert(localPoint);
607 auto rectOffset = renderContext->GetPaintRectWithoutTransform().GetOffset();
608 localPoint = localPoint - rectOffset;
609 }
610 point.SetX(localPoint.GetX());
611 point.SetY(localPoint.GetY());
612 }
613
ConvertPaintInfoToRect(const SelectHandlePaintInfo & paintInfo)614 RectF BaseTextSelectOverlay::ConvertPaintInfoToRect(const SelectHandlePaintInfo& paintInfo)
615 {
616 auto topOffset = paintInfo.startPoint;
617 RevertLocalPointWithTransform(topOffset);
618 auto bottomOffset = paintInfo.endPoint;
619 RevertLocalPointWithTransform(bottomOffset);
620 auto offset = topOffset + GetPaintOffsetWithoutTransform();
621 auto size = SizeF(paintInfo.width, bottomOffset.GetY() - topOffset.GetY());
622 return RectF(offset, size);
623 }
624
GetPaintOffsetWithoutTransform()625 OffsetF BaseTextSelectOverlay::GetPaintOffsetWithoutTransform()
626 {
627 auto pattern = GetPattern<Pattern>();
628 CHECK_NULL_RETURN(pattern, OffsetF());
629 OffsetF offset;
630 auto parent = pattern->GetHost();
631 if (!hasTransform_) {
632 return parent->GetTransformRelativeOffset();
633 }
634 while (parent) {
635 auto renderContext = parent->GetRenderContext();
636 CHECK_NULL_RETURN(renderContext, OffsetF());
637 offset += renderContext->GetPaintRectWithoutTransform().GetOffset();
638 parent = parent->GetAncestorNodeOfFrame(true);
639 }
640 return offset;
641 }
642
UpdateTransformFlag()643 void BaseTextSelectOverlay::UpdateTransformFlag()
644 {
645 hasTransform_ = HasUnsupportedTransform(true);
646 }
647
GetAncestorNodeViewPort()648 std::optional<RectF> BaseTextSelectOverlay::GetAncestorNodeViewPort()
649 {
650 if (IsClipHandleWithViewPort()) {
651 RectF viewPort;
652 if (GetClipHandleViewPort(viewPort)) {
653 return viewPort;
654 }
655 }
656 auto pattern = GetPattern<Pattern>();
657 CHECK_NULL_RETURN(pattern, std::nullopt);
658 auto host = pattern->GetHost();
659 CHECK_NULL_RETURN(host, std::nullopt);
660 auto parent = host->GetAncestorNodeOfFrame(true);
661 while (parent) {
662 auto scrollableContainer = parent->GetPattern<NestableScrollContainer>();
663 if (scrollableContainer) {
664 return parent->GetTransformRectRelativeToWindow();
665 }
666 parent = parent->GetAncestorNodeOfFrame(true);
667 }
668 return std::nullopt;
669 }
670
IsAcceptResetSelectionEvent(SourceType sourceType,TouchType touchType)671 bool BaseTextSelectOverlay::IsAcceptResetSelectionEvent(SourceType sourceType, TouchType touchType)
672 {
673 return (sourceType == SourceType::MOUSE || sourceType == SourceType::TOUCH) && touchType == TouchType::DOWN;
674 }
675
GetHandleDiameter()676 float BaseTextSelectOverlay::GetHandleDiameter()
677 {
678 auto overlayManager = SelectContentOverlayManager::GetOverlayManager();
679 CHECK_NULL_RETURN(overlayManager, 0.0f);
680 return overlayManager->GetHandleDiameter();
681 }
682
SwitchToOverlayMode()683 void BaseTextSelectOverlay::SwitchToOverlayMode()
684 {
685 if (HasUnsupportedTransform() || IsHandleInParentSafeAreaPadding()) {
686 return;
687 }
688 auto manager = GetManager<SelectContentOverlayManager>();
689 CHECK_NULL_VOID(manager);
690 handleLevelMode_ = HandleLevelMode::OVERLAY;
691 manager->SwitchToHandleMode(handleLevelMode_);
692 }
693
SwitchToEmbedMode()694 void BaseTextSelectOverlay::SwitchToEmbedMode()
695 {
696 CHECK_NULL_VOID(!isHandleMoving_);
697 auto manager = GetManager<SelectContentOverlayManager>();
698 CHECK_NULL_VOID(manager);
699 handleLevelMode_ = HandleLevelMode::EMBED;
700 manager->SwitchToHandleMode(handleLevelMode_);
701 }
702
GetHostScale()703 VectorF BaseTextSelectOverlay::GetHostScale()
704 {
705 auto pattern = GetPattern<Pattern>();
706 auto unitScale = VectorF(1, 1);
707 CHECK_NULL_RETURN(pattern, unitScale);
708 auto host = pattern->GetHost();
709 CHECK_NULL_RETURN(host, unitScale);
710 auto scaleX = 1.0f;
711 auto scaleY = 1.0f;
712 while (host && host->GetTag() != V2::WINDOW_SCENE_ETS_TAG) {
713 auto renderContext = host->GetRenderContext();
714 CHECK_NULL_RETURN(renderContext, unitScale);
715 auto scale = renderContext->GetTransformScaleValue(unitScale);
716 scaleX *= std::abs(scale.x);
717 scaleY *= std::abs(scale.y);
718 auto transformMatrix = renderContext->GetTransformMatrix();
719 if (transformMatrix.has_value()) {
720 DecomposedTransform transform;
721 TransformUtil::DecomposeTransform(transform, transformMatrix.value());
722 scaleX *= std::abs(transform.scale[0]);
723 scaleY *= std::abs(transform.scale[1]);
724 }
725 host = host->GetAncestorNodeOfFrame(true);
726 }
727 return VectorF(1.0f / scaleX, 1.0f / scaleY);
728 }
729
OnCloseOverlay(OptionMenuType menuType,CloseReason reason,RefPtr<OverlayInfo> info)730 void BaseTextSelectOverlay::OnCloseOverlay(OptionMenuType menuType, CloseReason reason, RefPtr<OverlayInfo> info)
731 {
732 isHandleDragging_ = false;
733 dragHandleIndex_ = DragHandleIndex::NONE;
734 if (reason == CloseReason::CLOSE_REASON_BY_RECREATE) {
735 return;
736 }
737 originalMenuIsShow_ = false;
738 if (enableHandleLevel_) {
739 auto host = GetOwner();
740 CHECK_NULL_VOID(host);
741 host->UnregisterNodeChangeListener();
742 }
743 }
744
SetHandleLevelMode(HandleLevelMode mode)745 void BaseTextSelectOverlay::SetHandleLevelMode(HandleLevelMode mode)
746 {
747 if (handleLevelMode_ == mode) {
748 return;
749 }
750 handleLevelMode_ = mode;
751 }
752
GetHandleLocalPaintRect(DragHandleIndex dragHandleIndex)753 RectF BaseTextSelectOverlay::GetHandleLocalPaintRect(DragHandleIndex dragHandleIndex)
754 {
755 return RectF();
756 }
757
IsPointsInRegion(const std::vector<PointF> & points,const RectF & regionRect)758 bool BaseTextSelectOverlay::IsPointsInRegion(const std::vector<PointF>& points, const RectF& regionRect)
759 {
760 for (const auto& point : points) {
761 if (!regionRect.IsInRegion(point)) {
762 return false;
763 }
764 }
765 return true;
766 }
767
GetHandlePoints(const RectF & handleRect,std::vector<PointF> & points,bool handleOnTop)768 void BaseTextSelectOverlay::GetHandlePoints(const RectF& handleRect, std::vector<PointF>& points, bool handleOnTop)
769 {
770 auto diameter = GetHandleDiameter();
771 auto handlePaintRect = handleRect;
772 auto offsetX = handlePaintRect.Left() + (handlePaintRect.Width() - diameter) / 2.0f;
773 auto offsetY = handleOnTop ? handlePaintRect.Top() - diameter : handlePaintRect.Bottom();
774 handlePaintRect.SetOffset(OffsetF(offsetX, offsetY));
775 handlePaintRect.SetSize(SizeF(diameter, diameter));
776 points.push_back(PointF(handlePaintRect.Left(), handlePaintRect.Top()));
777 points.push_back(PointF(handlePaintRect.Right(), handlePaintRect.Top()));
778 points.push_back(PointF(handlePaintRect.Left(), handlePaintRect.Bottom()));
779 points.push_back(PointF(handlePaintRect.Right(), handlePaintRect.Bottom()));
780 }
781
CheckHandleCanPaintInHost(const RectF & firstRect,const RectF & secondRect)782 bool BaseTextSelectOverlay::CheckHandleCanPaintInHost(const RectF& firstRect, const RectF& secondRect)
783 {
784 if (isChangeToOverlayModeAtEdge_) {
785 return false;
786 }
787 std::vector<PointF> firstPoints;
788 GetHandlePoints(firstRect, firstPoints, false);
789 std::vector<PointF> secondPoints;
790 GetHandlePoints(secondRect, secondPoints, false);
791 auto host = GetOwner();
792 CHECK_NULL_RETURN(host, false);
793 auto parent = host;
794 while (parent) {
795 CHECK_NULL_RETURN(parent->GetGeometryNode(), false);
796 auto parentRect = RectF();
797 parentRect.SetSize(parent->GetGeometryNode()->GetFrameSize());
798 if (IsPointsInRegion(firstPoints, parentRect) && IsPointsInRegion(secondPoints, parentRect)) {
799 return true;
800 }
801 auto renderContext = parent->GetRenderContext();
802 CHECK_NULL_RETURN(renderContext, false);
803 auto isClip = renderContext->GetClipEdge().value_or(false);
804 if (isClip) {
805 break;
806 }
807 auto paintOffset = renderContext->GetPaintRectWithoutTransform().GetOffset();
808 for (auto& point : firstPoints) {
809 point = point + paintOffset;
810 renderContext->GetPointTransform(point);
811 }
812 for (auto& point : secondPoints) {
813 point = point + paintOffset;
814 renderContext->GetPointTransform(point);
815 }
816 parent = parent->GetAncestorNodeOfFrame(true);
817 }
818 return false;
819 }
820
CalcHandleLevelMode(const RectF & firstLocalPaintRect,const RectF & secondLocalPaintRect)821 void BaseTextSelectOverlay::CalcHandleLevelMode(const RectF& firstLocalPaintRect, const RectF& secondLocalPaintRect)
822 {
823 if (CheckHandleCanPaintInHost(firstLocalPaintRect, secondLocalPaintRect) || HasUnsupportedTransform() ||
824 IsHandleInParentSafeAreaPadding(firstLocalPaintRect, secondLocalPaintRect)) {
825 SetHandleLevelMode(HandleLevelMode::EMBED);
826 } else {
827 SetHandleLevelMode(HandleLevelMode::OVERLAY);
828 }
829 }
830
OnAncestorNodeChanged(FrameNodeChangeInfoFlag flag)831 void BaseTextSelectOverlay::OnAncestorNodeChanged(FrameNodeChangeInfoFlag flag)
832 {
833 auto isStartScroll = IsAncestorNodeStartScroll(flag);
834 auto isStartAnimation = IsAncestorNodeStartAnimation(flag);
835 auto isTransformChanged = IsAncestorNodeTransformChange(flag);
836 auto isStartTransition = IsAncestorNodeHasTransition(flag);
837 auto isSwitchToEmbed = isStartScroll || isStartAnimation || isTransformChanged || isStartTransition;
838 // parent size changes but the child does not change.
839 if (IsAncestorNodeGeometryChange(flag)) {
840 isSwitchToEmbed = isSwitchToEmbed || CheckAndUpdateHostGlobalPaintRect();
841 }
842 auto isScrollEnd = IsAncestorNodeEndScroll(flag) || ((flag & AVOID_KEYBOARD_END_FALG) == AVOID_KEYBOARD_END_FALG);
843 isSwitchToEmbed = isSwitchToEmbed && (!isScrollEnd || HasUnsupportedTransform());
844 UpdateMenuWhileAncestorNodeChanged(
845 isStartScroll || isStartAnimation || isTransformChanged || isStartTransition, isScrollEnd, flag);
846 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
847 CHECK_NULL_VOID(pipeline);
848 auto switchTask = [weak = WeakClaim(this), isSwitchToEmbed, isScrollEnd]() {
849 auto overlay = weak.Upgrade();
850 CHECK_NULL_VOID(overlay);
851 if (isScrollEnd) {
852 overlay->SwitchToOverlayMode();
853 return;
854 }
855 if (isSwitchToEmbed) {
856 overlay->SwitchToEmbedMode();
857 }
858 };
859 if (AnimationUtils::IsImplicitAnimationOpen()) {
860 switchTask();
861 } else {
862 pipeline->AddAfterRenderTask(switchTask);
863 }
864 if ((flag & FRAME_NODE_CONTENT_CLIP_CHANGE) == FRAME_NODE_CONTENT_CLIP_CHANGE) {
865 if (IsOverlayMode() && IsHandleInParentSafeAreaPadding()) {
866 SwitchToEmbedMode();
867 }
868 UpdateViewPort();
869 }
870 }
871
UpdateMenuWhileAncestorNodeChanged(bool shouldHideMenu,bool shouldShowMenu,FrameNodeChangeInfoFlag extraFlag)872 void BaseTextSelectOverlay::UpdateMenuWhileAncestorNodeChanged(
873 bool shouldHideMenu, bool shouldShowMenu, FrameNodeChangeInfoFlag extraFlag)
874 {
875 auto manager = GetManager<SelectContentOverlayManager>();
876 CHECK_NULL_VOID(manager);
877 if (shouldHideMenu) {
878 manager->HideOptionMenu(true);
879 return;
880 }
881 if ((extraFlag & AVOID_KEYBOARD_END_FALG) == AVOID_KEYBOARD_END_FALG && !GetIsHandleDragging()) {
882 manager->ShowOptionMenu();
883 return;
884 }
885 if (shouldShowMenu && originalMenuIsShow_ && !GetIsHandleDragging() && !GetSelectArea().IsEmpty()) {
886 manager->ShowOptionMenu();
887 }
888 }
889
IsAncestorNodeStartAnimation(FrameNodeChangeInfoFlag flag)890 bool BaseTextSelectOverlay::IsAncestorNodeStartAnimation(FrameNodeChangeInfoFlag flag)
891 {
892 return ((flag & FRAME_NODE_CHANGE_START_ANIMATION) == FRAME_NODE_CHANGE_START_ANIMATION);
893 }
894
IsAncestorNodeGeometryChange(FrameNodeChangeInfoFlag flag)895 bool BaseTextSelectOverlay::IsAncestorNodeGeometryChange(FrameNodeChangeInfoFlag flag)
896 {
897 return ((flag & FRAME_NODE_CHANGE_GEOMETRY_CHANGE) == FRAME_NODE_CHANGE_GEOMETRY_CHANGE);
898 }
899
IsAncestorNodeStartScroll(FrameNodeChangeInfoFlag flag)900 bool BaseTextSelectOverlay::IsAncestorNodeStartScroll(FrameNodeChangeInfoFlag flag)
901 {
902 return ((flag & FRAME_NODE_CHANGE_START_SCROLL) == FRAME_NODE_CHANGE_START_SCROLL);
903 }
904
IsAncestorNodeEndScroll(FrameNodeChangeInfoFlag flag)905 bool BaseTextSelectOverlay::IsAncestorNodeEndScroll(FrameNodeChangeInfoFlag flag)
906 {
907 return ((flag & FRAME_NODE_CHANGE_END_SCROLL) == FRAME_NODE_CHANGE_END_SCROLL);
908 }
909
IsAncestorNodeTransformChange(FrameNodeChangeInfoFlag flag)910 bool BaseTextSelectOverlay::IsAncestorNodeTransformChange(FrameNodeChangeInfoFlag flag)
911 {
912 return ((flag & FRAME_NODE_CHANGE_TRANSFORM_CHANGE) == FRAME_NODE_CHANGE_TRANSFORM_CHANGE);
913 }
914
IsAncestorNodeHasTransition(FrameNodeChangeInfoFlag flag)915 bool BaseTextSelectOverlay::IsAncestorNodeHasTransition(FrameNodeChangeInfoFlag flag)
916 {
917 return ((flag & FRAME_NODE_CHANGE_TRANSITION_START) == FRAME_NODE_CHANGE_TRANSITION_START);
918 }
919
IsTouchAtHandle(const TouchEventInfo & info)920 bool BaseTextSelectOverlay::IsTouchAtHandle(const TouchEventInfo& info)
921 {
922 auto overlayManager = GetManager<SelectContentOverlayManager>();
923 CHECK_NULL_RETURN(overlayManager, false);
924 CHECK_NULL_RETURN(!info.GetTouches().empty(), false);
925 auto touchType = info.GetTouches().front().GetTouchType();
926 if (touchType == TouchType::DOWN) {
927 auto localOffset = info.GetTouches().front().GetLocalLocation();
928 auto globalOffset = info.GetTouches().front().GetGlobalLocation();
929 touchAtHandle_ = overlayManager->IsTouchAtHandle(
930 PointF(localOffset.GetX(), localOffset.GetY()), PointF(globalOffset.GetX(), globalOffset.GetY()));
931 } else if (touchType == TouchType::UP) {
932 if (touchAtHandle_) {
933 touchAtHandle_ = false;
934 return true;
935 }
936 }
937 return touchAtHandle_;
938 }
939
IsClickAtHandle(const GestureEvent & info)940 bool BaseTextSelectOverlay::IsClickAtHandle(const GestureEvent& info)
941 {
942 auto overlayManager = GetManager<SelectContentOverlayManager>();
943 CHECK_NULL_RETURN(overlayManager, false);
944 auto localOffset = info.GetLocalLocation();
945 auto globalOffset = info.GetGlobalLocation();
946 return overlayManager->IsTouchAtHandle(
947 PointF(localOffset.GetX(), localOffset.GetY()), PointF(globalOffset.GetX(), globalOffset.GetY()));
948 }
949
HasUnsupportedTransform(bool checkScale)950 bool BaseTextSelectOverlay::HasUnsupportedTransform(bool checkScale)
951 {
952 auto pattern = GetPattern<Pattern>();
953 CHECK_NULL_RETURN(pattern, false);
954 auto parent = pattern->GetHost();
955 CHECK_NULL_RETURN(parent, false);
956 while (parent) {
957 auto renderContext = parent->GetRenderContext();
958 CHECK_NULL_RETURN(renderContext, false);
959 if (parent->GetTag() == V2::WINDOW_SCENE_ETS_TAG) {
960 return false;
961 }
962 if (renderContext->HasMotionPath()) {
963 return true;
964 }
965 auto rotateVector = renderContext->GetTransformRotate();
966 if (rotateVector.has_value() && !NearZero(rotateVector->w) &&
967 !(NearZero(rotateVector->x) && NearZero(rotateVector->y) && NearZero(rotateVector->z))) {
968 return true;
969 }
970 if (CheckUnsupportedTransformMatrix(renderContext, checkScale)) {
971 return true;
972 }
973 auto translate = renderContext->GetTransformTranslate();
974 if (translate && !NearZero(translate->z.Value())) {
975 return true;
976 }
977 if (checkScale) {
978 auto scale = renderContext->GetTransformScale();
979 if (scale && (!NearEqual(scale->x, 1.0f) || !NearEqual(scale->y, 1.0f))) {
980 return true;
981 }
982 }
983 parent = parent->GetAncestorNodeOfFrame(true);
984 }
985 return false;
986 }
987
CheckUnsupportedTransformMatrix(const RefPtr<RenderContext> context,bool checkScale)988 bool BaseTextSelectOverlay::CheckUnsupportedTransformMatrix(const RefPtr<RenderContext> context, bool checkScale)
989 {
990 auto transformMatrix = context->GetTransformMatrix();
991 if (!transformMatrix) {
992 return false;
993 }
994 DecomposedTransform transform;
995 TransformUtil::DecomposeTransform(transform, transformMatrix.value());
996 Quaternion identity(0.0f, 0.0f, 0.0f, 1.0f);
997 const int32_t zTranslateIndex = 2;
998 if (transform.quaternion != identity || !NearZero(transform.translate[zTranslateIndex])) {
999 return true;
1000 }
1001 if (checkScale) {
1002 for (const auto& scalValue : transform.scale) {
1003 if (!NearEqual(scalValue, 1.0f)) {
1004 return true;
1005 }
1006 }
1007 }
1008 return false;
1009 }
1010
CheckSwitchToMode(HandleLevelMode mode)1011 bool BaseTextSelectOverlay::CheckSwitchToMode(HandleLevelMode mode)
1012 {
1013 if (mode == HandleLevelMode::OVERLAY && (HasUnsupportedTransform() || IsHandleInParentSafeAreaPadding())) {
1014 return false;
1015 }
1016 return true;
1017 }
1018
OnSelectionMenuOptionsUpdate(const NG::OnCreateMenuCallback && onCreateMenuCallback,const NG::OnMenuItemClickCallback && onMenuItemClick,const NG::OnPrepareMenuCallback && onPrepareMenuCallback)1019 void BaseTextSelectOverlay::OnSelectionMenuOptionsUpdate(const NG::OnCreateMenuCallback&& onCreateMenuCallback,
1020 const NG::OnMenuItemClickCallback&& onMenuItemClick, const NG::OnPrepareMenuCallback&& onPrepareMenuCallback)
1021 {
1022 onCreateMenuCallback_ = onCreateMenuCallback;
1023 onMenuItemClick_ = onMenuItemClick;
1024 onPrepareMenuCallback_ = onPrepareMenuCallback;
1025 }
1026
RegisterScrollingListener(const RefPtr<FrameNode> scrollableNode)1027 void BaseTextSelectOverlay::RegisterScrollingListener(const RefPtr<FrameNode> scrollableNode)
1028 {
1029 if (hasRegisterListener_) {
1030 return;
1031 }
1032 auto scrollingNode = scrollableNode;
1033 if (!scrollingNode) {
1034 auto host = GetOwner();
1035 CHECK_NULL_VOID(host);
1036 scrollingNode = host->GetAncestorNodeOfFrame(true);
1037 while (scrollingNode) {
1038 if (scrollingNode->GetTag() == V2::SWIPER_ETS_TAG) {
1039 break;
1040 }
1041 scrollingNode = scrollingNode->GetAncestorNodeOfFrame(true);
1042 }
1043 }
1044 if (scrollingNode) {
1045 auto pattern = scrollingNode->GetPattern<Pattern>();
1046 CHECK_NULL_VOID(pattern);
1047 auto scrollCallback = [weak = WeakClaim(this), scrollNode = WeakClaim(AceType::RawPtr(scrollableNode))] {
1048 auto overlay = weak.Upgrade();
1049 CHECK_NULL_VOID(overlay);
1050 overlay->OnHandleScrolling(scrollNode);
1051 };
1052 auto scrollListener = AceType::MakeRefPtr<ScrollingListener>(scrollCallback);
1053 pattern->RegisterScrollingListener(scrollListener);
1054 hasRegisterListener_ = true;
1055 }
1056 }
1057
OnHandleScrolling(const WeakPtr<FrameNode> & scrollingNode)1058 void BaseTextSelectOverlay::OnHandleScrolling(const WeakPtr<FrameNode>& scrollingNode)
1059 {
1060 if (SelectOverlayIsOn()) {
1061 HideMenu(true);
1062 auto taskExecutor = Container::CurrentTaskExecutor();
1063 CHECK_NULL_VOID(taskExecutor);
1064 taskExecutor->PostTask(
1065 [weak = WeakClaim(this), scrollingNode] {
1066 auto overlay = weak.Upgrade();
1067 CHECK_NULL_VOID(overlay);
1068 overlay->hasRegisterListener_ = false;
1069 if (overlay->SelectOverlayIsOn()) {
1070 overlay->RegisterScrollingListener(scrollingNode.Upgrade());
1071 }
1072 },
1073 TaskExecutor::TaskType::UI, "RegisterScrollingListener");
1074 } else {
1075 hasRegisterListener_ = false;
1076 }
1077 }
1078
CheckAndUpdateHostGlobalPaintRect()1079 bool BaseTextSelectOverlay::CheckAndUpdateHostGlobalPaintRect()
1080 {
1081 auto host = GetOwner();
1082 CHECK_NULL_RETURN(host, false);
1083 auto geometryNode = host->GetGeometryNode();
1084 CHECK_NULL_RETURN(geometryNode, false);
1085 auto framePaintRect = RectF(host->GetTransformRelativeOffset(), geometryNode->GetFrameSize());
1086 auto changed = globalPaintRect_.GetOffset() != framePaintRect.GetOffset();
1087 globalPaintRect_ = framePaintRect;
1088 return changed;
1089 }
1090
CheckHasTransformAttr()1091 bool BaseTextSelectOverlay::CheckHasTransformAttr()
1092 {
1093 auto pattern = GetPattern<Pattern>();
1094 CHECK_NULL_RETURN(pattern, false);
1095 auto host = pattern->GetHost();
1096 CHECK_NULL_RETURN(host, false);
1097 auto hasTransform = false;
1098 VectorF scaleIdentity(1.0f, 1.0f);
1099 Vector5F rotateIdentity(0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
1100 while (host) {
1101 auto renderContext = host->GetRenderContext();
1102 CHECK_NULL_RETURN(renderContext, false);
1103 if (host->GetTag() == V2::WINDOW_SCENE_ETS_TAG) {
1104 break;
1105 }
1106 if (renderContext->HasMotionPath()) {
1107 hasTransform = true;
1108 break;
1109 }
1110 // has rotate.
1111 auto rotateVector = renderContext->GetTransformRotate();
1112 if (rotateVector.has_value() && !(rotateIdentity == rotateVector.value())) {
1113 hasTransform = true;
1114 break;
1115 }
1116 // has scale.
1117 auto scaleVector = renderContext->GetTransformScale();
1118 if (scaleVector.has_value() && !(scaleIdentity == scaleVector.value())) {
1119 hasTransform = true;
1120 break;
1121 }
1122 // has z translate.
1123 auto translate = renderContext->GetTransformTranslate();
1124 if (translate && !NearZero(translate->z.Value())) {
1125 hasTransform = true;
1126 break;
1127 }
1128 if (CheckHasTransformMatrix(renderContext)) {
1129 hasTransform = true;
1130 break;
1131 }
1132 host = host->GetAncestorNodeOfFrame(true);
1133 }
1134 return hasTransform;
1135 }
1136
CheckHasTransformMatrix(const RefPtr<RenderContext> & context)1137 bool BaseTextSelectOverlay::CheckHasTransformMatrix(const RefPtr<RenderContext>& context)
1138 {
1139 auto transformMatrix = context->GetTransformMatrix();
1140 CHECK_NULL_RETURN(transformMatrix, false);
1141 const int32_t xIndex = 0;
1142 const int32_t yIndex = 1;
1143 const int32_t zIndex = 2;
1144 const int32_t wIndex = 3;
1145 DecomposedTransform transform;
1146 TransformUtil::DecomposeTransform(transform, transformMatrix.value());
1147 if (!NearZero(transform.translate[zIndex])) {
1148 return true;
1149 }
1150 Quaternion quaternionIdentity(0.0f, 0.0f, 0.0f, 1.0f);
1151 if (transform.quaternion != quaternionIdentity) {
1152 return true;
1153 }
1154 Vector3F scaleIdentity(1.0f, 1.0f, 1.0f);
1155 Vector3F scaleVector(transform.scale[xIndex], transform.scale[yIndex], transform.scale[zIndex]);
1156 if (!(scaleVector == scaleIdentity)) {
1157 return true;
1158 }
1159 Vector3F skewIdentity(0.0f, 0.0f, 0.0f);
1160 Vector3F skewVector(transform.skew[xIndex], transform.skew[yIndex], transform.skew[zIndex]);
1161 if (!(skewVector == skewIdentity)) {
1162 return true;
1163 }
1164 Vector4F perspectiveIdentity(0.0f, 0.0f, 0.0f, 1.0f);
1165 Vector4F perspectiveVector(transform.perspective[xIndex], transform.perspective[yIndex],
1166 transform.perspective[zIndex], transform.perspective[wIndex]);
1167 return !(perspectiveVector == perspectiveIdentity);
1168 }
1169
GetClipHandleViewPort(RectF & rect)1170 bool BaseTextSelectOverlay::GetClipHandleViewPort(RectF& rect)
1171 {
1172 auto host = GetOwner();
1173 CHECK_NULL_RETURN(host, false);
1174 if (HasUnsupportedTransform()) {
1175 return false;
1176 }
1177 RectF contentRect;
1178 if (!GetFrameNodeContentRect(host, contentRect)) {
1179 return false;
1180 }
1181 contentRect.SetOffset(contentRect.GetOffset() + host->GetPaintRectWithTransform().GetOffset());
1182 CHECK_NULL_RETURN(CalculateClippedRect(contentRect), false);
1183 UpdateClipHandleViewPort(contentRect);
1184 rect = contentRect;
1185 return true;
1186 }
1187
CalculateClippedRect(RectF & contentRect)1188 bool BaseTextSelectOverlay::CalculateClippedRect(RectF& contentRect)
1189 {
1190 auto host = GetOwner();
1191 CHECK_NULL_RETURN(host, false);
1192 auto parent = host->GetAncestorNodeOfFrame(true);
1193 while (parent) {
1194 RectF parentContentRect;
1195 if (!GetFrameNodeContentRect(parent, parentContentRect)) {
1196 return false;
1197 }
1198 auto renderContext = parent->GetRenderContext();
1199 CHECK_NULL_RETURN(renderContext, false);
1200 if (renderContext->GetClipEdge().value_or(false)) {
1201 auto isOverTheParentBottom = GreatNotEqual(contentRect.Top(), parentContentRect.Bottom());
1202 contentRect = contentRect.IntersectRectT(parentContentRect);
1203 if (isOverTheParentBottom) {
1204 contentRect.SetTop(parentContentRect.Bottom());
1205 }
1206 }
1207 contentRect.SetOffset(contentRect.GetOffset() + parent->GetPaintRectWithTransform().GetOffset());
1208 contentRect.SetWidth(std::max(contentRect.Width(), 0.0f));
1209 contentRect.SetHeight(std::max(contentRect.Height(), 0.0f));
1210 parent = parent->GetAncestorNodeOfFrame(true);
1211 }
1212 contentRect.SetWidth(std::max(contentRect.Width(), 0.0f));
1213 contentRect.SetHeight(std::max(contentRect.Height(), 0.0f));
1214 return true;
1215 }
1216
GetFrameNodeContentRect(const RefPtr<FrameNode> & node,RectF & contentRect)1217 bool BaseTextSelectOverlay::GetFrameNodeContentRect(const RefPtr<FrameNode>& node, RectF& contentRect)
1218 {
1219 CHECK_NULL_RETURN(node, false);
1220 if (GetScrollableClipContentRect(node, contentRect)) {
1221 return true;
1222 }
1223 auto geometryNode = node->GetGeometryNode();
1224 CHECK_NULL_RETURN(geometryNode, false);
1225 auto renderContext = node->GetRenderContext();
1226 CHECK_NULL_RETURN(renderContext, false);
1227 if (geometryNode->GetContent()) {
1228 contentRect = geometryNode->GetContentRect();
1229 } else {
1230 contentRect = RectF(OffsetF(0.0f, 0.0f), geometryNode->GetFrameSize());
1231 }
1232 return true;
1233 }
1234
MarkOverlayDirty()1235 void BaseTextSelectOverlay::MarkOverlayDirty()
1236 {
1237 if (SelectOverlayIsOn()) {
1238 auto host = GetOwner();
1239 CHECK_NULL_VOID(host);
1240 auto overlayNode = host->GetOverlayNode();
1241 CHECK_NULL_VOID(overlayNode);
1242 overlayNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1243 }
1244 }
1245
ApplySelectAreaWithKeyboard(RectF & selectArea)1246 void BaseTextSelectOverlay::ApplySelectAreaWithKeyboard(RectF& selectArea)
1247 {
1248 if (Negative(selectArea.Top())) {
1249 selectArea.SetHeight(selectArea.Height() + selectArea.Top());
1250 selectArea.SetTop(0.0f);
1251 }
1252 auto host = GetOwner();
1253 CHECK_NULL_VOID(host);
1254 auto pipeline = host->GetContext();
1255 CHECK_NULL_VOID(pipeline);
1256 auto safeAreaManager = pipeline->GetSafeAreaManager();
1257 CHECK_NULL_VOID(safeAreaManager);
1258 auto keyboardInset = safeAreaManager->GetKeyboardInset();
1259 if (keyboardInset.Length() <= 0) {
1260 return;
1261 }
1262 if (GreatOrEqual(selectArea.Top(), keyboardInset.start)) {
1263 selectArea.SetHeight(0.0f);
1264 }
1265 }
1266
OnHandleMarkInfoChange(const std::shared_ptr<SelectOverlayInfo> info,SelectOverlayDirtyFlag flag)1267 void BaseTextSelectOverlay::OnHandleMarkInfoChange(
1268 const std::shared_ptr<SelectOverlayInfo> info, SelectOverlayDirtyFlag flag)
1269 {
1270 auto manager = GetManager<SelectContentOverlayManager>();
1271 CHECK_NULL_VOID(manager);
1272 if ((flag & DIRTY_HANDLE_COLOR_FLAG) == DIRTY_HANDLE_COLOR_FLAG) {
1273 info->handlerColor = GetHandleColor();
1274 manager->MarkHandleDirtyNode(PROPERTY_UPDATE_RENDER);
1275 }
1276 if ((flag & DIRTY_FIRST_HANDLE) == DIRTY_FIRST_HANDLE ||
1277 (flag & DIRTY_SECOND_HANDLE) == DIRTY_SECOND_HANDLE) {
1278 if (info->menuInfo.showTranslate != (menuTranslateIsSupport_ && AllowTranslate() &&
1279 IsNeedMenuTranslate())) {
1280 info->menuInfo.showTranslate = !info->menuInfo.showTranslate;
1281 manager->NotifyUpdateToolBar(true);
1282 }
1283 if (info->menuInfo.showSearch != (isSupportMenuSearch_ && AllowSearch() &&
1284 IsNeedMenuSearch())) {
1285 info->menuInfo.showSearch = !info->menuInfo.showSearch;
1286 manager->NotifyUpdateToolBar(true);
1287 }
1288 if (info->menuInfo.showShare != (IsSupportMenuShare() && AllowShare() &&
1289 IsNeedMenuShare())) {
1290 info->menuInfo.showShare = !info->menuInfo.showShare;
1291 manager->NotifyUpdateToolBar(true);
1292 }
1293 }
1294 }
1295
UpdateHandleColor()1296 void BaseTextSelectOverlay::UpdateHandleColor()
1297 {
1298 auto manager = GetManager<SelectContentOverlayManager>();
1299 CHECK_NULL_VOID(manager);
1300 manager->MarkInfoChange(DIRTY_HANDLE_COLOR_FLAG);
1301 }
1302
IsNeedMenuTranslate()1303 bool BaseTextSelectOverlay::IsNeedMenuTranslate()
1304 {
1305 auto translation = GetSelectedText();
1306 return !std::regex_match(translation, std::regex("^\\s*$"));
1307 }
1308
ConvertWindowToScreenDomain(RectF rect)1309 RectF BaseTextSelectOverlay::ConvertWindowToScreenDomain(RectF rect)
1310 {
1311 auto host = GetOwner();
1312 CHECK_NULL_RETURN(host, rect);
1313 auto pipeline = host->GetContext();
1314 CHECK_NULL_RETURN(pipeline, rect);
1315 Rect windowOffset = pipeline->GetDisplayWindowRectInfo();
1316 rect.SetLeft(rect.Left() + windowOffset.Left());
1317 rect.SetTop(rect.Top() + windowOffset.Top());
1318 return rect;
1319 }
1320
ConvertWindowToScreenDomain(EdgeF edge)1321 EdgeF BaseTextSelectOverlay::ConvertWindowToScreenDomain(EdgeF edge)
1322 {
1323 auto host = GetOwner();
1324 CHECK_NULL_RETURN(host, edge);
1325 auto pipeline = host->GetContext();
1326 CHECK_NULL_RETURN(pipeline, edge);
1327 Rect windowOffset = pipeline->GetDisplayWindowRectInfo();
1328 edge.x += windowOffset.Left();
1329 edge.y += windowOffset.Top();
1330 return edge;
1331 }
1332
GetTranslateParamRectStr(RectF rect,EdgeF rectLeftTop,EdgeF rectRightBottom)1333 std::string BaseTextSelectOverlay::GetTranslateParamRectStr(RectF rect, EdgeF rectLeftTop, EdgeF rectRightBottom)
1334 {
1335 auto jsonValue = JsonUtil::Create(true);
1336 jsonValue->Put("x", std::round(rect.GetX()));
1337 jsonValue->Put("y", std::round(rect.GetY()));
1338 jsonValue->Put("width", std::round(rect.Width()));
1339 jsonValue->Put("height", std::round(rect.Height()));
1340 jsonValue->Put("startLeft", std::round(rectLeftTop.x));
1341 jsonValue->Put("startTop", std::round(rectLeftTop.y));
1342 jsonValue->Put("endRight", std::round(rectRightBottom.x));
1343 jsonValue->Put("endBottom", std::round(rectRightBottom.y));
1344 return jsonValue->ToString();
1345 }
1346
HandleOnTranslate()1347 void BaseTextSelectOverlay::HandleOnTranslate()
1348 {
1349 HideMenu(true);
1350 auto value = GetSelectedText();
1351 auto queryWord = std::regex_replace(value, std::regex("^\\s+|\\s+$"), "");
1352 if (!queryWord.empty()) {
1353 RectF rect = GetSelectArea();
1354 EdgeF rectLeftTop = GetSelectAreaStartLeftTop();
1355 EdgeF rectRightBottom = GetSelectAreaEndRightBottom();
1356 rect = ConvertWindowToScreenDomain(rect);
1357 rectLeftTop = ConvertWindowToScreenDomain(rectLeftTop);
1358 rectRightBottom = ConvertWindowToScreenDomain(rectRightBottom);
1359 TextTranslationAdapter::StartAITextTranslationTask(queryWord,
1360 GetTranslateParamRectStr(rect, rectLeftTop, rectRightBottom));
1361 }
1362 }
1363
IsNeedMenuSearch()1364 bool BaseTextSelectOverlay::IsNeedMenuSearch()
1365 {
1366 auto searchContent = GetSelectedText();
1367 return !std::regex_match(searchContent, std::regex("^\\s*$"));
1368 }
1369
HandleOnSearch()1370 void BaseTextSelectOverlay::HandleOnSearch()
1371 {
1372 HideMenu(true);
1373 auto value = GetSelectedText();
1374 auto queryWord = std::regex_replace(value, std::regex("^\\s+|\\s+$"), "");
1375 if (!queryWord.empty()) {
1376 auto pipeline = PipelineBase::GetCurrentContextSafelyWithCheck();
1377 CHECK_NULL_VOID(pipeline);
1378 pipeline->StartAbilityOnQuery(queryWord);
1379 }
1380 }
1381
IsSupportMenuShare()1382 bool BaseTextSelectOverlay::IsSupportMenuShare()
1383 {
1384 auto container = Container::Current();
1385 if (container && container->IsSceneBoardWindow()) {
1386 return false;
1387 }
1388 return SystemProperties::IsSyscapExist(SYSTEM_CAPABILITY_OF_SHARE);
1389 }
1390
IsNeedMenuShare()1391 bool BaseTextSelectOverlay::IsNeedMenuShare()
1392 {
1393 auto shareContent = GetSelectedText();
1394 auto shareWord = std::regex_replace(shareContent, std::regex("^\\s+|\\s+$"), "");
1395 if (shareWord.empty()) {
1396 return false;
1397 }
1398 auto maxShareLength = TextShareAdapter::GetMaxTextShareLength();
1399 if (shareWord.size() > maxShareLength) {
1400 return false;
1401 }
1402 return true;
1403 }
1404
HandleOnShare()1405 void BaseTextSelectOverlay::HandleOnShare()
1406 {
1407 HideMenu(true);
1408 auto value = GetSelectedText();
1409 auto shareWord = std::regex_replace(value, std::regex("^\\s+|\\s+$"), "");
1410 if (!shareWord.empty()) {
1411 auto pipeline = PipelineBase::GetCurrentContextSafelyWithCheck();
1412 CHECK_NULL_VOID(pipeline);
1413 auto containerId = pipeline->GetInstanceId();
1414 auto contentRect = GetSelectArea();
1415 TextShareAdapter::StartTextShareTask(containerId, contentRect, shareWord);
1416 }
1417 }
1418
GetScrollableClipInfo(const RefPtr<FrameNode> & node)1419 std::pair<ContentClipMode, std::optional<ContentClip>> BaseTextSelectOverlay::GetScrollableClipInfo(
1420 const RefPtr<FrameNode>& node)
1421 {
1422 auto props = DynamicCast<ScrollablePaintProperty>(node->GetPaintProperty<PaintProperty>());
1423 CHECK_NULL_RETURN(props, std::make_pair(ContentClipMode::DEFAULT, std::nullopt));
1424 auto clip = props->GetContentClip();
1425 CHECK_NULL_RETURN(clip, std::make_pair(ContentClipMode::DEFAULT, std::nullopt));
1426 auto mode = clip->first;
1427 if (mode == ContentClipMode::DEFAULT) {
1428 if (node->GetTag() == V2::GRID_ETS_TAG || node->GetTag() == V2::SCROLL_ETS_TAG) {
1429 mode = ContentClipMode::BOUNDARY;
1430 } else if (node->GetTag() == V2::LIST_ETS_TAG || node->GetTag() == V2::WATERFLOW_ETS_TAG) {
1431 mode = ContentClipMode::CONTENT_ONLY;
1432 }
1433 }
1434 return std::make_pair(mode, clip);
1435 }
1436
GetScrollableClipContentRect(const RefPtr<FrameNode> & node,RectF & rect)1437 bool BaseTextSelectOverlay::GetScrollableClipContentRect(const RefPtr<FrameNode>& node, RectF& rect)
1438 {
1439 auto clipInfo = GetScrollableClipInfo(node);
1440 auto geo = node->GetGeometryNode();
1441 CHECK_NULL_RETURN(geo, false);
1442 switch (clipInfo.first) {
1443 case ContentClipMode::SAFE_AREA:
1444 case ContentClipMode::CONTENT_ONLY: {
1445 rect = geo->GetPaddingRect();
1446 rect.SetOffset(rect.GetOffset() - geo->GetFrameOffset());
1447 return true;
1448 }
1449 case ContentClipMode::BOUNDARY: {
1450 rect = geo->GetFrameRect();
1451 rect.SetOffset({ 0.0f, 0.0f });
1452 return true;
1453 }
1454 case ContentClipMode::CUSTOM: {
1455 auto contentClip = clipInfo.second;
1456 CHECK_NULL_RETURN(contentClip, false);
1457 auto shapeRect = contentClip->second;
1458 CHECK_NULL_RETURN(shapeRect, false);
1459 auto clipOffset = shapeRect->GetOffset();
1460 rect = RectF(clipOffset.GetX().ConvertToPx(), clipOffset.GetY().ConvertToPx(),
1461 shapeRect->GetWidth().ConvertToPx(), shapeRect->GetHeight().ConvertToPx());
1462 return true;
1463 }
1464 default:
1465 return false;
1466 }
1467 }
1468
CheckHandleIsInSafeAreaPadding(const RefPtr<FrameNode> & node,const RectF & handle)1469 bool BaseTextSelectOverlay::CheckHandleIsInSafeAreaPadding(const RefPtr<FrameNode>& node, const RectF& handle)
1470 {
1471 auto clipInfo = GetScrollableClipInfo(node);
1472 if (clipInfo.first != ContentClipMode::SAFE_AREA) {
1473 return false;
1474 }
1475 auto layoutProperty = node->GetLayoutProperty();
1476 CHECK_NULL_RETURN(layoutProperty, false);
1477 auto safeAreaPadding = layoutProperty->GetOrCreateSafeAreaPadding();
1478 if (!safeAreaPadding.HasValue()) {
1479 return false;
1480 }
1481 auto geo = node->GetGeometryNode();
1482 CHECK_NULL_RETURN(geo, false);
1483 auto paddingRect = geo->GetPaddingRect();
1484 if (safeAreaPadding.left && LessNotEqual(handle.Left(), paddingRect.Left())) {
1485 return true;
1486 }
1487 if (safeAreaPadding.top && LessNotEqual(handle.Top(), paddingRect.Top())) {
1488 return true;
1489 }
1490 if (safeAreaPadding.right && GreatNotEqual(handle.Right(), paddingRect.Right())) {
1491 return true;
1492 }
1493 if (safeAreaPadding.bottom && GreatNotEqual(handle.Bottom(), paddingRect.Bottom())) {
1494 return true;
1495 }
1496 return false;
1497 }
1498
IsHandleInParentSafeAreaPadding(const RectF & firstRect,const RectF & secondRect)1499 bool BaseTextSelectOverlay::IsHandleInParentSafeAreaPadding(const RectF& firstRect, const RectF& secondRect)
1500 {
1501 auto firstHandlePaint = firstRect;
1502 auto secondHandlePaint = secondRect;
1503 auto parent = GetOwner();
1504 while (parent) {
1505 if (GetOwner() != parent) {
1506 if (CheckHandleIsInSafeAreaPadding(parent, secondHandlePaint)) {
1507 return true;
1508 }
1509 if (!IsSingleHandle() && CheckHandleIsInSafeAreaPadding(parent, firstHandlePaint)) {
1510 return true;
1511 }
1512 }
1513 auto context = parent->GetRenderContext();
1514 CHECK_NULL_RETURN(context, false);
1515 firstHandlePaint += context->GetPaintRectWithTransform().GetOffset();
1516 secondHandlePaint += context->GetPaintRectWithTransform().GetOffset();
1517 parent = parent->GetAncestorNodeOfFrame(true);
1518 }
1519 return false;
1520 }
1521
IsHandleInParentSafeAreaPadding()1522 bool BaseTextSelectOverlay::IsHandleInParentSafeAreaPadding()
1523 {
1524 auto overlayManager = GetManager<SelectContentOverlayManager>();
1525 CHECK_NULL_RETURN(overlayManager, false);
1526 auto overlayInfo = overlayManager->GetSelectOverlayInfo();
1527 CHECK_NULL_RETURN(overlayInfo, false);
1528 return IsHandleInParentSafeAreaPadding(
1529 overlayInfo->firstHandle.localPaintRect, overlayInfo->secondHandle.localPaintRect);
1530 }
1531
AddAvoidKeyboardCallback(bool isCustomKeyboard)1532 void BaseTextSelectOverlay::AddAvoidKeyboardCallback(bool isCustomKeyboard)
1533 {
1534 auto host = GetOwner();
1535 CHECK_NULL_VOID(host);
1536 auto context = host->GetContext();
1537 CHECK_NULL_VOID(context);
1538 auto textFieldManagerNg = DynamicCast<TextFieldManagerNG>(context->GetTextFieldManager());
1539 CHECK_NULL_VOID(textFieldManagerNg);
1540 textFieldManagerNg->AddAvoidKeyboardCallback(host->GetId(), isCustomKeyboard, [weak = WeakClaim(this)]() {
1541 auto overlay = weak.Upgrade();
1542 CHECK_NULL_VOID(overlay);
1543 if (!overlay->SelectOverlayIsOn()) {
1544 return;
1545 }
1546 auto host = overlay->GetOwner();
1547 CHECK_NULL_VOID(host);
1548 auto flag = host->GetChangeInfoFlag();
1549 host->ClearChangeInfoFlag();
1550 host->AddFrameNodeChangeInfoFlag(AVOID_KEYBOARD_END_FALG);
1551 host->ProcessFrameNodeChangeFlag();
1552 host->ClearChangeInfoFlag();
1553 host->AddFrameNodeChangeInfoFlag(flag);
1554 });
1555 }
1556
RemoveAvoidKeyboardCallback()1557 void BaseTextSelectOverlay::RemoveAvoidKeyboardCallback()
1558 {
1559 auto host = GetOwner();
1560 CHECK_NULL_VOID(host);
1561 auto context = host->GetContext();
1562 CHECK_NULL_VOID(context);
1563 auto textFieldManagerNg = DynamicCast<TextFieldManagerNG>(context->GetTextFieldManager());
1564 CHECK_NULL_VOID(textFieldManagerNg);
1565 textFieldManagerNg->RemoveAvoidKeyboardCallback(host->GetId());
1566 }
1567
IsHiddenHandle()1568 bool BaseTextSelectOverlay::IsHiddenHandle()
1569 {
1570 auto overlayManager = GetManager<SelectContentOverlayManager>();
1571 CHECK_NULL_RETURN(overlayManager, false);
1572 auto overlayInfo = overlayManager->GetSelectOverlayInfo();
1573 CHECK_NULL_RETURN(overlayInfo, false);
1574 return overlayInfo->isSingleHandle && overlayManager->IsHiddenHandle();
1575 }
1576
IsHandleVisible(bool isFirst)1577 bool BaseTextSelectOverlay::IsHandleVisible(bool isFirst)
1578 {
1579 auto overlayManager = GetManager<SelectContentOverlayManager>();
1580 CHECK_NULL_RETURN(overlayManager, false);
1581 auto overlayInfo = overlayManager->GetSelectOverlayInfo();
1582 CHECK_NULL_RETURN(overlayInfo, false);
1583 return isFirst ? overlayInfo->firstHandle.isShow : overlayInfo->secondHandle.isShow;
1584 }
1585
UpdateMenuOnWindowSizeChanged(WindowSizeChangeReason type)1586 void BaseTextSelectOverlay::UpdateMenuOnWindowSizeChanged(WindowSizeChangeReason type)
1587 {
1588 auto overlayManager = GetManager<SelectContentOverlayManager>();
1589 CHECK_NULL_VOID(overlayManager);
1590 if (overlayManager->IsRightClickSubWindowMenu()) {
1591 if (NeedsProcessMenuOnWinChange()) {
1592 CloseOverlay(false, CloseReason::CLOSE_REASON_WINDOW_SIZE_CHANGE);
1593 }
1594 } else if (overlayManager->IsSelectOverlaySubWindowMenu()) {
1595 if (isSuperFoldDisplayDevice_ && NeedsProcessMenuOnWinChange()) {
1596 CloseOverlay(false, CloseReason::CLOSE_REASON_WINDOW_SIZE_CHANGE);
1597 return;
1598 }
1599 if (overlayManager->IsMenuShow() && NeedsProcessMenuOnWinChange()) {
1600 HideMenu(true);
1601 TAG_LOGI(AceLogTag::ACE_SELECT_OVERLAY, "Hide selectoverlay subwindow menu on window size change.");
1602 }
1603 }
1604 }
1605
IsEnableSelectionMenu()1606 bool BaseTextSelectOverlay::IsEnableSelectionMenu()
1607 {
1608 auto host = GetOwner();
1609 CHECK_NULL_RETURN(host, true);
1610 auto pipelineContext = host->GetContext();
1611 CHECK_NULL_RETURN(pipelineContext, true);
1612 auto textOverlayTheme = pipelineContext->GetTheme<TextOverlayTheme>();
1613 CHECK_NULL_RETURN(textOverlayTheme, true);
1614 return textOverlayTheme->GetEnableSelectionMenu();
1615 }
1616
NeedsProcessMenuOnWinChange()1617 bool BaseTextSelectOverlay::NeedsProcessMenuOnWinChange()
1618 {
1619 auto host = GetOwner();
1620 CHECK_NULL_RETURN(host, false);
1621 auto pipelineContext = host->GetContext();
1622 CHECK_NULL_RETURN(pipelineContext, false);
1623 auto container = AceEngine::Get().GetContainer(pipelineContext->GetInstanceId());
1624 CHECK_NULL_RETURN(container, false);
1625 auto selectTheme = pipelineContext->GetTheme<SelectTheme>();
1626 CHECK_NULL_RETURN(selectTheme, false);
1627 return selectTheme->GetExpandDisplay() || container->IsFreeMultiWindow();
1628 }
1629
GetDragViewHandleRects(RectF & firstRect,RectF & secondRect)1630 bool BaseTextSelectOverlay::GetDragViewHandleRects(RectF& firstRect, RectF& secondRect)
1631 {
1632 auto overlayInfo = GetSelectOverlayInfos();
1633 CHECK_NULL_RETURN(overlayInfo, false);
1634 if (overlayInfo->handleLevelMode == HandleLevelMode::OVERLAY || CheckSwitchToMode(HandleLevelMode::OVERLAY)) {
1635 firstRect = overlayInfo->firstHandle.paintRect;
1636 secondRect = overlayInfo->secondHandle.paintRect;
1637 return true;
1638 }
1639 auto pattern = GetPattern<Pattern>();
1640 CHECK_NULL_RETURN(pattern, false);
1641 auto textDragBase = AceType::DynamicCast<TextDragBase>(pattern);
1642 CHECK_NULL_RETURN(textDragBase, false);
1643 auto dragParentOffset = textDragBase->GetParentGlobalOffset();
1644 firstRect = overlayInfo->firstHandle.localPaintRect + dragParentOffset;
1645 secondRect = overlayInfo->secondHandle.localPaintRect + dragParentOffset;
1646 return true;
1647 }
1648
UpdateIsSingleHandle(bool isSingleHandle)1649 void BaseTextSelectOverlay::UpdateIsSingleHandle(bool isSingleHandle)
1650 {
1651 SetIsSingleHandle(isSingleHandle);
1652 auto manager = GetManager<SelectContentOverlayManager>();
1653 CHECK_NULL_VOID(manager);
1654 manager->UpdateIsSingleHandle(isSingleHandle);
1655 }
1656 } // namespace OHOS::Ace::NG
1657