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