• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2023 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/text_pattern.h"
17 
18 #include <cstdint>
19 #include <iterator>
20 #include <stack>
21 #include <string>
22 
23 #include "base/geometry/ng/offset_t.h"
24 #include "base/geometry/ng/rect_t.h"
25 #include "base/geometry/offset.h"
26 #include "base/log/dump_log.h"
27 #include "base/log/log_wrapper.h"
28 #include "base/utils/string_utils.h"
29 #include "base/utils/utils.h"
30 #include "base/window/drag_window.h"
31 #include "core/common/ace_engine_ext.h"
32 #include "core/common/ai/data_detector_mgr.h"
33 #include "core/common/container.h"
34 #include "core/common/container_scope.h"
35 #include "core/common/font_manager.h"
36 #include "core/common/recorder/event_recorder.h"
37 #include "core/common/recorder/node_data_cache.h"
38 #include "core/common/udmf/udmf_client.h"
39 #include "core/common/vibrator/vibrator_utils.h"
40 #include "core/components/common/properties/text_style_parser.h"
41 #include "core/components/text_overlay/text_overlay_theme.h"
42 #include "core/components_ng/base/frame_node.h"
43 #include "core/components_ng/base/inspector_filter.h"
44 #include "core/components_ng/base/ui_node.h"
45 #include "core/components_ng/base/view_stack_processor.h"
46 #include "core/components_ng/event/gesture_event_hub.h"
47 #include "core/components_ng/event/long_press_event.h"
48 #include "core/components_ng/manager/select_overlay/select_overlay_manager.h"
49 #include "core/components_ng/pattern/image/image_layout_property.h"
50 #include "core/components_ng/pattern/rich_editor/paragraph_manager.h"
51 #include "core/components_ng/pattern/rich_editor_drag/rich_editor_drag_info.h"
52 #include "core/components_ng/pattern/rich_editor_drag/rich_editor_drag_pattern.h"
53 #include "core/components_ng/pattern/select_overlay/select_overlay_property.h"
54 #include "core/components_ng/pattern/text/span_node.h"
55 #include "core/components_ng/pattern/text/text_event_hub.h"
56 #include "core/components_ng/pattern/text/text_layout_algorithm.h"
57 #include "core/components_ng/pattern/text/text_layout_property.h"
58 #include "core/components_ng/pattern/text_drag/text_drag_pattern.h"
59 #include "core/components_ng/pattern/text/text_styles.h"
60 #include "core/components_ng/property/property.h"
61 #include "core/event/ace_events.h"
62 #include "core/text/text_emoji_processor.h"
63 #ifdef ENABLE_ROSEN_BACKEND
64 #include "core/components/custom_paint/rosen_render_custom_paint.h"
65 #endif
66 
67 namespace OHOS::Ace::NG {
68 namespace {
69 constexpr double DIMENSION_VALUE = 16.0;
70 constexpr char COPY[] = "copy";
71 constexpr char SELECT_TEXT[] = "selectText";
72 constexpr const char SYMBOL_COLOR[] = "BLACK";
73 constexpr int32_t API_PROTEXTION_GREATER_NINE = 9;
74 const std::u16string SYMBOL_TRANS = u"\uF0001";
75 constexpr float RICH_DEFAULT_SHADOW_COLOR = 0x33000000;
76 constexpr float RICH_DEFAULT_ELEVATION = 120.0f;
77 }; // namespace
78 
~TextPattern()79 TextPattern::~TextPattern()
80 {
81     // node destruct, need to stop text race animation
82     CHECK_NULL_VOID(contentMod_);
83     contentMod_->StopTextRace();
84 }
85 
OnWindowHide()86 void TextPattern::OnWindowHide()
87 {
88     if (magnifierController_) {
89         magnifierController_->RemoveMagnifierFrameNode();
90     }
91     CHECK_NULL_VOID(contentMod_);
92     contentMod_->PauseAnimation();
93     auto host = GetHost();
94     CHECK_NULL_VOID(host);
95     TAG_LOGD(AceLogTag::ACE_TEXT, "OnWindowHide [%{public}d]", host->GetId());
96 }
97 
OnWindowShow()98 void TextPattern::OnWindowShow()
99 {
100     CHECK_NULL_VOID(contentMod_);
101     contentMod_->ResumeAnimation();
102     auto host = GetHost();
103     CHECK_NULL_VOID(host);
104     TAG_LOGD(AceLogTag::ACE_TEXT, "OnWindowShow [%{public}d]", host->GetId());
105 }
106 
OnAttachToFrameNode()107 void TextPattern::OnAttachToFrameNode()
108 {
109     auto pipeline = PipelineContext::GetCurrentContextSafely();
110     CHECK_NULL_VOID(pipeline);
111     pipeline_ = pipeline;
112     auto host = GetHost();
113     CHECK_NULL_VOID(host);
114     auto fontManager = pipeline->GetFontManager();
115     if (fontManager) {
116         fontManager->AddFontNodeNG(host);
117     }
118     if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
119         if (pipeline->GetMinPlatformVersion() > API_PROTEXTION_GREATER_NINE) {
120             host->GetRenderContext()->UpdateClipEdge(true);
121             host->GetRenderContext()->SetClipToFrame(true);
122         }
123     }
124     InitSurfaceChangedCallback();
125     InitSurfacePositionChangedCallback();
126     pipeline->AddWindowStateChangedCallback(host->GetId());
127     auto textLayoutProperty = GetLayoutProperty<TextLayoutProperty>();
128     CHECK_NULL_VOID(textLayoutProperty);
129     textLayoutProperty->UpdateTextAlign(TextAlign::START);
130     textLayoutProperty->UpdateAlignment(Alignment::CENTER_LEFT);
131 }
132 
OnDetachFromFrameNode(FrameNode * node)133 void TextPattern::OnDetachFromFrameNode(FrameNode* node)
134 {
135     dataDetectorAdapter_->aiDetectDelayTask_.Cancel();
136     CloseSelectOverlay();
137     auto pipeline = pipeline_.Upgrade();
138     CHECK_NULL_VOID(pipeline);
139     if (HasSurfaceChangedCallback()) {
140         pipeline->UnregisterSurfaceChangedCallback(surfaceChangedCallbackId_.value_or(-1));
141     }
142     if (HasSurfacePositionChangedCallback()) {
143         pipeline->UnregisterSurfacePositionChangedCallback(surfacePositionChangedCallbackId_.value_or(-1));
144     }
145     auto frameNode = WeakClaim(node);
146     pipeline->RemoveFontNodeNG(frameNode);
147     auto fontManager = pipeline->GetFontManager();
148     if (fontManager) {
149         fontManager->UnRegisterCallbackNG(frameNode);
150         fontManager->RemoveVariationNodeNG(frameNode);
151     }
152     pipeline->RemoveOnAreaChangeNode(node->GetId());
153     pipeline->RemoveWindowStateChangedCallback(node->GetId());
154     pipeline->RemoveVisibleAreaChangeNode(node->GetId());
155 }
156 
CloseSelectOverlay()157 void TextPattern::CloseSelectOverlay()
158 {
159     CloseSelectOverlay(false);
160 }
161 
CloseSelectOverlay(bool animation)162 void TextPattern::CloseSelectOverlay(bool animation)
163 {
164     // Deprecated use selectOverlay_ instead.
165     if (selectOverlayProxy_ && !selectOverlayProxy_->IsClosed()) {
166         selectOverlayProxy_->Close(animation);
167         RemoveAreaChangeInner();
168     }
169     selectOverlay_->CloseOverlay(animation, CloseReason::CLOSE_REASON_NORMAL);
170 }
171 
ResetSelection()172 void TextPattern::ResetSelection()
173 {
174     if (textSelector_.IsValid() && !shiftFlag_) {
175         HandleSelectionChange(-1, -1);
176         auto host = GetHost();
177         CHECK_NULL_VOID(host);
178         host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
179     }
180 }
181 
InitSelection(const Offset & pos)182 void TextPattern::InitSelection(const Offset& pos)
183 {
184     CHECK_NULL_VOID(pManager_);
185     int32_t extend = pManager_->GetGlyphIndexByCoordinate(pos, true);
186     int32_t start = 0;
187     int32_t end = 0;
188     if (!pManager_->GetWordBoundary(extend, start, end)) {
189         start = extend;
190         end = std::min(static_cast<int32_t>(GetWideText().length()) + placeholderCount_,
191             extend + GetGraphemeClusterLength(GetWideText(), extend));
192     }
193     HandleSelectionChange(start, end);
194 }
195 
CalcCaretMetricsByPosition(int32_t extent,CaretMetricsF & caretCaretMetric,TextAffinity textAffinity)196 void TextPattern::CalcCaretMetricsByPosition(int32_t extent, CaretMetricsF& caretCaretMetric, TextAffinity textAffinity)
197 {
198     auto host = GetHost();
199     CHECK_NULL_VOID(host);
200     auto rect = host->GetGeometryNode()->GetFrameRect();
201     CHECK_NULL_VOID(pManager_);
202     auto computeSuccess = pManager_->CalcCaretMetricsByPosition(extent, caretCaretMetric, textAffinity);
203     if (!computeSuccess) {
204         caretCaretMetric = CaretMetricsF(OffsetF(0.0f, rect.Height()), 0.0f);
205     }
206 }
207 
CalculateHandleOffsetAndShowOverlay(bool isUsingMouse)208 void TextPattern::CalculateHandleOffsetAndShowOverlay(bool isUsingMouse)
209 {
210     parentGlobalOffset_ = GetParentGlobalOffset();
211     auto textContentGlobalOffset = selectOverlay_->GetHandleGlobalOffset() + contentRect_.GetOffset();
212     auto paragraphPaintOffset = textContentGlobalOffset - OffsetF(0.0f, std::min(baselineOffset_, 0.0f));
213 
214     // calculate firstHandleOffset, secondHandleOffset and handlePaintSize
215     CaretMetricsF firstHandleMetrics;
216     CaretMetricsF secondHandleMetrics;
217     CalcCaretMetricsByPosition(textSelector_.baseOffset, firstHandleMetrics, TextAffinity::DOWNSTREAM);
218     CalcCaretMetricsByPosition(textSelector_.destinationOffset, secondHandleMetrics, TextAffinity::UPSTREAM);
219     OffsetF firstHandleOffset = firstHandleMetrics.offset + paragraphPaintOffset;
220     OffsetF secondHandleOffset = secondHandleMetrics.offset + paragraphPaintOffset;
221 
222     textSelector_.selectionBaseOffset = firstHandleOffset;
223     textSelector_.selectionDestinationOffset = secondHandleOffset;
224 
225     RectF firstHandle;
226     firstHandle.SetOffset(firstHandleOffset);
227     firstHandle.SetSize({ SelectHandleInfo::GetDefaultLineWidth().ConvertToPx(), firstHandleMetrics.height });
228     firstHandle.SetOffset(OffsetF(firstHandle.GetX() - firstHandle.Width() / 2.0f, firstHandle.GetY()));
229     textSelector_.firstHandle = firstHandle;
230 
231     RectF secondHandle;
232     secondHandle.SetOffset(secondHandleOffset);
233     secondHandle.SetSize({ SelectHandleInfo::GetDefaultLineWidth().ConvertToPx(), secondHandleMetrics.height });
234     secondHandle.SetHeight(secondHandleMetrics.height);
235     secondHandle.SetOffset(OffsetF(secondHandle.GetX() - secondHandle.Width() / 2.0f, secondHandle.GetY()));
236     textSelector_.secondHandle = secondHandle;
237 }
238 
GetSpansInfoInStyledString(int32_t start,int32_t end)239 std::list<ResultObject> TextPattern::GetSpansInfoInStyledString(int32_t start, int32_t end)
240 {
241     std::list<ResultObject> resultObjects;
242     int32_t imageIndex = 0;
243     for (const auto& item : spans_) {
244         auto obj = item->GetSpanResultObject(start, end);
245         if (obj.type == SelectSpanType::TYPEIMAGE) {
246             obj.spanPosition.spanIndex = imageIndex;
247             ++imageIndex;
248         }
249         if (obj.isInit) {
250             resultObjects.emplace_back(obj);
251         }
252     }
253     return resultObjects;
254 }
255 
GetSpansInfo(int32_t start,int32_t end,GetSpansMethod method)256 SelectionInfo TextPattern::GetSpansInfo(int32_t start, int32_t end, GetSpansMethod method)
257 {
258     int32_t index = 0;
259     std::int32_t realEnd = 0;
260     std::int32_t realStart = 0;
261     SelectionInfo selection;
262     std::list<ResultObject> resultObjects;
263     auto length = GetTextContentLength();
264     if (method == GetSpansMethod::GETSPANS) {
265         realStart = (start == -1) ? 0 : start;
266         realEnd = (end == -1) ? length : end;
267         if (realStart > realEnd) {
268             std::swap(realStart, realEnd);
269         }
270         realStart = std::max(0, realStart);
271         realEnd = std::min(length, realEnd);
272     } else if (method == GetSpansMethod::ONSELECT) {
273         realEnd = std::min(length, end);
274         realStart = std::min(length, start);
275     }
276     selection.SetSelectionEnd(realEnd);
277     selection.SetSelectionStart(realStart);
278     if (realStart > length || realEnd < 0 || spans_.empty() || (start > length && end > length) ||
279         (method == GetSpansMethod::ONSELECT && realStart == realEnd)) {
280         selection.SetResultObjectList(resultObjects);
281         return selection;
282     }
283     if (isSpanStringMode_) {
284         auto result = GetSpansInfoInStyledString(realStart, realEnd);
285         selection.SetResultObjectList(result);
286         return selection;
287     }
288     const auto& children = GetAllChildren();
289     for (const auto& uinode : children) {
290         if (uinode->GetTag() == V2::IMAGE_ETS_TAG) {
291             ResultObject resultObject = GetImageResultObject(uinode, index, realStart, realEnd);
292             if (!resultObject.valueString.empty() || resultObject.valuePixelMap) {
293                 resultObjects.emplace_back(resultObject);
294             }
295         } else if (uinode->GetTag() == V2::SPAN_ETS_TAG) {
296             ResultObject resultObject = GetTextResultObject(uinode, index, realStart, realEnd);
297             if (!resultObject.valueString.empty()) {
298                 resultObjects.emplace_back(resultObject);
299             }
300         } else if (uinode->GetTag() == V2::SYMBOL_SPAN_ETS_TAG) {
301             ResultObject resultObject = GetSymbolSpanResultObject(uinode, index, realStart, realEnd);
302             if (!resultObject.valueString.empty()) {
303                 resultObjects.emplace_back(resultObject);
304             }
305         } else if (uinode->GetTag() == V2::PLACEHOLDER_SPAN_ETS_TAG ||
306             uinode->GetTag() == V2::CUSTOM_SPAN_NODE_ETS_TAG) {
307             ResultObject resultObject = GetBuilderResultObject(uinode, index, realStart, realEnd);
308             if (!resultObject.valueString.empty()) {
309                 resultObjects.emplace_back(resultObject);
310             }
311         }
312         index++;
313     }
314     selection.SetResultObjectList(resultObjects);
315     return selection;
316 }
317 
GetTextContentLength()318 int32_t TextPattern::GetTextContentLength()
319 {
320     if (!spans_.empty()) {
321         return static_cast<int32_t>(GetWideText().length()) + placeholderCount_;
322     }
323     return 0;
324 }
325 
StartVibratorByLongPress()326 void TextPattern::StartVibratorByLongPress()
327 {
328     CHECK_NULL_VOID(isEnableHapticFeedback_);
329     VibratorUtils::StartVibraFeedback("longPress.light");
330 }
331 
HandleLongPress(GestureEvent & info)332 void TextPattern::HandleLongPress(GestureEvent& info)
333 {
334     HandleSpanLongPressEvent(info);
335     if (!IsSelectableAndCopy() || isMousePressed_ || selectOverlay_->GetIsHandleDragging()) {
336         return;
337     }
338     auto host = GetHost();
339     CHECK_NULL_VOID(host);
340     auto hub = host->GetEventHub<EventHub>();
341     CHECK_NULL_VOID(hub);
342     auto gestureHub = hub->GetOrCreateGestureEventHub();
343     CHECK_NULL_VOID(gestureHub);
344     auto localOffset = info.GetLocalLocation();
345     if (selectOverlay_->HasRenderTransform()) {
346         localOffset = ConvertGlobalToLocalOffset(info.GetGlobalLocation());
347     }
348 
349     auto textLayoutProperty = GetLayoutProperty<TextLayoutProperty>();
350     if ((textLayoutProperty && textLayoutProperty->GetMaxLines() != 0) && GetWideText().length() != 0) {
351         StartVibratorByLongPress();
352     }
353 
354     if (IsDraggable(localOffset)) {
355         dragBoxes_ = GetTextBoxes();
356         // prevent long press event from being triggered when dragging
357         gestureHub->SetIsTextDraggable(true);
358         return;
359     }
360     gestureHub->SetIsTextDraggable(false);
361     auto textPaintOffset = contentRect_.GetOffset() - OffsetF(0.0f, std::min(baselineOffset_, 0.0f));
362     Offset textOffset = { localOffset.GetX() - textPaintOffset.GetX(), localOffset.GetY() - textPaintOffset.GetY() };
363     InitSelection(textOffset);
364     textResponseType_ = TextResponseType::LONG_PRESS;
365     UpdateSelectionSpanType(std::min(textSelector_.baseOffset, textSelector_.destinationOffset),
366         std::max(textSelector_.baseOffset, textSelector_.destinationOffset));
367     oldSelectedType_ = selectedType_.value_or(TextSpanType::NONE);
368     parentGlobalOffset_ = GetParentGlobalOffset();
369     CalculateHandleOffsetAndShowOverlay();
370     CloseSelectOverlay(true);
371     if (magnifierController_) {
372         magnifierController_->SetLocalOffset({ localOffset.GetX(), localOffset.GetY() });
373     }
374     StartGestureSelection(textSelector_.GetStart(), textSelector_.GetEnd(), localOffset);
375     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
376 }
377 
ShowShadow(const PointF & textOffset,const Color & color)378 bool TextPattern::ShowShadow(const PointF& textOffset, const Color& color)
379 {
380     CHECK_NULL_RETURN(overlayMod_, false);
381     CHECK_NULL_RETURN(hasUrlSpan_, false);
382     CHECK_NULL_RETURN(!spans_.empty() && pManager_, false);
383     int32_t start = 0;
384     for (const auto& item : spans_) {
385         if (!item) {
386             continue;
387         }
388         auto selectedRects = GetSelectedRects(start, item->position);
389         for (auto&& rect : selectedRects) {
390             if (!rect.IsInRegion(textOffset)) {
391                 continue;
392             }
393             if (!item->urlOnRelease) {
394                 overlayMod_->ClearSelectedForegroundColorAndRects();
395                 MarkDirtySelf();
396                 return false;
397             }
398             auto inter = GetStartAndEnd(start);
399             auto rects = GetSelectedRects(inter.first, inter.second);
400             overlayMod_->SetSelectedForegroundColorAndRects(rects, color.GetValue());
401             MarkDirtySelf();
402             return true;
403         }
404         start = item->position;
405     }
406     overlayMod_->ClearSelectedForegroundColorAndRects();
407     MarkDirtySelf();
408     return false;
409 }
410 
GetStartAndEnd(int32_t start)411 std::pair<int32_t, int32_t> TextPattern::GetStartAndEnd(int32_t start)
412 {
413     auto spanBases = styledString_->GetSpans(0, styledString_->GetLength(), SpanType::Url);
414     for (const auto& spanBase : spanBases) {
415         if (start >= spanBase->GetStartIndex() && start < spanBase->GetEndIndex()) {
416             return {spanBase->GetStartIndex(), spanBase->GetEndIndex()};
417         }
418     }
419     return {0, 0};
420 }
421 
HandleSpanLongPressEvent(GestureEvent & info)422 void TextPattern::HandleSpanLongPressEvent(GestureEvent& info)
423 {
424     RectF textContentRect = contentRect_;
425     textContentRect.SetTop(contentRect_.GetY() - std::min(baselineOffset_, 0.0f));
426     textContentRect.SetHeight(contentRect_.Height() - std::max(baselineOffset_, 0.0f));
427 
428     auto localLocation = info.GetLocalLocation();
429     if (selectOverlay_->HasRenderTransform()) {
430         localLocation = ConvertGlobalToLocalOffset(info.GetGlobalLocation());
431     }
432 
433     auto host = GetHost();
434     CHECK_NULL_VOID(host);
435     auto renderContext = host->GetRenderContext();
436     CHECK_NULL_VOID(renderContext);
437     PointF textOffset = { static_cast<float>(localLocation.GetX()) - textContentRect.GetX(),
438         static_cast<float>(localLocation.GetY()) - textContentRect.GetY() };
439     if (renderContext->GetClipEdge().has_value() && !renderContext->GetClipEdge().value() && overlayMod_) {
440         textContentRect = overlayMod_->GetBoundsRect();
441         textContentRect.SetTop(contentRect_.GetY() - std::min(baselineOffset_, 0.0f));
442     }
443     auto longPressFunc = [](RefPtr<SpanItem> item, GestureEvent& info, const RectF& rect,
444                              const PointF& textOffset) -> bool {
445         if (rect.IsInRegion(textOffset)) {
446             if (item && item->onLongPress) {
447                 item->onLongPress(info);
448             }
449             return true;
450         }
451         return false;
452     };
453 
454     if (textContentRect.IsInRegion(
455         PointF(static_cast<float>(localLocation.GetX()), static_cast<float>(localLocation.GetY()))) &&
456         !spans_.empty() && pManager_) {
457         int32_t start = 0;
458         for (const auto& item : spans_) {
459             if (!item) {
460                 continue;
461             }
462             auto selectedRects = GetSelectedRects(start, item->position);
463             for (auto&& rect : selectedRects) {
464                 CHECK_NULL_VOID(!longPressFunc(item, info, rect, textOffset));
465             }
466             start = item->position;
467         }
468     }
469 }
470 
471 // Deprecated: Use the TextSelectOverlay::OnHandleMove() instead.
472 // It is currently used by RichEditorPattern.
OnHandleMove(const RectF & handleRect,bool isFirstHandle)473 void TextPattern::OnHandleMove(const RectF& handleRect, bool isFirstHandle)
474 {
475     auto host = GetHost();
476     CHECK_NULL_VOID(host);
477     auto textContentGlobalOffset = parentGlobalOffset_ + contentRect_.GetOffset();
478     auto textPaintOffset = textContentGlobalOffset - OffsetF(0.0f, std::min(baselineOffset_, 0.0f));
479 
480     auto localOffset = handleRect.GetOffset();
481 
482     auto renderContext = host->GetRenderContext();
483     CHECK_NULL_VOID(renderContext);
484     auto clip = false;
485     if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
486         clip = true;
487     }
488     if (renderContext->GetClipEdge().value_or(clip)) {
489         if (localOffset.GetX() < textContentGlobalOffset.GetX()) {
490             localOffset.SetX(textContentGlobalOffset.GetX());
491         } else if (GreatOrEqual(localOffset.GetX(), textContentGlobalOffset.GetX() + contentRect_.Width())) {
492             localOffset.SetX(textContentGlobalOffset.GetX() + contentRect_.Width());
493         }
494 
495         if (localOffset.GetY() < textContentGlobalOffset.GetY()) {
496             localOffset.SetY(textContentGlobalOffset.GetY());
497         } else if (GreatNotEqual(localOffset.GetY(), textContentGlobalOffset.GetY() + contentRect_.Height())) {
498             localOffset.SetY(textContentGlobalOffset.GetY() + contentRect_.Height());
499         }
500     }
501 
502     localOffset -= textPaintOffset;
503 
504     CHECK_NULL_VOID(pManager_);
505     // the handle position is calculated based on the middle of the handle height.
506     if (isFirstHandle) {
507         auto start = GetHandleIndex(Offset(localOffset.GetX(), localOffset.GetY() +
508             (selectOverlayProxy_->IsHandleReverse() ? handleRect.Height() : 0)));
509         HandleSelectionChange(start, textSelector_.destinationOffset);
510     } else {
511         auto end = GetHandleIndex(Offset(localOffset.GetX(),
512             localOffset.GetY() + (selectOverlayProxy_->IsHandleReverse() || NearEqual(localOffset.GetY(), 0)
513                                          ? 0
514                                          : handleRect.Height())));
515         HandleSelectionChange(textSelector_.baseOffset, end);
516     }
517     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
518 
519     CHECK_NULL_VOID(selectOverlayProxy_);
520     auto start = textSelector_.GetTextStart();
521     auto end = textSelector_.GetTextEnd();
522     selectOverlayProxy_->SetSelectInfo(GetSelectedText(start, end));
523 }
524 
IsSelectAll()525 bool TextPattern::IsSelectAll()
526 {
527     return textSelector_.GetTextStart() == 0 &&
528            textSelector_.GetTextEnd() == static_cast<int32_t>(GetWideText().length()) + placeholderCount_;
529 }
GetWideText() const530 std::wstring TextPattern::GetWideText() const
531 {
532     return StringUtils::ToWstring(textForDisplay_);
533 }
534 
GetSelectedText(int32_t start,int32_t end) const535 std::string TextPattern::GetSelectedText(int32_t start, int32_t end) const
536 {
537     if (spans_.empty()) {
538         auto wideText = GetWideText();
539         auto min = std::clamp(std::max(std::min(start, end), 0), 0, static_cast<int32_t>(wideText.length()));
540         auto max = std::clamp(std::min(std::max(start, end), static_cast<int32_t>(wideText.length())), 0,
541             static_cast<int32_t>(wideText.length()));
542         return StringUtils::ToString(TextEmojiProcessor::SubWstring(min, max - min, wideText));
543     }
544     std::string value;
545     int32_t tag = 0;
546     for (const auto& span : spans_) {
547         if (span->GetSymbolUnicode() != 0) {
548             tag = span->position == -1 ? tag + 1 : span->position;
549             continue;
550         }
551         if (span->position - 1 >= start && span->placeholderIndex == -1 && span->position != -1) {
552             auto wideString = StringUtils::ToWstring(span->GetSpanContent());
553             auto max = std::min(span->position, end);
554             auto min = std::max(start, tag);
555             value += StringUtils::ToString(
556                 wideString.substr(std::clamp((min - tag), 0, static_cast<int32_t>(wideString.length())),
557                     std::clamp((max - min), 0, static_cast<int32_t>(wideString.length()))));
558         } else if (span->position - 1 >= start && span->position != -1) {
559             // image span or custom span (span->placeholderIndex != -1)
560             value += " ";
561         }
562         tag = span->position == -1 ? tag + 1 : span->position;
563         if (span->position >= end) {
564             break;
565         }
566     }
567     return value;
568 }
569 
HandleOnCopy()570 void TextPattern::HandleOnCopy()
571 {
572     CHECK_NULL_VOID(clipboard_);
573     if (textSelector_.IsValid() && textSelector_.GetTextStart() == textSelector_.GetTextEnd()) {
574         HandleSelectionChange(-1, -1);
575         return;
576     }
577     auto value = GetSelectedText(textSelector_.GetTextStart(), textSelector_.GetTextEnd());
578     if (IsSelectableAndCopy() || dataDetectorAdapter_->hasClickedMenuOption_) {
579         if (isSpanStringMode_ && !externalParagraph_) {
580             HandleOnCopySpanString();
581         } else if (!value.empty()) {
582             clipboard_->SetData(value, copyOption_);
583         }
584     }
585     HiddenMenu();
586     CHECK_NULL_VOID(!value.empty());
587     auto host = GetHost();
588     CHECK_NULL_VOID(host);
589     auto eventHub = host->GetEventHub<TextEventHub>();
590     CHECK_NULL_VOID(eventHub);
591     eventHub->FireOnCopy(value);
592 }
593 
HandleOnCopySpanString()594 void TextPattern::HandleOnCopySpanString()
595 {
596     auto subSpanString = styledString_->GetSubSpanString(textSelector_.GetTextStart(),
597         textSelector_.GetTextEnd() - textSelector_.GetTextStart());
598 #if defined(PREVIEW)
599     clipboard_->SetData(subSpanString->GetString(), copyOption_);
600     return;
601 #endif
602     RefPtr<PasteDataMix> pasteData = clipboard_->CreatePasteDataMix();
603     std::vector<uint8_t> tlvData;
604     subSpanString->EncodeTlv(tlvData);
605     clipboard_->AddSpanStringRecord(pasteData, tlvData);
606     clipboard_->AddTextRecord(pasteData, subSpanString->GetString());
607     clipboard_->SetData(pasteData, copyOption_);
608 }
609 
HiddenMenu()610 void TextPattern::HiddenMenu()
611 {
612     if (IsUsingMouse()) {
613         CloseSelectOverlay();
614     } else {
615         selectOverlay_->HideMenu();
616     }
617 }
618 
SetTextSelection(int32_t selectionStart,int32_t selectionEnd)619 void TextPattern::SetTextSelection(int32_t selectionStart, int32_t selectionEnd)
620 {
621     auto host = GetHost();
622     CHECK_NULL_VOID(host);
623     auto eventHub = host->GetEventHub<EventHub>();
624     CHECK_NULL_VOID(eventHub);
625     auto context = PipelineContext::GetCurrentContextSafely();
626     if (context) {
627         context->AddAfterLayoutTask([weak = WeakClaim(this), selectionStart, selectionEnd, eventHub]() {
628             auto textPattern = weak.Upgrade();
629             CHECK_NULL_VOID(textPattern);
630             auto renderContext = textPattern->GetRenderContext();
631             CHECK_NULL_VOID(renderContext);
632             auto obscuredReasons = renderContext->GetObscured().value_or(std::vector<ObscuredReasons>());
633             bool ifHaveObscured = textPattern->GetSpanItemChildren().empty() &&
634                                   std::any_of(obscuredReasons.begin(), obscuredReasons.end(),
635                                       [](const auto& reason) { return reason == ObscuredReasons::PLACEHOLDER; });
636             auto textLayoutProperty = textPattern->GetLayoutProperty<TextLayoutProperty>();
637             CHECK_NULL_VOID(textLayoutProperty);
638             if (textLayoutProperty->GetCalcLayoutConstraint() &&
639                 textLayoutProperty->GetCalcLayoutConstraint()->selfIdealSize.has_value()) {
640                 auto selfIdealSizeWidth = textLayoutProperty->GetCalcLayoutConstraint()->selfIdealSize->Width();
641                 auto selfIdealSizeHeight = textLayoutProperty->GetCalcLayoutConstraint()->selfIdealSize->Height();
642                 auto constraint = textLayoutProperty->GetLayoutConstraint();
643                 if ((selfIdealSizeWidth.has_value() && NearZero(selfIdealSizeWidth->GetDimension().ConvertToPxWithSize(
644                             constraint->percentReference.Width()))) ||
645                     (selfIdealSizeHeight.has_value() &&
646                         NearZero(selfIdealSizeHeight->GetDimension().ConvertToPxWithSize(
647                             constraint->percentReference.Height())))) {
648                     return;
649                 }
650             }
651 
652             auto mode = textLayoutProperty->GetTextSelectableModeValue(TextSelectableMode::SELECTABLE_UNFOCUSABLE);
653             if (mode == TextSelectableMode::UNSELECTABLE ||
654                 textLayoutProperty->GetCopyOptionValue(CopyOptions::None) == CopyOptions::None ||
655                 textLayoutProperty->GetTextOverflowValue(TextOverflow::CLIP) == TextOverflow::MARQUEE) {
656                 return;
657             }
658             if (!ifHaveObscured && eventHub->IsEnabled()) {
659                 textPattern->ActSetSelection(selectionStart, selectionEnd);
660             }
661         });
662     }
663     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
664 }
665 
GetRenderContext()666 RefPtr<RenderContext> TextPattern::GetRenderContext()
667 {
668     auto frameNode = GetHost();
669     CHECK_NULL_RETURN(frameNode, nullptr);
670     return frameNode->GetRenderContext();
671 }
672 
MaxLinesZero()673 bool TextPattern::MaxLinesZero()
674 {
675     auto textLayoutProperty = GetLayoutProperty<TextLayoutProperty>();
676     CHECK_NULL_RETURN(textLayoutProperty, false);
677     if (textLayoutProperty->GetMaxLines() == 0) {
678         CloseSelectOverlay();
679         ResetSelection();
680         return true;
681     }
682     return false;
683 }
684 
ShowSelectOverlay(const OverlayRequest & request)685 void TextPattern::ShowSelectOverlay(const OverlayRequest& request)
686 {
687     auto textLayoutProperty = GetLayoutProperty<TextLayoutProperty>();
688     CHECK_NULL_VOID(textLayoutProperty);
689     if (textLayoutProperty->GetMaxLines() == 0) {
690         CloseSelectOverlay();
691         ResetSelection();
692         return;
693     }
694     selectOverlay_->ProcessOverlay(request);
695 }
696 
HandleOnSelectAll()697 void TextPattern::HandleOnSelectAll()
698 {
699     auto textSize = static_cast<int32_t>(GetWideText().length()) + placeholderCount_;
700     HandleSelectionChange(0, textSize);
701     CalculateHandleOffsetAndShowOverlay();
702     CloseSelectOverlay(true);
703     if (IsUsingMouse()) {
704         if (IsSelected()) {
705             selectOverlay_->SetSelectionHoldCallback();
706         }
707     } else {
708         ShowSelectOverlay({ .animation = true });
709     }
710     auto host = GetHost();
711     CHECK_NULL_VOID(host);
712     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
713 }
714 
IsShowTranslate()715 bool TextPattern::IsShowTranslate()
716 {
717     auto host = GetHost();
718     CHECK_NULL_RETURN(host, false);
719     auto context = host->GetContext();
720     CHECK_NULL_RETURN(context, false);
721     auto textTheme = context->GetTheme<TextTheme>();
722     CHECK_NULL_RETURN(textTheme, false);
723     return textTheme->IsShowTranslate();
724 }
725 
InitLongPressEvent(const RefPtr<GestureEventHub> & gestureHub)726 void TextPattern::InitLongPressEvent(const RefPtr<GestureEventHub>& gestureHub)
727 {
728     constexpr int32_t longPressDelay = 600;
729     if (longPressEvent_) {
730         gestureHub->SetLongPressEvent(longPressEvent_, false, false, longPressDelay);
731         return;
732     }
733     auto longPressCallback = [weak = WeakClaim(this)](GestureEvent& info) {
734         auto pattern = weak.Upgrade();
735         CHECK_NULL_VOID(pattern);
736         pattern->sourceType_ = info.GetSourceDevice();
737         pattern->HandleLongPress(info);
738     };
739     longPressEvent_ = MakeRefPtr<LongPressEvent>(std::move(longPressCallback));
740 
741     // Default time is 500, used by drag event. Drag event would trigger if text is selected, but we want
742     // it to only trigger on the second long press, after selection. Therefore, long press delay of Selection needs to
743     // be slightly longer to ensure that order.
744     gestureHub->SetLongPressEvent(longPressEvent_, false, false, longPressDelay);
745 
746     auto onTextSelectorChange = [weak = WeakClaim(this)]() {
747         auto pattern = weak.Upgrade();
748         CHECK_NULL_VOID(pattern);
749         auto frameNode = pattern->GetHost();
750         CHECK_NULL_VOID(frameNode);
751         frameNode->OnAccessibilityEvent(AccessibilityEventType::TEXT_SELECTION_UPDATE);
752     };
753     textSelector_.SetOnAccessibility(std::move(onTextSelectorChange));
754 }
755 
OnHandleTouchUp()756 void TextPattern::OnHandleTouchUp()
757 {
758     CloseSelectOverlay();
759     ResetSelection();
760 }
761 
HandleClickEvent(GestureEvent & info)762 void TextPattern::HandleClickEvent(GestureEvent& info)
763 {
764     if ((selectOverlay_->IsClickAtHandle(info) && !multipleClickRecognizer_->IsRunning()) ||
765         selectOverlay_->GetIsHandleDragging()) {
766         return;
767     }
768     if (dataDetectorAdapter_->hasClickedAISpan_) {
769         dataDetectorAdapter_->hasClickedAISpan_ = false;
770     }
771     multipleClickRecognizer_->Start(info);
772     if (multipleClickRecognizer_->IsDoubleClick()) {
773         HandleDoubleClickEvent(info);
774     } else {
775         HandleSingleClickEvent(info);
776     }
777 }
778 
HandleUrlClick()779 bool TextPattern::HandleUrlClick()
780 {
781     if (LessNotEqual(clickedSpanPosition_, 0)) {
782         return false;
783     }
784     auto iter = spans_.begin();
785     std::advance(iter, clickedSpanPosition_);
786     RefPtr<SpanItem> span;
787     if (iter == spans_.end()) {
788         span = spans_.back();
789     } else {
790         span = *iter;
791     }
792     if (span && span->urlOnRelease) {
793         span->urlOnRelease();
794         return true;
795     }
796     return false;
797 }
798 
HandleSingleClickEvent(GestureEvent & info)799 void TextPattern::HandleSingleClickEvent(GestureEvent& info)
800 {
801     RectF textContentRect = contentRect_;
802     textContentRect.SetTop(contentRect_.GetY() - std::min(baselineOffset_, 0.0f));
803     textContentRect.SetHeight(contentRect_.Height() - std::max(baselineOffset_, 0.0f));
804     PointF textOffset = { info.GetLocalLocation().GetX() - textContentRect.GetX(),
805         info.GetLocalLocation().GetY() - textContentRect.GetY() };
806     if (IsSelectableAndCopy()) {
807         CheckClickedOnSpanOrText(textContentRect, info.GetLocalLocation());
808     }
809     if (HandleUrlClick()) {
810         return;
811     }
812     if (selectOverlay_->SelectOverlayIsOn() && !selectOverlay_->IsUsingMouse() &&
813         BetweenSelectedPosition(info.GetGlobalLocation())) {
814         if (dataDetectorAdapter_->GetCloseMenuForAISpanFlag()) {
815             selectOverlay_->EnableMenu();
816             dataDetectorAdapter_->SetCloseMenuForAISpanFlag(false);
817             return;
818         }
819         selectOverlay_->ToggleMenu();
820         selectOverlay_->SwitchToOverlayMode();
821         return;
822     }
823     if (!isMousePressed_) {
824         HandleClickAISpanEvent(textOffset);
825     }
826     if (dataDetectorAdapter_->hasClickedAISpan_) {
827         selectOverlay_->DisableMenu();
828         dataDetectorAdapter_->SetCloseMenuForAISpanFlag(true);
829         return;
830     }
831     HandleClickOnTextAndSpan(info);
832 }
833 
HandleClickOnTextAndSpan(GestureEvent & info)834 void TextPattern::HandleClickOnTextAndSpan(GestureEvent& info)
835 {
836     if (textSelector_.IsValid() && mouseStatus_ != MouseStatus::MOVE && !isMousePressed_) {
837         CloseSelectOverlay(true);
838         ResetSelection();
839     }
840     if (clickedSpanPosition_ == -1) {
841         ActTextOnClick(info);
842         return;
843     }
844     auto iter = spans_.begin();
845     std::advance(iter, clickedSpanPosition_);
846     RefPtr<SpanItem> span;
847     if (iter == spans_.end()) {
848         span = spans_.back();
849     } else {
850         span = *iter;
851     }
852     if (span && span->onClick) {
853         GestureEvent spanClickinfo = info;
854         EventTarget target = info.GetTarget();
855         target.area.SetWidth(Dimension(0.0f));
856         target.area.SetHeight(Dimension(0.0f));
857         spanClickinfo.SetTarget(target);
858         span->onClick(spanClickinfo);
859         RecordSpanClickEvent(span);
860     } else {
861         ActTextOnClick(info);
862     }
863 }
864 
ActTextOnClick(GestureEvent & info)865 void TextPattern::ActTextOnClick(GestureEvent& info)
866 {
867     if (onClick_) {
868         auto onClick = onClick_;
869         onClick(info);
870         RecordClickEvent();
871     }
872 }
873 
RecordClickEvent()874 void TextPattern::RecordClickEvent()
875 {
876     if (Recorder::EventRecorder::Get().IsComponentRecordEnable()) {
877         auto host = GetHost();
878         CHECK_NULL_VOID(host);
879         auto text = host->GetAccessibilityProperty<NG::AccessibilityProperty>()->GetText();
880         Recorder::EventParamsBuilder builder;
881         builder.SetId(host->GetInspectorIdValue(""))
882             .SetType(host->GetTag())
883             .SetText(text)
884             .SetDescription(host->GetAutoEventParamValue(""));
885         Recorder::EventRecorder::Get().OnClick(std::move(builder));
886     }
887 }
888 
RecordSpanClickEvent(const RefPtr<SpanItem> & span)889 void TextPattern::RecordSpanClickEvent(const RefPtr<SpanItem>& span)
890 {
891     if (Recorder::EventRecorder::Get().IsComponentRecordEnable()) {
892         Recorder::EventParamsBuilder builder;
893         builder.SetId(span->inspectId).SetText(span->content).SetDescription(span->description);
894         Recorder::EventRecorder::Get().OnClick(std::move(builder));
895     }
896 }
897 
HandleClickAISpanEvent(const PointF & textOffset)898 void TextPattern::HandleClickAISpanEvent(const PointF& textOffset)
899 {
900     dataDetectorAdapter_->hasClickedAISpan_ = false;
901     if (!NeedShowAIDetect() || mouseStatus_ == MouseStatus::MOVE || IsDragging()) {
902         return;
903     }
904 
905     for (const auto& kv : dataDetectorAdapter_->aiSpanMap_) {
906         auto& aiSpan = kv.second;
907         ClickAISpan(textOffset, aiSpan);
908         if (dataDetectorAdapter_->hasClickedAISpan_) {
909             return;
910         }
911     }
912 }
913 
CheckClickedOnSpanOrText(RectF textContentRect,const Offset & localLocation)914 bool TextPattern::CheckClickedOnSpanOrText(RectF textContentRect, const Offset& localLocation)
915 {
916     clickedSpanPosition_ = -1;
917     auto host = GetHost();
918     CHECK_NULL_RETURN(host, false);
919     auto renderContext = host->GetRenderContext();
920     CHECK_NULL_RETURN(host, false);
921     PointF textOffset = GetTextOffset(localLocation, textContentRect);
922     auto clip = false;
923     if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
924         clip = true;
925     }
926     if (renderContext->GetClipEdge().has_value() && !renderContext->GetClipEdge().value_or(clip) && overlayMod_) {
927         textContentRect = overlayMod_->GetBoundsRect();
928         textContentRect.SetTop(contentRect_.GetY() - std::min(baselineOffset_, 0.0f));
929     }
930     if (textContentRect.IsInRegion(
931         PointF(static_cast<float>(localLocation.GetX()), static_cast<float>(localLocation.GetY()))) &&
932         !spans_.empty() && pManager_) {
933         if (CalculateClickedSpanPosition(textOffset)) {
934             return true;
935         }
936     }
937     if (onClick_) {
938         return true;
939     }
940     return false;
941 }
942 
GetTextOffset(const Offset & localLocation,const RectF & contentRect)943 PointF TextPattern::GetTextOffset(const Offset &localLocation, const RectF &contentRect)
944 {
945     PointF textOffset = {static_cast<float>(localLocation.GetX()) - contentRect.GetX(),
946                          static_cast<float>(localLocation.GetY()) - contentRect.GetY()};
947     return textOffset;
948 }
949 
CalculateClickedSpanPosition(const PointF & textOffset)950 bool TextPattern::CalculateClickedSpanPosition(const PointF& textOffset)
951 {
952     int32_t start = 0;
953     for (const auto& item : spans_) {
954         clickedSpanPosition_++;
955         if (!item) {
956             continue;
957         }
958         auto end = isSpanStringMode_ && item->position == -1 ? item->interval.second : item->position;
959         auto selectedRects = GetSelectedRects(start, end);
960         start = end;
961         for (auto&& rect : selectedRects) {
962             if (!rect.IsInRegion(textOffset)) {
963                 continue;
964             }
965             return CheckAndClick(item);
966         }
967     }
968     clickedSpanPosition_ = -1;
969     return false;
970 }
971 
CheckAndClick(const RefPtr<SpanItem> & item)972 bool TextPattern::CheckAndClick(const RefPtr<SpanItem>& item)
973 {
974     if (item->onClick || item->urlOnRelease) {
975         return true;
976     }
977     clickedSpanPosition_ = -1;
978     return false;
979 }
980 
GetSelectedRects(int32_t start,int32_t end)981 std::vector<RectF> TextPattern::GetSelectedRects(int32_t start, int32_t end)
982 {
983     return pManager_->GetRects(start, end);
984 }
985 
ClickAISpan(const PointF & textOffset,const AISpan & aiSpan)986 bool TextPattern::ClickAISpan(const PointF& textOffset, const AISpan& aiSpan)
987 {
988     auto aiRects = pManager_->GetRects(aiSpan.start, aiSpan.end);
989     for (auto&& rect : aiRects) {
990         if (rect.IsInRegion(textOffset)) {
991             dataDetectorAdapter_->hasClickedAISpan_ = true;
992             if (leftMousePressed_) {
993                 dataDetectorAdapter_->ResponseBestMatchItem(aiSpan);
994                 return true;
995             }
996             return ShowAIEntityMenu(aiSpan);
997         }
998     }
999     return false;
1000 }
InitUrlMouseEvent()1001 void TextPattern::InitUrlMouseEvent()
1002 {
1003     CHECK_NULL_VOID(!urlMouseEventInitialized_);
1004     auto host = GetHost();
1005     CHECK_NULL_VOID(host);
1006     auto eventHub = host->GetEventHub<EventHub>();
1007     CHECK_NULL_VOID(eventHub);
1008     auto inputHub = eventHub->GetOrCreateInputEventHub();
1009     CHECK_NULL_VOID(inputHub);
1010     auto mouseTask = [weak = WeakClaim(this)](MouseInfo& info) {
1011         auto pattern = weak.Upgrade();
1012         if (pattern) {
1013             pattern->HandleUrlMouseEvent(info);
1014         }
1015     };
1016     auto mouseEvent = MakeRefPtr<InputEvent>(std::move(mouseTask));
1017     inputHub->AddOnMouseEvent(mouseEvent);
1018     auto mouseHoverTask = [weak = WeakClaim(this)](bool isHover) {
1019         auto pattern = weak.Upgrade();
1020         CHECK_NULL_VOID(pattern);
1021         pattern->URLOnHover(isHover);
1022     };
1023     auto mouseHoverEvent = MakeRefPtr<InputEvent>(std::move(mouseHoverTask));
1024     inputHub->AddOnHoverEvent(mouseHoverEvent);
1025     urlMouseEventInitialized_ = true;
1026 }
1027 
URLOnHover(bool isHover)1028 void TextPattern::URLOnHover(bool isHover)
1029 {
1030     CHECK_NULL_VOID(!isHover);
1031     auto host = GetHost();
1032     CHECK_NULL_VOID(host);
1033     auto nodeId = host->GetId();
1034     auto pipelineContext = PipelineContext::GetCurrentContextSafely();
1035     CHECK_NULL_VOID(pipelineContext);
1036     pipelineContext->ChangeMouseStyle(nodeId, MouseFormat::DEFAULT);
1037     pipelineContext->FreeMouseStyleHoldNode(nodeId);
1038     CHECK_NULL_VOID(overlayMod_);
1039     overlayMod_->ClearSelectedForegroundColorAndRects();
1040     MarkDirtySelf();
1041 }
1042 
HandleUrlMouseEvent(const MouseInfo & info)1043 void TextPattern::HandleUrlMouseEvent(const MouseInfo& info)
1044 {
1045     RectF textContentRect = contentRect_;
1046     textContentRect.SetTop(contentRect_.GetY() - std::min(baselineOffset_, 0.0f));
1047     textContentRect.SetHeight(contentRect_.Height() - std::max(baselineOffset_, 0.0f));
1048     auto localLocation = info.GetLocalLocation();
1049     if (selectOverlay_->HasRenderTransform()) {
1050         localLocation = ConvertGlobalToLocalOffset(info.GetGlobalLocation());
1051     }
1052     auto host = GetHost();
1053     CHECK_NULL_VOID(host);
1054     auto hostId = host->GetId();
1055     auto renderContext = host->GetRenderContext();
1056     CHECK_NULL_VOID(renderContext);
1057     PointF textOffset = { static_cast<float>(localLocation.GetX()) - textContentRect.GetX(),
1058         static_cast<float>(localLocation.GetY()) - textContentRect.GetY() };
1059     auto show = ShowShadow(textOffset, GetUrlHoverColor());
1060     auto pipelineContext = PipelineContext::GetCurrentContextSafely();
1061     CHECK_NULL_VOID(pipelineContext);
1062     if (show) {
1063         pipelineContext->SetMouseStyleHoldNode(hostId);
1064         pipelineContext->ChangeMouseStyle(hostId, MouseFormat::HAND_POINTING);
1065     } else {
1066         pipelineContext->ChangeMouseStyle(hostId, MouseFormat::DEFAULT);
1067         pipelineContext->FreeMouseStyleHoldNode(hostId);
1068     }
1069 }
1070 
HandleUrlTouchEvent(const TouchEventInfo & info)1071 void TextPattern::HandleUrlTouchEvent(const TouchEventInfo& info)
1072 {
1073     CHECK_NULL_VOID(overlayMod_);
1074     CHECK_NULL_VOID(!IsDragging());
1075     if (selectOverlay_->IsTouchAtHandle(info)) {
1076         return;
1077     }
1078     auto touchType = info.GetTouches().front().GetTouchType();
1079     if (touchType != TouchType::DOWN && touchType != TouchType::UP) {
1080         return;
1081     }
1082     if (touchType == TouchType::DOWN) {
1083         RectF textContentRect = contentRect_;
1084         auto touchOffset = info.GetTouches().front().GetLocalLocation();
1085         PointF textOffset = { static_cast<float>(touchOffset.GetX()) - textContentRect.GetX(),
1086             static_cast<float>(touchOffset.GetY()) - textContentRect.GetY() };
1087         ShowShadow(textOffset, GetUrlPressColor());
1088     } else {
1089         overlayMod_->ClearSelectedForegroundColorAndRects();
1090         MarkDirtySelf();
1091     }
1092 }
1093 
SetOnClickMenu(const AISpan & aiSpan,const CalculateHandleFunc & calculateHandleFunc,const ShowSelectOverlayFunc & showSelectOverlayFunc)1094 void TextPattern::SetOnClickMenu(const AISpan& aiSpan, const CalculateHandleFunc& calculateHandleFunc,
1095     const ShowSelectOverlayFunc& showSelectOverlayFunc)
1096 
1097 {
1098     dataDetectorAdapter_->onClickMenu_ = [aiSpan, weak = WeakClaim(this), calculateHandleFunc, showSelectOverlayFunc](
1099                                              const std::string& action) {
1100         auto pattern = weak.Upgrade();
1101         CHECK_NULL_VOID(pattern);
1102         pattern->CloseSelectOverlay();
1103         pattern->HandleSelectionChange(aiSpan.start, aiSpan.end);
1104         if (action == COPY) {
1105             pattern->HandleOnCopy();
1106             pattern->ResetSelection();
1107         } else if (action == SELECT_TEXT) {
1108             if (calculateHandleFunc == nullptr) {
1109                 pattern->CalculateHandleOffsetAndShowOverlay();
1110             } else {
1111                 calculateHandleFunc();
1112             }
1113             if (showSelectOverlayFunc == nullptr) {
1114                 pattern->ShowSelectOverlay({ .animation = true });
1115             } else {
1116                 showSelectOverlayFunc(pattern->textSelector_.firstHandle, pattern->textSelector_.secondHandle);
1117             }
1118             auto frameNode = pattern->GetHost();
1119             CHECK_NULL_VOID(frameNode);
1120             frameNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1121         }
1122     };
1123 }
1124 
ShowAIEntityMenu(const AISpan & aiSpan,const CalculateHandleFunc & calculateHandleFunc,const ShowSelectOverlayFunc & showSelectOverlayFunc)1125 bool TextPattern::ShowAIEntityMenu(const AISpan& aiSpan, const CalculateHandleFunc& calculateHandleFunc,
1126     const ShowSelectOverlayFunc& showSelectOverlayFunc)
1127 {
1128     auto host = GetHost();
1129     CHECK_NULL_RETURN(host, false);
1130     SetOnClickMenu(aiSpan, calculateHandleFunc, showSelectOverlayFunc);
1131     auto baseOffset = textSelector_.baseOffset;
1132     auto destinationOffset = textSelector_.destinationOffset;
1133     HandleSelectionChange(aiSpan.start, aiSpan.end);
1134     parentGlobalOffset_ = GetParentGlobalOffset();
1135     if (calculateHandleFunc == nullptr) {
1136         CalculateHandleOffsetAndShowOverlay();
1137     } else {
1138         calculateHandleFunc();
1139     }
1140     HandleSelectionChange(baseOffset, destinationOffset);
1141     RectF aiRect;
1142     if (textSelector_.firstHandle.Top() != textSelector_.secondHandle.Top()) {
1143         auto top = std::min(textSelector_.firstHandle.Top(), textSelector_.secondHandle.Top());
1144         auto bottom = std::max(textSelector_.firstHandle.Bottom(), textSelector_.secondHandle.Bottom());
1145         auto textContentGlobalOffset = parentGlobalOffset_ + contentRect_.GetOffset();
1146         auto left = textContentGlobalOffset.GetX();
1147         auto right = textContentGlobalOffset.GetY() + contentRect_.Width();
1148         aiRect = RectT(left, top, right - left, bottom - top);
1149     } else {
1150         aiRect = textSelector_.firstHandle.CombineRectT(textSelector_.secondHandle);
1151     }
1152     if (calculateHandleFunc == nullptr) {
1153         CalculateHandleOffsetAndShowOverlay();
1154     }
1155     bool isShowCopy = true;
1156     bool isShowSelectText = true;
1157     auto textLayoutProperty = GetLayoutProperty<TextLayoutProperty>();
1158     CHECK_NULL_RETURN(textLayoutProperty, false);
1159     auto mode = textLayoutProperty->GetTextSelectableModeValue(TextSelectableMode::SELECTABLE_UNFOCUSABLE);
1160     if (copyOption_ == CopyOptions::None) {
1161         isShowCopy = false;
1162         isShowSelectText = false;
1163     } else if (mode == TextSelectableMode::UNSELECTABLE) {
1164         isShowSelectText = false;
1165     }
1166     return dataDetectorAdapter_->ShowAIEntityMenu(aiSpan, aiRect, host, isShowCopy, isShowSelectText);
1167 }
1168 
HandleDoubleClickEvent(GestureEvent & info)1169 void TextPattern::HandleDoubleClickEvent(GestureEvent& info)
1170 {
1171     CheckOnClickEvent(info);
1172     if (!IsSelectableAndCopy() || textForDisplay_.empty()) {
1173         return;
1174     }
1175     auto host = GetHost();
1176     CHECK_NULL_VOID(host);
1177     auto hub = host->GetEventHub<EventHub>();
1178     CHECK_NULL_VOID(hub);
1179     auto gestureHub = hub->GetOrCreateGestureEventHub();
1180     CHECK_NULL_VOID(gestureHub);
1181     isDoubleClick_ = true;
1182     auto textPaintOffset = contentRect_.GetOffset() - OffsetF(0.0f, std::min(baselineOffset_, 0.0f));
1183     Offset textOffset = { info.GetLocalLocation().GetX() - textPaintOffset.GetX(),
1184         info.GetLocalLocation().GetY() - textPaintOffset.GetY() };
1185     InitSelection(textOffset);
1186     textResponseType_ = TextResponseType::NONE;
1187     UpdateSelectionSpanType(std::min(textSelector_.baseOffset, textSelector_.destinationOffset),
1188         std::max(textSelector_.baseOffset, textSelector_.destinationOffset));
1189     parentGlobalOffset_ = GetParentGlobalOffset();
1190     CalculateHandleOffsetAndShowOverlay();
1191     if (!isMousePressed_) {
1192         ShowSelectOverlay({ .animation = true });
1193     }
1194     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1195 }
1196 
CheckOnClickEvent(GestureEvent & info)1197 void TextPattern::CheckOnClickEvent(GestureEvent& info)
1198 {
1199     RectF textContentRect = contentRect_;
1200     textContentRect.SetTop(contentRect_.GetY() - std::min(baselineOffset_, 0.0f));
1201     textContentRect.SetHeight(contentRect_.Height() - std::max(baselineOffset_, 0.0f));
1202     PointF textOffset = { info.GetLocalLocation().GetX() - textContentRect.GetX(),
1203         info.GetLocalLocation().GetY() - textContentRect.GetY() };
1204     if (IsSelectableAndCopy()) {
1205         CheckClickedOnSpanOrText(textContentRect, info.GetLocalLocation());
1206     }
1207     HandleClickOnTextAndSpan(info);
1208 }
1209 
InitClickEvent(const RefPtr<GestureEventHub> & gestureHub)1210 void TextPattern::InitClickEvent(const RefPtr<GestureEventHub>& gestureHub)
1211 {
1212     CHECK_NULL_VOID(!clickEventInitialized_);
1213     auto clickCallback = [weak = WeakClaim(this)](GestureEvent& info) {
1214         auto pattern = weak.Upgrade();
1215         CHECK_NULL_VOID(pattern);
1216         pattern->sourceType_ = info.GetSourceDevice();
1217         pattern->HandleClickEvent(info);
1218     };
1219 
1220     auto clickListener = MakeRefPtr<ClickEvent>(std::move(clickCallback));
1221     clickListener->SetSysJudge([weak = WeakClaim(this)](const RefPtr<GestureInfo>& gestureInfo,
1222                                    const std::shared_ptr<BaseGestureEvent>& info) -> GestureJudgeResult {
1223         auto textPattern = weak.Upgrade();
1224         CHECK_NULL_RETURN(textPattern, GestureJudgeResult::CONTINUE);
1225         if (info->GetFingerList().empty()) {
1226             return GestureJudgeResult::CONTINUE;
1227         }
1228         auto localLocation = info->GetFingerList().begin()->localLocation_;
1229         auto contentRect = textPattern->GetTextContentRect();
1230         auto baselineOffset = textPattern->GetBaselineOffset();
1231 
1232         RectF textContentRect = contentRect;
1233         textContentRect.SetTop(contentRect.GetY() - std::min(baselineOffset, 0.0f));
1234         textContentRect.SetHeight(contentRect.Height() - std::max(baselineOffset, 0.0f));
1235         if (textPattern->GetCopyOptions() == CopyOptions::None && !textPattern->NeedShowAIDetect() &&
1236             !textPattern->CheckClickedOnSpanOrText(textContentRect, localLocation)) {
1237             return GestureJudgeResult::REJECT;
1238         }
1239         return GestureJudgeResult::CONTINUE;
1240     });
1241     gestureHub->AddClickEvent(clickListener);
1242     clickEventInitialized_ = true;
1243 }
1244 
InitMouseEvent()1245 void TextPattern::InitMouseEvent()
1246 {
1247     CHECK_NULL_VOID(!mouseEventInitialized_);
1248     auto host = GetHost();
1249     CHECK_NULL_VOID(host);
1250     auto eventHub = host->GetEventHub<EventHub>();
1251     CHECK_NULL_VOID(eventHub);
1252     auto inputHub = eventHub->GetOrCreateInputEventHub();
1253     CHECK_NULL_VOID(inputHub);
1254 
1255     auto mouseTask = [weak = WeakClaim(this)](MouseInfo& info) {
1256         auto pattern = weak.Upgrade();
1257         CHECK_NULL_VOID(pattern);
1258         pattern->HandleMouseEvent(info);
1259     };
1260     auto mouseEvent = MakeRefPtr<InputEvent>(std::move(mouseTask));
1261     inputHub->AddOnMouseEvent(mouseEvent);
1262     mouseEventInitialized_ = true;
1263 }
1264 
HandleMouseEvent(const MouseInfo & info)1265 void TextPattern::HandleMouseEvent(const MouseInfo& info)
1266 {
1267     auto textPaintOffset = contentRect_.GetOffset() - OffsetF(0.0f, std::min(baselineOffset_, 0.0f));
1268     Offset textOffset = { info.GetLocalLocation().GetX() - textPaintOffset.GetX(),
1269         info.GetLocalLocation().GetY() - textPaintOffset.GetY() };
1270     if (info.GetButton() == MouseButton::LEFT_BUTTON) {
1271         HandleMouseLeftButton(info, textOffset);
1272         if (IsSelected()) {
1273             selectOverlay_->SetSelectionHoldCallback();
1274         }
1275         sourceType_ = info.GetSourceDevice();
1276     } else if (info.GetButton() == MouseButton::RIGHT_BUTTON) {
1277         HandleMouseRightButton(info, textOffset);
1278         sourceType_ = info.GetSourceDevice();
1279     }
1280 }
1281 
HandleMouseLeftButton(const MouseInfo & info,const Offset & textOffset)1282 void TextPattern::HandleMouseLeftButton(const MouseInfo& info, const Offset& textOffset)
1283 {
1284     if (info.GetAction() == MouseAction::PRESS) {
1285         HandleMouseLeftPressAction(info, textOffset);
1286     } else if (info.GetAction() == MouseAction::MOVE) {
1287         HandleMouseLeftMoveAction(info, textOffset);
1288     } else if (info.GetAction() == MouseAction::RELEASE) {
1289         HandleMouseLeftReleaseAction(info, textOffset);
1290     }
1291 
1292     auto host = GetHost();
1293     CHECK_NULL_VOID(host);
1294     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1295 }
1296 
HandleMouseLeftPressAction(const MouseInfo & info,const Offset & textOffset)1297 void TextPattern::HandleMouseLeftPressAction(const MouseInfo& info, const Offset& textOffset)
1298 {
1299     isMousePressed_ = true;
1300     leftMousePressed_ = true;
1301     if (BetweenSelectedPosition(info.GetGlobalLocation())) {
1302         blockPress_ = true;
1303         return;
1304     }
1305     mouseStatus_ = MouseStatus::PRESSED;
1306     CHECK_NULL_VOID(pManager_);
1307     if (shiftFlag_) {
1308         auto end = pManager_->GetGlyphIndexByCoordinate(textOffset);
1309         HandleSelectionChange(textSelector_.baseOffset, end);
1310     } else {
1311         auto start = pManager_->GetGlyphIndexByCoordinate(textOffset);
1312         textSelector_.Update(start, start);
1313     }
1314     // auto scroll.
1315     scrollableParent_ = selectOverlay_->FindScrollableParent();
1316     auto host = GetHost();
1317     if (scrollableParent_.Upgrade() && host) {
1318         host->RegisterNodeChangeListener();
1319     }
1320 }
1321 
HandleMouseLeftReleaseAction(const MouseInfo & info,const Offset & textOffset)1322 void TextPattern::HandleMouseLeftReleaseAction(const MouseInfo& info, const Offset& textOffset)
1323 {
1324     if (blockPress_) {
1325         blockPress_ = false;
1326     }
1327     auto oldMouseStatus = mouseStatus_;
1328     mouseStatus_ = MouseStatus::RELEASED;
1329     if (isDoubleClick_) {
1330         isDoubleClick_ = false;
1331         isMousePressed_ = false;
1332         leftMousePressed_ = false;
1333         return;
1334     }
1335     if (oldMouseStatus != MouseStatus::MOVE && oldMouseStatus == MouseStatus::PRESSED && !IsDragging()) {
1336         HandleClickAISpanEvent(PointF(textOffset.GetX(), textOffset.GetY()));
1337         if (dataDetectorAdapter_->hasClickedAISpan_) {
1338             selectOverlay_->DisableMenu();
1339             isMousePressed_ = false;
1340             leftMousePressed_ = false;
1341             return;
1342         }
1343     }
1344 
1345     CHECK_NULL_VOID(pManager_);
1346     auto start = textSelector_.baseOffset;
1347     auto end = textSelector_.destinationOffset;
1348     if (!IsSelected() && !textSelector_.IsValid()) {
1349         start = -1;
1350         end = -1;
1351     }
1352     if (isMousePressed_ || oldMouseStatus == MouseStatus::MOVE || shiftFlag_) {
1353         HandleSelectionChange(start, end);
1354     }
1355 
1356     if (IsSelected() && oldMouseStatus == MouseStatus::MOVE && IsSelectedBindSelectionMenu()) {
1357         selectOverlay_->SetMouseMenuOffset(OffsetF(
1358             static_cast<float>(info.GetGlobalLocation().GetX()), static_cast<float>(info.GetGlobalLocation().GetY())));
1359         textResponseType_ = TextResponseType::SELECTED_BY_MOUSE;
1360         ShowSelectOverlay({ .animation = true });
1361     }
1362     isMousePressed_ = false;
1363     leftMousePressed_ = false;
1364 }
1365 
HandleMouseLeftMoveAction(const MouseInfo & info,const Offset & textOffset)1366 void TextPattern::HandleMouseLeftMoveAction(const MouseInfo& info, const Offset& textOffset)
1367 {
1368     if (!IsSelectableAndCopy()) {
1369         isMousePressed_ = false;
1370         leftMousePressed_ = false;
1371         return;
1372     }
1373     if (blockPress_ && !shiftFlag_) {
1374         dragBoxes_ = GetTextBoxes();
1375         return;
1376     }
1377     if (isMousePressed_) {
1378         mouseStatus_ = MouseStatus::MOVE;
1379         CHECK_NULL_VOID(pManager_);
1380         auto end = pManager_->GetGlyphIndexByCoordinate(textOffset);
1381         HandleSelectionChange(textSelector_.baseOffset, end);
1382     }
1383 }
1384 
HandleMouseRightButton(const MouseInfo & info,const Offset & textOffset)1385 void TextPattern::HandleMouseRightButton(const MouseInfo& info, const Offset& textOffset)
1386 {
1387     if (info.GetAction() == MouseAction::RELEASE) {
1388         selectOverlay_->SetMouseMenuOffset(OffsetF(
1389             static_cast<float>(info.GetGlobalLocation().GetX()), static_cast<float>(info.GetGlobalLocation().GetY())));
1390         if (!BetweenSelectedPosition(info.GetGlobalLocation())) {
1391             HandleClickAISpanEvent(PointF(textOffset.GetX(), textOffset.GetY()));
1392             if (dataDetectorAdapter_->hasClickedAISpan_) {
1393                 isMousePressed_ = false;
1394                 return;
1395             }
1396         }
1397         if (!IsSelectableAndCopy()) {
1398             return;
1399         }
1400 
1401         CalculateHandleOffsetAndShowOverlay(true);
1402         if (selectOverlay_->SelectOverlayIsOn()) {
1403             CloseSelectOverlay(true);
1404         }
1405         textResponseType_ = TextResponseType::RIGHT_CLICK;
1406         if (!IsSelected()) {
1407             auto spanNode = DynamicCast<FrameNode>(GetChildByIndex(GetSelectionSpanItemIndex(info)));
1408             if (spanNode && spanNode->GetTag() == V2::IMAGE_ETS_TAG) {
1409                 selectedType_ = TextSpanType::IMAGE;
1410             } else {
1411                 selectedType_ = TextSpanType::TEXT;
1412             }
1413         }
1414         ShowSelectOverlay({ .animation = true });
1415         isMousePressed_ = false;
1416         auto host = GetHost();
1417         CHECK_NULL_VOID(host);
1418         host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1419     } else if (info.GetAction() == MouseAction::PRESS) {
1420         isMousePressed_ = true;
1421         CloseSelectOverlay(true);
1422     }
1423 }
1424 
InitTouchEvent()1425 void TextPattern::InitTouchEvent()
1426 {
1427     CHECK_NULL_VOID(!touchEventInitialized_);
1428     auto host = GetHost();
1429     CHECK_NULL_VOID(host);
1430     auto gesture = host->GetOrCreateGestureEventHub();
1431     CHECK_NULL_VOID(gesture);
1432 
1433     auto touchTask = [weak = WeakClaim(this)](const TouchEventInfo& info) {
1434         auto pattern = weak.Upgrade();
1435         CHECK_NULL_VOID(pattern);
1436         pattern->sourceType_ = info.GetSourceDevice();
1437         pattern->HandleTouchEvent(info);
1438     };
1439     auto touchListener = MakeRefPtr<TouchEventImpl>(std::move(touchTask));
1440     gesture->AddTouchEvent(touchListener);
1441     touchEventInitialized_ = true;
1442 }
1443 
InitUrlTouchEvent()1444 void TextPattern::InitUrlTouchEvent()
1445 {
1446     CHECK_NULL_VOID(!urlTouchEventInitialized_);
1447     auto host = GetHost();
1448     CHECK_NULL_VOID(host);
1449     auto gesture = host->GetOrCreateGestureEventHub();
1450     CHECK_NULL_VOID(gesture);
1451 
1452     auto touchTask = [weak = WeakClaim(this)](const TouchEventInfo& info) {
1453         auto pattern = weak.Upgrade();
1454         CHECK_NULL_VOID(pattern);
1455         pattern->HandleUrlTouchEvent(info);
1456     };
1457     auto touchListener = MakeRefPtr<TouchEventImpl>(std::move(touchTask));
1458     gesture->AddTouchEvent(touchListener);
1459     urlTouchEventInitialized_ = true;
1460 }
1461 
MarkDirtySelf()1462 void TextPattern::MarkDirtySelf()
1463 {
1464     auto host = GetHost();
1465     CHECK_NULL_VOID(host);
1466     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1467 }
1468 
HandleTouchEvent(const TouchEventInfo & info)1469 void TextPattern::HandleTouchEvent(const TouchEventInfo& info)
1470 {
1471     DoGestureSelection(info);
1472 }
1473 
InitKeyEvent()1474 void TextPattern::InitKeyEvent()
1475 {
1476     CHECK_NULL_VOID(!keyEventInitialized_);
1477     auto host = GetHost();
1478     CHECK_NULL_VOID(host);
1479     auto focusHub = host->GetOrCreateFocusHub();
1480     CHECK_NULL_VOID(focusHub);
1481 
1482     auto keyTask = [weak = WeakClaim(this)](const KeyEvent& event) -> bool {
1483         auto pattern = weak.Upgrade();
1484         CHECK_NULL_RETURN(pattern, false);
1485         return pattern->HandleKeyEvent(event);
1486     };
1487     focusHub->SetOnKeyEventInternal(std::move(keyTask));
1488     keyEventInitialized_ = true;
1489 }
1490 
UpdateShiftFlag(const KeyEvent & keyEvent)1491 void TextPattern::UpdateShiftFlag(const KeyEvent& keyEvent)
1492 {
1493     bool flag = false;
1494     if (keyEvent.action == KeyAction::DOWN) {
1495         if (keyEvent.HasKey(KeyCode::KEY_SHIFT_LEFT) || keyEvent.HasKey(KeyCode::KEY_SHIFT_RIGHT)) {
1496             flag = true;
1497         }
1498     }
1499     if (flag != shiftFlag_) {
1500         shiftFlag_ = flag;
1501         if (!shiftFlag_) {
1502             // open drag
1503             InitDragEvent();
1504         } else  {
1505             // close drag
1506             ClearDragEvent();
1507         }
1508     }
1509 }
1510 
HandleKeyEvent(const KeyEvent & keyEvent)1511 bool TextPattern::HandleKeyEvent(const KeyEvent& keyEvent)
1512 {
1513     UpdateShiftFlag(keyEvent);
1514     if (keyEvent.action != KeyAction::DOWN) {
1515         return false;
1516     }
1517 
1518     if (keyEvent.IsCtrlWith(KeyCode::KEY_C)) {
1519         HandleOnCopy();
1520         return true;
1521     }
1522 
1523     if (keyEvent.IsCtrlWith(KeyCode::KEY_A)) {
1524         auto textSize = static_cast<int32_t>(textForDisplay_.length()) + placeholderCount_;
1525         HandleSelectionChange(0, textSize);
1526         CloseSelectOverlay();
1527         auto host = GetHost();
1528         CHECK_NULL_RETURN(host, false);
1529         host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1530         return true;
1531     }
1532 
1533     if (keyEvent.IsShiftWith(keyEvent.code)) {
1534         HandleOnSelect(keyEvent.code);
1535         return true;
1536     }
1537     return false;
1538 }
1539 
HandleOnSelect(KeyCode code)1540 void TextPattern::HandleOnSelect(KeyCode code)
1541 {
1542     auto end = textSelector_.GetEnd();
1543     switch (code) {
1544         case KeyCode::KEY_DPAD_LEFT: {
1545             HandleSelection(true, end - 1);
1546             break;
1547         }
1548         case KeyCode::KEY_DPAD_RIGHT: {
1549             HandleSelection(false, end + 1);
1550             break;
1551         }
1552         case KeyCode::KEY_DPAD_UP: {
1553             HandleSelectionUp();
1554             break;
1555         }
1556         case KeyCode::KEY_DPAD_DOWN: {
1557             HandleSelectionDown();
1558             break;
1559         }
1560         default:
1561             break;
1562     }
1563 }
1564 
HandleSelectionUp()1565 void TextPattern::HandleSelectionUp()
1566 {
1567     auto end = textSelector_.GetEnd();
1568     auto line = pManager_->GetLineCount();
1569     if (line == 1) {
1570         HandleSelection(true, 0);
1571         return;
1572     }
1573     CaretMetricsF secondHandleMetrics;
1574     CalcCaretMetricsByPosition(textSelector_.destinationOffset, secondHandleMetrics, TextAffinity::UPSTREAM);
1575     auto secondOffsetX = secondHandleMetrics.offset.GetX();
1576     auto secondOffsetY = secondHandleMetrics.offset.GetY();
1577     double height = GetTextHeight(end, false);
1578     Offset offset = { secondOffsetX, secondOffsetY - height * 0.5 };
1579     auto caculateIndex = GetHandleIndex(offset);
1580     if (end == caculateIndex) {
1581         caculateIndex = 0;
1582     }
1583     HandleSelection(true, caculateIndex);
1584 }
1585 
HandleSelectionDown()1586 void TextPattern::HandleSelectionDown()
1587 {
1588     auto end = textSelector_.GetEnd();
1589     auto line = pManager_->GetLineCount();
1590     auto lastIndex = GetActualTextLength();
1591     if (line == 1) {
1592         HandleSelection(true, lastIndex);
1593         return;
1594     }
1595     CaretMetricsF secondHandleMetrics;
1596     CalcCaretMetricsByPosition(textSelector_.destinationOffset, secondHandleMetrics, TextAffinity::UPSTREAM);
1597     auto secondOffsetX = secondHandleMetrics.offset.GetX();
1598     double height = GetTextHeight(end, true);
1599     auto caculateIndex = GetHandleIndex({ secondOffsetX, height });
1600     if (NearZero(height) || caculateIndex == end || caculateIndex > lastIndex) {
1601         caculateIndex = lastIndex;
1602     }
1603     HandleSelection(true, caculateIndex);
1604 }
1605 
HandleSelection(bool isEmojiStart,int32_t end)1606 void TextPattern::HandleSelection(bool isEmojiStart, int32_t end)
1607 {
1608     auto start = textSelector_.GetStart();
1609     auto lastIndex = GetActualTextLength();
1610     if (start < 0 || start > lastIndex || end < 0 || end > lastIndex) {
1611         return;
1612     }
1613     int32_t emojiStartIndex;
1614     int32_t emojiEndIndex;
1615     bool isIndexInEmoji = TextEmojiProcessor::IsIndexInEmoji(end, GetSelectedText(0, lastIndex),
1616         emojiStartIndex, emojiEndIndex);
1617     if (isIndexInEmoji) {
1618         end = isEmojiStart ? emojiStartIndex : emojiEndIndex;
1619     }
1620     HandleSelectionChange(start, end);
1621     CalculateHandleOffsetAndShowOverlay();
1622     CloseSelectOverlay(true);
1623     auto host = GetHost();
1624     CHECK_NULL_VOID(host);
1625     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1626 }
1627 
GetTextHeight(int32_t index,bool isNextLine)1628 double TextPattern::GetTextHeight(int32_t index, bool isNextLine)
1629 {
1630     auto lineCount = static_cast<int32_t>(pManager_->GetLineCount());
1631     auto lineHeight = 0.0;
1632     for (auto lineNumber = 0; lineNumber < lineCount; lineNumber++) {
1633         auto lineMetrics = GetLineMetrics(lineNumber);
1634         auto startIndex = static_cast<int32_t>(lineMetrics.startIndex);
1635         auto endIndex = static_cast<int32_t>(lineMetrics.endIndex);
1636         lineHeight += lineMetrics.height;
1637         if (isNextLine) {
1638             if (index <= endIndex && endIndex != GetActualTextLength()) {
1639                 return lineHeight;
1640             }
1641         } else {
1642             auto textLayoutProperty = GetLayoutProperty<TextLayoutProperty>();
1643             CHECK_NULL_RETURN(textLayoutProperty, 0);
1644             auto maxLines = textLayoutProperty->GetMaxLinesValue(Infinity<uint32_t>());
1645             if ((index <= endIndex && startIndex != 0) ||
1646                 ((lineNumber + 1) == static_cast<int32_t>(maxLines) && lineNumber != 0)) {
1647                 return GetLineMetrics(lineNumber - 1).height;
1648             }
1649         }
1650     }
1651     return 0.0;
1652 }
1653 
GetActualTextLength()1654 int32_t TextPattern::GetActualTextLength()
1655 {
1656     auto lineCount = static_cast<int32_t>(pManager_->GetLineCount());
1657     return GetLineMetrics(lineCount - 1).endIndex;
1658 }
1659 
SetTextSelectableMode(TextSelectableMode value)1660 void TextPattern::SetTextSelectableMode(TextSelectableMode value)
1661 {
1662     auto host = GetHost();
1663     CHECK_NULL_VOID(host);
1664     auto focusHub = host->GetOrCreateFocusHub();
1665     CHECK_NULL_VOID(focusHub);
1666     if (value == TextSelectableMode::SELECTABLE_FOCUSABLE) {
1667         focusHub->SetFocusable(true);
1668         focusHub->SetIsFocusOnTouch(true);
1669     } else {
1670         focusHub->SetFocusable(false);
1671         focusHub->SetIsFocusOnTouch(false);
1672     }
1673 }
1674 
IsSelectableAndCopy()1675 bool TextPattern::IsSelectableAndCopy()
1676 {
1677     auto textLayoutProperty = GetLayoutProperty<TextLayoutProperty>();
1678     CHECK_NULL_RETURN(textLayoutProperty, false);
1679     auto mode = textLayoutProperty->GetTextSelectableModeValue(TextSelectableMode::SELECTABLE_UNFOCUSABLE);
1680     return mode != TextSelectableMode::UNSELECTABLE && copyOption_ != CopyOptions::None;
1681 }
1682 
IsDraggable(const Offset & offset)1683 bool TextPattern::IsDraggable(const Offset& offset)
1684 {
1685     auto host = GetHost();
1686     CHECK_NULL_RETURN(host, false);
1687     auto eventHub = host->GetEventHub<EventHub>();
1688     bool draggable = eventHub->HasOnDragStart();
1689     if (IsSelectableAndCopy() && draggable &&
1690         GreatNotEqual(textSelector_.GetTextEnd(), textSelector_.GetTextStart())) {
1691         // Determine if the pan location is in the selected area
1692         auto selectedRects = pManager_->GetRects(textSelector_.GetTextStart(), textSelector_.GetTextEnd());
1693         TextBase::CalculateSelectedRect(selectedRects, contentRect_.Width());
1694         auto panOffset = OffsetF(offset.GetX(), offset.GetY()) - contentRect_.GetOffset() +
1695                          OffsetF(0.0f, std::min(baselineOffset_, 0.0f));
1696         for (const auto& selectedRect : selectedRects) {
1697             if (selectedRect.IsInRegion(PointF(panOffset.GetX(), panOffset.GetY()))) {
1698                 return true;
1699             }
1700         }
1701     }
1702     return false;
1703 }
1704 
OnDragStart(const RefPtr<Ace::DragEvent> & event,const std::string & extraParams)1705 NG::DragDropInfo TextPattern::OnDragStart(const RefPtr<Ace::DragEvent>& event, const std::string& extraParams)
1706 {
1707     DragDropInfo itemInfo;
1708     auto host = GetHost();
1709     CHECK_NULL_RETURN(host, itemInfo);
1710     if (overlayMod_) {
1711         overlayMod_->ClearSelectedForegroundColorAndRects();
1712     }
1713     auto hub = host->GetEventHub<EventHub>();
1714     auto gestureHub = hub->GetOrCreateGestureEventHub();
1715     auto selectStart = textSelector_.GetTextStart();
1716     auto selectEnd = textSelector_.GetTextEnd();
1717     recoverStart_ = selectStart;
1718     recoverEnd_ = selectEnd;
1719     auto textSelectInfo = GetSpansInfo(selectStart, selectEnd, GetSpansMethod::ONSELECT);
1720     dragResultObjects_ = textSelectInfo.GetSelection().resultObjects;
1721     ResetDragRecordSize(dragResultObjects_.empty() ? -1 : 1);
1722     status_ = Status::DRAGGING;
1723     if (dragResultObjects_.empty() || !gestureHub->GetIsTextDraggable()) {
1724         return itemInfo;
1725     }
1726     auto data = event->GetData();
1727     if (!data) {
1728         AddUdmfData(event);
1729     }
1730     CloseOperate();
1731     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1732     return itemInfo;
1733 }
1734 
AddUdmfTxtPreProcessor(const ResultObject src,ResultObject & result,bool isAppend)1735 void TextPattern::AddUdmfTxtPreProcessor(const ResultObject src, ResultObject& result, bool isAppend)
1736 {
1737     auto valueString = GetSelectedSpanText(StringUtils::ToWstring(src.valueString),
1738         src.offsetInSpan[RichEditorSpanRange::RANGESTART], src.offsetInSpan[RichEditorSpanRange::RANGEEND]);
1739     if (isAppend) {
1740         result.valueString = result.valueString + valueString;
1741     } else {
1742         result.valueString = valueString;
1743     }
1744 }
1745 
AddUdmfData(const RefPtr<Ace::DragEvent> & event)1746 void TextPattern::AddUdmfData(const RefPtr<Ace::DragEvent>& event)
1747 {
1748     RefPtr<UnifiedData> unifiedData = UdmfClient::GetInstance()->CreateUnifiedData();
1749     if (isSpanStringMode_) {
1750         std::vector<uint8_t> arr;
1751         auto dragSpanString = styledString_->GetSubSpanString(recoverStart_, recoverEnd_ - recoverStart_);
1752         dragSpanString->EncodeTlv(arr);
1753         UdmfClient::GetInstance()->AddSpanStringRecord(unifiedData, arr);
1754     } else {
1755         ProcessNormalUdmfData(unifiedData);
1756     }
1757     event->SetData(unifiedData);
1758 }
1759 
ProcessNormalUdmfData(const RefPtr<UnifiedData> & unifiedData)1760 void TextPattern::ProcessNormalUdmfData(const RefPtr<UnifiedData>& unifiedData)
1761 {
1762     std::list<ResultObject> finalResult;
1763     auto type = SelectSpanType::TYPESPAN;
1764     for (const auto& resultObj : dragResultObjects_) {
1765         if (finalResult.empty() || resultObj.type != SelectSpanType::TYPESPAN || type != SelectSpanType::TYPESPAN) {
1766             type = resultObj.type;
1767             finalResult.emplace_back(resultObj);
1768             if (resultObj.type == SelectSpanType::TYPESPAN) {
1769                 AddUdmfTxtPreProcessor(resultObj, finalResult.back(), false);
1770             }
1771         } else {
1772             AddUdmfTxtPreProcessor(resultObj, finalResult.back(), true);
1773         }
1774     }
1775     auto resultProcessor = [unifiedData, weak = WeakClaim(this)](const ResultObject& result) {
1776         auto pattern = weak.Upgrade();
1777         CHECK_NULL_VOID(pattern);
1778         if (result.type == SelectSpanType::TYPESPAN) {
1779             UdmfClient::GetInstance()->AddPlainTextRecord(unifiedData, result.valueString);
1780             return;
1781         }
1782         if (result.type == SelectSpanType::TYPEIMAGE) {
1783             if (result.valuePixelMap) {
1784                 pattern->AddPixelMapToUdmfData(result.valuePixelMap, unifiedData);
1785             } else if (result.valueString.size() > 1) {
1786                 UdmfClient::GetInstance()->AddImageRecord(unifiedData, result.valueString);
1787             } else {
1788                 // builder span, fill pixelmap data
1789                 auto builderNode = DynamicCast<FrameNode>(pattern->GetChildByIndex(result.spanPosition.spanIndex));
1790                 CHECK_NULL_VOID(builderNode);
1791                 pattern->AddPixelMapToUdmfData(builderNode->GetPixelMap(), unifiedData);
1792             }
1793         }
1794     };
1795     for (const auto& resultObj : finalResult) {
1796         resultProcessor(resultObj);
1797     }
1798 }
1799 
AddPixelMapToUdmfData(const RefPtr<PixelMap> & pixelMap,const RefPtr<UnifiedData> & unifiedData)1800 void TextPattern::AddPixelMapToUdmfData(const RefPtr<PixelMap>& pixelMap, const RefPtr<UnifiedData>& unifiedData)
1801 {
1802     CHECK_NULL_VOID(pixelMap && unifiedData);
1803     const uint8_t* pixels = pixelMap->GetPixels();
1804     CHECK_NULL_VOID(pixels);
1805     int32_t length = pixelMap->GetByteCount();
1806     std::vector<uint8_t> data(pixels, pixels + length);
1807     PixelMapRecordDetails details = { pixelMap->GetWidth(), pixelMap->GetHeight(),
1808         pixelMap->GetPixelFormat(), pixelMap->GetAlphaType() };
1809     UdmfClient::GetInstance()->AddPixelMapRecord(unifiedData, data, details);
1810 }
1811 
CloseOperate()1812 void TextPattern::CloseOperate()
1813 {
1814     UpdateSpanItemDragStatus(dragResultObjects_, true);
1815     recoverDragResultObjects_ = dragResultObjects_;
1816     AceEngineExt::GetInstance().DragStartExt();
1817     CloseKeyboard(true);
1818     CloseSelectOverlay();
1819     ResetSelection();
1820 }
1821 
OnDragStartNoChild(const RefPtr<Ace::DragEvent> & event,const std::string & extraParams)1822 DragDropInfo TextPattern::OnDragStartNoChild(const RefPtr<Ace::DragEvent>& event, const std::string& extraParams)
1823 {
1824     auto weakPtr = WeakClaim(this);
1825     DragDropInfo itemInfo;
1826     auto pattern = weakPtr.Upgrade();
1827     auto host = pattern->GetHost();
1828     auto hub = host->GetEventHub<EventHub>();
1829     auto gestureHub = hub->GetOrCreateGestureEventHub();
1830     CHECK_NULL_RETURN(gestureHub, itemInfo);
1831     if (!gestureHub->GetIsTextDraggable()) {
1832         return itemInfo;
1833     }
1834     auto layoutProperty = host->GetLayoutProperty<TextLayoutProperty>();
1835     pattern->status_ = Status::DRAGGING;
1836     pattern->contentMod_->ChangeDragStatus();
1837     pattern->showSelect_ = false;
1838     auto start = textSelector_.GetTextStart();
1839     pattern->recoverStart_ = start;
1840     auto end = textSelector_.GetTextEnd();
1841     pattern->recoverEnd_ = end;
1842     auto beforeStr = GetSelectedText(0, start);
1843     auto selectedStr = GetSelectedText(textSelector_.GetTextStart(), textSelector_.GetTextEnd());
1844     auto afterStr = GetSelectedText(end, GetWideText().length());
1845     pattern->dragContents_ = { beforeStr, selectedStr, afterStr };
1846 
1847     itemInfo.extraInfo = selectedStr;
1848     RefPtr<UnifiedData> unifiedData = UdmfClient::GetInstance()->CreateUnifiedData();
1849     UdmfClient::GetInstance()->AddPlainTextRecord(unifiedData, selectedStr);
1850     event->SetData(unifiedData);
1851     host->MarkDirtyNode(layoutProperty->GetMaxLinesValue(Infinity<float>()) <= 1 ? PROPERTY_UPDATE_MEASURE_SELF
1852                                                                                         : PROPERTY_UPDATE_MEASURE);
1853 
1854     CloseSelectOverlay();
1855     ResetSelection();
1856     return itemInfo;
1857 }
1858 
UpdateSpanItemDragStatus(const std::list<ResultObject> & resultObjects,bool isDragging)1859 void TextPattern::UpdateSpanItemDragStatus(const std::list<ResultObject>& resultObjects, bool isDragging)
1860 {
1861     if (resultObjects.empty()) {
1862         return;
1863     }
1864     auto dragStatusUpdateAction = [weakPtr = WeakClaim(this), isDragging](const ResultObject& resultObj) {
1865         auto pattern = weakPtr.Upgrade();
1866         CHECK_NULL_VOID(pattern);
1867         if (pattern->spans_.empty()) {
1868             return;
1869         }
1870         auto it = pattern->spans_.begin();
1871         if (resultObj.spanPosition.spanIndex >= static_cast<int32_t>(pattern->spans_.size())) {
1872             std::advance(it, !pattern->spans_.empty() ? static_cast<int32_t>(pattern->spans_.size()) - 1 : 0);
1873             TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "resultObj.spanPosition.spanIndex is larger than spans size.");
1874         } else {
1875             std::advance(it, resultObj.spanPosition.spanIndex);
1876         }
1877         auto spanItem = *it;
1878         CHECK_NULL_VOID(spanItem);
1879         if (resultObj.type == SelectSpanType::TYPESPAN) {
1880             if (pattern->isSpanStringMode_) {
1881                 spanItem = resultObj.span.Upgrade();
1882                 CHECK_NULL_VOID(spanItem);
1883             }
1884             if (isDragging) {
1885                 spanItem->StartDrag(resultObj.offsetInSpan[RichEditorSpanRange::RANGESTART],
1886                     resultObj.offsetInSpan[RichEditorSpanRange::RANGEEND]);
1887                 pattern->dragSpanItems_.emplace_back(spanItem);
1888             } else {
1889                 spanItem->EndDrag();
1890             }
1891             return;
1892         }
1893 
1894         if (resultObj.type == SelectSpanType::TYPEIMAGE) {
1895             if (isDragging) {
1896                 pattern->dragSpanItems_.emplace_back(spanItem);
1897             }
1898             auto imageNode = DynamicCast<FrameNode>(pattern->GetChildByIndex(resultObj.spanPosition.spanIndex));
1899             CHECK_NULL_VOID(imageNode);
1900             auto renderContext = imageNode->GetRenderContext();
1901             CHECK_NULL_VOID(renderContext);
1902             renderContext->UpdateOpacity(isDragging ? (double)DRAGGED_TEXT_OPACITY / 255 : 1);
1903             imageNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1904         }
1905     };
1906     for (const auto& resultObj : resultObjects) {
1907         dragStatusUpdateAction(resultObj);
1908     }
1909 }
1910 
OnDragEnd(const RefPtr<Ace::DragEvent> & event)1911 void TextPattern::OnDragEnd(const RefPtr<Ace::DragEvent>& event)
1912 {
1913     auto wk = WeakClaim(this);
1914     auto pattern = wk.Upgrade();
1915     CHECK_NULL_VOID(pattern);
1916     auto host = GetHost();
1917     CHECK_NULL_VOID(host);
1918     if (status_ == Status::DRAGGING) {
1919         status_ = Status::NONE;
1920     }
1921     dragSpanItems_.clear();
1922     if (dragResultObjects_.empty()) {
1923         return;
1924     }
1925     UpdateSpanItemDragStatus(dragResultObjects_, false);
1926     dragResultObjects_.clear();
1927     if (event && event->GetResult() != DragRet::DRAG_SUCCESS && IsSelectableAndCopy()) {
1928         HandleSelectionChange(recoverStart_, recoverEnd_);
1929         isShowMenu_ = false;
1930         if (GetCurrentDragTool() == SourceTool::FINGER) {
1931             CalculateHandleOffsetAndShowOverlay();
1932             ShowSelectOverlay({ .menuIsShow = false });
1933         }
1934     }
1935     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1936 }
1937 
OnDragEndNoChild(const RefPtr<Ace::DragEvent> & event)1938 void TextPattern::OnDragEndNoChild(const RefPtr<Ace::DragEvent>& event)
1939 {
1940     auto wk = WeakClaim(this);
1941     auto pattern = wk.Upgrade();
1942     CHECK_NULL_VOID(pattern);
1943     auto host = pattern->GetHost();
1944     CHECK_NULL_VOID(host);
1945     if (pattern->status_ == Status::DRAGGING) {
1946         pattern->status_ = Status::NONE;
1947         pattern->MarkContentChange();
1948         pattern->contentMod_->ChangeDragStatus();
1949         if (event && event->GetResult() != DragRet::DRAG_SUCCESS && IsSelectableAndCopy()) {
1950             HandleSelectionChange(recoverStart_, recoverEnd_);
1951             isShowMenu_ = false;
1952             if (GetCurrentDragTool() == SourceTool::FINGER) {
1953                 CalculateHandleOffsetAndShowOverlay();
1954                 ShowSelectOverlay({ .menuIsShow = false });
1955             }
1956         }
1957         auto layoutProperty = host->GetLayoutProperty<TextLayoutProperty>();
1958         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1959     }
1960 }
1961 
InitDragEvent()1962 void TextPattern::InitDragEvent()
1963 {
1964     auto host = GetHost();
1965     CHECK_NULL_VOID(host);
1966     auto eventHub = host->GetEventHub<EventHub>();
1967     CHECK_NULL_VOID(eventHub);
1968     auto gestureHub = host->GetOrCreateGestureEventHub();
1969     CHECK_NULL_VOID(gestureHub);
1970     gestureHub->InitDragDropEvent();
1971     gestureHub->SetTextDraggable(true);
1972     gestureHub->SetThumbnailCallback(GetThumbnailCallback());
1973     auto onDragStart = [weakPtr = WeakClaim(this)](
1974                            const RefPtr<OHOS::Ace::DragEvent>& event, const std::string& extraParams) -> DragDropInfo {
1975         NG::DragDropInfo itemInfo;
1976         auto pattern = weakPtr.Upgrade();
1977         CHECK_NULL_RETURN(pattern, itemInfo);
1978         auto eventHub = pattern->GetEventHub<EventHub>();
1979         CHECK_NULL_RETURN(eventHub, itemInfo);
1980         pattern->SetCurrentDragTool(event->GetSourceTool());
1981         if (pattern->spans_.empty() && !pattern->isSpanStringMode_) {
1982             return pattern->OnDragStartNoChild(event, extraParams);
1983         }
1984         return pattern->OnDragStart(event, extraParams);
1985     };
1986     eventHub->SetDefaultOnDragStart(std::move(onDragStart));
1987     auto onDragMove = [weakPtr = WeakClaim(this)](
1988                           const RefPtr<OHOS::Ace::DragEvent>& event, const std::string& extraParams) {
1989         auto pattern = weakPtr.Upgrade();
1990         CHECK_NULL_VOID(pattern);
1991         pattern->OnDragMove(event);
1992     };
1993     eventHub->SetOnDragMove(std::move(onDragMove));
1994     auto onDragEnd = [weakPtr = WeakClaim(this)](const RefPtr<OHOS::Ace::DragEvent>& event) {
1995         auto pattern = weakPtr.Upgrade();
1996         CHECK_NULL_VOID(pattern);
1997         // 拖拽框架强引用导致退出页面后还能够运行到这里
1998         if (pattern->isDetachFromMainTree_) {
1999             return;
2000         }
2001         ContainerScope scope(pattern->GetHostInstanceId());
2002         pattern->showSelect_ = true;
2003         if (pattern->spans_.empty()) {
2004             pattern->OnDragEndNoChild(event);
2005         } else {
2006             pattern->OnDragEnd(event);
2007         }
2008     };
2009     eventHub->SetOnDragEnd(std::move(onDragEnd));
2010 }
2011 
OnDragMove(const RefPtr<Ace::DragEvent> & event)2012 void TextPattern::OnDragMove(const RefPtr<Ace::DragEvent>& event)
2013 {
2014     auto weakPtr = WeakClaim(this);
2015     auto pattern = weakPtr.Upgrade();
2016     if (pattern->status_ == Status::DRAGGING) {
2017         CloseSelectOverlay();
2018         pattern->showSelect_ = false;
2019     }
2020 }
2021 
ClearDragEvent()2022 void TextPattern::ClearDragEvent()
2023 {
2024     auto host = GetHost();
2025     CHECK_NULL_VOID(host);
2026     auto eventHub = host->GetEventHub<EventHub>();
2027     CHECK_NULL_VOID(eventHub);
2028     auto gestureHub = host->GetOrCreateGestureEventHub();
2029     CHECK_NULL_VOID(gestureHub);
2030     gestureHub->SetTextDraggable(false);
2031     gestureHub->SetIsTextDraggable(false);
2032     gestureHub->SetThumbnailCallback(nullptr);
2033     eventHub->SetDefaultOnDragStart(nullptr);
2034     eventHub->SetOnDragMove(nullptr);
2035     eventHub->SetOnDragEnd(nullptr);
2036 }
2037 
GetThumbnailCallback()2038 std::function<void(Offset)> TextPattern::GetThumbnailCallback()
2039 {
2040     return [wk = WeakClaim(this)](const Offset& point) {
2041         auto pattern = wk.Upgrade();
2042         CHECK_NULL_VOID(pattern);
2043         if (pattern->BetweenSelectedPosition(point)) {
2044             auto host = pattern->GetHost();
2045             const auto& children = pattern->GetChildNodes();
2046             std::list<RefPtr<FrameNode>> imageChildren;
2047             for (const auto& child : children) {
2048                 auto node = DynamicCast<FrameNode>(child);
2049                 if (!node) {
2050                     continue;
2051                 }
2052                 auto image = node->GetPattern<ImagePattern>();
2053                 if (image) {
2054                     imageChildren.emplace_back(node);
2055                 }
2056             }
2057             RichEditorDragInfo info;
2058             info.firstHandle = pattern->textSelector_.firstHandle;
2059             info.secondHandle = pattern->textSelector_.secondHandle;
2060             pattern->dragNode_ = RichEditorDragPattern::CreateDragNode(pattern->GetHost(), imageChildren, info);
2061             auto textDragPattern = pattern->dragNode_->GetPattern<TextDragPattern>();
2062             if (textDragPattern) {
2063                 auto option = pattern->GetHost()->GetDragPreviewOption();
2064                 option.options.shadowPath = textDragPattern->GetBackgroundPath()->ConvertToSVGString();
2065                 option.options.shadow = Shadow(RICH_DEFAULT_ELEVATION, {0.0, 0.0}, Color(RICH_DEFAULT_SHADOW_COLOR),
2066                 ShadowStyle::OuterFloatingSM);
2067                 pattern->GetHost()->SetDragPreviewOptions(option);
2068             }
2069             FrameNode::ProcessOffscreenNode(pattern->dragNode_);
2070             auto gestureHub = host->GetOrCreateGestureEventHub();
2071             CHECK_NULL_VOID(gestureHub);
2072             gestureHub->SetPixelMap(nullptr);
2073         }
2074     };
2075 }
2076 
GetAllChildren() const2077 const std::list<RefPtr<UINode>>& TextPattern::GetAllChildren() const
2078 {
2079     return childNodes_;
2080 }
2081 
2082 // ===========================================================
2083 // TextDragBase implementations
GetSelectedSpanText(std::wstring value,int32_t start,int32_t end) const2084 std::string TextPattern::GetSelectedSpanText(std::wstring value, int32_t start, int32_t end) const
2085 {
2086     if (start < 0 || end > static_cast<int32_t>(value.length()) || start >= end) {
2087         return "";
2088     }
2089     auto min = std::min(start, end);
2090     auto max = std::max(start, end);
2091 
2092     return StringUtils::ToString(value.substr(min, max - min));
2093 }
2094 
GetSpanItemByIndex(int32_t index) const2095 RefPtr<SpanItem> TextPattern::GetSpanItemByIndex(int32_t index) const
2096 {
2097     int32_t size = static_cast<int32_t>(spans_.size());
2098     if (index < 0 || index >= size) {
2099         return nullptr;
2100     }
2101     auto pos = spans_.begin();
2102     std::advance(pos, index);
2103     return *pos;
2104 }
2105 
GetSymbolSpanResultObject(RefPtr<UINode> uinode,int32_t index,int32_t start,int32_t end)2106 ResultObject TextPattern::GetSymbolSpanResultObject(RefPtr<UINode> uinode, int32_t index, int32_t start, int32_t end)
2107 {
2108     bool selectFlag = false;
2109     ResultObject resultObject;
2110     resultObject.isDraggable = false;
2111     if (!DynamicCast<SpanNode>(uinode)) {
2112         return resultObject;
2113     }
2114     auto spanItem = DynamicCast<SpanNode>(uinode)->GetSpanItem();
2115     int32_t itemLength = static_cast<int32_t>(StringUtils::ToWstring(spanItem->content).length());
2116     int32_t endPosition = std::min(GetTextContentLength(), spanItem->position);
2117     int32_t startPosition = endPosition - itemLength;
2118 
2119     if (startPosition >= start && endPosition <= end) {
2120         selectFlag = true;
2121         resultObject.offsetInSpan[RichEditorSpanRange::RANGESTART] = 0;
2122         resultObject.offsetInSpan[RichEditorSpanRange::RANGEEND] = itemLength;
2123     } else if (startPosition < start && endPosition <= end && endPosition > start) {
2124         selectFlag = true;
2125         resultObject.offsetInSpan[RichEditorSpanRange::RANGESTART] = start - startPosition;
2126         resultObject.offsetInSpan[RichEditorSpanRange::RANGEEND] = itemLength;
2127     } else if (startPosition >= start && startPosition < end && endPosition >= end) {
2128         selectFlag = true;
2129         resultObject.offsetInSpan[RichEditorSpanRange::RANGESTART] = 0;
2130         resultObject.offsetInSpan[RichEditorSpanRange::RANGEEND] = end - startPosition;
2131     } else if (startPosition <= start && endPosition >= end) {
2132         selectFlag = true;
2133         resultObject.offsetInSpan[RichEditorSpanRange::RANGESTART] = start - startPosition;
2134         resultObject.offsetInSpan[RichEditorSpanRange::RANGEEND] = end - startPosition;
2135     }
2136     if (selectFlag) {
2137         resultObject.valueResource = spanItem->GetResourceObject();
2138         resultObject.spanPosition.spanIndex = index;
2139         resultObject.spanPosition.spanRange[RichEditorSpanRange::RANGESTART] = startPosition;
2140         resultObject.spanPosition.spanRange[RichEditorSpanRange::RANGEEND] = endPosition;
2141         resultObject.type = SelectSpanType::TYPESYMBOLSPAN;
2142         resultObject.valueString = std::to_string(spanItem->unicode);
2143         auto spanNode = DynamicCast<SpanNode>(uinode);
2144         resultObject.symbolSpanStyle = GetSymbolSpanStyleObject(spanNode);
2145     }
2146     return resultObject;
2147 }
2148 
GetSymbolSpanStyleObject(const RefPtr<SpanNode> & node)2149 SymbolSpanStyle TextPattern::GetSymbolSpanStyleObject(const RefPtr<SpanNode>& node)
2150 {
2151     SymbolSpanStyle symbolSpanStyle;
2152     std::string symbolColorValue;
2153     auto symbolColors = node->GetSymbolColorList();
2154     for (const auto& color : *symbolColors) {
2155         symbolColorValue += color.ColorToString() + ",";
2156     }
2157     symbolColorValue =
2158         symbolColorValue.substr(0, !symbolColorValue.empty() ? static_cast<int32_t>(symbolColorValue.size()) - 1 : 0);
2159     symbolSpanStyle.symbolColor = !symbolColorValue.empty() ? symbolColorValue : SYMBOL_COLOR;
2160     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
2161         symbolSpanStyle.fontSize = node->GetFontSizeValue(Dimension(DIMENSION_VALUE, DimensionUnit::VP)).ConvertToFp();
2162     } else {
2163         symbolSpanStyle.fontSize = node->GetFontSizeValue(Dimension(DIMENSION_VALUE, DimensionUnit::VP)).ConvertToVp();
2164     }
2165     symbolSpanStyle.fontWeight = static_cast<int32_t>(node->GetFontWeightValue(FontWeight::NORMAL));
2166     symbolSpanStyle.renderingStrategy = static_cast<int32_t>(node->GetSymbolRenderingStrategyValue(0));
2167     symbolSpanStyle.effectStrategy = static_cast<int32_t>(node->GetSymbolEffectStrategyValue(0));
2168     return symbolSpanStyle;
2169 }
2170 
2171 // ===========================================================
2172 // TextDragBase implementations
GetLineHeight() const2173 float TextPattern::GetLineHeight() const
2174 {
2175     auto selectedRects = pManager_->GetRects(textSelector_.GetTextStart(), textSelector_.GetTextEnd());
2176     CHECK_NULL_RETURN(selectedRects.size(), {});
2177     return selectedRects.front().Height();
2178 }
2179 
GetTextBoxes()2180 std::vector<RectF> TextPattern::GetTextBoxes()
2181 {
2182     return pManager_->GetRects(textSelector_.GetTextStart(), textSelector_.GetTextEnd());
2183 }
2184 
GetParentGlobalOffset() const2185 OffsetF TextPattern::GetParentGlobalOffset() const
2186 {
2187     selectOverlay_->UpdateHandleGlobalOffset();
2188     auto host = GetHost();
2189     CHECK_NULL_RETURN(host, {});
2190     auto pipeline = PipelineContext::GetCurrentContextSafely();
2191     CHECK_NULL_RETURN(pipeline, {});
2192     auto rootOffset = pipeline->GetRootRect().GetOffset();
2193     return host->GetPaintRectOffset(false, true) - rootOffset;
2194 }
2195 
CreateHandles()2196 void TextPattern::CreateHandles()
2197 {
2198     if (IsDragging()) {
2199         TAG_LOGI(AceLogTag::ACE_TEXT, "do not show handles when dragging");
2200         return;
2201     }
2202     ShowSelectOverlay();
2203 }
2204 
BetweenSelectedPosition(const Offset & globalOffset)2205 bool TextPattern::BetweenSelectedPosition(const Offset& globalOffset)
2206 {
2207     auto host = GetHost();
2208     CHECK_NULL_RETURN(host, false);
2209     auto offset = host->GetPaintRectOffset(false, true);
2210     auto localOffset = globalOffset - Offset(offset.GetX(), offset.GetY());
2211     if (selectOverlay_->HasRenderTransform()) {
2212         localOffset = ConvertGlobalToLocalOffset(globalOffset);
2213     }
2214     return IsDraggable(localOffset);
2215 }
2216 
2217 // end of TextDragBase implementations
2218 // ===========================================================
2219 
OnModifyDone()2220 void TextPattern::OnModifyDone()
2221 {
2222     Pattern::OnModifyDone();
2223     auto textLayoutProperty = GetLayoutProperty<TextLayoutProperty>();
2224     CHECK_NULL_VOID(textLayoutProperty);
2225     auto host = GetHost();
2226     CHECK_NULL_VOID(host);
2227     auto renderContext = host->GetRenderContext();
2228     CHECK_NULL_VOID(renderContext);
2229     auto nowTime = static_cast<unsigned long long>(GetSystemTimestamp());
2230     ACE_TEXT_SCOPED_TRACE("OnModifyDone[Text][id:%d][time:%llu]", host->GetId(), nowTime);
2231     DumpRecord(std::to_string(nowTime));
2232     if (!(PipelineContext::GetCurrentContextSafely() &&
2233             PipelineContext::GetCurrentContextSafely()->GetMinPlatformVersion() > API_PROTEXTION_GREATER_NINE)) {
2234         bool shouldClipToContent =
2235             textLayoutProperty->GetTextOverflow().value_or(TextOverflow::CLIP) == TextOverflow::CLIP;
2236         host->GetRenderContext()->SetClipToFrame(shouldClipToContent);
2237     }
2238     if (textLayoutProperty->GetTextOverflowValue(TextOverflow::CLIP) == TextOverflow::MARQUEE) {
2239         if (!renderContext->GetClipEdge().has_value()) {
2240             renderContext->UpdateClipEdge(true);
2241             renderContext->SetClipToFrame(true);
2242         }
2243         CloseSelectOverlay();
2244         ResetSelection();
2245         copyOption_ = CopyOptions::None;
2246     } else {
2247         copyOption_ = textLayoutProperty->GetCopyOption().value_or(CopyOptions::None);
2248     }
2249 
2250 
2251     const auto& children = host->GetChildren();
2252     if (children.empty()) {
2253         auto obscuredReasons = renderContext->GetObscured().value_or(std::vector<ObscuredReasons>());
2254         bool ifHaveObscured = std::any_of(obscuredReasons.begin(), obscuredReasons.end(),
2255             [](const auto& reason) { return reason == ObscuredReasons::PLACEHOLDER; });
2256         if (textLayoutProperty->GetTextOverflowValue(TextOverflow::CLIP) == TextOverflow::MARQUEE ||
2257             (ifHaveObscured && !isSpanStringMode_)) {
2258             CloseSelectOverlay();
2259             ResetSelection();
2260             copyOption_ = CopyOptions::None;
2261         }
2262 
2263         std::string textCache = textForDisplay_;
2264         if (!isSpanStringMode_) {
2265             textForDisplay_ = textLayoutProperty->GetContent().value_or("");
2266         }
2267         if (textCache != textForDisplay_) {
2268             host->OnAccessibilityEvent(AccessibilityEventType::TEXT_CHANGE, textCache, textForDisplay_);
2269             dataDetectorAdapter_->aiDetectInitialized_ = false;
2270             CloseSelectOverlay();
2271             ResetSelection();
2272         }
2273 
2274         if (CanStartAITask() && !dataDetectorAdapter_->aiDetectInitialized_) {
2275             ParseOriText(textForDisplay_);
2276         }
2277     }
2278 
2279     if (children.empty() && CanStartAITask() && !dataDetectorAdapter_->aiDetectInitialized_) {
2280         dataDetectorAdapter_->textForAI_ = textForDisplay_;
2281         dataDetectorAdapter_->StartAITask();
2282     }
2283 
2284     auto gestureEventHub = host->GetOrCreateGestureEventHub();
2285     CHECK_NULL_VOID(gestureEventHub);
2286     auto eventHub = host->GetEventHub<EventHub>();
2287     CHECK_NULL_VOID(eventHub);
2288     if (IsSelectableAndCopy()) {
2289         auto context = PipelineContext::GetCurrentContextSafely();
2290         CHECK_NULL_VOID(context);
2291         if (!clipboard_ && context) {
2292             clipboard_ = ClipboardProxy::GetInstance()->GetClipboard(context->GetTaskExecutor());
2293         }
2294         InitLongPressEvent(gestureEventHub);
2295         if (host->IsDraggable() && !shiftFlag_) {
2296             InitDragEvent();
2297         }
2298         InitKeyEvent();
2299         InitMouseEvent();
2300         InitTouchEvent();
2301         SetAccessibilityAction();
2302     } else {
2303         if (host->IsDraggable() || gestureEventHub->GetTextDraggable()) {
2304             gestureEventHub->SetTextDraggable(false);
2305             eventHub->SetDefaultOnDragStart(nullptr);
2306             if (!eventHub->HasOnDragStart() && IsTextNode()) {
2307                 gestureEventHub->RemoveDragEvent();
2308             }
2309         }
2310         if (longPressEvent_ && !hasSpanStringLongPressEvent_) {
2311             gestureEventHub->SetLongPressEvent(nullptr);
2312             longPressEvent_ = nullptr;
2313         }
2314     }
2315     if (onClick_ || IsSelectableAndCopy() || CanStartAITask()) {
2316         InitClickEvent(gestureEventHub);
2317         if (CanStartAITask()) {
2318             auto context = PipelineContext::GetCurrentContextSafely();
2319             CHECK_NULL_VOID(context);
2320             if (!clipboard_ && context) {
2321                 clipboard_ = ClipboardProxy::GetInstance()->GetClipboard(context->GetTaskExecutor());
2322             }
2323             InitMouseEvent();
2324         }
2325     }
2326     bool enabledCache = eventHub->IsEnabled();
2327     selectOverlay_->SetMenuTranslateIsSupport(IsShowTranslate());
2328     selectOverlay_->UpdateHandleColor();
2329     if (textDetectEnable_ && enabledCache != enabled_) {
2330         enabled_ = enabledCache;
2331         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
2332     }
2333     ProcessMarqueeVisibleAreaCallback();
2334 }
2335 
SetActionExecSubComponent()2336 bool TextPattern::SetActionExecSubComponent()
2337 {
2338     auto host = GetHost();
2339     CHECK_NULL_RETURN(host, false);
2340     auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
2341     CHECK_NULL_RETURN(accessibilityProperty, false);
2342     accessibilityProperty->SetActionExecSubComponent([weakPtr = WeakClaim(this)](int32_t spanId) -> bool {
2343             const auto& pattern = weakPtr.Upgrade();
2344             CHECK_NULL_RETURN(pattern, false);
2345             return pattern->ExecSubComponent(spanId);
2346         });
2347     return true;
2348 }
2349 
GetSubComponentInfos(std::vector<SubComponentInfo> & subComponentInfos)2350 size_t TextPattern::GetSubComponentInfos(std::vector<SubComponentInfo>& subComponentInfos)
2351 {
2352     subComponentInfos.clear();
2353     subComponentInfos_.clear();
2354     if (spans_.empty()) {
2355         GetSubComponentInfosForAISpans(subComponentInfos);
2356     } else {
2357         GetSubComponentInfosForSpans(subComponentInfos);
2358     }
2359     SetActionExecSubComponent();
2360     return subComponentInfos.size();
2361 }
2362 
GetSubComponentInfosForAISpans(std::vector<SubComponentInfo> & subComponentInfos)2363 void TextPattern::GetSubComponentInfosForAISpans(std::vector<SubComponentInfo>& subComponentInfos)
2364 {
2365     CHECK_NULL_VOID(dataDetectorAdapter_);
2366     for (const auto& kv : dataDetectorAdapter_->aiSpanMap_) {
2367         auto& aiSpan = kv.second;
2368         AddSubComponentInfoForAISpan(subComponentInfos, aiSpan.content, aiSpan);
2369     }
2370 }
2371 
GetSubComponentInfosForSpans(std::vector<SubComponentInfo> & subComponentInfos)2372 void TextPattern::GetSubComponentInfosForSpans(std::vector<SubComponentInfo>& subComponentInfos)
2373 {
2374     for (const auto& span : spans_) {
2375         if (span == nullptr) {
2376             continue; // skip null
2377         }
2378         if ((span->imageNodeId >= 0) || (span->unicode > 0)) {
2379             continue; // skip ImageSpan and SymbolSpan
2380         }
2381         if (span->spanItemType == SpanItemType::CustomSpan) {
2382             continue; // skip CustomSpan
2383         }
2384         auto placeholderSpan = DynamicCast<PlaceholderSpanItem>(span);
2385         if ((placeholderSpan != nullptr) && (placeholderSpan->placeholderSpanNodeId >=0)) {
2386             continue; // skip PlaceholderSpan
2387         }
2388         if (span->content.empty()) {
2389             continue; // skip empty text
2390         }
2391         AddSubComponentInfoForSpan(subComponentInfos, span->content, span);
2392         AddSubComponentInfosByDataDetectorForSpan(subComponentInfos, span);
2393     }
2394 }
2395 
AddSubComponentInfosByDataDetectorForSpan(std::vector<SubComponentInfo> & subComponentInfos,const RefPtr<SpanItem> & span)2396 void TextPattern::AddSubComponentInfosByDataDetectorForSpan(std::vector<SubComponentInfo>& subComponentInfos,
2397     const RefPtr<SpanItem>& span)
2398 {
2399     CHECK_NULL_VOID(span);
2400     CHECK_NULL_VOID(dataDetectorAdapter_);
2401     auto wSpanContent = StringUtils::ToWstring(span->content);
2402     int32_t wSpanContentLength = static_cast<int32_t>(wSpanContent.length());
2403     int32_t spanStart = span->position - wSpanContentLength;
2404     if (span->needRemoveNewLine) {
2405         spanStart -= 1;
2406     }
2407     int32_t preEnd = spanStart;
2408     auto aiSpanMap = dataDetectorAdapter_->aiSpanMap_;
2409     while (!aiSpanMap.empty()) {
2410         auto aiSpan = aiSpanMap.begin()->second;
2411         if (aiSpan.start >= span->position || preEnd >= span->position) {
2412             break;
2413         }
2414         int32_t aiSpanStartInSpan = std::max(spanStart, aiSpan.start);
2415         int32_t aiSpanEndInSpan = std::min(span->position, aiSpan.end);
2416         if (aiSpan.end <= spanStart || aiSpanStartInSpan < preEnd) {
2417             TAG_LOGI(AceLogTag::ACE_TEXT, "Error prediction");
2418             aiSpanMap.erase(aiSpanMap.begin());
2419             continue;
2420         }
2421         AddSubComponentInfoForAISpan(subComponentInfos, aiSpan.content, aiSpan);
2422         preEnd = aiSpanEndInSpan;
2423         if (aiSpan.end > span->position) {
2424             return;
2425         } else {
2426             aiSpanMap.erase(aiSpanMap.begin());
2427         }
2428     }
2429 }
2430 
ExecSubComponent(int32_t spanId)2431 bool TextPattern::ExecSubComponent(int32_t spanId)
2432 {
2433     if ((spanId < 0) || (spanId >= static_cast<int32_t>(subComponentInfos_.size()))) {
2434         return false;
2435     }
2436     auto subComponentInfo = subComponentInfos_[spanId];
2437     if (subComponentInfo.aiSpan.has_value()) {
2438         CHECK_NULL_RETURN(dataDetectorAdapter_, false);
2439         dataDetectorAdapter_->ResponseBestMatchItem(subComponentInfo.aiSpan.value());
2440         return true;
2441     }
2442     const auto& span = subComponentInfo.span.Upgrade();
2443     CHECK_NULL_RETURN(span, false);
2444     CHECK_NULL_RETURN(span->onClick, false);
2445     GestureEvent info;
2446     std::chrono::microseconds microseconds(GetMicroTickCount());
2447     TimeStamp time(microseconds);
2448     info.SetTimeStamp(time);
2449     span->onClick(info);
2450     return true;
2451 }
2452 
AddSubComponentInfoForSpan(std::vector<SubComponentInfo> & subComponentInfos,const std::string & content,const RefPtr<SpanItem> & span)2453 void TextPattern::AddSubComponentInfoForSpan(std::vector<SubComponentInfo>& subComponentInfos,
2454     const std::string& content, const RefPtr<SpanItem>& span)
2455 {
2456     CHECK_NULL_VOID(span);
2457     CHECK_NULL_VOID(span->onClick); // skip null onClick
2458     SubComponentInfo subComponentInfo;
2459     subComponentInfo.spanId = static_cast<int32_t>(subComponentInfos.size());
2460     subComponentInfo.spanText = content;
2461     if (span->accessibilityProperty == nullptr) {
2462         subComponentInfo.accessibilityLevel = AccessibilityProperty::Level::AUTO;
2463     } else {
2464         subComponentInfo.accessibilityText = span->accessibilityProperty->GetAccessibilityText();
2465         subComponentInfo.accessibilityDescription =
2466             span->accessibilityProperty->GetAccessibilityDescription();
2467         subComponentInfo.accessibilityLevel = span->accessibilityProperty->GetAccessibilityLevel();
2468     }
2469     subComponentInfos.emplace_back(subComponentInfo);
2470 
2471     SubComponentInfoEx subComponentInfoEx;
2472     subComponentInfoEx.span = span;
2473     subComponentInfos_.emplace_back(subComponentInfoEx);
2474 }
2475 
AddSubComponentInfoForAISpan(std::vector<SubComponentInfo> & subComponentInfos,const std::string & content,const AISpan & aiSpan)2476 void TextPattern::AddSubComponentInfoForAISpan(std::vector<SubComponentInfo>& subComponentInfos,
2477     const std::string& content, const AISpan& aiSpan)
2478 {
2479     SubComponentInfo subComponentInfo;
2480     subComponentInfo.spanId = static_cast<int32_t>(subComponentInfos.size());
2481     subComponentInfo.spanText = content;
2482     subComponentInfo.accessibilityLevel = AccessibilityProperty::Level::AUTO;
2483     subComponentInfos.emplace_back(subComponentInfo);
2484 
2485     SubComponentInfoEx subComponentInfoEx;
2486     subComponentInfoEx.aiSpan = aiSpan;
2487     subComponentInfos_.emplace_back(subComponentInfoEx);
2488 }
2489 
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const2490 void TextPattern::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
2491 {
2492     json->PutFixedAttr("content", textForDisplay_.c_str(), filter, FIXED_ATTR_CONTENT);
2493     /* no fixed attr below, just return */
2494     if (filter.IsFastFilter()) {
2495         return;
2496     }
2497     json->PutExtAttr("enableDataDetector", textDetectEnable_ ? "true" : "false", filter);
2498     json->PutExtAttr("dataDetectorConfig", dataDetectorAdapter_->textDetectConfigStr_.c_str(), filter);
2499     const auto& selector = GetTextSelector();
2500     auto result = "[" + std::to_string(selector.GetTextStart()) + "," + std::to_string(selector.GetTextEnd()) + "]";
2501     json->PutExtAttr("selection", result.c_str(), filter);
2502     auto textLayoutProp = GetLayoutProperty<TextLayoutProperty>();
2503     CHECK_NULL_VOID(textLayoutProp);
2504     json->PutExtAttr("fontSize", GetFontSizeInJson(textLayoutProp->GetFontSize()).c_str(), filter);
2505     if (textStyle_.has_value() && textStyle_->GetAdaptTextSize()) {
2506         auto adaptedFontSize = textStyle_->GetFontSize();
2507         json->PutExtAttr("actualFontSize", adaptedFontSize.ToString().c_str(), filter);
2508     } else {
2509         json->PutExtAttr("actualFontSize", GetFontSizeInJson(textLayoutProp->GetFontSize()).c_str(), filter);
2510     }
2511     json->PutExtAttr("font", GetFontInJson().c_str(), filter);
2512     json->PutExtAttr("bindSelectionMenu", GetBindSelectionMenuInJson().c_str(), filter);
2513     json->PutExtAttr("caretColor", GetCaretColor().c_str(), filter);
2514     json->PutExtAttr("selectedBackgroundColor", GetSelectedBackgroundColor().c_str(), filter);
2515 }
2516 
GetBindSelectionMenuInJson() const2517 std::string TextPattern::GetBindSelectionMenuInJson() const
2518 {
2519     auto jsonArray = JsonUtil::CreateArray(true);
2520     for (auto& [spanResponsePair, params] : selectionMenuMap_) {
2521         auto& [spanType, responseType] = spanResponsePair;
2522         auto jsonItem = JsonUtil::Create(true);
2523         jsonItem->Put("spanType", TextSpanTypeMapper::GetJsSpanType(spanType, params->isValid));
2524         jsonItem->Put("responseType", static_cast<int32_t>(responseType));
2525         jsonItem->Put("menuType", static_cast<int32_t>(SelectionMenuType::SELECTION_MENU));
2526         jsonArray->Put(jsonItem);
2527     }
2528     FillPreviewMenuInJson(jsonArray);
2529     return StringUtils::RestoreBackslash(jsonArray->ToString());
2530 }
2531 
GetFontInJson() const2532 std::string TextPattern::GetFontInJson() const
2533 {
2534     auto textLayoutProp = GetLayoutProperty<TextLayoutProperty>();
2535     CHECK_NULL_RETURN(textLayoutProp, "");
2536     auto jsonValue = JsonUtil::Create(true);
2537     jsonValue->Put("style", GetFontStyleInJson(textLayoutProp->GetItalicFontStyle()).c_str());
2538     jsonValue->Put("size", GetFontSizeInJson(textLayoutProp->GetFontSize()).c_str());
2539     jsonValue->Put("weight", GetFontWeightInJson(textLayoutProp->GetFontWeight()).c_str());
2540     jsonValue->Put("variableFontWeight", std::to_string(textLayoutProp->GetVariableFontWeight().value_or(0)).c_str());
2541     jsonValue->Put("enableVariableFontWeight",
2542                    textLayoutProp->GetEnableVariableFontWeight().value_or(false) ? "true" : "false");
2543     jsonValue->Put("family", GetFontFamilyInJson(textLayoutProp->GetFontFamily()).c_str());
2544     return jsonValue->ToString();
2545 }
2546 
OnAfterModifyDone()2547 void TextPattern::OnAfterModifyDone()
2548 {
2549     auto host = GetHost();
2550     CHECK_NULL_VOID(host);
2551     auto inspectorId = host->GetInspectorId().value_or("");
2552     if (!inspectorId.empty()) {
2553         auto prop = host->GetAccessibilityProperty<NG::AccessibilityProperty>();
2554         Recorder::NodeDataCache::Get().PutString(host, inspectorId, prop->GetText());
2555     }
2556 }
2557 
ActSetSelection(int32_t start,int32_t end)2558 void TextPattern::ActSetSelection(int32_t start, int32_t end)
2559 {
2560     if (start == -1 && end == -1) {
2561         ResetSelection();
2562         CloseSelectOverlay();
2563         return;
2564     }
2565     int32_t min = 0;
2566     int32_t textSize = static_cast<int32_t>(GetWideText().length()) + placeholderCount_;
2567     start = start < min ? min : start;
2568     end = end < min ? min : end;
2569     start = start > textSize ? textSize : start;
2570     end = end > textSize ? textSize : end;
2571     if (start >= end) {
2572         FireOnSelectionChange(-1, -1);
2573         return;
2574     }
2575     HandleSelectionChange(start, end);
2576     parentGlobalOffset_ = GetParentGlobalOffset();
2577     CalculateHandleOffsetAndShowOverlay();
2578     if (textSelector_.firstHandle == textSelector_.secondHandle) {
2579         ResetSelection();
2580         CloseSelectOverlay();
2581         return;
2582     }
2583     if (IsShowHandle()) {
2584         ShowSelectOverlay();
2585     } else {
2586         CloseSelectOverlay();
2587         if (IsSelected()) {
2588             selectOverlay_->SetSelectionHoldCallback();
2589         }
2590     }
2591     auto host = GetHost();
2592     CHECK_NULL_VOID(host);
2593     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2594 }
2595 
IsShowHandle()2596 bool TextPattern::IsShowHandle()
2597 {
2598     auto pipeline = PipelineContext::GetCurrentContextSafely();
2599     CHECK_NULL_RETURN(pipeline, false);
2600     auto theme = pipeline->GetTheme<TextTheme>();
2601     CHECK_NULL_RETURN(theme, false);
2602     return !theme->IsShowHandle();
2603 }
2604 
GetUrlHoverColor()2605 Color TextPattern::GetUrlHoverColor()
2606 {
2607     auto pipeline = PipelineContext::GetCurrentContextSafely();
2608     CHECK_NULL_RETURN(pipeline, Color());
2609     auto theme = pipeline->GetTheme<TextTheme>();
2610     CHECK_NULL_RETURN(theme, Color());
2611     return theme->GetUrlHoverColor();
2612 }
2613 
GetUrlPressColor()2614 Color TextPattern::GetUrlPressColor()
2615 {
2616     auto pipeline = PipelineContext::GetCurrentContextSafely();
2617     CHECK_NULL_RETURN(pipeline, Color());
2618     auto theme = pipeline->GetTheme<TextTheme>();
2619     CHECK_NULL_RETURN(theme, Color());
2620     return theme->GetUrlPressColor();
2621 }
2622 
GetUrlSpanColor()2623 Color TextPattern::GetUrlSpanColor()
2624 {
2625     auto pipeline = PipelineContext::GetCurrentContextSafely();
2626     CHECK_NULL_RETURN(pipeline, Color());
2627     auto theme = pipeline->GetTheme<TextTheme>();
2628     CHECK_NULL_RETURN(theme, Color());
2629 
2630     auto host = GetHost();
2631     CHECK_NULL_RETURN(host, Color());
2632     auto eventHub = host->GetEventHub<EventHub>();
2633     CHECK_NULL_RETURN(eventHub, Color());
2634 
2635     if (eventHub && !eventHub->IsEnabled()) {
2636         return theme->GetUrlDisabledColor();
2637     } else {
2638         return theme->GetUrlDefaultColor();
2639     }
2640 }
2641 
2642 // Deprecated: Use the TextSelectOverlay::ProcessOverlay() instead.
2643 // It is currently used by RichEditorPattern.
UpdateSelectOverlayOrCreate(SelectOverlayInfo & selectInfo,bool animation)2644 void TextPattern::UpdateSelectOverlayOrCreate(SelectOverlayInfo& selectInfo, bool animation)
2645 {
2646     if (selectOverlayProxy_ && !selectOverlayProxy_->IsClosed()) {
2647         SelectHandleInfo firstHandleInfo;
2648         firstHandleInfo.paintRect = textSelector_.firstHandle;
2649         CheckHandles(firstHandleInfo);
2650 
2651         SelectHandleInfo secondHandleInfo;
2652         secondHandleInfo.paintRect = textSelector_.secondHandle;
2653         CheckHandles(secondHandleInfo);
2654 
2655         auto start = textSelector_.GetTextStart();
2656         auto end = textSelector_.GetTextEnd();
2657         selectOverlayProxy_->SetSelectInfo(GetSelectedText(start, end));
2658         if (selectInfo.isNewAvoid) {
2659             selectOverlayProxy_->UpdateSelectArea(selectInfo.selectArea);
2660         }
2661         selectOverlayProxy_->UpdateFirstAndSecondHandleInfo(firstHandleInfo, secondHandleInfo);
2662         selectOverlayProxy_->ShowOrHiddenMenu(!firstHandleInfo.isShow && !secondHandleInfo.isShow);
2663     } else {
2664         auto pipeline = PipelineContext::GetCurrentContextSafely();
2665         CHECK_NULL_VOID(pipeline);
2666         auto host = GetHost();
2667         CHECK_NULL_VOID(host);
2668         pipeline->AddOnAreaChangeNode(host->GetId());
2669         selectInfo.callerFrameNode = GetHost();
2670         selectInfo.hitTestMode = HitTestMode::HTMDEFAULT;
2671         if (!selectInfo.isUsingMouse) {
2672             CheckHandles(selectInfo.firstHandle);
2673             CheckHandles(selectInfo.secondHandle);
2674         }
2675         selectOverlayProxy_ =
2676             pipeline->GetSelectOverlayManager()->CreateAndShowSelectOverlay(selectInfo, WeakClaim(this), animation);
2677         CHECK_NULL_VOID(selectOverlayProxy_);
2678         auto start = textSelector_.GetTextStart();
2679         auto end = textSelector_.GetTextEnd();
2680         selectOverlayProxy_->SetSelectInfo(GetSelectedText(start, end));
2681     }
2682 }
2683 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)2684 bool TextPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
2685 {
2686     if (config.skipMeasure || dirty->SkipMeasureContent()) {
2687         return false;
2688     }
2689     contentRect_ = dirty->GetGeometryNode()->GetContentRect();
2690 
2691     auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
2692     CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
2693     auto textLayoutAlgorithm = DynamicCast<TextLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
2694     CHECK_NULL_RETURN(textLayoutAlgorithm, false);
2695     baselineOffset_ = textLayoutAlgorithm->GetBaselineOffset();
2696     contentOffset_ = dirty->GetGeometryNode()->GetContentOffset();
2697     textStyle_ = textLayoutAlgorithm->GetTextStyle();
2698     ProcessOverlayAfterLayout();
2699     return true;
2700 }
2701 
ProcessOverlayAfterLayout()2702 void TextPattern::ProcessOverlayAfterLayout()
2703 {
2704     if (selectOverlay_->SelectOverlayIsOn()) {
2705         CalculateHandleOffsetAndShowOverlay();
2706         selectOverlay_->UpdateAllHandlesOffset();
2707         selectOverlay_->UpdateViewPort();
2708     }
2709 }
2710 
PreCreateLayoutWrapper()2711 void TextPattern::PreCreateLayoutWrapper()
2712 {
2713     auto host = GetHost();
2714     CHECK_NULL_VOID(host);
2715 
2716     auto paintProperty = GetPaintProperty<PaintProperty>();
2717     CHECK_NULL_VOID(paintProperty);
2718     auto flag = paintProperty->GetPropertyChangeFlag();
2719     auto textLayoutProperty = GetLayoutProperty<TextLayoutProperty>();
2720     CHECK_NULL_VOID(textLayoutProperty);
2721     auto layoutFlag = textLayoutProperty->GetPropertyChangeFlag();
2722     if (!CheckNeedMeasure(flag) && !CheckNeedMeasure(layoutFlag)) {
2723         return;
2724     }
2725 
2726     spans_.clear();
2727     childNodes_.clear();
2728 
2729     // When dirty areas are marked because of child node changes, the text rendering node tree is reset.
2730     const auto& children = host->GetChildren();
2731     if (children.empty()) {
2732         placeholderCount_ = 0;
2733         return;
2734     }
2735 
2736     // Depth-first iterates through all host's child nodes to collect the SpanNode object, building a text rendering
2737     // tree.
2738     std::stack<SpanNodeInfo> nodes;
2739     for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
2740         nodes.push({ .node = *iter });
2741     }
2742 
2743     InitSpanItem(nodes);
2744 }
2745 
InitSpanItem(std::stack<SpanNodeInfo> nodes)2746 void TextPattern::InitSpanItem(std::stack<SpanNodeInfo> nodes)
2747 {
2748     auto host = GetHost();
2749     CHECK_NULL_VOID(host);
2750     std::string textCache;
2751     std::string textForAICache;
2752     int32_t oldPlaceholderCount = placeholderCount_;
2753     placeholderCount_ = 0;
2754     if (!nodes.empty()) {
2755         textCache = textForDisplay_;
2756         textForAICache = dataDetectorAdapter_->textForAI_;
2757         textForDisplay_.clear();
2758         dataDetectorAdapter_->textForAI_.clear();
2759     }
2760 
2761     bool isSpanHasClick = false;
2762     CollectSpanNodes(nodes, isSpanHasClick);
2763     auto textLayoutProperty = GetLayoutProperty<TextLayoutProperty>();
2764     CHECK_NULL_VOID(textLayoutProperty);
2765     if (childNodes_.empty()) {
2766         textForDisplay_ = textLayoutProperty->GetContent().value_or("");
2767     }
2768     if (oldPlaceholderCount != placeholderCount_) {
2769         CloseSelectOverlay();
2770         ResetSelection();
2771     }
2772 
2773     if (textCache != textForDisplay_) {
2774         host->OnAccessibilityEvent(AccessibilityEventType::TEXT_CHANGE, textCache, textForDisplay_);
2775         OnAfterModifyDone();
2776         for (const auto& item : spans_) {
2777             if (item->inspectId.empty()) {
2778                 continue;
2779             }
2780             Recorder::NodeDataCache::Get().PutString(host, item->inspectId, item->content);
2781         }
2782         ResetAfterTextChange();
2783     }
2784     if (isSpanHasClick) {
2785         auto gestureEventHub = host->GetOrCreateGestureEventHub();
2786         InitClickEvent(gestureEventHub);
2787     }
2788     if (textForAICache != dataDetectorAdapter_->textForAI_) {
2789         dataDetectorAdapter_->aiDetectInitialized_ = false;
2790     }
2791     if (CanStartAITask() && !dataDetectorAdapter_->aiDetectInitialized_) {
2792         ParseOriText(textLayoutProperty->GetContent().value_or(""));
2793         if (!dataDetectorAdapter_->aiDetectInitialized_) {
2794             dataDetectorAdapter_->StartAITask();
2795         }
2796     }
2797 }
2798 
ResetAfterTextChange()2799 void TextPattern::ResetAfterTextChange()
2800 {
2801     CloseSelectOverlay();
2802     ResetSelection();
2803 }
2804 
ParseOriText(const std::string & currentText)2805 void TextPattern::ParseOriText(const std::string& currentText)
2806 {
2807     auto entityJson = JsonUtil::ParseJsonString(currentText);
2808     bool entityIsJson = !entityJson->IsNull();
2809     TAG_LOGI(AceLogTag::ACE_TEXT, "text content is the json format: %{public}d", entityIsJson);
2810     if (entityIsJson && !entityJson->GetValue("bundleName")->IsNull() &&
2811         dataDetectorAdapter_->ParseOriText(entityJson, textForDisplay_)) {
2812         if (childNodes_.empty()) {
2813             auto textLayoutProperty = GetLayoutProperty<TextLayoutProperty>();
2814             CHECK_NULL_VOID(textLayoutProperty);
2815             textLayoutProperty->UpdateContent(textForDisplay_);
2816         }
2817     }
2818 }
2819 
BeforeCreateLayoutWrapper()2820 void TextPattern::BeforeCreateLayoutWrapper()
2821 {
2822     if (!isSpanStringMode_) {
2823         PreCreateLayoutWrapper();
2824     }
2825     selectOverlay_->MarkOverlayDirty();
2826 }
2827 
CollectSpanNodes(std::stack<SpanNodeInfo> nodes,bool & isSpanHasClick)2828 void TextPattern::CollectSpanNodes(std::stack<SpanNodeInfo> nodes, bool& isSpanHasClick)
2829 {
2830     while (!nodes.empty()) {
2831         auto current = nodes.top();
2832         nodes.pop();
2833         if (!current.node) {
2834             continue;
2835         }
2836         UpdateContainerChildren(current.containerSpanNode, current.node);
2837         auto spanNode = DynamicCast<SpanNode>(current.node);
2838         auto tag = current.node->GetTag();
2839         if (spanNode && tag == V2::SYMBOL_SPAN_ETS_TAG && spanNode->GetSpanItem()->GetSymbolUnicode() != 0) {
2840             spanNode->CleanSpanItemChildren();
2841             UpdateChildProperty(spanNode);
2842             spanNode->MountToParagraph();
2843             textForDisplay_.append("  ");
2844             dataDetectorAdapter_->textForAI_.append(StringUtils::Str16ToStr8(SYMBOL_TRANS));
2845             childNodes_.push_back(current.node);
2846         } else if (spanNode && tag != V2::PLACEHOLDER_SPAN_ETS_TAG) {
2847             CollectTextSpanNodes(spanNode, isSpanHasClick);
2848             childNodes_.push_back(current.node);
2849         } else if (tag == V2::IMAGE_ETS_TAG || tag == V2::PLACEHOLDER_SPAN_ETS_TAG) {
2850             placeholderCount_++;
2851             AddChildSpanItem(current.node);
2852             dataDetectorAdapter_->textForAI_.append("\n");
2853             auto imageNode = DynamicCast<FrameNode>(current.node);
2854             if (!imageNode) {
2855                 continue;
2856             }
2857             auto focus_hub = imageNode->GetOrCreateFocusHub();
2858             if (focus_hub && focus_hub->GetOnClickCallback()) {
2859                 isSpanHasClick = true;
2860             }
2861             childNodes_.push_back(current.node);
2862         } else if (tag == V2::CUSTOM_SPAN_NODE_ETS_TAG) {
2863             placeholderCount_++;
2864             AddChildSpanItem(current.node);
2865             dataDetectorAdapter_->textForAI_.append("\n");
2866             childNodes_.emplace_back(current.node);
2867         }
2868         if (tag == V2::PLACEHOLDER_SPAN_ETS_TAG) {
2869             continue;
2870         }
2871         const auto& nextChildren = current.node->GetChildren();
2872         if (nextChildren.empty()) {
2873             continue;
2874         }
2875         auto containerSpanNode = tag == V2::CONTAINER_SPAN_ETS_TAG ? current.node : current.containerSpanNode;
2876         for (auto iter = nextChildren.rbegin(); iter != nextChildren.rend(); ++iter) {
2877             nodes.push({ .node = *iter, .containerSpanNode = containerSpanNode });
2878         }
2879     }
2880 }
2881 
CollectTextSpanNodes(const RefPtr<SpanNode> & spanNode,bool & isSpanHasClick)2882 void TextPattern::CollectTextSpanNodes(const RefPtr<SpanNode>& spanNode, bool& isSpanHasClick)
2883 {
2884     spanNode->CleanSpanItemChildren();
2885     UpdateChildProperty(spanNode);
2886     spanNode->MountToParagraph();
2887     textForDisplay_.append(spanNode->GetSpanItem()->content);
2888     dataDetectorAdapter_->textForAI_.append(spanNode->GetSpanItem()->content);
2889     if (spanNode->GetSpanItem()->onClick) {
2890         isSpanHasClick = true;
2891     }
2892 }
2893 
UpdateContainerChildren(const RefPtr<UINode> & parentNode,const RefPtr<UINode> & child)2894 void TextPattern::UpdateContainerChildren(const RefPtr<UINode>& parentNode, const RefPtr<UINode>& child)
2895 {
2896     CHECK_NULL_VOID(child);
2897     auto parent = DynamicCast<ContainerSpanNode>(parentNode);
2898     CHECK_NULL_VOID(parent);
2899     auto baseSpan = DynamicCast<BaseSpan>(child);
2900     if (baseSpan) {
2901         if (baseSpan->HasTextBackgroundStyle()) {
2902             return;
2903         }
2904         baseSpan->UpdateTextBackgroundFromParent(parent->GetTextBackgroundStyle());
2905         return;
2906     }
2907     if (child->GetTag() == V2::IMAGE_ETS_TAG) {
2908         auto imageNode = DynamicCast<FrameNode>(child);
2909         CHECK_NULL_VOID(imageNode);
2910         auto imageLayoutProperty = imageNode->GetLayoutProperty<ImageLayoutProperty>();
2911         CHECK_NULL_VOID(imageLayoutProperty);
2912         if (imageLayoutProperty->GetHasPlaceHolderStyleValue(false)) {
2913             return;
2914         }
2915         if (parent->GetTextBackgroundStyle().has_value()) {
2916             imageLayoutProperty->UpdatePlaceHolderStyle(parent->GetTextBackgroundStyle().value());
2917         }
2918     }
2919 }
2920 
GetGlobalOffset(Offset & offset)2921 void TextPattern::GetGlobalOffset(Offset& offset)
2922 {
2923     auto host = GetHost();
2924     CHECK_NULL_VOID(host);
2925     auto pipeline = PipelineContext::GetCurrentContextSafely();
2926     CHECK_NULL_VOID(pipeline);
2927     auto rootOffset = pipeline->GetRootRect().GetOffset();
2928     auto globalOffset = host->GetPaintRectOffset(false, true) - rootOffset;
2929     offset = Offset(globalOffset.GetX(), globalOffset.GetY());
2930 }
2931 
OnVisibleChange(bool isVisible)2932 void TextPattern::OnVisibleChange(bool isVisible)
2933 {
2934     if (!isVisible) {
2935         if (textSelector_.IsValid()) {
2936             CloseSelectOverlay();
2937             ResetSelection();
2938         }
2939         if (textDetectEnable_) {
2940             dataDetectorAdapter_->aiDetectDelayTask_.Cancel();
2941         }
2942     } else {
2943         if (CanStartAITask()) {
2944             dataDetectorAdapter_->StartAITask();
2945         }
2946     }
2947 }
2948 
InitSurfaceChangedCallback()2949 void TextPattern::InitSurfaceChangedCallback()
2950 {
2951     auto pipeline = PipelineContext::GetCurrentContextSafely();
2952     CHECK_NULL_VOID(pipeline);
2953     if (!HasSurfaceChangedCallback()) {
2954         auto callbackId = pipeline->RegisterSurfaceChangedCallback(
2955             [weak = WeakClaim(this)](int32_t newWidth, int32_t newHeight, int32_t prevWidth, int32_t prevHeight,
2956                 WindowSizeChangeReason type) {
2957                 auto pattern = weak.Upgrade();
2958                 if (pattern) {
2959                     pattern->HandleSurfaceChanged(newWidth, newHeight, prevWidth, prevHeight);
2960                 }
2961             });
2962         UpdateSurfaceChangedCallbackId(callbackId);
2963     }
2964 }
2965 
HandleSurfaceChanged(int32_t newWidth,int32_t newHeight,int32_t prevWidth,int32_t prevHeight)2966 void TextPattern::HandleSurfaceChanged(int32_t newWidth, int32_t newHeight, int32_t prevWidth, int32_t prevHeight)
2967 {
2968     TAG_LOGD(AceLogTag::ACE_TEXT_FIELD,
2969         "TextPattern handle surface change, new width %{public}d, new height %{public}d, prev width %{public}d, prev "
2970         "height %{public}d",
2971         newWidth, newHeight, prevWidth, prevHeight);
2972     if (newWidth == prevWidth && newHeight == prevHeight) {
2973         return;
2974     }
2975     CHECK_NULL_VOID(selectOverlay_->SelectOverlayIsOn());
2976     if (selectOverlay_->IsShowMouseMenu()) {
2977         CloseSelectOverlay();
2978     } else {
2979         auto context = PipelineContext::GetCurrentContextSafely();
2980         if (context) {
2981             context->AddAfterLayoutTask([weak = WeakClaim(this)]() {
2982                 auto pattern = weak.Upgrade();
2983                 CHECK_NULL_VOID(pattern);
2984                 pattern->CalculateHandleOffsetAndShowOverlay();
2985                 pattern->ShowSelectOverlay({ .menuIsShow = false });
2986             });
2987         }
2988     }
2989 }
2990 
InitSurfacePositionChangedCallback()2991 void TextPattern::InitSurfacePositionChangedCallback()
2992 {
2993     auto pipeline = PipelineContext::GetCurrentContextSafely();
2994     CHECK_NULL_VOID(pipeline);
2995     if (!HasSurfacePositionChangedCallback()) {
2996         auto callbackId =
2997             pipeline->RegisterSurfacePositionChangedCallback([weak = WeakClaim(this)](int32_t posX, int32_t posY) {
2998                 auto pattern = weak.Upgrade();
2999                 if (pattern) {
3000                     pattern->HandleSurfacePositionChanged(posX, posY);
3001                 }
3002             });
3003         UpdateSurfacePositionChangedCallbackId(callbackId);
3004     }
3005 }
3006 
AddChildSpanItem(const RefPtr<UINode> & child)3007 void TextPattern::AddChildSpanItem(const RefPtr<UINode>& child)
3008 {
3009     CHECK_NULL_VOID(child);
3010     auto chidNode = DynamicCast<FrameNode>(child);
3011     if (chidNode && chidNode->GetLayoutProperty() && chidNode->GetLayoutProperty()->IsOverlayNode()) {
3012         return;
3013     }
3014 
3015     if (child->GetTag() == V2::SPAN_ETS_TAG || child->GetTag() == V2::SYMBOL_SPAN_ETS_TAG) {
3016         auto spanNode = DynamicCast<SpanNode>(child);
3017         if (spanNode) {
3018             spans_.emplace_back(spanNode->GetSpanItem());
3019         }
3020     } else if (child->GetTag() == V2::IMAGE_ETS_TAG) {
3021         AddImageToSpanItem(child);
3022     } else if (child->GetTag() == V2::PLACEHOLDER_SPAN_ETS_TAG) {
3023         auto placeholderSpanNode = DynamicCast<PlaceholderSpanNode>(child);
3024         if (placeholderSpanNode) {
3025             auto placeholderSpan = placeholderSpanNode->GetSpanItem();
3026             placeholderSpan->placeholderSpanNodeId = placeholderSpanNode->GetId();
3027             spans_.emplace_back(placeholderSpan);
3028         }
3029     } else if (child->GetTag() == V2::CUSTOM_SPAN_NODE_ETS_TAG) {
3030         auto customSpanNode = DynamicCast<CustomSpanNode>(child);
3031         if (customSpanNode) {
3032             auto customSpan = customSpanNode->GetSpanItem();
3033             customSpan->placeholderSpanNodeId = customSpanNode->GetId();
3034             spans_.emplace_back(customSpan);
3035         }
3036     }
3037 }
3038 
AddImageToSpanItem(const RefPtr<UINode> & child)3039 void TextPattern::AddImageToSpanItem(const RefPtr<UINode>& child)
3040 {
3041     auto imageSpanNode = DynamicCast<ImageSpanNode>(child);
3042     if (imageSpanNode) {
3043         auto host = GetHost();
3044         CHECK_NULL_VOID(host);
3045         auto imageSpanItem = imageSpanNode->GetSpanItem();
3046         if (host->GetTag() != V2::RICH_EDITOR_ETS_TAG) {
3047             auto focus_hub = imageSpanNode->GetOrCreateFocusHub();
3048             CHECK_NULL_VOID(focus_hub);
3049             auto clickCall = focus_hub->GetOnClickCallback();
3050             if (clickCall) {
3051                 imageSpanItem->SetOnClickEvent(std::move(clickCall));
3052             }
3053             auto gesture = imageSpanNode->GetOrCreateGestureEventHub();
3054             CHECK_NULL_VOID(gesture);
3055             gesture->SetHitTestMode(HitTestMode::HTMNONE);
3056         }
3057         imageSpanItem->UpdatePlaceholderBackgroundStyle(imageSpanNode);
3058         spans_.emplace_back(imageSpanItem);
3059         spans_.back()->imageNodeId = imageSpanNode->GetId();
3060         return;
3061     }
3062     auto imageNode = DynamicCast<FrameNode>(child);
3063     if (imageNode) {
3064         auto imageSpanItem = MakeRefPtr<ImageSpanItem>();
3065         imageSpanItem->imageNodeId = imageNode->GetId();
3066         imageSpanItem->UpdatePlaceholderBackgroundStyle(imageNode);
3067         auto focus_hub = imageNode->GetOrCreateFocusHub();
3068         CHECK_NULL_VOID(focus_hub);
3069         auto clickCall = focus_hub->GetOnClickCallback();
3070         if (clickCall) {
3071             imageSpanItem->SetOnClickEvent(std::move(clickCall));
3072         }
3073         spans_.emplace_back(imageSpanItem);
3074         auto gesture = imageNode->GetOrCreateGestureEventHub();
3075         CHECK_NULL_VOID(gesture);
3076         gesture->SetHitTestMode(HitTestMode::HTMNONE);
3077         return;
3078     }
3079 }
3080 
DumpAdvanceInfo()3081 void TextPattern::DumpAdvanceInfo()
3082 {
3083     DumpLog::GetInstance().AddDesc(std::string("-----DumpAdvanceInfo-----"));
3084     DumpLog::GetInstance().AddDesc(
3085         std::string("BindSelectionMenu: ").append(std::to_string(selectionMenuMap_.empty())));
3086     auto host = GetHost();
3087     CHECK_NULL_VOID(host);
3088     auto renderContext = host->GetRenderContext();
3089     CHECK_NULL_VOID(renderContext);
3090     if (renderContext->HasForegroundColor()) {
3091         DumpLog::GetInstance().AddDesc(
3092             std::string("ForegroundColor: ").append(renderContext->GetForegroundColorValue().ColorToString()));
3093     }
3094     if (renderContext->GetForegroundColorStrategy().has_value()) {
3095         auto strategy = static_cast<int32_t>(renderContext->GetForegroundColorStrategyValue());
3096         DumpLog::GetInstance().AddDesc(std::string("ForegroundColorStrategy: ").append(std::to_string(strategy)));
3097     }
3098     DumpLog::GetInstance().AddDesc(std::string("Selection: ").append("(").append(textSelector_.ToString()).append(")"));
3099 }
3100 
DumpInfo()3101 void TextPattern::DumpInfo()
3102 {
3103     auto textLayoutProp = GetLayoutProperty<TextLayoutProperty>();
3104     CHECK_NULL_VOID(textLayoutProp);
3105     auto& dumpLog = DumpLog::GetInstance();
3106     auto nowTime = GetSystemTimestamp();
3107     dumpLog.AddDesc(std::string("frameRecord: ").append(frameRecord_));
3108     dumpLog.AddDesc(std::string("time: ").append(std::to_string(nowTime)));
3109     if (!IsSetObscured()) {
3110         dumpLog.AddDesc(std::string("Content: ").append(textLayoutProp->GetContent().value_or(" ")));
3111     }
3112     dumpLog.AddDesc(std::string("FontColor: ")
3113                         .append((textStyle_.has_value() ? textStyle_->GetTextColor() : Color::BLACK).ColorToString()));
3114     dumpLog.AddDesc(
3115         std::string("FontSize: ")
3116             .append((textStyle_.has_value() ? textStyle_->GetFontSize() : Dimension(DIMENSION_VALUE, DimensionUnit::FP))
3117                         .ToString()));
3118     if (textStyle_.has_value()) {
3119         dumpLog.AddDesc(std::string("MaxFontSize: ").append(textStyle_->GetAdaptMaxFontSize().ToString()));
3120         dumpLog.AddDesc(std::string("MinFontSize: ").append(textStyle_->GetAdaptMinFontSize().ToString()));
3121         dumpLog.AddDesc(std::string("FontWeight: ").append(StringUtils::ToString(textStyle_->GetFontWeight())));
3122         dumpLog.AddDesc(std::string("FontStyle: ").append(StringUtils::ToString(textStyle_->GetFontStyle())));
3123         dumpLog.AddDesc(std::string("LineHeight: ").append(textStyle_->GetLineHeight().ToString()));
3124         dumpLog.AddDesc(std::string("LineSpacing: ").append(textStyle_->GetLineSpacing().ToString()));
3125         dumpLog.AddDesc(std::string("maxLines: ").append(std::to_string(textStyle_->GetMaxLines())));
3126         dumpLog.AddDesc(std::string("BaselineOffset: ").append(textStyle_->GetBaselineOffset().ToString()));
3127         dumpLog.AddDesc(std::string("TextIndent: ").append(textStyle_->GetTextIndent().ToString()));
3128         dumpLog.AddDesc(std::string("LetterSpacing: ").append(textStyle_->GetLetterSpacing().ToString()));
3129         dumpLog.AddDesc(std::string("TextOverflow: ").append(StringUtils::ToString(textStyle_->GetTextOverflow())));
3130         dumpLog.AddDesc(std::string("TextAlign: ").append(StringUtils::ToString(textStyle_->GetTextAlign())));
3131         dumpLog.AddDesc(std::string("WordBreak: ").append(StringUtils::ToString(textStyle_->GetWordBreak())));
3132         dumpLog.AddDesc(std::string("TextCase: ").append(StringUtils::ToString(textStyle_->GetTextCase())));
3133         dumpLog.AddDesc(std::string("EllipsisMode: ").append(StringUtils::ToString(textStyle_->GetEllipsisMode())));
3134         dumpLog.AddDesc(
3135             std::string("LineBreakStrategy: ").append(GetLineBreakStrategyInJson(textStyle_->GetLineBreakStrategy())));
3136     }
3137     dumpLog.AddDesc(
3138         std::string("HeightAdaptivePolicy: ")
3139             .append(V2::ConvertWrapTextHeightAdaptivePolicyToString(
3140                 textLayoutProp->GetHeightAdaptivePolicy().value_or(TextHeightAdaptivePolicy::MAX_LINES_FIRST))));
3141     if (pManager_) {
3142         auto num = static_cast<int32_t>(pManager_->GetParagraphs().size());
3143         dumpLog.AddDesc(std::string("Paragraphs num: ").append(std::to_string(num)));
3144         dumpLog.AddDesc(std::string("PaintInfo: ").append(paintInfo_));
3145     }
3146     DumpScaleInfo();
3147     DumpTextEngineInfo();
3148     if (SystemProperties::GetDebugEnabled()) {
3149         DumpAdvanceInfo();
3150     }
3151 }
3152 
DumpScaleInfo()3153 void TextPattern::DumpScaleInfo()
3154 {
3155     auto& dumpLog = DumpLog::GetInstance();
3156     dumpLog.AddDesc(std::string("-----DumpScaleInfo-----"));
3157     auto host = GetHost();
3158     CHECK_NULL_VOID(host);
3159     auto pipeline = host->GetContext();
3160     CHECK_NULL_VOID(pipeline);
3161     auto fontScale = pipeline->GetFontScale();
3162     auto fontWeightScale = pipeline->GetFontWeightScale();
3163     auto followSystem = pipeline->IsFollowSystem();
3164     float maxFontScale = pipeline->GetMaxAppFontScale();
3165     auto halfLeading = pipeline->GetHalfLeading();
3166     dumpLog.AddDesc(std::string("fontScale: ").append(std::to_string(fontScale)));
3167     dumpLog.AddDesc(std::string("fontWeightScale: ").append(std::to_string(fontWeightScale)));
3168     dumpLog.AddDesc(std::string("IsFollowSystem: ").append(std::to_string(followSystem)));
3169     dumpLog.AddDesc(std::string("maxFontScale: ").append(std::to_string(maxFontScale)));
3170     dumpLog.AddDesc(std::string("halfLeading: ").append(std::to_string(halfLeading)));
3171 }
3172 
DumpTextEngineInfo()3173 void TextPattern::DumpTextEngineInfo()
3174 {
3175     auto& dumpLog = DumpLog::GetInstance();
3176     dumpLog.AddDesc(std::string("-----TextEngine paragraphs_ info-----"));
3177     dumpLog.AddDesc(std::string("contentRect :").append(contentRect_.ToString()));
3178     if (pManager_) {
3179         dumpLog.AddDesc(std::string("from TextEngine paragraphs_ info :"));
3180         dumpLog.AddDesc(std::string("DidExceedMaxLines:").append(std::to_string(pManager_->DidExceedMaxLines())));
3181         dumpLog.AddDesc(std::string("GetTextWidth:")
3182                             .append(std::to_string(pManager_->GetTextWidth()))
3183                             .append(" GetHeight:")
3184                             .append(std::to_string(pManager_->GetHeight()))
3185                             .append(" GetMaxWidth:")
3186                             .append(std::to_string(pManager_->GetMaxWidth()))
3187                             .append(" GetMaxIntrinsicWidth:")
3188                             .append(std::to_string(pManager_->GetMaxIntrinsicWidth())));
3189         dumpLog.AddDesc(std::string("GetLineCount:")
3190                             .append(std::to_string(pManager_->GetLineCount()))
3191                             .append(" GetLongestLine:")
3192                             .append(std::to_string(pManager_->GetLongestLine()))
3193                             .append(" GetLongestLineWithIndent:")
3194                             .append(std::to_string(pManager_->GetLongestLineWithIndent())));
3195     }
3196     dumpLog.AddDesc(std::string("spans size :").append(std::to_string(spans_.size())));
3197 }
3198 
UpdateChildProperty(const RefPtr<SpanNode> & child) const3199 void TextPattern::UpdateChildProperty(const RefPtr<SpanNode>& child) const
3200 {
3201     CHECK_NULL_VOID(child);
3202     auto host = GetHost();
3203     CHECK_NULL_VOID(host);
3204     auto textLayoutProp = host->GetLayoutProperty<TextLayoutProperty>();
3205     CHECK_NULL_VOID(textLayoutProp);
3206 
3207     auto inheritPropertyInfo = child->CalculateInheritPropertyInfo();
3208     for (const PropertyInfo& info : inheritPropertyInfo) {
3209         switch (info) {
3210             case PropertyInfo::FONTSIZE:
3211                 if (textLayoutProp->HasFontSize()) {
3212                     child->UpdateFontSizeWithoutFlushDirty(textLayoutProp->GetFontSize().value());
3213                 }
3214                 break;
3215             case PropertyInfo::FONTCOLOR:
3216                 if (textLayoutProp->HasTextColor()) {
3217                     child->UpdateTextColorWithoutFlushDirty(textLayoutProp->GetTextColor().value());
3218                 }
3219                 break;
3220             case PropertyInfo::FONTSTYLE:
3221                 if (textLayoutProp->HasItalicFontStyle()) {
3222                     child->UpdateItalicFontStyleWithoutFlushDirty(textLayoutProp->GetItalicFontStyle().value());
3223                 }
3224                 break;
3225             case PropertyInfo::FONTWEIGHT:
3226                 if (textLayoutProp->HasFontWeight()) {
3227                     child->UpdateFontWeightWithoutFlushDirty(textLayoutProp->GetFontWeight().value());
3228                 }
3229                 break;
3230             case PropertyInfo::FONTFAMILY:
3231                 if (textLayoutProp->HasFontFamily()) {
3232                     child->UpdateFontFamilyWithoutFlushDirty(textLayoutProp->GetFontFamily().value());
3233                 }
3234                 break;
3235             case PropertyInfo::FONTFEATURE:
3236                 if (textLayoutProp->HasFontFeature()) {
3237                     child->UpdateFontFeatureWithoutFlushDirty(textLayoutProp->GetFontFeature().value());
3238                 }
3239                 break;
3240             case PropertyInfo::TEXTDECORATION:
3241                 if (textLayoutProp->HasTextDecoration()) {
3242                     child->UpdateTextDecorationWithoutFlushDirty(textLayoutProp->GetTextDecoration().value());
3243                     if (textLayoutProp->HasTextDecorationColor()) {
3244                         child->UpdateTextDecorationColorWithoutFlushDirty(
3245                             textLayoutProp->GetTextDecorationColor().value());
3246                     }
3247                     if (textLayoutProp->HasTextDecorationStyle()) {
3248                         child->UpdateTextDecorationStyleWithoutFlushDirty(
3249                             textLayoutProp->GetTextDecorationStyle().value());
3250                     }
3251                 }
3252                 break;
3253             case PropertyInfo::TEXTCASE:
3254                 if (textLayoutProp->HasTextCase()) {
3255                     child->UpdateTextCaseWithoutFlushDirty(textLayoutProp->GetTextCase().value());
3256                 }
3257                 break;
3258             case PropertyInfo::LETTERSPACE:
3259                 if (textLayoutProp->HasLetterSpacing()) {
3260                     child->UpdateLetterSpacingWithoutFlushDirty(textLayoutProp->GetLetterSpacing().value());
3261                 }
3262                 break;
3263             case PropertyInfo::LINEHEIGHT:
3264                 if (textLayoutProp->HasLineHeight()) {
3265                     child->UpdateLineHeightWithoutFlushDirty(textLayoutProp->GetLineHeight().value());
3266                 }
3267                 break;
3268             case PropertyInfo::LINESPACING:
3269                 if (textLayoutProp->HasLineSpacing()) {
3270                     child->UpdateLineSpacingWithoutFlushDirty(textLayoutProp->GetLineSpacing().value());
3271                 }
3272                 break;
3273             case PropertyInfo::MIN_FONT_SCALE:
3274                 if (textLayoutProp->HasMinFontScale()) {
3275                     child->UpdateMinFontScaleWithoutFlushDirty(textLayoutProp->GetMinFontScale().value());
3276                 }
3277                 break;
3278             case PropertyInfo::MAX_FONT_SCALE:
3279                 if (textLayoutProp->HasMaxFontScale()) {
3280                     child->UpdateMaxFontScaleWithoutFlushDirty(textLayoutProp->GetMaxFontScale().value());
3281                 }
3282                 break;
3283             case PropertyInfo::TEXTSHADOW:
3284                 if (textLayoutProp->HasTextShadow()) {
3285                     child->UpdateTextShadowWithoutFlushDirty(textLayoutProp->GetTextShadow().value());
3286                 }
3287                 break;
3288             case PropertyInfo::HALFLEADING:
3289                 if (textLayoutProp->HasHalfLeading()) {
3290                     child->UpdateHalfLeadingWithoutFlushDirty(textLayoutProp->GetHalfLeading().value());
3291                 }
3292                 break;
3293             case PropertyInfo::VARIABLE_FONT_WEIGHT:
3294                 if (textLayoutProp->HasVariableFontWeight() && !child->GetHasUserFontWeight()) {
3295                     child->UpdateVariableFontWeightWithoutFlushDirty(textLayoutProp->GetVariableFontWeight().value());
3296                 }
3297                 break;
3298             case PropertyInfo::ENABLE_VARIABLE_FONT_WEIGHT:
3299                 if (textLayoutProp->HasEnableVariableFontWeight() && !child->GetHasUserFontWeight()) {
3300                     child->UpdateEnableVariableFontWeightWithoutFlushDirty(
3301                         textLayoutProp->GetEnableVariableFontWeight().value());
3302                 }
3303                 break;
3304             default:
3305                 break;
3306         }
3307     }
3308 }
3309 
SetAccessibilityAction()3310 void TextPattern::SetAccessibilityAction()
3311 {
3312     auto host = GetHost();
3313     CHECK_NULL_VOID(host);
3314     auto textAccessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
3315     CHECK_NULL_VOID(textAccessibilityProperty);
3316     textAccessibilityProperty->SetActionSetSelection(
3317         [weakPtr = WeakClaim(this)](int32_t start, int32_t end, bool isForward) {
3318             const auto& pattern = weakPtr.Upgrade();
3319             CHECK_NULL_VOID(pattern);
3320             auto textLayoutProperty = pattern->GetLayoutProperty<TextLayoutProperty>();
3321             CHECK_NULL_VOID(textLayoutProperty);
3322             auto mode = textLayoutProperty->GetTextSelectableModeValue(TextSelectableMode::SELECTABLE_UNFOCUSABLE);
3323             if (textLayoutProperty->GetCopyOptionValue(CopyOptions::None) != CopyOptions::None &&
3324                 mode != TextSelectableMode::UNSELECTABLE) {
3325                 pattern->ActSetSelection(start, end);
3326             }
3327         });
3328 
3329     textAccessibilityProperty->SetActionClearSelection([weakPtr = WeakClaim(this)]() {
3330         const auto& pattern = weakPtr.Upgrade();
3331         CHECK_NULL_VOID(pattern);
3332         auto textLayoutProperty = pattern->GetLayoutProperty<TextLayoutProperty>();
3333         CHECK_NULL_VOID(textLayoutProperty);
3334         auto mode = textLayoutProperty->GetTextSelectableModeValue(TextSelectableMode::SELECTABLE_UNFOCUSABLE);
3335         if (textLayoutProperty->GetCopyOptionValue(CopyOptions::None) != CopyOptions::None &&
3336             mode != TextSelectableMode::UNSELECTABLE) {
3337             pattern->CloseSelectOverlay(true);
3338             pattern->ResetSelection();
3339         }
3340     });
3341 
3342     textAccessibilityProperty->SetActionCopy([weakPtr = WeakClaim(this)]() {
3343         const auto& pattern = weakPtr.Upgrade();
3344         CHECK_NULL_VOID(pattern);
3345         auto textLayoutProperty = pattern->GetLayoutProperty<TextLayoutProperty>();
3346         CHECK_NULL_VOID(textLayoutProperty);
3347         auto mode = textLayoutProperty->GetTextSelectableModeValue(TextSelectableMode::SELECTABLE_UNFOCUSABLE);
3348         if (textLayoutProperty->GetCopyOptionValue(CopyOptions::None) != CopyOptions::None &&
3349             mode != TextSelectableMode::UNSELECTABLE) {
3350             pattern->HandleOnCopy();
3351             pattern->CloseSelectOverlay(true);
3352             pattern->ResetSelection();
3353         }
3354     });
3355 }
3356 
OnColorConfigurationUpdate()3357 void TextPattern::OnColorConfigurationUpdate()
3358 {
3359     auto textLayoutProperty = GetLayoutProperty<TextLayoutProperty>();
3360     CHECK_NULL_VOID(textLayoutProperty);
3361     CHECK_NULL_VOID(!textLayoutProperty->GetTextColorFlagByUserValue(false));
3362     auto context = PipelineContext::GetCurrentContextSafely();
3363     CHECK_NULL_VOID(context);
3364     auto theme = context->GetTheme<TextTheme>();
3365     CHECK_NULL_VOID(theme);
3366     textLayoutProperty->UpdateTextColor(theme->GetTextStyle().GetTextColor());
3367     if (magnifierController_) {
3368         magnifierController_->SetColorModeChange(true);
3369     }
3370     auto host = GetHost();
3371     CHECK_NULL_VOID(host);
3372     ACE_TEXT_SCOPED_TRACE("OnColorConfigurationUpdate[Text][self:%d]", host->GetId());
3373 }
3374 
GetDragUpperLeftCoordinates()3375 OffsetF TextPattern::GetDragUpperLeftCoordinates()
3376 {
3377     if (dragBoxes_.empty()) {
3378         return { 0.0f, 0.0f };
3379     }
3380     auto startY = dragBoxes_.front().Top();
3381     auto startX = dragBoxes_.front().Left();
3382 
3383     auto endY = dragBoxes_.back().Top();
3384     OffsetF offset;
3385     if (NearEqual(startY, endY)) {
3386         offset = { contentRect_.GetX() + startX, startY + contentRect_.GetY() };
3387     } else {
3388         offset = { contentRect_.GetX(), startY + contentRect_.GetY() };
3389     }
3390 
3391     return GetParentGlobalOffset() + offset;
3392 }
3393 
ProcessBoundRectByTextShadow(RectF & rect)3394 void TextPattern::ProcessBoundRectByTextShadow(RectF& rect)
3395 {
3396     auto property = GetHost()->GetLayoutProperty<TextLayoutProperty>();
3397     auto shadows = property->GetTextShadow();
3398     if (!shadows.has_value()) {
3399         return;
3400     }
3401     float leftOffsetX = 0.0f;
3402     float rightOffsetX = 0.0f;
3403     float upOffsetY = 0.0f;
3404     float downOffsetY = 0.0f;
3405     for (const auto& shadow : shadows.value()) {
3406         auto shadowBlurRadius = shadow.GetBlurRadius() * 2.0f;
3407         if (LessOrEqual(shadow.GetOffset().GetX(), 0.0f) && LessNotEqual(shadow.GetOffset().GetX(), leftOffsetX)) {
3408             leftOffsetX = shadow.GetOffset().GetX() - shadowBlurRadius;
3409         }
3410 
3411         if (GreatOrEqual(shadow.GetOffset().GetX(), 0.0f) &&
3412             GreatNotEqual(shadow.GetOffset().GetX() + shadowBlurRadius, rightOffsetX)) {
3413             rightOffsetX = shadow.GetOffset().GetX() + shadowBlurRadius;
3414         }
3415 
3416         if (LessOrEqual(shadow.GetOffset().GetY(), 0.0f) && LessNotEqual(shadow.GetOffset().GetY(), upOffsetY)) {
3417             upOffsetY = shadow.GetOffset().GetY() - shadowBlurRadius;
3418         }
3419 
3420         if (GreatOrEqual(shadow.GetOffset().GetY(), 0.0f) &&
3421             GreatNotEqual(shadow.GetOffset().GetY() + shadowBlurRadius, downOffsetY)) {
3422             downOffsetY = shadow.GetOffset().GetY() + shadowBlurRadius;
3423         }
3424     }
3425     rect.SetRect(
3426         leftOffsetX, upOffsetY, rect.Width() + rightOffsetX - leftOffsetX, rect.Height() + downOffsetY - upOffsetY);
3427 }
3428 
ProcessBoundRectByTextMarquee(RectF & rect)3429 void TextPattern::ProcessBoundRectByTextMarquee(RectF& rect)
3430 {
3431     auto host = GetHost();
3432     CHECK_NULL_VOID(host);
3433     auto textLayoutProperty = host->GetLayoutProperty<TextLayoutProperty>();
3434     CHECK_NULL_VOID(textLayoutProperty);
3435     if (!(textLayoutProperty->GetTextOverflowValue(TextOverflow::CLIP) == TextOverflow::MARQUEE)) {
3436         return;
3437     }
3438     auto geometryNode = host->GetGeometryNode();
3439     CHECK_NULL_VOID(geometryNode);
3440     auto contentSize = geometryNode->GetContentSize();
3441     CHECK_NULL_VOID(pManager_);
3442     if (pManager_->GetTextWidth() < contentSize.Width()) {
3443         return;
3444     }
3445     auto frameSize = geometryNode->GetFrameSize();
3446     auto relativeSelfLeftOffsetX =
3447         std::max(-1 * host->GetOffsetRelativeToWindow().GetX(), rect.GetOffset().GetX() - pManager_->GetTextWidth());
3448     rect.SetLeft(relativeSelfLeftOffsetX);
3449     rect.SetWidth(frameSize.Width() + pManager_->GetTextWidth() - relativeSelfLeftOffsetX);
3450 }
3451 
CreateNodePaintMethod()3452 RefPtr<NodePaintMethod> TextPattern::CreateNodePaintMethod()
3453 {
3454     CreateModifier();
3455     auto paintMethod =
3456         MakeRefPtr<TextPaintMethod>(WeakClaim(this), baselineOffset_, contentMod_, overlayMod_);
3457     auto host = GetHost();
3458     CHECK_NULL_RETURN(host, paintMethod);
3459     auto context = host->GetRenderContext();
3460     CHECK_NULL_RETURN(context, paintMethod);
3461     auto geometryNode = host->GetGeometryNode();
3462     CHECK_NULL_RETURN(geometryNode, paintMethod);
3463     auto frameSize = geometryNode->GetFrameSize();
3464     if (context->GetClipEdge().value_or(Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE))) {
3465         SetResponseRegion(frameSize, frameSize);
3466         return paintMethod;
3467     }
3468     CHECK_NULL_RETURN(pManager_, paintMethod);
3469     RectF boundsRect = overlayMod_->GetBoundsRect();
3470     auto boundsWidth = contentRect_.GetX() + std::ceil(pManager_->GetLongestLineWithIndent());
3471     auto boundsHeight = contentRect_.GetY() + static_cast<float>(pManager_->GetHeight() + std::fabs(baselineOffset_));
3472     boundsRect.SetWidth(boundsWidth);
3473     boundsRect.SetHeight(boundsHeight);
3474     SetResponseRegion(frameSize, boundsRect.GetSize());
3475     ProcessBoundRectByTextShadow(boundsRect);
3476     ProcessBoundRectByTextMarquee(boundsRect);
3477     boundsRect.SetWidth(std::max(frameSize.Width(), boundsRect.Width()));
3478     boundsRect.SetHeight(std::max(frameSize.Height(), boundsRect.Height()));
3479     auto baselineOffset = LessOrEqual(baselineOffset_, 0) ? std::fabs(baselineOffset_) : 0;
3480     pManager_->GetPaintRegion(boundsRect, contentRect_.GetX(), contentRect_.GetY() + baselineOffset);
3481     overlayMod_->SetBoundsRect(boundsRect);
3482     return paintMethod;
3483 }
3484 
SetResponseRegion(const SizeF & frameSize,const SizeF & boundsSize)3485 void TextPattern::SetResponseRegion(const SizeF& frameSize, const SizeF& boundsSize)
3486 {
3487     auto host = GetHost();
3488     CHECK_NULL_VOID(host);
3489     auto gestureHub = host->GetOrCreateGestureEventHub();
3490     CHECK_NULL_VOID(gestureHub);
3491     if (isUserSetResponseRegion_) {
3492         return;
3493     }
3494     std::vector<DimensionRect> hotZoneRegions;
3495     DimensionRect hotZoneRegion;
3496     hotZoneRegion.SetSize(DimensionSize(Dimension(std::max(boundsSize.Width(), frameSize.Width())),
3497         Dimension(std::max(frameSize.Height(), boundsSize.Height()))));
3498     hotZoneRegions.emplace_back(hotZoneRegion);
3499     gestureHub->SetResponseRegion(hotZoneRegions);
3500 }
3501 
CreateModifier()3502 void TextPattern::CreateModifier()
3503 {
3504     if (!contentMod_) {
3505         contentMod_ = MakeRefPtr<TextContentModifier>(textStyle_, WeakClaim(this));
3506     }
3507     if (!overlayMod_) {
3508         overlayMod_ = MakeRefPtr<TextOverlayModifier>();
3509     }
3510     if (isCustomFont_) {
3511         contentMod_->SetIsCustomFont(true);
3512     }
3513 }
3514 
GetHandleIndex(const Offset & offset) const3515 int32_t TextPattern::GetHandleIndex(const Offset& offset) const
3516 {
3517     return pManager_->GetGlyphIndexByCoordinate(offset);
3518 }
3519 
OnHandleAreaChanged()3520 void TextPattern::OnHandleAreaChanged()
3521 {
3522     if (selectOverlay_->SelectOverlayIsOn()) {
3523         auto parentGlobalOffset = GetParentGlobalOffset();
3524         if (parentGlobalOffset != parentGlobalOffset_) {
3525             parentGlobalOffset_ = parentGlobalOffset;
3526             CalculateHandleOffsetAndShowOverlay();
3527             ShowSelectOverlay({ .menuIsShow = false, .animation = true });
3528         }
3529     }
3530 }
3531 
RemoveAreaChangeInner()3532 void TextPattern::RemoveAreaChangeInner()
3533 {
3534     auto pipeline = PipelineContext::GetCurrentContextSafely();
3535     CHECK_NULL_VOID(pipeline);
3536     auto host = GetHost();
3537     CHECK_NULL_VOID(host);
3538     auto eventHub = host->GetEventHub<TextEventHub>();
3539     CHECK_NULL_VOID(eventHub);
3540     if (eventHub->HasOnAreaChanged()) {
3541         return;
3542     }
3543     pipeline->RemoveOnAreaChangeNode(host->GetId());
3544 }
3545 
SetTextDetectEnable(bool enable)3546 void TextPattern::SetTextDetectEnable(bool enable)
3547 {
3548     auto host = GetHost();
3549     CHECK_NULL_VOID(host);
3550     dataDetectorAdapter_->frameNode_ = host;
3551     if (enable == textDetectEnable_) {
3552         return;
3553     }
3554     textDetectEnable_ = enable;
3555     if (textDetectEnable_) {
3556         auto pipeline = PipelineContext::GetCurrentContextSafely();
3557         CHECK_NULL_VOID(pipeline);
3558         auto callback = [weak = WeakClaim(this)]() {
3559             auto pattern = weak.Upgrade();
3560             CHECK_NULL_VOID(pattern);
3561             pattern->dataDetectorAdapter_->GetAIEntityMenu();
3562         };
3563         pipeline->SetConfigChangedCallback(host->GetId(), callback);
3564     } else {
3565         dataDetectorAdapter_->CancelAITask();
3566     }
3567     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
3568 }
3569 
CanStartAITask()3570 bool TextPattern::CanStartAITask()
3571 {
3572     auto textLayoutProperty = GetLayoutProperty<TextLayoutProperty>();
3573     if (textLayoutProperty) {
3574         return textDetectEnable_ && enabled_ && !IsSetObscured() &&
3575                textLayoutProperty->GetTextOverflowValue(TextOverflow::CLIP) != TextOverflow::MARQUEE;
3576     } else {
3577         return textDetectEnable_ && enabled_;
3578     }
3579 }
3580 
NeedShowAIDetect()3581 bool TextPattern::NeedShowAIDetect()
3582 {
3583     return CanStartAITask() && !dataDetectorAdapter_->aiSpanMap_.empty();
3584 }
3585 
BindSelectionMenu(TextSpanType spanType,TextResponseType responseType,std::function<void ()> & menuBuilder,const SelectMenuParam & menuParam)3586 void TextPattern::BindSelectionMenu(TextSpanType spanType, TextResponseType responseType,
3587     std::function<void()>& menuBuilder, const SelectMenuParam& menuParam)
3588 {
3589     auto key = std::make_pair(spanType, responseType);
3590     auto it = selectionMenuMap_.find(key);
3591     if (it != selectionMenuMap_.end()) {
3592         if (menuBuilder == nullptr) {
3593             selectionMenuMap_.erase(it);
3594             return;
3595         }
3596         it->second->buildFunc = menuBuilder;
3597         it->second->onAppear = menuParam.onAppear;
3598         it->second->onDisappear = menuParam.onDisappear;
3599         it->second->onMenuShow = menuParam.onMenuShow;
3600         it->second->onMenuHide = menuParam.onMenuHide;
3601         it->second->isValid = menuParam.isValid;
3602         return;
3603     }
3604 
3605     auto selectionMenuParams = std::make_shared<SelectionMenuParams>(
3606         spanType, menuBuilder, menuParam.onAppear, menuParam.onDisappear, responseType);
3607     selectionMenuParams->onMenuShow = menuParam.onMenuShow;
3608     selectionMenuParams->onMenuHide = menuParam.onMenuHide;
3609     selectionMenuParams->isValid = menuParam.isValid;
3610     selectionMenuMap_[key] = selectionMenuParams;
3611     auto host = GetHost();
3612     CHECK_NULL_VOID(host);
3613     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
3614 }
3615 
CloseSelectionMenu()3616 void TextPattern::CloseSelectionMenu()
3617 {
3618     textResponseType_ = TextResponseType::NONE;
3619     CloseSelectOverlay(true);
3620 }
3621 
GetMenuParams(TextSpanType spanType,TextResponseType responseType)3622 std::shared_ptr<SelectionMenuParams> TextPattern::GetMenuParams(TextSpanType spanType, TextResponseType responseType)
3623 {
3624     // JS TextSpanType.DEFAULT = TextSpanType::NONE
3625     // JS TextResponseType.DEFAULT = TextResponseType::NONE
3626     std::vector<std::pair<TextSpanType, TextResponseType>> searchPairs = {
3627         { spanType, responseType },
3628         { spanType, TextResponseType::NONE },
3629     };
3630     if (spanType != TextSpanType::NONE) {
3631         searchPairs.push_back({ TextSpanType::NONE, responseType });
3632         searchPairs.push_back({ TextSpanType::NONE, TextResponseType::NONE });
3633     }
3634     for (const auto& key : searchPairs) {
3635         auto it = selectionMenuMap_.find(key);
3636         if (it != selectionMenuMap_.end()) {
3637             return it->second;
3638         }
3639     }
3640     TAG_LOGD(AceLogTag::ACE_TEXT, "The key not in selectionMenuMap_");
3641     return nullptr;
3642 }
3643 
CopySelectionMenuParams(SelectOverlayInfo & selectInfo,TextResponseType responseType)3644 void TextPattern::CopySelectionMenuParams(SelectOverlayInfo& selectInfo, TextResponseType responseType)
3645 {
3646     auto currentSpanType = selectedType_.value_or(TextSpanType::NONE);
3647     std::shared_ptr<SelectionMenuParams> menuParams = nullptr;
3648     menuParams = GetMenuParams(currentSpanType, responseType);
3649     if (menuParams == nullptr || !menuParams->isValid) {
3650         return;
3651     }
3652     CopyBindSelectionMenuParams(selectInfo, menuParams);
3653 }
3654 
CopyBindSelectionMenuParams(SelectOverlayInfo & selectInfo,std::shared_ptr<SelectionMenuParams> menuParams)3655 void TextPattern::CopyBindSelectionMenuParams(
3656     SelectOverlayInfo& selectInfo, std::shared_ptr<SelectionMenuParams> menuParams)
3657 {
3658     selectInfo.menuInfo.menuBuilder = menuParams->buildFunc;
3659     auto weak = AceType::WeakClaim(this);
3660     selectInfo.menuCallback.onAppear = [weak, menuParams]() {
3661         auto pattern = weak.Upgrade();
3662         CHECK_NULL_VOID(pattern);
3663         pattern->OnHandleSelectionMenuCallback(SelectionMenuCalblackId::MENU_APPEAR, menuParams);
3664     };
3665     selectInfo.menuCallback.onDisappear = menuParams->onDisappear;
3666     selectInfo.menuCallback.onMenuShow = [weak, menuParams]() {
3667         auto pattern = weak.Upgrade();
3668         CHECK_NULL_VOID(pattern);
3669         pattern->OnHandleSelectionMenuCallback(SelectionMenuCalblackId::MENU_SHOW, menuParams);
3670     };
3671     selectInfo.menuCallback.onMenuHide = [weak, menuParams]() {
3672         auto pattern = weak.Upgrade();
3673         CHECK_NULL_VOID(pattern);
3674         pattern->OnHandleSelectionMenuCallback(SelectionMenuCalblackId::MENU_HIDE, menuParams);
3675     };
3676 }
3677 
OnHandleSelectionMenuCallback(SelectionMenuCalblackId callbackId,std::shared_ptr<SelectionMenuParams> menuParams)3678 void TextPattern::OnHandleSelectionMenuCallback(
3679     SelectionMenuCalblackId callbackId, std::shared_ptr<SelectionMenuParams> menuParams)
3680 {
3681     std::function<void(int32_t, int32_t)> callback;
3682     switch (callbackId) {
3683         case SelectionMenuCalblackId::MENU_SHOW:
3684             callback = menuParams->onMenuShow;
3685             break;
3686         case SelectionMenuCalblackId::MENU_HIDE:
3687             callback = menuParams->onMenuHide;
3688             break;
3689         case SelectionMenuCalblackId::MENU_APPEAR:
3690             callback = menuParams->onAppear;
3691             break;
3692         default:
3693             callback = nullptr;
3694     }
3695     CHECK_NULL_VOID(callback);
3696     auto selectStart = std::min(textSelector_.baseOffset, textSelector_.destinationOffset);
3697     auto selectEnd = std::max(textSelector_.baseOffset, textSelector_.destinationOffset);
3698     callback(selectStart, selectEnd);
3699 }
3700 
FireOnSelectionChange(int32_t start,int32_t end)3701 void TextPattern::FireOnSelectionChange(int32_t start, int32_t end)
3702 {
3703     auto host = GetHost();
3704     CHECK_NULL_VOID(host);
3705     auto eventHub = host->GetEventHub<TextEventHub>();
3706     CHECK_NULL_VOID(eventHub);
3707     eventHub->FireOnSelectionChange(start, end);
3708 }
3709 
OnSelectionMenuOptionsUpdate(const NG::OnCreateMenuCallback && onCreateMenuCallback,const NG::OnMenuItemClickCallback && onMenuItemClick)3710 void TextPattern::OnSelectionMenuOptionsUpdate(
3711     const NG::OnCreateMenuCallback&& onCreateMenuCallback, const NG::OnMenuItemClickCallback&& onMenuItemClick)
3712 {
3713     selectOverlay_->OnSelectionMenuOptionsUpdate(std::move(onCreateMenuCallback), std::move(onMenuItemClick));
3714 }
3715 
StartVibratorByIndexChange(int32_t currentIndex,int32_t preIndex)3716 void TextPattern::StartVibratorByIndexChange(int32_t currentIndex, int32_t preIndex)
3717 {
3718     CHECK_NULL_VOID(isEnableHapticFeedback_ && (currentIndex != preIndex));
3719     VibratorUtils::StartVibraFeedback("slide");
3720 }
3721 
HandleSelectionChange(int32_t start,int32_t end)3722 void TextPattern::HandleSelectionChange(int32_t start, int32_t end)
3723 {
3724     if (textSelector_.GetStart() == start && textSelector_.GetEnd() == end) {
3725         return;
3726     }
3727     textSelector_.Update(start, end);
3728     UpdateSelectionSpanType(std::min(start, end), std::max(start, end));
3729     FireOnSelectionChange(std::min(start, end), std::max(start, end));
3730 }
3731 
IsSelectedBindSelectionMenu()3732 bool TextPattern::IsSelectedBindSelectionMenu()
3733 {
3734     auto currentSpanType = selectedType_.value_or(TextSpanType::TEXT);
3735     return GetMenuParams(currentSpanType, TextResponseType::SELECTED_BY_MOUSE) != nullptr;
3736 }
3737 
UpdateSelectionSpanType(int32_t selectStart,int32_t selectEnd)3738 void TextPattern::UpdateSelectionSpanType(int32_t selectStart, int32_t selectEnd)
3739 {
3740     UpdateSelectionType(GetSpansInfo(selectStart, selectEnd, GetSpansMethod::ONSELECT));
3741     if ((selectedType_ == TextSpanType::NONE && !textSelector_.StartEqualToDest()) ||
3742         textSelector_.StartEqualToDest()) {
3743         selectedType_ = TextSpanType::TEXT;
3744     }
3745 }
3746 
UpdateSelectionType(const SelectionInfo & selection)3747 void TextPattern::UpdateSelectionType(const SelectionInfo& selection)
3748 {
3749     selectedType_ = TextSpanType::NONE;
3750     auto list = selection.GetSelection().resultObjects;
3751     bool imageSelected = false;
3752     bool textSelected = false;
3753     bool builderSelected = false;
3754     for (const auto& obj : list) {
3755         if (obj.type == SelectSpanType::TYPEIMAGE) {
3756             imageSelected = true;
3757         } else if (obj.type == SelectSpanType::TYPESPAN) {
3758             textSelected = true;
3759         } else if (obj.type == SelectSpanType::TYPEBUILDERSPAN) {
3760             builderSelected = true;
3761         }
3762         if ((imageSelected && textSelected) || (builderSelected && textSelected) ||
3763             (imageSelected && builderSelected)) {
3764             selectedType_ = TextSpanType::MIXED;
3765             return;
3766         }
3767     }
3768     if (imageSelected) {
3769         selectedType_ = TextSpanType::IMAGE;
3770     } else if (textSelected) {
3771         selectedType_ = TextSpanType::TEXT;
3772     } else if (builderSelected) {
3773         selectedType_ = TextSpanType::BUILDER;
3774     }
3775 
3776     TAG_LOGD(AceLogTag::ACE_TEXT, "UpdateSelectionSpanType, selectedType_: %{public}d", selectedType_.value());
3777 }
3778 
GetSelectionSpanItemIndex(const MouseInfo & info)3779 int32_t TextPattern::GetSelectionSpanItemIndex(const MouseInfo& info)
3780 {
3781     RectF textContentRect = contentRect_;
3782     textContentRect.SetTop(contentRect_.GetY() - std::min(baselineOffset_, 0.0f));
3783     textContentRect.SetHeight(contentRect_.Height() - std::max(baselineOffset_, 0.0f));
3784     PointF textOffset = { info.GetLocalLocation().GetX() - textContentRect.GetX(),
3785         info.GetLocalLocation().GetY() - textContentRect.GetY() };
3786     if (!textContentRect.IsInRegion(PointF(info.GetLocalLocation().GetX(), info.GetLocalLocation().GetY())) ||
3787         spans_.empty() || pManager_->GetParagraphs().empty()) {
3788         return -1;
3789     }
3790     int32_t start = 0;
3791     bool isFind = false;
3792     int32_t index = -1;
3793     for (const auto& item : spans_) {
3794         index++;
3795         if (!item) {
3796             continue;
3797         }
3798         auto selectedRects = pManager_->GetRects(start, item->position);
3799         start = item->position;
3800         for (auto&& rect : selectedRects) {
3801             if (rect.IsInRegion(textOffset)) {
3802                 isFind = true;
3803                 break;
3804             }
3805         }
3806         if (isFind) {
3807             TAG_LOGD(AceLogTag::ACE_TEXT, "GetSelectionSpanItemIndex index: %{public}d", index);
3808             return index;
3809         }
3810     }
3811     return -1;
3812 }
3813 
GetBuilderResultObject(RefPtr<UINode> uiNode,int32_t index,int32_t start,int32_t end)3814 ResultObject TextPattern::GetBuilderResultObject(RefPtr<UINode> uiNode, int32_t index, int32_t start, int32_t end)
3815 {
3816     int32_t itemLength = 1;
3817     ResultObject resultObject;
3818     resultObject.isDraggable = true;
3819     if (!DynamicCast<FrameNode>(uiNode) || !GetSpanItemByIndex(index)) {
3820         return resultObject;
3821     }
3822     int32_t endPosition = std::min(GetTextContentLength(), GetSpanItemByIndex(index)->position);
3823     int32_t startPosition = endPosition - itemLength;
3824     if ((start <= startPosition) && (end >= endPosition)) {
3825         auto builderNode = DynamicCast<FrameNode>(uiNode);
3826         CHECK_NULL_RETURN(builderNode, resultObject);
3827         resultObject.spanPosition.spanIndex = index;
3828         resultObject.spanPosition.spanRange[RichEditorSpanRange::RANGESTART] = startPosition;
3829         resultObject.spanPosition.spanRange[RichEditorSpanRange::RANGEEND] = endPosition;
3830         resultObject.offsetInSpan[RichEditorSpanRange::RANGESTART] = 0;
3831         resultObject.offsetInSpan[RichEditorSpanRange::RANGEEND] = itemLength;
3832         resultObject.type = SelectSpanType::TYPEIMAGE;
3833         auto geometryNode = builderNode->GetGeometryNode();
3834         CHECK_NULL_RETURN(geometryNode, resultObject);
3835         resultObject.imageStyle.size[RichEditorImageSize::SIZEWIDTH] = geometryNode->GetMarginFrameSize().Width();
3836         resultObject.imageStyle.size[RichEditorImageSize::SIZEHEIGHT] = geometryNode->GetMarginFrameSize().Height();
3837         resultObject.valueString = " ";
3838     }
3839     return resultObject;
3840 }
3841 
SetStyledString(const RefPtr<SpanString> & value,bool closeSelectOverlay)3842 void TextPattern::SetStyledString(const RefPtr<SpanString>& value, bool closeSelectOverlay)
3843 {
3844     isSpanStringMode_ = true;
3845     auto host = GetHost();
3846     CHECK_NULL_VOID(host);
3847     if (closeSelectOverlay) {
3848         CloseSelectOverlay();
3849     }
3850     auto length = styledString_->GetLength();
3851     styledString_->RemoveCustomSpan();
3852     styledString_->ReplaceSpanString(0, length, value);
3853     spans_ = styledString_->GetSpanItems();
3854     ProcessSpanString();
3855     styledString_->AddCustomSpan();
3856     styledString_->SetFramNode(WeakClaim(host.GetRawPtr()));
3857     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
3858 }
3859 
GetTextStyleObject(const RefPtr<SpanNode> & node)3860 TextStyleResult TextPattern::GetTextStyleObject(const RefPtr<SpanNode>& node)
3861 {
3862     TextStyleResult textStyle;
3863     textStyle.fontColor = node->GetTextColorValue(Color::BLACK).ColorToString();
3864     textStyle.fontStyle = static_cast<int32_t>(node->GetItalicFontStyleValue(OHOS::Ace::FontStyle::NORMAL));
3865     textStyle.fontWeight = static_cast<int32_t>(node->GetFontWeightValue(FontWeight::NORMAL));
3866     std::string fontFamilyValue;
3867     const std::vector<std::string> defaultFontFamily = { "HarmonyOS Sans" };
3868     auto fontFamily = node->GetFontFamilyValue(defaultFontFamily);
3869     for (const auto& str : fontFamily) {
3870         fontFamilyValue += str;
3871         fontFamilyValue += ",";
3872     }
3873     fontFamilyValue =
3874         fontFamilyValue.substr(0, !fontFamilyValue.empty() ? static_cast<int32_t>(fontFamilyValue.size()) - 1 : 0);
3875     textStyle.fontFamily = !fontFamilyValue.empty() ? fontFamilyValue : defaultFontFamily.front();
3876     textStyle.decorationType = static_cast<int32_t>(node->GetTextDecorationValue(TextDecoration::NONE));
3877     textStyle.decorationColor = node->GetTextDecorationColorValue(Color::BLACK).ColorToString();
3878     textStyle.decorationStyle = static_cast<int32_t>(node->GetTextDecorationStyleValue(TextDecorationStyle::SOLID));
3879     textStyle.textAlign = static_cast<int32_t>(node->GetTextAlignValue(TextAlign::START));
3880     auto lm = node->GetLeadingMarginValue({});
3881     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
3882         textStyle.fontSize = node->GetFontSizeValue(Dimension(16.0f, DimensionUnit::VP)).ConvertToFp();
3883         textStyle.lineHeight = node->GetLineHeightValue(Dimension()).ConvertToFp();
3884         textStyle.letterSpacing = node->GetLetterSpacingValue(Dimension()).ConvertToFp();
3885         textStyle.lineSpacing = node->GetLineSpacingValue(Dimension()).ConvertToFp();
3886     } else {
3887         textStyle.fontSize = node->GetFontSizeValue(Dimension(16.0f, DimensionUnit::VP)).ConvertToVp();
3888         textStyle.lineHeight = node->GetLineHeightValue(Dimension()).ConvertToVp();
3889         textStyle.letterSpacing = node->GetLetterSpacingValue(Dimension()).ConvertToVp();
3890         textStyle.lineSpacing = node->GetLineSpacingValue(Dimension()).ConvertToVp();
3891     }
3892     textStyle.fontFeature = node->GetFontFeatureValue(ParseFontFeatureSettings("\"pnum\" 1"));
3893     textStyle.leadingMarginSize[RichEditorLeadingRange::LEADING_START] = lm.size.Width().ToString();
3894     textStyle.leadingMarginSize[RichEditorLeadingRange::LEADING_END] = lm.size.Height().ToString();
3895     textStyle.wordBreak = static_cast<int32_t>(node->GetWordBreakValue(WordBreak::BREAK_WORD));
3896     textStyle.lineBreakStrategy = static_cast<int32_t>(node->GetLineBreakStrategyValue(LineBreakStrategy::GREEDY));
3897     textStyle.textShadows = node->GetTextShadowValue({});
3898     return textStyle;
3899 }
3900 
GetChildByIndex(int32_t index) const3901 RefPtr<UINode> TextPattern::GetChildByIndex(int32_t index) const
3902 {
3903     const auto& children = childNodes_;
3904     int32_t size = static_cast<int32_t>(children.size());
3905     if (index < 0 || index >= size) {
3906         return nullptr;
3907     }
3908     auto pos = children.begin();
3909     std::advance(pos, index);
3910     return *pos;
3911 }
3912 
GetTextResultObject(RefPtr<UINode> uinode,int32_t index,int32_t start,int32_t end)3913 ResultObject TextPattern::GetTextResultObject(RefPtr<UINode> uinode, int32_t index, int32_t start, int32_t end)
3914 {
3915     bool selectFlag = false;
3916     ResultObject resultObject;
3917     if (!DynamicCast<SpanNode>(uinode)) {
3918         return resultObject;
3919     }
3920     auto spanItem = DynamicCast<SpanNode>(uinode)->GetSpanItem();
3921     int32_t itemLength = static_cast<int32_t>(StringUtils::ToWstring(spanItem->content).length());
3922     int32_t endPosition = std::min(GetTextContentLength(), spanItem->position);
3923     int32_t startPosition = endPosition - itemLength;
3924 
3925     if (startPosition >= start && endPosition <= end) {
3926         selectFlag = true;
3927         resultObject.offsetInSpan[RichEditorSpanRange::RANGESTART] = 0;
3928         resultObject.offsetInSpan[RichEditorSpanRange::RANGEEND] = itemLength;
3929     } else if (startPosition < start && endPosition <= end && endPosition > start) {
3930         selectFlag = true;
3931         resultObject.offsetInSpan[RichEditorSpanRange::RANGESTART] = start - startPosition;
3932         resultObject.offsetInSpan[RichEditorSpanRange::RANGEEND] = itemLength;
3933     } else if (startPosition >= start && startPosition < end && endPosition >= end) {
3934         selectFlag = true;
3935         resultObject.offsetInSpan[RichEditorSpanRange::RANGESTART] = 0;
3936         resultObject.offsetInSpan[RichEditorSpanRange::RANGEEND] = end - startPosition;
3937     } else if (startPosition <= start && endPosition >= end) {
3938         selectFlag = true;
3939         resultObject.offsetInSpan[RichEditorSpanRange::RANGESTART] = start - startPosition;
3940         resultObject.offsetInSpan[RichEditorSpanRange::RANGEEND] = end - startPosition;
3941     }
3942     if (selectFlag) {
3943         resultObject.spanPosition.spanIndex = index;
3944         resultObject.spanPosition.spanRange[RichEditorSpanRange::RANGESTART] = startPosition;
3945         resultObject.spanPosition.spanRange[RichEditorSpanRange::RANGEEND] = endPosition;
3946         resultObject.type = SelectSpanType::TYPESPAN;
3947         SetResultObjectText(resultObject, spanItem);
3948         auto spanNode = DynamicCast<SpanNode>(uinode);
3949         resultObject.textStyle = GetTextStyleObject(spanNode);
3950     }
3951     return resultObject;
3952 }
3953 
SetResultObjectText(ResultObject & resultObject,const RefPtr<SpanItem> & spanItem)3954 void TextPattern::SetResultObjectText(ResultObject& resultObject, const RefPtr<SpanItem>& spanItem)
3955 {
3956     CHECK_NULL_VOID(spanItem);
3957     resultObject.valueString = spanItem->content;
3958 }
3959 
GetImageResultObject(RefPtr<UINode> uinode,int32_t index,int32_t start,int32_t end)3960 ResultObject TextPattern::GetImageResultObject(RefPtr<UINode> uinode, int32_t index, int32_t start, int32_t end)
3961 {
3962     int32_t itemLength = 1;
3963     ResultObject resultObject;
3964     if (!DynamicCast<FrameNode>(uinode) || !GetSpanItemByIndex(index)) {
3965         return resultObject;
3966     }
3967     int32_t endPosition = std::min(GetTextContentLength(), GetSpanItemByIndex(index)->position);
3968     int32_t startPosition = endPosition - itemLength;
3969     if ((start <= startPosition) && (end >= endPosition)) {
3970         auto imageNode = DynamicCast<FrameNode>(uinode);
3971         auto imageLayoutProperty = DynamicCast<ImageLayoutProperty>(imageNode->GetLayoutProperty());
3972         resultObject.spanPosition.spanIndex = index;
3973         resultObject.spanPosition.spanRange[RichEditorSpanRange::RANGESTART] = startPosition;
3974         resultObject.spanPosition.spanRange[RichEditorSpanRange::RANGEEND] = endPosition;
3975         resultObject.offsetInSpan[RichEditorSpanRange::RANGESTART] = 0;
3976         resultObject.offsetInSpan[RichEditorSpanRange::RANGEEND] = itemLength;
3977         resultObject.type = SelectSpanType::TYPEIMAGE;
3978         if (!imageLayoutProperty->GetImageSourceInfo()->GetPixmap()) {
3979             resultObject.valueString = imageLayoutProperty->GetImageSourceInfo()->GetSrc();
3980         } else {
3981             resultObject.valuePixelMap = imageLayoutProperty->GetImageSourceInfo()->GetPixmap();
3982         }
3983         auto geometryNode = imageNode->GetGeometryNode();
3984         resultObject.imageStyle.size[RichEditorImageSize::SIZEWIDTH] = geometryNode->GetMarginFrameSize().Width();
3985         resultObject.imageStyle.size[RichEditorImageSize::SIZEHEIGHT] = geometryNode->GetMarginFrameSize().Height();
3986         if (imageLayoutProperty->HasImageFit()) {
3987             resultObject.imageStyle.objectFit = static_cast<int32_t>(imageLayoutProperty->GetImageFitValue());
3988         }
3989         if (imageLayoutProperty->HasVerticalAlign()) {
3990             resultObject.imageStyle.verticalAlign = static_cast<int32_t>(imageLayoutProperty->GetVerticalAlignValue());
3991         }
3992         if (imageLayoutProperty->GetMarginProperty()) {
3993             resultObject.imageStyle.margin = imageLayoutProperty->GetMarginProperty()->ToString();
3994         }
3995         auto imageRenderCtx = imageNode->GetRenderContext();
3996         if (imageRenderCtx->GetBorderRadius()) {
3997             BorderRadiusProperty brp;
3998             auto jsonObject = JsonUtil::Create(true);
3999             auto jsonBorder = JsonUtil::Create(true);
4000             InspectorFilter emptyFilter;
4001             imageRenderCtx->GetBorderRadiusValue(brp).ToJsonValue(jsonObject, jsonBorder, emptyFilter);
4002             resultObject.imageStyle.borderRadius = jsonObject->GetValue("borderRadius")->IsObject()
4003                                                        ? jsonObject->GetValue("borderRadius")->ToString()
4004                                                        : jsonObject->GetString("borderRadius");
4005         }
4006     }
4007     return resultObject;
4008 }
4009 
OnSensitiveStyleChange(bool isSensitive)4010 void TextPattern::OnSensitiveStyleChange(bool isSensitive)
4011 {
4012     auto host = GetHost();
4013     CHECK_NULL_VOID(host);
4014     isSensitive_ = isSensitive;
4015     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
4016 }
4017 
IsSensitiveEnalbe()4018 bool TextPattern::IsSensitiveEnalbe()
4019 {
4020     auto host = GetHost();
4021     CHECK_NULL_RETURN(host, false);
4022     return isSensitive_ && host->IsPrivacySensitive();
4023 }
4024 
ConvertGlobalToLocalOffset(const Offset & globalOffset)4025 Offset TextPattern::ConvertGlobalToLocalOffset(const Offset& globalOffset)
4026 {
4027     auto localPoint = OffsetF(globalOffset.GetX(), globalOffset.GetY());
4028     selectOverlay_->RevertLocalPointWithTransform(localPoint);
4029     return Offset(localPoint.GetX(), localPoint.GetY());
4030 }
4031 
MountImageNode(const RefPtr<ImageSpanItem> & imageItem)4032 void TextPattern::MountImageNode(const RefPtr<ImageSpanItem>& imageItem)
4033 {
4034     auto host = GetHost();
4035     CHECK_NULL_VOID(host);
4036     auto imageNode = ImageSpanNode::GetOrCreateSpanNode(V2::IMAGE_ETS_TAG,
4037         ElementRegister::GetInstance()->MakeUniqueId(), []() { return AceType::MakeRefPtr<ImagePattern>(); });
4038     auto imageLayoutProperty = imageNode->GetLayoutProperty<ImageLayoutProperty>();
4039     auto options = imageItem->options;
4040     imageLayoutProperty->UpdateImageSourceInfo(CreateImageSourceInfo(options));
4041     imageNode->MountToParent(host, host->GetChildren().size());
4042     SetImageNodeGesture(imageNode);
4043     if (options.imageAttribute.has_value()) {
4044         auto imgAttr = options.imageAttribute.value();
4045         auto imagePattern = imageNode->GetPattern<ImagePattern>();
4046         CHECK_NULL_VOID(imagePattern);
4047         imagePattern->SetSyncLoad(imgAttr.syncLoad);
4048         if (imgAttr.size.has_value()) {
4049             imageLayoutProperty->UpdateUserDefinedIdealSize(imgAttr.size->GetSize());
4050         }
4051         if (imgAttr.verticalAlign.has_value()) {
4052             imageLayoutProperty->UpdateVerticalAlign(imgAttr.verticalAlign.value());
4053         }
4054         if (imgAttr.objectFit.has_value()) {
4055             imageLayoutProperty->UpdateImageFit(imgAttr.objectFit.value());
4056         }
4057         if (imgAttr.marginProp.has_value()) {
4058             imageLayoutProperty->UpdateMargin(imgAttr.marginProp.value());
4059         }
4060         if (imgAttr.paddingProp.has_value()) {
4061             imageLayoutProperty->UpdatePadding(imgAttr.paddingProp.value());
4062         }
4063         if (imgAttr.borderRadius.has_value()) {
4064             auto imageRenderCtx = imageNode->GetRenderContext();
4065             imageRenderCtx->UpdateBorderRadius(imgAttr.borderRadius.value());
4066             imageRenderCtx->SetClipToBounds(true);
4067         }
4068         auto paintProperty = imageNode->GetPaintProperty<ImageRenderProperty>();
4069         if (imgAttr.colorFilterMatrix.has_value() && paintProperty) {
4070             paintProperty->UpdateColorFilter(imgAttr.colorFilterMatrix.value());
4071             paintProperty->ResetDrawingColorFilter();
4072         } else if (imgAttr.drawingColorFilter.has_value() && paintProperty) {
4073             paintProperty->UpdateDrawingColorFilter(imgAttr.drawingColorFilter.value());
4074             paintProperty->ResetColorFilter();
4075         }
4076     }
4077     imageNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
4078     imageNode->MarkModifyDone();
4079     imageItem->imageNodeId = imageNode->GetId();
4080     imageNode->SetImageItem(imageItem);
4081     childNodes_.emplace_back(imageNode);
4082 }
4083 
SetImageNodeGesture(RefPtr<ImageSpanNode> imageNode)4084 void TextPattern::SetImageNodeGesture(RefPtr<ImageSpanNode> imageNode)
4085 {
4086     auto gesture = imageNode->GetOrCreateGestureEventHub();
4087     CHECK_NULL_VOID(gesture);
4088     gesture->SetHitTestMode(HitTestMode::HTMNONE);
4089 }
4090 
CreateImageSourceInfo(const ImageSpanOptions & options)4091 ImageSourceInfo TextPattern::CreateImageSourceInfo(const ImageSpanOptions& options)
4092 {
4093     std::string src;
4094     RefPtr<PixelMap> pixMap = nullptr;
4095     std::string bundleName;
4096     std::string moduleName;
4097     if (options.image.has_value()) {
4098         src = options.image.value();
4099     }
4100     if (options.imagePixelMap.has_value()) {
4101         pixMap = options.imagePixelMap.value();
4102     }
4103     if (options.bundleName.has_value()) {
4104         bundleName = options.bundleName.value();
4105     }
4106     if (options.moduleName.has_value()) {
4107         moduleName = options.moduleName.value();
4108     }
4109     ImageSourceInfo info;
4110 #if defined(PIXEL_MAP_SUPPORTED)
4111     if (!options.imagePixelMap.has_value()) {
4112         info = ImageSourceInfo{ src, bundleName, moduleName };
4113     } else {
4114         info = ImageSourceInfo(pixMap);
4115     }
4116 #else
4117     info = ImageSourceInfo{ src, bundleName, moduleName };
4118 #endif
4119     info.SetIsUriPureNumber(options.isUriPureNumber.value_or(false));
4120     return info;
4121 }
4122 
ProcessSpanString()4123 void TextPattern::ProcessSpanString()
4124 {
4125     auto host = GetHost();
4126     CHECK_NULL_VOID(host);
4127     textForDisplay_.clear();
4128     childNodes_.clear();
4129     dataDetectorAdapter_->textForAI_.clear();
4130     host->Clean();
4131     hasSpanStringLongPressEvent_ = false;
4132     hasUrlSpan_ = false;
4133 
4134     // 适配AI&&挂载image节点
4135     auto imageChildren = host->GetChildren();
4136     for (const auto& span : spans_) {
4137         auto imageSpan = DynamicCast<ImageSpanItem>(span);
4138         if (imageSpan) {
4139             dataDetectorAdapter_->textForAI_ += '\n';
4140             MountImageNode(imageSpan);
4141         } else {
4142             dataDetectorAdapter_->textForAI_ += span->content;
4143         }
4144         if (span->onClick || span->urlOnRelease) {
4145             auto gestureEventHub = host->GetOrCreateGestureEventHub();
4146             InitClickEvent(gestureEventHub);
4147         }
4148         if (span->onLongPress) {
4149             auto gestureEventHub = host->GetOrCreateGestureEventHub();
4150             InitLongPressEvent(gestureEventHub);
4151             hasSpanStringLongPressEvent_ = true;
4152         }
4153         if (span->urlOnRelease) {
4154             hasUrlSpan_ = true;
4155             InitUrlMouseEvent();
4156             InitUrlTouchEvent();
4157         }
4158         textForDisplay_ += span->content;
4159     }
4160     if (dataDetectorAdapter_->textForAI_ != textForDisplay_) {
4161         dataDetectorAdapter_->aiDetectInitialized_ = false;
4162     }
4163     if (CanStartAITask() && !dataDetectorAdapter_->aiDetectInitialized_) {
4164         dataDetectorAdapter_->StartAITask();
4165     }
4166 }
4167 
SetExternalSpanItem(const std::list<RefPtr<SpanItem>> & spans)4168 void TextPattern::SetExternalSpanItem(const std::list<RefPtr<SpanItem>>& spans)
4169 {
4170     isSpanStringMode_ = !spans.empty();
4171     spans_ = spans;
4172     ProcessSpanString();
4173     auto layoutProperty = GetLayoutProperty<TextLayoutProperty>();
4174     CHECK_NULL_VOID(layoutProperty);
4175     layoutProperty->UpdateContent(textForDisplay_);
4176 }
4177 
GetTextContentRect(bool isActualText) const4178 RectF TextPattern::GetTextContentRect(bool isActualText) const
4179 {
4180     auto textRect = contentRect_;
4181     auto host = GetHost();
4182     CHECK_NULL_RETURN(host, textRect);
4183     auto renderContext = host->GetRenderContext();
4184     CHECK_NULL_RETURN(renderContext, textRect);
4185     CHECK_NULL_RETURN(pManager_, textRect);
4186     if (!renderContext->GetClipEdge().value_or(false) &&
4187         LessNotEqual(textRect.Width(), pManager_->GetLongestLine())) {
4188         textRect.SetWidth(pManager_->GetLongestLine());
4189     }
4190     if (isActualText && !renderContext->GetClipEdge().value_or(false) &&
4191         LessNotEqual(textRect.Height(), pManager_->GetHeight())) {
4192         textRect.SetHeight(pManager_->GetHeight());
4193     }
4194     return textRect;
4195 }
4196 
GetLineCount() const4197 size_t TextPattern::GetLineCount() const
4198 {
4199     CHECK_NULL_RETURN(pManager_, 0);
4200     return pManager_->GetLineCount();
4201 }
4202 
DidExceedMaxLines() const4203 bool TextPattern::DidExceedMaxLines() const
4204 {
4205     CHECK_NULL_RETURN(pManager_, false);
4206     return pManager_->DidExceedMaxLines();
4207 }
4208 
IsSetObscured()4209 bool TextPattern::IsSetObscured()
4210 {
4211     auto host = GetHost();
4212     CHECK_NULL_RETURN(host, false);
4213     auto renderContext = host->GetRenderContext();
4214     CHECK_NULL_RETURN(renderContext, false);
4215     auto obscuredReasons = renderContext->GetObscured().value_or(std::vector<ObscuredReasons>());
4216     bool ifHaveObscured = std::any_of(obscuredReasons.begin(), obscuredReasons.end(),
4217         [](const auto& reason) { return reason == ObscuredReasons::PLACEHOLDER; });
4218     return ifHaveObscured;
4219 }
4220 
GetLineMetrics(int32_t lineNumber)4221 TextLineMetrics TextPattern::GetLineMetrics(int32_t lineNumber)
4222 {
4223     CHECK_NULL_RETURN(pManager_, TextLineMetrics());
4224     if (lineNumber < 0 || GetLineCount() == 0 || lineNumber > static_cast<int32_t>(GetLineCount()) - 1) {
4225         TAG_LOGI(AceLogTag::ACE_TEXT, "GetLineMetrics failed, lineNumber not between 0 and max lines:%{public}d",
4226             lineNumber);
4227         return TextLineMetrics();
4228     }
4229     auto lineMetrics = pManager_->GetLineMetrics(lineNumber);
4230     RectF textContentRect = contentRect_;
4231     textContentRect.SetTop(contentRect_.GetY() - std::min(baselineOffset_, 0.0f));
4232     lineMetrics.x += textContentRect.GetX();
4233     lineMetrics.y += textContentRect.GetY();
4234     lineMetrics.baseline += textContentRect.GetY();
4235     return lineMetrics;
4236 }
4237 
GetRectsForRange(int32_t start,int32_t end,RectHeightStyle heightStyle,RectWidthStyle widthStyle)4238 std::vector<ParagraphManager::TextBox> TextPattern::GetRectsForRange(
4239     int32_t start, int32_t end, RectHeightStyle heightStyle, RectWidthStyle widthStyle)
4240 {
4241     if (start < 0 || end < 0 || start > end) {
4242         return {};
4243     }
4244     std::vector<ParagraphManager::TextBox> textBoxes = pManager_->GetRectsForRange(start, end, heightStyle, widthStyle);
4245     RectF textContentRect = contentRect_;
4246     textContentRect.SetTop(contentRect_.GetY() - std::min(baselineOffset_, 0.0f));
4247     std::vector<ParagraphManager::TextBox> adjustedTextBoxes;
4248     for (auto& textBox : textBoxes) {
4249         ParagraphManager::TextBox adjustedTextBox = textBox;
4250         adjustedTextBox.rect_.SetLeft(textBox.rect_.Left() + textContentRect.Left());
4251         adjustedTextBox.rect_.SetTop(textBox.rect_.Top() + textContentRect.Top());
4252         adjustedTextBoxes.push_back(adjustedTextBox);
4253     }
4254     return adjustedTextBoxes;
4255 }
4256 
ConvertLocalOffsetToParagraphOffset(const Offset & offset)4257 Offset TextPattern::ConvertLocalOffsetToParagraphOffset(const Offset& offset)
4258 {
4259     RectF textContentRect = contentRect_;
4260     textContentRect.SetTop(contentRect_.GetY() - std::min(baselineOffset_, 0.0f));
4261     Offset paragraphOffset = { offset.GetX() - textContentRect.GetX(), offset.GetY() - textContentRect.GetY() };
4262     return paragraphOffset;
4263 }
4264 
GetGlyphPositionAtCoordinate(int32_t x,int32_t y)4265 PositionWithAffinity TextPattern::GetGlyphPositionAtCoordinate(int32_t x, int32_t y)
4266 {
4267     Offset offset(x, y);
4268     return pManager_->GetGlyphPositionAtCoordinate(ConvertLocalOffsetToParagraphOffset(offset));
4269 }
4270 
ProcessMarqueeVisibleAreaCallback()4271 void TextPattern::ProcessMarqueeVisibleAreaCallback()
4272 {
4273     if (!IsMarqueeOverflow()) {
4274         return;
4275     }
4276     auto host = GetHost();
4277     CHECK_NULL_VOID(host);
4278     auto pipeline = GetContext();
4279     CHECK_NULL_VOID(pipeline);
4280     auto callback = [weak = WeakClaim(this)](bool visible, double ratio) {
4281         auto pattern = weak.Upgrade();
4282         CHECK_NULL_VOID(pattern);
4283         CHECK_NULL_VOID(pattern->contentMod_);
4284         if (!pattern->IsMarqueeOverflow()) {
4285             return;
4286         }
4287         if (visible && Positive(ratio)) {
4288             pattern->contentMod_->ResumeAnimation();
4289         }
4290         if (!visible && NonPositive(ratio)) {
4291             pattern->contentMod_->PauseAnimation();
4292         }
4293     };
4294     std::vector<double> ratioList = { 0.0 };
4295     pipeline->AddVisibleAreaChangeNode(host, ratioList, callback, false, true);
4296 }
4297 
OnTextOverflowChanged()4298 void TextPattern::OnTextOverflowChanged()
4299 {
4300     auto host = GetHost();
4301     CHECK_NULL_VOID(host);
4302     auto pipeline = GetContext();
4303     CHECK_NULL_VOID(pipeline);
4304     auto eventHub = host->GetEventHub<TextEventHub>();
4305     CHECK_NULL_VOID(eventHub);
4306     auto hasInnerCallabck = eventHub->HasVisibleAreaCallback(false);
4307     if (!hasInnerCallabck) {
4308         return;
4309     }
4310     auto hasUserCallback = eventHub->HasVisibleAreaCallback(true);
4311     if (!hasUserCallback) {
4312         pipeline->RemoveVisibleAreaChangeNode(host->GetId());
4313     }
4314     eventHub->CleanVisibleAreaCallback(false);
4315 }
4316 
OnFrameNodeChanged(FrameNodeChangeInfoFlag flag)4317 void TextPattern::OnFrameNodeChanged(FrameNodeChangeInfoFlag flag)
4318 {
4319     selectOverlay_->OnAncestorNodeChanged(flag);
4320 }
4321 
IsMarqueeOverflow() const4322 bool TextPattern::IsMarqueeOverflow() const
4323 {
4324     auto textLayoutProperty = GetLayoutProperty<TextLayoutProperty>();
4325     CHECK_NULL_RETURN(textLayoutProperty, false);
4326     return textLayoutProperty->GetTextOverflowValue(TextOverflow::CLIP) == TextOverflow::MARQUEE;
4327 }
4328 
UpdateFontColor(const Color & value)4329 void TextPattern::UpdateFontColor(const Color& value)
4330 {
4331     auto host = GetHost();
4332     CHECK_NULL_VOID(host);
4333     const auto& children = host->GetChildren();
4334     if (children.empty()) {
4335         auto paragraphs = pManager_->GetParagraphs();
4336         for (auto &&info : paragraphs) {
4337             auto paragraph = info.paragraph;
4338             CHECK_NULL_VOID(paragraph);
4339             auto length = paragraph->GetParagraphText().length();
4340             paragraph->UpdateColor(0, length, value);
4341         }
4342     } else {
4343         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
4344     }
4345 }
4346 
MarkDirtyNodeRender()4347 void TextPattern::MarkDirtyNodeRender()
4348 {
4349     auto host = GetHost();
4350     CHECK_NULL_VOID(host);
4351     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
4352 }
4353 
BeforeCreatePaintWrapper()4354 void TextPattern::BeforeCreatePaintWrapper()
4355 {
4356     // mark content dirty
4357     if (contentMod_) {
4358         contentMod_->ContentChange();
4359     }
4360 }
4361 
StartGestureSelection(int32_t start,int32_t end,const Offset & startOffset)4362 void TextPattern::StartGestureSelection(int32_t start, int32_t end, const Offset& startOffset)
4363 {
4364     scrollableParent_ = selectOverlay_->FindScrollableParent();
4365     TextGestureSelector::StartGestureSelection(start, end, startOffset);
4366 }
4367 
GetTouchIndex(const OffsetF & offset)4368 int32_t TextPattern::GetTouchIndex(const OffsetF& offset)
4369 {
4370     OffsetF deltaOffset;
4371     if (scrollableParent_.Upgrade()) {
4372         auto parentGlobalOffset = GetParentGlobalOffset();
4373         deltaOffset = parentGlobalOffset - parentGlobalOffset_;
4374     }
4375     auto paragraphOffset =
4376         offset - deltaOffset - GetTextContentRect().GetOffset() + OffsetF(0.0f, std::min(GetBaselineOffset(), 0.0f));
4377     return GetHandleIndex({ paragraphOffset.GetX(), paragraphOffset.GetY() });
4378 }
4379 
OnTextGestureSelectionUpdate(int32_t start,int32_t end,const TouchEventInfo & info)4380 void TextPattern::OnTextGestureSelectionUpdate(int32_t start, int32_t end, const TouchEventInfo& info)
4381 {
4382     selectOverlay_->TriggerScrollableParentToScroll(
4383         scrollableParent_.Upgrade(), info.GetTouches().front().GetGlobalLocation(), false);
4384     auto localOffset = info.GetTouches().front().GetLocalLocation();
4385     if (magnifierController_) {
4386         magnifierController_->SetLocalOffset({ localOffset.GetX(), localOffset.GetY() });
4387     }
4388     if (start != textSelector_.GetStart()) {
4389         StartVibratorByIndexChange(start, textSelector_.GetStart());
4390     } else if (end != textSelector_.GetEnd()) {
4391         StartVibratorByIndexChange(end, textSelector_.GetEnd());
4392     }
4393     auto host = GetHost();
4394     CHECK_NULL_VOID(host);
4395     HandleSelectionChange(start, end);
4396     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
4397 }
4398 
OnTextGenstureSelectionEnd()4399 void TextPattern::OnTextGenstureSelectionEnd()
4400 {
4401     selectOverlay_->TriggerScrollableParentToScroll(scrollableParent_.Upgrade(), Offset(), true);
4402     if (magnifierController_) {
4403         magnifierController_->RemoveMagnifierFrameNode();
4404     }
4405     CalculateHandleOffsetAndShowOverlay();
4406     ShowSelectOverlay({ .animation = true });
4407 }
4408 
ChangeHandleHeight(const GestureEvent & event,bool isFirst,bool isOverlayMode)4409 void TextPattern::ChangeHandleHeight(const GestureEvent& event, bool isFirst, bool isOverlayMode)
4410 {
4411     auto touchOffset = event.GetGlobalLocation();
4412     auto& currentHandle = isFirst ? textSelector_.firstHandle : textSelector_.secondHandle;
4413     bool isChangeFirstHandle = isFirst ? (!textSelector_.StartGreaterDest()) : textSelector_.StartGreaterDest();
4414     if (isChangeFirstHandle) {
4415         ChangeFirstHandleHeight(touchOffset, currentHandle);
4416     } else {
4417         ChangeSecondHandleHeight(touchOffset, currentHandle);
4418     }
4419 }
4420 
ChangeFirstHandleHeight(const Offset & touchOffset,RectF & handleRect)4421 void TextPattern::ChangeFirstHandleHeight(const Offset& touchOffset, RectF& handleRect)
4422 {
4423     auto height = handleRect.Height();
4424     CalculateDefaultHandleHeight(height);
4425     bool isTouchHandleCircle = LessNotEqual(touchOffset.GetY(), handleRect.Top());
4426     if (!isTouchHandleCircle) {
4427         handleRect.SetTop(static_cast<float>(touchOffset.GetY()) - height / 2.0f);
4428     }
4429     handleRect.SetHeight(height);
4430 }
4431 
ChangeSecondHandleHeight(const Offset & touchOffset,RectF & handleRect)4432 void TextPattern::ChangeSecondHandleHeight(const Offset& touchOffset, RectF& handleRect)
4433 {
4434     auto height = handleRect.Height();
4435     CalculateDefaultHandleHeight(height);
4436     bool isTouchHandleCircle = GreatNotEqual(touchOffset.GetY(), handleRect.Bottom());
4437     auto handleOffsetY = isTouchHandleCircle
4438                             ? handleRect.Bottom() - height
4439                             : static_cast<float>(touchOffset.GetY()) - height / 2.0f;
4440     handleRect.SetTop(handleOffsetY);
4441     handleRect.SetHeight(height);
4442 }
4443 
CalculateDefaultHandleHeight(float & height)4444 void TextPattern::CalculateDefaultHandleHeight(float& height)
4445 {
4446     CHECK_NULL_VOID(textStyle_.has_value());
4447 #ifdef ENABLE_ROSEN_BACKEND
4448     MeasureContext content;
4449     content.textContent = "a";
4450     content.fontSize = textStyle_.value().GetFontSize();
4451     auto fontweight = StringUtils::FontWeightToString(textStyle_.value().GetFontWeight());
4452     content.fontWeight = fontweight;
4453     height = std::max(static_cast<float>(RosenRenderCustomPaint::MeasureTextSizeInner(content).Height()), 0.0f);
4454 #endif
4455 }
4456 
BeforeSyncGeometryProperties(const DirtySwapConfig & config)4457 void TextPattern::BeforeSyncGeometryProperties(const DirtySwapConfig& config)
4458 {
4459     if (afterLayoutCallback_.has_value()) {
4460         (*afterLayoutCallback_)();
4461     }
4462 }
4463 
DoTextSelectionTouchCancel()4464 void TextPattern::DoTextSelectionTouchCancel()
4465 {
4466     CHECK_NULL_VOID(magnifierController_);
4467     magnifierController_->RemoveMagnifierFrameNode();
4468     ResetSelection();
4469 }
4470 
GetCaretColor() const4471 std::string TextPattern::GetCaretColor() const
4472 {
4473     auto context = PipelineContext::GetCurrentContextSafely();
4474     CHECK_NULL_RETURN(context, "");
4475     auto theme = context->GetTheme<TextTheme>();
4476     CHECK_NULL_RETURN(theme, "");
4477     auto textLayoutProperty = GetLayoutProperty<TextLayoutProperty>();
4478     CHECK_NULL_RETURN(textLayoutProperty, "");
4479     return textLayoutProperty->GetCursorColorValue(theme->GetCaretColor()).ColorToString();
4480 }
4481 
GetSelectedBackgroundColor() const4482 std::string TextPattern::GetSelectedBackgroundColor() const
4483 {
4484     auto context = PipelineContext::GetCurrentContextSafely();
4485     CHECK_NULL_RETURN(context, "");
4486     auto theme = context->GetTheme<TextTheme>();
4487     CHECK_NULL_RETURN(theme, "");
4488     auto textLayoutProperty = GetLayoutProperty<TextLayoutProperty>();
4489     CHECK_NULL_RETURN(textLayoutProperty, "");
4490     return textLayoutProperty->GetSelectedBackgroundColorValue(theme->GetSelectedColor()).ColorToString();
4491 }
4492 } // namespace OHOS::Ace::NG
4493