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