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