1 /*
2 * Copyright (c) 2021-2022 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/text/render_text.h"
17
18 #include "base/geometry/size.h"
19 #include "base/log/dump_log.h"
20 #include "core/common/ace_engine_ext.h"
21 #include "core/common/clipboard/clipboard_proxy.h"
22 #include "core/common/font_manager.h"
23 #include "core/components/container_modal/container_modal_constants.h"
24 #include "core/components/gesture_listener/gesture_listener_component.h"
25 #include "core/components/text/text_component.h"
26 #include "core/components/text_field/render_text_field.h"
27 #include "core/components/text_overlay/text_overlay_component.h"
28 #include "core/components_v2/inspector/utils.h"
29 #include "core/event/ace_event_helper.h"
30 #include "core/event/ace_events.h"
31
32 namespace OHOS::Ace {
33
34 namespace {
35 constexpr Dimension CURSOR_WIDTH = 1.5_vp;
36 constexpr double HANDLE_HOT_ZONE = 10.0;
37 } // namespace
38
~RenderText()39 RenderText::~RenderText()
40 {
41 auto context = context_.Upgrade();
42 if (context) {
43 context->RemoveFontNode(AceType::WeakClaim(this));
44 auto fontManager = context->GetFontManager();
45 if (fontManager) {
46 fontManager->UnRegisterCallback(AceType::WeakClaim(this));
47 fontManager->RemoveVariationNode(WeakClaim(this));
48 }
49 }
50
51 auto textOverlayManager = GetTextOverlayManager(context_);
52 if (textOverlayManager) {
53 auto textOverlayBase = textOverlayManager->GetTextOverlayBase();
54 if (textOverlayBase) {
55 auto targetNode = textOverlayManager->GetTargetNode();
56 if (targetNode == this) {
57 textOverlayManager->PopTextOverlay();
58 textOverlayBase->ChangeSelection(0, 0);
59 textOverlayBase->MarkIsOverlayShowed(false);
60 targetNode->MarkNeedRender();
61 }
62 }
63 }
64 }
65
Update(const RefPtr<Component> & component)66 void RenderText::Update(const RefPtr<Component>& component)
67 {
68 text_ = AceType::DynamicCast<TextComponent>(component);
69 CheckIfNeedMeasure();
70 auto context = context_.Upgrade();
71 if (!context) {
72 LOGE("the context is nullptr in text update");
73 return;
74 }
75 // Register callback for fonts.
76 auto callback = [weakText = AceType::WeakClaim(this)] {
77 auto text = weakText.Upgrade();
78 if (text) {
79 text->isCallbackCalled_ = true;
80 text->MarkNeedLayout();
81 }
82 };
83
84 auto fontManager = context->GetFontManager();
85 if (fontManager) {
86 for (const auto& familyName : textStyle_.GetFontFamilies()) {
87 auto isCustomFont = fontManager->RegisterCallback(AceType::WeakClaim(this), familyName, callback);
88 if (isCustomFont) {
89 isCustomFont_ = true;
90 }
91 }
92 fontManager->AddVariationNode(WeakClaim(this));
93 }
94 if (isFocus_) {
95 textStyle_.SetTextColor(focusColor_);
96 }
97
98 if (textStyle_.IsAllowScale() || textStyle_.GetFontSize().Unit() == DimensionUnit::FP) {
99 context->AddFontNode(AceType::WeakClaim(this));
100 }
101
102 if (!clipboard_ && context) {
103 clipboard_ = ClipboardProxy::GetInstance()->GetClipboard(context->GetTaskExecutor());
104 }
105
106 copyOption_ = text_->GetCopyOption();
107 textForDisplay_ = text_->GetData();
108 defaultTextDirection_ = TextDirection::LTR;
109 realTextDirection_ = defaultTextDirection_;
110 textAffinity_ = TextAffinity::UPSTREAM;
111 textValue_.text = text_->GetData();
112 cursorWidth_ = NormalizeToPx(CURSOR_WIDTH);
113 alignment_ = text_->GetAlignment();
114
115 onDragStart_ = text_->GetOnDragStartId();
116 onDragEnter_ = text_->GetOnDragEnterId();
117 onDragMove_ = text_->GetOnDragMoveId();
118 onDragLeave_ = text_->GetOnDragLeaveId();
119 onDrop_ = text_->GetOnDropId();
120 if (onDragStart_) {
121 CreateDragDropRecognizer(context_);
122 CreateSelectRecognizer();
123 }
124 }
125
OnPaintFinish()126 void RenderText::OnPaintFinish()
127 {
128 UpdateOverlay();
129 #if !defined(PREVIEW)
130 UpdateAccessibilityText();
131 #endif
132 }
133
UpdateAccessibilityText()134 void RenderText::UpdateAccessibilityText()
135 {
136 const auto& context = context_.Upgrade();
137 if (!context) {
138 return;
139 }
140 auto viewScale = context->GetViewScale();
141 if (NearZero(viewScale)) {
142 return;
143 }
144 auto accessibilityNode = GetAccessibilityNode().Upgrade();
145 if (!accessibilityNode) {
146 return;
147 }
148 if (GetChildren().empty()) {
149 if (text_) {
150 accessibilityNode->SetText(text_->GetData());
151 }
152 } else {
153 std::string accessibilityText;
154 for (const auto& child : GetChildren()) {
155 auto renderTextSpan = AceType::DynamicCast<RenderTextSpan>(child);
156 if (renderTextSpan) {
157 accessibilityText += renderTextSpan->GetSpanData();
158 }
159 }
160 accessibilityNode->SetText(accessibilityText);
161 }
162 if (!accessibilityNode->GetVisible()) { // Set 0 to item when whole outside of view port.
163 accessibilityNode->SetWidth(0.0);
164 accessibilityNode->SetHeight(0.0);
165 accessibilityNode->SetTop(0.0);
166 accessibilityNode->SetLeft(0.0);
167 return;
168 }
169 if (accessibilityNode->IsValidRect()) {
170 return; // Rect already clamp by viewport, no need to set again.
171 }
172 Size size = GetLayoutSize();
173 Offset globalOffset = GetGlobalOffsetExternal();
174 PositionInfo positionInfo = { (size.Width()) * viewScale, (size.Height()) * viewScale,
175 (globalOffset.GetX()) * viewScale, (globalOffset.GetY()) * viewScale };
176 accessibilityNode->SetPositionInfo(positionInfo);
177 accessibilityNode->SetIsMultiLine(GetTextLines() > 1);
178 }
179
IsDeclarativePara()180 bool RenderText::IsDeclarativePara()
181 {
182 auto context = context_.Upgrade();
183 if (!context) {
184 return false;
185 }
186
187 return context->GetIsDeclarative();
188 }
189
PerformLayout()190 void RenderText::PerformLayout()
191 {
192 // When the constraint is set, minHeight is reset to 0.0,
193 // and the occupied height is controlled by the parent node box
194 if (IsDeclarativePara()) {
195 LayoutParam layoutParam = GetLayoutParam();
196 auto minWidth = layoutParam.GetMinSize().Width();
197 auto minHeight = layoutParam.GetMinSize().Height();
198 if (GreatNotEqual(minHeight, 0.0f)) {
199 layoutParam.SetMinSize(Size(minWidth, 0.0f));
200 SetLayoutParam(layoutParam);
201 }
202 }
203 auto pipelineContext = GetContext().Upgrade();
204 if ((textStyle_.IsAllowScale() || textStyle_.GetFontSize().Unit() == DimensionUnit::FP) && pipelineContext &&
205 !NearEqual(fontScale_, pipelineContext->GetFontScale())) {
206 needMeasure_ = true;
207 fontScale_ = pipelineContext->GetFontScale();
208 }
209 if (pipelineContext) {
210 UpdateIfChanged(dipScale_, pipelineContext->GetDipScale());
211 }
212 Size size = Measure();
213 SetLayoutSize(GetLayoutParam().Constrain(size));
214 for (const auto& spanChild : GetChildren()) {
215 if (spanChild) {
216 const auto& param = GetLayoutParam();
217 spanChild->Layout(param);
218 }
219 }
220 textOverlayPaintRect_ = GetPaintRect();
221 }
222
TouchTest(const Point & globalPoint,const Point & parentLocalPoint,const TouchRestrict & touchRestrict,TouchTestResult & result)223 bool RenderText::TouchTest(const Point& globalPoint, const Point& parentLocalPoint, const TouchRestrict& touchRestrict,
224 TouchTestResult& result)
225 {
226 if (GetDisableTouchEvent() || disabled_) {
227 return false;
228 }
229
230 // Since the paintRect is relative to parent, use parent local point to perform touch test.
231 if (!InTouchRectList(parentLocalPoint, GetTouchRectList())) {
232 return false;
233 }
234
235 // Reset flag firstly.
236 needClickDetector_ = false;
237 needLongPressDetector_ = false;
238 needTouchDetector_ = false;
239 // Calculates the local point location in this node.
240 const auto localPoint = parentLocalPoint - GetPaintRect().GetOffset();
241 Offset localOffset = Offset(localPoint.GetX(), localPoint.GetY());
242 // If span of touch position has click event, need add click detector.
243 if (!GetEventMarker(GetTouchPosition(localOffset), GestureType::CLICK).IsEmpty() ||
244 !GetEventMarker(GetTouchPosition(localOffset), GestureType::REMOTE_MESSAGE).IsEmpty()) {
245 needClickDetector_ = true;
246 }
247 // If span of touch position has long press event, need add long press detector.
248 if (!GetEventMarker(GetTouchPosition(localOffset), GestureType::LONG_PRESS).IsEmpty()) {
249 needLongPressDetector_ = true;
250 }
251 // If span of touch position has touch event, need add touch detector.
252 if (!GetEventMarker(GetTouchPosition(localOffset), GestureType::TOUCH_START).IsEmpty() ||
253 !GetEventMarker(GetTouchPosition(localOffset), GestureType::TOUCH_MOVE).IsEmpty() ||
254 !GetEventMarker(GetTouchPosition(localOffset), GestureType::TOUCH_END).IsEmpty() ||
255 !GetEventMarker(GetTouchPosition(localOffset), GestureType::TOUCH_CANCEL).IsEmpty()) {
256 needTouchDetector_ = true;
257 }
258 if (!needClickDetector_ && !needLongPressDetector_ && !needTouchDetector_ && copyOption_ == CopyOptions::None &&
259 !onDragStart_) {
260 return false;
261 }
262
263 auto beforeSize = result.size();
264 if (touchable_) {
265 // Calculates the coordinate offset in this node.
266 const auto coordinateOffset = globalPoint - localPoint;
267 globalPoint_ = globalPoint;
268 OnTouchTestHit(coordinateOffset, touchRestrict, result);
269 }
270 auto endSize = result.size();
271 return beforeSize != endSize;
272 }
273
OnTouchTestHit(const Offset & coordinateOffset,const TouchRestrict & touchRestrict,TouchTestResult & result)274 void RenderText::OnTouchTestHit(
275 const Offset& coordinateOffset, const TouchRestrict& touchRestrict, TouchTestResult& result)
276 {
277 if (copyOption_ != CopyOptions::None) {
278 if (!textOverlayRecognizer_) {
279 textOverlayRecognizer_ = AceType::MakeRefPtr<LongPressRecognizer>(context_);
280 textOverlayRecognizer_->SetOnLongPress([weak = WeakClaim(this)](const LongPressInfo& info) {
281 auto client = weak.Upgrade();
282 if (client) {
283 client->OnLongPress(info);
284 }
285 });
286 }
287 textOverlayRecognizer_->SetCoordinateOffset(coordinateOffset);
288 textOverlayRecognizer_->SetTouchRestrict(touchRestrict);
289 textOverlayRecognizer_->SetUseCatchMode(false);
290 result.emplace_back(textOverlayRecognizer_);
291 }
292
293 if (onDragStart_) {
294 if (!hideTextOverlayRecognizer_) {
295 hideTextOverlayRecognizer_ = AceType::MakeRefPtr<ClickRecognizer>();
296 hideTextOverlayRecognizer_->SetOnClick([weak = WeakClaim(this)](const ClickInfo& info) {
297 auto text = weak.Upgrade();
298 if (text && info.GetSourceDevice() == SourceType::MOUSE) {
299 text->HideTextOverlay();
300 }
301 });
302 }
303 hideTextOverlayRecognizer_->SetCoordinateOffset(coordinateOffset);
304 hideTextOverlayRecognizer_->SetTouchRestrict(touchRestrict);
305 result.emplace_back(hideTextOverlayRecognizer_);
306
307 if (touchRestrict.sourceType == SourceType::MOUSE) {
308 Offset offset(globalPoint_.GetX(), globalPoint_.GetY());
309 if (IsSelectedText(offset, GetGlobalOffset())) {
310 result.emplace_back(dragDropGesture_);
311 } else {
312 result.emplace_back(selectRecognizer_);
313 }
314 } else {
315 auto renderText = AceType::Claim(this);
316 if (renderText) {
317 SetStartOffset(GetHandleOffset(0));
318 SetEndOffset(GetHandleOffset(textValue_.GetWideText().length()));
319 textValue_.UpdateSelection(0, textValue_.GetWideText().length());
320 }
321 result.emplace_back(dragDropGesture_);
322 }
323 }
324
325 if (GetChildren().empty()) {
326 return;
327 }
328
329 auto context = context_.Upgrade();
330 if (!context) {
331 return;
332 }
333
334 if (needTouchDetector_) {
335 if (!rawRecognizer_) {
336 rawRecognizer_ = AceType::MakeRefPtr<RawRecognizer>();
337 rawRecognizer_->SetOnTouchDown([weak = WeakClaim(this)](const TouchEventInfo& info) {
338 auto text = weak.Upgrade();
339 if (text && !info.GetTouches().empty()) {
340 text->HandleTouchEvent(GestureType::TOUCH_START,
341 info.GetTouches().front().GetLocalLocation() - text->GetGlobalOffset());
342 }
343 });
344
345 rawRecognizer_->SetOnTouchMove([weak = WeakClaim(this)](const TouchEventInfo& info) {
346 auto text = weak.Upgrade();
347 if (text && !info.GetTouches().empty()) {
348 text->HandleTouchEvent(GestureType::TOUCH_MOVE,
349 info.GetTouches().front().GetLocalLocation() - text->GetGlobalOffset());
350 }
351 });
352
353 rawRecognizer_->SetOnTouchUp([weak = WeakClaim(this)](const TouchEventInfo& info) {
354 auto text = weak.Upgrade();
355 if (text && !info.GetTouches().empty()) {
356 text->HandleTouchEvent(
357 GestureType::TOUCH_END, info.GetTouches().front().GetLocalLocation() - text->GetGlobalOffset());
358 }
359 });
360
361 rawRecognizer_->SetOnTouchCancel([weak = WeakClaim(this)](const TouchEventInfo& info) {
362 auto text = weak.Upgrade();
363 if (text && !info.GetTouches().empty()) {
364 text->HandleTouchEvent(GestureType::TOUCH_CANCEL,
365 info.GetTouches().front().GetLocalLocation() - text->GetGlobalOffset());
366 }
367 });
368 }
369 rawRecognizer_->SetTouchRestrict(touchRestrict);
370 rawRecognizer_->SetCoordinateOffset(coordinateOffset);
371 result.emplace_back(rawRecognizer_);
372 needTouchDetector_ = false;
373 }
374
375 if (needClickDetector_) {
376 if (!clickDetector_) {
377 clickDetector_ = AceType::MakeRefPtr<ClickRecognizer>();
378 clickDetector_->SetOnClick([weak = WeakClaim(this)](const ClickInfo& info) {
379 auto text = weak.Upgrade();
380 if (text) {
381 text->HandleClick(info);
382 }
383 });
384 clickDetector_->SetRemoteMessage([weak = WeakClaim(this)](const ClickInfo& info) {
385 auto text = weak.Upgrade();
386 if (text) {
387 text->HandleRemoteMessage(info);
388 }
389 });
390 }
391 clickDetector_->SetCoordinateOffset(coordinateOffset);
392 clickDetector_->SetTouchRestrict(touchRestrict);
393 clickDetector_->SetIsExternalGesture(true);
394 result.emplace_back(clickDetector_);
395 needClickDetector_ = false;
396 }
397
398 if (needLongPressDetector_) {
399 if (!longPressRecognizer_) {
400 longPressRecognizer_ = AceType::MakeRefPtr<LongPressRecognizer>(context_);
401 longPressRecognizer_->SetOnLongPress([weak = WeakClaim(this)](const LongPressInfo& info) {
402 auto text = weak.Upgrade();
403 if (text) {
404 text->HandleLongPress(info.GetLocalLocation());
405 }
406 });
407 }
408 longPressRecognizer_->SetCoordinateOffset(coordinateOffset);
409 longPressRecognizer_->SetTouchRestrict(touchRestrict);
410 result.emplace_back(longPressRecognizer_);
411 needLongPressDetector_ = false;
412 }
413 }
414
HideTextOverlay()415 void RenderText::HideTextOverlay()
416 {
417 auto textOverlayManager = GetTextOverlayManager(context_);
418 if (!textOverlayManager) {
419 return;
420 }
421
422 auto textOverlayBase = textOverlayManager->GetTextOverlayBase();
423 if (!textOverlayBase) {
424 return;
425 }
426
427 auto targetNode = textOverlayManager->GetTargetNode();
428 if (targetNode == this) {
429 textOverlayManager->PopTextOverlay();
430 textOverlayBase->ChangeSelection(0, 0);
431 textOverlayBase->MarkIsOverlayShowed(false);
432 targetNode->MarkNeedRender();
433 }
434 }
435
UpdateTextOverlay()436 void RenderText::UpdateTextOverlay()
437 {
438 auto textOverlayManager = GetTextOverlayManager(context_);
439 if (!textOverlayManager) {
440 return;
441 }
442
443 auto textOverlayBase = textOverlayManager->GetTextOverlayBase();
444 if (!textOverlayBase) {
445 return;
446 }
447
448 auto targetNode = textOverlayManager->GetTargetNode();
449 if (targetNode == this) {
450 targetNode->MarkNeedRender();
451 }
452 }
453
OnLongPress(const LongPressInfo & longPressInfo)454 void RenderText::OnLongPress(const LongPressInfo& longPressInfo)
455 {
456 if (longPressInfo.GetSourceDevice() == SourceType::MOUSE) {
457 return;
458 }
459
460 auto textOverlayManager = GetTextOverlayManager(context_);
461 if (textOverlayManager) {
462 auto textOverlayBase = textOverlayManager->GetTextOverlayBase();
463 if (textOverlayBase) {
464 auto targetNode = textOverlayManager->GetTargetNode();
465 if (targetNode) {
466 textOverlayManager->PopTextOverlay();
467 textOverlayBase->ChangeSelection(0, 0);
468 textOverlayBase->MarkIsOverlayShowed(false);
469 targetNode->MarkNeedRender();
470 }
471 }
472 textOverlayManager->SetTextOverlayBase(AceType::WeakClaim(this));
473 }
474
475 Offset longPressPosition = longPressInfo.GetGlobalLocation();
476 auto context = context_.Upgrade();
477 if (context) {
478 auto isContainerModal = context->GetWindowModal() == WindowModal::CONTAINER_MODAL &&
479 context->GetWindowManager()->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING;
480 if (isContainerModal) {
481 longPressPosition =
482 longPressPosition + Offset(-(CONTAINER_BORDER_WIDTH.ConvertToPx() + CONTENT_PADDING.ConvertToPx()),
483 -CONTAINER_TITLE_HEIGHT.ConvertToPx());
484 }
485 }
486
487 InitSelection(longPressPosition, GetGlobalOffset());
488 ShowTextOverlay(longPressPosition, false);
489 }
490
HandleMouseEvent(const MouseEvent & event)491 bool RenderText::HandleMouseEvent(const MouseEvent& event)
492 {
493 if (copyOption_ == CopyOptions::None) {
494 return false;
495 }
496 if (event.button == MouseButton::RIGHT_BUTTON && event.action == MouseAction::PRESS) {
497 Offset rightClickOffset = event.GetOffset();
498
499 auto textOverlayManager = GetTextOverlayManager(context_);
500 if (textOverlayManager) {
501 auto textOverlayBase = textOverlayManager->GetTextOverlayBase();
502 if (textOverlayBase) {
503 auto targetNode = textOverlayManager->GetTargetNode();
504 if (targetNode) {
505 textOverlayManager->PopTextOverlay();
506 textOverlayBase->ChangeSelection(0, 0);
507 textOverlayBase->MarkIsOverlayShowed(false);
508 targetNode->MarkNeedRender();
509 }
510 }
511 textOverlayManager->SetTextOverlayBase(AceType::WeakClaim(this));
512 }
513 InitSelection(rightClickOffset, GetGlobalOffset());
514 ShowTextOverlay(rightClickOffset, true);
515 return true;
516 }
517
518 return false;
519 }
520
ShowTextOverlay(const Offset & showOffset)521 void RenderText::ShowTextOverlay(const Offset& showOffset)
522 {
523 ShowTextOverlay(showOffset, false);
524 }
525
ShowTextOverlay(const Offset & showOffset,bool isUsingMouse)526 void RenderText::ShowTextOverlay(const Offset& showOffset, bool isUsingMouse)
527 {
528 auto selStart = textValue_.selection.GetStart();
529 auto selEnd = textValue_.selection.GetEnd();
530
531 Offset startHandleOffset = GetHandleOffset(selStart);
532 Offset endHandleOffset = GetHandleOffset(selEnd);
533
534 if (isOverlayShowed_ && updateHandlePosition_) {
535 Rect caretStart;
536 bool visible =
537 GetCaretRect(selStart, caretStart, 0.0) ? IsVisible(caretStart + textOffsetForShowCaret_) : false;
538 OverlayShowOption option { .showMenu = isOverlayShowed_,
539 .showStartHandle = visible,
540 .showEndHandle = visible,
541 .isSingleHandle = false,
542 .updateOverlayType = UpdateOverlayType::LONG_PRESS,
543 .startHandleOffset = startHandleOffset,
544 .endHandleOffset = endHandleOffset };
545 updateHandlePosition_(option);
546
547 // When the textOverlay is showed, restart the animation
548 if (!animator_) {
549 LOGE("Show textOverlay error, animator is nullptr");
550 return;
551 }
552 if (!animator_->IsStopped()) {
553 animator_->Stop();
554 }
555 animator_->Play();
556 return;
557 }
558
559 textOverlay_ =
560 AceType::MakeRefPtr<TextOverlayComponent>(GetThemeManager(), context_.Upgrade()->GetAccessibilityManager());
561 textOverlay_->SetWeakText(WeakClaim(this));
562 textOverlay_->SetLineHeight(selectHeight_);
563 Rect paintRect = { Offset::Zero(), GetLayoutParam().GetMaxSize() };
564 textOverlay_->SetClipRect(paintRect + Size(HANDLE_HOT_ZONE, HANDLE_HOT_ZONE) + GetOffsetToPage() -
565 Offset(HANDLE_HOT_ZONE / 2.0, 0.0));
566 textOverlay_->SetTextDirection(defaultTextDirection_);
567 textOverlay_->SetStartHandleOffset(startHandleOffset);
568 textOverlay_->SetEndHandleOffset(endHandleOffset);
569 textOverlay_->SetContext(context_);
570 textOverlay_->SetIsUsingMouse(isUsingMouse);
571 if (isUsingMouse) {
572 textOverlay_->SetMouseOffset(showOffset);
573 }
574 // Add the Animation
575 InitAnimation(context_);
576 RegisterCallbacksToOverlay();
577 MarkNeedRender();
578 }
579
RegisterCallbacksToOverlay()580 void RenderText::RegisterCallbacksToOverlay()
581 {
582 if (!textOverlay_) {
583 return;
584 }
585
586 textOverlay_->SetOnCopy([weak = AceType::WeakClaim(this)] {
587 auto text = weak.Upgrade();
588 if (text) {
589 text->HandleOnCopy();
590 }
591 });
592
593 textOverlay_->SetOnCopyAll(
594 [weak = AceType::WeakClaim(this)](const std::function<void(const Offset&, const Offset&)>& callback) {
595 auto text = weak.Upgrade();
596 if (text) {
597 text->HandleOnCopyAll(callback);
598 }
599 });
600
601 textOverlay_->SetOnStartHandleMove(
602 [weak = AceType::WeakClaim(this)](int32_t end, const Offset& startHandleOffset,
603 const std::function<void(const Offset&)>& startCallback, bool isSingleHandle) {
604 auto text = weak.Upgrade();
605 if (text) {
606 text->HandleOnStartHandleMove(end, startHandleOffset, startCallback, isSingleHandle);
607 }
608 });
609
610 textOverlay_->SetOnEndHandleMove([weak = AceType::WeakClaim(this)](int32_t start, const Offset& endHandleOffset,
611 const std::function<void(const Offset&)>& endCallback) {
612 auto text = weak.Upgrade();
613 if (text) {
614 text->HandleOnEndHandleMove(start, endHandleOffset, endCallback);
615 }
616 });
617
618 auto callback = [weak = WeakClaim(this), pipelineContext = context_, textOverlay = textOverlay_](
619 const std::string& data) {
620 auto context = pipelineContext.Upgrade();
621 if (!context) {
622 return;
623 }
624 auto textOverlayManager = context->GetTextOverlayManager();
625 if (!textOverlayManager) {
626 return;
627 }
628 textOverlayManager->PushTextOverlayToStack(textOverlay, pipelineContext);
629
630 auto text = weak.Upgrade();
631 if (!text) {
632 return;
633 }
634 text->UpdateOverlay();
635 text->MarkIsOverlayShowed(true);
636 };
637 if (clipboard_) {
638 clipboard_->GetData(callback);
639 }
640 }
641
UpdateOverlay()642 void RenderText::UpdateOverlay()
643 {
644 // When textfield PerformLayout, update overlay.
645 if (isOverlayShowed_ && updateHandlePosition_) {
646 auto selStart = textValue_.selection.GetStart();
647 auto selEnd = textValue_.selection.GetEnd();
648 Rect caretStart;
649 Rect caretEnd;
650 bool startHandleVisible =
651 GetCaretRect(selStart, caretStart, 0.0) ? IsVisible(caretStart + textOffsetForShowCaret_) : false;
652 bool endHandleVisible =
653 (selStart == selEnd)
654 ? startHandleVisible
655 : (GetCaretRect(selEnd, caretEnd, 0.0) ? IsVisible(caretEnd + textOffsetForShowCaret_) : false);
656
657 OverlayShowOption option { .showMenu = isOverlayShowed_,
658 .showStartHandle = startHandleVisible,
659 .showEndHandle = endHandleVisible,
660 .isSingleHandle = false,
661 .updateOverlayType = UpdateOverlayType::SCROLL,
662 .startHandleOffset = GetPositionForExtend(selStart),
663 .endHandleOffset = GetPositionForExtend(selEnd) };
664 updateHandlePosition_(option);
665 if (onClipRectChanged_) {
666 Rect paintRect = { Offset::Zero(), GetLayoutParam().GetMaxSize() };
667 onClipRectChanged_(paintRect + Size(HANDLE_HOT_ZONE, HANDLE_HOT_ZONE) + GetOffsetToPage() -
668 Offset(HANDLE_HOT_ZONE / 2.0, 0.0));
669 }
670 }
671 }
672
GetPositionForExtend(int32_t extend)673 Offset RenderText::GetPositionForExtend(int32_t extend)
674 {
675 if (extend < 0) {
676 extend = 0;
677 }
678 if (static_cast<size_t>(extend) > StringUtils::ToWstring(textValue_.text).length()) {
679 extend = static_cast<int32_t>(StringUtils::ToWstring(textValue_.text).length());
680 }
681 return GetHandleOffset(extend);
682 }
683
HandleOnCopy()684 void RenderText::HandleOnCopy()
685 {
686 if (!clipboard_) {
687 return;
688 }
689 if (textValue_.GetSelectedText().empty()) {
690 return;
691 }
692 clipboard_->SetData(textValue_.GetSelectedText(), copyOption_);
693
694 auto textOverlayManager = GetTextOverlayManager(context_);
695 if (textOverlayManager) {
696 textOverlayManager->PopTextOverlay();
697 }
698 isOverlayShowed_ = false;
699 textValue_.UpdateSelection(0, 0);
700 MarkNeedRender();
701 }
702
HandleOnCopyAll(const std::function<void (const Offset &,const Offset &)> & callback)703 void RenderText::HandleOnCopyAll(const std::function<void(const Offset&, const Offset&)>& callback)
704 {
705 auto textSize = textValue_.GetWideText().length();
706 textValue_.UpdateSelection(0, textSize);
707 if (callback) {
708 callback(GetPositionForExtend(0), GetPositionForExtend(textValue_.GetWideText().length()));
709 }
710 MarkNeedRender();
711 }
712
HandleOnStartHandleMove(int32_t end,const Offset & startHandleOffset,const std::function<void (const Offset &)> & startCallback,bool isSingleHandle)713 void RenderText::HandleOnStartHandleMove(int32_t end, const Offset& startHandleOffset,
714 const std::function<void(const Offset&)>& startCallback, bool isSingleHandle)
715 {
716 Offset realOffset = startHandleOffset;
717 if (startCallback) {
718 UpdateStartSelection(end, realOffset, GetGlobalOffset());
719 startCallback(GetHandleOffset(textValue_.selection.GetStart()));
720 }
721 MarkNeedRender();
722 }
723
HandleOnEndHandleMove(int32_t start,const Offset & endHandleOffset,const std::function<void (const Offset &)> & endCallback)724 void RenderText::HandleOnEndHandleMove(
725 int32_t start, const Offset& endHandleOffset, const std::function<void(const Offset&)>& endCallback)
726 {
727 Offset realOffset = endHandleOffset;
728 if (endCallback) {
729 UpdateEndSelection(start, realOffset, GetGlobalOffset());
730 endCallback(GetHandleOffset(textValue_.selection.GetEnd()));
731 }
732 MarkNeedRender();
733 }
734
FireEvent(const EventMarker & marker)735 void RenderText::FireEvent(const EventMarker& marker)
736 {
737 if (marker.IsEmpty()) {
738 return;
739 }
740
741 auto func = AceAsyncEvent<void()>::Create(marker, context_);
742 if (func) {
743 func();
744 }
745 }
746
HandleTouchEvent(GestureType type,const Offset & touchPosition)747 void RenderText::HandleTouchEvent(GestureType type, const Offset& touchPosition)
748 {
749 if (type == GestureType::TOUCH_START) {
750 touchStartPosition_ = GetTouchPosition(touchPosition);
751 }
752
753 auto eventMarker = GetEventMarker(touchStartPosition_, type);
754 if (!eventMarker.IsEmpty()) {
755 FireEvent(eventMarker);
756 return;
757 }
758
759 // If span has not touch event, use touch event of text.
760 if (!text_) {
761 return;
762 }
763 auto declaration = text_->GetDeclaration();
764 if (!declaration) {
765 return;
766 }
767 auto& rawEvent = static_cast<CommonRawEvent&>(declaration->GetEvent(EventTag::COMMON_RAW_EVENT));
768 if (!rawEvent.IsValid()) {
769 return;
770 }
771
772 switch (type) {
773 case GestureType::TOUCH_START:
774 eventMarker = rawEvent.touchStart.eventMarker;
775 break;
776 case GestureType::TOUCH_MOVE:
777 eventMarker = rawEvent.touchMove.eventMarker;
778 break;
779 case GestureType::TOUCH_END:
780 eventMarker = rawEvent.touchEnd.eventMarker;
781 break;
782 case GestureType::TOUCH_CANCEL:
783 eventMarker = rawEvent.touchCancel.eventMarker;
784 break;
785 default:
786 break;
787 }
788 FireEvent(eventMarker);
789 }
790
HandleClick(const ClickInfo & info)791 void RenderText::HandleClick(const ClickInfo& info)
792 {
793 auto clickPosition = info.GetLocalLocation();
794 auto clickMarker = GetEventMarker(GetTouchPosition(clickPosition), GestureType::CLICK);
795 // If span has not click event, use click event of text.
796 if (text_ && clickMarker.IsEmpty()) {
797 auto declaration = text_->GetDeclaration();
798 if (declaration) {
799 auto& gestureEvent =
800 static_cast<CommonGestureEvent&>(declaration->GetEvent(EventTag::COMMON_GESTURE_EVENT));
801 if (gestureEvent.IsValid() && !gestureEvent.click.eventMarker.IsEmpty()) {
802 clickMarker = gestureEvent.click.eventMarker;
803 }
804 }
805 }
806
807 auto onClick = AceAsyncEvent<void(const ClickInfo&)>::Create(clickMarker, context_);
808 if (onClick) {
809 onClick(info);
810 }
811 }
812
HandleRemoteMessage(const ClickInfo & info)813 void RenderText::HandleRemoteMessage(const ClickInfo& info)
814 {
815 auto clickPosition = info.GetLocalLocation();
816 auto clickMarker = GetEventMarker(GetTouchPosition(clickPosition), GestureType::REMOTE_MESSAGE);
817 // If span has not click event, use click event of text.
818 if (text_ && clickMarker.IsEmpty()) {
819 auto declaration = text_->GetDeclaration();
820 if (declaration) {
821 auto& gestureEvent =
822 static_cast<CommonGestureEvent&>(declaration->GetEvent(EventTag::COMMON_REMOTE_MESSAGE_GESTURE_EVENT));
823 if (gestureEvent.IsValid() && !gestureEvent.click.eventMarker.IsEmpty()) {
824 clickMarker = gestureEvent.click.eventMarker;
825 }
826 }
827 }
828
829 auto remoteMessage = AceAsyncEvent<void(const ClickInfo&)>::Create(clickMarker, context_);
830 if (remoteMessage) {
831 remoteMessage(info);
832 }
833 }
834
HandleLongPress(const Offset & longPressPosition)835 void RenderText::HandleLongPress(const Offset& longPressPosition)
836 {
837 auto longPressMarker = GetEventMarker(GetTouchPosition(longPressPosition), GestureType::LONG_PRESS);
838 // If span has not long press event, use long press event of text.
839 if (text_ && longPressMarker.IsEmpty()) {
840 auto declaration = text_->GetDeclaration();
841 if (declaration) {
842 auto& gestureEvent =
843 static_cast<CommonGestureEvent&>(declaration->GetEvent(EventTag::COMMON_GESTURE_EVENT));
844 if (gestureEvent.IsValid() && !gestureEvent.longPress.eventMarker.IsEmpty()) {
845 longPressMarker = gestureEvent.longPress.eventMarker;
846 }
847 }
848 }
849
850 FireEvent(longPressMarker);
851 }
852
GetEventMarker(int32_t position,GestureType type)853 EventMarker RenderText::GetEventMarker(int32_t position, GestureType type)
854 {
855 if (touchRegions_.empty()) {
856 return EventMarker();
857 }
858 for (const auto& region : touchRegions_) {
859 if (position < region.first) {
860 auto markerIter = region.second.find(type);
861 if (markerIter != region.second.end()) {
862 return markerIter->second;
863 }
864 return EventMarker();
865 }
866 }
867 return EventMarker();
868 }
869
OnStatusChanged(OHOS::Ace::RenderStatus renderStatus)870 void RenderText::OnStatusChanged(OHOS::Ace::RenderStatus renderStatus)
871 {
872 auto context = context_.Upgrade();
873 if (context && context->GetIsDeclarative()) {
874 return;
875 }
876
877 if (renderStatus == RenderStatus::FOCUS) {
878 textStyle_.SetTextColor(focusColor_);
879 isFocus_ = true;
880 } else {
881 textStyle_.SetTextColor(lostFocusColor_);
882 isFocus_ = false;
883 }
884 needMeasure_ = true;
885 Measure();
886 MarkNeedRender();
887 }
888
CheckIfNeedMeasure()889 void RenderText::CheckIfNeedMeasure()
890 {
891 if (!text_) {
892 return;
893 }
894
895 if (text_->IsChanged()) {
896 needMeasure_ = true;
897 }
898 UpdateIfChanged(defaultTextDirection_, text_->GetTextDirection());
899 realTextDirection_ = defaultTextDirection_;
900 UpdateIfChanged(textStyle_, text_->GetTextStyle());
901 UpdateIfChanged(focusColor_, text_->GetFocusColor());
902 UpdateIfChanged(lostFocusColor_, textStyle_.GetTextColor());
903 UpdateIfChanged(maxLines_, textStyle_.GetMaxLines());
904 if (needMeasure_) {
905 MarkNeedLayout();
906 }
907 }
908
GetTextData() const909 std::string RenderText::GetTextData() const
910 {
911 return text_ ? text_->GetData() : "";
912 }
913
SetTextData(const std::string & textData)914 void RenderText::SetTextData(const std::string& textData)
915 {
916 if (text_) {
917 text_->SetData(textData);
918 }
919 }
920
ClearRenderObject()921 void RenderText::ClearRenderObject()
922 {
923 RenderNode::ClearRenderObject();
924 text_.Reset();
925 textStyle_ = TextStyle();
926 defaultTextDirection_ = TextDirection::LTR;
927 focusColor_ = Color();
928 lostFocusColor_ = Color();
929 fontScale_ = 1.0;
930 dipScale_ = 1.0;
931 isFocus_ = false;
932 needMeasure_ = true;
933 isCallbackCalled_ = false;
934 }
935
GetContentSize()936 Size RenderText::GetContentSize()
937 {
938 if (textStyle_.GetAdaptTextSize()) {
939 return Size();
940 }
941 // Make sure text's height is not clipped, width is not guard.
942 auto measuredSize = Measure();
943 if (textStyle_.GetTextOverflow() != TextOverflow::NONE || maxLines_ > 1) {
944 measuredSize.SetWidth(0.0);
945 }
946 return measuredSize;
947 }
948
GetComponent()949 RefPtr<Component> RenderText::GetComponent()
950 {
951 return text_;
952 }
953
GetSelectedContent() const954 std::string RenderText::GetSelectedContent() const
955 {
956 return textValue_.GetSelectedText();
957 }
958
Dump()959 void RenderText::Dump()
960 {
961 DumpLog::GetInstance().AddDesc(std::string("Data: ").append(text_->GetData()));
962 DumpLog::GetInstance().AddDesc(std::string("FontColor: ").append(textStyle_.GetTextColor().ColorToString()));
963 DumpLog::GetInstance().AddDesc(std::string("FontSize: ").append(textStyle_.GetFontSize().ToString()));
964 DumpLog::GetInstance().AddDesc(
965 std::string("FontStyle: ").append(V2::ConvertWrapFontStyleToStirng(textStyle_.GetFontStyle())));
966 DumpLog::GetInstance().AddDesc(
967 std::string("FontWeight: ").append(V2::ConvertWrapFontWeightToStirng(textStyle_.GetFontWeight())));
968 std::string fontFamilies;
969 for (const auto& family : textStyle_.GetFontFamilies()) {
970 fontFamilies += family;
971 fontFamilies += ",";
972 }
973 DumpLog::GetInstance().AddDesc(std::string("FontFamily: ").append(fontFamilies));
974 DumpLog::GetInstance().AddDesc(std::string("CopyOptions: ").append(V2::ConvertWrapCopyOptionToString(copyOption_)));
975 }
976
GenerateDragItemInfo(const RefPtr<PipelineContext> & context,const GestureEvent & info)977 DragItemInfo RenderText::GenerateDragItemInfo(const RefPtr<PipelineContext>& context, const GestureEvent& info)
978 {
979 RefPtr<DragEvent> event = AceType::MakeRefPtr<DragEvent>();
980 event->SetX(context->ConvertPxToVp(Dimension(info.GetGlobalPoint().GetX(), DimensionUnit::PX)));
981 event->SetY(context->ConvertPxToVp(Dimension(info.GetGlobalPoint().GetY(), DimensionUnit::PX)));
982 selectedItemSize_ = GetLayoutSize();
983 auto extraParams = JsonUtil::Create(true);
984
985 return onDragStart_(event, extraParams->ToString());
986 }
987
PanOnActionStart(const GestureEvent & info)988 void RenderText::PanOnActionStart(const GestureEvent& info)
989 {
990 if (!onDragStart_) {
991 return;
992 }
993 auto pipelineContext = context_.Upgrade();
994 if (!pipelineContext) {
995 LOGE("Context is null.");
996 return;
997 }
998
999 GestureEvent newInfo = info;
1000 Point newPoint = UpdatePoint(pipelineContext, startPoint_);
1001 newInfo.SetGlobalPoint(newPoint);
1002 auto dragItemInfo = GenerateDragItemInfo(pipelineContext, newInfo);
1003 #if !defined(PREVIEW)
1004 if (!dragItemInfo.pixelMap && !dragItemInfo.customComponent) {
1005 auto initRenderNode = AceType::Claim(this);
1006 isDragDropNode_ = true;
1007 pipelineContext->SetInitRenderNode(initRenderNode);
1008
1009 AddDataToClipboard(pipelineContext, dragItemInfo.extraInfo, textValue_.GetSelectedText(), "");
1010 if (!dragWindow_) {
1011 auto rect = pipelineContext->GetCurrentWindowRect();
1012 dragWindow_ = DragWindow::CreateDragWindow("APP_DRAG_WINDOW",
1013 static_cast<int32_t>(info.GetGlobalPoint().GetX() + rect.Left()),
1014 static_cast<int32_t>(info.GetGlobalPoint().GetY() + rect.Top()),
1015 static_cast<int32_t>(GetPaintRect().Width()),
1016 static_cast<int32_t>(GetPaintRect().Height()));
1017 dragWindow_->SetOffset(static_cast<int32_t>(rect.Left()), static_cast<int32_t>(rect.Top()));
1018 dragWindow_->DrawText(paragraph_, GetPaintRect().GetOffset(), initRenderNode);
1019 }
1020 if (dragWindow_) {
1021 AceEngineExt::GetInstance().DragStartExt();
1022 }
1023 return;
1024 }
1025
1026 if (dragItemInfo.pixelMap) {
1027 auto initRenderNode = AceType::Claim(this);
1028 isDragDropNode_ = true;
1029 pipelineContext->SetInitRenderNode(initRenderNode);
1030
1031 AddDataToClipboard(pipelineContext, dragItemInfo.extraInfo, textValue_.GetSelectedText(), "");
1032 if (!dragWindow_) {
1033 auto rect = pipelineContext->GetCurrentWindowRect();
1034 dragWindow_ = DragWindow::CreateDragWindow("APP_DRAG_WINDOW",
1035 static_cast<int32_t>(info.GetGlobalPoint().GetX()) + rect.Left(),
1036 static_cast<int32_t>(info.GetGlobalPoint().GetY()) + rect.Top(), dragItemInfo.pixelMap->GetWidth(),
1037 dragItemInfo.pixelMap->GetHeight());
1038 dragWindow_->SetOffset(rect.Left(), rect.Top());
1039 dragWindow_->DrawPixelMap(dragItemInfo.pixelMap);
1040 }
1041 if (dragWindow_) {
1042 AceEngineExt::GetInstance().DragStartExt();
1043 }
1044 return;
1045 }
1046 #endif
1047 if (!dragItemInfo.customComponent) {
1048 LOGW("the drag custom component is null");
1049 return;
1050 }
1051
1052 hasDragItem_ = true;
1053 auto positionedComponent = AceType::MakeRefPtr<PositionedComponent>(dragItemInfo.customComponent);
1054 positionedComponent->SetTop(Dimension(GetGlobalOffset().GetY()));
1055 positionedComponent->SetLeft(Dimension(GetGlobalOffset().GetX()));
1056 SetLocalPoint(startPoint_ - GetGlobalOffset());
1057 auto updatePosition = [renderBox = AceType::Claim(this)](
1058 const std::function<void(const Dimension&, const Dimension&)>& func) {
1059 if (!renderBox) {
1060 return;
1061 }
1062 renderBox->SetUpdateBuilderFuncId(func);
1063 };
1064 positionedComponent->SetUpdatePositionFuncId(updatePosition);
1065 auto stackElement = pipelineContext->GetLastStack();
1066 stackElement->PushComponent(positionedComponent);
1067 }
1068
PanOnActionUpdate(const GestureEvent & info)1069 void RenderText::PanOnActionUpdate(const GestureEvent& info)
1070 {
1071 #if !defined(PREVIEW)
1072 if (isDragDropNode_ && dragWindow_) {
1073 int32_t x = static_cast<int32_t>(info.GetGlobalPoint().GetX());
1074 int32_t y = static_cast<int32_t>(info.GetGlobalPoint().GetY());
1075 if (lastDragMoveOffset_ == Offset(x, y)) {
1076 return;
1077 }
1078 lastDragMoveOffset_ = Offset(x, y);
1079 if (dragWindow_) {
1080 dragWindow_->MoveTo(x, y);
1081 }
1082 return;
1083 }
1084 #endif
1085 auto pipelineContext = context_.Upgrade();
1086 if (!pipelineContext) {
1087 LOGE("Context is null.");
1088 return;
1089 }
1090
1091 RefPtr<DragEvent> event = AceType::MakeRefPtr<DragEvent>();
1092 event->SetX(pipelineContext->ConvertPxToVp(Dimension(info.GetGlobalPoint().GetX(), DimensionUnit::PX)));
1093 event->SetY(pipelineContext->ConvertPxToVp(Dimension(info.GetGlobalPoint().GetY(), DimensionUnit::PX)));
1094
1095 Offset offset = info.GetGlobalPoint() - GetLocalPoint();
1096 if (GetUpdateBuilderFuncId()) {
1097 GetUpdateBuilderFuncId()(Dimension(offset.GetX()), Dimension(offset.GetY()));
1098 }
1099
1100 auto extraParams = JsonUtil::Create(true);
1101 auto targetDragDropNode = FindDragDropNode(pipelineContext, info);
1102 auto preDragDropNode = GetPreDragDropNode();
1103 if (preDragDropNode == targetDragDropNode) {
1104 if (targetDragDropNode && targetDragDropNode->GetOnDragMove()) {
1105 (targetDragDropNode->GetOnDragMove())(event, extraParams->ToString());
1106 }
1107 return;
1108 }
1109 if (preDragDropNode && preDragDropNode->GetOnDragLeave()) {
1110 (preDragDropNode->GetOnDragLeave())(event, extraParams->ToString());
1111 }
1112 if (targetDragDropNode && targetDragDropNode->GetOnDragEnter()) {
1113 (targetDragDropNode->GetOnDragEnter())(event, extraParams->ToString());
1114 }
1115 SetPreDragDropNode(targetDragDropNode);
1116 }
1117
PanOnActionEnd(const GestureEvent & info)1118 void RenderText::PanOnActionEnd(const GestureEvent& info)
1119 {
1120 auto pipelineContext = context_.Upgrade();
1121 if (!pipelineContext) {
1122 LOGE("Context is null.");
1123 return;
1124 }
1125 #if !defined(PREVIEW)
1126 if (isDragDropNode_) {
1127 isDragDropNode_ = false;
1128
1129 if (GetOnDrop()) {
1130 RefPtr<DragEvent> event = AceType::MakeRefPtr<DragEvent>();
1131 RefPtr<PasteData> pasteData = AceType::MakeRefPtr<PasteData>();
1132 event->SetPasteData(pasteData);
1133 event->SetX(pipelineContext->ConvertPxToVp(Dimension(info.GetGlobalPoint().GetX(), DimensionUnit::PX)));
1134 event->SetY(pipelineContext->ConvertPxToVp(Dimension(info.GetGlobalPoint().GetY(), DimensionUnit::PX)));
1135
1136 auto extraParams = JsonUtil::Create(true);
1137 (GetOnDrop())(event, extraParams->ToString());
1138 pipelineContext->SetInitRenderNode(nullptr);
1139 }
1140
1141 auto textfield = FindTargetRenderNode<RenderTextField>(context_.Upgrade(), info);
1142 if (textfield) {
1143 auto value = textfield->GetEditingValue();
1144 value.Append(textValue_.GetSelectedText());
1145 textfield->SetEditingValue(std::move(value));
1146 }
1147 if (info.GetSourceDevice() == SourceType::TOUCH) {
1148 textValue_.UpdateSelection(0, 0);
1149 }
1150 RestoreCilpboardData(pipelineContext);
1151 }
1152
1153 if (dragWindow_) {
1154 dragWindow_->Destroy();
1155 dragWindow_ = nullptr;
1156 return;
1157 }
1158 #endif
1159 RefPtr<DragEvent> event = AceType::MakeRefPtr<DragEvent>();
1160 RefPtr<PasteData> pasteData = AceType::MakeRefPtr<PasteData>();
1161 event->SetPasteData(pasteData);
1162 event->SetX(pipelineContext->ConvertPxToVp(Dimension(info.GetGlobalPoint().GetX(), DimensionUnit::PX)));
1163 event->SetY(pipelineContext->ConvertPxToVp(Dimension(info.GetGlobalPoint().GetY(), DimensionUnit::PX)));
1164
1165 Offset offset = info.GetGlobalPoint() - GetLocalPoint();
1166 if (GetUpdateBuilderFuncId()) {
1167 GetUpdateBuilderFuncId()(Dimension(offset.GetX()), Dimension(offset.GetY()));
1168 }
1169 if (hasDragItem_) {
1170 auto stackElement = pipelineContext->GetLastStack();
1171 stackElement->PopComponent();
1172 }
1173 hasDragItem_ = false;
1174
1175 ACE_DCHECK(GetPreDragDropNode() == FindTargetRenderNode<DragDropEvent>(pipelineContext, info));
1176 auto targetDragDropNode = GetPreDragDropNode();
1177 if (!targetDragDropNode) {
1178 return;
1179 }
1180 if (targetDragDropNode->GetOnDrop()) {
1181 auto extraParams = JsonUtil::Create(true);
1182 (targetDragDropNode->GetOnDrop())(event, extraParams->ToString());
1183 }
1184 SetPreDragDropNode(nullptr);
1185 }
1186
PanOnActionCancel()1187 void RenderText::PanOnActionCancel()
1188 {
1189 auto pipelineContext = context_.Upgrade();
1190 if (!pipelineContext) {
1191 LOGE("Context is null.");
1192 return;
1193 }
1194
1195 #if !defined(PREVIEW)
1196 if (isDragDropNode_) {
1197 isDragDropNode_ = false;
1198 RestoreCilpboardData(pipelineContext);
1199 }
1200
1201 if (dragWindow_) {
1202 dragWindow_->Destroy();
1203 dragWindow_ = nullptr;
1204 }
1205 #endif
1206 if (hasDragItem_) {
1207 auto stackElement = pipelineContext->GetLastStack();
1208 stackElement->PopComponent();
1209 hasDragItem_ = false;
1210 }
1211 SetPreDragDropNode(nullptr);
1212 }
1213
CreateSelectRecognizer()1214 void RenderText::CreateSelectRecognizer()
1215 {
1216 if (selectRecognizer_) {
1217 return;
1218 }
1219
1220 auto context = context_.Upgrade();
1221 if (!context) {
1222 return;
1223 }
1224
1225 PanDirection panDirection;
1226 selectRecognizer_ = AceType::MakeRefPtr<OHOS::Ace::PanRecognizer>(context, 1, panDirection, 0);
1227 selectRecognizer_->SetOnActionStart([weak = WeakClaim(this), context = context_](const GestureEvent& info) {
1228 if (info.GetSourceDevice() != SourceType::MOUSE) {
1229 return;
1230 }
1231
1232 auto text = weak.Upgrade();
1233 if (text) {
1234 text->HideTextOverlay();
1235 auto textOverlayManager = text->GetTextOverlayManager(context);
1236 if (textOverlayManager) {
1237 textOverlayManager->SetTextOverlayBase(weak);
1238 }
1239 Offset offset(info.GetGlobalPoint().GetX(), info.GetGlobalPoint().GetY());
1240 text->InitSelection(offset, text->GetGlobalOffset());
1241 }
1242 });
1243 selectRecognizer_->SetOnActionUpdate([weak = WeakClaim(this), context = context_](const GestureEvent& info) {
1244 if (info.GetSourceDevice() != SourceType::MOUSE) {
1245 return;
1246 }
1247
1248 auto text = weak.Upgrade();
1249 if (text) {
1250 Offset offset(info.GetGlobalPoint().GetX(), info.GetGlobalPoint().GetY());
1251 text->UpdateEndSelection(text->GetTextSelect().baseOffset, offset, text->GetGlobalOffset());
1252 text->SetStartOffset(text->GetHandleOffset(text->GetTextSelect().GetStart()));
1253 text->SetEndOffset(text->GetHandleOffset(text->GetTextSelect().GetEnd()));
1254 text->UpdateTextOverlay();
1255 }
1256 });
1257 }
1258
1259 } // namespace OHOS::Ace
1260