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 #include "core/components_ng/pattern/text_field/text_field_pattern.h"
17
18 #include <algorithm>
19 #include <atomic>
20 #include <cstdint>
21 #include <optional>
22 #include <ratio>
23 #include <regex>
24 #include <string>
25 #include <utility>
26 #include "base/geometry/dimension.h"
27 #include "base/log/event_report.h"
28 #include "base/memory/type_info_base.h"
29 #include "base/utils/utf_helper.h"
30 #include "core/common/ime/constant.h"
31 #include "core/components/common/properties/text_style.h"
32 #include "core/components_ng/pattern/select/select_pattern.h"
33 #include "core/components_ng/pattern/text/text_layout_property.h"
34 #include "core/components_ng/pattern/text_field/text_component_decorator.h"
35 #include "core/components_ng/pattern/text_field/text_field_layout_property.h"
36 #include "core/components_ng/property/layout_constraint.h"
37 #include "interfaces/inner_api/ui_session/ui_session_manager.h"
38
39 #include "base/i18n/localization.h"
40 #include "base/log/dump_log.h"
41 #include "base/log/log_wrapper.h"
42 #include "base/memory/referenced.h"
43 #include "base/utils/string_utils.h"
44 #include "base/utils/utils.h"
45 #include "core/common/clipboard/clipboard_proxy.h"
46 #include "core/common/container_scope.h"
47 #include "core/common/font_manager.h"
48 #include "core/common/ime/input_method_manager.h"
49 #include "core/common/ime/text_edit_controller.h"
50 #include "core/common/ime/text_input_client.h"
51 #include "core/common/ime/text_input_connection.h"
52 #include "core/common/ime/text_input_formatter.h"
53 #include "core/common/ime/text_input_type.h"
54 #include "core/common/ime/text_selection.h"
55 #include "core/common/recorder/event_recorder.h"
56 #include "core/common/recorder/node_data_cache.h"
57 #include "core/common/stylus/stylus_detector_mgr.h"
58 #include "core/common/vibrator/vibrator_utils.h"
59 #include "core/components/common/layout/constants.h"
60 #include "core/components/text_field/textfield_theme.h"
61 #include "core/components_ng/base/inspector_filter.h"
62 #include "core/components_ng/event/focus_hub.h"
63 #include "core/components_ng/pattern/stage/page_pattern.h"
64 #include "core/components_ng/pattern/text/span/span_string.h"
65 #include "core/components_ng/pattern/text/text_pattern.h"
66 #include "core/components_ng/pattern/text_field/text_field_manager.h"
67 #include "core/components_ng/pattern/text_field/text_field_paint_property.h"
68 #include "core/text/text_emoji_processor.h"
69 #ifndef ACE_UNITTEST
70 #ifdef ENABLE_STANDARD_INPUT
71 #include "parameters.h"
72
73 #include "core/components_ng/pattern/text_field/on_text_changed_listener_impl.h"
74 #endif
75 #endif
76 #include "core/common/udmf/udmf_client.h"
77
78 #ifdef WINDOW_SCENE_SUPPORTED
79 #include "core/components_ng/pattern/window_scene/helper/window_scene_helper.h"
80 #endif
81 namespace OHOS::Ace::NG {
82 namespace {
83
84 const BorderRadiusProperty ZERO_BORDER_RADIUS_PROPERTY(0.0_vp);
85 // need to be moved to TextFieldTheme
86 constexpr Dimension BORDER_DEFAULT_WIDTH = 0.0_vp;
87 constexpr Dimension TYPING_UNDERLINE_WIDTH = 2.0_px;
88 constexpr Dimension OVER_COUNT_BORDER_WIDTH = 1.0_vp;
89 constexpr Dimension INLINE_BORDER_WIDTH = 2.0_vp;
90 constexpr Dimension ERROR_UNDERLINE_WIDTH = 2.0_px;
91 constexpr Dimension UNDERLINE_WIDTH = 1.0_px;
92 constexpr uint32_t INLINE_DEFAULT_VIEW_MAXLINE = 3;
93 constexpr Dimension SCROLL_BAR_MIN_HEIGHT = 4.0_vp;
94 constexpr float MINFONTSCALE = 0.85f;
95 constexpr float MAXFONTSCALE = 3.20f;
96 #if defined(ENABLE_STANDARD_INPUT)
97 constexpr Dimension AVOID_OFFSET = 24.0_vp;
98 #endif
99 constexpr Dimension DEFAULT_FONT = Dimension(16, DimensionUnit::FP);
100 constexpr int32_t ILLEGAL_VALUE = 0;
101 constexpr double VELOCITY = -1000;
102 constexpr double MASS = 1.0;
103 constexpr double STIFFNESS = 428.0;
104 constexpr double DAMPING = 10.0;
105 constexpr uint32_t TWINKLING_INTERVAL_MS = 500;
106 constexpr uint32_t RECORD_MAX_LENGTH = 20;
107 constexpr uint32_t OBSCURE_SHOW_TICKS = 1;
108 constexpr int32_t FIND_TEXT_ZERO_INDEX = 1;
109 constexpr char16_t OBSCURING_CHARACTER = u'•';
110 constexpr char16_t OBSCURING_CHARACTER_FOR_AR = u'*';
111 const std::string NEWLINE = "\n";
112 const std::wstring WIDE_NEWLINE = StringUtils::ToWstring(NEWLINE);
113 const std::string INSPECTOR_PREFIX = "__SearchField__";
114 const std::string ERRORNODE_PREFIX = "ErrorNodeField__";
115 const OffsetF DEFAULT_NEGATIVE_CARET_OFFSET {-1.0f, -1.0f};
116 constexpr Dimension FLOATING_CARET_SHOW_ORIGIN_CARET_DISTANCE = 10.0_vp;
117 #if defined(ENABLE_STANDARD_INPUT)
118 constexpr int32_t AUTO_FILL_CANCEL = 2;
119 #endif
120
121 // need to be moved to formatter
122 const std::string DIGIT_WHITE_LIST = "[0-9]";
123 const std::string PHONE_WHITE_LIST = "[\\d\\-\\+\\*\\#]+";
124 const std::string EMAIL_WHITE_LIST = "[\\w.\\@]";
125 const std::string URL_WHITE_LIST = "[a-zA-z]+://[^\\s]*";
126 const std::string SHOW_PASSWORD_SVG = "SYS_SHOW_PASSWORD_SVG";
127 const std::string HIDE_PASSWORD_SVG = "SYS_HIDE_PASSWORD_SVG";
128 const std::string AUTO_FILL_PARAMS_USERNAME = "com.autofill.params.userName";
129 const std::string AUTO_FILL_PARAMS_NEWPASSWORD = "com.autofill.params.newPassword";
130 constexpr int32_t MAX_FILL_CONTENT_SIZE = 5;
131 constexpr int32_t DEFAULT_MODE = -1;
132 constexpr int32_t PREVIEW_TEXT_RANGE_DEFAULT = -1;
133 const std::string PREVIEW_STYLE_NORMAL = "normal";
134 const std::string PREVIEW_STYLE_UNDERLINE = "underline";
135
136 constexpr int32_t PREVIEW_NO_ERROR = 0;
137 constexpr int32_t PREVIEW_NULL_POINTER = 1;
138 constexpr int32_t PREVIEW_BAD_PARAMETERS = -1;
139 constexpr double MINIMAL_OFFSET = 0.01f;
140 constexpr int32_t KEYBOARD_DEFAULT_API = 9;
141 constexpr float RICH_DEFAULT_SHADOW_COLOR = 0x33000000;
142 constexpr float RICH_DEFAULT_ELEVATION = 120.0f;
143 constexpr float TIME_UNIT = 1000.0f;
144 constexpr float MAX_DRAG_SCROLL_SPEED = 2400.0f;
145 constexpr Dimension AUTO_SCROLL_HOT_ZONE_HEIGHT = 58.0_vp;
146 constexpr Dimension AUTO_SCROLL_HOT_ZONE_WIDTH = 26.0_vp;
147 constexpr float AUTO_SCROLL_HOT_AREA_LONGPRESS_DURATION = 80.0f;
148 constexpr Dimension AUTO_SCROLL_HOT_AREA_LONGPRESS_DISTANCE = 5.0_vp;
149 constexpr Dimension MOUSE_SCROLL_BAR_REGION_WIDTH = 8.0_vp;
150 constexpr int32_t HOVER_ANIMATION_DURATION = 250;
151 const RefPtr<Curve> MOVE_MAGNIFIER_CURVE =
152 AceType::MakeRefPtr<InterpolatingSpring>(0.0f, 1.0f, 228.0f, 30.0f);
153 constexpr int32_t LAND_DURATION = 100;
154
155 static std::unordered_map<AceAutoFillType, TextInputType> keyBoardMap_ = {
156 { AceAutoFillType::ACE_PASSWORD, TextInputType::VISIBLE_PASSWORD},
157 { AceAutoFillType::ACE_USER_NAME, TextInputType::USER_NAME },
158 { AceAutoFillType::ACE_NEW_PASSWORD, TextInputType::NEW_PASSWORD },
159 { AceAutoFillType::ACE_FULL_STREET_ADDRESS, TextInputType::TEXT },
160 { AceAutoFillType::ACE_HOUSE_NUMBER, TextInputType::TEXT },
161 { AceAutoFillType::ACE_DISTRICT_ADDRESS, TextInputType::TEXT },
162 { AceAutoFillType::ACE_CITY_ADDRESS, TextInputType::TEXT },
163 { AceAutoFillType::ACE_PROVINCE_ADDRESS, TextInputType::TEXT },
164 { AceAutoFillType::ACE_COUNTRY_ADDRESS, TextInputType::TEXT },
165 { AceAutoFillType::ACE_PERSON_FULL_NAME, TextInputType::TEXT },
166 { AceAutoFillType::ACE_PERSON_LAST_NAME, TextInputType::TEXT },
167 { AceAutoFillType::ACE_PERSON_FIRST_NAME, TextInputType::TEXT },
168 { AceAutoFillType::ACE_PHONE_NUMBER, TextInputType::PHONE },
169 { AceAutoFillType::ACE_PHONE_COUNTRY_CODE, TextInputType::PHONE },
170 { AceAutoFillType::ACE_FULL_PHONE_NUMBER, TextInputType::PHONE },
171 { AceAutoFillType::ACE_EMAIL_ADDRESS, TextInputType::EMAIL_ADDRESS },
172 { AceAutoFillType::ACE_BANK_CARD_NUMBER, TextInputType::NUMBER },
173 { AceAutoFillType::ACE_ID_CARD_NUMBER, TextInputType::NUMBER },
174 { AceAutoFillType::ACE_PRECISE_TIME, TextInputType::NUMBER },
175 { AceAutoFillType::ACE_HOUR_AND_MINUTE, TextInputType::NUMBER },
176 { AceAutoFillType::ACE_DATE, TextInputType::NUMBER },
177 { AceAutoFillType::ACE_MONTH, TextInputType::NUMBER },
178 { AceAutoFillType::ACE_YEAR, TextInputType::NUMBER },
179 { AceAutoFillType::ACE_NICKNAME, TextInputType::TEXT },
180 { AceAutoFillType::ACE_DETAIL_INFO_WITHOUT_STREET, TextInputType::TEXT },
181 { AceAutoFillType::ACE_FORMAT_ADDRESS, TextInputType::TEXT },
182 { AceAutoFillType::ACE_PASSPORT_NUMBER, TextInputType::TEXT },
183 { AceAutoFillType::ACE_VALIDITY, TextInputType::TEXT },
184 { AceAutoFillType::ACE_ISSUE_AT, TextInputType::TEXT },
185 { AceAutoFillType::ACE_ORGANIZATION, TextInputType::TEXT },
186 { AceAutoFillType::ACE_TAX_ID, TextInputType::TEXT },
187 { AceAutoFillType::ACE_ADDRESS_CITY_AND_STATE, TextInputType::TEXT },
188 { AceAutoFillType::ACE_FLIGHT_NUMBER, TextInputType::TEXT },
189 { AceAutoFillType::ACE_LICENSE_NUMBER, TextInputType::TEXT },
190 { AceAutoFillType::ACE_LICENSE_FILE_NUMBER, TextInputType::TEXT },
191 { AceAutoFillType::ACE_LICENSE_PLATE, TextInputType::TEXT },
192 { AceAutoFillType::ACE_ENGINE_NUMBER, TextInputType::TEXT },
193 { AceAutoFillType::ACE_LICENSE_CHASSIS_NUMBER, TextInputType::TEXT }};
194
195 static std::unordered_map<TextContentType, std::pair<AceAutoFillType, std::string>> contentTypeMap_ = {
196 {TextContentType::VISIBLE_PASSWORD,
197 std::make_pair(AceAutoFillType::ACE_PASSWORD, "TextContentType.VISIBLE_PASSWORD")},
198 {TextContentType::USER_NAME, std::make_pair(AceAutoFillType::ACE_USER_NAME, "TextContentType.USER_NAME")},
199 {TextContentType::NEW_PASSWORD, std::make_pair(AceAutoFillType::ACE_NEW_PASSWORD, "TextContentType.NEW_PASSWORD")},
200 {TextContentType::FULL_STREET_ADDRESS,
201 std::make_pair(AceAutoFillType::ACE_FULL_STREET_ADDRESS, "TextContentType.FULL_STREET_ADDRESS")},
202 {TextContentType::HOUSE_NUMBER, std::make_pair(AceAutoFillType::ACE_HOUSE_NUMBER, "TextContentType.HOUSE_NUMBER")},
203 {TextContentType::DISTRICT_ADDRESS,
204 std::make_pair(AceAutoFillType::ACE_DISTRICT_ADDRESS, "TextContentType.DISTRICT_ADDRESS")},
205 {TextContentType::CITY_ADDRESS, std::make_pair(AceAutoFillType::ACE_CITY_ADDRESS, "TextContentType.CITY_ADDRESS")},
206 {TextContentType::PROVINCE_ADDRESS,
207 std::make_pair(AceAutoFillType::ACE_PROVINCE_ADDRESS, "TextContentType.PROVINCE_ADDRESS")},
208 {TextContentType::COUNTRY_ADDRESS,
209 std::make_pair(AceAutoFillType::ACE_COUNTRY_ADDRESS, "TextContentType.COUNTRY_ADDRESS")},
210 {TextContentType::PERSON_FULL_NAME,
211 std::make_pair(AceAutoFillType::ACE_PERSON_FULL_NAME, "TextContentType.PERSON_FULL_NAME")},
212 {TextContentType::PERSON_LAST_NAME,
213 std::make_pair(AceAutoFillType::ACE_PERSON_LAST_NAME, "TextContentType.PERSON_LAST_NAME")},
214 {TextContentType::PERSON_FIRST_NAME,
215 std::make_pair(AceAutoFillType::ACE_PERSON_FIRST_NAME, "TextContentType.PERSON_FIRST_NAME")},
216 {TextContentType::PHONE_NUMBER, std::make_pair(AceAutoFillType::ACE_PHONE_NUMBER, "TextContentType.PHONE_NUMBER")},
217 {TextContentType::PHONE_COUNTRY_CODE,
218 std::make_pair(AceAutoFillType::ACE_PHONE_COUNTRY_CODE, "TextContentType.PHONE_COUNTRY_CODE")},
219 {TextContentType::FULL_PHONE_NUMBER,
220 std::make_pair(AceAutoFillType::ACE_FULL_PHONE_NUMBER, "TextContentType.FULL_PHONE_NUMBER")},
221 {TextContentType::EMAIL_ADDRESS,
222 std::make_pair(AceAutoFillType::ACE_EMAIL_ADDRESS, "TextContentType.EMAIL_ADDRESS")},
223 {TextContentType::BANK_CARD_NUMBER,
224 std::make_pair(AceAutoFillType::ACE_BANK_CARD_NUMBER, "TextContentType.BANK_CARD_NUMBER")},
225 {TextContentType::ID_CARD_NUMBER,
226 std::make_pair(AceAutoFillType::ACE_ID_CARD_NUMBER, "TextContentType.ID_CARD_NUMBER")},
227 {TextContentType::PRECISE_TIME, std::make_pair(AceAutoFillType::ACE_PRECISE_TIME, "TextContentType.PRECISE_TIME")},
228 {TextContentType::HOUR_AND_MINUTE,
229 std::make_pair(AceAutoFillType::ACE_HOUR_AND_MINUTE, "TextContentType.HOUR_AND_MINUTE")},
230 {TextContentType::DATE, std::make_pair(AceAutoFillType::ACE_DATE, "TextContentType.DATE")},
231 {TextContentType::MONTH, std::make_pair(AceAutoFillType::ACE_MONTH, "TextContentType.MONTH")},
232 {TextContentType::YEAR, std::make_pair(AceAutoFillType::ACE_YEAR, "TextContentType.YEAR")},
233 {TextContentType::NICKNAME, std::make_pair(AceAutoFillType::ACE_NICKNAME, "TextContentType.NICKNAME")},
234 {TextContentType::DETAIL_INFO_WITHOUT_STREET,
235 std::make_pair(AceAutoFillType::ACE_DETAIL_INFO_WITHOUT_STREET, "TextContentType.DETAIL_INFO_WITHOUT_STREET")},
236 {TextContentType::FORMAT_ADDRESS,
237 std::make_pair(AceAutoFillType::ACE_FORMAT_ADDRESS, "TextContentType.FORMAT_ADDRESS")},
238 {TextContentType::PASSPORT_NUMBER,
239 std::make_pair(AceAutoFillType::ACE_PASSPORT_NUMBER, "TextContentType.PASSPORT_NUMBER")},
240 {TextContentType::VALIDITY,
241 std::make_pair(AceAutoFillType::ACE_VALIDITY, "TextContentType.VALIDITY")},
242 {TextContentType::ISSUE_AT,
243 std::make_pair(AceAutoFillType::ACE_ISSUE_AT, "TextContentType.ISSUE_AT")},
244 {TextContentType::ORGANIZATION,
245 std::make_pair(AceAutoFillType::ACE_ORGANIZATION, "TextContentType.ORGANIZATION")},
246 {TextContentType::TAX_ID,
247 std::make_pair(AceAutoFillType::ACE_TAX_ID, "TextContentType.TAX_ID")},
248 {TextContentType::ADDRESS_CITY_AND_STATE,
249 std::make_pair(AceAutoFillType::ACE_ADDRESS_CITY_AND_STATE, "TextContentType.ADDRESS_CITY_AND_STATE")},
250 {TextContentType::FLIGHT_NUMBER,
251 std::make_pair(AceAutoFillType::ACE_FLIGHT_NUMBER, "TextContentType.FLIGHT_NUMBER")},
252 {TextContentType::LICENSE_NUMBER,
253 std::make_pair(AceAutoFillType::ACE_LICENSE_NUMBER, "TextContentType.LICENSE_NUMBER")},
254 {TextContentType::LICENSE_FILE_NUMBER,
255 std::make_pair(AceAutoFillType::ACE_LICENSE_FILE_NUMBER, "TextContentType.LICENSE_FILE_NUMBER")},
256 {TextContentType::LICENSE_PLATE,
257 std::make_pair(AceAutoFillType::ACE_LICENSE_PLATE, "TextContentType.LICENSE_PLATE")},
258 {TextContentType::ENGINE_NUMBER,
259 std::make_pair(AceAutoFillType::ACE_ENGINE_NUMBER, "TextContentType.ENGINE_NUMBER")},
260 {TextContentType::LICENSE_CHASSIS_NUMBER,
261 std::make_pair(AceAutoFillType::ACE_LICENSE_CHASSIS_NUMBER, "TextContentType.LICENSE_CHASSIS_NUMBER")},
262 {TextContentType::UNSPECIFIED, std::make_pair(AceAutoFillType::ACE_UNSPECIFIED, "TextContentType.UNSPECIFIED")}};
263
SwapIfLarger(int32_t & a,int32_t & b)264 void SwapIfLarger(int32_t& a, int32_t& b)
265 {
266 if (a > b) {
267 std::swap(a, b);
268 }
269 }
270
ConvertFontFamily(const std::vector<std::string> & fontFamily)271 std::string ConvertFontFamily(const std::vector<std::string>& fontFamily)
272 {
273 std::string result;
274 for (const auto& item : fontFamily) {
275 result += item;
276 result += ",";
277 }
278 result = result.substr(0, static_cast<int32_t>(result.length()) - 1);
279 return result;
280 }
281
282 } // namespace
283
OnAttachContext(PipelineContext * context)284 void TextFieldPattern::OnAttachContext(PipelineContext* context)
285 {
286 CHECK_NULL_VOID(context);
287 SetInstanceId(context->GetInstanceId());
288 }
289
OnDetachContext(PipelineContext * context)290 void TextFieldPattern::OnDetachContext(PipelineContext* context)
291 {
292 SetInstanceId(INSTANCE_ID_UNDEFINED);
293 }
294
CreateNodePaintMethod()295 RefPtr<NodePaintMethod> TextFieldPattern::CreateNodePaintMethod()
296 {
297 if (!textFieldContentModifier_) {
298 textFieldContentModifier_ = AceType::MakeRefPtr<TextFieldContentModifier>(WeakClaim(this));
299 }
300 auto textFieldOverlayModifier = AceType::DynamicCast<TextFieldOverlayModifier>(GetScrollBarOverlayModifier());
301 if (!textFieldOverlayModifier) {
302 textFieldOverlayModifier_ =
303 AceType::MakeRefPtr<TextFieldOverlayModifier>(WeakClaim(this), GetScrollEdgeEffect());
304 SetScrollBarOverlayModifier(textFieldOverlayModifier_);
305 }
306 if (!textFieldForegroundModifier_) {
307 textFieldForegroundModifier_ = AceType::MakeRefPtr<TextFieldForegroundModifier>(WeakClaim(this));
308 }
309 if (isCustomFont_) {
310 textFieldContentModifier_->SetIsCustomFont(true);
311 }
312 auto paint = AceType::MakeRefPtr<TextFieldPaintMethod>(
313 WeakClaim(this), textFieldOverlayModifier_, textFieldContentModifier_, textFieldForegroundModifier_);
314 auto scrollBar = GetScrollBar();
315 if (scrollBar) {
316 paint->SetScrollBar(scrollBar);
317 if (scrollBar->NeedPaint()) {
318 textFieldOverlayModifier_->SetRect(scrollBar->GetActiveRect());
319 } else if (!HasFocus()) {
320 auto scrollRect = scrollBar->GetActiveRect();
321 CalcScrollRect(scrollRect);
322 textFieldOverlayModifier_->SetRect(scrollRect);
323 textFieldOverlayModifier_->SetOpacity(0);
324 }
325 }
326 CalculateBoundsRect();
327 return paint;
328 }
329
CalculateBoundsRect()330 void TextFieldPattern::CalculateBoundsRect()
331 {
332 auto host = GetHost();
333 CHECK_NULL_VOID(host);
334 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
335 CHECK_NULL_VOID(layoutProperty);
336
337 auto geometryNode = host->GetGeometryNode();
338 auto frameOffset = geometryNode->GetFrameOffset();
339 auto frameSize = geometryNode->GetFrameSize();
340 bool isShowCount = IsShowCount() && !IsTextArea();
341 bool isShowError = layoutProperty->GetShowErrorTextValue(false) && errorDecorator_;
342 if (isShowCount && isShowError) {
343 auto textWidth = std::max(errorDecorator_ ? errorDecorator_->GetContentWidth() : 0.0f, frameSize.Width());
344 auto errorHeight = errorDecorator_? errorDecorator_->GetBoundHeight() : 0.0f;
345 auto countHeight = counterDecorator_? counterDecorator_->GetBoundHeight() : 0.0f;
346 auto bottomHeight = std::max(errorHeight, countHeight);
347 RectF boundsRect(0.0f, 0.0f, textWidth, bottomHeight + frameSize.Height());
348 textFieldOverlayModifier_->SetBoundsRect(boundsRect);
349 textFieldForegroundModifier_->SetBoundsRect(boundsRect);
350 } else if (isShowCount) {
351 auto countHeight = counterDecorator_? counterDecorator_->GetBoundHeight() : 0.0f;
352 RectF boundsRect(0.0f, 0.0f, frameSize.Width(), countHeight + frameSize.Height());
353 textFieldOverlayModifier_->SetBoundsRect(boundsRect);
354 textFieldForegroundModifier_->SetBoundsRect(boundsRect);
355 } else if (isShowError) {
356 auto textWidth = std::max(errorDecorator_ ? errorDecorator_->GetContentWidth() : 0.0f, frameSize.Width());
357 auto errorHeight = errorDecorator_? errorDecorator_->GetBoundHeight() : 0.0f;
358 RectF boundsRect(0.0f, 0.0f, textWidth, errorHeight + frameSize.Height());
359 textFieldOverlayModifier_->SetBoundsRect(boundsRect);
360 textFieldForegroundModifier_->SetBoundsRect(boundsRect);
361 } else {
362 if (NearEqual(maxFrameOffsetY_, 0.0f) && NearEqual(maxFrameHeight_, 0.0f)) {
363 maxFrameOffsetY_ = frameOffset.GetY();
364 maxFrameHeight_ = frameSize.Height();
365 }
366 maxFrameOffsetY_ = LessOrEqual(frameOffset.GetY(), maxFrameOffsetY_) ? frameOffset.GetY()
367 : maxFrameOffsetY_ - frameOffset.GetY();
368 maxFrameHeight_ = LessOrEqual(frameSize.Height(), maxFrameHeight_) ? maxFrameHeight_ : frameSize.Height();
369 RectF boundsRect(0.0f, 0.0f, frameSize.Width(), maxFrameHeight_ + UNDERLINE_WIDTH.ConvertToPx());
370 textFieldOverlayModifier_->SetBoundsRect(boundsRect);
371 textFieldForegroundModifier_->SetBoundsRect(boundsRect);
372 }
373 }
374
CalcScrollRect(Rect & inlineScrollRect)375 void TextFieldPattern::CalcScrollRect(Rect& inlineScrollRect)
376 {
377 if (!IsNormalInlineState()) {
378 // if textfield is not inline, no need to calc rect
379 return;
380 }
381 auto host = GetHost();
382 CHECK_NULL_VOID(host);
383 auto pipeline = host->GetContext();
384 CHECK_NULL_VOID(pipeline);
385 auto scrollBar = GetScrollBar();
386 CHECK_NULL_VOID(scrollBar);
387 Size size(frameRect_.Width(), inlineMeasureItem_.inlineSizeHeight);
388 auto positionMode_ = scrollBar->GetPositionMode();
389 double mainSize = (positionMode_ == PositionMode::BOTTOM ? size.Width() : size.Height());
390 auto barRegionSize = mainSize;
391 double estimatedHeight = inlineMeasureItem_.inlineContentRectHeight;
392 if (NearZero(estimatedHeight) || NearZero(estimatedHeight - mainSize)) {
393 return;
394 }
395 double activeSize = barRegionSize * mainSize / estimatedHeight - scrollBar->GetOutBoundary();
396 auto offsetScale = 0.0f;
397 if (NearEqual(mainSize, estimatedHeight)) {
398 offsetScale = 0.0;
399 } else {
400 offsetScale = (barRegionSize - activeSize) / (estimatedHeight - mainSize);
401 }
402 double lastMainOffset = std::max(
403 static_cast<double>(std::max(inlineMeasureItem_.inlineLastOffsetY, contentRect_.GetY() - textRect_.GetY())),
404 0.0);
405 double activeMainOffset = std::min(offsetScale * lastMainOffset, barRegionSize - activeSize);
406 inlineScrollRect.SetLeft(inlineScrollRect.GetOffset().GetX() - inlineMeasureItem_.inlineScrollRectOffsetX);
407 inlineScrollRect.SetTop(activeMainOffset);
408 inlineScrollRect.SetHeight(activeSize);
409 }
410
CreateObscuredText(int32_t len)411 std::u16string TextFieldPattern::CreateObscuredText(int32_t len)
412 {
413 std::u16string obscuredText;
414 if (Localization::GetInstance()->GetLanguage() == "ar") { // ar is the abbreviation of Arabic.
415 obscuredText = std::u16string(len, OBSCURING_CHARACTER_FOR_AR);
416 } else {
417 obscuredText = std::u16string(len, OBSCURING_CHARACTER);
418 }
419 return obscuredText;
420 }
421
CreateDisplayText(const std::u16string & content,int32_t nakedCharPosition,bool needObscureText,bool showPasswordDirectly)422 std::u16string TextFieldPattern::CreateDisplayText(
423 const std::u16string& content, int32_t nakedCharPosition, bool needObscureText, bool showPasswordDirectly)
424 {
425 if (!content.empty() && needObscureText) {
426 auto text =
427 TextFieldPattern::CreateObscuredText(static_cast<int32_t>(content.length()));
428 if (nakedCharPosition >= 0 && nakedCharPosition < static_cast<int32_t>(content.length())) {
429 if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE) || !showPasswordDirectly) {
430 text[nakedCharPosition] = content[nakedCharPosition];
431 }
432 }
433 return text;
434 }
435 return content;
436 }
437
GetTextOrPlaceHolderFontSize()438 float TextFieldPattern::GetTextOrPlaceHolderFontSize()
439 {
440 auto tmpHost = GetHost();
441 CHECK_NULL_RETURN(tmpHost, 0.0f);
442 auto textFieldLayoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
443 CHECK_NULL_RETURN(textFieldLayoutProperty, 0.0f);
444 auto textFieldTheme = GetTheme();
445 CHECK_NULL_RETURN(textFieldTheme, 0.0f);
446 Dimension fontSize;
447 if (textFieldLayoutProperty->HasFontSize() &&
448 textFieldLayoutProperty->GetFontSizeValue(Dimension()).IsNonNegative()) {
449 fontSize = textFieldLayoutProperty->GetFontSizeValue(Dimension());
450 } else {
451 return textFieldTheme ? static_cast<float>(textFieldTheme->GetFontSize().ConvertToPx())
452 : static_cast<float>(DEFAULT_FONT.ConvertToPx());
453 }
454 return std::min(static_cast<float>(fontSize.ConvertToPx()), contentRect_.Height());
455 }
456
TextFieldPattern()457 TextFieldPattern::TextFieldPattern() : twinklingInterval_(TWINKLING_INTERVAL_MS)
458 {
459 if (PipelineContext::GetCurrentContextSafelyWithCheck() &&
460 // for normal app add version protection, enable keyboard as default start from API 10 or higher
461 PipelineContext::GetCurrentContextSafelyWithCheck()->GetMinPlatformVersion() > KEYBOARD_DEFAULT_API) {
462 needToRequestKeyboardOnFocus_ = !GetIndependentControlKeyboard();
463 }
464 contentController_ = MakeRefPtr<ContentController>(WeakClaim(this));
465 selectController_ = MakeRefPtr<TextSelectController>(WeakClaim(this));
466 selectController_->InitContentController(contentController_);
467 magnifierController_ = MakeRefPtr<MagnifierController>(WeakClaim(this));
468 selectOverlay_ = MakeRefPtr<TextFieldSelectOverlay>(WeakClaim(this));
469 if (SystemProperties::GetDebugEnabled()) {
470 twinklingInterval_ = 3000; // 3000 : for AtuoUITest
471 }
472 ResetOriginCaretPosition();
473 callbackOldPreviewText_.offset = -1;
474 }
475
GetIndependentControlKeyboard()476 bool TextFieldPattern::GetIndependentControlKeyboard()
477 {
478 auto context = PipelineContext::GetCurrentContextSafelyWithCheck();
479 CHECK_NULL_RETURN(context, false);
480 auto theme = context->GetTheme<TextFieldTheme>();
481 CHECK_NULL_RETURN(theme, false);
482 independentControlKeyboard_ = theme->GetIndependentControlKeyboard();
483 return independentControlKeyboard_;
484 }
485
~TextFieldPattern()486 TextFieldPattern::~TextFieldPattern()
487 {
488 if (textEditingController_) {
489 textEditingController_->Clear();
490 textEditingController_->RemoveObserver(WeakClaim(this));
491 }
492 CloseSelectOverlay();
493 if (isCustomKeyboardAttached_) {
494 CloseCustomKeyboard();
495 }
496 RemoveTextFieldInfo();
497 }
498
CheckAndUpdateRecordBeforeOperation()499 void TextFieldPattern::CheckAndUpdateRecordBeforeOperation()
500 {
501 if (operationRecords_.size() == 0 ||
502 operationRecords_.back().caretPosition != selectController_->GetCaretIndex()) {
503 // record the state before the operation
504 // or caret position change
505 UpdateEditingValueToRecord();
506 }
507 }
508
BeforeCreateLayoutWrapper()509 void TextFieldPattern::BeforeCreateLayoutWrapper()
510 {
511 while (!inputOperations_.empty()) {
512 auto operation = inputOperations_.front();
513 inputOperations_.pop();
514 CheckAndUpdateRecordBeforeOperation();
515 switch (operation) {
516 case InputOperation::INSERT: {
517 ExecuteInsertValueCommand(insertCommands_.front());
518 insertCommands_.pop();
519 break;
520 }
521 case InputOperation::DELETE_BACKWARD: {
522 DeleteBackwardOperation(deleteBackwardOperations_.front());
523 deleteBackwardOperations_.pop();
524 HandleDeleteOnCounterScene();
525 break;
526 }
527 case InputOperation::DELETE_FORWARD: {
528 DeleteForwardOperation(deleteForwardOperations_.front());
529 deleteForwardOperations_.pop();
530 HandleDeleteOnCounterScene();
531 break;
532 }
533 case InputOperation::CURSOR_UP: {
534 CursorMoveUpOperation();
535 break;
536 }
537 case InputOperation::CURSOR_DOWN: {
538 CursorMoveDownOperation();
539 break;
540 }
541 case InputOperation::CURSOR_LEFT: {
542 CursorMoveLeftOperation();
543 break;
544 }
545 case InputOperation::CURSOR_RIGHT: {
546 CursorMoveRightOperation();
547 break;
548 }
549 case InputOperation::SET_PREVIEW_TEXT:
550 SetPreviewTextOperation(previewTextOperation_.front());
551 previewTextOperation_.pop();
552 break;
553 case InputOperation::SET_PREVIEW_FINISH:
554 FinishTextPreviewOperation();
555 break;
556 case InputOperation::INPUT:
557 ExecuteInputCommand(inputCommands_.front());
558 inputCommands_.pop();
559 break;
560 }
561 }
562 selectOverlay_->MarkOverlayDirty();
563 }
564
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)565 bool TextFieldPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
566 {
567 if (config.skipMeasure || dirty->SkipMeasureContent()) {
568 return false;
569 }
570 contentRect_ = dirty->GetGeometryNode()->GetContentRect();
571 frameRect_ = dirty->GetGeometryNode()->GetFrameRect();
572 auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
573 CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
574 auto textFieldLayoutAlgorithm = DynamicCast<TextFieldLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
575 CHECK_NULL_RETURN(textFieldLayoutAlgorithm, false);
576 auto paragraph = textFieldLayoutAlgorithm->GetParagraph();
577 float paragraphWidth = 0.0f;
578 if (paragraph) {
579 paragraph_ = paragraph;
580 paragraphWidth = std::max(paragraph->GetLongestLine(), 0.0f);
581 }
582 if (!IsDragging()) {
583 do {
584 if (!dragNode_) {
585 break;
586 }
587 auto dragNodePattern = AceType::DynamicCast<TextDragPattern>(dragNode_->GetPattern());
588 if (!dragNodePattern) {
589 break;
590 }
591 dragNodePattern->UpdateParagraph(paragraph_);
592 } while (false);
593 }
594 auto textRect = textFieldLayoutAlgorithm->GetTextRect();
595 auto isSameSizeMouseMenu = NearEqual(paragraphWidth, paragraphWidth_) &&
596 NearEqual(textRect.GetSize(), textRect_.GetSize()) && IsUsingMouse();
597 needToRefreshSelectOverlay_ = needToRefreshSelectOverlay_ && !isSameSizeMouseMenu;
598 paragraphWidth_ = paragraphWidth;
599 HandleContentSizeChange(textRect);
600 textRect_ = textRect;
601
602 if (textFieldContentModifier_) {
603 textFieldContentModifier_->ContentChange();
604 }
605
606 if (textFieldOverlayModifier_) {
607 textFieldOverlayModifier_->ContentChange();
608 }
609
610 auto oldParentGlobalOffset = parentGlobalOffset_;
611 parentGlobalOffset_ = GetPaintRectGlobalOffset();
612 inlineMeasureItem_ = textFieldLayoutAlgorithm->GetInlineMeasureItem();
613 auto isEditorValueChanged = FireOnTextChangeEvent();
614 UpdateCancelNode();
615 UpdateSelectController();
616 AdjustTextInReasonableArea();
617 UpdateCaretRect(isEditorValueChanged);
618 UpdateTextFieldManager(Offset(parentGlobalOffset_.GetX(), parentGlobalOffset_.GetY()), frameRect_.Height());
619 UpdateCaretInfoToController();
620 auto hostLayoutProperty =
621 dirty->GetHostNode() ? dirty->GetHostNode()->GetLayoutProperty<TextFieldLayoutProperty>() : nullptr;
622 if (hostLayoutProperty) {
623 hostLayoutProperty->ResetTextAlignChanged();
624 }
625 ProcessOverlayAfterLayout(oldParentGlobalOffset);
626 if (inlineSelectAllFlag_) {
627 HandleOnSelectAll(false, true);
628 inlineSelectAllFlag_ = false;
629 showSelect_ = true;
630 }
631 if (needSelectAll_ && !isLongPress_) {
632 HandleOnSelectAll(false);
633 needSelectAll_ = false;
634 }
635 if (mouseStatus_ == MouseStatus::RELEASED) {
636 mouseStatus_ = MouseStatus::NONE;
637 }
638 StopScrollable();
639 CheckScrollable();
640 UpdateScrollBarOffset();
641 if (config.frameSizeChange) {
642 ScheduleDisappearDelayTask();
643 }
644 SetAccessibilityClearAction();
645 SetAccessibilityPasswordIconAction();
646 SetAccessibilityUnitAction();
647 if (afterDragSelect_) {
648 UpdateSelectionAndHandleVisibility();
649 afterDragSelect_ = false;
650 }
651 releaseInDrop_ = false;
652 textParagraphIndent_ = textFieldLayoutAlgorithm->GetTextIndent();
653 return true;
654 }
655
UpdateSelectionAndHandleVisibility()656 void TextFieldPattern::UpdateSelectionAndHandleVisibility()
657 {
658 TextFieldRequestFocus(RequestFocusReason::DRAG_SELECT);
659 auto start = dragTextStart_;
660 auto end = dragTextEnd_;
661 if (isMouseOrTouchPad(sourceTool_) && releaseInDrop_) {
662 start = selectController_->GetCaretIndex()
663 - static_cast<int32_t>(contentController_->GetInsertValue().length());
664 end = selectController_->GetCaretIndex();
665 }
666 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "UpdateSelectionAndHandleVisibility range=[%{public}d--%{public}d]",
667 start, end);
668 UpdateSelection(start, end);
669 showSelect_ = true;
670
671 if (!isMouseOrTouchPad(sourceTool_)) {
672 ProcessOverlay({ .menuIsShow = false });
673 }
674 auto host = GetHost();
675 CHECK_NULL_VOID(host);
676 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
677 }
678
SetAccessibilityPasswordIconAction()679 void TextFieldPattern::SetAccessibilityPasswordIconAction()
680 {
681 CHECK_NULL_VOID(IsShowPasswordIcon());
682 auto passwordArea = AceType::DynamicCast<PasswordResponseArea>(responseArea_);
683 CHECK_NULL_VOID(passwordArea);
684 auto node = passwordArea->GetFrameNode();
685 CHECK_NULL_VOID(node);
686 auto textAccessibilityProperty = node->GetAccessibilityProperty<AccessibilityProperty>();
687 CHECK_NULL_VOID(textAccessibilityProperty);
688 textAccessibilityProperty->SetAccessibilityLevel("yes");
689 textAccessibilityProperty->SetAccessibilityText(GetPasswordIconPromptInformation(passwordArea->IsObscured()));
690 }
691
SetAccessibilityClearAction()692 void TextFieldPattern::SetAccessibilityClearAction()
693 {
694 CHECK_NULL_VOID(IsShowCancelButtonMode());
695 auto cleanNodeResponseArea = AceType::DynamicCast<CleanNodeResponseArea>(cleanNodeResponseArea_);
696 CHECK_NULL_VOID(cleanNodeResponseArea);
697 auto stackNode = cleanNodeResponseArea->GetFrameNode();
698 CHECK_NULL_VOID(stackNode);
699 auto textAccessibilityProperty = stackNode->GetAccessibilityProperty<AccessibilityProperty>();
700 CHECK_NULL_VOID(textAccessibilityProperty);
701 textAccessibilityProperty->SetAccessibilityLevel("yes");
702 auto layoutProperty = GetHost()->GetLayoutProperty<TextFieldLayoutProperty>();
703 CHECK_NULL_VOID(layoutProperty);
704 auto cleanNodeStyle = layoutProperty->GetCleanNodeStyleValue(CleanNodeStyle::INPUT);
705 auto hasContent = cleanNodeStyle == CleanNodeStyle::CONSTANT ||
706 (cleanNodeStyle == CleanNodeStyle::INPUT && HasText());
707 textAccessibilityProperty->SetAccessibilityText(hasContent ? GetCancelImageText() : "");
708 }
709
SetAccessibilityUnitAction()710 void TextFieldPattern::SetAccessibilityUnitAction()
711 {
712 if (!unitNode_ || !responseArea_) {
713 return;
714 }
715 auto unitNode = AceType::DynamicCast<FrameNode>(unitNode_);
716 CHECK_NULL_VOID(unitNode);
717 auto unitAccessibilityProperty = unitNode->GetAccessibilityProperty<AccessibilityProperty>();
718 CHECK_NULL_VOID(unitAccessibilityProperty);
719 unitAccessibilityProperty->SetAccessibilityLevel("yes");
720 }
721
HandleContentSizeChange(const RectF & textRect)722 void TextFieldPattern::HandleContentSizeChange(const RectF& textRect)
723 {
724 if (textRect_ == textRect) {
725 return;
726 }
727 auto host = GetHost();
728 CHECK_NULL_VOID(host);
729 if (!NearEqual(textRect.Height(), textRect_.Height())) {
730 PlayScrollBarAppearAnimation();
731 ScheduleDisappearDelayTask();
732 }
733 auto eventHub = host->GetEventHub<TextFieldEventHub>();
734 CHECK_NULL_VOID(eventHub);
735 if (eventHub->GetOnContentSizeChange()) {
736 auto pipeline = host->GetContext();
737 CHECK_NULL_VOID(pipeline);
738 auto weak = WeakClaim(Referenced::RawPtr(eventHub));
739 pipeline->AddAfterLayoutTask([textRect, weak]() {
740 auto eventHub = weak.Upgrade();
741 CHECK_NULL_VOID(eventHub);
742 eventHub->FireOnContentSizeChange(std::max(0.0f, textRect.Width()), textRect.Height());
743 });
744 }
745 }
746
ProcessOverlayAfterLayout(const OffsetF & prevOffset)747 void TextFieldPattern::ProcessOverlayAfterLayout(const OffsetF& prevOffset)
748 {
749 auto host = GetHost();
750 CHECK_NULL_VOID(host);
751 auto pipeline = host->GetContext();
752 CHECK_NULL_VOID(pipeline);
753 pipeline->AddAfterLayoutTask([weak = WeakClaim(this), prevOffset]() {
754 auto pattern = weak.Upgrade();
755 CHECK_NULL_VOID(pattern);
756 pattern->parentGlobalOffset_ = pattern->GetPaintRectGlobalOffset();
757 if (pattern->SelectOverlayIsOn()) {
758 if (pattern->IsSelected()) {
759 pattern->selectOverlay_->UpdateAllHandlesOffset();
760 } else {
761 pattern->selectOverlay_->UpdateSecondHandleOffset();
762 }
763 }
764 if (pattern->processOverlayDelayTask_) {
765 if (pattern->HasFocus()) {
766 pattern->processOverlayDelayTask_();
767 }
768 pattern->processOverlayDelayTask_ = nullptr;
769 } else if (prevOffset != pattern->parentGlobalOffset_) {
770 pattern->HandleParentGlobalOffsetChange();
771 } else if (pattern->needToRefreshSelectOverlay_ && pattern->SelectOverlayIsOn()) {
772 if (pattern->IsSelected()) {
773 pattern->StopTwinkling();
774 } else {
775 pattern->StartTwinkling();
776 }
777 pattern->selectOverlay_->SetUsingMouse(pattern->selectOverlay_->IsShowMouseMenu());
778 pattern->ProcessOverlay({ .menuIsShow = pattern->selectOverlay_->IsCurrentMenuVisibile() });
779 pattern->selectOverlay_->SetUsingMouse(false);
780 }
781 pattern->needToRefreshSelectOverlay_ = false;
782 });
783 }
784
HasFocus() const785 bool TextFieldPattern::HasFocus() const
786 {
787 auto focusHub = GetFocusHub();
788
789 CHECK_NULL_RETURN(focusHub, false);
790 return focusHub->IsCurrentFocus();
791 }
792
UpdateCaretInfoToController(bool forceUpdate)793 void TextFieldPattern::UpdateCaretInfoToController(bool forceUpdate)
794 {
795 CHECK_NULL_VOID(HasFocus());
796 #if defined(ENABLE_STANDARD_INPUT)
797 auto miscTextConfig = GetMiscTextConfig();
798 CHECK_NULL_VOID(miscTextConfig.has_value());
799 PreviewRange miscTextConfigRange {
800 miscTextConfig.value().range.start,
801 miscTextConfig.value().range.end
802 };
803 if (!forceUpdate && lastCursorRange_ == miscTextConfigRange &&
804 lastTextValue_ == contentController_->GetTextUtf16Value() &&
805 NearEqual(miscTextConfig.value().cursorInfo.top, lastCursorTop_)) {
806 return;
807 }
808 lastCursorRange_.Set(miscTextConfig.value().range.start, miscTextConfig.value().range.end);
809 lastTextValue_ = contentController_->GetTextUtf16Value();
810 lastCursorTop_ = miscTextConfig.value().cursorInfo.top;
811 MiscServices::CursorInfo cursorInfo = miscTextConfig.value().cursorInfo;
812 MiscServices::InputMethodController::GetInstance()->OnCursorUpdate(cursorInfo);
813 MiscServices::InputMethodController::GetInstance()->OnSelectionChange(
814 contentController_->GetTextUtf16Value(), selectController_->GetStartIndex(),
815 selectController_->GetEndIndex());
816 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD,
817 "UpdateCaretInfoToController, left %{public}f, top %{public}f, width %{public}f, height %{public}f; "
818 "selectController_ start "
819 "%{public}d, end %{public}d",
820 cursorInfo.left, cursorInfo.top, cursorInfo.width, cursorInfo.height, selectController_->GetStartIndex(),
821 selectController_->GetEndIndex());
822
823 #else
824 if (HasConnection()) {
825 TextEditingValue value;
826 value.text = contentController_->GetTextValue();
827 value.hint = UtfUtils::Str16DebugToStr8(GetPlaceHolder());
828 value.selection.Update(selectController_->GetStartIndex(), selectController_->GetEndIndex());
829 connection_->SetEditingState(value, GetInstanceId());
830 }
831 #endif
832 }
833
UpdateCaretRect(bool isEditorValueChanged)834 void TextFieldPattern::UpdateCaretRect(bool isEditorValueChanged)
835 {
836 auto focusHub = GetFocusHub();
837 if (IsSelected()) {
838 selectController_->MoveFirstHandleToContentRect(selectController_->GetFirstHandleIndex(), false);
839 selectController_->MoveSecondHandleToContentRect(selectController_->GetSecondHandleIndex(), false);
840 return;
841 }
842 if (focusHub && !focusHub->IsCurrentFocus() && !obscuredChange_) {
843 CloseSelectOverlay(true);
844 return;
845 }
846 selectController_->MoveCaretToContentRect(
847 selectController_->GetCaretIndex(), TextAffinity::DOWNSTREAM, isEditorValueChanged);
848 }
849
AdjustTextInReasonableArea()850 void TextFieldPattern::AdjustTextInReasonableArea()
851 {
852 // Adjust y.
853 auto contentBottomBoundary = contentRect_.GetY() + contentRect_.GetSize().Height();
854 if (textRect_.Height() > contentRect_.Height()) {
855 if (textRect_.GetY() + textRect_.Height() < contentBottomBoundary) {
856 auto dy = contentBottomBoundary - textRect_.GetY() - textRect_.Height();
857 textRect_.SetOffset(OffsetF(textRect_.GetX(), textRect_.GetY() + dy));
858 }
859 if (GreatNotEqual(textRect_.GetY(), contentRect_.GetY())) {
860 auto dy = textRect_.GetY() - contentRect_.GetY();
861 textRect_.SetOffset(OffsetF(textRect_.GetX(), textRect_.GetY() - dy));
862 }
863 } else {
864 if (textRect_.GetY() != contentRect_.GetY()) {
865 auto dy = contentRect_.GetY() - textRect_.GetY();
866 textRect_.SetOffset(OffsetF(textRect_.GetX(), textRect_.GetY() + dy));
867 }
868 }
869
870 // Adjust x.
871 auto contentRightBoundary = contentRect_.GetX() + contentRect_.GetSize().Width();
872 if (textRect_.Width() > contentRect_.Width()) {
873 if (textRect_.GetX() + textRect_.Width() < contentRightBoundary) {
874 auto dx = contentRightBoundary - textRect_.GetX() - textRect_.Width();
875 textRect_.SetLeft(textRect_.GetX() + dx);
876 }
877 if (GreatNotEqual(textRect_.GetX(), contentRect_.GetX())) {
878 auto dx = textRect_.GetX() - contentRect_.GetX();
879 textRect_.SetOffset(OffsetF(textRect_.GetX() - dx, textRect_.GetY()));
880 }
881 }
882 }
883
IsTextArea() const884 bool TextFieldPattern::IsTextArea() const
885 {
886 auto tmpHost = GetHost();
887 CHECK_NULL_RETURN(tmpHost, false);
888 auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
889 CHECK_NULL_RETURN(layoutProperty, true);
890 return layoutProperty->HasMaxLines() ? layoutProperty->GetMaxLinesValue(1) > 1 : true;
891 }
892
UpdateSelectionOffset()893 void TextFieldPattern::UpdateSelectionOffset()
894 {
895 CHECK_NULL_VOID(IsSelected());
896 selectController_->CalculateHandleOffset();
897 }
898
CalcCaretMetricsByPosition(int32_t extent,CaretMetricsF & caretCaretMetric,TextAffinity textAffinity)899 void TextFieldPattern::CalcCaretMetricsByPosition(
900 int32_t extent, CaretMetricsF& caretCaretMetric, TextAffinity textAffinity)
901 {
902 CHECK_NULL_VOID(paragraph_);
903 paragraph_->CalcCaretMetricsByPosition(extent, caretCaretMetric, textAffinity);
904 caretCaretMetric.offset.AddX(textRect_.GetX());
905 caretCaretMetric.offset.AddY(textRect_.GetY());
906 }
907
CursorInContentRegion()908 bool TextFieldPattern::CursorInContentRegion()
909 {
910 if (IsTextArea()) {
911 return GreatOrEqual(selectController_->GetCaretRect().GetY(), contentRect_.GetY()) &&
912 LessOrEqual(selectController_->GetCaretRect().GetY() + GetTextOrPlaceHolderFontSize(),
913 contentRect_.GetY() + contentRect_.Height());
914 }
915 auto theme = GetTheme();
916 CHECK_NULL_RETURN(theme, false);
917 return GreatOrEqual(selectController_->GetCaretRect().GetX(), contentRect_.GetX()) &&
918 LessOrEqual(selectController_->GetCaretRect().GetX() + theme->GetCursorWidth().ConvertToPx(),
919 contentRect_.GetX() + contentRect_.Width());
920 }
921
OffsetInContentRegion(const Offset & offset)922 bool TextFieldPattern::OffsetInContentRegion(const Offset& offset)
923 {
924 // real content region will minus basic padding on left and right
925 return GreatOrEqual(offset.GetX(), contentRect_.GetX()) &&
926 LessOrEqual(offset.GetX(), contentRect_.GetX() + contentRect_.Width());
927 }
928
CheckSelectAreaVisible()929 bool TextFieldPattern::CheckSelectAreaVisible()
930 {
931 auto tmpHost = GetHost();
932 CHECK_NULL_RETURN(tmpHost, false);
933 auto pipeline = tmpHost->GetContextRefPtr();
934 CHECK_NULL_RETURN(pipeline, false);
935 auto keyboardInset = pipeline->GetSafeAreaManager()->GetKeyboardInset();
936 auto selectArea = selectOverlay_->GetSelectArea();
937 auto globalOffset = GetPaintRectGlobalOffset();
938 auto globalContentRect = contentRect_;
939 globalContentRect.SetOffset(globalContentRect.GetOffset() + globalOffset);
940 if (selectArea.Bottom() < 0) {
941 return false;
942 } else if (!globalContentRect.IsInnerIntersectWith(selectArea)) {
943 return false;
944 } else if (keyboardInset.Length() > 0 && selectArea.Top() >= keyboardInset.start) {
945 return false;
946 }
947 return true;
948 }
949
OnScrollEndCallback()950 void TextFieldPattern::OnScrollEndCallback()
951 {
952 ScheduleDisappearDelayTask();
953 if (!IsUsingMouse() && SelectOverlayIsOn() && isTextSelectionMenuShow_ && CheckSelectAreaVisible()) {
954 selectOverlay_->ShowMenu();
955 }
956 }
957
OnTextAreaScroll(float offset)958 void TextFieldPattern::OnTextAreaScroll(float offset)
959 {
960 if (!IsTextArea() || textRect_.Height() <= contentRect_.Height()) {
961 return;
962 }
963 if (textRect_.GetY() + offset > contentRect_.GetY()) {
964 offset = contentRect_.GetY() - textRect_.GetY();
965 } else if (textRect_.GetY() + textRect_.Height() + offset < contentRect_.GetY() + contentRect_.Height()) {
966 offset = contentRect_.GetY() + contentRect_.Height() - textRect_.GetY() - textRect_.Height();
967 }
968 currentOffset_ = textRect_.GetY() + offset;
969 textRect_.SetOffset(OffsetF(textRect_.GetX(), currentOffset_));
970 UpdateHandlesOffsetOnScroll(offset);
971 UpdateScrollBarOffset();
972 }
973
OnTextInputScroll(float offset)974 void TextFieldPattern::OnTextInputScroll(float offset)
975 {
976 if (IsTextArea() || textRect_.Width() <= contentRect_.Width()) {
977 return;
978 }
979 if (textRect_.GetX() + offset > contentRect_.GetX()) {
980 offset = contentRect_.GetX() - textRect_.GetX();
981 } else if (textRect_.GetX() + textRect_.Width() + offset < contentRect_.GetX() + contentRect_.Width()) {
982 offset = contentRect_.GetX() + contentRect_.Width() - textRect_.GetX() - textRect_.Width();
983 }
984 currentOffset_ = textRect_.GetX() + offset;
985 textRect_.SetOffset(OffsetF(currentOffset_, textRect_.GetY()));
986 UpdateHandlesOffsetOnScroll(offset);
987 auto tmpHost = GetHost();
988 CHECK_NULL_VOID(tmpHost);
989 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
990 }
991
ConvertTouchOffsetToCaretPosition(const Offset & localOffset)992 int32_t TextFieldPattern::ConvertTouchOffsetToCaretPosition(const Offset& localOffset)
993 {
994 CHECK_NULL_RETURN(paragraph_, 0);
995 int32_t caretPositionIndex = 0;
996 if (!contentController_->IsEmpty()) {
997 caretPositionIndex = paragraph_->GetGlyphIndexByCoordinate(localOffset);
998 }
999 return caretPositionIndex;
1000 }
1001
ConvertTouchOffsetToCaretPositionNG(const Offset & localOffset)1002 int32_t TextFieldPattern::ConvertTouchOffsetToCaretPositionNG(const Offset& localOffset)
1003 {
1004 CHECK_NULL_RETURN(paragraph_, 0);
1005 auto offset = localOffset - Offset(textRect_.GetX(), textRect_.GetY());
1006 return paragraph_->GetGlyphIndexByCoordinate(offset);
1007 }
1008
1009 #if defined(IOS_PLATFORM)
GetGlobalOffset() const1010 Offset TextFieldPattern::GetGlobalOffset() const
1011 {
1012 Offset offset;
1013 auto host = GetHost();
1014 CHECK_NULL_RETURN(host, {});
1015 auto pipeline = host->GetContext();
1016 CHECK_NULL_RETURN(pipeline, {});
1017 auto rootOffset = pipeline->GetRootRect().GetOffset();
1018 auto globalOffset = host->GetPaintRectOffset(false, true) - rootOffset;
1019 offset = Offset(globalOffset.GetX(), globalOffset.GetY());
1020 return offset;
1021 }
1022
GetEditingBoxY() const1023 double TextFieldPattern::GetEditingBoxY() const
1024 {
1025 return GetGlobalOffset().GetY() + frameRect_.Height();
1026 };
1027
GetEditingBoxTopY() const1028 double TextFieldPattern::GetEditingBoxTopY() const
1029 {
1030 return GetGlobalOffset().GetY();
1031 };
1032
GetEditingBoxModel() const1033 bool TextFieldPattern::GetEditingBoxModel() const
1034 {
1035 bool isDeclarative = false;
1036 auto host = GetHost();
1037 CHECK_NULL_RETURN(host, false);
1038 auto pipeline = host->GetContext();
1039 if (pipeline && pipeline->GetIsDeclarative()) {
1040 isDeclarative = true;
1041 }
1042 return isDeclarative;
1043 };
1044 #endif
1045
HandleFocusEvent()1046 void TextFieldPattern::HandleFocusEvent()
1047 {
1048 isFocusedBeforeClick_ = true;
1049 focusIndex_ = FocuseIndex::TEXT;
1050 auto host = GetHost();
1051 CHECK_NULL_VOID(host);
1052 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "TextField %{public}d on focus", host->GetId());
1053 ACE_LAYOUT_SCOPED_TRACE("[TextField:%d] on focus", host->GetId());
1054 auto context = host->GetContextRefPtr();
1055 CHECK_NULL_VOID(context);
1056 context->AddOnAreaChangeNode(host->GetId());
1057 auto globalOffset = host->GetPaintRectOffset(false, true) - context->GetRootRect().GetOffset();
1058 UpdateTextFieldManager(Offset(globalOffset.GetX(), globalOffset.GetY()), frameRect_.Height());
1059 SetNeedToRequestKeyboardInner(!isLongPress_ && (dragRecipientStatus_ != DragStatus::DRAGGING) &&
1060 (dragStatus_ != DragStatus::DRAGGING) && !afterDragSelect_, RequestKeyboardInnerChangeReason::FOCUS);
1061 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
1062 CHECK_NULL_VOID(paintProperty);
1063 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
1064 CHECK_NULL_VOID(layoutProperty);
1065 auto isSelectAll = layoutProperty->GetSelectAllValueValue(false);
1066 if (isSelectAll && !contentController_->IsEmpty()) {
1067 needSelectAll_ = !independentControlKeyboard_;
1068 }
1069 SetIsEnableSubWindowMenu();
1070 ProcessFocusStyle();
1071 ProcessAutoFillOnFocus();
1072 RequestKeyboardByFocusSwitch();
1073 ResetFirstClickAfterGetFocus();
1074 SetFocusStyle();
1075 host->MarkDirtyNode(layoutProperty->GetMaxLinesValue(Infinity<float>()) <= 1 ?
1076 PROPERTY_UPDATE_MEASURE_SELF : PROPERTY_UPDATE_MEASURE);
1077 }
1078
SetFocusStyle()1079 void TextFieldPattern::SetFocusStyle()
1080 {
1081 if (IsUnderlineMode() || IsInlineMode()) {
1082 return;
1083 }
1084 auto host = GetHost();
1085 CHECK_NULL_VOID(host);
1086 auto renderContext = host->GetRenderContext();
1087 CHECK_NULL_VOID(renderContext);
1088 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
1089 CHECK_NULL_VOID(paintProperty);
1090 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
1091 CHECK_NULL_VOID(layoutProperty);
1092 auto textFieldTheme = GetTheme();
1093 CHECK_NULL_VOID(textFieldTheme);
1094
1095 if (!paintProperty->HasBackgroundColor()) {
1096 auto defaultBGColor = textFieldTheme->GetBgColor();
1097 if (paintProperty->GetBackgroundColorValue(defaultBGColor) == defaultBGColor) {
1098 renderContext->UpdateBackgroundColor(textFieldTheme->GetFocusBgColor());
1099 isFocusBGColorSet_ = true;
1100 }
1101 }
1102 auto defaultTextColor = textFieldTheme->GetTextColor();
1103 if (layoutProperty->GetTextColorValue(defaultTextColor) == defaultTextColor) {
1104 layoutProperty->UpdateTextColor(textFieldTheme->GetFocusTextColor());
1105 isFocusTextColorSet_ = true;
1106 }
1107 auto defaultPlaceholderColor = textFieldTheme->GetPlaceholderColor();
1108 if (layoutProperty->GetPlaceholderTextColorValue(defaultPlaceholderColor) == defaultPlaceholderColor) {
1109 layoutProperty->UpdatePlaceholderTextColor(textFieldTheme->GetFocusPlaceholderColor());
1110 isFocusPlaceholderColorSet_ = true;
1111 }
1112 }
1113
ClearFocusStyle()1114 void TextFieldPattern::ClearFocusStyle()
1115 {
1116 auto host = GetHost();
1117 CHECK_NULL_VOID(host);
1118 auto renderContext = host->GetRenderContext();
1119 CHECK_NULL_VOID(renderContext);
1120 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
1121 CHECK_NULL_VOID(paintProperty);
1122 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
1123 CHECK_NULL_VOID(layoutProperty);
1124 auto textFieldTheme = GetTheme();
1125 CHECK_NULL_VOID(textFieldTheme);
1126
1127 if (isFocusBGColorSet_) {
1128 renderContext->UpdateBackgroundColor(textFieldTheme->GetBgColor());
1129 isFocusBGColorSet_ = false;
1130 }
1131 if (isFocusTextColorSet_) {
1132 layoutProperty->UpdateTextColor(textFieldTheme->GetTextColor());
1133 isFocusTextColorSet_ = false;
1134 }
1135 if (isFocusPlaceholderColorSet_) {
1136 layoutProperty->UpdatePlaceholderTextColor(textFieldTheme->GetPlaceholderColor());
1137 isFocusPlaceholderColorSet_ = false;
1138 }
1139 }
1140
ProcessAutoFillOnFocus()1141 void TextFieldPattern::ProcessAutoFillOnFocus()
1142 {
1143 if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
1144 return;
1145 }
1146
1147 auto isIgnoreFocusReason =
1148 requestFocusReason_ == RequestFocusReason::DRAG_ENTER || requestFocusReason_ == RequestFocusReason::DRAG_MOVE ||
1149 requestFocusReason_ == RequestFocusReason::DRAG_END || requestFocusReason_ == RequestFocusReason::AUTO_FILL ||
1150 requestFocusReason_ == RequestFocusReason::CLICK || requestFocusReason_ == RequestFocusReason::MOUSE ||
1151 requestFocusReason_ == RequestFocusReason::DRAG_SELECT;
1152 if (needToRequestKeyboardOnFocus_ && !isIgnoreFocusReason && !IsModalCovered() && IsTriggerAutoFillPassword()) {
1153 DoProcessAutoFill();
1154 }
1155 }
1156
ProcessFocusStyle()1157 void TextFieldPattern::ProcessFocusStyle()
1158 {
1159 bool needTwinkling = true;
1160 if (IsNormalInlineState()) {
1161 ApplyInlineTheme();
1162 inlineFocusState_ = true;
1163 if (!contentController_->IsEmpty()) {
1164 inlineSelectAllFlag_ = (blurReason_ != BlurReason::WINDOW_BLUR &&
1165 requestFocusReason_ != RequestFocusReason::DRAG_SELECT);
1166 if (inlineSelectAllFlag_) {
1167 needTwinkling = false;
1168 }
1169 }
1170 ProcessResponseArea();
1171 }
1172 if (needTwinkling) {
1173 StartTwinkling();
1174 }
1175 NotifyOnEditChanged(true);
1176 if (!IsShowError() && IsUnderlineMode()) {
1177 auto textFieldTheme = GetTheme();
1178 CHECK_NULL_VOID(textFieldTheme);
1179 underlineColor_ = userUnderlineColor_.typing.value_or(textFieldTheme->GetUnderlineTypingColor());
1180 underlineWidth_ = TYPING_UNDERLINE_WIDTH;
1181 }
1182 }
1183
HandleSetSelection(int32_t start,int32_t end,bool showHandle)1184 void TextFieldPattern::HandleSetSelection(int32_t start, int32_t end, bool showHandle)
1185 {
1186 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "HandleSetSelection %{public}d, %{public}d, showOverlay:%{public}d", start, end,
1187 showHandle);
1188 StopTwinkling();
1189 UpdateSelection(start, end);
1190 if (showHandle) {
1191 ProcessOverlay();
1192 } else {
1193 CloseSelectOverlay();
1194 }
1195 UpdateCaretInfoToController();
1196 auto host = GetHost();
1197 CHECK_NULL_VOID(host);
1198 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1199 }
1200
HandleExtendAction(int32_t action)1201 void TextFieldPattern::HandleExtendAction(int32_t action)
1202 {
1203 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "HandleExtendAction %{public}d", action);
1204 switch (action) {
1205 case ACTION_SELECT_ALL: {
1206 HandleOnSelectAll(false);
1207 break;
1208 }
1209 case ACTION_CUT: {
1210 HandleOnCut();
1211 break;
1212 }
1213 case ACTION_COPY: {
1214 HandleOnCopy();
1215 break;
1216 }
1217 case ACTION_PASTE: {
1218 HandleOnPaste();
1219 break;
1220 }
1221 default: {
1222 break;
1223 }
1224 }
1225 }
1226
CursorMove(CaretMoveIntent direction)1227 void TextFieldPattern::CursorMove(CaretMoveIntent direction)
1228 {
1229 switch (direction) {
1230 case CaretMoveIntent::Left: {
1231 CursorMoveLeft();
1232 break;
1233 }
1234 case CaretMoveIntent::Right: {
1235 CursorMoveRight();
1236 break;
1237 }
1238 case CaretMoveIntent::Up: {
1239 CursorMoveUp();
1240 break;
1241 }
1242 case CaretMoveIntent::Down: {
1243 CursorMoveDown();
1244 break;
1245 }
1246 case CaretMoveIntent::LineBegin: {
1247 CursorMoveLineBegin();
1248 break;
1249 }
1250 case CaretMoveIntent::LineEnd: {
1251 CursorMoveLineEnd();
1252 break;
1253 }
1254 case CaretMoveIntent::LeftWord: {
1255 CursorMoveLeftWord();
1256 break;
1257 }
1258 case CaretMoveIntent::RightWord: {
1259 CursorMoveRightWord();
1260 break;
1261 }
1262 case CaretMoveIntent::ParagraghBegin: {
1263 CursorMoveToParagraphBegin();
1264 break;
1265 }
1266 case CaretMoveIntent::ParagraghEnd: {
1267 CursorMoveToParagraphEnd();
1268 break;
1269 }
1270 case CaretMoveIntent::Home: {
1271 CursorMoveHome();
1272 break;
1273 }
1274 case CaretMoveIntent::End: {
1275 CursorMoveEnd();
1276 break;
1277 }
1278 default: {
1279 TAG_LOGW(AceLogTag::ACE_TEXT_FIELD, "Unsupported operation of CursorMove for text field");
1280 }
1281 }
1282 }
1283
HandleSelect(CaretMoveIntent direction)1284 void TextFieldPattern::HandleSelect(CaretMoveIntent direction)
1285 {
1286 CloseSelectOverlay();
1287 switch (direction) {
1288 case CaretMoveIntent::Left: {
1289 HandleSelectionLeft();
1290 break;
1291 }
1292 case CaretMoveIntent::Right: {
1293 HandleSelectionRight();
1294 break;
1295 }
1296 case CaretMoveIntent::Up: {
1297 HandleSelectionUp();
1298 break;
1299 }
1300 case CaretMoveIntent::Down: {
1301 HandleSelectionDown();
1302 break;
1303 }
1304 case CaretMoveIntent::LineBegin: {
1305 HandleSelectionLineBegin();
1306 break;
1307 }
1308 case CaretMoveIntent::LineEnd: {
1309 HandleSelectionLineEnd();
1310 break;
1311 }
1312 case CaretMoveIntent::LeftWord: {
1313 HandleSelectionLeftWord();
1314 break;
1315 }
1316 case CaretMoveIntent::RightWord: {
1317 HandleSelectionRightWord();
1318 break;
1319 }
1320 case CaretMoveIntent::Home: {
1321 HandleSelectionHome();
1322 break;
1323 }
1324 case CaretMoveIntent::End: {
1325 HandleSelectionEnd();
1326 break;
1327 }
1328 // SelectionParagraghBegin/SelectionParagraghEnd not supported yet
1329 default: {
1330 TAG_LOGW(AceLogTag::ACE_TEXT_FIELD, "Unsupported select operation for text field");
1331 }
1332 }
1333 }
1334
InitDisableColor()1335 void TextFieldPattern::InitDisableColor()
1336 {
1337 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
1338 CHECK_NULL_VOID(layoutProperty);
1339 auto theme = GetTheme();
1340 CHECK_NULL_VOID(theme);
1341 if (IsUnderlineMode()) {
1342 underlineWidth_ = HasFocus() ? TYPING_UNDERLINE_WIDTH : UNDERLINE_WIDTH;
1343 Color underlineColor = HasFocus() ? userUnderlineColor_.typing.value_or(theme->GetUnderlineTypingColor())
1344 : userUnderlineColor_.normal.value_or(theme->GetUnderlineColor());
1345 if (IsShowError()) {
1346 underlineColor = userUnderlineColor_.error.value_or(theme->GetErrorUnderlineColor());
1347 }
1348 if (userUnderlineColor_.disable) {
1349 underlineColor_ = IsDisabled() ? userUnderlineColor_.disable.value() : underlineColor;
1350 } else {
1351 underlineColor_ = IsDisabled() ? theme->GetDisableUnderlineColor() : underlineColor;
1352 }
1353 }
1354 layoutProperty->UpdateIsDisabled(IsDisabled());
1355 }
1356
InitFocusEvent()1357 void TextFieldPattern::InitFocusEvent()
1358 {
1359 CHECK_NULL_VOID(!focusEventInitialized_);
1360 auto host = GetHost();
1361 CHECK_NULL_VOID(host);
1362 auto focusHub = host->GetOrCreateFocusHub();
1363 auto focusTask = [weak = WeakClaim(this)]() {
1364 auto pattern = weak.Upgrade();
1365 if (pattern) {
1366 pattern->HandleFocusEvent();
1367 }
1368 };
1369 focusHub->SetOnFocusInternal(focusTask);
1370 auto blurTask = [weak = WeakClaim(this)]() {
1371 auto pattern = weak.Upgrade();
1372 CHECK_NULL_VOID(pattern);
1373 pattern->HandleBlurEvent();
1374 };
1375 focusHub->SetOnBlurInternal(blurTask);
1376
1377 auto keyTask = [weak = WeakClaim(this)](const KeyEvent& keyEvent) -> bool {
1378 auto pattern = weak.Upgrade();
1379 CHECK_NULL_RETURN(pattern, false);
1380 return pattern->OnKeyEvent(keyEvent);
1381 };
1382 focusHub->SetOnKeyEventInternal(keyTask);
1383
1384 auto getInnerPaintRectCallback = [weak = WeakClaim(this)](RoundRect& paintRect) {
1385 auto pattern = weak.Upgrade();
1386 if (pattern) {
1387 pattern->GetInnerFocusPaintRect(paintRect);
1388 }
1389 };
1390 focusHub->SetInnerFocusPaintRectCallback(getInnerPaintRectCallback);
1391 focusEventInitialized_ = true;
1392 }
1393
CheckBlurReason()1394 bool TextFieldPattern::CheckBlurReason()
1395 {
1396 auto curFocusHub = GetFocusHub();
1397 CHECK_NULL_RETURN(curFocusHub, false);
1398 auto curBlurReason = curFocusHub->GetBlurReason();
1399 if (curBlurReason == BlurReason::FRAME_DESTROY) {
1400 TAG_LOGI(AceLogTag::ACE_KEYBOARD, "TextFieldPattern CheckBlurReason, Close Keyboard.");
1401 return true;
1402 }
1403 return false;
1404 }
1405
UpdateBlurReason()1406 void TextFieldPattern::UpdateBlurReason()
1407 {
1408 auto focusHub = GetFocusHub();
1409 CHECK_NULL_VOID(focusHub);
1410 blurReason_ = focusHub->GetBlurReason();
1411 }
1412
ProcNormalInlineStateInBlurEvent()1413 void TextFieldPattern::ProcNormalInlineStateInBlurEvent()
1414 {
1415 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
1416 CHECK_NULL_VOID(layoutProperty);
1417 if (IsNormalInlineState()) {
1418 if (IsTextArea() && isTextInput_) {
1419 layoutProperty->UpdateMaxLines(1);
1420 layoutProperty->UpdatePlaceholderMaxLines(1);
1421 }
1422 layoutProperty->ResetTextOverflowMaxLines();
1423 inlineSelectAllFlag_ = false;
1424 inlineFocusState_ = false;
1425 RestorePreInlineStates();
1426 }
1427 }
1428
ProcBorderAndUnderlineInBlurEvent()1429 void TextFieldPattern::ProcBorderAndUnderlineInBlurEvent()
1430 {
1431 auto host = GetHost();
1432 CHECK_NULL_VOID(host);
1433 auto textFieldTheme = GetTheme();
1434 CHECK_NULL_VOID(textFieldTheme);
1435 bool isShowError = IsShowError();
1436 bool isUnderlineMode = IsUnderlineMode();
1437 if (!isShowError && isUnderlineMode) {
1438 underlineColor_ = userUnderlineColor_.normal.value_or(textFieldTheme->GetUnderlineColor());
1439 underlineWidth_ = UNDERLINE_WIDTH;
1440 }
1441 if (showCountBorderStyle_) {
1442 showCountBorderStyle_ = false;
1443 if (isShowError) {
1444 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1445 }
1446 }
1447 if (!isShowError || (isShowError && !isUnderlineMode && !IsInPasswordMode())) {
1448 HandleCounterBorder();
1449 }
1450 }
1451
SetNeedToRequestKeyboardInner(bool needToRequestKeyboardInner,RequestKeyboardInnerChangeReason reason)1452 void TextFieldPattern::SetNeedToRequestKeyboardInner(bool needToRequestKeyboardInner,
1453 RequestKeyboardInnerChangeReason reason)
1454 {
1455 if (needToRequestKeyboardInner_ != needToRequestKeyboardInner) {
1456 TAG_LOGI(ACE_TEXT_FIELD, "Set needToRequestKeyboardInner_ to %{public}d : reason %{public}d",
1457 needToRequestKeyboardInner, static_cast<int32_t>(reason));
1458 }
1459 if (reason == RequestKeyboardInnerChangeReason::FOCUS && !needToRequestKeyboardInner) {
1460 TAG_LOGI(ACE_TEXT_FIELD, "field focus but set needToRequestKeyboardInner to false "
1461 "why: %{public}d %{public}d %{public}d", isLongPress_, dragRecipientStatus_, dragStatus_);
1462 }
1463 needToRequestKeyboardInner_ = needToRequestKeyboardInner;
1464 }
1465
HandleBlurEvent()1466 void TextFieldPattern::HandleBlurEvent()
1467 {
1468 auto host = GetHost();
1469 CHECK_NULL_VOID(host);
1470 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "TextField %{public}d OnBlur", host->GetId());
1471 auto context = host->GetContextRefPtr();
1472 CHECK_NULL_VOID(context);
1473 firstClickResetTask_.Cancel();
1474 firstClickAfterLosingFocus_ = true;
1475 UpdateBlurReason();
1476 auto textFieldManager = DynamicCast<TextFieldManagerNG>(context->GetTextFieldManager());
1477 if (textFieldManager) {
1478 textFieldManager->ClearOnFocusTextField(host->GetId());
1479 }
1480 ResetOriginCaretPosition();
1481
1482 shiftFlag_ = false;
1483 ProcBorderAndUnderlineInBlurEvent();
1484 ProcNormalInlineStateInBlurEvent();
1485 ModifyInnerStateInBlurEvent();
1486 if (magnifierController_) {
1487 magnifierController_->RemoveMagnifierFrameNode();
1488 }
1489 CloseSelectOverlay(!isKeyboardClosedByUser_ && blurReason_ == BlurReason::FOCUS_SWITCH);
1490 StopTwinkling();
1491 if (((customKeyboard_ || customKeyboardBuilder_) && isCustomKeyboardAttached_)) {
1492 CloseKeyboard(true);
1493 TAG_LOGI(AceLogTag::ACE_KEYBOARD, "textfield %{public}d on blur, close custom keyboard", host->GetId());
1494 }
1495 HandleCrossPlatformInBlurEvent();
1496 selectController_->UpdateCaretIndex(selectController_->GetCaretIndex());
1497 NotifyOnEditChanged(false);
1498 ResetFloatingCursorState();
1499 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1500 auto eventHub = host->GetEventHub<TextFieldEventHub>();
1501 CHECK_NULL_VOID(eventHub);
1502 if (!eventHub->HasOnAreaChanged()) {
1503 context->RemoveOnAreaChangeNode(host->GetId());
1504 }
1505 SetNeedToRequestKeyboardInner(false, RequestKeyboardInnerChangeReason::BLUR);
1506 if (isOnHover_) {
1507 RestoreDefaultMouseState();
1508 }
1509 ReportEvent();
1510 ScheduleDisappearDelayTask();
1511 requestFocusReason_ = RequestFocusReason::UNKNOWN;
1512 ClearFocusStyle();
1513 }
1514
ModifyInnerStateInBlurEvent()1515 void TextFieldPattern::ModifyInnerStateInBlurEvent()
1516 {
1517 isLongPress_ = false;
1518 isMoveCaretAnywhere_ = false;
1519 isFocusedBeforeClick_ = false;
1520 }
1521
HandleCrossPlatformInBlurEvent()1522 void TextFieldPattern::HandleCrossPlatformInBlurEvent()
1523 {
1524 #ifndef OHOS_PLATFORM
1525 if (HasConnection()) {
1526 CloseKeyboard(true);
1527 }
1528 #endif
1529 }
1530
OnKeyEvent(const KeyEvent & event)1531 bool TextFieldPattern::OnKeyEvent(const KeyEvent& event)
1532 {
1533 if (event.code == KeyCode::KEY_TAB && !contentController_->IsEmpty()) {
1534 if (isFocusedBeforeClick_) {
1535 isFocusedBeforeClick_ = false;
1536 HandleOnSelectAll(true);
1537 } else {
1538 CloseSelectOverlay(true);
1539 }
1540 }
1541 auto pipeline = GetContext();
1542 CHECK_NULL_RETURN(pipeline, false);
1543 auto textFieldManager = DynamicCast<TextFieldManagerNG>(pipeline->GetTextFieldManager());
1544 if (event.code == KeyCode::KEY_TAB && HasFocus() && !needToRequestKeyboardOnFocus_ && needToRequestKeyboardInner_ &&
1545 textFieldManager->GetImeShow()) {
1546 RequestKeyboardNotByFocusSwitch(RequestKeyboardReason::ON_KEY_EVENT);
1547 }
1548 // If independent control keyboard, press Enter to request keyboard.
1549 if (event.code == KeyCode::KEY_ENTER && HasFocus() && independentControlKeyboard_) {
1550 if (RequestKeyboard(false, true, true)) {
1551 NotifyOnEditChanged(true);
1552 }
1553 return true;
1554 }
1555 if (directionKeysMoveFocusOut_ && (IsMoveFocusOutFromLeft(event) || IsMoveFocusOutFromRight(event))) {
1556 TextInputClient::HandleKeyEvent(event);
1557 return false;
1558 }
1559 return TextInputClient::HandleKeyEvent(event);
1560 }
1561
IsMoveFocusOutFromLeft(const KeyEvent & event)1562 bool TextFieldPattern::IsMoveFocusOutFromLeft(const KeyEvent& event)
1563 {
1564 return (event.code == KeyCode::KEY_DPAD_LEFT || event.code == KeyCode::KEY_DPAD_UP) &&
1565 selectController_->GetCaretIndex() == 0;
1566 }
1567
IsMoveFocusOutFromRight(const KeyEvent & event)1568 bool TextFieldPattern::IsMoveFocusOutFromRight(const KeyEvent& event)
1569 {
1570 return (event.code == KeyCode::KEY_DPAD_RIGHT || event.code == KeyCode::KEY_DPAD_DOWN) &&
1571 selectController_->GetCaretIndex() == static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
1572 }
1573
HandleOnEscape()1574 bool TextFieldPattern::HandleOnEscape()
1575 {
1576 if (SelectOverlayIsOn()) {
1577 CloseSelectOverlay(true);
1578 if (!IsSelected() && HasFocus()) {
1579 StartTwinkling();
1580 }
1581 return false;
1582 }
1583 if (GetIsPreviewText()) {
1584 ResetPreviewTextState();
1585 return false;
1586 }
1587 if (HasFocus()) {
1588 StopTwinkling();
1589 TextFieldLostFocusToViewRoot();
1590 }
1591 return false;
1592 }
1593
HandleOnTab(bool backward)1594 bool TextFieldPattern::HandleOnTab(bool backward)
1595 {
1596 return backward ? UpdateFocusBackward() : UpdateFocusForward();
1597 }
1598
HandleOnUndoAction()1599 void TextFieldPattern::HandleOnUndoAction()
1600 {
1601 if (operationRecords_.empty()) {
1602 return;
1603 }
1604 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "HandleOnUndoAction");
1605 if (operationRecords_.size() == 1) {
1606 FireEventHubOnChange(u"");
1607 return;
1608 }
1609 auto value = operationRecords_.back();
1610 operationRecords_.pop_back();
1611 auto textEditingValue = operationRecords_.back(); // each record includes text and caret
1612 bool isWillChange = OnWillChangePreSetValue(textEditingValue.text);
1613 if (!isWillChange) {
1614 operationRecords_.emplace_back(value);
1615 return;
1616 }
1617 if (redoOperationRecords_.size() >= RECORD_MAX_LENGTH) {
1618 redoOperationRecords_.erase(redoOperationRecords_.begin());
1619 }
1620 if (operationRecords_.size() >= 1) {
1621 redoOperationRecords_.emplace_back(value); // the initial status is not recorded
1622 }
1623
1624 contentController_->SetTextValue(textEditingValue.text);
1625 if (value.beforeCaretPosition != -1) {
1626 selectController_->MoveCaretToContentRect(
1627 value.beforeCaretPosition, TextAffinity::DOWNSTREAM);
1628 } else {
1629 selectController_->MoveCaretToContentRect(
1630 textEditingValue.caretPosition, TextAffinity::DOWNSTREAM);
1631 }
1632 auto tmpHost = GetHost();
1633 CHECK_NULL_VOID(tmpHost);
1634 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
1635 }
1636
HandleOnRedoAction()1637 void TextFieldPattern::HandleOnRedoAction()
1638 {
1639 if (redoOperationRecords_.empty()) {
1640 return;
1641 }
1642 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "HandleOnRedoAction");
1643 auto textEditingValue = redoOperationRecords_.back();
1644 bool isWillChange = OnWillChangePreSetValue(textEditingValue.text);
1645 if (!isWillChange) {
1646 return;
1647 }
1648 redoOperationRecords_.pop_back();
1649 operationRecords_.emplace_back(textEditingValue);
1650 contentController_->SetTextValue(textEditingValue.text);
1651 selectController_->UpdateCaretIndex(textEditingValue.caretPosition);
1652 auto tmpHost = GetHost();
1653 CHECK_NULL_VOID(tmpHost);
1654 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
1655 }
1656
CanUndo()1657 bool TextFieldPattern::CanUndo()
1658 {
1659 return operationRecords_.size() > 1;
1660 }
1661
HasOperationRecords()1662 bool TextFieldPattern::HasOperationRecords()
1663 {
1664 return !operationRecords_.empty();
1665 }
1666
CanRedo()1667 bool TextFieldPattern::CanRedo()
1668 {
1669 return !redoOperationRecords_.empty();
1670 }
1671
HandleOnSelectAll(bool isKeyEvent,bool inlineStyle,bool showMenu)1672 void TextFieldPattern::HandleOnSelectAll(bool isKeyEvent, bool inlineStyle, bool showMenu)
1673 {
1674 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "HandleOnSelectAll");
1675 auto textSize = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
1676 if (textSize == 0) {
1677 return; // no content
1678 }
1679 if (inlineStyle) {
1680 auto dotPos = contentController_->GetTextUtf16Value().rfind(u'.');
1681 if (dotPos != std::string::npos && static_cast<int32_t>(dotPos) < textSize - FIND_TEXT_ZERO_INDEX) {
1682 textSize = static_cast<int32_t>(dotPos);
1683 }
1684 UpdateSelection(0, textSize);
1685 } else {
1686 UpdateSelection(0, textSize);
1687 }
1688 if (IsSelected()) {
1689 SetIsSingleHandle(false);
1690 }
1691 ResetObscureTickCountDown();
1692 auto tmpHost = GetHost();
1693 CHECK_NULL_VOID(tmpHost);
1694 parentGlobalOffset_ = GetPaintRectGlobalOffset();
1695 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1696 selectController_->MoveSecondHandleToContentRect(textSize);
1697 StopTwinkling();
1698 showSelect_ = true;
1699 if (isKeyEvent || inlineSelectAllFlag_ || IsUsingMouse()) {
1700 CloseSelectOverlay(true);
1701 if (inlineSelectAllFlag_ && !isKeyEvent && !IsUsingMouse()) {
1702 return;
1703 }
1704 if (IsSelected()) {
1705 selectOverlay_->SetSelectionHoldCallback();
1706 }
1707 return;
1708 }
1709 selectOverlay_->ProcessSelectAllOverlay({ .menuIsShow = showMenu, .animation = true });
1710 }
1711
HandleOnCopy(bool isUsingExternalKeyboard)1712 void TextFieldPattern::HandleOnCopy(bool isUsingExternalKeyboard)
1713 {
1714 CHECK_NULL_VOID(clipboard_);
1715 auto tmpHost = GetHost();
1716 CHECK_NULL_VOID(tmpHost);
1717 auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
1718 CHECK_NULL_VOID(layoutProperty);
1719 if (layoutProperty->GetCopyOptionsValue(CopyOptions::Local) == CopyOptions::None) {
1720 return;
1721 }
1722 if (!IsSelected() || IsInPasswordMode()) {
1723 return;
1724 }
1725 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "On copy, text selector %{public}s", selectController_->ToString().c_str());
1726 auto start = selectController_->GetStartIndex();
1727 auto end = selectController_->GetEndIndex();
1728 auto value = contentController_->GetSelectedValue(start, end);
1729 if (value.empty()) {
1730 return;
1731 }
1732 if (layoutProperty->GetCopyOptionsValue(CopyOptions::Local) != CopyOptions::None) {
1733 clipboard_->SetData(UtfUtils::Str16DebugToStr8(value), layoutProperty->GetCopyOptionsValue(CopyOptions::Local));
1734 }
1735
1736 if (isUsingExternalKeyboard || selectOverlay_->IsShowMouseMenu()) {
1737 CloseSelectOverlay(true);
1738 } else {
1739 selectOverlay_->HideMenu();
1740 }
1741 auto host = GetHost();
1742 CHECK_NULL_VOID(host);
1743 auto eventHub = host->GetEventHub<TextFieldEventHub>();
1744 CHECK_NULL_VOID(eventHub);
1745 eventHub->FireOnCopy(value);
1746 }
1747
IsShowHandle()1748 bool TextFieldPattern::IsShowHandle()
1749 {
1750 auto theme = GetTheme();
1751 CHECK_NULL_RETURN(theme, false);
1752 return !theme->IsTextFieldShowHandle();
1753 }
1754
GetCancelButton()1755 std::string TextFieldPattern::GetCancelButton()
1756 {
1757 auto theme = GetTheme();
1758 CHECK_NULL_RETURN(theme, "");
1759 return theme->GetCancelButton();
1760 }
1761
GetCancelImageText()1762 std::string TextFieldPattern::GetCancelImageText()
1763 {
1764 auto theme = GetTheme();
1765 CHECK_NULL_RETURN(theme, "");
1766 return theme->GetCancelImageText();
1767 }
1768
GetPasswordIconPromptInformation(bool show)1769 std::string TextFieldPattern::GetPasswordIconPromptInformation(bool show)
1770 {
1771 auto theme = GetTheme();
1772 CHECK_NULL_RETURN(theme, "");
1773 return show ? theme->GetShowPasswordPromptInformation() : theme->GetHiddenPasswordPromptInformation();
1774 }
1775
UpdateShowCountBorderStyle()1776 void TextFieldPattern::UpdateShowCountBorderStyle()
1777 {
1778 auto host = GetHost();
1779 CHECK_NULL_VOID(host);
1780 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
1781 CHECK_NULL_VOID(layoutProperty);
1782 if (layoutProperty->HasMaxLength()) {
1783 auto textLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
1784 auto maxLength = static_cast<int32_t>(layoutProperty->GetMaxLengthValue(Infinity<uint32_t>()));
1785 // if equal, the showCountBorderStyle_ is not changed
1786 if (textLength != maxLength) {
1787 showCountBorderStyle_ = textLength > maxLength;
1788 }
1789 }
1790 }
1791
HandleOnPaste()1792 void TextFieldPattern::HandleOnPaste()
1793 {
1794 auto pasteCallback = [weak = WeakClaim(this)](const std::string& data) {
1795 if (data.empty()) {
1796 TAG_LOGW(AceLogTag::ACE_TEXT_FIELD, "HandleOnPaste fail, because data is empty");
1797 return;
1798 }
1799 auto textfield = weak.Upgrade();
1800 CHECK_NULL_VOID(textfield);
1801 auto host = textfield->GetHost();
1802 CHECK_NULL_VOID(host);
1803 auto eventHub = host->GetEventHub<TextFieldEventHub>();
1804 CHECK_NULL_VOID(eventHub);
1805 TextCommonEvent event;
1806 const std::u16string pasteData = UtfUtils::Str8DebugToStr16(data);
1807 eventHub->FireOnPasteWithEvent(pasteData, event);
1808 if (event.IsPreventDefault()) {
1809 textfield->CloseSelectOverlay(true);
1810 textfield->selectController_->ResetHandles();
1811 textfield->StartTwinkling();
1812 return;
1813 }
1814 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "HandleOnPaste len:%{public}d", static_cast<int32_t>(pasteData.length()));
1815 textfield->AddInsertCommand(pasteData, InputReason::PASTE);
1816 };
1817 CHECK_NULL_VOID(clipboard_);
1818 clipboard_->GetData(pasteCallback);
1819 }
1820
IsShowTranslate()1821 bool TextFieldPattern::IsShowTranslate()
1822 {
1823 auto container = Container::Current();
1824 if (container && container->IsScenceBoardWindow()) {
1825 return false;
1826 }
1827
1828 auto host = GetHost();
1829 CHECK_NULL_RETURN(host, false);
1830 auto textFieldTheme = GetTheme();
1831 CHECK_NULL_RETURN(textFieldTheme, false);
1832 return textFieldTheme->GetTranslateIsSupport();
1833 }
1834
IsShowSearch()1835 bool TextFieldPattern::IsShowSearch()
1836 {
1837 auto container = Container::Current();
1838 if (container && container->IsScenceBoardWindow()) {
1839 return false;
1840 }
1841 auto host = GetHost();
1842 CHECK_NULL_RETURN(host, false);
1843 auto textFieldTheme = GetTheme();
1844 CHECK_NULL_RETURN(textFieldTheme, false);
1845 return textFieldTheme->GetIsSupportSearch();
1846 }
1847
HandleOnCameraInput()1848 void TextFieldPattern::HandleOnCameraInput()
1849 {
1850 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "TextFieldPattern::HandleOnCameraInput");
1851 #if defined(ENABLE_STANDARD_INPUT)
1852 if (textChangeListener_ == nullptr) {
1853 textChangeListener_ = new OnTextChangedListenerImpl(WeakClaim(this));
1854 }
1855 auto inputMethod = MiscServices::InputMethodController::GetInstance();
1856 if (!inputMethod) {
1857 TAG_LOGE(AceLogTag::ACE_TEXT_FIELD, "HandleOnCameraInput, inputMethod is null");
1858 return;
1859 }
1860 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
1861 if (imeShown_) {
1862 inputMethod->StartInputType(MiscServices::InputType::CAMERA_INPUT);
1863 } else {
1864 auto optionalTextConfig = GetMiscTextConfig();
1865 CHECK_NULL_VOID(optionalTextConfig.has_value());
1866 MiscServices::TextConfig textConfig = optionalTextConfig.value();
1867 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "HandleOnCameraInput set calling window id is : %{public}u",
1868 textConfig.windowId);
1869 #ifdef WINDOW_SCENE_SUPPORTED
1870 auto systemWindowId = GetSCBSystemWindowId();
1871 if (systemWindowId) {
1872 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "windowId From %{public}u to %{public}u.", textConfig.windowId,
1873 systemWindowId);
1874 textConfig.windowId = systemWindowId;
1875 }
1876 #endif
1877 auto ret = inputMethod->Attach(textChangeListener_, false, textConfig);
1878 if (ret == MiscServices::ErrorCode::NO_ERROR) {
1879 auto pipeline = GetContext();
1880 CHECK_NULL_VOID(pipeline);
1881 auto textFieldManager = AceType::DynamicCast<TextFieldManagerNG>(pipeline->GetTextFieldManager());
1882 CHECK_NULL_VOID(textFieldManager);
1883 textFieldManager->SetIsImeAttached(true);
1884 }
1885 inputMethod->StartInputType(MiscServices::InputType::CAMERA_INPUT);
1886 inputMethod->ShowTextInput();
1887 }
1888 CloseSelectOverlay(true);
1889 StartTwinkling();
1890 #endif
1891 #endif
1892 }
1893
StripNextLine(std::wstring & data)1894 void TextFieldPattern::StripNextLine(std::wstring& data)
1895 {
1896 CHECK_NULL_VOID(!(data.empty() || IsTextArea()));
1897 std::wstring result;
1898 bool dataChanged = false;
1899 int32_t dataPtr = 0;
1900 while (dataPtr < static_cast<int32_t>(data.length())) {
1901 if (data[dataPtr] != WIDE_NEWLINE[0]) {
1902 result += data[dataPtr];
1903 } else {
1904 dataChanged = true;
1905 }
1906 dataPtr++;
1907 }
1908 if (!dataChanged) {
1909 return;
1910 }
1911 data = result;
1912 }
1913
HandleOnCut()1914 void TextFieldPattern::HandleOnCut()
1915 {
1916 #if !defined(PREVIEW)
1917 CHECK_NULL_VOID(clipboard_);
1918 #endif
1919 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
1920 CHECK_NULL_VOID(layoutProperty);
1921
1922 if (layoutProperty->GetCopyOptionsValue(CopyOptions::Local) == CopyOptions::None) {
1923 return;
1924 }
1925 auto start = selectController_->GetStartIndex();
1926 auto end = selectController_->GetEndIndex();
1927 SwapIfLarger(start, end);
1928 if (!IsSelected() || IsInPasswordMode()) {
1929 return;
1930 }
1931 UpdateEditingValueToRecord();
1932 auto selectedText = contentController_->GetSelectedValue(start, end);
1933 if (layoutProperty->GetCopyOptionsValue(CopyOptions::Local) != CopyOptions::None) {
1934 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "Cut value size is %{private}zu",
1935 UtfUtils::Str16DebugToStr8(selectedText).size());
1936 clipboard_->SetData(UtfUtils::Str16DebugToStr8(selectedText),
1937 layoutProperty->GetCopyOptionsValue(CopyOptions::Local));
1938 }
1939 DeleteRange(start, end, false);
1940 auto host = GetHost();
1941 CHECK_NULL_VOID(host);
1942 auto eventHub = host->GetEventHub<TextFieldEventHub>();
1943 CHECK_NULL_VOID(eventHub);
1944 eventHub->FireOnCut(selectedText);
1945 host->MarkDirtyNode(layoutProperty->GetMaxLinesValue(Infinity<float>()) <= 1 ? PROPERTY_UPDATE_MEASURE_SELF
1946 : PROPERTY_UPDATE_MEASURE);
1947 }
1948
UpdateSelection(int32_t both)1949 void TextFieldPattern::UpdateSelection(int32_t both)
1950 {
1951 UpdateSelection(both, both);
1952 }
1953
UpdateSelection(int32_t start,int32_t end)1954 void TextFieldPattern::UpdateSelection(int32_t start, int32_t end)
1955 {
1956 auto startIndex = std::min(start, end);
1957 auto endIndex = std::max(start, end);
1958 startIndex = std::clamp(startIndex, 0, static_cast<int32_t>(contentController_->GetTextUtf16Value().length()));
1959 endIndex = std::clamp(endIndex, 0, static_cast<int32_t>(contentController_->GetTextUtf16Value().length()));
1960 if (startIndex != selectController_->GetStartIndex() || endIndex != selectController_->GetEndIndex()) {
1961 selectController_->UpdateHandleIndex(startIndex, endIndex);
1962 }
1963 }
1964
FireEventHubOnChange(const std::u16string & text)1965 void TextFieldPattern::FireEventHubOnChange(const std::u16string& text)
1966 {
1967 auto host = GetHost();
1968 CHECK_NULL_VOID(host);
1969 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
1970 CHECK_NULL_VOID(layoutProperty);
1971 if (!layoutProperty->GetNeedFireOnChangeValue(false)) {
1972 return;
1973 }
1974 auto textFieldTheme = GetTheme();
1975 CHECK_NULL_VOID(textFieldTheme);
1976 auto visible = layoutProperty->GetShowErrorTextValue(false);
1977 if (!visible && IsUnderlineMode()) {
1978 underlineColor_ = userUnderlineColor_.typing.value_or(textFieldTheme->GetUnderlineTypingColor());
1979 underlineWidth_ = TYPING_UNDERLINE_WIDTH;
1980 }
1981
1982 auto eventHub = host->GetEventHub<TextFieldEventHub>();
1983 CHECK_NULL_VOID(eventHub);
1984 ChangeValueInfo changeValueInfo;
1985 changeValueInfo.value = text;
1986 changeValueInfo.previewText.offset = hasPreviewText_ ? GetPreviewTextStart() : -1;
1987 changeValueInfo.previewText.value = GetPreviewTextValue();
1988 changeValueInfo.oldPreviewText = callbackOldPreviewText_;
1989 changeValueInfo.oldContent = callbackOldContent_;
1990 changeValueInfo.rangeBefore = callbackRangeBefore_;
1991 changeValueInfo.rangeAfter = callbackRangeAfter_;
1992 eventHub->FireOnChange(changeValueInfo);
1993 }
1994
HandleTouchEvent(const TouchEventInfo & info)1995 void TextFieldPattern::HandleTouchEvent(const TouchEventInfo& info)
1996 {
1997 CHECK_NULL_VOID(!IsDragging());
1998 CHECK_NULL_VOID(!info.GetTouches().empty());
1999 if (selectOverlay_->IsTouchAtHandle(info)) {
2000 return;
2001 }
2002 auto touchInfo = GetAcceptedTouchLocationInfo(info);
2003 CHECK_NULL_VOID(touchInfo);
2004 DoGestureSelection(info);
2005 ResetOriginCaretPosition();
2006 auto touchType = touchInfo->GetTouchType();
2007 if (touchType == TouchType::DOWN) {
2008 HandleTouchDown(touchInfo->GetLocalLocation());
2009 } else if (touchType == TouchType::UP) {
2010 OnCaretMoveDone(info);
2011 RequestKeyboardAfterLongPress();
2012 isLongPress_ = false;
2013 isMoveCaretAnywhere_ = false;
2014 HandleTouchUp();
2015 } else if (touchType == TouchType::MOVE) {
2016 if (isMoveCaretAnywhere_) {
2017 // edit + longpress + move, show caret anywhere on fonts.
2018 selectController_->MoveCaretAnywhere(info.GetTouches().front().GetLocalLocation());
2019 ShowCaretAndStopTwinkling();
2020 selectOverlay_->HideMenu();
2021 selectOverlay_->SetIsSingleHandle(false);
2022 return;
2023 }
2024 if (SelectOverlayIsOn() && !moveCaretState_.isTouchCaret) {
2025 return;
2026 }
2027 if (!IsUsingMouse() && HasFocus()) {
2028 HandleTouchMove(touchInfo.value());
2029 }
2030 } else if (touchType == TouchType::CANCEL) {
2031 StopContentScroll();
2032 if (magnifierController_ && magnifierController_->GetMagnifierNodeExist()) {
2033 magnifierController_->RemoveMagnifierFrameNode();
2034 }
2035 ResetTouchAndMoveCaretState();
2036 }
2037 }
2038
HandleTouchDown(const Offset & offset)2039 void TextFieldPattern::HandleTouchDown(const Offset& offset)
2040 {
2041 UpdatePressStyle(true);
2042 moveCaretState_.touchDownOffset = offset;
2043 if (HasStateStyle(UI_STATE_PRESSED)) {
2044 return;
2045 }
2046
2047 if (enableTouchAndHoverEffect_ && !isMousePressed_) {
2048 auto lastCaretRect = selectController_->GetCaretRect();
2049 moveCaretState_.isTouchCaret = HasFocus() && !IsSelected() && RepeatClickCaret(offset, lastCaretRect);
2050 isTouchPreviewText_ = GetTouchInnerPreviewText(offset);
2051 }
2052 }
2053
HandleTouchUp()2054 void TextFieldPattern::HandleTouchUp()
2055 {
2056 UpdatePressStyle(false);
2057 if (GetIsPreviewText() && isTouchPreviewText_) {
2058 StartTwinkling();
2059 }
2060 ResetTouchAndMoveCaretState();
2061 if (isMousePressed_) {
2062 isMousePressed_ = false;
2063 }
2064 if (magnifierController_) {
2065 magnifierController_->RemoveMagnifierFrameNode();
2066 }
2067 ScheduleDisappearDelayTask();
2068 }
2069
ResetTouchAndMoveCaretState()2070 void TextFieldPattern::ResetTouchAndMoveCaretState()
2071 {
2072 if (moveCaretState_.isTouchCaret) {
2073 moveCaretState_.isTouchCaret = false;
2074 CheckScrollable();
2075 UpdateScrollBarOffset();
2076 StartTwinkling();
2077 }
2078 if (moveCaretState_.isMoveCaret) {
2079 moveCaretState_.isMoveCaret = false;
2080 StopContentScroll();
2081 if (HasFocus()) {
2082 StartTwinkling();
2083 } else {
2084 StopTwinkling();
2085 }
2086 }
2087 FloatingCaretLand();
2088 }
2089
HandleTouchMove(const TouchLocationInfo & info)2090 void TextFieldPattern::HandleTouchMove(const TouchLocationInfo& info)
2091 {
2092 if (moveCaretState_.isTouchCaret && !moveCaretState_.isMoveCaret) {
2093 auto offset = info.GetLocalLocation();
2094 auto moveDistance = (offset - moveCaretState_.touchDownOffset).GetDistance();
2095 moveCaretState_.isMoveCaret = GreatNotEqual(moveDistance, moveCaretState_.minDinstance.ConvertToPx());
2096 if (moveCaretState_.isMoveCaret) {
2097 moveCaretState_.touchFingerId = info.GetFingerId();
2098 }
2099 }
2100 if (SelectOverlayIsOn() && moveCaretState_.isMoveCaret) {
2101 CloseSelectOverlay(false);
2102 }
2103 if (moveCaretState_.isMoveCaret || (GetIsPreviewText() && isTouchPreviewText_)) {
2104 ShowCaretAndStopTwinkling();
2105 UpdateCaretByTouchMove(info);
2106 }
2107 }
2108
StartVibratorByIndexChange(int32_t currentIndex,int32_t preIndex)2109 void TextFieldPattern::StartVibratorByIndexChange(int32_t currentIndex, int32_t preIndex)
2110 {
2111 CHECK_NULL_VOID(isEnableHapticFeedback_ && (currentIndex != preIndex));
2112 VibratorUtils::StartVibraFeedback("slide");
2113 }
2114
UpdateCaretByTouchMove(const TouchLocationInfo & info)2115 void TextFieldPattern::UpdateCaretByTouchMove(const TouchLocationInfo& info)
2116 {
2117 if (contentScroller_.isScrolling) {
2118 CheckScrollable();
2119 } else {
2120 scrollable_ = false;
2121 SetScrollEnabled(scrollable_);
2122 }
2123 // limit move when preview text is shown
2124 auto touchOffset = info.GetLocalLocation();
2125 if (GetIsPreviewText()) {
2126 TAG_LOGI(ACE_TEXT_FIELD, "UpdateCaretByTouchMove when has previewText");
2127 float offsetY = IsTextArea() ? GetTextRect().GetY() : contentRect_.GetY();
2128 std::vector<RectF> previewTextRects = GetPreviewTextRects();
2129 if (previewTextRects.empty()) {
2130 TAG_LOGI(ACE_TEXT_FIELD, "preview text rect error");
2131 return;
2132 }
2133
2134 double limitL;
2135 double limitR;
2136 double limitT = previewTextRects.front().Top() + offsetY + MINIMAL_OFFSET;
2137 double limitB = previewTextRects.back().Bottom() + offsetY - MINIMAL_OFFSET;
2138
2139 Offset previewTextTouchOffset;
2140 CalculatePreviewingTextMovingLimit(touchOffset, limitL, limitR);
2141
2142 previewTextTouchOffset.SetX(std::clamp(touchOffset.GetX(), limitL, limitR));
2143 previewTextTouchOffset.SetY(std::clamp(touchOffset.GetY(), limitT, limitB));
2144 selectController_->UpdateCaretInfoByOffset(previewTextTouchOffset, true, true);
2145 } else {
2146 if (HasText()) {
2147 UpdateContentScroller(touchOffset);
2148 }
2149 auto touchCaretX = std::clamp(
2150 touchOffset.GetX(), static_cast<double>(contentRect_.Left()), static_cast<double>(contentRect_.Right()));
2151 // 1/4 line height.
2152 auto yOffset = PreferredLineHeight() * 0.25f;
2153 auto touchCaretY = std::clamp(touchOffset.GetY(), static_cast<double>(contentRect_.Top()) + yOffset,
2154 static_cast<double>(contentRect_.Bottom()) - yOffset);
2155 selectController_->UpdateCaretInfoByOffset(
2156 !contentScroller_.isScrolling ? Offset(touchCaretX, touchCaretY) : touchOffset,
2157 !contentScroller_.isScrolling, true);
2158 if (magnifierController_ && HasText()) {
2159 SetMagnifierLocalOffsetToFloatingCaretPos();
2160 }
2161 }
2162
2163 UpdateCaretInfoToController();
2164 auto host = GetHost();
2165 CHECK_NULL_VOID(host);
2166 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2167 }
2168
SetMagnifierLocalOffsetToFloatingCaretPos()2169 void TextFieldPattern::SetMagnifierLocalOffsetToFloatingCaretPos()
2170 {
2171 auto floatCaretRectCenter = GetFloatingCaretRect().Center();
2172 if (floatCaretState_.lastFloatingCursorY.has_value() && !NearEqual(floatCaretState_.lastFloatingCursorY.value(),
2173 static_cast<float>(floatCaretRectCenter.GetY()))) {
2174 AnimationOption option = AnimationOption();
2175 option.SetCurve(MOVE_MAGNIFIER_CURVE);
2176 option.SetDuration(LAND_DURATION);
2177 AnimationUtils::Animate(option,
2178 [weak = WeakClaim(this), floatCaretRectCenter]() {
2179 auto pattern = weak.Upgrade();
2180 CHECK_NULL_VOID(pattern);
2181 pattern->GetMagnifierController()->SetLocalOffset({ floatCaretRectCenter.GetX(),
2182 floatCaretRectCenter.GetY() });
2183 });
2184 } else {
2185 magnifierController_->SetLocalOffset({ floatCaretRectCenter.GetX(), floatCaretRectCenter.GetY() });
2186 }
2187 floatCaretState_.lastFloatingCursorY = floatCaretRectCenter.GetY();
2188 }
2189
InitDragEvent()2190 void TextFieldPattern::InitDragEvent()
2191 {
2192 auto host = GetHost();
2193 CHECK_NULL_VOID(host);
2194 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
2195 CHECK_NULL_VOID(layoutProperty);
2196 if (!IsInPasswordMode() && layoutProperty->GetCopyOptionsValue(CopyOptions::Local) != CopyOptions::None &&
2197 host->IsDraggable()) {
2198 InitDragDropEvent();
2199 } else {
2200 ClearDragDropEvent();
2201 InitDragDropEventWithOutDragStart();
2202 }
2203 AddDragFrameNodeToManager(host);
2204 }
2205
GetThumbnailCallback()2206 std::function<void(Offset)> TextFieldPattern::GetThumbnailCallback()
2207 {
2208 auto callback = [weak = WeakClaim(this)](const Offset& point) {
2209 auto pattern = weak.Upgrade();
2210 CHECK_NULL_VOID(pattern);
2211 auto frameNode = pattern->GetHost();
2212 CHECK_NULL_VOID(frameNode);
2213 if (pattern->BetweenSelectedPosition(point)) {
2214 auto info = pattern->CreateTextDragInfo();
2215 pattern->dragNode_ = TextDragPattern::CreateDragNode(frameNode);
2216 auto textDragPattern = pattern->dragNode_->GetPattern<TextDragPattern>();
2217 if (textDragPattern) {
2218 textDragPattern->UpdateHandleAnimationInfo(info);
2219 auto option = pattern->GetHost()->GetDragPreviewOption();
2220 option.options.shadowPath = textDragPattern->GetBackgroundPath()->ConvertToSVGString();
2221 option.options.shadow = Shadow(RICH_DEFAULT_ELEVATION, {0.0, 0.0}, Color(RICH_DEFAULT_SHADOW_COLOR),
2222 ShadowStyle::OuterFloatingSM);
2223 pattern->GetHost()->SetDragPreviewOptions(option);
2224 }
2225 FrameNode::ProcessOffscreenNode(pattern->dragNode_);
2226 }
2227 auto gestureHub = frameNode->GetOrCreateGestureEventHub();
2228 CHECK_NULL_VOID(gestureHub);
2229 gestureHub->SetPixelMap(nullptr);
2230 };
2231 return callback;
2232 }
2233
CreateTextDragInfo() const2234 TextDragInfo TextFieldPattern::CreateTextDragInfo() const
2235 {
2236 TextDragInfo info;
2237 auto manager = selectOverlay_->GetManager<SelectContentOverlayManager>();
2238 CHECK_NULL_RETURN(manager, info);
2239 auto selectOverlayInfo = manager->GetSelectOverlayInfo();
2240 CHECK_NULL_RETURN(selectOverlayInfo, info);
2241 auto textFieldTheme = GetTheme();
2242 CHECK_NULL_RETURN(textFieldTheme, info);
2243 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
2244 CHECK_NULL_RETURN(paintProperty, info);
2245 auto handleColor = paintProperty->GetCursorColorValue(textFieldTheme->GetCursorColor());
2246 auto selectedBackgroundColor = textFieldTheme->GetSelectedColor();
2247 auto firstIndex = selectController_->GetFirstHandleIndex();
2248 auto secondIndex = selectController_->GetSecondHandleIndex();
2249 if (firstIndex > secondIndex) {
2250 info.secondHandle = selectOverlayInfo->firstHandle.paintRect;
2251 info.firstHandle = selectOverlayInfo->secondHandle.paintRect;
2252 } else {
2253 info.firstHandle = selectOverlayInfo->firstHandle.paintRect;
2254 info.secondHandle = selectOverlayInfo->secondHandle.paintRect;
2255 }
2256 auto firstIsShow = selectOverlayInfo->firstHandle.isShow;
2257 auto secondIsShow = selectOverlayInfo->secondHandle.isShow;
2258 if (!firstIsShow) {
2259 info.isFirstHandleAnimation = firstIsShow;
2260 }
2261 if (!secondIsShow) {
2262 info.isSecondHandleAnimation = secondIsShow;
2263 }
2264
2265 info.selectedBackgroundColor = selectedBackgroundColor;
2266 info.handleColor = handleColor;
2267 return info;
2268 }
2269
OnDragStart()2270 std::function<DragDropInfo(const RefPtr<OHOS::Ace::DragEvent>&, const std::string&)> TextFieldPattern::OnDragStart()
2271 {
2272 auto onDragStart = [weakPtr = WeakClaim(this)](const RefPtr<OHOS::Ace::DragEvent>& event,
2273 const std::string& extraParams) -> NG::DragDropInfo {
2274 NG::DragDropInfo itemInfo;
2275 auto pattern = weakPtr.Upgrade();
2276 CHECK_NULL_RETURN(pattern, itemInfo);
2277 auto host = pattern->GetHost();
2278 CHECK_NULL_RETURN(host, itemInfo);
2279 auto hub = host->GetEventHub<EventHub>();
2280 CHECK_NULL_RETURN(hub, itemInfo);
2281 auto gestureHub = hub->GetOrCreateGestureEventHub();
2282 CHECK_NULL_RETURN(gestureHub, itemInfo);
2283 pattern->sourceTool_ = event ? event->GetSourceTool() : SourceTool::UNKNOWN;
2284 if (!gestureHub->GetIsTextDraggable()) {
2285 return itemInfo;
2286 }
2287 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD,
2288 "%{public}d TextField OnDragStart, dragStatus_ is %{public}d, dragRecipientStatus_ is %{public}d",
2289 host->GetId(), static_cast<int32_t>(pattern->dragStatus_),
2290 static_cast<int32_t>(pattern->dragRecipientStatus_));
2291 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
2292 CHECK_NULL_RETURN(layoutProperty, itemInfo);
2293 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
2294 pattern->CloseHandleAndSelect();
2295 pattern->CloseKeyboard(true);
2296 #endif
2297 pattern->SetDragMovingScrollback();
2298 pattern->dragStatus_ = DragStatus::DRAGGING;
2299 auto pipeline = pattern->GetContext();
2300 CHECK_NULL_RETURN(pipeline, itemInfo);
2301 auto dragManager = pipeline->GetDragDropManager();
2302 CHECK_NULL_RETURN(dragManager, itemInfo);
2303 if (!pattern->IsNormalInlineState() && dragManager->IsDropAllowed(host)) {
2304 pattern->dragRecipientStatus_ = DragStatus::DRAGGING;
2305 }
2306 auto selectedStr = pattern->GetDragStyledText();
2307 itemInfo.extraInfo = selectedStr;
2308 RefPtr<UnifiedData> unifiedData = UdmfClient::GetInstance()->CreateUnifiedData();
2309 UdmfClient::GetInstance()->AddPlainTextRecord(unifiedData, selectedStr);
2310 event->SetData(unifiedData);
2311 host->MarkDirtyNode(layoutProperty->GetMaxLinesValue(Infinity<float>()) <= 1 ? PROPERTY_UPDATE_MEASURE_SELF
2312 : PROPERTY_UPDATE_MEASURE);
2313 return itemInfo;
2314 };
2315 return onDragStart;
2316 }
2317
GetDragStyledText()2318 std::string TextFieldPattern::GetDragStyledText()
2319 {
2320 showSelect_ = false;
2321 selectionMode_ = SelectionMode::SELECT;
2322 textFieldContentModifier_->ChangeDragStatus();
2323 auto start = selectController_->GetStartIndex();
2324 auto end = selectController_->GetEndIndex();
2325 GetEmojiSubStringRange(start, end);
2326 dragTextStart_ = start;
2327 dragTextEnd_ = end;
2328 std::u16string beforeStr = contentController_->GetValueBeforeIndex(start);
2329 std::u16string selectedStr = contentController_->GetSelectedValue(start, end);
2330 dragValue_ = selectedStr;
2331 std::u16string afterStr = contentController_->GetValueAfterIndex(end);
2332 dragContents_ = { beforeStr, selectedStr, afterStr };
2333 return UtfUtils::Str16DebugToStr8(selectedStr);
2334 }
2335
OnDragDrop()2336 std::function<void(const RefPtr<OHOS::Ace::DragEvent>&, const std::string&)> TextFieldPattern::OnDragDrop()
2337 {
2338 return [weakPtr = WeakClaim(this)](const RefPtr<OHOS::Ace::DragEvent>& event, const std::string& extraParams) {
2339 auto pattern = weakPtr.Upgrade();
2340 CHECK_NULL_VOID(pattern);
2341 pattern->StopContentScroll();
2342 pattern->sourceTool_ = event ? event->GetSourceTool() : SourceTool::UNKNOWN;
2343 auto host = pattern->GetHost();
2344 CHECK_NULL_VOID(host);
2345 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
2346 CHECK_NULL_VOID(layoutProperty);
2347
2348 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD,
2349 "%{public}d TextField OnDragDrop, dragStatus_ is %{public}d, dragRecipientStatus_ is %{public}d",
2350 host->GetId(), static_cast<int32_t>(pattern->dragStatus_),
2351 static_cast<int32_t>(pattern->dragRecipientStatus_));
2352 if (layoutProperty->GetIsDisabledValue(false) || pattern->IsNormalInlineState() || !pattern->HasFocus()) {
2353 event->SetResult(DragRet::DRAG_FAIL);
2354 return;
2355 }
2356 if (extraParams.empty()) {
2357 pattern->dragStatus_ = DragStatus::ON_DROP;
2358 pattern->textFieldContentModifier_->ChangeDragStatus();
2359 host->MarkDirtyNode(layoutProperty->GetMaxLinesValue(Infinity<float>()) <= 1 ? PROPERTY_UPDATE_MEASURE_SELF
2360 : PROPERTY_UPDATE_MEASURE);
2361 event->SetResult(DragRet::DRAG_FAIL);
2362 return;
2363 }
2364 bool isCopy = false;
2365 if (pattern->dragStatus_ == DragStatus::DRAGGING) {
2366 CHECK_NULL_VOID(event);
2367 auto gesturePressedCodes = event->GetPressedKeyCodes();
2368 if ((gesturePressedCodes.size() == 1) && ((gesturePressedCodes[0] == KeyCode::KEY_CTRL_LEFT) ||
2369 (gesturePressedCodes[0] == KeyCode::KEY_CTRL_RIGHT))) {
2370 isCopy = true;
2371 }
2372 }
2373 auto data = event->GetData();
2374 CHECK_NULL_VOID(data);
2375 std::u16string str;
2376 auto arr = UdmfClient::GetInstance()->GetSpanStringEntry(data);
2377 if (arr.size() > 0) {
2378 auto spanStr = SpanString::DecodeTlv(arr);
2379 str += spanStr->GetU16string();
2380 } else {
2381 auto plainText = UdmfClient::GetInstance()->GetPlainTextEntry(data);
2382 if (plainText.empty()) {
2383 std::string linkUrl;
2384 std::string linkTitle;
2385 UdmfClient::GetInstance()->GetLinkEntry(data, linkUrl, linkTitle);
2386 if (!linkTitle.empty()) {
2387 str += UtfUtils::Str8DebugToStr16(linkTitle);
2388 } else if (!linkUrl.empty()) {
2389 str += UtfUtils::Str8DebugToStr16(linkUrl);
2390 }
2391 }
2392 str += UtfUtils::Str8DebugToStr16(plainText);
2393 }
2394 pattern->dragRecipientStatus_ = DragStatus::NONE;
2395 if (str.empty()) {
2396 return;
2397 }
2398 if ((pattern->dragStatus_ == DragStatus::NONE) || isCopy) {
2399 pattern->AddInsertCommand(str, InputReason::DRAG);
2400 } else {
2401 InputCommandInfo inputCommandInfo;
2402 inputCommandInfo.deleteRange = { pattern->dragTextStart_, pattern->dragTextEnd_ };
2403 inputCommandInfo.insertOffset = pattern->selectController_->GetCaretIndex();
2404 inputCommandInfo.insertValue = str;
2405 inputCommandInfo.reason = InputReason::DRAG;
2406 pattern->AddInputCommand(inputCommandInfo);
2407 pattern->dragStatus_ = DragStatus::NONE;
2408 pattern->MarkContentChange();
2409 host->MarkDirtyNode(pattern->IsTextArea() ? PROPERTY_UPDATE_MEASURE : PROPERTY_UPDATE_MEASURE_SELF);
2410 }
2411 pattern->afterDragSelect_ = isMouseOrTouchPad(pattern->sourceTool_);
2412 pattern->releaseInDrop_ = true;
2413 FocusHub::LostFocusToViewRoot();
2414 };
2415 }
2416
ShowSelectAfterDragEvent()2417 void TextFieldPattern::ShowSelectAfterDragEvent()
2418 {
2419 selectController_->UpdateHandleIndex(dragTextStart_, dragTextEnd_);
2420 showSelect_ = true;
2421 if (!IsUsingMouse()) {
2422 DelayProcessOverlay({ .menuIsShow = false });
2423 }
2424 }
2425
InitDragDropEventWithOutDragStart()2426 void TextFieldPattern::InitDragDropEventWithOutDragStart()
2427 {
2428 auto host = GetHost();
2429 CHECK_NULL_VOID(host);
2430 auto gestureHub = host->GetOrCreateGestureEventHub();
2431 CHECK_NULL_VOID(gestureHub);
2432 gestureHub->InitDragDropEvent();
2433 auto eventHub = host->GetEventHub<EventHub>();
2434 CHECK_NULL_VOID(eventHub);
2435 InitDragDropCallBack();
2436 }
2437
InitDragDropEvent()2438 void TextFieldPattern::InitDragDropEvent()
2439 {
2440 auto host = GetHost();
2441 CHECK_NULL_VOID(host);
2442 auto gestureHub = host->GetOrCreateGestureEventHub();
2443 CHECK_NULL_VOID(gestureHub);
2444 gestureHub->InitDragDropEvent();
2445 auto callback = GetThumbnailCallback();
2446 gestureHub->SetThumbnailCallback(std::move(callback));
2447 auto eventHub = host->GetEventHub<EventHub>();
2448 CHECK_NULL_VOID(eventHub);
2449 eventHub->SetDefaultOnDragStart(OnDragStart());
2450 InitDragDropCallBack();
2451 gestureHub->SetTextDraggable(true);
2452 }
2453
InitDragDropCallBack()2454 void TextFieldPattern::InitDragDropCallBack()
2455 {
2456 auto host = GetHost();
2457 CHECK_NULL_VOID(host);
2458 auto eventHub = host->GetEventHub<EventHub>();
2459 CHECK_NULL_VOID(eventHub);
2460 auto onDragEnter = [weakPtr = WeakClaim(this)](
2461 const RefPtr<OHOS::Ace::DragEvent>& event, const std::string& extraParams) {
2462 auto pattern = weakPtr.Upgrade();
2463 CHECK_NULL_VOID(pattern);
2464 auto host = pattern->GetHost();
2465 CHECK_NULL_VOID(host);
2466 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD,
2467 "%{public}d TextField onDragEnter, dragStatus_ is %{public}d, dragRecipientStatus_ is %{public}d",
2468 host->GetId(), static_cast<int32_t>(pattern->dragStatus_),
2469 static_cast<int32_t>(pattern->dragRecipientStatus_));
2470
2471 auto pipeline = pattern->GetContext();
2472 CHECK_NULL_VOID(pipeline);
2473 auto dragManager = pipeline->GetDragDropManager();
2474 CHECK_NULL_VOID(dragManager);
2475 if (pattern->IsNormalInlineState() || !dragManager->IsDropAllowed(host)) {
2476 return;
2477 }
2478 pattern->SetDragMovingScrollback();
2479 pattern->dragRecipientStatus_ = DragStatus::DRAGGING;
2480 pattern->ResetPreviewTextState();
2481 auto focusHub = pattern->GetFocusHub();
2482 CHECK_NULL_VOID(focusHub);
2483 if (pattern->TextFieldRequestFocus(RequestFocusReason::DRAG_ENTER)) {
2484 pattern->StartTwinkling();
2485 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD,
2486 "%{public}d TextField onDragEnter Request Focus Success", host->GetId());
2487 }
2488 };
2489 eventHub->SetOnDragEnter(std::move(onDragEnter));
2490
2491 auto onDragMove = [weakPtr = WeakClaim(this)](
2492 const RefPtr<OHOS::Ace::DragEvent>& event, const std::string& extraParams) {
2493 auto pattern = weakPtr.Upgrade();
2494 CHECK_NULL_VOID(pattern);
2495 auto pipeline = pattern->GetContext();
2496 CHECK_NULL_VOID(pipeline);
2497 auto dragManager = pipeline->GetDragDropManager();
2498 CHECK_NULL_VOID(dragManager);
2499 auto host = pattern->GetHost();
2500 CHECK_NULL_VOID(host);
2501
2502 if (pattern->IsNormalInlineState() || !dragManager->IsDropAllowed(host)) {
2503 return;
2504 }
2505 if (!pattern->HasFocus()) {
2506 auto focusHub = pattern->GetFocusHub();
2507 CHECK_NULL_VOID(focusHub);
2508 if (pattern->TextFieldRequestFocus(RequestFocusReason::DRAG_MOVE)) {
2509 pattern->StartTwinkling();
2510 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD,
2511 "%{public}d TextField onDragMove Request Focus Success", host->GetId());
2512 }
2513 }
2514 auto textPaintOffset = pattern->GetPaintRectGlobalOffset();
2515 Offset localOffset =
2516 Offset(event->GetX(), event->GetY()) - Offset(textPaintOffset.GetX(), textPaintOffset.GetY());
2517 if (host->GetDragPreviewOption().enableEdgeAutoScroll) {
2518 pattern->UpdateContentScroller(localOffset);
2519 } else {
2520 pattern->contentScroller_.OnBeforeScrollingCallback(localOffset);
2521 pattern->PauseContentScroll();
2522 pattern->contentScroller_.hotAreaOffset.reset();
2523 }
2524 };
2525 eventHub->SetOnDragMove(std::move(onDragMove));
2526
2527 auto onDragLeave = [weakPtr = WeakClaim(this)](
2528 const RefPtr<OHOS::Ace::DragEvent>& event, const std::string& extraParams) {
2529 auto pattern = weakPtr.Upgrade();
2530 CHECK_NULL_VOID(pattern);
2531 auto host = pattern->GetHost();
2532 CHECK_NULL_VOID(host);
2533 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD,
2534 "%{public}d TextField onDragLeave, dragStatus_ is %{public}d, dragRecipientStatus_ is %{public}d",
2535 host->GetId(), static_cast<int32_t>(pattern->dragStatus_),
2536 static_cast<int32_t>(pattern->dragRecipientStatus_));
2537 pattern->dragRecipientStatus_ = DragStatus::NONE;
2538 auto focusHub = pattern->GetFocusHub();
2539 CHECK_NULL_VOID(focusHub);
2540 focusHub->LostFocus();
2541 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD,
2542 "%{public}d TextField onDragLeave Lost Focus", host->GetId());
2543 pattern->StopTwinkling();
2544 pattern->PauseContentScroll();
2545 };
2546 eventHub->SetOnDragLeave(std::move(onDragLeave));
2547
2548 auto onDragEnd = [weakPtr = WeakClaim(this)](const RefPtr<OHOS::Ace::DragEvent>& event) {
2549 auto pattern = weakPtr.Upgrade();
2550 CHECK_NULL_VOID(pattern);
2551 auto host = pattern->GetHost();
2552 CHECK_NULL_VOID(host);
2553 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD,
2554 "%{public}d TextField onDragEnd, dragStatus_ is %{public}d, dragRecipientStatus_ is %{public}d",
2555 host->GetId(), static_cast<int32_t>(pattern->dragStatus_),
2556 static_cast<int32_t>(pattern->dragRecipientStatus_));
2557 pattern->StopContentScroll();
2558 ContainerScope scope(pattern->GetHostInstanceId());
2559 if (pattern->dragStatus_ == DragStatus::DRAGGING && !pattern->isDetachFromMainTree_) {
2560 pattern->dragStatus_ = DragStatus::NONE;
2561 pattern->MarkContentChange();
2562 // Except for DRAG_SUCCESS, all of rest need to show
2563 auto paintProperty = pattern->GetPaintProperty<TextFieldPaintProperty>();
2564 CHECK_NULL_VOID(paintProperty);
2565 auto newDragValue =
2566 pattern->contentController_->GetSelectedValue(pattern->dragTextStart_, pattern->dragTextEnd_);
2567 auto focusHub = pattern->GetFocusHub();
2568 CHECK_NULL_VOID(focusHub);
2569 if (event != nullptr && event->GetResult() != DragRet::DRAG_SUCCESS &&
2570 newDragValue == pattern->dragValue_ &&
2571 paintProperty->GetInputStyleValue(InputStyle::DEFAULT) != InputStyle::INLINE &&
2572 focusHub->IsFocusable()) {
2573 pattern->ShowSelectAfterDragEvent();
2574 pattern->afterDragSelect_ = true;
2575 pattern->TextFieldRequestFocus(RequestFocusReason::DRAG_END);
2576 }
2577 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
2578 }
2579 if (event != nullptr && event->GetResult() != DragRet::DRAG_SUCCESS) {
2580 pattern->afterDragSelect_ = true;
2581 }
2582 pattern->CloseKeyboard(true);
2583 };
2584 eventHub->SetOnDragEnd(std::move(onDragEnd));
2585
2586 eventHub->SetOnDrop(OnDragDrop());
2587 }
2588
ClearDragDropEvent()2589 void TextFieldPattern::ClearDragDropEvent()
2590 {
2591 auto host = GetHost();
2592 CHECK_NULL_VOID(host);
2593 auto gestureHub = host->GetOrCreateGestureEventHub();
2594 CHECK_NULL_VOID(gestureHub);
2595 gestureHub->SetTextDraggable(false);
2596 gestureHub->SetIsTextDraggable(false);
2597 auto eventHub = host->GetEventHub<EventHub>();
2598 CHECK_NULL_VOID(eventHub);
2599 eventHub->SetOnDragStart(nullptr);
2600 eventHub->SetDefaultOnDragStart(nullptr);
2601 eventHub->SetOnDragEnter(nullptr);
2602 eventHub->SetOnDragMove(nullptr);
2603 eventHub->SetOnDragLeave(nullptr);
2604 eventHub->SetOnDragEnd(nullptr);
2605 eventHub->SetOnDrop(nullptr);
2606 }
2607
HandleOnDragStatusCallback(const DragEventType & dragEventType,const RefPtr<NotifyDragEvent> & notifyDragEvent)2608 void TextFieldPattern::HandleOnDragStatusCallback(
2609 const DragEventType& dragEventType, const RefPtr<NotifyDragEvent>& notifyDragEvent)
2610 {
2611 ScrollablePattern::HandleOnDragStatusCallback(dragEventType, notifyDragEvent);
2612 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "HandleOnDragStatusCallback dragEventType=%{public}d", dragEventType);
2613 if (dragEventType == DragEventType::DROP && dragRecipientStatus_ == DragStatus::DRAGGING) {
2614 StopContentScroll();
2615 StopTwinkling();
2616 }
2617 }
2618
InitTouchEvent()2619 void TextFieldPattern::InitTouchEvent()
2620 {
2621 CHECK_NULL_VOID(!touchListener_);
2622 auto host = GetHost();
2623 CHECK_NULL_VOID(host);
2624
2625 auto gesture = host->GetOrCreateGestureEventHub();
2626 CHECK_NULL_VOID(gesture);
2627 auto touchTask = [weak = WeakClaim(this)](const TouchEventInfo& info) {
2628 auto pattern = weak.Upgrade();
2629 CHECK_NULL_VOID(pattern);
2630 pattern->selectOverlay_->SetUsingMouse(info.GetSourceDevice() == SourceType::MOUSE);
2631 pattern->selectOverlay_->SetLastSourceType(info.GetSourceDevice());
2632 pattern->HandleTouchEvent(info);
2633 };
2634 touchListener_ = MakeRefPtr<TouchEventImpl>(std::move(touchTask));
2635 gesture->AddTouchEvent(touchListener_);
2636 }
2637
IsHandleDragging()2638 bool TextFieldPattern::IsHandleDragging()
2639 {
2640 CHECK_NULL_RETURN(selectOverlay_, false);
2641 return selectOverlay_->GetIsHandleDragging();
2642 }
2643
InitClickEvent()2644 void TextFieldPattern::InitClickEvent()
2645 {
2646 CHECK_NULL_VOID(!clickListener_);
2647 auto tmpHost = GetHost();
2648 CHECK_NULL_VOID(tmpHost);
2649 auto gesture = tmpHost->GetOrCreateGestureEventHub();
2650 auto clickCallback = [weak = WeakClaim(this)](GestureEvent& info) {
2651 auto pattern = weak.Upgrade();
2652 CHECK_NULL_VOID(pattern);
2653 pattern->HandleClickEvent(info);
2654 };
2655
2656 clickListener_ = MakeRefPtr<ClickEvent>(std::move(clickCallback));
2657 gesture->AddClickEvent(clickListener_);
2658 }
2659
HandleClickEvent(GestureEvent & info)2660 void TextFieldPattern::HandleClickEvent(GestureEvent& info)
2661 {
2662 CHECK_NULL_VOID(!IsDragging());
2663 CHECK_NULL_VOID(!IsHandleDragging());
2664 parentGlobalOffset_ = GetPaintRectGlobalOffset();
2665 auto focusHub = GetFocusHub();
2666 CHECK_NULL_VOID(focusHub);
2667 CHECK_NULL_VOID(selectOverlay_);
2668 CHECK_NULL_VOID(multipleClickRecognizer_);
2669 if ((selectOverlay_->IsClickAtHandle(info) && !multipleClickRecognizer_->IsValidClick(info)) ||
2670 !focusHub->IsFocusable()) {
2671 return;
2672 }
2673 focusIndex_ = FocuseIndex::TEXT;
2674 auto firstGetFocus = false;
2675 if (!HasFocus()) {
2676 auto host = GetHost();
2677 CHECK_NULL_VOID(host);
2678 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "textfield %{public}d request focus currently", host->GetId());
2679 firstGetFocus = true;
2680 if (!focusHub->IsFocusOnTouch().value_or(true) || !TextFieldRequestFocus(RequestFocusReason::CLICK)) {
2681 CloseSelectOverlay(true);
2682 StopTwinkling();
2683 return;
2684 }
2685 }
2686 firstGetFocus = firstGetFocus || firstClickAfterLosingFocus_;
2687 firstClickAfterLosingFocus_ = false;
2688 if (!firstGetFocus && CheckMousePressedOverScrollBar(info)) {
2689 return;
2690 }
2691 selectOverlay_->SetLastSourceType(info.GetSourceDevice());
2692 selectOverlay_->SetUsingMouse(info.GetSourceDevice() == SourceType::MOUSE);
2693 lastClickTimeStamp_ = info.GetTimeStamp();
2694 multipleClickRecognizer_->StartCounting(info);
2695 // register click event
2696 if (multipleClickRecognizer_->IsTripleClick()) {
2697 HandleTripleClickEvent(info);
2698 } else if (multipleClickRecognizer_->IsDoubleClick()) {
2699 HandleDoubleClickEvent(info);
2700 } else {
2701 HandleSingleClickEvent(info, firstGetFocus);
2702 }
2703 if (ResetObscureTickCountDown()) {
2704 auto host = GetHost();
2705 CHECK_NULL_VOID(host);
2706 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
2707 }
2708 isFocusedBeforeClick_ = false;
2709 }
2710
CheckMousePressedOverScrollBar(GestureEvent & info)2711 bool TextFieldPattern::CheckMousePressedOverScrollBar(GestureEvent& info)
2712 {
2713 if (IsMouseOverScrollBar(&info) && hasMousePressed_) {
2714 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
2715 CHECK_NULL_RETURN(layoutProperty, false);
2716 if (layoutProperty->GetDisplayModeValue(DisplayMode::AUTO) != DisplayMode::OFF) {
2717 auto touchRegion = GetScrollBar()->GetTouchRegion();
2718 bool reverse = info.GetLocalLocation().GetY() < touchRegion.Top();
2719 ScrollPage(reverse);
2720 return true;
2721 }
2722 }
2723 return false;
2724 }
2725
HandleBetweenSelectedPosition(const GestureEvent & info)2726 bool TextFieldPattern::HandleBetweenSelectedPosition(const GestureEvent& info)
2727 {
2728 if (!IsUsingMouse() && SelectOverlayIsOn() && BetweenSelectedPosition(info.GetGlobalLocation())) {
2729 CHECK_NULL_RETURN(selectOverlay_, false);
2730 // click selected area to switch show/hide state
2731 selectOverlay_->ToggleMenu();
2732 return true;
2733 }
2734 return false;
2735 }
2736
HandleSingleClickEvent(GestureEvent & info,bool firstGetFocus)2737 void TextFieldPattern::HandleSingleClickEvent(GestureEvent& info, bool firstGetFocus)
2738 {
2739 if (mouseStatus_ != MouseStatus::NONE && IsNormalInlineState()) {
2740 return;
2741 }
2742 if (HandleBetweenSelectedPosition(info)) {
2743 selectOverlay_->SwitchToOverlayMode();
2744 return;
2745 }
2746 auto host = GetHost();
2747 CHECK_NULL_VOID(host);
2748 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
2749 auto lastCaretIndex = selectController_->GetCaretIndex();
2750 if (mouseStatus_ != MouseStatus::MOVE) {
2751 UpdateCaretByClick(info.GetLocalLocation());
2752 }
2753 StartTwinkling();
2754 SetIsSingleHandle(true);
2755 bool needCloseOverlay = true;
2756 bool isRepeatClickCaret =
2757 RepeatClickCaret(info.GetLocalLocation(), lastCaretIndex) && !firstGetFocus;
2758 bool isInlineSelectAllOrEmpty = inlineSelectAllFlag_ || contentController_->IsEmpty();
2759 auto clickBlank = contentController_->IsEmpty() || selectController_->IsTouchAtLineEnd(info.GetLocalLocation());
2760 auto closeHandleAtBlank =
2761 clickBlank && isRepeatClickCaret && SelectOverlayIsOn() && selectOverlay_->IsSingleHandle();
2762 do {
2763 if (info.GetSourceDevice() == SourceType::MOUSE || (!isRepeatClickCaret && isInlineSelectAllOrEmpty) ||
2764 IsContentRectNonPositive() || closeHandleAtBlank) {
2765 break;
2766 }
2767 if (isRepeatClickCaret) {
2768 if (IsAccessibilityClick()) {
2769 break;
2770 }
2771 ProcessOverlay({ .animation = true });
2772 needCloseOverlay = false;
2773 } else if (needSelectAll_) {
2774 HandleOnSelectAll(false);
2775 }
2776 } while (false);
2777 if (needCloseOverlay || GetIsPreviewText()) {
2778 CloseSelectOverlay(true);
2779 StartTwinkling();
2780 }
2781 DoProcessAutoFill(info.GetSourceDevice());
2782 // emulate clicking bottom of the textField
2783 UpdateTextFieldManager(Offset(parentGlobalOffset_.GetX(), parentGlobalOffset_.GetY()), frameRect_.Height());
2784 TriggerAvoidOnCaretChange();
2785 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2786 }
2787
DoProcessAutoFill(SourceType sourceType)2788 void TextFieldPattern::DoProcessAutoFill(SourceType sourceType)
2789 {
2790 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "DoProcessAutoFill");
2791 if (!IsNeedProcessAutoFill()) {
2792 if (RequestKeyboardNotByFocusSwitch(RequestKeyboardReason::SINGLE_CLICK, sourceType)) {
2793 NotifyOnEditChanged(true);
2794 }
2795 return;
2796 }
2797 bool isPopup = false;
2798 auto isSuccess = ProcessAutoFill(isPopup);
2799 if (!isPopup && isSuccess) {
2800 SetNeedToRequestKeyboardInner(false, RequestKeyboardInnerChangeReason::AUTOFILL_PROCESS);
2801 } else if (RequestKeyboardNotByFocusSwitch(RequestKeyboardReason::SINGLE_CLICK, sourceType)) {
2802 NotifyOnEditChanged(true);
2803 }
2804 }
2805
IsAutoFillPasswordType(const AceAutoFillType & autoFillType)2806 bool TextFieldPattern::IsAutoFillPasswordType(const AceAutoFillType& autoFillType)
2807 {
2808 return (autoFillType == AceAutoFillType::ACE_USER_NAME || autoFillType == AceAutoFillType::ACE_PASSWORD ||
2809 autoFillType == AceAutoFillType::ACE_NEW_PASSWORD);
2810 }
2811
GetHintType()2812 HintToTypeWrap TextFieldPattern::GetHintType()
2813 {
2814 HintToTypeWrap hintToTypeWrap;
2815 auto container = Container::Current();
2816 CHECK_NULL_RETURN(container, hintToTypeWrap);
2817 auto onePlaceHolder = UtfUtils::Str16DebugToStr8(GetPlaceHolder());
2818 if (onePlaceHolder.empty()) {
2819 return hintToTypeWrap;
2820 }
2821 return container->PlaceHolderToType(onePlaceHolder);
2822 }
2823
CheckAutoFillType(const AceAutoFillType & autoFillType,bool isFromKeyBoard)2824 bool TextFieldPattern::CheckAutoFillType(const AceAutoFillType& autoFillType, bool isFromKeyBoard)
2825 {
2826 if (isFromKeyBoard) {
2827 return true;
2828 }
2829
2830 auto container = Container::Current();
2831 CHECK_NULL_RETURN(container, false);
2832 auto isTriggerPassword = IsTriggerAutoFillPassword();
2833 if (autoFillType == AceAutoFillType::ACE_UNSPECIFIED && !isTriggerPassword) {
2834 TAG_LOGI(AceLogTag::ACE_AUTO_FILL, "CheckAutoFillType :autoFillType is ACE_UNSPECIFIED.");
2835 return false;
2836 } else if (isTriggerPassword) {
2837 auto tempAutoFillType = IsAutoFillUserName(autoFillType) ? AceAutoFillType::ACE_USER_NAME : autoFillType;
2838 if (!container->IsNeedToCreatePopupWindow(tempAutoFillType)) {
2839 return GetAutoFillTriggeredStateByType(autoFillType);
2840 }
2841 }
2842 return true;
2843 }
2844
GetAutoFillTriggeredStateByType(const AceAutoFillType & autoFillType)2845 bool TextFieldPattern::GetAutoFillTriggeredStateByType(const AceAutoFillType& autoFillType)
2846 {
2847 auto host = GetHost();
2848 CHECK_NULL_RETURN(host, false);
2849 auto autoFillContainerNode = firstAutoFillContainerNode_.Upgrade();
2850 CHECK_NULL_RETURN(autoFillContainerNode, false);
2851 auto stateHolder = autoFillContainerNode->GetPattern<AutoFillTriggerStateHolder>();
2852 CHECK_NULL_RETURN(stateHolder, false);
2853 if (IsAutoFillUserName(autoFillType) || autoFillType == AceAutoFillType::ACE_PASSWORD) {
2854 return !stateHolder->IsAutoFillPasswordTriggered();
2855 }
2856 if (autoFillType == AceAutoFillType::ACE_NEW_PASSWORD) {
2857 return !stateHolder->IsAutoFillNewPasswordTriggered();
2858 }
2859 return false;
2860 }
2861
SetAutoFillTriggeredStateByType(const AceAutoFillType & autoFillType)2862 void TextFieldPattern::SetAutoFillTriggeredStateByType(const AceAutoFillType& autoFillType)
2863 {
2864 auto host = GetHost();
2865 CHECK_NULL_VOID(host);
2866 auto autoFillContainerNode = firstAutoFillContainerNode_.Upgrade();
2867 CHECK_NULL_VOID(autoFillContainerNode);
2868 auto stateHolder = autoFillContainerNode->GetPattern<AutoFillTriggerStateHolder>();
2869 CHECK_NULL_VOID(stateHolder);
2870 if (IsAutoFillUserName(autoFillType) || autoFillType == AceAutoFillType::ACE_PASSWORD) {
2871 stateHolder->SetAutoFillPasswordTriggered(true);
2872 } else if (autoFillType == AceAutoFillType::ACE_NEW_PASSWORD) {
2873 stateHolder->SetAutoFillNewPasswordTriggered(true);
2874 }
2875 }
2876
GetAutoFillType(bool isNeedToHitType)2877 AceAutoFillType TextFieldPattern::GetAutoFillType(bool isNeedToHitType)
2878 {
2879 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
2880 CHECK_NULL_RETURN(layoutProperty, AceAutoFillType::ACE_UNSPECIFIED);
2881 auto aceContentType =
2882 TextContentTypeToAceAutoFillType(layoutProperty->GetTextContentTypeValue(TextContentType::UNSPECIFIED));
2883 auto aceInputType = ConvertToAceAutoFillType(layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED));
2884 if (aceContentType != AceAutoFillType::ACE_UNSPECIFIED) {
2885 return aceContentType;
2886 }
2887 if (aceInputType != AceAutoFillType::ACE_UNSPECIFIED) {
2888 return aceInputType;
2889 }
2890 if (isNeedToHitType && !IsTriggerAutoFillPassword()) {
2891 auto hintToTypeWrap = GetHintType();
2892 return hintToTypeWrap.autoFillType;
2893 }
2894 return AceAutoFillType::ACE_UNSPECIFIED;
2895 }
2896
GetAutoFillTypeAndMetaData(bool isNeedToHitType)2897 HintToTypeWrap TextFieldPattern::GetAutoFillTypeAndMetaData(bool isNeedToHitType)
2898 {
2899 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
2900 HintToTypeWrap hintToTypeWrap;
2901 CHECK_NULL_RETURN(layoutProperty, hintToTypeWrap);
2902 auto aceContentType =
2903 TextContentTypeToAceAutoFillType(layoutProperty->GetTextContentTypeValue(TextContentType::UNSPECIFIED));
2904 auto aceInputType = ConvertToAceAutoFillType(layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED));
2905 if (aceContentType != AceAutoFillType::ACE_UNSPECIFIED) {
2906 hintToTypeWrap.autoFillType = aceContentType;
2907 return hintToTypeWrap;
2908 }
2909 if (aceInputType != AceAutoFillType::ACE_UNSPECIFIED) {
2910 hintToTypeWrap.autoFillType = aceInputType;
2911 return hintToTypeWrap;
2912 }
2913 if (isNeedToHitType && !IsTriggerAutoFillPassword()) {
2914 hintToTypeWrap = GetHintType();
2915 return hintToTypeWrap;
2916 }
2917 auto jsonValue = JsonUtil::Create(true);
2918 jsonValue->Put("type", TextInputTypeToString().c_str());
2919 hintToTypeWrap.metadata = jsonValue->ToString();
2920 return hintToTypeWrap;
2921 }
2922
CheckAutoFill(bool isFromKeyBoard)2923 bool TextFieldPattern::CheckAutoFill(bool isFromKeyBoard)
2924 {
2925 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
2926 CHECK_NULL_RETURN(layoutProperty, false);
2927 bool isEnableAutoFill = layoutProperty->GetEnableAutoFillValue(true);
2928 if (!isEnableAutoFill) {
2929 return false;
2930 }
2931 return CheckAutoFillType(GetAutoFillType(), isFromKeyBoard);
2932 }
2933
ProcessAutoFill(bool & isPopup,bool isFromKeyBoard,bool isNewPassWord)2934 bool TextFieldPattern::ProcessAutoFill(bool& isPopup, bool isFromKeyBoard, bool isNewPassWord)
2935 {
2936 if (!CheckAutoFill(isFromKeyBoard)) {
2937 TAG_LOGI(AceLogTag::ACE_AUTO_FILL, "don't need to auto fill.");
2938 return false;
2939 }
2940 auto host = GetHost();
2941 CHECK_NULL_RETURN(host, false);
2942 auto autoFillType = GetAutoFillType();
2943 auto container = Container::Current();
2944 if (container == nullptr) {
2945 TAG_LOGW(AceLogTag::ACE_AUTO_FILL, "Get current container is nullptr.");
2946 return false;
2947 }
2948 if (IsTriggerAutoFillPassword() && autoFillType == AceAutoFillType::ACE_UNSPECIFIED) {
2949 autoFillType = AceAutoFillType::ACE_USER_NAME;
2950 }
2951 auto onUIExtNodeDestroy = [weak = WeakPtr<FrameNode>(host)]() {
2952 TAG_LOGI(AceLogTag::ACE_AUTO_FILL, "onUIExtNodeDestroy called.");
2953 auto textFieldNode = weak.Upgrade();
2954 CHECK_NULL_VOID(textFieldNode);
2955 auto pageNode = textFieldNode->GetPageNode();
2956 CHECK_NULL_VOID(pageNode);
2957 auto pagePattern = pageNode->GetPattern<PagePattern>();
2958 CHECK_NULL_VOID(pagePattern);
2959 pagePattern->SetIsModalCovered(false);
2960 };
2961 auto onUIExtNodeBindingCompleted = [weak = WeakPtr<FrameNode>(host)]() {
2962 TAG_LOGI(AceLogTag::ACE_AUTO_FILL, "onUIExtNodeBindingCompleted called.");
2963 auto textFieldNode = weak.Upgrade();
2964 CHECK_NULL_VOID(textFieldNode);
2965 auto pageNode = textFieldNode->GetPageNode();
2966 CHECK_NULL_VOID(pageNode);
2967 auto pagePattern = pageNode->GetPattern<PagePattern>();
2968 CHECK_NULL_VOID(pagePattern);
2969 pagePattern->SetIsModalCovered(true);
2970 };
2971
2972 auto resultCode = container->RequestAutoFill(host, autoFillType, isNewPassWord, isPopup, autoFillSessionId_, true,
2973 onUIExtNodeDestroy, onUIExtNodeBindingCompleted);
2974 if (resultCode != AceAutoFillError::ACE_AUTO_FILL_PREVIOUS_REQUEST_NOT_FINISHED) {
2975 SetAutoFillTriggeredStateByType(autoFillType);
2976 SetFillRequestFinish(false);
2977 }
2978 return resultCode == AceAutoFillError::ACE_AUTO_FILL_SUCCESS;
2979 }
2980
HandleDoubleClickEvent(GestureEvent & info)2981 void TextFieldPattern::HandleDoubleClickEvent(GestureEvent& info)
2982 {
2983 if (GetIsPreviewText()) {
2984 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "refuse double click when has preview text.");
2985 return;
2986 }
2987
2988 if (showSelect_) {
2989 SetIsSingleHandle(true);
2990 }
2991 if (RequestKeyboardNotByFocusSwitch(RequestKeyboardReason::DOUBLE_CLICK)) {
2992 NotifyOnEditChanged(true);
2993 }
2994 if (CanChangeSelectState()) {
2995 selectController_->UpdateSelectByOffset(info.GetLocalLocation());
2996 UpdateCaretInfoToController();
2997 }
2998 if (IsSelected()) {
2999 StopTwinkling();
3000 SetIsSingleHandle(false);
3001 }
3002 if (info.GetSourceDevice() != SourceType::MOUSE && !IsContentRectNonPositive()) {
3003 ProcessOverlay({ .animation = true });
3004 }
3005 auto host = GetHost();
3006 CHECK_NULL_VOID(host);
3007 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
3008 }
3009
HandleTripleClickEvent(GestureEvent & info)3010 void TextFieldPattern::HandleTripleClickEvent(GestureEvent& info)
3011 {
3012 if (GetIsPreviewText()) {
3013 return;
3014 }
3015
3016 if (showSelect_) {
3017 SetIsSingleHandle(true);
3018 CloseSelectOverlay();
3019 }
3020 if (CanChangeSelectState()) {
3021 selectController_->UpdateSelectPragraphByOffset(info.GetLocalLocation());
3022 }
3023 if (IsSelected()) {
3024 StopTwinkling();
3025 SetIsSingleHandle(false);
3026 } else {
3027 StartTwinkling();
3028 }
3029 if (info.GetSourceDevice() != SourceType::MOUSE && !contentController_->IsEmpty() && !IsContentRectNonPositive()) {
3030 ProcessOverlay({ .animation = true });
3031 }
3032 auto host = GetHost();
3033 CHECK_NULL_VOID(host);
3034 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
3035 }
3036
ScheduleCursorTwinkling()3037 void TextFieldPattern::ScheduleCursorTwinkling()
3038 {
3039 if (isTransparent_) {
3040 return;
3041 }
3042 auto host = GetHost();
3043 CHECK_NULL_VOID(host);
3044 auto context = host->GetContext();
3045 CHECK_NULL_VOID(context);
3046
3047 if (!context->GetTaskExecutor()) {
3048 return;
3049 }
3050
3051 if (dragRecipientStatus_ == DragStatus::DRAGGING) {
3052 return;
3053 }
3054
3055 auto weak = WeakClaim(this);
3056 cursorTwinklingTask_.Reset([weak] {
3057 auto client = weak.Upgrade();
3058 CHECK_NULL_VOID(client);
3059 client->OnCursorTwinkling();
3060 });
3061 auto taskExecutor = context->GetTaskExecutor();
3062 CHECK_NULL_VOID(taskExecutor);
3063 taskExecutor->PostDelayedTask(cursorTwinklingTask_, TaskExecutor::TaskType::UI, twinklingInterval_,
3064 "ArkUITextFieldCursorTwinkling");
3065 }
3066
StartTwinkling()3067 void TextFieldPattern::StartTwinkling()
3068 {
3069 if (isTransparent_ || !HasFocus() || focusIndex_ == FocuseIndex::CANCEL || focusIndex_ == FocuseIndex::UNIT) {
3070 return;
3071 }
3072 // Ignore the result because all ops are called on this same thread (ACE UI).
3073 // The only reason failed is that the task has finished.
3074 cursorTwinklingTask_.Cancel();
3075
3076 // Show cursor right now.
3077 isCaretTwinkling_ = true;
3078 cursorVisible_ = true;
3079 auto tmpHost = GetHost();
3080 CHECK_NULL_VOID(tmpHost);
3081 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
3082 ScheduleCursorTwinkling();
3083 }
3084
OnCursorTwinkling()3085 void TextFieldPattern::OnCursorTwinkling()
3086 {
3087 cursorTwinklingTask_.Cancel();
3088 cursorVisible_ = !cursorVisible_;
3089 auto shouldMeasure = !IsTextArea() && IsInPasswordMode() && GetTextObscured() && obscureTickCountDown_ == 1;
3090 if (IsInPasswordMode() && GetTextObscured() && obscureTickCountDown_ > 0) {
3091 --obscureTickCountDown_;
3092 }
3093 auto host = GetHost();
3094 CHECK_NULL_VOID(host);
3095 if (shouldMeasure) {
3096 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
3097 } else {
3098 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
3099 }
3100 ScheduleCursorTwinkling();
3101 }
3102
StopTwinkling()3103 void TextFieldPattern::StopTwinkling()
3104 {
3105 cursorTwinklingTask_.Cancel();
3106
3107 // Repaint only if cursor is visible for now.
3108 isCaretTwinkling_ = false;
3109 auto tmpHost = GetHost();
3110 CHECK_NULL_VOID(tmpHost);
3111 if (cursorVisible_) {
3112 cursorVisible_ = false;
3113 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
3114 }
3115 if (ResetObscureTickCountDown()) {
3116 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
3117 }
3118 }
3119
ShowCaretAndStopTwinkling()3120 void TextFieldPattern::ShowCaretAndStopTwinkling()
3121 {
3122 cursorTwinklingTask_.Cancel();
3123
3124 // Repaint and make cursor visible.
3125 isCaretTwinkling_ = false;
3126 auto tmpHost = GetHost();
3127 CHECK_NULL_VOID(tmpHost);
3128 cursorVisible_ = true;
3129 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
3130 if (ResetObscureTickCountDown()) {
3131 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
3132 }
3133 }
3134
CheckIfNeedToResetKeyboard()3135 void TextFieldPattern::CheckIfNeedToResetKeyboard()
3136 {
3137 auto tmpHost = GetHost();
3138 CHECK_NULL_VOID(tmpHost);
3139 auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
3140 CHECK_NULL_VOID(layoutProperty);
3141 bool needToResetKeyboard = false;
3142 // check unspecified for first time entrance
3143 if (keyboard_ != layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED)) {
3144 auto autoFillType = GetAutoFillType(false);
3145 if (layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED) != TextInputType::UNSPECIFIED ||
3146 keyBoardMap_.find(autoFillType) == keyBoardMap_.end() || keyboard_ != keyBoardMap_[autoFillType]) {
3147 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "textfield %{public}d Keyboard type %{public}d changed to %{public}d",
3148 tmpHost->GetId(), (int)keyboard_, layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED));
3149 keyboard_ = layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED);
3150 ResetPreviewTextState();
3151 needToResetKeyboard = true;
3152 }
3153 }
3154 if (!needToResetKeyboard && action_ != TextInputAction::UNSPECIFIED) {
3155 needToResetKeyboard = action_ != GetTextInputActionValue(GetDefaultTextInputAction());
3156 }
3157 action_ = GetTextInputActionValue(GetDefaultTextInputAction());
3158 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
3159 if (needToResetKeyboard && HasFocus()) {
3160 if (isCustomKeyboardAttached_) {
3161 RequestKeyboardNotByFocusSwitch(RequestKeyboardReason::RESET_KEYBOARD);
3162 return;
3163 }
3164 #if defined(ENABLE_STANDARD_INPUT)
3165 auto inputMethod = MiscServices::InputMethodController::GetInstance();
3166 CHECK_NULL_VOID(inputMethod);
3167 MiscServices::Configuration config;
3168 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "textfield %{public}d Keyboard action is %{public}d",
3169 tmpHost->GetId(), action_);
3170 config.SetEnterKeyType(static_cast<MiscServices::EnterKeyType>(action_));
3171 config.SetTextInputType(static_cast<MiscServices::TextInputType>(keyboard_));
3172 inputMethod->OnConfigurationChange(config);
3173 #endif
3174 }
3175 #else
3176 if (needToResetKeyboard && HasConnection()) {
3177 CloseKeyboard(true);
3178 RequestKeyboard(false, true, true);
3179 }
3180 #endif
3181 }
3182
ProcessScroll()3183 void TextFieldPattern::ProcessScroll()
3184 {
3185 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
3186 CHECK_NULL_VOID(layoutProperty);
3187 if (IsTextArea() || IsNormalInlineState()) {
3188 SetAxis(Axis::VERTICAL);
3189 if (!GetScrollableEvent()) {
3190 AddScrollEvent();
3191 }
3192 auto barState = layoutProperty->GetDisplayModeValue(DisplayMode::AUTO);
3193 if (!barState_.has_value()) {
3194 barState_ = barState;
3195 }
3196 scrollBarVisible_ = barState != DisplayMode::OFF;
3197 SetScrollBar(barState == DisplayMode::OFF ? DisplayMode::ON : barState);
3198 auto scrollBar = GetScrollBar();
3199 if (scrollBar) {
3200 scrollBar->SetMinHeight(SCROLL_BAR_MIN_HEIGHT);
3201 }
3202 if (textFieldOverlayModifier_) {
3203 textFieldOverlayModifier_->SetScrollBar(scrollBar);
3204 UpdateScrollBarOffset();
3205 }
3206 } else {
3207 SetAxis(Axis::HORIZONTAL);
3208 SetScrollBar(DisplayMode::OFF);
3209 if (!GetScrollableEvent()) {
3210 AddScrollEvent();
3211 SetScrollEnabled(false);
3212 }
3213 }
3214 }
3215
HandleDeleteOnCounterScene()3216 void TextFieldPattern::HandleDeleteOnCounterScene()
3217 {
3218 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
3219 CHECK_NULL_VOID(layoutProperty);
3220 if (layoutProperty->HasMaxLength()) {
3221 showCountBorderStyle_ = false;
3222 HandleCountStyle();
3223 }
3224 }
3225
HandleCountStyle()3226 void TextFieldPattern::HandleCountStyle()
3227 {
3228 bool noDeleteOperation = deleteBackwardOperations_.empty() && deleteForwardOperations_.empty();
3229 if (!IsShowCount() || !noDeleteOperation) {
3230 return;
3231 }
3232 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
3233 CHECK_NULL_VOID(layoutProperty);
3234 auto inputValue = layoutProperty->GetSetCounterValue(DEFAULT_MODE);
3235 auto showBorder = layoutProperty->GetShowHighlightBorderValue(true);
3236 if (inputValue == DEFAULT_MODE) {
3237 if (showBorder) {
3238 HandleCounterBorder();
3239 }
3240 if (showCountBorderStyle_ && !showBorder) {
3241 UltralimitShake();
3242 }
3243 } else if (inputValue != ILLEGAL_VALUE) {
3244 if (showBorder) {
3245 HandleCounterBorder();
3246 }
3247 if (showCountBorderStyle_) {
3248 UltralimitShake();
3249 }
3250 }
3251 }
3252
ProcessUnderlineColorOnModifierDone()3253 void TextFieldPattern::ProcessUnderlineColorOnModifierDone()
3254 {
3255 if (IsShowError()) {
3256 return;
3257 }
3258 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
3259 auto inputValue = layoutProperty->GetSetCounterValue(DEFAULT_MODE);
3260 if (inputValue == ILLEGAL_VALUE) {
3261 return;
3262 }
3263 auto showBorder = layoutProperty->GetShowHighlightBorderValue(true);
3264 if (inputValue != DEFAULT_MODE && !showBorder) {
3265 return;
3266 }
3267 if (showCountBorderStyle_ && IsUnderlineMode() && HasFocus()) {
3268 auto theme = GetTheme();
3269 CHECK_NULL_VOID(theme);
3270 SetUnderlineColor(
3271 userUnderlineColor_.error.value_or(theme->GetErrorUnderlineColor()));
3272 }
3273 }
3274
ProcessCounter()3275 void TextFieldPattern::ProcessCounter()
3276 {
3277 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
3278 CHECK_NULL_VOID(layoutProperty);
3279 if (IsShowCount()) {
3280 AddCounterNode();
3281 CHECK_NULL_VOID(counterDecorator_);
3282 counterDecorator_->UpdateTextFieldMargin();
3283 } else {
3284 CleanCounterNode();
3285 }
3286 }
3287
ProcessSelection()3288 void TextFieldPattern::ProcessSelection()
3289 {
3290 auto textWidth = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
3291 if (SelectOverlayIsOn()) {
3292 needToRefreshSelectOverlay_ = textWidth > 0;
3293 UpdateSelection(std::clamp(selectController_->GetStartIndex(), 0, textWidth),
3294 std::clamp(selectController_->GetEndIndex(), 0, textWidth));
3295 SetIsSingleHandle(!IsSelected());
3296 selectOverlay_->UpdateHandleColor();
3297 if (isTextChangedAtCreation_ && textWidth == 0) {
3298 CloseSelectOverlay();
3299 StartTwinkling();
3300 }
3301 if (!isTextChangedAtCreation_ && selectOverlay_->IsShowMouseMenu()) {
3302 needToRefreshSelectOverlay_ = false;
3303 }
3304 return;
3305 }
3306 if (HasFocus()) {
3307 if (IsGestureSelectingText()) {
3308 UpdateSelection(std::clamp(selectController_->GetStartIndex(), 0, textWidth),
3309 std::clamp(selectController_->GetEndIndex(), 0, textWidth));
3310 }
3311 if (!IsSelected()) {
3312 StartTwinkling();
3313 }
3314 return;
3315 }
3316 needToRefreshSelectOverlay_ = false;
3317 }
3318
OnModifyDone()3319 void TextFieldPattern::OnModifyDone()
3320 {
3321 Pattern::OnModifyDone();
3322 auto host = GetHost();
3323 CHECK_NULL_VOID(host);
3324 auto context = host->GetContext();
3325 CHECK_NULL_VOID(context);
3326 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
3327 CHECK_NULL_VOID(layoutProperty);
3328 auto textFieldTheme = GetTheme();
3329 CHECK_NULL_VOID(textFieldTheme);
3330 directionKeysMoveFocusOut_ = textFieldTheme->GetDirectionKeysMoveFocusOut();
3331 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
3332 CHECK_NULL_VOID(paintProperty);
3333 CheckIfNeedToResetKeyboard();
3334 auto renderContext = host->GetRenderContext();
3335 CHECK_NULL_VOID(renderContext);
3336 auto textFieldPaintProperty = host->GetPaintPropertyPtr<TextFieldPaintProperty>();
3337 if (textFieldPaintProperty && textFieldPaintProperty->HasBorderColorFlagByUser()) {
3338 textFieldPaintProperty->UpdateBorderColorFlagByUser(
3339 renderContext->GetBorderColorValue(BorderColorProperty {}));
3340 }
3341 isTransparent_ = renderContext->GetOpacityValue(1.0f) == 0.0f;
3342 ApplyNormalTheme();
3343 ApplyUnderlineTheme();
3344 ApplyInlineTheme();
3345 ProcessInnerPadding();
3346 ProcessNumberOfLines();
3347
3348 InitClickEvent();
3349 InitLongPressEvent();
3350 InitFocusEvent();
3351 InitMouseEvent();
3352 InitTouchEvent();
3353
3354 SetAccessibilityAction();
3355 FilterInitializeText();
3356 InitDisableColor();
3357 ProcessResponseArea();
3358 if (!shiftFlag_) {
3359 InitDragEvent();
3360 }
3361 Register2DragDropManager();
3362 ProcessUnderlineColorOnModifierDone();
3363 if (!clipboard_ && context) {
3364 clipboard_ = ClipboardProxy::GetInstance()->GetClipboard(context->GetTaskExecutor());
3365 }
3366 if (barState_.has_value() && barState_.value() != layoutProperty->GetDisplayModeValue(DisplayMode::AUTO) &&
3367 HasFocus() && IsNormalInlineState()) {
3368 lastTextRectY_ = textRect_.GetY();
3369 }
3370 if (!IsDisabled() && IsShowError()) {
3371 SetShowError();
3372 } else {
3373 CleanErrorNode();
3374 }
3375 // The textRect position can't be changed by only redraw.
3376 if (!initTextRect_) {
3377 auto border = GetBorderWidthProperty();
3378 textRect_.SetLeft(GetPaddingLeft() + GetBorderLeft(border));
3379 textRect_.SetTop(GetPaddingTop() + GetBorderTop(border));
3380 AdjustTextRectByCleanNode(textRect_);
3381 initTextRect_ = true;
3382 }
3383 CalculateDefaultCursor();
3384
3385 ProcessSelection();
3386 isTextChangedAtCreation_ = false;
3387 if (layoutProperty->GetTypeChangedValue(false)) {
3388 layoutProperty->ResetTypeChanged();
3389 operationRecords_.clear();
3390 redoOperationRecords_.clear();
3391 }
3392 ProcessScroll();
3393 ProcessCounter();
3394 Register2DragDropManager();
3395 auto autoFillContainerNode = firstAutoFillContainerNode_.Upgrade();
3396 if (autoFillContainerNode) {
3397 UpdateTextFieldInfo();
3398 }
3399 TriggerAvoidWhenCaretGoesDown();
3400 selectOverlay_->SetMenuTranslateIsSupport(IsShowTranslate());
3401 selectOverlay_->SetIsSupportMenuSearch(IsShowSearch());
3402 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
3403 SetIsEnableSubWindowMenu();
3404 isModifyDone_ = true;
3405 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
3406 InitCancelButtonMouseEvent();
3407 InitPasswordButtonMouseEvent();
3408 }
3409 }
3410
TriggerAvoidWhenCaretGoesDown()3411 void TextFieldPattern::TriggerAvoidWhenCaretGoesDown()
3412 {
3413 auto host = GetHost();
3414 CHECK_NULL_VOID(host);
3415 auto context = host->GetContext();
3416 CHECK_NULL_VOID(context);
3417 auto textFieldManager = DynamicCast<TextFieldManagerNG>(context->GetTextFieldManager());
3418 if (context->UsingCaretAvoidMode() && HasFocus() && textFieldManager) {
3419 context->AddAfterLayoutTask([weak = WeakClaim(this), manager = WeakPtr<TextFieldManagerNG>(textFieldManager)] {
3420 auto textField = weak.Upgrade();
3421 CHECK_NULL_VOID(textField);
3422 auto textFieldManager = manager.Upgrade();
3423 CHECK_NULL_VOID(textFieldManager);
3424 auto caretPos = textFieldManager->GetFocusedNodeCaretRect().Top() + textFieldManager->GetHeight();
3425 auto lastCaretPos = textField->GetLastCaretPos();
3426 if (!lastCaretPos.has_value() || caretPos > lastCaretPos.value()) {
3427 TAG_LOGI(ACE_KEYBOARD, "Caret Position Goes Down, Retrigger Avoid");
3428 textField->TriggerAvoidOnCaretChange();
3429 }
3430 });
3431 }
3432 }
3433
ApplyNormalTheme()3434 void TextFieldPattern::ApplyNormalTheme()
3435 {
3436 if (IsUnderlineMode() || IsInlineMode()) {
3437 return;
3438 }
3439 SetThemeAttr();
3440 }
3441
OnAfterModifyDone()3442 void TextFieldPattern::OnAfterModifyDone()
3443 {
3444 auto host = GetHost();
3445 CHECK_NULL_VOID(host);
3446 auto inspectorId = host->GetInspectorId().value_or("");
3447 if (!inspectorId.empty()) {
3448 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
3449 bool isPwdType = false;
3450 if (layoutProperty) {
3451 auto inputType = layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED);
3452 isPwdType = inputType == TextInputType::VISIBLE_PASSWORD || inputType == TextInputType::NUMBER_PASSWORD ||
3453 inputType == TextInputType::SCREEN_LOCK_PASSWORD || inputType == TextInputType::NEW_PASSWORD;
3454 }
3455 if (!isPwdType) {
3456 Recorder::NodeDataCache::Get().PutString(host, inspectorId, contentController_->GetTextValue());
3457 }
3458 }
3459 }
3460
CalculateDefaultCursor()3461 void TextFieldPattern::CalculateDefaultCursor()
3462 {
3463 auto tmpHost = GetHost();
3464 CHECK_NULL_VOID(tmpHost);
3465 auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
3466 CHECK_NULL_VOID(layoutProperty);
3467 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
3468 CHECK_NULL_VOID(paintProperty);
3469 auto textFieldTheme = GetTheme();
3470 CHECK_NULL_VOID(textFieldTheme);
3471 float caretWidth = paintProperty->GetCursorWidth().has_value()
3472 ? static_cast<float>(paintProperty->GetCursorWidthValue().ConvertToPx())
3473 : static_cast<float>(textFieldTheme->GetCursorWidth().ConvertToPx());
3474 selectController_->UpdateCaretWidth(caretWidth);
3475 if (!contentController_->IsEmpty()) {
3476 return;
3477 }
3478 selectController_->UpdateCaretHeight(PreferredLineHeight());
3479 }
3480
AutoFillValueChanged()3481 void TextFieldPattern::AutoFillValueChanged()
3482 {
3483 if (IsFillRequestFinish()) {
3484 return;
3485 }
3486 auto host = GetHost();
3487 CHECK_NULL_VOID(host);
3488 auto aceContentType = GetAutoFillType();
3489 auto container = Container::Current();
3490 CHECK_NULL_VOID(container);
3491 auto isValidType =
3492 (aceContentType >= AceAutoFillType::ACE_PASSWORD &&
3493 aceContentType <= AceAutoFillType::END) || IsAutoFillUserName(aceContentType);
3494 if (isValidType && CheckAutoFill()) {
3495 container->UpdatePopupUIExtension(host, autoFillSessionId_);
3496 }
3497 }
3498
FireOnTextChangeEvent()3499 bool TextFieldPattern::FireOnTextChangeEvent()
3500 {
3501 auto host = GetHost();
3502 CHECK_NULL_RETURN(host, false);
3503 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
3504 CHECK_NULL_RETURN(layoutProperty, false);
3505 auto textCache = layoutProperty->GetValueValue(u"");
3506 auto previewTextCache = layoutProperty->GetPreviewTextValue({GetPreviewTextStart(), u""});
3507 PreviewText curPreviewText = {GetPreviewTextStart(), GetPreviewTextValue()};
3508 if (textCache == contentController_->GetTextUtf16Value() && previewTextCache.value == curPreviewText.value) {
3509 return false;
3510 }
3511 ResetOriginCaretPosition();
3512 AutoFillValueChanged();
3513 auto pipeline = GetContext();
3514 CHECK_NULL_RETURN(pipeline, false);
3515 AddTextFireOnChange();
3516 auto context = host->GetContextRefPtr();
3517 CHECK_NULL_RETURN(context, false);
3518 auto taskExecutor = context->GetTaskExecutor();
3519 CHECK_NULL_RETURN(taskExecutor, false);
3520 taskExecutor->PostTask(
3521 [weak = WeakClaim(this)] {
3522 auto pattern = weak.Upgrade();
3523 CHECK_NULL_VOID(pattern);
3524 if (!pattern->HasFocus()) {
3525 return;
3526 }
3527 pattern->ScrollToSafeArea();
3528 pattern->TriggerAvoidOnCaretChange();
3529 if (pattern->customKeyboard_ || pattern->customKeyboardBuilder_) {
3530 pattern->StartTwinkling();
3531 }
3532 },
3533 TaskExecutor::TaskType::UI, "ArkUITextFieldScrollToSafeArea", PriorityType::VIP);
3534 return true;
3535 }
3536
AddTextFireOnChange()3537 void TextFieldPattern::AddTextFireOnChange()
3538 {
3539 auto host = GetHost();
3540 CHECK_NULL_VOID(host);
3541 auto context = host->GetContextRefPtr();
3542 CHECK_NULL_VOID(context);
3543 context->AddAfterLayoutTask([weak = AceType::WeakClaim(this)] {
3544 auto pattern = weak.Upgrade();
3545 CHECK_NULL_VOID(pattern);
3546 auto host = pattern->GetHost();
3547 CHECK_NULL_VOID(host);
3548 auto eventHub = host->GetEventHub<TextFieldEventHub>();
3549 CHECK_NULL_VOID(eventHub);
3550 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
3551 CHECK_NULL_VOID(layoutProperty);
3552 auto textCache = layoutProperty->GetValueValue(u"");
3553 auto newText = pattern->GetTextContentController()->GetTextUtf16Value();
3554 layoutProperty->UpdateValue(newText);
3555 host->OnAccessibilityEvent(AccessibilityEventType::TEXT_CHANGE, UtfUtils::Str16DebugToStr8(textCache),
3556 UtfUtils::Str16DebugToStr8(newText));
3557 ChangeValueInfo changeValueInfo;
3558 changeValueInfo.value = pattern->GetBodyTextValue();
3559 changeValueInfo.previewText.offset = pattern->hasPreviewText_ ? pattern->GetPreviewTextStart() : -1;
3560 changeValueInfo.previewText.value = pattern->GetPreviewTextValue();
3561 changeValueInfo.oldPreviewText = pattern->callbackOldPreviewText_;
3562 changeValueInfo.oldContent = pattern->callbackOldContent_;
3563 changeValueInfo.rangeBefore = pattern->callbackRangeBefore_;
3564 changeValueInfo.rangeAfter = pattern->callbackRangeAfter_;
3565 layoutProperty->UpdatePreviewText(changeValueInfo.previewText);
3566 eventHub->FireOnChange(changeValueInfo);
3567
3568 pattern->RecordTextInputEvent();
3569 });
3570 }
3571
RecordTextInputEvent()3572 void TextFieldPattern::RecordTextInputEvent()
3573 {
3574 if (!Recorder::EventRecorder::Get().IsRecordEnable(Recorder::EventCategory::CATEGORY_TEXT_INPUT)) {
3575 return;
3576 }
3577 auto host = GetHost();
3578 CHECK_NULL_VOID(host);
3579 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
3580 CHECK_NULL_VOID(layoutProperty);
3581 auto inputType = layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED);
3582 auto isPwdType = inputType == TextInputType::VISIBLE_PASSWORD || inputType == TextInputType::NUMBER_PASSWORD ||
3583 inputType == TextInputType::SCREEN_LOCK_PASSWORD || inputType == TextInputType::NEW_PASSWORD;
3584 if (isPwdType) {
3585 return;
3586 }
3587 Recorder::EventParamsBuilder builder;
3588 builder.SetEventCategory(Recorder::EventCategory::CATEGORY_TEXT_INPUT)
3589 .SetEventType(Recorder::EventType::TEXT_INPUT)
3590 .SetId(host->GetInspectorId().value_or(""))
3591 .SetType(host->GetTag())
3592 .SetText(UtfUtils::Str16DebugToStr8(GetBodyTextValue()))
3593 .SetDescription(host->GetAutoEventParamValue(""))
3594 .SetHost(host);
3595 Recorder::EventRecorder::Get().OnEvent(std::move(builder));
3596 }
3597
FilterInitializeText()3598 void TextFieldPattern::FilterInitializeText()
3599 {
3600 if (HasInputOperation()) {
3601 return;
3602 }
3603 if (HasFocus()) {
3604 UpdateShowCountBorderStyle();
3605 if (showCountBorderStyle_) {
3606 HandleCountStyle();
3607 }
3608 }
3609 if (!contentController_->IsEmpty()) {
3610 auto originCaretIndex =
3611 TextRange { selectController_->GetFirstHandleIndex(), selectController_->GetSecondHandleIndex() };
3612 ChangeValueInfo changeValueInfo;
3613 changeValueInfo.oldContent = GetBodyTextValue();
3614 changeValueInfo.oldPreviewText.offset = hasPreviewText_ ? GetPreviewTextStart() : -1;
3615 changeValueInfo.oldPreviewText.value = GetPreviewTextValue();
3616 changeValueInfo.rangeBefore = TextRange { 0, changeValueInfo.oldContent.length() };
3617 auto textChanged = contentController_->FilterValue();
3618 changeValueInfo.value = GetBodyTextValue();
3619 changeValueInfo.previewText.offset = hasPreviewText_ ? GetPreviewTextStart() : -1;
3620 changeValueInfo.previewText.value = GetPreviewTextValue();
3621 changeValueInfo.rangeAfter = TextRange { 0, changeValueInfo.value.length() };
3622 if (isFilterChanged_) {
3623 bool isWillChange = FireOnWillChange(changeValueInfo);
3624 isFilterChanged_ = false;
3625 if (!isWillChange) {
3626 RecoverTextValueAndCaret(changeValueInfo.oldContent, originCaretIndex);
3627 return;
3628 }
3629 }
3630 if (!isTextChangedAtCreation_) {
3631 isTextChangedAtCreation_ = textChanged;
3632 }
3633 }
3634 if (static_cast<int32_t>(GetTextUtf16Value().length()) < GetCaretIndex()) {
3635 selectController_->UpdateCaretIndex(static_cast<int32_t>(GetTextUtf16Value().length()));
3636 }
3637 UpdateShowCountBorderStyle();
3638 }
3639
IsDisabled()3640 bool TextFieldPattern::IsDisabled()
3641 {
3642 auto tmpHost = GetHost();
3643 CHECK_NULL_RETURN(tmpHost, true);
3644 auto eventHub = tmpHost->GetEventHub<TextFieldEventHub>();
3645 CHECK_NULL_RETURN(eventHub, true);
3646 auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
3647 CHECK_NULL_RETURN(layoutProperty, true);
3648 return !eventHub->IsEnabled();
3649 }
3650
ProcessInnerPadding()3651 void TextFieldPattern::ProcessInnerPadding()
3652 {
3653 auto textFieldTheme = GetTheme();
3654 CHECK_NULL_VOID(textFieldTheme);
3655 auto themePadding = IsUnderlineMode() ? textFieldTheme->GetUnderlinePadding() : textFieldTheme->GetPadding();
3656 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
3657 CHECK_NULL_VOID(layoutProperty);
3658 PaddingPropertyF utilPadding;
3659 const auto& paddingProperty = layoutProperty->GetPaddingProperty();
3660 auto left = !paddingProperty ? CalcLength(themePadding.Left()).GetDimension()
3661 : paddingProperty->left.value_or(CalcLength(themePadding.Left())).GetDimension();
3662 utilPadding.left = left.ConvertToPx();
3663 auto top = !paddingProperty ? CalcLength(themePadding.Top()).GetDimension()
3664 : paddingProperty->top.value_or(CalcLength(themePadding.Top())).GetDimension();
3665 utilPadding.top = top.ConvertToPx();
3666 auto bottom = !paddingProperty ? CalcLength(themePadding.Bottom()).GetDimension()
3667 : paddingProperty->bottom.value_or(CalcLength(themePadding.Bottom())).GetDimension();
3668 utilPadding.bottom = bottom.ConvertToPx();
3669 auto right = !paddingProperty ? CalcLength(themePadding.Right()).GetDimension()
3670 : paddingProperty->right.value_or(CalcLength(themePadding.Right())).GetDimension();
3671 utilPadding.right = right.ConvertToPx();
3672 utilPadding_ = utilPadding;
3673 PaddingProperty paddings;
3674 paddings.top = NG::CalcLength(top);
3675 paddings.bottom = NG::CalcLength(bottom);
3676 paddings.left = NG::CalcLength(left);
3677 paddings.right = NG::CalcLength(right);
3678 layoutProperty->UpdatePadding(paddings);
3679 }
3680
ProcessNumberOfLines()3681 void TextFieldPattern::ProcessNumberOfLines()
3682 {
3683 auto tmpHost = GetHost();
3684 CHECK_NULL_VOID(tmpHost);
3685 auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
3686 CHECK_NULL_VOID(layoutProperty && layoutProperty->HasNumberOfLines());
3687 auto numberOfLines = layoutProperty->GetNumberOfLines().value();
3688 CHECK_NULL_VOID(numberOfLines > 0);
3689 auto lineHeight = layoutProperty->GetLineHeight().value_or(0.0_vp).ConvertToPx();
3690 if (LessOrEqual(lineHeight, 0.f)) {
3691 lineHeight = PreferredLineHeight(false);
3692 }
3693 auto lineSpacing = layoutProperty->GetLineSpacing().value_or(0.0_vp).ConvertToPx();
3694 auto contentHeight = numberOfLines * lineHeight + numberOfLines * lineSpacing;
3695 auto height = contentHeight + GetVerticalPaddingAndBorderSum();
3696
3697 // get previously user defined ideal width
3698 std::optional<CalcLength> width = std::nullopt;
3699 auto &&layoutConstraint = layoutProperty->GetCalcLayoutConstraint();
3700 if (layoutConstraint && layoutConstraint->selfIdealSize) {
3701 width = layoutConstraint->selfIdealSize->Width();
3702 }
3703 layoutProperty->UpdateUserDefinedIdealSize(CalcSize(width, CalcLength(height)));
3704 }
3705
InitLongPressEvent()3706 void TextFieldPattern::InitLongPressEvent()
3707 {
3708 CHECK_NULL_VOID(!longPressEvent_);
3709 auto tmpHost = GetHost();
3710 CHECK_NULL_VOID(tmpHost);
3711 auto gesture = tmpHost->GetOrCreateGestureEventHub();
3712 auto longPressCallback = [weak = WeakClaim(this)](GestureEvent& info) {
3713 auto pattern = weak.Upgrade();
3714 CHECK_NULL_VOID(pattern);
3715 pattern->selectOverlay_->SetUsingMouse(info.GetSourceDevice() == SourceType::MOUSE);
3716 pattern->selectOverlay_->SetLastSourceType(info.GetSourceDevice());
3717 pattern->HandleLongPress(info);
3718 };
3719 longPressEvent_ = MakeRefPtr<LongPressEvent>(std::move(longPressCallback));
3720 gesture->SetLongPressEvent(longPressEvent_);
3721 }
3722
StartVibratorByLongPress()3723 void TextFieldPattern::StartVibratorByLongPress()
3724 {
3725 CHECK_NULL_VOID(isEnableHapticFeedback_);
3726 VibratorUtils::StartVibraFeedback("longPress.light");
3727 }
3728
HandleLongPress(GestureEvent & info)3729 void TextFieldPattern::HandleLongPress(GestureEvent& info)
3730 {
3731 CHECK_NULL_VOID(!IsDragging());
3732 CHECK_NULL_VOID(!IsHandleDragging());
3733 auto focusHub = GetFocusHub();
3734 CHECK_NULL_VOID(focusHub);
3735 if (!focusHub->IsFocusable() || IsOnUnitByPosition(info.GetLocalLocation()) || GetIsPreviewText() ||
3736 IsOnPasswordByPosition(info.GetLocalLocation()) || IsOnCleanNodeByPosition(info.GetLocalLocation())) {
3737 return;
3738 }
3739 moveCaretState_.isTouchCaret = false;
3740 auto host = GetHost();
3741 CHECK_NULL_VOID(host);
3742 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "HandleLongPress %{public}d", host->GetId());
3743 if (ResetObscureTickCountDown()) {
3744 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
3745 }
3746 if (info.GetSourceDevice() == SourceType::MOUSE) {
3747 return;
3748 }
3749 auto hub = host->GetEventHub<EventHub>();
3750 CHECK_NULL_VOID(hub);
3751 auto gestureHub = hub->GetOrCreateGestureEventHub();
3752 CHECK_NULL_VOID(gestureHub);
3753 StartVibratorByLongPress();
3754 if (BetweenSelectedPosition(info)) {
3755 gestureHub->SetIsTextDraggable(true);
3756 return;
3757 }
3758 gestureHub->SetIsTextDraggable(false);
3759 isLongPress_ = true;
3760 if (!focusHub->IsCurrentFocus()) {
3761 TextFieldRequestFocus(RequestFocusReason::LONG_PRESS);
3762 }
3763
3764 auto localOffset = info.GetLocalLocation();
3765 if (CanChangeSelectState()) {
3766 selectController_->UpdateSelectWithBlank(localOffset);
3767 StopTwinkling();
3768 }
3769 SetIsSingleHandle(!IsSelected());
3770 auto start = selectController_->GetStartIndex();
3771 auto end = selectController_->GetEndIndex();
3772 CloseSelectOverlay();
3773 longPressFingerNum_ = info.GetFingerList().size();
3774 if (magnifierController_ && HasText() && (longPressFingerNum_ == 1)) {
3775 magnifierController_->SetLocalOffset({ localOffset.GetX(), localOffset.GetY() });
3776 }
3777 StartGestureSelection(start, end, localOffset);
3778 TriggerAvoidOnCaretChange();
3779 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
3780 }
3781
BetweenSelectedPosition(GestureEvent & info)3782 bool TextFieldPattern::BetweenSelectedPosition(GestureEvent& info)
3783 {
3784 if (!IsSelected()) {
3785 return false;
3786 }
3787 auto localOffset = info.GetLocalLocation();
3788 auto offsetX = IsTextArea() ? contentRect_.GetX() : textRect_.GetX();
3789 auto offsetY = IsTextArea() ? textRect_.GetY() : contentRect_.GetY();
3790 Offset offset = localOffset - Offset(offsetX, offsetY);
3791 for (const auto& rect : selectController_->GetSelectedRects()) {
3792 bool isInRange = rect.IsInRegion({ offset.GetX(), offset.GetY() });
3793 if (isInRange) {
3794 return true;
3795 }
3796 }
3797 return false;
3798 }
3799
CanChangeSelectState()3800 bool TextFieldPattern::CanChangeSelectState()
3801 {
3802 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
3803 CHECK_NULL_RETURN(layoutProperty, false);
3804 auto theme = GetTheme();
3805 CHECK_NULL_RETURN(theme, false);
3806 Dimension fontSize = layoutProperty->GetFontSizeValue(theme->GetFontSize());
3807 // fontSize == 0 can not change
3808 return !NearZero(fontSize.Value()) && !IsContentRectNonPositive();
3809 }
3810
IsAccessibilityClick()3811 bool TextFieldPattern::IsAccessibilityClick()
3812 {
3813 auto host = GetHost();
3814 CHECK_NULL_RETURN(host, false);
3815 auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
3816 CHECK_NULL_RETURN(accessibilityProperty, false);
3817 return accessibilityProperty->GetAccessibilityFocusState();
3818 }
3819
IsOnUnitByPosition(const Offset & localOffset)3820 bool TextFieldPattern::IsOnUnitByPosition(const Offset& localOffset)
3821 {
3822 if (!IsShowUnit()) {
3823 return false;
3824 }
3825 auto unitArea = AceType::DynamicCast<UnitResponseArea>(responseArea_);
3826 CHECK_NULL_RETURN(unitArea, false);
3827 auto frameNode = unitArea->GetFrameNode();
3828 CHECK_NULL_RETURN(frameNode, false);
3829 return frameNode->GetGeometryNode()->GetFrameRect().IsInRegion({ localOffset.GetX(), localOffset.GetY() });
3830 }
3831
IsOnPasswordByPosition(const Offset & localOffset)3832 bool TextFieldPattern::IsOnPasswordByPosition(const Offset& localOffset)
3833 {
3834 auto passwordArea = AceType::DynamicCast<PasswordResponseArea>(responseArea_);
3835 CHECK_NULL_RETURN(passwordArea, false);
3836 auto frameNode = passwordArea->GetFrameNode();
3837 CHECK_NULL_RETURN(frameNode, false);
3838 return frameNode->GetGeometryNode()->GetFrameRect().IsInRegion({ localOffset.GetX(), localOffset.GetY() });
3839 }
3840
IsOnCleanNodeByPosition(const Offset & localOffset)3841 bool TextFieldPattern::IsOnCleanNodeByPosition(const Offset& localOffset)
3842 {
3843 auto cleanNodeResponseArea = AceType::DynamicCast<CleanNodeResponseArea>(cleanNodeResponseArea_);
3844 CHECK_NULL_RETURN(cleanNodeResponseArea, false);
3845 auto frameNode = cleanNodeResponseArea->GetFrameNode();
3846 CHECK_NULL_RETURN(frameNode, false);
3847 return frameNode->GetGeometryNode()->GetFrameRect().IsInRegion({ localOffset.GetX(), localOffset.GetY() });
3848 }
3849
IsMouseOverScrollBar(const BaseEventInfo * info)3850 bool TextFieldPattern::IsMouseOverScrollBar(const BaseEventInfo* info)
3851 {
3852 CHECK_NULL_RETURN(GetScrollBar(), false);
3853 Point point;
3854 do {
3855 auto gestureEvent = TypeInfoHelper::DynamicCast<GestureEvent>(info);
3856 if (gestureEvent) {
3857 point = Point(gestureEvent->GetLocalLocation().GetX(), gestureEvent->GetLocalLocation().GetY());
3858 break;
3859 }
3860 auto mouseInfo = TypeInfoHelper::DynamicCast<MouseInfo>(info);
3861 if (mouseInfo) {
3862 point = Point(mouseInfo->GetLocalLocation().GetX(), mouseInfo->GetLocalLocation().GetY());
3863 break;
3864 }
3865 return false;
3866 } while (false);
3867 if (GetScrollBar()->NeedPaint() && GetScrollBar()->GetShapeMode() == ShapeMode::RECT) {
3868 auto barRect = GetScrollBar()->GetBarRect();
3869 auto mouseScrollbarRegionWidth = MOUSE_SCROLL_BAR_REGION_WIDTH.ConvertToPx();
3870 barRect.SetLeft(barRect.Left() + (barRect.Width() - mouseScrollbarRegionWidth));
3871 barRect.SetWidth(mouseScrollbarRegionWidth);
3872 barRect.SetHeight(frameRect_.Height());
3873 barRect.SetTop(0.0f);
3874 return barRect.IsInRegion(point);
3875 }
3876 return false;
3877 }
3878
UpdateCaretPositionWithClamp(const int32_t & pos)3879 void TextFieldPattern::UpdateCaretPositionWithClamp(const int32_t& pos)
3880 {
3881 selectController_->UpdateCaretIndex(
3882 std::clamp(pos, 0, static_cast<int32_t>(contentController_->GetTextUtf16Value().length())));
3883 }
3884
ProcessOverlay(const OverlayRequest & request)3885 void TextFieldPattern::ProcessOverlay(const OverlayRequest& request)
3886 {
3887 selectOverlay_->ProcessOverlay(request);
3888 }
3889
DelayProcessOverlay(const OverlayRequest & request)3890 void TextFieldPattern::DelayProcessOverlay(const OverlayRequest& request)
3891 {
3892 processOverlayDelayTask_ = [weak = WeakClaim(this), request]() {
3893 auto pattern = weak.Upgrade();
3894 CHECK_NULL_VOID(pattern);
3895 pattern->ProcessOverlay(request);
3896 };
3897 }
3898
CancelDelayProcessOverlay()3899 void TextFieldPattern::CancelDelayProcessOverlay()
3900 {
3901 if (processOverlayDelayTask_) {
3902 processOverlayDelayTask_ = nullptr;
3903 }
3904 }
3905
AllowCopy()3906 bool TextFieldPattern::AllowCopy()
3907 {
3908 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
3909 CHECK_NULL_RETURN(layoutProperty, false);
3910 return layoutProperty->GetCopyOptionsValue(CopyOptions::Local) != CopyOptions::None && !IsInPasswordMode();
3911 }
3912
OnDetachFromFrameNode(FrameNode * node)3913 void TextFieldPattern::OnDetachFromFrameNode(FrameNode* node)
3914 {
3915 CloseSelectOverlay();
3916 auto pipeline = node->GetContext();
3917 CHECK_NULL_VOID(pipeline);
3918 if (HasSurfaceChangedCallback()) {
3919 pipeline->UnregisterSurfaceChangedCallback(surfaceChangedCallbackId_.value_or(-1));
3920 }
3921 if (HasSurfacePositionChangedCallback()) {
3922 pipeline->UnregisterSurfacePositionChangedCallback(surfacePositionChangedCallbackId_.value_or(-1));
3923 }
3924 auto textFieldManager = DynamicCast<TextFieldManagerNG>(pipeline->GetTextFieldManager());
3925 if (textFieldManager) {
3926 textFieldManager->ClearOnFocusTextField(node->GetId());
3927 }
3928 auto frameNode = WeakClaim(node);
3929 pipeline->RemoveFontNodeNG(frameNode);
3930 auto fontManager = pipeline->GetFontManager();
3931 if (fontManager) {
3932 fontManager->UnRegisterCallbackNG(frameNode);
3933 fontManager->RemoveVariationNodeNG(frameNode);
3934 }
3935 pipeline->RemoveWindowSizeChangeCallback(node->GetId());
3936 pipeline->RemoveOnAreaChangeNode(node->GetId());
3937 }
3938
CloseSelectOverlay()3939 void TextFieldPattern::CloseSelectOverlay()
3940 {
3941 CloseSelectOverlay(false);
3942 }
3943
CloseSelectOverlay(bool animation)3944 void TextFieldPattern::CloseSelectOverlay(bool animation)
3945 {
3946 selectOverlay_->CloseOverlay(animation, CloseReason::CLOSE_REASON_NORMAL);
3947 auto host = GetHost();
3948 CHECK_NULL_VOID(host);
3949 auto gesture = host->GetOrCreateGestureEventHub();
3950 gesture->AddTouchEvent(GetTouchListener());
3951 }
3952
InitEditingValueText(std::u16string content)3953 void TextFieldPattern::InitEditingValueText(std::u16string content)
3954 {
3955 if (HasInputOperation()) {
3956 return;
3957 }
3958 contentController_->SetTextValueOnly(std::move(content));
3959 selectController_->UpdateCaretIndex(GetTextUtf16Value().length());
3960 if (GetIsPreviewText() && GetTextUtf16Value().empty()) {
3961 FinishTextPreviewOperation();
3962 }
3963 GetHost()->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
3964 }
3965
InitValueText(std::u16string content)3966 bool TextFieldPattern::InitValueText(std::u16string content)
3967 {
3968 if (GetIsPreviewText()) {
3969 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "Init when has previewText");
3970 return false;
3971 }
3972 if (HasInputOperation() && content != u"") {
3973 return false;
3974 }
3975 ChangeValueInfo changeValueInfo;
3976 changeValueInfo.oldContent = GetBodyTextValue();
3977 changeValueInfo.value = content;
3978 changeValueInfo.oldPreviewText.offset = hasPreviewText_ ? GetPreviewTextStart() : -1;
3979 changeValueInfo.oldPreviewText.value = GetPreviewTextValue();
3980 changeValueInfo.previewText = changeValueInfo.oldPreviewText;
3981 changeValueInfo.rangeBefore = TextRange { 0, changeValueInfo.oldContent.length() };
3982 changeValueInfo.rangeAfter = TextRange { 0, content.length() };
3983 bool isWillChange = FireOnWillChange(changeValueInfo);
3984 if (!isWillChange) {
3985 return false;
3986 }
3987 contentController_->SetTextValueOnly(std::move(content));
3988 selectController_->UpdateCaretIndex(GetTextUtf16Value().length());
3989 GetHost()->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
3990 return true;
3991 }
3992
InitMouseEvent()3993 void TextFieldPattern::InitMouseEvent()
3994 {
3995 CHECK_NULL_VOID(!mouseEvent_ || !hoverEvent_);
3996 auto tmpHost = GetHost();
3997 CHECK_NULL_VOID(tmpHost);
3998 auto eventHub = tmpHost->GetEventHub<TextFieldEventHub>();
3999 auto inputHub = eventHub->GetOrCreateInputEventHub();
4000
4001 auto mouseTask = [weak = WeakClaim(this)](MouseInfo& info) {
4002 auto pattern = weak.Upgrade();
4003 if (pattern) {
4004 pattern->HandleMouseEvent(info);
4005 if (info.GetButton() == MouseButton::LEFT_BUTTON && info.GetAction() == MouseAction::PRESS) {
4006 pattern->hasMousePressed_ = true;
4007 } else {
4008 pattern->hasMousePressed_ = false;
4009 }
4010 }
4011 };
4012 mouseEvent_ = MakeRefPtr<InputEvent>(std::move(mouseTask));
4013 inputHub->AddOnMouseEvent(mouseEvent_);
4014
4015 auto hoverTask = [weak = WeakClaim(this)](bool isHover) {
4016 auto pattern = weak.Upgrade();
4017 if (pattern) {
4018 pattern->OnHover(isHover);
4019 }
4020 };
4021 hoverEvent_ = MakeRefPtr<InputEvent>(std::move(hoverTask));
4022 inputHub->AddOnHoverEvent(hoverEvent_);
4023 InitPanEvent();
4024 }
4025
InitPanEvent()4026 void TextFieldPattern::InitPanEvent()
4027 {
4028 auto host = GetHost();
4029 CHECK_NULL_VOID(host);
4030 auto gestureHub = host->GetOrCreateGestureEventHub();
4031 CHECK_NULL_VOID(gestureHub);
4032 if (!boxSelectPanEvent_) {
4033 auto actionStartTask = [weak = WeakClaim(this)](const GestureEvent& info) {};
4034 auto actionUpdateTask = [weak = WeakClaim(this)](const GestureEvent& info) {};
4035 auto actionEndTask = [weak = WeakClaim(this)](const GestureEvent& info) {};
4036 GestureEventNoParameter actionCancelTask;
4037 boxSelectPanEvent_ = MakeRefPtr<PanEvent>(std::move(actionStartTask), std::move(actionUpdateTask),
4038 std::move(actionEndTask), std::move(actionCancelTask));
4039 }
4040 PanDirection panDirection = { .type = PanDirection::ALL };
4041 gestureHub->AddPanEvent(boxSelectPanEvent_, panDirection, 1, DEFAULT_PAN_DISTANCE);
4042 gestureHub->SetPanEventType(GestureTypeName::TEXTFIELD_BOXSELECT);
4043 gestureHub->SetOnGestureJudgeNativeBegin([weak = WeakClaim(this)](const RefPtr<NG::GestureInfo>& gestureInfo,
4044 const std::shared_ptr<BaseGestureEvent>& info) -> GestureJudgeResult {
4045 if (gestureInfo->GetType() == GestureTypeName::BOXSELECT &&
4046 gestureInfo->GetInputEventType() == InputEventType::MOUSE_BUTTON) {
4047 return GestureJudgeResult::REJECT;
4048 }
4049 auto pattern = weak.Upgrade();
4050 CHECK_NULL_RETURN(pattern, GestureJudgeResult::CONTINUE);
4051 if (gestureInfo->GetType() == GestureTypeName::TEXTFIELD_BOXSELECT &&
4052 gestureInfo->GetInputEventType() == InputEventType::TOUCH_SCREEN &&
4053 pattern->moveCaretState_.isMoveCaret) {
4054 return GestureJudgeResult::CONTINUE;
4055 }
4056 if (gestureInfo->GetType() == GestureTypeName::TEXTFIELD_BOXSELECT &&
4057 gestureInfo->GetInputEventType() != InputEventType::MOUSE_BUTTON) {
4058 return GestureJudgeResult::REJECT;
4059 }
4060 auto host = pattern->GetHost();
4061 CHECK_NULL_RETURN(host, GestureJudgeResult::CONTINUE);
4062 if (gestureInfo->GetType() == GestureTypeName::TEXTFIELD_BOXSELECT &&
4063 gestureInfo->GetInputEventType() == InputEventType::MOUSE_BUTTON &&
4064 host->IsDraggable() && pattern->IsPressSelectedBox()) {
4065 return GestureJudgeResult::REJECT;
4066 }
4067 if (pattern->GetCancelButtonTouchInfo()) {
4068 return GestureJudgeResult::REJECT;
4069 }
4070 return GestureJudgeResult::CONTINUE;
4071 });
4072 }
4073
OnHover(bool isHover)4074 void TextFieldPattern::OnHover(bool isHover)
4075 {
4076 auto frame = GetHost();
4077 CHECK_NULL_VOID(frame);
4078 auto frameId = frame->GetId();
4079 auto pipeline = frame->GetContext();
4080 auto textFieldTheme = GetTheme();
4081 if (!pipeline || !textFieldTheme) {
4082 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "Textfield %{public}d hover can't get pipeline",
4083 frame->GetId());
4084 return;
4085 }
4086 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "Textfield %{public}d %{public}s", frame->GetId(),
4087 isHover ? "on hover" : "exit hover");
4088 pipeline->SetMouseStyleHoldNode(frameId);
4089 if (!isHover) {
4090 int32_t windowId = 0;
4091 #ifdef WINDOW_SCENE_SUPPORTED
4092 windowId = static_cast<int32_t>(GetSCBSystemWindowId());
4093 #endif
4094 pipeline->ChangeMouseStyle(frameId, MouseFormat::DEFAULT, windowId);
4095 pipeline->FreeMouseStyleHoldNode(frameId);
4096 }
4097 UpdateHoverStyle(isHover);
4098 isOnHover_ = isHover;
4099 }
4100
UpdateHoverStyle(bool isHover)4101 void TextFieldPattern::UpdateHoverStyle(bool isHover)
4102 {
4103 if (!hoverAndPressBgColorEnabled_) {
4104 return;
4105 }
4106 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
4107 CHECK_NULL_VOID(paintProperty);
4108 auto theme = GetTheme();
4109 CHECK_NULL_VOID(theme);
4110 auto defaultThemeBgColor = theme->GetBgColor();
4111 auto textFieldBgColor = paintProperty->GetBackgroundColorValue(defaultThemeBgColor);
4112 auto bgColor = textFieldBgColor;
4113 if (textFieldBgColor == defaultThemeBgColor) {
4114 bgColor = IsUnderlineMode() ? Color::TRANSPARENT : defaultThemeBgColor;
4115 }
4116 auto hoverColor = bgColor.BlendColor(theme->GetPressColor());
4117 if (!HasFocus()) {
4118 if (isHover) {
4119 PlayAnimationHoverAndPress(hoverColor);
4120 } else {
4121 PlayAnimationHoverAndPress(bgColor);
4122 }
4123 }
4124 }
4125
UpdatePressStyle(bool isPressed)4126 void TextFieldPattern::UpdatePressStyle(bool isPressed)
4127 {
4128 if (!hoverAndPressBgColorEnabled_) {
4129 return;
4130 }
4131 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
4132 CHECK_NULL_VOID(paintProperty);
4133 auto theme = GetTheme();
4134 CHECK_NULL_VOID(theme);
4135 auto defaultThemeBgColor = theme->GetBgColor();
4136 auto textFieldBgColor = paintProperty->GetBackgroundColorValue(defaultThemeBgColor);
4137 auto bgColor = textFieldBgColor;
4138 if (textFieldBgColor == defaultThemeBgColor) {
4139 if (IsUnderlineMode()) {
4140 bgColor = Color::TRANSPARENT;
4141 } else {
4142 bgColor = HasFocus() ? theme->GetFocusBgColor() : defaultThemeBgColor;
4143 }
4144 }
4145 auto pressColor = bgColor.BlendColor(theme->GetHoverColor());
4146 if (isPressed) {
4147 PlayAnimationHoverAndPress(pressColor);
4148 } else {
4149 PlayAnimationHoverAndPress(bgColor);
4150 }
4151 }
4152
PlayAnimationHoverAndPress(const Color & color)4153 void TextFieldPattern::PlayAnimationHoverAndPress(const Color& color)
4154 {
4155 AnimationOption option = AnimationOption();
4156 option.SetDuration(HOVER_ANIMATION_DURATION);
4157 option.SetCurve(Curves::FRICTION);
4158 AnimationUtils::Animate(option, [weak = AceType::WeakClaim(this), color]() {
4159 auto textFieldPattern = weak.Upgrade();
4160 CHECK_NULL_VOID(textFieldPattern);
4161 textFieldPattern->UpdateTextFieldBgColor(color);
4162 });
4163 }
4164
UpdateTextFieldBgColor(const Color & color)4165 void TextFieldPattern::UpdateTextFieldBgColor(const Color& color)
4166 {
4167 auto host = GetHost();
4168 CHECK_NULL_VOID(host);
4169 auto renderContext = host->GetRenderContext();
4170 CHECK_NULL_VOID(renderContext);
4171 renderContext->UpdateBackgroundColor(color);
4172 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
4173 }
4174
RestoreDefaultMouseState()4175 void TextFieldPattern::RestoreDefaultMouseState()
4176 {
4177 int32_t windowId = 0;
4178 #ifdef WINDOW_SCENE_SUPPORTED
4179 windowId = static_cast<int32_t>(GetSCBSystemWindowId());
4180 #endif
4181 auto host = GetHost();
4182 CHECK_NULL_VOID(host);
4183 auto pipeline = host->GetContextRefPtr();
4184 CHECK_NULL_VOID(pipeline);
4185 auto id = host->GetId();
4186 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "RestoreDefaultMouseState id:%{public}d, winId:%{public}d", id, windowId);
4187 pipeline->SetMouseStyleHoldNode(id);
4188 pipeline->ChangeMouseStyle(id, MouseFormat::DEFAULT, windowId);
4189 }
4190
ChangeMouseState(const Offset location,int32_t frameId,bool isByPass)4191 void TextFieldPattern::ChangeMouseState(
4192 const Offset location, int32_t frameId, bool isByPass)
4193 {
4194 auto host = GetHost();
4195 CHECK_NULL_VOID(host);
4196 auto pipeline = host->GetContext();
4197 CHECK_NULL_VOID(pipeline);
4198 auto responseAreaWidth = (responseArea_ ? responseArea_->GetAreaRect().Width() : 0.0f) +
4199 (cleanNodeResponseArea_ ? cleanNodeResponseArea_->GetAreaRect().Width() : 0.0f);
4200 auto x = location.GetX();
4201 auto y = location.GetY();
4202 int32_t windowId = 0;
4203 #ifdef WINDOW_SCENE_SUPPORTED
4204 windowId = static_cast<int32_t>(GetSCBSystemWindowId());
4205 #endif
4206 if (GreatNotEqual(x, 0) && LessNotEqual(x, frameRect_.Width()) && GreatNotEqual(y, 0) &&
4207 LessNotEqual(y, frameRect_.Height())) {
4208 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
4209 CHECK_NULL_VOID(layoutProperty);
4210 auto isRTL = layoutProperty->GetNonAutoLayoutDirection() == TextDirection::RTL;
4211 if (!isRTL && GreatNotEqual(location.GetX(), frameRect_.Width() - responseAreaWidth)) {
4212 RestoreDefaultMouseState();
4213 } else if (isRTL && LessNotEqual(location.GetX(), responseAreaWidth)) {
4214 RestoreDefaultMouseState();
4215 } else {
4216 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "ChangeMouseState Id:%{public}d, winId:%{public}d", frameId, windowId);
4217 pipeline->SetMouseStyleHoldNode(frameId);
4218 pipeline->ChangeMouseStyle(frameId, MouseFormat::TEXT_CURSOR, windowId, isByPass);
4219 }
4220 } else {
4221 RestoreDefaultMouseState();
4222 }
4223 }
4224
HandleMouseEvent(MouseInfo & info)4225 void TextFieldPattern::HandleMouseEvent(MouseInfo& info)
4226 {
4227 CHECK_NULL_VOID(!IsDragging());
4228 auto tmpHost = GetHost();
4229 CHECK_NULL_VOID(tmpHost);
4230 auto frameId = tmpHost->GetId();
4231 auto pipeline = tmpHost->GetContext();
4232 CHECK_NULL_VOID(pipeline);
4233 info.SetStopPropagation(true);
4234 selectOverlay_->SetLastSourceType(info.GetSourceDevice());
4235 auto scrollBar = GetScrollBar();
4236 int32_t windowId = 0;
4237 #ifdef WINDOW_SCENE_SUPPORTED
4238 windowId = static_cast<int32_t>(GetSCBSystemWindowId());
4239 #endif
4240 if (scrollBar && (scrollBar->IsPressed() || scrollBar->IsHover() || IsMouseOverScrollBar(&info))) {
4241 pipeline->SetMouseStyleHoldNode(frameId);
4242 pipeline->ChangeMouseStyle(frameId, MouseFormat::DEFAULT, windowId);
4243 return;
4244 }
4245 ChangeMouseState(info.GetLocalLocation(), frameId, info.GetAction() == MouseAction::WINDOW_LEAVE);
4246
4247 if (info.GetAction() == OHOS::Ace::MouseAction::PRESS) {
4248 selectOverlay_->SetUsingMouse(true);
4249 }
4250 if (info.GetButton() == MouseButton::RIGHT_BUTTON) {
4251 HandleRightMouseEvent(info);
4252 } else if (info.GetButton() == MouseButton::LEFT_BUTTON) {
4253 HandleLeftMouseEvent(info);
4254 if (IsSelected()) {
4255 selectOverlay_->SetSelectionHoldCallback();
4256 }
4257 }
4258 if (info.GetAction() == OHOS::Ace::MouseAction::RELEASE) {
4259 selectOverlay_->SetUsingMouse(false);
4260 }
4261 if (!IsSelected()) {
4262 ResetOriginCaretPosition();
4263 }
4264 }
4265
HandleRightMouseEvent(MouseInfo & info)4266 void TextFieldPattern::HandleRightMouseEvent(MouseInfo& info)
4267 {
4268 if (info.GetAction() == OHOS::Ace::MouseAction::PRESS) {
4269 HandleRightMousePressEvent(info);
4270 return;
4271 }
4272 if (info.GetAction() == OHOS::Ace::MouseAction::RELEASE) {
4273 HandleRightMouseReleaseEvent(info);
4274 }
4275 }
4276
HandleRightMousePressEvent(MouseInfo & info)4277 void TextFieldPattern::HandleRightMousePressEvent(MouseInfo& info)
4278 {
4279 if (IsSelected() || GetIsPreviewText()) {
4280 return;
4281 }
4282 auto focusHub = GetFocusHub();
4283 if (!focusHub->IsFocusable()) {
4284 return;
4285 }
4286 FocusAndUpdateCaretByMouse(info);
4287 }
4288
HandleRightMouseReleaseEvent(MouseInfo & info)4289 void TextFieldPattern::HandleRightMouseReleaseEvent(MouseInfo& info)
4290 {
4291 if (GetIsPreviewText()) {
4292 return;
4293 }
4294 auto focusHub = GetFocusHub();
4295 if (focusHub->IsCurrentFocus()) {
4296 OffsetF rightClickOffset = OffsetF(
4297 static_cast<float>(info.GetGlobalLocation().GetX()), static_cast<float>(info.GetGlobalLocation().GetY()));
4298 selectOverlay_->SetMouseMenuOffset(rightClickOffset);
4299 ProcessOverlay();
4300 }
4301 }
4302
HandleLeftMouseEvent(MouseInfo & info)4303 void TextFieldPattern::HandleLeftMouseEvent(MouseInfo& info)
4304 {
4305 switch (info.GetAction()) {
4306 case OHOS::Ace::MouseAction::PRESS: {
4307 HandleLeftMousePressEvent(info);
4308 break;
4309 }
4310 case OHOS::Ace::MouseAction::MOVE: {
4311 HandleLeftMouseMoveEvent(info); // 注意鼠标拖拽的滚动效果
4312 break;
4313 }
4314 case OHOS::Ace::MouseAction::RELEASE: {
4315 HandleLeftMouseReleaseEvent(info);
4316 break;
4317 }
4318 default: {
4319 }
4320 }
4321 }
4322
HandleLeftMousePressEvent(MouseInfo & info)4323 void TextFieldPattern::HandleLeftMousePressEvent(MouseInfo& info)
4324 {
4325 isPressSelectedBox_ =
4326 (IsSelected() && BetweenSelectedPosition(info.GetGlobalLocation()) && !shiftFlag_);
4327 if (isPressSelectedBox_ || GetIsPreviewText()) {
4328 blockPress_ = true;
4329 return;
4330 }
4331 auto focusHub = GetFocusHub();
4332 if (!focusHub->IsFocusable()) {
4333 return;
4334 }
4335 mouseStatus_ = MouseStatus::PRESSED;
4336 blockPress_ = false;
4337 leftMouseCanMove_ = true;
4338 FocusAndUpdateCaretByMouse(info);
4339 }
4340
FocusAndUpdateCaretByMouse(MouseInfo & info)4341 void TextFieldPattern::FocusAndUpdateCaretByMouse(MouseInfo& info)
4342 {
4343 auto focusHub = GetFocusHub();
4344 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
4345 CHECK_NULL_VOID(paintProperty);
4346 if (!focusHub->IsFocusOnTouch().value_or(true) || !TextFieldRequestFocus(RequestFocusReason::MOUSE)) {
4347 StopTwinkling();
4348 return;
4349 }
4350 UpdateCaretByClick(info.GetLocalLocation());
4351 auto tmpHost = GetHost();
4352 CHECK_NULL_VOID(tmpHost);
4353 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
4354 }
4355
UpdateShiftFlag(const KeyEvent & keyEvent)4356 void TextFieldPattern::UpdateShiftFlag(const KeyEvent& keyEvent)
4357 {
4358 bool flag = false;
4359 if (keyEvent.action == KeyAction::DOWN) {
4360 if (keyEvent.HasKey(KeyCode::KEY_SHIFT_LEFT) || keyEvent.HasKey(KeyCode::KEY_SHIFT_RIGHT)) {
4361 flag = true;
4362 }
4363 }
4364 if (flag != shiftFlag_) {
4365 shiftFlag_ = flag;
4366 if (!shiftFlag_) {
4367 // open drag
4368 InitDragEvent();
4369 } else {
4370 // close drag
4371 ClearDragDropEvent();
4372 }
4373 }
4374 }
4375
UpdateCaretByClick(const Offset & localOffset)4376 void TextFieldPattern::UpdateCaretByClick(const Offset& localOffset)
4377 {
4378 if (shiftFlag_) {
4379 selectController_->UpdateSecondHandleInfoByMouseOffset(localOffset);
4380 StopTwinkling();
4381 } else {
4382 selectController_->UpdateCaretInfoByOffset(localOffset, true, false);
4383 StartTwinkling();
4384 }
4385 }
4386
HandleLeftMouseMoveEvent(MouseInfo & info)4387 void TextFieldPattern::HandleLeftMouseMoveEvent(MouseInfo& info)
4388 {
4389 if (!leftMouseCanMove_ || blockPress_) {
4390 return;
4391 }
4392 auto focusHub = GetFocusHub();
4393 if (!focusHub->IsCurrentFocus()) {
4394 return;
4395 }
4396 mouseStatus_ = MouseStatus::MOVE;
4397 if (GetTextUtf16Value().empty()) {
4398 return;
4399 }
4400 selectController_->UpdateSecondHandleInfoByMouseOffset(info.GetLocalLocation()); // 更新时上报事件
4401 showSelect_ = true;
4402 auto tmpHost = GetHost();
4403 CHECK_NULL_VOID(tmpHost);
4404 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
4405 }
4406
HandleLeftMouseReleaseEvent(MouseInfo & info)4407 void TextFieldPattern::HandleLeftMouseReleaseEvent(MouseInfo& info)
4408 {
4409 auto tmpHost = GetHost();
4410 CHECK_NULL_VOID(tmpHost);
4411 if (blockPress_ && mouseStatus_ == MouseStatus::PRESSED) {
4412 selectController_->UpdateCaretInfoByOffset(info.GetLocalLocation(), true, false);
4413 StartTwinkling();
4414 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
4415 }
4416 FreeMouseStyleHoldNode(info.GetLocalLocation());
4417 mouseStatus_ = MouseStatus::NONE;
4418 blockPress_ = false;
4419 leftMouseCanMove_ = false;
4420 if (HasFocus() && RequestKeyboardNotByFocusSwitch(RequestKeyboardReason::MOUSE_RELEASE)) {
4421 NotifyOnEditChanged(true);
4422 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
4423 }
4424 }
4425
FreeMouseStyleHoldNode(const Offset location)4426 void TextFieldPattern::FreeMouseStyleHoldNode(const Offset location)
4427 {
4428 auto rect = RectF(0.0f, 0.0f, frameRect_.Width(), frameRect_.Height());
4429 if (!location.IsPositiveOffset() || !rect.IsInRegion({ location.GetX(), location.GetY() })) {
4430 auto tmpHost = GetHost();
4431 CHECK_NULL_VOID(tmpHost);
4432 auto frameId = tmpHost->GetId();
4433 auto pipeline = GetContext();
4434 CHECK_NULL_VOID(pipeline);
4435 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "FreeMouseStyleHoldNode, id:%{public}d", frameId);
4436 pipeline->FreeMouseStyleHoldNode(frameId);
4437 }
4438 }
4439
UpdateTextFieldManager(const Offset & offset,float height)4440 void TextFieldPattern::UpdateTextFieldManager(const Offset& offset, float height)
4441 {
4442 auto tmpHost = GetHost();
4443 CHECK_NULL_VOID(tmpHost);
4444 auto context = tmpHost->GetContextRefPtr();
4445 CHECK_NULL_VOID(context);
4446 auto textFieldManager = DynamicCast<TextFieldManagerNG>(context->GetTextFieldManager());
4447 CHECK_NULL_VOID(textFieldManager);
4448 auto safeAreaManager = context->GetSafeAreaManager();
4449 CHECK_NULL_VOID(safeAreaManager);
4450 textFieldManager->UpdateScrollableParentViewPort(tmpHost);
4451 if (!HasFocus()) {
4452 return;
4453 }
4454 textFieldManager->SetClickPosition({ offset.GetX() + selectController_->GetCaretRect().GetX(),
4455 offset.GetY() + selectController_->GetCaretRect().GetY() });
4456 textFieldManager->SetHeight(selectController_->GetCaretRect().Height());
4457 textFieldManager->SetClickPositionOffset(safeAreaManager->GetKeyboardOffset());
4458 textFieldManager->SetOnFocusTextField(WeakClaim(this));
4459 textFieldManager->SetUsingCustomKeyboardAvoid(keyboardAvoidance_);
4460 textFieldManager->SetIfFocusTextFieldIsInline(IsNormalInlineState());
4461 }
4462
GetDefaultTextInputAction() const4463 TextInputAction TextFieldPattern::GetDefaultTextInputAction() const
4464 {
4465 TextInputAction defaultTextInputAction = TextInputAction::DONE;
4466 if (IsTextArea() && !isTextInput_) {
4467 defaultTextInputAction = TextInputAction::NEW_LINE;
4468 } else {
4469 defaultTextInputAction = TextInputAction::DONE;
4470 }
4471 return defaultTextInputAction;
4472 }
4473
4474 #ifdef WINDOW_SCENE_SUPPORTED
GetSCBSystemWindowId()4475 uint32_t TextFieldPattern::GetSCBSystemWindowId()
4476 {
4477 RefPtr<FrameNode> frameNode = GetHost();
4478 CHECK_NULL_RETURN(frameNode, {});
4479 auto focusSystemWindowId = WindowSceneHelper::GetFocusSystemWindowId(frameNode);
4480 return focusSystemWindowId;
4481 }
4482 #endif
4483
KeyboardContentTypeToInputType()4484 void TextFieldPattern::KeyboardContentTypeToInputType()
4485 {
4486 if (keyboard_ != TextInputType::UNSPECIFIED) {
4487 return;
4488 }
4489 auto autoFillType = GetAutoFillType(false);
4490 if (keyBoardMap_.find(autoFillType) != keyBoardMap_.end()) {
4491 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD,
4492 "Set InputType to %{public}d because of contentType", keyBoardMap_[autoFillType]);
4493 keyboard_ = keyBoardMap_[autoFillType];
4494 }
4495 }
4496
GetRequestKeyboardId()4497 int32_t TextFieldPattern::GetRequestKeyboardId()
4498 {
4499 auto host = GetHost();
4500 CHECK_NULL_RETURN(host, -1);
4501 return host->GetId();
4502 }
4503
RequestKeyboard(bool isFocusViewChanged,bool needStartTwinkling,bool needShowSoftKeyboard,SourceType sourceType)4504 bool TextFieldPattern::RequestKeyboard(bool isFocusViewChanged, bool needStartTwinkling, bool needShowSoftKeyboard,
4505 SourceType sourceType)
4506 {
4507 bool isFocus = HasFocus();
4508 if (!showKeyBoardOnFocus_ || !isFocus) {
4509 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "showKeyBoardOnFocus:%{public}d, isFocus:%{public}d", showKeyBoardOnFocus_,
4510 isFocus);
4511 return false;
4512 }
4513 auto tmpHost = GetHost();
4514 CHECK_NULL_RETURN(tmpHost, false);
4515 if (customKeyboard_ || customKeyboardBuilder_) {
4516 CHECK_NULL_RETURN(needShowSoftKeyboard, true);
4517 return RequestCustomKeyboard();
4518 }
4519 bool ok = true;
4520 KeyboardContentTypeToInputType();
4521 #if defined(ENABLE_STANDARD_INPUT)
4522 if (textChangeListener_ == nullptr) {
4523 textChangeListener_ = new OnTextChangedListenerImpl(WeakClaim(this));
4524 }
4525 auto inputMethod = MiscServices::InputMethodController::GetInstance();
4526 if (!inputMethod) {
4527 TAG_LOGE(AceLogTag::ACE_TEXT_FIELD, "RequestKeyboard, inputMethod is null");
4528 return false;
4529 }
4530 auto optionalTextConfig = GetMiscTextConfig();
4531 CHECK_NULL_RETURN(optionalTextConfig.has_value(), false);
4532 MiscServices::TextConfig textConfig = optionalTextConfig.value();
4533 ACE_LAYOUT_SCOPED_TRACE("RequestKeyboard[id:%d][WId:%u]", tmpHost->GetId(), textConfig.windowId);
4534 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD,
4535 "node:%{public}d, RequestKeyboard set calling window id:%{public}u"
4536 " inputType:%{public}d, enterKeyType:%{public}d, needKeyboard:%{public}d, sourceType:%{public}u",
4537 tmpHost->GetId(), textConfig.windowId, textConfig.inputAttribute.inputPattern,
4538 textConfig.inputAttribute.enterKeyType, needShowSoftKeyboard, sourceType);
4539 #ifdef WINDOW_SCENE_SUPPORTED
4540 auto systemWindowId = GetSCBSystemWindowId();
4541 if (systemWindowId) {
4542 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "windowId From %{public}u to %{public}u.", textConfig.windowId,
4543 systemWindowId);
4544 textConfig.windowId = systemWindowId;
4545 }
4546 #endif
4547 if ((customKeyboard_ || customKeyboardBuilder_) && isCustomKeyboardAttached_) {
4548 TAG_LOGI(AceLogTag::ACE_KEYBOARD, "Request SoftKeyboard, Close CustomKeyboard.");
4549 CloseCustomKeyboard();
4550 }
4551 auto context = tmpHost->GetContextRefPtr();
4552 if (context && context->GetTextFieldManager()) {
4553 auto textFieldManager = DynamicCast<TextFieldManagerNG>(context->GetTextFieldManager());
4554 textFieldManager->SetImeAttached(true);
4555 textFieldManager->SetLastRequestKeyboardId(GetRequestKeyboardId());
4556 }
4557 OHOS::MiscServices::AttachOptions attachOptions;
4558 attachOptions.isShowKeyboard = needShowSoftKeyboard;
4559 attachOptions.requestKeyboardReason =
4560 static_cast<OHOS::MiscServices::RequestKeyboardReason>(static_cast<int32_t>(sourceType));
4561 auto ret = inputMethod->Attach(textChangeListener_, attachOptions, textConfig);
4562 if (ret == MiscServices::ErrorCode::NO_ERROR) {
4563 auto pipeline = GetContext();
4564 CHECK_NULL_RETURN(pipeline, false);
4565 auto textFieldManager = AceType::DynamicCast<TextFieldManagerNG>(pipeline->GetTextFieldManager());
4566 CHECK_NULL_RETURN(textFieldManager, false);
4567 textFieldManager->SetIsImeAttached(true);
4568 }
4569 UpdateCaretInfoToController(true);
4570 if (!fillContentMap_.empty()) {
4571 inputMethod->SendPrivateCommand(fillContentMap_);
4572 fillContentMap_.clear();
4573 }
4574 #else
4575 ok = RequestKeyboardCrossPlatForm(isFocusViewChanged);
4576 #endif
4577 return ok;
4578 }
4579
RequestKeyboardCrossPlatForm(bool isFocusViewChanged)4580 bool TextFieldPattern::RequestKeyboardCrossPlatForm(bool isFocusViewChanged)
4581 {
4582 #if !defined(ENABLE_STANDARD_INPUT)
4583 auto tmpHost = GetHost();
4584 CHECK_NULL_RETURN(tmpHost, false);
4585 auto context = tmpHost->GetContextRefPtr();
4586 CHECK_NULL_RETURN(context, false);
4587 if (!HasConnection()) {
4588 TextInputConfiguration config;
4589 config.type = keyboard_;
4590 config.action = GetTextInputActionValue(GetDefaultTextInputAction());
4591 config.inputFilter = GetInputFilter();
4592 config.maxLength = GetMaxLength();
4593 if (keyboard_ == TextInputType::VISIBLE_PASSWORD || keyboard_ == TextInputType::NEW_PASSWORD) {
4594 config.obscureText = textObscured_;
4595 }
4596 connection_ = TextInputProxy::GetInstance().Attach(
4597 WeakClaim(this), config, context->GetTaskExecutor(), GetInstanceId());
4598
4599 if (!HasConnection()) {
4600 return false;
4601 }
4602 }
4603 TextEditingValue value;
4604 value.text = contentController_->GetTextValue();
4605 value.hint = UtfUtils::Str16DebugToStr8(GetPlaceHolder());
4606 value.selection.Update(selectController_->GetStartIndex(), selectController_->GetEndIndex());
4607 connection_->SetEditingState(value, GetInstanceId());
4608 connection_->Show(isFocusViewChanged, GetInstanceId());
4609 #endif
4610 return true;
4611 }
4612
4613 #if defined(ENABLE_STANDARD_INPUT)
GetMiscTextConfig() const4614 std::optional<MiscServices::TextConfig> TextFieldPattern::GetMiscTextConfig() const
4615 {
4616 auto tmpHost = GetHost();
4617 CHECK_NULL_RETURN(tmpHost, {});
4618 auto pipeline = tmpHost->GetContextRefPtr();
4619 CHECK_NULL_RETURN(pipeline, {});
4620 auto theme = GetTheme();
4621 CHECK_NULL_RETURN(theme, {});
4622 auto windowRect = pipeline->GetCurrentWindowRect();
4623 double positionY = (tmpHost->GetPaintRectOffset(false, true) - pipeline->GetRootRect().GetOffset()).GetY() + windowRect.Top();
4624 auto offset = AVOID_OFFSET.ConvertToPx();
4625 auto textPaintOffset = GetPaintRectGlobalOffset();
4626 double height = selectController_->GetCaretRect().Bottom() + windowRect.Top() +
4627 textPaintOffset.GetY() + offset - positionY;
4628
4629 GetInlinePositionYAndHeight(positionY, height);
4630
4631 auto manager = pipeline->GetSafeAreaManager();
4632 if (manager) {
4633 auto keyboardOffset = manager->GetKeyboardOffset();
4634 positionY -= keyboardOffset;
4635 }
4636
4637 MiscServices::CursorInfo cursorInfo { .left = selectController_->GetCaretRect().Left() + windowRect.Left() +
4638 textPaintOffset.GetX(),
4639 .top = selectController_->GetCaretRect().Top() + windowRect.Top() + textPaintOffset.GetY(),
4640 .width = theme->GetCursorWidth().ConvertToPx(),
4641 .height = selectController_->GetCaretRect().Height() };
4642 MiscServices::InputAttribute inputAttribute = { .inputPattern = (int32_t)keyboard_,
4643 .enterKeyType = (int32_t)GetTextInputActionValue(GetDefaultTextInputAction()),
4644 .isTextPreviewSupported = hasSupportedPreviewText_,
4645 .immersiveMode = static_cast<int32_t>(keyboardAppearance_)};
4646 MiscServices::TextConfig textConfig = { .inputAttribute = inputAttribute,
4647 .cursorInfo = cursorInfo,
4648 .range = { .start = selectController_->GetStartIndex(), .end = selectController_->GetEndIndex() },
4649 .windowId = pipeline->GetFocusWindowId(),
4650 .positionY = positionY,
4651 .height = height };
4652
4653 if (keyboard_ == TextInputType::NUMBER_DECIMAL) {
4654 textConfig.inputAttribute.inputPattern = (int32_t)TextInputType::NUMBER;
4655 }
4656 return textConfig;
4657 }
4658
GetInlinePositionYAndHeight(double & positionY,double & height) const4659 void TextFieldPattern::GetInlinePositionYAndHeight(double& positionY, double& height) const
4660 {
4661 if (IsNormalInlineState()) {
4662 auto theme = GetTheme();
4663 CHECK_NULL_VOID(theme);
4664 auto offset = AVOID_OFFSET.ConvertToPx();
4665 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
4666 PaddingProperty userPadding;
4667 if (paintProperty->HasPaddingByUser()) {
4668 userPadding = paintProperty->GetPaddingByUserValue();
4669 } else {
4670 userPadding.top = CalcLength(theme->GetPadding().Top());
4671 }
4672 auto topPadding = userPadding.top->GetDimension().ConvertToPx();
4673 auto safeBoundary = theme->GetInlineBorderWidth().ConvertToPx() * 2;
4674 positionY += static_cast<double>(inlineMeasureItem_.inlineSizeHeight) + safeBoundary + topPadding;
4675 height = offset;
4676
4677 auto tmpHost = GetHost();
4678 CHECK_NULL_VOID(tmpHost);
4679 auto pipeline = tmpHost->GetContextRefPtr();
4680 CHECK_NULL_VOID(pipeline);
4681 auto textFieldManager = DynamicCast<TextFieldManagerNG>(pipeline->GetTextFieldManager());
4682 CHECK_NULL_VOID(textFieldManager);
4683 TAG_LOGI(ACE_TEXT_FIELD, "SetInlineAvoidInfo positionY:%{public}f height:%{public}f sizeHeight:%{public}f",
4684 positionY, height, inlineMeasureItem_.inlineSizeHeight);
4685 textFieldManager->SetInlineTextFieldAvoidPositionYAndHeight(positionY, height);
4686 }
4687 }
4688
4689 #endif
4690
ConvertToAceAutoFillType(TextInputType type)4691 AceAutoFillType TextFieldPattern::ConvertToAceAutoFillType(TextInputType type)
4692 {
4693 static std::unordered_map<TextInputType, AceAutoFillType> convertMap = {
4694 { TextInputType::VISIBLE_PASSWORD, AceAutoFillType::ACE_PASSWORD },
4695 { TextInputType::USER_NAME, AceAutoFillType::ACE_USER_NAME },
4696 { TextInputType::NEW_PASSWORD, AceAutoFillType::ACE_NEW_PASSWORD },
4697 { TextInputType::NUMBER_PASSWORD, AceAutoFillType::ACE_PASSWORD } };
4698 auto it = convertMap.find(type);
4699 if (it != convertMap.end()) {
4700 return it->second;
4701 }
4702 return AceAutoFillType::ACE_UNSPECIFIED;
4703 }
4704
TextContentTypeToAceAutoFillType(const TextContentType & type)4705 AceAutoFillType TextFieldPattern::TextContentTypeToAceAutoFillType(const TextContentType& type)
4706 {
4707 if (contentTypeMap_.find(type) != contentTypeMap_.end()) {
4708 return contentTypeMap_[type].first;
4709 }
4710 return contentTypeMap_[TextContentType::UNSPECIFIED].first;
4711 }
4712
CloseKeyboard(bool forceClose)4713 bool TextFieldPattern::CloseKeyboard(bool forceClose)
4714 {
4715 return CloseKeyboard(forceClose, forceClose);
4716 }
4717
CloseKeyboard(bool forceClose,bool isStopTwinkling)4718 bool TextFieldPattern::CloseKeyboard(bool forceClose, bool isStopTwinkling)
4719 {
4720 if (forceClose) {
4721 if (isStopTwinkling) {
4722 StopTwinkling();
4723 }
4724 CloseSelectOverlay(true);
4725 auto host = GetHost();
4726 CHECK_NULL_RETURN(host, false);
4727 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "textfield %{public}d Will Close Soft keyboard.", host->GetId());
4728 if ((customKeyboard_ || customKeyboardBuilder_) && isCustomKeyboardAttached_) {
4729 return CloseCustomKeyboard();
4730 }
4731 #if defined(ENABLE_STANDARD_INPUT)
4732 auto inputMethod = MiscServices::InputMethodController::GetInstance();
4733 if (!inputMethod) {
4734 TAG_LOGE(AceLogTag::ACE_TEXT_FIELD, "CloseKeyboard, inputMethod is null");
4735 return false;
4736 }
4737 inputMethod->Close();
4738 #else
4739 if (HasConnection()) {
4740 connection_->Close(GetInstanceId());
4741 connection_ = nullptr;
4742 }
4743 #endif
4744 return true;
4745 }
4746 return false;
4747 }
4748
SetCustomKeyboardOption(bool supportAvoidance)4749 void TextFieldPattern::SetCustomKeyboardOption(bool supportAvoidance)
4750 {
4751 keyboardAvoidance_ = supportAvoidance;
4752 }
4753
RequestCustomKeyboard()4754 bool TextFieldPattern::RequestCustomKeyboard()
4755 {
4756 #if defined(ENABLE_STANDARD_INPUT)
4757 auto inputMethod = MiscServices::InputMethodController::GetInstance();
4758 if (inputMethod) {
4759 TAG_LOGI(AceLogTag::ACE_KEYBOARD, "TextField Request CustomKeyboard, Close keyboard Successfully.");
4760 inputMethod->RequestHideInput();
4761 inputMethod->Close();
4762 }
4763 #else
4764 if (HasConnection()) {
4765 connection_->Close(GetInstanceId());
4766 connection_ = nullptr;
4767 }
4768 #endif
4769
4770 if (isCustomKeyboardAttached_) {
4771 return true;
4772 }
4773 CHECK_NULL_RETURN(customKeyboard_ || customKeyboardBuilder_, false);
4774 auto frameNode = GetHost();
4775 CHECK_NULL_RETURN(frameNode, false);
4776 ACE_LAYOUT_SCOPED_TRACE("RequestCustomKeyboard[id:%d]", frameNode->GetId());
4777 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "RequestCustomKeyboard, id:%{public}d", frameNode->GetId());
4778 auto pipeline = frameNode->GetContext();
4779 CHECK_NULL_RETURN(pipeline, false);
4780 auto overlayManager = pipeline->GetOverlayManager();
4781 CHECK_NULL_RETURN(overlayManager, false);
4782 overlayManager->SetCustomKeyboardOption(keyboardAvoidance_);
4783 if (customKeyboardBuilder_) {
4784 overlayManager->BindKeyboard(customKeyboardBuilder_, frameNode->GetId());
4785 } else {
4786 overlayManager->BindKeyboardWithNode(customKeyboard_, frameNode->GetId());
4787 }
4788 auto textFieldManager = DynamicCast<TextFieldManagerNG>(pipeline->GetTextFieldManager());
4789 if (textFieldManager) {
4790 textFieldManager->SetLastRequestKeyboardId(GetRequestKeyboardId());
4791 }
4792 isCustomKeyboardAttached_ = true;
4793 keyboardOverlay_ = overlayManager;
4794 auto caretHeight = selectController_->GetCaretRect().Height();
4795 auto safeHeight = caretHeight + selectController_->GetCaretRect().GetY();
4796 if (selectController_->GetCaretRect().GetY() > caretHeight) {
4797 safeHeight = caretHeight;
4798 }
4799 keyboardOverlay_->AvoidCustomKeyboard(frameNode->GetId(), safeHeight);
4800 return true;
4801 }
4802
CloseCustomKeyboard()4803 bool TextFieldPattern::CloseCustomKeyboard()
4804 {
4805 auto frameNode = GetHost();
4806 CHECK_NULL_RETURN(frameNode, false);
4807 CHECK_NULL_RETURN(keyboardOverlay_, false);
4808 keyboardOverlay_->CloseKeyboard(frameNode->GetId());
4809 isCustomKeyboardAttached_ = false;
4810 return true;
4811 }
4812
OnTextInputActionUpdate(TextInputAction value)4813 void TextFieldPattern::OnTextInputActionUpdate(TextInputAction value) {}
4814
UpdatePasswordIconColor(const Color & color)4815 void TextFieldPattern::UpdatePasswordIconColor(const Color& color)
4816 {
4817 auto passwordArea = AceType::DynamicCast<PasswordResponseArea>(responseArea_);
4818 CHECK_NULL_VOID(passwordArea);
4819 passwordArea->UpdatePasswordIconColor(color);
4820 }
4821
OnThemeScopeUpdate(int32_t themeScopeId)4822 bool TextFieldPattern::OnThemeScopeUpdate(int32_t themeScopeId)
4823 {
4824 bool result = false;
4825 bool updateFlag = true;
4826 auto host = GetHost();
4827 CHECK_NULL_RETURN(host, result);
4828 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
4829 CHECK_NULL_RETURN(paintProperty, false);
4830 auto textFieldLayoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
4831 CHECK_NULL_RETURN(textFieldLayoutProperty, false);
4832 auto pipeline = host->GetContext();
4833 CHECK_NULL_RETURN(pipeline, result);
4834 auto textFieldTheme = pipeline->GetTheme<TextFieldTheme>(themeScopeId);
4835 textFieldTheme_ = textFieldTheme;
4836 CHECK_NULL_RETURN(textFieldTheme, result);
4837
4838 if (!paintProperty->HasBackgroundColor() && !IsUnderlineMode()) {
4839 auto renderContext = host->GetRenderContext();
4840 CHECK_NULL_RETURN(renderContext, result);
4841 auto bgColor = IsInlineMode() ? textFieldTheme->GetInlineBgColor() : textFieldTheme->GetBgColor();
4842 renderContext->UpdateBackgroundColor(bgColor);
4843 result = true;
4844 }
4845
4846 if (!paintProperty->HasTextColorFlagByUser()) {
4847 textFieldLayoutProperty->UpdateTextColor(textFieldTheme->GetTextColor());
4848 result = true;
4849 }
4850
4851 if (!paintProperty->GetCaretColorFlagByUserValue(false)) {
4852 paintProperty->UpdateCursorColor(textFieldTheme->GetCursorColor());
4853 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
4854 }
4855
4856 if (result || !paintProperty->GetPlaceholderColorFlagByUserValue(false)) {
4857 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
4858 updateFlag = false;
4859 }
4860 // no interface to set password icon color, should update every time
4861 UpdatePasswordIconColor(textFieldTheme->GetSymbolColor());
4862 return updateFlag;
4863 }
4864
BeforeIMEInsertValue(const std::u16string & insertValue,int32_t offset)4865 bool TextFieldPattern::BeforeIMEInsertValue(const std::u16string& insertValue, int32_t offset)
4866 {
4867 auto host = GetHost();
4868 CHECK_NULL_RETURN(host, true);
4869 auto eventHub = host->GetEventHub<TextFieldEventHub>();
4870 CHECK_NULL_RETURN(eventHub, true);
4871 InsertValueInfo insertValueInfo;
4872 insertValueInfo.insertOffset = offset;
4873 insertValueInfo.insertValue = insertValue;
4874 return eventHub->FireOnWillInsertValueEvent(insertValueInfo);
4875 }
4876
AfterIMEInsertValue(const std::u16string & insertValue)4877 void TextFieldPattern::AfterIMEInsertValue(const std::u16string& insertValue)
4878 {
4879 auto host = GetHost();
4880 CHECK_NULL_VOID(host);
4881 auto eventHub = host->GetEventHub<TextFieldEventHub>();
4882 CHECK_NULL_VOID(eventHub);
4883 InsertValueInfo insertValueInfo;
4884 auto offset = selectController_->GetCaretIndex();
4885 insertValueInfo.insertOffset = offset;
4886 insertValueInfo.insertValue = insertValue;
4887 return eventHub->FireOnDidInsertValueEvent(insertValueInfo);
4888 }
4889
CalcCounterAfterFilterInsertValue(int32_t curLength,const std::u16string insertValue,int32_t maxLength)4890 void TextFieldPattern::CalcCounterAfterFilterInsertValue(
4891 int32_t curLength, const std::u16string insertValue, int32_t maxLength)
4892 {
4893 bool textChange = false;
4894 auto result = insertValue;
4895 contentController_->FilterTextInputStyle(textChange, result);
4896 int32_t sum = curLength + static_cast<int32_t>(result.length());
4897 showCountBorderStyle_ = sum > maxLength;
4898 HandleCountStyle();
4899 }
4900
NotifyImfFinishTextPreview()4901 void TextFieldPattern::NotifyImfFinishTextPreview()
4902 {
4903 if (!HasFocus()) {
4904 return;
4905 }
4906 #if defined(ENABLE_STANDARD_INPUT)
4907 MiscServices::InputMethodController::GetInstance()->OnSelectionChange(
4908 u"", 0, 0);
4909 TAG_LOGD(AceLogTag::ACE_TEXT_FIELD, "notify imf that textfield exit textPreview");
4910 #endif
4911 }
4912
InsertValueByController(const std::u16string & insertValue,int32_t offset)4913 int32_t TextFieldPattern::InsertValueByController(const std::u16string& insertValue, int32_t offset)
4914 {
4915 auto host = GetHost();
4916 CHECK_NULL_RETURN(host, offset);
4917 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
4918 CHECK_NULL_RETURN(layoutProperty, offset);
4919 ChangeValueInfo changeValueInfo;
4920 changeValueInfo.oldContent = GetBodyTextValue();
4921 changeValueInfo.oldPreviewText.offset = hasPreviewText_ ? GetPreviewTextStart() : -1;
4922 changeValueInfo.oldPreviewText.value = GetPreviewTextValue();
4923 changeValueInfo.rangeBefore = TextRange { offset, offset };
4924 NotifyImfFinishTextPreview();
4925 int32_t originLength =
4926 static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
4927 bool hasInsertValue =
4928 contentController_->InsertValue(offset, insertValue);
4929 changeValueInfo.previewText.offset = hasPreviewText_ ? GetPreviewTextStart() : -1;
4930 changeValueInfo.previewText.value = GetPreviewTextValue();
4931 changeValueInfo.value = contentController_->GetTextUtf16Value();
4932 changeValueInfo.rangeAfter =
4933 TextRange { offset, offset + static_cast<int32_t>(contentController_->GetInsertValue().length()) };
4934 bool isWillChange = FireOnWillChange(changeValueInfo);
4935 if (!isWillChange) {
4936 contentController_->SetTextValue(changeValueInfo.oldContent);
4937 return false;
4938 }
4939 int32_t caretMoveLength =
4940 abs(static_cast<int32_t>(contentController_->GetTextUtf16Value().length()) - originLength);
4941 if (layoutProperty->HasMaxLength()) {
4942 CalcCounterAfterFilterInsertValue(originLength, insertValue,
4943 static_cast<int32_t>(layoutProperty->GetMaxLengthValue(Infinity<uint32_t>())));
4944 }
4945 selectController_->UpdateCaretIndex(offset + caretMoveLength);
4946
4947 auto pipeline = host->GetContext();
4948 CHECK_NULL_RETURN(pipeline, offset);
4949 pipeline->AddAfterLayoutTask([weak = WeakClaim(Referenced::RawPtr(selectController_))]() {
4950 auto selectController = weak.Upgrade();
4951 CHECK_NULL_VOID(selectController);
4952 int32_t index = selectController->GetCaretIndex();
4953 selectController->MoveCaretToContentRect(index);
4954 });
4955
4956 UpdateObscure(insertValue, hasInsertValue);
4957 UpdateEditingValueToRecord();
4958 focusIndex_ = FocuseIndex::TEXT;
4959 TwinklingByFocus();
4960 CloseSelectOverlay(true);
4961 ScrollToSafeArea();
4962 ProcessResponseArea();
4963 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
4964 return selectController_->GetCaretIndex();
4965 }
4966
ExecuteInsertValueCommand(const InsertCommandInfo & info)4967 void TextFieldPattern::ExecuteInsertValueCommand(const InsertCommandInfo& info)
4968 {
4969 auto insertValue = info.insertValue;
4970 auto isIME = (info.reason == InputReason::IME);
4971 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
4972 CHECK_NULL_VOID(layoutProperty);
4973 auto start = selectController_->GetStartIndex();
4974 auto end = selectController_->GetEndIndex();
4975 auto caretStart = IsSelected() ? start : selectController_->GetCaretIndex();
4976 if (isIME) {
4977 auto isInsert = BeforeIMEInsertValue(insertValue, caretStart);
4978 CHECK_NULL_VOID(isInsert);
4979 }
4980 int32_t caretMoveLength = 0;
4981 bool hasInsertValue = false;
4982 int32_t originLength = 0;
4983 auto oldContent = contentController_->GetTextUtf16Value();
4984 auto originCaretIndex =
4985 TextRange { selectController_->GetFirstHandleIndex(), selectController_->GetSecondHandleIndex() };
4986 if (IsSelected()) {
4987 auto value = contentController_->GetSelectedValue(start, end);
4988 auto isDelete = true;
4989 if (isIME) {
4990 isDelete = BeforeIMEDeleteValue(value, TextDeleteDirection::BACKWARD, end);
4991 }
4992 end = isDelete ? end : start;
4993 originLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length()) - (end - start);
4994 hasInsertValue = contentController_->ReplaceSelectedValue(start, end, insertValue);
4995 caretMoveLength = abs(static_cast<int32_t>(contentController_->GetTextUtf16Value().length()) - originLength);
4996 bool isWillChange = OnWillChangePreInsert(contentController_->GetInsertValue(), oldContent, start, end);
4997 if (!isWillChange) {
4998 RecoverTextValueAndCaret(oldContent, originCaretIndex);
4999 return;
5000 }
5001 if (isIME && isDelete) {
5002 selectController_->UpdateCaretIndex(start);
5003 AfterIMEDeleteValue(value, TextDeleteDirection::BACKWARD);
5004 }
5005 } else {
5006 originLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
5007 hasInsertValue = contentController_->InsertValue(selectController_->GetCaretIndex(), insertValue);
5008 caretMoveLength = abs(static_cast<int32_t>(contentController_->GetTextUtf16Value().length()) - originLength);
5009 bool isWillChange = OnWillChangePreInsert(contentController_->GetInsertValue(), oldContent, start, end);
5010 if (!isWillChange) {
5011 RecoverTextValueAndCaret(oldContent, originCaretIndex);
5012 return;
5013 }
5014 }
5015 if (layoutProperty->HasMaxLength()) {
5016 CalcCounterAfterFilterInsertValue(originLength, insertValue,
5017 static_cast<int32_t>(layoutProperty->GetMaxLengthValue(Infinity<uint32_t>())));
5018 }
5019 selectController_->UpdateCaretIndex(caretStart + caretMoveLength);
5020 UpdateObscure(insertValue, hasInsertValue);
5021 UpdateEditingValueToRecord();
5022 if (isIME) {
5023 AfterIMEInsertValue(contentController_->GetInsertValue());
5024 }
5025 TwinklingByFocus();
5026 }
5027
TwinklingByFocus()5028 void TextFieldPattern::TwinklingByFocus()
5029 {
5030 if (HasFocus() && focusIndex_ == FocuseIndex::TEXT) {
5031 cursorVisible_ = true;
5032 StartTwinkling();
5033 } else {
5034 cursorVisible_ = false;
5035 StopTwinkling();
5036 }
5037 }
5038
FinishTextPreviewByPreview(const std::u16string & insertValue)5039 bool TextFieldPattern::FinishTextPreviewByPreview(const std::u16string& insertValue)
5040 {
5041 if (GetIsPreviewText()) {
5042 PreviewTextInfo info = {
5043 .text = insertValue,
5044 .range = { -1, -1 },
5045 .isIme = false
5046 };
5047 inputOperations_.emplace(InputOperation::SET_PREVIEW_TEXT);
5048 previewTextOperation_.emplace(info);
5049 FinishTextPreview();
5050 return true;
5051 }
5052 return false;
5053 }
5054
UpdateObscure(const std::u16string & insertValue,bool hasInsertValue)5055 void TextFieldPattern::UpdateObscure(const std::u16string& insertValue, bool hasInsertValue)
5056 {
5057 if (!IsTextArea() && IsInPasswordMode() && GetTextObscured()) {
5058 auto host = GetHost();
5059 CHECK_NULL_VOID(host);
5060 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
5061 CHECK_NULL_VOID(layoutProperty);
5062 if (insertValue.length() == 1 &&
5063 (layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED) != TextInputType::NUMBER_PASSWORD ||
5064 std::isdigit(insertValue[0])) &&
5065 hasInsertValue) {
5066 auto content = contentController_->GetTextUtf16Value();
5067 auto insertIndex = selectController_->GetCaretIndex() - 1;
5068 insertIndex = std::clamp(insertIndex, 0, static_cast<int32_t>(content.length()));
5069 auto strBeforeCaret = content.empty() ? u"" : content.substr(insertIndex, 1);
5070 obscureTickCountDown_ = strBeforeCaret == insertValue ? OBSCURE_SHOW_TICKS : 0;
5071 nakedCharPosition_ = strBeforeCaret == insertValue ? insertIndex : -1;
5072 } else {
5073 obscureTickCountDown_ = 0;
5074 nakedCharPosition_ = -1;
5075 }
5076 }
5077 }
5078
InsertValue(const std::u16string & insertValue,bool isIME)5079 void TextFieldPattern::InsertValue(const std::u16string& insertValue, bool isIME)
5080 {
5081 InputReason reason = isIME ? InputReason::IME : InputReason::NONE;
5082 AddInsertCommand(insertValue, reason);
5083 }
5084
InsertValue(const std::string & insertValue,bool isIME)5085 void TextFieldPattern::InsertValue(const std::string& insertValue, bool isIME)
5086 {
5087 InsertValue(UtfUtils::Str8DebugToStr16(insertValue), isIME);
5088 }
5089
UltralimitShake()5090 void TextFieldPattern::UltralimitShake()
5091 {
5092 auto frameNode = GetHost();
5093 CHECK_NULL_VOID(frameNode);
5094 auto context = frameNode->GetRenderContext();
5095 CHECK_NULL_VOID(context);
5096 AnimationOption option;
5097 context->UpdateTranslateInXY({ -1.0, 0.0 });
5098 const RefPtr<InterpolatingSpring> curve =
5099 AceType::MakeRefPtr<InterpolatingSpring>(VELOCITY, MASS, STIFFNESS, DAMPING);
5100 option.SetCurve(curve);
5101 option.SetFillMode(FillMode::FORWARDS);
5102 auto pipelineContext = frameNode->GetContext();
5103 CHECK_NULL_VOID(pipelineContext);
5104 AnimationUtils::Animate(
5105 option,
5106 [weak = WeakClaim(Referenced::RawPtr(context))]() {
5107 auto context = weak.Upgrade();
5108 CHECK_NULL_VOID(context);
5109 context->UpdateTranslateInXY({ 0.0f, 0.0f });
5110 },
5111 option.GetOnFinishEvent());
5112 }
5113
AdjustFloatingCaretInfo(const Offset & localOffset,const HandleInfoNG & caretInfo,HandleInfoNG & floatingCaretInfo)5114 void TextFieldPattern::AdjustFloatingCaretInfo(const Offset& localOffset,
5115 const HandleInfoNG& caretInfo, HandleInfoNG& floatingCaretInfo)
5116 {
5117 CHECK_NULL_VOID(selectController_);
5118 auto offsetX = localOffset.GetX();
5119 auto offsetY = caretInfo.rect.Top();
5120 floatingCaretInfo.rect.SetHeight(caretInfo.rect.Height());
5121 auto contentRect = GetTextContentRect();
5122 offsetX = std::min(std::max(contentRect.Left(), static_cast<float>(offsetX)),
5123 contentRect.Right() - caretInfo.rect.Width());
5124 offsetY = std::min(std::max(contentRect.Top(), static_cast<float>(offsetY)),
5125 contentRect.Bottom() - floatingCaretInfo.rect.Height());
5126 floatingCaretInfo.UpdateOffset({offsetX, offsetY});
5127 bool reachBoundary = NearEqual(contentRect.Left(), offsetX) ||
5128 NearEqual(contentRect.Right() - caretInfo.rect.Width(), static_cast<float>(offsetX));
5129 bool distanceMoreThenTenVp = floatingCaretInfo.rect.GetOffset().GetDistance(caretInfo.rect.GetOffset())
5130 >= FLOATING_CARET_SHOW_ORIGIN_CARET_DISTANCE.ConvertToPx();
5131 TouchPosition pos = selectController_->GetTouchLinePos(localOffset);
5132 bool FloatCursorOnOriginLeft = floatingCaretInfo.rect.GetX() < caretInfo.rect.GetX();
5133 bool FloatCursorNotInText = ((pos == TouchPosition::LEFT && FloatCursorOnOriginLeft) ||
5134 (pos == TouchPosition::RIGHT && !FloatCursorOnOriginLeft));
5135 SetShowOriginCursor((reachBoundary || distanceMoreThenTenVp) && FloatCursorNotInText);
5136 SetFloatingCursorVisible(true);
5137 }
5138
FloatingCaretLand()5139 void TextFieldPattern::FloatingCaretLand()
5140 {
5141 CHECK_NULL_VOID(floatCaretState_.FloatingCursorVisible && textFieldOverlayModifier_ && selectController_);
5142 textFieldOverlayModifier_->StartFloatingCaretLand(selectController_->GetCaretRect().GetOffset());
5143 }
5144
CleanCounterNode()5145 void TextFieldPattern::CleanCounterNode()
5146 {
5147 counterDecorator_.Reset();
5148 }
5149
CleanErrorNode()5150 void TextFieldPattern::CleanErrorNode()
5151 {
5152 errorDecorator_.Reset();
5153 }
5154
UpdateEditingValueToRecord(int32_t beforeCaretPosition)5155 void TextFieldPattern::UpdateEditingValueToRecord(int32_t beforeCaretPosition)
5156 {
5157 if (operationRecords_.size() >= RECORD_MAX_LENGTH) {
5158 operationRecords_.erase(operationRecords_.begin());
5159 }
5160 TextEditingValueNG record {
5161 .text = contentController_->GetTextUtf16Value(),
5162 .caretPosition = selectController_->GetCaretIndex(),
5163 .beforeCaretPosition = beforeCaretPosition,
5164 };
5165 operationRecords_.emplace_back(record);
5166 }
5167
PreferredTextHeight(bool isPlaceholder,bool isAlgorithmMeasure)5168 float TextFieldPattern::PreferredTextHeight(bool isPlaceholder, bool isAlgorithmMeasure)
5169 {
5170 if (!isAlgorithmMeasure && paragraph_ && paragraph_->GetHeight() != 0.0f && paragraph_->GetLineCount() > 0) {
5171 return paragraph_->GetHeight() / paragraph_->GetLineCount();
5172 }
5173 RefPtr<Paragraph> paragraph;
5174 std::u16string textContent;
5175 TextStyle textStyle;
5176 auto tmpHost = GetHost();
5177 CHECK_NULL_RETURN(tmpHost, 0.0f);
5178 auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
5179 CHECK_NULL_RETURN(layoutProperty, 0.0f);
5180 auto textFieldTheme = GetTheme();
5181 CHECK_NULL_RETURN(textFieldTheme, 0.0f);
5182 // use text or placeHolder value if exists, space otherwise
5183 if (!isPlaceholder) {
5184 TextFieldLayoutAlgorithm::UpdateTextStyle(tmpHost, layoutProperty, textFieldTheme, textStyle, false);
5185 textContent = u"a";
5186 } else {
5187 TextFieldLayoutAlgorithm::UpdatePlaceholderTextStyle(tmpHost, layoutProperty, textFieldTheme, textStyle, false);
5188 textContent = u"b";
5189 }
5190 if (adaptFontSize_.has_value()) {
5191 textStyle.SetFontSize(adaptFontSize_.value());
5192 }
5193 if (textStyle.GetFontSize().IsNonPositive()) {
5194 textStyle.SetFontSize(DEFAULT_FONT);
5195 }
5196 if (textStyle.GetLineHeight().IsNegative()) {
5197 textStyle.SetLineHeight(Dimension(0.0));
5198 }
5199 ParagraphStyle paraStyle { .direction =
5200 TextFieldLayoutAlgorithm::GetTextDirection(contentController_->GetTextUtf16Value()),
5201 .align = textStyle.GetTextAlign(),
5202 .maxLines = textStyle.GetMaxLines(),
5203 .fontLocale = Localization::GetInstance()->GetFontLocale(),
5204 .wordBreak = textStyle.GetWordBreak(),
5205 .ellipsisMode = textStyle.GetEllipsisMode(),
5206 .lineBreakStrategy = textStyle.GetLineBreakStrategy(),
5207 .textOverflow = textStyle.GetTextOverflow(),
5208 .fontSize = FontSizeConvertToPx(textStyle.GetFontSize()) };
5209 paragraph = Paragraph::Create(paraStyle, FontCollection::Current());
5210 CHECK_NULL_RETURN(paragraph, 0.0f);
5211 paragraph->PushStyle(textStyle);
5212 UtfUtils::HandleInvalidUTF16(reinterpret_cast<uint16_t*>(textContent.data()), textContent.length(), 0);
5213 paragraph->AddText(textContent);
5214 paragraph->Build();
5215 paragraph->Layout(std::numeric_limits<double>::infinity());
5216 return paragraph->GetHeight();
5217 }
5218
FontSizeConvertToPx(const Dimension & fontSize)5219 float TextFieldPattern::FontSizeConvertToPx(const Dimension& fontSize)
5220 {
5221 return fontSize.ConvertToPx();
5222 }
5223
PreferredLineHeight(bool isAlgorithmMeasure)5224 float TextFieldPattern::PreferredLineHeight(bool isAlgorithmMeasure)
5225 {
5226 return PreferredTextHeight(contentController_->IsEmpty(), isAlgorithmMeasure);
5227 }
5228
OnCursorMoveDone(TextAffinity textAffinity,std::optional<Offset> offset)5229 void TextFieldPattern::OnCursorMoveDone(TextAffinity textAffinity, std::optional<Offset> offset)
5230 {
5231 auto tmpHost = GetHost();
5232 CHECK_NULL_VOID(tmpHost);
5233 StartTwinkling();
5234 CloseSelectOverlay();
5235 if (offset.has_value()) {
5236 selectController_->UpdateCaretInfoByOffset(offset.value());
5237 } else {
5238 selectController_->MoveCaretToContentRect(GetCaretIndex(), textAffinity);
5239 }
5240 if (ResetObscureTickCountDown()) {
5241 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
5242 } else {
5243 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
5244 }
5245 UpdateCaretInfoToController();
5246 }
5247
GetWordLength(int32_t originCaretPosition,int32_t directionMove,bool skipNewLineChar)5248 int32_t TextFieldPattern::GetWordLength(int32_t originCaretPosition, int32_t directionMove, bool skipNewLineChar)
5249 {
5250 if (contentController_->IsEmpty()) {
5251 return 0;
5252 }
5253 int32_t textLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
5254 if (originCaretPosition < 0 || originCaretPosition > textLength) {
5255 return 0;
5256 }
5257 // directionMove == 0 left, directionMove == 1 right
5258 // cannot get word length by current caret position and direction
5259 if ((directionMove == 0 && originCaretPosition == 0) || (directionMove == 1 && originCaretPosition == textLength)) {
5260 return 0;
5261 }
5262 int32_t offset = 0;
5263 int32_t strIndex = directionMove == 0 ? (originCaretPosition - 1) : originCaretPosition;
5264 auto wideTextValue = contentController_->GetTextUtf16Value();
5265 int32_t wordStart = 0;
5266 int32_t wordEnd = 0;
5267 while (directionMove == 0 ? strIndex >= 0 : strIndex <= textLength) {
5268 auto chr = wideTextValue[strIndex];
5269 // skip the special character
5270 if (chr == L' ' || (chr == L'\n' && skipNewLineChar)) {
5271 if (directionMove == 0) {
5272 strIndex--;
5273 } else {
5274 strIndex++;
5275 }
5276 offset++;
5277 continue;
5278 }
5279 // cal word length
5280 if (paragraph_ && paragraph_->GetWordBoundary(strIndex, wordStart, wordEnd)) {
5281 if (directionMove == 1) {
5282 offset += (wordEnd - strIndex);
5283 } else {
5284 offset += (strIndex - wordStart + 1); // when move left, actual offset should add 1
5285 }
5286 return std::clamp(offset, 0, textLength);
5287 }
5288 // GetWordBoundary fail
5289 return 0;
5290 }
5291 return std::clamp(offset, 0, textLength);
5292 }
5293
GetLineBeginPosition(int32_t originCaretPosition,bool needToCheckLineChanged)5294 int32_t TextFieldPattern::GetLineBeginPosition(int32_t originCaretPosition, bool needToCheckLineChanged)
5295 {
5296 if (contentController_->IsEmpty()) {
5297 return 0;
5298 }
5299 auto wideTextValue = contentController_->GetTextUtf16Value();
5300 int32_t textLength = static_cast<int32_t>(wideTextValue.length());
5301 if (originCaretPosition < 0 || originCaretPosition > textLength) {
5302 return 0;
5303 }
5304 if (originCaretPosition == 0) {
5305 return originCaretPosition;
5306 }
5307 int32_t moveLineBeginOffset = 0;
5308 int32_t strIndex = originCaretPosition;
5309 do {
5310 moveLineBeginOffset++;
5311 strIndex--;
5312 // stop moving caret if reaches \n, text head or caret line changed
5313 } while (((strIndex > 0) && (wideTextValue[strIndex] != u'\n')) &&
5314 (needToCheckLineChanged ? !CharLineChanged(strIndex) : true));
5315 if (strIndex < 0 || strIndex >= static_cast<int32_t>(wideTextValue.length())) {
5316 return 0;
5317 }
5318 if (strIndex > 0) {
5319 moveLineBeginOffset--;
5320 }
5321 if (moveLineBeginOffset > originCaretPosition) {
5322 return 0;
5323 }
5324 return originCaretPosition - moveLineBeginOffset;
5325 }
5326
GetLineEndPosition(int32_t originCaretPosition,bool needToCheckLineChanged)5327 int32_t TextFieldPattern::GetLineEndPosition(int32_t originCaretPosition, bool needToCheckLineChanged)
5328 {
5329 if (contentController_->IsEmpty()) {
5330 return 0;
5331 }
5332 auto wideTextValue = contentController_->GetTextUtf16Value();
5333 int32_t textLength = static_cast<int32_t>(wideTextValue.length());
5334 if (originCaretPosition < 0 || originCaretPosition > textLength) {
5335 return originCaretPosition;
5336 }
5337 if (originCaretPosition == textLength) {
5338 return originCaretPosition;
5339 }
5340 int32_t moveLineEndOffset = 0;
5341 int32_t strIndex = 0;
5342 for (strIndex = originCaretPosition; (strIndex <= textLength && wideTextValue[strIndex] != u'\n') &&
5343 (needToCheckLineChanged ? !CharLineChanged(strIndex) : true);
5344 strIndex++) {
5345 moveLineEndOffset++;
5346 }
5347 if (moveLineEndOffset > textLength - originCaretPosition) {
5348 return textLength;
5349 }
5350 return originCaretPosition + moveLineEndOffset;
5351 }
5352
CharLineChanged(int32_t caretPosition)5353 bool TextFieldPattern::CharLineChanged(int32_t caretPosition)
5354 {
5355 if (caretPosition < 0 || caretPosition > static_cast<int32_t>(contentController_->GetTextUtf16Value().length())) {
5356 return true;
5357 }
5358 CaretMetricsF caretMetrics;
5359 CalcCaretMetricsByPosition(caretPosition, caretMetrics);
5360 // the cursor is aligned with the text at the bottom
5361 return !NearEqual(caretMetrics.offset.GetY() + caretMetrics.height,
5362 selectController_->GetCaretRect().GetY() + selectController_->GetCaretRect().Height());
5363 }
5364
CursorMoveLeftOperation()5365 bool TextFieldPattern::CursorMoveLeftOperation()
5366 {
5367 if (focusIndex_ != FocuseIndex::TEXT) {
5368 return UpdateFocusBackward();
5369 }
5370 auto originCaretPosition = selectController_->GetCaretIndex();
5371 if (IsSelected()) {
5372 selectController_->UpdateCaretIndex(selectController_->GetStartIndex());
5373 CloseSelectOverlay();
5374 } else {
5375 UpdateCaretPositionWithClamp(
5376 selectController_->GetCaretIndex() -
5377 GetGraphemeClusterLength(contentController_->GetTextUtf16Value(), selectController_->GetCaretIndex(),
5378 true));
5379 }
5380 OnCursorMoveDone(TextAffinity::DOWNSTREAM);
5381 return originCaretPosition != selectController_->GetCaretIndex();
5382 }
5383
CursorMoveLeft()5384 bool TextFieldPattern::CursorMoveLeft()
5385 {
5386 if (inputOperations_.empty()) {
5387 return CursorMoveLeftOperation();
5388 }
5389
5390 inputOperations_.emplace(InputOperation::CURSOR_LEFT);
5391 return false;
5392 }
5393
CursorMoveLeftWord()5394 bool TextFieldPattern::CursorMoveLeftWord()
5395 {
5396 if (selectController_->GetCaretIndex() == 0) {
5397 return true;
5398 }
5399 int32_t originCaretPosition = selectController_->GetCaretIndex();
5400 int32_t textLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
5401 int32_t leftWordLength = GetWordLength(originCaretPosition, 0);
5402 if (leftWordLength < 0 || leftWordLength > textLength || selectController_->GetCaretIndex() - leftWordLength < 0) {
5403 return false;
5404 }
5405 if (IsSelected()) {
5406 selectController_->UpdateCaretIndex(selectController_->GetSecondHandleIndex() - leftWordLength);
5407 CloseSelectOverlay();
5408 } else {
5409 UpdateCaretPositionWithClamp(originCaretPosition - leftWordLength);
5410 }
5411 OnCursorMoveDone();
5412 return originCaretPosition != selectController_->GetCaretIndex();
5413 }
5414
CursorMoveLineBegin()5415 bool TextFieldPattern::CursorMoveLineBegin()
5416 {
5417 if (selectController_->GetCaretIndex() == 0 && !IsSelected()) {
5418 return true;
5419 }
5420 int32_t textLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
5421 int32_t originCaretPosition = selectController_->GetCaretIndex();
5422 int32_t lineBeginPosition = GetLineBeginPosition(originCaretPosition);
5423 if (lineBeginPosition < 0 || lineBeginPosition > textLength) {
5424 return false;
5425 }
5426 if (selectController_->IsSelectedAll()) {
5427 selectController_->UpdateCaretIndex(0);
5428 } else if (IsTextArea()) {
5429 UpdateCaretPositionWithClamp(lineBeginPosition);
5430 } else {
5431 UpdateCaretPositionWithClamp(0);
5432 }
5433 OnCursorMoveDone(TextAffinity::DOWNSTREAM);
5434 return originCaretPosition != selectController_->GetCaretIndex();
5435 }
5436
CursorMoveToParagraphBegin()5437 bool TextFieldPattern::CursorMoveToParagraphBegin()
5438 {
5439 if (selectController_->GetCaretIndex() == 0) {
5440 return true;
5441 }
5442 auto originCaretPosition = selectController_->GetCaretIndex();
5443 auto newPos = GetLineBeginPosition(originCaretPosition, false);
5444 if (newPos == originCaretPosition && originCaretPosition > 0) {
5445 newPos = GetLineBeginPosition(originCaretPosition - 1, false);
5446 }
5447 UpdateCaretPositionWithClamp(newPos);
5448 OnCursorMoveDone(TextAffinity::DOWNSTREAM);
5449 return originCaretPosition != selectController_->GetCaretIndex();
5450 }
5451
CursorMoveHome()5452 bool TextFieldPattern::CursorMoveHome()
5453 {
5454 // ctrl + home, caret move to position 0
5455 if (selectController_->GetCaretIndex() == 0) {
5456 return true;
5457 }
5458 int32_t originCaretPosition = selectController_->GetCaretIndex();
5459 UpdateCaretPositionWithClamp(0);
5460 OnCursorMoveDone();
5461 return originCaretPosition != selectController_->GetCaretIndex();
5462 }
5463
CursorMoveRightOperation()5464 bool TextFieldPattern::CursorMoveRightOperation()
5465 {
5466 if (focusIndex_ != FocuseIndex::TEXT) {
5467 return UpdateFocusForward();
5468 }
5469 auto originCaretPosition = selectController_->GetCaretIndex();
5470 if (IsSelected()) {
5471 CloseSelectOverlay();
5472 selectController_->UpdateCaretIndex(selectController_->GetEndIndex());
5473 } else {
5474 UpdateCaretPositionWithClamp(
5475 selectController_->GetCaretIndex() +
5476 GetGraphemeClusterLength(contentController_->GetTextUtf16Value(), selectController_->GetCaretIndex()));
5477 }
5478 OnCursorMoveDone(TextAffinity::DOWNSTREAM);
5479 return originCaretPosition != selectController_->GetCaretIndex();
5480 }
5481
CursorMoveRight()5482 bool TextFieldPattern::CursorMoveRight()
5483 {
5484 if (inputOperations_.empty()) {
5485 return CursorMoveRightOperation();
5486 }
5487 inputOperations_.emplace(InputOperation::CURSOR_RIGHT);
5488 return false;
5489 }
5490
CursorMoveRightWord()5491 bool TextFieldPattern::CursorMoveRightWord()
5492 {
5493 if (selectController_->GetCaretIndex() == static_cast<int32_t>(contentController_->GetTextUtf16Value().length())) {
5494 return true;
5495 }
5496 int32_t originCaretPosition = selectController_->GetCaretIndex();
5497 int32_t textLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
5498 int32_t rightWordLength = GetWordLength(originCaretPosition, 1);
5499 if (rightWordLength < 0 || rightWordLength > textLength ||
5500 rightWordLength + selectController_->GetCaretIndex() > textLength) {
5501 return false;
5502 }
5503 if (selectController_->IsSelectedAll()) {
5504 selectController_->UpdateCaretIndex(textLength);
5505 } else {
5506 UpdateCaretPositionWithClamp(originCaretPosition + rightWordLength);
5507 }
5508 OnCursorMoveDone();
5509 return originCaretPosition != selectController_->GetCaretIndex();
5510 }
5511
CursorMoveLineEnd()5512 bool TextFieldPattern::CursorMoveLineEnd()
5513 {
5514 if (selectController_->GetCaretIndex() == static_cast<int32_t>(contentController_->GetTextUtf16Value().length()) &&
5515 !IsSelected()) {
5516 return true;
5517 }
5518 int32_t originCaretPosition = selectController_->GetCaretIndex();
5519 int32_t textLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
5520 int32_t lineEndPosition = GetLineEndPosition(originCaretPosition);
5521 if (lineEndPosition < 0 || lineEndPosition > textLength) {
5522 return false;
5523 }
5524 if (selectController_->IsSelectedAll()) {
5525 selectController_->UpdateCaretIndex(textLength);
5526 } else if (IsTextArea()) {
5527 UpdateCaretPositionWithClamp(lineEndPosition);
5528 } else {
5529 UpdateCaretPositionWithClamp(textLength);
5530 }
5531 OnCursorMoveDone();
5532 return originCaretPosition != selectController_->GetCaretIndex();
5533 }
5534
CursorMoveToParagraphEnd()5535 bool TextFieldPattern::CursorMoveToParagraphEnd()
5536 {
5537 if (selectController_->GetCaretIndex() == static_cast<int32_t>(contentController_->GetTextUtf16Value().length())) {
5538 return true;
5539 }
5540 auto originCaretPosition = selectController_->GetCaretIndex();
5541 auto newPos = GetLineEndPosition(originCaretPosition, false);
5542 if (newPos == originCaretPosition && originCaretPosition > 0) {
5543 newPos = GetLineEndPosition(originCaretPosition + 1, false);
5544 }
5545 UpdateCaretPositionWithClamp(newPos);
5546 OnCursorMoveDone(TextAffinity::DOWNSTREAM);
5547 return originCaretPosition != selectController_->GetCaretIndex();
5548 }
5549
CursorMoveEnd()5550 bool TextFieldPattern::CursorMoveEnd()
5551 {
5552 // ctrl end, caret to the very end
5553 if (selectController_->GetCaretIndex() == static_cast<int32_t>(contentController_->GetTextUtf16Value().length())) {
5554 return true;
5555 }
5556 int32_t originCaretPosition = selectController_->GetCaretIndex();
5557 int32_t textLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
5558 UpdateCaretPositionWithClamp(textLength);
5559 OnCursorMoveDone();
5560 return originCaretPosition != selectController_->GetCaretIndex();
5561 }
5562
CursorMoveUpOperation()5563 bool TextFieldPattern::CursorMoveUpOperation()
5564 {
5565 if (!IsTextArea() && !IsSelected()) {
5566 return CursorMoveToParagraphBegin();
5567 }
5568 auto originCaretPosition = selectController_->GetCaretIndex();
5569 auto offsetX = selectController_->GetCaretRect().GetX();
5570 // multiply by 0.5f to convert to the grapheme center point of the previous line.
5571 float lineHeight = PreferredLineHeight() * 0.5f;
5572 auto offsetY = selectController_->GetCaretRect().GetY() - lineHeight;
5573 if (offsetY < textRect_.GetY() && !IsSelected()) {
5574 return CursorMoveToParagraphBegin();
5575 }
5576 std::optional<Offset> offset;
5577 offset.emplace(Offset(offsetX, offsetY));
5578 OnCursorMoveDone(TextAffinity::DOWNSTREAM, offset);
5579 return originCaretPosition != selectController_->GetCaretIndex();
5580 }
5581
CursorMoveUp()5582 bool TextFieldPattern::CursorMoveUp()
5583 {
5584 if (inputOperations_.empty()) {
5585 return CursorMoveUpOperation();
5586 }
5587
5588 inputOperations_.emplace(InputOperation::CURSOR_UP);
5589 return false;
5590 }
5591
CursorMoveDownOperation()5592 bool TextFieldPattern::CursorMoveDownOperation()
5593 {
5594 if (!IsTextArea() && !IsSelected()) {
5595 return CursorMoveToParagraphEnd();
5596 }
5597 auto originCaretPosition = selectController_->GetCaretIndex();
5598 auto offsetX = selectController_->GetCaretRect().GetX();
5599 // multiply by 1.5f to convert to the grapheme center point of the next line.
5600 float lineHeight = PreferredLineHeight() * 1.5f;
5601 auto offsetY = selectController_->GetCaretRect().GetY() + lineHeight;
5602 if (offsetY > textRect_.GetY() + textRect_.Height() && !IsSelected()) {
5603 return CursorMoveToParagraphEnd();
5604 }
5605 std::optional<Offset> offset;
5606 offset.emplace(Offset(offsetX, offsetY));
5607 OnCursorMoveDone(TextAffinity::DOWNSTREAM, offset);
5608 return originCaretPosition != selectController_->GetCaretIndex();
5609 }
5610
CursorMoveDown()5611 bool TextFieldPattern::CursorMoveDown()
5612 {
5613 if (inputOperations_.empty()) {
5614 return CursorMoveDownOperation();
5615 }
5616
5617 inputOperations_.emplace(InputOperation::CURSOR_DOWN);
5618 return false;
5619 }
5620
Delete(int32_t start,int32_t end)5621 void TextFieldPattern::Delete(int32_t start, int32_t end)
5622 {
5623 SwapIfLarger(start, end);
5624 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "Handle Delete within [%{public}d, %{public}d]", start, end);
5625 contentController_->erase(start, end - start);
5626 UpdateSelection(start);
5627 selectController_->MoveCaretToContentRect(start);
5628 if (isLongPress_) {
5629 CancelGestureSelection();
5630 }
5631 CloseSelectOverlay(true);
5632 StartTwinkling();
5633 UpdateEditingValueToRecord();
5634 auto tmpHost = GetHost();
5635 CHECK_NULL_VOID(tmpHost);
5636 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
5637 }
5638
HandleCounterBorder()5639 void TextFieldPattern::HandleCounterBorder()
5640 {
5641 auto theme = GetTheme();
5642 CHECK_NULL_VOID(theme);
5643 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
5644 CHECK_NULL_VOID(paintProperty);
5645 auto host = GetHost();
5646 CHECK_NULL_VOID(host);
5647 auto renderContext = host->GetRenderContext();
5648 CHECK_NULL_VOID(renderContext);
5649 if (showCountBorderStyle_) {
5650 if (IsUnderlineMode()) {
5651 underlineWidth_ = ERROR_UNDERLINE_WIDTH;
5652 SetUnderlineColor(userUnderlineColor_.error.value_or(theme->GetErrorUnderlineColor()));
5653 } else {
5654 if (!paintProperty->HasBorderWidthFlagByUser()) {
5655 paintProperty->UpdateInnerBorderWidth(OVER_COUNT_BORDER_WIDTH);
5656 paintProperty->UpdateInnerBorderColor(theme->GetOverCounterColor());
5657 } else {
5658 BorderColorProperty overCountBorderColor;
5659 overCountBorderColor.SetColor(theme->GetOverCounterColor());
5660 renderContext->UpdateBorderColor(overCountBorderColor);
5661 }
5662 }
5663 } else {
5664 if (IsUnderlineMode() && !IsShowError()) {
5665 ApplyUnderlineTheme();
5666 CHECK_NULL_VOID(counterDecorator_);
5667 counterDecorator_->UpdateTextFieldMargin();
5668 } else {
5669 SetThemeBorderAttr();
5670 }
5671 }
5672 }
5673
ProcessFocusIndexAction()5674 bool TextFieldPattern::ProcessFocusIndexAction()
5675 {
5676 if (focusIndex_ == FocuseIndex::CANCEL) {
5677 CleanNodeResponseKeyEvent();
5678 return false;
5679 }
5680 if (focusIndex_ == FocuseIndex::UNIT) {
5681 if (IsShowPasswordIcon()) {
5682 PasswordResponseKeyEvent();
5683 }
5684 if (IsShowUnit()) {
5685 UnitResponseKeyEvent();
5686 }
5687 return false;
5688 }
5689 return true;
5690 }
5691
PerformAction(TextInputAction action,bool forceCloseKeyboard)5692 void TextFieldPattern::PerformAction(TextInputAction action, bool forceCloseKeyboard)
5693 {
5694 if (!ProcessFocusIndexAction()) {
5695 return;
5696 }
5697 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "TextField PerformAction %{public}d", static_cast<int32_t>(action));
5698 auto host = GetHost();
5699 CHECK_NULL_VOID(host);
5700 // If the parent node is a Search, the Search callback is executed.
5701 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
5702 CHECK_NULL_VOID(paintProperty);
5703 auto eventHub = host->GetEventHub<TextFieldEventHub>();
5704 CHECK_NULL_VOID(eventHub);
5705 TextFieldCommonEvent event;
5706 event.SetText(contentController_->GetTextUtf16Value());
5707 if (IsNormalInlineState() && action != TextInputAction::NEW_LINE) {
5708 RecordSubmitEvent();
5709 eventHub->FireOnSubmit(static_cast<int32_t>(action), event);
5710 if (event.IsKeepEditable()) {
5711 return;
5712 }
5713 TextFieldLostFocusToViewRoot();
5714 return;
5715 }
5716 if (IsTextArea() && action == TextInputAction::NEW_LINE) {
5717 if (!textAreaBlurOnSubmit_) {
5718 if (GetInputFilter() != "\n") {
5719 InsertValue(u"\n", true);
5720 }
5721 } else {
5722 CloseKeyboard(forceCloseKeyboard, false);
5723 TextFieldLostFocusToViewRoot();
5724 }
5725 return;
5726 }
5727 eventHub->FireOnSubmit(static_cast<int32_t>(action), event);
5728 RecordSubmitEvent();
5729 if (event.IsKeepEditable()) {
5730 return;
5731 }
5732 // LostFocusToViewRoot may not cause current lost focus, only stop twinkling when it is truly lost focus,
5733 // which will call StopTwinkling on HandleBlurEvent method.
5734 if (textInputBlurOnSubmit_) {
5735 HandleCloseKeyboard(forceCloseKeyboard);
5736 }
5737 UiSessionManager::GetInstance()->ReportComponentChangeEvent("event", "Textfield.onSubmit");
5738 }
5739
TextFieldLostFocusToViewRoot()5740 void TextFieldPattern::TextFieldLostFocusToViewRoot()
5741 {
5742 CHECK_NULL_VOID(HasFocus());
5743 FocusHub::LostFocusToViewRoot();
5744 }
5745
RecordSubmitEvent() const5746 void TextFieldPattern::RecordSubmitEvent() const
5747 {
5748 if (!Recorder::EventRecorder::Get().IsComponentRecordEnable()) {
5749 return;
5750 }
5751 auto host = GetHost();
5752 CHECK_NULL_VOID(host);
5753 auto inspectorId = host->GetInspectorId().value_or("");
5754 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
5755 bool isPwdType = layoutProperty ? layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED) ==
5756 TextInputType::VISIBLE_PASSWORD
5757 : false;
5758 Recorder::EventParamsBuilder builder;
5759 builder.SetId(inspectorId)
5760 .SetType(host->GetTag())
5761 .SetEventType(Recorder::EventType::SEARCH_SUBMIT)
5762 .SetHost(host)
5763 .SetDescription(host->GetAutoEventParamValue(""));
5764 if (!isPwdType) {
5765 builder.SetText(contentController_->GetTextValue());
5766 }
5767 Recorder::EventRecorder::Get().OnEvent(std::move(builder));
5768 }
5769
UpdateEditingValue(const std::shared_ptr<TextEditingValue> & value,bool needFireChangeEvent)5770 void TextFieldPattern::UpdateEditingValue(const std::shared_ptr<TextEditingValue>& value, bool needFireChangeEvent)
5771 {
5772 #if !defined(ENABLE_STANDARD_INPUT)
5773 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
5774 if (layoutProperty && layoutProperty->HasMaxLength()) {
5775 bool textChange = false;
5776 auto result = UtfUtils::Str8DebugToStr16(value->text);
5777 contentController_->FilterTextInputStyle(textChange, result);
5778 auto resultLen = static_cast<int32_t>(result.length());
5779 auto maxLen = static_cast<int32_t>(layoutProperty->GetMaxLengthValue(Infinity<uint32_t>()));
5780 if (resultLen != maxLen) {
5781 showCountBorderStyle_ = resultLen > maxLen;
5782 HandleCountStyle();
5783 }
5784 }
5785 #endif
5786
5787 UpdateEditingValueToRecord();
5788 contentController_->SetTextValue(UtfUtils::Str8DebugToStr16(value->text));
5789 selectController_->UpdateCaretIndex(value->selection.baseOffset);
5790 ContainerScope scope(GetInstanceId());
5791 CloseSelectOverlay();
5792 StartTwinkling();
5793 auto host = GetHost();
5794 CHECK_NULL_VOID(host);
5795
5796 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
5797 }
5798
UpdateInputFilterErrorText(const std::u16string & errorText)5799 void TextFieldPattern::UpdateInputFilterErrorText(const std::u16string& errorText)
5800 {
5801 if (!errorText.empty()) {
5802 auto tmpHost = GetHost();
5803 CHECK_NULL_VOID(tmpHost);
5804 auto textFieldEventHub = tmpHost->GetEventHub<TextFieldEventHub>();
5805 CHECK_NULL_VOID(textFieldEventHub);
5806 textFieldEventHub->FireOnInputFilterError(errorText);
5807 }
5808 }
5809
UpdateInputFilterErrorText(const std::string & errorText)5810 void TextFieldPattern::UpdateInputFilterErrorText(const std::string& errorText)
5811 {
5812 UpdateInputFilterErrorText(UtfUtils::Str8DebugToStr16(errorText));
5813 }
5814
OnValueChanged(bool needFireChangeEvent,bool needFireSelectChangeEvent)5815 void TextFieldPattern::OnValueChanged(bool needFireChangeEvent, bool needFireSelectChangeEvent) {}
5816
OnHandleAreaChanged()5817 void TextFieldPattern::OnHandleAreaChanged()
5818 {
5819 auto parentGlobalOffset = GetPaintRectGlobalOffset();
5820 if (parentGlobalOffset != parentGlobalOffset_) {
5821 parentGlobalOffset_ = parentGlobalOffset;
5822 UpdateTextFieldManager(Offset(parentGlobalOffset_.GetX(), parentGlobalOffset_.GetY()), frameRect_.Height());
5823 HandleParentGlobalOffsetChange();
5824 }
5825 }
5826
HandleParentGlobalOffsetChange()5827 void TextFieldPattern::HandleParentGlobalOffsetChange()
5828 {
5829 selectController_->CalculateHandleOffset();
5830 CHECK_NULL_VOID(SelectOverlayIsOn() || selectOverlay_->SelectOverlayIsCreating());
5831 if (selectOverlay_->IsShowMouseMenu()) {
5832 CloseSelectOverlay();
5833 return;
5834 }
5835 if (selectOverlay_->IsHiddenHandle() && selectOverlay_->IsSingleHandle()) {
5836 selectOverlay_->ProcessOverlayOnAreaChanged({ .menuIsShow = false });
5837 } else {
5838 selectOverlay_->ProcessOverlay({ .menuIsShow = false });
5839 }
5840 }
5841
RequestKeyboardByFocusSwitch()5842 void TextFieldPattern::RequestKeyboardByFocusSwitch()
5843 {
5844 auto host = GetHost();
5845 CHECK_NULL_VOID(host);
5846 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD,
5847 "%{public}d RequestKeyboardByFocusSwitch: onFocus_: %{public}d Inner: %{public}d modalCovered: %{public}d",
5848 host->GetId(), needToRequestKeyboardOnFocus_, needToRequestKeyboardInner_, IsModalCovered());
5849 if (!needToRequestKeyboardInner_ || IsModalCovered()) {
5850 return;
5851 }
5852 auto pipeline = host->GetContextRefPtr();
5853 CHECK_NULL_VOID(pipeline);
5854 auto textFieldManager = DynamicCast<TextFieldManagerNG>(pipeline->GetTextFieldManager());
5855 CHECK_NULL_VOID(textFieldManager);
5856 textFieldManager->SetNeedToRequestKeyboard(true);
5857 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "%{public}d add requestkeyboard task", host->GetId());
5858 pipeline->AddAfterLayoutTask([weak = WeakClaim(this), manager = WeakPtr<TextFieldManagerNG>(textFieldManager)]() {
5859 auto textField = weak.Upgrade();
5860 CHECK_NULL_VOID(textField);
5861 auto textFieldManager = manager.Upgrade();
5862 if (textFieldManager && !textFieldManager->GetNeedToRequestKeyboard()) {
5863 // already call close/attach keyboard after text field get focus, so dont request keyboard now
5864 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "Already call close/attach before attach, no need attach this time");
5865 return;
5866 }
5867 if (!textField->needToRequestKeyboardInner_) {
5868 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "Not need to requestKeyboard inner");
5869 return;
5870 }
5871 if (!textField->RequestKeyboard(false, true, textField->needToRequestKeyboardOnFocus_)) {
5872 return;
5873 }
5874 textField->NotifyOnEditChanged(true);
5875 textField->SetNeedToRequestKeyboardInner(false, RequestKeyboardInnerChangeReason::REQUEST_KEYBOARD_SUCCESS);
5876 });
5877 }
5878
5879 // to distiguish request keyboard not by focus switching
RequestKeyboardNotByFocusSwitch(RequestKeyboardReason reason,SourceType sourceType)5880 bool TextFieldPattern::RequestKeyboardNotByFocusSwitch(RequestKeyboardReason reason, SourceType sourceType)
5881 {
5882 auto tmpHost = GetHost();
5883 CHECK_NULL_RETURN(tmpHost, false);
5884 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "%{public}d requestKeyboard With Reason %{public}s",
5885 tmpHost->GetId(), TextFieldPattern::RequestKeyboardReasonToString(reason).c_str());
5886 if (!RequestKeyboard(false, true, true, sourceType)) {
5887 return false;
5888 }
5889 auto context = tmpHost->GetContextRefPtr();
5890 CHECK_NULL_RETURN(context, true);
5891 auto textFieldManager = DynamicCast<TextFieldManagerNG>(context->GetTextFieldManager());
5892 CHECK_NULL_RETURN(textFieldManager, true);
5893 textFieldManager->SetNeedToRequestKeyboard(false);
5894 return true;
5895 }
5896
TextFieldRequestFocus(RequestFocusReason reason)5897 bool TextFieldPattern::TextFieldRequestFocus(RequestFocusReason reason)
5898 {
5899 if (HasFocus()) {
5900 return true;
5901 }
5902 auto host = GetHost();
5903 CHECK_NULL_RETURN(host, false);
5904 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "%{public}d Request Focus With Reason %{public}s",
5905 host->GetId(), TextFieldPattern::RequestFocusReasonToString(reason).c_str());
5906 auto focusHub = GetFocusHub();
5907 CHECK_NULL_RETURN(focusHub, false);
5908 requestFocusReason_ = reason;
5909 return focusHub->RequestFocusImmediately();
5910 }
5911
RequestFocusReasonToString(RequestFocusReason reason)5912 std::string TextFieldPattern::RequestFocusReasonToString(RequestFocusReason reason)
5913 {
5914 switch (reason) {
5915 case RequestFocusReason::DRAG_END: {
5916 return "DragEnd";
5917 }
5918 case RequestFocusReason::DRAG_MOVE: {
5919 return "DragMove";
5920 }
5921 case RequestFocusReason::DRAG_ENTER: {
5922 return "DragEnter";
5923 }
5924 case RequestFocusReason::CLICK: {
5925 return "Click";
5926 }
5927 case RequestFocusReason::LONG_PRESS: {
5928 return "LongPress";
5929 }
5930 case RequestFocusReason::AUTO_FILL: {
5931 return "AutoFill";
5932 }
5933 case RequestFocusReason::CLEAN_NODE: {
5934 return "CleanNode";
5935 }
5936 case RequestFocusReason::MOUSE: {
5937 return "Mouse";
5938 }
5939 case RequestFocusReason::UNKNOWN:
5940 default: {
5941 break;
5942 }
5943 }
5944 return "Unknown";
5945 }
5946
RequestKeyboardReasonToString(RequestKeyboardReason reason)5947 std::string TextFieldPattern::RequestKeyboardReasonToString(RequestKeyboardReason reason)
5948 {
5949 switch (reason) {
5950 case RequestKeyboardReason::ON_KEY_EVENT: {
5951 return "KeyEvent";
5952 }
5953 case RequestKeyboardReason::SINGLE_CLICK: {
5954 return "SingleClick";
5955 }
5956 case RequestKeyboardReason::DOUBLE_CLICK: {
5957 return "DoubleClick";
5958 }
5959 case RequestKeyboardReason::LONG_PRESS: {
5960 return "LongPress";
5961 }
5962 case RequestKeyboardReason::RESET_KEYBOARD: {
5963 return "ResetKeyboard";
5964 }
5965 case RequestKeyboardReason::MOUSE_RELEASE: {
5966 return "MouseRelease";
5967 }
5968 case RequestKeyboardReason::SET_SELECTION: {
5969 return "SetSelection";
5970 }
5971 case RequestKeyboardReason::SEARCH_REQUEST: {
5972 return "SearchRequest";
5973 }
5974 case RequestKeyboardReason::AUTO_FILL_REQUEST_FAIL: {
5975 return "AutoFillRequestFail";
5976 }
5977 case RequestKeyboardReason::SHOW_KEYBOARD_ON_FOCUS: {
5978 return "ShowKeyboardOnFocus";
5979 }
5980 case RequestKeyboardReason::STYLUS_DETECTOR: {
5981 return "StylusDetector";
5982 }
5983 case RequestKeyboardReason::CUSTOM_KEYBOARD: {
5984 return "CustomKeyboard";
5985 }
5986 case RequestKeyboardReason::UNKNOWN:
5987 default: {
5988 break;
5989 }
5990 }
5991 return "Unknown";
5992 }
5993
IsModalCovered()5994 bool TextFieldPattern::IsModalCovered()
5995 {
5996 auto host = GetHost();
5997 CHECK_NULL_RETURN(host, false);
5998 auto pageNode = host->GetPageNode();
5999 CHECK_NULL_RETURN(pageNode, false);
6000 auto pagePattern = pageNode->GetPattern<PagePattern>();
6001 CHECK_NULL_RETURN(pagePattern, false);
6002 return pagePattern->GetIsModalCovered();
6003 }
6004
OnVisibleChange(bool isVisible)6005 void TextFieldPattern::OnVisibleChange(bool isVisible)
6006 {
6007 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "visible change to %{public}d", isVisible);
6008 if (!isVisible && HasFocus()) {
6009 CloseKeyboard(true);
6010 if (SelectOverlayIsOn()) {
6011 StartTwinkling();
6012 }
6013 }
6014 }
6015
HandleSurfaceChanged(int32_t newWidth,int32_t newHeight,int32_t prevWidth,int32_t prevHeight)6016 void TextFieldPattern::HandleSurfaceChanged(int32_t newWidth, int32_t newHeight, int32_t prevWidth, int32_t prevHeight)
6017 {
6018 if (newWidth == prevWidth && newHeight == prevHeight) {
6019 return;
6020 }
6021 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD,
6022 "Textfield handleSurface change, new width %{public}d, new height %{public}d, prev width %{public}d, prev "
6023 "height %{public}d",
6024 newWidth, newHeight, prevWidth, prevHeight);
6025 if (SelectOverlayIsOn()) {
6026 if (selectOverlay_->IsShowMouseMenu()) {
6027 CloseSelectOverlay();
6028 } else if (newWidth != prevWidth || newHeight != prevHeight) {
6029 DelayProcessOverlay({ .menuIsShow = false });
6030 }
6031 selectOverlay_->RemoveAvoidKeyboardCallback();
6032 }
6033 auto tmpHost = GetHost();
6034 CHECK_NULL_VOID(tmpHost);
6035 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
6036 UpdateCaretInfoToController(true);
6037 if (magnifierController_->GetShowMagnifier()) {
6038 magnifierController_->RemoveMagnifierFrameNode();
6039 }
6040 }
6041
HandleSurfacePositionChanged(int32_t posX,int32_t posY)6042 void TextFieldPattern::HandleSurfacePositionChanged(int32_t posX, int32_t posY)
6043 {
6044 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "Textfield handleSurface position change, posX %{public}d, posY %{public}d",
6045 posX, posY);
6046 UpdateCaretInfoToController();
6047 }
6048
InitSurfaceChangedCallback()6049 void TextFieldPattern::InitSurfaceChangedCallback()
6050 {
6051 auto host = GetHost();
6052 CHECK_NULL_VOID(host);
6053 auto pipeline = host->GetContext();
6054 CHECK_NULL_VOID(pipeline);
6055 if (!HasSurfaceChangedCallback()) {
6056 auto callbackId = pipeline->RegisterSurfaceChangedCallback(
6057 [weak = WeakClaim(this)](int32_t newWidth, int32_t newHeight, int32_t prevWidth, int32_t prevHeight,
6058 WindowSizeChangeReason type) {
6059 auto pattern = weak.Upgrade();
6060 if (pattern) {
6061 pattern->HandleSurfaceChanged(newWidth, newHeight, prevWidth, prevHeight);
6062 }
6063 });
6064 UpdateSurfaceChangedCallbackId(callbackId);
6065 }
6066 }
6067
InitSurfacePositionChangedCallback()6068 void TextFieldPattern::InitSurfacePositionChangedCallback()
6069 {
6070 auto host = GetHost();
6071 CHECK_NULL_VOID(host);
6072 auto pipeline = host->GetContext();
6073 CHECK_NULL_VOID(pipeline);
6074 if (!HasSurfacePositionChangedCallback()) {
6075 auto callbackId =
6076 pipeline->RegisterSurfacePositionChangedCallback([weak = WeakClaim(this)](int32_t posX, int32_t posY) {
6077 auto pattern = weak.Upgrade();
6078 if (pattern) {
6079 pattern->HandleSurfacePositionChanged(posX, posY);
6080 }
6081 });
6082 UpdateSurfacePositionChangedCallbackId(callbackId);
6083 }
6084 }
6085
HandleOnDelete(bool backward)6086 void TextFieldPattern::HandleOnDelete(bool backward)
6087 {
6088 if (backward) {
6089 #if defined(PREVIEW)
6090 DeleteForward(1);
6091 #else
6092 DeleteBackward(1);
6093 #endif
6094 } else {
6095 #if defined(PREVIEW)
6096 DeleteBackward(1);
6097 #else
6098 DeleteForward(1);
6099 #endif
6100 }
6101 }
6102
HandleOnDeleteComb(bool backward)6103 bool TextFieldPattern::HandleOnDeleteComb(bool backward)
6104 {
6105 if (backward) {
6106 DeleteBackwardWord(); // LTR is left word,RTL is right word
6107 } else {
6108 DeleteForwardWord(); // LTR is right word,RTL is left word
6109 }
6110 return true;
6111 }
6112
DeleteBackwardWord()6113 void TextFieldPattern::DeleteBackwardWord()
6114 {
6115 int32_t originCaretPosition = selectController_->GetCaretIndex();
6116 int32_t textLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
6117 int32_t leftWordLength = GetWordLength(originCaretPosition, 0, false);
6118 if (leftWordLength < 0) {
6119 // delete 1 char
6120 leftWordLength = 1;
6121 }
6122 if (leftWordLength > textLength || selectController_->GetCaretIndex() - leftWordLength < 0) {
6123 // delete left
6124 leftWordLength = std::max(1, originCaretPosition);
6125 }
6126 DeleteBackward(leftWordLength);
6127 }
6128
DeleteForwardWord()6129 void TextFieldPattern::DeleteForwardWord()
6130 {
6131 int32_t originCaretPosition = selectController_->GetCaretIndex();
6132 int32_t textLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
6133 int32_t rightWordLength = GetWordLength(originCaretPosition, 1, false);
6134 if (rightWordLength < 0) {
6135 // delete 1 char
6136 rightWordLength = 1;
6137 }
6138 if (rightWordLength > textLength || rightWordLength + selectController_->GetCaretIndex() > textLength) {
6139 // delete right
6140 rightWordLength = std::max(1, textLength - originCaretPosition);
6141 }
6142 DeleteForward(rightWordLength);
6143 }
6144
HandleOnPageUp()6145 void TextFieldPattern::HandleOnPageUp()
6146 {
6147 if (!IsTextArea()) {
6148 return;
6149 }
6150 auto border = GetBorderWidthProperty();
6151 float frameRectHeight = std::max(frameRect_.Height(), PreferredLineHeight());
6152 float maxFrameHeight =
6153 frameRectHeight - GetPaddingTop() - GetPaddingBottom() - GetBorderTop(border) - GetBorderBottom(border);
6154 OnScrollCallback(maxFrameHeight, SCROLL_FROM_JUMP);
6155 auto caretRectOffset = selectController_->GetCaretRect().GetOffset();
6156 Offset offset(caretRectOffset.GetX(), GetPaddingTop() + GetBorderTop(border));
6157 selectController_->UpdateCaretInfoByOffset(offset, true);
6158 OnCursorMoveDone(TextAffinity::DOWNSTREAM);
6159 }
6160
HandleOnPageDown()6161 void TextFieldPattern::HandleOnPageDown()
6162 {
6163 if (!IsTextArea()) {
6164 return;
6165 }
6166 auto border = GetBorderWidthProperty();
6167 float frameRectHeight = std::max(frameRect_.Height(), PreferredLineHeight());
6168 float maxFrameHeight =
6169 frameRectHeight - GetPaddingTop() - GetPaddingBottom() - GetBorderTop(border) - GetBorderBottom(border);
6170 OnScrollCallback(-maxFrameHeight, SCROLL_FROM_JUMP);
6171 auto caretRectOffset = selectController_->GetCaretRect().GetOffset();
6172 Offset offset(caretRectOffset.GetX(), maxFrameHeight);
6173 selectController_->UpdateCaretInfoByOffset(offset, true);
6174 OnCursorMoveDone(TextAffinity::DOWNSTREAM);
6175 }
6176
GetEmojiSubStringRange(int32_t & start,int32_t & end)6177 void TextFieldPattern::GetEmojiSubStringRange(int32_t& start, int32_t& end)
6178 {
6179 TextEmojiSubStringRange range = TextEmojiProcessor::CalSubU16stringRange(
6180 start, end - start, GetTextUtf16Value(), false, true);
6181 start = range.startIndex;
6182 end = range.endIndex;
6183 }
6184
DeleteBackward(int32_t length)6185 void TextFieldPattern::DeleteBackward(int32_t length)
6186 {
6187 CHECK_NULL_VOID(!IsDragging());
6188 CHECK_NULL_VOID(focusIndex_ == FocuseIndex::TEXT);
6189 ResetObscureTickCountDown();
6190 if (IsSelected()) {
6191 auto start = selectController_->GetStartIndex();
6192 auto end = selectController_->GetEndIndex();
6193 DeleteTextRange(start, end, TextDeleteDirection::BACKWARD);
6194 return;
6195 }
6196 if (selectController_->GetCaretIndex() <= 0) {
6197 auto isDelete = BeforeIMEDeleteValue(u"", TextDeleteDirection::BACKWARD, 0);
6198 CHECK_NULL_VOID(isDelete);
6199 AfterIMEDeleteValue(u"", TextDeleteDirection::BACKWARD);
6200 return;
6201 }
6202 inputOperations_.emplace(InputOperation::DELETE_BACKWARD);
6203 deleteBackwardOperations_.emplace(length);
6204 CloseSelectOverlay();
6205 ScrollToSafeArea();
6206 auto tmpHost = GetHost();
6207 CHECK_NULL_VOID(tmpHost);
6208 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
6209 }
6210
DeleteBackwardOperation(int32_t length)6211 void TextFieldPattern::DeleteBackwardOperation(int32_t length)
6212 {
6213 int32_t idx = selectController_->GetCaretIndex();
6214 auto willDeleteLength = contentController_->GetDeleteLength(idx, length, true);
6215 auto value = contentController_->GetSelectedValue(idx - willDeleteLength, idx);
6216 auto isDelete = BeforeIMEDeleteValue(value, TextDeleteDirection::BACKWARD, idx);
6217 CHECK_NULL_VOID(isDelete);
6218 auto oldContent = contentController_->GetTextUtf16Value();
6219 int32_t count = contentController_->Delete(selectController_->GetCaretIndex(), length, true);
6220 auto isOnWillChange = OnWillChangePreDelete(oldContent, std::max(idx - count, 0), idx);
6221 if (!isOnWillChange) {
6222 contentController_->SetTextValue(oldContent);
6223 return;
6224 }
6225 selectController_->UpdateCaretIndex(std::max(idx - count, 0));
6226 if (GetIsPreviewText()) {
6227 UpdatePreviewIndex(GetPreviewTextStart(), GetPreviewTextEnd() - length);
6228 }
6229 AfterIMEDeleteValue(value, TextDeleteDirection::BACKWARD);
6230 StartTwinkling();
6231 focusIndex_ = FocuseIndex::TEXT;
6232 UpdateEditingValueToRecord();
6233 }
6234
DeleteForwardOperation(int32_t length)6235 void TextFieldPattern::DeleteForwardOperation(int32_t length)
6236 {
6237 auto caretIndex = selectController_->GetCaretIndex();
6238 auto willDeleteLength = contentController_->GetDeleteLength(caretIndex, length, false);
6239 auto value = contentController_->GetSelectedValue(caretIndex, caretIndex + willDeleteLength);
6240 auto isDelete = BeforeIMEDeleteValue(value, TextDeleteDirection::FORWARD, caretIndex);
6241 CHECK_NULL_VOID(isDelete);
6242 ResetObscureTickCountDown();
6243 auto oldContent = contentController_->GetTextUtf16Value();
6244 contentController_->Delete(caretIndex, length, false);
6245 if (GetIsPreviewText()) {
6246 UpdatePreviewIndex(GetPreviewTextStart(), GetPreviewTextEnd() - length);
6247 }
6248 auto isOnWillChange = OnWillChangePreDelete(oldContent, caretIndex, caretIndex + willDeleteLength);
6249 if (!isOnWillChange) {
6250 contentController_->SetTextValue(oldContent);
6251 return;
6252 }
6253 AfterIMEDeleteValue(value, TextDeleteDirection::FORWARD);
6254 StartTwinkling();
6255 focusIndex_ = FocuseIndex::TEXT;
6256 UpdateEditingValueToRecord();
6257 }
6258
DeleteForward(int32_t length)6259 void TextFieldPattern::DeleteForward(int32_t length)
6260 {
6261 CHECK_NULL_VOID(!IsDragging());
6262 CHECK_NULL_VOID(focusIndex_ == FocuseIndex::TEXT);
6263 if (IsSelected()) {
6264 auto start = selectController_->GetStartIndex();
6265 auto end = selectController_->GetEndIndex();
6266 DeleteRange(start, end);
6267 return;
6268 }
6269 auto contentLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
6270 if (selectController_->GetCaretIndex() >= contentLength) {
6271 auto isDelete = BeforeIMEDeleteValue(u"", TextDeleteDirection::FORWARD, contentLength);
6272 CHECK_NULL_VOID(isDelete);
6273 AfterIMEDeleteValue(u"", TextDeleteDirection::FORWARD);
6274 return;
6275 }
6276 inputOperations_.emplace(InputOperation::DELETE_FORWARD);
6277 deleteForwardOperations_.emplace(length);
6278 CloseSelectOverlay();
6279 auto tmpHost = GetHost();
6280 CHECK_NULL_VOID(tmpHost);
6281 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
6282 }
6283
BeforeIMEDeleteValue(const std::u16string & deleteValue,TextDeleteDirection direction,int32_t offset)6284 bool TextFieldPattern::BeforeIMEDeleteValue(
6285 const std::u16string& deleteValue, TextDeleteDirection direction, int32_t offset)
6286 {
6287 auto host = GetHost();
6288 CHECK_NULL_RETURN(host, true);
6289 auto eventHub = host->GetEventHub<TextFieldEventHub>();
6290 CHECK_NULL_RETURN(eventHub, true);
6291 DeleteValueInfo deleteValueInfo;
6292 deleteValueInfo.deleteOffset = offset;
6293 deleteValueInfo.deleteValue = deleteValue;
6294 deleteValueInfo.direction = direction;
6295 return eventHub->FireOnWillDeleteEvent(deleteValueInfo);
6296 }
6297
AfterIMEDeleteValue(const std::u16string & deleteValue,TextDeleteDirection direction)6298 void TextFieldPattern::AfterIMEDeleteValue(const std::u16string& deleteValue, TextDeleteDirection direction)
6299 {
6300 auto host = GetHost();
6301 CHECK_NULL_VOID(host);
6302 auto eventHub = host->GetEventHub<TextFieldEventHub>();
6303 CHECK_NULL_VOID(eventHub);
6304 DeleteValueInfo deleteValueInfo;
6305 deleteValueInfo.deleteOffset = selectController_->GetCaretIndex();
6306 deleteValueInfo.deleteValue = deleteValue;
6307 deleteValueInfo.direction = direction;
6308 return eventHub->FireOnDidDeleteValueEvent(deleteValueInfo);
6309 }
6310
GetLeftTextOfCursor(int32_t number)6311 std::u16string TextFieldPattern::GetLeftTextOfCursor(int32_t number)
6312 {
6313 auto start = selectController_->GetCaretIndex();
6314 if (IsSelected()) {
6315 start = selectController_->GetStartIndex();
6316 }
6317 return contentController_->GetSelectedValue(start - number, start);
6318 }
6319
GetRightTextOfCursor(int32_t number)6320 std::u16string TextFieldPattern::GetRightTextOfCursor(int32_t number)
6321 {
6322 auto end = selectController_->GetCaretIndex();
6323 if (IsSelected()) {
6324 end = selectController_->GetEndIndex();
6325 }
6326 return contentController_->GetSelectedValue(end, end + number);
6327 }
6328
GetTextIndexAtCursor()6329 int32_t TextFieldPattern::GetTextIndexAtCursor()
6330 {
6331 return selectController_->GetCaretIndex();
6332 }
6333
AfterSelection()6334 void TextFieldPattern::AfterSelection()
6335 {
6336 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "Selection %{public}s, caret position %{public}d",
6337 selectController_->ToString().c_str(), selectController_->GetCaretIndex());
6338 ResetObscureTickCountDown();
6339 auto tmpHost = GetHost();
6340 CHECK_NULL_VOID(tmpHost);
6341 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
6342 showSelect_ = IsSelected();
6343 }
6344
HandleSelectionUp()6345 void TextFieldPattern::HandleSelectionUp()
6346 {
6347 if (!IsSelected()) {
6348 UpdateSelection(selectController_->GetCaretIndex());
6349 }
6350 auto newOffsetY = selectController_->GetCaretRect().GetY() - PreferredLineHeight() * 0.5 - textRect_.GetY();
6351 if (GreatOrEqual(newOffsetY, 0.0)) {
6352 OffsetF originCaretPosition;
6353 auto caretXPosition = GetOriginCaretPosition(originCaretPosition) &&
6354 GreatNotEqual(selectController_->GetCaretRect().GetX() - contentRect_.GetX(), 0) ? // handle when line head
6355 originCaretPosition.GetX() : selectController_->GetCaretRect().GetX();
6356 selectController_->MoveSecondHandleByKeyBoard(paragraph_->GetGlyphIndexByCoordinate(
6357 Offset(caretXPosition - contentRect_.GetX(), newOffsetY)));
6358 } else {
6359 selectController_->MoveSecondHandleByKeyBoard(0);
6360 }
6361 AfterSelection();
6362 }
6363
HandleSelectionDown()6364 void TextFieldPattern::HandleSelectionDown()
6365 {
6366 if (!IsSelected()) {
6367 UpdateSelection(selectController_->GetCaretIndex());
6368 }
6369 auto newOffsetY = selectController_->GetCaretRect().GetY() + PreferredLineHeight() * 1.5 - textRect_.GetY();
6370 if (LessOrEqual(newOffsetY, textRect_.Height())) {
6371 OffsetF originCaretPosition;
6372 auto caretXPosition = GetOriginCaretPosition(originCaretPosition) ?
6373 originCaretPosition.GetX() : selectController_->GetCaretRect().GetX();
6374 selectController_->MoveSecondHandleByKeyBoard(paragraph_->GetGlyphIndexByCoordinate(
6375 Offset(caretXPosition - contentRect_.GetX(), newOffsetY)), TextAffinity::DOWNSTREAM);
6376 } else {
6377 selectController_->MoveSecondHandleByKeyBoard(
6378 static_cast<int32_t>(contentController_->GetTextUtf16Value().length()));
6379 }
6380 AfterSelection();
6381 }
6382
HandleSelectionLeft()6383 void TextFieldPattern::HandleSelectionLeft()
6384 {
6385 if (!IsSelected()) {
6386 if (selectController_->GetCaretIndex() == 0) {
6387 return;
6388 }
6389 UpdateSelection(selectController_->GetCaretIndex());
6390 selectController_->MoveSecondHandleByKeyBoard(
6391 selectController_->GetSecondHandleIndex() -
6392 GetGraphemeClusterLength(contentController_->GetTextUtf16Value(), selectController_->GetCaretIndex(),
6393 true));
6394 } else {
6395 selectController_->MoveSecondHandleByKeyBoard(selectController_->GetSecondHandleIndex() -
6396 GetGraphemeClusterLength(contentController_->GetTextUtf16Value(), selectController_->GetSecondHandleIndex(),
6397 true));
6398 }
6399 AfterSelection();
6400 }
6401
HandleSelectionLeftWord()6402 void TextFieldPattern::HandleSelectionLeftWord()
6403 {
6404 if (selectController_->GetCaretIndex() == 0) {
6405 return;
6406 }
6407 int32_t textLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
6408 int32_t leftWordLength = GetWordLength(selectController_->GetCaretIndex(), 0);
6409 if (leftWordLength < 0 || leftWordLength > textLength || selectController_->GetCaretIndex() - leftWordLength < 0) {
6410 return;
6411 }
6412 if (!IsSelected()) {
6413 UpdateSelection(selectController_->GetCaretIndex());
6414 selectController_->MoveSecondHandleByKeyBoard(selectController_->GetSecondHandleIndex() - leftWordLength);
6415 } else {
6416 selectController_->MoveSecondHandleByKeyBoard(selectController_->GetSecondHandleIndex() - leftWordLength);
6417 }
6418 AfterSelection();
6419 }
6420
HandleSelectionLineBegin()6421 void TextFieldPattern::HandleSelectionLineBegin()
6422 {
6423 if (selectController_->GetCaretIndex() == 0) {
6424 return;
6425 }
6426 int32_t textLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
6427 int32_t lineBeginPosition = GetLineBeginPosition(selectController_->GetCaretIndex());
6428 if (lineBeginPosition < 0 || lineBeginPosition > textLength) {
6429 return;
6430 }
6431 if (!IsSelected()) {
6432 UpdateSelection(selectController_->GetCaretIndex());
6433 selectController_->MoveSecondHandleByKeyBoard(lineBeginPosition);
6434 } else {
6435 selectController_->MoveSecondHandleByKeyBoard(lineBeginPosition);
6436 }
6437 AfterSelection();
6438 }
6439
HandleSelectionHome()6440 void TextFieldPattern::HandleSelectionHome()
6441 {
6442 if (selectController_->GetCaretIndex() == 0) {
6443 return;
6444 }
6445 if (!IsSelected()) {
6446 UpdateSelection(selectController_->GetCaretIndex());
6447 selectController_->MoveSecondHandleByKeyBoard(0);
6448 } else {
6449 selectController_->MoveSecondHandleByKeyBoard(0);
6450 }
6451 AfterSelection();
6452 }
6453
HandleSelectionRight()6454 void TextFieldPattern::HandleSelectionRight()
6455 {
6456 // if currently not in select mode, reset baseOffset and move destinationOffset and caret position
6457 if (!IsSelected()) {
6458 if (selectController_->GetCaretIndex() ==
6459 static_cast<int32_t>(contentController_->GetTextUtf16Value().length())) {
6460 return;
6461 }
6462 UpdateSelection(selectController_->GetCaretIndex());
6463 selectController_->MoveSecondHandleByKeyBoard(
6464 selectController_->GetSecondHandleIndex() +
6465 GetGraphemeClusterLength(contentController_->GetTextUtf16Value(),
6466 selectController_->GetSecondHandleIndex()));
6467 } else {
6468 // if currently not in select mode, move destinationOffset and caret position only
6469 selectController_->MoveSecondHandleByKeyBoard(
6470 selectController_->GetSecondHandleIndex() +
6471 GetGraphemeClusterLength(contentController_->GetTextUtf16Value(),
6472 selectController_->GetSecondHandleIndex()));
6473 }
6474 AfterSelection();
6475 }
6476
HandleSelectionRightWord()6477 void TextFieldPattern::HandleSelectionRightWord()
6478 {
6479 int32_t textLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
6480 if (selectController_->GetCaretIndex() == textLength) {
6481 return;
6482 }
6483 int32_t rightWordLength = GetWordLength(selectController_->GetCaretIndex(), 1);
6484 if (rightWordLength < 0 || rightWordLength > textLength ||
6485 rightWordLength + selectController_->GetCaretIndex() > textLength) {
6486 return;
6487 }
6488 if (!IsSelected()) {
6489 UpdateSelection(selectController_->GetCaretIndex());
6490 selectController_->MoveSecondHandleByKeyBoard(selectController_->GetSecondHandleIndex() + rightWordLength);
6491 } else {
6492 selectController_->MoveSecondHandleByKeyBoard(selectController_->GetSecondHandleIndex() + rightWordLength);
6493 AfterSelection();
6494 }
6495 }
6496
HandleSelectionLineEnd()6497 void TextFieldPattern::HandleSelectionLineEnd()
6498 {
6499 int32_t textLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
6500 if (selectController_->GetCaretIndex() == textLength) {
6501 return;
6502 }
6503 int32_t lineEndPosition = GetLineEndPosition(selectController_->GetCaretIndex());
6504 if (lineEndPosition < 0 || lineEndPosition > textLength) {
6505 return;
6506 }
6507 if (!IsSelected()) {
6508 UpdateSelection(selectController_->GetCaretIndex());
6509 selectController_->MoveSecondHandleByKeyBoard(lineEndPosition);
6510 } else {
6511 selectController_->MoveSecondHandleByKeyBoard(lineEndPosition);
6512 }
6513 AfterSelection();
6514 }
6515
HandleSelectionEnd()6516 void TextFieldPattern::HandleSelectionEnd()
6517 {
6518 // shift end, select to the end of current line
6519 int32_t endPos = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
6520 if (selectController_->GetCaretIndex() == endPos) {
6521 return;
6522 }
6523 if (!IsSelected()) {
6524 UpdateSelection(selectController_->GetCaretIndex());
6525 selectController_->MoveSecondHandleByKeyBoard(endPos);
6526 } else {
6527 selectController_->MoveSecondHandleByKeyBoard(endPos);
6528 }
6529 AfterSelection();
6530 }
6531
SetCaretPosition(int32_t position,bool moveContent)6532 void TextFieldPattern::SetCaretPosition(int32_t position, bool moveContent)
6533 {
6534 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "Set caret position to %{public}d", position);
6535 selectController_->MoveCaretToContentRect(position, TextAffinity::DOWNSTREAM, true, moveContent);
6536 UpdateCaretInfoToController();
6537 if (HasFocus() && !magnifierController_->GetShowMagnifier()) {
6538 StartTwinkling();
6539 }
6540 CloseSelectOverlay();
6541 CancelDelayProcessOverlay();
6542 TriggerAvoidOnCaretChange();
6543 auto tmpHost = GetHost();
6544 CHECK_NULL_VOID(tmpHost);
6545 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
6546 }
6547
SetCaretOffset(int32_t caretPostion)6548 bool TextFieldPattern::SetCaretOffset(int32_t caretPostion)
6549 {
6550 SetCaretPosition(caretPostion);
6551 return true;
6552 }
6553
SetSelectionFlag(int32_t selectionStart,int32_t selectionEnd,const std::optional<SelectionOptions> & options,bool isForward)6554 void TextFieldPattern::SetSelectionFlag(
6555 int32_t selectionStart, int32_t selectionEnd, const std::optional<SelectionOptions>& options, bool isForward)
6556 {
6557 if (!HasFocus() || GetIsPreviewText()) {
6558 return;
6559 }
6560 auto length = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
6561 selectionStart = std::clamp(selectionStart, 0, length);
6562 selectionEnd = std::clamp(selectionEnd, 0, length);
6563 moveCaretState_.isTouchCaret = false;
6564 bool isShowMenu = selectOverlay_->IsCurrentMenuVisibile();
6565 isTouchPreviewText_ = false;
6566 if (selectionStart == selectionEnd) {
6567 selectController_->MoveCaretToContentRect(selectionEnd, TextAffinity::DOWNSTREAM);
6568 StartTwinkling();
6569 } else {
6570 cursorVisible_ = false;
6571 showSelect_ = true;
6572 HandleSetSelection(selectionStart, selectionEnd, false);
6573 if (isForward) {
6574 selectController_->MoveSecondHandleToContentRect(selectionEnd);
6575 selectController_->MoveFirstHandleToContentRect(selectionStart, false);
6576 } else {
6577 selectController_->MoveFirstHandleToContentRect(selectionStart);
6578 selectController_->MoveSecondHandleToContentRect(selectionEnd);
6579 }
6580 }
6581 if (RequestKeyboardNotByFocusSwitch(RequestKeyboardReason::SET_SELECTION)) {
6582 NotifyOnEditChanged(true);
6583 }
6584 SetIsSingleHandle(!IsSelected());
6585 if (!IsShowHandle()) {
6586 CloseSelectOverlay(true);
6587 } else {
6588 isShowMenu = IsShowMenu(options, isShowMenu);
6589 if (!isShowMenu && IsUsingMouse()) {
6590 CloseSelectOverlay();
6591 } else {
6592 ProcessOverlay({ .menuIsShow = isShowMenu, .animation = true });
6593 }
6594 }
6595 TriggerAvoidWhenCaretGoesDown();
6596 auto host = GetHost();
6597 CHECK_NULL_VOID(host);
6598 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
6599 }
6600
SetSelection(int32_t start,int32_t end,const std::optional<SelectionOptions> & options,bool isForward)6601 void TextFieldPattern::SetSelection(int32_t start, int32_t end,
6602 const std::optional<SelectionOptions>& options, bool isForward)
6603 {
6604 SetSelectionFlag(start, end, options, isForward);
6605 }
6606
IsShowMenu(const std::optional<SelectionOptions> & options,bool defaultValue)6607 bool TextFieldPattern::IsShowMenu(const std::optional<SelectionOptions>& options, bool defaultValue)
6608 {
6609 if (!options.has_value()) {
6610 return false;
6611 }
6612 if (options.value().menuPolicy == MenuPolicy::HIDE) {
6613 return false;
6614 }
6615 if (options.value().menuPolicy == MenuPolicy::SHOW) {
6616 return true;
6617 }
6618 return defaultValue;
6619 }
6620
OnBackPressed()6621 bool TextFieldPattern::OnBackPressed()
6622 {
6623 auto tmpHost = GetHost();
6624 CHECK_NULL_RETURN(tmpHost, false);
6625 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "%{public}d receives back press event, %{public}d",
6626 tmpHost->GetId(), isCustomKeyboardAttached_);
6627 if (SelectOverlayIsOn()) {
6628 selectController_->UpdateCaretIndex(
6629 std::max(selectController_->GetFirstHandleIndex(), selectController_->GetSecondHandleIndex()));
6630 bool closeKeyboard = !selectOverlay_->IsCurrentMenuVisibile();
6631 CloseSelectOverlay();
6632 StartTwinkling();
6633 if (!closeKeyboard) {
6634 return IsStopBackPress();
6635 }
6636 }
6637 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
6638 if (!imeShown_ && !isCustomKeyboardAttached_) {
6639 #else
6640 if (!isCustomKeyboardAttached_) {
6641 #endif
6642 return false;
6643 }
6644
6645 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
6646 HandleCloseKeyboard(true);
6647 #if defined(ANDROID_PLATFORM)
6648 return false;
6649 #else
6650 return IsStopBackPress();
6651 #endif
6652 }
6653
6654 bool TextFieldPattern::IsStopBackPress() const
6655 {
6656 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
6657 CHECK_NULL_RETURN(layoutProperty, true);
6658 return layoutProperty->GetStopBackPressValue(true);
6659 }
6660
6661 void TextFieldPattern::HandleCloseKeyboard(bool forceClose)
6662 {
6663 if (independentControlKeyboard_) {
6664 CloseKeyboard(true, false);
6665 } else {
6666 CloseKeyboard(forceClose);
6667 if (HasFocus()) {
6668 FocusHub::LostFocusToViewRoot();
6669 }
6670 }
6671 }
6672
6673 int32_t TextFieldPattern::GetNakedCharPosition() const
6674 {
6675 if (IsTextArea() || !IsInPasswordMode() || obscureTickCountDown_ <= 0 || !GetTextObscured()) {
6676 return -1;
6677 }
6678 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
6679 CHECK_NULL_RETURN(layoutProperty, -1);
6680 auto content = contentController_->GetTextUtf16Value();
6681 if (content.empty()) {
6682 return -1;
6683 }
6684 return nakedCharPosition_;
6685 }
6686
6687 std::string TextFieldPattern::TextInputTypeToString() const
6688 {
6689 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
6690 CHECK_NULL_RETURN(layoutProperty, "");
6691 switch (layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED)) {
6692 case TextInputType::NUMBER:
6693 return IsTextArea() ? "TextAreaType.NUMBER" : "InputType.Number";
6694 case TextInputType::EMAIL_ADDRESS:
6695 return IsTextArea() ? "TextAreaType.EMAIL" : "InputType.Email";
6696 case TextInputType::PHONE:
6697 return IsTextArea() ? "TextAreaType.PHONE_NUMBER" : "InputType.PhoneNumber";
6698 case TextInputType::URL:
6699 return IsTextArea() ? "TextAreaType.URL" : "InputType.URL";
6700 case TextInputType::VISIBLE_PASSWORD:
6701 return "InputType.Password";
6702 case TextInputType::USER_NAME:
6703 return "InputType.USER_NAME";
6704 case TextInputType::NEW_PASSWORD:
6705 return "InputType.NEW_PASSWORD";
6706 case TextInputType::NUMBER_PASSWORD:
6707 return "InputType.NUMBER_PASSWORD";
6708 case TextInputType::NUMBER_DECIMAL:
6709 return IsTextArea() ? "TextAreaType.NUMBER_DECIMAL" : "InputType.NUMBER_DECIMAL";
6710 default:
6711 return isTextInput_ ? "InputType.Normal" : "TextAreaType.NORMAL";
6712 }
6713 }
6714
6715 std::string TextFieldPattern::TextContentTypeToString() const
6716 {
6717 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
6718 CHECK_NULL_RETURN(layoutProperty, "");
6719 auto contentType = layoutProperty->GetTextContentTypeValue(TextContentType::UNSPECIFIED);
6720 if (contentTypeMap_.find(contentType) != contentTypeMap_.end()) {
6721 return contentTypeMap_[contentType].second;
6722 }
6723 return contentTypeMap_[TextContentType::UNSPECIFIED].second;
6724 }
6725
6726 std::string TextFieldPattern::TextInputActionToString() const
6727 {
6728 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
6729 CHECK_NULL_RETURN(layoutProperty, "");
6730 switch (GetTextInputActionValue(GetDefaultTextInputAction())) {
6731 case TextInputAction::GO:
6732 return "EnterKeyType.Go";
6733 case TextInputAction::SEARCH:
6734 return "EnterKeyType.Search";
6735 case TextInputAction::SEND:
6736 return "EnterKeyType.Send";
6737 case TextInputAction::NEXT:
6738 return "EnterKeyType.Next";
6739 default:
6740 return "EnterKeyType.Done";
6741 }
6742 }
6743
6744 std::string TextFieldPattern::GetPlaceholderFont() const
6745 {
6746 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
6747 CHECK_NULL_RETURN(layoutProperty, "");
6748 auto theme = GetTheme();
6749 CHECK_NULL_RETURN(theme, "");
6750 auto jsonValue = JsonUtil::Create(true);
6751 if (layoutProperty->GetPlaceholderItalicFontStyle().value_or(Ace::FontStyle::NORMAL) == Ace::FontStyle::NORMAL) {
6752 jsonValue->Put("style", "FontStyle.Normal");
6753 } else {
6754 jsonValue->Put("style", "FontStyle.Italic");
6755 }
6756 // placeholder font size not exist in theme, use normal font size by default
6757 if (!layoutProperty->GetPlaceholderFontSize()) {
6758 jsonValue->Put("size", GetFontSize().c_str());
6759 } else {
6760 jsonValue->Put("size", layoutProperty->GetPlaceholderFontSize()->ToString().c_str());
6761 }
6762 auto weight = layoutProperty->GetPlaceholderFontWeightValue(theme->GetFontWeight());
6763 switch (weight) {
6764 case FontWeight::W100:
6765 jsonValue->Put("weight", "100");
6766 break;
6767 case FontWeight::W200:
6768 jsonValue->Put("weight", "200");
6769 break;
6770 case FontWeight::W300:
6771 jsonValue->Put("weight", "300");
6772 break;
6773 case FontWeight::W400:
6774 jsonValue->Put("weight", "400");
6775 break;
6776 case FontWeight::W500:
6777 jsonValue->Put("weight", "500");
6778 break;
6779 case FontWeight::W600:
6780 jsonValue->Put("weight", "600");
6781 break;
6782 case FontWeight::W700:
6783 jsonValue->Put("weight", "700");
6784 break;
6785 case FontWeight::W800:
6786 jsonValue->Put("weight", "800");
6787 break;
6788 case FontWeight::W900:
6789 jsonValue->Put("weight", "900");
6790 break;
6791 default:
6792 jsonValue->Put("fontWeight", V2::ConvertWrapFontWeightToStirng(weight).c_str());
6793 }
6794 auto family = layoutProperty->GetPlaceholderFontFamilyValue({ "sans-serif" });
6795 std::string jsonFamily = ConvertFontFamily(family);
6796 jsonValue->Put("fontFamily", jsonFamily.c_str());
6797 return jsonValue->ToString();
6798 }
6799
6800 RefPtr<TextFieldTheme> TextFieldPattern::GetTheme() const
6801 {
6802 if (textFieldTheme_.Upgrade()) {
6803 return textFieldTheme_.Upgrade();
6804 }
6805 auto tmpHost = GetHost();
6806 CHECK_NULL_RETURN(tmpHost, nullptr);
6807 auto context = tmpHost->GetContext();
6808 CHECK_NULL_RETURN(context, nullptr);
6809 auto theme = context->GetTheme<TextFieldTheme>(tmpHost->GetThemeScopeId());
6810 return theme;
6811 }
6812
6813 void TextFieldPattern::InitTheme()
6814 {
6815 auto tmpHost = GetHost();
6816 CHECK_NULL_VOID(tmpHost);
6817 auto context = tmpHost->GetContext();
6818 CHECK_NULL_VOID(context);
6819 textFieldTheme_ = context->GetTheme<TextFieldTheme>(tmpHost->GetThemeScopeId());
6820 }
6821
6822 std::string TextFieldPattern::GetTextColor() const
6823 {
6824 auto theme = GetTheme();
6825 CHECK_NULL_RETURN(theme, "");
6826 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
6827 CHECK_NULL_RETURN(layoutProperty, "");
6828 return layoutProperty->GetTextColorValue(theme->GetTextColor()).ColorToString();
6829 }
6830
6831 std::string TextFieldPattern::GetCaretColor() const
6832 {
6833 auto theme = GetTheme();
6834 CHECK_NULL_RETURN(theme, "");
6835 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
6836 CHECK_NULL_RETURN(paintProperty, "");
6837 return paintProperty->GetCursorColorValue(theme->GetCursorColor()).ColorToString();
6838 }
6839
6840 std::string TextFieldPattern::GetPlaceholderColor() const
6841 {
6842 auto theme = GetTheme();
6843 CHECK_NULL_RETURN(theme, "");
6844 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
6845 CHECK_NULL_RETURN(layoutProperty, "");
6846 return layoutProperty->GetPlaceholderTextColorValue(theme->GetPlaceholderColor()).ColorToString();
6847 }
6848
6849 std::string TextFieldPattern::GetFontSize() const
6850 {
6851 auto theme = GetTheme();
6852 CHECK_NULL_RETURN(theme, "");
6853 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
6854 CHECK_NULL_RETURN(layoutProperty, "");
6855 return layoutProperty->GetFontSizeValue(theme->GetFontSize()).ToString();
6856 }
6857
6858 std::string TextFieldPattern::GetMinFontSize() const
6859 {
6860 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
6861 CHECK_NULL_RETURN(layoutProperty, "");
6862 auto minFontSize = layoutProperty->GetAdaptMinFontSize();
6863 return minFontSize.has_value() ? minFontSize->ToString() : "";
6864 }
6865
6866 std::string TextFieldPattern::GetMaxFontSize() const
6867 {
6868 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
6869 CHECK_NULL_RETURN(layoutProperty, "");
6870 auto maxFontSize = layoutProperty->GetAdaptMaxFontSize();
6871 return maxFontSize.has_value() ? maxFontSize->ToString() : "";
6872 }
6873
6874 std::string TextFieldPattern::GetMinFontScale() const
6875 {
6876 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
6877 CHECK_NULL_RETURN(layoutProperty, std::to_string(MINFONTSCALE));
6878 return std::to_string(layoutProperty->GetMinFontScale().value_or(MINFONTSCALE));
6879 }
6880
6881 std::string TextFieldPattern::GetMaxFontScale() const
6882 {
6883 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
6884 CHECK_NULL_RETURN(layoutProperty, std::to_string(MAXFONTSCALE));
6885 return std::to_string(layoutProperty->GetMaxFontScale().value_or(MAXFONTSCALE));
6886 }
6887
6888 std::string TextFieldPattern::GetEllipsisMode() const
6889 {
6890 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
6891 CHECK_NULL_RETURN(layoutProperty, V2::ConvertEllipsisModeToString(EllipsisMode::TAIL));
6892 return V2::ConvertEllipsisModeToString(layoutProperty->GetEllipsisMode().value_or(
6893 EllipsisMode::TAIL));
6894 }
6895
6896 std::string TextFieldPattern::GetTextIndent() const
6897 {
6898 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
6899 CHECK_NULL_RETURN(layoutProperty, "");
6900 auto textIndent = layoutProperty->GetTextIndent();
6901 return textIndent.has_value() ? textIndent->ToString() : "";
6902 }
6903
6904 Ace::FontStyle TextFieldPattern::GetItalicFontStyle() const
6905 {
6906 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
6907 CHECK_NULL_RETURN(layoutProperty, Ace::FontStyle::NORMAL);
6908 return layoutProperty->GetItalicFontStyle().value_or(Ace::FontStyle::NORMAL);
6909 }
6910
6911 std::string TextFieldPattern::GetShowPasswordIconString() const
6912 {
6913 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
6914 CHECK_NULL_RETURN(layoutProperty, "false");
6915 return layoutProperty->GetShowPasswordIconValue(false) ? "true" : "false";
6916 }
6917
6918 std::string TextFieldPattern::GetInputStyleString() const
6919 {
6920 std::string result = isTextInput_ ? "TextInputStyle.Default" : "TextContentStyle.DEFAULT";
6921 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
6922 CHECK_NULL_RETURN(paintProperty, result);
6923 switch (paintProperty->GetInputStyleValue(InputStyle::DEFAULT)) {
6924 case InputStyle::INLINE:
6925 result = isTextInput_ ? "TextInputStyle.Inline" : "TextContentStyle.INLINE";
6926 break;
6927 case InputStyle::DEFAULT:
6928 default:
6929 break;
6930 }
6931 return result;
6932 }
6933
6934 FontWeight TextFieldPattern::GetFontWeight() const
6935 {
6936 auto theme = GetTheme();
6937 CHECK_NULL_RETURN(theme, FontWeight::NORMAL);
6938 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
6939 CHECK_NULL_RETURN(layoutProperty, FontWeight::NORMAL);
6940 return layoutProperty->GetFontWeightValue(theme->GetFontWeight());
6941 }
6942
6943 std::string TextFieldPattern::GetFontFamily() const
6944 {
6945 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
6946 CHECK_NULL_RETURN(layoutProperty, "HarmonyOS Sans");
6947 auto family = layoutProperty->GetFontFamilyValue({ "HarmonyOS Sans" });
6948 return ConvertFontFamily(family);
6949 }
6950
6951 TextAlign TextFieldPattern::GetTextAlign() const
6952 {
6953 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
6954 CHECK_NULL_RETURN(layoutProperty, TextAlign::START);
6955 return layoutProperty->GetTextAlign().value_or(TextAlign::START);
6956 }
6957
6958 uint32_t TextFieldPattern::GetMaxLength() const
6959 {
6960 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
6961 CHECK_NULL_RETURN(layoutProperty, Infinity<uint32_t>());
6962 return layoutProperty->HasMaxLength() ? layoutProperty->GetMaxLengthValue(Infinity<uint32_t>())
6963 : Infinity<uint32_t>();
6964 }
6965
6966 uint32_t TextFieldPattern::GetMaxLines() const
6967 {
6968 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
6969 CHECK_NULL_RETURN(layoutProperty, Infinity<uint32_t>());
6970 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
6971 CHECK_NULL_RETURN(paintProperty, Infinity<uint32_t>());
6972 if (IsNormalInlineState()) {
6973 return layoutProperty->GetMaxViewLinesValue(INLINE_DEFAULT_VIEW_MAXLINE);
6974 }
6975 return layoutProperty->HasMaxLines() ? layoutProperty->GetMaxLinesValue(Infinity<uint32_t>())
6976 : Infinity<uint32_t>();
6977 }
6978
6979 std::u16string TextFieldPattern::GetPlaceHolder() const
6980 {
6981 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
6982 CHECK_NULL_RETURN(layoutProperty, u"");
6983 return layoutProperty->GetPlaceholderValue(u"");
6984 }
6985
6986 std::string TextFieldPattern::GetInputFilter() const
6987 {
6988 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
6989 CHECK_NULL_RETURN(layoutProperty, "");
6990 return layoutProperty->GetInputFilterValue("");
6991 }
6992
6993 std::u16string TextFieldPattern::GetErrorTextString() const
6994 {
6995 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
6996 CHECK_NULL_RETURN(layoutProperty, u"");
6997 return layoutProperty->GetErrorTextValue(u"");
6998 }
6999
7000 bool TextFieldPattern::GetErrorTextState() const
7001 {
7002 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7003 CHECK_NULL_RETURN(layoutProperty, false);
7004 return layoutProperty->GetShowErrorTextValue(false);
7005 }
7006
7007 void TextFieldPattern::SearchRequestKeyboard()
7008 {
7009 StartTwinkling();
7010 if (RequestKeyboardNotByFocusSwitch(RequestKeyboardReason::SEARCH_REQUEST)) {
7011 NotifyOnEditChanged(true);
7012 }
7013 }
7014
7015 std::string TextFieldPattern::GetCopyOptionString() const
7016 {
7017 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7018 CHECK_NULL_RETURN(layoutProperty, "");
7019 std::string copyOptionString = "CopyOptions.Local";
7020 switch (layoutProperty->GetCopyOptionsValue(CopyOptions::Local)) {
7021 case CopyOptions::InApp:
7022 copyOptionString = "CopyOptions.InApp";
7023 break;
7024 case CopyOptions::Local:
7025 copyOptionString = "CopyOptions.Local";
7026 break;
7027 case CopyOptions::Distributed:
7028 copyOptionString = "CopyOptions.Distributed";
7029 break;
7030 case CopyOptions::None:
7031 copyOptionString = "CopyOptions.None";
7032 break;
7033 default:
7034 break;
7035 }
7036 return copyOptionString;
7037 }
7038
7039 std::string TextFieldPattern::GetBarStateString() const
7040 {
7041 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7042 CHECK_NULL_RETURN(layoutProperty, "");
7043 std::string displayModeString;
7044 switch (layoutProperty->GetDisplayModeValue(DisplayMode::AUTO)) {
7045 case DisplayMode::OFF:
7046 displayModeString = "BarState.OFF";
7047 break;
7048 case DisplayMode::ON:
7049 displayModeString = "BarState.ON";
7050 break;
7051 case DisplayMode::AUTO:
7052 default:
7053 displayModeString = "BarState.AUTO";
7054 break;
7055 }
7056 return displayModeString;
7057 }
7058
7059 void TextFieldPattern::UpdateScrollBarOffset()
7060 {
7061 if (!GetScrollBar() && !GetScrollBarProxy()) {
7062 return;
7063 }
7064 auto paddingHeight = GetPaddingTop() + GetPaddingBottom();
7065 auto contentHeight = contentRect_.Height();
7066 if (inlineFocusState_) {
7067 paddingHeight = 0.0f;
7068 contentHeight = GetSingleLineHeight() * GetMaxLines();
7069 }
7070 Size size(frameRect_.Width(), contentHeight + paddingHeight);
7071 UpdateScrollBarRegion(
7072 contentRect_.GetY() - textRect_.GetY(), textRect_.Height() + paddingHeight, size, Offset(0.0, 0.0));
7073 auto tmpHost = GetHost();
7074 CHECK_NULL_VOID(tmpHost);
7075 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
7076 }
7077
7078 void TextFieldPattern::PlayScrollBarAppearAnimation()
7079 {
7080 auto scrollBar = GetScrollBar();
7081 if (scrollBar) {
7082 scrollBar->PlayScrollBarAppearAnimation();
7083 }
7084 }
7085
7086 void TextFieldPattern::ScheduleDisappearDelayTask()
7087 {
7088 auto scrollBar = GetScrollBar();
7089 if (scrollBar) {
7090 scrollBar->SetPressed(false);
7091 scrollBar->PlayScrollBarShrinkAnimation();
7092 scrollBar->ScheduleDisappearDelayTask();
7093 }
7094 }
7095
7096 bool TextFieldPattern::OnScrollCallback(float offset, int32_t source)
7097 {
7098 if (source == SCROLL_FROM_START) {
7099 PlayScrollBarAppearAnimation();
7100 if (selectOverlay_->IsCurrentMenuVisibile()) {
7101 isTextSelectionMenuShow_ = true;
7102 } else if (CheckSelectAreaVisible()) {
7103 isTextSelectionMenuShow_ = false;
7104 }
7105 selectOverlay_->HideMenu(true);
7106 return true;
7107 }
7108 if (IsReachedBoundary(offset)) {
7109 return false;
7110 }
7111 PlayScrollBarAppearAnimation();
7112 OnTextInputScroll(offset);
7113 OnTextAreaScroll(offset);
7114 return true;
7115 }
7116
7117 void TextFieldPattern::CheckScrollable()
7118 {
7119 if (IsTextArea()) {
7120 if (contentController_->IsEmpty()) {
7121 scrollable_ = false;
7122 } else {
7123 scrollable_ = GreatNotEqual(textRect_.Height(), contentRect_.Height());
7124 }
7125 SetScrollEnabled(scrollable_);
7126 } else {
7127 SetScrollEnabled(GreatNotEqual(textRect_.Width(), contentRect_.Width()));
7128 }
7129 }
7130
7131 bool TextFieldPattern::HasStateStyle(UIState state) const
7132 {
7133 auto host = GetHost();
7134 CHECK_NULL_RETURN(host, false);
7135 auto hub = host->GetEventHub<EventHub>();
7136 CHECK_NULL_RETURN(hub, false);
7137 return hub->HasStateStyle(state);
7138 }
7139
7140 double TextFieldPattern::GetScrollBarWidth()
7141 {
7142 auto scrollBar = GetScrollBar();
7143 double scrollBarWidth = 0.0;
7144 if (scrollBar) {
7145 scrollBarWidth = scrollBar->GetBarRect().Width();
7146 }
7147 return scrollBarWidth;
7148 }
7149
7150 void TextFieldPattern::AddCounterNode()
7151 {
7152 auto host = GetHost();
7153 CHECK_NULL_VOID(host);
7154 if (counterDecorator_ && (IsShowPasswordIcon() || IsNormalInlineState())) {
7155 CleanCounterNode();
7156 return;
7157 }
7158 if (!counterDecorator_) {
7159 auto counterDecorator = MakeRefPtr<CounterDecorator>(host);
7160 counterDecorator_ = counterDecorator;
7161 }
7162 }
7163
7164 void TextFieldPattern::SetShowError()
7165 {
7166 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7167 CHECK_NULL_VOID(layoutProperty);
7168 auto passWordMode = IsInPasswordMode();
7169 auto textFieldTheme = GetTheme();
7170 CHECK_NULL_VOID(textFieldTheme);
7171 auto tmpHost = GetHost();
7172 CHECK_NULL_VOID(tmpHost);
7173 auto renderContext = tmpHost->GetRenderContext();
7174 CHECK_NULL_VOID(renderContext);
7175 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
7176 CHECK_NULL_VOID(paintProperty);
7177 auto isUnderLine = IsUnderlineMode();
7178 auto errorText = layoutProperty->GetErrorTextValue(u"");
7179 if (IsShowError()) { // update error state
7180 if (isUnderLine) {
7181 underlineColor_ = userUnderlineColor_.error.value_or(textFieldTheme->GetErrorUnderlineColor());
7182 underlineWidth_ = ERROR_UNDERLINE_WIDTH;
7183 } else if (passWordMode) {
7184 if (!paintProperty->HasBorderWidthFlagByUser()) {
7185 paintProperty->UpdateInnerBorderWidth(textFieldTheme->GetErrorTextInputBorderWidth());
7186 paintProperty->UpdateInnerBorderColor(textFieldTheme->GetPasswordErrorBorderColor());
7187 } else {
7188 BorderColorProperty borderColor;
7189 borderColor.SetColor(textFieldTheme->GetPasswordErrorBorderColor());
7190 renderContext->UpdateBorderColor(borderColor);
7191 }
7192 renderContext->UpdateBackgroundColor(textFieldTheme->GetPasswordErrorInputColor());
7193 layoutProperty->UpdateTextColor(textFieldTheme->GetPasswordErrorTextColor());
7194 if (!layoutProperty->HasPlaceholderTextColor()) {
7195 layoutProperty->UpdatePlaceholderTextColor(textFieldTheme->GetPlaceholderColor());
7196 }
7197 }
7198 }
7199 UpdateErrorTextMargin();
7200 }
7201
7202 float TextFieldPattern::CalcDecoratorWidth(const RefPtr<FrameNode>& decoratorNode)
7203 {
7204 float decoratorWidth = 0.0f;
7205 CHECK_NULL_RETURN(decoratorNode, 0.0f);
7206 auto textPattern = decoratorNode->GetPattern<TextPattern>();
7207 CHECK_NULL_RETURN(textPattern, 0.0f);
7208 auto paragraphs = textPattern->GetParagraphs();
7209 for (auto &&info : paragraphs) {
7210 if (info.paragraph) {
7211 float width = info.paragraph->GetLongestLine();
7212 decoratorWidth = std::max(decoratorWidth, width);
7213 }
7214 }
7215 return decoratorWidth;
7216 }
7217
7218 float TextFieldPattern::CalcDecoratorHeight(const RefPtr<FrameNode>& decoratorNode)
7219 {
7220 CHECK_NULL_RETURN(decoratorNode, 0.0f);
7221 auto geometryNode = decoratorNode->GetGeometryNode();
7222 CHECK_NULL_RETURN(geometryNode, 0.0f);
7223 return geometryNode->GetFrameRect().Height();
7224 }
7225
7226 void TextFieldPattern::UpdateErrorTextMargin()
7227 {
7228 auto tmpHost = GetHost();
7229 CHECK_NULL_VOID(tmpHost);
7230 if (IsShowError()) {
7231 if (!errorDecorator_) {
7232 auto errorDecorator = MakeRefPtr<ErrorDecorator>(tmpHost);
7233 errorDecorator_ = errorDecorator;
7234 }
7235 errorDecorator_->UpdateTextFieldMargin();
7236 } else {
7237 errorDecorator_.Reset();
7238 }
7239 }
7240
7241 void TextFieldPattern::ApplyUnderlineTheme()
7242 {
7243 if (!IsUnderlineMode()) {
7244 return;
7245 }
7246 SetThemeAttr();
7247 auto theme = GetTheme();
7248 CHECK_NULL_VOID(theme);
7249 if (IsShowError()) {
7250 underlineColor_ = userUnderlineColor_.error.value_or(theme->GetErrorUnderlineColor());
7251 } else {
7252 underlineColor_ = HasFocus() ? userUnderlineColor_.typing.value_or(theme->GetUnderlineTypingColor())
7253 : userUnderlineColor_.normal.value_or(theme->GetUnderlineColor());
7254 }
7255 underlineWidth_ = HasFocus() ? TYPING_UNDERLINE_WIDTH : UNDERLINE_WIDTH;
7256 }
7257
7258 float TextFieldPattern::GetMarginBottom() const
7259 {
7260 auto tmpHost = GetHost();
7261 CHECK_NULL_RETURN(tmpHost, 0.0f);
7262 auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
7263 CHECK_NULL_RETURN(layoutProperty, 0.0f);
7264 const auto& getMargin = layoutProperty->GetMarginProperty();
7265 if (getMargin && getMargin->bottom.has_value()) {
7266 return getMargin->bottom->GetDimension().ConvertToPx();
7267 }
7268 return 0.0f;
7269 }
7270
7271 std::string TextFieldPattern::GetShowResultImageSrc() const
7272 {
7273 auto tmpHost = GetHost();
7274 CHECK_NULL_RETURN(tmpHost, "");
7275 auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
7276 CHECK_NULL_RETURN(layoutProperty, "");
7277 auto showImageSource = layoutProperty->GetShowPasswordSourceInfo();
7278 if (showImageSource && !showImageSource->GetSrc().empty()) {
7279 return showImageSource->GetSrc();
7280 }
7281 return SHOW_PASSWORD_SVG;
7282 }
7283
7284 std::string TextFieldPattern::GetNormalUnderlineColorStr() const
7285 {
7286 auto theme = GetTheme();
7287 CHECK_NULL_RETURN(theme, "");
7288 Color normal = userUnderlineColor_.normal.value_or(theme->GetUnderlineColor());
7289 return normal.ColorToString();
7290 }
7291
7292 std::string TextFieldPattern::GetTypingUnderlineColorStr() const
7293 {
7294 auto theme = GetTheme();
7295 CHECK_NULL_RETURN(theme, "");
7296 Color typing = userUnderlineColor_.typing.value_or(theme->GetUnderlineTypingColor());
7297 return typing.ColorToString();
7298 }
7299
7300 std::string TextFieldPattern::GetDisableUnderlineColorStr() const
7301 {
7302 auto theme = GetTheme();
7303 CHECK_NULL_RETURN(theme, "");
7304 Color disable = userUnderlineColor_.disable.value_or(theme->GetDisableUnderlineColor());
7305 return disable.ColorToString();
7306 }
7307
7308 std::string TextFieldPattern::GetErrorUnderlineColorStr() const
7309 {
7310 auto theme = GetTheme();
7311 CHECK_NULL_RETURN(theme, "");
7312 Color error = userUnderlineColor_.error.value_or(theme->GetErrorUnderlineColor());
7313 return error.ColorToString();
7314 }
7315
7316 std::string TextFieldPattern::GetHideResultImageSrc() const
7317 {
7318 auto tmpHost = GetHost();
7319 CHECK_NULL_RETURN(tmpHost, "");
7320 auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
7321 CHECK_NULL_RETURN(layoutProperty, "");
7322 auto hideSourceInfo = layoutProperty->GetHidePasswordSourceInfo();
7323 if (hideSourceInfo && !hideSourceInfo->GetSrc().empty()) {
7324 return hideSourceInfo->GetSrc();
7325 }
7326 return HIDE_PASSWORD_SVG;
7327 }
7328
7329 void TextFieldPattern::RestorePreInlineStates()
7330 {
7331 ResetContextAttr();
7332 ApplyNormalTheme();
7333 ApplyUnderlineTheme();
7334 ProcessInnerPadding();
7335 ProcessResponseArea();
7336 ProcessRectPadding();
7337 }
7338
7339 void TextFieldPattern::ProcessRectPadding()
7340 {
7341 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7342 CHECK_NULL_VOID(layoutProperty);
7343 auto& paddingProperty = layoutProperty->GetPaddingProperty();
7344 CHECK_NULL_VOID(paddingProperty);
7345 auto top = paddingProperty->top.has_value() ? paddingProperty->top->GetDimension().ConvertToPx() : 0.0f;
7346 textRect_.SetTop(top);
7347 }
7348
7349 void TextFieldPattern::TextAreaInputRectUpdate(RectF& rect)
7350 {
7351 auto tmpHost = GetHost();
7352 CHECK_NULL_VOID(tmpHost);
7353 auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
7354 CHECK_NULL_VOID(layoutProperty);
7355 auto theme = GetTheme();
7356 CHECK_NULL_VOID(theme);
7357 if (IsTextArea() && !contentController_->IsEmpty()) {
7358 auto inputContentWidth = GetParagraph()->GetMaxIntrinsicWidth();
7359 switch (layoutProperty->GetTextAlignValue(TextAlign::START)) {
7360 case TextAlign::START:
7361 if (inputContentWidth < contentRect_.Width()) {
7362 rect.SetWidth(inputContentWidth);
7363 }
7364 break;
7365 case TextAlign::CENTER:
7366 if (inputContentWidth < contentRect_.Width()) {
7367 rect.SetLeft(
7368 static_cast<float>(rect.GetX()) + contentRect_.Width() / 2.0f - inputContentWidth / 2.0f);
7369 rect.SetWidth(inputContentWidth);
7370 }
7371 break;
7372 case TextAlign::END:
7373 if (inputContentWidth < contentRect_.Width()) {
7374 rect.SetLeft(static_cast<float>(rect.GetX()) + contentRect_.Width() -
7375 static_cast<float>(theme->GetCursorWidth().ConvertToPx()) - inputContentWidth);
7376 rect.SetWidth(inputContentWidth);
7377 }
7378 break;
7379 default:
7380 break;
7381 }
7382 }
7383 }
7384
7385 void TextFieldPattern::TextIsEmptyRect(RectF& rect)
7386 {
7387 rect = selectController_->CalculateEmptyValueCaretRect();
7388 }
7389
7390 void TextFieldPattern::UpdateRectByTextAlign(RectF& rect)
7391 {
7392 auto tmpHost = GetHost();
7393 CHECK_NULL_VOID(tmpHost);
7394 auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
7395 CHECK_NULL_VOID(layoutProperty);
7396 if (!layoutProperty->HasTextAlign()) {
7397 return;
7398 }
7399 switch (layoutProperty->GetTextAlignValue(TextAlign::START)) {
7400 case TextAlign::START:
7401 return;
7402 case TextAlign::CENTER:
7403 rect.SetLeft(rect.GetOffset().GetX() + (contentRect_.Width() - textRect_.Width()) * 0.5f);
7404 return;
7405 case TextAlign::END:
7406 rect.SetLeft(rect.GetOffset().GetX() + (contentRect_.Width() - textRect_.Width()));
7407 return;
7408 default:
7409 return;
7410 }
7411 }
7412
7413 void TextFieldPattern::ProcessInlinePaddingAndMargin()
7414 {
7415 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7416 CHECK_NULL_VOID(layoutProperty);
7417 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
7418 auto theme = GetTheme();
7419 CHECK_NULL_VOID(theme);
7420 PaddingProperty userPadding;
7421 MarginProperty userMargin;
7422 if (paintProperty->HasPaddingByUser()) {
7423 userPadding = paintProperty->GetPaddingByUserValue();
7424 } else {
7425 auto themePadding = IsUnderlineMode() ? theme->GetUnderlinePadding() : theme->GetPadding();
7426 userPadding.top = CalcLength(CalcLength(themePadding.Top()).GetDimension());
7427 userPadding.bottom = CalcLength(CalcLength(themePadding.Bottom()).GetDimension());
7428 userPadding.left = CalcLength(CalcLength(themePadding.Left()).GetDimension());
7429 userPadding.right = CalcLength(CalcLength(themePadding.Right()).GetDimension());
7430 }
7431 if (paintProperty->HasMarginByUser()) {
7432 userMargin = paintProperty->GetMarginByUserValue();
7433 }
7434 MarginProperty margin;
7435 margin.bottom = CalcLength(userMargin.bottom->GetDimension() + userPadding.bottom->GetDimension());
7436 margin.right = CalcLength(userMargin.right->GetDimension() + userPadding.right->GetDimension());
7437 margin.left = CalcLength(userMargin.left->GetDimension() + userPadding.left->GetDimension());
7438 margin.top = CalcLength(userMargin.top->GetDimension() + userPadding.top->GetDimension());
7439 layoutProperty->UpdateMargin(margin);
7440 if (!IsTextArea()) {
7441 layoutProperty->UpdatePlaceholderMaxLines(layoutProperty->GetMaxViewLinesValue(INLINE_DEFAULT_VIEW_MAXLINE));
7442 layoutProperty->ResetMaxLines();
7443 }
7444 if (layoutProperty->HasTextOverflow()) {
7445 layoutProperty->UpdateTextOverflowMaxLines(layoutProperty->GetMaxViewLinesValue(INLINE_DEFAULT_VIEW_MAXLINE));
7446 }
7447 }
7448
7449 void TextFieldPattern::ApplyInlineTheme()
7450 {
7451 if (!IsInlineMode()) {
7452 return;
7453 }
7454 auto tmpHost = GetHost();
7455 CHECK_NULL_VOID(tmpHost);
7456 auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
7457 CHECK_NULL_VOID(layoutProperty);
7458 auto renderContext = tmpHost->GetRenderContext();
7459 CHECK_NULL_VOID(renderContext);
7460 auto theme = GetTheme();
7461 CHECK_NULL_VOID(theme);
7462 layoutProperty->UpdateTextColor(theme->GetInlineTextColor());
7463 auto radius = theme->GetInlineRadiusSize();
7464 renderContext->UpdateBorderRadius({ radius.GetX(), radius.GetY(), radius.GetY(), radius.GetX() });
7465 renderContext->UpdateBackgroundColor(theme->GetInlineBgColor());
7466 BorderWidthProperty inlineBorderWidth;
7467 inlineBorderWidth.SetBorderWidth(INLINE_BORDER_WIDTH);
7468 layoutProperty->UpdateBorderWidth(inlineBorderWidth);
7469 renderContext->UpdateBorderWidth(inlineBorderWidth);
7470 BorderColorProperty inlineBorderColor;
7471 inlineBorderColor.SetColor(theme->GetInlineBorderColor());
7472 renderContext->UpdateBorderColor(inlineBorderColor);
7473
7474 if (layoutProperty->GetNonAutoLayoutDirection() == TextDirection::RTL) {
7475 layoutProperty->UpdatePadding({ CalcLength(theme->getInlinePaddingRight()),
7476 CalcLength(theme->getInlinePaddingLeft()), CalcLength(0.0f), CalcLength(0.0f) });
7477 } else {
7478 layoutProperty->UpdatePadding({ CalcLength(theme->getInlinePaddingLeft()),
7479 CalcLength(theme->getInlinePaddingRight()), CalcLength(0.0f), CalcLength(0.0f)});
7480 }
7481 ProcessInnerPadding();
7482 ProcessInlinePaddingAndMargin();
7483 }
7484
7485 bool TextFieldPattern::ResetObscureTickCountDown()
7486 {
7487 auto oldTickCountDown_ = obscureTickCountDown_;
7488 if (!IsTextArea() && GetTextObscured() && IsInPasswordMode()) {
7489 obscureTickCountDown_ = 0;
7490 }
7491 return oldTickCountDown_ != obscureTickCountDown_;
7492 }
7493
7494 bool TextFieldPattern::IsInPasswordMode() const
7495 {
7496 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7497 CHECK_NULL_RETURN(layoutProperty, false);
7498 auto inputType = layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED);
7499 return inputType == TextInputType::VISIBLE_PASSWORD || inputType == TextInputType::NUMBER_PASSWORD ||
7500 inputType == TextInputType::SCREEN_LOCK_PASSWORD || inputType == TextInputType::NEW_PASSWORD;
7501 }
7502
7503 bool TextFieldPattern::IsNormalInlineState() const
7504 {
7505 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
7506 CHECK_NULL_RETURN(paintProperty, false);
7507 auto tmpHost = GetHost();
7508 CHECK_NULL_RETURN(tmpHost, false);
7509 auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
7510 CHECK_NULL_RETURN(layoutProperty, false);
7511 return paintProperty->GetInputStyleValue(InputStyle::DEFAULT) == InputStyle::INLINE &&
7512 (layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED) == TextInputType::UNSPECIFIED ||
7513 layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED) == TextInputType::TEXT);
7514 }
7515
7516 bool TextFieldPattern::IsUnspecifiedOrTextType() const
7517 {
7518 auto tmpHost = GetHost();
7519 CHECK_NULL_RETURN(tmpHost, false);
7520 auto layoutProperty = tmpHost->GetLayoutProperty<TextFieldLayoutProperty>();
7521 CHECK_NULL_RETURN(layoutProperty, false);
7522 auto inputType = layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED);
7523 return inputType == TextInputType::UNSPECIFIED || inputType == TextInputType::TEXT;
7524 }
7525
7526 void TextFieldPattern::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
7527 {
7528 /* no fixed attr below, just return */
7529 if (filter.IsFastFilter()) {
7530 return;
7531 }
7532 json->PutExtAttr("placeholder", UtfUtils::Str16DebugToStr8(GetPlaceHolder()).c_str(), filter);
7533 json->PutExtAttr("text", contentController_->GetTextValue().c_str(), filter);
7534 json->PutExtAttr("fontSize", GetFontSize().c_str(), filter);
7535 json->PutExtAttr("fontColor", GetTextColor().c_str(), filter);
7536 json->PutExtAttr("fontStyle",
7537 GetItalicFontStyle() == Ace::FontStyle::NORMAL ? "FontStyle.Normal" : "FontStyle.Italic", filter);
7538 json->PutExtAttr("fontWeight", V2::ConvertWrapFontWeightToStirng(GetFontWeight()).c_str(), filter);
7539 json->PutExtAttr("fontFamily", GetFontFamily().c_str(), filter);
7540 json->PutExtAttr("textAlign", V2::ConvertWrapTextAlignToString(GetTextAlign()).c_str(), filter);
7541 json->PutExtAttr("caretColor", GetCaretColor().c_str(), filter);
7542 json->PutExtAttr("type", TextInputTypeToString().c_str(), filter);
7543 json->PutExtAttr("contentType", TextContentTypeToString().c_str(), filter);
7544 json->PutExtAttr("placeholderColor", GetPlaceholderColor().c_str(), filter);
7545 json->PutExtAttr("placeholderFont", GetPlaceholderFont().c_str(), filter);
7546 json->PutExtAttr("enterKeyType", TextInputActionToString().c_str(), filter);
7547 json->PutExtAttr("maxLength", GreatOrEqual(GetMaxLength(),
7548 Infinity<uint32_t>()) ? "INF" : std::to_string(GetMaxLength()).c_str(), filter);
7549 json->PutExtAttr("inputFilter", GetInputFilter().c_str(), filter);
7550 json->PutExtAttr("copyOption", GetCopyOptionString().c_str(), filter);
7551 json->PutExtAttr("style", GetInputStyleString().c_str(), filter);
7552
7553 auto jsonValue = JsonUtil::Create(true);
7554 if (IsShowPasswordSymbol()) {
7555 jsonValue->Put("onIconSrc", static_cast<int64_t>(GetTheme()->GetShowSymbolId()));
7556 jsonValue->Put("offIconSrc", static_cast<int64_t>(GetTheme()->GetHideSymbolId()));
7557 } else {
7558 jsonValue->Put("onIconSrc", GetShowResultImageSrc().c_str());
7559 jsonValue->Put("offIconSrc", GetHideResultImageSrc().c_str());
7560 }
7561 json->PutExtAttr("passwordIcon", jsonValue->ToString().c_str(), filter);
7562 json->PutExtAttr("showError", GetErrorTextState() ? UtfUtils::Str16DebugToStr8(GetErrorTextString()).c_str() :
7563 "undefined", filter);
7564 json->PutExtAttr("maxLines", GreatOrEqual(GetMaxLines(),
7565 Infinity<uint32_t>()) ? "INF" : std::to_string(GetMaxLines()).c_str(), filter);
7566 json->PutExtAttr("barState", GetBarStateString().c_str(), filter);
7567 json->PutExtAttr("caretPosition", std::to_string(GetCaretIndex()).c_str(), filter);
7568 json->PutExtAttr("enablePreviewText", GetSupportPreviewText(), filter);
7569 json->PutExtAttr("minFontScale", GetMinFontScale().c_str(), filter);
7570 json->PutExtAttr("maxFontScale", GetMaxFontScale().c_str(), filter);
7571 json->PutExtAttr("ellipsisMode",GetEllipsisMode().c_str(), filter);
7572 ToJsonValueForOption(json, filter);
7573 ToJsonValueSelectOverlay(json, filter);
7574 }
7575
7576 void TextFieldPattern::ToTreeJson(std::unique_ptr<JsonValue>& json, const InspectorConfig& config) const
7577 {
7578 Pattern::ToTreeJson(json, config);
7579 json->Put(TreeKey::CONTENT, contentController_->GetTextValue().c_str());
7580 json->Put(TreeKey::PLACEHOLDER, GetPlaceHolder().c_str());
7581 }
7582
7583 void TextFieldPattern::ToJsonValueForOption(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
7584 {
7585 auto underlineColorJsonValue = JsonUtil::Create(true);
7586 underlineColorJsonValue->Put("normal", GetNormalUnderlineColorStr().c_str());
7587 underlineColorJsonValue->Put("typing", GetTypingUnderlineColorStr().c_str());
7588 underlineColorJsonValue->Put("error", GetErrorUnderlineColorStr().c_str());
7589 underlineColorJsonValue->Put("disable", GetDisableUnderlineColorStr().c_str());
7590 json->PutExtAttr("underlineColor", underlineColorJsonValue->ToString().c_str(), filter);
7591
7592 auto host = GetHost();
7593 CHECK_NULL_VOID(host);
7594 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
7595 CHECK_NULL_VOID(layoutProperty);
7596 auto jsonShowCounter = JsonUtil::Create(true);
7597 jsonShowCounter->Put("value", layoutProperty->GetShowCounterValue(false));
7598 auto jsonShowCounterOptions = JsonUtil::Create(true);
7599 jsonShowCounterOptions->Put("thresholdPercentage", layoutProperty->GetSetCounterValue(DEFAULT_MODE));
7600 jsonShowCounterOptions->Put("highlightBorder", layoutProperty->GetShowHighlightBorderValue(true));
7601 jsonShowCounter->Put("options", jsonShowCounterOptions);
7602 json->PutExtAttr("showCounter", jsonShowCounter, filter);
7603 json->PutExtAttr("keyboardAppearance", static_cast<int32_t>(keyboardAppearance_), filter);
7604 json->PutExtAttr("enableHapticFeedback", isEnableHapticFeedback_ ? "true" : "false", filter);
7605 }
7606
7607 void TextFieldPattern::ToJsonValueSelectOverlay(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
7608 {
7609 json->PutExtAttr("CaretStatus", cursorVisible_ ? "show" : "hide", filter);
7610 json->PutExtAttr("CaretTwinkling", isCaretTwinkling_ ? "true" : "false", filter);
7611 json->PutExtAttr("caretRect", selectController_->GetCaretRect().ToString().c_str(), filter);
7612 json->PutExtAttr("caretWidth", std::to_string(selectController_->GetCaretRect().Width()).c_str(), filter);
7613 json->PutExtAttr("isShowMagnifier", magnifierController_->GetShowMagnifier() ? "true" : "false", filter);
7614 json->PutExtAttr("MagnifierPosition", magnifierController_->GetLocalOffset().ToString().c_str(), filter);
7615
7616 auto manager = selectOverlay_->GetManager<SelectContentOverlayManager>();
7617 CHECK_NULL_VOID(manager);
7618 auto selectOverlayInfo = manager->GetSelectOverlayInfo();
7619 CHECK_NULL_VOID(selectOverlayInfo);
7620
7621 //handle info
7622 json->PutExtAttr("IsSingleHandle", selectOverlayInfo->isSingleHandle ? "true" : "false", filter);
7623 json->PutExtAttr("IsHandleReverse", selectOverlayInfo->handleReverse ? "true" : "false", filter);
7624 json->PutExtAttr("FirstHandleRect", selectOverlayInfo->firstHandle.paintRect.ToString().c_str(), filter);
7625 json->PutExtAttr("FirstHandleStartPoint",
7626 selectOverlayInfo->firstHandle.paintInfo.startPoint.ToString().c_str(), filter);
7627 json->PutExtAttr("FirstHandleEndPoint",
7628 selectOverlayInfo->firstHandle.paintInfo.endPoint.ToString().c_str(), filter);
7629 json->PutExtAttr("IsFirstHandlePaintByPoints",
7630 selectOverlayInfo->firstHandle.isPaintHandleWithPoints ? "true" : "false", filter);
7631 json->PutExtAttr("SecondHandleRect", selectOverlayInfo->secondHandle.paintRect.ToString().c_str(), filter);
7632 json->PutExtAttr("SecondHandleStartPoint",
7633 selectOverlayInfo->secondHandle.paintInfo.startPoint.ToString().c_str(), filter);
7634 json->PutExtAttr("SecondHandleEndPoint",
7635 selectOverlayInfo->secondHandle.paintInfo.endPoint.ToString().c_str(), filter);
7636 json->PutExtAttr("IsSecondHandlePaintByPoints",
7637 selectOverlayInfo->secondHandle.isPaintHandleWithPoints ? "true" : "false", filter);
7638
7639 //menu
7640 auto menuNode = manager->GetSelectOverlayNode();
7641 CHECK_NULL_VOID(menuNode);
7642 json->PutExtAttr("MenuNode", menuNode->GetTag().c_str(), filter);
7643 if (menuNode->GetAncestorNodeOfFrame(true)) {
7644 json->PutExtAttr("MountOn", menuNode->GetAncestorNodeOfFrame(true)->GetTag().c_str(), filter);
7645 }
7646 auto menuLayoutProperty = menuNode->GetLayoutProperty();
7647 CHECK_NULL_VOID(menuLayoutProperty);
7648 auto menuVisible = static_cast<int32_t>(menuLayoutProperty->GetVisibility().value_or(VisibleType::VISIBLE));
7649 json->PutExtAttr("Visible", std::to_string(menuVisible).c_str(), filter);
7650 auto menuGeometryNode = menuNode->GetGeometryNode();
7651 CHECK_NULL_VOID(menuGeometryNode);
7652 json->PutExtAttr("MenuFrameRect", menuGeometryNode->GetFrameRect().ToString().c_str(), filter);
7653 json->PutExtAttr("MenuItemCount", std::to_string(selectOverlayInfo->menuOptionItems.size()).c_str(), filter);
7654 for (auto menuItme : selectOverlayInfo->menuOptionItems) {
7655 json->PutExtAttr("MenuItme", menuItme.content.value_or("").c_str(), filter);
7656 }
7657 }
7658
7659 void TextFieldPattern::FromJson(const std::unique_ptr<JsonValue>& json)
7660 {
7661 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
7662 layoutProperty->UpdatePlaceholder(UtfUtils::Str8DebugToStr16(json->GetString("placeholder")));
7663 UpdateEditingValue(json->GetString("text"), StringUtils::StringToInt(json->GetString("caretPosition")));
7664 FireOnTextChangeEvent();
7665 UpdateSelection(GetCaretIndex());
7666 auto maxLines = json->GetString("maxLines");
7667 if (!maxLines.empty() && maxLines != "INF") {
7668 layoutProperty->UpdateMaxLines(StringUtils::StringToUint(maxLines));
7669 }
7670 static const std::unordered_map<std::string, CopyOptions> uMap = {
7671 { "CopyOptions.None", CopyOptions::None },
7672 { "CopyOptions.InApp", CopyOptions::InApp },
7673 { "CopyOptions.Local", CopyOptions::Local },
7674 { "CopyOptions.Distributed", CopyOptions::Distributed },
7675 };
7676 auto copyOption = json->GetString("copyOption");
7677 CopyOptions copyOptionsEnum = CopyOptions::Local;
7678 auto iter = uMap.find(copyOption);
7679 if (iter != uMap.end()) {
7680 copyOptionsEnum = iter->second;
7681 }
7682 layoutProperty->UpdateCopyOptions(copyOptionsEnum);
7683 Pattern::FromJson(json);
7684 }
7685
7686 void TextFieldPattern::SetAccessibilityAction()
7687 {
7688 auto host = GetHost();
7689 CHECK_NULL_VOID(host);
7690 auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
7691 CHECK_NULL_VOID(accessibilityProperty);
7692 accessibilityProperty->SetAccessibilityGroup(true);
7693 SetAccessibilityActionOverlayAndSelection();
7694 SetAccessibilityActionGetAndSetCaretPosition();
7695 SetAccessibilityMoveTextAction();
7696 SetAccessibilityErrotText();
7697 }
7698
7699 void TextFieldPattern::SetAccessibilityActionOverlayAndSelection()
7700 {
7701 auto host = GetHost();
7702 CHECK_NULL_VOID(host);
7703 auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
7704 CHECK_NULL_VOID(accessibilityProperty);
7705 accessibilityProperty->SetActionSetText([weakPtr = WeakClaim(this)](const std::string& value) {
7706 const auto& pattern = weakPtr.Upgrade();
7707 CHECK_NULL_VOID(pattern);
7708 pattern->InsertValue(UtfUtils::Str8DebugToStr16(value));
7709 });
7710
7711 accessibilityProperty->SetActionSetSelection([weakPtr = WeakClaim(this)](int32_t start,
7712 int32_t end, bool isForward) {
7713 const auto& pattern = weakPtr.Upgrade();
7714 CHECK_NULL_VOID(pattern);
7715 pattern->SetSelectionFlag(start, end, std::nullopt, isForward);
7716 });
7717
7718 accessibilityProperty->SetActionCopy([weakPtr = WeakClaim(this)]() {
7719 const auto& pattern = weakPtr.Upgrade();
7720 CHECK_NULL_VOID(pattern);
7721 if (pattern->AllowCopy()) {
7722 pattern->HandleOnCopy();
7723 pattern->CloseSelectOverlay(true);
7724 }
7725 });
7726
7727 accessibilityProperty->SetActionCut([weakPtr = WeakClaim(this)]() {
7728 const auto& pattern = weakPtr.Upgrade();
7729 CHECK_NULL_VOID(pattern);
7730 if (pattern->AllowCopy()) {
7731 pattern->HandleOnCut();
7732 pattern->CloseSelectOverlay(true);
7733 }
7734 });
7735
7736 accessibilityProperty->SetActionPaste([weakPtr = WeakClaim(this)]() {
7737 const auto& pattern = weakPtr.Upgrade();
7738 CHECK_NULL_VOID(pattern);
7739 pattern->HandleOnPaste();
7740 pattern->CloseSelectOverlay(true);
7741 });
7742
7743 accessibilityProperty->SetActionClearSelection([weakPtr = WeakClaim(this)]() {
7744 const auto& pattern = weakPtr.Upgrade();
7745 CHECK_NULL_VOID(pattern);
7746 auto current = pattern->selectController_->GetEndIndex();
7747 pattern->SetInSelectMode(SelectionMode::NONE);
7748 pattern->UpdateSelection(current);
7749 pattern->SetSelectionFlag(current, current, std::nullopt);
7750 pattern->CloseSelectOverlay(true);
7751 pattern->StartTwinkling();
7752 });
7753 }
7754
7755 void TextFieldPattern::SetAccessibilityActionGetAndSetCaretPosition()
7756 {
7757 auto host = GetHost();
7758 CHECK_NULL_VOID(host);
7759 auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
7760 CHECK_NULL_VOID(accessibilityProperty);
7761 accessibilityProperty->SetActionSetIndex([weakPtr = WeakClaim(this)](int32_t index) {
7762 const auto& pattern = weakPtr.Upgrade();
7763 CHECK_NULL_VOID(pattern);
7764 pattern->SetCaretPosition(index);
7765 });
7766
7767 accessibilityProperty->SetActionGetIndex([weakPtr = WeakClaim(this)]() -> int32_t {
7768 const auto& pattern = weakPtr.Upgrade();
7769 CHECK_NULL_RETURN(pattern, -1);
7770 auto index = pattern->selectController_->GetCaretIndex();
7771 return index;
7772 });
7773 }
7774
7775 void TextFieldPattern::SetAccessibilityMoveTextAction()
7776 {
7777 auto host = GetHost();
7778 CHECK_NULL_VOID(host);
7779 auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
7780 CHECK_NULL_VOID(accessibilityProperty);
7781 accessibilityProperty->SetActionMoveText([weakPtr = WeakClaim(this)](int32_t moveUnit, bool forward) {
7782 const auto& pattern = weakPtr.Upgrade();
7783 CHECK_NULL_VOID(pattern);
7784 auto host = pattern->GetHost();
7785 CHECK_NULL_VOID(host);
7786 if (pattern->contentController_->IsEmpty()) {
7787 return;
7788 }
7789 int range = 0;
7790 if (moveUnit == 1) {
7791 range = 1;
7792 }
7793 auto caretPosition = forward ? pattern->selectController_->GetCaretIndex() + range
7794 : pattern->selectController_->GetCaretIndex() - range;
7795 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
7796 pattern->SetCaretPosition(caretPosition);
7797 });
7798 }
7799
7800 void TextFieldPattern::SetAccessibilityErrotText()
7801 {
7802 auto host = GetHost();
7803 CHECK_NULL_VOID(host);
7804 auto accessibilityProperty = host->GetAccessibilityProperty<TextFieldAccessibilityProperty>();
7805 CHECK_NULL_VOID(accessibilityProperty);
7806 accessibilityProperty->SetErrorText(UtfUtils::Str16DebugToStr8(GetErrorTextString()));
7807 }
7808
7809 void TextFieldPattern::StopEditing()
7810 {
7811 if (!HasFocus()) {
7812 return;
7813 }
7814 auto host = GetHost();
7815 CHECK_NULL_VOID(host);
7816 ContainerScope scope(host->GetInstanceId());
7817 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "textfield %{public}d Stop Editing", host->GetId());
7818 FocusHub::LostFocusToViewRoot();
7819 UpdateSelection(selectController_->GetCaretIndex());
7820 StopTwinkling();
7821 CloseKeyboard(true);
7822 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
7823 }
7824
7825 void TextFieldPattern::DumpInfo()
7826 {
7827 auto host = GetHost();
7828 CHECK_NULL_VOID(host);
7829 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
7830 CHECK_NULL_VOID(layoutProperty);
7831 auto& dumpLog = DumpLog::GetInstance();
7832 dumpLog.AddDesc(std::string("Content:").append(GetDumpTextValue()));
7833 dumpLog.AddDesc(std::string("autoWidth: ").append(std::to_string(layoutProperty->GetWidthAutoValue(false))));
7834 dumpLog.AddDesc(std::string("MaxLength:").append(std::to_string(GetMaxLength())));
7835 dumpLog.AddDesc(std::string("fontSize:").append(GetFontSize()));
7836 dumpLog.AddDesc(std::string("fontWeight:").append(V2::ConvertWrapFontWeightToStirng(GetFontWeight())));
7837 dumpLog.AddDesc(std::string("fontFamily:").append(GetFontFamily()));
7838 auto flag = GetItalicFontStyle() == Ace::FontStyle::NORMAL;
7839 dumpLog.AddDesc(std::string("fontStyle:").append(flag ? "FontStyle.Normal" : "FontStyle.Italic"));
7840 dumpLog.AddDesc(std::string("InputFilter:").append(GetInputFilter()));
7841 auto lineHeight = layoutProperty->GetLineHeight().value_or(0.0_vp).ConvertToPx();
7842 dumpLog.AddDesc(std::string("lineHeight:").append(std::to_string(lineHeight)));
7843 auto maxLines = GreatOrEqual(GetMaxLines(), Infinity<uint32_t>()) ? "INF" : std::to_string(GetMaxLines());
7844 dumpLog.AddDesc(std::string("MaxLines:").append(maxLines));
7845 dumpLog.AddDesc(std::string("TextIndent:").append(GetTextIndent()));
7846 dumpLog.AddDesc(std::string("showError:").append(GetErrorTextState() ?
7847 UtfUtils::Str16DebugToStr8(GetErrorTextString()) : "undefined"));
7848 dumpLog.AddDesc(std::string("CopyOption:").append(GetCopyOptionString()));
7849 dumpLog.AddDesc(std::string("TextAlign:").append(V2::ConvertWrapTextAlignToString(GetTextAlign())));
7850 dumpLog.AddDesc(std::string("CaretPosition:").append(std::to_string(GetCaretIndex())));
7851 dumpLog.AddDesc(std::string("type:").append(TextInputTypeToString()));
7852 dumpLog.AddDesc(std::string("enterKeyType:").append(TextInputActionToString()));
7853 dumpLog.AddDesc(std::string("HasFocus:").append(std::to_string(HasFocus())));
7854 dumpLog.AddDesc(std::string("enableKeyboardOnFocus:").append(std::to_string(needToRequestKeyboardOnFocus_)));
7855 dumpLog.AddDesc(std::string("supportPreviewText:").append(std::to_string(GetSupportPreviewText())));
7856 dumpLog.AddDesc(
7857 std::string("enableAutoFill:").append(std::to_string(layoutProperty->GetEnableAutoFillValue(true))));
7858 dumpLog.AddDesc(std::string("contentType:").append(TextContentTypeToString()));
7859 dumpLog.AddDesc(std::string("style:").append(GetInputStyleString()));
7860 dumpLog.AddDesc(std::string("PreviewTextStart:").append(std::to_string(GetPreviewTextStart())));
7861 dumpLog.AddDesc(std::string("PreviewTextEnd:").append(std::to_string(GetPreviewTextEnd())));
7862 dumpLog.AddDesc(std::string("PreTextValue:").append(UtfUtils::Str16DebugToStr8(GetPreviewTextValue())));
7863 dumpLog.AddDesc(textSelector_.ToString());
7864 dumpLog.AddDesc(std::string("wordBreak:")
7865 .append(V2::ConvertWrapWordBreakToString(layoutProperty->GetWordBreak().value_or(WordBreak::BREAK_WORD))));
7866 dumpLog.AddDesc(std::string("HeightAdaptivePolicy: ").append(V2::ConvertWrapTextHeightAdaptivePolicyToString(
7867 layoutProperty->GetHeightAdaptivePolicy().value_or(TextHeightAdaptivePolicy::MAX_LINES_FIRST))));
7868 dumpLog.AddDesc(std::string("IsAIWrite: ").append(std::to_string(IsShowAIWrite())));
7869 DumpPlaceHolderInfo();
7870 DumpScaleInfo();
7871 DumpTextEngineInfo();
7872 DumpAdvanceInfo();
7873 }
7874
7875 void TextFieldPattern::DumpTextEngineInfo()
7876 {
7877 auto& dumpLog = DumpLog::GetInstance();
7878 dumpLog.AddDesc(std::string("-----TextEngine paragraphs_ info-----"));
7879 CHECK_NULL_VOID(paragraph_);
7880 dumpLog.AddDesc(std::string("GetTextWidth:")
7881 .append(std::to_string(paragraph_->GetTextWidth()))
7882 .append(" GetHeight:")
7883 .append(std::to_string(paragraph_->GetHeight()))
7884 .append(" GetMaxWidth:")
7885 .append(std::to_string(paragraph_->GetMaxWidth()))
7886 .append(" GetMaxIntrinsicWidth:")
7887 .append(std::to_string(paragraph_->GetMaxIntrinsicWidth())));
7888 dumpLog.AddDesc(std::string("GetLineCount:")
7889 .append(std::to_string(paragraph_->GetLineCount()))
7890 .append(" GetLongestLine:")
7891 .append(std::to_string(paragraph_->GetLongestLine()))
7892 .append(" GetLongestLineWithIndent:")
7893 .append(std::to_string(paragraph_->GetLongestLineWithIndent())));
7894 }
7895
7896 void TextFieldPattern::DumpAdvanceInfo()
7897 {
7898 if (customKeyboard_ || customKeyboardBuilder_) {
7899 DumpLog::GetInstance().AddDesc(
7900 std::string("CustomKeyboard: true, Attached:").append(std::to_string(isCustomKeyboardAttached_)));
7901 }
7902 DumpLog::GetInstance().AddDesc(std::string("FontColor: ").append(GetTextColor()));
7903 #if defined(ENABLE_STANDARD_INPUT)
7904 auto miscTextConfig = GetMiscTextConfig();
7905 CHECK_NULL_VOID(miscTextConfig.has_value());
7906 MiscServices::TextConfig textConfig = miscTextConfig.value();
7907 DumpLog::GetInstance().AddDesc(
7908 std::string("RequestKeyboard calling window :").append(std::to_string(textConfig.windowId)));
7909 MiscServices::CursorInfo cursorInfo = miscTextConfig.value().cursorInfo;
7910 DumpLog::GetInstance().AddDesc(std::string("cursorInfo, left:")
7911 .append(std::to_string(cursorInfo.left))
7912 .append(", top:")
7913 .append(std::to_string(cursorInfo.top))
7914 .append(", width:")
7915 .append(std::to_string(cursorInfo.width))
7916 .append(", height:")
7917 .append(std::to_string(cursorInfo.height)));
7918 #endif
7919 DumpLog::GetInstance().AddDesc(std::string("textRect: ").append(contentRect_.ToString()));
7920 DumpLog::GetInstance().AddDesc(std::string("contentRect: ").append(contentRect_.ToString()));
7921 }
7922
7923 void TextFieldPattern::DumpPlaceHolderInfo()
7924 {
7925 DumpLog::GetInstance().AddDesc(std::string("placeholder: ").append(UtfUtils::Str16DebugToStr8(GetPlaceHolder())));
7926 DumpLog::GetInstance().AddDesc(std::string("placeholderColor: ").append(GetPlaceholderColor()));
7927 DumpLog::GetInstance().AddDesc(std::string("placeholderFont: ").append(GetPlaceholderFont()));
7928 }
7929
7930 void TextFieldPattern::DumpScaleInfo()
7931 {
7932 auto& dumpLog = DumpLog::GetInstance();
7933 dumpLog.AddDesc(std::string("-----DumpScaleInfo-----"));
7934 dumpLog.AddDesc(std::string("MinFontSize:").append(GetMinFontSize()));
7935 dumpLog.AddDesc(std::string("MaxFontSize:").append(GetMaxFontSize()));
7936 auto textLayoutProp = GetLayoutProperty<TextFieldLayoutProperty>();
7937 auto minFontScale = textLayoutProp->GetMinFontScale().value_or(0.0f);
7938 dumpLog.AddDesc(std::string("minFontScale: ").append(std::to_string(minFontScale)));
7939 auto maxfontScale = textLayoutProp->GetMaxFontScale().value_or(static_cast<float>(INT32_MAX));
7940 dumpLog.AddDesc(std::string("maxFontScale1: ").append(std::to_string(maxfontScale)));
7941 auto host = GetHost();
7942 CHECK_NULL_VOID(host);
7943 auto pipeline = host->GetContext();
7944 CHECK_NULL_VOID(pipeline);
7945 auto fontScale = pipeline->GetFontScale();
7946 auto fontWeightScale = pipeline->GetFontWeightScale();
7947 auto followSystem = pipeline->IsFollowSystem();
7948 float maxFontScale = pipeline->GetMaxAppFontScale();
7949 auto halfLeading = pipeline->GetHalfLeading();
7950 dumpLog.AddDesc(std::string("fontScale: ").append(std::to_string(fontScale)));
7951 dumpLog.AddDesc(std::string("fontWeightScale: ").append(std::to_string(fontWeightScale)));
7952 dumpLog.AddDesc(std::string("IsFollowSystem: ").append(std::to_string(followSystem)));
7953 dumpLog.AddDesc(std::string("maxFontScale: ").append(std::to_string(maxFontScale)));
7954 dumpLog.AddDesc(std::string("halfLeading: ").append(std::to_string(halfLeading)));
7955 }
7956
7957 std::string TextFieldPattern::GetDumpTextValue() const
7958 {
7959 if (IsInPasswordMode()) {
7960 auto len = GetTextValue().length();
7961 auto passwordLen = "passwordLen:" + std::to_string(len);
7962 return passwordLen;
7963 } else {
7964 return GetTextValue();
7965 }
7966 }
7967
7968 void TextFieldPattern::DumpViewDataPageNode(RefPtr<ViewDataWrap> viewDataWrap, bool needsRecordData)
7969 {
7970 CHECK_NULL_VOID(viewDataWrap);
7971 auto host = GetHost();
7972 CHECK_NULL_VOID(host);
7973 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
7974 CHECK_NULL_VOID(layoutProperty);
7975 auto autoFillTypeAndMetaData = GetAutoFillTypeAndMetaData();
7976 auto info = PageNodeInfoWrap::CreatePageNodeInfoWrap();
7977 CHECK_NULL_VOID(info);
7978 info->SetId(host->GetId());
7979 info->SetDepth(host->GetDepth());
7980 info->SetAutoFillType(autoFillTypeAndMetaData.autoFillType);
7981 info->SetMetadata(autoFillTypeAndMetaData.metadata);
7982 info->SetTag(host->GetTag());
7983 auto utf8TextValue = UtfUtils::Str16DebugToStr8(contentController_->GetTextUtf16Value());
7984 if (autoFillOtherAccount_) {
7985 viewDataWrap->SetOtherAccount(true);
7986 info->SetValue(utf8TextValue);
7987 autoFillOtherAccount_ = false;
7988 } else {
7989 info->SetValue(utf8TextValue);
7990 }
7991 if (needsRecordData) {
7992 lastAutoFillTextValue_ = utf8TextValue;
7993 }
7994 info->SetPlaceholder(UtfUtils::Str16DebugToStr8(GetPlaceHolder()));
7995 info->SetPasswordRules(layoutProperty->GetPasswordRulesValue(""));
7996 info->SetEnableAutoFill(layoutProperty->GetEnableAutoFillValue(true));
7997 auto offsetToWindow = host->GetTransformRelativeOffset();
7998 auto geometryNode = host->GetGeometryNode();
7999 CHECK_NULL_VOID(geometryNode);
8000 auto pageNodeRect = geometryNode->GetFrameRect();
8001 pageNodeRect.SetLeft(offsetToWindow.GetX());
8002 pageNodeRect.SetTop(offsetToWindow.GetY());
8003 info->SetPageNodeRect(pageNodeRect);
8004 info->SetIsFocus(HasFocus());
8005 viewDataWrap->AddPageNodeInfoWrap(info);
8006 }
8007
8008 void TextFieldPattern::NotifyFillRequestSuccess(RefPtr<ViewDataWrap> viewDataWrap,
8009 RefPtr<PageNodeInfoWrap> nodeWrap, AceAutoFillType autoFillType)
8010 {
8011 TAG_LOGI(AceLogTag::ACE_AUTO_FILL, "autoFillType:%{public}d", static_cast<int32_t>(autoFillType));
8012 SetFillRequestFinish(true);
8013 auto host = GetHost();
8014 CHECK_NULL_VOID(host);
8015 CHECK_NULL_VOID(viewDataWrap);
8016 CHECK_NULL_VOID(nodeWrap);
8017 auto isFocus = nodeWrap->GetIsFocus();
8018 if (isFocus && !HasFocus()) {
8019 TextFieldRequestFocus(RequestFocusReason::AUTO_FILL);
8020 DoProcessAutoFill();
8021 }
8022 auto type = GetAutoFillType();
8023 bool fromOtherAccount = viewDataWrap->GetOtherAccount();
8024 if (!(type == AceAutoFillType::ACE_NEW_PASSWORD && type == autoFillType) && !fromOtherAccount) {
8025 TAG_LOGI(AceLogTag::ACE_AUTO_FILL, "Set last auto fill text value.");
8026 lastAutoFillTextValue_ = nodeWrap->GetValue();
8027 }
8028
8029 if (!contentController_ || contentController_->GetTextValue() == nodeWrap->GetValue()) {
8030 return;
8031 }
8032 bool isWillChange = OnWillChangePreSetValue(UtfUtils::Str8DebugToStr16(nodeWrap->GetValue()));
8033 if (!isWillChange) {
8034 return;
8035 }
8036 contentController_->SetTextValue(UtfUtils::Str8DebugToStr16(nodeWrap->GetValue()));
8037 auto textLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
8038 selectController_->UpdateCaretIndex(textLength);
8039 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
8040 }
8041
8042 bool TextFieldPattern::ParseFillContentJsonValue(const std::unique_ptr<JsonValue>& jsonObject,
8043 std::unordered_map<std::string, std::variant<std::string, bool, int32_t>>& map)
8044 {
8045 if (!jsonObject->IsValid() || jsonObject->IsArray() || !jsonObject->IsObject()) {
8046 TAG_LOGW(AceLogTag::ACE_AUTO_FILL, "fillContent format is not right");
8047 return false;
8048 }
8049 auto child = jsonObject->GetChild();
8050
8051 while (child && child->IsValid()) {
8052 if (!child->IsObject() && child->IsString()) {
8053 std::string strKey = child->GetKey();
8054 std::string strVal = child->GetString();
8055 if (strKey.empty()) {
8056 continue;
8057 }
8058 if (map.size() < MAX_FILL_CONTENT_SIZE) {
8059 map.insert(std::pair<std::string, std::variant<std::string, bool, int32_t> >(strKey, strVal));
8060 } else {
8061 TAG_LOGW(AceLogTag::ACE_AUTO_FILL, "fillContent is more than 5");
8062 break;
8063 }
8064 }
8065 child = child->GetNext();
8066 }
8067 return true;
8068 }
8069
8070 void TextFieldPattern::NotifyFillRequestFailed(int32_t errCode, const std::string& fillContent, bool isPopup)
8071 {
8072 TAG_LOGI(AceLogTag::ACE_AUTO_FILL, "NotifyFillRequestFailed errCode:%{public}d", errCode);
8073 SetFillRequestFinish(true);
8074
8075 #if defined(ENABLE_STANDARD_INPUT)
8076 TAG_LOGI(AceLogTag::ACE_AUTO_FILL, "fillContent size is : %{public}zu", fillContent.size());
8077 if (errCode == AUTO_FILL_CANCEL) {
8078 if (!fillContent.empty() && IsTriggerAutoFillPassword()) {
8079 auto jsonObject = JsonUtil::ParseJsonString(fillContent);
8080 CHECK_NULL_VOID(jsonObject);
8081 fillContentMap_.clear();
8082 ParseFillContentJsonValue(jsonObject, fillContentMap_);
8083 }
8084 }
8085 if (!isPopup || (isPopup && errCode == AUTO_FILL_CANCEL)) {
8086 if (RequestKeyboardNotByFocusSwitch(RequestKeyboardReason::AUTO_FILL_REQUEST_FAIL)) {
8087 NotifyOnEditChanged(true);
8088 }
8089 }
8090 #endif
8091 }
8092
8093 bool TextFieldPattern::CheckAutoSave()
8094 {
8095 auto host = GetHost();
8096 CHECK_NULL_RETURN(host, false);
8097 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
8098 CHECK_NULL_RETURN(layoutProperty, false);
8099 if (!layoutProperty->GetEnableAutoFillValue(true)) {
8100 return false;
8101 }
8102 if (!contentController_ || contentController_->GetTextUtf16Value().empty()) {
8103 return false;
8104 }
8105 auto autoFillType = GetAutoFillType();
8106 if (IsAutoFillUserName(autoFillType)) {
8107 if (!lastAutoFillTextValue_.empty() &&
8108 contentController_->GetTextValue() != lastAutoFillTextValue_) {
8109 return true;
8110 }
8111 }
8112 if (AceAutoFillType::ACE_UNSPECIFIED < autoFillType && autoFillType <= AceAutoFillType::END &&
8113 !IsAutoFillUserName(autoFillType)) {
8114 if (contentController_->GetTextValue() != lastAutoFillTextValue_) {
8115 return true;
8116 }
8117 }
8118 return false;
8119 }
8120
8121 bool TextFieldPattern::IsTouchAtLeftOffset(float currentOffsetX)
8122 {
8123 return LessNotEqual(currentOffsetX, contentRect_.GetX() + contentRect_.Width() * 0.5);
8124 }
8125
8126 OffsetF TextFieldPattern::GetDragUpperLeftCoordinates()
8127 {
8128 if (!IsSelected()) {
8129 return { 0.0f, 0.0f };
8130 }
8131 auto selectRects = selectController_->GetSelectedRects();
8132 auto startY = selectRects.front().Top();
8133 auto startX = selectRects.front().Left();
8134 auto endY = selectRects.back().Top();
8135 OffsetF startOffset;
8136 if (NearEqual(startY, endY)) {
8137 startOffset = { (IsTextArea() ? contentRect_.GetX() : textRect_.GetX()) + startX,
8138 startY + (IsTextArea() ? textRect_.GetY() : contentRect_.GetY()) };
8139 } else {
8140 startOffset = { contentRect_.GetX(), startY + (IsTextArea() ? textRect_.GetY() : contentRect_.GetY()) };
8141 }
8142
8143 if (startOffset.GetY() < contentRect_.GetY()) {
8144 startOffset.SetY(contentRect_.GetY());
8145 }
8146 if (startOffset.GetX() < contentRect_.GetX()) {
8147 startOffset.SetX(contentRect_.GetX());
8148 }
8149 return startOffset + GetPaintRectGlobalOffset();
8150 }
8151
8152 void TextFieldPattern::OnColorConfigurationUpdate()
8153 {
8154 ScrollablePattern::OnColorConfigurationUpdate();
8155 auto host = GetHost();
8156 CHECK_NULL_VOID(host);
8157 auto theme = GetTheme();
8158 CHECK_NULL_VOID(theme);
8159 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
8160 CHECK_NULL_VOID(layoutProperty);
8161 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
8162 CHECK_NULL_VOID(paintProperty);
8163 if (!paintProperty->HasTextColorFlagByUser()) {
8164 layoutProperty->UpdateTextColor(theme->GetTextColor());
8165 }
8166 if (magnifierController_) {
8167 magnifierController_->SetColorModeChange(true);
8168 }
8169 auto context = host->GetContext();
8170 CHECK_NULL_VOID(context);
8171 auto colorMode = context->GetColorMode();
8172 SetOriginCursorColor(colorMode == ColorMode::DARK ? Color(0x4DFFFFFF) : Color(0x4D000000));
8173 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
8174 }
8175
8176 bool TextFieldPattern::IsReachedBoundary(float offset)
8177 {
8178 if (IsTextArea()) {
8179 return (NearEqual(textRect_.GetY(), contentRect_.GetY()) && GreatNotEqual(offset, 0.0f)) ||
8180 (NearEqual(textRect_.GetY() + textRect_.Height(), contentRect_.GetY() + contentRect_.Height()) &&
8181 LessNotEqual(offset, 0.0f));
8182 }
8183
8184 return (NearEqual(textRect_.GetX(), contentRect_.GetX()) && GreatNotEqual(offset, 0.0f)) ||
8185 (NearEqual(textRect_.GetX() + textRect_.Width(), contentRect_.GetX() + contentRect_.Width()) &&
8186 LessNotEqual(offset, 0.0f));
8187 }
8188
8189 OffsetF TextFieldPattern::GetTextPaintOffset() const
8190 {
8191 if (selectOverlay_->HasRenderTransform()) {
8192 return selectOverlay_->GetPaintRectOffsetWithTransform();
8193 }
8194 return GetPaintRectGlobalOffset();
8195 }
8196
8197 OffsetF TextFieldPattern::GetPaintRectGlobalOffset() const
8198 {
8199 auto host = GetHost();
8200 CHECK_NULL_RETURN(host, OffsetF(0.0f, 0.0f));
8201 auto pipeline = host->GetContextRefPtr();
8202 CHECK_NULL_RETURN(pipeline, OffsetF(0.0f, 0.0f));
8203 auto rootOffset = pipeline->GetRootRect().GetOffset();
8204 OffsetF textPaintOffset;
8205 textPaintOffset = host->GetPaintRectOffset(false, true);
8206 return textPaintOffset - rootOffset;
8207 }
8208
8209 void TextFieldPattern::UpdateSelectController()
8210 {
8211 selectController_->UpdateContentRect(contentRect_);
8212 selectController_->UpdateParagraph(paragraph_);
8213 }
8214
8215 bool TextFieldPattern::RepeatClickCaret(const Offset& offset, int32_t lastCaretIndex)
8216 {
8217 auto touchDownIndex = selectController_->ConvertTouchOffsetToPosition(offset);
8218 return lastCaretIndex == touchDownIndex && HasFocus();
8219 }
8220
8221 bool TextFieldPattern::RepeatClickCaret(const Offset& offset, const RectF& lastCaretRect)
8222 {
8223 auto caretRect = lastCaretRect;
8224 caretRect.SetLeft(caretRect.GetX() - caretRect.Height() / 2);
8225 caretRect.SetWidth(caretRect.Height());
8226 return caretRect.IsInRegion(PointF(offset.GetX(), offset.GetY()));
8227 }
8228
8229 void TextFieldPattern::OnAttachToFrameNode()
8230 {
8231 auto frameNode = GetHost();
8232 CHECK_NULL_VOID(frameNode);
8233 StylusDetectorMgr::GetInstance()->AddTextFieldFrameNode(frameNode, WeakClaim(this));
8234
8235 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
8236 CHECK_NULL_VOID(layoutProperty);
8237 layoutProperty->UpdateCopyOptions(CopyOptions::Local);
8238 auto pipeline = frameNode->GetContext();
8239 CHECK_NULL_VOID(pipeline);
8240 auto fontManager = pipeline->GetFontManager();
8241 if (fontManager) {
8242 auto host = GetHost();
8243 fontManager->AddFontNodeNG(host);
8244 }
8245 auto onTextSelectorChange = [weak = WeakClaim(this)]() {
8246 auto pattern = weak.Upgrade();
8247 CHECK_NULL_VOID(pattern);
8248 auto frameNode = pattern->GetHost();
8249 CHECK_NULL_VOID(frameNode);
8250 frameNode->OnAccessibilityEvent(AccessibilityEventType::TEXT_SELECTION_UPDATE);
8251 };
8252 selectController_->SetOnAccessibility(std::move(onTextSelectorChange));
8253 }
8254
8255 bool TextFieldPattern::NeedPaintSelect()
8256 {
8257 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
8258 CHECK_NULL_RETURN(paintProperty, false);
8259 auto firstHandle = paintProperty->GetFirstHandleInfo();
8260 auto secondHandle = paintProperty->GetSecondHandleInfo();
8261 auto caretInfo = selectController_->GetCaretInfo();
8262 if (!IsSelected()) {
8263 if (!firstHandle.has_value() || !secondHandle.has_value()) {
8264 paintProperty->UpdateFirstHandleInfo(caretInfo);
8265 paintProperty->UpdateSecondHandleInfo(caretInfo);
8266 return false;
8267 }
8268
8269 if (firstHandle->index != secondHandle->index || firstHandle->index != caretInfo.index) {
8270 paintProperty->UpdateFirstHandleInfo(caretInfo);
8271 paintProperty->UpdateSecondHandleInfo(caretInfo);
8272 return true;
8273 }
8274 return false;
8275 }
8276 auto needPaint = firstHandle != selectController_->GetFirstHandleInfo() ||
8277 secondHandle != selectController_->GetSecondHandleInfo();
8278 paintProperty->UpdateFirstHandleInfo(selectController_->GetFirstHandleInfo());
8279 paintProperty->UpdateSecondHandleInfo(selectController_->GetSecondHandleInfo());
8280 return needPaint;
8281 }
8282
8283 RefPtr<FocusHub> TextFieldPattern::GetFocusHub() const
8284 {
8285 auto host = GetHost();
8286 CHECK_NULL_RETURN(host, nullptr);
8287 auto focusHub = host->GetOrCreateFocusHub();
8288 return focusHub;
8289 }
8290
8291 void TextFieldPattern::OnObscuredChanged(bool isObscured)
8292 {
8293 ResetObscureTickCountDown();
8294 obscuredChange_ = textObscured_ != isObscured;
8295 textObscured_ = isObscured;
8296 CloseSelectOverlay(false);
8297 StartTwinkling();
8298 if (obscuredChange_) {
8299 selectController_->UpdateCaretIndex(static_cast<int32_t>(contentController_->GetTextUtf16Value().length()));
8300 }
8301 auto host = GetHost();
8302 CHECK_NULL_VOID(host);
8303 if (obscuredChange_) {
8304 auto eventHub = host->GetEventHub<TextFieldEventHub>();
8305 CHECK_NULL_VOID(eventHub);
8306 eventHub->FireOnSecurityStateChanged(!isObscured);
8307 }
8308 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
8309 }
8310
8311 void TextFieldPattern::CreateHandles()
8312 {
8313 if (IsDragging() || !HasFocus()) {
8314 return;
8315 }
8316 auto host = GetHost();
8317 CHECK_NULL_VOID(host);
8318 showSelect_ = true;
8319 if (selectOverlay_->IsUseTouchAtLast()) {
8320 SetIsSingleHandle(!IsSelected());
8321 ProcessOverlay({ .menuIsShow = false });
8322 }
8323 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
8324 }
8325
8326 void TextFieldPattern::NotifyOnEditChanged(bool isChanged)
8327 {
8328 auto host = GetHost();
8329 CHECK_NULL_VOID(host);
8330 auto eventHub = host->GetEventHub<TextFieldEventHub>();
8331 CHECK_NULL_VOID(eventHub);
8332 if (isChanged != isEdit_) {
8333 isEdit_ = isChanged;
8334 eventHub->FireOnEditChanged(isChanged);
8335 }
8336 }
8337
8338 size_t TextFieldPattern::GetLineCount() const
8339 {
8340 return paragraph_ ? paragraph_->GetLineCount() : 0;
8341 }
8342
8343 void TextFieldPattern::UpdateHandlesOffsetOnScroll(float offset)
8344 {
8345 if (SelectOverlayIsOn()) {
8346 selectController_->UpdateSecondHandleOffset();
8347 if (!selectOverlay_->IsSingleHandle()) {
8348 selectController_->UpdateFirstHandleOffset();
8349 selectController_->UpdateCaretOffset(TextAffinity::DOWNSTREAM, false);
8350 selectOverlay_->UpdateAllHandlesOffset();
8351 } else {
8352 selectController_->UpdateCaretOffset(IsTextArea() ? OffsetF(0.0f, offset) : OffsetF(offset, 0.0f));
8353 selectOverlay_->UpdateSecondHandleOffset();
8354 }
8355 } else {
8356 selectController_->UpdateCaretOffset(IsTextArea() ? OffsetF(0.0f, offset) : OffsetF(offset, 0.0f));
8357 }
8358 }
8359
8360 void TextFieldPattern::CloseHandleAndSelect()
8361 {
8362 CloseSelectOverlay(true);
8363 showSelect_ = false;
8364 }
8365
8366 bool TextFieldPattern::IsShowUnit() const
8367 {
8368 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
8369 CHECK_NULL_RETURN(layoutProperty, false);
8370 auto typeValue = layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED);
8371 return layoutProperty->GetShowUnderlineValue(false) &&
8372 (typeValue == TextInputType::UNSPECIFIED || typeValue == TextInputType::TEXT);
8373 }
8374
8375 bool TextFieldPattern::IsShowPasswordIcon() const
8376 {
8377 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
8378 CHECK_NULL_RETURN(layoutProperty, false);
8379 auto textfieldTheme = GetTheme();
8380 CHECK_NULL_RETURN(textfieldTheme, false);
8381 bool isShowPasswordIcon = textfieldTheme->IsShowPasswordIcon();
8382 return layoutProperty->GetShowPasswordIconValue(isShowPasswordIcon) && IsInPasswordMode();
8383 }
8384
8385 std::optional<bool> TextFieldPattern::IsShowPasswordText() const
8386 {
8387 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
8388 CHECK_NULL_RETURN(layoutProperty, false);
8389 return layoutProperty->GetShowPasswordText();
8390 }
8391
8392 bool TextFieldPattern::IsShowCancelButtonMode() const
8393 {
8394 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
8395 CHECK_NULL_RETURN(layoutProperty, false);
8396 return !IsNormalInlineState() && !IsTextArea() && layoutProperty->GetIsShowCancelButton().value_or(false);
8397 }
8398
8399 void TextFieldPattern::CheckPasswordAreaState()
8400 {
8401 auto showPasswordState = IsShowPasswordText();
8402 if (!showPasswordState.has_value()) {
8403 return;
8404 }
8405 auto passwordArea = AceType::DynamicCast<PasswordResponseArea>(responseArea_);
8406 CHECK_NULL_VOID(passwordArea);
8407 if (!showPasswordState_.has_value() || showPasswordState_.value() != showPasswordState.value()) {
8408 passwordArea->SetObscured(!showPasswordState.value());
8409 showPasswordState_ = showPasswordState.value();
8410 }
8411 }
8412
8413 void TextFieldPattern::AfterLayoutProcessCleanResponse(
8414 const RefPtr<CleanNodeResponseArea>& cleanNodeResponseArea)
8415 {
8416 CHECK_NULL_VOID(cleanNodeResponseArea);
8417 auto host = GetHost();
8418 CHECK_NULL_VOID(host);
8419 auto pipeline = host->GetContext();
8420 CHECK_NULL_VOID(pipeline);
8421 pipeline->AddAfterLayoutTask([weak = WeakClaim(Referenced::RawPtr(cleanNodeResponseArea))]() {
8422 auto cleanNodeResponseArea = weak.Upgrade();
8423 CHECK_NULL_VOID(cleanNodeResponseArea);
8424 cleanNodeResponseArea->UpdateCleanNode(cleanNodeResponseArea->IsShow());
8425 });
8426 }
8427
8428 void TextFieldPattern::ProcessCancelButton()
8429 {
8430 if (IsShowCancelButtonMode()) {
8431 auto cleanNodeResponseArea = AceType::DynamicCast<CleanNodeResponseArea>(cleanNodeResponseArea_);
8432 if (cleanNodeResponseArea) {
8433 cleanNodeResponseArea->Refresh();
8434 if (cleanNodeResponseArea->IsShow()) {
8435 AfterLayoutProcessCleanResponse(cleanNodeResponseArea);
8436 } else {
8437 UpdateCancelNode();
8438 }
8439 } else {
8440 cleanNodeResponseArea_ = AceType::MakeRefPtr<CleanNodeResponseArea>(WeakClaim(this));
8441 cleanNodeResponseArea = AceType::DynamicCast<CleanNodeResponseArea>(cleanNodeResponseArea_);
8442 cleanNodeResponseArea->InitResponseArea();
8443 UpdateCancelNode();
8444 AfterLayoutProcessCleanResponse(cleanNodeResponseArea);
8445 }
8446 } else {
8447 if (cleanNodeResponseArea_) {
8448 cleanNodeResponseArea_->ClearArea();
8449 cleanNodeResponseArea_.Reset();
8450 }
8451 }
8452 }
8453
8454 void TextFieldPattern::ProcessResponseArea()
8455 {
8456 ProcessCancelButton();
8457 if (IsInPasswordMode()) {
8458 auto passwordArea = AceType::DynamicCast<PasswordResponseArea>(responseArea_);
8459 if (passwordArea) {
8460 if (IsShowPasswordIcon()) {
8461 passwordArea->Refresh();
8462 } else {
8463 passwordArea->ClearArea();
8464 }
8465 CheckPasswordAreaState();
8466 return;
8467 }
8468 // responseArea_ may not be a password area.
8469 responseArea_ = AceType::MakeRefPtr<PasswordResponseArea>(WeakClaim(this), GetTextObscured());
8470 if (IsShowPasswordIcon()) {
8471 responseArea_->InitResponseArea();
8472 } else {
8473 responseArea_->ClearArea();
8474 }
8475 CheckPasswordAreaState();
8476 return;
8477 }
8478
8479 if (IsUnderlineMode()) {
8480 responseArea_ = AceType::MakeRefPtr<UnitResponseArea>(WeakClaim(this), unitNode_);
8481 responseArea_->InitResponseArea();
8482 auto host = GetHost();
8483 CHECK_NULL_VOID(host);
8484 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
8485 return;
8486 }
8487
8488 if (responseArea_) {
8489 responseArea_->ClearArea();
8490 }
8491 }
8492
8493 void TextFieldPattern::AdjustTextRectByCleanNode(RectF& textRect)
8494 {
8495 auto cleanNodeResponseArea = DynamicCast<CleanNodeResponseArea>(cleanNodeResponseArea_);
8496 CHECK_NULL_VOID(cleanNodeResponseArea);
8497 auto host = GetHost();
8498 CHECK_NULL_VOID(host);
8499 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
8500 CHECK_NULL_VOID(layoutProperty);
8501 auto cleanNodeStyle = layoutProperty->GetCleanNodeStyle().value_or(CleanNodeStyle::INPUT);
8502 auto isRTL = layoutProperty->GetNonAutoLayoutDirection() == TextDirection::RTL;
8503 if (isRTL && (cleanNodeStyle == CleanNodeStyle::CONSTANT ||
8504 (cleanNodeStyle == CleanNodeStyle::INPUT && !contentController_->IsEmpty()))) {
8505 auto textFieldTheme = GetTheme();
8506 CHECK_NULL_VOID(textFieldTheme);
8507 auto themePadding = textFieldTheme->GetPadding();
8508 auto rightOffset = static_cast<float>(themePadding.Left().ConvertToPx());
8509 textRect.SetLeft(textRect.GetX() + cleanNodeResponseArea->GetIconSize() + rightOffset);
8510 }
8511 }
8512
8513 void TextFieldPattern::UpdateCancelNode()
8514 {
8515 auto cleanNodeResponseArea = DynamicCast<CleanNodeResponseArea>(cleanNodeResponseArea_);
8516 CHECK_NULL_VOID(cleanNodeResponseArea);
8517 auto host = GetHost();
8518 CHECK_NULL_VOID(host);
8519 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
8520 CHECK_NULL_VOID(layoutProperty);
8521 auto cleanNodeStyle = layoutProperty->GetCleanNodeStyle().value_or(CleanNodeStyle::INPUT);
8522 if (cleanNodeStyle == CleanNodeStyle::CONSTANT ||
8523 (cleanNodeStyle == CleanNodeStyle::INPUT && !contentController_->IsEmpty())) {
8524 if (!cleanNodeResponseArea->IsShow() || cleanNodeResponseArea->CheckUpdateCleanNode()) {
8525 cleanNodeResponseArea->UpdateCleanNode(true);
8526 }
8527 } else if (cleanNodeStyle == CleanNodeStyle::INVISIBLE ||
8528 (cleanNodeStyle == CleanNodeStyle::INPUT && contentController_->IsEmpty())) {
8529 if (cleanNodeResponseArea->IsShow()) {
8530 cleanNodeResponseArea->UpdateCleanNode(false);
8531 }
8532 }
8533 }
8534
8535 bool TextFieldPattern::HasInputOperation()
8536 {
8537 return !deleteBackwardOperations_.empty() || !deleteForwardOperations_.empty() || !insertCommands_.empty();
8538 }
8539
8540 void TextFieldPattern::FocusForwardStopTwinkling()
8541 {
8542 auto host = GetHost();
8543 CHECK_NULL_VOID(host);
8544 UpdateSelection(selectController_->GetCaretIndex());
8545 StopTwinkling();
8546 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
8547 }
8548
8549 bool TextFieldPattern::UpdateFocusForward()
8550 {
8551 if (focusIndex_ == FocuseIndex::TEXT && HasFocus()) {
8552 FocusForwardStopTwinkling();
8553 if (!CancelNodeIsShow()) {
8554 if (responseArea_ == nullptr || (!IsShowUnit() && !IsShowPasswordIcon())) {
8555 return false;
8556 }
8557 focusIndex_ = FocuseIndex::UNIT;
8558 PaintResponseAreaRect();
8559 return true;
8560 }
8561 focusIndex_ = FocuseIndex::CANCEL;
8562 PaintCancelRect();
8563 return true;
8564 }
8565 if (focusIndex_ == FocuseIndex::CANCEL && HasFocus()) {
8566 FocusForwardStopTwinkling();
8567 if (responseArea_ == nullptr || (!IsShowUnit() && !IsShowPasswordIcon())) {
8568 return false;
8569 }
8570 focusIndex_ = FocuseIndex::UNIT;
8571 PaintResponseAreaRect();
8572 return true;
8573 }
8574 return false;
8575 }
8576
8577 bool TextFieldPattern::UpdateFocusBackward()
8578 {
8579 if (focusIndex_ == FocuseIndex::CANCEL && HasFocus()) {
8580 focusIndex_ = FocuseIndex::TEXT;
8581 PaintTextRect();
8582 StartTwinkling();
8583 return true;
8584 } else if (focusIndex_ == FocuseIndex::UNIT && HasFocus()) {
8585 if (!CancelNodeIsShow()) {
8586 focusIndex_ = FocuseIndex::TEXT;
8587 PaintTextRect();
8588 StartTwinkling();
8589 return true;
8590 }
8591 focusIndex_ = FocuseIndex::CANCEL;
8592 PaintCancelRect();
8593 return true;
8594 }
8595 return false;
8596 }
8597
8598 bool TextFieldPattern::HandleSpaceEvent()
8599 {
8600 if (focusIndex_ == FocuseIndex::CANCEL) {
8601 CleanNodeResponseKeyEvent();
8602 return true;
8603 } else if (focusIndex_ == FocuseIndex::UNIT) {
8604 if (IsShowPasswordIcon()) {
8605 PasswordResponseKeyEvent();
8606 }
8607 if (IsShowUnit()) {
8608 UnitResponseKeyEvent();
8609 }
8610 return true;
8611 }
8612 return false;
8613 }
8614
8615 void TextFieldPattern::PaintTextRect()
8616 {
8617 RoundRect focusRect;
8618 auto host = GetHost();
8619 CHECK_NULL_VOID(host);
8620 auto focusHub = host->GetFocusHub();
8621 CHECK_NULL_VOID(focusHub);
8622 focusHub->PaintInnerFocusState(focusRect);
8623 }
8624
8625 void TextFieldPattern::GetIconPaintRect(const RefPtr<TextInputResponseArea>& responseArea, RoundRect& paintRect)
8626 {
8627 auto stackNode = responseArea->GetFrameNode();
8628 CHECK_NULL_VOID(stackNode);
8629 auto stackRect = stackNode->GetGeometryNode()->GetFrameRect();
8630 auto imageNode = stackNode->GetFirstChild();
8631 CHECK_NULL_VOID(imageNode);
8632 auto imageFrameNode = AceType::DynamicCast<FrameNode>(imageNode);
8633 CHECK_NULL_VOID(imageFrameNode);
8634 auto imageRect = imageFrameNode->GetGeometryNode()->GetFrameRect();
8635 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
8636 CHECK_NULL_VOID(layoutProperty);
8637 auto isRTL = layoutProperty->GetNonAutoLayoutDirection() == TextDirection::RTL;
8638 RectF rect;
8639 if (isRTL) {
8640 rect = RectF(stackRect.GetX() + stackRect.Width() - imageRect.Width(),
8641 stackRect.GetY(), imageRect.Width(), imageRect.Height());
8642 } else {
8643 rect = RectF(stackRect.GetX(), stackRect.GetY(), imageRect.Width(), imageRect.Height());
8644 }
8645 paintRect.SetRect(rect);
8646 }
8647
8648 void TextFieldPattern::GetInnerFocusPaintRect(RoundRect& paintRect)
8649 {
8650 if (focusIndex_ == FocuseIndex::CANCEL) {
8651 CHECK_NULL_VOID(cleanNodeResponseArea_);
8652 GetIconPaintRect(cleanNodeResponseArea_, paintRect);
8653 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
8654 cleanNodeResponseArea_->CreateIconRect(paintRect, true);
8655 float cornerRadius = paintRect.GetRect().Width() / 2;
8656 paintRect.SetCornerRadius(cornerRadius);
8657 }
8658 } else if (focusIndex_ == FocuseIndex::UNIT) {
8659 if (IsShowPasswordIcon()) {
8660 CHECK_NULL_VOID(responseArea_);
8661 GetIconPaintRect(responseArea_, paintRect);
8662 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
8663 responseArea_->CreateIconRect(paintRect, true);
8664 }
8665 float cornerRadius = paintRect.GetRect().Width() / 2;
8666 paintRect.SetCornerRadius(cornerRadius);
8667 }
8668 if (IsShowUnit()) {
8669 CHECK_NULL_VOID(responseArea_);
8670 auto unitResponseArea = AceType::DynamicCast<UnitResponseArea>(responseArea_);
8671 CHECK_NULL_VOID(unitResponseArea);
8672 auto unitNode = unitResponseArea->GetFrameNode();
8673 CHECK_NULL_VOID(unitNode);
8674 auto unitRect = unitNode->GetGeometryNode()->GetFrameRect();
8675 paintRect.SetRect(unitRect);
8676 }
8677 } else {
8678 GetTextInputFocusPaintRect(paintRect);
8679 }
8680 }
8681
8682 void TextFieldPattern::GetTextInputFocusPaintRect(RoundRect& paintRect)
8683 {
8684 auto textfieldTheme = GetTheme();
8685 CHECK_NULL_VOID(textfieldTheme);
8686 auto isNeedFocusBox = textfieldTheme->NeedFocusBox();
8687 if (!isNeedFocusBox) {
8688 return;
8689 }
8690 auto host = GetHost();
8691 CHECK_NULL_VOID(host);
8692 auto geometryNode = host->GetGeometryNode();
8693 CHECK_NULL_VOID(geometryNode);
8694 auto textInputSize = geometryNode->GetFrameSize();
8695 auto focusPaintPadding = textfieldTheme->GetFocusPadding().ConvertToPx();
8696 float width = textInputSize.Width() + 2 * focusPaintPadding;
8697 float height = textInputSize.Height() + 2 * focusPaintPadding;
8698 paintRect.SetRect({ -focusPaintPadding, -focusPaintPadding, width, height });
8699 auto renderContext = host->GetRenderContext();
8700 CHECK_NULL_VOID(renderContext);
8701 auto radius = renderContext->GetBorderRadius().value_or(BorderRadiusProperty());
8702 paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_LEFT_POS,
8703 static_cast<float>(radius.radiusTopLeft->ConvertToPx() + focusPaintPadding),
8704 static_cast<float>(radius.radiusTopLeft->ConvertToPx() + focusPaintPadding));
8705 paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_RIGHT_POS,
8706 static_cast<float>(radius.radiusTopRight->ConvertToPx() + focusPaintPadding),
8707 static_cast<float>(radius.radiusTopRight->ConvertToPx() + focusPaintPadding));
8708 paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_LEFT_POS,
8709 static_cast<float>(radius.radiusBottomLeft->ConvertToPx() + focusPaintPadding),
8710 static_cast<float>(radius.radiusBottomLeft->ConvertToPx() + focusPaintPadding));
8711 paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_RIGHT_POS,
8712 static_cast<float>(radius.radiusBottomRight->ConvertToPx() + focusPaintPadding),
8713 static_cast<float>(radius.radiusBottomRight->ConvertToPx() + focusPaintPadding));
8714 }
8715
8716 void TextFieldPattern::PaintCancelRect()
8717 {
8718 RoundRect focusRect;
8719 GetInnerFocusPaintRect(focusRect);
8720 auto host = GetHost();
8721 CHECK_NULL_VOID(host);
8722 auto focusHub = host->GetFocusHub();
8723 CHECK_NULL_VOID(focusHub);
8724 focusHub->PaintInnerFocusState(focusRect);
8725 }
8726
8727 void TextFieldPattern::PaintResponseAreaRect()
8728 {
8729 if (IsShowPasswordIcon()) {
8730 PaintPasswordRect();
8731 }
8732 if (IsShowUnit()) {
8733 PaintUnitRect();
8734 }
8735 }
8736
8737 void TextFieldPattern::PaintPasswordRect()
8738 {
8739 RoundRect focusRect;
8740 GetInnerFocusPaintRect(focusRect);
8741 auto host = GetHost();
8742 CHECK_NULL_VOID(host);
8743 auto focusHub = host->GetFocusHub();
8744 CHECK_NULL_VOID(focusHub);
8745 focusHub->PaintInnerFocusState(focusRect);
8746 }
8747
8748 void TextFieldPattern::PaintUnitRect()
8749 {
8750 RoundRect focusRect;
8751 GetInnerFocusPaintRect(focusRect);
8752 auto host = GetHost();
8753 CHECK_NULL_VOID(host);
8754 auto focusHub = host->GetFocusHub();
8755 CHECK_NULL_VOID(focusHub);
8756 focusHub->PaintInnerFocusState(focusRect);
8757 }
8758
8759 void TextFieldPattern::CleanNodeResponseKeyEvent()
8760 {
8761 CHECK_NULL_VOID(!IsDragging());
8762 auto host = GetHost();
8763 CHECK_NULL_VOID(host);
8764 ClearTextContent();
8765 CloseSelectOverlay();
8766 SetFloatingCursorVisible(false);
8767 StartTwinkling();
8768 UpdateCaretInfoToController();
8769 if (!HasFocus()) {
8770 auto focusHub = host->GetOrCreateFocusHub();
8771 TextFieldRequestFocus(RequestFocusReason::CLEAN_NODE);
8772 }
8773 host->MarkModifyDone();
8774 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
8775
8776 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
8777 CHECK_NULL_VOID(layoutProperty);
8778 auto cleanNodeStyle = layoutProperty->GetCleanNodeStyle().value_or(CleanNodeStyle::INPUT);
8779 if (cleanNodeStyle == CleanNodeStyle::INPUT) {
8780 focusIndex_ = FocuseIndex::TEXT;
8781 }
8782 }
8783
8784 void TextFieldPattern::RegisterWindowSizeCallback()
8785 {
8786 if (isOritationListenerRegisted_) {
8787 return;
8788 }
8789 isOritationListenerRegisted_ = true;
8790 auto host = GetHost();
8791 CHECK_NULL_VOID(host);
8792 auto pipeline = host->GetContext();
8793 CHECK_NULL_VOID(pipeline);
8794 pipeline->AddWindowSizeChangeCallback(host->GetId());
8795 }
8796
8797 void TextFieldPattern::OnWindowSizeChanged(int32_t width, int32_t height, WindowSizeChangeReason type)
8798 {
8799 if (selectOverlay_) {
8800 selectOverlay_->UpdateMenuOnWindowSizeChanged(type);
8801 }
8802 if (type != WindowSizeChangeReason::ROTATION) {
8803 return;
8804 }
8805 if (SelectOverlayIsOn()) {
8806 selectController_->CalculateHandleOffset();
8807 selectOverlay_->ProcessOverlayOnAreaChanged({ .menuIsShow = false});
8808 }
8809 auto host = GetHost();
8810 CHECK_NULL_VOID(host);
8811 auto context = host->GetContextRefPtr();
8812 CHECK_NULL_VOID(context);
8813 auto taskExecutor = context->GetTaskExecutor();
8814 CHECK_NULL_VOID(taskExecutor);
8815 auto textFieldManager = DynamicCast<TextFieldManagerNG>(context->GetTextFieldManager());
8816 CHECK_NULL_VOID(textFieldManager);
8817 textFieldManager->ResetOptionalClickPosition();
8818 lastCaretPos_ = std::nullopt;
8819 taskExecutor->PostTask(
8820 [weak = WeakClaim(this), manager = WeakPtr<TextFieldManagerNG>(textFieldManager)] {
8821 auto textField = weak.Upgrade();
8822 CHECK_NULL_VOID(textField);
8823 auto host = textField->GetHost();
8824 CHECK_NULL_VOID(host);
8825 auto nodeId = host->GetId();
8826 textField->parentGlobalOffset_ = textField->GetPaintRectGlobalOffset();
8827 textField->UpdateTextFieldManager(Offset(textField->parentGlobalOffset_.GetX(),
8828 textField->parentGlobalOffset_.GetY()), textField->frameRect_.Height());
8829 if (textField->HasFocus()) {
8830 textField->UpdateCaretInfoToController(true);
8831 TAG_LOGI(ACE_TEXT_FIELD, "%{public}d OnWindowSizeChanged change parentGlobalOffset to: %{public}s",
8832 nodeId, textField->parentGlobalOffset_.ToString().c_str());
8833 auto textFieldManager = manager.Upgrade();
8834 CHECK_NULL_VOID(textFieldManager);
8835 auto container = Container::Current();
8836 CHECK_NULL_VOID(container);
8837 auto displayInfo = container->GetDisplayInfo();
8838 if (displayInfo) {
8839 auto dmRotation = static_cast<int32_t>(displayInfo->GetRotation());
8840 textFieldManager->SetFocusFieldOrientation(dmRotation);
8841 textFieldManager->SetFocusFieldAlreadyTriggerWsCallback(true);
8842 }
8843 }
8844 },
8845 TaskExecutor::TaskType::UI, "ArkUITextFieldOnWindowSizeChangedRotation");
8846 }
8847
8848 void TextFieldPattern::PasswordResponseKeyEvent()
8849 {
8850 auto passwordArea = AceType::DynamicCast<PasswordResponseArea>(responseArea_);
8851 CHECK_NULL_VOID(passwordArea);
8852 passwordArea->OnPasswordIconClicked();
8853 }
8854
8855 void TextFieldPattern::UnitResponseKeyEvent()
8856 {
8857 #ifndef ARKUI_WEARABLE
8858 auto unitArea = AceType::DynamicCast<UnitResponseArea>(responseArea_);
8859 CHECK_NULL_VOID(unitArea);
8860 auto frameNode = unitArea->GetFrameNode();
8861 CHECK_NULL_VOID(frameNode);
8862 if (frameNode->GetTag() == V2::SELECT_ETS_TAG) {
8863 auto selectPattern = frameNode->GetPattern<SelectPattern>();
8864 CHECK_NULL_VOID(selectPattern);
8865 selectPattern->ShowSelectMenu();
8866 }
8867 #endif
8868 }
8869
8870 void TextFieldPattern::ScrollToSafeArea() const
8871 {
8872 auto host = GetHost();
8873 CHECK_NULL_VOID(host);
8874 auto pipeline = host->GetContext();
8875 CHECK_NULL_VOID(pipeline);
8876 if (pipeline->UsingCaretAvoidMode()) {
8877 // using TriggerAvoidOnCaretChange instead in CaretAvoidMode
8878 return;
8879 }
8880 auto textFieldManager = DynamicCast<TextFieldManagerNG>(pipeline->GetTextFieldManager());
8881 CHECK_NULL_VOID(textFieldManager);
8882 textFieldManager->ScrollTextFieldToSafeArea();
8883 }
8884
8885 void TextFieldPattern::TriggerAvoidOnCaretChange()
8886 {
8887 CHECK_NULL_VOID(HasFocus());
8888 auto host = GetHost();
8889 CHECK_NULL_VOID(host);
8890 auto pipeline = host->GetContext();
8891 CHECK_NULL_VOID(pipeline);
8892 auto textFieldManager = DynamicCast<TextFieldManagerNG>(pipeline->GetTextFieldManager());
8893 CHECK_NULL_VOID(textFieldManager);
8894 CHECK_NULL_VOID(pipeline->UsingCaretAvoidMode());
8895 auto safeAreaManager = pipeline->GetSafeAreaManager();
8896 if (!safeAreaManager || NearEqual(safeAreaManager->GetKeyboardInset().Length(), 0)) {
8897 return;
8898 }
8899 if (selectOverlay_) {
8900 selectOverlay_->AddAvoidKeyboardCallback(isCustomKeyboardAttached_);
8901 }
8902 textFieldManager->TriggerAvoidOnCaretChange();
8903 auto caretPos = textFieldManager->GetFocusedNodeCaretRect().Top() + textFieldManager->GetHeight();
8904 SetLastCaretPos(caretPos);
8905 }
8906
8907 void TextFieldPattern::CheckTextAlignByDirection(TextAlign& textAlign, TextDirection direction)
8908 {
8909 if (direction == TextDirection::RTL) {
8910 if (textAlign == TextAlign::START) {
8911 textAlign = TextAlign::END;
8912 } else if (textAlign == TextAlign::END) {
8913 textAlign = TextAlign::START;
8914 }
8915 }
8916 }
8917
8918 void TextFieldPattern::RequestKeyboardAfterLongPress()
8919 {
8920 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
8921 if (isLongPress_ && HasFocus() && RequestKeyboardNotByFocusSwitch(RequestKeyboardReason::LONG_PRESS)) {
8922 NotifyOnEditChanged(true);
8923 if (!isCustomKeyboardAttached_ || keyboardAvoidance_) {
8924 selectOverlay_->AddAvoidKeyboardCallback(isCustomKeyboardAttached_);
8925 }
8926 }
8927 isLongPress_ = false;
8928 #endif
8929 }
8930
8931 void TextFieldPattern::GetCaretMetrics(CaretMetricsF& caretCaretMetric)
8932 {
8933 OffsetF offset = selectController_->GetCaretRect().GetOffset();
8934 float height = selectController_->GetCaretRect().Height();
8935 float width = selectController_->GetCaretRect().Width();
8936 auto host = GetHost();
8937 CHECK_NULL_VOID(host);
8938 auto textPaintOffset = host->GetPaintRectOffset(false, true);
8939 caretCaretMetric.offset = offset + textPaintOffset + OffsetF(width / 2.0f, 0.0f);
8940 caretCaretMetric.height = height;
8941 }
8942
8943 void TextFieldPattern::ScrollPage(bool reverse, bool smooth, AccessibilityScrollType scrollType)
8944 {
8945 auto border = GetBorderWidthProperty();
8946 float maxFrameHeight =
8947 frameRect_.Height() - GetPaddingTop() - GetPaddingBottom() - GetBorderTop(border) - GetBorderBottom(border);
8948 float distance = reverse ? maxFrameHeight : -maxFrameHeight;
8949 if (scrollType == AccessibilityScrollType::SCROLL_HALF) {
8950 distance = distance / 2.f;
8951 }
8952 OnScrollCallback(distance, SCROLL_FROM_JUMP);
8953 }
8954
8955 // correct after OnModifyDone
8956 bool TextFieldPattern::IsUnderlineMode() const
8957 {
8958 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
8959 CHECK_NULL_RETURN(layoutProperty, false);
8960 return layoutProperty->GetShowUnderlineValue(false) && IsUnspecifiedOrTextType() && !IsInlineMode();
8961 }
8962
8963 // correct after OnModifyDone
8964 bool TextFieldPattern::IsInlineMode() const
8965 {
8966 return HasFocus() && IsNormalInlineState();
8967 }
8968
8969 bool TextFieldPattern::IsShowError()
8970 {
8971 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
8972 CHECK_NULL_RETURN(layoutProperty, false);
8973 auto errorText = layoutProperty->GetErrorTextValue(u"");
8974 return layoutProperty->GetShowErrorTextValue(false) && !errorText.empty() && !IsNormalInlineState();
8975 }
8976
8977 bool TextFieldPattern::IsShowCount()
8978 {
8979 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
8980 CHECK_NULL_RETURN(layoutProperty, false);
8981 return layoutProperty->GetShowCounterValue(false) && !IsNormalInlineState() && !IsInPasswordMode() &&
8982 layoutProperty->HasMaxLength();
8983 }
8984
8985 void TextFieldPattern::ResetContextAttr()
8986 {
8987 auto host = GetHost();
8988 CHECK_NULL_VOID(host);
8989 auto renderContext = host->GetRenderContext();
8990 CHECK_NULL_VOID(renderContext);
8991 renderContext->ResetBorder();
8992 BorderWidthProperty borderWidth;
8993 borderWidth.SetBorderWidth(BORDER_DEFAULT_WIDTH);
8994 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
8995 CHECK_NULL_VOID(layoutProperty);
8996 layoutProperty->UpdateBorderWidth(borderWidth);
8997 }
8998
8999 void TextFieldPattern::SetThemeBorderAttr()
9000 {
9001 auto host = GetHost();
9002 CHECK_NULL_VOID(host);
9003 auto renderContext = host->GetRenderContext();
9004 CHECK_NULL_VOID(renderContext);
9005 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
9006 CHECK_NULL_VOID(layoutProperty);
9007 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
9008 CHECK_NULL_VOID(paintProperty);
9009 auto theme = GetTheme();
9010 CHECK_NULL_VOID(theme);
9011
9012 paintProperty->ResetInnerBorderColor();
9013 paintProperty->ResetInnerBorderWidth();
9014 if (!paintProperty->HasBorderColorFlagByUser()) {
9015 BorderColorProperty borderColor;
9016 borderColor.SetColor(theme->GetTextInputColor());
9017 renderContext->UpdateBorderColor(borderColor);
9018 } else {
9019 renderContext->UpdateBorderColor(paintProperty->GetBorderColorFlagByUserValue());
9020 }
9021
9022 if (!paintProperty->HasBorderRadiusFlagByUser()) {
9023 auto radius = theme->GetBorderRadius();
9024 BorderRadiusProperty borderRadius(radius.GetX(), radius.GetY(), radius.GetY(), radius.GetX());
9025 auto ultimatelyRadius = IsUnderlineMode() ? ZERO_BORDER_RADIUS_PROPERTY : borderRadius;
9026 renderContext->UpdateBorderRadius(ultimatelyRadius);
9027 } else {
9028 renderContext->UpdateBorderRadius(paintProperty->GetBorderRadiusFlagByUserValue());
9029 }
9030
9031 if (!paintProperty->HasBorderWidthFlagByUser()) {
9032 BorderWidthProperty borderWidth;
9033 if (IsTextArea() || IsUnderlineMode()) {
9034 borderWidth.SetBorderWidth(BORDER_DEFAULT_WIDTH);
9035 } else {
9036 borderWidth.SetBorderWidth(theme->GetTextInputWidth());
9037 }
9038 renderContext->UpdateBorderWidth(borderWidth);
9039 layoutProperty->UpdateBorderWidth(borderWidth);
9040 } else {
9041 renderContext->UpdateBorderWidth(paintProperty->GetBorderWidthFlagByUserValue());
9042 layoutProperty->UpdateBorderWidth(paintProperty->GetBorderWidthFlagByUserValue());
9043 }
9044 }
9045
9046 PaddingProperty TextFieldPattern::GetPaddingByUserValue()
9047 {
9048 PaddingProperty padding;
9049 auto theme = GetTheme();
9050 CHECK_NULL_RETURN(theme, padding);
9051 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
9052 CHECK_NULL_RETURN(paintProperty, padding);
9053 padding = paintProperty->GetPaddingByUserValue();
9054 auto themePadding = IsUnderlineMode() ? theme->GetUnderlinePadding() : theme->GetPadding();
9055 if (!padding.top.has_value()) {
9056 padding.top = CalcLength(CalcLength(themePadding.Top()).GetDimension());
9057 }
9058 if (!padding.bottom.has_value()) {
9059 padding.bottom = CalcLength(CalcLength(themePadding.Bottom()).GetDimension());
9060 }
9061 if (!padding.left.has_value()) {
9062 padding.left = CalcLength(CalcLength(themePadding.Left()).GetDimension());
9063 }
9064 if (!padding.right.has_value()) {
9065 padding.right = CalcLength(CalcLength(themePadding.Right()).GetDimension());
9066 }
9067 return padding;
9068 }
9069
9070 void TextFieldPattern::SetThemeAttr()
9071 {
9072 auto host = GetHost();
9073 CHECK_NULL_VOID(host);
9074 auto renderContext = host->GetRenderContext();
9075 CHECK_NULL_VOID(renderContext);
9076 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
9077 CHECK_NULL_VOID(layoutProperty);
9078 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
9079 CHECK_NULL_VOID(paintProperty);
9080 auto theme = GetTheme();
9081 CHECK_NULL_VOID(theme);
9082 SetThemeBorderAttr();
9083 if (!paintProperty->HasBackgroundColor()) {
9084 auto backgroundColor = isFocusBGColorSet_ ? theme->GetFocusBgColor() : theme->GetBgColor();
9085 backgroundColor = IsUnderlineMode() ? Color::TRANSPARENT : backgroundColor;
9086 renderContext->UpdateBackgroundColor(backgroundColor);
9087 } else {
9088 renderContext->UpdateBackgroundColor(paintProperty->GetBackgroundColorValue());
9089 }
9090
9091 if (!paintProperty->HasMarginByUser()) {
9092 MarginProperty margin;
9093 margin.SetEdges(CalcLength(0.0_vp));
9094 layoutProperty->UpdateMargin(margin);
9095 } else {
9096 layoutProperty->UpdateMargin(paintProperty->GetMarginByUserValue());
9097 }
9098
9099 if (!paintProperty->HasPaddingByUser()) {
9100 auto themePadding = IsUnderlineMode() ? theme->GetUnderlinePadding() : theme->GetPadding();
9101 PaddingProperty padding;
9102 padding.top = CalcLength(CalcLength(themePadding.Top()).GetDimension());
9103 padding.bottom = CalcLength(CalcLength(themePadding.Bottom()).GetDimension());
9104 padding.left = CalcLength(CalcLength(themePadding.Left()).GetDimension());
9105 padding.right = CalcLength(CalcLength(themePadding.Right()).GetDimension());
9106 layoutProperty->UpdatePadding(padding);
9107 } else {
9108 layoutProperty->UpdatePadding(GetPaddingByUserValue());
9109 }
9110
9111 if (!paintProperty->HasTextColorFlagByUser()) {
9112 auto textColor = isFocusTextColorSet_ ? theme->GetFocusTextColor() : theme->GetTextColor();
9113 layoutProperty->UpdateTextColor(textColor);
9114 } else {
9115 layoutProperty->UpdateTextColor(paintProperty->GetTextColorFlagByUserValue());
9116 }
9117 inlineFocusState_ = false;
9118 }
9119
9120 const Dimension& TextFieldPattern::GetAvoidSoftKeyboardOffset() const
9121 {
9122 auto textfieldTheme = GetTheme();
9123 if (!textfieldTheme) {
9124 return TextBase::GetAvoidSoftKeyboardOffset();
9125 }
9126 return textfieldTheme->GetAvoidKeyboardOffset();
9127 }
9128
9129 Offset TextFieldPattern::ConvertGlobalToLocalOffset(const Offset& globalOffset)
9130 {
9131 parentGlobalOffset_ = GetPaintRectGlobalOffset();
9132 auto localOffset = globalOffset - Offset(parentGlobalOffset_.GetX(), parentGlobalOffset_.GetY());
9133 if (selectOverlay_->HasRenderTransform()) {
9134 auto localOffsetF = OffsetF(globalOffset.GetX(), globalOffset.GetY());
9135 selectOverlay_->RevertLocalPointWithTransform(localOffsetF);
9136 localOffset.SetX(localOffsetF.GetX());
9137 localOffset.SetY(localOffsetF.GetY());
9138 }
9139 return localOffset;
9140 }
9141
9142 int32_t TextFieldPattern::SetPreviewText(const std::u16string &previewValue, const PreviewRange range)
9143 {
9144 PreviewTextInfo info = {
9145 .text = previewValue,
9146 .range = range,
9147 .isIme = true
9148 };
9149 auto host = GetHost();
9150 CHECK_NULL_RETURN(host, PREVIEW_NULL_POINTER);
9151 inputOperations_.emplace(InputOperation::SET_PREVIEW_TEXT);
9152 previewTextOperation_.emplace(info);
9153 CloseSelectOverlay(true);
9154 ScrollToSafeArea();
9155 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
9156 return PREVIEW_NO_ERROR;
9157 }
9158
9159 int32_t TextFieldPattern::SetPreviewText(const std::string &previewValue, const PreviewRange range)
9160 {
9161 return SetPreviewText(UtfUtils::Str8DebugToStr16(previewValue), range);
9162 }
9163
9164 void TextFieldPattern::SetPreviewTextOperation(PreviewTextInfo info)
9165 {
9166 auto host = GetHost();
9167 CHECK_NULL_VOID(host);
9168 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
9169 CHECK_NULL_VOID(layoutProperty);
9170 if (!hasPreviewText_) {
9171 bodyTextInPreivewing_ = GetTextUtf16Value();
9172 }
9173 auto rangeStart = info.range.start;
9174 auto rangeEnd = info.range.end;
9175 auto start = GetPreviewTextStart();
9176 auto end = GetPreviewTextEnd();
9177 if (IsSelected()) {
9178 start = selectController_->GetStartIndex();
9179 end = selectController_->GetEndIndex();
9180 } else {
9181 start = (rangeStart == PREVIEW_TEXT_RANGE_DEFAULT) ? start : rangeStart;
9182 end = (rangeEnd == PREVIEW_TEXT_RANGE_DEFAULT) ? end : rangeEnd;
9183 }
9184
9185 auto oldHasPreviewText = hasPreviewText_;
9186 ChangeValueInfo changeValueInfo;
9187 changeValueInfo.oldPreviewText.offset = hasPreviewText_ ? GetPreviewTextStart() : -1;
9188 changeValueInfo.oldPreviewText.value = GetPreviewTextValue();
9189 changeValueInfo.oldContent = GetBodyTextValue();
9190 changeValueInfo.rangeBefore = TextRange { GetPreviewTextStart(), GetPreviewTextStart() };
9191 changeValueInfo.rangeAfter = TextRange { GetPreviewTextStart(), GetPreviewTextStart() };
9192 auto originCaretIndex =
9193 TextRange { changeValueInfo.oldPreviewText.offset, changeValueInfo.oldPreviewText.offset };
9194 bool hasInsertValue = false;
9195 auto originLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length()) - (end - start);
9196 auto attemptInsertLength = static_cast<int32_t>(info.text.length()) - (end - start);
9197 if (layoutProperty->HasMaxLength() &&
9198 attemptInsertLength + static_cast<int32_t>(contentController_->GetTextUtf16Value().length()) >
9199 static_cast<int32_t>(layoutProperty->GetMaxLengthValue(Infinity<uint32_t>()))) {
9200 isPreviewTextOverCount_ = true;
9201 }
9202 hasInsertValue = contentController_->ReplaceSelectedValue(start, end, info.text);
9203 int32_t caretMoveLength = abs(static_cast<int32_t>(contentController_->GetTextUtf16Value().length()) -
9204 originLength);
9205
9206 int32_t delta =
9207 static_cast<int32_t>(contentController_->GetTextUtf16Value().length()) - originLength - (end - start);
9208 int32_t newCaretPosition = std::max(end, GetPreviewTextEnd()) + delta;
9209 newCaretPosition = std::clamp(newCaretPosition, 0,
9210 static_cast<int32_t>(contentController_->GetTextUtf16Value().length()));
9211 selectController_->UpdateCaretIndex(start + caretMoveLength);
9212
9213 UpdatePreviewIndex(start, newCaretPosition);
9214 hasPreviewText_ = true;
9215 changeValueInfo.value = GetBodyTextValue();
9216 changeValueInfo.previewText.offset = hasPreviewText_ ? GetPreviewTextStart() : -1;
9217 changeValueInfo.previewText.value = GetPreviewTextValue();
9218 bool isWillChange = FireOnWillChange(changeValueInfo);
9219 if (!isWillChange && !info.isIme) {
9220 RecoverTextValueAndCaret(changeValueInfo.oldContent, originCaretIndex);
9221 hasPreviewText_ = oldHasPreviewText;
9222 return;
9223 }
9224 if (HasFocus()) {
9225 cursorVisible_ = true;
9226 StartTwinkling();
9227 } else {
9228 cursorVisible_ = false;
9229 StopTwinkling();
9230 }
9231 }
9232
9233 void TextFieldPattern::FinishTextPreview()
9234 {
9235 inputOperations_.emplace(InputOperation::SET_PREVIEW_FINISH);
9236 auto host = GetHost();
9237 CHECK_NULL_VOID(host);
9238 ScrollToSafeArea();
9239 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
9240 }
9241
9242 void TextFieldPattern::FinishTextPreviewOperation()
9243 {
9244 if (!hasPreviewText_) {
9245 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "input state now is not at previewing text");
9246 return;
9247 }
9248 auto host = GetHost();
9249 CHECK_NULL_VOID(host);
9250 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
9251 CHECK_NULL_VOID(layoutProperty);
9252 if (layoutProperty->HasMaxLength()) {
9253 int32_t len = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
9254 showCountBorderStyle_ = isPreviewTextOverCount_ || (len >
9255 static_cast<int32_t>(layoutProperty->GetMaxLengthValue(Infinity<uint32_t>())));
9256 isPreviewTextOverCount_ = false;
9257 HandleCountStyle();
9258 }
9259
9260 auto oldValue = contentController_->GetTextUtf16Value();
9261 auto originCaretIndex =
9262 TextRange { selectController_->GetFirstHandleIndex(), selectController_->GetSecondHandleIndex() };
9263 ChangeValueInfo changeValueInfo;
9264 changeValueInfo.oldPreviewText.offset = hasPreviewText_ ? GetPreviewTextStart() : -1;
9265 changeValueInfo.oldPreviewText.value = GetPreviewTextValue();
9266 changeValueInfo.oldContent = GetBodyTextValue();
9267 changeValueInfo.rangeBefore = TextRange { GetPreviewTextStart(), GetPreviewTextStart() };
9268 auto start = GetPreviewTextStart();
9269 auto end = GetPreviewTextEnd();
9270 auto previewValue = GetPreviewTextValue();
9271 hasPreviewText_ = false;
9272 auto originLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length()) - (end - start);
9273 contentController_->ReplaceSelectedValue(start, end, previewValue);
9274 int32_t caretMoveLength = abs(static_cast<int32_t>(contentController_->GetTextUtf16Value().length()) -
9275 originLength);
9276 selectController_->UpdateCaretIndex(start + caretMoveLength);
9277 UpdateEditingValueToRecord();
9278 changeValueInfo.rangeAfter =
9279 TextRange { changeValueInfo.oldPreviewText.offset, selectController_->GetCaretIndex() };
9280 changeValueInfo.value = GetBodyTextValue();
9281 changeValueInfo.previewText.offset = hasPreviewText_ ? GetPreviewTextStart() : -1;
9282 changeValueInfo.previewText.value = GetPreviewTextValue();
9283 bool isWillChange = FireOnWillChange(changeValueInfo);
9284 if (!isWillChange) {
9285 RecoverTextValueAndCaret(oldValue, originCaretIndex);
9286 return;
9287 }
9288 if (HasFocus()) {
9289 cursorVisible_ = true;
9290 StartTwinkling();
9291 } else {
9292 cursorVisible_ = false;
9293 StopTwinkling();
9294 }
9295 bodyTextInPreivewing_ = u"";
9296 previewTextStart_ = PREVIEW_TEXT_RANGE_DEFAULT;
9297 previewTextEnd_ = PREVIEW_TEXT_RANGE_DEFAULT;
9298 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
9299 }
9300
9301 std::vector<RectF> TextFieldPattern::GetPreviewTextRects() const
9302 {
9303 if (!GetIsPreviewText()) {
9304 return {};
9305 }
9306 std::vector<RectF> boxes;
9307 std::vector<RectF> previewTextRects;
9308 CHECK_NULL_RETURN(paragraph_, boxes);
9309 paragraph_->GetRectsForRange(GetPreviewTextStart(), GetPreviewTextEnd(), boxes);
9310 if (boxes.empty()) {
9311 return {};
9312 }
9313 RectF linerRect(boxes.front().GetOffset(), SizeF(0, boxes.front().GetSize().Height()));
9314 float checkedTop = boxes.front().Top();
9315
9316 for (const auto& drawRect : boxes) {
9317 if (drawRect.Top() == checkedTop) {
9318 linerRect += SizeF(drawRect.GetSize().Width(), 0);
9319 } else {
9320 previewTextRects.emplace_back(linerRect);
9321 checkedTop = drawRect.Top();
9322 linerRect = drawRect;
9323 }
9324 }
9325 previewTextRects.emplace_back(linerRect);
9326 return previewTextRects;
9327 }
9328
9329 bool TextFieldPattern::NeedDrawPreviewText()
9330 {
9331 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
9332 CHECK_NULL_RETURN(paintProperty, false);
9333
9334 auto caretInfo = selectController_->GetCaretInfo();
9335 if (!paintProperty->HasPreviewTextStart() || !paintProperty->HasPreviewTextEnd()) {
9336 paintProperty->UpdatePreviewTextStart(caretInfo.index);
9337 paintProperty->UpdatePreviewTextEnd(caretInfo.index);
9338 }
9339
9340 auto paintStart = paintProperty->GetPreviewTextStart();
9341 auto paintEnd =paintProperty->GetPreviewTextEnd();
9342 if (!GetIsPreviewText()) {
9343 if (!paintStart.has_value() || !paintEnd.has_value()) {
9344 paintProperty->UpdatePreviewTextStart(caretInfo.index);
9345 paintProperty->UpdatePreviewTextEnd(caretInfo.index);
9346 return false;
9347 }
9348
9349 // end paint
9350 if (paintStart != paintEnd || paintStart.value() != caretInfo.index) {
9351 paintProperty->UpdatePreviewTextStart(caretInfo.index);
9352 paintProperty->UpdatePreviewTextEnd(caretInfo.index);
9353 return true;
9354 }
9355 return false;
9356 }
9357 auto needDraw = paintStart.value() != GetPreviewTextStart() ||
9358 paintEnd.value() != GetPreviewTextEnd();
9359 paintProperty->UpdatePreviewTextStart(GetPreviewTextStart());
9360 paintProperty->UpdatePreviewTextEnd(GetPreviewTextEnd());
9361 return needDraw;
9362 }
9363
9364 int32_t TextFieldPattern::CheckPreviewTextValidate(const std::u16string& previewValue, const PreviewRange range)
9365 {
9366 auto start = range.start;
9367 auto end = range.end;
9368 if (start != end && (start == PREVIEW_TEXT_RANGE_DEFAULT || end == PREVIEW_TEXT_RANGE_DEFAULT)) {
9369 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "range is not [-1,-1] or legal range");
9370 return PREVIEW_BAD_PARAMETERS;
9371 }
9372
9373 if (start != PREVIEW_TEXT_RANGE_DEFAULT && IsSelected()) {
9374 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "unsupported insert preview text when IsSelected");
9375 return PREVIEW_BAD_PARAMETERS;
9376 }
9377 return PREVIEW_NO_ERROR;
9378 }
9379
9380 int32_t TextFieldPattern::CheckPreviewTextValidate(const std::string& previewValue, const PreviewRange range)
9381 {
9382 return CheckPreviewTextValidate(UtfUtils::Str8DebugToStr16(previewValue), range);
9383 }
9384
9385 PreviewTextStyle TextFieldPattern::GetPreviewTextStyle() const
9386 {
9387 auto defaultStyle = PreviewTextStyle::NORMAL;
9388 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
9389 CHECK_NULL_RETURN(paintProperty, defaultStyle);
9390 if (paintProperty->HasPreviewTextStyle()) {
9391 auto style = paintProperty->GetPreviewTextStyle();
9392 if (style.value() == PREVIEW_STYLE_NORMAL) {
9393 return PreviewTextStyle::NORMAL;
9394 } else if (style.value() == PREVIEW_STYLE_UNDERLINE) {
9395 return PreviewTextStyle::UNDERLINE;
9396 }
9397 }
9398 return defaultStyle;
9399 }
9400
9401 void TextFieldPattern::ReceivePreviewTextStyle(const std::string& style)
9402 {
9403 auto paintProperty = GetPaintProperty<TextFieldPaintProperty>();
9404 CHECK_NULL_VOID(paintProperty);
9405 if (!style.empty()) {
9406 paintProperty->UpdatePreviewTextStyle(style);
9407 }
9408 }
9409
9410 void TextFieldPattern::CalculatePreviewingTextMovingLimit(const Offset& touchOffset, double& limitL, double& limitR)
9411 {
9412 float offsetX = IsTextArea() ? contentRect_.GetX() : GetTextRect().GetX();
9413 float offsetY = IsTextArea() ? GetTextRect().GetY() : contentRect_.GetY();
9414 std::vector<RectF> previewTextRects = GetPreviewTextRects();
9415 if (GreatNotEqual(touchOffset.GetY(), previewTextRects.back().Bottom() + offsetY)) {
9416 limitL = previewTextRects.back().Left() + offsetX + MINIMAL_OFFSET;
9417 limitR = previewTextRects.back().Right() + offsetX - MINIMAL_OFFSET;
9418 } else if (LessNotEqual(touchOffset.GetY(), previewTextRects.front().Top() + offsetY)) {
9419 limitL = previewTextRects.front().Left() + offsetX + MINIMAL_OFFSET;
9420 limitR = previewTextRects.front().Right() + offsetX - MINIMAL_OFFSET;
9421 } else {
9422 for (const auto& drawRect : previewTextRects) {
9423 if (GreatOrEqual(touchOffset.GetY(), drawRect.Top() + offsetY)
9424 && LessOrEqual(touchOffset.GetY(), drawRect.Bottom() + offsetY)) {
9425 limitL = drawRect.Left() + offsetX + MINIMAL_OFFSET;
9426 limitR = drawRect.Right() + offsetX - MINIMAL_OFFSET;
9427 break;
9428 }
9429 }
9430 }
9431 }
9432
9433 void TextFieldPattern::ResetPreviewTextState()
9434 {
9435 if (!GetIsPreviewText()) {
9436 return;
9437 }
9438 #if defined(ENABLE_STANDARD_INPUT)
9439 MiscServices::InputMethodController::GetInstance()->OnSelectionChange(
9440 StringUtils::Str8ToStr16(""), 0, 0);
9441 UpdateCaretInfoToController(true);
9442 #endif
9443 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "textfield onDragEnter when has previewText");
9444 FinishTextPreview();
9445 }
9446
9447 void TextFieldPattern::SetShowKeyBoardOnFocus(bool value)
9448 {
9449 if (showKeyBoardOnFocus_ == value) {
9450 return;
9451 }
9452 showKeyBoardOnFocus_ = value;
9453
9454 if (!HasFocus()) {
9455 return;
9456 }
9457
9458 if (value) {
9459 RequestKeyboardNotByFocusSwitch(RequestKeyboardReason::SHOW_KEYBOARD_ON_FOCUS);
9460 } else {
9461 CloseKeyboard(true, false);
9462 }
9463 }
9464
9465 void TextFieldPattern::OnCaretMoveDone(const TouchEventInfo& info)
9466 {
9467 if (isMoveCaretAnywhere_) {
9468 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "isMoveCaretAnywhere_=1, so restore caret");
9469 selectController_->UpdateCaretInfoByOffset(info.GetTouches().front().GetLocalLocation());
9470 StartTwinkling();
9471 }
9472 }
9473
9474 void TextFieldPattern::HiddenMenu()
9475 {
9476 selectOverlay_->HideMenu();
9477 }
9478
9479 void TextFieldPattern::OnSelectionMenuOptionsUpdate(
9480 const NG::OnCreateMenuCallback&& onCreateMenuCallback, const NG::OnMenuItemClickCallback&& onMenuItemClick)
9481 {
9482 selectOverlay_->OnSelectionMenuOptionsUpdate(std::move(onCreateMenuCallback), std::move(onMenuItemClick));
9483 }
9484
9485 bool TextFieldPattern::GetTouchInnerPreviewText(const Offset& offset) const
9486 {
9487 auto touchDownIndex = selectController_->ConvertTouchOffsetToPosition(offset);
9488 return GetPreviewTextStart() <= touchDownIndex && touchDownIndex <= GetPreviewTextEnd() && HasFocus();
9489 }
9490
9491 bool TextFieldPattern::IsResponseRegionExpandingNeededForStylus(const TouchEvent& touchEvent) const
9492 {
9493 if (touchEvent.sourceTool != SourceTool::PEN || touchEvent.type != TouchType::DOWN) {
9494 return false;
9495 }
9496 auto host = GetHost();
9497 CHECK_NULL_RETURN(host, false);
9498 auto focusHub = host->GetFocusHub();
9499 CHECK_NULL_RETURN(focusHub, false);
9500 if (!focusHub->IsFocusable() || !host->IsVisible()) {
9501 return false;
9502 }
9503 auto renderContext = host->GetRenderContext();
9504 CHECK_NULL_RETURN(renderContext, false);
9505 auto opacity = renderContext->GetOpacity();
9506 // if opacity is 0.0f, no need to hit frameNode.
9507 if (NearZero(opacity.value_or(1.0f))) {
9508 return false;
9509 }
9510 return !IsInPasswordMode();
9511 }
9512
9513 RectF TextFieldPattern::ExpandDefaultResponseRegion(RectF& rect)
9514 {
9515 return rect + NG::SizeF(0, OHOS::Ace::HOT_AREA_ADJUST_SIZE.ConvertToPx() * OHOS::Ace::HOT_AREA_EXPAND_TIME) +
9516 NG::OffsetF(0, -OHOS::Ace::HOT_AREA_ADJUST_SIZE.ConvertToPx());
9517 }
9518
9519 bool TextFieldPattern::IsContentRectNonPositive()
9520 {
9521 return NonPositive(contentRect_.Width());
9522 }
9523
9524 void TextFieldPattern::ReportEvent()
9525 {
9526 #if !defined(PREVIEW) && !defined(ACE_UNITTEST) && defined(OHOS_PLATFORM)
9527 if (UiSessionManager::GetInstance()->GetSearchEventRegistered()) {
9528 auto host = GetHost();
9529 CHECK_NULL_VOID(host);
9530 auto data = JsonUtil::Create();
9531 data->Put("event", "onTextSearch");
9532 data->Put("id", host->GetId());
9533 data->Put("$type", host->GetTag().data());
9534 data->Put("inputType", static_cast<int16_t>(GetKeyboard()));
9535 data->Put("text", GetTextValue().data());
9536 data->Put("position", host->GetGeometryNode()->GetFrameRect().ToString().data());
9537 // report all use textfield component unfocus event,more than just the search box
9538 UiSessionManager::GetInstance()->ReportSearchEvent(data->ToString());
9539 }
9540 #endif
9541 }
9542
9543 int32_t TextFieldPattern::GetTouchIndex(const OffsetF& offset)
9544 {
9545 return selectOverlay_->GetCaretPositionOnHandleMove(offset, true);
9546 }
9547
9548 void TextFieldPattern::StartGestureSelection(int32_t start, int32_t end, const Offset& startOffset)
9549 {
9550 TextGestureSelector::StartGestureSelection(start, end, startOffset);
9551 StopContentScroll();
9552 contentScroller_.scrollingCallback = [weak = WeakClaim(this), start, end](const Offset& localOffset) {
9553 auto pattern = weak.Upgrade();
9554 CHECK_NULL_VOID(pattern);
9555 auto index = pattern->GetTouchIndex({ localOffset.GetX(), localOffset.GetY() });
9556 auto startIndex = std::min(index, start);
9557 auto endIndex = std::max(index, end);
9558 pattern->UpdateSelectionByLongPress(startIndex, endIndex, localOffset);
9559 };
9560 }
9561
9562 void TextFieldPattern::OnTextGestureSelectionUpdate(int32_t start, int32_t end, const TouchEventInfo& info)
9563 {
9564 if (!HasText()) {
9565 return;
9566 }
9567 auto localOffset = info.GetTouches().front().GetLocalLocation();
9568 UpdateContentScroller(localOffset);
9569 if (contentScroller_.isScrolling) {
9570 return;
9571 }
9572 if (start != selectController_->GetStartIndex()) {
9573 StartVibratorByIndexChange(start, selectController_->GetStartIndex());
9574 } else if (end != selectController_->GetEndIndex()) {
9575 StartVibratorByIndexChange(end, selectController_->GetEndIndex());
9576 }
9577 UpdateSelectionByLongPress(start, end, localOffset);
9578 }
9579
9580 void TextFieldPattern::UpdateSelectionByLongPress(int32_t start, int32_t end, const Offset& localOffset)
9581 {
9582 if (magnifierController_ && HasText() && (longPressFingerNum_ == 1)) {
9583 contentScroller_.updateMagniferEpsilon = 0.0f - contentScroller_.updateMagniferEpsilon;
9584 magnifierController_->SetLocalOffset(
9585 { localOffset.GetX(), localOffset.GetY() + contentScroller_.updateMagniferEpsilon });
9586 }
9587 auto firstIndex = selectController_->GetFirstHandleIndex();
9588 auto secondIndex = selectController_->GetSecondHandleIndex();
9589 bool changed = false;
9590 if (start != firstIndex) {
9591 selectController_->MoveFirstHandleToContentRect(start, false, false);
9592 changed = true;
9593 }
9594 if (secondIndex != end) {
9595 selectController_->MoveSecondHandleToContentRect(end, false, false);
9596 changed = true;
9597 }
9598 if (!changed) {
9599 return;
9600 }
9601 auto host = GetHost();
9602 CHECK_NULL_VOID(host);
9603 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
9604 }
9605
9606 void TextFieldPattern::OnTextGenstureSelectionEnd(const TouchLocationInfo& locationInfo)
9607 {
9608 SetIsSingleHandle(!IsSelected());
9609 bool isScrolling = contentScroller_.isScrolling;
9610 StopContentScroll();
9611 if (IsContentRectNonPositive()) {
9612 return;
9613 }
9614 if (!isScrolling) {
9615 auto localLocation = locationInfo.GetLocalLocation();
9616 if (LessNotEqual(localLocation.GetX(), contentRect_.Left()) ||
9617 LessNotEqual(localLocation.GetY(), contentRect_.Top())) {
9618 selectController_->MoveFirstHandleToContentRect(selectController_->GetFirstHandleIndex(), false);
9619 } else if (GreatNotEqual(localLocation.GetX(), contentRect_.Right()) ||
9620 GreatNotEqual(localLocation.GetY(), contentRect_.Bottom())) {
9621 selectController_->MoveSecondHandleToContentRect(selectController_->GetSecondHandleIndex(), false);
9622 }
9623 } else {
9624 if (Positive(contentScroller_.stepOffset)) {
9625 selectController_->MoveFirstHandleToContentRect(selectController_->GetFirstHandleIndex(), false);
9626 } else if (Negative(contentScroller_.stepOffset)) {
9627 selectController_->MoveSecondHandleToContentRect(selectController_->GetSecondHandleIndex(), false);
9628 }
9629 }
9630 if (HasFocus()) {
9631 ProcessOverlay({ .animation = true });
9632 }
9633 }
9634
9635 PositionWithAffinity TextFieldPattern::GetGlyphPositionAtCoordinate(int32_t x, int32_t y)
9636 {
9637 PositionWithAffinity finalResult(0, TextAffinity::UPSTREAM);
9638 CHECK_NULL_RETURN(paragraph_, finalResult);
9639 Offset offset(x, y);
9640 return paragraph_->GetGlyphPositionAtCoordinate(ConvertTouchOffsetToTextOffset(offset));
9641 }
9642
9643 Offset TextFieldPattern::ConvertTouchOffsetToTextOffset(const Offset& touchOffset)
9644 {
9645 return touchOffset - Offset(textRect_.GetX(), textRect_.GetY());
9646 }
9647
9648 bool TextFieldPattern::InsertOrDeleteSpace(int32_t index)
9649 {
9650 // delete or insert space.
9651 auto wtext = GetTextUtf16Value();
9652 if (index >= 0 && index < static_cast<int32_t>(wtext.length())) {
9653 auto ret = SetCaretOffset(index);
9654 if (!ret) {
9655 return false;
9656 }
9657 if (wtext[index] == u' ') {
9658 DeleteForward(1);
9659 } else if (index > 0 && wtext[index - 1] == u' ') {
9660 DeleteBackward(1);
9661 } else {
9662 InsertValue(u" ", true);
9663 }
9664 return true;
9665 }
9666 return false;
9667 }
9668
9669 void TextFieldPattern::DeleteRange(int32_t start, int32_t end, bool isIME)
9670 {
9671 auto length = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
9672 if (start > end) {
9673 std::swap(start, end);
9674 }
9675 start = std::max(0, start);
9676 end = std::min(length, end);
9677 if (start > length || end < 0 || start == end) {
9678 return;
9679 }
9680 auto value = contentController_->GetSelectedValue(start, end);
9681 auto originCaretIndex =
9682 TextRange { selectController_->GetFirstHandleIndex(), selectController_->GetSecondHandleIndex() };
9683 if (isIME) {
9684 auto isDelete = BeforeIMEDeleteValue(value, TextDeleteDirection::FORWARD, start);
9685 CHECK_NULL_VOID(isDelete);
9686 }
9687 ResetObscureTickCountDown();
9688 CheckAndUpdateRecordBeforeOperation();
9689 auto oldContent = contentController_->GetTextUtf16Value();
9690 Delete(start, end);
9691 auto isOnWillChange = OnWillChangePreDelete(oldContent, start, end);
9692 if (!isOnWillChange) {
9693 RecoverTextValueAndCaret(oldContent, originCaretIndex);
9694 return;
9695 }
9696 if (isIME) {
9697 AfterIMEDeleteValue(value, TextDeleteDirection::FORWARD);
9698 }
9699 showCountBorderStyle_ = false;
9700 HandleCountStyle();
9701 }
9702
9703 void TextFieldPattern::DeleteTextRange(int32_t start, int32_t end, TextDeleteDirection direction)
9704 {
9705 auto length = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
9706 if (start > end) {
9707 std::swap(start, end);
9708 }
9709 start = std::max(0, start);
9710 end = std::min(length, end);
9711 if (start > length || end < 0 || start == end) {
9712 return;
9713 }
9714 auto value = contentController_->GetSelectedValue(start, end);
9715 auto originCaretIndex =
9716 TextRange { selectController_->GetFirstHandleIndex(), selectController_->GetSecondHandleIndex() };
9717 auto isDelete = BeforeIMEDeleteValue(value, direction, start);
9718 CHECK_NULL_VOID(isDelete);
9719 ResetObscureTickCountDown();
9720 CheckAndUpdateRecordBeforeOperation();
9721 auto oldContent = contentController_->GetTextUtf16Value();
9722 Delete(start, end);
9723 auto isOnWillChange = OnWillChangePreDelete(oldContent, start, end);
9724 if (!isOnWillChange) {
9725 RecoverTextValueAndCaret(oldContent, originCaretIndex);
9726 return;
9727 }
9728 AfterIMEDeleteValue(value, direction);
9729 showCountBorderStyle_ = false;
9730 HandleCountStyle();
9731 }
9732
9733 bool TextFieldPattern::IsShowAIWrite()
9734 {
9735 auto container = Container::Current();
9736 if (container && container->IsScenceBoardWindow()) {
9737 return false;
9738 }
9739
9740 auto host = GetHost();
9741 CHECK_NULL_RETURN(host, false);
9742 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
9743 CHECK_NULL_RETURN(layoutProperty, false);
9744 if (layoutProperty->GetCopyOptionsValue(CopyOptions::Local) == CopyOptions::None ||
9745 !IsUnspecifiedOrTextType()) {
9746 return false;
9747 }
9748
9749 auto textFieldTheme = GetTheme();
9750 CHECK_NULL_RETURN(textFieldTheme, false);
9751 auto bundleName = textFieldTheme->GetAIWriteBundleName();
9752 auto abilityName = textFieldTheme->GetAIWriteAbilityName();
9753 if (bundleName.empty() || abilityName.empty()) {
9754 TAG_LOGW(AceLogTag::ACE_TEXT_FIELD, "Failed to obtain AI write package name!");
9755 return false;
9756 }
9757 aiWriteAdapter_->SetBundleName(bundleName);
9758 aiWriteAdapter_->SetAbilityName(abilityName);
9759
9760 auto isAISupport = false;
9761 if (textFieldTheme->GetAIWriteIsSupport() == "true") {
9762 isAISupport = true;
9763 }
9764 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "Whether the device supports AI write: %{public}d, nodeId: %{public}d",
9765 isAISupport, host->GetId());
9766 return isAISupport;
9767 }
9768
9769 void TextFieldPattern::GetAIWriteInfo(AIWriteInfo& info)
9770 {
9771 // serialize the selected text
9772 info.selectStart = selectController_->GetStartIndex();
9773 info.selectEnd = selectController_->GetEndIndex();
9774 auto selectContent = contentController_->GetSelectedValue(info.selectStart, info.selectEnd);
9775 RefPtr<SpanString> spanString = AceType::MakeRefPtr<SpanString>(selectContent);
9776 spanString->EncodeTlv(info.selectBuffer);
9777 info.selectLength = static_cast<int32_t>(aiWriteAdapter_->GetSelectLengthOnlyText(spanString->GetU16string()));
9778 TAG_LOGD(AceLogTag::ACE_TEXT_FIELD, "Selected range=[%{public}d--%{public}d], content size=%{public}zu",
9779 info.selectStart, info.selectEnd, spanString->GetString().size());
9780
9781 // serialize the sentenced-level text
9782 auto textSize = static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
9783 auto contentAll = contentController_->GetTextUtf16Value();
9784 auto sentenceStart = 0;
9785 auto sentenceEnd = textSize;
9786 for (int32_t i = info.selectStart; i >= 0; --i) {
9787 if (aiWriteAdapter_->IsSentenceBoundary(contentAll[i])) {
9788 sentenceStart = i + 1;
9789 break;
9790 }
9791 }
9792 for (int32_t i = info.selectEnd; i < textSize; i++) {
9793 if (aiWriteAdapter_->IsSentenceBoundary(contentAll[i])) {
9794 sentenceEnd = i;
9795 break;
9796 }
9797 }
9798 info.start = info.selectStart - sentenceStart;
9799 info.end = info.selectEnd - sentenceStart;
9800 auto sentenceContent = contentController_->GetSelectedValue(sentenceStart, sentenceEnd);
9801 spanString = AceType::MakeRefPtr<SpanString>(sentenceContent);
9802 spanString->EncodeTlv(info.sentenceBuffer);
9803 TAG_LOGD(AceLogTag::ACE_TEXT_FIELD, "Sentence range=[%{public}d--%{public}d], content size=%{public}zu",
9804 sentenceStart, sentenceEnd, spanString->GetString().size());
9805
9806 auto host = GetHost();
9807 CHECK_NULL_VOID(host);
9808 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
9809 CHECK_NULL_VOID(layoutProperty);
9810 info.maxLength = static_cast<int32_t>(layoutProperty->GetMaxLengthValue(Infinity<uint32_t>()));
9811 info.firstHandle = selectController_->GetFirstHandleRect().ToString();
9812 info.secondHandle = selectController_->GetSecondHandleRect().ToString();
9813 info.componentType = host->GetTag();
9814 }
9815
9816 void TextFieldPattern::HandleOnAIWrite()
9817 {
9818 AIWriteInfo info;
9819 GetAIWriteInfo(info);
9820 CloseSelectOverlay();
9821 CloseKeyboard(true);
9822
9823 auto callback = [weak = WeakClaim(this), info](std::vector<uint8_t>& buffer) {
9824 auto pattern = weak.Upgrade();
9825 CHECK_NULL_VOID(pattern);
9826 pattern->HandleAIWriteResult(info.selectStart, info.selectEnd, buffer);
9827 auto aiWriteAdapter = pattern->aiWriteAdapter_;
9828 CHECK_NULL_VOID(aiWriteAdapter);
9829 aiWriteAdapter->CloseModalUIExtension();
9830 };
9831 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
9832 CHECK_NULL_VOID(pipeline);
9833 aiWriteAdapter_->SetPipelineContext(pipeline);
9834 aiWriteAdapter_->ShowModalUIExtension(info, callback);
9835 }
9836
9837 void TextFieldPattern::HandleAIWriteResult(int32_t start, int32_t end, std::vector<uint8_t>& buffer)
9838 {
9839 RefPtr<SpanString> spanString = SpanString::DecodeTlv(buffer);
9840 auto resultText = spanString->GetU16string();
9841 TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "Backfilling results range=[%{public}d--%{public}d], content size=%{public}zu",
9842 start, end, spanString->GetString().size());
9843 if (spanString->GetSpanItems().empty()) {
9844 return;
9845 }
9846
9847 auto host = GetHost();
9848 CHECK_NULL_VOID(host);
9849 auto value = contentController_->GetSelectedValue(start, end);
9850 InputCommandInfo inputCommandInfo;
9851 inputCommandInfo.deleteRange = { start, end };
9852 inputCommandInfo.insertOffset = start;
9853 inputCommandInfo.insertValue = resultText;
9854 inputCommandInfo.reason = InputReason::AI_WRITE;
9855 AddInputCommand(inputCommandInfo);
9856 }
9857
9858 bool TextFieldPattern::IsTextEditableForStylus() const
9859 {
9860 CHECK_NULL_RETURN(!HasCustomKeyboard(), false);
9861 auto host = GetHost();
9862 CHECK_NULL_RETURN(host, false);
9863 auto focusHub = host->GetFocusHub();
9864 CHECK_NULL_RETURN(focusHub, false);
9865 if (!focusHub->IsFocusable() || !host->IsVisible()) {
9866 return false;
9867 }
9868 auto renderContext = host->GetRenderContext();
9869 CHECK_NULL_RETURN(renderContext, false);
9870 auto opacity = renderContext->GetOpacity();
9871 // if opacity is 0.0f, no need to hit frameNode.
9872 if (NearZero(opacity.value_or(1.0f))) {
9873 return false;
9874 }
9875 return !IsInPasswordMode();
9876 }
9877
9878 void TextFieldPattern::UpdateContentScroller(const Offset& localOffset)
9879 {
9880 auto scrollStep = CalcAutoScrollStepOffset(localOffset);
9881 // 在热区外移动
9882 if (!scrollStep || (!GetScrollEnabled() && !moveCaretState_.isMoveCaret)) {
9883 contentScroller_.OnBeforeScrollingCallback(localOffset);
9884 PauseContentScroll();
9885 contentScroller_.hotAreaOffset.reset();
9886 return;
9887 }
9888 contentScroller_.stepOffset = scrollStep.value();
9889 contentScroller_.localOffset = localOffset;
9890 if (contentScroller_.isScrolling) {
9891 return;
9892 }
9893 contentScroller_.OnBeforeScrollingCallback(localOffset);
9894 if (!contentScroller_.hotAreaOffset) {
9895 contentScroller_.hotAreaOffset = localOffset;
9896 ScheduleContentScroll(AUTO_SCROLL_HOT_AREA_LONGPRESS_DURATION);
9897 } else {
9898 auto hotAreaMoveDistance = (localOffset - contentScroller_.hotAreaOffset.value()).GetDistance();
9899 if (GreatOrEqual(hotAreaMoveDistance, AUTO_SCROLL_HOT_AREA_LONGPRESS_DISTANCE.ConvertToPx())) {
9900 contentScroller_.hotAreaOffset = localOffset;
9901 contentScroller_.autoScrollTask.Cancel();
9902 ScheduleContentScroll(AUTO_SCROLL_HOT_AREA_LONGPRESS_DURATION);
9903 }
9904 }
9905 }
9906
9907 std::optional<float> TextFieldPattern::CalcAutoScrollStepOffset(const Offset& localOffset)
9908 {
9909 auto contentRect = GetContentRect();
9910 auto axis = GetAxis();
9911 auto isVertical = (axis == Axis::VERTICAL);
9912 auto hotArea = isVertical ? AUTO_SCROLL_HOT_ZONE_HEIGHT.ConvertToPx() : AUTO_SCROLL_HOT_ZONE_WIDTH.ConvertToPx();
9913 if (isVertical) {
9914 if (LessOrEqual(contentRect.Height(), hotArea)) {
9915 hotArea = contentRect.Height() / 3.0f;
9916 }
9917 } else {
9918 if (LessOrEqual(contentRect.Width(), hotArea)) {
9919 hotArea = contentRect.Width() / 3.0f;
9920 }
9921 }
9922 struct HotEdge {
9923 float start = 0.0f;
9924 float end = 0.0f;
9925 float scrollDirection = 1.0f;
9926 };
9927 std::vector<HotEdge> hotEdges = { { contentRect.Top() + hotArea, contentRect.Top(), 1.0f },
9928 { contentRect.Bottom() - hotArea, contentRect.Bottom(), -1.0f },
9929 { contentRect.Left() + hotArea, contentRect.Left(), 1.0f },
9930 { contentRect.Right() - hotArea, contentRect.Right(), -1.0f } };
9931 auto itStart = isVertical ? hotEdges.begin() : hotEdges.begin() + 2;
9932 auto point = isVertical ? localOffset.GetY() : localOffset.GetX();
9933 std::optional<float> scrollStep;
9934 for (auto it = itStart; it != (itStart + 2); ++it) {
9935 auto speed = CalcScrollSpeed(it->start, it->end, point);
9936 if (!NearZero(speed)) {
9937 scrollStep = speed * it->scrollDirection;
9938 break;
9939 }
9940 }
9941 return scrollStep;
9942 }
9943
9944 float TextFieldPattern::CalcScrollSpeed(float hotAreaStart, float hotAreaEnd, float point)
9945 {
9946 auto minHotArea = std::min(hotAreaStart, hotAreaEnd);
9947 auto maxHotArea = std::max(hotAreaStart, hotAreaEnd);
9948 if (GreatNotEqual(point, minHotArea) && LessNotEqual(point, maxHotArea)) {
9949 auto distanceRatio = (point - hotAreaStart) / (hotAreaEnd - hotAreaStart);
9950 auto speedFactor = Curves::SHARP->MoveInternal(distanceRatio);
9951 return ((MAX_DRAG_SCROLL_SPEED * speedFactor) / TIME_UNIT) * contentScroller_.scrollInterval;
9952 }
9953 return 0.0f;
9954 }
9955
9956 void TextFieldPattern::StopContentScroll()
9957 {
9958 PauseContentScroll();
9959 contentScroller_.scrollingCallback = nullptr;
9960 contentScroller_.beforeScrollingCallback = nullptr;
9961 }
9962
9963 void TextFieldPattern::PauseContentScroll()
9964 {
9965 contentScroller_.autoScrollTask.Cancel();
9966 contentScroller_.isScrolling = false;
9967 ScheduleDisappearDelayTask();
9968 }
9969
9970 void TextFieldPattern::ScheduleContentScroll(float delay)
9971 {
9972 auto host = GetHost();
9973 CHECK_NULL_VOID(host);
9974 auto context = host->GetContext();
9975 CHECK_NULL_VOID(context);
9976 auto taskExecutor = context->GetTaskExecutor();
9977 CHECK_NULL_VOID(taskExecutor);
9978 contentScroller_.autoScrollTask.Reset([weak = WeakClaim(this)]() {
9979 auto pattern = weak.Upgrade();
9980 CHECK_NULL_VOID(pattern);
9981 pattern->contentScroller_.isScrolling = true;
9982 pattern->contentScroller_.hotAreaOffset = std::nullopt;
9983 pattern->OnScrollCallback(pattern->contentScroller_.stepOffset, SCROLL_FROM_UPDATE);
9984 if (pattern->contentScroller_.scrollingCallback) {
9985 pattern->contentScroller_.scrollingCallback(pattern->contentScroller_.localOffset);
9986 }
9987 pattern->ScheduleContentScroll(pattern->contentScroller_.scrollInterval);
9988 });
9989 taskExecutor->PostDelayedTask(contentScroller_.autoScrollTask, TaskExecutor::TaskType::UI, delay,
9990 "ArkUIAutoScrollControllerScheduleAutoScroll");
9991 }
9992
9993 void TextFieldPattern::SetDragMovingScrollback()
9994 {
9995 StopContentScroll();
9996 contentScroller_.scrollingCallback = [weak = WeakClaim(this)](const Offset& localOffset) {
9997 auto pattern = weak.Upgrade();
9998 CHECK_NULL_VOID(pattern);
9999 auto host = pattern->GetHost();
10000 CHECK_NULL_VOID(host);
10001 auto pipeline = host->GetContext();
10002 CHECK_NULL_VOID(pipeline);
10003 auto theme = pipeline->GetTheme<TextFieldTheme>();
10004 CHECK_NULL_VOID(theme);
10005 Offset offset = localOffset - Offset(pattern->textRect_.GetX(), pattern->textRect_.GetY()) -
10006 Offset(0, theme->GetInsertCursorOffset().ConvertToPx());
10007 auto position = pattern->ConvertTouchOffsetToCaretPosition(offset);
10008 pattern->SetCaretPosition(position, false);
10009 pattern->ShowCaretAndStopTwinkling();
10010 };
10011 contentScroller_.beforeScrollingCallback = contentScroller_.scrollingCallback;
10012 }
10013
10014 void TextFieldPattern::OnAttachToMainTree()
10015 {
10016 isDetachFromMainTree_ = false;
10017 auto host = GetHost();
10018 CHECK_NULL_VOID(host);
10019 auto autoFillContainerNode = host->GetFirstAutoFillContainerNode();
10020 CHECK_NULL_VOID(autoFillContainerNode);
10021 firstAutoFillContainerNode_ = WeakClaim(RawPtr(autoFillContainerNode));
10022 AddTextFieldInfo();
10023 }
10024
10025 void TextFieldPattern::OnDetachFromMainTree()
10026 {
10027 isDetachFromMainTree_ = true;
10028 RemoveTextFieldInfo();
10029 }
10030
10031 TextFieldInfo TextFieldPattern::GenerateTextFieldInfo()
10032 {
10033 TextFieldInfo textFieldInfo;
10034 auto host = GetHost();
10035 CHECK_NULL_RETURN(host, textFieldInfo);
10036 textFieldInfo.nodeId = host->GetId();
10037 auto autoFillContainerNode = firstAutoFillContainerNode_.Upgrade();
10038 CHECK_NULL_RETURN(autoFillContainerNode, textFieldInfo);
10039 textFieldInfo.autoFillContainerNodeId = autoFillContainerNode->GetId();
10040 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
10041 CHECK_NULL_RETURN(layoutProperty, textFieldInfo);
10042 textFieldInfo.enableAutoFill = layoutProperty->GetEnableAutoFillValue(true);
10043 textFieldInfo.inputType = layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED);
10044 textFieldInfo.contentType = layoutProperty->GetTextContentTypeValue(TextContentType::UNSPECIFIED);
10045 return textFieldInfo;
10046 }
10047
10048 void TextFieldPattern::AddTextFieldInfo()
10049 {
10050 CHECK_NULL_VOID(IsNeedProcessAutoFill());
10051 auto host = GetHost();
10052 CHECK_NULL_VOID(host);
10053 auto pipeline = host->GetContext();
10054 CHECK_NULL_VOID(pipeline);
10055 auto textFieldManager = DynamicCast<TextFieldManagerNG>(pipeline->GetTextFieldManager());
10056 CHECK_NULL_VOID(textFieldManager);
10057 auto textFieldInfo = GenerateTextFieldInfo();
10058 textFieldManager->AddTextFieldInfo(textFieldInfo);
10059 }
10060
10061 void TextFieldPattern::RemoveTextFieldInfo()
10062 {
10063 CHECK_NULL_VOID(IsNeedProcessAutoFill());
10064 auto host = GetHost();
10065 CHECK_NULL_VOID(host);
10066 auto pipeline = host->GetContext();
10067 CHECK_NULL_VOID(pipeline);
10068 auto textFieldManager = DynamicCast<TextFieldManagerNG>(pipeline->GetTextFieldManager());
10069 CHECK_NULL_VOID(textFieldManager);
10070 auto nodeId = host->GetId();
10071 auto autoFillContainerNode = firstAutoFillContainerNode_.Upgrade();
10072 CHECK_NULL_VOID(autoFillContainerNode);
10073 auto autoFillContainerNodeId = autoFillContainerNode->GetId();
10074 textFieldManager->RemoveTextFieldInfo(autoFillContainerNodeId, nodeId);
10075 }
10076
10077 void TextFieldPattern::UpdateTextFieldInfo()
10078 {
10079 CHECK_NULL_VOID(IsNeedProcessAutoFill());
10080 auto host = GetHost();
10081 CHECK_NULL_VOID(host);
10082 auto pipeline = host->GetContext();
10083 CHECK_NULL_VOID(pipeline);
10084 auto textFieldManager = DynamicCast<TextFieldManagerNG>(pipeline->GetTextFieldManager());
10085 CHECK_NULL_VOID(textFieldManager);
10086 auto textFieldInfo = GenerateTextFieldInfo();
10087 textFieldManager->UpdateTextFieldInfo(textFieldInfo);
10088 }
10089
10090 bool TextFieldPattern::IsAutoFillUserName(const AceAutoFillType& autoFillType)
10091 {
10092 auto isUserName =
10093 autoFillType == AceAutoFillType::ACE_USER_NAME || autoFillType == AceAutoFillType::ACE_UNSPECIFIED;
10094 return isUserName && HasAutoFillPasswordNode();
10095 }
10096
10097 bool TextFieldPattern::HasAutoFillPasswordNode()
10098 {
10099 auto host = GetHost();
10100 CHECK_NULL_RETURN(host, false);
10101 auto pipeline = host->GetContext();
10102 CHECK_NULL_RETURN(pipeline, false);
10103 auto textFieldManager = DynamicCast<TextFieldManagerNG>(pipeline->GetTextFieldManager());
10104 CHECK_NULL_RETURN(textFieldManager, false);
10105 auto nodeId = host->GetId();
10106 auto autoFillContainerNode = firstAutoFillContainerNode_.Upgrade();
10107 CHECK_NULL_RETURN(autoFillContainerNode, false);
10108 auto autoFillContainerNodeId = autoFillContainerNode->GetId();
10109 return textFieldManager->HasAutoFillPasswordNodeInContainer(autoFillContainerNodeId, nodeId);
10110 }
10111
10112 bool TextFieldPattern::IsTriggerAutoFillPassword()
10113 {
10114 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
10115 CHECK_NULL_RETURN(layoutProperty, false);
10116 auto aceContentType =
10117 TextContentTypeToAceAutoFillType(layoutProperty->GetTextContentTypeValue(TextContentType::UNSPECIFIED));
10118 if (aceContentType != AceAutoFillType::ACE_UNSPECIFIED) {
10119 if (!IsAutoFillPasswordType(aceContentType)) {
10120 return false;
10121 } else {
10122 if (aceContentType == AceAutoFillType::ACE_PASSWORD ||
10123 aceContentType == AceAutoFillType::ACE_NEW_PASSWORD) {
10124 return true;
10125 }
10126 return HasAutoFillPasswordNode();
10127 }
10128 }
10129
10130 auto aceInputType = ConvertToAceAutoFillType(layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED));
10131 if (aceInputType != AceAutoFillType::ACE_UNSPECIFIED) {
10132 if (aceInputType == AceAutoFillType::ACE_PASSWORD || aceInputType == AceAutoFillType::ACE_NEW_PASSWORD) {
10133 return true;
10134 }
10135 }
10136 return HasAutoFillPasswordNode();
10137 }
10138
10139 bool TextFieldPattern::IsNeedProcessAutoFill()
10140 {
10141 return true;
10142 }
10143
10144 std::vector<RectF> TextFieldPattern::GetTextBoxesForSelect()
10145 {
10146 auto selectedRects = GetTextBoxes();
10147 CHECK_NULL_RETURN(paragraph_, selectedRects);
10148 auto paragraphStyle = paragraph_->GetParagraphStyle();
10149 auto textAlign = TextBase::CheckTextAlignByDirection(paragraphStyle.align, paragraphStyle.direction);
10150 const float blankWidth = TextBase::GetSelectedBlankLineWidth();
10151 auto contentWidth = GetTextContentRect().Width();
10152 TextBase::CalculateSelectedRectEx(selectedRects, -1.0f);
10153 for (auto& rect : selectedRects) {
10154 TextBase::UpdateSelectedBlankLineRect(rect, blankWidth, textAlign, contentWidth);
10155 }
10156 return selectedRects;
10157 }
10158
10159 void TextFieldPattern::AdjustSelectedBlankLineWidth(RectF& rect)
10160 {
10161 CHECK_NULL_VOID(paragraph_);
10162 auto paragraphStyle = paragraph_->GetParagraphStyle();
10163 auto textAlign = TextBase::CheckTextAlignByDirection(paragraphStyle.align, paragraphStyle.direction);
10164 const float blankWidth = TextBase::GetSelectedBlankLineWidth();
10165 auto contentWidth = GetTextContentRect().Width();
10166 TextBase::UpdateSelectedBlankLineRect(rect, blankWidth, textAlign, contentWidth);
10167 }
10168
10169 std::optional<TouchLocationInfo> TextFieldPattern::GetAcceptedTouchLocationInfo(const TouchEventInfo& info)
10170 {
10171 auto touchInfos = info.GetChangedTouches();
10172 if (touchInfos.empty()) {
10173 return std::nullopt;
10174 }
10175 if (!moveCaretState_.isMoveCaret && !IsGestureSelectingText()) {
10176 return touchInfos.front();
10177 }
10178 auto fingerId = moveCaretState_.isMoveCaret ? moveCaretState_.touchFingerId : GetSelectingFingerId();
10179 for (auto touchInfo : touchInfos) {
10180 if (touchInfo.GetFingerId() == fingerId) {
10181 return touchInfo;
10182 }
10183 }
10184 return std::nullopt;
10185 }
10186
10187 void TextFieldPattern::DoTextSelectionTouchCancel()
10188 {
10189 CHECK_NULL_VOID(magnifierController_);
10190 magnifierController_->RemoveMagnifierFrameNode();
10191 selectController_->UpdateCaretIndex(selectController_->GetCaretIndex());
10192 StopContentScroll();
10193 StartTwinkling();
10194 }
10195
10196 float TextFieldPattern::GetVerticalPaddingAndBorderSum() const
10197 {
10198 auto border = GetBorderWidthProperty();
10199 if (utilPadding_.has_value()) {
10200 return utilPadding_.value().top.value_or(0.0f) + utilPadding_.value().bottom.value_or(0.0f) +
10201 GetBorderTop(border) + GetBorderBottom(border);
10202 }
10203 auto textFieldTheme = GetTheme();
10204 CHECK_NULL_RETURN(textFieldTheme, 0.0f);
10205 auto themePadding = IsUnderlineMode() ? textFieldTheme->GetUnderlinePadding() : textFieldTheme->GetPadding();
10206 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
10207 CHECK_NULL_RETURN(layoutProperty, themePadding.Top().ConvertToPx() + themePadding.Bottom().ConvertToPx());
10208 const auto& paddingProperty = layoutProperty->GetPaddingProperty();
10209 CHECK_NULL_RETURN(paddingProperty, themePadding.Top().ConvertToPx() + themePadding.Bottom().ConvertToPx());
10210
10211 auto result = static_cast<float>(
10212 paddingProperty->top.value_or(CalcLength(themePadding.Top())).GetDimension().ConvertToPx() +
10213 paddingProperty->bottom.value_or(CalcLength(themePadding.Bottom())).GetDimension().ConvertToPx());
10214 return result + GetBorderTop(border) + GetBorderBottom(border);
10215 }
10216
10217 float TextFieldPattern::GetHorizontalPaddingAndBorderSum() const
10218 {
10219 auto border = GetBorderWidthProperty();
10220 if (utilPadding_.has_value()) {
10221 return utilPadding_.value().left.value_or(0.0f) + utilPadding_.value().right.value_or(0.0f) +
10222 GetBorderLeft(border) + GetBorderRight(border);
10223 }
10224 auto textFieldTheme = GetTheme();
10225 CHECK_NULL_RETURN(textFieldTheme, 0.0f);
10226 auto themePadding = IsUnderlineMode() ? textFieldTheme->GetUnderlinePadding() : textFieldTheme->GetPadding();
10227 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
10228 CHECK_NULL_RETURN(layoutProperty, themePadding.Left().ConvertToPx() + themePadding.Right().ConvertToPx());
10229 const auto& paddingProperty = layoutProperty->GetPaddingProperty();
10230 CHECK_NULL_RETURN(paddingProperty, themePadding.Left().ConvertToPx() + themePadding.Right().ConvertToPx());
10231 auto padding = static_cast<float>(
10232 paddingProperty->left.value_or(CalcLength(themePadding.Left())).GetDimension().ConvertToPx() +
10233 paddingProperty->right.value_or(CalcLength(themePadding.Right())).GetDimension().ConvertToPx());
10234 return padding + GetBorderLeft(border) + GetBorderRight(border);
10235 }
10236
10237 float TextFieldPattern::GetPaddingTop() const
10238 {
10239 if (utilPadding_.has_value()) {
10240 return utilPadding_.value().top.value_or(0.0f);
10241 }
10242 auto textFieldTheme = GetTheme();
10243 CHECK_NULL_RETURN(textFieldTheme, 0.0f);
10244 auto themePadding = IsUnderlineMode() ? textFieldTheme->GetUnderlinePadding() : textFieldTheme->GetPadding();
10245 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
10246 CHECK_NULL_RETURN(layoutProperty, themePadding.Top().ConvertToPx());
10247 const auto& paddingProperty = layoutProperty->GetPaddingProperty();
10248 CHECK_NULL_RETURN(paddingProperty, themePadding.Top().ConvertToPx());
10249 return static_cast<float>(
10250 paddingProperty->top.value_or(CalcLength(themePadding.Top())).GetDimension().ConvertToPx());
10251 }
10252
10253 float TextFieldPattern::GetPaddingBottom() const
10254 {
10255 if (utilPadding_.has_value()) {
10256 return utilPadding_.value().bottom.value_or(0.0f);
10257 }
10258 auto textFieldTheme = GetTheme();
10259 CHECK_NULL_RETURN(textFieldTheme, 0.0f);
10260 auto themePadding = IsUnderlineMode() ? textFieldTheme->GetUnderlinePadding() : textFieldTheme->GetPadding();
10261 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
10262 CHECK_NULL_RETURN(layoutProperty, themePadding.Bottom().ConvertToPx());
10263 const auto& paddingProperty = layoutProperty->GetPaddingProperty();
10264 CHECK_NULL_RETURN(paddingProperty, themePadding.Bottom().ConvertToPx());
10265 return static_cast<float>(
10266 paddingProperty->bottom.value_or(CalcLength(themePadding.Bottom())).GetDimension().ConvertToPx());
10267 }
10268
10269 float TextFieldPattern::GetPaddingLeft() const
10270 {
10271 if (utilPadding_.has_value()) {
10272 return utilPadding_.value().left.value_or(0.0f);
10273 }
10274 auto textFieldTheme = GetTheme();
10275 CHECK_NULL_RETURN(textFieldTheme, 0.0f);
10276 auto themePadding = IsUnderlineMode() ? textFieldTheme->GetUnderlinePadding() : textFieldTheme->GetPadding();
10277 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
10278 CHECK_NULL_RETURN(layoutProperty, themePadding.Left().ConvertToPx());
10279 const auto& paddingProperty = layoutProperty->GetPaddingProperty();
10280 CHECK_NULL_RETURN(paddingProperty, themePadding.Left().ConvertToPx());
10281 return static_cast<float>(
10282 paddingProperty->left.value_or(CalcLength(themePadding.Left())).GetDimension().ConvertToPx());
10283 }
10284
10285 float TextFieldPattern::GetPaddingRight() const
10286 {
10287 if (utilPadding_.has_value()) {
10288 return utilPadding_.value().right.value_or(0.0f);
10289 }
10290 auto textFieldTheme = GetTheme();
10291 CHECK_NULL_RETURN(textFieldTheme, 0.0f);
10292 auto themePadding = IsUnderlineMode() ? textFieldTheme->GetUnderlinePadding() : textFieldTheme->GetPadding();
10293 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
10294 CHECK_NULL_RETURN(layoutProperty, themePadding.Right().ConvertToPx());
10295 const auto& paddingProperty = layoutProperty->GetPaddingProperty();
10296 CHECK_NULL_RETURN(paddingProperty, themePadding.Right().ConvertToPx());
10297 return static_cast<float>(
10298 paddingProperty->right.value_or(CalcLength(themePadding.Right())).GetDimension().ConvertToPx());
10299 }
10300
10301 BorderWidthProperty TextFieldPattern::GetBorderWidthProperty() const
10302 {
10303 BorderWidthProperty currentBorderWidth;
10304 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
10305 CHECK_NULL_RETURN(layoutProperty, currentBorderWidth);
10306 if (layoutProperty->GetBorderWidthProperty() != nullptr) {
10307 currentBorderWidth = *(layoutProperty->GetBorderWidthProperty());
10308 } else {
10309 currentBorderWidth.SetBorderWidth(BORDER_DEFAULT_WIDTH);
10310 }
10311 return currentBorderWidth;
10312 }
10313
10314 float TextFieldPattern::GetBorderLeft(BorderWidthProperty border) const
10315 {
10316 auto leftBorderWidth = border.leftDimen.value_or(Dimension(0.0f));
10317 auto percentReferenceWidth = GetPercentReferenceWidth();
10318 if (leftBorderWidth.Unit() == DimensionUnit::PERCENT && percentReferenceWidth > 0) {
10319 return leftBorderWidth.Value() * percentReferenceWidth;
10320 }
10321 return leftBorderWidth.ConvertToPx();
10322 }
10323
10324 float TextFieldPattern::GetBorderTop(BorderWidthProperty border) const
10325 {
10326 auto topBorderWidth = border.topDimen.value_or(Dimension(0.0f));
10327 auto percentReferenceWidth = GetPercentReferenceWidth();
10328 if (topBorderWidth.Unit() == DimensionUnit::PERCENT && percentReferenceWidth > 0) {
10329 return topBorderWidth.Value() * percentReferenceWidth;
10330 }
10331 return topBorderWidth.ConvertToPx();
10332 }
10333
10334 float TextFieldPattern::GetBorderBottom(BorderWidthProperty border) const
10335 {
10336 auto bottomBorderWidth = border.bottomDimen.value_or(Dimension(0.0f));
10337 auto percentReferenceWidth = GetPercentReferenceWidth();
10338 if (bottomBorderWidth.Unit() == DimensionUnit::PERCENT && percentReferenceWidth > 0) {
10339 return bottomBorderWidth.Value() * percentReferenceWidth;
10340 }
10341 return bottomBorderWidth.ConvertToPx();
10342 }
10343
10344 float TextFieldPattern::GetBorderRight(BorderWidthProperty border) const
10345 {
10346 auto rightBorderWidth = border.rightDimen.value_or(Dimension(0.0f));
10347 auto percentReferenceWidth = GetPercentReferenceWidth();
10348 if (rightBorderWidth.Unit() == DimensionUnit::PERCENT && percentReferenceWidth > 0) {
10349 return rightBorderWidth.Value() * percentReferenceWidth;
10350 }
10351 return rightBorderWidth.ConvertToPx();
10352 }
10353
10354 void TextFieldPattern::ResetFirstClickAfterGetFocus()
10355 {
10356 if (!firstClickAfterLosingFocus_) {
10357 return;
10358 }
10359 auto host = GetHost();
10360 CHECK_NULL_VOID(host);
10361 auto pipeline = host->GetContext();
10362 CHECK_NULL_VOID(pipeline);
10363 auto taskExecutor = pipeline->GetTaskExecutor();
10364 CHECK_NULL_VOID(taskExecutor);
10365 firstClickResetTask_.Cancel();
10366 firstClickResetTask_.Reset([weak = WeakClaim(this)]() {
10367 auto pattern = weak.Upgrade();
10368 CHECK_NULL_VOID(pattern);
10369 pattern->firstClickAfterLosingFocus_ = false;
10370 });
10371 taskExecutor->PostDelayedTask(
10372 firstClickResetTask_, TaskExecutor::TaskType::UI, TWINKLING_INTERVAL_MS, "ResetFirstClickAfterGetFocusTask");
10373 }
10374
10375 SelectionInfo TextFieldPattern::GetSelection()
10376 {
10377 SelectionInfo selection;
10378 selection.SetSelectionStart(selectController_->GetStartIndex());
10379 selection.SetSelectionEnd(selectController_->GetEndIndex());
10380 return selection;
10381 }
10382
10383 FocusPattern TextFieldPattern::GetFocusPattern() const
10384 {
10385 FocusPattern focusPattern = { FocusType::NODE, true, FocusStyleType::FORCE_NONE };
10386 focusPattern.SetIsFocusActiveWhenFocused(true);
10387 auto host = GetHost();
10388 CHECK_NULL_RETURN(host, focusPattern);
10389 auto pipelineContext = host->GetContext();
10390 CHECK_NULL_RETURN(pipelineContext, focusPattern);
10391 auto theme = pipelineContext->GetTheme<TextFieldTheme>();
10392 CHECK_NULL_RETURN(theme, focusPattern);
10393 if (theme->NeedFocusBox()) {
10394 focusPattern.SetStyleType(FocusStyleType::OUTER_BORDER);
10395 }
10396 return focusPattern;
10397 }
10398
10399 bool TextFieldPattern::FireOnWillChange(const ChangeValueInfo& changeValueInfo)
10400 {
10401 auto host = GetHost();
10402 CHECK_NULL_RETURN(host, true);
10403 auto eventHub = host->GetEventHub<TextFieldEventHub>();
10404 CHECK_NULL_RETURN(eventHub, true);
10405 callbackRangeBefore_ = changeValueInfo.rangeBefore;
10406 callbackRangeAfter_ = changeValueInfo.rangeAfter;
10407 callbackOldContent_ = changeValueInfo.oldContent;
10408 callbackOldPreviewText_ = changeValueInfo.oldPreviewText;
10409 return eventHub->FireOnWillChangeEvent(changeValueInfo);
10410 }
10411
10412 bool TextFieldPattern::OnWillChangePreInsert(const std::u16string& insertValue, const std::u16string& oldContent,
10413 uint32_t start, uint32_t end)
10414 {
10415 auto host = GetHost();
10416 CHECK_NULL_RETURN(host, true);
10417 auto eventHub = host->GetEventHub<TextFieldEventHub>();
10418 CHECK_NULL_RETURN(eventHub, true);
10419 ChangeValueInfo changeValueInfo;
10420 PreviewText previewText {.offset = -1, .value = u""};
10421 if (hasPreviewText_) {
10422 previewText.offset = GetPreviewTextStart();
10423 previewText.value = GetPreviewTextValue();
10424 }
10425 changeValueInfo.oldPreviewText = previewText;
10426 changeValueInfo.previewText = previewText;
10427
10428 auto insertLength = insertValue.length();
10429 changeValueInfo.rangeBefore = TextRange { start, end };
10430 changeValueInfo.rangeAfter = TextRange { start, start + insertLength };
10431
10432 changeValueInfo.oldContent = oldContent;
10433 changeValueInfo.value = contentController_->GetTextUtf16Value();
10434 callbackRangeBefore_ = changeValueInfo.rangeBefore;
10435 callbackRangeAfter_ = changeValueInfo.rangeAfter;
10436 callbackOldContent_ = changeValueInfo.oldContent;
10437 callbackOldPreviewText_ = changeValueInfo.oldPreviewText;
10438 return eventHub->FireOnWillChangeEvent(changeValueInfo);
10439 }
10440
10441 bool TextFieldPattern::OnWillChangePreDelete(const std::u16string& oldContent, uint32_t start, uint32_t end)
10442 {
10443 auto host = GetHost();
10444 CHECK_NULL_RETURN(host, true);
10445 auto eventHub = host->GetEventHub<TextFieldEventHub>();
10446 CHECK_NULL_RETURN(eventHub, true);
10447 ChangeValueInfo changeValueInfo;
10448 PreviewText previewText {.offset = -1, .value = u""};
10449 if (hasPreviewText_) {
10450 previewText.offset = GetPreviewTextStart();
10451 previewText.value = GetPreviewTextValue();
10452 }
10453 changeValueInfo.oldPreviewText = previewText;
10454 changeValueInfo.previewText = previewText;
10455
10456 changeValueInfo.rangeBefore = TextRange { start, end };
10457 changeValueInfo.rangeAfter = TextRange { start, start };
10458
10459 changeValueInfo.oldContent = oldContent;
10460 changeValueInfo.value = contentController_->GetTextUtf16Value();
10461 callbackRangeBefore_ = changeValueInfo.rangeBefore;
10462 callbackRangeAfter_ = changeValueInfo.rangeAfter;
10463 callbackOldContent_ = changeValueInfo.oldContent;
10464 callbackOldPreviewText_ = changeValueInfo.oldPreviewText;
10465 return eventHub->FireOnWillChangeEvent(changeValueInfo);
10466 }
10467
10468 bool TextFieldPattern::OnWillChangePreSetValue(const std::u16string& newValue)
10469 {
10470 auto host = GetHost();
10471 CHECK_NULL_RETURN(host, true);
10472 auto eventHub = host->GetEventHub<TextFieldEventHub>();
10473 CHECK_NULL_RETURN(eventHub, true);
10474 ChangeValueInfo changeValueInfo;
10475 changeValueInfo.oldContent = contentController_->GetTextUtf16Value();
10476 changeValueInfo.value = newValue;
10477 changeValueInfo.previewText.offset = hasPreviewText_ ? GetPreviewTextStart() : -1;
10478 changeValueInfo.previewText.value = GetPreviewTextValue();
10479 changeValueInfo.oldPreviewText.offset = hasPreviewText_ ? GetPreviewTextStart() : -1;
10480 changeValueInfo.oldPreviewText.value = GetPreviewTextValue();
10481 changeValueInfo.rangeBefore = TextRange { 0, contentController_->GetTextUtf16Value().length() };
10482 changeValueInfo.rangeAfter = TextRange { 0, newValue.length() };
10483 callbackRangeBefore_ = changeValueInfo.rangeBefore;
10484 callbackRangeAfter_ = changeValueInfo.rangeAfter;
10485 callbackOldContent_ = changeValueInfo.oldContent;
10486 callbackOldPreviewText_ = changeValueInfo.oldPreviewText;
10487 return eventHub->FireOnWillChangeEvent(changeValueInfo);
10488 }
10489
10490 void TextFieldPattern::RecoverTextValueAndCaret(const std::u16string& oldValue, TextRange caretIndex)
10491 {
10492 contentController_->SetTextValueOnly(oldValue);
10493 selectController_->UpdateHandleIndex(caretIndex.start, caretIndex.end);
10494 if (IsSelected()) {
10495 ProcessOverlay({ .menuIsShow = false });
10496 }
10497 }
10498
10499 void TextFieldPattern::AddInsertCommand(const std::u16string& insertValue, InputReason reason)
10500 {
10501 auto host = GetHost();
10502 CHECK_NULL_VOID(host);
10503 if (reason != InputReason::PASTE) {
10504 if (!HasFocus()) {
10505 int32_t frameId = host->GetId();
10506 TAG_LOGW(AceLogTag::ACE_TEXT_FIELD, "textfield %{public}d on blur, can't insert value", frameId);
10507 int32_t depth = host->GetDepth();
10508 std::string errorType = "textfield on blur, can't insert value";
10509 EventReport::ReportTextFieldErrorEvent(frameId, depth, errorType);
10510 auto currentFocusNode = InputMethodManager::GetInstance()->GetCurFocusNode();
10511 auto curFocusNode = currentFocusNode.Upgrade();
10512 CHECK_NULL_VOID(curFocusNode);
10513 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "curFocusNode:%{public}s, ", curFocusNode->GetTag().c_str());
10514 return;
10515 }
10516 if (!isEdit_ || (reason == InputReason::IME && IsDragging())) {
10517 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD,
10518 "textfield %{public}d NOT allow input, isEdit_ = %{public}d, IsDragging = %{public}d", host->GetId(),
10519 isEdit_, IsDragging());
10520 return;
10521 }
10522 }
10523 if (focusIndex_ != FocuseIndex::TEXT) {
10524 if (insertValue == u" ") {
10525 HandleSpaceEvent();
10526 }
10527 return;
10528 }
10529 if (FinishTextPreviewByPreview(insertValue)) {
10530 return;
10531 }
10532 inputOperations_.emplace(InputOperation::INSERT);
10533 InsertCommandInfo info;
10534 info.insertValue = insertValue;
10535 info.reason = reason;
10536 insertCommands_.emplace(info);
10537 CloseSelectOverlay(true);
10538 ScrollToSafeArea();
10539 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
10540 }
10541
10542 void TextFieldPattern::AddInputCommand(const InputCommandInfo& inputCommandInfo)
10543 {
10544 auto host = GetHost();
10545 CHECK_NULL_VOID(host);
10546 inputOperations_.emplace(InputOperation::INPUT);
10547 inputCommands_.emplace(inputCommandInfo);
10548 CloseSelectOverlay(true);
10549 ScrollToSafeArea();
10550 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
10551 }
10552
10553 void TextFieldPattern::ExecuteInputCommand(const InputCommandInfo& info)
10554 {
10555 auto layoutProperty = GetLayoutProperty<TextFieldLayoutProperty>();
10556 CHECK_NULL_VOID(layoutProperty);
10557 auto start = info.deleteRange.start;
10558 auto end = info.deleteRange.end;
10559 auto insertValue = info.insertValue;
10560 auto caretIndex = info.insertOffset;
10561 auto originCaretIndex =
10562 TextRange { selectController_->GetFirstHandleIndex(), selectController_->GetSecondHandleIndex() };
10563 if ((info.reason == InputReason::IME || info.reason == InputReason::AI_WRITE) && !insertValue.empty()) {
10564 auto isInsert = BeforeIMEInsertValue(insertValue, caretIndex - (end - start));
10565 CHECK_NULL_VOID(isInsert);
10566 }
10567
10568 ChangeValueInfo changeValueInfo;
10569 changeValueInfo.oldContent = contentController_->GetTextUtf16Value();
10570 changeValueInfo.oldPreviewText.offset = hasPreviewText_ ? GetPreviewTextStart() : -1;
10571 changeValueInfo.oldPreviewText.value = GetPreviewTextValue();
10572 changeValueInfo.rangeBefore = TextRange { start, end };
10573
10574 auto isDelete = true;
10575 if (start != end) {
10576 auto deleteValue = contentController_->GetSelectedValue(start, end);
10577 if (info.reason == InputReason::IME || info.reason == InputReason::AI_WRITE) {
10578 isDelete = BeforeIMEDeleteValue(deleteValue, TextDeleteDirection::BACKWARD, end);
10579 }
10580 contentController_->erase(start, end - start);
10581 selectController_->UpdateCaretIndex(start);
10582 if ((info.reason == InputReason::IME || info.reason == InputReason::AI_WRITE) && isDelete) {
10583 AfterIMEDeleteValue(deleteValue, TextDeleteDirection::BACKWARD);
10584 }
10585 }
10586
10587 int32_t insertLength = 0;
10588 if (!insertValue.empty()) {
10589 if (info.insertOffset >= end && isDelete) {
10590 caretIndex = caretIndex - (end - start);
10591 }
10592 auto originLength = contentController_->GetTextUtf16Value().length();
10593 auto hasInsertValue = contentController_->InsertValue(caretIndex, info.insertValue);
10594 insertLength = static_cast<int32_t>(contentController_->GetTextUtf16Value().length() - originLength);
10595 caretIndex += insertLength;
10596
10597 if (layoutProperty->HasMaxLength()) {
10598 CalcCounterAfterFilterInsertValue(originLength, insertValue,
10599 static_cast<int32_t>(layoutProperty->GetMaxLengthValue(Infinity<uint32_t>())));
10600 }
10601 selectController_->UpdateCaretIndex(caretIndex);
10602 UpdateObscure(insertValue, hasInsertValue);
10603 if (info.reason == InputReason::IME || info.reason == InputReason::AI_WRITE) {
10604 AfterIMEInsertValue(contentController_->GetInsertValue());
10605 }
10606 }
10607
10608 changeValueInfo.value = contentController_->GetTextUtf16Value();
10609 changeValueInfo.previewText.offset = hasPreviewText_ ? GetPreviewTextStart() : -1;
10610 changeValueInfo.previewText.value = GetPreviewTextValue();
10611 changeValueInfo.rangeAfter = TextRange { caretIndex - insertLength, caretIndex };
10612
10613 bool isWillChange = FireOnWillChange(changeValueInfo);
10614 if (!isWillChange) {
10615 RecoverTextValueAndCaret(changeValueInfo.oldContent, originCaretIndex);
10616 return;
10617 }
10618 UpdateEditingValueToRecord();
10619 TwinklingByFocus();
10620 }
10621
10622 void TextFieldPattern::ClearTextContent()
10623 {
10624 if (GetIsPreviewText()) {
10625 PreviewTextInfo info = {
10626 .text = u"",
10627 .range = {-1, -1}
10628 };
10629 SetPreviewTextOperation(info);
10630 hasPreviewText_ = false;
10631 }
10632 if (contentController_->IsEmpty()) {
10633 return;
10634 }
10635 showCountBorderStyle_ = false;
10636 InputCommandInfo inputCommandInfo;
10637 inputCommandInfo.deleteRange = { 0, contentController_->GetTextUtf16Value().length() };
10638 inputCommandInfo.insertOffset = 0;
10639 inputCommandInfo.insertValue = u"";
10640 inputCommandInfo.reason = InputReason::CANCEL_BUTTON;
10641 AddInputCommand(inputCommandInfo);
10642 }
10643
10644 // return: whether the offset is valid, return false if invalid
10645 bool TextFieldPattern::GetOriginCaretPosition(OffsetF& offset) const
10646 {
10647 if (!originCaretPosition_.NonNegative()) {
10648 return false;
10649 }
10650 offset = originCaretPosition_;
10651 return true;
10652 }
10653
10654 void TextFieldPattern::ResetOriginCaretPosition()
10655 {
10656 originCaretPosition_ = DEFAULT_NEGATIVE_CARET_OFFSET;
10657 }
10658
10659 // Record current caret position if originCaretPosition_ is invalid
10660 // return: whether the current offset is recorded and valid
10661 bool TextFieldPattern::RecordOriginCaretPosition()
10662 {
10663 if (originCaretPosition_.NonNegative()) {
10664 return false;
10665 }
10666 originCaretPosition_ = selectController_->GetCaretRect().GetOffset();
10667 return originCaretPosition_.NonNegative();
10668 }
10669
10670 void TextFieldPattern::SetIsEnableSubWindowMenu()
10671 {
10672 if (selectOverlay_) {
10673 auto enable = !IsNeedProcessAutoFill() || !CheckAutoFill();
10674 selectOverlay_->SetIsHostNodeEnableSubWindowMenu(enable);
10675 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "SetIsEnableSubWindowMenu enable=%{public}d", enable);
10676 }
10677 }
10678
10679 void TextFieldPattern::InitCancelButtonMouseEvent()
10680 {
10681 CHECK_NULL_VOID(cleanNodeResponseArea_);
10682 auto cleanNodeResponseArea = AceType::DynamicCast<CleanNodeResponseArea>(cleanNodeResponseArea_);
10683 CHECK_NULL_VOID(cleanNodeResponseArea);
10684 auto stackNode = cleanNodeResponseArea->GetFrameNode();
10685 CHECK_NULL_VOID(stackNode);
10686 auto imageTouchHub = stackNode->GetOrCreateGestureEventHub();
10687 CHECK_NULL_VOID(imageTouchHub);
10688 auto imageInputHub = stackNode->GetOrCreateInputEventHub();
10689 CHECK_NULL_VOID(imageInputHub);
10690 auto imageHoverTask = [weak = WeakClaim(this),
10691 cleanNodeResponseAreaWeak = WeakPtr<TextInputResponseArea>(cleanNodeResponseArea_)](bool isHover) {
10692 auto cleanNodeResponseArea = cleanNodeResponseAreaWeak.Upgrade();
10693 CHECK_NULL_VOID(cleanNodeResponseArea);
10694 auto pattern = weak.Upgrade();
10695 if (pattern) {
10696 pattern->OnHover(isHover);
10697 pattern->HandleButtonMouseEvent(cleanNodeResponseArea, isHover);
10698 }
10699 };
10700 imageHoverEvent_ = MakeRefPtr<InputEvent>(std::move(imageHoverTask));
10701 imageInputHub->AddOnHoverEvent(imageHoverEvent_);
10702
10703 auto imageTouchTask = [weak = WeakClaim(this), cleanNodeResponseAreaWeak =
10704 WeakPtr<TextInputResponseArea>(cleanNodeResponseArea_)](const TouchEventInfo& info) {
10705 auto cleanNodeResponseArea = cleanNodeResponseAreaWeak.Upgrade();
10706 CHECK_NULL_VOID(cleanNodeResponseArea);
10707 auto pattern = weak.Upgrade();
10708 CHECK_NULL_VOID(pattern);
10709 auto touchType = info.GetTouches().front().GetTouchType();
10710 if (touchType == TouchType::DOWN) {
10711 pattern->HandleCancelButtonTouchDown(cleanNodeResponseArea);
10712 }
10713 if (touchType == TouchType::UP || touchType == TouchType::CANCEL) {
10714 pattern->HandleCancelButtonTouchUp();
10715 }
10716 };
10717
10718 imageTouchEvent_ = MakeRefPtr<TouchEventImpl>(std::move(imageTouchTask));
10719 imageTouchHub->AddTouchEvent(imageTouchEvent_);
10720 }
10721
10722 void TextFieldPattern::InitPasswordButtonMouseEvent()
10723 {
10724 CHECK_NULL_VOID(responseArea_);
10725 auto passwordResponseArea = AceType::DynamicCast<PasswordResponseArea>(responseArea_);
10726 CHECK_NULL_VOID(passwordResponseArea);
10727 auto stackNode = passwordResponseArea->GetFrameNode();
10728 CHECK_NULL_VOID(stackNode);
10729 auto imageTouchHub = stackNode->GetOrCreateGestureEventHub();
10730 CHECK_NULL_VOID(imageTouchHub);
10731 auto imageInputHub = stackNode->GetOrCreateInputEventHub();
10732 CHECK_NULL_VOID(imageInputHub);
10733 auto imageHoverTask =
10734 [weak = WeakClaim(this), responseAreaWeak = WeakPtr<TextInputResponseArea>(responseArea_)](bool isHover) {
10735 auto responseArea = responseAreaWeak.Upgrade();
10736 CHECK_NULL_VOID(responseArea);
10737 auto pattern = weak.Upgrade();
10738 if (pattern) {
10739 pattern->OnHover(isHover);
10740 pattern->HandleButtonMouseEvent(responseArea, isHover);
10741 }
10742 };
10743 imageHoverEvent_ = MakeRefPtr<InputEvent>(std::move(imageHoverTask));
10744 imageInputHub->AddOnHoverEvent(imageHoverEvent_);
10745
10746 auto imageTouchTask = [weak = WeakClaim(this), responseAreaWeak = WeakPtr<TextInputResponseArea>(responseArea_)]
10747 (const TouchEventInfo& info) {
10748 auto responseArea = responseAreaWeak.Upgrade();
10749 CHECK_NULL_VOID(responseArea);
10750 auto pattern = weak.Upgrade();
10751 CHECK_NULL_VOID(pattern);
10752 auto touchType = info.GetTouches().front().GetTouchType();
10753 if (touchType == TouchType::DOWN) {
10754 pattern->HandleCancelButtonTouchDown(responseArea);
10755 }
10756 if (touchType == TouchType::UP || touchType == TouchType::CANCEL) {
10757 pattern->HandleCancelButtonTouchUp();
10758 }
10759 };
10760 imageTouchEvent_ = MakeRefPtr<TouchEventImpl>(std::move(imageTouchTask));
10761 imageTouchHub->AddTouchEvent(imageTouchEvent_);
10762 }
10763
10764 void TextFieldPattern::HandleCancelButtonTouchDown(const RefPtr<TextInputResponseArea>& responseArea)
10765 {
10766 auto host = GetHost();
10767 CHECK_NULL_VOID(host);
10768 RoundRect mouseRect;
10769 CHECK_NULL_VOID(responseArea);
10770 responseArea->CreateIconRect(mouseRect, false);
10771 float cornerRadius = mouseRect.GetRect().Width() / 2;
10772 mouseRect.SetCornerRadius(cornerRadius);
10773 auto textFieldTheme = GetTheme();
10774 CHECK_NULL_VOID(textFieldTheme);
10775 auto touchColor = textFieldTheme->GetPressColor();
10776 std::vector<RoundRect> roundRectVector;
10777 roundRectVector.push_back(mouseRect);
10778 CHECK_NULL_VOID(textFieldOverlayModifier_);
10779 textFieldOverlayModifier_->SetHoverColorAndRects(roundRectVector, touchColor.GetValue());
10780 cancelButtonTouched_ = true;
10781 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
10782 }
10783
10784 void TextFieldPattern::HandleCancelButtonTouchUp()
10785 {
10786 auto host = GetHost();
10787 CHECK_NULL_VOID(host);
10788 CHECK_NULL_VOID(textFieldOverlayModifier_);
10789 textFieldOverlayModifier_->ClearHoverColorAndRects();
10790 cancelButtonTouched_ = false;
10791 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
10792 }
10793
10794 void TextFieldPattern::HandleButtonMouseEvent(const RefPtr<TextInputResponseArea>& responseArea, bool isHover)
10795 {
10796 auto host = GetHost();
10797 CHECK_NULL_VOID(host);
10798 CHECK_NULL_VOID(textFieldOverlayModifier_);
10799 if (isHover) {
10800 RoundRect mouseRect;
10801 CHECK_NULL_VOID(responseArea);
10802 responseArea->CreateIconRect(mouseRect, false);
10803 float cornerRadius = mouseRect.GetRect().Width() / 2;
10804 mouseRect.SetCornerRadius(cornerRadius);
10805 auto textFieldTheme = GetTheme();
10806 CHECK_NULL_VOID(textFieldTheme);
10807 auto touchColor = textFieldTheme->GetHoverColor();
10808 std::vector<RoundRect> roundRectVector;
10809 roundRectVector.push_back(mouseRect);
10810 textFieldOverlayModifier_->SetHoverColorAndRects(roundRectVector, touchColor.GetValue());
10811 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
10812 } else {
10813 textFieldOverlayModifier_->ClearHoverColorAndRects();
10814 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
10815 }
10816 }
10817
10818 double TextFieldPattern::GetPercentReferenceWidth() const
10819 {
10820 auto host = GetHost();
10821 if (host && host->GetGeometryNode() && host->GetGeometryNode()->GetParentLayoutConstraint().has_value()) {
10822 return host->GetGeometryNode()->GetParentLayoutConstraint()->percentReference.Width();
10823 }
10824 return 0.0f;
10825 }
10826
10827 void TextFieldPattern::NotifyKeyboardClosedByUser()
10828 {
10829 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "NotifyKeyboardClosedByUser");
10830 isKeyboardClosedByUser_ = true;
10831 FocusHub::LostFocusToViewRoot();
10832 isKeyboardClosedByUser_ = false;
10833 }
10834
10835 void TextFieldPattern::NotifyKeyboardClosed()
10836 {
10837 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "NotifyKeyboardClosed");
10838 CHECK_NULL_VOID(IsStopEditWhenCloseKeyboard()); // false when specified product
10839 if (HasFocus() && !(customKeyboard_ || customKeyboardBuilder_)) {
10840 FocusHub::LostFocusToViewRoot();
10841 }
10842 }
10843
10844 void TextFieldPattern::AddDragFrameNodeToManager(const RefPtr<FrameNode>& frameNode)
10845 {
10846 auto context = PipelineContext::GetCurrentContextSafelyWithCheck();
10847 CHECK_NULL_VOID(context);
10848 auto dragDropManager = context->GetDragDropManager();
10849 CHECK_NULL_VOID(dragDropManager);
10850 dragDropManager->AddDragFrameNode(frameNode->GetId(), AceType::WeakClaim(AceType::RawPtr(frameNode)));
10851 }
10852
10853 void TextFieldPattern::RemoveDragFrameNodeFromManager(const RefPtr<FrameNode>& frameNode)
10854 {
10855 auto context = PipelineContext::GetCurrentContextSafelyWithCheck();
10856 CHECK_NULL_VOID(context);
10857 auto dragDropManager = context->GetDragDropManager();
10858 CHECK_NULL_VOID(dragDropManager);
10859 dragDropManager->RemoveDragFrameNode(frameNode->GetId());
10860 }
10861
10862 bool TextFieldPattern::BetweenSelectedPosition(const Offset& globalOffset)
10863 {
10864 if (!IsSelected()) {
10865 return false;
10866 }
10867 auto localOffset = ConvertGlobalToLocalOffset(globalOffset);
10868 auto offsetX = IsTextArea() ? contentRect_.GetX() : textRect_.GetX();
10869 auto offsetY = IsTextArea() ? textRect_.GetY() : contentRect_.GetY();
10870 Offset offset = localOffset - Offset(offsetX, offsetY);
10871 for (const auto& rect : selectController_->GetSelectedRects()) {
10872 bool isInRange = rect.IsInRegion({ offset.GetX(), offset.GetY() });
10873 if (isInRange) {
10874 return true;
10875 }
10876 }
10877 return false;
10878 }
10879
10880 void TextFieldPattern::SetUnitNode(const RefPtr<NG::UINode>& unitNode)
10881 {
10882 if (unitNode_ && responseArea_) {
10883 // clear old node
10884 auto unitResponseArea = AceType::DynamicCast<UnitResponseArea>(responseArea_);
10885 CHECK_NULL_VOID(unitResponseArea);
10886 unitResponseArea->ClearArea();
10887 responseArea_ = nullptr;
10888 }
10889 unitNode_ = unitNode;
10890 }
10891
10892 void TextFieldPattern::SetCustomKeyboard(const std::function<void()>&& keyboardBuilder)
10893 {
10894 if (customKeyboardBuilder_ && isCustomKeyboardAttached_ && !keyboardBuilder) {
10895 // close customKeyboard and request system keyboard
10896 CloseCustomKeyboard();
10897 customKeyboardBuilder_ = keyboardBuilder; // refresh current keyboard
10898 RequestKeyboardNotByFocusSwitch(RequestKeyboardReason::CUSTOM_KEYBOARD);
10899 StartTwinkling();
10900 return;
10901 }
10902 if (!customKeyboardBuilder_ && keyboardBuilder) {
10903 // close system keyboard and request custom keyboard
10904 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
10905 if (imeShown_) {
10906 CloseKeyboard(true);
10907 customKeyboardBuilder_ = keyboardBuilder; // refresh current keyboard
10908 RequestKeyboardNotByFocusSwitch(RequestKeyboardReason::CUSTOM_KEYBOARD);
10909 StartTwinkling();
10910 return;
10911 }
10912 #endif
10913 }
10914 customKeyboardBuilder_ = keyboardBuilder;
10915 }
10916
10917 void TextFieldPattern::SetCustomKeyboardWithNode(const RefPtr<UINode>& keyboardBuilder)
10918 {
10919 if (customKeyboard_ && isCustomKeyboardAttached_ && !keyboardBuilder) {
10920 // close customKeyboard and request system keyboard
10921 CloseCustomKeyboard();
10922 customKeyboard_ = keyboardBuilder; // refresh current keyboard
10923 RequestKeyboardNotByFocusSwitch(RequestKeyboardReason::CUSTOM_KEYBOARD);
10924 StartTwinkling();
10925 return;
10926 }
10927 if (!customKeyboard_ && keyboardBuilder) {
10928 // close system keyboard and request custom keyboard
10929 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
10930 if (imeShown_) {
10931 CloseKeyboard(true);
10932 customKeyboard_ = keyboardBuilder; // refresh current keyboard
10933 RequestKeyboardNotByFocusSwitch(RequestKeyboardReason::CUSTOM_KEYBOARD);
10934 StartTwinkling();
10935 return;
10936 }
10937 #endif
10938 }
10939 customKeyboard_ = keyboardBuilder;
10940 }
10941
10942 bool TextFieldPattern::IsStopEditWhenCloseKeyboard()
10943 {
10944 auto host = GetHost();
10945 CHECK_NULL_RETURN(host, true);
10946 auto context = host->GetContext();
10947 CHECK_NULL_RETURN(context, true);
10948 return !(context->GetIsFocusActive() && independentControlKeyboard_);
10949 }
10950
10951 } // namespace OHOS::Ace::NG
10952