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