• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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_overlay_modifier.h"
17 
18 #include "base/utils/utils.h"
19 #include "core/components_ng/pattern/text_field/text_field_model.h"
20 #include "core/components_ng/pattern/text_field/text_field_pattern.h"
21 #include "core/components_ng/render/drawing_prop_convertor.h"
22 
23 namespace OHOS::Ace::NG {
24 namespace {
25 constexpr int32_t LAND_DURATION = 100;
26 const RefPtr<CubicCurve> LAND_CURVE = AceType::MakeRefPtr<CubicCurve>(0.2, 0, 0.2, 1.0f);
27 constexpr int32_t HALF_RECT = 2;
28 } // namespace
29 
TextFieldOverlayModifier(const WeakPtr<OHOS::Ace::NG::Pattern> & pattern,WeakPtr<ScrollEdgeEffect> && edgeEffect)30 TextFieldOverlayModifier::TextFieldOverlayModifier(
31     const WeakPtr<OHOS::Ace::NG::Pattern>& pattern, WeakPtr<ScrollEdgeEffect>&& edgeEffect)
32     : pattern_(pattern), edgeEffect_(edgeEffect)
33 {
34     auto textFieldPattern = DynamicCast<TextFieldPattern>(pattern_.Upgrade());
35     CHECK_NULL_VOID(textFieldPattern);
36     auto theme = textFieldPattern->GetTheme();
37     CHECK_NULL_VOID(theme);
38     cursorColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(Color()));
39     cursorWidth_ =
40         AceType::MakeRefPtr<AnimatablePropertyFloat>(static_cast<float>(theme->GetCursorWidth().ConvertToPx()));
41     selectedColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(Color()));
42     cursorVisible_ = AceType::MakeRefPtr<PropertyBool>(false);
43     showSelect_ = AceType::MakeRefPtr<PropertyBool>(false);
44     contentSize_ = AceType::MakeRefPtr<PropertySizeF>(SizeF());
45     contentOffset_ = AceType::MakeRefPtr<PropertyOffsetF>(OffsetF());
46     cursorOffset_ = AceType::MakeRefPtr<PropertyOffsetF>(textFieldPattern->GetCaretOffset());
47     floatingCursorOffset_ = AceType::MakeRefPtr<AnimatablePropertyOffsetF>(textFieldPattern->GetCaretOffset());
48     floatingCursorVisible_ = AceType::MakeRefPtr<PropertyBool>(false);
49     showOriginCursor_ = AceType::MakeRefPtr<PropertyBool>(false);
50     frameSize_ = AceType::MakeRefPtr<PropertySizeF>(SizeF());
51     currentOffset_ = AceType::MakeRefPtr<PropertyFloat>(0.0f);
52     underlineWidth_ = AceType::MakeRefPtr<PropertyFloat>(0.0f);
53     underlineColor_ = AceType::MakeRefPtr<PropertyColor>(Color());
54     changeSelectedRects_ = AceType::MakeRefPtr<PropertyBool>(false);
55     firstHandleOffset_ = AceType::MakeRefPtr<PropertyOffsetF>(OffsetF());
56     secondHandleOffset_ = AceType::MakeRefPtr<PropertyOffsetF>(OffsetF());
57     showPreviewText_ = AceType::MakeRefPtr<PropertyBool>(false);
58     changePreviewTextRects_ = AceType::MakeRefPtr<PropertyBool>(false);
59     previewTextDecorationColor_ = AceType::MakeRefPtr<PropertyColor>(Color());
60     previewTextStyle_ = PreviewTextStyle::NORMAL;
61     contentChange_ = AceType::MakeRefPtr<PropertyBool>(false);
62     hoverColor_ = AceType::MakeRefPtr<PropertyInt>(0);
63     ModifierAttachProperty();
64 }
65 
ModifierAttachProperty()66 void TextFieldOverlayModifier::ModifierAttachProperty()
67 {
68     AttachProperty(cursorColor_);
69     AttachProperty(cursorWidth_);
70     AttachProperty(selectedColor_);
71     AttachProperty(cursorVisible_);
72     AttachProperty(showSelect_);
73     AttachProperty(contentSize_);
74     AttachProperty(contentOffset_);
75     AttachProperty(cursorOffset_);
76     AttachProperty(floatingCursorOffset_);
77     AttachProperty(floatingCursorVisible_);
78     AttachProperty(showOriginCursor_);
79     AttachProperty(frameSize_);
80     AttachProperty(currentOffset_);
81     AttachProperty(underlineWidth_);
82     AttachProperty(underlineColor_);
83     AttachProperty(changeSelectedRects_);
84     AttachProperty(firstHandleOffset_);
85     AttachProperty(secondHandleOffset_);
86     AttachProperty(showPreviewText_);
87     AttachProperty(changePreviewTextRects_);
88     AttachProperty(previewTextDecorationColor_);
89     AttachProperty(contentChange_);
90 }
91 
ContentChange()92 void TextFieldOverlayModifier::ContentChange()
93 {
94     CHECK_NULL_VOID(contentChange_);
95     contentChange_->Set(!contentChange_->Get());
96 }
97 
SetFirstHandleOffset(const OffsetF & offset)98 void TextFieldOverlayModifier::SetFirstHandleOffset(const OffsetF& offset)
99 {
100     firstHandleOffset_->Set(offset);
101 }
102 
SetSecondHandleOffset(const OffsetF & offset)103 void TextFieldOverlayModifier::SetSecondHandleOffset(const OffsetF& offset)
104 {
105     secondHandleOffset_->Set(offset);
106 }
107 
onDraw(DrawingContext & context)108 void TextFieldOverlayModifier::onDraw(DrawingContext& context)
109 {
110     auto textFieldPattern = DynamicCast<TextFieldPattern>(pattern_.Upgrade());
111     CHECK_NULL_VOID(textFieldPattern);
112     auto host = textFieldPattern->GetHost();
113     CHECK_NULL_VOID(host);
114     auto& canvas = context.canvas;
115     if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
116         canvas.Save();
117         RSRect clipRect;
118         std::vector<RSPoint> clipRadius;
119         GetFrameRectClip(clipRect, clipRadius);
120         canvas.ClipRoundRect(clipRect, clipRadius, true);
121     }
122     PaintCursor(context);
123     PaintFloatingCursor(context);
124     PaintSelection(context);
125     if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
126         canvas.Restore();
127     }
128     PaintScrollBar(context);
129     PaintEdgeEffect(frameSize_->Get(), context.canvas);
130     PaintUnderline(context.canvas);
131     PaintPreviewTextDecoration(context);
132     if (host->GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
133         RSBrush brush;
134         brush.SetAntiAlias(true);
135         brush.SetColor(hoverColor_->Get());
136         canvas.AttachBrush(brush);
137         for (const auto& hoverRects : hoverRects_) {
138             auto rect = hoverRects.GetRect();
139             RSRect rsRect(rect.Left(), rect.Top(), rect.Right(), rect.Bottom());
140             canvas.DrawRoundRect(RSRoundRect(rsRect, rect.Width() / HALF_RECT, rect.Height() / HALF_RECT));
141         }
142         canvas.DetachBrush();
143         canvas.Restore();
144     }
145 }
146 
SetHoverColorAndRects(const std::vector<RoundRect> & hoverRects,uint32_t hoverColor)147 void TextFieldOverlayModifier::SetHoverColorAndRects(
148     const std::vector<RoundRect>& hoverRects, uint32_t hoverColor)
149 {
150     CHECK_NULL_VOID(hoverColor);
151     hoverRects_ = hoverRects;
152     hoverColor_->Set(static_cast<int32_t>(hoverColor));
153 }
154 
ClearHoverColorAndRects()155 void TextFieldOverlayModifier::ClearHoverColorAndRects()
156 {
157     hoverRects_.clear();
158 }
159 
GetFrameRectClip(RSRect & clipRect,std::vector<RSPoint> & clipRadius)160 void TextFieldOverlayModifier::GetFrameRectClip(RSRect& clipRect, std::vector<RSPoint>& clipRadius)
161 {
162     auto textFieldPattern = DynamicCast<TextFieldPattern>(pattern_.Upgrade());
163     CHECK_NULL_VOID(textFieldPattern);
164     auto host = textFieldPattern->GetHost();
165     CHECK_NULL_VOID(host);
166     auto renderContext = host->GetRenderContext();
167     CHECK_NULL_VOID(renderContext);
168     auto textFrameRect = textFieldPattern->GetFrameRect();
169     clipRect = RSRect(0.0f, 0.0f, textFrameRect.Width(), textFrameRect.Height());
170     auto radius = renderContext->GetBorderRadius().value_or(BorderRadiusProperty());
171     auto radiusTopLeft = RSPoint(static_cast<float>(radius.radiusTopLeft.value_or(0.0_vp).ConvertToPx()),
172         static_cast<float>(radius.radiusTopLeft.value_or(0.0_vp).ConvertToPx()));
173     clipRadius.emplace_back(radiusTopLeft);
174     auto radiusTopRight = RSPoint(static_cast<float>(radius.radiusTopRight.value_or(0.0_vp).ConvertToPx()),
175         static_cast<float>(radius.radiusTopRight.value_or(0.0_vp).ConvertToPx()));
176     clipRadius.emplace_back(radiusTopRight);
177     auto radiusBottomRight = RSPoint(static_cast<float>(radius.radiusBottomRight.value_or(0.0_vp).ConvertToPx()),
178         static_cast<float>(radius.radiusBottomRight.value_or(0.0_vp).ConvertToPx()));
179     clipRadius.emplace_back(radiusBottomRight);
180     auto radiusBottomLeft = RSPoint(static_cast<float>(radius.radiusBottomLeft.value_or(0.0_vp).ConvertToPx()),
181         static_cast<float>(radius.radiusBottomLeft.value_or(0.0_vp).ConvertToPx()));
182     clipRadius.emplace_back(radiusBottomLeft);
183 }
184 
PaintUnderline(RSCanvas & canvas) const185 void TextFieldOverlayModifier::PaintUnderline(RSCanvas& canvas) const
186 {
187     auto textFieldPattern = DynamicCast<TextFieldPattern>(pattern_.Upgrade());
188     CHECK_NULL_VOID(textFieldPattern);
189     auto layoutProperty = textFieldPattern->GetLayoutProperty<TextFieldLayoutProperty>();
190     CHECK_NULL_VOID(layoutProperty);
191     if (!(layoutProperty->GetShowUnderlineValue(false) && textFieldPattern->IsUnspecifiedOrTextType())) {
192         return;
193     }
194     if (textFieldPattern->IsNormalInlineState() && textFieldPattern->HasFocus()) {
195         return;
196     }
197     auto contentRect = textFieldPattern->GetContentRect();
198     auto textFrameRect = textFieldPattern->GetFrameRect();
199     auto responseArea = textFieldPattern->GetResponseArea();
200     auto responseAreaWidth = responseArea ? responseArea->GetAreaRect().Width() : 0.0f;
201     auto clearNodeResponseArea = textFieldPattern->GetCleanNodeResponseArea();
202     responseAreaWidth += clearNodeResponseArea ? clearNodeResponseArea->GetAreaRect().Width() : 0.0f;
203     auto hasResponseArea = GreatNotEqual(responseAreaWidth, 0.0f);
204     auto isRTL = layoutProperty->GetNonAutoLayoutDirection() == TextDirection::RTL;
205     Point leftPoint;
206     Point rightPoint;
207     auto host = textFieldPattern->GetHost();
208     CHECK_NULL_VOID(host);
209     auto isGreatAPI18 = host->GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN);
210     auto isNeedToAddPadding = isGreatAPI18 && textFieldPattern->IsUnderlineAndButtonMode();
211     if (isRTL) {
212         auto contentLeft = isNeedToAddPadding ? contentRect.Left() - textFieldPattern->GetPaddingLeft() :
213             contentRect.Left();
214         leftPoint.SetX(hasResponseArea ? 0.0 : contentLeft);
215         rightPoint.SetX(contentRect.Right());
216     } else {
217         auto contentRight = isNeedToAddPadding ? contentRect.Right() + textFieldPattern->GetPaddingRight() :
218             contentRect.Right();
219         leftPoint.SetX(contentRect.Left());
220         rightPoint.SetX(hasResponseArea ? textFrameRect.Width() : contentRight);
221     }
222 
223     leftPoint.SetY(textFrameRect.Height());
224     rightPoint.SetY(textFrameRect.Height());
225 
226     RSPen pen;
227     pen.SetColor(ToRSColor(underlineColor_->Get()));
228     pen.SetWidth(underlineWidth_->Get());
229     pen.SetAntiAlias(true);
230     canvas.AttachPen(pen);
231     canvas.DrawLine(ToRSPoint(PointF(leftPoint.GetX(), leftPoint.GetY())),
232         ToRSPoint(PointF(rightPoint.GetX(), rightPoint.GetY())));
233     canvas.DetachPen();
234 }
235 
PaintSelection(DrawingContext & context) const236 void TextFieldOverlayModifier::PaintSelection(DrawingContext& context) const
237 {
238     if (!showSelect_->Get() && !needPaintSelect_) {
239         return;
240     }
241     auto& canvas = context.canvas;
242     canvas.Save();
243     auto textFieldPattern = DynamicCast<TextFieldPattern>(pattern_.Upgrade());
244     CHECK_NULL_VOID(textFieldPattern);
245     auto host = textFieldPattern->GetHost();
246     CHECK_NULL_VOID(host);
247     auto pipelineContext = host->GetContext();
248     CHECK_NULL_VOID(pipelineContext);
249     auto themeManager = pipelineContext->GetThemeManager();
250     CHECK_NULL_VOID(themeManager);
251     auto theme = themeManager->GetTheme<TextFieldTheme>();
252     RSBrush brush;
253     brush.SetAntiAlias(true);
254     brush.SetColor(ToRSColor(selectedColor_->Get()));
255     canvas.AttachBrush(brush);
256     auto paintOffset = textFieldPattern->GetContentRect().GetOffset();
257     auto textBoxes = textFieldPattern->GetTextBoxesForSelect();
258     auto textRect = textFieldPattern->GetTextRect();
259     bool isTextArea = textFieldPattern->IsTextArea();
260     float clipRectHeight = 0.0f;
261     clipRectHeight = paintOffset.GetY() + contentSize_->Get().Height();
262     RSRect clipInnerRect;
263     auto defaultStyle = !textFieldPattern->IsNormalInlineState() || isTextArea;
264     if (defaultStyle) {
265         clipInnerRect = RSRect(paintOffset.GetX(), paintOffset.GetY(),
266             paintOffset.GetX() + contentSize_->Get().Width() + textFieldPattern->GetInlinePadding(), clipRectHeight);
267         canvas.ClipRect(clipInnerRect, RSClipOp::INTERSECT);
268     } else {
269         clipInnerRect = RSRect(paintOffset.GetX(), 0.0f, paintOffset.GetX() + contentSize_->Get().Width(),
270             textFieldPattern->GetFrameRect().Height());
271         canvas.ClipRect(clipInnerRect, RSClipOp::INTERSECT);
272     }
273     // for default style, selection height is equal to the content height
274     for (const auto& textBox : textBoxes) {
275         canvas.DrawRect(RSRect(textBox.Left() + (isTextArea ? contentOffset_->Get().GetX() : textRect.GetX()),
276             defaultStyle
277                 ? (textBox.Top() + (isTextArea ? textRect.GetY() : contentOffset_->Get().GetY()))
278                 : 0.0f,
279             textBox.Right() + (isTextArea ? contentOffset_->Get().GetX() : textRect.GetX()),
280             defaultStyle
281                 ? (textBox.Bottom() + (isTextArea ? textRect.GetY() : contentOffset_->Get().GetY()))
282                          : textFieldPattern->GetFrameRect().Height()));
283     }
284     canvas.DetachBrush();
285     canvas.Restore();
286 }
287 
PaintCursor(DrawingContext & context) const288 void TextFieldOverlayModifier::PaintCursor(DrawingContext& context) const
289 {
290     float cursorWidth = static_cast<float>(cursorWidth_->Get());
291     if (NearZero(cursorWidth)) {
292         return; // will not draw cursor
293     }
294 
295     auto& canvas = context.canvas;
296     auto textFieldPattern = DynamicCast<TextFieldPattern>(pattern_.Upgrade());
297     CHECK_NULL_VOID(textFieldPattern);
298     auto magnifierController = textFieldPattern->GetMagnifierController();
299     CHECK_NULL_VOID(magnifierController);
300 
301     auto showOriginCursor = floatingCursorVisible_->Get() && showOriginCursor_->Get();
302     auto cursorVisible = floatingCursorVisible_->Get() ? showOriginCursor_->Get() : cursorVisible_->Get();
303     if (!cursorVisible || textFieldPattern->IsSelected()) {
304         return;
305     }
306     canvas.Save();
307 
308     RSPen pen;
309     pen.SetAntiAlias(true);
310     pen.SetWidth(cursorWidth);
311     pen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
312 
313     if (showOriginCursor) {
314         pen.SetColor(ToRSColor(LinearColor(textFieldPattern->GetOriginCursorColor())));
315     } else {
316         pen.SetColor(ToRSColor(cursorColor_->Get()));
317     }
318     canvas.AttachPen(pen);
319     auto paintOffset = contentOffset_->Get();
320     ACE_LAYOUT_SCOPED_TRACE("PaintCursor[offset:%f, %f]", paintOffset.GetX(), paintOffset.GetY());
321     float clipRectHeight = 0.0f;
322     clipRectHeight = paintOffset.GetY() + contentSize_->Get().Height();
323     RSRect clipInnerRect(paintOffset.GetX(), paintOffset.GetY(),
324         // add extra clip space for cases such as auto width
325         paintOffset.GetX() + contentSize_->Get().Width() +
326             (LessOrEqual(contentSize_->Get().Width(), 0.0) ? cursorWidth_->Get() : 0.0f),
327         clipRectHeight);
328     canvas.ClipRect(clipInnerRect, RSClipOp::INTERSECT);
329 
330     auto caretRect = textFieldPattern->GetCaretRect();
331     float midPosX = caretRect.GetX() + cursorWidth / 2;
332     float startPosY = caretRect.GetY();
333     float endPosY = caretRect.GetY() + caretRect.Height();
334     float roundCapRadius = static_cast<float>(cursorWidth_->Get()) / 2;
335     canvas.DrawLine(RSPoint(midPosX, startPosY + roundCapRadius),
336         RSPoint(midPosX, endPosY - roundCapRadius));
337     canvas.DetachPen();
338     canvas.Restore();
339 }
340 
PaintFloatingCursor(DrawingContext & context) const341 void TextFieldOverlayModifier::PaintFloatingCursor(DrawingContext& context) const
342 {
343     float cursorWidth = static_cast<float>(cursorWidth_->Get());
344     if (NearZero(cursorWidth)) {
345         return; // will not draw cursor
346     }
347 
348     auto& canvas = context.canvas;
349     auto textFieldPattern = DynamicCast<TextFieldPattern>(pattern_.Upgrade());
350     CHECK_NULL_VOID(textFieldPattern);
351     if (!floatingCursorVisible_->Get() || textFieldPattern->IsSelected()) {
352         return;
353     }
354     canvas.Save();
355 
356     RSPen pen;
357     pen.SetAntiAlias(true);
358     pen.SetWidth(cursorWidth);
359     pen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
360     pen.SetColor(ToRSColor(cursorColor_->Get()));
361     canvas.AttachPen(pen);
362     auto paintOffset = contentOffset_->Get();
363     ACE_LAYOUT_SCOPED_TRACE("PaintCursor[offset:%f, %f]", paintOffset.GetX(), paintOffset.GetY());
364     float clipRectHeight = 0.0f;
365     clipRectHeight = paintOffset.GetY() + contentSize_->Get().Height();
366     RSRect clipInnerRect(paintOffset.GetX(), paintOffset.GetY(),
367         // add extra clip space for cases such as auto width
368         paintOffset.GetX() + contentSize_->Get().Width() +
369             (LessOrEqual(contentSize_->Get().Width(), 0.0) ? cursorWidth_->Get() : 0.0f),
370         clipRectHeight);
371     canvas.ClipRect(clipInnerRect, RSClipOp::INTERSECT);
372 
373     auto caretRect = textFieldPattern->GetFloatingCaretRect();
374     auto floatingOffset = floatingCursorOffset_->Get();
375     float midPosX = floatingOffset.GetX() + cursorWidth / 2;
376     float startPosY = floatingOffset.GetY();
377     float endPosY = floatingOffset.GetY() + caretRect.Height();
378     float roundCapRadius = static_cast<float>(cursorWidth_->Get()) / 2;
379     canvas.DrawLine(RSPoint(midPosX, startPosY + roundCapRadius),
380         RSPoint(midPosX, endPosY - roundCapRadius));
381     canvas.DetachPen();
382     canvas.Restore();
383 }
384 
StartFloatingCaretLand(const OffsetF & originCaretOffset)385 void TextFieldOverlayModifier::StartFloatingCaretLand(const OffsetF& originCaretOffset)
386 {
387     AnimationOption option = AnimationOption();
388     option.SetDuration(LAND_DURATION);
389     option.SetCurve(LAND_CURVE);
390     caretLanding_ = true;
391     auto pattern = pattern_.Upgrade();
392     auto host = pattern ? pattern->GetHost() : nullptr;
393     auto contextPtr = host ? host->GetContextRefPtr() : nullptr;
394     AnimationUtils::Animate(
395         option,
396         [weak = WeakClaim(this), originCaretOffset]() {
397             auto modifier = weak.Upgrade();
398             CHECK_NULL_VOID(modifier);
399             modifier->SetFloatingCursorOffset(originCaretOffset);
400         },
401         [weak = WeakClaim(this), pattern = pattern_]() {
402             auto textField = DynamicCast<TextFieldPattern>(pattern.Upgrade());
403             CHECK_NULL_VOID(textField);
404             auto modifier = weak.Upgrade();
405             CHECK_NULL_VOID(modifier);
406             modifier->SetFloatCaretLanding(false);
407             textField->ResetFloatingCursorState();
408             auto textFieldHost = textField->GetHost();
409             CHECK_NULL_VOID(textFieldHost);
410             textFieldHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
411         },
412         nullptr, contextPtr);
413 }
414 
PaintEdgeEffect(const SizeF & frameSize,RSCanvas & canvas)415 void TextFieldOverlayModifier::PaintEdgeEffect(const SizeF& frameSize, RSCanvas& canvas)
416 {
417     auto edgeEffect = edgeEffect_.Upgrade();
418     CHECK_NULL_VOID(edgeEffect);
419     edgeEffect->Paint(canvas, frameSize, { 0.0f, 0.0f });
420 }
421 
PaintScrollBar(DrawingContext & context)422 void TextFieldOverlayModifier::PaintScrollBar(DrawingContext& context)
423 {
424     auto textFieldPattern = DynamicCast<TextFieldPattern>(pattern_.Upgrade());
425     CHECK_NULL_VOID(textFieldPattern);
426     if (textFieldPattern->GetScrollBarVisible() && textFieldPattern->IsTextArea()) {
427         ScrollBarOverlayModifier::onDraw(context);
428     }
429 }
430 
PaintPreviewTextDecoration(DrawingContext & context) const431 void TextFieldOverlayModifier::PaintPreviewTextDecoration(DrawingContext& context) const
432 {
433     if (previewTextStyle_ != PreviewTextStyle::UNDERLINE ||
434         (!showPreviewText_->Get() && !needPaintPreviewText)) {
435         return;
436     }
437 
438     auto& canvas = context.canvas;
439     canvas.Save();
440     auto textFieldPattern = DynamicCast<TextFieldPattern>(pattern_.Upgrade());
441     CHECK_NULL_VOID(textFieldPattern);
442     auto host = textFieldPattern->GetHost();
443     CHECK_NULL_VOID(host);
444     auto pipelineContext = host->GetContext();
445     CHECK_NULL_VOID(pipelineContext);
446     auto themeManager = pipelineContext->GetThemeManager();
447     CHECK_NULL_VOID(themeManager);
448     auto theme = themeManager->GetTheme<TextFieldTheme>();
449 
450     auto textRect = textFieldPattern->GetTextRect();
451     bool isTextArea = textFieldPattern->IsTextArea();
452 
453     float offsetX = isTextArea ? contentOffset_->Get().GetX() : textRect.GetX();
454     float offsetY = isTextArea ? textRect.GetY() : contentOffset_->Get().GetY();
455     auto previewTextRect = textFieldPattern->GetPreviewTextRects();
456     if (previewTextRect.empty()) {
457         return;
458     }
459 
460     auto paintOffset = contentOffset_->Get();
461     float clipRectHeight = paintOffset.GetY() + contentSize_->Get().Height();
462     RSRect clipInnerRect;
463     auto defaultStyle = !textFieldPattern->IsNormalInlineState() || isTextArea;
464     if (defaultStyle) {
465         clipInnerRect = RSRect(paintOffset.GetX(), paintOffset.GetY(),
466             paintOffset.GetX() + contentSize_->Get().Width() + textFieldPattern->GetInlinePadding(), clipRectHeight);
467         canvas.ClipRect(clipInnerRect, RSClipOp::INTERSECT);
468     } else {
469         clipInnerRect = RSRect(paintOffset.GetX(), 0.0f, paintOffset.GetX() + contentSize_->Get().Width(),
470             textFieldPattern->GetFrameRect().Height());
471         canvas.ClipRect(clipInnerRect, RSClipOp::INTERSECT);
472     }
473 
474     auto underlineWidth = textFieldPattern->GetPreviewUnderlineWidth();
475     RSBrush brush;
476     brush.SetAntiAlias(true);
477     brush.SetColor(ToRSColor(previewTextDecorationColor_->Get()));
478     canvas.AttachBrush(brush);
479     for (const auto& drawRect : previewTextRect) {
480         RSRect rect(drawRect.Left() + offsetX, drawRect.Bottom() + offsetY - underlineWidth,
481                 drawRect.Right() + offsetX, drawRect.Bottom() + offsetY);
482         canvas.DrawRoundRect(RSRoundRect(rect, underlineWidth / 2, underlineWidth / 2));
483     }
484     canvas.DetachBrush();
485     canvas.Restore();
486 }
487 
SetCursorColor(Color & value)488 void TextFieldOverlayModifier::SetCursorColor(Color& value)
489 {
490     cursorColor_->Set(LinearColor(value));
491 }
492 
SetCursorWidth(float value)493 void TextFieldOverlayModifier::SetCursorWidth(float value)
494 {
495     cursorWidth_->Set(value);
496 }
497 
SetSelectedBackGroundColor(Color & value)498 void TextFieldOverlayModifier::SetSelectedBackGroundColor(Color& value)
499 {
500     selectedColor_->Set(LinearColor(value));
501 }
502 
SetCursorVisible(bool value)503 void TextFieldOverlayModifier::SetCursorVisible(bool value)
504 {
505     cursorVisible_->Set(value);
506 }
507 
SetContentSize(SizeF & value)508 void TextFieldOverlayModifier::SetContentSize(SizeF& value)
509 {
510     contentSize_->Set(value);
511 }
512 
SetContentOffset(OffsetF & value)513 void TextFieldOverlayModifier::SetContentOffset(OffsetF& value)
514 {
515     contentOffset_->Set(value);
516 }
517 
SetCursorOffset(const OffsetF & value)518 void TextFieldOverlayModifier::SetCursorOffset(const OffsetF& value)
519 {
520     cursorOffset_->Set(value);
521 }
522 
SetFloatingCursorOffset(const OffsetF & value)523 void TextFieldOverlayModifier::SetFloatingCursorOffset(const OffsetF& value)
524 {
525     floatingCursorOffset_->Set(value);
526 }
527 
SetFloatingCursorVisible(bool value)528 void TextFieldOverlayModifier::SetFloatingCursorVisible(bool value)
529 {
530     floatingCursorVisible_->Set(value);
531 }
532 
SetShowOriginCursor(bool value)533 void TextFieldOverlayModifier::SetShowOriginCursor(bool value)
534 {
535     showOriginCursor_->Set(value);
536 }
537 
538 
SetInputStyle(InputStyle & value)539 void TextFieldOverlayModifier::SetInputStyle(InputStyle& value)
540 {
541     inputStyle_ = value;
542 }
543 
SetFrameSize(const SizeF & value)544 void TextFieldOverlayModifier::SetFrameSize(const SizeF& value)
545 {
546     frameSize_->Set(value);
547 }
548 
SetCurrentOffset(float value)549 void TextFieldOverlayModifier::SetCurrentOffset(float value)
550 {
551     currentOffset_->Set(value);
552 }
553 
SetUnderlineWidth(float value)554 void TextFieldOverlayModifier::SetUnderlineWidth(float value)
555 {
556     underlineWidth_->Set(value);
557 }
558 
SetUnderlineColor(const Color & value)559 void TextFieldOverlayModifier::SetUnderlineColor(const Color& value)
560 {
561     underlineColor_->Set(value);
562 }
563 
SetScrollBar(const RefPtr<ScrollBar> & scrollBar)564 void TextFieldOverlayModifier::SetScrollBar(const RefPtr<ScrollBar>& scrollBar)
565 {
566     scrollBar_ = scrollBar;
567 }
568 
SetChangeSelectedRects(bool value)569 void TextFieldOverlayModifier::SetChangeSelectedRects(bool value)
570 {
571     if (value) {
572         changeSelectedRects_->Set(!changeSelectedRects_->Get());
573     }
574     needPaintSelect_ = value;
575 }
576 
SetShowSelect(bool value)577 void TextFieldOverlayModifier::SetShowSelect(bool value)
578 {
579     showSelect_->Set(value);
580 }
SetShowPreviewTextDecoration(bool value)581 void TextFieldOverlayModifier::SetShowPreviewTextDecoration(bool value)
582 {
583     showPreviewText_->Set(value);
584 }
SetPreviewTextRects(bool value)585 void TextFieldOverlayModifier::SetPreviewTextRects(bool value)
586 {
587     if (value) {
588         changePreviewTextRects_->Set(!changePreviewTextRects_->Get());
589     }
590     needPaintPreviewText = value;
591 }
SetPreviewTextDecorationColor(const Color & value)592 void TextFieldOverlayModifier::SetPreviewTextDecorationColor(const Color& value)
593 {
594     previewTextDecorationColor_->Set(value);
595 }
SetPreviewTextStyle(PreviewTextStyle style)596 void TextFieldOverlayModifier::SetPreviewTextStyle(PreviewTextStyle style)
597 {
598     previewTextStyle_ = style;
599 }
600 } // namespace OHOS::Ace::NG
601