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