1 /*
2  * Copyright (c) 2021-2023 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 "core/components/text/rosen_render_text.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 "render_service_client/core/ui/rs_node.h"
28 #include "unicode/uchar.h"
29 
30 #include "base/geometry/dimension.h"
31 #include "base/geometry/offset.h"
32 #include "base/i18n/localization.h"
33 #include "base/utils/string_utils.h"
34 #include "base/utils/utils.h"
35 #include "core/common/font_manager.h"
36 #include "core/components/font/constants_converter.h"
37 #include "core/components/font/rosen_font_collection.h"
38 #include "core/components/text/text_component.h"
39 #include "core/components/text_span/rosen_render_text_span.h"
40 #include "core/pipeline/base/rosen_render_context.h"
41 #include "core/pipeline/pipeline_context.h"
42 
43 namespace OHOS::Ace {
44 namespace {
45 
46 const std::u16string ELLIPSIS = u"\u2026";
47 constexpr Dimension ADAPT_UNIT = 1.0_fp;
48 constexpr int32_t COMPATIBLE_VERSION = 6;
49 
50 } // namespace
51 
Update(const RefPtr<Component> & component)52 void RosenRenderText::Update(const RefPtr<Component>& component)
53 {
54     RenderText::Update(component);
55     if (auto rsNode = GetRSNode()) {
56         bool shouldClipToContent = (textStyle_.GetTextOverflow() == TextOverflow::CLIP);
57         rsNode->SetClipToFrame(shouldClipToContent);
58         if (isCustomFont_) {
59             rsNode->SetIsCustomTextType(isCustomFont_);
60         }
61     }
62 }
63 
GetBaselineDistance(TextBaseline textBaseline)64 double RosenRenderText::GetBaselineDistance(TextBaseline textBaseline)
65 {
66     if (textBaseline == TextBaseline::IDEOGRAPHIC) {
67         return paragraph_->GetIdeographicBaseline() + std::max(NormalizeToPx(textStyle_.GetBaselineOffset()), 0.0);
68     }
69     return paragraph_->GetAlphabeticBaseline() + std::max(NormalizeToPx(textStyle_.GetBaselineOffset()), 0.0);
70 }
71 
Paint(RenderContext & context,const Offset & offset)72 void RosenRenderText::Paint(RenderContext& context, const Offset& offset)
73 {
74     if (!NeedPaint()) {
75         return;
76     }
77 
78     if (needMeasure_) {
79         LOGW("Text can not paint before measure.");
80         return;
81     }
82     auto canvas = static_cast<RosenRenderContext*>(&context)->GetCanvas();
83     auto rsNode = static_cast<RosenRenderContext*>(&context)->GetRSNode();
84     if (!canvas || !rsNode || !paragraph_) {
85         LOGE("Paint canvas or paragraph is null");
86         return;
87     }
88     rsNode->SetPaintOrder(true);
89 
90     RenderNode::Paint(context, offset);
91 
92     auto baselineOffset = std::min(NormalizeToPx(textStyle_.GetBaselineOffset()), 0.0);
93     auto paintOffset = offset - Offset(0.0, baselineOffset);
94     auto textRealWidth = paragraph_->GetMaxWidth();
95     auto textRealHeight = paragraph_->GetHeight();
96     SetParagraphWidth(textRealWidth);
97     SetParagraphHeight(textRealHeight);
98     float newX = paintOffset.GetX();
99     float newY = paintOffset.GetY();
100 
101     if (text_->GetDeclarationHeight().IsValid()) {
102         switch (textStyle_.GetTextVerticalAlign()) {
103             case VerticalAlign::TOP:
104                 break;
105             case VerticalAlign::BOTTOM:
106                 newY = offset.GetY() + (GetLayoutSize().Height() - textRealHeight) -
107                        std::max(NormalizeToPx(textStyle_.GetBaselineOffset()), 0.0);
108                 break;
109             case VerticalAlign::CENTER:
110                 newY = offset.GetY() - NormalizeToPx(textStyle_.GetBaselineOffset()) +
111                        (GetLayoutSize().Height() - textRealHeight) / 2.0;
112                 break;
113             default:
114                 break;
115         }
116     }
117 
118     switch (textStyle_.GetTextAlign()) {
119         case TextAlign::LEFT:
120             break;
121         case TextAlign::START:
122             if (TextDirection::RTL == defaultTextDirection_) {
123                 newX = paintOffset.GetX() + (GetLayoutSize().Width() - textRealWidth);
124             }
125             break;
126         case TextAlign::RIGHT:
127             newX = paintOffset.GetX() + (GetLayoutSize().Width() - textRealWidth);
128             break;
129         case TextAlign::END:
130             if (TextDirection::RTL != defaultTextDirection_) {
131                 newX = paintOffset.GetX() + (GetLayoutSize().Width() - textRealWidth);
132             }
133             break;
134         case TextAlign::CENTER:
135             newX = paintOffset.GetX() + (GetLayoutSize().Width() - textRealWidth) / 2.0;
136             break;
137         case TextAlign::JUSTIFY:
138             break;
139         default:
140             break;
141     }
142 
143     PaintSelection(canvas, GetGlobalOffset());
144     paragraph_->Paint(canvas, newX, newY);
145 }
146 
NeedPaint()147 bool RosenRenderText::NeedPaint()
148 {
149     // If font is custom font, paint text until font is ready.
150     auto pipelineContext = context_.Upgrade();
151     if (pipelineContext && pipelineContext->GetFontManager()) {
152         auto fontNames = pipelineContext->GetFontManager()->GetFontNames();
153         for (const auto& familyName : textStyle_.GetFontFamilies()) {
154             if (std::find(std::begin(fontNames), std::end(fontNames), familyName) != std::end(fontNames) &&
155                 !isCallbackCalled_) {
156                 return false;
157             }
158         }
159         for (const auto& child : GetChildren()) {
160             auto span = AceType::DynamicCast<RenderTextSpan>(child);
161             if (!span) {
162                 continue;
163             }
164             for (const auto& familyName : span->GetSpanStyle().GetFontFamilies()) {
165                 if (std::find(std::begin(fontNames), std::end(fontNames), familyName) != std::end(fontNames) &&
166                     !span->IsCallbackCalled()) {
167                     return false;
168                 }
169             }
170         }
171     }
172     return true;
173 }
174 
Measure()175 Size RosenRenderText::Measure()
176 {
177     if (!text_ || CheckMeasureFlag()) {
178         return GetSize();
179     }
180 
181     textStyle_.SetMaxLines(maxLines_);
182     lastLayoutMaxWidth_ = GetLayoutParam().GetMaxSize().Width();
183     lastLayoutMinWidth_ = GetLayoutParam().GetMinSize().Width();
184     lastLayoutMaxHeight_ = GetLayoutParam().GetMaxSize().Height();
185     lastLayoutMinHeight_ = GetLayoutParam().GetMinSize().Height();
186     if (!textStyle_.GetAdaptTextSize()) {
187         if (!UpdateParagraph()) {
188             LOGE("fail to initialize text paragraph");
189             return Size();
190         }
191         paragraph_->Layout(lastLayoutMaxWidth_);
192     } else {
193         if (!AdaptTextSize(lastLayoutMaxWidth_)) {
194             LOGE("fail to initialize text paragraph in adapt text size step");
195             return Size();
196         }
197     }
198     needMeasure_ = false;
199     // If you need to lay out the text according to the maximum layout width given by the parent, use it.
200     if (text_->GetMaxWidthLayout()) {
201         paragraphNewWidth_ = GetLayoutParam().GetMaxSize().Width();
202         return GetSize();
203     }
204     // The reason for the second layout is because the TextAlign property needs the width of the layout,
205     // and the width of the second layout is used as the width of the TextAlign layout.
206     if (!NearEqual(lastLayoutMinWidth_, lastLayoutMaxWidth_)) {
207         paragraphNewWidth_ = std::clamp(GetTextWidth(), lastLayoutMinWidth_, lastLayoutMaxWidth_);
208         if (!NearEqual(paragraphNewWidth_, paragraph_->GetMaxWidth())) {
209             ApplyIndents(paragraphNewWidth_);
210             paragraph_->Layout(std::ceil(paragraphNewWidth_));
211         }
212     }
213     EffectAutoMaxLines();
214     return GetSize();
215 }
216 
IsCompatibleVersion()217 bool RosenRenderText::IsCompatibleVersion()
218 {
219     auto context = context_.Upgrade();
220     if (!context) {
221         return false;
222     }
223     return context->GetMinPlatformVersion() >= COMPATIBLE_VERSION;
224 }
225 
CheckMeasureFlag()226 bool RosenRenderText::CheckMeasureFlag()
227 {
228     if (isCallbackCalled_) {
229         needMeasure_ = true;
230     }
231     for (const auto& child : GetChildren()) {
232         auto span = AceType::DynamicCast<RenderTextSpan>(child);
233         if (span && (span->IsCallbackCalled() || span->NeedLayout())) {
234             paragraph_.reset();
235             needMeasure_ = true;
236             break;
237         }
238     }
239 
240     double paragraphMaxWidth = GetLayoutParam().GetMaxSize().Width();
241     double paragraphMinWidth = GetLayoutParam().GetMinSize().Width();
242     double paragraphMaxHeight = GetLayoutParam().GetMaxSize().Height();
243     double paragraphMinHeight = GetLayoutParam().GetMinSize().Height();
244 
245     if (!needMeasure_) {
246         // Layout when constrains of height is changed.
247         if (!NearEqual(paragraphMaxHeight, lastLayoutMaxHeight_) ||
248             !NearEqual(paragraphMinHeight, lastLayoutMinHeight_)) {
249             return false;
250         }
251         bool constrainsAffect = true;
252         auto layoutWidth = GetSize().Width();
253         if (NearEqual(paragraphMaxWidth, lastLayoutMaxWidth_) && NearEqual(paragraphMinWidth, lastLayoutMinWidth_)) {
254             // Width constrains not changed.
255             constrainsAffect = false;
256         } else if (!IsCompatibleVersion() && GreatOrEqual(layoutWidth, paragraphMinWidth) &&
257                    LessOrEqual(layoutWidth, paragraphMaxWidth) && (lastLayoutMaxWidth_ - layoutWidth > 1.0)) {
258             // Constrains changed but has no effect. For example, text width is 100 when constrains [0, 200].
259             // When constrains changed to [100, 300], there's no need to do layout.
260             // An exception is that given [0, 100], resulting in layout 100. We assume the actual layout size is more
261             // than 100 due to soft-wrap.
262             if (!textStyle_.GetAdaptTextSize()) {
263                 constrainsAffect = false;
264             }
265         }
266         if (!constrainsAffect) {
267             return true;
268         }
269     }
270     return false;
271 }
272 
EffectAutoMaxLines()273 void RosenRenderText::EffectAutoMaxLines()
274 {
275     // Effect when max-lines set auto.
276     if (!paragraph_ || !text_ || !text_->GetAutoMaxLines()) {
277         return;
278     }
279 
280     auto lineCount = GetTextLines();
281     while (lineCount > 0 && GreatNotEqual(paragraph_->GetHeight(), GetLayoutParam().GetMaxSize().Height())) {
282         textStyle_.SetMaxLines(--lineCount);
283         UpdateParagraphAndLayout(lastLayoutMaxWidth_);
284     }
285 }
286 
AdaptTextSize(double paragraphMaxWidth)287 bool RosenRenderText::AdaptTextSize(double paragraphMaxWidth)
288 {
289     const auto& preferTextSizeGroups = textStyle_.GetPreferTextSizeGroups();
290     if (!preferTextSizeGroups.empty()) {
291         return AdaptPreferTextSizeGroup(paragraphMaxWidth);
292     }
293     const auto& preferFontSizes = textStyle_.GetPreferFontSizes();
294     if (!preferFontSizes.empty()) {
295         return AdaptPreferTextSize(paragraphMaxWidth);
296     }
297     return AdaptMinTextSize(paragraphMaxWidth);
298 }
299 
AdaptMinTextSize(double paragraphMaxWidth)300 bool RosenRenderText::AdaptMinTextSize(double paragraphMaxWidth)
301 {
302     double maxFontSize = NormalizeToPx(textStyle_.GetAdaptMaxFontSize());
303     double minFontSize = NormalizeToPx(textStyle_.GetAdaptMinFontSize());
304     if (LessNotEqual(maxFontSize, minFontSize) || LessOrEqual(textStyle_.GetAdaptMinFontSize().Value(), 0.0)) {
305         if (!UpdateParagraph()) {
306             LOGE("fail to initialize text paragraph when adapt min text size.");
307             return false;
308         }
309         paragraph_->Layout(lastLayoutMaxWidth_);
310         return true;
311     }
312     Dimension step = ADAPT_UNIT;
313     if (GreatNotEqual(textStyle_.GetAdaptFontSizeStep().Value(), 0.0)) {
314         step = textStyle_.GetAdaptFontSizeStep();
315     }
316     double stepSize = NormalizeToPx(step);
317     while (GreatOrEqual(maxFontSize, minFontSize)) {
318         textStyle_.SetFontSize(Dimension(maxFontSize));
319         if (!UpdateParagraphAndLayout(paragraphMaxWidth)) {
320             return false;
321         }
322         if (!DidExceedMaxLines(paragraphMaxWidth)) {
323             break;
324         }
325         maxFontSize -= stepSize;
326     }
327     return true;
328 }
329 
AdaptPreferTextSize(double paragraphMaxWidth)330 bool RosenRenderText::AdaptPreferTextSize(double paragraphMaxWidth)
331 {
332     // Use preferFontSizes to adapt lines.
333     const auto& preferFontSizes = textStyle_.GetPreferFontSizes();
334     for (const auto& fontSize : preferFontSizes) {
335         textStyle_.SetFontSize(fontSize);
336         if (!UpdateParagraphAndLayout(paragraphMaxWidth)) {
337             return false;
338         }
339         if (!DidExceedMaxLines(paragraphMaxWidth)) {
340             break;
341         }
342     }
343     return true;
344 }
345 
AdaptPreferTextSizeGroup(double paragraphMaxWidth)346 bool RosenRenderText::AdaptPreferTextSizeGroup(double paragraphMaxWidth)
347 {
348     // Use preferTextSizeGroup.
349     const auto& preferTextSizeGroups = textStyle_.GetPreferTextSizeGroups();
350     for (const auto& preferTextSizeGroup : preferTextSizeGroups) {
351         textStyle_.SetFontSize(preferTextSizeGroup.fontSize);
352         textStyle_.SetMaxLines(preferTextSizeGroup.maxLines);
353         textStyle_.SetTextOverflow(preferTextSizeGroup.textOverflow);
354         if (!UpdateParagraphAndLayout(paragraphMaxWidth)) {
355             return false;
356         }
357         if ((preferTextSizeGroup.textOverflow == TextOverflow::NONE) || (!DidExceedMaxLines(paragraphMaxWidth))) {
358             break;
359         }
360     }
361     return true;
362 }
363 
UpdateParagraphAndLayout(double paragraphMaxWidth)364 bool RosenRenderText::UpdateParagraphAndLayout(double paragraphMaxWidth)
365 {
366     if (!UpdateParagraph()) {
367         return false;
368     }
369     if (paragraph_) {
370         paragraph_->Layout(paragraphMaxWidth);
371     }
372     return true;
373 }
374 
GetTextLines()375 uint32_t RosenRenderText::GetTextLines()
376 {
377     uint32_t textLines = 0;
378 #ifndef USE_GRAPHIC_TEXT_GINE
379     auto paragraphTxt = static_cast<txt::ParagraphTxt*>(paragraph_.get());
380     if (paragraphTxt != nullptr) {
381         textLines = paragraphTxt->GetLineCount();
382     }
383 #else
384     if (paragraph_ != nullptr) {
385         textLines = paragraph_->GetLineCount();
386     }
387 #endif
388     return textLines;
389 }
390 
GetTouchPosition(const Offset & offset)391 int32_t RosenRenderText::GetTouchPosition(const Offset& offset)
392 {
393     if (!paragraph_) {
394         return 0;
395     }
396 #ifndef USE_GRAPHIC_TEXT_GINE
397     return static_cast<int32_t>(paragraph_->GetGlyphPositionAtCoordinate(offset.GetX(), offset.GetY()).position);
398 #else
399     return static_cast<int32_t>(paragraph_->GetGlyphIndexByCoordinate(offset.GetX(), offset.GetY()).index);
400 #endif
401 }
402 
GetSize()403 Size RosenRenderText::GetSize()
404 {
405     double height = paragraph_ ? paragraph_->GetHeight() : 0.0;
406     double heightFinal = std::min(
407         height + std::fabs(NormalizeToPx(textStyle_.GetBaselineOffset())), GetLayoutParam().GetMaxSize().Height());
408     const auto& VerticalAlign = textStyle_.GetTextVerticalAlign();
409     if (((VerticalAlign == VerticalAlign::TOP || VerticalAlign == VerticalAlign::CENTER ||
410             VerticalAlign == VerticalAlign::BOTTOM)) &&
411         text_->GetDeclarationHeight().IsValid()) {
412         heightFinal = GetLayoutParam().GetMaxSize().Height();
413     }
414 
415     return Size(text_->GetMaxWidthLayout() ? paragraphNewWidth_ : std::ceil(paragraphNewWidth_), heightFinal);
416 }
417 
ApplyWhiteSpace()418 std::string RosenRenderText::ApplyWhiteSpace()
419 {
420     std::string data = text_->GetData();
421     switch (textStyle_.GetWhiteSpace()) {
422         case WhiteSpace::NORMAL:
423             StringUtils::ReplaceTabAndNewLine(data);
424             break;
425         case WhiteSpace::PRE:
426             break;
427         case WhiteSpace::NOWRAP:
428             textStyle_.SetMaxLines(1);
429             StringUtils::ReplaceTabAndNewLine(data);
430             break;
431         case WhiteSpace::PRE_WRAP:
432             break;
433         case WhiteSpace::PRE_LINE:
434             StringUtils::ReplaceSpace(data);
435             break;
436         default:
437             break;
438     }
439     return data;
440 }
441 
ApplyIndents(double width)442 void RosenRenderText::ApplyIndents(double width)
443 {
444     std::vector<float> indents;
445     double indent;
446     if (textStyle_.GetTextIndent().Unit() != DimensionUnit::PERCENT) {
447         indent = NormalizeToPx(textStyle_.GetTextIndent());
448     } else {
449         indent = width * textStyle_.GetTextIndent().Value();
450     }
451 
452     if (indent > 0.0) {
453         indents.push_back(indent);
454         indents.push_back(0.0);
455     } else {
456         indents.push_back(0.0);
457         indents.push_back(-indent);
458     }
459 }
460 
UpdateParagraph()461 bool RosenRenderText::UpdateParagraph()
462 {
463     if (!text_) {
464         return false;
465     }
466 
467     using namespace Constants;
468 
469 #ifndef USE_GRAPHIC_TEXT_GINE
470     txt::ParagraphStyle style;
471 #else
472     Rosen::TypographyStyle style;
473 #endif
474 
475     if (alignment_.has_value()) {
476         textStyle_.SetTextAlign(alignment_.value());
477     }
478     const auto& textAlign = textStyle_.GetTextAlign();
479     if (textAlign == TextAlign::START || textAlign == TextAlign::END) {
480         std::string data = text_->GetData();
481         if (!GetChildren().empty()) {
482             for (const auto& child : GetChildren()) {
483                 auto span = DynamicCast<RenderTextSpan>(child);
484                 if (span && !span->GetSpanData().empty()) {
485                     data = span->GetSpanData();
486                     break;
487                 }
488             }
489         }
490         if (!ChangeDirectionIfNeeded(data)) {
491             defaultTextDirection_ = text_->GetTextDirection();
492         }
493     }
494     std::string displayData = ApplyWhiteSpace();
495 #ifndef USE_GRAPHIC_TEXT_GINE
496     style.text_direction = ConvertTxtTextDirection(defaultTextDirection_);
497     style.text_align = ConvertTxtTextAlign(textAlign);
498     style.max_lines = textStyle_.GetMaxLines();
499 #else
500     style.textDirection = ConvertTxtTextDirection(defaultTextDirection_);
501     style.textAlign = ConvertTxtTextAlign(textAlign);
502     style.maxLines = textStyle_.GetMaxLines();
503 #endif
504     style.locale = Localization::GetInstance()->GetFontLocale();
505     if (textStyle_.GetTextOverflow() == TextOverflow::ELLIPSIS) {
506         if (!IsCompatibleVersion() && textStyle_.GetMaxLines() == UINT32_MAX && !text_->GetAutoMaxLines()) {
507 #ifndef USE_GRAPHIC_TEXT_GINE
508             style.max_lines = 1;
509 #else
510             style.maxLines = 1;
511 #endif
512         }
513         style.ellipsis = ELLIPSIS;
514         auto context = GetContext().Upgrade();
515         if (context && context->UseLiteStyle()) {
516 #ifndef USE_GRAPHIC_TEXT_GINE
517             style.max_lines = 1;
518 #else
519             style.maxLines = 1;
520 #endif
521         }
522     }
523 
524 #ifndef USE_GRAPHIC_TEXT_GINE
525     std::unique_ptr<txt::ParagraphBuilder> builder;
526 #endif
527 
528     auto fontCollection = RosenFontCollection::GetInstance().GetFontCollection();
529     if (!fontCollection) {
530         LOGW("UpdateParagraph: fontCollection is null");
531         return false;
532     }
533 #ifndef USE_GRAPHIC_TEXT_GINE
534     builder = txt::ParagraphBuilder::CreateTxtBuilder(style, fontCollection);
535 #else
536     auto builder = Rosen::TypographyCreate::Create(style, fontCollection);
537 #endif
538     std::string textValue = "";
539 
540 #ifndef USE_GRAPHIC_TEXT_GINE
541     txt::TextStyle txtStyle;
542 #else
543     Rosen::TextStyle txtStyle;
544 #endif
545     ConvertTxtStyle(textStyle_, context_, txtStyle);
546     builder->PushStyle(txtStyle);
547     const auto& children = GetChildren();
548     if (!children.empty()) {
549         touchRegions_.clear();
550         for (const auto& child : children) {
551             auto textSpan = AceType::DynamicCast<RosenRenderTextSpan>(child);
552             if (textSpan) {
553                 textSpan->UpdateText(*builder, touchRegions_, textValue);
554             }
555         }
556         textValue_.text = textValue;
557         textForDisplay_ = textValue;
558     } else {
559         StringUtils::TransformStrCase(displayData, (int32_t)textStyle_.GetTextCase());
560 #ifndef USE_GRAPHIC_TEXT_GINE
561         builder->AddText(StringUtils::Str8ToStr16(displayData));
562 #else
563         builder->AppendText(StringUtils::Str8ToStr16(displayData));
564 #endif
565     }
566 #ifndef USE_GRAPHIC_TEXT_GINE
567     paragraph_ = builder->Build();
568 #else
569     paragraph_ = builder->CreateTypography();
570 #endif
571 
572     ApplyIndents(GetLayoutParam().GetMaxSize().Width());
573     return true;
574 }
575 
GetTextWidth()576 double RosenRenderText::GetTextWidth()
577 {
578     if (!paragraph_) {
579         return 0.0;
580     }
581     if (!IsCompatibleVersion()) {
582         return paragraph_->GetMaxIntrinsicWidth();
583     }
584 #ifndef USE_GRAPHIC_TEXT_GINE
585     auto* paragraphTxt = static_cast<txt::ParagraphTxt*>(paragraph_.get());
586     if (paragraphTxt != nullptr && paragraphTxt->GetLineCount() == 1) {
587         return std::max(paragraph_->GetLongestLine(), paragraph_->GetMaxIntrinsicWidth());
588     }
589     return paragraph_->GetLongestLine();
590 #else
591     if (paragraph_ != nullptr && paragraph_->GetLineCount() == 1) {
592         return std::max(paragraph_->GetActualWidth(), paragraph_->GetMaxIntrinsicWidth());
593     }
594     return paragraph_->GetActualWidth();
595 #endif
596 }
597 
DidExceedMaxLines(double paragraphMaxWidth)598 bool RosenRenderText::DidExceedMaxLines(double paragraphMaxWidth)
599 {
600 #ifndef USE_GRAPHIC_TEXT_GINE
601     auto* paragraphTxt = static_cast<txt::ParagraphTxt*>(paragraph_.get());
602     if (paragraphTxt != nullptr) {
603         bool didExceedMaxLines = paragraphTxt->DidExceedMaxLines() ||
604                                  (textStyle_.GetAdaptHeight() &&
605                                      GreatNotEqual(paragraph_->GetHeight(), GetLayoutParam().GetMaxSize().Height()));
606 #else
607     if (paragraph_ != nullptr) {
608         bool didExceedMaxLines = paragraph_->DidExceedMaxLines() ||
609                                  (textStyle_.GetAdaptHeight() &&
610                                      GreatNotEqual(paragraph_->GetHeight(), GetLayoutParam().GetMaxSize().Height()));
611 #endif
612         if (textStyle_.GetMaxLines() == 1) {
613             return didExceedMaxLines || GreatNotEqual(GetTextWidth(), paragraphMaxWidth);
614         }
615         return didExceedMaxLines;
616     }
617     return false;
618 }
619 
620 bool RosenRenderText::ChangeDirectionIfNeeded(const std::string& data)
621 {
622     auto declaration = text_->GetDeclaration();
623     if (!declaration) {
624         return false;
625     }
626     auto& commonAttr = static_cast<CommonAttribute&>(declaration->GetAttribute(AttributeTag::COMMON_ATTR));
627     if (!commonAttr.IsValid() || commonAttr.direction != TextDirection::AUTO) {
628         return false;
629     }
630     auto showingTextForWString = StringUtils::ToWstring(data);
631     for (const auto& charOfShowingText : showingTextForWString) {
632         if (u_charDirection(charOfShowingText) == UCharDirection::U_LEFT_TO_RIGHT) {
633             defaultTextDirection_ = TextDirection::LTR;
634             return true;
635         } else if (u_charDirection(charOfShowingText) == UCharDirection::U_RIGHT_TO_LEFT) {
636             defaultTextDirection_ = TextDirection::RTL;
637             return true;
638         } else if (!IsCompatibleVersion() &&
639                    u_charDirection(charOfShowingText) == UCharDirection::U_RIGHT_TO_LEFT_ARABIC) {
640             defaultTextDirection_ = TextDirection::RTL;
641             return true;
642         }
643     }
644     return false;
645 }
646 
647 bool RosenRenderText::MaybeRelease()
648 {
649     auto context = GetContext().Upgrade();
650     if (context && context->GetRenderFactory() && context->GetRenderFactory()->GetRenderTextFactory()->Recycle(this)) {
651         ClearRenderObject();
652         return false;
653     }
654     return true;
655 }
656 
657 void RosenRenderText::ClearRenderObject()
658 {
659     RenderText::ClearRenderObject();
660     paragraph_ = nullptr;
661     paragraphNewWidth_ = 0.0;
662     lastLayoutMaxWidth_ = 0.0;
663     lastLayoutMinWidth_ = 0.0;
664     lastLayoutMaxHeight_ = 0.0;
665     lastLayoutMinHeight_ = 0.0;
666 }
667 
668 Offset RosenRenderText::GetHandleOffset(int32_t extend)
669 {
670     Rect result;
671     GetCaretRect(extend, result);
672     selectHeight_ = result.Bottom() - result.Top();
673     Offset handleLocalOffset = Offset((result.Left() + result.Right()) / 2.0, result.Bottom());
674     Offset handleOffset = handleLocalOffset + GetOffsetToPage();
675     return handleOffset;
676 }
677 
678 } // namespace OHOS::Ace
679