• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 "rosen_render_text_field.h"
17 
18 #include <cmath>
19 
20 #ifndef USE_GRAPHIC_TEXT_GINE
21 #include "txt/paragraph_builder.h"
22 #include "txt/paragraph_txt.h"
23 #else
24 #include "rosen_text/typography.h"
25 #include "rosen_text/typography_create.h"
26 #endif
27 #include "include/effects/SkGradientShader.h"
28 #include "render_service_client/core/ui/rs_node.h"
29 #include "unicode/uchar.h"
30 
31 #include "base/i18n/localization.h"
32 #include "base/utils/string_utils.h"
33 #include "base/utils/system_properties.h"
34 #include "core/common/text_field_manager.h"
35 #include "core/components/box/render_box_base.h"
36 #include "core/components/calendar/rosen_render_calendar.h"
37 #include "core/components/common/painter/rosen_decoration_painter.h"
38 #include "core/components/common/painter/rosen_scroll_bar_painter.h"
39 #include "core/components/font/constants_converter.h"
40 #include "core/components/font/rosen_font_collection.h"
41 #include "core/pipeline/base/rosen_render_context.h"
42 
43 #if defined(ENABLE_STANDARD_INPUT)
44 #include "core/components/text_field/on_text_changed_listener_impl.h"
45 #endif
46 
47 namespace OHOS::Ace {
48 namespace {
49 
50 constexpr char16_t NEWLINE_CODE = u'\n';
51 // pixel for how far the caret to the top of paint rect. Sometimes may leave some space for the floor.
52 constexpr Color INLINE_STYLE_SELECTED_COLOR = Color(0x1A0A59F7);
53 constexpr double CARET_HEIGHT_OFFSET = -2.0;
54 constexpr Dimension CURSOR_WIDTH = 1.5_vp;
55 constexpr Dimension COUNT_SPACING = 4.0_vp;
56 constexpr double MAGNIFIER_GAIN = 1.25;
57 const char ELLIPSIS[] = "...";
58 constexpr Dimension DEFAULT_FOCUS_BORDER_WIDTH = 2.0_vp;
59 constexpr uint32_t DEFAULT_FOCUS_BORDER_COLOR = 0xFF254FF7;
60 constexpr double HALF = 0.5;
61 constexpr char16_t OPTICITY = 255;
62 
63 } // namespace
64 
65 // The outer rect has a decoration, return the inner rect excluded the decoration.
GetInnerRect(const Decoration & decoration,const Rect & outer,double dipScale) const66 Rect RosenRenderTextField::GetInnerRect(const Decoration& decoration, const Rect& outer, double dipScale) const
67 {
68     auto leftWidth = decoration.GetBorder().Left().GetWidth().ConvertToPx(dipScale) +
69                      NormalizePercentToPx(decoration.GetPadding().Left(), false);
70     auto topWidth = decoration.GetBorder().Top().GetWidth().ConvertToPx(dipScale) +
71                     NormalizePercentToPx(decoration.GetPadding().Top(), true);
72     auto rightWidth = decoration.GetBorder().Right().GetWidth().ConvertToPx(dipScale) +
73                       NormalizePercentToPx(decoration.GetPadding().Right(), false);
74     auto bottomWidth = decoration.GetBorder().Bottom().GetWidth().ConvertToPx(dipScale) +
75                        NormalizePercentToPx(decoration.GetPadding().Bottom(), true);
76     if (textDirection_ == TextDirection::RTL) {
77         leftWidth += paddingHorizonForSearch_;
78     } else {
79         rightWidth += paddingHorizonForSearch_;
80     }
81     double iconSpacing = iconImage_ ? NormalizeToPx(iconHotZoneSizeInDimension_) : 0.0;
82     double passwordIconSpacing = (keyboard_ == TextInputType::VISIBLE_PASSWORD && IsSelectiveDevice())
83                                      ? NormalizeToPx(iconHotZoneSizeInDimension_)
84                                      : 0.0;
85     if (textDirection_ == TextDirection::RTL) {
86         return Rect(outer.Left() + leftWidth + passwordIconSpacing, outer.Top() + topWidth,
87             outer.Right() - rightWidth - leftWidth - iconSpacing - passwordIconSpacing,
88             outer.Bottom() - bottomWidth - topWidth);
89     } else {
90         return Rect(outer.Left() + leftWidth + iconSpacing, outer.Top() + topWidth,
91             outer.Right() - rightWidth - leftWidth - iconSpacing - passwordIconSpacing,
92             outer.Bottom() - bottomWidth - topWidth);
93     }
94 }
95 
GetCaretRect(int32_t extent,Rect & caretRect,double caretHeightOffset) const96 bool RosenRenderTextField::GetCaretRect(int32_t extent, Rect& caretRect, double caretHeightOffset) const
97 {
98     CaretMetrics metrics;
99     bool computeSuccess = false;
100     DirectionStatus directionStatus = GetDirectionStatusOfPosition(extent);
101     if (extent != 0 && extent != static_cast<int32_t>(GetEditingValue().GetWideText().length()) &&
102         (directionStatus == DirectionStatus::LEFT_RIGHT || directionStatus == DirectionStatus::RIGHT_LEFT) &&
103         cursorPositionType_ != CursorPositionType::NONE && LessOrEqual(clickOffset_.GetX(), innerRect_.Width())) {
104         computeSuccess = ComputeOffsetForCaretCloserToClick(cursorPositionForShow_, metrics);
105     } else {
106         if (textAffinity_ == TextAffinity::DOWNSTREAM) {
107             computeSuccess =
108                 ComputeOffsetForCaretDownstream(extent, metrics) || ComputeOffsetForCaretUpstream(extent, metrics);
109         } else {
110             computeSuccess =
111                 ComputeOffsetForCaretUpstream(extent, metrics) || ComputeOffsetForCaretDownstream(extent, metrics);
112         }
113     }
114     if (computeSuccess && !GetEditingValue().text.empty()) {
115         if (metrics.height <= 0 || std::isnan(metrics.height)) {
116             // The reason may be text lines is exceed the paragraph maxline.
117             return false;
118         }
119         caretRect.SetRect(metrics.offset.GetX(), metrics.offset.GetY() + caretHeightOffset, NormalizeToPx(CURSOR_WIDTH),
120             metrics.height - caretHeightOffset * 2.0);
121     } else {
122         // Use proto caret.
123         caretRect = caretProto_ + MakeEmptyOffset();
124     }
125     return true;
126 }
127 
128 #ifndef USE_ROSEN_DRAWING
PaintCaret(SkCanvas & canvas,const Rect & caretRect)129 void RosenRenderTextField::PaintCaret(SkCanvas& canvas, const Rect& caretRect)
130 #else
131 void RosenRenderTextField::PaintCaret(RSCanvas& canvas, const Rect& caretRect)
132 #endif
133 {
134     // We simply not to draw the caret rather than do an alpha animation.
135     if (!caretRect_.IsValid() || !showCursor_ || !cursorVisibility_) {
136         return;
137     }
138 #ifndef USE_ROSEN_DRAWING
139     SkPaint paint;
140 #else
141     RSBrush brush;
142 #endif
143     Color cursorColor = cursorColor_;
144     if (!cursorColorIsSet_) {
145         // Default strategy: Keep color same with text.
146         cursorColor = style_.GetTextColor();
147     }
148 #ifndef USE_ROSEN_DRAWING
149     paint.setColor(Constants::ConvertSkColor(cursorColor));
150     paint.setAntiAlias(true);
151     if (NearZero(cursorRadius_.Value())) {
152         canvas.drawRect(
153             SkRect::MakeLTRB(caretRect.Left(), caretRect.Top(), caretRect.Right(), caretRect.Bottom()), paint);
154     } else {
155         const SkScalar radius = SkDoubleToScalar(NormalizeToPx(cursorRadius_));
156         SkRRect rrect;
157         rrect.setRectXY(SkRect::MakeLTRB(SkDoubleToScalar(caretRect.Left()), SkDoubleToScalar(caretRect.Top()),
158                             SkDoubleToScalar(caretRect.Right()), SkDoubleToScalar(caretRect.Bottom())),
159             radius, radius);
160         canvas.drawRRect(rrect, paint);
161     }
162 #else
163     brush.SetColor(cursorColor.GetValue());
164     brush.SetAntiAlias(true);
165     canvas.AttachBrush(brush);
166     if (NearZero(cursorRadius_.Value())) {
167         canvas.DrawRect(RSRect(caretRect.Left(), caretRect.Top(), caretRect.Right(), caretRect.Bottom()));
168     } else {
169         const RSScalar radius = static_cast<RSScalar>(NormalizeToPx(cursorRadius_));
170         RSRoundRect rrect(RSRect(static_cast<RSScalar>(caretRect.Left()), static_cast<RSScalar>(caretRect.Top()),
171                               static_cast<RSScalar>(caretRect.Right()), static_cast<RSScalar>(caretRect.Bottom())),
172             radius, radius);
173         canvas.DrawRoundRect(rrect);
174     }
175     canvas.DetachBrush();
176 #endif
177 }
178 
179 #ifndef USE_ROSEN_DRAWING
PaintSelectCaret(SkCanvas * canvas)180 void RosenRenderTextField::PaintSelectCaret(SkCanvas* canvas)
181 #else
182 void RosenRenderTextField::PaintSelectCaret(RSCanvas* canvas)
183 #endif
184 {
185     if (!isOverlayShowed_ || !paragraph_) {
186         return;
187     }
188 
189 #ifndef USE_ROSEN_DRAWING
190     SkPaint paint;
191     paint.setAntiAlias(true);
192     paint.setColor(cursorColor_.GetValue());
193     paint.setStrokeWidth(caretRect_.Width());
194     paint.setStrokeCap(SkPaint::Cap::kRound_Cap);
195 #else
196     RSPen pen;
197     pen.SetAntiAlias(true);
198     pen.SetColor(cursorColor_.GetValue());
199     pen.SetWidth(caretRect_.Width());
200     pen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
201 #endif
202 
203     Rect caretRect = caretRect_;
204     // 1.0_dp is UX design.
205     caretRect = caretRect + Offset(0.0, -CARET_HEIGHT_OFFSET - NormalizeToPx(1.0_vp)) +
206                 Size(0.0, (CARET_HEIGHT_OFFSET + NormalizeToPx(1.0_vp)) * 2.0);
207     if (IsSingleHandle()) {
208 #ifndef USE_ROSEN_DRAWING
209         canvas->drawLine((caretRect.Left() + caretRect.Right()) / 2.0, caretRect.Top(),
210             (caretRect.Top(), caretRect.Left() + caretRect.Right()) / 2.0, caretRect.Bottom(), paint);
211 #else
212         canvas->AttachPen(pen);
213         canvas->DrawLine(RSPoint((caretRect.Left() + caretRect.Right()) / 2.0, caretRect.Top()),
214             RSPoint((caretRect.Top(), caretRect.Left() + caretRect.Right()) / 2.0, caretRect.Bottom()));
215         canvas->DetachPen();
216 #endif
217     }
218 
219     const auto& selection = GetEditingValue().selection;
220     int32_t start = selection.GetStart();
221     int32_t end = selection.GetEnd();
222 
223 #ifndef USE_GRAPHIC_TEXT_GINE
224     const auto& boxes = paragraph_->GetRectsForRange(selection.GetStart(), selection.GetEnd(),
225         txt::Paragraph::RectHeightStyle::kMax, txt::Paragraph::RectWidthStyle::kTight);
226 #else
227     const auto& boxes = paragraph_->GetTextRectsByBoundary(selection.GetStart(), selection.GetEnd(),
228         Rosen::TextRectHeightStyle::COVER_TOP_AND_BOTTOM, Rosen::TextRectWidthStyle::TIGHT);
229 #endif
230     if (!boxes.empty()) {
231 #ifndef USE_GRAPHIC_TEXT_GINE
232         Offset startCaretOffset = Offset(
233             boxes.back().rect.fRight - boxes.front().rect.fLeft, boxes.back().rect.fTop - boxes.front().rect.fTop);
234 #else
235         Offset startCaretOffset = Offset(boxes.back().rect.GetRight() - boxes.front().rect.GetLeft(),
236             boxes.back().rect.GetTop() - boxes.front().rect.GetTop());
237 #endif
238         if (start >= GetInitIndex() && end >= GetInitIndex()) {
239             startCaretRect_ = caretRect + startCaretOffset;
240         } else {
241             startCaretRect_ = caretRect - startCaretOffset;
242         }
243     } else {
244         startCaretRect_ = caretRect;
245     }
246 
247     // Draw line
248     if (IsSingleHandle()) {
249 #ifndef USE_ROSEN_DRAWING
250         canvas->drawLine((startCaretRect_.Left() + startCaretRect_.Right()) / 2.0, startCaretRect_.Top(),
251             (startCaretRect_.Top(), startCaretRect_.Left() + startCaretRect_.Right()) / 2.0, startCaretRect_.Bottom(),
252             paint);
253 #else
254         canvas->AttachPen(pen);
255         canvas->DrawLine(RSPoint((startCaretRect_.Left() + startCaretRect_.Right()) / 2.0, startCaretRect_.Top()),
256             RSPoint((startCaretRect_.Top(), startCaretRect_.Left() + startCaretRect_.Right()) / 2.0,
257                 startCaretRect_.Bottom()));
258         canvas->DetachPen();
259 #endif
260     }
261 }
262 
263 #ifndef USE_ROSEN_DRAWING
PaintDecoration(const Offset & offset,SkCanvas * canvas,const Size & size,RenderContext & context)264 void RosenRenderTextField::PaintDecoration(
265     const Offset& offset, SkCanvas* canvas, const Size& size, RenderContext& context)
266 #else
267 void RosenRenderTextField::PaintDecoration(
268     const Offset& offset, RSCanvas* canvas, const Size& size, RenderContext& context)
269 #endif
270 {
271     auto pipelineContext = context_.Upgrade();
272     if (!pipelineContext) {
273         return;
274     }
275     pipelineContext->AddDirtyLayoutNode(AceType::Claim(this));
276 
277     Size deflateSize = ComputeDeflateSizeOfErrorAndCountText();
278     decoration_->SetBackgroundColor(inactiveBgColor_);
279     decoration_->SetAnimationColor(inactiveBgColor_);
280     RefPtr<RosenDecorationPainter> decorationPainter = AceType::MakeRefPtr<RosenDecorationPainter>(
281         decoration_, GetPaintRect() - deflateSize, size - deflateSize, pipelineContext->GetDipScale());
282     decorationPainter->PaintDecoration(offset, canvas, context);
283 }
284 
PaintIcon(const Offset & offset,RenderContext & context)285 void RosenRenderTextField::PaintIcon(const Offset& offset, RenderContext& context)
286 {
287     auto pipelineContext = context_.Upgrade();
288     if (!pipelineContext) {
289         return;
290     }
291     Offset verticalOffsetForCenter = ComputeVerticalOffsetForCenter(innerRect_.Height(), iconSize_);
292     // Paint header icon.
293     Offset iconOffset = offset;
294     Offset hotZoneOffset = Offset((iconHotZoneSize_ - iconSize_) / 2.0, 0.0);
295     if (iconImage_) {
296         iconOffset += innerRect_.GetOffset() + verticalOffsetForCenter;
297         if (textDirection_ == TextDirection::RTL) {
298             iconOffset += Offset(innerRect_.Width(), 0.0) + hotZoneOffset;
299         } else {
300             iconOffset += hotZoneOffset - Offset(iconHotZoneSize_, 0.0);
301         }
302         iconImage_->SetAdaptiveFrameRectFlag(false);
303         iconImage_->RenderWithContext(context, iconOffset);
304     }
305 
306     // Paint password icon.
307     if (keyboard_ == TextInputType::VISIBLE_PASSWORD && renderShowIcon_ && renderHideIcon_) {
308         Offset passwordIconOffset = offset + verticalOffsetForCenter + hotZoneOffset +
309                                     Offset(GetLayoutSize().Width() - iconHotZoneSize_, innerRect_.GetOffset().GetY());
310         if (textDirection_ == TextDirection::RTL) {
311             passwordIconOffset += Offset(-(GetLayoutSize().Width() - iconHotZoneSize_), 0.0);
312         }
313         if (obscure_) {
314             renderHideIcon_->RenderWithContext(context, passwordIconOffset);
315         } else {
316             renderShowIcon_->RenderWithContext(context, passwordIconOffset);
317         }
318         passwordIconRect_ = Rect(
319             passwordIconOffset - Offset((iconHotZoneSize_ - iconSize_) / 2.0, (iconHotZoneSize_ - iconSize_) / 2.0),
320             Size(iconHotZoneSize_, iconHotZoneSize_));
321     }
322 }
323 
324 #ifndef USE_ROSEN_DRAWING
PaintSelection(SkCanvas * canvas) const325 void RosenRenderTextField::PaintSelection(SkCanvas* canvas) const
326 #else
327 void RosenRenderTextField::PaintSelection(RSCanvas* canvas) const
328 #endif
329 {
330     if (!IsSelectiveDevice()) {
331         return;
332     }
333     using namespace Constants;
334     if (!paragraph_ || (canvas == nullptr) || !canPaintSelection_) {
335         return;
336     }
337     const auto& selection = GetEditingValue().selection;
338     if (GetEditingValue().text.empty() || selection.GetStart() == selection.GetEnd()) {
339         return;
340     }
341 #ifndef USE_GRAPHIC_TEXT_GINE
342     const auto& boxes = paragraph_->GetRectsForRange(selection.GetStart(), selection.GetEnd(),
343         txt::Paragraph::RectHeightStyle::kMax, txt::Paragraph::RectWidthStyle::kTight);
344 #else
345     const auto& boxes = paragraph_->GetTextRectsByBoundary(selection.GetStart(), selection.GetEnd(),
346         Rosen::TextRectHeightStyle::COVER_TOP_AND_BOTTOM, Rosen::TextRectWidthStyle::TIGHT);
347 #endif
348     if (boxes.empty()) {
349         return;
350     }
351 #ifndef USE_ROSEN_DRAWING
352     canvas->save();
353     SkPaint paint;
354     if (inputStyle_ == InputStyle::INLINE) {
355         paint.setColor(INLINE_STYLE_SELECTED_COLOR.GetValue());
356     } else {
357         paint.setColor(selectedColor_.GetValue());
358     }
359 #else
360     canvas->Save();
361     RSBrush brush;
362     if (inputStyle_ == InputStyle::INLINE) {
363         brush.SetColor(INLINE_STYLE_SELECTED_COLOR.GetValue());
364     } else {
365         brush.SetColor(selectedColor_.GetValue());
366     }
367 #endif
368     Offset effectiveOffset = innerRect_.GetOffset() + textOffsetForShowCaret_;
369     for (const auto& box : boxes) {
370         auto selectionRect = ConvertSkRect(box.rect) + effectiveOffset;
371         switch (inputStyle_) {
372             case InputStyle::INLINE:
373                 selectionRect.SetHeight(GetLayoutSize().Height());
374                 break;
375             case InputStyle::DEFAULT:
376                 selectionRect += ComputeVerticalOffsetForCenter(innerRect_.Height(), paragraph_->GetHeight());
377                 break;
378             default:
379                 LOGE("Unknown textinput style");
380                 break;
381         }
382 #ifndef USE_ROSEN_DRAWING
383         auto rect =
384             SkRect::MakeLTRB(selectionRect.Right(), selectionRect.Top(), selectionRect.Left(), selectionRect.Bottom());
385 
386 #ifndef USE_GRAPHIC_TEXT_GINE
387         if (box.direction == txt::TextDirection::ltr) {
388 #else
389         if (box.direction == Rosen::TextDirection::LTR) {
390 #endif
391             rect = SkRect::MakeLTRB(
392                 selectionRect.Left(), selectionRect.Top(), selectionRect.Right(), selectionRect.Bottom());
393         }
394         canvas->drawRect(rect, paint);
395     }
396     canvas->restore();
397 #else
398         auto rect = RSRect(selectionRect.Right(), selectionRect.Top(), selectionRect.Left(), selectionRect.Bottom());
399 
400 #ifndef USE_GRAPHIC_TEXT_GINE
401         if (box.direction == txt::TextDirection::ltr) {
402 #else
403         if (box.direction == Rosen::TextDirection::LTR) {
404 #endif
405             rect = RSRect(selectionRect.Left(), selectionRect.Top(), selectionRect.Right(), selectionRect.Bottom());
406         }
407         canvas->AttachBrush(brush);
408         canvas->DrawRect(rect);
409         canvas->DetachBrush();
410     }
411     canvas->Restore();
412 #endif
413 }
414 
415 #ifndef USE_ROSEN_DRAWING
416 void RosenRenderTextField::PaintTextAndPlaceholder(SkCanvas* canvas) const
417 #else
418 void RosenRenderTextField::PaintTextAndPlaceholder(RSCanvas* canvas) const
419 #endif
420 {
421     // Offset for the painting area of text
422     Offset textAreaOffset = innerRect_.GetOffset();
423     if (showPlaceholder_) {
424         textAreaOffset += ComputeVerticalOffsetForCenter(innerRect_.Height(), placeholderParagraph_->GetHeight());
425         placeholderParagraph_->Paint(canvas, textAreaOffset.GetX(), textAreaOffset.GetY());
426     } else {
427         textAreaOffset += ComputeVerticalOffsetForCenter(innerRect_.Height(), paragraph_->GetHeight());
428         Offset textOffset = textOffsetForShowCaret_ + textAreaOffset;
429         paragraph_->Paint(canvas, textOffset.GetX(), textOffset.GetY());
430     }
431 }
432 
433 #ifndef USE_ROSEN_DRAWING
434 void RosenRenderTextField::PaintErrorText(SkCanvas* canvas) const
435 #else
436 void RosenRenderTextField::PaintErrorText(RSCanvas* canvas) const
437 #endif
438 {
439     if (!errorParagraph_ || (canvas == nullptr)) {
440         return;
441     }
442     Offset errorOffset = innerRect_.GetOffset();
443     if (errorIsInner_) {
444 #ifndef USE_GRAPHIC_TEXT_GINE
445         double errorSpacing =
446             GreatOrEqual(errorParagraph_->GetLongestLine(), originInnerWidth_ - errorSpacing_) ? 0.0 : errorSpacing_;
447 #else
448         double errorSpacing =
449             GreatOrEqual(errorParagraph_->GetActualWidth(), originInnerWidth_ - errorSpacing_) ? 0.0 : errorSpacing_;
450 #endif
451         errorOffset +=
452             Offset(innerRect_.Width() + errorSpacing, (innerRect_.Height() - errorParagraph_->GetHeight()) / 2.0);
453     } else {
454         double bottomPadding = 0.0;
455         if (decoration_) {
456             bottomPadding = NormalizeToPx(decoration_->GetPadding().Bottom());
457         }
458         errorOffset += Offset(0.0, innerRect_.Height() + bottomPadding + NormalizeToPx(COUNT_SPACING));
459     }
460     errorParagraph_->Paint(canvas, errorOffset.GetX(), errorOffset.GetY());
461 }
462 
463 #ifndef USE_ROSEN_DRAWING
464 void RosenRenderTextField::PaintCountText(SkCanvas* canvas) const
465 #else
466 void RosenRenderTextField::PaintCountText(RSCanvas* canvas) const
467 #endif
468 {
469     if (!countParagraph_ || (canvas == nullptr)) {
470         return;
471     }
472     if (ShowCounter()) {
473 #ifndef USE_GRAPHIC_TEXT_GINE
474         Offset countOffset = innerRect_.GetOffset() +
475                              Offset(innerRect_.Width() - countParagraph_->GetLongestLine(), innerRect_.Height());
476 #else
477         Offset countOffset = innerRect_.GetOffset() +
478                              Offset(innerRect_.Width() - countParagraph_->GetActualWidth(), innerRect_.Height());
479 #endif
480         if (maxLines_ == 1) {
481             double bottomPadding = 0.0;
482             if (decoration_) {
483                 bottomPadding = NormalizeToPx(decoration_->GetPadding().Bottom());
484             }
485             countOffset += Offset(0.0, bottomPadding + NormalizeToPx(COUNT_SPACING));
486         }
487         countParagraph_->Paint(canvas, countOffset.GetX(), countOffset.GetY());
488     }
489 }
490 
491 #ifndef USE_ROSEN_DRAWING
492 SkVector RosenRenderTextField::GetSkRadii(const Radius& radius) const
493 {
494     SkVector fRadii;
495     fRadii.set(SkDoubleToScalar(NormalizeToPx(radius.GetX())), SkDoubleToScalar(NormalizeToPx(radius.GetY())));
496     return fRadii;
497 }
498 #else
499 RSPoint RosenRenderTextField::GetRSRadii(const Radius& radius) const
500 {
501     return RSPoint(
502         static_cast<RSScalar>(NormalizeToPx(radius.GetX())), static_cast<RSScalar>(NormalizeToPx(radius.GetY())));
503 }
504 #endif
505 
506 #ifndef USE_ROSEN_DRAWING
507 void RosenRenderTextField::PaintOverlayForHoverAndPress(const Offset& offset, SkCanvas* canvas) const
508 #else
509 void RosenRenderTextField::PaintOverlayForHoverAndPress(const Offset& offset, RSCanvas* canvas) const
510 #endif
511 {
512     if (canvas == nullptr) {
513         return;
514     }
515     auto pipelineContext = context_.Upgrade();
516     if (!pipelineContext) {
517         return;
518     }
519     Size deflateSize = ComputeDeflateSizeOfErrorAndCountText();
520     RefPtr<RosenDecorationPainter> decorationPainter = AceType::MakeRefPtr<RosenDecorationPainter>(decoration_,
521         GetPaintRect() - deflateSize, GetPaintRect().GetSize() - deflateSize, pipelineContext->GetDipScale());
522     Border border;
523     if (decoration_) {
524         border = decoration_->GetBorder();
525     }
526 #ifndef USE_ROSEN_DRAWING
527     SkRRect clipRRect = decorationPainter->GetBoxRRect(Offset(), border, 0.0, true);
528     canvas->save();
529     canvas->clipRRect(clipRRect, true);
530 
531     SkPaint paint;
532     paint.setColor(GetEventEffectColor().GetValue());
533     paint.setStyle(SkPaint::Style::kFill_Style);
534     paint.setAntiAlias(true);
535 
536     SkRect skRect = SkRect::MakeXYWH(offset.GetX(), offset.GetY(), GetLayoutSize().Width(), GetLayoutSize().Height());
537     SkRRect rrect = SkRRect::MakeEmpty();
538     SkVector fRadii[4] = { { 0.0, 0.0 }, { 0.0, 0.0 }, { 0.0, 0.0 }, { 0.0, 0.0 } };
539     fRadii[SkRRect::kUpperLeft_Corner] = GetSkRadii(border.TopLeftRadius());
540     fRadii[SkRRect::kUpperRight_Corner] = GetSkRadii(border.TopRightRadius());
541     fRadii[SkRRect::kLowerRight_Corner] = GetSkRadii(border.BottomRightRadius());
542     fRadii[SkRRect::kLowerLeft_Corner] = GetSkRadii(border.BottomLeftRadius());
543     rrect.setRectRadii(skRect, fRadii);
544     canvas->drawRRect(rrect, paint);
545     canvas->restore();
546 #else
547     RSRoundRect clipRRect = decorationPainter->GetBoxRRect(Offset(), border, 0.0, true);
548     canvas->Save();
549     canvas->ClipRoundRect(clipRRect, RSClipOp::INTERSECT, true);
550 
551     RSBrush brush;
552     brush.SetColor(GetEventEffectColor().GetValue());
553     brush.SetAntiAlias(true);
554 
555     auto rect = RSRect(offset.GetX(), offset.GetY(), GetLayoutSize().Width() + offset.GetX(),
556         GetLayoutSize().Height() + offset.GetY());
557     std::vector<RSPoint> fRadii;
558     fRadii.push_back(GetRSRadii(border.TopLeftRadius()));
559     fRadii.push_back(GetRSRadii(border.TopRightRadius()));
560     fRadii.push_back(GetRSRadii(border.BottomRightRadius()));
561     fRadii.push_back(GetRSRadii(border.BottomLeftRadius()));
562     RSRoundRect rrect(rect, fRadii);
563     canvas->AttachBrush(brush);
564     canvas->DrawRoundRect(rrect);
565     canvas->DetachBrush();
566     canvas->Restore();
567 #endif
568 }
569 
570 void RosenRenderTextField::PaintFocus(const Offset& offset, const Size& widthHeight, RenderContext& context)
571 {
572     auto canvas = static_cast<RosenRenderContext*>(&context)->GetCanvas();
573     if (!canvas) {
574         LOGE("Paint canvas is null");
575         return;
576     }
577 #ifndef USE_ROSEN_DRAWING
578     SkPaint paint;
579     paint.setColor(DEFAULT_FOCUS_BORDER_COLOR);
580     paint.setStrokeWidth(NormalizeToPx(DEFAULT_FOCUS_BORDER_WIDTH));
581     paint.setStyle(SkPaint::Style::kStroke_Style);
582     paint.setAntiAlias(true);
583 
584     SkRect skRect = SkRect::MakeXYWH(offset.GetX() + NormalizeToPx(DEFAULT_FOCUS_BORDER_WIDTH) * HALF,
585         offset.GetY() + NormalizeToPx(DEFAULT_FOCUS_BORDER_WIDTH) * HALF,
586         widthHeight.Width() - NormalizeToPx(DEFAULT_FOCUS_BORDER_WIDTH),
587         widthHeight.Height() - NormalizeToPx(DEFAULT_FOCUS_BORDER_WIDTH));
588     SkRRect rrect = SkRRect::MakeEmpty();
589     SkVector fRadii[4] = { { 0.0, 0.0 }, { 0.0, 0.0 }, { 0.0, 0.0 }, { 0.0, 0.0 } };
590     fRadii[SkRRect::kUpperLeft_Corner] = GetSkRadii(decoration_->GetBorder().TopLeftRadius());
591     fRadii[SkRRect::kUpperRight_Corner] = GetSkRadii(decoration_->GetBorder().TopRightRadius());
592     fRadii[SkRRect::kLowerRight_Corner] = GetSkRadii(decoration_->GetBorder().BottomRightRadius());
593     fRadii[SkRRect::kLowerLeft_Corner] = GetSkRadii(decoration_->GetBorder().BottomLeftRadius());
594     rrect.setRectRadii(skRect, fRadii);
595     canvas->drawRRect(rrect, paint);
596 #else
597     RSPen pen;
598     pen.SetColor(DEFAULT_FOCUS_BORDER_COLOR);
599     pen.SetWidth(NormalizeToPx(DEFAULT_FOCUS_BORDER_WIDTH));
600     pen.SetAntiAlias(true);
601 
602     RSScalar left = offset.GetX() + NormalizeToPx(DEFAULT_FOCUS_BORDER_WIDTH) * HALF;
603     RSScalar top = offset.GetY() + NormalizeToPx(DEFAULT_FOCUS_BORDER_WIDTH) * HALF;
604     RSScalar width = widthHeight.Width() - NormalizeToPx(DEFAULT_FOCUS_BORDER_WIDTH);
605     RSScalar height = widthHeight.Height() - NormalizeToPx(DEFAULT_FOCUS_BORDER_WIDTH);
606     auto rect = RSRect(left, top, width + left, height + top);
607     std::vector<RSPoint> fRadii;
608     fRadii.push_back(GetRSRadii(decoration_->GetBorder().TopLeftRadius()));
609     fRadii.push_back(GetRSRadii(decoration_->GetBorder().TopRightRadius()));
610     fRadii.push_back(GetRSRadii(decoration_->GetBorder().BottomRightRadius()));
611     fRadii.push_back(GetRSRadii(decoration_->GetBorder().BottomLeftRadius()));
612     RSRoundRect rrect(rect, fRadii);
613     canvas->AttachPen(pen);
614     canvas->DrawRoundRect(rrect);
615     canvas->DetachPen();
616 #endif
617 }
618 
619 #ifndef USE_ROSEN_DRAWING
620 void RosenRenderTextField::PaintScrollBar(const Offset& offset, RenderContext& context, SkCanvas* canvas)
621 #else
622 void RosenRenderTextField::PaintScrollBar(const Offset& offset, RenderContext& context, RSCanvas* canvas)
623 #endif
624 {
625     if (scrollBar_ && scrollBar_->NeedPaint()) {
626         scrollBar_->UpdateScrollBarRegion(offset, GetLayoutSize(), GetLastOffset(), GetLongestLine());
627         RefPtr<RosenScrollBarPainter> scrollBarPainter = AceType::MakeRefPtr<RosenScrollBarPainter>();
628         scrollBarPainter->PaintBar(canvas, offset, GetPaintRect(), scrollBar_, GetGlobalOffset(), OPTICITY);
629     }
630 }
631 
632 void RosenRenderTextField::Paint(RenderContext& context, const Offset& offset)
633 {
634     const auto renderContext = static_cast<RosenRenderContext*>(&context);
635     auto rsNode = renderContext->GetRSNode();
636     if (rsNode) {
637         rsNode->SetClipToFrame(true);
638     }
639 
640     auto canvas = renderContext->GetCanvas();
641     if (!canvas) {
642         LOGE("canvas fetch failed");
643         return;
644     }
645     auto pipelineContext = context_.Upgrade();
646     if (!(paragraph_ || placeholderParagraph_ || !pipelineContext) || IsInfiniteLayout()) {
647         LOGE("Paint canvas or paragraph is null");
648         return;
649     }
650     auto viewScale = pipelineContext->GetViewScale();
651     if (lastLayoutSize_ != GetLayoutSize() || !magnifierCanvas_) {
652 #ifndef USE_ROSEN_DRAWING
653         auto imageInfo = SkImageInfo::Make(GetLayoutSize().Width() * viewScale * MAGNIFIER_GAIN,
654             GetLayoutSize().Height() * viewScale * MAGNIFIER_GAIN, SkColorType::kRGBA_8888_SkColorType,
655             SkAlphaType::kOpaque_SkAlphaType);
656         if (imageInfo.width() < 0 || imageInfo.height() < 0) {
657             LOGE("Paint imageInfo width is invalid");
658             return;
659         }
660         canvasCache_.reset();
661         canvasCache_.allocPixels(imageInfo);
662         magnifierCanvas_ = std::make_unique<SkCanvas>(canvasCache_);
663 #else
664         auto width = GetLayoutSize().Width() * viewScale * MAGNIFIER_GAIN;
665         auto height = GetLayoutSize().Height() * viewScale * MAGNIFIER_GAIN;
666         if (width < 0 || height < 0) {
667             LOGE("Paint imageInfo width is invalid");
668             return;
669         }
670         RSBitmapFormat format = { RSColorType::COLORTYPE_RGBA_8888, RSAlphaType::ALPHATYPE_OPAQUE };
671         canvasCache_.Free();
672         canvasCache_.Build(width, height, format);
673         magnifierCanvas_ = std::make_unique<RSCanvas>();
674         magnifierCanvas_->Bind(canvasCache_);
675 #endif
676         lastLayoutSize_ = GetLayoutSize();
677     }
678 
679 #ifndef USE_ROSEN_DRAWING
680     canvasCache_.eraseColor(SK_ColorTRANSPARENT);
681     magnifierCanvas_->scale(viewScale * MAGNIFIER_GAIN, viewScale * MAGNIFIER_GAIN);
682 #else
683     canvasCache_.ClearWithColor(RSColor::COLOR_TRANSPARENT);
684     magnifierCanvas_->Scale(viewScale * MAGNIFIER_GAIN, viewScale * MAGNIFIER_GAIN);
685 #endif
686 
687     PaintTextField(offset, context, canvas);
688     PaintTextField(offset, context, magnifierCanvas_.get(), true);
689     PaintScrollBar(offset, context, canvas);
690 
691 #ifndef USE_ROSEN_DRAWING
692     magnifierCanvas_->scale(1.0 / (viewScale * MAGNIFIER_GAIN), 1.0 / (viewScale * MAGNIFIER_GAIN));
693 #else
694     magnifierCanvas_->Scale(1.0 / (viewScale * MAGNIFIER_GAIN), 1.0 / (viewScale * MAGNIFIER_GAIN));
695 #endif
696 
697     if ((SystemProperties::GetDeviceType() == DeviceType::PHONE ||
698             SystemProperties::GetDeviceType() == DeviceType::TABLET ||
699             SystemProperties::GetDeviceType() == DeviceType::TWO_IN_ONE) &&
700         hasFocus_) {
701         PaintFocus(offset, GetPaintRect().GetSize(), context);
702     }
703 }
704 
705 Size RosenRenderTextField::Measure()
706 {
707     ResetParagraphIfNeeded();
708 
709     UpdateCaretProto();
710 
711     auto pipelineContext = context_.Upgrade();
712     if (!pipelineContext) {
713         LOGE("No pipelineContext.");
714         return Size();
715     }
716 
717     double decorationHeight = 0.0;
718     if (decoration_) {
719         auto padding = decoration_->GetPadding();
720         auto paddingOri = padding;
721         padding.SetLeft(NormalizePercentToPx(padding.Left(), false));
722         padding.SetTop(NormalizePercentToPx(padding.Top(), true));
723         padding.SetRight(NormalizePercentToPx(padding.Right(), false));
724         padding.SetBottom(NormalizePercentToPx(padding.Bottom(), true));
725         decoration_->SetPadding(padding);
726         decorationHeight = decoration_->VerticalSpaceOccupied(pipelineContext->GetDipScale());
727         decoration_->SetPadding(paddingOri);
728     }
729 
730     auto paragraphStyle = CreateParagraphStyle();
731 #ifndef USE_GRAPHIC_TEXT_GINE
732     std::unique_ptr<txt::TextStyle> txtStyle;
733 #else
734     std::unique_ptr<Rosen::TextStyle> txtStyle;
735 #endif
736     double textAreaWidth = MeasureParagraph(paragraphStyle, txtStyle);
737     realTextWidth_ = textAreaWidth;
738     ComputeExtendHeight(decorationHeight);
739 
740     double height = NearZero(extendHeight_) ? GetLayoutParam().GetMaxSize().Height() : extendHeight_;
741     innerRect_ = { Offset::Zero(), GetLayoutParam().GetMaxSize() };
742     innerRect_.SetHeight(height);
743     Size size = innerRect_.GetSize();
744     if (decoration_) {
745         // Restrict painting rect to text area, excluding the decoration.
746         innerRect_ = GetInnerRect(*decoration_, innerRect_, pipelineContext->GetDipScale());
747     }
748     originInnerWidth_ = innerRect_.Width();
749     if (errorParagraph_ && errorIsInner_) {
750 #ifndef USE_GRAPHIC_TEXT_GINE
751         double deflateWidth = innerRect_.Width() - errorParagraph_->GetLongestLine() - errorSpacing_;
752 #else
753         double deflateWidth = innerRect_.Width() - errorParagraph_->GetActualWidth() - errorSpacing_;
754 #endif
755         innerRect_.SetWidth(GreatOrEqual(deflateWidth, 0.0) ? deflateWidth : 0.0);
756     }
757 
758     // Get height of text
759 #ifndef USE_GRAPHIC_TEXT_GINE
760     auto paragraphTxt = static_cast<txt::ParagraphTxt*>(paragraph_.get());
761     if (paragraphTxt != nullptr) {
762         textHeight_ = paragraphTxt->GetHeight();
763         textLines_ = paragraphTxt->GetLineCount();
764 #else
765     if (paragraph_ != nullptr) {
766         textHeight_ = paragraph_->GetHeight();
767         textLines_ = paragraph_->GetLineCount();
768 #endif
769     } else {
770         textHeight_ = 0.0;
771         textLines_ = 0;
772     }
773 
774     ComputeOffsetAfterLayout();
775 
776     SetShaderIfNeeded(std::move(paragraphStyle), std::move(txtStyle), textAreaWidth);
777 
778     return ComputeLayoutSize(size, decorationHeight);
779 }
780 
781 #ifndef USE_GRAPHIC_TEXT_GINE
782 double RosenRenderTextField::MeasureParagraph(
783     const std::unique_ptr<txt::ParagraphStyle>& paragraphStyle, std::unique_ptr<txt::TextStyle>& txtStyle)
784 #else
785 double RosenRenderTextField::MeasureParagraph(
786     const std::unique_ptr<Rosen::TypographyStyle>& paragraphStyle, std::unique_ptr<Rosen::TextStyle>& txtStyle)
787 #endif
788 {
789     double maxWidth = GetLayoutParam().GetMaxSize().Width();
790     // If single-line, give it infinity for layout and text will auto scroll following with caret.
791     double textAreaWidth = std::numeric_limits<double>::infinity();
792 
793     auto pipelineContext = context_.Upgrade();
794     if (!pipelineContext) {
795         LOGE("No pipelineContext.");
796         return textAreaWidth;
797     }
798 
799     double limitWidth = maxWidth;
800     if (decoration_) {
801         limitWidth = maxWidth - decoration_->HorizontalSpaceOccupied(pipelineContext->GetDipScale());
802     }
803     if (iconImage_) {
804         limitWidth -= iconHotZoneSize_;
805     }
806     if (keyboard_ == TextInputType::VISIBLE_PASSWORD) {
807         limitWidth -= iconHotZoneSize_;
808     }
809     limitWidth -= paddingHorizonForSearch_;
810     // If multi-line, set the maxWidth so that Paragraph can help us do soft-wrap.
811     if (maxLines_ != 1 || resetToStart_) {
812         textAreaWidth = limitWidth;
813     }
814 
815     auto displayText = GetTextForDisplay(GetEditingValue().text);
816     showPlaceholder_ = displayText.empty();
817     double errorTextWidth = 0.0;
818     paragraph_.reset(nullptr);
819     errorParagraph_.reset(nullptr);
820     countParagraph_.reset(nullptr);
821     placeholderParagraph_.reset(nullptr);
822     if (!errorText_.empty()) {
823 #ifndef USE_GRAPHIC_TEXT_GINE
824         std::unique_ptr<txt::ParagraphBuilder> errorBuilder =
825             txt::ParagraphBuilder::CreateTxtBuilder(*CreateParagraphStyle(true), GetFontCollection());
826 #else
827         std::unique_ptr<Rosen::TypographyCreate> errorBuilder =
828             Rosen::TypographyCreate::Create(*CreateParagraphStyle(true), GetFontCollection());
829 #endif
830         txtStyle = CreateTextStyle(errorTextStyle_);
831         errorBuilder->PushStyle(*txtStyle);
832 #ifndef USE_GRAPHIC_TEXT_GINE
833         errorBuilder->AddText(StringUtils::Str8ToStr16(errorText_));
834         errorParagraph_ = errorBuilder->Build();
835 #else
836         errorBuilder->AppendText(StringUtils::Str8ToStr16(errorText_));
837         errorParagraph_ = errorBuilder->CreateTypography();
838 #endif
839         errorParagraph_->Layout(textAreaWidth);
840 #ifndef USE_GRAPHIC_TEXT_GINE
841         errorTextWidth = errorIsInner_ ? errorParagraph_->GetLongestLine() : 0.0;
842 #else
843         errorTextWidth = errorIsInner_ ? errorParagraph_->GetActualWidth() : 0.0;
844 #endif
845     }
846     if (ShowCounter()) {
847 #ifndef USE_GRAPHIC_TEXT_GINE
848         std::unique_ptr<txt::ParagraphBuilder> countBuilder =
849             txt::ParagraphBuilder::CreateTxtBuilder(*CreateParagraphStyle(), GetFontCollection());
850 #else
851         std::unique_ptr<Rosen::TypographyCreate> countBuilder =
852             Rosen::TypographyCreate::Create(*CreateParagraphStyle(), GetFontCollection());
853 #endif
854         if (overCount_) {
855             txtStyle = CreateTextStyle(maxLines_ == 1 ? overCountStyleOuter_ : overCountStyle_);
856         } else {
857             txtStyle = CreateTextStyle(maxLines_ == 1 ? countTextStyleOuter_ : countTextStyle_);
858         }
859         countBuilder->PushStyle(*txtStyle);
860 #ifndef USE_GRAPHIC_TEXT_GINE
861         countBuilder->AddText(StringUtils::Str8ToStr16(
862             std::to_string(GetEditingValue().GetWideText().size()) + "/" + std::to_string(maxLength_)));
863         countParagraph_ = countBuilder->Build();
864 #else
865         countBuilder->AppendText(StringUtils::Str8ToStr16(
866             std::to_string(GetEditingValue().GetWideText().size()) + "/" + std::to_string(maxLength_)));
867         countParagraph_ = countBuilder->CreateTypography();
868 #endif
869         countParagraph_->Layout(textAreaWidth);
870     }
871     if (!showPlaceholder_) {
872 #ifndef USE_GRAPHIC_TEXT_GINE
873         std::unique_ptr<txt::ParagraphBuilder> builder =
874             txt::ParagraphBuilder::CreateTxtBuilder(*paragraphStyle, GetFontCollection());
875 #else
876         std::unique_ptr<Rosen::TypographyCreate> builder =
877             Rosen::TypographyCreate::Create(*paragraphStyle, GetFontCollection());
878 #endif
879         txtStyle = CreateTextStyle(style_);
880         builder->PushStyle(*txtStyle);
881 #ifndef USE_GRAPHIC_TEXT_GINE
882         builder->AddText(displayText);
883         paragraph_ = builder->Build();
884 #else
885         builder->AppendText(displayText);
886         paragraph_ = builder->CreateTypography();
887 #endif
888         paragraph_->Layout(textAreaWidth - errorTextWidth);
889 #ifndef USE_GRAPHIC_TEXT_GINE
890         if ((textDirection_ == TextDirection::RTL || realTextDirection_ == TextDirection::RTL) &&
891             LessOrEqual(paragraph_->GetLongestLine(), innerRect_.Width())) {
892 #else
893         if ((textDirection_ == TextDirection::RTL || realTextDirection_ == TextDirection::RTL) &&
894             LessOrEqual(paragraph_->GetActualWidth(), innerRect_.Width())) {
895 #endif
896             paragraph_->Layout(limitWidth);
897         }
898         if (IsOverflowX()) {
899 #ifndef USE_GRAPHIC_TEXT_GINE
900             (*paragraphStyle).max_lines = 1;
901 #else
902             (*paragraphStyle).maxLines = 1;
903 #endif
904             paragraph_->Layout(std::numeric_limits<double>::infinity());
905         }
906     } else {
907 #ifndef USE_GRAPHIC_TEXT_GINE
908         std::unique_ptr<txt::ParagraphBuilder> placeholderBuilder =
909             txt::ParagraphBuilder::CreateTxtBuilder(*paragraphStyle, GetFontCollection());
910 #else
911         std::unique_ptr<Rosen::TypographyCreate> placeholderBuilder =
912             Rosen::TypographyCreate::Create(*paragraphStyle, GetFontCollection());
913 #endif
914         txtStyle = CreateTextStyle(style_, true);
915         placeholderBuilder->PushStyle(*txtStyle);
916 #ifndef USE_GRAPHIC_TEXT_GINE
917         placeholderBuilder->AddText(StringUtils::Str8ToStr16(placeholder_));
918         placeholderParagraph_ = placeholderBuilder->Build();
919 #else
920         placeholderBuilder->AppendText(StringUtils::Str8ToStr16(placeholder_));
921         placeholderParagraph_ = placeholderBuilder->CreateTypography();
922 #endif
923         placeholderParagraph_->Layout(limitWidth - errorTextWidth);
924 #ifndef USE_GRAPHIC_TEXT_GINE
925         if (textDirection_ == TextDirection::RTL &&
926             LessOrEqual(placeholderParagraph_->GetLongestLine(), innerRect_.Width())) {
927 #else
928         if (textDirection_ == TextDirection::RTL &&
929             LessOrEqual(placeholderParagraph_->GetActualWidth(), innerRect_.Width())) {
930 #endif
931             placeholderParagraph_->Layout(limitWidth);
932         }
933     }
934     return textAreaWidth;
935 }
936 
937 void RosenRenderTextField::ComputeExtendHeight(double decorationHeight)
938 {
939     // Compute extendHeight which adjust to paragraph's height and max height when extend.
940     double heightInPx = 0.0;
941     if (height_.Unit() == DimensionUnit::PERCENT) {
942         auto parent = GetParent().Upgrade();
943         // If textfield can't handle percent, traverse parent to handle, here set max depth 4.
944         for (int32_t depth = 1; depth <= 4; ++depth) {
945             if (!parent) {
946                 break;
947             }
948             auto boxParent = AceType::DynamicCast<RenderBoxBase>(parent);
949             if (boxParent) {
950                 heightInPx = boxParent->CalculateHeightPercent(height_.Value());
951                 break;
952             }
953             parent = parent->GetParent().Upgrade();
954         }
955     } else {
956         heightInPx = NormalizeToPx(height_);
957     }
958     double deflateHeight = 0.0;
959     if (errorParagraph_ && !errorIsInner_) {
960         deflateHeight = errorParagraph_->GetHeight() + errorSpacing_;
961     }
962     if (countParagraph_ && ShowCounter()) {
963         deflateHeight = std::max(deflateHeight, countParagraph_->GetHeight() + errorSpacing_);
964     }
965     heightInPx = std::clamp(heightInPx, GetLayoutParam().GetMinSize().Height() - deflateHeight,
966         GetLayoutParam().GetMaxSize().Height() - deflateHeight);
967     if (paragraph_ && extend_ && GreatOrEqual(paragraph_->GetHeight(), heightInPx - decorationHeight)) {
968         extendHeight_ = paragraph_->GetHeight() + decorationHeight;
969     } else {
970         extendHeight_ = std::max(heightInPx, decorationHeight);
971     }
972     extendHeight_ = std::min(extendHeight_, GetLayoutParam().GetMaxSize().Height());
973 }
974 
975 double RosenRenderTextField::GetRealTextWidth() const
976 {
977     return realTextWidth_;
978 }
979 
980 void RosenRenderTextField::ComputeOffsetAfterLayout()
981 {
982     // Use glyphs dependent height.
983     if (GetCaretRect(GetEditingValue().selection.extentOffset, caretRect_, CARET_HEIGHT_OFFSET)) {
984         caretRect_ += innerRect_.GetOffset();
985         textOffsetForShowCaret_ = caretRect_.MagneticAttractedBy(innerRect_);
986         // Only single line input support reset to start.
987         if (resetToStart_ && keyboard_ != TextInputType::MULTILINE) {
988             caretRect_ -= textOffsetForShowCaret_;
989             textOffsetForShowCaret_ = Offset();
990         }
991         if (showPlaceholder_) {
992             caretRect_ += ComputeVerticalOffsetForCenter(innerRect_.Height(), placeholderParagraph_->GetHeight());
993         } else {
994             caretRect_ += ComputeVerticalOffsetForCenter(innerRect_.Height(), paragraph_->GetHeight());
995         }
996     }
997     RenderTextField::UpdateCaretInfoToController();
998 }
999 
1000 Offset RosenRenderTextField::ComputeVerticalOffsetForCenter(double outerHeight, double innerHeight) const
1001 {
1002     // Compute verticalOffsetForCenter_ when TextInputType is not MULTILINE.
1003     if (keyboard_ == TextInputType::MULTILINE) {
1004         return Offset();
1005     }
1006     return Offset(0.0, (outerHeight - innerHeight) / 2.0);
1007 }
1008 
1009 #ifndef USE_ROSEN_DRAWING
1010 sk_sp<SkShader> RosenRenderTextField::MakeGradientShader(double shadeWidth) const
1011 #else
1012 std::shared_ptr<RSShaderEffect> RosenRenderTextField::MakeGradientShader(double shadeWidth) const
1013 #endif
1014 {
1015     // If need move canvas for caret, the left side must be overflow.
1016     bool needShadeLeft = !NearZero(textOffsetForShowCaret_.GetX());
1017     // The actual width for text occupied.
1018     double textWidth = paragraph_->GetMaxIntrinsicWidth();
1019     // Width hidden on the right side. Attention: textOffsetForShowCaret_.GetX() is less than 0.
1020     double rightOverflow = textWidth + textOffsetForShowCaret_.GetX() - innerRect_.Width();
1021     bool needShadeRight = rightOverflow > 1.0;
1022 
1023     if (!needShadeLeft && !needShadeRight) {
1024         return nullptr;
1025     }
1026     if (!innerRect_.IsValid()) {
1027         return nullptr;
1028     }
1029 
1030     auto posLeft = static_cast<float>(shadeWidth / innerRect_.Width());
1031     float posRight = 1.0f - (posLeft * 2.0f);
1032     if (posRight < posLeft) {
1033         posRight = posLeft;
1034     }
1035 
1036     uint32_t originColor = style_.GetTextColor().GetValue();
1037     uint32_t transparentColor = originColor & 0x00FFFFFF;
1038 
1039 #ifndef USE_ROSEN_DRAWING
1040     SkPoint pts[] = { SkPoint::Make(SkDoubleToScalar(innerRect_.Left()), SkDoubleToScalar(0.0)),
1041         SkPoint::Make(SkDoubleToScalar(innerRect_.Right()), SkDoubleToScalar(0.0)) };
1042     // Text or placeholder color from alpha 0 - 255
1043     SkColor colors[] = { transparentColor, originColor, originColor, transparentColor };
1044     float pos[] = { 0.0f, posLeft, posRight, 1.0f };
1045 
1046     int32_t start = 0;
1047     int32_t renderCount = static_cast<int32_t>(sizeof(pos) / sizeof(pos[0]));
1048 #else
1049     RSPoint startPoint = RSPoint(static_cast<RSScalar>(innerRect_.Left()), static_cast<RSScalar>(0.0));
1050     RSPoint endPoint = RSPoint(static_cast<RSScalar>(innerRect_.Right()), static_cast<RSScalar>(0.0));
1051     // Text or placeholder color from alpha 0 - 255
1052     RSColorQuad colorsTemplate[] = { transparentColor, originColor, originColor, transparentColor };
1053     RSScalar posTemplate[] = { 0.0f, posLeft, posRight, 1.0f };
1054 
1055     int32_t start = 0;
1056     int32_t renderCount = static_cast<int32_t>(sizeof(posTemplate) / sizeof(posTemplate[0]));
1057 #endif
1058     int32_t totalCount = renderCount;
1059     if (!needShadeLeft) {
1060         start = 2;
1061         renderCount = 2;
1062     } else if (!needShadeRight) {
1063         start = 0;
1064         renderCount = 2;
1065     }
1066     if ((start + renderCount == totalCount) && blockRightShade_) {
1067         // when blocking right shade, ignore the last 2 points
1068         // in which case the renderCount must be greater or equal than 2
1069         renderCount -= 2;
1070         if (directionStatus_ == DirectionStatus::RIGHT_RIGHT) {
1071             start = 2;
1072         }
1073     }
1074 #ifndef USE_ROSEN_DRAWING
1075     return SkGradientShader::MakeLinear(pts, &colors[start], &pos[start], renderCount, SkTileMode::kClamp);
1076 #else
1077     std::vector<RSColorQuad> colors;
1078     std::vector<RSScalar> pos;
1079     for (int i = 0; i < renderCount; i++) {
1080         colors.push_back(colorsTemplate[start + i]);
1081         pos.push_back(posTemplate[start + i]);
1082     }
1083     return RSShaderEffect::CreateLinearGradient(startPoint, endPoint, colors, pos, RSTileMode::CLAMP);
1084 #endif
1085 }
1086 
1087 #ifndef USE_GRAPHIC_TEXT_GINE
1088 void RosenRenderTextField::SetShaderIfNeeded(
1089     std::unique_ptr<txt::ParagraphStyle> paragraphStyle, std::unique_ptr<txt::TextStyle> txtStyle, double textAreaWidth)
1090 #else
1091 void RosenRenderTextField::SetShaderIfNeeded(std::unique_ptr<Rosen::TypographyStyle> paragraphStyle,
1092     std::unique_ptr<Rosen::TextStyle> txtStyle, double textAreaWidth)
1093 #endif
1094 {
1095     if (maxLines_ != 1 || showPlaceholder_ || !paragraph_ || !needFade_) {
1096         // Not support placeHolder or multiline.
1097         return;
1098     }
1099 
1100     const double shadeWidth = innerRect_.Left();
1101     if (shadeWidth * 2 > innerRect_.Width()) {
1102         return;
1103     }
1104 
1105     auto shader = MakeGradientShader(shadeWidth);
1106     if (!shader) {
1107         return;
1108     }
1109 
1110 #ifndef USE_GRAPHIC_TEXT_GINE
1111     std::unique_ptr<txt::ParagraphBuilder> builder =
1112         txt::ParagraphBuilder::CreateTxtBuilder(*paragraphStyle, GetFontCollection());
1113 #ifndef USE_ROSEN_DRAWING
1114     txtStyle->has_foreground = true;
1115 #else
1116     txtStyle->has_foreground_brush = true;
1117 #endif
1118 #else
1119     std::unique_ptr<Rosen::TypographyCreate> builder =
1120         Rosen::TypographyCreate::Create(*paragraphStyle, GetFontCollection());
1121 #endif
1122 #ifndef USE_ROSEN_DRAWING
1123 #ifndef USE_GRAPHIC_TEXT_GINE
1124     txtStyle->foreground.setShader(shader);
1125 #else
1126     txtStyle->foreground->setShader(shader);
1127 #endif
1128 #else
1129 #ifndef USE_GRAPHIC_TEXT_GINE
1130     txtStyle->foreground_brush.SetShaderEffect(shader);
1131 #else
1132     txtStyle->foregroundBrush->SetShaderEffect(shader);
1133 #endif
1134 #endif
1135     builder->PushStyle(*txtStyle);
1136 #ifndef USE_GRAPHIC_TEXT_GINE
1137     builder->AddText(GetTextForDisplay(GetEditingValue().text));
1138     paragraph_ = builder->Build();
1139 #else
1140     builder->AppendText(GetTextForDisplay(GetEditingValue().text));
1141     paragraph_ = builder->CreateTypography();
1142 #endif
1143     paragraph_->Layout(textAreaWidth);
1144 }
1145 
1146 Size RosenRenderTextField::ComputeLayoutSize(const Size& size, double decorationHeight)
1147 {
1148     if (!extend_ || GreatOrEqual(innerRect_.GetSize().Height(), textHeight_)) {
1149         Size inflateSize;
1150         if (errorParagraph_ && !errorIsInner_) {
1151             // If error text is under textfield, height of textfield should add error text's height.
1152             inflateSize.SetHeight(errorParagraph_->GetHeight() + errorSpacing_);
1153         }
1154         if (countParagraph_ && ShowCounter()) {
1155             // If count text is under textfield, height of textfield should add count text's height.
1156             inflateSize.SetHeight(std::max(inflateSize.Height(), countParagraph_->GetHeight() + errorSpacing_));
1157         }
1158         return size + inflateSize;
1159     }
1160     if (GreatNotEqual(textHeight_, 0.0)) {
1161         innerRect_.SetHeight(textHeight_);
1162     }
1163     double maxWidth = GetLayoutParam().GetMaxSize().Width();
1164     return Size(maxWidth, innerRect_.Height() + decorationHeight);
1165 }
1166 
1167 #ifndef USE_GRAPHIC_TEXT_GINE
1168 std::unique_ptr<txt::ParagraphStyle> RosenRenderTextField::CreateParagraphStyle(bool isErrorText)
1169 #else
1170 std::unique_ptr<Rosen::TypographyStyle> RosenRenderTextField::CreateParagraphStyle(bool isErrorText)
1171 #endif
1172 {
1173     using namespace Constants;
1174 
1175 #ifndef USE_GRAPHIC_TEXT_GINE
1176     auto style = std::make_unique<txt::ParagraphStyle>();
1177 #else
1178     auto style = std::make_unique<Rosen::TypographyStyle>();
1179 #endif
1180     // If single-line, it shouldn't do soft-wrap for us.
1181     if (maxLines_ == 1 && resetToStart_) {
1182 #ifndef USE_GRAPHIC_TEXT_GINE
1183         style->max_lines = 1;
1184 #else
1185         style->maxLines = 1;
1186 #endif
1187         if (showEllipsis_ && keyboard_ != TextInputType::VISIBLE_PASSWORD) {
1188             style->ellipsis = StringUtils::Str8ToStr16(ELLIPSIS);
1189         }
1190     }
1191 #ifndef USE_GRAPHIC_TEXT_GINE
1192     style->text_align = ConvertTxtTextAlign(textAlign_);
1193     style->font_size = NormalizeToPx(style_.GetFontSize());
1194 #else
1195     style->textAlign = ConvertTxtTextAlign(textAlign_);
1196     style->fontSize = NormalizeToPx(style_.GetFontSize());
1197 #endif
1198 
1199     // If keyboard is password, don't change text_direction with first strong direction letter
1200     if (!isErrorText && keyboard_ == TextInputType::VISIBLE_PASSWORD && !GetEditingValue().text.empty()) {
1201 #ifndef USE_GRAPHIC_TEXT_GINE
1202         style->text_direction = ConvertTxtTextDirection(textDirection_);
1203 #else
1204         style->textDirection = ConvertTxtTextDirection(textDirection_);
1205 #endif
1206         realTextDirection_ = textDirection_;
1207         UpdateDirectionStatus();
1208         return style;
1209     }
1210     std::string showingText;
1211     if (isErrorText) {
1212         showingText = errorText_;
1213     } else {
1214         showingText = GetEditingValue().text;
1215         if (showingText.empty()) {
1216             showingText = placeholder_;
1217         }
1218     }
1219     // Use first strong direction letter to decide text_direction.
1220     existStrongDirectionLetter_ = false;
1221     auto showingTextForWString = StringUtils::ToWstring(showingText);
1222     for (const auto& charOfShowingText : showingTextForWString) {
1223         auto charDirection = u_charDirection(charOfShowingText);
1224         if (charDirection == UCharDirection::U_LEFT_TO_RIGHT) {
1225 #ifndef USE_GRAPHIC_TEXT_GINE
1226             style->text_direction = ConvertTxtTextDirection(TextDirection::LTR);
1227 #else
1228             style->textDirection = ConvertTxtTextDirection(TextDirection::LTR);
1229 #endif
1230             existStrongDirectionLetter_ = true;
1231             realTextDirection_ = TextDirection::LTR;
1232         } else if (charDirection == UCharDirection::U_RIGHT_TO_LEFT ||
1233                    charDirection == UCharDirection::U_RIGHT_TO_LEFT_ARABIC ||
1234                    charDirection == UCharDirection::U_ARABIC_NUMBER) {
1235 #ifndef USE_GRAPHIC_TEXT_GINE
1236             style->text_direction = ConvertTxtTextDirection(TextDirection::RTL);
1237 #else
1238             style->textDirection = ConvertTxtTextDirection(TextDirection::RTL);
1239 #endif
1240             existStrongDirectionLetter_ = true;
1241             realTextDirection_ = TextDirection::RTL;
1242         }
1243         if (existStrongDirectionLetter_) {
1244             break;
1245         }
1246     }
1247     if (!existStrongDirectionLetter_) {
1248 #ifndef USE_GRAPHIC_TEXT_GINE
1249         style->text_direction = ConvertTxtTextDirection(textDirection_);
1250 #else
1251         style->textDirection = ConvertTxtTextDirection(textDirection_);
1252 #endif
1253         realTextDirection_ = textDirection_;
1254     }
1255     UpdateDirectionStatus();
1256     if (keyboard_ != TextInputType::MULTILINE) {
1257 #ifdef USE_GRAPHIC_TEXT_GINE
1258         style->wordBreakType = Rosen::WordBreakType::BREAK_ALL;
1259 #endif
1260     }
1261     return style;
1262 }
1263 
1264 #ifndef USE_GRAPHIC_TEXT_GINE
1265 std::unique_ptr<txt::TextStyle> RosenRenderTextField::CreateTextStyle(const TextStyle& style, bool isPlaceholder)
1266 #else
1267 std::unique_ptr<Rosen::TextStyle> RosenRenderTextField::CreateTextStyle(const TextStyle& style, bool isPlaceholder)
1268 #endif
1269 {
1270     using namespace Constants;
1271 
1272 #ifndef USE_GRAPHIC_TEXT_GINE
1273     auto txtStyle = std::make_unique<txt::TextStyle>();
1274 #else
1275     auto txtStyle = std::make_unique<Rosen::TextStyle>();
1276 #endif
1277     if (isPlaceholder) {
1278         txtStyle->color = ConvertSkColor(placeholderColor_);
1279     } else {
1280         txtStyle->color = ConvertSkColor(style.GetTextColor());
1281     }
1282 
1283 #ifndef USE_GRAPHIC_TEXT_GINE
1284     txtStyle->font_families = style.GetFontFamilies();
1285     txtStyle->font_weight = ConvertTxtFontWeight(style.GetFontWeight());
1286     txtStyle->font_size = NormalizeToPx(style.GetFontSize());
1287     txtStyle->font_style = ConvertTxtFontStyle(style.GetFontStyle());
1288     txtStyle->text_baseline = ConvertTxtTextBaseline(style.GetTextBaseline());
1289 #else
1290     txtStyle->fontFamilies = style.GetFontFamilies();
1291     txtStyle->fontWeight = ConvertTxtFontWeight(style.GetFontWeight());
1292     txtStyle->fontSize = NormalizeToPx(style.GetFontSize());
1293     txtStyle->fontStyle = ConvertTxtFontStyle(style.GetFontStyle());
1294     txtStyle->baseline = ConvertTxtTextBaseline(style.GetTextBaseline());
1295 #endif
1296     txtStyle->locale = Localization::GetInstance()->GetFontLocale();
1297     return txtStyle;
1298 }
1299 
1300 void RosenRenderTextField::UpdateCaretProto()
1301 {
1302     caretProto_.SetRect(
1303         0.0, CARET_HEIGHT_OFFSET, NormalizeToPx(CURSOR_WIDTH), PreferredLineHeight() - 2.0 * CARET_HEIGHT_OFFSET);
1304 }
1305 
1306 double RosenRenderTextField::GetBoundaryOfParagraph(bool isLeftBoundary) const
1307 {
1308     if (!paragraph_ || GetEditingValue().text.empty()) {
1309         return 0.0;
1310     }
1311 #ifndef USE_GRAPHIC_TEXT_GINE
1312     auto boxes = paragraph_->GetRectsForRange(0, GetEditingValue().GetWideText().length(),
1313         txt::Paragraph::RectHeightStyle::kMax, txt::Paragraph::RectWidthStyle::kTight);
1314 #else
1315     auto boxes = paragraph_->GetTextRectsByBoundary(0, GetEditingValue().GetWideText().length(),
1316         Rosen::TextRectHeightStyle::COVER_TOP_AND_BOTTOM, Rosen::TextRectWidthStyle::TIGHT);
1317 #endif
1318     if (boxes.empty()) {
1319         return 0.0;
1320     }
1321 #ifndef USE_GRAPHIC_TEXT_GINE
1322     double leftBoundaryOfParagraph = boxes.front().rect.fLeft;
1323     double rightBoundaryOfParagraph = boxes.front().rect.fLeft;
1324     double bottomBoundaryOfParagraph = boxes.front().rect.fBottom;
1325 #else
1326     double leftBoundaryOfParagraph = boxes.front().rect.GetLeft();
1327     double rightBoundaryOfParagraph = boxes.front().rect.GetLeft();
1328     double bottomBoundaryOfParagraph = boxes.front().rect.GetBottom();
1329 #endif
1330     for (const auto& box : boxes) {
1331 #ifndef USE_GRAPHIC_TEXT_GINE
1332         if (cursorPositionType_ == CursorPositionType::END && !NearEqual(box.rect.fBottom, bottomBoundaryOfParagraph)) {
1333             bottomBoundaryOfParagraph = box.rect.fBottom;
1334             leftBoundaryOfParagraph = box.rect.fLeft;
1335             rightBoundaryOfParagraph = box.rect.fRight;
1336 #else
1337         if (cursorPositionType_ == CursorPositionType::END &&
1338             !NearEqual(box.rect.GetBottom(), bottomBoundaryOfParagraph)) {
1339             bottomBoundaryOfParagraph = box.rect.GetBottom();
1340             leftBoundaryOfParagraph = box.rect.GetLeft();
1341             rightBoundaryOfParagraph = box.rect.GetRight();
1342 #endif
1343             continue;
1344         }
1345 #ifndef USE_GRAPHIC_TEXT_GINE
1346         leftBoundaryOfParagraph = std::min(static_cast<double>(box.rect.fLeft), leftBoundaryOfParagraph);
1347         rightBoundaryOfParagraph = std::max(static_cast<double>(box.rect.fRight), rightBoundaryOfParagraph);
1348 #else
1349         leftBoundaryOfParagraph = std::min(static_cast<double>(box.rect.GetLeft()), leftBoundaryOfParagraph);
1350         rightBoundaryOfParagraph = std::max(static_cast<double>(box.rect.GetRight()), rightBoundaryOfParagraph);
1351 #endif
1352     }
1353     return isLeftBoundary ? leftBoundaryOfParagraph : rightBoundaryOfParagraph;
1354 }
1355 
1356 bool RosenRenderTextField::ComputeOffsetForCaretUpstream(int32_t extent, CaretMetrics& result) const
1357 {
1358     auto text = GetTextForDisplay(GetEditingValue().text);
1359     if (!paragraph_ || text.empty()) {
1360         return false;
1361     }
1362 
1363     char16_t prevChar = 0;
1364     if (static_cast<size_t>(extent) <= text.length()) {
1365         prevChar = text[std::max(0, extent - 1)];
1366     }
1367 
1368     result.Reset();
1369     int32_t graphemeClusterLength = StringUtils::NotInUtf16Bmp(prevChar) ? 2 : 1;
1370     int32_t prev = extent - graphemeClusterLength;
1371 #ifndef USE_GRAPHIC_TEXT_GINE
1372     auto boxes = paragraph_->GetRectsForRange(
1373         prev, extent, txt::Paragraph::RectHeightStyle::kMax, txt::Paragraph::RectWidthStyle::kTight);
1374 #else
1375     auto boxes = paragraph_->GetTextRectsByBoundary(
1376         prev, extent, Rosen::TextRectHeightStyle::COVER_TOP_AND_BOTTOM, Rosen::TextRectWidthStyle::TIGHT);
1377 #endif
1378     while (boxes.empty() && !GetEditingValue().text.empty()) {
1379         graphemeClusterLength *= 2;
1380         prev = extent - graphemeClusterLength;
1381         if (prev < 0) {
1382 #ifndef USE_GRAPHIC_TEXT_GINE
1383             boxes = paragraph_->GetRectsForRange(
1384                 0, extent, txt::Paragraph::RectHeightStyle::kMax, txt::Paragraph::RectWidthStyle::kTight);
1385 #else
1386             boxes = paragraph_->GetTextRectsByBoundary(
1387                 0, extent, Rosen::TextRectHeightStyle::COVER_TOP_AND_BOTTOM, Rosen::TextRectWidthStyle::TIGHT);
1388 #endif
1389             break;
1390         }
1391 #ifndef USE_GRAPHIC_TEXT_GINE
1392         boxes = paragraph_->GetRectsForRange(
1393             prev, extent, txt::Paragraph::RectHeightStyle::kMax, txt::Paragraph::RectWidthStyle::kTight);
1394 #else
1395         boxes = paragraph_->GetTextRectsByBoundary(
1396             prev, extent, Rosen::TextRectHeightStyle::COVER_TOP_AND_BOTTOM, Rosen::TextRectWidthStyle::TIGHT);
1397 #endif
1398     }
1399     if (boxes.empty()) {
1400         return false;
1401     }
1402 
1403     const auto& textBox = *boxes.begin();
1404 
1405     if (prevChar == NEWLINE_CODE) {
1406         // Return the start of next line.
1407         auto emptyOffset = MakeEmptyOffset();
1408         result.offset.SetX(emptyOffset.GetX());
1409 #ifndef USE_GRAPHIC_TEXT_GINE
1410         result.offset.SetY(textBox.rect.fBottom);
1411 #else
1412         result.offset.SetY(textBox.rect.GetBottom());
1413 #endif
1414         result.height = caretProto_.Height();
1415         return true;
1416     }
1417 
1418 #ifndef USE_GRAPHIC_TEXT_GINE
1419     bool isLtr = textBox.direction == txt::TextDirection::ltr;
1420 #else
1421     bool isLtr = textBox.direction == Rosen::TextDirection::LTR;
1422 #endif
1423     // Caret is within width of the upstream glyphs.
1424 #ifndef USE_GRAPHIC_TEXT_GINE
1425     double caretEnd = isLtr ? textBox.rect.fRight : textBox.rect.fLeft;
1426 #else
1427     double caretEnd = isLtr ? textBox.rect.GetRight() : textBox.rect.GetLeft();
1428 #endif
1429     if (cursorPositionType_ == CursorPositionType::END) {
1430         caretEnd = GetBoundaryOfParagraph(realTextDirection_ != TextDirection::LTR);
1431     }
1432     double dx = isLtr ? caretEnd : caretEnd - caretProto_.Width();
1433     double offsetX = std::min(dx, paragraph_->GetMaxWidth());
1434     result.offset.SetX(offsetX);
1435 #ifndef USE_GRAPHIC_TEXT_GINE
1436     result.offset.SetY(textBox.rect.fTop);
1437     result.height = textBox.rect.fBottom - textBox.rect.fTop;
1438 #else
1439     result.offset.SetY(textBox.rect.GetTop());
1440     result.height = textBox.rect.GetBottom() - textBox.rect.GetTop();
1441 #endif
1442     return true;
1443 }
1444 
1445 bool RosenRenderTextField::ComputeOffsetForCaretDownstream(int32_t extent, CaretMetrics& result) const
1446 {
1447     if (!paragraph_ || static_cast<size_t>(extent) >= GetEditingValue().GetWideText().length()) {
1448         return false;
1449     }
1450 
1451     result.Reset();
1452     const int32_t graphemeClusterLength = 1;
1453     const int32_t next = extent + graphemeClusterLength;
1454 #ifndef USE_GRAPHIC_TEXT_GINE
1455     auto boxes = paragraph_->GetRectsForRange(
1456         extent, next, txt::Paragraph::RectHeightStyle::kMax, txt::Paragraph::RectWidthStyle::kTight);
1457 #else
1458     auto boxes = paragraph_->GetTextRectsByBoundary(
1459         extent, next, Rosen::TextRectHeightStyle::COVER_TOP_AND_BOTTOM, Rosen::TextRectWidthStyle::TIGHT);
1460 #endif
1461     if (boxes.empty()) {
1462         return false;
1463     }
1464 
1465     const auto& textBox = *boxes.begin();
1466 #ifndef USE_GRAPHIC_TEXT_GINE
1467     bool isLtr = textBox.direction == txt::TextDirection::ltr;
1468 #else
1469     bool isLtr = textBox.direction == Rosen::TextDirection::LTR;
1470 #endif
1471     // Caret is within width of the downstream glyphs.
1472 #ifndef USE_GRAPHIC_TEXT_GINE
1473     double caretStart = isLtr ? textBox.rect.fLeft : textBox.rect.fRight;
1474 #else
1475     double caretStart = isLtr ? textBox.rect.GetLeft() : textBox.rect.GetRight();
1476 #endif
1477     if (cursorPositionType_ == CursorPositionType::END) {
1478         caretStart = GetBoundaryOfParagraph(realTextDirection_ != TextDirection::LTR);
1479     }
1480     double dx = isLtr ? caretStart : caretStart - caretProto_.Width();
1481     double offsetX = std::min(dx, paragraph_->GetMaxWidth());
1482     result.offset.SetX(offsetX);
1483 #ifndef USE_GRAPHIC_TEXT_GINE
1484     result.offset.SetY(textBox.rect.fTop);
1485     result.height = textBox.rect.fBottom - textBox.rect.fTop;
1486 #else
1487     result.offset.SetY(textBox.rect.GetTop());
1488     result.height = textBox.rect.GetBottom() - textBox.rect.GetTop();
1489 #endif
1490     return true;
1491 }
1492 
1493 bool RosenRenderTextField::ComputeOffsetForCaretCloserToClick(int32_t extent, CaretMetrics& result) const
1494 {
1495     CaretMetrics upStreamMetrics;
1496     bool upStreamSuccess = ComputeOffsetForCaretUpstream(extent, upStreamMetrics);
1497     CaretMetrics downStreamMetrics;
1498     bool downStreamSuccess = ComputeOffsetForCaretDownstream(extent, downStreamMetrics);
1499     bool nearToUpStream = LessOrEqual(std::abs(upStreamMetrics.offset.GetX() - clickOffset_.GetX()),
1500         std::abs(downStreamMetrics.offset.GetX() - clickOffset_.GetX()));
1501     result = nearToUpStream ? upStreamMetrics : downStreamMetrics;
1502     return upStreamSuccess || downStreamSuccess;
1503 }
1504 
1505 Offset RosenRenderTextField::MakeEmptyOffset() const
1506 {
1507     switch (textAlign_) {
1508         case TextAlign::LEFT: {
1509             return Offset::Zero();
1510         }
1511         case TextAlign::RIGHT: {
1512             return Offset(innerRect_.Width(), 0.0);
1513         }
1514         case TextAlign::JUSTIFY:
1515         case TextAlign::CENTER: {
1516             return Offset(innerRect_.Width() / 2.0, 0.0);
1517         }
1518         case TextAlign::END: {
1519             switch (realTextDirection_) {
1520                 case TextDirection::RTL: {
1521                     return Offset::Zero();
1522                 }
1523                 case TextDirection::LTR:
1524                 default: {
1525                     return Offset(innerRect_.Width(), 0.0);
1526                 }
1527             }
1528         }
1529         case TextAlign::START:
1530         default: {
1531             // Default to start.
1532             switch (realTextDirection_) {
1533                 case TextDirection::RTL: {
1534                     return Offset(innerRect_.Width(), 0.0);
1535                 }
1536                 case TextDirection::LTR:
1537                 default: {
1538                     return Offset::Zero();
1539                 }
1540             }
1541         }
1542     }
1543 }
1544 
1545 double RosenRenderTextField::PreferredLineHeight()
1546 {
1547     if (!template_) {
1548 #ifndef USE_GRAPHIC_TEXT_GINE
1549         std::unique_ptr<txt::ParagraphBuilder> builder =
1550             txt::ParagraphBuilder::CreateTxtBuilder(*CreateParagraphStyle(), GetFontCollection());
1551 #else
1552         std::unique_ptr<Rosen::TypographyCreate> builder =
1553             Rosen::TypographyCreate::Create(*CreateParagraphStyle(), GetFontCollection());
1554 #endif
1555         builder->PushStyle(*CreateTextStyle(style_));
1556         // Use a space for estimating line height if there is no placeholder.
1557         // Actually it has slight differ between cases.
1558         if (placeholder_.empty()) {
1559 #ifndef USE_GRAPHIC_TEXT_GINE
1560             builder->AddText(u" ");
1561 #else
1562             builder->AppendText(u" ");
1563 #endif
1564         } else {
1565 #ifndef USE_GRAPHIC_TEXT_GINE
1566             builder->AddText(StringUtils::Str8ToStr16(placeholder_));
1567 #else
1568             builder->AppendText(StringUtils::Str8ToStr16(placeholder_));
1569 #endif
1570         }
1571 #ifndef USE_GRAPHIC_TEXT_GINE
1572         template_ = builder->Build();
1573 #else
1574         template_ = builder->CreateTypography();
1575 #endif
1576         template_->Layout(Size::INFINITE_SIZE);
1577     }
1578     return template_->GetHeight();
1579 }
1580 
1581 #ifndef USE_GRAPHIC_TEXT_GINE
1582 std::shared_ptr<txt::FontCollection> RosenRenderTextField::GetFontCollection()
1583 #else
1584 std::shared_ptr<Rosen::FontCollection> RosenRenderTextField::GetFontCollection()
1585 #endif
1586 {
1587     return RosenFontCollection::GetInstance().GetFontCollection();
1588 }
1589 
1590 void RosenRenderTextField::ResetParagraphIfNeeded()
1591 {
1592     // When custom font is loaded, reset the paragraph.
1593     if (isCallbackCalled_) {
1594         if (paragraph_) {
1595             paragraph_.reset();
1596         }
1597         if (placeholderParagraph_) {
1598             placeholderParagraph_.reset();
1599         }
1600     }
1601 }
1602 
1603 int32_t RosenRenderTextField::GetCursorPositionForMoveUp()
1604 {
1605     if (!paragraph_) {
1606         return 0;
1607     }
1608     double verticalOffset = -textOffsetForShowCaret_.GetY() - PreferredLineHeight();
1609     return static_cast<int32_t>(paragraph_
1610 #ifndef USE_GRAPHIC_TEXT_GINE
1611                                     ->GetGlyphPositionAtCoordinate(
1612 #else
1613                                     ->GetGlyphIndexByCoordinate(
1614 #endif
1615 #ifndef USE_GRAPHIC_TEXT_GINE
1616                                         caretRect_.Left() - innerRect_.Left(), caretRect_.Top() + verticalOffset)
1617                                     .position);
1618 #else
1619                                         caretRect_.Left() - innerRect_.Left(), caretRect_.Top() + verticalOffset)
1620                                     .index);
1621 #endif
1622 }
1623 
1624 int32_t RosenRenderTextField::GetCursorPositionForMoveDown()
1625 {
1626     if (!paragraph_) {
1627         return 0;
1628     }
1629     double verticalOffset = -textOffsetForShowCaret_.GetY() + PreferredLineHeight();
1630     return static_cast<int32_t>(paragraph_
1631 
1632 #ifndef USE_GRAPHIC_TEXT_GINE
1633                                     ->GetGlyphPositionAtCoordinate(
1634 #else
1635                                     ->GetGlyphIndexByCoordinate(
1636 #endif
1637 
1638 #ifndef USE_GRAPHIC_TEXT_GINE
1639                                         caretRect_.Left() - innerRect_.Left(), caretRect_.Top() + verticalOffset)
1640                                     .position);
1641 #else
1642                                         caretRect_.Left() - innerRect_.Left(), caretRect_.Top() + verticalOffset)
1643                                     .index);
1644 #endif
1645 }
1646 
1647 int32_t RosenRenderTextField::GetCursorPositionForClick(const Offset& offset)
1648 {
1649     if (!paragraph_) {
1650         return 0;
1651     }
1652     cursorPositionType_ = CursorPositionType::NORMAL;
1653     clickOffset_ = offset - GetGlobalOffsetExternal() - innerRect_.GetOffset() - textOffsetForShowCaret_;
1654     // Solve can't select right boundary of RTL language.
1655     double rightBoundary = GetBoundaryOfParagraph(false);
1656     if (realTextDirection_ == TextDirection::RTL && GreatOrEqual(clickOffset_.GetX(), rightBoundary)) {
1657         return 0;
1658     }
1659     return static_cast<int32_t>(
1660 
1661 #ifndef USE_GRAPHIC_TEXT_GINE
1662         paragraph_->GetGlyphPositionAtCoordinate(clickOffset_.GetX(), clickOffset_.GetY()).position);
1663 #else
1664         paragraph_->GetGlyphIndexByCoordinate(clickOffset_.GetX(), clickOffset_.GetY()).index);
1665 #endif
1666 }
1667 
1668 int32_t RosenRenderTextField::AdjustCursorAndSelection(int32_t currentCursorPosition)
1669 {
1670     int32_t result = currentCursorPosition;
1671     // Place cursor to the right boundary of paragraph when direction is LTR,
1672     // place to the left boundary of paragraph when direction is RTL.
1673     auto paragraphStyle = CreateParagraphStyle();
1674 #ifndef USE_GRAPHIC_TEXT_GINE
1675     std::unique_ptr<txt::TextStyle> txtStyle;
1676 #else
1677     std::unique_ptr<Rosen::TextStyle> txtStyle;
1678 #endif
1679     MeasureParagraph(paragraphStyle, txtStyle);
1680     Rect tempRect;
1681     GetCaretRect(currentCursorPosition, tempRect);
1682     auto maxPosition = static_cast<int32_t>(GetEditingValue().GetWideText().length());
1683     double leftBoundary = GetBoundaryOfParagraph(true);
1684     double rightBoundary = GetBoundaryOfParagraph(false);
1685     if ((realTextDirection_ == TextDirection::LTR &&
1686             (NearEqual(tempRect.Left(), rightBoundary) || NearEqual(tempRect.Right(), rightBoundary))) ||
1687         (realTextDirection_ == TextDirection::RTL &&
1688             (NearEqual(tempRect.Left(), leftBoundary) || NearEqual(tempRect.Right(), leftBoundary)))) {
1689         result = maxPosition;
1690         cursorPositionType_ = CursorPositionType::END;
1691         return result;
1692     }
1693 
1694     // Get wstring before cursor.
1695     const char mark = ' ';
1696     std::string tempBefore = GetEditingValue().GetSelectedText(TextSelection(0, currentCursorPosition));
1697     StringUtils::DeleteAllMark(tempBefore, mark);
1698     const auto& textBeforeCursor = StringUtils::ToWstring(tempBefore);
1699     // Get wstring after cursor.
1700     std::string tempAfter = GetEditingValue().GetSelectedText(
1701         TextSelection(currentCursorPosition, GetEditingValue().GetWideText().length()));
1702     StringUtils::DeleteAllMark(tempAfter, mark);
1703     const auto& textAfterCursor = StringUtils::ToWstring(tempAfter);
1704     // Judge should or shouldn't adjust position.
1705     bool needAdjustPosition = NeedAdjustPosition(textBeforeCursor);
1706     if (!needAdjustPosition) {
1707         cursorPositionForShow_ = currentCursorPosition;
1708         return currentCursorPosition;
1709     }
1710 
1711     // Adjust position when click boundary of RTL and LTR.
1712     const auto& charBefore = textBeforeCursor.back();
1713     const auto& charAfter = textAfterCursor.front();
1714     bool isBeforeCharRtl =
1715         !textBeforeCursor.empty() && (u_charDirection(charBefore) == UCharDirection::U_RIGHT_TO_LEFT ||
1716                                          u_charDirection(charBefore) == UCharDirection::U_RIGHT_TO_LEFT_ARABIC);
1717     bool isAfterCharRtl =
1718         !textAfterCursor.empty() && (u_charDirection(charAfter) == UCharDirection::U_RIGHT_TO_LEFT ||
1719                                         u_charDirection(charAfter) == UCharDirection::U_RIGHT_TO_LEFT_ARABIC);
1720     bool adjustSuccess = true;
1721     if (realTextDirection_ == TextDirection::RTL) {
1722         adjustSuccess =
1723             AdjustCursorAndSelectionForRtl(isBeforeCharRtl, isAfterCharRtl, textBeforeCursor, textAfterCursor, result);
1724     } else if (realTextDirection_ == TextDirection::LTR) {
1725         adjustSuccess =
1726             AdjustCursorAndSelectionForLtr(isBeforeCharRtl, isAfterCharRtl, textBeforeCursor, textAfterCursor, result);
1727     }
1728     if (!adjustSuccess) {
1729         return currentCursorPosition;
1730     }
1731 
1732     if (isValueFromRemote_) {
1733         isValueFromRemote_ = false;
1734         return currentCursorPosition;
1735     }
1736     return result;
1737 }
1738 
1739 bool RosenRenderTextField::NeedAdjustPosition(const std::wstring& textBeforeCursor)
1740 {
1741     bool needAdjustPosition = false;
1742     if (!textBeforeCursor.empty()) {
1743         UCharDirection firstCharDirection = u_charDirection(*(textBeforeCursor.rbegin()));
1744         bool isFirstCharRtl = (firstCharDirection == UCharDirection::U_RIGHT_TO_LEFT ||
1745                                firstCharDirection == UCharDirection::U_RIGHT_TO_LEFT_ARABIC);
1746         for (auto iter = textBeforeCursor.rbegin(); iter != textBeforeCursor.rend(); ++iter) {
1747             auto charDirection = u_charDirection(*iter);
1748             bool isDirectionRtl = (charDirection == UCharDirection::U_RIGHT_TO_LEFT ||
1749                                    charDirection == UCharDirection::U_RIGHT_TO_LEFT_ARABIC);
1750             if (isDirectionRtl != isFirstCharRtl) {
1751                 needAdjustPosition = true;
1752                 break;
1753             }
1754         }
1755     }
1756     return needAdjustPosition;
1757 }
1758 
1759 bool RosenRenderTextField::AdjustCursorAndSelectionForLtr(bool isBeforeCharRtl, bool isAfterCharRtl,
1760     const std::wstring& textBeforeCursor, const std::wstring& textAfterCursor, int32_t& result)
1761 {
1762     int32_t currentCursorPosition = result;
1763     if (isBeforeCharRtl && !isAfterCharRtl) {
1764         if (textBeforeCursor.empty()) {
1765             return false;
1766         }
1767         int32_t count = 0;
1768         UCharDirection charDirection;
1769         for (auto iter = textBeforeCursor.rbegin(); iter != textBeforeCursor.rend(); ++iter) {
1770             charDirection = u_charDirection(*iter);
1771             if (charDirection != UCharDirection::U_RIGHT_TO_LEFT &&
1772                 charDirection != UCharDirection::U_RIGHT_TO_LEFT_ARABIC) {
1773                 break;
1774             }
1775             count++;
1776         }
1777         result = currentCursorPosition - count;
1778         cursorPositionType_ = CursorPositionType::BOUNDARY;
1779         cursorPositionForShow_ = currentCursorPosition;
1780     } else if (!isBeforeCharRtl && isAfterCharRtl) {
1781         if (textAfterCursor.empty()) {
1782             return false;
1783         }
1784         int32_t count = 0;
1785         UCharDirection charDirection;
1786         for (auto iter = textAfterCursor.begin(); iter != textAfterCursor.end(); ++iter) {
1787             charDirection = u_charDirection(*iter);
1788             if (charDirection != UCharDirection::U_RIGHT_TO_LEFT &&
1789                 charDirection != UCharDirection::U_RIGHT_TO_LEFT_ARABIC) {
1790                 break;
1791             }
1792             count++;
1793         }
1794         result = currentCursorPosition + count;
1795         cursorPositionType_ = CursorPositionType::BOUNDARY;
1796         cursorPositionForShow_ = currentCursorPosition;
1797     }
1798     return true;
1799 }
1800 
1801 bool RosenRenderTextField::AdjustCursorAndSelectionForRtl(bool isBeforeCharRtl, bool isAfterCharRtl,
1802     const std::wstring& textBeforeCursor, const std::wstring& textAfterCursor, int32_t& result)
1803 {
1804     int32_t currentCursorPosition = result;
1805     if (!isBeforeCharRtl && (isAfterCharRtl || textAfterCursor.empty())) {
1806         if (textBeforeCursor.empty()) {
1807             return false;
1808         }
1809         int32_t count = 0;
1810         UCharDirection charDirection;
1811         for (auto iter = textBeforeCursor.rbegin(); iter != textBeforeCursor.rend(); ++iter) {
1812             charDirection = u_charDirection(*iter);
1813             if (charDirection == UCharDirection::U_RIGHT_TO_LEFT ||
1814                 charDirection == UCharDirection::U_RIGHT_TO_LEFT_ARABIC) {
1815                 break;
1816             }
1817             count++;
1818         }
1819         result = currentCursorPosition - count;
1820         cursorPositionType_ = CursorPositionType::BOUNDARY;
1821         cursorPositionForShow_ = currentCursorPosition;
1822     } else if (isBeforeCharRtl && !isAfterCharRtl) {
1823         if (textAfterCursor.empty()) {
1824             return false;
1825         }
1826         int32_t count = 0;
1827         UCharDirection charDirection;
1828         for (auto iter = textAfterCursor.begin(); iter != textAfterCursor.end(); ++iter) {
1829             charDirection = u_charDirection(*iter);
1830             if (charDirection == UCharDirection::U_RIGHT_TO_LEFT ||
1831                 charDirection == UCharDirection::U_RIGHT_TO_LEFT_ARABIC) {
1832                 break;
1833             }
1834             count++;
1835         }
1836         result = currentCursorPosition + count;
1837         cursorPositionType_ = CursorPositionType::BOUNDARY;
1838         cursorPositionForShow_ = currentCursorPosition;
1839     }
1840     return true;
1841 }
1842 
1843 DirectionStatus RosenRenderTextField::GetDirectionStatusOfPosition(int32_t position) const
1844 {
1845     const char mark = ' ';
1846     std::string tempBefore = GetEditingValue().GetSelectedText(TextSelection(0, position));
1847     StringUtils::DeleteAllMark(tempBefore, mark);
1848     const auto& textBeforeCursor = StringUtils::ToWstring(tempBefore);
1849 
1850     std::string tempAfter =
1851         GetEditingValue().GetSelectedText(TextSelection(position, GetEditingValue().GetWideText().length()));
1852     StringUtils::DeleteAllMark(tempAfter, mark);
1853     const auto& textAfterCursor = StringUtils::ToWstring(tempAfter);
1854 
1855     bool isBeforeCharRtl = false;
1856     if (!textBeforeCursor.empty()) {
1857         const auto& charBefore = textBeforeCursor.back();
1858         isBeforeCharRtl = (u_charDirection(charBefore) == UCharDirection::U_RIGHT_TO_LEFT ||
1859                            u_charDirection(charBefore) == UCharDirection::U_RIGHT_TO_LEFT_ARABIC);
1860     }
1861 
1862     bool isAfterCharRtl = false;
1863     if (!textAfterCursor.empty()) {
1864         const auto& charAfter = textAfterCursor.front();
1865         isAfterCharRtl = (u_charDirection(charAfter) == UCharDirection::U_RIGHT_TO_LEFT ||
1866                           u_charDirection(charAfter) == UCharDirection::U_RIGHT_TO_LEFT_ARABIC);
1867     }
1868     return static_cast<DirectionStatus>(
1869         (static_cast<uint8_t>(isBeforeCharRtl) << 1) | static_cast<uint8_t>(isAfterCharRtl));
1870 }
1871 
1872 Offset RosenRenderTextField::GetHandleOffset(int32_t extend)
1873 {
1874     Rect result;
1875     GetCaretRect(extend, result);
1876     selectHeight_ = result.Bottom() - result.Top();
1877     Offset handleLocalOffset = Offset((result.Left() + result.Right()) / 2.0, result.Bottom());
1878     Offset handleOffset = handleLocalOffset + innerRect_.GetOffset() + GetOffsetToPage() + textOffsetForShowCaret_;
1879     if (paragraph_) {
1880         handleOffset += ComputeVerticalOffsetForCenter(innerRect_.Height(), paragraph_->GetHeight());
1881     } else if (placeholderParagraph_) {
1882         handleOffset += ComputeVerticalOffsetForCenter(innerRect_.Height(), placeholderParagraph_->GetHeight());
1883     } else {
1884         handleOffset += Offset(0.0, (innerRect_.Height() - PreferredLineHeight()) / 2.0);
1885     }
1886     return handleOffset;
1887 }
1888 
1889 Size RosenRenderTextField::ComputeDeflateSizeOfErrorAndCountText() const
1890 {
1891     Size deflateSize;
1892     if (errorParagraph_ && !errorIsInner_) {
1893         deflateSize.SetHeight(errorParagraph_->GetHeight() + errorSpacing_);
1894     }
1895     if (maxLines_ == 1 && countParagraph_ && ShowCounter()) {
1896         deflateSize.SetHeight(std::max(deflateSize.Height(), countParagraph_->GetHeight() + errorSpacing_));
1897     }
1898     return deflateSize;
1899 }
1900 
1901 #ifndef USE_ROSEN_DRAWING
1902 void RosenRenderTextField::PaintTextField(
1903     const Offset& offset, RenderContext& context, SkCanvas* canvas, bool isMagnifier)
1904 {
1905     canvas->save();
1906     canvas->translate(offset.GetX(), offset.GetY());
1907     Rect clipRect(Offset::Zero(), GetLayoutSize());
1908     canvas->clipRect(
1909         SkRect::MakeLTRB(clipRect.Left(), clipRect.Top(), clipRect.Right(), clipRect.Bottom()), SkClipOp::kIntersect);
1910 #else
1911 void RosenRenderTextField::PaintTextField(
1912     const Offset& offset, RenderContext& context, RSCanvas* canvas, bool isMagnifier)
1913 {
1914     canvas->Save();
1915     canvas->Translate(offset.GetX(), offset.GetY());
1916     Rect clipRect(Offset::Zero(), GetLayoutSize());
1917     canvas->ClipRect(RSRect(clipRect.Left(), clipRect.Top(), clipRect.Right(), clipRect.Bottom()), RSClipOp::INTERSECT);
1918 #endif
1919     if (!isMagnifier) {
1920         PaintDecoration(offset, canvas, GetPaintRect().GetSize(), context);
1921         PaintOverlayForHoverAndPress(offset, canvas);
1922         PaintIcon(offset, context);
1923     }
1924 
1925 #ifndef USE_ROSEN_DRAWING
1926     canvas->save();
1927     // Restrict painting rect to text area, excluding the decoration.
1928     canvas->clipRect(SkRect::MakeLTRB(innerRect_.Left(), innerRect_.Top(), innerRect_.Right(), innerRect_.Bottom()),
1929         SkClipOp::kIntersect);
1930 #else
1931     canvas->Save();
1932     // Restrict painting rect to text area, excluding the decoration.
1933     canvas->ClipRect(
1934         RSRect(innerRect_.Left(), innerRect_.Top(), innerRect_.Right(), innerRect_.Bottom()), RSClipOp::INTERSECT);
1935 #endif
1936     auto pipelineContext = context_.Upgrade();
1937     if (!pipelineContext ||
1938         lastLayoutSize_.Height() < decoration_->VerticalSpaceOccupied(pipelineContext->GetDipScale())) {
1939         return;
1940     }
1941     PaintSelection(canvas);
1942     // Paint cursor.
1943     PaintCaret(*canvas, caretRect_);
1944     PaintTextAndPlaceholder(canvas);
1945 #ifndef USE_ROSEN_DRAWING
1946     canvas->restore();
1947 
1948     PaintErrorText(canvas);
1949     canvas->restore();
1950 #else
1951     canvas->Restore();
1952 
1953     PaintErrorText(canvas);
1954     canvas->Restore();
1955 #endif
1956     PaintCountText(canvas);
1957     if (isMagnifier) {
1958         PaintSelectCaret(canvas);
1959     }
1960 }
1961 
1962 void RosenRenderTextField::ResetStatus()
1963 {
1964     template_.reset();
1965 }
1966 
1967 double RosenRenderTextField::GetLongestLine() const
1968 {
1969     if (paragraph_) {
1970 #ifndef USE_GRAPHIC_TEXT_GINE
1971         return paragraph_->GetLongestLine();
1972 #else
1973         return paragraph_->GetActualWidth();
1974 #endif
1975     }
1976     return RenderTextField::GetLongestLine();
1977 }
1978 
1979 } // namespace OHOS::Ace
1980