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