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