1 /*
2 * Copyright (c) 2021 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/text_field/render_text_field.h"
17
18 #include "base/i18n/localization.h"
19 #include "base/json/json_util.h"
20 #include "base/utils/string_utils.h"
21 #include "core/animation/curve_animation.h"
22 #include "core/common/clipboard/clipboard_proxy.h"
23 #include "core/common/font_manager.h"
24 #include "core/components/stack/stack_element.h"
25 #include "core/components/text/text_utils.h"
26 #include "core/components/text_overlay/text_overlay_component.h"
27 #include "core/components/text_overlay/text_overlay_element.h"
28 #include "core/event/ace_event_helper.h"
29
30 #if defined(ENABLE_STANDARD_INPUT)
31 #include "core/components/text_field/on_text_changed_listener_impl.h"
32 #endif
33
34 namespace OHOS::Ace {
35 namespace {
36
37 constexpr uint32_t TWINKLING_INTERVAL_MS = 500;
38 // Tick count indicate how long should the naked character should be displayed while obscure_ == true.
39 constexpr uint32_t OBSCURE_SHOW_TICKS = 3;
40 constexpr double HANDLE_HOT_ZONE = 10.0;
41
42 constexpr char16_t OBSCURING_CHARACTER = u'•';
43 constexpr char16_t OBSCURING_CHARACTER_FOR_AR = u'*';
44
45 constexpr int32_t DEFAULT_SELECT_INDEX = 0;
46 constexpr int32_t SHOW_HANDLE_DURATION = 250;
47 constexpr int32_t DOUBLE_CLICK_FINGERS = 1;
48 constexpr int32_t DOUBLE_CLICK_COUNTS = 2;
49 constexpr double FIFTY_PERCENT = 0.5;
50
51 constexpr Dimension OFFSET_FOCUS = 4.0_vp;
52 constexpr Dimension DEFLATE_RADIUS_FOCUS = 3.0_vp;
53
54 } // namespace
55
56 #if defined(ENABLE_STANDARD_INPUT)
UpdateConfiguration()57 void RenderTextField::UpdateConfiguration()
58 {
59 MiscServices::Configuration configuration;
60 configuration.SetEnterKeyType(static_cast<MiscServices::EnterKeyType>((int32_t)action_));
61 configuration.SetTextInputType(static_cast<MiscServices::TextInputType>((int32_t)keyboard_));
62 MiscServices::InputMethodController::GetInstance()->OnConfigurationChange(configuration);
63 }
64 #endif
65
RenderTextField()66 RenderTextField::RenderTextField()
67 : twinklingInterval(TWINKLING_INTERVAL_MS), controller_(AceType::MakeRefPtr<TextEditController>())
68 {}
69
~RenderTextField()70 RenderTextField::~RenderTextField()
71 {
72 LOGI("Destruction text field.");
73 if (controller_) {
74 controller_->Clear();
75 controller_->RemoveObserver(WeakClaim(this));
76 }
77 auto pipelineContext = context_.Upgrade();
78 if (!pipelineContext) {
79 return;
80 }
81 PopTextOverlay();
82 pipelineContext->RemoveFontNode(AceType::WeakClaim(this));
83 auto fontManager = pipelineContext->GetFontManager();
84 if (fontManager) {
85 fontManager->UnRegisterCallback(AceType::WeakClaim(this));
86 fontManager->RemoveVariationNode(WeakClaim(this));
87 }
88
89 // If soft keyboard is still exist, close it.
90 if (HasConnection()) {
91 #if defined(ENABLE_STANDARD_INPUT)
92 LOGI("Destruction text field, close input method.");
93 MiscServices::InputMethodController::GetInstance()->Close();
94 #else
95 connection_->Close(GetInstanceId());
96 connection_ = nullptr;
97 #endif
98 }
99 }
100
Update(const RefPtr<Component> & component)101 void RenderTextField::Update(const RefPtr<Component>& component)
102 {
103 const RefPtr<TextFieldComponent> textField = AceType::DynamicCast<TextFieldComponent>(component);
104 if (!textField) {
105 return;
106 }
107
108 // Clear children to avoid children increase.
109 ClearChildren();
110
111 if (textField->IsTextLengthLimited()) {
112 maxLength_ = textField->GetMaxLength();
113 }
114
115 selection_ = textField->GetSelection();
116 placeholder_ = textField->GetPlaceholder();
117 inputFilter_ = textField->GetInputFilter();
118 inactivePlaceholderColor_ = textField->GetPlaceholderColor();
119 focusPlaceholderColor_ = textField->GetFocusPlaceholderColor();
120 focusBgColor_ = textField->GetFocusBgColor();
121 focusTextColor_ = textField->GetFocusTextColor();
122 selectedColor_ = textField->GetSelectedColor();
123 pressColor_ = textField->GetPressColor();
124 decoration_ = textField->GetDecoration();
125 inactiveBgColor_ = textField->GetBgColor();
126 if (decoration_ && (decoration_->GetImage() || decoration_->GetGradient().IsValid())) {
127 inactiveBgColor_ = Color::TRANSPARENT;
128 focusBgColor_ = Color::TRANSPARENT;
129 }
130 originBorder_ = textField->GetOriginBorder();
131 style_ = textField->GetTextStyle();
132 placeHoldStyle_ = textField->GetPlaceHoldStyle();
133 editingStyle_ = textField->GetEditingStyle();
134 fontSize_ = style_.GetFontSize();
135 errorTextStyle_ = textField->GetErrorTextStyle();
136 errorSpacingInDimension_ = textField->GetErrorSpacing();
137 errorIsInner_ = textField->GetErrorIsInner();
138 errorBorderWidth_ = textField->GetErrorBorderWidth();
139 errorBorderColor_ = textField->GetErrorBorderColor();
140 needFade_ = textField->NeedFade();
141 inactiveTextColor_ = style_.GetTextColor();
142 maxLines_ = textField->GetTextMaxLines();
143 onTextChangeEvent_ = AceAsyncEvent<void(const std::string&)>::Create(textField->GetOnTextChange(), context_);
144 onError_ = textField->GetOnError();
145 onValueChangeEvent_ = textField->GetOnTextChange().GetUiStrFunction();
146 if (textField->GetOnChange()) {
147 onChange_ = *textField->GetOnChange();
148 }
149 if (textField->GetOnEditChanged()) {
150 onEditChanged_ = *textField->GetOnEditChanged();
151 }
152 if (textField->GetOnSubmit()) {
153 onSubmit_ = *textField->GetOnSubmit();
154 }
155 if (textField->GetOnClick()) {
156 onClick_ = *textField->GetOnClick();
157 }
158 onSelectChangeEvent_ = AceAsyncEvent<void(const std::string&)>::Create(textField->GetOnSelectChange(), context_);
159 onFinishInputEvent_ = AceAsyncEvent<void(const std::string&)>::Create(textField->GetOnFinishInput(), context_);
160 onTapEvent_ = AceAsyncEvent<void()>::Create(textField->GetOnTap(), context_);
161 catchMode_ = textField->GetOnTap().IsEmpty() || textField->GetOnTap().GetCatchMode();
162 static const int32_t bubbleModeVersion = 6;
163 auto pipeline = context_.Upgrade();
164 if (!catchMode_) {
165 if (pipeline && pipeline->GetMinPlatformVersion() >= bubbleModeVersion) {
166 catchMode_ = false;
167 } else {
168 catchMode_ = true;
169 }
170 }
171 onLongPressEvent_ = AceAsyncEvent<void()>::Create(textField->GetOnLongPress(), context_);
172 textAlign_ = textField->GetTextAlign();
173 textDirection_ = textField->GetTextDirection();
174 realTextDirection_ = textDirection_;
175 showCursor_ = textField->ShowCursor();
176 UpdateObscure(textField);
177 enabled_ = textField->IsEnabled();
178 widthReserved_ = textField->GetWidthReserved();
179 blockRightShade_ = textField->GetBlockRightShade();
180 isVisible_ = textField->IsVisible();
181 showPasswordIcon_ = textField->ShowPasswordIcon();
182 if (textField->HasSetResetToStart() && textField->GetUpdateType() == UpdateType::ALL) {
183 resetToStart_ = textField->GetResetToStart();
184 }
185 if (keyboard_ != textField->GetTextInputType()) {
186 auto context = context_.Upgrade();
187 if (context && context->GetIsDeclarative()) {
188 ClearEditingValue();
189 } else {
190 if (keyboard_ == TextInputType::VISIBLE_PASSWORD) {
191 ClearEditingValue();
192 }
193 }
194 keyboard_ = textField->GetTextInputType();
195 CloseKeyboard();
196 }
197
198 if (action_ != textField->GetAction()) {
199 auto context = context_.Upgrade();
200 if (context && context->GetIsDeclarative()) {
201 CloseKeyboard();
202 action_ = textField->GetAction();
203 } else {
204 action_ = textField->GetAction();
205 }
206 }
207
208 actionLabel_ = textField->GetActionLabel();
209 height_ = textField->GetHeight();
210 if (textField->IsCursorColorSet()) {
211 cursorColorIsSet_ = true;
212 cursorColor_ = textField->GetCursorColor();
213 }
214 cursorRadius_ = textField->GetCursorRadius();
215 textFieldController_ = textField->GetTextFieldController();
216 if (textFieldController_) {
217 auto weak = AceType::WeakClaim(this);
218 textFieldController_->SetCaretPosition([weak](int32_t caretPosition) {
219 auto textField = weak.Upgrade();
220 if (textField) {
221 textField->UpdateSelection(caretPosition);
222 textField->cursorPositionType_ = CursorPositionType::NORMAL;
223 textField->MarkNeedLayout();
224 }
225 });
226 }
227 if (textField->GetTextEditController() && controller_ != textField->GetTextEditController()) {
228 if (controller_) {
229 controller_->RemoveObserver(WeakClaim(this));
230 }
231 controller_ = textField->GetTextEditController();
232 }
233 if (controller_) {
234 controller_->RemoveObserver(WeakClaim(this));
235 controller_->AddObserver(WeakClaim(this));
236 controller_->SetHint(placeholder_);
237 if (textField->IsValueUpdated()) {
238 controller_->SetText(textField->GetValue(), false);
239 }
240 }
241 ApplyRestoreInfo();
242 extend_ = textField->IsExtend();
243 softKeyboardEnabled_ = textField->IsSoftKeyboardEnabled();
244 text_ = textField->GetValue();
245 showEllipsis_ = textField->ShowEllipsis();
246 auto context = context_.Upgrade();
247 if (!clipboard_ && context) {
248 clipboard_ = ClipboardProxy::GetInstance()->GetClipboard(context->GetTaskExecutor());
249 }
250
251 if ((style_.IsAllowScale() || style_.GetFontSize().Unit() == DimensionUnit::FP) && context) {
252 context->AddFontNode(AceType::WeakClaim(this));
253 }
254
255 showCounter_ = textField->ShowCounter();
256 countTextStyle_ = textField->GetCountTextStyle();
257 overCountStyle_ = textField->GetOverCountStyle();
258 countTextStyleOuter_ = textField->GetCountTextStyleOuter();
259 overCountStyleOuter_ = textField->GetOverCountStyleOuter();
260
261 inputOptions_ = textField->GetInputOptions();
262 onOptionsClick_ = textField->GetOnOptionsClick();
263 onTranslate_ = textField->GetOnTranslate();
264 onShare_ = textField->GetOnShare();
265 onSearch_ = textField->GetOnSearch();
266
267 #if defined(ENABLE_STANDARD_INPUT)
268 UpdateConfiguration();
269 #endif
270 SetCallback(textField);
271 UpdateFormatters();
272 UpdateFocusStyles();
273 UpdateIcon(textField);
274 RegisterFontCallbacks();
275 MarkNeedLayout();
276 UpdateAccessibilityAttr();
277 }
278
SetCallback(const RefPtr<TextFieldComponent> & textField)279 void RenderTextField::SetCallback(const RefPtr<TextFieldComponent>& textField)
280 {
281 if (textField->GetOnCopy()) {
282 onCopy_ = *textField->GetOnCopy();
283 }
284 if (textField->GetOnCut()) {
285 onCut_ = *textField->GetOnCut();
286 }
287 if (textField->GetOnPaste()) {
288 onPaste_ = *textField->GetOnPaste();
289 }
290 }
291
OnPaintFinish()292 void RenderTextField::OnPaintFinish()
293 {
294 UpdateFocusAnimation();
295 UpdateOverlay();
296 InitAccessibilityEventListener();
297 UpdateAccessibilityPosition();
298 }
299
PerformLayout()300 void RenderTextField::PerformLayout()
301 {
302 if (!lastLayoutParam_.has_value()) {
303 lastLayoutParam_ = std::make_optional(GetLayoutParam());
304 }
305
306 if (GetEditingValue().text.empty()) {
307 cursorPositionType_ = CursorPositionType::END;
308 }
309
310 auto context = context_.Upgrade();
311 if (context && context->GetIsDeclarative()) {
312 const auto& currentText = controller_->GetValue().text;
313 showPlaceholder_ = currentText.empty();
314 if (showPlaceholder_) {
315 SetTextStyle(placeHoldStyle_);
316 } else {
317 SetTextStyle(editingStyle_);
318 }
319 }
320
321 auto pipelineContext = GetContext().Upgrade();
322 if ((style_.IsAllowScale() || style_.GetFontSize().Unit() == DimensionUnit::FP) && pipelineContext &&
323 !NearEqual(fontScale_, pipelineContext->GetFontScale())) {
324 fontScale_ = pipelineContext->GetFontScale();
325 style_.SetFontSize(fontSize_ * fontScale_);
326 }
327
328 iconSize_ = NormalizeToPx(iconSizeInDimension_);
329 iconHotZoneSize_ = NormalizeToPx(iconHotZoneSizeInDimension_);
330 errorSpacing_ = NormalizeToPx(errorSpacingInDimension_);
331 if (!GetChildren().empty()) {
332 auto innerLayout = GetLayoutParam();
333 innerLayout.SetMinSize(Size());
334 const auto& child = GetChildren().front();
335 child->Layout(innerLayout);
336 }
337 SetLayoutSize(GetLayoutParam().Constrain(Measure()));
338 UpdateFocusAnimation();
339
340 LayoutParam layoutParam = GetLayoutParam();
341 layoutParam.SetMinSize(Size());
342 if (iconImage_) {
343 iconImage_->Layout(layoutParam);
344 }
345 if (renderShowIcon_) {
346 renderShowIcon_->Layout(layoutParam);
347 }
348 if (renderHideIcon_) {
349 renderHideIcon_->Layout(layoutParam);
350 }
351 if (needNotifyChangeEvent_ && (onTextChangeEvent_ || onValueChangeEvent_ || onChange_)) {
352 needNotifyChangeEvent_ = false;
353 if (onChange_) {
354 onChange_(GetEditingValue().text);
355 }
356 if (onValueChangeEvent_) {
357 onValueChangeEvent_(GetEditingValue().text);
358 }
359 if (onTextChangeEvent_) {
360 auto jsonResult = JsonUtil::Create(true);
361 jsonResult->Put("text", GetEditingValue().text.c_str());
362 jsonResult->Put("value", GetEditingValue().text.c_str());
363 jsonResult->Put("lines", textLines_);
364 jsonResult->Put("height", textHeight_);
365 onTextChangeEvent_(std::string(R"("change",)").append(jsonResult->ToString()));
366 }
367 }
368
369 HandleDeviceOrientationChange();
370 }
371
HandleMouseEvent(const MouseEvent & event)372 bool RenderTextField::HandleMouseEvent(const MouseEvent& event)
373 {
374 if (event.button == MouseButton::LEFT_BUTTON) {
375 if (event.action == MouseAction::PRESS) {
376 UpdateStartSelection(DEFAULT_SELECT_INDEX, event.GetOffset(), true, false);
377 } else if (event.action == MouseAction::MOVE) {
378 int32_t start = GetEditingValue().selection.baseOffset;
379 int32_t end = GetCursorPositionForClick(event.GetOffset());
380 UpdateSelection(start, end);
381 StopTwinkling();
382 MarkNeedRender();
383 } else {
384 LOGD("on left button release");
385 }
386 }
387
388 if (event.button == MouseButton::RIGHT_BUTTON && event.action == MouseAction::PRESS) {
389 Offset rightClickOffset = event.GetOffset();
390 ShowTextOverlay(rightClickOffset, false);
391 }
392
393 return true;
394 }
395
OnTouchTestHit(const Offset & coordinateOffset,const TouchRestrict & touchRestrict,TouchTestResult & result)396 void RenderTextField::OnTouchTestHit(
397 const Offset& coordinateOffset, const TouchRestrict& touchRestrict, TouchTestResult& result)
398 {
399 if (!enabled_) {
400 return;
401 }
402 if (!clickRecognizer_) {
403 clickRecognizer_ = AceType::MakeRefPtr<ClickRecognizer>();
404 clickRecognizer_->SetUseCatchMode(catchMode_);
405 auto weak = WeakClaim(this);
406 clickRecognizer_->SetOnClick([weak](const ClickInfo& info) {
407 auto client = weak.Upgrade();
408 if (client) {
409 client->OnClick(info);
410 }
411 });
412 clickRecognizer_->SetPriority(GesturePriority::Low);
413 }
414 clickRecognizer_->SetCoordinateOffset(coordinateOffset);
415 result.emplace_back(clickRecognizer_);
416
417 if (!doubleClickRecognizer_) {
418 doubleClickRecognizer_ =
419 AceType::MakeRefPtr<ClickRecognizer>(context_, DOUBLE_CLICK_FINGERS, DOUBLE_CLICK_COUNTS);
420 doubleClickRecognizer_->SetUseCatchMode(catchMode_);
421 auto weak = WeakClaim(this);
422 doubleClickRecognizer_->SetOnClick([weak](const ClickInfo& info) {
423 auto client = weak.Upgrade();
424 if (client) {
425 client->OnDoubleClick(info);
426 }
427 });
428 doubleClickRecognizer_->SetPriority(GesturePriority::High);
429 }
430 doubleClickRecognizer_->SetCoordinateOffset(coordinateOffset);
431 result.emplace_back(doubleClickRecognizer_);
432
433 if (!longPressRecognizer_) {
434 longPressRecognizer_ = AceType::MakeRefPtr<LongPressRecognizer>(context_);
435 auto weak = WeakClaim(this);
436 longPressRecognizer_->SetOnLongPress([weak = WeakClaim(this)](const LongPressInfo& info) {
437 auto client = weak.Upgrade();
438 if (client) {
439 client->OnLongPress(info);
440 }
441 });
442 longPressRecognizer_->SetPriority(GesturePriority::High);
443 }
444 longPressRecognizer_->SetCoordinateOffset(coordinateOffset);
445 longPressRecognizer_->SetTouchRestrict(touchRestrict);
446 result.emplace_back(longPressRecognizer_);
447
448 if (!rawRecognizer_) {
449 rawRecognizer_ = AceType::MakeRefPtr<RawRecognizer>();
450 auto weak = WeakClaim(this);
451 rawRecognizer_->SetOnTouchDown([weak = WeakClaim(this)](const TouchEventInfo& info) {
452 auto textField = weak.Upgrade();
453 if (textField) {
454 textField->StartPressAnimation(true);
455 }
456 });
457
458 rawRecognizer_->SetOnTouchUp([weak = WeakClaim(this)](const TouchEventInfo& info) {
459 auto textField = weak.Upgrade();
460 if (textField) {
461 textField->StartPressAnimation(false);
462 }
463 });
464
465 rawRecognizer_->SetOnTouchCancel([weak = WeakClaim(this)](const TouchEventInfo& info) {
466 auto textField = weak.Upgrade();
467 if (textField) {
468 textField->StartPressAnimation(false);
469 }
470 });
471 }
472 rawRecognizer_->SetTouchRestrict(touchRestrict);
473 rawRecognizer_->SetCoordinateOffset(coordinateOffset);
474 result.emplace_back(rawRecognizer_);
475 }
476
StartPressAnimation(bool pressDown)477 void RenderTextField::StartPressAnimation(bool pressDown)
478 {
479 if (!pressController_) {
480 pressController_ = AceType::MakeRefPtr<Animator>(context_);
481 }
482 if (pressController_->IsRunning()) {
483 pressController_->Stop();
484 }
485 pressController_->ClearInterpolators();
486 RefPtr<KeyframeAnimation<Color>> animation = AceType::MakeRefPtr<KeyframeAnimation<Color>>();
487 if (pressDown) {
488 CreateMouseAnimation(animation, GetEventEffectColor(), pressColor_);
489 } else {
490 CreateMouseAnimation(animation, GetEventEffectColor(), Color::TRANSPARENT);
491 }
492 pressController_->AddInterpolator(animation);
493 pressController_->SetDuration(PRESS_DURATION);
494 pressController_->SetFillMode(FillMode::FORWARDS);
495 pressController_->Forward();
496 }
497
OnClick(const ClickInfo & clickInfo)498 void RenderTextField::OnClick(const ClickInfo& clickInfo)
499 {
500 // Handle click on password icon when password icon is valid, switch between show and hide icon.
501 Point clickPoint = Point(clickInfo.GetLocalLocation().GetX(), clickInfo.GetLocalLocation().GetY());
502 if (showPasswordIcon_ && passwordIconRect_.IsInRegion(clickPoint)) {
503 obscure_ = !obscure_;
504 passwordRecord_ = obscure_;
505 PopTextOverlay();
506 MarkNeedLayout();
507 return;
508 }
509
510 isValueFromRemote_ = false;
511 auto globalPosition = clickInfo.GetGlobalLocation();
512 auto globalOffset = GetGlobalOffset();
513
514 if (SearchAction(globalPosition, globalOffset)) {
515 return;
516 }
517 if (tapCallback_) {
518 if (!tapCallback_()) {
519 return;
520 }
521 }
522 if (onTapEvent_) {
523 onTapEvent_();
524 }
525 if (onClick_) {
526 onClick_(clickInfo);
527 }
528 CursorMoveOnClick(globalPosition);
529 ShowError("", false);
530 UpdateStartSelection(DEFAULT_SELECT_INDEX, globalPosition, true, false);
531 if (clickInfo.GetSourceDevice() == SourceType::MOUSE) {
532 StartTwinkling();
533 } else {
534 StartTwinkling();
535 ShowTextOverlay(globalPosition, true);
536 }
537 auto context = GetContext().Upgrade();
538 if (context) {
539 context->SetClickPosition(GetGlobalOffset() + Size(0, GetLayoutSize().Height()));
540 }
541 }
542
SearchAction(const Offset & globalPosition,const Offset & globalOffset)543 bool RenderTextField::SearchAction(const Offset& globalPosition, const Offset& globalOffset)
544 {
545 double widthReserved = NormalizeToPx(widthReserved_);
546 if (widthReserved > 0) {
547 if (textDirection_ == TextDirection::RTL) {
548 if ((globalPosition.GetX() - globalOffset.GetX()) < widthReserved) {
549 controller_->SetText("");
550 return true;
551 } else if ((globalPosition.GetX() - globalOffset.GetX()) > (GetLayoutSize().Width() - iconHotZoneSize_) &&
552 iconImage_ && action_ == TextInputAction::SEARCH) {
553 PerformAction(action_, true);
554 return true;
555 }
556 } else {
557 if ((globalPosition.GetX() - globalOffset.GetX()) >= (GetLayoutSize().Width() - widthReserved)) {
558 controller_->SetText("");
559 return true;
560 } else if ((globalPosition.GetX() - globalOffset.GetX()) < iconHotZoneSize_ && iconImage_ &&
561 action_ == TextInputAction::SEARCH) {
562 PerformAction(action_, true);
563 return true;
564 }
565 }
566 }
567 return false;
568 }
569
OnDoubleClick(const ClickInfo & clickInfo)570 void RenderTextField::OnDoubleClick(const ClickInfo& clickInfo)
571 {
572 auto clickPosition = GetCursorPositionForClick(clickInfo.GetGlobalLocation());
573 auto selection = TextUtils::GetRangeOfSameType(GetEditingValue().text, clickPosition - 1);
574 UpdateSelection(selection.GetStart(), selection.GetEnd());
575 LOGI("text field accept double click, position: %{public}d, selection: %{public}s", clickPosition,
576 selection.ToString().c_str());
577 MarkNeedRender();
578 }
579
OnLongPress(const LongPressInfo & longPressInfo)580 void RenderTextField::OnLongPress(const LongPressInfo& longPressInfo)
581 {
582 if (tapCallback_ && !isOverlayShowed_) {
583 if (!tapCallback_()) {
584 return;
585 }
586 }
587
588 if (onLongPressEvent_) {
589 onLongPressEvent_();
590 }
591
592 ShowError("", false);
593
594 if (longPressInfo.GetSourceDevice() == SourceType::MOUSE) {
595 return;
596 }
597
598 Offset longPressPosition = longPressInfo.GetGlobalLocation();
599 bool isTextEnd =
600 (static_cast<size_t>(GetCursorPositionForClick(longPressPosition)) == GetEditingValue().GetWideText().length());
601 bool singleHandle = isTextEnd || GetEditingValue().text.empty();
602 bool isPassword = (keyboard_ == TextInputType::VISIBLE_PASSWORD);
603 UpdateStartSelection(DEFAULT_SELECT_INDEX, longPressPosition, singleHandle || isPassword, true);
604 ShowTextOverlay(longPressPosition, false);
605 }
606
ShowTextOverlay(const Offset & showOffset,bool isSingleHandle)607 void RenderTextField::ShowTextOverlay(const Offset& showOffset, bool isSingleHandle)
608 {
609 if (!isVisible_) {
610 return;
611 }
612
613 if (!IsSelectiveDevice()) {
614 StartTwinkling();
615 return;
616 }
617
618 isSingleHandle_ = isSingleHandle;
619
620 auto selStart = GetEditingValue().selection.GetStart();
621 auto selEnd = GetEditingValue().selection.GetEnd();
622
623 Offset startHandleOffset = GetHandleOffset(selStart);
624 Offset endHandleOffset = isSingleHandle ? startHandleOffset : GetHandleOffset(selEnd);
625
626 if (isOverlayShowed_ && updateHandlePosition_) {
627 Rect caretStart;
628 bool visible = GetCaretRect(selStart, caretStart) ? IsVisible(caretStart + textOffsetForShowCaret_) : false;
629 OverlayShowOption option { .showMenu = isOverlayShowed_,
630 .showStartHandle = visible,
631 .showEndHandle = visible,
632 .isSingleHandle = isSingleHandle,
633 .updateOverlayType = isSingleHandle ? UpdateOverlayType::CLICK : UpdateOverlayType::LONG_PRESS,
634 .startHandleOffset = startHandleOffset,
635 .endHandleOffset = endHandleOffset };
636 if (!isSingleHandle_ || startHandleOffset != endHandleOffset) {
637 isOverlayFocus_ = true;
638 }
639 updateHandlePosition_(option);
640
641 // When the textOverlay is showed, restart the animation
642 if (!animator_) {
643 LOGE("Show textOverlay error, animator is nullptr");
644 return;
645 }
646 if (!animator_->IsStopped()) {
647 animator_->Stop();
648 }
649 animator_->Play();
650 return;
651 }
652
653 // Pop text overlay before push.
654 PopTextOverlay();
655
656 textOverlay_ =
657 AceType::MakeRefPtr<TextOverlayComponent>(GetThemeManager(), context_.Upgrade()->GetAccessibilityManager());
658 textOverlay_->SetWeakTextField(WeakClaim(this));
659 textOverlay_->SetIsSingleHandle(isSingleHandle || (keyboard_ == TextInputType::VISIBLE_PASSWORD));
660 textOverlay_->SetLineHeight(selectHeight_);
661 textOverlay_->SetClipRect(
662 innerRect_ + Size(HANDLE_HOT_ZONE, HANDLE_HOT_ZONE) + GetOffsetToPage() - Offset(HANDLE_HOT_ZONE / 2.0, 0.0));
663 textOverlay_->SetTextDirection(textDirection_);
664 textOverlay_->SetRealTextDirection(existStrongDirectionLetter_ ? realTextDirection_ : TextDirection::LTR);
665 textOverlay_->SetIsPassword(keyboard_ == TextInputType::VISIBLE_PASSWORD);
666 textOverlay_->SetStartHandleOffset(startHandleOffset);
667 textOverlay_->SetEndHandleOffset(endHandleOffset);
668 textOverlay_->SetImageFill(imageFill_);
669 textOverlay_->SetOptions(inputOptions_);
670 textOverlay_->SetOptionsClickMarker(onOptionsClick_);
671 textOverlay_->SetTranslateButtonMarker(onTranslate_);
672 textOverlay_->SetShareButtonMarker(onShare_);
673 textOverlay_->SetSearchButtonMarker(onSearch_);
674 textOverlay_->SetContext(context_);
675 // Add the Animation
676 InitAnimation();
677
678 if (!isSingleHandle_ || startHandleOffset != endHandleOffset) {
679 isOverlayFocus_ = true;
680 }
681 RegisterCallbacksToOverlay();
682 }
683
InitAnimation()684 void RenderTextField::InitAnimation()
685 {
686 if (!textOverlay_) {
687 LOGE("InitAnimation error, textOverlay is nullptr");
688 return;
689 }
690
691 // Get the handleDiameter in theme, textoverlay is not nullptr
692 double initHandleDiameter = textOverlay_->GetHandleDiameter().Value();
693 double initHandleDiameterInner = textOverlay_->GetHandleDiameterInner().Value();
694
695 // Add the animation for handleDiameter
696 auto diameterAnimation = AceType::MakeRefPtr<CurveAnimation<double>>(
697 initHandleDiameter * FIFTY_PERCENT, initHandleDiameter, Curves::ELASTICS);
698 diameterAnimation->AddListener([text = AceType::WeakClaim(this)](double value) {
699 auto textField = text.Upgrade();
700 if (textField && textField->updateHandleDiameter_) {
701 textField->updateHandleDiameter_(value);
702 }
703 });
704
705 // Add the animation for handleDiameterinner
706 auto diameterInnerAnimation = AceType::MakeRefPtr<CurveAnimation<double>>(
707 initHandleDiameterInner * FIFTY_PERCENT, initHandleDiameterInner, Curves::ELASTICS);
708 diameterInnerAnimation->AddListener([text = AceType::WeakClaim(this)](double value) {
709 auto textField = text.Upgrade();
710 if (textField && textField->updateHandleDiameterInner_) {
711 textField->updateHandleDiameterInner_(value);
712 }
713 });
714
715 // Add the animation
716 LOGD("Add animation to animator");
717 animator_ = AceType::MakeRefPtr<Animator>(context_);
718 animator_->AddInterpolator(diameterAnimation);
719 animator_->AddInterpolator(diameterInnerAnimation);
720 animator_->SetDuration(SHOW_HANDLE_DURATION);
721 animator_->Play();
722 }
723
RegisterCallbacksToOverlay()724 void RenderTextField::RegisterCallbacksToOverlay()
725 {
726 if (!textOverlay_) {
727 return;
728 }
729 textOverlay_->SetOnCut([weak = AceType::WeakClaim(this)] {
730 auto textfield = weak.Upgrade();
731 if (textfield) {
732 textfield->HandleOnCut();
733 }
734 });
735
736 textOverlay_->SetOnCopy([weak = AceType::WeakClaim(this)] {
737 auto textfield = weak.Upgrade();
738 if (textfield) {
739 textfield->HandleOnCopy();
740 }
741 });
742
743 textOverlay_->SetOnCopyAll(
744 [weak = AceType::WeakClaim(this)](const std::function<void(const Offset&, const Offset&)>& callback) {
745 auto textfield = weak.Upgrade();
746 if (textfield) {
747 textfield->HandleOnCopyAll(callback);
748 }
749 });
750
751 textOverlay_->SetOnStartHandleMove(
752 [weak = AceType::WeakClaim(this)](int32_t end, const Offset& startHandleOffset,
753 const std::function<void(const Offset&)>& startCallback, bool isSingleHandle) {
754 auto textfield = weak.Upgrade();
755 if (textfield) {
756 textfield->HandleOnStartHandleMove(end, startHandleOffset, startCallback, isSingleHandle);
757 }
758 });
759
760 textOverlay_->SetOnEndHandleMove([weak = AceType::WeakClaim(this)](int32_t start, const Offset& endHandleOffset,
761 const std::function<void(const Offset&)>& endCallback) {
762 auto textfield = weak.Upgrade();
763 if (textfield) {
764 textfield->HandleOnEndHandleMove(start, endHandleOffset, endCallback);
765 }
766 });
767
768 auto callback = [weakTextField = WeakClaim(this)](const std::string& data) {
769 auto textfield = weakTextField.Upgrade();
770 if (textfield) {
771 auto textOverlay = textfield->textOverlay_;
772 if (textOverlay && !data.empty()) {
773 textOverlay->SetOnPaste([weakTextField] {
774 auto textfield = weakTextField.Upgrade();
775 if (textfield) {
776 textfield->HandleOnPaste();
777 }
778 });
779 }
780 textfield->PushTextOverlayToStack();
781 textfield->UpdateOverlay();
782 }
783 };
784 if (clipboard_) {
785 clipboard_->GetData(callback);
786 }
787
788 auto onFocusChange = [weak = WeakClaim(this)](bool isFocus, bool needCloseKeyboard) {
789 auto textField = weak.Upgrade();
790 if (textField) {
791 textField->OnOverlayFocusChange(isFocus, needCloseKeyboard);
792 }
793 };
794 textOverlay_->SetOnFocusChange(onFocusChange);
795 }
796
PushTextOverlayToStack()797 void RenderTextField::PushTextOverlayToStack()
798 {
799 if (!textOverlay_) {
800 LOGE("TextOverlay is null");
801 return;
802 }
803 hasTextOverlayPushed_ = true;
804 auto lastStack = GetLastStack();
805 if (!lastStack) {
806 LOGE("LastStack is null");
807 return;
808 }
809 isOverlayShowed_ = true;
810 lastStack->PushComponent(textOverlay_, false);
811 stackElement_ = WeakClaim(RawPtr(lastStack));
812 MarkNeedRender();
813 }
814
RequestKeyboard(bool isFocusViewChanged,bool needStartTwinkling)815 bool RenderTextField::RequestKeyboard(bool isFocusViewChanged, bool needStartTwinkling)
816 {
817 if (!enabled_) {
818 LOGD("TextField is not enabled.");
819 return false;
820 }
821
822 instanceId_ = ContainerScope::CurrentId();
823
824 if (softKeyboardEnabled_) {
825 LOGI("RenderTextField::CloseKeyboard: Request open soft keyboard");
826 #if defined(ENABLE_STANDARD_INPUT)
827 if (textChangeListener_ == nullptr) {
828 textChangeListener_ = new OnTextChangedListenerImpl(WeakClaim(this));
829 }
830 auto context = context_.Upgrade();
831 if (context) {
832 LOGI("RequestKeyboard set calling window id is : %{public}d", context->GetWindowId());
833 MiscServices::InputMethodController::GetInstance()->SetCallingWindow(context->GetWindowId());
834 }
835 MiscServices::InputMethodController::GetInstance()->Attach(textChangeListener_);
836 #else
837 if (!HasConnection()) {
838 AttachIme();
839 if (!HasConnection()) {
840 LOGE("Get TextInput connection error");
841 return false;
842 }
843 connection_->SetEditingState(GetEditingValue(), GetInstanceId());
844 }
845 connection_->Show(isFocusViewChanged, GetInstanceId());
846 #endif
847 }
848
849 if (keyboard_ != TextInputType::MULTILINE) {
850 resetToStart_ = false;
851 MarkNeedLayout();
852 }
853 if (needStartTwinkling) {
854 StartTwinkling();
855 }
856 if (onEditChanged_) {
857 onEditChanged_(softKeyboardEnabled_);
858 }
859 return true;
860 }
861
CloseKeyboard(bool forceClose)862 bool RenderTextField::CloseKeyboard(bool forceClose)
863 {
864 if (!isOverlayShowed_ || !isOverlayFocus_ || forceClose) {
865 if (!textFieldController_) {
866 StopTwinkling();
867 }
868 if (HasConnection()) {
869 LOGI("RenderTextField::CloseKeyboard: Request close soft keyboard");
870 #if defined(ENABLE_STANDARD_INPUT)
871 MiscServices::InputMethodController::GetInstance()->HideTextInput();
872 #else
873 connection_->Close(GetInstanceId());
874 connection_ = nullptr;
875 #endif
876 }
877
878 if (onKeyboardClose_) {
879 onKeyboardClose_(forceClose);
880 onKeyboardClose_ = nullptr;
881 UpdateSelection(GetEditingValue().selection.GetEnd());
882 MarkNeedLayout();
883 }
884
885 if (keyboard_ != TextInputType::MULTILINE) {
886 resetToStart_ = true;
887 MarkNeedLayout();
888 }
889 if (onEditChanged_) {
890 onEditChanged_(forceClose);
891 }
892 return true;
893 }
894 return false;
895 }
896
AttachIme()897 void RenderTextField::AttachIme()
898 {
899 auto context = context_.Upgrade();
900 if (!context) {
901 LOGW("No context exists, failed to request keyboard.");
902 return;
903 }
904
905 TextInputConfiguration config;
906 config.type = keyboard_;
907 config.action = action_;
908 config.actionLabel = actionLabel_;
909 config.obscureText = obscure_;
910 LOGD("Request keyboard configuration: type=%{private}d action=%{private}d actionLabel=%{private}s "
911 "obscureText=%{private}d",
912 keyboard_, action_, actionLabel_.c_str(), obscure_);
913 connection_ =
914 TextInputProxy::GetInstance().Attach(WeakClaim(this), config, context->GetTaskExecutor(), GetInstanceId());
915 }
916
StartTwinkling()917 void RenderTextField::StartTwinkling()
918 {
919 // Ignore the result because all ops are called on this same thread (ACE UI).
920 // The only reason failed is that the task has finished.
921 cursorTwinklingTask_.Cancel();
922
923 // Show cursor right now.
924 cursorVisibility_ = true;
925 // Does not matter call more than one times.
926 MarkNeedRender();
927
928 ScheduleCursorTwinkling();
929 }
930
StopTwinkling()931 void RenderTextField::StopTwinkling()
932 {
933 obscureTickPendings_ = 0;
934 cursorTwinklingTask_.Cancel();
935
936 if (cursorVisibility_) {
937 // Repaint only if cursor is visible for now.
938 cursorVisibility_ = false;
939 MarkNeedRender();
940 }
941 }
942
GetEditingValue() const943 const TextEditingValue& RenderTextField::GetEditingValue() const
944 {
945 return controller_->GetValue();
946 }
947
GetPreEditingValue() const948 const TextEditingValue& RenderTextField::GetPreEditingValue() const
949 {
950 return controller_->GetPreValue();
951 }
952
SetEditingValue(TextEditingValue && newValue,bool needFireChangeEvent)953 void RenderTextField::SetEditingValue(TextEditingValue&& newValue, bool needFireChangeEvent)
954 {
955 if (newValue.text != GetEditingValue().text && needFireChangeEvent) {
956 needNotifyChangeEvent_ = true;
957 }
958 ChangeCounterStyle(newValue);
959 auto context = context_.Upgrade();
960 if (context && context->GetIsDeclarative()) {
961 if (GetEditingValue().text.empty()) {
962 Dimension fontSize_ = placeHoldStyle_.GetFontSize();
963 if (fontSize_.Value() <= 0) {
964 Dimension fontSize_ { 14, DimensionUnit::FP };
965 placeHoldStyle_.SetFontSize(fontSize_);
966 }
967 SetTextStyle(placeHoldStyle_);
968 }
969 }
970
971 if (context && context->GetIsDeclarative()) {
972 if (inputFilter_.empty() || newValue.text.empty()) {
973 controller_->SetValue(newValue, needFireChangeEvent);
974 } else {
975 std::regex rw(inputFilter_);
976 if (regex_match(newValue.text.c_str(), rw)) {
977 inputCallBackStrSize_ = static_cast<int32_t>(newValue.text.length());
978 controller_->SetValue(newValue, needFireChangeEvent);
979 } else {
980 inputCallBackStr_ = newValue.text.substr(inputCallBackStrSize_);
981 if (onError_) {
982 onError_(inputCallBackStr_);
983 }
984 }
985 }
986 } else {
987 controller_->SetValue(newValue, needFireChangeEvent);
988 }
989 UpdateAccessibilityAttr();
990 }
991
ClearEditingValue()992 void RenderTextField::ClearEditingValue()
993 {
994 TextEditingValue emptyValue;
995 SetEditingValue(std::move(emptyValue));
996 }
997
GetTextForDisplay(const std::string & text) const998 std::u16string RenderTextField::GetTextForDisplay(const std::string& text) const
999 {
1000 std::u16string txtContent = StringUtils::Str8ToStr16(text);
1001 auto len = txtContent.length();
1002 if (!obscure_ || len == 0 || (obscureTickPendings_ > 0 && len == 1)) {
1003 return txtContent;
1004 }
1005
1006 std::u16string obscured;
1007 if (Localization::GetInstance()->GetLanguage() == "ar") { // ar is the abbreviation of Arabic.
1008 obscured = std::u16string(len, OBSCURING_CHARACTER_FOR_AR);
1009 } else {
1010 obscured = std::u16string(len, OBSCURING_CHARACTER);
1011 }
1012 int32_t posBeforeCursor = GetEditingValue().selection.extentOffset - 1;
1013 if (obscureTickPendings_ > 0 && posBeforeCursor >= 0 && static_cast<size_t>(posBeforeCursor) < obscured.length()) {
1014 // Let the last commit character naked.
1015 obscured[posBeforeCursor] = txtContent[posBeforeCursor];
1016 }
1017
1018 return obscured;
1019 }
1020
UpdateObscure(const RefPtr<TextFieldComponent> & textField)1021 void RenderTextField::UpdateObscure(const RefPtr<TextFieldComponent>& textField)
1022 {
1023 auto context = context_.Upgrade();
1024 if (context && context->GetIsDeclarative()) {
1025 if (!passwordRecord_) {
1026 if (keyboard_ != textField->GetTextInputType()) {
1027 passwordRecord_ = true;
1028 obscure_ = textField->NeedObscure();
1029 } else {
1030 obscure_ = !textField->NeedObscure();
1031 }
1032 } else {
1033 obscure_ = textField->NeedObscure();
1034 }
1035 } else {
1036 obscure_ = textField->NeedObscure();
1037 }
1038 }
1039
UpdateFormatters()1040 void RenderTextField::UpdateFormatters()
1041 {
1042 textInputFormatters_.clear();
1043
1044 if (maxLength_ < std::numeric_limits<uint32_t>::max()) {
1045 textInputFormatters_.emplace_back(std::make_unique<LengthLimitingFormatter>(maxLength_));
1046 }
1047
1048 if (maxLines_ == 1) {
1049 textInputFormatters_.emplace_back(std::make_unique<SingleLineFormatter>());
1050 }
1051
1052 switch (keyboard_) {
1053 case TextInputType::NUMBER: {
1054 textInputFormatters_.emplace_back(std::make_unique<NumberFormatter>());
1055 break;
1056 }
1057 case TextInputType::PHONE: {
1058 textInputFormatters_.emplace_back(std::make_unique<PhoneNumberFormatter>());
1059 break;
1060 }
1061 case TextInputType::EMAIL_ADDRESS: {
1062 textInputFormatters_.emplace_back(std::make_unique<EmailFormatter>());
1063 break;
1064 }
1065 case TextInputType::URL: {
1066 textInputFormatters_.emplace_back(std::make_unique<UriFormatter>());
1067 break;
1068 }
1069 default: {
1070 // No need limit.
1071 }
1072 }
1073
1074 TextEditingValue temp = GetEditingValue();
1075 for (const auto& formatter : textInputFormatters_) {
1076 if (formatter) {
1077 formatter->Format(GetEditingValue(), temp);
1078 }
1079 }
1080 SetEditingValue(std::move(temp));
1081 }
1082
UpdateEditingValue(const std::shared_ptr<TextEditingValue> & value,bool needFireChangeEvent)1083 void RenderTextField::UpdateEditingValue(const std::shared_ptr<TextEditingValue>& value, bool needFireChangeEvent)
1084 {
1085 if (!value) {
1086 LOGE("the value is nullptr");
1087 return;
1088 }
1089
1090 lastKnownRemoteEditingValue_ = value;
1091 lastKnownRemoteEditingValue_->hint = placeholder_;
1092 TextEditingValue temp = *lastKnownRemoteEditingValue_;
1093 if (cursorPositionType_ != CursorPositionType::END ||
1094 (temp.selection.baseOffset == temp.selection.extentOffset &&
1095 temp.selection.baseOffset != static_cast<int32_t>(temp.GetWideText().length()))) {
1096 cursorPositionType_ = CursorPositionType::NORMAL;
1097 isValueFromRemote_ = true;
1098 }
1099 ChangeCounterStyle(temp);
1100 for (const auto& formatter : textInputFormatters_) {
1101 // GetEditingValue() is the old value, and lastKnownRemoteEditingValue_ is the newer.
1102 if (formatter) {
1103 formatter->Format(GetEditingValue(), temp);
1104 }
1105 }
1106
1107 if (obscure_ && (temp.text.length() == GetEditingValue().text.length() + 1)) {
1108 // Reset pending.
1109 obscureTickPendings_ = OBSCURE_SHOW_TICKS;
1110 }
1111
1112 if (temp.text != GetEditingValue().text && needFireChangeEvent) {
1113 needNotifyChangeEvent_ = true;
1114 }
1115
1116 auto editingText = GetEditingValue().text;
1117 SetEditingValue(std::move(temp), needFireChangeEvent);
1118 UpdateRemoteEditingIfNeeded(needFireChangeEvent);
1119
1120 MarkNeedLayout();
1121
1122 // If input or delete text when overlay is showing, pop overlay from stack.
1123 if (lastKnownRemoteEditingValue_ && (lastKnownRemoteEditingValue_->text != editingText)) {
1124 if (onValueChange_) {
1125 onValueChange_();
1126 }
1127 }
1128 }
1129
PerformDefaultAction()1130 void RenderTextField::PerformDefaultAction()
1131 {
1132 PerformAction(action_);
1133 }
1134
PerformAction(TextInputAction action,bool forceCloseKeyboard)1135 void RenderTextField::PerformAction(TextInputAction action, bool forceCloseKeyboard)
1136 {
1137 LOGD("PerformAction %{public}d", static_cast<int32_t>(action));
1138 if (action == TextInputAction::NEXT && moveNextFocusEvent_) {
1139 moveNextFocusEvent_();
1140 } else {
1141 CloseKeyboard(forceCloseKeyboard);
1142 }
1143 if (onFinishInputEvent_) {
1144 auto jsonResult = JsonUtil::Create(true);
1145 jsonResult->Put("value", static_cast<int32_t>(action));
1146 onFinishInputEvent_(std::string(R"("enterkeyclick",)").append(jsonResult->ToString()));
1147 }
1148 if (onSubmitEvent_ && controller_) {
1149 onSubmitEvent_(controller_->GetValue().text);
1150 }
1151 if (onSubmit_) {
1152 onSubmit_(static_cast<int32_t>(action_));
1153 }
1154 }
1155
Measure()1156 Size RenderTextField::Measure()
1157 {
1158 return Size();
1159 }
1160
ScheduleCursorTwinkling()1161 void RenderTextField::ScheduleCursorTwinkling()
1162 {
1163 auto context = context_.Upgrade();
1164 if (!context) {
1165 LOGW("No context exists.");
1166 return;
1167 }
1168
1169 if (!context->GetTaskExecutor()) {
1170 LOGW("context has no task executor.");
1171 return;
1172 }
1173
1174 auto weak = WeakClaim(this);
1175 cursorTwinklingTask_.Reset([weak] {
1176 auto client = weak.Upgrade();
1177 if (client) {
1178 client->OnCursorTwinkling();
1179 }
1180 });
1181 auto taskExecutor = context->GetTaskExecutor();
1182 if (taskExecutor) {
1183 taskExecutor->PostDelayedTask(cursorTwinklingTask_, TaskExecutor::TaskType::UI, twinklingInterval);
1184 } else {
1185 LOGE("the task executor is nullptr");
1186 }
1187 }
1188
OnCursorTwinkling()1189 void RenderTextField::OnCursorTwinkling()
1190 {
1191 // When glyph changes from visible to invisible, layout is needed.
1192 obscureTickPendings_ == 1 ? MarkNeedLayout() : MarkNeedRender();
1193 if (obscureTickPendings_ > 0) {
1194 --obscureTickPendings_;
1195 }
1196 cursorVisibility_ = !cursorVisibility_;
1197 ScheduleCursorTwinkling();
1198 }
1199
OnKeyEvent(const KeyEvent & event)1200 bool RenderTextField::OnKeyEvent(const KeyEvent& event)
1201 {
1202 if (!enabled_) {
1203 return false;
1204 }
1205
1206 // If back or escape is clicked and overlay is showing, pop overlay firstly.
1207 if (event.action == KeyAction::UP && (event.code == KeyCode::KEY_BACK || event.code == KeyCode::KEY_ESCAPE)) {
1208 if (isOverlayShowed_) {
1209 PopTextOverlay();
1210 return false;
1211 }
1212 }
1213 if (event.action == KeyAction::UP &&
1214 ((event.code == KeyCode::KEY_SHIFT_LEFT || event.code == KeyCode::KEY_SHIFT_RIGHT) ||
1215 (event.code == KeyCode::KEY_CTRL_LEFT || event.code == KeyCode::KEY_CTRL_RIGHT))) {
1216 return HandleKeyEvent(event);
1217 }
1218
1219 if (event.action == KeyAction::DOWN) {
1220 cursorPositionType_ = CursorPositionType::NONE;
1221 bool moved = true;
1222 if (event.code == KeyCode::TV_CONTROL_LEFT) {
1223 CursorMoveLeft();
1224 } else if (event.code == KeyCode::TV_CONTROL_RIGHT) {
1225 CursorMoveRight();
1226 } else if (event.code == KeyCode::TV_CONTROL_UP) {
1227 CursorMoveUp();
1228 } else if (event.code == KeyCode::TV_CONTROL_DOWN) {
1229 CursorMoveDown();
1230 } else {
1231 moved = HandleKeyEvent(event);
1232 }
1233 if (moved) {
1234 // Obscure all glyphs immediately after cursor moved.
1235 obscureTickPendings_ = 0;
1236 }
1237 return moved;
1238 }
1239
1240 return false;
1241 }
1242
UpdateFocusStyles()1243 void RenderTextField::UpdateFocusStyles()
1244 {
1245 if (hasFocus_) {
1246 style_.SetTextColor(focusTextColor_);
1247 placeholderColor_ = focusPlaceholderColor_;
1248 if (decoration_) {
1249 decoration_->SetBackgroundColor(focusBgColor_);
1250 }
1251 } else {
1252 style_.SetTextColor(inactiveTextColor_);
1253 placeholderColor_ = inactivePlaceholderColor_;
1254 if (decoration_) {
1255 decoration_->SetBackgroundColor(inactiveBgColor_);
1256 }
1257 }
1258 }
1259
UpdateFocusAnimation()1260 void RenderTextField::UpdateFocusAnimation()
1261 {
1262 if (hasFocus_) {
1263 auto context = context_.Upgrade();
1264 if (!context) {
1265 return;
1266 }
1267 Offset offset;
1268 Size size;
1269 Radius deflateRadius;
1270 if (IsSelectiveDevice()) {
1271 double focusOffset = NormalizeToPx(OFFSET_FOCUS);
1272 offset = Offset(focusOffset, focusOffset);
1273 size = Size(focusOffset * 2.0, focusOffset * 2.0);
1274 deflateRadius = Radius(DEFLATE_RADIUS_FOCUS, DEFLATE_RADIUS_FOCUS);
1275 }
1276 RRect rrect = RRect::MakeRect(
1277 Rect(GetPosition() + offset, GetLayoutSize() - ComputeDeflateSizeOfErrorAndCountText() - size));
1278 if (decoration_) {
1279 const auto& border = decoration_->GetBorder();
1280 rrect.SetCorner({ border.TopLeftRadius() - deflateRadius, border.TopRightRadius() - deflateRadius,
1281 border.BottomRightRadius() - deflateRadius, border.BottomLeftRadius() - deflateRadius });
1282 }
1283 context->ShowFocusAnimation(rrect, focusBgColor_, GetGlobalOffset() + offset);
1284 }
1285 }
1286
UpdateIcon(const RefPtr<TextFieldComponent> & textField)1287 void RenderTextField::UpdateIcon(const RefPtr<TextFieldComponent>& textField)
1288 {
1289 if (!textField) {
1290 return;
1291 }
1292 iconSizeInDimension_ = textField->GetIconSize();
1293 iconHotZoneSizeInDimension_ = textField->GetIconHotZoneSize();
1294 UpdatePasswordIcon(textField);
1295
1296 double widthReserved = NormalizeToPx(widthReserved_);
1297 if (textField->GetIconImage() == iconSrc_ && textField->GetImageFill() == imageFill_ && widthReserved <= 0.0) {
1298 return;
1299 }
1300 imageFill_ = textField->GetImageFill();
1301 iconSrc_ = textField->GetIconImage();
1302 if (!iconSrc_.empty() || widthReserved > 0.0) {
1303 RefPtr<ImageComponent> imageComponent;
1304 if (iconSrc_.empty() && widthReserved > 0.0) {
1305 imageComponent = AceType::MakeRefPtr<ImageComponent>(InternalResource::ResourceId::SEARCH_SVG);
1306 } else {
1307 imageComponent = AceType::MakeRefPtr<ImageComponent>(iconSrc_);
1308 imageComponent->SetImageFill(imageFill_);
1309 }
1310 imageComponent->SetWidth(textField->GetIconSize());
1311 imageComponent->SetHeight(textField->GetIconSize());
1312 if (textDirection_ == TextDirection::RTL) {
1313 imageComponent->SetMatchTextDirection(true);
1314 imageComponent->SetTextDirection(TextDirection::RTL);
1315 }
1316
1317 iconImage_ = AceType::DynamicCast<RenderImage>(imageComponent->CreateRenderNode());
1318 if (!iconImage_) {
1319 return;
1320 }
1321 iconImage_->Attach(GetContext());
1322 iconImage_->SetDirectPaint(true);
1323 iconImage_->Update(imageComponent);
1324 AddChild(iconImage_);
1325 }
1326 }
1327
UpdatePasswordIcon(const RefPtr<TextFieldComponent> & textField)1328 void RenderTextField::UpdatePasswordIcon(const RefPtr<TextFieldComponent>& textField)
1329 {
1330 if (!IsSelectiveDevice()) {
1331 return;
1332 }
1333 if (!showPasswordIcon_) {
1334 renderShowIcon_.Reset();
1335 renderHideIcon_.Reset();
1336 return;
1337 }
1338
1339 showIconSrc_ = textField->GetShowIconImage();
1340 hideIconSrc_ = textField->GetHideIconImage();
1341
1342 // update show icon.
1343 RefPtr<ImageComponent> showImage;
1344 if (showIconSrc_.empty()) {
1345 showImage = AceType::MakeRefPtr<ImageComponent>(InternalResource::ResourceId::SHOW_PASSWORD_SVG);
1346 } else {
1347 showImage = AceType::MakeRefPtr<ImageComponent>(showIconSrc_);
1348 }
1349 showImage->SetWidth(textField->GetIconSize());
1350 showImage->SetHeight(textField->GetIconSize());
1351
1352 renderShowIcon_ = AceType::DynamicCast<RenderImage>(showImage->CreateRenderNode());
1353 if (!renderShowIcon_) {
1354 return;
1355 }
1356 renderShowIcon_->Attach(GetContext());
1357 renderShowIcon_->SetDirectPaint(true);
1358 renderShowIcon_->Update(showImage);
1359 AddChild(renderShowIcon_);
1360
1361 // update hide icon.
1362 RefPtr<ImageComponent> hideImage;
1363 if (hideIconSrc_.empty()) {
1364 hideImage = AceType::MakeRefPtr<ImageComponent>(InternalResource::ResourceId::HIDE_PASSWORD_SVG);
1365 } else {
1366 hideImage = AceType::MakeRefPtr<ImageComponent>(hideIconSrc_);
1367 }
1368 hideImage->SetWidth(textField->GetIconSize());
1369 hideImage->SetHeight(textField->GetIconSize());
1370
1371 renderHideIcon_ = AceType::DynamicCast<RenderImage>(hideImage->CreateRenderNode());
1372 if (!renderHideIcon_) {
1373 return;
1374 }
1375 renderHideIcon_->Attach(GetContext());
1376 renderHideIcon_->SetDirectPaint(true);
1377 renderHideIcon_->Update(hideImage);
1378 AddChild(renderHideIcon_);
1379 }
1380
UpdateOverlay()1381 void RenderTextField::UpdateOverlay()
1382 {
1383 // When textfield PerformLayout, update overlay.
1384 if (isOverlayShowed_ && updateHandlePosition_) {
1385 auto selStart = GetEditingValue().selection.GetStart();
1386 auto selEnd = GetEditingValue().selection.GetEnd();
1387 Rect caretStart;
1388 Rect caretEnd;
1389 bool startHandleVisible =
1390 GetCaretRect(selStart, caretStart) ? IsVisible(caretStart + textOffsetForShowCaret_) : false;
1391 bool endHandleVisible =
1392 (selStart == selEnd)
1393 ? startHandleVisible
1394 : (GetCaretRect(selEnd, caretEnd) ? IsVisible(caretEnd + textOffsetForShowCaret_) : false);
1395
1396 OverlayShowOption option { .showMenu = isOverlayShowed_,
1397 .showStartHandle = startHandleVisible,
1398 .showEndHandle = endHandleVisible,
1399 .isSingleHandle = isSingleHandle_,
1400 .updateOverlayType = UpdateOverlayType::SCROLL,
1401 .startHandleOffset = GetPositionForExtend(selStart, isSingleHandle_),
1402 .endHandleOffset = GetPositionForExtend(selEnd, isSingleHandle_) };
1403 updateHandlePosition_(option);
1404 if (onClipRectChanged_) {
1405 onClipRectChanged_(innerRect_ + Size(HANDLE_HOT_ZONE, HANDLE_HOT_ZONE) + GetOffsetToPage() -
1406 Offset(HANDLE_HOT_ZONE / 2.0, 0.0));
1407 }
1408 }
1409 }
1410
RegisterFontCallbacks()1411 void RenderTextField::RegisterFontCallbacks()
1412 {
1413 // Register callback for fonts.
1414 auto pipelineContext = context_.Upgrade();
1415 if (!pipelineContext) {
1416 return;
1417 }
1418 auto callback = [textfield = AceType::WeakClaim(this)] {
1419 auto refPtr = textfield.Upgrade();
1420 if (refPtr) {
1421 refPtr->isCallbackCalled_ = true;
1422 refPtr->MarkNeedLayout();
1423 }
1424 };
1425 auto fontManager = pipelineContext->GetFontManager();
1426 if (fontManager) {
1427 for (const auto& familyName : style_.GetFontFamilies()) {
1428 fontManager->RegisterCallback(AceType::WeakClaim(this), familyName, callback);
1429 }
1430 fontManager->AddVariationNode(WeakClaim(this));
1431 }
1432 }
1433
OnStatusChanged(OHOS::Ace::RenderStatus renderStatus)1434 void RenderTextField::OnStatusChanged(OHOS::Ace::RenderStatus renderStatus)
1435 {
1436 hasFocus_ = renderStatus == RenderStatus::FOCUS;
1437 UpdateFocusStyles();
1438 MarkNeedLayout();
1439
1440 if (!hasFocus_) {
1441 auto context = context_.Upgrade();
1442 if (!context) {
1443 return;
1444 }
1445 // Don't call cancel focus animation when next frame comes because then focus is switched, next node will
1446 // show focus immediately, we shouldn't cancel focus animation that time.
1447 context->CancelFocusAnimation();
1448 }
1449 }
1450
OnValueChanged(bool needFireChangeEvent,bool needFireSelectChangeEvent)1451 void RenderTextField::OnValueChanged(bool needFireChangeEvent, bool needFireSelectChangeEvent)
1452 {
1453 isValueFromFront_ = !needFireChangeEvent;
1454 TextEditingValue temp = GetEditingValue();
1455 for (const auto& formatter : textInputFormatters_) {
1456 if (formatter) {
1457 formatter->Format(GetEditingValue(), temp);
1458 }
1459 }
1460 if (cursorPositionType_ == CursorPositionType::NORMAL && temp.selection.GetStart() == temp.selection.GetEnd()) {
1461 temp.selection.Update(AdjustCursorAndSelection(temp.selection.GetEnd()));
1462 }
1463 FireSelectChangeIfNeeded(temp, needFireSelectChangeEvent);
1464 SetEditingValue(std::move(temp), needFireChangeEvent);
1465 UpdateRemoteEditingIfNeeded(needFireChangeEvent);
1466 MarkNeedLayout();
1467 }
1468
FireSelectChangeIfNeeded(const TextEditingValue & newValue,bool needFireSelectChangeEvent) const1469 void RenderTextField::FireSelectChangeIfNeeded(const TextEditingValue& newValue, bool needFireSelectChangeEvent) const
1470 {
1471 if (needFireSelectChangeEvent && onSelectChangeEvent_ && newValue.selection != GetPreEditingValue().selection) {
1472 auto jsonResult = JsonUtil::Create(true);
1473 jsonResult->Put("start", newValue.selection.GetStart());
1474 jsonResult->Put("end", newValue.selection.GetEnd());
1475 onSelectChangeEvent_(std::string(R"("selectchange",)").append(jsonResult->ToString()));
1476 }
1477 }
1478
CursorMoveLeft(CursorMoveSkip skip)1479 void RenderTextField::CursorMoveLeft(CursorMoveSkip skip)
1480 {
1481 if (skip != CursorMoveSkip::CHARACTER) {
1482 // Not support yet.
1483 LOGE("move skip not support character yet");
1484 return;
1485 }
1486 if (GetEditingValue().selection.extentOffset > 0) {
1487 isValueFromRemote_ = false;
1488 auto value = GetEditingValue();
1489 value.MoveLeft();
1490 SetEditingValue(std::move(value));
1491 }
1492 cursorPositionType_ = CursorPositionType::NONE;
1493 MarkNeedLayout();
1494 }
1495
CursorMoveRight(CursorMoveSkip skip)1496 void RenderTextField::CursorMoveRight(CursorMoveSkip skip)
1497 {
1498 if (skip != CursorMoveSkip::CHARACTER) {
1499 // Not support yet.
1500 LOGE("move skip not support character yet");
1501 return;
1502 }
1503
1504 auto text = GetTextForDisplay(GetEditingValue().text);
1505 if (text.length() > static_cast<size_t>(GetEditingValue().selection.extentOffset)) {
1506 isValueFromRemote_ = false;
1507 auto value = GetEditingValue();
1508 value.MoveRight();
1509 SetEditingValue(std::move(value));
1510 }
1511 cursorPositionType_ = CursorPositionType::NONE;
1512 MarkNeedLayout();
1513 }
1514
CursorMoveUp()1515 void RenderTextField::CursorMoveUp()
1516 {
1517 if (keyboard_ != TextInputType::MULTILINE) {
1518 return;
1519 }
1520 isValueFromRemote_ = false;
1521 auto value = GetEditingValue();
1522 value.MoveToPosition(GetCursorPositionForMoveUp());
1523 SetEditingValue(std::move(value));
1524 cursorPositionType_ = CursorPositionType::NONE;
1525 MarkNeedLayout();
1526 }
1527
CursorMoveDown()1528 void RenderTextField::CursorMoveDown()
1529 {
1530 if (keyboard_ != TextInputType::MULTILINE) {
1531 return;
1532 }
1533 isValueFromRemote_ = false;
1534 auto value = GetEditingValue();
1535 value.MoveToPosition(GetCursorPositionForMoveDown());
1536 SetEditingValue(std::move(value));
1537 cursorPositionType_ = CursorPositionType::NONE;
1538 MarkNeedLayout();
1539 }
1540
CursorMoveOnClick(const Offset & offset)1541 void RenderTextField::CursorMoveOnClick(const Offset& offset)
1542 {
1543 auto value = GetEditingValue();
1544 auto position = GetCursorPositionForClick(offset);
1545 value.MoveToPosition(position);
1546 SetEditingValue(std::move(value));
1547
1548 if (!GetEditingValue().text.empty() && position == GetEditingValue().selection.GetEnd()) {
1549 OnValueChanged(true, false);
1550 }
1551 }
1552
UpdateSelection(int32_t both)1553 void RenderTextField::UpdateSelection(int32_t both)
1554 {
1555 UpdateSelection(both, both);
1556 }
1557
UpdateSelection(int32_t start,int32_t end)1558 void RenderTextField::UpdateSelection(int32_t start, int32_t end)
1559 {
1560 auto value = GetEditingValue();
1561 value.UpdateSelection(start, end);
1562 SetEditingValue(std::move(value));
1563 auto refPtr = accessibilityNode_.Upgrade();
1564 if (refPtr) {
1565 refPtr->SetTextSelectionStart(start);
1566 refPtr->SetTextSelectionEnd(end);
1567 }
1568 }
1569
UpdateRemoteEditing(bool needFireChangeEvent)1570 void RenderTextField::UpdateRemoteEditing(bool needFireChangeEvent)
1571 {
1572 #if defined(ENABLE_STANDARD_INPUT)
1573 auto value = GetEditingValue();
1574 MiscServices::InputMethodController::GetInstance()->OnSelectionChange(
1575 StringUtils::Str8ToStr16(value.text), value.selection.GetStart(), value.selection.GetEnd());
1576 #else
1577 if (!HasConnection()) {
1578 return;
1579 }
1580 connection_->SetEditingState(GetEditingValue(), GetInstanceId(), needFireChangeEvent);
1581 #endif
1582 }
1583
UpdateRemoteEditingIfNeeded(bool needFireChangeEvent)1584 void RenderTextField::UpdateRemoteEditingIfNeeded(bool needFireChangeEvent)
1585 {
1586 if (!enabled_) {
1587 return;
1588 }
1589 #if defined(ENABLE_STANDARD_INPUT)
1590 UpdateRemoteEditing(needFireChangeEvent);
1591 #else
1592 if (!lastKnownRemoteEditingValue_ || GetEditingValue() != *lastKnownRemoteEditingValue_) {
1593 lastKnownRemoteEditingValue_ = std::make_shared<TextEditingValue>(GetEditingValue());
1594 UpdateRemoteEditing(needFireChangeEvent);
1595 }
1596 #endif
1597 }
1598
ShowError(const std::string & errorText,bool resetToStart)1599 void RenderTextField::ShowError(const std::string& errorText, bool resetToStart)
1600 {
1601 errorText_ = errorText;
1602 if (!errorText.empty()) {
1603 auto refPtr = accessibilityNode_.Upgrade();
1604 if (refPtr) {
1605 refPtr->SetErrorText(errorText);
1606 }
1607 }
1608
1609 if (!errorText.empty()) {
1610 ChangeBorderToErrorStyle();
1611 } else {
1612 if (decoration_) {
1613 decoration_->SetBorder(originBorder_);
1614 }
1615 }
1616 MarkNeedLayout();
1617 }
1618
SetOnValueChange(const std::function<void ()> & onValueChange)1619 void RenderTextField::SetOnValueChange(const std::function<void()>& onValueChange)
1620 {
1621 onValueChange_ = onValueChange;
1622 }
1623
GetOnValueChange() const1624 const std::function<void()>& RenderTextField::GetOnValueChange() const
1625 {
1626 return onValueChange_;
1627 }
1628
SetOnKeyboardClose(const std::function<void (bool)> & onKeyboardClose)1629 void RenderTextField::SetOnKeyboardClose(const std::function<void(bool)>& onKeyboardClose)
1630 {
1631 onKeyboardClose_ = onKeyboardClose;
1632 }
1633
SetOnClipRectChanged(const std::function<void (const Rect &)> & onClipRectChanged)1634 void RenderTextField::SetOnClipRectChanged(const std::function<void(const Rect&)>& onClipRectChanged)
1635 {
1636 onClipRectChanged_ = onClipRectChanged;
1637 }
1638
SetUpdateHandlePosition(const std::function<void (const OverlayShowOption &)> & updateHandlePosition)1639 void RenderTextField::SetUpdateHandlePosition(const std::function<void(const OverlayShowOption&)>& updateHandlePosition)
1640 {
1641 updateHandlePosition_ = updateHandlePosition;
1642 }
1643
SetUpdateHandleDiameter(const std::function<void (const double &)> & updateHandleDiameter)1644 void RenderTextField::SetUpdateHandleDiameter(const std::function<void(const double&)>& updateHandleDiameter)
1645 {
1646 updateHandleDiameter_ = updateHandleDiameter;
1647 }
1648
SetUpdateHandleDiameterInner(const std::function<void (const double &)> & updateHandleDiameterInner)1649 void RenderTextField::SetUpdateHandleDiameterInner(const std::function<void(const double&)>& updateHandleDiameterInner)
1650 {
1651 updateHandleDiameterInner_ = updateHandleDiameterInner;
1652 }
1653
SetIsOverlayShowed(bool isOverlayShowed,bool needStartTwinkling)1654 void RenderTextField::SetIsOverlayShowed(bool isOverlayShowed, bool needStartTwinkling)
1655 {
1656 isOverlayShowed_ = isOverlayShowed;
1657 // When pop overlay, reset selection and clear selected style.
1658 if (GetEditingValue().selection.GetStart() != GetEditingValue().selection.GetEnd()) {
1659 UpdateSelection(GetEditingValue().selection.GetEnd());
1660 }
1661 if (!isOverlayShowed_ && hasFocus_ && needStartTwinkling) {
1662 StartTwinkling();
1663 }
1664 }
1665
HandleOnCut()1666 void RenderTextField::HandleOnCut()
1667 {
1668 if (!clipboard_) {
1669 return;
1670 }
1671 clipboard_->SetData(GetEditingValue().GetSelectedText());
1672 if (onCut_) {
1673 onCut_(GetEditingValue().GetSelectedText());
1674 }
1675 auto value = GetEditingValue();
1676 value.text = value.GetBeforeSelection() + value.GetAfterSelection();
1677 value.UpdateSelection(GetEditingValue().selection.GetStart());
1678 SetEditingValue(std::move(value));
1679 }
1680
HandleOnCopy()1681 void RenderTextField::HandleOnCopy()
1682 {
1683 if (!clipboard_) {
1684 return;
1685 }
1686 clipboard_->SetData(GetEditingValue().GetSelectedText());
1687 if (onCopy_) {
1688 onCopy_(GetEditingValue().GetSelectedText());
1689 }
1690 UpdateSelection(GetEditingValue().selection.GetEnd());
1691 }
1692
HandleOnPaste()1693 void RenderTextField::HandleOnPaste()
1694 {
1695 if (!clipboard_) {
1696 return;
1697 }
1698 auto textSelection = GetEditingValue().selection;
1699 auto pasteCallback = [weak = WeakClaim(this), textSelection](const std::string& data) {
1700 auto textfield = weak.Upgrade();
1701 if (textfield) {
1702 auto value = textfield->GetEditingValue();
1703 value.selection = textSelection;
1704 value.text = value.GetBeforeSelection() + data + value.GetAfterSelection();
1705 value.UpdateSelection(textSelection.GetStart() + StringUtils::Str8ToStr16(data).length());
1706 textfield->SetEditingValue(std::move(value));
1707 if (textfield->onPaste_) {
1708 textfield->onPaste_(data);
1709 }
1710 }
1711 };
1712 clipboard_->GetData(pasteCallback);
1713 }
1714
HandleOnCopyAll(const std::function<void (const Offset &,const Offset &)> & callback)1715 void RenderTextField::HandleOnCopyAll(const std::function<void(const Offset&, const Offset&)>& callback)
1716 {
1717 isSingleHandle_ = false;
1718 cursorPositionType_ = CursorPositionType::NORMAL;
1719 auto textSize = GetEditingValue().GetWideText().length();
1720 if (textSize == 0) {
1721 isSingleHandle_ = true;
1722 }
1723 UpdateSelection(0, textSize);
1724 if (callback) {
1725 callback(GetPositionForExtend(0, isSingleHandle_),
1726 GetPositionForExtend(GetEditingValue().GetWideText().length(), isSingleHandle_));
1727 }
1728 }
1729
HandleOnStartHandleMove(int32_t end,const Offset & startHandleOffset,const std::function<void (const Offset &)> & startCallback,bool isSingleHandle)1730 void RenderTextField::HandleOnStartHandleMove(int32_t end, const Offset& startHandleOffset,
1731 const std::function<void(const Offset&)>& startCallback, bool isSingleHandle)
1732 {
1733 Offset realOffset = startHandleOffset;
1734 if (startCallback) {
1735 UpdateStartSelection(end, realOffset, isSingleHandle, false);
1736 startCallback(GetHandleOffset(GetEditingValue().selection.GetStart()));
1737 }
1738 }
1739
HandleOnEndHandleMove(int32_t start,const Offset & endHandleOffset,const std::function<void (const Offset &)> & endCallback)1740 void RenderTextField::HandleOnEndHandleMove(
1741 int32_t start, const Offset& endHandleOffset, const std::function<void(const Offset&)>& endCallback)
1742 {
1743 Offset realOffset = endHandleOffset;
1744 if (endCallback) {
1745 UpdateEndSelection(start, realOffset);
1746 endCallback(GetHandleOffset(GetEditingValue().selection.GetEnd()));
1747 }
1748 }
1749
GetLastStack() const1750 RefPtr<StackElement> RenderTextField::GetLastStack() const
1751 {
1752 auto context = context_.Upgrade();
1753 if (!context) {
1754 LOGE("Context is nullptr");
1755 return nullptr;
1756 }
1757 return context->GetLastStack();
1758 }
1759
HandleKeyEvent(const KeyEvent & event)1760 bool RenderTextField::HandleKeyEvent(const KeyEvent& event)
1761 {
1762 std::string appendElement;
1763 if (event.action == KeyAction::DOWN) {
1764 if (event.IsNumberKey()) {
1765 appendElement = event.ConvertCodeToString();
1766 } else if (event.IsLetterKey()) {
1767 if (event.IsKey({ KeyCode::KEY_CTRL_LEFT, KeyCode::KEY_A }) ||
1768 event.IsKey({ KeyCode::KEY_CTRL_RIGHT, KeyCode::KEY_A })) {
1769 HandleOnCopyAll(nullptr);
1770 } else if (event.IsKey({ KeyCode::KEY_CTRL_LEFT, KeyCode::KEY_C }) ||
1771 event.IsKey({ KeyCode::KEY_CTRL_RIGHT, KeyCode::KEY_C })) {
1772 HandleOnCopy();
1773 } else if (event.IsKey({ KeyCode::KEY_CTRL_LEFT, KeyCode::KEY_V }) ||
1774 event.IsKey({ KeyCode::KEY_CTRL_RIGHT, KeyCode::KEY_V })) {
1775 HandleOnPaste();
1776 } else if (event.IsKey({ KeyCode::KEY_CTRL_LEFT, KeyCode::KEY_X }) ||
1777 event.IsKey({ KeyCode::KEY_CTRL_RIGHT, KeyCode::KEY_X })) {
1778 HandleOnCut();
1779 } else {
1780 appendElement = event.ConvertCodeToString();
1781 }
1782 }
1783 MarkNeedLayout();
1784 }
1785 if (appendElement.empty()) {
1786 return false;
1787 }
1788 auto value = GetEditingValue();
1789 value.text = value.GetBeforeSelection() + appendElement + value.GetAfterSelection();
1790 value.UpdateSelection(
1791 std::max(GetEditingValue().selection.GetEnd(), 0) + StringUtils::Str8ToStr16(appendElement).length());
1792 SetEditingValue(std::move(value));
1793 MarkNeedLayout();
1794 return true;
1795 }
1796
UpdateAccessibilityAttr()1797 void RenderTextField::UpdateAccessibilityAttr()
1798 {
1799 auto refPtr = accessibilityNode_.Upgrade();
1800 if (!refPtr) {
1801 LOGW("RenderTextField accessibilityNode is null.");
1802 return;
1803 }
1804
1805 refPtr->SetHintText(placeholder_);
1806 refPtr->SetMaxTextLength(maxLength_);
1807 refPtr->SetEditable(enabled_);
1808 refPtr->SetClickableState(true);
1809 refPtr->SetLongClickableState(true);
1810 if (maxLines_ > 1) {
1811 refPtr->SetIsMultiLine(true);
1812 }
1813 if (controller_) {
1814 refPtr->SetText(controller_->GetText());
1815 }
1816 switch (keyboard_) {
1817 case TextInputType::TEXT:
1818 refPtr->SetTextInputType(AceTextCategory::INPUT_TYPE_TEXT);
1819 break;
1820 case TextInputType::NUMBER:
1821 refPtr->SetTextInputType(AceTextCategory::INPUT_TYPE_NUMBER);
1822 break;
1823 case TextInputType::DATETIME:
1824 refPtr->SetTextInputType(AceTextCategory::INPUT_TYPE_DATE);
1825 break;
1826 case TextInputType::EMAIL_ADDRESS:
1827 refPtr->SetTextInputType(AceTextCategory::INPUT_TYPE_EMAIL);
1828 break;
1829 case TextInputType::VISIBLE_PASSWORD:
1830 refPtr->SetTextInputType(AceTextCategory::INPUT_TYPE_PASSWORD);
1831 break;
1832 default:
1833 break;
1834 }
1835 }
1836
InitAccessibilityEventListener()1837 void RenderTextField::InitAccessibilityEventListener()
1838 {
1839 const auto& accessibilityNode = GetAccessibilityNode().Upgrade();
1840 if (!accessibilityNode) {
1841 return;
1842 }
1843 accessibilityNode->AddSupportAction(AceAction::ACTION_CLICK);
1844 accessibilityNode->SetActionClickImpl([weakPtr = WeakClaim(this)]() {
1845 const auto& textField = weakPtr.Upgrade();
1846 if (textField) {
1847 textField->OnClick(ClickInfo(0));
1848 }
1849 });
1850
1851 accessibilityNode->AddSupportAction(AceAction::ACTION_LONG_CLICK);
1852 accessibilityNode->SetActionLongClickImpl([weakPtr = WeakClaim(this)]() {
1853 const auto& textField = weakPtr.Upgrade();
1854 if (textField) {
1855 textField->OnLongPress(LongPressInfo(0));
1856 }
1857 });
1858 }
1859
UpdateDirectionStatus()1860 void RenderTextField::UpdateDirectionStatus()
1861 {
1862 directionStatus_ = static_cast<DirectionStatus>(
1863 (static_cast<uint8_t>(textDirection_) << 1) | static_cast<uint8_t>(realTextDirection_));
1864 }
1865
UpdateStartSelection(int32_t end,const Offset & pos,bool isSingleHandle,bool isLongPress)1866 void RenderTextField::UpdateStartSelection(int32_t end, const Offset& pos, bool isSingleHandle, bool isLongPress)
1867 {
1868 int32_t extend = GetCursorPositionForClick(pos);
1869 int32_t extendEnd = GetEditingValue().selection.GetEnd();
1870 if (isLongPress) {
1871 // Use custom selection if exist, otherwise select content near finger.
1872 if (selection_.IsValid()) {
1873 UpdateSelection(selection_.baseOffset, selection_.extentOffset);
1874 } else {
1875 extendEnd = extend + GetGraphemeClusterLength(extend, false);
1876 UpdateSelection(extend, extendEnd);
1877 }
1878 return;
1879 }
1880 if (isSingleHandle) {
1881 UpdateSelection(extend);
1882 } else {
1883 UpdateSelection(extend, end);
1884 }
1885 }
1886
UpdateEndSelection(int32_t start,const Offset & pos)1887 void RenderTextField::UpdateEndSelection(int32_t start, const Offset& pos)
1888 {
1889 int32_t extend = GetCursorPositionForClick(pos);
1890 UpdateSelection(start, extend);
1891 }
1892
GetPositionForExtend(int32_t extend,bool isSingleHandle)1893 Offset RenderTextField::GetPositionForExtend(int32_t extend, bool isSingleHandle)
1894 {
1895 if (extend < 0) {
1896 extend = 0;
1897 }
1898 if (static_cast<size_t>(extend) > GetEditingValue().GetWideText().length()) {
1899 extend = static_cast<int32_t>(GetEditingValue().GetWideText().length());
1900 }
1901 return GetHandleOffset(extend);
1902 }
1903
GetGraphemeClusterLength(int32_t extend,bool isPrefix) const1904 int32_t RenderTextField::GetGraphemeClusterLength(int32_t extend, bool isPrefix) const
1905 {
1906 auto text = GetTextForDisplay(GetEditingValue().text);
1907 char16_t aroundChar = 0;
1908 if (isPrefix) {
1909 if (static_cast<size_t>(extend) <= text.length()) {
1910 aroundChar = text[std::max(0, extend - 1)];
1911 }
1912 } else {
1913 if (static_cast<size_t>(extend) < (text.length())) {
1914 aroundChar = text[std::min(static_cast<int32_t>(text.length() - 1), extend)];
1915 }
1916 }
1917 return StringUtils::NotInUtf16Bmp(aroundChar) ? 2 : 1;
1918 }
1919
ShowCounter() const1920 bool RenderTextField::ShowCounter() const
1921 {
1922 return showCounter_ && maxLength_ < std::numeric_limits<uint32_t>::max();
1923 }
1924
ChangeCounterStyle(const TextEditingValue & value)1925 void RenderTextField::ChangeCounterStyle(const TextEditingValue& value)
1926 {
1927 if (!ShowCounter()) {
1928 return;
1929 }
1930 if (value.GetWideText().size() > maxLength_) {
1931 overCount_ = true;
1932 ChangeBorderToErrorStyle();
1933 } else if (value.GetWideText().size() < maxLength_) {
1934 overCount_ = false;
1935 if (decoration_) {
1936 decoration_->SetBorder(originBorder_);
1937 }
1938 }
1939 }
1940
ChangeBorderToErrorStyle()1941 void RenderTextField::ChangeBorderToErrorStyle()
1942 {
1943 if (!decoration_) {
1944 decoration_ = AceType::MakeRefPtr<Decoration>();
1945 }
1946 const auto& border = decoration_->GetBorder();
1947 BorderEdge errorBorderEdge(errorBorderColor_, errorBorderWidth_, BorderStyle::SOLID);
1948 Border errorBorder;
1949 if (!border.Left().HasValue() && !border.Top().HasValue() && !border.Right().HasValue() &&
1950 border.Bottom().HasValue()) {
1951 // Change over count style for linear input.
1952 errorBorder = Border(BorderEdge(), BorderEdge(), BorderEdge(), errorBorderEdge);
1953 } else {
1954 errorBorder = Border(errorBorderEdge);
1955 }
1956 errorBorder.SetBorderRadius(decoration_->GetBorder().TopLeftRadius());
1957 decoration_->SetBorder(errorBorder);
1958 }
1959
HandleDeviceOrientationChange()1960 void RenderTextField::HandleDeviceOrientationChange()
1961 {
1962 if (deviceOrientation_ != SystemProperties::GetDevcieOrientation()) {
1963 deviceOrientation_ = SystemProperties::GetDevcieOrientation();
1964 if (isOverlayShowed_) {
1965 onKeyboardClose_ = nullptr;
1966 PopTextOverlay();
1967 StartTwinkling();
1968 }
1969 }
1970 }
1971
OnHiddenChanged(bool hidden)1972 void RenderTextField::OnHiddenChanged(bool hidden)
1973 {
1974 if (hidden) {
1975 CloseKeyboard();
1976 PopTextOverlay();
1977 }
1978 }
1979
OnAppHide()1980 void RenderTextField::OnAppHide()
1981 {
1982 RenderNode::OnAppHide();
1983 OnHiddenChanged(true);
1984 }
1985
OnOverlayFocusChange(bool isFocus,bool needCloseKeyboard)1986 void RenderTextField::OnOverlayFocusChange(bool isFocus, bool needCloseKeyboard)
1987 {
1988 isOverlayFocus_ = isFocus;
1989 if (needCloseKeyboard && onOverlayFocusChange_) {
1990 onOverlayFocusChange_(isFocus);
1991 }
1992 }
1993
GetInstanceId() const1994 int32_t RenderTextField::GetInstanceId() const
1995 {
1996 auto context = context_.Upgrade();
1997 if (context) {
1998 return context->GetInstanceId();
1999 }
2000 return 0;
2001 }
2002
Insert(const std::string & text)2003 void RenderTextField::Insert(const std::string& text)
2004 {
2005 auto context = context_.Upgrade();
2006 if (context) {
2007 context->GetTaskExecutor()->PostTask(
2008 [weakPtr = WeakClaim(this), text] {
2009 const auto& textField = weakPtr.Upgrade();
2010 auto value = textField->GetEditingValue();
2011 auto textEditingValue = std::make_shared<TextEditingValue>();
2012 textEditingValue->text = value.GetBeforeSelection() + text + value.GetAfterSelection();
2013 textEditingValue->UpdateSelection(std::max(value.selection.GetStart(), 0) + text.length());
2014 textField->UpdateEditingValue(textEditingValue, true);
2015 },
2016 TaskExecutor::TaskType::UI);
2017 }
2018 }
2019
Delete(int32_t start,int32_t end)2020 void RenderTextField::Delete(int32_t start, int32_t end)
2021 {
2022 auto value = GetEditingValue();
2023 value.Delete(start, end);
2024 SetEditingValue(std::move(value));
2025 if (onValueChange_) {
2026 onValueChange_();
2027 }
2028 }
2029
PopTextOverlay()2030 void RenderTextField::PopTextOverlay()
2031 {
2032 const auto& stackElement = stackElement_.Upgrade();
2033 if (stackElement) {
2034 stackElement->PopTextOverlay();
2035 }
2036 isOverlayShowed_ = false;
2037 }
2038
ProvideRestoreInfo()2039 std::string RenderTextField::ProvideRestoreInfo()
2040 {
2041 if (!onIsCurrentFocus_ || !onIsCurrentFocus_()) {
2042 return "";
2043 }
2044 auto value = GetEditingValue();
2045 auto jsonObj = JsonUtil::Create(true);
2046 jsonObj->Put("start", value.selection.GetStart());
2047 jsonObj->Put("end", value.selection.GetEnd());
2048 return jsonObj->ToString();
2049 }
2050
ApplyRestoreInfo()2051 void RenderTextField::ApplyRestoreInfo()
2052 {
2053 if (GetRestoreInfo().empty()) {
2054 return;
2055 }
2056 auto info = JsonUtil::ParseJsonString(GetRestoreInfo());
2057 if (!info->IsValid() || !info->IsObject()) {
2058 LOGW("RenderTextField:: restore info is invalid");
2059 return;
2060 }
2061 auto jsonStart = info->GetValue("start");
2062 auto jsonEnd = info->GetValue("end");
2063 UpdateSelection(jsonStart->GetInt(), jsonEnd->GetInt());
2064 StartTwinkling();
2065 SetRestoreInfo("");
2066 }
2067
2068 } // namespace OHOS::Ace
2069