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