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