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/utils.h"
19 #include "core/components_ng/pattern/pattern.h"
20 #include "core/components_ng/pattern/scrollable/nestable_scroll_container.h"
21 #include "core/components_ng/pattern/select_overlay/select_overlay_property.h"
22 #include "core/components_ng/pattern/text_field/text_field_manager.h"
23 #include "core/components_v2/inspector/inspector_constants.h"
24
25 namespace OHOS::Ace::NG {
26 namespace {
27 constexpr int32_t NO_NEED_RESTART_SINGLE_HANDLE = 100;
28 } // namespace
ProcessOverlay(const OverlayRequest & request)29 void BaseTextSelectOverlay::ProcessOverlay(const OverlayRequest& request)
30 {
31 UpdateTransformFlag();
32 if (!PreProcessOverlay(request) || AnimationUtils::IsImplicitAnimationOpen()) {
33 return;
34 }
35 auto checkClipboard = [weak = WeakClaim(this), request](bool hasData) {
36 TAG_LOGI(AceLogTag::ACE_TEXT, "HasData callback from clipboard, data available ? %{public}d", hasData);
37 auto overlay = weak.Upgrade();
38 CHECK_NULL_VOID(overlay);
39 overlay->ShowSelectOverlay(request, hasData);
40 };
41 auto textBase = hostTextBase_.Upgrade();
42 CHECK_NULL_VOID(textBase);
43 auto clipboard = textBase->GetClipboard();
44 if (clipboard) {
45 auto mimeTypes = GetPasteMimeTypes();
46 if (!mimeTypes.empty()) {
47 clipboard->HasDataType(checkClipboard, mimeTypes);
48 return;
49 }
50 clipboard->HasData(checkClipboard);
51 } else {
52 checkClipboard(false);
53 }
54 }
55
ShowSelectOverlay(const OverlayRequest & request,bool hasClipboardData)56 void BaseTextSelectOverlay::ShowSelectOverlay(const OverlayRequest& request, bool hasClipboardData)
57 {
58 SetShowPaste(hasClipboardData);
59 SetMenuIsShow(request.menuIsShow);
60 SetIsShowHandleLine(!request.hideHandleLine);
61 latestReqeust_ = request;
62 if (!SelectOverlayIsOn() && enableHandleLevel_) {
63 auto firstLocalRect = GetFirstHandleLocalPaintRect();
64 auto secondLocalRect = GetSecondHandleLocalPaintRect();
65 CalcHandleLevelMode(firstLocalRect, secondLocalRect);
66 }
67 if (enableHandleLevel_) {
68 auto host = GetOwner();
69 CHECK_NULL_VOID(host);
70 host->RegisterNodeChangeListener();
71 RegisterScrollingListener(nullptr);
72 CheckAndUpdateHostGlobalPaintRect();
73 }
74 auto manager = SelectContentOverlayManager::GetOverlayManager(Claim(this));
75 CHECK_NULL_VOID(manager);
76 manager->Show(request.animation, request.requestCode);
77 }
78
ProcessOverlayOnAreaChanged(const OverlayRequest & request)79 void BaseTextSelectOverlay::ProcessOverlayOnAreaChanged(const OverlayRequest& request)
80 {
81 auto overlayRequest = request;
82 overlayRequest.requestCode = NO_NEED_RESTART_SINGLE_HANDLE;
83 ProcessOverlay(overlayRequest);
84 }
85
CheckRestartHiddenHandleTask(int32_t requestCode)86 bool BaseTextSelectOverlay::CheckRestartHiddenHandleTask(int32_t requestCode)
87 {
88 return requestCode != NO_NEED_RESTART_SINGLE_HANDLE;
89 }
90
IsShowMouseMenu()91 bool BaseTextSelectOverlay::IsShowMouseMenu()
92 {
93 auto overlayManager = GetManager<SelectContentOverlayManager>();
94 CHECK_NULL_RETURN(overlayManager, false);
95 return overlayManager->GetShowMenuType() == OptionMenuType::MOUSE_MENU;
96 }
97
IsCurrentMenuVisibile()98 bool BaseTextSelectOverlay::IsCurrentMenuVisibile()
99 {
100 auto overlayManager = GetManager<SelectContentOverlayManager>();
101 CHECK_NULL_RETURN(overlayManager, false);
102 return overlayManager->IsMenuShow();
103 }
104
IsHandleReverse()105 bool BaseTextSelectOverlay::IsHandleReverse()
106 {
107 auto overlayManager = GetManager<SelectContentOverlayManager>();
108 CHECK_NULL_RETURN(overlayManager, false);
109 return overlayManager->IsHandleReverse();
110 }
111
SelectOverlayIsOn()112 bool BaseTextSelectOverlay::SelectOverlayIsOn()
113 {
114 auto manager = GetManager<SelectContentOverlayManager>();
115 CHECK_NULL_RETURN(manager, false);
116 return manager->IsOpen();
117 }
118
SelectOverlayIsCreating()119 bool BaseTextSelectOverlay::SelectOverlayIsCreating()
120 {
121 auto manager = GetManager<SelectContentOverlayManager>();
122 CHECK_NULL_RETURN(manager, false);
123 return manager->IsCreating();
124 }
125
CloseOverlay(bool animation,CloseReason reason)126 void BaseTextSelectOverlay::CloseOverlay(bool animation, CloseReason reason)
127 {
128 auto overlayManager = GetManager<SelectContentOverlayManager>();
129 CHECK_NULL_VOID(overlayManager);
130 overlayManager->Close(GetOwnerId(), false, reason);
131 AfterCloseOverlay();
132 }
133
ToggleMenu()134 void BaseTextSelectOverlay::ToggleMenu()
135 {
136 auto manager = GetManager<SelectContentOverlayManager>();
137 CHECK_NULL_VOID(manager);
138 manager->ToggleOptionMenu();
139 UpdateOriginalMenuIsShow();
140 }
141
ShowMenu()142 void BaseTextSelectOverlay::ShowMenu()
143 {
144 auto manager = GetManager<SelectContentOverlayManager>();
145 CHECK_NULL_VOID(manager);
146 manager->ShowOptionMenu();
147 UpdateOriginalMenuIsShow();
148 }
149
HideMenu(bool noAnimation)150 void BaseTextSelectOverlay::HideMenu(bool noAnimation)
151 {
152 auto manager = GetManager<SelectContentOverlayManager>();
153 CHECK_NULL_VOID(manager);
154 manager->HideOptionMenu(noAnimation);
155 UpdateOriginalMenuIsShow();
156 }
157
DisableMenu()158 void BaseTextSelectOverlay::DisableMenu()
159 {
160 auto manager = GetManager<SelectContentOverlayManager>();
161 CHECK_NULL_VOID(manager);
162 manager->DisableMenu();
163 }
164
EnableMenu()165 void BaseTextSelectOverlay::EnableMenu()
166 {
167 auto manager = GetManager<SelectContentOverlayManager>();
168 CHECK_NULL_VOID(manager);
169 manager->EnableMenu();
170 }
171
UpdateAllHandlesOffset()172 void BaseTextSelectOverlay::UpdateAllHandlesOffset()
173 {
174 auto manager = GetManager<SelectContentOverlayManager>();
175 CHECK_NULL_VOID(manager);
176 manager->MarkInfoChange(DIRTY_DOUBLE_HANDLE | DIRTY_SELECT_AREA);
177 }
178
UpdateFirstHandleOffset()179 void BaseTextSelectOverlay::UpdateFirstHandleOffset()
180 {
181 auto manager = GetManager<SelectContentOverlayManager>();
182 CHECK_NULL_VOID(manager);
183 manager->MarkInfoChange(DIRTY_FIRST_HANDLE);
184 }
185
UpdateSecondHandleOffset()186 void BaseTextSelectOverlay::UpdateSecondHandleOffset()
187 {
188 auto manager = GetManager<SelectContentOverlayManager>();
189 CHECK_NULL_VOID(manager);
190 manager->MarkInfoChange(DIRTY_SECOND_HANDLE);
191 }
192
UpdateViewPort()193 void BaseTextSelectOverlay::UpdateViewPort()
194 {
195 auto manager = GetManager<SelectContentOverlayManager>();
196 CHECK_NULL_VOID(manager);
197 manager->MarkInfoChange(DIRTY_VIEWPORT);
198 }
199
GetOwner()200 RefPtr<FrameNode> BaseTextSelectOverlay::GetOwner()
201 {
202 auto pattern = GetPattern<Pattern>();
203 CHECK_NULL_RETURN(pattern, nullptr);
204 return pattern->GetHost();
205 }
206
OnHandleGlobalTouchEvent(SourceType sourceType,TouchType touchType,bool touchInside)207 void BaseTextSelectOverlay::OnHandleGlobalTouchEvent(SourceType sourceType, TouchType touchType, bool touchInside)
208 {
209 if (IsMouseClickDown(sourceType, touchType)) {
210 CloseOverlay(false, CloseReason::CLOSE_REASON_CLICK_OUTSIDE);
211 } else if (IsTouchUp(sourceType, touchType)) {
212 HideMenu(true);
213 }
214 }
215
CheckTouchInHostNode(const PointF & touchPoint)216 bool BaseTextSelectOverlay::CheckTouchInHostNode(const PointF& touchPoint)
217 {
218 auto host = GetOwner();
219 CHECK_NULL_RETURN(host, false);
220 auto geo = host->GetGeometryNode();
221 CHECK_NULL_RETURN(geo, false);
222 auto rect = RectF(OffsetF(0.0f, 0.0f), geo->GetFrameSize());
223 return rect.IsInRegion(touchPoint);
224 }
225
OnUpdateSelectOverlayInfo(SelectOverlayInfo & overlayInfo,int32_t requestCode)226 void BaseTextSelectOverlay::OnUpdateSelectOverlayInfo(SelectOverlayInfo& overlayInfo, int32_t requestCode)
227 {
228 overlayInfo.isSingleHandle = isSingleHandle_;
229 overlayInfo.isHandleLineShow = isShowHandleLine_;
230 overlayInfo.recreateOverlay = isUsingMouse_;
231 overlayInfo.rightClickOffset = mouseMenuOffset_;
232 overlayInfo.isUsingMouse = isUsingMouse_;
233 overlayInfo.isNewAvoid = true;
234 overlayInfo.hitTestMode = HitTestMode::HTMDEFAULT;
235 if (hasTransform_) {
236 overlayInfo.callerNodeInfo = {
237 .paintFrameRect = GetPaintRectWithTransform(),
238 .paintOffset = GetPaintRectOffsetWithTransform()
239 };
240 }
241 overlayInfo.ancestorViewPort = GetAncestorNodeViewPort();
242 overlayInfo.enableHandleLevel = enableHandleLevel_;
243 overlayInfo.handleLevelMode = handleLevelMode_;
244 if (enableHandleLevel_) {
245 overlayInfo.scale = GetHostScale();
246 }
247 overlayInfo.afterOnClick = [weak = WeakClaim(this)](const GestureEvent&, bool isFirst) {
248 auto overlay = weak.Upgrade();
249 CHECK_NULL_VOID(overlay);
250 overlay->UpdateOriginalMenuIsShow();
251 };
252 }
253
GetVisibleRect(const RefPtr<FrameNode> & node,const RectF & visibleRect)254 RectF BaseTextSelectOverlay::GetVisibleRect(const RefPtr<FrameNode>& node, const RectF& visibleRect)
255 {
256 CHECK_NULL_RETURN(node, visibleRect);
257 auto parentNode = node->GetAncestorNodeOfFrame(true);
258 CHECK_NULL_RETURN(parentNode, visibleRect);
259 if (parentNode->GetTag() == V2::PAGE_ETS_TAG) {
260 return visibleRect;
261 }
262 auto intersectRect = visibleRect;
263 auto scrollablePattern = AceType::DynamicCast<NestableScrollContainer>(parentNode->GetPattern());
264 auto geometryNode = parentNode->GetGeometryNode();
265 if (scrollablePattern && geometryNode) {
266 auto parentViewPort = RectF(parentNode->GetTransformRelativeOffset(), geometryNode->GetFrameSize());
267 if (parentViewPort.IsIntersectWith(visibleRect)) {
268 intersectRect = parentViewPort.IntersectRectT(visibleRect);
269 } else {
270 return RectF(0, 0, 0, 0);
271 }
272 }
273 return GetVisibleRect(parentNode, intersectRect);
274 }
275
RemoveSelectionHoldCallback()276 void BaseTextSelectOverlay::RemoveSelectionHoldCallback()
277 {
278 auto overlayManager = SelectContentOverlayManager::GetOverlayManager();
279 CHECK_NULL_VOID(overlayManager);
280 overlayManager->RemoveHoldSelectionCallback(GetOwnerId());
281 }
282
SetSelectionHoldCallback()283 void BaseTextSelectOverlay::SetSelectionHoldCallback()
284 {
285 auto overlayManager = SelectContentOverlayManager::GetOverlayManager();
286 CHECK_NULL_VOID(overlayManager);
287 HoldSelectionInfo selectionInfo;
288 selectionInfo.resetSelectionCallback = [weak = WeakClaim(this)]() {
289 auto overlay = weak.Upgrade();
290 CHECK_NULL_VOID(overlay);
291 overlay->OnResetTextSelection();
292 };
293 selectionInfo.checkTouchInArea = [weak = WeakClaim(this), manager = WeakClaim(AceType::RawPtr(overlayManager))](
294 const PointF& point) {
295 auto baseOverlay = weak.Upgrade();
296 CHECK_NULL_RETURN(baseOverlay, false);
297 auto overlayManager = manager.Upgrade();
298 CHECK_NULL_RETURN(overlayManager, false);
299 auto host = baseOverlay->GetOwner();
300 CHECK_NULL_RETURN(host, false);
301 auto localPoint = point;
302 overlayManager->ConvertPointRelativeToNode(host, localPoint);
303 return baseOverlay->CheckTouchInHostNode(localPoint);
304 };
305 selectionInfo.eventFilter = [weak = WeakClaim(this)](SourceType sourceType, TouchType touchType) {
306 auto overlay = weak.Upgrade();
307 CHECK_NULL_RETURN(overlay, false);
308 return overlay->IsAcceptResetSelectionEvent(sourceType, touchType);
309 };
310 overlayManager->SetHoldSelectionCallback(GetOwnerId(), selectionInfo);
311 }
312
GetVisibleContentRect()313 RectF BaseTextSelectOverlay::GetVisibleContentRect()
314 {
315 RectF visibleContentRect;
316 auto pattern = GetPattern<Pattern>();
317 CHECK_NULL_RETURN(pattern, visibleContentRect);
318 auto host = pattern->GetHost();
319 CHECK_NULL_RETURN(host, visibleContentRect);
320 auto context = host->GetContext();
321 CHECK_NULL_RETURN(context, visibleContentRect);
322 auto geometryNode = host->GetGeometryNode();
323 CHECK_NULL_RETURN(geometryNode, visibleContentRect);
324 auto paintOffset = host->GetTransformRelativeOffset();
325 visibleContentRect = RectF(geometryNode->GetContentOffset() + paintOffset, geometryNode->GetContentSize());
326 if (enableHandleLevel_ && handleLevelMode_ == HandleLevelMode::EMBED) {
327 return visibleContentRect;
328 }
329 return GetVisibleRect(pattern->GetHost(), visibleContentRect);
330 }
331
MergeSelectedBoxes(const std::vector<RectF> & boxes,const RectF & contentRect,const RectF & textRect,const OffsetF & paintOffset)332 RectF BaseTextSelectOverlay::MergeSelectedBoxes(
333 const std::vector<RectF>& boxes, const RectF& contentRect, const RectF& textRect, const OffsetF& paintOffset)
334 {
335 auto frontRect = boxes.front();
336 auto backRect = boxes.back();
337 RectF res;
338 if (GreatNotEqual(backRect.Bottom(), frontRect.Bottom())) {
339 res.SetRect(contentRect.GetX() + paintOffset.GetX(), frontRect.GetY() + textRect.GetY() + paintOffset.GetY(),
340 contentRect.Width(), backRect.Bottom() - frontRect.Top());
341 } else {
342 res.SetRect(frontRect.GetX() + textRect.GetX() + paintOffset.GetX(),
343 frontRect.GetY() + textRect.GetY() + paintOffset.GetY(), backRect.Right() - frontRect.Left(),
344 backRect.Bottom() - frontRect.Top());
345 }
346 return res;
347 }
348
SetTransformPaintInfo(SelectHandleInfo & handleInfo,const RectF & localHandleRect)349 void BaseTextSelectOverlay::SetTransformPaintInfo(SelectHandleInfo& handleInfo, const RectF& localHandleRect)
350 {
351 CHECK_NULL_VOID(hasTransform_);
352 SelectHandlePaintInfo paintInfo;
353 auto left = localHandleRect.Left() + localHandleRect.Width() / 2.0f;
354 std::vector<OffsetF> points = { OffsetF(left, localHandleRect.Top()), OffsetF(left, localHandleRect.Bottom()) };
355 GetGlobalPointsWithTransform(points);
356 paintInfo.startPoint = points[0];
357 paintInfo.endPoint = points[1];
358 paintInfo.width = localHandleRect.Width();
359 handleInfo.paintInfo = paintInfo;
360 handleInfo.paintInfoConverter = [weak = WeakClaim(this)](const SelectHandlePaintInfo& paintInfo) {
361 auto overlay = weak.Upgrade();
362 CHECK_NULL_RETURN(overlay, RectF());
363 return overlay->ConvertPaintInfoToRect(paintInfo);
364 };
365 handleInfo.isPaintHandleWithPoints = true;
366 handleInfo.isShow =
367 CheckHandleIsVisibleWithTransform(paintInfo.startPoint, paintInfo.endPoint, localHandleRect.Width());
368 }
369
CheckHandleIsVisibleWithTransform(const OffsetF & startPoint,const OffsetF & endPoint,float epsilon)370 bool BaseTextSelectOverlay::CheckHandleIsVisibleWithTransform(
371 const OffsetF& startPoint, const OffsetF& endPoint, float epsilon)
372 {
373 auto pattern = GetPattern<Pattern>();
374 CHECK_NULL_RETURN(pattern, true);
375 auto host = pattern->GetHost();
376 CHECK_NULL_RETURN(host, true);
377 auto geometryNode = host->GetGeometryNode();
378 CHECK_NULL_RETURN(geometryNode, true);
379 auto contentRect = geometryNode->GetContentRect();
380 auto rectVertices = GetGlobalRectVertexWithTransform(contentRect, epsilon);
381 auto leftTop = rectVertices[0];
382 auto rightTop = rectVertices[1];
383 auto leftBottom = rectVertices[2];
384 auto rightBottom = rectVertices[3];
385 auto isStartPointInRect = IsPointInRect(startPoint, leftBottom, rightBottom, rightTop, leftTop);
386 auto isEndPointInRect = IsPointInRect(endPoint, leftBottom, rightBottom, rightTop, leftTop);
387 if (isStartPointInRect && isEndPointInRect) {
388 auto visibleContentRect = GetVisibleContentRectWithTransform(epsilon);
389 leftTop = OffsetF(visibleContentRect.Left(), visibleContentRect.Top());
390 rightTop = OffsetF(visibleContentRect.Right(), visibleContentRect.Top());
391 leftBottom = OffsetF(visibleContentRect.Left(), visibleContentRect.Bottom());
392 rightBottom = OffsetF(visibleContentRect.Right(), visibleContentRect.Bottom());
393 isStartPointInRect = IsPointInRect(startPoint, leftBottom, rightBottom, rightTop, leftTop);
394 isEndPointInRect = IsPointInRect(endPoint, leftBottom, rightBottom, rightTop, leftTop);
395 return isStartPointInRect && isEndPointInRect;
396 }
397 return false;
398 }
399
IsPointInRect(const OffsetF & point,const OffsetF & lb,const OffsetF & rb,const OffsetF & rt,const OffsetF & lt)400 bool BaseTextSelectOverlay::IsPointInRect(
401 const OffsetF& point, const OffsetF& lb, const OffsetF& rb, const OffsetF& rt, const OffsetF& lt)
402 {
403 auto crossProduct = [](const OffsetF& point, const OffsetF& point1, const OffsetF& point2) {
404 auto pointStart = OffsetF(point2.GetX() - point1.GetX(), point2.GetY() - point1.GetY());
405 auto pointEnd = OffsetF(point.GetX() - point1.GetX(), point.GetY() - point1.GetY());
406 return pointStart.GetX() * pointEnd.GetY() - pointEnd.GetX() * pointStart.GetY();
407 };
408 auto bottomProduct = crossProduct(point, lb, rb);
409 auto rightProduct = crossProduct(point, rb, rt);
410 auto topProduct = crossProduct(point, rt, lt);
411 auto leftProduct = crossProduct(point, lt, lb);
412 std::vector<float> productVector = { bottomProduct, rightProduct, topProduct, leftProduct };
413 auto minMax = std::minmax_element(productVector.begin(), productVector.end());
414 // 所用向量叉积方向一致(都为正数或者都为负数),表示点在矩形内. 最小值大于0或者最大值小于0.
415 return Positive(*minMax.first) || Negative(* minMax.second);
416 }
417
GetVisibleContentRectWithTransform(float epsilon)418 RectF BaseTextSelectOverlay::GetVisibleContentRectWithTransform(float epsilon)
419 {
420 RectF visibleContentRect;
421 auto pattern = GetPattern<Pattern>();
422 CHECK_NULL_RETURN(pattern, visibleContentRect);
423 auto host = pattern->GetHost();
424 CHECK_NULL_RETURN(host, visibleContentRect);
425 auto context = host->GetContext();
426 CHECK_NULL_RETURN(context, visibleContentRect);
427 auto geometryNode = host->GetGeometryNode();
428 CHECK_NULL_RETURN(geometryNode, visibleContentRect);
429 visibleContentRect = geometryNode->GetContentRect();
430 auto width = visibleContentRect.Width() + 2 * epsilon;
431 auto height = visibleContentRect.Height() + 2 * epsilon;
432 visibleContentRect.SetLeft(visibleContentRect.Left() - epsilon);
433 visibleContentRect.SetTop(visibleContentRect.Top() - epsilon);
434 visibleContentRect.SetWidth(width);
435 visibleContentRect.SetHeight(height);
436 GetGlobalRectWithTransform(visibleContentRect);
437 return GetVisibleRect(pattern->GetHost(), visibleContentRect);
438 }
439
GetGlobalPointsWithTransform(std::vector<OffsetF> & points)440 void BaseTextSelectOverlay::GetGlobalPointsWithTransform(std::vector<OffsetF>& points)
441 {
442 CHECK_NULL_VOID(hasTransform_);
443 auto pattern = GetPattern<Pattern>();
444 CHECK_NULL_VOID(pattern);
445 auto parent = pattern->GetHost();
446 std::vector<PointF> convertPoints;
447 auto pointConverter = [](const OffsetF& offset) { return PointF(offset.GetX(), offset.GetY()); };
448 std::transform(points.begin(), points.end(), std::back_inserter(convertPoints), pointConverter);
449 while (parent) {
450 if (parent->GetTag() == V2::WINDOW_SCENE_ETS_TAG) {
451 break;
452 }
453 auto renderContext = parent->GetRenderContext();
454 CHECK_NULL_VOID(renderContext);
455 auto paintOffset = renderContext->GetPaintRectWithoutTransform().GetOffset();
456 for (auto& pointElement : convertPoints) {
457 pointElement = pointElement + paintOffset;
458 renderContext->GetPointTransform(pointElement);
459 }
460 parent = parent->GetAncestorNodeOfFrame(true);
461 }
462 points.clear();
463 auto offsetConverter = [](const PointF& point) { return OffsetF(point.GetX(), point.GetY()); };
464 std::transform(convertPoints.begin(), convertPoints.end(), std::back_inserter(points), offsetConverter);
465 }
466
GetGlobalRectWithTransform(RectF & localRect)467 void BaseTextSelectOverlay::GetGlobalRectWithTransform(RectF& localRect)
468 {
469 CHECK_NULL_VOID(hasTransform_);
470 auto rectVertex = GetGlobalRectVertexWithTransform(localRect);
471 auto compareOffsetX = [](const OffsetF& offset1, const OffsetF& offset2) {
472 return LessNotEqual(offset1.GetX(), offset2.GetX());
473 };
474 auto minMaxX = std::minmax_element(rectVertex.begin(), rectVertex.end(), compareOffsetX);
475 auto compareOffsetY = [](const OffsetF& offset1, const OffsetF& offset2) {
476 return LessNotEqual(offset1.GetY(), offset2.GetY());
477 };
478 auto minMaxY = std::minmax_element(rectVertex.begin(), rectVertex.end(), compareOffsetY);
479 localRect.SetOffset(OffsetF(minMaxX.first->GetX(), minMaxY.first->GetY()));
480 localRect.SetSize(
481 SizeF(minMaxX.second->GetX() - minMaxX.first->GetX(), minMaxY.second->GetY() - minMaxY.first->GetY()));
482 }
483
GetGlobalRectVertexWithTransform(const RectF & rect,float extendValue)484 std::vector<OffsetF> BaseTextSelectOverlay::GetGlobalRectVertexWithTransform(const RectF& rect, float extendValue)
485 {
486 std::vector<OffsetF> rectVertices = {
487 OffsetF(rect.Left() - extendValue, rect.Top() - extendValue),
488 OffsetF(rect.Right() + extendValue, rect.Top() - extendValue),
489 OffsetF(rect.Left() - extendValue, rect.Bottom() + extendValue),
490 OffsetF(rect.Right() + extendValue, rect.Bottom() + extendValue)
491 };
492 GetGlobalPointsWithTransform(rectVertices);
493 return rectVertices;
494 }
495
GetLocalPointWithTransform(OffsetF & localPoint)496 void BaseTextSelectOverlay::GetLocalPointWithTransform(OffsetF& localPoint)
497 {
498 CHECK_NULL_VOID(hasTransform_);
499 std::vector<OffsetF> points = { localPoint };
500 GetLocalPointsWithTransform(points);
501 localPoint = points[0];
502 }
503
GetLocalPointsWithTransform(std::vector<OffsetF> & localPoints)504 void BaseTextSelectOverlay::GetLocalPointsWithTransform(std::vector<OffsetF>& localPoints)
505 {
506 CHECK_NULL_VOID(hasTransform_);
507 auto textPaintOffset = GetPaintRectOffsetWithTransform();
508 GetGlobalPointsWithTransform(localPoints);
509 for (auto& pointElement : localPoints) {
510 pointElement = pointElement - textPaintOffset;
511 }
512 }
513
GetPaintRectWithTransform()514 RectF BaseTextSelectOverlay::GetPaintRectWithTransform()
515 {
516 auto pattern = GetPattern<Pattern>();
517 CHECK_NULL_RETURN(pattern, RectF());
518 auto host = pattern->GetHost();
519 CHECK_NULL_RETURN(host, RectF());
520 auto geometryNode = host->GetGeometryNode();
521 CHECK_NULL_RETURN(geometryNode, RectF());
522 auto globalFrameRect = RectF(OffsetF(0.0f, 0.0f), geometryNode->GetFrameSize());
523 GetGlobalRectWithTransform(globalFrameRect);
524 return globalFrameRect;
525 }
526
GetPaintRectOffsetWithTransform()527 OffsetF BaseTextSelectOverlay::GetPaintRectOffsetWithTransform()
528 {
529 auto pipeline = PipelineContext::GetCurrentContextSafely();
530 CHECK_NULL_RETURN(pipeline, OffsetF(0.0f, 0.0f));
531 auto globalFrameRect = GetPaintRectWithTransform();
532 return globalFrameRect.GetOffset() - pipeline->GetRootRect().GetOffset();
533 }
534
GetLocalRectWithTransform(RectF & rect)535 void BaseTextSelectOverlay::GetLocalRectWithTransform(RectF& rect)
536 {
537 CHECK_NULL_VOID(hasTransform_);
538 std::vector<OffsetF> localRectVertices = {
539 OffsetF(rect.Left(), rect.Top()),
540 OffsetF(rect.Right(), rect.Top()),
541 OffsetF(rect.Left(), rect.Bottom()),
542 OffsetF(rect.Right(), rect.Bottom())
543 };
544 GetLocalPointsWithTransform(localRectVertices);
545 auto compareOffsetX = [](const OffsetF& offset1, const OffsetF& offset2) {
546 return LessNotEqual(offset1.GetX(), offset2.GetX());
547 };
548 auto minMaxX = std::minmax_element(localRectVertices.begin(), localRectVertices.end(), compareOffsetX);
549 auto compareOffsetY = [](const OffsetF& offset1, const OffsetF& offset2) {
550 return LessNotEqual(offset1.GetY(), offset2.GetY());
551 };
552 auto minMaxY = std::minmax_element(localRectVertices.begin(), localRectVertices.end(), compareOffsetY);
553 rect.SetOffset(OffsetF(minMaxX.first->GetX(), minMaxY.first->GetY()));
554 rect.SetSize(SizeF(minMaxX.second->GetX() - minMaxX.first->GetX(), minMaxY.second->GetY() - minMaxY.first->GetY()));
555 }
556
RevertLocalPointWithTransform(OffsetF & point)557 void BaseTextSelectOverlay::RevertLocalPointWithTransform(OffsetF& point)
558 {
559 CHECK_NULL_VOID(hasTransform_);
560 auto pattern = GetPattern<Pattern>();
561 CHECK_NULL_VOID(pattern);
562 auto parent = pattern->GetHost();
563 CHECK_NULL_VOID(parent);
564 std::stack<RefPtr<FrameNode>> nodeStack;
565 while (parent) {
566 nodeStack.push(parent);
567 parent = parent->GetAncestorNodeOfFrame(true);
568 }
569 CHECK_NULL_VOID(!nodeStack.empty());
570 PointF localPoint(point.GetX(), point.GetY());
571 while (!nodeStack.empty()) {
572 parent = nodeStack.top();
573 CHECK_NULL_VOID(parent);
574 nodeStack.pop();
575 auto renderContext = parent->GetRenderContext();
576 CHECK_NULL_VOID(renderContext);
577 renderContext->GetPointWithRevert(localPoint);
578 auto rectOffset = renderContext->GetPaintRectWithoutTransform().GetOffset();
579 localPoint = localPoint - rectOffset;
580 }
581 point.SetX(localPoint.GetX());
582 point.SetY(localPoint.GetY());
583 }
584
ConvertPaintInfoToRect(const SelectHandlePaintInfo & paintInfo)585 RectF BaseTextSelectOverlay::ConvertPaintInfoToRect(const SelectHandlePaintInfo& paintInfo)
586 {
587 auto topOffset = paintInfo.startPoint;
588 RevertLocalPointWithTransform(topOffset);
589 auto bottomOffset = paintInfo.endPoint;
590 RevertLocalPointWithTransform(bottomOffset);
591 auto offset = topOffset + GetPaintOffsetWithoutTransform();
592 auto size = SizeF(paintInfo.width, bottomOffset.GetY() - topOffset.GetY());
593 return RectF(offset, size);
594 }
595
GetPaintOffsetWithoutTransform()596 OffsetF BaseTextSelectOverlay::GetPaintOffsetWithoutTransform()
597 {
598 auto pattern = GetPattern<Pattern>();
599 CHECK_NULL_RETURN(pattern, OffsetF());
600 OffsetF offset;
601 auto parent = pattern->GetHost();
602 if (!hasTransform_) {
603 return parent->GetTransformRelativeOffset();
604 }
605 while (parent) {
606 auto renderContext = parent->GetRenderContext();
607 CHECK_NULL_RETURN(renderContext, OffsetF());
608 offset += renderContext->GetPaintRectWithoutTransform().GetOffset();
609 parent = parent->GetAncestorNodeOfFrame(true);
610 }
611 return offset;
612 }
613
UpdateTransformFlag()614 void BaseTextSelectOverlay::UpdateTransformFlag()
615 {
616 auto pattern = GetPattern<Pattern>();
617 CHECK_NULL_VOID(pattern);
618 auto host = pattern->GetHost();
619 CHECK_NULL_VOID(host);
620 auto hasTransform = false;
621 while (host) {
622 auto renderContext = host->GetRenderContext();
623 CHECK_NULL_VOID(renderContext);
624 if (host->GetTag() == V2::WINDOW_SCENE_ETS_TAG) {
625 break;
626 }
627 if (!hasTransform) {
628 auto noTransformRect = renderContext->GetPaintRectWithoutTransform();
629 auto transformRect = renderContext->GetPaintRectWithTransform();
630 hasTransform = noTransformRect != transformRect;
631 }
632 host = host->GetAncestorNodeOfFrame(true);
633 }
634 hasTransform_ = hasTransform;
635 }
636
GetAncestorNodeViewPort()637 std::optional<RectF> BaseTextSelectOverlay::GetAncestorNodeViewPort()
638 {
639 if (IsClipHandleWithViewPort()) {
640 RectF viewPort;
641 if (GetClipHandleViewPort(viewPort)) {
642 return viewPort;
643 }
644 }
645 auto pattern = GetPattern<Pattern>();
646 CHECK_NULL_RETURN(pattern, std::nullopt);
647 auto host = pattern->GetHost();
648 CHECK_NULL_RETURN(host, std::nullopt);
649 auto parent = host->GetAncestorNodeOfFrame(true);
650 while (parent) {
651 auto scrollableContainer = parent->GetPattern<NestableScrollContainer>();
652 if (scrollableContainer) {
653 return parent->GetTransformRectRelativeToWindow();
654 }
655 parent = parent->GetAncestorNodeOfFrame(true);
656 }
657 return std::nullopt;
658 }
659
IsAcceptResetSelectionEvent(SourceType sourceType,TouchType touchType)660 bool BaseTextSelectOverlay::IsAcceptResetSelectionEvent(SourceType sourceType, TouchType touchType)
661 {
662 return (sourceType == SourceType::MOUSE || sourceType == SourceType::TOUCH) && touchType == TouchType::DOWN;
663 }
664
GetHandleDiameter()665 float BaseTextSelectOverlay::GetHandleDiameter()
666 {
667 auto overlayManager = SelectContentOverlayManager::GetOverlayManager();
668 CHECK_NULL_RETURN(overlayManager, 0.0f);
669 return overlayManager->GetHandleDiameter();
670 }
671
SwitchToOverlayMode()672 void BaseTextSelectOverlay::SwitchToOverlayMode()
673 {
674 if (HasUnsupportedTransform()) {
675 return;
676 }
677 auto manager = GetManager<SelectContentOverlayManager>();
678 CHECK_NULL_VOID(manager);
679 handleLevelMode_ = HandleLevelMode::OVERLAY;
680 manager->SwitchToHandleMode(handleLevelMode_);
681 }
682
SwitchToEmbedMode()683 void BaseTextSelectOverlay::SwitchToEmbedMode()
684 {
685 CHECK_NULL_VOID(!isHandleMoving_);
686 auto manager = GetManager<SelectContentOverlayManager>();
687 CHECK_NULL_VOID(manager);
688 handleLevelMode_ = HandleLevelMode::EMBED;
689 manager->SwitchToHandleMode(handleLevelMode_);
690 }
691
GetHostScale()692 VectorF BaseTextSelectOverlay::GetHostScale()
693 {
694 auto pattern = GetPattern<Pattern>();
695 auto unitScale = VectorF(1, 1);
696 CHECK_NULL_RETURN(pattern, unitScale);
697 auto host = pattern->GetHost();
698 CHECK_NULL_RETURN(host, unitScale);
699 auto scaleX = 1.0f;
700 auto scaleY = 1.0f;
701 while (host && host->GetTag() != V2::WINDOW_SCENE_ETS_TAG) {
702 auto renderContext = host->GetRenderContext();
703 CHECK_NULL_RETURN(renderContext, unitScale);
704 auto scale = renderContext->GetTransformScaleValue(unitScale);
705 scaleX *= std::abs(scale.x);
706 scaleY *= std::abs(scale.y);
707 auto transformMatrix = renderContext->GetTransformMatrix();
708 if (transformMatrix.has_value()) {
709 DecomposedTransform transform;
710 TransformUtil::DecomposeTransform(transform, transformMatrix.value());
711 scaleX *= std::abs(transform.scale[0]);
712 scaleY *= std::abs(transform.scale[1]);
713 }
714 host = host->GetAncestorNodeOfFrame(true);
715 }
716 return VectorF(1.0f / scaleX, 1.0f / scaleY);
717 }
718
OnCloseOverlay(OptionMenuType menuType,CloseReason reason,RefPtr<OverlayInfo> info)719 void BaseTextSelectOverlay::OnCloseOverlay(OptionMenuType menuType, CloseReason reason, RefPtr<OverlayInfo> info)
720 {
721 isHandleDragging_ = false;
722 originalMenuIsShow_ = false;
723 if (enableHandleLevel_) {
724 auto host = GetOwner();
725 CHECK_NULL_VOID(host);
726 host->UnregisterNodeChangeListener();
727 }
728 }
729
SetHandleLevelMode(HandleLevelMode mode)730 void BaseTextSelectOverlay::SetHandleLevelMode(HandleLevelMode mode)
731 {
732 if (handleLevelMode_ == mode) {
733 return;
734 }
735 handleLevelMode_ = mode;
736 }
737
GetFirstHandleLocalPaintRect()738 RectF BaseTextSelectOverlay::GetFirstHandleLocalPaintRect()
739 {
740 return RectF();
741 }
742
GetSecondHandleLocalPaintRect()743 RectF BaseTextSelectOverlay::GetSecondHandleLocalPaintRect()
744 {
745 return RectF();
746 }
747
IsPointsInRegion(const std::vector<PointF> & points,const RectF & regionRect)748 bool BaseTextSelectOverlay::IsPointsInRegion(const std::vector<PointF>& points, const RectF& regionRect)
749 {
750 for (const auto& point : points) {
751 if (!regionRect.IsInRegion(point)) {
752 return false;
753 }
754 }
755 return true;
756 }
757
GetHandlePoints(const RectF & handleRect,std::vector<PointF> & points,bool handleOnTop)758 void BaseTextSelectOverlay::GetHandlePoints(const RectF& handleRect, std::vector<PointF>& points, bool handleOnTop)
759 {
760 auto diameter = GetHandleDiameter();
761 auto handlePaintRect = handleRect;
762 auto offsetX = handlePaintRect.Left() + (handlePaintRect.Width() - diameter) / 2.0f;
763 auto offsetY = handleOnTop ? handlePaintRect.Top() - diameter : handlePaintRect.Bottom();
764 handlePaintRect.SetOffset(OffsetF(offsetX, offsetY));
765 handlePaintRect.SetSize(SizeF(diameter, diameter));
766 points.push_back(PointF(handlePaintRect.Left(), handlePaintRect.Top()));
767 points.push_back(PointF(handlePaintRect.Right(), handlePaintRect.Top()));
768 points.push_back(PointF(handlePaintRect.Left(), handlePaintRect.Bottom()));
769 points.push_back(PointF(handlePaintRect.Right(), handlePaintRect.Bottom()));
770 }
771
CheckHandleCanPaintInHost(const RectF & firstRect,const RectF & secondRect)772 bool BaseTextSelectOverlay::CheckHandleCanPaintInHost(const RectF& firstRect, const RectF& secondRect)
773 {
774 if (isChangeToOverlayModeAtEdge_) {
775 return false;
776 }
777 std::vector<PointF> firstPoints;
778 GetHandlePoints(firstRect, firstPoints, false);
779 std::vector<PointF> secondPoints;
780 GetHandlePoints(secondRect, secondPoints, false);
781 auto host = GetOwner();
782 CHECK_NULL_RETURN(host, false);
783 auto parent = host;
784 while (parent) {
785 CHECK_NULL_RETURN(parent->GetGeometryNode(), false);
786 auto parentRect = RectF();
787 parentRect.SetSize(parent->GetGeometryNode()->GetFrameSize());
788 if (IsPointsInRegion(firstPoints, parentRect) && IsPointsInRegion(secondPoints, parentRect)) {
789 return true;
790 }
791 auto renderContext = parent->GetRenderContext();
792 CHECK_NULL_RETURN(renderContext, false);
793 auto isClip = renderContext->GetClipEdge().value_or(false);
794 if (isClip) {
795 break;
796 }
797 auto paintOffset = renderContext->GetPaintRectWithoutTransform().GetOffset();
798 for (auto& point : firstPoints) {
799 point = point + paintOffset;
800 renderContext->GetPointTransform(point);
801 }
802 for (auto& point : secondPoints) {
803 point = point + paintOffset;
804 renderContext->GetPointTransform(point);
805 }
806 parent = parent->GetAncestorNodeOfFrame(true);
807 }
808 return false;
809 }
810
CalcHandleLevelMode(const RectF & firstLocalPaintRect,const RectF & secondLocalPaintRect)811 void BaseTextSelectOverlay::CalcHandleLevelMode(const RectF& firstLocalPaintRect, const RectF& secondLocalPaintRect)
812 {
813 if (CheckHandleCanPaintInHost(firstLocalPaintRect, secondLocalPaintRect) || HasUnsupportedTransform()) {
814 SetHandleLevelMode(HandleLevelMode::EMBED);
815 } else {
816 SetHandleLevelMode(HandleLevelMode::OVERLAY);
817 }
818 }
819
OnAncestorNodeChanged(FrameNodeChangeInfoFlag flag)820 void BaseTextSelectOverlay::OnAncestorNodeChanged(FrameNodeChangeInfoFlag flag)
821 {
822 auto isStartScroll = IsAncestorNodeStartScroll(flag);
823 auto isStartAnimation = IsAncestorNodeStartAnimation(flag);
824 auto isTransformChanged = IsAncestorNodeTransformChange(flag);
825 auto isStartTransition = IsAncestorNodeHasTransition(flag);
826 auto isSwitchToEmbed = isStartScroll || isStartAnimation || isTransformChanged || isStartTransition;
827 // parent size changes but the child does not change.
828 if (IsAncestorNodeGeometryChange(flag)) {
829 isSwitchToEmbed = isSwitchToEmbed || CheckAndUpdateHostGlobalPaintRect();
830 }
831 auto isScrollEnd = IsAncestorNodeEndScroll(flag);
832 isSwitchToEmbed = isSwitchToEmbed && (!isScrollEnd || HasUnsupportedTransform());
833 UpdateMenuWhileAncestorNodeChanged(
834 isStartScroll || isStartAnimation || isTransformChanged || isStartTransition, isScrollEnd);
835 auto pipeline = PipelineContext::GetCurrentContextSafely();
836 CHECK_NULL_VOID(pipeline);
837 pipeline->AddAfterRenderTask([weak = WeakClaim(this), isSwitchToEmbed, isScrollEnd]() {
838 auto overlay = weak.Upgrade();
839 CHECK_NULL_VOID(overlay);
840 if (isScrollEnd) {
841 overlay->SwitchToOverlayMode();
842 return;
843 }
844 if (isSwitchToEmbed) {
845 overlay->SwitchToEmbedMode();
846 }
847 });
848 }
849
UpdateMenuWhileAncestorNodeChanged(bool shouldHideMenu,bool shouldShowMenu)850 void BaseTextSelectOverlay::UpdateMenuWhileAncestorNodeChanged(bool shouldHideMenu, bool shouldShowMenu)
851 {
852 auto manager = GetManager<SelectContentOverlayManager>();
853 CHECK_NULL_VOID(manager);
854 if (shouldHideMenu) {
855 manager->HideOptionMenu(true);
856 return;
857 }
858 if (shouldShowMenu && originalMenuIsShow_ && !GetIsHandleDragging() && !GetSelectArea().IsEmpty()) {
859 manager->ShowOptionMenu();
860 }
861 }
862
IsAncestorNodeStartAnimation(FrameNodeChangeInfoFlag flag)863 bool BaseTextSelectOverlay::IsAncestorNodeStartAnimation(FrameNodeChangeInfoFlag flag)
864 {
865 return ((flag & FRAME_NODE_CHANGE_START_ANIMATION) == FRAME_NODE_CHANGE_START_ANIMATION);
866 }
867
IsAncestorNodeGeometryChange(FrameNodeChangeInfoFlag flag)868 bool BaseTextSelectOverlay::IsAncestorNodeGeometryChange(FrameNodeChangeInfoFlag flag)
869 {
870 return ((flag & FRAME_NODE_CHANGE_GEOMETRY_CHANGE) == FRAME_NODE_CHANGE_GEOMETRY_CHANGE);
871 }
872
IsAncestorNodeStartScroll(FrameNodeChangeInfoFlag flag)873 bool BaseTextSelectOverlay::IsAncestorNodeStartScroll(FrameNodeChangeInfoFlag flag)
874 {
875 return ((flag & FRAME_NODE_CHANGE_START_SCROLL) == FRAME_NODE_CHANGE_START_SCROLL);
876 }
877
IsAncestorNodeEndScroll(FrameNodeChangeInfoFlag flag)878 bool BaseTextSelectOverlay::IsAncestorNodeEndScroll(FrameNodeChangeInfoFlag flag)
879 {
880 return ((flag & FRAME_NODE_CHANGE_END_SCROLL) == FRAME_NODE_CHANGE_END_SCROLL);
881 }
882
IsAncestorNodeTransformChange(FrameNodeChangeInfoFlag flag)883 bool BaseTextSelectOverlay::IsAncestorNodeTransformChange(FrameNodeChangeInfoFlag flag)
884 {
885 return ((flag & FRAME_NODE_CHANGE_TRANSFORM_CHANGE) == FRAME_NODE_CHANGE_TRANSFORM_CHANGE);
886 }
887
IsAncestorNodeHasTransition(FrameNodeChangeInfoFlag flag)888 bool BaseTextSelectOverlay::IsAncestorNodeHasTransition(FrameNodeChangeInfoFlag flag)
889 {
890 return ((flag & FRAME_NODE_CHANGE_TRANSITION_START) == FRAME_NODE_CHANGE_TRANSITION_START);
891 }
892
IsTouchAtHandle(const TouchEventInfo & info)893 bool BaseTextSelectOverlay::IsTouchAtHandle(const TouchEventInfo& info)
894 {
895 auto overlayManager = GetManager<SelectContentOverlayManager>();
896 CHECK_NULL_RETURN(overlayManager, false);
897 CHECK_NULL_RETURN(!info.GetTouches().empty(), false);
898 auto touchType = info.GetTouches().front().GetTouchType();
899 if (touchType == TouchType::DOWN) {
900 auto localOffset = info.GetTouches().front().GetLocalLocation();
901 auto globalOffset = info.GetTouches().front().GetGlobalLocation();
902 touchAtHandle_ = overlayManager->IsTouchAtHandle(
903 PointF(localOffset.GetX(), localOffset.GetY()), PointF(globalOffset.GetX(), globalOffset.GetY()));
904 } else if (touchType == TouchType::UP) {
905 if (touchAtHandle_) {
906 touchAtHandle_ = false;
907 return true;
908 }
909 }
910 return touchAtHandle_;
911 }
912
IsClickAtHandle(const GestureEvent & info)913 bool BaseTextSelectOverlay::IsClickAtHandle(const GestureEvent& info)
914 {
915 auto overlayManager = GetManager<SelectContentOverlayManager>();
916 CHECK_NULL_RETURN(overlayManager, false);
917 auto localOffset = info.GetLocalLocation();
918 auto globalOffset = info.GetGlobalLocation();
919 return overlayManager->IsTouchAtHandle(
920 PointF(localOffset.GetX(), localOffset.GetY()), PointF(globalOffset.GetX(), globalOffset.GetY()));
921 }
922
HasUnsupportedTransform()923 bool BaseTextSelectOverlay::HasUnsupportedTransform()
924 {
925 auto pattern = GetPattern<Pattern>();
926 CHECK_NULL_RETURN(pattern, false);
927 auto parent = pattern->GetHost();
928 CHECK_NULL_RETURN(parent, false);
929 const int32_t zTranslateIndex = 2;
930 while (parent) {
931 auto renderContext = parent->GetRenderContext();
932 CHECK_NULL_RETURN(renderContext, false);
933 if (parent->GetTag() == V2::WINDOW_SCENE_ETS_TAG) {
934 return false;
935 }
936 if (renderContext->HasMotionPath()) {
937 return true;
938 }
939 auto rotateVector = renderContext->GetTransformRotate();
940 if (rotateVector.has_value() && !NearZero(rotateVector->w) &&
941 !(NearZero(rotateVector->x) && NearZero(rotateVector->y))) {
942 return true;
943 }
944 auto transformMatrix = renderContext->GetTransformMatrix();
945 if (transformMatrix) {
946 DecomposedTransform transform;
947 TransformUtil::DecomposeTransform(transform, transformMatrix.value());
948 Quaternion identity(0.0f, 0.0f, 0.0f, 1.0f);
949 if (transform.quaternion != identity || !NearZero(transform.translate[zTranslateIndex])) {
950 return true;
951 }
952 }
953 auto translate = renderContext->GetTransformTranslate();
954 if (translate && !NearZero(translate->z.Value())) {
955 return true;
956 }
957 parent = parent->GetAncestorNodeOfFrame(true);
958 }
959 return false;
960 }
961
CheckSwitchToMode(HandleLevelMode mode)962 bool BaseTextSelectOverlay::CheckSwitchToMode(HandleLevelMode mode)
963 {
964 if (mode == HandleLevelMode::OVERLAY && HasUnsupportedTransform()) {
965 return false;
966 }
967 return true;
968 }
969
OnSelectionMenuOptionsUpdate(const NG::OnCreateMenuCallback && onCreateMenuCallback,const NG::OnMenuItemClickCallback && onMenuItemClick)970 void BaseTextSelectOverlay::OnSelectionMenuOptionsUpdate(
971 const NG::OnCreateMenuCallback&& onCreateMenuCallback, const NG::OnMenuItemClickCallback&& onMenuItemClick)
972 {
973 onCreateMenuCallback_ = onCreateMenuCallback;
974 onMenuItemClick_ = onMenuItemClick;
975 }
976
RegisterScrollingListener(const RefPtr<FrameNode> scrollableNode)977 void BaseTextSelectOverlay::RegisterScrollingListener(const RefPtr<FrameNode> scrollableNode)
978 {
979 if (hasRegisterListener_) {
980 return;
981 }
982 auto scrollingNode = scrollableNode;
983 if (!scrollingNode) {
984 auto host = GetOwner();
985 CHECK_NULL_VOID(host);
986 scrollingNode = host->GetAncestorNodeOfFrame(true);
987 while (scrollingNode) {
988 if (scrollingNode->GetTag() == V2::SWIPER_ETS_TAG) {
989 break;
990 }
991 scrollingNode = scrollingNode->GetAncestorNodeOfFrame(true);
992 }
993 }
994 if (scrollingNode) {
995 auto pattern = scrollingNode->GetPattern<Pattern>();
996 CHECK_NULL_VOID(pattern);
997 auto scrollCallback = [weak = WeakClaim(this), scrollNode = WeakClaim(AceType::RawPtr(scrollableNode))] {
998 auto overlay = weak.Upgrade();
999 CHECK_NULL_VOID(overlay);
1000 overlay->OnHandleScrolling(scrollNode);
1001 };
1002 auto scrollListener = AceType::MakeRefPtr<ScrollingListener>(scrollCallback);
1003 pattern->RegisterScrollingListener(scrollListener);
1004 hasRegisterListener_ = true;
1005 }
1006 }
1007
OnHandleScrolling(const WeakPtr<FrameNode> & scrollingNode)1008 void BaseTextSelectOverlay::OnHandleScrolling(const WeakPtr<FrameNode>& scrollingNode)
1009 {
1010 if (SelectOverlayIsOn()) {
1011 HideMenu(true);
1012 auto taskExecutor = Container::CurrentTaskExecutor();
1013 taskExecutor->PostTask(
1014 [weak = WeakClaim(this), scrollingNode] {
1015 auto overlay = weak.Upgrade();
1016 CHECK_NULL_VOID(overlay);
1017 overlay->hasRegisterListener_ = false;
1018 if (overlay->SelectOverlayIsOn()) {
1019 overlay->RegisterScrollingListener(scrollingNode.Upgrade());
1020 }
1021 },
1022 TaskExecutor::TaskType::UI, "RegisterScrollingListener");
1023 } else {
1024 hasRegisterListener_ = false;
1025 }
1026 }
1027
CheckAndUpdateHostGlobalPaintRect()1028 bool BaseTextSelectOverlay::CheckAndUpdateHostGlobalPaintRect()
1029 {
1030 auto host = GetOwner();
1031 CHECK_NULL_RETURN(host, false);
1032 auto geometryNode = host->GetGeometryNode();
1033 CHECK_NULL_RETURN(geometryNode, false);
1034 auto framePaintRect = RectF(host->GetTransformRelativeOffset(), geometryNode->GetFrameSize());
1035 auto changed = globalPaintRect_ != framePaintRect;
1036 globalPaintRect_ = framePaintRect;
1037 return changed;
1038 }
1039
CheckHasTransformAttr()1040 bool BaseTextSelectOverlay::CheckHasTransformAttr()
1041 {
1042 auto pattern = GetPattern<Pattern>();
1043 CHECK_NULL_RETURN(pattern, false);
1044 auto host = pattern->GetHost();
1045 CHECK_NULL_RETURN(host, false);
1046 auto hasTransform = false;
1047 VectorF scaleIdentity(1.0f, 1.0f);
1048 Vector5F rotateIdentity(0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
1049 while (host) {
1050 auto renderContext = host->GetRenderContext();
1051 CHECK_NULL_RETURN(renderContext, false);
1052 if (host->GetTag() == V2::WINDOW_SCENE_ETS_TAG) {
1053 break;
1054 }
1055 if (renderContext->HasMotionPath()) {
1056 hasTransform = true;
1057 break;
1058 }
1059 // has rotate.
1060 auto rotateVector = renderContext->GetTransformRotate();
1061 if (rotateVector.has_value() && !(rotateIdentity == rotateVector.value())) {
1062 hasTransform = true;
1063 break;
1064 }
1065 // has scale.
1066 auto scaleVector = renderContext->GetTransformScale();
1067 if (scaleVector.has_value() && !(scaleIdentity == scaleVector.value())) {
1068 hasTransform = true;
1069 break;
1070 }
1071 // has z translate.
1072 auto translate = renderContext->GetTransformTranslate();
1073 if (translate && !NearZero(translate->z.Value())) {
1074 hasTransform = true;
1075 break;
1076 }
1077 if (CheckHasTransformMatrix(renderContext)) {
1078 hasTransform = true;
1079 break;
1080 }
1081 host = host->GetAncestorNodeOfFrame(true);
1082 }
1083 return hasTransform;
1084 }
1085
CheckHasTransformMatrix(const RefPtr<RenderContext> & context)1086 bool BaseTextSelectOverlay::CheckHasTransformMatrix(const RefPtr<RenderContext>& context)
1087 {
1088 auto transformMatrix = context->GetTransformMatrix();
1089 CHECK_NULL_RETURN(transformMatrix, false);
1090 const int32_t xIndex = 0;
1091 const int32_t yIndex = 1;
1092 const int32_t zIndex = 2;
1093 const int32_t wIndex = 3;
1094 DecomposedTransform transform;
1095 TransformUtil::DecomposeTransform(transform, transformMatrix.value());
1096 if (!NearZero(transform.translate[zIndex])) {
1097 return true;
1098 }
1099 Quaternion quaternionIdentity(0.0f, 0.0f, 0.0f, 1.0f);
1100 if (transform.quaternion != quaternionIdentity) {
1101 return true;
1102 }
1103 Vector3F scaleIdentity(1.0f, 1.0f, 1.0f);
1104 Vector3F scaleVector(transform.scale[xIndex], transform.scale[yIndex], transform.scale[zIndex]);
1105 if (!(scaleVector == scaleIdentity)) {
1106 return true;
1107 }
1108 Vector3F skewIdentity(0.0f, 0.0f, 0.0f);
1109 Vector3F skewVector(transform.skew[xIndex], transform.skew[yIndex], transform.skew[zIndex]);
1110 if (!(skewVector == skewIdentity)) {
1111 return true;
1112 }
1113 Vector4F perspectiveIdentity(0.0f, 0.0f, 0.0f, 1.0f);
1114 Vector4F perspectiveVector(transform.perspective[xIndex], transform.perspective[yIndex],
1115 transform.perspective[zIndex], transform.perspective[wIndex]);
1116 return !(perspectiveVector == perspectiveIdentity);
1117 }
1118
GetClipHandleViewPort(RectF & rect)1119 bool BaseTextSelectOverlay::GetClipHandleViewPort(RectF& rect)
1120 {
1121 auto host = GetOwner();
1122 CHECK_NULL_RETURN(host, false);
1123 if (HasUnsupportedTransform()) {
1124 return false;
1125 }
1126 RectF contentRect;
1127 if (!GetFrameNodeContentRect(host, contentRect)) {
1128 return false;
1129 }
1130 contentRect.SetOffset(contentRect.GetOffset() + host->GetPaintRectWithTransform().GetOffset());
1131 auto parent = host->GetAncestorNodeOfFrame(true);
1132 while (parent) {
1133 RectF parentContentRect;
1134 if (!GetFrameNodeContentRect(parent, parentContentRect)) {
1135 return false;
1136 }
1137 auto renderContext = parent->GetRenderContext();
1138 CHECK_NULL_RETURN(renderContext, false);
1139 if (renderContext->GetClipEdge().value_or(false)) {
1140 contentRect = contentRect.IntersectRectT(parentContentRect);
1141 }
1142 contentRect.SetOffset(contentRect.GetOffset() + parent->GetPaintRectWithTransform().GetOffset());
1143 parent = parent->GetAncestorNodeOfFrame(true);
1144 }
1145 contentRect.SetWidth(std::max(contentRect.Width(), 0.0f));
1146 contentRect.SetHeight(std::max(contentRect.Height(), 0.0f));
1147 UpdateClipHandleViewPort(contentRect);
1148 rect = contentRect;
1149 return true;
1150 }
1151
GetFrameNodeContentRect(const RefPtr<FrameNode> & node,RectF & contentRect)1152 bool BaseTextSelectOverlay::GetFrameNodeContentRect(const RefPtr<FrameNode>& node, RectF& contentRect)
1153 {
1154 CHECK_NULL_RETURN(node, false);
1155 auto geometryNode = node->GetGeometryNode();
1156 CHECK_NULL_RETURN(geometryNode, false);
1157 auto renderContext = node->GetRenderContext();
1158 CHECK_NULL_RETURN(renderContext, false);
1159 if (geometryNode->GetContent()) {
1160 contentRect = geometryNode->GetContentRect();
1161 } else {
1162 contentRect = RectF(OffsetF(0.0f, 0.0f), geometryNode->GetFrameSize());
1163 }
1164 return true;
1165 }
1166
MarkOverlayDirty()1167 void BaseTextSelectOverlay::MarkOverlayDirty()
1168 {
1169 if (SelectOverlayIsOn()) {
1170 auto host = GetOwner();
1171 CHECK_NULL_VOID(host);
1172 auto overlayNode = host->GetOverlayNode();
1173 CHECK_NULL_VOID(overlayNode);
1174 overlayNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1175 }
1176 }
1177
ApplySelectAreaWithKeyboard(RectF & selectArea)1178 void BaseTextSelectOverlay::ApplySelectAreaWithKeyboard(RectF& selectArea)
1179 {
1180 auto host = GetOwner();
1181 CHECK_NULL_VOID(host);
1182 auto pipeline = host->GetContext();
1183 CHECK_NULL_VOID(pipeline);
1184 auto safeAreaManager = pipeline->GetSafeAreaManager();
1185 CHECK_NULL_VOID(safeAreaManager);
1186 auto keyboardInset = safeAreaManager->GetKeyboardInset();
1187 if (keyboardInset.Length() <= 0) {
1188 return;
1189 }
1190 if (GreatOrEqual(selectArea.Top(), keyboardInset.start)) {
1191 selectArea.SetHeight(0.0f);
1192 }
1193 }
1194
OnHandleMarkInfoChange(const std::shared_ptr<SelectOverlayInfo> info,SelectOverlayDirtyFlag flag)1195 void BaseTextSelectOverlay::OnHandleMarkInfoChange(
1196 const std::shared_ptr<SelectOverlayInfo> info, SelectOverlayDirtyFlag flag)
1197 {
1198 auto manager = GetManager<SelectContentOverlayManager>();
1199 CHECK_NULL_VOID(manager);
1200 if ((flag & DIRTY_HANDLE_COLOR_FLAG) == DIRTY_HANDLE_COLOR_FLAG) {
1201 info->handlerColor = GetHandleColor();
1202 manager->MarkHandleDirtyNode(PROPERTY_UPDATE_RENDER);
1203 }
1204 }
1205
UpdateHandleColor()1206 void BaseTextSelectOverlay::UpdateHandleColor()
1207 {
1208 auto manager = GetManager<SelectContentOverlayManager>();
1209 CHECK_NULL_VOID(manager);
1210 manager->MarkInfoChange(DIRTY_HANDLE_COLOR_FLAG);
1211 }
1212 } // namespace OHOS::Ace::NG
1213