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