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