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