1 /*
2 * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #define NAPI_VERSION 8
17
18 #include "core/components_ng/pattern/text_field/text_field_pattern.h"
19
20 #include <algorithm>
21 #include <atomic>
22 #include <cstdint>
23 #include <optional>
24 #include <ratio>
25 #include <regex>
26 #include <string>
27 #include <utility>
28 #include "base/geometry/dimension.h"
29 #include "base/log/event_report.h"
30 #include "base/memory/type_info_base.h"
31 #include "base/utils/multi_thread.h"
32 #include "base/utils/utf_helper.h"
33 #include "core/common/ime/constant.h"
34 #include "core/components/common/properties/text_style.h"
35 #include "core/components_ng/pattern/select/select_pattern.h"
36 #include "core/components_ng/pattern/text/text_layout_property.h"
37 #include "core/components_ng/pattern/text_field/text_component_decorator.h"
38 #include "core/components_ng/pattern/text_field/text_field_layout_property.h"
39 #include "core/components_ng/property/layout_constraint.h"
40 #include "interfaces/inner_api/ui_session/ui_session_manager.h"
41
42 #include "base/i18n/localization.h"
43 #include "base/log/dump_log.h"
44 #include "base/log/log_wrapper.h"
45 #include "base/memory/referenced.h"
46 #include "base/utils/string_utils.h"
47 #include "base/utils/utils.h"
48 #include "core/common/clipboard/clipboard_proxy.h"
49 #include "core/common/container_scope.h"
50 #include "core/common/font_manager.h"
51 #include "core/common/ime/input_method_manager.h"
52 #include "core/common/ime/text_edit_controller.h"
53 #include "core/common/ime/text_input_client.h"
54 #include "core/common/ime/text_input_connection.h"
55 #include "core/common/ime/text_input_formatter.h"
56 #include "core/common/ime/text_input_type.h"
57 #include "core/common/ime/text_selection.h"
58 #include "core/common/recorder/event_recorder.h"
59 #include "core/common/recorder/node_data_cache.h"
60 #include "core/common/stylus/stylus_detector_mgr.h"
61 #include "core/common/vibrator/vibrator_utils.h"
62 #include "core/components/common/layout/constants.h"
63 #include "core/components/text_field/textfield_theme.h"
64 #include "core/components_ng/base/inspector_filter.h"
65 #include "core/components_ng/event/focus_hub.h"
66 #include "core/components_ng/pattern/stage/page_pattern.h"
67 #include "core/components_ng/pattern/text/span/span_string.h"
68 #include "core/components_ng/pattern/text/text_pattern.h"
69 #include "core/components_ng/pattern/text_field/text_field_manager.h"
70 #include "core/components_ng/pattern/text_field/text_field_paint_property.h"
71 #include "core/text/text_emoji_processor.h"
72 #ifndef ACE_UNITTEST
73 #ifdef ENABLE_STANDARD_INPUT
74 #include "parameters.h"
75 #include "adapter/ohos/entrance/ace_container.h"
76 #include "core/components_ng/pattern/text_field/on_text_changed_listener_impl.h"
77 #endif
78 #endif
79 #include "core/common/udmf/udmf_client.h"
80
81 #ifdef WINDOW_SCENE_SUPPORTED
82 #include "core/components_ng/pattern/window_scene/helper/window_scene_helper.h"
83 #endif
84 namespace OHOS::Ace::NG {
85 namespace {
86
87 const BorderRadiusProperty ZERO_BORDER_RADIUS_PROPERTY(0.0_vp);
88 // need to be moved to TextFieldTheme
89 constexpr Dimension BORDER_DEFAULT_WIDTH = 0.0_vp;
90 constexpr Dimension TYPING_UNDERLINE_WIDTH = 2.0_px;
91 constexpr Dimension OVER_COUNT_BORDER_WIDTH = 1.0_vp;
92 constexpr Dimension INLINE_BORDER_WIDTH = 2.0_vp;
93 constexpr Dimension ERROR_UNDERLINE_WIDTH = 2.0_px;
94 constexpr Dimension UNDERLINE_WIDTH = 1.0_px;
95 constexpr uint32_t INLINE_DEFAULT_VIEW_MAXLINE = 3;
96 constexpr Dimension SCROLL_BAR_MIN_HEIGHT = 4.0_vp;
97 constexpr float MINFONTSCALE = 0.85f;
98 constexpr float MAXFONTSCALE = 3.20f;
99 #if defined(ENABLE_STANDARD_INPUT)
100 constexpr Dimension AVOID_OFFSET = 24.0_vp;
101 #endif
102 constexpr Dimension DEFAULT_FONT = Dimension(16, DimensionUnit::FP);
103 constexpr int32_t ILLEGAL_VALUE = 0;
104 constexpr double VELOCITY = -1000;
105 constexpr double MASS = 1.0;
106 constexpr double STIFFNESS = 428.0;
107 constexpr double DAMPING = 10.0;
108 constexpr uint32_t TWINKLING_INTERVAL_MS = 500;
109 constexpr uint32_t RECORD_MAX_LENGTH = 20;
110 constexpr uint32_t OBSCURE_SHOW_TICKS = 1;
111 constexpr int32_t FIND_TEXT_ZERO_INDEX = 1;
112 constexpr char16_t OBSCURING_CHARACTER = u'•';
113 constexpr char16_t OBSCURING_CHARACTER_FOR_AR = u'*';
114 const std::string NEWLINE = "\n";
115 const std::wstring WIDE_NEWLINE = StringUtils::ToWstring(NEWLINE);
116 const std::string INSPECTOR_PREFIX = "__SearchField__";
117 const std::string ERRORNODE_PREFIX = "ErrorNodeField__";
118 const OffsetF DEFAULT_NEGATIVE_CARET_OFFSET {-1.0f, -1.0f};
119 constexpr Dimension FLOATING_CARET_SHOW_ORIGIN_CARET_DISTANCE = 10.0_vp;
120 #if defined(ENABLE_STANDARD_INPUT)
121 constexpr int32_t AUTO_FILL_CANCEL = 2;
122 constexpr size_t MAX_PLACEHOLDER_SIZE = 255;
123 constexpr size_t MAX_ABILITY_NAME_SIZE = 127;
124 #endif
125
126 // need to be moved to formatter
127 const std::string DIGIT_WHITE_LIST = "[0-9]";
128 const std::string PHONE_WHITE_LIST = "[\\d\\-\\+\\*\\#]+";
129 const std::string EMAIL_WHITE_LIST = "[\\w.\\@]";
130 const std::string URL_WHITE_LIST = "[a-zA-z]+://[^\\s]*";
131 const std::string SHOW_PASSWORD_SVG = "SYS_SHOW_PASSWORD_SVG";
132 const std::string HIDE_PASSWORD_SVG = "SYS_HIDE_PASSWORD_SVG";
133 const std::string AUTO_FILL_PARAMS_USERNAME = "com.autofill.params.userName";
134 const std::string AUTO_FILL_PARAMS_NEWPASSWORD = "com.autofill.params.newPassword";
135 constexpr int32_t DEFAULT_MODE = -1;
136 constexpr int32_t PREVIEW_TEXT_RANGE_DEFAULT = -1;
137 const std::string PREVIEW_STYLE_NORMAL = "normal";
138 const std::string PREVIEW_STYLE_UNDERLINE = "underline";
139
140 constexpr int32_t PREVIEW_NO_ERROR = 0;
141 constexpr int32_t PREVIEW_NULL_POINTER = 1;
142 constexpr int32_t DEFAULT_MIN_LINES = 1;
143 constexpr int32_t PREVIEW_BAD_PARAMETERS = -1;
144 constexpr double MINIMAL_OFFSET = 0.01f;
145 constexpr int32_t KEYBOARD_DEFAULT_API = 9;
146 constexpr float RICH_DEFAULT_SHADOW_COLOR = 0x33000000;
147 constexpr float RICH_DEFAULT_ELEVATION = 120.0f;
148 constexpr float TIME_UNIT = 1000.0f;
149 constexpr float MAX_DRAG_SCROLL_SPEED = 2400.0f;
150 constexpr Dimension AUTO_SCROLL_HOT_ZONE_HEIGHT = 58.0_vp;
151 constexpr Dimension AUTO_SCROLL_HOT_ZONE_WIDTH = 26.0_vp;
152 constexpr float AUTO_SCROLL_HOT_AREA_LONGPRESS_DURATION = 80.0f;
153 constexpr Dimension AUTO_SCROLL_HOT_AREA_LONGPRESS_DISTANCE = 5.0_vp;
154 constexpr Dimension MOUSE_SCROLL_BAR_REGION_WIDTH = 8.0_vp;
155 constexpr int32_t HOVER_ANIMATION_DURATION = 250;
156 const RefPtr<Curve> MOVE_MAGNIFIER_CURVE =
157 AceType::MakeRefPtr<InterpolatingSpring>(0.0f, 1.0f, 228.0f, 30.0f);
158 constexpr int32_t LAND_DURATION = 100;
159 constexpr int32_t ENTER_OFFSET = 1;
160
161 static std::unordered_map<AceAutoFillType, TextInputType> keyBoardMap_ = {
162 { AceAutoFillType::ACE_PASSWORD, TextInputType::VISIBLE_PASSWORD},
163 { AceAutoFillType::ACE_USER_NAME, TextInputType::USER_NAME },
164 { AceAutoFillType::ACE_NEW_PASSWORD, TextInputType::NEW_PASSWORD },
165 { AceAutoFillType::ACE_FULL_STREET_ADDRESS, TextInputType::TEXT },
166 { AceAutoFillType::ACE_HOUSE_NUMBER, TextInputType::TEXT },
167 { AceAutoFillType::ACE_DISTRICT_ADDRESS, TextInputType::TEXT },
168 { AceAutoFillType::ACE_CITY_ADDRESS, TextInputType::TEXT },
169 { AceAutoFillType::ACE_PROVINCE_ADDRESS, TextInputType::TEXT },
170 { AceAutoFillType::ACE_COUNTRY_ADDRESS, TextInputType::TEXT },
171 { AceAutoFillType::ACE_PERSON_FULL_NAME, TextInputType::TEXT },
172 { AceAutoFillType::ACE_PERSON_LAST_NAME, TextInputType::TEXT },
173 { AceAutoFillType::ACE_PERSON_FIRST_NAME, TextInputType::TEXT },
174 { AceAutoFillType::ACE_PHONE_NUMBER, TextInputType::PHONE },
175 { AceAutoFillType::ACE_PHONE_COUNTRY_CODE, TextInputType::PHONE },
176 { AceAutoFillType::ACE_FULL_PHONE_NUMBER, TextInputType::PHONE },
177 { AceAutoFillType::ACE_EMAIL_ADDRESS, TextInputType::EMAIL_ADDRESS },
178 { AceAutoFillType::ACE_BANK_CARD_NUMBER, TextInputType::NUMBER },
179 { AceAutoFillType::ACE_ID_CARD_NUMBER, TextInputType::NUMBER },
180 { AceAutoFillType::ACE_PRECISE_TIME, TextInputType::NUMBER },
181 { AceAutoFillType::ACE_HOUR_AND_MINUTE, TextInputType::NUMBER },
182 { AceAutoFillType::ACE_DATE, TextInputType::NUMBER },
183 { AceAutoFillType::ACE_MONTH, TextInputType::NUMBER },
184 { AceAutoFillType::ACE_YEAR, TextInputType::NUMBER },
185 { AceAutoFillType::ACE_NICKNAME, TextInputType::TEXT },
186 { AceAutoFillType::ACE_DETAIL_INFO_WITHOUT_STREET, TextInputType::TEXT },
187 { AceAutoFillType::ACE_FORMAT_ADDRESS, TextInputType::TEXT },
188 { AceAutoFillType::ACE_PASSPORT_NUMBER, TextInputType::TEXT },
189 { AceAutoFillType::ACE_VALIDITY, TextInputType::TEXT },
190 { AceAutoFillType::ACE_ISSUE_AT, TextInputType::TEXT },
191 { AceAutoFillType::ACE_ORGANIZATION, TextInputType::TEXT },
192 { AceAutoFillType::ACE_TAX_ID, TextInputType::TEXT },
193 { AceAutoFillType::ACE_ADDRESS_CITY_AND_STATE, TextInputType::TEXT },
194 { AceAutoFillType::ACE_FLIGHT_NUMBER, TextInputType::TEXT },
195 { AceAutoFillType::ACE_LICENSE_NUMBER, TextInputType::TEXT },
196 { AceAutoFillType::ACE_LICENSE_FILE_NUMBER, TextInputType::TEXT },
197 { AceAutoFillType::ACE_LICENSE_PLATE, TextInputType::TEXT },
198 { AceAutoFillType::ACE_ENGINE_NUMBER, TextInputType::TEXT },
199 { AceAutoFillType::ACE_LICENSE_CHASSIS_NUMBER, TextInputType::TEXT }};
200
201 static std::unordered_map<TextContentType, std::pair<AceAutoFillType, std::string>> contentTypeMap_ = {
202 {TextContentType::VISIBLE_PASSWORD,
203 std::make_pair(AceAutoFillType::ACE_PASSWORD, "TextContentType.VISIBLE_PASSWORD")},
204 {TextContentType::USER_NAME, std::make_pair(AceAutoFillType::ACE_USER_NAME, "TextContentType.USER_NAME")},
205 {TextContentType::NEW_PASSWORD, std::make_pair(AceAutoFillType::ACE_NEW_PASSWORD, "TextContentType.NEW_PASSWORD")},
206 {TextContentType::FULL_STREET_ADDRESS,
207 std::make_pair(AceAutoFillType::ACE_FULL_STREET_ADDRESS, "TextContentType.FULL_STREET_ADDRESS")},
208 {TextContentType::HOUSE_NUMBER, std::make_pair(AceAutoFillType::ACE_HOUSE_NUMBER, "TextContentType.HOUSE_NUMBER")},
209 {TextContentType::DISTRICT_ADDRESS,
210 std::make_pair(AceAutoFillType::ACE_DISTRICT_ADDRESS, "TextContentType.DISTRICT_ADDRESS")},
211 {TextContentType::CITY_ADDRESS, std::make_pair(AceAutoFillType::ACE_CITY_ADDRESS, "TextContentType.CITY_ADDRESS")},
212 {TextContentType::PROVINCE_ADDRESS,
213 std::make_pair(AceAutoFillType::ACE_PROVINCE_ADDRESS, "TextContentType.PROVINCE_ADDRESS")},
214 {TextContentType::COUNTRY_ADDRESS,
215 std::make_pair(AceAutoFillType::ACE_COUNTRY_ADDRESS, "TextContentType.COUNTRY_ADDRESS")},
216 {TextContentType::PERSON_FULL_NAME,
217 std::make_pair(AceAutoFillType::ACE_PERSON_FULL_NAME, "TextContentType.PERSON_FULL_NAME")},
218 {TextContentType::PERSON_LAST_NAME,
219 std::make_pair(AceAutoFillType::ACE_PERSON_LAST_NAME, "TextContentType.PERSON_LAST_NAME")},
220 {TextContentType::PERSON_FIRST_NAME,
221 std::make_pair(AceAutoFillType::ACE_PERSON_FIRST_NAME, "TextContentType.PERSON_FIRST_NAME")},
222 {TextContentType::PHONE_NUMBER, std::make_pair(AceAutoFillType::ACE_PHONE_NUMBER, "TextContentType.PHONE_NUMBER")},
223 {TextContentType::PHONE_COUNTRY_CODE,
224 std::make_pair(AceAutoFillType::ACE_PHONE_COUNTRY_CODE, "TextContentType.PHONE_COUNTRY_CODE")},
225 {TextContentType::FULL_PHONE_NUMBER,
226 std::make_pair(AceAutoFillType::ACE_FULL_PHONE_NUMBER, "TextContentType.FULL_PHONE_NUMBER")},
227 {TextContentType::EMAIL_ADDRESS,
228 std::make_pair(AceAutoFillType::ACE_EMAIL_ADDRESS, "TextContentType.EMAIL_ADDRESS")},
229 {TextContentType::BANK_CARD_NUMBER,
230 std::make_pair(AceAutoFillType::ACE_BANK_CARD_NUMBER, "TextContentType.BANK_CARD_NUMBER")},
231 {TextContentType::ID_CARD_NUMBER,
232 std::make_pair(AceAutoFillType::ACE_ID_CARD_NUMBER, "TextContentType.ID_CARD_NUMBER")},
233 {TextContentType::PRECISE_TIME, std::make_pair(AceAutoFillType::ACE_PRECISE_TIME, "TextContentType.PRECISE_TIME")},
234 {TextContentType::HOUR_AND_MINUTE,
235 std::make_pair(AceAutoFillType::ACE_HOUR_AND_MINUTE, "TextContentType.HOUR_AND_MINUTE")},
236 {TextContentType::DATE, std::make_pair(AceAutoFillType::ACE_DATE, "TextContentType.DATE")},
237 {TextContentType::MONTH, std::make_pair(AceAutoFillType::ACE_MONTH, "TextContentType.MONTH")},
238 {TextContentType::YEAR, std::make_pair(AceAutoFillType::ACE_YEAR, "TextContentType.YEAR")},
239 {TextContentType::NICKNAME, std::make_pair(AceAutoFillType::ACE_NICKNAME, "TextContentType.NICKNAME")},
240 {TextContentType::DETAIL_INFO_WITHOUT_STREET,
241 std::make_pair(AceAutoFillType::ACE_DETAIL_INFO_WITHOUT_STREET, "TextContentType.DETAIL_INFO_WITHOUT_STREET")},
242 {TextContentType::FORMAT_ADDRESS,
243 std::make_pair(AceAutoFillType::ACE_FORMAT_ADDRESS, "TextContentType.FORMAT_ADDRESS")},
244 {TextContentType::PASSPORT_NUMBER,
245 std::make_pair(AceAutoFillType::ACE_PASSPORT_NUMBER, "TextContentType.PASSPORT_NUMBER")},
246 {TextContentType::VALIDITY,
247 std::make_pair(AceAutoFillType::ACE_VALIDITY, "TextContentType.VALIDITY")},
248 {TextContentType::ISSUE_AT,
249 std::make_pair(AceAutoFillType::ACE_ISSUE_AT, "TextContentType.ISSUE_AT")},
250 {TextContentType::ORGANIZATION,
251 std::make_pair(AceAutoFillType::ACE_ORGANIZATION, "TextContentType.ORGANIZATION")},
252 {TextContentType::TAX_ID,
253 std::make_pair(AceAutoFillType::ACE_TAX_ID, "TextContentType.TAX_ID")},
254 {TextContentType::ADDRESS_CITY_AND_STATE,
255 std::make_pair(AceAutoFillType::ACE_ADDRESS_CITY_AND_STATE, "TextContentType.ADDRESS_CITY_AND_STATE")},
256 {TextContentType::FLIGHT_NUMBER,
257 std::make_pair(AceAutoFillType::ACE_FLIGHT_NUMBER, "TextContentType.FLIGHT_NUMBER")},
258 {TextContentType::LICENSE_NUMBER,
259 std::make_pair(AceAutoFillType::ACE_LICENSE_NUMBER, "TextContentType.LICENSE_NUMBER")},
260 {TextContentType::LICENSE_FILE_NUMBER,
261 std::make_pair(AceAutoFillType::ACE_LICENSE_FILE_NUMBER, "TextContentType.LICENSE_FILE_NUMBER")},
262 {TextContentType::LICENSE_PLATE,
263 std::make_pair(AceAutoFillType::ACE_LICENSE_PLATE, "TextContentType.LICENSE_PLATE")},
264 {TextContentType::ENGINE_NUMBER,
265 std::make_pair(AceAutoFillType::ACE_ENGINE_NUMBER, "TextContentType.ENGINE_NUMBER")},
266 {TextContentType::LICENSE_CHASSIS_NUMBER,
267 std::make_pair(AceAutoFillType::ACE_LICENSE_CHASSIS_NUMBER, "TextContentType.LICENSE_CHASSIS_NUMBER")},
268 {TextContentType::UNSPECIFIED, std::make_pair(AceAutoFillType::ACE_UNSPECIFIED, "TextContentType.UNSPECIFIED")}};
269
SwapIfLarger(int32_t & a,int32_t & b)270 void SwapIfLarger(int32_t& a, int32_t& b)
271 {
272 if (a > b) {
273 std::swap(a, b);
274 }
275 }
276
ConvertFontFamily(const std::vector<std::string> & fontFamily)277 std::string ConvertFontFamily(const std::vector<std::string>& fontFamily)
278 {
279 std::string result;
280 for (const auto& item : fontFamily) {
281 result += item;
282 result += ",";
283 }
284 result = result.substr(0, static_cast<int32_t>(result.length()) - 1);
285 return result;
286 }
287
288 } // namespace
289
OnAttachContext(PipelineContext * context)290 void TextFieldPattern::OnAttachContext(PipelineContext* context)
291 {
292 CHECK_NULL_VOID(context);
293 SetInstanceId(context->GetInstanceId());
294 }
295
OnDetachContext(PipelineContext * context)296 void TextFieldPattern::OnDetachContext(PipelineContext* context)
297 {
298 SetInstanceId(INSTANCE_ID_UNDEFINED);
299 }
300
CreateNodePaintMethod()301 RefPtr<NodePaintMethod> TextFieldPattern::CreateNodePaintMethod()
302 {
303 if (!textFieldContentModifier_) {
304 textFieldContentModifier_ = AceType::MakeRefPtr<TextFieldContentModifier>(WeakClaim(this));
305 }
306 auto textFieldOverlayModifier = AceType::DynamicCast<TextFieldOverlayModifier>(GetScrollBarOverlayModifier());
307 if (!textFieldOverlayModifier) {
308 textFieldOverlayModifier_ =
309 AceType::MakeRefPtr<TextFieldOverlayModifier>(WeakClaim(this), GetScrollEdgeEffect());
310 SetScrollBarOverlayModifier(textFieldOverlayModifier_);
311 }
312 if (!textFieldForegroundModifier_) {
313 textFieldForegroundModifier_ = AceType::MakeRefPtr<TextFieldForegroundModifier>(WeakClaim(this));
314 }
315 if (isCustomFont_) {
316 textFieldContentModifier_->SetIsCustomFont(true);
317 }
318 auto paint = AceType::MakeRefPtr<TextFieldPaintMethod>(
319 WeakClaim(this), textFieldOverlayModifier_, textFieldContentModifier_, textFieldForegroundModifier_);
320 auto scrollBar = GetScrollBar();
321 if (scrollBar) {
322 paint->SetScrollBar(scrollBar);
323 if (scrollBar->NeedPaint()) {
324 textFieldOverlayModifier_->SetRect(scrollBar->GetActiveRect());
325 } else if (!HasFocus() && NeedSetScrollRect()) {
326 auto scrollRect = scrollBar->GetActiveRect();
327 CalcScrollRect(scrollRect);
328 textFieldOverlayModifier_->SetRect(scrollRect);
329 textFieldOverlayModifier_->SetOpacity(0);
330 }
331 }
332 CalculateBoundsRect();
333 return paint;
334 }
335
NeedSetScrollRect()336 bool TextFieldPattern::NeedSetScrollRect()
337 {
338 auto textFieldLayoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
339 CHECK_NULL_RETURN(textFieldLayoutProperty, false);
340 bool needSetScrollRect = true;
341 if (!IsNormalInlineState() && textFieldLayoutProperty->HasOverflowMode() &&
342 lastOverflowMode_ != textFieldLayoutProperty->GetOverflowMode().value()) {
343 lastOverflowMode_ = textFieldLayoutProperty->GetOverflowMode().value();
344 needSetScrollRect = false;
345 }
346 if (!IsNormalInlineState() && textFieldLayoutProperty->HasTextOverflow() &&
347 lastTextOverflow_ != textFieldLayoutProperty->GetTextOverflow().value()) {
348 lastTextOverflow_ = textFieldLayoutProperty->GetTextOverflow().value();
349 needSetScrollRect = false;
350 }
351 if (IsNormalInlineState() && textFieldLayoutProperty->HasOverflowMode()) {
352 needSetScrollRect = false;
353 }
354 return needSetScrollRect;
355 }
356
CalculateBoundsRect()357 void TextFieldPattern::CalculateBoundsRect()
358 {
359 auto host = GetHost();
360 CHECK_NULL_VOID(host);
361 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
362 CHECK_NULL_VOID(layoutProperty);
363
364 auto geometryNode = host->GetGeometryNode();
365 auto frameOffset = geometryNode->GetFrameOffset();
366 auto frameSize = geometryNode->GetFrameSize();
367 bool isShowCount = IsShowCount() && !IsTextArea();
368 bool isShowError = layoutProperty->GetShowErrorTextValue(false) && errorDecorator_;
369 if (isShowCount && isShowError) {
370 auto textWidth = std::max(errorDecorator_ ? errorDecorator_->GetContentWidth() : 0.0f, frameSize.Width());
371 auto errorHeight = errorDecorator_? errorDecorator_->GetBoundHeight() : 0.0f;
372 auto countHeight = counterDecorator_? counterDecorator_->GetBoundHeight() : 0.0f;
373 auto bottomHeight = std::max(errorHeight, countHeight);
374 RectF boundsRect(0.0f, 0.0f, textWidth, bottomHeight + frameSize.Height());
375 textFieldOverlayModifier_->SetBoundsRect(boundsRect);
376 textFieldForegroundModifier_->SetBoundsRect(boundsRect);
377 } else if (isShowCount) {
378 auto countHeight = counterDecorator_? counterDecorator_->GetBoundHeight() : 0.0f;
379 RectF boundsRect(0.0f, 0.0f, frameSize.Width(), countHeight + frameSize.Height());
380 textFieldOverlayModifier_->SetBoundsRect(boundsRect);
381 textFieldForegroundModifier_->SetBoundsRect(boundsRect);
382 } else if (isShowError) {
383 auto textWidth = std::max(errorDecorator_ ? errorDecorator_->GetContentWidth() : 0.0f, frameSize.Width());
384 auto errorHeight = errorDecorator_? errorDecorator_->GetBoundHeight() : 0.0f;
385 RectF boundsRect(0.0f, 0.0f, textWidth, errorHeight + frameSize.Height());
386 textFieldOverlayModifier_->SetBoundsRect(boundsRect);
387 textFieldForegroundModifier_->SetBoundsRect(boundsRect);
388 } else {
389 if (NearEqual(maxFrameOffsetY_, 0.0f) && NearEqual(maxFrameHeight_, 0.0f)) {
390 maxFrameOffsetY_ = frameOffset.GetY();
391 maxFrameHeight_ = frameSize.Height();
392 }
393 maxFrameOffsetY_ = LessOrEqual(frameOffset.GetY(), maxFrameOffsetY_) ? frameOffset.GetY()
394 : maxFrameOffsetY_ - frameOffset.GetY();
395 maxFrameHeight_ = LessOrEqual(frameSize.Height(), maxFrameHeight_) ? maxFrameHeight_ : frameSize.Height();
396 RectF boundsRect(0.0f, 0.0f, frameSize.Width(), maxFrameHeight_ + UNDERLINE_WIDTH.ConvertToPx());
397 textFieldOverlayModifier_->SetBoundsRect(boundsRect);
398 textFieldForegroundModifier_->SetBoundsRect(boundsRect);
399 }
400 }
401
CalcScrollRect(Rect & inlineScrollRect)402 void TextFieldPattern::CalcScrollRect(Rect& inlineScrollRect)
403 {
404 if (!IsNormalInlineState()) {
405 // if textfield is not inline, no need to calc rect
406 return;
407 }
408 auto host = GetHost();
409 CHECK_NULL_VOID(host);
410 auto pipeline = host->GetContext();
411 CHECK_NULL_VOID(pipeline);
412 auto scrollBar = GetScrollBar();
413 CHECK_NULL_VOID(scrollBar);
414 Size size(frameRect_.Width(), inlineMeasureItem_.inlineSizeHeight);
415 auto positionMode_ = scrollBar->GetPositionMode();
416 double mainSize = (positionMode_ == PositionMode::BOTTOM ? size.Width() : size.Height());
417 auto barRegionSize = mainSize;
418 double estimatedHeight = inlineMeasureItem_.inlineContentRectHeight;
419 if (NearZero(estimatedHeight) || NearZero(estimatedHeight - mainSize)) {
420 return;
421 }
422 double activeSize = barRegionSize * mainSize / estimatedHeight - scrollBar->GetOutBoundary();
423 auto offsetScale = 0.0f;
424 if (NearEqual(mainSize, estimatedHeight)) {
425 offsetScale = 0.0;
426 } else {
427 offsetScale = (barRegionSize - activeSize) / (estimatedHeight - mainSize);
428 }
429 double lastMainOffset = std::max(
430 static_cast<double>(std::max(inlineMeasureItem_.inlineLastOffsetY, contentRect_.GetY() - textRect_.GetY())),
431 0.0);
432 double activeMainOffset = std::min(offsetScale * lastMainOffset, barRegionSize - activeSize);
433 inlineScrollRect.SetLeft(inlineScrollRect.GetOffset().GetX() - inlineMeasureItem_.inlineScrollRectOffsetX);
434 inlineScrollRect.SetTop(activeMainOffset);
435 inlineScrollRect.SetHeight(activeSize);
436 }
437
CreateObscuredText(int32_t len)438 std::u16string TextFieldPattern::CreateObscuredText(int32_t len)
439 {
440 std::u16string obscuredText;
441 if (Localization::GetInstance()->GetLanguage() == "ar") { // ar is the abbreviation of Arabic.
442 obscuredText = std::u16string(len, OBSCURING_CHARACTER_FOR_AR);
443 } else {
444 obscuredText = std::u16string(len, OBSCURING_CHARACTER);
445 }
446 return obscuredText;
447 }
448
CreateDisplayText(const std::u16string & content,int32_t nakedCharPosition,bool needObscureText,bool showPasswordDirectly)449 std::u16string TextFieldPattern::CreateDisplayText(
450 const std::u16string& content, int32_t nakedCharPosition, bool needObscureText, bool showPasswordDirectly)
451 {
452 if (!content.empty() && needObscureText) {
453 auto text =
454 TextFieldPattern::CreateObscuredText(static_cast<int32_t>(content.length()));
455 if (nakedCharPosition >= 0 && nakedCharPosition < static_cast<int32_t>(content.length())) {
456 if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE) || !showPasswordDirectly) {
457 text[nakedCharPosition] = content[nakedCharPosition];
458 }
459 }
460 return text;
461 }
462 return content;
463 }
464
GetTextOrPlaceHolderFontSize()465 float TextFieldPattern::GetTextOrPlaceHolderFontSize()
466 {
467 auto tmpHost = GetHost();
468 CHECK_NULL_RETURN(tmpHost, 0.0f);
469 auto textFieldLayoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
470 CHECK_NULL_RETURN(textFieldLayoutProperty, 0.0f);
471 auto textFieldTheme = GetTheme();
472 CHECK_NULL_RETURN(textFieldTheme, 0.0f);
473 Dimension fontSize;
474 if (textFieldLayoutProperty->HasFontSize() &&
475 textFieldLayoutProperty->GetFontSizeValue(Dimension()).IsNonNegative()) {
476 fontSize = textFieldLayoutProperty->GetFontSizeValue(Dimension());
477 } else {
478 return textFieldTheme ? static_cast<float>(textFieldTheme->GetFontSize().ConvertToPx())
479 : static_cast<float>(DEFAULT_FONT.ConvertToPx());
480 }
481 return std::min(static_cast<float>(fontSize.ConvertToPx()), contentRect_.Height());
482 }
483
TextFieldPattern()484 TextFieldPattern::TextFieldPattern() : twinklingInterval_(TWINKLING_INTERVAL_MS)
485 {
486 contentController_ = MakeRefPtr<ContentController>(WeakClaim(this));
487 selectController_ = MakeRefPtr<TextSelectController>(WeakClaim(this));
488 selectController_->InitContentController(contentController_);
489 magnifierController_ = MakeRefPtr<MagnifierController>(WeakClaim(this));
490 selectOverlay_ = MakeRefPtr<TextFieldSelectOverlay>(WeakClaim(this));
491 if (SystemProperties::GetDebugEnabled()) {
492 twinklingInterval_ = 3000; // 3000 : for AtuoUITest
493 }
494 ResetOriginCaretPosition();
495 callbackOldPreviewText_.offset = -1;
496 }
497
GetIndependentControlKeyboard()498 bool TextFieldPattern::GetIndependentControlKeyboard()
499 {
500 auto context = PipelineContext::GetCurrentContextSafelyWithCheck();
501 CHECK_NULL_RETURN(context, false);
502 auto theme = context->GetTheme<TextFieldTheme>();
503 CHECK_NULL_RETURN(theme, false);
504 independentControlKeyboard_ = theme->GetIndependentControlKeyboard();
505 return independentControlKeyboard_;
506 }
507
~TextFieldPattern()508 TextFieldPattern::~TextFieldPattern()
509 {
510 CloseSelectOverlay();
511 if (isCustomKeyboardAttached_) {
512 CloseCustomKeyboard();
513 }
514 RemoveTextFieldInfo();
515 }
516
CheckAndUpdateRecordBeforeOperation()517 void TextFieldPattern::CheckAndUpdateRecordBeforeOperation()
518 {
519 if (operationRecords_.size() == 0 ||
520 operationRecords_.back().caretPosition != selectController_->GetCaretIndex()) {
521 // record the state before the operation
522 // or caret position change
523 UpdateEditingValueToRecord();
524 }
525 }
526
BeforeCreateLayoutWrapper()527 void TextFieldPattern::BeforeCreateLayoutWrapper()
528 {
529 while (!inputOperations_.empty()) {
530 auto operation = inputOperations_.front();
531 inputOperations_.pop();
532 CheckAndUpdateRecordBeforeOperation();
533 switch (operation) {
534 case InputOperation::INSERT: {
535 ExecuteInsertValueCommand(insertCommands_.front());
536 insertCommands_.pop();
537 break;
538 }
539 case InputOperation::DELETE_BACKWARD: {
540 DeleteBackwardOperation(deleteBackwardOperations_.front());
541 deleteBackwardOperations_.pop();
542 HandleDeleteOnCounterScene();
543 break;
544 }
545 case InputOperation::DELETE_FORWARD: {
546 DeleteForwardOperation(deleteForwardOperations_.front());
547 deleteForwardOperations_.pop();
548 HandleDeleteOnCounterScene();
549 break;
550 }
551 case InputOperation::CURSOR_UP: {
552 CursorMoveUpOperation();
553 break;
554 }
555 case InputOperation::CURSOR_DOWN: {
556 CursorMoveDownOperation();
557 break;
558 }
559 case InputOperation::CURSOR_LEFT: {
560 CursorMoveLeftOperation();
561 break;
562 }
563 case InputOperation::CURSOR_RIGHT: {
564 CursorMoveRightOperation();
565 break;
566 }
567 case InputOperation::SET_PREVIEW_TEXT:
568 SetPreviewTextOperation(previewTextOperation_.front());
569 previewTextOperation_.pop();
570 break;
571 case InputOperation::SET_PREVIEW_FINISH:
572 FinishTextPreviewOperation();
573 break;
574 case InputOperation::INPUT:
575 ExecuteInputCommand(inputCommands_.front());
576 inputCommands_.pop();
577 break;
578 }
579 }
580 selectOverlay_->MarkOverlayDirty();
581 }
582
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)583 bool TextFieldPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
584 {
585 if (config.skipMeasure || dirty->SkipMeasureContent()) {
586 return false;
587 }
588 contentRect_ = dirty->GetGeometryNode()->GetContentRect();
589 frameRect_ = dirty->GetGeometryNode()->GetFrameRect();
590 auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
591 CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
592 auto textFieldLayoutAlgorithm = DynamicCast<TextFieldLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
593 CHECK_NULL_RETURN(textFieldLayoutAlgorithm, false);
594 auto paragraph = textFieldLayoutAlgorithm->GetParagraph();
595 float paragraphWidth = 0.0f;
596 bool skipUpdateParagraph = false;
597 if (paragraph) {
598 skipUpdateParagraph = ShouldSkipUpdateParagraph();
599 paragraph_ = paragraph;
600 paragraphWidth = std::max(paragraph->GetLongestLine(), 0.0f);
601 }
602 UpdateParagraphForDragNode(skipUpdateParagraph);
603 auto textRect = textFieldLayoutAlgorithm->GetTextRect();
604 auto isSameSizeMouseMenu = NearEqual(paragraphWidth, paragraphWidth_) &&
605 NearEqual(textRect.GetSize(), textRect_.GetSize()) && IsUsingMouse();
606 needToRefreshSelectOverlay_ = needToRefreshSelectOverlay_ && !isSameSizeMouseMenu;
607 paragraphWidth_ = paragraphWidth;
608 HandleContentSizeChange(textRect);
609 textRect_ = textRect;
610
611 if (textFieldContentModifier_) {
612 textFieldContentModifier_->ContentChange();
613 }
614
615 if (textFieldOverlayModifier_) {
616 textFieldOverlayModifier_->ContentChange();
617 }
618
619 auto oldParentGlobalOffset = parentGlobalOffset_;
620 parentGlobalOffset_ = GetPaintRectGlobalOffset();
621 inlineMeasureItem_ = textFieldLayoutAlgorithm->GetInlineMeasureItem();
622 auto isEditorValueChanged = FireOnTextChangeEvent();
623 UpdateCancelNode();
624 UpdateSelectController();
625 AdjustTextInReasonableArea();
626 UpdateCaretRect(isEditorValueChanged);
627 UpdateTextFieldManager(Offset(parentGlobalOffset_.GetX(), parentGlobalOffset_.GetY()), frameRect_.Height());
628 UpdateCaretInfoToController();
629 auto hostLayoutProperty =
630 dirty->GetHostNode() ? dirty->GetHostNode()->GetLayoutProperty<TextFieldLayoutProperty>() : nullptr;
631 if (hostLayoutProperty) {
632 hostLayoutProperty->ResetTextAlignChanged();
633 }
634 ProcessOverlayAfterLayout(oldParentGlobalOffset);
635 if (inlineSelectAllFlag_) {
636 HandleOnSelectAll(false, true);
637 inlineSelectAllFlag_ = false;
638 showSelect_ = true;
639 }
640 if (needSelectAll_ && !isLongPress_) {
641 HandleOnSelectAll(false);
642 needSelectAll_ = false;
643 }
644 if (mouseStatus_ == MouseStatus::RELEASED) {
645 mouseStatus_ = MouseStatus::NONE;
646 }
647 StopScrollable();
648 CheckScrollable();
649 UpdateScrollBarOffset();
650 if (config.frameSizeChange) {
651 ScheduleDisappearDelayTask();
652 }
653 SetAccessibilityClearAction();
654 SetAccessibilityPasswordIconAction();
655 SetAccessibilityUnitAction();
656 if (afterDragSelect_) {
657 UpdateSelectionAndHandleVisibility();
658 afterDragSelect_ = false;
659 }
660 releaseInDrop_ = false;
661 textParagraphIndent_ = textFieldLayoutAlgorithm->GetTextIndent();
662 return true;
663 }
664
OnSyncGeometryNode(const DirtySwapConfig & config)665 void TextFieldPattern::OnSyncGeometryNode(const DirtySwapConfig& config)
666 {
667 CHECK_NULL_VOID(HasFocus());
668 parentGlobalOffset_ = GetPaintRectGlobalOffset();
669 UpdateTextFieldManager(Offset(parentGlobalOffset_.GetX(), parentGlobalOffset_.GetY()), frameRect_.Height());
670 }
671
UpdateSelectionAndHandleVisibility()672 void TextFieldPattern::UpdateSelectionAndHandleVisibility()
673 {
674 TextFieldRequestFocus(RequestFocusReason::DRAG_SELECT);
675 auto start = dragTextStart_;
676 auto end = dragTextEnd_;
677 if (isMouseOrTouchPad(sourceTool_) && releaseInDrop_) {
678 start = selectController_->GetCaretIndex()
679 - static_cast<int32_t>(contentController_->GetInsertValue().length());
680 end = selectController_->GetCaretIndex();
681 }
682 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "UpdateSelectionAndHandleVisibility range=[%{public}d--%{public}d]",
683 start, end);
684 UpdateSelection(start, end);
685 showSelect_ = true;
686
687 if (!isMouseOrTouchPad(sourceTool_)) {
688 ProcessOverlay({ .menuIsShow = false });
689 }
690 auto host = GetHost();
691 CHECK_NULL_VOID(host);
692 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
693 }
694
SetAccessibilityPasswordIconAction()695 void TextFieldPattern::SetAccessibilityPasswordIconAction()
696 {
697 CHECK_NULL_VOID(IsShowPasswordIcon());
698 auto passwordArea = AceType::DynamicCast<PasswordResponseArea>(responseArea_);
699 CHECK_NULL_VOID(passwordArea);
700 auto node = passwordArea->GetFrameNode();
701 CHECK_NULL_VOID(node);
702 auto textAccessibilityProperty = node->GetAccessibilityProperty<AccessibilityProperty>();
703 CHECK_NULL_VOID(textAccessibilityProperty);
704 textAccessibilityProperty->SetAccessibilityLevel("yes");
705 textAccessibilityProperty->SetAccessibilityText(GetPasswordIconPromptInformation(passwordArea->IsObscured()));
706 textAccessibilityProperty->SetAccessibilityCustomRole("button");
707 }
708
SetAccessibilityClearAction()709 void TextFieldPattern::SetAccessibilityClearAction()
710 {
711 CHECK_NULL_VOID(IsShowCancelButtonMode());
712 auto cleanNodeResponseArea = AceType::DynamicCast<CleanNodeResponseArea>(cleanNodeResponseArea_);
713 CHECK_NULL_VOID(cleanNodeResponseArea);
714 auto stackNode = cleanNodeResponseArea->GetFrameNode();
715 CHECK_NULL_VOID(stackNode);
716 auto textAccessibilityProperty = stackNode->GetAccessibilityProperty<AccessibilityProperty>();
717 CHECK_NULL_VOID(textAccessibilityProperty);
718 textAccessibilityProperty->SetAccessibilityLevel("yes");
719 auto layoutProperty = GetHost()->GetLayoutProperty<TextFieldLayoutProperty>();
720 CHECK_NULL_VOID(layoutProperty);
721 auto cleanNodeStyle = layoutProperty->GetCleanNodeStyleValue(CleanNodeStyle::INPUT);
722 auto hasContent = cleanNodeStyle == CleanNodeStyle::CONSTANT ||
723 (cleanNodeStyle == CleanNodeStyle::INPUT && HasText());
724 textAccessibilityProperty->SetAccessibilityText(hasContent ? GetCancelButton() : "");
725 textAccessibilityProperty->SetAccessibilityCustomRole("button");
726 }
727
SetAccessibilityUnitAction()728 void TextFieldPattern::SetAccessibilityUnitAction()
729 {
730 if (!unitNode_ || !responseArea_) {
731 return;
732 }
733 auto unitNode = AceType::DynamicCast<FrameNode>(unitNode_);
734 CHECK_NULL_VOID(unitNode);
735 auto unitAccessibilityProperty = unitNode->GetAccessibilityProperty<AccessibilityProperty>();
736 CHECK_NULL_VOID(unitAccessibilityProperty);
737 unitAccessibilityProperty->SetAccessibilityLevel("yes");
738 }
739
HandleContentSizeChange(const RectF & textRect)740 void TextFieldPattern::HandleContentSizeChange(const RectF& textRect)
741 {
742 if (textRect_ == textRect) {
743 return;
744 }
745 auto host = GetHost();
746 CHECK_NULL_VOID(host);
747 if (!NearEqual(textRect.Height(), textRect_.Height())) {
748 PlayScrollBarAppearAnimation();
749 ScheduleDisappearDelayTask();
750 }
751 auto eventHub = host->GetOrCreateEventHub<TextFieldEventHub>();
752 CHECK_NULL_VOID(eventHub);
753 if (eventHub->GetOnContentSizeChange()) {
754 auto pipeline = host->GetContext();
755 CHECK_NULL_VOID(pipeline);
756 auto weak = WeakClaim(Referenced::RawPtr(eventHub));
757 pipeline->AddAfterLayoutTask([textRect, weak]() {
758 auto eventHub = weak.Upgrade();
759 CHECK_NULL_VOID(eventHub);
760 eventHub->FireOnContentSizeChange(std::max(0.0f, textRect.Width()), textRect.Height());
761 });
762 }
763 }
764
ProcessOverlayAfterLayout(const OffsetF & prevOffset)765 void TextFieldPattern::ProcessOverlayAfterLayout(const OffsetF& prevOffset)
766 {
767 auto host = GetHost();
768 CHECK_NULL_VOID(host);
769 auto pipeline = host->GetContext();
770 CHECK_NULL_VOID(pipeline);
771 pipeline->AddAfterLayoutTask([weak = WeakClaim(this), prevOffset]() {
772 auto pattern = weak.Upgrade();
773 CHECK_NULL_VOID(pattern);
774 pattern->parentGlobalOffset_ = pattern->GetPaintRectGlobalOffset();
775 if (pattern->SelectOverlayIsOn()) {
776 pattern->selectOverlay_->UpdateIsSingleHandle(!pattern->IsSelected());
777 if (pattern->IsSelected()) {
778 pattern->selectOverlay_->UpdateAllHandlesOffset();
779 } else {
780 pattern->selectOverlay_->UpdateSecondHandleOffset();
781 }
782 }
783 if (pattern->processOverlayDelayTask_) {
784 if (pattern->HasFocus()) {
785 pattern->processOverlayDelayTask_();
786 }
787 pattern->processOverlayDelayTask_ = nullptr;
788 } else if (prevOffset != pattern->parentGlobalOffset_) {
789 pattern->HandleParentGlobalOffsetChange();
790 } else if (pattern->needToRefreshSelectOverlay_ && pattern->SelectOverlayIsOn()) {
791 if (pattern->IsSelected()) {
792 pattern->StopTwinkling();
793 } else {
794 pattern->StartTwinkling();
795 }
796 pattern->selectOverlay_->SetUsingMouse(pattern->selectOverlay_->IsShowMouseMenu());
797 pattern->ProcessOverlay({ .menuIsShow = pattern->selectOverlay_->IsCurrentMenuVisibile() });
798 pattern->selectOverlay_->SetUsingMouse(false);
799 }
800 pattern->needToRefreshSelectOverlay_ = false;
801 });
802 }
803
HasFocus() const804 bool TextFieldPattern::HasFocus() const
805 {
806 auto focusHub = GetFocusHub();
807 CHECK_NULL_RETURN(focusHub, false);
808 return focusHub->IsCurrentFocus();
809 }
810
CheckAttachInput()811 bool TextFieldPattern::CheckAttachInput()
812 {
813 auto context = GetContext();
814 CHECK_NULL_RETURN(context, true);
815 auto textFieldManager = DynamicCast<TextFieldManagerNG>(context->GetTextFieldManager());
816 CHECK_NULL_RETURN(textFieldManager, true);
817 return textFieldManager->GetAttachInputId() == GetRequestKeyboardId();
818 }
819
UpdateCaretInfoToController(bool forceUpdate)820 void TextFieldPattern::UpdateCaretInfoToController(bool forceUpdate)
821 {
822 CHECK_NULL_VOID(HasFocus());
823 #if defined(ENABLE_STANDARD_INPUT)
824 CHECK_NULL_VOID(CheckAttachInput());
825 auto miscTextConfig = GetMiscTextConfig();
826 CHECK_NULL_VOID(miscTextConfig.has_value());
827 PreviewRange miscTextConfigRange {
828 miscTextConfig.value().range.start,
829 miscTextConfig.value().range.end
830 };
831 if (!forceUpdate && lastCursorRange_ == miscTextConfigRange &&
832 lastTextValue_ == contentController_->GetTextUtf16Value() &&
833 NearEqual(miscTextConfig.value().cursorInfo.top, lastCursorTop_) &&
834 NearEqual(miscTextConfig.value().cursorInfo.left, lastCursorLeft_)) {
835 return;
836 }
837 lastCursorRange_.Set(miscTextConfig.value().range.start, miscTextConfig.value().range.end);
838 lastTextValue_ = contentController_->GetTextUtf16Value();
839 lastCursorTop_ = miscTextConfig.value().cursorInfo.top;
840 lastCursorLeft_ = miscTextConfig.value().cursorInfo.left;
841 MiscServices::CursorInfo cursorInfo = miscTextConfig.value().cursorInfo;
842 MiscServices::InputMethodController::GetInstance()->OnCursorUpdate(cursorInfo);
843 MiscServices::InputMethodController::GetInstance()->OnSelectionChange(
844 contentController_->GetTextUtf16Value(), selectController_->GetStartIndex(),
845 selectController_->GetEndIndex());
846 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD,
847 "UpdateCaretInfoToController, left %{public}f, top %{public}f, width %{public}f, height %{public}f; "
848 "selectController_ start "
849 "%{public}d, end %{public}d",
850 cursorInfo.left, cursorInfo.top, cursorInfo.width, cursorInfo.height, selectController_->GetStartIndex(),
851 selectController_->GetEndIndex());
852
853 #else
854 if (HasConnection()) {
855 TextEditingValue value;
856 value.text = contentController_->GetTextValue();
857 value.hint = UtfUtils::Str16DebugToStr8(GetPlaceHolder());
858 value.selection.Update(selectController_->GetStartIndex(), selectController_->GetEndIndex());
859 connection_->SetEditingState(value, GetInstanceId());
860 }
861 #endif
862 }
863
UpdateCaretRect(bool isEditorValueChanged)864 void TextFieldPattern::UpdateCaretRect(bool isEditorValueChanged)
865 {
866 auto focusHub = GetFocusHub();
867 if (IsSelected()) {
868 selectController_->MoveFirstHandleToContentRect(selectController_->GetFirstHandleIndex(), false);
869 selectController_->MoveSecondHandleToContentRect(selectController_->GetSecondHandleIndex(), false);
870 return;
871 }
872 if (focusHub && !focusHub->IsCurrentFocus() && !obscuredChange_) {
873 CloseSelectOverlay(true);
874 return;
875 }
876 selectController_->MoveCaretToContentRect(
877 selectController_->GetCaretIndex(), TextAffinity::DOWNSTREAM, isEditorValueChanged);
878 }
879
AdjustTextInReasonableArea()880 void TextFieldPattern::AdjustTextInReasonableArea()
881 {
882 // Adjust y.
883 auto contentBottomBoundary = contentRect_.GetY() + contentRect_.GetSize().Height();
884 if (textRect_.Height() > contentRect_.Height()) {
885 if (textRect_.GetY() + textRect_.Height() < contentBottomBoundary) {
886 auto dy = contentBottomBoundary - textRect_.GetY() - textRect_.Height();
887 textRect_.SetOffset(OffsetF(textRect_.GetX(), textRect_.GetY() + dy));
888 }
889 if (GreatNotEqual(textRect_.GetY(), contentRect_.GetY())) {
890 auto dy = textRect_.GetY() - contentRect_.GetY();
891 textRect_.SetOffset(OffsetF(textRect_.GetX(), textRect_.GetY() - dy));
892 }
893 } else {
894 if (textRect_.GetY() != contentRect_.GetY()) {
895 auto dy = contentRect_.GetY() - textRect_.GetY();
896 textRect_.SetOffset(OffsetF(textRect_.GetX(), textRect_.GetY() + dy));
897 }
898 }
899
900 // Adjust x.
901 auto contentRightBoundary = contentRect_.GetX() + contentRect_.GetSize().Width();
902 if (textRect_.Width() > contentRect_.Width()) {
903 if (textRect_.GetX() + textRect_.Width() < contentRightBoundary) {
904 auto dx = contentRightBoundary - textRect_.GetX() - textRect_.Width();
905 textRect_.SetLeft(textRect_.GetX() + dx);
906 }
907 if (GreatNotEqual(textRect_.GetX(), contentRect_.GetX())) {
908 auto dx = textRect_.GetX() - contentRect_.GetX();
909 textRect_.SetOffset(OffsetF(textRect_.GetX() - dx, textRect_.GetY()));
910 }
911 }
912 }
913
IsTextArea() const914 bool TextFieldPattern::IsTextArea() const
915 {
916 auto tmpHost = GetHost();
917 CHECK_NULL_RETURN(tmpHost, false);
918 auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
919 CHECK_NULL_RETURN(layoutProperty, true);
920 return layoutProperty->HasMaxLines() ? layoutProperty->GetMaxLinesValue(1) > 1 : true;
921 }
922
UpdateSelectionOffset()923 void TextFieldPattern::UpdateSelectionOffset()
924 {
925 CHECK_NULL_VOID(IsSelected());
926 selectController_->CalculateHandleOffset();
927 }
928
CalcCaretMetricsByPosition(int32_t extent,CaretMetricsF & caretCaretMetric,TextAffinity textAffinity)929 void TextFieldPattern::CalcCaretMetricsByPosition(
930 int32_t extent, CaretMetricsF& caretCaretMetric, TextAffinity textAffinity)
931 {
932 CHECK_NULL_VOID(paragraph_);
933 paragraph_->CalcCaretMetricsByPosition(extent, caretCaretMetric, textAffinity);
934 caretCaretMetric.offset.AddX(textRect_.GetX());
935 caretCaretMetric.offset.AddY(textRect_.GetY());
936 }
937
CursorInContentRegion()938 bool TextFieldPattern::CursorInContentRegion()
939 {
940 if (IsTextArea()) {
941 return GreatOrEqual(selectController_->GetCaretRect().GetY(), contentRect_.GetY()) &&
942 LessOrEqual(selectController_->GetCaretRect().GetY() + GetTextOrPlaceHolderFontSize(),
943 contentRect_.GetY() + contentRect_.Height());
944 }
945 auto theme = GetTheme();
946 CHECK_NULL_RETURN(theme, false);
947 return GreatOrEqual(selectController_->GetCaretRect().GetX(), contentRect_.GetX()) &&
948 LessOrEqual(selectController_->GetCaretRect().GetX() + theme->GetCursorWidth().ConvertToPx(),
949 contentRect_.GetX() + contentRect_.Width());
950 }
951
OffsetInContentRegion(const Offset & offset)952 bool TextFieldPattern::OffsetInContentRegion(const Offset& offset)
953 {
954 // real content region will minus basic padding on left and right
955 return GreatOrEqual(offset.GetX(), contentRect_.GetX()) &&
956 LessOrEqual(offset.GetX(), contentRect_.GetX() + contentRect_.Width());
957 }
958
CheckSelectAreaVisible()959 bool TextFieldPattern::CheckSelectAreaVisible()
960 {
961 auto tmpHost = GetHost();
962 CHECK_NULL_RETURN(tmpHost, false);
963 auto pipeline = tmpHost->GetContextRefPtr();
964 CHECK_NULL_RETURN(pipeline, false);
965 auto keyboardInset = pipeline->GetSafeAreaManager()->GetKeyboardInset();
966 auto selectArea = selectOverlay_->GetSelectArea();
967 auto globalOffset = GetPaintRectGlobalOffset();
968 auto globalContentRect = contentRect_;
969 globalContentRect.SetOffset(globalContentRect.GetOffset() + globalOffset);
970 if (selectArea.Bottom() < 0) {
971 return false;
972 } else if (!globalContentRect.IsInnerIntersectWith(selectArea)) {
973 return false;
974 } else if (keyboardInset.Length() > 0 && selectArea.Top() >= keyboardInset.start) {
975 return false;
976 }
977 return true;
978 }
979
OnScrollEndCallback()980 void TextFieldPattern::OnScrollEndCallback()
981 {
982 ScheduleDisappearDelayTask();
983 if (!IsUsingMouse() && SelectOverlayIsOn() && isTextSelectionMenuShow_ && CheckSelectAreaVisible()) {
984 selectOverlay_->ShowMenu();
985 }
986 }
987
OnTextAreaScroll(float offset)988 void TextFieldPattern::OnTextAreaScroll(float offset)
989 {
990 if (!IsTextArea() || textRect_.Height() <= contentRect_.Height()) {
991 return;
992 }
993 if (textRect_.GetY() + offset > contentRect_.GetY()) {
994 offset = contentRect_.GetY() - textRect_.GetY();
995 } else if (textRect_.GetY() + textRect_.Height() + offset < contentRect_.GetY() + contentRect_.Height()) {
996 offset = contentRect_.GetY() + contentRect_.Height() - textRect_.GetY() - textRect_.Height();
997 }
998 currentOffset_ = textRect_.GetY() + offset;
999 textRect_.SetOffset(OffsetF(textRect_.GetX(), currentOffset_));
1000 UpdateHandlesOffsetOnScroll(offset);
1001 UpdateScrollBarOffset();
1002 }
1003
OnTextInputScroll(float offset)1004 void TextFieldPattern::OnTextInputScroll(float offset)
1005 {
1006 if (IsTextArea() || textRect_.Width() <= contentRect_.Width()) {
1007 return;
1008 }
1009 if (textRect_.GetX() + offset > contentRect_.GetX()) {
1010 offset = contentRect_.GetX() - textRect_.GetX();
1011 } else if (textRect_.GetX() + textRect_.Width() + offset < contentRect_.GetX() + contentRect_.Width()) {
1012 offset = contentRect_.GetX() + contentRect_.Width() - textRect_.GetX() - textRect_.Width();
1013 }
1014 currentOffset_ = textRect_.GetX() + offset;
1015 textRect_.SetOffset(OffsetF(currentOffset_, textRect_.GetY()));
1016 UpdateHandlesOffsetOnScroll(offset);
1017 auto tmpHost = GetHost();
1018 CHECK_NULL_VOID(tmpHost);
1019 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1020 }
1021
ConvertTouchOffsetToCaretPosition(const Offset & localOffset)1022 int32_t TextFieldPattern::ConvertTouchOffsetToCaretPosition(const Offset& localOffset)
1023 {
1024 CHECK_NULL_RETURN(paragraph_, 0);
1025 int32_t caretPositionIndex = 0;
1026 if (!contentController_->IsEmpty()) {
1027 caretPositionIndex = paragraph_->GetGlyphIndexByCoordinate(localOffset);
1028 }
1029 return caretPositionIndex;
1030 }
1031
ConvertTouchOffsetToCaretPositionNG(const Offset & localOffset)1032 int32_t TextFieldPattern::ConvertTouchOffsetToCaretPositionNG(const Offset& localOffset)
1033 {
1034 CHECK_NULL_RETURN(paragraph_, 0);
1035 auto offset = localOffset - Offset(textRect_.GetX(), textRect_.GetY());
1036 return paragraph_->GetGlyphIndexByCoordinate(offset);
1037 }
1038
1039 #if defined(IOS_PLATFORM)
GetGlobalOffset() const1040 Offset TextFieldPattern::GetGlobalOffset() const
1041 {
1042 Offset offset;
1043 auto host = GetHost();
1044 CHECK_NULL_RETURN(host, {});
1045 auto pipeline = host->GetContext();
1046 CHECK_NULL_RETURN(pipeline, {});
1047 auto rootOffset = pipeline->GetRootRect().GetOffset();
1048 auto globalOffset = host->GetPaintRectOffset(false, true) - rootOffset;
1049 offset = Offset(globalOffset.GetX(), globalOffset.GetY());
1050 return offset;
1051 }
1052
GetEditingBoxY() const1053 double TextFieldPattern::GetEditingBoxY() const
1054 {
1055 return GetGlobalOffset().GetY() + frameRect_.Height();
1056 };
1057
GetEditingBoxTopY() const1058 double TextFieldPattern::GetEditingBoxTopY() const
1059 {
1060 return GetGlobalOffset().GetY();
1061 };
1062
GetEditingBoxModel() const1063 bool TextFieldPattern::GetEditingBoxModel() const
1064 {
1065 bool isDeclarative = false;
1066 auto host = GetHost();
1067 CHECK_NULL_RETURN(host, false);
1068 auto pipeline = host->GetContext();
1069 if (pipeline && pipeline->GetIsDeclarative()) {
1070 isDeclarative = true;
1071 }
1072 return isDeclarative;
1073 };
1074 #endif
1075
HandleFocusEvent()1076 void TextFieldPattern::HandleFocusEvent()
1077 {
1078 isFocusedBeforeClick_ = true;
1079 focusIndex_ = FocuseIndex::TEXT;
1080 auto host = GetHost();
1081 CHECK_NULL_VOID(host);
1082 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "TextField %{public}d on focus", host->GetId());
1083 ACE_LAYOUT_SCOPED_TRACE("[TextField:%d] on focus", host->GetId());
1084 auto context = host->GetContextRefPtr();
1085 CHECK_NULL_VOID(context);
1086 context->AddOnAreaChangeNode(host->GetId());
1087 auto globalOffset = host->GetPaintRectOffset(false, true) - context->GetRootRect().GetOffset();
1088 UpdateTextFieldManager(Offset(globalOffset.GetX(), globalOffset.GetY()), frameRect_.Height());
1089 SetNeedToRequestKeyboardInner(!isLongPress_ && (dragRecipientStatus_ != DragStatus::DRAGGING) &&
1090 (dragStatus_ != DragStatus::DRAGGING) && !afterDragSelect_, RequestKeyboardInnerChangeReason::FOCUS);
1091 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
1092 CHECK_NULL_VOID(paintProperty);
1093 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
1094 CHECK_NULL_VOID(layoutProperty);
1095 auto isSelectAll = layoutProperty->GetSelectAllValueValue(false);
1096 if (isSelectAll && !contentController_->IsEmpty()) {
1097 needSelectAll_ = !independentControlKeyboard_;
1098 }
1099 SetIsEnableSubWindowMenu();
1100 ProcessFocusStyle();
1101 ProcessAutoFillOnFocus();
1102 RequestKeyboardByFocusSwitch();
1103 ResetFirstClickAfterGetFocus();
1104 SetFocusStyle();
1105 host->MarkDirtyNode(layoutProperty->GetMaxLinesValue(Infinity<float>()) <= 1 ?
1106 PROPERTY_UPDATE_MEASURE_SELF : PROPERTY_UPDATE_MEASURE);
1107 }
1108
SetFocusStyle()1109 void TextFieldPattern::SetFocusStyle()
1110 {
1111 if (IsUnderlineMode() || IsInlineMode()) {
1112 return;
1113 }
1114 auto host = GetHost();
1115 CHECK_NULL_VOID(host);
1116 auto renderContext = host->GetRenderContext();
1117 CHECK_NULL_VOID(renderContext);
1118 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
1119 CHECK_NULL_VOID(paintProperty);
1120 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
1121 CHECK_NULL_VOID(layoutProperty);
1122 auto textFieldTheme = GetTheme();
1123 CHECK_NULL_VOID(textFieldTheme);
1124
1125 if (!paintProperty->HasBackgroundColor()) {
1126 auto defaultBGColor = textFieldTheme->GetBgColor();
1127 if (paintProperty->GetBackgroundColorValue(defaultBGColor) == defaultBGColor) {
1128 renderContext->UpdateBackgroundColor(textFieldTheme->GetFocusBgColor());
1129 isFocusBGColorSet_ = true;
1130 }
1131 }
1132 auto defaultTextColor = textFieldTheme->GetTextColor();
1133 if (layoutProperty->GetTextColorValue(defaultTextColor) == defaultTextColor &&
1134 !paintProperty->HasTextColorFlagByUser()) {
1135 layoutProperty->UpdateTextColor(textFieldTheme->GetFocusTextColor());
1136 isFocusTextColorSet_ = true;
1137 }
1138 auto defaultPlaceholderColor = textFieldTheme->GetPlaceholderColor();
1139 if (layoutProperty->GetPlaceholderTextColorValue(defaultPlaceholderColor) == defaultPlaceholderColor) {
1140 layoutProperty->UpdatePlaceholderTextColor(textFieldTheme->GetFocusPlaceholderColor());
1141 isFocusPlaceholderColorSet_ = true;
1142 }
1143 }
1144
ClearFocusStyle()1145 void TextFieldPattern::ClearFocusStyle()
1146 {
1147 auto host = GetHost();
1148 CHECK_NULL_VOID(host);
1149 auto renderContext = host->GetRenderContext();
1150 CHECK_NULL_VOID(renderContext);
1151 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
1152 CHECK_NULL_VOID(paintProperty);
1153 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
1154 CHECK_NULL_VOID(layoutProperty);
1155 auto textFieldTheme = GetTheme();
1156 CHECK_NULL_VOID(textFieldTheme);
1157
1158 if (isFocusBGColorSet_ && !paintProperty->HasBackgroundColor()) {
1159 renderContext->UpdateBackgroundColor(textFieldTheme->GetBgColor());
1160 }
1161 if (isFocusTextColorSet_ && !paintProperty->HasTextColorFlagByUser()) {
1162 layoutProperty->UpdateTextColor(textFieldTheme->GetTextColor());
1163 }
1164 if (isFocusPlaceholderColorSet_ && !paintProperty->GetPlaceholderColorFlagByUserValue(false)) {
1165 layoutProperty->UpdatePlaceholderTextColor(textFieldTheme->GetPlaceholderColor());
1166 }
1167 isFocusBGColorSet_ = false;
1168 isFocusTextColorSet_ = false;
1169 isFocusPlaceholderColorSet_ = false;
1170 }
1171
ProcessAutoFillOnFocus()1172 void TextFieldPattern::ProcessAutoFillOnFocus()
1173 {
1174 auto host = GetHost();
1175 CHECK_NULL_VOID(host);
1176 if (host->LessThanAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
1177 return;
1178 }
1179
1180 auto isIgnoreFocusReason =
1181 requestFocusReason_ == RequestFocusReason::DRAG_ENTER || requestFocusReason_ == RequestFocusReason::DRAG_MOVE ||
1182 requestFocusReason_ == RequestFocusReason::DRAG_END || requestFocusReason_ == RequestFocusReason::AUTO_FILL ||
1183 requestFocusReason_ == RequestFocusReason::CLICK || requestFocusReason_ == RequestFocusReason::MOUSE ||
1184 requestFocusReason_ == RequestFocusReason::DRAG_SELECT;
1185 if (needToRequestKeyboardOnFocus_ && !isIgnoreFocusReason && !IsModalCovered() && IsTriggerAutoFillPassword()) {
1186 DoProcessAutoFill();
1187 }
1188 }
1189
ProcessFocusStyle()1190 void TextFieldPattern::ProcessFocusStyle()
1191 {
1192 bool needTwinkling = true;
1193 if (IsNormalInlineState()) {
1194 ApplyInlineTheme();
1195 inlineFocusState_ = true;
1196 if (!contentController_->IsEmpty()) {
1197 inlineSelectAllFlag_ = (blurReason_ != BlurReason::WINDOW_BLUR &&
1198 requestFocusReason_ != RequestFocusReason::DRAG_SELECT);
1199 if (inlineSelectAllFlag_) {
1200 needTwinkling = false;
1201 }
1202 }
1203 ProcessResponseArea();
1204 }
1205 if (needTwinkling) {
1206 StartTwinkling();
1207 }
1208 NotifyOnEditChanged(true);
1209 if (!IsShowError() && IsUnderlineMode()) {
1210 auto textFieldTheme = GetTheme();
1211 CHECK_NULL_VOID(textFieldTheme);
1212 underlineColor_ = userUnderlineColor_.typing.value_or(textFieldTheme->GetUnderlineTypingColor());
1213 underlineWidth_ = TYPING_UNDERLINE_WIDTH;
1214 }
1215 }
1216
HandleSetSelection(int32_t start,int32_t end,bool showHandle)1217 void TextFieldPattern::HandleSetSelection(int32_t start, int32_t end, bool showHandle)
1218 {
1219 auto host = GetHost();
1220 FREE_NODE_CHECK(host, HandleSetSelection,
1221 start, end, showHandle); // call HandleSetSelectionMultiThread() by multi thread
1222 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "HandleSetSelection %{public}d, %{public}d, showOverlay:%{public}d", start, end,
1223 showHandle);
1224 StopTwinkling();
1225 UpdateSelection(start, end);
1226 if (showHandle) {
1227 ProcessOverlay();
1228 } else {
1229 CloseSelectOverlay();
1230 }
1231 UpdateCaretInfoToController();
1232 CHECK_NULL_VOID(host);
1233 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1234 }
1235
HandleExtendAction(int32_t action)1236 void TextFieldPattern::HandleExtendAction(int32_t action)
1237 {
1238 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "HandleExtendAction %{public}d", action);
1239 switch (action) {
1240 case ACTION_SELECT_ALL: {
1241 HandleOnSelectAll(false);
1242 break;
1243 }
1244 case ACTION_CUT: {
1245 HandleOnCut();
1246 break;
1247 }
1248 case ACTION_COPY: {
1249 HandleOnCopy();
1250 break;
1251 }
1252 case ACTION_PASTE: {
1253 HandleOnPaste();
1254 break;
1255 }
1256 default: {
1257 break;
1258 }
1259 }
1260 }
1261
CursorMove(CaretMoveIntent direction)1262 void TextFieldPattern::CursorMove(CaretMoveIntent direction)
1263 {
1264 switch (direction) {
1265 case CaretMoveIntent::Left: {
1266 CursorMoveLeft();
1267 break;
1268 }
1269 case CaretMoveIntent::Right: {
1270 CursorMoveRight();
1271 break;
1272 }
1273 case CaretMoveIntent::Up: {
1274 CursorMoveUp();
1275 break;
1276 }
1277 case CaretMoveIntent::Down: {
1278 CursorMoveDown();
1279 break;
1280 }
1281 case CaretMoveIntent::LineBegin: {
1282 CursorMoveLineBegin();
1283 break;
1284 }
1285 case CaretMoveIntent::LineEnd: {
1286 CursorMoveLineEnd();
1287 break;
1288 }
1289 case CaretMoveIntent::LeftWord: {
1290 CursorMoveLeftWord();
1291 break;
1292 }
1293 case CaretMoveIntent::RightWord: {
1294 CursorMoveRightWord();
1295 break;
1296 }
1297 case CaretMoveIntent::ParagraghBegin: {
1298 CursorMoveToParagraphBegin();
1299 break;
1300 }
1301 case CaretMoveIntent::ParagraghEnd: {
1302 CursorMoveToParagraphEnd();
1303 break;
1304 }
1305 case CaretMoveIntent::Home: {
1306 CursorMoveHome();
1307 break;
1308 }
1309 case CaretMoveIntent::End: {
1310 CursorMoveEnd();
1311 break;
1312 }
1313 default: {
1314 TAG_LOGW(AceLogTag::ACE_TEXT_FIELD, "Unsupported operation of CursorMove for text field");
1315 }
1316 }
1317 }
1318
HandleSelect(CaretMoveIntent direction)1319 void TextFieldPattern::HandleSelect(CaretMoveIntent direction)
1320 {
1321 CloseSelectOverlay();
1322 switch (direction) {
1323 case CaretMoveIntent::Left: {
1324 HandleSelectionLeft();
1325 break;
1326 }
1327 case CaretMoveIntent::Right: {
1328 HandleSelectionRight();
1329 break;
1330 }
1331 case CaretMoveIntent::Up: {
1332 HandleSelectionUp();
1333 break;
1334 }
1335 case CaretMoveIntent::Down: {
1336 HandleSelectionDown();
1337 break;
1338 }
1339 case CaretMoveIntent::LineBegin: {
1340 HandleSelectionLineBegin();
1341 break;
1342 }
1343 case CaretMoveIntent::LineEnd: {
1344 HandleSelectionLineEnd();
1345 break;
1346 }
1347 case CaretMoveIntent::LeftWord: {
1348 HandleSelectionLeftWord();
1349 break;
1350 }
1351 case CaretMoveIntent::RightWord: {
1352 HandleSelectionRightWord();
1353 break;
1354 }
1355 case CaretMoveIntent::Home: {
1356 HandleSelectionHome();
1357 break;
1358 }
1359 case CaretMoveIntent::End: {
1360 HandleSelectionEnd();
1361 break;
1362 }
1363 case CaretMoveIntent::ParagraghBegin: {
1364 HandleSelectionParagraghBegin();
1365 break;
1366 }
1367 case CaretMoveIntent::ParagraghEnd: {
1368 HandleSelectionParagraghEnd();
1369 break;
1370 }
1371 default: {
1372 TAG_LOGW(AceLogTag::ACE_TEXT_FIELD, "Unsupported select operation for text field");
1373 }
1374 }
1375 }
1376
InitDisableColor()1377 void TextFieldPattern::InitDisableColor()
1378 {
1379 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
1380 CHECK_NULL_VOID(layoutProperty);
1381 auto theme = GetTheme();
1382 CHECK_NULL_VOID(theme);
1383 if (IsUnderlineMode()) {
1384 underlineWidth_ = HasFocus() ? TYPING_UNDERLINE_WIDTH : UNDERLINE_WIDTH;
1385 Color underlineColor = HasFocus() ? userUnderlineColor_.typing.value_or(theme->GetUnderlineTypingColor())
1386 : userUnderlineColor_.normal.value_or(theme->GetUnderlineColor());
1387 if (IsShowError()) {
1388 underlineColor = userUnderlineColor_.error.value_or(theme->GetErrorUnderlineColor());
1389 }
1390 if (userUnderlineColor_.disable) {
1391 underlineColor_ = IsDisabled() ? userUnderlineColor_.disable.value() : underlineColor;
1392 } else {
1393 underlineColor_ = IsDisabled() ? theme->GetDisableUnderlineColor() : underlineColor;
1394 }
1395 }
1396 layoutProperty->UpdateIsDisabled(IsDisabled());
1397 }
1398
InitFocusEvent()1399 void TextFieldPattern::InitFocusEvent()
1400 {
1401 CHECK_NULL_VOID(!focusEventInitialized_);
1402 auto host = GetHost();
1403 CHECK_NULL_VOID(host);
1404 auto focusHub = host->GetOrCreateFocusHub();
1405 auto focusTask = [weak = WeakClaim(this)](FocusReason reason) {
1406 auto pattern = weak.Upgrade();
1407 if (pattern) {
1408 pattern->HandleFocusEvent();
1409 }
1410 };
1411 focusHub->SetOnFocusInternal(focusTask);
1412 auto blurTask = [weak = WeakClaim(this)]() {
1413 auto pattern = weak.Upgrade();
1414 CHECK_NULL_VOID(pattern);
1415 pattern->HandleBlurEvent();
1416 };
1417 focusHub->SetOnBlurInternal(blurTask);
1418
1419 auto keyTask = [weak = WeakClaim(this)](const KeyEvent& keyEvent) -> bool {
1420 auto pattern = weak.Upgrade();
1421 CHECK_NULL_RETURN(pattern, false);
1422 return pattern->OnKeyEvent(keyEvent);
1423 };
1424 focusHub->SetOnKeyEventInternal(keyTask);
1425
1426 auto getInnerPaintRectCallback = [weak = WeakClaim(this)](RoundRect& paintRect) {
1427 auto pattern = weak.Upgrade();
1428 if (pattern) {
1429 pattern->GetInnerFocusPaintRect(paintRect);
1430 }
1431 };
1432 focusHub->SetInnerFocusPaintRectCallback(getInnerPaintRectCallback);
1433 focusEventInitialized_ = true;
1434 }
1435
CheckBlurReason()1436 bool TextFieldPattern::CheckBlurReason()
1437 {
1438 auto curFocusHub = GetFocusHub();
1439 CHECK_NULL_RETURN(curFocusHub, false);
1440 auto curBlurReason = curFocusHub->GetBlurReason();
1441 if (curBlurReason == BlurReason::FRAME_DESTROY) {
1442 TAG_LOGI(AceLogTag::ACE_KEYBOARD, "TextFieldPattern CheckBlurReason, Close Keyboard.");
1443 return true;
1444 }
1445 return false;
1446 }
1447
UpdateBlurReason()1448 void TextFieldPattern::UpdateBlurReason()
1449 {
1450 auto focusHub = GetFocusHub();
1451 CHECK_NULL_VOID(focusHub);
1452 blurReason_ = focusHub->GetBlurReason();
1453 }
1454
ProcNormalInlineStateInBlurEvent()1455 void TextFieldPattern::ProcNormalInlineStateInBlurEvent()
1456 {
1457 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
1458 CHECK_NULL_VOID(layoutProperty);
1459 if (IsNormalInlineState()) {
1460 if (IsTextArea() && isTextInput_) {
1461 layoutProperty->UpdateMaxLines(1);
1462 layoutProperty->UpdatePlaceholderMaxLines(1);
1463 }
1464 layoutProperty->ResetTextOverflowMaxLines();
1465 inlineSelectAllFlag_ = false;
1466 inlineFocusState_ = false;
1467 RestorePreInlineStates();
1468 }
1469 }
1470
ProcBorderAndUnderlineInBlurEvent()1471 void TextFieldPattern::ProcBorderAndUnderlineInBlurEvent()
1472 {
1473 auto host = GetHost();
1474 CHECK_NULL_VOID(host);
1475 auto textFieldTheme = GetTheme();
1476 CHECK_NULL_VOID(textFieldTheme);
1477 bool isShowError = IsShowError();
1478 bool isUnderlineMode = IsUnderlineMode();
1479 if (!isShowError && isUnderlineMode) {
1480 underlineColor_ = userUnderlineColor_.normal.value_or(textFieldTheme->GetUnderlineColor());
1481 underlineWidth_ = UNDERLINE_WIDTH;
1482 }
1483 if (showCountBorderStyle_) {
1484 showCountBorderStyle_ = false;
1485 if (isShowError) {
1486 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1487 }
1488 }
1489 if (!isShowError || (isShowError && !isUnderlineMode && !IsInPasswordMode())) {
1490 HandleCounterBorder();
1491 }
1492 }
1493
SetNeedToRequestKeyboardInner(bool needToRequestKeyboardInner,RequestKeyboardInnerChangeReason reason)1494 void TextFieldPattern::SetNeedToRequestKeyboardInner(bool needToRequestKeyboardInner,
1495 RequestKeyboardInnerChangeReason reason)
1496 {
1497 if (needToRequestKeyboardInner_ != needToRequestKeyboardInner) {
1498 TAG_LOGI(ACE_TEXT_FIELD, "Set needToRequestKeyboardInner_ to %{public}d : reason %{public}d",
1499 needToRequestKeyboardInner, static_cast<int32_t>(reason));
1500 }
1501 if (reason == RequestKeyboardInnerChangeReason::FOCUS && !needToRequestKeyboardInner) {
1502 TAG_LOGI(ACE_TEXT_FIELD, "field focus but set needToRequestKeyboardInner to false "
1503 "why: %{public}d %{public}d %{public}d", isLongPress_, dragRecipientStatus_, dragStatus_);
1504 }
1505 needToRequestKeyboardInner_ = needToRequestKeyboardInner;
1506 }
1507
HandleBlurEvent()1508 void TextFieldPattern::HandleBlurEvent()
1509 {
1510 auto host = GetHost();
1511 CHECK_NULL_VOID(host);
1512 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "TextField %{public}d OnBlur", host->GetId());
1513 auto context = host->GetContextRefPtr();
1514 CHECK_NULL_VOID(context);
1515 firstClickResetTask_.Cancel();
1516 firstClickAfterLosingFocus_ = true;
1517 UpdateBlurReason();
1518 auto textFieldManager = DynamicCast<TextFieldManagerNG>(context->GetTextFieldManager());
1519 if (textFieldManager) {
1520 textFieldManager->ClearOnFocusTextField(host->GetId());
1521 }
1522 ResetOriginCaretPosition();
1523
1524 shiftFlag_ = false;
1525 ProcBorderAndUnderlineInBlurEvent();
1526 ProcNormalInlineStateInBlurEvent();
1527 ModifyInnerStateInBlurEvent();
1528 if (magnifierController_) {
1529 magnifierController_->RemoveMagnifierFrameNode();
1530 }
1531 CloseSelectOverlay(!isKeyboardClosedByUser_ && blurReason_ == BlurReason::FOCUS_SWITCH);
1532 StopTwinkling();
1533 if (((customKeyboard_ || customKeyboardBuilder_) && isCustomKeyboardAttached_)) {
1534 CloseKeyboard(true);
1535 TAG_LOGI(AceLogTag::ACE_KEYBOARD, "textfield %{public}d on blur, close custom keyboard", host->GetId());
1536 }
1537 HandleCrossPlatformInBlurEvent();
1538 selectController_->UpdateCaretIndex(selectController_->GetCaretIndex());
1539 NotifyOnEditChanged(false);
1540 ResetFloatingCursorState();
1541 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1542 auto eventHub = host->GetOrCreateEventHub<TextFieldEventHub>();
1543 CHECK_NULL_VOID(eventHub);
1544 if (!eventHub->HasOnAreaChanged()) {
1545 context->RemoveOnAreaChangeNode(host->GetId());
1546 }
1547 SetNeedToRequestKeyboardInner(false, RequestKeyboardInnerChangeReason::BLUR);
1548 if (isOnHover_) {
1549 RestoreDefaultMouseState();
1550 }
1551 ReportEvent();
1552 ScheduleDisappearDelayTask();
1553 requestFocusReason_ = RequestFocusReason::UNKNOWN;
1554 ClearFocusStyle();
1555 }
1556
ModifyInnerStateInBlurEvent()1557 void TextFieldPattern::ModifyInnerStateInBlurEvent()
1558 {
1559 isLongPress_ = false;
1560 isMoveCaretAnywhere_ = false;
1561 isFocusedBeforeClick_ = false;
1562 }
1563
HandleCrossPlatformInBlurEvent()1564 void TextFieldPattern::HandleCrossPlatformInBlurEvent()
1565 {
1566 #ifndef OHOS_PLATFORM
1567 if (HasConnection()) {
1568 CloseKeyboard(true);
1569 }
1570 #endif
1571 }
1572
OnKeyEvent(const KeyEvent & event)1573 bool TextFieldPattern::OnKeyEvent(const KeyEvent& event)
1574 {
1575 if (event.code == KeyCode::KEY_TAB && !contentController_->IsEmpty()) {
1576 if (isFocusedBeforeClick_) {
1577 isFocusedBeforeClick_ = false;
1578 HandleOnSelectAll(true);
1579 } else {
1580 CloseSelectOverlay(true);
1581 }
1582 }
1583 auto pipeline = GetContext();
1584 CHECK_NULL_RETURN(pipeline, false);
1585 auto textFieldManager = DynamicCast<TextFieldManagerNG>(pipeline->GetTextFieldManager());
1586 if (event.code == KeyCode::KEY_TAB && HasFocus() && !needToRequestKeyboardOnFocus_ && needToRequestKeyboardInner_ &&
1587 textFieldManager->GetImeShow()) {
1588 RequestKeyboardNotByFocusSwitch(RequestKeyboardReason::ON_KEY_EVENT);
1589 }
1590 // If independent control keyboard, press Enter to request keyboard.
1591 if (event.code == KeyCode::KEY_ENTER && HasFocus() && independentControlKeyboard_) {
1592 if (RequestKeyboard(false, true, true)) {
1593 NotifyOnEditChanged(true);
1594 }
1595 return true;
1596 }
1597 if (directionKeysMoveFocusOut_ && (IsMoveFocusOutFromLeft(event) || IsMoveFocusOutFromRight(event))) {
1598 TextInputClient::HandleKeyEvent(event);
1599 return false;
1600 }
1601 return TextInputClient::HandleKeyEvent(event);
1602 }
1603
IsMoveFocusOutFromLeft(const KeyEvent & event)1604 bool TextFieldPattern::IsMoveFocusOutFromLeft(const KeyEvent& event)
1605 {
1606 return (event.code == KeyCode::KEY_DPAD_LEFT || event.code == KeyCode::KEY_DPAD_UP) &&
1607 selectController_->GetCaretIndex() == 0;
1608 }
1609
IsMoveFocusOutFromRight(const KeyEvent & event)1610 bool TextFieldPattern::IsMoveFocusOutFromRight(const KeyEvent& event)
1611 {
1612 return (event.code == KeyCode::KEY_DPAD_RIGHT || event.code == KeyCode::KEY_DPAD_DOWN) &&
1613 selectController_->GetCaretIndex() == static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
1614 }
1615
HandleOnEscape()1616 bool TextFieldPattern::HandleOnEscape()
1617 {
1618 if (SelectOverlayIsOn()) {
1619 CloseSelectOverlay(true);
1620 if (!IsSelected() && HasFocus()) {
1621 StartTwinkling();
1622 }
1623 return false;
1624 }
1625 if (GetIsPreviewText()) {
1626 ResetPreviewTextState();
1627 return false;
1628 }
1629 if (HasFocus()) {
1630 StopTwinkling();
1631 TextFieldLostFocusToViewRoot();
1632 }
1633 return false;
1634 }
1635
HandleOnTab(bool backward)1636 bool TextFieldPattern::HandleOnTab(bool backward)
1637 {
1638 return backward ? UpdateFocusBackward() : UpdateFocusForward();
1639 }
1640
HandleOnUndoAction()1641 void TextFieldPattern::HandleOnUndoAction()
1642 {
1643 if (operationRecords_.empty()) {
1644 return;
1645 }
1646 CHECK_NULL_VOID(!GetIsPreviewText());
1647 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "HandleOnUndoAction");
1648 if (operationRecords_.size() == 1) {
1649 FireEventHubOnChange(u"");
1650 return;
1651 }
1652 auto value = operationRecords_.back();
1653 operationRecords_.pop_back();
1654 auto textEditingValue = operationRecords_.back(); // each record includes text and caret
1655 bool isWillChange = OnWillChangePreSetValue(textEditingValue.text);
1656 if (!isWillChange) {
1657 operationRecords_.emplace_back(value);
1658 return;
1659 }
1660 if (redoOperationRecords_.size() >= RECORD_MAX_LENGTH) {
1661 redoOperationRecords_.erase(redoOperationRecords_.begin());
1662 }
1663 if (operationRecords_.size() >= 1) {
1664 redoOperationRecords_.emplace_back(value); // the initial status is not recorded
1665 }
1666
1667 contentController_->SetTextValue(textEditingValue.text);
1668 if (value.beforeCaretPosition != -1) {
1669 selectController_->MoveCaretToContentRect(
1670 value.beforeCaretPosition, TextAffinity::DOWNSTREAM);
1671 } else {
1672 selectController_->MoveCaretToContentRect(
1673 textEditingValue.caretPosition, TextAffinity::DOWNSTREAM);
1674 }
1675
1676 CloseSelectOverlay();
1677 StartTwinkling();
1678
1679 auto tmpHost = GetHost();
1680 CHECK_NULL_VOID(tmpHost);
1681 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
1682 }
1683
HandleOnRedoAction()1684 void TextFieldPattern::HandleOnRedoAction()
1685 {
1686 if (redoOperationRecords_.empty()) {
1687 return;
1688 }
1689 CHECK_NULL_VOID(!GetIsPreviewText());
1690 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "HandleOnRedoAction");
1691 auto textEditingValue = redoOperationRecords_.back();
1692 bool isWillChange = OnWillChangePreSetValue(textEditingValue.text);
1693 if (!isWillChange) {
1694 return;
1695 }
1696 redoOperationRecords_.pop_back();
1697 operationRecords_.emplace_back(textEditingValue);
1698 contentController_->SetTextValue(textEditingValue.text);
1699 selectController_->UpdateCaretIndex(textEditingValue.caretPosition);
1700 auto tmpHost = GetHost();
1701 CHECK_NULL_VOID(tmpHost);
1702 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
1703 }
1704
CanUndo()1705 bool TextFieldPattern::CanUndo()
1706 {
1707 return operationRecords_.size() > 1;
1708 }
1709
HasOperationRecords()1710 bool TextFieldPattern::HasOperationRecords()
1711 {
1712 return !operationRecords_.empty();
1713 }
1714
CanRedo()1715 bool TextFieldPattern::CanRedo()
1716 {
1717 return !redoOperationRecords_.empty();
1718 }
1719
HandleOnSelectAll(bool isKeyEvent,bool inlineStyle,bool showMenu)1720 void TextFieldPattern::HandleOnSelectAll(bool isKeyEvent, bool inlineStyle, bool showMenu)
1721 {
1722 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "HandleOnSelectAll");
1723 CHECK_NULL_VOID(!GetIsPreviewText());
1724 auto textSize = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
1725 if (textSize == 0) {
1726 return; // no content
1727 }
1728 if (inlineStyle) {
1729 auto dotPos = contentController_->GetTextUtf16Value().rfind(u'.');
1730 if (dotPos != std::string::npos && static_cast<int32_t>(dotPos) < textSize - FIND_TEXT_ZERO_INDEX) {
1731 textSize = static_cast<int32_t>(dotPos);
1732 }
1733 UpdateSelection(0, textSize);
1734 } else {
1735 UpdateSelection(0, textSize);
1736 }
1737 if (IsSelected()) {
1738 SetIsSingleHandle(false);
1739 }
1740 ResetObscureTickCountDown();
1741 auto tmpHost = GetHost();
1742 CHECK_NULL_VOID(tmpHost);
1743 parentGlobalOffset_ = GetPaintRectGlobalOffset();
1744 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1745 selectController_->MoveSecondHandleToContentRect(textSize);
1746 StopTwinkling();
1747 showSelect_ = true;
1748 if (isKeyEvent || inlineSelectAllFlag_ || IsUsingMouse()) {
1749 CloseSelectOverlay(true);
1750 if (inlineSelectAllFlag_ && !isKeyEvent && !IsUsingMouse()) {
1751 return;
1752 }
1753 if (IsSelected()) {
1754 selectOverlay_->SetSelectionHoldCallback();
1755 }
1756 return;
1757 }
1758 selectOverlay_->ProcessSelectAllOverlay({ .menuIsShow = showMenu, .animation = true });
1759 }
1760
HandleOnCopy(bool isUsingExternalKeyboard)1761 void TextFieldPattern::HandleOnCopy(bool isUsingExternalKeyboard)
1762 {
1763 CHECK_NULL_VOID(GetClipboard());
1764 auto tmpHost = GetHost();
1765 CHECK_NULL_VOID(tmpHost);
1766 auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
1767 CHECK_NULL_VOID(layoutProperty);
1768 if (layoutProperty->GetCopyOptionsValue(CopyOptions::Local) == CopyOptions::None) {
1769 return;
1770 }
1771 if (!IsSelected() || IsInPasswordMode()) {
1772 return;
1773 }
1774 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "On copy, text selector %{public}s", selectController_->ToString().c_str());
1775 auto start = selectController_->GetStartIndex();
1776 auto end = selectController_->GetEndIndex();
1777 auto value = contentController_->GetSelectedValue(start, end);
1778 if (value.empty()) {
1779 return;
1780 }
1781 if (layoutProperty->GetCopyOptionsValue(CopyOptions::Local) != CopyOptions::None) {
1782 clipboard_->SetData(UtfUtils::Str16DebugToStr8(value), layoutProperty->GetCopyOptionsValue(CopyOptions::Local));
1783 }
1784
1785 if (isUsingExternalKeyboard || selectOverlay_->IsShowMouseMenu()) {
1786 CloseSelectOverlay(true);
1787 } else {
1788 selectOverlay_->HideMenu();
1789 }
1790 auto host = GetHost();
1791 CHECK_NULL_VOID(host);
1792 auto eventHub = host->GetOrCreateEventHub<TextFieldEventHub>();
1793 CHECK_NULL_VOID(eventHub);
1794 eventHub->FireOnCopy(value);
1795 }
1796
IsShowHandle()1797 bool TextFieldPattern::IsShowHandle()
1798 {
1799 auto theme = GetTheme();
1800 CHECK_NULL_RETURN(theme, false);
1801 return !theme->IsTextFieldShowHandle();
1802 }
1803
GetCancelButton()1804 std::string TextFieldPattern::GetCancelButton()
1805 {
1806 auto theme = GetTheme();
1807 CHECK_NULL_RETURN(theme, "");
1808 return theme->GetCancelButton();
1809 }
1810
GetCancelImageText()1811 std::string TextFieldPattern::GetCancelImageText()
1812 {
1813 auto theme = GetTheme();
1814 CHECK_NULL_RETURN(theme, "");
1815 return theme->GetCancelImageText();
1816 }
1817
GetPasswordIconPromptInformation(bool show)1818 std::string TextFieldPattern::GetPasswordIconPromptInformation(bool show)
1819 {
1820 auto theme = GetTheme();
1821 CHECK_NULL_RETURN(theme, "");
1822 return show ? theme->GetShowPasswordPromptInformation() : theme->GetHiddenPasswordPromptInformation();
1823 }
1824
UpdateShowCountBorderStyle()1825 void TextFieldPattern::UpdateShowCountBorderStyle()
1826 {
1827 auto host = GetHost();
1828 CHECK_NULL_VOID(host);
1829 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
1830 CHECK_NULL_VOID(layoutProperty);
1831 if (layoutProperty->HasMaxLength()) {
1832 auto textLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
1833 auto maxLength = static_cast<int32_t>(layoutProperty->GetMaxLengthValue(Infinity<uint32_t>()));
1834 // if equal, the showCountBorderStyle_ is not changed
1835 if (textLength != maxLength) {
1836 showCountBorderStyle_ = textLength > maxLength;
1837 }
1838 }
1839 }
1840
HandleOnPaste()1841 void TextFieldPattern::HandleOnPaste()
1842 {
1843 auto pasteCallback = [weak = WeakClaim(this)](const std::string& data) {
1844 auto textfield = weak.Upgrade();
1845 CHECK_NULL_VOID(textfield);
1846 if (data.empty()) {
1847 TAG_LOGW(AceLogTag::ACE_TEXT_FIELD, "HandleOnPaste fail, because data is empty");
1848 textfield->suppressAccessibilityEvent_ = true;
1849 return;
1850 }
1851
1852 CHECK_NULL_VOID(!textfield->GetIsPreviewText());
1853 auto host = textfield->GetHost();
1854 CHECK_NULL_VOID(host);
1855 auto eventHub = host->GetOrCreateEventHub<TextFieldEventHub>();
1856 CHECK_NULL_VOID(eventHub);
1857 TextCommonEvent event;
1858 const std::u16string pasteData = UtfUtils::Str8DebugToStr16(data);
1859 eventHub->FireOnPasteWithEvent(pasteData, event);
1860 textfield->OnReportPasteEvent(host);
1861 if (event.IsPreventDefault()) {
1862 textfield->CloseSelectOverlay(true);
1863 textfield->selectController_->ResetHandles();
1864 textfield->StartTwinkling();
1865 textfield->suppressAccessibilityEvent_ = true;
1866 return;
1867 }
1868 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "HandleOnPaste len:%{public}d", static_cast<int32_t>(pasteData.length()));
1869 textfield->AddInsertCommand(pasteData, InputReason::PASTE);
1870 };
1871 CHECK_NULL_VOID(GetClipboard());
1872 clipboard_->GetData(pasteCallback);
1873 }
1874
IsShowTranslate()1875 bool TextFieldPattern::IsShowTranslate()
1876 {
1877 auto container = Container::Current();
1878 if (container && container->IsSceneBoardWindow()) {
1879 return false;
1880 }
1881
1882 auto host = GetHost();
1883 CHECK_NULL_RETURN(host, false);
1884 auto textFieldTheme = GetTheme();
1885 CHECK_NULL_RETURN(textFieldTheme, false);
1886 return textFieldTheme->GetTranslateIsSupport();
1887 }
1888
IsShowSearch()1889 bool TextFieldPattern::IsShowSearch()
1890 {
1891 auto container = Container::Current();
1892 if (container && container->IsSceneBoardWindow()) {
1893 return false;
1894 }
1895 auto host = GetHost();
1896 CHECK_NULL_RETURN(host, false);
1897 auto textFieldTheme = GetTheme();
1898 CHECK_NULL_RETURN(textFieldTheme, false);
1899 return textFieldTheme->GetIsSupportSearch();
1900 }
1901
HandleOnCameraInput()1902 void TextFieldPattern::HandleOnCameraInput()
1903 {
1904 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "TextFieldPattern::HandleOnCameraInput");
1905 #if defined(ENABLE_STANDARD_INPUT)
1906 if (textChangeListener_ == nullptr) {
1907 textChangeListener_ = new OnTextChangedListenerImpl(WeakClaim(this));
1908 }
1909 auto inputMethod = MiscServices::InputMethodController::GetInstance();
1910 if (!inputMethod) {
1911 TAG_LOGE(AceLogTag::ACE_TEXT_FIELD, "HandleOnCameraInput, inputMethod is null");
1912 return;
1913 }
1914 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
1915 if (imeShown_) {
1916 inputMethod->StartInputTypeAsync(MiscServices::InputType::CAMERA_INPUT);
1917 } else {
1918 FireOnWillAttachIME();
1919 auto optionalTextConfig = GetMiscTextConfig();
1920 CHECK_NULL_VOID(optionalTextConfig.has_value());
1921 MiscServices::TextConfig textConfig = optionalTextConfig.value();
1922 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "HandleOnCameraInput set calling window id is : %{public}u",
1923 textConfig.windowId);
1924 #ifdef WINDOW_SCENE_SUPPORTED
1925 auto systemWindowId = GetSCBSystemWindowId();
1926 if (systemWindowId) {
1927 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "windowId From %{public}u to %{public}u.", textConfig.windowId,
1928 systemWindowId);
1929 textConfig.windowId = systemWindowId;
1930 }
1931 #endif
1932 auto ret = inputMethod->Attach(textChangeListener_, false, textConfig);
1933 if (ret == MiscServices::ErrorCode::NO_ERROR) {
1934 auto pipeline = GetContext();
1935 CHECK_NULL_VOID(pipeline);
1936 auto textFieldManager = AceType::DynamicCast<TextFieldManagerNG>(pipeline->GetTextFieldManager());
1937 CHECK_NULL_VOID(textFieldManager);
1938 textFieldManager->SetIsImeAttached(true);
1939 }
1940 inputMethod->StartInputType(MiscServices::InputType::CAMERA_INPUT);
1941 inputMethod->ShowTextInput();
1942 }
1943 CloseSelectOverlay(true);
1944 StartTwinkling();
1945 #endif
1946 #endif
1947 }
1948
StripNextLine(std::wstring & data)1949 void TextFieldPattern::StripNextLine(std::wstring& data)
1950 {
1951 CHECK_NULL_VOID(!(data.empty() || IsTextArea()));
1952 std::wstring result;
1953 bool dataChanged = false;
1954 int32_t dataPtr = 0;
1955 while (dataPtr < static_cast<int32_t>(data.length())) {
1956 if (data[dataPtr] != WIDE_NEWLINE[0]) {
1957 result += data[dataPtr];
1958 } else {
1959 dataChanged = true;
1960 }
1961 dataPtr++;
1962 }
1963 if (!dataChanged) {
1964 return;
1965 }
1966 data = result;
1967 }
1968
HandleOnCut()1969 void TextFieldPattern::HandleOnCut()
1970 {
1971 CHECK_NULL_VOID(GetClipboard());
1972 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
1973 CHECK_NULL_VOID(layoutProperty);
1974
1975 if (layoutProperty->GetCopyOptionsValue(CopyOptions::Local) == CopyOptions::None) {
1976 suppressAccessibilityEvent_ = true;
1977 return;
1978 }
1979 auto start = selectController_->GetStartIndex();
1980 auto end = selectController_->GetEndIndex();
1981 SwapIfLarger(start, end);
1982 if (!IsSelected() || IsInPasswordMode()) {
1983 suppressAccessibilityEvent_ = true;
1984 return;
1985 }
1986 UpdateEditingValueToRecord();
1987 auto selectedText = contentController_->GetSelectedValue(start, end);
1988 if (layoutProperty->GetCopyOptionsValue(CopyOptions::Local) != CopyOptions::None) {
1989 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "Cut value size is %{private}zu",
1990 UtfUtils::Str16DebugToStr8(selectedText).size());
1991 clipboard_->SetData(UtfUtils::Str16DebugToStr8(selectedText),
1992 layoutProperty->GetCopyOptionsValue(CopyOptions::Local));
1993 }
1994 DeleteRange(start, end, false);
1995 auto host = GetHost();
1996 CHECK_NULL_VOID(host);
1997 auto eventHub = host->GetOrCreateEventHub<TextFieldEventHub>();
1998 CHECK_NULL_VOID(eventHub);
1999 eventHub->FireOnCut(selectedText);
2000 host->MarkDirtyNode(layoutProperty->GetMaxLinesValue(Infinity<float>()) <= 1 ? PROPERTY_UPDATE_MEASURE_SELF
2001 : PROPERTY_UPDATE_MEASURE);
2002 }
2003
UpdateSelection(int32_t both)2004 void TextFieldPattern::UpdateSelection(int32_t both)
2005 {
2006 UpdateSelection(both, both);
2007 }
2008
UpdateSelection(int32_t start,int32_t end)2009 void TextFieldPattern::UpdateSelection(int32_t start, int32_t end)
2010 {
2011 auto startIndex = std::min(start, end);
2012 auto endIndex = std::max(start, end);
2013 startIndex = std::clamp(startIndex, 0, static_cast<int32_t>(contentController_->GetTextUtf16Value().length()));
2014 endIndex = std::clamp(endIndex, 0, static_cast<int32_t>(contentController_->GetTextUtf16Value().length()));
2015 if (startIndex != selectController_->GetStartIndex() || endIndex != selectController_->GetEndIndex()) {
2016 selectController_->UpdateHandleIndex(startIndex, endIndex);
2017 }
2018 }
2019
FireEventHubOnChange(const std::u16string & text)2020 void TextFieldPattern::FireEventHubOnChange(const std::u16string& text)
2021 {
2022 auto host = GetHost();
2023 CHECK_NULL_VOID(host);
2024 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
2025 CHECK_NULL_VOID(layoutProperty);
2026 if (!layoutProperty->GetNeedFireOnChangeValue(false)) {
2027 return;
2028 }
2029 auto textFieldTheme = GetTheme();
2030 CHECK_NULL_VOID(textFieldTheme);
2031 auto visible = layoutProperty->GetShowErrorTextValue(false);
2032 if (!visible && IsUnderlineMode()) {
2033 underlineColor_ = userUnderlineColor_.typing.value_or(textFieldTheme->GetUnderlineTypingColor());
2034 underlineWidth_ = TYPING_UNDERLINE_WIDTH;
2035 }
2036
2037 auto eventHub = host->GetOrCreateEventHub<TextFieldEventHub>();
2038 CHECK_NULL_VOID(eventHub);
2039 ChangeValueInfo changeValueInfo;
2040 changeValueInfo.value = text;
2041 changeValueInfo.previewText.offset = hasPreviewText_ ? GetPreviewTextStart() : -1;
2042 changeValueInfo.previewText.value = GetPreviewTextValue();
2043 changeValueInfo.oldPreviewText = callbackOldPreviewText_;
2044 changeValueInfo.oldContent = callbackOldContent_;
2045 changeValueInfo.rangeBefore = callbackRangeBefore_;
2046 changeValueInfo.rangeAfter = callbackRangeAfter_;
2047 eventHub->FireOnChange(changeValueInfo);
2048 }
2049
HandleTouchEvent(const TouchEventInfo & info)2050 void TextFieldPattern::HandleTouchEvent(const TouchEventInfo& info)
2051 {
2052 CHECK_NULL_VOID(!IsDragging());
2053 CHECK_NULL_VOID(!info.GetTouches().empty());
2054 if (selectOverlay_->IsTouchAtHandle(info)) {
2055 return;
2056 }
2057 auto touchInfo = GetAcceptedTouchLocationInfo(info);
2058 CHECK_NULL_VOID(touchInfo);
2059 DoGestureSelection(info);
2060 ResetOriginCaretPosition();
2061 auto touchType = touchInfo->GetTouchType();
2062 if (touchType == TouchType::DOWN) {
2063 HandleTouchDown(touchInfo->GetLocalLocation());
2064 } else if (touchType == TouchType::UP) {
2065 OnCaretMoveDone(info);
2066 RequestKeyboardAfterLongPress();
2067 isLongPress_ = false;
2068 isMoveCaretAnywhere_ = false;
2069 HandleTouchUp();
2070 } else if (touchType == TouchType::MOVE) {
2071 if (isMoveCaretAnywhere_) {
2072 // edit + longpress + move, show caret anywhere on fonts.
2073 selectController_->MoveCaretAnywhere(info.GetTouches().front().GetLocalLocation());
2074 ShowCaretAndStopTwinkling();
2075 selectOverlay_->HideMenu();
2076 selectOverlay_->SetIsSingleHandle(false);
2077 return;
2078 }
2079 if (SelectOverlayIsOn() && !moveCaretState_.isTouchCaret) {
2080 return;
2081 }
2082 if (!IsUsingMouse() && HasFocus()) {
2083 HandleTouchMove(touchInfo.value());
2084 }
2085 } else if (touchType == TouchType::CANCEL) {
2086 StopContentScroll();
2087 if (magnifierController_ && magnifierController_->GetMagnifierNodeExist()) {
2088 magnifierController_->RemoveMagnifierFrameNode();
2089 }
2090 ResetTouchAndMoveCaretState();
2091 }
2092 }
2093
HandleTouchDown(const Offset & offset)2094 void TextFieldPattern::HandleTouchDown(const Offset& offset)
2095 {
2096 UpdatePressStyle(true);
2097 moveCaretState_.touchDownOffset = offset;
2098 if (HasStateStyle(UI_STATE_PRESSED)) {
2099 return;
2100 }
2101
2102 if (enableTouchAndHoverEffect_ && !isMousePressed_) {
2103 auto lastCaretRect = selectController_->GetCaretRect();
2104 moveCaretState_.isTouchCaret = HasFocus() && !IsSelected() && RepeatClickCaret(offset, lastCaretRect);
2105 isTouchPreviewText_ = GetTouchInnerPreviewText(offset);
2106 }
2107 }
2108
HandleTouchUp()2109 void TextFieldPattern::HandleTouchUp()
2110 {
2111 UpdatePressStyle(false);
2112 if (GetIsPreviewText() && isTouchPreviewText_) {
2113 StartTwinkling();
2114 }
2115 ResetTouchAndMoveCaretState();
2116 if (isMousePressed_) {
2117 isMousePressed_ = false;
2118 }
2119 if (magnifierController_) {
2120 magnifierController_->RemoveMagnifierFrameNode();
2121 }
2122 ScheduleDisappearDelayTask();
2123 }
2124
ResetTouchAndMoveCaretState()2125 void TextFieldPattern::ResetTouchAndMoveCaretState()
2126 {
2127 if (moveCaretState_.isTouchCaret) {
2128 moveCaretState_.isTouchCaret = false;
2129 CheckScrollable();
2130 UpdateScrollBarOffset();
2131 StartTwinkling();
2132 }
2133 if (moveCaretState_.isMoveCaret) {
2134 moveCaretState_.isMoveCaret = false;
2135 auto isAutoScrolling = contentScroller_.isScrolling;
2136 StopContentScroll();
2137 if (isAutoScrolling) {
2138 UpdateCaretRect(false);
2139 }
2140 if (HasFocus()) {
2141 StartTwinkling();
2142 } else {
2143 StopTwinkling();
2144 }
2145 }
2146 FloatingCaretLand();
2147 }
2148
HandleTouchMove(const TouchLocationInfo & info)2149 void TextFieldPattern::HandleTouchMove(const TouchLocationInfo& info)
2150 {
2151 if (moveCaretState_.isTouchCaret && !moveCaretState_.isMoveCaret) {
2152 auto offset = info.GetLocalLocation();
2153 auto moveDistance = (offset - moveCaretState_.touchDownOffset).GetDistance();
2154 moveCaretState_.isMoveCaret = GreatNotEqual(moveDistance, moveCaretState_.minDinstance.ConvertToPx());
2155 if (moveCaretState_.isMoveCaret) {
2156 moveCaretState_.touchFingerId = info.GetFingerId();
2157 contentScroller_.scrollingCallback = [weak = WeakClaim(this)](const Offset& localOffset) {
2158 auto pattern = weak.Upgrade();
2159 CHECK_NULL_VOID(pattern);
2160 pattern->UpdateMagnifierWithFloatingCaretPos();
2161 };
2162 }
2163 }
2164 if (SelectOverlayIsOn() && moveCaretState_.isMoveCaret) {
2165 CloseSelectOverlay(false);
2166 }
2167 if (moveCaretState_.isMoveCaret || (GetIsPreviewText() && isTouchPreviewText_)) {
2168 ShowCaretAndStopTwinkling();
2169 UpdateCaretByTouchMove(info);
2170 }
2171 }
2172
StartVibratorByIndexChange(int32_t currentIndex,int32_t preIndex)2173 void TextFieldPattern::StartVibratorByIndexChange(int32_t currentIndex, int32_t preIndex)
2174 {
2175 CHECK_NULL_VOID(isEnableHapticFeedback_ && (currentIndex != preIndex));
2176 VibratorUtils::StartVibraFeedback("slide");
2177 }
2178
UpdateCaretByTouchMove(const TouchLocationInfo & info)2179 void TextFieldPattern::UpdateCaretByTouchMove(const TouchLocationInfo& info)
2180 {
2181 if (contentScroller_.isScrolling) {
2182 CheckScrollable();
2183 } else {
2184 scrollable_ = false;
2185 SetScrollEnabled(scrollable_);
2186 }
2187 // limit move when preview text is shown
2188 auto touchOffset = info.GetLocalLocation();
2189 if (GetIsPreviewText()) {
2190 TAG_LOGI(ACE_TEXT_FIELD, "UpdateCaretByTouchMove when has previewText");
2191 float offsetY = IsTextArea() ? GetTextRect().GetY() : contentRect_.GetY();
2192 std::vector<RectF> previewTextRects = GetPreviewTextRects();
2193 if (previewTextRects.empty()) {
2194 TAG_LOGI(ACE_TEXT_FIELD, "preview text rect error");
2195 return;
2196 }
2197
2198 double limitL;
2199 double limitR;
2200 double limitT = previewTextRects.front().Top() + offsetY + MINIMAL_OFFSET;
2201 double limitB = previewTextRects.back().Bottom() + offsetY - MINIMAL_OFFSET;
2202
2203 Offset previewTextTouchOffset;
2204 CalculatePreviewingTextMovingLimit(touchOffset, limitL, limitR);
2205
2206 previewTextTouchOffset.SetX(std::clamp(touchOffset.GetX(), limitL, limitR));
2207 previewTextTouchOffset.SetY(std::clamp(touchOffset.GetY(), limitT, limitB));
2208 selectController_->UpdateCaretInfoByOffset(previewTextTouchOffset, true, true);
2209 } else {
2210 if (HasText()) {
2211 UpdateContentScroller(touchOffset);
2212 }
2213 auto touchCaretX = std::clamp(
2214 touchOffset.GetX(), static_cast<double>(contentRect_.Left()), static_cast<double>(contentRect_.Right()));
2215 // 1/4 line height.
2216 auto yOffset = PreferredLineHeight() * 0.25f;
2217 auto touchCaretY = std::clamp(touchOffset.GetY(), static_cast<double>(contentRect_.Top()) + yOffset,
2218 static_cast<double>(contentRect_.Bottom()) - yOffset);
2219 selectController_->UpdateCaretInfoByOffset(
2220 !contentScroller_.isScrolling ? Offset(touchCaretX, touchCaretY) : touchOffset,
2221 !contentScroller_.isScrolling, true);
2222 if (!contentScroller_.isScrolling) {
2223 UpdateMagnifierWithFloatingCaretPos();
2224 }
2225 }
2226
2227 UpdateCaretInfoToController();
2228 auto host = GetHost();
2229 CHECK_NULL_VOID(host);
2230 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2231 }
2232
SetMagnifierLocalOffsetToFloatingCaretPos()2233 void TextFieldPattern::SetMagnifierLocalOffsetToFloatingCaretPos()
2234 {
2235 auto floatCaretRectCenter = GetFloatingCaretRect().Center();
2236 if (floatCaretState_.lastFloatingCursorY.has_value() && !NearEqual(floatCaretState_.lastFloatingCursorY.value(),
2237 static_cast<float>(floatCaretRectCenter.GetY()))) {
2238 AnimationOption option = AnimationOption();
2239 option.SetCurve(MOVE_MAGNIFIER_CURVE);
2240 option.SetDuration(LAND_DURATION);
2241 AnimationUtils::Animate(option,
2242 [weak = WeakClaim(this), floatCaretRectCenter]() {
2243 auto pattern = weak.Upgrade();
2244 CHECK_NULL_VOID(pattern);
2245 pattern->GetMagnifierController()->SetLocalOffset({ floatCaretRectCenter.GetX(),
2246 floatCaretRectCenter.GetY() });
2247 });
2248 } else {
2249 magnifierController_->SetLocalOffset({ floatCaretRectCenter.GetX(), floatCaretRectCenter.GetY() });
2250 }
2251 floatCaretState_.lastFloatingCursorY = floatCaretRectCenter.GetY();
2252 }
2253
UpdateMagnifierWithFloatingCaretPos()2254 void TextFieldPattern::UpdateMagnifierWithFloatingCaretPos()
2255 {
2256 if (magnifierController_ && HasText()) {
2257 SetMagnifierLocalOffsetToFloatingCaretPos();
2258 }
2259 }
2260
InitDragEvent()2261 void TextFieldPattern::InitDragEvent()
2262 {
2263 auto host = GetHost();
2264 CHECK_NULL_VOID(host);
2265 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
2266 CHECK_NULL_VOID(layoutProperty);
2267 if (!IsInPasswordMode() && layoutProperty->GetCopyOptionsValue(CopyOptions::Local) != CopyOptions::None &&
2268 host->IsDraggable()) {
2269 InitDragDropEvent();
2270 } else {
2271 ClearDragDropEvent();
2272 InitDragDropEventWithOutDragStart();
2273 }
2274 }
2275
GetThumbnailCallback()2276 std::function<void(Offset)> TextFieldPattern::GetThumbnailCallback()
2277 {
2278 auto callback = [weak = WeakClaim(this)](const Offset& point) {
2279 auto pattern = weak.Upgrade();
2280 CHECK_NULL_VOID(pattern);
2281 auto frameNode = pattern->GetHost();
2282 CHECK_NULL_VOID(frameNode);
2283 if (pattern->BetweenSelectedPosition(point)) {
2284 auto info = pattern->CreateTextDragInfo();
2285 pattern->dragNode_ = TextDragPattern::CreateDragNode(frameNode);
2286 auto textDragPattern = pattern->dragNode_->GetPattern<TextDragPattern>();
2287 if (textDragPattern) {
2288 textDragPattern->UpdateHandleAnimationInfo(info);
2289 auto option = pattern->GetHost()->GetDragPreviewOption();
2290 option.options.shadowPath = textDragPattern->GetBackgroundPath()->ConvertToSVGString();
2291 option.options.shadow = Shadow(RICH_DEFAULT_ELEVATION, {0.0, 0.0}, Color(RICH_DEFAULT_SHADOW_COLOR),
2292 ShadowStyle::OuterFloatingSM);
2293 pattern->GetHost()->SetDragPreviewOptions(option);
2294 }
2295 FrameNode::ProcessOffscreenNode(pattern->dragNode_);
2296 }
2297 auto gestureHub = frameNode->GetOrCreateGestureEventHub();
2298 CHECK_NULL_VOID(gestureHub);
2299 gestureHub->SetPixelMap(nullptr);
2300 };
2301 return callback;
2302 }
2303
OnDragNodeDetachFromMainTree()2304 void TextFieldPattern::OnDragNodeDetachFromMainTree()
2305 {
2306 auto host = GetHost();
2307 CHECK_NULL_VOID(host);
2308 if (dragStatus_ == DragStatus::NONE) {
2309 selectOverlay_->ProcessOverlay( { .menuIsShow = false } );
2310 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2311 }
2312 }
2313
CreateTextDragInfo() const2314 TextDragInfo TextFieldPattern::CreateTextDragInfo() const
2315 {
2316 TextDragInfo info;
2317 auto manager = selectOverlay_->GetManager<SelectContentOverlayManager>();
2318 CHECK_NULL_RETURN(manager, info);
2319 auto selectOverlayInfo = manager->GetSelectOverlayInfo();
2320 CHECK_NULL_RETURN(selectOverlayInfo, info);
2321 auto textFieldTheme = GetTheme();
2322 CHECK_NULL_RETURN(textFieldTheme, info);
2323 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
2324 CHECK_NULL_RETURN(paintProperty, info);
2325 auto handleColor = paintProperty->GetCursorColorValue(textFieldTheme->GetCursorColor());
2326 auto selectedBackgroundColor = textFieldTheme->GetSelectedColor();
2327 auto firstIndex = selectController_->GetFirstHandleIndex();
2328 auto secondIndex = selectController_->GetSecondHandleIndex();
2329 auto firstIsShow = selectOverlayInfo->firstHandle.isShow;
2330 auto secondIsShow = selectOverlayInfo->secondHandle.isShow;
2331 if (firstIndex > secondIndex) {
2332 selectOverlay_->GetDragViewHandleRects(info.secondHandle, info.firstHandle);
2333 info.isFirstHandleAnimation = secondIsShow;
2334 info.isSecondHandleAnimation = firstIsShow;
2335 } else {
2336 selectOverlay_->GetDragViewHandleRects(info.firstHandle, info.secondHandle);
2337 info.isFirstHandleAnimation = firstIsShow;
2338 info.isSecondHandleAnimation = secondIsShow;
2339 }
2340 info.selectedBackgroundColor = selectedBackgroundColor;
2341 info.handleColor = handleColor;
2342 return info;
2343 }
2344
OnDragStart()2345 std::function<DragDropInfo(const RefPtr<OHOS::Ace::DragEvent>&, const std::string&)> TextFieldPattern::OnDragStart()
2346 {
2347 auto onDragStart = [weakPtr = WeakClaim(this)](const RefPtr<OHOS::Ace::DragEvent>& event,
2348 const std::string& extraParams) -> NG::DragDropInfo {
2349 NG::DragDropInfo itemInfo;
2350 auto pattern = weakPtr.Upgrade();
2351 CHECK_NULL_RETURN(pattern, itemInfo);
2352 auto host = pattern->GetHost();
2353 CHECK_NULL_RETURN(host, itemInfo);
2354 auto hub = host->GetOrCreateEventHub<EventHub>();
2355 CHECK_NULL_RETURN(hub, itemInfo);
2356 auto gestureHub = hub->GetOrCreateGestureEventHub();
2357 CHECK_NULL_RETURN(gestureHub, itemInfo);
2358 pattern->sourceTool_ = event ? event->GetSourceTool() : SourceTool::UNKNOWN;
2359 if (!gestureHub->GetIsTextDraggable()) {
2360 return itemInfo;
2361 }
2362 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD,
2363 "%{public}d TextField OnDragStart, dragStatus_ is %{public}d, dragRecipientStatus_ is %{public}d",
2364 host->GetId(), static_cast<int32_t>(pattern->dragStatus_),
2365 static_cast<int32_t>(pattern->dragRecipientStatus_));
2366 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
2367 CHECK_NULL_RETURN(layoutProperty, itemInfo);
2368 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
2369 pattern->CloseHandleAndSelect();
2370 pattern->CloseKeyboard(true);
2371 #endif
2372 pattern->SetDragMovingScrollback();
2373 pattern->dragStatus_ = DragStatus::DRAGGING;
2374 auto pipeline = pattern->GetContext();
2375 CHECK_NULL_RETURN(pipeline, itemInfo);
2376 auto dragManager = pipeline->GetDragDropManager();
2377 CHECK_NULL_RETURN(dragManager, itemInfo);
2378 if (!pattern->IsNormalInlineState() && dragManager->IsDropAllowed(host)) {
2379 pattern->dragRecipientStatus_ = DragStatus::DRAGGING;
2380 }
2381 auto selectedStr = pattern->GetDragStyledText();
2382 itemInfo.extraInfo = selectedStr;
2383 RefPtr<UnifiedData> unifiedData = UdmfClient::GetInstance()->CreateUnifiedData();
2384 UdmfClient::GetInstance()->AddPlainTextRecord(unifiedData, selectedStr);
2385 event->SetData(unifiedData);
2386 host->MarkDirtyNode(layoutProperty->GetMaxLinesValue(Infinity<float>()) <= 1 ? PROPERTY_UPDATE_MEASURE_SELF
2387 : PROPERTY_UPDATE_MEASURE);
2388 return itemInfo;
2389 };
2390 return onDragStart;
2391 }
2392
GetDragStyledText()2393 std::string TextFieldPattern::GetDragStyledText()
2394 {
2395 showSelect_ = false;
2396 selectionMode_ = SelectionMode::SELECT;
2397 textFieldContentModifier_->ChangeDragStatus();
2398 auto start = selectController_->GetStartIndex();
2399 auto end = selectController_->GetEndIndex();
2400 GetEmojiSubStringRange(start, end);
2401 dragTextStart_ = start;
2402 dragTextEnd_ = end;
2403 std::u16string beforeStr = contentController_->GetValueBeforeIndex(start);
2404 std::u16string selectedStr = contentController_->GetSelectedValue(start, end);
2405 dragValue_ = selectedStr;
2406 std::u16string afterStr = contentController_->GetValueAfterIndex(end);
2407 dragContents_ = { beforeStr, selectedStr, afterStr };
2408 return UtfUtils::Str16DebugToStr8(selectedStr);
2409 }
2410
OnDragDrop()2411 std::function<void(const RefPtr<OHOS::Ace::DragEvent>&, const std::string&)> TextFieldPattern::OnDragDrop()
2412 {
2413 return [weakPtr = WeakClaim(this)](const RefPtr<OHOS::Ace::DragEvent>& event, const std::string& extraParams) {
2414 auto pattern = weakPtr.Upgrade();
2415 CHECK_NULL_VOID(pattern);
2416 pattern->StopContentScroll();
2417 pattern->sourceTool_ = event ? event->GetSourceTool() : SourceTool::UNKNOWN;
2418 auto host = pattern->GetHost();
2419 CHECK_NULL_VOID(host);
2420 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
2421 CHECK_NULL_VOID(layoutProperty);
2422
2423 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD,
2424 "%{public}d TextField OnDragDrop, dragStatus_ is %{public}d, dragRecipientStatus_ is %{public}d",
2425 host->GetId(), static_cast<int32_t>(pattern->dragStatus_),
2426 static_cast<int32_t>(pattern->dragRecipientStatus_));
2427 if (layoutProperty->GetIsDisabledValue(false) || pattern->IsNormalInlineState() || !pattern->HasFocus()) {
2428 event->SetResult(DragRet::DRAG_FAIL);
2429 return;
2430 }
2431 if (extraParams.empty()) {
2432 pattern->dragStatus_ = DragStatus::ON_DROP;
2433 pattern->textFieldContentModifier_->ChangeDragStatus();
2434 host->MarkDirtyNode(layoutProperty->GetMaxLinesValue(Infinity<float>()) <= 1 ? PROPERTY_UPDATE_MEASURE_SELF
2435 : PROPERTY_UPDATE_MEASURE);
2436 event->SetResult(DragRet::DRAG_FAIL);
2437 return;
2438 }
2439 bool isCopy = false;
2440 if (pattern->dragStatus_ == DragStatus::DRAGGING) {
2441 CHECK_NULL_VOID(event);
2442 auto gesturePressedCodes = event->GetPressedKeyCodes();
2443 if ((gesturePressedCodes.size() == 1) && ((gesturePressedCodes[0] == KeyCode::KEY_CTRL_LEFT) ||
2444 (gesturePressedCodes[0] == KeyCode::KEY_CTRL_RIGHT))) {
2445 isCopy = true;
2446 }
2447 }
2448 auto data = event->GetData();
2449 CHECK_NULL_VOID(data);
2450 std::u16string str;
2451 auto arr = UdmfClient::GetInstance()->GetSpanStringEntry(data);
2452 if (arr.size() > 0) {
2453 auto spanStr = SpanString::DecodeTlv(arr);
2454 str += spanStr->GetU16string();
2455 } else {
2456 auto plainText = UdmfClient::GetInstance()->GetPlainTextEntry(data);
2457 if (plainText.empty()) {
2458 std::string linkUrl;
2459 std::string linkTitle;
2460 UdmfClient::GetInstance()->GetLinkEntry(data, linkUrl, linkTitle);
2461 if (!linkTitle.empty()) {
2462 str += UtfUtils::Str8DebugToStr16(linkTitle);
2463 } else if (!linkUrl.empty()) {
2464 str += UtfUtils::Str8DebugToStr16(linkUrl);
2465 }
2466 }
2467 str += UtfUtils::Str8DebugToStr16(plainText);
2468 }
2469 pattern->dragRecipientStatus_ = DragStatus::NONE;
2470 if (str.empty()) {
2471 return;
2472 }
2473 if ((pattern->dragStatus_ == DragStatus::NONE) || isCopy) {
2474 pattern->AddInsertCommand(str, InputReason::DRAG);
2475 } else {
2476 InputCommandInfo inputCommandInfo;
2477 inputCommandInfo.deleteRange = { pattern->dragTextStart_, pattern->dragTextEnd_ };
2478 inputCommandInfo.insertOffset = pattern->selectController_->GetCaretIndex();
2479 inputCommandInfo.insertValue = str;
2480 inputCommandInfo.reason = InputReason::DRAG;
2481 pattern->AddInputCommand(inputCommandInfo);
2482 pattern->dragStatus_ = DragStatus::NONE;
2483 pattern->MarkContentChange();
2484 host->MarkDirtyNode(pattern->IsTextArea() ? PROPERTY_UPDATE_MEASURE : PROPERTY_UPDATE_MEASURE_SELF);
2485 }
2486 pattern->afterDragSelect_ = isMouseOrTouchPad(pattern->sourceTool_);
2487 pattern->releaseInDrop_ = true;
2488 FocusHub::LostFocusToViewRoot();
2489 };
2490 }
2491
ShowSelectAfterDragEvent()2492 void TextFieldPattern::ShowSelectAfterDragEvent()
2493 {
2494 selectController_->UpdateHandleIndex(dragTextStart_, dragTextEnd_);
2495 showSelect_ = true;
2496 if (!IsUsingMouse()) {
2497 DelayProcessOverlay({ .menuIsShow = false });
2498 }
2499 }
2500
InitDragDropEventWithOutDragStart()2501 void TextFieldPattern::InitDragDropEventWithOutDragStart()
2502 {
2503 auto host = GetHost();
2504 CHECK_NULL_VOID(host);
2505 auto gestureHub = host->GetOrCreateGestureEventHub();
2506 CHECK_NULL_VOID(gestureHub);
2507 gestureHub->InitDragDropEvent();
2508 auto eventHub = host->GetOrCreateEventHub<EventHub>();
2509 CHECK_NULL_VOID(eventHub);
2510 InitDragDropCallBack();
2511 }
2512
InitDragDropEvent()2513 void TextFieldPattern::InitDragDropEvent()
2514 {
2515 auto host = GetHost();
2516 CHECK_NULL_VOID(host);
2517 auto gestureHub = host->GetOrCreateGestureEventHub();
2518 CHECK_NULL_VOID(gestureHub);
2519 gestureHub->InitDragDropEvent();
2520 auto callback = GetThumbnailCallback();
2521 gestureHub->SetThumbnailCallback(std::move(callback));
2522 auto eventHub = host->GetOrCreateEventHub<EventHub>();
2523 CHECK_NULL_VOID(eventHub);
2524 eventHub->SetDefaultOnDragStart(OnDragStart());
2525 InitDragDropCallBack();
2526 gestureHub->SetTextDraggable(true);
2527 }
2528
InitDragDropCallBack()2529 void TextFieldPattern::InitDragDropCallBack()
2530 {
2531 auto host = GetHost();
2532 CHECK_NULL_VOID(host);
2533 auto eventHub = host->GetOrCreateEventHub<EventHub>();
2534 CHECK_NULL_VOID(eventHub);
2535 auto onDragEnter = [weakPtr = WeakClaim(this)](
2536 const RefPtr<OHOS::Ace::DragEvent>& event, const std::string& extraParams) {
2537 auto pattern = weakPtr.Upgrade();
2538 CHECK_NULL_VOID(pattern);
2539 auto host = pattern->GetHost();
2540 CHECK_NULL_VOID(host);
2541 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD,
2542 "%{public}d TextField onDragEnter, dragStatus_ is %{public}d, dragRecipientStatus_ is %{public}d",
2543 host->GetId(), static_cast<int32_t>(pattern->dragStatus_),
2544 static_cast<int32_t>(pattern->dragRecipientStatus_));
2545 CHECK_NULL_VOID(!pattern->IsDisabled());
2546 auto pipeline = pattern->GetContext();
2547 CHECK_NULL_VOID(pipeline);
2548 auto dragManager = pipeline->GetDragDropManager();
2549 CHECK_NULL_VOID(dragManager);
2550 if (pattern->IsNormalInlineState() || !dragManager->IsDropAllowed(host)) {
2551 return;
2552 }
2553 pattern->SetDragMovingScrollback();
2554 pattern->dragRecipientStatus_ = DragStatus::DRAGGING;
2555 pattern->ResetPreviewTextState();
2556 auto focusHub = pattern->GetFocusHub();
2557 CHECK_NULL_VOID(focusHub);
2558 if (pattern->dragStatus_ != DragStatus::DRAGGING) {
2559 pattern->CloseKeyboard(true, false);
2560 }
2561 if (pattern->TextFieldRequestFocus(RequestFocusReason::DRAG_ENTER)) {
2562 pattern->StartTwinkling();
2563 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD,
2564 "%{public}d TextField onDragEnter Request Focus Success", host->GetId());
2565 }
2566 };
2567 eventHub->SetOnDragEnter(std::move(onDragEnter));
2568
2569 auto onDragMove = [weakPtr = WeakClaim(this)](
2570 const RefPtr<OHOS::Ace::DragEvent>& event, const std::string& extraParams) {
2571 auto pattern = weakPtr.Upgrade();
2572 CHECK_NULL_VOID(pattern);
2573 auto pipeline = pattern->GetContext();
2574 CHECK_NULL_VOID(pipeline);
2575 auto dragManager = pipeline->GetDragDropManager();
2576 CHECK_NULL_VOID(dragManager);
2577 auto host = pattern->GetHost();
2578 CHECK_NULL_VOID(host);
2579 CHECK_NULL_VOID(!pattern->IsDisabled());
2580
2581 if (pattern->IsNormalInlineState() || !dragManager->IsDropAllowed(host)) {
2582 return;
2583 }
2584 if (!pattern->HasFocus()) {
2585 auto focusHub = pattern->GetFocusHub();
2586 CHECK_NULL_VOID(focusHub);
2587 if (pattern->TextFieldRequestFocus(RequestFocusReason::DRAG_MOVE)) {
2588 pattern->StartTwinkling();
2589 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD,
2590 "%{public}d TextField onDragMove Request Focus Success", host->GetId());
2591 }
2592 }
2593 auto textPaintOffset = pattern->GetPaintRectGlobalOffset();
2594 Offset localOffset =
2595 Offset(event->GetX(), event->GetY()) - Offset(textPaintOffset.GetX(), textPaintOffset.GetY());
2596 if (host->GetDragPreviewOption().enableEdgeAutoScroll) {
2597 pattern->UpdateContentScroller(localOffset, AUTO_SCROLL_HOT_AREA_LONGPRESS_DURATION, false);
2598 } else {
2599 pattern->contentScroller_.OnBeforeScrollingCallback(localOffset);
2600 pattern->PauseContentScroll();
2601 pattern->contentScroller_.hotAreaOffset.reset();
2602 }
2603 };
2604 eventHub->SetOnDragMove(std::move(onDragMove));
2605
2606 auto onDragLeave = [weakPtr = WeakClaim(this)](
2607 const RefPtr<OHOS::Ace::DragEvent>& event, const std::string& extraParams) {
2608 auto pattern = weakPtr.Upgrade();
2609 CHECK_NULL_VOID(pattern);
2610 auto host = pattern->GetHost();
2611 CHECK_NULL_VOID(host);
2612 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD,
2613 "%{public}d TextField onDragLeave, dragStatus_ is %{public}d, dragRecipientStatus_ is %{public}d",
2614 host->GetId(), static_cast<int32_t>(pattern->dragStatus_),
2615 static_cast<int32_t>(pattern->dragRecipientStatus_));
2616 pattern->dragRecipientStatus_ = DragStatus::NONE;
2617 auto focusHub = pattern->GetFocusHub();
2618 CHECK_NULL_VOID(focusHub);
2619 focusHub->LostFocus();
2620 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD,
2621 "%{public}d TextField onDragLeave Lost Focus", host->GetId());
2622 pattern->StopTwinkling();
2623 pattern->PauseContentScroll();
2624 };
2625 eventHub->SetOnDragLeave(std::move(onDragLeave));
2626
2627 auto onDragEnd = [weakPtr = WeakClaim(this)](const RefPtr<OHOS::Ace::DragEvent>& event) {
2628 auto pattern = weakPtr.Upgrade();
2629 CHECK_NULL_VOID(pattern);
2630 auto host = pattern->GetHost();
2631 CHECK_NULL_VOID(host);
2632 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD,
2633 "%{public}d TextField onDragEnd, dragStatus_ is %{public}d, dragRecipientStatus_ is %{public}d",
2634 host->GetId(), static_cast<int32_t>(pattern->dragStatus_),
2635 static_cast<int32_t>(pattern->dragRecipientStatus_));
2636 pattern->StopContentScroll();
2637 ContainerScope scope(pattern->GetHostInstanceId());
2638 if (pattern->dragStatus_ == DragStatus::DRAGGING && !pattern->isDetachFromMainTree_) {
2639 pattern->dragStatus_ = DragStatus::NONE;
2640 pattern->MarkContentChange();
2641 // Except for DRAG_SUCCESS, all of rest need to show
2642 auto paintProperty = pattern->GetPaintProperty<TextFieldPaintProperty>();
2643 CHECK_NULL_VOID(paintProperty);
2644 auto newDragValue =
2645 pattern->contentController_->GetSelectedValue(pattern->dragTextStart_, pattern->dragTextEnd_);
2646 auto focusHub = pattern->GetFocusHub();
2647 CHECK_NULL_VOID(focusHub);
2648 if (event != nullptr && event->GetResult() != DragRet::DRAG_SUCCESS &&
2649 newDragValue == pattern->dragValue_ &&
2650 paintProperty->GetInputStyleValue(InputStyle::DEFAULT) != InputStyle::INLINE &&
2651 focusHub->IsFocusable()) {
2652 pattern->ShowSelectAfterDragEvent();
2653 pattern->afterDragSelect_ = true;
2654 pattern->TextFieldRequestFocus(RequestFocusReason::DRAG_END);
2655 }
2656 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
2657 }
2658 if (event != nullptr && event->GetResult() != DragRet::DRAG_SUCCESS) {
2659 pattern->afterDragSelect_ = true;
2660 }
2661 pattern->CloseKeyboard(true);
2662 };
2663 eventHub->SetOnDragEnd(std::move(onDragEnd));
2664
2665 eventHub->SetOnDrop(OnDragDrop());
2666 }
2667
ClearDragDropEvent()2668 void TextFieldPattern::ClearDragDropEvent()
2669 {
2670 auto host = GetHost();
2671 CHECK_NULL_VOID(host);
2672 auto gestureHub = host->GetOrCreateGestureEventHub();
2673 CHECK_NULL_VOID(gestureHub);
2674 gestureHub->SetTextDraggable(false);
2675 gestureHub->SetIsTextDraggable(false);
2676 auto eventHub = host->GetOrCreateEventHub<EventHub>();
2677 CHECK_NULL_VOID(eventHub);
2678 eventHub->SetOnDragStart(nullptr);
2679 eventHub->SetDefaultOnDragStart(nullptr);
2680 eventHub->SetOnDragEnter(nullptr);
2681 eventHub->SetOnDragMove(nullptr);
2682 eventHub->SetOnDragLeave(nullptr);
2683 eventHub->SetOnDragEnd(nullptr);
2684 eventHub->SetOnDrop(nullptr);
2685 }
2686
HandleOnDragStatusCallback(const DragEventType & dragEventType,const RefPtr<NotifyDragEvent> & notifyDragEvent)2687 void TextFieldPattern::HandleOnDragStatusCallback(
2688 const DragEventType& dragEventType, const RefPtr<NotifyDragEvent>& notifyDragEvent)
2689 {
2690 ScrollablePattern::HandleOnDragStatusCallback(dragEventType, notifyDragEvent);
2691 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "HandleOnDragStatusCallback dragEventType=%{public}d", dragEventType);
2692 if (dragEventType == DragEventType::DROP) {
2693 if (dragRecipientStatus_ == DragStatus::DRAGGING) {
2694 StopContentScroll();
2695 StopTwinkling();
2696 }
2697 dragRecipientStatus_ = DragStatus::NONE;
2698 }
2699 }
2700
InitTouchEvent()2701 void TextFieldPattern::InitTouchEvent()
2702 {
2703 CHECK_NULL_VOID(!touchListener_);
2704 auto host = GetHost();
2705 CHECK_NULL_VOID(host);
2706
2707 auto gesture = host->GetOrCreateGestureEventHub();
2708 CHECK_NULL_VOID(gesture);
2709 auto touchTask = [weak = WeakClaim(this)](const TouchEventInfo& info) {
2710 auto pattern = weak.Upgrade();
2711 CHECK_NULL_VOID(pattern);
2712 pattern->selectOverlay_->SetUsingMouse(info.GetSourceDevice() == SourceType::MOUSE);
2713 pattern->selectOverlay_->SetLastSourceType(info.GetSourceDevice());
2714 pattern->HandleTouchEvent(info);
2715 };
2716 touchListener_ = MakeRefPtr<TouchEventImpl>(std::move(touchTask));
2717 gesture->AddTouchEvent(touchListener_);
2718 }
2719
IsHandleDragging()2720 bool TextFieldPattern::IsHandleDragging()
2721 {
2722 CHECK_NULL_RETURN(selectOverlay_, false);
2723 return selectOverlay_->GetIsHandleDragging();
2724 }
2725
InitClickEvent()2726 void TextFieldPattern::InitClickEvent()
2727 {
2728 CHECK_NULL_VOID(!clickListener_);
2729 auto tmpHost = GetHost();
2730 CHECK_NULL_VOID(tmpHost);
2731 auto gesture = tmpHost->GetOrCreateGestureEventHub();
2732 auto clickCallback = [weak = WeakClaim(this)](GestureEvent& info) {
2733 auto pattern = weak.Upgrade();
2734 CHECK_NULL_VOID(pattern);
2735 pattern->HandleClickEvent(info);
2736 };
2737
2738 clickListener_ = MakeRefPtr<ClickEvent>(std::move(clickCallback));
2739 gesture->AddClickEvent(clickListener_);
2740 }
2741
HandleClickEvent(GestureEvent & info)2742 void TextFieldPattern::HandleClickEvent(GestureEvent& info)
2743 {
2744 CHECK_NULL_VOID(!IsDragging());
2745 CHECK_NULL_VOID(!IsHandleDragging());
2746 parentGlobalOffset_ = GetPaintRectGlobalOffset();
2747 auto focusHub = GetFocusHub();
2748 CHECK_NULL_VOID(focusHub);
2749 CHECK_NULL_VOID(selectOverlay_);
2750 auto multipleClickRecognizer = GetOrCreateMultipleClickRecognizer();
2751 CHECK_NULL_VOID(multipleClickRecognizer);
2752 if ((selectOverlay_->IsClickAtHandle(info) && !multipleClickRecognizer->IsValidClick(info)) ||
2753 !focusHub->IsFocusable()) {
2754 return;
2755 }
2756 focusIndex_ = FocuseIndex::TEXT;
2757 auto firstGetFocus = false;
2758 if (!HasFocus()) {
2759 auto host = GetHost();
2760 CHECK_NULL_VOID(host);
2761 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "textfield %{public}d request focus currently", host->GetId());
2762 firstGetFocus = true;
2763 if (!focusHub->IsFocusOnTouch().value_or(true) || !TextFieldRequestFocus(RequestFocusReason::CLICK)) {
2764 CloseSelectOverlay(true);
2765 StopTwinkling();
2766 return;
2767 }
2768 }
2769 firstGetFocus = firstGetFocus || firstClickAfterLosingFocus_;
2770 firstClickAfterLosingFocus_ = false;
2771 if (!firstGetFocus && CheckMousePressedOverScrollBar(info)) {
2772 return;
2773 }
2774 selectOverlay_->SetLastSourceType(info.GetSourceDevice());
2775 selectOverlay_->SetUsingMouse(info.GetSourceDevice() == SourceType::MOUSE);
2776 lastClickTimeStamp_ = info.GetTimeStamp();
2777 multipleClickRecognizer->StartCounting(info);
2778 // register click event
2779 if (multipleClickRecognizer->IsTripleClick()) {
2780 HandleTripleClickEvent(info);
2781 } else if (multipleClickRecognizer->IsDoubleClick()) {
2782 HandleDoubleClickEvent(info);
2783 } else {
2784 HandleSingleClickEvent(info, firstGetFocus);
2785 }
2786 if (ResetObscureTickCountDown()) {
2787 auto host = GetHost();
2788 CHECK_NULL_VOID(host);
2789 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
2790 }
2791 isFocusedBeforeClick_ = false;
2792 }
2793
CheckMousePressedOverScrollBar(GestureEvent & info)2794 bool TextFieldPattern::CheckMousePressedOverScrollBar(GestureEvent& info)
2795 {
2796 if (IsMouseOverScrollBar(&info) && hasMousePressed_) {
2797 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
2798 CHECK_NULL_RETURN(layoutProperty, false);
2799 if (layoutProperty->GetDisplayModeValue(DisplayMode::AUTO) != DisplayMode::OFF) {
2800 auto touchRegion = GetScrollBar()->GetTouchRegion();
2801 bool reverse = info.GetLocalLocation().GetY() < touchRegion.Top();
2802 ScrollPage(reverse);
2803 return true;
2804 }
2805 }
2806 return false;
2807 }
2808
HandleBetweenSelectedPosition(const GestureEvent & info)2809 bool TextFieldPattern::HandleBetweenSelectedPosition(const GestureEvent& info)
2810 {
2811 if (!IsUsingMouse() && SelectOverlayIsOn() && BetweenSelectedPosition(info.GetGlobalLocation())) {
2812 CHECK_NULL_RETURN(selectOverlay_, false);
2813 // click selected area to switch show/hide state
2814 selectOverlay_->ToggleMenu();
2815 return true;
2816 }
2817 return false;
2818 }
2819
HandleSingleClickEvent(GestureEvent & info,bool firstGetFocus)2820 void TextFieldPattern::HandleSingleClickEvent(GestureEvent& info, bool firstGetFocus)
2821 {
2822 if (mouseStatus_ != MouseStatus::NONE && IsNormalInlineState()) {
2823 return;
2824 }
2825 if (HandleBetweenSelectedPosition(info)) {
2826 selectOverlay_->SwitchToOverlayMode();
2827 return;
2828 }
2829 auto host = GetHost();
2830 CHECK_NULL_VOID(host);
2831 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
2832 auto lastCaretIndex = selectController_->GetCaretIndex();
2833 auto clickLocalOffset = GetCaretClickLocalOffset(info.GetLocalLocation());
2834 if (mouseStatus_ != MouseStatus::MOVE) {
2835 UpdateCaretByClick(clickLocalOffset);
2836 }
2837 StartTwinkling();
2838 SetIsSingleHandle(true);
2839 bool needCloseOverlay = true;
2840 bool isRepeatClickCaret = RepeatClickCaret(clickLocalOffset, lastCaretIndex) && !firstGetFocus;
2841 bool isInlineSelectAllOrEmpty = inlineSelectAllFlag_ || contentController_->IsEmpty();
2842 auto clickBlank = contentController_->IsEmpty() || selectController_->IsTouchAtLineEnd(info.GetLocalLocation());
2843 auto closeHandleAtBlank =
2844 clickBlank && isRepeatClickCaret && SelectOverlayIsOn() && selectOverlay_->IsSingleHandle();
2845 do {
2846 if (info.GetSourceDevice() == SourceType::MOUSE || (!isRepeatClickCaret && isInlineSelectAllOrEmpty) ||
2847 IsContentRectNonPositive() || closeHandleAtBlank) {
2848 break;
2849 }
2850 if (isRepeatClickCaret) {
2851 if (IsAccessibilityClick()) {
2852 break;
2853 }
2854 ProcessOverlay({ .animation = true });
2855 needCloseOverlay = false;
2856 } else if (needSelectAll_) {
2857 HandleOnSelectAll(false);
2858 }
2859 } while (false);
2860 if (needCloseOverlay || GetIsPreviewText()) {
2861 CloseSelectOverlay(true);
2862 StartTwinkling();
2863 }
2864 DoProcessAutoFill(info.GetSourceDevice());
2865 // emulate clicking bottom of the textField
2866 UpdateTextFieldManager(Offset(parentGlobalOffset_.GetX(), parentGlobalOffset_.GetY()), frameRect_.Height());
2867 TriggerAvoidOnCaretChange();
2868 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2869 }
2870
DoProcessAutoFill(SourceType sourceType)2871 void TextFieldPattern::DoProcessAutoFill(SourceType sourceType)
2872 {
2873 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "DoProcessAutoFill");
2874 if (!IsNeedProcessAutoFill()) {
2875 if (RequestKeyboardNotByFocusSwitch(RequestKeyboardReason::SINGLE_CLICK, sourceType)) {
2876 NotifyOnEditChanged(true);
2877 }
2878 return;
2879 }
2880 bool isPopup = false;
2881 auto isSuccess = ProcessAutoFill(isPopup);
2882 if (!isPopup && isSuccess) {
2883 SetNeedToRequestKeyboardInner(false, RequestKeyboardInnerChangeReason::AUTOFILL_PROCESS);
2884 } else if (RequestKeyboardNotByFocusSwitch(RequestKeyboardReason::SINGLE_CLICK, sourceType)) {
2885 NotifyOnEditChanged(true);
2886 }
2887 }
2888
IsAutoFillPasswordType(const AceAutoFillType & autoFillType)2889 bool TextFieldPattern::IsAutoFillPasswordType(const AceAutoFillType& autoFillType)
2890 {
2891 return (autoFillType == AceAutoFillType::ACE_USER_NAME || autoFillType == AceAutoFillType::ACE_PASSWORD ||
2892 autoFillType == AceAutoFillType::ACE_NEW_PASSWORD);
2893 }
2894
GetHintType()2895 HintToTypeWrap TextFieldPattern::GetHintType()
2896 {
2897 HintToTypeWrap hintToTypeWrap;
2898 auto container = Container::Current();
2899 CHECK_NULL_RETURN(container, hintToTypeWrap);
2900 auto onePlaceHolder = UtfUtils::Str16DebugToStr8(GetPlaceHolder());
2901 if (onePlaceHolder.empty()) {
2902 return hintToTypeWrap;
2903 }
2904 return container->PlaceHolderToType(onePlaceHolder);
2905 }
2906
CheckAutoFillType(const AceAutoFillType & autoFillType,bool isFromKeyBoard)2907 bool TextFieldPattern::CheckAutoFillType(const AceAutoFillType& autoFillType, bool isFromKeyBoard)
2908 {
2909 if (isFromKeyBoard) {
2910 return true;
2911 }
2912
2913 auto container = Container::Current();
2914 CHECK_NULL_RETURN(container, false);
2915 auto isTriggerPassword = IsTriggerAutoFillPassword();
2916 if (autoFillType == AceAutoFillType::ACE_UNSPECIFIED && !isTriggerPassword) {
2917 return false;
2918 } else if (isTriggerPassword) {
2919 auto tempAutoFillType = IsAutoFillUserName(autoFillType) ? AceAutoFillType::ACE_USER_NAME : autoFillType;
2920 if (!container->IsNeedToCreatePopupWindow(tempAutoFillType)) {
2921 return GetAutoFillTriggeredStateByType(autoFillType);
2922 }
2923 }
2924 return true;
2925 }
2926
GetAutoFillTriggeredStateByType(const AceAutoFillType & autoFillType)2927 bool TextFieldPattern::GetAutoFillTriggeredStateByType(const AceAutoFillType& autoFillType)
2928 {
2929 auto host = GetHost();
2930 CHECK_NULL_RETURN(host, false);
2931 auto autoFillContainerNode = firstAutoFillContainerNode_.Upgrade();
2932 CHECK_NULL_RETURN(autoFillContainerNode, false);
2933 auto stateHolder = autoFillContainerNode->GetPattern<AutoFillTriggerStateHolder>();
2934 CHECK_NULL_RETURN(stateHolder, false);
2935 if (IsAutoFillUserName(autoFillType) || autoFillType == AceAutoFillType::ACE_PASSWORD) {
2936 return !stateHolder->IsAutoFillPasswordTriggered();
2937 }
2938 if (autoFillType == AceAutoFillType::ACE_NEW_PASSWORD) {
2939 return !stateHolder->IsAutoFillNewPasswordTriggered();
2940 }
2941 return false;
2942 }
2943
SetAutoFillTriggeredStateByType(const AceAutoFillType & autoFillType)2944 void TextFieldPattern::SetAutoFillTriggeredStateByType(const AceAutoFillType& autoFillType)
2945 {
2946 auto host = GetHost();
2947 CHECK_NULL_VOID(host);
2948 auto autoFillContainerNode = firstAutoFillContainerNode_.Upgrade();
2949 CHECK_NULL_VOID(autoFillContainerNode);
2950 auto stateHolder = autoFillContainerNode->GetPattern<AutoFillTriggerStateHolder>();
2951 CHECK_NULL_VOID(stateHolder);
2952 if (IsAutoFillUserName(autoFillType) || autoFillType == AceAutoFillType::ACE_PASSWORD) {
2953 stateHolder->SetAutoFillPasswordTriggered(true);
2954 } else if (autoFillType == AceAutoFillType::ACE_NEW_PASSWORD) {
2955 stateHolder->SetAutoFillNewPasswordTriggered(true);
2956 }
2957 }
2958
GetAutoFillType(bool isNeedToHitType)2959 AceAutoFillType TextFieldPattern::GetAutoFillType(bool isNeedToHitType)
2960 {
2961 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
2962 CHECK_NULL_RETURN(layoutProperty, AceAutoFillType::ACE_UNSPECIFIED);
2963 auto aceContentType =
2964 TextContentTypeToAceAutoFillType(layoutProperty->GetTextContentTypeValue(TextContentType::UNSPECIFIED));
2965 auto aceInputType = ConvertToAceAutoFillType(layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED));
2966 if (aceContentType != AceAutoFillType::ACE_UNSPECIFIED) {
2967 return aceContentType;
2968 }
2969 if (aceInputType != AceAutoFillType::ACE_UNSPECIFIED) {
2970 return aceInputType;
2971 }
2972 if (isNeedToHitType && !IsTriggerAutoFillPassword()) {
2973 auto hintToTypeWrap = GetHintType();
2974 return hintToTypeWrap.autoFillType;
2975 }
2976 return AceAutoFillType::ACE_UNSPECIFIED;
2977 }
2978
GetAutoFillTypeAndMetaData(bool isNeedToHitType)2979 HintToTypeWrap TextFieldPattern::GetAutoFillTypeAndMetaData(bool isNeedToHitType)
2980 {
2981 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
2982 HintToTypeWrap hintToTypeWrap;
2983 CHECK_NULL_RETURN(layoutProperty, hintToTypeWrap);
2984 auto aceContentType =
2985 TextContentTypeToAceAutoFillType(layoutProperty->GetTextContentTypeValue(TextContentType::UNSPECIFIED));
2986 auto aceInputType = ConvertToAceAutoFillType(layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED));
2987 if (aceContentType != AceAutoFillType::ACE_UNSPECIFIED) {
2988 hintToTypeWrap.autoFillType = aceContentType;
2989 return hintToTypeWrap;
2990 }
2991 if (aceInputType != AceAutoFillType::ACE_UNSPECIFIED) {
2992 hintToTypeWrap.autoFillType = aceInputType;
2993 return hintToTypeWrap;
2994 }
2995 if (isNeedToHitType && !IsTriggerAutoFillPassword()) {
2996 hintToTypeWrap = GetHintType();
2997 return hintToTypeWrap;
2998 }
2999 auto jsonValue = JsonUtil::Create(true);
3000 jsonValue->Put("type", TextInputTypeToString().c_str());
3001 hintToTypeWrap.metadata = jsonValue->ToString();
3002 return hintToTypeWrap;
3003 }
3004
CheckAutoFill(bool isFromKeyBoard)3005 bool TextFieldPattern::CheckAutoFill(bool isFromKeyBoard)
3006 {
3007 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
3008 CHECK_NULL_RETURN(layoutProperty, false);
3009 bool isEnableAutoFill = layoutProperty->GetEnableAutoFillValue(true);
3010 if (!isEnableAutoFill) {
3011 return false;
3012 }
3013 return CheckAutoFillType(GetAutoFillType(), isFromKeyBoard);
3014 }
3015
ProcessAutoFill(bool & isPopup,bool isFromKeyBoard,bool isNewPassWord)3016 bool TextFieldPattern::ProcessAutoFill(bool& isPopup, bool isFromKeyBoard, bool isNewPassWord)
3017 {
3018 if (!CheckAutoFill(isFromKeyBoard)) {
3019 TAG_LOGI(AceLogTag::ACE_AUTO_FILL, "don't need to auto fill.");
3020 return false;
3021 }
3022 auto host = GetHost();
3023 CHECK_NULL_RETURN(host, false);
3024 auto autoFillType = GetAutoFillType();
3025 auto container = Container::Current();
3026 if (container == nullptr) {
3027 TAG_LOGW(AceLogTag::ACE_AUTO_FILL, "Get current container is nullptr.");
3028 return false;
3029 }
3030 if (IsTriggerAutoFillPassword() && autoFillType == AceAutoFillType::ACE_UNSPECIFIED) {
3031 autoFillType = AceAutoFillType::ACE_USER_NAME;
3032 }
3033 auto onUIExtNodeDestroy = [weak = WeakPtr<FrameNode>(host)]() {
3034 TAG_LOGI(AceLogTag::ACE_AUTO_FILL, "onUIExtNodeDestroy called.");
3035 auto textFieldNode = weak.Upgrade();
3036 CHECK_NULL_VOID(textFieldNode);
3037 auto pageNode = textFieldNode->GetPageNode();
3038 CHECK_NULL_VOID(pageNode);
3039 auto pagePattern = pageNode->GetPattern<PagePattern>();
3040 CHECK_NULL_VOID(pagePattern);
3041 pagePattern->SetIsModalCovered(false);
3042 };
3043 auto onUIExtNodeBindingCompleted = [weak = WeakPtr<FrameNode>(host)]() {
3044 TAG_LOGI(AceLogTag::ACE_AUTO_FILL, "onUIExtNodeBindingCompleted called.");
3045 auto textFieldNode = weak.Upgrade();
3046 CHECK_NULL_VOID(textFieldNode);
3047 auto pageNode = textFieldNode->GetPageNode();
3048 CHECK_NULL_VOID(pageNode);
3049 auto pagePattern = pageNode->GetPattern<PagePattern>();
3050 CHECK_NULL_VOID(pagePattern);
3051 pagePattern->SetIsModalCovered(true);
3052 };
3053
3054 auto resultCode = container->RequestAutoFill(host, autoFillType, isNewPassWord, isPopup, autoFillSessionId_, true,
3055 onUIExtNodeDestroy, onUIExtNodeBindingCompleted);
3056 if (resultCode != AceAutoFillError::ACE_AUTO_FILL_PREVIOUS_REQUEST_NOT_FINISHED) {
3057 SetAutoFillTriggeredStateByType(autoFillType);
3058 SetFillRequestFinish(false);
3059 }
3060 return resultCode == AceAutoFillError::ACE_AUTO_FILL_SUCCESS;
3061 }
3062
HandleDoubleClickEvent(GestureEvent & info)3063 void TextFieldPattern::HandleDoubleClickEvent(GestureEvent& info)
3064 {
3065 if (GetIsPreviewText()) {
3066 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "refuse double click when has preview text.");
3067 return;
3068 }
3069
3070 if (showSelect_) {
3071 SetIsSingleHandle(true);
3072 }
3073 if (RequestKeyboardNotByFocusSwitch(RequestKeyboardReason::DOUBLE_CLICK)) {
3074 NotifyOnEditChanged(true);
3075 }
3076 if (CanChangeSelectState()) {
3077 selectController_->UpdateSelectByOffset(info.GetLocalLocation());
3078 UpdateCaretInfoToController();
3079 }
3080 if (IsSelected()) {
3081 StopTwinkling();
3082 SetIsSingleHandle(false);
3083 }
3084 if (info.GetSourceDevice() != SourceType::MOUSE && !IsContentRectNonPositive()) {
3085 ProcessOverlay({ .animation = true });
3086 }
3087 auto host = GetHost();
3088 CHECK_NULL_VOID(host);
3089 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
3090 }
3091
HandleTripleClickEvent(GestureEvent & info)3092 void TextFieldPattern::HandleTripleClickEvent(GestureEvent& info)
3093 {
3094 if (GetIsPreviewText()) {
3095 return;
3096 }
3097
3098 if (showSelect_) {
3099 SetIsSingleHandle(true);
3100 CloseSelectOverlay();
3101 }
3102 if (CanChangeSelectState()) {
3103 selectController_->UpdateSelectPragraphByOffset(info.GetLocalLocation());
3104 UpdateCaretInfoToController();
3105 }
3106 if (IsSelected()) {
3107 StopTwinkling();
3108 SetIsSingleHandle(false);
3109 } else {
3110 StartTwinkling();
3111 }
3112 if (info.GetSourceDevice() != SourceType::MOUSE && !contentController_->IsEmpty() && !IsContentRectNonPositive()) {
3113 ProcessOverlay({ .animation = true });
3114 }
3115 auto host = GetHost();
3116 CHECK_NULL_VOID(host);
3117 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
3118 }
3119
ScheduleCursorTwinkling()3120 void TextFieldPattern::ScheduleCursorTwinkling()
3121 {
3122 if (isTransparent_) {
3123 return;
3124 }
3125 auto host = GetHost();
3126 CHECK_NULL_VOID(host);
3127 auto context = host->GetContext();
3128 CHECK_NULL_VOID(context);
3129
3130 if (!context->GetTaskExecutor()) {
3131 return;
3132 }
3133
3134 if (dragRecipientStatus_ == DragStatus::DRAGGING) {
3135 return;
3136 }
3137
3138 auto weak = WeakClaim(this);
3139 cursorTwinklingTask_.Reset([weak] {
3140 auto client = weak.Upgrade();
3141 CHECK_NULL_VOID(client);
3142 client->OnCursorTwinkling();
3143 });
3144 auto taskExecutor = context->GetTaskExecutor();
3145 CHECK_NULL_VOID(taskExecutor);
3146 taskExecutor->PostDelayedTask(cursorTwinklingTask_, TaskExecutor::TaskType::UI, twinklingInterval_,
3147 "ArkUITextFieldCursorTwinkling");
3148 }
3149
StartTwinkling()3150 void TextFieldPattern::StartTwinkling()
3151 {
3152 auto autoFillController = GetOrCreateAutoFillController();
3153 auto autoFillAnimationStatus =
3154 autoFillController ? autoFillController->GetAutoFillAnimationStatus() : AutoFillAnimationStatus::INIT;
3155 if (isTransparent_ || !HasFocus() || focusIndex_ == FocuseIndex::CANCEL || focusIndex_ == FocuseIndex::UNIT ||
3156 autoFillAnimationStatus != AutoFillAnimationStatus::INIT) {
3157 return;
3158 }
3159 // Ignore the result because all ops are called on this same thread (ACE UI).
3160 // The only reason failed is that the task has finished.
3161 cursorTwinklingTask_.Cancel();
3162
3163 // Show cursor right now.
3164 isCaretTwinkling_ = true;
3165 cursorVisible_ = true;
3166 auto tmpHost = GetHost();
3167 CHECK_NULL_VOID(tmpHost);
3168 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
3169 ScheduleCursorTwinkling();
3170 }
3171
OnCursorTwinkling()3172 void TextFieldPattern::OnCursorTwinkling()
3173 {
3174 cursorTwinklingTask_.Cancel();
3175 cursorVisible_ = !cursorVisible_;
3176 auto shouldMeasure = !IsTextArea() && IsInPasswordMode() && GetTextObscured() && obscureTickCountDown_ == 1;
3177 if (IsInPasswordMode() && GetTextObscured() && obscureTickCountDown_ > 0) {
3178 --obscureTickCountDown_;
3179 }
3180 auto host = GetHost();
3181 CHECK_NULL_VOID(host);
3182 if (shouldMeasure) {
3183 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
3184 } else {
3185 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
3186 }
3187 ScheduleCursorTwinkling();
3188 }
3189
StopTwinkling()3190 void TextFieldPattern::StopTwinkling()
3191 {
3192 cursorTwinklingTask_.Cancel();
3193
3194 // Repaint only if cursor is visible for now.
3195 isCaretTwinkling_ = false;
3196 auto tmpHost = GetHost();
3197 CHECK_NULL_VOID(tmpHost);
3198 if (cursorVisible_) {
3199 cursorVisible_ = false;
3200 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
3201 }
3202 if (ResetObscureTickCountDown()) {
3203 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
3204 }
3205 }
3206
ShowCaretAndStopTwinkling()3207 void TextFieldPattern::ShowCaretAndStopTwinkling()
3208 {
3209 cursorTwinklingTask_.Cancel();
3210
3211 // Repaint and make cursor visible.
3212 isCaretTwinkling_ = false;
3213 auto tmpHost = GetHost();
3214 CHECK_NULL_VOID(tmpHost);
3215 cursorVisible_ = true;
3216 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
3217 if (ResetObscureTickCountDown()) {
3218 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
3219 }
3220 }
3221
CheckIfNeedToResetKeyboard()3222 void TextFieldPattern::CheckIfNeedToResetKeyboard()
3223 {
3224 auto tmpHost = GetHost();
3225 CHECK_NULL_VOID(tmpHost);
3226 auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
3227 CHECK_NULL_VOID(layoutProperty);
3228 bool needToResetKeyboard = false;
3229 // check unspecified for first time entrance
3230 if (keyboard_ != layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED)) {
3231 auto autoFillType = GetAutoFillType(false);
3232 if (layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED) != TextInputType::UNSPECIFIED ||
3233 keyBoardMap_.find(autoFillType) == keyBoardMap_.end() || keyboard_ != keyBoardMap_[autoFillType]) {
3234 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "textfield %{public}d Keyboard type %{public}d changed to %{public}d",
3235 tmpHost->GetId(), (int)keyboard_, layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED));
3236 keyboard_ = layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED);
3237 ResetPreviewTextState();
3238 needToResetKeyboard = true;
3239 }
3240 }
3241 if (!needToResetKeyboard && action_ != TextInputAction::UNSPECIFIED) {
3242 needToResetKeyboard = action_ != GetTextInputActionValue(GetDefaultTextInputAction());
3243 }
3244 action_ = GetTextInputActionValue(GetDefaultTextInputAction());
3245 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
3246 if (needToResetKeyboard && HasFocus()) {
3247 if (isCustomKeyboardAttached_ || keyboard_ == TextInputType::ONE_TIME_CODE) {
3248 RequestKeyboardNotByFocusSwitch(RequestKeyboardReason::RESET_KEYBOARD);
3249 return;
3250 }
3251 #if defined(ENABLE_STANDARD_INPUT)
3252 auto inputMethod = MiscServices::InputMethodController::GetInstance();
3253 CHECK_NULL_VOID(inputMethod);
3254 MiscServices::Configuration config;
3255 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "textfield %{public}d Keyboard action is %{public}d",
3256 tmpHost->GetId(), action_);
3257 config.SetEnterKeyType(static_cast<MiscServices::EnterKeyType>(action_));
3258 config.SetTextInputType(static_cast<MiscServices::TextInputType>(keyboard_));
3259 inputMethod->OnConfigurationChange(config);
3260 #endif
3261 }
3262 #else
3263 if (needToResetKeyboard && HasConnection()) {
3264 CloseKeyboard(true);
3265 RequestKeyboard(false, true, true);
3266 }
3267 #endif
3268 }
3269
ProcessScroll()3270 void TextFieldPattern::ProcessScroll()
3271 {
3272 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
3273 CHECK_NULL_VOID(layoutProperty);
3274 if (IsTextArea() || IsNormalInlineState()) {
3275 SetAxis(Axis::VERTICAL);
3276 if (!GetScrollableEvent()) {
3277 AddScrollEvent();
3278 }
3279 auto barState = layoutProperty->GetDisplayModeValue(DisplayMode::AUTO);
3280 if (!barState_.has_value()) {
3281 barState_ = barState;
3282 }
3283 scrollBarVisible_ = barState != DisplayMode::OFF;
3284 SetScrollBar(barState == DisplayMode::OFF ? DisplayMode::ON : barState);
3285 auto scrollBar = GetScrollBar();
3286 if (scrollBar) {
3287 scrollBar->SetMinHeight(SCROLL_BAR_MIN_HEIGHT);
3288 }
3289 if (textFieldOverlayModifier_) {
3290 textFieldOverlayModifier_->SetScrollBar(scrollBar);
3291 UpdateScrollBarOffset();
3292 }
3293 } else {
3294 SetAxis(Axis::HORIZONTAL);
3295 SetScrollBar(DisplayMode::OFF);
3296 if (!GetScrollableEvent()) {
3297 AddScrollEvent();
3298 SetScrollEnabled(false);
3299 }
3300 }
3301 }
3302
HandleDeleteOnCounterScene()3303 void TextFieldPattern::HandleDeleteOnCounterScene()
3304 {
3305 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
3306 CHECK_NULL_VOID(layoutProperty);
3307 if (layoutProperty->HasMaxLength()) {
3308 showCountBorderStyle_ = false;
3309 HandleCountStyle();
3310 }
3311 }
3312
HandleCountStyle()3313 void TextFieldPattern::HandleCountStyle()
3314 {
3315 bool noDeleteOperation = deleteBackwardOperations_.empty() && deleteForwardOperations_.empty();
3316 if (!IsShowCount() || !noDeleteOperation) {
3317 return;
3318 }
3319 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
3320 CHECK_NULL_VOID(layoutProperty);
3321 auto inputValue = layoutProperty->GetSetCounterValue(DEFAULT_MODE);
3322 auto showBorder = layoutProperty->GetShowHighlightBorderValue(true);
3323 if (inputValue == DEFAULT_MODE) {
3324 if (showBorder) {
3325 HandleCounterBorder();
3326 }
3327 if (showCountBorderStyle_ && !showBorder) {
3328 UltralimitShake();
3329 }
3330 } else if (inputValue != ILLEGAL_VALUE) {
3331 if (showBorder) {
3332 HandleCounterBorder();
3333 }
3334 if (showCountBorderStyle_) {
3335 UltralimitShake();
3336 }
3337 }
3338 }
3339
ProcessUnderlineColorOnModifierDone()3340 void TextFieldPattern::ProcessUnderlineColorOnModifierDone()
3341 {
3342 if (IsShowError()) {
3343 return;
3344 }
3345 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
3346 auto inputValue = layoutProperty->GetSetCounterValue(DEFAULT_MODE);
3347 if (inputValue == ILLEGAL_VALUE) {
3348 return;
3349 }
3350 auto showBorder = layoutProperty->GetShowHighlightBorderValue(true);
3351 if (inputValue != DEFAULT_MODE && !showBorder) {
3352 return;
3353 }
3354 if (showCountBorderStyle_ && IsUnderlineMode() && HasFocus()) {
3355 auto theme = GetTheme();
3356 CHECK_NULL_VOID(theme);
3357 SetUnderlineColor(
3358 userUnderlineColor_.error.value_or(theme->GetErrorUnderlineColor()));
3359 }
3360 }
3361
ProcessCounter()3362 void TextFieldPattern::ProcessCounter()
3363 {
3364 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
3365 CHECK_NULL_VOID(layoutProperty);
3366 if (IsShowCount()) {
3367 AddCounterNode();
3368 CHECK_NULL_VOID(counterDecorator_);
3369 counterDecorator_->UpdateTextFieldMargin();
3370 } else {
3371 CleanCounterNode();
3372 }
3373 }
3374
ProcessSelection()3375 void TextFieldPattern::ProcessSelection()
3376 {
3377 auto textWidth = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
3378 if (SelectOverlayIsOn()) {
3379 needToRefreshSelectOverlay_ = textWidth > 0;
3380 UpdateSelection(std::clamp(selectController_->GetStartIndex(), 0, textWidth),
3381 std::clamp(selectController_->GetEndIndex(), 0, textWidth));
3382 SetIsSingleHandle(!IsSelected());
3383 selectOverlay_->UpdateHandleColor();
3384 if (isTextChangedAtCreation_ && textWidth == 0) {
3385 CloseSelectOverlay();
3386 StartTwinkling();
3387 }
3388 if (!isTextChangedAtCreation_ && selectOverlay_->IsShowMouseMenu()) {
3389 needToRefreshSelectOverlay_ = false;
3390 }
3391 return;
3392 }
3393 if (HasFocus()) {
3394 if (IsGestureSelectingText()) {
3395 UpdateSelection(std::clamp(selectController_->GetStartIndex(), 0, textWidth),
3396 std::clamp(selectController_->GetEndIndex(), 0, textWidth));
3397 }
3398 if (!IsSelected()) {
3399 StartTwinkling();
3400 }
3401 return;
3402 }
3403 needToRefreshSelectOverlay_ = false;
3404 }
3405
UpdateSelectOverlay(const RefPtr<OHOS::Ace::TextFieldTheme> & textFieldTheme)3406 void TextFieldPattern::UpdateSelectOverlay(const RefPtr<OHOS::Ace::TextFieldTheme>& textFieldTheme)
3407 {
3408 CHECK_NULL_VOID(textFieldTheme);
3409 auto container = Container::Current();
3410 if (container && container->IsSceneBoardWindow()) {
3411 return;
3412 }
3413 selectOverlay_->SetMenuTranslateIsSupport(textFieldTheme->GetTranslateIsSupport());
3414 selectOverlay_->SetIsSupportMenuSearch(textFieldTheme->GetIsSupportSearch());
3415 }
3416
OnModifyDone()3417 void TextFieldPattern::OnModifyDone()
3418 {
3419 auto host = GetHost();
3420 Pattern::OnModifyDone();
3421 CHECK_NULL_VOID(host);
3422 auto context = host->GetContext();
3423 CHECK_NULL_VOID(context);
3424 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
3425 CHECK_NULL_VOID(layoutProperty);
3426 auto textFieldTheme = GetTheme();
3427 CHECK_NULL_VOID(textFieldTheme);
3428 directionKeysMoveFocusOut_ = textFieldTheme->GetDirectionKeysMoveFocusOut();
3429 CheckIfNeedToResetKeyboard();
3430 auto renderContext = host->GetRenderContext();
3431 CHECK_NULL_VOID(renderContext);
3432 auto textFieldPaintProperty = host->GetPaintPropertyPtr<TextFieldPaintProperty>();
3433 if (textFieldPaintProperty && textFieldPaintProperty->HasBorderColorFlagByUser()) {
3434 textFieldPaintProperty->UpdateBorderColorFlagByUser(
3435 renderContext->GetBorderColorValue(BorderColorProperty {}));
3436 }
3437 isTransparent_ = renderContext->GetOpacityValue(1.0f) == 0.0f;
3438 ApplyNormalTheme();
3439 ApplyUnderlineTheme();
3440 ApplyInlineTheme();
3441 ProcessInnerPadding();
3442 ProcessNumberOfLines();
3443
3444 InitClickEvent();
3445 InitLongPressEvent();
3446 InitFocusEvent();
3447 InitMouseEvent();
3448 InitTouchEvent();
3449
3450 SetAccessibilityAction();
3451 FilterInitializeText();
3452 InitDisableColor();
3453 ProcessResponseArea();
3454 if (!shiftFlag_) {
3455 InitDragEvent();
3456 }
3457 Register2DragDropManager();
3458 ProcessUnderlineColorOnModifierDone();
3459 if (barState_.has_value() && barState_.value() != layoutProperty->GetDisplayModeValue(DisplayMode::AUTO) &&
3460 HasFocus() && IsNormalInlineState()) {
3461 lastTextRectY_ = textRect_.GetY();
3462 }
3463 if (!IsDisabled() && IsShowError()) {
3464 SetShowError();
3465 } else {
3466 CleanErrorNode();
3467 }
3468 // The textRect position can't be changed by only redraw.
3469 if (!initTextRect_) {
3470 auto border = GetBorderWidthProperty();
3471 textRect_.SetLeft(GetPaddingLeft() + GetBorderLeft(border));
3472 textRect_.SetTop(GetPaddingTop() + GetBorderTop(border));
3473 AdjustTextRectByCleanNode(textRect_);
3474 initTextRect_ = true;
3475 }
3476 CalculateDefaultCursor();
3477
3478 ProcessSelection();
3479 isTextChangedAtCreation_ = false;
3480 if (layoutProperty->GetTypeChangedValue(false)) {
3481 layoutProperty->ResetTypeChanged();
3482 ClearOperationRecords();
3483 }
3484 ProcessScroll();
3485 ProcessCounter();
3486 Register2DragDropManager();
3487 auto autoFillContainerNode = firstAutoFillContainerNode_.Upgrade();
3488 if (autoFillContainerNode) {
3489 UpdateTextFieldInfo();
3490 }
3491 TriggerAvoidWhenCaretGoesDown();
3492 UpdateSelectOverlay(textFieldTheme);
3493 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
3494 SetIsEnableSubWindowMenu();
3495 isModifyDone_ = true;
3496 if (host->GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
3497 InitCancelButtonMouseEvent();
3498 InitPasswordButtonMouseEvent();
3499 }
3500 }
3501
TriggerAvoidWhenCaretGoesDown()3502 void TextFieldPattern::TriggerAvoidWhenCaretGoesDown()
3503 {
3504 auto host = GetHost();
3505 CHECK_NULL_VOID(host);
3506 auto context = host->GetContext();
3507 CHECK_NULL_VOID(context);
3508 auto textFieldManager = DynamicCast<TextFieldManagerNG>(context->GetTextFieldManager());
3509 if (context->UsingCaretAvoidMode() && HasFocus() && textFieldManager) {
3510 context->AddAfterLayoutTask([weak = WeakClaim(this), manager = WeakPtr<TextFieldManagerNG>(textFieldManager)] {
3511 auto textField = weak.Upgrade();
3512 CHECK_NULL_VOID(textField);
3513 auto textFieldManager = manager.Upgrade();
3514 CHECK_NULL_VOID(textFieldManager);
3515 auto caretPos = textFieldManager->GetFocusedNodeCaretRect().Top() + textFieldManager->GetHeight();
3516 auto lastCaretPos = textField->GetLastCaretPos();
3517 if (!lastCaretPos.has_value() ||
3518 (caretPos > lastCaretPos.value() && textField->CheckIfNeedAvoidOnCaretChange(caretPos))) {
3519 TAG_LOGI(ACE_KEYBOARD, "Caret Position Goes Down, Retrigger Avoid");
3520 textField->TriggerAvoidOnCaretChange();
3521 }
3522 });
3523 }
3524 }
3525
CheckIfNeedAvoidOnCaretChange(float caretPos)3526 bool TextFieldPattern::CheckIfNeedAvoidOnCaretChange(float caretPos)
3527 {
3528 #if defined(ENABLE_STANDARD_INPUT)
3529 auto host = GetHost();
3530 CHECK_NULL_RETURN(host, true);
3531 auto pipeline = host->GetContext();
3532 CHECK_NULL_RETURN(pipeline, true);
3533 auto safeAreaMgr = pipeline->GetSafeAreaManager();
3534 CHECK_NULL_RETURN(safeAreaMgr, true);
3535 auto keyboard = safeAreaMgr->GetKeyboardInset();
3536 return keyboard.Length() > 0 && GreatNotEqual(caretPos, keyboard.start - AVOID_OFFSET.ConvertToPx());
3537 #else
3538 return true;
3539 #endif
3540 }
3541
ApplyNormalTheme()3542 void TextFieldPattern::ApplyNormalTheme()
3543 {
3544 if (IsUnderlineMode() || IsInlineMode()) {
3545 return;
3546 }
3547 SetThemeAttr();
3548 }
3549
OnAfterModifyDone()3550 void TextFieldPattern::OnAfterModifyDone()
3551 {
3552 auto host = GetHost();
3553 CHECK_NULL_VOID(host);
3554 auto inspectorId = host->GetInspectorId().value_or("");
3555 if (!inspectorId.empty()) {
3556 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
3557 bool isPwdType = false;
3558 if (layoutProperty) {
3559 auto inputType = layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED);
3560 isPwdType = inputType == TextInputType::VISIBLE_PASSWORD || inputType == TextInputType::NUMBER_PASSWORD ||
3561 inputType == TextInputType::SCREEN_LOCK_PASSWORD || inputType == TextInputType::NEW_PASSWORD;
3562 }
3563 if (!isPwdType) {
3564 Recorder::NodeDataCache::Get().PutString(host, inspectorId, contentController_->GetTextValue());
3565 }
3566 }
3567 }
3568
CalculateDefaultCursor()3569 void TextFieldPattern::CalculateDefaultCursor()
3570 {
3571 auto tmpHost = GetHost();
3572 CHECK_NULL_VOID(tmpHost);
3573 auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
3574 CHECK_NULL_VOID(layoutProperty);
3575 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
3576 CHECK_NULL_VOID(paintProperty);
3577 auto textFieldTheme = GetTheme();
3578 CHECK_NULL_VOID(textFieldTheme);
3579 float caretWidth = paintProperty->GetCursorWidth().has_value()
3580 ? static_cast<float>(paintProperty->GetCursorWidthValue().ConvertToPx())
3581 : static_cast<float>(textFieldTheme->GetCursorWidth().ConvertToPx());
3582 selectController_->UpdateCaretWidth(caretWidth);
3583 if (!contentController_->IsEmpty()) {
3584 return;
3585 }
3586 selectController_->UpdateCaretHeight(PreferredLineHeight());
3587 }
3588
AutoFillValueChanged()3589 void TextFieldPattern::AutoFillValueChanged()
3590 {
3591 if (IsFillRequestFinish()) {
3592 return;
3593 }
3594 auto host = GetHost();
3595 CHECK_NULL_VOID(host);
3596 auto aceContentType = GetAutoFillType();
3597 auto container = Container::Current();
3598 CHECK_NULL_VOID(container);
3599 auto isValidType =
3600 (aceContentType >= AceAutoFillType::ACE_PASSWORD &&
3601 aceContentType <= AceAutoFillType::END) || IsAutoFillUserName(aceContentType);
3602 if (isValidType && CheckAutoFill()) {
3603 container->UpdatePopupUIExtension(host, autoFillSessionId_);
3604 }
3605 }
3606
FireOnTextChangeEvent()3607 bool TextFieldPattern::FireOnTextChangeEvent()
3608 {
3609 auto host = GetHost();
3610 CHECK_NULL_RETURN(host, false);
3611 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
3612 CHECK_NULL_RETURN(layoutProperty, false);
3613 auto textCache = layoutProperty->GetValueValue(u"");
3614 auto previewTextCache = layoutProperty->GetPreviewTextValue({GetPreviewTextStart(), u""});
3615 PreviewText curPreviewText = {GetPreviewTextStart(), GetPreviewTextValue()};
3616 if (textCache == contentController_->GetTextUtf16Value() && previewTextCache.value == curPreviewText.value) {
3617 return false;
3618 }
3619 ResetOriginCaretPosition();
3620 AutoFillValueChanged();
3621 auto pipeline = GetContext();
3622 CHECK_NULL_RETURN(pipeline, false);
3623 AddTextFireOnChange();
3624 auto context = host->GetContextRefPtr();
3625 CHECK_NULL_RETURN(context, false);
3626 auto taskExecutor = context->GetTaskExecutor();
3627 CHECK_NULL_RETURN(taskExecutor, false);
3628 taskExecutor->PostTask(
3629 [weak = WeakClaim(this)] {
3630 auto pattern = weak.Upgrade();
3631 CHECK_NULL_VOID(pattern);
3632 if (!pattern->HasFocus()) {
3633 return;
3634 }
3635 pattern->ScrollToSafeArea();
3636 pattern->TriggerAvoidOnCaretChange();
3637 if (pattern->customKeyboard_ || pattern->customKeyboardBuilder_) {
3638 pattern->StartTwinkling();
3639 }
3640 },
3641 TaskExecutor::TaskType::UI, "ArkUITextFieldScrollToSafeArea", PriorityType::VIP);
3642 return true;
3643 }
3644
AddTextFireOnChange()3645 void TextFieldPattern::AddTextFireOnChange()
3646 {
3647 auto host = GetHost();
3648 CHECK_NULL_VOID(host);
3649 auto context = host->GetContextRefPtr();
3650 CHECK_NULL_VOID(context);
3651 context->AddAfterLayoutTask([weak = AceType::WeakClaim(this)] {
3652 auto pattern = weak.Upgrade();
3653 CHECK_NULL_VOID(pattern);
3654 auto host = pattern->GetHost();
3655 CHECK_NULL_VOID(host);
3656 auto eventHub = host->GetOrCreateEventHub<TextFieldEventHub>();
3657 CHECK_NULL_VOID(eventHub);
3658 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
3659 CHECK_NULL_VOID(layoutProperty);
3660 auto textCache = layoutProperty->GetValueValue(u"");
3661 auto newText = pattern->GetTextContentController()->GetTextUtf16Value();
3662 layoutProperty->UpdateValue(newText);
3663 host->OnAccessibilityEvent(AccessibilityEventType::TEXT_CHANGE, UtfUtils::Str16DebugToStr8(textCache),
3664 UtfUtils::Str16DebugToStr8(newText));
3665 ChangeValueInfo changeValueInfo;
3666 changeValueInfo.value = pattern->GetBodyTextValue();
3667 changeValueInfo.previewText.offset = pattern->hasPreviewText_ ? pattern->GetPreviewTextStart() : -1;
3668 changeValueInfo.previewText.value = pattern->GetPreviewTextValue();
3669 changeValueInfo.oldPreviewText = pattern->callbackOldPreviewText_;
3670 changeValueInfo.oldContent = pattern->callbackOldContent_;
3671 changeValueInfo.rangeBefore = pattern->callbackRangeBefore_;
3672 changeValueInfo.rangeAfter = pattern->callbackRangeAfter_;
3673 layoutProperty->UpdatePreviewText(changeValueInfo.previewText);
3674 eventHub->FireOnChange(changeValueInfo);
3675
3676 pattern->RecordTextInputEvent();
3677 auto callback = [weakPattern = weak](const std::string& type, const std::string& content) {
3678 auto strongPattern = weakPattern.Upgrade();
3679 CHECK_NULL_VOID(strongPattern);
3680 strongPattern->OnAccessibilityEventTextChange(type, content);
3681 };
3682
3683 pattern->ProcessAccessibilityTextChange(
3684 UtfUtils::Str16DebugToStr8(newText),
3685 std::move(callback),
3686 AceLogTag::ACE_TEXT_FIELD
3687 );
3688 });
3689 }
3690
RecordTextInputEvent()3691 void TextFieldPattern::RecordTextInputEvent()
3692 {
3693 if (!Recorder::EventRecorder::Get().IsRecordEnable(Recorder::EventCategory::CATEGORY_TEXT_INPUT)) {
3694 return;
3695 }
3696 auto host = GetHost();
3697 CHECK_NULL_VOID(host);
3698 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
3699 CHECK_NULL_VOID(layoutProperty);
3700 auto inputType = layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED);
3701 auto isPwdType = inputType == TextInputType::VISIBLE_PASSWORD || inputType == TextInputType::NUMBER_PASSWORD ||
3702 inputType == TextInputType::SCREEN_LOCK_PASSWORD || inputType == TextInputType::NEW_PASSWORD;
3703 if (isPwdType) {
3704 return;
3705 }
3706 Recorder::EventParamsBuilder builder;
3707 builder.SetEventCategory(Recorder::EventCategory::CATEGORY_TEXT_INPUT)
3708 .SetEventType(Recorder::EventType::TEXT_INPUT)
3709 .SetId(host->GetInspectorId().value_or(""))
3710 .SetType(host->GetTag())
3711 .SetText(UtfUtils::Str16DebugToStr8(GetBodyTextValue()))
3712 .SetDescription(host->GetAutoEventParamValue(""))
3713 .SetHost(host);
3714 Recorder::EventRecorder::Get().OnEvent(std::move(builder));
3715 }
3716
FilterInitializeText()3717 void TextFieldPattern::FilterInitializeText()
3718 {
3719 if (HasInputOperation()) {
3720 return;
3721 }
3722 if (HasFocus()) {
3723 UpdateShowCountBorderStyle();
3724 if (showCountBorderStyle_) {
3725 HandleCountStyle();
3726 }
3727 }
3728 if (!contentController_->IsEmpty()) {
3729 auto originCaretIndex =
3730 TextRange { selectController_->GetFirstHandleIndex(), selectController_->GetSecondHandleIndex() };
3731 ChangeValueInfo changeValueInfo;
3732 changeValueInfo.oldContent = GetBodyTextValue();
3733 changeValueInfo.oldPreviewText.offset = hasPreviewText_ ? GetPreviewTextStart() : -1;
3734 changeValueInfo.oldPreviewText.value = GetPreviewTextValue();
3735 changeValueInfo.rangeBefore = TextRange { 0, changeValueInfo.oldContent.length() };
3736 auto textChanged = contentController_->FilterValue();
3737 if (isFilterChanged_) {
3738 changeValueInfo.value = GetBodyTextValue();
3739 changeValueInfo.previewText.offset = hasPreviewText_ ? GetPreviewTextStart() : -1;
3740 changeValueInfo.previewText.value = GetPreviewTextValue();
3741 changeValueInfo.rangeAfter = TextRange { 0, changeValueInfo.value.length() };
3742 bool isWillChange = FireOnWillChange(changeValueInfo);
3743 isFilterChanged_ = false;
3744 if (!isWillChange) {
3745 RecoverTextValueAndCaret(changeValueInfo.oldContent, originCaretIndex);
3746 return;
3747 }
3748 }
3749 if (!isTextChangedAtCreation_) {
3750 isTextChangedAtCreation_ = textChanged;
3751 }
3752 }
3753 if (static_cast<int32_t>(GetTextUtf16Value().length()) < GetCaretIndex()) {
3754 selectController_->UpdateCaretIndex(static_cast<int32_t>(GetTextUtf16Value().length()));
3755 }
3756 UpdateShowCountBorderStyle();
3757 }
3758
IsDisabled()3759 bool TextFieldPattern::IsDisabled()
3760 {
3761 auto tmpHost = GetHost();
3762 CHECK_NULL_RETURN(tmpHost, true);
3763 auto eventHub = tmpHost->GetOrCreateEventHub<TextFieldEventHub>();
3764 CHECK_NULL_RETURN(eventHub, true);
3765 auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
3766 CHECK_NULL_RETURN(layoutProperty, true);
3767 return !eventHub->IsEnabled();
3768 }
3769
GetUnderlinePadding(const RefPtr<TextFieldTheme> & theme,bool processLeftPadding,bool processRightPadding) const3770 Edge TextFieldPattern::GetUnderlinePadding(const RefPtr<TextFieldTheme>& theme,
3771 bool processLeftPadding, bool processRightPadding) const
3772 {
3773 auto themePadding = theme->GetUnderlinePadding();
3774 auto host = GetHost();
3775 CHECK_NULL_RETURN(host, themePadding);
3776 if (!IsUnderlineAndButtonMode() || host->LessThanAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
3777 return themePadding;
3778 }
3779 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
3780 CHECK_NULL_RETURN(layoutProperty, themePadding);
3781 auto isRTL = layoutProperty->GetNonAutoLayoutDirection() == TextDirection::RTL;
3782 if (isRTL) {
3783 themePadding.SetLeft(theme->GetPadding().Left());
3784 } else {
3785 themePadding.SetRight(theme->GetPadding().Right());
3786 }
3787 if (processLeftPadding) {
3788 themePadding.SetLeft(theme->GetPadding().Left());
3789 }
3790 if (processRightPadding) {
3791 themePadding.SetRight(theme->GetPadding().Right());
3792 }
3793 return themePadding;
3794 }
3795
ProcessInnerPadding()3796 void TextFieldPattern::ProcessInnerPadding()
3797 {
3798 auto textFieldTheme = GetTheme();
3799 CHECK_NULL_VOID(textFieldTheme);
3800 auto themePadding = IsUnderlineMode() ? GetUnderlinePadding(textFieldTheme, false, false) :
3801 textFieldTheme->GetPadding();
3802 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
3803 CHECK_NULL_VOID(layoutProperty);
3804 PaddingPropertyF utilPadding;
3805 const auto& paddingProperty = layoutProperty->GetPaddingProperty();
3806 auto left = !paddingProperty ? CalcLength(themePadding.Left()).GetDimension()
3807 : paddingProperty->left.value_or(CalcLength(themePadding.Left())).GetDimension();
3808 utilPadding.left = left.ConvertToPx();
3809 auto top = !paddingProperty ? CalcLength(themePadding.Top()).GetDimension()
3810 : paddingProperty->top.value_or(CalcLength(themePadding.Top())).GetDimension();
3811 utilPadding.top = top.ConvertToPx();
3812 auto bottom = !paddingProperty ? CalcLength(themePadding.Bottom()).GetDimension()
3813 : paddingProperty->bottom.value_or(CalcLength(themePadding.Bottom())).GetDimension();
3814 utilPadding.bottom = bottom.ConvertToPx();
3815 auto right = !paddingProperty ? CalcLength(themePadding.Right()).GetDimension()
3816 : paddingProperty->right.value_or(CalcLength(themePadding.Right())).GetDimension();
3817 utilPadding.right = right.ConvertToPx();
3818 utilPadding_ = utilPadding;
3819 PaddingProperty paddings;
3820 paddings.top = NG::CalcLength(top);
3821 paddings.bottom = NG::CalcLength(bottom);
3822 paddings.left = NG::CalcLength(left);
3823 paddings.right = NG::CalcLength(right);
3824 layoutProperty->UpdatePadding(paddings);
3825 }
3826
ProcessNumberOfLines()3827 void TextFieldPattern::ProcessNumberOfLines()
3828 {
3829 auto tmpHost = GetHost();
3830 CHECK_NULL_VOID(tmpHost);
3831 auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
3832 CHECK_NULL_VOID(layoutProperty && layoutProperty->HasNumberOfLines());
3833 auto numberOfLines = layoutProperty->GetNumberOfLines().value();
3834 CHECK_NULL_VOID(numberOfLines > 0);
3835 auto lineHeight = layoutProperty->GetLineHeight().value_or(0.0_vp).ConvertToPx();
3836 if (LessOrEqual(lineHeight, 0.f)) {
3837 lineHeight = PreferredLineHeight(false);
3838 }
3839 auto lineSpacing = layoutProperty->GetLineSpacing().value_or(0.0_vp).ConvertToPx();
3840 auto contentHeight = numberOfLines * lineHeight + numberOfLines * lineSpacing;
3841 auto height = contentHeight + GetVerticalPaddingAndBorderSum();
3842
3843 // get previously user defined ideal width
3844 std::optional<CalcLength> width = std::nullopt;
3845 auto &&layoutConstraint = layoutProperty->GetCalcLayoutConstraint();
3846 if (layoutConstraint && layoutConstraint->selfIdealSize) {
3847 width = layoutConstraint->selfIdealSize->Width();
3848 }
3849 layoutProperty->UpdateUserDefinedIdealSize(CalcSize(width, CalcLength(height)));
3850 }
3851
InitLongPressEvent()3852 void TextFieldPattern::InitLongPressEvent()
3853 {
3854 CHECK_NULL_VOID(!longPressEvent_);
3855 auto tmpHost = GetHost();
3856 CHECK_NULL_VOID(tmpHost);
3857 auto gesture = tmpHost->GetOrCreateGestureEventHub();
3858 auto longPressCallback = [weak = WeakClaim(this)](GestureEvent& info) {
3859 auto pattern = weak.Upgrade();
3860 CHECK_NULL_VOID(pattern);
3861 pattern->selectOverlay_->SetUsingMouse(info.GetSourceDevice() == SourceType::MOUSE);
3862 pattern->selectOverlay_->SetLastSourceType(info.GetSourceDevice());
3863 pattern->HandleLongPress(info);
3864 };
3865 longPressEvent_ = MakeRefPtr<LongPressEvent>(std::move(longPressCallback));
3866 gesture->SetLongPressEvent(longPressEvent_);
3867 }
3868
StartVibratorByLongPress()3869 void TextFieldPattern::StartVibratorByLongPress()
3870 {
3871 CHECK_NULL_VOID(isEnableHapticFeedback_);
3872 VibratorUtils::StartVibraFeedback("longPress.light");
3873 }
3874
IsInResponseArea(const Offset & location)3875 bool TextFieldPattern::IsInResponseArea(const Offset& location)
3876 {
3877 return cancelButtonTouched_ || IsOnUnitByPosition(location) || IsOnPasswordByPosition(location) ||
3878 IsOnCleanNodeByPosition(location);
3879 }
3880
HandleLongPress(GestureEvent & info)3881 void TextFieldPattern::HandleLongPress(GestureEvent& info)
3882 {
3883 CHECK_NULL_VOID(!IsDragging());
3884 CHECK_NULL_VOID(!IsHandleDragging());
3885 auto focusHub = GetFocusHub();
3886 CHECK_NULL_VOID(focusHub);
3887 if (!focusHub->IsFocusable() || IsInResponseArea(info.GetLocalLocation()) || GetIsPreviewText()) {
3888 return;
3889 }
3890 moveCaretState_.isTouchCaret = false;
3891 auto host = GetHost();
3892 CHECK_NULL_VOID(host);
3893 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "HandleLongPress %{public}d", host->GetId());
3894 if (ResetObscureTickCountDown()) {
3895 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
3896 }
3897 if (info.GetSourceDevice() == SourceType::MOUSE) {
3898 return;
3899 }
3900 auto hub = host->GetOrCreateEventHub<EventHub>();
3901 CHECK_NULL_VOID(hub);
3902 auto gestureHub = hub->GetOrCreateGestureEventHub();
3903 CHECK_NULL_VOID(gestureHub);
3904 StartVibratorByLongPress();
3905 if (BetweenSelectedPosition(info)) {
3906 gestureHub->SetIsTextDraggable(true);
3907 return;
3908 }
3909 gestureHub->SetIsTextDraggable(false);
3910 isLongPress_ = true;
3911 if (!focusHub->IsCurrentFocus()) {
3912 TextFieldRequestFocus(RequestFocusReason::LONG_PRESS);
3913 }
3914
3915 auto localOffset = info.GetLocalLocation();
3916 if (CanChangeSelectState()) {
3917 selectController_->UpdateSelectWithBlank(localOffset);
3918 StopTwinkling();
3919 }
3920 SetIsSingleHandle(!IsSelected());
3921 auto start = selectController_->GetStartIndex();
3922 auto end = selectController_->GetEndIndex();
3923 CloseSelectOverlay();
3924 longPressFingerNum_ = info.GetFingerList().size();
3925 if (magnifierController_ && HasText() && (longPressFingerNum_ == 1)) {
3926 magnifierController_->SetLocalOffset({ localOffset.GetX(), localOffset.GetY() });
3927 }
3928 StartGestureSelection(start, end, localOffset);
3929 TriggerAvoidOnCaretChange();
3930 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
3931 }
3932
BetweenSelectedPosition(GestureEvent & info)3933 bool TextFieldPattern::BetweenSelectedPosition(GestureEvent& info)
3934 {
3935 if (!IsSelected()) {
3936 return false;
3937 }
3938 auto localOffset = info.GetLocalLocation();
3939 auto offsetX = IsTextArea() ? contentRect_.GetX() : textRect_.GetX();
3940 auto offsetY = IsTextArea() ? textRect_.GetY() : contentRect_.GetY();
3941 Offset offset = localOffset - Offset(offsetX, offsetY);
3942 for (const auto& rect : selectController_->GetSelectedRects()) {
3943 bool isInRange = rect.IsInRegion({ offset.GetX(), offset.GetY() });
3944 if (isInRange) {
3945 return true;
3946 }
3947 }
3948 return false;
3949 }
3950
CanChangeSelectState()3951 bool TextFieldPattern::CanChangeSelectState()
3952 {
3953 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
3954 CHECK_NULL_RETURN(layoutProperty, false);
3955 auto theme = GetTheme();
3956 CHECK_NULL_RETURN(theme, false);
3957 Dimension fontSize = layoutProperty->GetFontSizeValue(theme->GetFontSize());
3958 // fontSize == 0 can not change
3959 return !NearZero(fontSize.Value()) && !IsContentRectNonPositive();
3960 }
3961
IsAccessibilityClick()3962 bool TextFieldPattern::IsAccessibilityClick()
3963 {
3964 auto host = GetHost();
3965 CHECK_NULL_RETURN(host, false);
3966 auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
3967 CHECK_NULL_RETURN(accessibilityProperty, false);
3968 return accessibilityProperty->GetAccessibilityFocusState();
3969 }
3970
IsOnUnitByPosition(const Offset & localOffset)3971 bool TextFieldPattern::IsOnUnitByPosition(const Offset& localOffset)
3972 {
3973 if (!IsShowUnit()) {
3974 return false;
3975 }
3976 auto unitArea = AceType::DynamicCast<UnitResponseArea>(responseArea_);
3977 CHECK_NULL_RETURN(unitArea, false);
3978 auto frameNode = unitArea->GetFrameNode();
3979 CHECK_NULL_RETURN(frameNode, false);
3980 return frameNode->GetGeometryNode()->GetFrameRect().IsInRegion({ localOffset.GetX(), localOffset.GetY() });
3981 }
3982
IsOnPasswordByPosition(const Offset & localOffset)3983 bool TextFieldPattern::IsOnPasswordByPosition(const Offset& localOffset)
3984 {
3985 auto passwordArea = AceType::DynamicCast<PasswordResponseArea>(responseArea_);
3986 CHECK_NULL_RETURN(passwordArea, false);
3987 auto frameNode = passwordArea->GetFrameNode();
3988 CHECK_NULL_RETURN(frameNode, false);
3989 return frameNode->GetGeometryNode()->GetFrameRect().IsInRegion({ localOffset.GetX(), localOffset.GetY() });
3990 }
3991
IsOnCleanNodeByPosition(const Offset & localOffset)3992 bool TextFieldPattern::IsOnCleanNodeByPosition(const Offset& localOffset)
3993 {
3994 auto cleanNodeResponseArea = AceType::DynamicCast<CleanNodeResponseArea>(cleanNodeResponseArea_);
3995 CHECK_NULL_RETURN(cleanNodeResponseArea, false);
3996 auto frameNode = cleanNodeResponseArea->GetFrameNode();
3997 CHECK_NULL_RETURN(frameNode, false);
3998 return frameNode->GetGeometryNode()->GetFrameRect().IsInRegion({ localOffset.GetX(), localOffset.GetY() });
3999 }
4000
IsMouseOverScrollBar(const BaseEventInfo * info)4001 bool TextFieldPattern::IsMouseOverScrollBar(const BaseEventInfo* info)
4002 {
4003 CHECK_NULL_RETURN(GetScrollBar(), false);
4004 Point point;
4005 do {
4006 auto gestureEvent = TypeInfoHelper::DynamicCast<GestureEvent>(info);
4007 if (gestureEvent) {
4008 point = Point(gestureEvent->GetLocalLocation().GetX(), gestureEvent->GetLocalLocation().GetY());
4009 break;
4010 }
4011 auto mouseInfo = TypeInfoHelper::DynamicCast<MouseInfo>(info);
4012 if (mouseInfo) {
4013 point = Point(mouseInfo->GetLocalLocation().GetX(), mouseInfo->GetLocalLocation().GetY());
4014 break;
4015 }
4016 return false;
4017 } while (false);
4018 if (GetScrollBar()->NeedPaint() && GetScrollBar()->GetShapeMode() == ShapeMode::RECT) {
4019 auto barRect = GetScrollBar()->GetBarRect();
4020 auto mouseScrollbarRegionWidth = MOUSE_SCROLL_BAR_REGION_WIDTH.ConvertToPx();
4021 barRect.SetLeft(barRect.Left() + (barRect.Width() - mouseScrollbarRegionWidth));
4022 barRect.SetWidth(mouseScrollbarRegionWidth);
4023 barRect.SetHeight(frameRect_.Height());
4024 barRect.SetTop(0.0f);
4025 return barRect.IsInRegion(point);
4026 }
4027 return false;
4028 }
4029
UpdateCaretPositionWithClamp(const int32_t & pos)4030 void TextFieldPattern::UpdateCaretPositionWithClamp(const int32_t& pos)
4031 {
4032 selectController_->UpdateCaretIndex(
4033 std::clamp(pos, 0, static_cast<int32_t>(contentController_->GetTextUtf16Value().length())));
4034 }
4035
ProcessOverlay(const OverlayRequest & request)4036 void TextFieldPattern::ProcessOverlay(const OverlayRequest& request)
4037 {
4038 selectOverlay_->ProcessOverlay(request);
4039 }
4040
DelayProcessOverlay(const OverlayRequest & request)4041 void TextFieldPattern::DelayProcessOverlay(const OverlayRequest& request)
4042 {
4043 processOverlayDelayTask_ = [weak = WeakClaim(this), request]() {
4044 auto pattern = weak.Upgrade();
4045 CHECK_NULL_VOID(pattern);
4046 pattern->ProcessOverlay(request);
4047 };
4048 }
4049
CancelDelayProcessOverlay()4050 void TextFieldPattern::CancelDelayProcessOverlay()
4051 {
4052 if (processOverlayDelayTask_) {
4053 processOverlayDelayTask_ = nullptr;
4054 }
4055 }
4056
AllowCopy()4057 bool TextFieldPattern::AllowCopy()
4058 {
4059 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
4060 CHECK_NULL_RETURN(layoutProperty, false);
4061 return layoutProperty->GetCopyOptionsValue(CopyOptions::Local) != CopyOptions::None && !IsInPasswordMode();
4062 }
4063
OnDetachFromFrameNode(FrameNode * node)4064 void TextFieldPattern::OnDetachFromFrameNode(FrameNode* node)
4065 {
4066 THREAD_SAFE_NODE_CHECK(node, OnDetachFromFrameNode, node); // call OnDetachFromFrameNodeMultiThread() by multi thread
4067 selectOverlay_->CloseOverlay(false, CloseReason::CLOSE_REASON_NORMAL);
4068 auto pipeline = node->GetContext();
4069 CHECK_NULL_VOID(pipeline);
4070 if (HasSurfaceChangedCallback()) {
4071 pipeline->UnregisterSurfaceChangedCallback(surfaceChangedCallbackId_.value_or(-1));
4072 }
4073 if (HasSurfacePositionChangedCallback()) {
4074 pipeline->UnregisterSurfacePositionChangedCallback(surfacePositionChangedCallbackId_.value_or(-1));
4075 }
4076 auto textFieldManager = DynamicCast<TextFieldManagerNG>(pipeline->GetTextFieldManager());
4077 if (textFieldManager) {
4078 textFieldManager->ClearOnFocusTextField(node->GetId());
4079 }
4080 auto frameNode = WeakClaim(node);
4081 pipeline->RemoveFontNodeNG(frameNode);
4082 auto fontManager = pipeline->GetFontManager();
4083 if (fontManager) {
4084 fontManager->UnRegisterCallbackNG(frameNode);
4085 fontManager->RemoveVariationNodeNG(frameNode);
4086 }
4087 pipeline->RemoveWindowSizeChangeCallback(node->GetId());
4088 pipeline->RemoveOnAreaChangeNode(node->GetId());
4089 }
4090
CloseSelectOverlay()4091 void TextFieldPattern::CloseSelectOverlay()
4092 {
4093 CloseSelectOverlay(false);
4094 }
4095
CloseSelectOverlay(bool animation)4096 void TextFieldPattern::CloseSelectOverlay(bool animation)
4097 {
4098 selectOverlay_->CloseOverlay(animation, CloseReason::CLOSE_REASON_NORMAL);
4099 auto host = GetHost();
4100 CHECK_NULL_VOID(host);
4101 auto gesture = host->GetOrCreateGestureEventHub();
4102 gesture->AddTouchEvent(GetTouchListener());
4103 }
4104
InitEditingValueText(std::u16string content)4105 void TextFieldPattern::InitEditingValueText(std::u16string content)
4106 {
4107 if (HasInputOperation()) {
4108 return;
4109 }
4110 textCache_ = UtfUtils::Str16DebugToStr8(content);
4111 contentController_->SetTextValueOnly(std::move(content));
4112 selectController_->UpdateCaretIndex(GetTextUtf16Value().length());
4113 if (GetIsPreviewText() && GetTextUtf16Value().empty()) {
4114 FinishTextPreviewOperation();
4115 }
4116 GetHost()->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
4117 }
4118
InitValueText(std::u16string content)4119 bool TextFieldPattern::InitValueText(std::u16string content)
4120 {
4121 if (GetIsPreviewText()) {
4122 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "Init when has previewText");
4123 return false;
4124 }
4125 if (HasInputOperation() && content != u"") {
4126 return false;
4127 }
4128 textCache_ = UtfUtils::Str16DebugToStr8(content);
4129 ChangeValueInfo changeValueInfo;
4130 changeValueInfo.oldContent = GetBodyTextValue();
4131 changeValueInfo.value = content;
4132 changeValueInfo.oldPreviewText.offset = hasPreviewText_ ? GetPreviewTextStart() : -1;
4133 changeValueInfo.oldPreviewText.value = GetPreviewTextValue();
4134 changeValueInfo.previewText = changeValueInfo.oldPreviewText;
4135 changeValueInfo.rangeBefore = TextRange { 0, changeValueInfo.oldContent.length() };
4136 changeValueInfo.rangeAfter = TextRange { 0, content.length() };
4137 bool isWillChange = FireOnWillChange(changeValueInfo);
4138 if (!isWillChange) {
4139 return false;
4140 }
4141 contentController_->SetTextValueOnly(std::move(content));
4142 selectController_->UpdateCaretIndex(GetTextUtf16Value().length());
4143 GetHost()->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
4144 return true;
4145 }
4146
InitMouseEvent()4147 void TextFieldPattern::InitMouseEvent()
4148 {
4149 CHECK_NULL_VOID(!mouseEvent_ || !hoverEvent_);
4150 auto tmpHost = GetHost();
4151 CHECK_NULL_VOID(tmpHost);
4152 auto eventHub = tmpHost->GetOrCreateEventHub<TextFieldEventHub>();
4153 auto inputHub = eventHub->GetOrCreateInputEventHub();
4154
4155 auto mouseTask = [weak = WeakClaim(this)](MouseInfo& info) {
4156 auto pattern = weak.Upgrade();
4157 if (pattern) {
4158 pattern->HandleMouseEvent(info);
4159 if (info.GetButton() == MouseButton::LEFT_BUTTON && info.GetAction() == MouseAction::PRESS) {
4160 pattern->hasMousePressed_ = true;
4161 } else {
4162 pattern->hasMousePressed_ = false;
4163 }
4164 }
4165 };
4166 mouseEvent_ = MakeRefPtr<InputEvent>(std::move(mouseTask));
4167 inputHub->AddOnMouseEvent(mouseEvent_);
4168
4169 auto hoverTask = [weak = WeakClaim(this)](bool isHover, const HoverInfo& info) {
4170 auto pattern = weak.Upgrade();
4171 if (pattern) {
4172 pattern->OnHover(isHover, info);
4173 }
4174 };
4175 hoverEvent_ = MakeRefPtr<InputEvent>(std::move(hoverTask));
4176 inputHub->AddOnHoverEvent(hoverEvent_);
4177 InitPanEvent();
4178 }
4179
InitPanEvent()4180 void TextFieldPattern::InitPanEvent()
4181 {
4182 auto host = GetHost();
4183 CHECK_NULL_VOID(host);
4184 auto gestureHub = host->GetOrCreateGestureEventHub();
4185 CHECK_NULL_VOID(gestureHub);
4186 if (!boxSelectPanEvent_) {
4187 auto actionStartTask = [weak = WeakClaim(this)](const GestureEvent& info) {};
4188 auto actionUpdateTask = [weak = WeakClaim(this)](const GestureEvent& info) {};
4189 auto actionEndTask = [weak = WeakClaim(this)](const GestureEvent& info) {};
4190 GestureEventNoParameter actionCancelTask;
4191 boxSelectPanEvent_ = MakeRefPtr<PanEvent>(std::move(actionStartTask), std::move(actionUpdateTask),
4192 std::move(actionEndTask), std::move(actionCancelTask));
4193 }
4194 PanDirection panDirection = { .type = PanDirection::ALL };
4195 PanDistanceMap distanceMap = { { SourceTool::UNKNOWN, DEFAULT_PAN_DISTANCE.ConvertToPx() },
4196 { SourceTool::PEN, DEFAULT_PEN_PAN_DISTANCE.ConvertToPx() } };
4197 gestureHub->AddPanEvent(boxSelectPanEvent_, panDirection, 1, distanceMap);
4198 gestureHub->SetPanEventType(GestureTypeName::TEXTFIELD_BOXSELECT);
4199 gestureHub->SetOnGestureJudgeNativeBegin([weak = WeakClaim(this)](const RefPtr<NG::GestureInfo>& gestureInfo,
4200 const std::shared_ptr<BaseGestureEvent>& info) -> GestureJudgeResult {
4201 if (gestureInfo->GetType() == GestureTypeName::BOXSELECT &&
4202 gestureInfo->GetInputEventType() == InputEventType::MOUSE_BUTTON) {
4203 return GestureJudgeResult::REJECT;
4204 }
4205 auto pattern = weak.Upgrade();
4206 CHECK_NULL_RETURN(pattern, GestureJudgeResult::CONTINUE);
4207 if (gestureInfo->GetType() == GestureTypeName::TEXTFIELD_BOXSELECT &&
4208 gestureInfo->GetInputEventType() == InputEventType::TOUCH_SCREEN &&
4209 pattern->moveCaretState_.isMoveCaret) {
4210 return GestureJudgeResult::CONTINUE;
4211 }
4212 if (gestureInfo->GetType() == GestureTypeName::TEXTFIELD_BOXSELECT &&
4213 gestureInfo->GetInputEventType() != InputEventType::MOUSE_BUTTON) {
4214 return GestureJudgeResult::REJECT;
4215 }
4216 auto host = pattern->GetHost();
4217 CHECK_NULL_RETURN(host, GestureJudgeResult::CONTINUE);
4218 if (gestureInfo->GetType() == GestureTypeName::TEXTFIELD_BOXSELECT &&
4219 gestureInfo->GetInputEventType() == InputEventType::MOUSE_BUTTON &&
4220 host->IsDraggable() && pattern->IsPressSelectedBox()) {
4221 return GestureJudgeResult::REJECT;
4222 }
4223 if (pattern->GetCancelButtonTouchInfo()) {
4224 return GestureJudgeResult::REJECT;
4225 }
4226 return GestureJudgeResult::CONTINUE;
4227 });
4228 }
4229
OnHover(bool isHover,const HoverInfo & info)4230 void TextFieldPattern::OnHover(bool isHover, const HoverInfo& info)
4231 {
4232 auto frame = GetHost();
4233 CHECK_NULL_VOID(frame);
4234 auto frameId = frame->GetId();
4235 auto pipeline = frame->GetContext();
4236 auto textFieldTheme = GetTheme();
4237 if (!pipeline || !textFieldTheme) {
4238 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "Textfield %{public}d hover can't get pipeline",
4239 frame->GetId());
4240 return;
4241 }
4242 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "Textfield %{public}d %{public}s", frame->GetId(),
4243 isHover ? "on hover" : "exit hover");
4244 if (isHover) {
4245 pipeline->SetMouseStyleHoldNode(frameId);
4246 ChangeMouseState(info.GetLocalLocation(), frameId);
4247 } else {
4248 int32_t windowId = 0;
4249 #ifdef WINDOW_SCENE_SUPPORTED
4250 windowId = static_cast<int32_t>(GetSCBSystemWindowId());
4251 #endif
4252 pipeline->ChangeMouseStyle(frameId, MouseFormat::DEFAULT, windowId);
4253 pipeline->FreeMouseStyleHoldNode(frameId);
4254 }
4255 UpdateHoverStyle(isHover);
4256 isOnHover_ = isHover;
4257 }
4258
UpdateHoverStyle(bool isHover)4259 void TextFieldPattern::UpdateHoverStyle(bool isHover)
4260 {
4261 if (!hoverAndPressBgColorEnabled_) {
4262 return;
4263 }
4264 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
4265 CHECK_NULL_VOID(paintProperty);
4266 auto theme = GetTheme();
4267 CHECK_NULL_VOID(theme);
4268 auto defaultThemeBgColor = theme->GetBgColor();
4269 auto textFieldBgColor = paintProperty->GetBackgroundColorValue(defaultThemeBgColor);
4270 auto bgColor = textFieldBgColor;
4271 if (textFieldBgColor == defaultThemeBgColor) {
4272 bgColor = IsUnderlineMode() ? Color::TRANSPARENT : defaultThemeBgColor;
4273 }
4274 auto hoverColor = bgColor.BlendColor(theme->GetPressColor());
4275 if (!HasFocus()) {
4276 if (isHover) {
4277 PlayAnimationHoverAndPress(hoverColor);
4278 } else {
4279 PlayAnimationHoverAndPress(bgColor);
4280 }
4281 }
4282 }
4283
UpdatePressStyle(bool isPressed)4284 void TextFieldPattern::UpdatePressStyle(bool isPressed)
4285 {
4286 if (!hoverAndPressBgColorEnabled_) {
4287 return;
4288 }
4289 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
4290 CHECK_NULL_VOID(paintProperty);
4291 auto theme = GetTheme();
4292 CHECK_NULL_VOID(theme);
4293 auto defaultThemeBgColor = theme->GetBgColor();
4294 auto textFieldBgColor = paintProperty->GetBackgroundColorValue(defaultThemeBgColor);
4295 auto bgColor = textFieldBgColor;
4296 if (textFieldBgColor == defaultThemeBgColor) {
4297 if (IsUnderlineMode()) {
4298 bgColor = Color::TRANSPARENT;
4299 } else {
4300 bgColor = HasFocus() ? theme->GetFocusBgColor() : defaultThemeBgColor;
4301 }
4302 }
4303 auto pressColor = bgColor.BlendColor(theme->GetHoverColor());
4304 if (isPressed) {
4305 PlayAnimationHoverAndPress(pressColor);
4306 } else {
4307 PlayAnimationHoverAndPress(bgColor);
4308 }
4309 }
4310
PlayAnimationHoverAndPress(const Color & color)4311 void TextFieldPattern::PlayAnimationHoverAndPress(const Color& color)
4312 {
4313 AnimationOption option = AnimationOption();
4314 option.SetDuration(HOVER_ANIMATION_DURATION);
4315 option.SetCurve(Curves::FRICTION);
4316 AnimationUtils::Animate(option, [weak = AceType::WeakClaim(this), color]() {
4317 auto textFieldPattern = weak.Upgrade();
4318 CHECK_NULL_VOID(textFieldPattern);
4319 textFieldPattern->UpdateTextFieldBgColor(color);
4320 });
4321 }
4322
UpdateTextFieldBgColor(const Color & color)4323 void TextFieldPattern::UpdateTextFieldBgColor(const Color& color)
4324 {
4325 auto host = GetHost();
4326 CHECK_NULL_VOID(host);
4327 auto renderContext = host->GetRenderContext();
4328 CHECK_NULL_VOID(renderContext);
4329 renderContext->UpdateBackgroundColor(color);
4330 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
4331 }
4332
RestoreDefaultMouseState()4333 void TextFieldPattern::RestoreDefaultMouseState()
4334 {
4335 int32_t windowId = 0;
4336 #ifdef WINDOW_SCENE_SUPPORTED
4337 windowId = static_cast<int32_t>(GetSCBSystemWindowId());
4338 #endif
4339 auto host = GetHost();
4340 CHECK_NULL_VOID(host);
4341 auto pipeline = host->GetContextRefPtr();
4342 CHECK_NULL_VOID(pipeline);
4343 auto id = host->GetId();
4344 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "RestoreDefaultMouseState id:%{public}d, winId:%{public}d", id, windowId);
4345 pipeline->SetMouseStyleHoldNode(id);
4346 pipeline->ChangeMouseStyle(id, MouseFormat::DEFAULT, windowId);
4347 }
4348
ChangeMouseState(const Offset location,int32_t frameId)4349 void TextFieldPattern::ChangeMouseState(const Offset location, int32_t frameId)
4350 {
4351 auto host = GetHost();
4352 CHECK_NULL_VOID(host);
4353 auto pipeline = host->GetContext();
4354 CHECK_NULL_VOID(pipeline);
4355 auto responseAreaWidth = (responseArea_ ? responseArea_->GetAreaRect().Width() : 0.0f) +
4356 (cleanNodeResponseArea_ ? cleanNodeResponseArea_->GetAreaRect().Width() : 0.0f);
4357 auto x = location.GetX();
4358 auto y = location.GetY();
4359 int32_t windowId = 0;
4360 #ifdef WINDOW_SCENE_SUPPORTED
4361 windowId = static_cast<int32_t>(GetSCBSystemWindowId());
4362 #endif
4363 if (GreatNotEqual(x, 0) && LessNotEqual(x, frameRect_.Width()) && GreatNotEqual(y, 0) &&
4364 LessNotEqual(y, frameRect_.Height())) {
4365 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
4366 CHECK_NULL_VOID(layoutProperty);
4367 auto isRTL = layoutProperty->GetNonAutoLayoutDirection() == TextDirection::RTL;
4368 if (!isRTL && GreatNotEqual(location.GetX(), frameRect_.Width() - responseAreaWidth)) {
4369 RestoreDefaultMouseState();
4370 } else if (isRTL && LessNotEqual(location.GetX(), responseAreaWidth)) {
4371 RestoreDefaultMouseState();
4372 } else {
4373 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "ChangeMouseState Id:%{public}d, winId:%{public}d", frameId, windowId);
4374 pipeline->SetMouseStyleHoldNode(frameId);
4375 pipeline->ChangeMouseStyle(frameId, MouseFormat::TEXT_CURSOR, windowId);
4376 }
4377 } else {
4378 RestoreDefaultMouseState();
4379 }
4380 }
4381
HandleMouseEvent(MouseInfo & info)4382 void TextFieldPattern::HandleMouseEvent(MouseInfo& info)
4383 {
4384 CHECK_NULL_VOID(!IsDragging());
4385 auto tmpHost = GetHost();
4386 CHECK_NULL_VOID(tmpHost);
4387 auto frameId = tmpHost->GetId();
4388 auto pipeline = tmpHost->GetContext();
4389 CHECK_NULL_VOID(pipeline);
4390 info.SetStopPropagation(true);
4391 selectOverlay_->SetLastSourceType(info.GetSourceDevice());
4392 auto scrollBar = GetScrollBar();
4393 int32_t windowId = 0;
4394 #ifdef WINDOW_SCENE_SUPPORTED
4395 windowId = static_cast<int32_t>(GetSCBSystemWindowId());
4396 #endif
4397 if (scrollBar && (scrollBar->IsPressed() || scrollBar->IsHover() || IsMouseOverScrollBar(&info))) {
4398 pipeline->SetMouseStyleHoldNode(frameId);
4399 pipeline->ChangeMouseStyle(frameId, MouseFormat::DEFAULT, windowId);
4400 return;
4401 }
4402 if (info.GetAction() != MouseAction::WINDOW_LEAVE) {
4403 ChangeMouseState(info.GetLocalLocation(), frameId);
4404 }
4405
4406 if (info.GetAction() == OHOS::Ace::MouseAction::PRESS) {
4407 selectOverlay_->SetUsingMouse(true);
4408 }
4409 if (info.GetButton() == MouseButton::RIGHT_BUTTON) {
4410 HandleRightMouseEvent(info);
4411 } else if (info.GetButton() == MouseButton::LEFT_BUTTON) {
4412 HandleLeftMouseEvent(info);
4413 if (IsSelected()) {
4414 selectOverlay_->SetSelectionHoldCallback();
4415 }
4416 }
4417 if (info.GetAction() == OHOS::Ace::MouseAction::RELEASE) {
4418 selectOverlay_->SetUsingMouse(false);
4419 }
4420 if (!IsSelected()) {
4421 ResetOriginCaretPosition();
4422 }
4423 }
4424
HandleRightMouseEvent(MouseInfo & info)4425 void TextFieldPattern::HandleRightMouseEvent(MouseInfo& info)
4426 {
4427 if (info.GetAction() == OHOS::Ace::MouseAction::PRESS) {
4428 HandleRightMousePressEvent(info);
4429 return;
4430 }
4431 if (info.GetAction() == OHOS::Ace::MouseAction::RELEASE) {
4432 HandleRightMouseReleaseEvent(info);
4433 }
4434 }
4435
HandleRightMousePressEvent(MouseInfo & info)4436 void TextFieldPattern::HandleRightMousePressEvent(MouseInfo& info)
4437 {
4438 if (IsSelected() || GetIsPreviewText()) {
4439 return;
4440 }
4441 auto focusHub = GetFocusHub();
4442 if (!focusHub->IsFocusable()) {
4443 return;
4444 }
4445 FocusAndUpdateCaretByMouse(info);
4446 }
4447
HandleRightMouseReleaseEvent(MouseInfo & info)4448 void TextFieldPattern::HandleRightMouseReleaseEvent(MouseInfo& info)
4449 {
4450 if (GetIsPreviewText()) {
4451 return;
4452 }
4453 auto focusHub = GetFocusHub();
4454 if (focusHub->IsCurrentFocus()) {
4455 OffsetF rightClickOffset = OffsetF(
4456 static_cast<float>(info.GetGlobalLocation().GetX()), static_cast<float>(info.GetGlobalLocation().GetY()));
4457 selectOverlay_->SetMouseMenuOffset(rightClickOffset);
4458 ProcessOverlay();
4459 }
4460 }
4461
HandleLeftMouseEvent(MouseInfo & info)4462 void TextFieldPattern::HandleLeftMouseEvent(MouseInfo& info)
4463 {
4464 switch (info.GetAction()) {
4465 case OHOS::Ace::MouseAction::PRESS: {
4466 HandleLeftMousePressEvent(info);
4467 break;
4468 }
4469 case OHOS::Ace::MouseAction::MOVE: {
4470 HandleLeftMouseMoveEvent(info); // 注意鼠标拖拽的滚动效果
4471 break;
4472 }
4473 case OHOS::Ace::MouseAction::RELEASE: {
4474 HandleLeftMouseReleaseEvent(info);
4475 break;
4476 }
4477 default: {
4478 }
4479 }
4480 }
4481
HandleLeftMousePressEvent(MouseInfo & info)4482 void TextFieldPattern::HandleLeftMousePressEvent(MouseInfo& info)
4483 {
4484 isPressSelectedBox_ =
4485 (IsSelected() && BetweenSelectedPosition(info.GetGlobalLocation()) && !shiftFlag_);
4486 if (isPressSelectedBox_ || GetIsPreviewText()) {
4487 blockPress_ = true;
4488 return;
4489 }
4490 auto focusHub = GetFocusHub();
4491 if (!focusHub->IsFocusable()) {
4492 return;
4493 }
4494 mouseStatus_ = MouseStatus::PRESSED;
4495 blockPress_ = false;
4496 leftMouseCanMove_ = true;
4497 FocusAndUpdateCaretByMouse(info);
4498 }
4499
FocusAndUpdateCaretByMouse(MouseInfo & info)4500 void TextFieldPattern::FocusAndUpdateCaretByMouse(MouseInfo& info)
4501 {
4502 auto focusHub = GetFocusHub();
4503 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
4504 CHECK_NULL_VOID(paintProperty);
4505 if (!focusHub->IsFocusOnTouch().value_or(true) || !TextFieldRequestFocus(RequestFocusReason::MOUSE)) {
4506 StopTwinkling();
4507 return;
4508 }
4509 UpdateCaretByClick(GetCaretClickLocalOffset(info.GetLocalLocation()));
4510 auto tmpHost = GetHost();
4511 CHECK_NULL_VOID(tmpHost);
4512 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
4513 }
4514
UpdateShiftFlag(const KeyEvent & keyEvent)4515 void TextFieldPattern::UpdateShiftFlag(const KeyEvent& keyEvent)
4516 {
4517 bool flag = false;
4518 if (keyEvent.action == KeyAction::DOWN) {
4519 if (keyEvent.HasKey(KeyCode::KEY_SHIFT_LEFT) || keyEvent.HasKey(KeyCode::KEY_SHIFT_RIGHT)) {
4520 flag = true;
4521 }
4522 }
4523 if (flag != shiftFlag_) {
4524 shiftFlag_ = flag;
4525 if (!shiftFlag_) {
4526 // open drag
4527 InitDragEvent();
4528 } else {
4529 // close drag
4530 ClearDragDropEvent();
4531 }
4532 }
4533 }
4534
UpdateCaretByClick(const Offset & localOffset)4535 void TextFieldPattern::UpdateCaretByClick(const Offset& localOffset)
4536 {
4537 if (shiftFlag_) {
4538 selectController_->UpdateSecondHandleInfoByMouseOffset(localOffset);
4539 StopTwinkling();
4540 } else {
4541 selectController_->UpdateCaretInfoByOffset(localOffset, true, false);
4542 StartTwinkling();
4543 }
4544 }
4545
HandleLeftMouseMoveEvent(MouseInfo & info)4546 void TextFieldPattern::HandleLeftMouseMoveEvent(MouseInfo& info)
4547 {
4548 if (!leftMouseCanMove_ || blockPress_) {
4549 return;
4550 }
4551 auto focusHub = GetFocusHub();
4552 if (!focusHub->IsCurrentFocus()) {
4553 return;
4554 }
4555 mouseStatus_ = MouseStatus::MOVE;
4556 if (GetTextUtf16Value().empty()) {
4557 return;
4558 }
4559 selectController_->UpdateSecondHandleInfoByMouseOffset(info.GetLocalLocation()); // 更新时上报事件
4560 showSelect_ = true;
4561 auto tmpHost = GetHost();
4562 CHECK_NULL_VOID(tmpHost);
4563 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
4564 }
4565
HandleLeftMouseReleaseEvent(MouseInfo & info)4566 void TextFieldPattern::HandleLeftMouseReleaseEvent(MouseInfo& info)
4567 {
4568 auto tmpHost = GetHost();
4569 CHECK_NULL_VOID(tmpHost);
4570 if (blockPress_ && mouseStatus_ == MouseStatus::PRESSED) {
4571 selectController_->UpdateCaretInfoByOffset(info.GetLocalLocation(), true, false);
4572 StartTwinkling();
4573 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
4574 }
4575 FreeMouseStyleHoldNode(info.GetLocalLocation());
4576 mouseStatus_ = MouseStatus::NONE;
4577 blockPress_ = false;
4578 leftMouseCanMove_ = false;
4579 if (HasFocus() && RequestKeyboardNotByFocusSwitch(RequestKeyboardReason::MOUSE_RELEASE)) {
4580 NotifyOnEditChanged(true);
4581 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
4582 }
4583 }
4584
FreeMouseStyleHoldNode(const Offset location)4585 void TextFieldPattern::FreeMouseStyleHoldNode(const Offset location)
4586 {
4587 auto rect = RectF(0.0f, 0.0f, frameRect_.Width(), frameRect_.Height());
4588 if (!location.IsPositiveOffset() || !rect.IsInRegion({ location.GetX(), location.GetY() })) {
4589 auto tmpHost = GetHost();
4590 CHECK_NULL_VOID(tmpHost);
4591 auto frameId = tmpHost->GetId();
4592 auto pipeline = GetContext();
4593 CHECK_NULL_VOID(pipeline);
4594 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "FreeMouseStyleHoldNode, id:%{public}d", frameId);
4595 pipeline->FreeMouseStyleHoldNode(frameId);
4596 }
4597 }
4598
UpdateTextFieldManager(const Offset & offset,float height)4599 void TextFieldPattern::UpdateTextFieldManager(const Offset& offset, float height)
4600 {
4601 auto tmpHost = GetHost();
4602 CHECK_NULL_VOID(tmpHost);
4603 auto context = tmpHost->GetContextRefPtr();
4604 CHECK_NULL_VOID(context);
4605 auto textFieldManager = DynamicCast<TextFieldManagerNG>(context->GetTextFieldManager());
4606 CHECK_NULL_VOID(textFieldManager);
4607 auto safeAreaManager = context->GetSafeAreaManager();
4608 CHECK_NULL_VOID(safeAreaManager);
4609 textFieldManager->UpdateScrollableParentViewPort(tmpHost);
4610 if (!HasFocus()) {
4611 return;
4612 }
4613 textFieldManager->SetClickPosition({ offset.GetX() + selectController_->GetCaretRect().GetX(),
4614 offset.GetY() + selectController_->GetCaretRect().GetY() });
4615 textFieldManager->SetHeight(selectController_->GetCaretRect().Height());
4616 textFieldManager->SetClickPositionOffset(safeAreaManager->GetKeyboardOffset());
4617 textFieldManager->SetOnFocusTextField(WeakClaim(this));
4618 textFieldManager->SetUsingCustomKeyboardAvoid(keyboardAvoidance_);
4619 textFieldManager->SetIfFocusTextFieldIsInline(IsNormalInlineState());
4620 }
4621
GetDefaultTextInputAction() const4622 TextInputAction TextFieldPattern::GetDefaultTextInputAction() const
4623 {
4624 TextInputAction defaultTextInputAction = TextInputAction::DONE;
4625 if (IsTextArea() && !isTextInput_) {
4626 defaultTextInputAction = TextInputAction::NEW_LINE;
4627 } else {
4628 defaultTextInputAction = TextInputAction::DONE;
4629 }
4630 return defaultTextInputAction;
4631 }
4632
4633 #ifdef WINDOW_SCENE_SUPPORTED
GetSCBSystemWindowId()4634 uint32_t TextFieldPattern::GetSCBSystemWindowId()
4635 {
4636 RefPtr<FrameNode> frameNode = GetHost();
4637 CHECK_NULL_RETURN(frameNode, {});
4638 auto focusSystemWindowId = WindowSceneHelper::GetFocusSystemWindowId(frameNode);
4639 return focusSystemWindowId;
4640 }
4641 #endif
4642
KeyboardContentTypeToInputType()4643 void TextFieldPattern::KeyboardContentTypeToInputType()
4644 {
4645 if (keyboard_ != TextInputType::UNSPECIFIED) {
4646 return;
4647 }
4648 auto autoFillType = GetAutoFillType(false);
4649 if (keyBoardMap_.find(autoFillType) != keyBoardMap_.end()) {
4650 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD,
4651 "Set InputType to %{public}d because of contentType", keyBoardMap_[autoFillType]);
4652 keyboard_ = keyBoardMap_[autoFillType];
4653 }
4654 }
4655
GetRequestKeyboardId()4656 int32_t TextFieldPattern::GetRequestKeyboardId()
4657 {
4658 auto host = GetHost();
4659 CHECK_NULL_RETURN(host, -1);
4660 return host->GetId();
4661 }
4662
RequestKeyboard(bool isFocusViewChanged,bool needStartTwinkling,bool needShowSoftKeyboard,SourceType sourceType)4663 bool TextFieldPattern::RequestKeyboard(bool isFocusViewChanged, bool needStartTwinkling, bool needShowSoftKeyboard,
4664 SourceType sourceType)
4665 {
4666 bool isFocus = HasFocus();
4667 if (!showKeyBoardOnFocus_ || !isFocus) {
4668 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "showKeyBoardOnFocus:%{public}d, isFocus:%{public}d", showKeyBoardOnFocus_,
4669 isFocus);
4670 return false;
4671 }
4672 auto tmpHost = GetHost();
4673 CHECK_NULL_RETURN(tmpHost, false);
4674 if (customKeyboard_ || customKeyboardBuilder_) {
4675 CHECK_NULL_RETURN(needShowSoftKeyboard, true);
4676 return RequestCustomKeyboard();
4677 }
4678 bool ok = true;
4679 KeyboardContentTypeToInputType();
4680 #if defined(ENABLE_STANDARD_INPUT)
4681 if (textChangeListener_ == nullptr) {
4682 textChangeListener_ = new OnTextChangedListenerImpl(WeakClaim(this));
4683 }
4684 auto inputMethod = MiscServices::InputMethodController::GetInstance();
4685 if (!inputMethod) {
4686 TAG_LOGE(AceLogTag::ACE_TEXT_FIELD, "RequestKeyboard, inputMethod is null");
4687 return false;
4688 }
4689 FireOnWillAttachIME();
4690 auto optionalTextConfig = GetMiscTextConfig();
4691 CHECK_NULL_RETURN(optionalTextConfig.has_value(), false);
4692 MiscServices::TextConfig textConfig = optionalTextConfig.value();
4693 ACE_LAYOUT_SCOPED_TRACE("RequestKeyboard[id:%d][WId:%u]", tmpHost->GetId(), textConfig.windowId);
4694 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD,
4695 "node:%{public}d, RequestKeyboard set calling window id:%{public}u"
4696 " inputType:%{public}d, enterKeyType:%{public}d, needKeyboard:%{public}d, sourceType:%{public}u"
4697 " placeholderLength:%{public}zu",
4698 tmpHost->GetId(), textConfig.windowId, textConfig.inputAttribute.inputPattern,
4699 textConfig.inputAttribute.enterKeyType, needShowSoftKeyboard, sourceType,
4700 CountUtf16Chars(textConfig.inputAttribute.placeholder));
4701 #ifdef WINDOW_SCENE_SUPPORTED
4702 auto systemWindowId = GetSCBSystemWindowId();
4703 if (systemWindowId) {
4704 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "windowId From %{public}u to %{public}u.", textConfig.windowId,
4705 systemWindowId);
4706 textConfig.windowId = systemWindowId;
4707 }
4708 #endif
4709 if ((customKeyboard_ || customKeyboardBuilder_) && isCustomKeyboardAttached_) {
4710 TAG_LOGI(AceLogTag::ACE_KEYBOARD, "Request SoftKeyboard, Close CustomKeyboard.");
4711 CloseCustomKeyboard();
4712 }
4713 auto context = GetContext();
4714 if (context && context->GetTextFieldManager()) {
4715 auto textFieldManager = DynamicCast<TextFieldManagerNG>(context->GetTextFieldManager());
4716 textFieldManager->SetImeAttached(true);
4717 textFieldManager->SetLastRequestKeyboardId(GetRequestKeyboardId());
4718 }
4719 OHOS::MiscServices::AttachOptions attachOptions;
4720 attachOptions.isShowKeyboard = needShowSoftKeyboard;
4721 attachOptions.requestKeyboardReason =
4722 static_cast<OHOS::MiscServices::RequestKeyboardReason>(static_cast<int32_t>(sourceType));
4723 auto ret = inputMethod->Attach(textChangeListener_, attachOptions, textConfig);
4724 CHECK_NULL_RETURN(context, false);
4725 auto textFieldManager = AceType::DynamicCast<TextFieldManagerNG>(context->GetTextFieldManager());
4726 CHECK_NULL_RETURN(textFieldManager, false);
4727 if (ret == MiscServices::ErrorCode::NO_ERROR) {
4728 textFieldManager->SetIsImeAttached(true);
4729 textFieldManager->SetAttachInputId(GetRequestKeyboardId());
4730 }
4731 UpdateCaretInfoToController(true);
4732 auto fillContentMap = textFieldManager->GetFillContentMap(tmpHost->GetId());
4733 if (!fillContentMap.empty() && NeedsSendFillContent()) {
4734 inputMethod->SendPrivateCommand(fillContentMap);
4735 }
4736 #else
4737 ok = RequestKeyboardCrossPlatForm(isFocusViewChanged);
4738 #endif
4739 return ok;
4740 }
4741
RequestKeyboardCrossPlatForm(bool isFocusViewChanged)4742 bool TextFieldPattern::RequestKeyboardCrossPlatForm(bool isFocusViewChanged)
4743 {
4744 #if !defined(ENABLE_STANDARD_INPUT)
4745 auto tmpHost = GetHost();
4746 CHECK_NULL_RETURN(tmpHost, false);
4747 auto context = tmpHost->GetContextRefPtr();
4748 CHECK_NULL_RETURN(context, false);
4749 if (!HasConnection()) {
4750 TextInputConfiguration config;
4751 config.type = keyboard_;
4752 config.action = GetTextInputActionValue(GetDefaultTextInputAction());
4753 config.inputFilter = GetInputFilter();
4754 config.maxLength = GetMaxLength();
4755 if (keyboard_ == TextInputType::VISIBLE_PASSWORD || keyboard_ == TextInputType::NEW_PASSWORD) {
4756 config.obscureText = textObscured_;
4757 }
4758 connection_ = TextInputProxy::GetInstance().Attach(
4759 WeakClaim(this), config, context->GetTaskExecutor(), GetInstanceId());
4760
4761 if (!HasConnection()) {
4762 return false;
4763 }
4764 }
4765 TextEditingValue value;
4766 value.text = contentController_->GetTextValue();
4767 value.hint = UtfUtils::Str16DebugToStr8(GetPlaceHolder());
4768 value.selection.Update(selectController_->GetStartIndex(), selectController_->GetEndIndex());
4769 connection_->SetEditingState(value, GetInstanceId());
4770 connection_->Show(isFocusViewChanged, GetInstanceId());
4771 #endif
4772 return true;
4773 }
4774
4775 #if defined(ENABLE_STANDARD_INPUT)
GetMiscTextConfig() const4776 std::optional<MiscServices::TextConfig> TextFieldPattern::GetMiscTextConfig() const
4777 {
4778 auto tmpHost = GetHost();
4779 CHECK_NULL_RETURN(tmpHost, {});
4780 auto pipeline = tmpHost->GetContext();
4781 CHECK_NULL_RETURN(pipeline, {});
4782 auto theme = GetTheme();
4783 CHECK_NULL_RETURN(theme, {});
4784 auto windowRect = pipeline->GetCurrentWindowRect();
4785 double positionY = (tmpHost->GetPaintRectOffset(false, true) - pipeline->GetRootRect().GetOffset()).GetY() + windowRect.Top();
4786 auto offset = AVOID_OFFSET.ConvertToPx();
4787 auto textPaintOffset = GetPaintRectGlobalOffset();
4788 double height = selectController_->GetCaretRect().Bottom() + windowRect.Top() +
4789 textPaintOffset.GetY() + offset - positionY;
4790 std::u16string placeholder = TruncateText(GetPlaceHolder(), MAX_PLACEHOLDER_SIZE);
4791 std::u16string abilityName = TruncateText(UtfUtils::Str8ToStr16(AceApplicationInfo::GetInstance()
4792 .GetAbilityName()), MAX_ABILITY_NAME_SIZE);
4793
4794 GetInlinePositionYAndHeight(positionY, height);
4795
4796 auto manager = pipeline->GetSafeAreaManager();
4797 if (manager) {
4798 auto keyboardOffset = manager->GetKeyboardOffset();
4799 positionY -= keyboardOffset;
4800 }
4801
4802 ContainerScope scope(GetInstanceId());
4803 auto container = AceType::DynamicCast<Platform::AceContainer>(Container::Current());
4804
4805 MiscServices::CursorInfo cursorInfo { .left = selectController_->GetCaretRect().Left() + windowRect.Left() +
4806 textPaintOffset.GetX(),
4807 .top = selectController_->GetCaretRect().Top() + windowRect.Top() + textPaintOffset.GetY(),
4808 .width = theme->GetCursorWidth().ConvertToPx(),
4809 .height = selectController_->GetCaretRect().Height() };
4810 TAG_LOGI(ACE_TEXT_FIELD, "gradientMode = %{public}d fluidLightMode = %{public}d", imeGradientMode_, imeFluidLightMode_);
4811 MiscServices::InputAttribute inputAttribute = { .inputPattern = (int32_t)keyboard_,
4812 .enterKeyType = (int32_t)GetTextInputActionValue(GetDefaultTextInputAction()),
4813 .isTextPreviewSupported = hasSupportedPreviewText_,
4814 .immersiveMode = static_cast<int32_t>(keyboardAppearance_),
4815 .placeholder = placeholder,
4816 .abilityName = abilityName,
4817 .capitalizeMode = static_cast<MiscServices::CapitalizeMode>(GetAutoCapitalizationModeValue(AutoCapitalizationMode::NONE)),
4818 .gradientMode = static_cast<int32_t>(imeGradientMode_),
4819 .fluidLightMode = static_cast<int32_t>(imeFluidLightMode_)
4820 };
4821 MiscServices::TextConfig textConfig = { .inputAttribute = inputAttribute,
4822 .cursorInfo = cursorInfo,
4823 .range = { .start = selectController_->GetStartIndex(), .end = selectController_->GetEndIndex() },
4824 .windowId = pipeline->GetFocusWindowId(),
4825 .positionY = positionY,
4826 .height = height,
4827 .abilityToken = container ? container->GetToken() : nullptr
4828 };
4829
4830 return textConfig;
4831 }
4832
GetInlinePositionYAndHeight(double & positionY,double & height) const4833 void TextFieldPattern::GetInlinePositionYAndHeight(double& positionY, double& height) const
4834 {
4835 if (IsNormalInlineState()) {
4836 auto theme = GetTheme();
4837 CHECK_NULL_VOID(theme);
4838 auto offset = AVOID_OFFSET.ConvertToPx();
4839 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
4840 PaddingProperty userPadding;
4841 if (paintProperty->HasPaddingByUser()) {
4842 userPadding = paintProperty->GetPaddingByUserValue();
4843 } else {
4844 userPadding.top = CalcLength(theme->GetPadding().Top());
4845 }
4846 auto topPadding = userPadding.top->GetDimension().ConvertToPx();
4847 auto safeBoundary = theme->GetInlineBorderWidth().ConvertToPx() * 2;
4848 positionY += static_cast<double>(inlineMeasureItem_.inlineSizeHeight) + safeBoundary + topPadding;
4849 height = offset;
4850
4851 auto tmpHost = GetHost();
4852 CHECK_NULL_VOID(tmpHost);
4853 auto pipeline = tmpHost->GetContextRefPtr();
4854 CHECK_NULL_VOID(pipeline);
4855 auto textFieldManager = DynamicCast<TextFieldManagerNG>(pipeline->GetTextFieldManager());
4856 CHECK_NULL_VOID(textFieldManager);
4857 TAG_LOGI(ACE_TEXT_FIELD, "SetInlineAvoidInfo positionY:%{public}f height:%{public}f sizeHeight:%{public}f",
4858 positionY, height, inlineMeasureItem_.inlineSizeHeight);
4859 textFieldManager->SetInlineTextFieldAvoidPositionYAndHeight(positionY, height);
4860 }
4861 }
4862
4863 #endif
4864
ConvertToAceAutoFillType(TextInputType type)4865 AceAutoFillType TextFieldPattern::ConvertToAceAutoFillType(TextInputType type)
4866 {
4867 static std::unordered_map<TextInputType, AceAutoFillType> convertMap = {
4868 { TextInputType::VISIBLE_PASSWORD, AceAutoFillType::ACE_PASSWORD },
4869 { TextInputType::USER_NAME, AceAutoFillType::ACE_USER_NAME },
4870 { TextInputType::NEW_PASSWORD, AceAutoFillType::ACE_NEW_PASSWORD },
4871 { TextInputType::NUMBER_PASSWORD, AceAutoFillType::ACE_PASSWORD } };
4872 auto it = convertMap.find(type);
4873 if (it != convertMap.end()) {
4874 return it->second;
4875 }
4876 return AceAutoFillType::ACE_UNSPECIFIED;
4877 }
4878
TextContentTypeToAceAutoFillType(const TextContentType & type)4879 AceAutoFillType TextFieldPattern::TextContentTypeToAceAutoFillType(const TextContentType& type)
4880 {
4881 if (contentTypeMap_.find(type) != contentTypeMap_.end()) {
4882 return contentTypeMap_[type].first;
4883 }
4884 return contentTypeMap_[TextContentType::UNSPECIFIED].first;
4885 }
4886
CloseKeyboard(bool forceClose)4887 bool TextFieldPattern::CloseKeyboard(bool forceClose)
4888 {
4889 return CloseKeyboard(forceClose, forceClose);
4890 }
4891
CloseKeyboard(bool forceClose,bool isStopTwinkling)4892 bool TextFieldPattern::CloseKeyboard(bool forceClose, bool isStopTwinkling)
4893 {
4894 if (forceClose) {
4895 if (isStopTwinkling) {
4896 StopTwinkling();
4897 }
4898 CloseSelectOverlay(true);
4899 auto host = GetHost();
4900 CHECK_NULL_RETURN(host, false);
4901 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "textfield %{public}d Will Close Soft keyboard.", host->GetId());
4902 if ((customKeyboard_ || customKeyboardBuilder_) && isCustomKeyboardAttached_) {
4903 return CloseCustomKeyboard();
4904 }
4905 #if defined(ENABLE_STANDARD_INPUT)
4906 auto inputMethod = MiscServices::InputMethodController::GetInstance();
4907 if (!inputMethod) {
4908 TAG_LOGE(AceLogTag::ACE_TEXT_FIELD, "CloseKeyboard, inputMethod is null");
4909 return false;
4910 }
4911 inputMethod->Close();
4912 #else
4913 if (HasConnection()) {
4914 connection_->Close(GetInstanceId());
4915 connection_ = nullptr;
4916 }
4917 #endif
4918 return true;
4919 }
4920 return false;
4921 }
4922
SetCustomKeyboardOption(bool supportAvoidance)4923 void TextFieldPattern::SetCustomKeyboardOption(bool supportAvoidance)
4924 {
4925 keyboardAvoidance_ = supportAvoidance;
4926 }
4927
RequestCustomKeyboard()4928 bool TextFieldPattern::RequestCustomKeyboard()
4929 {
4930 #if defined(ENABLE_STANDARD_INPUT)
4931 auto inputMethod = MiscServices::InputMethodController::GetInstance();
4932 if (inputMethod) {
4933 TAG_LOGI(AceLogTag::ACE_KEYBOARD, "TextField Request CustomKeyboard, Close keyboard Successfully.");
4934 inputMethod->RequestHideInput();
4935 inputMethod->Close();
4936 }
4937 #else
4938 if (HasConnection()) {
4939 connection_->Close(GetInstanceId());
4940 connection_ = nullptr;
4941 }
4942 #endif
4943
4944 if (isCustomKeyboardAttached_) {
4945 return true;
4946 }
4947 CHECK_NULL_RETURN(customKeyboard_ || customKeyboardBuilder_, false);
4948 auto frameNode = GetHost();
4949 CHECK_NULL_RETURN(frameNode, false);
4950 ACE_LAYOUT_SCOPED_TRACE("RequestCustomKeyboard[id:%d]", frameNode->GetId());
4951 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "RequestCustomKeyboard, id:%{public}d", frameNode->GetId());
4952 auto pipeline = frameNode->GetContext();
4953 CHECK_NULL_RETURN(pipeline, false);
4954 auto overlayManager = pipeline->GetOverlayManager();
4955 CHECK_NULL_RETURN(overlayManager, false);
4956 overlayManager->SetCustomKeyboardOption(keyboardAvoidance_);
4957 if (customKeyboardBuilder_) {
4958 overlayManager->BindKeyboard(customKeyboardBuilder_, frameNode->GetId());
4959 } else {
4960 overlayManager->BindKeyboardWithNode(customKeyboard_, frameNode->GetId());
4961 }
4962 auto textFieldManager = DynamicCast<TextFieldManagerNG>(pipeline->GetTextFieldManager());
4963 if (textFieldManager) {
4964 textFieldManager->SetLastRequestKeyboardId(GetRequestKeyboardId());
4965 }
4966 isCustomKeyboardAttached_ = true;
4967 keyboardOverlay_ = overlayManager;
4968 auto caretHeight = selectController_->GetCaretRect().Height();
4969 auto safeHeight = caretHeight + selectController_->GetCaretRect().GetY();
4970 if (selectController_->GetCaretRect().GetY() > caretHeight) {
4971 safeHeight = caretHeight;
4972 }
4973 keyboardOverlay_->AvoidCustomKeyboard(frameNode->GetId(), safeHeight);
4974 return true;
4975 }
4976
CloseCustomKeyboard()4977 bool TextFieldPattern::CloseCustomKeyboard()
4978 {
4979 auto frameNode = GetHost();
4980 CHECK_NULL_RETURN(frameNode, false);
4981 CHECK_NULL_RETURN(keyboardOverlay_, false);
4982 keyboardOverlay_->CloseKeyboard(frameNode->GetId());
4983 isCustomKeyboardAttached_ = false;
4984 return true;
4985 }
4986
OnTextInputActionUpdate(TextInputAction value)4987 void TextFieldPattern::OnTextInputActionUpdate(TextInputAction value) {}
4988
OnAutoCapitalizationModeUpdate(AutoCapitalizationMode value)4989 void TextFieldPattern::OnAutoCapitalizationModeUpdate(AutoCapitalizationMode value) {}
4990
OnThemeScopeUpdate(int32_t themeScopeId)4991 bool TextFieldPattern::OnThemeScopeUpdate(int32_t themeScopeId)
4992 {
4993 bool result = false;
4994 bool updateFlag = true;
4995 auto host = GetHost();
4996 CHECK_NULL_RETURN(host, result);
4997 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
4998 CHECK_NULL_RETURN(paintProperty, false);
4999 auto textFieldLayoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
5000 CHECK_NULL_RETURN(textFieldLayoutProperty, false);
5001 auto pipeline = host->GetContext();
5002 CHECK_NULL_RETURN(pipeline, result);
5003 auto textFieldTheme = pipeline->GetTheme<TextFieldTheme>(themeScopeId);
5004 textFieldTheme_ = textFieldTheme;
5005 CHECK_NULL_RETURN(textFieldTheme, result);
5006
5007 if (!paintProperty->HasBackgroundColor() && !IsUnderlineMode()) {
5008 auto renderContext = host->GetRenderContext();
5009 CHECK_NULL_RETURN(renderContext, result);
5010 auto bgColor = IsInlineMode() ? textFieldTheme->GetInlineBgColor() : textFieldTheme->GetBgColor();
5011 renderContext->UpdateBackgroundColor(bgColor);
5012 result = true;
5013 }
5014
5015 if (!paintProperty->HasTextColorFlagByUser()) {
5016 textFieldLayoutProperty->UpdateTextColor(textFieldTheme->GetTextColor());
5017 result = true;
5018 }
5019
5020 if (!paintProperty->GetCaretColorFlagByUserValue(false)) {
5021 paintProperty->UpdateCursorColor(textFieldTheme->GetCursorColor());
5022 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
5023 }
5024
5025 if (result || !paintProperty->GetPlaceholderColorFlagByUserValue(false)) {
5026 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
5027 updateFlag = false;
5028 }
5029 if (responseArea_) {
5030 responseArea_->OnThemeScopeUpdate(textFieldTheme);
5031 }
5032 if (cleanNodeResponseArea_) {
5033 cleanNodeResponseArea_->OnThemeScopeUpdate(textFieldTheme);
5034 }
5035 return updateFlag;
5036 }
5037
BeforeIMEInsertValue(const std::u16string & insertValue,int32_t offset)5038 bool TextFieldPattern::BeforeIMEInsertValue(const std::u16string& insertValue, int32_t offset)
5039 {
5040 auto host = GetHost();
5041 CHECK_NULL_RETURN(host, true);
5042 auto eventHub = host->GetOrCreateEventHub<TextFieldEventHub>();
5043 CHECK_NULL_RETURN(eventHub, true);
5044 InsertValueInfo insertValueInfo;
5045 insertValueInfo.insertOffset = offset;
5046 insertValueInfo.insertValue = insertValue;
5047 return eventHub->FireOnWillInsertValueEvent(insertValueInfo);
5048 }
5049
AfterIMEInsertValue(const std::u16string & insertValue)5050 void TextFieldPattern::AfterIMEInsertValue(const std::u16string& insertValue)
5051 {
5052 auto host = GetHost();
5053 CHECK_NULL_VOID(host);
5054 auto eventHub = host->GetOrCreateEventHub<TextFieldEventHub>();
5055 CHECK_NULL_VOID(eventHub);
5056 InsertValueInfo insertValueInfo;
5057 auto offset = selectController_->GetCaretIndex();
5058 insertValueInfo.insertOffset = offset;
5059 insertValueInfo.insertValue = insertValue;
5060 return eventHub->FireOnDidInsertValueEvent(insertValueInfo);
5061 }
5062
CalcCounterAfterFilterInsertValue(int32_t curLength,const std::u16string insertValue,int32_t maxLength)5063 void TextFieldPattern::CalcCounterAfterFilterInsertValue(
5064 int32_t curLength, const std::u16string insertValue, int32_t maxLength)
5065 {
5066 bool textChange = false;
5067 auto result = insertValue;
5068 contentController_->FilterTextInputStyle(textChange, result);
5069 int32_t sum = curLength + static_cast<int32_t>(result.length());
5070 showCountBorderStyle_ = sum > maxLength;
5071 HandleCountStyle();
5072 }
5073
NotifyImfFinishTextPreview()5074 void TextFieldPattern::NotifyImfFinishTextPreview()
5075 {
5076 if (!HasFocus()) {
5077 return;
5078 }
5079 #if defined(ENABLE_STANDARD_INPUT)
5080 MiscServices::InputMethodController::GetInstance()->OnSelectionChange(
5081 u"", 0, 0);
5082 TAG_LOGD(AceLogTag::ACE_TEXT_FIELD, "notify imf that textfield exit textPreview");
5083 #endif
5084 }
5085
InsertValueByController(const std::u16string & insertValue,int32_t offset)5086 int32_t TextFieldPattern::InsertValueByController(const std::u16string& insertValue, int32_t offset)
5087 {
5088 auto host = GetHost();
5089 CHECK_NULL_RETURN(host, offset);
5090 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
5091 CHECK_NULL_RETURN(layoutProperty, offset);
5092 ChangeValueInfo changeValueInfo;
5093 changeValueInfo.oldContent = GetBodyTextValue();
5094 changeValueInfo.oldPreviewText.offset = hasPreviewText_ ? GetPreviewTextStart() : -1;
5095 changeValueInfo.oldPreviewText.value = GetPreviewTextValue();
5096 changeValueInfo.rangeBefore = TextRange { offset, offset };
5097 NotifyImfFinishTextPreview();
5098 int32_t originLength =
5099 static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
5100 bool hasInsertValue =
5101 contentController_->InsertValue(offset, insertValue);
5102 changeValueInfo.previewText.offset = hasPreviewText_ ? GetPreviewTextStart() : -1;
5103 changeValueInfo.previewText.value = GetPreviewTextValue();
5104 changeValueInfo.value = contentController_->GetTextUtf16Value();
5105 changeValueInfo.rangeAfter =
5106 TextRange { offset, offset + static_cast<int32_t>(contentController_->GetInsertValue().length()) };
5107 bool isWillChange = FireOnWillChange(changeValueInfo);
5108 if (!isWillChange) {
5109 contentController_->SetTextValue(changeValueInfo.oldContent);
5110 return false;
5111 }
5112 int32_t caretMoveLength =
5113 abs(static_cast<int32_t>(contentController_->GetTextUtf16Value().length()) - originLength);
5114 if (layoutProperty->HasMaxLength()) {
5115 CalcCounterAfterFilterInsertValue(originLength, insertValue,
5116 static_cast<int32_t>(layoutProperty->GetMaxLengthValue(Infinity<uint32_t>())));
5117 }
5118 selectController_->UpdateCaretIndex(offset + caretMoveLength);
5119
5120 auto pipeline = host->GetContext();
5121 CHECK_NULL_RETURN(pipeline, offset);
5122 pipeline->AddAfterLayoutTask([weak = WeakClaim(Referenced::RawPtr(selectController_))]() {
5123 auto selectController = weak.Upgrade();
5124 CHECK_NULL_VOID(selectController);
5125 int32_t index = selectController->GetCaretIndex();
5126 selectController->MoveCaretToContentRect(index);
5127 });
5128
5129 UpdateObscure(insertValue, hasInsertValue);
5130 UpdateEditingValueToRecord();
5131 focusIndex_ = FocuseIndex::TEXT;
5132 TwinklingByFocus();
5133 CloseSelectOverlay(true);
5134 ScrollToSafeArea();
5135 ProcessResponseArea();
5136 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
5137 return selectController_->GetCaretIndex();
5138 }
5139
ExecuteInsertValueCommand(const InsertCommandInfo & info)5140 void TextFieldPattern::ExecuteInsertValueCommand(const InsertCommandInfo& info)
5141 {
5142 auto insertValue = info.insertValue;
5143 auto isIME = (info.reason == InputReason::IME);
5144 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
5145 CHECK_NULL_VOID(layoutProperty);
5146 TwinklingByFocus();
5147 auto start = selectController_->GetStartIndex();
5148 auto end = selectController_->GetEndIndex();
5149 auto caretStart = IsSelected() ? start : selectController_->GetCaretIndex();
5150 if (isIME) {
5151 auto isInsert = BeforeIMEInsertValue(insertValue, caretStart);
5152 CHECK_NULL_VOID(isInsert);
5153 }
5154 int32_t caretMoveLength = 0;
5155 bool hasInsertValue = false;
5156 int32_t originLength = 0;
5157 auto oldContent = contentController_->GetTextUtf16Value();
5158 auto originCaretIndex =
5159 TextRange { selectController_->GetFirstHandleIndex(), selectController_->GetSecondHandleIndex() };
5160 if (IsSelected()) {
5161 auto value = contentController_->GetSelectedValue(start, end);
5162 auto isDelete = true;
5163 if (isIME) {
5164 isDelete = BeforeIMEDeleteValue(value, TextDeleteDirection::BACKWARD, end);
5165 }
5166 end = isDelete ? end : start;
5167 originLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length()) - (end - start);
5168 hasInsertValue = contentController_->ReplaceSelectedValue(start, end, insertValue);
5169 caretMoveLength = abs(static_cast<int32_t>(contentController_->GetTextUtf16Value().length()) - originLength);
5170 bool isWillChange = OnWillChangePreInsert(contentController_->GetInsertValue(), oldContent, start, end);
5171 if (!isWillChange) {
5172 RecoverTextValueAndCaret(oldContent, originCaretIndex);
5173 return;
5174 }
5175 if (isIME && isDelete) {
5176 selectController_->UpdateCaretIndex(start);
5177 AfterIMEDeleteValue(value, TextDeleteDirection::BACKWARD);
5178 }
5179 } else {
5180 originLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
5181 hasInsertValue = contentController_->InsertValue(selectController_->GetCaretIndex(), insertValue);
5182 caretMoveLength = abs(static_cast<int32_t>(contentController_->GetTextUtf16Value().length()) - originLength);
5183 bool isWillChange = OnWillChangePreInsert(contentController_->GetInsertValue(), oldContent, start, end);
5184 if (!isWillChange) {
5185 RecoverTextValueAndCaret(oldContent, originCaretIndex);
5186 return;
5187 }
5188 }
5189 if (layoutProperty->HasMaxLength()) {
5190 CalcCounterAfterFilterInsertValue(originLength, insertValue,
5191 static_cast<int32_t>(layoutProperty->GetMaxLengthValue(Infinity<uint32_t>())));
5192 }
5193 selectController_->UpdateCaretIndex(caretStart + caretMoveLength);
5194 UpdateObscure(insertValue, hasInsertValue);
5195 UpdateEditingValueToRecord();
5196 if (isIME) {
5197 AfterIMEInsertValue(contentController_->GetInsertValue());
5198 }
5199 }
5200
TwinklingByFocus()5201 void TextFieldPattern::TwinklingByFocus()
5202 {
5203 if (HasFocus() && focusIndex_ == FocuseIndex::TEXT) {
5204 cursorVisible_ = true;
5205 StartTwinkling();
5206 } else {
5207 cursorVisible_ = false;
5208 StopTwinkling();
5209 }
5210 }
5211
FinishTextPreviewByPreview(const std::u16string & insertValue)5212 bool TextFieldPattern::FinishTextPreviewByPreview(const std::u16string& insertValue)
5213 {
5214 if (GetIsPreviewText()) {
5215 PreviewTextInfo info = {
5216 .text = insertValue,
5217 .range = { -1, -1 },
5218 .isIme = false
5219 };
5220 inputOperations_.emplace(InputOperation::SET_PREVIEW_TEXT);
5221 previewTextOperation_.emplace(info);
5222 FinishTextPreview();
5223 return true;
5224 }
5225 return false;
5226 }
5227
UpdateObscure(const std::u16string & insertValue,bool hasInsertValue)5228 void TextFieldPattern::UpdateObscure(const std::u16string& insertValue, bool hasInsertValue)
5229 {
5230 if (!IsTextArea() && IsInPasswordMode() && GetTextObscured()) {
5231 auto host = GetHost();
5232 CHECK_NULL_VOID(host);
5233 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
5234 CHECK_NULL_VOID(layoutProperty);
5235 if (insertValue.length() == 1 &&
5236 (layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED) != TextInputType::NUMBER_PASSWORD ||
5237 std::isdigit(insertValue[0])) &&
5238 hasInsertValue) {
5239 auto content = contentController_->GetTextUtf16Value();
5240 auto insertIndex = selectController_->GetCaretIndex() - 1;
5241 insertIndex = std::clamp(insertIndex, 0, static_cast<int32_t>(content.length()));
5242 auto strBeforeCaret = content.empty() ? u"" : content.substr(insertIndex, 1);
5243 obscureTickCountDown_ = strBeforeCaret == insertValue ? OBSCURE_SHOW_TICKS : 0;
5244 nakedCharPosition_ = strBeforeCaret == insertValue ? insertIndex : -1;
5245 } else {
5246 obscureTickCountDown_ = 0;
5247 nakedCharPosition_ = -1;
5248 }
5249 }
5250 }
5251
InsertValue(const std::u16string & insertValue,bool isIME)5252 void TextFieldPattern::InsertValue(const std::u16string& insertValue, bool isIME)
5253 {
5254 InputReason reason = isIME ? InputReason::IME : InputReason::NONE;
5255 AddInsertCommand(insertValue, reason);
5256 }
5257
InsertValue(const std::string & insertValue,bool isIME)5258 void TextFieldPattern::InsertValue(const std::string& insertValue, bool isIME)
5259 {
5260 InsertValue(UtfUtils::Str8DebugToStr16(insertValue), isIME);
5261 }
5262
UltralimitShake()5263 void TextFieldPattern::UltralimitShake()
5264 {
5265 auto frameNode = GetHost();
5266 CHECK_NULL_VOID(frameNode);
5267 auto context = frameNode->GetRenderContext();
5268 CHECK_NULL_VOID(context);
5269 AnimationOption option;
5270 context->UpdateTranslateInXY({ -1.0, 0.0 });
5271 const RefPtr<InterpolatingSpring> curve =
5272 AceType::MakeRefPtr<InterpolatingSpring>(VELOCITY, MASS, STIFFNESS, DAMPING);
5273 option.SetCurve(curve);
5274 option.SetFillMode(FillMode::FORWARDS);
5275 auto pipelineContext = frameNode->GetContext();
5276 CHECK_NULL_VOID(pipelineContext);
5277 AnimationUtils::Animate(
5278 option,
5279 [weak = WeakClaim(Referenced::RawPtr(context))]() {
5280 auto context = weak.Upgrade();
5281 CHECK_NULL_VOID(context);
5282 context->UpdateTranslateInXY({ 0.0f, 0.0f });
5283 },
5284 option.GetOnFinishEvent());
5285 }
5286
AdjustFloatingCaretInfo(const Offset & localOffset,const HandleInfoNG & caretInfo,HandleInfoNG & floatingCaretInfo)5287 void TextFieldPattern::AdjustFloatingCaretInfo(const Offset& localOffset,
5288 const HandleInfoNG& caretInfo, HandleInfoNG& floatingCaretInfo)
5289 {
5290 CHECK_NULL_VOID(selectController_);
5291 auto offsetX = localOffset.GetX();
5292 auto offsetY = caretInfo.rect.Top();
5293 floatingCaretInfo.rect.SetHeight(caretInfo.rect.Height());
5294 auto contentRect = GetTextContentRect();
5295 offsetX = std::min(std::max(contentRect.Left(), static_cast<float>(offsetX)),
5296 contentRect.Right() - caretInfo.rect.Width());
5297 offsetY = std::min(std::max(contentRect.Top(), static_cast<float>(offsetY)),
5298 contentRect.Bottom() - floatingCaretInfo.rect.Height());
5299 floatingCaretInfo.UpdateOffset({offsetX, offsetY});
5300 bool reachBoundary = NearEqual(contentRect.Left(), offsetX) ||
5301 NearEqual(contentRect.Right() - caretInfo.rect.Width(), static_cast<float>(offsetX));
5302 bool distanceMoreThenTenVp = floatingCaretInfo.rect.GetOffset().GetDistance(caretInfo.rect.GetOffset())
5303 >= FLOATING_CARET_SHOW_ORIGIN_CARET_DISTANCE.ConvertToPx();
5304 TouchPosition pos = selectController_->GetTouchLinePos(localOffset);
5305 bool FloatCursorOnOriginLeft = floatingCaretInfo.rect.GetX() < caretInfo.rect.GetX();
5306 bool FloatCursorNotInText = ((pos == TouchPosition::LEFT && FloatCursorOnOriginLeft) ||
5307 (pos == TouchPosition::RIGHT && !FloatCursorOnOriginLeft));
5308 SetShowOriginCursor((reachBoundary || distanceMoreThenTenVp) && FloatCursorNotInText);
5309 SetFloatingCursorVisible(true);
5310 }
5311
FloatingCaretLand()5312 void TextFieldPattern::FloatingCaretLand()
5313 {
5314 CHECK_NULL_VOID(floatCaretState_.FloatingCursorVisible && textFieldOverlayModifier_ && selectController_);
5315 textFieldOverlayModifier_->StartFloatingCaretLand(selectController_->GetCaretRect().GetOffset());
5316 }
5317
CleanCounterNode()5318 void TextFieldPattern::CleanCounterNode()
5319 {
5320 counterDecorator_.Reset();
5321 }
5322
CleanErrorNode()5323 void TextFieldPattern::CleanErrorNode()
5324 {
5325 errorDecorator_.Reset();
5326 }
5327
UpdateEditingValueToRecord(int32_t beforeCaretPosition)5328 void TextFieldPattern::UpdateEditingValueToRecord(int32_t beforeCaretPosition)
5329 {
5330 if (operationRecords_.size() >= RECORD_MAX_LENGTH) {
5331 operationRecords_.erase(operationRecords_.begin());
5332 }
5333 TextEditingValueNG record {
5334 .text = contentController_->GetTextUtf16Value(),
5335 .caretPosition = selectController_->GetCaretIndex(),
5336 .beforeCaretPosition = beforeCaretPosition,
5337 };
5338 operationRecords_.emplace_back(record);
5339 }
5340
PreferredTextHeight(bool isPlaceholder,bool isAlgorithmMeasure)5341 float TextFieldPattern::PreferredTextHeight(bool isPlaceholder, bool isAlgorithmMeasure)
5342 {
5343 if (!isAlgorithmMeasure && paragraph_ && paragraph_->GetHeight() != 0.0f && paragraph_->GetLineCount() > 0) {
5344 return paragraph_->GetHeight() / paragraph_->GetLineCount();
5345 }
5346 RefPtr<Paragraph> paragraph;
5347 std::u16string textContent;
5348 TextStyle textStyle;
5349 auto tmpHost = GetHost();
5350 CHECK_NULL_RETURN(tmpHost, 0.0f);
5351 auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
5352 CHECK_NULL_RETURN(layoutProperty, 0.0f);
5353 auto textFieldTheme = GetTheme();
5354 CHECK_NULL_RETURN(textFieldTheme, 0.0f);
5355 // use text or placeHolder value if exists, space otherwise
5356 if (!isPlaceholder) {
5357 TextFieldLayoutAlgorithm::UpdateTextStyle(tmpHost, layoutProperty, textFieldTheme, textStyle, false);
5358 textContent = u"a";
5359 } else {
5360 TextFieldLayoutAlgorithm::UpdatePlaceholderTextStyle(tmpHost, layoutProperty, textFieldTheme, textStyle, false);
5361 textContent = u"b";
5362 }
5363 if (adaptFontSize_.has_value()) {
5364 textStyle.SetFontSize(adaptFontSize_.value());
5365 }
5366 if (textStyle.GetFontSize().IsNonPositive()) {
5367 textStyle.SetFontSize(DEFAULT_FONT);
5368 }
5369 if (textStyle.GetLineHeight().IsNegative()) {
5370 textStyle.SetLineHeight(Dimension(0.0));
5371 }
5372 ParagraphStyle paraStyle { .direction =
5373 TextFieldLayoutAlgorithm::GetTextDirection(contentController_->GetTextUtf16Value()),
5374 .align = textStyle.GetTextAlign(),
5375 .maxLines = textStyle.GetMaxLines(),
5376 .fontLocale = Localization::GetInstance()->GetFontLocale(),
5377 .wordBreak = textStyle.GetWordBreak(),
5378 .ellipsisMode = textStyle.GetEllipsisMode(),
5379 .lineBreakStrategy = textStyle.GetLineBreakStrategy(),
5380 .textOverflow = textStyle.GetTextOverflow(),
5381 .fontSize = FontSizeConvertToPx(textStyle.GetFontSize()) };
5382 paragraph = Paragraph::Create(paraStyle, FontCollection::Current());
5383 CHECK_NULL_RETURN(paragraph, 0.0f);
5384 paragraph->PushStyle(textStyle);
5385 UtfUtils::HandleInvalidUTF16(reinterpret_cast<uint16_t*>(textContent.data()), textContent.length(), 0);
5386 paragraph->AddText(textContent);
5387 paragraph->Build();
5388 paragraph->Layout(std::numeric_limits<double>::infinity());
5389 return paragraph->GetHeight();
5390 }
5391
FontSizeConvertToPx(const Dimension & fontSize)5392 float TextFieldPattern::FontSizeConvertToPx(const Dimension& fontSize)
5393 {
5394 return fontSize.ConvertToPx();
5395 }
5396
PreferredLineHeight(bool isAlgorithmMeasure)5397 float TextFieldPattern::PreferredLineHeight(bool isAlgorithmMeasure)
5398 {
5399 return PreferredTextHeight(contentController_->IsEmpty(), isAlgorithmMeasure);
5400 }
5401
OnCursorMoveDone(TextAffinity textAffinity,std::optional<Offset> offset)5402 void TextFieldPattern::OnCursorMoveDone(TextAffinity textAffinity, std::optional<Offset> offset)
5403 {
5404 auto tmpHost = GetHost();
5405 CHECK_NULL_VOID(tmpHost);
5406 StartTwinkling();
5407 CloseSelectOverlay();
5408 if (offset.has_value()) {
5409 selectController_->UpdateCaretInfoByOffset(offset.value());
5410 } else {
5411 selectController_->MoveCaretToContentRect(GetCaretIndex(), textAffinity);
5412 }
5413 if (ResetObscureTickCountDown()) {
5414 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
5415 } else {
5416 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
5417 }
5418 UpdateCaretInfoToController();
5419 }
5420
GetWordLength(int32_t originCaretPosition,int32_t directionMove,bool skipNewLineChar)5421 int32_t TextFieldPattern::GetWordLength(int32_t originCaretPosition, int32_t directionMove, bool skipNewLineChar)
5422 {
5423 if (contentController_->IsEmpty()) {
5424 return 0;
5425 }
5426 int32_t textLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
5427 if (originCaretPosition < 0 || originCaretPosition > textLength) {
5428 return 0;
5429 }
5430 // directionMove == 0 left, directionMove == 1 right
5431 // cannot get word length by current caret position and direction
5432 if ((directionMove == 0 && originCaretPosition == 0) || (directionMove == 1 && originCaretPosition == textLength)) {
5433 return 0;
5434 }
5435 int32_t offset = 0;
5436 int32_t strIndex = directionMove == 0 ? (originCaretPosition - 1) : originCaretPosition;
5437 auto wideTextValue = contentController_->GetTextUtf16Value();
5438 int32_t wordStart = 0;
5439 int32_t wordEnd = 0;
5440 while (directionMove == 0 ? strIndex >= 0 : strIndex <= textLength) {
5441 auto chr = wideTextValue[strIndex];
5442 // skip the special character
5443 if (chr == L' ' || (chr == L'\n' && skipNewLineChar)) {
5444 if (directionMove == 0) {
5445 strIndex--;
5446 } else {
5447 strIndex++;
5448 }
5449 offset++;
5450 continue;
5451 }
5452 // cal word length
5453 if (paragraph_ && paragraph_->GetWordBoundary(strIndex, wordStart, wordEnd)) {
5454 if (directionMove == 1) {
5455 offset += (wordEnd - strIndex);
5456 } else {
5457 offset += (strIndex - wordStart + 1); // when move left, actual offset should add 1
5458 }
5459 return std::clamp(offset, 0, textLength);
5460 }
5461 // GetWordBoundary fail
5462 return 0;
5463 }
5464 return std::clamp(offset, 0, textLength);
5465 }
5466
GetLineBeginPosition(int32_t originCaretPosition,bool needToCheckLineChanged)5467 int32_t TextFieldPattern::GetLineBeginPosition(int32_t originCaretPosition, bool needToCheckLineChanged)
5468 {
5469 if (contentController_->IsEmpty()) {
5470 return 0;
5471 }
5472 auto wideTextValue = contentController_->GetTextUtf16Value();
5473 int32_t textLength = static_cast<int32_t>(wideTextValue.length());
5474 if (originCaretPosition < 0 || originCaretPosition > textLength) {
5475 return 0;
5476 }
5477 if (originCaretPosition == 0) {
5478 return originCaretPosition;
5479 }
5480 int32_t moveLineBeginOffset = 0;
5481 int32_t strIndex = originCaretPosition;
5482 do {
5483 moveLineBeginOffset++;
5484 strIndex--;
5485 // stop moving caret if reaches \n, text head or caret line changed
5486 } while (((strIndex > 0) && (wideTextValue[strIndex] != u'\n')) &&
5487 (needToCheckLineChanged ? !CharLineChanged(strIndex) : true));
5488 if (strIndex < 0 || strIndex >= static_cast<int32_t>(wideTextValue.length())) {
5489 return 0;
5490 }
5491 if (strIndex > 0) {
5492 moveLineBeginOffset--;
5493 }
5494 if (moveLineBeginOffset > originCaretPosition) {
5495 return 0;
5496 }
5497 return originCaretPosition - moveLineBeginOffset;
5498 }
5499
GetLineEndPosition(int32_t originCaretPosition,bool needToCheckLineChanged)5500 int32_t TextFieldPattern::GetLineEndPosition(int32_t originCaretPosition, bool needToCheckLineChanged)
5501 {
5502 if (contentController_->IsEmpty()) {
5503 return 0;
5504 }
5505 auto wideTextValue = contentController_->GetTextUtf16Value();
5506 int32_t textLength = static_cast<int32_t>(wideTextValue.length());
5507 if (originCaretPosition < 0 || originCaretPosition > textLength) {
5508 return originCaretPosition;
5509 }
5510 if (originCaretPosition == textLength) {
5511 return originCaretPosition;
5512 }
5513 int32_t moveLineEndOffset = 0;
5514 int32_t strIndex = 0;
5515 for (strIndex = originCaretPosition; (strIndex <= textLength && wideTextValue[strIndex] != u'\n') &&
5516 (needToCheckLineChanged ? !CharLineChanged(strIndex) : true);
5517 strIndex++) {
5518 moveLineEndOffset++;
5519 }
5520 if (moveLineEndOffset > textLength - originCaretPosition) {
5521 return textLength;
5522 }
5523 return originCaretPosition + moveLineEndOffset;
5524 }
5525
CharLineChanged(int32_t caretPosition)5526 bool TextFieldPattern::CharLineChanged(int32_t caretPosition)
5527 {
5528 if (caretPosition < 0 || caretPosition > static_cast<int32_t>(contentController_->GetTextUtf16Value().length())) {
5529 return true;
5530 }
5531 CaretMetricsF caretMetrics;
5532 CalcCaretMetricsByPosition(caretPosition, caretMetrics);
5533 // the cursor is aligned with the text at the bottom
5534 return !NearEqual(caretMetrics.offset.GetY() + caretMetrics.height,
5535 selectController_->GetCaretRect().GetY() + selectController_->GetCaretRect().Height());
5536 }
5537
CursorMoveLeftOperation()5538 bool TextFieldPattern::CursorMoveLeftOperation()
5539 {
5540 if (focusIndex_ != FocuseIndex::TEXT) {
5541 return UpdateFocusBackward();
5542 }
5543 auto originCaretPosition = selectController_->GetCaretIndex();
5544 if (IsSelected()) {
5545 selectController_->UpdateCaretIndex(selectController_->GetStartIndex());
5546 CloseSelectOverlay();
5547 } else {
5548 UpdateCaretPositionWithClamp(
5549 selectController_->GetCaretIndex() -
5550 GetGraphemeClusterLength(contentController_->GetTextUtf16Value(), selectController_->GetCaretIndex(),
5551 true));
5552 }
5553 OnCursorMoveDone(TextAffinity::DOWNSTREAM);
5554 return originCaretPosition != selectController_->GetCaretIndex();
5555 }
5556
CursorMoveLeft()5557 bool TextFieldPattern::CursorMoveLeft()
5558 {
5559 if (inputOperations_.empty()) {
5560 return CursorMoveLeftOperation();
5561 }
5562
5563 inputOperations_.emplace(InputOperation::CURSOR_LEFT);
5564 return false;
5565 }
5566
CursorMoveLeftWord()5567 bool TextFieldPattern::CursorMoveLeftWord()
5568 {
5569 if (selectController_->GetCaretIndex() == 0) {
5570 return true;
5571 }
5572 int32_t originCaretPosition = selectController_->GetCaretIndex();
5573 int32_t textLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
5574 int32_t leftWordLength = GetWordLength(originCaretPosition, 0);
5575 if (leftWordLength < 0 || leftWordLength > textLength || selectController_->GetCaretIndex() - leftWordLength < 0) {
5576 return false;
5577 }
5578 if (IsSelected()) {
5579 selectController_->UpdateCaretIndex(selectController_->GetSecondHandleIndex() - leftWordLength);
5580 CloseSelectOverlay();
5581 } else {
5582 UpdateCaretPositionWithClamp(originCaretPosition - leftWordLength);
5583 }
5584 OnCursorMoveDone();
5585 return originCaretPosition != selectController_->GetCaretIndex();
5586 }
5587
CursorMoveLineBegin()5588 bool TextFieldPattern::CursorMoveLineBegin()
5589 {
5590 if (selectController_->GetCaretIndex() == 0 && !IsSelected()) {
5591 return true;
5592 }
5593 int32_t textLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
5594 int32_t originCaretPosition = selectController_->GetCaretIndex();
5595 int32_t lineBeginPosition = GetLineBeginPosition(originCaretPosition);
5596 if (lineBeginPosition < 0 || lineBeginPosition > textLength) {
5597 return false;
5598 }
5599 if (selectController_->IsSelectedAll()) {
5600 selectController_->UpdateCaretIndex(0);
5601 } else if (IsTextArea()) {
5602 UpdateCaretPositionWithClamp(lineBeginPosition);
5603 } else {
5604 UpdateCaretPositionWithClamp(0);
5605 }
5606 OnCursorMoveDone(TextAffinity::DOWNSTREAM);
5607 return originCaretPosition != selectController_->GetCaretIndex();
5608 }
5609
CursorMoveToParagraphBegin()5610 bool TextFieldPattern::CursorMoveToParagraphBegin()
5611 {
5612 if (selectController_->GetCaretIndex() == 0) {
5613 return true;
5614 }
5615 auto originCaretPosition = selectController_->GetCaretIndex();
5616 auto newPos = GetLineBeginPosition(originCaretPosition, false);
5617 if (newPos == originCaretPosition && originCaretPosition > 0) {
5618 newPos = GetLineBeginPosition(originCaretPosition - 1, false);
5619 }
5620 UpdateCaretPositionWithClamp(newPos);
5621 OnCursorMoveDone(TextAffinity::DOWNSTREAM);
5622 return originCaretPosition != selectController_->GetCaretIndex();
5623 }
5624
CursorMoveHome()5625 bool TextFieldPattern::CursorMoveHome()
5626 {
5627 // ctrl + home, caret move to position 0
5628 if (selectController_->GetCaretIndex() == 0) {
5629 return true;
5630 }
5631 int32_t originCaretPosition = selectController_->GetCaretIndex();
5632 UpdateCaretPositionWithClamp(0);
5633 OnCursorMoveDone();
5634 return originCaretPosition != selectController_->GetCaretIndex();
5635 }
5636
CursorMoveRightOperation()5637 bool TextFieldPattern::CursorMoveRightOperation()
5638 {
5639 if (focusIndex_ != FocuseIndex::TEXT) {
5640 return UpdateFocusForward();
5641 }
5642 auto originCaretPosition = selectController_->GetCaretIndex();
5643 if (IsSelected()) {
5644 CloseSelectOverlay();
5645 selectController_->UpdateCaretIndex(selectController_->GetEndIndex());
5646 } else {
5647 UpdateCaretPositionWithClamp(
5648 selectController_->GetCaretIndex() +
5649 GetGraphemeClusterLength(contentController_->GetTextUtf16Value(), selectController_->GetCaretIndex()));
5650 }
5651 OnCursorMoveDone(TextAffinity::DOWNSTREAM);
5652 return originCaretPosition != selectController_->GetCaretIndex();
5653 }
5654
CursorMoveRight()5655 bool TextFieldPattern::CursorMoveRight()
5656 {
5657 if (inputOperations_.empty()) {
5658 return CursorMoveRightOperation();
5659 }
5660 inputOperations_.emplace(InputOperation::CURSOR_RIGHT);
5661 return false;
5662 }
5663
CursorMoveRightWord()5664 bool TextFieldPattern::CursorMoveRightWord()
5665 {
5666 if (selectController_->GetCaretIndex() == static_cast<int32_t>(contentController_->GetTextUtf16Value().length())) {
5667 return true;
5668 }
5669 int32_t originCaretPosition = selectController_->GetCaretIndex();
5670 int32_t textLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
5671 int32_t rightWordLength = GetWordLength(originCaretPosition, 1);
5672 if (rightWordLength < 0 || rightWordLength > textLength ||
5673 rightWordLength + selectController_->GetCaretIndex() > textLength) {
5674 return false;
5675 }
5676 if (selectController_->IsSelectedAll()) {
5677 selectController_->UpdateCaretIndex(textLength);
5678 } else {
5679 UpdateCaretPositionWithClamp(originCaretPosition + rightWordLength);
5680 }
5681 OnCursorMoveDone();
5682 return originCaretPosition != selectController_->GetCaretIndex();
5683 }
5684
CursorMoveLineEnd()5685 bool TextFieldPattern::CursorMoveLineEnd()
5686 {
5687 if (selectController_->GetCaretIndex() == static_cast<int32_t>(contentController_->GetTextUtf16Value().length()) &&
5688 !IsSelected()) {
5689 return true;
5690 }
5691 int32_t originCaretPosition = selectController_->GetCaretIndex();
5692 int32_t textLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
5693 int32_t lineEndPosition = GetLineEndPosition(originCaretPosition);
5694 if (lineEndPosition < 0 || lineEndPosition > textLength) {
5695 return false;
5696 }
5697 if (selectController_->IsSelectedAll()) {
5698 selectController_->UpdateCaretIndex(textLength);
5699 } else if (IsTextArea()) {
5700 UpdateCaretPositionWithClamp(lineEndPosition);
5701 } else {
5702 UpdateCaretPositionWithClamp(textLength);
5703 }
5704 OnCursorMoveDone();
5705 return originCaretPosition != selectController_->GetCaretIndex();
5706 }
5707
CursorMoveToParagraphEnd()5708 bool TextFieldPattern::CursorMoveToParagraphEnd()
5709 {
5710 if (selectController_->GetCaretIndex() == static_cast<int32_t>(contentController_->GetTextUtf16Value().length())) {
5711 return true;
5712 }
5713 auto originCaretPosition = selectController_->GetCaretIndex();
5714 auto newPos = GetLineEndPosition(originCaretPosition, false);
5715 if (newPos == originCaretPosition && originCaretPosition > 0) {
5716 newPos = GetLineEndPosition(originCaretPosition + 1, false);
5717 }
5718 UpdateCaretPositionWithClamp(newPos);
5719 OnCursorMoveDone(TextAffinity::DOWNSTREAM);
5720 return originCaretPosition != selectController_->GetCaretIndex();
5721 }
5722
CursorMoveEnd()5723 bool TextFieldPattern::CursorMoveEnd()
5724 {
5725 // ctrl end, caret to the very end
5726 if (selectController_->GetCaretIndex() == static_cast<int32_t>(contentController_->GetTextUtf16Value().length())) {
5727 return true;
5728 }
5729 int32_t originCaretPosition = selectController_->GetCaretIndex();
5730 int32_t textLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
5731 UpdateCaretPositionWithClamp(textLength);
5732 OnCursorMoveDone();
5733 return originCaretPosition != selectController_->GetCaretIndex();
5734 }
5735
CursorMoveUpOperation()5736 bool TextFieldPattern::CursorMoveUpOperation()
5737 {
5738 if (!IsTextArea() && !IsSelected()) {
5739 return CursorMoveToParagraphBegin();
5740 }
5741 auto originCaretPosition = selectController_->GetCaretIndex();
5742 auto offsetX = selectController_->GetCaretRect().GetX();
5743 // multiply by 0.5f to convert to the grapheme center point of the previous line.
5744 float lineHeight = PreferredLineHeight() * 0.5f;
5745 auto offsetY = selectController_->GetCaretRect().GetY() - lineHeight;
5746 if (offsetY < textRect_.GetY() && !IsSelected()) {
5747 return CursorMoveToParagraphBegin();
5748 }
5749 std::optional<Offset> offset;
5750 offset.emplace(Offset(offsetX, offsetY));
5751 OnCursorMoveDone(TextAffinity::DOWNSTREAM, offset);
5752 return originCaretPosition != selectController_->GetCaretIndex();
5753 }
5754
CursorMoveUp()5755 bool TextFieldPattern::CursorMoveUp()
5756 {
5757 if (inputOperations_.empty()) {
5758 return CursorMoveUpOperation();
5759 }
5760
5761 inputOperations_.emplace(InputOperation::CURSOR_UP);
5762 return false;
5763 }
5764
CursorMoveDownOperation()5765 bool TextFieldPattern::CursorMoveDownOperation()
5766 {
5767 if (!IsTextArea() && !IsSelected()) {
5768 return CursorMoveToParagraphEnd();
5769 }
5770 auto originCaretPosition = selectController_->GetCaretIndex();
5771 auto offsetX = selectController_->GetCaretRect().GetX();
5772 // multiply by 1.5f to convert to the grapheme center point of the next line.
5773 float lineHeight = PreferredLineHeight() * 1.5f;
5774 auto offsetY = selectController_->GetCaretRect().GetY() + lineHeight;
5775 if (offsetY > textRect_.GetY() + textRect_.Height() && !IsSelected()) {
5776 return CursorMoveToParagraphEnd();
5777 }
5778 std::optional<Offset> offset;
5779 offset.emplace(Offset(offsetX, offsetY));
5780 OnCursorMoveDone(TextAffinity::DOWNSTREAM, offset);
5781 return originCaretPosition != selectController_->GetCaretIndex();
5782 }
5783
CursorMoveDown()5784 bool TextFieldPattern::CursorMoveDown()
5785 {
5786 if (inputOperations_.empty()) {
5787 return CursorMoveDownOperation();
5788 }
5789
5790 inputOperations_.emplace(InputOperation::CURSOR_DOWN);
5791 return false;
5792 }
5793
Delete(int32_t start,int32_t end)5794 void TextFieldPattern::Delete(int32_t start, int32_t end)
5795 {
5796 SwapIfLarger(start, end);
5797 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "Handle Delete within [%{public}d, %{public}d]", start, end);
5798 contentController_->erase(start, end - start);
5799 UpdateSelection(start);
5800 selectController_->MoveCaretToContentRect(start);
5801 if (isLongPress_) {
5802 CancelGestureSelection();
5803 }
5804 CloseSelectOverlay(true);
5805 StartTwinkling();
5806 auto beforeCaretPosition = end - start + selectController_->GetCaretIndex();
5807 UpdateEditingValueToRecord(beforeCaretPosition);
5808 auto tmpHost = GetHost();
5809 CHECK_NULL_VOID(tmpHost);
5810 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
5811 }
5812
HandleCounterBorder()5813 void TextFieldPattern::HandleCounterBorder()
5814 {
5815 auto theme = GetTheme();
5816 CHECK_NULL_VOID(theme);
5817 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
5818 CHECK_NULL_VOID(paintProperty);
5819 auto host = GetHost();
5820 CHECK_NULL_VOID(host);
5821 auto renderContext = host->GetRenderContext();
5822 CHECK_NULL_VOID(renderContext);
5823 if (showCountBorderStyle_) {
5824 if (IsUnderlineMode()) {
5825 underlineWidth_ = ERROR_UNDERLINE_WIDTH;
5826 SetUnderlineColor(userUnderlineColor_.error.value_or(theme->GetErrorUnderlineColor()));
5827 } else {
5828 if (!paintProperty->HasBorderWidthFlagByUser()) {
5829 paintProperty->UpdateInnerBorderWidth(OVER_COUNT_BORDER_WIDTH);
5830 paintProperty->UpdateInnerBorderColor(theme->GetOverCounterColor());
5831 } else {
5832 BorderColorProperty overCountBorderColor;
5833 overCountBorderColor.SetColor(theme->GetOverCounterColor());
5834 renderContext->UpdateBorderColor(overCountBorderColor);
5835 }
5836 }
5837 } else {
5838 if (IsUnderlineMode() && !IsShowError()) {
5839 ApplyUnderlineTheme();
5840 CHECK_NULL_VOID(counterDecorator_);
5841 counterDecorator_->UpdateTextFieldMargin();
5842 } else {
5843 SetThemeBorderAttr();
5844 }
5845 }
5846 }
5847
ProcessFocusIndexAction()5848 bool TextFieldPattern::ProcessFocusIndexAction()
5849 {
5850 if (focusIndex_ == FocuseIndex::CANCEL) {
5851 CleanNodeResponseKeyEvent();
5852 return false;
5853 }
5854 if (focusIndex_ == FocuseIndex::UNIT) {
5855 if (IsShowPasswordIcon()) {
5856 PasswordResponseKeyEvent();
5857 }
5858 if (IsShowUnit()) {
5859 UnitResponseKeyEvent();
5860 }
5861 return false;
5862 }
5863 return true;
5864 }
5865
PerformAction(TextInputAction action,bool forceCloseKeyboard)5866 void TextFieldPattern::PerformAction(TextInputAction action, bool forceCloseKeyboard)
5867 {
5868 if (!HasFocus()) {
5869 TAG_LOGW(AceLogTag::ACE_TEXT_FIELD, "Not Trigger OnSubmit because field blur");
5870 return;
5871 }
5872 if (!ProcessFocusIndexAction()) {
5873 TAG_LOGW(AceLogTag::ACE_TEXT_FIELD, "Not Trigger OnSubmit because focus index not on text");
5874 return;
5875 }
5876 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "TextField PerformAction %{public}d", static_cast<int32_t>(action));
5877 auto host = GetHost();
5878 CHECK_NULL_VOID(host);
5879 // If the parent node is a Search, the Search callback is executed.
5880 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
5881 CHECK_NULL_VOID(paintProperty);
5882 auto eventHub = host->GetOrCreateEventHub<TextFieldEventHub>();
5883 CHECK_NULL_VOID(eventHub);
5884 TextFieldCommonEvent event;
5885 event.SetText(contentController_->GetTextUtf16Value());
5886 if (IsNormalInlineState() && action != TextInputAction::NEW_LINE) {
5887 RecordSubmitEvent();
5888 eventHub->FireOnSubmit(static_cast<int32_t>(action), event);
5889 OnReportSubmitEvent(host);
5890 CHECK_NULL_VOID(!event.IsKeepEditable());
5891 TextFieldLostFocusToViewRoot();
5892 return;
5893 }
5894 if (IsTextArea() && action == TextInputAction::NEW_LINE) {
5895 if (!textAreaBlurOnSubmit_) {
5896 if (GetInputFilter() != "\n") {
5897 InsertValue(u"\n", true);
5898 }
5899 } else {
5900 CloseKeyboard(forceCloseKeyboard, false);
5901 TextFieldLostFocusToViewRoot();
5902 }
5903 return;
5904 }
5905 eventHub->FireOnSubmit(static_cast<int32_t>(action), event);
5906 OnReportSubmitEvent(host);
5907 RecordSubmitEvent();
5908 CHECK_NULL_VOID(!event.IsKeepEditable());
5909 // LostFocusToViewRoot may not cause current lost focus, only stop twinkling when it is truly lost focus,
5910 // which will call StopTwinkling on HandleBlurEvent method.
5911 if (textInputBlurOnSubmit_) {
5912 HandleCloseKeyboard(forceCloseKeyboard);
5913 }
5914 UiSessionManager::GetInstance()->ReportComponentChangeEvent("event", "Textfield.onSubmit");
5915 }
5916
TextFieldLostFocusToViewRoot()5917 void TextFieldPattern::TextFieldLostFocusToViewRoot()
5918 {
5919 CHECK_NULL_VOID(HasFocus());
5920 FocusHub::LostFocusToViewRoot();
5921 }
5922
RecordSubmitEvent() const5923 void TextFieldPattern::RecordSubmitEvent() const
5924 {
5925 if (!Recorder::EventRecorder::Get().IsComponentRecordEnable()) {
5926 return;
5927 }
5928 auto host = GetHost();
5929 CHECK_NULL_VOID(host);
5930 auto inspectorId = host->GetInspectorId().value_or("");
5931 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
5932 bool isPwdType = layoutProperty ? layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED) ==
5933 TextInputType::VISIBLE_PASSWORD
5934 : false;
5935 Recorder::EventParamsBuilder builder;
5936 builder.SetId(inspectorId)
5937 .SetType(host->GetTag())
5938 .SetEventType(Recorder::EventType::SEARCH_SUBMIT)
5939 .SetHost(host)
5940 .SetDescription(host->GetAutoEventParamValue(""));
5941 if (!isPwdType) {
5942 builder.SetText(contentController_->GetTextValue());
5943 }
5944 Recorder::EventRecorder::Get().OnEvent(std::move(builder));
5945 }
5946
UpdateEditingValue(const std::shared_ptr<TextEditingValue> & value,bool needFireChangeEvent)5947 void TextFieldPattern::UpdateEditingValue(const std::shared_ptr<TextEditingValue>& value, bool needFireChangeEvent)
5948 {
5949 auto result = UtfUtils::Str8DebugToStr16(value->text);
5950 #if !defined(ENABLE_STANDARD_INPUT)
5951 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
5952 if (layoutProperty && layoutProperty->HasMaxLength()) {
5953 bool textChange = false;
5954 contentController_->FilterTextInputStyle(textChange, result);
5955 auto resultLen = static_cast<int32_t>(result.length());
5956 auto maxLen = static_cast<int32_t>(layoutProperty->GetMaxLengthValue(Infinity<uint32_t>()));
5957 if (resultLen != maxLen) {
5958 showCountBorderStyle_ = resultLen > maxLen;
5959 HandleCountStyle();
5960 }
5961 auto deleteSize = resultLen - maxLen;
5962 if (resultLen > maxLen && value->selection.baseOffset >= deleteSize) {
5963 result.erase(value->selection.baseOffset - deleteSize, deleteSize);
5964 value->selection.baseOffset -= deleteSize;
5965 }
5966 }
5967 #endif
5968 UpdateEditingValueToRecord();
5969 contentController_->SetTextValue(result);
5970 selectController_->UpdateCaretIndex(value->selection.baseOffset);
5971 ContainerScope scope(GetInstanceId());
5972 CloseSelectOverlay();
5973 StartTwinkling();
5974 auto host = GetHost();
5975 CHECK_NULL_VOID(host);
5976
5977 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
5978 }
5979
UpdateInputFilterErrorText(const std::u16string & errorText)5980 void TextFieldPattern::UpdateInputFilterErrorText(const std::u16string& errorText)
5981 {
5982 if (!errorText.empty()) {
5983 auto tmpHost = GetHost();
5984 CHECK_NULL_VOID(tmpHost);
5985 auto textFieldEventHub = tmpHost->GetOrCreateEventHub<TextFieldEventHub>();
5986 CHECK_NULL_VOID(textFieldEventHub);
5987 textFieldEventHub->FireOnInputFilterError(errorText);
5988 }
5989 }
5990
UpdateInputFilterErrorText(const std::string & errorText)5991 void TextFieldPattern::UpdateInputFilterErrorText(const std::string& errorText)
5992 {
5993 UpdateInputFilterErrorText(UtfUtils::Str8DebugToStr16(errorText));
5994 }
5995
OnValueChanged(bool needFireChangeEvent,bool needFireSelectChangeEvent)5996 void TextFieldPattern::OnValueChanged(bool needFireChangeEvent, bool needFireSelectChangeEvent) {}
5997
OnHandleAreaChanged()5998 void TextFieldPattern::OnHandleAreaChanged()
5999 {
6000 auto parentGlobalOffset = GetPaintRectGlobalOffset();
6001 if (parentGlobalOffset != parentGlobalOffset_) {
6002 parentGlobalOffset_ = parentGlobalOffset;
6003 UpdateTextFieldManager(Offset(parentGlobalOffset_.GetX(), parentGlobalOffset_.GetY()), frameRect_.Height());
6004 HandleParentGlobalOffsetChange();
6005 }
6006 }
6007
HandleParentGlobalOffsetChange()6008 void TextFieldPattern::HandleParentGlobalOffsetChange()
6009 {
6010 selectController_->CalculateHandleOffset();
6011 CHECK_NULL_VOID(SelectOverlayIsOn() || selectOverlay_->SelectOverlayIsCreating());
6012 if (selectOverlay_->IsShowMouseMenu()) {
6013 CloseSelectOverlay();
6014 return;
6015 }
6016 if (selectOverlay_->IsHiddenHandle() && selectOverlay_->IsSingleHandle()) {
6017 selectOverlay_->ProcessOverlayOnAreaChanged({ .menuIsShow = false });
6018 } else {
6019 selectOverlay_->ProcessOverlay({ .menuIsShow = false });
6020 }
6021 }
6022
RequestKeyboardByFocusSwitch()6023 void TextFieldPattern::RequestKeyboardByFocusSwitch()
6024 {
6025 auto host = GetHost();
6026 CHECK_NULL_VOID(host);
6027 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD,
6028 "%{public}d RequestKeyboardByFocusSwitch: onFocus_: %{public}d Inner: %{public}d modalCovered: %{public}d",
6029 host->GetId(), needToRequestKeyboardOnFocus_, needToRequestKeyboardInner_, IsModalCovered());
6030 if (!needToRequestKeyboardInner_ || IsModalCovered()) {
6031 return;
6032 }
6033 auto pipeline = host->GetContextRefPtr();
6034 CHECK_NULL_VOID(pipeline);
6035 auto textFieldManager = DynamicCast<TextFieldManagerNG>(pipeline->GetTextFieldManager());
6036 CHECK_NULL_VOID(textFieldManager);
6037 textFieldManager->SetNeedToRequestKeyboard(true);
6038 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "%{public}d add requestkeyboard task", host->GetId());
6039 pipeline->AddAfterLayoutTask([weak = WeakClaim(this), manager = WeakPtr<TextFieldManagerNG>(textFieldManager)]() {
6040 auto textField = weak.Upgrade();
6041 CHECK_NULL_VOID(textField);
6042 auto textFieldManager = manager.Upgrade();
6043 if (textFieldManager && !textFieldManager->GetNeedToRequestKeyboard()) {
6044 // already call close/attach keyboard after text field get focus, so dont request keyboard now
6045 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "Already call close/attach before attach, no need attach this time");
6046 return;
6047 }
6048 if (!textField->needToRequestKeyboardInner_) {
6049 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "Not need to requestKeyboard inner");
6050 return;
6051 }
6052 if (!textField->RequestKeyboard(false, true, textField->needToRequestKeyboardOnFocus_)) {
6053 return;
6054 }
6055 textField->NotifyOnEditChanged(true);
6056 textField->SetNeedToRequestKeyboardInner(false, RequestKeyboardInnerChangeReason::REQUEST_KEYBOARD_SUCCESS);
6057 });
6058 }
6059
6060 // to distiguish request keyboard not by focus switching
RequestKeyboardNotByFocusSwitch(RequestKeyboardReason reason,SourceType sourceType)6061 bool TextFieldPattern::RequestKeyboardNotByFocusSwitch(RequestKeyboardReason reason, SourceType sourceType)
6062 {
6063 auto tmpHost = GetHost();
6064 CHECK_NULL_RETURN(tmpHost, false);
6065 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "%{public}d requestKeyboard With Reason %{public}s",
6066 tmpHost->GetId(), TextFieldPattern::RequestKeyboardReasonToString(reason).c_str());
6067 if (!RequestKeyboard(false, true, true, sourceType)) {
6068 return false;
6069 }
6070 auto context = tmpHost->GetContextRefPtr();
6071 CHECK_NULL_RETURN(context, true);
6072 auto textFieldManager = DynamicCast<TextFieldManagerNG>(context->GetTextFieldManager());
6073 CHECK_NULL_RETURN(textFieldManager, true);
6074 textFieldManager->SetNeedToRequestKeyboard(false);
6075 return true;
6076 }
6077
TextFieldRequestFocus(RequestFocusReason reason)6078 bool TextFieldPattern::TextFieldRequestFocus(RequestFocusReason reason)
6079 {
6080 if (HasFocus()) {
6081 return true;
6082 }
6083 auto host = GetHost();
6084 CHECK_NULL_RETURN(host, false);
6085 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "%{public}d Request Focus With Reason %{public}s",
6086 host->GetId(), TextFieldPattern::RequestFocusReasonToString(reason).c_str());
6087 auto focusHub = GetFocusHub();
6088 CHECK_NULL_RETURN(focusHub, false);
6089 requestFocusReason_ = reason;
6090 return focusHub->RequestFocusImmediately();
6091 }
6092
RequestFocusReasonToString(RequestFocusReason reason)6093 std::string TextFieldPattern::RequestFocusReasonToString(RequestFocusReason reason)
6094 {
6095 switch (reason) {
6096 case RequestFocusReason::DRAG_END: {
6097 return "DragEnd";
6098 }
6099 case RequestFocusReason::DRAG_MOVE: {
6100 return "DragMove";
6101 }
6102 case RequestFocusReason::DRAG_ENTER: {
6103 return "DragEnter";
6104 }
6105 case RequestFocusReason::CLICK: {
6106 return "Click";
6107 }
6108 case RequestFocusReason::LONG_PRESS: {
6109 return "LongPress";
6110 }
6111 case RequestFocusReason::AUTO_FILL: {
6112 return "AutoFill";
6113 }
6114 case RequestFocusReason::CLEAN_NODE: {
6115 return "CleanNode";
6116 }
6117 case RequestFocusReason::MOUSE: {
6118 return "Mouse";
6119 }
6120 case RequestFocusReason::UNKNOWN:
6121 default: {
6122 break;
6123 }
6124 }
6125 return "Unknown";
6126 }
6127
RequestKeyboardReasonToString(RequestKeyboardReason reason)6128 std::string TextFieldPattern::RequestKeyboardReasonToString(RequestKeyboardReason reason)
6129 {
6130 switch (reason) {
6131 case RequestKeyboardReason::ON_KEY_EVENT: {
6132 return "KeyEvent";
6133 }
6134 case RequestKeyboardReason::SINGLE_CLICK: {
6135 return "SingleClick";
6136 }
6137 case RequestKeyboardReason::DOUBLE_CLICK: {
6138 return "DoubleClick";
6139 }
6140 case RequestKeyboardReason::LONG_PRESS: {
6141 return "LongPress";
6142 }
6143 case RequestKeyboardReason::RESET_KEYBOARD: {
6144 return "ResetKeyboard";
6145 }
6146 case RequestKeyboardReason::MOUSE_RELEASE: {
6147 return "MouseRelease";
6148 }
6149 case RequestKeyboardReason::SET_SELECTION: {
6150 return "SetSelection";
6151 }
6152 case RequestKeyboardReason::SEARCH_REQUEST: {
6153 return "SearchRequest";
6154 }
6155 case RequestKeyboardReason::AUTO_FILL_REQUEST_FAIL: {
6156 return "AutoFillRequestFail";
6157 }
6158 case RequestKeyboardReason::SHOW_KEYBOARD_ON_FOCUS: {
6159 return "ShowKeyboardOnFocus";
6160 }
6161 case RequestKeyboardReason::STYLUS_DETECTOR: {
6162 return "StylusDetector";
6163 }
6164 case RequestKeyboardReason::CUSTOM_KEYBOARD: {
6165 return "CustomKeyboard";
6166 }
6167 case RequestKeyboardReason::UNKNOWN:
6168 default: {
6169 break;
6170 }
6171 }
6172 return "Unknown";
6173 }
6174
IsModalCovered()6175 bool TextFieldPattern::IsModalCovered()
6176 {
6177 auto host = GetHost();
6178 CHECK_NULL_RETURN(host, false);
6179 auto pageNode = host->GetPageNode();
6180 CHECK_NULL_RETURN(pageNode, false);
6181 auto pagePattern = pageNode->GetPattern<PagePattern>();
6182 CHECK_NULL_RETURN(pagePattern, false);
6183 return pagePattern->GetIsModalCovered();
6184 }
6185
HandleSurfaceChanged(int32_t newWidth,int32_t newHeight,int32_t prevWidth,int32_t prevHeight)6186 void TextFieldPattern::HandleSurfaceChanged(int32_t newWidth, int32_t newHeight, int32_t prevWidth, int32_t prevHeight)
6187 {
6188 if (newWidth == prevWidth && newHeight == prevHeight) {
6189 return;
6190 }
6191 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD,
6192 "Textfield handleSurface change, new width %{public}d, new height %{public}d, prev width %{public}d, prev "
6193 "height %{public}d",
6194 newWidth, newHeight, prevWidth, prevHeight);
6195 if (SelectOverlayIsOn()) {
6196 if (selectOverlay_->IsShowMouseMenu()) {
6197 CloseSelectOverlay();
6198 } else if (newWidth != prevWidth || newHeight != prevHeight) {
6199 DelayProcessOverlay({ .menuIsShow = false });
6200 }
6201 selectOverlay_->RemoveAvoidKeyboardCallback();
6202 }
6203 auto tmpHost = GetHost();
6204 CHECK_NULL_VOID(tmpHost);
6205 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
6206 UpdateCaretInfoToController(true);
6207 if (magnifierController_->GetShowMagnifier()) {
6208 magnifierController_->RemoveMagnifierFrameNode();
6209 }
6210 }
6211
HandleSurfacePositionChanged(int32_t posX,int32_t posY)6212 void TextFieldPattern::HandleSurfacePositionChanged(int32_t posX, int32_t posY)
6213 {
6214 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "Textfield handleSurface position change, posX %{public}d, posY %{public}d",
6215 posX, posY);
6216 UpdateCaretInfoToController();
6217 }
6218
InitSurfaceChangedCallback()6219 void TextFieldPattern::InitSurfaceChangedCallback()
6220 {
6221 auto host = GetHost();
6222 CHECK_NULL_VOID(host);
6223 FREE_NODE_CHECK(host, InitSurfaceChangedCallback); // call InitSurfaceChangedCallbackMultiThread() by multi thread
6224 auto pipeline = host->GetContext();
6225 CHECK_NULL_VOID(pipeline);
6226 if (!HasSurfaceChangedCallback()) {
6227 auto callbackId = pipeline->RegisterSurfaceChangedCallback(
6228 [weak = WeakClaim(this)](int32_t newWidth, int32_t newHeight, int32_t prevWidth, int32_t prevHeight,
6229 WindowSizeChangeReason type) {
6230 auto pattern = weak.Upgrade();
6231 if (pattern) {
6232 pattern->HandleSurfaceChanged(newWidth, newHeight, prevWidth, prevHeight);
6233 }
6234 });
6235 UpdateSurfaceChangedCallbackId(callbackId);
6236 }
6237 }
6238
InitSurfacePositionChangedCallback()6239 void TextFieldPattern::InitSurfacePositionChangedCallback()
6240 {
6241 auto host = GetHost();
6242 CHECK_NULL_VOID(host);
6243 FREE_NODE_CHECK(host,
6244 InitSurfacePositionChangedCallback); // call InitSurfacePositionChangedCallbackMultiThread() by multi thread
6245 auto pipeline = host->GetContext();
6246 CHECK_NULL_VOID(pipeline);
6247 if (!HasSurfacePositionChangedCallback()) {
6248 auto callbackId =
6249 pipeline->RegisterSurfacePositionChangedCallback([weak = WeakClaim(this)](int32_t posX, int32_t posY) {
6250 auto pattern = weak.Upgrade();
6251 if (pattern) {
6252 pattern->HandleSurfacePositionChanged(posX, posY);
6253 }
6254 });
6255 UpdateSurfacePositionChangedCallbackId(callbackId);
6256 }
6257 }
6258
HandleOnDelete(bool backward)6259 void TextFieldPattern::HandleOnDelete(bool backward)
6260 {
6261 if (backward) {
6262 #if defined(PREVIEW)
6263 DeleteForward(1);
6264 #else
6265 DeleteBackward(1);
6266 #endif
6267 } else {
6268 #if defined(PREVIEW)
6269 DeleteBackward(1);
6270 #else
6271 DeleteForward(1);
6272 #endif
6273 }
6274 }
6275
HandleOnDeleteComb(bool backward)6276 bool TextFieldPattern::HandleOnDeleteComb(bool backward)
6277 {
6278 if (backward) {
6279 DeleteBackwardWord(); // LTR is left word,RTL is right word
6280 } else {
6281 DeleteForwardWord(); // LTR is right word,RTL is left word
6282 }
6283 return true;
6284 }
6285
DeleteBackwardWord()6286 void TextFieldPattern::DeleteBackwardWord()
6287 {
6288 int32_t originCaretPosition = selectController_->GetCaretIndex();
6289 int32_t textLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
6290 int32_t leftWordLength = GetWordLength(originCaretPosition, 0, false);
6291 if (leftWordLength < 0) {
6292 // delete 1 char
6293 leftWordLength = 1;
6294 }
6295 if (leftWordLength > textLength || selectController_->GetCaretIndex() - leftWordLength < 0) {
6296 // delete left
6297 leftWordLength = std::max(1, originCaretPosition);
6298 }
6299 DeleteBackward(leftWordLength);
6300 }
6301
DeleteForwardWord()6302 void TextFieldPattern::DeleteForwardWord()
6303 {
6304 int32_t originCaretPosition = selectController_->GetCaretIndex();
6305 int32_t textLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
6306 int32_t rightWordLength = GetWordLength(originCaretPosition, 1, false);
6307 if (rightWordLength < 0) {
6308 // delete 1 char
6309 rightWordLength = 1;
6310 }
6311 if (rightWordLength > textLength || rightWordLength + selectController_->GetCaretIndex() > textLength) {
6312 // delete right
6313 rightWordLength = std::max(1, textLength - originCaretPosition);
6314 }
6315 DeleteForward(rightWordLength);
6316 }
6317
HandleOnPageUp()6318 void TextFieldPattern::HandleOnPageUp()
6319 {
6320 if (!IsTextArea()) {
6321 return;
6322 }
6323 auto border = GetBorderWidthProperty();
6324 float frameRectHeight = std::max(frameRect_.Height(), PreferredLineHeight());
6325 float maxFrameHeight =
6326 frameRectHeight - GetPaddingTop() - GetPaddingBottom() - GetBorderTop(border) - GetBorderBottom(border);
6327 OnScrollCallback(maxFrameHeight, SCROLL_FROM_JUMP);
6328 auto caretRectOffset = selectController_->GetCaretRect().GetOffset();
6329 Offset offset(caretRectOffset.GetX(), GetPaddingTop() + GetBorderTop(border));
6330 selectController_->UpdateCaretInfoByOffset(offset, true);
6331 OnCursorMoveDone(TextAffinity::DOWNSTREAM);
6332 }
6333
HandleOnPageDown()6334 void TextFieldPattern::HandleOnPageDown()
6335 {
6336 if (!IsTextArea()) {
6337 return;
6338 }
6339 auto border = GetBorderWidthProperty();
6340 float frameRectHeight = std::max(frameRect_.Height(), PreferredLineHeight());
6341 float maxFrameHeight =
6342 frameRectHeight - GetPaddingTop() - GetPaddingBottom() - GetBorderTop(border) - GetBorderBottom(border);
6343 OnScrollCallback(-maxFrameHeight, SCROLL_FROM_JUMP);
6344 auto caretRectOffset = selectController_->GetCaretRect().GetOffset();
6345 Offset offset(caretRectOffset.GetX(), maxFrameHeight);
6346 selectController_->UpdateCaretInfoByOffset(offset, true);
6347 OnCursorMoveDone(TextAffinity::DOWNSTREAM);
6348 }
6349
GetEmojiSubStringRange(int32_t & start,int32_t & end)6350 void TextFieldPattern::GetEmojiSubStringRange(int32_t& start, int32_t& end)
6351 {
6352 TextEmojiSubStringRange range = TextEmojiProcessor::CalSubU16stringRange(
6353 start, end - start, GetTextUtf16Value(), false, true);
6354 start = range.startIndex;
6355 end = range.endIndex;
6356 }
6357
DeleteBackward(int32_t length)6358 void TextFieldPattern::DeleteBackward(int32_t length)
6359 {
6360 CHECK_NULL_VOID(!IsDragging());
6361 CHECK_NULL_VOID(focusIndex_ == FocuseIndex::TEXT);
6362 ResetObscureTickCountDown();
6363 if (IsSelected()) {
6364 auto start = selectController_->GetStartIndex();
6365 auto end = selectController_->GetEndIndex();
6366 DeleteTextRange(start, end, TextDeleteDirection::BACKWARD);
6367 return;
6368 }
6369 if (selectController_->GetCaretIndex() <= 0) {
6370 auto isDelete = BeforeIMEDeleteValue(u"", TextDeleteDirection::BACKWARD, 0);
6371 CHECK_NULL_VOID(isDelete);
6372 AfterIMEDeleteValue(u"", TextDeleteDirection::BACKWARD);
6373 return;
6374 }
6375 inputOperations_.emplace(InputOperation::DELETE_BACKWARD);
6376 deleteBackwardOperations_.emplace(length);
6377 CloseSelectOverlay();
6378 ScrollToSafeArea();
6379 auto tmpHost = GetHost();
6380 CHECK_NULL_VOID(tmpHost);
6381 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
6382 }
6383
DeleteBackwardOperation(int32_t length)6384 void TextFieldPattern::DeleteBackwardOperation(int32_t length)
6385 {
6386 int32_t idx = selectController_->GetCaretIndex();
6387 auto willDeleteLength = contentController_->GetDeleteLength(idx, length, true);
6388 auto value = contentController_->GetSelectedValue(idx - willDeleteLength, idx);
6389 auto isDelete = BeforeIMEDeleteValue(value, TextDeleteDirection::BACKWARD, idx);
6390 CHECK_NULL_VOID(isDelete);
6391 auto oldContent = contentController_->GetTextUtf16Value();
6392 int32_t count = contentController_->Delete(selectController_->GetCaretIndex(), length, true);
6393 auto isOnWillChange = OnWillChangePreDelete(oldContent, std::max(idx - count, 0), idx);
6394 if (!isOnWillChange) {
6395 contentController_->SetTextValue(oldContent);
6396 return;
6397 }
6398 selectController_->UpdateCaretIndex(std::max(idx - count, 0));
6399 if (GetIsPreviewText()) {
6400 UpdatePreviewIndex(GetPreviewTextStart(), GetPreviewTextEnd() - length);
6401 }
6402 AfterIMEDeleteValue(value, TextDeleteDirection::BACKWARD);
6403 StartTwinkling();
6404 focusIndex_ = FocuseIndex::TEXT;
6405 UpdateEditingValueToRecord();
6406 }
6407
DeleteForwardOperation(int32_t length)6408 void TextFieldPattern::DeleteForwardOperation(int32_t length)
6409 {
6410 auto caretIndex = selectController_->GetCaretIndex();
6411 auto willDeleteLength = contentController_->GetDeleteLength(caretIndex, length, false);
6412 auto value = contentController_->GetSelectedValue(caretIndex, caretIndex + willDeleteLength);
6413 auto isDelete = BeforeIMEDeleteValue(value, TextDeleteDirection::FORWARD, caretIndex);
6414 CHECK_NULL_VOID(isDelete);
6415 ResetObscureTickCountDown();
6416 auto oldContent = contentController_->GetTextUtf16Value();
6417 contentController_->Delete(caretIndex, length, false);
6418 if (GetIsPreviewText()) {
6419 UpdatePreviewIndex(GetPreviewTextStart(), GetPreviewTextEnd() - length);
6420 }
6421 auto isOnWillChange = OnWillChangePreDelete(oldContent, caretIndex, caretIndex + willDeleteLength);
6422 if (!isOnWillChange) {
6423 contentController_->SetTextValue(oldContent);
6424 return;
6425 }
6426 AfterIMEDeleteValue(value, TextDeleteDirection::FORWARD);
6427 StartTwinkling();
6428 focusIndex_ = FocuseIndex::TEXT;
6429 UpdateEditingValueToRecord();
6430 }
6431
DeleteForward(int32_t length)6432 void TextFieldPattern::DeleteForward(int32_t length)
6433 {
6434 CHECK_NULL_VOID(!IsDragging());
6435 CHECK_NULL_VOID(focusIndex_ == FocuseIndex::TEXT);
6436 if (IsSelected()) {
6437 auto start = selectController_->GetStartIndex();
6438 auto end = selectController_->GetEndIndex();
6439 DeleteRange(start, end);
6440 return;
6441 }
6442 auto contentLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
6443 if (selectController_->GetCaretIndex() >= contentLength) {
6444 auto isDelete = BeforeIMEDeleteValue(u"", TextDeleteDirection::FORWARD, contentLength);
6445 CHECK_NULL_VOID(isDelete);
6446 AfterIMEDeleteValue(u"", TextDeleteDirection::FORWARD);
6447 return;
6448 }
6449 inputOperations_.emplace(InputOperation::DELETE_FORWARD);
6450 deleteForwardOperations_.emplace(length);
6451 CloseSelectOverlay();
6452 auto tmpHost = GetHost();
6453 CHECK_NULL_VOID(tmpHost);
6454 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
6455 }
6456
BeforeIMEDeleteValue(const std::u16string & deleteValue,TextDeleteDirection direction,int32_t offset)6457 bool TextFieldPattern::BeforeIMEDeleteValue(
6458 const std::u16string& deleteValue, TextDeleteDirection direction, int32_t offset)
6459 {
6460 auto host = GetHost();
6461 CHECK_NULL_RETURN(host, true);
6462 auto eventHub = host->GetOrCreateEventHub<TextFieldEventHub>();
6463 CHECK_NULL_RETURN(eventHub, true);
6464 DeleteValueInfo deleteValueInfo;
6465 deleteValueInfo.deleteOffset = offset;
6466 deleteValueInfo.deleteValue = deleteValue;
6467 deleteValueInfo.direction = direction;
6468 return eventHub->FireOnWillDeleteEvent(deleteValueInfo);
6469 }
6470
AfterIMEDeleteValue(const std::u16string & deleteValue,TextDeleteDirection direction)6471 void TextFieldPattern::AfterIMEDeleteValue(const std::u16string& deleteValue, TextDeleteDirection direction)
6472 {
6473 auto host = GetHost();
6474 CHECK_NULL_VOID(host);
6475 auto eventHub = host->GetOrCreateEventHub<TextFieldEventHub>();
6476 CHECK_NULL_VOID(eventHub);
6477 DeleteValueInfo deleteValueInfo;
6478 deleteValueInfo.deleteOffset = selectController_->GetCaretIndex();
6479 deleteValueInfo.deleteValue = deleteValue;
6480 deleteValueInfo.direction = direction;
6481 return eventHub->FireOnDidDeleteValueEvent(deleteValueInfo);
6482 }
6483
GetLeftTextOfCursor(int32_t number)6484 std::u16string TextFieldPattern::GetLeftTextOfCursor(int32_t number)
6485 {
6486 auto start = selectController_->GetCaretIndex();
6487 if (IsSelected()) {
6488 start = selectController_->GetStartIndex();
6489 }
6490 return contentController_->GetSelectedValue(start - number, start);
6491 }
6492
GetRightTextOfCursor(int32_t number)6493 std::u16string TextFieldPattern::GetRightTextOfCursor(int32_t number)
6494 {
6495 auto end = selectController_->GetCaretIndex();
6496 if (IsSelected()) {
6497 end = selectController_->GetEndIndex();
6498 }
6499 return contentController_->GetSelectedValue(end, end + number);
6500 }
6501
GetTextIndexAtCursor()6502 int32_t TextFieldPattern::GetTextIndexAtCursor()
6503 {
6504 return selectController_->GetCaretIndex();
6505 }
6506
AfterSelection()6507 void TextFieldPattern::AfterSelection()
6508 {
6509 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "Selection %{public}s, caret position %{public}d",
6510 selectController_->ToString().c_str(), selectController_->GetCaretIndex());
6511 ResetObscureTickCountDown();
6512 auto tmpHost = GetHost();
6513 CHECK_NULL_VOID(tmpHost);
6514 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
6515 showSelect_ = IsSelected();
6516 UpdateCaretInfoToController();
6517 }
6518
HandleSelectionUp()6519 void TextFieldPattern::HandleSelectionUp()
6520 {
6521 if (!IsSelected()) {
6522 UpdateSelection(selectController_->GetCaretIndex());
6523 }
6524 auto newOffsetY = selectController_->GetCaretRect().GetY() - PreferredLineHeight() * 0.5 - textRect_.GetY();
6525 if (GreatOrEqual(newOffsetY, 0.0)) {
6526 OffsetF originCaretPosition;
6527 auto caretXPosition = GetOriginCaretPosition(originCaretPosition) &&
6528 GreatNotEqual(selectController_->GetCaretRect().GetX() - contentRect_.GetX(), 0) ? // handle when line head
6529 originCaretPosition.GetX() : selectController_->GetCaretRect().GetX();
6530 auto offset = Offset(caretXPosition - contentRect_.GetX(), newOffsetY);
6531 auto index = paragraph_->GetGlyphIndexByCoordinate(offset);
6532 bool isAtLineBegin = false;
6533 LineMetrics lineMetrics;
6534 if (paragraph_->GetLineMetricsByCoordinate(offset, lineMetrics) && LessOrEqual(offset.GetX(), lineMetrics.x)) {
6535 isAtLineBegin = true;
6536 }
6537 selectController_->MoveSecondHandleByKeyBoard(index, isAtLineBegin ?
6538 std::make_optional<TextAffinity>(TextAffinity::DOWNSTREAM) : std::nullopt);
6539 } else {
6540 selectController_->MoveSecondHandleByKeyBoard(0);
6541 }
6542 AfterSelection();
6543 }
6544
HandleSelectionDown()6545 void TextFieldPattern::HandleSelectionDown()
6546 {
6547 if (!IsSelected()) {
6548 UpdateSelection(selectController_->GetCaretIndex());
6549 }
6550 auto newOffsetY = selectController_->GetCaretRect().GetY() + PreferredLineHeight() * 1.5 - textRect_.GetY();
6551 if (LessOrEqual(newOffsetY, textRect_.Height())) {
6552 OffsetF originCaretPosition;
6553 auto caretXPosition = GetOriginCaretPosition(originCaretPosition) ?
6554 originCaretPosition.GetX() : selectController_->GetCaretRect().GetX();
6555 selectController_->MoveSecondHandleByKeyBoard(paragraph_->GetGlyphIndexByCoordinate(
6556 Offset(caretXPosition - contentRect_.GetX(), newOffsetY)), TextAffinity::DOWNSTREAM);
6557 } else {
6558 selectController_->MoveSecondHandleByKeyBoard(
6559 static_cast<int32_t>(contentController_->GetTextUtf16Value().length()));
6560 }
6561 AfterSelection();
6562 }
6563
HandleSelectionLeft()6564 void TextFieldPattern::HandleSelectionLeft()
6565 {
6566 if (!IsSelected()) {
6567 if (selectController_->GetCaretIndex() == 0) {
6568 return;
6569 }
6570 UpdateSelection(selectController_->GetCaretIndex());
6571 selectController_->MoveSecondHandleByKeyBoard(
6572 selectController_->GetSecondHandleIndex() -
6573 GetGraphemeClusterLength(contentController_->GetTextUtf16Value(), selectController_->GetCaretIndex(),
6574 true));
6575 } else {
6576 selectController_->MoveSecondHandleByKeyBoard(selectController_->GetSecondHandleIndex() -
6577 GetGraphemeClusterLength(contentController_->GetTextUtf16Value(), selectController_->GetSecondHandleIndex(),
6578 true));
6579 }
6580 AfterSelection();
6581 }
6582
HandleSelectionLeftWord()6583 void TextFieldPattern::HandleSelectionLeftWord()
6584 {
6585 if (selectController_->GetCaretIndex() == 0) {
6586 return;
6587 }
6588 int32_t textLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
6589 int32_t leftWordLength = GetWordLength(selectController_->GetCaretIndex(), 0);
6590 if (leftWordLength < 0 || leftWordLength > textLength || selectController_->GetCaretIndex() - leftWordLength < 0) {
6591 return;
6592 }
6593 if (!IsSelected()) {
6594 UpdateSelection(selectController_->GetCaretIndex());
6595 selectController_->MoveSecondHandleByKeyBoard(selectController_->GetSecondHandleIndex() - leftWordLength);
6596 } else {
6597 selectController_->MoveSecondHandleByKeyBoard(selectController_->GetSecondHandleIndex() - leftWordLength);
6598 }
6599 AfterSelection();
6600 }
6601
HandleSelectionLineBegin()6602 void TextFieldPattern::HandleSelectionLineBegin()
6603 {
6604 if (selectController_->GetCaretIndex() == 0) {
6605 return;
6606 }
6607 int32_t textLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
6608 int32_t lineBeginPosition = GetLineBeginPosition(selectController_->GetCaretIndex());
6609 if (lineBeginPosition < 0 || lineBeginPosition > textLength) {
6610 return;
6611 }
6612 if (!IsSelected()) {
6613 UpdateSelection(selectController_->GetCaretIndex());
6614 selectController_->MoveSecondHandleByKeyBoard(lineBeginPosition);
6615 } else {
6616 selectController_->MoveSecondHandleByKeyBoard(lineBeginPosition);
6617 }
6618 AfterSelection();
6619 }
6620
HandleSelectionHome()6621 void TextFieldPattern::HandleSelectionHome()
6622 {
6623 if (selectController_->GetCaretIndex() == 0) {
6624 return;
6625 }
6626 if (!IsSelected()) {
6627 UpdateSelection(selectController_->GetCaretIndex());
6628 selectController_->MoveSecondHandleByKeyBoard(0);
6629 } else {
6630 selectController_->MoveSecondHandleByKeyBoard(0);
6631 }
6632 AfterSelection();
6633 }
6634
HandleSelectionParagraghBegin()6635 void TextFieldPattern::HandleSelectionParagraghBegin()
6636 {
6637 CHECK_NULL_VOID(selectController_);
6638 if (selectController_->GetCaretIndex() == 0) {
6639 return;
6640 }
6641 auto originCaretPosition = selectController_->GetCaretIndex();
6642 auto newPos = GetLineBeginPosition(originCaretPosition, false);
6643 if (newPos == originCaretPosition && originCaretPosition > 0) {
6644 newPos = GetLineBeginPosition(originCaretPosition - 1, false);
6645 }
6646 if (!IsSelected()) {
6647 UpdateSelection(selectController_->GetCaretIndex());
6648 selectController_->MoveSecondHandleByKeyBoard(newPos);
6649 } else {
6650 selectController_->MoveSecondHandleByKeyBoard(newPos);
6651 }
6652 AfterSelection();
6653 }
6654
HandleSelectionRight()6655 void TextFieldPattern::HandleSelectionRight()
6656 {
6657 // if currently not in select mode, reset baseOffset and move destinationOffset and caret position
6658 if (!IsSelected()) {
6659 if (selectController_->GetCaretIndex() ==
6660 static_cast<int32_t>(contentController_->GetTextUtf16Value().length())) {
6661 return;
6662 }
6663 UpdateSelection(selectController_->GetCaretIndex());
6664 selectController_->MoveSecondHandleByKeyBoard(
6665 selectController_->GetSecondHandleIndex() +
6666 GetGraphemeClusterLength(contentController_->GetTextUtf16Value(),
6667 selectController_->GetSecondHandleIndex()));
6668 } else {
6669 // if currently not in select mode, move destinationOffset and caret position only
6670 selectController_->MoveSecondHandleByKeyBoard(
6671 selectController_->GetSecondHandleIndex() +
6672 GetGraphemeClusterLength(contentController_->GetTextUtf16Value(),
6673 selectController_->GetSecondHandleIndex()));
6674 }
6675 AfterSelection();
6676 }
6677
HandleSelectionRightWord()6678 void TextFieldPattern::HandleSelectionRightWord()
6679 {
6680 int32_t textLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
6681 if (selectController_->GetCaretIndex() == textLength) {
6682 return;
6683 }
6684 int32_t rightWordLength = GetWordLength(selectController_->GetCaretIndex(), 1);
6685 if (rightWordLength < 0 || rightWordLength > textLength ||
6686 rightWordLength + selectController_->GetCaretIndex() > textLength) {
6687 return;
6688 }
6689 if (!IsSelected()) {
6690 UpdateSelection(selectController_->GetCaretIndex());
6691 selectController_->MoveSecondHandleByKeyBoard(selectController_->GetSecondHandleIndex() + rightWordLength);
6692 } else {
6693 selectController_->MoveSecondHandleByKeyBoard(selectController_->GetSecondHandleIndex() + rightWordLength);
6694 AfterSelection();
6695 }
6696 }
6697
HandleSelectionLineEnd()6698 void TextFieldPattern::HandleSelectionLineEnd()
6699 {
6700 int32_t textLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
6701 if (selectController_->GetCaretIndex() == textLength) {
6702 return;
6703 }
6704 int32_t lineEndPosition = GetLineEndPosition(selectController_->GetCaretIndex());
6705 if (lineEndPosition < 0 || lineEndPosition > textLength) {
6706 return;
6707 }
6708 if (!IsSelected()) {
6709 UpdateSelection(selectController_->GetCaretIndex());
6710 selectController_->MoveSecondHandleByKeyBoard(lineEndPosition);
6711 } else {
6712 selectController_->MoveSecondHandleByKeyBoard(lineEndPosition);
6713 }
6714 AfterSelection();
6715 }
6716
HandleSelectionEnd()6717 void TextFieldPattern::HandleSelectionEnd()
6718 {
6719 // shift end, select to the end of current line
6720 int32_t endPos = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
6721 if (selectController_->GetCaretIndex() == endPos) {
6722 return;
6723 }
6724 if (!IsSelected()) {
6725 UpdateSelection(selectController_->GetCaretIndex());
6726 selectController_->MoveSecondHandleByKeyBoard(endPos);
6727 } else {
6728 selectController_->MoveSecondHandleByKeyBoard(endPos);
6729 }
6730 AfterSelection();
6731 }
6732
HandleSelectionParagraghEnd()6733 void TextFieldPattern::HandleSelectionParagraghEnd()
6734 {
6735 CHECK_NULL_VOID(selectController_);
6736 if (selectController_->GetCaretIndex() == static_cast<int32_t>(contentController_->GetTextUtf16Value().length())) {
6737 return;
6738 }
6739 auto originCaretPosition = selectController_->GetCaretIndex();
6740 auto newPos = GetLineEndPosition(originCaretPosition, false) + ENTER_OFFSET;
6741 if (!IsSelected()) {
6742 UpdateSelection(selectController_->GetCaretIndex());
6743 selectController_->MoveSecondHandleByKeyBoard(newPos);
6744 } else {
6745 selectController_->MoveSecondHandleByKeyBoard(newPos);
6746 }
6747 AfterSelection();
6748 }
6749
SetCaretPosition(int32_t position,bool moveContent)6750 void TextFieldPattern::SetCaretPosition(int32_t position, bool moveContent)
6751 {
6752 auto host = GetHost();
6753 FREE_NODE_CHECK(host, SetCaretPosition, position, moveContent); // call SetCaretPositionMultiThread() by multi thread
6754 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "Set caret position to %{public}d", position);
6755 selectController_->MoveCaretToContentRect(position, TextAffinity::DOWNSTREAM, true, moveContent);
6756 UpdateCaretInfoToController();
6757 if (HasFocus() && !magnifierController_->GetShowMagnifier()) {
6758 StartTwinkling();
6759 }
6760 CloseSelectOverlay();
6761 CancelDelayProcessOverlay();
6762 TriggerAvoidOnCaretChange();
6763 auto tmpHost = GetHost();
6764 CHECK_NULL_VOID(tmpHost);
6765 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
6766 }
6767
SetCaretOffset(int32_t caretPostion)6768 bool TextFieldPattern::SetCaretOffset(int32_t caretPostion)
6769 {
6770 SetCaretPosition(caretPostion);
6771 return true;
6772 }
6773
SetSelectionFlag(int32_t selectionStart,int32_t selectionEnd,const std::optional<SelectionOptions> & options,bool isForward)6774 void TextFieldPattern::SetSelectionFlag(
6775 int32_t selectionStart, int32_t selectionEnd, const std::optional<SelectionOptions>& options, bool isForward)
6776 {
6777 auto host = GetHost();
6778 FREE_NODE_CHECK(host, SetSelectionFlag, selectionStart,
6779 selectionEnd, options, isForward); // call SetSelectionFlagMultiThread() by multi thread
6780 if (!HasFocus() || GetIsPreviewText()) {
6781 return;
6782 }
6783 auto length = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
6784 selectionStart = std::clamp(selectionStart, 0, length);
6785 selectionEnd = std::clamp(selectionEnd, 0, length);
6786 moveCaretState_.isTouchCaret = false;
6787 bool isShowMenu = selectOverlay_->IsCurrentMenuVisibile();
6788 isTouchPreviewText_ = false;
6789 if (selectionStart == selectionEnd) {
6790 selectController_->MoveCaretToContentRect(selectionEnd, TextAffinity::DOWNSTREAM);
6791 StartTwinkling();
6792 } else {
6793 cursorVisible_ = false;
6794 showSelect_ = true;
6795 HandleSetSelection(selectionStart, selectionEnd, false);
6796 if (isForward) {
6797 selectController_->MoveSecondHandleToContentRect(selectionEnd);
6798 selectController_->MoveFirstHandleToContentRect(selectionStart, false);
6799 } else {
6800 selectController_->MoveFirstHandleToContentRect(selectionStart);
6801 selectController_->MoveSecondHandleToContentRect(selectionEnd);
6802 }
6803 }
6804 if (RequestKeyboardNotByFocusSwitch(RequestKeyboardReason::SET_SELECTION)) {
6805 NotifyOnEditChanged(true);
6806 }
6807 SetIsSingleHandle(!IsSelected());
6808 if (!IsShowHandle()) {
6809 CloseSelectOverlay(true);
6810 } else {
6811 isShowMenu = IsShowMenu(options, isShowMenu);
6812 if (!isShowMenu && IsUsingMouse()) {
6813 CloseSelectOverlay();
6814 } else {
6815 ProcessOverlay({ .menuIsShow = isShowMenu, .animation = true });
6816 }
6817 }
6818 TriggerAvoidWhenCaretGoesDown();
6819 CHECK_NULL_VOID(host);
6820 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
6821 }
6822
SetSelection(int32_t start,int32_t end,const std::optional<SelectionOptions> & options,bool isForward)6823 void TextFieldPattern::SetSelection(int32_t start, int32_t end,
6824 const std::optional<SelectionOptions>& options, bool isForward)
6825 {
6826 SetSelectionFlag(start, end, options, isForward);
6827 }
6828
IsShowMenu(const std::optional<SelectionOptions> & options,bool defaultValue)6829 bool TextFieldPattern::IsShowMenu(const std::optional<SelectionOptions>& options, bool defaultValue)
6830 {
6831 if (!options.has_value()) {
6832 return false;
6833 }
6834 if (options.value().menuPolicy == MenuPolicy::HIDE) {
6835 return false;
6836 }
6837 if (options.value().menuPolicy == MenuPolicy::SHOW) {
6838 return true;
6839 }
6840 return defaultValue;
6841 }
6842
OnBackPressed()6843 bool TextFieldPattern::OnBackPressed()
6844 {
6845 auto tmpHost = GetHost();
6846 CHECK_NULL_RETURN(tmpHost, false);
6847 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "%{public}d receives back press event, %{public}d",
6848 tmpHost->GetId(), isCustomKeyboardAttached_);
6849 if (SelectOverlayIsOn()) {
6850 selectController_->UpdateCaretIndex(
6851 std::max(selectController_->GetFirstHandleIndex(), selectController_->GetSecondHandleIndex()));
6852 bool closeKeyboard = !selectOverlay_->IsCurrentMenuVisibile();
6853 CloseSelectOverlay();
6854 StartTwinkling();
6855 if (!closeKeyboard) {
6856 return IsStopBackPress();
6857 }
6858 }
6859 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
6860 if (!imeShown_ && !isCustomKeyboardAttached_) {
6861 #else
6862 if (!isCustomKeyboardAttached_) {
6863 #endif
6864 return false;
6865 }
6866
6867 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
6868 HandleCloseKeyboard(true);
6869 #if defined(ANDROID_PLATFORM)
6870 return false;
6871 #else
6872 return IsStopBackPress();
6873 #endif
6874 }
6875
6876 bool TextFieldPattern::IsStopBackPress() const
6877 {
6878 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
6879 CHECK_NULL_RETURN(layoutProperty, true);
6880 return layoutProperty->GetStopBackPressValue(true);
6881 }
6882
6883 void TextFieldPattern::HandleCloseKeyboard(bool forceClose)
6884 {
6885 if (independentControlKeyboard_) {
6886 CloseKeyboard(true, false);
6887 } else {
6888 CloseKeyboard(forceClose);
6889 if (HasFocus()) {
6890 FocusHub::LostFocusToViewRoot();
6891 }
6892 }
6893 }
6894
6895 int32_t TextFieldPattern::GetNakedCharPosition() const
6896 {
6897 if (IsTextArea() || !IsInPasswordMode() || obscureTickCountDown_ <= 0 || !GetTextObscured()) {
6898 return -1;
6899 }
6900 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
6901 CHECK_NULL_RETURN(layoutProperty, -1);
6902 auto content = contentController_->GetTextUtf16Value();
6903 if (content.empty()) {
6904 return -1;
6905 }
6906 return nakedCharPosition_;
6907 }
6908
6909 std::string TextFieldPattern::TextInputTypeToString() const
6910 {
6911 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
6912 CHECK_NULL_RETURN(layoutProperty, "");
6913 switch (layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED)) {
6914 case TextInputType::NUMBER:
6915 return IsTextArea() ? "TextAreaType.NUMBER" : "InputType.Number";
6916 case TextInputType::EMAIL_ADDRESS:
6917 return IsTextArea() ? "TextAreaType.EMAIL" : "InputType.Email";
6918 case TextInputType::PHONE:
6919 return IsTextArea() ? "TextAreaType.PHONE_NUMBER" : "InputType.PhoneNumber";
6920 case TextInputType::URL:
6921 return IsTextArea() ? "TextAreaType.URL" : "InputType.URL";
6922 case TextInputType::VISIBLE_PASSWORD:
6923 return "InputType.Password";
6924 case TextInputType::USER_NAME:
6925 return "InputType.USER_NAME";
6926 case TextInputType::NEW_PASSWORD:
6927 return "InputType.NEW_PASSWORD";
6928 case TextInputType::NUMBER_PASSWORD:
6929 return "InputType.NUMBER_PASSWORD";
6930 case TextInputType::NUMBER_DECIMAL:
6931 return IsTextArea() ? "TextAreaType.NUMBER_DECIMAL" : "InputType.NUMBER_DECIMAL";
6932 case TextInputType::ONE_TIME_CODE:
6933 return IsTextArea() ? "TextAreaType.ONE_TIME_CODE" : "InputType.ONE_TIME_CODE";
6934 default:
6935 return isTextInput_ ? "InputType.Normal" : "TextAreaType.NORMAL";
6936 }
6937 }
6938
6939 std::string TextFieldPattern::TextContentTypeToString() const
6940 {
6941 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
6942 CHECK_NULL_RETURN(layoutProperty, "");
6943 auto contentType = layoutProperty->GetTextContentTypeValue(TextContentType::UNSPECIFIED);
6944 if (contentTypeMap_.find(contentType) != contentTypeMap_.end()) {
6945 return contentTypeMap_[contentType].second;
6946 }
6947 return contentTypeMap_[TextContentType::UNSPECIFIED].second;
6948 }
6949
6950 std::string TextFieldPattern::TextInputActionToString() const
6951 {
6952 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
6953 CHECK_NULL_RETURN(layoutProperty, "");
6954 switch (GetTextInputActionValue(GetDefaultTextInputAction())) {
6955 case TextInputAction::GO:
6956 return "EnterKeyType.Go";
6957 case TextInputAction::SEARCH:
6958 return "EnterKeyType.Search";
6959 case TextInputAction::SEND:
6960 return "EnterKeyType.Send";
6961 case TextInputAction::NEXT:
6962 return "EnterKeyType.Next";
6963 default:
6964 return "EnterKeyType.Done";
6965 }
6966 }
6967
6968 std::string TextFieldPattern::AutoCapTypeToString() const
6969 {
6970 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
6971 CHECK_NULL_RETURN(layoutProperty, "");
6972 switch (GetAutoCapitalizationModeValue(AutoCapitalizationMode::NONE)) {
6973 case AutoCapitalizationMode::NONE:
6974 return "AutoCapitalizationMode.NONE";
6975 case AutoCapitalizationMode::WORDS:
6976 return "AutoCapitalizationMode.WORDS";
6977 case AutoCapitalizationMode::SENTENCES:
6978 return "AutoCapitalizationMode.SENTENCES";
6979 case AutoCapitalizationMode::ALL_CHARACTERS:
6980 return "AutoCapitalizationMode.ALL_CHARACTERS";
6981 default:
6982 return "AutoCapitalizationMode.NONE";
6983 }
6984 }
6985
6986 std::string TextFieldPattern::GetPlaceholderFont() const
6987 {
6988 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
6989 CHECK_NULL_RETURN(layoutProperty, "");
6990 auto theme = GetTheme();
6991 CHECK_NULL_RETURN(theme, "");
6992 auto jsonValue = JsonUtil::Create(true);
6993 if (layoutProperty->GetPlaceholderItalicFontStyle().value_or(Ace::FontStyle::NORMAL) == Ace::FontStyle::NORMAL) {
6994 jsonValue->Put("style", "FontStyle.Normal");
6995 } else {
6996 jsonValue->Put("style", "FontStyle.Italic");
6997 }
6998 // placeholder font size not exist in theme, use normal font size by default
6999 if (!layoutProperty->GetPlaceholderFontSize()) {
7000 jsonValue->Put("size", GetFontSize().c_str());
7001 } else {
7002 jsonValue->Put("size", layoutProperty->GetPlaceholderFontSize()->ToString().c_str());
7003 }
7004 auto weight = layoutProperty->GetPlaceholderFontWeightValue(theme->GetFontWeight());
7005 switch (weight) {
7006 case FontWeight::W100:
7007 jsonValue->Put("weight", "100");
7008 break;
7009 case FontWeight::W200:
7010 jsonValue->Put("weight", "200");
7011 break;
7012 case FontWeight::W300:
7013 jsonValue->Put("weight", "300");
7014 break;
7015 case FontWeight::W400:
7016 jsonValue->Put("weight", "400");
7017 break;
7018 case FontWeight::W500:
7019 jsonValue->Put("weight", "500");
7020 break;
7021 case FontWeight::W600:
7022 jsonValue->Put("weight", "600");
7023 break;
7024 case FontWeight::W700:
7025 jsonValue->Put("weight", "700");
7026 break;
7027 case FontWeight::W800:
7028 jsonValue->Put("weight", "800");
7029 break;
7030 case FontWeight::W900:
7031 jsonValue->Put("weight", "900");
7032 break;
7033 default:
7034 jsonValue->Put("fontWeight", V2::ConvertWrapFontWeightToStirng(weight).c_str());
7035 }
7036 auto family = layoutProperty->GetPlaceholderFontFamilyValue({ "sans-serif" });
7037 std::string jsonFamily = ConvertFontFamily(family);
7038 jsonValue->Put("fontFamily", jsonFamily.c_str());
7039 return jsonValue->ToString();
7040 }
7041
7042 RefPtr<TextFieldTheme> TextFieldPattern::GetTheme() const
7043 {
7044 if (textFieldTheme_.Upgrade()) {
7045 return textFieldTheme_.Upgrade();
7046 }
7047 auto tmpHost = GetHost();
7048 CHECK_NULL_RETURN(tmpHost, nullptr);
7049 auto context = tmpHost->GetContext();
7050 CHECK_NULL_RETURN(context, nullptr);
7051 auto theme = context->GetTheme<TextFieldTheme>(tmpHost->GetThemeScopeId());
7052 return theme;
7053 }
7054
7055 void TextFieldPattern::InitTheme()
7056 {
7057 auto tmpHost = GetHost();
7058 CHECK_NULL_VOID(tmpHost);
7059 auto context = tmpHost->GetContext();
7060 CHECK_NULL_VOID(context);
7061 auto theme = context->GetTheme<TextFieldTheme>(tmpHost->GetThemeScopeId());
7062 textFieldTheme_ = theme;
7063 // for normal app add version protection, enable keyboard as default start from API 10 or higher
7064 if (context->GetMinPlatformVersion() > KEYBOARD_DEFAULT_API) {
7065 if (theme) {
7066 independentControlKeyboard_ = theme->GetIndependentControlKeyboard();
7067 needToRequestKeyboardOnFocus_ = !independentControlKeyboard_;
7068 } else {
7069 needToRequestKeyboardOnFocus_ = true;
7070 }
7071 }
7072 }
7073
7074 std::string TextFieldPattern::GetTextColor() const
7075 {
7076 auto theme = GetTheme();
7077 CHECK_NULL_RETURN(theme, "");
7078 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7079 CHECK_NULL_RETURN(layoutProperty, "");
7080 return layoutProperty->GetTextColorValue(theme->GetTextColor()).ColorToString();
7081 }
7082
7083 std::string TextFieldPattern::GetCaretColor() const
7084 {
7085 auto theme = GetTheme();
7086 CHECK_NULL_RETURN(theme, "");
7087 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
7088 CHECK_NULL_RETURN(paintProperty, "");
7089 return paintProperty->GetCursorColorValue(theme->GetCursorColor()).ColorToString();
7090 }
7091
7092 std::string TextFieldPattern::GetPlaceholderColor() const
7093 {
7094 auto theme = GetTheme();
7095 CHECK_NULL_RETURN(theme, "");
7096 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7097 CHECK_NULL_RETURN(layoutProperty, "");
7098 return layoutProperty->GetPlaceholderTextColorValue(theme->GetPlaceholderColor()).ColorToString();
7099 }
7100
7101 std::string TextFieldPattern::GetFontSize() const
7102 {
7103 auto theme = GetTheme();
7104 CHECK_NULL_RETURN(theme, "");
7105 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7106 CHECK_NULL_RETURN(layoutProperty, "");
7107 return layoutProperty->GetFontSizeValue(theme->GetFontSize()).ToString();
7108 }
7109
7110 std::string TextFieldPattern::GetMinFontSize() const
7111 {
7112 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7113 CHECK_NULL_RETURN(layoutProperty, "");
7114 auto minFontSize = layoutProperty->GetAdaptMinFontSize();
7115 return minFontSize.has_value() ? minFontSize->ToString() : "";
7116 }
7117
7118 std::string TextFieldPattern::GetMaxFontSize() const
7119 {
7120 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7121 CHECK_NULL_RETURN(layoutProperty, "");
7122 auto maxFontSize = layoutProperty->GetAdaptMaxFontSize();
7123 return maxFontSize.has_value() ? maxFontSize->ToString() : "";
7124 }
7125
7126 std::string TextFieldPattern::GetMinFontScale() const
7127 {
7128 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7129 CHECK_NULL_RETURN(layoutProperty, std::to_string(MINFONTSCALE));
7130 return std::to_string(layoutProperty->GetMinFontScale().value_or(MINFONTSCALE));
7131 }
7132
7133 std::string TextFieldPattern::GetMaxFontScale() const
7134 {
7135 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7136 CHECK_NULL_RETURN(layoutProperty, std::to_string(MAXFONTSCALE));
7137 return std::to_string(layoutProperty->GetMaxFontScale().value_or(MAXFONTSCALE));
7138 }
7139
7140 std::string TextFieldPattern::GetEllipsisMode() const
7141 {
7142 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7143 CHECK_NULL_RETURN(layoutProperty, V2::ConvertEllipsisModeToString(EllipsisMode::TAIL));
7144 return V2::ConvertEllipsisModeToString(layoutProperty->GetEllipsisMode().value_or(
7145 EllipsisMode::TAIL));
7146 }
7147
7148 std::string TextFieldPattern::GetTextIndent() const
7149 {
7150 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7151 CHECK_NULL_RETURN(layoutProperty, "");
7152 auto textIndent = layoutProperty->GetTextIndent();
7153 return textIndent.has_value() ? textIndent->ToString() : "";
7154 }
7155
7156 Ace::FontStyle TextFieldPattern::GetItalicFontStyle() const
7157 {
7158 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7159 CHECK_NULL_RETURN(layoutProperty, Ace::FontStyle::NORMAL);
7160 return layoutProperty->GetItalicFontStyle().value_or(Ace::FontStyle::NORMAL);
7161 }
7162
7163 std::string TextFieldPattern::GetShowPasswordIconString() const
7164 {
7165 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7166 CHECK_NULL_RETURN(layoutProperty, "false");
7167 return layoutProperty->GetShowPasswordIconValue(false) ? "true" : "false";
7168 }
7169
7170 std::string TextFieldPattern::GetInputStyleString() const
7171 {
7172 std::string result = isTextInput_ ? "TextInputStyle.Default" : "TextContentStyle.DEFAULT";
7173 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
7174 CHECK_NULL_RETURN(paintProperty, result);
7175 switch (paintProperty->GetInputStyleValue(InputStyle::DEFAULT)) {
7176 case InputStyle::INLINE:
7177 result = isTextInput_ ? "TextInputStyle.Inline" : "TextContentStyle.INLINE";
7178 break;
7179 case InputStyle::DEFAULT:
7180 default:
7181 break;
7182 }
7183 return result;
7184 }
7185
7186 FontWeight TextFieldPattern::GetFontWeight() const
7187 {
7188 auto theme = GetTheme();
7189 CHECK_NULL_RETURN(theme, FontWeight::NORMAL);
7190 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7191 CHECK_NULL_RETURN(layoutProperty, FontWeight::NORMAL);
7192 return layoutProperty->GetFontWeightValue(theme->GetFontWeight());
7193 }
7194
7195 std::string TextFieldPattern::GetFontFamily() const
7196 {
7197 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7198 CHECK_NULL_RETURN(layoutProperty, "HarmonyOS Sans");
7199 auto family = layoutProperty->GetFontFamilyValue({ "HarmonyOS Sans" });
7200 return ConvertFontFamily(family);
7201 }
7202
7203 TextAlign TextFieldPattern::GetTextAlign() const
7204 {
7205 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7206 CHECK_NULL_RETURN(layoutProperty, TextAlign::START);
7207 return layoutProperty->GetTextAlign().value_or(TextAlign::START);
7208 }
7209
7210 uint32_t TextFieldPattern::GetMaxLength() const
7211 {
7212 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7213 CHECK_NULL_RETURN(layoutProperty, Infinity<uint32_t>());
7214 return layoutProperty->HasMaxLength() ? layoutProperty->GetMaxLengthValue(Infinity<uint32_t>())
7215 : Infinity<uint32_t>();
7216 }
7217
7218 uint32_t TextFieldPattern::GetMaxLines() const
7219 {
7220 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7221 CHECK_NULL_RETURN(layoutProperty, Infinity<uint32_t>());
7222 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
7223 CHECK_NULL_RETURN(paintProperty, Infinity<uint32_t>());
7224 if (IsNormalInlineState()) {
7225 return layoutProperty->GetMaxViewLinesValue(INLINE_DEFAULT_VIEW_MAXLINE);
7226 }
7227 return layoutProperty->HasMaxLines() ? layoutProperty->GetMaxLinesValue(Infinity<uint32_t>())
7228 : Infinity<uint32_t>();
7229 }
7230
7231 uint32_t TextFieldPattern::GetMinLines() const
7232 {
7233 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7234 CHECK_NULL_RETURN(layoutProperty, DEFAULT_MIN_LINES);
7235 return layoutProperty->GetMinLines().value_or(DEFAULT_MIN_LINES);
7236 }
7237
7238 std::u16string TextFieldPattern::GetPlaceHolder() const
7239 {
7240 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7241 CHECK_NULL_RETURN(layoutProperty, u"");
7242 return layoutProperty->GetPlaceholderValue(u"");
7243 }
7244
7245 std::string TextFieldPattern::GetInputFilter() const
7246 {
7247 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7248 CHECK_NULL_RETURN(layoutProperty, "");
7249 return layoutProperty->GetInputFilterValue("");
7250 }
7251
7252 std::u16string TextFieldPattern::GetErrorTextString() const
7253 {
7254 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7255 CHECK_NULL_RETURN(layoutProperty, u"");
7256 return layoutProperty->GetErrorTextValue(u"");
7257 }
7258
7259 bool TextFieldPattern::GetErrorTextState() const
7260 {
7261 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7262 CHECK_NULL_RETURN(layoutProperty, false);
7263 return layoutProperty->GetShowErrorTextValue(false);
7264 }
7265
7266 void TextFieldPattern::SearchRequestKeyboard()
7267 {
7268 StartTwinkling();
7269 if (RequestKeyboardNotByFocusSwitch(RequestKeyboardReason::SEARCH_REQUEST)) {
7270 NotifyOnEditChanged(true);
7271 }
7272 }
7273
7274 std::string TextFieldPattern::GetCopyOptionString() const
7275 {
7276 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7277 CHECK_NULL_RETURN(layoutProperty, "");
7278 std::string copyOptionString = "CopyOptions.Local";
7279 switch (layoutProperty->GetCopyOptionsValue(CopyOptions::Local)) {
7280 case CopyOptions::InApp:
7281 copyOptionString = "CopyOptions.InApp";
7282 break;
7283 case CopyOptions::Local:
7284 copyOptionString = "CopyOptions.Local";
7285 break;
7286 case CopyOptions::Distributed:
7287 copyOptionString = "CopyOptions.Distributed";
7288 break;
7289 case CopyOptions::None:
7290 copyOptionString = "CopyOptions.None";
7291 break;
7292 default:
7293 break;
7294 }
7295 return copyOptionString;
7296 }
7297
7298 std::string TextFieldPattern::GetBarStateString() const
7299 {
7300 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7301 CHECK_NULL_RETURN(layoutProperty, "");
7302 std::string displayModeString;
7303 switch (layoutProperty->GetDisplayModeValue(DisplayMode::AUTO)) {
7304 case DisplayMode::OFF:
7305 displayModeString = "BarState.OFF";
7306 break;
7307 case DisplayMode::ON:
7308 displayModeString = "BarState.ON";
7309 break;
7310 case DisplayMode::AUTO:
7311 default:
7312 displayModeString = "BarState.AUTO";
7313 break;
7314 }
7315 return displayModeString;
7316 }
7317
7318 void TextFieldPattern::UpdateScrollBarOffset()
7319 {
7320 if (!GetScrollBar() && !GetScrollBarProxy()) {
7321 return;
7322 }
7323 auto paddingHeight = GetPaddingTop() + GetPaddingBottom();
7324 auto contentHeight = contentRect_.Height();
7325 if (inlineFocusState_) {
7326 paddingHeight = 0.0f;
7327 contentHeight = GetSingleLineHeight() * GetMaxLines();
7328 }
7329 Size size(frameRect_.Width(), contentHeight + paddingHeight);
7330 UpdateScrollBarRegion(
7331 contentRect_.GetY() - textRect_.GetY(), textRect_.Height() + paddingHeight, size, Offset(0.0, 0.0));
7332 auto tmpHost = GetHost();
7333 CHECK_NULL_VOID(tmpHost);
7334 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
7335 }
7336
7337 void TextFieldPattern::PlayScrollBarAppearAnimation()
7338 {
7339 auto scrollBar = GetScrollBar();
7340 if (scrollBar) {
7341 scrollBar->PlayScrollBarAppearAnimation();
7342 }
7343 }
7344
7345 void TextFieldPattern::ScheduleDisappearDelayTask()
7346 {
7347 auto scrollBar = GetScrollBar();
7348 if (scrollBar) {
7349 scrollBar->SetPressed(false);
7350 scrollBar->PlayScrollBarShrinkAnimation();
7351 scrollBar->ScheduleDisappearDelayTask();
7352 }
7353 }
7354
7355 bool TextFieldPattern::OnScrollCallback(float offset, int32_t source)
7356 {
7357 if (source == SCROLL_FROM_START) {
7358 PlayScrollBarAppearAnimation();
7359 if (selectOverlay_->IsCurrentMenuVisibile()) {
7360 isTextSelectionMenuShow_ = true;
7361 } else if (CheckSelectAreaVisible()) {
7362 isTextSelectionMenuShow_ = false;
7363 }
7364 selectOverlay_->HideMenu(true);
7365 return true;
7366 }
7367 if (IsReachedBoundary(offset)) {
7368 return false;
7369 }
7370 PlayScrollBarAppearAnimation();
7371 OnTextInputScroll(offset);
7372 OnTextAreaScroll(offset);
7373 return true;
7374 }
7375
7376 void TextFieldPattern::CheckScrollable()
7377 {
7378 if (IsTextArea()) {
7379 if (contentController_->IsEmpty()) {
7380 scrollable_ = false;
7381 } else {
7382 scrollable_ = GreatNotEqual(textRect_.Height(), contentRect_.Height());
7383 }
7384 SetScrollEnabled(scrollable_);
7385 } else {
7386 SetScrollEnabled(GreatNotEqual(textRect_.Width(), contentRect_.Width()));
7387 }
7388 }
7389
7390 bool TextFieldPattern::HasStateStyle(UIState state) const
7391 {
7392 auto host = GetHost();
7393 CHECK_NULL_RETURN(host, false);
7394 auto hub = host->GetOrCreateEventHub<EventHub>();
7395 CHECK_NULL_RETURN(hub, false);
7396 return hub->HasStateStyle(state);
7397 }
7398
7399 double TextFieldPattern::GetScrollBarWidth()
7400 {
7401 auto scrollBar = GetScrollBar();
7402 double scrollBarWidth = 0.0;
7403 if (scrollBar) {
7404 scrollBarWidth = scrollBar->GetBarRect().Width();
7405 }
7406 return scrollBarWidth;
7407 }
7408
7409 void TextFieldPattern::AddCounterNode()
7410 {
7411 auto host = GetHost();
7412 CHECK_NULL_VOID(host);
7413 if (counterDecorator_ && (IsShowPasswordIcon() || IsNormalInlineState())) {
7414 CleanCounterNode();
7415 return;
7416 }
7417 if (!counterDecorator_) {
7418 auto counterDecorator = MakeRefPtr<CounterDecorator>(host);
7419 counterDecorator_ = counterDecorator;
7420 }
7421 }
7422
7423 void TextFieldPattern::SetShowError()
7424 {
7425 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7426 CHECK_NULL_VOID(layoutProperty);
7427 auto passWordMode = IsInPasswordMode();
7428 auto textFieldTheme = GetTheme();
7429 CHECK_NULL_VOID(textFieldTheme);
7430 auto tmpHost = GetHost();
7431 CHECK_NULL_VOID(tmpHost);
7432 auto renderContext = tmpHost->GetRenderContext();
7433 CHECK_NULL_VOID(renderContext);
7434 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
7435 CHECK_NULL_VOID(paintProperty);
7436 auto isUnderLine = IsUnderlineMode();
7437 auto errorText = layoutProperty->GetErrorTextValue(u"");
7438 if (IsShowError()) { // update error state
7439 if (isUnderLine) {
7440 underlineColor_ = userUnderlineColor_.error.value_or(textFieldTheme->GetErrorUnderlineColor());
7441 underlineWidth_ = ERROR_UNDERLINE_WIDTH;
7442 } else if (passWordMode) {
7443 if (!paintProperty->HasBorderWidthFlagByUser()) {
7444 paintProperty->UpdateInnerBorderWidth(textFieldTheme->GetErrorTextInputBorderWidth());
7445 paintProperty->UpdateInnerBorderColor(textFieldTheme->GetPasswordErrorBorderColor());
7446 } else {
7447 BorderColorProperty borderColor;
7448 borderColor.SetColor(textFieldTheme->GetPasswordErrorBorderColor());
7449 renderContext->UpdateBorderColor(borderColor);
7450 }
7451 renderContext->UpdateBackgroundColor(textFieldTheme->GetPasswordErrorInputColor());
7452 layoutProperty->UpdateTextColor(textFieldTheme->GetPasswordErrorTextColor());
7453 if (!layoutProperty->HasPlaceholderTextColor()) {
7454 layoutProperty->UpdatePlaceholderTextColor(textFieldTheme->GetPlaceholderColor());
7455 }
7456 }
7457 }
7458 UpdateErrorTextMargin();
7459 }
7460
7461 float TextFieldPattern::CalcDecoratorWidth(const RefPtr<FrameNode>& decoratorNode)
7462 {
7463 float decoratorWidth = 0.0f;
7464 CHECK_NULL_RETURN(decoratorNode, 0.0f);
7465 auto textPattern = decoratorNode->GetPattern<TextPattern>();
7466 CHECK_NULL_RETURN(textPattern, 0.0f);
7467 auto paragraphs = textPattern->GetParagraphs();
7468 for (auto &&info : paragraphs) {
7469 if (info.paragraph) {
7470 float width = info.paragraph->GetLongestLine();
7471 decoratorWidth = std::max(decoratorWidth, width);
7472 }
7473 }
7474 return decoratorWidth;
7475 }
7476
7477 float TextFieldPattern::CalcDecoratorHeight(const RefPtr<FrameNode>& decoratorNode)
7478 {
7479 CHECK_NULL_RETURN(decoratorNode, 0.0f);
7480 auto geometryNode = decoratorNode->GetGeometryNode();
7481 CHECK_NULL_RETURN(geometryNode, 0.0f);
7482 return geometryNode->GetFrameRect().Height();
7483 }
7484
7485 void TextFieldPattern::UpdateErrorTextMargin()
7486 {
7487 auto tmpHost = GetHost();
7488 CHECK_NULL_VOID(tmpHost);
7489 if (IsShowError()) {
7490 if (!errorDecorator_) {
7491 auto errorDecorator = MakeRefPtr<ErrorDecorator>(tmpHost);
7492 errorDecorator_ = errorDecorator;
7493 }
7494 errorDecorator_->UpdateTextFieldMargin();
7495 } else {
7496 errorDecorator_.Reset();
7497 }
7498 }
7499
7500 void TextFieldPattern::ApplyUnderlineTheme()
7501 {
7502 if (!IsUnderlineMode()) {
7503 return;
7504 }
7505 SetThemeAttr();
7506 auto theme = GetTheme();
7507 CHECK_NULL_VOID(theme);
7508 if (IsShowError()) {
7509 underlineColor_ = userUnderlineColor_.error.value_or(theme->GetErrorUnderlineColor());
7510 } else {
7511 underlineColor_ = HasFocus() ? userUnderlineColor_.typing.value_or(theme->GetUnderlineTypingColor())
7512 : userUnderlineColor_.normal.value_or(theme->GetUnderlineColor());
7513 }
7514 underlineWidth_ = HasFocus() ? TYPING_UNDERLINE_WIDTH : UNDERLINE_WIDTH;
7515 }
7516
7517 float TextFieldPattern::GetMarginBottom() const
7518 {
7519 auto tmpHost = GetHost();
7520 CHECK_NULL_RETURN(tmpHost, 0.0f);
7521 auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
7522 CHECK_NULL_RETURN(layoutProperty, 0.0f);
7523 const auto& getMargin = layoutProperty->GetMarginProperty();
7524 if (getMargin && getMargin->bottom.has_value()) {
7525 return getMargin->bottom->GetDimension().ConvertToPx();
7526 }
7527 return 0.0f;
7528 }
7529
7530 std::string TextFieldPattern::GetShowResultImageSrc() const
7531 {
7532 auto tmpHost = GetHost();
7533 CHECK_NULL_RETURN(tmpHost, "");
7534 auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
7535 CHECK_NULL_RETURN(layoutProperty, "");
7536 auto showImageSource = layoutProperty->GetShowPasswordSourceInfo();
7537 if (showImageSource && !showImageSource->GetSrc().empty()) {
7538 return showImageSource->GetSrc();
7539 }
7540 return SHOW_PASSWORD_SVG;
7541 }
7542
7543 std::string TextFieldPattern::GetNormalUnderlineColorStr() const
7544 {
7545 auto theme = GetTheme();
7546 CHECK_NULL_RETURN(theme, "");
7547 Color normal = userUnderlineColor_.normal.value_or(theme->GetUnderlineColor());
7548 return normal.ColorToString();
7549 }
7550
7551 std::string TextFieldPattern::GetTypingUnderlineColorStr() const
7552 {
7553 auto theme = GetTheme();
7554 CHECK_NULL_RETURN(theme, "");
7555 Color typing = userUnderlineColor_.typing.value_or(theme->GetUnderlineTypingColor());
7556 return typing.ColorToString();
7557 }
7558
7559 std::string TextFieldPattern::GetDisableUnderlineColorStr() const
7560 {
7561 auto theme = GetTheme();
7562 CHECK_NULL_RETURN(theme, "");
7563 Color disable = userUnderlineColor_.disable.value_or(theme->GetDisableUnderlineColor());
7564 return disable.ColorToString();
7565 }
7566
7567 std::string TextFieldPattern::GetErrorUnderlineColorStr() const
7568 {
7569 auto theme = GetTheme();
7570 CHECK_NULL_RETURN(theme, "");
7571 Color error = userUnderlineColor_.error.value_or(theme->GetErrorUnderlineColor());
7572 return error.ColorToString();
7573 }
7574
7575 std::string TextFieldPattern::GetHideResultImageSrc() const
7576 {
7577 auto tmpHost = GetHost();
7578 CHECK_NULL_RETURN(tmpHost, "");
7579 auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
7580 CHECK_NULL_RETURN(layoutProperty, "");
7581 auto hideSourceInfo = layoutProperty->GetHidePasswordSourceInfo();
7582 if (hideSourceInfo && !hideSourceInfo->GetSrc().empty()) {
7583 return hideSourceInfo->GetSrc();
7584 }
7585 return HIDE_PASSWORD_SVG;
7586 }
7587
7588 void TextFieldPattern::RestorePreInlineStates()
7589 {
7590 ResetContextAttr();
7591 ApplyNormalTheme();
7592 ApplyUnderlineTheme();
7593 ProcessInnerPadding();
7594 ProcessResponseArea();
7595 ProcessRectPadding();
7596 }
7597
7598 void TextFieldPattern::ProcessRectPadding()
7599 {
7600 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7601 CHECK_NULL_VOID(layoutProperty);
7602 auto& paddingProperty = layoutProperty->GetPaddingProperty();
7603 CHECK_NULL_VOID(paddingProperty);
7604 auto top = paddingProperty->top.has_value() ? paddingProperty->top->GetDimension().ConvertToPx() : 0.0f;
7605 textRect_.SetTop(top);
7606 }
7607
7608 void TextFieldPattern::TextAreaInputRectUpdate(RectF& rect)
7609 {
7610 auto tmpHost = GetHost();
7611 CHECK_NULL_VOID(tmpHost);
7612 auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
7613 CHECK_NULL_VOID(layoutProperty);
7614 auto theme = GetTheme();
7615 CHECK_NULL_VOID(theme);
7616 if (IsTextArea() && !contentController_->IsEmpty()) {
7617 auto inputContentWidth = GetParagraph()->GetMaxIntrinsicWidth();
7618 switch (layoutProperty->GetTextAlignValue(TextAlign::START)) {
7619 case TextAlign::START:
7620 if (inputContentWidth < contentRect_.Width()) {
7621 rect.SetWidth(inputContentWidth);
7622 }
7623 break;
7624 case TextAlign::CENTER:
7625 if (inputContentWidth < contentRect_.Width()) {
7626 rect.SetLeft(
7627 static_cast<float>(rect.GetX()) + contentRect_.Width() / 2.0f - inputContentWidth / 2.0f);
7628 rect.SetWidth(inputContentWidth);
7629 }
7630 break;
7631 case TextAlign::END:
7632 if (inputContentWidth < contentRect_.Width()) {
7633 rect.SetLeft(static_cast<float>(rect.GetX()) + contentRect_.Width() -
7634 static_cast<float>(theme->GetCursorWidth().ConvertToPx()) - inputContentWidth);
7635 rect.SetWidth(inputContentWidth);
7636 }
7637 break;
7638 default:
7639 break;
7640 }
7641 }
7642 }
7643
7644 void TextFieldPattern::TextIsEmptyRect(RectF& rect)
7645 {
7646 rect = selectController_->CalculateEmptyValueCaretRect();
7647 }
7648
7649 void TextFieldPattern::UpdateRectByTextAlign(RectF& rect)
7650 {
7651 auto tmpHost = GetHost();
7652 CHECK_NULL_VOID(tmpHost);
7653 auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
7654 CHECK_NULL_VOID(layoutProperty);
7655 if (!layoutProperty->HasTextAlign()) {
7656 return;
7657 }
7658 switch (layoutProperty->GetTextAlignValue(TextAlign::START)) {
7659 case TextAlign::START:
7660 return;
7661 case TextAlign::CENTER:
7662 rect.SetLeft(rect.GetOffset().GetX() + (contentRect_.Width() - textRect_.Width()) * 0.5f);
7663 return;
7664 case TextAlign::END:
7665 rect.SetLeft(rect.GetOffset().GetX() + (contentRect_.Width() - textRect_.Width()));
7666 return;
7667 default:
7668 return;
7669 }
7670 }
7671
7672 void TextFieldPattern::ProcessInlinePaddingAndMargin()
7673 {
7674 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7675 CHECK_NULL_VOID(layoutProperty);
7676 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
7677 auto theme = GetTheme();
7678 CHECK_NULL_VOID(theme);
7679 PaddingProperty userPadding;
7680 MarginProperty userMargin;
7681 if (paintProperty->HasPaddingByUser()) {
7682 userPadding = paintProperty->GetPaddingByUserValue();
7683 } else {
7684 auto themePadding = IsUnderlineMode() ? theme->GetUnderlinePadding() : theme->GetPadding();
7685 userPadding.top = CalcLength(CalcLength(themePadding.Top()).GetDimension());
7686 userPadding.bottom = CalcLength(CalcLength(themePadding.Bottom()).GetDimension());
7687 userPadding.left = CalcLength(CalcLength(themePadding.Left()).GetDimension());
7688 userPadding.right = CalcLength(CalcLength(themePadding.Right()).GetDimension());
7689 }
7690 if (paintProperty->HasMarginByUser()) {
7691 userMargin = paintProperty->GetMarginByUserValue();
7692 }
7693 MarginProperty margin;
7694 margin.bottom = CalcLength(userMargin.bottom->GetDimension() + userPadding.bottom->GetDimension());
7695 margin.right = CalcLength(userMargin.right->GetDimension() + userPadding.right->GetDimension());
7696 margin.left = CalcLength(userMargin.left->GetDimension() + userPadding.left->GetDimension());
7697 margin.top = CalcLength(userMargin.top->GetDimension() + userPadding.top->GetDimension());
7698 layoutProperty->UpdateMargin(margin);
7699 if (!IsTextArea()) {
7700 layoutProperty->UpdatePlaceholderMaxLines(layoutProperty->GetMaxViewLinesValue(INLINE_DEFAULT_VIEW_MAXLINE));
7701 layoutProperty->ResetMaxLines();
7702 }
7703 if (layoutProperty->HasTextOverflow()) {
7704 layoutProperty->UpdateTextOverflowMaxLines(layoutProperty->GetMaxViewLinesValue(INLINE_DEFAULT_VIEW_MAXLINE));
7705 }
7706 }
7707
7708 void TextFieldPattern::ApplyInlineTheme()
7709 {
7710 if (!IsInlineMode()) {
7711 return;
7712 }
7713 auto tmpHost = GetHost();
7714 CHECK_NULL_VOID(tmpHost);
7715 auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
7716 CHECK_NULL_VOID(layoutProperty);
7717 auto renderContext = tmpHost->GetRenderContext();
7718 CHECK_NULL_VOID(renderContext);
7719 auto theme = GetTheme();
7720 CHECK_NULL_VOID(theme);
7721 layoutProperty->UpdateTextColor(theme->GetInlineTextColor());
7722 auto radius = theme->GetInlineRadiusSize();
7723 renderContext->UpdateBorderRadius({ radius.GetX(), radius.GetY(), radius.GetY(), radius.GetX() });
7724 renderContext->UpdateBackgroundColor(theme->GetInlineBgColor());
7725 BorderWidthProperty inlineBorderWidth;
7726 inlineBorderWidth.SetBorderWidth(INLINE_BORDER_WIDTH);
7727 layoutProperty->UpdateBorderWidth(inlineBorderWidth);
7728 renderContext->UpdateBorderWidth(inlineBorderWidth);
7729 BorderColorProperty inlineBorderColor;
7730 inlineBorderColor.SetColor(theme->GetInlineBorderColor());
7731 renderContext->UpdateBorderColor(inlineBorderColor);
7732
7733 if (layoutProperty->GetNonAutoLayoutDirection() == TextDirection::RTL) {
7734 layoutProperty->UpdatePadding({ CalcLength(theme->getInlinePaddingRight()),
7735 CalcLength(theme->getInlinePaddingLeft()), CalcLength(0.0f), CalcLength(0.0f) });
7736 } else {
7737 layoutProperty->UpdatePadding({ CalcLength(theme->getInlinePaddingLeft()),
7738 CalcLength(theme->getInlinePaddingRight()), CalcLength(0.0f), CalcLength(0.0f)});
7739 }
7740 ProcessInnerPadding();
7741 ProcessInlinePaddingAndMargin();
7742 }
7743
7744 bool TextFieldPattern::ResetObscureTickCountDown()
7745 {
7746 auto oldTickCountDown_ = obscureTickCountDown_;
7747 if (!IsTextArea() && GetTextObscured() && IsInPasswordMode()) {
7748 obscureTickCountDown_ = 0;
7749 }
7750 return oldTickCountDown_ != obscureTickCountDown_;
7751 }
7752
7753 bool TextFieldPattern::IsInPasswordMode() const
7754 {
7755 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7756 CHECK_NULL_RETURN(layoutProperty, false);
7757 auto inputType = layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED);
7758 return inputType == TextInputType::VISIBLE_PASSWORD || inputType == TextInputType::NUMBER_PASSWORD ||
7759 inputType == TextInputType::SCREEN_LOCK_PASSWORD || inputType == TextInputType::NEW_PASSWORD;
7760 }
7761
7762 bool TextFieldPattern::IsNormalInlineState() const
7763 {
7764 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
7765 CHECK_NULL_RETURN(paintProperty, false);
7766 auto tmpHost = GetHost();
7767 CHECK_NULL_RETURN(tmpHost, false);
7768 auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
7769 CHECK_NULL_RETURN(layoutProperty, false);
7770 return paintProperty->GetInputStyleValue(InputStyle::DEFAULT) == InputStyle::INLINE &&
7771 (layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED) == TextInputType::UNSPECIFIED ||
7772 layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED) == TextInputType::TEXT);
7773 }
7774
7775 bool TextFieldPattern::IsUnspecifiedOrTextType() const
7776 {
7777 auto tmpHost = GetHost();
7778 CHECK_NULL_RETURN(tmpHost, false);
7779 auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
7780 CHECK_NULL_RETURN(layoutProperty, false);
7781 auto inputType = layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED);
7782 return inputType == TextInputType::UNSPECIFIED || inputType == TextInputType::TEXT;
7783 }
7784
7785 void TextFieldPattern::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
7786 {
7787 /* no fixed attr below, just return */
7788 if (filter.IsFastFilter()) {
7789 return;
7790 }
7791 json->PutExtAttr("placeholder", UtfUtils::Str16DebugToStr8(GetPlaceHolder()).c_str(), filter);
7792 json->PutExtAttr("text", contentController_->GetTextValue().c_str(), filter);
7793 json->PutExtAttr("fontSize", GetFontSize().c_str(), filter);
7794 json->PutExtAttr("fontColor", GetTextColor().c_str(), filter);
7795 json->PutExtAttr("fontStyle",
7796 GetItalicFontStyle() == Ace::FontStyle::NORMAL ? "FontStyle.Normal" : "FontStyle.Italic", filter);
7797 json->PutExtAttr("fontWeight", V2::ConvertWrapFontWeightToStirng(GetFontWeight()).c_str(), filter);
7798 json->PutExtAttr("fontFamily", GetFontFamily().c_str(), filter);
7799 json->PutExtAttr("textAlign", V2::ConvertWrapTextAlignToString(GetTextAlign()).c_str(), filter);
7800 json->PutExtAttr("caretColor", GetCaretColor().c_str(), filter);
7801 json->PutExtAttr("type", TextInputTypeToString().c_str(), filter);
7802 json->PutExtAttr("contentType", TextContentTypeToString().c_str(), filter);
7803 json->PutExtAttr("placeholderColor", GetPlaceholderColor().c_str(), filter);
7804 json->PutExtAttr("placeholderFont", GetPlaceholderFont().c_str(), filter);
7805 json->PutExtAttr("enterKeyType", TextInputActionToString().c_str(), filter);
7806 json->PutExtAttr("maxLength", GreatOrEqual(GetMaxLength(),
7807 Infinity<uint32_t>()) ? "INF" : std::to_string(GetMaxLength()).c_str(), filter);
7808 json->PutExtAttr("inputFilter", GetInputFilter().c_str(), filter);
7809 json->PutExtAttr("copyOption", GetCopyOptionString().c_str(), filter);
7810 json->PutExtAttr("style", GetInputStyleString().c_str(), filter);
7811
7812 auto jsonValue = JsonUtil::Create(true);
7813 if (IsShowPasswordSymbol()) {
7814 jsonValue->Put("onIconSrc", static_cast<int64_t>(GetTheme()->GetShowSymbolId()));
7815 jsonValue->Put("offIconSrc", static_cast<int64_t>(GetTheme()->GetHideSymbolId()));
7816 } else {
7817 jsonValue->Put("onIconSrc", GetShowResultImageSrc().c_str());
7818 jsonValue->Put("offIconSrc", GetHideResultImageSrc().c_str());
7819 }
7820 json->PutExtAttr("passwordIcon", jsonValue->ToString().c_str(), filter);
7821 json->PutExtAttr("showError", GetErrorTextState() ? UtfUtils::Str16DebugToStr8(GetErrorTextString()).c_str() :
7822 "undefined", filter);
7823 json->PutExtAttr("maxLines", GreatOrEqual(GetMaxLines(),
7824 Infinity<uint32_t>()) ? "INF" : std::to_string(GetMaxLines()).c_str(), filter);
7825 json->PutExtAttr("minLines", std::to_string(GetMinLines()).c_str(), filter);
7826 json->PutExtAttr("barState", GetBarStateString().c_str(), filter);
7827 json->PutExtAttr("caretPosition", std::to_string(GetCaretIndex()).c_str(), filter);
7828 json->PutExtAttr("enablePreviewText", GetSupportPreviewText(), filter);
7829 json->PutExtAttr("minFontScale", GetMinFontScale().c_str(), filter);
7830 json->PutExtAttr("maxFontScale", GetMaxFontScale().c_str(), filter);
7831 json->PutExtAttr("ellipsisMode",GetEllipsisMode().c_str(), filter);
7832 json->PutExtAttr("autoCapitalizationMode", AutoCapTypeToString().c_str(), filter);
7833 ToJsonValueForOption(json, filter);
7834 ToJsonValueForFontFeature(json, filter);
7835 ToJsonValueSelectOverlay(json, filter);
7836 ToJsonValueForStroke(json, filter);
7837 }
7838
7839 void TextFieldPattern::ToTreeJson(std::unique_ptr<JsonValue>& json, const InspectorConfig& config) const
7840 {
7841 Pattern::ToTreeJson(json, config);
7842 json->Put(TreeKey::CONTENT, contentController_->GetTextValue().c_str());
7843 json->Put(TreeKey::PLACEHOLDER, GetPlaceHolder().c_str());
7844 }
7845
7846 void TextFieldPattern::ToJsonValueForFontFeature(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
7847 {
7848 auto host = GetHost();
7849 CHECK_NULL_VOID(host);
7850 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
7851 CHECK_NULL_VOID(layoutProperty);
7852 if (!layoutProperty->HasFontFeature()) {
7853 json->PutExtAttr("fontFeature", "", filter);
7854 return;
7855 }
7856 auto fontFeature = layoutProperty->GetFontFeature().value();
7857 std::string fontFeatureString = "";
7858 for (const auto& fontFeatureItem : fontFeature) {
7859 fontFeatureString += fontFeatureItem.first;
7860 fontFeatureString += " ";
7861 fontFeatureString += fontFeatureItem.second ? "on" : "off";
7862 fontFeatureString += ",";
7863 }
7864 if (!fontFeatureString.empty()) {
7865 fontFeatureString.pop_back();
7866 }
7867 json->PutExtAttr("fontFeature", fontFeatureString.c_str(), filter);
7868 }
7869
7870 void TextFieldPattern::ToJsonValueForOption(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
7871 {
7872 auto underlineColorJsonValue = JsonUtil::Create(true);
7873 underlineColorJsonValue->Put("normal", GetNormalUnderlineColorStr().c_str());
7874 underlineColorJsonValue->Put("typing", GetTypingUnderlineColorStr().c_str());
7875 underlineColorJsonValue->Put("error", GetErrorUnderlineColorStr().c_str());
7876 underlineColorJsonValue->Put("disable", GetDisableUnderlineColorStr().c_str());
7877 json->PutExtAttr("underlineColor", underlineColorJsonValue->ToString().c_str(), filter);
7878
7879 auto host = GetHost();
7880 CHECK_NULL_VOID(host);
7881 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
7882 CHECK_NULL_VOID(layoutProperty);
7883 auto jsonShowCounter = JsonUtil::Create(true);
7884 jsonShowCounter->Put("value", layoutProperty->GetShowCounterValue(false));
7885 auto jsonShowCounterOptions = JsonUtil::Create(true);
7886 jsonShowCounterOptions->Put("thresholdPercentage", layoutProperty->GetSetCounterValue(DEFAULT_MODE));
7887 jsonShowCounterOptions->Put("highlightBorder", layoutProperty->GetShowHighlightBorderValue(true));
7888 jsonShowCounter->Put("options", jsonShowCounterOptions);
7889 json->PutExtAttr("showCounter", jsonShowCounter, filter);
7890 json->PutExtAttr("keyboardAppearance", static_cast<int32_t>(keyboardAppearance_), filter);
7891 json->PutExtAttr("enableHapticFeedback", isEnableHapticFeedback_ ? "true" : "false", filter);
7892 }
7893
7894 void TextFieldPattern::ToJsonValueSelectOverlay(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
7895 {
7896 json->PutExtAttr("CaretStatus", cursorVisible_ ? "show" : "hide", filter);
7897 json->PutExtAttr("CaretTwinkling", isCaretTwinkling_ ? "true" : "false", filter);
7898 json->PutExtAttr("caretRect", selectController_->GetCaretRect().ToString().c_str(), filter);
7899 json->PutExtAttr("caretWidth", std::to_string(selectController_->GetCaretRect().Width()).c_str(), filter);
7900 json->PutExtAttr("isShowMagnifier", magnifierController_->GetShowMagnifier() ? "true" : "false", filter);
7901 json->PutExtAttr("MagnifierPosition", magnifierController_->GetLocalOffset().ToString().c_str(), filter);
7902
7903 auto manager = selectOverlay_->GetManager<SelectContentOverlayManager>();
7904 CHECK_NULL_VOID(manager);
7905 auto selectOverlayInfo = manager->GetSelectOverlayInfo();
7906 CHECK_NULL_VOID(selectOverlayInfo);
7907
7908 //handle info
7909 json->PutExtAttr("IsSingleHandle", selectOverlayInfo->isSingleHandle ? "true" : "false", filter);
7910 json->PutExtAttr("IsHandleReverse", selectOverlayInfo->handleReverse ? "true" : "false", filter);
7911 json->PutExtAttr("FirstHandleRect", selectOverlayInfo->firstHandle.paintRect.ToString().c_str(), filter);
7912 json->PutExtAttr("FirstHandleStartPoint",
7913 selectOverlayInfo->firstHandle.paintInfo.startPoint.ToString().c_str(), filter);
7914 json->PutExtAttr("FirstHandleEndPoint",
7915 selectOverlayInfo->firstHandle.paintInfo.endPoint.ToString().c_str(), filter);
7916 json->PutExtAttr("IsFirstHandlePaintByPoints",
7917 selectOverlayInfo->firstHandle.isPaintHandleWithPoints ? "true" : "false", filter);
7918 json->PutExtAttr("SecondHandleRect", selectOverlayInfo->secondHandle.paintRect.ToString().c_str(), filter);
7919 json->PutExtAttr("SecondHandleStartPoint",
7920 selectOverlayInfo->secondHandle.paintInfo.startPoint.ToString().c_str(), filter);
7921 json->PutExtAttr("SecondHandleEndPoint",
7922 selectOverlayInfo->secondHandle.paintInfo.endPoint.ToString().c_str(), filter);
7923 json->PutExtAttr("IsSecondHandlePaintByPoints",
7924 selectOverlayInfo->secondHandle.isPaintHandleWithPoints ? "true" : "false", filter);
7925
7926 //menu
7927 auto menuNode = manager->GetSelectOverlayNode();
7928 CHECK_NULL_VOID(menuNode);
7929 json->PutExtAttr("MenuNode", menuNode->GetTag().c_str(), filter);
7930 if (menuNode->GetAncestorNodeOfFrame(true)) {
7931 json->PutExtAttr("MountOn", menuNode->GetAncestorNodeOfFrame(true)->GetTag().c_str(), filter);
7932 }
7933 auto menuLayoutProperty = menuNode->GetLayoutProperty();
7934 CHECK_NULL_VOID(menuLayoutProperty);
7935 auto menuVisible = static_cast<int32_t>(menuLayoutProperty->GetVisibility().value_or(VisibleType::VISIBLE));
7936 json->PutExtAttr("Visible", std::to_string(menuVisible).c_str(), filter);
7937 auto menuGeometryNode = menuNode->GetGeometryNode();
7938 CHECK_NULL_VOID(menuGeometryNode);
7939 json->PutExtAttr("MenuFrameRect", menuGeometryNode->GetFrameRect().ToString().c_str(), filter);
7940 json->PutExtAttr("MenuItemCount", std::to_string(selectOverlayInfo->menuOptionItems.size()).c_str(), filter);
7941 for (auto menuItme : selectOverlayInfo->menuOptionItems) {
7942 json->PutExtAttr("MenuItme", menuItme.content.value_or("").c_str(), filter);
7943 }
7944 }
7945
7946 std::string TextFieldPattern::GetStrokeWidth() const
7947 {
7948 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7949 CHECK_NULL_RETURN(layoutProperty, "");
7950 return (layoutProperty->GetStrokeWidth().value_or(Dimension())).ToString();
7951 }
7952
7953 std::string TextFieldPattern::GetStrokeColor() const
7954 {
7955 auto theme = GetTheme();
7956 CHECK_NULL_RETURN(theme, "");
7957 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7958 CHECK_NULL_RETURN(layoutProperty, "");
7959
7960 if (layoutProperty->HasStrokeColor() && layoutProperty->GetStrokeColor().has_value()) {
7961 auto strokeColor = layoutProperty->GetStrokeColor().value().ColorToString();
7962 if (!strokeColor.empty()) {
7963 return strokeColor;
7964 }
7965 }
7966
7967 auto textColor = layoutProperty->GetTextColor();
7968 if (textColor.has_value()) {
7969 return textColor.value().ColorToString();
7970 }
7971
7972 return theme->GetTextColor().ColorToString();
7973 }
7974
7975 void TextFieldPattern::ToJsonValueForStroke(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
7976 {
7977 json->PutExtAttr("strokeWidth", GetStrokeWidth().c_str(), filter);
7978 json->PutExtAttr("strokeColor", GetStrokeColor().c_str(), filter);
7979 }
7980
7981 void TextFieldPattern::FromJson(const std::unique_ptr<JsonValue>& json)
7982 {
7983 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7984 layoutProperty->UpdatePlaceholder(UtfUtils::Str8DebugToStr16(json->GetString("placeholder")));
7985 UpdateEditingValue(json->GetString("text"), StringUtils::StringToInt(json->GetString("caretPosition")));
7986 FireOnTextChangeEvent();
7987 UpdateSelection(GetCaretIndex());
7988 auto maxLines = json->GetString("maxLines");
7989 if (!maxLines.empty() && maxLines != "INF") {
7990 layoutProperty->UpdateMaxLines(StringUtils::StringToUint(maxLines));
7991 }
7992 static const std::unordered_map<std::string, CopyOptions> uMap = {
7993 { "CopyOptions.None", CopyOptions::None },
7994 { "CopyOptions.InApp", CopyOptions::InApp },
7995 { "CopyOptions.Local", CopyOptions::Local },
7996 { "CopyOptions.Distributed", CopyOptions::Distributed },
7997 };
7998 auto copyOption = json->GetString("copyOption");
7999 CopyOptions copyOptionsEnum = CopyOptions::Local;
8000 auto iter = uMap.find(copyOption);
8001 if (iter != uMap.end()) {
8002 copyOptionsEnum = iter->second;
8003 }
8004 layoutProperty->UpdateCopyOptions(copyOptionsEnum);
8005 Pattern::FromJson(json);
8006 }
8007
8008 void TextFieldPattern::SetAccessibilityAction()
8009 {
8010 SetAccessibilityActionOverlayAndSelection();
8011 SetAccessibilityActionGetAndSetCaretPosition();
8012 SetAccessibilityMoveTextAction();
8013 SetAccessibilityErrorText();
8014 }
8015
8016 void TextFieldPattern::SetAccessibilityActionOverlayAndSelection()
8017 {
8018 auto host = GetHost();
8019 CHECK_NULL_VOID(host);
8020 auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
8021 CHECK_NULL_VOID(accessibilityProperty);
8022 accessibilityProperty->SetActionSetText([weakPtr = WeakClaim(this)](const std::string& value) {
8023 const auto& pattern = weakPtr.Upgrade();
8024 CHECK_NULL_VOID(pattern);
8025 pattern->InsertValue(UtfUtils::Str8DebugToStr16(value));
8026 });
8027
8028 accessibilityProperty->SetActionSetSelection([weakPtr = WeakClaim(this)](int32_t start,
8029 int32_t end, bool isForward) {
8030 const auto& pattern = weakPtr.Upgrade();
8031 CHECK_NULL_VOID(pattern);
8032 pattern->SetSelectionFlag(start, end, std::nullopt, isForward);
8033 });
8034
8035 accessibilityProperty->SetActionClearSelection([weakPtr = WeakClaim(this)]() {
8036 const auto& pattern = weakPtr.Upgrade();
8037 CHECK_NULL_VOID(pattern);
8038 auto current = pattern->selectController_->GetEndIndex();
8039 pattern->SetInSelectMode(SelectionMode::NONE);
8040 pattern->UpdateSelection(current);
8041 pattern->SetSelectionFlag(current, current, std::nullopt);
8042 pattern->CloseSelectOverlay(true);
8043 pattern->StartTwinkling();
8044 });
8045 SetAccessibilityEditAction();
8046 }
8047
8048 void TextFieldPattern::SetAccessibilityEditAction()
8049 {
8050 auto host = GetHost();
8051 CHECK_NULL_VOID(host);
8052 auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
8053 CHECK_NULL_VOID(accessibilityProperty);
8054
8055 accessibilityProperty->SetActionCopy([weakPtr = WeakClaim(this)]() {
8056 const auto& pattern = weakPtr.Upgrade();
8057 CHECK_NULL_VOID(pattern);
8058 if (pattern->AllowCopy()) {
8059 pattern->HandleOnCopy();
8060 pattern->CloseSelectOverlay(true);
8061 }
8062 });
8063
8064 accessibilityProperty->SetActionCut([weakPtr = WeakClaim(this)]() {
8065 const auto& pattern = weakPtr.Upgrade();
8066 CHECK_NULL_VOID(pattern);
8067 if (pattern->AllowCopy()) {
8068 pattern->suppressAccessibilityEvent_ = false;
8069 pattern->HandleOnCut();
8070 pattern->CloseSelectOverlay(true);
8071 }
8072 });
8073
8074 accessibilityProperty->SetActionPaste([weakPtr = WeakClaim(this)]() {
8075 const auto& pattern = weakPtr.Upgrade();
8076 CHECK_NULL_VOID(pattern);
8077 pattern->suppressAccessibilityEvent_ = false;
8078 pattern->HandleOnPaste();
8079 pattern->CloseSelectOverlay(true);
8080 });
8081 }
8082
8083 void TextFieldPattern::SetAccessibilityActionGetAndSetCaretPosition()
8084 {
8085 auto host = GetHost();
8086 CHECK_NULL_VOID(host);
8087 auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
8088 CHECK_NULL_VOID(accessibilityProperty);
8089 accessibilityProperty->SetActionSetIndex([weakPtr = WeakClaim(this)](int32_t index) {
8090 const auto& pattern = weakPtr.Upgrade();
8091 CHECK_NULL_VOID(pattern);
8092 pattern->SetCaretPosition(index);
8093 });
8094
8095 accessibilityProperty->SetActionGetIndex([weakPtr = WeakClaim(this)]() -> int32_t {
8096 const auto& pattern = weakPtr.Upgrade();
8097 CHECK_NULL_RETURN(pattern, -1);
8098 auto index = pattern->selectController_->GetCaretIndex();
8099 return index;
8100 });
8101 }
8102
8103 void TextFieldPattern::SetAccessibilityMoveTextAction()
8104 {
8105 auto host = GetHost();
8106 CHECK_NULL_VOID(host);
8107 auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
8108 CHECK_NULL_VOID(accessibilityProperty);
8109 accessibilityProperty->SetActionMoveText([weakPtr = WeakClaim(this)](int32_t moveUnit, bool forward) {
8110 const auto& pattern = weakPtr.Upgrade();
8111 CHECK_NULL_VOID(pattern);
8112 auto host = pattern->GetHost();
8113 CHECK_NULL_VOID(host);
8114 if (pattern->contentController_->IsEmpty()) {
8115 return;
8116 }
8117 int range = 0;
8118 if (moveUnit == 1) {
8119 range = 1;
8120 }
8121 auto caretPosition = forward ? pattern->selectController_->GetCaretIndex() + range
8122 : pattern->selectController_->GetCaretIndex() - range;
8123 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
8124 pattern->SetCaretPosition(caretPosition);
8125 });
8126 }
8127
8128 void TextFieldPattern::SetAccessibilityErrorText()
8129 {
8130 auto host = GetHost();
8131 CHECK_NULL_VOID(host);
8132 auto accessibilityProperty = host->GetAccessibilityProperty<TextFieldAccessibilityProperty>();
8133 CHECK_NULL_VOID(accessibilityProperty);
8134 if (!IsDisabled() && IsShowError()) {
8135 accessibilityProperty->SetErrorText(UtfUtils::Str16DebugToStr8(GetErrorTextString()));
8136 } else {
8137 accessibilityProperty->SetErrorText("");
8138 }
8139 }
8140
8141 void TextFieldPattern::StopEditing()
8142 {
8143 auto host = GetHost();
8144 FREE_NODE_CHECK(host, StopEditing); // call StopEditingMultiThread() by multi thread
8145 if (!HasFocus()) {
8146 return;
8147 }
8148 CHECK_NULL_VOID(host);
8149 ContainerScope scope(host->GetInstanceId());
8150 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "textfield %{public}d Stop Editing", host->GetId());
8151 FocusHub::LostFocusToViewRoot();
8152 UpdateSelection(selectController_->GetCaretIndex());
8153 StopTwinkling();
8154 CloseKeyboard(true);
8155 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
8156 }
8157
8158 void TextFieldPattern::DumpInfo()
8159 {
8160 auto host = GetHost();
8161 CHECK_NULL_VOID(host);
8162 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
8163 CHECK_NULL_VOID(layoutProperty);
8164 auto& dumpLog = DumpLog::GetInstance();
8165 dumpLog.AddDesc(std::string("Content:").append(GetDumpTextValue()));
8166 dumpLog.AddDesc(std::string("AutocapitalizationMode:").append(AutoCapTypeToString()));
8167 dumpLog.AddDesc(std::string("autoWidth: ").append(std::to_string(layoutProperty->GetWidthAutoValue(false))));
8168 dumpLog.AddDesc(std::string("MaxLength:").append(std::to_string(GetMaxLength())));
8169 dumpLog.AddDesc(std::string("fontSize:").append(GetFontSize()));
8170 dumpLog.AddDesc(std::string("fontWeight:").append(V2::ConvertWrapFontWeightToStirng(GetFontWeight())));
8171 dumpLog.AddDesc(std::string("fontFamily:").append(GetFontFamily()));
8172 auto flag = GetItalicFontStyle() == Ace::FontStyle::NORMAL;
8173 dumpLog.AddDesc(std::string("fontStyle:").append(flag ? "FontStyle.Normal" : "FontStyle.Italic"));
8174 dumpLog.AddDesc(std::string("InputFilter:").append(GetInputFilter()));
8175 auto lineHeight = layoutProperty->GetLineHeight().value_or(0.0_vp).ConvertToPx();
8176 dumpLog.AddDesc(std::string("lineHeight:").append(std::to_string(lineHeight)));
8177 auto maxLines = GreatOrEqual(GetMaxLines(), Infinity<uint32_t>()) ? "INF" : std::to_string(GetMaxLines());
8178 dumpLog.AddDesc(std::string("MaxLines:").append(maxLines));
8179 dumpLog.AddDesc(std::string("TextIndent:").append(GetTextIndent()));
8180 dumpLog.AddDesc(std::string("showError:").append(GetErrorTextState() ?
8181 UtfUtils::Str16DebugToStr8(GetErrorTextString()) : "undefined"));
8182 dumpLog.AddDesc(std::string("CopyOption:").append(GetCopyOptionString()));
8183 dumpLog.AddDesc(std::string("TextAlign:").append(V2::ConvertWrapTextAlignToString(GetTextAlign())));
8184 dumpLog.AddDesc(std::string("CaretPosition:").append(std::to_string(GetCaretIndex())));
8185 dumpLog.AddDesc(std::string("type:").append(TextInputTypeToString()));
8186 dumpLog.AddDesc(std::string("enterKeyType:").append(TextInputActionToString()));
8187 dumpLog.AddDesc(std::string("HasFocus:").append(std::to_string(HasFocus())));
8188 dumpLog.AddDesc(std::string("enableKeyboardOnFocus:").append(std::to_string(needToRequestKeyboardOnFocus_)));
8189 dumpLog.AddDesc(std::string("supportPreviewText:").append(std::to_string(GetSupportPreviewText())));
8190 dumpLog.AddDesc(
8191 std::string("enableAutoFill:").append(std::to_string(layoutProperty->GetEnableAutoFillValue(true))));
8192 dumpLog.AddDesc(std::string("contentType:").append(TextContentTypeToString()));
8193 dumpLog.AddDesc(std::string("style:").append(GetInputStyleString()));
8194 dumpLog.AddDesc(std::string("PreviewTextStart:").append(std::to_string(GetPreviewTextStart())));
8195 dumpLog.AddDesc(std::string("PreviewTextEnd:").append(std::to_string(GetPreviewTextEnd())));
8196 dumpLog.AddDesc(std::string("PreTextValue:").append(UtfUtils::Str16DebugToStr8(GetPreviewTextValue())));
8197 dumpLog.AddDesc(textSelector_.ToString());
8198 dumpLog.AddDesc(std::string("wordBreak:")
8199 .append(V2::ConvertWrapWordBreakToString(layoutProperty->GetWordBreak().value_or(WordBreak::BREAK_WORD))));
8200 dumpLog.AddDesc(std::string("HeightAdaptivePolicy: ").append(V2::ConvertWrapTextHeightAdaptivePolicyToString(
8201 layoutProperty->GetHeightAdaptivePolicy().value_or(TextHeightAdaptivePolicy::MAX_LINES_FIRST))));
8202 dumpLog.AddDesc(std::string("IsAIWrite: ").append(std::to_string(IsShowAIWrite())));
8203 DumpPlaceHolderInfo();
8204 DumpScaleInfo();
8205 DumpTextEngineInfo();
8206 DumpAdvanceInfo();
8207 }
8208
8209 void TextFieldPattern::DumpTextEngineInfo()
8210 {
8211 auto& dumpLog = DumpLog::GetInstance();
8212 dumpLog.AddDesc(std::string("-----TextEngine paragraphs_ info-----"));
8213 CHECK_NULL_VOID(paragraph_);
8214 dumpLog.AddDesc(std::string("GetTextWidth:")
8215 .append(std::to_string(paragraph_->GetTextWidth()))
8216 .append(" GetHeight:")
8217 .append(std::to_string(paragraph_->GetHeight()))
8218 .append(" GetMaxWidth:")
8219 .append(std::to_string(paragraph_->GetMaxWidth()))
8220 .append(" GetMaxIntrinsicWidth:")
8221 .append(std::to_string(paragraph_->GetMaxIntrinsicWidth())));
8222 dumpLog.AddDesc(std::string("GetLineCount:")
8223 .append(std::to_string(paragraph_->GetLineCount()))
8224 .append(" GetLongestLine:")
8225 .append(std::to_string(paragraph_->GetLongestLine()))
8226 .append(" GetLongestLineWithIndent:")
8227 .append(std::to_string(paragraph_->GetLongestLineWithIndent())));
8228 }
8229
8230 void TextFieldPattern::DumpAdvanceInfo()
8231 {
8232 if (customKeyboard_ || customKeyboardBuilder_) {
8233 DumpLog::GetInstance().AddDesc(
8234 std::string("CustomKeyboard: true, Attached:").append(std::to_string(isCustomKeyboardAttached_)));
8235 }
8236 DumpLog::GetInstance().AddDesc(std::string("FontColor: ").append(GetTextColor()));
8237 #if defined(ENABLE_STANDARD_INPUT)
8238 auto miscTextConfig = GetMiscTextConfig();
8239 CHECK_NULL_VOID(miscTextConfig.has_value());
8240 MiscServices::TextConfig textConfig = miscTextConfig.value();
8241 DumpLog::GetInstance().AddDesc(
8242 std::string("RequestKeyboard calling window :").append(std::to_string(textConfig.windowId)));
8243 MiscServices::CursorInfo cursorInfo = miscTextConfig.value().cursorInfo;
8244 DumpLog::GetInstance().AddDesc(std::string("cursorInfo, left:")
8245 .append(std::to_string(cursorInfo.left))
8246 .append(", top:")
8247 .append(std::to_string(cursorInfo.top))
8248 .append(", width:")
8249 .append(std::to_string(cursorInfo.width))
8250 .append(", height:")
8251 .append(std::to_string(cursorInfo.height)));
8252 #endif
8253 DumpLog::GetInstance().AddDesc(std::string("textRect: ").append(contentRect_.ToString()));
8254 DumpLog::GetInstance().AddDesc(std::string("contentRect: ").append(contentRect_.ToString()));
8255 }
8256
8257 void TextFieldPattern::DumpPlaceHolderInfo()
8258 {
8259 DumpLog::GetInstance().AddDesc(std::string("placeholder: ").append(UtfUtils::Str16DebugToStr8(GetPlaceHolder())));
8260 DumpLog::GetInstance().AddDesc(std::string("placeholderColor: ").append(GetPlaceholderColor()));
8261 DumpLog::GetInstance().AddDesc(std::string("placeholderFont: ").append(GetPlaceholderFont()));
8262 }
8263
8264 void TextFieldPattern::DumpScaleInfo()
8265 {
8266 auto& dumpLog = DumpLog::GetInstance();
8267 dumpLog.AddDesc(std::string("-----DumpScaleInfo-----"));
8268 dumpLog.AddDesc(std::string("MinFontSize:").append(GetMinFontSize()));
8269 dumpLog.AddDesc(std::string("MaxFontSize:").append(GetMaxFontSize()));
8270 auto textLayoutProp = GetLayoutProperty<TextFieldLayoutProperty>();
8271 auto minFontScale = textLayoutProp->GetMinFontScale().value_or(0.0f);
8272 dumpLog.AddDesc(std::string("minFontScale: ").append(std::to_string(minFontScale)));
8273 auto maxfontScale = textLayoutProp->GetMaxFontScale().value_or(static_cast<float>(INT32_MAX));
8274 dumpLog.AddDesc(std::string("maxFontScale1: ").append(std::to_string(maxfontScale)));
8275 auto host = GetHost();
8276 CHECK_NULL_VOID(host);
8277 auto pipeline = host->GetContext();
8278 CHECK_NULL_VOID(pipeline);
8279 auto fontScale = pipeline->GetFontScale();
8280 auto fontWeightScale = pipeline->GetFontWeightScale();
8281 auto followSystem = pipeline->IsFollowSystem();
8282 float maxFontScale = pipeline->GetMaxAppFontScale();
8283 auto halfLeading = pipeline->GetHalfLeading();
8284 dumpLog.AddDesc(std::string("fontScale: ").append(std::to_string(fontScale)));
8285 dumpLog.AddDesc(std::string("fontWeightScale: ").append(std::to_string(fontWeightScale)));
8286 dumpLog.AddDesc(std::string("IsFollowSystem: ").append(std::to_string(followSystem)));
8287 dumpLog.AddDesc(std::string("maxFontScale: ").append(std::to_string(maxFontScale)));
8288 dumpLog.AddDesc(std::string("halfLeading: ").append(std::to_string(halfLeading)));
8289 }
8290
8291 std::string TextFieldPattern::GetDumpTextValue() const
8292 {
8293 if (IsInPasswordMode()) {
8294 auto len = GetTextValue().length();
8295 auto passwordLen = "passwordLen:" + std::to_string(len);
8296 return passwordLen;
8297 } else {
8298 return GetTextValue();
8299 }
8300 }
8301
8302 void TextFieldPattern::DumpViewDataPageNode(RefPtr<ViewDataWrap> viewDataWrap, bool needsRecordData)
8303 {
8304 CHECK_NULL_VOID(viewDataWrap);
8305 auto host = GetHost();
8306 CHECK_NULL_VOID(host);
8307 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
8308 CHECK_NULL_VOID(layoutProperty);
8309 auto autoFillTypeAndMetaData = GetAutoFillTypeAndMetaData();
8310 auto info = PageNodeInfoWrap::CreatePageNodeInfoWrap();
8311 CHECK_NULL_VOID(info);
8312 info->SetId(host->GetId());
8313 info->SetDepth(host->GetDepth());
8314 info->SetAutoFillType(autoFillTypeAndMetaData.autoFillType);
8315 info->SetMetadata(autoFillTypeAndMetaData.metadata);
8316 info->SetTag(host->GetTag());
8317 auto utf8TextValue = UtfUtils::Str16DebugToStr8(contentController_->GetTextUtf16Value());
8318 if (autoFillOtherAccount_) {
8319 viewDataWrap->SetOtherAccount(true);
8320 info->SetValue(utf8TextValue);
8321 autoFillOtherAccount_ = false;
8322 } else {
8323 info->SetValue(utf8TextValue);
8324 }
8325 if (needsRecordData) {
8326 lastAutoFillTextValue_ = utf8TextValue;
8327 }
8328 info->SetPlaceholder(UtfUtils::Str16DebugToStr8(GetPlaceHolder()));
8329 info->SetPasswordRules(layoutProperty->GetPasswordRulesValue(""));
8330 info->SetEnableAutoFill(layoutProperty->GetEnableAutoFillValue(true));
8331 auto offsetToWindow = host->GetTransformRelativeOffset();
8332 auto geometryNode = host->GetGeometryNode();
8333 CHECK_NULL_VOID(geometryNode);
8334 auto pageNodeRect = geometryNode->GetFrameRect();
8335 pageNodeRect.SetLeft(offsetToWindow.GetX());
8336 pageNodeRect.SetTop(offsetToWindow.GetY());
8337 info->SetPageNodeRect(pageNodeRect);
8338 info->SetIsFocus(HasFocus());
8339 viewDataWrap->AddPageNodeInfoWrap(info);
8340 }
8341
8342 void TextFieldPattern::NotifyFillRequestSuccess(RefPtr<ViewDataWrap> viewDataWrap,
8343 RefPtr<PageNodeInfoWrap> nodeWrap, AceAutoFillType autoFillType)
8344 {
8345 TAG_LOGI(AceLogTag::ACE_AUTO_FILL, "autoFillType:%{public}d", static_cast<int32_t>(autoFillType));
8346 SetFillRequestFinish(true);
8347 auto host = GetHost();
8348 CHECK_NULL_VOID(host);
8349 CHECK_NULL_VOID(viewDataWrap);
8350 CHECK_NULL_VOID(nodeWrap);
8351 auto isFocus = nodeWrap->GetIsFocus();
8352 if (isFocus && !HasFocus()) {
8353 TextFieldRequestFocus(RequestFocusReason::AUTO_FILL);
8354 DoProcessAutoFill();
8355 }
8356 auto type = GetAutoFillType();
8357 bool fromOtherAccount = viewDataWrap->GetOtherAccount();
8358 if (!(type == AceAutoFillType::ACE_NEW_PASSWORD && type == autoFillType) && !fromOtherAccount) {
8359 TAG_LOGI(AceLogTag::ACE_AUTO_FILL, "Set last auto fill text value.");
8360 lastAutoFillTextValue_ = nodeWrap->GetValue();
8361 }
8362 if (!contentController_ || contentController_->GetTextValue() == nodeWrap->GetValue()) {
8363 return;
8364 }
8365 RemoveFillContentMap();
8366 BeforeAutoFillAnimation(UtfUtils::Str8DebugToStr16(nodeWrap->GetValue()), type);
8367 }
8368
8369 void TextFieldPattern::NotifyFillRequestFailed(int32_t errCode, const std::string& fillContent, bool isPopup)
8370 {
8371 TAG_LOGI(AceLogTag::ACE_AUTO_FILL, "NotifyFillRequestFailed errCode:%{public}d", errCode);
8372 SetFillRequestFinish(true);
8373
8374 #if defined(ENABLE_STANDARD_INPUT)
8375 TAG_LOGI(AceLogTag::ACE_AUTO_FILL, "fillContent size is : %{public}zu", fillContent.size());
8376 if (errCode == AUTO_FILL_CANCEL) {
8377 if (!fillContent.empty() && IsTriggerAutoFillPassword()) {
8378 auto jsonObject = JsonUtil::ParseJsonString(fillContent);
8379 CHECK_NULL_VOID(jsonObject);
8380 auto host = GetHost();
8381 CHECK_NULL_VOID(host);
8382 auto context = host->GetContext();
8383 CHECK_NULL_VOID(context);
8384 auto textFieldManager = DynamicCast<TextFieldManagerNG>(context->GetTextFieldManager());
8385 CHECK_NULL_VOID(textFieldManager);
8386 textFieldManager->ParseFillContentJsonValue(jsonObject);
8387 }
8388 }
8389 if (!isPopup || (isPopup && errCode == AUTO_FILL_CANCEL)) {
8390 if (RequestKeyboardNotByFocusSwitch(RequestKeyboardReason::AUTO_FILL_REQUEST_FAIL)) {
8391 NotifyOnEditChanged(true);
8392 }
8393 }
8394 #endif
8395 }
8396
8397 bool TextFieldPattern::CheckAutoSave()
8398 {
8399 auto host = GetHost();
8400 CHECK_NULL_RETURN(host, false);
8401 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
8402 CHECK_NULL_RETURN(layoutProperty, false);
8403 if (!layoutProperty->GetEnableAutoFillValue(true)) {
8404 return false;
8405 }
8406 if (!contentController_ || contentController_->GetTextUtf16Value().empty()) {
8407 return false;
8408 }
8409 auto autoFillType = GetAutoFillType();
8410 if (IsAutoFillUserName(autoFillType)) {
8411 if (!lastAutoFillTextValue_.empty() &&
8412 contentController_->GetTextValue() != lastAutoFillTextValue_) {
8413 return true;
8414 }
8415 }
8416 if (AceAutoFillType::ACE_UNSPECIFIED < autoFillType && autoFillType <= AceAutoFillType::END &&
8417 !IsAutoFillUserName(autoFillType)) {
8418 if (contentController_->GetTextValue() != lastAutoFillTextValue_) {
8419 return true;
8420 }
8421 }
8422 return false;
8423 }
8424
8425 bool TextFieldPattern::IsTouchAtLeftOffset(float currentOffsetX)
8426 {
8427 return LessNotEqual(currentOffsetX, contentRect_.GetX() + contentRect_.Width() * 0.5);
8428 }
8429
8430 OffsetF TextFieldPattern::GetDragUpperLeftCoordinates()
8431 {
8432 if (!IsSelected()) {
8433 return { 0.0f, 0.0f };
8434 }
8435 auto selectRects = selectController_->GetSelectedRects();
8436 auto startY = selectRects.front().Top();
8437 auto startX = selectRects.front().Left();
8438 auto endY = selectRects.back().Top();
8439 OffsetF startOffset;
8440 if (NearEqual(startY, endY)) {
8441 startOffset = { (IsTextArea() ? contentRect_.GetX() : textRect_.GetX()) + startX,
8442 startY + (IsTextArea() ? textRect_.GetY() : contentRect_.GetY()) };
8443 } else {
8444 startOffset = { contentRect_.GetX(), startY + (IsTextArea() ? textRect_.GetY() : contentRect_.GetY()) };
8445 }
8446
8447 if (startOffset.GetY() < contentRect_.GetY()) {
8448 startOffset.SetY(contentRect_.GetY());
8449 }
8450 if (startOffset.GetX() < contentRect_.GetX()) {
8451 startOffset.SetX(contentRect_.GetX());
8452 }
8453 return startOffset + GetPaintRectGlobalOffset();
8454 }
8455
8456 void TextFieldPattern::OnColorConfigurationUpdate()
8457 {
8458 ScrollablePattern::OnColorConfigurationUpdate();
8459 auto host = GetHost();
8460 CHECK_NULL_VOID(host);
8461 auto theme = GetTheme();
8462 CHECK_NULL_VOID(theme);
8463 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
8464 CHECK_NULL_VOID(layoutProperty);
8465 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
8466 CHECK_NULL_VOID(paintProperty);
8467 if (!paintProperty->HasTextColorFlagByUser()) {
8468 layoutProperty->UpdateTextColor(theme->GetTextColor());
8469 }
8470 if (magnifierController_) {
8471 magnifierController_->SetColorModeChange(true);
8472 }
8473 auto context = host->GetContext();
8474 CHECK_NULL_VOID(context);
8475 auto colorMode = context->GetColorMode();
8476 SetOriginCursorColor(colorMode == ColorMode::DARK ? Color(0x4DFFFFFF) : Color(0x4D000000));
8477 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
8478 }
8479
8480 bool TextFieldPattern::IsReachedBoundary(float offset)
8481 {
8482 if (IsTextArea()) {
8483 return (NearEqual(textRect_.GetY(), contentRect_.GetY()) && GreatNotEqual(offset, 0.0f)) ||
8484 (NearEqual(textRect_.GetY() + textRect_.Height(), contentRect_.GetY() + contentRect_.Height()) &&
8485 LessNotEqual(offset, 0.0f));
8486 }
8487
8488 return (NearEqual(textRect_.GetX(), contentRect_.GetX()) && GreatNotEqual(offset, 0.0f)) ||
8489 (NearEqual(textRect_.GetX() + textRect_.Width(), contentRect_.GetX() + contentRect_.Width()) &&
8490 LessNotEqual(offset, 0.0f));
8491 }
8492
8493 OffsetF TextFieldPattern::GetTextPaintOffset() const
8494 {
8495 return GetPaintRectGlobalOffset();
8496 }
8497
8498 OffsetF TextFieldPattern::GetPaintRectGlobalOffset() const
8499 {
8500 auto host = GetHost();
8501 CHECK_NULL_RETURN(host, OffsetF(0.0f, 0.0f));
8502 auto pipeline = host->GetContextRefPtr();
8503 CHECK_NULL_RETURN(pipeline, OffsetF(0.0f, 0.0f));
8504 auto rootOffset = pipeline->GetRootRect().GetOffset();
8505 OffsetF textPaintOffset;
8506 textPaintOffset = host->GetPaintRectOffsetNG(false, true);
8507 return textPaintOffset - rootOffset;
8508 }
8509
8510 void TextFieldPattern::UpdateSelectController()
8511 {
8512 selectController_->UpdateContentRect(contentRect_);
8513 selectController_->UpdateParagraph(paragraph_);
8514 }
8515
8516 bool TextFieldPattern::RepeatClickCaret(const Offset& offset, int32_t lastCaretIndex)
8517 {
8518 auto touchDownIndex = selectController_->ConvertTouchOffsetToPosition(offset);
8519 return lastCaretIndex == touchDownIndex && HasFocus();
8520 }
8521
8522 bool TextFieldPattern::RepeatClickCaret(const Offset& offset, const RectF& lastCaretRect)
8523 {
8524 auto caretRect = lastCaretRect;
8525 caretRect.SetLeft(caretRect.GetX() - caretRect.Height() / 2);
8526 caretRect.SetWidth(caretRect.Height());
8527 return caretRect.IsInRegion(PointF(offset.GetX(), offset.GetY()));
8528 }
8529
8530 void TextFieldPattern::OnAttachToFrameNode()
8531 {
8532 auto frameNode = GetHost();
8533 CHECK_NULL_VOID(frameNode);
8534 THREAD_SAFE_NODE_CHECK(frameNode, OnAttachToFrameNode); // call OnAttachToFrameNodeMultiThread() by multi thread
8535 StylusDetectorMgr::GetInstance()->AddTextFieldFrameNode(frameNode, WeakClaim(this));
8536
8537 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
8538 CHECK_NULL_VOID(layoutProperty);
8539 layoutProperty->UpdateCopyOptions(CopyOptions::Local);
8540 auto pipeline = frameNode->GetContext();
8541 CHECK_NULL_VOID(pipeline);
8542 auto fontManager = pipeline->GetFontManager();
8543 if (fontManager) {
8544 auto host = GetHost();
8545 fontManager->AddFontNodeNG(host);
8546 }
8547 auto onTextSelectorChange = [weak = WeakClaim(this)]() {
8548 auto pattern = weak.Upgrade();
8549 CHECK_NULL_VOID(pattern);
8550 auto frameNode = pattern->GetHost();
8551 CHECK_NULL_VOID(frameNode);
8552 frameNode->OnAccessibilityEvent(AccessibilityEventType::TEXT_SELECTION_UPDATE);
8553 };
8554 selectController_->SetOnAccessibility(std::move(onTextSelectorChange));
8555 }
8556
8557 bool TextFieldPattern::NeedPaintSelect()
8558 {
8559 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
8560 CHECK_NULL_RETURN(paintProperty, false);
8561 auto firstHandle = paintProperty->GetFirstHandleInfo();
8562 auto secondHandle = paintProperty->GetSecondHandleInfo();
8563 auto caretInfo = selectController_->GetCaretInfo();
8564 if (!IsSelected()) {
8565 if (!firstHandle.has_value() || !secondHandle.has_value()) {
8566 paintProperty->UpdateFirstHandleInfo(caretInfo);
8567 paintProperty->UpdateSecondHandleInfo(caretInfo);
8568 return false;
8569 }
8570
8571 if (firstHandle->index != secondHandle->index || firstHandle->index != caretInfo.index) {
8572 paintProperty->UpdateFirstHandleInfo(caretInfo);
8573 paintProperty->UpdateSecondHandleInfo(caretInfo);
8574 return true;
8575 }
8576 return false;
8577 }
8578 auto needPaint = firstHandle != selectController_->GetFirstHandleInfo() ||
8579 secondHandle != selectController_->GetSecondHandleInfo();
8580 paintProperty->UpdateFirstHandleInfo(selectController_->GetFirstHandleInfo());
8581 paintProperty->UpdateSecondHandleInfo(selectController_->GetSecondHandleInfo());
8582 return needPaint;
8583 }
8584
8585 RefPtr<FocusHub> TextFieldPattern::GetFocusHub() const
8586 {
8587 auto host = GetHost();
8588 CHECK_NULL_RETURN(host, nullptr);
8589 auto focusHub = host->GetOrCreateFocusHub();
8590 return focusHub;
8591 }
8592
8593 void TextFieldPattern::OnObscuredChanged(bool isObscured)
8594 {
8595 ResetObscureTickCountDown();
8596 obscuredChange_ = textObscured_ != isObscured;
8597 textObscured_ = isObscured;
8598 CloseSelectOverlay(false);
8599 StartTwinkling();
8600 if (obscuredChange_) {
8601 selectController_->UpdateCaretIndex(static_cast<int32_t>(contentController_->GetTextUtf16Value().length()));
8602 }
8603 auto host = GetHost();
8604 CHECK_NULL_VOID(host);
8605 if (obscuredChange_) {
8606 auto eventHub = host->GetOrCreateEventHub<TextFieldEventHub>();
8607 CHECK_NULL_VOID(eventHub);
8608 eventHub->FireOnSecurityStateChanged(!isObscured);
8609 }
8610 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
8611 }
8612
8613 void TextFieldPattern::CreateHandles()
8614 {
8615 if (IsDragging() || !HasFocus()) {
8616 return;
8617 }
8618 auto host = GetHost();
8619 CHECK_NULL_VOID(host);
8620 showSelect_ = true;
8621 if (selectOverlay_->IsUseTouchAtLast()) {
8622 SetIsSingleHandle(!IsSelected());
8623 ProcessOverlay({ .menuIsShow = false });
8624 }
8625 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
8626 }
8627
8628 void TextFieldPattern::NotifyOnEditChanged(bool isChanged)
8629 {
8630 auto host = GetHost();
8631 CHECK_NULL_VOID(host);
8632 auto eventHub = host->GetOrCreateEventHub<TextFieldEventHub>();
8633 CHECK_NULL_VOID(eventHub);
8634 if (isChanged != isEdit_) {
8635 isEdit_ = isChanged;
8636 eventHub->FireOnEditChanged(isChanged);
8637 }
8638 }
8639
8640 size_t TextFieldPattern::GetLineCount() const
8641 {
8642 return paragraph_ ? paragraph_->GetLineCount() : 0;
8643 }
8644
8645 void TextFieldPattern::UpdateHandlesOffsetOnScroll(float offset)
8646 {
8647 if (SelectOverlayIsOn()) {
8648 selectController_->UpdateSecondHandleOffset();
8649 if (!selectOverlay_->IsSingleHandle()) {
8650 selectController_->UpdateFirstHandleOffset();
8651 selectController_->UpdateCaretOffset(TextAffinity::DOWNSTREAM, false);
8652 selectOverlay_->UpdateAllHandlesOffset();
8653 } else {
8654 selectController_->UpdateCaretOffset(IsTextArea() ? OffsetF(0.0f, offset) : OffsetF(offset, 0.0f));
8655 selectOverlay_->UpdateSecondHandleOffset();
8656 }
8657 } else {
8658 selectController_->UpdateCaretOffset(IsTextArea() ? OffsetF(0.0f, offset) : OffsetF(offset, 0.0f));
8659 }
8660 }
8661
8662 void TextFieldPattern::CloseHandleAndSelect()
8663 {
8664 CloseSelectOverlay(true);
8665 showSelect_ = false;
8666 }
8667
8668 bool TextFieldPattern::IsShowUnit() const
8669 {
8670 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
8671 CHECK_NULL_RETURN(layoutProperty, false);
8672 auto typeValue = layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED);
8673 return layoutProperty->GetShowUnderlineValue(false) &&
8674 (typeValue == TextInputType::UNSPECIFIED || typeValue == TextInputType::TEXT) &&
8675 unitNode_ != nullptr;
8676 }
8677
8678 bool TextFieldPattern::IsShowPasswordIcon() const
8679 {
8680 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
8681 CHECK_NULL_RETURN(layoutProperty, false);
8682 auto textfieldTheme = GetTheme();
8683 CHECK_NULL_RETURN(textfieldTheme, false);
8684 bool isShowPasswordIcon = textfieldTheme->IsShowPasswordIcon();
8685 return layoutProperty->GetShowPasswordIconValue(isShowPasswordIcon) && IsInPasswordMode();
8686 }
8687
8688 std::optional<bool> TextFieldPattern::IsShowPasswordText() const
8689 {
8690 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
8691 CHECK_NULL_RETURN(layoutProperty, false);
8692 return layoutProperty->GetShowPasswordText();
8693 }
8694
8695 bool TextFieldPattern::IsShowCancelButtonMode() const
8696 {
8697 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
8698 CHECK_NULL_RETURN(layoutProperty, false);
8699 return !IsNormalInlineState() && !IsTextArea() && layoutProperty->GetIsShowCancelButton().value_or(false);
8700 }
8701
8702 void TextFieldPattern::CheckPasswordAreaState()
8703 {
8704 auto showPasswordState = IsShowPasswordText();
8705 if (!showPasswordState.has_value()) {
8706 return;
8707 }
8708 auto passwordArea = AceType::DynamicCast<PasswordResponseArea>(responseArea_);
8709 CHECK_NULL_VOID(passwordArea);
8710 if (!showPasswordState_.has_value() || showPasswordState_.value() != showPasswordState.value()) {
8711 passwordArea->SetObscured(!showPasswordState.value());
8712 showPasswordState_ = showPasswordState.value();
8713 }
8714 }
8715
8716 void TextFieldPattern::AfterLayoutProcessCleanResponse(
8717 const RefPtr<CleanNodeResponseArea>& cleanNodeResponseArea)
8718 {
8719 CHECK_NULL_VOID(cleanNodeResponseArea);
8720 auto host = GetHost();
8721 CHECK_NULL_VOID(host);
8722 auto pipeline = host->GetContext();
8723 CHECK_NULL_VOID(pipeline);
8724 pipeline->AddAfterLayoutTask([weak = WeakClaim(Referenced::RawPtr(cleanNodeResponseArea))]() {
8725 auto cleanNodeResponseArea = weak.Upgrade();
8726 CHECK_NULL_VOID(cleanNodeResponseArea);
8727 cleanNodeResponseArea->UpdateCleanNode(cleanNodeResponseArea->IsShow());
8728 });
8729 }
8730
8731 void TextFieldPattern::ProcessCancelButton()
8732 {
8733 if (IsShowCancelButtonMode()) {
8734 auto cleanNodeResponseArea = AceType::DynamicCast<CleanNodeResponseArea>(cleanNodeResponseArea_);
8735 if (cleanNodeResponseArea) {
8736 cleanNodeResponseArea->Refresh();
8737 if (cleanNodeResponseArea->IsShow()) {
8738 AfterLayoutProcessCleanResponse(cleanNodeResponseArea);
8739 } else {
8740 UpdateCancelNode();
8741 }
8742 } else {
8743 cleanNodeResponseArea_ = AceType::MakeRefPtr<CleanNodeResponseArea>(WeakClaim(this));
8744 cleanNodeResponseArea = AceType::DynamicCast<CleanNodeResponseArea>(cleanNodeResponseArea_);
8745 cleanNodeResponseArea->InitResponseArea();
8746 UpdateCancelNode();
8747 AfterLayoutProcessCleanResponse(cleanNodeResponseArea);
8748 }
8749 } else {
8750 if (cleanNodeResponseArea_) {
8751 cleanNodeResponseArea_->ClearArea();
8752 cleanNodeResponseArea_.Reset();
8753 }
8754 }
8755 }
8756
8757 void TextFieldPattern::ProcessResponseArea()
8758 {
8759 ProcessCancelButton();
8760 if (IsInPasswordMode()) {
8761 auto passwordArea = AceType::DynamicCast<PasswordResponseArea>(responseArea_);
8762 if (passwordArea) {
8763 if (IsShowPasswordIcon()) {
8764 passwordArea->Refresh();
8765 } else {
8766 passwordArea->ClearArea();
8767 }
8768 CheckPasswordAreaState();
8769 return;
8770 }
8771 // responseArea_ may not be a password area.
8772 if (responseArea_) {
8773 responseArea_->ClearArea();
8774 }
8775 responseArea_ = AceType::MakeRefPtr<PasswordResponseArea>(WeakClaim(this), GetTextObscured());
8776 if (IsShowPasswordIcon()) {
8777 responseArea_->InitResponseArea();
8778 } else {
8779 responseArea_->ClearArea();
8780 }
8781 CheckPasswordAreaState();
8782 return;
8783 }
8784
8785 if (IsUnderlineMode()) {
8786 if (responseArea_) {
8787 responseArea_->ClearArea();
8788 }
8789 responseArea_ = AceType::MakeRefPtr<UnitResponseArea>(WeakClaim(this), unitNode_);
8790 responseArea_->InitResponseArea();
8791 auto host = GetHost();
8792 CHECK_NULL_VOID(host);
8793 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
8794 return;
8795 }
8796
8797 if (responseArea_) {
8798 responseArea_->ClearArea();
8799 }
8800 }
8801
8802 void TextFieldPattern::AdjustTextRectByCleanNode(RectF& textRect)
8803 {
8804 auto cleanNodeResponseArea = DynamicCast<CleanNodeResponseArea>(cleanNodeResponseArea_);
8805 CHECK_NULL_VOID(cleanNodeResponseArea);
8806 auto host = GetHost();
8807 CHECK_NULL_VOID(host);
8808 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
8809 CHECK_NULL_VOID(layoutProperty);
8810 auto cleanNodeStyle = layoutProperty->GetCleanNodeStyle().value_or(CleanNodeStyle::INPUT);
8811 auto isRTL = layoutProperty->GetNonAutoLayoutDirection() == TextDirection::RTL;
8812 if (isRTL && (cleanNodeStyle == CleanNodeStyle::CONSTANT ||
8813 (cleanNodeStyle == CleanNodeStyle::INPUT && !contentController_->IsEmpty()))) {
8814 auto textFieldTheme = GetTheme();
8815 CHECK_NULL_VOID(textFieldTheme);
8816 auto themePadding = textFieldTheme->GetPadding();
8817 auto rightOffset = static_cast<float>(themePadding.Left().ConvertToPx());
8818 textRect.SetLeft(textRect.GetX() + cleanNodeResponseArea->GetIconSize() + rightOffset);
8819 }
8820 }
8821
8822 void TextFieldPattern::UpdateCancelNode()
8823 {
8824 auto cleanNodeResponseArea = DynamicCast<CleanNodeResponseArea>(cleanNodeResponseArea_);
8825 CHECK_NULL_VOID(cleanNodeResponseArea);
8826 auto host = GetHost();
8827 CHECK_NULL_VOID(host);
8828 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
8829 CHECK_NULL_VOID(layoutProperty);
8830 auto cleanNodeStyle = layoutProperty->GetCleanNodeStyle().value_or(CleanNodeStyle::INPUT);
8831 if (cleanNodeStyle == CleanNodeStyle::CONSTANT ||
8832 (cleanNodeStyle == CleanNodeStyle::INPUT && !contentController_->IsEmpty())) {
8833 if (!cleanNodeResponseArea->IsShow() || cleanNodeResponseArea->CheckUpdateCleanNode()) {
8834 cleanNodeResponseArea->UpdateCleanNode(true);
8835 }
8836 } else if (cleanNodeStyle == CleanNodeStyle::INVISIBLE ||
8837 (cleanNodeStyle == CleanNodeStyle::INPUT && contentController_->IsEmpty())) {
8838 if (cleanNodeResponseArea->IsShow()) {
8839 cleanNodeResponseArea->UpdateCleanNode(false);
8840 }
8841 }
8842 }
8843
8844 bool TextFieldPattern::HasInputOperation()
8845 {
8846 return !deleteBackwardOperations_.empty() || !deleteForwardOperations_.empty() || !insertCommands_.empty();
8847 }
8848
8849 void TextFieldPattern::FocusForwardStopTwinkling()
8850 {
8851 auto host = GetHost();
8852 CHECK_NULL_VOID(host);
8853 UpdateSelection(selectController_->GetCaretIndex());
8854 StopTwinkling();
8855 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
8856 }
8857
8858 bool TextFieldPattern::UpdateFocusForward()
8859 {
8860 if (focusIndex_ == FocuseIndex::TEXT && HasFocus()) {
8861 FocusForwardStopTwinkling();
8862 if (!CancelNodeIsShow()) {
8863 if (responseArea_ == nullptr || (!IsShowUnit() && !IsShowPasswordIcon())) {
8864 return false;
8865 }
8866 focusIndex_ = FocuseIndex::UNIT;
8867 PaintResponseAreaRect();
8868 return true;
8869 }
8870 focusIndex_ = FocuseIndex::CANCEL;
8871 PaintCancelRect();
8872 return true;
8873 }
8874 if (focusIndex_ == FocuseIndex::CANCEL && HasFocus()) {
8875 FocusForwardStopTwinkling();
8876 if (responseArea_ == nullptr || (!IsShowUnit() && !IsShowPasswordIcon())) {
8877 return false;
8878 }
8879 focusIndex_ = FocuseIndex::UNIT;
8880 PaintResponseAreaRect();
8881 return true;
8882 }
8883 return false;
8884 }
8885
8886 bool TextFieldPattern::UpdateFocusBackward()
8887 {
8888 if (focusIndex_ == FocuseIndex::CANCEL && HasFocus()) {
8889 focusIndex_ = FocuseIndex::TEXT;
8890 PaintTextRect();
8891 StartTwinkling();
8892 return true;
8893 } else if (focusIndex_ == FocuseIndex::UNIT && HasFocus()) {
8894 if (!CancelNodeIsShow()) {
8895 focusIndex_ = FocuseIndex::TEXT;
8896 PaintTextRect();
8897 StartTwinkling();
8898 return true;
8899 }
8900 focusIndex_ = FocuseIndex::CANCEL;
8901 PaintCancelRect();
8902 return true;
8903 }
8904 return false;
8905 }
8906
8907 bool TextFieldPattern::HandleSpaceEvent()
8908 {
8909 if (focusIndex_ == FocuseIndex::CANCEL) {
8910 CleanNodeResponseKeyEvent();
8911 return true;
8912 } else if (focusIndex_ == FocuseIndex::UNIT) {
8913 if (IsShowPasswordIcon()) {
8914 PasswordResponseKeyEvent();
8915 }
8916 if (IsShowUnit()) {
8917 UnitResponseKeyEvent();
8918 }
8919 return true;
8920 }
8921 return false;
8922 }
8923
8924 void TextFieldPattern::PaintTextRect()
8925 {
8926 RoundRect focusRect;
8927 auto host = GetHost();
8928 CHECK_NULL_VOID(host);
8929 auto focusHub = host->GetFocusHub();
8930 CHECK_NULL_VOID(focusHub);
8931 focusHub->PaintInnerFocusState(focusRect);
8932 }
8933
8934 void TextFieldPattern::GetIconPaintRect(const RefPtr<TextInputResponseArea>& responseArea, RoundRect& paintRect)
8935 {
8936 auto stackNode = responseArea->GetFrameNode();
8937 CHECK_NULL_VOID(stackNode);
8938 auto stackRect = stackNode->GetGeometryNode()->GetFrameRect();
8939 auto imageNode = stackNode->GetFirstChild();
8940 CHECK_NULL_VOID(imageNode);
8941 auto imageFrameNode = AceType::DynamicCast<FrameNode>(imageNode);
8942 CHECK_NULL_VOID(imageFrameNode);
8943 auto imageRect = imageFrameNode->GetGeometryNode()->GetFrameRect();
8944 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
8945 CHECK_NULL_VOID(layoutProperty);
8946 auto isRTL = layoutProperty->GetNonAutoLayoutDirection() == TextDirection::RTL;
8947 RectF rect;
8948 if (isRTL) {
8949 rect = RectF(stackRect.GetX() + stackRect.Width() - imageRect.Width(),
8950 stackRect.GetY(), imageRect.Width(), imageRect.Height());
8951 } else {
8952 rect = RectF(stackRect.GetX(), stackRect.GetY(), imageRect.Width(), imageRect.Height());
8953 }
8954 paintRect.SetRect(rect);
8955 }
8956
8957 void TextFieldPattern::GetInnerFocusPaintRect(RoundRect& paintRect)
8958 {
8959 auto host = GetHost();
8960 CHECK_NULL_VOID(host);
8961 if (focusIndex_ == FocuseIndex::CANCEL) {
8962 CHECK_NULL_VOID(cleanNodeResponseArea_);
8963 GetIconPaintRect(cleanNodeResponseArea_, paintRect);
8964 if (host->GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
8965 cleanNodeResponseArea_->CreateIconRect(paintRect, true);
8966 float cornerRadius = paintRect.GetRect().Width() / 2;
8967 paintRect.SetCornerRadius(cornerRadius);
8968 }
8969 } else if (focusIndex_ == FocuseIndex::UNIT) {
8970 if (IsShowPasswordIcon()) {
8971 CHECK_NULL_VOID(responseArea_);
8972 GetIconPaintRect(responseArea_, paintRect);
8973 if (host->GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
8974 responseArea_->CreateIconRect(paintRect, true);
8975 }
8976 float cornerRadius = paintRect.GetRect().Width() / 2;
8977 paintRect.SetCornerRadius(cornerRadius);
8978 }
8979 if (IsShowUnit()) {
8980 CHECK_NULL_VOID(responseArea_);
8981 auto unitResponseArea = AceType::DynamicCast<UnitResponseArea>(responseArea_);
8982 CHECK_NULL_VOID(unitResponseArea);
8983 auto unitNode = unitResponseArea->GetFrameNode();
8984 CHECK_NULL_VOID(unitNode);
8985 auto unitRect = unitNode->GetGeometryNode()->GetFrameRect();
8986 paintRect.SetRect(unitRect);
8987 }
8988 } else {
8989 GetTextInputFocusPaintRect(paintRect);
8990 }
8991 }
8992
8993 void TextFieldPattern::GetTextInputFocusPaintRect(RoundRect& paintRect)
8994 {
8995 auto textfieldTheme = GetTheme();
8996 CHECK_NULL_VOID(textfieldTheme);
8997 auto isNeedFocusBox = textfieldTheme->NeedFocusBox();
8998 if (!isNeedFocusBox) {
8999 return;
9000 }
9001 auto host = GetHost();
9002 CHECK_NULL_VOID(host);
9003 auto geometryNode = host->GetGeometryNode();
9004 CHECK_NULL_VOID(geometryNode);
9005 auto textInputSize = geometryNode->GetFrameSize();
9006 auto focusPaintPadding = textfieldTheme->GetFocusPadding().ConvertToPx();
9007 float width = textInputSize.Width() + 2 * focusPaintPadding;
9008 float height = textInputSize.Height() + 2 * focusPaintPadding;
9009 paintRect.SetRect({ -focusPaintPadding, -focusPaintPadding, width, height });
9010 auto renderContext = host->GetRenderContext();
9011 CHECK_NULL_VOID(renderContext);
9012 auto radius = renderContext->GetBorderRadius().value_or(BorderRadiusProperty());
9013 paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_LEFT_POS,
9014 static_cast<float>(radius.radiusTopLeft->ConvertToPx() + focusPaintPadding),
9015 static_cast<float>(radius.radiusTopLeft->ConvertToPx() + focusPaintPadding));
9016 paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_RIGHT_POS,
9017 static_cast<float>(radius.radiusTopRight->ConvertToPx() + focusPaintPadding),
9018 static_cast<float>(radius.radiusTopRight->ConvertToPx() + focusPaintPadding));
9019 paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_LEFT_POS,
9020 static_cast<float>(radius.radiusBottomLeft->ConvertToPx() + focusPaintPadding),
9021 static_cast<float>(radius.radiusBottomLeft->ConvertToPx() + focusPaintPadding));
9022 paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_RIGHT_POS,
9023 static_cast<float>(radius.radiusBottomRight->ConvertToPx() + focusPaintPadding),
9024 static_cast<float>(radius.radiusBottomRight->ConvertToPx() + focusPaintPadding));
9025 }
9026
9027 void TextFieldPattern::PaintCancelRect()
9028 {
9029 RoundRect focusRect;
9030 GetInnerFocusPaintRect(focusRect);
9031 auto host = GetHost();
9032 CHECK_NULL_VOID(host);
9033 auto focusHub = host->GetFocusHub();
9034 CHECK_NULL_VOID(focusHub);
9035 focusHub->PaintInnerFocusState(focusRect);
9036 }
9037
9038 void TextFieldPattern::PaintResponseAreaRect()
9039 {
9040 if (IsShowPasswordIcon()) {
9041 PaintPasswordRect();
9042 }
9043 if (IsShowUnit()) {
9044 PaintUnitRect();
9045 }
9046 }
9047
9048 void TextFieldPattern::PaintPasswordRect()
9049 {
9050 RoundRect focusRect;
9051 GetInnerFocusPaintRect(focusRect);
9052 auto host = GetHost();
9053 CHECK_NULL_VOID(host);
9054 auto focusHub = host->GetFocusHub();
9055 CHECK_NULL_VOID(focusHub);
9056 focusHub->PaintInnerFocusState(focusRect);
9057 }
9058
9059 void TextFieldPattern::PaintUnitRect()
9060 {
9061 RoundRect focusRect;
9062 GetInnerFocusPaintRect(focusRect);
9063 auto host = GetHost();
9064 CHECK_NULL_VOID(host);
9065 auto focusHub = host->GetFocusHub();
9066 CHECK_NULL_VOID(focusHub);
9067 focusHub->PaintInnerFocusState(focusRect);
9068 }
9069
9070 void TextFieldPattern::CleanNodeResponseKeyEvent()
9071 {
9072 CHECK_NULL_VOID(!IsDragging());
9073 auto host = GetHost();
9074 CHECK_NULL_VOID(host);
9075 ClearTextContent();
9076 CloseSelectOverlay();
9077 SetFloatingCursorVisible(false);
9078 StartTwinkling();
9079 UpdateCaretInfoToController();
9080 if (!HasFocus()) {
9081 auto focusHub = host->GetOrCreateFocusHub();
9082 TextFieldRequestFocus(RequestFocusReason::CLEAN_NODE);
9083 }
9084 host->MarkModifyDone();
9085 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
9086
9087 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
9088 CHECK_NULL_VOID(layoutProperty);
9089 auto cleanNodeStyle = layoutProperty->GetCleanNodeStyle().value_or(CleanNodeStyle::INPUT);
9090 if (cleanNodeStyle == CleanNodeStyle::INPUT) {
9091 focusIndex_ = FocuseIndex::TEXT;
9092 }
9093 }
9094
9095 void TextFieldPattern::OnWindowSizeChanged(int32_t width, int32_t height, WindowSizeChangeReason type)
9096 {
9097 if (selectOverlay_) {
9098 selectOverlay_->UpdateMenuOnWindowSizeChanged(type);
9099 }
9100 if (type != WindowSizeChangeReason::ROTATION) {
9101 return;
9102 }
9103 if (SelectOverlayIsOn()) {
9104 selectController_->CalculateHandleOffset();
9105 selectOverlay_->ProcessOverlayOnAreaChanged({ .menuIsShow = false});
9106 }
9107 auto host = GetHost();
9108 CHECK_NULL_VOID(host);
9109 auto context = host->GetContextRefPtr();
9110 CHECK_NULL_VOID(context);
9111 auto taskExecutor = context->GetTaskExecutor();
9112 CHECK_NULL_VOID(taskExecutor);
9113 auto textFieldManager = DynamicCast<TextFieldManagerNG>(context->GetTextFieldManager());
9114 CHECK_NULL_VOID(textFieldManager);
9115 textFieldManager->ResetOptionalClickPosition();
9116 lastCaretPos_ = std::nullopt;
9117 taskExecutor->PostTask(
9118 [weak = WeakClaim(this), manager = WeakPtr<TextFieldManagerNG>(textFieldManager)] {
9119 auto textField = weak.Upgrade();
9120 CHECK_NULL_VOID(textField);
9121 auto host = textField->GetHost();
9122 CHECK_NULL_VOID(host);
9123 auto nodeId = host->GetId();
9124 textField->parentGlobalOffset_ = textField->GetPaintRectGlobalOffset();
9125 textField->UpdateTextFieldManager(Offset(textField->parentGlobalOffset_.GetX(),
9126 textField->parentGlobalOffset_.GetY()), textField->frameRect_.Height());
9127 if (textField->HasFocus()) {
9128 textField->UpdateCaretInfoToController(true);
9129 TAG_LOGI(ACE_TEXT_FIELD, "%{public}d OnWindowSizeChanged change parentGlobalOffset to: %{public}s",
9130 nodeId, textField->parentGlobalOffset_.ToString().c_str());
9131 auto textFieldManager = manager.Upgrade();
9132 CHECK_NULL_VOID(textFieldManager);
9133 auto container = Container::Current();
9134 CHECK_NULL_VOID(container);
9135 auto displayInfo = container->GetDisplayInfo();
9136 if (displayInfo) {
9137 auto dmRotation = static_cast<int32_t>(displayInfo->GetRotation());
9138 textFieldManager->SetFocusFieldOrientation(dmRotation);
9139 }
9140 }
9141 },
9142 TaskExecutor::TaskType::UI, "ArkUITextFieldOnWindowSizeChangedRotation");
9143 }
9144
9145 void TextFieldPattern::PasswordResponseKeyEvent()
9146 {
9147 auto passwordArea = AceType::DynamicCast<PasswordResponseArea>(responseArea_);
9148 CHECK_NULL_VOID(passwordArea);
9149 passwordArea->OnPasswordIconClicked();
9150 }
9151
9152 void TextFieldPattern::UnitResponseKeyEvent()
9153 {
9154 auto unitArea = AceType::DynamicCast<UnitResponseArea>(responseArea_);
9155 CHECK_NULL_VOID(unitArea);
9156 auto frameNode = unitArea->GetFrameNode();
9157 CHECK_NULL_VOID(frameNode);
9158 if (frameNode->GetTag() == V2::SELECT_ETS_TAG) {
9159 auto selectPattern = frameNode->GetPattern<SelectPattern>();
9160 CHECK_NULL_VOID(selectPattern);
9161 selectPattern->ShowSelectMenu();
9162 }
9163 }
9164
9165 void TextFieldPattern::ScrollToSafeArea() const
9166 {
9167 auto host = GetHost();
9168 CHECK_NULL_VOID(host);
9169 auto pipeline = host->GetContext();
9170 CHECK_NULL_VOID(pipeline);
9171 if (pipeline->UsingCaretAvoidMode()) {
9172 // using TriggerAvoidOnCaretChange instead in CaretAvoidMode
9173 return;
9174 }
9175 auto textFieldManager = DynamicCast<TextFieldManagerNG>(pipeline->GetTextFieldManager());
9176 CHECK_NULL_VOID(textFieldManager);
9177 textFieldManager->ScrollTextFieldToSafeArea();
9178 }
9179
9180 void TextFieldPattern::TriggerAvoidOnCaretChange()
9181 {
9182 CHECK_NULL_VOID(HasFocus());
9183 auto host = GetHost();
9184 CHECK_NULL_VOID(host);
9185 auto pipeline = host->GetContext();
9186 CHECK_NULL_VOID(pipeline);
9187 auto textFieldManager = DynamicCast<TextFieldManagerNG>(pipeline->GetTextFieldManager());
9188 CHECK_NULL_VOID(textFieldManager);
9189 CHECK_NULL_VOID(pipeline->UsingCaretAvoidMode());
9190 auto safeAreaManager = pipeline->GetSafeAreaManager();
9191 if (!safeAreaManager || NearEqual(safeAreaManager->GetKeyboardInset().Length(), 0)) {
9192 return;
9193 }
9194 if (selectOverlay_) {
9195 selectOverlay_->AddAvoidKeyboardCallback(isCustomKeyboardAttached_);
9196 }
9197 textFieldManager->TriggerAvoidOnCaretChange();
9198 auto caretPos = textFieldManager->GetFocusedNodeCaretRect().Top() + textFieldManager->GetHeight();
9199 SetLastCaretPos(caretPos);
9200 }
9201
9202 void TextFieldPattern::CheckTextAlignByDirection(TextAlign& textAlign, TextDirection direction)
9203 {
9204 if (direction == TextDirection::RTL) {
9205 if (textAlign == TextAlign::START) {
9206 textAlign = TextAlign::END;
9207 } else if (textAlign == TextAlign::END) {
9208 textAlign = TextAlign::START;
9209 }
9210 }
9211 }
9212
9213 void TextFieldPattern::RequestKeyboardAfterLongPress()
9214 {
9215 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
9216 if (isLongPress_ && HasFocus() && RequestKeyboardNotByFocusSwitch(RequestKeyboardReason::LONG_PRESS)) {
9217 NotifyOnEditChanged(true);
9218 if (!isCustomKeyboardAttached_ || keyboardAvoidance_) {
9219 selectOverlay_->AddAvoidKeyboardCallback(isCustomKeyboardAttached_);
9220 }
9221 }
9222 isLongPress_ = false;
9223 #endif
9224 }
9225
9226 void TextFieldPattern::GetCaretMetrics(CaretMetricsF& caretCaretMetric)
9227 {
9228 OffsetF offset = selectController_->GetCaretRect().GetOffset();
9229 float height = selectController_->GetCaretRect().Height();
9230 float width = selectController_->GetCaretRect().Width();
9231 auto host = GetHost();
9232 CHECK_NULL_VOID(host);
9233 auto textPaintOffset = host->GetPaintRectOffset(false, true);
9234 caretCaretMetric.offset = offset + textPaintOffset + OffsetF(width / 2.0f, 0.0f);
9235 caretCaretMetric.height = height;
9236 }
9237
9238 void TextFieldPattern::ScrollPage(bool reverse, bool smooth, AccessibilityScrollType scrollType)
9239 {
9240 auto border = GetBorderWidthProperty();
9241 float maxFrameHeight =
9242 frameRect_.Height() - GetPaddingTop() - GetPaddingBottom() - GetBorderTop(border) - GetBorderBottom(border);
9243 float distance = reverse ? maxFrameHeight : -maxFrameHeight;
9244 if (scrollType == AccessibilityScrollType::SCROLL_HALF) {
9245 distance = distance / 2.f;
9246 }
9247 OnScrollCallback(distance, SCROLL_FROM_JUMP);
9248 }
9249
9250 // correct after OnModifyDone
9251 bool TextFieldPattern::IsUnderlineMode() const
9252 {
9253 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
9254 CHECK_NULL_RETURN(layoutProperty, false);
9255 return layoutProperty->GetShowUnderlineValue(false) && IsUnspecifiedOrTextType() && !IsInlineMode();
9256 }
9257
9258 // correct after OnModifyDone
9259 bool TextFieldPattern::IsInlineMode() const
9260 {
9261 return HasFocus() && IsNormalInlineState();
9262 }
9263
9264 bool TextFieldPattern::IsShowError()
9265 {
9266 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
9267 CHECK_NULL_RETURN(layoutProperty, false);
9268 auto errorText = layoutProperty->GetErrorTextValue(u"");
9269 return layoutProperty->GetShowErrorTextValue(false) && !errorText.empty() && !IsNormalInlineState();
9270 }
9271
9272 bool TextFieldPattern::IsShowCount()
9273 {
9274 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
9275 CHECK_NULL_RETURN(layoutProperty, false);
9276 return layoutProperty->GetShowCounterValue(false) && !IsNormalInlineState() && !IsInPasswordMode() &&
9277 layoutProperty->HasMaxLength();
9278 }
9279
9280 void TextFieldPattern::ResetContextAttr()
9281 {
9282 auto host = GetHost();
9283 CHECK_NULL_VOID(host);
9284 auto renderContext = host->GetRenderContext();
9285 CHECK_NULL_VOID(renderContext);
9286 renderContext->ResetBorder();
9287 BorderWidthProperty borderWidth;
9288 borderWidth.SetBorderWidth(BORDER_DEFAULT_WIDTH);
9289 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
9290 CHECK_NULL_VOID(layoutProperty);
9291 layoutProperty->UpdateBorderWidth(borderWidth);
9292 }
9293
9294 void TextFieldPattern::SetThemeBorderAttr()
9295 {
9296 auto host = GetHost();
9297 CHECK_NULL_VOID(host);
9298 auto renderContext = host->GetRenderContext();
9299 CHECK_NULL_VOID(renderContext);
9300 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
9301 CHECK_NULL_VOID(layoutProperty);
9302 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
9303 CHECK_NULL_VOID(paintProperty);
9304 auto theme = GetTheme();
9305 CHECK_NULL_VOID(theme);
9306
9307 paintProperty->ResetInnerBorderColor();
9308 paintProperty->ResetInnerBorderWidth();
9309 if (!paintProperty->HasBorderColorFlagByUser()) {
9310 BorderColorProperty borderColor;
9311 borderColor.SetColor(theme->GetTextInputColor());
9312 renderContext->UpdateBorderColor(borderColor);
9313 } else {
9314 renderContext->UpdateBorderColor(paintProperty->GetBorderColorFlagByUserValue());
9315 }
9316
9317 if (!paintProperty->HasBorderRadiusFlagByUser()) {
9318 auto radius = theme->GetBorderRadius();
9319 BorderRadiusProperty borderRadius(radius.GetX(), radius.GetY(), radius.GetY(), radius.GetX());
9320 auto ultimatelyRadius = IsUnderlineMode() ? ZERO_BORDER_RADIUS_PROPERTY : borderRadius;
9321 renderContext->UpdateBorderRadius(ultimatelyRadius);
9322 } else {
9323 renderContext->UpdateBorderRadius(paintProperty->GetBorderRadiusFlagByUserValue());
9324 }
9325
9326 if (!paintProperty->HasBorderWidthFlagByUser()) {
9327 BorderWidthProperty borderWidth;
9328 if (IsTextArea() || IsUnderlineMode()) {
9329 borderWidth.SetBorderWidth(BORDER_DEFAULT_WIDTH);
9330 } else {
9331 borderWidth.SetBorderWidth(theme->GetTextInputWidth());
9332 }
9333 renderContext->UpdateBorderWidth(borderWidth);
9334 layoutProperty->UpdateBorderWidth(borderWidth);
9335 } else {
9336 renderContext->UpdateBorderWidth(paintProperty->GetBorderWidthFlagByUserValue());
9337 layoutProperty->UpdateBorderWidth(paintProperty->GetBorderWidthFlagByUserValue());
9338 }
9339 }
9340
9341 PaddingProperty TextFieldPattern::GetPaddingByUserValue()
9342 {
9343 PaddingProperty padding;
9344 auto theme = GetTheme();
9345 CHECK_NULL_RETURN(theme, padding);
9346 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
9347 CHECK_NULL_RETURN(paintProperty, padding);
9348 padding = paintProperty->GetPaddingByUserValue();
9349 auto themePadding = IsUnderlineMode() ? theme->GetUnderlinePadding() : theme->GetPadding();
9350 if (!padding.top.has_value()) {
9351 padding.top = CalcLength(CalcLength(themePadding.Top()).GetDimension());
9352 }
9353 if (!padding.bottom.has_value()) {
9354 padding.bottom = CalcLength(CalcLength(themePadding.Bottom()).GetDimension());
9355 }
9356 if (!padding.left.has_value()) {
9357 padding.left = CalcLength(CalcLength(themePadding.Left()).GetDimension());
9358 }
9359 if (!padding.right.has_value()) {
9360 padding.right = CalcLength(CalcLength(themePadding.Right()).GetDimension());
9361 }
9362 return padding;
9363 }
9364
9365 void TextFieldPattern::SetThemeAttr()
9366 {
9367 auto host = GetHost();
9368 CHECK_NULL_VOID(host);
9369 auto renderContext = host->GetRenderContext();
9370 CHECK_NULL_VOID(renderContext);
9371 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
9372 CHECK_NULL_VOID(layoutProperty);
9373 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
9374 CHECK_NULL_VOID(paintProperty);
9375 auto theme = GetTheme();
9376 CHECK_NULL_VOID(theme);
9377 SetThemeBorderAttr();
9378 if (!paintProperty->HasBackgroundColor()) {
9379 auto backgroundColor = isFocusBGColorSet_ ? theme->GetFocusBgColor() : theme->GetBgColor();
9380 backgroundColor = IsUnderlineMode() ? Color::TRANSPARENT : backgroundColor;
9381 renderContext->UpdateBackgroundColor(backgroundColor);
9382 } else {
9383 renderContext->UpdateBackgroundColor(paintProperty->GetBackgroundColorValue());
9384 }
9385
9386 if (!paintProperty->HasMarginByUser()) {
9387 MarginProperty margin;
9388 margin.SetEdges(CalcLength(0.0_vp));
9389 layoutProperty->UpdateMargin(margin);
9390 } else {
9391 layoutProperty->UpdateMargin(paintProperty->GetMarginByUserValue());
9392 }
9393
9394 if (!paintProperty->HasPaddingByUser()) {
9395 auto themePadding = IsUnderlineMode() ? GetUnderlinePadding(theme, false, false) : theme->GetPadding();
9396 PaddingProperty padding;
9397 padding.top = CalcLength(CalcLength(themePadding.Top()).GetDimension());
9398 padding.bottom = CalcLength(CalcLength(themePadding.Bottom()).GetDimension());
9399 padding.left = CalcLength(CalcLength(themePadding.Left()).GetDimension());
9400 padding.right = CalcLength(CalcLength(themePadding.Right()).GetDimension());
9401 layoutProperty->UpdatePadding(padding);
9402 } else {
9403 layoutProperty->UpdatePadding(GetPaddingByUserValue());
9404 }
9405
9406 if (!paintProperty->HasTextColorFlagByUser()) {
9407 auto textColor = isFocusTextColorSet_ ? theme->GetFocusTextColor() : theme->GetTextColor();
9408 layoutProperty->UpdateTextColor(textColor);
9409 } else {
9410 layoutProperty->UpdateTextColor(paintProperty->GetTextColorFlagByUserValue());
9411 }
9412 inlineFocusState_ = false;
9413 }
9414
9415 const Dimension& TextFieldPattern::GetAvoidSoftKeyboardOffset() const
9416 {
9417 auto textfieldTheme = GetTheme();
9418 if (!textfieldTheme) {
9419 return TextBase::GetAvoidSoftKeyboardOffset();
9420 }
9421 return textfieldTheme->GetAvoidKeyboardOffset();
9422 }
9423
9424 Offset TextFieldPattern::ConvertGlobalToLocalOffset(const Offset& globalOffset)
9425 {
9426 parentGlobalOffset_ = GetPaintRectGlobalOffset();
9427 auto localOffset = globalOffset - Offset(parentGlobalOffset_.GetX(), parentGlobalOffset_.GetY());
9428 if (selectOverlay_->HasRenderTransform()) {
9429 auto localOffsetF = OffsetF(globalOffset.GetX(), globalOffset.GetY());
9430 selectOverlay_->RevertLocalPointWithTransform(localOffsetF);
9431 localOffset.SetX(localOffsetF.GetX());
9432 localOffset.SetY(localOffsetF.GetY());
9433 }
9434 return localOffset;
9435 }
9436
9437 int32_t TextFieldPattern::SetPreviewText(const std::u16string &previewValue, const PreviewRange range)
9438 {
9439 PreviewTextInfo info = {
9440 .text = previewValue,
9441 .range = range,
9442 .isIme = true
9443 };
9444 auto host = GetHost();
9445 CHECK_NULL_RETURN(host, PREVIEW_NULL_POINTER);
9446 inputOperations_.emplace(InputOperation::SET_PREVIEW_TEXT);
9447 previewTextOperation_.emplace(info);
9448 CloseSelectOverlay(true);
9449 ScrollToSafeArea();
9450 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
9451 return PREVIEW_NO_ERROR;
9452 }
9453
9454 int32_t TextFieldPattern::SetPreviewText(const std::string &previewValue, const PreviewRange range)
9455 {
9456 return SetPreviewText(UtfUtils::Str8DebugToStr16(previewValue), range);
9457 }
9458
9459 void TextFieldPattern::SetPreviewTextOperation(PreviewTextInfo info)
9460 {
9461 auto host = GetHost();
9462 CHECK_NULL_VOID(host);
9463 FREE_NODE_CHECK(host, SetPreviewTextOperation, info); // call SetPreviewTextOperationMultiThread() by multi thread
9464 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
9465 CHECK_NULL_VOID(layoutProperty);
9466 if (!hasPreviewText_) {
9467 auto fullStr = GetTextUtf16Value();
9468 if (IsSelected()) {
9469 uint32_t startIndex = static_cast<uint32_t>(selectController_->GetStartIndex());
9470 uint32_t endIndex = static_cast<uint32_t>(selectController_->GetEndIndex());
9471 if (startIndex < fullStr.length() && endIndex <= fullStr.length()) {
9472 fullStr.erase(startIndex, endIndex - startIndex);
9473 }
9474 }
9475 bodyTextInPreivewing_ = fullStr;
9476 }
9477 auto rangeStart = info.range.start;
9478 auto rangeEnd = info.range.end;
9479 auto start = GetPreviewTextStart();
9480 auto end = GetPreviewTextEnd();
9481 if (IsSelected()) {
9482 start = selectController_->GetStartIndex();
9483 end = selectController_->GetEndIndex();
9484 } else {
9485 start = (rangeStart == PREVIEW_TEXT_RANGE_DEFAULT) ? start : rangeStart;
9486 end = (rangeEnd == PREVIEW_TEXT_RANGE_DEFAULT) ? end : rangeEnd;
9487 }
9488
9489 ChangeValueInfo changeValueInfo;
9490 changeValueInfo.oldPreviewText.offset = hasPreviewText_ ? GetPreviewTextStart() : -1;
9491 changeValueInfo.oldPreviewText.value = GetPreviewTextValue();
9492 changeValueInfo.oldContent = GetBodyTextValue();
9493 changeValueInfo.rangeBefore = TextRange { GetPreviewTextStart(), GetPreviewTextStart() };
9494 changeValueInfo.rangeAfter = TextRange { GetPreviewTextStart(), GetPreviewTextStart() };
9495 bool hasInsertValue = false;
9496 auto originLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length()) - (end - start);
9497 hasInsertValue = contentController_->ReplaceSelectedValue(start, end, info.text);
9498 int32_t caretMoveLength = abs(static_cast<int32_t>(contentController_->GetTextUtf16Value().length()) -
9499 originLength);
9500
9501 int32_t delta =
9502 static_cast<int32_t>(contentController_->GetTextUtf16Value().length()) - originLength - (end - start);
9503 int32_t newCaretPosition = std::max(end, GetPreviewTextEnd()) + delta;
9504 newCaretPosition = std::clamp(newCaretPosition, 0,
9505 static_cast<int32_t>(contentController_->GetTextUtf16Value().length()));
9506 selectController_->UpdateCaretIndex(start + caretMoveLength);
9507
9508 UpdatePreviewIndex(start, newCaretPosition);
9509 hasPreviewText_ = true;
9510 changeValueInfo.value = GetBodyTextValue();
9511 changeValueInfo.previewText.offset = hasPreviewText_ ? GetPreviewTextStart() : -1;
9512 changeValueInfo.previewText.value = GetPreviewTextValue();
9513 FireOnWillChange(changeValueInfo);
9514 if (HasFocus()) {
9515 cursorVisible_ = true;
9516 StartTwinkling();
9517 } else {
9518 cursorVisible_ = false;
9519 StopTwinkling();
9520 }
9521 }
9522
9523 void TextFieldPattern::FinishTextPreview()
9524 {
9525 inputOperations_.emplace(InputOperation::SET_PREVIEW_FINISH);
9526 auto host = GetHost();
9527 CHECK_NULL_VOID(host);
9528 ScrollToSafeArea();
9529 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
9530 }
9531
9532 void TextFieldPattern::FinishTextPreviewOperation(bool triggerOnWillChange)
9533 {
9534 auto host = GetHost();
9535 FREE_NODE_CHECK(host, FinishTextPreviewOperation,
9536 triggerOnWillChange); // call FinishTextPreviewOperationMultiThread() by multi thread
9537 if (!hasPreviewText_) {
9538 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "input state now is not at previewing text");
9539 return;
9540 }
9541 CHECK_NULL_VOID(host);
9542 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
9543 CHECK_NULL_VOID(layoutProperty);
9544 if (layoutProperty->HasMaxLength()) {
9545 int32_t len = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
9546 showCountBorderStyle_ = len > static_cast<int32_t>(layoutProperty->GetMaxLengthValue(Infinity<uint32_t>()));
9547 HandleCountStyle();
9548 }
9549
9550 ChangeValueInfo changeValueInfo;
9551 changeValueInfo.oldPreviewText.offset = hasPreviewText_ ? GetPreviewTextStart() : -1;
9552 changeValueInfo.oldPreviewText.value = GetPreviewTextValue();
9553 changeValueInfo.oldContent = GetBodyTextValue();
9554 changeValueInfo.rangeBefore = TextRange { GetPreviewTextStart(), GetPreviewTextStart() };
9555 auto start = GetPreviewTextStart();
9556 auto end = GetPreviewTextEnd();
9557 auto previewValue = GetPreviewTextValue();
9558 hasPreviewText_ = false;
9559 auto originLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length()) - (end - start);
9560 contentController_->ReplaceSelectedValue(start, end, previewValue);
9561 int32_t caretMoveLength = abs(static_cast<int32_t>(contentController_->GetTextUtf16Value().length()) -
9562 originLength);
9563 selectController_->UpdateCaretIndex(start + caretMoveLength);
9564 UpdateEditingValueToRecord();
9565 changeValueInfo.rangeAfter =
9566 TextRange { changeValueInfo.oldPreviewText.offset, selectController_->GetCaretIndex() };
9567 changeValueInfo.value = GetBodyTextValue();
9568 changeValueInfo.previewText.offset = hasPreviewText_ ? GetPreviewTextStart() : -1;
9569 changeValueInfo.previewText.value = GetPreviewTextValue();
9570 bool isWillChange = true;
9571 if (triggerOnWillChange) {
9572 isWillChange = FireOnWillChange(changeValueInfo);
9573 }
9574 if (!isWillChange) {
9575 contentController_->SetTextValueOnly(changeValueInfo.oldContent);
9576 selectController_->UpdateHandleIndex(start, start);
9577 return;
9578 }
9579 if (HasFocus()) {
9580 cursorVisible_ = true;
9581 StartTwinkling();
9582 } else {
9583 cursorVisible_ = false;
9584 StopTwinkling();
9585 }
9586 bodyTextInPreivewing_ = u"";
9587 previewTextStart_ = PREVIEW_TEXT_RANGE_DEFAULT;
9588 previewTextEnd_ = PREVIEW_TEXT_RANGE_DEFAULT;
9589 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
9590 }
9591
9592 std::vector<RectF> TextFieldPattern::GetPreviewTextRects() const
9593 {
9594 if (!GetIsPreviewText()) {
9595 return {};
9596 }
9597 std::vector<RectF> boxes;
9598 std::vector<RectF> previewTextRects;
9599 CHECK_NULL_RETURN(paragraph_, boxes);
9600 paragraph_->GetRectsForRange(GetPreviewTextStart(), GetPreviewTextEnd(), boxes);
9601 if (boxes.empty()) {
9602 return {};
9603 }
9604 RectF linerRect(boxes.front().GetOffset(), SizeF(0, boxes.front().GetSize().Height()));
9605 float checkedTop = boxes.front().Top();
9606
9607 for (const auto& drawRect : boxes) {
9608 if (drawRect.Top() == checkedTop) {
9609 linerRect += SizeF(drawRect.GetSize().Width(), 0);
9610 } else {
9611 previewTextRects.emplace_back(linerRect);
9612 checkedTop = drawRect.Top();
9613 linerRect = drawRect;
9614 }
9615 }
9616 previewTextRects.emplace_back(linerRect);
9617 return previewTextRects;
9618 }
9619
9620 bool TextFieldPattern::NeedDrawPreviewText()
9621 {
9622 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
9623 CHECK_NULL_RETURN(paintProperty, false);
9624
9625 auto caretInfo = selectController_->GetCaretInfo();
9626 if (!paintProperty->HasPreviewTextStart() || !paintProperty->HasPreviewTextEnd()) {
9627 paintProperty->UpdatePreviewTextStart(caretInfo.index);
9628 paintProperty->UpdatePreviewTextEnd(caretInfo.index);
9629 }
9630
9631 auto paintStart = paintProperty->GetPreviewTextStart();
9632 auto paintEnd =paintProperty->GetPreviewTextEnd();
9633 if (!GetIsPreviewText()) {
9634 if (!paintStart.has_value() || !paintEnd.has_value()) {
9635 paintProperty->UpdatePreviewTextStart(caretInfo.index);
9636 paintProperty->UpdatePreviewTextEnd(caretInfo.index);
9637 return false;
9638 }
9639
9640 // end paint
9641 if (paintStart != paintEnd || paintStart.value() != caretInfo.index) {
9642 paintProperty->UpdatePreviewTextStart(caretInfo.index);
9643 paintProperty->UpdatePreviewTextEnd(caretInfo.index);
9644 return true;
9645 }
9646 return false;
9647 }
9648 auto needDraw = paintStart.value() != GetPreviewTextStart() ||
9649 paintEnd.value() != GetPreviewTextEnd();
9650 paintProperty->UpdatePreviewTextStart(GetPreviewTextStart());
9651 paintProperty->UpdatePreviewTextEnd(GetPreviewTextEnd());
9652 return needDraw;
9653 }
9654
9655 int32_t TextFieldPattern::CheckPreviewTextValidate(const std::u16string& previewValue, const PreviewRange range)
9656 {
9657 auto start = range.start;
9658 auto end = range.end;
9659 if (start != end && (start == PREVIEW_TEXT_RANGE_DEFAULT || end == PREVIEW_TEXT_RANGE_DEFAULT)) {
9660 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "range is not [-1,-1] or legal range");
9661 return PREVIEW_BAD_PARAMETERS;
9662 }
9663
9664 if (start != PREVIEW_TEXT_RANGE_DEFAULT && IsSelected()) {
9665 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "unsupported insert preview text when IsSelected");
9666 return PREVIEW_BAD_PARAMETERS;
9667 }
9668 return PREVIEW_NO_ERROR;
9669 }
9670
9671 int32_t TextFieldPattern::CheckPreviewTextValidate(const std::string& previewValue, const PreviewRange range)
9672 {
9673 return CheckPreviewTextValidate(UtfUtils::Str8DebugToStr16(previewValue), range);
9674 }
9675
9676 PreviewTextStyle TextFieldPattern::GetPreviewTextStyle() const
9677 {
9678 auto defaultStyle = PreviewTextStyle::NORMAL;
9679 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
9680 CHECK_NULL_RETURN(paintProperty, defaultStyle);
9681 if (paintProperty->HasPreviewTextStyle()) {
9682 auto style = paintProperty->GetPreviewTextStyle();
9683 CHECK_NULL_RETURN(style, defaultStyle);
9684 if (style.value() == PREVIEW_STYLE_NORMAL) {
9685 return PreviewTextStyle::NORMAL;
9686 } else if (style.value() == PREVIEW_STYLE_UNDERLINE) {
9687 return PreviewTextStyle::UNDERLINE;
9688 }
9689 }
9690 return defaultStyle;
9691 }
9692
9693 void TextFieldPattern::ReceivePreviewTextStyle(const std::string& style)
9694 {
9695 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
9696 CHECK_NULL_VOID(paintProperty);
9697 if (!style.empty()) {
9698 paintProperty->UpdatePreviewTextStyle(style);
9699 }
9700 }
9701
9702 void TextFieldPattern::CalculatePreviewingTextMovingLimit(const Offset& touchOffset, double& limitL, double& limitR)
9703 {
9704 float offsetX = IsTextArea() ? contentRect_.GetX() : GetTextRect().GetX();
9705 float offsetY = IsTextArea() ? GetTextRect().GetY() : contentRect_.GetY();
9706 std::vector<RectF> previewTextRects = GetPreviewTextRects();
9707 if (GreatNotEqual(touchOffset.GetY(), previewTextRects.back().Bottom() + offsetY)) {
9708 limitL = previewTextRects.back().Left() + offsetX + MINIMAL_OFFSET;
9709 limitR = previewTextRects.back().Right() + offsetX - MINIMAL_OFFSET;
9710 } else if (LessNotEqual(touchOffset.GetY(), previewTextRects.front().Top() + offsetY)) {
9711 limitL = previewTextRects.front().Left() + offsetX + MINIMAL_OFFSET;
9712 limitR = previewTextRects.front().Right() + offsetX - MINIMAL_OFFSET;
9713 } else {
9714 for (const auto& drawRect : previewTextRects) {
9715 if (GreatOrEqual(touchOffset.GetY(), drawRect.Top() + offsetY)
9716 && LessOrEqual(touchOffset.GetY(), drawRect.Bottom() + offsetY)) {
9717 limitL = drawRect.Left() + offsetX + MINIMAL_OFFSET;
9718 limitR = drawRect.Right() + offsetX - MINIMAL_OFFSET;
9719 break;
9720 }
9721 }
9722 }
9723 }
9724
9725 void TextFieldPattern::ResetPreviewTextState()
9726 {
9727 if (!GetIsPreviewText()) {
9728 return;
9729 }
9730 #if defined(ENABLE_STANDARD_INPUT)
9731 MiscServices::InputMethodController::GetInstance()->OnSelectionChange(
9732 StringUtils::Str8ToStr16(""), 0, 0);
9733 UpdateCaretInfoToController(true);
9734 #endif
9735 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "textfield onDragEnter when has previewText");
9736 FinishTextPreview();
9737 }
9738
9739 void TextFieldPattern::SetShowKeyBoardOnFocus(bool value)
9740 {
9741 auto host = GetHost();
9742 FREE_NODE_CHECK(host, SetShowKeyBoardOnFocus, value); // call SetShowKeyBoardOnFocusMultiThread() by multi thread
9743 if (showKeyBoardOnFocus_ == value) {
9744 return;
9745 }
9746 showKeyBoardOnFocus_ = value;
9747
9748 if (!HasFocus()) {
9749 return;
9750 }
9751
9752 if (value) {
9753 RequestKeyboardNotByFocusSwitch(RequestKeyboardReason::SHOW_KEYBOARD_ON_FOCUS);
9754 } else {
9755 CloseKeyboard(true, false);
9756 }
9757 }
9758
9759 void TextFieldPattern::OnCaretMoveDone(const TouchEventInfo& info)
9760 {
9761 if (isMoveCaretAnywhere_) {
9762 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "isMoveCaretAnywhere_=1, so restore caret");
9763 selectController_->UpdateCaretInfoByOffset(info.GetTouches().front().GetLocalLocation());
9764 StartTwinkling();
9765 }
9766 }
9767
9768 void TextFieldPattern::HiddenMenu()
9769 {
9770 selectOverlay_->HideMenu();
9771 }
9772
9773 void TextFieldPattern::OnSelectionMenuOptionsUpdate(const NG::OnCreateMenuCallback&& onCreateMenuCallback,
9774 const NG::OnMenuItemClickCallback&& onMenuItemClick, const NG::OnPrepareMenuCallback&& onPrepareMenuCallback)
9775 {
9776 selectOverlay_->OnSelectionMenuOptionsUpdate(
9777 std::move(onCreateMenuCallback), std::move(onMenuItemClick), std::move(onPrepareMenuCallback));
9778 }
9779
9780 bool TextFieldPattern::GetTouchInnerPreviewText(const Offset& offset) const
9781 {
9782 auto touchDownIndex = selectController_->ConvertTouchOffsetToPosition(offset);
9783 return GetPreviewTextStart() <= touchDownIndex && touchDownIndex <= GetPreviewTextEnd() && HasFocus();
9784 }
9785
9786 bool TextFieldPattern::IsResponseRegionExpandingNeededForStylus(const TouchEvent& touchEvent) const
9787 {
9788 if (touchEvent.sourceTool != SourceTool::PEN || touchEvent.type != TouchType::DOWN) {
9789 return false;
9790 }
9791 auto host = GetHost();
9792 CHECK_NULL_RETURN(host, false);
9793 auto focusHub = host->GetFocusHub();
9794 CHECK_NULL_RETURN(focusHub, false);
9795 if (!focusHub->IsFocusable() || !host->IsVisible()) {
9796 return false;
9797 }
9798 auto renderContext = host->GetRenderContext();
9799 CHECK_NULL_RETURN(renderContext, false);
9800 auto opacity = renderContext->GetOpacity();
9801 // if opacity is 0.0f, no need to hit frameNode.
9802 if (NearZero(opacity.value_or(1.0f))) {
9803 return false;
9804 }
9805 return !IsInPasswordMode();
9806 }
9807
9808 RectF TextFieldPattern::ExpandDefaultResponseRegion(RectF& rect)
9809 {
9810 return rect + NG::SizeF(0, OHOS::Ace::HOT_AREA_ADJUST_SIZE.ConvertToPx() * OHOS::Ace::HOT_AREA_EXPAND_TIME) +
9811 NG::OffsetF(0, -OHOS::Ace::HOT_AREA_ADJUST_SIZE.ConvertToPx());
9812 }
9813
9814 bool TextFieldPattern::IsContentRectNonPositive()
9815 {
9816 return NonPositive(contentRect_.Width());
9817 }
9818
9819 void TextFieldPattern::ReportEvent()
9820 {
9821 #if !defined(PREVIEW) && !defined(ACE_UNITTEST) && defined(OHOS_PLATFORM)
9822 auto host = GetHost();
9823 CHECK_NULL_VOID(host);
9824 if (UiSessionManager::GetInstance()->GetSearchEventRegistered()) {
9825 auto data = JsonUtil::Create();
9826 data->Put("event", "onTextSearch");
9827 data->Put("id", host->GetId());
9828 data->Put("$type", host->GetTag().data());
9829 data->Put("inputType", static_cast<int16_t>(GetKeyboard()));
9830 data->Put("text", GetTextValue().data());
9831 data->Put("position", host->GetGeometryNode()->GetFrameRect().ToString().data());
9832 // report all use textfield component unfocus event,more than just the search box
9833 UiSessionManager::GetInstance()->ReportSearchEvent(data->ToString());
9834 }
9835 if (!IsInPasswordMode()) {
9836 auto value = InspectorJsonUtil::Create();
9837 CHECK_NULL_VOID(value);
9838 auto textString = GetTextValue();
9839 value->Put("text", textString.c_str());
9840 UiSessionManager::GetInstance()->ReportComponentChangeEvent(host->GetId(), "event", value);
9841 SEC_TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "nodeId:[%{public}d] TextField reportComponentChangeEvent %{public}zu",
9842 host->GetId(), textString.length());
9843 }
9844 #endif
9845 }
9846
9847 int32_t TextFieldPattern::GetTouchIndex(const OffsetF& offset)
9848 {
9849 return selectOverlay_->GetCaretPositionOnHandleMove(offset, true);
9850 }
9851
9852 void TextFieldPattern::StartGestureSelection(int32_t start, int32_t end, const Offset& startOffset)
9853 {
9854 TextGestureSelector::StartGestureSelection(start, end, startOffset);
9855 StopContentScroll();
9856 contentScroller_.scrollingCallback = [weak = WeakClaim(this), start, end](const Offset& localOffset) {
9857 auto pattern = weak.Upgrade();
9858 CHECK_NULL_VOID(pattern);
9859 auto index = pattern->GetTouchIndex({ localOffset.GetX(), localOffset.GetY() });
9860 auto startIndex = std::min(index, start);
9861 auto endIndex = std::max(index, end);
9862 pattern->UpdateSelectionByLongPress(startIndex, endIndex, localOffset);
9863 };
9864 }
9865
9866 void TextFieldPattern::OnTextGestureSelectionUpdate(int32_t start, int32_t end, const TouchEventInfo& info)
9867 {
9868 if (!HasText()) {
9869 return;
9870 }
9871 auto localOffset = info.GetTouches().front().GetLocalLocation();
9872 UpdateContentScroller(localOffset);
9873 if (contentScroller_.isScrolling) {
9874 return;
9875 }
9876 if (start != selectController_->GetStartIndex()) {
9877 StartVibratorByIndexChange(start, selectController_->GetStartIndex());
9878 } else if (end != selectController_->GetEndIndex()) {
9879 StartVibratorByIndexChange(end, selectController_->GetEndIndex());
9880 }
9881 UpdateSelectionByLongPress(start, end, localOffset);
9882 }
9883
9884 void TextFieldPattern::UpdateSelectionByLongPress(int32_t start, int32_t end, const Offset& localOffset)
9885 {
9886 if (magnifierController_ && HasText() && (longPressFingerNum_ == 1)) {
9887 magnifierController_->SetLocalOffset({ localOffset.GetX(), localOffset.GetY() });
9888 }
9889 auto firstIndex = selectController_->GetFirstHandleIndex();
9890 auto secondIndex = selectController_->GetSecondHandleIndex();
9891 bool changed = false;
9892 if (start != firstIndex) {
9893 selectController_->MoveFirstHandleToContentRect(start, false, false);
9894 changed = true;
9895 }
9896 if (secondIndex != end) {
9897 selectController_->MoveSecondHandleToContentRect(end, false, false);
9898 changed = true;
9899 }
9900 if (!changed) {
9901 return;
9902 }
9903 auto host = GetHost();
9904 CHECK_NULL_VOID(host);
9905 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
9906 }
9907
9908 void TextFieldPattern::OnTextGestureSelectionEnd(const TouchLocationInfo& locationInfo)
9909 {
9910 SetIsSingleHandle(!IsSelected());
9911 bool isScrolling = contentScroller_.isScrolling;
9912 StopContentScroll();
9913 if (IsContentRectNonPositive()) {
9914 return;
9915 }
9916 auto needRender = false;
9917 do {
9918 if (!isScrolling) {
9919 auto localLocation = locationInfo.GetLocalLocation();
9920 if (LessNotEqual(localLocation.GetX(), contentRect_.Left()) ||
9921 LessNotEqual(localLocation.GetY(), contentRect_.Top())) {
9922 selectController_->MoveFirstHandleToContentRect(selectController_->GetFirstHandleIndex(), false);
9923 needRender = true;
9924 break;
9925 } else if (GreatNotEqual(localLocation.GetX(), contentRect_.Right()) ||
9926 GreatNotEqual(localLocation.GetY(), contentRect_.Bottom())) {
9927 selectController_->MoveSecondHandleToContentRect(selectController_->GetSecondHandleIndex(), false);
9928 needRender = true;
9929 break;
9930 }
9931 }
9932 if (Positive(contentScroller_.stepOffset)) {
9933 selectController_->MoveFirstHandleToContentRect(selectController_->GetFirstHandleIndex(), false);
9934 needRender = true;
9935 } else if (Negative(contentScroller_.stepOffset)) {
9936 selectController_->MoveSecondHandleToContentRect(selectController_->GetSecondHandleIndex(), false);
9937 needRender = true;
9938 }
9939 } while (false);
9940 if (HasFocus()) {
9941 ProcessOverlay({ .animation = true });
9942 }
9943 if (needRender) {
9944 auto host = GetHost();
9945 CHECK_NULL_VOID(host);
9946 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
9947 }
9948 }
9949
9950 PositionWithAffinity TextFieldPattern::GetGlyphPositionAtCoordinate(int32_t x, int32_t y)
9951 {
9952 PositionWithAffinity finalResult(0, TextAffinity::UPSTREAM);
9953 CHECK_NULL_RETURN(paragraph_, finalResult);
9954 Offset offset(x, y);
9955 return paragraph_->GetGlyphPositionAtCoordinate(ConvertTouchOffsetToTextOffset(offset));
9956 }
9957
9958 Offset TextFieldPattern::ConvertTouchOffsetToTextOffset(const Offset& touchOffset)
9959 {
9960 return touchOffset - Offset(textRect_.GetX(), textRect_.GetY());
9961 }
9962
9963 bool TextFieldPattern::InsertOrDeleteSpace(int32_t index)
9964 {
9965 // delete or insert space.
9966 auto wtext = GetTextUtf16Value();
9967 if (index >= 0 && index < static_cast<int32_t>(wtext.length())) {
9968 auto ret = SetCaretOffset(index);
9969 if (!ret) {
9970 return false;
9971 }
9972 if (wtext[index] == u' ') {
9973 DeleteForward(1);
9974 } else if (index > 0 && wtext[index - 1] == u' ') {
9975 DeleteBackward(1);
9976 } else {
9977 InsertValue(u" ", true);
9978 }
9979 return true;
9980 }
9981 return false;
9982 }
9983
9984 void TextFieldPattern::DeleteRange(int32_t start, int32_t end, bool isIME)
9985 {
9986 auto length = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
9987 if (start > end) {
9988 std::swap(start, end);
9989 }
9990 start = std::max(0, start);
9991 end = std::min(length, end);
9992 if (start > length || end < 0 || start == end) {
9993 return;
9994 }
9995 auto value = contentController_->GetSelectedValue(start, end);
9996 auto originCaretIndex =
9997 TextRange { selectController_->GetFirstHandleIndex(), selectController_->GetSecondHandleIndex() };
9998 if (isIME) {
9999 auto isDelete = BeforeIMEDeleteValue(value, TextDeleteDirection::FORWARD, start);
10000 CHECK_NULL_VOID(isDelete);
10001 }
10002 ResetObscureTickCountDown();
10003 CheckAndUpdateRecordBeforeOperation();
10004 auto oldContent = contentController_->GetTextUtf16Value();
10005 Delete(start, end);
10006 auto isOnWillChange = OnWillChangePreDelete(oldContent, start, end);
10007 if (!isOnWillChange) {
10008 RecoverTextValueAndCaret(oldContent, originCaretIndex);
10009 return;
10010 }
10011 if (isIME) {
10012 AfterIMEDeleteValue(value, TextDeleteDirection::FORWARD);
10013 }
10014 showCountBorderStyle_ = false;
10015 HandleCountStyle();
10016 }
10017
10018 void TextFieldPattern::DeleteTextRange(int32_t start, int32_t end, TextDeleteDirection direction)
10019 {
10020 auto length = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
10021 if (start > end) {
10022 std::swap(start, end);
10023 }
10024 start = std::max(0, start);
10025 end = std::min(length, end);
10026 if (start > length || end < 0 || start == end) {
10027 return;
10028 }
10029 auto value = contentController_->GetSelectedValue(start, end);
10030 auto originCaretIndex =
10031 TextRange { selectController_->GetFirstHandleIndex(), selectController_->GetSecondHandleIndex() };
10032 auto isDelete = BeforeIMEDeleteValue(value, direction, start);
10033 CHECK_NULL_VOID(isDelete);
10034 ResetObscureTickCountDown();
10035 CheckAndUpdateRecordBeforeOperation();
10036 auto oldContent = contentController_->GetTextUtf16Value();
10037 Delete(start, end);
10038 auto isOnWillChange = OnWillChangePreDelete(oldContent, start, end);
10039 if (!isOnWillChange) {
10040 RecoverTextValueAndCaret(oldContent, originCaretIndex);
10041 return;
10042 }
10043 AfterIMEDeleteValue(value, direction);
10044 showCountBorderStyle_ = false;
10045 HandleCountStyle();
10046 }
10047
10048 bool TextFieldPattern::IsShowAIWrite()
10049 {
10050 auto container = Container::Current();
10051 if (container && container->IsSceneBoardWindow()) {
10052 return false;
10053 }
10054
10055 auto host = GetHost();
10056 CHECK_NULL_RETURN(host, false);
10057 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
10058 CHECK_NULL_RETURN(layoutProperty, false);
10059 if (layoutProperty->GetCopyOptionsValue(CopyOptions::Local) == CopyOptions::None ||
10060 !IsUnspecifiedOrTextType()) {
10061 return false;
10062 }
10063
10064 auto textFieldTheme = GetTheme();
10065 CHECK_NULL_RETURN(textFieldTheme, false);
10066 auto bundleName = textFieldTheme->GetAIWriteBundleName();
10067 auto abilityName = textFieldTheme->GetAIWriteAbilityName();
10068 if (bundleName.empty() || abilityName.empty()) {
10069 TAG_LOGW(AceLogTag::ACE_TEXT_FIELD, "Failed to obtain AI write package name!");
10070 return false;
10071 }
10072
10073 auto isAISupport = false;
10074 if (textFieldTheme->GetAIWriteIsSupport() == "true") {
10075 isAISupport = true;
10076 }
10077 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "Whether the device supports AI write: %{public}d, nodeId: %{public}d",
10078 isAISupport, host->GetId());
10079 if (isAISupport) {
10080 auto pipeline = host->GetContext();
10081 CHECK_NULL_RETURN(pipeline, false);
10082 aiWriteAdapter_ = pipeline->GetOrCreateAIWriteAdapter(); // initialize TextFieldPattern's aiWriteAdapter_ here.
10083 auto aiWriteAdapter = aiWriteAdapter_.Upgrade();
10084 CHECK_NULL_RETURN(aiWriteAdapter, false);
10085 aiWriteAdapter->SetBundleName(bundleName);
10086 aiWriteAdapter->SetAbilityName(abilityName);
10087 }
10088
10089 return isAISupport;
10090 }
10091
10092 void TextFieldPattern::GetAIWriteInfo(AIWriteInfo& info)
10093 {
10094 auto aiWriteAdapter = aiWriteAdapter_.Upgrade();
10095 CHECK_NULL_VOID(aiWriteAdapter);
10096 // serialize the selected text
10097 info.selectStart = selectController_->GetStartIndex();
10098 info.selectEnd = selectController_->GetEndIndex();
10099 auto selectContent = contentController_->GetSelectedValue(info.selectStart, info.selectEnd);
10100 RefPtr<SpanString> spanString = AceType::MakeRefPtr<SpanString>(selectContent);
10101 spanString->EncodeTlv(info.selectBuffer);
10102 info.selectLength = static_cast<int32_t>(aiWriteAdapter->GetSelectLengthOnlyText(spanString->GetU16string()));
10103 TAG_LOGD(AceLogTag::ACE_TEXT_FIELD, "Selected range=[%{public}d--%{public}d], content size=%{public}zu",
10104 info.selectStart, info.selectEnd, spanString->GetString().size());
10105
10106 // serialize the sentenced-level text
10107 auto textSize = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
10108 auto contentAll = contentController_->GetTextUtf16Value();
10109 auto sentenceStart = 0;
10110 auto sentenceEnd = textSize;
10111 for (int32_t i = info.selectStart; i >= 0; --i) {
10112 if (aiWriteAdapter->IsSentenceBoundary(contentAll[i])) {
10113 sentenceStart = i + 1;
10114 break;
10115 }
10116 }
10117 for (int32_t i = info.selectEnd; i < textSize; i++) {
10118 if (aiWriteAdapter->IsSentenceBoundary(contentAll[i])) {
10119 sentenceEnd = i;
10120 break;
10121 }
10122 }
10123 info.start = info.selectStart - sentenceStart;
10124 info.end = info.selectEnd - sentenceStart;
10125 auto sentenceContent = contentController_->GetSelectedValue(sentenceStart, sentenceEnd);
10126 spanString = AceType::MakeRefPtr<SpanString>(sentenceContent);
10127 spanString->EncodeTlv(info.sentenceBuffer);
10128 TAG_LOGD(AceLogTag::ACE_TEXT_FIELD, "Sentence range=[%{public}d--%{public}d], content size=%{public}zu",
10129 sentenceStart, sentenceEnd, spanString->GetString().size());
10130
10131 auto host = GetHost();
10132 CHECK_NULL_VOID(host);
10133 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
10134 CHECK_NULL_VOID(layoutProperty);
10135 info.maxLength = static_cast<int32_t>(layoutProperty->GetMaxLengthValue(Infinity<uint32_t>()));
10136 info.firstHandle = selectController_->GetFirstHandleRect().ToString();
10137 info.secondHandle = selectController_->GetSecondHandleRect().ToString();
10138 info.componentType = host->GetTag();
10139 }
10140
10141 void TextFieldPattern::HandleOnAIWrite()
10142 {
10143 auto aiWriteAdapter = aiWriteAdapter_.Upgrade();
10144 CHECK_NULL_VOID(aiWriteAdapter);
10145 AIWriteInfo info;
10146 GetAIWriteInfo(info);
10147 CloseSelectOverlay();
10148 CloseKeyboard(true);
10149
10150 auto callback = [weak = WeakClaim(this), info](std::vector<uint8_t>& buffer) {
10151 auto pattern = weak.Upgrade();
10152 CHECK_NULL_VOID(pattern);
10153 pattern->HandleAIWriteResult(info.selectStart, info.selectEnd, buffer);
10154 auto weakAiWriteAdapter = pattern->aiWriteAdapter_;
10155 auto aiWriteAdapter = weakAiWriteAdapter.Upgrade();
10156 CHECK_NULL_VOID(aiWriteAdapter);
10157 aiWriteAdapter->CloseModalUIExtension();
10158 };
10159 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
10160 CHECK_NULL_VOID(pipeline);
10161 aiWriteAdapter->SetPipelineContext(pipeline);
10162 aiWriteAdapter->ShowModalUIExtension(info, callback);
10163 }
10164
10165 void TextFieldPattern::HandleAIWriteResult(int32_t start, int32_t end, std::vector<uint8_t>& buffer)
10166 {
10167 RefPtr<SpanString> spanString = SpanString::DecodeTlv(buffer);
10168 auto resultText = spanString->GetU16string();
10169 TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "Backfilling results range=[%{public}d--%{public}d], content size=%{public}zu",
10170 start, end, spanString->GetString().size());
10171 if (spanString->GetSpanItems().empty()) {
10172 return;
10173 }
10174
10175 auto host = GetHost();
10176 CHECK_NULL_VOID(host);
10177 auto value = contentController_->GetSelectedValue(start, end);
10178 InputCommandInfo inputCommandInfo;
10179 inputCommandInfo.deleteRange = { start, end };
10180 inputCommandInfo.insertOffset = start;
10181 inputCommandInfo.insertValue = resultText;
10182 inputCommandInfo.reason = InputReason::AI_WRITE;
10183 AddInputCommand(inputCommandInfo);
10184 }
10185
10186 bool TextFieldPattern::IsTextEditableForStylus() const
10187 {
10188 CHECK_NULL_RETURN(!HasCustomKeyboard(), false);
10189 auto host = GetHost();
10190 CHECK_NULL_RETURN(host, false);
10191 auto focusHub = host->GetFocusHub();
10192 CHECK_NULL_RETURN(focusHub, false);
10193 if (!focusHub->IsFocusable() || !host->IsVisible()) {
10194 return false;
10195 }
10196 auto renderContext = host->GetRenderContext();
10197 CHECK_NULL_RETURN(renderContext, false);
10198 auto opacity = renderContext->GetOpacity();
10199 // if opacity is 0.0f, no need to hit frameNode.
10200 if (NearZero(opacity.value_or(1.0f))) {
10201 return false;
10202 }
10203 return !IsInPasswordMode();
10204 }
10205
10206 void TextFieldPattern::UpdateContentScroller(const Offset& offset, float delay, bool enableScrollOutside)
10207 {
10208 auto localOffset = enableScrollOutside ? AdjustAutoScrollOffset(offset) : offset;
10209 auto scrollStep = CalcAutoScrollStepOffset(localOffset);
10210 // 在热区外移动
10211 if (!scrollStep || (!GetScrollEnabled() && !moveCaretState_.isMoveCaret)) {
10212 contentScroller_.OnBeforeScrollingCallback(localOffset);
10213 PauseContentScroll();
10214 contentScroller_.hotAreaOffset.reset();
10215 return;
10216 }
10217 contentScroller_.stepOffset = scrollStep.value();
10218 contentScroller_.localOffset = localOffset;
10219 if (contentScroller_.isScrolling) {
10220 return;
10221 }
10222 contentScroller_.OnBeforeScrollingCallback(localOffset);
10223 if (!contentScroller_.hotAreaOffset) {
10224 contentScroller_.hotAreaOffset = localOffset;
10225 ScheduleContentScroll(delay);
10226 } else {
10227 auto hotAreaMoveDistance = (localOffset - contentScroller_.hotAreaOffset.value()).GetDistance();
10228 if (GreatOrEqual(hotAreaMoveDistance, AUTO_SCROLL_HOT_AREA_LONGPRESS_DISTANCE.ConvertToPx())) {
10229 contentScroller_.hotAreaOffset = localOffset;
10230 contentScroller_.autoScrollTask.Cancel();
10231 ScheduleContentScroll(delay);
10232 }
10233 }
10234 }
10235
10236 Offset TextFieldPattern::AdjustAutoScrollOffset(const Offset& offset)
10237 {
10238 auto contentRect = GetContentRect();
10239 // ensure the point is in the content area.
10240 double margin = 1.0f;
10241 auto offsetX = std::clamp(offset.GetX(), static_cast<double>(contentRect.Left()) + margin,
10242 static_cast<double>(contentRect.Right()) - margin);
10243 auto offsetY = std::clamp(offset.GetY(), static_cast<double>(contentRect.Top()) + margin,
10244 static_cast<double>(contentRect.Bottom()) - margin);
10245 return Offset(offsetX, offsetY);
10246 }
10247
10248 std::optional<float> TextFieldPattern::CalcAutoScrollStepOffset(const Offset& localOffset)
10249 {
10250 auto contentRect = GetContentRect();
10251 auto axis = GetAxis();
10252 auto isVertical = (axis == Axis::VERTICAL);
10253 auto hotArea = isVertical ? AUTO_SCROLL_HOT_ZONE_HEIGHT.ConvertToPx() : AUTO_SCROLL_HOT_ZONE_WIDTH.ConvertToPx();
10254 if (isVertical) {
10255 if (LessOrEqual(contentRect.Height(), hotArea)) {
10256 hotArea = contentRect.Height() / 3.0f;
10257 }
10258 } else {
10259 if (LessOrEqual(contentRect.Width(), hotArea)) {
10260 hotArea = contentRect.Width() / 3.0f;
10261 }
10262 }
10263 struct HotEdge {
10264 float start = 0.0f;
10265 float end = 0.0f;
10266 float scrollDirection = 1.0f;
10267 };
10268 std::vector<HotEdge> hotEdges = { { contentRect.Top() + hotArea, contentRect.Top(), 1.0f },
10269 { contentRect.Bottom() - hotArea, contentRect.Bottom(), -1.0f },
10270 { contentRect.Left() + hotArea, contentRect.Left(), 1.0f },
10271 { contentRect.Right() - hotArea, contentRect.Right(), -1.0f } };
10272 auto itStart = isVertical ? hotEdges.begin() : hotEdges.begin() + 2;
10273 auto point = isVertical ? localOffset.GetY() : localOffset.GetX();
10274 std::optional<float> scrollStep;
10275 for (auto it = itStart; it != (itStart + 2); ++it) {
10276 auto speed = CalcScrollSpeed(it->start, it->end, point);
10277 if (!NearZero(speed)) {
10278 scrollStep = speed * it->scrollDirection;
10279 break;
10280 }
10281 }
10282 return scrollStep;
10283 }
10284
10285 float TextFieldPattern::CalcScrollSpeed(float hotAreaStart, float hotAreaEnd, float point)
10286 {
10287 auto minHotArea = std::min(hotAreaStart, hotAreaEnd);
10288 auto maxHotArea = std::max(hotAreaStart, hotAreaEnd);
10289 if (GreatNotEqual(point, minHotArea) && LessNotEqual(point, maxHotArea)) {
10290 auto distanceRatio = (point - hotAreaStart) / (hotAreaEnd - hotAreaStart);
10291 auto speedFactor = Curves::SHARP->MoveInternal(distanceRatio);
10292 return ((MAX_DRAG_SCROLL_SPEED * speedFactor) / TIME_UNIT) * contentScroller_.scrollInterval;
10293 }
10294 return 0.0f;
10295 }
10296
10297 void TextFieldPattern::StopContentScroll()
10298 {
10299 PauseContentScroll();
10300 contentScroller_.scrollingCallback = nullptr;
10301 contentScroller_.beforeScrollingCallback = nullptr;
10302 }
10303
10304 void TextFieldPattern::PauseContentScroll()
10305 {
10306 contentScroller_.autoScrollTask.Cancel();
10307 contentScroller_.isScrolling = false;
10308 ScheduleDisappearDelayTask();
10309 }
10310
10311 void TextFieldPattern::ScheduleContentScroll(float delay)
10312 {
10313 auto host = GetHost();
10314 CHECK_NULL_VOID(host);
10315 auto context = host->GetContext();
10316 CHECK_NULL_VOID(context);
10317 auto taskExecutor = context->GetTaskExecutor();
10318 CHECK_NULL_VOID(taskExecutor);
10319 contentScroller_.autoScrollTask.Reset([weak = WeakClaim(this)]() {
10320 auto pattern = weak.Upgrade();
10321 CHECK_NULL_VOID(pattern);
10322 pattern->contentScroller_.isScrolling = true;
10323 pattern->contentScroller_.hotAreaOffset = std::nullopt;
10324 pattern->OnScrollCallback(pattern->contentScroller_.stepOffset, SCROLL_FROM_UPDATE);
10325 if (pattern->contentScroller_.scrollingCallback) {
10326 pattern->contentScroller_.scrollingCallback(pattern->contentScroller_.localOffset);
10327 }
10328 pattern->ScheduleContentScroll(pattern->contentScroller_.scrollInterval);
10329 });
10330 taskExecutor->PostDelayedTask(contentScroller_.autoScrollTask, TaskExecutor::TaskType::UI, delay,
10331 "ArkUIAutoScrollControllerScheduleAutoScroll");
10332 }
10333
10334 void TextFieldPattern::SetDragMovingScrollback()
10335 {
10336 StopContentScroll();
10337 contentScroller_.scrollingCallback = [weak = WeakClaim(this)](const Offset& localOffset) {
10338 auto pattern = weak.Upgrade();
10339 CHECK_NULL_VOID(pattern);
10340 auto host = pattern->GetHost();
10341 CHECK_NULL_VOID(host);
10342 auto pipeline = host->GetContext();
10343 CHECK_NULL_VOID(pipeline);
10344 auto theme = pipeline->GetTheme<TextFieldTheme>();
10345 CHECK_NULL_VOID(theme);
10346 Offset offset = localOffset - Offset(pattern->textRect_.GetX(), pattern->textRect_.GetY()) -
10347 Offset(0, theme->GetInsertCursorOffset().ConvertToPx());
10348 auto position = pattern->ConvertTouchOffsetToCaretPosition(offset);
10349 pattern->SetCaretPosition(position, false);
10350 pattern->ShowCaretAndStopTwinkling();
10351 };
10352 contentScroller_.beforeScrollingCallback = contentScroller_.scrollingCallback;
10353 }
10354
10355 void TextFieldPattern::OnAttachToMainTree()
10356 {
10357 auto host = GetHost();
10358 THREAD_SAFE_NODE_CHECK(host, OnAttachToMainTree); // call OnAttachToMainTreeMultiThread() by multi thread
10359 isDetachFromMainTree_ = false;
10360 CHECK_NULL_VOID(host);
10361 auto autoFillContainerNode = host->GetFirstAutoFillContainerNode();
10362 CHECK_NULL_VOID(autoFillContainerNode);
10363 firstAutoFillContainerNode_ = WeakClaim(RawPtr(autoFillContainerNode));
10364 AddTextFieldInfo();
10365 }
10366
10367 void TextFieldPattern::OnDetachFromMainTree()
10368 {
10369 auto host = GetHost();
10370 THREAD_SAFE_NODE_CHECK(host, OnDetachFromMainTree); // call OnDetachFromMainTreeMultiThread() by multi thread
10371 isDetachFromMainTree_ = true;
10372 RemoveTextFieldInfo();
10373 RemoveFillContentMap();
10374 }
10375
10376 TextFieldInfo TextFieldPattern::GenerateTextFieldInfo()
10377 {
10378 TextFieldInfo textFieldInfo;
10379 auto host = GetHost();
10380 CHECK_NULL_RETURN(host, textFieldInfo);
10381 textFieldInfo.nodeId = host->GetId();
10382 auto autoFillContainerNode = firstAutoFillContainerNode_.Upgrade();
10383 CHECK_NULL_RETURN(autoFillContainerNode, textFieldInfo);
10384 textFieldInfo.autoFillContainerNodeId = autoFillContainerNode->GetId();
10385 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
10386 CHECK_NULL_RETURN(layoutProperty, textFieldInfo);
10387 textFieldInfo.enableAutoFill = layoutProperty->GetEnableAutoFillValue(true);
10388 textFieldInfo.inputType = layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED);
10389 textFieldInfo.contentType = layoutProperty->GetTextContentTypeValue(TextContentType::UNSPECIFIED);
10390 return textFieldInfo;
10391 }
10392
10393 void TextFieldPattern::AddTextFieldInfo()
10394 {
10395 CHECK_NULL_VOID(IsNeedProcessAutoFill());
10396 auto host = GetHost();
10397 CHECK_NULL_VOID(host);
10398 auto pipeline = host->GetContext();
10399 CHECK_NULL_VOID(pipeline);
10400 auto textFieldManager = DynamicCast<TextFieldManagerNG>(pipeline->GetTextFieldManager());
10401 CHECK_NULL_VOID(textFieldManager);
10402 auto textFieldInfo = GenerateTextFieldInfo();
10403 textFieldManager->AddTextFieldInfo(textFieldInfo);
10404 }
10405
10406 void TextFieldPattern::RemoveTextFieldInfo()
10407 {
10408 CHECK_NULL_VOID(IsNeedProcessAutoFill());
10409 auto host = GetHost();
10410 CHECK_NULL_VOID(host);
10411 auto pipeline = host->GetContext();
10412 CHECK_NULL_VOID(pipeline);
10413 auto textFieldManager = DynamicCast<TextFieldManagerNG>(pipeline->GetTextFieldManager());
10414 CHECK_NULL_VOID(textFieldManager);
10415 auto nodeId = host->GetId();
10416 auto autoFillContainerNode = firstAutoFillContainerNode_.Upgrade();
10417 CHECK_NULL_VOID(autoFillContainerNode);
10418 auto autoFillContainerNodeId = autoFillContainerNode->GetId();
10419 textFieldManager->RemoveTextFieldInfo(autoFillContainerNodeId, nodeId);
10420 }
10421
10422 void TextFieldPattern::UpdateTextFieldInfo()
10423 {
10424 CHECK_NULL_VOID(IsNeedProcessAutoFill());
10425 auto host = GetHost();
10426 CHECK_NULL_VOID(host);
10427 auto pipeline = host->GetContext();
10428 CHECK_NULL_VOID(pipeline);
10429 auto textFieldManager = DynamicCast<TextFieldManagerNG>(pipeline->GetTextFieldManager());
10430 CHECK_NULL_VOID(textFieldManager);
10431 auto textFieldInfo = GenerateTextFieldInfo();
10432 textFieldManager->UpdateTextFieldInfo(textFieldInfo);
10433 }
10434
10435 bool TextFieldPattern::IsAutoFillUserName(const AceAutoFillType& autoFillType)
10436 {
10437 auto isUserName =
10438 autoFillType == AceAutoFillType::ACE_USER_NAME || autoFillType == AceAutoFillType::ACE_UNSPECIFIED;
10439 return isUserName && HasAutoFillPasswordNode();
10440 }
10441
10442 bool TextFieldPattern::HasAutoFillPasswordNode()
10443 {
10444 auto host = GetHost();
10445 CHECK_NULL_RETURN(host, false);
10446 auto pipeline = host->GetContext();
10447 CHECK_NULL_RETURN(pipeline, false);
10448 auto textFieldManager = DynamicCast<TextFieldManagerNG>(pipeline->GetTextFieldManager());
10449 CHECK_NULL_RETURN(textFieldManager, false);
10450 auto nodeId = host->GetId();
10451 auto autoFillContainerNode = firstAutoFillContainerNode_.Upgrade();
10452 CHECK_NULL_RETURN(autoFillContainerNode, false);
10453 auto autoFillContainerNodeId = autoFillContainerNode->GetId();
10454 return textFieldManager->HasAutoFillPasswordNodeInContainer(autoFillContainerNodeId, nodeId);
10455 }
10456
10457 bool TextFieldPattern::IsTriggerAutoFillPassword()
10458 {
10459 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
10460 CHECK_NULL_RETURN(layoutProperty, false);
10461 auto aceContentType =
10462 TextContentTypeToAceAutoFillType(layoutProperty->GetTextContentTypeValue(TextContentType::UNSPECIFIED));
10463 if (aceContentType != AceAutoFillType::ACE_UNSPECIFIED) {
10464 if (!IsAutoFillPasswordType(aceContentType)) {
10465 return false;
10466 } else {
10467 if (aceContentType == AceAutoFillType::ACE_PASSWORD ||
10468 aceContentType == AceAutoFillType::ACE_NEW_PASSWORD) {
10469 return true;
10470 }
10471 return HasAutoFillPasswordNode();
10472 }
10473 }
10474
10475 auto aceInputType = ConvertToAceAutoFillType(layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED));
10476 if (aceInputType != AceAutoFillType::ACE_UNSPECIFIED) {
10477 if (aceInputType == AceAutoFillType::ACE_PASSWORD || aceInputType == AceAutoFillType::ACE_NEW_PASSWORD) {
10478 return true;
10479 }
10480 }
10481 return HasAutoFillPasswordNode();
10482 }
10483
10484 bool TextFieldPattern::IsNeedProcessAutoFill()
10485 {
10486 return true;
10487 }
10488
10489 std::vector<RectF> TextFieldPattern::GetTextBoxesForSelect()
10490 {
10491 auto selectedRects = GetTextBoxes();
10492 CHECK_NULL_RETURN(paragraph_, selectedRects);
10493 auto paragraphStyle = paragraph_->GetParagraphStyle();
10494 auto textAlign = TextBase::CheckTextAlignByDirection(paragraphStyle.align, paragraphStyle.direction);
10495 const float blankWidth = TextBase::GetSelectedBlankLineWidth();
10496 auto contentWidth = GetTextContentRect().Width();
10497 TextBase::CalculateSelectedRectEx(selectedRects, -1.0f);
10498 for (auto& rect : selectedRects) {
10499 TextBase::UpdateSelectedBlankLineRect(rect, blankWidth, textAlign, contentWidth);
10500 }
10501 return selectedRects;
10502 }
10503
10504 void TextFieldPattern::AdjustSelectedBlankLineWidth(RectF& rect)
10505 {
10506 CHECK_NULL_VOID(paragraph_);
10507 auto paragraphStyle = paragraph_->GetParagraphStyle();
10508 auto textAlign = TextBase::CheckTextAlignByDirection(paragraphStyle.align, paragraphStyle.direction);
10509 const float blankWidth = TextBase::GetSelectedBlankLineWidth();
10510 auto contentWidth = GetTextContentRect().Width();
10511 TextBase::UpdateSelectedBlankLineRect(rect, blankWidth, textAlign, contentWidth + GetTextContentRect().Left());
10512 }
10513
10514 std::optional<TouchLocationInfo> TextFieldPattern::GetAcceptedTouchLocationInfo(const TouchEventInfo& info)
10515 {
10516 auto touchInfos = info.GetChangedTouches();
10517 if (touchInfos.empty()) {
10518 return std::nullopt;
10519 }
10520 if (!moveCaretState_.isMoveCaret && !IsGestureSelectingText()) {
10521 return touchInfos.front();
10522 }
10523 auto fingerId = moveCaretState_.isMoveCaret ? moveCaretState_.touchFingerId : GetSelectingFingerId();
10524 for (auto touchInfo : touchInfos) {
10525 if (touchInfo.GetFingerId() == fingerId) {
10526 return touchInfo;
10527 }
10528 }
10529 return std::nullopt;
10530 }
10531
10532 void TextFieldPattern::DoTextSelectionTouchCancel()
10533 {
10534 CHECK_NULL_VOID(magnifierController_);
10535 magnifierController_->RemoveMagnifierFrameNode();
10536 selectController_->UpdateCaretIndex(selectController_->GetCaretIndex());
10537 StopContentScroll();
10538 StartTwinkling();
10539 }
10540
10541 float TextFieldPattern::GetVerticalPaddingAndBorderSum() const
10542 {
10543 auto border = GetBorderWidthProperty();
10544 if (utilPadding_.has_value()) {
10545 return utilPadding_.value().top.value_or(0.0f) + utilPadding_.value().bottom.value_or(0.0f) +
10546 GetBorderTop(border) + GetBorderBottom(border);
10547 }
10548 auto textFieldTheme = GetTheme();
10549 CHECK_NULL_RETURN(textFieldTheme, 0.0f);
10550 auto themePadding = IsUnderlineMode() ? textFieldTheme->GetUnderlinePadding() : textFieldTheme->GetPadding();
10551 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
10552 CHECK_NULL_RETURN(layoutProperty, themePadding.Top().ConvertToPx() + themePadding.Bottom().ConvertToPx());
10553 const auto& paddingProperty = layoutProperty->GetPaddingProperty();
10554 CHECK_NULL_RETURN(paddingProperty, themePadding.Top().ConvertToPx() + themePadding.Bottom().ConvertToPx());
10555
10556 auto result = static_cast<float>(
10557 paddingProperty->top.value_or(CalcLength(themePadding.Top())).GetDimension().ConvertToPx() +
10558 paddingProperty->bottom.value_or(CalcLength(themePadding.Bottom())).GetDimension().ConvertToPx());
10559 return result + GetBorderTop(border) + GetBorderBottom(border);
10560 }
10561
10562 float TextFieldPattern::GetHorizontalPaddingAndBorderSum() const
10563 {
10564 auto border = GetBorderWidthProperty();
10565 if (utilPadding_.has_value()) {
10566 return utilPadding_.value().left.value_or(0.0f) + utilPadding_.value().right.value_or(0.0f) +
10567 GetBorderLeft(border) + GetBorderRight(border);
10568 }
10569 auto textFieldTheme = GetTheme();
10570 CHECK_NULL_RETURN(textFieldTheme, 0.0f);
10571 auto themePadding = IsUnderlineMode() ? textFieldTheme->GetUnderlinePadding() : textFieldTheme->GetPadding();
10572 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
10573 CHECK_NULL_RETURN(layoutProperty, themePadding.Left().ConvertToPx() + themePadding.Right().ConvertToPx());
10574 const auto& paddingProperty = layoutProperty->GetPaddingProperty();
10575 CHECK_NULL_RETURN(paddingProperty, themePadding.Left().ConvertToPx() + themePadding.Right().ConvertToPx());
10576 auto padding = static_cast<float>(
10577 paddingProperty->left.value_or(CalcLength(themePadding.Left())).GetDimension().ConvertToPx() +
10578 paddingProperty->right.value_or(CalcLength(themePadding.Right())).GetDimension().ConvertToPx());
10579 return padding + GetBorderLeft(border) + GetBorderRight(border);
10580 }
10581
10582 float TextFieldPattern::GetPaddingTop() const
10583 {
10584 if (utilPadding_.has_value()) {
10585 return utilPadding_.value().top.value_or(0.0f);
10586 }
10587 auto textFieldTheme = GetTheme();
10588 CHECK_NULL_RETURN(textFieldTheme, 0.0f);
10589 auto themePadding = IsUnderlineMode() ? textFieldTheme->GetUnderlinePadding() : textFieldTheme->GetPadding();
10590 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
10591 CHECK_NULL_RETURN(layoutProperty, themePadding.Top().ConvertToPx());
10592 const auto& paddingProperty = layoutProperty->GetPaddingProperty();
10593 CHECK_NULL_RETURN(paddingProperty, themePadding.Top().ConvertToPx());
10594 return static_cast<float>(
10595 paddingProperty->top.value_or(CalcLength(themePadding.Top())).GetDimension().ConvertToPx());
10596 }
10597
10598 float TextFieldPattern::GetPaddingBottom() const
10599 {
10600 if (utilPadding_.has_value()) {
10601 return utilPadding_.value().bottom.value_or(0.0f);
10602 }
10603 auto textFieldTheme = GetTheme();
10604 CHECK_NULL_RETURN(textFieldTheme, 0.0f);
10605 auto themePadding = IsUnderlineMode() ? textFieldTheme->GetUnderlinePadding() : textFieldTheme->GetPadding();
10606 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
10607 CHECK_NULL_RETURN(layoutProperty, themePadding.Bottom().ConvertToPx());
10608 const auto& paddingProperty = layoutProperty->GetPaddingProperty();
10609 CHECK_NULL_RETURN(paddingProperty, themePadding.Bottom().ConvertToPx());
10610 return static_cast<float>(
10611 paddingProperty->bottom.value_or(CalcLength(themePadding.Bottom())).GetDimension().ConvertToPx());
10612 }
10613
10614 float TextFieldPattern::GetPaddingLeft() const
10615 {
10616 if (utilPadding_.has_value()) {
10617 return utilPadding_.value().left.value_or(0.0f);
10618 }
10619 auto textFieldTheme = GetTheme();
10620 CHECK_NULL_RETURN(textFieldTheme, 0.0f);
10621 auto themePadding = IsUnderlineMode() ? GetUnderlinePadding(textFieldTheme, true, false) :
10622 textFieldTheme->GetPadding();
10623 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
10624 CHECK_NULL_RETURN(layoutProperty, themePadding.Left().ConvertToPx());
10625 const auto& paddingProperty = layoutProperty->GetPaddingProperty();
10626 CHECK_NULL_RETURN(paddingProperty, themePadding.Left().ConvertToPx());
10627 return static_cast<float>(
10628 paddingProperty->left.value_or(CalcLength(themePadding.Left())).GetDimension().ConvertToPx());
10629 }
10630
10631 float TextFieldPattern::GetPaddingRight() const
10632 {
10633 if (utilPadding_.has_value()) {
10634 return utilPadding_.value().right.value_or(0.0f);
10635 }
10636 auto textFieldTheme = GetTheme();
10637 CHECK_NULL_RETURN(textFieldTheme, 0.0f);
10638 auto themePadding = IsUnderlineMode() ? GetUnderlinePadding(textFieldTheme, false, true) :
10639 textFieldTheme->GetPadding();
10640 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
10641 CHECK_NULL_RETURN(layoutProperty, themePadding.Right().ConvertToPx());
10642 const auto& paddingProperty = layoutProperty->GetPaddingProperty();
10643 CHECK_NULL_RETURN(paddingProperty, themePadding.Right().ConvertToPx());
10644 return static_cast<float>(
10645 paddingProperty->right.value_or(CalcLength(themePadding.Right())).GetDimension().ConvertToPx());
10646 }
10647
10648 BorderWidthProperty TextFieldPattern::GetBorderWidthProperty() const
10649 {
10650 BorderWidthProperty currentBorderWidth;
10651 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
10652 CHECK_NULL_RETURN(layoutProperty, currentBorderWidth);
10653 if (layoutProperty->GetBorderWidthProperty() != nullptr) {
10654 currentBorderWidth = *(layoutProperty->GetBorderWidthProperty());
10655 } else {
10656 currentBorderWidth.SetBorderWidth(BORDER_DEFAULT_WIDTH);
10657 }
10658 return currentBorderWidth;
10659 }
10660
10661 float TextFieldPattern::GetBorderLeft(BorderWidthProperty border) const
10662 {
10663 auto leftBorderWidth = border.leftDimen.value_or(Dimension(0.0f));
10664 auto percentReferenceWidth = GetPercentReferenceWidth();
10665 if (leftBorderWidth.Unit() == DimensionUnit::PERCENT && percentReferenceWidth > 0) {
10666 return leftBorderWidth.Value() * percentReferenceWidth;
10667 }
10668 return leftBorderWidth.ConvertToPx();
10669 }
10670
10671 float TextFieldPattern::GetBorderTop(BorderWidthProperty border) const
10672 {
10673 auto topBorderWidth = border.topDimen.value_or(Dimension(0.0f));
10674 auto percentReferenceWidth = GetPercentReferenceWidth();
10675 if (topBorderWidth.Unit() == DimensionUnit::PERCENT && percentReferenceWidth > 0) {
10676 return topBorderWidth.Value() * percentReferenceWidth;
10677 }
10678 return topBorderWidth.ConvertToPx();
10679 }
10680
10681 float TextFieldPattern::GetBorderBottom(BorderWidthProperty border) const
10682 {
10683 auto bottomBorderWidth = border.bottomDimen.value_or(Dimension(0.0f));
10684 auto percentReferenceWidth = GetPercentReferenceWidth();
10685 if (bottomBorderWidth.Unit() == DimensionUnit::PERCENT && percentReferenceWidth > 0) {
10686 return bottomBorderWidth.Value() * percentReferenceWidth;
10687 }
10688 return bottomBorderWidth.ConvertToPx();
10689 }
10690
10691 float TextFieldPattern::GetBorderRight(BorderWidthProperty border) const
10692 {
10693 auto rightBorderWidth = border.rightDimen.value_or(Dimension(0.0f));
10694 auto percentReferenceWidth = GetPercentReferenceWidth();
10695 if (rightBorderWidth.Unit() == DimensionUnit::PERCENT && percentReferenceWidth > 0) {
10696 return rightBorderWidth.Value() * percentReferenceWidth;
10697 }
10698 return rightBorderWidth.ConvertToPx();
10699 }
10700
10701 void TextFieldPattern::ResetFirstClickAfterGetFocus()
10702 {
10703 if (!firstClickAfterLosingFocus_) {
10704 return;
10705 }
10706 auto host = GetHost();
10707 CHECK_NULL_VOID(host);
10708 auto pipeline = host->GetContext();
10709 CHECK_NULL_VOID(pipeline);
10710 auto taskExecutor = pipeline->GetTaskExecutor();
10711 CHECK_NULL_VOID(taskExecutor);
10712 firstClickResetTask_.Cancel();
10713 firstClickResetTask_.Reset([weak = WeakClaim(this)]() {
10714 auto pattern = weak.Upgrade();
10715 CHECK_NULL_VOID(pattern);
10716 pattern->firstClickAfterLosingFocus_ = false;
10717 });
10718 taskExecutor->PostDelayedTask(
10719 firstClickResetTask_, TaskExecutor::TaskType::UI, TWINKLING_INTERVAL_MS, "ResetFirstClickAfterGetFocusTask");
10720 }
10721
10722 SelectionInfo TextFieldPattern::GetSelection()
10723 {
10724 SelectionInfo selection;
10725 selection.SetSelectionStart(selectController_->GetStartIndex());
10726 selection.SetSelectionEnd(selectController_->GetEndIndex());
10727 return selection;
10728 }
10729
10730 FocusPattern TextFieldPattern::GetFocusPattern() const
10731 {
10732 FocusPattern focusPattern = { FocusType::NODE, true, FocusStyleType::FORCE_NONE };
10733 focusPattern.SetIsFocusActiveWhenFocused(true);
10734 auto host = GetHost();
10735 CHECK_NULL_RETURN(host, focusPattern);
10736 auto pipelineContext = host->GetContext();
10737 CHECK_NULL_RETURN(pipelineContext, focusPattern);
10738 auto theme = pipelineContext->GetTheme<TextFieldTheme>();
10739 CHECK_NULL_RETURN(theme, focusPattern);
10740 if (theme->NeedFocusBox()) {
10741 focusPattern.SetStyleType(FocusStyleType::OUTER_BORDER);
10742 }
10743 return focusPattern;
10744 }
10745
10746 bool TextFieldPattern::FireOnWillChange(const ChangeValueInfo& changeValueInfo)
10747 {
10748 auto host = GetHost();
10749 CHECK_NULL_RETURN(host, true);
10750 auto eventHub = host->GetOrCreateEventHub<TextFieldEventHub>();
10751 CHECK_NULL_RETURN(eventHub, true);
10752 callbackRangeBefore_ = changeValueInfo.rangeBefore;
10753 callbackRangeAfter_ = changeValueInfo.rangeAfter;
10754 callbackOldContent_ = changeValueInfo.oldContent;
10755 callbackOldPreviewText_ = changeValueInfo.oldPreviewText;
10756 return eventHub->FireOnWillChangeEvent(changeValueInfo);
10757 }
10758
10759 bool TextFieldPattern::OnWillChangePreInsert(const std::u16string& insertValue, const std::u16string& oldContent,
10760 uint32_t start, uint32_t end)
10761 {
10762 auto host = GetHost();
10763 CHECK_NULL_RETURN(host, true);
10764 auto eventHub = host->GetOrCreateEventHub<TextFieldEventHub>();
10765 CHECK_NULL_RETURN(eventHub, true);
10766 ChangeValueInfo changeValueInfo;
10767 PreviewText previewText {.offset = -1, .value = u""};
10768 if (hasPreviewText_) {
10769 previewText.offset = GetPreviewTextStart();
10770 previewText.value = GetPreviewTextValue();
10771 }
10772 changeValueInfo.oldPreviewText = previewText;
10773 changeValueInfo.previewText = previewText;
10774
10775 auto insertLength = insertValue.length();
10776 changeValueInfo.rangeBefore = TextRange { start, end };
10777 changeValueInfo.rangeAfter = TextRange { start, start + insertLength };
10778
10779 changeValueInfo.oldContent = oldContent;
10780 changeValueInfo.value = contentController_->GetTextUtf16Value();
10781 callbackRangeBefore_ = changeValueInfo.rangeBefore;
10782 callbackRangeAfter_ = changeValueInfo.rangeAfter;
10783 callbackOldContent_ = changeValueInfo.oldContent;
10784 callbackOldPreviewText_ = changeValueInfo.oldPreviewText;
10785 return eventHub->FireOnWillChangeEvent(changeValueInfo);
10786 }
10787
10788 bool TextFieldPattern::OnWillChangePreDelete(const std::u16string& oldContent, uint32_t start, uint32_t end)
10789 {
10790 auto host = GetHost();
10791 CHECK_NULL_RETURN(host, true);
10792 auto eventHub = host->GetOrCreateEventHub<TextFieldEventHub>();
10793 CHECK_NULL_RETURN(eventHub, true);
10794 ChangeValueInfo changeValueInfo;
10795 PreviewText previewText {.offset = -1, .value = u""};
10796 if (hasPreviewText_) {
10797 previewText.offset = GetPreviewTextStart();
10798 previewText.value = GetPreviewTextValue();
10799 }
10800 changeValueInfo.oldPreviewText = previewText;
10801 changeValueInfo.previewText = previewText;
10802
10803 changeValueInfo.rangeBefore = TextRange { start, end };
10804 changeValueInfo.rangeAfter = TextRange { start, start };
10805
10806 changeValueInfo.oldContent = oldContent;
10807 changeValueInfo.value = contentController_->GetTextUtf16Value();
10808 callbackRangeBefore_ = changeValueInfo.rangeBefore;
10809 callbackRangeAfter_ = changeValueInfo.rangeAfter;
10810 callbackOldContent_ = changeValueInfo.oldContent;
10811 callbackOldPreviewText_ = changeValueInfo.oldPreviewText;
10812 return eventHub->FireOnWillChangeEvent(changeValueInfo);
10813 }
10814
10815 bool TextFieldPattern::OnWillChangePreSetValue(const std::u16string& newValue)
10816 {
10817 auto host = GetHost();
10818 CHECK_NULL_RETURN(host, true);
10819 auto eventHub = host->GetOrCreateEventHub<TextFieldEventHub>();
10820 CHECK_NULL_RETURN(eventHub, true);
10821 ChangeValueInfo changeValueInfo;
10822 changeValueInfo.oldContent = contentController_->GetTextUtf16Value();
10823 changeValueInfo.value = newValue;
10824 changeValueInfo.previewText.offset = hasPreviewText_ ? GetPreviewTextStart() : -1;
10825 changeValueInfo.previewText.value = GetPreviewTextValue();
10826 changeValueInfo.oldPreviewText.offset = hasPreviewText_ ? GetPreviewTextStart() : -1;
10827 changeValueInfo.oldPreviewText.value = GetPreviewTextValue();
10828 changeValueInfo.rangeBefore = TextRange { 0, contentController_->GetTextUtf16Value().length() };
10829 changeValueInfo.rangeAfter = TextRange { 0, newValue.length() };
10830 callbackRangeBefore_ = changeValueInfo.rangeBefore;
10831 callbackRangeAfter_ = changeValueInfo.rangeAfter;
10832 callbackOldContent_ = changeValueInfo.oldContent;
10833 callbackOldPreviewText_ = changeValueInfo.oldPreviewText;
10834 return eventHub->FireOnWillChangeEvent(changeValueInfo);
10835 }
10836
10837 void TextFieldPattern::RecoverTextValueAndCaret(const std::u16string& oldValue, TextRange caretIndex)
10838 {
10839 contentController_->SetTextValueOnly(oldValue);
10840 selectController_->UpdateHandleIndex(caretIndex.start, caretIndex.end);
10841 if (IsSelected()) {
10842 ProcessOverlay({ .menuIsShow = false });
10843 }
10844 }
10845
10846 void TextFieldPattern::AddInsertCommand(const std::u16string& insertValue, InputReason reason)
10847 {
10848 auto host = GetHost();
10849 CHECK_NULL_VOID(host);
10850 ACE_SCOPED_TRACE("TextInput[%d]AddInsertCommand freeze:[%d] previewText:[%d]", host->GetId(),
10851 host->IsFreeze(), GetIsPreviewText());
10852 if (reason != InputReason::PASTE) {
10853 if (!HasFocus()) {
10854 int32_t frameId = host->GetId();
10855 TAG_LOGW(AceLogTag::ACE_TEXT_FIELD, "textfield %{public}d on blur, can't insert value", frameId);
10856 int32_t depth = host->GetDepth();
10857 std::string errorType = "textfield on blur, can't insert value";
10858 EventReport::ReportTextFieldErrorEvent(frameId, depth, errorType);
10859 auto currentFocusNode = InputMethodManager::GetInstance()->GetCurFocusNode();
10860 auto curFocusNode = currentFocusNode.Upgrade();
10861 CHECK_NULL_VOID(curFocusNode);
10862 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "curFocusNode:%{public}s, ", curFocusNode->GetTag().c_str());
10863 return;
10864 }
10865 if (!isEdit_ || (reason == InputReason::IME && IsDragging())) {
10866 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD,
10867 "textfield %{public}d NOT allow input, isEdit_ = %{public}d, IsDragging = %{public}d", host->GetId(),
10868 isEdit_, IsDragging());
10869 return;
10870 }
10871 }
10872 if (focusIndex_ != FocuseIndex::TEXT) {
10873 if (insertValue == u" ") {
10874 HandleSpaceEvent();
10875 }
10876 return;
10877 }
10878 if (FinishTextPreviewByPreview(insertValue)) {
10879 return;
10880 }
10881 inputOperations_.emplace(InputOperation::INSERT);
10882 InsertCommandInfo info;
10883 info.insertValue = insertValue;
10884 info.reason = reason;
10885 insertCommands_.emplace(info);
10886 CloseSelectOverlay(true);
10887 ScrollToSafeArea();
10888 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
10889 }
10890
10891 void TextFieldPattern::AddInputCommand(const InputCommandInfo& inputCommandInfo)
10892 {
10893 auto host = GetHost();
10894 CHECK_NULL_VOID(host);
10895 inputOperations_.emplace(InputOperation::INPUT);
10896 inputCommands_.emplace(inputCommandInfo);
10897 CloseSelectOverlay(true);
10898 ScrollToSafeArea();
10899 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
10900 }
10901
10902 void TextFieldPattern::ExecuteInputCommand(const InputCommandInfo& info)
10903 {
10904 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
10905 CHECK_NULL_VOID(layoutProperty);
10906 auto start = info.deleteRange.start;
10907 auto end = info.deleteRange.end;
10908 auto insertValue = info.insertValue;
10909 auto caretIndex = info.insertOffset;
10910 auto originCaretIndex =
10911 TextRange { selectController_->GetFirstHandleIndex(), selectController_->GetSecondHandleIndex() };
10912 if ((info.reason == InputReason::IME || info.reason == InputReason::AI_WRITE) && !insertValue.empty()) {
10913 auto isInsert = BeforeIMEInsertValue(insertValue, caretIndex - (end - start));
10914 CHECK_NULL_VOID(isInsert);
10915 }
10916
10917 ChangeValueInfo changeValueInfo;
10918 changeValueInfo.oldContent = contentController_->GetTextUtf16Value();
10919 changeValueInfo.oldPreviewText.offset = hasPreviewText_ ? GetPreviewTextStart() : -1;
10920 changeValueInfo.oldPreviewText.value = GetPreviewTextValue();
10921 changeValueInfo.rangeBefore = TextRange { start, end };
10922
10923 auto isDelete = true;
10924 if (start != end) {
10925 auto deleteValue = contentController_->GetSelectedValue(start, end);
10926 if (info.reason == InputReason::IME || info.reason == InputReason::AI_WRITE) {
10927 isDelete = BeforeIMEDeleteValue(deleteValue, TextDeleteDirection::BACKWARD, end);
10928 }
10929 contentController_->erase(start, end - start);
10930 selectController_->UpdateCaretIndex(start);
10931 if ((info.reason == InputReason::IME || info.reason == InputReason::AI_WRITE) && isDelete) {
10932 AfterIMEDeleteValue(deleteValue, TextDeleteDirection::BACKWARD);
10933 }
10934 }
10935
10936 int32_t insertLength = 0;
10937 if (!insertValue.empty()) {
10938 if (info.insertOffset >= end && isDelete) {
10939 caretIndex = caretIndex - (end - start);
10940 }
10941 auto originLength = contentController_->GetTextUtf16Value().length();
10942 auto hasInsertValue = contentController_->InsertValue(caretIndex, info.insertValue);
10943 insertLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length() - originLength);
10944 caretIndex += insertLength;
10945
10946 if (layoutProperty->HasMaxLength()) {
10947 CalcCounterAfterFilterInsertValue(originLength, insertValue,
10948 static_cast<int32_t>(layoutProperty->GetMaxLengthValue(Infinity<uint32_t>())));
10949 }
10950 selectController_->UpdateCaretIndex(caretIndex);
10951 UpdateObscure(insertValue, hasInsertValue);
10952 if (info.reason == InputReason::IME || info.reason == InputReason::AI_WRITE) {
10953 AfterIMEInsertValue(contentController_->GetInsertValue());
10954 }
10955 }
10956
10957 changeValueInfo.value = contentController_->GetTextUtf16Value();
10958 changeValueInfo.previewText.offset = hasPreviewText_ ? GetPreviewTextStart() : -1;
10959 changeValueInfo.previewText.value = GetPreviewTextValue();
10960 changeValueInfo.rangeAfter = TextRange { caretIndex - insertLength, caretIndex };
10961
10962 bool isWillChange = FireOnWillChange(changeValueInfo);
10963 if (!isWillChange) {
10964 RecoverTextValueAndCaret(changeValueInfo.oldContent, originCaretIndex);
10965 return;
10966 }
10967 UpdateEditingValueToRecord();
10968 TwinklingByFocus();
10969 }
10970
10971 void TextFieldPattern::ClearTextContent()
10972 {
10973 if (GetIsPreviewText()) {
10974 PreviewTextInfo info = {
10975 .text = u"",
10976 .range = {-1, -1}
10977 };
10978 SetPreviewTextOperation(info);
10979 hasPreviewText_ = false;
10980 }
10981 if (contentController_->IsEmpty()) {
10982 return;
10983 }
10984 showCountBorderStyle_ = false;
10985 HandleCountStyle();
10986 InputCommandInfo inputCommandInfo;
10987 inputCommandInfo.deleteRange = { 0, contentController_->GetTextUtf16Value().length() };
10988 inputCommandInfo.insertOffset = 0;
10989 inputCommandInfo.insertValue = u"";
10990 inputCommandInfo.reason = InputReason::CANCEL_BUTTON;
10991 AddInputCommand(inputCommandInfo);
10992 }
10993
10994 // return: whether the offset is valid, return false if invalid
10995 bool TextFieldPattern::GetOriginCaretPosition(OffsetF& offset) const
10996 {
10997 if (!originCaretPosition_.NonNegative()) {
10998 return false;
10999 }
11000 offset = originCaretPosition_;
11001 return true;
11002 }
11003
11004 void TextFieldPattern::ResetOriginCaretPosition()
11005 {
11006 originCaretPosition_ = DEFAULT_NEGATIVE_CARET_OFFSET;
11007 }
11008
11009 // Record current caret position if originCaretPosition_ is invalid
11010 // return: whether the current offset is recorded and valid
11011 bool TextFieldPattern::RecordOriginCaretPosition()
11012 {
11013 if (originCaretPosition_.NonNegative()) {
11014 return false;
11015 }
11016 originCaretPosition_ = selectController_->GetCaretRect().GetOffset();
11017 return originCaretPosition_.NonNegative();
11018 }
11019
11020 void TextFieldPattern::SetIsEnableSubWindowMenu()
11021 {
11022 if (selectOverlay_) {
11023 auto enable = !IsNeedProcessAutoFill() || !CheckAutoFill();
11024 selectOverlay_->SetIsHostNodeEnableSubWindowMenu(enable);
11025 if (!enable) {
11026 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "SetIsEnableSubWindowMenu not enable");
11027 }
11028 }
11029 }
11030
11031 void TextFieldPattern::InitCancelButtonMouseEvent()
11032 {
11033 CHECK_NULL_VOID(cleanNodeResponseArea_);
11034 auto cleanNodeResponseArea = AceType::DynamicCast<CleanNodeResponseArea>(cleanNodeResponseArea_);
11035 CHECK_NULL_VOID(cleanNodeResponseArea);
11036 auto stackNode = cleanNodeResponseArea->GetFrameNode();
11037 CHECK_NULL_VOID(stackNode);
11038 auto imageTouchHub = stackNode->GetOrCreateGestureEventHub();
11039 CHECK_NULL_VOID(imageTouchHub);
11040 auto imageInputHub = stackNode->GetOrCreateInputEventHub();
11041 CHECK_NULL_VOID(imageInputHub);
11042 auto imageHoverTask = [weak = WeakClaim(this), cleanNodeResponseAreaWeak =
11043 WeakPtr<TextInputResponseArea>(cleanNodeResponseArea_)](bool isHover, const HoverInfo& info) {
11044 auto cleanNodeResponseArea = cleanNodeResponseAreaWeak.Upgrade();
11045 CHECK_NULL_VOID(cleanNodeResponseArea);
11046 auto pattern = weak.Upgrade();
11047 if (pattern) {
11048 pattern->OnHover(isHover, info);
11049 pattern->HandleButtonMouseEvent(cleanNodeResponseArea, isHover);
11050 }
11051 };
11052 imageHoverEvent_ = MakeRefPtr<InputEvent>(std::move(imageHoverTask));
11053 imageInputHub->AddOnHoverEvent(imageHoverEvent_);
11054
11055 auto imageTouchTask = [weak = WeakClaim(this), cleanNodeResponseAreaWeak =
11056 WeakPtr<TextInputResponseArea>(cleanNodeResponseArea_)](const TouchEventInfo& info) {
11057 auto cleanNodeResponseArea = cleanNodeResponseAreaWeak.Upgrade();
11058 CHECK_NULL_VOID(cleanNodeResponseArea);
11059 auto pattern = weak.Upgrade();
11060 CHECK_NULL_VOID(pattern);
11061 auto touchType = info.GetTouches().front().GetTouchType();
11062 if (touchType == TouchType::DOWN) {
11063 pattern->HandleCancelButtonTouchDown(cleanNodeResponseArea);
11064 }
11065 if (touchType == TouchType::UP || touchType == TouchType::CANCEL) {
11066 pattern->HandleCancelButtonTouchUp();
11067 }
11068 };
11069
11070 imageTouchEvent_ = MakeRefPtr<TouchEventImpl>(std::move(imageTouchTask));
11071 imageTouchHub->AddTouchEvent(imageTouchEvent_);
11072 }
11073
11074 void TextFieldPattern::InitPasswordButtonMouseEvent()
11075 {
11076 CHECK_NULL_VOID(responseArea_);
11077 auto passwordResponseArea = AceType::DynamicCast<PasswordResponseArea>(responseArea_);
11078 CHECK_NULL_VOID(passwordResponseArea);
11079 auto stackNode = passwordResponseArea->GetFrameNode();
11080 CHECK_NULL_VOID(stackNode);
11081 auto imageTouchHub = stackNode->GetOrCreateGestureEventHub();
11082 CHECK_NULL_VOID(imageTouchHub);
11083 auto imageInputHub = stackNode->GetOrCreateInputEventHub();
11084 CHECK_NULL_VOID(imageInputHub);
11085 auto imageHoverTask = [weak = WeakClaim(this), responseAreaWeak =
11086 WeakPtr<TextInputResponseArea>(responseArea_)](bool isHover, const HoverInfo& info) {
11087 auto responseArea = responseAreaWeak.Upgrade();
11088 CHECK_NULL_VOID(responseArea);
11089 auto pattern = weak.Upgrade();
11090 if (pattern) {
11091 pattern->OnHover(isHover, info);
11092 pattern->HandleButtonMouseEvent(responseArea, isHover);
11093 }
11094 };
11095 imageHoverEvent_ = MakeRefPtr<InputEvent>(std::move(imageHoverTask));
11096 imageInputHub->AddOnHoverEvent(imageHoverEvent_);
11097
11098 auto imageTouchTask = [weak = WeakClaim(this), responseAreaWeak = WeakPtr<TextInputResponseArea>(responseArea_)]
11099 (const TouchEventInfo& info) {
11100 auto responseArea = responseAreaWeak.Upgrade();
11101 CHECK_NULL_VOID(responseArea);
11102 auto pattern = weak.Upgrade();
11103 CHECK_NULL_VOID(pattern);
11104 auto touchType = info.GetTouches().front().GetTouchType();
11105 if (touchType == TouchType::DOWN) {
11106 pattern->HandleCancelButtonTouchDown(responseArea);
11107 }
11108 if (touchType == TouchType::UP || touchType == TouchType::CANCEL) {
11109 pattern->HandleCancelButtonTouchUp();
11110 }
11111 };
11112 imageTouchEvent_ = MakeRefPtr<TouchEventImpl>(std::move(imageTouchTask));
11113 imageTouchHub->AddTouchEvent(imageTouchEvent_);
11114 }
11115
11116 void TextFieldPattern::HandleCancelButtonTouchDown(const RefPtr<TextInputResponseArea>& responseArea)
11117 {
11118 auto host = GetHost();
11119 CHECK_NULL_VOID(host);
11120 RoundRect mouseRect;
11121 CHECK_NULL_VOID(responseArea);
11122 responseArea->CreateIconRect(mouseRect, false);
11123 float cornerRadius = mouseRect.GetRect().Width() / 2;
11124 mouseRect.SetCornerRadius(cornerRadius);
11125 auto textFieldTheme = GetTheme();
11126 CHECK_NULL_VOID(textFieldTheme);
11127 auto touchColor = textFieldTheme->GetPressColor();
11128 std::vector<RoundRect> roundRectVector;
11129 roundRectVector.push_back(mouseRect);
11130 CHECK_NULL_VOID(textFieldOverlayModifier_);
11131 textFieldOverlayModifier_->SetHoverColorAndRects(roundRectVector, touchColor.GetValue());
11132 cancelButtonTouched_ = true;
11133 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
11134 }
11135
11136 void TextFieldPattern::HandleCancelButtonTouchUp()
11137 {
11138 auto host = GetHost();
11139 CHECK_NULL_VOID(host);
11140 CHECK_NULL_VOID(textFieldOverlayModifier_);
11141 textFieldOverlayModifier_->ClearHoverColorAndRects();
11142 cancelButtonTouched_ = false;
11143 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
11144 }
11145
11146 void TextFieldPattern::HandleButtonMouseEvent(const RefPtr<TextInputResponseArea>& responseArea, bool isHover)
11147 {
11148 auto host = GetHost();
11149 CHECK_NULL_VOID(host);
11150 CHECK_NULL_VOID(textFieldOverlayModifier_);
11151 if (isHover) {
11152 RoundRect mouseRect;
11153 CHECK_NULL_VOID(responseArea);
11154 responseArea->CreateIconRect(mouseRect, false);
11155 float cornerRadius = mouseRect.GetRect().Width() / 2;
11156 mouseRect.SetCornerRadius(cornerRadius);
11157 auto textFieldTheme = GetTheme();
11158 CHECK_NULL_VOID(textFieldTheme);
11159 auto touchColor = textFieldTheme->GetHoverColor();
11160 std::vector<RoundRect> roundRectVector;
11161 roundRectVector.push_back(mouseRect);
11162 textFieldOverlayModifier_->SetHoverColorAndRects(roundRectVector, touchColor.GetValue());
11163 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
11164 } else {
11165 textFieldOverlayModifier_->ClearHoverColorAndRects();
11166 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
11167 }
11168 }
11169
11170 double TextFieldPattern::GetPercentReferenceWidth() const
11171 {
11172 auto host = GetHost();
11173 if (host && host->GetGeometryNode() && host->GetGeometryNode()->GetParentLayoutConstraint().has_value()) {
11174 return host->GetGeometryNode()->GetParentLayoutConstraint()->percentReference.Width();
11175 }
11176 return 0.0f;
11177 }
11178
11179 void TextFieldPattern::NotifyKeyboardClosedByUser()
11180 {
11181 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "NotifyKeyboardClosedByUser");
11182 CHECK_NULL_VOID(HasFocus());
11183 isKeyboardClosedByUser_ = true;
11184 FocusHub::LostFocusToViewRoot();
11185 isKeyboardClosedByUser_ = false;
11186 }
11187
11188 void TextFieldPattern::NotifyKeyboardClosed()
11189 {
11190 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "NotifyKeyboardClosed");
11191 CHECK_NULL_VOID(IsStopEditWhenCloseKeyboard()); // false when specified product
11192 if (HasFocus() && !(customKeyboard_ || customKeyboardBuilder_)) {
11193 FocusHub::LostFocusToViewRoot();
11194 }
11195 }
11196
11197 bool TextFieldPattern::BetweenSelectedPosition(const Offset& globalOffset)
11198 {
11199 if (!IsSelected()) {
11200 return false;
11201 }
11202 auto localOffset = ConvertGlobalToLocalOffset(globalOffset);
11203 auto offsetX = IsTextArea() ? contentRect_.GetX() : textRect_.GetX();
11204 auto offsetY = IsTextArea() ? textRect_.GetY() : contentRect_.GetY();
11205 Offset offset = localOffset - Offset(offsetX, offsetY);
11206 for (const auto& rect : selectController_->GetSelectedRects()) {
11207 bool isInRange = rect.IsInRegion({ offset.GetX(), offset.GetY() });
11208 if (isInRange) {
11209 return true;
11210 }
11211 }
11212 return false;
11213 }
11214
11215 void TextFieldPattern::SetUnitNode(const RefPtr<NG::UINode>& unitNode)
11216 {
11217 if (unitNode_ && responseArea_) {
11218 // clear old node
11219 auto unitResponseArea = AceType::DynamicCast<UnitResponseArea>(responseArea_);
11220 CHECK_NULL_VOID(unitResponseArea);
11221 unitResponseArea->ClearArea();
11222 responseArea_ = nullptr;
11223 }
11224 unitNode_ = unitNode;
11225 }
11226
11227 void TextFieldPattern::SetCustomKeyboard(const std::function<void()>&& keyboardBuilder)
11228 {
11229 if (customKeyboardBuilder_ && isCustomKeyboardAttached_ && !keyboardBuilder) {
11230 // close customKeyboard and request system keyboard
11231 CloseCustomKeyboard();
11232 customKeyboardBuilder_ = keyboardBuilder; // refresh current keyboard
11233 RequestKeyboardNotByFocusSwitch(RequestKeyboardReason::CUSTOM_KEYBOARD);
11234 StartTwinkling();
11235 return;
11236 }
11237 if (!customKeyboardBuilder_ && keyboardBuilder) {
11238 // close system keyboard and request custom keyboard
11239 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
11240 if (imeShown_) {
11241 CloseKeyboard(true);
11242 customKeyboardBuilder_ = keyboardBuilder; // refresh current keyboard
11243 RequestKeyboardNotByFocusSwitch(RequestKeyboardReason::CUSTOM_KEYBOARD);
11244 StartTwinkling();
11245 return;
11246 }
11247 #endif
11248 }
11249 customKeyboardBuilder_ = keyboardBuilder;
11250 }
11251
11252 void TextFieldPattern::SetCustomKeyboardWithNode(const RefPtr<UINode>& keyboardBuilder)
11253 {
11254 auto host = GetHost();
11255 FREE_NODE_CHECK(host, SetCustomKeyboardWithNode,
11256 keyboardBuilder); // call SetCustomKeyboardWithNodeMultiThread() by multi thread
11257 if (customKeyboard_ && isCustomKeyboardAttached_ && !keyboardBuilder) {
11258 // close customKeyboard and request system keyboard
11259 CloseCustomKeyboard();
11260 customKeyboard_ = keyboardBuilder; // refresh current keyboard
11261 RequestKeyboardNotByFocusSwitch(RequestKeyboardReason::CUSTOM_KEYBOARD);
11262 StartTwinkling();
11263 return;
11264 }
11265 if (!customKeyboard_ && keyboardBuilder) {
11266 // close system keyboard and request custom keyboard
11267 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
11268 if (imeShown_) {
11269 CloseKeyboard(true);
11270 customKeyboard_ = keyboardBuilder; // refresh current keyboard
11271 RequestKeyboardNotByFocusSwitch(RequestKeyboardReason::CUSTOM_KEYBOARD);
11272 StartTwinkling();
11273 return;
11274 }
11275 #endif
11276 }
11277 customKeyboard_ = keyboardBuilder;
11278 }
11279
11280 bool TextFieldPattern::IsStopEditWhenCloseKeyboard()
11281 {
11282 auto host = GetHost();
11283 CHECK_NULL_RETURN(host, true);
11284 auto context = host->GetContext();
11285 CHECK_NULL_RETURN(context, true);
11286 return !(context->GetIsFocusActive() && independentControlKeyboard_);
11287 }
11288
11289 void TextFieldPattern::OnReportPasteEvent(const RefPtr<FrameNode>& frameNode)
11290 {
11291 CHECK_NULL_VOID(frameNode);
11292 if (frameNode->GetTag() == V2::TEXTINPUT_ETS_TAG) {
11293 UiSessionManager::GetInstance()->ReportComponentChangeEvent("event", "TextInput.onPasteComplete");
11294 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "nodeId:[%{public}d] TextInput reportComponentChangeEvent onPasteComplete",
11295 frameNode->GetId());
11296 } else if (frameNode->GetTag() == V2::SEARCH_Field_ETS_TAG) {
11297 UiSessionManager::GetInstance()->ReportComponentChangeEvent("event", "Search.onPasteComplete");
11298 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "nodeId:[%{public}d] Search reportComponentChangeEvent onPasteComplete",
11299 frameNode->GetId());
11300 }
11301 }
11302
11303 void TextFieldPattern::OnReportSubmitEvent(const RefPtr<FrameNode>& frameNode)
11304 {
11305 CHECK_NULL_VOID(frameNode);
11306 if (frameNode->GetTag() == V2::TEXTINPUT_ETS_TAG) {
11307 UiSessionManager::GetInstance()->ReportComponentChangeEvent("event", "TextInput.onSubmitComplete");
11308 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "nodeId:[%{public}d] TextInput reportComponentChangeEvent onSubmitComplete",
11309 frameNode->GetId());
11310 }
11311 }
11312
11313 void TextFieldPattern::BeforeAutoFillAnimation(const std::u16string& content, const AceAutoFillType& type)
11314 {
11315 auto host = GetHost();
11316 CHECK_NULL_VOID(host);
11317 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
11318 CHECK_NULL_VOID(layoutProperty);
11319 auto enableAutoFillAnimation = layoutProperty->GetEnableAutoFillAnimationValue(true);
11320 auto textValue = content;
11321 contentController_->FilterValue(textValue);
11322 CHECK_NULL_VOID(GetOrCreateAutoFillController());
11323 autoFillController_->SetAutoFillTextUtf16Value(textValue);
11324 auto onFinishCallback = [weak = AceType::WeakClaim(this), textValue, unFilteredValue = content]() {
11325 auto textFieldPattern = weak.Upgrade();
11326 CHECK_NULL_VOID(textFieldPattern);
11327 auto autoFillController = textFieldPattern->GetOrCreateAutoFillController();
11328 CHECK_NULL_VOID(autoFillController);
11329 autoFillController->ResetAutoFillAnimationStatus();
11330 auto hostNode = textFieldPattern->GetHost();
11331 CHECK_NULL_VOID(hostNode);
11332 if (!textFieldPattern->OnWillChangePreSetValue(unFilteredValue)) {
11333 hostNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
11334 return;
11335 }
11336 auto contentController = textFieldPattern->GetTextContentController();
11337 CHECK_NULL_VOID(contentController);
11338 contentController->SetTextValue(unFilteredValue);
11339 auto textLength = static_cast<int32_t>(contentController->GetTextUtf16Value().length());
11340 auto selectController = textFieldPattern->GetTextSelectController();
11341 CHECK_NULL_VOID(selectController);
11342 selectController->UpdateCaretIndex(textLength);
11343 hostNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
11344 };
11345 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
11346 auto needsAnimation = pipeline && enableAutoFillAnimation &&
11347 (type == AceAutoFillType::ACE_NEW_PASSWORD || type == AceAutoFillType::ACE_PASSWORD) &&
11348 textValue.length() > 0;
11349 if (needsAnimation) {
11350 autoFillController_->SetAutoFillAnimationStatus(AutoFillAnimationStatus::SHOW_ICON);
11351 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
11352 pipeline->AddAfterLayoutTask(
11353 [weak = AceType::WeakClaim(this), onFinish = std::move(onFinishCallback), textValue]() {
11354 auto textFieldPattern = weak.Upgrade();
11355 CHECK_NULL_VOID(textFieldPattern);
11356 auto autoFillController = textFieldPattern->GetOrCreateAutoFillController();
11357 CHECK_NULL_VOID(autoFillController);
11358 autoFillController->StartAutoFillAnimation(onFinish, textValue);
11359 });
11360 } else {
11361 onFinishCallback();
11362 }
11363 }
11364
11365 void TextFieldPattern::RemoveFillContentMap()
11366 {
11367 auto host = GetHost();
11368 CHECK_NULL_VOID(host);
11369 auto pipeline = host->GetContext();
11370 CHECK_NULL_VOID(pipeline);
11371 auto textFieldManager = DynamicCast<TextFieldManagerNG>(pipeline->GetTextFieldManager());
11372 CHECK_NULL_VOID(textFieldManager);
11373 auto nodeId = host->GetId();
11374 textFieldManager->RemoveFillContentMap(nodeId);
11375 }
11376
11377 bool TextFieldPattern::NeedsSendFillContent()
11378 {
11379 CHECK_NULL_RETURN(IsNeedProcessAutoFill(), false);
11380 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
11381 CHECK_NULL_RETURN(layoutProperty, false);
11382 bool isEnableAutoFill = layoutProperty->GetEnableAutoFillValue(true);
11383 if (!isEnableAutoFill) {
11384 return false;
11385 }
11386 return IsTriggerAutoFillPassword();
11387 }
11388
11389 void TextFieldPattern::OnAccessibilityEventTextChange(const std::string& changeType, const std::string& changeString)
11390 {
11391 auto pipeline = GetContext();
11392 CHECK_NULL_VOID(pipeline);
11393 auto host = GetHost();
11394 CHECK_NULL_VOID(host);
11395 AccessibilityEvent event;
11396 event.type = AccessibilityEventType::TEXT_CHANGE;
11397 event.nodeId = host->GetAccessibilityId();
11398 std::string finalText;
11399 if (IsInPasswordMode()) {
11400 char16_t obscuring =
11401 Localization::GetInstance()->GetLanguage() == "ar" ? OBSCURING_CHARACTER_FOR_AR : OBSCURING_CHARACTER;
11402 finalText = UtfUtils::Str16DebugToStr8(std::u16string(changeString.length(), obscuring));
11403 } else {
11404 finalText = changeString;
11405 }
11406 event.extraEventInfo.insert({ changeType, finalText });
11407 pipeline->SendEventToAccessibilityWithNode(event, GetHost());
11408 }
11409
11410 IMEClient TextFieldPattern::GetIMEClientInfo()
11411 {
11412 IMEClient clientInfo;
11413 auto host = GetHost();
11414 CHECK_NULL_RETURN(host, clientInfo);
11415 clientInfo.nodeId = host->GetId();
11416 return clientInfo;
11417 }
11418
11419 void TextFieldPattern::FireOnWillAttachIME()
11420 {
11421 auto host = GetHost();
11422 CHECK_NULL_VOID(host);
11423 auto eventHub = host->GetEventHub<TextFieldEventHub>();
11424 CHECK_NULL_VOID(eventHub);
11425 eventHub->FireOnWillAttachIME(GetIMEClientInfo());
11426 }
11427
11428 void TextFieldPattern::OnColorModeChange(uint32_t colorMode)
11429 {
11430 Pattern::OnColorModeChange(colorMode);
11431 auto host = GetHost();
11432 CHECK_NULL_VOID(host);
11433 host->MarkModifyDone();
11434 }
11435
11436 #define DEFINE_PROP_HANDLER(KEY_TYPE, VALUE_TYPE, UPDATE_METHOD) \
11437 { \
11438 #KEY_TYPE, [](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) { \
11439 if (auto realValue = std::get_if<VALUE_TYPE>(&(value->GetValue()))) { \
11440 prop->UPDATE_METHOD(*realValue); \
11441 } \
11442 } \
11443 }
11444
11445 void TextFieldPattern::UpdatePropertyImpl(const std::string& key, RefPtr<PropertyValueBase> value)
11446 {
11447 auto frameNode = GetHost();
11448 CHECK_NULL_VOID(frameNode);
11449 auto layoutProperty = frameNode->GetLayoutPropertyPtr<TextFieldLayoutProperty>();
11450 CHECK_NULL_VOID(layoutProperty);
11451 CHECK_NULL_VOID(value);
11452
11453 using Handler = std::function<void(TextFieldLayoutProperty*, RefPtr<PropertyValueBase>)>;
11454 const std::unordered_map<std::string, Handler> handlers = {
11455 DEFINE_PROP_HANDLER(fontSize, CalcDimension, UpdateFontSize),
11456 DEFINE_PROP_HANDLER(decorationColor, Color, UpdateTextDecorationColor),
11457 DEFINE_PROP_HANDLER(minFontSize, CalcDimension, UpdateAdaptMinFontSize),
11458 DEFINE_PROP_HANDLER(maxFontSize, CalcDimension, UpdateAdaptMaxFontSize),
11459 DEFINE_PROP_HANDLER(lineHeight, CalcDimension, UpdateLineHeight),
11460 DEFINE_PROP_HANDLER(lineHeight, CalcDimension, UpdateLineHeight),
11461 DEFINE_PROP_HANDLER(cancelButtonIconSrc, std::string, UpdateIconSrc),
11462
11463 {"placeholder", [](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11464 if (auto realValue = std::get_if<std::u16string>(&(value->GetValue()))) {
11465 prop->UpdatePlaceholder(*realValue);
11466 }
11467 }
11468 },
11469
11470 {"text", [wp = WeakClaim(this)](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11471 if (auto realValue = std::get_if<std::u16string>(&(value->GetValue()))) {
11472 auto pattern = wp.Upgrade();
11473 CHECK_NULL_VOID(pattern);
11474 auto oldValue = pattern->GetTextUtf16Value();
11475 if (*realValue != oldValue) {
11476 pattern->InitEditingValueText(*realValue);
11477 pattern->SetTextChangedAtCreation(true);
11478 }
11479 }
11480 }
11481 },
11482
11483 {"cancelButtonIconSize", [wp = WeakClaim(this)](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11484 if (auto realValue = std::get_if<CalcDimension>(&(value->GetValue()))) {
11485 auto pattern = wp.Upgrade();
11486 CHECK_NULL_VOID(pattern);
11487 realValue->SetUnit(DimensionUnit::VP);
11488 prop->UpdateIconSize(*realValue);
11489 pattern->ProcessResponseArea();
11490 }
11491 }
11492 },
11493
11494 {"cancelButtonIconColor", [wp = WeakClaim(this)](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11495 if (auto realValue = std::get_if<Color>(&(value->GetValue()))) {
11496 auto pattern = wp.Upgrade();
11497 CHECK_NULL_VOID(pattern);
11498 prop->UpdateIconColor(*realValue);
11499 pattern->ProcessResponseArea();
11500 }
11501 }
11502 },
11503
11504 {"placeholderColor", [wp = WeakClaim(RawPtr(frameNode))](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11505 if (auto realValue = std::get_if<Color>(&(value->GetValue()))) {
11506 prop->UpdatePlaceholderTextColor(*realValue);
11507 auto frameNode = wp.Upgrade();
11508 CHECK_NULL_VOID(frameNode);
11509 ACE_UPDATE_NODE_PAINT_PROPERTY(TextFieldPaintProperty, PlaceholderColorFlagByUser, true, frameNode);
11510 }
11511 }
11512 },
11513
11514 {"placeholderFontSize", [](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11515 if (auto realValue = std::get_if<CalcDimension>(&(value->GetValue()))) {
11516 prop->UpdatePlaceholderFontSize(*realValue);
11517 prop->UpdatePreferredPlaceholderLineHeightNeedToUpdate(true);
11518 }
11519 }
11520 },
11521
11522 {"placeholderFontFamily", [](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11523 if (auto realValue = std::get_if<std::vector<std::string>>(&(value->GetValue()))) {
11524 prop->UpdatePlaceholderFontFamily(*realValue);
11525 prop->UpdatePreferredPlaceholderLineHeightNeedToUpdate(true);
11526 }
11527 }
11528 },
11529
11530 {"backgroundColor", [wp = WeakClaim(RawPtr(frameNode))](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11531 if (auto realValue = std::get_if<Color>(&(value->GetValue()))) {
11532 auto frameNode = wp.Upgrade();
11533 CHECK_NULL_VOID(frameNode);
11534 ACE_UPDATE_NODE_PAINT_PROPERTY(TextFieldPaintProperty, BackgroundColor, *realValue, frameNode);
11535 ACE_UPDATE_NODE_RENDER_CONTEXT(BackgroundColor, *realValue, frameNode);
11536 }
11537 }
11538 },
11539
11540 {"foregroundColor", [wp = WeakClaim(RawPtr(frameNode))](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11541 if (auto realValue = std::get_if<Color>(&(value->GetValue()))) {
11542 prop->UpdateTextColor(*realValue);
11543 auto frameNode = wp.Upgrade();
11544 CHECK_NULL_VOID(frameNode);
11545 auto renderContext = frameNode->GetRenderContext();
11546 CHECK_NULL_VOID(renderContext);
11547 if (renderContext->GetForegroundColorStrategy().has_value()) {
11548 renderContext->UpdateForegroundColorStrategy(ForegroundColorStrategy::NONE);
11549 renderContext->ResetForegroundColorStrategy();
11550 }
11551 renderContext->UpdateForegroundColor(*realValue);
11552 renderContext->UpdateForegroundColorFlag(true);
11553 }
11554 }
11555 },
11556
11557 {"caretColor", [wp = WeakClaim(RawPtr(frameNode))](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11558 if (auto realValue = std::get_if<Color>(&(value->GetValue()))) {
11559 auto frameNode = wp.Upgrade();
11560 CHECK_NULL_VOID(frameNode);
11561 ACE_UPDATE_NODE_PAINT_PROPERTY(TextFieldPaintProperty, CursorColor, *realValue, frameNode);
11562 ACE_UPDATE_NODE_PAINT_PROPERTY(TextFieldPaintProperty, CaretColorFlagByUser, true, frameNode);
11563 }
11564 }
11565 },
11566
11567 {"selectedBackgroundColor", [wp = WeakClaim(RawPtr(frameNode))](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11568 if (auto realValue = std::get_if<Color>(&(value->GetValue()))) {
11569 if (realValue->GetAlpha() == 255) {
11570 *realValue = realValue->ChangeOpacity(0.2);
11571 }
11572 auto frameNode = wp.Upgrade();
11573 CHECK_NULL_VOID(frameNode);
11574 ACE_UPDATE_NODE_PAINT_PROPERTY(TextFieldPaintProperty, SelectedBackgroundColor, *realValue, frameNode);
11575 }
11576 }
11577 },
11578
11579 {"caretWidth", [wp = WeakClaim(this)](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11580 if (auto realValue = std::get_if<CalcDimension>(&(value->GetValue()))) {
11581 auto pattern = wp.Upgrade();
11582 CHECK_NULL_VOID(pattern);
11583 auto frameNode = pattern->GetHost();
11584 CHECK_NULL_VOID(frameNode);
11585 realValue->SetUnit(DimensionUnit::VP);
11586 ACE_UPDATE_NODE_PAINT_PROPERTY(TextFieldPaintProperty, CursorWidth, *realValue, frameNode);
11587 pattern->CalculateDefaultCursor();
11588 }
11589 }
11590 },
11591
11592 {"letterSpacing", [wp = WeakClaim(RawPtr(frameNode))](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11593 if (auto realValue = std::get_if<CalcDimension>(&(value->GetValue()))) {
11594 auto frameNode = wp.Upgrade();
11595 CHECK_NULL_VOID(frameNode);
11596 realValue->SetUnit(DimensionUnit::VP);
11597 prop->UpdateLetterSpacing(*realValue);
11598 }
11599 }
11600 },
11601
11602 {"width", [](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11603 if (auto realValue = std::get_if<CalcDimension>(&(value->GetValue()))) {
11604 realValue->SetUnit(DimensionUnit::VP);
11605 if (LessNotEqual(realValue->Value(), 0.0)) {
11606 return;
11607 }
11608 CalcLength width(*realValue);
11609 std::optional<CalcLength> height = std::nullopt;
11610 auto&& layoutConstraint = prop->GetCalcLayoutConstraint();
11611 if (layoutConstraint && layoutConstraint->selfIdealSize) {
11612 height = layoutConstraint->selfIdealSize->Height();
11613 }
11614 prop->UpdateUserDefinedIdealSize(CalcSize(width, height));
11615 }
11616 }
11617 },
11618
11619 {"paddingTop", [wp = WeakClaim(RawPtr(frameNode))](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11620 if (auto realValue = std::get_if<CalcDimension>(&(value->GetValue()))) {
11621 auto frameNode = wp.Upgrade();
11622 CHECK_NULL_VOID(frameNode);
11623 auto paintProperty = frameNode->GetPaintProperty<TextFieldPaintProperty>();
11624 CHECK_NULL_VOID(paintProperty);
11625 PaddingProperty padding;
11626 padding = paintProperty->GetPaddingByUserValue(padding);
11627 realValue->SetUnit(DimensionUnit::VP);
11628 padding.top = CalcLength(*realValue);
11629 paintProperty->UpdatePaddingByUser(padding);
11630 }
11631 }
11632 },
11633
11634 {"paddingBottom", [wp = WeakClaim(RawPtr(frameNode))](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11635 if (auto realValue = std::get_if<CalcDimension>(&(value->GetValue()))) {
11636 auto frameNode = wp.Upgrade();
11637 CHECK_NULL_VOID(frameNode);
11638 auto paintProperty = frameNode->GetPaintProperty<TextFieldPaintProperty>();
11639 CHECK_NULL_VOID(paintProperty);
11640 PaddingProperty padding;
11641 padding = paintProperty->GetPaddingByUserValue(padding);
11642 realValue->SetUnit(DimensionUnit::VP);
11643 padding.bottom = CalcLength(*realValue);
11644 paintProperty->UpdatePaddingByUser(padding);
11645 }
11646 }
11647 },
11648
11649 {"paddingLeft", [wp = WeakClaim(RawPtr(frameNode))](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11650 if (auto realValue = std::get_if<CalcDimension>(&(value->GetValue()))) {
11651 auto frameNode = wp.Upgrade();
11652 CHECK_NULL_VOID(frameNode);
11653 auto paintProperty = frameNode->GetPaintProperty<TextFieldPaintProperty>();
11654 CHECK_NULL_VOID(paintProperty);
11655 PaddingProperty padding;
11656 padding = paintProperty->GetPaddingByUserValue(padding);
11657 realValue->SetUnit(DimensionUnit::VP);
11658 padding.left = CalcLength(*realValue);
11659 paintProperty->UpdatePaddingByUser(padding);
11660 }
11661 }
11662 },
11663
11664 {"paddingRight", [wp = WeakClaim(RawPtr(frameNode))](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11665 if (auto realValue = std::get_if<CalcDimension>(&(value->GetValue()))) {
11666 auto frameNode = wp.Upgrade();
11667 CHECK_NULL_VOID(frameNode);
11668 auto paintProperty = frameNode->GetPaintProperty<TextFieldPaintProperty>();
11669 CHECK_NULL_VOID(paintProperty);
11670 PaddingProperty padding;
11671 padding = paintProperty->GetPaddingByUserValue(padding);
11672 realValue->SetUnit(DimensionUnit::VP);
11673 padding.right = CalcLength(*realValue);
11674 paintProperty->UpdatePaddingByUser(padding);
11675 }
11676 }
11677 },
11678
11679 {"marginTop", [wp = WeakClaim(RawPtr(frameNode))](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11680 if (auto realValue = std::get_if<CalcDimension>(&(value->GetValue()))) {
11681 auto frameNode = wp.Upgrade();
11682 CHECK_NULL_VOID(frameNode);
11683 auto paintProperty = frameNode->GetPaintProperty<TextFieldPaintProperty>();
11684 CHECK_NULL_VOID(paintProperty);
11685 PaddingProperty margin;
11686 margin = paintProperty->GetMarginByUserValue(margin);
11687 realValue->SetUnit(DimensionUnit::VP);
11688 margin.top = CalcLength(*realValue);
11689 paintProperty->UpdatePaddingByUser(margin);
11690 }
11691 }
11692 },
11693
11694 {"marginBottom", [wp = WeakClaim(RawPtr(frameNode))](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11695 if (auto realValue = std::get_if<CalcDimension>(&(value->GetValue()))) {
11696 auto frameNode = wp.Upgrade();
11697 CHECK_NULL_VOID(frameNode);
11698 auto paintProperty = frameNode->GetPaintProperty<TextFieldPaintProperty>();
11699 CHECK_NULL_VOID(paintProperty);
11700 PaddingProperty margin;
11701 margin = paintProperty->GetMarginByUserValue(margin);
11702 realValue->SetUnit(DimensionUnit::VP);
11703 margin.bottom = CalcLength(*realValue);
11704 paintProperty->UpdatePaddingByUser(margin);
11705 }
11706 }
11707 },
11708
11709 {"marginLeft", [wp = WeakClaim(RawPtr(frameNode))](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11710 if (auto realValue = std::get_if<CalcDimension>(&(value->GetValue()))) {
11711 auto frameNode = wp.Upgrade();
11712 CHECK_NULL_VOID(frameNode);
11713 auto paintProperty = frameNode->GetPaintProperty<TextFieldPaintProperty>();
11714 CHECK_NULL_VOID(paintProperty);
11715 PaddingProperty margin;
11716 margin = paintProperty->GetMarginByUserValue(margin);
11717 realValue->SetUnit(DimensionUnit::VP);
11718 margin.left = CalcLength(*realValue);
11719 paintProperty->UpdatePaddingByUser(margin);
11720 }
11721 }
11722 },
11723
11724 {"marginRight", [wp = WeakClaim(RawPtr(frameNode))](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11725 if (auto realValue = std::get_if<CalcDimension>(&(value->GetValue()))) {
11726 auto frameNode = wp.Upgrade();
11727 CHECK_NULL_VOID(frameNode);
11728 auto paintProperty = frameNode->GetPaintProperty<TextFieldPaintProperty>();
11729 CHECK_NULL_VOID(paintProperty);
11730 PaddingProperty margin;
11731 margin = paintProperty->GetMarginByUserValue(margin);
11732 realValue->SetUnit(DimensionUnit::VP);
11733 margin.right = CalcLength(*realValue);
11734 paintProperty->UpdatePaddingByUser(margin);
11735 }
11736 }
11737 },
11738
11739 {"fontWeight", [](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11740 if (auto realValue = std::get_if<std::string>(&(value->GetValue()))) {
11741 FontWeight fontWeight = ConvertStrToFontWeight(*realValue);
11742 prop->UpdateFontWeight(fontWeight);
11743 prop->UpdatePreferredTextLineHeightNeedToUpdate(true);
11744 }
11745 }
11746 },
11747
11748 {"fontColor", [wp = WeakClaim(RawPtr(frameNode))](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11749 if (auto realValue = std::get_if<Color>(&(value->GetValue()))) {
11750 prop->UpdateTextColor(*realValue);
11751 auto frameNode = wp.Upgrade();
11752 CHECK_NULL_VOID(frameNode);
11753 ACE_UPDATE_NODE_RENDER_CONTEXT(ForegroundColor, *realValue, frameNode);
11754 ACE_RESET_NODE_RENDER_CONTEXT(RenderContext, ForegroundColorStrategy, frameNode);
11755 ACE_UPDATE_NODE_RENDER_CONTEXT(ForegroundColorFlag, true, frameNode);
11756 ACE_UPDATE_NODE_PAINT_PROPERTY(TextFieldPaintProperty, TextColorFlagByUser, *realValue, frameNode);
11757 }
11758 }
11759 },
11760
11761 {"fontFamily", [](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11762 if (auto realValue = std::get_if<std::vector<std::string>>(&(value->GetValue()))) {
11763 prop->UpdateFontFamily(*realValue);
11764 prop->UpdatePreferredTextLineHeightNeedToUpdate(true);
11765 }
11766 }
11767 },
11768
11769 {"errorString", [](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11770 if (auto realValue = std::get_if<std::u16string>(&(value->GetValue()))) {
11771 prop->UpdateErrorText(*realValue);
11772 prop->UpdateShowErrorText(true);
11773 }
11774 }
11775 },
11776
11777 {"onIconSrc", [wp = WeakClaim(this)](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11778 if (auto realValue = std::get_if<std::string>(&(value->GetValue()))) {
11779 auto pattern = wp.Upgrade();
11780 CHECK_NULL_VOID(pattern);
11781 auto frameNode = pattern->GetHost();
11782 CHECK_NULL_VOID(frameNode);
11783 pattern->SetIsPasswordSymbol(false);
11784 ACE_UPDATE_NODE_LAYOUT_PROPERTY(TextFieldLayoutProperty, ShowPasswordSourceInfo,
11785 ImageSourceInfo(*realValue, "", ""), frameNode);
11786 }
11787 }
11788 },
11789
11790 {"offIconSrc", [wp = WeakClaim(this)](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11791 if (auto realValue = std::get_if<std::string>(&(value->GetValue()))) {
11792 auto pattern = wp.Upgrade();
11793 CHECK_NULL_VOID(pattern);
11794 auto frameNode = pattern->GetHost();
11795 CHECK_NULL_VOID(frameNode);
11796 pattern->SetIsPasswordSymbol(false);
11797 ACE_UPDATE_NODE_LAYOUT_PROPERTY(TextFieldLayoutProperty, HidePasswordSourceInfo,
11798 ImageSourceInfo(*realValue, "", ""), frameNode);
11799 }
11800 }
11801 },
11802
11803 {"inputFilter", [wp = WeakClaim(this)](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11804 if (auto realValue = std::get_if<std::string>(&(value->GetValue()))) {
11805 prop->UpdateInputFilter(*realValue);
11806 auto pattern = wp.Upgrade();
11807 CHECK_NULL_VOID(pattern);
11808 pattern->FilterInitializeText();
11809 }
11810 }
11811 },
11812
11813 {"underlineColorTyping", [wp = WeakClaim(this)](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11814 if (auto realValue = std::get_if<Color>(&(value->GetValue()))) {
11815 auto pattern = wp.Upgrade();
11816 CHECK_NULL_VOID(pattern);
11817 pattern->SetTypingUnderlineColor(*realValue);
11818 }
11819 }
11820 },
11821
11822 {"underlineColorNormal", [wp = WeakClaim(this)](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11823 if (auto realValue = std::get_if<Color>(&(value->GetValue()))) {
11824 auto pattern = wp.Upgrade();
11825 CHECK_NULL_VOID(pattern);
11826 pattern->SetNormalUnderlineColor(*realValue);
11827 }
11828 }
11829 },
11830
11831 {"underlineColorError", [wp = WeakClaim(this)](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11832 if (auto realValue = std::get_if<Color>(&(value->GetValue()))) {
11833 auto pattern = wp.Upgrade();
11834 CHECK_NULL_VOID(pattern);
11835 pattern->SetErrorUnderlineColor(*realValue);
11836 }
11837 }
11838 },
11839
11840 {"underlineColorDisable", [wp = WeakClaim(this)](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11841 if (auto realValue = std::get_if<Color>(&(value->GetValue()))) {
11842 auto pattern = wp.Upgrade();
11843 CHECK_NULL_VOID(pattern);
11844 pattern->SetDisableUnderlineColor(*realValue);
11845 }
11846 }
11847 },
11848
11849 {"textIndent", [](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11850 if (auto realValue = std::get_if<CalcDimension>(&(value->GetValue()))) {
11851 realValue->SetUnit(DimensionUnit::VP);
11852 prop->UpdateTextIndent(*realValue);
11853 }
11854 }
11855 },
11856
11857 {"cancelButtonIconColorDefault", [wp = WeakClaim(this)](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11858 auto pattern = wp.Upgrade();
11859 CHECK_NULL_VOID(pattern);
11860 auto host = pattern->GetHost();
11861 CHECK_NULL_VOID(host);
11862 Color iconColor;
11863 auto context = host->GetContext();
11864 CHECK_NULL_VOID(context);
11865 auto colorMode = context->GetColorMode();
11866 if (colorMode == ColorMode::DARK) {
11867 auto theme = pattern->GetTheme();
11868 iconColor = theme->GetCancelButtonIconColor();
11869 }
11870 prop->UpdateIconColor(iconColor);
11871 }
11872 },
11873
11874 {"minFontScale", [](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11875 if (auto realValue = std::get_if<float>(&(value->GetValue()))) {
11876 float minFontScale = *realValue;
11877 minFontScale = LessOrEqual(minFontScale, 0.0f) ? 0.0f : minFontScale;
11878 minFontScale = GreatOrEqual(minFontScale, 1.0f) ? 1.0f : minFontScale;
11879 prop->UpdateMinFontScale(minFontScale);
11880 }
11881 }
11882 },
11883
11884 {"maxFontScale", [](TextFieldLayoutProperty* prop, RefPtr<PropertyValueBase> value) {
11885 if (auto realValue = std::get_if<float>(&(value->GetValue()))) {
11886 float maxFontScale = *realValue;
11887 maxFontScale = LessOrEqual(maxFontScale, 1.0f) ? 1.0f : maxFontScale;
11888 prop->UpdateMaxFontScale(maxFontScale);
11889 }
11890 }
11891 },
11892 };
11893
11894 auto it = handlers.find(key);
11895 if (it != handlers.end()) {
11896 it->second(layoutProperty, value);
11897 }
11898
11899 if (frameNode->GetRerenderable()) {
11900 frameNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
11901 }
11902 }
11903
11904 void TextFieldPattern::SetBackBorderRadius()
11905 {
11906 auto frameNode = GetHost();
11907 CHECK_NULL_VOID(frameNode);
11908 auto renderContext = frameNode->GetRenderContext();
11909 CHECK_NULL_VOID(renderContext);
11910 auto layoutProperty = frameNode->GetLayoutProperty<TextFieldLayoutProperty>();
11911 CHECK_NULL_VOID(layoutProperty);
11912
11913 bool isRTL = layoutProperty->GetNonAutoLayoutDirection() == TextDirection::RTL;
11914 auto borderRadiusProperty = renderContext->GetBorderRadius();
11915 CHECK_NULL_VOID(borderRadiusProperty);
11916 auto radius = borderRadiusProperty.value();
11917
11918 radius.radiusTopLeft = radius.radiusTopLeft.has_value() ? radius.radiusTopLeft :
11919 (isRTL ? radius.radiusTopEnd : radius.radiusTopStart);
11920 radius.radiusTopRight = radius.radiusTopRight.has_value() ? radius.radiusTopRight :
11921 (isRTL ? radius.radiusTopStart : radius.radiusTopEnd);
11922 radius.radiusBottomLeft = radius.radiusBottomLeft.has_value() ? radius.radiusBottomLeft :
11923 (isRTL ? radius.radiusBottomEnd : radius.radiusBottomStart);
11924 radius.radiusBottomRight = radius.radiusBottomRight.has_value() ? radius.radiusBottomRight :
11925 (isRTL ? radius.radiusBottomStart : radius.radiusBottomEnd);
11926
11927 ACE_UPDATE_NODE_PAINT_PROPERTY(TextFieldPaintProperty, BorderRadiusFlagByUser, radius, frameNode);
11928 }
11929
11930 void TextFieldPattern::UpdateBorderResource()
11931 {
11932 auto frameNode = GetHost();
11933 auto renderContext = frameNode->GetRenderContext();
11934 CHECK_NULL_VOID(renderContext);
11935 if (renderContext->HasBorderRadius()) {
11936 SetBackBorderRadius();
11937 }
11938 if (renderContext->HasBorderColor()) {
11939 ACE_UPDATE_NODE_PAINT_PROPERTY(
11940 TextFieldPaintProperty, BorderColorFlagByUser, renderContext->GetBorderColor().value(), frameNode);
11941 }
11942 if (renderContext->HasBorderWidth()) {
11943 ACE_UPDATE_NODE_PAINT_PROPERTY(
11944 TextFieldPaintProperty, BorderWidthFlagByUser, renderContext->GetBorderWidth().value(), frameNode);
11945 }
11946 if (renderContext->HasBorderStyle()) {
11947 ACE_UPDATE_NODE_PAINT_PROPERTY(
11948 TextFieldPaintProperty, BorderStyleFlagByUser, renderContext->GetBorderStyle().value(), frameNode);
11949 }
11950 }
11951
11952 void TextFieldPattern::UpdateMarginResource()
11953 {
11954 auto frameNode = GetHost();
11955 CHECK_NULL_VOID(frameNode);
11956 auto layoutProperty = frameNode->GetLayoutProperty<TextFieldLayoutProperty>();
11957 CHECK_NULL_VOID(layoutProperty);
11958 const auto& margin = layoutProperty->GetMarginProperty();
11959 CHECK_NULL_VOID(margin);
11960 bool isRTL = layoutProperty->GetNonAutoLayoutDirection() == TextDirection::RTL;
11961
11962 MarginProperty userMargin;
11963 userMargin.top = margin->top;
11964 userMargin.bottom = margin->bottom;
11965 userMargin.left = margin->left.has_value() ? margin->left :
11966 (isRTL ? margin->end : margin->start);
11967 userMargin.right = margin->right.has_value() ? margin->right :
11968 (isRTL ? margin->start : margin->end);
11969 ACE_UPDATE_PAINT_PROPERTY(TextFieldPaintProperty, MarginByUser, userMargin);
11970 }
11971
11972 Offset TextFieldPattern::GetCaretClickLocalOffset(const Offset& offset)
11973 {
11974 if (!IsTextArea()) {
11975 return offset;
11976 }
11977 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
11978 CHECK_NULL_RETURN(layoutProperty, offset);
11979 auto isRTL = layoutProperty->GetNonAutoLayoutDirection() == TextDirection::RTL;
11980 auto localOffset = offset;
11981 if (GreatNotEqual(localOffset.GetY(), textRect_.Bottom())) {
11982 localOffset.SetX(isRTL ? contentRect_.Left() : contentRect_.Right());
11983 localOffset.SetY(textRect_.Bottom() - PreferredLineHeight() / 2.0f);
11984 } else if (GreatNotEqual(localOffset.GetY(), contentRect_.Bottom())) {
11985 localOffset.SetX(isRTL ? contentRect_.Left() : contentRect_.Right());
11986 localOffset.SetY(contentRect_.Bottom() - PreferredLineHeight() / 2.0f);
11987 }
11988 return localOffset;
11989 }
11990
11991 bool TextFieldPattern::ShouldSkipUpdateParagraph()
11992 {
11993 if (IsDragging() || !dragNode_ || !IsNormalInlineState()) {
11994 return false;
11995 }
11996 auto dragNodePattern = AceType::DynamicCast<TextDragPattern>(dragNode_->GetPattern());
11997 CHECK_NULL_RETURN(dragNodePattern, false);
11998 if (!dragNodePattern->IsAnimating()) {
11999 return false;
12000 }
12001 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "Destroy the paragraph after the drag floating animation ends.");
12002 dragNodePattern->UpdateAnimatingParagraph();
12003 return true;
12004 }
12005
12006 void TextFieldPattern::UpdateParagraphForDragNode(bool skipUpdate)
12007 {
12008 if (IsDragging() || !dragNode_ || skipUpdate) {
12009 return;
12010 }
12011 auto dragNodePattern = AceType::DynamicCast<TextDragPattern>(dragNode_->GetPattern());
12012 CHECK_NULL_VOID(dragNodePattern);
12013 dragNodePattern->UpdateParagraph(paragraph_);
12014 }
12015 } // namespace OHOS::Ace::NG
12016