• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "core/components_ng/pattern/text_field/text_field_pattern.h"
17 
18 #include <algorithm>
19 #include <cstdint>
20 #include <optional>
21 #include <regex>
22 #include <string>
23 #include <utility>
24 
25 #include "base/geometry/dimension.h"
26 #include "base/geometry/ng/offset_t.h"
27 #include "base/geometry/offset.h"
28 #include "base/i18n/localization.h"
29 #include "base/log/dump_log.h"
30 #include "base/memory/referenced.h"
31 #include "base/utils/string_utils.h"
32 #include "base/utils/utils.h"
33 #include "core/common/clipboard/clipboard_proxy.h"
34 #include "core/common/container_scope.h"
35 #include "core/common/font_manager.h"
36 #include "core/common/ime/text_edit_controller.h"
37 #include "core/common/ime/text_input_client.h"
38 #include "core/common/ime/text_input_connection.h"
39 #include "core/common/ime/text_input_formatter.h"
40 #include "core/common/ime/text_input_type.h"
41 #include "core/common/ime/text_selection.h"
42 #include "core/components/common/layout/constants.h"
43 #include "core/components/text_field/textfield_theme.h"
44 #include "core/components/theme/icon_theme.h"
45 #include "core/components_ng/image_provider/image_loading_context.h"
46 #include "core/components_ng/pattern/search/search_event_hub.h"
47 #include "core/components_ng/pattern/search/search_pattern.h"
48 #include "core/components_ng/pattern/text_drag/text_drag_pattern.h"
49 #include "core/components_ng/pattern/text_field/text_field_controller.h"
50 #include "core/components_ng/pattern/text_field/text_field_event_hub.h"
51 #include "core/components_ng/pattern/text_field/text_field_layout_algorithm.h"
52 #include "core/components_ng/pattern/text_field/text_field_layout_property.h"
53 #include "core/components_ng/pattern/text_field/text_field_manager.h"
54 #include "core/components_ng/pattern/text_field/text_field_model.h"
55 #include "core/components_ng/pattern/text_field/text_field_model_ng.h"
56 #include "core/components_ng/pattern/text_field/text_selector.h"
57 #include "core/components_ng/property/property.h"
58 #include "core/components_ng/render/drawing.h"
59 #include "core/components_ng/render/drawing_prop_convertor.h"
60 #include "core/components_ng/render/paragraph.h"
61 #include "core/components_v2/inspector/inspector_constants.h"
62 #include "core/components_v2/inspector/utils.h"
63 #include "core/image/image_source_info.h"
64 #include "core/pipeline_ng/pipeline_context.h"
65 #if not defined(ACE_UNITTEST)
66 #if defined(ENABLE_STANDARD_INPUT)
67 #include "core/components_ng/pattern/text_field/on_text_changed_listener_impl.h"
68 #endif
69 #endif
70 #ifdef ENABLE_DRAG_FRAMEWORK
71 #include "core/common/udmf/udmf_client.h"
72 #endif
73 
74 namespace OHOS::Ace::NG {
75 namespace {
76 constexpr Dimension BORDER_DEFAULT_WIDTH = 0.0_vp;
77 constexpr Dimension ERROR_BORDER_WIDTH = 1.0_vp;
78 constexpr Dimension OVER_COUNT_BORDER_WIDTH = 1.0_vp;
79 constexpr Dimension INLINE_BORDER_WIDTH = 2.0_vp;
80 constexpr Dimension UNDERLINE_NORMAL_HEIGHT = 48.0_vp;
81 constexpr Dimension UNDERLINE_NORMAL_PADDING = 12.0_vp;
82 constexpr Dimension DEFAULT_FONT = Dimension(16, DimensionUnit::FP);
83 // uncertainty range when comparing selectedTextBox to contentRect
84 constexpr float BOX_EPSILON = 0.5f;
85 constexpr float ERROR_TEXT_CAPSULE_MARGIN = 33.0f;
86 constexpr uint32_t TWINKLING_INTERVAL_MS = 500;
87 constexpr uint32_t RECORD_MAX_LENGTH = 20;
88 constexpr uint32_t OBSCURE_SHOW_TICKS = 3;
89 constexpr uint32_t FIND_TEXT_ZERO_INDEX = 1;
90 constexpr char16_t OBSCURING_CHARACTER = u'•';
91 constexpr char16_t OBSCURING_CHARACTER_FOR_AR = u'*';
92 const std::string NEWLINE = "\n";
93 const std::wstring WIDE_NEWLINE = StringUtils::ToWstring(NEWLINE);
94 const std::string DIGIT_WHITE_LIST = "[0-9]";
95 const std::string PHONE_WHITE_LIST = "[\\d\\-\\+\\*\\#]+";
96 const std::string EMAIL_WHITE_LIST = "[\\w.\\@]";
97 const std::string URL_WHITE_LIST = "[a-zA-z]+://[^\\s]*";
98 const std::string SHOW_PASSWORD_SVG = "SYS_SHOW_PASSWORD_SVG";
99 const std::string HIDE_PASSWORD_SVG = "SYS_HIDE_PASSWORD_SVG";
100 
SwapIfLarger(int32_t & a,int32_t & b)101 void SwapIfLarger(int32_t& a, int32_t& b)
102 {
103     if (a > b) {
104         std::swap(a, b);
105     }
106 }
107 
RemoveErrorTextFromValue(const std::string & value,const std::string & errorText,std::string & result)108 void RemoveErrorTextFromValue(const std::string& value, const std::string& errorText, std::string& result)
109 {
110     int32_t valuePtr = 0;
111     int32_t errorTextPtr = 0;
112     auto valueSize = static_cast<int32_t>(value.length());
113     auto errorTextSize = static_cast<int32_t>(errorText.length());
114     while (errorTextPtr < errorTextSize) {
115         while (value[valuePtr] != errorText[errorTextPtr] && valuePtr < valueSize) {
116             result += value[valuePtr];
117             valuePtr++;
118         }
119         // no more text left to remove in value
120         if (valuePtr >= valueSize) {
121             return;
122         }
123         // increase both value ptr and error text ptr if char in value is removed
124         valuePtr++;
125         errorTextPtr++;
126     }
127     result += value.substr(valuePtr);
128 }
129 
ConvertFontFamily(const std::vector<std::string> & fontFamily)130 std::string ConvertFontFamily(const std::vector<std::string>& fontFamily)
131 {
132     std::string result;
133     for (const auto& item : fontFamily) {
134         result += item;
135         result += ",";
136     }
137     result = result.substr(0, result.length() - 1);
138     return result;
139 }
140 
141 } // namespace
142 
CreateObscuredText(int32_t len)143 std::u16string TextFieldPattern::CreateObscuredText(int32_t len)
144 {
145     std::u16string obscuredText;
146     if (Localization::GetInstance()->GetLanguage() == "ar") { // ar is the abbreviation of Arabic.
147         obscuredText = std::u16string(len, OBSCURING_CHARACTER_FOR_AR);
148     } else {
149         obscuredText = std::u16string(len, OBSCURING_CHARACTER);
150     }
151     return obscuredText;
152 }
153 
CreateDisplayText(const std::string & content,int32_t nakedCharPosition,bool needObscureText)154 std::u16string TextFieldPattern::CreateDisplayText(
155     const std::string& content, int32_t nakedCharPosition, bool needObscureText)
156 {
157     if (!content.empty() && needObscureText) {
158         auto text =
159             TextFieldPattern::CreateObscuredText(static_cast<int32_t>(StringUtils::ToWstring(content).length()));
160         if (nakedCharPosition >= 0 && nakedCharPosition < static_cast<int32_t>(content.length())) {
161             auto rawContent = StringUtils::Str8ToStr16(content);
162             text[nakedCharPosition] = rawContent[nakedCharPosition];
163         }
164         return text;
165     }
166     return StringUtils::Str8ToStr16(content);
167 }
168 
GetTextOrPlaceHolderFontSize()169 float TextFieldPattern::GetTextOrPlaceHolderFontSize()
170 {
171     auto tmpHost = GetHost();
172     CHECK_NULL_RETURN(tmpHost, 0.0f);
173     auto pipeline = tmpHost->GetContext();
174     CHECK_NULL_RETURN(pipeline, 0.0f);
175     auto textFieldLayoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
176     CHECK_NULL_RETURN(textFieldLayoutProperty, 0.0f);
177     auto themeManager = pipeline->GetThemeManager();
178     CHECK_NULL_RETURN(themeManager, 0.0f);
179     auto textFieldTheme = themeManager->GetTheme<TextFieldTheme>();
180     CHECK_NULL_RETURN(textFieldTheme, 0.0f);
181     Dimension fontSize;
182     if (textFieldLayoutProperty->HasFontSize() &&
183         textFieldLayoutProperty->GetFontSizeValue(Dimension()).IsNonNegative()) {
184         fontSize = textFieldLayoutProperty->GetFontSizeValue(Dimension());
185     } else {
186         return textFieldTheme ? static_cast<float>(textFieldTheme->GetFontSize().ConvertToPx())
187                               : static_cast<float>(DEFAULT_FONT.ConvertToPx());
188     }
189     return std::min(static_cast<float>(fontSize.ConvertToPx()), contentRect_.Height());
190 }
191 
TextFieldPattern()192 TextFieldPattern::TextFieldPattern() : twinklingInterval_(TWINKLING_INTERVAL_MS)
193 {
194     if (PipelineBase::GetCurrentContext() &&
195         // for normal app add version protection, enable keyboard as default start from API 10 or higher
196         PipelineBase::GetCurrentContext()->GetMinPlatformVersion() > 9 &&
197         // UIExtension Ability focus windowId setted by component user window, can not enable keyboard as default
198         !PipelineBase::GetCurrentContext()->IsFocusWindowIdSetted()) {
199         needToRequestKeyboardOnFocus_ = true;
200     }
201 }
202 
~TextFieldPattern()203 TextFieldPattern::~TextFieldPattern()
204 {
205     LOGI("Destruction of text field.");
206     if (textEditingController_) {
207         textEditingController_->Clear();
208         textEditingController_->RemoveObserver(WeakClaim(this));
209     }
210     CloseSelectOverlay();
211     // If soft keyboard is still exist, close it.
212     if (HasConnection()) {
213 #if defined(ENABLE_STANDARD_INPUT)
214         LOGI("Destruction of text field, close input method.");
215         MiscServices::InputMethodController::GetInstance()->HideTextInput();
216         MiscServices::InputMethodController::GetInstance()->Close();
217 #else
218         connection_->Close(GetInstanceId());
219         connection_ = nullptr;
220 #endif
221     }
222     if (isCustomKeyboardAttached_) {
223         CloseCustomKeyboard();
224     }
225 }
226 
BeforeCreateLayoutWrapper()227 void TextFieldPattern::BeforeCreateLayoutWrapper()
228 {
229     if (caretUpdateType_ == CaretUpdateType::PRESSED || caretUpdateType_ == CaretUpdateType::LONG_PRESSED) {
230         UpdateCaretByPressOrLongPress();
231         MarkRedrawOverlay();
232     } else if (caretUpdateType_ == CaretUpdateType::EVENT) {
233         if (isMousePressed_) {
234             // handle mouse event only
235             UpdateCaretPositionByMouseMovement();
236         }
237     }
238     UpdateEditingValueCaretPositionToRecord();
239     if (!IsSelected()) {
240         UpdateSelection(textEditingValue_.caretPosition);
241     }
242 }
243 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)244 bool TextFieldPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
245 {
246     if (config.skipMeasure || dirty->SkipMeasureContent()) {
247         return false;
248     }
249     contentRect_ = dirty->GetGeometryNode()->GetContentRect();
250     frameRect_ = dirty->GetGeometryNode()->GetFrameRect();
251     if (!inlineState_.saveInlineState) {
252         inlineState_.saveInlineState = true;
253         inlineState_.frameRect = frameRect_;
254     }
255     auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
256     CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
257     auto textFieldLayoutAlgorithm = DynamicCast<TextFieldLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
258     CHECK_NULL_RETURN(textFieldLayoutAlgorithm, false);
259     auto paragraph = textFieldLayoutAlgorithm->GetParagraph();
260     if (paragraph) {
261         paragraph_ = paragraph;
262     }
263     auto counterParagraph = textFieldLayoutAlgorithm->GetCounterParagraph();
264     if (counterParagraph) {
265         counterParagraph_ = counterParagraph;
266         countHeight_ = counterParagraph->GetHeight();
267     }
268     auto errorParagraph = textFieldLayoutAlgorithm->GetErrorParagraph();
269     if (errorParagraph) {
270         errorParagraph_ = errorParagraph;
271     }
272     if (!IsDragging()) {
273         dragParagraph_ = paragraph_;
274     }
275 
276     auto paragraphWidth = textFieldLayoutAlgorithm->GetParagraphWidth();
277     auto textRect = textFieldLayoutAlgorithm->GetTextRect();
278     if (!(needToRefreshSelectOverlay_ &&
279             (!NearEqual(paragraphWidth, paragraphWidth_) || !NearEqual(textRect, textRect_))) ||
280         (LessOrEqual(paragraphWidth, -Infinity<float>()) && LessOrEqual(paragraphWidth_, -Infinity<float>()))) {
281         needToRefreshSelectOverlay_ = false;
282     }
283     paragraphWidth_ = paragraphWidth;
284     textRect_ = textRect;
285     imageRect_ = textFieldLayoutAlgorithm->GetImageRect();
286     unitWidth_ = textFieldLayoutAlgorithm->GetUnitWidth();
287     parentGlobalOffset_ = textFieldLayoutAlgorithm->GetParentGlobalOffset();
288     UpdateTextFieldManager(Offset(parentGlobalOffset_.GetX(), parentGlobalOffset_.GetY()), frameRect_.Height());
289     auto textRectNotNeedToChange = UpdateCaretRect();
290     UpdateCaretInfoToController();
291     auto hostLayoutProperty =
292         dirty->GetHostNode() ? dirty->GetHostNode()->GetLayoutProperty<TextFieldLayoutProperty>() : nullptr;
293     if (paragraph) {
294         if (inlineFocusState_) {
295             CalcSize idealSize;
296             auto paragraphWidth = paragraph_->GetLongestLine();
297             std::optional<CalcLength> width(paragraphWidth + inlinePadding_);
298             idealSize.SetWidth(width);
299             hostLayoutProperty->UpdateUserDefinedIdealSize(idealSize);
300         }
301     }
302     if (hostLayoutProperty) {
303         hostLayoutProperty->ResetTextAlignChanged();
304     }
305     if (needToRefreshSelectOverlay_) {
306         ProcessOverlay();
307         StopTwinkling();
308         needToRefreshSelectOverlay_ = false;
309     }
310     if (inlineSelectAllFlag_) {
311         HandleOnSelectAll(false, true);
312         inlineSelectAllFlag_ = false;
313     }
314     if (updateSelectionAfterObscure_) {
315         GetTextRectsInRange(textSelector_.GetStart(), textSelector_.GetEnd(), textBoxes_);
316         updateSelectionAfterObscure_ = false;
317     }
318     if (hostLayoutProperty && hostLayoutProperty->GetFontSizeChangedValue(false)) {
319         GetTextRectsInRange(textSelector_.GetStart(), textSelector_.GetEnd(), textBoxes_);
320         hostLayoutProperty->ResetFontSizeChanged();
321     }
322     if (mouseStatus_ == MouseStatus::RELEASED) {
323         mouseStatus_ = MouseStatus::NONE;
324     }
325     if (IsTextArea()) {
326         CheckScrollable();
327     } else {
328         SetScrollEnable(GreatNotEqual(textRect_.Width(), contentRect_.Width()));
329     }
330     UpdateScrollBarOffset();
331     if (config.frameSizeChange) {
332         if (GetScrollBar() != nullptr) {
333             GetScrollBar()->ScheduleDisapplearDelayTask();
334         }
335     }
336     if (textRectNotNeedToChange) {
337         return true;
338     }
339     // after new text input or events such as left right key,
340     // the procedure will be:
341     // caret position change (such as move left)
342     // caret get offset from typographic algorithm
343     // if caret position exceeds constrained content region, adjust both caret position and text rect offset
344     float dx = AdjustTextRectOffsetX();
345     float dy = AdjustTextAreaOffsetY();
346     UpdateSelectionOffset();
347     if (caretUpdateType_ == CaretUpdateType::HANDLE_MOVE) {
348         if (!NearZero(dx) || !NearZero(dy)) {
349             UpdateOtherHandleOnMove(dx, dy);
350         }
351         // trigger selection box repaint
352         MarkRedrawOverlay();
353     } else if (caretUpdateType_ == CaretUpdateType::HANDLE_MOVE_DONE) {
354         SetHandlerOnMoveDone();
355     } else if ((!NearZero(dx) || !NearZero(dy)) && SelectOverlayIsOn() && selectionMode_ == SelectionMode::SELECT) {
356         SelectHandleInfo firstInfo, secondInfo;
357         SizeF handlePaintSize = { SelectHandleInfo::GetDefaultLineWidth().ConvertToPx(), caretRect_.Height() };
358         textSelector_.firstHandleOffset_.AddX(dx);
359         textSelector_.firstHandleOffset_.AddY(dy);
360         firstInfo.paintRect = { textSelector_.firstHandleOffset_, handlePaintSize };
361         textSelector_.secondHandleOffset_.AddX(dx);
362         textSelector_.secondHandleOffset_.AddY(dy);
363         secondInfo.paintRect = { textSelector_.secondHandleOffset_, handlePaintSize };
364         selectOverlayProxy_->UpdateFirstAndSecondHandleInfo(firstInfo, secondInfo);
365     }
366     caretUpdateType_ = CaretUpdateType::NONE;
367     return true;
368 }
369 
HasFocus() const370 bool TextFieldPattern::HasFocus() const
371 {
372     auto tmpHost = GetHost();
373     CHECK_NULL_RETURN(tmpHost, false);
374     auto focusHub = tmpHost->GetOrCreateFocusHub();
375 
376     if (IsSearchParentNode()) {
377         auto parentFrameNode = AceType::DynamicCast<FrameNode>(tmpHost->GetParent());
378         focusHub = parentFrameNode->GetOrCreateFocusHub();
379     }
380 
381     CHECK_NULL_RETURN(focusHub, false);
382     return focusHub->IsCurrentFocus();
383 }
384 
UpdateCaretInfoToController() const385 void TextFieldPattern::UpdateCaretInfoToController() const
386 {
387     CHECK_NULL_VOID_NOLOG(HasFocus());
388 #if defined(ENABLE_STANDARD_INPUT)
389     auto miscTextConfig = GetMiscTextConfig();
390     CHECK_NULL_VOID(miscTextConfig.has_value());
391     MiscServices::CursorInfo cursorInfo = miscTextConfig.value().cursorInfo;
392     LOGD("UpdateCaretInfoToController, left %{public}f, top %{public}f, width %{public}f, height %{public}f",
393         cursorInfo.left, cursorInfo.top, cursorInfo.width, cursorInfo.height);
394     MiscServices::InputMethodController::GetInstance()->OnCursorUpdate(cursorInfo);
395     auto value = GetEditingValue();
396     LOGD("Start %{public}d, end %{public}d", textSelector_.GetStart(), textSelector_.GetEnd());
397     MiscServices::InputMethodController::GetInstance()->OnSelectionChange(
398         StringUtils::Str8ToStr16(value.text), textSelector_.GetStart(), textSelector_.GetEnd());
399 
400 #else
401     if (HasConnection()) {
402         TextEditingValue value;
403         value.text = textEditingValue_.text;
404         value.hint = GetPlaceHolder();
405         value.selection.Update(textSelector_.baseOffset, textSelector_.destinationOffset);
406         connection_->SetEditingState(value, GetInstanceId());
407     }
408 #endif
409 }
410 
411 // return: true if text rect offset will NOT be further changed by caret position
UpdateCaretRect()412 bool TextFieldPattern::UpdateCaretRect()
413 {
414     auto tmpHost = GetHost();
415     CHECK_NULL_RETURN(tmpHost, false);
416     auto focusHub = tmpHost->GetOrCreateFocusHub();
417     if (IsSearchParentNode()) {
418         auto parentFrameNode = AceType::DynamicCast<FrameNode>(tmpHost->GetParent());
419         focusHub = parentFrameNode->GetOrCreateFocusHub();
420     }
421     if (focusHub && !focusHub->IsCurrentFocus()) {
422         CloseSelectOverlay(true);
423         LOGW("Not on focus, cannot update caret");
424         return true;
425     }
426 
427     if (textEditingValue_.text.empty()) {
428         SetCaretOffsetForEmptyTextOrPositionZero();
429         return false;
430     }
431 
432     UpdateCaretRectByPosition(textEditingValue_.caretPosition);
433 
434     if (caretUpdateType_ == CaretUpdateType::NONE) {
435         return true;
436     }
437     return false;
438 }
439 
GetIconSize()440 float TextFieldPattern::GetIconSize()
441 {
442     auto tmpHost = GetHost();
443     CHECK_NULL_RETURN(tmpHost, 0.0f);
444     auto pipeline = tmpHost->GetContext();
445     CHECK_NULL_RETURN(pipeline, 0.0f);
446     auto themeManager = pipeline->GetThemeManager();
447     CHECK_NULL_RETURN(themeManager, 0.0f);
448     auto textFieldTheme = themeManager->GetTheme<TextFieldTheme>();
449     CHECK_NULL_RETURN(textFieldTheme, 0.0f);
450     return static_cast<float>(textFieldTheme->GetIconSize().ConvertToPx());
451 }
452 
GetIconHotZoneSize()453 float TextFieldPattern::GetIconHotZoneSize()
454 {
455     auto tmpHost = GetHost();
456     CHECK_NULL_RETURN(tmpHost, 0.0f);
457     auto pipeline = tmpHost->GetContext();
458     CHECK_NULL_RETURN(pipeline, 0.0f);
459     auto themeManager = pipeline->GetThemeManager();
460     CHECK_NULL_RETURN(themeManager, 0.0f);
461     auto textFieldTheme = themeManager->GetTheme<TextFieldTheme>();
462     CHECK_NULL_RETURN(textFieldTheme, 0.0f);
463     return static_cast<float>(textFieldTheme->GetIconHotZoneSize().ConvertToPx());
464 }
465 
GetIconRightOffset()466 float TextFieldPattern::GetIconRightOffset()
467 {
468     auto iconSize = GetIconSize();
469     auto iconHotZoneSize = GetIconHotZoneSize();
470     if (NearZero(iconSize) || NearZero(iconHotZoneSize)) {
471         return 0.0f;
472     }
473     return (iconHotZoneSize - iconSize) / 2.0f;
474 }
475 
CreateSingleHandle(bool animation,bool isMenuShow)476 void TextFieldPattern::CreateSingleHandle(bool animation, bool isMenuShow)
477 {
478     auto tmpHost = GetHost();
479     CHECK_NULL_VOID(tmpHost);
480     isSingleHandle_ = true;
481     RectF secondHandle;
482     auto secondHandleMetrics = CalcCursorOffsetByPosition(textEditingValue_.caretPosition, isTouchAtLeftOffset_);
483     OffsetF secondHandleOffset(secondHandleMetrics.offset.GetX() + parentGlobalOffset_.GetX(),
484         secondHandleMetrics.offset.GetY() + parentGlobalOffset_.GetY());
485     if (textEditingValue_.Empty()) {
486         auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
487         auto align = layoutProperty ? layoutProperty->GetTextAlignValue(TextAlign::START) : TextAlign::START;
488         float offsetX = contentRect_.GetX();
489         auto baseWidth = frameRect_.Width();
490         auto showingPasswordIcon = (layoutProperty ? layoutProperty->GetShowPasswordIcon().value_or(true) : false) &&
491                                    (layoutProperty ? layoutProperty->GetTextInputTypeValue(
492                                                          TextInputType::UNSPECIFIED) == TextInputType::VISIBLE_PASSWORD
493                                                    : false);
494         baseWidth -= showingPasswordIcon ? GetIconSize() + GetIconRightOffset() : 0.0f;
495         switch (align) {
496             case TextAlign::CENTER:
497                 offsetX = baseWidth * 0.5f;
498                 break;
499             case TextAlign::END:
500                 offsetX = baseWidth - GetPaddingRight();
501                 break;
502             case TextAlign::START:
503             default:
504                 break;
505         }
506         secondHandleOffset =
507             OffsetF(offsetX + parentGlobalOffset_.GetX(), contentRect_.GetY() + parentGlobalOffset_.GetY());
508     }
509     textSelector_.secondHandleOffset_ = secondHandleOffset;
510     SizeF handlePaintSize = { SelectHandleInfo::GetDefaultLineWidth().ConvertToPx(), caretRect_.Height() };
511     secondHandle.SetOffset(secondHandleOffset);
512     secondHandle.SetSize(handlePaintSize);
513     ShowSelectOverlay(std::nullopt, secondHandle, animation, isMenuShow);
514     selectionMode_ = SelectionMode::NONE;
515     StartTwinkling();
516 }
517 
UpdateCaretByPressOrLongPress()518 bool TextFieldPattern::UpdateCaretByPressOrLongPress()
519 {
520     if (CaretPositionCloseToTouchPosition() && !SelectOverlayIsOn() &&
521         caretUpdateType_ != CaretUpdateType::LONG_PRESSED && !isMousePressed_) {
522         CreateSingleHandle(true, false);
523         return true;
524     }
525     // caret offset updated by gesture will not cause textRect to change offset
526     UpdateCaretPositionByPressOffset();
527     if (caretUpdateType_ == CaretUpdateType::PRESSED) {
528         if (!GetEditingValue().text.empty() && isFocusedBeforeClick_ && !isMousePressed_) {
529             CreateSingleHandle(true, false);
530         } else {
531             StartTwinkling();
532         }
533         UpdateSelection(textEditingValue_.caretPosition);
534     } else if (caretUpdateType_ == CaretUpdateType::LONG_PRESSED) {
535         // in long press case, we have caret and one handle at pressed location and another handle at -1 or +1 position
536         ProcessOverlay(true);
537     }
538     GetTextRectsInRange(textSelector_.GetStart(), textSelector_.GetEnd(), textBoxes_);
539     return true;
540 }
541 
UpdateCaretByRightClick()542 void TextFieldPattern::UpdateCaretByRightClick()
543 {
544     ProcessOverlay(true);
545 }
546 
CaretPositionCloseToTouchPosition()547 bool TextFieldPattern::CaretPositionCloseToTouchPosition()
548 {
549     auto xInRange = GreatOrEqual(lastTouchOffset_.GetX(), caretRect_.GetX() - PreferredLineHeight()) &&
550                     LessOrEqual(lastTouchOffset_.GetX(), caretRect_.GetX() + PreferredLineHeight());
551     auto yInRange = GreatOrEqual(lastTouchOffset_.GetY(), caretRect_.GetY()) &&
552                     LessOrEqual(lastTouchOffset_.GetY(), caretRect_.GetY() + PreferredLineHeight());
553     return xInRange && yInRange;
554 }
555 
IsTextArea() const556 bool TextFieldPattern::IsTextArea() const
557 {
558     auto tmpHost = GetHost();
559     CHECK_NULL_RETURN(tmpHost, false);
560     auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
561     CHECK_NULL_RETURN(layoutProperty, true);
562     return layoutProperty->HasMaxLines() ? layoutProperty->GetMaxLinesValue(1) > 1 : true;
563 }
564 
UpdateDestinationToCaretByEvent()565 void TextFieldPattern::UpdateDestinationToCaretByEvent()
566 {
567     CHECK_NULL_VOID_NOLOG(isMousePressed_);
568     UpdateSelection(textSelector_.GetStart(), textEditingValue_.caretPosition);
569     if (textSelector_.destinationOffset != textSelector_.baseOffset) {
570         selectionMode_ = SelectionMode::SELECT;
571     }
572 }
573 
UpdateCaretPositionByLastTouchOffset()574 void TextFieldPattern::UpdateCaretPositionByLastTouchOffset()
575 {
576     Offset offset = GetLastTouchOffset() - Offset(textRect_.GetX(), textRect_.GetY());
577     auto position = ConvertTouchOffsetToCaretPosition(offset);
578     textEditingValue_.CursorMoveToPosition(position);
579 }
580 
581 // return bool that caret might move out of content rect and need adjust position
UpdateCaretPositionByMouseMovement()582 bool TextFieldPattern::UpdateCaretPositionByMouseMovement()
583 {
584     if (GetEditingValue().text.empty()) {
585         caretRect_.SetLeft(textRect_.GetX());
586         caretRect_.SetTop(textRect_.GetY());
587         selectionMode_ = SelectionMode::NONE;
588         UpdateSelection(0, 0);
589         return false;
590     }
591     bool needToShiftCaretAndTextRect = false;
592     // if mouse keep at position out of content rect, caret will keep moving left or right
593     if (lastTouchOffset_.GetX() < contentRect_.GetX() ||
594         lastTouchOffset_.GetX() > contentRect_.GetX() + contentRect_.Width()) {
595         needToShiftCaretAndTextRect = true;
596     }
597     UpdateCaretPositionByLastTouchOffset();
598     UpdateSelection(textSelector_.GetStart(), textEditingValue_.caretPosition);
599     GetTextRectsInRange(textSelector_.GetStart(), textSelector_.GetEnd(), textBoxes_);
600     selectionMode_ =
601         textSelector_.destinationOffset == textSelector_.baseOffset ? SelectionMode::NONE : SelectionMode::SELECT;
602     return needToShiftCaretAndTextRect;
603 }
604 
UpdateCaretOffsetByEvent()605 void TextFieldPattern::UpdateCaretOffsetByEvent()
606 {
607     if (textEditingValue_.text.empty()) {
608         UpdateSelection(0, 0);
609         SetCaretOffsetForEmptyTextOrPositionZero();
610         return;
611     }
612     if (isMousePressed_) {
613         // handle mouse event only
614         UpdateCaretPositionByMouseMovement();
615         return;
616     }
617     if (!IsSelected()) {
618         UpdateSelection(textEditingValue_.caretPosition);
619     }
620     UpdateCaretRectByPosition(textEditingValue_.caretPosition);
621 }
622 
UpdateSelectionOffset()623 void TextFieldPattern::UpdateSelectionOffset()
624 {
625     CHECK_NULL_VOID_NOLOG(IsSelected());
626     if (textSelector_.baseOffset == textSelector_.destinationOffset) {
627         textSelector_.selectionBaseOffset.SetX(caretRect_.GetX());
628         textSelector_.selectionDestinationOffset.SetX(caretRect_.GetX());
629         return;
630     }
631     if (selectionMode_ == SelectionMode::SELECT_ALL) {
632         textSelector_.selectionBaseOffset.SetX(textRect_.GetX());
633         textSelector_.selectionDestinationOffset.SetX(textRect_.GetX() + textRect_.Width());
634         std::optional<RectF> firstHandleOption;
635         std::optional<RectF> secondHandleOption;
636         if (textBoxes_.empty()) {
637             return;
638         }
639         if (SelectOverlayIsOn()) {
640             SizeF handlePaintSize = { SelectHandleInfo::GetDefaultLineWidth().ConvertToPx(), caretRect_.Height() };
641             auto textBoxLocalOffsetBegin =
642                 OffsetF(textBoxes_.begin()->rect_.GetLeft() + (IsTextArea() ? contentRect_.GetX() : textRect_.GetX()),
643                     textBoxes_.begin()->rect_.GetTop() + (IsTextArea() ? textRect_.GetY() : contentRect_.GetY()) +
644                         BOX_EPSILON);
645             auto textBoxLocalOffsetEnd =
646                 OffsetF(textBoxes_.rbegin()->rect_.GetRight() + (IsTextArea() ? contentRect_.GetX() : textRect_.GetX()),
647                     textBoxes_.rbegin()->rect_.GetTop() + (IsTextArea() ? textRect_.GetY() : contentRect_.GetY()) +
648                         BOX_EPSILON);
649             OffsetF firstHandleOffset(textBoxLocalOffsetBegin.GetX() + parentGlobalOffset_.GetX(),
650                 textBoxLocalOffsetBegin.GetY() + parentGlobalOffset_.GetY() - BOX_EPSILON);
651             textSelector_.firstHandleOffset_ = firstHandleOffset;
652             RectF firstHandle;
653             firstHandle.SetOffset(firstHandleOffset);
654             firstHandle.SetSize(handlePaintSize);
655             firstHandleOption = firstHandle;
656             OffsetF secondHandleOffset(textBoxLocalOffsetEnd.GetX() + parentGlobalOffset_.GetX(),
657                 textBoxLocalOffsetEnd.GetY() + parentGlobalOffset_.GetY() - BOX_EPSILON);
658             textSelector_.secondHandleOffset_ = secondHandleOffset;
659             RectF secondHandle;
660             secondHandle.SetOffset(secondHandleOffset);
661             secondHandle.SetSize(handlePaintSize);
662             secondHandleOption = secondHandle;
663             if (firstHandleOption.has_value() || secondHandleOption.has_value()) {
664                 ShowSelectOverlay(firstHandleOption, secondHandleOption, true);
665             }
666         }
667         return;
668     }
669 }
670 
UpdateCaretPositionByTextEdit()671 void TextFieldPattern::UpdateCaretPositionByTextEdit()
672 {
673     if (textEditingValue_.text.empty()) {
674         UpdateSelection(0);
675         SetCaretOffsetForEmptyTextOrPositionZero();
676         return;
677     }
678     if (textEditingValue_.caretPosition == 0) {
679         SetCaretOffsetForEmptyTextOrPositionZero();
680         return;
681     }
682     UpdateCaretRectByPosition(textEditingValue_.caretPosition);
683     UpdateSelection(textEditingValue_.caretPosition);
684 }
685 
UpdateCaretRectByPosition(int32_t position)686 void TextFieldPattern::UpdateCaretRectByPosition(int32_t position)
687 {
688     auto caretMetrics = CalcCursorOffsetByPosition(position, isTouchAtLeftOffset_);
689     caretRect_.SetLeft(caretMetrics.offset.GetX());
690     // add 1.0f here for offsetToParagraphBeginning offsetY is negative when caret position is zero
691     caretRect_.SetTop(caretMetrics.offset.GetY());
692     caretRect_.SetHeight(caretMetrics.height);
693     auto tmpHost = GetHost();
694     CHECK_NULL_VOID(tmpHost);
695     auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
696     CHECK_NULL_VOID(layoutProperty);
697     layoutProperty->UpdateCaretPosition(textEditingValue_.caretPosition);
698 }
699 
SetCaretOffsetForEmptyTextOrPositionZero()700 void TextFieldPattern::SetCaretOffsetForEmptyTextOrPositionZero()
701 {
702     auto tmpHost = GetHost();
703     CHECK_NULL_VOID(tmpHost);
704     auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
705     caretRect_.SetLeft(IsTextArea() ? contentRect_.Left() : textRect_.GetX());
706     caretRect_.SetTop(IsTextArea() ? textRect_.GetY() : contentRect_.Top());
707     caretRect_.SetHeight(PreferredLineHeight());
708     switch (layoutProperty->GetTextAlignValue(TextAlign::START)) {
709         case TextAlign::START:
710             caretRect_.SetLeft(textRect_.GetX());
711             return;
712         case TextAlign::CENTER:
713             caretRect_.SetLeft(static_cast<float>(contentRect_.GetX()) + contentRect_.Width() / 2.0f);
714             return;
715         case TextAlign::END:
716             caretRect_.SetLeft(static_cast<float>(contentRect_.GetX()) + contentRect_.Width() -
717                                static_cast<float>(CURSOR_WIDTH.ConvertToPx()));
718             return;
719         default:
720             caretRect_.SetLeft(textRect_.GetX());
721             return;
722     }
723 }
724 
UpdateCaretPositionByPressOffset()725 void TextFieldPattern::UpdateCaretPositionByPressOffset()
726 {
727     if (GetEditingValue().text.empty()) {
728         textEditingValue_.CursorMoveToPosition(0);
729         return;
730     }
731     UpdateCaretPositionByLastTouchOffset();
732 
733     selectionMode_ = SelectionMode::NONE;
734 }
735 
CalcCursorOffsetByPosition(int32_t position,bool isStart)736 CaretMetricsF TextFieldPattern::CalcCursorOffsetByPosition(int32_t position, bool isStart)
737 {
738     // this function will calculate caret offset and height by caret position
739     auto tmpHost = GetHost();
740     CaretMetricsF result;
741     CHECK_NULL_RETURN(tmpHost, result);
742     CaretMetricsF resultDownstream;
743     CaretMetricsF resultUpstream;
744     auto isSuccessDownstream = ComputeOffsetForCaretDownstream(position, resultDownstream);
745     auto isSuccessUpstream = ComputeOffsetForCaretUpstream(position, resultUpstream);
746     LOGD("position : %{public}d resultDownstream: %{public}s resultUpstream: %{public}s", position,
747         resultDownstream.offset.ToString().c_str(), resultUpstream.offset.ToString().c_str());
748     if (!(isSuccessDownstream || isSuccessUpstream)) {
749         LOGW("Get caret offset failed, set it to text start");
750         if (IsTextArea()) {
751             auto offsetX = contentRect_.GetX();
752             auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
753             switch (layoutProperty->GetTextAlignValue(TextAlign::START)) {
754                 case TextAlign::CENTER:
755                     offsetX = static_cast<float>(contentRect_.GetX()) + contentRect_.Width() / 2.0f;
756                     break;
757                 case TextAlign::END:
758                     offsetX = static_cast<float>(contentRect_.GetX()) + contentRect_.Width() -
759                               static_cast<float>(CURSOR_WIDTH.ConvertToPx());
760                     break;
761                 default:
762                     break;
763             }
764             result.offset = OffsetF(offsetX, contentRect_.GetY());
765         } else {
766             result.offset = OffsetF(textRect_.GetX(), contentRect_.GetY());
767         }
768         result.height = textBoxes_.empty() ? PreferredLineHeight() : textBoxes_.begin()->rect_.GetHeight();
769         return result;
770     }
771     if (isSuccessDownstream && isStart && resultUpstream.offset.GetY() < resultDownstream.offset.GetY()) {
772         result = resultDownstream;
773     } else if (isSuccessUpstream && !isStart && resultUpstream.offset.GetY() < resultDownstream.offset.GetY()) {
774         result = resultUpstream;
775     } else {
776         if (isSuccessDownstream) {
777             result = resultDownstream;
778         } else {
779             result = resultUpstream;
780         }
781     }
782     LOGD("result stream: %{public}s ", result.ToString().c_str());
783     result.offset.AddX(IsTextArea() ? contentRect_.GetX() : textRect_.GetX());
784     result.offset.AddY(IsTextArea() ? textRect_.GetY() : contentRect_.GetY());
785     return result;
786 }
787 
AdjustTextRectOffsetX()788 float TextFieldPattern::AdjustTextRectOffsetX()
789 {
790     auto cursorWidth = caretRect_.Width();
791     auto contentLeftBoundary = contentRect_.GetX();
792     auto contentRightBoundary = contentRect_.GetX() + contentRect_.GetSize().Width() - unitWidth_;
793     if (IsTextArea()) {
794         caretRect_.SetLeft(std::clamp(caretRect_.GetX(), contentLeftBoundary, contentRightBoundary - cursorWidth));
795         return 0.0f;
796     }
797     float textDx = 0.0f;
798     if (textRect_.Width() > contentRect_.Width()) {
799         if (textRect_.GetX() + textRect_.Width() < contentRightBoundary) {
800             textDx = contentRightBoundary - textRect_.GetX() - textRect_.Width();
801             caretRect_.SetLeft(caretRect_.GetX() + textDx);
802             textRect_.SetLeft(textRect_.GetX() + textDx);
803         }
804     }
805     // text rect length exceeds content length, but cursor is still in the region
806     if (CursorInContentRegion()) {
807         return textDx;
808     }
809     auto offsetToParagraphBeginning = caretRect_.GetX() - textRect_.GetX();
810     float dx = 0.0f;
811     if (caretRect_.GetX() < contentLeftBoundary) {
812         dx = contentLeftBoundary - caretRect_.GetX();
813         caretRect_.SetLeft(caretRect_.GetX() + dx);
814         textRect_.SetLeft(caretRect_.GetX() - offsetToParagraphBeginning);
815     } else if (caretRect_.GetX() + cursorWidth > contentRightBoundary) {
816         dx = (contentRightBoundary - static_cast<float>(cursorWidth)) - caretRect_.GetX();
817         caretRect_.SetLeft(caretRect_.GetX() + dx);
818         textRect_.SetLeft(caretRect_.GetX() - offsetToParagraphBeginning);
819     }
820     dx += textDx;
821     return dx;
822 }
823 
AdjustTextAreaOffsetY()824 float TextFieldPattern::AdjustTextAreaOffsetY()
825 {
826     if (!IsTextArea()) {
827         return 0.0f;
828     }
829 
830     if (caretRect_.GetY() < contentRect_.GetY()) {
831         auto dy = contentRect_.GetY() - caretRect_.GetY();
832         caretRect_.SetTop(caretRect_.GetY() + dy);
833         textRect_.SetOffset(OffsetF(textRect_.GetX(), textRect_.GetY() + dy));
834         return dy;
835     }
836     auto dy = contentRect_.GetY() + GetBorderTop() + contentRect_.Height() - (caretRect_.Height() + caretRect_.GetY());
837     if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
838         dy = contentRect_.GetY() + contentRect_.Height() - (caretRect_.Height() + caretRect_.GetY());
839     }
840     // caret does not exceed bottom boundary, still need to check against safeArea
841     if (GreatOrEqual(dy, 0.0f)) {
842         return FitCursorInSafeArea();
843     }
844     caretRect_.SetTop(caretRect_.GetY() + dy - BOX_EPSILON * 2);
845     textRect_.SetOffset(OffsetF(textRect_.GetX(), textRect_.GetY() + dy - BOX_EPSILON * 2));
846     return dy;
847 }
848 
CursorInContentRegion()849 bool TextFieldPattern::CursorInContentRegion()
850 {
851     if (IsTextArea()) {
852         return GreatOrEqual(caretRect_.Top(), contentRect_.GetY()) &&
853                LessOrEqual(
854                    caretRect_.Top() + GetTextOrPlaceHolderFontSize(), contentRect_.GetY() + contentRect_.Height());
855     }
856     return GreatOrEqual(caretRect_.GetX(), contentRect_.GetX()) &&
857            LessOrEqual(
858                caretRect_.GetX() + CURSOR_WIDTH.ConvertToPx(), contentRect_.GetX() + contentRect_.Width() - unitWidth_);
859 }
860 
FitCursorInSafeArea()861 float TextFieldPattern::FitCursorInSafeArea()
862 {
863     if (caretUpdateType_ != CaretUpdateType::INPUT) {
864         return 0.0f;
865     }
866     // check if caret is below safeArea
867     auto pipeline = PipelineContext::GetCurrentContext();
868     auto safeAreaBottom = pipeline->GetSafeArea().bottom_;
869     safeAreaBottom = safeAreaBottom.Combine(pipeline->GetSafeAreaManager()->GetKeyboardInset());
870     CHECK_NULL_RETURN_NOLOG(safeAreaBottom.IsValid(), 0.0f);
871     // get global height of caret
872     auto host = GetHost();
873     auto globalBottom = host->GetPaintRectOffset().GetY() + caretRect_.Bottom();
874     if (globalBottom > safeAreaBottom.start) {
875         auto dy = safeAreaBottom.start - globalBottom;
876         caretRect_.SetTop(caretRect_.GetY() + dy);
877         textRect_.SetOffset(OffsetF(textRect_.GetX(), textRect_.GetY() + dy));
878         return dy;
879     }
880     return 0.0f;
881 }
882 
OffsetInContentRegion(const Offset & offset)883 bool TextFieldPattern::OffsetInContentRegion(const Offset& offset)
884 {
885     // real content region will minus basic padding on left and right
886     return GreatOrEqual(offset.GetX(), contentRect_.GetX()) &&
887            LessOrEqual(offset.GetX(), contentRect_.GetX() + contentRect_.Width());
888 }
889 
OnScrollEndCallback()890 void TextFieldPattern::OnScrollEndCallback()
891 {
892     auto scrollBar = GetScrollBar();
893     if (scrollBar) {
894         scrollBar->ScheduleDisapplearDelayTask();
895     }
896     auto selectOverlayProxy = GetSelectOverlay();
897     CHECK_NULL_VOID_NOLOG(selectOverlayProxy);
898     if (originalIsMenuShow_) {
899         selectOverlayProxy->ShowOrHiddenMenu(false);
900     }
901 }
902 
OnTextAreaScroll(float offset)903 void TextFieldPattern::OnTextAreaScroll(float offset)
904 {
905     LOGI("OnTextAreaScroll with offset %{public}f", offset);
906     if (!IsTextArea() || textRect_.Height() <= contentRect_.Height()) {
907         return;
908     }
909     if (textRect_.GetY() + offset > contentRect_.GetY()) {
910         offset = contentRect_.GetY() - textRect_.GetY();
911     } else if (textRect_.GetY() + textRect_.Height() + offset < contentRect_.GetY() + contentRect_.Height()) {
912         offset = contentRect_.GetY() + contentRect_.Height() - textRect_.GetY() - textRect_.Height();
913     }
914     caretRect_.SetTop(caretRect_.GetY() + offset);
915     currentOffset_ = textRect_.GetY() + offset;
916     textRect_.SetOffset(OffsetF(textRect_.GetX(), currentOffset_));
917     if (SelectOverlayIsOn()) {
918         SizeF handlePaintSize = { SelectHandleInfo::GetDefaultLineWidth().ConvertToPx(), caretRect_.Height() };
919         textSelector_.secondHandleOffset_.SetY(textSelector_.secondHandleOffset_.GetY() + offset);
920         std::optional<RectF> secondHandle = RectF(textSelector_.secondHandleOffset_, handlePaintSize);
921         auto secondHandleHeight = 0.0f;
922         auto secondHandleOffset = textSelector_.secondHandleOffset_ - parentGlobalOffset_;
923         if (GreatOrEqual(offset, 0.0f) && GreatNotEqual(secondHandleOffset.GetY(), contentRect_.GetY())) {
924             secondHandleHeight = secondHandle->Height();
925         }
926         if (LessNotEqual(offset, 0.0f) && GreatNotEqual(secondHandleOffset.GetY() + secondHandle->Height(),
927                                               contentRect_.GetY() + contentRect_.Height())) {
928             secondHandleHeight = secondHandle->Height();
929         }
930         std::optional<RectF> firstHandle;
931         auto firstHandleHeight = 0.0f;
932         if (!isSingleHandle_) {
933             textSelector_.firstHandleOffset_.SetY(textSelector_.firstHandleOffset_.GetY() + offset);
934             firstHandle = { textSelector_.firstHandleOffset_, handlePaintSize };
935             auto firstHandleOffset = textSelector_.firstHandleOffset_ - parentGlobalOffset_;
936             if (GreatOrEqual(offset, 0.0f) && GreatNotEqual(firstHandleOffset.GetY(), contentRect_.GetY())) {
937                 firstHandleHeight = firstHandle->Height();
938             }
939             if (LessNotEqual(offset, 0.0f) && GreatNotEqual(firstHandleOffset.GetY() + firstHandle->Height(),
940                                                   contentRect_.GetY() + contentRect_.Height())) {
941                 firstHandleHeight = firstHandle->Height();
942             }
943         }
944         SelectHandleInfo firstHandleInfo;
945         SelectHandleInfo secondHandleInfo;
946         firstHandleInfo.paintRect =
947             RectF(firstHandle->Left(), firstHandle->Top(), firstHandle->Width(), firstHandle->Height());
948         secondHandleInfo.paintRect =
949             RectF(secondHandle->Left(), secondHandle->Top(), secondHandle->Width(), secondHandle->Height());
950         if (firstHandle.has_value()) {
951             firstHandleInfo.isShow = CheckHandleVisible(firstHandle.value());
952         }
953         if (secondHandle.has_value()) {
954             secondHandleInfo.isShow = CheckHandleVisible(secondHandle.value());
955         }
956         if (!isSingleHandle_) {
957             selectOverlayProxy_->UpdateFirstAndSecondHandleInfo(firstHandleInfo, secondHandleInfo);
958         } else {
959             selectOverlayProxy_->UpdateSecondSelectHandleInfo(secondHandleInfo);
960         }
961     }
962     UpdateScrollBarOffset();
963 }
964 
OnTextInputScroll(float offset)965 void TextFieldPattern::OnTextInputScroll(float offset)
966 {
967     if (IsTextArea() || textRect_.Width() <= contentRect_.Width()) {
968         return;
969     }
970     if (textRect_.GetX() + offset > contentRect_.GetX()) {
971         offset = contentRect_.GetX() - textRect_.GetX();
972     } else if (textRect_.GetX() + textRect_.Width() + offset < contentRect_.GetX() + contentRect_.Width()) {
973         offset = contentRect_.GetX() + contentRect_.Width() - textRect_.GetX() - textRect_.Width();
974     }
975     caretRect_.SetLeft(caretRect_.GetX() + offset);
976     currentOffset_ = textRect_.GetX() + offset;
977     textRect_.SetOffset(OffsetF(currentOffset_, textRect_.GetY()));
978     if (SelectOverlayIsOn()) {
979         SizeF handlePaintSize = { SelectHandleInfo::GetDefaultLineWidth().ConvertToPx(), caretRect_.Height() };
980         textSelector_.secondHandleOffset_.SetX(textSelector_.secondHandleOffset_.GetX() + offset);
981         std::optional<RectF> secondHandle = RectF(textSelector_.secondHandleOffset_, handlePaintSize);
982         std::optional<RectF> firstHandle;
983         if (!isSingleHandle_) {
984             textSelector_.firstHandleOffset_.SetX(textSelector_.firstHandleOffset_.GetX() + offset);
985             firstHandle = { textSelector_.firstHandleOffset_, handlePaintSize };
986         }
987         SelectHandleInfo firstHandleInfo;
988         SelectHandleInfo secondHandleInfo;
989         firstHandleInfo.paintRect =
990             RectF(firstHandle->Left(), firstHandle->Top(), firstHandle->Width(), firstHandle->Height());
991         secondHandleInfo.paintRect =
992             RectF(secondHandle->Left(), secondHandle->Top(), secondHandle->Width(), secondHandle->Height());
993         CheckHandles(firstHandle, secondHandle);
994         if (!firstHandle.has_value()) {
995             firstHandleInfo.isShow = false;
996         }
997         if (!secondHandle.has_value()) {
998             secondHandleInfo.isShow = false;
999         }
1000         if (!isSingleHandle_) {
1001             selectOverlayProxy_->UpdateFirstAndSecondHandleInfo(firstHandleInfo, secondHandleInfo);
1002         } else {
1003             selectOverlayProxy_->UpdateSecondSelectHandleInfo(secondHandleInfo);
1004         }
1005     }
1006     auto tmpHost = GetHost();
1007     CHECK_NULL_VOID(tmpHost);
1008     tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1009 }
1010 
GetTextRectsInRange(int32_t base,int32_t destination,std::vector<RSTypographyProperties::TextBox> & textBoxes)1011 void TextFieldPattern::GetTextRectsInRange(
1012     int32_t base, int32_t destination, std::vector<RSTypographyProperties::TextBox>& textBoxes)
1013 {
1014     SwapIfLarger(base, destination);
1015     if (!paragraph_) {
1016         return;
1017     }
1018 
1019     textBoxes = paragraph_->GetRectsForRange(
1020         base, destination, RSTypographyProperties::RectHeightStyle::MAX, RSTypographyProperties::RectWidthStyle::TIGHT);
1021     if (textBoxes.size() == 1 && caretUpdateType_ == CaretUpdateType::LONG_PRESSED) {
1022         Offset offset = GetLastTouchOffset() - Offset(textRect_.GetX(), textRect_.GetY());
1023         if (offset.GetX() < textBoxes[0].rect_.GetLeft() || offset.GetY() < textBoxes[0].rect_.GetTop()) {
1024             int32_t start = 0;
1025             int32_t end = 0;
1026             GetWordBoundaryPositon(base - 1, start, end);
1027             auto tmp = paragraph_->GetRectsForRange(start, end, RSTypographyProperties::RectHeightStyle::MAX,
1028                 RSTypographyProperties::RectWidthStyle::TIGHT);
1029             if (tmp.size() != 1) {
1030                 return;
1031             }
1032             if (LastTouchIsInSelectRegion(tmp)) {
1033                 textBoxes = tmp;
1034                 textSelector_.Update(start, end);
1035                 if (textEditingValue_.caretPosition != end) {
1036                     textEditingValue_.caretPosition = end;
1037                 }
1038             }
1039         }
1040     }
1041 }
1042 
ComputeOffsetForCaretDownstream(int32_t extent,CaretMetricsF & result)1043 bool TextFieldPattern::ComputeOffsetForCaretDownstream(int32_t extent, CaretMetricsF& result)
1044 {
1045     CHECK_NULL_RETURN_NOLOG(paragraph_, false);
1046     auto wideText = textEditingValue_.GetWideText();
1047     if (!IsTextArea() && static_cast<size_t>(extent) >= wideText.length()) {
1048         return false;
1049     }
1050 
1051     result.Reset();
1052     const int32_t graphemeClusterLength = 1;
1053     const int32_t next = extent + graphemeClusterLength;
1054     auto textBoxes = paragraph_->GetRectsForRange(
1055         extent, next, RSTypographyProperties::RectHeightStyle::MAX, RSTypographyProperties::RectWidthStyle::TIGHT);
1056 
1057     if (textBoxes.empty()) {
1058         LOGD("Box empty");
1059         return false;
1060     }
1061 
1062     const auto& textBox = *textBoxes.begin();
1063     auto lastStringBeforeCursor = wideText.substr(
1064         std::clamp(textEditingValue_.caretPosition - 1, 0, static_cast<int32_t>(wideText.length()) - 1), 1);
1065     // Caret is within width of the downstream glyphs.
1066     if (lastStringBeforeCursor == WIDE_NEWLINE &&
1067         (caretUpdateType_ == CaretUpdateType::INPUT || caretUpdateType_ == CaretUpdateType::DEL)) {
1068         result.offset.SetX(MakeEmptyOffset().GetX());
1069         result.offset.SetY(textBox.rect_.GetTop());
1070         result.height = textBox.rect_.GetHeight();
1071         return true;
1072     }
1073 
1074     // Caret is within width of the downstream glyphs.
1075     float offsetX = textBox.rect_.GetLeft();
1076     result.offset.SetX(offsetX);
1077     result.offset.SetY(textBox.rect_.GetTop());
1078     result.height = textBox.rect_.GetHeight();
1079     return true;
1080 }
1081 
ComputeOffsetForCaretUpstream(int32_t extent,CaretMetricsF & result) const1082 bool TextFieldPattern::ComputeOffsetForCaretUpstream(int32_t extent, CaretMetricsF& result) const
1083 {
1084     auto text = textEditingValue_.text;
1085     auto wideText = textEditingValue_.GetWideText();
1086     if (!paragraph_ || wideText.empty() || textEditingValue_.caretPosition == 0 ||
1087         textEditingValue_.caretPosition > static_cast<int32_t>(wideText.length())) {
1088         return false;
1089     }
1090 
1091     char16_t prevChar = 0;
1092     if (static_cast<size_t>(extent) <= textEditingValue_.GetWideText().length()) {
1093         prevChar = text[std::max(0, extent - 1)];
1094     }
1095 
1096     result.Reset();
1097     int32_t graphemeClusterLength = StringUtils::NotInUtf16Bmp(prevChar) ? 2 : 1;
1098     int32_t prev = extent - graphemeClusterLength;
1099     auto boxes = paragraph_->GetRectsForRange(
1100         prev, extent, RSTypographyProperties::RectHeightStyle::MAX, RSTypographyProperties::RectWidthStyle::TIGHT);
1101     while (boxes.empty() && !textEditingValue_.text.empty()) {
1102         graphemeClusterLength *= 2;
1103         prev = extent - graphemeClusterLength;
1104         if (prev < 0) {
1105             boxes = paragraph_->GetRectsForRange(
1106                 0, extent, RSTypographyProperties::RectHeightStyle::MAX, RSTypographyProperties::RectWidthStyle::TIGHT);
1107             break;
1108         }
1109         boxes = paragraph_->GetRectsForRange(
1110             prev, extent, RSTypographyProperties::RectHeightStyle::MAX, RSTypographyProperties::RectWidthStyle::TIGHT);
1111     }
1112     if (boxes.empty()) {
1113         LOGD("Empty box");
1114         return false;
1115     }
1116 
1117     const auto& textBox = *boxes.begin();
1118     auto caretPosition = textEditingValue_.caretPosition;
1119     auto maxPos = static_cast<int32_t>(wideText.length()) - 1;
1120     auto lastStringBeforeCursor = wideText.substr(std::clamp(caretPosition - 1, 0, maxPos), 1);
1121     // Caret is within width of the downstream glyphs.
1122     if (lastStringBeforeCursor == WIDE_NEWLINE &&
1123         (caretUpdateType_ == CaretUpdateType::INPUT || caretUpdateType_ == CaretUpdateType::DEL)) {
1124         result.offset.SetX(MakeEmptyOffset().GetX());
1125         result.offset.SetY(textBox.rect_.GetBottom());
1126         result.height = textBox.rect_.GetHeight();
1127         return true;
1128     }
1129     result.offset.SetX(textBox.rect_.GetRight());
1130     result.offset.SetY(textBox.rect_.GetTop());
1131     result.height = textBox.rect_.GetHeight();
1132     return true;
1133 }
1134 
MakeEmptyOffset() const1135 OffsetF TextFieldPattern::MakeEmptyOffset() const
1136 {
1137     auto tmpHost = GetHost();
1138     CHECK_NULL_RETURN(tmpHost, {});
1139     auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
1140     CHECK_NULL_RETURN(layoutProperty, {});
1141     switch (layoutProperty->GetTextAlignValue(TextAlign::START)) {
1142         case TextAlign::CENTER:
1143             return OffsetF(contentRect_.Width() * 0.5f, 0.0f);
1144         case TextAlign::END:
1145             return OffsetF(contentRect_.Width(), 0.0f);
1146         case TextAlign::START:
1147         default:
1148             return {};
1149     }
1150 }
1151 
ConvertTouchOffsetToCaretPosition(const Offset & localOffset)1152 int32_t TextFieldPattern::ConvertTouchOffsetToCaretPosition(const Offset& localOffset)
1153 {
1154     CHECK_NULL_RETURN(paragraph_, 0);
1155     return static_cast<int32_t>(paragraph_->GetGlyphPositionAtCoordinate(localOffset.GetX(), localOffset.GetY()).pos_);
1156 }
1157 
GetWordBoundaryPositon(int32_t offset,int32_t & start,int32_t & end)1158 void TextFieldPattern::GetWordBoundaryPositon(int32_t offset, int32_t& start, int32_t& end)
1159 {
1160     CHECK_NULL_VOID_NOLOG(paragraph_);
1161     auto positon = paragraph_->GetWordBoundary(offset);
1162     start = static_cast<int32_t>(positon.start_);
1163     end = static_cast<int32_t>(positon.end_);
1164 }
1165 
DisplayPlaceHolder()1166 bool TextFieldPattern::DisplayPlaceHolder()
1167 {
1168     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
1169     CHECK_NULL_RETURN(layoutProperty, false);
1170     auto value = layoutProperty->GetValueValue("");
1171     return value.empty();
1172 }
1173 
GetEditingValue() const1174 const TextEditingValueNG& TextFieldPattern::GetEditingValue() const
1175 {
1176     return textEditingValue_;
1177 }
1178 
1179 #if defined(IOS_PLATFORM)
GetGlobalOffset() const1180 Offset TextFieldPattern::GetGlobalOffset() const
1181 {
1182     Offset offset;
1183     auto host = GetHost();
1184     CHECK_NULL_RETURN(host, {});
1185     auto pipeline = host->GetContext();
1186     CHECK_NULL_RETURN(pipeline, {});
1187     auto rootOffset = pipeline->GetRootRect().GetOffset();
1188     auto globalOffset = host->GetPaintRectOffset() - rootOffset;
1189     offset = Offset(globalOffset.GetX(), globalOffset.GetY());
1190     return offset;
1191 }
1192 
GetEditingBoxY() const1193 double TextFieldPattern::GetEditingBoxY() const
1194 {
1195     return GetGlobalOffset().GetY() + frameRect_.Height();
1196 };
1197 
GetEditingBoxTopY() const1198 double TextFieldPattern::GetEditingBoxTopY() const
1199 {
1200     return GetGlobalOffset().GetY();
1201 };
1202 
GetEditingBoxModel() const1203 bool TextFieldPattern::GetEditingBoxModel() const
1204 {
1205     bool isDeclarative = false;
1206     auto host = GetHost();
1207     CHECK_NULL_RETURN(host, false);
1208     auto pipeline = host->GetContext();
1209     if (pipeline && pipeline->GetIsDeclarative()) {
1210         isDeclarative = true;
1211     }
1212     return isDeclarative;
1213 };
1214 #endif
1215 
HandleFocusEvent()1216 void TextFieldPattern::HandleFocusEvent()
1217 {
1218     auto host = GetHost();
1219     CHECK_NULL_VOID(host);
1220     LOGI("TextField %{public}d on focus", host->GetId());
1221     auto context = host->GetContext();
1222     CHECK_NULL_VOID(context);
1223     auto globalOffset = host->GetPaintRectOffset() - context->GetRootRect().GetOffset();
1224     UpdateTextFieldManager(Offset(globalOffset.GetX(), globalOffset.GetY()), frameRect_.Height());
1225     if (caretUpdateType_ != CaretUpdateType::PRESSED) {
1226         caretUpdateType_ = CaretUpdateType::EVENT;
1227         needToRequestKeyboardInner_ = !(dragRecipientStatus_ == DragStatus::DRAGGING);
1228     }
1229     auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
1230     CHECK_NULL_VOID(paintProperty);
1231     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
1232     CHECK_NULL_VOID(layoutProperty);
1233     if (IsNormalInlineState() && (!textEditingValue_.GetWideText().empty() ||
1234         !layoutProperty->GetPlaceholderValue("").empty())) {
1235         ApplyInlineStates(true);
1236         inlineSelectAllFlag_ = true;
1237         inlineFocusState_ = true;
1238         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1239     } else {
1240         StartTwinkling();
1241     }
1242     auto eventHub = host->GetEventHub<TextFieldEventHub>();
1243     CHECK_NULL_VOID(eventHub);
1244     eventHub->FireOnEditChanged(true);
1245     CloseSelectOverlay();
1246     auto visible = layoutProperty->GetShowErrorTextValue(false);
1247     if (!visible && layoutProperty->GetShowUnderlineValue(false) &&
1248         layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED) == TextInputType::UNSPECIFIED) {
1249         auto renderContext = host->GetRenderContext();
1250         auto pipeline = PipelineBase::GetCurrentContext();
1251         CHECK_NULL_VOID(pipeline);
1252         auto textFieldTheme = pipeline->GetTheme<TextFieldTheme>();
1253         CHECK_NULL_VOID(textFieldTheme);
1254         auto radius = textFieldTheme->GetBorderRadiusSize();
1255         underlineColor_ = textFieldTheme->GetUnderlineTypingColor();
1256         underlineWidth_ = TYPING_UNDERLINE_WIDTH;
1257         renderContext->UpdateBorderRadius({ radius.GetX(), radius.GetY(), radius.GetY(), radius.GetX() });
1258     }
1259     host->MarkDirtyNode(layoutProperty->GetMaxLinesValue(Infinity<float>()) <= 1 ? PROPERTY_UPDATE_MEASURE_SELF
1260                                                                                       : PROPERTY_UPDATE_MEASURE);
1261 }
1262 
HandleSetSelection(int32_t start,int32_t end,bool showHandle)1263 void TextFieldPattern::HandleSetSelection(int32_t start, int32_t end, bool showHandle)
1264 {
1265     LOGI("HandleSetSelection %{public}d, %{public}d", start, end);
1266     CloseSelectOverlay();
1267     UpdateSelection(start, end);
1268     textEditingValue_.caretPosition =
1269         std::clamp(end, 0, static_cast<int32_t>(textEditingValue_.GetWideText().length()));
1270     selectionMode_ = start == end ? SelectionMode::NONE : SelectionMode::SELECT;
1271     GetTextRectsInRange(textSelector_.GetStart(), textSelector_.GetEnd(), textBoxes_);
1272     AdjustTextSelectionRectOffsetX();
1273     UpdateCaretRectByPosition(textEditingValue_.caretPosition);
1274     if (showHandle) {
1275         if (start == end) {
1276             CreateSingleHandle();
1277         } else {
1278             CreateHandles();
1279         }
1280     }
1281     UpdateCaretInfoToController();
1282     auto tmpHost = GetHost();
1283     CHECK_NULL_VOID(tmpHost);
1284     tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1285 }
1286 
AdjustTextSelectionRectOffsetX()1287 void TextFieldPattern::AdjustTextSelectionRectOffsetX()
1288 {
1289     if (textBoxes_.empty()) {
1290         return;
1291     }
1292     auto contentLeftBoundary = contentRect_.GetX();
1293     auto contentRightBoundary = contentRect_.GetX() + contentRect_.GetSize().Width() - unitWidth_;
1294     auto selectionStart = textBoxes_.begin()->rect_.GetLeft() + textRect_.GetX();
1295     auto selectionEnd = textBoxes_.begin()->rect_.GetRight() + textRect_.GetX();
1296 
1297     float dx = 0.0f;
1298     if (selectionEnd < contentLeftBoundary) {
1299         if (selectionStart < selectionEnd) {
1300             dx = contentLeftBoundary - selectionStart;
1301         } else {
1302             dx = contentLeftBoundary - selectionEnd;
1303         }
1304     } else if (selectionEnd > contentRightBoundary) {
1305         if (selectionStart < selectionEnd) {
1306             dx = selectionEnd - contentRightBoundary;
1307         } else {
1308             dx = selectionStart - contentRightBoundary;
1309         }
1310     }
1311     textRect_.SetLeft(textRect_.GetX() + dx);
1312 }
1313 
HandleExtendAction(int32_t action)1314 void TextFieldPattern::HandleExtendAction(int32_t action)
1315 {
1316     LOGI("HandleExtendAction %{public}d", action);
1317     switch (action) {
1318         case ACTION_SELECT_ALL: {
1319             HandleOnSelectAll(false);
1320             break;
1321         }
1322         case ACTION_CUT: {
1323             HandleOnCut();
1324             break;
1325         }
1326         case ACTION_COPY: {
1327             HandleOnCopy();
1328             break;
1329         }
1330         case ACTION_PASTE: {
1331             HandleOnPaste();
1332             break;
1333         }
1334         default: {
1335             break;
1336         }
1337     }
1338 }
1339 
HandleSelect(int32_t keyCode,int32_t cursorMoveSkip)1340 void TextFieldPattern::HandleSelect(int32_t keyCode, int32_t cursorMoveSkip)
1341 {
1342     LOGI("HandleSelect, current caret position %{public}d", textEditingValue_.caretPosition);
1343     KeyCode code = static_cast<KeyCode>(keyCode);
1344     caretUpdateType_ = CaretUpdateType::EVENT;
1345     switch (code) {
1346         case KeyCode::KEY_DPAD_LEFT: {
1347             HandleSelectionLeft();
1348             break;
1349         }
1350         case KeyCode::KEY_DPAD_RIGHT: {
1351             HandleSelectionRight();
1352             break;
1353         }
1354         case KeyCode::KEY_DPAD_UP: {
1355             HandleSelectionUp();
1356             break;
1357         }
1358         case KeyCode::KEY_DPAD_DOWN: {
1359             HandleSelectionDown();
1360             break;
1361         }
1362         default: {
1363             break;
1364         }
1365     }
1366 }
1367 
InitFocusEvent()1368 void TextFieldPattern::InitFocusEvent()
1369 {
1370     CHECK_NULL_VOID_NOLOG(!focusEventInitialized_);
1371     auto host = GetHost();
1372     CHECK_NULL_VOID(host);
1373     auto focusHub = host->GetOrCreateFocusHub();
1374     auto focusTask = [weak = WeakClaim(this)]() {
1375         auto pattern = weak.Upgrade();
1376         if (pattern) {
1377             pattern->HandleFocusEvent();
1378         }
1379     };
1380     focusHub->SetOnFocusInternal(focusTask);
1381     auto blurTask = [weak = WeakClaim(this)]() {
1382         auto pattern = weak.Upgrade();
1383         CHECK_NULL_VOID_NOLOG(pattern);
1384         pattern->HandleBlurEvent();
1385     };
1386     focusHub->SetOnBlurInternal(blurTask);
1387 
1388     auto keyTask = [weak = WeakClaim(this)](const KeyEvent& keyEvent) -> bool {
1389         auto pattern = weak.Upgrade();
1390         CHECK_NULL_RETURN(pattern, false);
1391         return pattern->OnKeyEvent(keyEvent);
1392     };
1393     focusHub->SetOnKeyEventInternal(keyTask);
1394     focusEventInitialized_ = true;
1395 }
1396 
HandleBlurEvent()1397 void TextFieldPattern::HandleBlurEvent()
1398 {
1399     auto host = GetHost();
1400     CHECK_NULL_VOID(host);
1401     LOGI("TextField %{public}d OnBlur", host->GetId());
1402     auto context = PipelineContext::GetCurrentContext();
1403     CHECK_NULL_VOID(context);
1404     auto textFieldManager = DynamicCast<TextFieldManagerNG>(context->GetTextFieldManager());
1405     if (textFieldManager) {
1406         textFieldManager->ClearOnFocusTextField();
1407     }
1408     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
1409     CHECK_NULL_VOID(layoutProperty);
1410     auto pipeline = PipelineBase::GetCurrentContext();
1411     CHECK_NULL_VOID(pipeline);
1412     auto textFieldTheme = pipeline->GetTheme<TextFieldTheme>();
1413     CHECK_NULL_VOID(textFieldTheme);
1414     auto visible = layoutProperty->GetShowErrorTextValue(false);
1415     if (!visible && layoutProperty->GetShowUnderlineValue(false) &&
1416         layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED) == TextInputType::UNSPECIFIED) {
1417         auto renderContext = host->GetRenderContext();
1418         renderContext->UpdateBorderRadius(borderRadius_);
1419         underlineColor_ = textFieldTheme->GetUnderlineColor();
1420         underlineWidth_ = UNDERLINE_WIDTH;
1421     }
1422     auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
1423     CHECK_NULL_VOID(paintProperty);
1424     if (IsNormalInlineState()) {
1425         if (IsTextArea() && isTextInput_) {
1426             layoutProperty->UpdateMaxLines(1);
1427         }
1428         inlineSelectAllFlag_ = false;
1429         inlineFocusState_ = false;
1430         RestorePreInlineStates();
1431     }
1432     needToRequestKeyboardInner_ = false;
1433     isFocusedBeforeClick_ = false;
1434     StopTwinkling();
1435     CloseKeyboard(true);
1436     MarkRedrawOverlay();
1437     textSelector_.Update(-1);
1438     selectionMode_ = SelectionMode::NONE;
1439     auto eventHub = host->GetEventHub<TextFieldEventHub>();
1440     eventHub->FireOnEditChanged(false);
1441     CloseSelectOverlay(true);
1442     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1443 }
1444 
OnKeyEvent(const KeyEvent & event)1445 bool TextFieldPattern::OnKeyEvent(const KeyEvent& event)
1446 {
1447     caretUpdateType_ = CaretUpdateType::EVENT;
1448     CloseSelectOverlay(true);
1449     auto context = PipelineContext::GetCurrentContext();
1450     auto textFieldManager = DynamicCast<TextFieldManagerNG>(context->GetTextFieldManager());
1451     CHECK_NULL_RETURN(textFieldManager, false);
1452     auto keyEventHandler = textFieldManager->GetKeyEventHandler();
1453     keyEventHandler->UpdateWeakPattern(AceType::WeakClaim(this));
1454     return keyEventHandler->HandleKeyEvent(event);
1455 }
1456 
HandleOnUndoAction()1457 void TextFieldPattern::HandleOnUndoAction()
1458 {
1459     LOGI("TextFieldPattern::HandleOnUndoAction");
1460     if (operationRecords_.empty()) {
1461         LOGW("Operation records empty, cannot undo");
1462         return;
1463     }
1464     auto value = operationRecords_.back();
1465     operationRecords_.pop_back();
1466     if (redoOperationRecords_.size() >= RECORD_MAX_LENGTH && !(redoOperationRecords_.empty())) {
1467         redoOperationRecords_.erase(redoOperationRecords_.begin());
1468     }
1469     redoOperationRecords_.push_back(value);
1470     if (operationRecords_.empty()) {
1471         LOGW("No record left, clear");
1472         FireEventHubOnChange("");
1473         ClearEditingValue();
1474         return;
1475     }
1476     textEditingValue_ = operationRecords_.back();
1477     SetEditingValueToProperty(textEditingValue_.text);
1478     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
1479     CHECK_NULL_VOID(layoutProperty);
1480     auto tmpHost = GetHost();
1481     CHECK_NULL_VOID(tmpHost);
1482     tmpHost->MarkDirtyNode(layoutProperty->GetMaxLinesValue(Infinity<float>()) <= 1 ? PROPERTY_UPDATE_MEASURE_SELF
1483                                                                                       : PROPERTY_UPDATE_MEASURE);
1484     FireEventHubOnChange(GetEditingValue().text);
1485 }
1486 
HandleOnRedoAction()1487 void TextFieldPattern::HandleOnRedoAction()
1488 {
1489     LOGI("TextFieldPattern::HandleOnRedoAction");
1490     if (redoOperationRecords_.empty()) {
1491         LOGW("Redo operation records empty, cannot undo");
1492         return;
1493     }
1494     textEditingValue_ = redoOperationRecords_.back();
1495     redoOperationRecords_.pop_back();
1496     operationRecords_.push_back(textEditingValue_);
1497     SetEditingValueToProperty(textEditingValue_.text);
1498     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
1499     CHECK_NULL_VOID(layoutProperty);
1500     auto tmpHost = GetHost();
1501     CHECK_NULL_VOID(tmpHost);
1502     tmpHost->MarkDirtyNode(layoutProperty->GetMaxLinesValue(Infinity<float>()) <= 1 ? PROPERTY_UPDATE_MEASURE_SELF
1503                                                                                       : PROPERTY_UPDATE_MEASURE);
1504     FireEventHubOnChange(GetEditingValue().text);
1505 }
1506 
HandleOnSelectAll(bool isKeyEvent,bool inlineStyle)1507 void TextFieldPattern::HandleOnSelectAll(bool isKeyEvent, bool inlineStyle)
1508 {
1509     LOGI("TextFieldPattern::HandleOnSelectAll");
1510     auto textSize = static_cast<int32_t>(GetEditingValue().GetWideText().length());
1511     if (inlineStyle == true) {
1512         if (GetEditingValue().GetWideText().rfind(L".") < textSize - FIND_TEXT_ZERO_INDEX) {
1513             textSize = GetEditingValue().GetWideText().rfind(L".");
1514         }
1515         UpdateSelection(0, textSize);
1516     } else {
1517         UpdateSelection(0, textSize);
1518     }
1519     updateSelectionAfterObscure_ = ResetObscureTickCountDown();
1520     textEditingValue_.caretPosition = textSize;
1521     selectionMode_ = SelectionMode::SELECT_ALL;
1522     caretUpdateType_ = CaretUpdateType::EVENT;
1523     MarkRedrawOverlay();
1524     GetTextRectsInRange(textSelector_.GetStart(), textSelector_.GetEnd(), textBoxes_);
1525     isSingleHandle_ = textEditingValue_.text.empty();
1526     auto tmpHost = GetHost();
1527     CHECK_NULL_VOID(tmpHost);
1528     tmpHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1529 
1530     if (!inlineSelectAllFlag_) {
1531         CloseSelectOverlay(true);
1532         std::optional<RectF> firstHandle = textSelector_.firstHandle;
1533         std::optional<RectF> secondHandle = textSelector_.secondHandle;
1534         ShowSelectOverlay(firstHandle, secondHandle);
1535     }
1536 }
1537 
HandleOnCopy()1538 void TextFieldPattern::HandleOnCopy()
1539 {
1540     LOGI("TextFieldPattern::HandleOnCopy");
1541     CHECK_NULL_VOID(clipboard_);
1542     auto tmpHost = GetHost();
1543     CHECK_NULL_VOID(tmpHost);
1544     auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
1545     CHECK_NULL_VOID(layoutProperty);
1546     caretUpdateType_ = CaretUpdateType::NONE;
1547     if (layoutProperty->GetCopyOptionsValue(CopyOptions::Distributed) == CopyOptions::None) {
1548         LOGW("Copy option not allowed");
1549         return;
1550     }
1551     if (layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED) == TextInputType::VISIBLE_PASSWORD) {
1552         LOGW("Cannot copy in password mode");
1553         selectionMode_ = SelectionMode::NONE;
1554         UpdateCaretPositionWithClamp(textSelector_.GetEnd());
1555         UpdateSelection(textEditingValue_.caretPosition);
1556         StartTwinkling();
1557         return;
1558     }
1559     if (!IsSelected() || (textSelector_.IsValid() && textSelector_.GetStart() == textSelector_.GetEnd())) {
1560         LOGW("Nothing to select");
1561         return;
1562     }
1563     LOGI("On copy, text selector %{public}s", textSelector_.ToString().c_str());
1564     auto value = GetEditingValue().GetSelectedText(textSelector_.GetStart(), textSelector_.GetEnd());
1565     if (value.empty()) {
1566         LOGW("Copy value is empty");
1567         return;
1568     }
1569     if (layoutProperty->GetCopyOptionsValue(CopyOptions::Distributed) != CopyOptions::None) {
1570         LOGI("Copy value is %{private}s", value.c_str());
1571         clipboard_->SetData(value, layoutProperty->GetCopyOptionsValue(CopyOptions::Distributed));
1572     }
1573 
1574     UpdateCaretPositionWithClamp(textSelector_.GetEnd());
1575     UpdateSelection(textEditingValue_.caretPosition);
1576     UpdateCaretRectByPosition(textEditingValue_.caretPosition);
1577     selectionMode_ = SelectionMode::NONE;
1578     StartTwinkling();
1579     // If the parent node is a Search, the Search callback is executed.
1580     if (IsSearchParentNode()) {
1581         auto parentFrameNode = AceType::DynamicCast<FrameNode>(tmpHost->GetParent());
1582         auto eventHub = parentFrameNode->GetEventHub<SearchEventHub>();
1583         CHECK_NULL_VOID(eventHub);
1584         eventHub->FireOnCopy(value);
1585         return;
1586     }
1587 
1588     auto eventHub = tmpHost->GetEventHub<TextFieldEventHub>();
1589     CHECK_NULL_VOID(eventHub);
1590     eventHub->FireOnCopy(value);
1591 }
1592 
HandleOnPaste()1593 void TextFieldPattern::HandleOnPaste()
1594 {
1595     LOGI("TextFieldPattern::HandleOnPaste");
1596     auto pasteCallback = [weak = WeakClaim(this), textSelector = textSelector_](const std::string& data) {
1597         if (data.empty()) {
1598             LOGW("Paste value is empty");
1599             return;
1600         }
1601         auto textfield = weak.Upgrade();
1602         CHECK_NULL_VOID_NOLOG(textfield);
1603         auto tmpHost = textfield->GetHost();
1604         CHECK_NULL_VOID(tmpHost);
1605         auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
1606         CHECK_NULL_VOID(layoutProperty);
1607         auto value = textfield->GetEditingValue();
1608         auto valueLength = textfield->GetEditingValue().GetWideText().length();
1609         int32_t start = 0;
1610         int32_t end = 0;
1611         if (textfield->IsSelected()) {
1612             start = textSelector.GetStart();
1613             end = textSelector.GetEnd();
1614             SwapIfLarger(start, end);
1615         } else {
1616             start = value.caretPosition;
1617             end = value.caretPosition;
1618         }
1619         std::string result;
1620         std::string valueToUpdate(data);
1621         textfield->EditingValueFilter(valueToUpdate, result, true);
1622         LOGD("After filter paste value is %{private}s", result.c_str());
1623         std::wstring pasteData;
1624         std::wstring wData = StringUtils::ToWstring(result);
1625         textfield->StripNextLine(wData);
1626         if (wData.length() + valueLength - (end - start) > textfield->GetMaxLength()) {
1627             pasteData = wData.substr(0, textfield->GetMaxLength() - valueLength + (end - start));
1628         } else {
1629             pasteData = wData;
1630         }
1631         value.text =
1632             value.GetValueBeforePosition(start) + StringUtils::ToString(pasteData) + value.GetValueAfterPosition(end);
1633         auto newCaretPosition = std::clamp(std::min(start, end) + static_cast<int32_t>(pasteData.length()), 0,
1634             static_cast<int32_t>(StringUtils::ToWstring(value.text).length()));
1635         textfield->ResetObscureTickCountDown();
1636         textfield->UpdateEditingValue(value.text, newCaretPosition);
1637         textfield->UpdateSelection(newCaretPosition);
1638         textfield->SetEditingValueToProperty(value.text);
1639         textfield->SetInSelectMode(SelectionMode::NONE);
1640         textfield->SetCaretUpdateType(CaretUpdateType::INPUT);
1641         textfield->UpdateEditingValueToRecord();
1642         auto host = textfield->GetHost();
1643         CHECK_NULL_VOID(host);
1644         // If the parent node is a Search, the Search callback is executed.
1645         if (textfield->IsSearchParentNode()) {
1646             auto parentFrameNode = AceType::DynamicCast<FrameNode>(host->GetParent());
1647             auto eventHub = parentFrameNode->GetEventHub<SearchEventHub>();
1648             CHECK_NULL_VOID(eventHub);
1649             eventHub->FireOnPaste(StringUtils::ToString(pasteData));
1650             textfield->FireEventHubOnChange(value.text);
1651             host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1652             return;
1653         }
1654 
1655         auto eventHub = tmpHost->GetEventHub<TextFieldEventHub>();
1656         CHECK_NULL_VOID(eventHub);
1657         eventHub->FireOnPaste(StringUtils::ToString(pasteData));
1658         textfield->FireEventHubOnChange(value.text);
1659         host->MarkDirtyNode(layoutProperty->GetMaxLinesValue(Infinity<float>()) <= 1 ? PROPERTY_UPDATE_MEASURE_SELF
1660                                                                                      : PROPERTY_UPDATE_MEASURE);
1661         textfield->StartTwinkling();
1662     };
1663     CHECK_NULL_VOID(clipboard_);
1664     clipboard_->GetData(pasteCallback);
1665 }
1666 
StripNextLine(std::wstring & data)1667 void TextFieldPattern::StripNextLine(std::wstring& data)
1668 {
1669     CHECK_NULL_VOID(!(data.empty() || IsTextArea()));
1670     std::wstring result;
1671     bool dataChanged = false;
1672     int32_t dataPtr = 0;
1673     while (dataPtr < static_cast<int32_t>(data.length())) {
1674         if (data[dataPtr] != WIDE_NEWLINE[0]) {
1675             result += data[dataPtr];
1676         } else {
1677             dataChanged = true;
1678         }
1679         dataPtr++;
1680     }
1681     CHECK_NULL_VOID(dataChanged);
1682     data = result;
1683 }
1684 
HandleOnCut()1685 void TextFieldPattern::HandleOnCut()
1686 {
1687     LOGI("TextFieldPattern::HandleOnCut");
1688 #if !defined(PREVIEW)
1689     CHECK_NULL_VOID(clipboard_);
1690 #endif
1691     auto tmpHost = GetHost();
1692     CHECK_NULL_VOID(tmpHost);
1693     auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
1694     CHECK_NULL_VOID(layoutProperty);
1695     caretUpdateType_ = CaretUpdateType::NONE;
1696     if (layoutProperty->GetCopyOptionsValue(CopyOptions::Distributed) == CopyOptions::None) {
1697         LOGW("Copy option not allowed");
1698         return;
1699     }
1700     auto start = textSelector_.GetStart();
1701     auto end = textSelector_.GetEnd();
1702     SwapIfLarger(start, end);
1703     if (!IsSelected() || (textSelector_.IsValid() && start == end)) {
1704         LOGW("HandleOnCut nothing Selected");
1705         return;
1706     }
1707     auto value = GetEditingValue();
1708     auto selectedText = value.GetSelectedText(start, end);
1709     if (layoutProperty->GetCopyOptionsValue(CopyOptions::Distributed) != CopyOptions::None) {
1710         LOGI("Cut value is %{private}s", selectedText.c_str());
1711         clipboard_->SetData(selectedText, layoutProperty->GetCopyOptionsValue(CopyOptions::Distributed));
1712     }
1713     textEditingValue_.text =
1714         textEditingValue_.GetValueBeforePosition(start) + textEditingValue_.GetValueAfterPosition(end);
1715     textEditingValue_.CursorMoveToPosition(start);
1716     SetEditingValueToProperty(textEditingValue_.text);
1717     selectionMode_ = SelectionMode::NONE;
1718     CloseSelectOverlay(true);
1719     StartTwinkling();
1720     UpdateEditingValueToRecord();
1721     UpdateSelection(textEditingValue_.caretPosition);
1722     MarkRedrawOverlay();
1723     cursorVisible_ = true;
1724 
1725     auto host = GetHost();
1726     CHECK_NULL_VOID(host);
1727     // If the parent node is a Search, the Search callback is executed.
1728     if (IsSearchParentNode()) {
1729         auto parentFrameNode = AceType::DynamicCast<FrameNode>(host->GetParent());
1730         auto eventHub = parentFrameNode->GetEventHub<SearchEventHub>();
1731         CHECK_NULL_VOID(eventHub);
1732         eventHub->FireOnCut(selectedText);
1733         FireEventHubOnChange(textEditingValue_.text);
1734         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1735         return;
1736     }
1737 
1738     auto eventHub = host->GetEventHub<TextFieldEventHub>();
1739     CHECK_NULL_VOID(eventHub);
1740     eventHub->FireOnCut(selectedText);
1741     FireEventHubOnChange(textEditingValue_.text);
1742     host->MarkDirtyNode(layoutProperty->GetMaxLinesValue(Infinity<float>()) <= 1 ? PROPERTY_UPDATE_MEASURE_SELF
1743                                                                                  : PROPERTY_UPDATE_MEASURE);
1744 }
1745 
UpdateSelection(int32_t both)1746 void TextFieldPattern::UpdateSelection(int32_t both)
1747 {
1748     UpdateSelection(both, both);
1749 }
1750 
UpdateSelection(int32_t start,int32_t end)1751 void TextFieldPattern::UpdateSelection(int32_t start, int32_t end)
1752 {
1753     if (start != textSelector_.GetStart() || end != textSelector_.GetEnd()) {
1754         FireOnSelectionChange(start, end);
1755         textSelector_.Update(start, end);
1756     }
1757 }
1758 
FireOnSelectionChange(int32_t start,int32_t end)1759 void TextFieldPattern::FireOnSelectionChange(int32_t start, int32_t end)
1760 {
1761     auto host = GetHost();
1762     CHECK_NULL_VOID(host);
1763     auto eventHub = host->GetEventHub<TextFieldEventHub>();
1764     eventHub->FireOnSelectionChange(start, end);
1765 }
1766 
FireEventHubOnChange(const std::string & text)1767 void TextFieldPattern::FireEventHubOnChange(const std::string& text)
1768 {
1769     auto host = GetHost();
1770     CHECK_NULL_VOID(host);
1771     auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
1772     CHECK_NULL_VOID(layoutProperty);
1773     if (!layoutProperty->GetNeedFireOnChangeValue(false)) {
1774         return;
1775     }
1776     // If the parent node is a Search, the Search callback is executed.
1777     if (IsSearchParentNode()) {
1778         auto parentFrameNode = AceType::DynamicCast<FrameNode>(host->GetParent());
1779         auto eventHub = parentFrameNode->GetEventHub<SearchEventHub>();
1780         CHECK_NULL_VOID(eventHub);
1781         eventHub->UpdateChangeEvent(text);
1782         return;
1783     }
1784     auto pipeline = PipelineBase::GetCurrentContext();
1785     CHECK_NULL_VOID(pipeline);
1786     auto textFieldTheme = pipeline->GetTheme<TextFieldTheme>();
1787     CHECK_NULL_VOID(textFieldTheme);
1788     auto visible = layoutProperty->GetShowErrorTextValue(false);
1789     if (!visible && layoutProperty->GetShowUnderlineValue(false) &&
1790         layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED) == TextInputType::UNSPECIFIED) {
1791         underlineColor_ = textFieldTheme->GetUnderlineTypingColor();
1792         underlineWidth_ = TYPING_UNDERLINE_WIDTH;
1793     }
1794     if (IsTextArea() && layoutProperty->HasMaxLength()) {
1795         HandleCounterBorder();
1796     }
1797 
1798     auto eventHub = host->GetEventHub<TextFieldEventHub>();
1799     CHECK_NULL_VOID(eventHub);
1800     eventHub->FireOnChange(text);
1801 }
1802 
HandleTouchEvent(const TouchEventInfo & info)1803 void TextFieldPattern::HandleTouchEvent(const TouchEventInfo& info)
1804 {
1805     if (SelectOverlayIsOn()) {
1806         return;
1807     }
1808     auto touchType = info.GetTouches().front().GetTouchType();
1809     if (touchType == TouchType::DOWN) {
1810         HandleTouchDown(info.GetTouches().front().GetLocalLocation());
1811     } else if (touchType == TouchType::UP) {
1812         HandleTouchUp();
1813     }
1814 }
1815 
HandleTouchDown(const Offset & offset)1816 void TextFieldPattern::HandleTouchDown(const Offset& offset)
1817 {
1818     LOGI("HandleTouchDown");
1819     if (HasStateStyle(UI_STATE_PRESSED)) {
1820         return;
1821     }
1822     if (enableTouchAndHoverEffect_ && !isMousePressed_) {
1823         auto textfieldPaintProperty = GetPaintProperty<TextFieldPaintProperty>();
1824         CHECK_NULL_VOID(textfieldPaintProperty);
1825         auto tmpHost = GetHost();
1826         CHECK_NULL_VOID(tmpHost);
1827         auto renderContext = tmpHost->GetRenderContext();
1828         auto pipeline = PipelineContext::GetCurrentContext();
1829         CHECK_NULL_VOID(pipeline);
1830         auto textFieldTheme = pipeline->GetTheme<TextFieldTheme>();
1831         CHECK_NULL_VOID(textFieldTheme);
1832         auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
1833         CHECK_NULL_VOID(layoutProperty);
1834         if (layoutProperty->GetShowUnderlineValue(false) &&
1835             layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED) == TextInputType::UNSPECIFIED) {
1836             auto radius = textFieldTheme->GetBorderRadiusSize();
1837             renderContext->UpdateBorderRadius({ radius.GetX(), radius.GetY(), radius.GetY(), radius.GetX() });
1838         }
1839         tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1840     }
1841 }
1842 
HandleTouchUp()1843 void TextFieldPattern::HandleTouchUp()
1844 {
1845     LOGI("HandleTouchUp");
1846     if (isMousePressed_) {
1847         LOGI("TextFieldPattern::HandleTouchUp of mouse");
1848         isMousePressed_ = false;
1849     }
1850     if (enableTouchAndHoverEffect_ && !HasStateStyle(UI_STATE_PRESSED)) {
1851         auto tmpHost = GetHost();
1852         CHECK_NULL_VOID(tmpHost);
1853         auto renderContext = tmpHost->GetRenderContext();
1854         if (!isOnHover_) {
1855             auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
1856             CHECK_NULL_VOID(layoutProperty);
1857             if (layoutProperty->GetShowUnderlineValue(false) &&
1858                 layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED) == TextInputType::UNSPECIFIED) {
1859                 renderContext->UpdateBorderRadius(borderRadius_);
1860             }
1861             if (layoutProperty->GetShowUnderlineValue(false) && HasFocus() &&
1862                 layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED) == TextInputType::UNSPECIFIED) {
1863                 auto pipeline = PipelineBase::GetCurrentContext();
1864                 CHECK_NULL_VOID(pipeline);
1865                 auto textFieldTheme = pipeline->GetTheme<TextFieldTheme>();
1866                 CHECK_NULL_VOID(textFieldTheme);
1867                 auto radius = textFieldTheme->GetBorderRadiusSize();
1868                 renderContext->UpdateBorderRadius({ radius.GetX(), radius.GetY(), radius.GetY(), radius.GetX() });
1869             }
1870         }
1871     }
1872 }
1873 
1874 #ifdef ENABLE_DRAG_FRAMEWORK
GetThumbnailCallback()1875 std::function<void(Offset)> TextFieldPattern::GetThumbnailCallback()
1876 {
1877     auto callback = [weak = WeakClaim(this)](const Offset& point) {
1878         auto pattern = weak.Upgrade();
1879         CHECK_NULL_VOID(pattern);
1880         auto frameNode = pattern->GetHost();
1881         CHECK_NULL_VOID(frameNode);
1882         if (pattern->BetweenSelectedPosition(point)) {
1883             pattern->dragNode_ = TextDragPattern::CreateDragNode(frameNode);
1884             FrameNode::ProcessOffscreenNode(pattern->dragNode_);
1885         }
1886         auto gestureHub = frameNode->GetOrCreateGestureEventHub();
1887         CHECK_NULL_VOID(gestureHub);
1888         gestureHub->SetPixelMap(nullptr);
1889     };
1890     return callback;
1891 }
1892 
InitDragDropEvent()1893 void TextFieldPattern::InitDragDropEvent()
1894 {
1895     auto host = GetHost();
1896     CHECK_NULL_VOID(host);
1897     auto gestureHub = host->GetOrCreateGestureEventHub();
1898     CHECK_NULL_VOID(gestureHub);
1899     gestureHub->InitDragDropEvent();
1900     gestureHub->SetTextDraggable(true);
1901     auto callback = GetThumbnailCallback();
1902     gestureHub->SetThumbnailCallback(std::move(callback));
1903     auto eventHub = host->GetEventHub<EventHub>();
1904     CHECK_NULL_VOID(eventHub);
1905     auto onDragStart = [weakPtr = WeakClaim(this)](const RefPtr<OHOS::Ace::DragEvent>& event,
1906                            const std::string& extraParams) -> NG::DragDropInfo {
1907         NG::DragDropInfo itemInfo;
1908         auto pattern = weakPtr.Upgrade();
1909         CHECK_NULL_RETURN(pattern, itemInfo);
1910         auto host = pattern->GetHost();
1911         CHECK_NULL_RETURN(host, itemInfo);
1912         auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
1913         CHECK_NULL_RETURN(layoutProperty, itemInfo);
1914         pattern->dragStatus_ = DragStatus::DRAGGING;
1915         pattern->textFieldContentModifier_->ChangeDragStatus();
1916         pattern->selectionMode_ = SelectionMode::NONE;
1917         pattern->dragTextStart_ = std::min(pattern->textSelector_.GetStart(), pattern->textSelector_.GetEnd());
1918         pattern->dragTextEnd_ = std::max(pattern->textSelector_.GetStart(), pattern->textSelector_.GetEnd());
1919         auto textEditingValue = pattern->GetEditingValue();
1920         std::string beforeStr = textEditingValue.GetValueBeforePosition(pattern->dragTextStart_);
1921         std::string selectedStr = textEditingValue.GetSelectedText(pattern->dragTextStart_, pattern->dragTextEnd_);
1922         std::string afterStr = textEditingValue.GetValueAfterPosition(pattern->dragTextEnd_);
1923         pattern->dragContents_ = { beforeStr, selectedStr, afterStr };
1924         itemInfo.extraInfo = selectedStr;
1925         RefPtr<UnifiedData> unifiedData = UdmfClient::GetInstance()->CreateUnifiedData();
1926         UdmfClient::GetInstance()->AddPlainTextRecord(unifiedData, selectedStr);
1927         event->SetData(unifiedData);
1928         host->MarkDirtyNode(layoutProperty->GetMaxLinesValue(Infinity<float>()) <= 1 ? PROPERTY_UPDATE_MEASURE_SELF
1929                                                                                      : PROPERTY_UPDATE_MEASURE);
1930         return itemInfo;
1931     };
1932     if (!eventHub->HasOnDragStart()) {
1933         eventHub->SetOnDragStart(std::move(onDragStart));
1934     }
1935 
1936     auto onDragEnter = [weakPtr = WeakClaim(this)](
1937                            const RefPtr<OHOS::Ace::DragEvent>& event, const std::string& extraParams) {
1938         auto pattern = weakPtr.Upgrade();
1939         CHECK_NULL_VOID(pattern);
1940         if (pattern->dragStatus_ == DragStatus::ON_DROP) {
1941             pattern->dragStatus_ = DragStatus::NONE;
1942         }
1943 
1944         pattern->dragRecipientStatus_ = DragStatus::DRAGGING;
1945     };
1946     eventHub->SetOnDragEnter(std::move(onDragEnter));
1947 
1948     auto onDragMove = [weakPtr = WeakClaim(this)](
1949                           const RefPtr<OHOS::Ace::DragEvent>& event, const std::string& extraParams) {
1950         auto pattern = weakPtr.Upgrade();
1951         CHECK_NULL_VOID(pattern);
1952         auto touchX = event->GetX();
1953         auto touchY = event->GetY();
1954         Offset offset = Offset(touchX, touchY) - Offset(pattern->textRect_.GetX(), pattern->textRect_.GetY()) -
1955                         Offset(pattern->parentGlobalOffset_.GetX(), pattern->parentGlobalOffset_.GetY());
1956         auto position = pattern->ConvertTouchOffsetToCaretPosition(offset);
1957         auto host = pattern->GetHost();
1958         CHECK_NULL_VOID(host);
1959         auto focusHub = host->GetOrCreateFocusHub();
1960         if (pattern->IsSearchParentNode()) {
1961             auto parentFrameNode = AceType::DynamicCast<FrameNode>(host->GetParent());
1962             focusHub = parentFrameNode->GetOrCreateFocusHub();
1963         }
1964         focusHub->RequestFocusImmediately();
1965         pattern->SetCaretPosition(position);
1966         pattern->StartTwinkling();
1967     };
1968     eventHub->SetOnDragMove(std::move(onDragMove));
1969 
1970     auto onDragLeave = [weakPtr = WeakClaim(this)](
1971                            const RefPtr<OHOS::Ace::DragEvent>& event, const std::string& extraParams) {
1972         auto pattern = weakPtr.Upgrade();
1973         CHECK_NULL_VOID(pattern);
1974         pattern->StopTwinkling();
1975         pattern->dragRecipientStatus_ = DragStatus::NONE;
1976     };
1977     eventHub->SetOnDragLeave(std::move(onDragLeave));
1978 
1979     auto onDragEnd = [weakPtr = WeakClaim(this), id = Container::CurrentId()](
1980                          const RefPtr<OHOS::Ace::DragEvent>& event) {
1981         ContainerScope scope(id);
1982         auto pattern = weakPtr.Upgrade();
1983         CHECK_NULL_VOID(pattern);
1984         LOGD("TextFieldPattern  onDragEnd result: %{public}d dragStatus: %{public}d", event->GetResult(),
1985             pattern->dragStatus_);
1986         if (pattern->dragStatus_ == DragStatus::DRAGGING) {
1987             pattern->dragStatus_ = DragStatus::NONE;
1988             pattern->MarkContentChange();
1989             auto host = pattern->GetHost();
1990             CHECK_NULL_VOID(host);
1991             auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
1992             CHECK_NULL_VOID(layoutProperty);
1993             host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1994         }
1995     };
1996     eventHub->SetOnDragEnd(std::move(onDragEnd));
1997 
1998     auto onDrop = [weakPtr = WeakClaim(this)](
1999                       const RefPtr<OHOS::Ace::DragEvent>& event, const std::string& extraParams) {
2000         auto pattern = weakPtr.Upgrade();
2001         CHECK_NULL_VOID(pattern);
2002         auto host = pattern->GetHost();
2003         CHECK_NULL_VOID(host);
2004         if (extraParams.empty()) {
2005             pattern->dragStatus_ = DragStatus::ON_DROP;
2006             pattern->textFieldContentModifier_->ChangeDragStatus();
2007             auto host = pattern->GetHost();
2008             CHECK_NULL_VOID(host);
2009             auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
2010             CHECK_NULL_VOID(layoutProperty);
2011             host->MarkDirtyNode(layoutProperty->GetMaxLinesValue(Infinity<float>()) <= 1 ? PROPERTY_UPDATE_MEASURE_SELF
2012                                                                                          : PROPERTY_UPDATE_MEASURE);
2013             return;
2014         }
2015         auto data = event->GetData();
2016         CHECK_NULL_VOID(data);
2017         auto records = UdmfClient::GetInstance()->GetPlainTextRecords(data);
2018         std::string str = "";
2019         for (const auto& record : records) {
2020             str += record;
2021         }
2022         pattern->needToRequestKeyboardInner_ = true;
2023         pattern->dragRecipientStatus_ = DragStatus::NONE;
2024         if (str.empty()) {
2025             return;
2026         }
2027         if (pattern->dragStatus_ == DragStatus::NONE) {
2028             pattern->InsertValue(str);
2029         } else {
2030             auto current = pattern->textEditingValue_.caretPosition;
2031             float dragTextStart = pattern->dragTextStart_;
2032             float dragTextEnd = pattern->dragTextEnd_;
2033             if (current < dragTextStart) {
2034                 pattern->textEditingValue_.text = pattern->textEditingValue_.GetValueBeforePosition(dragTextStart) +
2035                                                   pattern->textEditingValue_.GetValueAfterPosition(dragTextEnd);
2036                 pattern->InsertValue(str);
2037             } else if (current > dragTextEnd) {
2038                 pattern->textEditingValue_.text = pattern->textEditingValue_.GetValueBeforePosition(dragTextStart) +
2039                                                   pattern->textEditingValue_.GetValueAfterPosition(dragTextEnd);
2040                 pattern->textEditingValue_.caretPosition = current - (dragTextEnd - dragTextStart);
2041                 pattern->InsertValue(str);
2042             }
2043             pattern->dragStatus_ = DragStatus::NONE;
2044             pattern->MarkContentChange();
2045             host->MarkDirtyNode(pattern->IsTextArea() ? PROPERTY_UPDATE_MEASURE : PROPERTY_UPDATE_MEASURE_SELF);
2046         }
2047     };
2048     eventHub->SetOnDrop(std::move(onDrop));
2049 }
2050 
ClearDragDropEvent()2051 void TextFieldPattern::ClearDragDropEvent()
2052 {
2053     auto host = GetHost();
2054     CHECK_NULL_VOID(host);
2055     auto gestureHub = host->GetOrCreateGestureEventHub();
2056     CHECK_NULL_VOID(gestureHub);
2057     gestureHub->SetTextDraggable(false);
2058     auto eventHub = host->GetEventHub<EventHub>();
2059     CHECK_NULL_VOID(eventHub);
2060     eventHub->SetOnDragStart(nullptr);
2061     eventHub->SetOnDragEnter(nullptr);
2062     eventHub->SetOnDragMove(nullptr);
2063     eventHub->SetOnDragLeave(nullptr);
2064     eventHub->SetOnDragEnd(nullptr);
2065     eventHub->SetOnDrop(nullptr);
2066 }
2067 #endif
2068 
InitTouchEvent()2069 void TextFieldPattern::InitTouchEvent()
2070 {
2071     CHECK_NULL_VOID_NOLOG(!touchListener_);
2072     auto host = GetHost();
2073     CHECK_NULL_VOID(host);
2074 
2075     auto gesture = host->GetOrCreateGestureEventHub();
2076     CHECK_NULL_VOID(gesture);
2077     auto touchTask = [weak = WeakClaim(this)](const TouchEventInfo& info) {
2078         auto pattern = weak.Upgrade();
2079         CHECK_NULL_VOID_NOLOG(pattern);
2080         pattern->HandleTouchEvent(info);
2081     };
2082     touchListener_ = MakeRefPtr<TouchEventImpl>(std::move(touchTask));
2083     gesture->AddTouchEvent(touchListener_);
2084 }
2085 
InitClickEvent()2086 void TextFieldPattern::InitClickEvent()
2087 {
2088     CHECK_NULL_VOID_NOLOG(!clickListener_);
2089     auto tmpHost = GetHost();
2090     CHECK_NULL_VOID(tmpHost);
2091     auto gesture = tmpHost->GetOrCreateGestureEventHub();
2092     auto clickCallback = [weak = WeakClaim(this)](GestureEvent& info) {
2093         auto pattern = weak.Upgrade();
2094         CHECK_NULL_VOID(pattern);
2095         pattern->HandleClickEvent(info);
2096     };
2097 
2098     clickListener_ = MakeRefPtr<ClickEvent>(std::move(clickCallback));
2099     gesture->AddClickEvent(clickListener_);
2100 }
2101 
HandleClickEvent(GestureEvent & info)2102 void TextFieldPattern::HandleClickEvent(GestureEvent& info)
2103 {
2104     LOGI("TextFieldPattern::HandleClickEvent");
2105     auto host = GetHost();
2106     CHECK_NULL_VOID(host);
2107     auto context = host->GetContext();
2108     CHECK_NULL_VOID(context);
2109     auto globalOffset = host->GetPaintRectOffset() - context->GetRootRect().GetOffset();
2110     // emulate clicking bottom of the textField
2111     UpdateTextFieldManager(Offset(globalOffset.GetX(), globalOffset.GetY()), frameRect_.Height());
2112     auto focusHub = host->GetOrCreateFocusHub();
2113 
2114     if (IsSearchParentNode()) {
2115         auto parentFrameNode = AceType::DynamicCast<FrameNode>(host->GetParent());
2116         focusHub = parentFrameNode->GetOrCreateFocusHub();
2117     }
2118 
2119     if (!focusHub->IsFocusable()) {
2120         LOGI("Textfield %{public}d is not focusable ,cannot request keyboard", host->GetId());
2121         return;
2122     }
2123     lastTouchOffset_ = info.GetLocalLocation();
2124     isTouchAtLeftOffset_ = IsTouchAtLeftOffset(lastTouchOffset_.GetX());
2125     caretUpdateType_ = CaretUpdateType::PRESSED;
2126     isFocusedBeforeClick_ = HasFocus();
2127     selectionMode_ = SelectionMode::NONE;
2128     isUsingMouse_ = false;
2129     CloseSelectOverlay(true);
2130     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
2131     if (lastTouchOffset_.GetX() > frameRect_.Width() - imageRect_.Width() - GetIconRightOffset() &&
2132         NeedShowPasswordIcon()) {
2133         LOGI("Password Icon pressed, change text to be shown only");
2134         textObscured_ = !textObscured_;
2135         ProcessPasswordIcon();
2136         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
2137         caretUpdateType_ = CaretUpdateType::ICON_PRESSED;
2138         return;
2139     }
2140     ResetObscureTickCountDown();
2141     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
2142     StartTwinkling();
2143 
2144     if (isMousePressed_) {
2145         LOGI("TextFieldPattern::HandleTouchUp of mouse");
2146         isMousePressed_ = false;
2147         return;
2148     }
2149     if (!focusHub->IsFocusOnTouch().value_or(true) || !focusHub->RequestFocusImmediately()) {
2150         LOGE("Request focus failed, cannot open input method");
2151         StopTwinkling();
2152         return;
2153     }
2154     if (RequestKeyboard(false, true, true)) {
2155         auto eventHub = host->GetEventHub<TextFieldEventHub>();
2156         CHECK_NULL_VOID(eventHub);
2157         eventHub->FireOnEditChanged(true);
2158     }
2159 }
2160 
ScheduleCursorTwinkling()2161 void TextFieldPattern::ScheduleCursorTwinkling()
2162 {
2163     if (isTransparent_) {
2164         return;
2165     }
2166     auto host = GetHost();
2167     CHECK_NULL_VOID(host);
2168     auto context = host->GetContext();
2169     CHECK_NULL_VOID(context);
2170 
2171     if (!context->GetTaskExecutor()) {
2172         LOGW("context has no task executor.");
2173         return;
2174     }
2175 
2176     auto weak = WeakClaim(this);
2177     cursorTwinklingTask_.Reset([weak] {
2178         auto client = weak.Upgrade();
2179         CHECK_NULL_VOID_NOLOG(client);
2180         client->OnCursorTwinkling();
2181     });
2182     auto taskExecutor = context->GetTaskExecutor();
2183     CHECK_NULL_VOID(taskExecutor);
2184     taskExecutor->PostDelayedTask(cursorTwinklingTask_, TaskExecutor::TaskType::UI, twinklingInterval_);
2185 }
2186 
StartTwinkling()2187 void TextFieldPattern::StartTwinkling()
2188 {
2189     if (isTransparent_) {
2190         return;
2191     }
2192     // Ignore the result because all ops are called on this same thread (ACE UI).
2193     // The only reason failed is that the task has finished.
2194     cursorTwinklingTask_.Cancel();
2195 
2196     // Show cursor right now.
2197     cursorVisible_ = true;
2198     auto tmpHost = GetHost();
2199     CHECK_NULL_VOID(tmpHost);
2200     tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2201     ScheduleCursorTwinkling();
2202 }
2203 
OnCursorTwinkling()2204 void TextFieldPattern::OnCursorTwinkling()
2205 {
2206     cursorTwinklingTask_.Cancel();
2207     cursorVisible_ = !cursorVisible_;
2208     auto shouldMeasure = !IsTextArea() && IsInPasswordMode() && GetTextObscured() && obscureTickCountDown_ == 1;
2209     if (IsInPasswordMode() && GetTextObscured() && obscureTickCountDown_ > 0) {
2210         --obscureTickCountDown_;
2211     }
2212     auto tmpHost = GetHost();
2213     CHECK_NULL_VOID(tmpHost);
2214     if (shouldMeasure) {
2215         caretUpdateType_ = CaretUpdateType::EVENT;
2216         tmpHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
2217     } else {
2218         tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2219     }
2220     ScheduleCursorTwinkling();
2221 }
2222 
StopTwinkling()2223 void TextFieldPattern::StopTwinkling()
2224 {
2225     cursorTwinklingTask_.Cancel();
2226 
2227     // Repaint only if cursor is visible for now.
2228     auto tmpHost = GetHost();
2229     CHECK_NULL_VOID(tmpHost);
2230     if (cursorVisible_) {
2231         cursorVisible_ = false;
2232         tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2233     }
2234     if (ResetObscureTickCountDown()) {
2235         tmpHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
2236     }
2237 }
2238 
CheckIfNeedToResetKeyboard()2239 void TextFieldPattern::CheckIfNeedToResetKeyboard()
2240 {
2241     auto tmpHost = GetHost();
2242     CHECK_NULL_VOID(tmpHost);
2243     auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
2244     CHECK_NULL_VOID(layoutProperty);
2245     bool needToResetKeyboard = false;
2246     // check unspecified  for first time entrance
2247     if (keyboard_ != layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED)) {
2248         LOGI("Keyboard type changed to %{public}d", layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED));
2249         keyboard_ = layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED);
2250         needToResetKeyboard = true;
2251     }
2252     if (!needToResetKeyboard && action_ != TextInputAction::UNSPECIFIED) {
2253         needToResetKeyboard = action_ != GetTextInputActionValue(TextInputAction::DONE);
2254     }
2255     action_ = GetTextInputActionValue(TextInputAction::DONE);
2256     LOGI("Keyboard action is %{public}d", action_);
2257 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
2258     // if keyboard attached and keyboard is shown, pull up keyboard again
2259     if (needToResetKeyboard && imeAttached_ && imeShown_) {
2260         CloseKeyboard(true);
2261         RequestKeyboard(false, true, true);
2262     }
2263 #else
2264     if (needToResetKeyboard && HasConnection()) {
2265         CloseKeyboard(true);
2266         RequestKeyboard(false, true, true);
2267     }
2268 #endif
2269 }
2270 
OnModifyDone()2271 void TextFieldPattern::OnModifyDone()
2272 {
2273     Pattern::OnModifyDone();
2274     auto host = GetHost();
2275     CHECK_NULL_VOID(host);
2276     auto context = host->GetContext();
2277     CHECK_NULL_VOID(context);
2278     instanceId_ = context->GetInstanceId();
2279     auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
2280     CHECK_NULL_VOID(layoutProperty);
2281     auto pipeline = PipelineBase::GetCurrentContext();
2282     CHECK_NULL_VOID(pipeline);
2283     auto textFieldTheme = pipeline->GetTheme<TextFieldTheme>();
2284     CHECK_NULL_VOID(textFieldTheme);
2285     CheckIfNeedToResetKeyboard();
2286     if (layoutProperty->GetShowUnderlineValue(false) &&
2287         layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED) == TextInputType::UNSPECIFIED) {
2288         underlineWidth_ = UNDERLINE_WIDTH;
2289         underlineColor_ = IsDisabled() ? textFieldTheme->GetDisableUnderlineColor()
2290                                        : textFieldTheme->GetUnderlineColor();
2291         SaveUnderlineStates();
2292     }
2293     auto renderContext = host->GetRenderContext();
2294     CHECK_NULL_VOID(renderContext);
2295     isTransparent_ = renderContext->GetOpacityValue(1.0f) == 0.0f;
2296     if (!preErrorState_ && !restoreMarginState_) {
2297         SavePasswordModeStates();
2298     }
2299     InitClickEvent();
2300     InitLongPressEvent();
2301     InitFocusEvent();
2302     InitMouseEvent();
2303     InitTouchEvent();
2304     SetAccessibilityAction();
2305     FilterExistText();
2306 #ifdef ENABLE_DRAG_FRAMEWORK
2307     if (layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED) != TextInputType::VISIBLE_PASSWORD) {
2308         InitDragDropEvent();
2309         AddDragFrameNodeToManager(host);
2310     } else {
2311         ClearDragDropEvent();
2312         RemoveDragFrameNodeFromManager(host);
2313     }
2314 #endif // ENABLE_DRAG_FRAMEWORK
2315     ProcessPasswordIcon();
2316     context->AddOnAreaChangeNode(host->GetId());
2317     if (!clipboard_ && context) {
2318         clipboard_ = ClipboardProxy::GetInstance()->GetClipboard(context->GetTaskExecutor());
2319     }
2320     if (barState_.has_value() && barState_.value() != layoutProperty->GetDisplayModeValue(DisplayMode::AUTO) &&
2321         HasFocus() && IsNormalInlineState()) {
2322         lastTextRectY_ = textRect_.GetY();
2323     }
2324     ProcessInnerPadding();
2325     textRect_.SetLeft(textRect_.GetX() + offsetDifference_.GetX());
2326     textRect_.SetTop(textRect_.GetY() + offsetDifference_.GetY());
2327     CalculateDefaultCursor();
2328     auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
2329     CHECK_NULL_VOID(paintProperty);
2330     if (renderContext->HasBackgroundColor()) {
2331         paintProperty->UpdateBackgroundColor(renderContext->GetBackgroundColorValue());
2332     }
2333     auto textWidth = static_cast<int32_t>(textEditingValue_.GetWideText().length());
2334     if (SelectOverlayIsOn()) {
2335         needToRefreshSelectOverlay_ = true;
2336         UpdateSelection(
2337             std::clamp(textSelector_.GetStart(), 0, textWidth), std::clamp(textSelector_.GetEnd(), 0, textWidth));
2338         UpdateCaretPositionWithClamp(textSelector_.GetEnd());
2339         if (!textSelector_.StartEqualToDest()) {
2340             selectionMode_ = SelectionMode::SELECT;
2341         }
2342     }
2343     if (layoutProperty->GetTypeChangedValue(false)) {
2344         layoutProperty->ResetTypeChanged();
2345         operationRecords_.clear();
2346         redoOperationRecords_.clear();
2347     }
2348     auto maxLength = GetMaxLength();
2349     if (GreatNotEqual(textWidth, maxLength)) {
2350         textEditingValue_.text = StringUtils::ToString(textEditingValue_.GetWideText().substr(0, maxLength));
2351         UpdateCaretPositionWithClamp(textEditingValue_.caretPosition);
2352         SetEditingValueToProperty(textEditingValue_.text);
2353         auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
2354         CHECK_NULL_VOID(layoutProperty);
2355         layoutProperty->UpdateNeedFireOnChange(true);
2356     }
2357     FireOnChangeIfNeeded();
2358     if (IsTextArea() || IsNormalInlineState()) {
2359         SetAxis(Axis::VERTICAL);
2360         if (!GetScrollableEvent()) {
2361             AddScrollEvent();
2362         }
2363         auto barState = layoutProperty->GetDisplayModeValue(DisplayMode::AUTO);
2364         if (!barState_.has_value()) {
2365             barState_ = barState;
2366         }
2367         scrollBarVisible_ = true;
2368         if (barState == DisplayMode::OFF) {
2369             scrollBarVisible_ = false;
2370         }
2371         SetScrollBar(barState == DisplayMode::OFF ? DisplayMode::ON : barState);
2372         auto scrollBar = GetScrollBar();
2373         if (scrollBar) {
2374             scrollBar->SetMinHeight(SCROLL_BAR_MIN_HEIGHT);
2375             scrollBar->SetStartReservedHeight(0.0_px);
2376             scrollBar->SetEndReservedHeight(0.0_px);
2377         }
2378         if (textFieldOverlayModifier_) {
2379             textFieldOverlayModifier_->SetScrollBar(scrollBar);
2380             UpdateScrollBarOffset();
2381             MarkRedrawOverlay();
2382         }
2383     } else {
2384         SetAxis(Axis::HORIZONTAL);
2385         if (!GetScrollableEvent()) {
2386             AddScrollEvent();
2387             SetScrollEnable(false);
2388         }
2389     }
2390     if (!IsNormalInlineState() && !IsDisabled()) {
2391         SetShowError();
2392     }
2393     if (IsTextArea() && layoutProperty->HasMaxLength()) {
2394         if (setBorderFlag_) {
2395             auto pipeline = PipelineContext::GetCurrentContext();
2396             CHECK_NULL_VOID(pipeline);
2397             auto themeManager = pipeline->GetThemeManager();
2398             CHECK_NULL_VOID(themeManager);
2399             auto textFieldTheme = themeManager->GetTheme<TextFieldTheme>();
2400             lastDiffBorderColor_.SetColor(textFieldTheme->GetOverCountBorderColor());
2401             lastDiffBorderWidth_.SetBorderWidth(OVER_COUNT_BORDER_WIDTH);
2402             setBorderFlag_ = false;
2403         }
2404         HandleCounterBorder();
2405     }
2406     if (!IsTextArea()) {
2407         isTextInput_ = true;
2408     }
2409     auto inputStyle = paintProperty->GetInputStyleValue(InputStyle::DEFAULT);
2410     if (!inlineState_.saveInlineState) {
2411         inlineState_.saveInlineState = false;
2412         SaveInlineStates();
2413     }
2414     if (!HasFocus() && inlineState_.saveInlineState) {
2415         SaveInlineStates();
2416     }
2417     if (HasFocus() && IsNormalInlineState()) {
2418         preInputStyle_ == InputStyle::DEFAULT ? ApplyInlineStates(true) : ApplyInlineStates(false);
2419     }
2420     if (layoutProperty->GetShowUnderlineValue(false) &&
2421         (layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED) == TextInputType::UNSPECIFIED ||
2422         layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED) == TextInputType::TEXT)) {
2423         ApplyUnderlineStates();
2424     }
2425     if (preInputStyle_ == InputStyle::INLINE && inputStyle == InputStyle::DEFAULT &&
2426         (layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED) == TextInputType::UNSPECIFIED ||
2427         layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED) == TextInputType::TEXT)) {
2428         if (IsTextArea() && isTextInput_) {
2429             layoutProperty->UpdateMaxLines(1);
2430         }
2431         inlineSelectAllFlag_ = false;
2432         inlineFocusState_ = false;
2433         RestorePreInlineStates();
2434     }
2435     preInputStyle_ = inputStyle;
2436 }
2437 
CalculateDefaultCursor()2438 void TextFieldPattern::CalculateDefaultCursor()
2439 {
2440     auto tmpHost = GetHost();
2441     CHECK_NULL_VOID(tmpHost);
2442     auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
2443     CHECK_NULL_VOID(layoutProperty);
2444     auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
2445     CHECK_NULL_VOID(paintProperty);
2446     float caretWidth = paintProperty->GetCursorWidth().has_value()
2447                            ? static_cast<float>(paintProperty->GetCursorWidthValue().ConvertToPx())
2448                            : static_cast<float>(CURSOR_WIDTH.ConvertToPx());
2449     caretRect_.SetWidth(caretWidth);
2450     if (textEditingValue_.caretPosition != 0) {
2451         return;
2452     }
2453     caretRect_.SetLeft(GetPaddingLeft());
2454     caretRect_.SetTop(GetPaddingTop());
2455     caretRect_.SetHeight(PreferredLineHeight());
2456     CHECK_NULL_VOID(layoutProperty->GetCalcLayoutConstraint());
2457     CHECK_NULL_VOID(layoutProperty->GetCalcLayoutConstraint()->selfIdealSize.has_value());
2458     CHECK_NULL_VOID(layoutProperty->GetCalcLayoutConstraint()->selfIdealSize.value().Height().has_value());
2459     auto alignment = layoutProperty->GetPositionProperty()
2460                          ? layoutProperty->GetPositionProperty()->GetAlignment().value_or(Alignment::CENTER)
2461                          : Alignment::CENTER;
2462     auto idealHeight = layoutProperty->GetCalcLayoutConstraint()->selfIdealSize.value().Height().value();
2463     caretRect_.SetTop(
2464         (1.0 + alignment.GetVertical()) * (idealHeight.GetDimension().ConvertToPx() - PreferredLineHeight()) / 2.0);
2465 }
2466 
FireOnChangeIfNeeded()2467 void TextFieldPattern::FireOnChangeIfNeeded()
2468 {
2469     auto tmpHost = GetHost();
2470     CHECK_NULL_VOID(tmpHost);
2471     auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
2472     CHECK_NULL_VOID(layoutProperty);
2473     if (!layoutProperty->GetNeedFireOnChangeValue(false)) {
2474         return;
2475     }
2476     layoutProperty->UpdateNeedFireOnChange(false);
2477     auto eventHub = tmpHost->GetEventHub<TextFieldEventHub>();
2478     CHECK_NULL_VOID(eventHub);
2479     eventHub->FireOnChange(textEditingValue_.text);
2480 }
2481 
IsDisabled()2482 bool TextFieldPattern::IsDisabled()
2483 {
2484     auto tmpHost = GetHost();
2485     CHECK_NULL_RETURN(tmpHost, true);
2486     auto eventHub = tmpHost->GetEventHub<TextFieldEventHub>();
2487     CHECK_NULL_RETURN(eventHub, true);
2488     auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
2489     CHECK_NULL_RETURN(layoutProperty, true);
2490     auto pipeline = PipelineBase::GetCurrentContext();
2491     CHECK_NULL_RETURN(pipeline, true);
2492     auto theme = pipeline->GetTheme<TextFieldTheme>();
2493     CHECK_NULL_RETURN(theme, true);
2494     if (!eventHub->IsEnabled()) {
2495         layoutProperty->UpdateTextColor(theme->GetDisableTextColor());
2496     }
2497     return !eventHub->IsEnabled();
2498 }
2499 
ProcessInnerPadding()2500 void TextFieldPattern::ProcessInnerPadding()
2501 {
2502     auto tmpHost = GetHost();
2503     CHECK_NULL_VOID(tmpHost);
2504     auto pipeline = tmpHost->GetContext();
2505     CHECK_NULL_VOID(pipeline);
2506     auto themeManager = pipeline->GetThemeManager();
2507     CHECK_NULL_VOID(themeManager);
2508     auto textFieldTheme = themeManager->GetTheme<TextFieldTheme>();
2509     CHECK_NULL_VOID(textFieldTheme);
2510     auto themePadding = textFieldTheme->GetPadding();
2511     auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
2512     CHECK_NULL_VOID(layoutProperty);
2513 
2514     BorderWidthProperty currentBorderWidth;
2515     if (layoutProperty->GetBorderWidthProperty() != nullptr) {
2516         currentBorderWidth = *(layoutProperty->GetBorderWidthProperty());
2517     } else {
2518         currentBorderWidth.SetBorderWidth(BORDER_DEFAULT_WIDTH);
2519     }
2520     auto& paddingProperty = layoutProperty->GetPaddingProperty();
2521     auto left = !paddingProperty
2522                     ? CalcLength(themePadding.Left()).GetDimension().ConvertToPx()
2523                     : paddingProperty->left.value_or(CalcLength(themePadding.Left())).GetDimension().ConvertToPx();
2524     offsetDifference_.SetX(left + (float)currentBorderWidth.leftDimen->ConvertToPx() - GetPaddingLeft() -
2525                            GetBorderLeft());
2526     if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
2527         offsetDifference_.SetX(left - GetPaddingLeft());
2528     }
2529     utilPadding_.left = left;
2530     auto top = !paddingProperty
2531                    ? CalcLength(themePadding.Top()).GetDimension().ConvertToPx()
2532                    : paddingProperty->top.value_or(CalcLength(themePadding.Top())).GetDimension().ConvertToPx();
2533     offsetDifference_.SetY(top + (float)currentBorderWidth.topDimen->ConvertToPx() - GetPaddingTop() -
2534                            GetBorderTop());
2535     if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
2536         offsetDifference_.SetY(top - GetPaddingTop());
2537     }
2538     utilPadding_.top = top;
2539     utilPadding_.bottom =
2540         !paddingProperty
2541             ? CalcLength(themePadding.Bottom()).GetDimension().ConvertToPx()
2542             : paddingProperty->bottom.value_or(CalcLength(themePadding.Bottom())).GetDimension().ConvertToPx();
2543     utilPadding_.right =
2544         !paddingProperty
2545             ? CalcLength(themePadding.Right()).GetDimension().ConvertToPx()
2546             : paddingProperty->right.value_or(CalcLength(themePadding.Right())).GetDimension().ConvertToPx();
2547     lastBorderWidth_ = currentBorderWidth;
2548 }
2549 
InitLongPressEvent()2550 void TextFieldPattern::InitLongPressEvent()
2551 {
2552     CHECK_NULL_VOID_NOLOG(!longPressEvent_);
2553     auto tmpHost = GetHost();
2554     CHECK_NULL_VOID(tmpHost);
2555     auto gesture = tmpHost->GetOrCreateGestureEventHub();
2556     auto longPressCallback = [weak = WeakClaim(this)](GestureEvent& info) {
2557         auto pattern = weak.Upgrade();
2558         CHECK_NULL_VOID(pattern);
2559         pattern->HandleLongPress(info);
2560     };
2561     longPressEvent_ = MakeRefPtr<LongPressEvent>(std::move(longPressCallback));
2562     gesture->SetLongPressEvent(longPressEvent_);
2563 
2564     auto onTextSelectorChange = [weak = WeakClaim(this)]() {
2565         auto pattern = weak.Upgrade();
2566         CHECK_NULL_VOID(pattern);
2567         auto frameNode = pattern->GetHost();
2568         CHECK_NULL_VOID(frameNode);
2569         frameNode->OnAccessibilityEvent(AccessibilityEventType::TEXT_SELECTION_UPDATE);
2570     };
2571     textSelector_.SetOnAccessibility(std::move(onTextSelectorChange));
2572 }
2573 
HandleLongPress(GestureEvent & info)2574 void TextFieldPattern::HandleLongPress(GestureEvent& info)
2575 {
2576     auto host = GetHost();
2577     CHECK_NULL_VOID(host);
2578     lastTouchOffset_ = info.GetLocalLocation();
2579     auto hub = host->GetEventHub<EventHub>();
2580     CHECK_NULL_VOID(hub);
2581     auto gestureHub = hub->GetOrCreateGestureEventHub();
2582     CHECK_NULL_VOID(gestureHub);
2583     if (BetweenSelectedPosition(info.GetGlobalLocation())) {
2584 #ifdef ENABLE_DRAG_FRAMEWORK
2585         gestureHub->SetIsTextDraggable(true);
2586 #endif
2587         return;
2588     }
2589 #ifdef ENABLE_DRAG_FRAMEWORK
2590     gestureHub->SetIsTextDraggable(false);
2591 #endif
2592     caretUpdateType_ = (isMousePressed_ || !HasFocus()) ? CaretUpdateType::PRESSED : CaretUpdateType::LONG_PRESSED;
2593     isSingleHandle_ = false;
2594     isUsingMouse_ = false;
2595     ResetObscureTickCountDown();
2596     LOGI("TextField %{public}d handle long press", host->GetId());
2597     auto focusHub = host->GetOrCreateFocusHub();
2598     CloseSelectOverlay(true);
2599     if (IsSearchParentNode()) {
2600         auto parentFrameNode = AceType::DynamicCast<FrameNode>(host->GetParent());
2601         focusHub = parentFrameNode->GetOrCreateFocusHub();
2602     }
2603 
2604     if (!focusHub->IsFocusOnTouch().value_or(true) || !focusHub->RequestFocusImmediately()) {
2605         LOGE("Long press request focus failed");
2606         StopTwinkling();
2607         return;
2608     }
2609     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
2610 }
2611 
UpdateSelectorByPosition(const int32_t & pos)2612 void TextFieldPattern::UpdateSelectorByPosition(const int32_t& pos)
2613 {
2614     CHECK_NULL_VOID(paragraph_);
2615     int32_t start = 0;
2616     int32_t end = 0;
2617     GetWordBoundaryPositon(pos, start, end);
2618     textSelector_.Update(start, end);
2619     if (textEditingValue_.caretPosition != end) {
2620         textEditingValue_.caretPosition = end;
2621     }
2622 }
2623 
GetGraphemeClusterLength(const std::wstring & text,int32_t extend,bool checkPrev)2624 int32_t TextFieldPattern::GetGraphemeClusterLength(const std::wstring& text, int32_t extend, bool checkPrev)
2625 {
2626     char16_t aroundChar = 0;
2627     if (checkPrev) {
2628         if (static_cast<size_t>(extend) <= text.length()) {
2629             aroundChar = text[std::max(0, extend - 1)];
2630         }
2631     } else {
2632         if (static_cast<size_t>(extend) <= (text.length())) {
2633             aroundChar = text[std::min(static_cast<int32_t>(text.length() - 1), extend)];
2634         }
2635     }
2636     return StringUtils::NotInUtf16Bmp(aroundChar) ? 2 : 1;
2637 }
2638 
UpdateCaretPositionWithClamp(const int32_t & pos)2639 void TextFieldPattern::UpdateCaretPositionWithClamp(const int32_t& pos)
2640 {
2641     textEditingValue_.caretPosition =
2642         std::clamp(pos, 0, static_cast<int32_t>(GetEditingValue().GetWideText().length()));
2643 }
2644 
ProcessOverlay(bool animation)2645 void TextFieldPattern::ProcessOverlay(bool animation)
2646 {
2647     if (caretUpdateType_ != CaretUpdateType::RIGHT_CLICK) {
2648         StopTwinkling();
2649     }
2650     if (textEditingValue_.text.empty()) {
2651         CreateSingleHandle(animation);
2652         return;
2653     }
2654     if (caretUpdateType_ == CaretUpdateType::LONG_PRESSED) {
2655         // When the content length is 1, you need to use the TextBox and pressing coordinates to determine whether it is
2656         // selected
2657         if (textEditingValue_.text.length() == 1) {
2658             std::vector<RSTypographyProperties::TextBox> box;
2659             GetTextRectsInRange(0, 1, box);
2660             if (LastTouchIsInSelectRegion(box)) {
2661                 UpdateSelection(0, 1);
2662                 textEditingValue_.CursorMoveToPosition(1);
2663                 CreateHandles(animation);
2664                 return;
2665             }
2666         }
2667         if (textEditingValue_.caretPosition == 0 && GetLastTouchOffset().GetX() < textRect_.GetX()) {
2668             UpdateSelection(0);
2669             CreateSingleHandle(animation);
2670             return;
2671         } else if (textEditingValue_.CaretAtLast() && GetLastTouchOffset().GetX() > textRect_.GetX()) {
2672             UpdateSelection(textEditingValue_.caretPosition);
2673             CreateSingleHandle(animation);
2674             return;
2675         } else {
2676             UpdateSelectorByPosition(textEditingValue_.caretPosition);
2677         }
2678         if (!textSelector_.StartEqualToDest()) {
2679             FireOnSelectionChange(textSelector_.GetStart(), textSelector_.GetEnd());
2680             selectionMode_ = SelectionMode::SELECT;
2681         }
2682     }
2683     CreateHandles(animation);
2684 }
2685 
CreateHandles()2686 void TextFieldPattern::CreateHandles()
2687 {
2688     CreateHandles(false);
2689 }
2690 
CreateHandles(bool animation)2691 void TextFieldPattern::CreateHandles(bool animation)
2692 {
2693     std::vector<RSTypographyProperties::TextBox> tmp;
2694     MarkRedrawOverlay();
2695     GetTextRectsInRange(textSelector_.GetStart(), textSelector_.GetEnd(), tmp);
2696     auto firstHandlePosition = CalcCursorOffsetByPosition(textSelector_.GetStart());
2697     OffsetF firstHandleOffset(firstHandlePosition.offset.GetX() + parentGlobalOffset_.GetX(),
2698         firstHandlePosition.offset.GetY() + parentGlobalOffset_.GetY());
2699     textSelector_.firstHandleOffset_ = firstHandleOffset;
2700     auto secondHandlePosition = CalcCursorOffsetByPosition(textSelector_.GetEnd(), false);
2701     OffsetF secondHandleOffset(secondHandlePosition.offset.GetX() + parentGlobalOffset_.GetX(),
2702         secondHandlePosition.offset.GetY() + parentGlobalOffset_.GetY());
2703     textSelector_.secondHandleOffset_ = secondHandleOffset;
2704     SizeF handlePaintSize = { SelectHandleInfo::GetDefaultLineWidth().ConvertToPx(), caretRect_.Height() };
2705     std::optional<RectF> firstHandle = RectF(firstHandleOffset, handlePaintSize);
2706     std::optional<RectF> secondHandle = RectF(secondHandleOffset, handlePaintSize);
2707     LOGD("First handle %{public}s, second handle %{public}s", firstHandle->ToString().c_str(),
2708         secondHandle->ToString().c_str());
2709     CheckHandles(firstHandle, secondHandle);
2710     ShowSelectOverlay(firstHandle, secondHandle, animation);
2711     textBoxes_ = tmp;
2712 }
2713 
ShowSelectOverlay(const std::optional<RectF> & firstHandle,const std::optional<RectF> & secondHandle,bool animation,bool isMenuShow)2714 void TextFieldPattern::ShowSelectOverlay(
2715     const std::optional<RectF>& firstHandle, const std::optional<RectF>& secondHandle, bool animation, bool isMenuShow)
2716 {
2717     CloseSelectOverlay();
2718     if (isTransparent_) {
2719         return;
2720     }
2721     auto pipeline = PipelineContext::GetCurrentContext();
2722     CHECK_NULL_VOID(pipeline);
2723     auto hasDataCallback = [weak = WeakClaim(this), pipeline, firstHandle, secondHandle, animation, isMenuShow](
2724                                bool hasData) {
2725         LOGI("HasData callback from clipboard, data available ? %{public}d", hasData);
2726         auto pattern = weak.Upgrade();
2727         SelectOverlayInfo selectInfo;
2728         if (!pattern->IsUsingMouse()) {
2729             if (firstHandle.has_value()) {
2730                 selectInfo.firstHandle.paintRect = firstHandle.value();
2731             } else {
2732                 selectInfo.firstHandle.isShow = false;
2733             }
2734             if (secondHandle.has_value()) {
2735                 selectInfo.secondHandle.paintRect = secondHandle.value();
2736             } else {
2737                 selectInfo.secondHandle.isShow = false;
2738             }
2739         }
2740         if (firstHandle.has_value()) {
2741             selectInfo.firstHandle.isShow = pattern->CheckHandleVisible(firstHandle.value());
2742         }
2743         if (secondHandle.has_value()) {
2744             selectInfo.secondHandle.isShow = pattern->CheckHandleVisible(secondHandle.value());
2745         }
2746         selectInfo.isSingleHandle = !firstHandle.has_value() || !secondHandle.has_value();
2747         if (selectInfo.isSingleHandle && pattern->IsTextArea() &&
2748             pattern->GetSelectMode() == SelectionMode::SELECT_ALL) {
2749             auto contentRect = pattern->GetContentRect();
2750             auto parentGlobalOffset = pattern->GetParentGlobalOffset();
2751             selectInfo.menuInfo.menuOffset =
2752                 OffsetF(contentRect.GetOffset().GetX() + contentRect.Width() / 2.0 + parentGlobalOffset.GetX(),
2753                     contentRect.GetOffset().GetY() + parentGlobalOffset.GetY());
2754         }
2755         selectInfo.onHandleMove = [weak](const RectF& handleRect, bool isFirst) {
2756             auto pattern = weak.Upgrade();
2757             CHECK_NULL_VOID(pattern);
2758             pattern->OnHandleMove(handleRect, isFirst);
2759         };
2760         selectInfo.onHandleMoveDone = [weak](const RectF& handleRect, bool isFirst) {
2761             auto pattern = weak.Upgrade();
2762             CHECK_NULL_VOID(pattern);
2763             pattern->OnHandleMoveDone(handleRect, isFirst);
2764         };
2765 
2766         auto host = pattern->GetHost();
2767         CHECK_NULL_VOID_NOLOG(host);
2768         auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
2769         CHECK_NULL_VOID(layoutProperty);
2770 
2771         bool isHideSelectionMenu = layoutProperty->GetSelectionMenuHiddenValue(false);
2772         selectInfo.isUsingMouse = pattern->IsUsingMouse();
2773         if (isHideSelectionMenu && selectInfo.isUsingMouse) {
2774             return;
2775         }
2776 
2777         selectInfo.rightClickOffset = pattern->GetRightClickOffset();
2778         selectInfo.singleLineHeight = pattern->PreferredLineHeight();
2779         pattern->UpdateSelectMenuInfo(hasData, isHideSelectionMenu);
2780         selectInfo.menuInfo = pattern->GetSelectMenuInfo();
2781         if (!isMenuShow) {
2782             selectInfo.menuInfo.menuIsShow = false;
2783         }
2784         if (pattern->isSingleHandle_) {
2785             selectInfo.isHandleLineShow = false;
2786         }
2787         selectInfo.menuCallback.onCopy = [weak]() {
2788             auto pattern = weak.Upgrade();
2789             CHECK_NULL_VOID(pattern);
2790             pattern->HandleOnCopy();
2791             pattern->CloseSelectOverlay(true);
2792         };
2793 
2794         selectInfo.menuCallback.onCut = [weak]() {
2795             auto pattern = weak.Upgrade();
2796             CHECK_NULL_VOID(pattern);
2797             pattern->HandleOnCut();
2798             pattern->CloseSelectOverlay(true);
2799         };
2800 
2801         selectInfo.menuCallback.onPaste = [weak]() {
2802             auto pattern = weak.Upgrade();
2803             CHECK_NULL_VOID(pattern);
2804             pattern->HandleOnPaste();
2805             pattern->CloseSelectOverlay(true);
2806         };
2807         selectInfo.menuCallback.onSelectAll = [weak]() {
2808             auto pattern = weak.Upgrade();
2809             CHECK_NULL_VOID(pattern);
2810             pattern->HandleOnSelectAll(false);
2811             pattern->UpdateCopyAllStatus();
2812             pattern->SetNeedCloseOverlay(false);
2813         };
2814         selectInfo.onClose = [weak](bool closedByGlobalEvent) {
2815             if (closedByGlobalEvent) {
2816                 auto pattern = weak.Upgrade();
2817                 CHECK_NULL_VOID(pattern);
2818                 auto host = pattern->GetHost();
2819                 CHECK_NULL_VOID(host);
2820                 auto current = pattern->GetTextSelector().GetEnd();
2821                 pattern->SetInSelectMode(SelectionMode::NONE);
2822                 pattern->UpdateSelection(current);
2823                 pattern->MarkRedrawOverlay();
2824                 pattern->StartTwinkling();
2825                 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
2826             }
2827         };
2828 
2829         if (!pattern->GetMenuOptionItems().empty()) {
2830             selectInfo.menuOptionItems = pattern->GetMenuOptionItems();
2831         }
2832         auto gesture = host->GetOrCreateGestureEventHub();
2833         gesture->RemoveTouchEvent(pattern->GetTouchListener());
2834         pattern->SetSelectOverlay(pipeline->GetSelectOverlayManager()->CreateAndShowSelectOverlay(
2835             selectInfo, WeakClaim(RawPtr(pattern)), animation));
2836 
2837         auto selectOverlay = pattern->GetSelectOverlay();
2838         CHECK_NULL_VOID_NOLOG(selectOverlay);
2839         auto start = pattern->GetTextSelector().GetStart();
2840         auto end = pattern->GetTextSelector().GetEnd();
2841         selectOverlay->SetSelectInfo(pattern->GetTextEditingValue().GetSelectedText(start, end));
2842         if (isMenuShow) {
2843             selectOverlay->ShowOrHiddenMenu(isHideSelectionMenu);
2844         }
2845         selectOverlay->DisableMenu(isHideSelectionMenu);
2846     };
2847     clipboard_->HasData(hasDataCallback);
2848 }
2849 
AllowCopy()2850 bool TextFieldPattern::AllowCopy()
2851 {
2852     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
2853     CHECK_NULL_RETURN(layoutProperty, false);
2854     return layoutProperty->GetCopyOptionsValue(CopyOptions::Distributed) != CopyOptions::None &&
2855            layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED) != TextInputType::VISIBLE_PASSWORD;
2856 }
2857 
OnDetachFromFrameNode(FrameNode * node)2858 void TextFieldPattern::OnDetachFromFrameNode(FrameNode* node)
2859 {
2860     CloseSelectOverlay();
2861     auto pipeline = PipelineContext::GetCurrentContext();
2862     CHECK_NULL_VOID(pipeline);
2863     if (HasSurfaceChangedCallback()) {
2864         LOGD("Unregister surface change callback with id %{public}d", surfaceChangedCallbackId_.value_or(-1));
2865         pipeline->UnregisterSurfaceChangedCallback(surfaceChangedCallbackId_.value_or(-1));
2866     }
2867     if (HasSurfacePositionChangedCallback()) {
2868         LOGD("Unregister surface position change callback with id %{public}d",
2869             surfacePositionChangedCallbackId_.value_or(-1));
2870         pipeline->UnregisterSurfacePositionChangedCallback(surfacePositionChangedCallbackId_.value_or(-1));
2871     }
2872     auto textFieldManager = DynamicCast<TextFieldManagerNG>(pipeline->GetTextFieldManager());
2873     if (textFieldManager) {
2874         textFieldManager->ClearOnFocusTextField();
2875     }
2876     auto frameNode = WeakClaim(node);
2877     pipeline->RemoveFontNodeNG(frameNode);
2878     auto fontManager = pipeline->GetFontManager();
2879     if (fontManager) {
2880         fontManager->UnRegisterCallbackNG(frameNode);
2881         fontManager->RemoveVariationNodeNG(frameNode);
2882     }
2883 }
2884 
CloseSelectOverlay()2885 void TextFieldPattern::CloseSelectOverlay()
2886 {
2887     CloseSelectOverlay(false);
2888 }
2889 
CloseSelectOverlay(bool animation)2890 void TextFieldPattern::CloseSelectOverlay(bool animation)
2891 {
2892     if (selectOverlayProxy_) {
2893         LOGI("Close select overlay");
2894         selectOverlayProxy_->Close(animation);
2895     }
2896     auto host = GetHost();
2897     CHECK_NULL_VOID_NOLOG(host);
2898     auto gesture = host->GetOrCreateGestureEventHub();
2899     gesture->AddTouchEvent(GetTouchListener());
2900     originalIsMenuShow_ = false;
2901 }
2902 
SelectOverlayIsOn()2903 bool TextFieldPattern::SelectOverlayIsOn()
2904 {
2905     auto pipeline = PipelineContext::GetCurrentContext();
2906     CHECK_NULL_RETURN(pipeline, false);
2907     CHECK_NULL_RETURN_NOLOG(selectOverlayProxy_, false);
2908     auto overlayId = selectOverlayProxy_->GetSelectOverlayId();
2909     return pipeline->GetSelectOverlayManager()->HasSelectOverlay(overlayId);
2910 }
2911 
OnHandleMove(const RectF & handleRect,bool isFirstHandle)2912 void TextFieldPattern::OnHandleMove(const RectF& handleRect, bool isFirstHandle)
2913 {
2914     CHECK_NULL_VOID_NOLOG(SelectOverlayIsOn());
2915     CHECK_NULL_VOID_NOLOG(!textEditingValue_.Empty());
2916     isFirstHandle_ = isFirstHandle;
2917     auto localOffset = handleRect.GetOffset() - parentGlobalOffset_;
2918     isTouchAtLeftOffset_ = IsTouchAtLeftOffset(localOffset.GetX());
2919     auto position = UpdateCaretPositionOnHandleMove(localOffset);
2920     textEditingValue_.CursorMoveToPosition(position);
2921     auto caretMetrics = CalcCursorOffsetByPosition(position, isTouchAtLeftOffset_);
2922     caretRect_.SetOffset(caretMetrics.offset);
2923     selectionMode_ = isSingleHandle_ ? SelectionMode::NONE : SelectionMode::SELECT;
2924     caretUpdateType_ = CaretUpdateType::HANDLE_MOVE;
2925     UpdateTextSelectorByHandleMove(isFirstHandle, position, caretMetrics.offset);
2926 
2927     auto selectOverlay = GetSelectOverlay();
2928     CHECK_NULL_VOID_NOLOG(selectOverlay);
2929     auto start = GetTextSelector().GetStart();
2930     auto end = GetTextSelector().GetEnd();
2931     selectOverlay->SetSelectInfo(GetTextEditingValue().GetSelectedText(start, end));
2932 
2933     GetTextRectsInRange(start, end, textBoxes_);
2934     auto tmpHost = GetHost();
2935     CHECK_NULL_VOID(tmpHost);
2936     tmpHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
2937 }
2938 
UpdateCaretPositionOnHandleMove(const OffsetF & localOffset)2939 int32_t TextFieldPattern::UpdateCaretPositionOnHandleMove(const OffsetF& localOffset)
2940 {
2941     int32_t position = 0;
2942     if (!IsTextArea()) {
2943         if (localOffset.GetX() < contentRect_.GetX()) {
2944             position = std::max(static_cast<int32_t>(textEditingValue_.caretPosition -
2945                                                      GetGraphemeClusterLength(GetEditingValue().GetWideText(),
2946                                                          GetEditingValue().caretPosition, true)),
2947                 0);
2948         } else if (GreatOrEqual(localOffset.GetX(), contentRect_.GetX() + contentRect_.Width())) {
2949             position = std::min(static_cast<int32_t>(textEditingValue_.caretPosition +
2950                                                      GetGraphemeClusterLength(GetEditingValue().GetWideText(),
2951                                                          GetEditingValue().caretPosition)),
2952                 static_cast<int32_t>(textEditingValue_.GetWideText().length()));
2953         } else {
2954             Offset offset(localOffset.GetX() - textRect_.GetX(), 0.0f);
2955             position = ConvertTouchOffsetToCaretPosition(offset);
2956         }
2957         return position;
2958     }
2959     if (localOffset.GetY() < contentRect_.GetY()) {
2960         position = ConvertTouchOffsetToCaretPosition(Offset(
2961             localOffset.GetX() - GetPaddingLeft(), localOffset.GetY() - textRect_.GetY() - PreferredLineHeight()));
2962     } else if (GreatOrEqual(localOffset.GetY(), contentRect_.GetY() + contentRect_.Height())) {
2963         position = ConvertTouchOffsetToCaretPosition(Offset(
2964             localOffset.GetX() - GetPaddingLeft(), localOffset.GetY() - textRect_.GetY() + PreferredLineHeight()));
2965     } else {
2966         position = ConvertTouchOffsetToCaretPosition(
2967             Offset(localOffset.GetX() - GetPaddingLeft(), localOffset.GetY() - textRect_.GetY()));
2968     }
2969     return position;
2970 }
2971 
UpdateCopyAllStatus()2972 void TextFieldPattern::UpdateCopyAllStatus()
2973 {
2974     selectMenuInfo_.showCopyAll = !IsSelectAll();
2975     auto host = GetHost();
2976     CHECK_NULL_VOID(host);
2977     auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
2978     CHECK_NULL_VOID(layoutProperty);
2979     if (selectOverlayProxy_ && !layoutProperty->GetSelectionMenuHiddenValue(false)) {
2980         selectOverlayProxy_->UpdateSelectMenuInfo(selectMenuInfo_);
2981     }
2982 }
2983 
UpdateTextSelectorByHandleMove(bool isMovingBase,int32_t position,OffsetF & offsetToParagraphBeginning)2984 void TextFieldPattern::UpdateTextSelectorByHandleMove(
2985     bool isMovingBase, int32_t position, OffsetF& offsetToParagraphBeginning)
2986 {
2987     if (isSingleHandle_) {
2988         textSelector_.selectionBaseOffset = offsetToParagraphBeginning;
2989         textSelector_.selectionDestinationOffset = textSelector_.selectionBaseOffset;
2990         UpdateSelection(position);
2991         return;
2992     }
2993     if (isMovingBase) {
2994         UpdateSelection(position, textSelector_.GetEnd());
2995         textSelector_.selectionBaseOffset = offsetToParagraphBeginning;
2996         return;
2997     }
2998     UpdateSelection(textSelector_.GetStart(), position);
2999     textSelector_.selectionDestinationOffset = offsetToParagraphBeginning;
3000 }
3001 
OnHandleMoveDone(const RectF &,bool isFirstHandle)3002 void TextFieldPattern::OnHandleMoveDone(const RectF& /* handleRect */, bool isFirstHandle)
3003 {
3004     CHECK_NULL_VOID_NOLOG(SelectOverlayIsOn());
3005     caretUpdateType_ = CaretUpdateType::HANDLE_MOVE_DONE;
3006     isFirstHandle_ = isFirstHandle;
3007     if (!isSingleHandle_) {
3008         StopTwinkling();
3009     }
3010     UpdateCopyAllStatus();
3011     auto tmpHost = GetHost();
3012     CHECK_NULL_VOID(tmpHost);
3013     tmpHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
3014 }
3015 
UpdateOtherHandleOnMove(float dx,float dy)3016 void TextFieldPattern::UpdateOtherHandleOnMove(float dx, float dy)
3017 {
3018     SelectHandleInfo firstInfo, secondInfo;
3019     SizeF handlePaintSize = { SelectHandleInfo::GetDefaultLineWidth().ConvertToPx(), caretRect_.Height() };
3020     if (isFirstHandle_) {
3021         // update position of the other handle
3022         textSelector_.secondHandleOffset_.AddX(dx);
3023         textSelector_.secondHandleOffset_.AddY(dy);
3024         secondInfo.paintRect = { textSelector_.secondHandleOffset_, handlePaintSize };
3025         // hide the other handle if it's outside content rect
3026         auto handleOffset = textSelector_.secondHandleOffset_ - parentGlobalOffset_;
3027         secondInfo.isShow =
3028             contentRect_.IsInRegion({ handleOffset.GetX(), handleOffset.GetY() + caretRect_.Height() / 2 });
3029         selectOverlayProxy_->UpdateSecondSelectHandleInfo(secondInfo);
3030     } else {
3031         textSelector_.firstHandleOffset_.AddX(dx);
3032         textSelector_.firstHandleOffset_.AddY(dy);
3033         firstInfo.paintRect = { textSelector_.firstHandleOffset_, handlePaintSize };
3034 
3035         auto handleOffset = textSelector_.firstHandleOffset_ - parentGlobalOffset_;
3036         firstInfo.isShow =
3037             contentRect_.IsInRegion({ handleOffset.GetX(), handleOffset.GetY() + caretRect_.Height() / 2 });
3038         selectOverlayProxy_->UpdateFirstSelectHandleInfo(firstInfo);
3039     }
3040 }
3041 
SetHandlerOnMoveDone()3042 void TextFieldPattern::SetHandlerOnMoveDone()
3043 {
3044     SelectHandleInfo info;
3045     auto newHandleOffset = parentGlobalOffset_;
3046     CaretMetricsF handleOffset;
3047     if (!isSingleHandle_) {
3048         handleOffset = CalcCursorOffsetByPosition(
3049             isFirstHandle_ ? textSelector_.baseOffset : textSelector_.destinationOffset, isFirstHandle_ ? true : false);
3050     } else {
3051         handleOffset = CalcCursorOffsetByPosition(textEditingValue_.caretPosition, isTouchAtLeftOffset_);
3052     }
3053     newHandleOffset += handleOffset.offset;
3054     SizeF handlePaintSize = { SelectHandleInfo::GetDefaultLineWidth().ConvertToPx(), caretRect_.Height() };
3055     RectF newHandle;
3056     newHandle.SetOffset(newHandleOffset);
3057     newHandle.SetSize(handlePaintSize);
3058     info.paintRect = newHandle;
3059     info.needLayout = true;
3060     selectionMode_ = isSingleHandle_ ? SelectionMode::NONE : SelectionMode::SELECT;
3061     if (isFirstHandle_) {
3062         textSelector_.firstHandleOffset_ = newHandleOffset;
3063         selectOverlayProxy_->UpdateFirstSelectHandleInfo(info);
3064         return;
3065     }
3066     textSelector_.secondHandleOffset_ = newHandleOffset;
3067     selectOverlayProxy_->UpdateSecondSelectHandleInfo(info);
3068 }
3069 
InitEditingValueText(std::string content)3070 void TextFieldPattern::InitEditingValueText(std::string content)
3071 {
3072     textEditingValue_.text = std::move(content);
3073     textEditingValue_.caretPosition = textEditingValue_.GetWideText().length();
3074     SetEditingValueToProperty(textEditingValue_.text);
3075     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
3076     CHECK_NULL_VOID(layoutProperty);
3077     layoutProperty->UpdateNeedFireOnChange(true);
3078 }
3079 
InitCaretPosition(std::string content)3080 void TextFieldPattern::InitCaretPosition(std::string content)
3081 {
3082     textEditingValue_.caretPosition = static_cast<int32_t>(StringUtils::ToWstring(content).length());
3083 }
3084 
InitMouseEvent()3085 void TextFieldPattern::InitMouseEvent()
3086 {
3087     CHECK_NULL_VOID_NOLOG(!mouseEvent_ || !hoverEvent_);
3088     auto tmpHost = GetHost();
3089     CHECK_NULL_VOID(tmpHost);
3090     auto eventHub = tmpHost->GetEventHub<TextFieldEventHub>();
3091     auto inputHub = eventHub->GetOrCreateInputEventHub();
3092 
3093     auto mouseTask = [weak = WeakClaim(this)](MouseInfo& info) {
3094         auto pattern = weak.Upgrade();
3095         if (pattern) {
3096             pattern->HandleMouseEvent(info);
3097         }
3098     };
3099     mouseEvent_ = MakeRefPtr<InputEvent>(std::move(mouseTask));
3100     inputHub->AddOnMouseEvent(mouseEvent_);
3101 
3102     auto hoverTask = [weak = WeakClaim(this)](bool isHover) {
3103         auto pattern = weak.Upgrade();
3104         if (pattern) {
3105             pattern->OnHover(isHover);
3106         }
3107     };
3108     hoverEvent_ = MakeRefPtr<InputEvent>(std::move(hoverTask));
3109     inputHub->AddOnHoverEvent(hoverEvent_);
3110 }
3111 
OnHover(bool isHover)3112 void TextFieldPattern::OnHover(bool isHover)
3113 {
3114     auto tmpHost = GetHost();
3115     CHECK_NULL_VOID(tmpHost);
3116     LOGI("Textfield %{public}d %{public}s", tmpHost->GetId(), isHover ? "on hover" : "exit hover");
3117     auto frameId = tmpHost->GetId();
3118     auto pipeline = PipelineContext::GetCurrentContext();
3119     CHECK_NULL_VOID(pipeline);
3120     auto themeManager = pipeline->GetThemeManager();
3121     CHECK_NULL_VOID(themeManager);
3122     auto textFieldTheme = themeManager->GetTheme<TextFieldTheme>();
3123     CHECK_NULL_VOID(textFieldTheme);
3124     if (isHover) {
3125         pipeline->SetMouseStyleHoldNode(frameId);
3126         pipeline->ChangeMouseStyle(frameId, MouseFormat::TEXT_CURSOR);
3127     } else {
3128         pipeline->ChangeMouseStyle(frameId, MouseFormat::DEFAULT);
3129         pipeline->FreeMouseStyleHoldNode(frameId);
3130     }
3131     isOnHover_ = isHover;
3132     if (enableTouchAndHoverEffect_) {
3133         auto textfieldPaintProperty = GetPaintProperty<TextFieldPaintProperty>();
3134         CHECK_NULL_VOID(textfieldPaintProperty);
3135         auto renderContext = tmpHost->GetRenderContext();
3136         auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
3137         CHECK_NULL_VOID(layoutProperty);
3138         if (isOnHover_) {
3139             if (layoutProperty->GetShowUnderlineValue(false) &&
3140                 layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED) == TextInputType::UNSPECIFIED) {
3141                 auto radius = textFieldTheme->GetBorderRadiusSize();
3142                 renderContext->UpdateBorderRadius({ radius.GetX(), radius.GetY(), radius.GetY(), radius.GetX() });
3143             }
3144             tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
3145             return;
3146         }
3147         isOnHover_ = false;
3148         if (!isMousePressed_) {
3149             if (layoutProperty->GetShowUnderlineValue(false) &&
3150                 layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED) == TextInputType::UNSPECIFIED) {
3151                 renderContext->UpdateBorderRadius(borderRadius_);
3152             }
3153             if (layoutProperty->GetShowUnderlineValue(false) && HasFocus() &&
3154                 layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED) == TextInputType::UNSPECIFIED) {
3155                 auto radius = textFieldTheme->GetBorderRadiusSize();
3156                 renderContext->UpdateBorderRadius({ radius.GetX(), radius.GetY(), radius.GetY(), radius.GetX() });
3157             }
3158         }
3159         tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
3160     }
3161 }
3162 
HandleMouseEvent(MouseInfo & info)3163 void TextFieldPattern::HandleMouseEvent(MouseInfo& info)
3164 {
3165     auto tmpHost = GetHost();
3166     CHECK_NULL_VOID(tmpHost);
3167     auto frameId = tmpHost->GetId();
3168     auto pipeline = PipelineContext::GetCurrentContext();
3169     CHECK_NULL_VOID(pipeline);
3170     pipeline->SetMouseStyleHoldNode(frameId);
3171 
3172     if (!IsSearchParentNode()) {
3173         info.SetStopPropagation(true);
3174     }
3175 
3176     if (info.GetLocalLocation().GetX() > (frameRect_.Width() - imageRect_.Width() - GetIconRightOffset()) &&
3177         NeedShowPasswordIcon()) {
3178         pipeline->ChangeMouseStyle(frameId, MouseFormat::DEFAULT);
3179         return;
3180     } else {
3181         pipeline->ChangeMouseStyle(frameId, MouseFormat::TEXT_CURSOR);
3182     }
3183 
3184     auto focusHub = tmpHost->GetOrCreateFocusHub();
3185 
3186     if (IsSearchParentNode()) {
3187         auto parentFrameNode = AceType::DynamicCast<FrameNode>(tmpHost->GetParent());
3188         focusHub = parentFrameNode->GetOrCreateFocusHub();
3189     }
3190 
3191     if (info.GetButton() == MouseButton::RIGHT_BUTTON) {
3192         if (info.GetAction() == MouseAction::PRESS) {
3193             LOGI("Handle mouse right button press");
3194             isMousePressed_ = true;
3195         }
3196         if (info.GetAction() == MouseAction::PRESS || info.GetAction() == MouseAction::RELEASE) {
3197             CloseSelectOverlay(true);
3198         }
3199 
3200         if (info.GetAction() == MouseAction::RELEASE) {
3201             LOGI("Handle mouse right button release");
3202             rightClickOffset_ = OffsetF(static_cast<float>(info.GetGlobalLocation().GetX()),
3203                 static_cast<float>(info.GetGlobalLocation().GetY()));
3204             lastTouchOffset_ = info.GetLocalLocation();
3205             caretUpdateType_ = CaretUpdateType::RIGHT_CLICK;
3206             isSingleHandle_ = false;
3207             isUsingMouse_ = true;
3208             mouseStatus_ = MouseStatus::RELEASED;
3209             isMousePressed_ = false;
3210             ProcessOverlay(true);
3211             caretUpdateType_ = CaretUpdateType::NONE;
3212         }
3213         return;
3214     }
3215     if (info.GetAction() == MouseAction::PRESS) {
3216         LOGI("Handle mouse left button press");
3217         if (IsSelected() && BetweenSelectedPosition(info.GetGlobalLocation())) {
3218             blockPress_ = true;
3219             return;
3220         }
3221         blockPress_ = false;
3222         CloseSelectOverlay(true);
3223         if (!focusHub->IsFocusable()) {
3224             return;
3225         }
3226         isMousePressed_ = true;
3227         mouseStatus_ = MouseStatus::PRESSED;
3228         StartTwinkling();
3229         lastTouchOffset_ = info.GetLocalLocation();
3230         isTouchAtLeftOffset_ = IsTouchAtLeftOffset(lastTouchOffset_.GetX());
3231         caretUpdateType_ = CaretUpdateType::PRESSED;
3232         selectionMode_ = SelectionMode::NONE;
3233         UpdateCaretPositionByPressOffset();
3234         auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
3235         CHECK_NULL_VOID(paintProperty);
3236         if (paintProperty->GetInputStyleValue(InputStyle::DEFAULT) != InputStyle::INLINE &&
3237             (!focusHub->IsFocusOnTouch().value_or(true) || !focusHub->RequestFocusImmediately())) {
3238             LOGE("Request focus failed, cannot open input method");
3239             StopTwinkling();
3240             return;
3241         }
3242         tmpHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
3243         return;
3244     }
3245     if (info.GetAction() == MouseAction::RELEASE) {
3246         LOGI("Handle mouse left button release");
3247         if (blockPress_) {
3248             blockPress_ = false;
3249         }
3250         CloseSelectOverlay(true);
3251         caretUpdateType_ = CaretUpdateType::NONE;
3252         isMousePressed_ = false;
3253         mouseStatus_ = MouseStatus::RELEASED;
3254         if (!focusHub->IsCurrentFocus()) {
3255             return;
3256         }
3257         if (RequestKeyboard(false, true, true)) {
3258             auto eventHub = tmpHost->GetEventHub<TextFieldEventHub>();
3259             CHECK_NULL_VOID(eventHub);
3260             eventHub->FireOnEditChanged(true);
3261             tmpHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
3262         }
3263     }
3264 
3265     if (info.GetAction() == MouseAction::MOVE) {
3266         if (!isMousePressed_ || blockPress_) {
3267             return;
3268         }
3269         caretUpdateType_ = CaretUpdateType::EVENT;
3270         lastTouchOffset_ = info.GetLocalLocation();
3271         isTouchAtLeftOffset_ = IsTouchAtLeftOffset(lastTouchOffset_.GetX());
3272         mouseStatus_ = MouseStatus::MOVE;
3273         MarkRedrawOverlay();
3274         tmpHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
3275     }
3276 }
3277 
UpdatePositionOfParagraph(int32_t position)3278 void TextFieldPattern::UpdatePositionOfParagraph(int32_t position)
3279 {
3280     textEditingValue_.CursorMoveToPosition(position);
3281 }
3282 
UpdateTextFieldManager(const Offset & offset,float height)3283 void TextFieldPattern::UpdateTextFieldManager(const Offset& offset, float height)
3284 {
3285     if (!HasFocus()) {
3286         return;
3287     }
3288     auto tmpHost = GetHost();
3289     CHECK_NULL_VOID(tmpHost);
3290     auto context = tmpHost->GetContext();
3291     CHECK_NULL_VOID(context);
3292     auto textFieldManager = DynamicCast<TextFieldManagerNG>(context->GetTextFieldManager());
3293     CHECK_NULL_VOID(textFieldManager);
3294     textFieldManager->SetClickPosition(offset);
3295     textFieldManager->SetHeight(height);
3296     textFieldManager->SetOnFocusTextField(WeakClaim(this));
3297 }
3298 
GetDefaultTextInputAction()3299 TextInputAction TextFieldPattern::GetDefaultTextInputAction()
3300 {
3301     TextInputAction defaultTextInputAction = TextInputAction::DONE;
3302     if (IsSearchParentNode()) {
3303         defaultTextInputAction = TextInputAction::SEARCH;
3304     } else if (IsTextArea()) {
3305         defaultTextInputAction = TextInputAction::UNSPECIFIED;
3306     } else {
3307         defaultTextInputAction = TextInputAction::DONE;
3308     }
3309     return defaultTextInputAction;
3310 }
3311 
GetInputFilterWithInputType()3312 std::string TextFieldPattern::GetInputFilterWithInputType()
3313 {
3314     std::string inputFilter = GetInputFilter();
3315     if (!inputFilter.empty()) {
3316         return inputFilter;
3317     }
3318 
3319     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
3320     CHECK_NULL_RETURN(layoutProperty, "");
3321     auto textInputType = layoutProperty->GetTextInputType();
3322     if (textInputType.has_value()) {
3323         switch (textInputType.value()) {
3324             case TextInputType::NUMBER: {
3325                 inputFilter = "[0-9]";
3326                 break;
3327             }
3328             case TextInputType::PHONE: {
3329                 inputFilter = "[\\d\\-\\+\\*\\#]+";
3330                 break;
3331             }
3332             case TextInputType::EMAIL_ADDRESS: {
3333                 inputFilter = "[A-Za-z0-9_.\\@]";
3334                 break;
3335             }
3336             default: {
3337                 break;
3338             }
3339         }
3340     }
3341     return inputFilter;
3342 }
3343 
RequestKeyboard(bool isFocusViewChanged,bool needStartTwinkling,bool needShowSoftKeyboard)3344 bool TextFieldPattern::RequestKeyboard(bool isFocusViewChanged, bool needStartTwinkling, bool needShowSoftKeyboard)
3345 {
3346     auto tmpHost = GetHost();
3347     CHECK_NULL_RETURN(tmpHost, false);
3348     auto context = tmpHost->GetContext();
3349     CHECK_NULL_RETURN(context, false);
3350     if (needShowSoftKeyboard) {
3351         LOGI("Start to request keyboard");
3352         if (customKeyboardBulder_) {
3353             return RequestCustomKeyboard();
3354         }
3355 #if defined(ENABLE_STANDARD_INPUT)
3356         if (textChangeListener_ == nullptr) {
3357             textChangeListener_ = new OnTextChangedListenerImpl(WeakClaim(this));
3358         }
3359         auto inputMethod = MiscServices::InputMethodController::GetInstance();
3360         if (!inputMethod) {
3361             LOGE("Request open soft keyboard failed because input method is null.");
3362             return false;
3363         }
3364         auto optionalTextConfig = GetMiscTextConfig();
3365         CHECK_NULL_RETURN(optionalTextConfig.has_value(), false);
3366         MiscServices::TextConfig textConfig = optionalTextConfig.value();
3367         LOGI("RequestKeyboard set calling window id is : %{public}u", textConfig.windowId);
3368         inputMethod->Attach(textChangeListener_, needShowSoftKeyboard, textConfig);
3369 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
3370         imeAttached_ = true;
3371 #endif
3372 #else
3373         if (!HasConnection()) {
3374             TextInputConfiguration config;
3375             config.type = keyboard_;
3376             config.action = GetTextInputActionValue(GetDefaultTextInputAction());
3377             config.inputFilter = GetInputFilterWithInputType();
3378             config.maxLength = GetMaxLength();
3379             if (keyboard_ == TextInputType::VISIBLE_PASSWORD) {
3380                 config.obscureText = textObscured_;
3381             }
3382             LOGI("Request keyboard configuration: type=%{private}d action=%{private}d obscureText=%{private}d",
3383                 keyboard_, config.action, textObscured_);
3384             connection_ = TextInputProxy::GetInstance().Attach(
3385                 WeakClaim(this), config, context->GetTaskExecutor(), GetInstanceId());
3386 
3387             if (!HasConnection()) {
3388                 LOGE("Get TextInput connection error");
3389                 return false;
3390             }
3391             TextEditingValue value;
3392             value.text = textEditingValue_.text;
3393             value.hint = GetPlaceHolder();
3394             value.selection.Update(textSelector_.baseOffset, textSelector_.destinationOffset);
3395             connection_->SetEditingState(value, GetInstanceId());
3396         }
3397         connection_->Show(isFocusViewChanged, GetInstanceId());
3398 #endif
3399     }
3400     return true;
3401 }
3402 
3403 #if defined(ENABLE_STANDARD_INPUT)
GetMiscTextConfig() const3404 std::optional<MiscServices::TextConfig> TextFieldPattern::GetMiscTextConfig() const
3405 {
3406     auto tmpHost = GetHost();
3407     CHECK_NULL_RETURN(tmpHost, {});
3408     auto pipeline = tmpHost->GetContext();
3409     CHECK_NULL_RETURN(pipeline, {});
3410     auto windowRect = pipeline->GetCurrentWindowRect();
3411     MiscServices::CursorInfo cursorInfo { .left = caretRect_.Left() + windowRect.Left() + parentGlobalOffset_.GetX(),
3412         .top = caretRect_.Top() + windowRect.Top() + parentGlobalOffset_.GetY(),
3413         .width = CURSOR_WIDTH.ConvertToPx(),
3414         .height = caretRect_.Height() };
3415     MiscServices::InputAttribute inputAttribute = { .inputPattern = (int32_t)keyboard_,
3416         .enterKeyType = (int32_t)GetTextInputActionValue(TextInputAction::DONE) };
3417     MiscServices::TextConfig textConfig = {
3418         .inputAttribute = inputAttribute,
3419         .cursorInfo = cursorInfo,
3420         .range = { .start = textSelector_.GetStart(), .end = textSelector_.GetEnd() },
3421         .windowId = pipeline->GetFocusWindowId()};
3422     return textConfig;
3423 }
3424 #endif
3425 
CloseKeyboard(bool forceClose)3426 bool TextFieldPattern::CloseKeyboard(bool forceClose)
3427 {
3428     LOGI("Request close soft keyboard");
3429     if (forceClose) {
3430         StopTwinkling();
3431         CloseSelectOverlay(true);
3432         if (customKeyboardBulder_ && isCustomKeyboardAttached_) {
3433             return CloseCustomKeyboard();
3434         }
3435 #if defined(ENABLE_STANDARD_INPUT)
3436 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
3437         if (!imeAttached_) {
3438             return false;
3439         }
3440 #endif
3441         auto inputMethod = MiscServices::InputMethodController::GetInstance();
3442         if (!inputMethod) {
3443             LOGE("Request close soft keyboard failed because input method is null.");
3444             return false;
3445         }
3446         inputMethod->HideTextInput();
3447         inputMethod->Close();
3448 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
3449         imeAttached_ = false;
3450 #endif
3451 #else
3452         if (HasConnection()) {
3453             connection_->Close(GetInstanceId());
3454             connection_ = nullptr;
3455         }
3456 #endif
3457         return true;
3458     }
3459     return false;
3460 }
3461 
RequestCustomKeyboard()3462 bool TextFieldPattern::RequestCustomKeyboard()
3463 {
3464     if (isCustomKeyboardAttached_) {
3465         return true;
3466     }
3467     CHECK_NULL_RETURN(customKeyboardBulder_, false);
3468     auto frameNode = GetHost();
3469     CHECK_NULL_RETURN(frameNode, false);
3470     auto pipeline = PipelineContext::GetCurrentContext();
3471     CHECK_NULL_RETURN(pipeline, false);
3472     auto overlayManager = pipeline->GetOverlayManager();
3473     CHECK_NULL_RETURN(overlayManager, false);
3474     overlayManager->BindKeyboard(customKeyboardBulder_, frameNode->GetId());
3475     isCustomKeyboardAttached_ = true;
3476     return true;
3477 }
3478 
CloseCustomKeyboard()3479 bool TextFieldPattern::CloseCustomKeyboard()
3480 {
3481     auto frameNode = GetHost();
3482     CHECK_NULL_RETURN(frameNode, false);
3483 
3484     auto pipeline = PipelineContext::GetCurrentContext();
3485     CHECK_NULL_RETURN(pipeline, false);
3486     auto overlayManager = pipeline->GetOverlayManager();
3487     CHECK_NULL_RETURN(overlayManager, false);
3488     overlayManager->CloseKeyboard(frameNode->GetId());
3489     isCustomKeyboardAttached_ = false;
3490     return true;
3491 }
3492 
ProcessPasswordIcon()3493 void TextFieldPattern::ProcessPasswordIcon()
3494 {
3495     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
3496     CHECK_NULL_VOID(layoutProperty);
3497     if (layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED) != TextInputType::VISIBLE_PASSWORD) {
3498         return;
3499     }
3500     bool showPasswordIcon = layoutProperty->GetShowPasswordIconValue(true);
3501     if (!showPasswordIcon) {
3502         return;
3503     }
3504     if (textObscured_) {
3505         ImageSourceInfo hidePasswordSourceInfo = GetImageSourceInfoFromTheme(textObscured_);
3506         if (hideUserDefinedIcon_) {
3507             UpdateUserDefineResource(hidePasswordSourceInfo);
3508         } else {
3509             UpdateInternalResource(hidePasswordSourceInfo);
3510         }
3511         LoadNotifier hideIconLoadNotifier(CreateDataReadyCallback(textObscured_),
3512             CreateLoadSuccessCallback(textObscured_), CreateLoadFailCallback(textObscured_));
3513         hidePasswordImageLoadingCtx_ =
3514             AceType::MakeRefPtr<ImageLoadingContext>(hidePasswordSourceInfo, std::move(hideIconLoadNotifier), true);
3515         hidePasswordImageLoadingCtx_->LoadImageData();
3516         return;
3517     }
3518     if (!textObscured_) {
3519         ImageSourceInfo showPasswordSourceInfo = GetImageSourceInfoFromTheme(textObscured_);
3520         if (showUserDefinedIcon_) {
3521             UpdateUserDefineResource(showPasswordSourceInfo);
3522         } else {
3523             UpdateInternalResource(showPasswordSourceInfo);
3524         }
3525         LoadNotifier showIconLoadNotifier(CreateDataReadyCallback(textObscured_),
3526             CreateLoadSuccessCallback(textObscured_), CreateLoadFailCallback(textObscured_));
3527         showPasswordImageLoadingCtx_ =
3528             AceType::MakeRefPtr<ImageLoadingContext>(showPasswordSourceInfo, std::move(showIconLoadNotifier), true);
3529         showPasswordImageLoadingCtx_->LoadImageData();
3530         return;
3531     }
3532 }
3533 
GetImageSourceInfoFromTheme(bool checkHidePasswordIcon)3534 ImageSourceInfo TextFieldPattern::GetImageSourceInfoFromTheme(bool checkHidePasswordIcon)
3535 {
3536     auto tmpHost = GetHost();
3537     CHECK_NULL_RETURN(tmpHost, {});
3538     auto context = tmpHost->GetContext();
3539     CHECK_NULL_RETURN(context, {});
3540     ImageSourceInfo imageSourceInfo;
3541     auto theme = context->GetTheme<TextFieldTheme>();
3542     CHECK_NULL_RETURN(theme, imageSourceInfo);
3543     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
3544     CHECK_NULL_RETURN(layoutProperty, imageSourceInfo);
3545     if (checkHidePasswordIcon && hideUserDefinedIcon_) {
3546         return layoutProperty->GetHidePasswordSourceInfoValue(imageSourceInfo);
3547     }
3548     if (checkHidePasswordIcon) {
3549         imageSourceInfo.SetResourceId(InternalResource::ResourceId::HIDE_PASSWORD_SVG);
3550         return imageSourceInfo;
3551     }
3552     if (showUserDefinedIcon_) {
3553         return layoutProperty->GetShowPasswordSourceInfoValue(imageSourceInfo);
3554     }
3555     imageSourceInfo.SetResourceId(InternalResource::ResourceId::SHOW_PASSWORD_SVG);
3556     return imageSourceInfo;
3557 }
3558 
UpdateUserDefineResource(ImageSourceInfo & sourceInfo)3559 void TextFieldPattern::UpdateUserDefineResource(ImageSourceInfo& sourceInfo)
3560 {
3561     auto pipeline = PipelineBase::GetCurrentContext();
3562     CHECK_NULL_VOID(pipeline);
3563     auto iconPath = sourceInfo.GetSrc();
3564     if (iconPath.empty()) {
3565         LOGE("Icon path empty");
3566         return;
3567     }
3568     sourceInfo.SetDimension(DEFAULT_FONT, DEFAULT_FONT);
3569     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
3570     CHECK_NULL_VOID(layoutProperty);
3571     if (textObscured_) {
3572         layoutProperty->UpdateHidePasswordSourceInfo(sourceInfo);
3573         return;
3574     }
3575     layoutProperty->UpdateShowPasswordSourceInfo(sourceInfo);
3576 }
3577 
UpdateInternalResource(ImageSourceInfo & sourceInfo)3578 void TextFieldPattern::UpdateInternalResource(ImageSourceInfo& sourceInfo)
3579 {
3580     CHECK_NULL_VOID_NOLOG(sourceInfo.IsInternalResource());
3581     auto pipeline = PipelineBase::GetCurrentContext();
3582     CHECK_NULL_VOID(pipeline);
3583     auto iconTheme = pipeline->GetTheme<IconTheme>();
3584     CHECK_NULL_VOID(iconTheme);
3585     auto iconPath = iconTheme->GetIconPath(sourceInfo.GetResourceId());
3586     if (iconPath.empty()) {
3587         LOGE("Icon path empty");
3588         return;
3589     }
3590     auto theme = pipeline->GetTheme<TextFieldTheme>();
3591     CHECK_NULL_VOID(theme);
3592     if (IsDisabled()) {
3593         sourceInfo.SetSrc(iconPath, theme->GetDisableTextColor());
3594     } else {
3595         sourceInfo.SetSrc(iconPath);
3596     }
3597     sourceInfo.SetDimension(DEFAULT_FONT, DEFAULT_FONT);
3598     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
3599     CHECK_NULL_VOID(layoutProperty);
3600     if (textObscured_) {
3601         layoutProperty->UpdateHidePasswordSourceInfo(sourceInfo);
3602         return;
3603     }
3604     layoutProperty->UpdateShowPasswordSourceInfo(sourceInfo);
3605 }
3606 
CreateLoadSuccessCallback(bool checkHidePasswordIcon)3607 LoadSuccessNotifyTask TextFieldPattern::CreateLoadSuccessCallback(bool checkHidePasswordIcon)
3608 {
3609     auto task = [weak = WeakClaim(this), checkHidePasswordIcon](const ImageSourceInfo& /* sourceInfo */) {
3610         auto pattern = weak.Upgrade();
3611         CHECK_NULL_VOID(pattern);
3612         pattern->OnImageLoadSuccess(checkHidePasswordIcon);
3613     };
3614     return task;
3615 }
3616 
CreateDataReadyCallback(bool checkHidePasswordIcon)3617 DataReadyNotifyTask TextFieldPattern::CreateDataReadyCallback(bool checkHidePasswordIcon)
3618 {
3619     auto task = [weak = WeakClaim(this), checkHidePasswordIcon](const ImageSourceInfo& /* sourceInfo */) {
3620         auto pattern = weak.Upgrade();
3621         CHECK_NULL_VOID(pattern);
3622         pattern->OnImageDataReady(checkHidePasswordIcon);
3623     };
3624     return task;
3625 }
3626 
CreateLoadFailCallback(bool checkHidePasswordIcon)3627 LoadFailNotifyTask TextFieldPattern::CreateLoadFailCallback(bool checkHidePasswordIcon)
3628 {
3629     auto task = [weak = WeakClaim(this), checkHidePasswordIcon](const ImageSourceInfo& /* sourceInfo */) {
3630         auto pattern = weak.Upgrade();
3631         CHECK_NULL_VOID(pattern);
3632         pattern->OnImageLoadFail(checkHidePasswordIcon);
3633     };
3634     return task;
3635 }
3636 
OnImageLoadFail(bool checkHidePasswordIcon)3637 void TextFieldPattern::OnImageLoadFail(bool checkHidePasswordIcon)
3638 {
3639     LOGE("Image data load fail for %{public}s", checkHidePasswordIcon ? "hide icon" : "show icon");
3640     if (checkHidePasswordIcon && hideUserDefinedIcon_) {
3641         hideUserDefinedIcon_ = false;
3642         ProcessPasswordIcon();
3643         hideUserDefinedIcon_ = true;
3644     }
3645     if (!checkHidePasswordIcon && showUserDefinedIcon_) {
3646         showUserDefinedIcon_ = false;
3647         ProcessPasswordIcon();
3648         showUserDefinedIcon_ = true;
3649     }
3650 }
3651 
OnImageDataReady(bool checkHidePasswordIcon)3652 void TextFieldPattern::OnImageDataReady(bool checkHidePasswordIcon)
3653 {
3654     ACE_SCOPED_TRACE("TextFieldPattern::OnImageDataReady");
3655     auto host = GetHost();
3656     CHECK_NULL_VOID(host);
3657     LOGI("Image data ready for %{public}s", checkHidePasswordIcon ? "hide icon" : "show icon");
3658 
3659     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
3660 }
3661 
OnImageLoadSuccess(bool checkHidePasswordIcon)3662 void TextFieldPattern::OnImageLoadSuccess(bool checkHidePasswordIcon)
3663 {
3664     ACE_SCOPED_TRACE("TextFieldPattern::OnImageLoadSuccess");
3665     ImagePaintConfig config;
3666     auto host = GetHost();
3667     CHECK_NULL_VOID(host);
3668     host->MarkNeedRenderOnly();
3669     if (checkHidePasswordIcon) {
3670         LOGI("Load hide icon successfully");
3671         hidePasswordCanvasImage_ = hidePasswordImageLoadingCtx_->MoveCanvasImage();
3672         config.srcRect_ = hidePasswordImageLoadingCtx_->GetSrcRect();
3673         config.dstRect_ = hidePasswordImageLoadingCtx_->GetDstRect();
3674         config.isSvg_ = hidePasswordImageLoadingCtx_->GetSourceInfo().IsSvg();
3675         hidePasswordCanvasImage_->SetPaintConfig(config);
3676         return;
3677     }
3678     LOGI("Load show icon successfully");
3679     showPasswordCanvasImage_ = showPasswordImageLoadingCtx_->MoveCanvasImage();
3680     config.srcRect_ = showPasswordImageLoadingCtx_->GetSrcRect();
3681     config.dstRect_ = showPasswordImageLoadingCtx_->GetDstRect();
3682     config.isSvg_ = showPasswordImageLoadingCtx_->GetSourceInfo().IsSvg();
3683     showPasswordCanvasImage_->SetPaintConfig(config);
3684 }
3685 
OnTextInputActionUpdate(TextInputAction value)3686 void TextFieldPattern::OnTextInputActionUpdate(TextInputAction value) {}
3687 
InsertValue(const std::string & insertValue)3688 void TextFieldPattern::InsertValue(const std::string& insertValue)
3689 {
3690     LOGD("Insert value '%{public}s'", insertValue.c_str());
3691     auto wideInsertValue = StringUtils::ToWstring(insertValue);
3692     LOGD("Insert length %{public}d", static_cast<int32_t>(wideInsertValue.length()));
3693     auto originLength = static_cast<uint32_t>(textEditingValue_.GetWideText().length());
3694     if (originLength >= GetMaxLength() && !IsSelected()) {
3695         LOGW("Max length reached");
3696         return;
3697     }
3698 
3699     std::string valueToUpdate;
3700     if (originLength + wideInsertValue.length() >= GetMaxLength() && !IsSelected()) {
3701         valueToUpdate = StringUtils::ToString(wideInsertValue.substr(0, GetMaxLength() - originLength));
3702     } else {
3703         valueToUpdate = insertValue;
3704     }
3705     std::string oldText = textEditingValue_.text;
3706     auto caretStart = 0;
3707     std::string result;
3708     auto host = GetHost();
3709     CHECK_NULL_VOID(host);
3710     auto textFieldLayoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
3711     CHECK_NULL_VOID(textFieldLayoutProperty);
3712     auto start = textSelector_.GetStart();
3713     auto end = textSelector_.GetEnd();
3714     SwapIfLarger(start, end);
3715     if (IsSelected()) {
3716         LOGI("In select mode, replace selected text");
3717         caretStart = start;
3718     } else {
3719         caretStart = textEditingValue_.caretPosition;
3720     }
3721     EditingValueFilter(valueToUpdate, result, true);
3722     if (result.empty()) {
3723         return;
3724     }
3725     if (IsSelected()) {
3726         textEditingValue_.text =
3727             textEditingValue_.GetValueBeforePosition(start) + result + textEditingValue_.GetValueAfterPosition(end);
3728     } else {
3729         textEditingValue_.text =
3730             textEditingValue_.GetValueBeforeCursor() + result + textEditingValue_.GetValueAfterCursor();
3731     }
3732     textEditingValue_.CursorMoveToPosition(caretStart + static_cast<int32_t>(StringUtils::ToWstring(result).length()));
3733     if (!IsTextArea() && IsInPasswordMode() && GetTextObscured()) {
3734         if (wideInsertValue.length() == 1) {
3735             obscureTickCountDown_ = OBSCURE_SHOW_TICKS;
3736             nakedCharPosition_ = textEditingValue_.caretPosition - 1;
3737         } else {
3738             obscureTickCountDown_ = 0;
3739             nakedCharPosition_ = -1;
3740         }
3741     }
3742     SetEditingValueToProperty(textEditingValue_.text);
3743     UpdateEditingValueToRecord();
3744     caretUpdateType_ = CaretUpdateType::INPUT;
3745     cursorVisible_ = true;
3746     selectionMode_ = SelectionMode::NONE;
3747     CloseSelectOverlay(true);
3748     StartTwinkling();
3749     // If the parent node is a Search, the Search callback is executed.
3750     if (IsSearchParentNode()) {
3751         auto parentFrameNode = AceType::DynamicCast<FrameNode>(host->GetParent());
3752         auto eventHub = parentFrameNode->GetEventHub<SearchEventHub>();
3753         CHECK_NULL_VOID(eventHub);
3754         eventHub->UpdateChangeEvent(textEditingValue_.text);
3755         parentFrameNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
3756         return;
3757     }
3758 
3759     auto eventHub = host->GetEventHub<TextFieldEventHub>();
3760     CHECK_NULL_VOID(eventHub);
3761     eventHub->FireOnChange(textEditingValue_.text);
3762     auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
3763     CHECK_NULL_VOID(layoutProperty);
3764     if (IsTextArea() && layoutProperty->HasMaxLength()) {
3765         HandleCounterBorder();
3766     }
3767     host->MarkDirtyNode(layoutProperty->GetMaxLinesValue(Infinity<float>()) <= 1 ? PROPERTY_UPDATE_MEASURE_SELF
3768                                                                                  : PROPERTY_UPDATE_MEASURE);
3769 }
3770 
UpdateEditingValueToRecord()3771 void TextFieldPattern::UpdateEditingValueToRecord()
3772 {
3773     if (operationRecords_.size() >= RECORD_MAX_LENGTH) {
3774         // case of max length is 0
3775         if (operationRecords_.empty()) {
3776             return;
3777         }
3778         operationRecords_.erase(operationRecords_.begin());
3779     }
3780     operationRecords_.emplace_back(textEditingValue_);
3781 }
3782 
UpdateEditingValueCaretPositionToRecord()3783 void TextFieldPattern::UpdateEditingValueCaretPositionToRecord()
3784 {
3785     if (operationRecords_.empty()) {
3786         LOGW("Operation records empty, cannot update position");
3787         return;
3788     }
3789     if (operationRecords_.back().caretPosition != textEditingValue_.caretPosition) {
3790         operationRecords_.back().caretPosition = textEditingValue_.caretPosition;
3791     }
3792 }
3793 
FilterWithRegex(const std::string & filter,const std::string & valueToUpdate,std::string & result,bool needToEscape)3794 bool TextFieldPattern::FilterWithRegex(
3795     const std::string& filter, const std::string& valueToUpdate, std::string& result, bool needToEscape)
3796 {
3797     if (filter.empty() || valueToUpdate.empty()) {
3798         LOGD("Text is empty or filter is empty");
3799         return false;
3800     }
3801     std::string escapeFilter;
3802     if (needToEscape && !TextFieldControllerBase::EscapeString(filter, escapeFilter)) {
3803         LOGE("Escape filter string failed");
3804         return false;
3805     }
3806     if (!needToEscape) {
3807         escapeFilter = filter;
3808     }
3809     std::regex filterRegex(escapeFilter);
3810     auto errorText = regex_replace(valueToUpdate, filterRegex, "");
3811     RemoveErrorTextFromValue(valueToUpdate, errorText, result);
3812     auto tmpHost = GetHost();
3813     CHECK_NULL_RETURN(tmpHost, false);
3814     if (!errorText.empty()) {
3815         auto textFieldEventHub = tmpHost->GetEventHub<TextFieldEventHub>();
3816         CHECK_NULL_RETURN(textFieldEventHub, false);
3817         LOGI("Error text %{private}s", errorText.c_str());
3818         textFieldEventHub->FireOnInputFilterError(errorText);
3819     }
3820     auto textFieldAccessibilityProperty = tmpHost->GetAccessibilityProperty<TextFieldAccessibilityProperty>();
3821     CHECK_NULL_RETURN(textFieldAccessibilityProperty, false);
3822     textFieldAccessibilityProperty->SetErrorText(errorText);
3823     return !errorText.empty();
3824 }
3825 
EditingValueFilter(std::string & valueToUpdate,std::string & result,bool isInsertValue)3826 void TextFieldPattern::EditingValueFilter(std::string& valueToUpdate, std::string& result, bool isInsertValue)
3827 {
3828     auto tmpHost = GetHost();
3829     CHECK_NULL_VOID(tmpHost);
3830     auto textFieldLayoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
3831     CHECK_NULL_VOID(textFieldLayoutProperty);
3832     // filter text editing value with user defined filter first
3833     auto inputFilter = textFieldLayoutProperty->GetInputFilterValue("");
3834     bool textChanged = false;
3835     if (!inputFilter.empty()) {
3836         textChanged |= FilterWithRegex(inputFilter, valueToUpdate, result);
3837     }
3838     if (textChanged) {
3839         valueToUpdate = result;
3840         textChanged = false;
3841     }
3842     result = "";
3843     switch (textFieldLayoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED)) {
3844         case TextInputType::NUMBER: {
3845             textChanged |= FilterWithRegex(DIGIT_WHITE_LIST, valueToUpdate, result);
3846             break;
3847         }
3848         case TextInputType::PHONE: {
3849             textChanged |= FilterWithRegex(PHONE_WHITE_LIST, valueToUpdate, result);
3850             break;
3851         }
3852         case TextInputType::EMAIL_ADDRESS: {
3853             if (valueToUpdate == "@" && isInsertValue) {
3854                 auto charExists = textEditingValue_.text.find('@') != std::string::npos;
3855                 result = charExists ? "" : valueToUpdate;
3856                 return;
3857             } else {
3858                 textChanged |= FilterWithRegex(EMAIL_WHITE_LIST, valueToUpdate, result);
3859                 textChanged |= FilterWithEmail(result);
3860             }
3861             break;
3862         }
3863         case TextInputType::URL: {
3864             textChanged |= FilterWithRegex(URL_WHITE_LIST, valueToUpdate, result);
3865             break;
3866         }
3867         case TextInputType::VISIBLE_PASSWORD: {
3868             textChanged |= FilterWithAscii(valueToUpdate, result);
3869             break;
3870         }
3871         default: {
3872             // No need limit.
3873         }
3874     }
3875     if (!textChanged) {
3876         result = valueToUpdate;
3877     }
3878 }
3879 
FilterWithAscii(const std::string & valueToUpdate,std::string & result)3880 bool TextFieldPattern::FilterWithAscii(const std::string& valueToUpdate, std::string& result)
3881 {
3882     if (valueToUpdate.empty()) {
3883         LOGD("Text is empty or filter is empty");
3884         return false;
3885     }
3886     bool textChange = true;
3887     std::string errorText = "";
3888     for (size_t valuePtr = 0; valuePtr < valueToUpdate.size(); valuePtr++) {
3889         if (isascii(valueToUpdate[valuePtr])) {
3890             result += valueToUpdate[valuePtr];
3891         } else {
3892             errorText += valueToUpdate[valuePtr];
3893         }
3894     }
3895     if (errorText.empty()) {
3896         textChange = false;
3897     } else {
3898         LOGI("FilterWithAscii Error text %{private}s", errorText.c_str());
3899     }
3900     return textChange;
3901 }
3902 
FilterWithEmail(std::string & result)3903 bool TextFieldPattern::FilterWithEmail(std::string& result)
3904 {
3905     auto valueToUpdate = result;
3906     bool first = true;
3907     std::replace_if(
3908         result.begin(), result.end(),
3909         [&first](const char c) {
3910             if (c == '@' && !first)
3911                 return true;
3912             if (c == '@')
3913                 first = false;
3914             return false;
3915         },
3916         ' ');
3917 
3918     // remove the spaces
3919     result.erase(std::remove(result.begin(), result.end(), ' '), result.end());
3920     return result != valueToUpdate;
3921 }
3922 
PreferredTextHeight(bool isPlaceholder)3923 float TextFieldPattern::PreferredTextHeight(bool isPlaceholder)
3924 {
3925     auto tmpHost = GetHost();
3926     CHECK_NULL_RETURN(tmpHost, 0.0f);
3927     auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
3928     CHECK_NULL_RETURN(layoutProperty, 0.0f);
3929     // check if util paragraph need to update
3930     if (!isPlaceholder &&
3931         (textLineHeightUtilParagraph_ && !layoutProperty->GetPreferredTextLineHeightNeedToUpdateValue(true))) {
3932         return static_cast<float>(textLineHeightUtilParagraph_->GetHeight());
3933 
3934     } else if (isPlaceholder && (placeholderLineHeightUtilParagraph_ &&
3935                                     !layoutProperty->GetPreferredPlaceholderLineHeightNeedToUpdateValue(true))) {
3936         return static_cast<float>(placeholderLineHeightUtilParagraph_->GetHeight());
3937     }
3938     auto pipeline = tmpHost->GetContext();
3939     CHECK_NULL_RETURN(pipeline, 0.0f);
3940     auto themeManager = pipeline->GetThemeManager();
3941     CHECK_NULL_RETURN(themeManager, 0.0f);
3942     auto textFieldTheme = themeManager->GetTheme<TextFieldTheme>();
3943     CHECK_NULL_RETURN(textFieldTheme, 0.0f);
3944     std::string textContent;
3945     TextStyle textStyle;
3946     // use text or placeHolder value if exists, space otherwise
3947     if (!isPlaceholder) {
3948         TextFieldLayoutAlgorithm::UpdateTextStyle(tmpHost, layoutProperty, textFieldTheme, textStyle, false);
3949         textContent = "a";
3950     } else {
3951         TextFieldLayoutAlgorithm::UpdatePlaceholderTextStyle(
3952             tmpHost, layoutProperty, textFieldTheme, textStyle, false);
3953         textContent = "b";
3954     }
3955     if (textStyle.GetFontSize().IsNonPositive()) {
3956         textStyle.SetFontSize(DEFAULT_FONT);
3957     }
3958     RSParagraphStyle paraStyle;
3959     paraStyle.textDirection_ = ToRSTextDirection(TextFieldLayoutAlgorithm::GetTextDirection(textEditingValue_.text));
3960     paraStyle.textAlign_ = ToRSTextAlign(textStyle.GetTextAlign());
3961     paraStyle.maxLines_ = textStyle.GetMaxLines();
3962     paraStyle.locale_ = Localization::GetInstance()->GetFontLocale();
3963     paraStyle.wordBreakType_ = ToRSWordBreakType(textStyle.GetWordBreak());
3964     paraStyle.fontSize_ = textStyle.GetFontSize().ConvertToPx();
3965     if (LessOrEqual(paraStyle.fontSize_, 0.0f)) {
3966         paraStyle.fontSize_ = DEFAULT_FONT.ConvertToPx();
3967     }
3968     if (textStyle.GetTextOverflow() == TextOverflow::ELLIPSIS) {
3969         paraStyle.ellipsis_ = RSParagraphStyle::ELLIPSIS;
3970     }
3971     auto builder = RSParagraphBuilder::CreateRosenBuilder(paraStyle, RSFontCollection::GetInstance(false));
3972     builder->PushStyle(ToRSTextStyle(PipelineContext::GetCurrentContext(), textStyle));
3973     StringUtils::TransformStrCase(textEditingValue_.text, static_cast<int32_t>(textStyle.GetTextCase()));
3974     builder->AddText(StringUtils::Str8ToStr16(textContent));
3975     builder->Pop();
3976     if (!isPlaceholder) {
3977         textLineHeightUtilParagraph_ = builder->Build();
3978         textLineHeightUtilParagraph_->Layout(std::numeric_limits<double>::infinity());
3979         layoutProperty->UpdatePreferredTextLineHeightNeedToUpdate(false);
3980         return static_cast<float>(textLineHeightUtilParagraph_->GetHeight());
3981     }
3982     placeholderLineHeightUtilParagraph_ = builder->Build();
3983     placeholderLineHeightUtilParagraph_->Layout(std::numeric_limits<double>::infinity());
3984     layoutProperty->UpdatePreferredPlaceholderLineHeightNeedToUpdate(false);
3985     return static_cast<float>(placeholderLineHeightUtilParagraph_->GetHeight());
3986 }
3987 
PreferredLineHeight()3988 float TextFieldPattern::PreferredLineHeight()
3989 {
3990     return PreferredTextHeight(textEditingValue_.text.empty());
3991 }
3992 
OnCursorMoveDone()3993 void TextFieldPattern::OnCursorMoveDone()
3994 {
3995     CloseSelectOverlay();
3996     caretUpdateType_ = CaretUpdateType::EVENT;
3997     selectionMode_ = SelectionMode::NONE;
3998     UpdateSelection(textEditingValue_.caretPosition);
3999     GetTextRectsInRange(textSelector_.GetStart(), textSelector_.GetEnd(), textBoxes_);
4000     auto tmpHost = GetHost();
4001     CHECK_NULL_VOID(tmpHost);
4002     tmpHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
4003 }
4004 
GetWordLength(int32_t originCaretPosition,int32_t directionMove)4005 int32_t TextFieldPattern::GetWordLength(int32_t originCaretPosition, int32_t directionMove)
4006 {
4007     if (textEditingValue_.text.empty()) {
4008         return 0;
4009     }
4010     int32_t textLength = static_cast<int32_t>(textEditingValue_.GetWideText().length());
4011     if (originCaretPosition < 0 || originCaretPosition > textLength) {
4012         LOGD("Get word length failed, the origin caret position is out of range");
4013         return 0;
4014     }
4015     // directionMove == 0 left, directionMove == 1 right
4016     // cannot get word length by current caret position and direction
4017     if ((directionMove == 0 && originCaretPosition == 0) || (directionMove == 1 && originCaretPosition == textLength)) {
4018         return 0;
4019     }
4020     int32_t offset = 0;
4021     int32_t strIndex = 0;
4022     auto wideTextValue = textEditingValue_.GetWideText();
4023     for (directionMove == 0 ? strIndex = (originCaretPosition - 1) : strIndex = originCaretPosition;
4024          directionMove == 0 ? strIndex >= 0 : strIndex <= textLength;) {
4025         if ((wideTextValue[strIndex] >= L'0' && wideTextValue[strIndex] <= L'9') ||
4026             (wideTextValue[strIndex] >= L'a' && wideTextValue[strIndex] <= L'z') ||
4027             (wideTextValue[strIndex] >= L'A' && wideTextValue[strIndex] <= L'Z')) {
4028             offset++;
4029         } else {
4030             if (offset > 0) {
4031                 break;
4032             }
4033             offset = 1;
4034             break;
4035         }
4036         if (directionMove == 0) {
4037             strIndex--;
4038         } else {
4039             strIndex++;
4040         }
4041     }
4042     return offset;
4043 }
4044 
GetLineBeginPosition(int32_t originCaretPosition,bool needToCheckLineChanged)4045 int32_t TextFieldPattern::GetLineBeginPosition(int32_t originCaretPosition, bool needToCheckLineChanged)
4046 {
4047     if (textEditingValue_.text.empty()) {
4048         return 0;
4049     }
4050     int32_t textLength = static_cast<int32_t>(textEditingValue_.GetWideText().length());
4051     if (originCaretPosition < 0 || originCaretPosition > textLength) {
4052         LOGD("Get begin position failed, the origin caret position is out of range");
4053         return 0;
4054     }
4055     if (originCaretPosition == 0) {
4056         return originCaretPosition;
4057     }
4058     int32_t moveLineBeginOffset = 0;
4059     int32_t strIndex = originCaretPosition;
4060     auto wideTextValue = textEditingValue_.GetWideText();
4061     do {
4062         moveLineBeginOffset++;
4063         strIndex--;
4064         // stop moving caret if reaches \n, text head or caret line changed
4065     } while (((strIndex > 0) && (wideTextValue[strIndex] != L'\n')) ||
4066              (needToCheckLineChanged && !CharLineChanged(strIndex)));
4067     if (strIndex < 0 || strIndex >= static_cast<int32_t>(wideTextValue.length())) {
4068         return 0;
4069     }
4070     if (wideTextValue[strIndex] == L'\n') {
4071         moveLineBeginOffset--;
4072     }
4073     if (moveLineBeginOffset > originCaretPosition) {
4074         return 0;
4075     }
4076     return originCaretPosition - moveLineBeginOffset;
4077 }
4078 
GetLineEndPosition(int32_t originCaretPosition,bool needToCheckLineChanged)4079 int32_t TextFieldPattern::GetLineEndPosition(int32_t originCaretPosition, bool needToCheckLineChanged)
4080 {
4081     if (textEditingValue_.text.empty()) {
4082         return 0;
4083     }
4084     int32_t textLength = static_cast<int32_t>(textEditingValue_.GetWideText().length());
4085     if (originCaretPosition < 0 || originCaretPosition > textLength) {
4086         LOGD("Get line end position failed, the origin caret position is out of range");
4087         return originCaretPosition;
4088     }
4089     if (originCaretPosition == textLength) {
4090         return originCaretPosition;
4091     }
4092     int32_t moveLineEndOffset = 0;
4093     int32_t strIndex = 0;
4094     auto wideTextValue = textEditingValue_.GetWideText();
4095     for (strIndex = originCaretPosition + 1; (strIndex <= textLength && wideTextValue[strIndex] != L'\n') ||
4096                                              (needToCheckLineChanged && !CharLineChanged(strIndex));
4097          strIndex++) {
4098         moveLineEndOffset++;
4099     }
4100     if (moveLineEndOffset > textLength - originCaretPosition) {
4101         return textLength;
4102     }
4103     return originCaretPosition + moveLineEndOffset;
4104 }
4105 
CharLineChanged(int32_t caretPosition)4106 bool TextFieldPattern::CharLineChanged(int32_t caretPosition)
4107 {
4108     if (caretPosition < 0 || caretPosition > static_cast<int32_t>(textEditingValue_.GetWideText().length())) {
4109         return true;
4110     }
4111     auto caretMetrics = CalcCursorOffsetByPosition(caretPosition);
4112     return !NearEqual(caretMetrics.offset.GetY(), caretRect_.GetY());
4113 }
4114 
CursorMoveLeft()4115 bool TextFieldPattern::CursorMoveLeft()
4116 {
4117     LOGI("Handle cursor move left");
4118     ResetObscureTickCountDown();
4119     auto originCaretPosition = textEditingValue_.caretPosition;
4120     if (IsSelected() && selectionMode_ == SelectionMode::SELECT_ALL) {
4121         textEditingValue_.caretPosition = 0;
4122     } else if (IsSelected()) {
4123         textBoxes_.clear();
4124     } else {
4125         UpdateCaretPositionWithClamp(
4126             textEditingValue_.caretPosition -
4127             GetGraphemeClusterLength(textEditingValue_.GetWideText(), textEditingValue_.caretPosition, true));
4128     }
4129     OnCursorMoveDone();
4130     if (originCaretPosition == textEditingValue_.caretPosition) {
4131         return false;
4132     }
4133     return true;
4134 }
4135 
CursorMoveLeftWord()4136 bool TextFieldPattern::CursorMoveLeftWord()
4137 {
4138     if (textEditingValue_.caretPosition == 0) {
4139         LOGW("Caret position at beginning, cannot move to left");
4140         return true;
4141     }
4142     int32_t originCaretPosition = textEditingValue_.caretPosition;
4143     int32_t textLength = static_cast<int32_t>(textEditingValue_.GetWideText().length());
4144     int32_t leftWordLength = GetWordLength(originCaretPosition, 0);
4145     if (leftWordLength < 0 || leftWordLength > textLength || textEditingValue_.caretPosition - leftWordLength < 0) {
4146         LOGD("Get left word length faild, the left word offset is out of range");
4147         return false;
4148     }
4149     if (IsSelected() && selectionMode_ == SelectionMode::SELECT_ALL) {
4150         textEditingValue_.caretPosition = 0;
4151     } else if (IsSelected()) {
4152         textBoxes_.clear();
4153     } else {
4154         UpdateCaretPositionWithClamp(originCaretPosition - leftWordLength);
4155     }
4156     ResetObscureTickCountDown();
4157     OnCursorMoveDone();
4158     return originCaretPosition != textEditingValue_.caretPosition;
4159 }
4160 
CursorMoveLineBegin()4161 bool TextFieldPattern::CursorMoveLineBegin()
4162 {
4163     if (textEditingValue_.caretPosition == 0) {
4164         LOGW("Caret position at beginning, cannot move to left");
4165         return true;
4166     }
4167     int32_t textLength = static_cast<int32_t>(textEditingValue_.GetWideText().length());
4168     int32_t originCaretPosition = textEditingValue_.caretPosition;
4169     int32_t lineBeginPosition = GetLineBeginPosition(originCaretPosition);
4170     if (lineBeginPosition < 0 || lineBeginPosition > textLength) {
4171         LOGD("Cursor move to line begin faild, the line begin offset is out of range");
4172         return false;
4173     }
4174     if (IsSelected() && selectionMode_ == SelectionMode::SELECT_ALL) {
4175         textEditingValue_.caretPosition = 0;
4176     } else if (IsTextArea()) {
4177         UpdateCaretPositionWithClamp(lineBeginPosition);
4178     } else {
4179         UpdateCaretPositionWithClamp(0);
4180     }
4181     ResetObscureTickCountDown();
4182     OnCursorMoveDone();
4183     return originCaretPosition != textEditingValue_.caretPosition;
4184 }
4185 
CursorMoveToParagraphBegin()4186 bool TextFieldPattern::CursorMoveToParagraphBegin()
4187 {
4188     if (textEditingValue_.caretPosition == 0) {
4189         LOGW("Caret position at beginning, cannot move to left");
4190         return true;
4191     }
4192     auto originCaretPosition = textEditingValue_.caretPosition;
4193     UpdateCaretPositionWithClamp(GetLineBeginPosition(originCaretPosition, false));
4194     OnCursorMoveDone();
4195     return originCaretPosition != textEditingValue_.caretPosition;
4196 }
4197 
CursorMoveHome()4198 bool TextFieldPattern::CursorMoveHome()
4199 {
4200     // ctrl + home, caret move to position 0
4201     if (textEditingValue_.caretPosition == 0) {
4202         LOGW("Caret position at beginning, cannot move to left");
4203         return true;
4204     }
4205     int32_t originCaretPosition = textEditingValue_.caretPosition;
4206     UpdateCaretPositionWithClamp(0);
4207     OnCursorMoveDone();
4208     return originCaretPosition != textEditingValue_.caretPosition;
4209 }
4210 
CursorMoveRight()4211 bool TextFieldPattern::CursorMoveRight()
4212 {
4213     LOGI("Handle cursor move right");
4214     ResetObscureTickCountDown();
4215     auto originCaretPosition = textEditingValue_.caretPosition;
4216     if (IsSelected() && selectionMode_ == SelectionMode::SELECT_ALL) {
4217         textEditingValue_.caretPosition = static_cast<int32_t>(textEditingValue_.GetWideText().length());
4218     } else if (IsSelected()) {
4219         textBoxes_.clear();
4220     } else {
4221         UpdateCaretPositionWithClamp(
4222             textEditingValue_.caretPosition +
4223             GetGraphemeClusterLength(textEditingValue_.GetWideText(), textEditingValue_.caretPosition));
4224     }
4225     OnCursorMoveDone();
4226     if (originCaretPosition == textEditingValue_.caretPosition) {
4227         return false;
4228     }
4229     return true;
4230 }
4231 
CursorMoveRightWord()4232 bool TextFieldPattern::CursorMoveRightWord()
4233 {
4234     if (textEditingValue_.caretPosition == static_cast<int32_t>(textEditingValue_.GetWideText().length())) {
4235         LOGW("Caret position at the end, cannot move to right");
4236         return true;
4237     }
4238     int32_t originCaretPosition = textEditingValue_.caretPosition;
4239     int32_t textLength = static_cast<int32_t>(textEditingValue_.GetWideText().length());
4240     int32_t rightWordLength = GetWordLength(originCaretPosition, 1);
4241     if (rightWordLength < 0 || rightWordLength > textLength ||
4242         rightWordLength + textEditingValue_.caretPosition > textLength) {
4243         LOGD("Get right word length failed, the right word offset is out of range");
4244         return false;
4245     }
4246     if (IsSelected() && selectionMode_ == SelectionMode::SELECT_ALL) {
4247         textEditingValue_.caretPosition = textLength;
4248     } else {
4249         UpdateCaretPositionWithClamp(originCaretPosition + rightWordLength);
4250     }
4251     ResetObscureTickCountDown();
4252     OnCursorMoveDone();
4253     return originCaretPosition != textEditingValue_.caretPosition;
4254 }
4255 
CursorMoveLineEnd()4256 bool TextFieldPattern::CursorMoveLineEnd()
4257 {
4258     if (textEditingValue_.caretPosition == static_cast<int32_t>(textEditingValue_.GetWideText().length())) {
4259         LOGW("Caret position at the end, cannot move to right");
4260         return true;
4261     }
4262     int32_t originCaretPosition = textEditingValue_.caretPosition;
4263     int32_t textLength = static_cast<int32_t>(textEditingValue_.GetWideText().length());
4264     int32_t lineEndPosition = GetLineEndPosition(originCaretPosition);
4265     if (lineEndPosition < 0 || lineEndPosition > textLength) {
4266         LOGD("Handle cursor move to line end failed, the line end position is out of range");
4267         return false;
4268     }
4269     if (IsSelected() && selectionMode_ == SelectionMode::SELECT_ALL) {
4270         textEditingValue_.caretPosition = textLength;
4271     } else if (IsTextArea()) {
4272         UpdateCaretPositionWithClamp(lineEndPosition);
4273     } else {
4274         UpdateCaretPositionWithClamp(textLength);
4275     }
4276     ResetObscureTickCountDown();
4277     OnCursorMoveDone();
4278     return originCaretPosition != textEditingValue_.caretPosition;
4279 }
4280 
CursorMoveToParagraphEnd()4281 bool TextFieldPattern::CursorMoveToParagraphEnd()
4282 {
4283     if (textEditingValue_.caretPosition == static_cast<int32_t>(textEditingValue_.GetWideText().length())) {
4284         LOGW("Caret position at the end, cannot move to right");
4285         return true;
4286     }
4287     auto originCaretPosition = textEditingValue_.caretPosition;
4288     UpdateCaretPositionWithClamp(GetLineEndPosition(originCaretPosition, false));
4289     OnCursorMoveDone();
4290     return originCaretPosition != textEditingValue_.caretPosition;
4291 }
4292 
CursorMoveEnd()4293 bool TextFieldPattern::CursorMoveEnd()
4294 {
4295     // ctrl end, caret to the very end
4296     if (textEditingValue_.caretPosition == static_cast<int32_t>(textEditingValue_.GetWideText().length())) {
4297         LOGW("Caret position at the end, cannot move to right");
4298         return true;
4299     }
4300     int32_t originCaretPosition = textEditingValue_.caretPosition;
4301     int32_t textLength = static_cast<int32_t>(textEditingValue_.GetWideText().length());
4302     UpdateCaretPositionWithClamp(textLength);
4303     OnCursorMoveDone();
4304     return originCaretPosition != textEditingValue_.caretPosition;
4305 }
4306 
CursorMoveUp()4307 bool TextFieldPattern::CursorMoveUp()
4308 {
4309     LOGI("Handle cursor move up");
4310     CHECK_NULL_RETURN_NOLOG(IsTextArea(), false);
4311     auto originCaretPosition = textEditingValue_.caretPosition;
4312     auto offsetX = caretRect_.GetX() - contentRect_.GetX();
4313     auto offsetY = caretRect_.GetY() - textRect_.GetY();
4314     // multiply by 0.5f to convert to the grapheme center point of the previous line.
4315     float verticalOffset = offsetY - PreferredLineHeight() * 0.5f;
4316     textEditingValue_.caretPosition = static_cast<int32_t>(
4317 #ifndef NEW_SKIA
4318         paragraph_->GetGlyphPositionAtCoordinateWithCluster(caretRect_.GetX(), verticalOffset).pos_);
4319 #else
4320         paragraph_->GetGlyphPositionAtCoordinate(offsetX, verticalOffset).pos_);
4321 #endif
4322     OnCursorMoveDone();
4323     if (originCaretPosition == textEditingValue_.caretPosition) {
4324         return false;
4325     }
4326     return true;
4327 }
4328 
CursorMoveDown()4329 bool TextFieldPattern::CursorMoveDown()
4330 {
4331     LOGI("Handle cursor move down");
4332     CHECK_NULL_RETURN_NOLOG(IsTextArea(), false);
4333     auto originCaretPosition = textEditingValue_.caretPosition;
4334     auto offsetX = caretRect_.GetX() - contentRect_.GetX();
4335     auto offsetY = caretRect_.GetY() - textRect_.GetY();
4336     // multiply by 1.5f to convert to the grapheme center point of the next line.
4337     float verticalOffset = offsetY + PreferredLineHeight() * 1.5f;
4338     textEditingValue_.caretPosition = static_cast<int32_t>(
4339 #ifndef NEW_SKIA
4340         paragraph_->GetGlyphPositionAtCoordinateWithCluster(caretRect_.GetX(), verticalOffset).pos_);
4341 #else
4342         paragraph_->GetGlyphPositionAtCoordinate(offsetX, verticalOffset).pos_);
4343 #endif
4344     OnCursorMoveDone();
4345     if (originCaretPosition == textEditingValue_.caretPosition) {
4346         return false;
4347     }
4348     return true;
4349 }
4350 
Delete(int32_t start,int32_t end)4351 void TextFieldPattern::Delete(int32_t start, int32_t end)
4352 {
4353     SwapIfLarger(start, end);
4354     LOGI("Handle Delete within [%{public}d, %{public}d]", start, end);
4355     textEditingValue_.text =
4356         textEditingValue_.GetValueBeforePosition(start) + textEditingValue_.GetValueAfterPosition(end);
4357     UpdateCaretPositionWithClamp(start);
4358     SetEditingValueToProperty(textEditingValue_.text);
4359     FireEventHubOnChange(GetEditingValue().text);
4360     selectionMode_ = SelectionMode::NONE;
4361     caretUpdateType_ = CaretUpdateType::DEL;
4362     CloseSelectOverlay();
4363     StartTwinkling();
4364     UpdateEditingValueToRecord();
4365     auto tmpHost = GetHost();
4366     CHECK_NULL_VOID(tmpHost);
4367     auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
4368     CHECK_NULL_VOID(layoutProperty);
4369     if (IsTextArea() && layoutProperty->HasMaxLength()) {
4370         HandleCounterBorder();
4371     }
4372     // trigger repaint of select mask
4373     ++drawOverlayFlag_;
4374     tmpHost->MarkDirtyNode(layoutProperty->GetMaxLinesValue(Infinity<float>()) <= 1 ? PROPERTY_UPDATE_MEASURE_SELF
4375                                                                                       : PROPERTY_UPDATE_MEASURE);
4376 }
4377 
SetEditingValueToProperty(const std::string & newValueText)4378 void TextFieldPattern::SetEditingValueToProperty(const std::string& newValueText)
4379 {
4380     auto host = GetHost();
4381     CHECK_NULL_VOID(host);
4382     auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
4383     CHECK_NULL_VOID(layoutProperty);
4384     auto textCache = layoutProperty->GetValueValue("");
4385     layoutProperty->UpdateValue(newValueText);
4386     if (textCache != newValueText) {
4387         layoutProperty->UpdateNeedFireOnChange(true);
4388         caretUpdateType_ = CaretUpdateType::INPUT;
4389         host->OnAccessibilityEvent(AccessibilityEventType::TEXT_CHANGE, textCache, newValueText.c_str());
4390     } else {
4391         layoutProperty->UpdateNeedFireOnChange(false);
4392     }
4393 }
4394 
ClearEditingValue()4395 void TextFieldPattern::ClearEditingValue()
4396 {
4397     textEditingValue_.Reset();
4398     SetEditingValueToProperty("");
4399     UpdateEditingValueToRecord();
4400     auto tmpHost = GetHost();
4401     CHECK_NULL_VOID(tmpHost);
4402     auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
4403     CHECK_NULL_VOID(layoutProperty);
4404     tmpHost->MarkDirtyNode(layoutProperty->GetMaxLinesValue(Infinity<float>()) <= 1 ? PROPERTY_UPDATE_MEASURE_SELF
4405                                                                                       : PROPERTY_UPDATE_MEASURE);
4406 }
4407 
HandleCounterBorder()4408 void TextFieldPattern::HandleCounterBorder()
4409 {
4410     auto tmpHost = GetHost();
4411     CHECK_NULL_VOID(tmpHost);
4412     auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
4413     CHECK_NULL_VOID(layoutProperty);
4414     auto pipeline = PipelineContext::GetCurrentContext();
4415     CHECK_NULL_VOID(pipeline);
4416     auto themeManager = pipeline->GetThemeManager();
4417     CHECK_NULL_VOID(themeManager);
4418     auto textFieldTheme = themeManager->GetTheme<TextFieldTheme>();
4419     CHECK_NULL_VOID(textFieldTheme);
4420     auto maxLength = GetMaxLength();
4421     auto currentLength = static_cast<uint32_t>(textEditingValue_.GetWideText().length());
4422 
4423     BorderWidthProperty currentBorderWidth;
4424     if (layoutProperty->GetBorderWidthProperty() != nullptr) {
4425         currentBorderWidth = *(layoutProperty->GetBorderWidthProperty());
4426     } else {
4427         currentBorderWidth.SetBorderWidth(BORDER_DEFAULT_WIDTH);
4428     }
4429     BorderWidthProperty overCountBorderWidth;
4430     overCountBorderWidth.SetBorderWidth(OVER_COUNT_BORDER_WIDTH);
4431 
4432     BorderColorProperty currentBorderColor;
4433     auto renderContext = tmpHost->GetRenderContext();
4434     CHECK_NULL_VOID(renderContext);
4435     if (renderContext->HasBorderColor()) {
4436         currentBorderColor = renderContext->GetBorderColor().value();
4437     }
4438     BorderColorProperty overCountBorderColor;
4439     overCountBorderColor.SetColor(textFieldTheme->GetOverCountBorderColor());
4440     if (currentLength == maxLength) {
4441         if (!(currentBorderWidth == overCountBorderWidth)) {
4442             lastDiffBorderWidth_ = currentBorderWidth;
4443             layoutProperty->UpdateBorderWidth(overCountBorderWidth);
4444             renderContext->UpdateBorderWidth(overCountBorderWidth);
4445         }
4446         if (!(currentBorderColor == overCountBorderColor)) {
4447             lastDiffBorderColor_ = currentBorderColor;
4448             renderContext->UpdateBorderColor(overCountBorderColor);
4449         }
4450     } else {
4451         if (currentBorderWidth == overCountBorderWidth) {
4452             layoutProperty->UpdateBorderWidth(lastDiffBorderWidth_);
4453             renderContext->UpdateBorderWidth(lastDiffBorderWidth_);
4454         }
4455         if (currentBorderColor == overCountBorderColor) {
4456             renderContext->UpdateBorderColor(lastDiffBorderColor_);
4457         }
4458     }
4459 }
4460 
PerformAction(TextInputAction action,bool forceCloseKeyboard)4461 void TextFieldPattern::PerformAction(TextInputAction action, bool forceCloseKeyboard)
4462 {
4463     LOGI("PerformAction  %{public}d", static_cast<int32_t>(action));
4464     auto host = GetHost();
4465     CHECK_NULL_VOID(host);
4466     // If the parent node is a Search, the Search callback is executed.
4467     if (IsSearchParentNode()) {
4468         auto parentFrameNode = AceType::DynamicCast<FrameNode>(host->GetParent());
4469         auto eventHub = parentFrameNode->GetEventHub<SearchEventHub>();
4470         CHECK_NULL_VOID(eventHub);
4471         eventHub->UpdateSubmitEvent(textEditingValue_.text);
4472         CloseKeyboard(forceCloseKeyboard);
4473         return;
4474     }
4475 
4476     auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
4477     CHECK_NULL_VOID(paintProperty);
4478     auto eventHub = host->GetEventHub<TextFieldEventHub>();
4479     if (IsNormalInlineState()) {
4480         HandleBlurEvent();
4481         eventHub->FireOnSubmit(static_cast<int32_t>(action));
4482         return;
4483     }
4484 
4485     if (IsTextArea()) {
4486         if (GetInputFilter() != "\n") {
4487             InsertValue("\n");
4488         }
4489         return;
4490     }
4491     eventHub->FireOnSubmit(static_cast<int32_t>(action));
4492     CloseKeyboard(forceCloseKeyboard);
4493 }
4494 
UpdateEditingValue(const std::shared_ptr<TextEditingValue> & value,bool needFireChangeEvent)4495 void TextFieldPattern::UpdateEditingValue(const std::shared_ptr<TextEditingValue>& value, bool needFireChangeEvent)
4496 {
4497     textEditingValue_.text = value->text;
4498     textEditingValue_.caretPosition = value->selection.baseOffset;
4499     ContainerScope scope(GetInstanceId());
4500     SetEditingValueToProperty(textEditingValue_.text);
4501     UpdateEditingValueToRecord();
4502     caretUpdateType_ = CaretUpdateType::INPUT;
4503     selectionMode_ = SelectionMode::NONE;
4504     CloseSelectOverlay();
4505     StartTwinkling();
4506     auto host = GetHost();
4507     CHECK_NULL_VOID(host);
4508     // If the parent node is a Search, the Search callback is executed.
4509     if (IsSearchParentNode()) {
4510         auto parentFrameNode = AceType::DynamicCast<FrameNode>(host->GetParent());
4511         auto eventHub = parentFrameNode->GetEventHub<SearchEventHub>();
4512         CHECK_NULL_VOID(eventHub);
4513         eventHub->UpdateChangeEvent(textEditingValue_.text);
4514         parentFrameNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
4515         return;
4516     }
4517 
4518     if (needFireChangeEvent) {
4519         auto eventHub = host->GetEventHub<TextFieldEventHub>();
4520         CHECK_NULL_VOID(eventHub);
4521         eventHub->FireOnChange(textEditingValue_.text);
4522     }
4523 
4524     auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
4525     CHECK_NULL_VOID(layoutProperty);
4526     host->MarkDirtyNode(layoutProperty->GetMaxLinesValue(Infinity<float>()) <= 1 ? PROPERTY_UPDATE_MEASURE_SELF
4527                                                                                  : PROPERTY_UPDATE_MEASURE);
4528 }
4529 
UpdateInputFilterErrorText(const std::string & errorText)4530 void TextFieldPattern::UpdateInputFilterErrorText(const std::string& errorText)
4531 {
4532     if (!errorText.empty()) {
4533         auto tmpHost = GetHost();
4534         CHECK_NULL_VOID(tmpHost);
4535         auto textFieldEventHub = tmpHost->GetEventHub<TextFieldEventHub>();
4536         CHECK_NULL_VOID(textFieldEventHub);
4537         textFieldEventHub->FireOnInputFilterError(errorText);
4538     }
4539 }
4540 
OnValueChanged(bool needFireChangeEvent,bool needFireSelectChangeEvent)4541 void TextFieldPattern::OnValueChanged(bool needFireChangeEvent, bool needFireSelectChangeEvent) {}
4542 
OnAreaChangedInner()4543 void TextFieldPattern::OnAreaChangedInner()
4544 {
4545     auto host = GetHost();
4546     CHECK_NULL_VOID(host);
4547     auto context = host->GetContext();
4548     CHECK_NULL_VOID(context);
4549     auto parentGlobalOffset = host->GetPaintRectOffset() - context->GetRootRect().GetOffset();
4550     if (parentGlobalOffset != parentGlobalOffset_) {
4551         parentGlobalOffset_ = parentGlobalOffset;
4552         UpdateTextFieldManager(Offset(parentGlobalOffset_.GetX(), parentGlobalOffset_.GetY()), frameRect_.Height());
4553         CHECK_NULL_VOID_NOLOG(SelectOverlayIsOn());
4554         textSelector_.selectionBaseOffset.SetX(CalcCursorOffsetByPosition(textSelector_.GetStart()).offset.GetX());
4555         textSelector_.selectionDestinationOffset.SetX(
4556             CalcCursorOffsetByPosition(textSelector_.GetEnd(), false).offset.GetX());
4557         UpdateSelection(textSelector_.GetStart(), textSelector_.GetEnd());
4558         if (isSingleHandle_) {
4559             CreateSingleHandle();
4560             RequestKeyboardOnFocus();
4561             return;
4562         }
4563         ProcessOverlay();
4564         selectionMode_ = SelectionMode::SELECT;
4565     }
4566     RequestKeyboardOnFocus();
4567 }
4568 
RequestKeyboardOnFocus()4569 void TextFieldPattern::RequestKeyboardOnFocus()
4570 {
4571     if (!needToRequestKeyboardOnFocus_ || !needToRequestKeyboardInner_) {
4572         return;
4573     }
4574     LOGI("RequestKeyboardOnFocus");
4575     if (!RequestKeyboard(false, true, true)) {
4576         return;
4577     }
4578     StartTwinkling();
4579     LOGI("RequestKeyboardOnFocus ok, reset flag");
4580     auto tmpHost = GetHost();
4581     CHECK_NULL_VOID(tmpHost);
4582     auto eventHub = tmpHost->GetEventHub<TextFieldEventHub>();
4583     CHECK_NULL_VOID(eventHub);
4584     eventHub->FireOnEditChanged(true);
4585     needToRequestKeyboardInner_ = false;
4586 }
4587 
OnVisibleChange(bool isVisible)4588 void TextFieldPattern::OnVisibleChange(bool isVisible)
4589 {
4590     LOGI("visible change to %{public}d", isVisible);
4591     if (!isVisible) {
4592         LOGI("TextField is not visible");
4593         caretUpdateType_ = CaretUpdateType::INPUT;
4594         selectionMode_ = SelectionMode::NONE;
4595         CloseKeyboard(true);
4596         if (SelectOverlayIsOn()) {
4597             StartTwinkling();
4598         }
4599         CloseSelectOverlay();
4600     }
4601 }
4602 
HandleSurfaceChanged(int32_t newWidth,int32_t newHeight,int32_t prevWidth,int32_t prevHeight)4603 void TextFieldPattern::HandleSurfaceChanged(int32_t newWidth, int32_t newHeight, int32_t prevWidth, int32_t prevHeight)
4604 {
4605     LOGI("Textfield handle surface change, new width %{public}d, new height %{public}d, prev width %{public}d, prev "
4606          "height %{public}d",
4607         newWidth, newHeight, prevWidth, prevHeight);
4608     CloseSelectOverlay();
4609     if (HasFocus() && isSingleHandle_) {
4610         StartTwinkling();
4611     }
4612     UpdateCaretInfoToController();
4613 }
4614 
HandleSurfacePositionChanged(int32_t posX,int32_t posY) const4615 void TextFieldPattern::HandleSurfacePositionChanged(int32_t posX, int32_t posY) const
4616 {
4617     LOGI("Textfield handle surface position change, posX %{public}d, posY %{public}d", posX, posY);
4618     UpdateCaretInfoToController();
4619 }
4620 
InitSurfaceChangedCallback()4621 void TextFieldPattern::InitSurfaceChangedCallback()
4622 {
4623     auto host = GetHost();
4624     CHECK_NULL_VOID(host);
4625     auto pipeline = host->GetContext();
4626     CHECK_NULL_VOID(pipeline);
4627     if (!HasSurfaceChangedCallback()) {
4628         auto callbackId = pipeline->RegisterSurfaceChangedCallback(
4629             [weak = WeakClaim(this)](int32_t newWidth, int32_t newHeight, int32_t prevWidth, int32_t prevHeight,
4630                 WindowSizeChangeReason type) {
4631                 auto pattern = weak.Upgrade();
4632                 if (pattern) {
4633                     pattern->HandleSurfaceChanged(newWidth, newHeight, prevWidth, prevHeight);
4634                 }
4635             });
4636         LOGI("Add surface changed callback id %{public}d", callbackId);
4637         UpdateSurfaceChangedCallbackId(callbackId);
4638     }
4639 }
4640 
InitSurfacePositionChangedCallback()4641 void TextFieldPattern::InitSurfacePositionChangedCallback()
4642 {
4643     auto host = GetHost();
4644     CHECK_NULL_VOID(host);
4645     auto pipeline = host->GetContext();
4646     CHECK_NULL_VOID(pipeline);
4647     if (!HasSurfacePositionChangedCallback()) {
4648         auto callbackId =
4649             pipeline->RegisterSurfacePositionChangedCallback([weak = WeakClaim(this)](int32_t posX, int32_t posY) {
4650                 auto pattern = weak.Upgrade();
4651                 if (pattern) {
4652                     pattern->HandleSurfacePositionChanged(posX, posY);
4653                 }
4654             });
4655         LOGI("Add position changed callback id %{public}d", callbackId);
4656         UpdateSurfacePositionChangedCallbackId(callbackId);
4657     }
4658 }
4659 
DeleteBackward(int32_t length)4660 void TextFieldPattern::DeleteBackward(int32_t length)
4661 {
4662     LOGI("Handle DeleteBackward %{public}d characters", length);
4663     if (IsSelected()) {
4664         ResetObscureTickCountDown();
4665         Delete(textSelector_.GetStart(), textSelector_.GetEnd());
4666         return;
4667     }
4668     if (textEditingValue_.caretPosition <= 0) {
4669         LOGW("Caret position at the beginning , cannot DeleteBackward");
4670         return;
4671     }
4672     ResetObscureTickCountDown();
4673     auto start = std::max(textEditingValue_.caretPosition - length, 0);
4674     auto end =
4675         std::min(textEditingValue_.caretPosition, static_cast<int32_t>(textEditingValue_.GetWideText().length()));
4676     textEditingValue_.text =
4677         textEditingValue_.GetValueBeforePosition(start) + textEditingValue_.GetValueAfterPosition(end);
4678     textEditingValue_.CursorMoveToPosition(textEditingValue_.caretPosition - length);
4679     SetEditingValueToProperty(textEditingValue_.text);
4680     FireEventHubOnChange(GetEditingValue().text);
4681     selectionMode_ = SelectionMode::NONE;
4682     caretUpdateType_ = CaretUpdateType::DEL;
4683     CloseSelectOverlay();
4684     StartTwinkling();
4685     UpdateEditingValueToRecord();
4686     auto tmpHost = GetHost();
4687     CHECK_NULL_VOID(tmpHost);
4688     auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
4689     CHECK_NULL_VOID(layoutProperty);
4690     if (IsTextArea() && layoutProperty->HasMaxLength()) {
4691         HandleCounterBorder();
4692     }
4693     tmpHost->MarkDirtyNode(layoutProperty->GetMaxLinesValue(Infinity<float>()) <= 1 ? PROPERTY_UPDATE_MEASURE_SELF
4694                                                                                       : PROPERTY_UPDATE_MEASURE);
4695 }
4696 
DeleteForward(int32_t length)4697 void TextFieldPattern::DeleteForward(int32_t length)
4698 {
4699     LOGI("Handle DeleteForward %{public}d characters", length);
4700     if (IsSelected()) {
4701         ResetObscureTickCountDown();
4702         Delete(textSelector_.GetStart(), textSelector_.GetEnd());
4703         return;
4704     }
4705     if (textEditingValue_.caretPosition >= static_cast<int32_t>(textEditingValue_.GetWideText().length())) {
4706         LOGW("Caret position at the end , cannot DeleteForward");
4707         return;
4708     }
4709     ResetObscureTickCountDown();
4710     textEditingValue_.text = textEditingValue_.GetValueBeforePosition(textEditingValue_.caretPosition) +
4711                              textEditingValue_.GetValueAfterPosition(textEditingValue_.caretPosition + length);
4712     SetEditingValueToProperty(textEditingValue_.text);
4713     FireEventHubOnChange(GetEditingValue().text);
4714     selectionMode_ = SelectionMode::NONE;
4715     caretUpdateType_ = CaretUpdateType::INPUT;
4716     CloseSelectOverlay();
4717     StartTwinkling();
4718     UpdateEditingValueToRecord();
4719     auto tmpHost = GetHost();
4720     CHECK_NULL_VOID(tmpHost);
4721     auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
4722     CHECK_NULL_VOID(layoutProperty);
4723     if (IsTextArea() && layoutProperty->HasMaxLength()) {
4724         HandleCounterBorder();
4725     }
4726     tmpHost->MarkDirtyNode(layoutProperty->GetMaxLinesValue(Infinity<float>()) <= 1 ? PROPERTY_UPDATE_MEASURE_SELF
4727                                                                                       : PROPERTY_UPDATE_MEASURE);
4728 }
4729 
GetLeftTextOfCursor(int32_t number)4730 std::u16string TextFieldPattern::GetLeftTextOfCursor(int32_t number)
4731 {
4732     auto start = textEditingValue_.caretPosition;
4733     if (IsSelected()) {
4734         start = std::min(textSelector_.GetStart(), textSelector_.GetEnd());
4735     }
4736     auto stringText = textEditingValue_.GetSelectedText(start - number, start);
4737     return StringUtils::Str8ToStr16(stringText);
4738 }
4739 
GetRightTextOfCursor(int32_t number)4740 std::u16string TextFieldPattern::GetRightTextOfCursor(int32_t number)
4741 {
4742     auto end = textEditingValue_.caretPosition;
4743     if (IsSelected()) {
4744         end = std::max(textSelector_.GetStart(), textSelector_.GetEnd());
4745     }
4746     auto stringText = textEditingValue_.GetSelectedText(end, end + number);
4747     return StringUtils::Str8ToStr16(stringText);
4748 }
4749 
GetTextIndexAtCursor()4750 int32_t TextFieldPattern::GetTextIndexAtCursor()
4751 {
4752     return textEditingValue_.caretPosition;
4753 }
4754 
AfterSelection()4755 void TextFieldPattern::AfterSelection()
4756 {
4757     LOGI("Selection %{public}s, caret position %{public}d", textSelector_.ToString().c_str(),
4758         textEditingValue_.caretPosition);
4759     updateSelectionAfterObscure_ = ResetObscureTickCountDown();
4760     GetTextRectsInRange(textSelector_.GetStart(), textSelector_.GetEnd(), textBoxes_);
4761     caretUpdateType_ = CaretUpdateType::EVENT;
4762     auto tmpHost = GetHost();
4763     CHECK_NULL_VOID(tmpHost);
4764     auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
4765     CHECK_NULL_VOID(layoutProperty);
4766     tmpHost->MarkDirtyNode(layoutProperty->GetMaxLinesValue(Infinity<float>()) <= 1 ? PROPERTY_UPDATE_MEASURE_SELF
4767                                                                                       : PROPERTY_UPDATE_MEASURE);
4768 }
4769 
HandleSelectionUp()4770 void TextFieldPattern::HandleSelectionUp()
4771 {
4772     LOGI("Handle selection up");
4773     if (!IsTextArea()) {
4774         LOGW("Unsupported operation for text field");
4775         return;
4776     }
4777     if (selectionMode_ != SelectionMode::SELECT) {
4778         UpdateSelection(textEditingValue_.caretPosition);
4779     }
4780     auto newOffsetY = caretRect_.GetY() - PreferredLineHeight() * 0.5 - textRect_.GetY();
4781     textEditingValue_.caretPosition =
4782 #ifndef NEW_SKIA
4783         static_cast<int32_t>(paragraph_->GetGlyphPositionAtCoordinateWithCluster(caretRect_.GetX(), newOffsetY).pos_);
4784 #else
4785         static_cast<int32_t>(paragraph_->GetGlyphPositionAtCoordinate(caretRect_.GetX(), newOffsetY).pos_);
4786 #endif
4787     UpdateSelection(textSelector_.GetStart(), textEditingValue_.caretPosition);
4788     selectionMode_ = SelectionMode::SELECT;
4789     if (textSelector_.baseOffset == textSelector_.destinationOffset) {
4790         selectionMode_ = SelectionMode::NONE;
4791     }
4792     AfterSelection();
4793 }
4794 
HandleSelectionDown()4795 void TextFieldPattern::HandleSelectionDown()
4796 {
4797     LOGI("Handle selection down");
4798     if (!IsTextArea()) {
4799         LOGW("Unsupported operation for text field");
4800         return;
4801     }
4802     if (selectionMode_ != SelectionMode::SELECT) {
4803         UpdateSelection(textEditingValue_.caretPosition);
4804     }
4805     auto newOffsetY = caretRect_.GetY() + PreferredLineHeight() * 1.5 - textRect_.GetY();
4806     textEditingValue_.caretPosition =
4807 #ifndef NEW_SKIA
4808         static_cast<int32_t>(paragraph_->GetGlyphPositionAtCoordinateWithCluster(caretRect_.GetX(), newOffsetY).pos_);
4809 #else
4810         static_cast<int32_t>(paragraph_->GetGlyphPositionAtCoordinate(caretRect_.GetX(), newOffsetY).pos_);
4811 #endif
4812     UpdateSelection(textSelector_.GetStart(), textEditingValue_.caretPosition);
4813     selectionMode_ = SelectionMode::SELECT;
4814     if (textSelector_.baseOffset == textSelector_.destinationOffset) {
4815         selectionMode_ = SelectionMode::NONE;
4816     }
4817     AfterSelection();
4818 }
4819 
HandleSelectionLeft()4820 void TextFieldPattern::HandleSelectionLeft()
4821 {
4822     LOGI("Handle selection left");
4823     if (!IsSelected()) {
4824         if (textEditingValue_.caretPosition == 0) {
4825             LOGW("Caret position at beginning, cannot update selection to left");
4826             return;
4827         }
4828         UpdateSelection(textEditingValue_.caretPosition,
4829             std::max(textSelector_.baseOffset -
4830                          GetGraphemeClusterLength(GetEditingValue().GetWideText(), textSelector_.baseOffset, true),
4831                 0));
4832         UpdateCaretPositionWithClamp(textSelector_.destinationOffset);
4833         selectionMode_ = SelectionMode::SELECT;
4834     } else {
4835         textSelector_.destinationOffset =
4836             std::max(textSelector_.destinationOffset - GetGraphemeClusterLength(GetEditingValue().GetWideText(),
4837                                                            textSelector_.destinationOffset, true),
4838                 0);
4839         UpdateCaretPositionWithClamp(textSelector_.destinationOffset);
4840         if (textSelector_.destinationOffset == textSelector_.baseOffset) {
4841             selectionMode_ = SelectionMode::NONE;
4842         }
4843     }
4844     AfterSelection();
4845 }
4846 
HandleSelectionLeftWord()4847 void TextFieldPattern::HandleSelectionLeftWord()
4848 {
4849     if (textEditingValue_.caretPosition == 0) {
4850         LOGW("Caret position at beginning, cannot update selection to left");
4851         return;
4852     }
4853     int32_t textLength = static_cast<int32_t>(textEditingValue_.GetWideText().length());
4854     int32_t leftWordLength = GetWordLength(textEditingValue_.caretPosition, 0);
4855     if (leftWordLength < 0 || leftWordLength > textLength || textEditingValue_.caretPosition - leftWordLength < 0) {
4856         LOGD("Handle select a left word failed, the left word offset is out of range");
4857         return;
4858     }
4859     if (!IsSelected()) {
4860         textSelector_.destinationOffset = textEditingValue_.caretPosition - leftWordLength;
4861         UpdateSelection(textEditingValue_.caretPosition, textSelector_.destinationOffset);
4862         UpdateCaretPositionWithClamp(textSelector_.destinationOffset);
4863         selectionMode_ = SelectionMode::SELECT;
4864     } else {
4865         textSelector_.destinationOffset = textEditingValue_.caretPosition - leftWordLength;
4866         UpdateCaretPositionWithClamp(textSelector_.destinationOffset);
4867         if (textSelector_.destinationOffset == textSelector_.baseOffset) {
4868             selectionMode_ = SelectionMode::NONE;
4869         }
4870     }
4871     AfterSelection();
4872 }
4873 
HandleSelectionLineBegin()4874 void TextFieldPattern::HandleSelectionLineBegin()
4875 {
4876     if (textEditingValue_.caretPosition == 0) {
4877         LOGW("Caret position at beginning, cannot update selection to left");
4878         return;
4879     }
4880     int32_t textLength = static_cast<int32_t>(textEditingValue_.GetWideText().length());
4881     int32_t lineBeginPosition = GetLineBeginPosition(textEditingValue_.caretPosition);
4882     if (lineBeginPosition < 0 || lineBeginPosition > textLength) {
4883         LOGD("Handle select line begin failed, the line begin offset is out of range");
4884         return;
4885     }
4886     if (!IsSelected()) {
4887         textSelector_.destinationOffset = lineBeginPosition;
4888         UpdateSelection(textEditingValue_.caretPosition, textSelector_.destinationOffset);
4889         UpdateCaretPositionWithClamp(textSelector_.destinationOffset);
4890         selectionMode_ = SelectionMode::SELECT;
4891     } else {
4892         textSelector_.destinationOffset = lineBeginPosition;
4893         UpdateCaretPositionWithClamp(textSelector_.destinationOffset);
4894         if (textSelector_.destinationOffset == textSelector_.baseOffset) {
4895             selectionMode_ = SelectionMode::NONE;
4896         }
4897     }
4898     AfterSelection();
4899 }
4900 
HandleSelectionHome()4901 void TextFieldPattern::HandleSelectionHome()
4902 {
4903     if (textEditingValue_.caretPosition == 0) {
4904         LOGW("Caret position at beginning, cannot update selection to left");
4905         return;
4906     }
4907     if (!IsSelected()) {
4908         textSelector_.destinationOffset = 0;
4909         UpdateSelection(textEditingValue_.caretPosition, textSelector_.destinationOffset);
4910         UpdateCaretPositionWithClamp(textSelector_.destinationOffset);
4911         selectionMode_ = SelectionMode::SELECT;
4912     } else {
4913         textSelector_.destinationOffset = 0;
4914         UpdateCaretPositionWithClamp(textSelector_.destinationOffset);
4915         if (textSelector_.destinationOffset == textSelector_.baseOffset) {
4916             selectionMode_ = SelectionMode::NONE;
4917         }
4918     }
4919     AfterSelection();
4920 }
4921 
HandleSelectionRight()4922 void TextFieldPattern::HandleSelectionRight()
4923 {
4924     LOGI("Handle selection right");
4925     // if currently not in select mode, reset baseOffset and move destinationOffset and caret position
4926     if (!IsSelected()) {
4927         if (textEditingValue_.caretPosition == static_cast<int32_t>(textEditingValue_.GetWideText().length())) {
4928             LOGW("Caret position at the end, cannot update selection to right");
4929             return;
4930         }
4931         UpdateSelection(textEditingValue_.caretPosition,
4932             std::min(textSelector_.baseOffset +
4933                          GetGraphemeClusterLength(GetEditingValue().GetWideText(), textSelector_.baseOffset),
4934                 static_cast<int32_t>(textEditingValue_.GetWideText().length())));
4935         UpdateCaretPositionWithClamp(textSelector_.destinationOffset);
4936         selectionMode_ = SelectionMode::SELECT;
4937     } else {
4938         // if currently not in select mode, move destinationOffset and caret position only
4939         textSelector_.destinationOffset =
4940             std::min(textSelector_.destinationOffset +
4941                          GetGraphemeClusterLength(GetEditingValue().GetWideText(), textSelector_.destinationOffset),
4942                 static_cast<int32_t>(textEditingValue_.GetWideText().length()));
4943         UpdateCaretPositionWithClamp(textSelector_.destinationOffset);
4944         if (textSelector_.destinationOffset == textSelector_.baseOffset) {
4945             selectionMode_ = SelectionMode::NONE;
4946         }
4947     }
4948     AfterSelection();
4949 }
4950 
HandleSelectionRightWord()4951 void TextFieldPattern::HandleSelectionRightWord()
4952 {
4953     int32_t textLength = static_cast<int32_t>(textEditingValue_.GetWideText().length());
4954     if (textEditingValue_.caretPosition == textLength) {
4955         LOGW("Caret position at the end, cannot update selection to right");
4956         return;
4957     }
4958     int32_t rightWordLength = GetWordLength(textEditingValue_.caretPosition, 1);
4959     if (rightWordLength < 0 || rightWordLength > textLength ||
4960         rightWordLength + textEditingValue_.caretPosition > textLength) {
4961         LOGD("Handle select a right word failed, the right word offset is out of range");
4962         return;
4963     }
4964     if (!IsSelected()) {
4965         textSelector_.destinationOffset = textEditingValue_.caretPosition + rightWordLength;
4966         UpdateSelection(textEditingValue_.caretPosition, textSelector_.destinationOffset);
4967         UpdateCaretPositionWithClamp(textSelector_.destinationOffset);
4968         selectionMode_ = SelectionMode::SELECT;
4969     } else {
4970         textSelector_.destinationOffset = textEditingValue_.caretPosition + rightWordLength;
4971         UpdateCaretPositionWithClamp(textSelector_.destinationOffset);
4972         if (textSelector_.destinationOffset == textSelector_.baseOffset) {
4973             selectionMode_ = SelectionMode::NONE;
4974         }
4975     }
4976     AfterSelection();
4977 }
4978 
HandleSelectionLineEnd()4979 void TextFieldPattern::HandleSelectionLineEnd()
4980 {
4981     int32_t textLength = static_cast<int32_t>(textEditingValue_.GetWideText().length());
4982     if (textEditingValue_.caretPosition == textLength) {
4983         LOGW("Caret position at the end, cannot update selection to right");
4984         return;
4985     }
4986     int32_t lineEndPosition = GetLineEndPosition(textEditingValue_.caretPosition);
4987     if (lineEndPosition < 0 || lineEndPosition > textLength) {
4988         LOGD("Handle select a line end failed, the line end offset is out of range");
4989         return;
4990     }
4991     if (!IsSelected()) {
4992         textSelector_.destinationOffset = lineEndPosition;
4993         UpdateSelection(textEditingValue_.caretPosition, textSelector_.destinationOffset);
4994         UpdateCaretPositionWithClamp(textSelector_.destinationOffset);
4995         selectionMode_ = SelectionMode::SELECT;
4996     } else {
4997         textSelector_.destinationOffset = lineEndPosition;
4998         UpdateCaretPositionWithClamp(textSelector_.destinationOffset);
4999         if (textSelector_.destinationOffset == textSelector_.baseOffset) {
5000             selectionMode_ = SelectionMode::NONE;
5001         }
5002     }
5003     AfterSelection();
5004 }
5005 
HandleSelectionEnd()5006 void TextFieldPattern::HandleSelectionEnd()
5007 {
5008     // shift end, select to the end of current line
5009     int32_t endPos = static_cast<int32_t>(textEditingValue_.GetWideText().length());
5010     if (textEditingValue_.caretPosition == endPos) {
5011         LOGW("Caret position at the end, cannot update selection to right");
5012         return;
5013     }
5014     if (!IsSelected()) {
5015         textSelector_.destinationOffset = endPos;
5016         UpdateSelection(textEditingValue_.caretPosition, textSelector_.destinationOffset);
5017         UpdateCaretPositionWithClamp(textSelector_.destinationOffset);
5018         selectionMode_ = SelectionMode::SELECT;
5019     } else {
5020         textSelector_.destinationOffset = endPos;
5021         UpdateCaretPositionWithClamp(textSelector_.destinationOffset);
5022         if (textSelector_.destinationOffset == textSelector_.baseOffset) {
5023             selectionMode_ = SelectionMode::NONE;
5024         }
5025     }
5026     AfterSelection();
5027 }
5028 
SetCaretPosition(int32_t position)5029 void TextFieldPattern::SetCaretPosition(int32_t position)
5030 {
5031     LOGI("Set caret position to %{public}d", position);
5032     textEditingValue_.caretPosition =
5033         std::clamp(position, 0, static_cast<int32_t>(textEditingValue_.GetWideText().length()));
5034     selectionMode_ = SelectionMode::NONE;
5035     caretUpdateType_ = CaretUpdateType::EVENT;
5036     CloseSelectOverlay();
5037     auto tmpHost = GetHost();
5038     CHECK_NULL_VOID(tmpHost);
5039     tmpHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
5040 }
5041 
SetTextSelection(int32_t selectionStart,int32_t selectionEnd)5042 void TextFieldPattern::SetTextSelection(int32_t selectionStart, int32_t selectionEnd)
5043 {
5044     selectionStart = selectionStart < 0 ? 0 : selectionStart;
5045     selectionEnd = std::clamp(selectionEnd, 0, static_cast<int32_t>(textEditingValue_.GetWideText().length()));
5046     if (selectionStart > selectionEnd) {
5047         selectionStart = selectionEnd;
5048     }
5049     auto host = GetHost();
5050     CHECK_NULL_VOID(host);
5051     auto instanceId = GetInstanceId();
5052     ContainerScope scope(instanceId);
5053     auto context = host->GetContext();
5054     CHECK_NULL_VOID(context);
5055     auto taskExecutor = context->GetTaskExecutor();
5056     CHECK_NULL_VOID(taskExecutor);
5057     auto task = [weak = WeakClaim(this), selectionStart, selectionEnd] {
5058         auto client = AceType::DynamicCast<TextFieldPattern>(weak.Upgrade());
5059         if (!client) {
5060             LOGE("text field is null");
5061             return;
5062         }
5063         ContainerScope scope(client->GetInstanceId());
5064         client->HandleSetSelection(selectionStart, selectionEnd, false);
5065         if (selectionStart == selectionEnd) {
5066             client->SetInSelectMode(SelectionMode::NONE);
5067             client->StartTwinkling();
5068         } else {
5069             client->SetInSelectMode(SelectionMode::SELECT);
5070             client->StopTwinkling();
5071         }
5072         client->isUsingMouse_ = false;
5073         client->SetCaretUpdateType(CaretUpdateType::EVENT);
5074         client->CloseSelectOverlay();
5075         client->MarkRedrawOverlay();
5076         if (client->RequestKeyboard(false, true, true)) {
5077             auto textFieldFrameNode = client->GetHost();
5078             CHECK_NULL_VOID(textFieldFrameNode);
5079             auto eventHub = textFieldFrameNode->GetEventHub<TextFieldEventHub>();
5080             CHECK_NULL_VOID(eventHub);
5081             eventHub->FireOnEditChanged(true);
5082         }
5083     };
5084     taskExecutor->PostTask(task, TaskExecutor::TaskType::UI);
5085 }
5086 
SetSelectionFlag(int32_t selectionStart,int32_t selectionEnd)5087 void TextFieldPattern::SetSelectionFlag(int32_t selectionStart, int32_t selectionEnd)
5088 {
5089     if (!HasFocus()) {
5090         return;
5091     }
5092     cursorVisible_ = false;
5093     MarkRedrawOverlay();
5094     SetTextSelection(selectionStart, selectionEnd);
5095     auto host = GetHost();
5096     CHECK_NULL_VOID(host);
5097     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
5098 }
5099 
CaretMoveToLastNewLineChar()5100 void TextFieldPattern::CaretMoveToLastNewLineChar()
5101 {
5102     while (textEditingValue_.caretPosition > 0) {
5103         textEditingValue_.caretPosition -= 1;
5104         if (textEditingValue_.text.substr(textEditingValue_.caretPosition, 1) == "\n") {
5105             break;
5106         }
5107     }
5108 }
5109 
OnBackPressed()5110 bool TextFieldPattern::OnBackPressed()
5111 {
5112     auto tmpHost = GetHost();
5113     CHECK_NULL_RETURN(tmpHost, false);
5114     LOGI("Textfield %{public}d receives back press event", tmpHost->GetId());
5115 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
5116     if ((!imeAttached_ || (imeAttached_ && !imeShown_)) && !isCustomKeyboardAttached_) {
5117 #else
5118     if (!isCustomKeyboardAttached_) {
5119 #endif
5120         LOGI("Ime is not attached or is hidden, return for not consuming the back press event");
5121         return false;
5122     }
5123 
5124     LOGI("Closing keyboard on back press");
5125     CloseKeyboard(true);
5126 #if defined(ANDROID_PLATFORM)
5127     return false;
5128 #else
5129     return true;
5130 #endif
5131 }
5132 
5133 int32_t TextFieldPattern::GetNakedCharPosition() const
5134 {
5135     if (IsTextArea() || !IsInPasswordMode() || obscureTickCountDown_ <= 0 || !GetTextObscured()) {
5136         return -1;
5137     }
5138     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
5139     CHECK_NULL_RETURN(layoutProperty, -1);
5140     auto content = layoutProperty->GetValueValue("");
5141     if (content.empty()) {
5142         return -1;
5143     }
5144     return nakedCharPosition_;
5145 }
5146 
5147 std::string TextFieldPattern::TextInputTypeToString() const
5148 {
5149     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
5150     CHECK_NULL_RETURN(layoutProperty, "");
5151     switch (layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED)) {
5152         case TextInputType::NUMBER:
5153             return "InputType.Number";
5154         case TextInputType::EMAIL_ADDRESS:
5155             return "InputType.Email";
5156         case TextInputType::VISIBLE_PASSWORD:
5157             return "InputType.Password";
5158         default:
5159             return "InputType.Normal";
5160     }
5161 }
5162 
5163 std::string TextFieldPattern::TextInputActionToString() const
5164 {
5165     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
5166     CHECK_NULL_RETURN(layoutProperty, "");
5167     switch (GetTextInputActionValue(TextInputAction::DONE)) {
5168         case TextInputAction::GO:
5169             return "EnterKeyType.Go";
5170         case TextInputAction::SEARCH:
5171             return "EnterKeyType.Search";
5172         case TextInputAction::SEND:
5173             return "EnterKeyType.Send";
5174         case TextInputAction::NEXT:
5175             return "EnterKeyType.Next";
5176         default:
5177             return "EnterKeyType.Done";
5178     }
5179 }
5180 
5181 std::string TextFieldPattern::GetPlaceholderFont() const
5182 {
5183     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
5184     CHECK_NULL_RETURN(layoutProperty, "");
5185     auto tmpHost = GetHost();
5186     CHECK_NULL_RETURN(tmpHost, "");
5187     auto context = tmpHost->GetContext();
5188     CHECK_NULL_RETURN(context, "");
5189     auto theme = context->GetTheme<TextFieldTheme>();
5190     CHECK_NULL_RETURN(theme, "");
5191     auto jsonValue = JsonUtil::Create(true);
5192     if (layoutProperty->GetPlaceholderItalicFontStyle().value_or(Ace::FontStyle::NORMAL) == Ace::FontStyle::NORMAL) {
5193         jsonValue->Put("style", "FontStyle.Normal");
5194     } else {
5195         jsonValue->Put("style", "FontStyle.Italic");
5196     }
5197     // placeholder font size not exist in theme, use normal font size by default
5198     if (!layoutProperty->GetPlaceholderFontSize()) {
5199         jsonValue->Put("size", GetFontSize().c_str());
5200     } else {
5201         jsonValue->Put("size", layoutProperty->GetPlaceholderFontSize()->ToString().c_str());
5202     }
5203     auto weight = layoutProperty->GetPlaceholderFontWeightValue(theme->GetFontWeight());
5204     switch (weight) {
5205         case FontWeight::W100:
5206             jsonValue->Put("weight", "100");
5207             break;
5208         case FontWeight::W200:
5209             jsonValue->Put("weight", "200");
5210             break;
5211         case FontWeight::W300:
5212             jsonValue->Put("weight", "300");
5213             break;
5214         case FontWeight::W400:
5215             jsonValue->Put("weight", "400");
5216             break;
5217         case FontWeight::W500:
5218             jsonValue->Put("weight", "500");
5219             break;
5220         case FontWeight::W600:
5221             jsonValue->Put("weight", "600");
5222             break;
5223         case FontWeight::W700:
5224             jsonValue->Put("weight", "700");
5225             break;
5226         case FontWeight::W800:
5227             jsonValue->Put("weight", "800");
5228             break;
5229         case FontWeight::W900:
5230             jsonValue->Put("weight", "900");
5231             break;
5232         default:
5233             jsonValue->Put("fontWeight", V2::ConvertWrapFontWeightToStirng(weight).c_str());
5234     }
5235     auto family = layoutProperty->GetPlaceholderFontFamilyValue({ "sans-serif" });
5236     std::string jsonFamily = ConvertFontFamily(family);
5237     jsonValue->Put("fontFamily", jsonFamily.c_str());
5238     return jsonValue->ToString();
5239 }
5240 
5241 RefPtr<TextFieldTheme> TextFieldPattern::GetTheme() const
5242 {
5243     auto tmpHost = GetHost();
5244     CHECK_NULL_RETURN(tmpHost, nullptr);
5245     auto context = tmpHost->GetContext();
5246     CHECK_NULL_RETURN(context, nullptr);
5247     auto theme = context->GetTheme<TextFieldTheme>();
5248     return theme;
5249 }
5250 
5251 std::string TextFieldPattern::GetTextColor() const
5252 {
5253     auto theme = GetTheme();
5254     CHECK_NULL_RETURN(theme, "");
5255     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
5256     CHECK_NULL_RETURN(layoutProperty, "");
5257     return layoutProperty->GetTextColorValue(theme->GetTextColor()).ColorToString();
5258 }
5259 
5260 std::string TextFieldPattern::GetCaretColor() const
5261 {
5262     auto theme = GetTheme();
5263     CHECK_NULL_RETURN(theme, "");
5264     auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
5265     CHECK_NULL_RETURN(paintProperty, "");
5266     return paintProperty->GetCursorColorValue(theme->GetCursorColor()).ColorToString();
5267 }
5268 
5269 std::string TextFieldPattern::GetPlaceholderColor() const
5270 {
5271     auto theme = GetTheme();
5272     CHECK_NULL_RETURN(theme, "");
5273     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
5274     CHECK_NULL_RETURN(layoutProperty, "");
5275     return layoutProperty->GetPlaceholderTextColorValue(theme->GetTextColor()).ColorToString();
5276 }
5277 
5278 std::string TextFieldPattern::GetFontSize() const
5279 {
5280     auto theme = GetTheme();
5281     CHECK_NULL_RETURN(theme, "");
5282     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
5283     CHECK_NULL_RETURN(layoutProperty, "");
5284     return layoutProperty->GetFontSizeValue(theme->GetFontSize()).ToString();
5285 }
5286 
5287 Ace::FontStyle TextFieldPattern::GetItalicFontStyle() const
5288 {
5289     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
5290     CHECK_NULL_RETURN(layoutProperty, Ace::FontStyle::NORMAL);
5291     return layoutProperty->GetItalicFontStyle().value_or(Ace::FontStyle::NORMAL);
5292 }
5293 
5294 std::string TextFieldPattern::GetShowPasswordIconString() const
5295 {
5296     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
5297     CHECK_NULL_RETURN(layoutProperty, "false");
5298     return layoutProperty->GetShowPasswordIconValue(false) ? "true" : "false";
5299 }
5300 
5301 std::string TextFieldPattern::GetInputStyleString() const
5302 {
5303     std::string result = isTextInput_ ? "TextInputStyle.Default" : "TextContentStyle.DEFAULT";
5304     auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
5305     CHECK_NULL_RETURN(paintProperty, result);
5306     switch (paintProperty->GetInputStyleValue(InputStyle::DEFAULT)) {
5307         case InputStyle::INLINE:
5308             result = isTextInput_ ? "TextInputStyle.Inline" : "TextContentStyle.INLINE";
5309             break;
5310         case InputStyle::DEFAULT:
5311         default:
5312             break;
5313     }
5314     return result;
5315 }
5316 
5317 FontWeight TextFieldPattern::GetFontWeight() const
5318 {
5319     auto theme = GetTheme();
5320     CHECK_NULL_RETURN(theme, FontWeight::NORMAL);
5321     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
5322     CHECK_NULL_RETURN(layoutProperty, FontWeight::NORMAL);
5323     return layoutProperty->GetFontWeightValue(theme->GetFontWeight());
5324 }
5325 
5326 std::string TextFieldPattern::GetFontFamily() const
5327 {
5328     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
5329     CHECK_NULL_RETURN(layoutProperty, "HarmonyOS Sans");
5330     auto family = layoutProperty->GetFontFamilyValue({ "HarmonyOS Sans" });
5331     return ConvertFontFamily(family);
5332 }
5333 
5334 TextAlign TextFieldPattern::GetTextAlign() const
5335 {
5336     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
5337     CHECK_NULL_RETURN(layoutProperty, TextAlign::START);
5338     return layoutProperty->GetTextAlign().value_or(TextAlign::START);
5339 }
5340 
5341 uint32_t TextFieldPattern::GetMaxLength() const
5342 {
5343     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
5344     CHECK_NULL_RETURN(layoutProperty, Infinity<uint32_t>());
5345     return layoutProperty->HasMaxLength() ? layoutProperty->GetMaxLengthValue(Infinity<uint32_t>())
5346                                           : Infinity<uint32_t>();
5347 }
5348 
5349 uint32_t TextFieldPattern::GetMaxLines() const
5350 {
5351     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
5352     CHECK_NULL_RETURN(layoutProperty, Infinity<uint32_t>());
5353     auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
5354     CHECK_NULL_RETURN(paintProperty, Infinity<uint32_t>());
5355     if (IsNormalInlineState()) {
5356         return layoutProperty->GetMaxViewLinesValue(INLINE_DEFAULT_VIEW_MAXLINE);
5357     }
5358     return layoutProperty->HasMaxLines() ? layoutProperty->GetMaxLinesValue(Infinity<uint32_t>())
5359                                          : Infinity<uint32_t>();
5360 }
5361 
5362 std::string TextFieldPattern::GetPlaceHolder() const
5363 {
5364     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
5365     CHECK_NULL_RETURN(layoutProperty, "");
5366     return layoutProperty->GetPlaceholderValue("");
5367 }
5368 
5369 std::string TextFieldPattern::GetInputFilter() const
5370 {
5371     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
5372     CHECK_NULL_RETURN(layoutProperty, "");
5373     return layoutProperty->GetInputFilterValue("");
5374 }
5375 
5376 std::string TextFieldPattern::GetErrorTextString() const
5377 {
5378     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
5379     CHECK_NULL_RETURN(layoutProperty, "");
5380     return layoutProperty->GetErrorTextValue("");
5381 }
5382 
5383 bool TextFieldPattern::GetErrorTextState() const
5384 {
5385     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
5386     CHECK_NULL_RETURN(layoutProperty, false);
5387     return layoutProperty->GetShowErrorTextValue(false);
5388 }
5389 
5390 bool TextFieldPattern::IsSearchParentNode() const
5391 {
5392     auto tmpHost = GetHost();
5393     CHECK_NULL_RETURN(tmpHost, false);
5394     auto parentFrameNode = AceType::DynamicCast<FrameNode>(tmpHost->GetParent());
5395     return parentFrameNode && parentFrameNode->GetTag() == V2::SEARCH_ETS_TAG;
5396 }
5397 
5398 void TextFieldPattern::SearchRequestKeyboard()
5399 {
5400     StartTwinkling();
5401     caretUpdateType_ = CaretUpdateType::PRESSED;
5402     selectionMode_ = SelectionMode::NONE;
5403     if (RequestKeyboard(false, true, true)) {
5404         auto tmpHost = GetHost();
5405         CHECK_NULL_VOID(tmpHost);
5406         auto eventHub = tmpHost->GetEventHub<TextFieldEventHub>();
5407         CHECK_NULL_VOID(eventHub);
5408         eventHub->FireOnEditChanged(true);
5409     }
5410 }
5411 
5412 std::string TextFieldPattern::GetCopyOptionString() const
5413 {
5414     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
5415     CHECK_NULL_RETURN(layoutProperty, "");
5416     std::string copyOptionString = "CopyOptions.None";
5417     switch (layoutProperty->GetCopyOptionsValue(CopyOptions::None)) {
5418         case CopyOptions::InApp:
5419             copyOptionString = "CopyOptions.InApp";
5420             break;
5421         case CopyOptions::Local:
5422             copyOptionString = "CopyOptions.Local";
5423             break;
5424         case CopyOptions::Distributed:
5425             copyOptionString = "CopyOptions.Distributed";
5426             break;
5427         case CopyOptions::None:
5428         default:
5429             break;
5430     }
5431     return copyOptionString;
5432 }
5433 
5434 std::string TextFieldPattern::GetBarStateString() const
5435 {
5436     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
5437     CHECK_NULL_RETURN(layoutProperty, "");
5438     std::string displayModeString;
5439     switch (layoutProperty->GetDisplayModeValue(DisplayMode::AUTO)) {
5440         case DisplayMode::OFF:
5441             displayModeString = "BarState.OFF";
5442             break;
5443         case DisplayMode::ON:
5444             displayModeString = "BarState.ON";
5445             break;
5446         case DisplayMode::AUTO:
5447         default:
5448             displayModeString = "BarState.AUTO";
5449             break;
5450     }
5451     return displayModeString;
5452 }
5453 
5454 void TextFieldPattern::UpdateScrollBarOffset()
5455 {
5456     if (textEditingValue_.text.empty()) {
5457         return;
5458     }
5459     if (!GetScrollBar() && !GetScrollBarProxy()) {
5460         return;
5461     }
5462     auto tmpHost = GetHost();
5463     CHECK_NULL_VOID(tmpHost);
5464     auto paddingHeight = GetPaddingTop() + GetPaddingBottom();
5465     auto paddingRight = GetPaddingRight();
5466     auto contentHeight = contentRect_.Height();
5467     if (inlineFocusState_) {
5468         paddingHeight = 0.0f;
5469         paddingRight = 0.0f;
5470         contentHeight = GetSingleLineHeight() * GetMaxLines();
5471     }
5472     Size size(contentRect_.Width() + paddingRight, contentHeight + paddingHeight);
5473     UpdateScrollBarRegion(
5474         contentRect_.GetY() - textRect_.GetY(), textRect_.Height() + paddingHeight, size, Offset(0.0, 0.0));
5475     tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
5476 }
5477 
5478 bool TextFieldPattern::OnScrollCallback(float offset, int32_t source)
5479 {
5480     if (source == SCROLL_FROM_START) {
5481         auto scrollBar = GetScrollBar();
5482         if (scrollBar) {
5483             scrollBar->PlayScrollBarStartAnimation();
5484         }
5485         auto selectOverlayProxy = GetSelectOverlay();
5486         if (selectOverlayProxy) {
5487             if (selectOverlayProxy->IsHandleShow()) {
5488                 originalIsMenuShow_ = selectOverlayProxy->IsMenuShow();
5489             }
5490             selectOverlayProxy->ShowOrHiddenMenu(true);
5491         }
5492         return true;
5493     }
5494     OnTextInputScroll(offset);
5495     OnTextAreaScroll(offset);
5496     return true;
5497 }
5498 
5499 void TextFieldPattern::CheckScrollable()
5500 {
5501     auto host = GetHost();
5502     CHECK_NULL_VOID(host);
5503     auto hub = host->GetEventHub<EventHub>();
5504     CHECK_NULL_VOID(hub);
5505     auto gestureHub = hub->GetOrCreateGestureEventHub();
5506     CHECK_NULL_VOID(gestureHub);
5507     auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
5508     CHECK_NULL_VOID(layoutProperty);
5509 
5510     if (textEditingValue_.text.empty()) {
5511         scrollable_ = false;
5512     } else {
5513         if (layoutProperty->GetShowCounterValue(false) && counterParagraph_ && !isCounterIdealheight_ &&
5514             !IsNormalInlineState()) {
5515             scrollable_ = GreatNotEqual(textRect_.Height(), contentRect_.Height() - counterParagraph_->GetHeight());
5516         } else {
5517             scrollable_ = GreatNotEqual(textRect_.Height(), contentRect_.Height());
5518         }
5519     }
5520     SetScrollEnable(scrollable_);
5521 }
5522 
5523 bool TextFieldPattern::HasStateStyle(UIState state) const
5524 {
5525     auto host = GetHost();
5526     CHECK_NULL_RETURN(host, false);
5527     auto hub = host->GetEventHub<EventHub>();
5528     CHECK_NULL_RETURN(hub, false);
5529     return hub->HasStateStyle(state);
5530 }
5531 
5532 double TextFieldPattern::GetScrollBarWidth()
5533 {
5534     auto scrollBar = GetScrollBar();
5535     double scrollBarWidth = 0.0;
5536     if (scrollBar) {
5537         scrollBarWidth = scrollBar->GetBarRect().Width();
5538     }
5539     return scrollBarWidth;
5540 }
5541 
5542 void TextFieldPattern::SetUnitNode(const RefPtr<NG::UINode>& unitNode)
5543 {
5544     auto host = GetHost();
5545     CHECK_NULL_VOID(host);
5546     CHECK_NULL_VOID(unitNode);
5547     if (host->GetChildren().size() != 0) {
5548         host->Clean();
5549     }
5550     unitNode->MountToParent(host);
5551 }
5552 
5553 void TextFieldPattern::SetShowError()
5554 {
5555     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
5556     CHECK_NULL_VOID(layoutProperty);
5557     auto passWordMode =
5558         layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED) == TextInputType::VISIBLE_PASSWORD;
5559     auto pipeline = PipelineBase::GetCurrentContext();
5560     CHECK_NULL_VOID(pipeline);
5561     auto themeManager = pipeline->GetThemeManager();
5562     CHECK_NULL_VOID(themeManager);
5563     auto textFieldTheme = themeManager->GetTheme<TextFieldTheme>();
5564     CHECK_NULL_VOID(textFieldTheme);
5565     auto tmpHost = GetHost();
5566     CHECK_NULL_VOID(tmpHost);
5567     auto renderContext = tmpHost->GetRenderContext();
5568     CHECK_NULL_VOID(renderContext);
5569     auto visible = layoutProperty->GetShowErrorTextValue(false);
5570     auto inputType = layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED);
5571 
5572     if (visible && layoutProperty->GetShowUnderlineValue(false) && inputType == TextInputType::UNSPECIFIED) {
5573         underlineColor_ = textFieldTheme->GetErrorUnderlineColor();
5574         underlineWidth_ = ERROR_UNDERLINE_WIDTH;
5575         preErrorState_ = true;
5576     }
5577     if (!visible && layoutProperty->GetShowUnderlineValue(false) && inputType == TextInputType::UNSPECIFIED) {
5578         underlineColor_ = textFieldTheme->GetUnderlineColor();
5579         underlineWidth_ = UNDERLINE_WIDTH;
5580         preErrorState_ = false;
5581     }
5582     if (visible && passWordMode) {
5583         BorderWidthProperty borderWidth;
5584         BorderColorProperty borderColor;
5585         preErrorState_ = true;
5586         borderWidth.SetBorderWidth(ERROR_BORDER_WIDTH);
5587         layoutProperty->UpdateBorderWidth(borderWidth);
5588         borderColor.SetColor(textFieldTheme->GetPasswordErrorBorderColor());
5589         renderContext->UpdateBorderColor(borderColor);
5590         renderContext->UpdateBackgroundColor(textFieldTheme->GetPasswordErrorInputColor());
5591         layoutProperty->UpdateTextColor(textFieldTheme->GetPasswordErrorTextColor());
5592     }
5593     if (!visible && passWordMode) {
5594         layoutProperty->UpdateBorderWidth(passwordModeStyle_.borderwidth);
5595         renderContext->UpdateBorderColor(passwordModeStyle_.borderColor);
5596         renderContext->UpdateBackgroundColor(passwordModeStyle_.bgColor);
5597         layoutProperty->UpdateTextColor(passwordModeStyle_.textColor);
5598         preErrorState_ = false;
5599     }
5600     if (visible && !passWordMode) {
5601         layoutProperty->UpdateBorderWidth(passwordModeStyle_.borderwidth);
5602         renderContext->UpdateBorderColor(passwordModeStyle_.borderColor);
5603         renderContext->UpdateBackgroundColor(passwordModeStyle_.bgColor);
5604         layoutProperty->UpdateTextColor(passwordModeStyle_.textColor);
5605         preErrorState_ = true;
5606     }
5607     UpdateErrorTextMargin();
5608 }
5609 
5610 void TextFieldPattern::UpdateErrorTextMargin()
5611 {
5612     auto tmpHost = GetHost();
5613     CHECK_NULL_VOID(tmpHost);
5614     auto renderContext = tmpHost->GetRenderContext();
5615     CHECK_NULL_VOID(renderContext);
5616     auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
5617     CHECK_NULL_VOID(layoutProperty);
5618     MarginProperty errorMargin;
5619     if (layoutProperty->GetShowErrorTextValue(false) && (preErrorMargin_ < ERROR_TEXT_CAPSULE_MARGIN)) {
5620         errorMargin.bottom = CalcLength(ERROR_TEXT_CAPSULE_MARGIN);
5621         layoutProperty->UpdateMargin(errorMargin);
5622         restoreMarginState_ = true;
5623     } else if (restoreMarginState_ == true) {
5624         errorMargin.bottom = CalcLength(preErrorMargin_);
5625         layoutProperty->UpdateMargin(errorMargin);
5626         restoreMarginState_ = false;
5627     }
5628 }
5629 
5630 void TextFieldPattern::SavePasswordModeStates()
5631 {
5632     auto tmpHost = GetHost();
5633     CHECK_NULL_VOID(tmpHost);
5634     auto renderContext = tmpHost->GetRenderContext();
5635     CHECK_NULL_VOID(renderContext);
5636     auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
5637     CHECK_NULL_VOID(layoutProperty);
5638     auto pipeline = PipelineContext::GetCurrentContext();
5639     CHECK_NULL_VOID(pipeline);
5640     auto themeManager = pipeline->GetThemeManager();
5641     CHECK_NULL_VOID(themeManager);
5642     auto textFieldTheme = themeManager->GetTheme<TextFieldTheme>();
5643     CHECK_NULL_VOID(textFieldTheme);
5644     preErrorMargin_ = GetMarginBottom();
5645     passwordModeStyle_.bgColor = renderContext->GetBackgroundColor().value_or(textFieldTheme->GetBgColor());
5646     passwordModeStyle_.textColor = layoutProperty->GetTextColorValue(textFieldTheme->GetTextColor());
5647     if (layoutProperty->GetBorderWidthProperty() != nullptr) {
5648         passwordModeStyle_.borderwidth = *(layoutProperty->GetBorderWidthProperty());
5649     } else {
5650         BorderWidthProperty borderWidth;
5651         borderWidth.SetBorderWidth(BORDER_DEFAULT_WIDTH);
5652         passwordModeStyle_.borderwidth = borderWidth;
5653     }
5654     BorderColorProperty borderColor;
5655     borderColor.SetColor(Color::TRANSPARENT);
5656     passwordModeStyle_.borderColor = renderContext->GetBorderColor().value_or(borderColor);
5657     auto radius = textFieldTheme->GetBorderRadius();
5658     BorderRadiusProperty borderRadius { radius.GetX(), radius.GetY(), radius.GetY(), radius.GetX() };
5659     passwordModeStyle_.radius = renderContext->GetBorderRadius().value_or(borderRadius);
5660 
5661     const auto& paddingProperty = layoutProperty->GetPaddingProperty();
5662     if (paddingProperty) {
5663         passwordModeStyle_.padding.left = CalcLength(paddingProperty->left->GetDimension().ConvertToPx());
5664         passwordModeStyle_.padding.top = CalcLength(paddingProperty->top->GetDimension().ConvertToPx());
5665         passwordModeStyle_.padding.bottom = CalcLength(paddingProperty->bottom->GetDimension().ConvertToPx());
5666         passwordModeStyle_.padding.right = CalcLength(paddingProperty->right->GetDimension().ConvertToPx());
5667     } else {
5668         passwordModeStyle_.padding.left = CalcLength(0.0);
5669         passwordModeStyle_.padding.top = CalcLength(0.0);
5670         passwordModeStyle_.padding.bottom = CalcLength(0.0);
5671         passwordModeStyle_.padding.right = CalcLength(0.0);
5672     }
5673 }
5674 
5675 void TextFieldPattern::SaveUnderlineStates()
5676 {
5677     auto tmpHost = GetHost();
5678     CHECK_NULL_VOID(tmpHost);
5679     auto renderContext = tmpHost->GetRenderContext();
5680     CHECK_NULL_VOID(renderContext);
5681     Radius radius;
5682     BorderRadiusProperty borderRadius { radius.GetX(), radius.GetY(), radius.GetY(), radius.GetX() };
5683     borderRadius_ = renderContext->GetBorderRadius().value_or(borderRadius);
5684 }
5685 
5686 void TextFieldPattern::ApplyUnderlineStates()
5687 {
5688     auto tmpHost = GetHost();
5689     CHECK_NULL_VOID(tmpHost);
5690     auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
5691     CHECK_NULL_VOID(layoutProperty);
5692     auto renderContext = tmpHost->GetRenderContext();
5693     CHECK_NULL_VOID(renderContext);
5694     auto theme = GetTheme();
5695     CHECK_NULL_VOID(theme);
5696     renderContext->UpdateBackgroundColor(Color::TRANSPARENT);
5697     CalcSize idealSize;
5698     layoutProperty->UpdatePadding({ CalcLength(UNDERLINE_NORMAL_PADDING), CalcLength(UNDERLINE_NORMAL_PADDING),
5699         CalcLength(0.0_vp), CalcLength(0.0_vp) });
5700     ProcessInnerPadding();
5701     if (layoutProperty->GetPropertyChangeFlag() == PROPERTY_UPDATE_NORMAL) {
5702         std::optional<CalcLength> height(UNDERLINE_NORMAL_HEIGHT);
5703         idealSize.SetHeight(height);
5704         layoutProperty->UpdateUserDefinedIdealSize(idealSize);
5705     }
5706     layoutProperty->UpdateFontSize(theme->GetUnderlineFontSize());
5707     if (!layoutProperty->HasTextColor()) {
5708         layoutProperty->UpdateTextColor(theme->GetUnderlineTextColor());
5709     }
5710     Radius radius;
5711     renderContext->UpdateBorderRadius({ radius.GetX(), radius.GetY(), radius.GetY(), radius.GetX() });
5712 }
5713 
5714 float TextFieldPattern::GetMarginBottom() const
5715 {
5716     auto tmpHost = GetHost();
5717     CHECK_NULL_RETURN(tmpHost, 0.0f);
5718     auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
5719     CHECK_NULL_RETURN(layoutProperty, 0.0f);
5720     auto& getMargin = layoutProperty->GetMarginProperty();
5721     if (getMargin && getMargin->bottom.has_value()) {
5722         return getMargin->bottom->GetDimension().ConvertToPx();
5723     }
5724     return 0.0f;
5725 }
5726 
5727 std::string TextFieldPattern::GetShowResultImageSrc() const
5728 {
5729     auto tmpHost = GetHost();
5730     CHECK_NULL_RETURN(tmpHost, "");
5731     auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
5732     CHECK_NULL_RETURN(layoutProperty, "");
5733     if (showUserDefinedIcon_) {
5734         return showUserDefinedIconSrc_;
5735     }
5736     return SHOW_PASSWORD_SVG;
5737 }
5738 
5739 std::string TextFieldPattern::GetHideResultImageSrc() const
5740 {
5741     auto tmpHost = GetHost();
5742     CHECK_NULL_RETURN(tmpHost, "");
5743     auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
5744     CHECK_NULL_RETURN(layoutProperty, "");
5745     if (hideUserDefinedIcon_) {
5746         return hideUserDefinedIconSrc_;
5747     }
5748     return HIDE_PASSWORD_SVG;
5749 }
5750 
5751 void TextFieldPattern::SaveInlineStates()
5752 {
5753     auto tmpHost = GetHost();
5754     CHECK_NULL_VOID(tmpHost);
5755     auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
5756     CHECK_NULL_VOID(layoutProperty);
5757     auto renderContext = tmpHost->GetRenderContext();
5758     CHECK_NULL_VOID(renderContext);
5759     auto theme = GetTheme();
5760     CHECK_NULL_VOID(theme);
5761     inlineState_.textColor = layoutProperty->GetTextColorValue(theme->GetTextColor());
5762     inlineState_.bgColor = renderContext->GetBackgroundColor().value_or(theme->GetBgColor());
5763     auto radius = theme->GetBorderRadius();
5764     BorderRadiusProperty borderRadius { radius.GetX(), radius.GetY(), radius.GetY(), radius.GetX() };
5765     inlineState_.radius = renderContext->GetBorderRadius().value_or(borderRadius);
5766     if (layoutProperty->GetBorderWidthProperty() != nullptr) {
5767         inlineState_.borderWidth = *(layoutProperty->GetBorderWidthProperty());
5768     } else {
5769         inlineState_.borderWidth.SetBorderWidth(BORDER_DEFAULT_WIDTH);
5770     }
5771     if (renderContext->HasBorderColor()) {
5772         inlineState_.borderColor = renderContext->GetBorderColor().value();
5773         inlineState_.hasBorderColor = true;
5774     }
5775     const auto& paddingProperty = layoutProperty->GetPaddingProperty();
5776     if (paddingProperty) {
5777         inlineState_.padding.left = CalcLength(paddingProperty->left->GetDimension().ConvertToPx());
5778         inlineState_.padding.top = CalcLength(paddingProperty->top->GetDimension().ConvertToPx());
5779         inlineState_.padding.bottom = CalcLength(paddingProperty->bottom->GetDimension().ConvertToPx());
5780         inlineState_.padding.right = CalcLength(paddingProperty->right->GetDimension().ConvertToPx());
5781     } else {
5782         inlineState_.padding.left = CalcLength(0.0_vp);
5783         inlineState_.padding.top = CalcLength(0.0_vp);
5784         inlineState_.padding.bottom = CalcLength(0.0_vp);
5785         inlineState_.padding.right = CalcLength(0.0_vp);
5786     }
5787     const auto& marginProperty = layoutProperty->GetMarginProperty();
5788     if (marginProperty) {
5789         inlineState_.margin.left = CalcLength(marginProperty->left->GetDimension().ConvertToPx());
5790         inlineState_.margin.top = CalcLength(marginProperty->top->GetDimension().ConvertToPx());
5791         inlineState_.margin.bottom = CalcLength(marginProperty->bottom->GetDimension().ConvertToPx());
5792         inlineState_.margin.right = CalcLength(marginProperty->right->GetDimension().ConvertToPx());
5793     } else {
5794         inlineState_.margin.left = CalcLength(0.0_vp);
5795         inlineState_.margin.top = CalcLength(0.0_vp);
5796         inlineState_.margin.bottom = CalcLength(0.0_vp);
5797         inlineState_.margin.right = CalcLength(0.0_vp);
5798     }
5799     if (inlineState_.saveInlineState) {
5800         inlineState_.frameRect = frameRect_;
5801     }
5802 }
5803 
5804 void TextFieldPattern::TextIsEmptyRect(RectF& rect)
5805 {
5806     auto tmpHost = GetHost();
5807     CHECK_NULL_VOID(tmpHost);
5808     auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
5809     CHECK_NULL_VOID(layoutProperty);
5810     if (GetEditingValue().text.empty()) {
5811         switch (layoutProperty->GetTextAlignValue(TextAlign::START)) {
5812             case TextAlign::START:
5813                 break;
5814             case TextAlign::CENTER:
5815                 rect.SetLeft(static_cast<float>(rect.GetX()) + contentRect_.Width() / 2.0f);
5816                 break;
5817             case TextAlign::END:
5818                 rect.SetLeft(static_cast<float>(rect.GetX()) + contentRect_.Width() -
5819                              static_cast<float>(CURSOR_WIDTH.ConvertToPx()));
5820                 break;
5821             default:
5822                 break;
5823         }
5824         return;
5825     }
5826 }
5827 
5828 void TextFieldPattern::TextAreaInputRectUpdate(RectF& rect)
5829 {
5830     auto tmpHost = GetHost();
5831     CHECK_NULL_VOID(tmpHost);
5832     auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
5833     CHECK_NULL_VOID(layoutProperty);
5834     if (IsTextArea() && !GetEditingValue().text.empty()) {
5835         auto inputContentWidth = GetParagraph()->GetMaxIntrinsicWidth();
5836         switch (layoutProperty->GetTextAlignValue(TextAlign::START)) {
5837             case TextAlign::START:
5838                 if (inputContentWidth < contentRect_.Width()) {
5839                     rect.SetWidth(inputContentWidth);
5840                 }
5841                 break;
5842             case TextAlign::CENTER:
5843                 if (inputContentWidth < contentRect_.Width()) {
5844                     rect.SetLeft(
5845                         static_cast<float>(rect.GetX()) + contentRect_.Width() / 2.0f - inputContentWidth / 2.0f);
5846                     rect.SetWidth(inputContentWidth);
5847                 }
5848                 break;
5849             case TextAlign::END:
5850                 if (inputContentWidth < contentRect_.Width()) {
5851                     rect.SetLeft(static_cast<float>(rect.GetX()) + contentRect_.Width() -
5852                                  static_cast<float>(CURSOR_WIDTH.ConvertToPx()) - inputContentWidth);
5853                     rect.SetWidth(inputContentWidth);
5854                 }
5855                 break;
5856             default:
5857                 break;
5858         }
5859     }
5860 }
5861 
5862 void TextFieldPattern::UpdateRectByAlignment(RectF& rect)
5863 {
5864     auto tmpHost = GetHost();
5865     CHECK_NULL_VOID(tmpHost);
5866     auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
5867     CHECK_NULL_VOID(layoutProperty);
5868     auto alignment = layoutProperty->GetPositionProperty()
5869                          ? layoutProperty->GetPositionProperty()->GetAlignment().value_or(Alignment::CENTER)
5870                          : Alignment::CENTER;
5871     if (alignment == Alignment::CENTER_LEFT || alignment == Alignment::CENTER || alignment == Alignment::CENTER_RIGHT) {
5872         rect.SetTop(frameRect_.Height() / 2.0f - rect.Height() / 2.0f);
5873     } else if (alignment == Alignment::BOTTOM_LEFT || alignment == Alignment::BOTTOM_CENTER ||
5874                alignment == Alignment::BOTTOM_RIGHT) {
5875         rect.SetTop(frameRect_.Height() - rect.Height());
5876     } else if (alignment == Alignment::TOP_LEFT || alignment == Alignment::TOP_CENTER ||
5877                alignment == Alignment::TOP_RIGHT) {
5878         rect.SetTop(0);
5879     } else {
5880     }
5881     if (rect.Height() > contentRect_.Height()) {
5882         rect.SetTop(textRect_.GetY());
5883     }
5884 }
5885 
5886 void TextFieldPattern::ApplyInlineStates(bool focusStatus)
5887 {
5888     auto tmpHost = GetHost();
5889     CHECK_NULL_VOID(tmpHost);
5890     auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
5891     CHECK_NULL_VOID(layoutProperty);
5892     auto renderContext = tmpHost->GetRenderContext();
5893     CHECK_NULL_VOID(renderContext);
5894     auto pipeline = PipelineContext::GetCurrentContext();
5895     CHECK_NULL_VOID(pipeline);
5896     auto theme = pipeline->GetTheme<TextFieldTheme>();
5897     CHECK_NULL_VOID(theme);
5898     layoutProperty->UpdateTextColor(theme->GetInlineTextColor());
5899     auto radius = theme->GetInlineRadiusSize();
5900     renderContext->UpdateBorderRadius({ radius.GetX(), radius.GetY(), radius.GetY(), radius.GetX() });
5901     renderContext->UpdateBackgroundColor(theme->GetInlineBgColor());
5902     BorderWidthProperty inlineBorderWidth;
5903     inlineBorderWidth.SetBorderWidth(INLINE_BORDER_WIDTH);
5904     layoutProperty->UpdateBorderWidth(inlineBorderWidth);
5905     renderContext->UpdateBorderWidth(inlineBorderWidth);
5906     BorderColorProperty inlineBorderColor;
5907     inlineBorderColor.SetColor(theme->GetInlineBorderColor());
5908     renderContext->UpdateBorderColor(inlineBorderColor);
5909     auto padding = theme->GetInlineBorderWidth();
5910     layoutProperty->UpdatePadding(
5911         { CalcLength(padding), CalcLength(padding), CalcLength(padding), CalcLength(padding) });
5912     ProcessInnerPadding();
5913     SetTextRectOffset();
5914     MarginProperty margin;
5915     margin.bottom =
5916         CalcLength(inlineState_.padding.bottom->GetDimension() + inlineState_.margin.bottom->GetDimension());
5917     margin.right = CalcLength(inlineState_.padding.right->GetDimension() + inlineState_.margin.right->GetDimension());
5918     margin.left = CalcLength(inlineState_.padding.left->GetDimension() + inlineState_.margin.left->GetDimension());
5919     margin.top = CalcLength(inlineState_.padding.top->GetDimension() + inlineState_.margin.top->GetDimension());
5920     layoutProperty->UpdateMargin(margin);
5921     CalcSize idealSize;
5922     inlinePadding_ = padding.ConvertToPx() + padding.ConvertToPx();
5923     if (focusStatus) {
5924         previewWidth_ = paragraph_->GetLongestLine() + inlinePadding_;
5925         std::optional<CalcLength> width(previewWidth_);
5926         idealSize.SetWidth(width);
5927     } else {
5928         std::optional<CalcLength> width(previewWidth_);
5929         idealSize.SetWidth(width);
5930     }
5931     layoutProperty->UpdateUserDefinedIdealSize(idealSize);
5932     auto&& layoutConstraint = layoutProperty->GetCalcLayoutConstraint();
5933     if (layoutConstraint && layoutConstraint->selfIdealSize && layoutConstraint->selfIdealSize->Height()) {
5934         layoutProperty->ClearUserDefinedIdealSize(false, true);
5935         inlineState_.setHeight = true;
5936     }
5937     if (!IsTextArea()) {
5938         layoutProperty->ResetMaxLines();
5939     }
5940 }
5941 
5942 bool TextFieldPattern::ResetObscureTickCountDown()
5943 {
5944     auto oldTickCountDown_ = obscureTickCountDown_;
5945     if (!IsTextArea() && GetTextObscured() && IsInPasswordMode()) {
5946         obscureTickCountDown_ = 0;
5947     }
5948     return oldTickCountDown_ != obscureTickCountDown_;
5949 }
5950 
5951 bool TextFieldPattern::IsInPasswordMode() const
5952 {
5953     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
5954     CHECK_NULL_RETURN(layoutProperty, false);
5955     return layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED) == TextInputType::VISIBLE_PASSWORD;
5956 }
5957 
5958 void TextFieldPattern::RestorePreInlineStates()
5959 {
5960     auto tmpHost = GetHost();
5961     CHECK_NULL_VOID(tmpHost);
5962     auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
5963     CHECK_NULL_VOID(layoutProperty);
5964     auto renderContext = tmpHost->GetRenderContext();
5965     CHECK_NULL_VOID(renderContext);
5966     auto pipeline = PipelineContext::GetCurrentContext();
5967     CHECK_NULL_VOID(pipeline);
5968     layoutProperty->UpdateTextColor(inlineState_.textColor);
5969     layoutProperty->UpdatePadding(inlineState_.padding);
5970     ProcessInnerPadding();
5971     inlinePadding_ = 0.0f;
5972     BorderWidthProperty currentBorderWidth;
5973     if (layoutProperty->GetBorderWidthProperty() != nullptr) {
5974         currentBorderWidth = *(layoutProperty->GetBorderWidthProperty());
5975     } else {
5976         currentBorderWidth.SetBorderWidth(BORDER_DEFAULT_WIDTH);
5977     }
5978     textRect_.SetOffset(OffsetF((GetPaddingLeft() + (float)(currentBorderWidth.leftDimen->ConvertToPx())),
5979                                 (GetPaddingTop() + (float)currentBorderWidth.topDimen->ConvertToPx())));
5980     if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
5981         textRect_.SetOffset(OffsetF(GetPaddingLeft(), GetPaddingTop()));
5982     }
5983     layoutProperty->UpdateMargin(inlineState_.margin);
5984     CalcSize idealSize;
5985     std::optional<CalcLength> width(inlineState_.frameRect.Width());
5986     idealSize.SetWidth(width);
5987     if (inlineState_.setHeight) {
5988         std::optional<CalcLength> height(inlineState_.frameRect.Height());
5989         idealSize.SetHeight(height);
5990     }
5991     layoutProperty->UpdateUserDefinedIdealSize(idealSize);
5992     renderContext->UpdateBackgroundColor(inlineState_.bgColor);
5993     layoutProperty->UpdateBorderWidth(inlineState_.borderWidth);
5994     renderContext->UpdateBorderWidth(inlineState_.borderWidth);
5995     renderContext->UpdateBorderRadius(inlineState_.radius);
5996     if (inlineState_.hasBorderColor) {
5997         renderContext->UpdateBorderColor(inlineState_.borderColor);
5998     }
5999     selectionMode_ = SelectionMode::NONE;
6000 }
6001 
6002 bool TextFieldPattern::IsNormalInlineState() const
6003 {
6004     auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
6005     CHECK_NULL_RETURN(paintProperty, false);
6006     auto tmpHost = GetHost();
6007     CHECK_NULL_RETURN(tmpHost, false);
6008     auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
6009     CHECK_NULL_RETURN(layoutProperty, false);
6010     return paintProperty->GetInputStyleValue(InputStyle::DEFAULT) == InputStyle::INLINE &&
6011            (layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED) == TextInputType::UNSPECIFIED ||
6012            layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED) == TextInputType::TEXT);
6013 }
6014 
6015 void TextFieldPattern::ToJsonValue(std::unique_ptr<JsonValue>& json) const
6016 {
6017     json->Put("placeholder", GetPlaceHolder().c_str());
6018     json->Put("text", textEditingValue_.text.c_str());
6019     json->Put("fontSize", GetFontSize().c_str());
6020     json->Put("fontColor", GetTextColor().c_str());
6021     json->Put("fontStyle", GetItalicFontStyle() == Ace::FontStyle::NORMAL ? "FontStyle.Normal" : "FontStyle.Italic");
6022     json->Put("fontWeight", V2::ConvertWrapFontWeightToStirng(GetFontWeight()).c_str());
6023     json->Put("fontFamily", GetFontFamily().c_str());
6024     json->Put("textAlign", V2::ConvertWrapTextAlignToString(GetTextAlign()).c_str());
6025     json->Put("caretColor", GetCaretColor().c_str());
6026     json->Put("type", TextInputTypeToString().c_str());
6027     json->Put("placeholderColor", GetPlaceholderColor().c_str());
6028     json->Put("placeholderFont", GetPlaceholderFont().c_str());
6029     json->Put("enterKeyType", TextInputActionToString().c_str());
6030     auto maxLength = GetMaxLength();
6031     json->Put("maxLength", GreatOrEqual(maxLength, Infinity<uint32_t>()) ? "INF" : std::to_string(maxLength).c_str());
6032     json->Put("inputFilter", GetInputFilter().c_str());
6033     json->Put("copyOption", GetCopyOptionString().c_str());
6034     json->Put("style", GetInputStyleString().c_str());
6035     auto jsonValue = JsonUtil::Create(true);
6036     jsonValue->Put("onIconSrc", GetShowResultImageSrc().c_str());
6037     jsonValue->Put("offIconSrc", GetHideResultImageSrc().c_str());
6038     json->Put("passwordIcon", jsonValue->ToString().c_str());
6039     json->Put("showError", GetErrorTextState() ? GetErrorTextString().c_str() : "undefined");
6040     auto maxLines = GetMaxLines();
6041     json->Put("maxLines", GreatOrEqual(maxLines, Infinity<uint32_t>()) ? "INF" : std::to_string(maxLines).c_str());
6042     json->Put("barState", GetBarStateString().c_str());
6043 }
6044 
6045 void TextFieldPattern::FromJson(const std::unique_ptr<JsonValue>& json)
6046 {
6047     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
6048     layoutProperty->UpdatePlaceholder(json->GetString("placeholder"));
6049     UpdateEditingValue(json->GetString("text"), StringUtils::StringToInt(json->GetString("caretPosition")));
6050     SetEditingValueToProperty(textEditingValue_.text);
6051     UpdateSelection(textEditingValue_.caretPosition);
6052     auto maxLines = json->GetString("maxLines");
6053     if (!maxLines.empty() && maxLines != "INF") {
6054         layoutProperty->UpdateMaxLines(StringUtils::StringToUint(maxLines));
6055     }
6056     static const std::unordered_map<std::string, CopyOptions> uMap = {
6057         { "CopyOptions.None", CopyOptions::None },
6058         { "CopyOptions.InApp", CopyOptions::InApp },
6059         { "CopyOptions.Local", CopyOptions::Local },
6060         { "CopyOptions.Distributed", CopyOptions::Distributed },
6061     };
6062     auto copyOption = json->GetString("copyOption");
6063     layoutProperty->UpdateCopyOptions(uMap.count(copyOption) ? uMap.at(copyOption) : CopyOptions::None);
6064     Pattern::FromJson(json);
6065 }
6066 
6067 void TextFieldPattern::SetAccessibilityAction()
6068 {
6069     auto host = GetHost();
6070     CHECK_NULL_VOID(host);
6071     auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
6072     CHECK_NULL_VOID(accessibilityProperty);
6073     accessibilityProperty->SetActionSetText([weakPtr = WeakClaim(this)](const std::string& value) {
6074         const auto& pattern = weakPtr.Upgrade();
6075         CHECK_NULL_VOID(pattern);
6076         pattern->InsertValue(value);
6077     });
6078 
6079     accessibilityProperty->SetActionSetSelection([weakPtr = WeakClaim(this)](int32_t start, int32_t end) {
6080         const auto& pattern = weakPtr.Upgrade();
6081         CHECK_NULL_VOID(pattern);
6082         pattern->SetSelectionFlag(start, end);
6083     });
6084 
6085     accessibilityProperty->SetActionCopy([weakPtr = WeakClaim(this)]() {
6086         const auto& pattern = weakPtr.Upgrade();
6087         CHECK_NULL_VOID(pattern);
6088         if (pattern->AllowCopy()) {
6089             pattern->HandleOnCopy();
6090             pattern->CloseSelectOverlay(true);
6091         }
6092     });
6093 
6094     accessibilityProperty->SetActionCut([weakPtr = WeakClaim(this)]() {
6095         const auto& pattern = weakPtr.Upgrade();
6096         CHECK_NULL_VOID(pattern);
6097         if (pattern->AllowCopy()) {
6098             pattern->HandleOnCut();
6099             pattern->CloseSelectOverlay(true);
6100         }
6101     });
6102 
6103     accessibilityProperty->SetActionPaste([weakPtr = WeakClaim(this)]() {
6104         const auto& pattern = weakPtr.Upgrade();
6105         CHECK_NULL_VOID(pattern);
6106         pattern->HandleOnPaste();
6107         pattern->CloseSelectOverlay(true);
6108     });
6109 
6110     accessibilityProperty->SetActionClearSelection([weakPtr = WeakClaim(this)]() {
6111         const auto& pattern = weakPtr.Upgrade();
6112         CHECK_NULL_VOID(pattern);
6113         auto current = pattern->GetTextSelector().GetEnd();
6114         pattern->SetInSelectMode(SelectionMode::NONE);
6115         pattern->UpdateSelection(current);
6116         pattern->SetSelectionFlag(current, current);
6117         pattern->CloseSelectOverlay(true);
6118         pattern->StartTwinkling();
6119     });
6120     SetAccessibilityScrollAction();
6121     SetAccessibilityMoveTextAction();
6122 }
6123 
6124 void TextFieldPattern::SetAccessibilityMoveTextAction()
6125 {
6126     auto host = GetHost();
6127     CHECK_NULL_VOID(host);
6128     auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
6129     CHECK_NULL_VOID(accessibilityProperty);
6130     accessibilityProperty->SetActionMoveText([weakPtr = WeakClaim(this)](int32_t moveUnit, bool forward) {
6131         const auto& pattern = weakPtr.Upgrade();
6132         CHECK_NULL_VOID(pattern);
6133         auto host = pattern->GetHost();
6134         CHECK_NULL_VOID(host);
6135         if (pattern->GetEditingValue().GetWideText().empty()) {
6136             return;
6137         }
6138         int range = 0;
6139         if (moveUnit == 1) {
6140             range = 1;
6141         }
6142         auto caretPosition = forward ? pattern->textEditingValue_.caretPosition + range
6143                                      : pattern->textEditingValue_.caretPosition - range;
6144         auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
6145         layoutProperty->UpdateCaretPosition(caretPosition);
6146         pattern->SetCaretPosition(caretPosition);
6147         pattern->UpdateCaretPositionByTextEdit();
6148     });
6149 }
6150 
6151 void TextFieldPattern::SetAccessibilityScrollAction()
6152 {
6153     auto host = GetHost();
6154     CHECK_NULL_VOID(host);
6155     auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
6156     CHECK_NULL_VOID(accessibilityProperty);
6157     accessibilityProperty->SetActionScrollForward([weakPtr = WeakClaim(this)]() {
6158         const auto& pattern = weakPtr.Upgrade();
6159         CHECK_NULL_VOID(pattern);
6160         if (pattern->IsScrollable()) {
6161             auto frameNode = pattern->GetHost();
6162             CHECK_NULL_VOID(frameNode);
6163             auto offset = pattern->GetTextContentRect().Height();
6164             float scrollDistance =
6165                 pattern->GetTextRect().Height() - (std::abs((pattern->GetTextRect().GetY() - offset)));
6166             if (offset > scrollDistance) {
6167                 pattern->OnTextAreaScroll(-scrollDistance);
6168                 frameNode->OnAccessibilityEvent(AccessibilityEventType::SCROLL_END);
6169                 return;
6170             }
6171             pattern->OnTextAreaScroll(-offset);
6172             frameNode->OnAccessibilityEvent(AccessibilityEventType::SCROLL_END);
6173         }
6174     });
6175 
6176     accessibilityProperty->SetActionScrollBackward([weakPtr = WeakClaim(this)]() {
6177         const auto& pattern = weakPtr.Upgrade();
6178         CHECK_NULL_VOID(pattern);
6179         if (pattern->IsScrollable()) {
6180             auto frameNode = pattern->GetHost();
6181             CHECK_NULL_VOID(frameNode);
6182             auto offset = pattern->GetTextContentRect().Height();
6183             float scrollDistance = std::abs(pattern->GetTextRect().GetY() - pattern->GetTextContentRect().GetY());
6184             if (offset > scrollDistance) {
6185                 pattern->OnTextAreaScroll(scrollDistance);
6186                 frameNode->OnAccessibilityEvent(AccessibilityEventType::SCROLL_END);
6187                 return;
6188             }
6189             pattern->OnTextAreaScroll(offset);
6190             frameNode->OnAccessibilityEvent(AccessibilityEventType::SCROLL_END);
6191         }
6192     });
6193 }
6194 
6195 void TextFieldPattern::CheckHandles(std::optional<RectF>& firstHandle, std::optional<RectF>& secondHandle,
6196     float firstHandleSize, float secondHandleSize)
6197 {
6198     auto firstHandleOffset = textSelector_.firstHandleOffset_ - parentGlobalOffset_;
6199     if (!contentRect_.IsInRegion(
6200             { firstHandleOffset.GetX(), firstHandleOffset.GetY() + BOX_EPSILON + firstHandleSize })) {
6201         // hide firstHandle when it's out of content region
6202         firstHandle = std::nullopt;
6203     }
6204     auto secondHandleOffset = textSelector_.secondHandleOffset_ - parentGlobalOffset_;
6205     if (!contentRect_.IsInRegion(
6206             { secondHandleOffset.GetX(), secondHandleOffset.GetY() + BOX_EPSILON + secondHandleSize })) {
6207         // hide secondHandle when it's out of content region
6208         secondHandle = std::nullopt;
6209     }
6210     LOGD("firstHandleOffset %{public}s, secondHandleOffset %{public}s contentRect: %{public}s",
6211         firstHandleOffset.ToString().c_str(), secondHandleOffset.ToString().c_str(), contentRect_.ToString().c_str());
6212 }
6213 
6214 void TextFieldPattern::StopEditing()
6215 {
6216     LOGI("TextFieldPattern: StopEditing");
6217     if (!HasFocus()) {
6218         return;
6219     }
6220 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
6221     if (GetImeAttached() || isCustomKeyboardAttached_) {
6222 #else
6223     if (isCustomKeyboardAttached_) {
6224 #endif
6225         auto host = GetHost();
6226         CHECK_NULL_VOID(host);
6227         auto eventHub = host->GetEventHub<TextFieldEventHub>();
6228         CHECK_NULL_VOID(eventHub);
6229         eventHub->FireOnEditChanged(false);
6230     }
6231     HandleSetSelection(textEditingValue_.caretPosition, textEditingValue_.caretPosition);
6232     StopTwinkling();
6233     MarkRedrawOverlay();
6234     CloseSelectOverlay();
6235     CloseKeyboard(true);
6236 }
6237 
6238 bool TextFieldPattern::LastTouchIsInSelectRegion(const std::vector<RSTypographyProperties::TextBox>& boxes)
6239 {
6240     if (boxes.empty()) {
6241         return false;
6242     }
6243 
6244     Offset offset = GetLastTouchOffset() - Offset(textRect_.GetX(), textRect_.GetY());
6245     for (const auto& box : boxes) {
6246         RectF rect(box.rect_.GetLeft(), box.rect_.GetTop(), box.rect_.GetWidth(), box.rect_.GetHeight());
6247         if (rect.IsInRegion({ offset.GetX(), offset.GetY() })) {
6248             return true;
6249         }
6250     }
6251     return false;
6252 }
6253 bool TextFieldPattern::CheckHandleVisible(const RectF& paintRect)
6254 {
6255     OffsetF offset(paintRect.GetX() - parentGlobalOffset_.GetX(), paintRect.GetY() - parentGlobalOffset_.GetY());
6256     return !(!contentRect_.IsInRegion({ offset.GetX(), offset.GetY() + paintRect.Height() - BOX_EPSILON }) ||
6257              !contentRect_.IsInRegion({ offset.GetX(), offset.GetY() + BOX_EPSILON }));
6258 }
6259 
6260 void TextFieldPattern::SetTextRectOffset()
6261 {
6262     auto tmpHost = GetHost();
6263     CHECK_NULL_VOID(tmpHost);
6264     auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
6265     CHECK_NULL_VOID(layoutProperty);
6266     if (barState_.has_value() && barState_.value() != layoutProperty->GetDisplayModeValue(DisplayMode::AUTO)) {
6267         barState_ = layoutProperty->GetDisplayModeValue(DisplayMode::AUTO);
6268         textRect_.SetOffset(OffsetF(GetPaddingLeft(), lastTextRectY_));
6269     } else {
6270         textRect_.SetOffset(OffsetF(GetPaddingLeft(), GetPaddingTop()));
6271     }
6272 }
6273 
6274 void TextFieldPattern::FilterExistText()
6275 {
6276     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
6277     CHECK_NULL_VOID(layoutProperty);
6278     auto inputFilter = layoutProperty->GetInputFilter();
6279     auto inputType = layoutProperty->GetTextInputType();
6280     if ((inputFilter.has_value() || inputType.has_value()) && !textEditingValue_.text.empty()) {
6281         std::string result;
6282         auto textEditorValue = textEditingValue_.text;
6283         EditingValueFilter(textEditorValue, result);
6284         if (textEditingValue_.text != result) {
6285             InitEditingValueText(result);
6286         }
6287     }
6288 }
6289 
6290 void TextFieldPattern::DumpInfo()
6291 {
6292     if (customKeyboardBulder_) {
6293         DumpLog::GetInstance().AddDesc(std::string("CustomKeyboard: true")
6294                                            .append(", Attached: ").append(std::to_string(isCustomKeyboardAttached_)));
6295     }
6296 }
6297 
6298 bool TextFieldPattern::IsTouchAtLeftOffset(float currentOffsetX)
6299 {
6300     return LessNotEqual(currentOffsetX, contentRect_.GetX() + contentRect_.Width() * 0.5);
6301 }
6302 
6303 OffsetF TextFieldPattern::GetDragUpperLeftCoordinates()
6304 {
6305     if (textBoxes_.empty()) {
6306         return { 0.0f, 0.0f };
6307     }
6308     auto startY = textBoxes_.front().rect_.GetTop();
6309     auto startX = textBoxes_.front().rect_.GetLeft();
6310     auto endY = textBoxes_.back().rect_.GetTop();
6311 
6312     OffsetF startOffset;
6313     if (NearEqual(startY, endY)) {
6314         startOffset = { (IsTextArea() ? contentRect_.GetX() : textRect_.GetX()) + startX,
6315             startY + (IsTextArea() ? textRect_.GetY() : contentRect_.GetY()) };
6316     } else {
6317         startOffset = { contentRect_.GetX(),
6318             startY + (IsTextArea() ? textRect_.GetY() : contentRect_.GetY()) };
6319     }
6320 
6321     if (startOffset.GetY() < contentRect_.GetY()) {
6322         startOffset.SetY(contentRect_.GetY());
6323     }
6324     if (startOffset.GetX() < contentRect_.GetX()) {
6325         startOffset.SetX(contentRect_.GetX());
6326     }
6327     return startOffset + parentGlobalOffset_;
6328 }
6329 
6330 void TextFieldPattern::OnColorConfigurationUpdate()
6331 {
6332     auto host = GetHost();
6333     CHECK_NULL_VOID(host);
6334     auto context = host->GetContext();
6335     CHECK_NULL_VOID(context);
6336     auto theme = context->GetTheme<TextTheme>();
6337     CHECK_NULL_VOID(theme);
6338     auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
6339     CHECK_NULL_VOID(layoutProperty);
6340     layoutProperty->UpdateTextColor(theme->GetTextStyle().GetTextColor());
6341     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
6342 }
6343 } // namespace OHOS::Ace::NG
6344