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