• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-2024 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 <algorithm>
18 #include <chrono>
19 #include <cstddef>
20 #include <cstdint>
21 #include <functional>
22 #include <iterator>
23 #include <sstream>
24 #include <string>
25 #include <utility>
26 
27 #include "interfaces/inner_api/ui_session/ui_session_manager.h"
28 #include "adapter/ohos/capability/clipboard/clipboard_impl.h"
29 #include "base/geometry/offset.h"
30 #include "base/i18n/localization.h"
31 #include "base/log/ace_trace.h"
32 #include "base/log/dump_log.h"
33 #include "base/log/log_wrapper.h"
34 #include "base/memory/ace_type.h"
35 #include "base/utils/string_utils.h"
36 #include "base/utils/utf_helper.h"
37 #include "base/utils/utils.h"
38 #include "core/common/ai/data_detector_mgr.h"
39 #include "core/common/clipboard/paste_data.h"
40 #include "core/common/container.h"
41 #include "core/common/container_scope.h"
42 #include "core/common/ime/text_input_client.h"
43 #include "core/common/share/text_share_adapter.h"
44 #include "core/common/stylus/stylus_detector_mgr.h"
45 #include "core/common/vibrator/vibrator_utils.h"
46 #include "core/components/common/layout/constants.h"
47 #include "core/components/common/properties/text_style_parser.h"
48 #include "core/components_ng/base/inspector_filter.h"
49 #include "core/components_ng/base/observer_handler.h"
50 #include "core/components_ng/base/view_stack_processor.h"
51 #include "core/components_ng/event/event_hub.h"
52 #include "core/components_ng/event/gesture_event_hub.h"
53 #include "core/components_ng/event/long_press_event.h"
54 #include "core/components_ng/pattern/image/image_pattern.h"
55 #include "core/components_ng/pattern/overlay/keyboard_base_pattern.h"
56 #include "core/components_ng/pattern/rich_editor/one_step_drag_controller.h"
57 #include "core/components_ng/pattern/rich_editor/color_mode_processor.h"
58 #include "core/components_ng/pattern/rich_editor/rich_editor_event_hub.h"
59 #include "core/components_ng/pattern/rich_editor/rich_editor_layout_property.h"
60 #include "core/components_ng/pattern/rich_editor/rich_editor_model.h"
61 #include "core/components_ng/pattern/rich_editor/rich_editor_utils.h"
62 #include "core/components_ng/pattern/rich_editor_drag/rich_editor_drag_pattern.h"
63 #include "core/components_ng/pattern/text_field/text_field_manager.h"
64 #include "core/components_ng/pattern/text_field/text_input_ai_checker.h"
65 
66 #ifndef ACE_UNITTEST
67 #ifdef ENABLE_STANDARD_INPUT
68 #include "refbase.h"
69 
70 #include "core/components_ng/pattern/text_field/on_text_changed_listener_impl.h"
71 #endif
72 #endif
73 
74 #include "core/common/udmf/udmf_client.h"
75 
76 #ifdef WINDOW_SCENE_SUPPORTED
77 #include "core/components_ng/pattern/window_scene/helper/window_scene_helper.h"
78 #endif
79 
80 #ifdef ENABLE_ROSEN_BACKEND
81 #include "core/components/custom_paint/rosen_render_custom_paint.h"
82 #endif
83 
84 namespace OHOS::Ace::NG {
85 
86 namespace {
87 #if defined(ENABLE_STANDARD_INPUT)
88 // should be moved to theme
89 constexpr float CARET_WIDTH = 1.5f;
90 constexpr float DEFAULT_CARET_HEIGHT = 18.5f;
91 constexpr Dimension KEYBOARD_AVOID_OFFSET = 24.0_vp;
92 #endif
93 constexpr int32_t IMAGE_SPAN_LENGTH = 1;
94 constexpr int32_t SYMBOL_SPAN_LENGTH = 2;
95 constexpr uint32_t RICH_EDITOR_TWINKLING_INTERVAL_MS = 500;
96 constexpr uint32_t RICH_EDITOR_TWINKLING_INTERVAL_MS_DEBUG = 3000;
97 constexpr int32_t AUTO_SCROLL_INTERVAL = 15;
98 constexpr Dimension CARET_BOTTOM_DISTANCE = 16.0_vp;
99 constexpr Dimension AUTO_SCROLL_EDGE_DISTANCE = 15.0_vp;
100 constexpr Dimension AUTO_SCROLL_DRAG_EDGE_DISTANCE = 58.0_vp;
101 constexpr float MAX_DRAG_SCROLL_SPEED = 2400.0f;
102 constexpr float TIME_UNIT = 1000.0f;
103 constexpr float DOUBLE_CLICK_INTERVAL_MS = 300.0f;
104 constexpr uint32_t RECORD_MAX_LENGTH = 20;
105 constexpr float DEFAILT_OPACITY = 0.2f;
106 constexpr int64_t COLOR_OPAQUE = 255;
107 constexpr int32_t MAX_CLICK = 3;
108 
109 constexpr Color SYSTEM_CARET_COLOR = Color(0xff007dff);
110 constexpr Color SYSTEM_SELECT_BACKGROUND_COLOR = Color(0x33007dff);
111 
112 const auto MAGNIFIER_ANIMATION_CURVE = AceType::MakeRefPtr<InterpolatingSpring>(0.0f, 1.0f, 228.0f, 30.0f);
113 constexpr int32_t MAGNIFIER_ANIMATION_DURATION = 100;
114 
115 constexpr int32_t ERROR_BAD_PARAMETERS = -1;
116 constexpr char PREVIEW_STYLE_NORMAL[] = "normal";
117 constexpr char PREVIEW_STYLE_UNDERLINE[] = "underline";
118 const std::u16string LINE_SEPARATOR = u"\n";
119 // hen do ai anaylsis, we should limit the left an right limit of the string
120 constexpr static int32_t AI_TEXT_RANGE_LEFT = 50;
121 constexpr static int32_t AI_TEXT_RANGE_RIGHT = 50;
122 constexpr static int32_t NONE_SELECT_TYPE = -1;
123 
124 constexpr float RICH_DEFAULT_SHADOW_COLOR = 0x33000000;
125 constexpr float RICH_DEFAULT_ELEVATION = 120.0f;
126 constexpr int32_t CUSTOM_CONTENT_LENGTH = 1;
127 constexpr int32_t SYMBOL_CONTENT_LENGTH = 2;
128 constexpr int32_t PLACEHOLDER_LENGTH = 6;
129 const std::u16string PLACEHOLDER_MARK = u"![id";
130 const std::string SPACE_CHARS = "^\\s+|\\s+$";
131 const static std::regex REMOVE_SPACE_CHARS{SPACE_CHARS};
__anon3068b39a0202(const RefPtr<SpanItem>& span)132 const auto URL_SPAN_FILTER = [](const RefPtr<SpanItem>& span){ return (span->urlOnRelease); };
133 } // namespace
134 
RichEditorPattern()135 RichEditorPattern::RichEditorPattern() :
136 #ifndef ACE_UNITTEST
137     isAPI14Plus(Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_FOURTEEN)),
138 #else
139     isAPI14Plus(true),
140 #endif
141     isAPI16Plus(Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_SIXTEEN)),
142     isAPI18Plus(Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)),
143     isAPI20Plus(Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWENTY))
144 {
145     selectOverlay_ = AceType::MakeRefPtr<RichEditorSelectOverlay>(WeakClaim(this));
146     magnifierController_ = MakeRefPtr<MagnifierController>(WeakClaim(this));
147     styledString_ = MakeRefPtr<MutableSpanString>(u"");
148     styledString_->SetSpanWatcher(WeakClaim(this));
149     twinklingInterval_ = SystemProperties::GetDebugEnabled()
150         ? RICH_EDITOR_TWINKLING_INTERVAL_MS_DEBUG : RICH_EDITOR_TWINKLING_INTERVAL_MS;
151     floatingCaretState_.UpdateOriginCaretColor(GetDisplayColorMode());
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     if (GetTextContentLength() > maxLength_.value_or(INT_MAX)) {
164         TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "SetStyledString: Reach the maxLength. maxLength=%{public}d", maxLength_.value_or(INT_MAX));
165         return;
166     }
167     CHECK_NULL_VOID(value && styledString_);
168     auto subValue = value;
169     if (value->GetLength() != styledString_->GetLength() && value->GetLength() > maxLength_.value_or(INT_MAX)) {
170         auto subLength = CalculateTruncationLength(value->GetU16string(), maxLength_.value_or(INT_MAX));
171         if (subLength == 0) {
172             IF_TRUE(IsPreviewTextInputting() && !previewTextRecord_.previewTextExiting, NotifyExitTextPreview(true));
173             return;
174         }
175         subValue = value->GetSubSpanString(0, subLength);
176     }
177     IF_TRUE(IsPreviewTextInputting() && !previewTextRecord_.previewTextExiting, NotifyExitTextPreview(true));
178     CloseSelectOverlay();
179     ResetSelection();
180     styledString_->RemoveCustomSpan();
181     auto length = styledString_->GetLength();
182     styledString_->ReplaceSpanString(0, length, subValue);
183     SetCaretPosition(styledString_->GetLength());
184     SetNeedMoveCaretToContentRect();
185     auto host = GetHost();
186     CHECK_NULL_VOID(host);
187     styledString_->AddCustomSpan();
188     styledString_->SetFramNode(host);
189     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
190     ForceTriggerAvoidOnCaretChange();
191 }
192 
UpdateSpanItems(const std::list<RefPtr<NG::SpanItem>> & spanItems)193 void RichEditorPattern::UpdateSpanItems(const std::list<RefPtr<NG::SpanItem>>& spanItems)
194 {
195     SetSpanItemChildren(spanItems);
196     ProcessStyledString();
197 }
198 
ProcessStyledString()199 void RichEditorPattern::ProcessStyledString()
200 {
201     auto host = GetHost();
202     CHECK_NULL_VOID(host);
203     std::u16string textCache = textForDisplay_;
204     textForDisplay_.clear();
205     dataDetectorAdapter_->textForAI_.clear();
206     host->Clean();
207     RemoveEmptySpanItems();
208     hasUrlSpan_ = false;
209     for (const auto& span : spans_) {
210         if (!span) {
211             continue;
212         }
213         auto imageSpan = DynamicCast<ImageSpanItem>(span);
214         if (imageSpan) {
215             MountImageNode(imageSpan);
216             dataDetectorAdapter_->textForAI_ += u'\n';
217         } else {
218             dataDetectorAdapter_->textForAI_ += span->content;
219         }
220         textForDisplay_ += span->content;
221         auto [spanStart, spanEnd] = span->interval;
222         span->rangeStart = spanStart;
223         span->position = spanEnd;
224 
225         if (span->urlOnRelease) {
226             hasUrlSpan_ = true;
227         }
228     }
229     if (textForDisplay_ != textCache) {
230         dataDetectorAdapter_->aiDetectInitialized_ = false;
231     }
232     if (CanStartAITask() && !dataDetectorAdapter_->aiDetectInitialized_) {
233         dataDetectorAdapter_->StartAITask();
234     }
235 }
236 
MountImageNode(const RefPtr<ImageSpanItem> & imageItem)237 void RichEditorPattern::MountImageNode(const RefPtr<ImageSpanItem>& imageItem)
238 {
239     auto host = GetHost();
240     CHECK_NULL_VOID(host);
241     CHECK_NULL_VOID(imageItem);
242     auto options = imageItem->options;
243     auto imageNode = ImageSpanNode::GetOrCreateSpanNode(V2::IMAGE_ETS_TAG,
244         ElementRegister::GetInstance()->MakeUniqueId(), []() { return AceType::MakeRefPtr<ImagePattern>(); });
245     auto pattern = imageNode->GetPattern<ImagePattern>();
246     CHECK_NULL_VOID(pattern);
247     if (options.imagePixelMap.has_value()) {
248         pattern->SetSyncLoad(true);
249     } else if (options.imageAttribute.has_value()) {
250         pattern->SetSyncLoad(options.imageAttribute.value().syncLoad);
251     }
252     auto index = host->GetChildren().size();
253     imageNodes.push_back(imageNode);
254     imageNode->MountToParent(host, index);
255     HandleImageDrag(imageNode);
256     SetImageLayoutProperty(imageNode, options);
257     imageItem->imageNodeId = imageNode->GetId();
258     imageNode->SetImageItem(imageItem);
259 }
260 
SetImageLayoutProperty(RefPtr<ImageSpanNode> imageNode,const ImageSpanOptions & options)261 void RichEditorPattern::SetImageLayoutProperty(RefPtr<ImageSpanNode> imageNode, const ImageSpanOptions& options)
262 {
263     CHECK_NULL_VOID(imageNode);
264     auto imageLayoutProperty = imageNode->GetLayoutProperty<ImageLayoutProperty>();
265     CHECK_NULL_VOID(imageLayoutProperty);
266     std::function<ImageSourceInfo()> createSourceInfoFunc = CreateImageSourceInfo(options);
267     imageLayoutProperty->UpdateImageSourceInfo(createSourceInfoFunc());
268     if (options.imageAttribute.has_value()) {
269         auto imgAttr = options.imageAttribute.value();
270         if (imgAttr.size.has_value()) {
271             imageLayoutProperty->UpdateUserDefinedIdealSize(imgAttr.size->GetSize());
272         }
273         if (imgAttr.verticalAlign.has_value()) {
274             imageLayoutProperty->UpdateVerticalAlign(imgAttr.verticalAlign.value());
275         }
276         if (imgAttr.objectFit.has_value()) {
277             imageLayoutProperty->UpdateImageFit(imgAttr.objectFit.value());
278         }
279         if (imgAttr.marginProp.has_value()) {
280             imageLayoutProperty->UpdateMargin(imgAttr.marginProp.value());
281         }
282         if (imgAttr.paddingProp.has_value()) {
283             imageLayoutProperty->UpdatePadding(imgAttr.paddingProp.value());
284         }
285         if (imgAttr.borderRadius.has_value()) {
286             auto imageRenderCtx = imageNode->GetRenderContext();
287             imageRenderCtx->UpdateBorderRadius(imgAttr.borderRadius.value());
288             imageRenderCtx->SetClipToBounds(true);
289         }
290         auto paintProperty = imageNode->GetPaintProperty<ImageRenderProperty>();
291         if (imgAttr.colorFilterMatrix.has_value() && paintProperty) {
292             paintProperty->UpdateColorFilter(imgAttr.colorFilterMatrix.value());
293             paintProperty->ResetDrawingColorFilter();
294         } else if (imgAttr.drawingColorFilter.has_value() && paintProperty) {
295             paintProperty->UpdateDrawingColorFilter(imgAttr.drawingColorFilter.value());
296             paintProperty->ResetColorFilter();
297         }
298     }
299     imageNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
300     imageNode->MarkModifyDone();
301     IF_PRESENT(oneStepDragController_, MarkDirtyNode(WeakClaim(RawPtr(imageNode))));
302 }
303 
InsertValueInStyledStringMore(RefPtr<SpanString> insertStyledString,int32_t changeStart,int32_t changeLength,std::u16string & subValue,bool needReplaceInTextPreview)304 void RichEditorPattern::InsertValueInStyledStringMore(RefPtr<SpanString> insertStyledString, int32_t changeStart,
305     int32_t changeLength, std::u16string& subValue, bool needReplaceInTextPreview)
306 {
307     bool isSingleHandleMoving = selectOverlay_->IsSingleHandleMoving();
308     if (textSelector_.IsValid()) {
309         ResetSelection();
310     }
311     CloseSelectOverlay();
312     if (insertStyledString) {
313         styledString_->InsertSpanString(changeStart, insertStyledString);
314     } else {
315         styledString_->InsertString(changeStart, subValue);
316     }
317     SetCaretPosition(changeStart + static_cast<int32_t>(subValue.length()), !needReplaceInTextPreview);
318     IF_TRUE((!caretVisible_ || isSingleHandleMoving) && HasFocus(), StartTwinkling());
319     auto host = GetHost();
320     CHECK_NULL_VOID(host);
321     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
322     host->MarkModifyDone();
323     AfterStyledStringChange(changeStart, changeLength, subValue);
324 }
325 
InsertValueInStyledString(const std::u16string & insertValue,bool calledByImf)326 void RichEditorPattern::InsertValueInStyledString(const std::u16string& insertValue, bool calledByImf)
327 {
328     CHECK_NULL_VOID(styledString_);
329     IF_TRUE(calledByImf && previewTextRecord_.IsValid(), FinishTextPreviewInner());
330     int32_t changeStart = caretPosition_;
331     int32_t changeLength = 0;
332     if (textSelector_.IsValid()) {
333         changeStart = textSelector_.GetTextStart();
334         changeLength = textSelector_.GetTextEnd() - changeStart;
335     }
336     auto subValue = insertValue;
337     if (!ProcessTextTruncationOperation(subValue, calledByImf)) {
338         return;
339     }
340     auto needReplaceInTextPreview = (previewTextRecord_.needReplacePreviewText || previewTextRecord_.needReplaceText) &&
341                                previewTextRecord_.replacedRange.end - previewTextRecord_.replacedRange.start > 0;
342     if (needReplaceInTextPreview) {
343         changeStart= previewTextRecord_.replacedRange.start;
344         changeLength = previewTextRecord_.replacedRange.end - previewTextRecord_.replacedRange.start;
345     }
346     bool isPreventChange = false;
347     RefPtr<SpanString> insertStyledString = nullptr;
348     if (typingStyle_.has_value() && typingTextStyle_.has_value()) {
349         insertStyledString = CreateStyledStringByTextStyle(subValue, typingStyle_.value(), typingTextStyle_.value());
350         isPreventChange = !BeforeStyledStringChange(changeStart, changeLength, insertStyledString);
351     } else {
352         isPreventChange = !BeforeStyledStringChange(changeStart, changeLength, subValue);
353     }
354     CHECK_NULL_VOID(!isPreventChange || previewTextRecord_.needReplacePreviewText);
355     if (changeLength > 0 && (subValue.length() > 0 || !calledByImf)) {
356         auto start = needReplaceInTextPreview ? previewTextRecord_.replacedRange.start : caretPosition_;
357         auto isUpdateCaret = !needReplaceInTextPreview;
358         DeleteValueInStyledString(start, changeLength, false, isUpdateCaret);
359     }
360     InsertValueInStyledStringMore(insertStyledString, changeStart, changeLength, subValue, needReplaceInTextPreview);
361 }
362 
CreateStyledStringByTextStyle(const std::u16string & insertValue,const struct UpdateSpanStyle & updateSpanStyle,const TextStyle & textStyle)363 RefPtr<SpanString> RichEditorPattern::CreateStyledStringByTextStyle(
364     const std::u16string& insertValue, const struct UpdateSpanStyle& updateSpanStyle, const TextStyle& textStyle)
365 {
366     auto styledString = AceType::MakeRefPtr<SpanString>(insertValue);
367     auto length = styledString->GetLength();
368     std::vector<RefPtr<SpanBase>> spans;
369     spans.push_back(CreateFontSpanByTextStyle(updateSpanStyle, textStyle, length));
370     spans.push_back(CreateDecorationSpanByTextStyle(updateSpanStyle, textStyle, length));
371     if (updateSpanStyle.updateTextShadows.has_value()) {
372         spans.push_back(AceType::MakeRefPtr<TextShadowSpan>(textStyle.GetTextShadows(), 0, length));
373     }
374     if (updateSpanStyle.updateLineHeight.has_value()) {
375         spans.push_back(AceType::MakeRefPtr<LineHeightSpan>(textStyle.GetLineHeight(), 0, length));
376     }
377     if (updateSpanStyle.updateHalfLeading.has_value()) {
378         spans.push_back(AceType::MakeRefPtr<HalfLeadingSpan>(textStyle.GetHalfLeading(), 0, length));
379     }
380     if (updateSpanStyle.updateLetterSpacing.has_value()) {
381         spans.push_back(AceType::MakeRefPtr<LetterSpacingSpan>(textStyle.GetLetterSpacing(), 0, length));
382     }
383     if (updateSpanStyle.updateTextBackgroundStyle.has_value()) {
384         spans.push_back(AceType::MakeRefPtr<BackgroundColorSpan>(textStyle.GetTextBackgroundStyle(), 0, length));
385     }
386     styledString->BindWithSpans(spans);
387     return styledString;
388 }
389 
CreateFontSpanByTextStyle(const struct UpdateSpanStyle & updateSpanStyle,const TextStyle & textStyle,int32_t length)390 RefPtr<FontSpan> RichEditorPattern::CreateFontSpanByTextStyle(
391     const struct UpdateSpanStyle& updateSpanStyle, const TextStyle& textStyle, int32_t length)
392 {
393     Font font;
394     if (updateSpanStyle.updateFontWeight.has_value()) {
395         font.fontWeight = textStyle.GetFontWeight();
396     }
397     if (updateSpanStyle.updateFontSize.has_value()) {
398         font.fontSize = textStyle.GetFontSize();
399     }
400     if (updateSpanStyle.updateItalicFontStyle.has_value()) {
401         font.fontStyle = textStyle.GetFontStyle();
402     }
403     if (updateSpanStyle.updateFontFamily.has_value()) {
404         font.fontFamilies = textStyle.GetFontFamilies();
405     }
406     if (updateSpanStyle.updateTextColor.has_value()) {
407         font.fontColor = textStyle.GetTextColor();
408     }
409     return AceType::MakeRefPtr<FontSpan>(font, 0, length);
410 }
411 
CreateDecorationSpanByTextStyle(const struct UpdateSpanStyle & updateSpanStyle,const TextStyle & textStyle,int32_t length)412 RefPtr<DecorationSpan> RichEditorPattern::CreateDecorationSpanByTextStyle(
413     const struct UpdateSpanStyle& updateSpanStyle, const TextStyle& textStyle, int32_t length)
414 {
415     TextDecoration type = TextDecoration::NONE;
416     std::optional<Color> colorOption;
417     std::optional<TextDecorationStyle> styleOption;
418     if (updateSpanStyle.updateTextDecoration.has_value()) {
419         type = textStyle.GetTextDecoration();
420     }
421     if (updateSpanStyle.updateTextDecorationColor.has_value()) {
422         colorOption = textStyle.GetTextDecorationColor();
423     }
424     if (updateSpanStyle.updateTextDecorationStyle.has_value()) {
425         styleOption = textStyle.GetTextDecorationStyle();
426     }
427     return AceType::MakeRefPtr<DecorationSpan>(type, colorOption, styleOption, 0, length);
428 }
429 
DeleteBackwardInStyledString(int32_t length)430 void RichEditorPattern::DeleteBackwardInStyledString(int32_t length)
431 {
432     DeleteValueInStyledString(caretPosition_ - length, length);
433 }
434 
DeleteForwardInStyledString(int32_t length,bool isIME)435 void RichEditorPattern::DeleteForwardInStyledString(int32_t length, bool isIME)
436 {
437     DeleteValueInStyledString(caretPosition_, length, isIME);
438 }
439 
DeleteValueInStyledString(int32_t start,int32_t length,bool isIME,bool isUpdateCaret)440 void RichEditorPattern::DeleteValueInStyledString(int32_t start, int32_t length, bool isIME, bool isUpdateCaret)
441 {
442     CHECK_NULL_VOID(styledString_);
443     if (!textSelector_.SelectNothing()) {
444         start = textSelector_.GetTextStart();
445         length = textSelector_.GetTextEnd() - textSelector_.GetTextStart();
446     }
447     auto range = TextEmojiProcessor::CalSubU16stringRange(start, length, styledString_->GetU16string(), true, true);
448     start = range.startIndex;
449     length = range.endIndex - range.startIndex;
450     bool isPreventChange = isIME && !BeforeStyledStringChange(start, length, u"");
451     TAG_LOGI(AceLogTag::ACE_RICH_TEXT,
452         "deleteInSS, start=%{public}d, length=%{public}d, isPreventChange=%{public}d, "
453         "isPreviewTextInputting=%{public}d",
454         start, length, isPreventChange, IsPreviewTextInputting());
455     CHECK_NULL_VOID(!isPreventChange || IsPreviewTextInputting());
456     bool isSingleHandleMoving = selectOverlay_->IsSingleHandleMoving();
457     if (textSelector_.IsValid()) {
458         CloseSelectOverlay();
459         ResetSelection();
460     }
461     styledString_->RemoveString(start, length);
462     if (isUpdateCaret) {
463         SetCaretPosition(start, !isModifyingContent_);
464     }
465     if ((!caretVisible_ || isSingleHandleMoving) && HasFocus()) {
466         StartTwinkling();
467         if (!isEditing_ && isIME) {
468             TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "previewLongPress_ is true, before RequestKeyboard");
469             RequestKeyboard(false, true, true);
470             HandleOnEditChanged(true);
471             previewLongPress_ = false;
472         }
473     }
474     if (isIME) {
475         AfterStyledStringChange(start, length, u"");
476     }
477     auto host = GetHost();
478     CHECK_NULL_VOID(host);
479     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
480     host->MarkModifyDone();
481 }
482 
BeforeStyledStringChange(int32_t start,int32_t length,const std::u16string & string)483 bool RichEditorPattern::BeforeStyledStringChange(int32_t start, int32_t length, const std::u16string& string)
484 {
485     auto eventHub = GetEventHub<RichEditorEventHub>();
486     CHECK_NULL_RETURN(eventHub, true);
487     CHECK_NULL_RETURN(eventHub->HasOnStyledStringWillChange(), true);
488     auto styledString = AceType::MakeRefPtr<SpanString>(string);
489     auto stringLength = styledString->GetLength();
490     auto changeStart = std::clamp(start, 0, GetTextContentLength());
491     if (stringLength != 0) {
492         auto lastStyles = styledString_->GetSpans(changeStart - 1, 1);
493         for (auto && style : lastStyles) {
494             if (!style) {
495                 continue;
496             }
497             auto spanType = style->GetSpanType();
498             if (spanType == SpanType::Image || spanType == SpanType::CustomSpan) {
499                 continue;
500             }
501             auto span = style->GetSubSpan(0, stringLength);
502             styledString->AddSpan(span);
503         }
504     }
505     return BeforeStyledStringChange(changeStart, length, styledString);
506 }
507 
BeforeStyledStringChange(int32_t start,int32_t length,const RefPtr<SpanString> & styledString)508 bool RichEditorPattern::BeforeStyledStringChange(int32_t start, int32_t length, const RefPtr<SpanString>& styledString)
509 {
510     auto eventHub = GetEventHub<RichEditorEventHub>();
511     CHECK_NULL_RETURN(eventHub, true);
512     CHECK_NULL_RETURN(eventHub->HasOnStyledStringWillChange(), true);
513     auto replaceMentString = AceType::MakeRefPtr<MutableSpanString>(u"");
514     replaceMentString->AppendSpanString(styledString);
515     StyledStringChangeValue changeValue;
516     auto changeStart = std::clamp(start, 0, GetTextContentLength());
517     auto changeEnd = std::clamp(changeStart + length, 0, GetTextContentLength());
518     changeValue.SetRangeBefore({ changeStart, changeEnd });
519     changeValue.SetReplacementString(replaceMentString);
520     if (!previewTextRecord_.newPreviewContent.empty()) {
521         auto previewTextStyledString = AceType::MakeRefPtr<MutableSpanString>(previewTextRecord_.newPreviewContent);
522         changeValue.SetPreviewText(previewTextStyledString);
523     }
524     return eventHub->FireOnStyledStringWillChange(changeValue);
525 }
526 
AfterStyledStringChange(int32_t start,int32_t length,const std::u16string & string)527 void RichEditorPattern::AfterStyledStringChange(int32_t start, int32_t length, const std::u16string& string)
528 {
529     auto eventHub = GetEventHub<RichEditorEventHub>();
530     CHECK_NULL_VOID(eventHub);
531     if (eventHub->HasOnStyledStringDidChange()) {
532         StyledStringChangeValue changeValue;
533         auto changeStart = std::clamp(start, 0, GetTextContentLength());
534         auto changeEnd = changeStart + length;
535         auto stringLength = static_cast<int32_t>(string.length());
536         auto stringEnd = changeStart + stringLength;
537         changeValue.SetRangeBefore({ changeStart, changeEnd });
538         changeValue.SetRangeAfter({ changeStart, stringEnd });
539         eventHub->FireOnStyledStringDidChange(changeValue);
540     }
541     ForceTriggerAvoidOnCaretChange();
542 }
543 
OnModifyDone()544 void RichEditorPattern::OnModifyDone()
545 {
546     Pattern::CheckLocalized();
547     auto host = GetHost();
548     CHECK_NULL_VOID(host);
549     auto layoutProperty = host->GetLayoutProperty<TextLayoutProperty>();
550     copyOption_ = layoutProperty->GetCopyOption().value_or(CopyOptions::Distributed);
551     auto context = host->GetContext();
552     CHECK_NULL_VOID(context);
553     ResetKeyboardIfNeed();
554     context->AddOnAreaChangeNode(host->GetId());
555     if (!clipboard_ && context) {
556         clipboard_ = ClipboardProxy::GetInstance()->GetClipboard(context->GetTaskExecutor());
557     }
558     instanceId_ = context->GetInstanceId();
559     InitMouseEvent();
560     InitAISpanHoverEvent();
561     auto focusHub = host->GetOrCreateFocusHub();
562     CHECK_NULL_VOID(focusHub);
563     InitFocusEvent(focusHub);
564     auto gestureEventHub = host->GetOrCreateGestureEventHub();
565     InitClickEvent(gestureEventHub);
566     InitLongPressEvent(gestureEventHub);
567     InitTouchEvent();
568     InitPanEvent();
569     HandleEnabled();
570     ProcessInnerPadding();
571     InitScrollablePattern();
572     SetAccessibilityAction();
573     selectOverlay_->SetMenuTranslateIsSupport(IsShowTranslate());
574     selectOverlay_->SetIsSupportMenuSearch(IsShowSearch());
575     if (host->IsDraggable()) {
576         InitDragDropEvent();
577         AddDragFrameNodeToManager(host);
578     } else {
579         ClearDragDropEvent();
580         RemoveDragFrameNodeFromManager(host);
581     }
582     Register2DragDropManager();
583     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
584 
585     auto eventHub = host->GetEventHub<EventHub>();
586     CHECK_NULL_VOID(eventHub);
587     bool enabledCache = eventHub->IsEnabled();
588     if (textDetectEnable_ && enabledCache != enabled_) {
589         enabled_ = enabledCache;
590         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
591     }
592     SetIsEnableSubWindowMenu();
593 }
594 
HandleEnabled()595 void RichEditorPattern::HandleEnabled()
596 {
597     auto host = GetHost();
598     CHECK_NULL_VOID(host);
599     auto renderContext = host->GetRenderContext();
600     CHECK_NULL_VOID(renderContext);
601     if (IsDisabled()) {
602         auto richEditorTheme = GetTheme<RichEditorTheme>();
603         CHECK_NULL_VOID(richEditorTheme);
604         auto disabledAlpha = richEditorTheme->GetDisabledAlpha();
605         renderContext->OnOpacityUpdate(disabledAlpha);
606     } else {
607         auto opacity = renderContext->GetOpacity().value_or(1.0);
608         renderContext->OnOpacityUpdate(opacity);
609     }
610 }
611 
BeforeCreateLayoutWrapper()612 void RichEditorPattern::BeforeCreateLayoutWrapper()
613 {
614     ACE_SCOPED_TRACE("RichEditorBeforeCreateLayoutWrapper");
615     if (!isSpanStringMode_) {
616         TextPattern::PreCreateLayoutWrapper();
617         hasUrlSpan_ = std::any_of(spans_.begin(), spans_.end(), URL_SPAN_FILTER);
618     } else if (contentMod_) {
619         contentMod_->ContentChange();
620     }
621 }
622 
UpdateMagnifierStateAfterLayout(bool frameSizeChange)623 void RichEditorPattern::UpdateMagnifierStateAfterLayout(bool frameSizeChange)
624 {
625     CHECK_NULL_VOID(!selectOverlay_->GetIsHandleMoving());
626     if (frameSizeChange && magnifierController_ && magnifierController_->GetMagnifierNodeExist()) {
627         ResetTouchSelectState();
628         ResetTouchAndMoveCaretState();
629         magnifierController_->RemoveMagnifierFrameNode();
630     }
631 }
632 
UpdateGestureHotZone(const RefPtr<LayoutWrapper> & dirty)633 void RichEditorPattern::UpdateGestureHotZone(const RefPtr<LayoutWrapper>& dirty)
634 {
635     const auto& geometryNode = dirty->GetGeometryNode();
636     auto paddingSize = geometryNode->GetPaddingSize();
637     auto paddingOffset = geometryNode->GetPaddingOffset() - geometryNode->GetFrameOffset();
638 
639     auto hotZoneWidth = Dimension(paddingSize.Width());
640     auto hotZoneHeight = Dimension(paddingSize.Height());
641     auto hotZoneOffset = DimensionOffset(Offset(paddingOffset.GetX(), paddingOffset.GetY()));
642 
643     auto gestureHub = GetGestureEventHub();
644     CHECK_NULL_VOID(gestureHub);
645     gestureHub->SetResponseRegion({ { hotZoneWidth, hotZoneHeight, hotZoneOffset } });
646 }
647 
ClearOnFocusTextField(FrameNode * node)648 void RichEditorPattern::ClearOnFocusTextField(FrameNode* node)
649 {
650     CHECK_NULL_VOID(isAPI14Plus && node);
651     auto context = node->GetContextRefPtr();
652     CHECK_NULL_VOID(context);
653     auto textFieldManager = DynamicCast<TextFieldManagerNG>(context->GetTextFieldManager());
654     IF_PRESENT(textFieldManager, ClearOnFocusTextField(node->GetId()));
655 }
656 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)657 bool RichEditorPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
658 {
659     CHECK_NULL_RETURN(!config.skipMeasure && !dirty->SkipMeasureContent(), false);
660     auto originalFrameRect = frameRect_;
661     frameRect_ = dirty->GetGeometryNode()->GetFrameRect();
662     auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
663     CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
664     auto richEditorLayoutAlgorithm =
665         DynamicCast<RichEditorLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
666     CHECK_NULL_RETURN(richEditorLayoutAlgorithm, false);
667     UpdateParentOffsetAndOverlay();
668     richTextRect_ = richEditorLayoutAlgorithm->GetTextRect();
669     UpdateTextFieldManager(Offset(parentGlobalOffset_.GetX(), parentGlobalOffset_.GetY()), frameRect_.Height());
670     bool ret = TextPattern::OnDirtyLayoutWrapperSwap(dirty, config);
671     UpdateScrollStateAfterLayout(config.frameSizeChange);
672     UpdateMagnifierStateAfterLayout(config.frameSizeChange);
673     IF_TRUE(!isRichEditorInit_, FireOnReady());
674     MoveCaretOnLayoutSwap();
675     HandleTasksOnLayoutSwap();
676     HandleSelectOverlayOnLayoutSwap();
677     IF_TRUE(originalFrameRect.GetSize() != frameRect_.GetSize(), {
678         TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "frame size change");
679         TriggerAvoidOnCaretChangeNextFrame();
680     });
681     IF_TRUE(!isModifyingContent_, UpdateCaretInfoToController());
682     auto host = GetHost();
683     CHECK_NULL_RETURN(host, ret);
684     auto context = host->GetRenderContext();
685     CHECK_NULL_RETURN(context, ret);
686     if (context->GetClipEdge().has_value()) {
687         auto geometryNode = host->GetGeometryNode();
688         auto frameOffset = geometryNode->GetFrameOffset();
689         auto frameSize = geometryNode->GetFrameSize();
690         auto height = static_cast<float>(paragraphs_.GetHeight() + std::fabs(baselineOffset_));
691         if (!context->GetClipEdge().value() && LessNotEqual(frameSize.Height(), height)) {
692             RectF boundsRect(frameOffset.GetX(), frameOffset.GetY(), frameSize.Width(), height);
693             CHECK_NULL_RETURN(overlayMod_, ret);
694             overlayMod_->SetBoundsRect(boundsRect);
695         }
696     }
697     caretUpdateType_ = CaretUpdateType::NONE;
698     IF_PRESENT(oneStepDragController_, HandleDirtyNodes());
699     UpdateGestureHotZone(dirty);
700     if (afterDragSelect_) {
701         UpdateSelectionAndHandleVisibility();
702         afterDragSelect_ = false;
703     }
704     releaseInDrop_ = false;
705     return ret;
706 }
707 
UpdateSelectionAndHandleVisibility()708 void RichEditorPattern::UpdateSelectionAndHandleVisibility()
709 {
710     auto start = recoverStart_;
711     auto end = recoverEnd_;
712     if (textSelector_.GetStart() == start && textSelector_.GetEnd() == end) {
713         return;
714     }
715     auto host = GetHost();
716     CHECK_NULL_VOID(host);
717     if (isMouseOrTouchPad(sourceTool_) && releaseInDrop_) {
718         start = lastCaretPosition_;
719         end = insertValueLength_ + lastCaretPosition_;
720     }
721     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "UpdateSelectionAndHandleVisibility range=[%{public}d--%{public}d]", start, end);
722     textSelector_.Update(start, end);
723 
724     if (!isMouseOrTouchPad(sourceTool_)) {
725         if (!selectOverlay_->IsBothHandlesShow() && !selectOverlay_->SelectOverlayIsCreating()) {
726             showSelect_ = true;
727             host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
728             CalculateHandleOffsetAndShowOverlay();
729             selectOverlay_->ProcessOverlay({.menuIsShow = false, .animation = false});
730         }
731     }
732     FireOnSelectionChange(start, end, true);
733 }
734 
HandleSelectOverlayOnLayoutSwap()735 void RichEditorPattern::HandleSelectOverlayOnLayoutSwap()
736 {
737     bool needToRefreshSelectOverlay = textSelector_.IsValid() && SelectOverlayIsOn() && !IsPreviewTextInputting();
738     CHECK_NULL_VOID(needToRefreshSelectOverlay);
739     auto overlayTask = [weak = WeakClaim(this)]() {
740         auto pattern = weak.Upgrade();
741         CHECK_NULL_VOID(pattern);
742         auto selectOverlay = pattern->selectOverlay_;
743         IF_PRESENT(selectOverlay, UpdateSelectOverlayOnAreaChanged());
744     };
745     if (AnimationUtils::IsImplicitAnimationOpen()) {
746         auto pipeline = GetContext();
747         CHECK_NULL_VOID(pipeline);
748         pipeline->AddAfterRenderTask(overlayTask);
749     } else {
750         overlayTask();
751     }
752 }
753 
FireOnReady()754 void RichEditorPattern::FireOnReady()
755 {
756     auto eventHub = GetEventHub<RichEditorEventHub>();
757     CHECK_NULL_VOID(eventHub);
758     eventHub->FireOnReady();
759     ClearOperationRecords();
760     isFirstCallOnReady_ = true;
761     isRichEditorInit_ = true;
762 }
763 
MoveCaretOnLayoutSwap()764 void RichEditorPattern::MoveCaretOnLayoutSwap()
765 {
766     MoveCaretAfterTextChange();
767     if (needMoveCaretToContentRect_ || isEditing_) {
768         MoveCaretToContentRect();
769         needMoveCaretToContentRect_ = false;
770     }
771 }
772 
CreateImageSourceInfo(const ImageSpanOptions & options)773 std::function<ImageSourceInfo()> RichEditorPattern::CreateImageSourceInfo(const ImageSpanOptions& options)
774 {
775     std::string src;
776     RefPtr<PixelMap> pixMap = nullptr;
777     std::string bundleName;
778     std::string moduleName;
779     if (options.image.has_value()) {
780         src = options.image.value();
781     }
782     if (options.imagePixelMap.has_value()) {
783         pixMap = options.imagePixelMap.value();
784     }
785     if (options.bundleName.has_value()) {
786         bundleName = options.bundleName.value();
787     }
788     if (options.moduleName.has_value()) {
789         moduleName = options.moduleName.value();
790     }
791     auto createSourceInfoFunc = [src, noPixMap = !options.imagePixelMap.has_value(),
792                                     isUriPureNumber = options.isUriPureNumber.value_or(false), pixMap, bundleName,
793                                     moduleName]() -> ImageSourceInfo {
794         ImageSourceInfo info;
795 #if defined(PIXEL_MAP_SUPPORTED)
796         if (noPixMap) {
797             info = ImageSourceInfo { src, bundleName, moduleName };
798         } else {
799             info = ImageSourceInfo(pixMap);
800         }
801 #else
802         info = ImageSourceInfo { src, bundleName, moduleName };
803 #endif
804         info.SetIsUriPureNumber(isUriPureNumber);
805         return info;
806     };
807     return std::move(createSourceInfoFunc);
808 }
809 
GetTextContentLength()810 int32_t RichEditorPattern::GetTextContentLength()
811 {
812     if (isSpanStringMode_ && styledString_) {
813         return styledString_->GetLength();
814     }
815     if (!spans_.empty()) {
816         auto it = spans_.rbegin();
817         return (*it)->position;
818     }
819     return 0;
820 }
821 
SetPreviewMenuParam(TextSpanType spanType,std::function<void ()> & builder,const SelectMenuParam & menuParam)822 void RichEditorPattern::SetPreviewMenuParam(TextSpanType spanType, std::function<void()>& builder, const SelectMenuParam& menuParam)
823 {
824     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "SetPreviewMenuParam, spanType=%{public}d", spanType);
825     if (!oneStepDragController_) {
826         oneStepDragController_ = std::make_unique<OneStepDragController>(WeakClaim(this));
827     }
828     oneStepDragController_->SetMenuParam(spanType, builder, menuParam);
829 }
830 
HandleImageDrag(const RefPtr<ImageSpanNode> & imageNode)831 void RichEditorPattern::HandleImageDrag(const RefPtr<ImageSpanNode>& imageNode)
832 {
833     DisableDrag(imageNode);
834     IF_PRESENT(oneStepDragController_, EnableOneStepDrag(TextSpanType::IMAGE, imageNode));
835 }
836 
DisableDrag(const RefPtr<ImageSpanNode> & imageNode)837 void RichEditorPattern::DisableDrag(const RefPtr<ImageSpanNode>& imageNode)
838 {
839     // Disable the image itself event
840     imageNode->SetDraggable(false);
841     auto gesture = imageNode->GetOrCreateGestureEventHub();
842     CHECK_NULL_VOID(gesture);
843     gesture->InitDragDropEvent();
844     gesture->SetDragEvent(nullptr, { PanDirection::DOWN }, 0, Dimension(0));
845 }
846 
SetGestureOptions(UserGestureOptions options,RefPtr<SpanItem> spanItem)847 void RichEditorPattern::SetGestureOptions(UserGestureOptions options, RefPtr<SpanItem> spanItem)
848 {
849     IF_TRUE(options.onClick, spanItem->SetOnClickEvent(std::move(options.onClick)));
850     IF_TRUE(options.onLongPress, spanItem->SetLongPressEvent(std::move(options.onLongPress)));
851     IF_TRUE(options.onDoubleClick, spanItem->SetDoubleClickEvent(std::move(options.onDoubleClick)));
852 }
853 
AddSpanHoverEvent(RefPtr<SpanItem> spanItem,const RefPtr<FrameNode> & frameNode,const SpanOptionBase & options)854 void RichEditorPattern::AddSpanHoverEvent(
855     RefPtr<SpanItem> spanItem, const RefPtr<FrameNode>& frameNode, const SpanOptionBase& options)
856 {
857     auto onHoverFunc = options.userMouseOption.onHover;
858     CHECK_NULL_VOID(spanItem && frameNode && onHoverFunc);
859     auto tag = frameNode->GetTag();
860     spanItem->SetHoverEvent(std::move(onHoverFunc));
861     auto eventHub = frameNode->GetEventHub<EventHub>();
862     CHECK_NULL_VOID(eventHub);
863     auto inputHub = eventHub->GetOrCreateInputEventHub();
864     CHECK_NULL_VOID(inputHub);
865     auto hoverTask = [weak = WeakClaim(Referenced::RawPtr(spanItem)), tag](bool isHover, HoverInfo& info) {
866         auto item = weak.Upgrade();
867         if (item && item->onHover) {
868             TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "[%{public}s] onHover status :[%{public}d]", tag.c_str(), isHover);
869             item->onHover(isHover, info);
870         }
871     };
872     auto hoverEvent = MakeRefPtr<InputEvent>(std::move(hoverTask));
873     inputHub->AddOnHoverEvent(hoverEvent);
874 }
875 
AddImageSpan(const ImageSpanOptions & options,bool isPaste,int32_t index,bool updateCaret)876 int32_t RichEditorPattern::AddImageSpan(const ImageSpanOptions& options, bool isPaste, int32_t index,
877     bool updateCaret)
878 {
879     if (GetTextContentLength() >= maxLength_.value_or(INT_MAX)) {
880         TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "AddImageSpan: Reach the maxLength. maxLength=%{public}d", maxLength_.value_or(INT_MAX));
881         return 0;
882     }
883     auto host = GetHost();
884     CHECK_NULL_RETURN(host, -1);
885     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "AddImageSpan, opts=%{public}s, updateCaret=%{public}d",
886         options.ToString().c_str(), updateCaret);
887     NotifyExitTextPreview(false);
888     auto imageNode = ImageSpanNode::GetOrCreateSpanNode(V2::IMAGE_ETS_TAG,
889         ElementRegister::GetInstance()->MakeUniqueId(), []() { return AceType::MakeRefPtr<ImagePattern>(); });
890     auto pattern = imageNode->GetPattern<ImagePattern>();
891     CHECK_NULL_RETURN(pattern, -1);
892     pattern->SetSyncLoad(true);
893     int32_t insertIndex = options.offset.value_or(GetTextContentLength());
894     insertIndex = std::min(insertIndex, GetTextContentLength());
895     RichEditorChangeValue changeValue;
896     CHECK_NULL_RETURN(BeforeAddImage(changeValue, options, insertIndex), -1);
897 
898     HandleImageDrag(imageNode);
899     AddOprationWhenAddImage(options.offset.value_or(static_cast<int32_t>(GetTextContentLength())));
900     int32_t spanIndex = TextSpanSplit(insertIndex);
901     IF_TRUE(spanIndex == -1, spanIndex = static_cast<int32_t>(host->GetChildren().size()));
902 
903     imageNodes.push_back(imageNode);
904     imageNode->MountToParent(host, spanIndex);
905     auto renderContext = imageNode->GetRenderContext();
906     IF_PRESENT(renderContext, SetNeedAnimateFlag(false));
907     SetImageLayoutProperty(imageNode, options);
908     auto spanItem = imageNode->GetSpanItem();
909     // The length of the imageSpan defaults to the length of a character to calculate the position
910     spanItem->content = u" ";
911     spanItem->SetImageSpanOptions(options);
912     spanItem->spanItemType = SpanItemType::IMAGE;
913     AddSpanItem(spanItem, spanIndex);
914     SetGestureOptions(options.userGestureOption, spanItem);
915     auto userMouseOption = options.userMouseOption;
916     if (userMouseOption.onHover) {
917         spanItem->onHover_ = std::move(userMouseOption.onHover);
918         hoverableNodes.push_back(imageNode);
919     }
920     placeholderCount_++;
921     if (updateCaret) {
922         SetCaretPosition(insertIndex + spanItem->content.length());
923         SetNeedMoveCaretToContentRect();
924     }
925     ResetSelectionAfterAddSpan(isPaste);
926     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
927     host->MarkModifyDone();
928     AfterContentChange(changeValue);
929     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "end");
930     return spanIndex;
931 }
932 
CreateHoverInfo(const MouseInfo & info)933 HoverInfo RichEditorPattern::CreateHoverInfo(const MouseInfo& info)
934 {
935     HoverInfo hoverInfo;
936     hoverInfo.SetType(info.GetType());
937     hoverInfo.SetTimeStamp(info.GetTimeStamp());
938     hoverInfo.SetTarget(info.GetTarget());
939     hoverInfo.SetSourceDevice(info.GetSourceDevice());
940     hoverInfo.SetForce(info.GetForce());
941     IF_TRUE(info.GetTiltX(), hoverInfo.SetTiltX(info.GetTiltX().value()));
942     IF_TRUE(info.GetTiltY(), hoverInfo.SetTiltY(info.GetTiltY().value()));
943     hoverInfo.SetSourceTool(info.GetSourceTool());
944     hoverInfo.SetDeviceId(info.GetDeviceId());
945     hoverInfo.SetTargetDisplayId(info.GetTargetDisplayId());
946     hoverInfo.SetStopPropagation(info.IsStopPropagation());
947     hoverInfo.SetPreventDefault(info.IsPreventDefault());
948     hoverInfo.SetPatternName(info.GetPatternName());
949     hoverInfo.SetPressedKeyCodes(info.GetPressedKeyCodes());
950     hoverInfo.SetIsPostEventResult(info.GetIsPostEventResult());
951     hoverInfo.SetPostEventNodeId(info.GetPostEventNodeId());
952     return hoverInfo;
953 }
954 
HandleImageHoverEvent(const MouseInfo & mouseInfo)955 void RichEditorPattern::HandleImageHoverEvent(const MouseInfo& mouseInfo)
956 {
957     CHECK_NULL_VOID(mouseInfo.GetAction() == MouseAction::MOVE && !isMousePressed_);
958     ACE_SCOPED_TRACE("RichEditorHandleImageHoverEvent");
959     PointF mouseOffset = { mouseInfo.GetLocalLocation().GetX(), mouseInfo.GetLocalLocation().GetY() };
960     HoverInfo info = CreateHoverInfo(mouseInfo);
961     for (auto it = hoverableNodes.begin(); it != hoverableNodes.end();) {
962         auto spanNode = it->Upgrade();
963         if (!spanNode) {
964             it = hoverableNodes.erase(it);
965             continue;
966         }
967         const auto& imageSpanItem = spanNode->GetSpanItem();
968         if (!imageSpanItem || !imageSpanItem->onHover_) {
969             it = hoverableNodes.erase(it);
970             continue;
971         }
972         const auto& geoNode = spanNode->GetGeometryNode();
973         CHECK_NULL_CONTINUE(geoNode);
974         const auto& imageRect = geoNode->GetFrameRect();
975         if (!imageRect.IsInRegion(mouseOffset)) {
976             ++it;
977             continue;
978         }
979         if (!lastHoverSpanItem_) {
980             imageSpanItem->onHover_(true, info);
981             lastHoverSpanItem_ = imageSpanItem;
982             lastHoverInfo_ = info;
983             return;
984         }
985         CHECK_NULL_VOID(Referenced::RawPtr(lastHoverSpanItem_) != Referenced::RawPtr(imageSpanItem));
986         imageSpanItem->onHover_(true, info);
987         lastHoverSpanItem_->onHover_(false, info);
988         lastHoverSpanItem_ = imageSpanItem;
989         lastHoverInfo_ = info;
990         return;
991     }
992 
993     if (lastHoverSpanItem_) {
994         lastHoverSpanItem_->onHover_(false, info);
995         lastHoverSpanItem_.Reset();
996     }
997 }
998 
AddOprationWhenAddImage(int32_t beforeCaretPos)999 void RichEditorPattern::AddOprationWhenAddImage(int32_t beforeCaretPos)
1000 {
1001     OperationRecord record;
1002     record.beforeCaretPosition = beforeCaretPos;
1003     record.addText = u" ";
1004     ClearRedoOperationRecords();
1005     record.afterCaretPosition = record.beforeCaretPosition + 1;
1006     AddOperationRecord(record);
1007 }
1008 
ResetSelectionAfterAddSpan(bool isPaste)1009 void RichEditorPattern::ResetSelectionAfterAddSpan(bool isPaste)
1010 {
1011     if (isPaste || !textSelector_.IsValid()) {
1012         return;
1013     }
1014     CloseSelectOverlay();
1015     ResetSelection();
1016     if (isEditing_ && !caretVisible_) {
1017         StartTwinkling();
1018     }
1019 }
1020 
AddSpanItem(const RefPtr<SpanItem> & item,int32_t offset)1021 void RichEditorPattern::AddSpanItem(const RefPtr<SpanItem>& item, int32_t offset)
1022 {
1023     auto host = GetHost();
1024     CHECK_NULL_VOID(host);
1025     if (offset == -1) {
1026         offset = static_cast<int32_t>(host->GetChildren().size());
1027     }
1028     offset = std::clamp(offset, 0, static_cast<int32_t>(host->GetChildren().size()) - 1);
1029     auto it = spans_.begin();
1030     std::advance(it, offset);
1031     spans_.insert(it, item);
1032     UpdateSpanPosition();
1033 }
1034 
OnAttachToFrameNode()1035 void RichEditorPattern::OnAttachToFrameNode()
1036 {
1037     TextPattern::OnAttachToFrameNode();
1038     richEditorInstanceId_ = Container::CurrentIdSafely();
1039     auto frameNode = GetHost();
1040     CHECK_NULL_VOID(frameNode);
1041     frameId_ = frameNode->GetId();
1042     frameNode->GetRenderContext()->UpdateClipEdge(true);
1043     frameNode->GetRenderContext()->SetClipToFrame(true);
1044     StylusDetectorMgr::GetInstance()->AddTextFieldFrameNode(frameNode, WeakClaim(this));
1045     auto context = GetContext();
1046     CHECK_NULL_VOID(context);
1047     context->AddWindowSizeChangeCallback(frameId_);
1048 }
1049 
OnDetachFromFrameNode(FrameNode * node)1050 void RichEditorPattern::OnDetachFromFrameNode(FrameNode* node)
1051 {
1052     TextPattern::OnDetachFromFrameNode(node);
1053     ScrollablePattern::OnDetachFromFrameNode(node);
1054     ClearOnFocusTextField(node);
1055     auto context = GetContext();
1056     IF_PRESENT(context, RemoveWindowSizeChangeCallback(frameId_));
1057 }
1058 
AddPlaceholderSpan(const RefPtr<UINode> & customNode,const SpanOptionBase & options)1059 int32_t RichEditorPattern::AddPlaceholderSpan(const RefPtr<UINode>& customNode, const SpanOptionBase& options)
1060 {
1061     if (GetTextContentLength() >= maxLength_.value_or(INT_MAX)) {
1062         TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "AddPlaceholderSpan: Reach the maxLength. maxLength=%{public}d", maxLength_.value_or(INT_MAX));
1063         return 0;
1064     }
1065     CHECK_NULL_RETURN(customNode, 0);
1066     auto host = GetHost();
1067     CHECK_NULL_RETURN(host, 0);
1068     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "AddPlaceholderSpan");
1069     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "options=%{public}s", options.ToString().c_str());
1070     NotifyExitTextPreview(false);
1071     auto placeholderSpanNode = PlaceholderSpanNode::GetOrCreateSpanNode(V2::PLACEHOLDER_SPAN_ETS_TAG,
1072         ElementRegister::GetInstance()->MakeUniqueId(), []() { return AceType::MakeRefPtr<PlaceholderSpanPattern>(); });
1073     CHECK_NULL_RETURN(placeholderSpanNode, 0);
1074     customNode->MountToParent(placeholderSpanNode);
1075     SetSelfAndChildDraggableFalse(customNode);
1076     IF_PRESENT(oneStepDragController_, EnableOneStepDrag(TextSpanType::BUILDER, placeholderSpanNode));
1077     auto focusHub = placeholderSpanNode->GetOrCreateFocusHub();
1078     focusHub->SetFocusable(false);
1079     int32_t insertIndex = options.offset.value_or(GetTextContentLength());
1080     int32_t spanIndex = TextSpanSplit(insertIndex);
1081     if (spanIndex == -1) {
1082         spanIndex = static_cast<int32_t>(host->GetChildren().size());
1083     }
1084     builderNodes.push_back(placeholderSpanNode);
1085     placeholderSpanNode->MountToParent(host, spanIndex);
1086     auto renderContext = placeholderSpanNode->GetRenderContext();
1087     IF_PRESENT(renderContext, SetNeedAnimateFlag(false));
1088     auto spanItem = placeholderSpanNode->GetSpanItem();
1089     spanItem->content = u" ";
1090     spanItem->SetCustomNode(customNode);
1091     spanItem->dragBackgroundColor_ = options.dragBackgroundColor;
1092     spanItem->isDragShadowNeeded_ = options.isDragShadowNeeded;
1093     AddSpanItem(spanItem, spanIndex);
1094     placeholderCount_++;
1095     SetCaretPosition(insertIndex + spanItem->content.length());
1096     ResetSelectionAfterAddSpan(false);
1097     auto placeholderPipelineContext = placeholderSpanNode->GetContext();
1098     IF_PRESENT(placeholderPipelineContext, SetDoKeyboardAvoidAnimate(false));
1099     SetNeedMoveCaretToContentRect();
1100     AddOnPlaceholderHoverEvent(placeholderSpanNode);
1101     placeholderSpanNode->MarkModifyDone();
1102     placeholderSpanNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1103     host->MarkModifyDone();
1104     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1105     return spanIndex;
1106 }
1107 
AddOnPlaceholderHoverEvent(const RefPtr<PlaceholderSpanNode> & placeholderSpanNode)1108 void RichEditorPattern::AddOnPlaceholderHoverEvent(const RefPtr<PlaceholderSpanNode>& placeholderSpanNode)
1109 {
1110     CHECK_NULL_VOID(placeholderSpanNode);
1111     auto inputHub = placeholderSpanNode->GetOrCreateInputEventHub();
1112     CHECK_NULL_VOID(inputHub);
1113     auto hoverTask = [weak = WeakClaim(this)](bool isHover) {
1114         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "placeholder, on hover event isHover=%{public}d", isHover);
1115         auto pattern = weak.Upgrade();
1116         CHECK_NULL_VOID(pattern);
1117         pattern->OnPlaceholderHover(isHover);
1118     };
1119     auto hoverEvent = MakeRefPtr<InputEvent>(std::move(hoverTask));
1120     inputHub->AddOnHoverEvent(hoverEvent);
1121 }
1122 
OnPlaceholderHover(bool isHover)1123 void RichEditorPattern::OnPlaceholderHover(bool isHover)
1124 {
1125     auto host = GetHost();
1126     CHECK_NULL_VOID(host);
1127     auto pipeline = GetContext();
1128     CHECK_NULL_VOID(pipeline);
1129     auto nodeId = host->GetId();
1130     if (isHover) {
1131         pipeline->FreeMouseStyleHoldNode(nodeId);
1132     } else {
1133         pipeline->FreeMouseStyleHoldNode();
1134         ChangeMouseStyle(MouseFormat::TEXT_CURSOR);
1135     }
1136 }
1137 
SetSelfAndChildDraggableFalse(const RefPtr<UINode> & customNode)1138 void RichEditorPattern::SetSelfAndChildDraggableFalse(const RefPtr<UINode>& customNode)
1139 {
1140     CHECK_NULL_VOID(customNode);
1141     auto frameNode = DynamicCast<FrameNode>(customNode);
1142     if (frameNode) {
1143         auto gestureEventHub = frameNode->GetOrCreateGestureEventHub();
1144         IF_PRESENT(gestureEventHub, SetDragForbiddenForcely(true));
1145     }
1146     for (const auto& child : customNode->GetChildren()) {
1147         SetSelfAndChildDraggableFalse(child);
1148     }
1149 }
1150 
AddTextSpan(TextSpanOptions options,bool isPaste,int32_t index)1151 int32_t RichEditorPattern::AddTextSpan(TextSpanOptions options, bool isPaste, int32_t index)
1152 {
1153     if (GetTextContentLength() >= maxLength_.value_or(INT_MAX)) {
1154         TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "AddTextSpan: Reach the maxLength. maxLength=%{public}d", maxLength_.value_or(INT_MAX));
1155         return 0;
1156     }
1157     auto length = CalculateTruncationLength(options.value, maxLength_.value_or(INT_MAX) - GetTextContentLength());
1158     if (length == 0) {
1159         return -1;
1160     }
1161     options.value = options.value.substr(0, length);
1162     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "AddTextSpan, opts=%{public}s", ToBriefString(options).c_str());
1163     SEC_TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "AddTextSpan, opts=%{public}s", options.ToString().c_str());
1164     AdjustAddPosition(options);
1165     NotifyExitTextPreview();
1166     OperationRecord record;
1167     auto textContentLength = GetTextContentLength();
1168     if (options.offset.has_value()) {
1169         options.offset = std::clamp(options.offset.value(), 0, textContentLength);
1170     }
1171     record.beforeCaretPosition = std::clamp(options.offset.value_or(textContentLength), 0, textContentLength);
1172     record.addText = options.value;
1173     RichEditorChangeValue changeValue;
1174     CHECK_NULL_RETURN(BeforeChangeText(changeValue, options), -1);
1175     ClearRedoOperationRecords();
1176     record.afterCaretPosition = record.beforeCaretPosition + static_cast<int32_t>(options.value.length());
1177     AddOperationRecord(record);
1178     auto ret = AddTextSpanOperation(options, isPaste, index, false);
1179     SetNeedMoveCaretToContentRect();
1180     if (!previewTextRecord_.IsValid()) {
1181         AfterContentChange(changeValue);
1182     }
1183     return ret;
1184 }
1185 
AdjustAddPosition(TextSpanOptions & options)1186 void RichEditorPattern::AdjustAddPosition(TextSpanOptions& options)
1187 {
1188     CHECK_NULL_VOID(IsPreviewTextInputting() && options.offset.has_value());
1189     auto& offset = options.offset.value();
1190     auto delta = offset - previewTextRecord_.startOffset;
1191     offset -= std::min(std::max(0, delta), previewTextRecord_.endOffset - previewTextRecord_.startOffset);
1192 }
1193 
AddTextSpanOperation(const TextSpanOptions & options,bool isPaste,int32_t index,bool needLeadingMargin,bool updateCaretPosition)1194 int32_t RichEditorPattern::AddTextSpanOperation(
1195     const TextSpanOptions& options, bool isPaste, int32_t index, bool needLeadingMargin, bool updateCaretPosition)
1196 {
1197     auto host = GetHost();
1198     CHECK_NULL_RETURN(host, -1);
1199 
1200     auto* stack = ViewStackProcessor::GetInstance();
1201     auto nodeId = stack->ClaimNodeId();
1202     auto spanNode = SpanNode::GetOrCreateSpanNode(nodeId);
1203 
1204     int32_t spanIndex = 0;
1205     int32_t offset = -1;
1206     if (options.offset.has_value()) {
1207         offset = TextSpanSplit(options.offset.value(), needLeadingMargin);
1208         if (offset == -1) {
1209             spanIndex = static_cast<int32_t>(host->GetChildren().size());
1210         } else {
1211             spanIndex = offset;
1212         }
1213         spanNode->MountToParent(host, offset);
1214     } else if (index != -1) {
1215         spanNode->MountToParent(host, index);
1216         spanIndex = index;
1217     } else {
1218         spanIndex = static_cast<int32_t>(host->GetChildren().size());
1219         spanNode->MountToParent(host);
1220     }
1221     auto textStyle = options.style;
1222     if (options.urlAddress.has_value() && options.useThemeFontColor && textStyle.has_value()) {
1223         textStyle.value().SetTextColor(GetUrlSpanColor());
1224     }
1225     auto spanItem = spanNode->GetSpanItem();
1226     spanItem->SetTextStyle(textStyle);
1227     spanItem->useThemeFontColor = options.useThemeFontColor;
1228     spanItem->useThemeDecorationColor = options.useThemeDecorationColor;
1229     UpdateSpanNode(spanNode, options);
1230     AddSpanItem(spanItem, offset);
1231     if (!options.style.has_value()) {
1232         SetDefaultColor(spanNode);
1233     }
1234     if (options.paraStyle) {
1235         UpdateParagraphStyle(spanNode, *options.paraStyle);
1236     }
1237     SetGestureOptions(options.userGestureOption, spanItem);
1238     if (updateCaretPosition && !previewTextRecord_.IsValid()) {
1239         if (options.offset.has_value()) {
1240             SetCaretPosition(options.offset.value() + options.value.length());
1241         } else {
1242             SetCaretPosition(GetTextContentLength());
1243         }
1244     }
1245     ResetSelectionAfterAddSpan(isPaste);
1246     SpanNodeFission(spanNode);
1247     return spanIndex;
1248 }
1249 
UpdateSpanNode(RefPtr<SpanNode> spanNode,const TextSpanOptions & options)1250 void RichEditorPattern::UpdateSpanNode(RefPtr<SpanNode> spanNode, const TextSpanOptions& options)
1251 {
1252     spanNode->UpdateContent(options.value);
1253     if (options.style.has_value()) {
1254         const TextStyle& textStyle = options.style.value();
1255         spanNode->UpdateTextColorWithoutCheck(textStyle.GetTextColor());
1256         spanNode->UpdateFontSize(textStyle.GetFontSize());
1257         spanNode->UpdateItalicFontStyle(textStyle.GetFontStyle());
1258         spanNode->UpdateFontWeight(textStyle.GetFontWeight());
1259         spanNode->UpdateFontFamily(textStyle.GetFontFamilies());
1260         spanNode->UpdateTextDecoration(textStyle.GetTextDecoration());
1261         spanNode->UpdateTextDecorationColorWithoutCheck(textStyle.GetTextDecorationColor());
1262         spanNode->UpdateTextDecorationStyle(textStyle.GetTextDecorationStyle());
1263         spanNode->UpdateTextShadow(textStyle.GetTextShadows());
1264         spanNode->UpdateHalfLeading(textStyle.GetHalfLeading());
1265         spanNode->UpdateLineHeight(textStyle.GetLineHeight());
1266         spanNode->UpdateLetterSpacing(textStyle.GetLetterSpacing());
1267         spanNode->UpdateFontFeature(textStyle.GetFontFeatures());
1268         UpdateTextBackgroundStyle(spanNode, textStyle.GetTextBackgroundStyle());
1269     }
1270     UpdateUrlStyle(spanNode, options.urlAddress);
1271 }
1272 
UpdateTextBackgroundStyle(RefPtr<SpanNode> & spanNode,const std::optional<TextBackgroundStyle> & style)1273 void RichEditorPattern::UpdateTextBackgroundStyle(
1274     RefPtr<SpanNode>& spanNode, const std::optional<TextBackgroundStyle>& style)
1275 {
1276     CHECK_NULL_VOID(style.has_value());
1277     TextBackgroundStyle backgroundStyle = style.value();
1278     backgroundStyle.needCompareGroupId = true;
1279     backgroundStyle.groupId = ElementRegister::GetInstance()->MakeUniqueId();
1280     spanNode->UpdateTextBackgroundFromParent(backgroundStyle);
1281 }
1282 
UpdateUrlStyle(RefPtr<SpanNode> & spanNode,const std::optional<std::u16string> & urlAddressOpt)1283 void RichEditorPattern::UpdateUrlStyle(RefPtr<SpanNode>& spanNode, const std::optional<std::u16string>& urlAddressOpt)
1284 {
1285     CHECK_NULL_VOID(spanNode && urlAddressOpt.has_value());
1286     auto& spanItem = spanNode->GetSpanItem();
1287     CHECK_NULL_VOID(spanItem);
1288     auto& urlAddress = urlAddressOpt.value();
1289 
1290     // handle url span callback
1291     std::function<void()> urlOnRelease;
1292     if (!urlAddress.empty()) {
1293         urlOnRelease = [add = UtfUtils::Str16ToStr8(urlAddress)]() {
1294             auto pipelineContext = PipelineContext::GetCurrentContextSafelyWithCheck();
1295             CHECK_NULL_VOID(pipelineContext);
1296             pipelineContext->HyperlinkStartAbility(add);
1297         };
1298     }
1299     spanItem->SetUrlOnReleaseEvent(std::move(urlOnRelease));
1300     spanItem->urlAddress = urlAddress;
1301 
1302     // handle url span color
1303     CHECK_NULL_VOID(spanItem->useThemeFontColor);
1304     if (urlAddress.empty()) {
1305         auto theme = GetTheme<RichEditorTheme>();
1306         CHECK_NULL_VOID(theme);
1307         const auto& themeTextStyle = theme->GetTextStyle();
1308         spanNode->UpdateTextColor(themeTextStyle.GetTextColor());
1309     } else {
1310         spanNode->UpdateTextColor(GetUrlSpanColor());
1311     }
1312 }
1313 
AddSymbolSpan(const SymbolSpanOptions & options,bool isPaste,int32_t index)1314 int32_t RichEditorPattern::AddSymbolSpan(const SymbolSpanOptions& options, bool isPaste, int32_t index)
1315 {
1316     if (GetTextContentLength() >= maxLength_.value_or(INT_MAX) - 1) {
1317         TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "AddSymbolSpan: Reach the maxLength. maxLength=%{public}d", maxLength_.value_or(INT_MAX));
1318         return 0;
1319     }
1320     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "options=%{public}s", options.ToString().c_str());
1321     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "isPaste=%{public}d, index=%{public}d", isPaste, index);
1322 
1323     NotifyExitTextPreview(false);
1324     RichEditorChangeValue changeValue;
1325     CHECK_NULL_RETURN(BeforeAddSymbol(changeValue, options), -1);
1326     OperationRecord record;
1327     record.beforeCaretPosition = options.offset.value_or(static_cast<int32_t>(GetTextContentLength()));
1328     record.addText = u" ";
1329     ClearRedoOperationRecords();
1330     record.afterCaretPosition = record.beforeCaretPosition + 1;
1331     AddOperationRecord(record);
1332     auto ret = AddSymbolSpanOperation(options, isPaste, index);
1333     SetNeedMoveCaretToContentRect();
1334     AfterContentChange(changeValue);
1335     return ret;
1336 }
1337 
AddSymbolSpanOperation(const SymbolSpanOptions & options,bool isPaste,int32_t index)1338 int32_t RichEditorPattern::AddSymbolSpanOperation(const SymbolSpanOptions& options, bool isPaste, int32_t index)
1339 {
1340     auto host = GetHost();
1341     CHECK_NULL_RETURN(host, -1);
1342 
1343     auto* stack = ViewStackProcessor::GetInstance();
1344     auto nodeId = stack->ClaimNodeId();
1345     auto spanNode = SpanNode::GetOrCreateSpanNode(V2::SYMBOL_SPAN_ETS_TAG, nodeId);
1346 
1347     int32_t insertIndex = options.offset.value_or(GetTextContentLength());
1348     int32_t spanIndex = TextSpanSplit(insertIndex);
1349     if (spanIndex == -1) {
1350         spanIndex = static_cast<int32_t>(host->GetChildren().size());
1351     }
1352     spanNode->MountToParent(host, spanIndex);
1353     spanNode->UpdateContent(options.symbolId);
1354     if (options.style.has_value()) {
1355         spanNode->UpdateFontSize(options.style.value().GetFontSize());
1356         spanNode->UpdateFontWeight(options.style.value().GetFontWeight());
1357         spanNode->UpdateSymbolColorList(options.style.value().GetSymbolColorList());
1358         spanNode->UpdateSymbolRenderingStrategy(options.style.value().GetRenderStrategy());
1359         spanNode->UpdateSymbolEffectStrategy(options.style.value().GetEffectStrategy());
1360         spanNode->UpdateSymbolType(options.style.value().GetSymbolType());
1361         spanNode->UpdateFontFamily(options.style.value().GetFontFamilies());
1362     }
1363     auto spanItem = spanNode->GetSpanItem();
1364     spanItem->content = u"  ";
1365     spanItem->spanItemType = SpanItemType::SYMBOL;
1366     spanItem->SetSymbolId(options.symbolId);
1367     spanItem->SetTextStyle(options.style);
1368     spanItem->SetResourceObject(options.resourceObject);
1369     AddSpanItem(spanItem, spanIndex);
1370     SetCaretPosition(insertIndex + spanItem->content.length());
1371     ResetSelectionAfterAddSpan(false);
1372     SpanNodeFission(spanNode);
1373     return spanIndex;
1374 }
1375 
BeforeAddSymbol(RichEditorChangeValue & changeValue,const SymbolSpanOptions & options)1376 bool RichEditorPattern::BeforeAddSymbol(RichEditorChangeValue& changeValue, const SymbolSpanOptions& options)
1377 {
1378     auto eventHub = GetEventHub<RichEditorEventHub>();
1379     CHECK_NULL_RETURN(eventHub, false);
1380     CHECK_NULL_RETURN(eventHub->HasOnWillChange(), true);
1381 
1382     int32_t contentLength = GetTextContentLength();
1383     int32_t insertIndex = options.offset.value_or(contentLength);
1384     insertIndex = std::clamp(insertIndex, 0, contentLength);
1385 
1386     changeValue.SetRangeBefore({ insertIndex, insertIndex });
1387     changeValue.SetRangeAfter({ insertIndex, insertIndex + SYMBOL_SPAN_LENGTH });
1388     RichEditorAbstractSpanResult retInfo;
1389     TextInsertValueInfo info;
1390     CalcInsertValueObj(info, insertIndex, true);
1391     int32_t spanIndex = info.GetSpanIndex();
1392     retInfo.SetSpanIndex(spanIndex);
1393     retInfo.SetOffsetInSpan(0);
1394     retInfo.SetValueString(std::to_string(options.symbolId));
1395     retInfo.SetEraseLength(SYMBOL_SPAN_LENGTH);
1396     retInfo.SetSpanRangeStart(insertIndex);
1397     retInfo.SetSpanRangeEnd(insertIndex + SYMBOL_SPAN_LENGTH);
1398     retInfo.SetSpanType(SpanResultType::SYMBOL);
1399 
1400     TextStyle style = options.style.value_or(TextStyle());
1401     retInfo.SetSymbolSpanStyle(SymbolSpanStyle(style));
1402     retInfo.SetValueResource(options.resourceObject);
1403 
1404     changeValue.SetRichEditorReplacedSymbolSpans(retInfo);
1405     auto ret = eventHub->FireOnWillChange(changeValue);
1406     return ret;
1407 }
1408 
AfterContentChange(RichEditorChangeValue & changeValue)1409 void RichEditorPattern::AfterContentChange(RichEditorChangeValue& changeValue)
1410 {
1411     auto eventHub = GetEventHub<RichEditorEventHub>();
1412     if (eventHub && eventHub->HasOnDidChange()) {
1413         eventHub->FireOnDidChange(changeValue);
1414     }
1415     ForceTriggerAvoidOnCaretChange();
1416 }
1417 
SpanNodeFission(RefPtr<SpanNode> & spanNode)1418 void RichEditorPattern::SpanNodeFission(RefPtr<SpanNode>& spanNode)
1419 {
1420     auto spanItem = spanNode->GetSpanItem();
1421     auto wContent = spanItem->content;
1422     auto spanStart = spanItem->position - wContent.length();
1423     for (size_t i = 0; i < wContent.length(); i++) {
1424         if (wContent[i] == '\n') {
1425             TextSpanSplit(static_cast<int32_t>(spanStart + i + 1));
1426         }
1427     }
1428     UpdateSpanPosition();
1429 }
1430 
DeleteSpans(const RangeOptions & options)1431 void RichEditorPattern::DeleteSpans(const RangeOptions& options)
1432 {
1433     IF_TRUE(previewTextRecord_.previewTextExiting, TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "exiting preview"));
1434     IF_TRUE(IsPreviewTextInputting() && !previewTextRecord_.previewTextExiting, NotifyExitTextPreview());
1435     auto length = GetTextContentLength();
1436     int32_t start = options.start.value_or(0);
1437     int32_t end = options.end.value_or(length);
1438     if (start > end) {
1439         std::swap(start, end);
1440     }
1441     start = std::max(0, start);
1442     end = std::min(length, end);
1443     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "delete spans range=[%{public}d, %{public}d]", start, end);
1444     if (start > length || end < 0 || start == end) {
1445         return;
1446     }
1447     AdjustSelector(start, end);
1448     OperationRecord record;
1449     record.beforeCaretPosition = start;
1450     std::u16string u16valueString;
1451     GetContentBySpans(u16valueString);
1452     record.deleteText = u16valueString.substr(start, end - start);
1453     RichEditorChangeValue changeValue;
1454     changeValue.SetRangeBefore({ start, end });
1455     changeValue.SetRangeAfter({ start, start });
1456     if (auto eventHub = GetEventHub<RichEditorEventHub>(); eventHub) {
1457         CHECK_NULL_VOID(eventHub->FireOnWillChange(changeValue));
1458     }
1459     ClearRedoOperationRecords();
1460     record.afterCaretPosition = start;
1461     AddOperationRecord(record);
1462     DeleteSpansOperation(start, end);
1463     AfterContentChange(changeValue);
1464 }
1465 
DeleteSpansOperation(int32_t start,int32_t end)1466 void RichEditorPattern::DeleteSpansOperation(int32_t start, int32_t end)
1467 {
1468     auto startInfo = GetSpanPositionInfo(start);
1469     auto endInfo = GetSpanPositionInfo(end - 1);
1470     if (startInfo.spanIndex_ == endInfo.spanIndex_) {
1471         DeleteSpanByRange(start, end, startInfo);
1472     } else {
1473         DeleteSpansByRange(start, end, startInfo, endInfo);
1474     }
1475     RemoveEmptySpanItems();
1476     if (textSelector_.IsValid()) {
1477         SetCaretPosition(textSelector_.GetTextStart());
1478         CloseSelectOverlay();
1479         ResetSelection();
1480     }
1481     SetCaretOffset(start);
1482     auto host = GetHost();
1483     CHECK_NULL_VOID(host);
1484     if (host->GetChildren().empty() || GetTextContentLength() == 0) {
1485         SetCaretPosition(0);
1486         textForDisplay_.clear();
1487     }
1488     UpdateSpanPosition();
1489 }
1490 
RemoveEmptySpanItems()1491 void RichEditorPattern::RemoveEmptySpanItems()
1492 {
1493     for (auto it = spans_.begin(); it != spans_.end();) {
1494         if ((*it)->content.empty()) {
1495             it = spans_.erase(it);
1496         } else {
1497             ++it;
1498         }
1499     }
1500 }
1501 
RemoveEmptySpanNodes()1502 void RichEditorPattern::RemoveEmptySpanNodes()
1503 {
1504     auto host = GetHost();
1505     CHECK_NULL_VOID(host);
1506     auto& spanNodes = host->GetChildren();
1507     for (auto it = spanNodes.begin(); it != spanNodes.end();) {
1508         auto spanNode = AceType::DynamicCast<SpanNode>(*it);
1509         if (!spanNode) {
1510             ++it;
1511             continue;
1512         }
1513         if (spanNode->GetSpanItem()->content.empty()) {
1514             it = host->RemoveChild(spanNode);
1515         } else {
1516             ++it;
1517         }
1518     }
1519 }
1520 
RemoveEmptySpans()1521 void RichEditorPattern::RemoveEmptySpans()
1522 {
1523     RemoveEmptySpanItems();
1524     RemoveEmptySpanNodes();
1525 }
1526 
DeleteSpanByRange(int32_t start,int32_t end,SpanPositionInfo info)1527 void RichEditorPattern::DeleteSpanByRange(int32_t start, int32_t end, SpanPositionInfo info)
1528 {
1529     auto host = GetHost();
1530     CHECK_NULL_VOID(host);
1531     auto childrens = host->GetChildren();
1532     auto it = childrens.begin();
1533     std::advance(it, info.spanIndex_);
1534     CHECK_NULL_VOID(it != childrens.end());
1535     if (start == info.spanStart_ && end == info.spanEnd_) {
1536         ClearContent(*it);
1537         host->RemoveChild(*it);
1538     } else {
1539         auto spanNode = DynamicCast<SpanNode>(*it);
1540         CHECK_NULL_VOID(spanNode);
1541         auto spanItem = spanNode->GetSpanItem();
1542         auto beforStr = spanItem->content.substr(0, start - info.spanStart_);
1543         auto endStr = spanItem->content.substr(end - info.spanStart_);
1544         spanNode->UpdateContent(beforStr + endStr);
1545     }
1546     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1547     host->MarkModifyDone();
1548 }
1549 
DeleteSpansByRange(int32_t start,int32_t end,SpanPositionInfo startInfo,SpanPositionInfo endInfo)1550 void RichEditorPattern::DeleteSpansByRange(
1551     int32_t start, int32_t end, SpanPositionInfo startInfo, SpanPositionInfo endInfo)
1552 {
1553     auto host = GetHost();
1554     CHECK_NULL_VOID(host);
1555     auto childrens = host->GetChildren();
1556     CHECK_NULL_VOID(!childrens.empty());
1557 
1558     auto itStart = childrens.begin();
1559     if (startInfo.spanIndex_ >= static_cast<int32_t>(childrens.size())) {
1560         std::advance(itStart, static_cast<int32_t>(childrens.size()) - 1);
1561         TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "startInfo.spanIndex_ is larger than childrens size");
1562     } else {
1563         std::advance(itStart, startInfo.spanIndex_);
1564     }
1565     CHECK_NULL_VOID(itStart != childrens.end());
1566     auto saveStartSpan = (start == startInfo.spanStart_) ? 0 : 1;
1567     if (saveStartSpan) {
1568         auto spanNodeStart = DynamicCast<SpanNode>(*itStart);
1569         CHECK_NULL_VOID(spanNodeStart);
1570         auto spanItemStart = spanNodeStart->GetSpanItem();
1571         auto beforStr = spanItemStart->content.substr(0, start - startInfo.spanStart_);
1572         spanNodeStart->UpdateContent(beforStr);
1573     }
1574     auto itEnd = childrens.begin();
1575     std::advance(itEnd, endInfo.spanIndex_);
1576     auto delEndSpan = (end == endInfo.spanEnd_) ? 1 : 0;
1577     if (!delEndSpan) {
1578         auto spanNodeEnd = DynamicCast<SpanNode>(*itEnd);
1579         CHECK_NULL_VOID(spanNodeEnd);
1580         auto spanItemEnd = spanNodeEnd->GetSpanItem();
1581         auto endStr = spanItemEnd->content.substr(end - endInfo.spanStart_, endInfo.spanEnd_ - end);
1582         spanNodeEnd->UpdateContent(endStr);
1583     }
1584     auto startIter = childrens.begin();
1585     std::advance(startIter, startInfo.spanIndex_ + saveStartSpan);
1586     auto endIter = childrens.begin();
1587     std::advance(endIter, endInfo.spanIndex_);
1588     for (auto iter = startIter; iter != endIter; ++iter) {
1589         ClearContent(*iter);
1590         host->RemoveChild(*iter);
1591     }
1592     if (endIter != childrens.end() && delEndSpan) {
1593         ClearContent(*endIter);
1594         host->RemoveChild(*endIter);
1595     }
1596     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1597     host->MarkModifyDone();
1598 }
1599 
GetLeftTextOfCursor(int32_t number)1600 std::u16string RichEditorPattern::GetLeftTextOfCursor(int32_t number)
1601 {
1602     if (number > caretPosition_) {
1603         number = caretPosition_;
1604     }
1605     auto start = caretPosition_;
1606     if (IsSelected()) {
1607         start = std::min(textSelector_.GetStart(), textSelector_.GetEnd());
1608     }
1609     return GetSelectedText(start - number, start);
1610 }
1611 
GetRightTextOfCursor(int32_t number)1612 std::u16string RichEditorPattern::GetRightTextOfCursor(int32_t number)
1613 {
1614     auto end = caretPosition_;
1615     if (IsSelected()) {
1616         end = std::max(textSelector_.GetStart(), textSelector_.GetEnd());
1617     }
1618     return GetSelectedText(end, end + number);
1619 }
1620 
GetTextIndexAtCursor()1621 int32_t RichEditorPattern::GetTextIndexAtCursor()
1622 {
1623     return caretPosition_;
1624 }
1625 
ClearContent(const RefPtr<UINode> & child)1626 void RichEditorPattern::ClearContent(const RefPtr<UINode>& child)
1627 {
1628     CHECK_NULL_VOID(child);
1629     if (child->GetTag() == V2::SPAN_ETS_TAG) {
1630         auto spanNode = DynamicCast<SpanNode>(child);
1631         if (spanNode) {
1632             spanNode->UpdateContent(u"");
1633             spanNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1634         }
1635         return;
1636     }
1637     auto imageSpanNode = DynamicCast<ImageSpanNode>(child);
1638     if (imageSpanNode) {
1639         imageSpanNode->GetSpanItem()->content.clear();
1640         imageSpanNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1641         return;
1642     }
1643     auto placeholderSpanNode = DynamicCast<PlaceholderSpanNode>(child);
1644     if (placeholderSpanNode) {
1645         placeholderSpanNode->GetSpanItem()->content.clear();
1646         placeholderSpanNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1647     }
1648 }
1649 
GetSpanPositionInfo(int32_t position)1650 SpanPositionInfo RichEditorPattern::GetSpanPositionInfo(int32_t position)
1651 {
1652     SpanPositionInfo spanPositionInfo(-1, -1, -1, -1);
1653     CHECK_NULL_RETURN(!spans_.empty(), spanPositionInfo);
1654     position = std::clamp(position, 0, GetTextContentLength());
1655     // find the spanItem where the position is
1656     auto it = std::find_if(spans_.begin(), spans_.end(), [position](const RefPtr<SpanItem>& spanItem) {
1657         return (spanItem->position - static_cast<int32_t>(spanItem->content.length()) <= position) &&
1658                (position < spanItem->position);
1659     });
1660     if (it != spans_.end() && (*it)->unicode != 0 && (*it)->position - caretPosition_ + moveLength_ == 1) {
1661         it++;
1662         moveLength_++;
1663         position++;
1664     }
1665 
1666     // the position is at the end
1667     if (it == spans_.end()) {
1668         return spanPositionInfo;
1669     }
1670 
1671     spanPositionInfo.spanIndex_ = std::distance(spans_.begin(), it);
1672     int32_t contentLen = static_cast<int32_t>((*it)->content.length());
1673     spanPositionInfo.spanStart_ = (*it)->position - contentLen;
1674     spanPositionInfo.spanEnd_ = (*it)->position;
1675     spanPositionInfo.spanOffset_ = position - spanPositionInfo.spanStart_;
1676     return spanPositionInfo;
1677 }
1678 
CopyTextSpanStyle(RefPtr<SpanNode> & source,RefPtr<SpanNode> & target,bool needLeadingMargin)1679 void RichEditorPattern::CopyTextSpanStyle(RefPtr<SpanNode>& source, RefPtr<SpanNode>& target, bool needLeadingMargin)
1680 {
1681     CopyTextSpanFontStyle(source, target);
1682     CopyTextSpanLineStyle(source, target, needLeadingMargin);
1683     CopyTextSpanUrlStyle(source, target);
1684 }
1685 
CopyTextSpanFontStyle(RefPtr<SpanNode> & source,RefPtr<SpanNode> & target)1686 void RichEditorPattern::CopyTextSpanFontStyle(RefPtr<SpanNode>& source, RefPtr<SpanNode>& target)
1687 {
1688     CHECK_NULL_VOID(source);
1689     CHECK_NULL_VOID(source->GetTag() == V2::SPAN_ETS_TAG);
1690     CHECK_NULL_VOID(target);
1691     COPY_SPAN_STYLE_IF_PRESENT(source, target, FontSize);
1692     COPY_SPAN_STYLE_IF_PRESENT(source, target, TextColor);
1693     COPY_SPAN_STYLE_IF_PRESENT(source, target, ItalicFontStyle);
1694     COPY_SPAN_STYLE_IF_PRESENT(source, target, FontWeight);
1695     COPY_SPAN_STYLE_IF_PRESENT(source, target, FontFamily);
1696     COPY_SPAN_STYLE_IF_PRESENT(source, target, TextDecoration);
1697     COPY_SPAN_STYLE_IF_PRESENT(source, target, TextDecorationColor);
1698     COPY_SPAN_STYLE_IF_PRESENT(source, target, TextDecorationStyle);
1699     COPY_SPAN_STYLE_IF_PRESENT(source, target, TextCase);
1700     COPY_SPAN_STYLE_IF_PRESENT(source, target, LineHeight);
1701     COPY_SPAN_STYLE_IF_PRESENT(source, target, HalfLeading);
1702     COPY_SPAN_STYLE_IF_PRESENT(source, target, LetterSpacing);
1703     COPY_SPAN_STYLE_IF_PRESENT(source, target, FontFeature);
1704     COPY_SPAN_STYLE_IF_PRESENT(source, target, TextShadow);
1705     target->GetSpanItem()->useThemeFontColor = source->GetSpanItem()->useThemeFontColor;
1706     target->GetSpanItem()->useThemeDecorationColor = source->GetSpanItem()->useThemeDecorationColor;
1707     UpdateTextBackgroundStyle(target, source->GetTextBackgroundStyle());
1708 }
1709 
CopyTextSpanLineStyle(RefPtr<SpanNode> & source,RefPtr<SpanNode> & target,bool needLeadingMargin)1710 void RichEditorPattern::CopyTextSpanLineStyle(
1711     RefPtr<SpanNode>& source, RefPtr<SpanNode>& target, bool needLeadingMargin)
1712 {
1713     CHECK_NULL_VOID(source);
1714     CHECK_NULL_VOID(target);
1715     COPY_SPAN_STYLE_IF_PRESENT(source, target, TextAlign);
1716     COPY_SPAN_STYLE_IF_PRESENT(source, target, WordBreak);
1717     COPY_SPAN_STYLE_IF_PRESENT(source, target, LineBreakStrategy);
1718     COPY_SPAN_STYLE_IF_PRESENT(source, target, ParagraphSpacing);
1719     needLeadingMargin |= previewTextRecord_.previewTextHasStarted;
1720     if (source->HasLeadingMargin()) {
1721         auto leadingMargin = source->GetLeadingMarginValue({});
1722         if (!needLeadingMargin) {
1723             leadingMargin.pixmap.Reset();
1724         }
1725         target->UpdateLeadingMargin(leadingMargin);
1726     }
1727 }
1728 
CopyTextSpanUrlStyle(RefPtr<SpanNode> & source,RefPtr<SpanNode> & target)1729 void RichEditorPattern::CopyTextSpanUrlStyle(RefPtr<SpanNode>& source, RefPtr<SpanNode>& target)
1730 {
1731     CHECK_NULL_VOID(source && source->GetTag() == V2::SPAN_ETS_TAG);
1732     CHECK_NULL_VOID(target && target->GetTag() == V2::SPAN_ETS_TAG);
1733     const auto& sourceSpanItem = source->GetSpanItem();
1734     const auto& targetSpanItem = target->GetSpanItem();
1735     CHECK_NULL_VOID(sourceSpanItem && targetSpanItem);
1736     targetSpanItem->urlOnRelease = sourceSpanItem->urlOnRelease;
1737     targetSpanItem->urlAddress = sourceSpanItem->urlAddress;
1738 }
1739 
CopyGestureOption(const RefPtr<SpanNode> & source,RefPtr<SpanNode> & target)1740 void RichEditorPattern::CopyGestureOption(const RefPtr<SpanNode>& source, RefPtr<SpanNode>& target)
1741 {
1742     CHECK_NULL_VOID(source);
1743     CHECK_NULL_VOID(target);
1744     auto sourceItem = source->GetSpanItem();
1745     CHECK_NULL_VOID(sourceItem);
1746     auto targetItem = target->GetSpanItem();
1747     CHECK_NULL_VOID(targetItem);
1748 
1749     if (sourceItem->onClick) {
1750         auto tmpClickFunc = sourceItem->onClick;
1751         targetItem->SetOnClickEvent(std::move(tmpClickFunc));
1752     }
1753     if (sourceItem->onLongPress) {
1754         auto tmpLongPressFunc = sourceItem->onLongPress;
1755         targetItem->SetLongPressEvent(std::move(tmpLongPressFunc));
1756     }
1757     if (sourceItem->onDoubleClick) {
1758         auto tmpDoubleClickFunc = sourceItem->onDoubleClick;
1759         targetItem->SetDoubleClickEvent(std::move(tmpDoubleClickFunc));
1760     }
1761     if (sourceItem->onHover) {
1762         auto tmpHoverFunc = sourceItem->onHover;
1763         targetItem->SetHoverEvent(std::move(tmpHoverFunc));
1764     }
1765 }
1766 
TextSpanSplit(int32_t position,bool needLeadingMargin)1767 int32_t RichEditorPattern::TextSpanSplit(int32_t position, bool needLeadingMargin)
1768 {
1769     CHECK_NULL_RETURN(!spans_.empty(), -1);
1770 
1771     SpanPositionInfo positionInfo = GetSpanPositionInfo(position);
1772     int32_t spanIndex = positionInfo.spanIndex_;
1773     int32_t spanStart = positionInfo.spanStart_;
1774     int32_t spanEnd = positionInfo.spanEnd_;
1775     int32_t offsetInSpan = positionInfo.spanOffset_;
1776     TAG_LOGD(AceLogTag::ACE_RICH_TEXT,
1777         "position=%{public}d, spanIndex=%{public}d, spanRange=[%{public}d,%{public}d], offsetInSpan=%{public}d",
1778         position, spanIndex, spanStart, spanEnd, offsetInSpan);
1779 
1780     CHECK_NULL_RETURN((offsetInSpan > 0), spanIndex);
1781 
1782     auto host = GetHost();
1783     CHECK_NULL_RETURN(host, -1);
1784     auto spanNode = DynamicCast<SpanNode>(host->GetChildAtIndex(spanIndex));
1785     CHECK_NULL_RETURN(spanNode, -1);
1786 
1787     auto spanItem = spanNode->GetSpanItem();
1788     auto spanItemContent = spanItem->content;
1789     offsetInSpan = std::min(offsetInSpan, static_cast<int32_t>(spanItemContent.length()));
1790 
1791     spanNode->UpdateContent(spanItemContent.substr(0, offsetInSpan));
1792     spanItem->position = spanStart + offsetInSpan;
1793 
1794     auto nodeId = ViewStackProcessor::GetInstance()->ClaimNodeId();
1795     auto newSpanNode = SpanNode::GetOrCreateSpanNode(nodeId);
1796     CHECK_NULL_RETURN(newSpanNode, -1);
1797 
1798     CopyTextSpanStyle(spanNode, newSpanNode, needLeadingMargin);
1799     CopyGestureOption(spanNode, newSpanNode);
1800     newSpanNode->UpdateContent(spanItemContent.substr(offsetInSpan));
1801     newSpanNode->MountToParent(host, spanIndex + 1);
1802 
1803     auto newSpanItem = newSpanNode->GetSpanItem();
1804     newSpanItem->rangeStart = spanStart + offsetInSpan;
1805     newSpanItem->position = spanEnd;
1806 
1807     auto spanIter = spans_.begin();
1808     std::advance(spanIter, spanIndex + 1);
1809     spans_.insert(spanIter, newSpanItem);
1810 
1811     return spanIndex + 1;
1812 }
1813 
GetCaretPosition()1814 int32_t RichEditorPattern::GetCaretPosition()
1815 {
1816     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "GetCaretPosition");
1817     return caretPosition_;
1818 }
1819 
SetCaretOffset(int32_t caretPosition)1820 bool RichEditorPattern::SetCaretOffset(int32_t caretPosition)
1821 {
1822     if (IsPreviewTextInputting()) {
1823         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "intercept operation in previewText state");
1824         return false;
1825     }
1826     int32_t inputCaretPosition = caretPosition;
1827     AdjustSelector(caretPosition, HandleType::SECOND);
1828     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "setCaretOffset, in=%{public}d, afterAdjust=%{public}d",
1829         inputCaretPosition, caretPosition);
1830     bool success = SetCaretPosition(caretPosition);
1831     auto host = GetHost();
1832     CHECK_NULL_RETURN(host, false);
1833     auto focusHub = host->GetOrCreateFocusHub();
1834     CHECK_NULL_RETURN(focusHub, false);
1835     if (focusHub->IsCurrentFocus()) {
1836         isCursorAlwaysDisplayed_ = false;
1837         StartTwinkling();
1838     }
1839     CloseSelectOverlay();
1840     ResetSelection();
1841     return success;
1842 }
1843 
CalcCursorOffsetByPosition(int32_t position,float & selectLineHeight,bool downStreamFirst,bool needLineHighest)1844 OffsetF RichEditorPattern::CalcCursorOffsetByPosition(
1845     int32_t position, float& selectLineHeight, bool downStreamFirst, bool needLineHighest)
1846 {
1847     selectLineHeight = 0.0f;
1848     auto host = GetHost();
1849     CHECK_NULL_RETURN(host, OffsetF(0, 0));
1850     auto pipeline = host->GetContext();
1851     CHECK_NULL_RETURN(pipeline, OffsetF(0, 0));
1852     auto rootOffset = pipeline->GetRootRect().GetOffset();
1853     auto textPaintOffset = richTextRect_.GetOffset();
1854     needLineHighest |= IsCustomSpanInCaretPos(position, downStreamFirst);
1855     auto startOffset = paragraphs_.ComputeCursorOffset(position, selectLineHeight, downStreamFirst, needLineHighest);
1856     auto children = host->GetChildren();
1857     if (NearZero(selectLineHeight)) {
1858         if (children.empty() || GetTextContentLength() == 0) {
1859             return textPaintOffset - rootOffset;
1860         }
1861         if (std::all_of(children.begin(), children.end(), [](RefPtr<UINode>& node) {
1862                 CHECK_NULL_RETURN(node, false);
1863                 return (node->GetTag() == V2::IMAGE_ETS_TAG || node->GetTag() == V2::PLACEHOLDER_SPAN_ETS_TAG);
1864             })) {
1865             bool isTail = false;
1866             auto it = children.begin();
1867             if (position >= static_cast<int32_t>(children.size())) {
1868                 std::advance(it, (static_cast<int32_t>(children.size()) - 1));
1869                 isTail = true;
1870             } else {
1871                 std::advance(it, position);
1872             }
1873             if (it == children.end()) {
1874                 return startOffset;
1875             }
1876             auto imageNode = DynamicCast<FrameNode>(*it);
1877             if (imageNode) {
1878                 auto geometryNode = imageNode->GetGeometryNode();
1879                 CHECK_NULL_RETURN(geometryNode, OffsetF(0.0f, 0.0f));
1880                 startOffset = geometryNode->GetMarginFrameOffset();
1881                 selectLineHeight = geometryNode->GetMarginFrameSize().Height();
1882                 startOffset += isTail ? OffsetF(geometryNode->GetMarginFrameSize().Width(), 0.0f) : OffsetF(0.0f, 0.0f);
1883             }
1884             return startOffset;
1885         }
1886     }
1887     auto caretOffset = startOffset + textPaintOffset + rootOffset;
1888     CHECK_NULL_RETURN(overlayMod_, caretOffset);
1889     caretOffset.SetX(std::clamp(caretOffset.GetX(), 0.0f, richTextRect_.Right()));
1890     return caretOffset;
1891 }
1892 
HandleCurrentPositionParagraphInfo(float & lastLineTop,float & paragraphSpacing)1893 void RichEditorPattern::HandleCurrentPositionParagraphInfo(float& lastLineTop, float& paragraphSpacing)
1894 {
1895     auto paragraphInfo = paragraphs_.GetParagrahInfo(caretPosition_);
1896     paragraphSpacing = paragraphInfo.paragraphStyle.paragraphSpacing.ConvertToPx();
1897     float lastLineHeight = 0.0f;
1898     CHECK_EQUAL_VOID(paragraphInfo.end - 1 >= paragraphInfo.start, false);
1899     lastLineTop = CalcCursorOffsetByPosition(paragraphInfo.end -1, lastLineHeight, true, true).GetY();
1900 }
1901 
IsCustomSpanInCaretPos(int32_t position,bool downStreamFirst)1902 bool RichEditorPattern::IsCustomSpanInCaretPos(int32_t position, bool downStreamFirst)
1903 {
1904     CHECK_NULL_RETURN((isSpanStringMode_ && styledString_), false);
1905     auto start = downStreamFirst ? position : position - 1;
1906     start = std::clamp(start, 0, GetTextContentLength());
1907     auto lastStyles = styledString_->GetSpans(start, 1);
1908     for (auto& style : lastStyles) {
1909         if (style && style->GetSpanType() == SpanType::CustomSpan) {
1910             return true;
1911         }
1912     }
1913     return false;
1914 }
1915 
SetCaretPositionWithAffinity(PositionWithAffinity positionWithAffinity)1916 void RichEditorPattern::SetCaretPositionWithAffinity(PositionWithAffinity positionWithAffinity)
1917 {
1918     auto currentPosition = static_cast<int32_t>(positionWithAffinity.position_);
1919     SetCaretPosition(currentPosition);
1920     caretAffinityPolicy_ = (positionWithAffinity.affinity_ == TextAffinity::UPSTREAM)
1921                                 ? CaretAffinityPolicy::UPSTREAM_FIRST
1922                                 : CaretAffinityPolicy::DOWNSTREAM_FIRST;
1923 }
1924 
SetCaretPosition(int32_t pos,bool needNotifyImf)1925 bool RichEditorPattern::SetCaretPosition(int32_t pos, bool needNotifyImf)
1926 {
1927     auto correctPos = std::clamp(pos, 0, GetTextContentLength());
1928     IF_TRUE(!isModifyingContent_, AdjustSelector(correctPos, HandleType::SECOND));
1929     ResetLastClickOffset();
1930     caretAffinityPolicy_ = CaretAffinityPolicy::DEFAULT;
1931     CHECK_NULL_RETURN((pos == correctPos), false);
1932     if (caretPosition_ != correctPos) {
1933         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "caret:%{public}d->%{public}d", caretPosition_, correctPos);
1934         lastCaretPosition_ = caretPosition_;
1935         caretPosition_ = correctPos;
1936         FireOnSelectionChange(caretPosition_);
1937         if (caretChangeListener_) {
1938             caretChangeListener_(caretPosition_);
1939         }
1940     }
1941     if (needNotifyImf) {
1942         UpdateCaretInfoToController();
1943     }
1944     return true;
1945 }
1946 
FireOnSelectionChange(const int32_t caretPosition)1947 void RichEditorPattern::FireOnSelectionChange(const int32_t caretPosition)
1948 {
1949     if (!textSelector_.SelectNothing() || !caretTwinkling_) {
1950         return;
1951     }
1952     FireOnSelectionChange(caretPosition, caretPosition);
1953 }
1954 
FireOnSelectionChange(const TextSelector & selector)1955 void RichEditorPattern::FireOnSelectionChange(const TextSelector& selector)
1956 {
1957     if (selector.SelectNothing()) {
1958         return;
1959     }
1960     FireOnSelectionChange(selector.GetStart(), selector.GetEnd());
1961 }
1962 
FireOnSelectionChange(int32_t start,int32_t end,bool isForced)1963 void RichEditorPattern::FireOnSelectionChange(int32_t start, int32_t end, bool isForced)
1964 {
1965     auto eventHub = GetEventHub<RichEditorEventHub>();
1966     CHECK_NULL_VOID(eventHub);
1967     CHECK_NULL_VOID(isForced || HasFocus() || dataDetectorAdapter_->hasClickedMenuOption_);
1968     bool isSingleHandle = selectOverlay_->IsSingleHandle();
1969     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "onSelectionChange, range=[%{public}d,%{public}d], isTwinkling=%{public}d, "
1970         "isSingleHandle=%{public}d", start, end, caretTwinkling_, isSingleHandle);
1971     if (start < 0 || end < 0) {
1972         return;
1973     }
1974     if (start == end && !caretTwinkling_ && !isSingleHandle) {
1975         return;
1976     }
1977     if (start > end) {
1978         std::swap(start, end);
1979     }
1980     auto range = SelectionRangeInfo(start, end);
1981     if (range == lastSelectionRange_) {
1982         return;
1983     }
1984     lastSelectionRange_ = std::move(range);
1985     eventHub->FireOnSelectionChange(&range);
1986 }
1987 
GetCaretVisible() const1988 bool RichEditorPattern::GetCaretVisible() const
1989 {
1990     return caretVisible_;
1991 }
1992 
OnWindowHide()1993 void RichEditorPattern::OnWindowHide()
1994 {
1995     ScrollablePattern::OnWindowHide();
1996 }
1997 
SetUpdateSpanStyle(struct UpdateSpanStyle updateSpanStyle)1998 void RichEditorPattern::SetUpdateSpanStyle(struct UpdateSpanStyle updateSpanStyle)
1999 {
2000     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "SetUpdateSpanStyle");
2001     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "updateSpanStyle=%{public}s", updateSpanStyle.ToString().c_str());
2002     updateSpanStyle_ = updateSpanStyle;
2003 }
2004 
GetUpdateSpanStyle()2005 UpdateSpanStyle RichEditorPattern::GetUpdateSpanStyle()
2006 {
2007     return updateSpanStyle_;
2008 }
2009 
SetTypingStyle(std::optional<struct UpdateSpanStyle> typingStyle,std::optional<TextStyle> textStyle)2010 void RichEditorPattern::SetTypingStyle(std::optional<struct UpdateSpanStyle> typingStyle,
2011     std::optional<TextStyle> textStyle)
2012 {
2013     typingStyle_ = typingStyle;
2014     typingTextStyle_ = textStyle;
2015     if (typingStyle_.has_value() && typingTextStyle_.has_value()) {
2016         IF_TRUE(typingStyle_->updateTextBackgroundStyle,
2017             typingStyle_->updateTextBackgroundStyle->needCompareGroupId = false);
2018         auto textBackgroundStyle = typingTextStyle_->GetTextBackgroundStyle();
2019         if (textBackgroundStyle) {
2020             textBackgroundStyle->needCompareGroupId = false;
2021             typingTextStyle_->SetTextBackgroundStyle(textBackgroundStyle);
2022         }
2023     }
2024     presetParagraph_ = nullptr;
2025     if (spans_.empty() || !previewTextRecord_.previewContent.empty()) {
2026         auto host = GetHost();
2027         CHECK_NULL_VOID(host);
2028         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
2029     }
2030 }
2031 
GetTypingStyle()2032 std::optional<struct UpdateSpanStyle> RichEditorPattern::GetTypingStyle()
2033 {
2034     return typingStyle_;
2035 }
2036 
UpdateFontFeatureTextStyle(RefPtr<SpanNode> & spanNode,struct UpdateSpanStyle & updateSpanStyle,TextStyle & textStyle)2037 void RichEditorPattern::UpdateFontFeatureTextStyle(
2038     RefPtr<SpanNode>& spanNode, struct UpdateSpanStyle& updateSpanStyle, TextStyle& textStyle)
2039 {
2040     if (updateSpanStyle.updateFontFeature.has_value()) {
2041         spanNode->UpdateFontFeature(textStyle.GetFontFeatures());
2042     }
2043 }
2044 
UpdateTextStyle(RefPtr<SpanNode> & spanNode,struct UpdateSpanStyle updateSpanStyle,TextStyle textStyle)2045 void RichEditorPattern::UpdateTextStyle(
2046     RefPtr<SpanNode>& spanNode, struct UpdateSpanStyle updateSpanStyle, TextStyle textStyle)
2047 {
2048     CHECK_NULL_VOID(spanNode->GetTag() == V2::SPAN_ETS_TAG);
2049     auto host = GetHost();
2050     CHECK_NULL_VOID(host);
2051     UpdateFontFeatureTextStyle(spanNode, updateSpanStyle, textStyle);
2052     if (updateSpanStyle.updateTextColor.has_value()) {
2053         spanNode->UpdateTextColorWithoutCheck(textStyle.GetTextColor());
2054         spanNode->GetSpanItem()->useThemeFontColor = false;
2055     }
2056     if (updateSpanStyle.updateLineHeight.has_value()) {
2057         spanNode->UpdateLineHeight(textStyle.GetLineHeight());
2058     }
2059     if (updateSpanStyle.updateHalfLeading.has_value()) {
2060         spanNode->UpdateHalfLeading(textStyle.GetHalfLeading());
2061     }
2062     if (updateSpanStyle.updateLetterSpacing.has_value()) {
2063         spanNode->UpdateLetterSpacing(textStyle.GetLetterSpacing());
2064     }
2065     if (updateSpanStyle.updateFontSize.has_value()) {
2066         spanNode->UpdateFontSize(textStyle.GetFontSize());
2067     }
2068     if (updateSpanStyle.updateItalicFontStyle.has_value()) {
2069         spanNode->UpdateItalicFontStyle(textStyle.GetFontStyle());
2070     }
2071     if (updateSpanStyle.updateFontWeight.has_value()) {
2072         spanNode->UpdateFontWeight(textStyle.GetFontWeight());
2073     }
2074     if (updateSpanStyle.updateFontFamily.has_value()) {
2075         spanNode->UpdateFontFamily(textStyle.GetFontFamilies());
2076     }
2077     UpdateDecoration(spanNode, updateSpanStyle, textStyle);
2078     if (updateSpanStyle.updateTextShadows.has_value()) {
2079         spanNode->UpdateTextShadow(textStyle.GetTextShadows());
2080     }
2081     if (updateSpanStyle.updateTextBackgroundStyle.has_value()) {
2082         UpdateTextBackgroundStyle(spanNode, textStyle.GetTextBackgroundStyle());
2083     }
2084     UpdateUrlStyle(spanNode, updateSpanStyle.updateUrlAddress);
2085 
2086     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
2087     host->MarkModifyDone();
2088 }
2089 
UpdateDecoration(RefPtr<SpanNode> & spanNode,struct UpdateSpanStyle & updateSpanStyle,TextStyle & textStyle)2090 void RichEditorPattern::UpdateDecoration(
2091     RefPtr<SpanNode>& spanNode, struct UpdateSpanStyle& updateSpanStyle, TextStyle& textStyle)
2092 {
2093     if (updateSpanStyle.updateTextDecoration.has_value()) {
2094         spanNode->UpdateTextDecoration(textStyle.GetTextDecoration());
2095         spanNode->GetSpanItem()->useThemeDecorationColor = false;
2096     }
2097     if (updateSpanStyle.updateTextDecorationColor.has_value()) {
2098         spanNode->UpdateTextDecorationColorWithoutCheck(textStyle.GetTextDecorationColor());
2099     }
2100     if (updateSpanStyle.updateTextDecorationStyle.has_value()) {
2101         spanNode->UpdateTextDecorationStyle(textStyle.GetTextDecorationStyle());
2102     }
2103 }
2104 
UpdateSymbolStyle(RefPtr<SpanNode> & spanNode,struct UpdateSpanStyle updateSpanStyle,TextStyle textStyle)2105 void RichEditorPattern::UpdateSymbolStyle(
2106     RefPtr<SpanNode>& spanNode, struct UpdateSpanStyle updateSpanStyle, TextStyle textStyle)
2107 {
2108     CHECK_NULL_VOID(spanNode->GetTag() == V2::SYMBOL_SPAN_ETS_TAG);
2109     auto host = GetHost();
2110     CHECK_NULL_VOID(host);
2111     UpdateFontFeatureTextStyle(spanNode, updateSpanStyle, textStyle);
2112     if (updateSpanStyle.updateSymbolFontSize.has_value()) {
2113         spanNode->UpdateFontSize(updateSpanStyle.updateSymbolFontSize.value());
2114     }
2115     if (updateSpanStyle.updateSymbolFontWeight.has_value()) {
2116         spanNode->UpdateFontWeight(updateSpanStyle.updateSymbolFontWeight.value());
2117     }
2118     if (updateSpanStyle.updateSymbolColor.has_value()) {
2119         spanNode->UpdateSymbolColorList(updateSpanStyle.updateSymbolColor.value());
2120     }
2121     if (updateSpanStyle.updateSymbolRenderingStrategy.has_value()) {
2122         spanNode->UpdateSymbolRenderingStrategy(updateSpanStyle.updateSymbolRenderingStrategy.value());
2123     }
2124     if (updateSpanStyle.updateSymbolEffectStrategy.has_value()) {
2125         spanNode->UpdateSymbolEffectStrategy(updateSpanStyle.updateSymbolEffectStrategy.value());
2126     }
2127     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
2128     host->MarkModifyDone();
2129 }
2130 
HasSameTypingStyle(const RefPtr<SpanNode> & spanNode)2131 bool RichEditorPattern::HasSameTypingStyle(const RefPtr<SpanNode>& spanNode)
2132 {
2133     auto spanItem = spanNode->GetSpanItem();
2134     CHECK_NULL_RETURN(spanItem, false);
2135     auto spanTextStyle = spanItem->GetTextStyle();
2136     if (spanTextStyle.has_value() && typingTextStyle_.has_value()) {
2137         return spanTextStyle.value() == typingTextStyle_.value();
2138     } else {
2139         return !(spanTextStyle.has_value() || typingTextStyle_.has_value());
2140     }
2141 }
2142 
UpdateImageStyle(RefPtr<FrameNode> & imageNode,const ImageSpanAttribute & imageStyle)2143 void RichEditorPattern::UpdateImageStyle(RefPtr<FrameNode>& imageNode, const ImageSpanAttribute& imageStyle)
2144 {
2145     CHECK_NULL_VOID(imageNode);
2146     CHECK_NULL_VOID(imageNode->GetTag() == V2::IMAGE_ETS_TAG);
2147     auto host = GetHost();
2148     CHECK_NULL_VOID(host);
2149     auto imageLayoutProperty = imageNode->GetLayoutProperty<ImageLayoutProperty>();
2150     CHECK_NULL_VOID(imageLayoutProperty);
2151     if (updateSpanStyle_.updateImageWidth.has_value() || updateSpanStyle_.updateImageHeight.has_value()) {
2152         imageLayoutProperty->UpdateUserDefinedIdealSize(imageStyle.size->GetSize());
2153     }
2154     if (updateSpanStyle_.updateImageFit.has_value()) {
2155         imageLayoutProperty->UpdateImageFit(imageStyle.objectFit.value());
2156     }
2157     if (updateSpanStyle_.updateImageVerticalAlign.has_value()) {
2158         imageLayoutProperty->UpdateVerticalAlign(imageStyle.verticalAlign.value());
2159     }
2160     if (updateSpanStyle_.borderRadius.has_value()) {
2161         auto imageRenderCtx = imageNode->GetRenderContext();
2162         imageRenderCtx->UpdateBorderRadius(imageStyle.borderRadius.value());
2163         imageRenderCtx->SetClipToBounds(true);
2164     }
2165     if (updateSpanStyle_.marginProp.has_value()) {
2166         imageLayoutProperty->UpdateMargin(imageStyle.marginProp.value());
2167     }
2168     UpdateImageAttribute(imageNode, imageStyle);
2169     imageNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
2170     imageNode->MarkModifyDone();
2171     IF_PRESENT(oneStepDragController_, MarkDirtyNode(WeakClaim((ImageSpanNode*) RawPtr(imageNode))));
2172     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
2173     host->MarkModifyDone();
2174 }
2175 
UpdateImageAttribute(RefPtr<FrameNode> & imageNode,const ImageSpanAttribute & imageStyle)2176 void RichEditorPattern::UpdateImageAttribute(RefPtr<FrameNode>& imageNode, const ImageSpanAttribute& imageStyle)
2177 {
2178     CHECK_NULL_VOID(imageNode);
2179     auto node = DynamicCast<ImageSpanNode>(imageNode);
2180     CHECK_NULL_VOID(node);
2181     auto imageSpanItem = DynamicCast<ImageSpanItem>(node->GetSpanItem());
2182     CHECK_NULL_VOID(imageSpanItem);
2183     imageSpanItem->options.imageAttribute = imageStyle;
2184     imageSpanItem->MarkDirty();
2185 }
2186 
SymbolSpanUpdateStyle(RefPtr<SpanNode> & spanNode,struct UpdateSpanStyle updateSpanStyle,TextStyle textStyle)2187 bool RichEditorPattern::SymbolSpanUpdateStyle(
2188     RefPtr<SpanNode>& spanNode, struct UpdateSpanStyle updateSpanStyle, TextStyle textStyle)
2189 {
2190     if (spanNode->GetTag() == V2::SYMBOL_SPAN_ETS_TAG) {
2191         UpdateSymbolStyle(spanNode, updateSpanStyle_, textStyle);
2192         return true;
2193     }
2194     return false;
2195 }
2196 
UpdateSpanStyle(int32_t start,int32_t end,const TextStyle & textStyle,const ImageSpanAttribute & imageStyle)2197 void RichEditorPattern::UpdateSpanStyle(
2198     int32_t start, int32_t end, const TextStyle& textStyle, const ImageSpanAttribute& imageStyle)
2199 {
2200     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "updateSpanStyle, [%{public}d,%{public}d], %{public}s",
2201         start, end, ToBriefString(textStyle, imageStyle, updateSpanStyle_).c_str());
2202     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "textStyle=%{public}s, imageStyle=%{public}s",
2203         textStyle.ToString().c_str(), imageStyle.ToString().c_str());
2204     auto host = GetHost();
2205     CHECK_NULL_VOID(host);
2206     AdjustSelector(start, end);
2207     int32_t spanStart = 0;
2208     int32_t spanEnd = 0;
2209     for (auto it = host->GetChildren().begin(); it != host->GetChildren().end(); ++it) {
2210         auto spanNode = DynamicCast<SpanNode>(*it);
2211         auto imageNode = DynamicCast<FrameNode>(*it);
2212         if (!spanNode) {
2213             if (spanEnd != 0) {
2214                 spanStart = spanEnd;
2215             }
2216             spanEnd = spanStart + 1;
2217         } else {
2218             spanNode->GetSpanItem()->GetIndex(spanStart, spanEnd);
2219         }
2220         if (spanEnd < start) {
2221             continue;
2222         }
2223 
2224         if (spanStart >= start && spanEnd <= end) {
2225             if (spanNode) {
2226                 UpdateSymbolStyle(spanNode, updateSpanStyle_, textStyle);
2227                 UpdateTextStyle(spanNode, updateSpanStyle_, textStyle);
2228             } else {
2229                 UpdateImageStyle(imageNode, imageStyle);
2230             }
2231             if (spanEnd == end) {
2232                 break;
2233             }
2234         } else if ((spanStart < start && start < spanEnd) || (spanStart < end && end < spanEnd)) {
2235             if (SymbolSpanUpdateStyle(spanNode, updateSpanStyle_, textStyle)) {
2236                 continue;
2237             }
2238             auto index = spanStart < start && start < spanEnd ? start : end;
2239             TextSpanSplit(index, true);
2240             --it;
2241         } else if (spanStart >= end) {
2242             break;
2243         }
2244     }
2245 }
2246 
GetChildByIndex(int32_t index) const2247 RefPtr<UINode> RichEditorPattern::GetChildByIndex(int32_t index) const
2248 {
2249     auto host = GetHost();
2250     CHECK_NULL_RETURN(host, nullptr);
2251     return host->GetChildAtIndex(index);
2252 }
2253 
SetResultObjectText(ResultObject & resultObject,const RefPtr<SpanItem> & spanItem)2254 void RichEditorPattern::SetResultObjectText(ResultObject& resultObject, const RefPtr<SpanItem>& spanItem)
2255 {
2256     CHECK_NULL_VOID(spanItem);
2257     resultObject.valueString = spanItem->content;
2258     if (spanItem->rangeStart <= previewTextRecord_.startOffset && spanItem->position >= previewTextRecord_.endOffset) {
2259         resultObject.previewText = previewTextRecord_.previewContent;
2260     }
2261     resultObject.urlAddress = spanItem->urlAddress;
2262 }
2263 
GetContentBySpans(std::u16string & u16Str)2264 void RichEditorPattern::GetContentBySpans(std::u16string& u16Str)
2265 {
2266     uint32_t length = 1;
2267     for (auto iter = spans_.cbegin(); iter != spans_.cend(); iter++) {
2268         length += (*iter)->content.length();
2269     }
2270     u16Str.reserve(length);
2271 
2272     for (auto iter = spans_.cbegin(); iter != spans_.cend(); iter++) {
2273         u16Str.append((*iter)->content);
2274     }
2275 }
2276 
SetSelectSpanStyle(int32_t start,int32_t end,KeyCode code,bool isStart)2277 void RichEditorPattern::SetSelectSpanStyle(int32_t start, int32_t end, KeyCode code, bool isStart)
2278 {
2279     TextStyle spanStyle;
2280     struct UpdateSpanStyle updateSpanStyle;
2281     ImageSpanAttribute imageStyle;
2282     auto it = std::find_if(spans_.begin(), spans_.end(), [start](const RefPtr<SpanItem>& spanItem) {
2283         return (spanItem->rangeStart <= start) && (start < spanItem->position);
2284     });
2285     if (it == spans_.end()) {
2286         return;
2287     }
2288     std::optional<TextStyle> spanTextStyle = (*it)->GetTextStyle();
2289     if (spanTextStyle.has_value()) {
2290         spanStyle = spanTextStyle.value();
2291     }
2292     HandleSelectFontStyleWrapper(code, spanStyle);
2293     updateSpanStyle.updateTextColor = spanStyle.GetTextColor();
2294     updateSpanStyle.updateFontSize = spanStyle.GetFontSize();
2295     updateSpanStyle.updateItalicFontStyle = spanStyle.GetFontStyle();
2296     updateSpanStyle.updateFontWeight = spanStyle.GetFontWeight();
2297     updateSpanStyle.updateFontFamily = spanStyle.GetFontFamilies();
2298     updateSpanStyle.updateTextDecoration = spanStyle.GetTextDecoration();
2299     if (!isStart) {
2300         auto updateSpanStyle_ = GetUpdateSpanStyle();
2301         switch (code) {
2302             case KeyCode::KEY_B:
2303                 updateSpanStyle.updateFontWeight = updateSpanStyle_.updateFontWeight;
2304                 spanStyle.SetFontWeight(updateSpanStyle_.updateFontWeight.value());
2305                 break;
2306             case KeyCode::KEY_I:
2307                 updateSpanStyle.updateItalicFontStyle = updateSpanStyle_.updateItalicFontStyle;
2308                 spanStyle.SetFontStyle(updateSpanStyle_.updateItalicFontStyle.value());
2309                 break;
2310             case KeyCode::KEY_U:
2311                 updateSpanStyle.updateTextDecoration = updateSpanStyle_.updateTextDecoration;
2312                 spanStyle.SetTextDecoration(updateSpanStyle_.updateTextDecoration.value());
2313                 break;
2314             default:
2315                 LOGW("Unsupported select operation for HandleSelectFontStyleWrapper");
2316                 return;
2317         }
2318     }
2319     SetUpdateSpanStyle(updateSpanStyle);
2320     UpdateSpanStyle(start, end, spanStyle, imageStyle);
2321 }
2322 
GetSelectSpansPositionInfo(int32_t & start,int32_t & end,SpanPositionInfo & startPositionSpanInfo,SpanPositionInfo & endPositionSpanInfo)2323 void RichEditorPattern::GetSelectSpansPositionInfo(
2324     int32_t& start, int32_t& end, SpanPositionInfo& startPositionSpanInfo, SpanPositionInfo& endPositionSpanInfo)
2325 {
2326     bool isText = false;
2327     auto host = GetHost();
2328     CHECK_NULL_VOID(host);
2329     std::find_if(spans_.begin(), spans_.end(), [&start, &end, &isText](const RefPtr<SpanItem>& spanItem) {
2330         if ((spanItem->rangeStart <= start) && (start < spanItem->position) && start < end) {
2331             if (spanItem->spanItemType == NG::SpanItemType::NORMAL && spanItem->unicode == 0) {
2332                 isText = true;
2333                 return true;
2334             }
2335             start += spanItem->content.length();
2336         }
2337         return false;
2338     });
2339     CHECK_EQUAL_VOID(isText, false);
2340     std::find_if(spans_.rbegin(), spans_.rend(), [&end](const RefPtr<SpanItem>& spanItem) {
2341         if ((spanItem->rangeStart < end) && (end <= spanItem->position)) {
2342             if (spanItem->spanItemType == NG::SpanItemType::NORMAL && spanItem->unicode == 0) {
2343                 return true;
2344             }
2345             end = spanItem->rangeStart;
2346         }
2347         return false;
2348     });
2349     startPositionSpanInfo = GetSpanPositionInfo(start);
2350     startPositionSpanInfo.spanIndex_ =
2351         std::clamp(startPositionSpanInfo.spanIndex_, 0, static_cast<int32_t>(host->GetChildren().size()) - 1);
2352     if (end == GetTextContentLength()) {
2353         endPositionSpanInfo.spanIndex_ = spans_.size() - 1;
2354         auto spanIter = spans_.begin();
2355         endPositionSpanInfo.spanIndex_ =
2356             std::clamp(endPositionSpanInfo.spanIndex_, 0, static_cast<int32_t>(host->GetChildren().size()) - 1);
2357         std::advance(spanIter, endPositionSpanInfo.spanIndex_);
2358         auto contentLen = (*spanIter)->content.length();
2359         endPositionSpanInfo.spanStart_ = (*spanIter)->position - contentLen;
2360         endPositionSpanInfo.spanEnd_ = (*spanIter)->position;
2361         endPositionSpanInfo.spanOffset_ = contentLen;
2362     } else {
2363         endPositionSpanInfo = GetSpanPositionInfo(end);
2364     }
2365     if (endPositionSpanInfo.spanIndex_ == -1) {
2366         endPositionSpanInfo = startPositionSpanInfo;
2367     }
2368 }
2369 
GetSpanNodeIter(int32_t index)2370 std::list<RefPtr<UINode>>::const_iterator RichEditorPattern::GetSpanNodeIter(int32_t index)
2371 {
2372     auto host = GetHost();
2373     CHECK_NULL_RETURN(host, {});
2374     auto spanNodeIter = host->GetChildren().begin();
2375     std::advance(spanNodeIter, index);
2376     return spanNodeIter;
2377 }
2378 
GetSelectSpanSplit(SpanPositionInfo & startPositionSpanInfo,SpanPositionInfo & endPositionSpanInfo)2379 std::list<SpanPosition> RichEditorPattern::GetSelectSpanSplit(
2380     SpanPositionInfo& startPositionSpanInfo, SpanPositionInfo& endPositionSpanInfo)
2381 {
2382     std::list<SpanPosition> resultObjects;
2383     int32_t spanIndex = 0;
2384     auto itStart = GetSpanNodeIter(startPositionSpanInfo.spanIndex_);
2385     auto itEnd = GetSpanNodeIter(endPositionSpanInfo.spanIndex_);
2386     auto itEndNext = GetSpanNodeIter(endPositionSpanInfo.spanIndex_ + 1);
2387     for (auto itSelect = itStart; itSelect != itEndNext; itSelect++) {
2388         SpanPosition resultObject;
2389         auto spanNode = DynamicCast<SpanNode>(*itSelect);
2390         if (!spanNode || spanNode->GetTag() != V2::SPAN_ETS_TAG) {
2391             continue;
2392         }
2393         auto spanItem = spanNode->GetSpanItem();
2394         if (itSelect == itStart) {
2395             if (startPositionSpanInfo.spanOffset_ == 0) {
2396                 resultObject.spanRange[RichEditorSpanRange::RANGESTART] = startPositionSpanInfo.spanStart_;
2397             } else {
2398                 resultObject.spanRange[RichEditorSpanRange::RANGESTART] =
2399                     startPositionSpanInfo.spanStart_ + startPositionSpanInfo.spanOffset_;
2400             }
2401             resultObject.spanRange[RichEditorSpanRange::RANGEEND] = startPositionSpanInfo.spanEnd_;
2402             resultObject.spanIndex = spanIndex;
2403             spanIndex++;
2404             resultObjects.emplace_back(resultObject);
2405             continue;
2406         }
2407         if (itSelect == itEnd) {
2408             resultObject.spanRange[RichEditorSpanRange::RANGESTART] = endPositionSpanInfo.spanStart_;
2409             if (endPositionSpanInfo.spanOffset_ == static_cast<int32_t>(spanItem->content.size())) {
2410                 resultObject.spanRange[RichEditorSpanRange::RANGEEND] = endPositionSpanInfo.spanEnd_;
2411             } else {
2412                 resultObject.spanRange[RichEditorSpanRange::RANGEEND] =
2413                     endPositionSpanInfo.spanStart_ + endPositionSpanInfo.spanOffset_;
2414             }
2415             resultObject.spanIndex = spanIndex;
2416             spanIndex++;
2417             resultObjects.emplace_back(resultObject);
2418             continue;
2419         }
2420         resultObject.spanRange[RichEditorSpanRange::RANGESTART] =
2421             spanItem->position - spanItem->content.length();
2422         resultObject.spanRange[RichEditorSpanRange::RANGEEND] = spanItem->position;
2423         resultObject.spanIndex = spanIndex;
2424         spanIndex++;
2425         resultObjects.emplace_back(resultObject);
2426     }
2427     return resultObjects;
2428 }
2429 
GetSelectSpanInfo(int32_t start,int32_t end)2430 std::list<SpanPosition> RichEditorPattern::GetSelectSpanInfo(int32_t start, int32_t end)
2431 {
2432     SpanPositionInfo startPositionSpanInfo(-1, -1, -1, -1);
2433     SpanPositionInfo endPositionSpanInfo(-1, -1, -1, -1);
2434     std::list<SpanPosition> resultObjects;
2435     int32_t spanIndex = 0;
2436     GetSelectSpansPositionInfo(start, end, startPositionSpanInfo, endPositionSpanInfo);
2437     CHECK_EQUAL_RETURN(startPositionSpanInfo.spanStart_, -1, resultObjects);
2438     if (startPositionSpanInfo.spanIndex_ == endPositionSpanInfo.spanIndex_) {
2439         SpanPosition resultObject;
2440         resultObject.spanRange[RichEditorSpanRange::RANGESTART] = start;
2441         resultObject.spanRange[RichEditorSpanRange::RANGEEND] = end;
2442         resultObject.spanIndex = spanIndex;
2443         resultObjects.emplace_back(resultObject);
2444     } else {
2445         resultObjects = GetSelectSpanSplit(startPositionSpanInfo, endPositionSpanInfo);
2446     }
2447     return resultObjects;
2448 }
2449 
GetSpansInfoByRange(int32_t start,int32_t end)2450 SelectionInfo RichEditorPattern::GetSpansInfoByRange(int32_t start, int32_t end)
2451 {
2452     auto selectionInfo = GetSpansInfo(start, end , GetSpansMethod::GETSPANS);
2453     auto& resultObjects = selectionInfo.GetSelectionRef().resultObjects;
2454     for (auto& resObj : resultObjects) {
2455         CHECK_NULL_CONTINUE(resObj.type == SelectSpanType::TYPESPAN);
2456         auto uiNode = GetChildByIndex(resObj.spanPosition.spanIndex);
2457         auto spanNode = DynamicCast<SpanNode>(uiNode);
2458         CHECK_NULL_CONTINUE(spanNode);
2459         auto fontFamily = spanNode->GetFontFamily();
2460         IF_TRUE(!fontFamily, resObj.textStyle.fontFamily.clear());
2461     }
2462     return selectionInfo;
2463 }
2464 
UpdateSelectSpanStyle(int32_t start,int32_t end,KeyCode code)2465 void RichEditorPattern::UpdateSelectSpanStyle(int32_t start, int32_t end, KeyCode code)
2466 {
2467     std::list<SpanPosition> resultObjects;
2468     resultObjects = GetSelectSpanInfo(start, end);
2469     bool isFirstText = true;
2470     for (auto& spanStyleIter : resultObjects) {
2471         SetSelectSpanStyle(spanStyleIter.spanRange[RichEditorSpanRange::RANGESTART],
2472             spanStyleIter.spanRange[RichEditorSpanRange::RANGEEND], code, isFirstText);
2473         isFirstText = false;
2474     }
2475 }
2476 
CheckStyledStringRangeValid(int32_t start,int32_t length)2477 bool RichEditorPattern::CheckStyledStringRangeValid(int32_t start, int32_t length)
2478 {
2479     if (!styledString_ || !styledString_->CheckRange(start, length)) {
2480         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "range:[%{public}d-%{public}d] is invalid or styledString is null",
2481             start, start + length);
2482         return false;
2483     }
2484     return true;
2485 }
2486 
UpdateSelectStyledStringStyle(int32_t start,int32_t end,KeyCode code)2487 void RichEditorPattern::UpdateSelectStyledStringStyle(int32_t start, int32_t end, KeyCode code)
2488 {
2489     CHECK_NULL_VOID(CheckStyledStringRangeValid(start, end - start));
2490     Font updateFont;
2491     bool isFirstSpanStylePresent;
2492     switch (code) {
2493     case KeyCode::KEY_B: {
2494         auto firstFontSpan = DynamicCast<FontSpan>(styledString_->GetSpan(start, 1, SpanType::Font));
2495         isFirstSpanStylePresent = firstFontSpan && firstFontSpan->GetFont().fontWeight == FontWeight::BOLD;
2496         updateFont.fontWeight = isFirstSpanStylePresent ? FontWeight::NORMAL : FontWeight::BOLD;
2497         UpdateStyledStringFontStyle(start, end, updateFont);
2498         break;
2499     }
2500     case KeyCode::KEY_I: {
2501         auto firstFontSpan = DynamicCast<FontSpan>(styledString_->GetSpan(start, 1, SpanType::Font));
2502         isFirstSpanStylePresent = firstFontSpan && firstFontSpan->GetFont().fontStyle == OHOS::Ace::FontStyle::ITALIC;
2503         updateFont.fontStyle = isFirstSpanStylePresent ? OHOS::Ace::FontStyle::NORMAL : OHOS::Ace::FontStyle::ITALIC;
2504         UpdateStyledStringFontStyle(start, end, updateFont);
2505         break;
2506     }
2507     case KeyCode::KEY_U: {
2508         auto firstDecorationSpan = DynamicCast<DecorationSpan>(styledString_->GetSpan(start, 1, SpanType::Decoration));
2509         isFirstSpanStylePresent =
2510             firstDecorationSpan && firstDecorationSpan->GetTextDecorationType() == TextDecoration::UNDERLINE;
2511         auto updateDecorationType = isFirstSpanStylePresent ? TextDecoration::NONE : TextDecoration::UNDERLINE;
2512         UpdateStyledStringDecorationType(start, end, updateDecorationType);
2513         break;
2514     }
2515     default:
2516         TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "Unsupported key code for UpdateSelectStyledStringStyle");
2517         return;
2518     }
2519 }
2520 
2521 template<typename T>
UpdateSpansStyleInRange(int32_t start,int32_t end,const RefPtr<SpanBase> & baseSpan,std::function<RefPtr<T> (const RefPtr<T> &)> && updateSpanFunc)2522 void RichEditorPattern::UpdateSpansStyleInRange(int32_t start, int32_t end, const RefPtr<SpanBase>& baseSpan,
2523     std::function<RefPtr<T>(const RefPtr<T>&)>&& updateSpanFunc)
2524 {
2525     auto length = end - start;
2526     CHECK_NULL_VOID(CheckStyledStringRangeValid(start, length));
2527     CHECK_NULL_VOID(baseSpan);
2528     auto spanType = baseSpan->GetSpanType();
2529     std::vector<RefPtr<SpanBase>> updateSpans;
2530     updateSpans.push_back(baseSpan);
2531     auto originalSpans = styledString_->GetSpans(start, length, spanType);
2532     for (auto& originalSpan : originalSpans) {
2533         auto originalTypedSpan = DynamicCast<T>(originalSpan);
2534         CHECK_NULL_CONTINUE(originalTypedSpan)
2535         updateSpans.push_back(updateSpanFunc(originalTypedSpan));
2536     }
2537     paragraphCache_.Clear();
2538     styledString_->BindWithSpans(updateSpans);
2539     styledString_->NotifySpanWatcher();
2540 }
2541 
UpdateStyledStringFontStyle(int32_t start,int32_t end,const Font & font)2542 void RichEditorPattern::UpdateStyledStringFontStyle(int32_t start, int32_t end, const Font& font)
2543 {
2544     auto fontSpan = AceType::MakeRefPtr<FontSpan>(font, start, end);
2545     auto updateFontSpanFunc = [&font](const RefPtr<FontSpan>& oriFontSpan) -> RefPtr<FontSpan> {
2546         CHECK_NULL_RETURN(oriFontSpan, nullptr);
2547         auto fontStyle = oriFontSpan->GetFont();
2548         if (font.fontStyle.has_value()) {
2549             fontStyle.fontStyle = font.fontStyle.value();
2550         }
2551         if (font.fontWeight.has_value()) {
2552             fontStyle.fontWeight = font.fontWeight.value();
2553         }
2554         return AceType::MakeRefPtr<FontSpan>(fontStyle, oriFontSpan->GetStartIndex(), oriFontSpan->GetEndIndex());
2555     };
2556     UpdateSpansStyleInRange<FontSpan>(start, end, fontSpan, updateFontSpanFunc);
2557 }
2558 
UpdateStyledStringDecorationType(int32_t start,int32_t end,const TextDecoration & type)2559 void RichEditorPattern::UpdateStyledStringDecorationType(int32_t start, int32_t end, const TextDecoration& type)
2560 {
2561     std::optional<Color> colorOption;
2562     std::optional<TextDecorationStyle> styleOption;
2563     auto decorationSpan = AceType::MakeRefPtr<DecorationSpan>(type, colorOption, styleOption, start, end);
2564     auto updateDecorationSpanFunc = [&type](const RefPtr<DecorationSpan>& oriDecorationSpan) -> RefPtr<DecorationSpan> {
2565         CHECK_NULL_RETURN(oriDecorationSpan, nullptr);
2566         auto decorationColor = oriDecorationSpan->GetColor();
2567         auto decorationStyle = oriDecorationSpan->GetTextDecorationStyle();
2568         return AceType::MakeRefPtr<DecorationSpan>(type, decorationColor, decorationStyle,
2569             oriDecorationSpan->GetStartIndex(), oriDecorationSpan->GetEndIndex());
2570     };
2571     UpdateSpansStyleInRange<DecorationSpan>(start, end, decorationSpan, updateDecorationSpanFunc);
2572 }
2573 
CloseSystemMenu()2574 void RichEditorPattern::CloseSystemMenu()
2575 {
2576     if (!SelectOverlayIsOn()) {
2577         return;
2578     }
2579     auto selectOverlayInfo = selectOverlay_->GetSelectOverlayInfo();
2580     if (selectOverlayInfo && !selectOverlayInfo->menuInfo.menuBuilder) {
2581         CloseSelectOverlay();
2582     }
2583 }
2584 
SetAccessibilityAction()2585 void RichEditorPattern::SetAccessibilityAction()
2586 {
2587     auto host = GetHost();
2588     CHECK_NULL_VOID(host);
2589     auto property = host->GetAccessibilityProperty<AccessibilityProperty>();
2590     CHECK_NULL_VOID(property);
2591     property->SetActionSetSelection([weakPtr = WeakClaim(this)](int32_t start, int32_t end, bool isForward) {
2592         TAG_LOGI(AceLogTag::ACE_RICH_TEXT,
2593             "Accessibility SetSelection, range=[%{public}d,%{public}d], isForward=%{public}d", start, end, isForward);
2594         const auto& pattern = weakPtr.Upgrade();
2595         CHECK_NULL_VOID(pattern);
2596         pattern->SetSelection(start, end, std::nullopt, isForward);
2597     });
2598 
2599     property->SetActionSetIndex([weakPtr = WeakClaim(this)](int32_t index) {
2600         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "Accessibility SetCaretOffset, index=%{public}d", index);
2601         const auto& pattern = weakPtr.Upgrade();
2602         CHECK_NULL_VOID(pattern);
2603         pattern->SetCaretOffset(index);
2604     });
2605 
2606     property->SetActionGetIndex([weakPtr = WeakClaim(this)]() -> int32_t {
2607         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "Accessibility GetCaretPosition");
2608         const auto& pattern = weakPtr.Upgrade();
2609         CHECK_NULL_RETURN(pattern, -1);
2610         return pattern->GetCaretPosition();
2611     });
2612     SetAccessibilityEditAction();
2613 }
2614 
SetAccessibilityEditAction()2615 void RichEditorPattern::SetAccessibilityEditAction()
2616 {
2617     auto host = GetHost();
2618     CHECK_NULL_VOID(host);
2619     auto property = host->GetAccessibilityProperty<AccessibilityProperty>();
2620     CHECK_NULL_VOID(property);
2621     property->SetActionSetText([weakPtr = WeakClaim(this)](const std::string& value) {
2622         std::u16string u16Value = UtfUtils::Str8ToStr16(value);
2623         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "EditAction setText, length: %{public}d",
2624             static_cast<int32_t>(u16Value.length()));
2625         const auto& pattern = weakPtr.Upgrade();
2626         CHECK_NULL_VOID(pattern);
2627         pattern->InsertValue(u16Value);
2628     });
2629 
2630     property->SetActionCopy([weakPtr = WeakClaim(this)]() {
2631         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "EditAction copy");
2632         const auto& pattern = weakPtr.Upgrade();
2633         CHECK_NULL_VOID(pattern);
2634         pattern->HandleOnCopy();
2635         pattern->CloseSelectionMenu();
2636     });
2637 
2638     property->SetActionCut([weakPtr = WeakClaim(this)]() {
2639         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "EditAction cut");
2640         const auto& pattern = weakPtr.Upgrade();
2641         CHECK_NULL_VOID(pattern);
2642         pattern->HandleOnCut();
2643     });
2644 
2645     property->SetActionPaste([weakPtr = WeakClaim(this)]() {
2646         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "EditAction paste");
2647         const auto& pattern = weakPtr.Upgrade();
2648         CHECK_NULL_VOID(pattern);
2649         pattern->HandleOnPaste();
2650         pattern->CloseSelectionMenu();
2651     });
2652 
2653     property->SetActionClearSelection([weakPtr = WeakClaim(this)]() {
2654         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "EditAction clearSelection");
2655         const auto& pattern = weakPtr.Upgrade();
2656         CHECK_NULL_VOID(pattern);
2657         pattern->CloseSelectionMenu();
2658         pattern->ResetSelection();
2659         pattern->StartTwinkling();
2660     });
2661 }
2662 
IsAccessibilityClick()2663 bool RichEditorPattern::IsAccessibilityClick()
2664 {
2665     auto host = GetHost();
2666     CHECK_NULL_RETURN(host, false);
2667     auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
2668     CHECK_NULL_RETURN(accessibilityProperty, false);
2669     return accessibilityProperty->GetAccessibilityFocusState();
2670 }
2671 
GetParagraphInfo(int32_t start,int32_t end)2672 std::vector<ParagraphInfo> RichEditorPattern::GetParagraphInfo(int32_t start, int32_t end)
2673 {
2674     std::vector<ParagraphInfo> res;
2675     auto spanNodes = GetParagraphNodes(start, end);
2676     CHECK_NULL_RETURN(!spanNodes.empty(), {});
2677 
2678     auto&& firstSpan = spanNodes.front()->GetSpanItem();
2679     auto paraStart = firstSpan->position - static_cast<int32_t>(firstSpan->content.length());
2680 
2681     for (auto it = spanNodes.begin(); it != spanNodes.end(); ++it) {
2682         if (it == std::prev(spanNodes.end()) || (*it)->GetSpanItem()->content.back() == u'\n') {
2683             ParagraphInfo info;
2684             auto lm = (*it)->GetLeadingMarginValue({});
2685             std::optional<double> spacingOpt;
2686             if (auto spacing = (*it)->GetParagraphSpacing(); spacing.has_value()) {
2687                 spacingOpt = spacing.value().ConvertToFp();
2688             }
2689             res.emplace_back(ParagraphInfo {
2690                 .leadingMarginPixmap = lm.pixmap,
2691                 .leadingMarginSize = { lm.size.Width().ToString(),
2692                     lm.size.Height().ToString() },
2693                 .textAlign = static_cast<int32_t>((*it)->GetTextAlignValue(TextAlign::START)),
2694                 .wordBreak = static_cast<int32_t>((*it)->GetWordBreakValue(WordBreak::BREAK_WORD)),
2695                 .lineBreakStrategy = static_cast<int32_t>((*it)->GetLineBreakStrategyValue(LineBreakStrategy::GREEDY)),
2696                 .paragraphSpacing = spacingOpt,
2697                 .range = { paraStart, (*it)->GetSpanItem()->position },
2698             });
2699             paraStart = (*it)->GetSpanItem()->position;
2700         }
2701     }
2702 
2703     return res;
2704 }
2705 
GetParagraphLength(const std::list<RefPtr<UINode>> & spans) const2706 int32_t RichEditorPattern::GetParagraphLength(const std::list<RefPtr<UINode>>& spans) const
2707 {
2708     if (spans.empty()) {
2709         return 0;
2710     }
2711     int32_t imageSpanCnt = 0;
2712     for (auto it = spans.rbegin(); it != spans.rend(); ++it) {
2713         auto spanNode = DynamicCast<SpanNode>(*it);
2714         if (spanNode) {
2715             return spanNode->GetSpanItem()->position + imageSpanCnt;
2716         }
2717         ++imageSpanCnt;
2718     }
2719     return imageSpanCnt;
2720 }
2721 
GetParagraphNodes(int32_t start,int32_t end) const2722 std::vector<RefPtr<SpanNode>> RichEditorPattern::GetParagraphNodes(int32_t start, int32_t end) const
2723 {
2724     CHECK_NULL_RETURN(start != end, {});
2725     auto host = GetHost();
2726     CHECK_NULL_RETURN(host, {});
2727     CHECK_NULL_RETURN(!host->GetChildren().empty(), {});
2728 
2729     const auto& spans = host->GetChildren();
2730     int32_t length = GetParagraphLength(spans);
2731     std::vector<RefPtr<SpanNode>> res;
2732 
2733     if (start >= length) {
2734         return res;
2735     }
2736 
2737     auto headIt = spans.begin();
2738     auto flagNode = headIt;
2739     bool isEnd = false;
2740     int32_t spanEnd = -1;
2741     while (flagNode != spans.end()) {
2742         auto spanNode = DynamicCast<SpanNode>(*flagNode);
2743         if (spanNode) {
2744             auto&& info = spanNode->GetSpanItem();
2745             spanEnd = info->position;
2746             isEnd = info->content.back() == u'\n';
2747         } else {
2748             ++spanEnd;
2749             isEnd = false;
2750         }
2751         flagNode++;
2752         if (spanEnd > start) {
2753             break;
2754         }
2755         if (isEnd) {
2756             headIt = flagNode;
2757         }
2758     }
2759     while (headIt != flagNode) {
2760         auto spanNode = DynamicCast<SpanNode>(*headIt);
2761         if (spanNode) {
2762             res.emplace_back(spanNode);
2763         }
2764         headIt++;
2765     }
2766     while (flagNode != spans.end() && (spanEnd < end || !isEnd)) {
2767         auto spanNode = DynamicCast<SpanNode>(*flagNode);
2768         if (spanNode) {
2769             res.emplace_back(spanNode);
2770             auto&& info = spanNode->GetSpanItem();
2771             spanEnd = info->position;
2772             isEnd = info->content.back() == u'\n';
2773         } else {
2774             ++spanEnd;
2775             isEnd = false;
2776         }
2777         flagNode++;
2778     }
2779 
2780     return res;
2781 }
2782 
UpdateParagraphStyle(int32_t start,int32_t end,const struct UpdateParagraphStyle & style)2783 void RichEditorPattern::UpdateParagraphStyle(int32_t start, int32_t end, const struct UpdateParagraphStyle& style)
2784 {
2785     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "updateParagraphStyle, range=[%{public}d,%{public}d]", start, end);
2786     auto spanNodes = GetParagraphNodes(start, end);
2787     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "spanNode cnt=%{public}d, style=%{public}s",
2788         static_cast<int32_t>(spanNodes.size()), style.ToString().c_str());
2789     for (const auto& spanNode : spanNodes) {
2790         UpdateParagraphStyle(spanNode, style);
2791     }
2792 }
2793 
UpdateParagraphStyle(RefPtr<SpanNode> spanNode,const struct UpdateParagraphStyle & style)2794 void RichEditorPattern::UpdateParagraphStyle(RefPtr<SpanNode> spanNode, const struct UpdateParagraphStyle& style)
2795 {
2796     CHECK_NULL_VOID(spanNode);
2797     spanNode->UpdateTextAlign(style.textAlign.value_or(TextAlign::START));
2798     spanNode->UpdateWordBreak(style.wordBreak.value_or(WordBreak::BREAK_WORD));
2799     spanNode->UpdateLineBreakStrategy(style.lineBreakStrategy.value_or(LineBreakStrategy::GREEDY));
2800     if (style.paragraphSpacing.has_value()) {
2801         spanNode->UpdateParagraphSpacing(style.paragraphSpacing.value());
2802     } else {
2803         spanNode->ResetParagraphSpacing();
2804     }
2805     if (style.leadingMargin.has_value()) {
2806         spanNode->GetSpanItem()->leadingMargin = *style.leadingMargin;
2807         spanNode->UpdateLeadingMargin(*style.leadingMargin);
2808     }
2809     IF_PRESENT(GetHost(), MarkDirtyNode(PROPERTY_UPDATE_MEASURE));
2810 }
2811 
ScheduleCaretTwinkling()2812 void RichEditorPattern::ScheduleCaretTwinkling()
2813 {
2814     ContainerScope scope(richEditorInstanceId_);
2815     auto host = GetHost();
2816     CHECK_NULL_VOID(host);
2817     auto context = host->GetContext();
2818     CHECK_NULL_VOID(context);
2819 
2820     if (!context->GetTaskExecutor()) {
2821         return;
2822     }
2823 
2824     if (isCursorAlwaysDisplayed_) {
2825         return;
2826     }
2827 
2828     auto weak = WeakClaim(this);
2829     caretTwinklingTask_.Reset([weak, instanceId = richEditorInstanceId_] {
2830         ContainerScope scope(instanceId);
2831         auto client = weak.Upgrade();
2832         CHECK_NULL_VOID(client);
2833         client->OnCaretTwinkling();
2834     });
2835     auto taskExecutor = context->GetTaskExecutor();
2836     CHECK_NULL_VOID(taskExecutor);
2837     taskExecutor->PostDelayedTask(caretTwinklingTask_, TaskExecutor::TaskType::UI, twinklingInterval_,
2838         "ArkUIRichEditorScheduleCaretTwinkling");
2839 }
2840 
StartTwinkling()2841 void RichEditorPattern::StartTwinkling()
2842 {
2843     caretTwinklingTask_.Cancel();
2844     caretVisible_ = true;
2845     auto tmpHost = GetHost();
2846     CHECK_NULL_VOID(tmpHost);
2847     tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2848     ScheduleCaretTwinkling();
2849     // Fire on selecion change when caret invisible -> visible
2850     if (!caretTwinkling_) {
2851         TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "StartTwinkling");
2852         caretTwinkling_ = true;
2853         FireOnSelectionChange(caretPosition_, caretPosition_);
2854     }
2855 }
2856 
ShowCaretWithoutTwinkling()2857 void RichEditorPattern::ShowCaretWithoutTwinkling()
2858 {
2859     isCursorAlwaysDisplayed_ = true;
2860     StartTwinkling();
2861 }
2862 
OnCaretTwinkling()2863 void RichEditorPattern::OnCaretTwinkling()
2864 {
2865     caretTwinklingTask_.Cancel();
2866     caretVisible_ = !caretVisible_;
2867     GetHost()->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2868     ScheduleCaretTwinkling();
2869 }
2870 
StopTwinkling()2871 void RichEditorPattern::StopTwinkling()
2872 {
2873     if (caretTwinkling_) {
2874         TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "StopTwinkling");
2875     }
2876     caretTwinkling_ = false;
2877     isCursorAlwaysDisplayed_ = false;
2878     caretTwinklingTask_.Cancel();
2879     if (caretVisible_) {
2880         caretVisible_ = false;
2881         GetHost()->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2882     }
2883 }
2884 
HandleClickEvent(GestureEvent & info)2885 void RichEditorPattern::HandleClickEvent(GestureEvent& info)
2886 {
2887     if (selectOverlay_->GetIsHandleMoving() || isMouseSelect_) {
2888         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "click rejected, isHandleMoving=%{public}d, isMouseSelect=%{public}d",
2889             selectOverlay_->GetIsHandleMoving(), isMouseSelect_);
2890         return;
2891     }
2892     auto focusHub = GetFocusHub();
2893     CHECK_NULL_VOID(focusHub);
2894     if (!focusHub->IsFocusable()) {
2895         return;
2896     }
2897 
2898     if (!HasFocus() && !focusHub->IsFocusOnTouch().value_or(true)) {
2899         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "HandleClickEvent fail when IsFocusOnTouch false");
2900         CloseSelectOverlay();
2901         StopTwinkling();
2902         return;
2903     }
2904 
2905     selectionMenuOffsetClick_ = OffsetF(
2906         static_cast<float>(info.GetGlobalLocation().GetX()), static_cast<float>(info.GetGlobalLocation().GetY()));
2907     if (dataDetectorAdapter_->hasClickedAISpan_) {
2908         dataDetectorAdapter_->hasClickedAISpan_ = false;
2909     }
2910     multipleClickRecognizer_->Start(info);
2911     if (multipleClickRecognizer_->IsTripleClick()) {
2912         HandleTripleClickEvent(info);
2913     } else if (multipleClickRecognizer_->IsDoubleClick()) {
2914         HandleDoubleClickEvent(info);
2915     } else {
2916         HandleSingleClickEvent(info);
2917         NotifyCaretChange();
2918     }
2919 }
2920 
HandleClickSelection(const OHOS::Ace::GestureEvent & info)2921 bool RichEditorPattern::HandleClickSelection(const OHOS::Ace::GestureEvent& info)
2922 {
2923     CHECK_NULL_RETURN(!selectOverlay_->GetIsHandleMoving(), true);
2924     if (SelectOverlayIsOn()) {
2925         selectOverlay_->SwitchToOverlayMode();
2926         selectOverlay_->ToggleMenu();
2927     } else {
2928         CalculateHandleOffsetAndShowOverlay();
2929         selectOverlay_->ProcessOverlay({.animation = true, .requestCode = REQUEST_RECREATE});
2930     }
2931     return true;
2932 }
2933 
IsClickEventOnlyForMenuToggle(const OHOS::Ace::GestureEvent & info)2934 bool RichEditorPattern::IsClickEventOnlyForMenuToggle(const OHOS::Ace::GestureEvent& info)
2935 {
2936     CHECK_NULL_RETURN(info.GetSourceDevice() != SourceType::MOUSE, false);
2937     // In preview state or single handle showing, clicking handle has toggled the menu display
2938     bool hasHandledMenuToggleByClick =
2939         selectOverlay_->IsClickAtHandle(info) && (!isEditing_ || selectOverlay_->IsSingleHandleShow());
2940     CHECK_NULL_RETURN(!hasHandledMenuToggleByClick, true);
2941     if (showSelect_ && BetweenSelection(info.GetGlobalLocation())) {
2942         return HandleClickSelection(info);
2943     }
2944     return false;
2945 }
2946 
HandleSingleClickEvent(OHOS::Ace::GestureEvent & info)2947 void RichEditorPattern::HandleSingleClickEvent(OHOS::Ace::GestureEvent& info)
2948 {
2949     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "handleSingleClick");
2950     hasClicked_ = true;
2951     lastClickTimeStamp_ = info.GetTimeStamp();
2952     CHECK_NULL_VOID(!IsClickEventOnlyForMenuToggle(info));
2953     CHECK_NULL_VOID(!HandleUrlSpanClickEvent(info));
2954 
2955     Offset textOffset = ConvertTouchOffsetToTextOffset(info.GetLocalLocation());
2956     IF_TRUE(!isMousePressed_, HandleClickAISpanEvent(PointF(textOffset.GetX(), textOffset.GetY())));
2957 
2958     if (dataDetectorAdapter_->hasClickedAISpan_ || dataDetectorAdapter_->pressedByLeftMouse_) {
2959         IF_TRUE(SelectOverlayIsOn(), selectOverlay_->HideMenu());
2960         return;
2961     }
2962 
2963     HandleUserClickEvent(info);
2964     CHECK_NULL_VOID(!info.IsPreventDefault());
2965     bool isMouseClick = info.GetSourceDevice() == SourceType::MOUSE;
2966     bool isMouseClickWithShift = shiftFlag_ && isMouseClick && !IsPreviewTextInputting();
2967     if (textSelector_.IsValid() && !isMouseSelect_ && !isMouseClickWithShift) {
2968         CloseSelectOverlay();
2969         ResetSelection();
2970     }
2971     moveCaretState_.Reset();
2972     caretUpdateType_ = CaretUpdateType::PRESSED;
2973     CHECK_NULL_VOID(overlayMod_);
2974     RectF lastCaretRect = GetCaretRect();
2975     int32_t lastCaretPosition = caretPosition_;
2976     bool isCaretTwinkling = caretTwinkling_;
2977     auto position = paragraphs_.GetIndex(textOffset);
2978     AdjustCursorPosition(position);
2979     if (auto focusHub = GetFocusHub(); focusHub) {
2980         IF_TRUE(!isMouseClick || (blockPress_ && !isMouseClickWithShift), SetCaretPosition(position));
2981         IF_TRUE(isMouseClickWithShift, HandleShiftSelect(position));
2982         if (focusHub->IsCurrentFocus()) {
2983             HandleOnEditChanged(true);
2984         }
2985         if (focusHub->RequestFocusImmediately()) {
2986             IF_TRUE(!shiftFlag_ || textSelector_.SelectNothing(), StartTwinkling());
2987             RequestKeyboard(false, true, true, info.GetSourceDevice());
2988         }
2989     }
2990     UseHostToUpdateTextFieldManager();
2991     CalcCaretInfoByClick(info.GetLocalLocation());
2992     CHECK_NULL_VOID(!isMouseClick);
2993     if (IsShowSingleHandleByClick(info, lastCaretPosition, lastCaretRect, isCaretTwinkling)) {
2994         CreateAndShowSingleHandle();
2995     }
2996 }
2997 
GetTextOffset(const Offset & localLocation,const RectF & contentRect)2998 PointF RichEditorPattern::GetTextOffset(const Offset &localLocation, const RectF &contentRect)
2999 {
3000     PointF textOffset = {static_cast<float>(localLocation.GetX()) - GetTextRect().GetX(),
3001                          static_cast<float>(localLocation.GetY()) - GetTextRect().GetY()};
3002     return textOffset;
3003 }
3004 
GetSelectedRects(int32_t start,int32_t end)3005 std::vector<RectF> RichEditorPattern::GetSelectedRects(int32_t start, int32_t end)
3006 {
3007     return paragraphs_.GetRects(start, end);
3008 }
3009 
ConvertTouchOffsetToTextOffset(const Offset & touchOffset)3010 Offset RichEditorPattern::ConvertTouchOffsetToTextOffset(const Offset& touchOffset)
3011 {
3012     richTextRect_.SetTop(richTextRect_.GetY() - std::min(baselineOffset_, 0.0f));
3013     richTextRect_.SetHeight(richTextRect_.Height() - std::max(baselineOffset_, 0.0f));
3014     return touchOffset - Offset(richTextRect_.GetX(), richTextRect_.GetY());
3015 }
3016 
IsShowSingleHandleByClick(const OHOS::Ace::GestureEvent & info,int32_t lastCaretPosition,const RectF & lastCaretRect,bool isCaretTwinkling)3017 bool RichEditorPattern::IsShowSingleHandleByClick(
3018     const OHOS::Ace::GestureEvent& info, int32_t lastCaretPosition, const RectF& lastCaretRect, bool isCaretTwinkling)
3019 {
3020     auto isAccessibilityClick = IsAccessibilityClick();
3021     if (!isCaretTwinkling || (info.GetSourceDevice() == SourceType::MOUSE) || isAccessibilityClick) {
3022         TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "isCaretTwinkling=%{public}d,sourceType=%{public}d,"
3023             "isAccessibilityClick=%{public}d", isCaretTwinkling, info.GetSourceDevice(), isAccessibilityClick);
3024         return false;
3025     }
3026     auto offset = info.GetLocalLocation();
3027     Offset textOffset = ConvertTouchOffsetToTextOffset(offset);
3028     auto position = (GetTextContentLength() == 0) ? 0 : paragraphs_.GetIndex(textOffset);
3029     if (position != lastCaretPosition) {
3030         TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "clickCaretPosition=%{public}d but lastCaretPosition=%{public}d",
3031             position, lastCaretPosition);
3032         return false;
3033     }
3034     auto paragraphEndPos = GetParagraphEndPosition(lastCaretPosition);
3035     if (lastCaretPosition == paragraphEndPos || IsTouchAtLineEnd(lastCaretPosition, textOffset)) {
3036         TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "repeat click lineEnd or paragraphEndPos=%{public}d", paragraphEndPos);
3037         return true;
3038     }
3039     return RepeatClickCaret(offset, lastCaretRect);
3040 }
3041 
RepeatClickCaret(const Offset & offset,const RectF & lastCaretRect)3042 bool RichEditorPattern::RepeatClickCaret(const Offset& offset, const RectF& lastCaretRect)
3043 {
3044     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "caretTwinkling=%{public}d offset=%{public}s lastCaretRect=%{public}s",
3045         caretTwinkling_, offset.ToString().c_str(), lastCaretRect.ToString().c_str());
3046     CHECK_NULL_RETURN(caretTwinkling_, false);
3047     auto lastCaretHeight = lastCaretRect.Height();
3048     auto handleHotZone = selectOverlay_->GetHandleHotZoneRadius();
3049     auto caretHotZoneRect =
3050         RectF(lastCaretRect.GetX() - handleHotZone, lastCaretRect.GetY(), handleHotZone * 2, lastCaretHeight);
3051     return caretHotZoneRect.IsInRegion(PointF(offset.GetX(), offset.GetY()));
3052 }
3053 
CreateAndShowSingleHandle()3054 void RichEditorPattern::CreateAndShowSingleHandle()
3055 {
3056     if (IsPreviewTextInputting()) {
3057         return;
3058     }
3059     textResponseType_ = TextResponseType::LONG_PRESS;
3060     selectOverlay_->SetIsSingleHandle(true);
3061     textSelector_.Update(caretPosition_);
3062     CalculateHandleOffsetAndShowOverlay();
3063     UpdateSelectionType(GetSpansInfo(caretPosition_, caretPosition_, GetSpansMethod::ONSELECT));
3064     selectOverlay_->ProcessOverlay({ .animation = true });
3065 }
3066 
MoveCaretAndStartFocus(const Offset & textOffset)3067 void RichEditorPattern::MoveCaretAndStartFocus(const Offset& textOffset)
3068 {
3069     auto position = paragraphs_.GetIndex(textOffset);
3070     AdjustCursorPosition(position);
3071 
3072     auto focusHub = GetFocusHub();
3073     if (focusHub) {
3074         SetCaretPosition(position);
3075         if (focusHub->RequestFocusImmediately()) {
3076             IF_TRUE(!shiftFlag_ || textSelector_.SelectNothing(), StartTwinkling());
3077             if (overlayMod_) {
3078                 RequestKeyboard(false, true, true);
3079             }
3080             HandleOnEditChanged(true);
3081         }
3082     }
3083     UseHostToUpdateTextFieldManager();
3084 }
3085 
HandleDoubleClickEvent(OHOS::Ace::GestureEvent & info)3086 void RichEditorPattern::HandleDoubleClickEvent(OHOS::Ace::GestureEvent& info)
3087 {
3088     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "HandleDoubleClickEvent");
3089     caretUpdateType_ = CaretUpdateType::DOUBLE_CLICK;
3090     HandleDoubleClickOrLongPress(info);
3091     caretUpdateType_ = CaretUpdateType::NONE;
3092 }
3093 
HandleUserGestureEvent(GestureEvent & info,std::function<bool (RefPtr<SpanItem> item,GestureEvent & info)> && gestureFunc)3094 bool RichEditorPattern::HandleUserGestureEvent(
3095     GestureEvent& info, std::function<bool(RefPtr<SpanItem> item, GestureEvent& info)>&& gestureFunc)
3096 {
3097     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "HandleUserGestureEvent");
3098     RectF textContentRect = contentRect_;
3099     textContentRect.SetTop(contentRect_.GetY() - std::min(baselineOffset_, 0.0f));
3100     textContentRect.SetHeight(contentRect_.Height() - std::max(baselineOffset_, 0.0f));
3101     if (!textContentRect.IsInRegion(PointF(info.GetLocalLocation().GetX(), info.GetLocalLocation().GetY())) ||
3102         spans_.empty()) {
3103         return false;
3104     }
3105     PointF textOffset = { info.GetLocalLocation().GetX() - GetTextRect().GetX(),
3106         info.GetLocalLocation().GetY() - GetTextRect().GetY() };
3107     int32_t start = 0;
3108     bool isParagraphHead = true;
3109     Offset paragraphOffset(0, 0);
3110     for (const auto& item : spans_) {
3111         if (!item) {
3112             continue;
3113         }
3114         std::vector<RectF> selectedRects = paragraphs_.GetRects(start, item->position);
3115         start = item->position;
3116         if (isParagraphHead && !selectedRects.empty()) {
3117             if (item->leadingMargin.has_value()) {
3118                 auto addWidth = item->leadingMargin.value().size.Width();
3119                 selectedRects[0].SetLeft(selectedRects[0].GetX() - addWidth.ConvertToPx());
3120                 selectedRects[0].SetWidth(selectedRects[0].GetSize().Width() + addWidth.ConvertToPx());
3121             }
3122             paragraphOffset.SetX(selectedRects[0].GetOffset().GetX());
3123             paragraphOffset.SetY(selectedRects[0].GetOffset().GetY());
3124             isParagraphHead = false;
3125         }
3126         if (!isParagraphHead && item->content.back() == '\n') {
3127             isParagraphHead = true;
3128         }
3129         for (auto&& rect : selectedRects) {
3130             if (!rect.IsInRegion(textOffset)) {
3131                 continue;
3132             }
3133             info = info.SetScreenLocation(
3134                 Offset(textOffset.GetX() - paragraphOffset.GetX(), textOffset.GetY() - paragraphOffset.GetY()));
3135             return gestureFunc(item, info);
3136         }
3137     }
3138     return false;
3139 }
3140 
ClickAISpan(const PointF & textOffset,const AISpan & aiSpan)3141 bool RichEditorPattern::ClickAISpan(const PointF& textOffset, const AISpan& aiSpan)
3142 {
3143     auto calculateHandleFunc = [weak = WeakClaim(this)]() {
3144         auto pattern = weak.Upgrade();
3145         CHECK_NULL_VOID(pattern);
3146         pattern->CalculateHandleOffsetAndShowOverlay();
3147     };
3148     auto showSelectOverlayFunc = [weak = WeakClaim(this)](const RectF& firstHandle, const RectF& secondHandle) {
3149         auto pattern = weak.Upgrade();
3150         CHECK_NULL_VOID(pattern);
3151         pattern->SetCaretPosition(pattern->textSelector_.destinationOffset);
3152         auto focusHub = pattern->GetFocusHub();
3153         CHECK_NULL_VOID(focusHub);
3154         focusHub->RequestFocusImmediately();
3155         IF_TRUE(!pattern->isEditing_, pattern->CloseKeyboard(true));
3156         pattern->ShowSelectOverlay(firstHandle, secondHandle);
3157     };
3158 
3159     std::vector<RectF> aiRects = paragraphs_.GetRects(aiSpan.start, aiSpan.end);
3160     for (auto&& rect : aiRects) {
3161         if (rect.IsInRegion(textOffset)) {
3162             dataDetectorAdapter_->clickedAISpan_ = aiSpan;
3163             if (leftMousePress_) {
3164                 dataDetectorAdapter_->pressedByLeftMouse_ = true;
3165                 return true;
3166             }
3167             dataDetectorAdapter_->hasClickedAISpan_ = true;
3168             ShowAIEntityMenu(aiSpan, calculateHandleFunc, showSelectOverlayFunc);
3169             return true;
3170         }
3171     }
3172     return false;
3173 }
3174 
GetStartAndEnd(int32_t start,const RefPtr<SpanItem> & item)3175 std::pair<int32_t, int32_t> RichEditorPattern::GetStartAndEnd(int32_t start, const RefPtr<SpanItem>& item)
3176 {
3177     return isSpanStringMode_
3178         ? TextPattern::GetStartAndEnd(start, item)
3179         : std::make_pair(item->rangeStart, item->position);
3180 }
3181 
HandleUrlSpanClickEvent(const GestureEvent & info)3182 bool RichEditorPattern::HandleUrlSpanClickEvent(const GestureEvent& info)
3183 {
3184     RectF textContentRect = contentRect_;
3185     textContentRect.SetTop(contentRect_.GetY() - std::min(baselineOffset_, 0.0f));
3186     textContentRect.SetHeight(contentRect_.Height() - std::max(baselineOffset_, 0.0f));
3187 
3188     CheckClickedOnSpanOrText(textContentRect, info.GetLocalLocation());
3189     auto clickedSpanPosition = GetClickedSpanPosition();
3190     if (LessNotEqual(clickedSpanPosition, 0)) {
3191         return false;
3192     }
3193     auto iter = spans_.begin();
3194     std::advance(iter, clickedSpanPosition);
3195     RefPtr<SpanItem> span;
3196     if (iter == spans_.end()) {
3197         span = spans_.back();
3198     } else {
3199         span = *iter;
3200     }
3201     if (span && span->urlOnRelease) {
3202         span->urlOnRelease();
3203         return true;
3204     }
3205     return false;
3206 }
3207 
HandleUserClickEvent(GestureEvent & info)3208 bool RichEditorPattern::HandleUserClickEvent(GestureEvent& info)
3209 {
3210     auto clickFunc = [](RefPtr<SpanItem> item, GestureEvent& info) -> bool {
3211         if (item && item->onClick) {
3212             item->onClick(info);
3213             return true;
3214         }
3215         return false;
3216     };
3217     return HandleUserGestureEvent(info, std::move(clickFunc));
3218 }
3219 
CalcCaretInfoByClick(const Offset & touchOffset)3220 void RichEditorPattern::CalcCaretInfoByClick(const Offset& touchOffset)
3221 {
3222     auto textRect = GetTextRect();
3223     textRect.SetTop(textRect.GetY() - std::min(baselineOffset_, 0.0f));
3224     textRect.SetHeight(textRect.Height() - std::max(baselineOffset_, 0.0f));
3225     Offset textOffset = { touchOffset.GetX() - textRect.GetX(), touchOffset.GetY() - textRect.GetY() };
3226     auto [lastClickOffset, caretHeight] = CalcAndRecordLastClickCaretInfo(textOffset);
3227     CHECK_NULL_VOID(overlayMod_);
3228     DynamicCast<RichEditorOverlayModifier>(overlayMod_)->SetCaretOffsetAndHeight(lastClickOffset, caretHeight);
3229     MoveCaretToContentRect();
3230 }
3231 
CalcAndRecordLastClickCaretInfo(const Offset & textOffset)3232 std::pair<OffsetF, float> RichEditorPattern::CalcAndRecordLastClickCaretInfo(const Offset& textOffset)
3233 {
3234     // get the caret position
3235     auto positionWithAffinity = paragraphs_.GetGlyphPositionAtCoordinate(textOffset);
3236     auto position = static_cast<int32_t>(positionWithAffinity.position_);
3237     // get the caret offset when click
3238     float caretHeight = 0.0f;
3239     auto lastClickOffset = paragraphs_.ComputeCursorInfoByClick(position, caretHeight,
3240         OffsetF(static_cast<float>(textOffset.GetX()), static_cast<float>(textOffset.GetY())));
3241 
3242     lastClickOffset += richTextRect_.GetOffset();
3243     if (isShowPlaceholder_) {
3244         auto [caretOffset, preferredHeight] = CalculateEmptyValueCaretRect();
3245         lastClickOffset = caretOffset;
3246     }
3247     SetLastClickOffset(lastClickOffset);
3248     caretAffinityPolicy_ = (positionWithAffinity.affinity_ == TextAffinity::UPSTREAM)
3249                                 ? CaretAffinityPolicy::UPSTREAM_FIRST
3250                                 : CaretAffinityPolicy::DOWNSTREAM_FIRST;
3251     return std::make_pair(lastClickOffset, caretHeight);
3252 }
3253 
InitClickEvent(const RefPtr<GestureEventHub> & gestureHub)3254 void RichEditorPattern::InitClickEvent(const RefPtr<GestureEventHub>& gestureHub)
3255 {
3256     CHECK_NULL_VOID(!clickEventInitialized_);
3257     auto clickCallback = [weak = WeakClaim(this)](GestureEvent& info) {
3258         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "click callback, sourceType=%{public}d", info.GetSourceDevice());
3259         auto pattern = weak.Upgrade();
3260         CHECK_NULL_VOID(pattern);
3261         pattern->sourceType_ = info.GetSourceDevice();
3262         pattern->HandleClickEvent(info);
3263     };
3264     auto clickListener = MakeRefPtr<ClickEvent>(std::move(clickCallback));
3265     gestureHub->AddClickAfterEvent(clickListener);
3266     clickEventInitialized_ = true;
3267 }
3268 
InitFocusEvent(const RefPtr<FocusHub> & focusHub)3269 void RichEditorPattern::InitFocusEvent(const RefPtr<FocusHub>& focusHub)
3270 {
3271     CHECK_NULL_VOID(!focusEventInitialized_);
3272     auto focusTask = [weak = WeakClaim(this)]() {
3273         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "rich editor in focus");
3274         auto pattern = weak.Upgrade();
3275         CHECK_NULL_VOID(pattern);
3276         pattern->HandleFocusEvent();
3277     };
3278     focusHub->SetOnFocusInternal(focusTask);
3279     auto blurTask = [weak = WeakClaim(this)]() {
3280         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "rich editor in blur");
3281         auto pattern = weak.Upgrade();
3282         CHECK_NULL_VOID(pattern);
3283         pattern->HandleBlurEvent();
3284     };
3285     focusHub->SetOnBlurInternal(blurTask);
3286     focusEventInitialized_ = true;
3287     auto keyTask = [weak = WeakClaim(this)](const KeyEvent& keyEvent) -> bool {
3288         auto pattern = weak.Upgrade();
3289         CHECK_NULL_RETURN(pattern, false);
3290         return pattern->OnKeyEvent(keyEvent);
3291     };
3292     focusHub->SetOnKeyEventInternal(std::move(keyTask));
3293 }
3294 
GetBlurReason()3295 BlurReason RichEditorPattern::GetBlurReason()
3296 {
3297     auto host = GetHost();
3298     CHECK_NULL_RETURN(host, BlurReason::FOCUS_SWITCH);
3299     auto curFocusHub = host->GetFocusHub();
3300     CHECK_NULL_RETURN(curFocusHub, BlurReason::FOCUS_SWITCH);
3301     return curFocusHub->GetBlurReason();
3302 }
3303 
HandleBlurEvent()3304 void RichEditorPattern::HandleBlurEvent()
3305 {
3306     auto reason = GetBlurReason();
3307     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "HandleBlurEvent/%{public}d, blur reason=%{public}d", frameId_, reason);
3308     auto host = GetHost();
3309     ClearOnFocusTextField(RawPtr(host));
3310     host.Reset();
3311     IF_PRESENT(multipleClickRecognizer_, Stop());
3312     CHECK_NULL_VOID(showSelect_ || !IsSelected());
3313     isLongPress_ = false;
3314     ResetTouchSelectState();
3315     shiftFlag_ = false;
3316     moveCaretState_.Reset();
3317     floatingCaretState_.Reset();
3318     StopTwinkling();
3319     // The pattern handles blurevent, Need to close the softkeyboard first.
3320     if ((customKeyboardBuilder_ && isCustomKeyboardAttached_) || reason == BlurReason::FRAME_DESTROY) {
3321         TAG_LOGI(AceLogTag::ACE_KEYBOARD, "RichEditor Blur, Close Keyboard.");
3322         CloseSelectOverlay();
3323         ResetSelection();
3324         CloseKeyboard(false);
3325     }
3326     if (magnifierController_) {
3327         magnifierController_->RemoveMagnifierFrameNode();
3328     }
3329     if (IsSelected() && reason == BlurReason::FOCUS_SWITCH) {
3330         CloseSelectOverlay();
3331         ResetSelection();
3332     } else if (IsSelected()) {
3333         selectOverlay_->HideMenu(true);
3334     } else {
3335         CloseSelectOverlay();
3336     }
3337     if (reason != BlurReason::WINDOW_BLUR) {
3338         lastSelectionRange_.reset();
3339     }
3340     HandleOnEditChanged(false);
3341 }
3342 
HandleFocusEvent()3343 void RichEditorPattern::HandleFocusEvent()
3344 {
3345     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "HandleFocusEvent/%{public}d", frameId_);
3346     blockKbInFloatingWindow_= false;
3347     UseHostToUpdateTextFieldManager();
3348     if (previewLongPress_ || isOnlyRequestFocus_) {
3349         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "HandleFocusEvent, previewLongPress=%{public}d,"
3350             "OnlyRequestFocus=%{public}d", previewLongPress_, isOnlyRequestFocus_);
3351         isOnlyRequestFocus_ = false;
3352         return;
3353     }
3354     SetIsEnableSubWindowMenu();
3355     if (textSelector_.SelectNothing()) {
3356         StartTwinkling();
3357     }
3358     auto host = GetHost();
3359     if (host) {
3360         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
3361     }
3362 
3363     bool clickAIMenu = dataDetectorAdapter_->hasClickedMenuOption_;
3364     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "longPress=%{public}d, clickAIMenu=%{public}d", isLongPress_, clickAIMenu);
3365     bool bindKeyboard = !isLongPress_ && !clickAIMenu;
3366     CHECK_NULL_VOID(bindKeyboard);
3367 
3368     auto windowMode = GetWindowMode();
3369     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "requestKeyboard=%{public}d, windowMode=%{public}d, rightButton=%{public}d",
3370         needToRequestKeyboardOnFocus_, windowMode, usingMouseRightButton_);
3371 
3372     bool needShowSoftKeyboard = needToRequestKeyboardOnFocus_;
3373     needShowSoftKeyboard &= !usingMouseRightButton_; // do not show kb when mouseRightClick
3374 
3375     if (windowMode == WindowMode::WINDOW_MODE_FLOATING) {
3376         blockKbInFloatingWindow_ = needShowSoftKeyboard;
3377         needShowSoftKeyboard = false;
3378     }
3379 
3380     RequestKeyboard(false, true, needShowSoftKeyboard);
3381     HandleOnEditChanged(true);
3382 }
3383 
OnFocusNodeChange(FocusReason focusReason)3384 void RichEditorPattern::OnFocusNodeChange(FocusReason focusReason)
3385 {
3386     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "OnFocusNodeChange/%{public}d, reason=%{public}d, blockKbInFloating=%{public}d",
3387         frameId_, focusReason, blockKbInFloatingWindow_);
3388     CHECK_NULL_VOID(blockKbInFloatingWindow_);
3389     blockKbInFloatingWindow_= false;
3390     CHECK_NULL_VOID(GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING);
3391     CHECK_NULL_VOID(focusReason != FocusReason::WINDOW_FOCUS);
3392     CHECK_NULL_VOID(HasFocus() && isEditing_);
3393     bool clickAIMenu = dataDetectorAdapter_->hasClickedMenuOption_;
3394     bool bindKeyboard = !isLongPress_ && !clickAIMenu;
3395     CHECK_NULL_VOID(bindKeyboard);
3396     CHECK_NULL_VOID(needToRequestKeyboardOnFocus_ && !usingMouseRightButton_);
3397 
3398     RequestKeyboard(false, true, true);
3399 }
3400 
GetWindowMode()3401 WindowMode RichEditorPattern::GetWindowMode()
3402 {
3403     auto pipelineContext = GetContext();
3404     CHECK_NULL_RETURN(pipelineContext, WindowMode::WINDOW_MODE_UNDEFINED);
3405     auto windowManager = pipelineContext->GetWindowManager();
3406     CHECK_NULL_RETURN(windowManager, WindowMode::WINDOW_MODE_UNDEFINED);
3407     return windowManager->GetWindowMode();
3408 }
3409 
GetIsMidScene()3410 bool RichEditorPattern::GetIsMidScene()
3411 {
3412     auto context = GetContext();
3413     CHECK_NULL_RETURN(context, false);
3414     auto windowManager = context->GetWindowManager();
3415     CHECK_NULL_RETURN(windowManager, false);
3416     bool isMidScene = false;
3417     int32_t ret = windowManager->GetIsMidScene(isMidScene);
3418     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "GetIsMidScene ret=%{public}d", ret);
3419     return isMidScene;
3420 }
3421 
UseHostToUpdateTextFieldManager()3422 void RichEditorPattern::UseHostToUpdateTextFieldManager()
3423 {
3424     auto host = GetHost();
3425     CHECK_NULL_VOID(host);
3426     auto context = host->GetContext();
3427     CHECK_NULL_VOID(context);
3428     auto globalOffset = host->GetPaintRectOffsetNG(false, true) - context->GetRootRect().GetOffset();
3429     UpdateTextFieldManager(Offset(globalOffset.GetX(), globalOffset.GetY()), frameRect_.Height());
3430 }
3431 
OnVisibleChange(bool isVisible)3432 void RichEditorPattern::OnVisibleChange(bool isVisible)
3433 {
3434     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "isVisible=%{public}d", isVisible);
3435     TextPattern::OnVisibleChange(isVisible);
3436     StopTwinkling();
3437     CloseSelectOverlay();
3438     ResetSelection();
3439     if (!isVisible && HasFocus()) {
3440         CloseKeyboard(false);
3441     }
3442 }
3443 
CloseKeyboard(bool forceClose)3444 bool RichEditorPattern::CloseKeyboard(bool forceClose)
3445 {
3446     if (customKeyboardBuilder_ && isCustomKeyboardAttached_) {
3447         return CloseCustomKeyboard();
3448     }
3449     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "Request close soft keyboard.");
3450 #if defined(ENABLE_STANDARD_INPUT)
3451 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
3452     if (!imeAttached_ && !forceClose) {
3453         return false;
3454     }
3455 #endif
3456     auto inputMethod = MiscServices::InputMethodController::GetInstance();
3457     CHECK_NULL_RETURN(inputMethod, false);
3458     inputMethod->HideTextInput();
3459     inputMethod->Close();
3460 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
3461     imeAttached_ = false;
3462 #endif
3463 #else
3464     if (HasConnection()) {
3465         connection_->Close(GetInstanceId());
3466         connection_ = nullptr;
3467     }
3468 #endif
3469     return true;
3470 }
3471 
HandleDraggableFlag(bool isTouchSelectArea)3472 void RichEditorPattern::HandleDraggableFlag(bool isTouchSelectArea)
3473 {
3474     if (copyOption_ != CopyOptions::None && isTouchSelectArea) {
3475         bool isContentDraggalbe = JudgeContentDraggable();
3476         if (isContentDraggalbe) {
3477             dragBoxes_ = GetTextBoxes();
3478         }
3479         SetIsTextDraggable(isContentDraggalbe);
3480     } else {
3481         SetIsTextDraggable(false);
3482     }
3483 }
3484 
SetIsTextDraggable(bool isTextDraggable)3485 void RichEditorPattern::SetIsTextDraggable(bool isTextDraggable)
3486 {
3487     auto gestureHub = GetGestureEventHub();
3488     IF_PRESENT(gestureHub, SetIsTextDraggable(isTextDraggable));
3489 }
3490 
JudgeContentDraggable()3491 bool RichEditorPattern::JudgeContentDraggable()
3492 {
3493     if (!IsSelected() || copyOption_ == CopyOptions::None) {
3494         return false ;
3495     }
3496     auto selectInfo = GetSpansInfo(textSelector_.GetTextStart(), textSelector_.GetTextEnd(), GetSpansMethod::ONSELECT);
3497     auto selResult = selectInfo.GetSelection().resultObjects;
3498     auto iter = std::find_if(selResult.begin(), selResult.end(), [](ResultObject& obj) { return obj.isDraggable; });
3499     return iter != selResult.end();
3500 }
3501 
CalculateCaretOffsetAndHeight()3502 std::pair<OffsetF, float> RichEditorPattern::CalculateCaretOffsetAndHeight()
3503 {
3504     OffsetF caretOffset;
3505     float caretHeight = 0.0f;
3506     auto caretPosition = caretPosition_;
3507     float caretHeightUp = 0.0f;
3508     auto caretBoundaryRect = GetCaretBoundaryRect();
3509     OffsetF caretOffsetUp = CalcCursorOffsetByPosition(caretPosition, caretHeightUp, false, false);
3510     if (isShowPlaceholder_) {
3511         auto textAlign = GetTextAlignByDirection();
3512         IF_TRUE(textAlign == TextAlign::END, caretOffsetUp.SetX(caretBoundaryRect.Right()));
3513         return { caretOffsetUp, caretHeightUp };
3514     }
3515     if (GetTextContentLength() <= 0) {
3516         constexpr float DEFAULT_CARET_HEIGHT = 18.5f;
3517         auto [caretOffset, preferredHeight] = CalculateEmptyValueCaretRect();
3518         caretHeight = typingTextStyle_.has_value() ? preferredHeight
3519             : static_cast<float>(Dimension(DEFAULT_CARET_HEIGHT, DimensionUnit::VP).ConvertToPx());
3520         return { caretOffset, caretHeight };
3521     }
3522     float caretHeightDown = 0.0f;
3523     OffsetF caretOffsetDown = CalcCursorOffsetByPosition(caretPosition, caretHeightDown, true, false);
3524     bool isCaretPosInLineEnd = !NearEqual(caretOffsetDown.GetX(), caretOffsetUp.GetX(), 0.5f);
3525     bool isShowCaretDown = isCaretPosInLineEnd;
3526     if ((caretAffinityPolicy_ != CaretAffinityPolicy::DEFAULT) && isCaretPosInLineEnd) {
3527         // show caret by click
3528         isShowCaretDown = (caretAffinityPolicy_ == CaretAffinityPolicy::DOWNSTREAM_FIRST);
3529     }
3530     caretOffset = isShowCaretDown ? caretOffsetDown : caretOffsetUp;
3531     caretHeight = isShowCaretDown ? caretHeightDown : caretHeightUp;
3532     // Handle caret offset at the right boundary of the content rect
3533     if (GreatOrEqual(caretOffset.GetX(), caretBoundaryRect.Right())) {
3534         auto overlayModifier = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
3535         CHECK_NULL_RETURN(overlayModifier, std::make_pair(caretOffset, caretHeight));
3536         auto caretWidth = overlayModifier->GetCaretWidth();
3537         caretOffset.SetX(caretOffset.GetX() - caretWidth);
3538     }
3539     return std::make_pair(caretOffset, caretHeight);
3540 }
3541 
CalculateEmptyValueCaretRect()3542 std::pair<OffsetF, float> RichEditorPattern::CalculateEmptyValueCaretRect()
3543 {
3544     OffsetF offset;
3545     auto textAlign = GetTextAlignByDirection();
3546     switch (textAlign) {
3547         case TextAlign::START:
3548             offset.SetX(contentRect_.GetX());
3549             break;
3550         case TextAlign::CENTER:
3551             offset.SetX(contentRect_.GetX() + contentRect_.Width() / 2.0f);
3552             break;
3553         case TextAlign::END: {
3554             auto overlayModifier = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
3555             auto caretWidth = overlayModifier ? overlayModifier->GetCaretWidth() : 0.0f;
3556             offset.SetX(contentRect_.Right() - caretWidth);
3557             break;
3558         }
3559         default:
3560             break;
3561     }
3562     auto offsetY = richTextRect_.GetY();
3563     float caretHeight = 0.0f;
3564     if (!presetParagraph_) {
3565         PreferredParagraph();
3566     }
3567     if (presetParagraph_) {
3568         CaretMetricsF caretCaretMetric;
3569         presetParagraph_->CalcCaretMetricsByPosition(1, caretCaretMetric, TextAffinity::UPSTREAM, false);
3570         offsetY += caretCaretMetric.offset.GetY();
3571         caretHeight = caretCaretMetric.height;
3572     }
3573     offset.SetY(offsetY);
3574     return std::make_pair(offset, caretHeight);
3575 }
3576 
UpdateModifierCaretOffsetAndHeight()3577 void RichEditorPattern::UpdateModifierCaretOffsetAndHeight()
3578 {
3579     CHECK_NULL_VOID(overlayMod_);
3580     auto overlayModifier = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
3581     CHECK_NULL_VOID(overlayModifier);
3582     auto [caretOffset, caretHeight] = CalculateCaretOffsetAndHeight();
3583     overlayModifier->SetCaretOffsetAndHeight(caretOffset, caretHeight);
3584 }
3585 
NotifyCaretChange()3586 void RichEditorPattern::NotifyCaretChange()
3587 {
3588     CHECK_NULL_VOID(!IsSelected());
3589     TriggerAvoidOnCaretChange();
3590 }
3591 
GetTextAlignByDirection()3592 TextAlign RichEditorPattern::GetTextAlignByDirection()
3593 {
3594     auto layoutProperty = GetLayoutProperty<TextLayoutProperty>();
3595     CHECK_NULL_RETURN(layoutProperty, TextAlign::START);
3596     auto textAlign = layoutProperty->GetTextAlignValue(TextAlign::START);
3597     auto direction = layoutProperty->GetNonAutoLayoutDirection();
3598     if (direction == TextDirection::RTL) {
3599         if (textAlign == TextAlign::START) {
3600             textAlign = TextAlign::END;
3601         } else {
3602             textAlign = TextAlign::START;
3603         }
3604     }
3605     return textAlign;
3606 }
3607 
HandleLongPress(GestureEvent & info)3608 void RichEditorPattern::HandleLongPress(GestureEvent& info)
3609 {
3610     CHECK_NULL_VOID(!selectOverlay_->GetIsHandleMoving());
3611     auto focusHub = GetFocusHub();
3612     CHECK_NULL_VOID(focusHub);
3613     if (!focusHub->IsFocusable()) {
3614         return;
3615     }
3616     if (info.GetFingerList().size() > 1) {
3617         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "More than one finger detected, ignoring this long press event");
3618         return;
3619     }
3620     if (sourceType_ == SourceType::MOUSE && hasUrlSpan_) {
3621         HandleUrlSpanShowShadow(info.GetLocalLocation(), info.GetGlobalLocation(), GetUrlPressColor());
3622     }
3623 
3624     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "HandleLongPress");
3625     moveCaretState_.Reset();
3626     caretUpdateType_ = CaretUpdateType::LONG_PRESSED;
3627     selectionMenuOffsetClick_ = OffsetF(
3628         static_cast<float>(info.GetGlobalLocation().GetX()), static_cast<float>(info.GetGlobalLocation().GetY()));
3629     HandleDoubleClickOrLongPress(info);
3630     caretUpdateType_ = CaretUpdateType::NONE;
3631 }
3632 
HandleUrlSpanShowShadow(const Offset & localLocation,const Offset & globalOffset,const Color & color)3633 bool RichEditorPattern::HandleUrlSpanShowShadow(const Offset& localLocation, const Offset& globalOffset, const Color& color)
3634 {
3635     RectF textContentRect = contentRect_;
3636     textContentRect.SetTop(contentRect_.GetY() - std::min(baselineOffset_, 0.0f));
3637     textContentRect.SetHeight(contentRect_.Height() - std::max(baselineOffset_, 0.0f));
3638 
3639     auto localLocationOffset = localLocation;
3640     if (selectOverlay_->HasRenderTransform()) {
3641         localLocationOffset = ConvertGlobalToLocalOffset(globalOffset);
3642     }
3643 
3644     PointF textOffset = {static_cast<float>(localLocationOffset.GetX()) - GetTextRect().GetX(),
3645                          static_cast<float>(localLocationOffset.GetY()) - GetTextRect().GetY()};
3646     return ShowShadow(textOffset, color);
3647 }
3648 
HandleDoubleClickOrLongPress(GestureEvent & info)3649 void RichEditorPattern::HandleDoubleClickOrLongPress(GestureEvent& info)
3650 {
3651     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "caretUpdateType=%{public}d", caretUpdateType_);
3652     if (IsPreviewTextInputting()) {
3653         TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "do not handle DoubleClickOrLongPress in previewTextInputting");
3654         return;
3655     }
3656     if (IsDragging()) {
3657         TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "do not handle DoubleClickOrLongPress during drag");
3658         return;
3659     }
3660     auto host = GetHost();
3661     CHECK_NULL_VOID(host);
3662     textResponseType_ = TextResponseType::LONG_PRESS;
3663     if (caretUpdateType_ == CaretUpdateType::LONG_PRESSED) {
3664         HandleUserLongPressEvent(info);
3665     } else if (caretUpdateType_ == CaretUpdateType::DOUBLE_CLICK) {
3666         HandleUserDoubleClickEvent(info);
3667     }
3668     bool isDoubleClick = caretUpdateType_== CaretUpdateType::DOUBLE_CLICK;
3669     if (isDoubleClick && info.GetSourceTool() == SourceTool::FINGER && IsSelected()) {
3670         showSelect_ = true;
3671         host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
3672         ShowSelectOverlay(textSelector_.firstHandle, textSelector_.secondHandle);
3673     }
3674     bool isLongPressSelectArea = BetweenSelection(info.GetGlobalLocation()) && !isDoubleClick;
3675     HandleDraggableFlag(isLongPressSelectArea);
3676     bool isLongPressByMouse = isMousePressed_ && caretUpdateType_== CaretUpdateType::LONG_PRESSED;
3677     if (isLongPressSelectArea && !isLongPressByMouse) {
3678         StartVibratorByLongPress();
3679     }
3680     bool isMouseClickWithShift = shiftFlag_ && info.GetSourceDevice() == SourceType::MOUSE;
3681     bool isInterceptEvent = isLongPressSelectArea || isLongPressByMouse || isMouseClickWithShift;
3682     if (isInterceptEvent) {
3683         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "intercept longPressReason:[%{public}d, %{public}d] shiftSelect:%{public}d",
3684             isLongPressSelectArea, isLongPressByMouse, isMouseClickWithShift);
3685         return;
3686     }
3687     HandleDoubleClickOrLongPress(info, host);
3688     if (IsSelected()) {
3689         TriggerAvoidOnCaretChangeNextFrame();
3690     } else {
3691         ForceTriggerAvoidOnCaretChange(true);
3692     }
3693 }
3694 
ConvertGlobalToLocalOffset(const Offset & globalOffset)3695 Offset RichEditorPattern::ConvertGlobalToLocalOffset(const Offset& globalOffset)
3696 {
3697     auto localPoint = OffsetF(globalOffset.GetX(), globalOffset.GetY());
3698     selectOverlay_->RevertLocalPointWithTransform(localPoint);
3699     return Offset(localPoint.GetX(), localPoint.GetY());
3700 }
3701 
HandleSelect(GestureEvent & info,int32_t selectStart,int32_t selectEnd)3702 void RichEditorPattern::HandleSelect(GestureEvent& info, int32_t selectStart, int32_t selectEnd)
3703 {
3704     initSelector_ = { selectStart, selectEnd };
3705     if (IsSelected()) {
3706         showSelect_ = true;
3707     }
3708     FireOnSelect(selectStart, selectEnd);
3709     SetCaretPositionWithAffinity({ selectEnd, TextAffinity::UPSTREAM });
3710     MoveCaretToContentRect();
3711     CalculateHandleOffsetAndShowOverlay();
3712     if (IsShowSelectMenuUsingMouse()) {
3713         CloseSelectOverlay();
3714     }
3715     selectionMenuOffset_ = info.GetGlobalLocation();
3716 }
3717 
HandleDoubleClickOrLongPress(GestureEvent & info,RefPtr<FrameNode> host)3718 void RichEditorPattern::HandleDoubleClickOrLongPress(GestureEvent& info, RefPtr<FrameNode> host)
3719 {
3720     auto focusHub = host->GetOrCreateFocusHub();
3721     CHECK_NULL_VOID(focusHub);
3722     isLongPress_ = true;
3723     auto localOffset = info.GetLocalLocation();
3724     if (selectOverlay_->HasRenderTransform()) {
3725         localOffset = ConvertGlobalToLocalOffset(info.GetGlobalLocation());
3726     }
3727     auto textPaintOffset = GetTextRect().GetOffset() - OffsetF(0.0, std::min(baselineOffset_, 0.0f));
3728     Offset textOffset = { localOffset.GetX() - textPaintOffset.GetX(), localOffset.GetY() - textPaintOffset.GetY() };
3729     if (caretUpdateType_ == CaretUpdateType::LONG_PRESSED) {
3730         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "LONG_PRESSED and isEditing=%{public}d", isEditing_);
3731         if (textSelector_.IsValid()) {
3732             CloseSelectOverlay();
3733             ResetSelection();
3734         }
3735         StartVibratorByLongPress();
3736         editingLongPress_ = isEditing_;
3737         previewLongPress_ = !isEditing_;
3738     }
3739     focusHub->RequestFocusImmediately();
3740     InitSelection(textOffset);
3741     auto selectEnd = textSelector_.GetTextEnd();
3742     auto selectStart = textSelector_.GetTextStart();
3743     HandleSelect(info, selectStart, selectEnd);
3744     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
3745     if (overlayMod_ && caretUpdateType_ == CaretUpdateType::DOUBLE_CLICK) {
3746         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "double click. shall enter edit state.set 1");
3747         HandleOnEditChanged(true);
3748         RequestKeyboard(false, true, true);
3749     }
3750     bool isDoubleClickByMouse =
3751         info.GetSourceDevice() == SourceType::MOUSE && caretUpdateType_ == CaretUpdateType::DOUBLE_CLICK;
3752     bool isShowSelectOverlay = !isDoubleClickByMouse && caretUpdateType_ != CaretUpdateType::LONG_PRESSED;
3753     if (isShowSelectOverlay) {
3754         selectOverlay_->ProcessOverlay({ .menuIsShow = !selectOverlay_->GetIsHandleMoving(), .animation = true });
3755         StopTwinkling();
3756     } else if (selectStart == selectEnd && isDoubleClickByMouse) {
3757         StartTwinkling();
3758     } else {
3759         StopTwinkling();
3760     }
3761 }
3762 
StartVibratorByLongPress()3763 void RichEditorPattern::StartVibratorByLongPress()
3764 {
3765     CHECK_NULL_VOID(isEnableHapticFeedback_);
3766     VibratorUtils::StartVibraFeedback("longPress.light");
3767 }
3768 
HandleUserLongPressEvent(GestureEvent & info)3769 bool RichEditorPattern::HandleUserLongPressEvent(GestureEvent& info)
3770 {
3771     auto longPressFunc = [](RefPtr<SpanItem> item, GestureEvent& info) -> bool {
3772         if (item && item->onLongPress) {
3773             item->onLongPress(info);
3774             return true;
3775         }
3776         return false;
3777     };
3778     return HandleUserGestureEvent(info, std::move(longPressFunc));
3779 }
3780 
HandleUserDoubleClickEvent(GestureEvent & info)3781 bool RichEditorPattern::HandleUserDoubleClickEvent(GestureEvent& info)
3782 {
3783     auto doubleClickFunc = [](RefPtr<SpanItem> item, GestureEvent& info) -> bool {
3784         if (item && item->onDoubleClick) {
3785             item->onDoubleClick(info);
3786             return true;
3787         }
3788         return false;
3789     };
3790     return HandleUserGestureEvent(info, std::move(doubleClickFunc));
3791 }
3792 
HandleMenuCallbackOnSelectAll(bool isShowMenu)3793 void RichEditorPattern::HandleMenuCallbackOnSelectAll(bool isShowMenu)
3794 {
3795     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "HandleMenuCallbackOnSelectAll");
3796     auto textSize = GetTextContentLength();
3797     textSelector_.Update(0, textSize);
3798     CalculateHandleOffsetAndShowOverlay();
3799     if (selectOverlay_->IsUsingMouse()) {
3800         CloseSelectOverlay();
3801     }
3802     IF_TRUE(IsSelected(), StopTwinkling());
3803     auto selectOverlayInfo = selectOverlay_->GetSelectOverlayInfo();
3804     if (selectOverlayInfo && selectOverlay_->IsUsingMouse()) {
3805         textResponseType_ = static_cast<TextResponseType>(selectOverlayInfo->menuInfo.responseType.value_or(0));
3806     } else {
3807         textResponseType_ = TextResponseType::LONG_PRESS;
3808     }
3809     selectMenuInfo_.showCopyAll = false;
3810     auto host = GetHost();
3811     CHECK_NULL_VOID(host);
3812     FireOnSelect(textSelector_.GetTextStart(), textSelector_.GetTextEnd());
3813     showSelect_ = true;
3814     if (!selectOverlay_->IsUsingMouse()) {
3815         selectOverlay_->ProcessOverlay({ .menuIsShow = isShowMenu, .animation = true });
3816     }
3817     SetCaretPosition(textSize);
3818     MoveCaretToContentRect();
3819     TriggerAvoidOnCaretChangeNextFrame();
3820     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
3821 }
3822 
InitLongPressEvent(const RefPtr<GestureEventHub> & gestureHub)3823 void RichEditorPattern::InitLongPressEvent(const RefPtr<GestureEventHub>& gestureHub)
3824 {
3825     CHECK_NULL_VOID(!longPressEvent_);
3826     auto longPressCallback = [weak = WeakClaim(this)](GestureEvent& info) {
3827         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "long press callback, sourceType=%{public}d", info.GetSourceDevice());
3828         auto pattern = weak.Upgrade();
3829         CHECK_NULL_VOID(pattern);
3830         pattern->sourceType_ = info.GetSourceDevice();
3831         pattern->HandleLongPress(info);
3832     };
3833     longPressEvent_ = MakeRefPtr<LongPressEvent>(std::move(longPressCallback));
3834     gestureHub->SetLongPressEvent(longPressEvent_);
3835 
3836     auto onTextSelectorChange = [weak = WeakClaim(this), &selector = textSelector_]() {
3837         auto pattern = weak.Upgrade();
3838         CHECK_NULL_VOID(pattern);
3839         if (!selector.SelectNothing()) {
3840             pattern->StopTwinkling();
3841         }
3842         IF_PRESENT(pattern->oneStepDragController_,
3843             SetEnableEventResponse(selector, pattern->imageNodes, pattern->builderNodes));
3844         pattern->FireOnSelectionChange(selector);
3845         auto frameNode = pattern->GetHost();
3846         CHECK_NULL_VOID(frameNode);
3847         frameNode->OnAccessibilityEvent(AccessibilityEventType::TEXT_SELECTION_UPDATE);
3848     };
3849     textSelector_.SetOnAccessibility(std::move(onTextSelectorChange));
3850 }
3851 
UpdateSelector(int32_t start,int32_t end)3852 void RichEditorPattern::UpdateSelector(int32_t start, int32_t end)
3853 {
3854     AdjustSelector(start, end);
3855     textSelector_.Update(start, end);
3856 }
3857 
AdjustSelector(int32_t & start,int32_t & end,SelectorAdjustPolicy policy)3858 void RichEditorPattern::AdjustSelector(int32_t& start, int32_t& end, SelectorAdjustPolicy policy)
3859 {
3860     AdjustSelector(start, HandleType::FIRST, policy);
3861     AdjustSelector(end, HandleType::SECOND, policy);
3862 }
3863 
AdjustSelector(int32_t & index,HandleType handleType,SelectorAdjustPolicy policy)3864 void RichEditorPattern::AdjustSelector(int32_t& index, HandleType handleType,  SelectorAdjustPolicy policy)
3865 {
3866     bool isAdjust = AdjustSelectorForSymbol(index, handleType, policy);
3867     CHECK_NULL_VOID(!isAdjust);
3868     AdjustSelectorForEmoji(index, handleType, policy);
3869 }
3870 
AdjustSelectorForSymbol(int32_t & index,HandleType handleType,SelectorAdjustPolicy policy)3871 bool RichEditorPattern::AdjustSelectorForSymbol(int32_t& index, HandleType handleType, SelectorAdjustPolicy policy)
3872 {
3873     auto it = GetSpanIter(index);
3874     CHECK_NULL_RETURN((it != spans_.end()), false);
3875     auto spanItem = *it;
3876     CHECK_NULL_RETURN(spanItem, false);
3877 
3878     auto spanStart = spanItem->rangeStart;
3879     auto spanEnd = spanItem->position;
3880     if (spanItem->unicode != 0 && spanItem->Contains(index)) {
3881         auto it = SELECTOR_ADJUST_DIR_MAP.find({ handleType, policy });
3882         index = (it->second == MoveDirection::BACKWARD) ? spanStart : spanEnd;
3883         return true;
3884     }
3885     return false;
3886 }
3887 
GetEmojiRelation(int index)3888 EmojiRelation RichEditorPattern::GetEmojiRelation(int index)
3889 {
3890     auto it = GetSpanIter(index);
3891     CHECK_NULL_RETURN((it != spans_.end()), EmojiRelation::NO_EMOJI);
3892     auto spanItem = *it;
3893     CHECK_NULL_RETURN(spanItem, EmojiRelation::NO_EMOJI);
3894     int32_t emojiStartIndex;
3895     int32_t emojiEndIndex;
3896     return TextEmojiProcessor::GetIndexRelationToEmoji(index - spanItem->rangeStart, spanItem->content,
3897         emojiStartIndex, emojiEndIndex);
3898 }
3899 
AdjustSelectorForEmoji(int & index,HandleType handleType,SelectorAdjustPolicy policy)3900 bool RichEditorPattern::AdjustSelectorForEmoji(int& index, HandleType handleType, SelectorAdjustPolicy policy)
3901 {
3902     auto it = GetSpanIter(index);
3903     CHECK_NULL_RETURN((it != spans_.end()), false);
3904     auto spanItem = *it;
3905     CHECK_NULL_RETURN(spanItem, false);
3906 
3907     int32_t emojiStartIndex;
3908     int32_t emojiEndIndex;
3909     int32_t spanStart = spanItem->rangeStart;
3910     EmojiRelation relation = TextEmojiProcessor::GetIndexRelationToEmoji(index - spanStart, spanItem->content,
3911         emojiStartIndex, emojiEndIndex);
3912     if (relation != EmojiRelation::IN_EMOJI && relation != EmojiRelation::MIDDLE_EMOJI) {
3913         // no need adjusting when index is not warpped in emojis
3914         return false;
3915     }
3916     int32_t start = 0;
3917     int32_t end = 0;
3918     bool isBoundaryGet = paragraphs_.GetWordBoundary(index, start, end); // boundary from engine
3919     if (isBoundaryGet) {
3920         if (handleType == HandleType::FIRST) {
3921             index = start;
3922         } else {
3923             if (index > start) {
3924                 // index to emoji, move index to end of emoji, double check "in emoji state"
3925                 index = end;
3926             }
3927         }
3928     } else {
3929         if (relation == EmojiRelation::IN_EMOJI) {
3930             int32_t indexInSpan = (handleType == HandleType::FIRST) ? emojiStartIndex : emojiEndIndex;
3931             index = spanItem->rangeStart + indexInSpan;
3932         }
3933     }
3934     TAG_LOGD(AceLogTag::ACE_RICH_TEXT,
3935         "index=%{public}d, handleType=%{public}d, emojiRange=[%{public}d,%{public}d] isBoundaryGet=%{public}d "\
3936         "boundary=[%{public}d, %{public}d]",
3937         index, handleType, emojiStartIndex, emojiEndIndex, isBoundaryGet, start, end);
3938     return true;
3939 }
3940 
GetSpanIter(int32_t index)3941 std::list<RefPtr<SpanItem>>::iterator RichEditorPattern::GetSpanIter(int32_t index)
3942 {
3943     return std::find_if(spans_.begin(), spans_.end(), [index](const RefPtr<SpanItem>& spanItem) {
3944         return spanItem->rangeStart <= index && index < spanItem->position;
3945     });
3946 }
3947 
GetSpanType(int32_t index)3948 SpanItemType RichEditorPattern::GetSpanType(int32_t index)
3949 {
3950     auto it = GetSpanIter(index);
3951     CHECK_NULL_RETURN((it != spans_.end()), SpanItemType::NORMAL);
3952     auto& spanItem = *it;
3953     CHECK_NULL_RETURN(spanItem, SpanItemType::NORMAL);
3954     return spanItem->spanItemType;
3955 }
3956 
GetGlyphPositionAtCoordinate(int32_t x,int32_t y)3957 PositionWithAffinity RichEditorPattern::GetGlyphPositionAtCoordinate(int32_t x, int32_t y)
3958 {
3959     Offset offset(x, y);
3960     return paragraphs_.GetGlyphPositionAtCoordinate(ConvertTouchOffsetToTextOffset(offset));
3961 }
3962 
InitDragDropEvent()3963 void RichEditorPattern::InitDragDropEvent()
3964 {
3965     auto host = GetHost();
3966     CHECK_NULL_VOID(host);
3967     auto gestureHub = host->GetOrCreateGestureEventHub();
3968     CHECK_NULL_VOID(gestureHub);
3969     gestureHub->InitDragDropEvent();
3970     gestureHub->SetThumbnailCallback(GetThumbnailCallback());
3971     auto eventHub = host->GetEventHub<EventHub>();
3972     CHECK_NULL_VOID(eventHub);
3973     auto onDragMove = [weakPtr = WeakClaim(this)](
3974                           const RefPtr<OHOS::Ace::DragEvent>& event, const std::string& extraParams) {
3975         auto pattern = weakPtr.Upgrade();
3976         CHECK_NULL_VOID(pattern);
3977         pattern->showSelect_ = false;
3978         pattern->OnDragMove(event);
3979     };
3980     eventHub->SetOnDragMove(std::move(onDragMove));
3981     OnDragStartAndEnd();
3982     onDragDropAndLeave();
3983 }
3984 
OnDragStartAndEnd()3985 void RichEditorPattern::OnDragStartAndEnd()
3986 {
3987     auto host = GetHost();
3988     CHECK_NULL_VOID(host);
3989     auto eventHub = host->GetEventHub<EventHub>();
3990     CHECK_NULL_VOID(eventHub);
3991     auto onDragStart = [weakPtr = WeakClaim(this)](const RefPtr<OHOS::Ace::DragEvent>& event,
3992                            const std::string& extraParams) -> NG::DragDropInfo {
3993         NG::DragDropInfo itemInfo;
3994         auto pattern = weakPtr.Upgrade();
3995         CHECK_NULL_RETURN(pattern, itemInfo);
3996         return pattern->HandleDragStart(event, extraParams);
3997     };
3998     eventHub->SetDefaultOnDragStart(std::move(onDragStart));
3999     auto onDragEnd = [weakPtr = WeakClaim(this), scopeId = Container::CurrentId()](
4000                          const RefPtr<OHOS::Ace::DragEvent>& event) {
4001         ContainerScope scope(scopeId);
4002         auto pattern = weakPtr.Upgrade();
4003         CHECK_NULL_VOID(pattern);
4004         pattern->isDragSponsor_ = false;
4005         pattern->dragRange_ = { 0, 0 };
4006         pattern->showSelect_ = true;
4007         pattern->StopAutoScroll();
4008         pattern->ClearRedoOperationRecords();
4009         pattern->OnDragEnd(event);
4010     };
4011     eventHub->SetOnDragEnd(std::move(onDragEnd));
4012 }
4013 
HandleDragStart(const RefPtr<Ace::DragEvent> & event,const std::string & extraParams)4014 NG::DragDropInfo RichEditorPattern::HandleDragStart(const RefPtr<Ace::DragEvent>& event, const std::string& extraParams)
4015 {
4016     if (!isDragSponsor_) {
4017         isDragSponsor_ = true;
4018         dragRange_ = { textSelector_.GetTextStart(), textSelector_.GetTextEnd() };
4019     }
4020     sourceTool_ = event ? event->GetSourceTool() : SourceTool::UNKNOWN;
4021     timestamp_ = std::chrono::system_clock::now().time_since_epoch().count();
4022     auto eventHub = GetEventHub<RichEditorEventHub>();
4023     CHECK_NULL_RETURN(eventHub, {});
4024     eventHub->SetTimestamp(timestamp_);
4025     showSelect_ = false;
4026     auto dropInfo = OnDragStart(event, extraParams);
4027     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "HandleDragStart dragStatus=%{public}d", status_);
4028     return dropInfo;
4029 }
4030 
onDragDropAndLeave()4031 void RichEditorPattern::onDragDropAndLeave()
4032 {
4033     auto host = GetHost();
4034     CHECK_NULL_VOID(host);
4035     auto eventHub = host->GetEventHub<EventHub>();
4036     CHECK_NULL_VOID(eventHub);
4037     auto onDragDrop = [weakPtr = WeakClaim(this), scopeId = Container::CurrentId()](
4038                           const RefPtr<OHOS::Ace::DragEvent>& event, const std::string& value) {
4039         ContainerScope scope(scopeId);
4040         auto pattern = weakPtr.Upgrade();
4041         CHECK_NULL_VOID(pattern);
4042         auto host = pattern->GetHost();
4043         CHECK_NULL_VOID(host);
4044         auto eventHub = host->GetEventHub<EventHub>();
4045         pattern->sourceTool_ = event ? event->GetSourceTool() : SourceTool::UNKNOWN;
4046         CHECK_NULL_VOID(eventHub && eventHub->IsEnabled());
4047         bool isCopy = false;
4048         if (pattern->status_ == Status::DRAGGING) {
4049             CHECK_NULL_VOID(event);
4050             auto gesturePressedCodes = event->GetPressedKeyCodes();
4051             if ((gesturePressedCodes.size() == 1) && ((gesturePressedCodes[0] == KeyCode::KEY_CTRL_LEFT) ||
4052                 (gesturePressedCodes[0] == KeyCode::KEY_CTRL_RIGHT))) {
4053                 isCopy = true;
4054             }
4055         }
4056         pattern->status_ = Status::ON_DROP;
4057         pattern->HandleOnDragDrop(event, isCopy);
4058         pattern->status_ = Status::NONE;
4059     };
4060     eventHub->SetOnDrop(std::move(onDragDrop));
4061     auto onDragDragLeave = [weakPtr = WeakClaim(this), scopeId = Container::CurrentId()](
4062                                const RefPtr<OHOS::Ace::DragEvent>& event, const std::string& value) {
4063         ContainerScope scope(scopeId);
4064         auto pattern = weakPtr.Upgrade();
4065         IF_PRESENT(pattern, StopAutoScroll());
4066     };
4067     eventHub->SetOnDragLeave(onDragDragLeave);
4068 }
4069 
ClearDragDropEvent()4070 void RichEditorPattern::ClearDragDropEvent()
4071 {
4072     auto host = GetHost();
4073     CHECK_NULL_VOID(host);
4074     SetIsTextDraggable(false);
4075     auto eventHub = host->GetEventHub<EventHub>();
4076     CHECK_NULL_VOID(eventHub);
4077     eventHub->SetOnDragStart(nullptr);
4078     eventHub->SetOnDragEnter(nullptr);
4079     eventHub->SetOnDragMove(nullptr);
4080     eventHub->SetOnDragLeave(nullptr);
4081     eventHub->SetOnDragEnd(nullptr);
4082     eventHub->SetOnDrop(nullptr);
4083 }
4084 
OnDragMove(const RefPtr<OHOS::Ace::DragEvent> & event)4085 void RichEditorPattern::OnDragMove(const RefPtr<OHOS::Ace::DragEvent>& event)
4086 {
4087     auto theme = GetTheme<RichEditorTheme>();
4088     CHECK_NULL_VOID(theme);
4089     auto touchX = event->GetX();
4090     auto touchY = event->GetY();
4091     auto textRect = GetTextRect();
4092     textRect.SetTop(textRect.GetY() - std::min(baselineOffset_, 0.0f));
4093     Offset textOffset = { touchX - textRect.GetX() - GetParentGlobalOffset().GetX(),
4094         touchY - textRect.GetY() - GetParentGlobalOffset().GetY() - theme->GetInsertCursorOffset().ConvertToPx() };
4095     auto position = isShowPlaceholder_? 0 : paragraphs_.GetIndex(textOffset);
4096     ResetSelection();
4097     CloseSelectOverlay();
4098     SetCaretPosition(position);
4099     CalcAndRecordLastClickCaretInfo(textOffset);
4100     auto [caretOffset, caretHeight] = CalculateCaretOffsetAndHeight();
4101     CHECK_NULL_VOID(overlayMod_);
4102     auto overlayModifier = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
4103     overlayModifier->SetCaretOffsetAndHeight(caretOffset, caretHeight);
4104 
4105     auto host = GetHost();
4106     CHECK_NULL_VOID(host);
4107     if (host->GetDragPreviewOption().enableEdgeAutoScroll) {
4108         AutoScrollParam param = { .autoScrollEvent = AutoScrollEvent::DRAG, .showScrollbar = true };
4109         auto localOffset = OffsetF(touchX, touchY) - parentGlobalOffset_;
4110         AutoScrollByEdgeDetection(param, localOffset, EdgeDetectionStrategy::IN_BOUNDARY);
4111     } else if (isAutoScrollRunning_) {
4112         StopAutoScroll();
4113     }
4114 }
4115 
OnDragEnd(const RefPtr<Ace::DragEvent> & event)4116 void RichEditorPattern::OnDragEnd(const RefPtr<Ace::DragEvent>& event)
4117 {
4118     ResetDragRecordSize(-1);
4119     if (status_ == Status::DRAGGING) {
4120         status_ = Status::NONE;
4121     }
4122     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "OnDragEnd dragStatus=%{public}d", status_);
4123     ResetDragSpanItems();
4124     CHECK_NULL_VOID(!recoverDragResultObjects_.empty());
4125     UpdateSpanItemDragStatus(recoverDragResultObjects_, false);
4126     recoverDragResultObjects_.clear();
4127     auto focusHub = GetFocusHub();
4128     if (event && focusHub && event->GetResult() != DragRet::DRAG_SUCCESS && focusHub->IsFocusable()) {
4129         afterDragSelect_ = true;
4130         HandleSelectionChange(recoverStart_, recoverEnd_);
4131         showSelect_ = true;
4132         CalculateHandleOffsetAndShowOverlay();
4133         ResetSelection();
4134     }
4135     auto host = GetHost();
4136     IF_PRESENT(host, MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF));
4137 }
4138 
ToStyledString(int32_t start,int32_t end)4139 RefPtr<SpanString> RichEditorPattern::ToStyledString(int32_t start, int32_t end)
4140 {
4141     auto length = GetTextContentLength();
4142     int32_t realStart = (start == -1) ? 0 : std::clamp(start, 0, length);
4143     int32_t realEnd = (end == -1) ? length : std::clamp(end, 0, length);
4144     if (realStart > realEnd) {
4145         std::swap(realStart, realEnd);
4146     }
4147     RefPtr<SpanString> spanString = MakeRefPtr<SpanString>(u"");
4148     if (aiWriteAdapter_->GetAIWrite()) {
4149         SetSubSpansWithAIWrite(spanString, realStart, realEnd);
4150     } else {
4151         SetSubSpans(spanString, realStart, realEnd);
4152     }
4153     SetSubMap(spanString);
4154     return spanString;
4155 }
4156 
FromStyledString(const RefPtr<SpanString> & spanString)4157 SelectionInfo RichEditorPattern::FromStyledString(const RefPtr<SpanString>& spanString)
4158 {
4159     std::list<ResultObject> resultObjects;
4160     int32_t start = 0;
4161     int32_t end = 0;
4162     if (spanString && !spanString->GetSpanItems().empty()) {
4163         auto spans = spanString->GetSpanItems();
4164         int32_t index = 0;
4165         std::for_each(spans.begin(), spans.end(),
4166             [&index, &resultObjects, weak = WeakClaim(this)](RefPtr<SpanItem>& item) {
4167                 CHECK_NULL_VOID(item);
4168                 auto pattern = weak.Upgrade();
4169                 CHECK_NULL_VOID(pattern);
4170                 auto obj = item->GetSpanResultObject(item->interval.first, item->interval.second);
4171                 if (AceType::InstanceOf<ImageSpanItem>(item)) {
4172                     obj.imageStyle = pattern->GetImageStyleBySpanItem(item);
4173                 } else if (!AceType::InstanceOf<CustomSpanItem>(item)) {
4174                     obj.textStyle = pattern->GetTextStyleBySpanItem(item);
4175                 }
4176                 obj.spanPosition.spanIndex = index;
4177                 ++index;
4178                 if (obj.isInit) {
4179                     resultObjects.emplace_back(obj);
4180                 }
4181         });
4182         if (spans.back()) {
4183             end = spans.back()->interval.second;
4184         }
4185         if (spans.front()) {
4186             start = spans.front()->interval.first;
4187         }
4188     }
4189     SelectionInfo selection;
4190     selection.SetSelectionEnd(end);
4191     selection.SetSelectionStart(start);
4192     selection.SetResultObjectList(resultObjects);
4193     return selection;
4194 }
4195 
GetTextStyleBySpanItem(const RefPtr<SpanItem> & spanItem)4196 TextStyleResult RichEditorPattern::GetTextStyleBySpanItem(const RefPtr<SpanItem>& spanItem)
4197 {
4198     TextStyleResult textStyle;
4199     CHECK_NULL_RETURN(spanItem, textStyle);
4200     auto theme = GetTheme<RichEditorTheme>();
4201     TextStyle style = theme ? theme->GetTextStyle() : TextStyle();
4202     if (spanItem->fontStyle) {
4203         textStyle.fontColor = spanItem->fontStyle->GetTextColor().value_or(style.GetTextColor()).ColorToString();
4204         textStyle.fontSize =
4205             spanItem->fontStyle->GetFontSize().value_or(Dimension(DEFAULT_TEXT_SIZE, DimensionUnit::FP)).ConvertToFp();
4206         textStyle.fontStyle =
4207             static_cast<int32_t>(spanItem->fontStyle->GetItalicFontStyle().value_or(OHOS::Ace::FontStyle::NORMAL));
4208         textStyle.fontWeight = static_cast<int32_t>(spanItem->fontStyle->GetFontWeight().value_or(FontWeight::NORMAL));
4209         std::string fontFamilyValue;
4210         const std::vector<std::string> defaultFontFamily = { "HarmonyOS Sans" };
4211         auto fontFamily = spanItem->fontStyle->GetFontFamily().value_or(defaultFontFamily);
4212         for (const auto& str : fontFamily) {
4213             fontFamilyValue += str;
4214             fontFamilyValue += ",";
4215         }
4216         fontFamilyValue = fontFamilyValue.substr(0, fontFamilyValue.size() ? fontFamilyValue.size() - 1 : 0);
4217         textStyle.fontFamily = !fontFamilyValue.empty() ? fontFamilyValue : defaultFontFamily.front();
4218         textStyle.decorationType =
4219             static_cast<int32_t>(spanItem->fontStyle->GetTextDecoration().value_or(TextDecoration::NONE));
4220         textStyle.decorationColor =
4221             spanItem->fontStyle->GetTextDecorationColor().value_or(style.GetTextDecorationColor()).ColorToString();
4222         textStyle.decorationStyle =
4223             static_cast<int32_t>(spanItem->fontStyle->GetTextDecorationStyle().value_or(TextDecorationStyle::SOLID));
4224         textStyle.fontFeature = spanItem->fontStyle->GetFontFeature().value_or(ParseFontFeatureSettings("\"pnum\" 1"));
4225         textStyle.letterSpacing = spanItem->fontStyle->GetLetterSpacing().value_or(Dimension()).ConvertToFp();
4226     }
4227     if (spanItem->textLineStyle) {
4228         textStyle.lineHeight = spanItem->textLineStyle->GetLineHeight().value_or(Dimension()).ConvertToFp();
4229         textStyle.halfLeading = spanItem->textLineStyle->GetHalfLeading().value_or(false);
4230         textStyle.lineSpacing = spanItem->textLineStyle->GetLineSpacing().value_or(Dimension()).ConvertToFp();
4231         textStyle.textAlign = static_cast<int32_t>(spanItem->textLineStyle->GetTextAlign().value_or(TextAlign::START));
4232         auto lm = spanItem->textLineStyle->GetLeadingMargin();
4233         if (lm.has_value()) {
4234             textStyle.leadingMarginSize[RichEditorLeadingRange::LEADING_START] = lm.value().size.Width().ToString();
4235             textStyle.leadingMarginSize[RichEditorLeadingRange::LEADING_END] = lm.value().size.Height().ToString();
4236         }
4237         textStyle.wordBreak =
4238             static_cast<int32_t>(spanItem->textLineStyle->GetWordBreak().value_or(WordBreak::BREAK_WORD));
4239         textStyle.lineBreakStrategy =
4240             static_cast<int32_t>(spanItem->textLineStyle->GetLineBreakStrategy().value_or(LineBreakStrategy::GREEDY));
4241         textStyle.paragraphSpacing = spanItem->textLineStyle->GetParagraphSpacing();
4242     }
4243     textStyle.textBackgroundStyle = spanItem->backgroundStyle;
4244     return textStyle;
4245 }
4246 
GetImageStyleBySpanItem(const RefPtr<SpanItem> & spanItem)4247 ImageStyleResult RichEditorPattern::GetImageStyleBySpanItem(const RefPtr<SpanItem>& spanItem)
4248 {
4249     ImageStyleResult imageStyle;
4250     auto imageSpanItem = DynamicCast<ImageSpanItem>(spanItem);
4251     CHECK_NULL_RETURN(imageSpanItem, imageStyle);
4252     auto imageAttributeOp = imageSpanItem->options.imageAttribute;
4253     CHECK_NULL_RETURN(imageAttributeOp.has_value(), imageStyle);
4254     auto imageSizeOp = imageAttributeOp->size;
4255     if (imageSizeOp.has_value() && imageSizeOp->width.has_value() && imageSizeOp->height.has_value()) {
4256         imageStyle.size[RichEditorImageSize::SIZEWIDTH] = imageSizeOp->width->ConvertToPx();
4257         imageStyle.size[RichEditorImageSize::SIZEHEIGHT] = imageSizeOp->height->ConvertToPx();
4258     }
4259     if (imageAttributeOp->verticalAlign.has_value()) {
4260         imageStyle.verticalAlign = static_cast<int32_t>(imageAttributeOp->verticalAlign.value());
4261     }
4262     if (imageAttributeOp->objectFit.has_value()) {
4263         imageStyle.objectFit = static_cast<int32_t>(imageAttributeOp->objectFit.value());
4264     }
4265     if (imageAttributeOp->marginProp.has_value()) {
4266         imageStyle.margin = imageAttributeOp->marginProp->ToString();
4267     }
4268     if (imageAttributeOp->borderRadius.has_value()) {
4269         imageStyle.borderRadius = imageAttributeOp->borderRadius->ToString();
4270     }
4271     return imageStyle;
4272 }
4273 
SetSubSpansWithAIWrite(RefPtr<SpanString> & spanString,int32_t start,int32_t end)4274 void RichEditorPattern::SetSubSpansWithAIWrite(RefPtr<SpanString>& spanString, int32_t start, int32_t end)
4275 {
4276     placeholderSpansMap_.clear();
4277     CHECK_NULL_VOID(spanString);
4278     std::list<RefPtr<SpanItem>> subSpans;
4279     std::u16string text;
4280     size_t index = 0;
4281     size_t placeholderGains = 0;
4282     for (const auto& spanItem : spans_) {
4283         if (!spanItem) {
4284             continue;
4285         }
4286         auto oldEnd = spanItem->position;
4287         auto oldStart = spanItem->rangeStart;
4288         if (oldEnd <= start || oldStart >= end) {
4289             continue;
4290         }
4291         RefPtr<SpanItem> newSpanItem = MakeRefPtr<SpanItem>();
4292         auto spanStart = oldStart <= start ? 0 : oldStart - start;
4293         auto spanEnd = oldEnd < end ? oldEnd - start : end - start;
4294         spanStart += static_cast<int32_t>(placeholderGains);
4295         if (spanItem->spanItemType == SpanItemType::NORMAL) {
4296             newSpanItem = spanItem->GetSameStyleSpanItem();
4297             newSpanItem->urlAddress = spanItem->urlAddress;
4298             newSpanItem->content = spanItem->content
4299                     .substr(std::max(start - oldStart, 0), std::min(end, oldEnd) - std::max(start, oldStart));
4300         } else {
4301             InitPlaceholderSpansMap(newSpanItem, spanItem, index, placeholderGains);
4302             spanEnd += static_cast<int32_t>(placeholderGains);
4303         }
4304         newSpanItem->interval = {spanStart, spanEnd};
4305         newSpanItem->position = spanEnd;
4306         newSpanItem->rangeStart = spanStart;
4307         newSpanItem->textLineStyle->ResetLeadingMargin();
4308         text.append(newSpanItem->content);
4309         subSpans.emplace_back(newSpanItem);
4310     }
4311     spanString->SetString(text);
4312     spanString->SetSpanItems(std::move(subSpans));
4313 }
4314 
InitPlaceholderSpansMap(RefPtr<SpanItem> & newSpanItem,const RefPtr<SpanItem> & spanItem,size_t & index,size_t & placeholderGains)4315 void RichEditorPattern::InitPlaceholderSpansMap(
4316     RefPtr<SpanItem>& newSpanItem, const RefPtr<SpanItem>& spanItem, size_t& index, size_t& placeholderGains)
4317 {
4318     newSpanItem->content = UtfUtils::Str8ToStr16("![id" + std::to_string(index++) + "]");
4319     switch (spanItem->spanItemType) {
4320         case SpanItemType::SYMBOL: {
4321             placeholderSpansMap_[newSpanItem->content] = spanItem;
4322             placeholderGains += PLACEHOLDER_LENGTH - SYMBOL_CONTENT_LENGTH;
4323             break;
4324         }
4325         case SpanItemType::CustomSpan: {
4326             if (!isSpanStringMode_) {
4327                 placeholderSpansMap_[newSpanItem->content] = spanItem;
4328             } else {
4329                 auto customSpanItem = DynamicCast<CustomSpanItem>(spanItem);
4330                 placeholderSpansMap_[newSpanItem->content] = customSpanItem;
4331             }
4332             placeholderGains += PLACEHOLDER_LENGTH - CUSTOM_CONTENT_LENGTH;
4333             break;
4334         }
4335         case SpanItemType::IMAGE: {
4336             placeholderSpansMap_[newSpanItem->content] = spanItem;
4337             placeholderGains += PLACEHOLDER_LENGTH - CUSTOM_CONTENT_LENGTH;
4338             break;
4339         }
4340         default:
4341             break;
4342     }
4343 }
4344 
SetSubSpans(RefPtr<SpanString> & spanString,int32_t start,int32_t end)4345 void RichEditorPattern::SetSubSpans(RefPtr<SpanString>& spanString, int32_t start, int32_t end)
4346 {
4347     CHECK_NULL_VOID(spanString);
4348     std::list<RefPtr<SpanItem>> subSpans;
4349     std::u16string text;
4350     for (const auto& spanItem : spans_) {
4351         if (!spanItem || spanItem->spanItemType == SpanItemType::CustomSpan ||
4352             spanItem->spanItemType == SpanItemType::SYMBOL) {
4353             continue;
4354         }
4355         auto spanEndPos = spanItem->position;
4356         auto spanStartPos = spanItem->rangeStart;
4357         if (spanEndPos > start && spanStartPos < end) {
4358             int32_t oldStart = spanStartPos;
4359             int32_t oldEnd = spanEndPos;
4360             auto spanStart = oldStart <= start ? 0 : oldStart - start;
4361             auto spanEnd = oldEnd < end ? oldEnd - start : end - start;
4362             auto newSpanItem = GetSameSpanItem(spanItem);
4363             CHECK_NULL_CONTINUE(newSpanItem);
4364             newSpanItem->spanItemType = spanItem->spanItemType;
4365             newSpanItem->interval = {spanStart, spanEnd};
4366             newSpanItem->position = spanEnd;
4367             newSpanItem->rangeStart = spanStart;
4368             newSpanItem->content = spanItem->content
4369                     .substr(std::max(start - oldStart, 0), std::min(end, oldEnd) - std::max(start, oldStart));
4370             text.append(newSpanItem->content);
4371             subSpans.emplace_back(newSpanItem);
4372         }
4373     }
4374     spanString->SetString(text);
4375     spanString->SetSpanItems(std::move(subSpans));
4376 }
4377 
GetSameSpanItem(const RefPtr<SpanItem> & spanItem)4378 RefPtr<SpanItem> RichEditorPattern::GetSameSpanItem(const RefPtr<SpanItem>& spanItem)
4379 {
4380     CHECK_NULL_RETURN(spanItem, nullptr);
4381     if (spanItem->spanItemType == SpanItemType::IMAGE) {
4382         auto imageSpanItem = DynamicCast<ImageSpanItem>(spanItem);
4383         CHECK_NULL_RETURN(imageSpanItem, nullptr);
4384         auto newSpanItem = MakeRefPtr<ImageSpanItem>();
4385         auto options = imageSpanItem->options;
4386         if (!options.imagePixelMap) {
4387             auto imageNode = GetImageSpanNodeBySpanItem(imageSpanItem);
4388             CHECK_NULL_RETURN(imageNode, nullptr);
4389             auto pattern = imageNode->GetPattern<ImagePattern>();
4390             CHECK_NULL_RETURN(pattern, nullptr);
4391             auto image = pattern->GetCanvasImage();
4392             CHECK_NULL_RETURN(image, nullptr);
4393             auto pixelMap = image->GetPixelMap();
4394             if (!pixelMap) {
4395                 pixelMap = imageNode->GetDragPixelMap();
4396             }
4397             options.imagePixelMap = pixelMap;
4398         }
4399         newSpanItem->SetImageSpanOptions(options);
4400         return newSpanItem;
4401     } else if (spanItem->spanItemType == SpanItemType::NORMAL) {
4402         auto newSpanItem = spanItem->GetSameStyleSpanItem();
4403         newSpanItem->urlAddress = spanItem->urlAddress;
4404         return newSpanItem;
4405     }
4406     return nullptr;
4407 }
4408 
GetImageSpanNodeBySpanItem(const RefPtr<ImageSpanItem> & spanItem)4409 RefPtr<ImageSpanNode> RichEditorPattern::GetImageSpanNodeBySpanItem(const RefPtr<ImageSpanItem>& spanItem)
4410 {
4411     auto host = GetHost();
4412     CHECK_NULL_RETURN(host, nullptr);
4413     auto uiNodes = host->GetChildren();
4414     auto it = std::find_if(uiNodes.begin(), uiNodes.end(), [spanItem](const RefPtr<UINode>& uiNode) {
4415         auto imageSpanNode = DynamicCast<ImageSpanNode>(uiNode);
4416         CHECK_NULL_RETURN(imageSpanNode, false);
4417         return imageSpanNode->GetSpanItem() == spanItem;
4418     });
4419     CHECK_NULL_RETURN(it != uiNodes.end(), nullptr);
4420     return DynamicCast<ImageSpanNode>(*it);
4421 }
4422 
SetSubMap(RefPtr<SpanString> & spanString)4423 void RichEditorPattern::SetSubMap(RefPtr<SpanString>& spanString)
4424 {
4425     CHECK_NULL_VOID(spanString);
4426     auto subSpans = spanString->GetSpanItems();
4427     std::unordered_map<SpanType, std::list<RefPtr<SpanBase>>> subMap;
4428     for (auto& spanItem : subSpans) {
4429         if (!spanItem) {
4430             continue;
4431         }
4432         auto start = spanItem->rangeStart;
4433         auto end = spanItem->position;
4434         std::list<RefPtr<SpanBase>> spanBases;
4435         if (spanItem->spanItemType == NG::SpanItemType::IMAGE) {
4436             spanBases = { spanString->ToImageSpan(spanItem, start, end) };
4437         } else if (spanItem->spanItemType == NG::SpanItemType::NORMAL) {
4438             spanBases = { spanString->ToFontSpan(spanItem, start, end),
4439                 spanString->ToDecorationSpan(spanItem, start, end),
4440                 spanString->ToBaselineOffsetSpan(spanItem, start, end),
4441                 spanString->ToLetterSpacingSpan(spanItem, start, end),
4442                 spanString->ToGestureSpan(spanItem, start, end),
4443                 spanString->ToParagraphStyleSpan(spanItem, start, end),
4444                 spanString->ToLineHeightSpan(spanItem, start, end),
4445                 spanString->ToBackgroundColorSpan(spanItem, start, end),
4446                 spanString->ToUrlSpan(spanItem, start, end) };
4447         }
4448         for (auto& spanBase : spanBases) {
4449             if (!spanBase) {
4450                 continue;
4451             }
4452             auto it = subMap.find(spanBase->GetSpanType());
4453             if (it == subMap.end()) {
4454                 subMap.insert({ spanBase->GetSpanType(), { spanBase } });
4455             } else {
4456                 it->second.emplace_back(std::move(spanBase));
4457             }
4458         }
4459     }
4460     spanString->SetSpanMap(std::move(subMap));
4461 }
4462 
AddSpanByPasteData(const RefPtr<SpanString> & spanString)4463 void RichEditorPattern::AddSpanByPasteData(const RefPtr<SpanString>& spanString)
4464 {
4465     CHECK_NULL_VOID(spanString);
4466     if (spanString->GetSpansMap().empty()) {
4467         CompleteStyledString(const_cast<RefPtr<SpanString>&>(spanString));
4468     }
4469     if (isSpanStringMode_) {
4470         InsertStyledStringByPaste(spanString);
4471     } else {
4472         AddSpansByPaste(spanString->GetSpanItems());
4473     }
4474 
4475     if (aiWriteAdapter_->GetAIWrite()) {
4476         return;
4477     }
4478     StartTwinkling();
4479     auto host = GetHost();
4480     CHECK_NULL_VOID(host);
4481     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
4482     host->MarkModifyDone();
4483 }
4484 
CompleteStyledString(RefPtr<SpanString> & spanString)4485 void RichEditorPattern::CompleteStyledString(RefPtr<SpanString>& spanString)
4486 {
4487     CHECK_NULL_VOID(spanString);
4488     std::u16string text;
4489     auto spans = spanString->GetSpanItems();
4490     std::for_each(spans.begin(), spans.end(), [&text](RefPtr<SpanItem>& item) {
4491         CHECK_NULL_VOID(item);
4492         text.append(item->content);
4493         item->position = item->interval.second;
4494         item->rangeStart = item->interval.first;
4495     });
4496     spanString->SetString(std::move(text));
4497     SetSubMap(spanString);
4498 }
4499 
InsertStyledStringByPaste(const RefPtr<SpanString> & spanString)4500 void RichEditorPattern::InsertStyledStringByPaste(const RefPtr<SpanString>& spanString)
4501 {
4502     CHECK_NULL_VOID(spanString && styledString_);
4503     int32_t changeStart = caretPosition_;
4504     int32_t changeLength = 0;
4505     if (textSelector_.IsValid()) {
4506         changeStart = textSelector_.GetTextStart();
4507         changeLength = textSelector_.GetTextEnd() - textSelector_.GetTextStart();
4508     }
4509     CHECK_NULL_VOID(BeforeStyledStringChange(changeStart, changeLength, spanString));
4510     auto subSpanString = spanString;
4511     int32_t startLength = maxLength_.value_or(INT_MAX) + changeLength - GetTextContentLength();
4512     if (spanString->GetLength() >= startLength) {
4513         auto range = TextEmojiProcessor::CalSubU16stringRange(
4514             startLength, spanString->GetLength() - startLength, spanString->GetU16string(), true, true);
4515         auto subLength = range.endIndex - range.startIndex;
4516         subSpanString = subSpanString->GetSubSpanString(0, spanString->GetLength() - subLength);
4517     }
4518 
4519     if (changeLength > 0 && subSpanString->GetLength() > 0) {
4520         DeleteForwardInStyledString(changeLength, false);
4521     }
4522     ResetSelection();
4523     styledString_->InsertSpanString(changeStart, subSpanString);
4524     SetCaretPosition(caretPosition_ + subSpanString->GetLength());
4525     AfterStyledStringChange(changeStart, changeLength, subSpanString->GetU16string());
4526 }
4527 
HandleOnDragInsertStyledString(const RefPtr<SpanString> & spanString,bool isCopy)4528 void RichEditorPattern::HandleOnDragInsertStyledString(const RefPtr<SpanString>& spanString, bool isCopy)
4529 {
4530     CHECK_NULL_VOID(spanString);
4531     int currentCaretPosition = caretPosition_;
4532     auto strLength = spanString->GetLength();
4533     insertValueLength_ = strLength;
4534     if (isDragSponsor_ && !isCopy) {
4535         bool isInsertForward = currentCaretPosition < dragRange_.first;
4536         bool isInsertBackward = currentCaretPosition > dragRange_.second;
4537         CHECK_NULL_VOID(isInsertForward || isInsertBackward);
4538         CHECK_NULL_VOID(BeforeStyledStringChange(currentCaretPosition, 0, spanString));
4539         styledString_->InsertSpanString(currentCaretPosition, spanString);
4540         AfterStyledStringChange(currentCaretPosition, 0, spanString->GetU16string());
4541         if (isInsertForward) {
4542             SetCaretPosition(currentCaretPosition + strLength);
4543             dragRange_.first += strLength;
4544             dragRange_.second += strLength;
4545         }
4546         DeleteValueInStyledString(dragRange_.first, strLength, true, false);
4547     } else {
4548         CHECK_NULL_VOID(BeforeStyledStringChange(currentCaretPosition, 0, spanString));
4549         styledString_->InsertSpanString(currentCaretPosition, spanString);
4550         SetCaretPosition(currentCaretPosition + strLength);
4551         AfterStyledStringChange(currentCaretPosition, 0, spanString->GetU16string());
4552     }
4553     StartTwinkling();
4554     auto host = GetHost();
4555     CHECK_NULL_VOID(host);
4556     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
4557 }
4558 
AddSpansByPaste(const std::list<RefPtr<NG::SpanItem>> & spans)4559 void RichEditorPattern::AddSpansByPaste(const std::list<RefPtr<NG::SpanItem>>& spans)
4560 {
4561     if (GetTextContentLength() >= maxLength_.value_or(INT_MAX)) {
4562         TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "AddSpansByPaste: Reach the maxLength. maxLength=%{public}d", maxLength_.value_or(INT_MAX));
4563         return;
4564     }
4565     if (textSelector_.IsValid()) {
4566         SetCaretPosition(textSelector_.GetTextStart());
4567         DeleteForward(textSelector_.GetTextStart(), textSelector_.GetTextEnd() - textSelector_.GetTextStart());
4568         ResetSelection();
4569     }
4570     for (const auto& spanItem : spans) {
4571         if (!spanItem) {
4572             continue;
4573         }
4574         auto imageSpanItem = DynamicCast<ImageSpanItem>(spanItem);
4575         if (imageSpanItem) {
4576             auto options = imageSpanItem->options;
4577             options.offset = caretPosition_;
4578             AddImageSpan(options, true, caretPosition_, true);
4579         } else {
4580             auto options = GetTextSpanOptions(spanItem);
4581             AddTextSpan(options, true, caretPosition_);
4582         }
4583     }
4584 }
4585 
CalculateTruncationLength(const std::u16string & insertValue,int32_t start)4586 int32_t RichEditorPattern::CalculateTruncationLength(const std::u16string& insertValue, int32_t start)
4587 {
4588     if (!textSelector_.SelectNothing()) {
4589         start += textSelector_.GetTextEnd() - textSelector_.GetTextStart();
4590     }
4591     auto truncationLength = static_cast<int32_t>(insertValue.length()) - start;
4592     auto range = TextEmojiProcessor::CalSubU16stringRange(start, truncationLength, insertValue, true, true);
4593     auto allowInsertLength = static_cast<int32_t>(insertValue.length()) - range.endIndex + range.startIndex;
4594     return allowInsertLength;
4595 }
4596 
GetTextSpanOptions(const RefPtr<SpanItem> & spanItem)4597 TextSpanOptions RichEditorPattern::GetTextSpanOptions(const RefPtr<SpanItem>& spanItem)
4598 {
4599     CHECK_NULL_RETURN(spanItem, {});
4600     TextStyle textStyle = GetDefaultTextStyle();
4601     UseSelfStyle(spanItem->fontStyle, spanItem->textLineStyle, textStyle);
4602     textStyle.SetTextBackgroundStyle(spanItem->backgroundStyle);
4603     struct UpdateParagraphStyle paraStyle;
4604     paraStyle.textAlign = spanItem->textLineStyle->GetTextAlign();
4605     paraStyle.leadingMargin = spanItem->textLineStyle->GetLeadingMargin();
4606     paraStyle.wordBreak = spanItem->textLineStyle->GetWordBreak();
4607     paraStyle.lineBreakStrategy = spanItem->textLineStyle->GetLineBreakStrategy();
4608     paraStyle.paragraphSpacing = spanItem->textLineStyle->GetParagraphSpacing();
4609     TextSpanOptions options;
4610     options.value = spanItem->content;
4611     options.offset = caretPosition_;
4612     UserGestureOptions gestureOption;
4613     gestureOption.onClick = spanItem->onClick;
4614     gestureOption.onLongPress = spanItem->onLongPress;
4615     options.userGestureOption = gestureOption;
4616     options.style = textStyle;
4617     options.paraStyle = paraStyle;
4618     return options;
4619 }
4620 
ResetDragSpanItems()4621 void RichEditorPattern::ResetDragSpanItems()
4622 {
4623     auto host = GetHost();
4624     CHECK_NULL_VOID(host);
4625     std::unordered_set<int32_t> nodeIds;
4626     std::for_each(dragSpanItems_.begin(), dragSpanItems_.end(), [&nodeIds](RefPtr<SpanItem>& item) {
4627         CHECK_NULL_VOID(item);
4628         item->EndDrag();
4629         auto imageSpanItem = DynamicCast<ImageSpanItem>(item);
4630         if (imageSpanItem) {
4631             nodeIds.emplace(imageSpanItem->imageNodeId);
4632             return;
4633         }
4634         auto placeholderSpanItem = DynamicCast<PlaceholderSpanItem>(item);
4635         if (placeholderSpanItem) {
4636             nodeIds.emplace(placeholderSpanItem->placeholderSpanNodeId);
4637         }
4638     });
4639     const auto& childrens = host->GetChildren();
4640     for (const auto& child : childrens) {
4641         auto findResult = nodeIds.find(child->GetId());
4642         CHECK_NULL_CONTINUE(findResult != nodeIds.end());
4643         auto node = DynamicCast<FrameNode>(child);
4644         CHECK_NULL_CONTINUE(node);
4645         auto renderContext = node->GetRenderContext();
4646         CHECK_NULL_CONTINUE(renderContext);
4647         renderContext->UpdateOpacity(1);
4648         node->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
4649     }
4650     dragSpanItems_.clear();
4651 }
4652 
SelectOverlayIsOn()4653 bool RichEditorPattern::SelectOverlayIsOn()
4654 {
4655     return selectOverlay_->SelectOverlayIsOn();
4656 }
4657 
UpdateEditingValue(const std::shared_ptr<TextEditingValue> & value,bool needFireChangeEvent)4658 void RichEditorPattern::UpdateEditingValue(const std::shared_ptr<TextEditingValue>& value, bool needFireChangeEvent)
4659 {
4660 #ifdef ENABLE_STANDARD_INPUT
4661     InsertValue(UtfUtils::Str8ToStr16(value->text), true);
4662 #else
4663     if (value->isDelete) {
4664         HandleOnDelete(true);
4665     } else {
4666         InsertValue(UtfUtils::Str8ToStr16(value->appendText));
4667     }
4668 #endif
4669 }
4670 
HandleAISpanHoverEvent(const MouseInfo & info)4671 void RichEditorPattern::HandleAISpanHoverEvent(const MouseInfo& info)
4672 {
4673     if (info.GetAction() != MouseAction::MOVE || !NeedShowAIDetect()) {
4674         return;
4675     }
4676     auto scrollBar = GetScrollBar();
4677     if (scrollBar && (scrollBar->IsHover() || scrollBar->IsPressed())) {
4678         return;
4679     }
4680     if (dataDetectorAdapter_->aiSpanRects_.empty()) {
4681         for (const auto& kv : dataDetectorAdapter_->aiSpanMap_) {
4682             auto& aiSpan = kv.second;
4683             const auto& aiRects = paragraphs_.GetRects(aiSpan.start, aiSpan.end);
4684             dataDetectorAdapter_->aiSpanRects_.insert(
4685                 dataDetectorAdapter_->aiSpanRects_.end(), aiRects.begin(), aiRects.end());
4686         }
4687     }
4688 
4689     auto textPaintOffset = GetTextRect().GetOffset() - OffsetF(0.0f, std::min(baselineOffset_, 0.0f));
4690     PointF textOffset = { info.GetLocalLocation().GetX() - textPaintOffset.GetX(),
4691         info.GetLocalLocation().GetY() - textPaintOffset.GetY() };
4692     auto host = GetHost();
4693     CHECK_NULL_VOID(host);
4694     auto pipeline = GetContext();
4695     CHECK_NULL_VOID(pipeline);
4696     auto nodeId = host->GetId();
4697     for (auto&& rect : dataDetectorAdapter_->aiSpanRects_) {
4698         if (!rect.IsInRegion(textOffset)) {
4699             continue;
4700         }
4701         if (currentMouseStyle_ != MouseFormat::HAND_POINTING) {
4702             pipeline->ChangeMouseStyle(nodeId, MouseFormat::HAND_POINTING);
4703             currentMouseStyle_ = MouseFormat::HAND_POINTING;
4704         }
4705         return;
4706     }
4707     if (currentMouseStyle_ != MouseFormat::TEXT_CURSOR) {
4708         pipeline->ChangeMouseStyle(nodeId, MouseFormat::TEXT_CURSOR);
4709         currentMouseStyle_ = MouseFormat::TEXT_CURSOR;
4710     }
4711 }
4712 
InitMouseEvent()4713 void RichEditorPattern::InitMouseEvent()
4714 {
4715     CHECK_NULL_VOID(!mouseEventInitialized_);
4716     auto host = GetHost();
4717     CHECK_NULL_VOID(host);
4718     auto eventHub = host->GetEventHub<EventHub>();
4719     CHECK_NULL_VOID(eventHub);
4720     auto inputHub = eventHub->GetOrCreateInputEventHub();
4721     CHECK_NULL_VOID(inputHub);
4722 
4723     auto mouseTask = [weak = WeakClaim(this)](MouseInfo& info) {
4724         auto pattern = weak.Upgrade();
4725         CHECK_NULL_VOID(pattern);
4726         pattern->HandleMouseEvent(info);
4727     };
4728     auto mouseEvent = MakeRefPtr<InputEvent>(std::move(mouseTask));
4729     inputHub->AddOnMouseEvent(mouseEvent);
4730     auto hoverTask = [weak = WeakClaim(this)](bool isHover) {
4731         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "on hover event isHover=%{public}d", isHover);
4732         auto pattern = weak.Upgrade();
4733         if (pattern) {
4734             pattern->OnHover(isHover);
4735         }
4736     };
4737     auto hoverEvent = MakeRefPtr<InputEvent>(std::move(hoverTask));
4738     inputHub->AddOnHoverEvent(hoverEvent);
4739     mouseEventInitialized_ = true;
4740 }
4741 
OnHover(bool isHover)4742 void RichEditorPattern::OnHover(bool isHover)
4743 {
4744     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "isHover=%{public}d", isHover);
4745     if (!isHover && lastHoverSpanItem_) {
4746         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "spanItem hover false");
4747         lastHoverSpanItem_->onHover_(false, lastHoverInfo_);
4748         lastHoverSpanItem_.Reset();
4749     }
4750     auto scrollBar = GetScrollBar();
4751     if (isHover && (!scrollBar || !scrollBar->IsPressed())) {
4752         ChangeMouseStyle(MouseFormat::TEXT_CURSOR);
4753     } else {
4754         ChangeMouseStyle(MouseFormat::DEFAULT, true);
4755         HandleUrlSpanForegroundClear();
4756     }
4757 }
4758 
ChangeMouseStyle(MouseFormat format,bool freeMouseHoldNode)4759 void RichEditorPattern::ChangeMouseStyle(MouseFormat format, bool freeMouseHoldNode)
4760 {
4761     auto host = GetHost();
4762     CHECK_NULL_VOID(host);
4763     auto pipeline = GetContext();
4764     CHECK_NULL_VOID(pipeline);
4765     auto nodeId = host->GetId();
4766     // Do not change mouse style to text-cursor if the right-button custom menu is showing
4767     bool shouldPreventChange = (format == MouseFormat::TEXT_CURSOR && selectOverlay_->IsRightButtonCustomMenuShow());
4768     CHECK_NULL_VOID(!shouldPreventChange);
4769     pipeline->SetMouseStyleHoldNode(nodeId);
4770     pipeline->ChangeMouseStyle(nodeId, format);
4771     currentMouseStyle_ = format;
4772     IF_TRUE(freeMouseHoldNode, pipeline->FreeMouseStyleHoldNode(nodeId));
4773 }
4774 
RequestKeyboard(bool isFocusViewChanged,bool needStartTwinkling,bool needShowSoftKeyboard,SourceType sourceType)4775 bool RichEditorPattern::RequestKeyboard(bool isFocusViewChanged, bool needStartTwinkling, bool needShowSoftKeyboard,
4776     SourceType sourceType)
4777 {
4778     auto host = GetHost();
4779     CHECK_NULL_RETURN(host, false);
4780     auto context = host->GetContext();
4781     CHECK_NULL_RETURN(context, false);
4782     CHECK_NULL_RETURN(needShowSoftKeyboard, false);
4783     if (needShowSoftKeyboard && customKeyboardBuilder_) {
4784         return RequestCustomKeyboard();
4785     }
4786 #if defined(ENABLE_STANDARD_INPUT)
4787     if (!EnableStandardInput(needShowSoftKeyboard, sourceType)) {
4788         return false;
4789     }
4790 #else
4791     if (!UnableStandardInput(isFocusViewChanged)) {
4792         return false;
4793     }
4794 #endif
4795     return true;
4796 }
4797 
4798 #if defined(ENABLE_STANDARD_INPUT)
4799 #ifdef WINDOW_SCENE_SUPPORTED
GetSCBSystemWindowId()4800 uint32_t RichEditorPattern::GetSCBSystemWindowId()
4801 {
4802     RefPtr<FrameNode> frameNode = GetHost();
4803     CHECK_NULL_RETURN(frameNode, {});
4804     auto focusSystemWindowId = WindowSceneHelper::GetFocusSystemWindowId(frameNode);
4805     return focusSystemWindowId;
4806 }
4807 #endif
4808 
EnableStandardInput(bool needShowSoftKeyboard,SourceType sourceType)4809 bool RichEditorPattern::EnableStandardInput(bool needShowSoftKeyboard, SourceType sourceType)
4810 {
4811     auto host = GetHost();
4812     CHECK_NULL_RETURN(host, false);
4813     auto context = host->GetContext();
4814     CHECK_NULL_RETURN(context, false);
4815     if (richEditTextChangeListener_ == nullptr) {
4816         richEditTextChangeListener_ = new OnTextChangedListenerImpl(WeakClaim(this));
4817     }
4818     auto inputMethod = MiscServices::InputMethodController::GetInstance();
4819     CHECK_NULL_RETURN(inputMethod, false);
4820     auto miscTextConfig = GetMiscTextConfig();
4821     CHECK_NULL_RETURN(miscTextConfig.has_value(), false);
4822     TAG_LOGD(
4823         AceLogTag::ACE_RICH_TEXT, "RequestKeyboard set calling window id is : %{public}u", miscTextConfig->windowId);
4824     MiscServices::TextConfig textconfig = miscTextConfig.value();
4825 #ifdef WINDOW_SCENE_SUPPORTED
4826     auto systemWindowId = GetSCBSystemWindowId();
4827     if (systemWindowId) {
4828         miscTextConfig->windowId = systemWindowId;
4829     }
4830 #endif
4831     auto textFieldManager = DynamicCast<TextFieldManagerNG>(context->GetTextFieldManager());
4832     if (host && textFieldManager) {
4833         textFieldManager->SetImeAttached(true);
4834         textFieldManager->SetLastRequestKeyboardId(host->GetId());
4835     }
4836     OHOS::MiscServices::AttachOptions attachOptions;
4837     attachOptions.isShowKeyboard = needShowSoftKeyboard;
4838     attachOptions.requestKeyboardReason =
4839         static_cast<OHOS::MiscServices::RequestKeyboardReason>(static_cast<int32_t>(sourceType));
4840     auto ret = inputMethod->Attach(richEditTextChangeListener_, attachOptions, textconfig);
4841     if (ret == MiscServices::ErrorCode::NO_ERROR) {
4842         textFieldManager->SetIsImeAttached(true);
4843     }
4844     UpdateCaretInfoToController();
4845     if (context) {
4846         inputMethod->SetCallingWindow(context->GetWindowId());
4847     }
4848 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
4849     imeAttached_ = true;
4850 #endif
4851     return true;
4852 }
4853 
GetMiscTextConfig()4854 std::optional<MiscServices::TextConfig> RichEditorPattern::GetMiscTextConfig()
4855 {
4856     auto tmpHost = GetHost();
4857     CHECK_NULL_RETURN(tmpHost, {});
4858     auto pipeline = tmpHost->GetContextRefPtr();
4859     auto renderContext = tmpHost->GetRenderContext();
4860     CHECK_NULL_RETURN(pipeline && renderContext, {});
4861 
4862     float caretHeight = 0.0f;
4863     OffsetF caretOffset = CalcCursorOffsetByPosition(caretPosition_, caretHeight);
4864     if (NearZero(caretHeight)) {
4865         auto overlayModifier = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
4866         caretHeight = overlayModifier ? overlayModifier->GetCaretHeight() : DEFAULT_CARET_HEIGHT;
4867     }
4868     if (NearZero(caretHeight)) {
4869         auto [caretAdjustOffset, caretAdjustHeight] = CalculateCaretOffsetAndHeight();
4870         caretHeight = caretAdjustHeight;
4871     }
4872 
4873     // richeditor relative to root node offset(without transform)
4874     auto parentGlobalOffset = renderContext->GetPaintRectWithoutTransform().GetOffset() -
4875         pipeline->GetRootRect().GetOffset();
4876     // caret top (without transform)
4877     auto caretTop = caretOffset.GetY() + parentGlobalOffset.GetY();
4878     double positionY = parentGlobalOffset.GetY();
4879     double height = caretTop + caretHeight + KEYBOARD_AVOID_OFFSET.ConvertToPx() - positionY;
4880 
4881     if (auto manager = pipeline->GetSafeAreaManager(); manager) {
4882         auto keyboardOffset = manager->GetKeyboardOffset();
4883         positionY -= keyboardOffset;
4884     }
4885     OffsetF caretLeftTopPoint(caretOffset.GetX() + parentGlobalOffset.GetX(), caretTop);
4886     OffsetF caretRightBottomPoint(caretLeftTopPoint.GetX() + CARET_WIDTH, caretLeftTopPoint.GetY() + caretHeight);
4887     HandlePointWithTransform(caretLeftTopPoint);
4888     HandlePointWithTransform(caretRightBottomPoint);
4889     // window rect relative to screen
4890     auto windowRect = pipeline->GetCurrentWindowRect();
4891     MiscServices::CursorInfo cursorInfo { .left = caretLeftTopPoint.GetX() + windowRect.Left(),
4892         .top = caretLeftTopPoint.GetY() + windowRect.Top(),
4893         .width = std::abs(caretLeftTopPoint.GetX() - caretRightBottomPoint.GetX()),
4894         .height = std::abs(caretLeftTopPoint.GetY() - caretRightBottomPoint.GetY()) };
4895     MiscServices::InputAttribute inputAttribute = { .inputPattern = (int32_t)TextInputType::UNSPECIFIED,
4896         .enterKeyType = (int32_t)GetTextInputActionValue(GetDefaultTextInputAction()),
4897         .isTextPreviewSupported = isTextPreviewSupported_ && (!isSpanStringMode_ || isAPI18Plus),
4898         .immersiveMode = static_cast<int32_t>(keyboardAppearance_) };
4899     auto start = textSelector_.IsValid() ? textSelector_.GetStart() : caretPosition_;
4900     auto end = textSelector_.IsValid() ? textSelector_.GetEnd() : caretPosition_;
4901     MiscServices::TextConfig textConfig = { .inputAttribute = inputAttribute,
4902         .cursorInfo = cursorInfo,
4903         .range = { .start = start, .end = end },
4904         .windowId = pipeline->GetFocusWindowId(),
4905         .positionY = positionY + windowRect.Top(),
4906         .height = height };
4907     return textConfig;
4908 }
4909 #else
UnableStandardInput(bool isFocusViewChanged)4910 bool RichEditorPattern::UnableStandardInput(bool isFocusViewChanged)
4911 {
4912     auto host = GetHost();
4913     CHECK_NULL_RETURN(host, false);
4914     auto context = host->GetContext();
4915     CHECK_NULL_RETURN(context, false);
4916     if (HasConnection()) {
4917         connection_->Show(isFocusViewChanged, GetInstanceId());
4918         return true;
4919     }
4920     TextInputConfiguration config;
4921     config.type = TextInputType::UNSPECIFIED;
4922     config.action = TextInputAction::DONE;
4923     config.obscureText = false;
4924     connection_ =
4925         TextInputProxy::GetInstance().Attach(WeakClaim(this), config, context->GetTaskExecutor(), GetInstanceId());
4926     if (!HasConnection()) {
4927         return false;
4928     }
4929     TextEditingValue value;
4930     if (spans_.empty()) {
4931         value.text = UtfUtils::Str16ToStr8(textForDisplay_);
4932     } else {
4933         for (auto it = spans_.begin(); it != spans_.end(); it++) {
4934             if ((*it)->placeholderIndex < 0) {
4935                 value.text.append(UtfUtils::Str16ToStr8((*it)->content));
4936             } else {
4937                 value.text.append(" ");
4938             }
4939         }
4940     }
4941     value.selection.Update(caretPosition_, caretPosition_);
4942     connection_->SetEditingState(value, GetInstanceId());
4943     connection_->Show(isFocusViewChanged, GetInstanceId());
4944     return true;
4945 }
4946 #endif
4947 
OnColorConfigurationUpdate()4948 void RichEditorPattern::OnColorConfigurationUpdate()
4949 {
4950     auto colorMode = GetColorMode();
4951     floatingCaretState_.UpdateOriginCaretColor(GetDisplayColorMode());
4952     if (colorMode == ColorMode::COLOR_MODE_UNDEFINED) {
4953         OnCommonColorChange();
4954     }
4955 }
4956 
OnThemeScopeUpdate(int32_t themeScopeId)4957 bool RichEditorPattern::OnThemeScopeUpdate(int32_t themeScopeId)
4958 {
4959     IF_PRESENT(magnifierController_, SetColorModeChange(true));
4960     floatingCaretState_.UpdateOriginCaretColor(GetDisplayColorMode());
4961     OnCommonColorChange();
4962     return false;
4963 }
4964 
OnCommonColorChange()4965 void RichEditorPattern::OnCommonColorChange()
4966 {
4967     auto host = GetHost();
4968     auto theme = GetTheme<RichEditorTheme>();
4969     auto textLayoutProperty = GetLayoutProperty<TextLayoutProperty>();
4970     CHECK_NULL_VOID(host && theme && textLayoutProperty);
4971 
4972     auto displayColorMode = GetDisplayColorMode();
4973     COLOR_MODE_LOCK(displayColorMode);
4974 
4975     const auto& themeTextStyle = theme->GetTextStyle();
4976     auto themeTextColor = themeTextStyle.GetTextColor();
4977     auto themeTextDecColor = themeTextStyle.GetTextDecorationColor();
4978     textLayoutProperty->UpdateTextColor(themeTextColor);
4979     textLayoutProperty->UpdateTextDecorationColor(themeTextDecColor);
4980     auto themeUrlSpanColor = GetUrlSpanColor();
4981     textLayoutProperty->UpdateUrlDefualtColor(themeUrlSpanColor);
4982     textLayoutProperty->UpdateUrlHoverColor(GetUrlHoverColor());
4983     textLayoutProperty->UpdateUrlPressedColor(GetUrlPressColor());
4984 
4985     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "theme, ColorMode=%{public}d, TextColor=%{public}s, DecorationColor=%{public}s",
4986         displayColorMode, themeTextColor.ToString().c_str(), themeTextDecColor.ToString().c_str());
4987 
4988     const auto& spans = host->GetChildren();
4989     for (const auto& uiNode : spans) {
4990         auto placeholderSpan = DynamicCast<PlaceholderSpanNode>(uiNode);
4991         if (placeholderSpan) {
4992             auto spanItem = placeholderSpan->GetSpanItem();
4993             CHECK_NULL_CONTINUE(spanItem);
4994             IF_PRESENT(spanItem, UpdateColorByResourceId());
4995         }
4996         auto spanNode = DynamicCast<SpanNode>(uiNode);
4997         CHECK_NULL_CONTINUE(spanNode);
4998         auto spanItem = spanNode->GetSpanItem();
4999         CHECK_NULL_CONTINUE(spanItem);
5000         auto& textColor = spanItem->urlOnRelease ? themeUrlSpanColor : themeTextColor;
5001         IF_TRUE(spanItem->useThemeFontColor, spanNode->UpdateTextColorWithoutCheck(textColor));
5002         IF_TRUE(spanItem->useThemeDecorationColor, spanNode->UpdateTextDecorationColorWithoutCheck(themeTextDecColor));
5003         spanNode->UpdateColorByResourceId();
5004     }
5005     paragraphCache_.Clear();
5006     IF_PRESENT(typingTextStyle_, UpdateColorByResourceId());
5007     IF_PRESENT(typingStyle_, UpdateColorByResourceId());
5008     IF_PRESENT(selectedBackgroundColor_, UpdateColorByResourceId());
5009 
5010     IF_PRESENT(magnifierController_, SetColorModeChange(true));
5011     auto scrollBar = GetScrollBar();
5012     auto scrollbarTheme = GetTheme<ScrollBarTheme>();
5013     CHECK_NULL_VOID(scrollBar && scrollbarTheme);
5014     scrollBar->SetForegroundColor(scrollbarTheme->GetForegroundColor());
5015     scrollBar->SetBackgroundColor(scrollbarTheme->GetBackgroundColor());
5016 }
5017 
UpdateCaretInfoToController()5018 void RichEditorPattern::UpdateCaretInfoToController()
5019 {
5020     CHECK_NULL_VOID(HasFocus());
5021     std::u16string text = u"";
5022     for (auto iter = spans_.begin(); iter != spans_.end(); iter++) {
5023         text += (*iter)->content;
5024     }
5025     auto start = textSelector_.IsValid() ? textSelector_.GetStart() : caretPosition_;
5026     auto end = textSelector_.IsValid() ? textSelector_.GetEnd() : caretPosition_;
5027 #if defined(ENABLE_STANDARD_INPUT)
5028     auto miscTextConfig = GetMiscTextConfig();
5029     CHECK_NULL_VOID(miscTextConfig.has_value());
5030     MiscServices::CursorInfo cursorInfo = miscTextConfig.value().cursorInfo;
5031     MiscServices::InputMethodController::GetInstance()->OnCursorUpdate(cursorInfo);
5032     MiscServices::InputMethodController::GetInstance()->OnSelectionChange(
5033         text, start, end);
5034     TAG_LOGD(AceLogTag::ACE_RICH_TEXT,
5035         "CursorInfo: pos=[%{public}.2f,%{public}.2f], size=[%{public}.2f,%{public}.2f], caret=%{public}d;"
5036         "OnSelectionChange: textLen=%{public}zu, range=[%{public}d,%{public}d]",
5037         cursorInfo.left, cursorInfo.top, cursorInfo.width, cursorInfo.height, caretPosition_,
5038         text.length(), start, end);
5039 #else
5040     if (HasConnection()) {
5041         TextEditingValue editingValue;
5042         editingValue.text = UtfUtils::Str16ToStr8(text);
5043         editingValue.hint = "";
5044         editingValue.selection.Update(start, end);
5045         connection_->SetEditingState(editingValue, GetInstanceId());
5046     }
5047 #endif
5048 }
5049 
HasConnection() const5050 bool RichEditorPattern::HasConnection() const
5051 {
5052 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
5053     return imeAttached_;
5054 #else
5055     return connection_ != nullptr;
5056 #endif
5057 }
5058 
SetCustomKeyboardOption(bool supportAvoidance)5059 void RichEditorPattern::SetCustomKeyboardOption(bool supportAvoidance)
5060 {
5061     keyboardAvoidance_ = supportAvoidance;
5062 }
5063 
RequestCustomKeyboard()5064 bool RichEditorPattern::RequestCustomKeyboard()
5065 {
5066 #if defined(ENABLE_STANDARD_INPUT)
5067     auto inputMethod = MiscServices::InputMethodController::GetInstance();
5068     if (inputMethod) {
5069         TAG_LOGI(AceLogTag::ACE_KEYBOARD, "RequestCKeyboard,close softkeyboard.");
5070         inputMethod->RequestHideInput();
5071         inputMethod->Close();
5072     }
5073 #else
5074     if (HasConnection()) {
5075         connection_->Close(GetInstanceId());
5076         connection_ = nullptr;
5077     }
5078 #endif
5079 
5080     if (isCustomKeyboardAttached_) {
5081         return true;
5082     }
5083     CHECK_NULL_RETURN(customKeyboardBuilder_, false);
5084     auto frameNode = GetHost();
5085     CHECK_NULL_RETURN(frameNode, false);
5086     auto pipeline = frameNode->GetContext();
5087     CHECK_NULL_RETURN(pipeline, false);
5088     auto overlayManager = pipeline->GetOverlayManager();
5089     CHECK_NULL_RETURN(overlayManager, false);
5090     overlayManager->SetCustomKeyboardOption(keyboardAvoidance_);
5091     overlayManager->BindKeyboard(customKeyboardBuilder_, frameNode->GetId());
5092     isCustomKeyboardAttached_ = true;
5093     contentChange_ = false;
5094     keyboardOverlay_ = overlayManager;
5095     auto [caretOffset, caretHeight] = CalculateCaretOffsetAndHeight();
5096     keyboardOverlay_->AvoidCustomKeyboard(frameNode->GetId(), caretHeight);
5097     return true;
5098 }
5099 
CloseCustomKeyboard()5100 bool RichEditorPattern::CloseCustomKeyboard()
5101 {
5102     auto frameNode = GetHost();
5103     CHECK_NULL_RETURN(frameNode, false);
5104     CHECK_NULL_RETURN(keyboardOverlay_, false);
5105     keyboardOverlay_->CloseKeyboard(frameNode->GetId());
5106     isCustomKeyboardAttached_ = false;
5107     contentChange_ = false;
5108     return true;
5109 }
5110 
CheckPreviewTextValidate(const std::u16string & previewTextValue,const PreviewRange range)5111 int32_t RichEditorPattern::CheckPreviewTextValidate(const std::u16string& previewTextValue, const PreviewRange range)
5112 {
5113     if (IsDragging()) {
5114         TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "SetPreviewText is not allowed while dragging");
5115         return ERROR_BAD_PARAMETERS;
5116     }
5117     return NO_ERRORS;
5118 }
5119 
CheckPreviewTextValidate(const std::string & previewTextValue,const PreviewRange range)5120 int32_t RichEditorPattern::CheckPreviewTextValidate(const std::string& previewTextValue, const PreviewRange range)
5121 {
5122     return CheckPreviewTextValidate(UtfUtils::Str8DebugToStr16(previewTextValue), range);
5123 }
5124 
SetPreviewText(const std::u16string & previewTextValue,const PreviewRange range)5125 int32_t RichEditorPattern::SetPreviewText(const std::u16string& previewTextValue, const PreviewRange range)
5126 {
5127     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "SetPreviewText, range=[%{public}d,%{public}d], isSSMode=%{public}d",
5128         range.start, range.end, isSpanStringMode_);
5129     CHECK_NULL_RETURN(!isSpanStringMode_ || isAPI18Plus, ERROR_BAD_PARAMETERS);
5130     SEC_TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "previewText=%{public}s", UtfUtils::Str16ToStr8(previewTextValue).c_str());
5131     auto host = GetHost();
5132     CHECK_NULL_RETURN(host, ERROR_BAD_PARAMETERS);
5133     CHECK_NULL_RETURN(!IsDragging(), ERROR_BAD_PARAMETERS);
5134 
5135     if (!IsPreviewTextInputting()) {
5136         if (!InitPreviewText(previewTextValue, range)) {
5137             return ERROR_BAD_PARAMETERS;
5138         }
5139     } else {
5140         if (!UpdatePreviewText(previewTextValue, range)) {
5141             return ERROR_BAD_PARAMETERS;
5142         }
5143     }
5144     previewTextRecord_.replacedRange.Set(previewTextRecord_.startOffset, previewTextRecord_.endOffset);
5145     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
5146     return NO_ERRORS;
5147 }
5148 
InitPreviewText(const std::u16string & previewTextValue,const PreviewRange & range)5149 bool RichEditorPattern::InitPreviewText(const std::u16string& previewTextValue, const PreviewRange& range)
5150 {
5151     if (range.start != -1 || range.end != -1) {
5152         return ReplaceText(previewTextValue, range);
5153     }
5154     // interrupt touch selecting when initialize preview text
5155     ResetTouchSelectState();
5156     IF_PRESENT(magnifierController_, RemoveMagnifierFrameNode());
5157     auto& record = previewTextRecord_;
5158     record.needReplacePreviewText = true;
5159     record.previewTextHasStarted = true;
5160     record.replacedRange = range;
5161     record.startOffset = textSelector_.SelectNothing() ? caretPosition_ : textSelector_.GetTextStart();
5162     record.newPreviewContent = previewTextValue;
5163     auto length = static_cast<int32_t>(previewTextValue.length());
5164     record.endOffset = record.startOffset + length;
5165     auto spanCountBefore = spans_.size();
5166     ProcessInsertValue(previewTextValue, OperationType::IME, false);
5167     record.isSpanSplit = spans_.size() - spanCountBefore > 1;
5168     record.previewContent = record.newPreviewContent;
5169     record.newPreviewContent.clear();
5170     record.needReplacePreviewText = false;
5171     return true;
5172 }
5173 
ReplaceText(const std::u16string & previewTextValue,const PreviewRange & range)5174 bool RichEditorPattern::ReplaceText(const std::u16string& previewTextValue, const PreviewRange& range)
5175 {
5176     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "ReplaceText");
5177     if (range.start < 0 || range.end < range.start || range.end > GetTextContentLength()) {
5178         TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "bad PreviewRange");
5179         return false;
5180     }
5181     previewTextRecord_.replacedRange = range;
5182     previewTextRecord_.needReplaceText = true;
5183     previewTextRecord_.startOffset = range.start;
5184     previewTextRecord_.endOffset = range.end;
5185     ProcessInsertValue(previewTextValue, OperationType::IME, false);
5186     previewTextRecord_.needReplaceText = false;
5187     return true;
5188 }
5189 
5190 // Used for text replacement, without notifying developer caret change
DeleteByRange(OperationRecord * const record,int32_t start,int32_t end)5191 void RichEditorPattern::DeleteByRange(OperationRecord* const record, int32_t start, int32_t end)
5192 {
5193     auto length = end - start;
5194     CHECK_NULL_VOID(length > 0);
5195     lastCaretPosition_ = caretPosition_;
5196     caretPosition_ = std::clamp(start, 0, GetTextContentLength());
5197     if (isSpanStringMode_) {
5198         DeleteValueInStyledString(start, length, true, false);
5199         return;
5200     }
5201     std::u16string deleteText = DeleteForwardOperation(length);
5202     if (record && deleteText.length() != 0) {
5203         record->deleteText = deleteText;
5204     }
5205 }
5206 
UpdatePreviewText(const std::u16string & previewTextValue,const PreviewRange & range)5207 bool RichEditorPattern::UpdatePreviewText(const std::u16string& previewTextValue, const PreviewRange& range)
5208 {
5209     auto& record = previewTextRecord_;
5210     if (range.start == -1 && range.end == -1 && !record.previewContent.empty()) {
5211         record.replacedRange.Set(record.startOffset, record.endOffset);
5212         record.newPreviewContent = previewTextValue;
5213         record.needReplacePreviewText = true;
5214         record.needUpdateCaret = caretPosition_ == record.endOffset;
5215         ProcessInsertValue(previewTextValue, OperationType::IME, false);
5216         record.previewContent = record.newPreviewContent;
5217         record.newPreviewContent.clear();
5218         record.endOffset = record.startOffset + static_cast<int32_t>(previewTextValue.length());
5219         record.needReplacePreviewText = false;
5220         record.needUpdateCaret = true;
5221     } else {
5222         if (range.start < record.startOffset || range.end > record.endOffset || range.end < range.start) {
5223             TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "bad PreviewRange");
5224             return false;
5225         }
5226         if (previewTextValue.empty() && range.start == range.end) {
5227             SetCaretPosition(range.end);
5228             return false;
5229         }
5230         auto replaceIndex = range.start - record.startOffset;
5231         auto replaceLength = range.end - range.start;
5232         auto oldContent = record.previewContent;
5233         auto oldPreviewLength = static_cast<int32_t>(oldContent.length());
5234         if (replaceIndex < 0 || replaceIndex + replaceLength > oldPreviewLength) {
5235             TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "bad replaced range ");
5236             return false;
5237         }
5238         auto newContent = oldContent.replace(replaceIndex, replaceLength, previewTextValue);
5239         record.replacedRange = range;
5240         record.newPreviewContent = newContent;
5241         record.needReplacePreviewText = true;
5242         ProcessInsertValue(previewTextValue, OperationType::IME, false);
5243         record.previewContent = record.newPreviewContent;
5244         record.newPreviewContent.clear();
5245         record.endOffset = record.startOffset + static_cast<int32_t>(newContent.length());
5246         record.needReplacePreviewText = false;
5247     }
5248     return true;
5249 }
5250 
GetPreviewTextInfo() const5251 const PreviewTextInfo RichEditorPattern::GetPreviewTextInfo() const
5252 {
5253     PreviewTextInfo info;
5254     if (!previewTextRecord_.previewContent.empty()) {
5255         info.value = previewTextRecord_.previewContent;
5256         info.offset = previewTextRecord_.startOffset;
5257     }
5258     return info;
5259 }
5260 
MergeAdjacentSpans(int32_t caretPosition)5261 void RichEditorPattern::MergeAdjacentSpans(int32_t caretPosition)
5262 {
5263     auto host = GetHost();
5264     CHECK_NULL_VOID(host);
5265     auto uiNodes = host->GetChildren();
5266     auto it = std::find_if(uiNodes.begin(), uiNodes.end(), [caretPosition](const RefPtr<UINode>& uiNode) {
5267         auto spanNode = DynamicCast<SpanNode>(uiNode);
5268         CHECK_NULL_RETURN(spanNode, false);
5269         return spanNode->GetSpanItem()->position == caretPosition;
5270     });
5271     CHECK_NULL_VOID(it != uiNodes.end());
5272     auto beforeSpanNode = DynamicCast<SpanNode>(*it);
5273     ++it;
5274     CHECK_NULL_VOID(it != uiNodes.end());
5275     auto afterSpanNode = DynamicCast<SpanNode>(*it);
5276     CHECK_NULL_VOID(beforeSpanNode && afterSpanNode);
5277     CHECK_NULL_VOID(beforeSpanNode->GetTag() == V2::SPAN_ETS_TAG && afterSpanNode->GetTag() == V2::SPAN_ETS_TAG);
5278     auto beforeSpanItem = beforeSpanNode->GetSpanItem();
5279     auto afterSpanItem = afterSpanNode->GetSpanItem();
5280     CHECK_NULL_VOID(beforeSpanItem && afterSpanItem);
5281     beforeSpanNode->UpdateContent(beforeSpanItem->content + afterSpanItem->content);
5282     afterSpanItem->content.clear();
5283     RemoveEmptySpans();
5284 }
5285 
FinishTextPreview()5286 void RichEditorPattern::FinishTextPreview()
5287 {
5288     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "FinishTextPreview byImf");
5289     if (previewTextRecord_.previewContent.empty()) {
5290         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "previewContent is empty");
5291         RemoveEmptySpans();
5292         IF_TRUE(previewTextRecord_.isSpanSplit, MergeAdjacentSpans(caretPosition_));
5293         previewTextRecord_.Reset();
5294         return;
5295     }
5296     auto previewContent = previewTextRecord_.previewContent;
5297     FinishTextPreviewInner();
5298     ProcessInsertValue(previewContent, OperationType::IME, false);
5299 }
5300 
FinishTextPreviewInner(bool deletePreviewText)5301 void RichEditorPattern::FinishTextPreviewInner(bool deletePreviewText)
5302 {
5303     CHECK_NULL_VOID(previewTextRecord_.previewTextHasStarted);
5304     TAG_LOGI(AceLogTag::ACE_RICH_TEXT,
5305         "FinishTextPreviewInner, deleteText=%{public}d, previewContent is empty=%{public}d", deletePreviewText,
5306         previewTextRecord_.previewContent.empty());
5307     previewTextRecord_.previewTextExiting = true;
5308     IF_TRUE(deletePreviewText && !previewTextRecord_.previewContent.empty(),
5309         DeleteByRange(nullptr, previewTextRecord_.startOffset, previewTextRecord_.endOffset));
5310     previewTextRecord_.Reset();
5311 }
5312 
NotifyExitTextPreview(bool deletePreviewText)5313 void RichEditorPattern::NotifyExitTextPreview(bool deletePreviewText)
5314 {
5315     CHECK_NULL_VOID(previewTextRecord_.previewTextHasStarted);
5316     CHECK_NULL_VOID(HasFocus());
5317     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "NotifyExitTextPreview");
5318     FinishTextPreviewInner(deletePreviewText);
5319     NotifyImfFinishTextPreview();
5320 }
5321 
NotifyImfFinishTextPreview()5322 void RichEditorPattern::NotifyImfFinishTextPreview()
5323 {
5324 #if defined(ENABLE_STANDARD_INPUT)
5325     MiscServices::InputMethodController::GetInstance()->OnSelectionChange(u"", caretPosition_, caretPosition_);
5326     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "notify imf that richEditor exit textPreview");
5327 #endif
5328 }
5329 
GetPreviewTextRects()5330 std::vector<RectF> RichEditorPattern::GetPreviewTextRects()
5331 {
5332     auto rects = paragraphs_.GetRects(previewTextRecord_.startOffset, previewTextRecord_.endOffset,
5333         RectHeightPolicy::COVER_TEXT);
5334     auto offset = GetTextRect().GetOffset() - OffsetF(0.0f, std::min(baselineOffset_, 0.0f));
5335     for (RectF& rect : rects) {
5336         rect += offset;
5337     }
5338     return rects;
5339 }
5340 
GetPreviewTextStyle() const5341 PreviewTextStyle RichEditorPattern::GetPreviewTextStyle() const
5342 {
5343     auto previewTextStyle = PreviewTextStyle::NORMAL;
5344     auto property = GetLayoutProperty<RichEditorLayoutProperty>();
5345     if (property && property->HasPreviewTextStyle()) {
5346         auto style = property->GetPreviewTextStyle();
5347         CHECK_NULL_RETURN(style.has_value(), previewTextStyle);
5348         if (style.value() == PREVIEW_STYLE_NORMAL) {
5349             previewTextStyle = PreviewTextStyle::NORMAL;
5350         } else if (style.value() == PREVIEW_STYLE_UNDERLINE) {
5351             previewTextStyle = PreviewTextStyle::UNDERLINE;
5352         } else {
5353             TAG_LOGW(
5354                 AceLogTag::ACE_RICH_TEXT, "invalid previewTextStyle of RichEditorLayoutProperty");
5355         }
5356     }
5357     return previewTextStyle;
5358 }
5359 
GetPreviewTextDecorationColor() const5360 const Color& RichEditorPattern::GetPreviewTextDecorationColor() const
5361 {
5362     auto pipeline = PipelineBase::GetCurrentContextSafelyWithCheck();
5363     CHECK_NULL_RETURN(pipeline, Color::TRANSPARENT);
5364     auto theme = pipeline->GetTheme<RichEditorTheme>();
5365     CHECK_NULL_RETURN(theme, Color::TRANSPARENT);
5366     if (GetPreviewTextStyle() == PreviewTextStyle::UNDERLINE) {
5367         return theme->GetPreviewUnderLineColor();
5368     }
5369     return Color::TRANSPARENT;
5370 }
5371 
GetPreviewTextUnderlineWidth() const5372 float RichEditorPattern::GetPreviewTextUnderlineWidth() const
5373 {
5374     auto pipeline = PipelineBase::GetCurrentContextSafelyWithCheck();
5375     CHECK_NULL_RETURN(pipeline, 0.0f);
5376     auto theme = pipeline->GetTheme<RichEditorTheme>();
5377     CHECK_NULL_RETURN(theme, 0.0f);
5378     return theme->GetPreviewUnderlineWidth().ConvertToPx();
5379 }
5380 
IsIMEOperation(OperationType operationType)5381 bool RichEditorPattern::IsIMEOperation(OperationType operationType)
5382 {
5383     return operationType == OperationType::IME;
5384 }
5385 
InsertValue(const std::string & insertValue,bool isIME)5386 void RichEditorPattern::InsertValue(const std::string& insertValue, bool isIME)
5387 {
5388     InsertValue(UtfUtils::Str8ToStr16(insertValue), isIME);
5389 }
5390 
InsertValue(const std::u16string & insertValue,bool isIME)5391 void RichEditorPattern::InsertValue(const std::u16string& insertValue, bool isIME)
5392 {
5393     InsertValueByOperationType(insertValue, isIME ? OperationType::IME : OperationType::DEFAULT);
5394 }
5395 
InsertValueByOperationType(const std::u16string & insertValue,OperationType operationType)5396 void RichEditorPattern::InsertValueByOperationType(const std::u16string& insertValue, OperationType operationType)
5397 {
5398     ProcessInsertValue(insertValue, operationType, true);
5399 }
5400 
ProcessTextTruncationOperation(std::u16string & text,bool calledByImf)5401 bool RichEditorPattern::ProcessTextTruncationOperation(std::u16string& text, bool calledByImf)
5402 {
5403     bool needTruncationInsertValue = calledByImf || !previewTextRecord_.needReplacePreviewText;
5404     int32_t selectLength =
5405         textSelector_.SelectNothing() ? 0 : textSelector_.GetTextEnd() - textSelector_.GetTextStart();
5406     int32_t previewContentLength = previewTextRecord_.previewContent.empty()
5407                                        ? previewTextRecord_.replacedRange.end - previewTextRecord_.replacedRange.start
5408                                        : static_cast<int32_t>(previewTextRecord_.previewContent.length());
5409 
5410     if (!needTruncationInsertValue || GetTextContentLength() - previewContentLength < maxLength_.value_or(INT_MAX)) {
5411         if (needTruncationInsertValue && text.length() != 1) {
5412             auto maxLength = maxLength_.value_or(INT_MAX) - GetTextContentLength() + previewContentLength;
5413             auto allowInsertLength =  CalculateTruncationLength(text, maxLength);
5414             if (allowInsertLength == 0) {
5415                 TAG_LOGD(AceLogTag::ACE_RICH_TEXT,
5416                     "ProcessTextTruncation: No space to insert text. maxLength=%{public}d",
5417                     maxLength_.value_or(INT_MAX));
5418                 return false;
5419             }
5420             text = text.substr(0, allowInsertLength);
5421             return true;
5422         }
5423         return true;
5424     }
5425 
5426     if (previewTextRecord_.needReplaceText) {
5427         text = text.substr(0, maxLength_.value_or(INT_MAX) + selectLength);
5428         return true;
5429     }
5430     if (!textSelector_.SelectNothing()) {
5431         auto allowInsertLength = CalculateTruncationLength(text, 0);
5432         if (allowInsertLength == 0) {
5433             TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "ProcessTextTruncation: No space to insert text. maxLength=%{public}d",
5434                 maxLength_.value_or(INT_MAX));
5435             return false;
5436         }
5437         text = text.substr(0, allowInsertLength);
5438         return true;
5439     }
5440     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "ProcessTextTruncation: maxLength=%{public}d", maxLength_.value_or(INT_MAX));
5441     IF_TRUE(IsPreviewTextInputting(), FinishTextPreviewInner());
5442     return false;
5443 }
5444 
ProcessInsertValueMore(const std::u16string & text,OperationRecord record,OperationType operationType,RichEditorChangeValue changeValue,PreviewTextRecord preRecord)5445 void RichEditorPattern::ProcessInsertValueMore(const std::u16string& text, OperationRecord record,
5446     OperationType operationType, RichEditorChangeValue changeValue, PreviewTextRecord preRecord)
5447 {
5448     if (preRecord.needReplacePreviewText && !previewTextRecord_.needReplacePreviewText) {
5449         TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "previewText finished when ProcessInsertValue");
5450         NotifyImfFinishTextPreview();
5451         return;
5452     }
5453     ClearRedoOperationRecords();
5454     InsertValueOperation(text, &record, operationType);
5455     record.afterCaretPosition = caretPosition_;
5456     if (isDragSponsor_) {
5457         record.deleteCaretPostion = dragRange_.first;
5458     }
5459     AddOperationRecord(record);
5460     AfterContentChange(changeValue);
5461 }
5462 
5463 // operationType: when type is IME, it controls whether to perform ime callbacks
5464 // calledByImf: true means real input; false means preview input
ProcessInsertValue(const std::u16string & insertValue,OperationType operationType,bool calledByImf)5465 void RichEditorPattern::ProcessInsertValue(const std::u16string& insertValue, OperationType operationType,
5466     bool calledByImf)
5467 {
5468     CONTENT_MODIFY_LOCK(this);
5469     auto text = insertValue;
5470     if (!ProcessTextTruncationOperation(text, calledByImf)) {
5471         return;
5472     }
5473     bool isIME = IsIMEOperation(operationType);
5474     TAG_LOGI(AceLogTag::ACE_RICH_TEXT,
5475         "insertLen=%{public}zu, isIME=%{public}d, calledByImf=%{public}d, isSpanString=%{public}d",
5476         insertValue.length(), isIME, calledByImf, isSpanStringMode_);
5477     SEC_TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "insertValue=%{public}s",
5478         StringUtils::RestoreEscape(UtfUtils::Str16ToStr8(insertValue)).c_str());
5479 
5480     if (isIME && calledByImf && (!isEditing_ || IsDragging())) {
5481         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "NOT allow input, isEditing=%{public}d, isDragging=%{public}d",
5482             isEditing_, IsDragging());
5483         return;
5484     }
5485     if (isSpanStringMode_) {
5486         InsertValueInStyledString(text, calledByImf);
5487         return;
5488     }
5489     OperationRecord record;
5490     record.beforeCaretPosition = caretPosition_ + moveLength_;
5491     if (textSelector_.IsValid()) {
5492         record.beforeCaretPosition = textSelector_.GetTextStart();
5493     }
5494     record.addText = text;
5495 
5496     RichEditorChangeValue changeValue;
5497     PreviewTextRecord preRecord = previewTextRecord_;
5498     bool allowContentChange = BeforeChangeText(changeValue, record, RecordType::INSERT);
5499     if (calledByImf && previewTextRecord_.IsValid()) {
5500         FinishTextPreviewInner();
5501     }
5502     bool allowImeInput = isIME ? BeforeIMEInsertValue(text) : true;
5503     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "allowContentChange=%{public}d, allowImeInput=%{public}d, needReplacePreviewText=%{public}d",
5504         allowContentChange, allowImeInput, previewTextRecord_.needReplacePreviewText);
5505     bool allowPreviewText = previewTextRecord_.needReplacePreviewText;
5506     CHECK_NULL_VOID((allowContentChange && allowImeInput) || allowPreviewText);
5507     ProcessInsertValueMore(text, record, operationType, changeValue, preRecord);
5508 }
5509 
InsertValueOperation(const std::u16string & insertValue,OperationRecord * const record,OperationType operationType)5510 void RichEditorPattern::InsertValueOperation(const std::u16string& insertValue, OperationRecord* const record,
5511     OperationType operationType)
5512 {
5513     bool isSelector = textSelector_.IsValid();
5514     if (isSelector) {
5515         DeleteByRange(record, textSelector_.GetTextStart(), textSelector_.GetTextEnd());
5516         ResetSelection();
5517     } else if (previewTextRecord_.needReplacePreviewText || previewTextRecord_.needReplaceText) {
5518         DeleteByRange(record, previewTextRecord_.replacedRange.start, previewTextRecord_.replacedRange.end);
5519     }
5520     bool isSingleHandleMoving = selectOverlay_->IsSingleHandleMoving();
5521     CloseSelectOverlay();
5522     TextInsertValueInfo info;
5523     CalcInsertValueObj(info);
5524     IF_TRUE((!caretVisible_ || isSingleHandleMoving) && HasFocus(), StartTwinkling());
5525     auto host = GetHost();
5526     CHECK_NULL_VOID(host);
5527     bool isIME = IsIMEOperation(operationType);
5528     RefPtr<SpanNode> spanNode = DynamicCast<SpanNode>(host->GetChildAtIndex(info.GetSpanIndex()));
5529     RefPtr<SpanNode> spanNodeBefore = DynamicCast<SpanNode>(host->GetChildAtIndex(info.GetSpanIndex() - 1));
5530     RefPtr<SpanNode> targetSpanNode = spanNode;
5531     bool needCreateNewSpan = host->GetChildren().empty();
5532     if (info.GetOffsetInSpan() == 0) {
5533         bool spanNodeBeforeCanInsert = spanNodeBefore && spanNodeBefore->GetTag() == V2::SPAN_ETS_TAG;
5534         bool spanNodeCanInsert = spanNode && spanNode->GetTag() == V2::SPAN_ETS_TAG;
5535         bool insertToBeforeNode = spanNodeBeforeCanInsert && !spanNodeCanInsert;
5536         insertToBeforeNode |= spanNodeBeforeCanInsert && spanNodeCanInsert && !IsLineSeparatorInLast(spanNodeBefore);
5537         if (insertToBeforeNode) {
5538             auto spanItem = spanNodeBefore->GetSpanItem();
5539             info.SetSpanIndex(info.GetSpanIndex() - 1);
5540             info.SetOffsetInSpan(spanItem->position - spanItem->rangeStart);
5541             targetSpanNode = spanNodeBefore;
5542         }
5543         needCreateNewSpan |= !spanNodeBeforeCanInsert && !spanNodeCanInsert;
5544     }
5545     if (needCreateNewSpan) {
5546         CreateTextSpanNode(targetSpanNode, info, insertValue, isIME);
5547         return;
5548     }
5549     if (typingStyle_.has_value() && !HasSameTypingStyle(targetSpanNode)) {
5550         InsertDiffStyleValueInSpan(targetSpanNode, info, insertValue, isIME);
5551         return;
5552     }
5553     InsertValueToSpanNode(targetSpanNode, insertValue, info);
5554     AfterInsertValue(targetSpanNode, static_cast<int32_t>(insertValue.length()), false, isIME);
5555 }
5556 
DeleteSelectOperation(OperationRecord * const record)5557 void RichEditorPattern::DeleteSelectOperation(OperationRecord* const record)
5558 {
5559     std::u16string deleteText = DeleteForwardOperation(textSelector_.GetTextEnd() - textSelector_.GetTextStart());
5560     if (record && deleteText.length() != 0) {
5561         record->deleteText = deleteText;
5562     }
5563     CloseSelectOverlay();
5564     ResetSelection();
5565 }
5566 
CreateTextStyleByTypingStyle()5567 TextStyle RichEditorPattern::CreateTextStyleByTypingStyle()
5568 {
5569     auto theme = GetTheme<RichEditorTheme>();
5570     auto ret = theme ? theme->GetTextStyle() : TextStyle();
5571     CHECK_NULL_RETURN(typingStyle_.has_value() && typingTextStyle_.has_value(), ret);
5572     const auto& updateSpanStyle = typingStyle_.value();
5573     const auto& textStyle = typingTextStyle_.value();
5574     IF_TRUE(updateSpanStyle.updateFontFeature, ret.SetFontFeatures(textStyle.GetFontFeatures()));
5575     IF_TRUE(updateSpanStyle.updateTextColor, ret.SetTextColor(textStyle.GetTextColor()));
5576     IF_TRUE(updateSpanStyle.updateLineHeight, ret.SetLineHeight(textStyle.GetLineHeight()));
5577     IF_TRUE(updateSpanStyle.updateLetterSpacing, ret.SetLetterSpacing(textStyle.GetLetterSpacing()));
5578     IF_TRUE(updateSpanStyle.updateFontSize, ret.SetFontSize(textStyle.GetFontSize()));
5579     IF_TRUE(updateSpanStyle.updateItalicFontStyle, ret.SetFontStyle(textStyle.GetFontStyle()));
5580     IF_TRUE(updateSpanStyle.updateFontWeight, ret.SetFontWeight(textStyle.GetFontWeight()));
5581     IF_TRUE(updateSpanStyle.updateFontFamily, ret.SetFontFamilies(textStyle.GetFontFamilies()));
5582     IF_TRUE(updateSpanStyle.updateTextShadows, ret.SetTextShadows(textStyle.GetTextShadows()));
5583     IF_TRUE(updateSpanStyle.updateHalfLeading, ret.SetHalfLeading(textStyle.GetHalfLeading()));
5584     IF_TRUE(updateSpanStyle.updateTextDecoration, ret.SetTextDecoration(textStyle.GetTextDecoration()));
5585     IF_TRUE(updateSpanStyle.updateTextDecorationColor, ret.SetTextDecorationColor(textStyle.GetTextDecorationColor()));
5586     IF_TRUE(updateSpanStyle.updateTextDecorationStyle, ret.SetTextDecorationStyle(textStyle.GetTextDecorationStyle()));
5587     IF_TRUE(updateSpanStyle.updateTextBackgroundStyle, ret.SetTextBackgroundStyle(textStyle.GetTextBackgroundStyle()));
5588     return ret;
5589 }
5590 
InsertDiffStyleValueInSpan(RefPtr<SpanNode> & spanNode,const TextInsertValueInfo & info,const std::u16string & insertValue,bool isIME)5591 void RichEditorPattern::InsertDiffStyleValueInSpan(
5592     RefPtr<SpanNode>& spanNode, const TextInsertValueInfo& info, const std::u16string& insertValue, bool isIME)
5593 {
5594     auto host = GetHost();
5595     CHECK_NULL_VOID(host);
5596     TextSpanOptions options;
5597     options.value = insertValue;
5598     options.offset = caretPosition_;
5599     options.style = CreateTextStyleByTypingStyle();
5600     options.useThemeFontColor = typingStyle_->useThemeFontColor;
5601     options.useThemeDecorationColor = typingStyle_->useThemeDecorationColor;
5602     auto newSpanIndex = AddTextSpanOperation(options, false, -1,  true, false);
5603     auto newSpanNode = DynamicCast<SpanNode>(host->GetChildAtIndex(newSpanIndex));
5604     CopyTextSpanLineStyle(spanNode, newSpanNode, true);
5605     AfterInsertValue(newSpanNode, static_cast<int32_t>(insertValue.length()), true, isIME);
5606 }
5607 
IsLineSeparatorInLast(RefPtr<SpanNode> & spanNode)5608 bool RichEditorPattern::IsLineSeparatorInLast(RefPtr<SpanNode>& spanNode)
5609 {
5610     std::u16string content = spanNode->GetSpanItem()->content;
5611     return !content.empty() && content.back() == u'\n';
5612 }
5613 
InsertValueToSpanNode(RefPtr<SpanNode> & spanNode,const std::u16string & insertValue,const TextInsertValueInfo & info)5614 void RichEditorPattern::InsertValueToSpanNode(
5615     RefPtr<SpanNode>& spanNode, const std::u16string& insertValue, const TextInsertValueInfo& info)
5616 {
5617     auto spanItem = spanNode->GetSpanItem();
5618     CHECK_NULL_VOID(spanItem);
5619     auto textTemp = spanItem->content;
5620     auto textTempSize = static_cast<int32_t>(textTemp.size());
5621     if (textTempSize < info.GetOffsetInSpan() || info.GetOffsetInSpan() < 0) {
5622         TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "InsertValueToSpanNode error, spanSize=%{public}d, offsetInSpan=%{public}d",
5623             textTempSize, info.GetOffsetInSpan());
5624         RichEditorInfo errorInfo { RichEditorErrorType::INSERT_VALUE, textTempSize,
5625             static_cast<int32_t>(insertValue.length()), info.GetOffsetInSpan() };
5626         RichEditorErrorReport(errorInfo);
5627         return;
5628     }
5629     textTemp.insert(info.GetOffsetInSpan(), insertValue);
5630     spanNode->UpdateContent(textTemp);
5631     UpdateSpanPosition();
5632     SpanNodeFission(spanNode);
5633 }
5634 
InsertValueToBeforeSpan(RefPtr<SpanNode> & spanNodeBefore,const std::u16string & insertValue)5635 RefPtr<SpanNode> RichEditorPattern::InsertValueToBeforeSpan(
5636     RefPtr<SpanNode>& spanNodeBefore, const std::u16string& insertValue)
5637 {
5638     auto spanItem = spanNodeBefore->GetSpanItem();
5639     CHECK_NULL_RETURN(spanItem, spanNodeBefore);
5640     auto textTemp = spanItem->content;
5641     textTemp.append(insertValue);
5642 
5643     auto index = textTemp.find(LINE_SEPARATOR);
5644     if (index != std::u16string::npos) {
5645         spanNodeBefore->UpdateContent(textTemp.substr(0, index + 1));
5646         auto textAfter = textTemp.substr(index + 1);
5647         spanItem->position += static_cast<int32_t>(insertValue.length()) - static_cast<int32_t>(textAfter.length());
5648         if (!textAfter.empty()) {
5649             auto host = GetHost();
5650             CHECK_NULL_RETURN(spanItem, spanNodeBefore);
5651             TextInsertValueInfo infoAfter;
5652             infoAfter.SetSpanIndex(host->GetChildIndex(spanNodeBefore) + 1);
5653             infoAfter.SetOffsetInSpan(0);
5654             auto nodeId = ViewStackProcessor::GetInstance()->ClaimNodeId();
5655             RefPtr<SpanNode> spanNodeAfter = SpanNode::GetOrCreateSpanNode(nodeId);
5656             spanNodeAfter->MountToParent(host, infoAfter.GetSpanIndex());
5657             spanNodeAfter->UpdateContent(textAfter);
5658             CopyTextSpanStyle(spanNodeBefore, spanNodeAfter);
5659             auto spanItemAfter = spanNodeAfter->GetSpanItem();
5660             spanItemAfter->position = static_cast<int32_t>(textTemp.length());
5661             spanItemAfter->useThemeFontColor = spanItem->useThemeFontColor;
5662             spanItemAfter->useThemeDecorationColor = spanItem->useThemeDecorationColor;
5663             AddSpanItem(spanItemAfter, host->GetChildIndex(spanNodeBefore) + 1);
5664             SpanNodeFission(spanNodeAfter);
5665             return spanNodeAfter;
5666         }
5667     } else {
5668         spanNodeBefore->UpdateContent(textTemp);
5669         spanItem->position += static_cast<int32_t>(insertValue.length());
5670     }
5671     return spanNodeBefore;
5672 }
5673 
CreateTextSpanNode(RefPtr<SpanNode> & spanNode,const TextInsertValueInfo & info,const std::u16string & insertValue,bool isIME)5674 void RichEditorPattern::CreateTextSpanNode(
5675     RefPtr<SpanNode>& spanNode, const TextInsertValueInfo& info, const std::u16string& insertValue, bool isIME)
5676 {
5677     auto host = GetHost();
5678     CHECK_NULL_VOID(host);
5679     auto nodeId = ViewStackProcessor::GetInstance()->ClaimNodeId();
5680     spanNode = SpanNode::GetOrCreateSpanNode(nodeId);
5681     spanNode->MountToParent(host, info.GetSpanIndex());
5682     auto spanItem = spanNode->GetSpanItem();
5683     if (typingStyle_.has_value() && typingTextStyle_.has_value()) {
5684         spanItem->useThemeFontColor = typingStyle_->useThemeFontColor;
5685         spanItem->useThemeDecorationColor = typingStyle_->useThemeDecorationColor;
5686         UpdateTextStyle(spanNode, typingStyle_.value(), typingTextStyle_.value());
5687         auto spanItem = spanNode->GetSpanItem();
5688         spanItem->SetTextStyle(typingTextStyle_);
5689     } else {
5690         spanNode->UpdateFontSize(Dimension(DEFAULT_TEXT_SIZE, DimensionUnit::FP));
5691         SetDefaultColor(spanNode);
5692     }
5693     AddSpanItem(spanItem, info.GetSpanIndex());
5694     spanNode->UpdateContent(insertValue);
5695     UpdateSpanPosition();
5696     SpanNodeFission(spanNode);
5697     AfterInsertValue(spanNode, static_cast<int32_t>(insertValue.length()), true, isIME);
5698 }
5699 
SetDefaultColor(RefPtr<SpanNode> & spanNode)5700 void RichEditorPattern::SetDefaultColor(RefPtr<SpanNode>& spanNode)
5701 {
5702     auto richEditorTheme = GetTheme<RichEditorTheme>();
5703     CHECK_NULL_VOID(richEditorTheme);
5704     Color textColor = richEditorTheme->GetTextStyle().GetTextColor();
5705     spanNode->UpdateTextColorWithoutCheck(textColor);
5706     spanNode->UpdateTextDecorationColorWithoutCheck(textColor);
5707     if (auto& spanItem = spanNode->GetSpanItem(); spanItem && spanItem->urlOnRelease) {
5708         spanNode->UpdateTextColor(GetUrlSpanColor());
5709     }
5710 }
5711 
BeforeIMEInsertValue(const std::u16string & insertValue)5712 bool RichEditorPattern::BeforeIMEInsertValue(const std::u16string& insertValue)
5713 {
5714     auto eventHub = GetEventHub<RichEditorEventHub>();
5715     CHECK_NULL_RETURN(eventHub, true);
5716     RichEditorInsertValue insertValueInfo;
5717     insertValueInfo.SetInsertOffset(caretPosition_);
5718     if (!previewTextRecord_.newPreviewContent.empty()) {
5719         insertValueInfo.SetPreviewText(previewTextRecord_.newPreviewContent);
5720     } else {
5721         insertValueInfo.SetInsertValue(insertValue);
5722     }
5723     return eventHub->FireAboutToIMEInput(insertValueInfo);
5724 }
5725 
AfterInsertValue(const RefPtr<SpanNode> & spanNode,int32_t insertValueLength,bool isCreate,bool isIME)5726 void RichEditorPattern::AfterInsertValue(
5727     const RefPtr<SpanNode>& spanNode, int32_t insertValueLength, bool isCreate, bool isIME)
5728 {
5729     isTextChange_ = true;
5730     moveDirection_ = MoveDirection::FORWARD;
5731     moveLength_ += insertValueLength;
5732     IF_TRUE(!previewTextRecord_.needUpdateCaret, moveLength_ = 0);
5733     UpdateSpanPosition();
5734     if (isIME || aiWriteAdapter_->GetAIWrite()) {
5735         AfterIMEInsertValue(spanNode, insertValueLength, isCreate);
5736         return;
5737     }
5738     MoveCaretAfterTextChange();
5739 }
5740 
AfterIMEInsertValue(const RefPtr<SpanNode> & spanNode,int32_t insertValueLength,bool isCreate)5741 bool RichEditorPattern::AfterIMEInsertValue(const RefPtr<SpanNode>& spanNode, int32_t insertValueLength, bool isCreate)
5742 {
5743     ACE_SCOPED_TRACE("RichEditorAfterIMEInsertValue");
5744     auto host = GetHost();
5745     CHECK_NULL_RETURN(host, false);
5746     auto eventHub = GetEventHub<RichEditorEventHub>();
5747     CHECK_NULL_RETURN(eventHub, false);
5748 
5749     RichEditorAbstractSpanResult retInfo;
5750     retInfo.SetSpanIndex(host->GetChildIndex(spanNode));
5751     retInfo.SetEraseLength(insertValueLength);
5752     auto spanItem = spanNode->GetSpanItem();
5753     if (!previewTextRecord_.newPreviewContent.empty()) {
5754         retInfo.SetPreviewText(previewTextRecord_.newPreviewContent);
5755     } else {
5756         retInfo.SetValue(spanItem->content);
5757     }
5758     auto contentLength = static_cast<int32_t>(spanItem->content.length());
5759     retInfo.SetSpanRangeStart(spanItem->position - contentLength);
5760     retInfo.SetSpanRangeEnd(spanItem->position);
5761     retInfo.SetOffsetInSpan(caretPosition_ - retInfo.GetSpanRangeStart());
5762     retInfo.SetFontColor(spanNode->GetTextColorValue(Color::BLACK).ColorToString());
5763     retInfo.SetFontSize(spanNode->GetFontSizeValue(Dimension(DEFAULT_TEXT_SIZE, DimensionUnit::FP)).ConvertToVp());
5764     retInfo.SetFontStyle(spanNode->GetItalicFontStyleValue(OHOS::Ace::FontStyle::NORMAL));
5765     retInfo.SetFontWeight(static_cast<int32_t>(spanNode->GetFontWeightValue(FontWeight::NORMAL)));
5766     retInfo.SetTextStyle(GetTextStyleObject(spanNode));
5767     retInfo.SetUrlAddress(spanItem->urlAddress);
5768     std::string fontFamilyValue;
5769     auto fontFamily = spanNode->GetFontFamilyValue({ "HarmonyOS Sans" });
5770     for (const auto& str : fontFamily) {
5771         fontFamilyValue += str;
5772     }
5773     retInfo.SetFontFamily(fontFamilyValue);
5774     retInfo.SetTextDecoration(spanNode->GetTextDecorationValue(TextDecoration::NONE));
5775     retInfo.SetTextDecorationStyle(spanNode->GetTextDecorationStyleValue(TextDecorationStyle::SOLID));
5776     retInfo.SetFontFeature(spanNode->GetFontFeatureValue(ParseFontFeatureSettings("\"pnum\" 1")));
5777     retInfo.SetColor(spanNode->GetTextDecorationColorValue(Color::BLACK).ColorToString());
5778     TextRange onDidIMEInputRange{ caretPosition_, caretPosition_ + insertValueLength };
5779     MoveCaretAfterTextChange();
5780     eventHub->FireOnIMEInputComplete(retInfo);
5781     eventHub->FireOnDidIMEInput(onDidIMEInputRange);
5782     return true;
5783 }
5784 
DoDeleteActions(int32_t currentPosition,int32_t length,RichEditorDeleteValue & info)5785 bool RichEditorPattern::DoDeleteActions(int32_t currentPosition, int32_t length, RichEditorDeleteValue& info)
5786 {
5787     auto eventHub = GetEventHub<RichEditorEventHub>();
5788     CHECK_NULL_RETURN(eventHub, false);
5789     auto allowDelete = eventHub->FireAboutToDelete(info);
5790     info.ResetRichEditorDeleteSpans();
5791     CalcDeleteValueObj(currentPosition, length, info);
5792     bool doDelete = allowDelete || IsPreviewTextInputting();
5793     if (doDelete) {
5794         bool isSingleHandleMoving = selectOverlay_->IsSingleHandleMoving();
5795         CloseSelectOverlay();
5796         ResetSelection();
5797         DeleteByDeleteValueInfo(info);
5798         IF_TRUE((!caretVisible_ || isSingleHandleMoving) && HasFocus(), StartTwinkling());
5799         eventHub->FireOnDeleteComplete();
5800         UiSessionManager::GetInstance()->ReportComponentChangeEvent("event", "RichEditor.OnDeleteComplete");
5801     }
5802     return doDelete;
5803 }
5804 
IsEmojiOnCaretPosition(int32_t & emojiLength,bool isBackward,int32_t length)5805 std::pair<bool, bool> RichEditorPattern::IsEmojiOnCaretPosition(int32_t& emojiLength, bool isBackward, int32_t length)
5806 {
5807     bool isEmojiOnCaretBackward = false;
5808     bool isEmojiOnCaretForward = false;
5809     std::u16string u16;
5810     GetContentBySpans(u16);
5811     auto caretPos = std::clamp(caretPosition_, 0, static_cast<int32_t>(u16.length()));
5812     emojiLength = TextEmojiProcessor::Delete(caretPos, length, u16, isBackward);
5813     if (emojiLength > 0) {
5814         if (isBackward) {
5815             isEmojiOnCaretBackward = true;
5816         } else {
5817             isEmojiOnCaretForward = true;
5818         }
5819     }
5820     return std::make_pair(isEmojiOnCaretBackward, isEmojiOnCaretForward);
5821 }
5822 
HandleOnDelete(bool backward)5823 void RichEditorPattern::HandleOnDelete(bool backward)
5824 {
5825     if (backward) {
5826 #if defined(PREVIEW)
5827         DeleteForward(1);
5828 #else
5829         DeleteBackward(1);
5830 #endif
5831     } else {
5832 #if defined(PREVIEW)
5833         DeleteBackward(1);
5834 #else
5835         DeleteForward(1);
5836 #endif
5837     }
5838 }
5839 
CalculateDeleteLength(int32_t length,bool isBackward)5840 int32_t RichEditorPattern::CalculateDeleteLength(int32_t length, bool isBackward)
5841 {
5842     // handle selector
5843     if (!textSelector_.SelectNothing()) {
5844         lastCaretPosition_ = caretPosition_;
5845         caretPosition_ = isBackward ? textSelector_.GetTextEnd() : textSelector_.GetTextStart();
5846         return textSelector_.GetTextEnd() - textSelector_.GetTextStart();
5847     }
5848 
5849     // handle symbol, assume caret is not within symbol
5850     auto iter = std::find_if(spans_.begin(), spans_.end(), [index = caretPosition_, isBackward]
5851     (const RefPtr<SpanItem>& spanItem) {
5852         return isBackward
5853         ? (spanItem->rangeStart < index && index <= spanItem->position)
5854         : (spanItem->rangeStart <= index && index < spanItem->position);
5855     });
5856     CHECK_NULL_RETURN(iter == spans_.end() || !(*iter) || (*iter)->unicode == 0, SYMBOL_SPAN_LENGTH);
5857 
5858     // handle emoji
5859     int32_t emojiLength = 0;
5860     auto [isEmojiOnCaretBackward, isEmojiOnCaretForward] = IsEmojiOnCaretPosition(emojiLength, isBackward, length);
5861     if ((isBackward && isEmojiOnCaretBackward) || (!isBackward && isEmojiOnCaretForward)) {
5862         return emojiLength;
5863     }
5864 
5865     return length;
5866 }
5867 
DeleteBackward(int32_t oriLength)5868 void RichEditorPattern::DeleteBackward(int32_t oriLength)
5869 {
5870     int32_t length = isAPI14Plus ? std::clamp(oriLength, 0, caretPosition_) : oriLength;
5871     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "oriLength=%{public}d, length=%{public}d, isDragging=%{public}d",
5872         oriLength, length, IsDragging());
5873     CHECK_NULL_VOID(!IsDragging());
5874     if (isSpanStringMode_) {
5875         DeleteBackwardInStyledString(length);
5876         return;
5877     }
5878     if (IsPreviewTextInputting()) {
5879         TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "do not handle DeleteBackward on previewTextInputting");
5880         return;
5881     }
5882     OperationRecord record;
5883     record.beforeCaretPosition = caretPosition_;
5884     RichEditorChangeValue changeValue;
5885     CHECK_NULL_VOID(BeforeChangeText(changeValue, record, RecordType::DEL_BACKWARD, length));
5886     std::u16string deleteText = DeleteBackwardOperation(length);
5887     if (deleteText.length() != 0) {
5888         ClearRedoOperationRecords();
5889         record.deleteText = deleteText;
5890         record.afterCaretPosition = caretPosition_;
5891         AddOperationRecord(record);
5892         AfterContentChange(changeValue);
5893     }
5894 }
5895 
DeleteBackwardOperation(int32_t length)5896 std::u16string RichEditorPattern::DeleteBackwardOperation(int32_t length)
5897 {
5898     length = CalculateDeleteLength(length, true);
5899     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "delete length=%{public}d", length);
5900     std::u16string textContent;
5901     GetContentBySpans(textContent);
5902 
5903     if (static_cast<int32_t>(textContent.length()) != GetTextContentLength()) {
5904         TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "textContent length mismatch, %{public}d vs. %{public}d",
5905             static_cast<int32_t>(textContent.length()), GetTextContentLength());
5906     }
5907     auto start = std::clamp(caretPosition_ - length, 0, static_cast<int32_t>(textContent.length()));
5908     std::u16string deleteText =
5909         textContent.substr(static_cast<uint32_t>(start), static_cast<uint32_t>(caretPosition_ - start));
5910     RichEditorDeleteValue info;
5911     info.SetRichEditorDeleteDirection(RichEditorDeleteDirection::BACKWARD);
5912     if (caretPosition_ == 0) {
5913         info.SetLength(0);
5914         DoDeleteActions(0, 0, info);
5915         return deleteText;
5916     }
5917     info.SetOffset(caretPosition_ - length);
5918     info.SetLength(length);
5919     int32_t currentPosition = std::clamp((caretPosition_ - length), 0, static_cast<int32_t>(GetTextContentLength()));
5920     if (!spans_.empty()) {
5921         CalcDeleteValueObj(currentPosition, length, info);
5922         bool doDelete = DoDeleteActions(currentPosition, length, info);
5923         if (!doDelete) {
5924             return u"";
5925         }
5926     }
5927     auto host = GetHost();
5928     if (host && host->GetChildren().empty()) {
5929         textForDisplay_.clear();
5930     }
5931     RequestKeyboardToEdit();
5932     return deleteText;
5933 }
5934 
DeleteForward(int32_t oriLength)5935 void RichEditorPattern::DeleteForward(int32_t oriLength)
5936 {
5937     int32_t length = isAPI14Plus ? std::clamp(oriLength, 0, GetTextContentLength() - caretPosition_) : oriLength;
5938     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "oriLength=%{public}d, length=%{public}d, isDragging=%{public}d",
5939         oriLength, length, IsDragging());
5940     CHECK_NULL_VOID(!IsDragging());
5941     if (isSpanStringMode_) {
5942         DeleteForwardInStyledString(length);
5943         return;
5944     }
5945     if (IsPreviewTextInputting()) {
5946         TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "do not handle DeleteForward in previewTextInputting");
5947         return;
5948     }
5949     OperationRecord record;
5950     record.beforeCaretPosition = caretPosition_;
5951     RichEditorChangeValue changeValue;
5952     CHECK_NULL_VOID(BeforeChangeText(changeValue, record, RecordType::DEL_FORWARD, length));
5953     std::u16string deleteText = DeleteForwardOperation(length);
5954     if (deleteText.length() != 0) {
5955         ClearRedoOperationRecords();
5956         record.deleteText = deleteText;
5957         record.afterCaretPosition = caretPosition_;
5958         AddOperationRecord(record);
5959         AfterContentChange(changeValue);
5960     }
5961 }
5962 
DeleteForwardOperation(int32_t length)5963 std::u16string RichEditorPattern::DeleteForwardOperation(int32_t length)
5964 {
5965     length = CalculateDeleteLength(length, false);
5966     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "delete length=%{public}d", length);
5967     std::u16string textContent;
5968     GetContentBySpans(textContent);
5969     if (static_cast<int32_t>(textContent.length()) != GetTextContentLength()) {
5970         TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "textContent length mismatch, %{public}d vs. %{public}d",
5971             static_cast<int32_t>(textContent.length()), GetTextContentLength());
5972     }
5973     auto end = std::clamp(caretPosition_ + length, 0, static_cast<int32_t>(textContent.length()));
5974     std::u16string deleteText = textContent.substr(
5975         static_cast<uint32_t>(std::clamp(caretPosition_, 0, static_cast<int32_t>(textContent.length()))),
5976         static_cast<uint32_t>(end - caretPosition_));
5977     RichEditorDeleteValue info;
5978     info.SetOffset(caretPosition_);
5979     info.SetRichEditorDeleteDirection(RichEditorDeleteDirection::FORWARD);
5980     int32_t currentPosition = caretPosition_;
5981     if (currentPosition == GetTextContentLength()) {
5982         info.SetLength(0);
5983         DoDeleteActions(currentPosition, 0, info);
5984         return deleteText;
5985     }
5986     info.SetLength(length);
5987     if (!spans_.empty()) {
5988         CalcDeleteValueObj(currentPosition, length, info);
5989         bool doDelete = DoDeleteActions(currentPosition, length, info);
5990         if (!doDelete) {
5991             return u"";
5992         }
5993     }
5994     return deleteText;
5995 }
5996 
DeleteContent(int32_t length)5997 void RichEditorPattern::DeleteContent(int32_t length)
5998 {
5999     length = CalculateDeleteLength(length, true);
6000     std::u16string textContent;
6001     GetContentBySpans(textContent);
6002 
6003     auto start = std::clamp(GetTextContentLength() - length, 0, static_cast<int32_t>(textContent.length()));
6004     std::u16string deleteText =
6005         textContent.substr(static_cast<uint32_t>(start), static_cast<uint32_t>(GetTextContentLength() - start));
6006     RichEditorDeleteValue info;
6007     info.SetRichEditorDeleteDirection(RichEditorDeleteDirection::BACKWARD);
6008     if (GetTextContentLength() == 0) {
6009         info.SetLength(0);
6010         DoDeleteActions(0, 0, info);
6011         return;
6012     }
6013     info.SetOffset(GetTextContentLength() - length);
6014     info.SetLength(length);
6015     int32_t currentPosition = std::clamp((GetTextContentLength() - length), 0, static_cast<int32_t>(GetTextContentLength()));
6016     if (!spans_.empty()) {
6017         CalcDeleteValueObj(currentPosition, length, info);
6018         bool doDelete = DoDeleteActions(currentPosition, length, info);
6019         if (!doDelete) {
6020             return;
6021         }
6022     }
6023     auto host = GetHost();
6024     if (host && host->GetChildren().empty()) {
6025         textForDisplay_.clear();
6026     }
6027     RequestKeyboardToEdit();
6028 }
6029 
DeleteToMaxLength(std::optional<int32_t> length)6030 void RichEditorPattern::DeleteToMaxLength(std::optional<int32_t> length)
6031 {
6032     if (length.value_or(INT_MAX) >= GetTextContentLength()) {
6033         return;
6034     }
6035     int32_t textContentLength = GetTextContentLength();
6036     if (isSpanStringMode_) {
6037         DeleteValueInStyledString(length.value_or(INT_MAX), GetTextContentLength() - length.value_or(INT_MAX));
6038     } else {
6039         while (textContentLength > length.value_or(INT_MAX)) {
6040             textContentLength -= CalculateDeleteLength(CUSTOM_CONTENT_LENGTH, true);
6041             DeleteContent(CUSTOM_CONTENT_LENGTH);
6042         }
6043     }
6044 }
6045 
OnBackPressed()6046 bool RichEditorPattern::OnBackPressed()
6047 {
6048     auto tmpHost = GetHost();
6049     CHECK_NULL_RETURN(tmpHost, false);
6050     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "RichEditor %{public}d receives back press event, isStopBackPress=%{public}d",
6051         tmpHost->GetId(), isStopBackPress_);
6052     if (SelectOverlayIsOn()) {
6053         CloseSelectOverlay();
6054         textSelector_.Update(textSelector_.destinationOffset);
6055         StartTwinkling();
6056         return isStopBackPress_;
6057     }
6058 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
6059     if (!imeShown_ && !isCustomKeyboardAttached_) {
6060 #else
6061     if (!isCustomKeyboardAttached_) {
6062 #endif
6063         return false;
6064     }
6065     tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
6066     ResetSelection();
6067     CloseKeyboard(false);
6068     FocusHub::LostFocusToViewRoot();
6069 #if defined(ANDROID_PLATFORM)
6070     return false;
6071 #else
6072     return isStopBackPress_;
6073 #endif
6074 }
6075 
6076 void RichEditorPattern::SetInputMethodStatus(bool keyboardShown)
6077 {
6078 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
6079     imeShown_ = keyboardShown;
6080 #endif
6081 }
6082 
6083 bool RichEditorPattern::BeforeStatusCursorMove(bool isLeft)
6084 {
6085     CHECK_NULL_RETURN(textSelector_.IsValid(), true);
6086     CHECK_NULL_RETURN(!selectOverlay_->IsSingleHandleShow(), true);
6087     SetCaretPosition(isLeft ? textSelector_.GetTextStart() : textSelector_.GetTextEnd());
6088     MoveCaretToContentRect();
6089     StartTwinkling();
6090     CloseSelectOverlay();
6091     ResetSelection();
6092     return false;
6093 }
6094 
6095 bool RichEditorPattern::CursorMoveLeft()
6096 {
6097     CHECK_NULL_RETURN(BeforeStatusCursorMove(true), false);
6098     CloseSelectOverlay();
6099     ResetSelection();
6100     int32_t emojiLength = 0;
6101     int32_t caretPosition = caretPosition_;
6102     constexpr int32_t DELETE_COUNT = 1;
6103     auto [isEmojiOnCaretBackward, isEmojiOnCaretForward] = IsEmojiOnCaretPosition(emojiLength, true, DELETE_COUNT);
6104     if (isEmojiOnCaretBackward) {
6105         caretPosition = std::clamp((caretPosition_ - emojiLength), 0, static_cast<int32_t>(GetTextContentLength()));
6106     } else {
6107         caretPosition = std::clamp((caretPosition_ - 1), 0, static_cast<int32_t>(GetTextContentLength()));
6108     }
6109     AdjustSelectorForSymbol(caretPosition, HandleType::SECOND, SelectorAdjustPolicy::EXCLUDE);
6110     if (caretPosition_ == caretPosition) {
6111         return false;
6112     }
6113     SetCaretPosition(caretPosition);
6114     MoveCaretToContentRect();
6115     StartTwinkling();
6116     auto host = GetHost();
6117     CHECK_NULL_RETURN(host, false);
6118     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
6119     return true;
6120 }
6121 
6122 bool RichEditorPattern::CursorMoveRight()
6123 {
6124     CHECK_NULL_RETURN(BeforeStatusCursorMove(false), false);
6125     CloseSelectOverlay();
6126     ResetSelection();
6127     int32_t emojiLength = 0;
6128     int32_t caretPosition = caretPosition_;
6129     constexpr int32_t DELETE_COUNT = 1;
6130     auto [isEmojiOnCaretBackward, isEmojiOnCaretForward] = IsEmojiOnCaretPosition(emojiLength, false, DELETE_COUNT);
6131     if (isEmojiOnCaretForward) {
6132         caretPosition = std::clamp((caretPosition_ + emojiLength), 0, static_cast<int32_t>(GetTextContentLength()));
6133     } else {
6134         caretPosition = std::clamp((caretPosition_ + 1), 0, static_cast<int32_t>(GetTextContentLength()));
6135     }
6136     AdjustSelectorForSymbol(caretPosition, HandleType::SECOND, SelectorAdjustPolicy::INCLUDE);
6137     if (caretPosition_ == caretPosition) {
6138         return false;
6139     }
6140     SetCaretPosition(caretPosition);
6141     MoveCaretToContentRect();
6142     StartTwinkling();
6143     auto host = GetHost();
6144     CHECK_NULL_RETURN(host, false);
6145     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
6146     return true;
6147 }
6148 
6149 bool RichEditorPattern::CursorMoveUp()
6150 {
6151     CloseSelectOverlay();
6152     ResetSelection();
6153     float caretHeight = 0.0f;
6154     float leadingMarginOffset = 0.0f;
6155     CaretOffsetInfo caretInfo;
6156     if (static_cast<int32_t>(GetTextContentLength()) > 1) {
6157         caretInfo = GetCaretOffsetInfoByPosition();
6158         int32_t caretPosition = CalcMoveUpPos(leadingMarginOffset);
6159         CHECK_NULL_RETURN(overlayMod_, false);
6160         auto overlayMod = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
6161         auto currentCaretOffsetOverlay = overlayMod->GetCaretOffset();
6162         auto caretOffsetWidth = overlayMod->GetCaretWidth();
6163         auto rectLineInfo = CalcLineInfoByPosition();
6164         caretPosition = std::clamp(caretPosition, 0, static_cast<int32_t>(GetTextContentLength()));
6165         if (caretPosition_ == caretPosition) {
6166             caretPosition = 0;
6167         }
6168         // at line middle or line end
6169         bool cursorNotAtLineStart =
6170             NearEqual(currentCaretOffsetOverlay.GetX(), caretInfo.caretOffsetUp.GetX(), caretOffsetWidth);
6171         bool isEnter = NearZero(currentCaretOffsetOverlay.GetX() - richTextRect_.GetX(), rectLineInfo.GetX());
6172         SetCaretPosition(caretPosition);
6173         MoveCaretToContentRect();
6174         if (cursorNotAtLineStart && !isEnter) {
6175             OffsetF caretOffset = CalcCursorOffsetByPosition(caretPosition_, caretHeight, false, false);
6176             SetLastClickOffset(caretOffset);
6177             caretAffinityPolicy_ = CaretAffinityPolicy::UPSTREAM_FIRST;
6178         }
6179     }
6180     StartTwinkling();
6181     auto host = GetHost();
6182     CHECK_NULL_RETURN(host, false);
6183     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
6184     return true;
6185 }
6186 
6187 bool RichEditorPattern::CursorMoveDown()
6188 {
6189     CloseSelectOverlay();
6190     ResetSelection();
6191     if (static_cast<int32_t>(GetTextContentLength()) > 1) {
6192         float caretHeight = 0.0f;
6193         float leadingMarginOffset = 0.0f;
6194         float caretHeightEnd = 0.0f;
6195         CaretOffsetInfo caretInfo;
6196         int32_t caretPositionEnd;
6197         caretInfo = GetCaretOffsetInfoByPosition();
6198         caretPositionEnd = CalcMoveDownPos(leadingMarginOffset);
6199         CHECK_NULL_RETURN(overlayMod_, false);
6200         auto overlayMod = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
6201         auto caretOffsetOverlay = overlayMod->GetCaretOffset();
6202         auto caretOffsetWidth = overlayMod->GetCaretWidth();
6203         bool cursorNotAtLineStart =
6204             NearEqual(caretOffsetOverlay.GetX(), caretInfo.caretOffsetUp.GetX(), caretOffsetWidth);
6205         bool isEnter = NearZero(caretInfo.caretOffsetUp.GetX() - richTextRect_.GetX(), leadingMarginOffset);
6206         caretPositionEnd = std::clamp(caretPositionEnd, 0, static_cast<int32_t>(GetTextContentLength()));
6207         auto currentLineInfo = CalcLineInfoByPosition();
6208         if (caretPositionEnd <= caretPosition_) {
6209             OffsetF caretOffsetEnd = CalcCursorOffsetByPosition(GetTextContentLength(), caretHeightEnd);
6210             if (NearEqual(caretOffsetEnd.GetY() - GetTextRect().GetY(), currentLineInfo.GetY(), 0.5f)) {
6211                 caretPositionEnd = GetTextContentLength();
6212             } else {
6213                 caretPositionEnd += 1;
6214             }
6215         }
6216         SetCaretPosition(caretPositionEnd);
6217         if (cursorNotAtLineStart && caretPosition_ != 0 && !isEnter) {
6218             OffsetF caretOffset = CalcCursorOffsetByPosition(caretPosition_, caretHeight, false, false);
6219             SetLastClickOffset(caretOffset);
6220             caretAffinityPolicy_ = CaretAffinityPolicy::UPSTREAM_FIRST;
6221         }
6222         MoveCaretToContentRect();
6223     }
6224     StartTwinkling();
6225     auto host = GetHost();
6226     CHECK_NULL_RETURN(host, false);
6227     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
6228     return true;
6229 }
6230 
6231 void RichEditorPattern::CursorMoveToNextWord(CaretMoveIntent direction)
6232 {
6233     CHECK_NULL_VOID(direction == CaretMoveIntent::LeftWord || direction == CaretMoveIntent::RightWord);
6234     bool isDirectionLeft = direction == CaretMoveIntent::LeftWord;
6235     auto index = caretPosition_;
6236     if (!textSelector_.SelectNothing()) {
6237         index = isDirectionLeft ? textSelector_.GetTextStart() + 1 : textSelector_.GetTextEnd() - 1;
6238     }
6239     auto newPos = isDirectionLeft ? GetLeftWordIndex(index) : GetRightWordIndex(index);
6240     CloseSelectOverlay();
6241     ResetSelection();
6242     SetCaretPosition(newPos);
6243     MoveCaretToContentRect();
6244     IF_TRUE(isEditing_, StartTwinkling());
6245     auto host = GetHost();
6246     CHECK_NULL_VOID(host);
6247     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
6248 }
6249 
6250 int32_t RichEditorPattern::GetLeftWordIndex(int32_t index)
6251 {
6252     AdjustIndexSkipSpace(index, MoveDirection::BACKWARD);
6253     int32_t newPos = std::max(0, index - 1);
6254     AdjustSelectorForSymbol(newPos, HandleType::FIRST, SelectorAdjustPolicy::INCLUDE);
6255     AdjustWordSelection(newPos, index);
6256     AdjustSelector(newPos, HandleType::FIRST);
6257     return newPos;
6258 }
6259 
6260 int32_t RichEditorPattern::GetRightWordIndex(int32_t index)
6261 {
6262     int32_t newPos = std::min(index + 1, GetTextContentLength());
6263     AdjustWordSelection(index, newPos);
6264     AdjustSelector(newPos, HandleType::SECOND);
6265     AdjustIndexSkipSpace(newPos, MoveDirection::FORWARD);
6266     return newPos;
6267 }
6268 
6269 bool RichEditorPattern::CursorMoveToParagraphBegin()
6270 {
6271     CloseSelectOverlay();
6272     ResetSelection();
6273     auto newPos = GetParagraphBeginPosition(caretPosition_);
6274     if (newPos == caretPosition_ && caretPosition_ > 0) {
6275         newPos = GetParagraphBeginPosition(caretPosition_ - 1);
6276     }
6277     if (newPos == caretPosition_) {
6278         return false;
6279     }
6280     SetCaretPosition(newPos);
6281     MoveCaretToContentRect();
6282     StartTwinkling();
6283     auto host = GetHost();
6284     CHECK_NULL_RETURN(host, false);
6285     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
6286     return true;
6287 }
6288 
6289 bool RichEditorPattern::CursorMoveToParagraphEnd()
6290 {
6291     CloseSelectOverlay();
6292     ResetSelection();
6293     auto newPos = GetParagraphEndPosition(caretPosition_);
6294     if (newPos == caretPosition_ && caretPosition_ < static_cast<int32_t>(GetTextContentLength())) {
6295         newPos = GetParagraphEndPosition(caretPosition_ + 1);
6296     }
6297     if (newPos == caretPosition_) {
6298         return false;
6299     }
6300     SetCaretPosition(newPos);
6301     MoveCaretToContentRect();
6302     StartTwinkling();
6303     auto host = GetHost();
6304     CHECK_NULL_RETURN(host, false);
6305     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
6306     return true;
6307 }
6308 
6309 bool RichEditorPattern::CursorMoveHome()
6310 {
6311     CloseSelectOverlay();
6312     ResetSelection();
6313     if (0 == caretPosition_) {
6314         return false;
6315     }
6316     SetCaretPosition(0);
6317     MoveCaretToContentRect();
6318     StartTwinkling();
6319     auto host = GetHost();
6320     CHECK_NULL_RETURN(host, false);
6321     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
6322     return true;
6323 }
6324 
6325 bool RichEditorPattern::CursorMoveEnd()
6326 {
6327     int32_t currentPositionIndex = 0;
6328     if (textSelector_.SelectNothing()) {
6329         currentPositionIndex = caretPosition_;
6330     } else {
6331         currentPositionIndex = textSelector_.GetTextEnd();
6332     }
6333     CloseSelectOverlay();
6334     ResetSelection();
6335     auto newPos = GetTextContentLength();
6336     if (newPos == currentPositionIndex) {
6337         StartTwinkling();
6338         return false;
6339     }
6340     SetCaretPosition(newPos);
6341     MoveCaretToContentRect();
6342     StartTwinkling();
6343     auto host = GetHost();
6344     CHECK_NULL_RETURN(host, false);
6345     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
6346     return true;
6347 }
6348 
6349 int32_t RichEditorPattern::GetLeftWordPosition(int32_t caretPosition)
6350 {
6351     int32_t offset = 0;
6352     bool jumpSpace = true;
6353     for (auto iter = spans_.rbegin(); iter != spans_.rend(); iter++) {
6354         auto span = *iter;
6355         auto content = span->content;
6356         if (caretPosition <= span->position - static_cast<int32_t>(content.length())) {
6357             continue;
6358         }
6359         int32_t position = span->position;
6360         for (auto iterContent = content.rbegin(); iterContent != content.rend(); iterContent++) {
6361             if (position-- > caretPosition) {
6362                 continue;
6363             }
6364             if (*iterContent != u' ' || span->placeholderIndex >= 0) {
6365                 jumpSpace = false;
6366             }
6367             if (position + 1 == caretPosition) {
6368                 if (!(StringUtils::IsLetterOrNumberForWchar(*iterContent) ||
6369                         (*iterContent == u' ' && span->placeholderIndex < 0))) {
6370                     return std::clamp(caretPosition - 1, 0, static_cast<int32_t>(GetTextContentLength()));
6371                 }
6372             }
6373             if (!jumpSpace) {
6374                 if (!StringUtils::IsLetterOrNumberForWchar(*iterContent)) {
6375                     return std::clamp(caretPosition - offset, 0, static_cast<int32_t>(GetTextContentLength()));
6376                 }
6377             } else {
6378                 if (*iterContent == u' ' && span->placeholderIndex >= 0) {
6379                     return std::clamp(caretPosition - offset, 0, static_cast<int32_t>(GetTextContentLength()));
6380                 }
6381             }
6382             offset++;
6383         }
6384     }
6385     return std::clamp(caretPosition - offset, 0, static_cast<int32_t>(GetTextContentLength()));
6386 }
6387 
6388 int32_t RichEditorPattern::GetRightWordPosition(int32_t caretPosition)
6389 {
6390     int32_t offset = 0;
6391     bool jumpSpace = false;
6392     for (auto iter = spans_.cbegin(); iter != spans_.cend(); iter++) {
6393         auto span = *iter;
6394         auto content = span->content;
6395         if (caretPosition > span->position) {
6396             continue;
6397         }
6398         int32_t position = span->position - static_cast<int32_t>(content.length());
6399         for (auto iterContent = content.cbegin(); iterContent != content.cend(); iterContent++) {
6400             if (position++ < caretPosition) {
6401                 continue;
6402             }
6403             if (*iterContent == u' ' && span->placeholderIndex < 0) {
6404                 jumpSpace = true;
6405                 offset++;
6406                 continue;
6407             }
6408             if (position - 1 == caretPosition) {
6409                 if (!StringUtils::IsLetterOrNumberForWchar(*iterContent)) {
6410                     return std::clamp(caretPosition + 1, 0, static_cast<int32_t>(GetTextContentLength()));
6411                 }
6412             }
6413             if (jumpSpace) {
6414                 if (*iterContent != u' ' || span->placeholderIndex >= 0) {
6415                     return std::clamp(caretPosition + offset, 0, static_cast<int32_t>(GetTextContentLength()));
6416                 }
6417             } else {
6418                 if (!(StringUtils::IsLetterOrNumberForWchar(*iterContent) ||
6419                         (*iterContent == u' ' && span->placeholderIndex < 0))) {
6420                     return std::clamp(caretPosition + offset, 0, static_cast<int32_t>(GetTextContentLength()));
6421                 }
6422             }
6423             offset++;
6424         }
6425     }
6426     return std::clamp(caretPosition + offset, 0, static_cast<int32_t>(GetTextContentLength()));
6427 }
6428 
6429 int32_t RichEditorPattern::GetParagraphBeginPosition(int32_t caretPosition)
6430 {
6431     int32_t offset = 0;
6432     for (auto iter = spans_.rbegin(); iter != spans_.rend(); iter++) {
6433         auto span = *iter;
6434         auto content = span->content;
6435         if (caretPosition <= span->position - static_cast<int32_t>(content.length())) {
6436             continue;
6437         }
6438         int32_t position = span->position;
6439         for (auto iterContent = content.rbegin(); iterContent != content.rend(); iterContent++) {
6440             if (position-- > caretPosition) {
6441                 continue;
6442             }
6443             if (*iterContent == u'\n') {
6444                 return std::clamp(caretPosition - offset, 0, static_cast<int32_t>(GetTextContentLength()));
6445             }
6446             offset++;
6447         }
6448     }
6449     return std::clamp(caretPosition - offset, 0, static_cast<int32_t>(GetTextContentLength()));
6450 }
6451 
6452 int32_t RichEditorPattern::GetParagraphEndPosition(int32_t caretPosition)
6453 {
6454     int32_t offset = 0;
6455     for (auto iter = spans_.cbegin(); iter != spans_.cend(); iter++) {
6456         auto span = *iter;
6457         auto content = span->content;
6458         if (caretPosition > span->position) {
6459             continue;
6460         }
6461         int32_t position = span->position - static_cast<int32_t>(content.length());
6462         for (auto iterContent = content.cbegin(); iterContent != content.cend(); iterContent++) {
6463             if (position++ < caretPosition) {
6464                 continue;
6465             }
6466             if (*iterContent == u'\n') {
6467                 return std::clamp(caretPosition + offset, 0, static_cast<int32_t>(GetTextContentLength()));
6468             }
6469             offset++;
6470         }
6471     }
6472     return std::clamp(caretPosition + offset, 0, static_cast<int32_t>(GetTextContentLength()));
6473 }
6474 
6475 void RichEditorPattern::HandleOnSelectAll()
6476 {
6477     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "HandleOnSelectAll IsPreviewTextInputting:%{public}d", IsPreviewTextInputting());
6478     CHECK_NULL_VOID(!IsPreviewTextInputting());
6479     CloseSelectOverlay();
6480     auto host = GetHost();
6481     CHECK_NULL_VOID(host);
6482     textResponseType_.reset();
6483     int32_t newPos = static_cast<int32_t>(GetTextContentLength());
6484     textSelector_.Update(0, newPos);
6485     FireOnSelect(textSelector_.GetTextStart(), textSelector_.GetTextEnd());
6486     SetCaretPosition(newPos);
6487     MoveCaretToContentRect();
6488     IF_TRUE(IsSelected(), StopTwinkling());
6489     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
6490 }
6491 
6492 int32_t RichEditorPattern::CaretPositionSelectEmoji(CaretMoveIntent direction)
6493 {
6494     int32_t newPos = caretPosition_;
6495     int32_t emojiLength = 0;
6496     constexpr int32_t DELETE_COUNT = 1;
6497     if (direction == CaretMoveIntent::Left) {
6498         auto [isEmojiOnCaretBackward, isEmojiOnCaretForward] = IsEmojiOnCaretPosition(emojiLength, true, DELETE_COUNT);
6499         if (isEmojiOnCaretBackward) {
6500             newPos = caretPosition_ - emojiLength;
6501         } else {
6502             newPos = caretPosition_ - 1;
6503         }
6504         AdjustSelectorForSymbol(newPos, HandleType::FIRST, SelectorAdjustPolicy::INCLUDE);
6505         return newPos;
6506     }
6507     auto [isEmojiOnCaretBackward, isEmojiOnCaretForward] = IsEmojiOnCaretPosition(emojiLength, false, DELETE_COUNT);
6508     if (direction == CaretMoveIntent::Right) {
6509         if (isEmojiOnCaretForward) {
6510             newPos = caretPosition_ + emojiLength;
6511         } else {
6512             newPos = caretPosition_ + 1;
6513         }
6514         AdjustSelectorForSymbol(newPos, HandleType::SECOND, SelectorAdjustPolicy::INCLUDE);
6515     }
6516     return newPos;
6517 }
6518 
6519 void RichEditorPattern::HandleSelect(CaretMoveIntent direction)
6520 {
6521     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "direction=%{public}d", direction);
6522     CloseSelectOverlay();
6523     auto host = GetHost();
6524     CHECK_NULL_VOID(host);
6525     int32_t newPos, fixedPos = caretPosition_;
6526     if (IsSelected()) {
6527         fixedPos = (caretPosition_ == textSelector_.GetTextStart() ? textSelector_.GetTextEnd()
6528                                                                    : textSelector_.GetTextStart());
6529     }
6530     newPos = HandleSelectWrapper(direction, fixedPos);
6531     if (newPos == -1) {
6532         return;
6533     }
6534     newPos = std::clamp(newPos, 0, static_cast<int32_t>(GetTextContentLength()));
6535     if (newPos == caretPosition_) {
6536         return;
6537     }
6538     UpdateSelector(fixedPos, newPos);
6539     FireOnSelect(textSelector_.GetTextStart(), textSelector_.GetTextEnd());
6540     SetCaretPosition(newPos);
6541     MoveCaretToContentRect();
6542     if (textSelector_.SelectNothing()) {
6543         StartTwinkling();
6544     } else {
6545         StopTwinkling();
6546     }
6547     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
6548 }
6549 
6550 void RichEditorPattern::ClearOperationRecords()
6551 {
6552     ClearRedoOperationRecords();
6553     if (operationRecords_.empty()) {
6554         return;
6555     }
6556     operationRecords_.clear();
6557 }
6558 
6559 void RichEditorPattern::ClearRedoOperationRecords()
6560 {
6561     if (redoOperationRecords_.empty()) {
6562         return;
6563     }
6564     redoOperationRecords_.clear();
6565 }
6566 
6567 void RichEditorPattern::AddOperationRecord(const OperationRecord& record)
6568 {
6569     if (operationRecords_.size() >= RECORD_MAX_LENGTH) {
6570         // case of max length is 0
6571         if (operationRecords_.empty()) {
6572             return;
6573         }
6574         operationRecords_.erase(operationRecords_.begin());
6575     }
6576     operationRecords_.emplace_back(record);
6577 }
6578 
6579 void RichEditorPattern::UpdateShiftFlag(const KeyEvent& keyEvent)
6580 {
6581     bool hasKeyShift = keyEvent.HasKey(KeyCode::KEY_SHIFT_LEFT) || keyEvent.HasKey(KeyCode::KEY_SHIFT_RIGHT);
6582     auto action = keyEvent.action;
6583     bool isShiftPressed = hasKeyShift && (action == KeyAction::DOWN || action == KeyAction::UP);
6584     if (isShiftPressed != shiftFlag_) {
6585         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "UpdateShiftFlag:%{public}d by action:%{public}d", isShiftPressed, action);
6586         shiftFlag_ = isShiftPressed;
6587     }
6588 }
6589 
6590 bool RichEditorPattern::HandleOnEscape()
6591 {
6592     CloseSelectOverlay();
6593     return false;
6594 }
6595 
6596 void RichEditorPattern::HandleOnUndoAction()
6597 {
6598     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "HandleOnUndoAction");
6599     if (operationRecords_.empty()) {
6600         return;
6601     }
6602     auto value = operationRecords_.back();
6603     RichEditorChangeValue changeValue;
6604     CHECK_NULL_VOID(BeforeChangeText(changeValue, value, RecordType::UNDO));
6605     operationRecords_.pop_back();
6606     if (redoOperationRecords_.size() >= RECORD_MAX_LENGTH && !(redoOperationRecords_.empty())) {
6607         redoOperationRecords_.erase(redoOperationRecords_.begin());
6608     }
6609     redoOperationRecords_.push_back(value);
6610     CloseSelectOverlay();
6611     ResetSelection();
6612     if (value.addText.has_value() && value.deleteCaretPostion != -1) {
6613         UndoDrag(value);
6614         AfterContentChange(changeValue);
6615         return;
6616     }
6617     if (value.addText.has_value() && value.deleteText.has_value()) {
6618         SetCaretPosition(value.afterCaretPosition);
6619         DeleteBackwardOperation(TextEmojiProcessor::GetCharacterNum(value.addText.value_or(u"")));
6620         InsertValueOperation(value.deleteText.value_or(u""));
6621         AfterContentChange(changeValue);
6622         return;
6623     }
6624     if (value.addText.has_value()) {
6625         SetCaretPosition(value.afterCaretPosition);
6626         DeleteBackwardOperation(TextEmojiProcessor::GetCharacterNum(value.addText.value_or(u"")));
6627     }
6628     if (value.deleteText.has_value()) {
6629         SetCaretPosition(value.afterCaretPosition);
6630         InsertValueOperation(value.deleteText.value_or(u""));
6631     }
6632     AfterContentChange(changeValue);
6633 }
6634 
6635 void RichEditorPattern::HandleOnRedoAction()
6636 {
6637     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "HandleOnRedoAction");
6638     if (redoOperationRecords_.empty()) {
6639         return;
6640     }
6641     auto value = redoOperationRecords_.back();
6642     RichEditorChangeValue changeValue;
6643     CHECK_NULL_VOID(BeforeChangeText(changeValue, value, RecordType::REDO));
6644     redoOperationRecords_.pop_back();
6645     if (value.addText.has_value() && value.deleteCaretPostion != -1) {
6646         RedoDrag(value);
6647         AfterContentChange(changeValue);
6648         return;
6649     }
6650     if (value.addText.has_value() && value.deleteText.has_value()) {
6651         SetCaretPosition(value.beforeCaretPosition);
6652         DeleteForwardOperation(value.deleteText.value_or(u"").length());
6653         InsertValueOperation(value.addText.value_or(u""));
6654         operationRecords_.push_back(value);
6655         AfterContentChange(changeValue);
6656         return;
6657     }
6658     if (value.deleteText.has_value()) {
6659         SetCaretPosition(value.beforeCaretPosition);
6660         if (value.beforeCaretPosition != value.afterCaretPosition) {
6661             DeleteBackwardOperation(value.deleteText.value_or(u"").length());
6662         } else {
6663             DeleteForwardOperation(value.deleteText.value_or(u"").length());
6664         }
6665     }
6666     if (value.addText.has_value()) {
6667         SetCaretPosition(value.beforeCaretPosition);
6668         InsertValueOperation(value.addText.value_or(u""));
6669     }
6670     operationRecords_.push_back(value);
6671     AfterContentChange(changeValue);
6672 }
6673 
6674 void RichEditorPattern::CalcInsertValueObj(TextInsertValueInfo& info)
6675 {
6676     if (spans_.empty()) {
6677         info.SetSpanIndex(0);
6678         info.SetOffsetInSpan(0);
6679         return;
6680     }
6681     auto it = std::find_if(
6682         spans_.begin(), spans_.end(), [caretPosition = caretPosition_ + moveLength_](const RefPtr<SpanItem>& spanItem) {
6683             if (spanItem->content.empty()) {
6684                 return spanItem->position == caretPosition;
6685             }
6686             return spanItem->rangeStart <= caretPosition && caretPosition < spanItem->position;
6687         });
6688     if (it != spans_.end() && (*it)->unicode != 0 && (*it)->position - caretPosition_ + moveLength_ == 1) {
6689         it++;
6690         moveLength_++;
6691     }
6692     info.SetSpanIndex(std::distance(spans_.begin(), it));
6693     if (it == spans_.end()) {
6694         info.SetOffsetInSpan(0);
6695         return;
6696     }
6697     info.SetOffsetInSpan(
6698         caretPosition_ + moveLength_ - ((*it)->position - (*it)->content.length()));
6699 }
6700 
6701 void RichEditorPattern::CalcDeleteValueObj(int32_t currentPosition, int32_t length, RichEditorDeleteValue& info)
6702 {
6703     auto it =
6704         std::find_if(spans_.begin(), spans_.end(), [caretPosition = currentPosition](const RefPtr<SpanItem>& spanItem) {
6705             return (spanItem->position - static_cast<int32_t>(spanItem->content.length()) <= caretPosition) &&
6706                    (caretPosition < spanItem->position);
6707         });
6708     while (it != spans_.end() && length > 0) {
6709         if ((*it)->placeholderIndex >= 0 || (*it)->unicode != 0) {
6710             RichEditorAbstractSpanResult spanResult;
6711             spanResult.SetSpanIndex(std::distance(spans_.begin(), it));
6712             int32_t eraseLength = 0;
6713             if ((*it)->unicode != 0) {
6714                 eraseLength = DeleteValueSetSymbolSpan(*it, spanResult);
6715             } else if (AceType::InstanceOf<ImageSpanItem>(*it)) {
6716                 eraseLength = DeleteValueSetImageSpan(*it, spanResult);
6717             } else {
6718                 eraseLength = DeleteValueSetBuilderSpan(*it, spanResult);
6719             }
6720             currentPosition += eraseLength;
6721             length -= eraseLength;
6722             info.SetRichEditorDeleteSpans(spanResult);
6723         } else {
6724             RichEditorAbstractSpanResult spanResult;
6725             spanResult.SetSpanIndex(std::distance(spans_.begin(), it));
6726             auto eraseLength = DeleteValueSetTextSpan(*it, currentPosition, length, spanResult);
6727             length -= eraseLength;
6728             currentPosition += eraseLength;
6729             info.SetRichEditorDeleteSpans(spanResult);
6730         }
6731         std::advance(it, 1);
6732     }
6733 }
6734 
6735 RefPtr<SpanNode> RichEditorPattern::GetSpanNodeBySpanItem(const RefPtr<SpanItem> spanItem)
6736 {
6737     RefPtr<SpanNode> spanNode;
6738     auto iter = std::find(spans_.begin(), spans_.end(), spanItem);
6739     if (iter == spans_.end()) {
6740         return spanNode;
6741     }
6742     auto spanIndex = std::distance(spans_.begin(), iter);
6743     auto host = GetHost();
6744     CHECK_NULL_RETURN(host, spanNode);
6745     auto it = host->GetChildren().begin();
6746     std::advance(it, spanIndex);
6747     spanNode = AceType::DynamicCast<SpanNode>(*it);
6748     return spanNode;
6749 }
6750 
6751 int32_t RichEditorPattern::DeleteValueSetSymbolSpan(
6752     const RefPtr<SpanItem>& spanItem, RichEditorAbstractSpanResult& spanResult)
6753 {
6754     spanResult.SetSpanType(SpanResultType::SYMBOL);
6755     spanResult.SetSpanRangeEnd(spanItem->position);
6756     spanResult.SetSpanRangeStart(spanItem->position - SYMBOL_SPAN_LENGTH);
6757     spanResult.SetEraseLength(SYMBOL_SPAN_LENGTH);
6758     spanResult.SetValueString(std::to_string(spanItem->unicode));
6759     spanResult.SetValueResource(spanItem->GetResourceObject());
6760     auto spanNode = GetSpanNodeBySpanItem(spanItem);
6761     if (spanNode) {
6762         spanResult.SetSymbolSpanStyle(GetSymbolSpanStyleObject(spanNode));
6763     }
6764     return SYMBOL_SPAN_LENGTH;
6765 }
6766 
6767 int32_t RichEditorPattern::DeleteValueSetImageSpan(
6768     const RefPtr<SpanItem>& spanItem, RichEditorAbstractSpanResult& spanResult)
6769 {
6770     spanResult.SetSpanType(SpanResultType::IMAGE);
6771     spanResult.SetSpanRangeEnd(spanItem->position);
6772     spanResult.SetSpanRangeStart(spanItem->position - 1);
6773     spanResult.SetEraseLength(1);
6774     auto host = GetHost();
6775     CHECK_NULL_RETURN(host, IMAGE_SPAN_LENGTH);
6776     auto uiNode = host->GetChildAtIndex(spanResult.GetSpanIndex());
6777     CHECK_NULL_RETURN(uiNode, IMAGE_SPAN_LENGTH);
6778     auto imageNode = AceType::DynamicCast<FrameNode>(uiNode);
6779     CHECK_NULL_RETURN(imageNode, IMAGE_SPAN_LENGTH);
6780     auto imageRenderCtx = imageNode->GetRenderContext();
6781     if (imageRenderCtx->GetBorderRadius()) {
6782         BorderRadiusProperty brp;
6783         auto jsonObject = JsonUtil::Create(true);
6784         auto jsonBorder = JsonUtil::Create(true);
6785         InspectorFilter filter;
6786         imageRenderCtx->GetBorderRadiusValue(brp).ToJsonValue(jsonObject, jsonBorder, filter);
6787         spanResult.SetBorderRadius(jsonObject->GetValue("borderRadius")->IsObject()
6788                                        ? jsonObject->GetValue("borderRadius")->ToString()
6789                                        : jsonObject->GetString("borderRadius"));
6790     }
6791     auto geometryNode = imageNode->GetGeometryNode();
6792     CHECK_NULL_RETURN(geometryNode, IMAGE_SPAN_LENGTH);
6793     auto imageLayoutProperty = DynamicCast<ImageLayoutProperty>(imageNode->GetLayoutProperty());
6794     CHECK_NULL_RETURN(imageLayoutProperty, IMAGE_SPAN_LENGTH);
6795     spanResult.SetSizeWidth(geometryNode->GetMarginFrameSize().Width());
6796     spanResult.SetSizeHeight(geometryNode->GetMarginFrameSize().Height());
6797     if (imageLayoutProperty->GetMarginProperty()) {
6798         spanResult.SetMargin(imageLayoutProperty->GetMarginProperty()->ToString());
6799     }
6800     if (!imageLayoutProperty->GetImageSourceInfo()->GetPixmap()) {
6801         spanResult.SetValueResourceStr(imageLayoutProperty->GetImageSourceInfo()->GetSrc());
6802     } else {
6803         spanResult.SetValuePixelMap(imageLayoutProperty->GetImageSourceInfo()->GetPixmap());
6804     }
6805     if (imageLayoutProperty->HasImageFit()) {
6806         spanResult.SetImageFit(imageLayoutProperty->GetImageFitValue());
6807     }
6808     if (imageLayoutProperty->HasVerticalAlign()) {
6809         spanResult.SetVerticalAlign(imageLayoutProperty->GetVerticalAlignValue());
6810     }
6811     return IMAGE_SPAN_LENGTH;
6812 }
6813 
6814 int32_t RichEditorPattern::DeleteValueSetBuilderSpan(
6815     const RefPtr<SpanItem>& spanItem, RichEditorAbstractSpanResult& spanResult)
6816 {
6817     spanResult.SetSpanType(SpanResultType::IMAGE);
6818     spanResult.SetSpanRangeEnd(spanItem->position);
6819     spanResult.SetSpanRangeStart(spanItem->position - 1);
6820     spanResult.SetEraseLength(1);
6821     auto host = GetHost();
6822     CHECK_NULL_RETURN(host, 1);
6823     auto uiNode = host->GetChildAtIndex(spanResult.GetSpanIndex());
6824     CHECK_NULL_RETURN(uiNode, 1);
6825     auto builderNode = AceType::DynamicCast<FrameNode>(uiNode);
6826     CHECK_NULL_RETURN(builderNode, 1);
6827     auto geometryNode = builderNode->GetGeometryNode();
6828     CHECK_NULL_RETURN(geometryNode, 1);
6829     spanResult.SetSizeWidth(geometryNode->GetMarginFrameSize().Width());
6830     spanResult.SetSizeHeight(geometryNode->GetMarginFrameSize().Height());
6831     return 1;
6832 }
6833 
6834 int32_t RichEditorPattern::DeleteValueSetTextSpan(
6835     const RefPtr<SpanItem>& spanItem, int32_t currentPosition, int32_t length, RichEditorAbstractSpanResult& spanResult)
6836 {
6837     spanResult.SetSpanType(SpanResultType::TEXT);
6838     auto contentStartPosition
6839         = spanItem->position - static_cast<int32_t>(spanItem->content.length());
6840     spanResult.SetSpanRangeStart(contentStartPosition);
6841     int32_t eraseLength = 0;
6842     if (spanItem->position - currentPosition >= length) {
6843         eraseLength = length;
6844     } else {
6845         eraseLength = spanItem->position - currentPosition;
6846     }
6847     spanResult.SetSpanRangeEnd(spanItem->position);
6848     if (!previewTextRecord_.previewContent.empty()) {
6849         spanResult.SetPreviewText(previewTextRecord_.previewContent);
6850     } else {
6851         spanResult.SetValue(spanItem->content);
6852     }
6853     spanResult.SetOffsetInSpan(currentPosition - contentStartPosition);
6854     spanResult.SetEraseLength(eraseLength);
6855     spanResult.SetUrlAddress(spanItem->urlAddress);
6856     if (!spanItem->GetTextStyle().has_value()) {
6857         TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "SpanItem text style is empty.");
6858         return eraseLength;
6859     }
6860     spanResult.SetFontColor(spanItem->GetTextStyle()->GetTextColor().ColorToString());
6861     spanResult.SetFontSize(spanItem->GetTextStyle()->GetFontSize().Value());
6862     spanResult.SetFontStyle(spanItem->GetTextStyle()->GetFontStyle());
6863     spanResult.SetFontWeight((int32_t)(spanItem->GetTextStyle()->GetFontWeight()));
6864     if (!spanItem->GetTextStyle()->GetFontFamilies().empty()) {
6865         spanResult.SetFontFamily(spanItem->GetTextStyle()->GetFontFamilies().at(0));
6866     }
6867     spanResult.SetColor(spanItem->GetTextStyle()->GetTextDecorationColor().ColorToString());
6868     spanResult.SetTextDecoration(spanItem->GetTextStyle()->GetTextDecoration());
6869     spanResult.SetTextDecorationStyle(spanItem->GetTextStyle()->GetTextDecorationStyle());
6870     spanResult.SetFontFeature(spanItem->GetTextStyle()->GetFontFeatures());
6871     auto host = GetHost();
6872     CHECK_NULL_RETURN(host, eraseLength);
6873     auto uiNode = host->GetChildAtIndex(spanResult.GetSpanIndex());
6874     CHECK_NULL_RETURN(uiNode, eraseLength);
6875     auto spanNode = DynamicCast<SpanNode>(uiNode);
6876     CHECK_NULL_RETURN(spanNode, eraseLength);
6877     spanResult.SetTextStyle(GetTextStyleObject(spanNode));
6878     return eraseLength;
6879 }
6880 
6881 void RichEditorPattern::DeleteByDeleteValueInfo(const RichEditorDeleteValue& info)
6882 {
6883     auto deleteSpans = info.GetRichEditorDeleteSpans();
6884     if (deleteSpans.empty()) {
6885         return;
6886     }
6887     auto host = GetHost();
6888     CHECK_NULL_VOID(host);
6889     ProcessDeleteNodes(deleteSpans);
6890     UpdateSpanPosition();
6891     SetCaretPosition(info.GetOffset(), false);
6892     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
6893     OnModifyDone();
6894 }
6895 
6896 int32_t RichEditorPattern::ProcessDeleteNodes(std::list<RichEditorAbstractSpanResult>& deleteSpans)
6897 {
6898     auto eraseLength = 0;
6899     auto host = GetHost();
6900     CHECK_NULL_RETURN(host, eraseLength);
6901     std::set<int32_t, std::greater<int32_t>> deleteNodes;
6902     for (const auto& it : deleteSpans) {
6903         eraseLength += it.GetEraseLength();
6904         switch (it.GetType()) {
6905             case SpanResultType::TEXT: {
6906                 auto ui_node = host->GetChildAtIndex(it.GetSpanIndex());
6907                 CHECK_NULL_RETURN(ui_node, eraseLength);
6908                 auto spanNode = DynamicCast<SpanNode>(ui_node);
6909                 CHECK_NULL_RETURN(spanNode, eraseLength);
6910                 auto spanItem = spanNode->GetSpanItem();
6911                 CHECK_NULL_RETURN(spanItem, eraseLength);
6912                 auto textTemp = spanItem->content;
6913                 auto textTempSize = static_cast<int32_t>(textTemp.size());
6914                 if (textTempSize < it.OffsetInSpan()) {
6915                     TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "ProcessDeleteNodes failed, "
6916                         "contentLen=%{public}zu, spanItemSize=%{public}d, offsetInSpan=%{public}d",
6917                         textTemp.length(), textTempSize, it.OffsetInSpan());
6918                     RichEditorInfo errorInfo { RichEditorErrorType::DELETE_NODE, textTempSize,
6919                         it.GetEraseLength(), it.OffsetInSpan() };
6920                     RichEditorErrorReport(errorInfo);
6921                     continue;
6922                 }
6923                 textTemp.erase(it.OffsetInSpan(), it.GetEraseLength());
6924                 if (textTemp.size() == 0) {
6925                     deleteNodes.emplace(it.GetSpanIndex());
6926                 }
6927                 spanNode->UpdateContent(textTemp);
6928                 spanItem->position -= it.GetEraseLength();
6929                 break;
6930             }
6931             case SpanResultType::IMAGE:
6932                 deleteNodes.emplace(it.GetSpanIndex());
6933                 break;
6934             case SpanResultType::SYMBOL:
6935                 deleteNodes.emplace(it.GetSpanIndex());
6936                 break;
6937             default:
6938                 break;
6939         }
6940     }
6941     RemoveEmptySpan(deleteNodes);
6942     return eraseLength;
6943 }
6944 
6945 void RichEditorPattern::RemoveEmptySpan(std::set<int32_t, std::greater<int32_t>>& deleteSpanIndexs)
6946 {
6947     auto host = GetHost();
6948     CHECK_NULL_VOID(host);
6949     for (auto index : deleteSpanIndexs) {
6950         host->RemoveChildAtIndex(index);
6951         auto it = spans_.begin();
6952         std::advance(it, index);
6953         if (it != spans_.end()) {
6954             spans_.erase(it);
6955         }
6956     }
6957 }
6958 
6959 RefPtr<GestureEventHub> RichEditorPattern::GetGestureEventHub() {
6960     auto host = GetHost();
6961     CHECK_NULL_RETURN(host, nullptr);
6962     return host->GetOrCreateGestureEventHub();
6963 }
6964 
6965 bool RichEditorPattern::OnKeyEvent(const KeyEvent& keyEvent)
6966 {
6967     return TextInputClient::HandleKeyEvent(keyEvent);
6968 }
6969 
6970 void RichEditorPattern::HandleExtendAction(int32_t action)
6971 {
6972     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "HandleExtendAction %{public}d", action);
6973     switch (action) {
6974         case ACTION_SELECT_ALL:
6975             HandleMenuCallbackOnSelectAll(false);
6976             break;
6977         case ACTION_CUT:
6978             HandleOnCut();
6979             break;
6980         case ACTION_COPY:
6981             HandleOnCopy();
6982             break;
6983         case ACTION_PASTE:
6984             HandleOnPaste();
6985             break;
6986         default:
6987             break;
6988     }
6989 }
6990 
6991 void RichEditorPattern::CursorMove(CaretMoveIntent direction)
6992 {
6993     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "direction=%{public}d", direction);
6994     switch (direction) {
6995         case CaretMoveIntent::Left:
6996             CursorMoveLeft();
6997             break;
6998         case CaretMoveIntent::Right:
6999             CursorMoveRight();
7000             break;
7001         case CaretMoveIntent::Up:
7002             CursorMoveUp();
7003             break;
7004         case CaretMoveIntent::Down:
7005             CursorMoveDown();
7006             break;
7007         case CaretMoveIntent::LeftWord:
7008             CursorMoveToNextWord(direction);
7009             break;
7010         case CaretMoveIntent::RightWord:
7011             CursorMoveToNextWord(direction);
7012             break;
7013         case CaretMoveIntent::ParagraghBegin:
7014             CursorMoveToParagraphBegin();
7015             break;
7016         case CaretMoveIntent::ParagraghEnd:
7017             CursorMoveToParagraphEnd();
7018             break;
7019         case CaretMoveIntent::Home:
7020             CursorMoveHome();
7021             break;
7022         case CaretMoveIntent::End:
7023             CursorMoveEnd();
7024             break;
7025         case CaretMoveIntent::LineBegin:
7026             CursorMoveLineBegin();
7027             break;
7028         case CaretMoveIntent::LineEnd:
7029             CursorMoveLineEnd();
7030             break;
7031         default:
7032             LOGW("Unsupported cursor move operation for rich editor");
7033     }
7034 }
7035 
7036 void RichEditorPattern::MoveCaretAfterTextChange()
7037 {
7038     CHECK_NULL_VOID(isTextChange_ && moveLength_ != 0);
7039     isTextChange_ = false;
7040     switch (moveDirection_) {
7041         case MoveDirection::BACKWARD:
7042             SetCaretPosition(std::clamp((caretPosition_ - moveLength_), 0, GetTextContentLength()), false);
7043             break;
7044         case MoveDirection::FORWARD:
7045             SetCaretPosition(std::clamp((caretPosition_ + moveLength_), 0, GetTextContentLength()), false);
7046             break;
7047         default:
7048             break;
7049     }
7050     moveLength_ = 0;
7051 }
7052 
7053 void RichEditorPattern::InitTouchEvent()
7054 {
7055     CHECK_NULL_VOID(!touchListener_);
7056     auto gesture = GetGestureEventHub();
7057     CHECK_NULL_VOID(gesture);
7058     auto touchTask = [weak = WeakClaim(this)](const TouchEventInfo& info) {
7059         auto pattern = weak.Upgrade();
7060         CHECK_NULL_VOID(pattern);
7061         pattern->sourceType_ = info.GetSourceDevice();
7062         pattern->HandleTouchEvent(info);
7063     };
7064     touchListener_ = MakeRefPtr<TouchEventImpl>(std::move(touchTask));
7065     gesture->AddTouchEvent(touchListener_);
7066 }
7067 
7068 void RichEditorPattern::InitPanEvent()
7069 {
7070     CHECK_NULL_VOID(!panEvent_);
7071     auto gestureHub = GetGestureEventHub();
7072     CHECK_NULL_VOID(gestureHub);
7073     auto actionStartTask = [](const GestureEvent& info) {};
7074     auto actionUpdateTask = [](const GestureEvent& info) {};
7075     auto actionEndTask = [](const GestureEvent& info) {};
7076     GestureEventNoParameter actionCancelTask;
7077     panEvent_ = MakeRefPtr<PanEvent>(std::move(actionStartTask), std::move(actionUpdateTask),
7078         std::move(actionEndTask), std::move(actionCancelTask));
7079     PanDirection panDirection = { .type = PanDirection::ALL };
7080     gestureHub->AddPanEvent(panEvent_, panDirection, 1, DEFAULT_PAN_DISTANCE);
7081     gestureHub->SetPanEventType(GestureTypeName::PAN_GESTURE);
7082     gestureHub->SetOnGestureJudgeNativeBegin([weak = WeakClaim(this)](const RefPtr<NG::GestureInfo>& gestureInfo,
7083                                                  const std::shared_ptr<BaseGestureEvent>& info) -> GestureJudgeResult {
7084         auto pattern = weak.Upgrade();
7085         CHECK_NULL_RETURN(pattern, GestureJudgeResult::CONTINUE);
7086         auto gestureType = gestureInfo->GetType();
7087         auto inputEventType = gestureInfo->GetInputEventType();
7088         bool isDraggingCaret = (gestureType == GestureTypeName::PAN_GESTURE)
7089             && (inputEventType == InputEventType::TOUCH_SCREEN) && pattern->moveCaretState_.isMoveCaret;
7090         bool isMouseSelecting = (gestureType == GestureTypeName::PAN_GESTURE)
7091             && (inputEventType == InputEventType::MOUSE_BUTTON) && !pattern->blockPress_;
7092         if (isDraggingCaret || isMouseSelecting) {
7093             TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "prevent pan gesture draggingCaret=%{public}d mouseSelecting=%{public}d",
7094                 isDraggingCaret, isMouseSelecting);
7095             return GestureJudgeResult::CONTINUE;
7096         }
7097         CHECK_NULL_RETURN(gestureInfo->GetType() != GestureTypeName::PAN_GESTURE, GestureJudgeResult::REJECT);
7098         return GestureJudgeResult::CONTINUE;
7099     });
7100 }
7101 
7102 void RichEditorPattern::HandleTouchEvent(const TouchEventInfo& info)
7103 {
7104     CHECK_NULL_VOID(!selectOverlay_->IsTouchAtHandle(info));
7105     CHECK_NULL_VOID(!info.GetTouches().empty());
7106     auto acceptedTouchInfo = GetAcceptedTouchLocationInfo(info);
7107     CHECK_NULL_VOID(acceptedTouchInfo.has_value());
7108     auto touchInfo = acceptedTouchInfo.value();
7109     auto touchType = touchInfo.GetTouchType();
7110     if (touchType == TouchType::DOWN) {
7111         HandleTouchDown(touchInfo);
7112         if (hasUrlSpan_) {
7113             HandleUrlSpanShowShadow(touchInfo.GetLocalLocation(), touchInfo.GetGlobalLocation(), GetUrlPressColor());
7114         }
7115     } else if (touchType == TouchType::UP) {
7116         IF_TRUE(status_ == Status::FLOATING, status_ = Status::NONE);
7117         HandleTouchUp();
7118         if (hasUrlSpan_) {
7119             HandleUrlSpanForegroundClear();
7120         }
7121     } else if (touchType == TouchType::MOVE) {
7122         HandleTouchMove(touchInfo);
7123     } else if (touchType == TouchType::CANCEL) {
7124         IF_PRESENT(magnifierController_, RemoveMagnifierFrameNode());
7125         HandleTouchCancelAfterLongPress();
7126         ResetTouchAndMoveCaretState();
7127     }
7128 }
7129 
7130 std::optional<TouchLocationInfo> RichEditorPattern::GetAcceptedTouchLocationInfo(const TouchEventInfo& info)
7131 {
7132     const auto& touchInfos = info.GetChangedTouches();
7133     CHECK_NULL_RETURN(!touchInfos.empty(), std::nullopt);
7134     CHECK_NULL_RETURN(isTouchSelecting_ || moveCaretState_.touchFingerId.has_value(), touchInfos.front());
7135     const int32_t touchFingerId = isTouchSelecting_ ? selectingFingerId_ : moveCaretState_.touchFingerId.value();
7136     for (const auto& touchInfo : touchInfos) {
7137         if (touchInfo.GetFingerId() == touchFingerId) {
7138             return touchInfo;
7139         }
7140     }
7141     return std::nullopt;
7142 }
7143 
7144 void RichEditorPattern::HandleUrlSpanForegroundClear()
7145 {
7146     overlayMod_->ClearSelectedForegroundColorAndRects();
7147     MarkDirtySelf();
7148 }
7149 
7150 void RichEditorPattern::HandleTouchDown(const TouchLocationInfo& info)
7151 {
7152     auto sourceTool = info.GetSourceTool();
7153     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "Touch down longPressState=[%{public}d, %{public}d], source=%{public}d",
7154         previewLongPress_, editingLongPress_, sourceTool);
7155     globalOffsetOnMoveStart_ = GetPaintRectGlobalOffset();
7156     moveCaretState_.Reset();
7157     ResetTouchSelectState();
7158     CHECK_NULL_VOID(HasFocus() && sourceTool == SourceTool::FINGER);
7159     auto touchDownOffset = info.GetLocalLocation();
7160     moveCaretState_.touchDownOffset = touchDownOffset;
7161     RectF lastCaretRect = GetCaretRect();
7162     if (RepeatClickCaret(touchDownOffset, lastCaretRect)) {
7163         moveCaretState_.isTouchCaret = true;
7164         auto host = GetHost();
7165         CHECK_NULL_VOID(host);
7166     }
7167 }
7168 
7169 void RichEditorPattern::HandleTouchUp()
7170 {
7171     HandleTouchUpAfterLongPress();
7172     ResetTouchAndMoveCaretState();
7173     ResetTouchSelectState();
7174     if (magnifierController_) {
7175         magnifierController_->RemoveMagnifierFrameNode();
7176     }
7177 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
7178     if (isLongPress_) {
7179         isLongPress_ = false;
7180     }
7181 #endif
7182 }
7183 
7184 void RichEditorPattern::StartFloatingCaretLand()
7185 {
7186     AnimationUtils::StopAnimation(magnifierAnimation_);
7187     CHECK_NULL_VOID(floatingCaretState_.isFloatingCaretVisible);
7188     auto caretOffset = CalculateCaretOffsetAndHeight().first;
7189     auto overlayMod = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
7190     IF_PRESENT(overlayMod, StartFloatingCaretLand(caretOffset));
7191 }
7192 
7193 void RichEditorPattern::ResetTouchAndMoveCaretState()
7194 {
7195     if (moveCaretState_.isMoveCaret) {
7196         isCursorAlwaysDisplayed_ = false;
7197         IF_TRUE(isEditing_, StartTwinkling());
7198     }
7199     StopAutoScroll();
7200     CheckScrollable();
7201     UpdateScrollBarOffset();
7202     moveCaretState_.Reset();
7203     StartFloatingCaretLand();
7204 }
7205 
7206 void RichEditorPattern::ResetTouchSelectState()
7207 {
7208     selectingFingerId_ = -1;
7209     isTouchSelecting_ = false;
7210     previewLongPress_ = false;
7211     editingLongPress_ = false;
7212 }
7213 
7214 void RichEditorPattern::HandleTouchUpAfterLongPress()
7215 {
7216     CHECK_NULL_VOID(editingLongPress_ || previewLongPress_);
7217     auto selectStart = std::min(textSelector_.GetTextStart(), GetTextContentLength());
7218     auto selectEnd = std::min(textSelector_.GetTextEnd(), GetTextContentLength());
7219     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "after long press textSelector=[%{public}d, %{public}d] isEditing=%{public}d",
7220         selectStart, selectEnd, isEditing_);
7221     textSelector_.Update(selectStart, selectEnd);
7222     FireOnSelect(selectStart, selectEnd);
7223     SetCaretPositionWithAffinity({ selectEnd, TextAffinity::UPSTREAM });
7224     CalculateHandleOffsetAndShowOverlay();
7225     selectOverlay_->ProcessOverlay({ .animation = true });
7226     FireOnSelectionChange(selectStart, selectEnd);
7227     IF_TRUE(IsSingleHandle(), ForceTriggerAvoidOnCaretChange());
7228 }
7229 
7230 void RichEditorPattern::HandleTouchCancelAfterLongPress()
7231 {
7232     CHECK_NULL_VOID(editingLongPress_ || previewLongPress_);
7233     auto selectStart = std::min(textSelector_.GetTextStart(), GetTextContentLength());
7234     auto selectEnd = std::min(textSelector_.GetTextEnd(), GetTextContentLength());
7235     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "touch canceled, textSelector=[%{public}d, %{public}d] isEditing=%{public}d",
7236         selectStart, selectEnd, isEditing_);
7237     textSelector_.Update(selectStart, selectEnd);
7238     SetCaretPositionWithAffinity({ selectEnd, TextAffinity::UPSTREAM });
7239     CalculateHandleOffsetAndShowOverlay();
7240     selectOverlay_->ProcessOverlay({ .menuIsShow = selectOverlay_->IsCurrentMenuVisibile(), .animation = true });
7241     FireOnSelectionChange(selectStart, selectEnd);
7242 }
7243 
7244 void RichEditorPattern::HandleTouchMove(const TouchLocationInfo& info)
7245 {
7246     auto originalLocaloffset = info.GetLocalLocation();
7247     auto offset = AdjustLocalOffsetOnMoveEvent(originalLocaloffset);
7248     if (previewLongPress_ || editingLongPress_) {
7249         if (!isTouchSelecting_) {
7250             TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "Touch selecting start id= %{public}d", info.GetFingerId());
7251             showSelect_ = true;
7252             isTouchSelecting_ = true;
7253             selectingFingerId_ = info.GetFingerId();
7254         }
7255         UpdateSelectionByTouchMove(offset);
7256         return;
7257     }
7258     CHECK_NULL_VOID(moveCaretState_.isTouchCaret && caretTwinkling_);
7259     if (!moveCaretState_.isMoveCaret) {
7260         auto moveDistance = (offset - moveCaretState_.touchDownOffset).GetDistance();
7261         IF_TRUE(GreatNotEqual(moveDistance, moveCaretState_.minDistance.ConvertToPx()),
7262             OnMoveCaretStart(info.GetFingerId()));
7263     }
7264     UpdateCaretByTouchMove(offset);
7265 }
7266 
7267 void RichEditorPattern::OnMoveCaretStart(int32_t fingerId)
7268 {
7269     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "Move caret start id=%{public}d", fingerId);
7270     moveCaretState_.isMoveCaret = true;
7271     moveCaretState_.touchFingerId = fingerId;
7272     scrollable_ = false;
7273     SetScrollEnabled(scrollable_);
7274     UpdateScrollBarOffset();
7275     ShowCaretWithoutTwinkling();
7276 }
7277 
7278 void RichEditorPattern::UpdateCaretByTouchMove(const Offset& offset)
7279 {
7280     CHECK_NULL_VOID(moveCaretState_.isMoveCaret);
7281     auto host = GetHost();
7282     CHECK_NULL_VOID(host);
7283     if (SelectOverlayIsOn()) {
7284         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "Close select overlay while dragging caret");
7285         selectOverlay_->CloseOverlay(false, CloseReason::CLOSE_REASON_NORMAL);
7286     }
7287     auto touchOffset = Offset(offset.GetX(), std::max(offset.GetY(), static_cast<double>(contentRect_.GetY())));
7288     Offset textOffset = ConvertTouchOffsetToTextOffset(touchOffset);
7289     auto positionWithAffinity = paragraphs_.GetGlyphPositionAtCoordinate(textOffset);
7290     SetCaretPositionWithAffinity(positionWithAffinity);
7291     SetCaretTouchMoveOffset(offset);
7292     CalcAndRecordLastClickCaretInfo(textOffset);
7293     auto [caretOffset, caretHeight] = CalculateCaretOffsetAndHeight();
7294     auto floatingCaretCenter =
7295         Offset(floatingCaretState_.touchMoveOffset->GetX(), caretOffset.GetY() + caretHeight / 2);
7296     SetMagnifierOffsetWithAnimation(floatingCaretCenter);
7297     AutoScrollParam param = { .autoScrollEvent = AutoScrollEvent::CARET, .showScrollbar = true };
7298     AutoScrollByEdgeDetection(param, OffsetF(offset.GetX(), offset.GetY()), EdgeDetectionStrategy::OUT_BOUNDARY);
7299     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
7300 }
7301 
7302 void RichEditorPattern::SetCaretTouchMoveOffset(const Offset& localOffset)
7303 {
7304     double moveDistance = 0.0;
7305     auto positionType = GetPositionTypeFromLine();
7306     auto caretBoundaryRect = GetCaretBoundaryRect();
7307     if (positionType == PositionType::DEFAULT) {
7308         floatingCaretState_.UpdateByTouchMove(localOffset, moveDistance, caretBoundaryRect);
7309         return;
7310     }
7311     auto [caretOffset, caretHeight] = CalculateCaretOffsetAndHeight();
7312     bool isCaretAtEmptyParagraph =
7313         positionType == PositionType::PARAGRAPH_START && caretPosition_ == GetParagraphEndPosition(caretPosition_);
7314     if (isCaretAtEmptyParagraph) {
7315         moveDistance = std::abs(localOffset.GetX() - caretOffset.GetX());
7316     } else {
7317         moveDistance = (caretAffinityPolicy_ == CaretAffinityPolicy::DOWNSTREAM_FIRST || caretPosition_ == 0)
7318                         ? caretOffset.GetX() - localOffset.GetX() : localOffset.GetX() - caretOffset.GetX();
7319     }
7320     floatingCaretState_.UpdateByTouchMove(localOffset, moveDistance, caretBoundaryRect);
7321 }
7322 
7323 RectF RichEditorPattern::GetCaretBoundaryRect()
7324 {
7325     auto caretBoundaryRect = contentRect_;
7326     auto overlayModifier = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
7327     CHECK_NULL_RETURN(overlayModifier, caretBoundaryRect);
7328     auto caretWidth = overlayModifier->GetCaretWidth();
7329     caretBoundaryRect.SetWidth(caretBoundaryRect.Width() - caretWidth);
7330     return caretBoundaryRect;
7331 }
7332 
7333 void RichEditorPattern::SetMagnifierLocalOffset(Offset offset)
7334 {
7335     CHECK_NULL_VOID(magnifierController_);
7336     auto localOffset = OffsetF{ offset.GetX(), offset.GetY() };
7337     auto localOffsetWithTrans = localOffset;
7338     selectOverlay_->GetLocalPointWithTransform(localOffsetWithTrans);
7339     magnifierController_->SetLocalOffset(localOffsetWithTrans, localOffset);
7340 }
7341 
7342 void RichEditorPattern::SetMagnifierOffsetWithAnimation(Offset offset)
7343 {
7344     CHECK_NULL_VOID(magnifierController_);
7345     auto currentLocalOffset = magnifierController_->GetLocalOffset();
7346     auto currentOffset = magnifierController_->GetLocalOffsetWithoutTrans().value_or(currentLocalOffset);
7347     if (NearEqual(currentOffset.GetY(), offset.GetY(), 0.5f) || !magnifierController_->GetShowMagnifier()) {
7348         SetMagnifierLocalOffset(offset);
7349         return;
7350     }
7351     AnimationUtils::StopAnimation(magnifierAnimation_);
7352     AnimationOption option{ MAGNIFIER_ANIMATION_CURVE, MAGNIFIER_ANIMATION_DURATION };
7353     magnifierAnimation_ = AnimationUtils::StartAnimation(option, [weak = WeakClaim(this), offset]() {
7354         auto pattern = weak.Upgrade();
7355         CHECK_NULL_VOID(pattern);
7356         pattern->SetMagnifierLocalOffset(offset);
7357     });
7358 }
7359 
7360 Offset RichEditorPattern::AdjustLocalOffsetOnMoveEvent(const Offset& originalOffset)
7361 {
7362     auto deltaOffset = GetPaintRectGlobalOffset() - globalOffsetOnMoveStart_;
7363     return { originalOffset.GetX() - deltaOffset.GetX(), originalOffset.GetY() - deltaOffset.GetY() };
7364 }
7365 
7366 void RichEditorPattern::StartVibratorByIndexChange(int32_t currentIndex, int32_t preIndex)
7367 {
7368     CHECK_NULL_VOID(isEnableHapticFeedback_ && (currentIndex != preIndex));
7369     VibratorUtils::StartVibraFeedback("slide");
7370 }
7371 
7372 bool RichEditorPattern::IsScrollBarPressed(const MouseInfo& info)
7373 {
7374     auto scrollBar = GetScrollBar();
7375     bool isScrollBarShow = scrollBar && scrollBar->NeedPaint();
7376     CHECK_NULL_RETURN(isScrollBarShow, false);
7377     Point point(info.GetLocalLocation().GetX(), info.GetLocalLocation().GetY());
7378     return scrollBar->InBarRectRegion(point);
7379 }
7380 
7381 void RichEditorPattern::HandleMouseLeftButtonMove(const MouseInfo& info)
7382 {
7383     ACE_SCOPED_TRACE("RichEditorHandleMouseLeftButtonMove");
7384     CHECK_NULL_VOID(!IsPreviewTextInputting());
7385     if (blockPress_) {
7386         ACE_SCOPED_TRACE("RichEditorUpdateDragBoxes");
7387         dragBoxes_ = GetTextBoxes();
7388         return;
7389     }
7390     CHECK_NULL_VOID(leftMousePress_);
7391 
7392     auto localOffset = info.GetLocalLocation();
7393     const auto& globalOffset = info.GetGlobalLocation();
7394     auto paintOffset = GetPaintRectGlobalOffset();
7395     if (!selectOverlay_->HasRenderTransform()) {
7396         localOffset = Offset(globalOffset.GetX() - paintOffset.GetX(), globalOffset.GetY() - paintOffset.GetY());
7397     }
7398     Offset textOffset = ConvertTouchOffsetToTextOffset(localOffset);
7399     if (dataDetectorAdapter_->pressedByLeftMouse_) {
7400         dataDetectorAdapter_->pressedByLeftMouse_ = false;
7401         MoveCaretAndStartFocus(textOffset);
7402     }
7403 
7404     auto focusHub = GetFocusHub();
7405     CHECK_NULL_VOID(focusHub);
7406     CHECK_NULL_VOID(focusHub->IsCurrentFocus());
7407 
7408     mouseStatus_ = MouseStatus::MOVE;
7409     HandleMouseSelect(localOffset);
7410     auto host = GetHost();
7411     CHECK_NULL_VOID(host);
7412     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
7413 }
7414 
7415 void RichEditorPattern::HandleMouseSelect(const Offset& localOffset)
7416 {
7417     if (!textSelector_.IsValid()) {
7418         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "prevent mouse selecting because selection has been reset");
7419         return;
7420     }
7421     Offset textOffset = ConvertTouchOffsetToTextOffset(localOffset);
7422     auto position = GetTextContentLength() == 0 ? 0 : paragraphs_.GetIndex(textOffset);
7423     UpdateSelector(textSelector_.baseOffset, position);
7424     if (!isFirstMouseSelect_) {
7425         AdjustCursorPosition(position);
7426         SetCaretPosition(position);
7427         AutoScrollParam param = {
7428             .autoScrollEvent = AutoScrollEvent::MOUSE, .showScrollbar = true, .eventOffset = localOffset
7429         };
7430         AutoScrollByEdgeDetection(param, OffsetF(localOffset.GetX(), localOffset.GetY()),
7431             EdgeDetectionStrategy::OUT_BOUNDARY);
7432         showSelect_ = true;
7433     } else {
7434         isFirstMouseSelect_ = false;
7435     }
7436     if (textSelector_.SelectNothing()) {
7437         StartTwinkling();
7438     } else {
7439         StopTwinkling();
7440     }
7441     isMouseSelect_ = true;
7442 }
7443 
7444 void RichEditorPattern::HandleMouseLeftButtonPress(const MouseInfo& info)
7445 {
7446     isMousePressed_ = true;
7447     auto frameNodeRange = GetSpanRangeByLocalOffset(info.GetLocalLocation());
7448     bool frameNodeSelected = textSelector_.ContainsRange(frameNodeRange);
7449     bool pressFrameNode = !frameNodeSelected && InRangeRect(info.GetGlobalLocation(), frameNodeRange);
7450     if (IsPreviewTextInputting() || IsScrollBarPressed(info) || BetweenSelectedPosition(info.GetGlobalLocation()) ||
7451         pressFrameNode) {
7452         blockPress_ = true;
7453         return;
7454     }
7455     auto focusHub = GetFocusHub();
7456     CHECK_NULL_VOID(focusHub);
7457     if (!focusHub->IsFocusable()) {
7458         return;
7459     }
7460     auto textPaintOffset = GetTextRect().GetOffset() - OffsetF(0.0, std::min(baselineOffset_, 0.0f));
7461     Offset textOffset = { info.GetLocalLocation().GetX() - textPaintOffset.GetX(),
7462         info.GetLocalLocation().GetY() - textPaintOffset.GetY() };
7463     int32_t position = (GetTextContentLength() == 0) ? 0 : paragraphs_.GetIndex(textOffset);
7464     if (shiftFlag_) {
7465         HandleShiftSelect(position);
7466     } else {
7467         IF_TRUE(!textSelector_.SelectNothing(), ResetSelection());
7468         textSelector_.Update(position);
7469     }
7470     leftMousePress_ = true;
7471     globalOffsetOnMoveStart_ = GetPaintRectGlobalOffset();
7472     mouseStatus_ = MouseStatus::PRESSED;
7473     blockPress_ = false;
7474     caretUpdateType_ = CaretUpdateType::PRESSED;
7475     dataDetectorAdapter_->pressedByLeftMouse_ = false;
7476     HandleClickAISpanEvent(PointF(textOffset.GetX(), textOffset.GetY()));
7477     if (dataDetectorAdapter_->pressedByLeftMouse_) {
7478         return;
7479     }
7480     UseHostToUpdateTextFieldManager();
7481     MoveCaretAndStartFocus(textOffset);
7482     CalcCaretInfoByClick(info.GetLocalLocation());
7483 }
7484 
7485 void RichEditorPattern::HandleShiftSelect(int32_t position)
7486 {
7487     CHECK_NULL_VOID(shiftFlag_);
7488     int32_t start = textSelector_.SelectNothing() ? caretPosition_ : textSelector_.baseOffset;
7489     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "HandleShiftSelect [%{public}d-%{public}d]", start, position);
7490     UpdateSelector(start, position);
7491     SetCaretPosition(position);
7492     FireOnSelect(textSelector_.GetTextStart(), textSelector_.GetTextEnd());
7493     auto host = GetHost();
7494     CHECK_NULL_VOID(host);
7495     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
7496 }
7497 
7498 void RichEditorPattern::HandleMouseLeftButtonRelease(const MouseInfo& info)
7499 {
7500     blockPress_ = false;
7501     leftMousePress_ = false;
7502     CHECK_NULL_VOID(!IsPreviewTextInputting());
7503     auto oldMouseStatus = mouseStatus_;
7504     mouseStatus_ = MouseStatus::RELEASED;
7505     isMouseSelect_ = false;
7506     isFirstMouseSelect_ = true;
7507     if (!showSelect_) {
7508         showSelect_ = true;
7509         ResetSelection();
7510     }
7511     if (dataDetectorAdapter_->pressedByLeftMouse_ && oldMouseStatus != MouseStatus::MOVE && !IsDragging()) {
7512         dataDetectorAdapter_->ResponseBestMatchItem(dataDetectorAdapter_->clickedAISpan_);
7513         dataDetectorAdapter_->pressedByLeftMouse_ = false;
7514         isMousePressed_ = false;
7515         return;
7516     }
7517 
7518     auto selectStart = std::min(textSelector_.baseOffset, textSelector_.destinationOffset);
7519     auto selectEnd = std::max(textSelector_.baseOffset, textSelector_.destinationOffset);
7520     if (selectStart != selectEnd && isMousePressed_ && oldMouseStatus == MouseStatus::MOVE) {
7521         FireOnSelect(selectStart, selectEnd);
7522     }
7523     StopAutoScroll();
7524     if (textSelector_.IsValid() && !textSelector_.StartEqualToDest() && IsSelectedBindSelectionMenu() &&
7525         oldMouseStatus == MouseStatus::MOVE) {
7526         auto offsetX = static_cast<float>(info.GetGlobalLocation().GetX());
7527         auto offsetY = static_cast<float>(info.GetGlobalLocation().GetY());
7528         selectionMenuOffsetByMouse_ = OffsetF(offsetX, offsetY);
7529         selectionMenuOffsetClick_ = OffsetF(offsetX, offsetY);
7530         ShowSelectOverlay(RectF(), RectF(), false, TextResponseType::SELECTED_BY_MOUSE);
7531     }
7532     isMousePressed_ = false;
7533     if (HasFocus()) {
7534         HandleOnEditChanged(true);
7535     }
7536 }
7537 
7538 void RichEditorPattern::HandleMouseLeftButton(const MouseInfo& info)
7539 {
7540     if (info.GetAction() == MouseAction::MOVE) {
7541         HandleMouseLeftButtonMove(info);
7542     } else if (info.GetAction() == MouseAction::PRESS) {
7543         HandleMouseLeftButtonPress(info);
7544     } else if (info.GetAction() == MouseAction::RELEASE) {
7545         HandleMouseLeftButtonRelease(info);
7546     }
7547 }
7548 
7549 void RichEditorPattern::HandleMouseRightButton(const MouseInfo& info)
7550 {
7551     CHECK_NULL_VOID(!IsPreviewTextInputting());
7552     auto focusHub = GetFocusHub();
7553     CHECK_NULL_VOID(focusHub);
7554     if (!focusHub->IsFocusable()) {
7555         return;
7556     }
7557     if (info.GetAction() == MouseAction::PRESS) {
7558         isMousePressed_ = true;
7559         usingMouseRightButton_ = true;
7560         CloseSelectOverlay();
7561     } else if (info.GetAction() == MouseAction::RELEASE) {
7562         auto offsetX = static_cast<float>(info.GetGlobalLocation().GetX());
7563         auto offsetY = static_cast<float>(info.GetGlobalLocation().GetY());
7564         selectionMenuOffsetByMouse_ = OffsetF(offsetX, offsetY);
7565         selectionMenuOffsetClick_ = OffsetF(offsetX, offsetY);
7566         selectOverlay_->SetIsSingleHandle(false);
7567         if (textSelector_.IsValid() && BetweenSelection(info.GetGlobalLocation())) {
7568             ShowSelectOverlay(RectF(), RectF(), IsSelectAll(), TextResponseType::RIGHT_CLICK);
7569             isMousePressed_ = false;
7570             usingMouseRightButton_ = false;
7571             return;
7572         }
7573         auto textPaintOffset = GetTextRect().GetOffset() - OffsetF(0.0f, std::min(baselineOffset_, 0.0f));
7574         Offset textOffset = { info.GetLocalLocation().GetX() - textPaintOffset.GetX(),
7575             info.GetLocalLocation().GetY() - textPaintOffset.GetY() };
7576         HandleClickAISpanEvent(PointF(textOffset.GetX(), textOffset.GetY()));
7577         if (dataDetectorAdapter_->hasClickedAISpan_) {
7578             dataDetectorAdapter_->hasClickedAISpan_ = false;
7579             isMousePressed_ = false;
7580             usingMouseRightButton_ = false;
7581             return;
7582         }
7583         if (textSelector_.IsValid()) {
7584             CloseSelectOverlay();
7585             ResetSelection();
7586         }
7587         MouseRightFocus(info);
7588         ShowSelectOverlay(RectF(), RectF(), IsSelectAll(), TextResponseType::RIGHT_CLICK);
7589         isMousePressed_ = false;
7590         usingMouseRightButton_ = false;
7591     }
7592 }
7593 
7594 std::pair<int32_t, int32_t> RichEditorPattern::GetSpanRangeByLocalOffset(Offset localOffset)
7595 {
7596     Offset textOffset = ConvertTouchOffsetToTextOffset(localOffset);
7597     auto [pos, affinity] = paragraphs_.GetGlyphPositionAtCoordinate(textOffset);
7598     auto spanFilter = [](SpanItemType itemType) {
7599         return itemType == SpanItemType::IMAGE
7600             || itemType == SpanItemType::PLACEHOLDER
7601             || itemType == SpanItemType::CustomSpan; };
7602     auto it = std::find_if(spans_.begin(), spans_.end(),
7603         [pos = static_cast<int32_t>(pos), affinity = affinity, spanFilter](const RefPtr<SpanItem>& spanItem) {
7604             CHECK_NULL_RETURN(spanFilter(spanItem->spanItemType), false);
7605             return pos == (affinity == TextAffinity::UPSTREAM ? spanItem->position : spanItem->rangeStart);
7606         });
7607     bool isMouseOnTarget = it != spans_.end();
7608     CHECK_NULL_RETURN(isMouseOnTarget, std::make_pair(-1, -1));
7609     return affinity == TextAffinity::UPSTREAM ? std::make_pair(pos - 1, pos) : std::make_pair(pos, pos + 1);
7610 }
7611 
7612 void RichEditorPattern::MouseRightFocus(const MouseInfo& info)
7613 {
7614     auto host = GetHost();
7615     CHECK_NULL_VOID(host);
7616     auto focusHub = host->GetOrCreateFocusHub();
7617     CHECK_NULL_VOID(focusHub);
7618     focusHub->RequestFocusImmediately();
7619 
7620     auto selectRange = GetSpanRangeByLocalOffset(info.GetLocalLocation());
7621     if (InRangeRect(info.GetGlobalLocation(), selectRange)) {
7622         selectedType_ = TextSpanType::IMAGE;
7623         textSelector_.Update(selectRange.first, selectRange.second);
7624         FireOnSelect(selectRange.first, selectRange.second);
7625         host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
7626         return;
7627     }
7628     if (textSelector_.IsValid()) {
7629         ResetSelection();
7630     }
7631     Offset textOffset = ConvertTouchOffsetToTextOffset(info.GetLocalLocation());
7632     auto position = paragraphs_.GetIndex(textOffset);
7633     SetCaretPosition(position);
7634     CalcAndRecordLastClickCaretInfo(textOffset);
7635     auto [caretOffset, caretHeight] = CalculateCaretOffsetAndHeight();
7636     selectedType_ = TextSpanType::TEXT;
7637     CHECK_NULL_VOID(overlayMod_);
7638     DynamicCast<RichEditorOverlayModifier>(overlayMod_)->SetCaretOffsetAndHeight(caretOffset, caretHeight);
7639     StartTwinkling();
7640 }
7641 
7642 void RichEditorPattern::FireOnSelect(int32_t selectStart, int32_t selectEnd)
7643 {
7644     auto eventHub = GetEventHub<RichEditorEventHub>();
7645     CHECK_NULL_VOID(eventHub);
7646     auto textSelectInfo = GetSpansInfo(selectStart, selectEnd, GetSpansMethod::ONSELECT);
7647     if (!textSelectInfo.GetSelection().resultObjects.empty()) {
7648         eventHub->FireOnSelect(&textSelectInfo);
7649     }
7650     UpdateSelectionType(textSelectInfo);
7651 }
7652 
7653 void RichEditorPattern::UpdateSelectionType(const SelectionInfo& textSelectInfo)
7654 {
7655     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
7656         TextPattern::UpdateSelectionType(GetAdjustedSelectionInfo(textSelectInfo));
7657     } else {
7658         TextPattern::UpdateSelectionType(textSelectInfo);
7659     }
7660 }
7661 
7662 SelectionInfo RichEditorPattern::GetAdjustedSelectionInfo(const SelectionInfo& textSelectInfo)
7663 {
7664     auto selection = textSelectInfo.GetSelection();
7665     auto resultObjects = selection.resultObjects;
7666     std::for_each(resultObjects.begin(), resultObjects.end(), [](ResultObject& object) {
7667         if (object.type == SelectSpanType::TYPEIMAGE && object.valueString == u" " && object.valuePixelMap == nullptr) {
7668             object.type = SelectSpanType::TYPEBUILDERSPAN;
7669         }
7670     });
7671     SelectionInfo adjustedInfo;
7672     adjustedInfo.SetSelectionStart(selection.selection[RichEditorSpanRange::RANGESTART]);
7673     adjustedInfo.SetSelectionEnd(selection.selection[RichEditorSpanRange::RANGEEND]);
7674     adjustedInfo.SetResultObjectList(resultObjects);
7675     return adjustedInfo;
7676 }
7677 
7678 void RichEditorPattern::HandleMouseEvent(const MouseInfo& info)
7679 {
7680     HandleImageHoverEvent(info);
7681     if (selectOverlay_->IsHandleShow() && info.GetAction() == MouseAction::PRESS) {
7682         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "Close selectOverlay when handle is showing");
7683         CloseSelectOverlay();
7684     }
7685     auto scrollBar = GetScrollBar();
7686     if (scrollBar && (scrollBar->IsHover() || scrollBar->IsPressed())) {
7687         ChangeMouseStyle(MouseFormat::DEFAULT);
7688         HandleUrlSpanForegroundClear();
7689         return;
7690     }
7691 
7692     if (hasUrlSpan_) {
7693         auto show = HandleUrlSpanShowShadow(info.GetLocalLocation(), info.GetGlobalLocation(), GetUrlHoverColor());
7694         if (show) {
7695             ChangeMouseStyle(MouseFormat::HAND_POINTING);
7696         } else {
7697             ChangeMouseStyle(MouseFormat::TEXT_CURSOR);
7698         }
7699     }
7700 
7701     if (currentMouseStyle_ == MouseFormat::DEFAULT && !IsDragging()) {
7702         ChangeMouseStyle(MouseFormat::TEXT_CURSOR);
7703     }
7704 
7705     caretUpdateType_ = CaretUpdateType::NONE;
7706     if (info.GetButton() == MouseButton::LEFT_BUTTON) {
7707         sourceType_ = info.GetSourceDevice();
7708         HandleMouseLeftButton(info);
7709     } else if (info.GetButton() == MouseButton::RIGHT_BUTTON) {
7710         sourceType_ = info.GetSourceDevice();
7711         HandleMouseRightButton(info);
7712     }
7713 }
7714 
7715 Color RichEditorPattern::GetUrlHoverColor()
7716 {
7717     auto theme = GetTheme<RichEditorTheme>();
7718     CHECK_NULL_RETURN(theme, Color());
7719     return theme->GetUrlHoverColor();
7720 }
7721 
7722 Color RichEditorPattern::GetUrlPressColor()
7723 {
7724     auto theme = GetTheme<RichEditorTheme>();
7725     CHECK_NULL_RETURN(theme, Color());
7726     return theme->GetUrlPressColor();
7727 }
7728 
7729 Color RichEditorPattern::GetUrlSpanColor()
7730 {
7731     auto theme = GetTheme<RichEditorTheme>();
7732     CHECK_NULL_RETURN(theme, Color());
7733     return theme->GetUrlDefaultColor();
7734 }
7735 
7736 void RichEditorPattern::TriggerAvoidOnCaretChange()
7737 {
7738     CHECK_NULL_VOID(HasFocus());
7739     auto host = GetHost();
7740     CHECK_NULL_VOID(host);
7741     auto pipeline = host->GetContext();
7742     CHECK_NULL_VOID(pipeline);
7743     auto textFieldManager = DynamicCast<TextFieldManagerNG>(pipeline->GetTextFieldManager());
7744     CHECK_NULL_VOID(textFieldManager);
7745     CHECK_NULL_VOID(pipeline->UsingCaretAvoidMode());
7746     auto safeAreaManager = pipeline->GetSafeAreaManager();
7747     if (!safeAreaManager || NearZero(safeAreaManager->GetKeyboardInset().Length(), 0)) {
7748         return;
7749     }
7750     textFieldManager->SetHeight(GetCaretRect().Height());
7751     auto taskExecutor = pipeline->GetTaskExecutor();
7752     CHECK_NULL_VOID(taskExecutor);
7753     taskExecutor->PostTask([manager = WeakPtr<TextFieldManagerNG>(textFieldManager)] {
7754         auto textFieldManager = manager.Upgrade();
7755         CHECK_NULL_VOID(textFieldManager);
7756         textFieldManager->TriggerAvoidOnCaretChange();
7757     }, TaskExecutor::TaskType::UI, "ArkUIRichEditorTriggerAvoidOnCaretChange", PriorityType::VIP);
7758 }
7759 
7760 void RichEditorPattern::OnWindowSizeChanged(int32_t width, int32_t height, WindowSizeChangeReason type)
7761 {
7762     selectOverlay_->UpdateMenuOnWindowSizeChanged(type);
7763     CHECK_NULL_VOID(type == WindowSizeChangeReason::ROTATION);
7764     auto host = GetHost();
7765     CHECK_NULL_VOID(host);
7766     auto context = host->GetContextRefPtr();
7767     CHECK_NULL_VOID(context);
7768     auto taskExecutor = context->GetTaskExecutor();
7769     CHECK_NULL_VOID(taskExecutor);
7770     auto textFieldManager = DynamicCast<TextFieldManagerNG>(context->GetTextFieldManager());
7771     CHECK_NULL_VOID(textFieldManager);
7772     textFieldManager->ResetOptionalClickPosition();
7773     taskExecutor->PostTask(
7774         [weak = WeakClaim(this), manager = WeakPtr<TextFieldManagerNG>(textFieldManager)] {
7775             auto pattern = weak.Upgrade();
7776             CHECK_NULL_VOID(pattern);
7777             pattern->UpdateParentOffsetAndOverlay();
7778             pattern->UpdateModifierCaretOffsetAndHeight();
7779             pattern->UpdateTextFieldManager(Offset(pattern->parentGlobalOffset_.GetX(),
7780                 pattern->parentGlobalOffset_.GetY()), pattern->frameRect_.Height());
7781             pattern->UpdateCaretInfoToController();
7782             if (pattern->HasFocus()) {
7783                 auto textFieldManager = manager.Upgrade();
7784                 CHECK_NULL_VOID(textFieldManager);
7785                 auto container = Container::Current();
7786                 CHECK_NULL_VOID(container);
7787                 auto displayInfo = container->GetDisplayInfo();
7788                 if (displayInfo) {
7789                     auto dmRotation = static_cast<int32_t>(displayInfo->GetRotation());
7790                     textFieldManager->SetFocusFieldOrientation(dmRotation);
7791                     textFieldManager->SetFocusFieldAlreadyTriggerWsCallback(true);
7792                 }
7793             }
7794         },
7795         TaskExecutor::TaskType::UI, "ArkUIRichEditorOnWindowSizeChangedRotation", PriorityType::VIP);
7796 }
7797 
7798 void RichEditorPattern::CopySelectionMenuParams(SelectOverlayInfo& selectInfo, TextResponseType responseType)
7799 {
7800     auto selectType = selectedType_.value_or(TextSpanType::NONE);
7801     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "textSpanType=%{public}d, responseType=%{public}d", selectType, responseType);
7802     std::shared_ptr<SelectionMenuParams> menuParams = GetMenuParams(selectType, responseType);
7803     CHECK_NULL_VOID(menuParams);
7804 
7805     // long pressing on the image needs to set the position of the pop-up menu following the long pressing position
7806     if (selectType == TextSpanType::IMAGE && !selectInfo.isUsingMouse) {
7807         selectInfo.menuInfo.menuOffset = OffsetF(selectionMenuOffset_.GetX(), selectionMenuOffset_.GetY());
7808     }
7809 
7810     CopyBindSelectionMenuParams(selectInfo, menuParams);
7811 }
7812 
7813 void RichEditorPattern::ShowSelectOverlay(const RectF& firstHandle, const RectF& secondHandle, bool isCopyAll,
7814     TextResponseType responseType, bool handleReverse)
7815 {
7816     CHECK_NULL_VOID(!IsPreviewTextInputting());
7817     textResponseType_ = responseType;
7818     selectOverlay_->ProcessOverlay({.animation = true});
7819 }
7820 
7821 void RichEditorPattern::SetIsEnableSubWindowMenu()
7822 {
7823     selectOverlay_->SetIsHostNodeEnableSubWindowMenu(true);
7824 }
7825 
7826 void RichEditorPattern::CheckEditorTypeChange()
7827 {
7828     CHECK_NULL_VOID(selectOverlayProxy_);
7829     CHECK_NULL_VOID(!selectOverlayProxy_->IsClosed());
7830     if (selectOverlayProxy_->GetSelectOverlayMangerInfo().menuInfo.editorType.value_or(static_cast<int32_t>(
7831             TextSpanType::NONE)) != static_cast<int32_t>(selectedType_.value_or(TextSpanType::NONE))) {
7832         CloseSelectOverlay();
7833     }
7834 }
7835 
7836 void RichEditorPattern::OnCopyOperationExt(RefPtr<PasteDataMix>& pasteData)
7837 {
7838     auto subSpanString =
7839         ToStyledString(textSelector_.GetTextStart(), textSelector_.GetTextEnd());
7840     std::vector<uint8_t> tlvData;
7841     subSpanString->EncodeTlv(tlvData);
7842     auto text = subSpanString->GetString();
7843     clipboard_->AddSpanStringRecord(pasteData, tlvData);
7844 }
7845 
7846 void RichEditorPattern::HandleOnCopyStyledString()
7847 {
7848     RefPtr<PasteDataMix> pasteData = clipboard_->CreatePasteDataMix();
7849     auto subSpanString = styledString_->GetSubSpanString(textSelector_.GetTextStart(),
7850         textSelector_.GetTextEnd() - textSelector_.GetTextStart());
7851 #ifdef PREVIEW
7852     clipboard_->SetData(subSpanString->GetString(), CopyOptions::Distributed);
7853 #else
7854     std::vector<uint8_t> tlvData;
7855     subSpanString->EncodeTlv(tlvData);
7856     clipboard_->AddSpanStringRecord(pasteData, tlvData);
7857     clipboard_->AddTextRecord(pasteData, subSpanString->GetString());
7858     clipboard_->SetData(pasteData, copyOption_);
7859 #endif
7860 }
7861 
7862 void RichEditorPattern::OnCopyOperation(bool isUsingExternalKeyboard)
7863 {
7864     if (isSpanStringMode_) {
7865         HandleOnCopyStyledString();
7866         return;
7867     }
7868     RefPtr<PasteDataMix> pasteData = clipboard_->CreatePasteDataMix();
7869     auto selectStart = textSelector_.GetTextStart();
7870     auto selectEnd = textSelector_.GetTextEnd();
7871     auto textSelectInfo = GetSpansInfo(selectStart, selectEnd, GetSpansMethod::ONSELECT);
7872     auto copyResultObjects = textSelectInfo.GetSelection().resultObjects;
7873     caretUpdateType_ = CaretUpdateType::NONE;
7874     if (copyResultObjects.empty()) {
7875         return;
7876     }
7877     for (auto resultObj = copyResultObjects.rbegin(); resultObj != copyResultObjects.rend(); ++resultObj) {
7878         ProcessResultObject(pasteData, *resultObj);
7879     }
7880     clipboard_->SetData(pasteData, copyOption_);
7881 }
7882 
7883 void RichEditorPattern::ProcessResultObject(RefPtr<PasteDataMix> pasteData, const ResultObject& result)
7884 {
7885     CHECK_NULL_VOID(pasteData);
7886     auto multiTypeRecordImpl = AceType::MakeRefPtr<MultiTypeRecordImpl>();
7887     if (result.type == SelectSpanType::TYPESPAN) {
7888         auto data = UtfUtils::Str16ToStr8(GetSelectedSpanText(result.valueString,
7889             result.offsetInSpan[RichEditorSpanRange::RANGESTART], result.offsetInSpan[RichEditorSpanRange::RANGEEND]));
7890 #ifdef PREVIEW
7891         clipboard_->SetData(data, CopyOptions::Distributed);
7892 #else
7893         multiTypeRecordImpl->SetPlainText(data);
7894         EncodeTlvDataByResultObject(result, multiTypeRecordImpl->GetSpanStringBuffer());
7895         clipboard_->AddMultiTypeRecord(pasteData, multiTypeRecordImpl);
7896 #endif
7897         return;
7898     }
7899     if (result.type == SelectSpanType::TYPEIMAGE) {
7900 #ifdef PREVIEW
7901         if (result.valuePixelMap) {
7902             clipboard_->AddPixelMapRecord(pasteData, result.valuePixelMap);
7903         } else {
7904             clipboard_->AddImageRecord(pasteData, UtfUtils::Str16ToStr8(result.valueString));
7905         }
7906 #else
7907         if (result.valuePixelMap) {
7908             multiTypeRecordImpl->SetPixelMap(result.valuePixelMap);
7909         } else {
7910             multiTypeRecordImpl->SetUri(UtfUtils::Str16ToStr8(result.valueString));
7911         }
7912         EncodeTlvDataByResultObject(result, multiTypeRecordImpl->GetSpanStringBuffer());
7913         clipboard_->AddMultiTypeRecord(pasteData, multiTypeRecordImpl);
7914 #endif
7915     }
7916 }
7917 
7918 void RichEditorPattern::EncodeTlvDataByResultObject(const ResultObject& result, std::vector<uint8_t>& tlvData)
7919 {
7920     auto selectStart = result.spanPosition.spanRange[RichEditorSpanRange::RANGESTART] + result.offsetInSpan[RichEditorSpanRange::RANGESTART];
7921     auto selectEnd = result.spanPosition.spanRange[RichEditorSpanRange::RANGESTART] + result.offsetInSpan[RichEditorSpanRange::RANGEEND];
7922     auto spanString = ToStyledString(selectStart, selectEnd);
7923     spanString->EncodeTlv(tlvData);
7924 }
7925 
7926 void RichEditorPattern::HandleOnCopy(bool isUsingExternalKeyboard)
7927 {
7928     CHECK_NULL_VOID(clipboard_);
7929     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "isUsingExternalKeyboard=%{public}d, copyOption=%{public}d",
7930         isUsingExternalKeyboard, copyOption_);
7931     if (copyOption_ == CopyOptions::None) {
7932         return;
7933     }
7934     auto eventHub = GetEventHub<RichEditorEventHub>();
7935     CHECK_NULL_VOID(eventHub);
7936     TextCommonEvent event;
7937     eventHub->FireOnCopy(event);
7938     IF_TRUE(!event.IsPreventDefault(), OnCopyOperation(isUsingExternalKeyboard));
7939     if (selectOverlay_->IsUsingMouse() || isUsingExternalKeyboard) {
7940         CloseSelectOverlay();
7941     } else {
7942         selectOverlay_->HideMenu();
7943     }
7944 }
7945 
7946 void RichEditorPattern::ResetAfterPaste()
7947 {
7948     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "ResetAfterPaste");
7949     auto pasteStr = GetPasteStr();
7950     SetCaretSpanIndex(-1);
7951     StartTwinkling();
7952     RequestKeyboardToEdit();
7953     CloseSelectOverlay();
7954     InsertValueByPaste(pasteStr);
7955     ClearPasteStr();
7956 }
7957 
7958 void RichEditorPattern::InsertValueByPaste(const std::u16string& pasteStr)
7959 {
7960     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "InsertValueByPaste");
7961     if (isSpanStringMode_) {
7962         InsertValueInStyledString(pasteStr);
7963         return;
7964     }
7965     InsertValueByOperationType(pasteStr, OperationType::DEFAULT);
7966 }
7967 
7968 void RichEditorPattern::HandleOnPaste()
7969 {
7970     if (IsPreviewTextInputting()) {
7971         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "Paste blocked during preview text input");
7972         return;
7973     }
7974     auto eventHub = GetEventHub<RichEditorEventHub>();
7975     CHECK_NULL_VOID(eventHub);
7976     TextCommonEvent event;
7977     eventHub->FireOnPaste(event);
7978     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "HandleOnPaste, preventDefault=%{public}d", event.IsPreventDefault());
7979     if (event.IsPreventDefault()) {
7980         CloseSelectOverlay();
7981         ResetSelection();
7982         StartTwinkling();
7983         RequestKeyboardToEdit();
7984         return;
7985     }
7986     CHECK_NULL_VOID(clipboard_);
7987 #ifdef PREVIEW
7988     auto pasteCallback = [weak = WeakClaim(this)](const std::string& text) {
7989         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "pasteCallback callback in previewer");
7990         auto richEditor = weak.Upgrade();
7991         CHECK_NULL_VOID(richEditor);
7992         richEditor->PasteStr(text);
7993     };
7994     clipboard_->GetData(pasteCallback);
7995 #else
7996     auto isSpanStringMode = isSpanStringMode_;
7997     auto pasteCallback = [weak = WeakClaim(this), isSpanStringMode](std::vector<std::vector<uint8_t>>& arrs,
7998                              const std::string& text, bool& isMulitiTypeRecord) {
7999         TAG_LOGI(AceLogTag::ACE_RICH_TEXT,
8000             "pasteCallback callback, isMulitiTypeRecord : [%{public}d], isSpanStringMode : [%{public}d]",
8001             isMulitiTypeRecord, isSpanStringMode);
8002         auto richEditor = weak.Upgrade();
8003         CHECK_NULL_VOID(richEditor);
8004         std::list<RefPtr<SpanString>> spanStrings;
8005         for (auto arr : arrs) {
8006             spanStrings.push_back(SpanString::DecodeTlv(arr));
8007         }
8008         if (!spanStrings.empty() && !isMulitiTypeRecord) {
8009             for (auto spanString : spanStrings) {
8010                 richEditor->AddSpanByPasteData(spanString);
8011                 richEditor->RequestKeyboardToEdit();
8012             }
8013             return;
8014         }
8015         richEditor->PasteStr(text);
8016     };
8017     clipboard_->GetSpanStringData(pasteCallback);
8018 #endif
8019 }
8020 
8021 void RichEditorPattern::PasteStr(const std::string& text)
8022 {
8023     if (text.empty()) {
8024         ResetSelection();
8025         StartTwinkling();
8026         CloseSelectOverlay();
8027         RequestKeyboardToEdit();
8028         return;
8029     }
8030     AddPasteStr(text);
8031     ResetAfterPaste();
8032 }
8033 
8034 void RichEditorPattern::SetCaretSpanIndex(int32_t index)
8035 {
8036     caretSpanIndex_ = index;
8037 }
8038 
8039 void RichEditorPattern::HandleOnCut()
8040 {
8041     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "copyOption=%{public}d, textSelector_.IsValid()=%{public}d",
8042         copyOption_, textSelector_.IsValid());
8043     if (copyOption_ == CopyOptions::None) {
8044         return;
8045     }
8046     if (!textSelector_.IsValid()) {
8047         return;
8048     }
8049     auto eventHub = GetEventHub<RichEditorEventHub>();
8050     CHECK_NULL_VOID(eventHub);
8051     TextCommonEvent event;
8052     eventHub->FireOnCut(event);
8053     if (event.IsPreventDefault()) {
8054         CloseSelectOverlay();
8055         ResetSelection();
8056         StartTwinkling();
8057         RequestKeyboardToEdit();
8058         return;
8059     }
8060 
8061     caretUpdateType_ = CaretUpdateType::NONE;
8062     OnCopyOperation();
8063     DeleteBackward(1);
8064 }
8065 
8066 void RichEditorPattern::HandleOnShare()
8067 {
8068     auto eventHub = GetEventHub<RichEditorEventHub>();
8069     CHECK_NULL_VOID(eventHub);
8070     TextCommonEvent event;
8071     eventHub->FireOnShare(event);
8072     selectOverlay_->HideMenu(true);
8073     auto value = selectOverlay_->GetSelectedText();
8074     auto shareWord = std::regex_replace(value, REMOVE_SPACE_CHARS, "");
8075     CHECK_NULL_VOID(!shareWord.empty());
8076     auto pipeline = GetContext();
8077     CHECK_NULL_VOID(pipeline);
8078     auto containerId = pipeline->GetInstanceId();
8079     auto contentRect = selectOverlay_->GetSelectArea();
8080     TextShareAdapter::StartTextShareTask(containerId, contentRect, shareWord);
8081 }
8082 
8083 std::function<void(Offset)> RichEditorPattern::GetThumbnailCallback()
8084 {
8085     return [wk = WeakClaim(this)](const Offset& point) {
8086         auto pattern = wk.Upgrade();
8087         CHECK_NULL_VOID(pattern);
8088         if (!pattern->BetweenSelectedPosition(point)) {
8089             return;
8090         }
8091         auto isContentDraggable = pattern->JudgeContentDraggable();
8092         if (!isContentDraggable) {
8093             TAG_LOGE(AceLogTag::ACE_RICH_TEXT, "GetThumbnailCallback call, draggable is false");
8094             pattern->SetIsTextDraggable(false);
8095             return;
8096         }
8097         if (pattern->dragBoxes_.empty()) {
8098             pattern->dragBoxes_ = pattern->GetTextBoxes();
8099         }
8100         pattern->CreateDragNode();
8101     };
8102 }
8103 
8104 void RichEditorPattern::CreateDragNode()
8105 {
8106     auto host = GetHost();
8107     CHECK_NULL_VOID(host);
8108     auto children = host->GetChildren();
8109     std::list<RefPtr<FrameNode>> imageChildren;
8110     for (const auto& child : children) {
8111         auto node = DynamicCast<FrameNode>(child);
8112         CHECK_NULL_CONTINUE(node);
8113         if (auto& tag = node->GetTag(); tag == V2::IMAGE_ETS_TAG || tag == V2::PLACEHOLDER_SPAN_ETS_TAG) {
8114             imageChildren.emplace_back(node);
8115         }
8116     }
8117     TextDragInfo info;
8118     info.maxSelectedWidth = GetMaxSelectedWidth();
8119     info.handleColor = GetCaretColor();
8120     info.selectedBackgroundColor = GetSelectedBackgroundColor();
8121     auto selectOverlayInfo = selectOverlay_->GetSelectOverlayInfo();
8122     if (selectOverlayInfo.has_value()) {
8123         if (selectOverlayInfo->firstHandle.isShow) {
8124             info.firstHandle = selectOverlayInfo->firstHandle.paintRect;
8125         }
8126         if (selectOverlayInfo->secondHandle.isShow) {
8127             info.secondHandle =  selectOverlayInfo->secondHandle.paintRect;
8128         }
8129     }
8130     if (textSelector_.GetTextEnd() - textSelector_.GetTextStart() == 1) {
8131         auto spanItem = GetSpanItemByPosition(textSelector_.GetTextStart());
8132         auto placeholderSpanItem = DynamicCast<PlaceholderSpanItem>(spanItem);
8133         if (placeholderSpanItem) {
8134             info.dragBackgroundColor = placeholderSpanItem->dragBackgroundColor_;
8135             info.isDragShadowNeeded = placeholderSpanItem->isDragShadowNeeded_;
8136         }
8137     }
8138     dragNode_ = RichEditorDragPattern::CreateDragNode(host, imageChildren, info);
8139     CHECK_NULL_VOID(dragNode_);
8140     InitDragShadow(host, dragNode_, info.isDragShadowNeeded, info.dragBackgroundColor.has_value());
8141     FrameNode::ProcessOffscreenNode(dragNode_);
8142 }
8143 
8144 float RichEditorPattern::GetMaxSelectedWidth()
8145 {
8146     auto boxes = paragraphs_.GetRects(textSelector_.GetTextStart(), textSelector_.GetTextEnd());
8147     CHECK_NULL_RETURN(!boxes.empty(), 0.0f);
8148     float startX = boxes.front().Left();
8149     float endX = boxes.front().Right();
8150     for (const auto& box : boxes) {
8151         startX = std::min(startX, box.Left());
8152         endX = std::max(endX, box.Right());
8153     }
8154     startX = std::min(0.0f, startX);
8155     return std::abs(startX - endX);
8156 }
8157 
8158 void RichEditorPattern::InitDragShadow(const RefPtr<FrameNode>& host, const RefPtr<FrameNode>& dragNode,
8159     bool isDragShadowNeeded, bool hasDragBackgroundColor)
8160 {
8161     CHECK_NULL_VOID(host && dragNode);
8162     auto textDragPattern = dragNode->GetPattern<TextDragPattern>();
8163     CHECK_NULL_VOID(textDragPattern);
8164     auto option = host->GetDragPreviewOption();
8165     if (isDragShadowNeeded) {
8166         option.options.shadowPath = textDragPattern->GetBackgroundPath()->ConvertToSVGString();
8167         option.options.shadow = Shadow(RICH_DEFAULT_ELEVATION, {0.0, 0.0}, Color(RICH_DEFAULT_SHADOW_COLOR),
8168             ShadowStyle::OuterFloatingSM);
8169         option.options.isFilled = !hasDragBackgroundColor;
8170     } else {
8171         option.options.shadowPath.clear();
8172         option.options.shadow.reset();
8173         option.options.isFilled = true;
8174     }
8175     host->SetDragPreviewOptions(option);
8176 }
8177 
8178 void RichEditorPattern::CreateHandles()
8179 {
8180     if (IsDragging()) {
8181         TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "do not show handles when dragging");
8182         return;
8183     }
8184     auto host = GetHost();
8185     CHECK_NULL_VOID(host);
8186     CalculateHandleOffsetAndShowOverlay();
8187     selectOverlay_->ProcessOverlay({ .menuIsShow = selectOverlay_->IsCurrentMenuVisibile(), .animation = true });
8188 }
8189 
8190 void RichEditorPattern::ShowHandles(const bool isNeedShowHandles)
8191 {
8192     if (!IsSelected()) {
8193         showSelect_ = true;
8194         IF_TRUE(isEditing_, StartTwinkling());
8195         return;
8196     }
8197     ShowHandles();
8198 }
8199 
8200 void RichEditorPattern::ShowHandles()
8201 {
8202     auto host = GetHost();
8203     CHECK_NULL_VOID(host);
8204     if (!selectOverlay_->IsBothHandlesShow() && !selectOverlay_->SelectOverlayIsCreating()) {
8205         showSelect_ = true;
8206         host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
8207         CHECK_NULL_VOID(textSelector_.IsValid());
8208         CHECK_NULL_VOID(!isMouseSelect_);
8209         CalculateHandleOffsetAndShowOverlay();
8210         selectOverlay_->ProcessOverlay({.menuIsShow = false, .animation = false});
8211     }
8212 }
8213 
8214 void RichEditorPattern::OnAreaChangedInner()
8215 {
8216     auto host = GetHost();
8217     CHECK_NULL_VOID(host);
8218     auto context = host->GetContext();
8219     CHECK_NULL_VOID(context);
8220     auto prevParentGlobalOffset = parentGlobalOffset_;
8221     UpdateParentOffsetAndOverlay();
8222     IF_TRUE(parentGlobalOffset_ != prevParentGlobalOffset,
8223         UpdateTextFieldManager(Offset(parentGlobalOffset_.GetX(), parentGlobalOffset_.GetY()), frameRect_.Height()));
8224     IF_TRUE(parentGlobalOffset_ != prevParentGlobalOffset, UpdateCaretInfoToController());
8225 }
8226 
8227 void RichEditorPattern::UpdateParentOffsetAndOverlay()
8228 {
8229     auto parentGlobalOffset = GetPaintRectGlobalOffset(); // offset on screen(with transformation)
8230     CHECK_NULL_VOID(parentGlobalOffset != parentGlobalOffset_);
8231     parentGlobalOffset_ = parentGlobalOffset;
8232     OnParentOffsetChange();
8233     selectOverlay_->UpdateSelectOverlayOnAreaChanged();
8234 }
8235 
8236 
8237 void RichEditorPattern::OnParentOffsetChange()
8238 {
8239     auto context = GetContext();
8240     CHECK_NULL_VOID(context);
8241     auto overlayManager = context->GetOverlayManager();
8242     IF_PRESENT(overlayManager, CloseAIEntityMenu(frameId_));
8243 }
8244 
8245 void RichEditorPattern::CloseSelectionMenu()
8246 {
8247     // used by sdk
8248     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "CloseSelectionMenu");
8249     CloseSelectOverlay();
8250 }
8251 
8252 void RichEditorPattern::OnDragNodeFloating()
8253 {
8254     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "OnDragNodeFloating");
8255     status_ = Status::FLOATING;
8256 }
8257 
8258 void RichEditorPattern::CloseSelectOverlay()
8259 {
8260     // used by inner
8261     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "CloseSelectOverlay");
8262     selectOverlay_->CloseOverlay(true, CloseReason::CLOSE_REASON_NORMAL);
8263 }
8264 
8265 void RichEditorPattern::CloseHandleAndSelect()
8266 {
8267     selectOverlay_->CloseOverlay(false, CloseReason::CLOSE_REASON_DRAG_FLOATING);
8268     showSelect_ = false;
8269     auto host = GetHost();
8270     IF_PRESENT(host, MarkDirtyNode(PROPERTY_UPDATE_RENDER));
8271 }
8272 
8273 void RichEditorPattern::CalculateHandleOffsetAndShowOverlay(bool isUsingMouse)
8274 {
8275     auto globalOffset = GetGlobalOffset();
8276     if (!selectOverlay_->GetIsHandleMoving()) {
8277         textSelector_.ReverseTextSelector();
8278     }
8279     int32_t baseOffset = std::min(textSelector_.baseOffset, GetTextContentLength());
8280     int32_t destinationOffset = std::min(textSelector_.destinationOffset, GetTextContentLength());
8281     SizeF firstHandlePaintSize;
8282     SizeF secondHandlePaintSize;
8283     OffsetF firstHandleOffset;
8284     OffsetF secondHandleOffset;
8285     auto isSingleHandle = IsSingleHandle();
8286     selectOverlay_->SetIsSingleHandle(isSingleHandle);
8287     if (isSingleHandle) {
8288         auto [caretOffset, caretHeight] = CalculateCaretOffsetAndHeight();
8289         // only show the second handle.
8290         secondHandlePaintSize = { SelectHandleInfo::GetDefaultLineWidth().ConvertToPx(), caretHeight };
8291         secondHandleOffset = caretOffset + globalOffset;
8292     } else {
8293         float startSelectHeight = 0.0f;
8294         float endSelectHeight = 0.0f;
8295         auto startOffset = CalcCursorOffsetByPosition(baseOffset, startSelectHeight, true, false);
8296         auto endOffset = CalcCursorOffsetByPosition(destinationOffset, endSelectHeight, false, false);
8297         firstHandlePaintSize = { SelectHandleInfo::GetDefaultLineWidth().ConvertToPx(), startSelectHeight };
8298         secondHandlePaintSize = { SelectHandleInfo::GetDefaultLineWidth().ConvertToPx(), endSelectHeight };
8299         firstHandleOffset = startOffset + globalOffset;
8300         secondHandleOffset = endOffset + globalOffset;
8301         firstHandleOffset.SetX(firstHandleOffset.GetX() - firstHandlePaintSize.Width() / 2.0f);
8302         secondHandleOffset.SetX(secondHandleOffset.GetX() - secondHandlePaintSize.Width() / 2.0f);
8303     }
8304     textSelector_.selectionBaseOffset = firstHandleOffset;
8305     textSelector_.selectionDestinationOffset = secondHandleOffset;
8306     textSelector_.firstHandle = RectF{ firstHandleOffset, firstHandlePaintSize };
8307     textSelector_.secondHandle = RectF{ secondHandleOffset, secondHandlePaintSize };
8308 }
8309 
8310 void RichEditorPattern::CalculateDefaultHandleHeight(float& height)
8311 {
8312 #ifdef ENABLE_ROSEN_BACKEND
8313     MeasureContext content;
8314     content.textContent = "a";
8315     content.fontSize = TEXT_DEFAULT_FONT_SIZE;
8316     auto fontweight = StringUtils::FontWeightToString(FontWeight::NORMAL);
8317     content.fontWeight = fontweight;
8318     height = std::max(static_cast<float>(RosenRenderCustomPaint::MeasureTextSizeInner(content).Height()), 0.0f);
8319 #endif
8320 }
8321 
8322 OffsetF RichEditorPattern::GetGlobalOffset() const
8323 {
8324     auto host = GetHost();
8325     CHECK_NULL_RETURN(host, OffsetF());
8326     auto pipeline = host->GetContext();
8327     CHECK_NULL_RETURN(pipeline, OffsetF());
8328     auto rootOffset = pipeline->GetRootRect().GetOffset();
8329     auto richEditorPaintOffset = host->GetPaintRectOffsetNG(false, true);
8330     if (selectOverlay_->HasRenderTransform()) {
8331         richEditorPaintOffset = selectOverlay_->GetPaintOffsetWithoutTransform();
8332     }
8333     return richEditorPaintOffset - rootOffset;
8334 }
8335 
8336 bool RichEditorPattern::IsSingleHandle()
8337 {
8338     CHECK_NULL_RETURN(!selectOverlay_->GetIsHandleMoving(), selectOverlay_->IsSingleHandle());
8339     return GetTextContentLength() == 0 || !IsSelected();
8340 }
8341 
8342 bool RichEditorPattern::IsHandlesShow()
8343 {
8344     return selectOverlay_->IsBothHandlesShow();
8345 }
8346 
8347 void RichEditorPattern::ResetSelection()
8348 {
8349     bool selectNothing = textSelector_.SelectNothing();
8350     textSelector_.Update(-1, -1);
8351     if (!selectNothing) {
8352         TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "ResetSelection");
8353         auto host = GetHost();
8354         CHECK_NULL_VOID(host);
8355         auto eventHub = host->GetEventHub<RichEditorEventHub>();
8356         CHECK_NULL_VOID(eventHub);
8357         auto textSelectInfo = GetSpansInfo(-1, -1, GetSpansMethod::ONSELECT);
8358         eventHub->FireOnSelect(&textSelectInfo);
8359         UpdateSelectionType(textSelectInfo);
8360         host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
8361     }
8362 }
8363 
8364 bool RichEditorPattern::BetweenSelection(const Offset& globalOffset)
8365 {
8366     return InRangeRect(globalOffset, { textSelector_.GetTextStart(), textSelector_.GetTextEnd() });
8367 }
8368 
8369 bool RichEditorPattern::InRangeRect(const Offset& globalOffset, const std::pair<int32_t, int32_t>& range)
8370 {
8371     auto host = GetHost();
8372     CHECK_NULL_RETURN(host, false);
8373     CHECK_NULL_RETURN(0 <= range.first && range.first < range.second, false);
8374     auto offset = host->GetPaintRectOffsetNG(false, true);
8375     auto localOffset = globalOffset - Offset(offset.GetX(), offset.GetY());
8376     if (selectOverlay_->HasRenderTransform()) {
8377         localOffset = ConvertGlobalToLocalOffset(globalOffset);
8378     }
8379     auto eventHub = host->GetEventHub<EventHub>();
8380     if (GreatNotEqual(range.second, range.first)) {
8381         // Determine if the pan location is in the selected area
8382         auto rangeRects = paragraphs_.GetRects(range.first, range.second);
8383         auto panOffset = OffsetF(localOffset.GetX(), localOffset.GetY()) - GetTextRect().GetOffset() +
8384                          OffsetF(0.0, std::min(baselineOffset_, 0.0f));
8385         for (const auto& rangeRect : rangeRects) {
8386             if (rangeRect.IsInRegion(PointF(panOffset.GetX(), panOffset.GetY()))) {
8387                 return true;
8388             }
8389         }
8390     }
8391     return false;
8392 }
8393 
8394 bool RichEditorPattern::BetweenSelectedPosition(const Offset& globalOffset)
8395 {
8396     return copyOption_ != CopyOptions::None && BetweenSelection(globalOffset);
8397 }
8398 
8399 void RichEditorPattern::HandleSurfaceChanged(
8400     int32_t newWidth, int32_t newHeight, int32_t prevWidth, int32_t prevHeight, WindowSizeChangeReason type)
8401 {
8402     if (newWidth != prevWidth || newHeight != prevHeight) {
8403         TextPattern::HandleSurfaceChanged(newWidth, newHeight, prevWidth, prevHeight, type);
8404         UpdateOriginIsMenuShow(false);
8405     }
8406     UpdateCaretInfoToController();
8407     if (magnifierController_) {
8408         magnifierController_->RemoveMagnifierFrameNode();
8409     }
8410 }
8411 
8412 void RichEditorPattern::HandleSurfacePositionChanged(int32_t posX, int32_t posY)
8413 {
8414     UpdateCaretInfoToController();
8415 }
8416 
8417 void RichEditorPattern::DumpInfo()
8418 {
8419     auto& dumpLog = DumpLog::GetInstance();
8420     if (customKeyboardBuilder_) {
8421         dumpLog.AddDesc(std::string("CustomKeyboard, Attached: ").append(std::to_string(isCustomKeyboardAttached_)));
8422     }
8423     auto host = GetHost();
8424     CHECK_NULL_VOID(host);
8425     auto richEditorTheme = GetTheme<RichEditorTheme>();
8426     CHECK_NULL_VOID(richEditorTheme);
8427     dumpLog.AddDesc(std::string("caret offset: ").append(GetCaretRect().GetOffset().ToString()));
8428     dumpLog.AddDesc(std::string("caret height: ")
8429             .append(std::to_string(NearZero(GetCaretRect().Height())
8430                                        ? richEditorTheme->GetDefaultCaretHeight().ConvertToPx()
8431                                        : GetCaretRect().Height())));
8432     dumpLog.AddDesc(std::string("text rect: ").append(richTextRect_.ToString()));
8433     dumpLog.AddDesc(std::string("content rect: ").append(contentRect_.ToString()));
8434     auto richEditorPaintOffset = host->GetPaintRectOffsetNG(false, true);
8435     bool hasRenderTransform = selectOverlay_->HasRenderTransform();
8436     if (hasRenderTransform) {
8437         richEditorPaintOffset = selectOverlay_->GetPaintOffsetWithoutTransform();
8438     }
8439     dumpLog.AddDesc(std::string("hasRenderTransform: ").append(std::to_string(hasRenderTransform)));
8440     dumpLog.AddDesc(std::string("richEditorPaintOffset: ").append(richEditorPaintOffset.ToString()));
8441     auto selectOverlayInfo = selectOverlay_->GetSelectOverlayInfo();
8442     CHECK_NULL_VOID(selectOverlayInfo);
8443     dumpLog.AddDesc(std::string("selectOverlay info: ").append(selectOverlayInfo->ToString()));
8444     dumpLog.AddDesc(std::string("IsAIWrite: ").append(std::to_string(IsShowAIWrite())));
8445     dumpLog.AddDesc(std::string("keyboardAppearance: ")
8446             .append(std::to_string(static_cast<int32_t>(keyboardAppearance_))));
8447 }
8448 
8449 void RichEditorPattern::RichEditorErrorReport(RichEditorInfo& info)
8450 {
8451     auto pipeline = GetContext();
8452     CHECK_NULL_VOID(pipeline);
8453     auto taskExecutor = pipeline->GetTaskExecutor();
8454     CHECK_NULL_VOID(taskExecutor);
8455     taskExecutor->PostTask(
8456         [info] {
8457             EventReport::ReportRichEditorInfo(info);
8458         },
8459         TaskExecutor::TaskType::BACKGROUND, "ArkUIRichEditorErrorReport");
8460 }
8461 
8462 bool RichEditorPattern::HasFocus() const
8463 {
8464     auto focusHub = GetFocusHub();
8465     CHECK_NULL_RETURN(focusHub, false);
8466     return focusHub->IsCurrentFocus();
8467 }
8468 
8469 void RichEditorPattern::UpdateTextFieldManager(const Offset& offset, float height)
8470 {
8471     if (!HasFocus()) {
8472         return;
8473     }
8474     auto context = GetHost()->GetContext();
8475     CHECK_NULL_VOID(context);
8476     auto richEditorTheme = context->GetTheme<RichEditorTheme>();
8477     CHECK_NULL_VOID(richEditorTheme);
8478     auto textFieldManager = DynamicCast<TextFieldManagerNG>(context->GetTextFieldManager());
8479     CHECK_NULL_VOID(textFieldManager);
8480     auto safeAreaManager = context->GetSafeAreaManager();
8481     CHECK_NULL_VOID(safeAreaManager);
8482     auto [caretOffset, caretHeight] = CalculateCaretOffsetAndHeight();
8483     textFieldManager->SetClickPosition({ offset.GetX() + caretOffset.GetX(), offset.GetY() + caretOffset.GetY() });
8484     textFieldManager->SetHeight(NearZero(caretHeight)
8485                                     ? richEditorTheme->GetDefaultCaretHeight().ConvertToPx()
8486                                     : caretHeight);
8487     textFieldManager->SetClickPositionOffset(safeAreaManager->GetKeyboardOffset());
8488     textFieldManager->SetOnFocusTextField(WeakClaim(this));
8489     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_FOURTEEN)) {
8490         textFieldManager->SetUsingCustomKeyboardAvoid(keyboardAvoidance_);
8491     }
8492     if (!isTextChange_) {
8493         return;
8494     }
8495     auto taskExecutor = context->GetTaskExecutor();
8496     CHECK_NULL_VOID(taskExecutor);
8497     taskExecutor->PostTask(
8498         [weak = WeakClaim(this)] {
8499             auto pattern = weak.Upgrade();
8500             CHECK_NULL_VOID(pattern);
8501             pattern->ScrollToSafeArea();
8502         },
8503         TaskExecutor::TaskType::UI, "ArkUIRichEditorScrollToSafeArea", PriorityType::VIP);
8504 }
8505 
8506 bool RichEditorPattern::IsDisabled() const
8507 {
8508     auto eventHub = GetEventHub<RichEditorEventHub>();
8509     CHECK_NULL_RETURN(eventHub, true);
8510     return !eventHub->IsEnabled();
8511 }
8512 
8513 void RichEditorPattern::MouseDoubleClickParagraphEnd(int32_t& index)
8514 {
8515     bool isMouseDoubleClick = caretUpdateType_ == CaretUpdateType::DOUBLE_CLICK && sourceType_ == SourceType::MOUSE;
8516     CHECK_NULL_VOID(isMouseDoubleClick);
8517     auto paragraphEndPos = GetParagraphEndPosition(index);
8518     auto paragraphBeginPos = GetParagraphBeginPosition(index);
8519     bool isBeginEqualEnd = paragraphBeginPos == paragraphEndPos;
8520     CHECK_NULL_VOID(!isBeginEqualEnd);
8521     if (index == paragraphEndPos) {
8522         index -= 1;
8523     }
8524 }
8525 
8526 void RichEditorPattern::AdjustSelectionExcludeSymbol(int32_t& start, int32_t& end)
8527 {
8528     AdjustSelectorForSymbol(start, HandleType::FIRST, SelectorAdjustPolicy::EXCLUDE);
8529     AdjustSelectorForSymbol(end, HandleType::SECOND, SelectorAdjustPolicy::EXCLUDE);
8530 }
8531 
8532 void RichEditorPattern::InitSelection(const Offset& pos)
8533 {
8534     auto [currentPosition, selectType] = JudgeSelectType(pos);
8535     switch (selectType) {
8536         case SelectType::SELECT_NOTHING:
8537             TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "select nothing currentPos=%{public}d", currentPosition);
8538             textSelector_.Update(currentPosition, currentPosition);
8539             return;
8540         case SelectType::SELECT_BACKWARD:
8541             currentPosition = std::max(0, currentPosition - 1);
8542             break;
8543         case SelectType::SELECT_FORWARD:
8544             break;
8545         default:
8546             TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "exception select type");
8547     }
8548     int32_t nextPosition = std::min(currentPosition + 1, GetTextContentLength());
8549     AdjustSelectionExcludeSymbol(currentPosition, nextPosition);
8550     if (!IsCustomSpanInCaretPos(currentPosition, true)) {
8551         AdjustWordSelection(currentPosition, nextPosition);
8552     }
8553     AdjustSelector(currentPosition, nextPosition);
8554     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "init select [%{public}d--%{public}d]", currentPosition, nextPosition);
8555     textSelector_.Update(currentPosition, nextPosition);
8556     if (IsSelectEmpty(currentPosition, nextPosition)) {
8557         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "select rect is empty, select nothing");
8558         textSelector_.Update(currentPosition, currentPosition);
8559     }
8560 }
8561 
8562 std::pair<int32_t, SelectType> RichEditorPattern::JudgeSelectType(const Offset& pos)
8563 {
8564     auto positionWithAffinity = paragraphs_.GetGlyphPositionAtCoordinate(pos);
8565     auto currentPosition = (GetTextContentLength() == 0) ? 0 : static_cast<int32_t>(positionWithAffinity.position_);
8566     auto selectType = SelectType::SELECT_NOTHING;
8567     CHECK_NULL_RETURN(GetTextContentLength() != 0, std::make_pair(currentPosition, selectType));
8568     bool isNeedSkipLineSeparator = !editingLongPress_ && IsSelectEmpty(currentPosition, currentPosition + 1);
8569     if (isNeedSkipLineSeparator && AdjustIndexSkipLineSeparator(currentPosition)) {
8570         return std::make_pair(currentPosition, SelectType::SELECT_BACKWARD);
8571     }
8572     auto height = paragraphs_.GetHeight();
8573     if (GreatNotEqual(pos.GetY(), height)) {
8574         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "touchPosY[%{public}f] > paragraphsHeight[%{public}f]", pos.GetY(), height);
8575         IF_TRUE(!editingLongPress_, selectType = SelectType::SELECT_BACKWARD);
8576         return std::make_pair(GetTextContentLength(), selectType);
8577     }
8578     TextAffinity currentAffinity = positionWithAffinity.affinity_;
8579     bool isTouchLineEnd = currentAffinity == TextAffinity::UPSTREAM && !IsTouchBeforeCaret(currentPosition, pos);
8580     if (editingLongPress_ && isTouchLineEnd) {
8581         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "touchLineEnd select nothing currentAffinity=%{public}d", currentAffinity);
8582         return std::make_pair(currentPosition, selectType);
8583     }
8584     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "currentPosition=%{public}d, currentAffinity=%{public}d",
8585         currentPosition, currentAffinity);
8586     selectType = (currentAffinity == TextAffinity::UPSTREAM) ? SelectType::SELECT_BACKWARD : SelectType::SELECT_FORWARD;
8587     return std::make_pair(currentPosition, selectType);
8588 }
8589 
8590 bool RichEditorPattern::IsSelectEmpty(int32_t start, int32_t end)
8591 {
8592     auto selectedRects = paragraphs_.GetRects(start, end);
8593     return selectedRects.empty() || (selectedRects.size() == 1 && NearZero((selectedRects[0].Width())));
8594 }
8595 
8596 bool RichEditorPattern::AdjustIndexSkipLineSeparator(int32_t& currentPosition)
8597 {
8598     std::u16string contentText;
8599     for (auto iter = spans_.cbegin(); iter != spans_.cend(); iter++) {
8600         contentText.append((*iter)->content);
8601         CHECK_NULL_BREAK(currentPosition > (*iter)->position);
8602     }
8603     auto contentLength = static_cast<int32_t>(contentText.length());
8604     if (currentPosition > contentLength) {
8605         TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "currentPosition=%{public}d but contentLength=%{public}d",
8606             currentPosition, contentLength);
8607         return false;
8608     }
8609     auto index = currentPosition - 1;
8610     while (index > 0) {
8611         CHECK_NULL_BREAK(contentText[index] == u'\n');
8612         index--;
8613     }
8614     if (index != currentPosition - 1) {
8615         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "skip lineSeparator %{public}d->%{public}d", currentPosition, index + 1);
8616         currentPosition = index + 1;
8617         return true;
8618     }
8619     return false;
8620 }
8621 
8622 bool RichEditorPattern::AdjustIndexSkipSpace(int32_t& currentPosition, const MoveDirection direction)
8623 {
8624     bool isBackward = (direction == MoveDirection::BACKWARD);
8625     std::u16string contentText;
8626     GetContentBySpans(contentText);
8627     auto contentLength = static_cast<int32_t>(contentText.length());
8628     bool isPositionInvalid = (isBackward && currentPosition == 0) || (!isBackward && currentPosition == contentLength);
8629     if (isPositionInvalid) {
8630         TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "AdjustIndexSkipSpace position=%{public}d but contentLength=%{public}d",
8631             currentPosition, contentLength);
8632         return false;
8633     }
8634     int32_t index = isBackward ? (currentPosition - 1) : currentPosition;
8635     while (isBackward ? index >= 0 : index < contentLength) {
8636         CHECK_NULL_BREAK(contentText[index] == u' ' && GetSpanType(index) == SpanItemType::NORMAL);
8637         isBackward ? index-- : index++;
8638     }
8639     int32_t adjustedIndex = isBackward ? (index + 1) : index;
8640     if (adjustedIndex != currentPosition) {
8641         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "skip space %{public}d->%{public}d", currentPosition, adjustedIndex);
8642         currentPosition = adjustedIndex;
8643         return true;
8644     }
8645     return false;
8646 }
8647 
8648 bool RichEditorPattern::ResetOnInvalidSelection(int32_t start, int32_t end)
8649 {
8650     if (start < end) {
8651         return false;
8652     }
8653     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "SetSelection failed, the selected area is empty.");
8654     CloseSelectOverlay();
8655     ResetSelection();
8656     StartTwinkling();
8657     return true;
8658 }
8659 
8660 bool RichEditorPattern::IsShowHandle()
8661 {
8662     auto richEditorTheme = GetTheme<RichEditorTheme>();
8663     CHECK_NULL_RETURN(richEditorTheme, false);
8664     return !richEditorTheme->IsRichEditorShowHandle();
8665 }
8666 
8667 void RichEditorPattern::UpdateSelectionInfo(int32_t start, int32_t end)
8668 {
8669     UpdateSelectionType(GetSpansInfo(start, end, GetSpansMethod::ONSELECT));
8670     auto selectOverlayInfo = selectOverlay_->GetSelectOverlayInfo();
8671     textResponseType_ = selectOverlayInfo
8672                         ? static_cast<TextResponseType>(selectOverlayInfo->menuInfo.responseType.value_or(0))
8673                         : TextResponseType::LONG_PRESS;
8674     if (IsShowHandle() && !IsUsingMouse()) {
8675         ResetIsMousePressed();
8676         sourceType_ = SourceType::TOUCH;
8677     }
8678 }
8679 
8680 void RichEditorPattern::SetSelection(int32_t start, int32_t end, const std::optional<SelectionOptions>& options,
8681     bool isForward)
8682 {
8683     bool hasFocus = HasFocus();
8684     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "setSelection, range=[%{public}d,%{public}d], hasFocus=%{public}d, "
8685         "isEditing=%{public}d", start, end, hasFocus, isEditing_);
8686     CHECK_NULL_VOID(hasFocus);
8687     if (IsPreviewTextInputting()) {
8688         TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "SetSelection failed for previewText inputting");
8689         return;
8690     }
8691     if (start == -1 && end == -1) {
8692         start = 0;
8693         end = GetTextContentLength();
8694     } else {
8695         start = std::clamp(start, 0, GetTextContentLength());
8696         end = std::clamp(end, 0, GetTextContentLength());
8697     }
8698     CHECK_NULL_VOID(!ResetOnInvalidSelection(start, end));
8699     UpdateSelector(start, end);
8700 
8701     if (textSelector_.IsValid() && !textSelector_.StartEqualToDest()) {
8702         StopTwinkling();
8703         if (start != textSelector_.GetTextStart() || end != textSelector_.GetTextEnd()) {
8704             FireOnSelect(textSelector_.GetTextStart(), textSelector_.GetTextEnd());
8705         }
8706     }
8707     SetCaretPosition(isForward ? textSelector_.GetTextStart() : textSelector_.GetTextEnd());
8708     MoveCaretToContentRect();
8709     CalculateHandleOffsetAndShowOverlay();
8710     UpdateSelectionInfo(textSelector_.GetTextStart(), textSelector_.GetTextEnd());
8711     ProcessOverlayOnSetSelection(options);
8712     auto host = GetHost();
8713     CHECK_NULL_VOID(host);
8714     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
8715 }
8716 
8717 void RichEditorPattern::ProcessOverlayOnSetSelection(const std::optional<SelectionOptions>& options)
8718 {
8719     if (!IsShowHandle()) {
8720         CloseSelectOverlay();
8721     } else if (!options.has_value() || options.value().menuPolicy == MenuPolicy::DEFAULT) {
8722         selectOverlay_->ProcessOverlay({ .menuIsShow = selectOverlay_->IsCurrentMenuVisibile(),
8723             .animation = true, .requestCode = REQUEST_RECREATE });
8724         IF_PRESENT(magnifierController_, RemoveMagnifierFrameNode());
8725     } else if (options.value().menuPolicy == MenuPolicy::HIDE) {
8726         if (selectOverlay_->IsUsingMouse()) {
8727             CloseSelectOverlay();
8728         } else {
8729             selectOverlay_->ProcessOverlay({ .menuIsShow = false, .animation = true });
8730         }
8731     } else if (options.value().menuPolicy == MenuPolicy::SHOW) {
8732         if (selectOverlay_->IsUsingMouse() || sourceType_ == SourceType::MOUSE) {
8733             selectionMenuOffsetByMouse_ = selectionMenuOffsetClick_;
8734         }
8735         selectOverlay_->ProcessOverlay({ .animation = true, .requestCode = REQUEST_RECREATE });
8736         IF_PRESENT(magnifierController_, RemoveMagnifierFrameNode());
8737     }
8738 }
8739 
8740 void RichEditorPattern::BindSelectionMenu(TextResponseType type, TextSpanType richEditorType,
8741     std::function<void()>& menuBuilder, const SelectMenuParam& menuParam)
8742 {
8743     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "BindSelectionMenu spanType = %{public}d, responseType = %{public}d",
8744         richEditorType, type);
8745     TextPattern::BindSelectionMenu(richEditorType, type, menuBuilder, menuParam);
8746 }
8747 
8748 RefPtr<NodePaintMethod> RichEditorPattern::CreateNodePaintMethod()
8749 {
8750     if (!contentMod_) {
8751         contentMod_ = MakeRefPtr<RichEditorContentModifier>(textStyle_, &paragraphs_, WeakClaim(this));
8752     }
8753     if (!overlayMod_) {
8754         auto scrollBar = GetScrollBar();
8755         if (scrollBar) {
8756             auto scrollBarModifier = AceType::MakeRefPtr<ScrollBarOverlayModifier>();
8757             scrollBarModifier->SetRect(scrollBar->GetActiveRect());
8758             scrollBarModifier->SetPositionMode(scrollBar->GetPositionMode());
8759             SetScrollBarOverlayModifier(scrollBarModifier);
8760         }
8761         SetEdgeEffect(EdgeEffect::FADE, GetAlwaysEnabled());
8762         SetEdgeEffect();
8763         overlayMod_ = AceType::MakeRefPtr<RichEditorOverlayModifier>(
8764             WeakClaim(this), GetScrollBarOverlayModifier(), GetScrollEdgeEffect());
8765     }
8766 
8767     if (GetIsCustomFont()) {
8768         contentMod_->SetIsCustomFont(true);
8769     }
8770     return MakeRefPtr<RichEditorPaintMethod>(WeakClaim(this), &paragraphs_, baselineOffset_, contentMod_, overlayMod_);
8771 }
8772 
8773 int32_t RichEditorPattern::GetHandleIndex(const Offset& offset) const
8774 {
8775     CHECK_NULL_RETURN(!isShowPlaceholder_, 0);
8776     return paragraphs_.GetIndex(Offset(offset.GetX() + contentRect_.GetX() - richTextRect_.GetX(),
8777         offset.GetY() + contentRect_.GetY() - richTextRect_.GetY()));
8778 }
8779 
8780 std::vector<RectF> RichEditorPattern::GetTextBoxes()
8781 {
8782     auto selectedRects = paragraphs_.GetRects(textSelector_.GetTextStart(), textSelector_.GetTextEnd());
8783     std::vector<RectF> res;
8784     res.reserve(selectedRects.size());
8785     for (auto&& rect : selectedRects) {
8786         res.emplace_back(rect);
8787     }
8788     if (!res.empty() && paragraphs_.IsSelectLineHeadAndUseLeadingMargin(textSelector_.GetTextStart())) {
8789         // To make drag screenshot include LeadingMarginPlaceholder when not single line
8790         if (res.front().GetY() != res.back().GetY()) {
8791             res.front().SetLeft(0.0f);
8792         }
8793     }
8794     return res;
8795 }
8796 
8797 float RichEditorPattern::GetLineHeight() const
8798 {
8799     auto selectedRects = paragraphs_.GetRects(textSelector_.GetTextStart(), textSelector_.GetTextEnd());
8800     CHECK_NULL_RETURN(selectedRects.size(), 0.0f);
8801     return selectedRects.front().Height();
8802 }
8803 
8804 size_t RichEditorPattern::GetLineCount() const
8805 {
8806     return paragraphs_.GetLineCount();
8807 }
8808 
8809 TextLineMetrics RichEditorPattern::GetLineMetrics(int32_t lineNumber)
8810 {
8811     if (lineNumber < 0 || GetLineCount() == 0 || static_cast<uint32_t>(lineNumber) > GetLineCount() - 1) {
8812         TAG_LOGE(AceLogTag::ACE_RICH_TEXT,
8813                 "GetLineMetrics failed, lineNumber not between 0 and max lines:%{public}d", lineNumber);
8814         return TextLineMetrics();
8815     }
8816     auto lineMetrics = paragraphs_.GetLineMetrics(lineNumber);
8817     const auto& textRect = GetTextRect();
8818     lineMetrics.x += textRect.GetX();
8819     lineMetrics.y += textRect.GetY();
8820     lineMetrics.baseline += textRect.GetY();
8821     return lineMetrics;
8822 }
8823 
8824 std::vector<ParagraphManager::TextBox> RichEditorPattern::GetRectsForRange(
8825     int32_t start, int32_t end, RectHeightStyle heightStyle, RectWidthStyle widthStyle)
8826 {
8827     if (start < 0 || end < 0 || start > end) {
8828         return {};
8829     }
8830     std::vector<ParagraphManager::TextBox> textBoxes =
8831         paragraphs_.GetRectsForRange(start, end, heightStyle, widthStyle);
8832     const auto& textRect = richTextRect_;
8833     std::vector<ParagraphManager::TextBox> adjustedTextBoxes;
8834     for (auto& textBox : textBoxes) {
8835         ParagraphManager::TextBox adjustedTextBox = textBox;
8836         adjustedTextBox.rect_.SetLeft(textBox.rect_.Left() + textRect.Left());
8837         adjustedTextBox.rect_.SetTop(textBox.rect_.Top() + textRect.Top());
8838         adjustedTextBoxes.push_back(adjustedTextBox);
8839     }
8840     return adjustedTextBoxes;
8841 }
8842 
8843 float RichEditorPattern::GetLetterSpacing() const
8844 {
8845     auto selectedRects = paragraphs_.GetRects(textSelector_.GetTextStart(), textSelector_.GetTextEnd());
8846     CHECK_NULL_RETURN(!selectedRects.empty(), 0.0f);
8847     return selectedRects.front().Width();
8848 }
8849 
8850 void RichEditorPattern::UpdateSelectMenuInfo(SelectMenuInfo& menuInfo)
8851 {
8852     bool isSupportCameraInput = false;
8853 #if defined(ENABLE_STANDARD_INPUT)
8854     auto inputMethod = MiscServices::InputMethodController::GetInstance();
8855     isSupportCameraInput =
8856         inputMethod && inputMethod->IsInputTypeSupported(MiscServices::InputType::CAMERA_INPUT);
8857 #endif
8858     menuInfo.showCameraInput = !IsSelected() && isSupportCameraInput && !customKeyboardBuilder_;
8859     if (textResponseType_.has_value()) {
8860         menuInfo.responseType = static_cast<int32_t>(textResponseType_.value());
8861     }
8862 }
8863 
8864 RectF RichEditorPattern::GetCaretRect() const
8865 {
8866     RectF rect;
8867     CHECK_NULL_RETURN(overlayMod_, rect);
8868     auto richEditorOverlay = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
8869     CHECK_NULL_RETURN(richEditorOverlay, rect);
8870     rect.SetOffset(richEditorOverlay->GetCaretOffset());
8871     rect.SetHeight(richEditorOverlay->GetCaretHeight());
8872     return rect;
8873 }
8874 
8875 void RichEditorPattern::ScrollToSafeArea() const
8876 {
8877     auto host = GetHost();
8878     CHECK_NULL_VOID(host);
8879     auto pipeline = host->GetContext();
8880     CHECK_NULL_VOID(pipeline);
8881     if (pipeline->UsingCaretAvoidMode()) {
8882         // using TriggerAvoidOnCaretChange instead in CaretAvoidMode
8883         return;
8884     }
8885     auto textFieldManager = DynamicCast<TextFieldManagerNG>(pipeline->GetTextFieldManager());
8886     CHECK_NULL_VOID(textFieldManager);
8887     textFieldManager->ScrollTextFieldToSafeArea();
8888 }
8889 
8890 void RichEditorPattern::InitScrollablePattern()
8891 {
8892     auto layoutProperty = GetLayoutProperty<RichEditorLayoutProperty>();
8893     CHECK_NULL_VOID(layoutProperty);
8894     auto barState = layoutProperty->GetDisplayModeValue(DisplayMode::AUTO);
8895     CHECK_NULL_VOID(!barDisplayMode_.has_value() || barDisplayMode_.value() != barState);
8896     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "setBarState=%{public}d", barState);
8897     barDisplayMode_ = barState;
8898     if (!GetScrollableEvent()) {
8899         AddScrollEvent();
8900     }
8901     SetAxis(Axis::VERTICAL);
8902     if (barState != DisplayMode::AUTO) {
8903         barState = DisplayMode::ON;
8904     }
8905     SetScrollBar(barState);
8906     auto scrollBar = GetScrollBar();
8907     if (scrollBar) {
8908         auto richEditorTheme = GetTheme<RichEditorTheme>();
8909         CHECK_NULL_VOID(richEditorTheme);
8910         scrollBar->SetMinHeight(richEditorTheme->GetScrollbarMinHeight());
8911     }
8912     if (overlayMod_) {
8913         UpdateScrollBarOffset();
8914     }
8915     auto& paddingProperty = layoutProperty->GetPaddingProperty();
8916     if (paddingProperty) {
8917         auto offsetY = paddingProperty->top.has_value() ? paddingProperty->top->GetDimension().ConvertToPx() : 0.0f;
8918         auto offsetX = paddingProperty->left.has_value() ? paddingProperty->left->GetDimension().ConvertToPx() : 0.0f;
8919         richTextRect_.SetOffset(OffsetF(offsetX, offsetY));
8920     }
8921 }
8922 
8923 void RichEditorPattern::ProcessInnerPadding()
8924 {
8925     auto theme = GetTheme<RichEditorTheme>();
8926     CHECK_NULL_VOID(theme);
8927     auto host = GetHost();
8928     CHECK_NULL_VOID(host);
8929     auto layoutProperty = host->GetLayoutProperty<RichEditorLayoutProperty>();
8930     CHECK_NULL_VOID(layoutProperty);
8931     auto themePadding = theme->GetPadding();
8932     auto& paddingProp = layoutProperty->GetPaddingProperty();
8933     auto left = !paddingProp ? CalcLength(themePadding.Left()).GetDimension()
8934                              : paddingProp->left.value_or(CalcLength(themePadding.Left())).GetDimension();
8935     auto top = !paddingProp ? CalcLength(themePadding.Top()).GetDimension()
8936                             : paddingProp->top.value_or(CalcLength(themePadding.Top())).GetDimension();
8937     auto bottom = !paddingProp ? CalcLength(themePadding.Bottom()).GetDimension()
8938                                : paddingProp->bottom.value_or(CalcLength(themePadding.Bottom())).GetDimension();
8939     auto right = !paddingProp ? CalcLength(themePadding.Right()).GetDimension()
8940                               : paddingProp->right.value_or(CalcLength(themePadding.Right())).GetDimension();
8941     PaddingProperty paddings;
8942     paddings.top = NG::CalcLength(top);
8943     paddings.bottom = NG::CalcLength(bottom);
8944     paddings.left = NG::CalcLength(left);
8945     paddings.right = NG::CalcLength(right);
8946     layoutProperty->UpdatePadding(paddings);
8947 }
8948 
8949 void RichEditorPattern::UpdateScrollStateAfterLayout(bool shouldDisappear)
8950 {
8951     bool hasTextOffsetChanged = false;
8952     if (GreatNotEqual(richTextRect_.GetY(), contentRect_.GetY())) {
8953         auto offset = richTextRect_.GetOffset();
8954         offset.AddY(contentRect_.GetY() - richTextRect_.GetY());
8955         richTextRect_.SetOffset(offset);
8956         hasTextOffsetChanged = true;
8957     }
8958     if (GreatNotEqual(richTextRect_.Height(), contentRect_.Height()) &&
8959         LessNotEqual(richTextRect_.Bottom(), contentRect_.Bottom())) {
8960         auto offset = richTextRect_.GetOffset();
8961         offset.AddY(contentRect_.Bottom() - richTextRect_.Bottom());
8962         richTextRect_.SetOffset(offset);
8963         hasTextOffsetChanged = true;
8964     }
8965     if (LessOrEqual(richTextRect_.Height(), contentRect_.Height()) &&
8966         LessNotEqual(richTextRect_.GetY(), contentRect_.GetY())) {
8967         richTextRect_.SetOffset(contentRect_.GetOffset());
8968         hasTextOffsetChanged = true;
8969     }
8970     if (hasTextOffsetChanged) {
8971         UpdateChildrenOffset();
8972     }
8973     StopScrollable();
8974     CheckScrollable();
8975     if (overlayMod_) {
8976         UpdateScrollBarOffset();
8977     }
8978     auto scrollBar = GetScrollBar();
8979     CHECK_NULL_VOID(scrollBar);
8980 
8981     if (isFirstCallOnReady_) {
8982         isFirstCallOnReady_ = false;
8983         scrollBar->ScheduleDisappearDelayTask();
8984         return;
8985     }
8986     if (shouldDisappear) {
8987         scrollBar->ScheduleDisappearDelayTask();
8988     }
8989 }
8990 
8991 bool RichEditorPattern::OnScrollCallback(float offset, int32_t source)
8992 {
8993     auto scrollBar = GetScrollBar();
8994     if (source == SCROLL_FROM_START) {
8995         IF_PRESENT(scrollBar, PlayScrollBarAppearAnimation());
8996         if (SelectOverlayIsOn()) {
8997             selectOverlay_->HideMenu(true);
8998         }
8999         ScrollablePattern::RecordScrollEvent(Recorder::EventType::SCROLL_START);
9000         UIObserverHandler::GetInstance().NotifyScrollEventStateChange(
9001             AceType::WeakClaim(this), ScrollEventType::SCROLL_START);
9002         return true;
9003     }
9004     if (IsReachedBoundary(offset)) {
9005         return false;
9006     }
9007     if (scrollBar && source == SCROLL_FROM_JUMP) {
9008         scrollBar->PlayScrollBarAppearAnimation();
9009         scrollBar->ScheduleDisappearDelayTask();
9010     }
9011     auto newOffset = MoveTextRect(offset);
9012     MoveFirstHandle(newOffset);
9013     MoveSecondHandle(newOffset);
9014     dataDetectorAdapter_->aiSpanRects_.clear();
9015     return true;
9016 }
9017 
9018 float RichEditorPattern::GetCrossOverHeight() const
9019 {
9020     if (!keyboardAvoidance_ || !contentChange_ || AceApplicationInfo::GetInstance().
9021         GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_FOURTEEN)) {
9022         return 0.0f;
9023     }
9024     auto host = GetHost();
9025     CHECK_NULL_RETURN(host, 0.0f);
9026     auto pipeline = host->GetContext();
9027     CHECK_NULL_RETURN(pipeline, 0.0f);
9028     auto rootHeight = pipeline->GetRootHeight();
9029     auto keyboardY = rootHeight - pipeline->GetSafeAreaManager()->GetKeyboardInset().Length();
9030     if (GreatOrEqual(keyboardY, rootHeight)) {
9031         return 0.0f;
9032     }
9033     float height = contentRect_.Bottom();
9034     float frameY = parentGlobalOffset_.GetY() + contentRect_.GetY();
9035     float bottom = frameY + height;
9036     auto crossOverHeight = bottom - keyboardY;
9037     if (LessOrEqual(crossOverHeight, 0.0f)) {
9038         return 0.0f;
9039     }
9040     return crossOverHeight;
9041 }
9042 
9043 float RichEditorPattern::MoveTextRect(float offset)
9044 {
9045     auto keyboardOffset = GetCrossOverHeight();
9046     if (GreatNotEqual(richTextRect_.Height(), contentRect_.Height() - keyboardOffset)) {
9047         if (GreatNotEqual(richTextRect_.GetY() + offset, contentRect_.GetY())) {
9048             offset = contentRect_.GetY() - richTextRect_.GetY();
9049         } else if (LessNotEqual(richTextRect_.Bottom() + offset, contentRect_.Bottom() - keyboardOffset)) {
9050             offset = contentRect_.Bottom() - keyboardOffset - richTextRect_.Bottom();
9051         }
9052     } else if (!NearEqual(richTextRect_.GetY(), contentRect_.GetY())) {
9053         offset = contentRect_.GetY() - richTextRect_.GetY();
9054     } else {
9055         return 0.0f;
9056     }
9057     if (NearEqual(offset, 0.0f)) {
9058         return offset;
9059     }
9060     scrollOffset_ = richTextRect_.GetY() + offset;
9061     richTextRect_.SetOffset(OffsetF(richTextRect_.GetX(), scrollOffset_));
9062     UpdateScrollBarOffset();
9063     UpdateChildrenOffset();
9064     if (auto host = GetHost(); host) {
9065         host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
9066     }
9067     return offset;
9068 }
9069 
9070 void RichEditorPattern::MoveFirstHandle(float offset)
9071 {
9072     if (SelectOverlayIsOn() && !NearEqual(offset, 0.0f)) {
9073         textSelector_.selectionBaseOffset.AddY(offset);
9074         auto firstHandleOffset = textSelector_.firstHandle.GetOffset();
9075         firstHandleOffset.AddY(offset);
9076         textSelector_.firstHandle.SetOffset(firstHandleOffset);
9077         selectOverlay_->UpdateFirstHandleOffset();
9078     }
9079 }
9080 
9081 void RichEditorPattern::MoveSecondHandle(float offset)
9082 {
9083     if (SelectOverlayIsOn() && !NearEqual(offset, 0.0f)) {
9084         textSelector_.selectionDestinationOffset.AddY(offset);
9085         auto secondHandleOffset = textSelector_.secondHandle.GetOffset();
9086         secondHandleOffset.AddY(offset);
9087         textSelector_.secondHandle.SetOffset(secondHandleOffset);
9088         selectOverlay_->UpdateSecondHandleOffset();
9089     }
9090 }
9091 
9092 void RichEditorPattern::SetNeedMoveCaretToContentRect()
9093 {
9094     CHECK_NULL_VOID(isRichEditorInit_);
9095     needMoveCaretToContentRect_ = true;
9096 }
9097 
9098 void RichEditorPattern::MoveCaretToContentRect()
9099 {
9100     auto [caretOffset, caretHeight] = CalculateCaretOffsetAndHeight();
9101     MoveCaretToContentRect(caretOffset, caretHeight);
9102 }
9103 
9104 void RichEditorPattern::MoveCaretToContentRect(const OffsetF& caretOffset, float caretHeight)
9105 {
9106     auto keyboardOffset = GetCrossOverHeight();
9107     auto contentRect = GetTextContentRect();
9108     auto textRect = GetTextRect();
9109     auto scrollBar = GetScrollBar();
9110     if (scrollBar) {
9111         scrollBar->PlayScrollBarAppearAnimation();
9112         scrollBar->ScheduleDisappearDelayTask();
9113     }
9114     if (LessOrEqual(textRect.Height(), contentRect.Height() - keyboardOffset) || isShowPlaceholder_) {
9115         return;
9116     }
9117     if (LessNotEqual(contentRect.GetSize().Height(), caretHeight) &&
9118         !NearEqual(caretOffset.GetY() + caretHeight, contentRect.Bottom() - keyboardOffset)) {
9119         OnScrollCallback(contentRect.Bottom() - keyboardOffset - caretOffset.GetY() - caretHeight, SCROLL_FROM_NONE);
9120     }
9121     if (LessNotEqual(contentRect.GetSize().Height(), caretHeight)) {
9122         return;
9123     }
9124     if (LessNotEqual(caretOffset.GetY(), contentRect.GetY())) {
9125         if (LessOrEqual(caretOffset.GetX(), GetTextRect().GetX())) {
9126             OnScrollCallback(contentRect.GetY() - caretOffset.GetY() + caretHeight, SCROLL_FROM_NONE);
9127         } else {
9128             OnScrollCallback(contentRect.GetY() - caretOffset.GetY(), SCROLL_FROM_NONE);
9129         }
9130     } else if (GreatNotEqual(caretOffset.GetY() + caretHeight, contentRect.Bottom() - keyboardOffset)) {
9131         auto distance = contentRect.Bottom() - keyboardOffset - caretOffset.GetY() - caretHeight -
9132             CARET_BOTTOM_DISTANCE.ConvertToPx();
9133         OnScrollCallback(distance, SCROLL_FROM_NONE);
9134     }
9135 }
9136 
9137 void RichEditorPattern::MoveCaretToContentRect(float offset, int32_t source)
9138 {
9139     float caretHeight = 0.0f;
9140     auto caretOffset = CalcCursorOffsetByPosition(caretPosition_, caretHeight);
9141     auto keyboardOffset = GetCrossOverHeight();
9142     auto contentRect = GetTextContentRect();
9143     auto distance = contentRect.Bottom() - keyboardOffset - caretOffset.GetY() - caretHeight - offset;
9144     OnScrollCallback(distance, source);
9145 }
9146 
9147 bool RichEditorPattern::IsCaretInContentArea()
9148 {
9149     float caretHeight = 0.0f;
9150     auto caretOffset = CalcCursorOffsetByPosition(caretPosition_, caretHeight);
9151     auto keyboardOffset = GetCrossOverHeight();
9152     auto contentRect = GetTextContentRect();
9153     return GreatNotEqual(caretOffset.GetY() + caretHeight, contentRect.GetY())
9154         && LessNotEqual(caretOffset.GetY(), contentRect.Bottom() - keyboardOffset);
9155 }
9156 
9157 void RichEditorPattern::UpdateScrollBarOffset()
9158 {
9159     if (!GetScrollBar() && !GetScrollBarProxy()) {
9160         return;
9161     }
9162     Size size(frameRect_.Width(), frameRect_.Height());
9163     auto verticalGap = frameRect_.Height() - contentRect_.Height();
9164     UpdateScrollBarRegion(
9165         contentRect_.GetY() - richTextRect_.GetY(), richTextRect_.Height() + verticalGap, size, Offset(0.0, 0.0));
9166     auto tmpHost = GetHost();
9167     CHECK_NULL_VOID(tmpHost);
9168     tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
9169 }
9170 
9171 void RichEditorPattern::OnScrollEndCallback()
9172 {
9173     auto scrollBar = GetScrollBar();
9174     if (scrollBar) {
9175         scrollBar->ScheduleDisappearDelayTask();
9176     }
9177     CHECK_NULL_VOID(!selectOverlay_->GetIsHandleMoving());
9178     if (IsSelectAreaVisible()) {
9179         auto info = selectOverlay_->GetSelectOverlayInfo();
9180         if (info && info->menuInfo.menuBuilder) {
9181             selectOverlay_->ProcessOverlay({ .animation = true });
9182         } else {
9183             selectOverlay_->UpdateMenuOffset();
9184             selectOverlay_->ShowMenu();
9185         }
9186     }
9187     if (AnimateStoped()) {
9188         ScrollablePattern::RecordScrollEvent(Recorder::EventType::SCROLL_STOP);
9189         UIObserverHandler::GetInstance().NotifyScrollEventStateChange(
9190             AceType::WeakClaim(this), ScrollEventType::SCROLL_STOP);
9191     }
9192 }
9193 
9194 bool RichEditorPattern::IsSelectAreaVisible()
9195 {
9196     auto host = GetHost();
9197     CHECK_NULL_RETURN(host, false);
9198     auto pipeline = host->GetContext();
9199     CHECK_NULL_RETURN(pipeline, false);
9200     auto safeAreaManager = pipeline->GetSafeAreaManager();
9201     CHECK_NULL_RETURN(safeAreaManager, false);
9202     auto keyboardInsert = safeAreaManager->GetKeyboardInset();
9203     auto selectArea = GetSelectArea(SelectRectsType::ALL_LINES);
9204 
9205     return !selectArea.IsEmpty() && LessNotEqual(selectArea.Top(), keyboardInsert.start);
9206 }
9207 
9208 bool RichEditorPattern::IsReachedBoundary(float offset)
9209 {
9210     auto keyboardOffset = GetCrossOverHeight();
9211     return (NearEqual(richTextRect_.GetY(), contentRect_.GetY()) && GreatNotEqual(offset, 0.0f)) ||
9212            (NearEqual(richTextRect_.GetY() + richTextRect_.Height(),
9213                 contentRect_.GetY() + contentRect_.Height() - keyboardOffset) &&
9214                LessNotEqual(offset, 0.0f));
9215 }
9216 
9217 void RichEditorPattern::CheckScrollable()
9218 {
9219     auto gestureHub = GetGestureEventHub();
9220     CHECK_NULL_VOID(gestureHub);
9221     scrollable_ = GetTextContentLength() > 0 && GreatNotEqual(richTextRect_.Height(), contentRect_.Height());
9222     SetScrollEnabled(scrollable_);
9223 }
9224 
9225 void RichEditorPattern::UpdateChildrenOffset()
9226 {
9227     auto host = GetHost();
9228     CHECK_NULL_VOID(host);
9229     std::vector<int32_t> placeholderIndex;
9230     for (const auto& child : spans_) {
9231         if (!child) {
9232             continue;
9233         }
9234         if (AceType::InstanceOf<ImageSpanItem>(child) || AceType::InstanceOf<PlaceholderSpanItem>(child)) {
9235             placeholderIndex.emplace_back(child->placeholderIndex);
9236         }
9237     }
9238     if (spans_.empty() || placeholderIndex.empty()) {
9239         return;
9240     }
9241     size_t index = 0;
9242     std::vector<RectF> rectsForPlaceholders = paragraphs_.GetPlaceholderRects();
9243     auto childrenNodes = host->GetChildren();
9244     auto textOffset = GetTextRect().GetOffset();
9245     for (const auto& child : childrenNodes) {
9246         auto childNode = AceType::DynamicCast<FrameNode>(child);
9247         if (!childNode) {
9248             continue;
9249         }
9250         if (!(childNode->GetPattern<ImagePattern>() || childNode->GetPattern<PlaceholderSpanPattern>())) {
9251             continue;
9252         }
9253         if (isSpanStringMode_) {
9254             auto imageSpanNode = AceType::DynamicCast<ImageSpanNode>(child);
9255             if (imageSpanNode && imageSpanNode->GetSpanItem()) {
9256                 index = static_cast<uint32_t>(imageSpanNode->GetSpanItem()->placeholderIndex);
9257             }
9258         }
9259         if (index >= rectsForPlaceholders.size()) {
9260             break;
9261         }
9262         auto rect = rectsForPlaceholders.at(index);
9263         auto geometryNode = childNode->GetGeometryNode();
9264         if (geometryNode) {
9265             geometryNode->SetMarginFrameOffset(textOffset + OffsetF(rect.Left(), rect.Top()));
9266             childNode->ForceSyncGeometryNode();
9267             childNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
9268         }
9269         ++index;
9270     }
9271 }
9272 
9273 void RichEditorPattern::AutoScrollByEdgeDetection(AutoScrollParam param, OffsetF offset, EdgeDetectionStrategy strategy)
9274 {
9275     if (NearEqual(prevAutoScrollOffset_.GetY(), offset.GetY())) {
9276         return;
9277     }
9278     prevAutoScrollOffset_ = offset;
9279     auto contentRect = GetTextContentRect();
9280     auto isDragging = param.autoScrollEvent == AutoScrollEvent::DRAG;
9281     float edgeThreshold = isDragging ? AUTO_SCROLL_DRAG_EDGE_DISTANCE.ConvertToPx()
9282                                      : AUTO_SCROLL_EDGE_DISTANCE.ConvertToPx();
9283     auto maxHeight = isDragging ? frameRect_.Height() : contentRect.Height();
9284     if (GreatNotEqual(edgeThreshold * 2, maxHeight)) {
9285         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "AutoScrollByEdgeDetection: hot area height is great than max height.");
9286         return;
9287     }
9288     float topEdgeThreshold = isDragging ? edgeThreshold : edgeThreshold + contentRect.GetY();
9289     float bottomThreshold = isDragging ? frameRect_.Height() - edgeThreshold : contentRect.Bottom() - edgeThreshold;
9290     if (param.autoScrollEvent == AutoScrollEvent::HANDLE) {
9291         auto handleTopOffset = offset;
9292         auto handleBottomOffset = OffsetF(offset.GetX(), offset.GetY() + param.handleRect.Height());
9293         if (GreatNotEqual(handleBottomOffset.GetY(), bottomThreshold)) {
9294             param.offset = bottomThreshold - handleBottomOffset.GetY();
9295             ScheduleAutoScroll(param);
9296         } else if (LessNotEqual(handleTopOffset.GetY(), topEdgeThreshold)) {
9297             param.offset = topEdgeThreshold - handleTopOffset.GetY();
9298             ScheduleAutoScroll(param);
9299         } else {
9300             StopAutoScroll();
9301         }
9302         return;
9303     }
9304     // drag and mouse
9305     if (GreatNotEqual(offset.GetY(), bottomThreshold)) {
9306         param.offset = isDragging ? -CalcDragSpeed(bottomThreshold, frameRect_.Height(), offset.GetY())
9307                                   : bottomThreshold - offset.GetY();
9308         ScheduleAutoScroll(param);
9309     } else if (LessNotEqual(offset.GetY(), topEdgeThreshold)) {
9310         param.offset = isDragging ? CalcDragSpeed(topEdgeThreshold, 0, offset.GetY())
9311                                   : topEdgeThreshold - offset.GetY();
9312         ScheduleAutoScroll(param);
9313     } else {
9314         StopAutoScroll();
9315     }
9316 }
9317 
9318 float RichEditorPattern::CalcDragSpeed(float hotAreaStart, float hotAreaEnd, float point)
9319 {
9320     auto distanceRatio = (point - hotAreaStart) / (hotAreaEnd - hotAreaStart);
9321     auto speedFactor = Curves::SHARP->MoveInternal(distanceRatio);
9322     return ((MAX_DRAG_SCROLL_SPEED * speedFactor) / TIME_UNIT) * AUTO_SCROLL_INTERVAL;
9323 }
9324 
9325 void RichEditorPattern::ScheduleAutoScroll(AutoScrollParam param)
9326 {
9327     if (GreatNotEqual(param.offset, 0.0f) && IsReachTop()) {
9328         return;
9329     }
9330     if (LessNotEqual(param.offset, 0.0f) && IsReachBottom()) {
9331         return;
9332     }
9333     auto host = GetHost();
9334     CHECK_NULL_VOID(host);
9335     auto context = host->GetContext();
9336     CHECK_NULL_VOID(context);
9337     auto taskExecutor = context->GetTaskExecutor();
9338     CHECK_NULL_VOID(taskExecutor);
9339     if (param.isFirstRun_) {
9340         param.isFirstRun_ = false;
9341         currentScrollParam_ = param;
9342         if (isAutoScrollRunning_) {
9343             return;
9344         }
9345     }
9346     autoScrollTask_.Reset([weak = WeakClaim(this)]() {
9347         auto client = weak.Upgrade();
9348         CHECK_NULL_VOID(client);
9349         client->OnAutoScroll(client->currentScrollParam_);
9350         if (client->IsReachTop() || client->IsReachBottom()) {
9351             client->StopAutoScroll();
9352         }
9353     });
9354     isAutoScrollRunning_ = true;
9355     taskExecutor->PostDelayedTask(autoScrollTask_, TaskExecutor::TaskType::UI, AUTO_SCROLL_INTERVAL,
9356         "ArkUIRichEditorScheduleAutoScroll");
9357 }
9358 
9359 void RichEditorPattern::OnAutoScroll(AutoScrollParam param)
9360 {
9361     if (param.showScrollbar) {
9362         auto scrollBar = GetScrollBar();
9363         IF_PRESENT(scrollBar, PlayScrollBarAppearAnimation());
9364         param.showScrollbar = false;
9365     }
9366     CHECK_NULL_VOID(param.autoScrollEvent != AutoScrollEvent::NONE);
9367     auto newOffset = MoveTextRect(param.offset);
9368     switch (param.autoScrollEvent) {
9369         case AutoScrollEvent::CARET:
9370             break;
9371         case AutoScrollEvent::HANDLE: {
9372             param.isFirstHandle ? MoveSecondHandle(newOffset) : MoveFirstHandle(newOffset);
9373             selectOverlay_->OnHandleMove(param.handleRect, param.isFirstHandle);
9374             break;
9375         }
9376         case AutoScrollEvent::DRAG:
9377             break;
9378         case AutoScrollEvent::MOUSE: {
9379             auto textOffset = ConvertTouchOffsetToTextOffset(param.eventOffset);
9380             int32_t extend = (GetTextContentLength() == 0) ? 0 : paragraphs_.GetIndex(textOffset);
9381             UpdateSelector(textSelector_.baseOffset, extend);
9382             SetCaretPosition(std::max(textSelector_.baseOffset, extend));
9383             break;
9384         }
9385         default:
9386             TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "Unsupported auto scroll event type");
9387             return;
9388     }
9389     CHECK_NULL_VOID(!NearEqual(newOffset, 0.0f));
9390     ScheduleAutoScroll(param);
9391 }
9392 
9393 void RichEditorPattern::StopAutoScroll()
9394 {
9395     isAutoScrollRunning_ = false;
9396     autoScrollTask_.Cancel();
9397     prevAutoScrollOffset_ = OffsetF(0.0f, 0.0f);
9398     auto scrollBar = GetScrollBar();
9399     IF_PRESENT(scrollBar, ScheduleDisappearDelayTask());
9400 }
9401 
9402 bool RichEditorPattern::NeedAiAnalysis(
9403     const CaretUpdateType targeType, const int32_t pos, const int32_t& spanStart, const std::string& content)
9404 {
9405     if (spanStart < 0) {
9406         TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "NeedAiAnalysis -spanStart:%{public}d, return!", spanStart);
9407         return false;
9408     }
9409 
9410     if (!InputAIChecker::NeedAIAnalysis(content.empty(), targeType, lastClickTimeStamp_ - lastAiPosTimeStamp_)) {
9411         return false;
9412     }
9413 
9414     if (IsClickBoundary(pos) && targeType == CaretUpdateType::PRESSED) {
9415         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "NeedAiAnalysis IsClickBoundary, return!");
9416         return false;
9417     }
9418     EmojiRelation relation = GetEmojiRelation(pos);
9419     if (relation == EmojiRelation::IN_EMOJI || relation == EmojiRelation::MIDDLE_EMOJI ||
9420         relation == EmojiRelation::BEFORE_EMOJI) {
9421         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "NeedAiAnalysis emoji relation=%{public}d, return!", relation);
9422         return false;
9423     }
9424     return true;
9425 }
9426 
9427 void RichEditorPattern::AdjustCursorPosition(int32_t& pos)
9428 {
9429     // the rich text has some spans, the pos is belong to the whole richtext content, should use (pos - spanStarint)
9430     int32_t spanStart = -1;
9431     // get the span text by the position, maybe text is empty
9432     std::string content = GetPositionSpansText(pos, spanStart);
9433 
9434     if (NeedAiAnalysis(CaretUpdateType::PRESSED, pos, spanStart, content)) {
9435         int32_t aiPos = pos - spanStart;
9436         DataDetectorMgr::GetInstance().AdjustCursorPosition(aiPos, content, lastAiPosTimeStamp_, lastClickTimeStamp_);
9437         if (aiPos < 0) {
9438             return;
9439         }
9440         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "get ai pos:%{public}d--spanStart%{public}d", aiPos, spanStart);
9441         pos = aiPos + spanStart;
9442     }
9443 }
9444 
9445 bool RichEditorPattern::AdjustWordSelection(int32_t& start, int32_t& end)
9446 {
9447     // the rich text has some spans, the pos is belong to the whole richtext content, should use (pos - spanStarint)
9448     int32_t spanStart = -1;
9449     // get the span text by the position, maybe text is empty
9450     std::string content = GetPositionSpansText(start, spanStart);
9451     if (NeedAiAnalysis(CaretUpdateType::DOUBLE_CLICK, start, spanStart, content)) {
9452         int32_t aiPosStart = start - spanStart;
9453         int32_t aiPosEnd = end - spanStart;
9454         DataDetectorMgr::GetInstance().AdjustWordSelection(aiPosStart, content, aiPosStart, aiPosEnd);
9455         if (aiPosStart < 0 || aiPosEnd < 0) {
9456             return false;
9457         }
9458 
9459         start = std::min(aiPosStart + spanStart, GetTextContentLength());
9460         end = std::min(aiPosEnd + spanStart, GetTextContentLength());
9461         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "get ai selector [%{public}d--%{public}d]", start, end);
9462         return true;
9463     }
9464     return false;
9465 }
9466 
9467 void RichEditorPattern::AdjustPlaceholderSelection(int32_t& start, int32_t& end, const Offset& touchPos)
9468 {
9469     CHECK_NULL_VOID(!spans_.empty());
9470     if (!IsTouchBeforeCaret(start, touchPos)) {
9471         return;
9472     }
9473     auto it = std::find_if(spans_.begin(), spans_.end(), [start](const RefPtr<SpanItem>& spanItem) {
9474         return spanItem->position == start;
9475     });
9476     if (it != spans_.end()) {
9477         // adjust selection if touch right of image or placeholder
9478         auto spanIndex = std::distance(spans_.begin(), it);
9479         auto spanNodeBefore = DynamicCast<FrameNode>(GetChildByIndex(spanIndex));
9480         if (spanNodeBefore && (spanNodeBefore->GetTag() == V2::IMAGE_ETS_TAG ||
9481             spanNodeBefore->GetTag() == V2::PLACEHOLDER_SPAN_ETS_TAG)) {
9482             end = start;
9483             --start;
9484             TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "get placeholder selector [%{public}d--%{public}d]", start, end);
9485         }
9486     }
9487 }
9488 
9489 bool RichEditorPattern::IsTouchAtLineEnd(int32_t caretPos, const Offset& textOffset)
9490 {
9491     auto positionWithAffinity = paragraphs_.GetGlyphPositionAtCoordinate(textOffset);
9492     TextAffinity currentAffinity = positionWithAffinity.affinity_;
9493     return currentAffinity == TextAffinity::UPSTREAM && !IsTouchBeforeCaret(caretPos, textOffset);
9494 }
9495 
9496 bool RichEditorPattern::IsTouchBeforeCaret(int32_t caretPos, const Offset& textOffset) {
9497     CHECK_NULL_RETURN(!spans_.empty(), false);
9498     float selectLineHeight = 0.0f;
9499     OffsetF caretOffsetUp = paragraphs_.ComputeCursorOffset(caretPos, selectLineHeight);
9500     auto needAdjustRect = RectF{ 0, caretOffsetUp.GetY(), caretOffsetUp.GetX(), selectLineHeight };
9501     return needAdjustRect.IsInRegion(PointF{ textOffset.GetX(), textOffset.GetY() });
9502 }
9503 
9504 bool RichEditorPattern::IsClickBoundary(const int32_t position)
9505 {
9506     if (InputAIChecker::IsSingleClickAtBoundary(position, GetTextContentLength())) {
9507         return true;
9508     }
9509 
9510     float height = 0;
9511     auto handleOffset = CalcCursorOffsetByPosition(position, height);
9512     if (InputAIChecker::IsMultiClickAtBoundary(handleOffset, TextPattern::GetTextRect())) {
9513         return true;
9514     }
9515     return false;
9516 }
9517 
9518 std::string RichEditorPattern::GetPositionSpansText(int32_t position, int32_t& startSpan)
9519 {
9520     int32_t start = position - AI_TEXT_RANGE_LEFT;
9521     int32_t end = position + AI_TEXT_RANGE_RIGHT;
9522 
9523     start = std::clamp(start, 0, GetTextContentLength());
9524     end = std::clamp(end, 0, GetTextContentLength());
9525     AdjustSelector(start, end);
9526     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "caret=%{public}d, range=[%{public}d,%{public}d]", position, start, end);
9527 
9528     // get all the spans between start and end, then filter the valid text
9529     auto infos = GetSpansInfo(start, end, GetSpansMethod::ONSELECT);
9530     if (infos.GetSelection().resultObjects.empty()) {
9531         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "get spans text is null pos:%{public}d,return", position);
9532         return "";
9533     }
9534     auto list = infos.GetSelection().resultObjects;
9535 
9536     std::stringstream sstream;
9537     for (const auto& obj : list) {
9538         if (obj.type != SelectSpanType::TYPESPAN) {
9539             if (obj.spanPosition.spanRange[0] == position) {
9540                 startSpan = -1;
9541                 return "";
9542             } else if (obj.spanPosition.spanRange[1] <= position) {
9543                 sstream.str("");
9544                 startSpan = -1;
9545             } else {
9546                 break;
9547             }
9548         } else {
9549             if (startSpan < 0) {
9550                 startSpan = obj.spanPosition.spanRange[0] + obj.offsetInSpan[0];
9551             }
9552             // we should use the wide string deal to avoid crash
9553             auto wideText = obj.valueString;
9554             int32_t textLen = static_cast<int32_t>(wideText.length());
9555             if (obj.offsetInSpan[0] < textLen && obj.offsetInSpan[1] <= textLen) {
9556                 sstream << UtfUtils::Str16ToStr8(
9557                     wideText.substr(obj.offsetInSpan[0], obj.offsetInSpan[1] - obj.offsetInSpan[0]));
9558             }
9559         }
9560     }
9561 
9562     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "get spans text ret spanStart:%{public}d", startSpan);
9563     return sstream.str();
9564 }
9565 
9566 bool RichEditorPattern::IsShowSelectMenuUsingMouse()
9567 {
9568     auto host = GetHost();
9569     CHECK_NULL_RETURN(host, false);
9570     auto pipeline = host->GetContext();
9571     CHECK_NULL_RETURN(pipeline, false);
9572     auto selectOverlayManager = pipeline->GetSelectOverlayManager();
9573     CHECK_NULL_RETURN(selectOverlayManager, false);
9574     return selectOverlayManager->GetSelectOverlayInfo().isUsingMouse;
9575 }
9576 
9577 RefPtr<FocusHub> RichEditorPattern::GetFocusHub() const
9578 {
9579     auto host = GetHost();
9580     CHECK_NULL_RETURN(host, nullptr);
9581     auto focusHub = host->GetOrCreateFocusHub();
9582     return focusHub;
9583 }
9584 
9585 void RichEditorPattern::HandleCursorOnDragMoved(const RefPtr<NotifyDragEvent>& notifyDragEvent)
9586 {
9587     auto host = GetHost();
9588     CHECK_NULL_VOID(host);
9589     if (HasFocus()) {
9590         if (!isCursorAlwaysDisplayed_) {
9591             isCursorAlwaysDisplayed_ = true;
9592             StartTwinkling();
9593         }
9594         if (SystemProperties::GetDebugEnabled()) {
9595             TAG_LOGD(AceLogTag::ACE_RICH_TEXT,
9596                 "In OnDragMoved, the cursor has always Displayed in the textField, id:" SEC_PLD(%{public}d),
9597                     SEC_PARAM(host->GetId()));
9598         }
9599         return;
9600     }
9601     TAG_LOGI(AceLogTag::ACE_RICH_TEXT,
9602         "In OnDragMoved, the dragging node is moving in the richEditor, id:" SEC_PLD(%{public}d),
9603             SEC_PARAM(host->GetId()));
9604     auto focusHub = GetFocusHub();
9605     CHECK_NULL_VOID(focusHub);
9606     isOnlyRequestFocus_ = true;
9607     focusHub->RequestFocusImmediately();
9608     if (focusHub->IsCurrentFocus()) {
9609         ShowCaretWithoutTwinkling();
9610     }
9611 };
9612 
9613 void RichEditorPattern::HandleCursorOnDragLeaved(const RefPtr<NotifyDragEvent>& notifyDragEvent)
9614 {
9615     auto host = GetHost();
9616     CHECK_NULL_VOID(host);
9617     TAG_LOGI(AceLogTag::ACE_RICH_TEXT,
9618         "In OnDragLeaved, the dragging node has left from richEditor, id:" SEC_PLD(%{public}d),
9619             SEC_PARAM(host->GetId()));
9620     auto focusHub = GetFocusHub();
9621     CHECK_NULL_VOID(focusHub);
9622     focusHub->LostFocusToViewRoot();
9623     StopTwinkling();
9624 };
9625 
9626 void RichEditorPattern::HandleCursorOnDragEnded(const RefPtr<NotifyDragEvent>& notifyDragEvent)
9627 {
9628     auto host = GetHost();
9629     CHECK_NULL_VOID(host);
9630     auto focusHub = GetFocusHub();
9631     CHECK_NULL_VOID(focusHub);
9632     StopAutoScroll();
9633     if (!isCursorAlwaysDisplayed_) {
9634         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "In OnDragEnded,"
9635             " the released location is not in the current richEditor, id:" SEC_PLD(%{public}d),
9636                 SEC_PARAM(host->GetId()));
9637         IF_TRUE(HasFocus(), CloseKeyboard(false));
9638         focusHub->LostFocus();
9639         StopTwinkling();
9640         return;
9641     }
9642     TAG_LOGI(AceLogTag::ACE_RICH_TEXT,
9643         "In OnDragEnded, the released location is in the current richEditor, id:" SEC_PLD(%{public}d),
9644             SEC_PARAM(host->GetId()));
9645     focusHub->LostFocusToViewRoot();
9646     isCursorAlwaysDisplayed_ = false;
9647     StopTwinkling();
9648 };
9649 
9650 void RichEditorPattern::HandleOnDragStatusCallback(
9651     const DragEventType& dragEventType, const RefPtr<NotifyDragEvent>& notifyDragEvent)
9652 {
9653     ScrollablePattern::HandleOnDragStatusCallback(dragEventType, notifyDragEvent);
9654     switch (dragEventType) {
9655         case DragEventType::MOVE:
9656             HandleCursorOnDragMoved(notifyDragEvent);
9657             break;
9658         case DragEventType::LEAVE:
9659             HandleCursorOnDragLeaved(notifyDragEvent);
9660             break;
9661         case DragEventType::DROP:
9662             HandleCursorOnDragEnded(notifyDragEvent);
9663             break;
9664         default:
9665             break;
9666     }
9667 }
9668 
9669 void RichEditorPattern::HandleOnCameraInput()
9670 {
9671     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "HandleOnCameraInput");
9672 #if defined(ENABLE_STANDARD_INPUT)
9673     if (richEditTextChangeListener_ == nullptr) {
9674         richEditTextChangeListener_ = new OnTextChangedListenerImpl(WeakClaim(this));
9675     }
9676     auto inputMethod = MiscServices::InputMethodController::GetInstance();
9677     if (!inputMethod) {
9678         return;
9679     }
9680     StartTwinkling();
9681 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
9682     if (imeShown_) {
9683         inputMethod->StartInputType(MiscServices::InputType::CAMERA_INPUT);
9684     } else {
9685         HandleOnEditChanged(true);
9686         auto optionalTextConfig = GetMiscTextConfig();
9687         CHECK_NULL_VOID(optionalTextConfig.has_value());
9688         MiscServices::TextConfig textConfig = optionalTextConfig.value();
9689         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "HandleOnCameraInput set calling window id is : %{public}u",
9690             textConfig.windowId);
9691 #ifdef WINDOW_SCENE_SUPPORTED
9692         auto systemWindowId = GetSCBSystemWindowId();
9693         if (systemWindowId) {
9694             TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "windowId From %{public}u to %{public}u.", textConfig.windowId,
9695                 systemWindowId);
9696             textConfig.windowId = systemWindowId;
9697         }
9698 #endif
9699         auto ret = inputMethod->Attach(richEditTextChangeListener_, false, textConfig);
9700         if (ret == MiscServices::ErrorCode::NO_ERROR) {
9701             auto pipeline = GetContext();
9702             CHECK_NULL_VOID(pipeline);
9703             auto textFieldManager = AceType::DynamicCast<TextFieldManagerNG>(pipeline->GetTextFieldManager());
9704             CHECK_NULL_VOID(textFieldManager);
9705             textFieldManager->SetIsImeAttached(true);
9706         }
9707         inputMethod->StartInputType(MiscServices::InputType::CAMERA_INPUT);
9708         inputMethod->ShowTextInput();
9709     }
9710     CloseSelectOverlay();
9711 #endif
9712 #endif
9713 }
9714 
9715 bool RichEditorPattern::CanStartAITask()
9716 {
9717     return TextPattern::CanStartAITask() && !isEditing_ && !spans_.empty();
9718 }
9719 
9720 bool RichEditorPattern::NeedShowAIDetect()
9721 {
9722     return TextPattern::NeedShowAIDetect() && !isEditing_ && !isShowPlaceholder_ && !spans_.empty();
9723 }
9724 
9725 void RichEditorPattern::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
9726 {
9727     /* no fixed attr below, just return */
9728     if (filter.IsFastFilter()) {
9729         return;
9730     }
9731     json->PutExtAttr("enableDataDetector", textDetectEnable_ ? "true" : "false", filter);
9732     json->PutExtAttr("dataDetectorConfig", dataDetectorAdapter_->textDetectConfigStr_.c_str(), filter);
9733     json->PutExtAttr("placeholder", GetPlaceHolderInJson().c_str(), filter);
9734     json->PutExtAttr("bindSelectionMenu", GetBindSelectionMenuInJson().c_str(), filter);
9735     json->PutExtAttr("stopBackPress", isStopBackPress_ ? "true" : "false", filter);
9736     json->PutExtAttr("keyboardAppearance", static_cast<int32_t>(keyboardAppearance_), filter);
9737     json->PutExtAttr("maxLength", maxLength_.value_or(INT_MAX), filter);
9738     json->PutExtAttr("enableHapticFeedback", isEnableHapticFeedback_ ? "true" : "false", filter);
9739     json->PutExtAttr("barState", static_cast<int32_t>(GetBarDisplayMode()), filter);
9740     json->PutExtAttr("enableKeyboardOnFocus", needToRequestKeyboardOnFocus_ ? "true" : "false", filter);
9741 }
9742 
9743 void RichEditorPattern::FillPreviewMenuInJson(const std::unique_ptr<JsonValue>& jsonValue) const
9744 {
9745     IF_PRESENT(oneStepDragController_, FillJsonValue(jsonValue));
9746 }
9747 
9748 std::string RichEditorPattern::GetPlaceHolderInJson() const
9749 {
9750     auto host = GetHost();
9751     CHECK_NULL_RETURN(host, "");
9752     auto layoutProperty = host->GetLayoutProperty<TextLayoutProperty>();
9753     bool hasPlaceHolder = layoutProperty && layoutProperty->HasPlaceholder()
9754         && !layoutProperty->GetPlaceholder().value().empty();
9755     CHECK_NULL_RETURN(hasPlaceHolder, "");
9756     auto jsonValue = JsonUtil::Create(true);
9757     jsonValue->Put("value", UtfUtils::Str16ToStr8(layoutProperty->GetPlaceholderValue(u"")).c_str());
9758     auto jsonFont = JsonUtil::Create(true);
9759     jsonFont->Put("size", GetFontSizeWithThemeInJson(layoutProperty->GetPlaceholderFontSize()).c_str());
9760     jsonFont->Put("weight", GetFontWeightInJson(layoutProperty->GetPlaceholderFontWeight()).c_str());
9761     jsonFont->Put("family", GetFontFamilyInJson(layoutProperty->GetPlaceholderFontFamily()).c_str());
9762     jsonFont->Put("style", GetFontStyleInJson(layoutProperty->GetPlaceholderItalicFontStyle()).c_str());
9763     auto jsonStyle = JsonUtil::Create(true);
9764     jsonStyle->Put("font", jsonFont->ToString().c_str());
9765     jsonStyle->Put("fontColor", GetTextColorInJson(layoutProperty->GetPlaceholderTextColor()).c_str());
9766     jsonValue->Put("style", jsonStyle->ToString().c_str());
9767     return StringUtils::RestoreBackslash(jsonValue->ToString());
9768 }
9769 
9770 std::string RichEditorPattern::GetTextColorInJson(const std::optional<Color>& value) const
9771 {
9772     CHECK_NULL_RETURN(!value, value->ColorToString());
9773     auto host = GetHost();
9774     CHECK_NULL_RETURN(host, "");
9775     auto pipeline = host->GetContext();
9776     CHECK_NULL_RETURN(pipeline, "");
9777     auto richEditorTheme = pipeline->GetTheme<RichEditorTheme>();
9778     CHECK_NULL_RETURN(richEditorTheme, "");
9779     Color textColor = richEditorTheme->GetTextStyle().GetTextColor();
9780     return textColor.ColorToString();
9781 }
9782 
9783 void RichEditorPattern::GetCaretMetrics(CaretMetricsF& caretCaretMetric)
9784 {
9785     float caretHeight = 0.0f;
9786     OffsetF caretOffset = CalcCursorOffsetByPosition(caretPosition_, caretHeight);
9787     auto host = GetHost();
9788     CHECK_NULL_VOID(host);
9789     auto offset = host->GetPaintRectOffsetNG(false, true);
9790     caretOffset += offset;
9791     caretCaretMetric.offset = caretOffset;
9792     caretCaretMetric.height = caretHeight;
9793 }
9794 
9795 void RichEditorPattern::OnVirtualKeyboardAreaChanged()
9796 {
9797     CHECK_NULL_VOID(SelectOverlayIsOn() && !selectOverlay_->GetIsHandleMoving() && !selectOverlay_->GetIsHandleHidden());
9798     float selectLineHeight = 0.0f;
9799     textSelector_.selectionBaseOffset.SetX(
9800         CalcCursorOffsetByPosition(textSelector_.GetStart(), selectLineHeight).GetX());
9801     textSelector_.selectionDestinationOffset.SetX(
9802         CalcCursorOffsetByPosition(textSelector_.GetEnd(), selectLineHeight).GetX());
9803     CreateHandles();
9804 }
9805 
9806 void RichEditorPattern::ResetDragOption()
9807 {
9808     auto gestureEventHub = GetGestureEventHub();
9809     CHECK_NULL_VOID(gestureEventHub);
9810     if (gestureEventHub->GetIsTextDraggable()) {
9811         CloseSelectOverlay();
9812         ResetSelection();
9813     }
9814 }
9815 
9816 void RichEditorPattern::AdjustSelectRects(SelectRectsType pos, std::vector<RectF>& selectRects)
9817 {
9818     if (pos == SelectRectsType::LEFT_TOP_POINT) {
9819         selectRects.erase(std::next(selectRects.begin()), selectRects.end());
9820         selectRects.front().SetSize({0, 0});
9821     } else if (pos == SelectRectsType::RIGHT_BOTTOM_POINT) {
9822         selectRects.erase(selectRects.begin(), std::prev(selectRects.end()));
9823         selectRects.front().SetRect({selectRects.front().Right(), selectRects.front().Bottom()}, {0, 0});
9824     }
9825 }
9826 
9827 RectF RichEditorPattern::GetSelectArea(SelectRectsType pos)
9828 {
9829     RectF rect;
9830     auto paintOffset = selectOverlay_->GetPaintOffsetWithoutTransform();
9831     auto selectRects = paragraphs_.GetRects(textSelector_.GetTextStart(), textSelector_.GetTextEnd());
9832     auto contentRect = contentRect_;
9833     contentRect.SetOffset(contentRect.GetOffset() + paintOffset);
9834     auto host = GetHost();
9835     CHECK_NULL_RETURN(host, rect);
9836     auto parent = host->GetAncestorNodeOfFrame(false);
9837     contentRect = GetVisibleContentRect(parent, contentRect);
9838     AppendSelectRect(selectRects);
9839     if (selectRects.empty()) {
9840         CHECK_NULL_RETURN(overlayMod_, rect);
9841         auto richEditorOverlay = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
9842         CHECK_NULL_RETURN(richEditorOverlay, rect);
9843         auto [caretOffset, caretHeight] = CalculateCaretOffsetAndHeight();
9844         auto caretWidth = Dimension(1.5f, DimensionUnit::VP).ConvertToPx();
9845         auto selectRect = RectF(caretOffset + paintOffset, SizeF(caretWidth, caretHeight));
9846         return selectRect.IntersectRectT(contentRect);
9847     }
9848     AdjustSelectRects(pos, selectRects);
9849     auto frontRect = selectRects.front();
9850     auto backRect = selectRects.back();
9851     float selectAreaRight = frontRect.Right();
9852     float selectAreaLeft = frontRect.Left();
9853     if (selectRects.size() != 1) {
9854         std::unordered_map<float, RectF> selectLineRect;
9855         for (const auto& box : selectRects) {
9856             auto combineLineRect = box;
9857             auto top = box.Top();
9858             if (selectLineRect.find(top) == selectLineRect.end()) {
9859                 selectLineRect.insert({ top, combineLineRect });
9860             } else {
9861                 combineLineRect = combineLineRect.CombineRectT(selectLineRect[top]);
9862                 selectLineRect.insert({ top, combineLineRect });
9863             }
9864             selectAreaRight = std::max(selectAreaRight, combineLineRect.Right());
9865             selectAreaLeft = std::min(selectAreaLeft, combineLineRect.Left());
9866         }
9867     }
9868     RectF res = { selectAreaLeft + richTextRect_.GetX() + paintOffset.GetX(),
9869         frontRect.GetY() + richTextRect_.GetY() + paintOffset.GetY(), selectAreaRight - selectAreaLeft,
9870         backRect.Bottom() - frontRect.Top() };
9871     return res.IntersectRectT(contentRect);
9872 }
9873 
9874 void RichEditorPattern::AppendSelectRect(std::vector<RectF>& selectRects)
9875 {
9876     CHECK_NULL_VOID(!selectOverlay_->IsSingleHandle());
9877     auto startPosition = textSelector_.GetTextStart();
9878     auto endPosition = textSelector_.GetTextEnd();
9879     auto height = 0.0f;
9880     auto caretWidth = Dimension(1.5f, DimensionUnit::VP).ConvertToPx();
9881     if (paragraphs_.IsIndexAtParagraphEnd(startPosition + 1)) {
9882         auto offset = paragraphs_.ComputeCursorOffset(startPosition, height, false, false);
9883         RectF rect = RectF(offset.GetX(), offset.GetY(), caretWidth, height);
9884         selectRects.insert(selectRects.begin(), rect);
9885     }
9886     if (paragraphs_.IsIndexAtParagraphEnd(endPosition)) {
9887         auto offset = paragraphs_.ComputeCursorOffset(endPosition, height, true, false);
9888         RectF rect = RectF(offset.GetX(), offset.GetY(), caretWidth, height);
9889         selectRects.emplace_back(rect);
9890     }
9891 }
9892 
9893 bool RichEditorPattern::IsTouchInFrameArea(const PointF& touchPoint)
9894 {
9895     auto host = GetHost();
9896     CHECK_NULL_RETURN(host, false);
9897     auto viewPort = RectF(parentGlobalOffset_, frameRect_.GetSize());
9898     auto parent = host->GetAncestorNodeOfFrame(false);
9899     viewPort = GetVisibleContentRect(parent, viewPort);
9900     return viewPort.IsInRegion(touchPoint);
9901 }
9902 
9903 bool RichEditorPattern::SetPlaceholder(std::vector<std::list<RefPtr<SpanItem>>>& spanItemList)
9904 {
9905     if (!spans_.empty()) {
9906         isShowPlaceholder_ = false;
9907         return false;
9908     }
9909     auto host = GetHost();
9910     CHECK_NULL_RETURN(host, false);
9911     auto layoutProperty = host->GetLayoutProperty<TextLayoutProperty>();
9912     CHECK_NULL_RETURN(layoutProperty, false);
9913     if (!layoutProperty->HasPlaceholder() || layoutProperty->GetPlaceholder().value().empty()) {
9914         isShowPlaceholder_ = false;
9915         return false;
9916     }
9917     auto placeholderValue = layoutProperty->GetPlaceholder().value();
9918     auto* stack = ViewStackProcessor::GetInstance();
9919     CHECK_NULL_RETURN(stack, false);
9920     auto nodeId = stack->ClaimNodeId();
9921     auto placeholderNode = SpanNode::GetOrCreateSpanNode(nodeId);
9922     CHECK_NULL_RETURN(placeholderNode, false);
9923     if (layoutProperty->HasPlaceholderFontSize()) {
9924         placeholderNode->UpdateFontSize(layoutProperty->GetPlaceholderFontSize().value());
9925     }
9926     if (layoutProperty->HasPlaceholderFontWeight()) {
9927         placeholderNode->UpdateFontWeight(layoutProperty->GetPlaceholderFontWeight().value());
9928     }
9929     if (layoutProperty->HasPlaceholderFontFamily()) {
9930         placeholderNode->UpdateFontFamily(layoutProperty->GetPlaceholderFontFamily().value());
9931     }
9932     if (layoutProperty->HasPlaceholderItalicFontStyle()) {
9933         placeholderNode->UpdateItalicFontStyle(layoutProperty->GetPlaceholderItalicFontStyle().value());
9934     }
9935     if (layoutProperty->HasPlaceholderTextColor()) {
9936         placeholderNode->UpdateTextColorWithoutCheck(layoutProperty->GetPlaceholderTextColor().value());
9937     } else {
9938         auto theme = GetTheme<RichEditorTheme>();
9939         placeholderNode->UpdateTextColorWithoutCheck(theme ? theme->GetPlaceholderColor() : Color());
9940     }
9941 
9942     auto spanItem = placeholderNode->GetSpanItem();
9943     CHECK_NULL_RETURN(spanItem, false);
9944     spanItem->content = placeholderValue;
9945     spanItemList.clear();
9946     spanItemList.push_back({ { {spanItem} } });
9947     isShowPlaceholder_ = true;
9948     return true;
9949 }
9950 
9951 std::string RichEditorPattern::GetPlaceHolder() const
9952 {
9953     auto host = GetHost();
9954     CHECK_NULL_RETURN(host, "");
9955     auto layoutProperty = host->GetLayoutProperty<TextLayoutProperty>();
9956     CHECK_NULL_RETURN(layoutProperty, "");
9957     return UtfUtils::Str16ToStr8(layoutProperty->GetPlaceholderValue(u""));
9958 }
9959 
9960 Color RichEditorPattern::GetCaretColor()
9961 {
9962     if (caretColor_.has_value()) {
9963         return caretColor_.value();
9964     }
9965     auto richEditorTheme = GetTheme<RichEditorTheme>();
9966     CHECK_NULL_RETURN(richEditorTheme, SYSTEM_CARET_COLOR);
9967     return richEditorTheme->GetCaretColor();
9968 }
9969 
9970 Color RichEditorPattern::GetSelectedBackgroundColor()
9971 {
9972     Color selectedBackgroundColor;
9973     if (selectedBackgroundColor_.has_value()) {
9974         selectedBackgroundColor = selectedBackgroundColor_.value();
9975     } else {
9976         auto richEditorTheme = GetTheme<RichEditorTheme>();
9977         CHECK_NULL_RETURN(richEditorTheme, SYSTEM_SELECT_BACKGROUND_COLOR);
9978         selectedBackgroundColor = richEditorTheme->GetSelectedBackgroundColor();
9979     }
9980     // Alpha == 255 Means completely opaque
9981     if (selectedBackgroundColor.GetAlpha() == COLOR_OPAQUE) {
9982         selectedBackgroundColor = selectedBackgroundColor.ChangeOpacity(DEFAILT_OPACITY);
9983     }
9984     return selectedBackgroundColor;
9985 }
9986 
9987 void RichEditorPattern::HandleOnDragDropStyledString(const RefPtr<OHOS::Ace::DragEvent>& event, bool isCopy)
9988 {
9989     CHECK_NULL_VOID(event);
9990     auto data = event->GetData();
9991     CHECK_NULL_VOID(data);
9992     auto arr = UdmfClient::GetInstance()->GetSpanStringRecord(data);
9993     if (!arr.empty()) {
9994         auto spanStr = SpanString::DecodeTlv(arr);
9995         if (!spanStr->GetSpanItems().empty()) {
9996             if (isSpanStringMode_) {
9997                 HandleOnDragInsertStyledString(spanStr, isCopy);
9998                 return;
9999             }
10000             AddSpanByPasteData(spanStr);
10001             return;
10002         }
10003     }
10004 
10005     auto records = UdmfClient::GetInstance()->GetPlainTextRecords(data);
10006     if (records.empty()) {
10007         return;
10008     }
10009     std::string str;
10010     for (const auto& record : records) {
10011         str += record;
10012     }
10013     if (str.empty()) {
10014         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "text is empty.");
10015         return;
10016     }
10017     if (isSpanStringMode_) {
10018         InsertValueInStyledString(UtfUtils::Str8ToStr16(str));
10019     } else {
10020         HandleOnDragDropTextOperation(UtfUtils::Str8ToStr16(str), isDragSponsor_, isCopy);
10021     }
10022 }
10023 
10024 void RichEditorPattern::HandleOnDragDrop(const RefPtr<OHOS::Ace::DragEvent>& event, bool isCopy)
10025 {
10026     auto host = GetHost();
10027     CHECK_NULL_VOID(host);
10028     auto eventHub = host->GetEventHub<RichEditorEventHub>();
10029     CHECK_NULL_VOID(eventHub);
10030     TextCommonEvent textCommonEvent;
10031     if (textCommonEvent.IsPreventDefault()) {
10032         CloseSelectOverlay();
10033         ResetSelection();
10034         StartTwinkling();
10035         return;
10036     }
10037     HandleOnDragDropStyledString(event, isCopy);
10038     if (textSelector_.IsValid()) {
10039         CloseSelectOverlay();
10040         ResetSelection();
10041     }
10042     auto focusHub = host->GetOrCreateFocusHub();
10043     CHECK_NULL_VOID(focusHub);
10044     if (focusHub->IsCurrentFocus()) {
10045         StartTwinkling();
10046     }
10047     afterDragSelect_ = isMouseOrTouchPad(sourceTool_);
10048     releaseInDrop_ = true;
10049 }
10050 
10051 void RichEditorPattern::DeleteForward(int32_t currentPosition, int32_t length)
10052 {
10053     RichEditorDeleteValue info;
10054     info.SetOffset(currentPosition);
10055     info.SetRichEditorDeleteDirection(RichEditorDeleteDirection::FORWARD);
10056     info.SetLength(length);
10057     CalcDeleteValueObj(currentPosition, length, info);
10058     DeleteByDeleteValueInfo(info);
10059 }
10060 
10061 int32_t RichEditorPattern::HandleOnDragDeleteForward()
10062 {
10063     int32_t allDelLength = 0;
10064     SelectionInfo textSelectInfo = GetSpansInfo(dragRange_.first, dragRange_.second, GetSpansMethod::ONSELECT);
10065     std::list<ResultObject> dragResultObjects = textSelectInfo.GetSelection().resultObjects;
10066     for (auto ri = dragResultObjects.rbegin(); ri != dragResultObjects.rend(); ++ri) {
10067         if (SelectSpanType::TYPESPAN == ri->type || (SelectSpanType::TYPEIMAGE == ri->type && ri->valueString != u" ")) {
10068             int32_t spanStart = ri->offsetInSpan[RichEditorSpanRange::RANGESTART];
10069             int32_t spanEnd = ri->offsetInSpan[RichEditorSpanRange::RANGEEND];
10070             int32_t reStart = ri->spanPosition.spanRange[RichEditorSpanRange::RANGESTART];
10071             int32_t delStart = reStart;
10072             if (spanStart > 0) {
10073                 delStart += spanStart;
10074             }
10075             int32_t delLength = spanEnd - spanStart;
10076             DeleteForward(delStart, delLength);
10077             allDelLength += delLength;
10078         }
10079     }
10080     return allDelLength;
10081 }
10082 
10083 void RichEditorPattern::HandleOnDragDropTextOperation(const std::u16string& insertValue, bool isDeleteSelect, bool isCopy)
10084 {
10085     insertValueLength_ = static_cast<int32_t>(insertValue.length());
10086     if (!isDeleteSelect || isCopy) {
10087         InsertValueByOperationType(insertValue, OperationType::DRAG);
10088         return;
10089     }
10090     int32_t currentPosition = caretPosition_;
10091     int32_t strLength = static_cast<int32_t>(insertValue.length());
10092     OperationRecord record;
10093     record.addText = insertValue;
10094     record.beforeCaretPosition = dragRange_.first;
10095     RichEditorChangeValue changeValue;
10096     // drag not move, do not fire contentChange
10097     if (dragRange_.first <= currentPosition && currentPosition <= dragRange_.second) {
10098         lastCaretPosition_ = dragRange_.first;
10099         return;
10100     }
10101     CHECK_NULL_VOID(BeforeChangeText(changeValue, record, RecordType::DRAG));
10102     if (currentPosition < dragRange_.first) {
10103         InsertValueByOperationType(insertValue, OperationType::DRAG);
10104         dragRange_.first += strLength;
10105         dragRange_.second += strLength;
10106         HandleOnDragDeleteForward();
10107         lastCaretPosition_ = currentPosition;
10108     } else if (currentPosition > dragRange_.second) {
10109         InsertValueByOperationType(insertValue, OperationType::DRAG);
10110         int32_t delLength = HandleOnDragDeleteForward();
10111         caretPosition_ -= delLength;
10112         lastCaretPosition_ = currentPosition - strLength;
10113     }
10114 
10115     AfterContentChange(changeValue);
10116 }
10117 
10118 void RichEditorPattern::UndoDrag(const OperationRecord& record)
10119 {
10120     if (!record.addText.has_value() || record.deleteCaretPostion == -1) {
10121         return;
10122     }
10123     const auto& str = record.addText.value();
10124     int32_t length = static_cast<int32_t>(str.length());
10125     DeleteForward(record.beforeCaretPosition, length);
10126 
10127     lastCaretPosition_ = caretPosition_;
10128     caretPosition_ = record.deleteCaretPostion;
10129     InsertValueOperation(str, nullptr, OperationType::DEFAULT);
10130 }
10131 
10132 void RichEditorPattern::RedoDrag(const OperationRecord& record)
10133 {
10134     if (!record.addText.has_value() || record.deleteCaretPostion == -1) {
10135         return;
10136     }
10137     RichEditorChangeValue changeValue;
10138     CHECK_NULL_VOID(BeforeChangeText(changeValue, record, RecordType::REDO));
10139     const auto& str = record.addText.value();
10140     int32_t length = static_cast<int32_t>(str.length());
10141     DeleteForward(record.deleteCaretPostion, length);
10142     lastCaretPosition_ = caretPosition_;
10143     caretPosition_ = record.beforeCaretPosition;
10144     InsertValueOperation(str, nullptr, OperationType::DRAG);
10145     AfterContentChange(changeValue);
10146 }
10147 
10148 void RichEditorPattern::HandleOnDragInsertValueOperation(const std::u16string& insertValue)
10149 {
10150     InsertValueByOperationType(insertValue, OperationType::DRAG);
10151 }
10152 
10153 void RichEditorPattern::HandleOnDragInsertValue(const std::u16string& insertValue)
10154 {
10155     OperationRecord record;
10156     record.beforeCaretPosition = caretPosition_ + moveLength_;
10157     if (textSelector_.IsValid()) {
10158         record.beforeCaretPosition = textSelector_.GetTextStart();
10159     }
10160     record.addText = insertValue;
10161     ClearRedoOperationRecords();
10162     InsertValueByOperationType(insertValue, OperationType::DRAG);
10163     int32_t length = dragRange_.second - dragRange_.first;
10164     record.afterCaretPosition = record.beforeCaretPosition + length;
10165     record.deleteCaretPostion = dragRange_.first;
10166     AddOperationRecord(record);
10167 }
10168 
10169 bool RichEditorPattern::IsEditing()
10170 {
10171     return isEditing_;
10172 }
10173 
10174 void RichEditorPattern::HandleOnEditChanged(bool isEditing)
10175 {
10176     CHECK_NULL_VOID(isEditing_ != isEditing);
10177     auto host = GetHost();
10178     CHECK_NULL_VOID(host);
10179     auto eventHub = host->GetEventHub<RichEditorEventHub>();
10180     CHECK_NULL_VOID(eventHub);
10181 
10182     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "editState->%{public}d", isEditing);
10183     isEditing_ = isEditing;
10184     eventHub->FireOnEditingChange(isEditing);
10185 
10186     if (CanStartAITask()) {
10187         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "leave edit state, start AI task");
10188         dataDetectorAdapter_->StartAITask();
10189     } else {
10190         if (isEditing) {
10191             TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "enter edit state, reset previewLongPress_");
10192             previewLongPress_ = false;
10193         }
10194         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
10195     }
10196 }
10197 
10198 void RichEditorPattern::ResetKeyboardIfNeed()
10199 {
10200     bool needToResetKeyboard = false;
10201     auto currentAction = GetTextInputActionValue(GetDefaultTextInputAction());
10202     // When the enter key type changes, the keyboard needs to be reset.
10203     if (action_ != TextInputAction::UNSPECIFIED) {
10204         needToResetKeyboard = action_ != currentAction;
10205     }
10206     action_ = currentAction;
10207 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
10208     if (needToResetKeyboard) {
10209         // if keyboard attached or keyboard is shown, pull up keyboard again
10210         if (imeShown_ || isCustomKeyboardAttached_) {
10211             if (HasFocus()) {
10212                 RequestKeyboard(false, true, true);
10213             }
10214             return;
10215         }
10216 #if defined(ENABLE_STANDARD_INPUT)
10217         auto inputMethod = MiscServices::InputMethodController::GetInstance();
10218         CHECK_NULL_VOID(inputMethod);
10219         MiscServices::Configuration config;
10220         config.SetEnterKeyType(static_cast<MiscServices::EnterKeyType>(action_));
10221         config.SetTextInputType(static_cast<MiscServices::TextInputType>(keyboard_));
10222         inputMethod->OnConfigurationChange(config);
10223 #endif
10224     }
10225 #else
10226     if (needToResetKeyboard && HasConnection()) {
10227         CloseSelectOverlay();
10228         ResetSelection();
10229         CloseKeyboard(false);
10230         RequestKeyboard(false, true, true);
10231     }
10232 #endif
10233 }
10234 
10235 void RichEditorPattern::OnTextInputActionUpdate(TextInputAction value) {}
10236 
10237 void RichEditorPattern::PerformAction(TextInputAction action, bool forceCloseKeyboard)
10238 {
10239     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "PerformAction, action=%{public}d", action);
10240     auto host = GetHost();
10241     CHECK_NULL_VOID(host);
10242     // When the Enter key is triggered, perform a line feed operation.
10243     if (action == TextInputAction::NEW_LINE) {
10244         InsertValue(u"\n", true);
10245     }
10246     // Enter key type callback
10247     TextFieldCommonEvent event;
10248     auto eventHub = host->GetEventHub<RichEditorEventHub>();
10249     eventHub->FireOnSubmit(static_cast<int32_t>(action), event);
10250     // If the developer wants to keep editing, editing will not stop
10251     if (event.IsKeepEditable() || action == TextInputAction::NEW_LINE) {
10252         return;
10253     }
10254     // Exit the editing state
10255     StopEditing();
10256 }
10257 
10258 void RichEditorPattern::StopEditing()
10259 {
10260     CHECK_NULL_VOID(HasFocus());
10261     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "StopEditing");
10262 
10263     // The selection status disappears, the cursor is hidden, and the soft keyboard is exited
10264     HandleBlurEvent();
10265     // In order to avoid the physical keyboard being able to type, you need to make sure that you lose focus
10266     FocusHub::LostFocusToViewRoot();
10267 }
10268 
10269 TextInputAction RichEditorPattern::GetDefaultTextInputAction() const
10270 {
10271     // As with TextInput, it is a line break by default
10272     return TextInputAction::NEW_LINE;
10273 }
10274 
10275 void RichEditorPattern::GetChangeSpanStyle(RichEditorChangeValue& changeValue, std::optional<TextStyle>& spanTextStyle,
10276     std::optional<struct UpdateParagraphStyle>& spanParaStyle, std::optional<std::u16string>& urlAddress,
10277     const RefPtr<SpanNode>& spanNode, int32_t spanIndex)
10278 {
10279     auto originalSpans = changeValue.GetRichEditorOriginalSpans();
10280     if (spanIndex == 0 && originalSpans.size()) {
10281         const RichEditorAbstractSpanResult& firstInfo = originalSpans.front();
10282         const RichEditorAbstractSpanResult& lastInfo = originalSpans.back();
10283         int32_t firstLength = static_cast<int32_t>(firstInfo.GetValue().length());
10284         int32_t lastLength = static_cast<int32_t>(lastInfo.GetValue().length());
10285         if (firstInfo.GetEraseLength() == firstLength && lastInfo.GetEraseLength() == lastLength) {
10286             if (spans_.size() == originalSpans.size() ||
10287                 static_cast<int32_t>(spans_.size()) == (lastInfo.GetSpanIndex() + 1)) {
10288                 urlAddress.reset();
10289                 return; // all spanNode be deleted, set default style
10290             }
10291             spanIndex = lastInfo.GetSpanIndex() + 1;
10292         } else if (firstInfo.GetEraseLength() == firstLength) {
10293             spanIndex = lastInfo.GetSpanIndex();
10294         }
10295         auto it = spans_.begin();
10296         std::advance(it, spanIndex);
10297         if ((*it)->unicode != 0 || DynamicCast<PlaceholderSpanItem>(*it)) {
10298             return; // is not a textSpan(Image/Symbol/other)
10299         }
10300         spanTextStyle = (*it)->GetTextStyle();
10301         struct UpdateParagraphStyle paraStyle;
10302         paraStyle.textAlign = (*it)->textLineStyle->GetTextAlign();
10303         paraStyle.leadingMargin = (*it)->textLineStyle->GetLeadingMargin();
10304         paraStyle.wordBreak = (*it)->textLineStyle->GetWordBreak();
10305         paraStyle.lineBreakStrategy = (*it)->textLineStyle->GetLineBreakStrategy();
10306         paraStyle.paragraphSpacing = (*it)->textLineStyle->GetParagraphSpacing();
10307         spanParaStyle = paraStyle;
10308     } else if (spanNode && spanNode->GetSpanItem()) {
10309         spanTextStyle = spanNode->GetSpanItem()->GetTextStyle();
10310         struct UpdateParagraphStyle paraStyle;
10311         paraStyle.textAlign = spanNode->GetTextAlign();
10312         paraStyle.leadingMargin = spanNode->GetLeadingMarginValue({});
10313         paraStyle.wordBreak = spanNode->GetWordBreak();
10314         paraStyle.lineBreakStrategy = spanNode->GetLineBreakStrategy();
10315         paraStyle.paragraphSpacing = spanNode->GetParagraphSpacing();
10316         spanParaStyle = paraStyle;
10317     }
10318 }
10319 
10320 void RichEditorPattern::GetReplacedSpan(RichEditorChangeValue& changeValue, int32_t& innerPosition,
10321     const std::u16string& insertValue, int32_t textIndex, std::optional<TextStyle> textStyle,
10322     std::optional<struct UpdateParagraphStyle> paraStyle, std::optional<std::u16string> urlAddress,
10323     bool isCreate, bool fixDel)
10324 {
10325     std::u16string originalStr;
10326     int32_t originalPos = 0;
10327     RefPtr<SpanItem> spanItem = fixDel ? GetDelPartiallySpanItem(changeValue, originalStr, originalPos) : nullptr;
10328     TextInsertValueInfo info;
10329     CalcInsertValueObj(info, textIndex, isCreate);
10330     int32_t spanIndex = info.GetSpanIndex();
10331     int32_t offsetInSpan = info.GetOffsetInSpan();
10332     auto host = GetHost();
10333     CHECK_NULL_VOID(host);
10334     auto uiNode = host->GetChildAtIndex(spanIndex);
10335     RefPtr<SpanNode> spanNode = DynamicCast<SpanNode>(uiNode);
10336     if (!isCreate && textIndex && uiNode && uiNode->GetTag() != V2::SPAN_ETS_TAG) {
10337         spanNode = nullptr;
10338         ++spanIndex; // select/create a new span When the span is not a textSpan(Image/Symbol/other)
10339         offsetInSpan = 0;
10340         spanNode = DynamicCast<SpanNode>(host->GetChildAtIndex(spanIndex));
10341     }
10342 
10343     changeValue.SetRangeAfter({ innerPosition, innerPosition + insertValue.length()});
10344     std::u16string textTemp = insertValue;
10345     if (!textStyle && !isCreate && spanNode) {
10346         if (typingStyle_ && !HasSameTypingStyle(spanNode)) {
10347             textStyle = typingTextStyle_; // create a new span When have a different typingStyle
10348             bool insertInSpan = textIndex && offsetInSpan;
10349             spanIndex = insertInSpan ? spanIndex + 1 : spanIndex;
10350             offsetInSpan = 0;
10351         } else {
10352             textTemp = spanNode->GetSpanItem()->content;
10353             textTemp.insert(offsetInSpan, insertValue);
10354             urlAddress = spanNode->GetSpanItem()->urlAddress;
10355         }
10356     }
10357 
10358     auto it = textTemp.find(LINE_SEPARATOR);
10359     bool containNextLine = it != std::u16string::npos;
10360 
10361     if (textStyle || containNextLine) { // SpanNode Fission
10362         GetReplacedSpanFission(changeValue, innerPosition, textTemp, spanIndex, offsetInSpan, textStyle, paraStyle,
10363             urlAddress);
10364     } else {
10365         std::optional<TextStyle> spanTextStyle = textStyle ? textStyle : typingTextStyle_;
10366         std::optional<struct UpdateParagraphStyle> spanParaStyle = paraStyle;
10367         GetChangeSpanStyle(changeValue, spanTextStyle, spanParaStyle, urlAddress, spanNode, spanIndex);
10368         CreateSpanResult(changeValue, innerPosition, spanIndex, offsetInSpan, offsetInSpan + insertValue.length(),
10369             textTemp, spanTextStyle, spanParaStyle, urlAddress);
10370         innerPosition += static_cast<int32_t>(insertValue.length());
10371     }
10372 
10373     if (spanItem) {
10374         spanItem->content = originalStr;
10375         spanItem->position = originalPos;
10376     }
10377 }
10378 
10379 void RichEditorPattern::GetReplacedSpanFission(RichEditorChangeValue& changeValue, int32_t& innerPosition,
10380     std::u16string& content, int32_t startSpanIndex, int32_t offsetInSpan, std::optional<TextStyle> textStyle,
10381     std::optional<struct UpdateParagraphStyle> paraStyle, const std::optional<std::u16string>& urlAddress)
10382 {
10383     int spanIndex = startSpanIndex;
10384     auto index = content.find(LINE_SEPARATOR);
10385     while (index != std::u16string::npos) {
10386         auto textAfter = content.substr(index + 1);
10387         if (textAfter.empty()) {
10388             break;
10389         }
10390         auto textBefore = content.substr(0, index + 1);
10391         if (offsetInSpan != static_cast<int32_t>(textBefore.length())) {
10392             CreateSpanResult(changeValue, innerPosition, spanIndex, offsetInSpan, textBefore.length(),
10393                 textBefore, textStyle, paraStyle, urlAddress);
10394             innerPosition += textBefore.length() - offsetInSpan;
10395         }
10396         content = textAfter;
10397         index = content.find(LINE_SEPARATOR);
10398         offsetInSpan = 0;
10399         ++spanIndex;
10400     }
10401     CreateSpanResult(changeValue, innerPosition, spanIndex, offsetInSpan, content.length(),
10402         content, textStyle, paraStyle, urlAddress);
10403     innerPosition += static_cast<int32_t>(content.length());
10404 }
10405 
10406 void RichEditorPattern::CreateSpanResult(RichEditorChangeValue& changeValue, int32_t& innerPosition, int32_t spanIndex,
10407     int32_t offsetInSpan, int32_t endInSpan, std::u16string content, std::optional<TextStyle> textStyle,
10408     std::optional<struct UpdateParagraphStyle> paraStyle, const std::optional<std::u16string>& urlAddress)
10409 {
10410     RichEditorAbstractSpanResult retInfo;
10411     if (textStyle) {
10412         SetTextStyleToRet(retInfo, *textStyle);
10413     } else {
10414         retInfo.SetFontColor((Color::BLACK).ColorToString());
10415         retInfo.SetFontSize(Dimension(DEFAULT_TEXT_SIZE, DimensionUnit::FP).ConvertToVp());
10416         retInfo.SetFontStyle(OHOS::Ace::FontStyle::NORMAL);
10417         retInfo.SetFontWeight(static_cast<int32_t>(FontWeight::NORMAL));
10418         retInfo.SetTextDecoration(TextDecoration::NONE);
10419         retInfo.SetColor((Color::BLACK).ColorToString());
10420         retInfo.SetFontFamily("HarmonyOS Sans");
10421     }
10422     IF_TRUE(urlAddress.has_value(), retInfo.SetUrlAddress(urlAddress.value()));
10423     retInfo.SetSpanIndex(spanIndex);
10424     if (!previewTextRecord_.newPreviewContent.empty()) {
10425         retInfo.SetPreviewText(previewTextRecord_.newPreviewContent);
10426     } else {
10427         retInfo.SetValue(content);
10428     }
10429     int32_t rangStart = std::max(0, innerPosition - offsetInSpan);
10430     retInfo.SetSpanRangeStart(rangStart);
10431     retInfo.SetSpanRangeEnd(rangStart + content.length());
10432     retInfo.SetOffsetInSpan(offsetInSpan);
10433     retInfo.SetEraseLength(endInSpan - offsetInSpan);
10434     if (paraStyle) {
10435         TextStyleResult textStyleResult = retInfo.GetTextStyle();
10436         textStyleResult.textAlign = static_cast<int32_t>(paraStyle->textAlign.value_or(TextAlign::START));
10437         if (paraStyle->leadingMargin) {
10438             textStyleResult.leadingMarginSize[0] = paraStyle->leadingMargin->size.Width().ToString();
10439             textStyleResult.leadingMarginSize[1] = paraStyle->leadingMargin->size.Height().ToString();
10440         }
10441         IF_TRUE(paraStyle->wordBreak.has_value(),
10442             textStyleResult.wordBreak = static_cast<int32_t>(paraStyle->wordBreak.value()));
10443         IF_TRUE(paraStyle->lineBreakStrategy.has_value(),
10444             textStyleResult.lineBreakStrategy = static_cast<int32_t>(paraStyle->lineBreakStrategy.value()));
10445         IF_TRUE(paraStyle->paragraphSpacing.has_value(), textStyleResult.paragraphSpacing =
10446             Dimension(paraStyle->paragraphSpacing.value().ConvertToFp(), DimensionUnit::FP));
10447         retInfo.SetTextStyle(textStyleResult);
10448     }
10449     changeValue.SetRichEditorReplacedSpans(retInfo);
10450 }
10451 
10452 void RichEditorPattern::SetTextStyleToRet(RichEditorAbstractSpanResult& retInfo, const TextStyle& textStyle)
10453 {
10454     retInfo.SetTextDecoration(textStyle.GetTextDecoration());
10455     retInfo.SetFontColor(textStyle.GetTextColor().ColorToString());
10456     retInfo.SetColor(textStyle.GetTextDecorationColor().ColorToString());
10457     retInfo.SetTextDecorationStyle(textStyle.GetTextDecorationStyle());
10458     retInfo.SetFontSize(textStyle.GetFontSize().ConvertToVp());
10459     retInfo.SetFontStyle(textStyle.GetFontStyle());
10460     TextStyleResult textStyleResult;
10461     textStyleResult.lineHeight = textStyle.GetLineHeight().ConvertToVp();
10462     textStyleResult.halfLeading = textStyle.GetHalfLeading();
10463     textStyleResult.letterSpacing = textStyle.GetLetterSpacing().ConvertToVp();
10464     textStyleResult.textShadows = textStyle.GetTextShadows();
10465     textStyleResult.textBackgroundStyle = textStyle.GetTextBackgroundStyle();
10466     retInfo.SetTextStyle(textStyleResult);
10467     retInfo.SetLineHeight(textStyle.GetLineHeight().ConvertToVp());
10468     retInfo.SetHalfLeading(textStyle.GetHalfLeading());
10469     retInfo.SetLetterspacing(textStyle.GetLetterSpacing().ConvertToVp());
10470     retInfo.SetFontFeature(textStyle.GetFontFeatures());
10471     std::string fontFamilyValue;
10472     auto fontFamily = textStyle.GetFontFamilies();
10473     for (const auto& str : fontFamily) {
10474         fontFamilyValue += str;
10475     }
10476     retInfo.SetFontFamily(fontFamilyValue);
10477     retInfo.SetFontWeight((int32_t)textStyle.GetFontWeight());
10478 }
10479 
10480 void RichEditorPattern::CalcInsertValueObj(TextInsertValueInfo& info, int textIndex, bool isCreate)
10481 {
10482     if (spans_.empty()) {
10483         info.SetSpanIndex(0);
10484         info.SetOffsetInSpan(0);
10485         return;
10486     }
10487     auto it = std::find_if(
10488         spans_.begin(), spans_.end(), [caretPosition = textIndex](const RefPtr<SpanItem>& spanItem) {
10489             auto spanLength = static_cast<int32_t>(spanItem->content.length());
10490             if (spanLength == 0) {
10491                 return spanItem->position == caretPosition;
10492             }
10493             return (spanItem->position - spanLength <= caretPosition) && (caretPosition <= spanItem->position);
10494         });
10495     if (it == spans_.end()) {
10496         info.SetSpanIndex(static_cast<int32_t>(spans_.size()) - 1);
10497         info.SetOffsetInSpan((*spans_.rbegin())->content.length());
10498         return;
10499     }
10500     if (textIndex && isCreate) {
10501         info.SetSpanIndex(std::distance(spans_.begin(), it) + 1);
10502         info.SetOffsetInSpan(0);
10503         return;
10504     }
10505     if ((*it)->content.back() == '\n' && (*it)->position == textIndex) { // next line/span begin
10506         info.SetSpanIndex(std::distance(spans_.begin(), it) + 1);
10507         info.SetOffsetInSpan(0);
10508     } else {
10509         info.SetSpanIndex(std::distance(spans_.begin(), it));
10510         int32_t spanStart = (*it)->position - static_cast<int32_t>((*it)->content.length());
10511         info.SetOffsetInSpan(textIndex - spanStart);
10512     }
10513 }
10514 
10515 void RichEditorPattern::GetDeletedSpan(RichEditorChangeValue& changeValue, int32_t& innerPosition,
10516     int32_t length, RichEditorDeleteDirection direction)
10517 {
10518     RichEditorDeleteValue info;
10519     if (!textSelector_.SelectNothing()) {
10520         length = textSelector_.GetTextEnd() - textSelector_.GetTextStart();
10521         innerPosition = std::min(textSelector_.GetStart(), textSelector_.GetEnd());
10522     } else if (!previewTextRecord_.previewContent.empty() || previewTextRecord_.needReplaceText) {
10523         length = previewTextRecord_.replacedRange.end - previewTextRecord_.replacedRange.start;
10524         innerPosition = previewTextRecord_.replacedRange.start;
10525     } else {
10526         int32_t emojiLength = CalculateDeleteLength(length, (direction == RichEditorDeleteDirection::BACKWARD));
10527         if (direction == RichEditorDeleteDirection::BACKWARD) {
10528             innerPosition -= emojiLength;
10529         }
10530         if (length < emojiLength) {
10531             length = emojiLength;
10532         }
10533     }
10534 
10535     info.SetOffset(innerPosition);
10536     info.SetRichEditorDeleteDirection(direction);
10537     info.SetLength(length);
10538     if (!spans_.empty()) {
10539         CalcDeleteValueObj(innerPosition, length, info);
10540     }
10541     if (!spans_.empty() || isAPI14Plus) {
10542         changeValue.SetRangeBefore({ innerPosition, innerPosition + length });
10543         changeValue.SetRangeAfter({ innerPosition, innerPosition });
10544     }
10545     const std::list<RichEditorAbstractSpanResult>& resultList = info.GetRichEditorDeleteSpans();
10546     for (auto& it : resultList) {
10547         if (it.GetType() == SpanResultType::TEXT) {
10548             changeValue.SetRichEditorOriginalSpans(it);
10549         } else if (it.GetType() == SpanResultType::SYMBOL && textSelector_.SelectNothing() &&
10550             previewTextRecord_.previewContent.empty()) {
10551             int32_t symbolStart = it.GetSpanRangeStart();
10552             changeValue.SetRichEditorOriginalSpans(it);
10553             changeValue.SetRangeBefore({ symbolStart, symbolStart + SYMBOL_SPAN_LENGTH });
10554             changeValue.SetRangeAfter({ symbolStart, symbolStart });
10555         }
10556     }
10557 }
10558 
10559 RefPtr<SpanItem> RichEditorPattern::GetDelPartiallySpanItem(
10560     RichEditorChangeValue& changeValue, std::u16string& originalStr, int32_t& originalPos)
10561 {
10562     RefPtr<SpanItem> retItem = nullptr;
10563     if (changeValue.GetRichEditorOriginalSpans().size() == 0) {
10564         return retItem;
10565     }
10566     std::u16string textTemp;
10567     auto originalSpans = changeValue.GetRichEditorOriginalSpans();
10568     const RichEditorAbstractSpanResult& firstResult = originalSpans.front();
10569     auto it = spans_.begin();
10570     std::advance(it, firstResult.GetSpanIndex());
10571     retItem = *it;
10572     originalStr = retItem->content;
10573     originalPos = retItem->position;
10574     retItem->content.erase(firstResult.OffsetInSpan(), firstResult.GetEraseLength());
10575     retItem->position -= firstResult.GetEraseLength();
10576     if (firstResult.GetEraseLength() != static_cast<int32_t>(firstResult.GetValue().length())) {
10577         return retItem;
10578     }
10579 
10580     if (firstResult.GetSpanIndex() == 0) {
10581         int32_t spanIndex = 0;
10582         for (auto& orgIt : originalSpans) {
10583             spanIndex = orgIt.GetSpanIndex();
10584             if (orgIt.GetEraseLength() != static_cast<int32_t>(orgIt.GetValue().length())) {
10585                 // find the deleted(Partially) spanItem
10586                 auto findIt = spans_.begin();
10587                 std::advance(findIt, spanIndex);
10588                 textTemp = (*findIt)->content;
10589                 textTemp.erase(orgIt.OffsetInSpan(), orgIt.GetEraseLength());
10590                 retItem->content = textTemp;
10591                 retItem->position = textTemp.length();
10592                 return retItem;
10593             }
10594         }
10595         if (spans_.size() == originalSpans.size() || static_cast<int32_t>(spans_.size()) == (spanIndex + 1)) {
10596             return retItem; // all spanNode be deleted
10597         }
10598         auto nextIt = spans_.begin();
10599         std::advance(nextIt, spanIndex + 1);
10600         if ((*nextIt)->unicode != 0 || DynamicCast<PlaceholderSpanItem>(*nextIt)) {
10601             return retItem; // is not a textSpan(Image/Symbol/other)
10602         }
10603         retItem->content = (*nextIt)->content;
10604         retItem->position = static_cast<int32_t>(retItem->content.length());
10605     }
10606     return retItem;
10607 }
10608 
10609 bool RichEditorPattern::BeforeChangeText(RichEditorChangeValue& changeValue, const TextSpanOptions& options)
10610 {
10611     auto eventHub = GetEventHub<RichEditorEventHub>();
10612     CHECK_NULL_RETURN(eventHub, false);
10613     if (!eventHub->HasOnWillChange() && !eventHub->HasOnDidChange()) {
10614         return true;
10615     }
10616     int32_t innerPosition = caretPosition_;
10617 
10618    // AddTextSpan
10619     std::optional<TextStyle> textStyle = std::nullopt;
10620     if (options.style.has_value()) {
10621         textStyle = options.style;
10622     }
10623     if (options.offset.has_value()) {
10624         if (spans_.empty() || options.offset.value() < 0) {
10625             innerPosition = 0;
10626         } else if (options.offset.value() > GetTextContentLength()) {
10627             innerPosition = GetTextContentLength();
10628         } else {
10629             innerPosition = options.offset.value();
10630         }
10631     } else {
10632         innerPosition = GetTextContentLength();
10633     }
10634     // only add, do not delete
10635     changeValue.SetRangeBefore({ innerPosition, innerPosition });
10636     GetReplacedSpan(changeValue, innerPosition, options.value, innerPosition, textStyle, options.paraStyle,
10637         options.urlAddress, true);
10638 
10639     CHECK_NULL_RETURN(eventHub->HasOnWillChange(), true);
10640     auto ret = eventHub->FireOnWillChange(changeValue);
10641     return ret;
10642 }
10643 
10644 bool RichEditorPattern::BeforeAddImage(RichEditorChangeValue& changeValue,
10645     const ImageSpanOptions& options, int32_t insertIndex)
10646 {
10647     auto eventHub = GetEventHub<RichEditorEventHub>();
10648     CHECK_NULL_RETURN(eventHub, false);
10649     if (!eventHub->HasOnWillChange() && !eventHub->HasOnDidChange()) {
10650         return true;
10651     }
10652     changeValue.SetRangeBefore({ insertIndex, insertIndex });
10653     changeValue.SetRangeAfter({ insertIndex, insertIndex + 1});
10654     RichEditorAbstractSpanResult retInfo;
10655     TextInsertValueInfo info;
10656     CalcInsertValueObj(info, insertIndex, true);
10657     int32_t spanIndex = info.GetSpanIndex();
10658     retInfo.SetSpanIndex(spanIndex);
10659     if (options.image) {
10660         retInfo.SetValueResourceStr(*options.image);
10661     }
10662     if (options.imagePixelMap) {
10663         retInfo.SetValuePixelMap(*options.imagePixelMap);
10664     }
10665     if (options.imageAttribute.has_value()) {
10666         auto imgAttr = options.imageAttribute.value();
10667         if (imgAttr.size.has_value()) {
10668             retInfo.SetSizeWidth(imgAttr.size->width.value_or(CalcDimension()).ConvertToPx());
10669             retInfo.SetSizeHeight(imgAttr.size->height.value_or(CalcDimension()).ConvertToPx());
10670         }
10671         if (imgAttr.verticalAlign.has_value()) {
10672             retInfo.SetVerticalAlign(imgAttr.verticalAlign.value());
10673         }
10674         if (imgAttr.objectFit.has_value()) {
10675             retInfo.SetImageFit(imgAttr.objectFit.value());
10676         }
10677         if (imgAttr.marginProp.has_value()) {
10678             retInfo.SetMargin(imgAttr.marginProp.value().ToString());
10679         }
10680         if (imgAttr.borderRadius.has_value()) {
10681             retInfo.SetBorderRadius(imgAttr.borderRadius.value().ToString());
10682         }
10683     }
10684     retInfo.SetOffsetInSpan(0);
10685     retInfo.SetEraseLength(1);
10686     retInfo.SetSpanRangeStart(insertIndex);
10687     retInfo.SetSpanRangeEnd(insertIndex + 1);
10688     retInfo.SetSpanType(SpanResultType::IMAGE);
10689     changeValue.SetRichEditorReplacedImageSpans(retInfo);
10690     CHECK_NULL_RETURN(eventHub->HasOnWillChange(), true);
10691     auto ret = eventHub->FireOnWillChange(changeValue);
10692     return ret;
10693 }
10694 
10695 void RichEditorPattern::FixMoveDownChange(RichEditorChangeValue& changeValue, int32_t delLength)
10696 {
10697     int32_t delSpanCount = 0;
10698     for (auto& it : changeValue.GetRichEditorOriginalSpans()) {
10699         if (it.GetEraseLength() == static_cast<int32_t>(it.GetValue().length())) {
10700             ++delSpanCount;
10701         }
10702     }
10703     for (auto& it : const_cast<std::vector<RichEditorAbstractSpanResult>&>(changeValue.GetRichEditorReplacedSpans())) {
10704         if (delSpanCount) {
10705             it.SetSpanIndex(it.GetSpanIndex() - delSpanCount);
10706         }
10707     }
10708 }
10709 
10710 void RichEditorPattern::BeforeUndo(
10711     RichEditorChangeValue& changeValue, int32_t& innerPosition, const OperationRecord& record)
10712 {
10713     innerPosition = record.afterCaretPosition;
10714     if (record.addText.has_value() && record.deleteCaretPostion != -1) { // UndoDrag
10715         GetDeletedSpan(changeValue, innerPosition, record.addText.value_or(u"").length(),
10716             RichEditorDeleteDirection::FORWARD);
10717         innerPosition = record.deleteCaretPostion;
10718         GetReplacedSpan(changeValue, innerPosition, record.addText.value(), innerPosition, std::nullopt, std::nullopt);
10719     } else if (record.addText.has_value() && record.deleteText.has_value()) {
10720         GetDeletedSpan(changeValue, innerPosition, record.addText.value_or(u"").length(),
10721             RichEditorDeleteDirection::BACKWARD);
10722         GetReplacedSpan(
10723             changeValue, innerPosition, record.deleteText.value(), innerPosition, std::nullopt, std::nullopt);
10724     } else if (record.deleteText.has_value()) {
10725         GetReplacedSpan(
10726             changeValue, innerPosition, record.deleteText.value(), innerPosition, std::nullopt, std::nullopt);
10727     } else if (record.addText.has_value()) {
10728         GetDeletedSpan(changeValue, innerPosition, record.addText.value_or(u"").length(),
10729             RichEditorDeleteDirection::BACKWARD);
10730     }
10731 }
10732 
10733 void RichEditorPattern::BeforeRedo(
10734     RichEditorChangeValue& changeValue, int32_t& innerPosition, const OperationRecord& record)
10735 {
10736     innerPosition = record.beforeCaretPosition - record.addText.value_or(u"").length();
10737     if (record.addText.has_value() && record.deleteCaretPostion != -1) { // RedoDrag
10738         innerPosition = record.deleteCaretPostion;
10739         GetDeletedSpan(changeValue, innerPosition, record.addText.value_or(u"").length(),
10740             RichEditorDeleteDirection::FORWARD);
10741         innerPosition = record.beforeCaretPosition;
10742         GetReplacedSpan(changeValue, innerPosition, record.addText.value(), innerPosition, std::nullopt, std::nullopt);
10743     } else if (record.addText.has_value() && record.deleteText.has_value()) {
10744         GetDeletedSpan(changeValue, innerPosition, record.deleteText.value_or(u"").length(),
10745             RichEditorDeleteDirection::FORWARD);
10746         GetReplacedSpan(changeValue, innerPosition, record.addText.value(), innerPosition, std::nullopt, std::nullopt);
10747     } else if (record.deleteText.has_value()) {
10748         innerPosition = record.beforeCaretPosition - record.deleteText.value_or(u"").length();
10749         GetDeletedSpan(changeValue, innerPosition, record.deleteText.value_or(u"").length(),
10750             RichEditorDeleteDirection::FORWARD);
10751     } else if (record.addText.has_value()) {
10752         innerPosition = std::min(innerPosition, record.afterCaretPosition);
10753         int32_t innerAddPosition = record.afterCaretPosition - static_cast<int32_t>(record.addText.value().length());
10754         if (changeValue.GetRichEditorOriginalSpans().empty()) {
10755             innerPosition = caretPosition_;
10756             innerAddPosition = caretPosition_;
10757         }
10758         GetReplacedSpan(changeValue, innerAddPosition, record.addText.value(), innerPosition,
10759             std::nullopt, std::nullopt);
10760     }
10761 }
10762 
10763 void RichEditorPattern::BeforeDrag(
10764     RichEditorChangeValue& changeValue, int32_t& innerPosition, const OperationRecord& record)
10765 {
10766     std::u16string recordAddText = record.addText.value_or(u"");
10767     int length = recordAddText.length();
10768     int32_t nowPosition = innerPosition;
10769     std::optional<TextStyle> style = std::nullopt;
10770     if (typingStyle_.has_value() && typingTextStyle_.has_value()) {
10771         style = typingTextStyle_.value();
10772     }
10773     if (!isDragSponsor_) { // drag from outside
10774         GetReplacedSpan(
10775             changeValue, innerPosition, recordAddText, innerPosition, style, std::nullopt, std::nullopt, true, false);
10776     } else if (nowPosition < record.beforeCaretPosition + length) { // move up
10777         innerPosition = record.beforeCaretPosition;
10778         GetDeletedSpan(changeValue, innerPosition, length, RichEditorDeleteDirection::FORWARD);
10779         innerPosition = nowPosition;
10780         GetReplacedSpan(
10781             changeValue, innerPosition, recordAddText, nowPosition, style, std::nullopt, std::nullopt, true, false);
10782     } else { // move down
10783         innerPosition = record.beforeCaretPosition;
10784         GetDeletedSpan(changeValue, innerPosition, length, RichEditorDeleteDirection::FORWARD);
10785         innerPosition = nowPosition - length;
10786         GetReplacedSpan(
10787             changeValue, innerPosition, recordAddText, nowPosition, style, std::nullopt, std::nullopt, true, false);
10788         FixMoveDownChange(changeValue, length);
10789     }
10790 }
10791 
10792 bool RichEditorPattern::BeforeChangeText(
10793     RichEditorChangeValue& changeValue, const OperationRecord& record, RecordType type, int32_t delLength)
10794 {
10795     int32_t innerPosition = caretPosition_;
10796     auto eventHub = GetEventHub<RichEditorEventHub>();
10797     CHECK_NULL_RETURN(eventHub, false);
10798     if (!eventHub->HasOnWillChange() && !eventHub->HasOnDidChange()) {
10799         return true;
10800     }
10801 
10802     if (RecordType::INSERT == type) {
10803         if (textSelector_.IsValid()) {
10804             GetDeletedSpan(changeValue, innerPosition,
10805                 static_cast<int32_t>(textSelector_.GetTextEnd() - textSelector_.GetTextStart()));
10806         } else if (!previewTextRecord_.previewContent.empty() || previewTextRecord_.needReplaceText) {
10807             GetDeletedSpan(changeValue, innerPosition,
10808                 static_cast<int32_t>(previewTextRecord_.replacedRange.end - previewTextRecord_.replacedRange.start));
10809         }
10810         if (record.addText.has_value()) {
10811             GetReplacedSpan(changeValue, innerPosition, record.addText.value(), innerPosition, std::nullopt, std::nullopt);
10812         }
10813     }
10814     if (RecordType::DEL_FORWARD == type) {
10815         innerPosition = record.beforeCaretPosition;
10816         GetDeletedSpan(changeValue, innerPosition, delLength, RichEditorDeleteDirection::FORWARD);
10817     }
10818     if (RecordType::DEL_BACKWARD == type) {
10819         innerPosition = record.beforeCaretPosition;
10820         GetDeletedSpan(changeValue, innerPosition, delLength, RichEditorDeleteDirection::BACKWARD);
10821     }
10822     if (RecordType::UNDO == type) {
10823         BeforeUndo(changeValue, innerPosition, record);
10824     }
10825     if (RecordType::REDO == type) {
10826         BeforeRedo(changeValue, innerPosition, record);
10827     }
10828     if (RecordType::DRAG == type) {
10829         BeforeDrag(changeValue, innerPosition, record);
10830     }
10831     bool isDelete = RecordType::DEL_FORWARD == type || RecordType::DEL_BACKWARD == type;
10832     if (changeValue.GetRichEditorOriginalSpans().empty() && !isDelete) {
10833         // only add, do not delete
10834         changeValue.SetRangeBefore({ caretPosition_, caretPosition_ });
10835     }
10836 
10837     CHECK_NULL_RETURN(eventHub->HasOnWillChange(), true);
10838     auto ret = eventHub->FireOnWillChange(changeValue);
10839     return ret;
10840 }
10841 
10842 OffsetF RichEditorPattern::GetTextPaintOffset() const
10843 {
10844     if (selectOverlay_->HasRenderTransform()) {
10845         return selectOverlay_->GetPaintRectOffsetWithTransform();
10846     }
10847     return GetPaintRectGlobalOffset();
10848 }
10849 
10850 OffsetF RichEditorPattern::GetPaintRectGlobalOffset() const
10851 {
10852     auto host = GetHost();
10853     CHECK_NULL_RETURN(host, OffsetF(0.0f, 0.0f));
10854     auto pipeline = host->GetContextRefPtr();
10855     CHECK_NULL_RETURN(pipeline, OffsetF(0.0f, 0.0f));
10856     auto rootOffset = pipeline->GetRootRect().GetOffset();
10857     auto textPaintOffset = host->GetPaintRectOffsetNG(false, true);
10858     return textPaintOffset - rootOffset;
10859 }
10860 
10861 void RichEditorPattern::HandlePointWithTransform(OffsetF& point)
10862 {
10863     auto host = GetHost();
10864     CHECK_NULL_VOID(host);
10865     PointF convertPoint = { point.GetX(), point.GetY() };
10866     auto parent = host;
10867     while (parent && (parent->GetTag() != V2::WINDOW_SCENE_ETS_TAG)) {
10868         auto renderContext = parent->GetRenderContext();
10869         CHECK_NULL_VOID(renderContext);
10870         auto paintOffset = renderContext->GetPaintRectWithoutTransform().GetOffset();
10871         if (parent != host) {
10872             convertPoint = convertPoint + paintOffset;
10873         }
10874         renderContext->GetPointTransform(convertPoint);
10875         parent = parent->GetAncestorNodeOfFrame(true);
10876     }
10877     point = { convertPoint.GetX(), convertPoint.GetY() };
10878 }
10879 
10880 CaretOffsetInfo RichEditorPattern::GetCaretOffsetInfoByPosition(int32_t position)
10881 {
10882     CaretOffsetInfo caretInfo;
10883     int32_t currrentPosition = 0;
10884     if (position == -1) {
10885         currrentPosition = caretPosition_;
10886     } else {
10887         currrentPosition = position;
10888     }
10889     caretInfo.caretOffsetUp = CalcCursorOffsetByPosition(currrentPosition, caretInfo.caretHeightUp, false, false);
10890     caretInfo.caretOffsetDown = CalcCursorOffsetByPosition(currrentPosition, caretInfo.caretHeightDown, true, false);
10891     caretInfo.caretOffsetLine = CalcCursorOffsetByPosition(currrentPosition, caretInfo.caretHeightLine);
10892     return caretInfo;
10893 }
10894 
10895 void RichEditorPattern::CalcLineSidesIndexByPosition(int32_t& startIndex, int32_t& endIndex)
10896 {
10897     Offset textStartOffset;
10898     Offset textEndOffset;
10899 
10900     CHECK_NULL_VOID(overlayMod_);
10901     auto overlayMod = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
10902     auto minDet = paragraphs_.minParagraphFontSize.value_or(GetTextThemeFontSize());
10903     float textOffsetY = richTextRect_.GetY() - (minDet / 2.0);
10904     auto currentCaretOffsetOverlay = overlayMod->GetCaretOffset();
10905     textStartOffset = Offset(0, currentCaretOffsetOverlay.GetY() - textOffsetY);
10906     textEndOffset = Offset(richTextRect_.Width(), currentCaretOffsetOverlay.GetY() - textOffsetY);
10907     startIndex = paragraphs_.GetIndex(textStartOffset);
10908     endIndex = paragraphs_.GetIndex(textEndOffset);
10909 }
10910 
10911 RectF RichEditorPattern::CalcLineInfoByPosition()
10912 {
10913     int32_t startIndex = 0;
10914     int32_t endIndex = 0;
10915 
10916     CalcLineSidesIndexByPosition(startIndex, endIndex);
10917     if (startIndex == endIndex) {
10918         endIndex += 1;
10919     }
10920     auto selectedRects = paragraphs_.GetRects(startIndex, endIndex);
10921     CHECK_NULL_RETURN(selectedRects.size(), {});
10922     return selectedRects.front();
10923 }
10924 
10925 int32_t RichEditorPattern::CalcMoveUpPos(float& leadingMarginOffset)
10926 {
10927     int32_t caretPosition;
10928     CaretOffsetInfo caretInfo;
10929     float textOffsetDownY = 0.0f;
10930     int32_t startIndex = 0;
10931     int32_t endIndex = 0;
10932     Offset textOffset;
10933 
10934     caretInfo = GetCaretOffsetInfoByPosition();
10935     auto minDet = paragraphs_.minParagraphFontSize.value_or(GetTextThemeFontSize());
10936     CHECK_NULL_RETURN(overlayMod_, 0);
10937     auto overlayMod = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
10938     auto caretOffsetOverlay = overlayMod->GetCaretOffset();
10939     auto caretOffsetWidth = overlayMod->GetCaretWidth();
10940     bool cursorNotAtLineStart = NearEqual(caretOffsetOverlay.GetX(), caretInfo.caretOffsetUp.GetX(), caretOffsetWidth);
10941     float textOffsetY = richTextRect_.GetY() + (minDet / 2.0); // 2.0 Cursor one half at the center position
10942     CalcLineSidesIndexByPosition(startIndex, endIndex);
10943     auto rectLineInfo = CalcLineInfoByPosition();
10944     leadingMarginOffset = rectLineInfo.GetX();
10945     if (cursorNotAtLineStart) {
10946         textOffsetDownY = caretInfo.caretOffsetLine.GetY() - textOffsetY;
10947         // lm mean leadingMargin abbr
10948         auto lmSizeOffset = (endIndex - startIndex <= 1 && NearEqual(rectLineInfo.Width(), richTextRect_.Width()))
10949                                 ? rectLineInfo.GetX()
10950                                 : 0;
10951         textOffset = Offset(caretInfo.caretOffsetLine.GetX() - richTextRect_.GetX() + lmSizeOffset, textOffsetDownY);
10952     } else {
10953         textOffsetDownY = caretInfo.caretOffsetLine.GetY() + caretInfo.caretHeightLine - textOffsetY;
10954         textOffset = Offset(caretOffsetOverlay.GetX() - richTextRect_.GetX(), textOffsetDownY);
10955     }
10956     caretPosition = paragraphs_.GetIndex(textOffset);
10957     return caretPosition;
10958 }
10959 
10960 int32_t RichEditorPattern::CalcMoveDownPos(float& leadingMarginOffset)
10961 {
10962     CaretOffsetInfo caretInfo;
10963     float textOffsetDownY = 0.0f;
10964     Offset textOffset;
10965     int32_t caretPositionEnd;
10966 
10967     caretInfo = GetCaretOffsetInfoByPosition();
10968     auto minDet = paragraphs_.minParagraphFontSize.value_or(GetTextThemeFontSize());
10969     CHECK_NULL_RETURN(overlayMod_, 0);
10970     auto overlayMod = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
10971     auto caretOffsetOverlay = overlayMod->GetCaretOffset();
10972     auto caretOffsetWidth = overlayMod->GetCaretWidth();
10973     float textOffsetX = richTextRect_.GetX();
10974     float textOffsetY = richTextRect_.GetY() - (minDet / 2.0);
10975     bool cursorNotAtLineStart = NearEqual(caretOffsetOverlay.GetX(), caretInfo.caretOffsetUp.GetX(), caretOffsetWidth);
10976     // midle or enter
10977     auto rectLineInfo = CalcLineInfoByPosition();
10978     leadingMarginOffset = rectLineInfo.GetX();
10979     auto lineHeightDis = rectLineInfo.Height();
10980     // midle or end, first line start position,end line end position
10981     textOffsetDownY = caretInfo.caretOffsetLine.GetY() + caretInfo.caretHeightLine - textOffsetY;
10982     float lastLineTop = 0.0f;
10983     float paragraphSpacing = 0.0f;
10984     HandleCurrentPositionParagraphInfo(lastLineTop, paragraphSpacing);
10985     if (cursorNotAtLineStart || caretPosition_ == 0) {
10986         IF_TRUE(NearEqual(std::floor(caretInfo.caretOffsetLine.GetY()), std::floor(lastLineTop)),
10987             textOffsetDownY += paragraphSpacing);
10988         textOffset = Offset(caretInfo.caretOffsetLine.GetX() - textOffsetX, textOffsetDownY);
10989     } else {
10990         IF_TRUE(NearEqual(std::floor(caretInfo.caretOffsetLine.GetY() + lineHeightDis), std::floor(lastLineTop)),
10991             textOffsetDownY += paragraphSpacing);
10992         textOffsetDownY += lineHeightDis;
10993         textOffset = Offset(caretOffsetOverlay.GetX() - textOffsetX, textOffsetDownY);
10994     }
10995     caretPositionEnd = paragraphs_.GetIndex(textOffset);
10996     return caretPositionEnd;
10997 }
10998 
10999 int32_t RichEditorPattern::CalcLineBeginPosition()
11000 {
11001     float caretHeight = 0.0f;
11002     OffsetF caretOffset = CalcCursorOffsetByPosition(caretPosition_, caretHeight, false, false);
11003     auto textPaintOffset = GetTextRect().GetOffset() - OffsetF(0.0, std::min(baselineOffset_, 0.0f));
11004     auto minDet = paragraphs_.minParagraphFontSize.value_or(GetTextThemeFontSize());
11005     auto textOffsetY = caretOffset.GetY() - textPaintOffset.GetY() + (minDet / 2.0);
11006     Offset textOffset = { 0, textOffsetY };
11007     auto newPos = paragraphs_.GetIndex(textOffset);
11008     return newPos;
11009 }
11010 
11011 float RichEditorPattern::GetTextThemeFontSize()
11012 {
11013     auto theme = GetTheme<TextTheme>();
11014     CHECK_NULL_RETURN(theme, 0.0f);
11015     auto textStyle = theme->GetTextStyle();
11016     return textStyle.GetFontSize().ConvertToPx();
11017 }
11018 
11019 int32_t RichEditorPattern::CalcLineEndPosition(int32_t index)
11020 {
11021     CaretOffsetInfo caretInfo;
11022     int32_t realCaretOffsetY = 0;
11023     int32_t realLastClickOffsetY = 0;
11024 
11025     caretInfo = GetCaretOffsetInfoByPosition(index);
11026     if (NearEqual(richTextRect_.GetY(), contentRect_.GetY())) {
11027         realLastClickOffsetY = lastClickOffset_.GetY();
11028         realCaretOffsetY = caretInfo.caretOffsetDown.GetY();
11029     } else {
11030         auto scrollOffset =
11031             caretInfo.caretOffsetDown.GetY() - caretInfo.caretOffsetUp.GetY() + caretInfo.caretOffsetLine.GetY();
11032         realLastClickOffsetY = lastClickOffset_.GetY() + std::abs(richTextRect_.GetY()) + contentRect_.GetY();
11033         realCaretOffsetY = scrollOffset + std::abs(richTextRect_.GetY()) + contentRect_.GetY();
11034     }
11035     auto textPaintOffset = contentRect_.GetOffset() - OffsetF(0.0, std::min(baselineOffset_, 0.0f));
11036     auto minDet = paragraphs_.minParagraphFontSize.value_or(GetTextThemeFontSize());
11037     Offset textOffset;
11038     auto rectLineInfo = CalcLineInfoByPosition();
11039     float textWidth = richTextRect_.Width() + rectLineInfo.GetX();
11040     float textPaintOffsetY = textPaintOffset.GetY() - (minDet / 2.0);
11041     float textOffsetClickY = realLastClickOffsetY - textPaintOffsetY;
11042     float textOffsetDownY = realCaretOffsetY - textPaintOffsetY;
11043     if (lastClickOffset_.NonNegative()) {
11044         textOffset = { textWidth, textOffsetClickY };
11045     } else {
11046         textOffset = { textWidth, textOffsetDownY };
11047     }
11048     auto position = paragraphs_.GetIndex(textOffset);
11049     return position;
11050 }
11051 
11052 int32_t RichEditorPattern::CalcSingleLineBeginPosition(int32_t fixedPos)
11053 {
11054     float caretHeightDown = 0.0f;
11055     OffsetF caretOffsetDown = CalcCursorOffsetByPosition(fixedPos, caretHeightDown, true, false);
11056     float caretHeightUp = 0.0f;
11057     OffsetF caretOffsetUp = CalcCursorOffsetByPosition(fixedPos, caretHeightUp, false, false);
11058     bool isCaretPosInLineEnd = !NearEqual(caretOffsetDown.GetX(), caretOffsetUp.GetX(), 0.5f);
11059 
11060     auto overlayMod = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
11061     CHECK_NULL_RETURN(overlayMod_, false);
11062     auto caretOffsetOverlay = overlayMod->GetCaretOffset();
11063     bool cursorNotAtLineStart = NearEqual(caretOffsetOverlay.GetX(), caretOffsetUp.GetX(), 0.5f);
11064 
11065     Offset textOffset;
11066     if (!cursorNotAtLineStart && !lastClickOffset_.IsNegative()) {
11067         return fixedPos;
11068     } else if (isCaretPosInLineEnd && lastClickOffset_.IsNegative()) {
11069         return lastSelectionRange_.start_;
11070     } else {
11071         float caretHeight = 0.0f;
11072         OffsetF caretOffsetFixed = CalcCursorOffsetByPosition(fixedPos, caretHeight, false, false);
11073         textOffset = { 0, caretOffsetFixed.GetY() };
11074     }
11075     auto position = paragraphs_.GetIndex(textOffset);
11076     return position;
11077 }
11078 
11079 int32_t RichEditorPattern::CalcSingleLineEndPosition(int32_t fixedPos)
11080 {
11081     auto rectLineInfo = CalcLineInfoByPosition();
11082     float textWidth = richTextRect_.Width() + rectLineInfo.GetX();
11083 
11084     float caretHeightDown = 0.0f;
11085     OffsetF caretOffsetDown = CalcCursorOffsetByPosition(fixedPos, caretHeightDown, true, false);
11086     float caretHeightUp = 0.0f;
11087     OffsetF caretOffsetUp = CalcCursorOffsetByPosition(fixedPos, caretHeightUp, false, false);
11088     bool isCaretPosInLineEnd = !NearEqual(caretOffsetDown.GetX(), caretOffsetUp.GetX(), 0.5f);
11089 
11090     auto overlayMod = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
11091     CHECK_NULL_RETURN(overlayMod_, false);
11092     auto caretOffsetOverlay = overlayMod->GetCaretOffset();
11093     bool cursorNotAtLineStart = NearEqual(caretOffsetOverlay.GetX(), caretOffsetUp.GetX(), 0.5f);
11094 
11095     Offset textOffset;
11096     if (isCaretPosInLineEnd && lastClickOffset_.IsNegative() && lastSelectionRange_.end_ > fixedPos) {
11097         return lastSelectionRange_.end_;
11098     } else if (!cursorNotAtLineStart && isCaretPosInLineEnd && fixedPos == caretPosition_) {
11099         textOffset = { textWidth, caretOffsetOverlay.GetY() };
11100     } else if (isCaretPosInLineEnd && lastSelectionRange_.end_ <= fixedPos) {
11101         CursorMoveLineEnd();
11102         return fixedPos;
11103     } else if (cursorNotAtLineStart && isCaretPosInLineEnd) {
11104         return fixedPos;
11105     } else {
11106         float caretHeight = 0.0f;
11107         OffsetF caretOffsetFixed = CalcCursorOffsetByPosition(fixedPos, caretHeight, false, false);
11108         textOffset = { textWidth, caretOffsetFixed.GetY() };
11109     }
11110     auto position = paragraphs_.GetIndex(textOffset);
11111     return position;
11112 }
11113 
11114 bool RichEditorPattern::CursorMoveLineBegin()
11115 {
11116     int32_t currentPositionIndex = 0;
11117     if (textSelector_.SelectNothing()) {
11118         currentPositionIndex = caretPosition_;
11119     } else {
11120         currentPositionIndex = textSelector_.GetTextStart();
11121     }
11122     CloseSelectOverlay();
11123     ResetSelection();
11124     float caretHeightDown = 0.0f;
11125     Offset textOffset;
11126 
11127     if (0 == currentPositionIndex) {
11128         SetCaretPosition(currentPositionIndex);
11129         StartTwinkling();
11130         return false;
11131     }
11132     OffsetF caretOffsetDown = CalcCursorOffsetByPosition(currentPositionIndex, caretHeightDown, true, false);
11133     auto textPaintOffset = GetTextRect().GetOffset() - OffsetF(0.0, std::min(baselineOffset_, 0.0f));
11134     auto minDet = paragraphs_.minParagraphFontSize.value_or(GetTextThemeFontSize());
11135     float textPaintOffsetY = textPaintOffset.GetY() - (minDet / 2.0);
11136     if (lastClickOffset_.NonNegative()) {
11137         textOffset = { 0, lastClickOffset_.GetY() - textPaintOffsetY };
11138     } else {
11139         textOffset = { 0, caretOffsetDown.GetY() - textPaintOffsetY };
11140     }
11141     auto position = paragraphs_.GetIndex(textOffset);
11142     AdjustCursorPosition(position);
11143     SetCaretPosition(position);
11144     MoveCaretToContentRect();
11145     StartTwinkling();
11146     auto host = GetHost();
11147     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
11148     return true;
11149 }
11150 
11151 bool RichEditorPattern::CursorMoveLineEnd()
11152 {
11153     int32_t position = 0;
11154     if (!textSelector_.SelectNothing()) {
11155         position = textSelector_.GetTextEnd();
11156         CaretOffsetInfo caretInfo = GetCaretOffsetInfoByPosition(position);
11157         bool cursorAtLineEnd = !NearEqual(caretInfo.caretOffsetUp.GetX(), caretInfo.caretOffsetDown.GetX(), 0.5f);
11158         bool cursorAfterNewLine = (position - 1) == GetParagraphEndPosition(position - 1);
11159         if (cursorAfterNewLine) {
11160             --position;
11161         } else if (!cursorAtLineEnd) {
11162             position = CalcLineEndPosition(textSelector_.GetTextEnd());
11163         }
11164     } else {
11165         position = CalcLineEndPosition();
11166     }
11167     CloseSelectOverlay();
11168     ResetSelection();
11169     float caretHeight = 0.0f;
11170     CHECK_NULL_RETURN(overlayMod_, false);
11171     auto overlayMod = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
11172     SetCaretPosition(position);
11173     StartTwinkling();
11174     OffsetF caretOffset = CalcCursorOffsetByPosition(caretPosition_, caretHeight, false, false);
11175     overlayMod->SetCaretOffsetAndHeight(caretOffset, caretHeight);
11176     SetLastClickOffset(caretOffset);
11177     caretAffinityPolicy_ = CaretAffinityPolicy::UPSTREAM_FIRST;
11178     MoveCaretToContentRect(caretOffset, caretHeight);
11179     auto host = GetHost();
11180     CHECK_NULL_RETURN(host, false);
11181     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
11182     return true;
11183 }
11184 
11185 void RichEditorPattern::HandleSelectFontStyle(KeyCode code)
11186 {
11187     if (textSelector_.SelectNothing() || isSpanStringMode_) {
11188         return;
11189     }
11190     auto host = GetHost();
11191     CHECK_NULL_VOID(host);
11192     UpdateSelectSpanStyle(textSelector_.GetTextStart(), textSelector_.GetTextEnd(), code);
11193     StopTwinkling();
11194     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
11195 }
11196 
11197 void RichEditorPattern::HandleOnShowMenu()
11198 {
11199     auto isSelectAreaVisible = IsSelectAreaVisible();
11200     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "HandleOnShowMenu, selectAreaVisible=%{public}d,"
11201         "previewTextInputting=%{public}d,isDragging=%{public}d,isMoveCaret=%{public}d,isHandleMoving=%{public}d,"
11202         "isTouchSelecting=%{public}d,mouseStatus=%{public}d",
11203         isSelectAreaVisible, IsPreviewTextInputting(), IsDragging(), moveCaretState_.isMoveCaret,
11204         selectOverlay_->GetIsHandleMoving(), isTouchSelecting_, mouseStatus_);
11205     CHECK_NULL_VOID(isSelectAreaVisible && !IsPreviewTextInputting() && !IsDragging());
11206     CHECK_NULL_VOID(!moveCaretState_.isMoveCaret && !selectOverlay_->GetIsHandleMoving());
11207     CHECK_NULL_VOID(!isTouchSelecting_ && mouseStatus_ != MouseStatus::MOVE);
11208 
11209     if (sourceType_ == SourceType::MOUSE) {
11210         if (!IsSelected()) {
11211             selectedType_ = TextSpanType::TEXT;
11212         }
11213         textResponseType_ = TextResponseType::RIGHT_CLICK;
11214         selectionMenuOffsetByMouse_ = GetCaretRect().GetOffset() + GetParentGlobalOffset();
11215         selectOverlay_->ProcessOverlay({ .animation = true });
11216         return;
11217     }
11218     if (!IsSelected()) {
11219         CreateAndShowSingleHandle();
11220         return;
11221     }
11222     if (SelectOverlayIsOn()) {
11223         selectOverlay_->SwitchToOverlayMode();
11224         if (selectOverlay_->NeedRefreshMenu()) {
11225             selectOverlay_->ProcessOverlay({ .animation = true, .requestCode = REQUEST_RECREATE });
11226             return;
11227         }
11228         selectOverlay_->UpdateMenuOffset();
11229         selectOverlay_->ShowMenu();
11230         return;
11231     }
11232     CalculateHandleOffsetAndShowOverlay();
11233     selectOverlay_->ProcessOverlay({ .animation = true });
11234 }
11235 
11236 PositionType RichEditorPattern::GetPositionTypeFromLine()
11237 {
11238     auto overlayMod = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
11239     CHECK_NULL_RETURN(overlayMod, PositionType::DEFAULT);
11240     auto currentCaretOffsetOverlay = overlayMod->GetCaretOffset();
11241     auto caretOffsetWidth = overlayMod->GetCaretWidth();
11242     int32_t currentParagraphStart = GetParagraphBeginPosition(caretPosition_);
11243     bool isParagraphStart = caretPosition_ == currentParagraphStart;
11244     CHECK_NULL_RETURN(!isParagraphStart, PositionType::PARAGRAPH_START);
11245     int32_t currentParagraphEnd = GetParagraphEndPosition(caretPosition_);
11246     bool isParagraphEnd = caretPosition_ == currentParagraphEnd;
11247     CHECK_NULL_RETURN(!isParagraphEnd, PositionType::PARAGRAPH_END);
11248     CaretOffsetInfo caretInfo = GetCaretOffsetInfoByPosition();
11249     bool isCaretAtLineMiddle = NearEqual(caretInfo.caretOffsetDown.GetX(), caretInfo.caretOffsetUp.GetX(), 0.5f);
11250     CHECK_NULL_RETURN(!isCaretAtLineMiddle, PositionType::DEFAULT);
11251     bool isCaretAtLineEnd =
11252         NearEqual(currentCaretOffsetOverlay.GetX(), caretInfo.caretOffsetUp.GetX(), caretOffsetWidth);
11253     CHECK_NULL_RETURN(!isCaretAtLineEnd, PositionType::LINE_END);
11254     return PositionType::LINE_START;
11255 }
11256 
11257 int32_t RichEditorPattern::HandleSelectWrapper(CaretMoveIntent direction, int32_t fixedPos)
11258 {
11259     int32_t index = GetCaretPosition();
11260     switch (direction) {
11261         case CaretMoveIntent::Left:
11262             return CaretPositionSelectEmoji(CaretMoveIntent::Left);
11263         case CaretMoveIntent::Right:
11264             return CaretPositionSelectEmoji(CaretMoveIntent::Right);
11265         case CaretMoveIntent::Up:
11266             return HandleKbVerticalSelection(true);
11267         case CaretMoveIntent::Down:
11268             return HandleKbVerticalSelection(false);
11269         case CaretMoveIntent::LeftWord: {
11270             return GetLeftWordIndex(index);
11271         }
11272         case CaretMoveIntent::RightWord: {
11273             return GetRightWordIndex(index);
11274         }
11275         case CaretMoveIntent::ParagraghBegin:
11276             return HandleSelectParagraghPos(true);
11277         case CaretMoveIntent::ParagraghEnd:
11278             return HandleSelectParagraghPos(false);
11279         case CaretMoveIntent::LineBegin:
11280             return CalcSingleLineBeginPosition(fixedPos);
11281         case CaretMoveIntent::LineEnd:
11282             return CalcSingleLineEndPosition(fixedPos);
11283         default:
11284             return NONE_SELECT_TYPE;
11285     }
11286 }
11287 
11288 int32_t RichEditorPattern::HandleKbVerticalSelection(bool isUp)
11289 {
11290     float caretHeight = 0.0f;
11291     float newCaretHeight = 0.0f;
11292     float careOffsetY = 0.0f;
11293     int32_t newPos;
11294     Offset textOffset;
11295     OffsetF caretOffset = CalcCursorOffsetByPosition(caretPosition_, caretHeight);
11296     auto minDet = paragraphs_.minParagraphFontSize.value_or(GetTextThemeFontSize()) / 2.0;
11297     auto positionType = GetPositionTypeFromLine();
11298     if (isUp) {
11299         float selectStartHeight = 0.0f;
11300         OffsetF selectStartOffset = CalcCursorOffsetByPosition(textSelector_.GetTextStart(), selectStartHeight);
11301         careOffsetY = caretOffset.GetY() - GetTextRect().GetY() - minDet;
11302         textOffset = Offset(caretOffset.GetX() - GetTextRect().GetX(), careOffsetY);
11303         CHECK_NULL_RETURN(GreatNotEqual(textOffset.GetY(), 0), 0);
11304         newPos = paragraphs_.GetIndex(textOffset, true);
11305         OffsetF newCaretOffset = CalcCursorOffsetByPosition(newPos, newCaretHeight);
11306         CHECK_EQUAL_RETURN(!textSelector_.SelectNothing() && textSelector_.GetTextEnd() == caretPosition_ &&
11307             selectStartOffset.GetY() == newCaretOffset.GetY(), true, textSelector_.GetTextStart());
11308     } else {
11309         float selectEndHeight = 0.0f;
11310         OffsetF selectEndOffset = CalcCursorOffsetByPosition(textSelector_.GetEnd(), selectEndHeight);
11311         careOffsetY = caretOffset.GetY() - GetTextRect().GetY() + caretHeight + (minDet / 2.0);
11312         float lastLineTop = 0.0f;
11313         float paragraphSpacing = 0.0f;
11314         HandleCurrentPositionParagraphInfo(lastLineTop, paragraphSpacing);
11315         if (positionType == PositionType::LINE_START) {
11316             auto overlayMod = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
11317             CHECK_NULL_RETURN(overlayMod, 0);
11318             auto caretOffsetOverlay = overlayMod->GetCaretOffset();
11319             auto rectLineInfo = CalcLineInfoByPosition();
11320             careOffsetY += rectLineInfo.Height();
11321             IF_TRUE(NearEqual(std::floor(caretOffset.GetY() + rectLineInfo.Height()), std::floor(lastLineTop)),
11322                 careOffsetY += paragraphSpacing);
11323             textOffset = Offset(caretOffsetOverlay.GetX() - GetTextRect().GetX(), careOffsetY);
11324         } else {
11325             IF_TRUE(NearEqual(std::floor(caretOffset.GetY()), std::floor(lastLineTop)),
11326                 careOffsetY += paragraphSpacing);
11327             textOffset = Offset(caretOffset.GetX() - GetTextRect().GetX(), careOffsetY);
11328         }
11329         auto height = paragraphs_.GetHeight();
11330         CHECK_NULL_RETURN(LessNotEqual(textOffset.GetY(), height), GetTextContentLength());
11331         newPos = paragraphs_.GetIndex(textOffset, true);
11332         OffsetF newCaretOffset = CalcCursorOffsetByPosition(newPos, newCaretHeight);
11333         CHECK_EQUAL_RETURN(!textSelector_.SelectNothing() && textSelector_.GetTextStart() == caretPosition_ &&
11334             selectEndOffset.GetY() == newCaretOffset.GetY(), true, textSelector_.GetTextEnd());
11335     }
11336     return newPos;
11337 }
11338 
11339 int32_t RichEditorPattern::HandleSelectParagraghPos(bool direction)
11340 {
11341     int32_t newPos = 0;
11342     CloseSelectOverlay();
11343     ResetSelection();
11344     if (direction) {
11345         newPos = GetParagraphBeginPosition(caretPosition_);
11346         if (newPos == caretPosition_ && caretPosition_ > 0) {
11347             newPos = GetParagraphBeginPosition(caretPosition_ - 1);
11348         }
11349     } else {
11350         newPos = GetParagraphEndPosition(caretPosition_);
11351         if (newPos == caretPosition_ && caretPosition_ < static_cast<int32_t>(GetTextContentLength())) {
11352             newPos = GetParagraphEndPosition(caretPosition_ + 1);
11353         }
11354     }
11355     return newPos;
11356 }
11357 
11358 void RichEditorPattern::HandleSelectFontStyleWrapper(KeyCode code, TextStyle& spanStyle)
11359 {
11360     switch (code) {
11361         case KeyCode::KEY_B:
11362             if (spanStyle.GetFontWeight() == Ace::FontWeight::BOLD) {
11363                 spanStyle.SetFontWeight(Ace::FontWeight::NORMAL);
11364             } else {
11365                 spanStyle.SetFontWeight(Ace::FontWeight::BOLD);
11366             }
11367             break;
11368         case KeyCode::KEY_I:
11369             if (spanStyle.GetFontStyle() == OHOS::Ace::FontStyle::ITALIC) {
11370                 spanStyle.SetFontStyle(OHOS::Ace::FontStyle::NORMAL);
11371             } else {
11372                 spanStyle.SetFontStyle(OHOS::Ace::FontStyle::ITALIC);
11373             }
11374             break;
11375         case KeyCode::KEY_U:
11376             if (spanStyle.GetTextDecoration() == TextDecoration::UNDERLINE) {
11377                 spanStyle.SetTextDecoration(TextDecoration::NONE);
11378             } else {
11379                 spanStyle.SetTextDecoration(TextDecoration::UNDERLINE);
11380             }
11381             break;
11382         default:
11383             LOGW("Unsupported select operation for HandleSelectFrontStyle");
11384             return;
11385     }
11386 }
11387 
11388 void RichEditorPattern::AIDeleteComb(int32_t start, int32_t end, int32_t& aiPosition, bool direction)
11389 {
11390     std::u16string selectTextContent;
11391     GetContentBySpans(selectTextContent);
11392     // get select content
11393     std::u16string selectData16 = selectTextContent.substr(static_cast<int32_t>(start), static_cast<int32_t>(end - start));
11394     std::string selectData = StringUtils::Str16ToStr8(selectData16);
11395     int32_t aiPosStart;
11396     int32_t aiPosEnd;
11397     int32_t caretPosition;
11398     int32_t size = 1;
11399 
11400     if (direction) {
11401         caretPosition = end - start - size;
11402         DataDetectorMgr::GetInstance().AdjustWordSelection(caretPosition, selectData, aiPosStart, aiPosEnd);
11403         aiPosition = aiPosStart + start;
11404     } else {
11405         caretPosition = 0;
11406         DataDetectorMgr::GetInstance().AdjustWordSelection(caretPosition, selectData, aiPosStart, aiPosEnd);
11407         aiPosition = aiPosEnd + start;
11408     }
11409     if (aiPosStart < 0 || aiPosEnd < 0) {
11410         aiPosition = GetCaretPosition();
11411     }
11412 }
11413 
11414 bool RichEditorPattern::HandleOnDeleteComb(bool backward)
11415 {
11416     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "HandleOnDeleteComb backward=%{public}d", backward);
11417     if (textSelector_.IsValid()) {
11418         CloseSelectOverlay();
11419         SetCaretPosition(textSelector_.GetTextStart());
11420         ResetSelection();
11421     }
11422     if (backward) {
11423         DeleteBackwardWord();
11424     } else {
11425         DeleteForwardWord();
11426     }
11427     MoveCaretToContentRect();
11428     StartTwinkling();
11429     auto host = GetHost();
11430     CHECK_NULL_RETURN(host, false);
11431     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
11432     return true;
11433 }
11434 
11435 void RichEditorPattern::DeleteBackwardWord()
11436 {
11437     CHECK_NULL_VOID(caretPosition_ != 0);
11438     int32_t startIndex = caretPosition_;
11439     int32_t spaceEndIndex = startIndex;
11440     AdjustIndexSkipSpace(spaceEndIndex, MoveDirection::BACKWARD);
11441     int32_t wordEndIndex = std::max(0, spaceEndIndex - 1);
11442     AdjustSelectorForSymbol(wordEndIndex, HandleType::FIRST, SelectorAdjustPolicy::INCLUDE);
11443     AdjustWordSelection(wordEndIndex, spaceEndIndex);
11444     DeleteBackward(startIndex - wordEndIndex);
11445 }
11446 
11447 void RichEditorPattern::DeleteForwardWord()
11448 {
11449     CHECK_NULL_VOID(caretPosition_ != GetTextContentLength());
11450     int32_t startIndex = caretPosition_;
11451     int32_t spaceEndIndex = startIndex;
11452     AdjustIndexSkipSpace(spaceEndIndex, MoveDirection::FORWARD);
11453     int32_t wordEndIndex = std::min(spaceEndIndex + 1, GetTextContentLength());
11454     AdjustWordSelection(spaceEndIndex, wordEndIndex);
11455     DeleteForward(wordEndIndex - startIndex);
11456 }
11457 
11458 const std::list<RefPtr<UINode>>& RichEditorPattern::GetAllChildren() const
11459 {
11460     childNodes_.clear();
11461     auto host = GetHost();
11462     CHECK_NULL_RETURN(host, childNodes_);
11463     auto children = host->GetChildren();
11464     for (const auto& child: children) {
11465         childNodes_.push_back(child);
11466     }
11467     return childNodes_;
11468 }
11469 
11470 void RichEditorPattern::HandleTripleClickEvent(OHOS::Ace::GestureEvent& info)
11471 {
11472     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "HandleTripleClickEvent");
11473     CHECK_EQUAL_VOID(IsPreviewTextInputting(), true);
11474     CHECK_EQUAL_VOID(IsDragging(), true);
11475     bool isMouseClickWithShift = shiftFlag_ && info.GetSourceDevice() == SourceType::MOUSE;
11476     CHECK_EQUAL_VOID(isMouseClickWithShift, true);
11477     auto focusHub = GetFocusHub();
11478     CHECK_NULL_VOID(focusHub);
11479     CHECK_EQUAL_VOID(focusHub->IsFocusable(), false);
11480     auto textPaintOffset = GetTextRect().GetOffset() - OffsetF(0.0, std::min(baselineOffset_, 0.0f));
11481     Offset textOffset = { info.GetLocalLocation().GetX() - textPaintOffset.GetX(),
11482         info.GetLocalLocation().GetY() - textPaintOffset.GetY() };
11483     int32_t pos = paragraphs_.GetIndex(textOffset);
11484 
11485     int32_t start = 0;
11486     int32_t end = 0;
11487     auto& paragraphInfoList = paragraphs_.GetParagraphs();
11488     if (!paragraphInfoList.empty() && pos == paragraphInfoList.back().end) {
11489         start = paragraphInfoList.back().start;
11490         end = paragraphInfoList.back().end;
11491     } else {
11492         for (const auto& paragraph : paragraphInfoList) {
11493             if (pos >= paragraph.start && pos < paragraph.end) {
11494                 start = paragraph.start;
11495                 end = paragraph.end;
11496                 break;
11497             }
11498         }
11499     }
11500     if (!paragraphInfoList.empty() && paragraphInfoList.back().end != end) {
11501         --end;
11502     }
11503     end = std::min(GetTextContentLength(), end);
11504     start = std::min(GetTextContentLength(), start);
11505     CHECK_EQUAL_VOID(start > end, true);
11506     TripleClickSection(info, start, end, pos);
11507 }
11508 
11509 void RichEditorPattern::UpdateSelectionByTouchMove(const Offset& touchOffset)
11510 {
11511     // While previewing + long press and move, then shall select content.
11512     auto host = GetHost();
11513     CHECK_NULL_VOID(host);
11514 
11515     Offset textOffset = ConvertTouchOffsetToTextOffset(touchOffset);
11516     auto positionWithAffinity = paragraphs_.GetGlyphPositionAtCoordinate(textOffset);
11517     SetCaretPositionWithAffinity(positionWithAffinity);
11518     MoveCaretToContentRect();
11519     int32_t currentPosition = GreatNotEqual(textOffset.GetY(), paragraphs_.GetHeight())
11520                                 ? GetTextContentLength()
11521                                 : caretPosition_;
11522     IF_TRUE(GetTextContentLength() > 0, SetMagnifierLocalOffset(touchOffset));
11523     auto [initSelectStart, initSelectEnd] = initSelector_;
11524     int32_t start = std::min(initSelectStart, currentPosition);
11525     int32_t end = std::max(initSelectEnd, currentPosition);
11526     if (start == textSelector_.GetTextStart()) {
11527         StartVibratorByIndexChange(end, textSelector_.GetTextEnd());
11528     } else {
11529         StartVibratorByIndexChange(start, textSelector_.GetTextStart());
11530     }
11531     HandleSelectionChange(start, end);
11532     TriggerAvoidOnCaretChange();
11533     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
11534 }
11535 
11536 void RichEditorPattern::HideMenu()
11537 {
11538     selectOverlay_->HideMenu();
11539 }
11540 
11541 void RichEditorPattern::OnSelectionMenuOptionsUpdate(
11542     const NG::OnCreateMenuCallback&& onCreateMenuCallback, const NG::OnMenuItemClickCallback&& onMenuItemClick)
11543 {
11544     selectOverlay_->OnSelectionMenuOptionsUpdate(std::move(onCreateMenuCallback), std::move(onMenuItemClick));
11545 }
11546 
11547 bool RichEditorPattern::CheckTripClickEvent(GestureEvent& info)
11548 {
11549     clickInfo_.push_back(info.GetTimeStamp());
11550     if (clickInfo_.size() > MAX_CLICK) {
11551         clickInfo_.erase(clickInfo_.begin());
11552     }
11553     if (clickInfo_.size() == MAX_CLICK) {
11554         std::chrono::duration<float, std::ratio<1, InputAIChecker::SECONDS_TO_MILLISECONDS>>
11555             clickTimeIntervalOne = clickInfo_[1] - clickInfo_[0];
11556         std::chrono::duration<float, std::ratio<1, InputAIChecker::SECONDS_TO_MILLISECONDS>>
11557             clickTimeIntervalTwo = clickInfo_[2] - clickInfo_[1];
11558         if (clickTimeIntervalOne.count() < DOUBLE_CLICK_INTERVAL_MS
11559             && clickTimeIntervalTwo.count() < DOUBLE_CLICK_INTERVAL_MS) {
11560             return true;
11561         }
11562     }
11563     return false;
11564 }
11565 
11566 void RichEditorPattern::PreferredParagraph()
11567 {
11568     CHECK_NULL_VOID(typingTextStyle_.has_value());
11569     if (presetParagraph_) {
11570         presetParagraph_->Reset();
11571         presetParagraph_ = nullptr;
11572     }
11573     std::string textContent;
11574     textContent = "a";
11575     TextStyle textStyle;
11576     textStyle = typingTextStyle_.value();
11577     ParagraphStyle paraStyle {
11578         .align = textStyle.GetTextAlign(),
11579         .maxLines = textStyle.GetMaxLines(),
11580         .fontLocale = Localization::GetInstance()->GetFontLocale(),
11581         .wordBreak = textStyle.GetWordBreak(),
11582         .lineBreakStrategy = textStyle.GetLineBreakStrategy(),
11583         .textOverflow = textStyle.GetTextOverflow(),
11584         .fontSize = textStyle.GetFontSize().ConvertToPx(),
11585         .halfLeading = textStyle.GetHalfLeading(),
11586         .paragraphSpacing = textStyle.GetParagraphSpacing() };
11587     presetParagraph_ = Paragraph::Create(paraStyle, FontCollection::Current());
11588     CHECK_NULL_VOID(presetParagraph_);
11589     presetParagraph_->PushStyle(textStyle);
11590     presetParagraph_->AddText(StringUtils::Str8ToStr16(textContent));
11591     presetParagraph_->Build();
11592     presetParagraph_->Layout(std::numeric_limits<double>::infinity());
11593 }
11594 
11595 void RichEditorPattern::TripleClickSection(GestureEvent& info, int32_t start, int32_t end, int32_t pos)
11596 {
11597     auto host = GetHost();
11598     CHECK_NULL_VOID(host);
11599     textSelector_.Update(start, end);
11600     if (IsShowHandle()) {
11601         SetCaretPositionWithAffinity({ end, TextAffinity::UPSTREAM });
11602         MoveCaretToContentRect();
11603     }
11604     UpdateSelectionType(GetSpansInfo(start, end, GetSpansMethod::ONSELECT));
11605     if (info.GetSourceDevice() == SourceType::TOUCH) {
11606         showSelect_ = true;
11607         RequestKeyboard(false, true, true);
11608         HandleOnEditChanged(true);
11609         CalculateHandleOffsetAndShowOverlay();
11610         selectOverlay_->ProcessOverlay({ .menuIsShow = !selectOverlay_->GetIsHandleMoving(), .animation = true });
11611     }
11612     if (info.GetSourceDevice() == SourceType::TOUCH && start == end) {
11613         selectOverlay_->SetIsSingleHandle(true);
11614     }
11615     if (textSelector_.SelectNothing()) {
11616         textSelector_.Update(pos, pos);
11617     } else {
11618         StopTwinkling();
11619     }
11620     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
11621 }
11622 
11623 void RichEditorPattern::RequestKeyboardToEdit()
11624 {
11625     CHECK_NULL_VOID(!isEditing_ && HasFocus());
11626     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "request keyboard and enter edit");
11627     RequestKeyboard(false, true, true);
11628     HandleOnEditChanged(true);
11629 }
11630 
11631 bool RichEditorPattern::IsResponseRegionExpandingNeededForStylus(const TouchEvent& touchEvent) const
11632 {
11633     if (touchEvent.sourceTool != SourceTool::PEN || touchEvent.type != TouchType::DOWN) {
11634         return false;
11635     }
11636     auto host = GetHost();
11637     CHECK_NULL_RETURN(host, false);
11638     auto focusHub = host->GetFocusHub();
11639     CHECK_NULL_RETURN(focusHub, false);
11640     if (!focusHub->IsFocusable() || !host->IsVisible()) {
11641         return false;
11642     }
11643     auto renderContext = host->GetRenderContext();
11644     CHECK_NULL_RETURN(renderContext, false);
11645     auto opacity = renderContext->GetOpacity();
11646     // if opacity is 0.0f, no need to hit frameNode.
11647     if (NearZero(opacity.value_or(1.0f))) {
11648         return false;
11649     }
11650     return true;
11651 }
11652 
11653 RectF RichEditorPattern::ExpandDefaultResponseRegion(RectF& rect)
11654 {
11655     return rect + NG::SizeF(0, OHOS::Ace::HOT_AREA_ADJUST_SIZE.ConvertToPx() * OHOS::Ace::HOT_AREA_EXPAND_TIME) +
11656            NG::OffsetF(0, -OHOS::Ace::HOT_AREA_ADJUST_SIZE.ConvertToPx());
11657 }
11658 
11659 bool RichEditorPattern::InsertOrDeleteSpace(int32_t index)
11660 {
11661     // delete or insert space
11662     if (index < 0 || index >= GetTextContentLength()) {
11663         TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "index is invalid, index=%{public}d", index);
11664         return false;
11665     }
11666     bool success = SetCaretPosition(index);
11667     CHECK_NULL_RETURN(success, false);
11668     CloseSelectOverlay();
11669     ResetSelection();
11670 
11671     auto curIt = GetSpanIter(index);
11672     if (curIt != spans_.end()) {
11673         std::u16string curText = (*curIt)->content;
11674         if ((*curIt)->spanItemType == SpanItemType::NORMAL
11675             && index >= (*curIt)->rangeStart && curText[index - (*curIt)->rangeStart] == u' ') {
11676             TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "delete forward");
11677             DeleteForward(1);
11678             return true;
11679         }
11680     }
11681 
11682     auto preIt = GetSpanIter(index - 1);
11683     if (preIt != spans_.end()) {
11684         std::u16string preText = (*preIt)->content;
11685         if ((*preIt)->spanItemType == SpanItemType::NORMAL
11686             && index - 1 >= (*preIt)->rangeStart && preText[index - 1 - (*preIt)->rangeStart] == u' ') {
11687             TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "delete backward");
11688             DeleteBackward(1);
11689             return true;
11690         }
11691     }
11692 
11693     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "insert value");
11694     InsertValue(u" ", true);
11695     return true;
11696 }
11697 
11698 void RichEditorPattern::DeleteRange(int32_t start, int32_t end, bool isIME)
11699 {
11700     if (start > end) {
11701         std::swap(start, end);
11702     }
11703     start = std::max(0, start);
11704     end = std::min(GetTextContentLength(), end);
11705     if (start > GetTextContentLength() || end < 0 || start == end) {
11706         TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "start=%{public}d, end=%{public}d, not in the range", start, end);
11707         return;
11708     }
11709     CHECK_NULL_VOID(!IsPreviewTextInputting());
11710     SetCaretPosition(start);
11711     auto length = end - start;
11712     if (isSpanStringMode_) {
11713         DeleteValueInStyledString(start, length, true, false);
11714         return;
11715     }
11716     OperationRecord record;
11717     record.beforeCaretPosition = caretPosition_;
11718     RichEditorChangeValue changeValue;
11719     CHECK_NULL_VOID(BeforeChangeText(changeValue, record, RecordType::DEL_FORWARD, length));
11720     std::u16string textContent;
11721     GetContentBySpans(textContent);
11722     auto realEnd = std::clamp(caretPosition_ + length, 0, static_cast<int32_t>(textContent.length()));
11723     std::u16string deleteText = textContent.substr(
11724         static_cast<uint32_t>(std::clamp(caretPosition_, 0, static_cast<int32_t>(textContent.length()))),
11725         static_cast<uint32_t>(realEnd - caretPosition_));
11726     if (caretPosition_ != GetTextContentLength()) {
11727         RichEditorDeleteValue info;
11728         info.SetOffset(caretPosition_);
11729         info.SetRichEditorDeleteDirection(RichEditorDeleteDirection::FORWARD);
11730         info.SetLength(length);
11731         int32_t currentPosition = caretPosition_;
11732         if (!spans_.empty()) {
11733             CalcDeleteValueObj(currentPosition, length, info);
11734             bool doDelete = DoDeleteActions(currentPosition, length, info);
11735             CHECK_NULL_VOID(doDelete);
11736         }
11737     }
11738     CHECK_NULL_VOID(deleteText.length() != 0);
11739     ClearRedoOperationRecords();
11740     record.deleteText = deleteText;
11741     record.afterCaretPosition = caretPosition_;
11742     AddOperationRecord(record);
11743     AfterContentChange(changeValue);
11744 }
11745 
11746 void RichEditorPattern::HandleOnPageUp()
11747 {
11748     HandlePageScroll(true);
11749 }
11750 
11751 void RichEditorPattern::HandleOnPageDown()
11752 {
11753     HandlePageScroll(false);
11754 }
11755 
11756 void RichEditorPattern::HandlePageScroll(bool isPageUp)
11757 {
11758     auto visibleRect = selectOverlay_->GetVisibleRect();
11759     float distance = isPageUp ? visibleRect.Height() : -visibleRect.Height();
11760     RectF curCaretRect = GetCaretRect();
11761     auto height = paragraphs_.GetHeight();
11762     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "PageScroll isPageUp:%{public}d distance:%{public}f paragraphsHeight:%{public}f",
11763         isPageUp, distance, height);
11764     CloseSelectOverlay();
11765     ResetSelection();
11766     OnScrollCallback(distance, SCROLL_FROM_JUMP);
11767     auto paintOffset = selectOverlay_->GetPaintOffsetWithoutTransform();
11768     float offsetY = isPageUp ? visibleRect.Top() : visibleRect.Bottom();
11769     auto localOffset = Offset(curCaretRect.GetX(), offsetY - paintOffset.GetY());
11770     auto textOffset = ConvertTouchOffsetToTextOffset(localOffset);
11771     auto positionWithAffinity = paragraphs_.GetGlyphPositionAtCoordinate(textOffset);
11772     // If scrolling to the first or last line, move the cursor to the beginning or end of the line
11773     if (isPageUp && LessOrEqual(textOffset.GetY(), 0)) {
11774         positionWithAffinity = PositionWithAffinity(0, TextAffinity::DOWNSTREAM);
11775     } else if (!isPageUp && GreatOrEqual(textOffset.GetY(), height)) {
11776         positionWithAffinity = PositionWithAffinity(GetTextContentLength(), TextAffinity::UPSTREAM);
11777     }
11778     SetCaretPositionWithAffinity(positionWithAffinity);
11779     IF_TRUE(isEditing_, StartTwinkling());
11780 }
11781 
11782 TextStyle RichEditorPattern::GetDefaultTextStyle()
11783 {
11784     auto theme = GetTheme<RichEditorTheme>();
11785     TextStyle style = theme ? theme->GetTextStyle() : TextStyle();
11786     style.SetFontSize(Dimension(DEFAULT_TEXT_SIZE, DimensionUnit::FP));
11787     style.SetFontFeatures(ParseFontFeatureSettings("\"pnum\" 1"));
11788     style.SetFontFamilies({ "HarmonyOS Sans" });
11789     return style;
11790 }
11791 
11792 bool RichEditorPattern::IsShowTranslate()
11793 {
11794     auto richEditorTheme = GetTheme<RichEditorTheme>();
11795     CHECK_NULL_RETURN(richEditorTheme, false);
11796     return richEditorTheme->GetTranslateIsSupport();
11797 }
11798 
11799 bool RichEditorPattern::IsShowSearch()
11800 {
11801     auto richEditorTheme = GetTheme<RichEditorTheme>();
11802     CHECK_NULL_RETURN(richEditorTheme, false);
11803     return richEditorTheme->GetSearchIsSupport();
11804 }
11805 
11806 bool RichEditorPattern::IsShowAIWrite()
11807 {
11808     CHECK_NULL_RETURN(!textSelector_.SelectNothing(), false);
11809     auto container = Container::Current();
11810     if (container && container->IsScenceBoardWindow()) {
11811         return false;
11812     }
11813 
11814     if (copyOption_ == CopyOptions::None) {
11815         return false;
11816     }
11817     auto theme = GetTheme<RichEditorTheme>();
11818     CHECK_NULL_RETURN(theme, false);
11819     auto bundleName = theme->GetAIWriteBundleName();
11820     auto abilityName = theme->GetAIWriteAbilityName();
11821     if (bundleName.empty() || abilityName.empty()) {
11822         TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "Failed to obtain AI write package name!");
11823         return false;
11824     }
11825     aiWriteAdapter_->SetBundleName(bundleName);
11826     aiWriteAdapter_->SetAbilityName(abilityName);
11827 
11828     auto isAISupport = false;
11829     if (theme->GetAIWriteIsSupport() == "true") {
11830         isAISupport = true;
11831     }
11832 
11833     auto host = GetHost();
11834     CHECK_NULL_RETURN(host, false);
11835     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "Whether the device supports AI write: %{public}d, nodeId: %{public}d",
11836         isAISupport, host->GetId());
11837     return isAISupport;
11838 }
11839 
11840 void RichEditorPattern::GetAIWriteInfo(AIWriteInfo& info)
11841 {
11842     CHECK_NULL_VOID(!textSelector_.SelectNothing());
11843     info.firstHandle = textSelector_.firstHandle.ToString();
11844     info.secondHandle = textSelector_.secondHandle.ToString();
11845     info.selectStart = textSelector_.GetTextStart();
11846     info.selectEnd = textSelector_.GetTextEnd();
11847     auto host = GetHost();
11848     CHECK_NULL_VOID(host);
11849     info.componentType = host->GetTag();
11850 
11851     // serialize the sentenced-level text
11852     auto textSize = static_cast<int32_t>(GetTextForDisplay().length()) + placeholderCount_;
11853     RefPtr<SpanString> spanString = ToStyledString(0, textSize);
11854     auto contentAll = spanString->GetU16string();
11855     auto sentenceStart = 0;
11856     auto sentenceEnd = textSize;
11857     for (int32_t i = info.selectStart; i >= 0; --i) {
11858         if (aiWriteAdapter_->IsSentenceBoundary(contentAll[i])) {
11859             sentenceStart = i + 1;
11860             break;
11861         }
11862     }
11863     for (int32_t i = info.selectEnd; i < textSize; i++) {
11864         if (aiWriteAdapter_->IsSentenceBoundary(contentAll[i])) {
11865             sentenceEnd = i;
11866             break;
11867         }
11868     }
11869     info.start = info.selectStart - sentenceStart;
11870     info.end = info.selectEnd - sentenceStart;
11871     spanString = ToStyledString(sentenceStart, sentenceEnd);
11872     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "Sentence range=[%{public}d-%{public}d], content=" SEC_PLD(%{public}s),
11873         sentenceStart, sentenceEnd, SEC_PARAM(spanString->GetString().c_str()));
11874     spanString->EncodeTlv(info.sentenceBuffer);
11875 
11876     // serialize the selected text
11877     spanString = ToStyledString(info.selectStart, info.selectEnd);
11878     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "Selected range=[%{public}d-%{public}d], content=" SEC_PLD(%{public}s),
11879         info.selectStart, info.selectEnd, SEC_PARAM(spanString->GetString().c_str()));
11880     spanString->EncodeTlv(info.selectBuffer);
11881     info.selectLength = static_cast<int32_t>(aiWriteAdapter_->GetSelectLengthOnlyText(spanString->GetU16string()));
11882 }
11883 
11884 void RichEditorPattern::HandleOnAIWrite()
11885 {
11886     aiWriteAdapter_->SetAIWrite(true);
11887     AIWriteInfo info;
11888     GetAIWriteInfo(info);
11889     CloseSelectOverlay();
11890     ResetSelection();
11891     CloseKeyboard(false);
11892 
11893     auto callback = [weak = WeakClaim(this), info](std::vector<uint8_t>& buffer) {
11894         auto pattern = weak.Upgrade();
11895         CHECK_NULL_VOID(pattern);
11896         pattern->HandleAIWriteResult(info.selectStart, info.selectEnd, buffer);
11897         auto aiWriteAdapter = pattern->aiWriteAdapter_;
11898         CHECK_NULL_VOID(aiWriteAdapter);
11899         aiWriteAdapter->CloseModalUIExtension();
11900     };
11901     auto host = GetHost();
11902     CHECK_NULL_VOID(host);
11903     auto pipeline = host->GetContext();
11904     CHECK_NULL_VOID(pipeline);
11905     aiWriteAdapter_->SetPipelineContext(WeakClaim(pipeline));
11906     aiWriteAdapter_->ShowModalUIExtension(info, callback);
11907 }
11908 
11909 SymbolSpanOptions RichEditorPattern::GetSymbolSpanOptions(const RefPtr<SpanItem>& spanItem)
11910 {
11911     CHECK_NULL_RETURN(spanItem, {});
11912     TextStyle textStyle = GetDefaultTextStyle();
11913     UseSelfStyle(spanItem->fontStyle, spanItem->textLineStyle, textStyle);
11914     SymbolSpanOptions options;
11915     options.style = textStyle;
11916     options.offset = caretPosition_;
11917     options.resourceObject = spanItem->GetResourceObject();
11918     options.symbolId = spanItem->GetSymbolId();
11919     return options;
11920 }
11921 
11922 void RichEditorPattern::ReplacePlaceholderWithCustomSpan(
11923     const RefPtr<SpanItem>& spanItem, size_t& index, size_t& textIndex)
11924 {
11925     if (isSpanStringMode_) {
11926         auto customSpanItem = DynamicCast<CustomSpanItem>(spanItem);
11927         auto customSpan = MakeRefPtr<CustomSpan>();
11928         if (customSpanItem->onMeasure.has_value()) {
11929             customSpan->SetOnMeasure(customSpanItem->onMeasure.value());
11930         }
11931         if (customSpanItem->onDraw.has_value()) {
11932             customSpan->SetOnDraw(customSpanItem->onDraw.value());
11933         }
11934         auto spanString = MakeRefPtr<MutableSpanString>(customSpan);
11935         InsertStyledStringByPaste(spanString);
11936     } else {
11937         auto customSpanItem = DynamicCast<PlaceholderSpanItem>(spanItem);
11938         CHECK_NULL_VOID(customSpanItem);
11939         auto customNode = customSpanItem->GetCustomNode();
11940         SpanOptionBase options;
11941         options.offset = caretPosition_;
11942         AddPlaceholderSpan(customNode, options);
11943     }
11944     textIndex = index + PLACEHOLDER_LENGTH;
11945 }
11946 
11947 void RichEditorPattern::ReplacePlaceholderWithSymbolSpan(
11948     const RefPtr<SpanItem>& spanItem, size_t& index, size_t& textIndex)
11949 {
11950     auto options = GetSymbolSpanOptions(spanItem);
11951     options.offset = caretPosition_;
11952     AddSymbolSpan(options, false, caretPosition_);
11953     textIndex = index + PLACEHOLDER_LENGTH;
11954 }
11955 
11956 void RichEditorPattern::ReplacePlaceholderWithImageSpan(
11957     const RefPtr<SpanItem>& spanItem, size_t& index, size_t& textIndex)
11958 {
11959     auto imageSpanItem = DynamicCast<ImageSpanItem>(spanItem);
11960     CHECK_NULL_VOID(imageSpanItem);
11961     auto options = imageSpanItem->options;
11962     options.offset = caretPosition_;
11963     if (isSpanStringMode_) {
11964         auto spanString = MakeRefPtr<SpanString>(options);
11965         InsertStyledStringByPaste(spanString);
11966     } else {
11967         AddImageSpan(options, true, caretPosition_, true);
11968     }
11969     textIndex = index + PLACEHOLDER_LENGTH;
11970 }
11971 
11972 void RichEditorPattern::ReplacePlaceholderWithRawSpans(
11973     const RefPtr<SpanItem>& spanItem, size_t& index, size_t& textIndex)
11974 {
11975     switch (spanItem->spanItemType) {
11976         case SpanItemType::SYMBOL:
11977             ReplacePlaceholderWithSymbolSpan(spanItem, index, textIndex);
11978             return;
11979         case SpanItemType::CustomSpan:
11980             ReplacePlaceholderWithCustomSpan(spanItem, index, textIndex);
11981             return;
11982         case SpanItemType::IMAGE:
11983             ReplacePlaceholderWithImageSpan(spanItem, index, textIndex);
11984             return;
11985         default:
11986             return;
11987     }
11988 }
11989 
11990 void RichEditorPattern::AddSpansAndReplacePlaceholder(RefPtr<SpanString>& spanString)
11991 {
11992     auto content = spanString->GetU16string();
11993     size_t textIndex = 0;
11994     size_t index = content.find(PLACEHOLDER_MARK);
11995 
11996     while (index != std::u16string::npos) {
11997         if (textIndex < index) {
11998             auto subSpan = spanString->GetSubSpanString(textIndex, index - textIndex);
11999             AddSpanByPasteData(subSpan);
12000         }
12001         auto key = content.substr(index, PLACEHOLDER_LENGTH);
12002         if (placeholderSpansMap_.find(key) == placeholderSpansMap_.end()) {
12003             index = content.find(PLACEHOLDER_MARK, index + 1);
12004             continue;
12005         }
12006         auto spanItem = placeholderSpansMap_[key];
12007         if (!spanItem) {
12008             index = content.find(PLACEHOLDER_MARK, index + 1);
12009             continue;
12010         }
12011         ReplacePlaceholderWithRawSpans(spanItem, index, textIndex);
12012         index = content.find(PLACEHOLDER_MARK, index + 1);
12013     }
12014     if (textIndex < content.length()) {
12015         auto subSpan = spanString->GetSubSpanString(textIndex, content.length() - textIndex);
12016         AddSpanByPasteData(subSpan);
12017     }
12018 }
12019 
12020 void RichEditorPattern::InsertSpanByBackData(RefPtr<SpanString>& spanString)
12021 {
12022     CHECK_NULL_VOID(spanString);
12023     if (textSelector_.IsValid()) {
12024         SetCaretPosition(textSelector_.GetTextStart());
12025         DeleteForward(textSelector_.GetTextStart(), textSelector_.GetTextEnd() - textSelector_.GetTextStart());
12026         ResetSelection();
12027     }
12028     if (placeholderSpansMap_.empty()) {
12029         AddSpanByPasteData(spanString);
12030     } else {
12031         AddSpansAndReplacePlaceholder(spanString);
12032     }
12033     StartTwinkling();
12034     auto host = GetHost();
12035     CHECK_NULL_VOID(host);
12036     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
12037     host->MarkModifyDone();
12038 }
12039 
12040 void RichEditorPattern::HandleAIWriteResult(int32_t start, int32_t end, std::vector<uint8_t>& buffer)
12041 {
12042     RefPtr<SpanString> spanString = SpanString::DecodeTlv(buffer);
12043     if (spanString->GetSpanItems().empty()) {
12044         return;
12045     }
12046     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "Backfilling results range=[%{public}d--%{public}d], content=" SEC_PLD(%{public}s),
12047         start, end, SEC_PARAM(spanString->GetString().c_str()));
12048 
12049     textSelector_.Update(start, end);
12050     auto length = end - start;
12051     CHECK_NULL_VOID(length > 0);
12052     DeleteBackward(length);
12053     InsertSpanByBackData(spanString);
12054     BeforeIMEInsertValue(UtfUtils::Str8ToStr16(spanString->GetString()));
12055     InsertValue(u"");
12056 }
12057 
12058 bool RichEditorPattern::IsTextEditableForStylus() const
12059 {
12060     CHECK_NULL_RETURN(!customKeyboardBuilder_, false);
12061     auto host = GetHost();
12062     CHECK_NULL_RETURN(host, false);
12063     auto focusHub = host->GetFocusHub();
12064     CHECK_NULL_RETURN(focusHub, false);
12065     if (!focusHub->IsFocusable() || !host->IsVisible()) {
12066         return false;
12067     }
12068     auto renderContext = host->GetRenderContext();
12069     CHECK_NULL_RETURN(renderContext, false);
12070     auto opacity = renderContext->GetOpacity();
12071     // if opacity is 0.0f, no need to hit frameNode.
12072     if (NearZero(opacity.value_or(1.0f))) {
12073         return false;
12074     }
12075     return true;
12076 }
12077 
12078 void RichEditorPattern::DumpInfo(std::unique_ptr<JsonValue>& json)
12079 {
12080     if (customKeyboardBuilder_) {
12081         json->Put("CustomKeyboard, Attached", std::to_string(isCustomKeyboardAttached_).c_str());
12082     }
12083     auto host = GetHost();
12084     CHECK_NULL_VOID(host);
12085     auto richEditorTheme = GetTheme<RichEditorTheme>();
12086     CHECK_NULL_VOID(richEditorTheme);
12087     json->Put("caret offset", GetCaretRect().GetOffset().ToString().c_str());
12088     json->Put("caret height",
12089         std::to_string(NearZero(GetCaretRect().Height()) ? richEditorTheme->GetDefaultCaretHeight().ConvertToPx()
12090                                                          : GetCaretRect().Height())
12091             .c_str());
12092     json->Put("text rect", richTextRect_.ToString().c_str());
12093     json->Put("content rect", contentRect_.ToString().c_str());
12094     auto richEditorPaintOffset = host->GetPaintRectOffsetNG(false, true);
12095     bool hasRenderTransform = selectOverlay_->HasRenderTransform();
12096     if (hasRenderTransform) {
12097         richEditorPaintOffset = selectOverlay_->GetPaintOffsetWithoutTransform();
12098     }
12099     json->Put("hasRenderTransform", std::to_string(hasRenderTransform).c_str());
12100     json->Put("richEditorPaintOffset", richEditorPaintOffset.ToString().c_str());
12101     auto selectOverlayInfo = selectOverlay_->GetSelectOverlayInfo();
12102     CHECK_NULL_VOID(selectOverlayInfo);
12103     json->Put("selectOverlay info", selectOverlayInfo->ToString().c_str());
12104 }
12105 
12106 RectF RichEditorPattern::GetCaretRelativeRect()
12107 {
12108     CHECK_NULL_RETURN(caretTwinkling_, RectF(-1, -1, -1, -1));
12109     auto [caretOffset, caretHeight] = CalculateCaretOffsetAndHeight();
12110     CHECK_NULL_RETURN(overlayMod_, RectF(0, 0, 0, 0));
12111     auto caretWidth = DynamicCast<RichEditorOverlayModifier>(overlayMod_)->GetCaretWidth();
12112     return RectF(caretOffset.GetX(), caretOffset.GetY(), caretWidth, caretHeight);
12113 }
12114 } // namespace OHOS::Ace::NG
12115