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