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