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