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