• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 #include "core/components_ng/pattern/rich_editor/rich_editor_pattern.h"
16 
17 #include <chrono>
18 #include <cstddef>
19 #include <cstdint>
20 #include <functional>
21 #include <iterator>
22 #include <sstream>
23 #include <string>
24 #include <utility>
25 
26 #if !defined(PREVIEW) && defined(OHOS_PLATFORM)
27 #include "interfaces/inner_api/ui_session/ui_session_manager.h"
28 #endif
29 #include "adapter/ohos/capability/clipboard/clipboard_impl.h"
30 #include "base/geometry/dimension.h"
31 #include "base/geometry/ng/offset_t.h"
32 #include "base/geometry/ng/rect_t.h"
33 #include "base/geometry/offset.h"
34 #include "base/i18n/localization.h"
35 #include "base/log/ace_trace.h"
36 #include "base/log/dump_log.h"
37 #include "base/log/log_wrapper.h"
38 #include "base/memory/ace_type.h"
39 #include "base/utils/string_utils.h"
40 #include "base/utils/utils.h"
41 #include "core/common/ai/data_detector_mgr.h"
42 #include "core/common/clipboard/paste_data.h"
43 #include "core/common/container.h"
44 #include "core/common/container_scope.h"
45 #include "core/common/ime/text_input_client.h"
46 #include "core/common/stylus/stylus_detector_mgr.h"
47 #include "core/common/vibrator/vibrator_utils.h"
48 #include "core/components/common/layout/constants.h"
49 #include "core/components/common/properties/text_style_parser.h"
50 #include "core/components_ng/base/inspector_filter.h"
51 #include "core/components_ng/base/observer_handler.h"
52 #include "core/components_ng/base/view_stack_processor.h"
53 #include "core/components_ng/event/event_hub.h"
54 #include "core/components_ng/event/gesture_event_hub.h"
55 #include "core/components_ng/event/long_press_event.h"
56 #include "core/components_ng/pattern/image/image_pattern.h"
57 #include "core/components_ng/pattern/overlay/keyboard_base_pattern.h"
58 #include "core/components_ng/pattern/rich_editor/one_step_drag_controller.h"
59 #include "core/components_ng/pattern/rich_editor/rich_editor_event_hub.h"
60 #include "core/components_ng/pattern/rich_editor/rich_editor_layout_property.h"
61 #include "core/components_ng/pattern/rich_editor/rich_editor_model.h"
62 #include "core/components_ng/pattern/rich_editor/rich_editor_overlay_modifier.h"
63 #include "core/components_ng/pattern/rich_editor/rich_editor_theme.h"
64 #include "core/components_ng/pattern/rich_editor/selection_info.h"
65 #include "core/components_ng/pattern/rich_editor_drag/rich_editor_drag_info.h"
66 #include "core/components_ng/pattern/rich_editor_drag/rich_editor_drag_pattern.h"
67 #include "core/components_ng/pattern/text/span_node.h"
68 #include "core/components_ng/pattern/text/text_base.h"
69 #include "core/components_ng/pattern/text/typed_text.h"
70 #include "core/components_ng/pattern/text_field/text_field_manager.h"
71 #include "core/components_ng/pattern/text_field/text_field_model.h"
72 #include "core/components_ng/pattern/text_field/text_input_ai_checker.h"
73 #include "core/components_ng/property/property.h"
74 #include "core/components_v2/inspector/inspector_constants.h"
75 #include "core/gestures/gesture_info.h"
76 #include "core/pipeline/base/element_register.h"
77 
78 #ifndef ACE_UNITTEST
79 #ifdef ENABLE_STANDARD_INPUT
80 #include "commonlibrary/c_utils/base/include/refbase.h"
81 
82 #include "core/components_ng/pattern/text_field/on_text_changed_listener_impl.h"
83 #endif
84 #endif
85 
86 #include "core/common/ace_engine_ext.h"
87 #include "core/common/udmf/udmf_client.h"
88 
89 #ifdef WINDOW_SCENE_SUPPORTED
90 #include "core/components_ng/pattern/window_scene/helper/window_scene_helper.h"
91 #endif
92 
93 #ifdef ENABLE_ROSEN_BACKEND
94 #include "core/components/custom_paint/rosen_render_custom_paint.h"
95 #endif
96 
97 namespace OHOS::Ace::NG {
98 namespace {
99 #if defined(ENABLE_STANDARD_INPUT)
100 // should be moved to theme
101 constexpr float CARET_WIDTH = 1.5f;
102 constexpr float DEFAULT_CARET_HEIGHT = 18.5f;
103 constexpr Dimension KEYBOARD_AVOID_OFFSET = 24.0_vp;
104 #endif
105 constexpr int32_t IMAGE_SPAN_LENGTH = 1;
106 constexpr int32_t SYMBOL_SPAN_LENGTH = 2;
107 constexpr int32_t RICH_EDITOR_TWINKLING_INTERVAL_MS = 500;
108 constexpr int32_t AUTO_SCROLL_INTERVAL = 15;
109 constexpr Dimension CARET_BOTTOM_DISTANCE = 16.0_vp;
110 constexpr Dimension AUTO_SCROLL_EDGE_DISTANCE = 15.0_vp;
111 constexpr Dimension AUTO_SCROLL_DRAG_EDGE_DISTANCE = 58.0_vp;
112 constexpr float MAX_DRAG_SCROLL_SPEED = 2400.0f;
113 constexpr float TIME_UNIT = 1000.0f;
114 constexpr uint32_t RECORD_MAX_LENGTH = 20;
115 constexpr float DOUBLE_CLICK_INTERVAL_MS = 300.0f;
116 
117 constexpr float DEFAILT_OPACITY = 0.2f;
118 constexpr int64_t COLOR_OPAQUE = 255;
119 constexpr int32_t MAX_CLICK = 3;
120 
121 constexpr Color SYSTEM_CARET_COLOR = Color(0xff007dff);
122 constexpr Color SYSTEM_SELECT_BACKGROUND_COLOR = Color(0x33007dff);
123 
124 constexpr int32_t ERROR_BAD_PARAMETERS = -1;
125 constexpr char PREVIEW_STYLE_NORMAL[] = "normal";
126 constexpr char PREVIEW_STYLE_UNDERLINE[] = "underline";
127 const std::wstring lineSeparator = L"\n";
128 // hen do ai anaylsis, we should limit the left an right limit of the string
129 constexpr static int32_t AI_TEXT_RANGE_LEFT = 50;
130 constexpr static int32_t AI_TEXT_RANGE_RIGHT = 50;
131 constexpr static int32_t NONE_SELECT_TYPE = -1;
132 constexpr float RICH_DEFAULT_SHADOW_COLOR = 0x33000000;
133 constexpr float RICH_DEFAULT_ELEVATION = 120.0f;
134 constexpr int32_t CUSTOM_CONTENT_LENGTH = 1;
135 constexpr int32_t SYMBOL_CONTENT_LENGTH = 2;
136 constexpr int32_t PLACEHOLDER_LENGTH = 6;
137 const std::wstring PLACEHOLDER_MARK = L"![id";
138 constexpr int32_t RICH_DEFAULT_AI_WORD = 100;
139 } // namespace
140 
RichEditorPattern()141 RichEditorPattern::RichEditorPattern() :
142 #ifndef ACE_UNITTEST
143     isAPI14Plus(AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_FOURTEEN))
144 #else
145     isAPI14Plus(true)
146 #endif
147 {
148     magnifierController_ = MakeRefPtr<MagnifierController>(WeakClaim(this));
149     selectOverlay_ = AceType::MakeRefPtr<RichEditorSelectOverlay>(WeakClaim(this));
150     styledString_ = MakeRefPtr<MutableSpanString>("");
151     styledString_->SetSpanWatcher(WeakClaim(this));
152 }
153 
~RichEditorPattern()154 RichEditorPattern::~RichEditorPattern()
155 {
156     if (isCustomKeyboardAttached_) {
157         CloseCustomKeyboard();
158     }
159 }
160 
SetStyledString(const RefPtr<SpanString> & value)161 void RichEditorPattern::SetStyledString(const RefPtr<SpanString>& value)
162 {
163     CHECK_NULL_VOID(value && styledString_);
164     CloseSelectOverlay();
165     ResetSelection();
166     styledString_->RemoveCustomSpan();
167     auto length = styledString_->GetLength();
168     styledString_->ReplaceSpanString(0, length, value);
169     SetCaretPosition(styledString_->GetLength());
170     MoveCaretToContentRect();
171     auto host = GetHost();
172     CHECK_NULL_VOID(host);
173     styledString_->AddCustomSpan();
174     styledString_->SetFramNode(WeakClaim(host.GetRawPtr()));
175     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
176     ForceTriggerAvoidOnCaretChange();
177 }
178 
UpdateSpanItems(const std::list<RefPtr<NG::SpanItem>> & spanItems)179 void RichEditorPattern::UpdateSpanItems(const std::list<RefPtr<NG::SpanItem>>& spanItems)
180 {
181     SetSpanItemChildren(spanItems);
182     ProcessStyledString();
183 }
184 
ProcessStyledString()185 void RichEditorPattern::ProcessStyledString()
186 {
187     auto host = GetHost();
188     CHECK_NULL_VOID(host);
189     std::string textCache = textForDisplay_;
190     textForDisplay_.clear();
191     dataDetectorAdapter_->textForAI_.clear();
192     host->Clean();
193     RemoveEmptySpanItems();
194     hasUrlSpan_ = false;
195     for (const auto& span : spans_) {
196         if (!span) {
197             continue;
198         }
199         auto imageSpan = DynamicCast<ImageSpanItem>(span);
200         if (imageSpan) {
201             MountImageNode(imageSpan);
202             dataDetectorAdapter_->textForAI_ += '\n';
203         } else {
204             dataDetectorAdapter_->textForAI_ += span->content;
205         }
206         textForDisplay_ += span->content;
207         auto [spanStart, spanEnd] = span->interval;
208         span->rangeStart = spanStart;
209         span->position = spanEnd;
210 
211         if (span->urlOnRelease) {
212             hasUrlSpan_ = true;
213         }
214     }
215     if (textForDisplay_ != textCache) {
216         dataDetectorAdapter_->aiDetectInitialized_ = false;
217     }
218     if (CanStartAITask() && !dataDetectorAdapter_->aiDetectInitialized_) {
219         dataDetectorAdapter_->StartAITask();
220     }
221 }
222 
MountImageNode(const RefPtr<ImageSpanItem> & imageItem)223 void RichEditorPattern::MountImageNode(const RefPtr<ImageSpanItem>& imageItem)
224 {
225     auto host = GetHost();
226     CHECK_NULL_VOID(host);
227     CHECK_NULL_VOID(imageItem);
228     auto options = imageItem->options;
229     auto imageNode = ImageSpanNode::GetOrCreateSpanNode(V2::IMAGE_ETS_TAG,
230         ElementRegister::GetInstance()->MakeUniqueId(), []() { return AceType::MakeRefPtr<ImagePattern>(); });
231     auto pattern = imageNode->GetPattern<ImagePattern>();
232     CHECK_NULL_VOID(pattern);
233     if (options.imagePixelMap.has_value()) {
234         pattern->SetSyncLoad(true);
235     } else if (options.imageAttribute.has_value()) {
236         pattern->SetSyncLoad(options.imageAttribute.value().syncLoad);
237     }
238     auto index = host->GetChildren().size();
239     imageNodes.push_back(WeakClaim(imageNode.GetRawPtr()));
240     imageNode->MountToParent(host, index);
241     HandleImageDrag(imageNode);
242     SetImageLayoutProperty(imageNode, options);
243     imageNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
244     imageNode->MarkModifyDone();
245     imageItem->imageNodeId = imageNode->GetId();
246     imageNode->SetImageItem(imageItem);
247 }
248 
SetImageLayoutProperty(RefPtr<ImageSpanNode> imageNode,const ImageSpanOptions & options)249 void RichEditorPattern::SetImageLayoutProperty(RefPtr<ImageSpanNode> imageNode, const ImageSpanOptions& options)
250 {
251     CHECK_NULL_VOID(imageNode);
252     auto imageLayoutProperty = imageNode->GetLayoutProperty<ImageLayoutProperty>();
253     CHECK_NULL_VOID(imageLayoutProperty);
254     std::function<ImageSourceInfo()> createSourceInfoFunc = CreateImageSourceInfo(options);
255     imageLayoutProperty->UpdateImageSourceInfo(createSourceInfoFunc());
256     if (options.imageAttribute.has_value()) {
257         auto imgAttr = options.imageAttribute.value();
258         if (imgAttr.size.has_value()) {
259             imageLayoutProperty->UpdateUserDefinedIdealSize(imgAttr.size->GetSize());
260         }
261         if (imgAttr.verticalAlign.has_value()) {
262             imageLayoutProperty->UpdateVerticalAlign(imgAttr.verticalAlign.value());
263         }
264         if (imgAttr.objectFit.has_value()) {
265             imageLayoutProperty->UpdateImageFit(imgAttr.objectFit.value());
266         }
267         if (imgAttr.marginProp.has_value()) {
268             imageLayoutProperty->UpdateMargin(imgAttr.marginProp.value());
269         }
270         if (imgAttr.paddingProp.has_value()) {
271             imageLayoutProperty->UpdatePadding(imgAttr.paddingProp.value());
272         }
273         if (imgAttr.borderRadius.has_value()) {
274             auto imageRenderCtx = imageNode->GetRenderContext();
275             imageRenderCtx->UpdateBorderRadius(imgAttr.borderRadius.value());
276             imageRenderCtx->SetClipToBounds(true);
277         }
278         auto paintProperty = imageNode->GetPaintProperty<ImageRenderProperty>();
279         if (imgAttr.colorFilterMatrix.has_value() && paintProperty) {
280             paintProperty->UpdateColorFilter(imgAttr.colorFilterMatrix.value());
281             paintProperty->ResetDrawingColorFilter();
282         } else if (imgAttr.drawingColorFilter.has_value() && paintProperty) {
283             paintProperty->UpdateDrawingColorFilter(imgAttr.drawingColorFilter.value());
284             paintProperty->ResetColorFilter();
285         }
286     }
287     imageNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
288     imageNode->MarkModifyDone();
289     IF_PRESENT(oneStepDragController_, MarkDirtyNode(WeakClaim(RawPtr(imageNode))));
290 }
291 
InsertValueInStyledString(const std::string & insertValue)292 void RichEditorPattern::InsertValueInStyledString(const std::string& insertValue)
293 {
294     CHECK_NULL_VOID(styledString_);
295     int32_t changeStart = caretPosition_;
296     int32_t changeLength = 0;
297     if (textSelector_.IsValid()) {
298         changeStart = textSelector_.GetTextStart();
299         changeLength = textSelector_.GetTextEnd() - changeStart;
300     }
301     bool isPreventChange = false;
302     RefPtr<SpanString> insertStyledString = nullptr;
303     if (typingStyle_.has_value() && typingTextStyle_.has_value()) {
304         insertStyledString = CreateStyledStringByTextStyle(insertValue, typingStyle_.value(), typingTextStyle_.value());
305         isPreventChange = !BeforeStyledStringChange(changeStart, changeLength, insertStyledString);
306     } else {
307         isPreventChange = !BeforeStyledStringChange(changeStart, changeLength, insertValue);
308     }
309     CHECK_NULL_VOID(!isPreventChange);
310     if (changeLength > 0) {
311         DeleteForwardInStyledString(changeLength, false);
312     }
313     if (textSelector_.IsValid()) {
314         CloseSelectOverlay();
315         ResetSelection();
316     }
317     if (insertStyledString) {
318         styledString_->InsertSpanString(changeStart, insertStyledString);
319     } else {
320         styledString_->InsertString(changeStart, insertValue);
321     }
322     SetCaretPosition(changeStart + static_cast<int32_t>(StringUtils::ToWstring(insertValue).length()));
323     if (!caretVisible_) {
324         StartTwinkling();
325     }
326     auto host = GetHost();
327     CHECK_NULL_VOID(host);
328     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
329     host->MarkModifyDone();
330     AfterStyledStringChange(changeStart, changeLength, insertValue);
331 }
332 
CreateStyledStringByTextStyle(const std::string & insertValue,const struct UpdateSpanStyle & updateSpanStyle,const TextStyle & textStyle)333 RefPtr<SpanString> RichEditorPattern::CreateStyledStringByTextStyle(
334     const std::string& insertValue, const struct UpdateSpanStyle& updateSpanStyle, const TextStyle& textStyle)
335 {
336     auto styledString = AceType::MakeRefPtr<SpanString>(insertValue);
337     auto length = styledString->GetLength();
338     auto fontSpan = CreateFontSpanByTextStyle(updateSpanStyle, textStyle, length);
339     styledString->AddSpan(fontSpan);
340     auto decorationSpan = CreateDecorationSpanByTextStyle(updateSpanStyle, textStyle, length);
341     styledString->AddSpan(decorationSpan);
342     if (updateSpanStyle.updateTextShadows.has_value()) {
343         auto textShadowSpan = AceType::MakeRefPtr<TextShadowSpan>(textStyle.GetTextShadows(), 0, length);
344         styledString->AddSpan(textShadowSpan);
345     }
346     if (updateSpanStyle.updateLineHeight.has_value()) {
347         auto lineHeightSpan = AceType::MakeRefPtr<LineHeightSpan>(textStyle.GetLineHeight(), 0, length);
348         styledString->AddSpan(lineHeightSpan);
349     }
350     if (updateSpanStyle.updateLetterSpacing.has_value()) {
351         auto letterSpacingSpan = AceType::MakeRefPtr<LetterSpacingSpan>(textStyle.GetLetterSpacing(), 0, length);
352         styledString->AddSpan(letterSpacingSpan);
353     }
354     return styledString;
355 }
356 
CreateFontSpanByTextStyle(const struct UpdateSpanStyle & updateSpanStyle,const TextStyle & textStyle,int32_t length)357 RefPtr<FontSpan> RichEditorPattern::CreateFontSpanByTextStyle(
358     const struct UpdateSpanStyle& updateSpanStyle, const TextStyle& textStyle, int32_t length)
359 {
360     Font font;
361     if (updateSpanStyle.updateFontWeight.has_value()) {
362         font.fontWeight = textStyle.GetFontWeight();
363     }
364     if (updateSpanStyle.updateFontSize.has_value()) {
365         font.fontSize = textStyle.GetFontSize();
366     }
367     if (updateSpanStyle.updateItalicFontStyle.has_value()) {
368         font.fontStyle = textStyle.GetFontStyle();
369     }
370     if (updateSpanStyle.updateFontFamily.has_value()) {
371         font.fontFamilies = textStyle.GetFontFamilies();
372     }
373     if (updateSpanStyle.updateTextColor.has_value()) {
374         font.fontColor = textStyle.GetTextColor();
375     }
376     return AceType::MakeRefPtr<FontSpan>(font, 0, length);
377 }
378 
CreateDecorationSpanByTextStyle(const struct UpdateSpanStyle & updateSpanStyle,const TextStyle & textStyle,int32_t length)379 RefPtr<DecorationSpan> RichEditorPattern::CreateDecorationSpanByTextStyle(
380     const struct UpdateSpanStyle& updateSpanStyle, const TextStyle& textStyle, int32_t length)
381 {
382     TextDecoration type = TextDecoration::NONE;
383     std::optional<Color> colorOption;
384     std::optional<TextDecorationStyle> styleOption;
385     if (updateSpanStyle.updateTextDecoration.has_value()) {
386         type = textStyle.GetTextDecoration();
387     }
388     if (updateSpanStyle.updateTextDecorationColor.has_value()) {
389         colorOption = textStyle.GetTextDecorationColor();
390     }
391     if (updateSpanStyle.updateTextDecorationStyle.has_value()) {
392         styleOption = textStyle.GetTextDecorationStyle();
393     }
394     return AceType::MakeRefPtr<DecorationSpan>(type, colorOption, styleOption, 0, length);
395 }
396 
DeleteBackwardInStyledString(int32_t length)397 void RichEditorPattern::DeleteBackwardInStyledString(int32_t length)
398 {
399     DeleteValueInStyledString(caretPosition_ - length, length);
400 }
401 
DeleteForwardInStyledString(int32_t length,bool isIME)402 void RichEditorPattern::DeleteForwardInStyledString(int32_t length, bool isIME)
403 {
404     DeleteValueInStyledString(caretPosition_, length, isIME);
405 }
406 
DeleteValueInStyledString(int32_t start,int32_t length,bool isIME,bool isUpdateCaret)407 void RichEditorPattern::DeleteValueInStyledString(int32_t start, int32_t length, bool isIME, bool isUpdateCaret)
408 {
409     CHECK_NULL_VOID(styledString_);
410     if (!textSelector_.SelectNothing()) {
411         start = textSelector_.GetTextStart();
412         length = textSelector_.GetTextEnd() - textSelector_.GetTextStart();
413     }
414     auto range = TextEmojiProcessor::CalSubWstringRange(start, length, styledString_->GetWideString(), true);
415     start = range.startIndex;
416     length = range.endIndex - range.startIndex;
417     bool isPreventChange = isIME && !BeforeStyledStringChange(start, length, "");
418     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "start=%{public}d, length=%{public}d, isPreventChange=%{public}d",
419         start, length, isPreventChange);
420     CHECK_NULL_VOID(!isPreventChange);
421     if (textSelector_.IsValid()) {
422         CloseSelectOverlay();
423         ResetSelection();
424     }
425     styledString_->RemoveString(start, length);
426     if (isUpdateCaret) {
427         SetCaretPosition(start);
428     }
429     if (!caretVisible_) {
430         StartTwinkling();
431         if (previewLongPress_ && isIME) {
432             TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "previewLongPress_ is true, before RequestKeyboard");
433             RequestKeyboard(false, true, true);
434             HandleOnEditChanged(true);
435             previewLongPress_ = false;
436         }
437     }
438     if (isIME) {
439         AfterStyledStringChange(start, length, "");
440     }
441     auto host = GetHost();
442     CHECK_NULL_VOID(host);
443     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
444     host->MarkModifyDone();
445 }
446 
BeforeStyledStringChange(int32_t start,int32_t length,const std::string & string)447 bool RichEditorPattern::BeforeStyledStringChange(int32_t start, int32_t length, const std::string& string)
448 {
449     auto eventHub = GetEventHub<RichEditorEventHub>();
450     CHECK_NULL_RETURN(eventHub, true);
451     CHECK_NULL_RETURN(eventHub->HasOnStyledStringWillChange(), true);
452     auto styledString = AceType::MakeRefPtr<SpanString>(string);
453     auto stringLength = styledString->GetLength();
454     auto changeStart = std::clamp(start, 0, GetTextContentLength());
455     if (stringLength != 0) {
456         auto lastStyles = styledString_->GetSpans(changeStart - 1, 1);
457         for (auto && style : lastStyles) {
458             if (!style) {
459                 continue;
460             }
461             auto spanType = style->GetSpanType();
462             if (spanType == SpanType::Image || spanType == SpanType::CustomSpan) {
463                 continue;
464             }
465             auto span = style->GetSubSpan(0, stringLength);
466             styledString->AddSpan(span);
467         }
468     }
469     return BeforeStyledStringChange(changeStart, length, styledString);
470 }
471 
BeforeStyledStringChange(int32_t start,int32_t length,const RefPtr<SpanString> & styledString)472 bool RichEditorPattern::BeforeStyledStringChange(int32_t start, int32_t length, const RefPtr<SpanString>& styledString)
473 {
474     auto eventHub = GetEventHub<RichEditorEventHub>();
475     CHECK_NULL_RETURN(eventHub, true);
476     CHECK_NULL_RETURN(eventHub->HasOnStyledStringWillChange(), true);
477     auto replaceMentString = AceType::MakeRefPtr<MutableSpanString>("");
478     replaceMentString->AppendSpanString(styledString);
479     StyledStringChangeValue changeValue;
480     auto changeStart = std::clamp(start, 0, GetTextContentLength());
481     auto changeEnd = std::clamp(changeStart + length, 0, GetTextContentLength());
482     changeValue.SetRangeBefore({ changeStart, changeEnd });
483     changeValue.SetReplacementString(replaceMentString);
484     return eventHub->FireOnStyledStringWillChange(changeValue);
485 }
486 
AfterStyledStringChange(int32_t start,int32_t length,const std::string & string)487 void RichEditorPattern::AfterStyledStringChange(int32_t start, int32_t length, const std::string& string)
488 {
489     auto eventHub = GetEventHub<RichEditorEventHub>();
490     CHECK_NULL_VOID(eventHub);
491     if (eventHub->HasOnStyledStringDidChange()) {
492         StyledStringChangeValue changeValue;
493         auto changeStart = std::clamp(start, 0, GetTextContentLength());
494         auto changeEnd = changeStart + length;
495         auto stringLength = static_cast<int32_t>(StringUtils::ToWstring(string).length());
496         auto stringEnd = changeStart + stringLength;
497         changeValue.SetRangeBefore({ changeStart, changeEnd });
498         changeValue.SetRangeAfter({ changeStart, stringEnd });
499         eventHub->FireOnStyledStringDidChange(changeValue);
500     }
501     ForceTriggerAvoidOnCaretChange();
502 }
503 
OnModifyDone()504 void RichEditorPattern::OnModifyDone()
505 {
506     auto host = GetHost();
507     CHECK_NULL_VOID(host);
508     auto layoutProperty = host->GetLayoutProperty<TextLayoutProperty>();
509     copyOption_ = layoutProperty->GetCopyOption().value_or(CopyOptions::Distributed);
510     auto context = host->GetContext();
511     CHECK_NULL_VOID(context);
512     ResetKeyboardIfNeed();
513     context->AddOnAreaChangeNode(host->GetId());
514     if (!clipboard_ && context) {
515         clipboard_ = ClipboardProxy::GetInstance()->GetClipboard(context->GetTaskExecutor());
516     }
517     instanceId_ = context->GetInstanceId();
518     InitMouseEvent();
519     auto focusHub = host->GetOrCreateFocusHub();
520     CHECK_NULL_VOID(focusHub);
521     InitFocusEvent(focusHub);
522     auto gestureEventHub = host->GetOrCreateGestureEventHub();
523     InitClickEvent(gestureEventHub);
524     InitLongPressEvent(gestureEventHub);
525     InitTouchEvent();
526     InitPanEvent();
527     HandleEnabled();
528     ProcessInnerPadding();
529     InitScrollablePattern();
530     SetAccessibilityAction();
531     selectOverlay_->SetMenuTranslateIsSupport(IsShowTranslate());
532     if (host->IsDraggable()) {
533         InitDragDropEvent();
534         AddDragFrameNodeToManager(host);
535     } else {
536         ClearDragDropEvent();
537         RemoveDragFrameNodeFromManager(host);
538     }
539     Register2DragDropManager();
540     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
541 
542     auto eventHub = host->GetEventHub<EventHub>();
543     CHECK_NULL_VOID(eventHub);
544     bool enabledCache = eventHub->IsEnabled();
545     if (textDetectEnable_ && enabledCache != enabled_) {
546         enabled_ = enabledCache;
547         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
548     }
549 }
550 
HandleEnabled()551 void RichEditorPattern::HandleEnabled()
552 {
553     auto host = GetHost();
554     CHECK_NULL_VOID(host);
555     auto renderContext = host->GetRenderContext();
556     CHECK_NULL_VOID(renderContext);
557     if (IsDisabled()) {
558         auto pipeline = host->GetContext();
559         CHECK_NULL_VOID(pipeline);
560         auto richEditorTheme = pipeline->GetTheme<RichEditorTheme>();
561         CHECK_NULL_VOID(richEditorTheme);
562         auto disabledAlpha = richEditorTheme->GetDisabledAlpha();
563         renderContext->OnOpacityUpdate(disabledAlpha);
564     } else {
565         auto opacity = renderContext->GetOpacity().value_or(1.0);
566         renderContext->OnOpacityUpdate(opacity);
567     }
568 }
569 
BeforeCreateLayoutWrapper()570 void RichEditorPattern::BeforeCreateLayoutWrapper()
571 {
572     ACE_SCOPED_TRACE("RichEditorBeforeCreateLayoutWrapper");
573     if (!isSpanStringMode_) {
574         TextPattern::PreCreateLayoutWrapper();
575     } else if (contentMod_) {
576         contentMod_->ContentChange();
577     }
578 }
579 
UpdateMagnifierStateAfterLayout(bool frameSizeChange)580 void RichEditorPattern::UpdateMagnifierStateAfterLayout(bool frameSizeChange)
581 {
582     CHECK_NULL_VOID(!selectOverlay_->GetIsHandleMoving());
583     if (frameSizeChange && magnifierController_ && magnifierController_->GetMagnifierNodeExist()) {
584         previewLongPress_ = false;
585         editingLongPress_ = false;
586         if (moveCaretState_.isMoveCaret) {
587             isCursorAlwaysDisplayed_ = false;
588             StartTwinkling();
589         }
590         moveCaretState_.Reset();
591         magnifierController_->RemoveMagnifierFrameNode();
592     }
593 }
594 
ClearOnFocusTextField()595 void RichEditorPattern::ClearOnFocusTextField()
596 {
597     CHECK_NULL_VOID(AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_FOURTEEN));
598     auto host = GetHost();
599     CHECK_NULL_VOID(host);
600     auto context = host->GetContextRefPtr();
601     CHECK_NULL_VOID(context);
602     auto textFieldManager = DynamicCast<TextFieldManagerNG>(context->GetTextFieldManager());
603     CHECK_NULL_VOID(textFieldManager);
604     textFieldManager->ClearOnFocusTextField(host->GetId());
605 }
606 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)607 bool RichEditorPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
608 {
609     CHECK_NULL_RETURN(!config.skipMeasure && !dirty->SkipMeasureContent(), false);
610     auto originalFrameRect = frameRect_;
611     frameRect_ = dirty->GetGeometryNode()->GetFrameRect();
612     auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
613     CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
614     auto richEditorLayoutAlgorithm =
615         DynamicCast<RichEditorLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
616     CHECK_NULL_RETURN(richEditorLayoutAlgorithm, false);
617     auto parentGlobalOffset = richEditorLayoutAlgorithm->GetParentGlobalOffset();
618     richTextRect_ = richEditorLayoutAlgorithm->GetTextRect();
619     if (parentGlobalOffset != parentGlobalOffset_) {
620         parentGlobalOffset_ = parentGlobalOffset;
621         selectOverlay_->UpdateSelectOverlayOnAreaChanged();
622     }
623     UpdateTextFieldManager(Offset(parentGlobalOffset_.GetX(), parentGlobalOffset_.GetY()), frameRect_.Height());
624     bool ret = TextPattern::OnDirtyLayoutWrapperSwap(dirty, config);
625     UpdateScrollStateAfterLayout(config.frameSizeChange);
626     UpdateMagnifierStateAfterLayout(config.frameSizeChange);
627     IF_TRUE(!isRichEditorInit_, FireOnReady());
628     MoveCaretOnLayoutSwap();
629     HandleTasksOnLayoutSwap();
630     HandleSelectOverlayOnLayoutSwap();
631     IF_TRUE(originalFrameRect.GetSize() != frameRect_.GetSize(), {
632         TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "frame size change");
633         TriggerAvoidOnCaretChangeNextFrame();
634     });
635     IF_TRUE(!isModifyingContent_, UpdateCaretInfoToController());
636     auto host = GetHost();
637     CHECK_NULL_RETURN(host, ret);
638     SupplementIdealSizeWidth(host);
639     auto context = host->GetRenderContext();
640     CHECK_NULL_RETURN(context, ret);
641     if (context->GetClipEdge().has_value()) {
642         auto geometryNode = host->GetGeometryNode();
643         auto frameOffset = geometryNode->GetFrameOffset();
644         auto frameSize = geometryNode->GetFrameSize();
645         auto height = static_cast<float>(paragraphs_.GetHeight() + std::fabs(baselineOffset_));
646         if (!context->GetClipEdge().value() && LessNotEqual(frameSize.Height(), height)) {
647             RectF boundsRect(frameOffset.GetX(), frameOffset.GetY(), frameSize.Width(), height);
648             CHECK_NULL_RETURN(overlayMod_, ret);
649             overlayMod_->SetBoundsRect(boundsRect);
650         }
651     }
652     caretUpdateType_ = CaretUpdateType::NONE;
653     IF_PRESENT(oneStepDragController_, HandleDirtyNodes());
654     return ret;
655 }
656 
HandleSelectOverlayOnLayoutSwap()657 void RichEditorPattern::HandleSelectOverlayOnLayoutSwap()
658 {
659     bool needToRefreshSelectOverlay = textSelector_.IsValid() && SelectOverlayIsOn() && !IsPreviewTextInputting();
660     CHECK_NULL_VOID(needToRefreshSelectOverlay);
661     auto overlayTask = [weak = WeakClaim(this)]() {
662         auto pattern = weak.Upgrade();
663         CHECK_NULL_VOID(pattern);
664         auto selectOverlay = pattern->selectOverlay_;
665         CHECK_NULL_VOID(selectOverlay);
666         pattern->CalculateHandleOffsetAndShowOverlay();
667         selectOverlay->ProcessOverlay({ .menuIsShow = selectOverlay->IsCurrentMenuVisibile(), .animation = true });
668     };
669     if (AnimationUtils::IsImplicitAnimationOpen()) {
670         auto pipeline = PipelineContext::GetCurrentContextSafely();
671         CHECK_NULL_VOID(pipeline);
672         pipeline->AddAfterRenderTask(overlayTask);
673     } else {
674         overlayTask();
675     }
676 }
677 
FireOnReady()678 void RichEditorPattern::FireOnReady()
679 {
680     auto eventHub = GetEventHub<RichEditorEventHub>();
681     CHECK_NULL_VOID(eventHub);
682     eventHub->FireOnReady();
683     ClearOperationRecords();
684     isFirstCallOnReady_ = true;
685     isRichEditorInit_ = true;
686 }
687 
SupplementIdealSizeWidth(const RefPtr<FrameNode> & frameNode)688 void RichEditorPattern::SupplementIdealSizeWidth(const RefPtr<FrameNode>& frameNode)
689 {
690     auto layoutProperty = frameNode->GetLayoutProperty<RichEditorLayoutProperty>();
691     CHECK_NULL_VOID(layoutProperty);
692     auto&& constraint = layoutProperty->GetCalcLayoutConstraint();
693     if (!constraint || !constraint->selfIdealSize.has_value() || !constraint->selfIdealSize->Width().has_value()) {
694         layoutProperty->UpdateUserDefinedIdealSize(CalcSize(CalcLength(frameRect_.Width()), std::nullopt));
695     }
696 }
697 
MoveCaretOnLayoutSwap()698 void RichEditorPattern::MoveCaretOnLayoutSwap()
699 {
700     MoveCaretAfterTextChange();
701     if (needMoveCaretToContentRect_ || isEditing_) {
702         MoveCaretToContentRect();
703         needMoveCaretToContentRect_ = false;
704     }
705 }
706 
CreateImageSourceInfo(const ImageSpanOptions & options)707 std::function<ImageSourceInfo()> RichEditorPattern::CreateImageSourceInfo(const ImageSpanOptions& options)
708 {
709     std::string src;
710     RefPtr<PixelMap> pixMap = nullptr;
711     std::string bundleName;
712     std::string moduleName;
713     if (options.image.has_value()) {
714         src = options.image.value();
715     }
716     if (options.imagePixelMap.has_value()) {
717         pixMap = options.imagePixelMap.value();
718     }
719     if (options.bundleName.has_value()) {
720         bundleName = options.bundleName.value();
721     }
722     if (options.moduleName.has_value()) {
723         moduleName = options.moduleName.value();
724     }
725     auto createSourceInfoFunc = [src, noPixMap = !options.imagePixelMap.has_value(),
726                                     isUriPureNumber = options.isUriPureNumber.value_or(false), pixMap, bundleName,
727                                     moduleName]() -> ImageSourceInfo {
728         ImageSourceInfo info;
729 #if defined(PIXEL_MAP_SUPPORTED)
730         if (noPixMap) {
731             info = ImageSourceInfo { src, bundleName, moduleName };
732         } else {
733             info = ImageSourceInfo(pixMap);
734         }
735 #else
736         info = ImageSourceInfo { src, bundleName, moduleName };
737 #endif
738         info.SetIsUriPureNumber(isUriPureNumber);
739         return info;
740     };
741     return std::move(createSourceInfoFunc);
742 }
743 
GetTextContentLength()744 int32_t RichEditorPattern::GetTextContentLength()
745 {
746     if (isSpanStringMode_ && styledString_) {
747         return styledString_->GetLength();
748     }
749     if (!spans_.empty()) {
750         auto it = spans_.rbegin();
751         return (*it)->position;
752     }
753     return 0;
754 }
755 
SetPreviewMenuParam(TextSpanType spanType,std::function<void ()> & builder,const SelectMenuParam & menuParam)756 void RichEditorPattern::SetPreviewMenuParam(TextSpanType spanType, std::function<void()>& builder, const SelectMenuParam& menuParam)
757 {
758     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "SetPreviewMenuParam, spanType=%{public}d", spanType);
759     if (!oneStepDragController_) {
760         oneStepDragController_ = std::make_unique<OneStepDragController>(WeakClaim(this));
761     }
762     oneStepDragController_->SetMenuParam(spanType, builder, menuParam);
763 }
764 
HandleImageDrag(const RefPtr<ImageSpanNode> & imageNode)765 void RichEditorPattern::HandleImageDrag(const RefPtr<ImageSpanNode>& imageNode)
766 {
767     DisableDrag(imageNode);
768     IF_PRESENT(oneStepDragController_, EnableOneStepDrag(TextSpanType::IMAGE, imageNode));
769 }
770 
DisableDrag(const RefPtr<ImageSpanNode> & imageNode)771 void RichEditorPattern::DisableDrag(const RefPtr<ImageSpanNode>& imageNode)
772 {
773     // Disable the image itself event
774     imageNode->SetDraggable(false);
775     auto gesture = imageNode->GetOrCreateGestureEventHub();
776     CHECK_NULL_VOID(gesture);
777     gesture->InitDragDropEvent();
778     gesture->SetDragEvent(nullptr, { PanDirection::DOWN }, 0, Dimension(0));
779 }
780 
SetGestureOptions(UserGestureOptions options,RefPtr<SpanItem> spanItem)781 void RichEditorPattern::SetGestureOptions(UserGestureOptions options, RefPtr<SpanItem> spanItem)
782 {
783     IF_TRUE(options.onClick, spanItem->SetOnClickEvent(std::move(options.onClick)));
784     IF_TRUE(options.onLongPress, spanItem->SetLongPressEvent(std::move(options.onLongPress)));
785     IF_TRUE(options.onDoubleClick, spanItem->SetDoubleClickEvent(std::move(options.onDoubleClick)));
786 }
787 
AddSpanHoverEvent(RefPtr<SpanItem> spanItem,const RefPtr<FrameNode> & frameNode,const SpanOptionBase & options)788 void RichEditorPattern::AddSpanHoverEvent(
789     RefPtr<SpanItem> spanItem, const RefPtr<FrameNode>& frameNode, const SpanOptionBase& options)
790 {
791     auto onHoverFunc = options.userMouseOption.onHover;
792     CHECK_NULL_VOID(spanItem && frameNode && onHoverFunc);
793     auto tag = frameNode->GetTag();
794     spanItem->SetHoverEvent(std::move(onHoverFunc));
795     auto eventHub = frameNode->GetEventHub<EventHub>();
796     CHECK_NULL_VOID(eventHub);
797     auto inputHub = eventHub->GetOrCreateInputEventHub();
798     CHECK_NULL_VOID(inputHub);
799     auto hoverTask = [weak = WeakClaim(spanItem.GetRawPtr()), tag](bool isHover, HoverInfo& info) {
800         auto item = weak.Upgrade();
801         if (item && item->onHover) {
802             TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "[%{public}s] onHover status :[%{public}d]", tag.c_str(), isHover);
803             item->onHover(isHover, info);
804         }
805     };
806     auto hoverEvent = MakeRefPtr<InputEvent>(std::move(hoverTask));
807     inputHub->AddOnHoverEvent(hoverEvent);
808 }
809 
AddImageSpan(const ImageSpanOptions & options,bool isPaste,int32_t index,bool updateCaret)810 int32_t RichEditorPattern::AddImageSpan(const ImageSpanOptions& options, bool isPaste, int32_t index, bool updateCaret)
811 {
812     auto host = GetHost();
813     CHECK_NULL_RETURN(host, -1);
814     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "options=%{public}s", options.ToString().c_str());
815     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "isPaste=%{public}d, index=%{public}d, updateCaret=%{public}d",
816         isPaste, index, updateCaret);
817     auto imageNode = ImageSpanNode::GetOrCreateSpanNode(V2::IMAGE_ETS_TAG,
818         ElementRegister::GetInstance()->MakeUniqueId(), []() { return AceType::MakeRefPtr<ImagePattern>(); });
819     auto pattern = imageNode->GetPattern<ImagePattern>();
820     CHECK_NULL_RETURN(pattern, -1);
821     pattern->SetSyncLoad(true);
822     auto imageLayoutProperty = imageNode->GetLayoutProperty<ImageLayoutProperty>();
823     int32_t insertIndex = std::min(options.offset.value_or(GetTextContentLength()), GetTextContentLength());
824     RichEditorChangeValue changeValue;
825     CHECK_NULL_RETURN(BeforeAddImage(changeValue, options, insertIndex), -1);
826 
827     HandleImageDrag(imageNode);
828     AddOprationWhenAddImage(options.offset.value_or(static_cast<int32_t>(GetTextContentLength())));
829     int32_t spanIndex = TextSpanSplit(insertIndex);
830     IF_TRUE(spanIndex == -1, spanIndex = static_cast<int32_t>(host->GetChildren().size()));
831 
832     imageNodes.push_back(WeakClaim(imageNode.GetRawPtr()));
833     imageNode->MountToParent(host, spanIndex);
834     std::function<ImageSourceInfo()> createSourceInfoFunc = CreateImageSourceInfo(options);
835     imageLayoutProperty->UpdateImageSourceInfo(createSourceInfoFunc());
836     auto renderContext = imageNode->GetRenderContext();
837     if (renderContext) {
838         renderContext->SetNeedAnimateFlag(false);
839     }
840     SetImageLayoutProperty(imageNode, options);
841     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
842     host->MarkModifyDone();
843     auto spanItem = imageNode->GetSpanItem();
844     // The length of the imageSpan defaults to the length of a character to calculate the position
845     spanItem->content = " ";
846     spanItem->SetImageSpanOptions(options);
847     AddSpanItem(spanItem, spanIndex);
848     SetGestureOptions(options.userGestureOption, spanItem);
849     AddSpanHoverEvent(spanItem, imageNode, options);
850     placeholderCount_++;
851     if (updateCaret) {
852         SetCaretPosition(insertIndex + spanItem->content.length());
853         SetNeedMoveCaretToContentRect();
854     }
855     ResetSelectionAfterAddSpan(isPaste);
856     AfterContentChange(changeValue);
857     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "end");
858     return spanIndex;
859 }
860 
AddOprationWhenAddImage(int32_t beforeCaretPos)861 void RichEditorPattern::AddOprationWhenAddImage(int32_t beforeCaretPos)
862 {
863     OperationRecord record;
864     record.beforeCaretPosition = beforeCaretPos;
865     record.addText = " ";
866     ClearRedoOperationRecords();
867     record.afterCaretPosition = record.beforeCaretPosition + 1;
868     AddOperationRecord(record);
869 }
870 
ResetSelectionAfterAddSpan(bool isPaste)871 void RichEditorPattern::ResetSelectionAfterAddSpan(bool isPaste)
872 {
873     if (isPaste || !textSelector_.IsValid()) {
874         return;
875     }
876     CloseSelectOverlay();
877     ResetSelection();
878     if (isEditing_ && !caretVisible_) {
879         StartTwinkling();
880     }
881 }
882 
AddSpanItem(const RefPtr<SpanItem> & item,int32_t offset)883 void RichEditorPattern::AddSpanItem(const RefPtr<SpanItem>& item, int32_t offset)
884 {
885     auto host = GetHost();
886     CHECK_NULL_VOID(host);
887     if (offset == -1) {
888         offset = static_cast<int32_t>(host->GetChildren().size());
889     }
890     offset = std::clamp(offset, 0, static_cast<int32_t>(host->GetChildren().size()) - 1);
891     auto it = spans_.begin();
892     std::advance(it, offset);
893     spans_.insert(it, item);
894     UpdateSpanPosition();
895 }
896 
OnAttachToFrameNode()897 void RichEditorPattern::OnAttachToFrameNode()
898 {
899     TextPattern::OnAttachToFrameNode();
900     richEditorInstanceId_ = Container::CurrentIdSafely();
901     auto frameNode = GetHost();
902     CHECK_NULL_VOID(frameNode);
903     frameId_ = frameNode->GetId();
904     auto renderContext = frameNode->GetRenderContext();
905     CHECK_NULL_VOID(renderContext);
906     renderContext->UpdateClipEdge(true);
907     renderContext->SetClipToFrame(true);
908     StylusDetectorMgr::GetInstance()->AddTextFieldFrameNode(frameNode, WeakClaim(this));
909     auto context = GetContext();
910     CHECK_NULL_VOID(context);
911     context->AddWindowSizeChangeCallback(frameId_);
912 }
913 
OnDetachFromFrameNode(FrameNode * node)914 void RichEditorPattern::OnDetachFromFrameNode(FrameNode* node)
915 {
916     TextPattern::OnDetachFromFrameNode(node);
917     ScrollablePattern::OnDetachFromFrameNode(node);
918     ClearOnFocusTextField();
919     auto context = GetContext();
920     CHECK_NULL_VOID(context);
921     context->RemoveWindowSizeChangeCallback(frameId_);
922 }
923 
AddPlaceholderSpan(const RefPtr<UINode> & customNode,const SpanOptionBase & options)924 int32_t RichEditorPattern::AddPlaceholderSpan(const RefPtr<UINode>& customNode, const SpanOptionBase& options)
925 {
926     auto host = GetHost();
927     CHECK_NULL_RETURN(host, 0);
928     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "AddPlaceholderSpan");
929     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "options=%{public}s", options.ToString().c_str());
930     auto placeholderSpanNode = PlaceholderSpanNode::GetOrCreateSpanNode(V2::PLACEHOLDER_SPAN_ETS_TAG,
931         ElementRegister::GetInstance()->MakeUniqueId(), []() { return AceType::MakeRefPtr<PlaceholderSpanPattern>(); });
932     CHECK_NULL_RETURN(placeholderSpanNode, 0);
933     customNode->MountToParent(placeholderSpanNode);
934     SetSelfAndChildDraggableFalse(customNode);
935     IF_PRESENT(oneStepDragController_, EnableOneStepDrag(TextSpanType::BUILDER, placeholderSpanNode));
936     auto focusHub = placeholderSpanNode->GetOrCreateFocusHub();
937     focusHub->SetFocusable(false);
938     int32_t insertIndex = options.offset.value_or(GetTextContentLength());
939     insertIndex = std::min(insertIndex, GetTextContentLength());
940     int32_t spanIndex = TextSpanSplit(insertIndex);
941     if (spanIndex == -1) {
942         spanIndex = static_cast<int32_t>(host->GetChildren().size());
943     }
944     builderNodes.push_back(WeakClaim(placeholderSpanNode.GetRawPtr()));
945     placeholderSpanNode->MountToParent(host, spanIndex);
946     auto renderContext = placeholderSpanNode->GetRenderContext();
947     if (renderContext) {
948         renderContext->SetNeedAnimateFlag(false);
949     }
950     auto spanItem = placeholderSpanNode->GetSpanItem();
951     spanItem->content = " ";
952     spanItem->spanItemType = SpanItemType::CustomSpan;
953     spanItem->SetCustomNode(customNode);
954     AddSpanItem(spanItem, spanIndex);
955     placeholderCount_++;
956     SetCaretPosition(insertIndex + spanItem->content.length());
957     ResetSelectionAfterAddSpan(false);
958     auto placeholderPipelineContext = placeholderSpanNode->GetContext();
959     if (placeholderPipelineContext) {
960         placeholderPipelineContext->SetDoKeyboardAvoidAnimate(false);
961     }
962     SetNeedMoveCaretToContentRect();
963     placeholderSpanNode->MarkModifyDone();
964     placeholderSpanNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
965     host->MarkModifyDone();
966     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
967     return spanIndex;
968 }
969 
SetSelfAndChildDraggableFalse(const RefPtr<UINode> & customNode)970 void RichEditorPattern::SetSelfAndChildDraggableFalse(const RefPtr<UINode>& customNode)
971 {
972     CHECK_NULL_VOID(customNode);
973     auto frameNode = DynamicCast<FrameNode>(customNode);
974     if (frameNode) {
975         auto gestureEventHub = frameNode->GetOrCreateGestureEventHub();
976         IF_PRESENT(gestureEventHub, SetDragForbiddenForcely(true));
977     }
978     for (const auto& child : customNode->GetChildren()) {
979         SetSelfAndChildDraggableFalse(child);
980     }
981 }
982 
AddTextSpan(TextSpanOptions options,bool isPaste,int32_t index)983 int32_t RichEditorPattern::AddTextSpan(TextSpanOptions options, bool isPaste, int32_t index)
984 {
985     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "options=%{private}s", options.ToString().c_str());
986     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "isPaste=%{public}d, index=%{public}d", isPaste, index);
987     NotifyExitTextPreview();
988     OperationRecord record;
989     auto textContentLength = GetTextContentLength();
990     if (options.offset) {
991         options.offset = std::clamp(options.offset.value(), 0, textContentLength);
992     }
993     record.beforeCaretPosition = std::clamp(options.offset.value_or(textContentLength), 0, textContentLength);
994     record.addText = options.value;
995     RichEditorChangeValue changeValue;
996     CHECK_NULL_RETURN(BeforeChangeText(changeValue, options), -1);
997     ClearRedoOperationRecords();
998     record.afterCaretPosition =
999         record.beforeCaretPosition + static_cast<int32_t>(StringUtils::ToWstring(options.value).length());
1000     AddOperationRecord(record);
1001     auto ret = AddTextSpanOperation(options, isPaste, index, false);
1002     SetNeedMoveCaretToContentRect();
1003     if (!previewTextRecord_.IsValid()) {
1004         AfterContentChange(changeValue);
1005     }
1006     return ret;
1007 }
1008 
AddTextSpanOperation(const TextSpanOptions & options,bool isPaste,int32_t index,bool needLeadingMargin,bool updateCaretPosition)1009 int32_t RichEditorPattern::AddTextSpanOperation(
1010     const TextSpanOptions& options, bool isPaste, int32_t index, bool needLeadingMargin, bool updateCaretPosition)
1011 {
1012     auto host = GetHost();
1013     CHECK_NULL_RETURN(host, -1);
1014 
1015     auto* stack = ViewStackProcessor::GetInstance();
1016     auto nodeId = stack->ClaimNodeId();
1017     auto spanNode = SpanNode::GetOrCreateSpanNode(nodeId);
1018 
1019     int32_t spanIndex = 0;
1020     int32_t offset = -1;
1021     if (options.offset.has_value()) {
1022         offset = TextSpanSplit(options.offset.value(), needLeadingMargin);
1023         if (offset == -1) {
1024             spanIndex = static_cast<int32_t>(host->GetChildren().size());
1025         } else {
1026             spanIndex = offset;
1027         }
1028         spanNode->MountToParent(host, offset);
1029     } else if (index != -1) {
1030         spanNode->MountToParent(host, index);
1031         spanIndex = index;
1032     } else {
1033         spanIndex = static_cast<int32_t>(host->GetChildren().size());
1034         spanNode->MountToParent(host);
1035     }
1036     UpdateSpanNode(spanNode, options);
1037     auto spanItem = spanNode->GetSpanItem();
1038     spanItem->content = options.value;
1039     spanItem->SetTextStyle(options.style);
1040     spanItem->useThemeFontColor = options.useThemeFontColor;
1041     spanItem->useThemeDecorationColor = options.useThemeDecorationColor;
1042     AddSpanItem(spanItem, offset);
1043     if (!options.style.has_value()) {
1044         SetDefaultColor(spanNode);
1045     }
1046     if (options.paraStyle) {
1047         UpdateParagraphStyle(spanNode, *options.paraStyle);
1048     }
1049     SetGestureOptions(options.userGestureOption, spanItem);
1050     if (updateCaretPosition && !previewTextRecord_.IsValid()) {
1051         if (options.offset.has_value()) {
1052             SetCaretPosition(options.offset.value() + StringUtils::ToWstring(options.value).length());
1053         } else {
1054             SetCaretPosition(GetTextContentLength());
1055         }
1056     }
1057     ResetSelectionAfterAddSpan(isPaste);
1058     SpanNodeFission(spanNode);
1059     return spanIndex;
1060 }
1061 
UpdateSpanNode(RefPtr<SpanNode> spanNode,const TextSpanOptions & options)1062 void RichEditorPattern::UpdateSpanNode(RefPtr<SpanNode> spanNode, const TextSpanOptions& options)
1063 {
1064     spanNode->UpdateContent(options.value);
1065     spanNode->AddPropertyInfo(PropertyInfo::NONE);
1066     CHECK_NULL_VOID(options.style.has_value());
1067 
1068     TextStyle textStyle = options.style.value();
1069     spanNode->UpdateTextColor(textStyle.GetTextColor());
1070     spanNode->AddPropertyInfo(PropertyInfo::FONTCOLOR);
1071     spanNode->UpdateFontSize(textStyle.GetFontSize());
1072     spanNode->AddPropertyInfo(PropertyInfo::FONTSIZE);
1073     spanNode->UpdateItalicFontStyle(textStyle.GetFontStyle());
1074     spanNode->AddPropertyInfo(PropertyInfo::FONTSTYLE);
1075     spanNode->UpdateFontWeight(textStyle.GetFontWeight());
1076     spanNode->AddPropertyInfo(PropertyInfo::FONTWEIGHT);
1077     spanNode->UpdateFontFamily(textStyle.GetFontFamilies());
1078     spanNode->AddPropertyInfo(PropertyInfo::FONTFAMILY);
1079     spanNode->UpdateTextDecoration(textStyle.GetTextDecoration());
1080     spanNode->AddPropertyInfo(PropertyInfo::TEXTDECORATION);
1081     spanNode->UpdateTextDecorationColor(textStyle.GetTextDecorationColor());
1082     spanNode->AddPropertyInfo(PropertyInfo::NONE);
1083     spanNode->UpdateTextDecorationStyle(textStyle.GetTextDecorationStyle());
1084     spanNode->AddPropertyInfo(PropertyInfo::NONE);
1085     spanNode->UpdateTextShadow(textStyle.GetTextShadows());
1086     spanNode->AddPropertyInfo(PropertyInfo::TEXTSHADOW);
1087     spanNode->UpdateLineHeight(textStyle.GetLineHeight());
1088     spanNode->AddPropertyInfo(PropertyInfo::LINEHEIGHT);
1089     spanNode->UpdateLetterSpacing(textStyle.GetLetterSpacing());
1090     spanNode->AddPropertyInfo(PropertyInfo::LETTERSPACE);
1091     spanNode->UpdateFontFeature(textStyle.GetFontFeatures());
1092     spanNode->AddPropertyInfo(PropertyInfo::FONTFEATURE);
1093 }
1094 
AddSymbolSpan(const SymbolSpanOptions & options,bool isPaste,int32_t index)1095 int32_t RichEditorPattern::AddSymbolSpan(const SymbolSpanOptions& options, bool isPaste, int32_t index)
1096 {
1097     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "options=%{public}s", options.ToString().c_str());
1098     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "isPaste=%{public}d, index=%{public}d", isPaste, index);
1099 
1100     RichEditorChangeValue changeValue;
1101     CHECK_NULL_RETURN(BeforeAddSymbol(changeValue, options), -1);
1102     OperationRecord record;
1103     record.beforeCaretPosition = options.offset.value_or(static_cast<int32_t>(GetTextContentLength()));
1104     record.addText = " ";
1105     ClearRedoOperationRecords();
1106     record.afterCaretPosition = record.beforeCaretPosition +
1107 	    static_cast<int32_t>(std::to_string(options.symbolId).length());
1108     AddOperationRecord(record);
1109     auto ret = AddSymbolSpanOperation(options, isPaste, index);
1110     SetNeedMoveCaretToContentRect();
1111     AfterContentChange(changeValue);
1112     return ret;
1113 }
1114 
AddSymbolSpanOperation(const SymbolSpanOptions & options,bool isPaste,int32_t index)1115 int32_t RichEditorPattern::AddSymbolSpanOperation(const SymbolSpanOptions& options, bool isPaste, int32_t index)
1116 {
1117     auto host = GetHost();
1118     CHECK_NULL_RETURN(host, -1);
1119 
1120     auto* stack = ViewStackProcessor::GetInstance();
1121     auto nodeId = stack->ClaimNodeId();
1122     auto spanNode = SpanNode::GetOrCreateSpanNode(V2::SYMBOL_SPAN_ETS_TAG, nodeId);
1123 
1124     int32_t insertIndex = options.offset.value_or(GetTextContentLength());
1125     insertIndex = std::min(insertIndex, GetTextContentLength());
1126     int32_t spanIndex = TextSpanSplit(insertIndex);
1127     if (spanIndex == -1) {
1128         spanIndex = static_cast<int32_t>(host->GetChildren().size());
1129     }
1130     spanNode->MountToParent(host, spanIndex);
1131     spanNode->UpdateContent(options.symbolId);
1132     spanNode->AddPropertyInfo(PropertyInfo::NONE);
1133     if (options.style.has_value()) {
1134         spanNode->UpdateFontSize(options.style.value().GetFontSize());
1135         spanNode->AddPropertyInfo(PropertyInfo::FONTSIZE);
1136         spanNode->UpdateFontWeight(options.style.value().GetFontWeight());
1137         spanNode->AddPropertyInfo(PropertyInfo::FONTWEIGHT);
1138         spanNode->UpdateSymbolColorList(options.style.value().GetSymbolColorList());
1139         spanNode->AddPropertyInfo(PropertyInfo::SYMBOL_COLOR);
1140         spanNode->UpdateSymbolRenderingStrategy(options.style.value().GetRenderStrategy());
1141         spanNode->AddPropertyInfo(PropertyInfo::SYMBOL_RENDERING_STRATEGY);
1142         spanNode->UpdateSymbolEffectStrategy(options.style.value().GetEffectStrategy());
1143         spanNode->AddPropertyInfo(PropertyInfo::SYMBOL_EFFECT_STRATEGY);
1144     }
1145     auto spanItem = spanNode->GetSpanItem();
1146     spanItem->content = "  ";
1147     spanItem->spanItemType = SpanItemType::SYMBOL;
1148     spanItem->SetSymbolId(options.symbolId);
1149     spanItem->SetTextStyle(options.style);
1150     spanItem->SetResourceObject(options.resourceObject);
1151     AddSpanItem(spanItem, spanIndex);
1152     SetCaretPosition(insertIndex + spanItem->content.length());
1153     ResetSelectionAfterAddSpan(false);
1154     SpanNodeFission(spanNode);
1155     return spanIndex;
1156 }
1157 
BeforeAddSymbol(RichEditorChangeValue & changeValue,const SymbolSpanOptions & options)1158 bool RichEditorPattern::BeforeAddSymbol(RichEditorChangeValue& changeValue, const SymbolSpanOptions& options)
1159 {
1160     auto eventHub = GetEventHub<RichEditorEventHub>();
1161     CHECK_NULL_RETURN(eventHub, false);
1162     CHECK_NULL_RETURN(eventHub->HasOnWillChange(), true);
1163 
1164     int32_t contentLength = GetTextContentLength();
1165     int32_t insertIndex = options.offset.value_or(contentLength);
1166     insertIndex = std::clamp(insertIndex, 0, contentLength);
1167 
1168     changeValue.SetRangeBefore({ insertIndex, insertIndex });
1169     changeValue.SetRangeAfter({ insertIndex, insertIndex + SYMBOL_SPAN_LENGTH });
1170     RichEditorAbstractSpanResult retInfo;
1171     TextInsertValueInfo info;
1172     CalcInsertValueObj(info, insertIndex, true);
1173     int32_t spanIndex = info.GetSpanIndex();
1174     retInfo.SetSpanIndex(spanIndex);
1175     retInfo.SetOffsetInSpan(0);
1176     retInfo.SetValue(std::to_string(options.symbolId));
1177     retInfo.SetEraseLength(SYMBOL_SPAN_LENGTH);
1178     retInfo.SetSpanRangeStart(insertIndex);
1179     retInfo.SetSpanRangeEnd(insertIndex + SYMBOL_SPAN_LENGTH);
1180     retInfo.SetSpanType(SpanResultType::SYMBOL);
1181 
1182     TextStyle style = options.style.value_or(TextStyle());
1183     retInfo.SetSymbolSpanStyle(SymbolSpanStyle(style));
1184     retInfo.SetValueResource(options.resourceObject);
1185 
1186     changeValue.SetRichEditorReplacedSymbolSpans(retInfo);
1187     auto ret = eventHub->FireOnWillChange(changeValue);
1188     return ret;
1189 }
1190 
AfterContentChange(RichEditorChangeValue & changeValue)1191 void RichEditorPattern::AfterContentChange(RichEditorChangeValue& changeValue)
1192 {
1193     auto eventHub = GetEventHub<RichEditorEventHub>();
1194     if (eventHub && eventHub->HasOnDidChange()) {
1195         eventHub->FireOnDidChange(changeValue);
1196     }
1197     ForceTriggerAvoidOnCaretChange();
1198 }
1199 
SpanNodeFission(RefPtr<SpanNode> & spanNode)1200 void RichEditorPattern::SpanNodeFission(RefPtr<SpanNode>& spanNode)
1201 {
1202     auto spanItem = spanNode->GetSpanItem();
1203     auto wContent = StringUtils::ToWstring(spanItem->content);
1204     auto spanStart = spanItem->position - static_cast<int32_t>(wContent.length());
1205     for (size_t i = 0; i < wContent.length(); i++) {
1206         if (wContent[i] == '\n') {
1207             TextSpanSplit(static_cast<int32_t>(spanStart + i + 1));
1208         }
1209     }
1210     UpdateSpanPosition();
1211 }
1212 
DeleteSpans(const RangeOptions & options)1213 void RichEditorPattern::DeleteSpans(const RangeOptions& options)
1214 {
1215     NotifyExitTextPreview();
1216     auto length = GetTextContentLength();
1217     int32_t start = options.start.value_or(0);
1218     int32_t end = options.end.value_or(length);
1219     if (start > end) {
1220         std::swap(start, end);
1221     }
1222     start = std::max(0, start);
1223     end = std::min(length, end);
1224     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "range=[%{public}d, %{public}d]", start, end);
1225     if (start > length || end < 0 || start == end) {
1226         return;
1227     }
1228     AdjustSelector(start, end);
1229     OperationRecord record;
1230     record.beforeCaretPosition = start;
1231     std::wstringstream wss;
1232     for (auto iter = spans_.cbegin(); iter != spans_.cend(); iter++) {
1233         wss << StringUtils::ToWstring((*iter)->content);
1234     }
1235     std::wstring deleteText = wss.str().substr(start, end - start);
1236     record.deleteText = StringUtils::ToString(deleteText);
1237     RichEditorChangeValue changeValue;
1238     CHECK_NULL_VOID(BeforeChangeText(changeValue, record, RecordType::DEL_FORWARD, deleteText.length()));
1239     ClearRedoOperationRecords();
1240     record.afterCaretPosition = start;
1241     AddOperationRecord(record);
1242     DeleteSpansOperation(start, end);
1243     AfterContentChange(changeValue);
1244 }
1245 
DeleteSpansOperation(int32_t start,int32_t end)1246 void RichEditorPattern::DeleteSpansOperation(int32_t start, int32_t end)
1247 {
1248     auto startInfo = GetSpanPositionInfo(start);
1249     auto endInfo = GetSpanPositionInfo(end - 1);
1250     if (startInfo.spanIndex_ == endInfo.spanIndex_) {
1251         DeleteSpanByRange(start, end, startInfo);
1252     } else {
1253         DeleteSpansByRange(start, end, startInfo, endInfo);
1254     }
1255     RemoveEmptySpanItems();
1256     if (textSelector_.IsValid()) {
1257         SetCaretPosition(textSelector_.GetTextStart());
1258         CloseSelectOverlay();
1259         ResetSelection();
1260     }
1261     SetCaretOffset(start);
1262     auto host = GetHost();
1263     CHECK_NULL_VOID(host);
1264     auto childrens = host->GetChildren();
1265     if (childrens.empty() || GetTextContentLength() == 0) {
1266         SetCaretPosition(0);
1267     }
1268     UpdateSpanPosition();
1269 }
1270 
RemoveEmptySpanItems()1271 void RichEditorPattern::RemoveEmptySpanItems()
1272 {
1273     for (auto it = spans_.begin(); it != spans_.end();) {
1274         if ((*it)->content.empty()) {
1275             it = spans_.erase(it);
1276         } else {
1277             ++it;
1278         }
1279     }
1280 }
1281 
RemoveEmptySpanNodes()1282 void RichEditorPattern::RemoveEmptySpanNodes()
1283 {
1284     auto host = GetHost();
1285     CHECK_NULL_VOID(host);
1286     auto& spanNodes = host->GetChildren();
1287     for (auto it = spanNodes.begin(); it != spanNodes.end();) {
1288         auto spanNode = AceType::DynamicCast<SpanNode>(*it);
1289         if (!spanNode) {
1290             ++it;
1291             continue;
1292         }
1293         if (spanNode->GetSpanItem()->content.empty()) {
1294             it = host->RemoveChild(spanNode);
1295         } else {
1296             ++it;
1297         }
1298     }
1299 }
1300 
RemoveEmptySpans()1301 void RichEditorPattern::RemoveEmptySpans()
1302 {
1303     RemoveEmptySpanItems();
1304     RemoveEmptySpanNodes();
1305 }
1306 
DeleteSpanByRange(int32_t start,int32_t end,SpanPositionInfo info)1307 void RichEditorPattern::DeleteSpanByRange(int32_t start, int32_t end, SpanPositionInfo info)
1308 {
1309     auto host = GetHost();
1310     CHECK_NULL_VOID(host);
1311     auto childrens = host->GetChildren();
1312     auto it = childrens.begin();
1313     std::advance(it, info.spanIndex_);
1314     CHECK_NULL_VOID(it != childrens.end());
1315     if (start == info.spanStart_ && end == info.spanEnd_) {
1316         ClearContent(*it);
1317         host->RemoveChild(*it);
1318     } else {
1319         auto spanNode = DynamicCast<SpanNode>(*it);
1320         CHECK_NULL_VOID(spanNode);
1321         auto spanItem = spanNode->GetSpanItem();
1322         auto beforStr = StringUtils::ToWstring(spanItem->content).substr(0, start - info.spanStart_);
1323         auto endStr = StringUtils::ToWstring(spanItem->content).substr(end - info.spanStart_);
1324         std::wstring result = beforStr + endStr;
1325         auto str = StringUtils::ToString(result);
1326         spanNode->UpdateContent(str);
1327     }
1328     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1329     host->MarkModifyDone();
1330 }
1331 
DeleteSpansByRange(int32_t start,int32_t end,SpanPositionInfo startInfo,SpanPositionInfo endInfo)1332 void RichEditorPattern::DeleteSpansByRange(
1333     int32_t start, int32_t end, SpanPositionInfo startInfo, SpanPositionInfo endInfo)
1334 {
1335     auto host = GetHost();
1336     CHECK_NULL_VOID(host);
1337     auto childrens = host->GetChildren();
1338     CHECK_NULL_VOID(!childrens.empty());
1339 
1340     auto itStart = childrens.begin();
1341     if (startInfo.spanIndex_ >= static_cast<int32_t>(childrens.size())) {
1342         std::advance(itStart, static_cast<int32_t>(childrens.size()) - 1);
1343         TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "startInfo.spanIndex_ is larger than childrens size");
1344     } else {
1345         std::advance(itStart, startInfo.spanIndex_);
1346     }
1347     CHECK_NULL_VOID(itStart != childrens.end());
1348     auto saveStartSpan = (start == startInfo.spanStart_) ? 0 : 1;
1349     if (saveStartSpan) {
1350         auto spanNodeStart = DynamicCast<SpanNode>(*itStart);
1351         CHECK_NULL_VOID(spanNodeStart);
1352         auto spanItemStart = spanNodeStart->GetSpanItem();
1353         auto beforStr = StringUtils::ToWstring(spanItemStart->content).substr(0, start - startInfo.spanStart_);
1354         auto strStart = StringUtils::ToString(beforStr);
1355         spanNodeStart->UpdateContent(strStart);
1356     }
1357     auto itEnd = childrens.begin();
1358     std::advance(itEnd, endInfo.spanIndex_);
1359     auto delEndSpan = (end == endInfo.spanEnd_) ? 1 : 0;
1360     if (!delEndSpan) {
1361         auto spanNodeEnd = DynamicCast<SpanNode>(*itEnd);
1362         CHECK_NULL_VOID(spanNodeEnd);
1363         auto spanItemEnd = spanNodeEnd->GetSpanItem();
1364         auto endStr =
1365             StringUtils::ToWstring(spanItemEnd->content).substr(end - endInfo.spanStart_, endInfo.spanEnd_ - end);
1366         auto strEnd = StringUtils::ToString(endStr);
1367         spanNodeEnd->UpdateContent(strEnd);
1368     }
1369     auto startIter = childrens.begin();
1370     std::advance(startIter, startInfo.spanIndex_ + saveStartSpan);
1371     auto endIter = childrens.begin();
1372     std::advance(endIter, endInfo.spanIndex_);
1373     for (auto iter = startIter; iter != endIter; ++iter) {
1374         ClearContent(*iter);
1375         host->RemoveChild(*iter);
1376     }
1377     if (endIter != childrens.end() && delEndSpan) {
1378         ClearContent(*endIter);
1379         host->RemoveChild(*endIter);
1380     }
1381     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1382     host->MarkModifyDone();
1383 }
1384 
GetLeftTextOfCursor(int32_t number)1385 std::u16string RichEditorPattern::GetLeftTextOfCursor(int32_t number)
1386 {
1387     if (number > caretPosition_) {
1388         number = caretPosition_;
1389     }
1390     auto start = caretPosition_;
1391     if (IsSelected()) {
1392         start = std::min(textSelector_.GetStart(), textSelector_.GetEnd());
1393     }
1394     auto stringText = GetSelectedText(start - number, start);
1395     return StringUtils::Str8ToStr16(stringText);
1396 }
1397 
GetRightTextOfCursor(int32_t number)1398 std::u16string RichEditorPattern::GetRightTextOfCursor(int32_t number)
1399 {
1400     auto end = caretPosition_;
1401     if (IsSelected()) {
1402         end = std::max(textSelector_.GetStart(), textSelector_.GetEnd());
1403     }
1404     auto stringText = GetSelectedText(end, end + number);
1405     return StringUtils::Str8ToStr16(stringText);
1406 }
1407 
GetTextIndexAtCursor()1408 int32_t RichEditorPattern::GetTextIndexAtCursor()
1409 {
1410     return caretPosition_;
1411 }
1412 
ClearContent(const RefPtr<UINode> & child)1413 void RichEditorPattern::ClearContent(const RefPtr<UINode>& child)
1414 {
1415     CHECK_NULL_VOID(child);
1416     if (child->GetTag() == V2::SPAN_ETS_TAG) {
1417         auto spanNode = DynamicCast<SpanNode>(child);
1418         if (spanNode) {
1419             spanNode->UpdateContent("");
1420             spanNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1421         }
1422         return;
1423     }
1424     auto imageSpanNode = DynamicCast<ImageSpanNode>(child);
1425     if (imageSpanNode) {
1426         imageSpanNode->GetSpanItem()->content.clear();
1427         imageSpanNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1428         return;
1429     }
1430     auto placeholderSpanNode = DynamicCast<PlaceholderSpanNode>(child);
1431     if (placeholderSpanNode) {
1432         placeholderSpanNode->GetSpanItem()->content.clear();
1433         placeholderSpanNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1434     }
1435 }
1436 
GetSpanPositionInfo(int32_t position)1437 SpanPositionInfo RichEditorPattern::GetSpanPositionInfo(int32_t position)
1438 {
1439     SpanPositionInfo spanPositionInfo(-1, -1, -1, -1);
1440     CHECK_NULL_RETURN(!spans_.empty(), spanPositionInfo);
1441     position = std::clamp(position, 0, GetTextContentLength());
1442     // find the spanItem where the position is
1443     auto it = std::find_if(spans_.begin(), spans_.end(), [position](const RefPtr<SpanItem>& spanItem) {
1444         return (spanItem->position - static_cast<int32_t>(StringUtils::ToWstring(spanItem->content).length()) <=
1445                    position) &&
1446                (position < spanItem->position);
1447     });
1448     if (it != spans_.end() && (*it)->unicode != 0 && (*it)->position - caretPosition_ + moveLength_ == 1) {
1449         it++;
1450         moveLength_++;
1451         position++;
1452     }
1453 
1454     // the position is at the end
1455     if (it == spans_.end()) {
1456         return spanPositionInfo;
1457     }
1458 
1459     spanPositionInfo.spanIndex_ = std::distance(spans_.begin(), it);
1460     auto contentLen = static_cast<int32_t>(StringUtils::ToWstring((*it)->content).length());
1461     spanPositionInfo.spanStart_ = (*it)->position - contentLen;
1462     spanPositionInfo.spanEnd_ = (*it)->position;
1463     spanPositionInfo.spanOffset_ = position - spanPositionInfo.spanStart_;
1464     return spanPositionInfo;
1465 }
1466 
CopyTextSpanStyle(RefPtr<SpanNode> & source,RefPtr<SpanNode> & target,bool needLeadingMargin)1467 void RichEditorPattern::CopyTextSpanStyle(RefPtr<SpanNode>& source, RefPtr<SpanNode>& target, bool needLeadingMargin)
1468 {
1469     CopyTextSpanFontStyle(source, target);
1470     CopyTextSpanLineStyle(source, target, needLeadingMargin);
1471 }
1472 
CopyTextSpanFontStyle(RefPtr<SpanNode> & source,RefPtr<SpanNode> & target)1473 void RichEditorPattern::CopyTextSpanFontStyle(RefPtr<SpanNode>& source, RefPtr<SpanNode>& target)
1474 {
1475     CHECK_NULL_VOID(source);
1476     CHECK_NULL_VOID(source->GetTag() == V2::SPAN_ETS_TAG);
1477     CHECK_NULL_VOID(target);
1478     COPY_SPAN_STYLE_IF_PRESENT(source, target, FontSize, PropertyInfo::FONTSIZE);
1479     COPY_SPAN_STYLE_IF_PRESENT(source, target, TextColor, PropertyInfo::FONTCOLOR);
1480     COPY_SPAN_STYLE_IF_PRESENT(source, target, ItalicFontStyle, PropertyInfo::FONTSTYLE);
1481     COPY_SPAN_STYLE_IF_PRESENT(source, target, FontWeight, PropertyInfo::FONTWEIGHT);
1482     COPY_SPAN_STYLE_IF_PRESENT(source, target, FontFamily, PropertyInfo::FONTFAMILY);
1483     COPY_SPAN_STYLE_IF_PRESENT(source, target, TextDecoration, PropertyInfo::TEXTDECORATION);
1484     COPY_SPAN_STYLE_IF_PRESENT(source, target, TextDecorationColor, PropertyInfo::NONE);
1485     COPY_SPAN_STYLE_IF_PRESENT(source, target, TextDecorationStyle, PropertyInfo::NONE);
1486     COPY_SPAN_STYLE_IF_PRESENT(source, target, TextCase, PropertyInfo::TEXTCASE);
1487     COPY_SPAN_STYLE_IF_PRESENT(source, target, LineHeight, PropertyInfo::LINEHEIGHT);
1488     COPY_SPAN_STYLE_IF_PRESENT(source, target, LetterSpacing, PropertyInfo::LETTERSPACE);
1489     COPY_SPAN_STYLE_IF_PRESENT(source, target, FontFeature, PropertyInfo::FONTFEATURE);
1490     COPY_SPAN_STYLE_IF_PRESENT(source, target, TextShadow, PropertyInfo::TEXTSHADOW);
1491     target->GetSpanItem()->useThemeFontColor = source->GetSpanItem()->useThemeFontColor;
1492     target->GetSpanItem()->useThemeDecorationColor = source->GetSpanItem()->useThemeDecorationColor;
1493 }
1494 
CopyTextSpanLineStyle(RefPtr<SpanNode> & source,RefPtr<SpanNode> & target,bool needLeadingMargin)1495 void RichEditorPattern::CopyTextSpanLineStyle(
1496     RefPtr<SpanNode>& source, RefPtr<SpanNode>& target, bool needLeadingMargin)
1497 {
1498     CHECK_NULL_VOID(source);
1499     CHECK_NULL_VOID(target);
1500     COPY_SPAN_STYLE_IF_PRESENT(source, target, TextAlign, PropertyInfo::TEXT_ALIGN);
1501     COPY_SPAN_STYLE_IF_PRESENT(source, target, WordBreak, PropertyInfo::WORD_BREAK);
1502     COPY_SPAN_STYLE_IF_PRESENT(source, target, LineBreakStrategy, PropertyInfo::LINE_BREAK_STRATEGY);
1503     needLeadingMargin |= previewTextRecord_.isPreviewTextInputting;
1504     if (source->HasLeadingMargin()) {
1505         auto leadingMargin = source->GetLeadingMarginValue({});
1506         if (!needLeadingMargin) {
1507             leadingMargin.pixmap.Reset();
1508         }
1509         target->UpdateLeadingMargin(leadingMargin);
1510         target->AddPropertyInfo(PropertyInfo::LEADING_MARGIN);
1511     }
1512 }
1513 
CopyGestureOption(const RefPtr<SpanNode> & source,RefPtr<SpanNode> & target)1514 void RichEditorPattern::CopyGestureOption(const RefPtr<SpanNode>& source, RefPtr<SpanNode>& target)
1515 {
1516     CHECK_NULL_VOID(source);
1517     CHECK_NULL_VOID(target);
1518     auto sourceItem = source->GetSpanItem();
1519     CHECK_NULL_VOID(sourceItem);
1520     auto targetItem = target->GetSpanItem();
1521     CHECK_NULL_VOID(targetItem);
1522 
1523     if (sourceItem->onClick) {
1524         auto tmpClickFunc = sourceItem->onClick;
1525         targetItem->SetOnClickEvent(std::move(tmpClickFunc));
1526     }
1527     if (sourceItem->onLongPress) {
1528         auto tmpLongPressFunc = sourceItem->onLongPress;
1529         targetItem->SetLongPressEvent(std::move(tmpLongPressFunc));
1530     }
1531     if (sourceItem->onDoubleClick) {
1532         auto tmpOnDoubleClick = sourceItem->onDoubleClick;
1533         targetItem->SetDoubleClickEvent(std::move(tmpOnDoubleClick));
1534     }
1535     if (sourceItem->onHover) {
1536         auto tmpHoverFunc = sourceItem->onHover;
1537         targetItem->SetHoverEvent(std::move(tmpHoverFunc));
1538     }
1539 }
1540 
TextSpanSplit(int32_t position,bool needLeadingMargin)1541 int32_t RichEditorPattern::TextSpanSplit(int32_t position, bool needLeadingMargin)
1542 {
1543     CHECK_NULL_RETURN(!spans_.empty(), -1);
1544 
1545     SpanPositionInfo positionInfo = GetSpanPositionInfo(position);
1546     int32_t spanIndex = positionInfo.spanIndex_;
1547     int32_t spanStart = positionInfo.spanStart_;
1548     int32_t spanEnd = positionInfo.spanEnd_;
1549     int32_t offsetInSpan = positionInfo.spanOffset_;
1550     TAG_LOGD(AceLogTag::ACE_RICH_TEXT,
1551         "position=%{public}d, spanIndex=%{public}d, spanRange=[%{public}d,%{public}d], offsetInSpan=%{public}d",
1552         position, spanIndex, spanStart, spanEnd, offsetInSpan);
1553 
1554     CHECK_NULL_RETURN((offsetInSpan > 0), spanIndex);
1555 
1556     auto host = GetHost();
1557     CHECK_NULL_RETURN(host, -1);
1558     auto spanNode = DynamicCast<SpanNode>(host->GetChildAtIndex(spanIndex));
1559     CHECK_NULL_RETURN(spanNode, -1);
1560 
1561     auto spanItem = spanNode->GetSpanItem();
1562     auto spanItemContent = StringUtils::ToWstring(spanItem->content);
1563     offsetInSpan = std::min(offsetInSpan, static_cast<int32_t>(spanItemContent.length()));
1564 
1565     auto firstContent = spanItemContent.substr(0, offsetInSpan);
1566     spanNode->UpdateContent(StringUtils::ToString(firstContent));
1567     spanItem->position = spanStart + offsetInSpan;
1568 
1569     auto nodeId = ViewStackProcessor::GetInstance()->ClaimNodeId();
1570     auto newSpanNode = SpanNode::GetOrCreateSpanNode(nodeId);
1571     CHECK_NULL_RETURN(newSpanNode, -1);
1572 
1573     CopyTextSpanStyle(spanNode, newSpanNode, needLeadingMargin);
1574     CopyGestureOption(spanNode, newSpanNode);
1575     auto secondContent = spanItemContent.substr(offsetInSpan);
1576     newSpanNode->UpdateContent(StringUtils::ToString(secondContent));
1577     newSpanNode->MountToParent(host, spanIndex + 1);
1578 
1579     auto newSpanItem = newSpanNode->GetSpanItem();
1580     newSpanItem->rangeStart = spanStart + offsetInSpan;
1581     newSpanItem->position = spanEnd;
1582 
1583     auto spanIter = spans_.begin();
1584     std::advance(spanIter, spanIndex + 1);
1585     spans_.insert(spanIter, newSpanItem);
1586 
1587     return spanIndex + 1;
1588 }
1589 
GetCaretPosition()1590 int32_t RichEditorPattern::GetCaretPosition()
1591 {
1592     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "GetCaretPosition");
1593     return caretPosition_;
1594 }
1595 
SetCaretOffset(int32_t caretPosition)1596 bool RichEditorPattern::SetCaretOffset(int32_t caretPosition)
1597 {
1598     if (IsPreviewTextInputting()) {
1599         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "intercept operation in previewText state");
1600         return false;
1601     }
1602     int32_t inputCaretPosition = caretPosition;
1603     AdjustSelector(caretPosition, HandleType::SECOND);
1604     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "in=%{public}d, afterAdjust=%{public}d", inputCaretPosition, caretPosition);
1605     bool success = SetCaretPosition(caretPosition);
1606     auto host = GetHost();
1607     CHECK_NULL_RETURN(host, false);
1608     auto focusHub = host->GetOrCreateFocusHub();
1609     CHECK_NULL_RETURN(focusHub, false);
1610     if (focusHub->IsCurrentFocus()) {
1611         isCursorAlwaysDisplayed_ = false;
1612         StartTwinkling();
1613     }
1614     CloseSelectOverlay();
1615     ResetSelection();
1616     return success;
1617 }
1618 
CalcCursorOffsetByPosition(int32_t position,float & selectLineHeight,bool downStreamFirst,bool needLineHighest)1619 OffsetF RichEditorPattern::CalcCursorOffsetByPosition(
1620     int32_t position, float& selectLineHeight, bool downStreamFirst, bool needLineHighest)
1621 {
1622     selectLineHeight = 0.0f;
1623     auto host = GetHost();
1624     CHECK_NULL_RETURN(host, OffsetF(0, 0));
1625     auto pipeline = host->GetContext();
1626     CHECK_NULL_RETURN(pipeline, OffsetF(0, 0));
1627     auto rootOffset = pipeline->GetRootRect().GetOffset();
1628     auto textPaintOffset = richTextRect_.GetOffset();
1629     needLineHighest |= IsCustomSpanInCaretPos(position, downStreamFirst);
1630     auto startOffset = paragraphs_.ComputeCursorOffset(position, selectLineHeight, downStreamFirst, needLineHighest);
1631     auto children = host->GetChildren();
1632     if (NearZero(selectLineHeight)) {
1633         if (children.empty() || GetTextContentLength() == 0) {
1634             return textPaintOffset - rootOffset;
1635         }
1636         if (std::all_of(children.begin(), children.end(), [](RefPtr<UINode>& node) {
1637                 CHECK_NULL_RETURN(node, false);
1638                 return (node->GetTag() == V2::IMAGE_ETS_TAG || node->GetTag() == V2::PLACEHOLDER_SPAN_ETS_TAG);
1639             })) {
1640             bool isTail = false;
1641             auto it = children.begin();
1642             if (position >= static_cast<int32_t>(children.size())) {
1643                 std::advance(it, (static_cast<int32_t>(children.size()) - 1));
1644                 isTail = true;
1645             } else {
1646                 std::advance(it, position);
1647             }
1648             if (it == children.end()) {
1649                 return startOffset;
1650             }
1651             auto imageNode = DynamicCast<FrameNode>(*it);
1652             if (imageNode) {
1653                 auto geometryNode = imageNode->GetGeometryNode();
1654                 CHECK_NULL_RETURN(geometryNode, OffsetF(0.0f, 0.0f));
1655                 startOffset = geometryNode->GetMarginFrameOffset();
1656                 selectLineHeight = geometryNode->GetMarginFrameSize().Height();
1657                 startOffset += isTail ? OffsetF(geometryNode->GetMarginFrameSize().Width(), 0.0f) : OffsetF(0.0f, 0.0f);
1658             }
1659             return startOffset;
1660         }
1661     }
1662     auto caretOffset = startOffset + textPaintOffset + rootOffset;
1663     CHECK_NULL_RETURN(overlayMod_, caretOffset);
1664     caretOffset.SetX(std::clamp(caretOffset.GetX(), 0.0f, richTextRect_.Right()));
1665     return caretOffset;
1666 }
1667 
IsCustomSpanInCaretPos(int32_t position,bool downStreamFirst)1668 bool RichEditorPattern::IsCustomSpanInCaretPos(int32_t position, bool downStreamFirst)
1669 {
1670     CHECK_NULL_RETURN((isSpanStringMode_ && styledString_), false);
1671     auto start = downStreamFirst ? position : position - 1;
1672     start = std::clamp(start, 0, GetTextContentLength());
1673     auto lastStyles = styledString_->GetSpans(start, 1);
1674     for (auto& style : lastStyles) {
1675         if (style && style->GetSpanType() == SpanType::CustomSpan) {
1676             return true;
1677         }
1678     }
1679     return false;
1680 }
1681 
SetCaretPositionWithAffinity(PositionWithAffinity positionWithAffinity)1682 void RichEditorPattern::SetCaretPositionWithAffinity(PositionWithAffinity positionWithAffinity)
1683 {
1684     auto currentPosition = static_cast<int32_t>(positionWithAffinity.position_);
1685     SetCaretPosition(currentPosition);
1686     caretAffinityPolicy_ = (positionWithAffinity.affinity_ == TextAffinity::UPSTREAM)
1687                                 ? CaretAffinityPolicy::UPSTREAM_FIRST
1688                                 : CaretAffinityPolicy::DOWNSTREAM_FIRST;
1689 }
1690 
SetCaretPosition(int32_t pos,bool needNotifyImf)1691 bool RichEditorPattern::SetCaretPosition(int32_t pos, bool needNotifyImf)
1692 {
1693     auto correctPos = std::clamp(pos, 0, GetTextContentLength());
1694     ResetLastClickOffset();
1695     caretAffinityPolicy_ = CaretAffinityPolicy::DEFAULT;
1696     CHECK_NULL_RETURN((pos == correctPos), false);
1697     if (caretPosition_ != correctPos) {
1698         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "caret:%{public}d->%{public}d", caretPosition_, correctPos);
1699         caretPosition_ = correctPos;
1700         FireOnSelectionChange(caretPosition_);
1701         if (caretChangeListener_) {
1702             caretChangeListener_(caretPosition_);
1703         }
1704     }
1705     if (needNotifyImf) {
1706         UpdateCaretInfoToController();
1707     }
1708     return true;
1709 }
1710 
RegisiterCaretChangeListener(std::function<void (int32_t)> && listener)1711 void RichEditorPattern::RegisiterCaretChangeListener(std::function<void(int32_t)>&& listener)
1712 {
1713     caretChangeListener_ = listener;
1714 }
1715 
FireOnSelectionChange(const int32_t caretPosition)1716 void RichEditorPattern::FireOnSelectionChange(const int32_t caretPosition)
1717 {
1718     if (!textSelector_.SelectNothing() || !caretTwinkling_) {
1719         return;
1720     }
1721     FireOnSelectionChange(caretPosition, caretPosition);
1722 }
1723 
FireOnSelectionChange(const TextSelector & selector)1724 void RichEditorPattern::FireOnSelectionChange(const TextSelector& selector)
1725 {
1726     if (selector.SelectNothing()) {
1727         return;
1728     }
1729     FireOnSelectionChange(selector.GetStart(), selector.GetEnd());
1730 }
1731 
FireOnSelectionChange(int32_t start,int32_t end,bool isForced)1732 void RichEditorPattern::FireOnSelectionChange(int32_t start, int32_t end, bool isForced)
1733 {
1734     auto host = GetHost();
1735     CHECK_NULL_VOID(host);
1736     auto eventHub = host->GetEventHub<RichEditorEventHub>();
1737     CHECK_NULL_VOID(eventHub);
1738     CHECK_NULL_VOID(isForced || HasFocus() || dataDetectorAdapter_->hasClickedMenuOption_);
1739     bool isSingleHandle = selectOverlay_->IsSingleHandle();
1740     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "range=[%{public}d,%{public}d],isTwinkling=%{public}d,isSingleHandle=%{public}d",
1741         start, end, caretTwinkling_, isSingleHandle);
1742     if (start < 0 || end < 0) {
1743         return;
1744     }
1745     if (start == end && !caretTwinkling_ && !isSingleHandle) {
1746         return;
1747     }
1748     if (start > end) {
1749         std::swap(start, end);
1750     }
1751     auto range = SelectionRangeInfo(start, end);
1752     if (range == lastSelectionRange_) {
1753         return;
1754     }
1755     lastSelectionRange_ = std::move(range);
1756     eventHub->FireOnSelectionChange(&range);
1757 }
1758 
GetCaretVisible() const1759 bool RichEditorPattern::GetCaretVisible() const
1760 {
1761     return caretVisible_;
1762 }
1763 
OnWindowHide()1764 void RichEditorPattern::OnWindowHide()
1765 {
1766     ScrollablePattern::OnWindowHide();
1767 }
1768 
SetUpdateSpanStyle(struct UpdateSpanStyle updateSpanStyle)1769 void RichEditorPattern::SetUpdateSpanStyle(struct UpdateSpanStyle updateSpanStyle)
1770 {
1771     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "SetUpdateSpanStyle");
1772     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "updateSpanStyle=%{public}s", updateSpanStyle.ToString().c_str());
1773     updateSpanStyle_ = updateSpanStyle;
1774 }
1775 
SetTypingStyle(std::optional<struct UpdateSpanStyle> typingStyle,std::optional<TextStyle> textStyle)1776 void RichEditorPattern::SetTypingStyle(std::optional<struct UpdateSpanStyle> typingStyle,
1777     std::optional<TextStyle> textStyle)
1778 {
1779     typingStyle_ = typingStyle;
1780     typingTextStyle_ = textStyle;
1781     presetParagraph_ = nullptr;
1782     if (spans_.empty() || !previewTextRecord_.previewContent.empty()) {
1783         auto host = GetHost();
1784         CHECK_NULL_VOID(host);
1785         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1786     }
1787 }
1788 
GetUpdateSpanStyle()1789 UpdateSpanStyle RichEditorPattern::GetUpdateSpanStyle()
1790 {
1791     return updateSpanStyle_;
1792 }
1793 
GetTypingStyle()1794 std::optional<struct UpdateSpanStyle> RichEditorPattern::GetTypingStyle()
1795 {
1796     return typingStyle_;
1797 }
1798 
UpdateFontFeatureTextStyle(RefPtr<SpanNode> & spanNode,struct UpdateSpanStyle & updateSpanStyle,TextStyle & textStyle)1799 void RichEditorPattern::UpdateFontFeatureTextStyle(
1800     RefPtr<SpanNode>& spanNode, struct UpdateSpanStyle& updateSpanStyle, TextStyle& textStyle)
1801 {
1802     if (updateSpanStyle.updateFontFeature.has_value()) {
1803         spanNode->UpdateFontFeature(textStyle.GetFontFeatures());
1804         spanNode->AddPropertyInfo(PropertyInfo::FONTFEATURE);
1805     }
1806 }
UpdateTextStyle(RefPtr<SpanNode> & spanNode,struct UpdateSpanStyle updateSpanStyle,TextStyle textStyle)1807 void RichEditorPattern::UpdateTextStyle(
1808     RefPtr<SpanNode>& spanNode, struct UpdateSpanStyle updateSpanStyle, TextStyle textStyle)
1809 {
1810     CHECK_NULL_VOID(spanNode->GetTag() == V2::SPAN_ETS_TAG);
1811     auto host = GetHost();
1812     CHECK_NULL_VOID(host);
1813     UpdateFontFeatureTextStyle(spanNode, updateSpanStyle, textStyle);
1814     if (updateSpanStyle.updateTextColor.has_value()) {
1815         spanNode->UpdateTextColor(textStyle.GetTextColor());
1816         spanNode->GetSpanItem()->useThemeFontColor = false;
1817         spanNode->AddPropertyInfo(PropertyInfo::FONTCOLOR);
1818     }
1819     if (updateSpanStyle.updateLineHeight.has_value()) {
1820         spanNode->UpdateLineHeight(textStyle.GetLineHeight());
1821         spanNode->AddPropertyInfo(PropertyInfo::LINEHEIGHT);
1822     }
1823     if (updateSpanStyle.updateLetterSpacing.has_value()) {
1824         spanNode->UpdateLetterSpacing(textStyle.GetLetterSpacing());
1825         spanNode->AddPropertyInfo(PropertyInfo::LETTERSPACE);
1826     }
1827     if (updateSpanStyle.updateFontSize.has_value()) {
1828         spanNode->UpdateFontSize(textStyle.GetFontSize());
1829         spanNode->AddPropertyInfo(PropertyInfo::FONTSIZE);
1830     }
1831     if (updateSpanStyle.updateItalicFontStyle.has_value()) {
1832         spanNode->UpdateItalicFontStyle(textStyle.GetFontStyle());
1833         spanNode->AddPropertyInfo(PropertyInfo::FONTSTYLE);
1834     }
1835     if (updateSpanStyle.updateFontWeight.has_value()) {
1836         spanNode->UpdateFontWeight(textStyle.GetFontWeight());
1837         spanNode->AddPropertyInfo(PropertyInfo::FONTWEIGHT);
1838     }
1839     if (updateSpanStyle.updateFontFamily.has_value()) {
1840         spanNode->UpdateFontFamily(textStyle.GetFontFamilies());
1841         spanNode->AddPropertyInfo(PropertyInfo::FONTFAMILY);
1842     }
1843     UpdateDecoration(spanNode, updateSpanStyle, textStyle);
1844     if (updateSpanStyle.updateTextShadows.has_value()) {
1845         spanNode->UpdateTextShadow(textStyle.GetTextShadows());
1846         spanNode->AddPropertyInfo(PropertyInfo::TEXTSHADOW);
1847     }
1848     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1849     host->MarkModifyDone();
1850 }
1851 
UpdateDecoration(RefPtr<SpanNode> & spanNode,struct UpdateSpanStyle & updateSpanStyle,TextStyle & textStyle)1852 void RichEditorPattern::UpdateDecoration(
1853     RefPtr<SpanNode>& spanNode, struct UpdateSpanStyle& updateSpanStyle, TextStyle& textStyle)
1854 {
1855     if (updateSpanStyle.updateTextDecoration.has_value()) {
1856         spanNode->UpdateTextDecoration(textStyle.GetTextDecoration());
1857         spanNode->GetSpanItem()->useThemeDecorationColor = false;
1858         spanNode->AddPropertyInfo(PropertyInfo::TEXTDECORATION);
1859     }
1860     if (updateSpanStyle.updateTextDecorationColor.has_value()) {
1861         spanNode->UpdateTextDecorationColor(textStyle.GetTextDecorationColor());
1862         spanNode->AddPropertyInfo(PropertyInfo::NONE);
1863     }
1864     if (updateSpanStyle.updateTextDecorationStyle.has_value()) {
1865         spanNode->UpdateTextDecorationStyle(textStyle.GetTextDecorationStyle());
1866         spanNode->AddPropertyInfo(PropertyInfo::NONE);
1867     }
1868 }
1869 
UpdateSymbolStyle(RefPtr<SpanNode> & spanNode,struct UpdateSpanStyle updateSpanStyle,TextStyle textStyle)1870 void RichEditorPattern::UpdateSymbolStyle(
1871     RefPtr<SpanNode>& spanNode, struct UpdateSpanStyle updateSpanStyle, TextStyle textStyle)
1872 {
1873     CHECK_NULL_VOID(spanNode->GetTag() == V2::SYMBOL_SPAN_ETS_TAG);
1874     auto host = GetHost();
1875     CHECK_NULL_VOID(host);
1876     if (updateSpanStyle.updateSymbolFontSize.has_value()) {
1877         spanNode->UpdateFontSize(updateSpanStyle.updateSymbolFontSize.value());
1878         spanNode->AddPropertyInfo(PropertyInfo::FONTSIZE);
1879     }
1880     if (updateSpanStyle.updateSymbolFontWeight.has_value()) {
1881         spanNode->UpdateFontWeight(updateSpanStyle.updateSymbolFontWeight.value());
1882         spanNode->AddPropertyInfo(PropertyInfo::FONTWEIGHT);
1883     }
1884     if (updateSpanStyle.updateSymbolColor.has_value()) {
1885         spanNode->UpdateSymbolColorList(updateSpanStyle.updateSymbolColor.value());
1886         spanNode->AddPropertyInfo(PropertyInfo::SYMBOL_COLOR);
1887     }
1888     if (updateSpanStyle.updateSymbolRenderingStrategy.has_value()) {
1889         spanNode->UpdateSymbolRenderingStrategy(updateSpanStyle.updateSymbolRenderingStrategy.value());
1890         spanNode->AddPropertyInfo(PropertyInfo::SYMBOL_RENDERING_STRATEGY);
1891     }
1892     if (updateSpanStyle.updateSymbolEffectStrategy.has_value()) {
1893         spanNode->UpdateSymbolEffectStrategy(updateSpanStyle.updateSymbolEffectStrategy.value());
1894         spanNode->AddPropertyInfo(PropertyInfo::SYMBOL_EFFECT_STRATEGY);
1895     }
1896     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1897     host->MarkModifyDone();
1898 }
1899 
HasSameTypingStyle(const RefPtr<SpanNode> & spanNode)1900 bool RichEditorPattern::HasSameTypingStyle(const RefPtr<SpanNode>& spanNode)
1901 {
1902     auto spanItem = spanNode->GetSpanItem();
1903     CHECK_NULL_RETURN(spanItem, false);
1904     auto spanTextstyle = spanItem->GetTextStyle();
1905     if (spanTextstyle.has_value() && typingTextStyle_.has_value()) {
1906         return spanTextstyle.value() == typingTextStyle_.value();
1907     } else {
1908         return !(spanTextstyle.has_value() || typingTextStyle_.has_value());
1909     }
1910 }
1911 
UpdateImageStyle(RefPtr<FrameNode> & imageNode,const ImageSpanAttribute & imageStyle)1912 void RichEditorPattern::UpdateImageStyle(RefPtr<FrameNode>& imageNode, const ImageSpanAttribute& imageStyle)
1913 {
1914     CHECK_NULL_VOID(imageNode);
1915     CHECK_NULL_VOID(imageNode->GetTag() == V2::IMAGE_ETS_TAG);
1916     auto host = GetHost();
1917     CHECK_NULL_VOID(host);
1918     auto imageLayoutProperty = imageNode->GetLayoutProperty<ImageLayoutProperty>();
1919     CHECK_NULL_VOID(imageLayoutProperty);
1920     if (updateSpanStyle_.updateImageWidth.has_value() || updateSpanStyle_.updateImageHeight.has_value()) {
1921         imageLayoutProperty->UpdateUserDefinedIdealSize(imageStyle.size->GetSize());
1922     }
1923     if (updateSpanStyle_.updateImageFit.has_value()) {
1924         imageLayoutProperty->UpdateImageFit(imageStyle.objectFit.value());
1925     }
1926     if (updateSpanStyle_.updateImageVerticalAlign.has_value()) {
1927         imageLayoutProperty->UpdateVerticalAlign(imageStyle.verticalAlign.value());
1928     }
1929     if (updateSpanStyle_.borderRadius.has_value()) {
1930         auto imageRenderCtx = imageNode->GetRenderContext();
1931         imageRenderCtx->UpdateBorderRadius(imageStyle.borderRadius.value());
1932         imageRenderCtx->SetClipToBounds(true);
1933     }
1934     if (updateSpanStyle_.marginProp.has_value()) {
1935         imageLayoutProperty->UpdateMargin(imageStyle.marginProp.value());
1936     }
1937     UpdateImageAttribute(imageNode, imageStyle);
1938     imageNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1939     imageNode->MarkModifyDone();
1940     IF_PRESENT(oneStepDragController_, MarkDirtyNode(WeakClaim((ImageSpanNode*) RawPtr(imageNode))));
1941     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1942     host->MarkModifyDone();
1943 }
1944 
UpdateImageAttribute(RefPtr<FrameNode> & imageNode,const ImageSpanAttribute & imageStyle)1945 void RichEditorPattern::UpdateImageAttribute(RefPtr<FrameNode>& imageNode, const ImageSpanAttribute& imageStyle)
1946 {
1947     CHECK_NULL_VOID(imageNode);
1948     auto node = DynamicCast<ImageSpanNode>(imageNode);
1949     CHECK_NULL_VOID(node);
1950     auto imageSpanItem = DynamicCast<ImageSpanItem>(node->GetSpanItem());
1951     CHECK_NULL_VOID(imageSpanItem);
1952     imageSpanItem->options.imageAttribute = imageStyle;
1953 }
1954 
SymbolSpanUpdateStyle(RefPtr<SpanNode> & spanNode,struct UpdateSpanStyle updateSpanStyle,TextStyle textStyle)1955 bool RichEditorPattern::SymbolSpanUpdateStyle(
1956     RefPtr<SpanNode>& spanNode, struct UpdateSpanStyle updateSpanStyle, TextStyle textStyle)
1957 {
1958     if (spanNode->GetTag() == V2::SYMBOL_SPAN_ETS_TAG) {
1959         UpdateSymbolStyle(spanNode, updateSpanStyle_, textStyle);
1960         return true;
1961     }
1962     return false;
1963 }
1964 
UpdateSpanStyle(int32_t start,int32_t end,const TextStyle & textStyle,const ImageSpanAttribute & imageStyle)1965 void RichEditorPattern::UpdateSpanStyle(
1966     int32_t start, int32_t end, const TextStyle& textStyle, const ImageSpanAttribute& imageStyle)
1967 {
1968     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "range=[%{public}d,%{public}d]", start, end);
1969     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "textStyle=%{public}s, imageStyle=%{public}s",
1970         textStyle.ToString().c_str(), imageStyle.ToString().c_str());
1971     auto host = GetHost();
1972     CHECK_NULL_VOID(host);
1973     AdjustSelector(start, end);
1974     int32_t spanStart = 0;
1975     int32_t spanEnd = 0;
1976     for (auto it = host->GetChildren().begin(); it != host->GetChildren().end(); ++it) {
1977         auto spanNode = DynamicCast<SpanNode>(*it);
1978         auto imageNode = DynamicCast<FrameNode>(*it);
1979         if (!spanNode) {
1980             if (spanEnd != 0) {
1981                 spanStart = spanEnd;
1982             }
1983             spanEnd = spanStart + 1;
1984         } else {
1985             spanNode->GetSpanItem()->GetIndex(spanStart, spanEnd);
1986         }
1987         if (spanEnd < start) {
1988             continue;
1989         }
1990 
1991         if (spanStart >= start && spanEnd <= end) {
1992             if (spanNode) {
1993                 UpdateSymbolStyle(spanNode, updateSpanStyle_, textStyle);
1994                 UpdateTextStyle(spanNode, updateSpanStyle_, textStyle);
1995             } else {
1996                 UpdateImageStyle(imageNode, imageStyle);
1997             }
1998             if (spanEnd == end) {
1999                 break;
2000             }
2001         } else if ((spanStart < start && start < spanEnd) || (spanStart < end && end < spanEnd)) {
2002             if (SymbolSpanUpdateStyle(spanNode, updateSpanStyle_, textStyle)) {
2003                 continue;
2004             }
2005             auto index = spanStart < start && start < spanEnd ? start : end;
2006             TextSpanSplit(index, true);
2007             --it;
2008         } else if (spanStart >= end) {
2009             break;
2010         }
2011     }
2012 }
2013 
SetResultObjectText(ResultObject & resultObject,const RefPtr<SpanItem> & spanItem)2014 void RichEditorPattern::SetResultObjectText(ResultObject& resultObject, const RefPtr<SpanItem>& spanItem)
2015 {
2016     CHECK_NULL_VOID(spanItem);
2017     resultObject.valueString = spanItem->content;
2018     if (spanItem->rangeStart <= previewTextRecord_.startOffset && spanItem->position >= previewTextRecord_.endOffset) {
2019         resultObject.previewText = previewTextRecord_.previewContent;
2020     }
2021 }
2022 
GetContentBySpans()2023 std::string RichEditorPattern::GetContentBySpans()
2024 {
2025     std::stringstream ss;
2026     for (auto iter = spans_.cbegin(); iter != spans_.cend(); iter++) {
2027         ss << (*iter)->content;
2028     }
2029     auto textContent = ss.str();
2030     return textContent;
2031 }
2032 
TextEmojiSplit(int32_t & start,int32_t end,std::string & content)2033 ResultObject RichEditorPattern::TextEmojiSplit(int32_t& start, int32_t end, std::string& content)
2034 {
2035     ResultObject resultObject;
2036     int32_t emojiStartIndex = 0;
2037     int32_t emojiEndIndex = 0;
2038     int32_t emojiLength = 0;
2039     bool isEmoji = false;
2040     int32_t initStart = start;
2041     for (auto index = start; index <= end; index++) {
2042         emojiStartIndex = 0;
2043         emojiEndIndex = 0;
2044         EmojiRelation indexRelationEmoji =
2045             TextEmojiProcessor::GetIndexRelationToEmoji(index - start, content, emojiStartIndex, emojiEndIndex);
2046         // caret position after emoji
2047         if (indexRelationEmoji == EmojiRelation::AFTER_EMOJI || indexRelationEmoji == EmojiRelation::MIDDLE_EMOJI) {
2048             resultObject.spanPosition.spanRange[RichEditorSpanRange::RANGESTART] = start;
2049             auto allTextContent = GetContentBySpans();
2050             std::u16string u16Content = StringUtils::Str8ToStr16(allTextContent);
2051             auto caretPos = std::clamp(index, 0, static_cast<int32_t>(u16Content.length()));
2052             emojiLength = TextEmojiProcessor::Delete(caretPos, 1, allTextContent, true);
2053             resultObject.spanPosition.spanRange[RichEditorSpanRange::RANGEEND] = index - emojiLength;
2054             resultObject.type = SelectSpanType::TYPESPAN;
2055             start = index;
2056             isEmoji = true;
2057             break;
2058         }
2059     }
2060 
2061     if (!isEmoji) {
2062         resultObject.spanPosition.spanRange[RichEditorSpanRange::RANGESTART] = start;
2063         resultObject.spanPosition.spanRange[RichEditorSpanRange::RANGEEND] = end;
2064         resultObject.type = SelectSpanType::TYPESPAN;
2065         start = end;
2066         return resultObject;
2067     }
2068     std::u16string u16Content = StringUtils::Str8ToStr16(content);
2069     CHECK_NULL_RETURN(!(end - start < 0), resultObject);
2070     std::u16string temp = u16Content.substr(start - initStart, end - start);
2071     content = StringUtils::Str16ToStr8(temp);
2072     return resultObject;
2073 }
2074 
GetEmojisBySelect(int32_t start,int32_t end)2075 SelectionInfo RichEditorPattern::GetEmojisBySelect(int32_t start, int32_t end)
2076 {
2077     SelectionInfo selection;
2078     std::list<ResultObject> resultObjects;
2079     CHECK_NULL_RETURN(textSelector_.IsValid(), selection);
2080 
2081     // get all content
2082     auto selectTextContent = GetContentBySpans();
2083     CHECK_NULL_RETURN(!selectTextContent.empty(), selection);
2084     std::u16string u16Content = StringUtils::Str8ToStr16(selectTextContent);
2085     // get select content
2086     std::u16string selectData16 = u16Content.substr(static_cast<int32_t>(start), static_cast<int32_t>(end - start));
2087     std::string selectData = StringUtils::Str16ToStr8(selectData16);
2088     // set SelectionInfo start position and end position
2089     selection.SetSelectionStart(start);
2090     selection.SetSelectionEnd(end);
2091     while (start != end) {
2092         ResultObject resultObject = TextEmojiSplit(start, end, selectData);
2093         resultObjects.emplace_back(resultObject);
2094     }
2095     selection.SetResultObjectList(resultObjects);
2096     return selection;
2097 }
2098 
MixTextEmojiUpdateStyle(int32_t start,int32_t end,TextStyle textStyle,ImageSpanAttribute imageStyle)2099 void RichEditorPattern::MixTextEmojiUpdateStyle(
2100     int32_t start, int32_t end, TextStyle textStyle, ImageSpanAttribute imageStyle)
2101 {
2102     SelectionInfo textSelectInfo = GetEmojisBySelect(start, end);
2103     std::list<ResultObject> textResultObjects = textSelectInfo.GetSelection().resultObjects;
2104     for (const auto& textIter : textResultObjects) {
2105         int32_t newStart = textIter.spanPosition.spanRange[RichEditorSpanRange::RANGESTART];
2106         int32_t newEnd = textIter.spanPosition.spanRange[RichEditorSpanRange::RANGEEND];
2107         if (newStart == newEnd) {
2108             continue;
2109         }
2110         UpdateSpanStyle(newStart, newEnd, textStyle, imageStyle);
2111     }
2112 }
2113 
SetSelectSpanStyle(int32_t start,int32_t end,KeyCode code,bool isStart)2114 void RichEditorPattern::SetSelectSpanStyle(int32_t start, int32_t end, KeyCode code, bool isStart)
2115 {
2116     TextStyle spanStyle;
2117     struct UpdateSpanStyle updateSpanStyle;
2118     ImageSpanAttribute imageStyle;
2119 
2120     auto it = std::find_if(spans_.begin(), spans_.end(), [start](const RefPtr<SpanItem>& spanItem) {
2121         return (spanItem->rangeStart <= start) && (start < spanItem->position);
2122     });
2123     if (it == spans_.end()) {
2124         return;
2125     }
2126     std::optional<TextStyle> spanTextStyle = (*it)->GetTextStyle();
2127     if (spanTextStyle.has_value()) {
2128         spanStyle = spanTextStyle.value();
2129     }
2130     HandleSelectFontStyleWrapper(code, spanStyle);
2131     updateSpanStyle.updateTextColor = spanStyle.GetTextColor();
2132     updateSpanStyle.updateFontSize = spanStyle.GetFontSize();
2133     updateSpanStyle.updateItalicFontStyle = spanStyle.GetFontStyle();
2134     updateSpanStyle.updateFontWeight = spanStyle.GetFontWeight();
2135     updateSpanStyle.updateFontFamily = spanStyle.GetFontFamilies();
2136     updateSpanStyle.updateTextDecoration = spanStyle.GetTextDecoration();
2137     if (!isStart) {
2138         auto updateSpanStyle_ = GetUpdateSpanStyle();
2139         switch (code) {
2140             case KeyCode::KEY_B:
2141                 updateSpanStyle.updateFontWeight = updateSpanStyle_.updateFontWeight;
2142                 spanStyle.SetFontWeight(updateSpanStyle_.updateFontWeight.value());
2143                 break;
2144             case KeyCode::KEY_I:
2145                 updateSpanStyle.updateItalicFontStyle = updateSpanStyle_.updateItalicFontStyle;
2146                 spanStyle.SetFontStyle(updateSpanStyle_.updateItalicFontStyle.value());
2147                 break;
2148             case KeyCode::KEY_U:
2149                 updateSpanStyle.updateTextDecoration = updateSpanStyle_.updateTextDecoration;
2150                 spanStyle.SetTextDecoration(updateSpanStyle_.updateTextDecoration.value());
2151                 break;
2152             default:
2153                 LOGW("Unsupported select operation for HandleSelectFontStyleWrapper");
2154                 return;
2155         }
2156     }
2157     SetUpdateSpanStyle(updateSpanStyle);
2158     MixTextEmojiUpdateStyle(start, end, spanStyle, imageStyle);
2159 }
2160 
GetSelectSpansPositionInfo(int32_t & start,int32_t & end,SpanPositionInfo & startPositionSpanInfo,SpanPositionInfo & endPositionSpanInfo)2161 void RichEditorPattern::GetSelectSpansPositionInfo(
2162     int32_t& start, int32_t& end, SpanPositionInfo& startPositionSpanInfo, SpanPositionInfo& endPositionSpanInfo)
2163 {
2164     bool isText = false;
2165     auto host = GetHost();
2166     CHECK_NULL_VOID(host);
2167     std::find_if(spans_.begin(), spans_.end(), [&start, &end, &isText](const RefPtr<SpanItem>& spanItem) {
2168         if ((spanItem->rangeStart <= start) && (start < spanItem->position) && start < end) {
2169             if (spanItem->spanItemType == NG::SpanItemType::NORMAL && spanItem->unicode == 0) {
2170                 isText = true;
2171                 return true;
2172             }
2173             start += StringUtils::ToWstring(spanItem->content).length();
2174         }
2175         return false;
2176     });
2177     CHECK_EQUAL_VOID(isText, false);
2178     std::find_if(spans_.rbegin(), spans_.rend(), [&end](const RefPtr<SpanItem>& spanItem) {
2179         if ((spanItem->rangeStart < end) && (end <= spanItem->position)) {
2180             if (spanItem->spanItemType == NG::SpanItemType::NORMAL && spanItem->unicode == 0) {
2181                 return true;
2182             }
2183             end = spanItem->rangeStart;
2184         }
2185         return false;
2186     });
2187     startPositionSpanInfo = GetSpanPositionInfo(start);
2188     startPositionSpanInfo.spanIndex_ =
2189         std::clamp(startPositionSpanInfo.spanIndex_, 0, static_cast<int32_t>(host->GetChildren().size()) - 1);
2190     if (end == GetTextContentLength()) {
2191         endPositionSpanInfo.spanIndex_ = spans_.size() - 1;
2192         auto spanIter = spans_.begin();
2193         endPositionSpanInfo.spanIndex_ =
2194             std::clamp(endPositionSpanInfo.spanIndex_, 0, static_cast<int32_t>(host->GetChildren().size()) - 1);
2195         std::advance(spanIter, endPositionSpanInfo.spanIndex_);
2196         auto contentLen = StringUtils::ToWstring((*spanIter)->content).length();
2197         endPositionSpanInfo.spanStart_ = (*spanIter)->position - contentLen;
2198         endPositionSpanInfo.spanEnd_ = (*spanIter)->position;
2199         endPositionSpanInfo.spanOffset_ = contentLen;
2200     } else {
2201         endPositionSpanInfo = GetSpanPositionInfo(end);
2202     }
2203     if (endPositionSpanInfo.spanIndex_ == -1) {
2204         endPositionSpanInfo = startPositionSpanInfo;
2205     }
2206 }
2207 
GetSpanNodeIter(int32_t index)2208 std::list<RefPtr<UINode>>::const_iterator RichEditorPattern::GetSpanNodeIter(int32_t index)
2209 {
2210     auto host = GetHost();
2211     CHECK_NULL_RETURN(host, {});
2212     auto spanNodeIter = host->GetChildren().begin();
2213     std::advance(spanNodeIter, index);
2214     return spanNodeIter;
2215 }
2216 
GetSelectSpanSplit(SpanPositionInfo & startPositionSpanInfo,SpanPositionInfo & endPositionSpanInfo)2217 std::list<SpanPosition> RichEditorPattern::GetSelectSpanSplit(
2218     SpanPositionInfo& startPositionSpanInfo, SpanPositionInfo& endPositionSpanInfo)
2219 {
2220     std::list<SpanPosition> resultObjects;
2221     int32_t spanIndex = 0;
2222     auto itStart = GetSpanNodeIter(startPositionSpanInfo.spanIndex_);
2223     auto itEnd = GetSpanNodeIter(endPositionSpanInfo.spanIndex_);
2224     auto itEndNext = GetSpanNodeIter(endPositionSpanInfo.spanIndex_ + 1);
2225     for (auto itSelect = itStart; itSelect != itEndNext; itSelect++) {
2226         SpanPosition resultObject;
2227         auto spanNode = DynamicCast<SpanNode>(*itSelect);
2228         if (!spanNode || spanNode->GetTag() != V2::SPAN_ETS_TAG) {
2229             continue;
2230         }
2231         auto spanItem = spanNode->GetSpanItem();
2232         if (itSelect == itStart) {
2233             if (startPositionSpanInfo.spanOffset_ == 0) {
2234                 resultObject.spanRange[RichEditorSpanRange::RANGESTART] = startPositionSpanInfo.spanStart_;
2235             } else {
2236                 resultObject.spanRange[RichEditorSpanRange::RANGESTART] =
2237                     startPositionSpanInfo.spanStart_ + startPositionSpanInfo.spanOffset_;
2238             }
2239             resultObject.spanRange[RichEditorSpanRange::RANGEEND] = startPositionSpanInfo.spanEnd_;
2240             resultObject.spanIndex = spanIndex;
2241             spanIndex++;
2242             resultObjects.emplace_back(resultObject);
2243             continue;
2244         }
2245         if (itSelect == itEnd) {
2246             resultObject.spanRange[RichEditorSpanRange::RANGESTART] = endPositionSpanInfo.spanStart_;
2247             if (endPositionSpanInfo.spanOffset_ == static_cast<int32_t>(spanItem->content.size())) {
2248                 resultObject.spanRange[RichEditorSpanRange::RANGEEND] = endPositionSpanInfo.spanEnd_;
2249             } else {
2250                 resultObject.spanRange[RichEditorSpanRange::RANGEEND] =
2251                     endPositionSpanInfo.spanStart_ + endPositionSpanInfo.spanOffset_;
2252             }
2253             resultObject.spanIndex = spanIndex;
2254             spanIndex++;
2255             resultObjects.emplace_back(resultObject);
2256             continue;
2257         }
2258         resultObject.spanRange[RichEditorSpanRange::RANGESTART] =
2259             spanItem->position - StringUtils::ToWstring(spanItem->content).length();
2260         resultObject.spanRange[RichEditorSpanRange::RANGEEND] = spanItem->position;
2261         resultObject.spanIndex = spanIndex;
2262         spanIndex++;
2263         resultObjects.emplace_back(resultObject);
2264     }
2265     return resultObjects;
2266 }
2267 
GetSelectSpanInfo(int32_t start,int32_t end)2268 std::list<SpanPosition> RichEditorPattern::GetSelectSpanInfo(int32_t start, int32_t end)
2269 {
2270     SpanPositionInfo startPositionSpanInfo(-1, -1, -1, -1);
2271     SpanPositionInfo endPositionSpanInfo(-1, -1, -1, -1);
2272     std::list<SpanPosition> resultObjects;
2273     int32_t spanIndex = 0;
2274     GetSelectSpansPositionInfo(start, end, startPositionSpanInfo, endPositionSpanInfo);
2275     CHECK_EQUAL_RETURN(startPositionSpanInfo.spanStart_, -1, resultObjects);
2276     if (startPositionSpanInfo.spanIndex_ == endPositionSpanInfo.spanIndex_) {
2277         SpanPosition resultObject;
2278         resultObject.spanRange[RichEditorSpanRange::RANGESTART] = start;
2279         resultObject.spanRange[RichEditorSpanRange::RANGEEND] = end;
2280         resultObject.spanIndex = spanIndex;
2281         resultObjects.emplace_back(resultObject);
2282     } else {
2283         resultObjects = GetSelectSpanSplit(startPositionSpanInfo, endPositionSpanInfo);
2284     }
2285     return resultObjects;
2286 }
2287 
IsTextSpanFromResult(int32_t & start,int32_t & end,KeyCode code)2288 bool RichEditorPattern::IsTextSpanFromResult(int32_t& start, int32_t& end, KeyCode code)
2289 {
2290     SelectionInfo textSelectInfo = GetEmojisBySelect(start, end);
2291     std::list<ResultObject> textResultObjects = textSelectInfo.GetSelection().resultObjects;
2292     for (const auto& textIter : textResultObjects) {
2293         if (textIter.spanPosition.spanRange[RichEditorSpanRange::RANGESTART] !=
2294             textIter.spanPosition.spanRange[RichEditorSpanRange::RANGEEND]) {
2295             start = textIter.spanPosition.spanRange[RichEditorSpanRange::RANGESTART];
2296             SetSelectSpanStyle(start, end, code, true);
2297             return true;
2298         }
2299     }
2300     return false;
2301 }
2302 
UpdateSelectSpanStyle(int32_t start,int32_t end,KeyCode code)2303 void RichEditorPattern::UpdateSelectSpanStyle(int32_t start, int32_t end, KeyCode code)
2304 {
2305     bool isFirstText = false;
2306     std::list<SpanPosition> resultObjects;
2307     resultObjects = GetSelectSpanInfo(start, end);
2308     for (auto& spanStyleIter : resultObjects) {
2309         if (!isFirstText) {
2310             isFirstText = IsTextSpanFromResult(spanStyleIter.spanRange[RichEditorSpanRange::RANGESTART],
2311                 spanStyleIter.spanRange[RichEditorSpanRange::RANGEEND], code);
2312             continue;
2313         }
2314         SetSelectSpanStyle(spanStyleIter.spanRange[RichEditorSpanRange::RANGESTART],
2315             spanStyleIter.spanRange[RichEditorSpanRange::RANGEEND], code, false);
2316     }
2317 }
2318 
CloseSystemMenu()2319 void RichEditorPattern::CloseSystemMenu()
2320 {
2321     if (!SelectOverlayIsOn()) {
2322         return;
2323     }
2324     auto selectOverlayInfo = selectOverlay_->GetSelectOverlayInfo();
2325     if (selectOverlayInfo && !selectOverlayInfo->menuInfo.menuBuilder) {
2326         CloseSelectOverlay();
2327     }
2328 }
2329 
SetAccessibilityAction()2330 void RichEditorPattern::SetAccessibilityAction()
2331 {
2332     auto host = GetHost();
2333     CHECK_NULL_VOID(host);
2334     auto property = host->GetAccessibilityProperty<AccessibilityProperty>();
2335     CHECK_NULL_VOID(property);
2336     property->SetActionSetSelection([weakPtr = WeakClaim(this)](int32_t start, int32_t end, bool isForward) {
2337         TAG_LOGI(AceLogTag::ACE_RICH_TEXT,
2338             "Accessibility SetSelection, range=[%{public}d,%{public}d], isForward=%{public}d", start, end, isForward);
2339         const auto& pattern = weakPtr.Upgrade();
2340         CHECK_NULL_VOID(pattern);
2341         pattern->SetSelection(start, end, std::nullopt, isForward);
2342     });
2343 
2344     property->SetActionSetIndex([weakPtr = WeakClaim(this)](int32_t index) {
2345         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "Accessibility SetCaretOffset, index=%{public}d", index);
2346         const auto& pattern = weakPtr.Upgrade();
2347         CHECK_NULL_VOID(pattern);
2348         pattern->SetCaretOffset(index);
2349     });
2350 
2351     property->SetActionGetIndex([weakPtr = WeakClaim(this)]() -> int32_t {
2352         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "Accessibility GetCaretPosition");
2353         const auto& pattern = weakPtr.Upgrade();
2354         CHECK_NULL_RETURN(pattern, -1);
2355         return pattern->GetCaretPosition();
2356     });
2357     SetAccessibilityEditAction();
2358 }
2359 
SetAccessibilityEditAction()2360 void RichEditorPattern::SetAccessibilityEditAction()
2361 {
2362     auto host = GetHost();
2363     CHECK_NULL_VOID(host);
2364     auto property = host->GetAccessibilityProperty<AccessibilityProperty>();
2365     CHECK_NULL_VOID(property);
2366     property->SetActionSetText([weakPtr = WeakClaim(this)](const std::string& value) {
2367         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "EditAction setText, length: %{public}d",
2368             static_cast<int32_t>(StringUtils::ToWstring(value).length()));
2369         const auto& pattern = weakPtr.Upgrade();
2370         CHECK_NULL_VOID(pattern);
2371         pattern->InsertValue(value);
2372     });
2373 
2374     property->SetActionCopy([weakPtr = WeakClaim(this)]() {
2375         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "EditAction copy");
2376         const auto& pattern = weakPtr.Upgrade();
2377         CHECK_NULL_VOID(pattern);
2378         pattern->HandleOnCopy();
2379         pattern->CloseSelectionMenu();
2380     });
2381 
2382     property->SetActionCut([weakPtr = WeakClaim(this)]() {
2383         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "EditAction cut");
2384         const auto& pattern = weakPtr.Upgrade();
2385         CHECK_NULL_VOID(pattern);
2386         pattern->HandleOnCut();
2387     });
2388 
2389     property->SetActionPaste([weakPtr = WeakClaim(this)]() {
2390         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "EditAction paste");
2391         const auto& pattern = weakPtr.Upgrade();
2392         CHECK_NULL_VOID(pattern);
2393         pattern->HandleOnPaste();
2394         pattern->CloseSelectionMenu();
2395     });
2396 
2397     property->SetActionClearSelection([weakPtr = WeakClaim(this)]() {
2398         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "EditAction clearSelection");
2399         const auto& pattern = weakPtr.Upgrade();
2400         CHECK_NULL_VOID(pattern);
2401         pattern->CloseSelectionMenu();
2402         pattern->ResetSelection();
2403         pattern->StartTwinkling();
2404     });
2405 }
2406 
GetParagraphInfo(int32_t start,int32_t end)2407 std::vector<ParagraphInfo> RichEditorPattern::GetParagraphInfo(int32_t start, int32_t end)
2408 {
2409     std::vector<ParagraphInfo> res;
2410     auto spanNodes = GetParagraphNodes(start, end);
2411     CHECK_NULL_RETURN(!spanNodes.empty(), {});
2412 
2413     auto&& firstSpan = spanNodes.front()->GetSpanItem();
2414     auto paraStart = firstSpan->position - static_cast<int32_t>(StringUtils::ToWstring(firstSpan->content).length());
2415 
2416     for (auto it = spanNodes.begin(); it != spanNodes.end(); ++it) {
2417         if (it == std::prev(spanNodes.end()) || StringUtils::ToWstring((*it)->GetSpanItem()->content).back() == L'\n') {
2418             ParagraphInfo info;
2419             auto lm = (*it)->GetLeadingMarginValue({});
2420 
2421             res.emplace_back(ParagraphInfo {
2422                 .leadingMarginPixmap = lm.pixmap,
2423                 .leadingMarginSize = { lm.size.Width().ToString(),
2424                     lm.size.Height().ToString() },
2425                 .textAlign = static_cast<int32_t>((*it)->GetTextAlignValue(TextAlign::START)),
2426                 .wordBreak = static_cast<int32_t>((*it)->GetWordBreakValue(WordBreak::BREAK_WORD)),
2427                 .lineBreakStrategy = static_cast<int32_t>((*it)->GetLineBreakStrategyValue(LineBreakStrategy::GREEDY)),
2428                 .range = { paraStart, (*it)->GetSpanItem()->position },
2429             });
2430             paraStart = (*it)->GetSpanItem()->position;
2431         }
2432     }
2433 
2434     return res;
2435 }
2436 
GetParagraphLength(const std::list<RefPtr<UINode>> & spans) const2437 int32_t RichEditorPattern::GetParagraphLength(const std::list<RefPtr<UINode>>& spans) const
2438 {
2439     if (spans.empty()) {
2440         return 0;
2441     }
2442     int32_t imageSpanCnt = 0;
2443     for (auto it = spans.rbegin(); it != spans.rend(); ++it) {
2444         auto spanNode = DynamicCast<SpanNode>(*it);
2445         if (spanNode) {
2446             return spanNode->GetSpanItem()->position + imageSpanCnt;
2447         }
2448         ++imageSpanCnt;
2449     }
2450     return imageSpanCnt;
2451 }
2452 
GetParagraphNodes(int32_t start,int32_t end) const2453 std::vector<RefPtr<SpanNode>> RichEditorPattern::GetParagraphNodes(int32_t start, int32_t end) const
2454 {
2455     CHECK_NULL_RETURN(start != end, {});
2456     auto host = GetHost();
2457     CHECK_NULL_RETURN(host, {});
2458     CHECK_NULL_RETURN(!host->GetChildren().empty(), {});
2459 
2460     const auto& spans = host->GetChildren();
2461     int32_t length = GetParagraphLength(spans);
2462     std::vector<RefPtr<SpanNode>> res;
2463 
2464     if (start >= length) {
2465         return res;
2466     }
2467 
2468     auto headIt = spans.begin();
2469     auto flagNode = headIt;
2470     bool isEnd = false;
2471     int32_t spanEnd = -1;
2472     while (flagNode != spans.end()) {
2473         auto spanNode = DynamicCast<SpanNode>(*flagNode);
2474         if (spanNode) {
2475             auto&& info = spanNode->GetSpanItem();
2476             spanEnd = info->position;
2477             isEnd = StringUtils::ToWstring(info->content).back() == '\n';
2478         } else {
2479             ++spanEnd;
2480             isEnd = false;
2481         }
2482         flagNode++;
2483         if (spanEnd > start) {
2484             break;
2485         }
2486         if (isEnd) {
2487             headIt = flagNode;
2488         }
2489     }
2490     while (headIt != flagNode) {
2491         auto spanNode = DynamicCast<SpanNode>(*headIt);
2492         if (spanNode) {
2493             res.emplace_back(spanNode);
2494         }
2495         headIt++;
2496     }
2497     while (flagNode != spans.end() && (spanEnd < end || !isEnd)) {
2498         auto spanNode = DynamicCast<SpanNode>(*flagNode);
2499         if (spanNode) {
2500             res.emplace_back(spanNode);
2501             auto&& info = spanNode->GetSpanItem();
2502             spanEnd = info->position;
2503             isEnd = StringUtils::ToWstring(info->content).back() == '\n';
2504         } else {
2505             ++spanEnd;
2506             isEnd = false;
2507         }
2508         flagNode++;
2509     }
2510 
2511     return res;
2512 }
2513 
UpdateParagraphStyle(int32_t start,int32_t end,const struct UpdateParagraphStyle & style)2514 void RichEditorPattern::UpdateParagraphStyle(int32_t start, int32_t end, const struct UpdateParagraphStyle& style)
2515 {
2516     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "range=[%{public}d,%{public}d]", start, end);
2517     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "style=%{public}s", style.ToString().c_str());
2518     auto spanNodes = GetParagraphNodes(start, end);
2519     for (const auto& spanNode : spanNodes) {
2520         UpdateParagraphStyle(spanNode, style);
2521     }
2522 }
2523 
UpdateParagraphStyle(RefPtr<SpanNode> spanNode,const struct UpdateParagraphStyle & style)2524 void RichEditorPattern::UpdateParagraphStyle(RefPtr<SpanNode> spanNode, const struct UpdateParagraphStyle& style)
2525 {
2526     CHECK_NULL_VOID(spanNode);
2527     spanNode->UpdateTextAlign(style.textAlign.value_or(TextAlign::START));
2528     spanNode->UpdateWordBreak(style.wordBreak.value_or(WordBreak::BREAK_WORD));
2529     spanNode->UpdateLineBreakStrategy(style.lineBreakStrategy.value_or(LineBreakStrategy::GREEDY));
2530     if (style.leadingMargin.has_value()) {
2531         spanNode->GetSpanItem()->leadingMargin = *style.leadingMargin;
2532         spanNode->UpdateLeadingMargin(*style.leadingMargin);
2533     }
2534 }
2535 
ScheduleCaretTwinkling()2536 void RichEditorPattern::ScheduleCaretTwinkling()
2537 {
2538     ContainerScope scope(richEditorInstanceId_);
2539     auto host = GetHost();
2540     CHECK_NULL_VOID(host);
2541     auto context = host->GetContext();
2542     CHECK_NULL_VOID(context);
2543 
2544     if (!context->GetTaskExecutor()) {
2545         return;
2546     }
2547 
2548     if (isCursorAlwaysDisplayed_) {
2549         return;
2550     }
2551 
2552     auto weak = WeakClaim(this);
2553     caretTwinklingTask_.Reset([weak, instanceId = richEditorInstanceId_] {
2554         ContainerScope scope(instanceId);
2555         auto client = weak.Upgrade();
2556         CHECK_NULL_VOID(client);
2557         client->OnCaretTwinkling();
2558     });
2559     auto taskExecutor = context->GetTaskExecutor();
2560     CHECK_NULL_VOID(taskExecutor);
2561     taskExecutor->PostDelayedTask(caretTwinklingTask_, TaskExecutor::TaskType::UI, RICH_EDITOR_TWINKLING_INTERVAL_MS,
2562         "ArkUIRichEditorScheduleCaretTwinkling");
2563 }
2564 
StartTwinkling()2565 void RichEditorPattern::StartTwinkling()
2566 {
2567     caretTwinklingTask_.Cancel();
2568     // Fire on selecion change when caret invisible -> visible
2569     if (!caretTwinkling_) {
2570         TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "StartTwinkling");
2571         caretTwinkling_ = true;
2572         FireOnSelectionChange(caretPosition_, caretPosition_);
2573     }
2574     caretVisible_ = true;
2575     auto tmpHost = GetHost();
2576     CHECK_NULL_VOID(tmpHost);
2577     tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2578     ScheduleCaretTwinkling();
2579 }
2580 
ShowCaretWithoutTwinkling()2581 void RichEditorPattern::ShowCaretWithoutTwinkling()
2582 {
2583     isCursorAlwaysDisplayed_ = true;
2584     StartTwinkling();
2585 }
2586 
OnCaretTwinkling()2587 void RichEditorPattern::OnCaretTwinkling()
2588 {
2589     caretTwinklingTask_.Cancel();
2590     caretVisible_ = !caretVisible_;
2591     GetHost()->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2592     ScheduleCaretTwinkling();
2593 }
2594 
StopTwinkling()2595 void RichEditorPattern::StopTwinkling()
2596 {
2597     if (caretTwinkling_) {
2598         TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "StopTwinkling");
2599     }
2600     caretTwinkling_ = false;
2601     isCursorAlwaysDisplayed_ = false;
2602     caretTwinklingTask_.Cancel();
2603     if (caretVisible_) {
2604         caretVisible_ = false;
2605         GetHost()->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2606     }
2607 }
2608 
HandleClickEvent(GestureEvent & info)2609 void RichEditorPattern::HandleClickEvent(GestureEvent& info)
2610 {
2611     CHECK_NULL_VOID(!selectOverlay_->GetIsHandleMoving());
2612     auto focusHub = GetFocusHub();
2613     CHECK_NULL_VOID(focusHub);
2614     if (!focusHub->IsFocusable()) {
2615         return;
2616     }
2617 
2618     if (!HasFocus() && !focusHub->IsFocusOnTouch().value_or(true)) {
2619         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "HandleClickEvent fail when IsFocusOnTouch false");
2620         CloseSelectOverlay();
2621         StopTwinkling();
2622         return;
2623     }
2624 
2625     selectionMenuOffsetClick_ = OffsetF(
2626         static_cast<float>(info.GetGlobalLocation().GetX()), static_cast<float>(info.GetGlobalLocation().GetY()));
2627     if (dataDetectorAdapter_->hasClickedAISpan_) {
2628         dataDetectorAdapter_->hasClickedAISpan_ = false;
2629     }
2630     multipleClickRecognizer_->Start(info);
2631     if (multipleClickRecognizer_->IsTripleClick()) {
2632         HandleTripleClickEvent(info);
2633     } else if (multipleClickRecognizer_->IsDoubleClick()) {
2634         HandleDoubleClickEvent(info);
2635     } else {
2636         HandleSingleClickEvent(info);
2637         NotifyCaretChange();
2638     }
2639 }
2640 
HandleClickSelection(const OHOS::Ace::GestureEvent & info)2641 bool RichEditorPattern::HandleClickSelection(const OHOS::Ace::GestureEvent& info)
2642 {
2643     CHECK_NULL_RETURN(!selectOverlay_->GetIsHandleMoving(), true);
2644     if (SelectOverlayIsOn()) {
2645         selectOverlay_->SwitchToOverlayMode();
2646         selectOverlay_->ToggleMenu();
2647     } else {
2648         CalculateHandleOffsetAndShowOverlay();
2649         selectOverlay_->ProcessOverlay({.animation = true, .requestCode = REQUEST_RECREATE});
2650     }
2651     return true;
2652 }
2653 
IsClickEventOnlyForMenuToggle(const OHOS::Ace::GestureEvent & info)2654 bool RichEditorPattern::IsClickEventOnlyForMenuToggle(const OHOS::Ace::GestureEvent& info)
2655 {
2656     CHECK_NULL_RETURN(info.GetSourceDevice() != SourceType::MOUSE, false);
2657     // In preview state or single handle showing, clicking handle has toggled the menu display
2658     bool hasHandledMenuToggleByClick =
2659         selectOverlay_->IsClickAtHandle(info) && (!isEditing_ || selectOverlay_->IsSingleHandleShow());
2660     CHECK_NULL_RETURN(!hasHandledMenuToggleByClick, true);
2661     if (BetweenSelection(info.GetGlobalLocation())) {
2662         return HandleClickSelection(info);
2663     }
2664     return false;
2665 }
2666 
HandleSingleClickEvent(OHOS::Ace::GestureEvent & info)2667 void RichEditorPattern::HandleSingleClickEvent(OHOS::Ace::GestureEvent& info)
2668 {
2669     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "handleSingleClick");
2670     hasClicked_ = true;
2671     lastClickTimeStamp_ = info.GetTimeStamp();
2672     CHECK_NULL_VOID(!IsClickEventOnlyForMenuToggle(info));
2673 
2674     if (HandleUrlSpanClickEvent(info)) {
2675         return;
2676     }
2677 
2678     Offset textOffset = ConvertTouchOffsetToTextOffset(info.GetLocalLocation());
2679     IF_TRUE(!isMousePressed_, HandleClickAISpanEvent(PointF(textOffset.GetX(), textOffset.GetY())));
2680 
2681     if (dataDetectorAdapter_->hasClickedAISpan_ || dataDetectorAdapter_->pressedByLeftMouse_) {
2682         IF_TRUE(SelectOverlayIsOn(), selectOverlay_->HideMenu());
2683         return;
2684     }
2685 
2686     HandleUserClickEvent(info);
2687     CHECK_NULL_VOID(!info.IsPreventDefault());
2688     bool isMouseClick = info.GetSourceDevice() == SourceType::MOUSE;
2689     bool isMouseClickWithShift = shiftFlag_ && isMouseClick && !IsPreviewTextInputting();
2690     if (textSelector_.IsValid() && !isMouseSelect_ && !isMouseClickWithShift) {
2691         CloseSelectOverlay();
2692         ResetSelection();
2693     }
2694     moveCaretState_.Reset();
2695     caretUpdateType_ = CaretUpdateType::PRESSED;
2696 
2697     CHECK_NULL_VOID(overlayMod_);
2698     RectF lastCaretRect = GetCaretRect();
2699     int32_t lastCaretPosition = caretPosition_;
2700     bool isCaretTwinkling = caretTwinkling_;
2701     auto position = paragraphs_.GetIndex(textOffset);
2702     AdjustCursorPosition(position);
2703     if (auto focusHub = GetFocusHub(); focusHub) {
2704         if (isMouseClickWithShift) {
2705             HandleShiftSelect(position);
2706         } else {
2707             SetCaretPosition(position);
2708         }
2709         if (focusHub->RequestFocusImmediately()) {
2710             IF_TRUE(!shiftFlag_ || textSelector_.SelectNothing(), StartTwinkling());
2711             RequestKeyboard(false, true, true);
2712             TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "focusHub: set HandleOnEditChanged to 1");
2713             HandleOnEditChanged(true);
2714         }
2715     }
2716     UseHostToUpdateTextFieldManager();
2717     CalcCaretInfoByClick(info.GetLocalLocation());
2718     CHECK_NULL_VOID(!isMouseClick);
2719     if (IsShowSingleHandleByClick(info, lastCaretPosition, lastCaretRect, isCaretTwinkling)) {
2720         CreateAndShowSingleHandle();
2721     }
2722 }
2723 
GetTextOffset(const Offset & localLocation,const RectF & contentRect)2724 PointF RichEditorPattern::GetTextOffset(const Offset &localLocation, const RectF &contentRect)
2725 {
2726     PointF textOffset = {static_cast<float>(localLocation.GetX()) - GetTextRect().GetX(),
2727                          static_cast<float>(localLocation.GetY()) - GetTextRect().GetY()};
2728     return textOffset;
2729 }
2730 
GetSelectedRects(int32_t start,int32_t end)2731 std::vector<RectF> RichEditorPattern::GetSelectedRects(int32_t start, int32_t end)
2732 {
2733     return paragraphs_.GetRects(start, end);
2734 }
2735 
ConvertTouchOffsetToTextOffset(const Offset & touchOffset)2736 Offset RichEditorPattern::ConvertTouchOffsetToTextOffset(const Offset& touchOffset)
2737 {
2738     richTextRect_.SetTop(richTextRect_.GetY() - std::min(baselineOffset_, 0.0f));
2739     richTextRect_.SetHeight(richTextRect_.Height() - std::max(baselineOffset_, 0.0f));
2740     return touchOffset - Offset(richTextRect_.GetX(), richTextRect_.GetY());
2741 }
2742 
IsShowSingleHandleByClick(const OHOS::Ace::GestureEvent & info,int32_t lastCaretPosition,const RectF & lastCaretRect,bool isCaretTwinkling)2743 bool RichEditorPattern::IsShowSingleHandleByClick(
2744     const OHOS::Ace::GestureEvent& info, int32_t lastCaretPosition, const RectF& lastCaretRect, bool isCaretTwinkling)
2745 {
2746     CHECK_NULL_RETURN(isCaretTwinkling && (info.GetSourceDevice() != SourceType::MOUSE), false);
2747     auto offset = info.GetLocalLocation();
2748     Offset textOffset = ConvertTouchOffsetToTextOffset(offset);
2749     auto position = paragraphs_.GetIndex(textOffset);
2750     CHECK_NULL_RETURN(position == lastCaretPosition, false);
2751     auto paragraphEndPos = GetParagraphEndPosition(lastCaretPosition);
2752     if (lastCaretPosition == paragraphEndPos || IsTouchAtLineEnd(lastCaretPosition, textOffset)) {
2753         TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "repeat click lineEnd or paragraphEndPos=%{public}d", paragraphEndPos);
2754         return true;
2755     }
2756     return RepeatClickCaret(offset, lastCaretRect);
2757 }
2758 
RepeatClickCaret(const Offset & offset,int32_t lastCaretPosition,const RectF & lastCaretRect)2759 bool RichEditorPattern::RepeatClickCaret(const Offset& offset, int32_t lastCaretPosition, const RectF& lastCaretRect)
2760 {
2761     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "caretTwinkling=%{public}d offset=%{public}s lastCaretRect=%{public}s",
2762         caretTwinkling_, offset.ToString().c_str(), lastCaretRect.ToString().c_str());
2763     CHECK_NULL_RETURN(caretTwinkling_, false);
2764     Offset textOffset = ConvertTouchOffsetToTextOffset(offset);
2765     auto position = paragraphs_.GetIndex(textOffset);
2766     if (position != lastCaretPosition) {
2767         TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "clickCaretPosition=%{public}d but lastCaretPosition=%{public}d",
2768             position, lastCaretPosition);
2769         return false;
2770     }
2771     return RepeatClickCaret(offset, lastCaretRect);
2772 }
2773 
RepeatClickCaret(const Offset & offset,const RectF & lastCaretRect)2774 bool RichEditorPattern::RepeatClickCaret(const Offset& offset, const RectF& lastCaretRect)
2775 {
2776     auto lastCaretHeight = lastCaretRect.Height();
2777     auto handleHotZone = selectOverlay_->GetHandleHotZoneRadius();
2778     auto caretHotZoneRect =
2779         RectF(lastCaretRect.GetX() - handleHotZone, lastCaretRect.GetY(), handleHotZone * 2, lastCaretHeight);
2780     return caretHotZoneRect.IsInRegion(PointF(offset.GetX(), offset.GetY()));
2781 }
2782 
CreateAndShowSingleHandle()2783 void RichEditorPattern::CreateAndShowSingleHandle()
2784 {
2785     if (IsPreviewTextInputting()) {
2786         return;
2787     }
2788     textResponseType_ = TextResponseType::LONG_PRESS;
2789     selectOverlay_->SetIsSingleHandle(true);
2790     textSelector_.Update(caretPosition_);
2791     CalculateHandleOffsetAndShowOverlay();
2792     UpdateSelectionType(GetSpansInfo(caretPosition_, caretPosition_, GetSpansMethod::ONSELECT));
2793     selectOverlay_->ProcessOverlay({ .animation = true });
2794 }
2795 
MoveCaretAndStartFocus(const Offset & textOffset)2796 void RichEditorPattern::MoveCaretAndStartFocus(const Offset& textOffset)
2797 {
2798     auto position = paragraphs_.GetIndex(textOffset);
2799     AdjustCursorPosition(position);
2800 
2801     auto focusHub = GetFocusHub();
2802     if (focusHub) {
2803         SetCaretPosition(position);
2804         if (focusHub->RequestFocusImmediately()) {
2805             IF_TRUE(!shiftFlag_ || textSelector_.SelectNothing(), StartTwinkling());
2806             if (overlayMod_) {
2807                 RequestKeyboard(false, true, true);
2808             }
2809             HandleOnEditChanged(true);
2810         }
2811     }
2812     UseHostToUpdateTextFieldManager();
2813 }
2814 
HandleDoubleClickEvent(OHOS::Ace::GestureEvent & info)2815 void RichEditorPattern::HandleDoubleClickEvent(OHOS::Ace::GestureEvent& info)
2816 {
2817     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "HandleDoubleClickEvent");
2818     caretUpdateType_ = CaretUpdateType::DOUBLE_CLICK;
2819     HandleDoubleClickOrLongPress(info);
2820     caretUpdateType_ = CaretUpdateType::NONE;
2821 }
2822 
HandleUserGestureEvent(GestureEvent & info,std::function<bool (RefPtr<SpanItem> item,GestureEvent & info)> && gestureFunc)2823 bool RichEditorPattern::HandleUserGestureEvent(
2824     GestureEvent& info, std::function<bool(RefPtr<SpanItem> item, GestureEvent& info)>&& gestureFunc)
2825 {
2826     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "HandleUserGestureEvent");
2827     RectF textContentRect = contentRect_;
2828     textContentRect.SetTop(contentRect_.GetY() - std::min(baselineOffset_, 0.0f));
2829     textContentRect.SetHeight(contentRect_.Height() - std::max(baselineOffset_, 0.0f));
2830     if (!textContentRect.IsInRegion(PointF(info.GetLocalLocation().GetX(), info.GetLocalLocation().GetY())) ||
2831         spans_.empty()) {
2832         return false;
2833     }
2834     PointF textOffset = { info.GetLocalLocation().GetX() - GetTextRect().GetX(),
2835         info.GetLocalLocation().GetY() - GetTextRect().GetY() };
2836     int32_t start = 0;
2837     bool isParagraphHead = true;
2838     Offset paragraphOffset(0, 0);
2839     for (const auto& item : spans_) {
2840         if (!item) {
2841             continue;
2842         }
2843         std::vector<RectF> selectedRects = paragraphs_.GetRects(start, item->position);
2844         start = item->position;
2845         if (isParagraphHead && !selectedRects.empty()) {
2846             if (item->leadingMargin.has_value()) {
2847                 auto addWidth = item->leadingMargin.value().size.Width();
2848                 selectedRects[0].SetLeft(selectedRects[0].GetX() - addWidth.ConvertToPx());
2849                 selectedRects[0].SetWidth(selectedRects[0].GetSize().Width() + addWidth.ConvertToPx());
2850             }
2851             paragraphOffset.SetX(selectedRects[0].GetOffset().GetX());
2852             paragraphOffset.SetY(selectedRects[0].GetOffset().GetY());
2853             isParagraphHead = false;
2854         }
2855         if (!isParagraphHead && item->content.back() == '\n') {
2856             isParagraphHead = true;
2857         }
2858         for (auto&& rect : selectedRects) {
2859             if (!rect.IsInRegion(textOffset)) {
2860                 continue;
2861             }
2862             info = info.SetScreenLocation(
2863                 Offset(textOffset.GetX() - paragraphOffset.GetX(), textOffset.GetY() - paragraphOffset.GetY()));
2864             return gestureFunc(item, info);
2865         }
2866     }
2867     return false;
2868 }
2869 
HandleOnlyImageSelected(const Offset & globalOffset,const SourceTool sourceTool)2870 void RichEditorPattern::HandleOnlyImageSelected(const Offset& globalOffset, const SourceTool sourceTool)
2871 {
2872     CHECK_NULL_VOID(sourceTool != SourceTool::FINGER);
2873     CHECK_NULL_VOID(sourceTool != SourceTool::PEN);
2874     if (IsSelected()) {
2875         return;
2876     }
2877     auto textRect = GetTextRect();
2878     textRect.SetTop(textRect.GetY() - std::min(baselineOffset_, 0.0f));
2879     textRect.SetHeight(textRect.Height() - std::max(baselineOffset_, 0.0f));
2880     Offset offset = Offset(textRect.GetX(), textRect.GetY());
2881     auto textOffset = globalOffset - offset;
2882     int32_t currentPosition = paragraphs_.GetIndex(textOffset);
2883     currentPosition = std::min(currentPosition, GetTextContentLength());
2884     int32_t nextPosition = currentPosition + GetGraphemeClusterLength(GetWideText(), currentPosition);
2885     nextPosition = std::min(nextPosition, GetTextContentLength());
2886     AdjustPlaceholderSelection(currentPosition, nextPosition, textOffset);
2887     auto textSelectInfo = GetSpansInfo(currentPosition, nextPosition, GetSpansMethod::ONSELECT);
2888     auto results = textSelectInfo.GetSelection().resultObjects;
2889     if (results.size() == 1 && results.front().type == SelectSpanType::TYPEIMAGE && results.front().valueString != " "
2890         && !isOnlyImageDrag_) {
2891         textSelector_.Update(currentPosition, nextPosition);
2892         isOnlyImageDrag_ = true;
2893         showSelect_ = false;
2894         CalculateHandleOffsetAndShowOverlay();
2895         if (selectOverlay_->IsBothHandlesShow()) {
2896             TextPattern::CloseSelectOverlay(false);
2897         }
2898         auto focusHub = GetFocusHub();
2899         if (focusHub && sourceTool != SourceTool::FINGER) {
2900             auto isSuccess = focusHub->RequestFocusImmediately();
2901             TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "only image selected, textSelector=[%{public}d, %{public}d], "
2902                 "requestFocus=%{public}d, isFocus=%{public}d",
2903                 textSelector_.GetTextStart(), textSelector_.GetTextEnd(), isSuccess, HasFocus());
2904             FireOnSelectionChange(textSelector_);
2905         }
2906     }
2907 }
2908 
ClickAISpan(const PointF & textOffset,const AISpan & aiSpan)2909 bool RichEditorPattern::ClickAISpan(const PointF& textOffset, const AISpan& aiSpan)
2910 {
2911     auto calculateHandleFunc = [weak = WeakClaim(this)]() {
2912         auto pattern = weak.Upgrade();
2913         CHECK_NULL_VOID(pattern);
2914         pattern->CalculateHandleOffsetAndShowOverlay();
2915     };
2916     auto showSelectOverlayFunc = [weak = WeakClaim(this)](const RectF& firstHandle, const RectF& secondHandle) {
2917         auto pattern = weak.Upgrade();
2918         CHECK_NULL_VOID(pattern);
2919         pattern->SetCaretPosition(pattern->textSelector_.destinationOffset);
2920         auto focusHub = pattern->GetFocusHub();
2921         CHECK_NULL_VOID(focusHub);
2922         focusHub->RequestFocusImmediately();
2923         pattern->ShowSelectOverlay(firstHandle, secondHandle);
2924     };
2925 
2926     std::vector<RectF> aiRects = paragraphs_.GetRects(aiSpan.start, aiSpan.end);
2927     for (auto&& rect : aiRects) {
2928         if (rect.IsInRegion(textOffset)) {
2929             dataDetectorAdapter_->clickedAISpan_ = aiSpan;
2930             if (leftMousePress_) {
2931                 dataDetectorAdapter_->pressedByLeftMouse_ = true;
2932                 return true;
2933             }
2934             dataDetectorAdapter_->hasClickedAISpan_ = true;
2935             ShowAIEntityMenu(aiSpan, calculateHandleFunc, showSelectOverlayFunc);
2936             return true;
2937         }
2938     }
2939     return false;
2940 }
2941 
HandleUrlSpanClickEvent(const GestureEvent & info)2942 bool RichEditorPattern::HandleUrlSpanClickEvent(const GestureEvent& info)
2943 {
2944     RectF textContentRect = contentRect_;
2945     textContentRect.SetTop(contentRect_.GetY() - std::min(baselineOffset_, 0.0f));
2946     textContentRect.SetHeight(contentRect_.Height() - std::max(baselineOffset_, 0.0f));
2947 
2948     CheckClickedOnSpanOrText(textContentRect, info.GetLocalLocation());
2949     auto clickedSpanPosition = GetClickedSpanPosition();
2950     if (LessNotEqual(clickedSpanPosition, 0)) {
2951         return false;
2952     }
2953     auto iter = spans_.begin();
2954     std::advance(iter, clickedSpanPosition);
2955     RefPtr<SpanItem> span;
2956     if (iter == spans_.end()) {
2957         span = spans_.back();
2958     } else {
2959         span = *iter;
2960     }
2961     if (span && span->urlOnRelease) {
2962         span->urlOnRelease();
2963         return true;
2964     }
2965     return false;
2966 }
2967 
HandleUserClickEvent(GestureEvent & info)2968 bool RichEditorPattern::HandleUserClickEvent(GestureEvent& info)
2969 {
2970     auto clickFunc = [](RefPtr<SpanItem> item, GestureEvent& info) -> bool {
2971         if (item && item->onClick) {
2972             item->onClick(info);
2973             return true;
2974         }
2975         return false;
2976     };
2977     return HandleUserGestureEvent(info, std::move(clickFunc));
2978 }
2979 
CalcCaretInfoByClick(const Offset & touchOffset)2980 void RichEditorPattern::CalcCaretInfoByClick(const Offset& touchOffset)
2981 {
2982     auto textRect = GetTextRect();
2983     textRect.SetTop(textRect.GetY() - std::min(baselineOffset_, 0.0f));
2984     textRect.SetHeight(textRect.Height() - std::max(baselineOffset_, 0.0f));
2985     Offset textOffset = { touchOffset.GetX() - textRect.GetX(), touchOffset.GetY() - textRect.GetY() };
2986     auto [lastClickOffset, caretHeight] = CalcAndRecordLastClickCaretInfo(textOffset);
2987     CHECK_NULL_VOID(overlayMod_);
2988     DynamicCast<RichEditorOverlayModifier>(overlayMod_)->SetCaretOffsetAndHeight(lastClickOffset, caretHeight);
2989     MoveCaretToContentRect();
2990 }
2991 
CalcAndRecordLastClickCaretInfo(const Offset & textOffset)2992 std::pair<OffsetF, float> RichEditorPattern::CalcAndRecordLastClickCaretInfo(const Offset& textOffset)
2993 {
2994     // get the caret position
2995     auto positionWithAffinity = paragraphs_.GetGlyphPositionAtCoordinate(textOffset);
2996     auto position = static_cast<int32_t>(positionWithAffinity.position_);
2997     // get the caret offset when click
2998     float caretHeight = 0.0f;
2999     auto lastClickOffset = paragraphs_.ComputeCursorInfoByClick(position, caretHeight,
3000         OffsetF(static_cast<float>(textOffset.GetX()), static_cast<float>(textOffset.GetY())));
3001 
3002     lastClickOffset += richTextRect_.GetOffset();
3003     if (isShowPlaceholder_) {
3004         auto [caretOffset, preferredHeight] = CalculateEmptyValueCaretRect();
3005         lastClickOffset = caretOffset;
3006     }
3007     SetLastClickOffset(lastClickOffset);
3008     caretAffinityPolicy_ = (positionWithAffinity.affinity_ == TextAffinity::UPSTREAM)
3009                                 ? CaretAffinityPolicy::UPSTREAM_FIRST
3010                                 : CaretAffinityPolicy::DOWNSTREAM_FIRST;
3011     return std::make_pair(lastClickOffset, caretHeight);
3012 }
3013 
InitClickEvent(const RefPtr<GestureEventHub> & gestureHub)3014 void RichEditorPattern::InitClickEvent(const RefPtr<GestureEventHub>& gestureHub)
3015 {
3016     CHECK_NULL_VOID(!clickEventInitialized_);
3017     auto clickCallback = [weak = WeakClaim(this)](GestureEvent& info) {
3018         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "click callback, sourceType=%{public}d", info.GetSourceDevice());
3019         auto pattern = weak.Upgrade();
3020         CHECK_NULL_VOID(pattern);
3021         pattern->sourceType_ = info.GetSourceDevice();
3022         pattern->HandleClickEvent(info);
3023     };
3024     auto clickListener = MakeRefPtr<ClickEvent>(std::move(clickCallback));
3025     gestureHub->AddClickAfterEvent(clickListener);
3026     clickEventInitialized_ = true;
3027 }
3028 
InitFocusEvent(const RefPtr<FocusHub> & focusHub)3029 void RichEditorPattern::InitFocusEvent(const RefPtr<FocusHub>& focusHub)
3030 {
3031     CHECK_NULL_VOID(!focusEventInitialized_);
3032     auto focusTask = [weak = WeakClaim(this)]() {
3033         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "rich editor in focus");
3034         auto pattern = weak.Upgrade();
3035         CHECK_NULL_VOID(pattern);
3036         pattern->HandleFocusEvent();
3037     };
3038     focusHub->SetOnFocusInternal(focusTask);
3039     auto blurTask = [weak = WeakClaim(this)]() {
3040         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "rich editor in blur");
3041         auto pattern = weak.Upgrade();
3042         CHECK_NULL_VOID(pattern);
3043         pattern->HandleBlurEvent();
3044     };
3045     focusHub->SetOnBlurInternal(blurTask);
3046     focusEventInitialized_ = true;
3047     auto keyTask = [weak = WeakClaim(this)](const KeyEvent& keyEvent) -> bool {
3048         auto pattern = weak.Upgrade();
3049         CHECK_NULL_RETURN(pattern, false);
3050         return pattern->OnKeyEvent(keyEvent);
3051     };
3052     focusHub->SetOnKeyEventInternal(std::move(keyTask));
3053 }
3054 
GetBlurReason()3055 BlurReason RichEditorPattern::GetBlurReason()
3056 {
3057     auto host = GetHost();
3058     CHECK_NULL_RETURN(host, BlurReason::FOCUS_SWITCH);
3059     auto curFocusHub = host->GetFocusHub();
3060     CHECK_NULL_RETURN(curFocusHub, BlurReason::FOCUS_SWITCH);
3061     return curFocusHub->GetBlurReason();
3062 }
3063 
HandleBlurEvent()3064 void RichEditorPattern::HandleBlurEvent()
3065 {
3066     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "HandleBlurEvent/%{public}d", frameId_);
3067     CHECK_NULL_VOID(showSelect_ || !IsSelected());
3068     ClearOnFocusTextField();
3069     isLongPress_ = false;
3070     previewLongPress_ = false;
3071     editingLongPress_ = false;
3072     shiftFlag_ = false;
3073     moveCaretState_.Reset();
3074     StopTwinkling();
3075     auto reason = GetBlurReason();
3076     // The pattern handles blurevent, Need to close the softkeyboard first.
3077     if ((customKeyboardBuilder_ && isCustomKeyboardAttached_) || reason == BlurReason::FRAME_DESTROY) {
3078         TAG_LOGI(AceLogTag::ACE_KEYBOARD, "RichEditor Blur, Close Keyboard.");
3079         CloseKeyboard(false);
3080     }
3081     if (magnifierController_) {
3082         magnifierController_->RemoveMagnifierFrameNode();
3083     }
3084     if (IsSelected()) {
3085         CalculateHandleOffsetAndShowOverlay();
3086         selectOverlay_->ProcessOverlay({ .menuIsShow = false});
3087     } else {
3088         CloseSelectOverlay();
3089     }
3090     isCaretInContentArea_ = reason == BlurReason::WINDOW_BLUR && IsCaretInContentArea();
3091     if (reason != BlurReason::WINDOW_BLUR) {
3092         lastSelectionRange_.reset();
3093         HandleOnEditChanged(false);
3094     }
3095     isMoveCaretAnywhere_ = false;
3096 }
3097 
HandleFocusEvent()3098 void RichEditorPattern::HandleFocusEvent()
3099 {
3100     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "HandleFocusEvent/%{public}d", frameId_);
3101     UseHostToUpdateTextFieldManager();
3102     if (previewLongPress_ || isOnlyRequestFocus_) {
3103         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "HandleFocusEvent, previewLongPress=%{public}d,"
3104             "OnlyRequestFocus=%{public}d", previewLongPress_, isOnlyRequestFocus_);
3105         isOnlyRequestFocus_ = false;
3106         return;
3107     }
3108     if (textSelector_.SelectNothing()) {
3109         StartTwinkling();
3110     }
3111     bool isFontScaleChanged = false;
3112     auto pipelineContext = PipelineBase::GetCurrentContext();
3113     if (pipelineContext) {
3114         auto currentFontScale = pipelineContext->GetFontScale() * pipelineContext->GetDipScale();
3115         isFontScaleChanged = !NearEqual(lastFontScale_, currentFontScale);
3116         lastFontScale_ = currentFontScale;
3117     }
3118     auto host = GetHost();
3119     if (host) {
3120         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
3121     }
3122     if (!usingMouseRightButton_ && !isLongPress_ && !dataDetectorAdapter_->hasClickedMenuOption_) {
3123         auto windowMode = GetWindowMode();
3124         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "onFocus, requestKeyboard=%{public}d, windowMode=%{public}d",
3125             needToRequestKeyboardOnFocus_, windowMode);
3126         bool needShowSoftKeyboard = needToRequestKeyboardOnFocus_ && windowMode != WindowMode::WINDOW_MODE_FLOATING;
3127         RequestKeyboard(false, true, needShowSoftKeyboard);
3128         HandleOnEditChanged(true);
3129     }
3130 }
3131 
GetWindowMode()3132 WindowMode RichEditorPattern::GetWindowMode()
3133 {
3134     auto pipelineContext = PipelineBase::GetCurrentContextSafely();
3135     CHECK_NULL_RETURN(pipelineContext, WindowMode::WINDOW_MODE_UNDEFINED);
3136     auto windowManager = pipelineContext->GetWindowManager();
3137     CHECK_NULL_RETURN(windowManager, WindowMode::WINDOW_MODE_UNDEFINED);
3138     return windowManager->GetWindowMode();
3139 }
3140 
UseHostToUpdateTextFieldManager()3141 void RichEditorPattern::UseHostToUpdateTextFieldManager()
3142 {
3143     auto host = GetHost();
3144     CHECK_NULL_VOID(host);
3145     auto context = host->GetContext();
3146     CHECK_NULL_VOID(context);
3147     auto globalOffset = host->GetPaintRectOffsetNG(false, true) - context->GetRootRect().GetOffset();
3148     UpdateTextFieldManager(Offset(globalOffset.GetX(), globalOffset.GetY()), frameRect_.Height());
3149 }
3150 
OnVisibleChange(bool isVisible)3151 void RichEditorPattern::OnVisibleChange(bool isVisible)
3152 {
3153     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "isVisible=%{public}d", isVisible);
3154     TextPattern::OnVisibleChange(isVisible);
3155     StopTwinkling();
3156     CloseKeyboard(false);
3157 }
3158 
CloseKeyboard(bool forceClose)3159 bool RichEditorPattern::CloseKeyboard(bool forceClose)
3160 {
3161     CloseSelectOverlay();
3162     ResetSelection();
3163     if (customKeyboardBuilder_ && isCustomKeyboardAttached_) {
3164         return CloseCustomKeyboard();
3165     }
3166     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "Request close soft keyboard.");
3167 #if defined(ENABLE_STANDARD_INPUT)
3168 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
3169     if (!imeAttached_ && !forceClose) {
3170         return false;
3171     }
3172 #endif
3173     auto inputMethod = MiscServices::InputMethodController::GetInstance();
3174     CHECK_NULL_RETURN(inputMethod, false);
3175     inputMethod->HideTextInput();
3176     inputMethod->Close();
3177 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
3178     imeAttached_ = false;
3179 #endif
3180 #else
3181     if (HasConnection()) {
3182         connection_->Close(GetInstanceId());
3183         connection_ = nullptr;
3184     }
3185 #endif
3186     return true;
3187 }
3188 
HandleDraggableFlag(bool isTouchSelectArea)3189 void RichEditorPattern::HandleDraggableFlag(bool isTouchSelectArea)
3190 {
3191     auto gestureHub = GetGestureEventHub();
3192     CHECK_NULL_VOID(gestureHub);
3193     if (copyOption_ != CopyOptions::None && isTouchSelectArea) {
3194         bool isContentDraggalbe = JudgeContentDraggable();
3195         if (isContentDraggalbe) {
3196             dragBoxes_ = GetTextBoxes();
3197         }
3198         gestureHub->SetIsTextDraggable(isContentDraggalbe);
3199     } else {
3200         gestureHub->SetIsTextDraggable(false);
3201     }
3202 }
3203 
SetIsTextDraggable(bool isTextDraggable)3204 void RichEditorPattern::SetIsTextDraggable(bool isTextDraggable)
3205 {
3206     auto gestureHub = GetGestureEventHub();
3207     CHECK_NULL_VOID(gestureHub);
3208     gestureHub->SetIsTextDraggable(isTextDraggable);
3209 }
3210 
JudgeContentDraggable()3211 bool RichEditorPattern::JudgeContentDraggable()
3212 {
3213     if (!IsSelected() || copyOption_ == CopyOptions::None) {
3214         return false ;
3215     }
3216     auto selectInfo = GetSpansInfo(textSelector_.GetTextStart(), textSelector_.GetTextEnd(), GetSpansMethod::ONSELECT);
3217     auto selResult = selectInfo.GetSelection().resultObjects;
3218     auto iter = std::find_if(selResult.begin(), selResult.end(), [](ResultObject& obj) { return obj.isDraggable; });
3219     return iter != selResult.end();
3220 }
3221 
CalculateCaretOffsetAndHeight()3222 std::pair<OffsetF, float> RichEditorPattern::CalculateCaretOffsetAndHeight()
3223 {
3224     OffsetF caretOffset;
3225     float caretHeight = 0.0f;
3226     auto caretPosition = caretPosition_;
3227     float caretHeightUp = 0.0f;
3228     auto overlayModifier = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
3229     CHECK_NULL_RETURN(overlayModifier, std::make_pair(caretOffset, caretHeight));
3230     auto caretWidth = overlayModifier->GetCaretWidth();
3231     auto contentRect = GetTextContentRect();
3232     OffsetF caretOffsetUp = CalcCursorOffsetByPosition(caretPosition, caretHeightUp, false, false);
3233     if (isShowPlaceholder_) {
3234         auto textAlign = GetTextAlignByDirection();
3235         IF_TRUE(textAlign == TextAlign::END, caretOffsetUp.SetX(contentRect.Right() - caretWidth));
3236         return { caretOffsetUp, caretHeightUp };
3237     }
3238     if (GetTextContentLength() <= 0) {
3239         constexpr float DEFAULT_CARET_HEIGHT = 18.5f;
3240         auto [caretOffset, preferredHeight] = CalculateEmptyValueCaretRect();
3241         caretHeight = typingTextStyle_.has_value() ? preferredHeight
3242             : static_cast<float>(Dimension(DEFAULT_CARET_HEIGHT, DimensionUnit::VP).ConvertToPx());
3243         return { caretOffset, caretHeight };
3244     }
3245     float caretHeightDown = 0.0f;
3246     OffsetF caretOffsetDown = CalcCursorOffsetByPosition(caretPosition, caretHeightDown, true, false);
3247     bool isCaretPosInLineEnd = !NearEqual(caretOffsetDown.GetX(), caretOffsetUp.GetX(), 0.5f);
3248     bool isShowCaretDown = isCaretPosInLineEnd;
3249     if ((caretAffinityPolicy_ != CaretAffinityPolicy::DEFAULT) && isCaretPosInLineEnd) {
3250         // show caret by click
3251         isShowCaretDown = (caretAffinityPolicy_ == CaretAffinityPolicy::DOWNSTREAM_FIRST);
3252     }
3253     caretOffset = isShowCaretDown ? caretOffsetDown : caretOffsetUp;
3254     caretHeight = isShowCaretDown ? caretHeightDown : caretHeightUp;
3255     if (GreatOrEqual(caretOffset.GetX() + caretWidth, contentRect.Right())) {
3256         caretOffset.SetX(caretOffset.GetX() - caretWidth);
3257     }
3258     return std::make_pair(caretOffset, caretHeight);
3259 }
3260 
CalculateEmptyValueCaretRect()3261 std::pair<OffsetF, float> RichEditorPattern::CalculateEmptyValueCaretRect()
3262 {
3263     OffsetF offset;
3264     auto textAlign = GetTextAlignByDirection();
3265     switch (textAlign) {
3266         case TextAlign::START:
3267             offset.SetX(contentRect_.GetX());
3268             break;
3269         case TextAlign::CENTER:
3270             offset.SetX(contentRect_.GetX() + contentRect_.Width() / 2.0f);
3271             break;
3272         case TextAlign::END: {
3273             auto overlayModifier = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
3274             auto caretWidth = overlayModifier ? overlayModifier->GetCaretWidth() : 0.0f;
3275             offset.SetX(contentRect_.Right() - caretWidth);
3276             break;
3277         }
3278         default:
3279             break;
3280     }
3281     auto offsetY = richTextRect_.GetY();
3282     float caretHeight = 0.0f;
3283     if (!presetParagraph_) {
3284         PreferredParagraph();
3285     }
3286     if (presetParagraph_) {
3287         CaretMetricsF caretCaretMetric;
3288         presetParagraph_->CalcCaretMetricsByPosition(1, caretCaretMetric, TextAffinity::UPSTREAM, false);
3289         offsetY += caretCaretMetric.offset.GetY();
3290         caretHeight = caretCaretMetric.height;
3291     }
3292     offset.SetY(offsetY);
3293     return std::make_pair(offset, caretHeight);
3294 }
3295 
UpdateModifierCaretOffsetAndHeight()3296 void RichEditorPattern::UpdateModifierCaretOffsetAndHeight()
3297 {
3298     CHECK_NULL_VOID(overlayMod_);
3299     auto overlayModifier = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
3300     CHECK_NULL_VOID(overlayModifier);
3301     auto [caretOffset, caretHeight] = CalculateCaretOffsetAndHeight();
3302     overlayModifier->SetCaretOffsetAndHeight(caretOffset, caretHeight);
3303 }
3304 
NotifyCaretChange()3305 void RichEditorPattern::NotifyCaretChange()
3306 {
3307     CHECK_NULL_VOID(!IsSelected());
3308     TriggerAvoidOnCaretChange();
3309 }
3310 
GetTextAlignByDirection()3311 TextAlign RichEditorPattern::GetTextAlignByDirection()
3312 {
3313     auto layoutProperty = GetLayoutProperty<TextLayoutProperty>();
3314     CHECK_NULL_RETURN(layoutProperty, TextAlign::START);
3315     auto textAlign = layoutProperty->GetTextAlignValue(TextAlign::START);
3316     auto direction = layoutProperty->GetNonAutoLayoutDirection();
3317     if (direction == TextDirection::RTL) {
3318         if (textAlign == TextAlign::START) {
3319             textAlign = TextAlign::END;
3320         } else {
3321             textAlign = TextAlign::START;
3322         }
3323     }
3324     return textAlign;
3325 }
3326 
HandleLongPress(GestureEvent & info)3327 void RichEditorPattern::HandleLongPress(GestureEvent& info)
3328 {
3329     CHECK_NULL_VOID(!selectOverlay_->GetIsHandleMoving());
3330     auto focusHub = GetFocusHub();
3331     CHECK_NULL_VOID(focusHub);
3332     if (!focusHub->IsFocusable()) {
3333         return;
3334     }
3335     if (info.GetFingerList().size() > 1) {
3336         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "More than one finger detected, ignoring this long press event");
3337         return;
3338     }
3339 
3340     if (sourceType_ == SourceType::MOUSE && hasUrlSpan_) {
3341         HandleUrlSpanShowShadow(info.GetLocalLocation(), info.GetGlobalLocation(), GetUrlPressColor());
3342     }
3343 
3344     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "HandleLongPress");
3345     moveCaretState_.Reset();
3346     caretUpdateType_ = CaretUpdateType::LONG_PRESSED;
3347     selectionMenuOffsetClick_ = OffsetF(
3348         static_cast<float>(info.GetGlobalLocation().GetX()), static_cast<float>(info.GetGlobalLocation().GetY()));
3349     HandleDoubleClickOrLongPress(info);
3350     caretUpdateType_ = CaretUpdateType::NONE;
3351 }
3352 
HandleUrlSpanShowShadow(const Offset & localLocation,const Offset & globalOffset,const Color & color)3353 bool RichEditorPattern::HandleUrlSpanShowShadow(const Offset& localLocation, const Offset& globalOffset, const Color& color)
3354 {
3355     RectF textContentRect = contentRect_;
3356     textContentRect.SetTop(contentRect_.GetY() - std::min(baselineOffset_, 0.0f));
3357     textContentRect.SetHeight(contentRect_.Height() - std::max(baselineOffset_, 0.0f));
3358 
3359     auto localLocationOffset = localLocation;
3360     if (selectOverlay_->HasRenderTransform()) {
3361         localLocationOffset = ConvertGlobalToLocalOffset(globalOffset);
3362     }
3363 
3364     PointF textOffset = {static_cast<float>(localLocationOffset.GetX()) - GetTextRect().GetX(),
3365                          static_cast<float>(localLocationOffset.GetY()) - GetTextRect().GetY()};
3366     return ShowShadow(textOffset, color);
3367 }
3368 
HandleDoubleClickOrLongPress(GestureEvent & info)3369 void RichEditorPattern::HandleDoubleClickOrLongPress(GestureEvent& info)
3370 {
3371     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "caretUpdateType=%{public}d", caretUpdateType_);
3372     if (IsPreviewTextInputting()) {
3373         TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "do not handle DoubleClickOrLongPress in previewTextInputting");
3374         return;
3375     }
3376     if (IsDragging()) {
3377         TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "do not handle DoubleClickOrLongPress during drag");
3378         return;
3379     }
3380     auto host = GetHost();
3381     CHECK_NULL_VOID(host);
3382     textResponseType_ = TextResponseType::LONG_PRESS;
3383     if (caretUpdateType_ == CaretUpdateType::LONG_PRESSED) {
3384         HandleUserLongPressEvent(info);
3385     } else if (caretUpdateType_ == CaretUpdateType::DOUBLE_CLICK) {
3386         HandleUserDoubleClickEvent(info);
3387     }
3388     bool isDoubleClick = caretUpdateType_== CaretUpdateType::DOUBLE_CLICK;
3389     if (isDoubleClick && info.GetSourceTool() == SourceTool::FINGER && IsSelected()) {
3390         showSelect_ = true;
3391         host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
3392         ShowSelectOverlay(textSelector_.firstHandle, textSelector_.secondHandle);
3393     }
3394     bool isLongPressSelectArea = BetweenSelection(info.GetGlobalLocation()) && !isDoubleClick;
3395     HandleDraggableFlag(isLongPressSelectArea);
3396     bool isLongPressByMouse = isMousePressed_ && caretUpdateType_== CaretUpdateType::LONG_PRESSED;
3397     if (isLongPressSelectArea && !isLongPressByMouse) {
3398         StartVibratorByLongPress();
3399     }
3400     bool isMouseClickWithShift = shiftFlag_ && info.GetSourceDevice() == SourceType::MOUSE;
3401     bool isInterceptEvent = isLongPressSelectArea || isLongPressByMouse || isMouseClickWithShift;
3402     if (isInterceptEvent) {
3403         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "intercept longPressReason:[%{public}d, %{public}d] shiftSelect:%{public}d",
3404             isLongPressSelectArea, isLongPressByMouse, isMouseClickWithShift);
3405         return;
3406     }
3407     HandleDoubleClickOrLongPress(info, host);
3408     if (IsSelected()) {
3409         TriggerAvoidOnCaretChangeNextFrame();
3410     } else {
3411         ForceTriggerAvoidOnCaretChange(true);
3412     }
3413 }
3414 
ConvertGlobalToLocalOffset(const Offset & globalOffset)3415 Offset RichEditorPattern::ConvertGlobalToLocalOffset(const Offset& globalOffset)
3416 {
3417     parentGlobalOffset_ = GetPaintRectGlobalOffset();
3418     auto localPoint = OffsetF(globalOffset.GetX(), globalOffset.GetY());
3419     selectOverlay_->RevertLocalPointWithTransform(localPoint);
3420     return Offset(localPoint.GetX(), localPoint.GetY());
3421 }
3422 
HandleSelect(GestureEvent & info,int32_t selectStart,int32_t selectEnd)3423 void RichEditorPattern::HandleSelect(GestureEvent& info, int32_t selectStart, int32_t selectEnd)
3424 {
3425     initSelector_ = { selectStart, selectEnd };
3426     if (IsSelected()) {
3427         showSelect_ = true;
3428     }
3429     FireOnSelect(selectStart, selectEnd);
3430     SetCaretPositionWithAffinity({ selectEnd, TextAffinity::UPSTREAM });
3431     MoveCaretToContentRect();
3432     CalculateHandleOffsetAndShowOverlay();
3433     if (IsShowSelectMenuUsingMouse()) {
3434         CloseSelectOverlay();
3435     }
3436     selectionMenuOffset_ = info.GetGlobalLocation();
3437 }
3438 
HandleDoubleClickOrLongPress(GestureEvent & info,RefPtr<FrameNode> host)3439 void RichEditorPattern::HandleDoubleClickOrLongPress(GestureEvent& info, RefPtr<FrameNode> host)
3440 {
3441     auto focusHub = host->GetOrCreateFocusHub();
3442     CHECK_NULL_VOID(focusHub);
3443     isLongPress_ = true;
3444     auto localOffset = info.GetLocalLocation();
3445     if (selectOverlay_->HasRenderTransform()) {
3446         localOffset = ConvertGlobalToLocalOffset(info.GetGlobalLocation());
3447     }
3448     auto textPaintOffset = GetTextRect().GetOffset() - OffsetF(0.0, std::min(baselineOffset_, 0.0f));
3449     Offset textOffset = { localOffset.GetX() - textPaintOffset.GetX(), localOffset.GetY() - textPaintOffset.GetY() };
3450     if (caretUpdateType_ == CaretUpdateType::LONG_PRESSED) {
3451         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "LONG_PRESSED and isEditing=%{public}d", isEditing_);
3452         if (textSelector_.IsValid()) {
3453             CloseSelectOverlay();
3454             ResetSelection();
3455         }
3456         StartVibratorByLongPress();
3457         editingLongPress_ = isEditing_;
3458         previewLongPress_ = !isEditing_;
3459         IF_TRUE(previewLongPress_, CloseKeyboard(true));
3460     }
3461     focusHub->RequestFocusImmediately();
3462     InitSelection(textOffset);
3463     auto selectEnd = textSelector_.GetTextEnd();
3464     auto selectStart = textSelector_.GetTextStart();
3465     HandleSelect(info, selectStart, selectEnd);
3466     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
3467     if (overlayMod_ && caretUpdateType_ == CaretUpdateType::DOUBLE_CLICK) {
3468         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "double click. shall enter edit state.set 1");
3469         HandleOnEditChanged(true);
3470         RequestKeyboard(false, true, true);
3471     }
3472     bool isDoubleClickByMouse =
3473         info.GetSourceDevice() == SourceType::MOUSE && caretUpdateType_ == CaretUpdateType::DOUBLE_CLICK;
3474     bool isShowSelectOverlay = !isDoubleClickByMouse && caretUpdateType_ != CaretUpdateType::LONG_PRESSED;
3475     if (isShowSelectOverlay) {
3476         selectOverlay_->ProcessOverlay({ .menuIsShow = !selectOverlay_->GetIsHandleMoving(), .animation = true });
3477         StopTwinkling();
3478     } else if (selectStart == selectEnd && isDoubleClickByMouse) {
3479         StartTwinkling();
3480     } else {
3481         StopTwinkling();
3482     }
3483 }
3484 
StartVibratorByLongPress()3485 void RichEditorPattern::StartVibratorByLongPress()
3486 {
3487     CHECK_NULL_VOID(isEnableHapticFeedback_);
3488     VibratorUtils::StartVibraFeedback("longPress.light");
3489 }
3490 
HandleUserLongPressEvent(GestureEvent & info)3491 bool RichEditorPattern::HandleUserLongPressEvent(GestureEvent& info)
3492 {
3493     auto longPressFunc = [](RefPtr<SpanItem> item, GestureEvent& info) -> bool {
3494         if (item && item->onLongPress) {
3495             item->onLongPress(info);
3496             return true;
3497         }
3498         return false;
3499     };
3500     return HandleUserGestureEvent(info, std::move(longPressFunc));
3501 }
3502 
HandleUserDoubleClickEvent(GestureEvent & info)3503 bool RichEditorPattern::HandleUserDoubleClickEvent(GestureEvent& info)
3504 {
3505     auto doubleClickFunc = [](RefPtr<SpanItem> item, GestureEvent& info) -> bool {
3506         if (item && item->onDoubleClick) {
3507             item->onDoubleClick(info);
3508             return true;
3509         }
3510         return false;
3511     };
3512     return HandleUserGestureEvent(info, std::move(doubleClickFunc));
3513 }
3514 
HandleMenuCallbackOnSelectAll()3515 void RichEditorPattern::HandleMenuCallbackOnSelectAll()
3516 {
3517     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "HandleMenuCallbackOnSelectAll");
3518     auto textSize = GetTextContentLength();
3519     textSelector_.Update(0, textSize);
3520     SetCaretPosition(textSize);
3521     MoveCaretToContentRect();
3522 
3523     CalculateHandleOffsetAndShowOverlay();
3524     if (selectOverlay_->IsUsingMouse()) {
3525         CloseSelectOverlay();
3526         StopTwinkling();
3527     }
3528     FireOnSelect(textSelector_.GetTextStart(), textSelector_.GetTextEnd());
3529     auto selectOverlayInfo = selectOverlay_->GetSelectOverlayInfo();
3530     if (selectOverlayInfo && selectOverlay_->IsUsingMouse()) {
3531         textResponseType_ = static_cast<TextResponseType>(selectOverlayInfo->menuInfo.responseType.value_or(0));
3532     } else {
3533         textResponseType_ = TextResponseType::LONG_PRESS;
3534     }
3535     showSelect_ = true;
3536     if (!selectOverlay_->IsUsingMouse()) {
3537         selectOverlay_->ProcessOverlay({ .animation = true });
3538     }
3539     auto host = GetHost();
3540     CHECK_NULL_VOID(host);
3541     TriggerAvoidOnCaretChangeNextFrame();
3542     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
3543 }
3544 
InitLongPressEvent(const RefPtr<GestureEventHub> & gestureHub)3545 void RichEditorPattern::InitLongPressEvent(const RefPtr<GestureEventHub>& gestureHub)
3546 {
3547     CHECK_NULL_VOID(!longPressEvent_);
3548     auto longPressCallback = [weak = WeakClaim(this)](GestureEvent& info) {
3549         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "long press callback");
3550         auto pattern = weak.Upgrade();
3551         CHECK_NULL_VOID(pattern);
3552         pattern->sourceType_ = info.GetSourceDevice();
3553         pattern->HandleLongPress(info);
3554     };
3555     longPressEvent_ = MakeRefPtr<LongPressEvent>(std::move(longPressCallback));
3556     gestureHub->SetLongPressEvent(longPressEvent_);
3557 
3558     auto onTextSelectorChange = [weak = WeakClaim(this), &selector = textSelector_]() {
3559         auto pattern = weak.Upgrade();
3560         CHECK_NULL_VOID(pattern);
3561         if (!selector.SelectNothing()) {
3562             pattern->StopTwinkling();
3563         }
3564         IF_PRESENT(pattern->oneStepDragController_,
3565         SetEnableEventResponse(selector, pattern->imageNodes, pattern->builderNodes));
3566         pattern->FireOnSelectionChange(selector);
3567         auto frameNode = pattern->GetHost();
3568         CHECK_NULL_VOID(frameNode);
3569         frameNode->OnAccessibilityEvent(AccessibilityEventType::TEXT_SELECTION_UPDATE);
3570     };
3571     textSelector_.SetOnAccessibility(std::move(onTextSelectorChange));
3572 }
3573 
UpdateSelector(int32_t start,int32_t end)3574 void RichEditorPattern::UpdateSelector(int32_t start, int32_t end)
3575 {
3576     AdjustSelector(start, end);
3577     textSelector_.Update(start, end);
3578 }
3579 
AdjustSelector(int32_t & start,int32_t & end,SelectorAdjustPolicy policy)3580 void RichEditorPattern::AdjustSelector(int32_t& start, int32_t& end, SelectorAdjustPolicy policy)
3581 {
3582     AdjustSelector(start, HandleType::FIRST, policy);
3583     AdjustSelector(end, HandleType::SECOND, policy);
3584 }
3585 
AdjustSelector(int32_t & index,HandleType handleType,SelectorAdjustPolicy policy)3586 void RichEditorPattern::AdjustSelector(int32_t& index, HandleType handleType,  SelectorAdjustPolicy policy)
3587 {
3588     bool isAdjust = AdjustSelectorForSymbol(index, handleType, policy);
3589     CHECK_NULL_VOID(!isAdjust);
3590     AdjustSelectorForEmoji(index, handleType, policy);
3591 }
3592 
AdjustSelectorForSymbol(int32_t & index,HandleType handleType,SelectorAdjustPolicy policy)3593 bool RichEditorPattern::AdjustSelectorForSymbol(int32_t& index, HandleType handleType, SelectorAdjustPolicy policy)
3594 {
3595     auto it = GetSpanIter(index);
3596     CHECK_NULL_RETURN((it != spans_.end()), false);
3597     auto spanItem = *it;
3598     CHECK_NULL_RETURN(spanItem, false);
3599 
3600     auto spanStart = spanItem->rangeStart;
3601     auto spanEnd = spanItem->position;
3602     if (spanItem->unicode != 0 && spanItem->Contains(index)) {
3603         auto it = SELECTOR_ADJUST_DIR_MAP.find({ handleType, policy });
3604         index = (it->second == MoveDirection::BACKWARD) ? spanStart : spanEnd;
3605         return true;
3606     }
3607     return false;
3608 }
3609 
GetEmojiRelation(int index)3610 EmojiRelation RichEditorPattern::GetEmojiRelation(int index)
3611 {
3612     auto it = GetSpanIter(index);
3613     CHECK_NULL_RETURN((it != spans_.end()), EmojiRelation::NO_EMOJI);
3614     auto spanItem = *it;
3615     CHECK_NULL_RETURN(spanItem, EmojiRelation::NO_EMOJI);
3616     int32_t emojiStartIndex;
3617     int32_t emojiEndIndex;
3618     return TextEmojiProcessor::GetIndexRelationToEmoji(index - spanItem->rangeStart, spanItem->content,
3619         emojiStartIndex, emojiEndIndex);
3620 }
3621 
AdjustSelectorForEmoji(int & index,HandleType handleType,SelectorAdjustPolicy policy)3622 bool RichEditorPattern::AdjustSelectorForEmoji(int& index, HandleType handleType, SelectorAdjustPolicy policy)
3623 {
3624     auto it = GetSpanIter(index);
3625     CHECK_NULL_RETURN((it != spans_.end()), false);
3626     auto spanItem = *it;
3627     CHECK_NULL_RETURN(spanItem, false);
3628 
3629     int32_t emojiStartIndex;
3630     int32_t emojiEndIndex;
3631     int32_t spanStart = spanItem->rangeStart;
3632     EmojiRelation relation = TextEmojiProcessor::GetIndexRelationToEmoji(index - spanStart, spanItem->content,
3633         emojiStartIndex, emojiEndIndex);
3634     if (relation != EmojiRelation::IN_EMOJI && relation != EmojiRelation::MIDDLE_EMOJI) {
3635         // no need adjusting when index is not warpped in emojis
3636         return false;
3637     }
3638     int32_t start = 0;
3639     int32_t end = 0;
3640     bool isBoundaryGet = paragraphs_.GetWordBoundary(index, start, end); // boundary from engine
3641     if (isBoundaryGet) {
3642         if (handleType == HandleType::FIRST) {
3643             index = start;
3644         } else {
3645             if (index > start) {
3646                 // index to emoji, move index to end of emoji, double check "in emoji state"
3647                 index = end;
3648             }
3649         }
3650     } else {
3651         if (relation == EmojiRelation::IN_EMOJI) {
3652             int32_t indexInSpan = (handleType == HandleType::FIRST) ? emojiStartIndex : emojiEndIndex;
3653             index = spanItem->rangeStart + indexInSpan;
3654         }
3655     }
3656     TAG_LOGD(AceLogTag::ACE_RICH_TEXT,
3657         "index=%{public}d, handleType=%{public}d, emojiRange=[%{public}d,%{public}d] isBoundaryGet=%{public}d "\
3658         "boundary=[%{public}d, %{public}d]",
3659         index, handleType, emojiStartIndex, emojiEndIndex, isBoundaryGet, start, end);
3660     return true;
3661 }
3662 
GetSpanIter(int32_t index)3663 std::list<RefPtr<SpanItem>>::iterator RichEditorPattern::GetSpanIter(int32_t index)
3664 {
3665     return std::find_if(spans_.begin(), spans_.end(), [index](const RefPtr<SpanItem>& spanItem) {
3666         return spanItem->rangeStart <= index && index < spanItem->position;
3667     });
3668 }
3669 
GetSpanType(int32_t index)3670 SpanItemType RichEditorPattern::GetSpanType(int32_t index)
3671 {
3672     auto it = GetSpanIter(index);
3673     CHECK_NULL_RETURN((it != spans_.end()), SpanItemType::NORMAL);
3674     auto& spanItem = *it;
3675     CHECK_NULL_RETURN(spanItem, SpanItemType::NORMAL);
3676     return spanItem->spanItemType;
3677 }
3678 
GetGlyphPositionAtCoordinate(int32_t x,int32_t y)3679 PositionWithAffinity RichEditorPattern::GetGlyphPositionAtCoordinate(int32_t x, int32_t y)
3680 {
3681     Offset offset(x, y);
3682     return paragraphs_.GetGlyphPositionAtCoordinate(ConvertTouchOffsetToTextOffset(offset));
3683 }
3684 
InitDragDropEvent()3685 void RichEditorPattern::InitDragDropEvent()
3686 {
3687     auto host = GetHost();
3688     CHECK_NULL_VOID(host);
3689     auto gestureHub = host->GetOrCreateGestureEventHub();
3690     CHECK_NULL_VOID(gestureHub);
3691     gestureHub->InitDragDropEvent();
3692     gestureHub->SetThumbnailCallback(GetThumbnailCallback());
3693     auto eventHub = host->GetEventHub<EventHub>();
3694     CHECK_NULL_VOID(eventHub);
3695     auto onDragMove = [weakPtr = WeakClaim(this)](
3696                           const RefPtr<OHOS::Ace::DragEvent>& event, const std::string& extraParams) {
3697         auto pattern = weakPtr.Upgrade();
3698         CHECK_NULL_VOID(pattern);
3699         pattern->showSelect_ = false;
3700         pattern->OnDragMove(event);
3701     };
3702     eventHub->SetOnDragMove(std::move(onDragMove));
3703     OnDragStartAndEnd();
3704     onDragDropAndLeave();
3705 }
3706 
OnDragStartAndEnd()3707 void RichEditorPattern::OnDragStartAndEnd()
3708 {
3709     auto host = GetHost();
3710     CHECK_NULL_VOID(host);
3711     auto eventHub = host->GetEventHub<EventHub>();
3712     CHECK_NULL_VOID(eventHub);
3713     auto onDragStart = [weakPtr = WeakClaim(this)](const RefPtr<OHOS::Ace::DragEvent>& event,
3714                            const std::string& extraParams) -> NG::DragDropInfo {
3715         NG::DragDropInfo itemInfo;
3716         auto pattern = weakPtr.Upgrade();
3717         CHECK_NULL_RETURN(pattern, itemInfo);
3718         return pattern->HandleDragStart(event, extraParams);
3719     };
3720     eventHub->SetDefaultOnDragStart(std::move(onDragStart));
3721     auto onDragEnd = [weakPtr = WeakClaim(this), scopeId = Container::CurrentId()](
3722                          const RefPtr<OHOS::Ace::DragEvent>& event) {
3723         ContainerScope scope(scopeId);
3724         auto pattern = weakPtr.Upgrade();
3725         CHECK_NULL_VOID(pattern);
3726         pattern->isOnlyImageDrag_ = false;
3727         pattern->isDragSponsor_ = false;
3728         pattern->dragRange_ = { 0, 0 };
3729         pattern->showSelect_ = true;
3730         pattern->StopAutoScroll();
3731         pattern->ClearRedoOperationRecords();
3732         pattern->OnDragEnd(event);
3733     };
3734     eventHub->SetOnDragEnd(std::move(onDragEnd));
3735 }
3736 
HandleDragStart(const RefPtr<Ace::DragEvent> & event,const std::string & extraParams)3737 NG::DragDropInfo RichEditorPattern::HandleDragStart(const RefPtr<Ace::DragEvent>& event, const std::string& extraParams)
3738 {
3739     if (!isDragSponsor_) {
3740         isDragSponsor_ = true;
3741         dragRange_ = { textSelector_.GetTextStart(), textSelector_.GetTextEnd() };
3742     }
3743     timestamp_ = std::chrono::system_clock::now().time_since_epoch().count();
3744     auto eventHub = GetEventHub<RichEditorEventHub>();
3745     CHECK_NULL_RETURN(eventHub, {});
3746     eventHub->SetTimestamp(timestamp_);
3747     showSelect_ = false;
3748     auto dropInfo = OnDragStart(event, extraParams);
3749     if (isOnlyImageDrag_) {
3750         recoverStart_ = -1;
3751         recoverEnd_ = -1;
3752     }
3753     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "HandleDragStart dragStatus=%{public}d", status_);
3754     return dropInfo;
3755 }
3756 
onDragDropAndLeave()3757 void RichEditorPattern::onDragDropAndLeave()
3758 {
3759     auto host = GetHost();
3760     CHECK_NULL_VOID(host);
3761     auto eventHub = host->GetEventHub<EventHub>();
3762     CHECK_NULL_VOID(eventHub);
3763     auto onDragDrop = [weakPtr = WeakClaim(this), scopeId = Container::CurrentId()](
3764                           const RefPtr<OHOS::Ace::DragEvent>& event, const std::string& value) {
3765         ContainerScope scope(scopeId);
3766         auto pattern = weakPtr.Upgrade();
3767         CHECK_NULL_VOID(pattern);
3768         auto host = pattern->GetHost();
3769         CHECK_NULL_VOID(host);
3770         auto eventHub = host->GetEventHub<EventHub>();
3771         CHECK_NULL_VOID(eventHub);
3772         if (!eventHub->IsEnabled()) {
3773             return;
3774         }
3775         pattern->status_ = Status::ON_DROP;
3776         pattern->HandleOnDragDrop(event);
3777         pattern->status_ = Status::NONE;
3778     };
3779     eventHub->SetOnDrop(std::move(onDragDrop));
3780     auto onDragDragLeave = [weakPtr = WeakClaim(this), scopeId = Container::CurrentId()](
3781                                const RefPtr<OHOS::Ace::DragEvent>& event, const std::string& value) {
3782         ContainerScope scope(scopeId);
3783         auto pattern = weakPtr.Upgrade();
3784         CHECK_NULL_VOID(pattern);
3785         pattern->StopAutoScroll();
3786     };
3787     eventHub->SetOnDragLeave(onDragDragLeave);
3788 }
3789 
ClearDragDropEvent()3790 void RichEditorPattern::ClearDragDropEvent()
3791 {
3792     auto host = GetHost();
3793     CHECK_NULL_VOID(host);
3794     auto gestureHub = host->GetOrCreateGestureEventHub();
3795     CHECK_NULL_VOID(gestureHub);
3796     gestureHub->SetIsTextDraggable(false);
3797     auto eventHub = host->GetEventHub<EventHub>();
3798     CHECK_NULL_VOID(eventHub);
3799     eventHub->SetDefaultOnDragStart(nullptr);
3800     eventHub->SetOnDragEnter(nullptr);
3801     eventHub->SetOnDragMove(nullptr);
3802     eventHub->SetOnDragLeave(nullptr);
3803     eventHub->SetOnDragEnd(nullptr);
3804     eventHub->SetOnDrop(nullptr);
3805 }
3806 
OnDragMove(const RefPtr<OHOS::Ace::DragEvent> & event)3807 void RichEditorPattern::OnDragMove(const RefPtr<OHOS::Ace::DragEvent>& event)
3808 {
3809     auto weakPtr = WeakClaim(this);
3810     auto pattern = weakPtr.Upgrade();
3811     CHECK_NULL_VOID(pattern);
3812     pattern->showSelect_ = true;
3813     auto pipeline = PipelineBase::GetCurrentContext();
3814     CHECK_NULL_VOID(pipeline);
3815     auto theme = pipeline->GetTheme<RichEditorTheme>();
3816     CHECK_NULL_VOID(theme);
3817     auto touchX = event->GetX();
3818     auto touchY = event->GetY();
3819     auto textRect = GetTextRect();
3820     textRect.SetTop(textRect.GetY() - std::min(baselineOffset_, 0.0f));
3821     Offset textOffset = { touchX - textRect.GetX() - GetParentGlobalOffset().GetX(),
3822         touchY - textRect.GetY() - GetParentGlobalOffset().GetY() - theme->GetInsertCursorOffset().ConvertToPx() };
3823     auto position = isShowPlaceholder_? 0 : paragraphs_.GetIndex(textOffset);
3824     ResetSelection();
3825     CloseSelectOverlay();
3826     SetCaretPosition(position);
3827     CalcAndRecordLastClickCaretInfo(textOffset);
3828     auto [caretOffset, caretHeight] = CalculateCaretOffsetAndHeight();
3829     CHECK_NULL_VOID(overlayMod_);
3830     auto overlayModifier = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
3831     overlayModifier->SetCaretOffsetAndHeight(caretOffset, caretHeight);
3832 
3833     AutoScrollParam param = { .autoScrollEvent = AutoScrollEvent::DRAG, .showScrollbar = true };
3834     auto localOffset = OffsetF(touchX, touchY) - parentGlobalOffset_;
3835     AutoScrollByEdgeDetection(param, localOffset, EdgeDetectionStrategy::IN_BOUNDARY);
3836 }
3837 
OnDragEnd(const RefPtr<Ace::DragEvent> & event)3838 void RichEditorPattern::OnDragEnd(const RefPtr<Ace::DragEvent>& event)
3839 {
3840     ResetDragRecordSize(-1);
3841     auto host = GetHost();
3842     CHECK_NULL_VOID(host);
3843     if (status_ == Status::DRAGGING) {
3844         status_ = Status::NONE;
3845     }
3846     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "OnDragEnd dragStatus=%{public}d", status_);
3847     ResetDragSpanItems();
3848     if (recoverDragResultObjects_.empty()) {
3849         return;
3850     }
3851     UpdateSpanItemDragStatus(recoverDragResultObjects_, false);
3852     recoverDragResultObjects_.clear();
3853     auto focusHub = GetFocusHub();
3854     if (event && focusHub && event->GetResult() != DragRet::DRAG_SUCCESS && focusHub->IsFocusable()) {
3855         HandleSelectionChange(recoverStart_, recoverEnd_);
3856         showSelect_ = true;
3857         CalculateHandleOffsetAndShowOverlay();
3858         ResetSelection();
3859     }
3860     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
3861 }
3862 
ToStyledString(int32_t start,int32_t end)3863 RefPtr<SpanString> RichEditorPattern::ToStyledString(int32_t start, int32_t end)
3864 {
3865     auto length = GetTextContentLength();
3866     int32_t realStart = (start == -1) ? 0 : std::clamp(start, 0, length);
3867     int32_t realEnd = (end == -1) ? length : std::clamp(end, 0, length);
3868     if (realStart > realEnd) {
3869         std::swap(realStart, realEnd);
3870     }
3871     RefPtr<SpanString> spanString = MakeRefPtr<SpanString>("");
3872     if (aiWriteAdapter_->GetAIWrite()) {
3873         SetSubSpansWithAIWrite(spanString, realStart, realEnd);
3874     } else {
3875         SetSubSpans(spanString, realStart, realEnd);
3876     }
3877     SetSubMap(spanString);
3878     return spanString;
3879 }
3880 
FromStyledString(const RefPtr<SpanString> & spanString)3881 SelectionInfo RichEditorPattern::FromStyledString(const RefPtr<SpanString>& spanString)
3882 {
3883     std::list<ResultObject> resultObjects;
3884     int32_t start = 0;
3885     int32_t end = 0;
3886     if (spanString && !spanString->GetSpanItems().empty()) {
3887         auto spans = spanString->GetSpanItems();
3888         int32_t index = 0;
3889         std::for_each(spans.begin(), spans.end(),
3890             [&index, &resultObjects, weak = WeakClaim(this)](RefPtr<SpanItem>& item) {
3891                 CHECK_NULL_VOID(item);
3892                 auto pattern = weak.Upgrade();
3893                 CHECK_NULL_VOID(pattern);
3894                 auto obj = item->GetSpanResultObject(item->interval.first, item->interval.second);
3895                 if (AceType::InstanceOf<ImageSpanItem>(item)) {
3896                     obj.imageStyle = pattern->GetImageStyleBySpanItem(item);
3897                 } else if (!AceType::InstanceOf<CustomSpanItem>(item)) {
3898                     obj.textStyle = pattern->GetTextStyleBySpanItem(item);
3899                 }
3900                 obj.spanPosition.spanIndex = index;
3901                 ++index;
3902                 if (obj.isInit) {
3903                     resultObjects.emplace_back(obj);
3904                 }
3905         });
3906         if (spans.back()) {
3907             end = spans.back()->interval.second;
3908         }
3909         if (spans.front()) {
3910             start = spans.front()->interval.first;
3911         }
3912     }
3913     SelectionInfo selection;
3914     selection.SetSelectionEnd(end);
3915     selection.SetSelectionStart(start);
3916     selection.SetResultObjectList(resultObjects);
3917     return selection;
3918 }
3919 
GetTextStyleBySpanItem(const RefPtr<SpanItem> & spanItem)3920 TextStyleResult RichEditorPattern::GetTextStyleBySpanItem(const RefPtr<SpanItem>& spanItem)
3921 {
3922     TextStyleResult textStyle;
3923     CHECK_NULL_RETURN(spanItem, textStyle);
3924     auto theme = GetTheme<RichEditorTheme>();
3925     TextStyle style = theme ? theme->GetTextStyle() : TextStyle();
3926     if (spanItem->fontStyle) {
3927         textStyle.fontColor = spanItem->fontStyle->GetTextColor().value_or(style.GetTextColor()).ColorToString();
3928         textStyle.fontSize =
3929             spanItem->fontStyle->GetFontSize().value_or(Dimension(16.0f, DimensionUnit::VP)).ConvertToFp();
3930         textStyle.fontStyle =
3931             static_cast<int32_t>(spanItem->fontStyle->GetItalicFontStyle().value_or(OHOS::Ace::FontStyle::NORMAL));
3932         textStyle.fontWeight = static_cast<int32_t>(spanItem->fontStyle->GetFontWeight().value_or(FontWeight::NORMAL));
3933         std::string fontFamilyValue;
3934         const std::vector<std::string> defaultFontFamily = { "HarmonyOS Sans" };
3935         auto fontFamily = spanItem->fontStyle->GetFontFamily().value_or(defaultFontFamily);
3936         for (const auto& str : fontFamily) {
3937             fontFamilyValue += str;
3938             fontFamilyValue += ",";
3939         }
3940         fontFamilyValue = fontFamilyValue.substr(0, fontFamilyValue.size() > 0 ? fontFamilyValue.size() - 1 : 0);
3941         textStyle.fontFamily = !fontFamilyValue.empty() ? fontFamilyValue : defaultFontFamily.front();
3942         textStyle.decorationType =
3943             static_cast<int32_t>(spanItem->fontStyle->GetTextDecoration().value_or(TextDecoration::NONE));
3944         textStyle.decorationColor =
3945             spanItem->fontStyle->GetTextDecorationColor().value_or(style.GetTextDecorationColor()).ColorToString();
3946         textStyle.decorationStyle =
3947             static_cast<int32_t>(spanItem->fontStyle->GetTextDecorationStyle().value_or(TextDecorationStyle::SOLID));
3948         textStyle.fontFeature = spanItem->fontStyle->GetFontFeature().value_or(ParseFontFeatureSettings("\"pnum\" 1"));
3949         textStyle.letterSpacing = spanItem->fontStyle->GetLetterSpacing().value_or(Dimension()).ConvertToFp();
3950     }
3951     if (spanItem->textLineStyle) {
3952         textStyle.lineHeight = spanItem->textLineStyle->GetLineHeight().value_or(Dimension()).ConvertToFp();
3953         textStyle.lineSpacing = spanItem->textLineStyle->GetLineSpacing().value_or(Dimension()).ConvertToFp();
3954         textStyle.textAlign = static_cast<int32_t>(spanItem->textLineStyle->GetTextAlign().value_or(TextAlign::START));
3955         auto lm = spanItem->textLineStyle->GetLeadingMargin();
3956         if (lm.has_value()) {
3957             textStyle.leadingMarginSize[RichEditorLeadingRange::LEADING_START] = lm.value().size.Width().ToString();
3958             textStyle.leadingMarginSize[RichEditorLeadingRange::LEADING_END] = lm.value().size.Height().ToString();
3959         }
3960         textStyle.wordBreak =
3961             static_cast<int32_t>(spanItem->textLineStyle->GetWordBreak().value_or(WordBreak::BREAK_WORD));
3962         textStyle.lineBreakStrategy =
3963             static_cast<int32_t>(spanItem->textLineStyle->GetLineBreakStrategy().value_or(LineBreakStrategy::GREEDY));
3964     }
3965     return textStyle;
3966 }
3967 
GetImageStyleBySpanItem(const RefPtr<SpanItem> & spanItem)3968 ImageStyleResult RichEditorPattern::GetImageStyleBySpanItem(const RefPtr<SpanItem>& spanItem)
3969 {
3970     ImageStyleResult imageStyle;
3971     auto imageSpanItem = DynamicCast<ImageSpanItem>(spanItem);
3972     CHECK_NULL_RETURN(imageSpanItem, imageStyle);
3973     auto imageAttributeOp = imageSpanItem->options.imageAttribute;
3974     CHECK_NULL_RETURN(imageAttributeOp.has_value(), imageStyle);
3975     auto imageSizeOp = imageAttributeOp->size;
3976     if (imageSizeOp.has_value() && imageSizeOp->width.has_value() && imageSizeOp->height.has_value()) {
3977         imageStyle.size[RichEditorImageSize::SIZEWIDTH] = imageSizeOp->width->ConvertToPx();
3978         imageStyle.size[RichEditorImageSize::SIZEHEIGHT] = imageSizeOp->height->ConvertToPx();
3979     }
3980     if (imageAttributeOp->verticalAlign.has_value()) {
3981         imageStyle.verticalAlign = static_cast<int32_t>(imageAttributeOp->verticalAlign.value());
3982     }
3983     if (imageAttributeOp->objectFit.has_value()) {
3984         imageStyle.objectFit = static_cast<int32_t>(imageAttributeOp->objectFit.value());
3985     }
3986     if (imageAttributeOp->marginProp.has_value()) {
3987         imageStyle.margin = imageAttributeOp->marginProp->ToString();
3988     }
3989     if (imageAttributeOp->borderRadius.has_value()) {
3990         imageStyle.borderRadius = imageAttributeOp->borderRadius->ToString();
3991     }
3992     return imageStyle;
3993 }
3994 
SetSubSpansWithAIWrite(RefPtr<SpanString> & spanString,int32_t start,int32_t end)3995 void RichEditorPattern::SetSubSpansWithAIWrite(RefPtr<SpanString>& spanString, int32_t start, int32_t end)
3996 {
3997     placeholderSpansMap_.clear();
3998     CHECK_NULL_VOID(spanString);
3999     std::list<RefPtr<SpanItem>> subSpans;
4000     std::string text;
4001     size_t index = 0;
4002     size_t placeholderGains = 0;
4003     for (const auto& spanItem : spans_) {
4004         if (!spanItem) {
4005             continue;
4006         }
4007         auto oldEnd = spanItem->position;
4008         auto oldStart = spanItem->rangeStart;
4009         if (oldEnd <= start || oldStart >= end) {
4010             continue;
4011         }
4012         RefPtr<SpanItem> newSpanItem = MakeRefPtr<SpanItem>();
4013         auto spanStart = oldStart <= start ? 0 : oldStart - start;
4014         auto spanEnd = oldEnd < end ? oldEnd - start : end - start;
4015         spanStart += static_cast<int32_t>(placeholderGains);
4016         if (spanItem->spanItemType == SpanItemType::NORMAL) {
4017             newSpanItem = spanItem->GetSameStyleSpanItem();
4018             newSpanItem->content = StringUtils::ToString(
4019                 StringUtils::ToWstring(spanItem->content)
4020                     .substr(std::max(start - oldStart, 0), std::min(end, oldEnd) - std::max(start, oldStart)));
4021         } else {
4022             InitPlaceholderSpansMap(newSpanItem, spanItem, index, placeholderGains);
4023             spanEnd += static_cast<int32_t>(placeholderGains);
4024         }
4025         newSpanItem->interval = {spanStart, spanEnd};
4026         newSpanItem->position = spanStart;
4027         newSpanItem->rangeStart = spanEnd;
4028         newSpanItem->textLineStyle->ResetLeadingMargin();
4029         text.append(newSpanItem->content);
4030         subSpans.emplace_back(newSpanItem);
4031     }
4032     spanString->SetString(text);
4033     spanString->SetSpanItems(std::move(subSpans));
4034 }
4035 
InitPlaceholderSpansMap(RefPtr<SpanItem> & newSpanItem,const RefPtr<SpanItem> & spanItem,size_t & index,size_t & placeholderGains)4036 void RichEditorPattern::InitPlaceholderSpansMap(
4037     RefPtr<SpanItem>& newSpanItem, const RefPtr<SpanItem>& spanItem, size_t& index, size_t& placeholderGains)
4038 {
4039     newSpanItem->content = "![id" + std::to_string(index++) + "]";
4040     switch (spanItem->spanItemType) {
4041         case SpanItemType::SYMBOL: {
4042             placeholderSpansMap_[newSpanItem->content] = spanItem;
4043             placeholderGains += PLACEHOLDER_LENGTH - SYMBOL_CONTENT_LENGTH;
4044             break;
4045         }
4046         case SpanItemType::CustomSpan: {
4047             if (!isSpanStringMode_) {
4048                 placeholderSpansMap_[newSpanItem->content] = spanItem;
4049             } else {
4050                 auto customSpanItem = DynamicCast<CustomSpanItem>(spanItem);
4051                 placeholderSpansMap_[newSpanItem->content] = customSpanItem;
4052             }
4053             placeholderGains += PLACEHOLDER_LENGTH - CUSTOM_CONTENT_LENGTH;
4054             break;
4055         }
4056         case SpanItemType::IMAGE: {
4057             placeholderSpansMap_[newSpanItem->content] = spanItem;
4058             placeholderGains += PLACEHOLDER_LENGTH - CUSTOM_CONTENT_LENGTH;
4059             break;
4060         }
4061         default:
4062             break;
4063     }
4064 }
4065 
SetSubSpans(RefPtr<SpanString> & spanString,int32_t start,int32_t end)4066 void RichEditorPattern::SetSubSpans(RefPtr<SpanString>& spanString, int32_t start, int32_t end)
4067 {
4068     CHECK_NULL_VOID(spanString);
4069     std::list<RefPtr<SpanItem>> subSpans;
4070     std::string text;
4071     for (const auto& spanItem : spans_) {
4072         if (!spanItem ||
4073             (!AceType::InstanceOf<ImageSpanItem>(spanItem) && AceType::InstanceOf<PlaceholderSpanItem>(spanItem))) {
4074             continue;
4075         }
4076         auto spanEndPos = spanItem->position;
4077         auto spanStartPos = spanItem->rangeStart;
4078         if (spanEndPos > start && spanStartPos < end) {
4079             int32_t oldStart = spanStartPos;
4080             int32_t oldEnd = spanEndPos;
4081             auto spanStart = oldStart <= start ? 0 : oldStart - start;
4082             auto spanEnd = oldEnd < end ? oldEnd - start : end - start;
4083             auto newSpanItem = GetSameSpanItem(spanItem);
4084             CHECK_NULL_CONTINUE(newSpanItem);
4085             newSpanItem->spanItemType = spanItem->spanItemType;
4086             newSpanItem->interval = {spanStart, spanEnd};
4087             newSpanItem->position = spanStart;
4088             newSpanItem->rangeStart = spanEnd;
4089             newSpanItem->content = StringUtils::ToString(
4090                 StringUtils::ToWstring(spanItem->content)
4091                     .substr(std::max(start - oldStart, 0), std::min(end, oldEnd) - std::max(start, oldStart)));
4092             text.append(newSpanItem->content);
4093             subSpans.emplace_back(newSpanItem);
4094         }
4095     }
4096     spanString->SetString(text);
4097     spanString->SetSpanItems(std::move(subSpans));
4098 }
4099 
GetSameSpanItem(const RefPtr<SpanItem> & spanItem)4100 RefPtr<SpanItem> RichEditorPattern::GetSameSpanItem(const RefPtr<SpanItem>& spanItem)
4101 {
4102     CHECK_NULL_RETURN(spanItem, nullptr);
4103     if (spanItem->spanItemType == SpanItemType::IMAGE) {
4104         auto imageSpanItem = DynamicCast<ImageSpanItem>(spanItem);
4105         CHECK_NULL_RETURN(imageSpanItem, nullptr);
4106         auto newSpanItem = MakeRefPtr<ImageSpanItem>();
4107         auto options = imageSpanItem->options;
4108         if (!options.imagePixelMap) {
4109             auto imageNode = GetImageSpanNodeBySpanItem(imageSpanItem);
4110             CHECK_NULL_RETURN(imageNode, nullptr);
4111             auto pattern = imageNode->GetPattern<ImagePattern>();
4112             CHECK_NULL_RETURN(pattern, nullptr);
4113             auto image = pattern->GetCanvasImage();
4114             CHECK_NULL_RETURN(image, nullptr);
4115             auto pixelMap = image->GetPixelMap();
4116             if (!pixelMap) {
4117                 pixelMap = imageNode->GetPixelMap();
4118             }
4119             options.imagePixelMap = pixelMap;
4120         }
4121         newSpanItem->SetImageSpanOptions(options);
4122         return newSpanItem;
4123     } else if (spanItem->spanItemType == SpanItemType::NORMAL) {
4124         auto newSpanItem = spanItem->GetSameStyleSpanItem();
4125         return newSpanItem;
4126     }
4127     return nullptr;
4128 }
4129 
GetImageSpanNodeBySpanItem(const RefPtr<ImageSpanItem> & spanItem)4130 RefPtr<ImageSpanNode> RichEditorPattern::GetImageSpanNodeBySpanItem(const RefPtr<ImageSpanItem>& spanItem)
4131 {
4132     auto host = GetHost();
4133     CHECK_NULL_RETURN(host, nullptr);
4134     auto uiNodes = host->GetChildren();
4135     auto it = std::find_if(uiNodes.begin(), uiNodes.end(), [spanItem](const RefPtr<UINode>& uiNode) {
4136         auto imageSpanNode = DynamicCast<ImageSpanNode>(uiNode);
4137         CHECK_NULL_RETURN(imageSpanNode, false);
4138         return imageSpanNode->GetSpanItem() == spanItem;
4139     });
4140     CHECK_NULL_RETURN(it != uiNodes.end(), nullptr);
4141     return DynamicCast<ImageSpanNode>(*it);
4142 }
4143 
SetSubMap(RefPtr<SpanString> & spanString)4144 void RichEditorPattern::SetSubMap(RefPtr<SpanString>& spanString)
4145 {
4146     CHECK_NULL_VOID(spanString);
4147     auto subSpans = spanString->GetSpanItems();
4148     std::unordered_map<SpanType, std::list<RefPtr<SpanBase>>> subMap;
4149     for (auto& spanItem : subSpans) {
4150         if (!spanItem) {
4151             continue;
4152         }
4153         auto start = spanItem->rangeStart;
4154         auto end = spanItem->position;
4155         std::list<RefPtr<SpanBase>> spanBases;
4156         if (spanItem->spanItemType == NG::SpanItemType::IMAGE) {
4157             spanBases = { spanString->ToImageSpan(spanItem, start, end) };
4158         } else if (spanItem->spanItemType == NG::SpanItemType::NORMAL) {
4159             spanBases = { spanString->ToFontSpan(spanItem, start, end),
4160                 spanString->ToDecorationSpan(spanItem, start, end),
4161                 spanString->ToBaselineOffsetSpan(spanItem, start, end),
4162                 spanString->ToLetterSpacingSpan(spanItem, start, end),
4163                 spanString->ToGestureSpan(spanItem, start, end),
4164                 spanString->ToParagraphStyleSpan(spanItem, start, end),
4165                 spanString->ToLineHeightSpan(spanItem, start, end) };
4166         }
4167         for (auto& spanBase : spanBases) {
4168             if (!spanBase) {
4169                 continue;
4170             }
4171             auto it = subMap.find(spanBase->GetSpanType());
4172             if (it == subMap.end()) {
4173                 subMap.insert({ spanBase->GetSpanType(), { spanBase } });
4174             } else {
4175                 it->second.emplace_back(std::move(spanBase));
4176             }
4177         }
4178     }
4179     spanString->SetSpanMap(std::move(subMap));
4180 }
4181 
AddSpanByPasteData(const RefPtr<SpanString> & spanString)4182 void RichEditorPattern::AddSpanByPasteData(const RefPtr<SpanString>& spanString)
4183 {
4184     CHECK_NULL_VOID(spanString);
4185     if (spanString->GetSpansMap().empty()) {
4186         CompleteStyledString(const_cast<RefPtr<SpanString>&>(spanString));
4187     }
4188     if (isSpanStringMode_) {
4189         InsertStyledStringByPaste(spanString);
4190     } else {
4191         AddSpansByPaste(spanString->GetSpanItems());
4192     }
4193 
4194     if (aiWriteAdapter_->GetAIWrite()) {
4195         return;
4196     }
4197     StartTwinkling();
4198     auto host = GetHost();
4199     CHECK_NULL_VOID(host);
4200     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
4201     host->MarkModifyDone();
4202 }
4203 
CompleteStyledString(RefPtr<SpanString> & spanString)4204 void RichEditorPattern::CompleteStyledString(RefPtr<SpanString>& spanString)
4205 {
4206     CHECK_NULL_VOID(spanString);
4207     std::string text;
4208     auto spans = spanString->GetSpanItems();
4209     std::for_each(spans.begin(), spans.end(), [&text](RefPtr<SpanItem>& item) {
4210         CHECK_NULL_VOID(item);
4211         text.append(item->content);
4212         item->position = item->interval.second;
4213         item->rangeStart = item->interval.first;
4214     });
4215     spanString->SetString(std::move(text));
4216     SetSubMap(spanString);
4217 }
4218 
InsertStyledStringByPaste(const RefPtr<SpanString> & spanString)4219 void RichEditorPattern::InsertStyledStringByPaste(const RefPtr<SpanString>& spanString)
4220 {
4221     CHECK_NULL_VOID(spanString && styledString_);
4222     int32_t changeStart = caretPosition_;
4223     int32_t changeLength = 0;
4224     if (textSelector_.IsValid()) {
4225         changeStart = textSelector_.GetTextStart();
4226         changeLength = textSelector_.GetTextEnd() - textSelector_.GetTextStart();
4227     }
4228     CHECK_NULL_VOID(BeforeStyledStringChange(changeStart, changeLength, spanString));
4229     if (changeLength > 0) {
4230         DeleteForwardInStyledString(changeLength, false);
4231     }
4232     ResetSelection();
4233     styledString_->InsertSpanString(changeStart, spanString);
4234     SetCaretPosition(caretPosition_ + spanString->GetLength());
4235     AfterStyledStringChange(changeStart, changeLength, spanString->GetString());
4236 }
4237 
HandleOnDragInsertStyledString(const RefPtr<SpanString> & spanString)4238 void RichEditorPattern::HandleOnDragInsertStyledString(const RefPtr<SpanString>& spanString)
4239 {
4240     CHECK_NULL_VOID(spanString);
4241     int currentCaretPosition = caretPosition_;
4242     auto strLength = spanString->GetLength();
4243     if (isDragSponsor_) {
4244         bool isInsertForward = currentCaretPosition < dragRange_.first;
4245         bool isInsertBackward = currentCaretPosition > dragRange_.second;
4246         CHECK_NULL_VOID(isInsertForward || isInsertBackward);
4247         CHECK_NULL_VOID(BeforeStyledStringChange(currentCaretPosition, 0, spanString));
4248         styledString_->InsertSpanString(currentCaretPosition, spanString);
4249         AfterStyledStringChange(currentCaretPosition, 0, spanString->GetString());
4250         if (isInsertForward) {
4251             SetCaretPosition(currentCaretPosition + strLength);
4252             dragRange_.first += strLength;
4253             dragRange_.second += strLength;
4254         }
4255         DeleteValueInStyledString(dragRange_.first, strLength, true, false);
4256     } else {
4257         CHECK_NULL_VOID(BeforeStyledStringChange(currentCaretPosition, 0, spanString));
4258         styledString_->InsertSpanString(currentCaretPosition, spanString);
4259         SetCaretPosition(currentCaretPosition + strLength);
4260         AfterStyledStringChange(currentCaretPosition, 0, spanString->GetString());
4261     }
4262     StartTwinkling();
4263     auto host = GetHost();
4264     CHECK_NULL_VOID(host);
4265     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
4266 }
4267 
AddSpansByPaste(const std::list<RefPtr<NG::SpanItem>> & spans)4268 void RichEditorPattern::AddSpansByPaste(const std::list<RefPtr<NG::SpanItem>>& spans)
4269 {
4270     if (textSelector_.IsValid()) {
4271         SetCaretPosition(textSelector_.GetTextStart());
4272         DeleteForward(textSelector_.GetTextStart(), textSelector_.GetTextEnd() - textSelector_.GetTextStart());
4273         ResetSelection();
4274     }
4275     for (const auto& spanItem : spans) {
4276         if (!spanItem) {
4277             continue;
4278         }
4279         auto imageSpanItem = DynamicCast<ImageSpanItem>(spanItem);
4280         if (imageSpanItem) {
4281             auto options = imageSpanItem->options;
4282             options.offset = caretPosition_;
4283             AddImageSpan(options, true, caretPosition_, true);
4284         } else {
4285             auto options = GetTextSpanOptions(spanItem);
4286             AddTextSpan(options, true, caretPosition_);
4287         }
4288     }
4289 }
4290 
GetTextSpanOptions(const RefPtr<SpanItem> & spanItem)4291 TextSpanOptions RichEditorPattern::GetTextSpanOptions(const RefPtr<SpanItem>& spanItem)
4292 {
4293     CHECK_NULL_RETURN(spanItem, {});
4294     TextStyle textStyle = GetDefaultTextStyle();
4295     UseSelfStyle(spanItem->fontStyle, spanItem->textLineStyle, textStyle);
4296     struct UpdateParagraphStyle paraStyle;
4297     paraStyle.textAlign = spanItem->textLineStyle->GetTextAlign();
4298     paraStyle.leadingMargin = spanItem->textLineStyle->GetLeadingMargin();
4299     paraStyle.wordBreak = spanItem->textLineStyle->GetWordBreak();
4300     paraStyle.lineBreakStrategy = spanItem->textLineStyle->GetLineBreakStrategy();
4301     TextSpanOptions options;
4302     options.value = spanItem->content;
4303     options.offset = caretPosition_;
4304     UserGestureOptions gestureOption;
4305     gestureOption.onClick = spanItem->onClick;
4306     gestureOption.onLongPress = spanItem->onLongPress;
4307     options.userGestureOption = gestureOption;
4308     options.style = textStyle;
4309     options.paraStyle = paraStyle;
4310     return options;
4311 }
4312 
ResetDragSpanItems()4313 void RichEditorPattern::ResetDragSpanItems()
4314 {
4315     auto host = GetHost();
4316     CHECK_NULL_VOID(host);
4317     std::unordered_set<int32_t> nodeIds;
4318     std::for_each(dragSpanItems_.begin(), dragSpanItems_.end(), [&nodeIds](RefPtr<SpanItem>& item) {
4319         CHECK_NULL_VOID(item);
4320         item->EndDrag();
4321         auto imageSpanItem = DynamicCast<ImageSpanItem>(item);
4322         if (imageSpanItem) {
4323             nodeIds.emplace(imageSpanItem->imageNodeId);
4324             return;
4325         }
4326         auto placeholderSpanItem = DynamicCast<PlaceholderSpanItem>(item);
4327         if (placeholderSpanItem) {
4328             nodeIds.emplace(placeholderSpanItem->placeholderSpanNodeId);
4329         }
4330     });
4331     const auto& childrens = host->GetChildren();
4332     for (const auto& child : childrens) {
4333         auto findResult = nodeIds.find(child->GetId());
4334         if (findResult == nodeIds.end()) {
4335             continue;
4336         }
4337         auto node = DynamicCast<FrameNode>(child);
4338         if (!node) {
4339             continue;
4340         }
4341         auto renderContext = node->GetRenderContext();
4342         if (!renderContext) {
4343             continue;
4344         }
4345         renderContext->UpdateOpacity(1);
4346         node->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
4347     }
4348     dragSpanItems_.clear();
4349 }
4350 
SelectOverlayIsOn()4351 bool RichEditorPattern::SelectOverlayIsOn()
4352 {
4353     return selectOverlay_->SelectOverlayIsOn();
4354 }
4355 
UpdateEditingValue(const std::shared_ptr<TextEditingValue> & value,bool needFireChangeEvent)4356 void RichEditorPattern::UpdateEditingValue(const std::shared_ptr<TextEditingValue>& value, bool needFireChangeEvent)
4357 {
4358 #ifdef ENABLE_STANDARD_INPUT
4359     InsertValue(value->text, true);
4360 #else
4361     if (value->isDelete) {
4362         HandleOnDelete(true);
4363     } else {
4364         InsertValue(value->appendText);
4365     }
4366 #endif
4367 }
4368 
InitMouseEvent()4369 void RichEditorPattern::InitMouseEvent()
4370 {
4371     CHECK_NULL_VOID(!mouseEventInitialized_);
4372     auto host = GetHost();
4373     CHECK_NULL_VOID(host);
4374     auto eventHub = host->GetEventHub<EventHub>();
4375     CHECK_NULL_VOID(eventHub);
4376     auto inputHub = eventHub->GetOrCreateInputEventHub();
4377     CHECK_NULL_VOID(inputHub);
4378 
4379     auto mouseTask = [weak = WeakClaim(this)](MouseInfo& info) {
4380         auto pattern = weak.Upgrade();
4381         CHECK_NULL_VOID(pattern);
4382         pattern->sourceType_ = info.GetSourceDevice();
4383         pattern->HandleMouseEvent(info);
4384     };
4385     auto mouseEvent = MakeRefPtr<InputEvent>(std::move(mouseTask));
4386     inputHub->AddOnMouseEvent(mouseEvent);
4387     auto hoverTask = [weak = WeakClaim(this)](bool isHover) {
4388         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "on hover event isHover=%{public}d", isHover);
4389         auto pattern = weak.Upgrade();
4390         if (pattern) {
4391             pattern->OnHover(isHover);
4392         }
4393     };
4394     auto hoverEvent = MakeRefPtr<InputEvent>(std::move(hoverTask));
4395     inputHub->AddOnHoverEvent(hoverEvent);
4396     mouseEventInitialized_ = true;
4397 }
4398 
OnHover(bool isHover)4399 void RichEditorPattern::OnHover(bool isHover)
4400 {
4401     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "isHover=%{public}d", isHover);
4402     auto frame = GetHost();
4403     CHECK_NULL_VOID(frame);
4404     auto frameId = frame->GetId();
4405     auto pipeline = frame->GetContext();
4406     CHECK_NULL_VOID(pipeline);
4407     auto scrollBar = GetScrollBar();
4408     if (isHover && (!scrollBar || !scrollBar->IsPressed())) {
4409         pipeline->SetMouseStyleHoldNode(frameId);
4410         pipeline->ChangeMouseStyle(frameId, MouseFormat::TEXT_CURSOR);
4411         currentMouseStyle_ = MouseFormat::TEXT_CURSOR;
4412     } else {
4413         pipeline->ChangeMouseStyle(frameId, MouseFormat::DEFAULT);
4414         currentMouseStyle_ = MouseFormat::DEFAULT;
4415         pipeline->FreeMouseStyleHoldNode(frameId);
4416         HandleUrlSpanForegroundClear();
4417     }
4418 }
4419 
RequestKeyboard(bool isFocusViewChanged,bool needStartTwinkling,bool needShowSoftKeyboard)4420 bool RichEditorPattern::RequestKeyboard(bool isFocusViewChanged, bool needStartTwinkling, bool needShowSoftKeyboard)
4421 {
4422     auto host = GetHost();
4423     CHECK_NULL_RETURN(host, false);
4424     auto context = host->GetContext();
4425     CHECK_NULL_RETURN(context, false);
4426     CHECK_NULL_RETURN(needShowSoftKeyboard, false);
4427     if (needShowSoftKeyboard && customKeyboardBuilder_) {
4428         return RequestCustomKeyboard();
4429     }
4430 #if defined(ENABLE_STANDARD_INPUT)
4431     if (!EnableStandardInput(needShowSoftKeyboard)) {
4432         return false;
4433     }
4434 #else
4435     if (!UnableStandardInput(isFocusViewChanged)) {
4436         return false;
4437     }
4438 #endif
4439     return true;
4440 }
4441 
4442 #if defined(ENABLE_STANDARD_INPUT)
4443 #ifdef WINDOW_SCENE_SUPPORTED
GetSCBSystemWindowId()4444 uint32_t RichEditorPattern::GetSCBSystemWindowId()
4445 {
4446     RefPtr<FrameNode> frameNode = GetHost();
4447     CHECK_NULL_RETURN(frameNode, {});
4448     auto focusSystemWindowId = WindowSceneHelper::GetFocusSystemWindowId(frameNode);
4449     TAG_LOGD(AceLogTag::ACE_KEYBOARD, "RichEditor Find SCBSystemWindowId End, (%{public}d).", focusSystemWindowId);
4450     return focusSystemWindowId;
4451 }
4452 #endif
4453 
EnableStandardInput(bool needShowSoftKeyboard)4454 bool RichEditorPattern::EnableStandardInput(bool needShowSoftKeyboard)
4455 {
4456     auto host = GetHost();
4457     CHECK_NULL_RETURN(host, false);
4458     auto context = host->GetContext();
4459     CHECK_NULL_RETURN(context, false);
4460     MiscServices::Configuration configuration;
4461     configuration.SetEnterKeyType(static_cast<MiscServices::EnterKeyType>(
4462         static_cast<int32_t>(GetTextInputActionValue(GetDefaultTextInputAction()))));
4463     configuration.SetTextInputType(
4464         static_cast<MiscServices::TextInputType>(static_cast<int32_t>(TextInputType::UNSPECIFIED)));
4465     MiscServices::InputMethodController::GetInstance()->OnConfigurationChange(configuration);
4466     if (richEditTextChangeListener_ == nullptr) {
4467         richEditTextChangeListener_ = new OnTextChangedListenerImpl(WeakClaim(this));
4468     }
4469     auto inputMethod = MiscServices::InputMethodController::GetInstance();
4470     CHECK_NULL_RETURN(inputMethod, false);
4471     auto miscTextConfig = GetMiscTextConfig();
4472     CHECK_NULL_RETURN(miscTextConfig.has_value(), false);
4473     TAG_LOGD(
4474         AceLogTag::ACE_RICH_TEXT, "RequestKeyboard set calling window id is : %{public}u", miscTextConfig->windowId);
4475     MiscServices::TextConfig textconfig = miscTextConfig.value();
4476 #ifdef WINDOW_SCENE_SUPPORTED
4477     auto systemWindowId = GetSCBSystemWindowId();
4478     if (systemWindowId) {
4479         TAG_LOGD(AceLogTag::ACE_KEYBOARD, "windowid(%{public}u->%{public}u.", miscTextConfig->windowId, systemWindowId);
4480         miscTextConfig->windowId = systemWindowId;
4481     }
4482 #endif
4483     auto textFieldManager = DynamicCast<TextFieldManagerNG>(context->GetTextFieldManager());
4484     if (host && textFieldManager) {
4485         textFieldManager->SetLastRequestKeyboardId(host->GetId());
4486     }
4487     auto ret = inputMethod->Attach(richEditTextChangeListener_, needShowSoftKeyboard, textconfig);
4488     if (ret == MiscServices::ErrorCode::NO_ERROR) {
4489         textFieldManager->SetIsImeAttached(true);
4490     }
4491     UpdateCaretInfoToController();
4492     if (context) {
4493         inputMethod->SetCallingWindow(context->GetWindowId());
4494     }
4495 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
4496     imeAttached_ = true;
4497 #endif
4498     return true;
4499 }
4500 
GetMiscTextConfig()4501 std::optional<MiscServices::TextConfig> RichEditorPattern::GetMiscTextConfig()
4502 {
4503     auto tmpHost = GetHost();
4504     CHECK_NULL_RETURN(tmpHost, {});
4505     auto pipeline = tmpHost->GetContextRefPtr();
4506     auto renderContext = tmpHost->GetRenderContext();
4507     CHECK_NULL_RETURN(pipeline && renderContext, {});
4508 
4509     float caretHeight = 0.0f;
4510     OffsetF caretOffset = CalcCursorOffsetByPosition(caretPosition_, caretHeight);
4511     if (NearZero(caretHeight)) {
4512         auto overlayModifier = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
4513         caretHeight = overlayModifier ? overlayModifier->GetCaretHeight() : DEFAULT_CARET_HEIGHT;
4514     }
4515     if (NearZero(caretHeight)) {
4516         auto [caretAdjustOffset, caretAdjustHeight] = CalculateCaretOffsetAndHeight();
4517         caretHeight = caretAdjustHeight;
4518     }
4519 
4520     // richeditor relative to root node offset(without transform)
4521     auto parentGlobalOffset = renderContext->GetPaintRectWithoutTransform().GetOffset() -
4522         pipeline->GetRootRect().GetOffset();
4523     // caret top (without transform)
4524     auto caretTop = caretOffset.GetY() + parentGlobalOffset.GetY();
4525     double positionY = parentGlobalOffset.GetY();
4526     double height = caretTop + caretHeight + KEYBOARD_AVOID_OFFSET.ConvertToPx() - positionY;
4527 
4528     if (auto manager = pipeline->GetSafeAreaManager(); manager) {
4529         auto keyboardOffset = manager->GetKeyboardOffset();
4530         positionY -= keyboardOffset;
4531     }
4532     OffsetF caretLeftTopPoint(caretOffset.GetX() + parentGlobalOffset.GetX(), caretTop);
4533     OffsetF caretRightBottomPoint(caretLeftTopPoint.GetX() + CARET_WIDTH, caretLeftTopPoint.GetY() + caretHeight);
4534     HandlePointWithTransform(caretLeftTopPoint);
4535     HandlePointWithTransform(caretRightBottomPoint);
4536     // window rect relative to screen
4537     auto windowRect = pipeline->GetCurrentWindowRect();
4538     MiscServices::CursorInfo cursorInfo { .left = caretLeftTopPoint.GetX() + windowRect.Left(),
4539         .top = caretLeftTopPoint.GetY() + windowRect.Top(),
4540         .width = std::abs(caretLeftTopPoint.GetX() - caretRightBottomPoint.GetX()),
4541         .height = std::abs(caretLeftTopPoint.GetY() - caretRightBottomPoint.GetY()) };
4542     MiscServices::InputAttribute inputAttribute = { .inputPattern = (int32_t)TextInputType::UNSPECIFIED,
4543         .enterKeyType = (int32_t)GetTextInputActionValue(GetDefaultTextInputAction()),
4544         .isTextPreviewSupported = !isSpanStringMode_ && isTextPreviewSupported_,
4545         .immersiveMode = static_cast<int32_t>(keyboardAppearance_) };
4546     auto start = textSelector_.IsValid() ? textSelector_.GetStart() : caretPosition_;
4547     auto end = textSelector_.IsValid() ? textSelector_.GetEnd() : caretPosition_;
4548     MiscServices::TextConfig textConfig = { .inputAttribute = inputAttribute,
4549         .cursorInfo = cursorInfo,
4550         .range = { .start = start, .end = end },
4551         .windowId = pipeline->GetFocusWindowId(),
4552         .positionY = positionY + windowRect.Top(),
4553         .height = height };
4554     return textConfig;
4555 }
4556 #else
UnableStandardInput(bool isFocusViewChanged)4557 bool RichEditorPattern::UnableStandardInput(bool isFocusViewChanged)
4558 {
4559     auto host = GetHost();
4560     CHECK_NULL_RETURN(host, false);
4561     auto context = host->GetContext();
4562     CHECK_NULL_RETURN(context, false);
4563     if (HasConnection()) {
4564         connection_->Show(isFocusViewChanged, GetInstanceId());
4565         return true;
4566     }
4567     TextInputConfiguration config;
4568     config.type = TextInputType::UNSPECIFIED;
4569     config.action = TextInputAction::DONE;
4570     config.obscureText = false;
4571     connection_ =
4572         TextInputProxy::GetInstance().Attach(WeakClaim(this), config, context->GetTaskExecutor(), GetInstanceId());
4573     if (!HasConnection()) {
4574         return false;
4575     }
4576     TextEditingValue value;
4577     if (spans_.empty()) {
4578         value.text = textForDisplay_;
4579     } else {
4580         for (auto it = spans_.begin(); it != spans_.end(); it++) {
4581             if ((*it)->placeholderIndex < 0) {
4582                 value.text.append((*it)->content);
4583             } else {
4584                 value.text.append(" ");
4585             }
4586         }
4587     }
4588     value.selection.Update(caretPosition_, caretPosition_);
4589     connection_->SetEditingState(value, GetInstanceId());
4590     connection_->Show(isFocusViewChanged, GetInstanceId());
4591     return true;
4592 }
4593 #endif
4594 
OnColorConfigurationUpdate()4595 void RichEditorPattern::OnColorConfigurationUpdate()
4596 {
4597     auto host = GetHost();
4598     CHECK_NULL_VOID(host);
4599     auto theme = GetTheme<RichEditorTheme>();
4600     CHECK_NULL_VOID(theme);
4601     auto textLayoutProperty = GetLayoutProperty<TextLayoutProperty>();
4602     CHECK_NULL_VOID(textLayoutProperty);
4603     const auto& themeTextStyle = theme->GetTextStyle();
4604     auto themeTextColor = themeTextStyle.GetTextColor();
4605     auto themeTextDecorationColor = themeTextStyle.GetTextDecorationColor();
4606     textLayoutProperty->UpdateTextColor(themeTextColor);
4607     textLayoutProperty->UpdateTextDecorationColor(themeTextDecorationColor);
4608 
4609     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "theme, TextColor=%{public}s, DecorationColor=%{public}s",
4610         themeTextColor.ToString().c_str(), themeTextDecorationColor.ToString().c_str());
4611 
4612     const auto& spans = host->GetChildren();
4613     for (const auto& uiNode : spans) {
4614         auto spanNode = DynamicCast<SpanNode>(uiNode);
4615         if (!spanNode) {
4616             continue;
4617         }
4618         auto spanItem = spanNode->GetSpanItem();
4619         if (!spanItem) {
4620             continue;
4621         }
4622         IF_TRUE(spanItem->useThemeFontColor, spanNode->UpdateTextColor(themeTextColor));
4623         IF_TRUE(spanItem->useThemeDecorationColor, spanNode->UpdateTextDecorationColor(themeTextDecorationColor));
4624         spanNode->UpdateColorByResourceId();
4625     }
4626     IF_PRESENT(typingTextStyle_, UpdateColorByResourceId());
4627     IF_PRESENT(typingStyle_, UpdateColorByResourceId());
4628 
4629     IF_PRESENT(magnifierController_, SetColorModeChange(true));
4630     auto scrollBar = GetScrollBar();
4631     auto scrollbarTheme = GetTheme<ScrollBarTheme>();
4632     CHECK_NULL_VOID(scrollBar && scrollbarTheme);
4633     scrollBar->SetForegroundColor(scrollbarTheme->GetForegroundColor());
4634     scrollBar->SetBackgroundColor(scrollbarTheme->GetBackgroundColor());
4635 }
4636 
UpdateCaretInfoToController()4637 void RichEditorPattern::UpdateCaretInfoToController()
4638 {
4639     CHECK_NULL_VOID(HasFocus());
4640     std::string text = "";
4641     for (auto iter = spans_.begin(); iter != spans_.end(); iter++) {
4642         text += (*iter)->content;
4643     }
4644     auto start = textSelector_.IsValid() ? textSelector_.GetStart() : caretPosition_;
4645     auto end = textSelector_.IsValid() ? textSelector_.GetEnd() : caretPosition_;
4646 #if defined(ENABLE_STANDARD_INPUT)
4647     auto miscTextConfig = GetMiscTextConfig();
4648     CHECK_NULL_VOID(miscTextConfig.has_value());
4649     MiscServices::CursorInfo cursorInfo = miscTextConfig.value().cursorInfo;
4650     MiscServices::InputMethodController::GetInstance()->OnCursorUpdate(cursorInfo);
4651     MiscServices::InputMethodController::GetInstance()->OnSelectionChange(
4652         StringUtils::Str8ToStr16(text), start, end);
4653     TAG_LOGD(AceLogTag::ACE_RICH_TEXT,
4654         "CursorInfo: pos=[%{public}.2f,%{public}.2f], size=[%{public}.2f,%{public}.2f], caret=%{public}d;"
4655         "OnSelectionChange: textLen=%{public}zu, range=[%{public}d,%{public}d]",
4656         cursorInfo.left, cursorInfo.top, cursorInfo.width, cursorInfo.height, caretPosition_,
4657         StringUtils::Str8ToStr16(text).length(), start, end);
4658 #else
4659     if (HasConnection()) {
4660         TextEditingValue editingValue;
4661         editingValue.text = text;
4662         editingValue.hint = "";
4663         editingValue.selection.Update(start, end);
4664         connection_->SetEditingState(editingValue, GetInstanceId());
4665     }
4666 #endif
4667 }
4668 
HasConnection() const4669 bool RichEditorPattern::HasConnection() const
4670 {
4671 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
4672     return imeAttached_;
4673 #else
4674     return connection_ != nullptr;
4675 #endif
4676 }
4677 
SetCustomKeyboardOption(bool supportAvoidance)4678 void RichEditorPattern::SetCustomKeyboardOption(bool supportAvoidance)
4679 {
4680     keyboardAvoidance_ = supportAvoidance;
4681 }
4682 
RequestCustomKeyboard()4683 bool RichEditorPattern::RequestCustomKeyboard()
4684 {
4685 #if defined(ENABLE_STANDARD_INPUT)
4686     auto inputMethod = MiscServices::InputMethodController::GetInstance();
4687     if (inputMethod) {
4688         TAG_LOGD(AceLogTag::ACE_KEYBOARD, "RichRequest CustomKeyboard, Close keyboard Successfully.");
4689         inputMethod->RequestHideInput();
4690         inputMethod->Close();
4691     }
4692 #else
4693     if (HasConnection()) {
4694         connection_->Close(GetInstanceId());
4695         connection_ = nullptr;
4696     }
4697 #endif
4698 
4699     if (isCustomKeyboardAttached_) {
4700         return true;
4701     }
4702     CHECK_NULL_RETURN(customKeyboardBuilder_, false);
4703     auto frameNode = GetHost();
4704     CHECK_NULL_RETURN(frameNode, false);
4705     auto pipeline = frameNode->GetContext();
4706     CHECK_NULL_RETURN(pipeline, false);
4707     auto overlayManager = pipeline->GetOverlayManager();
4708     CHECK_NULL_RETURN(overlayManager, false);
4709     overlayManager->SetCustomKeyboardOption(keyboardAvoidance_);
4710     overlayManager->BindKeyboard(customKeyboardBuilder_, frameNode->GetId());
4711     isCustomKeyboardAttached_ = true;
4712     contentChange_ = false;
4713     keyboardOverlay_ = overlayManager;
4714     auto [caretOffset, caretHeight] = CalculateCaretOffsetAndHeight();
4715     keyboardOverlay_->AvoidCustomKeyboard(frameNode->GetId(), caretHeight);
4716     return true;
4717 }
4718 
CloseCustomKeyboard()4719 bool RichEditorPattern::CloseCustomKeyboard()
4720 {
4721     auto frameNode = GetHost();
4722     CHECK_NULL_RETURN(frameNode, false);
4723     CHECK_NULL_RETURN(keyboardOverlay_, false);
4724     keyboardOverlay_->CloseKeyboard(frameNode->GetId());
4725     isCustomKeyboardAttached_ = false;
4726     contentChange_ = false;
4727     return true;
4728 }
4729 
SetPreviewText(const std::string & previewTextValue,const PreviewRange range)4730 int32_t RichEditorPattern::SetPreviewText(const std::string& previewTextValue, const PreviewRange range)
4731 {
4732     CHECK_NULL_RETURN(!isSpanStringMode_, ERROR_BAD_PARAMETERS);
4733     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "previewTextValue=%{private}s, range=[%{public}d,%{public}d]",
4734         previewTextValue.c_str(), range.start, range.end);
4735     auto host = GetHost();
4736     CHECK_NULL_RETURN(host, ERROR_BAD_PARAMETERS);
4737     previewTextRecord_.hasDiff = true;
4738     if (!IsPreviewTextInputting()) {
4739         if (!InitPreviewText(previewTextValue, range)) {
4740             previewTextRecord_.hasDiff = false;
4741             return ERROR_BAD_PARAMETERS;
4742         }
4743     } else {
4744         if (!UpdatePreviewText(previewTextValue, range)) {
4745             previewTextRecord_.hasDiff = false;
4746             return ERROR_BAD_PARAMETERS;
4747         }
4748     }
4749     previewTextRecord_.hasDiff = false;
4750     previewTextRecord_.replacedRange.Set(previewTextRecord_.startOffset, previewTextRecord_.endOffset);
4751     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
4752     return NO_ERRORS;
4753 }
4754 
InitPreviewText(const std::string & previewTextValue,const PreviewRange range)4755 bool RichEditorPattern::InitPreviewText(const std::string& previewTextValue, const PreviewRange range)
4756 {
4757     if (range.start != -1 || range.end != -1) {
4758         return ReplacePreviewText(previewTextValue, range);
4759     }
4760     auto& record = previewTextRecord_;
4761     record.isPreviewTextInputting = true;
4762     record.replacedRange = range;
4763     record.startOffset = textSelector_.SelectNothing() ? caretPosition_ : textSelector_.GetTextStart();
4764     record.newPreviewContent = previewTextValue;
4765     ProcessInsertValue(previewTextValue, OperationType::IME, false);
4766     record.previewContent = record.newPreviewContent;
4767     auto length = static_cast<int32_t>(StringUtils::ToWstring(previewTextValue).length());
4768     record.endOffset = record.startOffset + length;
4769     record.newPreviewContent.clear();
4770     return true;
4771 }
4772 
ReplacePreviewText(const std::string & previewTextValue,const PreviewRange & range)4773 bool RichEditorPattern::ReplacePreviewText(const std::string& previewTextValue, const PreviewRange& range)
4774 {
4775     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "ReplacePreviewText");
4776     if (range.start < 0 || range.end < range.start || range.end > GetTextContentLength()) {
4777         TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "bad PreviewRange");
4778         return false;
4779     }
4780     previewTextRecord_.replacedRange = range;
4781     previewTextRecord_.startOffset = range.start;
4782     previewTextRecord_.endOffset = range.end;
4783     ProcessInsertValue(previewTextValue, OperationType::IME, false);
4784     return true;
4785 }
4786 
4787 // Used for text replacement, without notifying developer caret change
DeleteByRange(OperationRecord * const record,int32_t start,int32_t end)4788 void RichEditorPattern::DeleteByRange(OperationRecord* const record, int32_t start, int32_t end)
4789 {
4790     auto length = end - start;
4791     CHECK_NULL_VOID(length > 0);
4792     caretPosition_ = std::clamp(start, 0, GetTextContentLength());
4793     std::wstring deleteText = DeleteForwardOperation(length);
4794     if (record && deleteText.length() != 0) {
4795         record->deleteText = StringUtils::ToString(deleteText);
4796     }
4797 }
4798 
UpdatePreviewText(const std::string & previewTextValue,const PreviewRange range)4799 bool RichEditorPattern::UpdatePreviewText(const std::string& previewTextValue, const PreviewRange range)
4800 {
4801     auto& record = previewTextRecord_;
4802     if (range.start == -1 && range.end == -1 && !record.previewContent.empty()) {
4803         record.replacedRange.Set(record.startOffset, record.endOffset);
4804         record.newPreviewContent = previewTextValue;
4805         ProcessInsertValue(previewTextValue, OperationType::IME, false);
4806         record.previewContent = record.newPreviewContent;
4807         record.newPreviewContent.clear();
4808         record.endOffset =
4809             record.startOffset + static_cast<int32_t>(StringUtils::ToWstring(previewTextValue).length());
4810     } else {
4811         if (range.start < record.startOffset || range.end > record.endOffset || range.end < range.start) {
4812             TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "bad PreviewRange");
4813             return false;
4814         }
4815         if (previewTextValue.empty() && range.start == range.end) {
4816             SetCaretPosition(range.end);
4817             return false;
4818         }
4819         auto replaceIndex = range.start - record.startOffset;
4820         auto replaceLength = range.end - range.start;
4821         auto oldContent = record.previewContent;
4822         auto oldPreviewLength = static_cast<int32_t>(StringUtils::ToWstring(oldContent).length());
4823         if (replaceIndex < 0 || replaceIndex + replaceLength > oldPreviewLength) {
4824             TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "bad replaced range ");
4825             return false;
4826         }
4827         auto newContent =
4828             StringUtils::ToString(StringUtils::ToWstring(oldContent)
4829                                       .replace(replaceIndex, replaceLength, StringUtils::ToWstring(previewTextValue)));
4830         record.replacedRange = range;
4831         record.newPreviewContent = newContent;
4832         ProcessInsertValue(previewTextValue, OperationType::IME, false);
4833         record.previewContent = record.newPreviewContent;
4834         record.newPreviewContent.clear();
4835         record.endOffset =
4836             record.startOffset + static_cast<int32_t>(StringUtils::ToWstring(newContent).length());
4837     }
4838     return true;
4839 }
4840 
GetPreviewTextInfo() const4841 const PreviewTextInfo RichEditorPattern::GetPreviewTextInfo() const
4842 {
4843     PreviewTextInfo info;
4844     if (!previewTextRecord_.previewContent.empty()) {
4845         info.value = previewTextRecord_.previewContent;
4846         info.offset = previewTextRecord_.startOffset;
4847     }
4848     return info;
4849 }
4850 
FinishTextPreview()4851 void RichEditorPattern::FinishTextPreview()
4852 {
4853     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "FinishTextPreview byImf");
4854     if (previewTextRecord_.previewContent.empty()) {
4855         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "previewContent is empty");
4856         RemoveEmptySpans();
4857         previewTextRecord_.Reset();
4858         return;
4859     }
4860     auto previewContent = previewTextRecord_.previewContent;
4861     FinishTextPreviewInner();
4862     ProcessInsertValue(previewContent, OperationType::IME, false);
4863 }
4864 
FinishTextPreviewInner()4865 void RichEditorPattern::FinishTextPreviewInner()
4866 {
4867     CHECK_NULL_VOID(IsPreviewTextInputting());
4868     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "FinishTextPreviewInner");
4869     DeleteByRange(nullptr, previewTextRecord_.startOffset, previewTextRecord_.endOffset);
4870     previewTextRecord_.Reset();
4871 }
4872 
NotifyExitTextPreview()4873 void RichEditorPattern::NotifyExitTextPreview()
4874 {
4875     CHECK_NULL_VOID(IsPreviewTextInputting());
4876     CHECK_NULL_VOID(HasFocus());
4877     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "NotifyExitTextPreview");
4878     FinishTextPreviewInner();
4879     std::string text = "";
4880 #if defined(ENABLE_STANDARD_INPUT)
4881     MiscServices::InputMethodController::GetInstance()->OnSelectionChange(
4882         StringUtils::Str8ToStr16(text), caretPosition_, caretPosition_);
4883     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "notify imf that richEditor exit textPreview");
4884 #endif
4885 }
4886 
GetPreviewTextRects()4887 std::vector<RectF> RichEditorPattern::GetPreviewTextRects()
4888 {
4889     auto rects = paragraphs_.GetRects(previewTextRecord_.startOffset, previewTextRecord_.endOffset,
4890         RectHeightPolicy::COVER_TEXT);
4891     auto offset = GetTextRect().GetOffset() - OffsetF(0.0f, std::min(baselineOffset_, 0.0f));
4892     for (RectF& rect : rects) {
4893         rect += offset;
4894     }
4895     return rects;
4896 }
4897 
GetPreviewTextStyle() const4898 PreviewTextStyle RichEditorPattern::GetPreviewTextStyle() const
4899 {
4900     auto previewTextStyle = PreviewTextStyle::UNDERLINE;
4901     auto property = GetLayoutProperty<RichEditorLayoutProperty>();
4902     if (property && property->HasPreviewTextStyle()) {
4903         auto style = property->GetPreviewTextStyle();
4904         if (style == PREVIEW_STYLE_NORMAL) {
4905             previewTextStyle = PreviewTextStyle::NORMAL;
4906         } else if (style == PREVIEW_STYLE_UNDERLINE) {
4907             previewTextStyle = PreviewTextStyle::UNDERLINE;
4908         } else {
4909             TAG_LOGW(
4910                 AceLogTag::ACE_RICH_TEXT, "invalid previewTextStyle of RichEditorLayoutProperty");
4911         }
4912     }
4913     return previewTextStyle;
4914 }
4915 
GetPreviewTextDecorationColor() const4916 const Color& RichEditorPattern::GetPreviewTextDecorationColor() const
4917 {
4918     auto pipeline = PipelineBase::GetCurrentContext();
4919     CHECK_NULL_RETURN(pipeline, Color::TRANSPARENT);
4920     auto theme = pipeline->GetTheme<RichEditorTheme>();
4921     CHECK_NULL_RETURN(theme, Color::TRANSPARENT);
4922     if (GetPreviewTextStyle() == PreviewTextStyle::UNDERLINE) {
4923         return theme->GetPreviewUnderLineColor();
4924     }
4925     return Color::TRANSPARENT;
4926 }
4927 
GetPreviewTextUnderlineWidth() const4928 float RichEditorPattern::GetPreviewTextUnderlineWidth() const
4929 {
4930     auto pipeline = PipelineBase::GetCurrentContext();
4931     CHECK_NULL_RETURN(pipeline, 0.0f);
4932     auto theme = pipeline->GetTheme<RichEditorTheme>();
4933     CHECK_NULL_RETURN(theme, 0.0f);
4934     return theme->GetPreviewUnderlineWidth().ConvertToPx();
4935 }
4936 
IsIMEOperation(OperationType operationType)4937 bool RichEditorPattern::IsIMEOperation(OperationType operationType)
4938 {
4939     return operationType == OperationType::IME;
4940 }
4941 
InsertValue(const std::string & insertValue,bool isIME)4942 void RichEditorPattern::InsertValue(const std::string& insertValue, bool isIME)
4943 {
4944     InsertValueByOperationType(insertValue, isIME ? OperationType::IME : OperationType::DEFAULT);
4945 }
4946 
InsertValueByOperationType(const std::string & insertValue,OperationType operationType)4947 void RichEditorPattern::InsertValueByOperationType(const std::string& insertValue, OperationType operationType)
4948 {
4949     ProcessInsertValue(insertValue, operationType, true);
4950 }
4951 
4952 // operationType: when type is IME, it controls whether to perform ime callbacks
4953 // calledByImf: true means real input; false means preview input
ProcessInsertValue(const std::string & insertValue,OperationType operationType,bool calledByImf)4954 void RichEditorPattern::ProcessInsertValue(const std::string& insertValue, OperationType operationType,
4955     bool calledByImf)
4956 {
4957     CONTENT_MODIFY_LOCK(this);
4958     bool isIME = IsIMEOperation(operationType);
4959     TAG_LOGI(AceLogTag::ACE_RICH_TEXT,
4960         "insertLen=%{public}zu, isIME=%{public}d, calledByImf=%{public}d, isSpanString=%{public}d",
4961         StringUtils::ToWstring(insertValue).length(), isIME, calledByImf, isSpanStringMode_);
4962     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "insertValue=[%{private}s]", StringUtils::RestoreEscape(insertValue).c_str());
4963 
4964     if (isIME && calledByImf && (!isEditing_ || IsDragging())) {
4965         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "NOT allow input, isEditing=%{public}d, isDragging=%{public}d",
4966             isEditing_, IsDragging());
4967         return;
4968     }
4969     if (isSpanStringMode_) {
4970         InsertValueInStyledString(insertValue);
4971         return;
4972     }
4973     OperationRecord record;
4974     record.beforeCaretPosition = caretPosition_ + moveLength_;
4975     if (textSelector_.IsValid()) {
4976         record.beforeCaretPosition = textSelector_.GetTextStart();
4977     }
4978     record.addText = insertValue;
4979 
4980     RichEditorChangeValue changeValue;
4981     bool allowContentChange = BeforeChangeText(changeValue, record, RecordType::INSERT);
4982     if (calledByImf && previewTextRecord_.IsValid()) {
4983         FinishTextPreviewInner();
4984     }
4985     bool allowImeInput = isIME ? BeforeIMEInsertValue(insertValue) : true;
4986     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "allowContentChange=%{public}d, allowImeInput=%{public}d, hasDiff=%{public}d",
4987         allowContentChange, allowImeInput, previewTextRecord_.hasDiff);
4988     CHECK_NULL_VOID(allowContentChange && allowImeInput || previewTextRecord_.hasDiff);
4989 
4990     ClearRedoOperationRecords();
4991     InsertValueOperation(insertValue, &record, operationType);
4992     record.afterCaretPosition = caretPosition_;
4993     if (isDragSponsor_) {
4994         record.deleteCaretPostion = dragRange_.first;
4995     }
4996     AddOperationRecord(record);
4997     AfterContentChange(changeValue);
4998 }
4999 
InsertValueOperation(const std::string & insertValue,OperationRecord * const record,OperationType operationType)5000 void RichEditorPattern::InsertValueOperation(const std::string& insertValue, OperationRecord* const record,
5001     OperationType operationType)
5002 {
5003     bool isSelector = textSelector_.IsValid();
5004     if (isSelector) {
5005         DeleteByRange(record, textSelector_.GetTextStart(), textSelector_.GetTextEnd());
5006         CloseSelectOverlay();
5007         ResetSelection();
5008     } else if (previewTextRecord_.hasDiff) {
5009         DeleteByRange(record, previewTextRecord_.replacedRange.start, previewTextRecord_.replacedRange.end);
5010     }
5011     TextInsertValueInfo info;
5012     CalcInsertValueObj(info);
5013     if (!caretVisible_) {
5014         StartTwinkling();
5015     }
5016     auto host = GetHost();
5017     CHECK_NULL_VOID(host);
5018     bool isIME = IsIMEOperation(operationType);
5019     RefPtr<SpanNode> spanNode = DynamicCast<SpanNode>(host->GetChildAtIndex(info.GetSpanIndex()));
5020     RefPtr<SpanNode> spanNodeBefore = DynamicCast<SpanNode>(host->GetChildAtIndex(info.GetSpanIndex() - 1));
5021     RefPtr<SpanNode> targetSpanNode = spanNode;
5022     bool needCreateNewSpan = host->GetChildren().empty();
5023     if (info.GetOffsetInSpan() == 0) {
5024         bool spanNodeBeforeCanInsert = spanNodeBefore && spanNodeBefore->GetTag() == V2::SPAN_ETS_TAG;
5025         bool spanNodeCanInsert = spanNode && spanNode->GetTag() == V2::SPAN_ETS_TAG;
5026         bool insertToBeforeNode = spanNodeBeforeCanInsert && !spanNodeCanInsert;
5027         insertToBeforeNode |= spanNodeBeforeCanInsert && spanNodeCanInsert && !IsLineSeparatorInLast(spanNodeBefore);
5028         if (insertToBeforeNode) {
5029             auto spanItem = spanNodeBefore->GetSpanItem();
5030             info.SetSpanIndex(info.GetSpanIndex() - 1);
5031             info.SetOffsetInSpan(spanItem->position - spanItem->rangeStart);
5032             targetSpanNode = spanNodeBefore;
5033         }
5034         needCreateNewSpan |= !spanNodeBeforeCanInsert && !spanNodeCanInsert;
5035     }
5036     if (needCreateNewSpan) {
5037         CreateTextSpanNode(targetSpanNode, info, insertValue, isIME);
5038         return;
5039     }
5040     if (typingStyle_.has_value() && !HasSameTypingStyle(targetSpanNode) && operationType != OperationType::DRAG) {
5041         InsertDiffStyleValueInSpan(targetSpanNode, info, insertValue, isIME);
5042         return;
5043     }
5044     InsertValueToSpanNode(targetSpanNode, insertValue, info);
5045     AfterInsertValue(targetSpanNode, static_cast<int32_t>(StringUtils::ToWstring(insertValue).length()), false, isIME);
5046 }
5047 
DeleteSelectOperation(OperationRecord * const record)5048 void RichEditorPattern::DeleteSelectOperation(OperationRecord* const record)
5049 {
5050     std::wstring deleteText = DeleteForwardOperation(textSelector_.GetTextEnd() - textSelector_.GetTextStart());
5051     if (record && deleteText.length() != 0) {
5052         record->deleteText = StringUtils::ToString(deleteText);
5053     }
5054     CloseSelectOverlay();
5055     ResetSelection();
5056 }
5057 
InsertDiffStyleValueInSpan(RefPtr<SpanNode> & spanNode,const TextInsertValueInfo & info,const std::string & insertValue,bool isIME)5058 void RichEditorPattern::InsertDiffStyleValueInSpan(
5059     RefPtr<SpanNode>& spanNode, const TextInsertValueInfo& info, const std::string& insertValue, bool isIME)
5060 {
5061     auto host = GetHost();
5062     CHECK_NULL_VOID(host);
5063     TextSpanOptions options;
5064     options.value = insertValue;
5065     options.offset = caretPosition_;
5066     auto theme = GetTheme<RichEditorTheme>();
5067     options.style = theme ? theme->GetTextStyle() : TextStyle();
5068     options.useThemeFontColor = typingStyle_->useThemeFontColor;
5069     options.useThemeDecorationColor = typingStyle_->useThemeDecorationColor;
5070     auto newSpanIndex = AddTextSpanOperation(options, false, -1,  true, false);
5071     auto newSpanNode = DynamicCast<SpanNode>(host->GetChildAtIndex(newSpanIndex));
5072     if (typingStyle_.has_value() && typingTextStyle_.has_value()) {
5073         UpdateTextStyle(newSpanNode, typingStyle_.value(), typingTextStyle_.value());
5074     }
5075     CopyTextSpanLineStyle(spanNode, newSpanNode, true);
5076     AfterInsertValue(newSpanNode, static_cast<int32_t>(StringUtils::ToWstring(insertValue).length()), true, isIME);
5077 }
5078 
IsLineSeparatorInLast(RefPtr<SpanNode> & spanNode)5079 bool RichEditorPattern::IsLineSeparatorInLast(RefPtr<SpanNode>& spanNode)
5080 {
5081     std::string content = spanNode->GetSpanItem()->content;
5082     std::wstring wContent = StringUtils::ToWstring(content);
5083     return !wContent.empty() && wContent.back() == L'\n';
5084 }
5085 
InsertValueToSpanNode(RefPtr<SpanNode> & spanNode,const std::string & insertValue,const TextInsertValueInfo & info)5086 void RichEditorPattern::InsertValueToSpanNode(
5087     RefPtr<SpanNode>& spanNode, const std::string& insertValue, const TextInsertValueInfo& info)
5088 {
5089     auto spanItem = spanNode->GetSpanItem();
5090     CHECK_NULL_VOID(spanItem);
5091     auto text = spanItem->content;
5092     std::wstring textTemp = StringUtils::ToWstring(text);
5093     auto textTempSize = static_cast<int32_t>(textTemp.size());
5094     if (textTempSize < info.GetOffsetInSpan()) {
5095         TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "InsertValue error, offsetInSpan is greater than the size of spanItem, "
5096             "spanItemSize = %{public}d, offsetInSpan = %{public}d", textTempSize, info.GetOffsetInSpan());
5097         return;
5098     }
5099     std::wstring insertValueTemp = StringUtils::ToWstring(insertValue);
5100     textTemp.insert(info.GetOffsetInSpan(), insertValueTemp);
5101     text = StringUtils::ToString(textTemp);
5102     spanNode->UpdateContent(text);
5103     UpdateSpanPosition();
5104     SpanNodeFission(spanNode);
5105 }
5106 
InsertValueToBeforeSpan(RefPtr<SpanNode> & spanNodeBefore,const std::string & insertValue)5107 RefPtr<SpanNode> RichEditorPattern::InsertValueToBeforeSpan(
5108     RefPtr<SpanNode>& spanNodeBefore, const std::string& insertValue)
5109 {
5110     auto spanItem = spanNodeBefore->GetSpanItem();
5111     CHECK_NULL_RETURN(spanItem, spanNodeBefore);
5112     auto text = spanItem->content;
5113     std::wstring textTemp = StringUtils::ToWstring(text);
5114     std::wstring insertValueTemp = StringUtils::ToWstring(insertValue);
5115     textTemp.append(insertValueTemp);
5116 
5117     auto index = textTemp.find(lineSeparator);
5118     if (index != std::wstring::npos) {
5119         auto textBefore = textTemp.substr(0, index + 1);
5120         auto textAfter = textTemp.substr(index + 1);
5121         text = StringUtils::ToString(textBefore);
5122         spanNodeBefore->UpdateContent(text);
5123         spanItem->position += static_cast<int32_t>(insertValueTemp.length()) - static_cast<int32_t>(textAfter.length());
5124         if (!textAfter.empty()) {
5125             auto host = GetHost();
5126             CHECK_NULL_RETURN(spanItem, spanNodeBefore);
5127             TextInsertValueInfo infoAfter;
5128             infoAfter.SetSpanIndex(host->GetChildIndex(spanNodeBefore) + 1);
5129             infoAfter.SetOffsetInSpan(0);
5130             auto nodeId = ViewStackProcessor::GetInstance()->ClaimNodeId();
5131             RefPtr<SpanNode> spanNodeAfter = SpanNode::GetOrCreateSpanNode(nodeId);
5132             spanNodeAfter->MountToParent(host, infoAfter.GetSpanIndex());
5133             spanNodeAfter->UpdateContent(StringUtils::ToString(textAfter));
5134             CopyTextSpanStyle(spanNodeBefore, spanNodeAfter);
5135             auto spanItemAfter = spanNodeAfter->GetSpanItem();
5136             spanItemAfter->position = static_cast<int32_t>(textTemp.length());
5137             spanItemAfter->useThemeFontColor = spanItem->useThemeFontColor;
5138             spanItemAfter->useThemeDecorationColor = spanItem->useThemeDecorationColor;
5139             AddSpanItem(spanItemAfter, host->GetChildIndex(spanNodeBefore) + 1);
5140             SpanNodeFission(spanNodeAfter);
5141             return spanNodeAfter;
5142         }
5143     } else {
5144         text = StringUtils::ToString(textTemp);
5145         spanNodeBefore->UpdateContent(text);
5146         spanItem->position += static_cast<int32_t>(StringUtils::ToWstring(insertValue).length());
5147     }
5148     return spanNodeBefore;
5149 }
5150 
CreateTextSpanNode(RefPtr<SpanNode> & spanNode,const TextInsertValueInfo & info,const std::string & insertValue,bool isIME)5151 void RichEditorPattern::CreateTextSpanNode(
5152     RefPtr<SpanNode>& spanNode, const TextInsertValueInfo& info, const std::string& insertValue, bool isIME)
5153 {
5154     auto host = GetHost();
5155     CHECK_NULL_VOID(host);
5156     auto nodeId = ViewStackProcessor::GetInstance()->ClaimNodeId();
5157     spanNode = SpanNode::GetOrCreateSpanNode(nodeId);
5158     spanNode->MountToParent(host, info.GetSpanIndex());
5159     auto spanItem = spanNode->GetSpanItem();
5160 
5161     if (typingStyle_.has_value() && typingTextStyle_.has_value()) {
5162         spanItem->useThemeFontColor = typingStyle_->useThemeFontColor;
5163         spanItem->useThemeDecorationColor = typingStyle_->useThemeDecorationColor;
5164         UpdateTextStyle(spanNode, typingStyle_.value(), typingTextStyle_.value());
5165         auto spanItem = spanNode->GetSpanItem();
5166         spanItem->SetTextStyle(typingTextStyle_);
5167     } else {
5168         spanNode->UpdateFontSize(Dimension(DEFAULT_TEXT_SIZE, DimensionUnit::FP));
5169         spanNode->AddPropertyInfo(PropertyInfo::FONTSIZE);
5170         SetDefaultColor(spanNode);
5171     }
5172     spanNode->UpdateContent(insertValue);
5173     AddSpanItem(spanItem, info.GetSpanIndex());
5174     UpdateSpanPosition();
5175     SpanNodeFission(spanNode);
5176     AfterInsertValue(spanNode, static_cast<int32_t>(StringUtils::ToWstring(insertValue).length()), true, isIME);
5177 }
5178 
SetDefaultColor(RefPtr<SpanNode> & spanNode)5179 void RichEditorPattern::SetDefaultColor(RefPtr<SpanNode>& spanNode)
5180 {
5181     auto host = GetHost();
5182     CHECK_NULL_VOID(host);
5183     auto pipeline = host->GetContext();
5184     CHECK_NULL_VOID(pipeline);
5185     auto richEditorTheme = pipeline->GetTheme<RichEditorTheme>();
5186     CHECK_NULL_VOID(richEditorTheme);
5187     Color textColor = richEditorTheme->GetTextStyle().GetTextColor();
5188     spanNode->UpdateTextColor(textColor);
5189     spanNode->AddPropertyInfo(PropertyInfo::FONTCOLOR);
5190     spanNode->UpdateTextDecorationColor(textColor);
5191     spanNode->AddPropertyInfo(PropertyInfo::NONE);
5192 }
5193 
BeforeIMEInsertValue(const std::string & insertValue)5194 bool RichEditorPattern::BeforeIMEInsertValue(const std::string& insertValue)
5195 {
5196     auto eventHub = GetEventHub<RichEditorEventHub>();
5197     CHECK_NULL_RETURN(eventHub, true);
5198     RichEditorInsertValue insertValueInfo;
5199     insertValueInfo.SetInsertOffset(caretPosition_);
5200     if (!previewTextRecord_.newPreviewContent.empty()) {
5201         insertValueInfo.SetPreviewText(previewTextRecord_.newPreviewContent);
5202     } else {
5203         insertValueInfo.SetInsertValue(insertValue);
5204     }
5205     return eventHub->FireAboutToIMEInput(insertValueInfo);
5206 }
5207 
AfterInsertValue(const RefPtr<SpanNode> & spanNode,int32_t insertValueLength,bool isCreate,bool isIME)5208 void RichEditorPattern::AfterInsertValue(
5209     const RefPtr<SpanNode>& spanNode, int32_t insertValueLength, bool isCreate, bool isIME)
5210 {
5211     isTextChange_ = true;
5212     moveDirection_ = MoveDirection::FORWARD;
5213     moveLength_ += insertValueLength;
5214     UpdateSpanPosition();
5215     if (isIME || aiWriteAdapter_->GetAIWrite()) {
5216         AfterIMEInsertValue(spanNode, insertValueLength, isCreate);
5217         return;
5218     }
5219     MoveCaretAfterTextChange();
5220 }
5221 
AfterIMEInsertValue(const RefPtr<SpanNode> & spanNode,int32_t insertValueLength,bool isCreate)5222 bool RichEditorPattern::AfterIMEInsertValue(const RefPtr<SpanNode>& spanNode, int32_t insertValueLength, bool isCreate)
5223 {
5224     ACE_SCOPED_TRACE("RichEditorAfterIMEInsertValue");
5225     auto host = GetHost();
5226     CHECK_NULL_RETURN(host, false);
5227     auto eventHub = GetEventHub<RichEditorEventHub>();
5228     CHECK_NULL_RETURN(eventHub, false);
5229 
5230     RichEditorAbstractSpanResult retInfo;
5231     retInfo.SetSpanIndex(host->GetChildIndex(spanNode));
5232     retInfo.SetEraseLength(insertValueLength);
5233     auto spanItem = spanNode->GetSpanItem();
5234     if (!previewTextRecord_.newPreviewContent.empty()) {
5235         retInfo.SetPreviewText(previewTextRecord_.newPreviewContent);
5236     } else {
5237         retInfo.SetValue(spanItem->content);
5238     }
5239     auto contentLength = static_cast<int32_t>(StringUtils::ToWstring(spanItem->content).length());
5240     retInfo.SetSpanRangeStart(spanItem->position - contentLength);
5241     retInfo.SetSpanRangeEnd(spanItem->position);
5242     retInfo.SetOffsetInSpan(caretPosition_ - retInfo.GetSpanRangeStart());
5243     retInfo.SetFontColor(spanNode->GetTextColorValue(Color::BLACK).ColorToString());
5244     retInfo.SetFontSize(spanNode->GetFontSizeValue(Dimension(16.0f, DimensionUnit::VP)).ConvertToVp());
5245     retInfo.SetFontStyle(spanNode->GetItalicFontStyleValue(OHOS::Ace::FontStyle::NORMAL));
5246     retInfo.SetFontWeight(static_cast<int32_t>(spanNode->GetFontWeightValue(FontWeight::NORMAL)));
5247     retInfo.SetTextStyle(GetTextStyleObject(spanNode));
5248     std::string fontFamilyValue;
5249     auto fontFamily = spanNode->GetFontFamilyValue({ "HarmonyOS Sans" });
5250     for (const auto& str : fontFamily) {
5251         fontFamilyValue += str;
5252     }
5253     retInfo.SetFontFamily(fontFamilyValue);
5254     retInfo.SetTextDecoration(spanNode->GetTextDecorationValue(TextDecoration::NONE));
5255     retInfo.SetTextDecorationStyle(spanNode->GetTextDecorationStyleValue(TextDecorationStyle::SOLID));
5256     retInfo.SetFontFeature(spanNode->GetFontFeatureValue(ParseFontFeatureSettings("\"pnum\" 1")));
5257     retInfo.SetColor(spanNode->GetTextDecorationColorValue(Color::BLACK).ColorToString());
5258     retInfo.SetTextStyle(GetTextStyleObject(spanNode));
5259     TextRange onDidIMEInputRange{ caretPosition_, caretPosition_ + insertValueLength };
5260     MoveCaretAfterTextChange();
5261     eventHub->FireOnIMEInputComplete(retInfo);
5262     eventHub->FireOnDidIMEInput(onDidIMEInputRange);
5263     return true;
5264 }
5265 
ResetFirstNodeStyle()5266 void RichEditorPattern::ResetFirstNodeStyle()
5267 {
5268     auto tmpHost = GetHost();
5269     CHECK_NULL_VOID(tmpHost);
5270     auto spans = tmpHost->GetChildren();
5271     if (!spans.empty()) {
5272         auto&& firstNode = DynamicCast<SpanNode>(*(spans.begin()));
5273         if (firstNode) {
5274             firstNode->ResetTextAlign();
5275             firstNode->ResetLeadingMargin();
5276             tmpHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
5277         }
5278     }
5279 }
5280 
DoDeleteActions(int32_t currentPosition,int32_t length,RichEditorDeleteValue & info)5281 bool RichEditorPattern::DoDeleteActions(int32_t currentPosition, int32_t length, RichEditorDeleteValue& info)
5282 {
5283     auto eventHub = GetEventHub<RichEditorEventHub>();
5284     CHECK_NULL_RETURN(eventHub, false);
5285     auto allowDelete = eventHub->FireAboutToDelete(info);
5286     info.ResetRichEditorDeleteSpans();
5287     CalcDeleteValueObj(currentPosition, length, info);
5288     bool doDelete = allowDelete || IsPreviewTextInputting();
5289     if (doDelete) {
5290         CloseSelectOverlay();
5291         ResetSelection();
5292         DeleteByDeleteValueInfo(info);
5293         if (!caretVisible_) {
5294             StartTwinkling();
5295         }
5296         eventHub->FireOnDeleteComplete();
5297     }
5298 #if !defined(PREVIEW) && defined(OHOS_PLATFORM)
5299     UiSessionManager::GetInstance().ReportComponentChangeEvent("event", "RichEditor.OnDeleteComplete");
5300 #endif
5301     return doDelete;
5302 }
5303 
IsEmojiOnCaretPosition(int32_t & emojiLength,bool isBackward,int32_t length)5304 std::pair<bool, bool> RichEditorPattern::IsEmojiOnCaretPosition(int32_t& emojiLength, bool isBackward, int32_t length)
5305 {
5306     bool isEmojiOnCaretBackward = false;
5307     bool isEmojiOnCaretForward = false;
5308     std::stringstream ss;
5309     for (auto iter = spans_.cbegin(); iter != spans_.cend(); iter++) {
5310         ss << (*iter)->content;
5311     }
5312 
5313     auto content = ss.str();
5314     std::u16string u16 = StringUtils::Str8ToStr16(content);
5315     auto caretPos = std::clamp(caretPosition_, 0, static_cast<int32_t>(u16.length()));
5316     emojiLength = TextEmojiProcessor::Delete(caretPos, length, content, isBackward);
5317     if (emojiLength > 0) {
5318         if (isBackward) {
5319             isEmojiOnCaretBackward = true;
5320         } else {
5321             isEmojiOnCaretForward = true;
5322         }
5323     }
5324     return std::make_pair(isEmojiOnCaretBackward, isEmojiOnCaretForward);
5325 }
5326 
HandleOnDelete(bool backward)5327 void RichEditorPattern::HandleOnDelete(bool backward)
5328 {
5329     if (backward) {
5330 #if defined(PREVIEW)
5331         DeleteForward(1);
5332 #else
5333         DeleteBackward(1);
5334 #endif
5335     } else {
5336 #if defined(PREVIEW)
5337         DeleteBackward(1);
5338 #else
5339         DeleteForward(1);
5340 #endif
5341     }
5342 }
5343 
CalculateDeleteLength(int32_t length,bool isBackward)5344 int32_t RichEditorPattern::CalculateDeleteLength(int32_t length, bool isBackward)
5345 {
5346     // handle selector
5347     if (!textSelector_.SelectNothing()) {
5348         caretPosition_ = isBackward ? textSelector_.GetTextEnd() : textSelector_.GetTextStart();
5349         return textSelector_.GetTextEnd() - textSelector_.GetTextStart();
5350     }
5351 
5352     // handle symbol, assume caret is not within symbol
5353     auto iter = std::find_if(spans_.begin(), spans_.end(), [index = caretPosition_, isBackward]
5354     (const RefPtr<SpanItem>& spanItem) {
5355         return isBackward
5356         ? (spanItem->rangeStart < index && index <= spanItem->position)
5357         : (spanItem->rangeStart <= index && index < spanItem->position);
5358     });
5359     CHECK_NULL_RETURN(iter == spans_.end() || !(*iter) || (*iter)->unicode == 0, SYMBOL_SPAN_LENGTH);
5360 
5361     // handle emoji
5362     int32_t emojiLength = 0;
5363     auto [isEmojiOnCaretBackward, isEmojiOnCaretForward] = IsEmojiOnCaretPosition(emojiLength, isBackward, length);
5364     if ((isBackward && isEmojiOnCaretBackward) || (!isBackward && isEmojiOnCaretForward)) {
5365         return emojiLength;
5366     }
5367 
5368     return length;
5369 }
5370 
DeleteBackward(int32_t oriLength)5371 void RichEditorPattern::DeleteBackward(int32_t oriLength)
5372 {
5373     int32_t length = isAPI14Plus ? std::clamp(oriLength, 0, caretPosition_) : oriLength;
5374     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "oriLength=%{public}d, length=%{public}d, isDragging=%{public}d",
5375         oriLength, length, IsDragging());
5376     CHECK_NULL_VOID(!IsDragging());
5377     if (isSpanStringMode_) {
5378         DeleteBackwardInStyledString(length);
5379         return;
5380     }
5381     if (IsPreviewTextInputting()) {
5382         TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "do not handle DeleteBackward on previewTextInputting");
5383         return;
5384     }
5385     OperationRecord record;
5386     record.beforeCaretPosition = caretPosition_;
5387     RichEditorChangeValue changeValue;
5388     CHECK_NULL_VOID(BeforeChangeText(changeValue, record, RecordType::DEL_BACKWARD, length));
5389     std::wstring deleteText = DeleteBackwardOperation(length);
5390     if (deleteText.length() != 0) {
5391         ClearRedoOperationRecords();
5392         record.deleteText = StringUtils::ToString(deleteText);
5393         record.afterCaretPosition = caretPosition_;
5394         AddOperationRecord(record);
5395         AfterContentChange(changeValue);
5396     }
5397 }
5398 
DeleteBackwardOperation(int32_t length)5399 std::wstring RichEditorPattern::DeleteBackwardOperation(int32_t length)
5400 {
5401     length = CalculateDeleteLength(length, true);
5402     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "delete length=%{public}d", length);
5403     std::wstringstream wss;
5404     for (auto iter = spans_.cbegin(); iter != spans_.cend(); iter++) {
5405         wss << StringUtils::ToWstring((*iter)->content);
5406     }
5407     auto textContent = wss.str();
5408     if (static_cast<int32_t>(textContent.length()) != GetTextContentLength()) {
5409         TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "textContent length mismatch, %{public}d vs. %{public}d",
5410             static_cast<int32_t>(textContent.length()), GetTextContentLength());
5411     }
5412     auto start = std::clamp(caretPosition_ - length, 0, static_cast<int32_t>(textContent.length()));
5413     std::wstring deleteText =
5414         textContent.substr(static_cast<uint32_t>(start), static_cast<uint32_t>(caretPosition_ - start));
5415     RichEditorDeleteValue info;
5416     info.SetRichEditorDeleteDirection(RichEditorDeleteDirection::BACKWARD);
5417     if (caretPosition_ == 0) {
5418         info.SetLength(0);
5419         ResetFirstNodeStyle();
5420         DoDeleteActions(0, 0, info);
5421         return deleteText;
5422     }
5423     info.SetOffset(caretPosition_ - length);
5424     info.SetLength(length);
5425     int32_t currentPosition = std::clamp((caretPosition_ - length), 0, static_cast<int32_t>(GetTextContentLength()));
5426     if (!spans_.empty()) {
5427         CalcDeleteValueObj(currentPosition, length, info);
5428         bool doDelete = DoDeleteActions(currentPosition, length, info);
5429         if (!doDelete) {
5430             return L"";
5431         }
5432     }
5433     auto host = GetHost();
5434     if (host && host->GetChildren().empty()) {
5435         textForDisplay_.clear();
5436     }
5437     RequestKeyboardToEdit();
5438     return deleteText;
5439 }
5440 
DeleteForward(int32_t oriLength)5441 void RichEditorPattern::DeleteForward(int32_t oriLength)
5442 {
5443     int32_t length = isAPI14Plus ? std::clamp(oriLength, 0, GetTextContentLength() - caretPosition_) : oriLength;
5444     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "oriLength=%{public}d, length=%{public}d, isDragging=%{public}d",
5445         oriLength, length, IsDragging());
5446     CHECK_NULL_VOID(!IsDragging());
5447     if (isSpanStringMode_) {
5448         DeleteForwardInStyledString(length);
5449         return;
5450     }
5451     if (IsPreviewTextInputting()) {
5452         TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "do not handle DeleteForward in previewTextInputting");
5453         return;
5454     }
5455     OperationRecord record;
5456     record.beforeCaretPosition = caretPosition_;
5457     RichEditorChangeValue changeValue;
5458     CHECK_NULL_VOID(BeforeChangeText(changeValue, record, RecordType::DEL_FORWARD, length));
5459     std::wstring deleteText = DeleteForwardOperation(length);
5460     if (deleteText.length() != 0) {
5461         ClearRedoOperationRecords();
5462         record.deleteText = StringUtils::ToString(deleteText);
5463         record.afterCaretPosition = caretPosition_;
5464         AddOperationRecord(record);
5465         AfterContentChange(changeValue);
5466     }
5467 }
5468 
DeleteForwardOperation(int32_t length)5469 std::wstring RichEditorPattern::DeleteForwardOperation(int32_t length)
5470 {
5471     length = CalculateDeleteLength(length, false);
5472     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "delete length=%{public}d", length);
5473     std::wstringstream wss;
5474     for (auto iter = spans_.cbegin(); iter != spans_.cend(); iter++) {
5475         wss << StringUtils::ToWstring((*iter)->content);
5476     }
5477     auto textContent = wss.str();
5478     if (static_cast<int32_t>(textContent.length()) != GetTextContentLength()) {
5479         TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "textContent length mismatch, %{public}d vs. %{public}d",
5480             static_cast<int32_t>(textContent.length()), GetTextContentLength());
5481     }
5482     auto end = std::clamp(caretPosition_ + length, 0, static_cast<int32_t>(textContent.length()));
5483     std::wstring deleteText = textContent.substr(
5484         static_cast<uint32_t>(std::clamp(caretPosition_, 0, static_cast<int32_t>(textContent.length()))),
5485         static_cast<uint32_t>(end - caretPosition_));
5486     if (caretPosition_ == GetTextContentLength()) {
5487         return deleteText;
5488     }
5489     RichEditorDeleteValue info;
5490     info.SetOffset(caretPosition_);
5491     info.SetRichEditorDeleteDirection(RichEditorDeleteDirection::FORWARD);
5492     info.SetLength(length);
5493     int32_t currentPosition = caretPosition_;
5494     if (!spans_.empty()) {
5495         CalcDeleteValueObj(currentPosition, length, info);
5496         bool doDelete = DoDeleteActions(currentPosition, length, info);
5497         if (!doDelete) {
5498             return L"";
5499         }
5500     }
5501     return deleteText;
5502 }
5503 
OnBackPressed()5504 bool RichEditorPattern::OnBackPressed()
5505 {
5506     auto tmpHost = GetHost();
5507     CHECK_NULL_RETURN(tmpHost, false);
5508     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "RichEditor %{public}d receives back press event", tmpHost->GetId());
5509     if (SelectOverlayIsOn()) {
5510         CloseSelectOverlay();
5511         textSelector_.Update(textSelector_.destinationOffset);
5512         StartTwinkling();
5513         return true;
5514     }
5515 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
5516     if (!imeShown_ && !isCustomKeyboardAttached_) {
5517 #else
5518     if (!isCustomKeyboardAttached_) {
5519 #endif
5520         return false;
5521     }
5522     tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
5523     CloseKeyboard(false);
5524     FocusHub::LostFocusToViewRoot();
5525 #if defined(ANDROID_PLATFORM)
5526     return false;
5527 #else
5528     return true;
5529 #endif
5530 }
5531 
5532 void RichEditorPattern::SetInputMethodStatus(bool keyboardShown)
5533 {
5534 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
5535     imeShown_ = keyboardShown;
5536 #endif
5537 }
5538 
5539 bool RichEditorPattern::BeforeStatusCursorMove(bool isLeft)
5540 {
5541     CHECK_NULL_RETURN(textSelector_.IsValid(), true);
5542     CHECK_NULL_RETURN(!selectOverlay_->IsSingleHandleShow(), true);
5543     SetCaretPosition(isLeft ? textSelector_.GetTextStart() : textSelector_.GetTextEnd());
5544     MoveCaretToContentRect();
5545     StartTwinkling();
5546     CloseSelectOverlay();
5547     ResetSelection();
5548     return false;
5549 }
5550 
5551 bool RichEditorPattern::CursorMoveLeft()
5552 {
5553     CHECK_NULL_RETURN(BeforeStatusCursorMove(true), false);
5554     CloseSelectOverlay();
5555     ResetSelection();
5556     int32_t emojiLength = 0;
5557     int32_t caretPosition = caretPosition_;
5558     constexpr int32_t DELETE_COUNT = 1;
5559     auto [isEmojiOnCaretBackward, isEmojiOnCaretForward] = IsEmojiOnCaretPosition(emojiLength, true, DELETE_COUNT);
5560     if (isEmojiOnCaretBackward) {
5561         caretPosition = std::clamp((caretPosition_ - emojiLength), 0, static_cast<int32_t>(GetTextContentLength()));
5562     } else {
5563         caretPosition = std::clamp((caretPosition_ - 1), 0, static_cast<int32_t>(GetTextContentLength()));
5564     }
5565     AdjustSelectorForSymbol(caretPosition, HandleType::SECOND, SelectorAdjustPolicy::EXCLUDE);
5566     if (caretPosition_ == caretPosition) {
5567         return false;
5568     }
5569     SetCaretPosition(caretPosition);
5570     MoveCaretToContentRect();
5571     StartTwinkling();
5572     auto host = GetHost();
5573     CHECK_NULL_RETURN(host, false);
5574     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
5575     return true;
5576 }
5577 
5578 bool RichEditorPattern::CursorMoveRight()
5579 {
5580     CHECK_NULL_RETURN(BeforeStatusCursorMove(false), false);
5581     CloseSelectOverlay();
5582     ResetSelection();
5583     int32_t emojiLength = 0;
5584     int32_t caretPosition = caretPosition_;
5585     constexpr int32_t DELETE_COUNT = 1;
5586     auto [isEmojiOnCaretBackward, isEmojiOnCaretForward] = IsEmojiOnCaretPosition(emojiLength, false, DELETE_COUNT);
5587     if (isEmojiOnCaretForward) {
5588         caretPosition = std::clamp((caretPosition_ + emojiLength), 0, static_cast<int32_t>(GetTextContentLength()));
5589     } else {
5590         caretPosition = std::clamp((caretPosition_ + 1), 0, static_cast<int32_t>(GetTextContentLength()));
5591     }
5592     AdjustSelectorForSymbol(caretPosition, HandleType::SECOND, SelectorAdjustPolicy::INCLUDE);
5593     if (caretPosition_ == caretPosition) {
5594         return false;
5595     }
5596     SetCaretPosition(caretPosition);
5597     MoveCaretToContentRect();
5598     StartTwinkling();
5599     auto host = GetHost();
5600     CHECK_NULL_RETURN(host, false);
5601     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
5602     return true;
5603 }
5604 
5605 bool RichEditorPattern::CursorMoveUp()
5606 {
5607     CHECK_NULL_RETURN(!SelectOverlayIsOn(), false);
5608     ResetSelection();
5609     float caretHeight = 0.0f;
5610     float leadingMarginOffset = 0.0f;
5611     CaretOffsetInfo caretInfo;
5612     if (static_cast<int32_t>(GetTextContentLength()) > 1) {
5613         caretInfo = GetCaretOffsetInfoByPosition();
5614         int32_t caretPosition = CalcMoveUpPos(leadingMarginOffset);
5615         CHECK_NULL_RETURN(overlayMod_, false);
5616         auto overlayMod = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
5617         auto currentCaretOffsetOverlay = overlayMod->GetCaretOffset();
5618         auto caretOffsetWidth = overlayMod->GetCaretWidth();
5619         auto rectLineInfo = CalcLineInfoByPosition();
5620         caretPosition = std::clamp(caretPosition, 0, static_cast<int32_t>(GetTextContentLength()));
5621         if (caretPosition_ == caretPosition) {
5622             caretPosition = 0;
5623         }
5624         // at line middle or line end
5625         bool cursorNotAtLineStart =
5626             NearEqual(currentCaretOffsetOverlay.GetX(), caretInfo.caretOffsetUp.GetX(), caretOffsetWidth);
5627         bool isEnter = NearZero(currentCaretOffsetOverlay.GetX() - richTextRect_.GetX(), rectLineInfo.GetX());
5628         SetCaretPosition(caretPosition);
5629         MoveCaretToContentRect();
5630         if (cursorNotAtLineStart && !isEnter) {
5631             OffsetF caretOffset = CalcCursorOffsetByPosition(caretPosition_, caretHeight, false, false);
5632             SetLastClickOffset(caretOffset);
5633         }
5634     }
5635     StartTwinkling();
5636     auto host = GetHost();
5637     CHECK_NULL_RETURN(host, false);
5638     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
5639     return true;
5640 }
5641 
5642 bool RichEditorPattern::CursorMoveDown()
5643 {
5644     CHECK_NULL_RETURN(!SelectOverlayIsOn(), false);
5645     ResetSelection();
5646     if (static_cast<int32_t>(GetTextContentLength()) > 1) {
5647         float caretHeight = 0.0f;
5648         float leadingMarginOffset = 0.0f;
5649         float caretHeightEnd = 0.0f;
5650         CaretOffsetInfo caretInfo;
5651         int32_t caretPositionEnd;
5652         caretInfo = GetCaretOffsetInfoByPosition();
5653         caretPositionEnd = CalcMoveDownPos(leadingMarginOffset);
5654         CHECK_NULL_RETURN(overlayMod_, false);
5655         auto overlayMod = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
5656         auto caretOffsetOverlay = overlayMod->GetCaretOffset();
5657         auto caretOffsetWidth = overlayMod->GetCaretWidth();
5658         bool cursorNotAtLineStart =
5659             NearEqual(caretOffsetOverlay.GetX(), caretInfo.caretOffsetUp.GetX(), caretOffsetWidth);
5660         bool isEnter = NearZero(caretInfo.caretOffsetUp.GetX() - richTextRect_.GetX(), leadingMarginOffset);
5661         caretPositionEnd = std::clamp(caretPositionEnd, 0, static_cast<int32_t>(GetTextContentLength()));
5662         auto currentLineInfo = CalcLineInfoByPosition();
5663         if (caretPositionEnd <= caretPosition_) {
5664             OffsetF caretOffsetEnd = CalcCursorOffsetByPosition(GetTextContentLength(), caretHeightEnd);
5665             if (NearEqual(caretOffsetEnd.GetY() - GetTextRect().GetY(), currentLineInfo.GetY(), 0.5f)) {
5666                 caretPositionEnd = GetTextContentLength();
5667             } else {
5668                 caretPositionEnd += 1;
5669             }
5670         }
5671         SetCaretPosition(caretPositionEnd);
5672         if (cursorNotAtLineStart && caretPosition_ != 0 && !isEnter) {
5673             OffsetF caretOffset = CalcCursorOffsetByPosition(caretPosition_, caretHeight, false, false);
5674             SetLastClickOffset(caretOffset);
5675         }
5676         MoveCaretToContentRect();
5677     }
5678     StartTwinkling();
5679     auto host = GetHost();
5680     CHECK_NULL_RETURN(host, false);
5681     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
5682     return true;
5683 }
5684 
5685 void RichEditorPattern::CursorMoveToNextWord(CaretMoveIntent direction)
5686 {
5687     CHECK_NULL_VOID(direction == CaretMoveIntent::LeftWord || direction == CaretMoveIntent::RightWord);
5688     auto newPos = direction == CaretMoveIntent::LeftWord ? GetLeftWordIndex() : GetRightWordIndex();
5689     CloseSelectOverlay();
5690     ResetSelection();
5691     SetCaretPosition(newPos);
5692     MoveCaretToContentRect();
5693     IF_TRUE(isEditing_, StartTwinkling());
5694     auto host = GetHost();
5695     CHECK_NULL_VOID(host);
5696     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
5697 }
5698 
5699 int32_t RichEditorPattern::GetLeftWordIndex()
5700 {
5701     int32_t index = textSelector_.SelectNothing() ? caretPosition_ : textSelector_.GetTextStart() + 1;
5702     AdjustIndexSkipSpace(index, MoveDirection::BACKWARD);
5703     int32_t newPos = std::max(0, index - 1);
5704     AdjustWordSelection(newPos, index);
5705     AdjustSelector(newPos, HandleType::FIRST);
5706     return newPos;
5707 }
5708 
5709 int32_t RichEditorPattern::GetRightWordIndex()
5710 {
5711     int32_t index = textSelector_.SelectNothing() ? caretPosition_ : textSelector_.GetTextEnd() - 1;
5712     int32_t newPos = std::min(index + 1, GetTextContentLength());
5713     AdjustWordSelection(index, newPos);
5714     AdjustSelector(newPos, HandleType::SECOND);
5715     AdjustIndexSkipSpace(newPos, MoveDirection::FORWARD);
5716     return newPos;
5717 }
5718 
5719 bool RichEditorPattern::CursorMoveToParagraphBegin()
5720 {
5721     CloseSelectOverlay();
5722     ResetSelection();
5723     auto newPos = GetParagraphBeginPosition(caretPosition_);
5724     if (newPos == caretPosition_ && caretPosition_ > 0) {
5725         newPos = GetParagraphBeginPosition(caretPosition_ - 1);
5726     }
5727     if (newPos == caretPosition_) {
5728         return false;
5729     }
5730     SetCaretPosition(newPos);
5731     MoveCaretToContentRect();
5732     StartTwinkling();
5733     auto host = GetHost();
5734     CHECK_NULL_RETURN(host, false);
5735     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
5736     return true;
5737 }
5738 
5739 bool RichEditorPattern::CursorMoveToParagraphEnd()
5740 {
5741     CloseSelectOverlay();
5742     ResetSelection();
5743     auto newPos = GetParagraphEndPosition(caretPosition_);
5744     if (newPos == caretPosition_ && caretPosition_ < static_cast<int32_t>(GetTextContentLength())) {
5745         newPos = GetParagraphEndPosition(caretPosition_ + 1);
5746     }
5747     if (newPos == caretPosition_) {
5748         return false;
5749     }
5750     SetCaretPosition(newPos);
5751     MoveCaretToContentRect();
5752     StartTwinkling();
5753     auto host = GetHost();
5754     CHECK_NULL_RETURN(host, false);
5755     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
5756     return true;
5757 }
5758 
5759 bool RichEditorPattern::CursorMoveHome()
5760 {
5761     CloseSelectOverlay();
5762     ResetSelection();
5763     if (0 == caretPosition_) {
5764         return false;
5765     }
5766     SetCaretPosition(0);
5767     MoveCaretToContentRect();
5768     StartTwinkling();
5769     auto host = GetHost();
5770     CHECK_NULL_RETURN(host, false);
5771     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
5772     return true;
5773 }
5774 
5775 bool RichEditorPattern::CursorMoveEnd()
5776 {
5777     int32_t currentPositionIndex = 0;
5778     if (textSelector_.SelectNothing()) {
5779         currentPositionIndex = caretPosition_;
5780     } else {
5781         currentPositionIndex = textSelector_.GetTextEnd();
5782     }
5783     CloseSelectOverlay();
5784     ResetSelection();
5785     auto newPos = GetTextContentLength();
5786     if (newPos == currentPositionIndex) {
5787         StartTwinkling();
5788         return false;
5789     }
5790     SetCaretPosition(newPos);
5791     MoveCaretToContentRect();
5792     StartTwinkling();
5793     auto host = GetHost();
5794     CHECK_NULL_RETURN(host, false);
5795     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
5796     return true;
5797 }
5798 
5799 int32_t RichEditorPattern::GetLeftWordPosition(int32_t caretPosition)
5800 {
5801     int32_t offset = 0;
5802     bool jumpSpace = true;
5803     for (auto iter = spans_.rbegin(); iter != spans_.rend(); iter++) {
5804         auto span = *iter;
5805         auto content = StringUtils::ToWstring(span->content);
5806         if (caretPosition <= span->position - static_cast<int32_t>(content.length())) {
5807             continue;
5808         }
5809         int32_t position = span->position;
5810         for (auto iterContent = content.rbegin(); iterContent != content.rend(); iterContent++) {
5811             if (position-- > caretPosition) {
5812                 continue;
5813             }
5814             if (*iterContent != L' ' || span->placeholderIndex >= 0) {
5815                 jumpSpace = false;
5816             }
5817             if (position + 1 == caretPosition) {
5818                 if (!(StringUtils::IsLetterOrNumberForWchar(*iterContent) ||
5819                         (*iterContent == L' ' && span->placeholderIndex < 0))) {
5820                     return std::clamp(caretPosition - 1, 0, static_cast<int32_t>(GetTextContentLength()));
5821                 }
5822             }
5823             if (!jumpSpace) {
5824                 if (!StringUtils::IsLetterOrNumberForWchar(*iterContent)) {
5825                     return std::clamp(caretPosition - offset, 0, static_cast<int32_t>(GetTextContentLength()));
5826                 }
5827             } else {
5828                 if (*iterContent == L' ' && span->placeholderIndex >= 0) {
5829                     return std::clamp(caretPosition - offset, 0, static_cast<int32_t>(GetTextContentLength()));
5830                 }
5831             }
5832             offset++;
5833         }
5834     }
5835     return std::clamp(caretPosition - offset, 0, static_cast<int32_t>(GetTextContentLength()));
5836 }
5837 
5838 int32_t RichEditorPattern::GetRightWordPosition(int32_t caretPosition)
5839 {
5840     int32_t offset = 0;
5841     bool jumpSpace = false;
5842     for (auto iter = spans_.cbegin(); iter != spans_.cend(); iter++) {
5843         auto span = *iter;
5844         auto content = StringUtils::ToWstring(span->content);
5845         if (caretPosition > span->position) {
5846             continue;
5847         }
5848         int32_t position = span->position - static_cast<int32_t>(content.length());
5849         for (auto iterContent = content.cbegin(); iterContent != content.cend(); iterContent++) {
5850             if (position++ < caretPosition) {
5851                 continue;
5852             }
5853             if (*iterContent == L' ' && span->placeholderIndex < 0) {
5854                 jumpSpace = true;
5855                 offset++;
5856                 continue;
5857             }
5858             if (position - 1 == caretPosition) {
5859                 if (!StringUtils::IsLetterOrNumberForWchar(*iterContent)) {
5860                     return std::clamp(caretPosition + 1, 0, static_cast<int32_t>(GetTextContentLength()));
5861                 }
5862             }
5863             if (jumpSpace) {
5864                 if (*iterContent != L' ' || span->placeholderIndex >= 0) {
5865                     return std::clamp(caretPosition + offset, 0, static_cast<int32_t>(GetTextContentLength()));
5866                 }
5867             } else {
5868                 if (!(StringUtils::IsLetterOrNumberForWchar(*iterContent) ||
5869                         (*iterContent == L' ' && span->placeholderIndex < 0))) {
5870                     return std::clamp(caretPosition + offset, 0, static_cast<int32_t>(GetTextContentLength()));
5871                 }
5872             }
5873             offset++;
5874         }
5875     }
5876     return std::clamp(caretPosition + offset, 0, static_cast<int32_t>(GetTextContentLength()));
5877 }
5878 
5879 int32_t RichEditorPattern::GetParagraphBeginPosition(int32_t caretPosition)
5880 {
5881     int32_t offset = 0;
5882     for (auto iter = spans_.rbegin(); iter != spans_.rend(); iter++) {
5883         auto span = *iter;
5884         auto content = StringUtils::ToWstring(span->content);
5885         if (caretPosition <= span->position - static_cast<int32_t>(content.length())) {
5886             continue;
5887         }
5888         int32_t position = span->position;
5889         for (auto iterContent = content.rbegin(); iterContent != content.rend(); iterContent++) {
5890             if (position-- > caretPosition) {
5891                 continue;
5892             }
5893             if (*iterContent == L'\n') {
5894                 return std::clamp(caretPosition - offset, 0, static_cast<int32_t>(GetTextContentLength()));
5895             }
5896             offset++;
5897         }
5898     }
5899     return std::clamp(caretPosition - offset, 0, static_cast<int32_t>(GetTextContentLength()));
5900 }
5901 
5902 int32_t RichEditorPattern::GetParagraphEndPosition(int32_t caretPosition)
5903 {
5904     int32_t offset = 0;
5905     for (auto iter = spans_.cbegin(); iter != spans_.cend(); iter++) {
5906         auto span = *iter;
5907         auto content = StringUtils::ToWstring(span->content);
5908         if (caretPosition > span->position) {
5909             continue;
5910         }
5911         int32_t position = span->position - static_cast<int32_t>(content.length());
5912         for (auto iterContent = content.cbegin(); iterContent != content.cend(); iterContent++) {
5913             if (position++ < caretPosition) {
5914                 continue;
5915             }
5916             if (*iterContent == L'\n') {
5917                 return std::clamp(caretPosition + offset, 0, static_cast<int32_t>(GetTextContentLength()));
5918             }
5919             offset++;
5920         }
5921     }
5922     return std::clamp(caretPosition + offset, 0, static_cast<int32_t>(GetTextContentLength()));
5923 }
5924 
5925 void RichEditorPattern::HandleOnSelectAll()
5926 {
5927     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "HandleOnSelectAll");
5928     CloseSelectOverlay();
5929     auto host = GetHost();
5930     CHECK_NULL_VOID(host);
5931     int32_t newPos = static_cast<int32_t>(GetTextContentLength());
5932     textSelector_.Update(0, newPos);
5933     FireOnSelect(textSelector_.GetTextStart(), textSelector_.GetTextEnd());
5934     SetCaretPosition(newPos);
5935     MoveCaretToContentRect();
5936     StopTwinkling();
5937     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
5938 }
5939 
5940 int32_t RichEditorPattern::CaretPositionSelectEmoji(CaretMoveIntent direction)
5941 {
5942     int32_t newPos = caretPosition_;
5943     int32_t emojiLength = 0;
5944     constexpr int32_t DELETE_COUNT = 1;
5945     if (direction == CaretMoveIntent::Left) {
5946         auto [isEmojiOnCaretBackward, isEmojiOnCaretForward] = IsEmojiOnCaretPosition(emojiLength, true, DELETE_COUNT);
5947         if (isEmojiOnCaretBackward) {
5948             newPos = caretPosition_ - emojiLength;
5949         } else {
5950             newPos = caretPosition_ - 1;
5951         }
5952         return newPos;
5953     }
5954     auto [isEmojiOnCaretBackward, isEmojiOnCaretForward] = IsEmojiOnCaretPosition(emojiLength, false, DELETE_COUNT);
5955     if (direction == CaretMoveIntent::Right) {
5956         if (isEmojiOnCaretForward) {
5957             newPos = caretPosition_ + emojiLength;
5958         } else {
5959             newPos = caretPosition_ + 1;
5960         }
5961     }
5962     return newPos;
5963 }
5964 
5965 void RichEditorPattern::HandleSelect(CaretMoveIntent direction)
5966 {
5967     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "direction=%{public}d", direction);
5968     CloseSelectOverlay();
5969     auto host = GetHost();
5970     CHECK_NULL_VOID(host);
5971     int32_t newPos, fixedPos = caretPosition_;
5972     if (IsSelected()) {
5973         fixedPos = (caretPosition_ == textSelector_.GetTextStart() ? textSelector_.GetTextEnd()
5974                                                                    : textSelector_.GetTextStart());
5975     }
5976     newPos = HandleSelectWrapper(direction, fixedPos);
5977     if (newPos == -1) {
5978         return;
5979     }
5980     newPos = std::clamp(newPos, 0, static_cast<int32_t>(GetTextContentLength()));
5981     if (newPos == caretPosition_) {
5982         return;
5983     }
5984     UpdateSelector(newPos, fixedPos);
5985     FireOnSelect(textSelector_.GetTextStart(), textSelector_.GetTextEnd());
5986     SetCaretPosition(newPos);
5987     MoveCaretToContentRect();
5988     if (textSelector_.SelectNothing()) {
5989         StartTwinkling();
5990     } else {
5991         StopTwinkling();
5992     }
5993     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
5994 }
5995 
5996 void RichEditorPattern::ClearOperationRecords()
5997 {
5998     ClearRedoOperationRecords();
5999     if (operationRecords_.empty()) {
6000         return;
6001     }
6002     operationRecords_.clear();
6003 }
6004 
6005 void RichEditorPattern::ClearRedoOperationRecords()
6006 {
6007     if (redoOperationRecords_.empty()) {
6008         return;
6009     }
6010     redoOperationRecords_.clear();
6011 }
6012 
6013 void RichEditorPattern::AddOperationRecord(const OperationRecord& record)
6014 {
6015     if (operationRecords_.size() >= RECORD_MAX_LENGTH) {
6016         // case of max length is 0
6017         if (operationRecords_.empty()) {
6018             return;
6019         }
6020         operationRecords_.erase(operationRecords_.begin());
6021     }
6022     operationRecords_.emplace_back(record);
6023 }
6024 
6025 void RichEditorPattern::UpdateShiftFlag(const KeyEvent& keyEvent)
6026 {
6027     bool flag = keyEvent.action == KeyAction::DOWN
6028         && (keyEvent.HasKey(KeyCode::KEY_SHIFT_LEFT) || keyEvent.HasKey(KeyCode::KEY_SHIFT_RIGHT));
6029     if (flag != shiftFlag_) {
6030         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "UpdateShiftFlag to %{public}d", flag);
6031         shiftFlag_ = flag;
6032     }
6033 }
6034 
6035 bool RichEditorPattern::HandleOnEscape()
6036 {
6037     CloseSelectOverlay();
6038     return false;
6039 }
6040 
6041 void RichEditorPattern::HandleOnUndoAction()
6042 {
6043     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "HandleOnUndoAction");
6044     if (operationRecords_.empty()) {
6045         return;
6046     }
6047     auto value = operationRecords_.back();
6048     RichEditorChangeValue changeValue;
6049     CHECK_NULL_VOID(BeforeChangeText(changeValue, value, RecordType::UNDO));
6050     operationRecords_.pop_back();
6051     if (redoOperationRecords_.size() >= RECORD_MAX_LENGTH && !(redoOperationRecords_.empty())) {
6052         redoOperationRecords_.erase(redoOperationRecords_.begin());
6053     }
6054     redoOperationRecords_.push_back(value);
6055     CloseSelectOverlay();
6056     ResetSelection();
6057     if (value.addText.has_value() && value.deleteCaretPostion != -1) {
6058         UndoDrag(value);
6059         AfterContentChange(changeValue);
6060         return;
6061     }
6062     if (value.addText.has_value() && value.deleteText.has_value()) {
6063         SetCaretPosition(value.afterCaretPosition);
6064         DeleteBackwardOperation(TextEmojiProcessor::GetCharacterNum(value.addText.value_or("")));
6065         InsertValueOperation(value.deleteText.value_or(""));
6066         AfterContentChange(changeValue);
6067         return;
6068     }
6069     if (value.addText.has_value()) {
6070         SetCaretPosition(value.afterCaretPosition);
6071         DeleteBackwardOperation(TextEmojiProcessor::GetCharacterNum(value.addText.value_or("")));
6072     }
6073     if (value.deleteText.has_value()) {
6074         SetCaretPosition(value.afterCaretPosition);
6075         InsertValueOperation(value.deleteText.value_or(""));
6076     }
6077     AfterContentChange(changeValue);
6078 }
6079 
6080 void RichEditorPattern::HandleOnRedoAction()
6081 {
6082     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "HandleOnRedoAction");
6083     if (redoOperationRecords_.empty()) {
6084         return;
6085     }
6086     auto value = redoOperationRecords_.back();
6087     RichEditorChangeValue changeValue;
6088     CHECK_NULL_VOID(BeforeChangeText(changeValue, value, RecordType::REDO));
6089     redoOperationRecords_.pop_back();
6090     if (value.addText.has_value() && value.deleteCaretPostion != -1) {
6091         RedoDrag(value);
6092         AfterContentChange(changeValue);
6093         return;
6094     }
6095     if (value.addText.has_value() && value.deleteText.has_value()) {
6096         SetCaretPosition(value.beforeCaretPosition);
6097         DeleteForwardOperation(StringUtils::ToWstring(value.deleteText.value_or("")).length());
6098         InsertValueOperation(value.addText.value_or(""));
6099         operationRecords_.push_back(value);
6100         AfterContentChange(changeValue);
6101         return;
6102     }
6103     if (value.deleteText.has_value()) {
6104         SetCaretPosition(value.beforeCaretPosition);
6105         if (value.beforeCaretPosition != value.afterCaretPosition) {
6106             DeleteBackwardOperation(StringUtils::ToWstring(value.deleteText.value_or("")).length());
6107         } else {
6108             DeleteForwardOperation(StringUtils::ToWstring(value.deleteText.value_or("")).length());
6109         }
6110     }
6111     if (value.addText.has_value()) {
6112         SetCaretPosition(value.beforeCaretPosition);
6113         InsertValueOperation(value.addText.value_or(""));
6114     }
6115     operationRecords_.push_back(value);
6116     AfterContentChange(changeValue);
6117 }
6118 
6119 void RichEditorPattern::CalcInsertValueObj(TextInsertValueInfo& info)
6120 {
6121     if (spans_.empty()) {
6122         info.SetSpanIndex(0);
6123         info.SetOffsetInSpan(0);
6124         return;
6125     }
6126     auto it = std::find_if(
6127         spans_.begin(), spans_.end(), [caretPosition = caretPosition_ + moveLength_](const RefPtr<SpanItem>& spanItem) {
6128             if (spanItem->content.empty()) {
6129                 return spanItem->position == caretPosition;
6130             }
6131             return spanItem->rangeStart <= caretPosition && caretPosition < spanItem->position;
6132         });
6133     if (it != spans_.end() && (*it)->unicode != 0 && (*it)->position - caretPosition_ + moveLength_ == 1) {
6134         it++;
6135         moveLength_++;
6136     }
6137     info.SetSpanIndex(std::distance(spans_.begin(), it));
6138     if (it == spans_.end()) {
6139         info.SetOffsetInSpan(0);
6140         return;
6141     }
6142     info.SetOffsetInSpan(
6143         caretPosition_ + moveLength_ - ((*it)->position - StringUtils::ToWstring((*it)->content).length()));
6144 }
6145 
6146 void RichEditorPattern::CalcDeleteValueObj(int32_t currentPosition, int32_t length, RichEditorDeleteValue& info)
6147 {
6148     auto it =
6149         std::find_if(spans_.begin(), spans_.end(), [caretPosition = currentPosition](const RefPtr<SpanItem>& spanItem) {
6150             return (spanItem->position - static_cast<int32_t>(StringUtils::ToWstring(spanItem->content).length()) <=
6151                        caretPosition) &&
6152                    (caretPosition < spanItem->position);
6153         });
6154     while (it != spans_.end() && length > 0) {
6155         if ((*it)->placeholderIndex >= 0 || (*it)->unicode != 0) {
6156             RichEditorAbstractSpanResult spanResult;
6157             spanResult.SetSpanIndex(std::distance(spans_.begin(), it));
6158             int32_t eraseLength = 0;
6159             if ((*it)->unicode != 0) {
6160                 eraseLength = DeleteValueSetSymbolSpan(*it, spanResult);
6161             } else if (AceType::InstanceOf<ImageSpanItem>(*it)) {
6162                 eraseLength = DeleteValueSetImageSpan(*it, spanResult);
6163             } else {
6164                 eraseLength = DeleteValueSetBuilderSpan(*it, spanResult);
6165             }
6166             currentPosition += eraseLength;
6167             length -= eraseLength;
6168             info.SetRichEditorDeleteSpans(spanResult);
6169         } else {
6170             RichEditorAbstractSpanResult spanResult;
6171             spanResult.SetSpanIndex(std::distance(spans_.begin(), it));
6172             auto eraseLength = DeleteValueSetTextSpan(*it, currentPosition, length, spanResult);
6173             length -= eraseLength;
6174             currentPosition += eraseLength;
6175             info.SetRichEditorDeleteSpans(spanResult);
6176         }
6177         std::advance(it, 1);
6178     }
6179 }
6180 
6181 RefPtr<SpanNode> RichEditorPattern::GetSpanNodeBySpanItem(const RefPtr<SpanItem> spanItem)
6182 {
6183     RefPtr<SpanNode> spanNode;
6184     auto iter = std::find(spans_.begin(), spans_.end(), spanItem);
6185     if (iter == spans_.end()) {
6186         return spanNode;
6187     }
6188     auto spanIndex = std::distance(spans_.begin(), iter);
6189     auto host = GetHost();
6190     CHECK_NULL_RETURN(host, spanNode);
6191     auto it = host->GetChildren().begin();
6192     std::advance(it, spanIndex);
6193     spanNode = AceType::DynamicCast<SpanNode>(*it);
6194     return spanNode;
6195 }
6196 
6197 int32_t RichEditorPattern::DeleteValueSetSymbolSpan(
6198     const RefPtr<SpanItem>& spanItem, RichEditorAbstractSpanResult& spanResult)
6199 {
6200     spanResult.SetSpanType(SpanResultType::SYMBOL);
6201     spanResult.SetSpanRangeEnd(spanItem->position);
6202     spanResult.SetSpanRangeStart(spanItem->position - SYMBOL_SPAN_LENGTH);
6203     spanResult.SetEraseLength(SYMBOL_SPAN_LENGTH);
6204     spanResult.SetValueString(std::to_string(spanItem->unicode));
6205     spanResult.SetValueResource(spanItem->GetResourceObject());
6206     auto spanNode = GetSpanNodeBySpanItem(spanItem);
6207     if (spanNode) {
6208         spanResult.SetSymbolSpanStyle(GetSymbolSpanStyleObject(spanNode));
6209     }
6210     return SYMBOL_SPAN_LENGTH;
6211 }
6212 
6213 int32_t RichEditorPattern::DeleteValueSetImageSpan(
6214     const RefPtr<SpanItem>& spanItem, RichEditorAbstractSpanResult& spanResult)
6215 {
6216     spanResult.SetSpanType(SpanResultType::IMAGE);
6217     spanResult.SetSpanRangeEnd(spanItem->position);
6218     spanResult.SetSpanRangeStart(spanItem->position - 1);
6219     spanResult.SetEraseLength(1);
6220     auto host = GetHost();
6221     CHECK_NULL_RETURN(host, IMAGE_SPAN_LENGTH);
6222     auto uiNode = host->GetChildAtIndex(spanResult.GetSpanIndex());
6223     CHECK_NULL_RETURN(uiNode, IMAGE_SPAN_LENGTH);
6224     auto imageNode = AceType::DynamicCast<FrameNode>(uiNode);
6225     CHECK_NULL_RETURN(imageNode, IMAGE_SPAN_LENGTH);
6226     auto imageRenderCtx = imageNode->GetRenderContext();
6227     if (imageRenderCtx->GetBorderRadius()) {
6228         BorderRadiusProperty brp;
6229         auto jsonObject = JsonUtil::Create(true);
6230         auto jsonBorder = JsonUtil::Create(true);
6231         InspectorFilter filter;
6232         imageRenderCtx->GetBorderRadiusValue(brp).ToJsonValue(jsonObject, jsonBorder, filter);
6233         spanResult.SetBorderRadius(jsonObject->GetValue("borderRadius")->IsObject()
6234                                        ? jsonObject->GetValue("borderRadius")->ToString()
6235                                        : jsonObject->GetString("borderRadius"));
6236     }
6237     auto geometryNode = imageNode->GetGeometryNode();
6238     CHECK_NULL_RETURN(geometryNode, IMAGE_SPAN_LENGTH);
6239     auto imageLayoutProperty = DynamicCast<ImageLayoutProperty>(imageNode->GetLayoutProperty());
6240     CHECK_NULL_RETURN(imageLayoutProperty, IMAGE_SPAN_LENGTH);
6241     spanResult.SetSizeWidth(geometryNode->GetMarginFrameSize().Width());
6242     spanResult.SetSizeHeight(geometryNode->GetMarginFrameSize().Height());
6243     if (imageLayoutProperty->GetMarginProperty()) {
6244         spanResult.SetMargin(imageLayoutProperty->GetMarginProperty()->ToString());
6245     }
6246     if (!imageLayoutProperty->GetImageSourceInfo()->GetPixmap()) {
6247         spanResult.SetValueResourceStr(imageLayoutProperty->GetImageSourceInfo()->GetSrc());
6248     } else {
6249         spanResult.SetValuePixelMap(imageLayoutProperty->GetImageSourceInfo()->GetPixmap());
6250     }
6251     if (imageLayoutProperty->HasImageFit()) {
6252         spanResult.SetImageFit(imageLayoutProperty->GetImageFitValue());
6253     }
6254     if (imageLayoutProperty->HasVerticalAlign()) {
6255         spanResult.SetVerticalAlign(imageLayoutProperty->GetVerticalAlignValue());
6256     }
6257     return IMAGE_SPAN_LENGTH;
6258 }
6259 
6260 int32_t RichEditorPattern::DeleteValueSetBuilderSpan(
6261     const RefPtr<SpanItem>& spanItem, RichEditorAbstractSpanResult& spanResult)
6262 {
6263     spanResult.SetSpanType(SpanResultType::IMAGE);
6264     spanResult.SetSpanRangeEnd(spanItem->position);
6265     spanResult.SetSpanRangeStart(spanItem->position - 1);
6266     spanResult.SetEraseLength(1);
6267     auto host = GetHost();
6268     CHECK_NULL_RETURN(host, 1);
6269     auto uiNode = host->GetChildAtIndex(spanResult.GetSpanIndex());
6270     CHECK_NULL_RETURN(uiNode, 1);
6271     auto builderNode = AceType::DynamicCast<FrameNode>(uiNode);
6272     CHECK_NULL_RETURN(builderNode, 1);
6273     auto geometryNode = builderNode->GetGeometryNode();
6274     CHECK_NULL_RETURN(geometryNode, 1);
6275     spanResult.SetSizeWidth(geometryNode->GetMarginFrameSize().Width());
6276     spanResult.SetSizeHeight(geometryNode->GetMarginFrameSize().Height());
6277     return 1;
6278 }
6279 
6280 int32_t RichEditorPattern::DeleteValueSetTextSpan(
6281     const RefPtr<SpanItem>& spanItem, int32_t currentPosition, int32_t length, RichEditorAbstractSpanResult& spanResult)
6282 {
6283     spanResult.SetSpanType(SpanResultType::TEXT);
6284     auto contentStartPosition
6285         = spanItem->position - static_cast<int32_t>(StringUtils::ToWstring(spanItem->content).length());
6286     spanResult.SetSpanRangeStart(contentStartPosition);
6287     int32_t eraseLength = 0;
6288     if (spanItem->position - currentPosition >= length) {
6289         eraseLength = length;
6290     } else {
6291         eraseLength = spanItem->position - currentPosition;
6292     }
6293     spanResult.SetSpanRangeEnd(spanItem->position);
6294     if (!previewTextRecord_.previewContent.empty()) {
6295         spanResult.SetPreviewText(previewTextRecord_.previewContent);
6296     } else {
6297         spanResult.SetValue(spanItem->content);
6298     }
6299     spanResult.SetOffsetInSpan(currentPosition - contentStartPosition);
6300     spanResult.SetEraseLength(eraseLength);
6301     if (!spanItem->GetTextStyle().has_value()) {
6302         TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "SpanItem text style is empty.");
6303         return eraseLength;
6304     }
6305     spanResult.SetFontColor(spanItem->GetTextStyle()->GetTextColor().ColorToString());
6306     spanResult.SetFontSize(spanItem->GetTextStyle()->GetFontSize().Value());
6307     spanResult.SetFontStyle(spanItem->GetTextStyle()->GetFontStyle());
6308     spanResult.SetFontWeight((int32_t)(spanItem->GetTextStyle()->GetFontWeight()));
6309     if (!spanItem->GetTextStyle()->GetFontFamilies().empty()) {
6310         spanResult.SetFontFamily(spanItem->GetTextStyle()->GetFontFamilies().at(0));
6311     }
6312     spanResult.SetColor(spanItem->GetTextStyle()->GetTextDecorationColor().ColorToString());
6313     spanResult.SetTextDecoration(spanItem->GetTextStyle()->GetTextDecoration());
6314     spanResult.SetTextDecorationStyle(spanItem->GetTextStyle()->GetTextDecorationStyle());
6315     spanResult.SetFontFeature(spanItem->GetTextStyle()->GetFontFeatures());
6316     auto host = GetHost();
6317     CHECK_NULL_RETURN(host, eraseLength);
6318     auto uiNode = host->GetChildAtIndex(spanResult.GetSpanIndex());
6319     CHECK_NULL_RETURN(uiNode, eraseLength);
6320     auto spanNode = DynamicCast<SpanNode>(uiNode);
6321     CHECK_NULL_RETURN(spanNode, eraseLength);
6322     spanResult.SetTextStyle(GetTextStyleObject(spanNode));
6323     return eraseLength;
6324 }
6325 
6326 void RichEditorPattern::DeleteByDeleteValueInfo(const RichEditorDeleteValue& info)
6327 {
6328     auto deleteSpans = info.GetRichEditorDeleteSpans();
6329     if (deleteSpans.empty()) {
6330         return;
6331     }
6332     auto host = GetHost();
6333     CHECK_NULL_VOID(host);
6334     ProcessDeleteNodes(deleteSpans);
6335     UpdateSpanPosition();
6336     SetCaretPosition(info.GetOffset(), false);
6337     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
6338     OnModifyDone();
6339 }
6340 
6341 int32_t RichEditorPattern::ProcessDeleteNodes(std::list<RichEditorAbstractSpanResult>& deleteSpans)
6342 {
6343     auto eraseLength = 0;
6344     auto host = GetHost();
6345     CHECK_NULL_RETURN(host, eraseLength);
6346     std::set<int32_t, std::greater<int32_t>> deleteNodes;
6347     for (const auto& it : deleteSpans) {
6348         eraseLength += it.GetEraseLength();
6349         switch (it.GetType()) {
6350             case SpanResultType::TEXT: {
6351                 auto ui_node = host->GetChildAtIndex(it.GetSpanIndex());
6352                 CHECK_NULL_RETURN(ui_node, eraseLength);
6353                 auto spanNode = DynamicCast<SpanNode>(ui_node);
6354                 CHECK_NULL_RETURN(spanNode, eraseLength);
6355                 auto spanItem = spanNode->GetSpanItem();
6356                 CHECK_NULL_RETURN(spanItem, eraseLength);
6357                 auto text = spanItem->content;
6358                 std::wstring textTemp = StringUtils::ToWstring(text);
6359                 auto textTempSize = static_cast<int32_t>(textTemp.size());
6360                 if (textTempSize < it.OffsetInSpan()) {
6361                     TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "ProcessDeleteNodes failed, "
6362                         "content = %{private}s, spanItemSize = %{public}d, offsetInSpan = %{public}d",
6363                         text.c_str(), textTempSize, it.OffsetInSpan());
6364                     continue;
6365                 }
6366                 textTemp.erase(it.OffsetInSpan(), it.GetEraseLength());
6367                 if (textTemp.size() == 0) {
6368                     deleteNodes.emplace(it.GetSpanIndex());
6369                 }
6370                 text = StringUtils::ToString(textTemp);
6371                 spanNode->UpdateContent(text);
6372                 spanItem->position -= it.GetEraseLength();
6373                 break;
6374             }
6375             case SpanResultType::IMAGE:
6376                 deleteNodes.emplace(it.GetSpanIndex());
6377                 break;
6378             case SpanResultType::SYMBOL:
6379                 deleteNodes.emplace(it.GetSpanIndex());
6380                 break;
6381             default:
6382                 break;
6383         }
6384     }
6385     RemoveEmptySpan(deleteNodes);
6386     return eraseLength;
6387 }
6388 
6389 void RichEditorPattern::RemoveEmptySpan(std::set<int32_t, std::greater<int32_t>>& deleteSpanIndexs)
6390 {
6391     auto host = GetHost();
6392     CHECK_NULL_VOID(host);
6393     for (auto index : deleteSpanIndexs) {
6394         host->RemoveChildAtIndex(index);
6395         auto it = spans_.begin();
6396         std::advance(it, index);
6397         if (it != spans_.end()) {
6398             spans_.erase(it);
6399         }
6400     }
6401 }
6402 
6403 RefPtr<GestureEventHub> RichEditorPattern::GetGestureEventHub() {
6404     auto host = GetHost();
6405     CHECK_NULL_RETURN(host, nullptr);
6406     return host->GetOrCreateGestureEventHub();
6407 }
6408 
6409 bool RichEditorPattern::OnKeyEvent(const KeyEvent& keyEvent)
6410 {
6411     return TextInputClient::HandleKeyEvent(keyEvent);
6412 }
6413 
6414 void RichEditorPattern::CursorMove(CaretMoveIntent direction)
6415 {
6416     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "direction=%{public}d", direction);
6417     switch (direction) {
6418         case CaretMoveIntent::Left:
6419             CursorMoveLeft();
6420             break;
6421         case CaretMoveIntent::Right:
6422             CursorMoveRight();
6423             break;
6424         case CaretMoveIntent::Up:
6425             CursorMoveUp();
6426             break;
6427         case CaretMoveIntent::Down:
6428             CursorMoveDown();
6429             break;
6430         case CaretMoveIntent::LeftWord:
6431             CursorMoveToNextWord(direction);
6432             break;
6433         case CaretMoveIntent::RightWord:
6434             CursorMoveToNextWord(direction);
6435             break;
6436         case CaretMoveIntent::ParagraghBegin:
6437             CursorMoveToParagraphBegin();
6438             break;
6439         case CaretMoveIntent::ParagraghEnd:
6440             CursorMoveToParagraphEnd();
6441             break;
6442         case CaretMoveIntent::Home:
6443             CursorMoveHome();
6444             break;
6445         case CaretMoveIntent::End:
6446             CursorMoveEnd();
6447             break;
6448         case CaretMoveIntent::LineBegin:
6449             CursorMoveLineBegin();
6450             break;
6451         case CaretMoveIntent::LineEnd:
6452             CursorMoveLineEnd();
6453             break;
6454         default:
6455             LOGW("Unsupported cursor move operation for rich editor");
6456     }
6457 }
6458 
6459 void RichEditorPattern::MoveCaretAfterTextChange()
6460 {
6461     CHECK_NULL_VOID(isTextChange_);
6462     isTextChange_ = false;
6463     switch (moveDirection_) {
6464         case MoveDirection::BACKWARD:
6465             SetCaretPosition(
6466                 std::clamp((caretPosition_ - moveLength_), 0, static_cast<int32_t>(GetTextContentLength())), false);
6467             break;
6468         case MoveDirection::FORWARD:
6469             SetCaretPosition(
6470                 std::clamp((caretPosition_ + moveLength_), 0, static_cast<int32_t>(GetTextContentLength())), false);
6471             break;
6472         default:
6473             break;
6474     }
6475     moveLength_ = 0;
6476 }
6477 
6478 void RichEditorPattern::InitTouchEvent()
6479 {
6480     CHECK_NULL_VOID(!touchListener_);
6481     auto gesture = GetGestureEventHub();
6482     CHECK_NULL_VOID(gesture);
6483     auto touchTask = [weak = WeakClaim(this)](const TouchEventInfo& info) {
6484         auto pattern = weak.Upgrade();
6485         CHECK_NULL_VOID(pattern);
6486         pattern->HandleTouchEvent(info);
6487     };
6488     touchListener_ = MakeRefPtr<TouchEventImpl>(std::move(touchTask));
6489     gesture->AddTouchEvent(touchListener_);
6490 }
6491 
6492 void RichEditorPattern::InitPanEvent()
6493 {
6494     CHECK_NULL_VOID(!panEvent_);
6495     auto host = GetHost();
6496     CHECK_NULL_VOID(host);
6497     auto gestureHub = host->GetOrCreateGestureEventHub();
6498     CHECK_NULL_VOID(gestureHub);
6499     auto actionStartTask = [](const GestureEvent& info) {};
6500     auto actionUpdateTask = [](const GestureEvent& info) {};
6501     auto actionEndTask = [](const GestureEvent& info) {};
6502     GestureEventNoParameter actionCancelTask;
6503     panEvent_ = MakeRefPtr<PanEvent>(std::move(actionStartTask), std::move(actionUpdateTask),
6504         std::move(actionEndTask), std::move(actionCancelTask));
6505     PanDirection panDirection = { .type = PanDirection::ALL };
6506     gestureHub->AddPanEvent(panEvent_, panDirection, 1, DEFAULT_PAN_DISTANCE);
6507     gestureHub->SetPanEventType(GestureTypeName::PAN_GESTURE);
6508     gestureHub->SetOnGestureJudgeNativeBegin([weak = WeakClaim(this)](const RefPtr<NG::GestureInfo>& gestureInfo,
6509                                                  const std::shared_ptr<BaseGestureEvent>& info) -> GestureJudgeResult {
6510         auto pattern = weak.Upgrade();
6511         CHECK_NULL_RETURN(pattern, GestureJudgeResult::CONTINUE);
6512         auto gestureType = gestureInfo->GetType();
6513         auto inputEventType = gestureInfo->GetInputEventType();
6514         bool isDraggingCaret = (gestureType == GestureTypeName::PAN_GESTURE)
6515             && (inputEventType == InputEventType::TOUCH_SCREEN) && pattern->moveCaretState_.isMoveCaret;
6516         bool isMouseSelecting = (gestureType == GestureTypeName::PAN_GESTURE)
6517             && (inputEventType == InputEventType::MOUSE_BUTTON) && !pattern->blockPress_;
6518         if (isDraggingCaret || isMouseSelecting) {
6519             TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "prevent pan gesture draggingCaret=%{public}d mouseSelecting=%{public}d",
6520                 isDraggingCaret, isMouseSelecting);
6521             return GestureJudgeResult::CONTINUE;
6522         }
6523         CHECK_NULL_RETURN(gestureInfo->GetType() != GestureTypeName::PAN_GESTURE, GestureJudgeResult::REJECT);
6524         return GestureJudgeResult::CONTINUE;
6525     });
6526 }
6527 
6528 void RichEditorPattern::HandleTouchEvent(const TouchEventInfo& info)
6529 {
6530     CHECK_NULL_VOID(!selectOverlay_->IsTouchAtHandle(info));
6531     CHECK_NULL_VOID(!info.GetTouches().empty());
6532     auto touchInfo = info.GetTouches().front();
6533     auto touchType = touchInfo.GetTouchType();
6534     if (touchType == TouchType::DOWN) {
6535         HandleTouchDown(info);
6536         bool isMousePressWithShift = shiftFlag_ && info.GetSourceTool() == SourceTool::MOUSE;
6537         IF_TRUE(!isMousePressWithShift, HandleOnlyImageSelected(touchInfo.GetLocalLocation(), info.GetSourceTool()));
6538         if (hasUrlSpan_) {
6539             HandleUrlSpanShowShadow(touchInfo.GetLocalLocation(), touchInfo.GetGlobalLocation(), GetUrlPressColor());
6540         }
6541     } else if (touchType == TouchType::UP) {
6542         isOnlyImageDrag_ = false;
6543         HandleTouchUp();
6544         if (hasUrlSpan_) {
6545             HandleUrlSpanForegroundClear();
6546         }
6547     } else if (touchType == TouchType::MOVE) {
6548         auto originalLocaloffset = touchInfo.GetLocalLocation();
6549         auto localOffset = AdjustLocalOffsetOnMoveEvent(originalLocaloffset);
6550         HandleTouchMove(localOffset);
6551     }
6552 }
6553 
6554 void RichEditorPattern::HandleUrlSpanForegroundClear()
6555 {
6556     overlayMod_->ClearSelectedForegroundColorAndRects();
6557     MarkDirtySelf();
6558 }
6559 
6560 void RichEditorPattern::HandleTouchDown(const TouchEventInfo& info)
6561 {
6562     auto sourceTool = info.GetSourceTool();
6563     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "Touch down longPressState=[%{public}d, %{public}d], source=%{public}d",
6564         previewLongPress_, editingLongPress_, sourceTool);
6565     globalOffsetOnMoveStart_ = GetParentGlobalOffset();
6566     moveCaretState_.Reset();
6567     isMoveCaretAnywhere_ = false;
6568     previewLongPress_ = false;
6569     editingLongPress_ = false;
6570     CHECK_NULL_VOID(HasFocus() && sourceTool == SourceTool::FINGER);
6571     auto touchDownOffset = info.GetTouches().front().GetLocalLocation();
6572     moveCaretState_.touchDownOffset = touchDownOffset;
6573     RectF lastCaretRect = GetCaretRect();
6574     if (RepeatClickCaret(touchDownOffset, caretPosition_, lastCaretRect)) {
6575         moveCaretState_.isTouchCaret = true;
6576         auto host = GetHost();
6577         CHECK_NULL_VOID(host);
6578     }
6579 }
6580 
6581 void RichEditorPattern::HandleTouchUp()
6582 {
6583     HandleTouchUpAfterLongPress();
6584     if (moveCaretState_.isMoveCaret) {
6585         isCursorAlwaysDisplayed_ = false;
6586         StartTwinkling();
6587     }
6588     CheckScrollable();
6589     moveCaretState_.Reset();
6590     isMoveCaretAnywhere_ = false;
6591     editingLongPress_ = false;
6592     if (magnifierController_) {
6593         magnifierController_->RemoveMagnifierFrameNode();
6594     }
6595 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
6596     if (isLongPress_) {
6597         isLongPress_ = false;
6598     }
6599 #endif
6600 }
6601 
6602 void RichEditorPattern::HandleTouchUpAfterLongPress()
6603 {
6604     CHECK_NULL_VOID(editingLongPress_ || previewLongPress_);
6605     auto selectStart = textSelector_.GetTextStart();
6606     auto selectEnd = textSelector_.GetTextEnd();
6607     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "after long press textSelector=[%{public}d, %{public}d] isEditing=%{public}d",
6608         selectStart, selectEnd, isEditing_);
6609     FireOnSelect(selectStart, selectEnd);
6610     SetCaretPositionWithAffinity({ selectEnd, TextAffinity::UPSTREAM });
6611     CalculateHandleOffsetAndShowOverlay();
6612     selectOverlay_->ProcessOverlay({ .animation = true });
6613     FireOnSelectionChange(selectStart, selectEnd);
6614     IF_TRUE(IsSingleHandle(), ForceTriggerAvoidOnCaretChange());
6615 }
6616 
6617 void RichEditorPattern::HandleTouchMove(const Offset& offset)
6618 {
6619     if (previewLongPress_ || editingLongPress_) {
6620         UpdateSelectionByTouchMove(offset);
6621         return;
6622     }
6623     CHECK_NULL_VOID(moveCaretState_.isTouchCaret);
6624     if (!moveCaretState_.isMoveCaret) {
6625         auto moveDistance = (offset - moveCaretState_.touchDownOffset).GetDistance();
6626         if (GreatNotEqual(moveDistance, moveCaretState_.minDistance.ConvertToPx())) {
6627             TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "Move caret distance greater than minDistance");
6628             moveCaretState_.isMoveCaret = true;
6629             ShowCaretWithoutTwinkling();
6630         }
6631     }
6632     UpdateCaretByTouchMove(offset);
6633 }
6634 
6635 void RichEditorPattern::UpdateCaretByTouchMove(const Offset& offset)
6636 {
6637     CHECK_NULL_VOID(moveCaretState_.isMoveCaret);
6638     auto host = GetHost();
6639     CHECK_NULL_VOID(host);
6640     scrollable_ = false;
6641     SetScrollEnabled(scrollable_);
6642     if (SelectOverlayIsOn()) {
6643         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "Close select overlay while dragging caret");
6644         selectOverlay_->CloseOverlay(false, CloseReason::CLOSE_REASON_NORMAL);
6645     }
6646     auto preCaretPosition = caretPosition_;
6647     Offset textOffset = ConvertTouchOffsetToTextOffset(offset);
6648     auto positionWithAffinity = paragraphs_.GetGlyphPositionAtCoordinate(textOffset);
6649     SetCaretPositionWithAffinity(positionWithAffinity);
6650     MoveCaretToContentRect();
6651     StartVibratorByIndexChange(caretPosition_, preCaretPosition);
6652     CalcAndRecordLastClickCaretInfo(textOffset);
6653     auto localOffset = OffsetF(offset.GetX(), offset.GetY());
6654     if (magnifierController_) {
6655         magnifierController_->SetLocalOffset(localOffset);
6656     }
6657     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
6658 }
6659 
6660 Offset RichEditorPattern::AdjustLocalOffsetOnMoveEvent(const Offset& originalOffset)
6661 {
6662     auto deltaOffset = GetParentGlobalOffset() - globalOffsetOnMoveStart_;
6663     return { originalOffset.GetX() - deltaOffset.GetX(), originalOffset.GetY() - deltaOffset.GetY() };
6664 }
6665 
6666 void RichEditorPattern::StartVibratorByIndexChange(int32_t currentIndex, int32_t preIndex)
6667 {
6668     CHECK_NULL_VOID(isEnableHapticFeedback_ && (currentIndex != preIndex));
6669     VibratorUtils::StartVibraFeedback("slide");
6670 }
6671 
6672 bool RichEditorPattern::IsScrollBarPressed(const MouseInfo& info)
6673 {
6674     auto scrollBar = GetScrollBar();
6675     bool isScrollBarShow = scrollBar && scrollBar->NeedPaint();
6676     CHECK_NULL_RETURN(isScrollBarShow, false);
6677     Point point(info.GetLocalLocation().GetX(), info.GetLocalLocation().GetY());
6678     return scrollBar->InBarRectRegion(point);
6679 }
6680 
6681 void RichEditorPattern::HandleMouseLeftButtonMove(const MouseInfo& info)
6682 {
6683     ACE_SCOPED_TRACE("RichEditorHandleMouseLeftButtonMove");
6684     if (blockPress_) {
6685         ACE_SCOPED_TRACE("RichEditorUpdateDragBoxes");
6686         dragBoxes_ = GetTextBoxes();
6687         return;
6688     }
6689     CHECK_NULL_VOID(leftMousePress_);
6690 
6691     auto localOffset = AdjustLocalOffsetOnMoveEvent(info.GetLocalLocation());
6692     Offset textOffset = ConvertTouchOffsetToTextOffset(localOffset);
6693     if (dataDetectorAdapter_->pressedByLeftMouse_) {
6694         dataDetectorAdapter_->pressedByLeftMouse_ = false;
6695         MoveCaretAndStartFocus(textOffset);
6696     }
6697 
6698     auto focusHub = GetFocusHub();
6699     CHECK_NULL_VOID(focusHub);
6700     CHECK_NULL_VOID(focusHub->IsCurrentFocus());
6701 
6702     mouseStatus_ = MouseStatus::MOVE;
6703     if (isFirstMouseSelect_) {
6704         int32_t extend = paragraphs_.GetIndex(textOffset);
6705         UpdateSelector(textSelector_.baseOffset, extend);
6706         isFirstMouseSelect_ = false;
6707     } else {
6708         int32_t extend = paragraphs_.GetIndex(textOffset);
6709         UpdateSelector(textSelector_.baseOffset, extend);
6710         auto position = paragraphs_.GetIndex(textOffset);
6711         AdjustCursorPosition(position);
6712         SetCaretPosition(position);
6713         AutoScrollParam param = {
6714             .autoScrollEvent = AutoScrollEvent::MOUSE, .showScrollbar = true, .eventOffset = info.GetLocalLocation()
6715         };
6716         AutoScrollByEdgeDetection(param, OffsetF(info.GetLocalLocation().GetX(), info.GetLocalLocation().GetY()),
6717             EdgeDetectionStrategy::OUT_BOUNDARY);
6718         showSelect_ = true;
6719     }
6720     if (textSelector_.SelectNothing()) {
6721         if (!caretTwinkling_) {
6722             StartTwinkling();
6723         }
6724     } else {
6725         StopTwinkling();
6726     }
6727     isMouseSelect_ = true;
6728     auto host = GetHost();
6729     CHECK_NULL_VOID(host);
6730     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
6731 }
6732 
6733 void RichEditorPattern::HandleMouseLeftButtonPress(const MouseInfo& info)
6734 {
6735     isMousePressed_ = true;
6736     IF_TRUE(!shiftFlag_, HandleOnlyImageSelected(info.GetLocalLocation(), SourceTool::MOUSE));
6737     if ((IsPreviewTextInputting() && shiftFlag_) || IsScrollBarPressed(info)
6738         || BetweenSelectedPosition(info.GetGlobalLocation())) {
6739         blockPress_ = true;
6740         return;
6741     }
6742     auto focusHub = GetFocusHub();
6743     CHECK_NULL_VOID(focusHub);
6744     if (!focusHub->IsFocusable()) {
6745         return;
6746     }
6747     auto textPaintOffset = GetTextRect().GetOffset() - OffsetF(0.0, std::min(baselineOffset_, 0.0f));
6748     Offset textOffset = { info.GetLocalLocation().GetX() - textPaintOffset.GetX(),
6749         info.GetLocalLocation().GetY() - textPaintOffset.GetY() };
6750     int32_t position = (GetTextContentLength() == 0) ? 0 : paragraphs_.GetIndex(textOffset);
6751     if (shiftFlag_) {
6752         HandleShiftSelect(position);
6753     } else {
6754         IF_TRUE(!textSelector_.SelectNothing(), ResetSelection());
6755         textSelector_.Update(position);
6756     }
6757     leftMousePress_ = true;
6758     globalOffsetOnMoveStart_ = GetParentGlobalOffset();
6759     mouseStatus_ = MouseStatus::PRESSED;
6760     blockPress_ = false;
6761     caretUpdateType_ = CaretUpdateType::PRESSED;
6762     dataDetectorAdapter_->pressedByLeftMouse_ = false;
6763     HandleClickAISpanEvent(PointF(textOffset.GetX(), textOffset.GetY()));
6764     if (dataDetectorAdapter_->pressedByLeftMouse_) {
6765         return;
6766     }
6767     UseHostToUpdateTextFieldManager();
6768     MoveCaretAndStartFocus(textOffset);
6769     CalcCaretInfoByClick(info.GetLocalLocation());
6770 }
6771 
6772 void RichEditorPattern::HandleShiftSelect(int32_t position)
6773 {
6774     CHECK_NULL_VOID(shiftFlag_);
6775     int32_t start = textSelector_.SelectNothing() ? caretPosition_ : textSelector_.baseOffset;
6776     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "HandleShiftSelect [%{public}d-%{public}d]", start, position);
6777     UpdateSelector(start, position);
6778     FireOnSelect(textSelector_.GetTextStart(), textSelector_.GetTextEnd());
6779     auto host = GetHost();
6780     CHECK_NULL_VOID(host);
6781     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
6782 }
6783 
6784 void RichEditorPattern::HandleMouseLeftButtonRelease(const MouseInfo& info)
6785 {
6786     blockPress_ = false;
6787     leftMousePress_ = false;
6788     auto oldMouseStatus = mouseStatus_;
6789     mouseStatus_ = MouseStatus::RELEASED;
6790     isMouseSelect_ = false;
6791     isFirstMouseSelect_ = true;
6792     isOnlyImageDrag_ = false;
6793     if (!showSelect_) {
6794         showSelect_ = true;
6795         ResetSelection();
6796     }
6797     if (dataDetectorAdapter_->pressedByLeftMouse_ && oldMouseStatus != MouseStatus::MOVE && !IsDragging()) {
6798         dataDetectorAdapter_->ResponseBestMatchItem(dataDetectorAdapter_->clickedAISpan_);
6799         dataDetectorAdapter_->pressedByLeftMouse_ = false;
6800         isMousePressed_ = false;
6801         return;
6802     }
6803 
6804     auto selectStart = std::min(textSelector_.baseOffset, textSelector_.destinationOffset);
6805     auto selectEnd = std::max(textSelector_.baseOffset, textSelector_.destinationOffset);
6806     if (selectStart != selectEnd) {
6807         FireOnSelect(selectStart, selectEnd);
6808     }
6809     StopAutoScroll(false);
6810     if (textSelector_.IsValid() && !textSelector_.StartEqualToDest() && IsSelectedBindSelectionMenu() &&
6811         oldMouseStatus == MouseStatus::MOVE) {
6812         auto offsetX = static_cast<float>(info.GetGlobalLocation().GetX());
6813         auto offsetY = static_cast<float>(info.GetGlobalLocation().GetY());
6814         selectionMenuOffsetByMouse_ = OffsetF(offsetX, offsetY);
6815         selectionMenuOffsetClick_ = OffsetF(offsetX, offsetY);
6816         ShowSelectOverlay(RectF(), RectF(), false, TextResponseType::SELECTED_BY_MOUSE);
6817     }
6818     isMousePressed_ = false;
6819     if (HasFocus()) {
6820         HandleOnEditChanged(true);
6821     }
6822 }
6823 
6824 void RichEditorPattern::HandleMouseLeftButton(const MouseInfo& info)
6825 {
6826     if (info.GetAction() == MouseAction::MOVE) {
6827         HandleMouseLeftButtonMove(info);
6828     } else if (info.GetAction() == MouseAction::PRESS) {
6829         HandleMouseLeftButtonPress(info);
6830     } else if (info.GetAction() == MouseAction::RELEASE) {
6831         HandleMouseLeftButtonRelease(info);
6832     }
6833 }
6834 
6835 void RichEditorPattern::HandleMouseRightButton(const MouseInfo& info)
6836 {
6837     auto focusHub = GetFocusHub();
6838     CHECK_NULL_VOID(focusHub);
6839     if (!focusHub->IsFocusable()) {
6840         return;
6841     }
6842     if (info.GetAction() == MouseAction::PRESS) {
6843         isMousePressed_ = true;
6844         usingMouseRightButton_ = true;
6845         CloseSelectOverlay();
6846     } else if (info.GetAction() == MouseAction::RELEASE) {
6847         auto offsetX = static_cast<float>(info.GetGlobalLocation().GetX());
6848         auto offsetY = static_cast<float>(info.GetGlobalLocation().GetY());
6849         selectionMenuOffsetByMouse_ = OffsetF(offsetX, offsetY);
6850         selectionMenuOffsetClick_ = OffsetF(offsetX, offsetY);
6851         selectOverlay_->SetIsSingleHandle(false);
6852         if (textSelector_.IsValid() && BetweenSelection(info.GetGlobalLocation())) {
6853             ShowSelectOverlay(RectF(), RectF());
6854             isMousePressed_ = false;
6855             usingMouseRightButton_ = false;
6856             return;
6857         }
6858         auto textPaintOffset = GetTextRect().GetOffset() - OffsetF(0.0f, std::min(baselineOffset_, 0.0f));
6859         Offset textOffset = { info.GetLocalLocation().GetX() - textPaintOffset.GetX(),
6860             info.GetLocalLocation().GetY() - textPaintOffset.GetY() };
6861         HandleClickAISpanEvent(PointF(textOffset.GetX(), textOffset.GetY()));
6862         if (dataDetectorAdapter_->hasClickedAISpan_) {
6863             dataDetectorAdapter_->hasClickedAISpan_ = false;
6864             isMousePressed_ = false;
6865             usingMouseRightButton_ = false;
6866             return;
6867         }
6868         if (textSelector_.IsValid()) {
6869             CloseSelectOverlay();
6870             ResetSelection();
6871         }
6872         MouseRightFocus(info);
6873         ShowSelectOverlay(RectF(), RectF());
6874         isMousePressed_ = false;
6875         usingMouseRightButton_ = false;
6876     }
6877 }
6878 
6879 void RichEditorPattern::MouseRightFocus(const MouseInfo& info)
6880 {
6881     auto textRect = GetTextRect();
6882     textRect.SetTop(textRect.GetY() - std::min(baselineOffset_, 0.0f));
6883     textRect.SetHeight(textRect.Height() - std::max(baselineOffset_, 0.0f));
6884     Offset textOffset = { info.GetLocalLocation().GetX() - textRect.GetX(),
6885         info.GetLocalLocation().GetY() - textRect.GetY() };
6886     InitSelection(textOffset);
6887     auto selectStart = std::min(textSelector_.baseOffset, textSelector_.destinationOffset);
6888     auto selectEnd = std::max(textSelector_.baseOffset, textSelector_.destinationOffset);
6889     auto host = GetHost();
6890     CHECK_NULL_VOID(host);
6891     auto focusHub = host->GetOrCreateFocusHub();
6892     CHECK_NULL_VOID(focusHub);
6893     focusHub->RequestFocusImmediately();
6894     SetCaretPosition(selectEnd);
6895 
6896     TextInsertValueInfo spanInfo;
6897     CalcInsertValueObj(spanInfo);
6898     auto spanNode = DynamicCast<FrameNode>(GetChildByIndex(spanInfo.GetSpanIndex() - 1));
6899     auto isNeedSelected = spanNode && (spanNode->GetTag() == V2::IMAGE_ETS_TAG ||
6900         spanNode->GetTag() == V2::PLACEHOLDER_SPAN_ETS_TAG);
6901     if (isNeedSelected && BetweenSelectedPosition(info.GetGlobalLocation())) {
6902         selectedType_ = TextSpanType::IMAGE;
6903         FireOnSelect(selectStart, selectEnd);
6904         host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
6905         return;
6906     }
6907     if (textSelector_.IsValid()) {
6908         ResetSelection();
6909     }
6910     auto position = paragraphs_.GetIndex(textOffset);
6911     SetCaretPosition(position);
6912     CalcAndRecordLastClickCaretInfo(textOffset);
6913     auto [caretOffset, caretHeight] = CalculateCaretOffsetAndHeight();
6914     selectedType_ = TextSpanType::TEXT;
6915     CHECK_NULL_VOID(overlayMod_);
6916     DynamicCast<RichEditorOverlayModifier>(overlayMod_)->SetCaretOffsetAndHeight(caretOffset, caretHeight);
6917     StartTwinkling();
6918 }
6919 
6920 void RichEditorPattern::FireOnSelect(int32_t selectStart, int32_t selectEnd)
6921 {
6922     auto host = GetHost();
6923     CHECK_NULL_VOID(host);
6924     auto eventHub = host->GetEventHub<RichEditorEventHub>();
6925     CHECK_NULL_VOID(eventHub);
6926     auto textSelectInfo = GetSpansInfo(selectStart, selectEnd, GetSpansMethod::ONSELECT);
6927     if (!textSelectInfo.GetSelection().resultObjects.empty()) {
6928         eventHub->FireOnSelect(&textSelectInfo);
6929     }
6930     UpdateSelectionType(textSelectInfo);
6931 }
6932 
6933 void RichEditorPattern::UpdateSelectionType(const SelectionInfo& textSelectInfo)
6934 {
6935     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
6936         TextPattern::UpdateSelectionType(GetAdjustedSelectionInfo(textSelectInfo));
6937     } else {
6938         TextPattern::UpdateSelectionType(textSelectInfo);
6939     }
6940 }
6941 
6942 SelectionInfo RichEditorPattern::GetAdjustedSelectionInfo(const SelectionInfo& textSelectInfo)
6943 {
6944     auto selection = textSelectInfo.GetSelection();
6945     auto resultObjects = selection.resultObjects;
6946     std::for_each(resultObjects.begin(), resultObjects.end(), [](ResultObject& object) {
6947         if (object.type == SelectSpanType::TYPEIMAGE && object.valueString == " " && object.valuePixelMap == nullptr) {
6948             object.type = SelectSpanType::TYPEBUILDERSPAN;
6949         }
6950     });
6951     SelectionInfo adjustedInfo;
6952     adjustedInfo.SetSelectionStart(selection.selection[RichEditorSpanRange::RANGESTART]);
6953     adjustedInfo.SetSelectionEnd(selection.selection[RichEditorSpanRange::RANGEEND]);
6954     adjustedInfo.SetResultObjectList(resultObjects);
6955     return adjustedInfo;
6956 }
6957 
6958 void RichEditorPattern::HandleMouseEvent(const MouseInfo& info)
6959 {
6960     auto tmpHost = GetHost();
6961     CHECK_NULL_VOID(tmpHost);
6962     auto frameId = tmpHost->GetId();
6963     auto pipeline = tmpHost->GetContext();
6964     CHECK_NULL_VOID(pipeline);
6965     if (selectOverlay_->IsHandleShow() && info.GetAction() == MouseAction::PRESS) {
6966         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "Close selectOverlay when handle is showing");
6967         CloseSelectOverlay();
6968     }
6969     auto scrollBar = GetScrollBar();
6970     if (scrollBar && (scrollBar->IsHover() || scrollBar->IsPressed())) {
6971         pipeline->SetMouseStyleHoldNode(frameId);
6972         pipeline->ChangeMouseStyle(frameId, MouseFormat::DEFAULT);
6973         currentMouseStyle_ = MouseFormat::DEFAULT;
6974         HandleUrlSpanForegroundClear();
6975         return;
6976     }
6977 
6978     if (hasUrlSpan_) {
6979         auto show = HandleUrlSpanShowShadow(info.GetLocalLocation(), info.GetGlobalLocation(), GetUrlHoverColor());
6980         if (show) {
6981             pipeline->SetMouseStyleHoldNode(frameId);
6982             pipeline->ChangeMouseStyle(frameId, MouseFormat::HAND_POINTING);
6983         } else {
6984             pipeline->SetMouseStyleHoldNode(frameId);
6985             pipeline->ChangeMouseStyle(frameId, MouseFormat::TEXT_CURSOR);
6986         }
6987     }
6988 
6989     if (currentMouseStyle_ == MouseFormat::DEFAULT) {
6990         pipeline->SetMouseStyleHoldNode(frameId);
6991         pipeline->ChangeMouseStyle(frameId, MouseFormat::TEXT_CURSOR);
6992         currentMouseStyle_ = MouseFormat::TEXT_CURSOR;
6993     }
6994 
6995     caretUpdateType_ = CaretUpdateType::NONE;
6996     if (info.GetButton() == MouseButton::LEFT_BUTTON) {
6997         HandleMouseLeftButton(info);
6998     } else if (info.GetButton() == MouseButton::RIGHT_BUTTON) {
6999         HandleMouseRightButton(info);
7000     }
7001 }
7002 
7003 Color RichEditorPattern::GetUrlHoverColor()
7004 {
7005     auto pipeline = PipelineContext::GetCurrentContextSafely();
7006     CHECK_NULL_RETURN(pipeline, Color());
7007     auto theme = pipeline->GetTheme<RichEditorTheme>();
7008     CHECK_NULL_RETURN(theme, Color());
7009     return theme->GetUrlHoverColor();
7010 }
7011 
7012 Color RichEditorPattern::GetUrlPressColor()
7013 {
7014     auto pipeline = PipelineContext::GetCurrentContextSafely();
7015     CHECK_NULL_RETURN(pipeline, Color());
7016     auto theme = pipeline->GetTheme<RichEditorTheme>();
7017     CHECK_NULL_RETURN(theme, Color());
7018     return theme->GetUrlPressColor();
7019 }
7020 
7021 Color RichEditorPattern::GetUrlSpanColor()
7022 {
7023     auto pipeline = PipelineContext::GetCurrentContextSafely();
7024     CHECK_NULL_RETURN(pipeline, Color());
7025     auto theme = pipeline->GetTheme<RichEditorTheme>();
7026     CHECK_NULL_RETURN(theme, Color());
7027     return theme->GetUrlDefaultColor();
7028 }
7029 
7030 void RichEditorPattern::TriggerAvoidOnCaretChange()
7031 {
7032     CHECK_NULL_VOID(HasFocus());
7033     auto host = GetHost();
7034     CHECK_NULL_VOID(host);
7035     auto pipeline = host->GetContext();
7036     CHECK_NULL_VOID(pipeline);
7037     auto textFieldManager = DynamicCast<TextFieldManagerNG>(pipeline->GetTextFieldManager());
7038     CHECK_NULL_VOID(textFieldManager);
7039     CHECK_NULL_VOID(pipeline->UsingCaretAvoidMode());
7040     auto safeAreaManager = pipeline->GetSafeAreaManager();
7041     if (!safeAreaManager || NearZero(safeAreaManager->GetKeyboardInset().Length(), 0)) {
7042         return;
7043     }
7044     textFieldManager->SetHeight(GetCaretRect().Height());
7045     auto taskExecutor = pipeline->GetTaskExecutor();
7046     CHECK_NULL_VOID(taskExecutor);
7047     taskExecutor->PostTask([manager = WeakPtr<TextFieldManagerNG>(textFieldManager)] {
7048         auto textFieldManager = manager.Upgrade();
7049         CHECK_NULL_VOID(textFieldManager);
7050         textFieldManager->TriggerAvoidOnCaretChange();
7051     }, TaskExecutor::TaskType::UI, "ArkUIRichEditorNotifyCaretChange");}
7052 
7053 void RichEditorPattern::OnWindowSizeChanged(int32_t width, int32_t height, WindowSizeChangeReason type)
7054 {
7055     CHECK_NULL_VOID(type == WindowSizeChangeReason::ROTATION);
7056     if (SelectOverlayIsOn()) {
7057         CalculateHandleOffsetAndShowOverlay();
7058         selectOverlay_->ProcessOverlayOnAreaChanged({ .menuIsShow = false });
7059     }
7060     auto host = GetHost();
7061     CHECK_NULL_VOID(host);
7062     auto context = host->GetContextRefPtr();
7063     CHECK_NULL_VOID(context);
7064     auto taskExecutor = context->GetTaskExecutor();
7065     CHECK_NULL_VOID(taskExecutor);
7066     auto textFieldManager = DynamicCast<TextFieldManagerNG>(context->GetTextFieldManager());
7067     CHECK_NULL_VOID(textFieldManager);
7068     textFieldManager->ResetOptionalClickPosition();
7069     taskExecutor->PostTask(
7070         [weak = WeakClaim(this), manager = WeakPtr<TextFieldManagerNG>(textFieldManager)] {
7071             auto pattern = weak.Upgrade();
7072             CHECK_NULL_VOID(pattern);
7073             pattern->parentGlobalOffset_ = pattern->GetPaintRectGlobalOffset();
7074             pattern->UpdateModifierCaretOffsetAndHeight();
7075             pattern->UpdateTextFieldManager(Offset(pattern->parentGlobalOffset_.GetX(),
7076                 pattern->parentGlobalOffset_.GetY()), pattern->frameRect_.Height());
7077             pattern->UpdateCaretInfoToController();
7078         },
7079         TaskExecutor::TaskType::UI, "ArkUIRichEditorOnWindowSizeChangedRotation");
7080 }
7081 
7082 void RichEditorPattern::CopySelectionMenuParams(SelectOverlayInfo& selectInfo, TextResponseType responseType)
7083 {
7084     auto selectType = selectedType_.value_or(TextSpanType::NONE);
7085     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "textSpanType=%{public}d, responseType=%{public}d", selectType, responseType);
7086     std::shared_ptr<SelectionMenuParams> menuParams = GetMenuParams(selectType, responseType);
7087     CHECK_NULL_VOID(menuParams);
7088 
7089     // long pressing on the image needs to set the position of the pop-up menu following the long pressing position
7090     if (selectType == TextSpanType::IMAGE && !selectInfo.isUsingMouse) {
7091         selectInfo.menuInfo.menuOffset = OffsetF(selectionMenuOffset_.GetX(), selectionMenuOffset_.GetY());
7092     }
7093 
7094     CopyBindSelectionMenuParams(selectInfo, menuParams);
7095 }
7096 
7097 void RichEditorPattern::ShowSelectOverlay(const RectF& firstHandle, const RectF& secondHandle, bool isCopyAll,
7098     TextResponseType responseType, bool handleReverse)
7099 {
7100     CHECK_NULL_VOID(!IsPreviewTextInputting());
7101     textResponseType_ = responseType;
7102     selectOverlay_->ProcessOverlay({.animation = true});
7103 }
7104 
7105 void RichEditorPattern::OnCopyOperationExt(RefPtr<PasteDataMix>& pasteData)
7106 {
7107     auto subSpanString =
7108         ToStyledString(textSelector_.GetTextStart(), textSelector_.GetTextEnd());
7109     std::vector<uint8_t> tlvData;
7110     subSpanString->EncodeTlv(tlvData);
7111     auto text = subSpanString->GetString();
7112     clipboard_->AddSpanStringRecord(pasteData, tlvData);
7113 }
7114 
7115 void RichEditorPattern::HandleOnCopyStyledString()
7116 {
7117     RefPtr<PasteDataMix> pasteData = clipboard_->CreatePasteDataMix();
7118     auto subSpanString = styledString_->GetSubSpanString(textSelector_.GetTextStart(),
7119         textSelector_.GetTextEnd() - textSelector_.GetTextStart());
7120     std::vector<uint8_t> tlvData;
7121     subSpanString->EncodeTlv(tlvData);
7122     clipboard_->AddSpanStringRecord(pasteData, tlvData);
7123     clipboard_->AddTextRecord(pasteData, subSpanString->GetString());
7124     clipboard_->SetData(pasteData, copyOption_);
7125 }
7126 
7127 void RichEditorPattern::OnCopyOperation(bool isUsingExternalKeyboard)
7128 {
7129     if (isSpanStringMode_) {
7130         HandleOnCopyStyledString();
7131         return;
7132     }
7133     RefPtr<PasteDataMix> pasteData = clipboard_->CreatePasteDataMix();
7134     auto selectStart = textSelector_.GetTextStart();
7135     auto selectEnd = textSelector_.GetTextEnd();
7136     auto textSelectInfo = GetSpansInfo(selectStart, selectEnd, GetSpansMethod::ONSELECT);
7137     auto copyResultObjects = textSelectInfo.GetSelection().resultObjects;
7138     caretUpdateType_ = CaretUpdateType::NONE;
7139     if (copyResultObjects.empty()) {
7140         return;
7141     }
7142     for (auto resultObj = copyResultObjects.rbegin(); resultObj != copyResultObjects.rend(); ++resultObj) {
7143         ProcessResultObject(pasteData, *resultObj);
7144     }
7145     clipboard_->SetData(pasteData, copyOption_);
7146 }
7147 
7148 void RichEditorPattern::ProcessResultObject(RefPtr<PasteDataMix> pasteData, const ResultObject& result)
7149 {
7150     CHECK_NULL_VOID(pasteData);
7151     auto multiTypeRecordImpl = AceType::MakeRefPtr<MultiTypeRecordImpl>();
7152     if (result.type == SelectSpanType::TYPESPAN) {
7153         auto data = GetSelectedSpanText(StringUtils::ToWstring(result.valueString),
7154             result.offsetInSpan[RichEditorSpanRange::RANGESTART], result.offsetInSpan[RichEditorSpanRange::RANGEEND]);
7155 #ifdef PREVIEW
7156         clipboard_->SetData(data, CopyOptions::Distributed);
7157 #else
7158         multiTypeRecordImpl->SetPlainText(data);
7159         EncodeTlvDataByResultObject(result, multiTypeRecordImpl->GetSpanStringBuffer());
7160         clipboard_->AddMultiTypeRecord(pasteData, multiTypeRecordImpl);
7161 #endif
7162         return;
7163     }
7164     if (result.type == SelectSpanType::TYPEIMAGE) {
7165 #ifdef PREVIEW
7166         if (result.valuePixelMap) {
7167             clipboard_->AddPixelMapRecord(pasteData, result.valuePixelMap);
7168         } else {
7169             clipboard_->AddImageRecord(pasteData, result.valueString);
7170         }
7171 #else
7172         if (result.valuePixelMap) {
7173             multiTypeRecordImpl->SetPixelMap(result.valuePixelMap);
7174         } else {
7175             multiTypeRecordImpl->SetUri(result.valueString);
7176         }
7177         EncodeTlvDataByResultObject(result, multiTypeRecordImpl->GetSpanStringBuffer());
7178         clipboard_->AddMultiTypeRecord(pasteData, multiTypeRecordImpl);
7179 #endif
7180     }
7181 }
7182 
7183 void RichEditorPattern::EncodeTlvDataByResultObject(const ResultObject& result, std::vector<uint8_t>& tlvData)
7184 {
7185     auto selectStart = result.spanPosition.spanRange[RichEditorSpanRange::RANGESTART] + result.offsetInSpan[RichEditorSpanRange::RANGESTART];
7186     auto selectEnd = result.spanPosition.spanRange[RichEditorSpanRange::RANGESTART] + result.offsetInSpan[RichEditorSpanRange::RANGEEND];
7187     auto spanString = ToStyledString(selectStart, selectEnd);
7188     spanString->EncodeTlv(tlvData);
7189 }
7190 
7191 void RichEditorPattern::HandleOnCopy(bool isUsingExternalKeyboard)
7192 {
7193     CHECK_NULL_VOID(clipboard_);
7194     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "isUsingExternalKeyboard=%{public}d, copyOption=%{public}d",
7195         isUsingExternalKeyboard, copyOption_);
7196     if (copyOption_ == CopyOptions::None) {
7197         return;
7198     }
7199     auto host = GetHost();
7200     CHECK_NULL_VOID(host);
7201     auto eventHub = host->GetEventHub<RichEditorEventHub>();
7202     CHECK_NULL_VOID(eventHub);
7203     TextCommonEvent event;
7204     eventHub->FireOnCopy(event);
7205     if (event.IsPreventDefault()) {
7206         CloseSelectOverlay();
7207         ResetSelection();
7208         StartTwinkling();
7209         return;
7210     }
7211     OnCopyOperation(isUsingExternalKeyboard);
7212     if (selectOverlay_->IsUsingMouse() || isUsingExternalKeyboard) {
7213         CloseSelectOverlay();
7214     } else {
7215         selectOverlay_->HideMenu();
7216     }
7217 }
7218 
7219 void RichEditorPattern::ResetAfterPaste()
7220 {
7221     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "ResetAfterPaste");
7222     auto pasteStr = GetPasteStr();
7223     SetCaretSpanIndex(-1);
7224     StartTwinkling();
7225     RequestKeyboardToEdit();
7226     CloseSelectOverlay();
7227     InsertValueByPaste(pasteStr);
7228     ClearPasteStr();
7229 }
7230 
7231 void RichEditorPattern::InsertValueByPaste(const std::string& pasteStr)
7232 {
7233     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "InsertValueByPaste");
7234     if (isSpanStringMode_) {
7235         InsertValueInStyledString(pasteStr);
7236         return;
7237     }
7238     InsertValueByOperationType(pasteStr, OperationType::DEFAULT);
7239 }
7240 
7241 void RichEditorPattern::HandleOnPaste()
7242 {
7243     auto host = GetHost();
7244     CHECK_NULL_VOID(host);
7245     auto eventHub = host->GetEventHub<RichEditorEventHub>();
7246     CHECK_NULL_VOID(eventHub);
7247     TextCommonEvent event;
7248     eventHub->FireOnPaste(event);
7249     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "HandleOnPaste, preventDefault=%{public}d", event.IsPreventDefault());
7250     if (event.IsPreventDefault()) {
7251         CloseSelectOverlay();
7252         ResetSelection();
7253         StartTwinkling();
7254         RequestKeyboardToEdit();
7255         return;
7256     }
7257     auto isSpanStringMode = isSpanStringMode_;
7258     auto pasteCallback = [weak = WeakClaim(this), isSpanStringMode](std::vector<std::vector<uint8_t>>& arrs,
7259                              const std::string& text, bool& isMulitiTypeRecord) {
7260         TAG_LOGI(AceLogTag::ACE_RICH_TEXT,
7261             "pasteCallback callback, isMulitiTypeRecord : [%{public}d], isSpanStringMode : [%{public}d]",
7262             isMulitiTypeRecord, isSpanStringMode);
7263         auto richEditor = weak.Upgrade();
7264         CHECK_NULL_VOID(richEditor);
7265         std::list<RefPtr<SpanString>> spanStrings;
7266         for (auto arr : arrs) {
7267             spanStrings.push_back(SpanString::DecodeTlv(arr));
7268         }
7269         if (!spanStrings.empty() && !isMulitiTypeRecord) {
7270             for (auto spanString : spanStrings) {
7271                 richEditor->AddSpanByPasteData(spanString);
7272                 richEditor->RequestKeyboardToEdit();
7273             }
7274             return;
7275         }
7276         if (text.empty()) {
7277             richEditor->ResetSelection();
7278             richEditor->StartTwinkling();
7279             richEditor->CloseSelectOverlay();
7280             richEditor->RequestKeyboardToEdit();
7281             return;
7282         }
7283         richEditor->AddPasteStr(text);
7284         richEditor->ResetAfterPaste();
7285     };
7286     CHECK_NULL_VOID(clipboard_);
7287     clipboard_->GetSpanStringData(pasteCallback);
7288 }
7289 
7290 void RichEditorPattern::SetCaretSpanIndex(int32_t index)
7291 {
7292     caretSpanIndex_ = index;
7293 }
7294 
7295 void RichEditorPattern::HandleOnCut()
7296 {
7297     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "copyOption=%{public}d, textSelector_.IsValid()=%{public}d",
7298         copyOption_, textSelector_.IsValid());
7299     if (copyOption_ == CopyOptions::None) {
7300         return;
7301     }
7302     if (!textSelector_.IsValid()) {
7303         return;
7304     }
7305     auto host = GetHost();
7306     CHECK_NULL_VOID(host);
7307     auto eventHub = host->GetEventHub<RichEditorEventHub>();
7308     CHECK_NULL_VOID(eventHub);
7309     TextCommonEvent event;
7310     eventHub->FireOnCut(event);
7311     if (event.IsPreventDefault()) {
7312         CloseSelectOverlay();
7313         ResetSelection();
7314         StartTwinkling();
7315         RequestKeyboardToEdit();
7316         return;
7317     }
7318 
7319     caretUpdateType_ = CaretUpdateType::NONE;
7320     OnCopyOperation();
7321     DeleteBackward();
7322 }
7323 
7324 std::function<void(Offset)> RichEditorPattern::GetThumbnailCallback()
7325 {
7326     return [wk = WeakClaim(this)](const Offset& point) {
7327         auto pattern = wk.Upgrade();
7328         CHECK_NULL_VOID(pattern);
7329         if (!pattern->BetweenSelectedPosition(point)) {
7330             return;
7331         }
7332         auto gesture = pattern->GetGestureEventHub();
7333         CHECK_NULL_VOID(gesture);
7334         auto isContentDraggable = pattern->JudgeContentDraggable();
7335         if (!isContentDraggable) {
7336             gesture->SetIsTextDraggable(false);
7337             return;
7338         }
7339         auto host = pattern->GetHost();
7340         auto children = host->GetChildren();
7341         std::list<RefPtr<FrameNode>> imageChildren;
7342         for (const auto& child : children) {
7343             auto node = DynamicCast<FrameNode>(child);
7344             if (!node) {
7345                 continue;
7346             }
7347             auto tag = node->GetTag();
7348             if (tag == V2::IMAGE_ETS_TAG || tag == V2::PLACEHOLDER_SPAN_ETS_TAG) {
7349                 imageChildren.emplace_back(node);
7350             }
7351         }
7352         RichEditorDragInfo info;
7353         info.handleColor = pattern->GetCaretColor();
7354         info.selectedBackgroundColor = pattern->GetSelectedBackgroundColor();
7355         pattern->CalculateHandleOffsetAndShowOverlay();
7356         auto firstHandleInfo = pattern->GetFirstHandleInfo();
7357         if (firstHandleInfo.has_value() && firstHandleInfo.value().isShow) {
7358             info.firstHandle = pattern->textSelector_.firstHandle;
7359         }
7360         auto secondHandleInfo = pattern->GetSecondHandleInfo();
7361         if (secondHandleInfo.has_value() && secondHandleInfo.value().isShow) {
7362             info.secondHandle = pattern->textSelector_.secondHandle;
7363         }
7364         pattern->dragNode_ = RichEditorDragPattern::CreateDragNode(host, imageChildren, info);
7365         auto textDragPattern = pattern->dragNode_->GetPattern<TextDragPattern>();
7366         auto option = host->GetDragPreviewOption();
7367         option.options.shadowPath = textDragPattern->GetBackgroundPath()->ConvertToSVGString();
7368         option.options.shadow = Shadow(RICH_DEFAULT_ELEVATION, {0.0, 0.0}, Color(RICH_DEFAULT_SHADOW_COLOR),
7369             ShadowStyle::OuterFloatingSM);
7370         host->SetDragPreviewOptions(option);
7371         FrameNode::ProcessOffscreenNode(pattern->dragNode_);
7372         auto gestureHub = host->GetOrCreateGestureEventHub();
7373         CHECK_NULL_VOID(gestureHub);
7374         gestureHub->SetPixelMap(nullptr);
7375     };
7376 }
7377 
7378 void RichEditorPattern::CreateHandles()
7379 {
7380     if (IsDragging()) {
7381         TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "do not show handles when dragging");
7382         return;
7383     }
7384     auto host = GetHost();
7385     CHECK_NULL_VOID(host);
7386     CalculateHandleOffsetAndShowOverlay();
7387     selectOverlay_->ProcessOverlay({ .menuIsShow = selectOverlay_->IsCurrentMenuVisibile(), .animation = true });
7388 }
7389 
7390 void RichEditorPattern::ShowHandles(const bool isNeedShowHandles)
7391 {
7392     if (!isNeedShowHandles) {
7393         auto info = GetSpansInfo(textSelector_.GetTextStart(), textSelector_.GetTextEnd(), GetSpansMethod::ONSELECT);
7394         auto selResult = info.GetSelection().resultObjects;
7395         if (isMousePressed_ && selResult.size() == 1 && selResult.front().type == SelectSpanType::TYPEIMAGE) {
7396             textSelector_.Update(-1, -1);
7397             auto host = GetHost();
7398             CHECK_NULL_VOID(host);
7399             host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
7400             return;
7401         }
7402     }
7403     ShowHandles();
7404 }
7405 
7406 void RichEditorPattern::ShowHandles()
7407 {
7408     auto host = GetHost();
7409     CHECK_NULL_VOID(host);
7410     if (!selectOverlay_->IsBothHandlesShow() && !selectOverlay_->SelectOverlayIsCreating()) {
7411         showSelect_ = true;
7412         host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
7413         CalculateHandleOffsetAndShowOverlay();
7414         selectOverlay_->ProcessOverlay({.animation = false});
7415     }
7416 }
7417 
7418 void RichEditorPattern::OnAreaChangedInner()
7419 {
7420     auto host = GetHost();
7421     CHECK_NULL_VOID(host);
7422     auto context = host->GetContext();
7423     CHECK_NULL_VOID(context);
7424     auto parentGlobalOffset = GetPaintRectGlobalOffset(); // offset on screen(with transformation)
7425     if (parentGlobalOffset != parentGlobalOffset_) {
7426         parentGlobalOffset_ = parentGlobalOffset;
7427         UpdateTextFieldManager(Offset(parentGlobalOffset_.GetX(), parentGlobalOffset_.GetY()), frameRect_.Height());
7428         selectOverlay_->UpdateSelectOverlayOnAreaChanged();
7429     }
7430 }
7431 
7432 void RichEditorPattern::CloseSelectionMenu()
7433 {
7434     // used by sdk
7435     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "CloseSelectionMenu");
7436     CloseSelectOverlay();
7437 }
7438 
7439 void RichEditorPattern::CloseSelectOverlay()
7440 {
7441     // used by inner
7442     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "CloseSelectOverlay");
7443     selectOverlay_->CloseOverlay(true, CloseReason::CLOSE_REASON_NORMAL);
7444 }
7445 
7446 void RichEditorPattern::CloseHandleAndSelect()
7447 {
7448     selectOverlay_->CloseOverlay(false, CloseReason::CLOSE_REASON_DRAG_FLOATING);
7449     showSelect_ = false;
7450 }
7451 
7452 void RichEditorPattern::CalculateHandleOffsetAndShowOverlay(bool isUsingMouse)
7453 {
7454     auto globalOffset = GetGlobalOffset();
7455     if (!selectOverlay_->GetIsHandleMoving()) {
7456         textSelector_.ReverseTextSelector();
7457     }
7458     int32_t baseOffset = std::min(textSelector_.baseOffset, GetTextContentLength());
7459     int32_t destinationOffset = std::min(textSelector_.destinationOffset, GetTextContentLength());
7460     SizeF firstHandlePaintSize;
7461     SizeF secondHandlePaintSize;
7462     OffsetF firstHandleOffset;
7463     OffsetF secondHandleOffset;
7464     auto isSingleHandle = IsSingleHandle();
7465     selectOverlay_->SetIsSingleHandle(isSingleHandle);
7466     if (isSingleHandle) {
7467         auto [caretOffset, caretHeight] = CalculateCaretOffsetAndHeight();
7468         // only show the second handle.
7469         secondHandlePaintSize = { SelectHandleInfo::GetDefaultLineWidth().ConvertToPx(), caretHeight };
7470         secondHandleOffset = caretOffset + globalOffset;
7471     } else {
7472         float startSelectHeight = 0.0f;
7473         float endSelectHeight = 0.0f;
7474         auto startOffset = CalcCursorOffsetByPosition(baseOffset, startSelectHeight, true, false);
7475         auto endOffset = CalcCursorOffsetByPosition(destinationOffset, endSelectHeight, false, false);
7476         firstHandlePaintSize = { SelectHandleInfo::GetDefaultLineWidth().ConvertToPx(), startSelectHeight };
7477         secondHandlePaintSize = { SelectHandleInfo::GetDefaultLineWidth().ConvertToPx(), endSelectHeight };
7478         firstHandleOffset = startOffset + globalOffset;
7479         secondHandleOffset = endOffset + globalOffset;
7480         firstHandleOffset.SetX(firstHandleOffset.GetX() - firstHandlePaintSize.Width() / 2.0f);
7481         secondHandleOffset.SetX(secondHandleOffset.GetX() - secondHandlePaintSize.Width() / 2.0f);
7482     }
7483     textSelector_.selectionBaseOffset = firstHandleOffset;
7484     textSelector_.selectionDestinationOffset = secondHandleOffset;
7485     textSelector_.firstHandle = RectF{ firstHandleOffset, firstHandlePaintSize };
7486     textSelector_.secondHandle = RectF{ secondHandleOffset, secondHandlePaintSize };
7487 }
7488 
7489 void RichEditorPattern::CalculateDefaultHandleHeight(float& height)
7490 {
7491 #ifdef ENABLE_ROSEN_BACKEND
7492     MeasureContext content;
7493     content.textContent = "a";
7494     content.fontSize = TEXT_DEFAULT_FONT_SIZE;
7495     auto fontweight = StringUtils::FontWeightToString(FontWeight::NORMAL);
7496     content.fontWeight = fontweight;
7497     height = std::max(static_cast<float>(RosenRenderCustomPaint::MeasureTextSizeInner(content).Height()), 0.0f);
7498 #endif
7499 }
7500 
7501 OffsetF RichEditorPattern::GetGlobalOffset() const
7502 {
7503     auto host = GetHost();
7504     CHECK_NULL_RETURN(host, OffsetF());
7505     auto pipeline = host->GetContext();
7506     CHECK_NULL_RETURN(pipeline, OffsetF());
7507     auto rootOffset = pipeline->GetRootRect().GetOffset();
7508     auto richEditorPaintOffset = host->GetPaintRectOffsetNG(false, true);
7509     if (selectOverlay_->HasRenderTransform()) {
7510         richEditorPaintOffset = selectOverlay_->GetPaintOffsetWithoutTransform();
7511     }
7512     return richEditorPaintOffset - rootOffset;
7513 }
7514 
7515 bool RichEditorPattern::IsSingleHandle()
7516 {
7517     return GetTextContentLength() == 0 || !IsSelected();
7518 }
7519 
7520 bool RichEditorPattern::IsHandlesShow()
7521 {
7522     return selectOverlay_->IsBothHandlesShow();
7523 }
7524 
7525 void RichEditorPattern::ResetSelection()
7526 {
7527     bool selectNothing = textSelector_.SelectNothing();
7528     textSelector_.Update(-1, -1);
7529     if (!selectNothing) {
7530         TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "ResetSelection");
7531         auto host = GetHost();
7532         CHECK_NULL_VOID(host);
7533         auto eventHub = host->GetEventHub<RichEditorEventHub>();
7534         CHECK_NULL_VOID(eventHub);
7535         auto textSelectInfo = GetSpansInfo(-1, -1, GetSpansMethod::ONSELECT);
7536         eventHub->FireOnSelect(&textSelectInfo);
7537         UpdateSelectionType(textSelectInfo);
7538         host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
7539     }
7540 }
7541 
7542 bool RichEditorPattern::BetweenSelection(const Offset& globalOffset)
7543 {
7544     auto host = GetHost();
7545     CHECK_NULL_RETURN(host, false);
7546     auto offset = host->GetPaintRectOffsetNG(false, true);
7547     auto localOffset = globalOffset - Offset(offset.GetX(), offset.GetY());
7548     if (selectOverlay_->HasRenderTransform()) {
7549         localOffset = ConvertGlobalToLocalOffset(globalOffset);
7550     }
7551     auto eventHub = host->GetEventHub<EventHub>();
7552     if (GreatNotEqual(textSelector_.GetTextEnd(), textSelector_.GetTextStart())) {
7553         // Determine if the pan location is in the selected area
7554         auto selectedRects = paragraphs_.GetRects(textSelector_.GetTextStart(), textSelector_.GetTextEnd());
7555         auto panOffset = OffsetF(localOffset.GetX(), localOffset.GetY()) - GetTextRect().GetOffset() +
7556                          OffsetF(0.0, std::min(baselineOffset_, 0.0f));
7557         for (const auto& selectedRect : selectedRects) {
7558             if (selectedRect.IsInRegion(PointF(panOffset.GetX(), panOffset.GetY()))) {
7559                 return true;
7560             }
7561         }
7562     }
7563     return false;
7564 }
7565 
7566 bool RichEditorPattern::BetweenSelectedPosition(const Offset& globalOffset)
7567 {
7568     return copyOption_ != CopyOptions::None && BetweenSelection(globalOffset);
7569 }
7570 
7571 void RichEditorPattern::HandleSurfaceChanged(int32_t newWidth, int32_t newHeight, int32_t prevWidth, int32_t prevHeight)
7572 {
7573     if (newWidth != prevWidth || newHeight != prevHeight) {
7574         TextPattern::HandleSurfaceChanged(newWidth, newHeight, prevWidth, prevHeight);
7575         UpdateOriginIsMenuShow(false);
7576     }
7577     UpdateCaretInfoToController();
7578     previewLongPress_ = false;
7579     editingLongPress_ = false;
7580     if (magnifierController_) {
7581         magnifierController_->RemoveMagnifierFrameNode();
7582     }
7583 }
7584 
7585 void RichEditorPattern::HandleSurfacePositionChanged(int32_t posX, int32_t posY)
7586 {
7587     UpdateCaretInfoToController();
7588 }
7589 
7590 void RichEditorPattern::DumpInfo()
7591 {
7592     auto& dumpLog = DumpLog::GetInstance();
7593     if (customKeyboardBuilder_) {
7594         dumpLog.AddDesc(std::string("CustomKeyboard, Attached: ").append(std::to_string(isCustomKeyboardAttached_)));
7595     }
7596     auto host = GetHost();
7597     CHECK_NULL_VOID(host);
7598     auto context = host->GetContext();
7599     CHECK_NULL_VOID(context);
7600     auto richEditorTheme = context->GetTheme<RichEditorTheme>();
7601     CHECK_NULL_VOID(richEditorTheme);
7602     dumpLog.AddDesc(std::string("caret offset: ").append(GetCaretRect().GetOffset().ToString()));
7603     dumpLog.AddDesc(std::string("caret height: ")
7604             .append(std::to_string(NearZero(GetCaretRect().Height())
7605                                        ? richEditorTheme->GetDefaultCaretHeight().ConvertToPx()
7606                                        : GetCaretRect().Height())));
7607     dumpLog.AddDesc(std::string("text rect: ").append(richTextRect_.ToString()));
7608     dumpLog.AddDesc(std::string("content rect: ").append(contentRect_.ToString()));
7609     auto richEditorPaintOffset = host->GetPaintRectOffsetNG(false, true);
7610     bool hasRenderTransform = selectOverlay_->HasRenderTransform();
7611     if (hasRenderTransform) {
7612         richEditorPaintOffset = selectOverlay_->GetPaintOffsetWithoutTransform();
7613     }
7614     dumpLog.AddDesc(std::string("hasRenderTransform: ").append(std::to_string(hasRenderTransform)));
7615     dumpLog.AddDesc(std::string("richEditorPaintOffset: ").append(richEditorPaintOffset.ToString()));
7616     auto selectOverlayInfo = selectOverlay_->GetSelectOverlayInfo();
7617     CHECK_NULL_VOID(selectOverlayInfo);
7618     dumpLog.AddDesc(std::string("selectOverlay info: ").append(selectOverlayInfo->ToString()));
7619     dumpLog.AddDesc(std::string("IsAIWrite: ").append(std::to_string(IsShowAIWrite())));
7620     dumpLog.AddDesc(std::string("keyboardAppearance: ")
7621             .append(std::to_string(static_cast<int32_t>(keyboardAppearance_))));
7622 }
7623 
7624 bool RichEditorPattern::HasFocus() const
7625 {
7626     auto focusHub = GetFocusHub();
7627     CHECK_NULL_RETURN(focusHub, false);
7628     return focusHub->IsCurrentFocus();
7629 }
7630 
7631 void RichEditorPattern::UpdateTextFieldManager(const Offset& offset, float height)
7632 {
7633     if (!HasFocus()) {
7634         return;
7635     }
7636     auto context = GetHost()->GetContext();
7637     CHECK_NULL_VOID(context);
7638     auto richEditorTheme = context->GetTheme<RichEditorTheme>();
7639     CHECK_NULL_VOID(richEditorTheme);
7640     auto textFieldManager = DynamicCast<TextFieldManagerNG>(context->GetTextFieldManager());
7641     CHECK_NULL_VOID(textFieldManager);
7642     auto safeAreaManager = context->GetSafeAreaManager();
7643     CHECK_NULL_VOID(safeAreaManager);
7644     auto [caretOffset, caretHeight] = CalculateCaretOffsetAndHeight();
7645     textFieldManager->SetClickPosition({ offset.GetX() + caretOffset.GetX(), offset.GetY() + caretOffset.GetY() });
7646     textFieldManager->SetHeight(NearZero(caretHeight)
7647                                     ? richEditorTheme->GetDefaultCaretHeight().ConvertToPx()
7648                                     : caretHeight);
7649     textFieldManager->SetClickPositionOffset(safeAreaManager->GetKeyboardOffset());
7650     textFieldManager->SetOnFocusTextField(WeakClaim(this));
7651     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_FOURTEEN)) {
7652         textFieldManager->SetUsingCustomKeyboardAvoid(keyboardAvoidance_);
7653     }
7654     if (!isTextChange_) {
7655         return;
7656     }
7657     auto taskExecutor = context->GetTaskExecutor();
7658     CHECK_NULL_VOID(taskExecutor);
7659     taskExecutor->PostTask(
7660         [weak = WeakClaim(this)] {
7661             auto pattern = weak.Upgrade();
7662             CHECK_NULL_VOID(pattern);
7663             pattern->ScrollToSafeArea();
7664         },
7665         TaskExecutor::TaskType::UI, "ArkUIRichEditorScrollToSafeArea");
7666 }
7667 
7668 bool RichEditorPattern::IsDisabled() const
7669 {
7670     auto eventHub = GetHost()->GetEventHub<RichEditorEventHub>();
7671     CHECK_NULL_RETURN(eventHub, true);
7672     return !eventHub->IsEnabled();
7673 }
7674 
7675 void RichEditorPattern::MouseDoubleClickParagraphEnd(int32_t& index)
7676 {
7677     bool isMouseDoubleClick = caretUpdateType_ == CaretUpdateType::DOUBLE_CLICK && sourceType_ == SourceType::MOUSE;
7678     CHECK_NULL_VOID(isMouseDoubleClick);
7679     auto paragraphEndPos = GetParagraphEndPosition(index);
7680     auto paragraphBeginPos = GetParagraphBeginPosition(index);
7681     bool isBeginEqualEnd = paragraphBeginPos == paragraphEndPos;
7682     CHECK_NULL_VOID(!isBeginEqualEnd);
7683     if (index == paragraphEndPos) {
7684         index -= 1;
7685     }
7686 }
7687 
7688 void RichEditorPattern::AdjustSelectionExcludeSymbol(int32_t& start, int32_t& end)
7689 {
7690     AdjustSelectorForSymbol(start, HandleType::FIRST, SelectorAdjustPolicy::EXCLUDE);
7691     AdjustSelectorForSymbol(end, HandleType::SECOND, SelectorAdjustPolicy::EXCLUDE);
7692 }
7693 
7694 void RichEditorPattern::InitSelection(const Offset& pos)
7695 {
7696     auto [currentPosition, selectType] = JudgeSelectType(pos);
7697     switch (selectType) {
7698         case SelectType::SELECT_NOTHING:
7699             TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "select nothing currentPos=%{public}d", currentPosition);
7700             textSelector_.Update(currentPosition, currentPosition);
7701             return;
7702         case SelectType::SELECT_BACKWARD:
7703             currentPosition = std::max(0, currentPosition - 1);
7704             break;
7705         case SelectType::SELECT_FORWARD:
7706             break;
7707         default:
7708             TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "exception select type");
7709     }
7710     int32_t nextPosition = std::min(currentPosition + 1, GetTextContentLength());
7711     AdjustSelectionExcludeSymbol(currentPosition, nextPosition);
7712     if (!IsCustomSpanInCaretPos(currentPosition, true)) {
7713         AdjustWordSelection(currentPosition, nextPosition);
7714     }
7715     AdjustSelector(currentPosition, nextPosition);
7716     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "init select [%{public}d--%{public}d]", currentPosition, nextPosition);
7717     textSelector_.Update(currentPosition, nextPosition);
7718     if (IsSelectEmpty(currentPosition, nextPosition)) {
7719         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "select rect is empty, select nothing");
7720         textSelector_.Update(currentPosition, currentPosition);
7721     }
7722 }
7723 
7724 std::pair<int32_t, SelectType> RichEditorPattern::JudgeSelectType(const Offset& pos)
7725 {
7726     auto positionWithAffinity = paragraphs_.GetGlyphPositionAtCoordinate(pos);
7727     auto currentPosition = (GetTextContentLength() == 0) ? 0 : static_cast<int32_t>(positionWithAffinity.position_);
7728     auto selectType = SelectType::SELECT_NOTHING;
7729     CHECK_NULL_RETURN(GetTextContentLength() != 0, std::make_pair(currentPosition, selectType));
7730     bool isNeedSkipLineSeparator = !editingLongPress_ && IsSelectEmpty(currentPosition, currentPosition + 1);
7731     if (isNeedSkipLineSeparator && AdjustIndexSkipLineSeparator(currentPosition)) {
7732         return std::make_pair(currentPosition, SelectType::SELECT_BACKWARD);
7733     }
7734     auto height = paragraphs_.GetHeight();
7735     if (GreatNotEqual(pos.GetY(), height)) {
7736         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "touchPosY[%{public}f] > paragraphsHeight[%{public}f]", pos.GetY(), height);
7737         IF_TRUE(!editingLongPress_, selectType = SelectType::SELECT_BACKWARD);
7738         return std::make_pair(GetTextContentLength(), selectType);
7739     }
7740     TextAffinity currentAffinity = positionWithAffinity.affinity_;
7741     bool isTouchLineEnd = currentAffinity == TextAffinity::UPSTREAM && !IsTouchBeforeCaret(currentPosition, pos);
7742     if (editingLongPress_ && isTouchLineEnd) {
7743         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "touchLineEnd select nothing currentAffinity=%{public}d", currentAffinity);
7744         return std::make_pair(currentPosition, selectType);
7745     }
7746     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "currentPosition=%{public}d, currentAffinity=%{public}d",
7747         currentPosition, currentAffinity);
7748     selectType = (currentAffinity == TextAffinity::UPSTREAM) ? SelectType::SELECT_BACKWARD : SelectType::SELECT_FORWARD;
7749     return std::make_pair(currentPosition, selectType);
7750 }
7751 
7752 bool RichEditorPattern::IsSelectEmpty(int32_t start, int32_t end)
7753 {
7754     auto selectedRects = paragraphs_.GetRects(start, end);
7755     return selectedRects.empty() || (selectedRects.size() == 1 && NearZero((selectedRects[0].Width())));
7756 }
7757 
7758 bool RichEditorPattern::AdjustIndexSkipLineSeparator(int32_t& currentPosition)
7759 {
7760     std::wstringstream wss;
7761     for (auto iter = spans_.cbegin(); iter != spans_.cend(); iter++) {
7762         auto span = *iter;
7763         auto content = StringUtils::ToWstring(span->content);
7764         wss << content;
7765         CHECK_NULL_BREAK(currentPosition > span->position);
7766     }
7767     auto contentText = wss.str();
7768     auto contentLength = static_cast<int32_t>(contentText.length());
7769     if (currentPosition > contentLength) {
7770         TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "currentPosition=%{public}d but contentLength=%{public}d",
7771             currentPosition, contentLength);
7772         return false;
7773     }
7774     auto index = currentPosition - 1;
7775     while (index > 0) {
7776         CHECK_NULL_BREAK(contentText[index] == L'\n');
7777         index--;
7778     }
7779     if (index != currentPosition - 1) {
7780         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "skip lineSeparator %{public}d->%{public}d", currentPosition, index + 1);
7781         currentPosition = index + 1;
7782         return true;
7783     }
7784     return false;
7785 }
7786 
7787 bool RichEditorPattern::AdjustIndexSkipSpace(int32_t& currentPosition, const MoveDirection direction)
7788 {
7789     bool isBackward = (direction == MoveDirection::BACKWARD);
7790     std::wstringstream wss;
7791     for (auto iter = spans_.cbegin(); iter != spans_.cend(); iter++) {
7792         auto span = *iter;
7793         auto content = StringUtils::ToWstring(span->content);
7794         wss << content;
7795     }
7796     auto contentText = wss.str();
7797     auto contentLength = static_cast<int32_t>(contentText.length());
7798     bool isPositionInvalid = (isBackward && currentPosition == 0) || (!isBackward && currentPosition == contentLength);
7799     if (isPositionInvalid) {
7800         TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "AdjustIndexSkipSpace position=%{public}d but contentLength=%{public}d",
7801             currentPosition, contentLength);
7802         return false;
7803     }
7804     int32_t index = isBackward ? (currentPosition - 1) : currentPosition;
7805     while (isBackward ? index >= 0 : index < contentLength) {
7806         CHECK_NULL_BREAK(contentText[index] == u' ' && GetSpanType(index) == SpanItemType::NORMAL);
7807         isBackward ? index-- : index++;
7808     }
7809     int32_t adjustedIndex = isBackward ? (index + 1) : index;
7810     if (adjustedIndex != currentPosition) {
7811         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "skip space %{public}d->%{public}d", currentPosition, adjustedIndex);
7812         currentPosition = adjustedIndex;
7813         return true;
7814     }
7815     return false;
7816 }
7817 
7818 void RichEditorPattern::HandleSelectOverlayWithOptions(const SelectionOptions& options)
7819 {
7820     if (options.menuPolicy == MenuPolicy::SHOW) {
7821         if (isMousePressed_ || sourceType_ == SourceType::MOUSE) {
7822             selectionMenuOffsetByMouse_ = selectionMenuOffsetClick_;
7823         }
7824         if (SelectOverlayIsOn()) {
7825             selectOverlay_->ProcessOverlay({.animation = true, .requestCode = REQUEST_RECREATE});
7826         } else {
7827             ShowSelectOverlay(textSelector_.firstHandle, textSelector_.secondHandle, IsSelectAll());
7828         }
7829     } else if (options.menuPolicy == MenuPolicy::HIDE) {
7830         if (SelectOverlayIsOn()) {
7831             CloseSelectOverlay();
7832         }
7833     }
7834 }
7835 
7836 bool RichEditorPattern::ResetOnInvalidSelection(int32_t start, int32_t end)
7837 {
7838     if (start < end) {
7839         return false;
7840     }
7841     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "SetSelection failed, the selected area is empty.");
7842     CloseSelectOverlay();
7843     ResetSelection();
7844     StartTwinkling();
7845     return true;
7846 }
7847 
7848 void RichEditorPattern::RefreshSelectOverlay(bool isMousePressed, bool selectedTypeChange)
7849 {
7850     if (isMousePressed && !selectedTypeChange) {
7851         return;
7852     }
7853     CloseSelectOverlay();
7854     auto responseType = static_cast<TextResponseType>(
7855         selectOverlayProxy_->GetSelectOverlayMangerInfo().menuInfo.responseType.value_or(0));
7856     ShowSelectOverlay(textSelector_.firstHandle, textSelector_.secondHandle, IsSelectAll(), responseType);
7857 }
7858 
7859 bool RichEditorPattern::IsShowHandle()
7860 {
7861     auto pipeline = PipelineBase::GetCurrentContext();
7862     CHECK_NULL_RETURN(pipeline, false);
7863     auto richEditorTheme = pipeline->GetTheme<RichEditorTheme>();
7864     CHECK_NULL_RETURN(richEditorTheme, false);
7865     return !richEditorTheme->IsRichEditorShowHandle();
7866 }
7867 
7868 void RichEditorPattern::UpdateSelectionInfo(int32_t start, int32_t end)
7869 {
7870     UpdateSelectionType(GetSpansInfo(start, end, GetSpansMethod::ONSELECT));
7871     auto selectOverlayInfo = selectOverlay_->GetSelectOverlayInfo();
7872     textResponseType_ = selectOverlayInfo
7873                         ? static_cast<TextResponseType>(selectOverlayInfo->menuInfo.responseType.value_or(0))
7874                         : TextResponseType::LONG_PRESS;
7875     if (IsShowHandle() && !selectOverlay_->IsUsingMouse()) {
7876         ResetIsMousePressed();
7877         sourceType_ = SourceType::TOUCH;
7878     } else {
7879         isMousePressed_ = true;
7880     }
7881 }
7882 
7883 void RichEditorPattern::SetSelection(int32_t start, int32_t end, const std::optional<SelectionOptions>& options,
7884     bool isForward)
7885 {
7886     bool hasFocus = HasFocus();
7887     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "range=[%{public}d,%{public}d], hasFocus=%{public}d, isForward=%{public}d",
7888         start, end, hasFocus, isForward);
7889     CHECK_NULL_VOID(hasFocus);
7890     if (IsPreviewTextInputting()) {
7891         TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "SetSelection failed for previewText inputting");
7892         return;
7893     }
7894     if (start == -1 && end == -1) {
7895         start = 0;
7896         end = GetTextContentLength();
7897     } else {
7898         start = std::clamp(start, 0, GetTextContentLength());
7899         end = std::clamp(end, 0, GetTextContentLength());
7900     }
7901     if (ResetOnInvalidSelection(start, end)) {
7902         return;
7903     }
7904     UpdateSelector(start, end);
7905 
7906     if (textSelector_.IsValid() && !textSelector_.StartEqualToDest()) {
7907         StopTwinkling();
7908         if (start != textSelector_.GetTextStart() || end != textSelector_.GetTextEnd()) {
7909             FireOnSelect(textSelector_.GetTextStart(), textSelector_.GetTextEnd());
7910         }
7911     }
7912     SetCaretPosition(isForward ? textSelector_.GetTextStart() : textSelector_.GetTextEnd());
7913     MoveCaretToContentRect();
7914     CalculateHandleOffsetAndShowOverlay();
7915     UpdateSelectionInfo(textSelector_.GetTextStart(), textSelector_.GetTextEnd());
7916     ProcessOverlayOnSetSelection(options);
7917     auto host = GetHost();
7918     CHECK_NULL_VOID(host);
7919     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
7920 }
7921 
7922 void RichEditorPattern::ProcessOverlayOnSetSelection(const std::optional<SelectionOptions>& options)
7923 {
7924     if (!IsShowHandle()) {
7925         CloseSelectOverlay();
7926     } else if (!options.has_value() || options.value().menuPolicy == MenuPolicy::DEFAULT) {
7927         selectOverlay_->ProcessOverlay({ .menuIsShow = selectOverlay_->IsCurrentMenuVisibile(),
7928             .animation = true, .requestCode = REQUEST_RECREATE });
7929     } else if (options.value().menuPolicy == MenuPolicy::HIDE) {
7930         if (selectOverlay_->IsUsingMouse()) {
7931             CloseSelectOverlay();
7932         } else {
7933             selectOverlay_->ProcessOverlay({ .menuIsShow = false, .animation = true });
7934         }
7935     } else if (options.value().menuPolicy == MenuPolicy::SHOW) {
7936         if (selectOverlay_->IsUsingMouse() || sourceType_ == SourceType::MOUSE) {
7937             selectionMenuOffsetByMouse_ = selectionMenuOffsetClick_;
7938         }
7939         selectOverlay_->ProcessOverlay({ .animation = true, .requestCode = REQUEST_RECREATE });
7940     }
7941 }
7942 
7943 void RichEditorPattern::BindSelectionMenu(TextResponseType type, TextSpanType richEditorType,
7944     std::function<void()>& menuBuilder, const SelectMenuParam& menuParam)
7945 {
7946     TextPattern::BindSelectionMenu(
7947         richEditorType, type, menuBuilder, menuParam);
7948 }
7949 
7950 RefPtr<NodePaintMethod> RichEditorPattern::CreateNodePaintMethod()
7951 {
7952     if (!contentMod_) {
7953         contentMod_ = MakeRefPtr<RichEditorContentModifier>(textStyle_, &paragraphs_, WeakClaim(this));
7954     }
7955     if (!overlayMod_) {
7956         auto scrollBar = GetScrollBar();
7957         if (scrollBar) {
7958             auto scrollBarModifier = AceType::MakeRefPtr<ScrollBarOverlayModifier>();
7959             scrollBarModifier->SetRect(scrollBar->GetActiveRect());
7960             scrollBarModifier->SetPositionMode(scrollBar->GetPositionMode());
7961             SetScrollBarOverlayModifier(scrollBarModifier);
7962         }
7963         SetEdgeEffect(EdgeEffect::FADE, GetAlwaysEnabled());
7964         SetEdgeEffect();
7965         overlayMod_ = AceType::MakeRefPtr<RichEditorOverlayModifier>(
7966             WeakClaim(this), GetScrollBarOverlayModifier(), GetScrollEdgeEffect());
7967     }
7968 
7969     if (GetIsCustomFont()) {
7970         contentMod_->SetIsCustomFont(true);
7971     }
7972     return MakeRefPtr<RichEditorPaintMethod>(WeakClaim(this), &paragraphs_, baselineOffset_, contentMod_, overlayMod_);
7973 }
7974 
7975 int32_t RichEditorPattern::GetHandleIndex(const Offset& offset) const
7976 {
7977     return paragraphs_.GetIndex(Offset(offset.GetX() + contentRect_.GetX() - richTextRect_.GetX(),
7978         offset.GetY() + contentRect_.GetY() - richTextRect_.GetY()));
7979 }
7980 
7981 std::vector<RectF> RichEditorPattern::GetTextBoxes()
7982 {
7983     auto selectedRects = paragraphs_.GetRects(textSelector_.GetTextStart(), textSelector_.GetTextEnd());
7984     std::vector<RectF> res;
7985     res.reserve(selectedRects.size());
7986     for (auto&& rect : selectedRects) {
7987         res.emplace_back(rect);
7988     }
7989     if (!res.empty() && paragraphs_.IsSelectLineHeadAndUseLeadingMargin(textSelector_.GetTextStart())) {
7990         // To make drag screenshot include LeadingMarginPlaceholder when not single line
7991         if (res.front().GetY() != res.back().GetY()) {
7992             res.front().SetLeft(0.0f);
7993         }
7994     }
7995     return res;
7996 }
7997 
7998 float RichEditorPattern::GetLineHeight() const
7999 {
8000     auto selectedRects = paragraphs_.GetRects(textSelector_.GetTextStart(), textSelector_.GetTextEnd());
8001     CHECK_NULL_RETURN(selectedRects.size(), 0.0f);
8002     return selectedRects.front().Height();
8003 }
8004 
8005 size_t RichEditorPattern::GetLineCount() const
8006 {
8007     return paragraphs_.GetLineCount();
8008 }
8009 
8010 TextLineMetrics RichEditorPattern::GetLineMetrics(int32_t lineNumber)
8011 {
8012     if (lineNumber < 0 || GetLineCount() == 0 || static_cast<uint32_t>(lineNumber) > GetLineCount() - 1) {
8013         TAG_LOGE(AceLogTag::ACE_RICH_TEXT,
8014                 "GetLineMetrics failed, lineNumber not between 0 and max lines:%{public}d", lineNumber);
8015         return TextLineMetrics();
8016     }
8017     auto lineMetrics = paragraphs_.GetLineMetrics(lineNumber);
8018     const auto& textRect = GetTextRect();
8019     lineMetrics.x += textRect.GetX();
8020     lineMetrics.y += textRect.GetY();
8021     lineMetrics.baseline += textRect.GetY();
8022     return lineMetrics;
8023 }
8024 
8025 std::vector<ParagraphManager::TextBox> RichEditorPattern::GetRectsForRange(
8026     int32_t start, int32_t end, RectHeightStyle heightStyle, RectWidthStyle widthStyle)
8027 {
8028     if (start < 0 || end < 0 || start > end) {
8029         return {};
8030     }
8031     std::vector<ParagraphManager::TextBox> textBoxes =
8032         paragraphs_.GetRectsForRange(start, end, heightStyle, widthStyle);
8033     const auto& textRect = richTextRect_;
8034     std::vector<ParagraphManager::TextBox> adjustedTextBoxes;
8035     for (auto& textBox : textBoxes) {
8036         ParagraphManager::TextBox adjustedTextBox = textBox;
8037         adjustedTextBox.rect_.SetLeft(textBox.rect_.Left() + textRect.Left());
8038         adjustedTextBox.rect_.SetTop(textBox.rect_.Top() + textRect.Top());
8039         adjustedTextBoxes.push_back(adjustedTextBox);
8040     }
8041     return adjustedTextBoxes;
8042 }
8043 
8044 float RichEditorPattern::GetLetterSpacing() const
8045 {
8046     auto selectedRects = paragraphs_.GetRects(textSelector_.GetTextStart(), textSelector_.GetTextEnd());
8047     CHECK_NULL_RETURN(!selectedRects.empty(), 0.0f);
8048     return selectedRects.front().Width();
8049 }
8050 
8051 void RichEditorPattern::UpdateSelectMenuInfo(SelectMenuInfo& menuInfo)
8052 {
8053     bool isSupportCameraInput = false;
8054 #if defined(ENABLE_STANDARD_INPUT)
8055     auto inputMethod = MiscServices::InputMethodController::GetInstance();
8056     isSupportCameraInput =
8057         inputMethod && inputMethod->IsInputTypeSupported(MiscServices::InputType::CAMERA_INPUT);
8058 #endif
8059     menuInfo.showCameraInput = !IsSelected() && isSupportCameraInput && !customKeyboardBuilder_;
8060     if (textResponseType_.has_value()) {
8061         menuInfo.responseType = static_cast<int32_t>(textResponseType_.value());
8062     }
8063 }
8064 
8065 bool RichEditorPattern::IsShowSelectMenuUsingMouse()
8066 {
8067     auto pipeline = PipelineContext::GetCurrentContext();
8068     CHECK_NULL_RETURN(pipeline, false);
8069     auto selectOverlayManager = pipeline->GetSelectOverlayManager();
8070     CHECK_NULL_RETURN(selectOverlayManager, false);
8071     return selectOverlayManager->GetSelectOverlayInfo().isUsingMouse;
8072 }
8073 
8074 RectF RichEditorPattern::GetCaretRect() const
8075 {
8076     RectF rect;
8077     CHECK_NULL_RETURN(overlayMod_, rect);
8078     auto richEditorOverlay = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
8079     CHECK_NULL_RETURN(richEditorOverlay, rect);
8080     rect.SetOffset(richEditorOverlay->GetCaretOffset());
8081     rect.SetHeight(richEditorOverlay->GetCaretHeight());
8082     return rect;
8083 }
8084 
8085 void RichEditorPattern::ScrollToSafeArea() const
8086 {
8087     auto host = GetHost();
8088     CHECK_NULL_VOID(host);
8089     auto pipeline = host->GetContext();
8090     CHECK_NULL_VOID(pipeline);
8091     if (pipeline->UsingCaretAvoidMode()) {
8092         // using TriggerAvoidOnCaretChange instead in CaretAvoidMode
8093         return;
8094     }
8095     auto textFieldManager = DynamicCast<TextFieldManagerNG>(pipeline->GetTextFieldManager());
8096     CHECK_NULL_VOID(textFieldManager);
8097     textFieldManager->ScrollTextFieldToSafeArea();
8098 }
8099 
8100 void RichEditorPattern::InitScrollablePattern()
8101 {
8102     auto layoutProperty = GetLayoutProperty<RichEditorLayoutProperty>();
8103     CHECK_NULL_VOID(layoutProperty);
8104     auto barState = layoutProperty->GetDisplayModeValue(DisplayMode::AUTO);
8105     CHECK_NULL_VOID(!barDisplayMode_ || barDisplayMode_.value() != barState);
8106     barDisplayMode_ = barState;
8107     if (!GetScrollableEvent()) {
8108         AddScrollEvent();
8109     }
8110     SetAxis(Axis::VERTICAL);
8111     // not paint bar in overlay modifier when state=off
8112     if (barState != DisplayMode::AUTO) {
8113         barState = DisplayMode::ON;
8114     }
8115     SetScrollBar(barState);
8116     auto scrollBar = GetScrollBar();
8117     if (scrollBar) {
8118         auto host = GetHost();
8119         CHECK_NULL_VOID(host);
8120         auto pipeline = host->GetContext();
8121         CHECK_NULL_VOID(pipeline);
8122         auto richEditorTheme = pipeline->GetTheme<RichEditorTheme>();
8123         CHECK_NULL_VOID(richEditorTheme);
8124         scrollBar->SetMinHeight(richEditorTheme->GetScrollbarMinHeight());
8125     }
8126     if (overlayMod_) {
8127         UpdateScrollBarOffset();
8128     }
8129     auto& paddingProperty = layoutProperty->GetPaddingProperty();
8130     if (paddingProperty) {
8131         auto offsetY = paddingProperty->top.has_value() ? paddingProperty->top->GetDimension().ConvertToPx() : 0.0f;
8132         auto offsetX = paddingProperty->left.has_value() ? paddingProperty->left->GetDimension().ConvertToPx() : 0.0f;
8133         richTextRect_.SetOffset(OffsetF(offsetX, offsetY));
8134     }
8135 }
8136 
8137 void RichEditorPattern::ProcessInnerPadding()
8138 {
8139     auto context = PipelineBase::GetCurrentContext();
8140     CHECK_NULL_VOID(context);
8141     auto theme = context->GetTheme<RichEditorTheme>();
8142     CHECK_NULL_VOID(theme);
8143     auto host = GetHost();
8144     CHECK_NULL_VOID(host);
8145     auto layoutProperty = host->GetLayoutProperty<RichEditorLayoutProperty>();
8146     CHECK_NULL_VOID(layoutProperty);
8147     auto themePadding = theme->GetPadding();
8148     auto& paddingProp = layoutProperty->GetPaddingProperty();
8149     auto left = !paddingProp ? CalcLength(themePadding.Left()).GetDimension()
8150                              : paddingProp->left.value_or(CalcLength(themePadding.Left())).GetDimension();
8151     auto top = !paddingProp ? CalcLength(themePadding.Top()).GetDimension()
8152                             : paddingProp->top.value_or(CalcLength(themePadding.Top())).GetDimension();
8153     auto bottom = !paddingProp ? CalcLength(themePadding.Bottom()).GetDimension()
8154                                : paddingProp->bottom.value_or(CalcLength(themePadding.Bottom())).GetDimension();
8155     auto right = !paddingProp ? CalcLength(themePadding.Right()).GetDimension()
8156                               : paddingProp->right.value_or(CalcLength(themePadding.Right())).GetDimension();
8157     PaddingProperty paddings;
8158     paddings.top = NG::CalcLength(top);
8159     paddings.bottom = NG::CalcLength(bottom);
8160     paddings.left = NG::CalcLength(left);
8161     paddings.right = NG::CalcLength(right);
8162     layoutProperty->UpdatePadding(paddings);
8163 }
8164 
8165 void RichEditorPattern::UpdateScrollStateAfterLayout(bool shouldDisappear)
8166 {
8167     bool hasTextOffsetChanged = false;
8168     if (GreatNotEqual(richTextRect_.GetY(), contentRect_.GetY())) {
8169         auto offset = richTextRect_.GetOffset();
8170         offset.AddY(contentRect_.GetY() - richTextRect_.GetY());
8171         richTextRect_.SetOffset(offset);
8172         hasTextOffsetChanged = true;
8173     }
8174     if (GreatNotEqual(richTextRect_.Height(), contentRect_.Height()) &&
8175         LessNotEqual(richTextRect_.Bottom(), contentRect_.Bottom())) {
8176         auto offset = richTextRect_.GetOffset();
8177         offset.AddY(contentRect_.Bottom() - richTextRect_.Bottom());
8178         richTextRect_.SetOffset(offset);
8179         hasTextOffsetChanged = true;
8180     }
8181     if (LessOrEqual(richTextRect_.Height(), contentRect_.Height()) &&
8182         LessNotEqual(richTextRect_.GetY(), contentRect_.GetY())) {
8183         richTextRect_.SetOffset(contentRect_.GetOffset());
8184         hasTextOffsetChanged = true;
8185     }
8186     if (hasTextOffsetChanged) {
8187         UpdateChildrenOffset();
8188     }
8189     StopScrollable();
8190     CheckScrollable();
8191     if (overlayMod_) {
8192         UpdateScrollBarOffset();
8193     }
8194     auto scrollBar = GetScrollBar();
8195     CHECK_NULL_VOID(scrollBar);
8196 
8197     if (isFirstCallOnReady_) {
8198         isFirstCallOnReady_ = false;
8199         scrollBar->ScheduleDisappearDelayTask();
8200         return;
8201     }
8202     if (shouldDisappear) {
8203         scrollBar->ScheduleDisappearDelayTask();
8204     }
8205 }
8206 
8207 bool RichEditorPattern::OnScrollCallback(float offset, int32_t source)
8208 {
8209     auto scrollBar = GetScrollBar();
8210     if (source == SCROLL_FROM_START) {
8211         IF_PRESENT(scrollBar, PlayScrollBarAppearAnimation());
8212         if (SelectOverlayIsOn()) {
8213             selectOverlay_->HideMenu(true);
8214         }
8215         UIObserverHandler::GetInstance().NotifyScrollEventStateChange(
8216             AceType::WeakClaim(this), ScrollEventType::SCROLL_START);
8217         return true;
8218     }
8219     if (IsReachedBoundary(offset)) {
8220         return false;
8221     }
8222     if (scrollBar && source == SCROLL_FROM_JUMP) {
8223         scrollBar->PlayScrollBarAppearAnimation();
8224         scrollBar->ScheduleDisappearDelayTask();
8225     }
8226     auto newOffset = MoveTextRect(offset);
8227     MoveFirstHandle(newOffset);
8228     MoveSecondHandle(newOffset);
8229     return true;
8230 }
8231 
8232 float RichEditorPattern::GetCrossOverHeight() const
8233 {
8234     if (!keyboardAvoidance_ || !contentChange_ || AceApplicationInfo::GetInstance().
8235         GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_FOURTEEN)) {
8236         return 0.0f;
8237     }
8238     auto host = GetHost();
8239     CHECK_NULL_RETURN(host, 0.0f);
8240     auto pipeline = host->GetContext();
8241     CHECK_NULL_RETURN(pipeline, 0.0f);
8242     auto rootHeight = pipeline->GetRootHeight();
8243     auto keyboardY = rootHeight - pipeline->GetSafeAreaManager()->GetKeyboardInset().Length();
8244     if (GreatOrEqual(keyboardY, rootHeight)) {
8245         return 0.0f;
8246     }
8247     float height = contentRect_.Bottom();
8248     float frameY = parentGlobalOffset_.GetY() + contentRect_.GetY();
8249     float bottom = frameY + height;
8250     auto crossOverHeight = bottom - keyboardY;
8251     if (LessOrEqual(crossOverHeight, 0.0f)) {
8252         return 0.0f;
8253     }
8254     return crossOverHeight;
8255 }
8256 
8257 float RichEditorPattern::MoveTextRect(float offset)
8258 {
8259     auto keyboardOffset = GetCrossOverHeight();
8260     if (GreatNotEqual(richTextRect_.Height(), contentRect_.Height() - keyboardOffset)) {
8261         if (GreatNotEqual(richTextRect_.GetY() + offset, contentRect_.GetY())) {
8262             offset = contentRect_.GetY() - richTextRect_.GetY();
8263         } else if (LessNotEqual(richTextRect_.Bottom() + offset, contentRect_.Bottom() - keyboardOffset)) {
8264             offset = contentRect_.Bottom() - keyboardOffset - richTextRect_.Bottom();
8265         }
8266     } else if (!NearEqual(richTextRect_.GetY(), contentRect_.GetY())) {
8267         offset = contentRect_.GetY() - richTextRect_.GetY();
8268     } else {
8269         return 0.0f;
8270     }
8271     if (NearEqual(offset, 0.0f)) {
8272         return offset;
8273     }
8274     scrollOffset_ = richTextRect_.GetY() + offset;
8275     richTextRect_.SetOffset(OffsetF(richTextRect_.GetX(), scrollOffset_));
8276     UpdateScrollBarOffset();
8277     UpdateChildrenOffset();
8278     if (auto host = GetHost(); host) {
8279         host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
8280     }
8281     return offset;
8282 }
8283 
8284 void RichEditorPattern::MoveFirstHandle(float offset)
8285 {
8286     if (SelectOverlayIsOn() && !NearEqual(offset, 0.0f)) {
8287         textSelector_.selectionBaseOffset.AddY(offset);
8288         auto firstHandleOffset = textSelector_.firstHandle.GetOffset();
8289         firstHandleOffset.AddY(offset);
8290         textSelector_.firstHandle.SetOffset(firstHandleOffset);
8291         selectOverlay_->UpdateFirstHandleOffset();
8292     }
8293 }
8294 
8295 void RichEditorPattern::MoveSecondHandle(float offset)
8296 {
8297     if (SelectOverlayIsOn() && !NearEqual(offset, 0.0f)) {
8298         textSelector_.selectionDestinationOffset.AddY(offset);
8299         auto secondHandleOffset = textSelector_.secondHandle.GetOffset();
8300         secondHandleOffset.AddY(offset);
8301         textSelector_.secondHandle.SetOffset(secondHandleOffset);
8302         selectOverlay_->UpdateSecondHandleOffset();
8303     }
8304 }
8305 
8306 void RichEditorPattern::SetNeedMoveCaretToContentRect()
8307 {
8308     CHECK_NULL_VOID(isRichEditorInit_);
8309     needMoveCaretToContentRect_ = true;
8310 }
8311 
8312 void RichEditorPattern::MoveCaretToContentRect()
8313 {
8314     auto [caretOffset, caretHeight] = CalculateCaretOffsetAndHeight();
8315     MoveCaretToContentRect(caretOffset, caretHeight);
8316 }
8317 
8318 void RichEditorPattern::MoveCaretToContentRect(const OffsetF& caretOffset, float caretHeight)
8319 {
8320     auto keyboardOffset = GetCrossOverHeight();
8321     auto contentRect = GetTextContentRect();
8322     auto textRect = GetTextRect();
8323     if (LessOrEqual(textRect.Height(), contentRect.Height() - keyboardOffset) || isShowPlaceholder_) {
8324         return;
8325     }
8326     if (LessNotEqual(contentRect.GetSize().Height(), caretHeight) &&
8327         !NearEqual(caretOffset.GetY() + caretHeight, contentRect.Bottom() - keyboardOffset)) {
8328         OnScrollCallback(contentRect.Bottom() - keyboardOffset - caretOffset.GetY() - caretHeight, SCROLL_FROM_NONE);
8329     }
8330     if (LessNotEqual(contentRect.GetSize().Height(), caretHeight)) {
8331         return;
8332     }
8333     if (LessNotEqual(caretOffset.GetY(), contentRect.GetY())) {
8334         if (LessOrEqual(caretOffset.GetX(), GetTextRect().GetX())) {
8335             OnScrollCallback(contentRect.GetY() - caretOffset.GetY() + caretHeight, SCROLL_FROM_NONE);
8336         } else {
8337             OnScrollCallback(contentRect.GetY() - caretOffset.GetY(), SCROLL_FROM_NONE);
8338         }
8339     } else if (GreatNotEqual(caretOffset.GetY() + caretHeight, contentRect.Bottom() - keyboardOffset)) {
8340         auto distance = contentRect.Bottom() - keyboardOffset - caretOffset.GetY() - caretHeight -
8341             CARET_BOTTOM_DISTANCE.ConvertToPx();
8342         OnScrollCallback(distance, SCROLL_FROM_NONE);
8343     }
8344 }
8345 
8346 void RichEditorPattern::MoveCaretToContentRect(float offset, int32_t source)
8347 {
8348     float caretHeight = 0.0f;
8349     auto caretOffset = CalcCursorOffsetByPosition(caretPosition_, caretHeight);
8350     auto keyboardOffset = GetCrossOverHeight();
8351     auto contentRect = GetTextContentRect();
8352     auto distance = contentRect.Bottom() - keyboardOffset - caretOffset.GetY() - caretHeight - offset;
8353     OnScrollCallback(distance, source);
8354 }
8355 
8356 bool RichEditorPattern::IsCaretInContentArea()
8357 {
8358     float caretHeight = 0.0f;
8359     auto caretOffset = CalcCursorOffsetByPosition(caretPosition_, caretHeight);
8360     auto keyboardOffset = GetCrossOverHeight();
8361     auto contentRect = GetTextContentRect();
8362     return GreatNotEqual(caretOffset.GetY() + caretHeight, contentRect.GetY())
8363         && LessNotEqual(caretOffset.GetY(), contentRect.Bottom() - keyboardOffset);
8364 }
8365 
8366 void RichEditorPattern::UpdateScrollBarOffset()
8367 {
8368     if (!GetScrollBar() && !GetScrollBarProxy()) {
8369         return;
8370     }
8371     Size size(frameRect_.Width(), frameRect_.Height());
8372     auto verticalGap = frameRect_.Height() - contentRect_.Height();
8373     UpdateScrollBarRegion(
8374         contentRect_.GetY() - richTextRect_.GetY(), richTextRect_.Height() + verticalGap, size, Offset(0.0, 0.0));
8375     auto tmpHost = GetHost();
8376     CHECK_NULL_VOID(tmpHost);
8377     tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
8378 }
8379 
8380 void RichEditorPattern::OnScrollEndCallback()
8381 {
8382     auto scrollBar = GetScrollBar();
8383     if (scrollBar) {
8384         scrollBar->ScheduleDisappearDelayTask();
8385     }
8386     CHECK_NULL_VOID(!selectOverlay_->GetIsHandleMoving());
8387     if (IsSelectAreaVisible()) {
8388         selectOverlay_->UpdateMenuOffset();
8389         selectOverlay_->ShowMenu();
8390     }
8391     if (AnimateStoped()) {
8392         UIObserverHandler::GetInstance().NotifyScrollEventStateChange(
8393             AceType::WeakClaim(this), ScrollEventType::SCROLL_STOP);
8394     }
8395 }
8396 
8397 bool RichEditorPattern::IsSelectAreaVisible()
8398 {
8399     auto host = GetHost();
8400     CHECK_NULL_RETURN(host, false);
8401     auto pipeline = host->GetContext();
8402     CHECK_NULL_RETURN(pipeline, false);
8403     auto safeAreaManager = pipeline->GetSafeAreaManager();
8404     CHECK_NULL_RETURN(safeAreaManager, false);
8405     auto keyboardInsert = safeAreaManager->GetKeyboardInset();
8406     auto selectArea = GetSelectArea(SelectRectsType::ALL_LINES);
8407 
8408     return !selectArea.IsEmpty() && LessNotEqual(selectArea.Top(), keyboardInsert.start);
8409 }
8410 
8411 bool RichEditorPattern::IsReachedBoundary(float offset)
8412 {
8413     auto keyboardOffset = GetCrossOverHeight();
8414     return (NearEqual(richTextRect_.GetY(), contentRect_.GetY()) && GreatNotEqual(offset, 0.0f)) ||
8415            (NearEqual(richTextRect_.GetY() + richTextRect_.Height(),
8416                 contentRect_.GetY() + contentRect_.Height() - keyboardOffset) &&
8417                LessNotEqual(offset, 0.0f));
8418 }
8419 
8420 void RichEditorPattern::CheckScrollable()
8421 {
8422     auto gestureHub = GetGestureEventHub();
8423     CHECK_NULL_VOID(gestureHub);
8424     scrollable_ = GetTextContentLength() > 0 && GreatNotEqual(richTextRect_.Height(), contentRect_.Height());
8425     SetScrollEnabled(scrollable_);
8426 }
8427 
8428 void RichEditorPattern::UpdateChildrenOffset()
8429 {
8430     auto host = GetHost();
8431     CHECK_NULL_VOID(host);
8432     std::vector<int32_t> placeholderIndex;
8433     for (const auto& child : spans_) {
8434         if (!child) {
8435             continue;
8436         }
8437         if (AceType::InstanceOf<ImageSpanItem>(child) || AceType::InstanceOf<PlaceholderSpanItem>(child)) {
8438             placeholderIndex.emplace_back(child->placeholderIndex);
8439         }
8440     }
8441     if (spans_.empty() || placeholderIndex.empty()) {
8442         return;
8443     }
8444     size_t index = 0;
8445     std::vector<RectF> rectsForPlaceholders = paragraphs_.GetPlaceholderRects();
8446     auto childrenNodes = host->GetChildren();
8447     auto textOffset = GetTextRect().GetOffset();
8448     for (const auto& child : childrenNodes) {
8449         auto childNode = AceType::DynamicCast<FrameNode>(child);
8450         if (!childNode) {
8451             continue;
8452         }
8453         if (!(childNode->GetPattern<ImagePattern>() || childNode->GetPattern<PlaceholderSpanPattern>())) {
8454             continue;
8455         }
8456         if (isSpanStringMode_) {
8457             auto imageSpanNode = AceType::DynamicCast<ImageSpanNode>(child);
8458             if (imageSpanNode && imageSpanNode->GetSpanItem()) {
8459                 index = static_cast<uint32_t>(imageSpanNode->GetSpanItem()->placeholderIndex);
8460             }
8461         }
8462         if (index >= rectsForPlaceholders.size()) {
8463             break;
8464         }
8465         auto rect = rectsForPlaceholders.at(index);
8466         auto geometryNode = childNode->GetGeometryNode();
8467         if (geometryNode) {
8468             geometryNode->SetMarginFrameOffset(textOffset + OffsetF(rect.Left(), rect.Top()));
8469             childNode->ForceSyncGeometryNode();
8470             childNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
8471         }
8472         ++index;
8473     }
8474 }
8475 
8476 void RichEditorPattern::AutoScrollByEdgeDetection(AutoScrollParam param, OffsetF offset, EdgeDetectionStrategy strategy)
8477 {
8478     if (NearEqual(prevAutoScrollOffset_.GetY(), offset.GetY())) {
8479         return;
8480     }
8481     prevAutoScrollOffset_ = offset;
8482     auto contentRect = GetTextContentRect();
8483     auto isDragging = param.autoScrollEvent == AutoScrollEvent::DRAG;
8484     float edgeThreshold = isDragging ? AUTO_SCROLL_DRAG_EDGE_DISTANCE.ConvertToPx()
8485                                      : AUTO_SCROLL_EDGE_DISTANCE.ConvertToPx();
8486     auto maxHeight = isDragging ? frameRect_.Height() : contentRect.Height();
8487     if (GreatNotEqual(edgeThreshold * 2, maxHeight)) {
8488         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "AutoScrollByEdgeDetection: hot area height is great than max height.");
8489         return;
8490     }
8491     float topEdgeThreshold = isDragging ? edgeThreshold : edgeThreshold + contentRect.GetY();
8492     float bottomThreshold = isDragging ? frameRect_.Height() - edgeThreshold : contentRect.Bottom() - edgeThreshold;
8493     if (param.autoScrollEvent == AutoScrollEvent::HANDLE) {
8494         auto handleTopOffset = offset;
8495         auto handleBottomOffset = OffsetF(offset.GetX(), offset.GetY() + param.handleRect.Height());
8496         if (GreatNotEqual(handleBottomOffset.GetY(), bottomThreshold)) {
8497             param.offset = bottomThreshold - handleBottomOffset.GetY();
8498             ScheduleAutoScroll(param);
8499         } else if (LessNotEqual(handleTopOffset.GetY(), topEdgeThreshold)) {
8500             param.offset = topEdgeThreshold - handleTopOffset.GetY();
8501             ScheduleAutoScroll(param);
8502         } else {
8503             StopAutoScroll();
8504         }
8505         return;
8506     }
8507     // drag and mouse
8508     if (GreatNotEqual(offset.GetY(), bottomThreshold)) {
8509         param.offset = isDragging ? -CalcDragSpeed(bottomThreshold, frameRect_.Height(), offset.GetY())
8510                                   : bottomThreshold - offset.GetY();
8511         ScheduleAutoScroll(param);
8512     } else if (LessNotEqual(offset.GetY(), topEdgeThreshold)) {
8513         param.offset = isDragging ? CalcDragSpeed(topEdgeThreshold, 0, offset.GetY())
8514                                   : topEdgeThreshold - offset.GetY();
8515         ScheduleAutoScroll(param);
8516     } else {
8517         StopAutoScroll();
8518     }
8519 }
8520 
8521 float RichEditorPattern::CalcDragSpeed(float hotAreaStart, float hotAreaEnd, float point)
8522 {
8523     auto distanceRatio = (point - hotAreaStart) / (hotAreaEnd - hotAreaStart);
8524     auto speedFactor = Curves::SHARP->MoveInternal(distanceRatio);
8525     return ((MAX_DRAG_SCROLL_SPEED * speedFactor) / TIME_UNIT) * AUTO_SCROLL_INTERVAL;
8526 }
8527 
8528 void RichEditorPattern::ScheduleAutoScroll(AutoScrollParam param)
8529 {
8530     if (GreatNotEqual(param.offset, 0.0f) && IsReachTop()) {
8531         return;
8532     }
8533     if (LessNotEqual(param.offset, 0.0f) && IsReachBottom()) {
8534         return;
8535     }
8536     auto host = GetHost();
8537     CHECK_NULL_VOID(host);
8538     auto context = host->GetContext();
8539     CHECK_NULL_VOID(context);
8540     auto taskExecutor = context->GetTaskExecutor();
8541     CHECK_NULL_VOID(taskExecutor);
8542     if (param.isFirstRun_) {
8543         param.isFirstRun_ = false;
8544         currentScrollParam_ = param;
8545         if (isAutoScrollRunning_) {
8546             return;
8547         }
8548     }
8549     autoScrollTask_.Reset([weak = WeakClaim(this)]() {
8550         auto client = weak.Upgrade();
8551         CHECK_NULL_VOID(client);
8552         client->OnAutoScroll(client->currentScrollParam_);
8553         if (client->IsReachTop() || client->IsReachBottom()) {
8554             client->StopAutoScroll();
8555         }
8556     });
8557     isAutoScrollRunning_ = true;
8558     taskExecutor->PostDelayedTask(autoScrollTask_, TaskExecutor::TaskType::UI, AUTO_SCROLL_INTERVAL,
8559         "ArkUIRichEditorScheduleAutoScroll");
8560 }
8561 
8562 void RichEditorPattern::OnAutoScroll(AutoScrollParam param)
8563 {
8564     if (param.showScrollbar) {
8565         auto scrollBar = GetScrollBar();
8566         if (scrollBar) {
8567             scrollBar->PlayScrollBarAppearAnimation();
8568         }
8569         param.showScrollbar = false;
8570     }
8571 
8572     if (param.autoScrollEvent == AutoScrollEvent::HANDLE) {
8573         auto newOffset = MoveTextRect(param.offset);
8574         if (param.isFirstHandle) {
8575             MoveSecondHandle(newOffset);
8576         } else {
8577             MoveFirstHandle(newOffset);
8578         }
8579         selectOverlay_->OnHandleMove(param.handleRect, param.isFirstHandle);
8580         if (NearEqual(newOffset, 0.0f)) {
8581             return;
8582         }
8583         ScheduleAutoScroll(param);
8584         return;
8585     }
8586 
8587     if (param.autoScrollEvent == AutoScrollEvent::DRAG) {
8588         auto newOffset = MoveTextRect(param.offset);
8589         if (NearEqual(newOffset, 0.0f)) {
8590             return;
8591         }
8592         ScheduleAutoScroll(param);
8593         return;
8594     }
8595 
8596     if (param.autoScrollEvent == AutoScrollEvent::MOUSE) {
8597         auto newOffset = MoveTextRect(param.offset);
8598         auto textOffset =
8599             Offset(param.eventOffset.GetX() - GetTextRect().GetX(), param.eventOffset.GetY() - GetTextRect().GetY());
8600         int32_t extend = paragraphs_.GetIndex(textOffset);
8601         UpdateSelector(textSelector_.baseOffset, extend);
8602         SetCaretPosition(std::max(textSelector_.baseOffset, extend));
8603         if (NearEqual(newOffset, 0.0f)) {
8604             return;
8605         }
8606         ScheduleAutoScroll(param);
8607     }
8608 }
8609 
8610 void RichEditorPattern::StopAutoScroll(bool hideBarImmediately)
8611 {
8612     isAutoScrollRunning_ = false;
8613     autoScrollTask_.Cancel();
8614     prevAutoScrollOffset_ = OffsetF(0.0f, 0.0f);
8615     auto scrollBar = GetScrollBar();
8616     if (scrollBar && hideBarImmediately) {
8617         scrollBar->PlayScrollBarDisappearAnimation();
8618     }
8619 }
8620 
8621 bool RichEditorPattern::NeedAiAnalysis(
8622     const CaretUpdateType targeType, const int32_t pos, const int32_t& spanStart, const std::string& content)
8623 {
8624     if (spanStart < 0) {
8625         TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "NeedAiAnalysis -spanStart:%{public}d, return!", spanStart);
8626         return false;
8627     }
8628 
8629     if (!InputAIChecker::NeedAIAnalysis(content, targeType, lastClickTimeStamp_ - lastAiPosTimeStamp_)) {
8630         return false;
8631     }
8632 
8633     if (IsClickBoundary(pos) && targeType == CaretUpdateType::PRESSED) {
8634         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "NeedAiAnalysis IsClickBoundary, return!");
8635         return false;
8636     }
8637     EmojiRelation relation = GetEmojiRelation(pos);
8638     if (relation == EmojiRelation::IN_EMOJI || relation == EmojiRelation::MIDDLE_EMOJI ||
8639         relation == EmojiRelation::BEFORE_EMOJI) {
8640         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "NeedAiAnalysis emoji relation=%{public}d, return!", relation);
8641         return false;
8642     }
8643     return true;
8644 }
8645 
8646 void RichEditorPattern::AdjustCursorPosition(int32_t& pos)
8647 {
8648     // the rich text has some spans, the pos is belong to the whole richtext content, should use (pos - spanStarint)
8649     int32_t spanStart = -1;
8650     // get the span text by the position, maybe text is empty
8651     std::string content = GetPositionSpansText(pos, spanStart);
8652 
8653     if (NeedAiAnalysis(CaretUpdateType::PRESSED, pos, spanStart, content)) {
8654         int32_t aiPos = pos - spanStart;
8655         DataDetectorMgr::GetInstance().AdjustCursorPosition(aiPos, content, lastAiPosTimeStamp_, lastClickTimeStamp_);
8656         if (aiPos < 0) {
8657             return;
8658         }
8659         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "get ai pos:%{public}d--spanStart%{public}d", aiPos, spanStart);
8660         pos = aiPos + spanStart;
8661     }
8662 }
8663 
8664 bool RichEditorPattern::AdjustWordSelection(int32_t& start, int32_t& end)
8665 {
8666     // the rich text has some spans, the pos is belong to the whole richtext content, should use (pos - spanStarint)
8667     int32_t spanStart = -1;
8668     // get the span text by the position, maybe text is empty
8669     std::string content = GetPositionSpansText(start, spanStart);
8670     if (NeedAiAnalysis(CaretUpdateType::DOUBLE_CLICK, start, spanStart, content)) {
8671         int32_t aiPosStart = start - spanStart;
8672         int32_t aiPosEnd = end - spanStart;
8673         DataDetectorMgr::GetInstance().AdjustWordSelection(aiPosStart, content, aiPosStart, aiPosEnd);
8674         if (aiPosStart < 0 || aiPosEnd < 0) {
8675             return false;
8676         }
8677 
8678         start = std::min(aiPosStart + spanStart, GetTextContentLength());
8679         end = std::min(aiPosEnd + spanStart, GetTextContentLength());
8680         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "get ai selector [%{public}d--%{public}d]", start, end);
8681         return true;
8682     }
8683     return false;
8684 }
8685 
8686 void RichEditorPattern::AdjustPlaceholderSelection(int32_t& start, int32_t& end, const Offset& touchPos)
8687 {
8688     CHECK_NULL_VOID(!spans_.empty());
8689     if (!IsTouchBeforeCaret(start, touchPos)) {
8690         return;
8691     }
8692     auto it = std::find_if(spans_.begin(), spans_.end(), [start](const RefPtr<SpanItem>& spanItem) {
8693         return spanItem->position == start;
8694     });
8695     if (it != spans_.end()) {
8696         // adjust selection if touch right of image or placeholder
8697         auto spanIndex = std::distance(spans_.begin(), it);
8698         auto spanNodeBefore = DynamicCast<FrameNode>(GetChildByIndex(spanIndex));
8699         if (spanNodeBefore && (spanNodeBefore->GetTag() == V2::IMAGE_ETS_TAG ||
8700             spanNodeBefore->GetTag() == V2::PLACEHOLDER_SPAN_ETS_TAG)) {
8701             end = start;
8702             --start;
8703             TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "get placeholder selector [%{public}d--%{public}d]", start, end);
8704         }
8705     }
8706 }
8707 
8708 bool RichEditorPattern::IsTouchAtLineEnd(int32_t caretPos, const Offset& textOffset)
8709 {
8710     auto positionWithAffinity = paragraphs_.GetGlyphPositionAtCoordinate(textOffset);
8711     TextAffinity currentAffinity = positionWithAffinity.affinity_;
8712     return currentAffinity == TextAffinity::UPSTREAM && !IsTouchBeforeCaret(caretPos, textOffset);
8713 }
8714 
8715 bool RichEditorPattern::IsTouchBeforeCaret(int32_t caretPos, const Offset& textOffset) {
8716     CHECK_NULL_RETURN(!spans_.empty(), false);
8717     float selectLineHeight = 0.0f;
8718     OffsetF caretOffsetUp = paragraphs_.ComputeCursorOffset(caretPos, selectLineHeight);
8719     auto needAdjustRect = RectF{ 0, caretOffsetUp.GetY(), caretOffsetUp.GetX(), selectLineHeight };
8720     return needAdjustRect.IsInRegion(PointF{ textOffset.GetX(), textOffset.GetY() });
8721 }
8722 
8723 bool RichEditorPattern::IsClickBoundary(const int32_t position)
8724 {
8725     if (InputAIChecker::IsSingleClickAtBoundary(position, GetTextContentLength())) {
8726         return true;
8727     }
8728 
8729     float height = 0;
8730     auto handleOffset = CalcCursorOffsetByPosition(position, height);
8731     if (InputAIChecker::IsMultiClickAtBoundary(handleOffset, TextPattern::GetTextRect())) {
8732         return true;
8733     }
8734     return false;
8735 }
8736 
8737 std::string RichEditorPattern::GetPositionSpansText(int32_t position, int32_t& startSpan)
8738 {
8739     int32_t start = position - AI_TEXT_RANGE_LEFT;
8740     int32_t end = position + AI_TEXT_RANGE_RIGHT;
8741 
8742     start = std::clamp(start, 0, GetTextContentLength());
8743     end = std::clamp(end, 0, GetTextContentLength());
8744     AdjustSelector(start, end);
8745     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "caret=%{public}d, range=[%{public}d,%{public}d]", position, start, end);
8746 
8747     // get all the spans between start and end, then filter the valid text
8748     auto infos = GetSpansInfo(start, end, GetSpansMethod::ONSELECT);
8749     if (infos.GetSelection().resultObjects.empty()) {
8750         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "get spans text is null pos:%{public}d,return", position);
8751         return "";
8752     }
8753     auto list = infos.GetSelection().resultObjects;
8754 
8755     std::stringstream sstream;
8756     for (const auto& obj : list) {
8757         if (obj.type != SelectSpanType::TYPESPAN) {
8758             if (obj.spanPosition.spanRange[0] == position) {
8759                 startSpan = -1;
8760                 return "";
8761             } else if (obj.spanPosition.spanRange[1] <= position) {
8762                 sstream.str("");
8763                 startSpan = -1;
8764             } else {
8765                 break;
8766             }
8767         } else {
8768             if (startSpan < 0) {
8769                 startSpan = obj.spanPosition.spanRange[0] + obj.offsetInSpan[0];
8770             }
8771             // we should use the wide string deal to avoid crash
8772             auto wideText = StringUtils::ToWstring(obj.valueString);
8773             int32_t textLen = static_cast<int32_t>(wideText.length());
8774             if (obj.offsetInSpan[0] < textLen && obj.offsetInSpan[1] <= textLen) {
8775                 sstream << StringUtils::ToString(
8776                     wideText.substr(obj.offsetInSpan[0], obj.offsetInSpan[1] - obj.offsetInSpan[0]));
8777             } else {
8778                 TAG_LOGE(AceLogTag::ACE_RICH_TEXT,
8779                     "wideText substr out of range, wideText.length = %{public}zu, substr = [%{public}d, %{public}d]",
8780                     wideText.length(), obj.offsetInSpan[0], obj.offsetInSpan[1] - obj.offsetInSpan[0]);
8781             }
8782         }
8783     }
8784 
8785     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "get spans text ret spanStart:%{public}d", startSpan);
8786     return sstream.str();
8787 }
8788 
8789 void RichEditorPattern::HandleOnCameraInput()
8790 {
8791 #if defined(ENABLE_STANDARD_INPUT)
8792     if (richEditTextChangeListener_ == nullptr) {
8793         richEditTextChangeListener_ = new OnTextChangedListenerImpl(WeakClaim(this));
8794     }
8795     auto inputMethod = MiscServices::InputMethodController::GetInstance();
8796     if (!inputMethod) {
8797         return;
8798     }
8799     StartTwinkling();
8800 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
8801     if (imeShown_) {
8802         inputMethod->StartInputType(MiscServices::InputType::CAMERA_INPUT);
8803     } else {
8804         HandleOnEditChanged(true);
8805         auto optionalTextConfig = GetMiscTextConfig();
8806         CHECK_NULL_VOID(optionalTextConfig.has_value());
8807         MiscServices::TextConfig textConfig = optionalTextConfig.value();
8808         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "HandleOnCameraInput set calling window id is : %{public}u",
8809             textConfig.windowId);
8810 #ifdef WINDOW_SCENE_SUPPORTED
8811         auto systemWindowId = GetSCBSystemWindowId();
8812         if (systemWindowId) {
8813             TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "Rich windowId From %{public}u to %{public}u.", textConfig.windowId,
8814                 systemWindowId);
8815             textConfig.windowId = systemWindowId;
8816         }
8817 #endif
8818         inputMethod->Attach(richEditTextChangeListener_, false, textConfig);
8819         inputMethod->StartInputType(MiscServices::InputType::CAMERA_INPUT);
8820         inputMethod->ShowTextInput();
8821     }
8822     CloseSelectOverlay();
8823 #endif
8824 #endif
8825 }
8826 
8827 RefPtr<FocusHub> RichEditorPattern::GetFocusHub() const
8828 {
8829     auto host = GetHost();
8830     CHECK_NULL_RETURN(host, nullptr);
8831     auto focusHub = host->GetOrCreateFocusHub();
8832     return focusHub;
8833 }
8834 
8835 void RichEditorPattern::HandleCursorOnDragMoved(const RefPtr<NotifyDragEvent>& notifyDragEvent)
8836 {
8837     auto host = GetHost();
8838     CHECK_NULL_VOID(host);
8839     if (HasFocus()) {
8840         if (!isCursorAlwaysDisplayed_) {
8841             isCursorAlwaysDisplayed_ = true;
8842             StartTwinkling();
8843         }
8844         if (SystemProperties::GetDebugEnabled()) {
8845             TAG_LOGD(AceLogTag::ACE_TEXT_FIELD,
8846                 "In OnDragMoved, the cursor has always Displayed in the textField, id:%{public}d", host->GetId());
8847         }
8848         return;
8849     }
8850     TAG_LOGI(AceLogTag::ACE_RICH_TEXT,
8851         "In OnDragMoved, the dragging node is moving in the richEditor, id:%{public}d", host->GetId());
8852     auto focusHub = GetFocusHub();
8853     CHECK_NULL_VOID(focusHub);
8854     isOnlyRequestFocus_ = true;
8855     focusHub->RequestFocusImmediately();
8856     if (focusHub->IsCurrentFocus()) {
8857         ShowCaretWithoutTwinkling();
8858     }
8859 };
8860 
8861 void RichEditorPattern::HandleCursorOnDragLeaved(const RefPtr<NotifyDragEvent>& notifyDragEvent)
8862 {
8863     auto host = GetHost();
8864     CHECK_NULL_VOID(host);
8865     TAG_LOGI(AceLogTag::ACE_RICH_TEXT,
8866         "In OnDragLeaved, the dragging node has left from richEditor, id:%{public}d", host->GetId());
8867     auto focusHub = GetFocusHub();
8868     CHECK_NULL_VOID(focusHub);
8869     focusHub->LostFocusToViewRoot();
8870     StopTwinkling();
8871 };
8872 
8873 void RichEditorPattern::HandleCursorOnDragEnded(const RefPtr<NotifyDragEvent>& notifyDragEvent)
8874 {
8875     auto host = GetHost();
8876     CHECK_NULL_VOID(host);
8877     auto focusHub = GetFocusHub();
8878     CHECK_NULL_VOID(focusHub);
8879     StopAutoScroll();
8880     if (!isCursorAlwaysDisplayed_) {
8881         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "In OnDragEnded,"
8882             " the released location is not in the current richEditor, id:%{public}d", host->GetId());
8883         focusHub->LostFocus();
8884         StopTwinkling();
8885         return;
8886     }
8887     TAG_LOGI(AceLogTag::ACE_RICH_TEXT,
8888         "In OnDragEnded, the released location is in the current richEditor, id:%{public}d", host->GetId());
8889     focusHub->LostFocusToViewRoot();
8890     isCursorAlwaysDisplayed_ = false;
8891     StopTwinkling();
8892 };
8893 
8894 void RichEditorPattern::HandleOnDragStatusCallback(
8895     const DragEventType& dragEventType, const RefPtr<NotifyDragEvent>& notifyDragEvent)
8896 {
8897     ScrollablePattern::HandleOnDragStatusCallback(dragEventType, notifyDragEvent);
8898     switch (dragEventType) {
8899         case DragEventType::MOVE:
8900             HandleCursorOnDragMoved(notifyDragEvent);
8901             break;
8902         case DragEventType::LEAVE:
8903             HandleCursorOnDragLeaved(notifyDragEvent);
8904             break;
8905         case DragEventType::DROP:
8906             HandleCursorOnDragEnded(notifyDragEvent);
8907             break;
8908         default:
8909             break;
8910     }
8911 }
8912 bool RichEditorPattern::CanStartAITask()
8913 {
8914     return TextPattern::CanStartAITask() && !isEditing_ && !isShowPlaceholder_;
8915 }
8916 
8917 bool RichEditorPattern::NeedShowAIDetect()
8918 {
8919     return TextPattern::NeedShowAIDetect() && !isEditing_ && !isShowPlaceholder_;
8920 }
8921 
8922 void RichEditorPattern::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
8923 {
8924     /* no fixed attr below, just return */
8925     if (filter.IsFastFilter()) {
8926         return;
8927     }
8928     json->PutExtAttr("enableDataDetector", textDetectEnable_ ? "true" : "false", filter);
8929     json->PutExtAttr("dataDetectorConfig", dataDetectorAdapter_->textDetectConfigStr_.c_str(), filter);
8930     json->PutExtAttr("placeholder", GetPlaceHolderInJson().c_str(), filter);
8931     json->PutExtAttr("bindSelectionMenu", GetBindSelectionMenuInJson().c_str(), filter);
8932     json->PutExtAttr("keyboardAppearance", static_cast<int32_t>(keyboardAppearance_), filter);
8933 }
8934 
8935 void RichEditorPattern::FillPreviewMenuInJson(const std::unique_ptr<JsonValue>& jsonValue) const
8936 {
8937     IF_PRESENT(oneStepDragController_, FillJsonValue(jsonValue));
8938 }
8939 
8940 std::string RichEditorPattern::GetPlaceHolderInJson() const
8941 {
8942     auto host = GetHost();
8943     CHECK_NULL_RETURN(host, "");
8944     auto layoutProperty = host->GetLayoutProperty<TextLayoutProperty>();
8945     bool hasPlaceHolder = layoutProperty && layoutProperty->HasPlaceholder()
8946         && !layoutProperty->GetPlaceholder().value().empty();
8947     CHECK_NULL_RETURN(hasPlaceHolder, "");
8948     auto jsonValue = JsonUtil::Create(true);
8949     jsonValue->Put("value", layoutProperty->GetPlaceholderValue("").c_str());
8950     auto jsonFont = JsonUtil::Create(true);
8951     jsonFont->Put("size", GetFontSizeInJson(layoutProperty->GetPlaceholderFontSize()).c_str());
8952     jsonFont->Put("weight", GetFontWeightInJson(layoutProperty->GetPlaceholderFontWeight()).c_str());
8953     jsonFont->Put("family", GetFontFamilyInJson(layoutProperty->GetPlaceholderFontFamily()).c_str());
8954     jsonFont->Put("style", GetFontStyleInJson(layoutProperty->GetPlaceholderItalicFontStyle()).c_str());
8955     auto jsonStyle = JsonUtil::Create(true);
8956     jsonStyle->Put("font", jsonFont->ToString().c_str());
8957     jsonStyle->Put("fontColor", GetTextColorInJson(layoutProperty->GetPlaceholderTextColor()).c_str());
8958     jsonValue->Put("style", jsonStyle->ToString().c_str());
8959     return StringUtils::RestoreBackslash(jsonValue->ToString());
8960 }
8961 
8962 std::string RichEditorPattern::GetTextColorInJson(const std::optional<Color>& value) const
8963 {
8964     CHECK_NULL_RETURN(!value, value->ColorToString());
8965     auto host = GetHost();
8966     CHECK_NULL_RETURN(host, "");
8967     auto pipeline = host->GetContext();
8968     CHECK_NULL_RETURN(pipeline, "");
8969     auto richEditorTheme = pipeline->GetTheme<RichEditorTheme>();
8970     CHECK_NULL_RETURN(richEditorTheme, "");
8971     Color textColor = richEditorTheme->GetTextStyle().GetTextColor();
8972     return textColor.ColorToString();
8973 }
8974 
8975 void RichEditorPattern::GetCaretMetrics(CaretMetricsF& caretCaretMetric)
8976 {
8977     float caretHeight = 0.0f;
8978     OffsetF caretOffset = CalcCursorOffsetByPosition(caretPosition_, caretHeight);
8979     auto host = GetHost();
8980     CHECK_NULL_VOID(host);
8981     auto offset = host->GetPaintRectOffsetNG(false, true);
8982     caretOffset += offset;
8983     caretCaretMetric.offset = caretOffset;
8984     caretCaretMetric.height = caretHeight;
8985 }
8986 
8987 void RichEditorPattern::OnVirtualKeyboardAreaChanged()
8988 {
8989     CHECK_NULL_VOID(SelectOverlayIsOn() && !selectOverlay_->GetIsHandleMoving());
8990     float selectLineHeight = 0.0f;
8991     textSelector_.selectionBaseOffset.SetX(
8992         CalcCursorOffsetByPosition(textSelector_.GetStart(), selectLineHeight).GetX());
8993     textSelector_.selectionDestinationOffset.SetX(
8994         CalcCursorOffsetByPosition(textSelector_.GetEnd(), selectLineHeight).GetX());
8995     CreateHandles();
8996 }
8997 
8998 void RichEditorPattern::ResetDragOption()
8999 {
9000     auto gestureEventHub = GetGestureEventHub();
9001     CHECK_NULL_VOID(gestureEventHub);
9002     if (gestureEventHub->GetIsTextDraggable()) {
9003         CloseSelectOverlay();
9004         ResetSelection();
9005     }
9006 }
9007 
9008 void RichEditorPattern::AdjustSelectRects(SelectRectsType pos, std::vector<RectF>& selectRects)
9009 {
9010     if (pos == SelectRectsType::LEFT_TOP_POINT) {
9011         selectRects.erase(std::next(selectRects.begin()), selectRects.end());
9012         selectRects.front().SetSize({0, 0});
9013     } else if (pos == SelectRectsType::RIGHT_BOTTOM_POINT) {
9014         selectRects.erase(selectRects.begin(), std::prev(selectRects.end()));
9015         selectRects.front().SetRect({selectRects.front().Right(), selectRects.front().Bottom()}, {0, 0});
9016     }
9017 }
9018 
9019 RectF RichEditorPattern::GetSelectArea(SelectRectsType pos)
9020 {
9021     RectF rect;
9022     auto paintOffset = selectOverlay_->GetPaintOffsetWithoutTransform();
9023     auto selectRects = paragraphs_.GetRects(textSelector_.GetTextStart(), textSelector_.GetTextEnd());
9024     auto contentRect = contentRect_;
9025     contentRect.SetOffset(contentRect.GetOffset() + paintOffset);
9026     auto host = GetHost();
9027     CHECK_NULL_RETURN(host, rect);
9028     auto parent = host->GetAncestorNodeOfFrame(false);
9029     contentRect = GetVisibleContentRect(parent, contentRect);
9030     if (selectRects.empty()) {
9031         CHECK_NULL_RETURN(overlayMod_, rect);
9032         auto richEditorOverlay = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
9033         CHECK_NULL_RETURN(richEditorOverlay, rect);
9034         auto caretHeight = richEditorOverlay->GetCaretHeight();
9035         auto caretOffset = richEditorOverlay->GetCaretOffset();
9036         if (isShowPlaceholder_) {
9037             auto [offset, preferredHeight] = CalculateEmptyValueCaretRect();
9038             caretOffset = offset;
9039         }
9040         auto caretWidth = Dimension(1.5f, DimensionUnit::VP).ConvertToPx();
9041         auto selectRect = RectF(caretOffset + paintOffset, SizeF(caretWidth, caretHeight));
9042         return selectRect.IntersectRectT(contentRect);
9043     }
9044     AdjustSelectRects(pos, selectRects);
9045     auto frontRect = selectRects.front();
9046     auto backRect = selectRects.back();
9047     RectF res;
9048     if (GreatNotEqual(backRect.Bottom(), frontRect.Bottom())) {
9049         res.SetRect(contentRect_.GetX() + paintOffset.GetX(),
9050             frontRect.GetY() + richTextRect_.GetY() + paintOffset.GetY(), contentRect_.Width(),
9051             backRect.Bottom() - frontRect.Top());
9052     } else {
9053         res.SetRect(frontRect.GetX() + richTextRect_.GetX() + paintOffset.GetX(),
9054             frontRect.GetY() + richTextRect_.GetY() + paintOffset.GetY(), backRect.Right() - frontRect.Left(),
9055             backRect.Bottom() - frontRect.Top());
9056     }
9057     return res.IntersectRectT(contentRect);
9058 }
9059 
9060 bool RichEditorPattern::IsTouchInFrameArea(const PointF& touchPoint)
9061 {
9062     auto host = GetHost();
9063     CHECK_NULL_RETURN(host, false);
9064     auto viewPort = RectF(parentGlobalOffset_, frameRect_.GetSize());
9065     auto parent = host->GetAncestorNodeOfFrame(false);
9066     viewPort = GetVisibleContentRect(parent, viewPort);
9067     return viewPort.IsInRegion(touchPoint);
9068 }
9069 
9070 bool RichEditorPattern::SetPlaceholder(std::vector<std::list<RefPtr<SpanItem>>>& spanItemList)
9071 {
9072     if (!spans_.empty()) {
9073         isShowPlaceholder_ = false;
9074         return false;
9075     }
9076     auto host = GetHost();
9077     CHECK_NULL_RETURN(host, false);
9078     auto layoutProperty = host->GetLayoutProperty<TextLayoutProperty>();
9079     CHECK_NULL_RETURN(layoutProperty, false);
9080     if (!layoutProperty->HasPlaceholder() || layoutProperty->GetPlaceholder().value().empty()) {
9081         isShowPlaceholder_ = false;
9082         return false;
9083     }
9084     auto placeholderValue = layoutProperty->GetPlaceholder().value();
9085     auto* stack = ViewStackProcessor::GetInstance();
9086     CHECK_NULL_RETURN(stack, false);
9087     auto nodeId = stack->ClaimNodeId();
9088     auto placeholderNode = SpanNode::GetOrCreateSpanNode(nodeId);
9089     CHECK_NULL_RETURN(placeholderNode, false);
9090     if (layoutProperty->HasPlaceholderFontSize()) {
9091         placeholderNode->UpdateFontSize(layoutProperty->GetPlaceholderFontSize().value());
9092     }
9093     if (layoutProperty->HasPlaceholderFontWeight()) {
9094         placeholderNode->UpdateFontWeight(layoutProperty->GetPlaceholderFontWeight().value());
9095     }
9096     if (layoutProperty->HasPlaceholderFontFamily()) {
9097         placeholderNode->UpdateFontFamily(layoutProperty->GetPlaceholderFontFamily().value());
9098     }
9099     if (layoutProperty->HasPlaceholderItalicFontStyle()) {
9100         placeholderNode->UpdateItalicFontStyle(layoutProperty->GetPlaceholderItalicFontStyle().value());
9101     }
9102     if (layoutProperty->HasPlaceholderTextColor()) {
9103         placeholderNode->UpdateTextColor(layoutProperty->GetPlaceholderTextColor().value());
9104     } else {
9105         auto theme = GetTheme<RichEditorTheme>();
9106         placeholderNode->UpdateTextColor(theme ? theme->GetPlaceholderColor() : Color());
9107     }
9108 
9109     auto spanItem = placeholderNode->GetSpanItem();
9110     CHECK_NULL_RETURN(spanItem, false);
9111     spanItem->content = placeholderValue;
9112     spanItemList.clear();
9113     spanItemList.push_back({ { {spanItem} } });
9114     isShowPlaceholder_ = true;
9115     return true;
9116 }
9117 
9118 std::string RichEditorPattern::GetPlaceHolder() const
9119 {
9120     auto host = GetHost();
9121     CHECK_NULL_RETURN(host, "");
9122     auto layoutProperty = host->GetLayoutProperty<TextLayoutProperty>();
9123     CHECK_NULL_RETURN(layoutProperty, "");
9124     return layoutProperty->GetPlaceholderValue("");
9125 }
9126 
9127 Color RichEditorPattern::GetCaretColor()
9128 {
9129     if (caretColor_.has_value()) {
9130         return caretColor_.value();
9131     }
9132     auto host = GetHost();
9133     CHECK_NULL_RETURN(host, SYSTEM_CARET_COLOR);
9134     auto pipeline = host->GetContext();
9135     CHECK_NULL_RETURN(pipeline, SYSTEM_CARET_COLOR);
9136     auto richEditorTheme = pipeline->GetTheme<RichEditorTheme>();
9137     CHECK_NULL_RETURN(richEditorTheme, SYSTEM_CARET_COLOR);
9138     return richEditorTheme->GetCaretColor();
9139 }
9140 
9141 Color RichEditorPattern::GetSelectedBackgroundColor()
9142 {
9143     Color selectedBackgroundColor;
9144     if (selectedBackgroundColor_.has_value()) {
9145         selectedBackgroundColor = selectedBackgroundColor_.value();
9146     } else {
9147         auto host = GetHost();
9148         CHECK_NULL_RETURN(host, SYSTEM_SELECT_BACKGROUND_COLOR);
9149         auto pipeline = host->GetContext();
9150         CHECK_NULL_RETURN(pipeline, SYSTEM_SELECT_BACKGROUND_COLOR);
9151         auto richEditorTheme = pipeline->GetTheme<RichEditorTheme>();
9152         CHECK_NULL_RETURN(richEditorTheme, SYSTEM_SELECT_BACKGROUND_COLOR);
9153         selectedBackgroundColor = richEditorTheme->GetSelectedBackgroundColor();
9154     }
9155     // Alpha == 255 Means completely opaque
9156     if (selectedBackgroundColor.GetAlpha() == COLOR_OPAQUE) {
9157         selectedBackgroundColor = selectedBackgroundColor.ChangeOpacity(DEFAILT_OPACITY);
9158     }
9159     return selectedBackgroundColor;
9160 }
9161 
9162 void RichEditorPattern::HandleOnDragDropStyledString(const RefPtr<OHOS::Ace::DragEvent>& event)
9163 {
9164     CHECK_NULL_VOID(event);
9165     auto data = event->GetData();
9166     CHECK_NULL_VOID(data);
9167     auto arr = UdmfClient::GetInstance()->GetSpanStringRecord(data);
9168     if (!arr.empty()) {
9169         auto spanStr = SpanString::DecodeTlv(arr);
9170         if (!spanStr->GetSpanItems().empty()) {
9171             if (isSpanStringMode_) {
9172                 HandleOnDragInsertStyledString(spanStr);
9173                 return;
9174             }
9175             AddSpanByPasteData(spanStr);
9176             return;
9177         }
9178     }
9179 
9180     auto records = UdmfClient::GetInstance()->GetPlainTextRecords(data);
9181     if (records.empty()) {
9182         return;
9183     }
9184     std::string str;
9185     for (const auto& record : records) {
9186         str += record;
9187     }
9188     if (str.empty()) {
9189         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "text is empty.");
9190         return;
9191     }
9192     if (isSpanStringMode_) {
9193         InsertValueInStyledString(str);
9194     } else {
9195         HandleOnDragDropTextOperation(str, isDragSponsor_);
9196     }
9197 }
9198 
9199 void RichEditorPattern::HandleOnDragDrop(const RefPtr<OHOS::Ace::DragEvent>& event)
9200 {
9201     auto host = GetHost();
9202     CHECK_NULL_VOID(host);
9203     auto eventHub = host->GetEventHub<RichEditorEventHub>();
9204     CHECK_NULL_VOID(eventHub);
9205     TextCommonEvent textCommonEvent;
9206     if (textCommonEvent.IsPreventDefault()) {
9207         CloseSelectOverlay();
9208         ResetSelection();
9209         StartTwinkling();
9210         return;
9211     }
9212     HandleOnDragDropStyledString(event);
9213     if (textSelector_.IsValid()) {
9214         CloseSelectOverlay();
9215         ResetSelection();
9216     }
9217     auto focusHub = GetHost()->GetOrCreateFocusHub();
9218     CHECK_NULL_VOID(focusHub);
9219     if (focusHub->IsCurrentFocus()) {
9220         StartTwinkling();
9221     }
9222 }
9223 
9224 void RichEditorPattern::DeleteForward(int32_t currentPosition, int32_t length)
9225 {
9226     RichEditorDeleteValue info;
9227     info.SetOffset(currentPosition);
9228     info.SetRichEditorDeleteDirection(RichEditorDeleteDirection::FORWARD);
9229     info.SetLength(length);
9230     CalcDeleteValueObj(currentPosition, length, info);
9231     DeleteByDeleteValueInfo(info);
9232 }
9233 
9234 int32_t RichEditorPattern::HandleOnDragDeleteForward()
9235 {
9236     int32_t allDelLength = 0;
9237     SelectionInfo textSelectInfo = GetSpansInfo(dragRange_.first, dragRange_.second, GetSpansMethod::ONSELECT);
9238     std::list<ResultObject> dragResultObjects = textSelectInfo.GetSelection().resultObjects;
9239     for (auto ri = dragResultObjects.rbegin(); ri != dragResultObjects.rend(); ++ri) {
9240         if (SelectSpanType::TYPESPAN == ri->type || (SelectSpanType::TYPEIMAGE == ri->type && ri->valueString != " ")) {
9241             int32_t spanStart = ri->offsetInSpan[RichEditorSpanRange::RANGESTART];
9242             int32_t spanEnd = ri->offsetInSpan[RichEditorSpanRange::RANGEEND];
9243             int32_t reStart = ri->spanPosition.spanRange[RichEditorSpanRange::RANGESTART];
9244             int32_t delStart = reStart;
9245             if (spanStart > 0) {
9246                 delStart += spanStart;
9247             }
9248             int32_t delLength = spanEnd - spanStart;
9249             DeleteForward(delStart, delLength);
9250             allDelLength += delLength;
9251         }
9252     }
9253     return allDelLength;
9254 }
9255 
9256 void RichEditorPattern::HandleOnDragDropTextOperation(const std::string& insertValue, bool isDeleteSelect)
9257 {
9258     if (!isDeleteSelect) {
9259         InsertValueByOperationType(insertValue, OperationType::DRAG);
9260         return;
9261     }
9262     int32_t currentPosition = caretPosition_;
9263     int32_t strLength = static_cast<int32_t>(StringUtils::ToWstring(insertValue).length());
9264     OperationRecord record;
9265     record.addText = insertValue;
9266     record.beforeCaretPosition = dragRange_.first;
9267     RichEditorChangeValue changeValue;
9268     CHECK_NULL_VOID(BeforeChangeText(changeValue, record, RecordType::DRAG));
9269     if (currentPosition < dragRange_.first) {
9270         InsertValueByOperationType(insertValue, OperationType::DRAG);
9271         dragRange_.first += strLength;
9272         dragRange_.second += strLength;
9273         HandleOnDragDeleteForward();
9274     } else if (currentPosition > dragRange_.second) {
9275         InsertValueByOperationType(insertValue, OperationType::DRAG);
9276         int32_t delLength = HandleOnDragDeleteForward();
9277         caretPosition_ -= delLength;
9278     }
9279 
9280     AfterContentChange(changeValue);
9281 }
9282 
9283 void RichEditorPattern::UndoDrag(const OperationRecord& record)
9284 {
9285     if (!record.addText.has_value() || record.deleteCaretPostion == -1) {
9286         return;
9287     }
9288     const std::string& str = record.addText.value();
9289     int32_t length = static_cast<int32_t>(StringUtils::ToWstring(str).length());
9290     DeleteForward(record.beforeCaretPosition, length);
9291 
9292     caretPosition_ = record.deleteCaretPostion;
9293     InsertValueOperation(str, nullptr, OperationType::DEFAULT);
9294 }
9295 
9296 void RichEditorPattern::RedoDrag(const OperationRecord& record)
9297 {
9298     if (!record.addText.has_value() || record.deleteCaretPostion == -1) {
9299         return;
9300     }
9301     RichEditorChangeValue changeValue;
9302     CHECK_NULL_VOID(BeforeChangeText(changeValue, record, RecordType::REDO));
9303     const std::string& str = record.addText.value();
9304     int32_t length = static_cast<int32_t>(StringUtils::ToWstring(str).length());
9305     DeleteForward(record.deleteCaretPostion, length);
9306     caretPosition_ = record.beforeCaretPosition;
9307     InsertValueOperation(str, nullptr, OperationType::DRAG);
9308     AfterContentChange(changeValue);
9309 }
9310 
9311 void RichEditorPattern::HandleOnDragInsertValueOperation(const std::string& insertValue)
9312 {
9313     InsertValueByOperationType(insertValue, OperationType::DRAG);
9314 }
9315 
9316 void RichEditorPattern::HandleOnDragInsertValue(const std::string& insertValue)
9317 {
9318     OperationRecord record;
9319     record.beforeCaretPosition = caretPosition_ + moveLength_;
9320     if (textSelector_.IsValid()) {
9321         record.beforeCaretPosition = textSelector_.GetTextStart();
9322     }
9323     record.addText = insertValue;
9324     ClearRedoOperationRecords();
9325     InsertValueByOperationType(insertValue, OperationType::DRAG);
9326     int32_t length = dragRange_.second - dragRange_.first;
9327     record.afterCaretPosition = record.beforeCaretPosition + length;
9328     record.deleteCaretPostion = dragRange_.first;
9329     AddOperationRecord(record);
9330 }
9331 
9332 bool RichEditorPattern::IsEditing()
9333 {
9334     return isEditing_;
9335 }
9336 
9337 void RichEditorPattern::HandleOnEditChanged(bool isEditing)
9338 {
9339     if (isEditing_ == isEditing) {
9340         return;
9341     }
9342     auto host = GetHost();
9343     CHECK_NULL_VOID(host);
9344     auto eventHub = host->GetEventHub<RichEditorEventHub>();
9345     CHECK_NULL_VOID(eventHub);
9346     isEditing_ = isEditing;
9347     eventHub->FireOnEditingChange(isEditing);
9348     if (CanStartAITask()) {
9349         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "leave edit state, start AI task");
9350         dataDetectorAdapter_->StartAITask();
9351     } else {
9352         if (isEditing) {
9353             TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "enter edit state, reset previewLongPress_");
9354             previewLongPress_ = false;
9355         }
9356         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
9357     }
9358 }
9359 
9360 void RichEditorPattern::ResetKeyboardIfNeed()
9361 {
9362     bool needToResetKeyboard = false;
9363     auto currentAction = GetTextInputActionValue(GetDefaultTextInputAction());
9364     // When the enter key type changes, the keyboard needs to be reset.
9365     if (action_ != TextInputAction::UNSPECIFIED) {
9366         needToResetKeyboard = action_ != currentAction;
9367     }
9368     action_ = currentAction;
9369 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
9370     if (needToResetKeyboard) {
9371         // if keyboard attached or keyboard is shown, pull up keyboard again
9372         if (imeShown_ || isCustomKeyboardAttached_) {
9373             if (HasFocus()) {
9374                 RequestKeyboard(false, true, true);
9375             }
9376             return;
9377         }
9378 #if defined(ENABLE_STANDARD_INPUT)
9379         auto inputMethod = MiscServices::InputMethodController::GetInstance();
9380         CHECK_NULL_VOID(inputMethod);
9381         MiscServices::Configuration config;
9382         config.SetEnterKeyType(static_cast<MiscServices::EnterKeyType>(action_));
9383         config.SetTextInputType(static_cast<MiscServices::TextInputType>(keyboard_));
9384         inputMethod->OnConfigurationChange(config);
9385 #endif
9386     }
9387 #else
9388     if (needToResetKeyboard && HasConnection()) {
9389         CloseKeyboard(false);
9390         RequestKeyboard(false, true, true);
9391     }
9392 #endif
9393 }
9394 
9395 void RichEditorPattern::OnTextInputActionUpdate(TextInputAction value) {}
9396 
9397 void RichEditorPattern::PerformAction(TextInputAction action, bool forceCloseKeyboard)
9398 {
9399     auto host = GetHost();
9400     CHECK_NULL_VOID(host);
9401     // When the Enter key is triggered, perform a line feed operation.
9402     if (action == TextInputAction::NEW_LINE) {
9403         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "action=%{public}d, forceCloseKeyboard=%{public}d", action,
9404             forceCloseKeyboard);
9405         InsertValue("\n", true);
9406     }
9407     // Enter key type callback
9408     TextFieldCommonEvent event;
9409     auto eventHub = host->GetEventHub<RichEditorEventHub>();
9410     eventHub->FireOnSubmit(static_cast<int32_t>(action), event);
9411     // If the developer wants to keep editing, editing will not stop
9412     if (event.IsKeepEditable() || action == TextInputAction::NEW_LINE) {
9413         return;
9414     }
9415     // Exit the editing state
9416     StopEditing();
9417 }
9418 
9419 void RichEditorPattern::StopEditing()
9420 {
9421     CHECK_NULL_VOID(HasFocus());
9422     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "StopEditing");
9423 
9424     // The selection status disappears, the cursor is hidden, and the soft keyboard is exited
9425     HandleBlurEvent();
9426     // In order to avoid the physical keyboard being able to type, you need to make sure that you lose focus
9427     FocusHub::LostFocusToViewRoot();
9428 }
9429 
9430 TextInputAction RichEditorPattern::GetDefaultTextInputAction() const
9431 {
9432     // As with TextInput, it is a line break by default
9433     return TextInputAction::NEW_LINE;
9434 }
9435 
9436 void RichEditorPattern::GetChangeSpanStyle(RichEditorChangeValue& changeValue, std::optional<TextStyle>& spanTextStyle,
9437     std::optional<struct UpdateParagraphStyle>& spanParaStyle, const RefPtr<SpanNode>& spanNode, int32_t spanIndex)
9438 {
9439     auto originalSpans = changeValue.GetRichEditorOriginalSpans();
9440     if (spanIndex == 0 && originalSpans.size()) {
9441         const RichEditorAbstractSpanResult& firstInfo = originalSpans.front();
9442         const RichEditorAbstractSpanResult& lastInfo = originalSpans.back();
9443         int32_t firstLength = static_cast<int32_t>(StringUtils::ToWstring(firstInfo.GetValue()).length());
9444         int32_t lastLength = static_cast<int32_t>(StringUtils::ToWstring(lastInfo.GetValue()).length());
9445         if (firstInfo.GetEraseLength() == firstLength && lastInfo.GetEraseLength() == lastLength) {
9446             if (spans_.size() == originalSpans.size() ||
9447                 static_cast<int32_t>(spans_.size()) == (lastInfo.GetSpanIndex() + 1)) {
9448                 return; // all spanNode be deleted, set default style
9449             }
9450             spanIndex = lastInfo.GetSpanIndex() + 1;
9451         } else if (firstInfo.GetEraseLength() == firstLength) {
9452             spanIndex = lastInfo.GetSpanIndex();
9453         }
9454         auto it = spans_.begin();
9455         std::advance(it, spanIndex);
9456         if ((*it)->unicode != 0 || DynamicCast<PlaceholderSpanItem>(*it)) {
9457             return; // is not a textSpan(Image/Symbol/other)
9458         }
9459         spanTextStyle = (*it)->GetTextStyle();
9460         struct UpdateParagraphStyle paraStyle;
9461         paraStyle.textAlign = (*it)->textLineStyle->GetTextAlign();
9462         paraStyle.leadingMargin = (*it)->textLineStyle->GetLeadingMargin();
9463         paraStyle.wordBreak = (*it)->textLineStyle->GetWordBreak();
9464         paraStyle.lineBreakStrategy = (*it)->textLineStyle->GetLineBreakStrategy();
9465         spanParaStyle = paraStyle;
9466     } else if (spanNode && spanNode->GetSpanItem()) {
9467         spanTextStyle = spanNode->GetSpanItem()->GetTextStyle();
9468         struct UpdateParagraphStyle paraStyle;
9469         paraStyle.textAlign = spanNode->GetTextAlign();
9470         paraStyle.leadingMargin = spanNode->GetLeadingMarginValue({});
9471         paraStyle.wordBreak = spanNode->GetWordBreak();
9472         paraStyle.lineBreakStrategy = spanNode->GetLineBreakStrategy();
9473         spanParaStyle = paraStyle;
9474     }
9475 }
9476 
9477 void RichEditorPattern::GetReplacedSpan(RichEditorChangeValue& changeValue, int32_t& innerPosition,
9478     const std::string& insertValue, int32_t textIndex, std::optional<TextStyle> textStyle,
9479     std::optional<struct UpdateParagraphStyle> paraStyle, bool isCreate, bool fixDel)
9480 {
9481     std::string originalStr;
9482     int32_t originalPos = 0;
9483     RefPtr<SpanItem> spanItem = fixDel ? GetDelPartiallySpanItem(changeValue, originalStr, originalPos) : nullptr;
9484 
9485     TextInsertValueInfo info;
9486     CalcInsertValueObj(info, textIndex, isCreate);
9487     int32_t spanIndex = info.GetSpanIndex();
9488     int32_t offsetInSpan = info.GetOffsetInSpan();
9489     auto host = GetHost();
9490     CHECK_NULL_VOID(host);
9491     auto uiNode = host->GetChildAtIndex(spanIndex);
9492     RefPtr<SpanNode> spanNode = DynamicCast<SpanNode>(uiNode);
9493     if (!isCreate && textIndex && uiNode && uiNode->GetTag() != V2::SPAN_ETS_TAG) {
9494         spanNode = nullptr;
9495         ++spanIndex; // select/create a new span When the span is not a textSpan(Image/Symbol/other)
9496         offsetInSpan = 0;
9497         spanNode = DynamicCast<SpanNode>(host->GetChildAtIndex(spanIndex));
9498     }
9499 
9500     auto wInsertValue = StringUtils::ToWstring(insertValue);
9501     changeValue.SetRangeAfter({ innerPosition, innerPosition + wInsertValue.length()});
9502     std::wstring textTemp = wInsertValue;
9503     if (!textStyle && !isCreate && spanNode) {
9504         if (typingStyle_ && !HasSameTypingStyle(spanNode)) {
9505             textStyle = typingTextStyle_; // create a new span When have a different typingStyle
9506             bool insertInSpan = textIndex && offsetInSpan;
9507             spanIndex = insertInSpan ? spanIndex + 1 : spanIndex;
9508             offsetInSpan = 0;
9509         } else {
9510             textTemp = StringUtils::ToWstring(spanNode->GetSpanItem()->content);
9511             textTemp.insert(offsetInSpan, wInsertValue);
9512         }
9513     }
9514 
9515     auto it = textTemp.find(lineSeparator);
9516     bool containNextLine = it != std::wstring::npos;
9517     auto content = StringUtils::ToString(textTemp);
9518 
9519     if (textStyle || containNextLine) { // SpanNode Fission
9520         GetReplacedSpanFission(changeValue, innerPosition, content, spanIndex, offsetInSpan, textStyle, paraStyle);
9521     } else {
9522         std::optional<TextStyle> spanTextStyle = textStyle ? textStyle : typingTextStyle_;
9523         std::optional<struct UpdateParagraphStyle> spanParaStyle = paraStyle;
9524         GetChangeSpanStyle(changeValue, spanTextStyle, spanParaStyle, spanNode, spanIndex);
9525         CreateSpanResult(changeValue, innerPosition, spanIndex, offsetInSpan, offsetInSpan + wInsertValue.length(),
9526             content, spanTextStyle, spanParaStyle);
9527         innerPosition += wInsertValue.length();
9528     }
9529 
9530     if (spanItem) {
9531         spanItem->content = originalStr;
9532         spanItem->position = originalPos;
9533     }
9534 }
9535 
9536 void RichEditorPattern::GetReplacedSpanFission(RichEditorChangeValue& changeValue, int32_t& innerPosition,
9537     std::string& content, int32_t startSpanIndex, int32_t offsetInSpan, std::optional<TextStyle> textStyle,
9538     std::optional<struct UpdateParagraphStyle> paraStyle)
9539 {
9540     std::vector<RichEditorAbstractSpanResult> ret;
9541     int spanIndex = startSpanIndex;
9542     auto wContent = StringUtils::ToWstring(content);
9543 
9544     auto index = wContent.find(lineSeparator);
9545     while (index != std::wstring::npos) {
9546         auto textAfter = wContent.substr(index + 1);
9547         if (textAfter.empty()) {
9548             break;
9549         }
9550         auto textBefore = wContent.substr(0, index + 1);
9551         if (offsetInSpan != static_cast<int32_t>(textBefore.length())) {
9552             CreateSpanResult(changeValue, innerPosition, spanIndex, offsetInSpan, textBefore.length(),
9553                 StringUtils::ToString(textBefore), textStyle, paraStyle);
9554             innerPosition += textBefore.length() - offsetInSpan;
9555         }
9556         wContent = textAfter;
9557         index = wContent.find(lineSeparator);
9558         offsetInSpan = 0;
9559         ++spanIndex;
9560     }
9561     CreateSpanResult(changeValue, innerPosition, spanIndex, offsetInSpan, wContent.length(),
9562         StringUtils::ToString(wContent), textStyle, paraStyle);
9563     innerPosition += wContent.length();
9564 }
9565 
9566 void RichEditorPattern::CreateSpanResult(RichEditorChangeValue& changeValue, int32_t& innerPosition, int32_t spanIndex,
9567     int32_t offsetInSpan, int32_t endInSpan, std::string content, std::optional<TextStyle> textStyle,
9568     std::optional<struct UpdateParagraphStyle> paraStyle)
9569 {
9570     RichEditorAbstractSpanResult retInfo;
9571     if (textStyle) {
9572         SetTextStyleToRet(retInfo, *textStyle);
9573     } else {
9574         retInfo.SetFontColor((Color::BLACK).ColorToString());
9575         retInfo.SetFontSize(Dimension(16.0f, DimensionUnit::VP).ConvertToVp());
9576         retInfo.SetFontStyle(OHOS::Ace::FontStyle::NORMAL);
9577         retInfo.SetFontWeight(static_cast<int32_t>(FontWeight::NORMAL));
9578         retInfo.SetTextDecoration(TextDecoration::NONE);
9579         retInfo.SetColor((Color::BLACK).ColorToString());
9580         retInfo.SetFontFamily("HarmonyOS Sans");
9581     }
9582     retInfo.SetSpanIndex(spanIndex);
9583     if (!previewTextRecord_.newPreviewContent.empty()) {
9584         retInfo.SetPreviewText(previewTextRecord_.newPreviewContent);
9585     } else {
9586         retInfo.SetValue(content);
9587     }
9588     int32_t rangStart = std::max(0, innerPosition - offsetInSpan);
9589     retInfo.SetSpanRangeStart(rangStart);
9590     retInfo.SetSpanRangeEnd(rangStart + StringUtils::ToWstring(content).length());
9591     retInfo.SetOffsetInSpan(offsetInSpan);
9592     retInfo.SetEraseLength(endInSpan - offsetInSpan);
9593     if (paraStyle) {
9594         TextStyleResult textStyleResult = retInfo.GetTextStyle();
9595         textStyleResult.textAlign = static_cast<int32_t>(paraStyle->textAlign.value_or(TextAlign::START));
9596         if (paraStyle->leadingMargin) {
9597             textStyleResult.leadingMarginSize[0] = paraStyle->leadingMargin->size.Width().ToString();
9598             textStyleResult.leadingMarginSize[1] = paraStyle->leadingMargin->size.Height().ToString();
9599         }
9600         IF_TRUE(paraStyle->wordBreak, textStyleResult.wordBreak = static_cast<int32_t>(paraStyle->wordBreak.value()));
9601         IF_TRUE(paraStyle->lineBreakStrategy,
9602             textStyleResult.lineBreakStrategy = static_cast<int32_t>(paraStyle->lineBreakStrategy.value()));
9603         retInfo.SetTextStyle(textStyleResult);
9604     }
9605     changeValue.SetRichEditorReplacedSpans(retInfo);
9606 }
9607 
9608 void RichEditorPattern::SetTextStyleToRet(RichEditorAbstractSpanResult& retInfo, const TextStyle& textStyle)
9609 {
9610     retInfo.SetTextDecoration(textStyle.GetTextDecoration());
9611     retInfo.SetFontColor(textStyle.GetTextColor().ColorToString());
9612     retInfo.SetColor(textStyle.GetTextDecorationColor().ColorToString());
9613     retInfo.SetTextDecorationStyle(textStyle.GetTextDecorationStyle());
9614     retInfo.SetFontSize(textStyle.GetFontSize().ConvertToVp());
9615     retInfo.SetFontStyle(textStyle.GetFontStyle());
9616     TextStyleResult textStyleResult;
9617     textStyleResult.lineHeight = textStyle.GetLineHeight().ConvertToVp();
9618     textStyleResult.letterSpacing = textStyle.GetLetterSpacing().ConvertToVp();
9619     textStyleResult.textShadows = textStyle.GetTextShadows();
9620     retInfo.SetTextStyle(textStyleResult);
9621     retInfo.SetLineHeight(textStyle.GetLineHeight().ConvertToVp());
9622     retInfo.SetLetterspacing(textStyle.GetLetterSpacing().ConvertToVp());
9623     retInfo.SetFontFeature(textStyle.GetFontFeatures());
9624     std::string fontFamilyValue;
9625     auto fontFamily = textStyle.GetFontFamilies();
9626     for (const auto& str : fontFamily) {
9627         fontFamilyValue += str;
9628     }
9629     retInfo.SetFontFamily(fontFamilyValue);
9630     retInfo.SetFontWeight((int32_t)textStyle.GetFontWeight());
9631 }
9632 
9633 void RichEditorPattern::CalcInsertValueObj(TextInsertValueInfo& info, int textIndex, bool isCreate)
9634 {
9635     if (spans_.empty()) {
9636         info.SetSpanIndex(0);
9637         info.SetOffsetInSpan(0);
9638         return;
9639     }
9640     auto it = std::find_if(
9641         spans_.begin(), spans_.end(), [caretPosition = textIndex](const RefPtr<SpanItem>& spanItem) {
9642             auto spanLength = static_cast<int32_t>(StringUtils::ToWstring(spanItem->content).length());
9643             if (spanLength == 0) {
9644                 return spanItem->position == caretPosition;
9645             }
9646             return (spanItem->position - spanLength <= caretPosition) && (caretPosition <= spanItem->position);
9647         });
9648     if (it == spans_.end()) {
9649         info.SetSpanIndex(static_cast<int32_t>(spans_.size()) - 1);
9650         info.SetOffsetInSpan(StringUtils::ToWstring((*spans_.rbegin())->content).length());
9651         return;
9652     }
9653     if (textIndex && isCreate) {
9654         info.SetSpanIndex(std::distance(spans_.begin(), it) + 1);
9655         info.SetOffsetInSpan(0);
9656         return;
9657     }
9658     if ((*it)->content.back() == '\n' && (*it)->position == textIndex) { // next line/span begin
9659         info.SetSpanIndex(std::distance(spans_.begin(), it) + 1);
9660         info.SetOffsetInSpan(0);
9661     } else {
9662         info.SetSpanIndex(std::distance(spans_.begin(), it));
9663         int32_t spanStart = (*it)->position - StringUtils::ToWstring((*it)->content).length();
9664         info.SetOffsetInSpan(textIndex - spanStart);
9665     }
9666 }
9667 
9668 void RichEditorPattern::GetDeletedSpan(RichEditorChangeValue& changeValue, int32_t& innerPosition,
9669     int32_t length, RichEditorDeleteDirection direction, bool isResetSelection)
9670 {
9671     RichEditorDeleteValue info;
9672     if (!textSelector_.SelectNothing()) {
9673         length = textSelector_.GetTextEnd() - textSelector_.GetTextStart();
9674         innerPosition = std::min(textSelector_.GetStart(), textSelector_.GetEnd());
9675     } else if (!previewTextRecord_.previewContent.empty()) {
9676         length = previewTextRecord_.replacedRange.end - previewTextRecord_.replacedRange.start;
9677         innerPosition = previewTextRecord_.replacedRange.start;
9678     } else {
9679         int32_t emojiLength = CalculateDeleteLength(length, (direction == RichEditorDeleteDirection::BACKWARD));
9680         if (isResetSelection) {
9681             CloseSelectOverlay();
9682             ResetSelection();
9683         }
9684         if (direction == RichEditorDeleteDirection::BACKWARD) {
9685             innerPosition -= emojiLength;
9686         }
9687         if (length < emojiLength) {
9688             length = emojiLength;
9689         }
9690     }
9691 
9692     info.SetOffset(innerPosition);
9693     info.SetRichEditorDeleteDirection(direction);
9694     info.SetLength(length);
9695     if (!spans_.empty()) {
9696         CalcDeleteValueObj(innerPosition, length, info);
9697     }
9698     if (!spans_.empty() || isAPI14Plus) {
9699         changeValue.SetRangeBefore({ innerPosition, innerPosition + length });
9700         changeValue.SetRangeAfter({ innerPosition, innerPosition });
9701     }
9702     const std::list<RichEditorAbstractSpanResult>& resultList = info.GetRichEditorDeleteSpans();
9703     for (auto& it : resultList) {
9704         if (it.GetType() == SpanResultType::TEXT) {
9705             changeValue.SetRichEditorOriginalSpans(it);
9706         } else if (it.GetType() == SpanResultType::SYMBOL && textSelector_.SelectNothing() &&
9707             previewTextRecord_.previewContent.empty()) {
9708             int32_t symbolStart = it.GetSpanRangeStart();
9709             changeValue.SetRichEditorOriginalSpans(it);
9710             changeValue.SetRangeBefore({ symbolStart, symbolStart + SYMBOL_SPAN_LENGTH });
9711             changeValue.SetRangeAfter({ symbolStart, symbolStart });
9712         }
9713     }
9714 }
9715 
9716 RefPtr<SpanItem> RichEditorPattern::GetDelPartiallySpanItem(
9717     RichEditorChangeValue& changeValue, std::string& originalStr, int32_t& originalPos)
9718 {
9719     RefPtr<SpanItem> retItem = nullptr;
9720     if (changeValue.GetRichEditorOriginalSpans().size() == 0) {
9721         return retItem;
9722     }
9723     std::wstring textTemp;
9724     auto originalSpans = changeValue.GetRichEditorOriginalSpans();
9725     const RichEditorAbstractSpanResult& firstResult = originalSpans.front();
9726     auto it = spans_.begin();
9727     std::advance(it, firstResult.GetSpanIndex());
9728     retItem = *it;
9729     originalStr = retItem->content;
9730     originalPos = retItem->position;
9731     textTemp = StringUtils::ToWstring(originalStr).erase(firstResult.OffsetInSpan(), firstResult.GetEraseLength());
9732     retItem->content = StringUtils::ToString(textTemp);
9733     retItem->position -= firstResult.GetEraseLength();
9734     if (firstResult.GetEraseLength() != static_cast<int32_t>(StringUtils::ToWstring(firstResult.GetValue()).length())) {
9735         return retItem;
9736     }
9737 
9738     if (firstResult.GetSpanIndex() == 0) {
9739         int32_t spanIndex = 0;
9740         for (auto& orgIt : originalSpans) {
9741             spanIndex = orgIt.GetSpanIndex();
9742             if (orgIt.GetEraseLength() != static_cast<int32_t>(StringUtils::ToWstring(orgIt.GetValue()).length())) {
9743                 // find the deleted(Partially) spanItem
9744                 auto findIt = spans_.begin();
9745                 std::advance(findIt, spanIndex);
9746                 textTemp = StringUtils::ToWstring((*findIt)->content);
9747                 textTemp.erase(orgIt.OffsetInSpan(), orgIt.GetEraseLength());
9748                 retItem->content = StringUtils::ToString(textTemp);
9749                 retItem->position = textTemp.length();
9750                 return retItem;
9751             }
9752         }
9753         if (spans_.size() == originalSpans.size() || static_cast<int32_t>(spans_.size()) == (spanIndex + 1)) {
9754             return retItem; // all spanNode be deleted
9755         }
9756         auto nextIt = spans_.begin();
9757         std::advance(nextIt, spanIndex + 1);
9758         if ((*nextIt)->unicode != 0 || DynamicCast<PlaceholderSpanItem>(*nextIt)) {
9759             return retItem; // is not a textSpan(Image/Symbol/other)
9760         }
9761         retItem->content = (*nextIt)->content;
9762         retItem->position = StringUtils::ToWstring(retItem->content).length();
9763     }
9764     return retItem;
9765 }
9766 
9767 bool RichEditorPattern::BeforeChangeText(RichEditorChangeValue& changeValue, const TextSpanOptions& options)
9768 {
9769     auto eventHub = GetEventHub<RichEditorEventHub>();
9770     CHECK_NULL_RETURN(eventHub, false);
9771     if (!eventHub->HasOnWillChange() && !eventHub->HasOnDidChange()) {
9772         return true;
9773     }
9774     int32_t innerPosition = caretPosition_;
9775 
9776    // AddTextSpan
9777     std::optional<TextStyle> textStyle = std::nullopt;
9778     if (options.style.has_value()) {
9779         textStyle = options.style;
9780     }
9781     if (options.offset.has_value()) {
9782         if (spans_.empty() || options.offset.value() < 0) {
9783             innerPosition = 0;
9784         } else if (options.offset.value() > GetTextContentLength()) {
9785             innerPosition = GetTextContentLength();
9786         } else {
9787             innerPosition = options.offset.value();
9788         }
9789     } else {
9790         innerPosition = GetTextContentLength();
9791     }
9792     // only add, do not delete
9793     changeValue.SetRangeBefore({ innerPosition, innerPosition });
9794     GetReplacedSpan(changeValue, innerPosition, options.value, innerPosition, textStyle, options.paraStyle, true);
9795     CHECK_NULL_RETURN(eventHub->HasOnWillChange(), true);
9796     auto ret = eventHub->FireOnWillChange(changeValue);
9797     return ret;
9798 }
9799 
9800 bool RichEditorPattern::BeforeAddImage(RichEditorChangeValue& changeValue,
9801     const ImageSpanOptions& options, int32_t insertIndex)
9802 {
9803     auto eventHub = GetEventHub<RichEditorEventHub>();
9804     CHECK_NULL_RETURN(eventHub, false);
9805     if (!eventHub->HasOnWillChange() && !eventHub->HasOnDidChange()) {
9806         return true;
9807     }
9808     changeValue.SetRangeBefore({ insertIndex, insertIndex });
9809     changeValue.SetRangeAfter({ insertIndex, insertIndex + 1 });
9810     RichEditorAbstractSpanResult retInfo;
9811     TextInsertValueInfo info;
9812     CalcInsertValueObj(info, insertIndex, true);
9813     int32_t spanIndex = info.GetSpanIndex();
9814     retInfo.SetSpanIndex(spanIndex);
9815     if (options.image) {
9816         retInfo.SetValueResourceStr(*options.image);
9817     }
9818     if (options.imagePixelMap) {
9819         retInfo.SetValuePixelMap(*options.imagePixelMap);
9820     }
9821     if (options.imageAttribute.has_value()) {
9822         auto imgAttr = options.imageAttribute.value();
9823         if (imgAttr.size.has_value()) {
9824             retInfo.SetSizeWidth(imgAttr.size->width.value_or(CalcDimension()).ConvertToPx());
9825             retInfo.SetSizeHeight(imgAttr.size->height.value_or(CalcDimension()).ConvertToPx());
9826         }
9827         if (imgAttr.verticalAlign.has_value()) {
9828             retInfo.SetVerticalAlign(imgAttr.verticalAlign.value());
9829         }
9830         if (imgAttr.objectFit.has_value()) {
9831             retInfo.SetImageFit(imgAttr.objectFit.value());
9832         }
9833         if (imgAttr.marginProp.has_value()) {
9834             retInfo.SetMargin(imgAttr.marginProp.value().ToString());
9835         }
9836         if (imgAttr.borderRadius.has_value()) {
9837             retInfo.SetBorderRadius(imgAttr.borderRadius.value().ToString());
9838         }
9839     }
9840     retInfo.SetOffsetInSpan(0);
9841     retInfo.SetEraseLength(1);
9842     retInfo.SetSpanRangeStart(insertIndex);
9843     retInfo.SetSpanRangeEnd(insertIndex + 1);
9844     retInfo.SetSpanType(SpanResultType::IMAGE);
9845     changeValue.SetRichEditorReplacedImageSpans(retInfo);
9846     CHECK_NULL_RETURN(eventHub->HasOnWillChange(), true);
9847     auto ret = eventHub->FireOnWillChange(changeValue);
9848     return ret;
9849 }
9850 
9851 void RichEditorPattern::FixMoveDownChange(RichEditorChangeValue& changeValue, int32_t delLength)
9852 {
9853     int32_t delSpanCount = 0;
9854     for (auto& it : changeValue.GetRichEditorOriginalSpans()) {
9855         if (it.GetEraseLength() == static_cast<int32_t>(StringUtils::ToWstring(it.GetValue()).length())) {
9856             ++delSpanCount;
9857         }
9858     }
9859     for (auto& it : const_cast<std::vector<RichEditorAbstractSpanResult>&>(changeValue.GetRichEditorReplacedSpans())) {
9860         if (delSpanCount) {
9861             it.SetSpanIndex(it.GetSpanIndex() - delSpanCount);
9862         }
9863     }
9864 }
9865 
9866 void RichEditorPattern::BeforeUndo(
9867     RichEditorChangeValue& changeValue, int32_t& innerPosition, const OperationRecord& record)
9868 {
9869     innerPosition = record.afterCaretPosition;
9870     if (record.addText.has_value() && record.deleteCaretPostion != -1) { // UndoDrag
9871         GetDeletedSpan(changeValue, innerPosition, StringUtils::ToWstring(record.addText.value_or("")).length(),
9872             RichEditorDeleteDirection::FORWARD);
9873         innerPosition = record.deleteCaretPostion;
9874         GetReplacedSpan(changeValue, innerPosition, record.addText.value(), innerPosition, std::nullopt, std::nullopt);
9875     } else if (record.addText.has_value() && record.deleteText.has_value()) {
9876         GetDeletedSpan(changeValue, innerPosition, StringUtils::ToWstring(record.addText.value_or("")).length(),
9877             RichEditorDeleteDirection::BACKWARD);
9878         GetReplacedSpan(
9879             changeValue, innerPosition, record.deleteText.value(), innerPosition, std::nullopt, std::nullopt);
9880     } else if (record.deleteText.has_value()) {
9881         GetReplacedSpan(
9882             changeValue, innerPosition, record.deleteText.value(), innerPosition, std::nullopt, std::nullopt);
9883     } else if (record.addText.has_value()) {
9884         GetDeletedSpan(changeValue, innerPosition, StringUtils::ToWstring(record.addText.value_or("")).length(),
9885             RichEditorDeleteDirection::BACKWARD);
9886     }
9887 }
9888 
9889 void RichEditorPattern::BeforeRedo(
9890     RichEditorChangeValue& changeValue, int32_t& innerPosition, const OperationRecord& record)
9891 {
9892     innerPosition = record.beforeCaretPosition - StringUtils::ToWstring(record.addText.value_or("")).length();
9893     if (record.addText.has_value() && record.deleteCaretPostion != -1) { // RedoDrag
9894         innerPosition = record.deleteCaretPostion;
9895         GetDeletedSpan(changeValue, innerPosition, StringUtils::ToWstring(record.addText.value_or("")).length(),
9896             RichEditorDeleteDirection::FORWARD);
9897         innerPosition = record.beforeCaretPosition;
9898         GetReplacedSpan(changeValue, innerPosition, record.addText.value(), innerPosition, std::nullopt, std::nullopt);
9899     } else if (record.addText.has_value() && record.deleteText.has_value()) {
9900         GetDeletedSpan(changeValue, innerPosition, StringUtils::ToWstring(record.deleteText.value_or("")).length(),
9901             RichEditorDeleteDirection::FORWARD);
9902         GetReplacedSpan(changeValue, innerPosition, record.addText.value(), innerPosition, std::nullopt, std::nullopt);
9903     } else if (record.deleteText.has_value()) {
9904         innerPosition = record.beforeCaretPosition - StringUtils::ToWstring(record.deleteText.value_or("")).length();
9905         GetDeletedSpan(changeValue, innerPosition, StringUtils::ToWstring(record.deleteText.value_or("")).length(),
9906             RichEditorDeleteDirection::FORWARD);
9907     } else if (record.addText.has_value()) {
9908         innerPosition = std::min(innerPosition, record.afterCaretPosition);
9909         int32_t innerAddPosition = record.afterCaretPosition - static_cast<int32_t>(record.addText.value().length());
9910         if (changeValue.GetRichEditorOriginalSpans().empty()) {
9911             innerPosition = caretPosition_;
9912             innerAddPosition = caretPosition_;
9913         }
9914         GetReplacedSpan(changeValue, innerAddPosition, record.addText.value(), innerPosition,
9915             std::nullopt, std::nullopt);
9916     }
9917 }
9918 
9919 void RichEditorPattern::BeforeDrag(
9920     RichEditorChangeValue& changeValue, int32_t& innerPosition, const OperationRecord& record)
9921 {
9922     int length = StringUtils::ToWstring(record.addText.value_or("")).length();
9923     int32_t nowPosition = innerPosition;
9924     std::optional<TextStyle> style = std::nullopt;
9925     if (typingStyle_.has_value() && typingTextStyle_.has_value()) {
9926         style = typingTextStyle_.value();
9927     }
9928     if (!isDragSponsor_) { // drag from outside
9929         GetReplacedSpan(
9930             changeValue, innerPosition, record.addText.value(), innerPosition, style, std::nullopt, true, false);
9931     } else if (nowPosition < record.beforeCaretPosition + length) { // move up
9932         innerPosition = record.beforeCaretPosition;
9933         GetDeletedSpan(changeValue, innerPosition, length, RichEditorDeleteDirection::FORWARD);
9934         innerPosition = nowPosition;
9935         GetReplacedSpan(
9936             changeValue, innerPosition, record.addText.value(), nowPosition, style, std::nullopt, true, false);
9937     } else { // move down
9938         innerPosition = record.beforeCaretPosition;
9939         GetDeletedSpan(changeValue, innerPosition, length, RichEditorDeleteDirection::FORWARD);
9940         innerPosition = nowPosition - length;
9941         GetReplacedSpan(
9942             changeValue, innerPosition, record.addText.value(), nowPosition, style, std::nullopt, true, false);
9943         FixMoveDownChange(changeValue, length);
9944     }
9945 }
9946 
9947 bool RichEditorPattern::BeforeChangeText(
9948     RichEditorChangeValue& changeValue, const OperationRecord& record, RecordType type, int32_t delLength)
9949 {
9950     int32_t innerPosition = caretPosition_;
9951     auto eventHub = GetEventHub<RichEditorEventHub>();
9952     CHECK_NULL_RETURN(eventHub, false);
9953     if (!eventHub->HasOnWillChange() && !eventHub->HasOnDidChange()) {
9954         return true;
9955     }
9956 
9957     if (RecordType::INSERT == type) {
9958         if (textSelector_.IsValid()) {
9959             GetDeletedSpan(changeValue, innerPosition,
9960                 static_cast<int32_t>(textSelector_.GetTextEnd() - textSelector_.GetTextStart()));
9961         } else if (!previewTextRecord_.previewContent.empty()) {
9962             GetDeletedSpan(changeValue, innerPosition,
9963                 static_cast<int32_t>(previewTextRecord_.replacedRange.end - previewTextRecord_.replacedRange.start));
9964         }
9965         GetReplacedSpan(changeValue, innerPosition, record.addText.value(), innerPosition, std::nullopt, std::nullopt);
9966     }
9967     if (RecordType::DEL_FORWARD == type) {
9968         innerPosition = record.beforeCaretPosition;
9969         GetDeletedSpan(changeValue, innerPosition, delLength, RichEditorDeleteDirection::FORWARD, false);
9970     }
9971     if (RecordType::DEL_BACKWARD == type) {
9972         innerPosition = record.beforeCaretPosition;
9973         GetDeletedSpan(changeValue, innerPosition, delLength, RichEditorDeleteDirection::BACKWARD, false);
9974     }
9975     if (RecordType::UNDO == type) {
9976         BeforeUndo(changeValue, innerPosition, record);
9977     }
9978     if (RecordType::REDO == type) {
9979         BeforeRedo(changeValue, innerPosition, record);
9980     }
9981     if (RecordType::DRAG == type) {
9982         BeforeDrag(changeValue, innerPosition, record);
9983     }
9984     bool isDelete = RecordType::DEL_FORWARD == type || RecordType::DEL_BACKWARD == type;
9985     if (changeValue.GetRichEditorOriginalSpans().empty() && !isDelete) {
9986         // only add, do not delete
9987         changeValue.SetRangeBefore({ caretPosition_, caretPosition_ });
9988     }
9989 
9990     CHECK_NULL_RETURN(eventHub->HasOnWillChange(), true);
9991     auto ret = eventHub->FireOnWillChange(changeValue);
9992     return ret;
9993 }
9994 
9995 OffsetF RichEditorPattern::GetTextPaintOffset() const
9996 {
9997     if (selectOverlay_->HasRenderTransform()) {
9998         return selectOverlay_->GetPaintRectOffsetWithTransform();
9999     }
10000     return GetPaintRectGlobalOffset();
10001 }
10002 
10003 OffsetF RichEditorPattern::GetPaintRectGlobalOffset() const
10004 {
10005     auto host = GetHost();
10006     CHECK_NULL_RETURN(host, OffsetF(0.0f, 0.0f));
10007     auto pipeline = host->GetContextRefPtr();
10008     CHECK_NULL_RETURN(pipeline, OffsetF(0.0f, 0.0f));
10009     auto rootOffset = pipeline->GetRootRect().GetOffset();
10010     auto textPaintOffset = host->GetPaintRectOffsetNG(false, true);
10011     return textPaintOffset - rootOffset;
10012 }
10013 
10014 void RichEditorPattern::HandlePointWithTransform(OffsetF& point)
10015 {
10016     auto host = GetHost();
10017     CHECK_NULL_VOID(host);
10018     PointF convertPoint = { point.GetX(), point.GetY() };
10019     auto parent = host;
10020     while (parent && (parent->GetTag() != V2::WINDOW_SCENE_ETS_TAG)) {
10021         auto renderContext = parent->GetRenderContext();
10022         CHECK_NULL_VOID(renderContext);
10023         auto paintOffset = renderContext->GetPaintRectWithoutTransform().GetOffset();
10024         if (parent != host) {
10025             convertPoint = convertPoint + paintOffset;
10026         }
10027         renderContext->GetPointTransform(convertPoint);
10028         parent = parent->GetAncestorNodeOfFrame(true);
10029     }
10030     point = { convertPoint.GetX(), convertPoint.GetY() };
10031 }
10032 
10033 const std::list<RefPtr<UINode>>& RichEditorPattern::GetAllChildren() const
10034 {
10035     childNodes_.clear();
10036     auto host = GetHost();
10037     CHECK_NULL_RETURN(host, childNodes_);
10038     auto children = host->GetChildren();
10039     for (const auto& child: children) {
10040         childNodes_.push_back(child);
10041     }
10042     return childNodes_;
10043 }
10044 
10045 CaretOffsetInfo RichEditorPattern::GetCaretOffsetInfoByPosition(int32_t position)
10046 {
10047     CaretOffsetInfo caretInfo;
10048     int32_t currrentPosition = 0;
10049     if (position == -1) {
10050         currrentPosition = caretPosition_;
10051     } else {
10052         currrentPosition = position;
10053     }
10054     caretInfo.caretOffsetUp = CalcCursorOffsetByPosition(currrentPosition, caretInfo.caretHeightUp, false, false);
10055     caretInfo.caretOffsetDown = CalcCursorOffsetByPosition(currrentPosition, caretInfo.caretHeightDown, true, false);
10056     caretInfo.caretOffsetLine = CalcCursorOffsetByPosition(currrentPosition, caretInfo.caretHeightLine);
10057     return caretInfo;
10058 }
10059 
10060 void RichEditorPattern::CalcLineSidesIndexByPosition(int32_t& startIndex, int32_t& endIndex)
10061 {
10062     Offset textStartOffset;
10063     Offset textEndOffset;
10064 
10065     CHECK_NULL_VOID(overlayMod_);
10066     auto overlayMod = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
10067     auto minDet = paragraphs_.minParagraphFontSize.value_or(GetTextThemeFontSize());
10068     float textOffsetY = richTextRect_.GetY() - (minDet / 2.0);
10069     auto currentCaretOffsetOverlay = overlayMod->GetCaretOffset();
10070     textStartOffset = Offset(0, currentCaretOffsetOverlay.GetY() - textOffsetY);
10071     textEndOffset = Offset(richTextRect_.Width(), currentCaretOffsetOverlay.GetY() - textOffsetY);
10072     startIndex = paragraphs_.GetIndex(textStartOffset);
10073     endIndex = paragraphs_.GetIndex(textEndOffset);
10074 }
10075 
10076 RectF RichEditorPattern::CalcLineInfoByPosition()
10077 {
10078     int32_t startIndex = 0;
10079     int32_t endIndex = 0;
10080 
10081     CalcLineSidesIndexByPosition(startIndex, endIndex);
10082     if (startIndex == endIndex) {
10083         endIndex += 1;
10084     }
10085     auto selectedRects = paragraphs_.GetRects(startIndex, endIndex);
10086     CHECK_NULL_RETURN(selectedRects.size(), {});
10087     return selectedRects.front();
10088 }
10089 
10090 int32_t RichEditorPattern::CalcMoveUpPos(float& leadingMarginOffset)
10091 {
10092     int32_t caretPosition;
10093     CaretOffsetInfo caretInfo;
10094     float textOffsetDownY = 0.0f;
10095     int32_t startIndex = 0;
10096     int32_t endIndex = 0;
10097     Offset textOffset;
10098 
10099     caretInfo = GetCaretOffsetInfoByPosition();
10100     auto minDet = paragraphs_.minParagraphFontSize.value_or(GetTextThemeFontSize());
10101     CHECK_NULL_RETURN(overlayMod_, 0);
10102     auto overlayMod = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
10103     auto caretOffsetOverlay = overlayMod->GetCaretOffset();
10104     auto caretOffsetWidth = overlayMod->GetCaretWidth();
10105     bool cursorNotAtLineStart = NearEqual(caretOffsetOverlay.GetX(), caretInfo.caretOffsetUp.GetX(), caretOffsetWidth);
10106     float textOffsetY = richTextRect_.GetY() + (minDet / 2.0); // 2.0 Cursor one half at the center position
10107     CalcLineSidesIndexByPosition(startIndex, endIndex);
10108     auto rectLineInfo = CalcLineInfoByPosition();
10109     leadingMarginOffset = rectLineInfo.GetX();
10110     if (cursorNotAtLineStart) {
10111         textOffsetDownY = caretInfo.caretOffsetLine.GetY() - textOffsetY;
10112         // lm mean leadingMargin abbr
10113         auto lmSizeOffset = (endIndex - startIndex <= 1 && NearEqual(rectLineInfo.Width(), richTextRect_.Width()))
10114                                 ? rectLineInfo.GetX()
10115                                 : 0;
10116         textOffset = Offset(caretInfo.caretOffsetLine.GetX() - richTextRect_.GetX() + lmSizeOffset, textOffsetDownY);
10117     } else {
10118         textOffsetDownY = caretInfo.caretOffsetLine.GetY() + caretInfo.caretHeightLine - textOffsetY;
10119         textOffset = Offset(caretOffsetOverlay.GetX() - richTextRect_.GetX(), textOffsetDownY);
10120     }
10121     caretPosition = paragraphs_.GetIndex(textOffset);
10122     return caretPosition;
10123 }
10124 
10125 int32_t RichEditorPattern::CalcMoveDownPos(float& leadingMarginOffset)
10126 {
10127     CaretOffsetInfo caretInfo;
10128     float textOffsetDownY = 0.0f;
10129     Offset textOffset;
10130     int32_t caretPositionEnd;
10131 
10132     caretInfo = GetCaretOffsetInfoByPosition();
10133     auto minDet = paragraphs_.minParagraphFontSize.value_or(GetTextThemeFontSize());
10134     CHECK_NULL_RETURN(overlayMod_, 0);
10135     auto overlayMod = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
10136     auto caretOffsetOverlay = overlayMod->GetCaretOffset();
10137     auto caretOffsetWidth = overlayMod->GetCaretWidth();
10138     float textOffsetX = richTextRect_.GetX();
10139     float textOffsetY = richTextRect_.GetY() - (minDet / 2.0);
10140     bool cursorNotAtLineStart = NearEqual(caretOffsetOverlay.GetX(), caretInfo.caretOffsetUp.GetX(), caretOffsetWidth);
10141     // midle or enter
10142     auto rectLineInfo = CalcLineInfoByPosition();
10143     leadingMarginOffset = rectLineInfo.GetX();
10144     auto lineHeightDis = rectLineInfo.Height();
10145     // midle or end, first line start position,end line end position
10146     textOffsetDownY = caretInfo.caretOffsetLine.GetY() + caretInfo.caretHeightLine - textOffsetY;
10147     if (cursorNotAtLineStart || caretPosition_ == 0) {
10148         textOffset = Offset(caretInfo.caretOffsetLine.GetX() - textOffsetX, textOffsetDownY);
10149     } else {
10150         textOffsetDownY += lineHeightDis;
10151         textOffset = Offset(caretOffsetOverlay.GetX() - textOffsetX, textOffsetDownY);
10152     }
10153     caretPositionEnd = paragraphs_.GetIndex(textOffset);
10154     return caretPositionEnd;
10155 }
10156 
10157 int32_t RichEditorPattern::CalcLineBeginPosition()
10158 {
10159     float caretHeight = 0.0f;
10160     OffsetF caretOffset = CalcCursorOffsetByPosition(caretPosition_, caretHeight, false, false);
10161     auto textPaintOffset = GetTextRect().GetOffset() - OffsetF(0.0, std::min(baselineOffset_, 0.0f));
10162     auto minDet = paragraphs_.minParagraphFontSize.value_or(GetTextThemeFontSize());
10163     auto textOffsetY = caretOffset.GetY() - textPaintOffset.GetY() + (minDet / 2.0);
10164     Offset textOffset = { 0, textOffsetY };
10165     auto newPos = paragraphs_.GetIndex(textOffset);
10166     return newPos;
10167 }
10168 
10169 float RichEditorPattern::GetTextThemeFontSize()
10170 {
10171     auto host = GetHost();
10172     CHECK_NULL_RETURN(host, 0.0f);
10173     auto context = host->GetContext();
10174     CHECK_NULL_RETURN(context, 0.0f);
10175     auto theme = context->GetTheme<TextTheme>();
10176     CHECK_NULL_RETURN(theme, 0.0f);
10177     auto textStyle = theme->GetTextStyle();
10178     return textStyle.GetFontSize().ConvertToPx();
10179 }
10180 
10181 int32_t RichEditorPattern::CalcLineEndPosition(int32_t index)
10182 {
10183     CaretOffsetInfo caretInfo;
10184     int32_t realCaretOffsetY = 0;
10185     int32_t realLastClickOffsetY = 0;
10186 
10187     caretInfo = GetCaretOffsetInfoByPosition(index);
10188     if (NearEqual(richTextRect_.GetY(), contentRect_.GetY())) {
10189         realLastClickOffsetY = lastClickOffset_.GetY();
10190         realCaretOffsetY = caretInfo.caretOffsetDown.GetY();
10191     } else {
10192         auto scrollOffset =
10193             caretInfo.caretOffsetDown.GetY() - caretInfo.caretOffsetUp.GetY() + caretInfo.caretOffsetLine.GetY();
10194         realLastClickOffsetY = lastClickOffset_.GetY() + std::abs(richTextRect_.GetY()) + contentRect_.GetY();
10195         realCaretOffsetY = scrollOffset + std::abs(richTextRect_.GetY()) + contentRect_.GetY();
10196     }
10197     auto textPaintOffset = contentRect_.GetOffset() - OffsetF(0.0, std::min(baselineOffset_, 0.0f));
10198     auto minDet = paragraphs_.minParagraphFontSize.value_or(GetTextThemeFontSize());
10199     Offset textOffset;
10200     auto rectLineInfo = CalcLineInfoByPosition();
10201     float textWidth = richTextRect_.Width() + rectLineInfo.GetX();
10202     float textPaintOffsetY = textPaintOffset.GetY() - (minDet / 2.0);
10203     float textOffsetClickY = realLastClickOffsetY - textPaintOffsetY;
10204     float textOffsetDownY = realCaretOffsetY - textPaintOffsetY;
10205     if (lastClickOffset_.NonNegative()) {
10206         textOffset = { textWidth, textOffsetClickY };
10207     } else {
10208         textOffset = { textWidth, textOffsetDownY };
10209     }
10210     auto position = paragraphs_.GetIndex(textOffset);
10211     return position;
10212 }
10213 
10214 bool RichEditorPattern::CursorMoveLineBegin()
10215 {
10216     int32_t currentPositionIndex = 0;
10217     if (textSelector_.SelectNothing()) {
10218         currentPositionIndex = caretPosition_;
10219     } else {
10220         currentPositionIndex = textSelector_.GetTextStart();
10221     }
10222     CloseSelectOverlay();
10223     ResetSelection();
10224     float caretHeightDown = 0.0f;
10225     Offset textOffset;
10226 
10227     if (0 == currentPositionIndex) {
10228         SetCaretPosition(currentPositionIndex);
10229         StartTwinkling();
10230         return false;
10231     }
10232     OffsetF caretOffsetDown = CalcCursorOffsetByPosition(currentPositionIndex, caretHeightDown, true, false);
10233     auto textPaintOffset = GetTextRect().GetOffset() - OffsetF(0.0, std::min(baselineOffset_, 0.0f));
10234     auto minDet = paragraphs_.minParagraphFontSize.value_or(GetTextThemeFontSize());
10235     float textPaintOffsetY = textPaintOffset.GetY() - (minDet / 2.0);
10236     if (lastClickOffset_.NonNegative()) {
10237         textOffset = { 0, lastClickOffset_.GetY() - textPaintOffsetY };
10238     } else {
10239         textOffset = { 0, caretOffsetDown.GetY() - textPaintOffsetY };
10240     }
10241     auto position = paragraphs_.GetIndex(textOffset);
10242     AdjustCursorPosition(position);
10243     SetCaretPosition(position);
10244     MoveCaretToContentRect();
10245     StartTwinkling();
10246     auto host = GetHost();
10247     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
10248     return true;
10249 }
10250 
10251 bool RichEditorPattern::CursorMoveLineEnd()
10252 {
10253     int32_t position = 0;
10254     if (!textSelector_.SelectNothing()) {
10255         CaretOffsetInfo caretInfo = GetCaretOffsetInfoByPosition(textSelector_.GetTextEnd());
10256         bool cursorAtLineEnd = !NearEqual(caretInfo.caretOffsetUp.GetX(), caretInfo.caretOffsetDown.GetX(), 0.5f);
10257         if (cursorAtLineEnd) {
10258             position = textSelector_.GetTextEnd();
10259         } else {
10260             position = CalcLineEndPosition(textSelector_.GetTextEnd());
10261         }
10262     } else {
10263         position = CalcLineEndPosition();
10264     }
10265     CloseSelectOverlay();
10266     ResetSelection();
10267     float caretHeight = 0.0f;
10268     CHECK_NULL_RETURN(overlayMod_, false);
10269     auto overlayMod = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
10270     SetCaretPosition(position);
10271     StartTwinkling();
10272     OffsetF caretOffset = CalcCursorOffsetByPosition(caretPosition_, caretHeight, false, false);
10273     overlayMod->SetCaretOffsetAndHeight(caretOffset, caretHeight);
10274     SetLastClickOffset(caretOffset);
10275     caretAffinityPolicy_ = CaretAffinityPolicy::UPSTREAM_FIRST;
10276     MoveCaretToContentRect(caretOffset, caretHeight);
10277     auto host = GetHost();
10278     CHECK_NULL_RETURN(host, false);
10279     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
10280     return true;
10281 }
10282 
10283 void RichEditorPattern::HandleSelectFontStyle(KeyCode code)
10284 {
10285     if (textSelector_.SelectNothing() || isSpanStringMode_) {
10286         return;
10287     }
10288     auto host = GetHost();
10289     CHECK_NULL_VOID(host);
10290     UpdateSelectSpanStyle(textSelector_.GetTextStart(), textSelector_.GetTextEnd(), code);
10291     StopTwinkling();
10292     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
10293 }
10294 
10295 void RichEditorPattern::HandleOnShowMenu()
10296 {
10297     CHECK_NULL_VOID(overlayMod_);
10298     auto overlayMod = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
10299     auto caretOffsetOverlay = overlayMod->GetCaretOffset();
10300     auto host = GetHost();
10301     CHECK_NULL_VOID(host);
10302     auto focusHub = host->GetOrCreateFocusHub();
10303     CHECK_NULL_VOID(focusHub);
10304     selectionMenuOffsetByMouse_ = OffsetF(
10305         parentGlobalOffset_.GetX() + caretOffsetOverlay.GetX(), parentGlobalOffset_.GetY() + caretOffsetOverlay.GetY());
10306     focusHub->RequestFocusImmediately();
10307     StartTwinkling();
10308     ShowSelectOverlay(RectF(), RectF(), IsSelectAll(), TextResponseType::RIGHT_CLICK);
10309 }
10310 
10311 PositionType RichEditorPattern::GetPositionTypeFromLine()
10312 {
10313     auto overlayMod = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
10314     CHECK_NULL_RETURN(overlayMod, PositionType::DEFAULT);
10315     auto currentCaretOffsetOverlay = overlayMod->GetCaretOffset();
10316     auto caretOffsetWidth = overlayMod->GetCaretWidth();
10317     int32_t currentParagraphStart = GetParagraphBeginPosition(caretPosition_);
10318     bool isParagraphStart = caretPosition_ == currentParagraphStart;
10319     CHECK_NULL_RETURN(!isParagraphStart, PositionType::PARAGRAPH_START);
10320     int32_t currentParagraphEnd = GetParagraphEndPosition(caretPosition_);
10321     bool isParagraphEnd = caretPosition_ == currentParagraphEnd;
10322     CHECK_NULL_RETURN(!isParagraphEnd, PositionType::PARAGRAPH_END);
10323     CaretOffsetInfo caretInfo = GetCaretOffsetInfoByPosition();
10324     bool isCaretAtLineMiddle = NearEqual(caretInfo.caretOffsetDown.GetX(), caretInfo.caretOffsetUp.GetX(), 0.5f);
10325     CHECK_NULL_RETURN(!isCaretAtLineMiddle, PositionType::DEFAULT);
10326     bool isCaretAtLineEnd =
10327         NearEqual(currentCaretOffsetOverlay.GetX(), caretInfo.caretOffsetUp.GetX(), caretOffsetWidth);
10328     CHECK_NULL_RETURN(!isCaretAtLineEnd, PositionType::LINE_END);
10329     return PositionType::LINE_START;
10330 }
10331 
10332 int32_t RichEditorPattern::HandleSelectWrapper(CaretMoveIntent direction, int32_t fixedPos)
10333 {
10334     int32_t index = GetCaretPosition();
10335     switch (direction) {
10336         case CaretMoveIntent::Left:
10337             return CaretPositionSelectEmoji(CaretMoveIntent::Left);
10338         case CaretMoveIntent::Right:
10339             return CaretPositionSelectEmoji(CaretMoveIntent::Right);
10340         case CaretMoveIntent::Up:
10341             return HandleSelectPosition(true);
10342         case CaretMoveIntent::Down:
10343             return HandleSelectPosition(false);
10344         case CaretMoveIntent::LeftWord: {
10345             int32_t startPosition = 0;
10346             int32_t aiContentStart = 0;
10347             aiContentStart = std::clamp(index - RICH_DEFAULT_AI_WORD, 0, GetTextContentLength());
10348             AIDeleteComb(aiContentStart, index, startPosition, true);
10349             return startPosition;
10350         }
10351         case CaretMoveIntent::RightWord: {
10352             int32_t endPosition = 0;
10353             int32_t aiContentEnd = GetTextContentLength();
10354             aiContentEnd = std::clamp(index + RICH_DEFAULT_AI_WORD, 0, GetTextContentLength());
10355             AIDeleteComb(index, aiContentEnd, endPosition, false);
10356             return endPosition;
10357         }
10358         case CaretMoveIntent::ParagraghBegin:
10359             return HandleSelectParagraghPos(true);
10360         case CaretMoveIntent::ParagraghEnd:
10361             return HandleSelectParagraghPos(false);
10362         case CaretMoveIntent::LineBegin:
10363             return CalcLineBeginPosition();
10364         case CaretMoveIntent::LineEnd:
10365             return CalcLineEndPosition();
10366         default:
10367             return NONE_SELECT_TYPE;
10368     }
10369 }
10370 
10371 int32_t RichEditorPattern::HandleSelectPosition(bool isForward)
10372 {
10373     float caretHeight = 0.0f;
10374     float newCaretHeight = 0.0f;
10375     float careOffsetY = 0.0f;
10376     int32_t newPos;
10377     Offset textOffset;
10378     OffsetF caretOffset = CalcCursorOffsetByPosition(caretPosition_, caretHeight);
10379     auto minDet = paragraphs_.minParagraphFontSize.value_or(GetTextThemeFontSize()) / 2.0;
10380     auto positionType = GetPositionTypeFromLine();
10381     if (isForward) {
10382         float selectStartHeight = 0.0f;
10383         OffsetF selectStartOffset = CalcCursorOffsetByPosition(textSelector_.GetTextStart(), selectStartHeight);
10384         careOffsetY = caretOffset.GetY() - GetTextRect().GetY() - minDet;
10385         newPos = paragraphs_.GetIndex(Offset(caretOffset.GetX() - GetTextRect().GetX(), careOffsetY), true);
10386         OffsetF newCaretOffset = CalcCursorOffsetByPosition(newPos, newCaretHeight);
10387         if (!textSelector_.SelectNothing() && textSelector_.GetTextEnd() == caretPosition_ &&
10388             selectStartOffset.GetY() == newCaretOffset.GetY()) {
10389             return textSelector_.GetTextStart();
10390         }
10391     } else {
10392         float selectEndHeight = 0.0f;
10393         OffsetF selectEndOffset = CalcCursorOffsetByPosition(textSelector_.GetEnd(), selectEndHeight);
10394         careOffsetY = caretOffset.GetY() - GetTextRect().GetY() + caretHeight + (minDet / 2.0);
10395         if (positionType == PositionType::LINE_START) {
10396             auto overlayMod = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
10397             CHECK_NULL_RETURN(overlayMod, 0);
10398             auto caretOffsetOverlay = overlayMod->GetCaretOffset();
10399             auto rectLineInfo = CalcLineInfoByPosition();
10400             careOffsetY += rectLineInfo.Height();
10401             textOffset = Offset(caretOffsetOverlay.GetX() - GetTextRect().GetX(), careOffsetY);
10402         } else {
10403             textOffset = Offset(caretOffset.GetX() - GetTextRect().GetX(), careOffsetY);
10404         }
10405         newPos = paragraphs_.GetIndex(textOffset, true);
10406         OffsetF newCaretOffset = CalcCursorOffsetByPosition(newPos, newCaretHeight);
10407         if (!textSelector_.SelectNothing() && textSelector_.GetTextStart() == caretPosition_ &&
10408             selectEndOffset.GetY() == newCaretOffset.GetY()) {
10409             return textSelector_.GetTextEnd();
10410         }
10411     }
10412     bool isParagraphStart = newPos == GetParagraphBeginPosition(newPos);
10413     if (isParagraphStart && newPos != GetTextContentLength() && newPos != 0) {
10414         return newPos - 1;
10415     }
10416     return newPos;
10417 }
10418 
10419 int32_t RichEditorPattern::HandleSelectParagraghPos(bool direction)
10420 {
10421     int32_t newPos = 0;
10422     CloseSelectOverlay();
10423     ResetSelection();
10424     if (direction) {
10425         newPos = GetParagraphBeginPosition(caretPosition_);
10426         if (newPos == caretPosition_ && caretPosition_ > 0) {
10427             newPos = GetParagraphBeginPosition(caretPosition_ - 1);
10428         }
10429     } else {
10430         newPos = GetParagraphEndPosition(caretPosition_);
10431         if (newPos == caretPosition_ && caretPosition_ < static_cast<int32_t>(GetTextContentLength())) {
10432             newPos = GetParagraphEndPosition(caretPosition_ + 1);
10433         }
10434     }
10435     return newPos;
10436 }
10437 
10438 void RichEditorPattern::HandleSelectFontStyleWrapper(KeyCode code, TextStyle& spanStyle)
10439 {
10440     switch (code) {
10441         case KeyCode::KEY_B:
10442             if (spanStyle.GetFontWeight() == Ace::FontWeight::BOLD) {
10443                 spanStyle.SetFontWeight(Ace::FontWeight::NORMAL);
10444             } else {
10445                 spanStyle.SetFontWeight(Ace::FontWeight::BOLD);
10446             }
10447             break;
10448         case KeyCode::KEY_I:
10449             if (spanStyle.GetFontStyle() == OHOS::Ace::FontStyle::ITALIC) {
10450                 spanStyle.SetFontStyle(OHOS::Ace::FontStyle::NORMAL);
10451             } else {
10452                 spanStyle.SetFontStyle(OHOS::Ace::FontStyle::ITALIC);
10453             }
10454             break;
10455         case KeyCode::KEY_U:
10456             if (spanStyle.GetTextDecoration() == TextDecoration::UNDERLINE) {
10457                 spanStyle.SetTextDecoration(TextDecoration::NONE);
10458             } else {
10459                 spanStyle.SetTextDecoration(TextDecoration::UNDERLINE);
10460             }
10461             break;
10462         default:
10463             LOGW("Unsupported select operation for HandleSelectFrontStyle");
10464             return;
10465     }
10466 }
10467 
10468 void RichEditorPattern::AIDeleteComb(int32_t start, int32_t end, int32_t& aiPosition, bool direction)
10469 {
10470     auto selectTextContent = GetContentBySpans();
10471     std::u16string u16Content = StringUtils::Str8ToStr16(selectTextContent);
10472     // get select content
10473     std::u16string selectData16 = u16Content.substr(static_cast<int32_t>(start), static_cast<int32_t>(end - start));
10474     std::string selectData = StringUtils::Str16ToStr8(selectData16);
10475     int32_t aiPosStart;
10476     int32_t aiPosEnd;
10477     int32_t caretPosition;
10478     int32_t size = 1;
10479 
10480     if (direction) {
10481         caretPosition = end - start - size;
10482         DataDetectorMgr::GetInstance().AdjustWordSelection(caretPosition, selectData, aiPosStart, aiPosEnd);
10483         aiPosition = aiPosStart + start;
10484     } else {
10485         caretPosition = 0;
10486         DataDetectorMgr::GetInstance().AdjustWordSelection(caretPosition, selectData, aiPosStart, aiPosEnd);
10487         aiPosition = aiPosEnd + start;
10488     }
10489     if (aiPosStart < 0 || aiPosEnd < 0) {
10490         aiPosition = GetCaretPosition();
10491     }
10492 }
10493 
10494 bool RichEditorPattern::HandleOnDeleteComb(bool backward)
10495 {
10496     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "HandleOnDeleteComb backward=%{public}d", backward);
10497     if (textSelector_.IsValid()) {
10498         CloseSelectOverlay();
10499         SetCaretPosition(textSelector_.GetTextStart());
10500         ResetSelection();
10501     }
10502     if (backward) {
10503         DeleteBackwardWord();
10504     } else {
10505         DeleteForwardWord();
10506     }
10507     MoveCaretToContentRect();
10508     StartTwinkling();
10509     auto host = GetHost();
10510     CHECK_NULL_RETURN(host, false);
10511     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
10512     return true;
10513 }
10514 
10515 void RichEditorPattern::DeleteBackwardWord()
10516 {
10517     CHECK_NULL_VOID(caretPosition_ != 0);
10518     int32_t startIndex = caretPosition_;
10519     int32_t spaceEndIndex = startIndex;
10520     AdjustIndexSkipSpace(spaceEndIndex, MoveDirection::BACKWARD);
10521     int32_t wordEndIndex = std::max(0, spaceEndIndex - 1);
10522     AdjustWordSelection(wordEndIndex, spaceEndIndex);
10523     DeleteBackward(startIndex - wordEndIndex);
10524 }
10525 
10526 void RichEditorPattern::DeleteForwardWord()
10527 {
10528     CHECK_NULL_VOID(caretPosition_ != GetTextContentLength());
10529     int32_t startIndex = caretPosition_;
10530     int32_t spaceEndIndex = startIndex;
10531     AdjustIndexSkipSpace(spaceEndIndex, MoveDirection::FORWARD);
10532     int32_t wordEndIndex = std::min(spaceEndIndex + 1, GetTextContentLength());
10533     AdjustWordSelection(spaceEndIndex, wordEndIndex);
10534     DeleteForward(wordEndIndex - startIndex);
10535 }
10536 
10537 void RichEditorPattern::HandleTripleClickEvent(OHOS::Ace::GestureEvent& info)
10538 {
10539     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "HandleTripleClickEvent");
10540     CHECK_EQUAL_VOID(IsPreviewTextInputting(), true);
10541     CHECK_EQUAL_VOID(IsDragging(), true);
10542     bool isMouseClickWithShift = shiftFlag_ && info.GetSourceDevice() == SourceType::MOUSE;
10543     CHECK_EQUAL_VOID(isMouseClickWithShift, true);
10544     auto focusHub = GetFocusHub();
10545     CHECK_NULL_VOID(focusHub);
10546     CHECK_EQUAL_VOID(focusHub->IsFocusable(), false);
10547     auto textPaintOffset = GetTextRect().GetOffset() - OffsetF(0.0, std::min(baselineOffset_, 0.0f));
10548     Offset textOffset = { info.GetLocalLocation().GetX() - textPaintOffset.GetX(),
10549         info.GetLocalLocation().GetY() - textPaintOffset.GetY() };
10550     int32_t pos = paragraphs_.GetIndex(textOffset);
10551 
10552     int32_t start = 0;
10553     int32_t end = 0;
10554     auto& paragraphInfoList = paragraphs_.GetParagraphs();
10555     if (pos == paragraphInfoList.back().end) {
10556         start = paragraphInfoList.back().start;
10557         end = paragraphInfoList.back().end;
10558     } else {
10559         for (const auto& paragraph : paragraphInfoList) {
10560             if (pos >= paragraph.start && pos < paragraph.end) {
10561                 start = paragraph.start;
10562                 end = paragraph.end;
10563                 break;
10564             }
10565         }
10566     }
10567     if (paragraphInfoList.back().end != end) {
10568         --end;
10569     }
10570     end = std::min(GetTextContentLength(), end);
10571     start = std::min(GetTextContentLength(), start);
10572     CHECK_EQUAL_VOID(start > end, true);
10573     TripleClickSection(info, start, end, pos);
10574 }
10575 
10576 void RichEditorPattern::OnSelectionMenuOptionsUpdate(
10577     const NG::OnCreateMenuCallback&& onCreateMenuCallback, const NG::OnMenuItemClickCallback&& onMenuItemClick)
10578 {
10579     selectOverlay_->OnSelectionMenuOptionsUpdate(std::move(onCreateMenuCallback), std::move(onMenuItemClick));
10580 }
10581 
10582 bool RichEditorPattern::CheckTripClickEvent(GestureEvent& info)
10583 {
10584     clickInfo_.push_back(info.GetTimeStamp());
10585     if (clickInfo_.size() > MAX_CLICK) {
10586         clickInfo_.erase(clickInfo_.begin());
10587     }
10588     if (clickInfo_.size() == MAX_CLICK) {
10589         std::chrono::duration<float, std::ratio<1, InputAIChecker::SECONDS_TO_MILLISECONDS>>
10590             clickTimeIntervalOne = clickInfo_[1] - clickInfo_[0];
10591         std::chrono::duration<float, std::ratio<1, InputAIChecker::SECONDS_TO_MILLISECONDS>>
10592             clickTimeIntervalTwo = clickInfo_[2] - clickInfo_[1];
10593         if (clickTimeIntervalOne.count() < DOUBLE_CLICK_INTERVAL_MS
10594             && clickTimeIntervalTwo.count() < DOUBLE_CLICK_INTERVAL_MS) {
10595             return true;
10596         }
10597     }
10598     return false;
10599 }
10600 
10601 void RichEditorPattern::PreferredParagraph()
10602 {
10603     CHECK_NULL_VOID(typingTextStyle_.has_value());
10604     if (presetParagraph_) {
10605         presetParagraph_->Reset();
10606         presetParagraph_ = nullptr;
10607     }
10608     std::string textContent;
10609     textContent = "a";
10610     TextStyle textStyle;
10611     textStyle = typingTextStyle_.value();
10612     ParagraphStyle paraStyle {
10613         .align = textStyle.GetTextAlign(),
10614         .maxLines = textStyle.GetMaxLines(),
10615         .fontLocale = Localization::GetInstance()->GetFontLocale(),
10616         .wordBreak = textStyle.GetWordBreak(),
10617         .lineBreakStrategy = textStyle.GetLineBreakStrategy(),
10618         .textOverflow = textStyle.GetTextOverflow(),
10619         .fontSize = textStyle.GetFontSize().ConvertToPx() };
10620     presetParagraph_ = Paragraph::Create(paraStyle, FontCollection::Current());
10621     CHECK_NULL_VOID(presetParagraph_);
10622     presetParagraph_->PushStyle(textStyle);
10623     presetParagraph_->AddText(StringUtils::Str8ToStr16(textContent));
10624     presetParagraph_->Build();
10625     presetParagraph_->Layout(std::numeric_limits<double>::infinity());
10626 }
10627 
10628 void RichEditorPattern::ShowCaretNoTwinkling(const Offset& textOffset)
10629 {
10630     auto position = paragraphs_.GetIndex(textOffset);
10631     SetCaretPosition(position);
10632     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "show caret no twinkling at position=%{public}d", position);
10633     StopTwinkling();
10634     caretVisible_ = true;
10635     isMoveCaretAnywhere_ = true;
10636     auto host = GetHost();
10637     CHECK_NULL_VOID(host);
10638     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
10639 
10640     CHECK_NULL_VOID(overlayMod_);
10641     auto [lastClickOffset, caretHeight] = CalcAndRecordLastClickCaretInfo(textOffset);
10642     auto localOffset = OffsetF(textOffset.GetX(), lastClickOffset.GetY());
10643     DynamicCast<RichEditorOverlayModifier>(overlayMod_)->SetCaretOffsetAndHeight(localOffset, caretHeight);
10644 
10645     // select + long press, so cancel selection.
10646     if (textSelector_.IsValid()) {
10647         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "select + long press, so cancel selection");
10648         CloseSelectOverlay();
10649         ResetSelection();
10650     }
10651 }
10652 
10653 void RichEditorPattern::UpdateSelectionByTouchMove(const Offset& touchOffset)
10654 {
10655     // While previewing + long press and move, then shall select content.
10656     auto host = GetHost();
10657     CHECK_NULL_VOID(host);
10658 
10659     Offset textOffset = ConvertTouchOffsetToTextOffset(touchOffset);
10660     auto positionWithAffinity = paragraphs_.GetGlyphPositionAtCoordinate(textOffset);
10661     SetCaretPositionWithAffinity(positionWithAffinity);
10662     MoveCaretToContentRect();
10663     int32_t currentPosition = GreatNotEqual(textOffset.GetY(), paragraphs_.GetHeight())
10664                                 ? GetTextContentLength()
10665                                 : caretPosition_;
10666     auto localOffset = OffsetF(touchOffset.GetX(), touchOffset.GetY());
10667     if (magnifierController_ && GetTextContentLength() > 0) {
10668         magnifierController_->SetLocalOffset(localOffset);
10669     }
10670     auto [initSelectStart, initSelectEnd] = initSelector_;
10671     int32_t start = std::min(initSelectStart, currentPosition);
10672     int32_t end = std::max(initSelectEnd, currentPosition);
10673     if (start == textSelector_.GetTextStart()) {
10674         StartVibratorByIndexChange(end, textSelector_.GetTextEnd());
10675     } else {
10676         StartVibratorByIndexChange(start, textSelector_.GetTextStart());
10677     }
10678     HandleSelectionChange(start, end);
10679     TriggerAvoidOnCaretChange();
10680     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
10681 }
10682 
10683 void RichEditorPattern::MoveCaretAnywhere(const Offset& offset)
10684 {
10685     // While editing + long press and move, then shall move caret:caret show anywhere on the fonts.
10686     CHECK_NULL_VOID(isMoveCaretAnywhere_);
10687     Offset textOffset = ConvertTouchOffsetToTextOffset(offset);
10688     auto position = paragraphs_.GetIndex(textOffset);
10689     AdjustCursorPosition(position);
10690     SetCaretPosition(position);
10691     auto [caretOffset, caretHeight] = CalcAndRecordLastClickCaretInfo(textOffset);
10692     CHECK_NULL_VOID(overlayMod_);
10693     auto localOffset = OffsetF(offset.GetX(), caretOffset.GetY());
10694 
10695     auto host = GetHost();
10696     CHECK_NULL_VOID(host);
10697     auto geometryNode = host->GetGeometryNode();
10698     CHECK_NULL_VOID(geometryNode);
10699     auto frameSize = geometryNode->GetFrameSize();
10700     // make sure the caret is display in the range of frame.
10701     localOffset.SetX(std::clamp(localOffset.GetX(), 0.0f, frameSize.Width()));
10702     DynamicCast<RichEditorOverlayModifier>(overlayMod_)->SetCaretOffsetAndHeight(localOffset, caretHeight);
10703     MoveCaretToContentRect(localOffset, caretHeight);
10704 }
10705 
10706 void RichEditorPattern::TripleClickSection(GestureEvent& info, int32_t start, int32_t end, int32_t pos)
10707 {
10708     auto host = GetHost();
10709     CHECK_NULL_VOID(host);
10710     textSelector_.Update(start, end);
10711     if (info.GetSourceTool() == SourceTool::FINGER) {
10712         showSelect_ = true;
10713         RequestKeyboard(false, true, true);
10714         HandleOnEditChanged(true);
10715         SetCaretPositionWithAffinity({ end, TextAffinity::UPSTREAM });
10716         MoveCaretToContentRect();
10717         CalculateHandleOffsetAndShowOverlay();
10718         selectOverlay_->ProcessOverlay({ .menuIsShow = !selectOverlay_->GetIsHandleMoving(), .animation = true });
10719     }
10720     if (info.GetSourceTool() == SourceTool::FINGER && start == end) {
10721         selectOverlay_->SetIsSingleHandle(true);
10722     }
10723     if (textSelector_.SelectNothing()) {
10724         textSelector_.Update(pos, pos);
10725     } else {
10726         StopTwinkling();
10727     }
10728     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
10729 }
10730 
10731 void RichEditorPattern::RequestKeyboardToEdit()
10732 {
10733     CHECK_NULL_VOID(!isEditing_ && HasFocus());
10734     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "request keyboard and enter edit");
10735     RequestKeyboard(false, true, true);
10736     HandleOnEditChanged(true);
10737 }
10738 
10739 bool RichEditorPattern::IsResponseRegionExpandingNeededForStylus(const TouchEvent& touchEvent) const
10740 {
10741     if (touchEvent.sourceTool != SourceTool::PEN || touchEvent.type != TouchType::DOWN) {
10742         return false;
10743     }
10744     auto host = GetHost();
10745     CHECK_NULL_RETURN(host, false);
10746     auto focusHub = host->GetFocusHub();
10747     CHECK_NULL_RETURN(focusHub, false);
10748     if (!focusHub->IsFocusable() || !host->IsVisible()) {
10749         return false;
10750     }
10751     auto renderContext = host->GetRenderContext();
10752     CHECK_NULL_RETURN(renderContext, false);
10753     auto opacity = renderContext->GetOpacity();
10754     // if opacity is 0.0f, no need to hit frameNode.
10755     if (NearZero(opacity.value_or(1.0f))) {
10756         return false;
10757     }
10758     return true;
10759 }
10760 
10761 RectF RichEditorPattern::ExpandDefaultResponseRegion(RectF& rect)
10762 {
10763     return rect + NG::SizeF(0, OHOS::Ace::HOT_AREA_ADJUST_SIZE.ConvertToPx() * OHOS::Ace::HOT_AREA_EXPAND_TIME) +
10764            NG::OffsetF(0, -OHOS::Ace::HOT_AREA_ADJUST_SIZE.ConvertToPx());
10765 }
10766 
10767 bool RichEditorPattern::InsertOrDeleteSpace(int32_t index)
10768 {
10769     // delete or insert space
10770     if (index < 0 || index >= GetTextContentLength()) {
10771         TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "index is invalid, index=%{public}d", index);
10772         return false;
10773     }
10774     bool success = SetCaretPosition(index);
10775     CHECK_NULL_RETURN(success, false);
10776     CloseSelectOverlay();
10777     ResetSelection();
10778 
10779     auto curIt = GetSpanIter(index);
10780     if (curIt != spans_.end()) {
10781         std::wstring curText = StringUtils::ToWstring((*curIt)->content);
10782         if ((*curIt)->spanItemType == SpanItemType::NORMAL
10783             && index >= (*curIt)->rangeStart && curText[index - (*curIt)->rangeStart] == L' ') {
10784             TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "delete forward");
10785             DeleteForward(1);
10786             return true;
10787         }
10788     }
10789 
10790     auto preIt = GetSpanIter(index - 1);
10791     if (preIt != spans_.end()) {
10792         std::wstring preText = StringUtils::ToWstring((*preIt)->content);
10793         if ((*preIt)->spanItemType == SpanItemType::NORMAL
10794             && index - 1 >= (*preIt)->rangeStart && preText[index - 1 - (*preIt)->rangeStart] == L' ') {
10795             TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "delete backward");
10796             DeleteBackward(1);
10797             return true;
10798         }
10799     }
10800 
10801     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "insert value");
10802     InsertValue(" ", true);
10803     return true;
10804 }
10805 
10806 void RichEditorPattern::DeleteRange(int32_t start, int32_t end, bool isIME)
10807 {
10808     if (start > end) {
10809         std::swap(start, end);
10810     }
10811     start = std::max(0, start);
10812     end = std::min(GetTextContentLength(), end);
10813     if (start > GetTextContentLength() || end < 0 || start == end) {
10814         TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "start=%{public}d, end=%{public}d, not in the range", start, end);
10815         return;
10816     }
10817     CHECK_NULL_VOID(!IsPreviewTextInputting());
10818     SetCaretPosition(start);
10819     auto length = end - start;
10820     if (isSpanStringMode_) {
10821         DeleteValueInStyledString(start, length, true, false);
10822         return;
10823     }
10824     OperationRecord record;
10825     record.beforeCaretPosition = caretPosition_;
10826     RichEditorChangeValue changeValue;
10827     CHECK_NULL_VOID(BeforeChangeText(changeValue, record, RecordType::DEL_FORWARD, length));
10828     std::wstringstream wss;
10829     for (auto iter = spans_.cbegin(); iter != spans_.cend(); iter++) {
10830         wss << StringUtils::ToWstring((*iter)->content);
10831     }
10832     auto textContent = wss.str();
10833     auto realEnd = std::clamp(caretPosition_ + length, 0, static_cast<int32_t>(textContent.length()));
10834     std::wstring deleteText = textContent.substr(
10835         static_cast<uint32_t>(std::clamp(caretPosition_, 0, static_cast<int32_t>(textContent.length()))),
10836         static_cast<uint32_t>(realEnd - caretPosition_));
10837     if (caretPosition_ != GetTextContentLength()) {
10838         RichEditorDeleteValue info;
10839         info.SetOffset(caretPosition_);
10840         info.SetRichEditorDeleteDirection(RichEditorDeleteDirection::FORWARD);
10841         info.SetLength(length);
10842         int32_t currentPosition = caretPosition_;
10843         if (!spans_.empty()) {
10844             CalcDeleteValueObj(currentPosition, length, info);
10845             bool doDelete = DoDeleteActions(currentPosition, length, info);
10846             CHECK_NULL_VOID(doDelete);
10847         }
10848     }
10849     CHECK_NULL_VOID(deleteText.length() != 0);
10850     ClearRedoOperationRecords();
10851     record.deleteText = StringUtils::ToString(deleteText);
10852     record.afterCaretPosition = caretPosition_;
10853     AddOperationRecord(record);
10854     AfterContentChange(changeValue);
10855 }
10856 
10857 void RichEditorPattern::HandleOnPageUp()
10858 {
10859     HandlePageScroll(true);
10860 }
10861 
10862 void RichEditorPattern::HandleOnPageDown()
10863 {
10864     HandlePageScroll(false);
10865 }
10866 
10867 void RichEditorPattern::HandlePageScroll(bool isPageUp)
10868 {
10869     auto visibleRect = selectOverlay_->GetVisibleRect();
10870     float distance = isPageUp ? visibleRect.Height() : -visibleRect.Height();
10871     RectF curCaretRect = GetCaretRect();
10872     auto height = paragraphs_.GetHeight();
10873     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "PageScroll isPageUp:%{public}d distance:%{public}f paragraphsHeight:%{public}f",
10874         isPageUp, distance, height);
10875     CloseSelectOverlay();
10876     ResetSelection();
10877     OnScrollCallback(distance, SCROLL_FROM_JUMP);
10878     auto paintOffset = selectOverlay_->GetPaintOffsetWithoutTransform();
10879     float offsetY = isPageUp ? visibleRect.Top() : visibleRect.Bottom();
10880     auto localOffset = Offset(curCaretRect.GetX(), offsetY - paintOffset.GetY());
10881     auto textOffset = ConvertTouchOffsetToTextOffset(localOffset);
10882     auto positionWithAffinity = paragraphs_.GetGlyphPositionAtCoordinate(textOffset);
10883     // If scrolling to the first or last line, move the cursor to the beginning or end of the line
10884     if (isPageUp && LessOrEqual(textOffset.GetY(), 0)) {
10885         positionWithAffinity = PositionWithAffinity(0, TextAffinity::DOWNSTREAM);
10886     } else if (!isPageUp && GreatOrEqual(textOffset.GetY(), height)) {
10887         positionWithAffinity = PositionWithAffinity(GetTextContentLength(), TextAffinity::UPSTREAM);
10888     }
10889     SetCaretPositionWithAffinity(positionWithAffinity);
10890     IF_TRUE(isEditing_, StartTwinkling());
10891 }
10892 
10893 TextStyle RichEditorPattern::GetDefaultTextStyle()
10894 {
10895     auto theme = GetTheme<RichEditorTheme>();
10896     TextStyle style = theme ? theme->GetTextStyle() : TextStyle();
10897     style.SetFontSize(Dimension(16.0f, DimensionUnit::VP));
10898     style.SetFontFeatures(ParseFontFeatureSettings("\"pnum\" 1"));
10899     style.SetFontFamilies({ "HarmonyOS Sans" });
10900     return style;
10901 }
10902 
10903 bool RichEditorPattern::IsTextEditableForStylus() const
10904 {
10905     auto host = GetHost();
10906     CHECK_NULL_RETURN(host, false);
10907     auto focusHub = host->GetFocusHub();
10908     CHECK_NULL_RETURN(focusHub, false);
10909     if (!focusHub->IsFocusable() || !host->IsVisible()) {
10910         return false;
10911     }
10912     auto renderContext = host->GetRenderContext();
10913     CHECK_NULL_RETURN(renderContext, false);
10914     auto opacity = renderContext->GetOpacity();
10915     // if opacity is 0.0f, no need to hit frameNode.
10916     if (NearZero(opacity.value_or(1.0f))) {
10917         return false;
10918     }
10919     return true;
10920 }
10921 
10922 bool RichEditorPattern::IsShowTranslate()
10923 {
10924     auto richEditorTheme = GetTheme<RichEditorTheme>();
10925     CHECK_NULL_RETURN(richEditorTheme, false);
10926     return richEditorTheme->GetTranslateIsSupport();
10927 }
10928 
10929 bool RichEditorPattern::IsShowAIWrite()
10930 {
10931     CHECK_NULL_RETURN(!textSelector_.SelectNothing(), false);
10932     auto container = Container::Current();
10933     if (container && container->IsScenceBoardWindow()) {
10934         return false;
10935     }
10936 
10937     if (copyOption_ == CopyOptions::None) {
10938         return false;
10939     }
10940     auto theme = GetTheme<RichEditorTheme>();
10941     CHECK_NULL_RETURN(theme, false);
10942     auto bundleName = theme->GetAIWriteBundleName();
10943     auto abilityName = theme->GetAIWriteAbilityName();
10944     if (bundleName.empty() || abilityName.empty()) {
10945         return false;
10946     }
10947     aiWriteAdapter_->SetBundleName(bundleName);
10948     aiWriteAdapter_->SetAbilityName(abilityName);
10949     TAG_LOGI(AceLogTag::ACE_RICH_TEXT,
10950         "BundleName: %{public}s, abilityName: %{public}s", bundleName.c_str(), abilityName.c_str());
10951 
10952     auto isAISupport = false;
10953     if (theme->GetAIWriteIsSupport() == "true") {
10954         isAISupport = true;
10955     }
10956     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "isAISupport: %{public}d", isAISupport);
10957     return isAISupport;
10958 }
10959 
10960 void RichEditorPattern::GetAIWriteInfo(AIWriteInfo& info)
10961 {
10962     CHECK_NULL_VOID(!textSelector_.SelectNothing());
10963     info.firstHandle = textSelector_.firstHandle.ToString();
10964     info.secondHandle = textSelector_.secondHandle.ToString();
10965     info.selectStart = textSelector_.GetTextStart();
10966     info.selectEnd = textSelector_.GetTextEnd();
10967     auto host = GetHost();
10968     CHECK_NULL_VOID(host);
10969     info.componentType = host->GetTag();
10970 
10971     // serialize the sentenced-level text
10972     auto textSize = static_cast<int32_t>(GetWideText().length()) + placeholderCount_;
10973     RefPtr<SpanString> spanString = ToStyledString(0, textSize);
10974     auto contentAll = spanString->GetWideString();
10975     auto sentenceStart = 0;
10976     auto sentenceEnd = textSize;
10977     for (int32_t i = info.selectStart; i >= 0; --i) {
10978         if (aiWriteAdapter_->IsSentenceBoundary(contentAll[i])) {
10979             sentenceStart = i + 1;
10980             break;
10981         }
10982     }
10983     for (int32_t i = info.selectEnd; i < textSize; i++) {
10984         if (aiWriteAdapter_->IsSentenceBoundary(contentAll[i])) {
10985             sentenceEnd = i;
10986             break;
10987         }
10988     }
10989     info.start = info.selectStart - sentenceStart;
10990     info.end = info.selectEnd - sentenceStart;
10991     spanString = ToStyledString(sentenceStart, sentenceEnd);
10992     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "Sentence range=[%{public}d--%{public}d], content = %{private}s",
10993         sentenceStart, sentenceEnd, spanString->GetString().c_str());
10994     spanString->EncodeTlv(info.sentenceBuffer);
10995 
10996     // serialize the selected text
10997     spanString = ToStyledString(info.selectStart, info.selectEnd);
10998     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "Selected range=[%{public}d--%{public}d], content = %{private}s",
10999         info.selectStart, info.selectEnd, spanString->GetString().c_str());
11000     spanString->EncodeTlv(info.selectBuffer);
11001     info.selectLength = static_cast<int32_t>(aiWriteAdapter_->GetSelectLengthOnlyText(spanString->GetWideString()));
11002 }
11003 
11004 void RichEditorPattern::HandleOnAIWrite()
11005 {
11006     aiWriteAdapter_->SetAIWrite(true);
11007     AIWriteInfo info;
11008     GetAIWriteInfo(info);
11009     CloseSelectOverlay();
11010     CloseKeyboard(true);
11011 
11012     auto callback = [weak = WeakClaim(this), info](std::vector<uint8_t>& buffer) {
11013         auto pattern = weak.Upgrade();
11014         CHECK_NULL_VOID(pattern);
11015         pattern->HandleAIWriteResult(info.selectStart, info.selectEnd, buffer);
11016         auto aiWriteAdapter = pattern->aiWriteAdapter_;
11017         CHECK_NULL_VOID(aiWriteAdapter);
11018         aiWriteAdapter->CloseModalUIExtension();
11019     };
11020     auto host = GetHost();
11021     CHECK_NULL_VOID(host);
11022     auto pipeline = host->GetContext();
11023     CHECK_NULL_VOID(pipeline);
11024     aiWriteAdapter_->SetPipelineContext(WeakClaim(pipeline));
11025     aiWriteAdapter_->ShowModalUIExtension(info, callback);
11026 }
11027 
11028 SymbolSpanOptions RichEditorPattern::GetSymbolSpanOptions(const RefPtr<SpanItem>& spanItem)
11029 {
11030     CHECK_NULL_RETURN(spanItem, {});
11031     TextStyle textStyle = GetDefaultTextStyle();
11032     UseSelfStyle(spanItem->fontStyle, spanItem->textLineStyle, textStyle);
11033     SymbolSpanOptions options;
11034     options.style = textStyle;
11035     options.offset = caretPosition_;
11036     options.resourceObject = spanItem->GetResourceObject();
11037     options.symbolId = spanItem->GetSymbolId();
11038     return options;
11039 }
11040 
11041 void RichEditorPattern::ReplacePlaceholderWithCustomSpan(
11042     const RefPtr<SpanItem>& spanItem, size_t& index, size_t& textIndex)
11043 {
11044     if (isSpanStringMode_) {
11045         auto customSpanItem = DynamicCast<CustomSpanItem>(spanItem);
11046         auto customSpan = MakeRefPtr<CustomSpan>();
11047         if (customSpanItem->onMeasure.has_value()) {
11048             customSpan->SetOnMeasure(customSpanItem->onMeasure.value());
11049         }
11050         if (customSpanItem->onDraw.has_value()) {
11051             customSpan->SetOnDraw(customSpanItem->onDraw.value());
11052         }
11053         auto spanString = MakeRefPtr<MutableSpanString>(customSpan);
11054         InsertStyledStringByPaste(spanString);
11055     } else {
11056         auto customSpanItem = DynamicCast<PlaceholderSpanItem>(spanItem);
11057         CHECK_NULL_VOID(customSpanItem);
11058         auto customNode = customSpanItem->GetCustomNode();
11059         SpanOptionBase options;
11060         options.offset = caretPosition_;
11061         AddPlaceholderSpan(customNode, options);
11062     }
11063     textIndex = index + PLACEHOLDER_LENGTH;
11064 }
11065 
11066 void RichEditorPattern::ReplacePlaceholderWithSymbolSpan(
11067     const RefPtr<SpanItem>& spanItem, size_t& index, size_t& textIndex)
11068 {
11069     auto options = GetSymbolSpanOptions(spanItem);
11070     options.offset = caretPosition_;
11071     AddSymbolSpan(options, false, caretPosition_);
11072     textIndex = index + PLACEHOLDER_LENGTH;
11073 }
11074 
11075 void RichEditorPattern::ReplacePlaceholderWithImageSpan(
11076     const RefPtr<SpanItem>& spanItem, size_t& index, size_t& textIndex)
11077 {
11078     auto imageSpanItem = DynamicCast<ImageSpanItem>(spanItem);
11079     CHECK_NULL_VOID(imageSpanItem);
11080     auto options = imageSpanItem->options;
11081     options.offset = caretPosition_;
11082     if (isSpanStringMode_) {
11083         auto spanString = MakeRefPtr<SpanString>(options);
11084         InsertStyledStringByPaste(spanString);
11085     } else {
11086         AddImageSpan(options, true, caretPosition_, true);
11087     }
11088     textIndex = index + PLACEHOLDER_LENGTH;
11089 }
11090 
11091 void RichEditorPattern::ReplacePlaceholderWithRawSpans(
11092     const RefPtr<SpanItem>& spanItem, size_t& index, size_t& textIndex)
11093 {
11094     switch (spanItem->spanItemType) {
11095         case SpanItemType::SYMBOL:
11096             ReplacePlaceholderWithSymbolSpan(spanItem, index, textIndex);
11097             return;
11098         case SpanItemType::CustomSpan:
11099             ReplacePlaceholderWithCustomSpan(spanItem, index, textIndex);
11100             return;
11101         case SpanItemType::IMAGE:
11102             ReplacePlaceholderWithImageSpan(spanItem, index, textIndex);
11103             return;
11104         default:
11105             return;
11106     }
11107 }
11108 
11109 void RichEditorPattern::AddSpansAndReplacePlaceholder(RefPtr<SpanString>& spanString)
11110 {
11111     auto content = spanString->GetWideString();
11112     size_t textIndex = 0;
11113     size_t index = content.find(PLACEHOLDER_MARK);
11114 
11115     while (index != std::string::npos) {
11116         if (textIndex < index) {
11117             auto subSpan = spanString->GetSubSpanString(textIndex, index - textIndex);
11118             AddSpanByPasteData(subSpan);
11119         }
11120         auto key = StringUtils::ToString(content.substr(index, PLACEHOLDER_LENGTH));
11121         if (placeholderSpansMap_.find(key) == placeholderSpansMap_.end()) {
11122             index = content.find(PLACEHOLDER_MARK, index + 1);
11123             continue;
11124         }
11125         auto spanItem = placeholderSpansMap_[key];
11126         if (!spanItem) {
11127             index = content.find(PLACEHOLDER_MARK, index + 1);
11128             continue;
11129         }
11130         ReplacePlaceholderWithRawSpans(spanItem, index, textIndex);
11131         index = content.find(PLACEHOLDER_MARK, index + 1);
11132     }
11133     if (textIndex < content.length()) {
11134         auto subSpan = spanString->GetSubSpanString(textIndex, content.length() - textIndex);
11135         AddSpanByPasteData(subSpan);
11136     }
11137 }
11138 
11139 void RichEditorPattern::InsertSpanByBackData(RefPtr<SpanString>& spanString)
11140 {
11141     CHECK_NULL_VOID(spanString);
11142     if (textSelector_.IsValid()) {
11143         SetCaretPosition(textSelector_.GetTextStart());
11144         DeleteForward(textSelector_.GetTextStart(), textSelector_.GetTextEnd() - textSelector_.GetTextStart());
11145         ResetSelection();
11146     }
11147     if (placeholderSpansMap_.empty()) {
11148         AddSpanByPasteData(spanString);
11149     } else {
11150         AddSpansAndReplacePlaceholder(spanString);
11151     }
11152     StartTwinkling();
11153     auto host = GetHost();
11154     CHECK_NULL_VOID(host);
11155     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
11156     host->MarkModifyDone();
11157 }
11158 
11159 void RichEditorPattern::HandleAIWriteResult(int32_t start, int32_t end, std::vector<uint8_t>& buffer)
11160 {
11161     RefPtr<SpanString> spanString = SpanString::DecodeTlv(buffer);
11162     if (spanString->GetSpanItems().empty()) {
11163         return;
11164     }
11165     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "Backfilling results range=[%{public}d--%{public}d], content = %{private}s",
11166         start, end, spanString->GetString().c_str());
11167     textSelector_.Update(start, end);
11168     auto length = end - start;
11169     CHECK_NULL_VOID(length > 0);
11170     DeleteBackward(length);
11171     InsertSpanByBackData(spanString);
11172     BeforeIMEInsertValue(spanString->GetString());
11173     InsertValue("");
11174 }
11175 } // namespace OHOS::Ace::NG
11176