1 /*
2  * Copyright (c) 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_ng/pattern/text/text_content_modifier.h"
17 #include <cstdint>
18 #include <optional>
19 
20 #include "base/log/ace_trace.h"
21 #include "base/utils/utils.h"
22 #include "core/components_ng/pattern/text/text_pattern.h"
23 #include "core/components_ng/render/animation_utils.h"
24 #include "core/components_ng/render/drawing.h"
25 #include "core/components_ng/render/drawing_prop_convertor.h"
26 #include "core/components_ng/render/image_painter.h"
27 #include "core/components_v2/inspector/utils.h"
28 #include "core/pipeline_ng/pipeline_context.h"
29 #include "frameworks/core/components_ng/render/adapter/animated_image.h"
30 #include "frameworks/core/components_ng/render/adapter/pixelmap_image.h"
31 
32 namespace OHOS::Ace::NG {
33 namespace {
34 constexpr float RACE_MOVE_PERCENT_MIN = 0.0f;
35 constexpr float RACE_MOVE_PERCENT_MAX = 100.0f;
36 constexpr int32_t RACE_DURATION = 2000;
37 constexpr float RACE_SPACE_WIDTH = 48.0f;
38 constexpr Dimension DEFAULT_MARQUEE_SCROLL_AMOUNT = 6.0_vp;
39 constexpr double DEFAULT_MARQUEE_SCROLL_DELAY = 85.0; // Delay time between each jump.
40 constexpr float ROUND_VALUE = 0.5f;
41 constexpr uint32_t POINT_COUNT = 4;
42 constexpr float OBSCURED_ALPHA = 0.2f;
43 const FontWeight FONT_WEIGHT_CONVERT_MAP[] = {
44     FontWeight::W100,
45     FontWeight::W200,
46     FontWeight::W300,
47     FontWeight::W400,
48     FontWeight::W500,
49     FontWeight::W600,
50     FontWeight::W700,
51     FontWeight::W800,
52     FontWeight::W900,
53     FontWeight::W700,       // FontWeight::BOLD
54     FontWeight::W400,       // FontWeight::NORMAL
55     FontWeight::W900,       // FontWeight::BOLDER,
56     FontWeight::W100,       // FontWeight::LIGHTER
57     FontWeight::W500,       // FontWeight::MEDIUM
58     FontWeight::W400,       // FontWeight::REGULAR
59 };
60 
ConvertFontWeight(FontWeight fontWeight)61 inline FontWeight ConvertFontWeight(FontWeight fontWeight)
62 {
63     return FONT_WEIGHT_CONVERT_MAP[(int)fontWeight];
64 }
65 } // namespace
66 
TextContentModifier(const std::optional<TextStyle> & textStyle,const WeakPtr<Pattern> & pattern)67 TextContentModifier::TextContentModifier(const std::optional<TextStyle>& textStyle, const WeakPtr<Pattern>& pattern)
68     : pattern_(pattern)
69 {
70     auto patternUpgrade = pattern_.Upgrade();
71     CHECK_NULL_VOID(patternUpgrade);
72     auto textPattern = DynamicCast<TextPattern>(patternUpgrade);
73     CHECK_NULL_VOID(textPattern);
74     auto host = textPattern->GetHost();
75     CHECK_NULL_VOID(host);
76     auto geometryNode = host->GetGeometryNode();
77     CHECK_NULL_VOID(geometryNode);
78 
79     contentChange_ = MakeRefPtr<PropertyInt>(0);
80     AttachProperty(contentChange_);
81 
82     auto contentRect = geometryNode->GetContentRect();
83     contentOffset_ = MakeRefPtr<PropertyOffsetF>(contentRect.GetOffset());
84     contentSize_ = MakeRefPtr<PropertySizeF>(contentRect.GetSize());
85     AttachProperty(contentOffset_);
86     AttachProperty(contentSize_);
87     dragStatus_ = MakeRefPtr<PropertyBool>(false);
88     AttachProperty(dragStatus_);
89 
90     if (textStyle.has_value()) {
91         SetDefaultAnimatablePropertyValue(textStyle.value());
92     }
93 
94     racePercentFloat_ = MakeRefPtr<AnimatablePropertyFloat>(0.0f);
95     AttachProperty(racePercentFloat_);
96     if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
97         clip_ = MakeRefPtr<PropertyBool>(true);
98     } else {
99         clip_ = MakeRefPtr<PropertyBool>(false);
100     }
101     AttachProperty(clip_);
102     fontReady_ = MakeRefPtr<PropertyBool>(false);
103     AttachProperty(fontReady_);
104 
105     auto baselineOffset = textPattern->GetBaselineOffset();
106     paintOffset_ = contentRect.GetOffset() - OffsetF(0.0, std::min(baselineOffset, 0.0f));
107 }
108 
ChangeDragStatus()109 void TextContentModifier::ChangeDragStatus()
110 {
111     CHECK_NULL_VOID(dragStatus_);
112     dragStatus_->Set(!dragStatus_->Get());
113 }
114 
SetDefaultAnimatablePropertyValue(const TextStyle & textStyle)115 void TextContentModifier::SetDefaultAnimatablePropertyValue(const TextStyle& textStyle)
116 {
117     SetDefaultFontSize(textStyle);
118     SetDefaultAdaptMinFontSize(textStyle);
119     SetDefaultAdaptMaxFontSize(textStyle);
120     SetDefaultFontWeight(textStyle);
121     SetDefaultTextColor(textStyle);
122     SetDefaultTextShadow(textStyle);
123     SetDefaultTextDecoration(textStyle);
124     SetDefaultBaselineOffset(textStyle);
125     SetDefaultLineHeight(textStyle);
126 }
127 
SetDefaultFontSize(const TextStyle & textStyle)128 void TextContentModifier::SetDefaultFontSize(const TextStyle& textStyle)
129 {
130     float fontSizeValue = textStyle.GetFontSize().ConvertToPxDistribute(
131         textStyle.GetMinFontScale(), textStyle.GetMaxFontScale(), textStyle.IsAllowScale());
132     fontSizeFloat_ = MakeRefPtr<AnimatablePropertyFloat>(fontSizeValue);
133     AttachProperty(fontSizeFloat_);
134 }
135 
SetDefaultAdaptMinFontSize(const TextStyle & textStyle)136 void TextContentModifier::SetDefaultAdaptMinFontSize(const TextStyle& textStyle)
137 {
138     float fontSizeValue = textStyle.GetFontSize().Value();
139     auto pipelineContext = PipelineContext::GetCurrentContextSafely();
140     if (pipelineContext) {
141         fontSizeValue = textStyle.GetAdaptMinFontSize().ConvertToPxDistribute(
142             textStyle.GetMinFontScale(), textStyle.GetMaxFontScale(), textStyle.IsAllowScale());
143     }
144 
145     adaptMinFontSizeFloat_ = MakeRefPtr<AnimatablePropertyFloat>(fontSizeValue);
146     AttachProperty(adaptMinFontSizeFloat_);
147 }
148 
SetDefaultAdaptMaxFontSize(const TextStyle & textStyle)149 void TextContentModifier::SetDefaultAdaptMaxFontSize(const TextStyle& textStyle)
150 {
151     float fontSizeValue = textStyle.GetFontSize().Value();
152     auto pipelineContext = PipelineContext::GetCurrentContextSafely();
153     if (pipelineContext) {
154         fontSizeValue = textStyle.GetAdaptMaxFontSize().ConvertToPxDistribute(
155             textStyle.GetMinFontScale(), textStyle.GetMaxFontScale(), textStyle.IsAllowScale());
156     }
157 
158     adaptMaxFontSizeFloat_ = MakeRefPtr<AnimatablePropertyFloat>(fontSizeValue);
159     AttachProperty(adaptMaxFontSizeFloat_);
160 }
161 
SetDefaultFontWeight(const TextStyle & textStyle)162 void TextContentModifier::SetDefaultFontWeight(const TextStyle& textStyle)
163 {
164     fontWeightFloat_ =
165         MakeRefPtr<AnimatablePropertyFloat>(static_cast<float>(ConvertFontWeight(textStyle.GetFontWeight())));
166     AttachProperty(fontWeightFloat_);
167 }
168 
SetDefaultTextColor(const TextStyle & textStyle)169 void TextContentModifier::SetDefaultTextColor(const TextStyle& textStyle)
170 {
171     animatableTextColor_ = MakeRefPtr<AnimatablePropertyColor>(LinearColor(textStyle.GetTextColor()));
172     AttachProperty(animatableTextColor_);
173 }
174 
SetDefaultTextShadow(const TextStyle & textStyle)175 void TextContentModifier::SetDefaultTextShadow(const TextStyle& textStyle)
176 {
177     auto&& textShadows = textStyle.GetTextShadows();
178     if (textShadows.empty()) {
179         AddDefaultShadow();
180         return;
181     }
182     shadows_.clear();
183     shadows_.reserve(textShadows.size());
184     for (auto&& textShadow : textShadows) {
185         AddShadow(textShadow);
186     }
187 }
188 
AddShadow(const Shadow & shadow)189 void TextContentModifier::AddShadow(const Shadow& shadow)
190 {
191     auto shadowBlurRadiusFloat = MakeRefPtr<AnimatablePropertyFloat>(shadow.GetBlurRadius());
192     auto shadowOffsetXFloat = MakeRefPtr<AnimatablePropertyFloat>(shadow.GetOffset().GetX());
193     auto shadowOffsetYFloat = MakeRefPtr<AnimatablePropertyFloat>(shadow.GetOffset().GetY());
194     auto shadowColor = MakeRefPtr<AnimatablePropertyColor>(LinearColor(shadow.GetColor()));
195     Shadow textShadow;
196     textShadow.SetBlurRadius(shadow.GetBlurRadius());
197     textShadow.SetOffset(shadow.GetOffset());
198     textShadow.SetColor(shadow.GetColor());
199     shadows_.emplace_back(ShadowProp { .shadow = textShadow,
200         .blurRadius = shadowBlurRadiusFloat,
201         .offsetX = shadowOffsetXFloat,
202         .offsetY = shadowOffsetYFloat,
203         .color = shadowColor });
204     AttachProperty(shadowBlurRadiusFloat);
205     AttachProperty(shadowOffsetXFloat);
206     AttachProperty(shadowOffsetYFloat);
207     AttachProperty(shadowColor);
208 }
209 
SetDefaultTextDecoration(const TextStyle & textStyle)210 void TextContentModifier::SetDefaultTextDecoration(const TextStyle& textStyle)
211 {
212     textDecoration_ = textStyle.GetTextDecoration();
213     textDecorationColor_ = textStyle.GetTextDecorationColor();
214     textDecorationColorAlpha_ = MakeRefPtr<AnimatablePropertyFloat>(
215         textDecoration_ == TextDecoration::NONE ? 0.0f : textDecorationColor_->GetAlpha());
216     AttachProperty(textDecorationColorAlpha_);
217 }
SetDefaultBaselineOffset(const TextStyle & textStyle)218 void TextContentModifier::SetDefaultBaselineOffset(const TextStyle& textStyle)
219 {
220     float baselineOffset = textStyle.GetBaselineOffset().Value();
221     auto pipelineContext = PipelineContext::GetCurrentContextSafely();
222     if (pipelineContext) {
223         baselineOffset = textStyle.GetBaselineOffset().ConvertToPxDistribute(
224             textStyle.GetMinFontScale(), textStyle.GetMaxFontScale(), textStyle.IsAllowScale());
225     }
226 
227     baselineOffsetFloat_ = MakeRefPtr<AnimatablePropertyFloat>(baselineOffset);
228     AttachProperty(baselineOffsetFloat_);
229 }
230 
SetDefaultLineHeight(const TextStyle & textStyle)231 void TextContentModifier::SetDefaultLineHeight(const TextStyle& textStyle)
232 {
233     float lineHeight = textStyle.GetLineHeight().Value();
234     auto pipelineContext = PipelineContext::GetCurrentContextSafelyWithCheck();
235     if (pipelineContext) {
236         lineHeight = textStyle.GetLineHeight().ConvertToPxDistribute(
237             textStyle.GetMinFontScale(), textStyle.GetMaxFontScale(), textStyle.IsAllowScale());
238     }
239 
240     lineHeightFloat_ = MakeRefPtr<AnimatablePropertyFloat>(lineHeight);
241     AttachProperty(lineHeightFloat_);
242 }
243 
SetClip(bool clip)244 void TextContentModifier::SetClip(bool clip)
245 {
246     if (clip_) {
247         clip_->Set(clip);
248     }
249 }
250 
SetFontReady(bool value)251 void TextContentModifier::SetFontReady(bool value)
252 {
253     if (fontReady_) {
254         fontReady_->Set(value);
255     }
256 }
257 
UpdateImageNodeVisible(const VisibleType visible)258 void TextContentModifier::UpdateImageNodeVisible(const VisibleType visible)
259 {
260     for (const auto& imageWeak : imageNodeList_) {
261         auto imageNode = imageWeak.Upgrade();
262         if (!imageNode) {
263             continue;
264         }
265         auto layoutProperty = imageNode->GetLayoutProperty();
266         if (!layoutProperty) {
267             continue;
268         }
269         layoutProperty->UpdateVisibility(visible, true);
270     }
271 }
272 
PaintImage(RSCanvas & canvas,float x,float y)273 void TextContentModifier::PaintImage(RSCanvas& canvas, float x, float y)
274 {
275     if (!AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
276         return;
277     }
278     auto pattern = DynamicCast<TextPattern>(pattern_.Upgrade());
279     CHECK_NULL_VOID(pattern);
280     size_t index = 0;
281     auto rectsForPlaceholders = pattern->GetRectsForPlaceholders();
282     auto placeHolderIndexVector = pattern->GetPlaceHolderIndex();
283     auto placeholdersSize = rectsForPlaceholders.size();
284     auto placeHolderIndexSize = static_cast<int32_t>(placeHolderIndexVector.size());
285     for (const auto& imageWeak : imageNodeList_) {
286         auto imageChild = imageWeak.Upgrade();
287         if (!imageChild) {
288             continue;
289         }
290         if (index >= placeholdersSize) {
291             return;
292         }
293         auto tmp = static_cast<int32_t>(placeHolderIndexVector.at(index));
294         if (tmp >= placeHolderIndexSize || tmp < 0) {
295             return;
296         }
297         auto rect = rectsForPlaceholders.at(tmp);
298         if (!DrawImage(imageChild, canvas, x, y, rect)) {
299             continue;
300         }
301         ++index;
302     }
303 }
304 
DrawImage(const RefPtr<FrameNode> & imageNode,RSCanvas & canvas,float x,float y,const RectF & rect)305 bool TextContentModifier::DrawImage(const RefPtr<FrameNode>& imageNode, RSCanvas& canvas, float x, float y,
306     const RectF& rect)
307 {
308     CHECK_NULL_RETURN(imageNode, false);
309     auto imagePattern = DynamicCast<ImagePattern>(imageNode->GetPattern());
310     if (!imagePattern) {
311         return false;
312     }
313     auto layoutProperty = imageNode->GetLayoutProperty<ImageLayoutProperty>();
314     if (!layoutProperty) {
315         return false;
316     }
317     const auto& marginProperty = layoutProperty->GetMarginProperty();
318     float marginTop = 0.0f;
319     float marginLeft = 0.0f;
320     if (marginProperty) {
321         marginLeft = marginProperty->left.has_value() ? marginProperty->left->GetDimension().ConvertToPx() : 0.0f;
322         marginTop = marginProperty->top.has_value() ? marginProperty->top->GetDimension().ConvertToPx() : 0.0f;
323     }
324     auto canvasImage = imagePattern->GetCanvasImage();
325     if (!canvasImage) {
326         canvasImage = imagePattern->GetAltCanvasImage();
327     }
328     if (AceType::InstanceOf<AnimatedImage>(canvasImage)) {
329         auto animatedImage = DynamicCast<AnimatedImage>(canvasImage);
330         if (!animatedImage->GetIsAnimating()) {
331             animatedImage->ControlAnimation(true);
332         }
333     }
334     auto geometryNode = imageNode->GetGeometryNode();
335     if (!canvasImage || !geometryNode) {
336         return false;
337     }
338     RectF imageRect(rect.Left() + x + marginLeft, rect.Top() + y + marginTop,
339         geometryNode->GetFrameSize().Width(), geometryNode->GetFrameSize().Height());
340     const auto config = canvasImage->GetPaintConfig();
341     SizeF imageSize(canvasImage->GetWidth(), canvasImage->GetHeight());
342     SizeF contentSize(geometryNode->GetFrameSize().Width(), geometryNode->GetFrameSize().Height());
343     RectF srcRect;
344     RectF dstRect;
345     ImagePainter::ApplyImageFit(config.imageFit_, imageSize, contentSize, srcRect, dstRect);
346     canvasImage->DrawRect(canvas, ToRSRect(srcRect), ToRSRect(imageRect));
347     return true;
348 }
349 
PaintCustomSpan(DrawingContext & drawingContext)350 void TextContentModifier::PaintCustomSpan(DrawingContext& drawingContext)
351 {
352     auto pattern = DynamicCast<TextPattern>(pattern_.Upgrade());
353     CHECK_NULL_VOID(pattern);
354     auto pManager = pattern->GetParagraphManager();
355     CHECK_NULL_VOID(pManager);
356     auto rectsForPlaceholders = pattern->GetRectsForPlaceholders();
357     auto customSpanPlaceholderInfo = pattern->GetCustomSpanPlaceholderInfo();
358     auto x = paintOffset_.GetX();
359     auto y = paintOffset_.GetY();
360     auto rectsForPlaceholderSize = rectsForPlaceholders.size();
361     for (const auto& customSpanPlaceholder : customSpanPlaceholderInfo) {
362         if (!customSpanPlaceholder.onDraw) {
363             continue;
364         }
365         auto index = customSpanPlaceholder.customSpanIndex;
366         if (index >= static_cast<int32_t>(rectsForPlaceholderSize) || index < 0) {
367             return;
368         }
369         auto rect = rectsForPlaceholders.at(index);
370         auto lineMetrics = pManager->GetLineMetricsByRectF(rect, customSpanPlaceholder.paragraphIndex);
371         CustomSpanOptions customSpanOptions;
372         customSpanOptions.x = static_cast<float>(rect.Left()) + x;
373         customSpanOptions.lineTop = lineMetrics.y + y;
374         customSpanOptions.lineBottom = lineMetrics.y + lineMetrics.height + y;
375         customSpanOptions.baseline = lineMetrics.y + lineMetrics.ascender + y;
376         customSpanPlaceholder.onDraw(drawingContext, customSpanOptions);
377     }
378 }
379 
onDraw(DrawingContext & drawingContext)380 void TextContentModifier::onDraw(DrawingContext& drawingContext)
381 {
382     auto textPattern = DynamicCast<TextPattern>(pattern_.Upgrade());
383     CHECK_NULL_VOID(textPattern);
384     auto pManager = textPattern->GetParagraphManager();
385     CHECK_NULL_VOID(pManager);
386     if (pManager->GetParagraphs().empty()) {
387         textPattern->DumpRecord(",onDraw GetParagraphs empty:");
388         return;
389     }
390     auto host = textPattern->GetHost();
391     CHECK_NULL_VOID(host);
392     ACE_SCOPED_TRACE(
393         "Text[id:%d] paint[offset:%f,%f]", host->GetId(), paintOffset_.GetX(), paintOffset_.GetY());
394     PropertyChangeFlag flag = 0;
395     if (NeedMeasureUpdate(flag)) {
396         host->MarkDirtyNode(flag);
397     }
398     if (!ifPaintObscuration_) {
399         auto& canvas = drawingContext.canvas;
400         CHECK_NULL_VOID(contentSize_);
401         CHECK_NULL_VOID(contentOffset_);
402         auto contentSize = contentSize_->Get();
403         auto contentOffset = contentOffset_->Get();
404         canvas.Save();
405         if (clip_ && clip_->Get() &&
406             (!fontSize_.has_value() || !fontSizeFloat_ ||
407                 NearEqual(fontSize_.value().Value(), fontSizeFloat_->Get()))) {
408             RSRect clipInnerRect = RSRect(contentOffset.GetX(), contentOffset.GetY(),
409                 contentSize.Width() + contentOffset.GetX(), contentSize.Height() + contentOffset.GetY());
410             canvas.ClipRect(clipInnerRect, RSClipOp::INTERSECT);
411         }
412         if (!CheckMarqueeState(MarqueeState::RUNNING)) {
413             auto paintOffsetY = paintOffset_.GetY();
414             textPattern->DumpRecord(",Paint id:" + std::to_string(host->GetId()));
415             auto paragraphs = pManager->GetParagraphs();
416             for (auto && info : paragraphs) {
417                 auto paragraph = info.paragraph;
418                 CHECK_NULL_VOID(paragraph);
419                 paragraph->Paint(canvas, paintOffset_.GetX(), paintOffsetY);
420                 paintOffsetY += paragraph->GetHeight();
421             }
422         } else {
423             // Racing
424             DrawTextRacing(drawingContext);
425         }
426         canvas.Restore();
427     } else {
428         DrawObscuration(drawingContext);
429     }
430     PaintCustomSpan(drawingContext);
431 }
432 
DrawTextRacing(DrawingContext & drawingContext)433 void TextContentModifier::DrawTextRacing(DrawingContext& drawingContext)
434 {
435     auto pattern = DynamicCast<TextPattern>(pattern_.Upgrade());
436     CHECK_NULL_VOID(pattern);
437     auto pManager = pattern->GetParagraphManager();
438     CHECK_NULL_VOID(pManager);
439     auto paragraph = pManager->GetParagraphs().front().paragraph;
440     float textRacePercent = GetTextRaceDirection() == TextDirection::LTR ? GetTextRacePercent()
441                                                                          : RACE_MOVE_PERCENT_MAX - GetTextRacePercent();
442     float paragraph1Offset =
443         (paragraph->GetTextWidth() + textRaceSpaceWidth_) * textRacePercent / RACE_MOVE_PERCENT_MAX * -1;
444     if ((paintOffset_.GetX() + paragraph1Offset + paragraph->GetTextWidth()) > 0) {
445         paragraph->Paint(drawingContext.canvas, paintOffset_.GetX() + paragraph1Offset, paintOffset_.GetY());
446         PaintImage(drawingContext.canvas, paintOffset_.GetX() + paragraph1Offset, paintOffset_.GetY());
447     }
448     float paragraph2Offset = paragraph1Offset + paragraph->GetTextWidth() + textRaceSpaceWidth_;
449     if ((paintOffset_.GetX() + paragraph2Offset) < drawingContext.width) {
450         paragraph->Paint(drawingContext.canvas, paintOffset_.GetX() + paragraph2Offset, paintOffset_.GetY());
451         PaintImage(drawingContext.canvas, paintOffset_.GetX() + paragraph2Offset, paintOffset_.GetY());
452     }
453 }
454 
DrawObscuration(DrawingContext & drawingContext)455 void TextContentModifier::DrawObscuration(DrawingContext& drawingContext)
456 {
457     RSCanvas& canvas = drawingContext.canvas;
458     RSBrush brush;
459     std::vector<RSPoint> radiusXY(POINT_COUNT);
460     Dimension borderRadius = Dimension(2.0, DimensionUnit::VP);
461     for (auto& radius : radiusXY) {
462         radius.SetX(static_cast<float>(borderRadius.ConvertToPx()));
463         radius.SetY(static_cast<float>(borderRadius.ConvertToPx()));
464     }
465     CHECK_NULL_VOID(animatableTextColor_);
466     Color fillColor = Color(animatableTextColor_->Get().GetValue());
467     RSColor rrSColor(fillColor.GetRed(), fillColor.GetGreen(), fillColor.GetBlue(),
468         (uint32_t)(fillColor.GetAlpha() * OBSCURED_ALPHA));
469     brush.SetColor(rrSColor);
470     brush.SetAntiAlias(true);
471     canvas.AttachBrush(brush);
472     CHECK_NULL_VOID(fontSizeFloat_);
473     float fontSize = fontSizeFloat_->Get();
474     std::vector<float> textLineWidth;
475     float currentLineWidth = 0.0f;
476     int32_t maxLineCount = 0;
477     CHECK_NULL_VOID(contentSize_);
478     CHECK_NULL_VOID(contentOffset_);
479     for (auto i = 0U; i < drawObscuredRects_.size(); i++) {
480         if (!NearEqual(drawObscuredRects_[i].Width(), 0.0f) && !NearEqual(drawObscuredRects_[i].Height(), 0.0f)) {
481             currentLineWidth += drawObscuredRects_[i].Width();
482             if (i == (!drawObscuredRects_.empty() ? drawObscuredRects_.size() - 1 : 0)) {
483                 textLineWidth.push_back(currentLineWidth);
484                 maxLineCount += LessOrEqual(drawObscuredRects_[i].Bottom(), contentSize_->Get().Height()) ? 1 : 0;
485             } else if (!NearEqual(drawObscuredRects_[i].Bottom(), drawObscuredRects_[i + 1].Bottom())) {
486                 textLineWidth.push_back(currentLineWidth);
487                 maxLineCount += LessOrEqual(drawObscuredRects_[i].Bottom(), contentSize_->Get().Height()) ? 1 : 0;
488                 currentLineWidth = 0;
489             } else {
490                 /** nothing to do **/
491             }
492         }
493     }
494     CHECK_NULL_VOID(baselineOffsetFloat_);
495     auto baselineOffset = baselineOffsetFloat_->Get();
496     int32_t obscuredLineCount = std::min(maxLineCount, static_cast<int32_t>(textLineWidth.size()));
497     float offsetY = (contentSize_->Get().Height() - std::fabs(baselineOffset) - (obscuredLineCount * fontSize)) /
498                     (obscuredLineCount + 1);
499     for (auto i = 0; i < obscuredLineCount; i++) {
500         RSRoundRect rSRoundRect(
501             RSRect(contentOffset_->Get().GetX(),
502                 contentOffset_->Get().GetY() - std::min(baselineOffset, 0.0f) +
503                     std::max(offsetY + ((offsetY + fontSize) * i), 0.0f),
504                 contentOffset_->Get().GetX() + std::min(textLineWidth[i], contentSize_->Get().Width()),
505                 contentOffset_->Get().GetY() - std::min(baselineOffset, 0.0f) +
506                     std::min(offsetY + ((offsetY + fontSize) * i) + fontSize, contentSize_->Get().Height())),
507             radiusXY);
508         canvas.DrawRoundRect(rSRoundRect);
509     }
510     canvas.DetachBrush();
511 }
512 
ModifyFontSizeInTextStyle(TextStyle & textStyle)513 void TextContentModifier::ModifyFontSizeInTextStyle(TextStyle& textStyle)
514 {
515     if (fontSize_.has_value() && fontSizeFloat_) {
516         lastFontSize_ = fontSizeFloat_->Get();
517         textStyle.SetFontSize(Dimension(fontSizeFloat_->Get(), DimensionUnit::PX));
518     }
519 }
520 
ModifyAdaptMinFontSizeInTextStyle(TextStyle & textStyle)521 void TextContentModifier::ModifyAdaptMinFontSizeInTextStyle(TextStyle& textStyle)
522 {
523     if (adaptMinFontSize_.has_value() && adaptMinFontSizeFloat_) {
524         lastMinFontSize_ = adaptMinFontSizeFloat_->Get();
525         textStyle.SetAdaptMinFontSize(Dimension(adaptMinFontSizeFloat_->Get(), DimensionUnit::PX));
526     }
527 }
528 
ModifyAdaptMaxFontSizeInTextStyle(TextStyle & textStyle)529 void TextContentModifier::ModifyAdaptMaxFontSizeInTextStyle(TextStyle& textStyle)
530 {
531     if (adaptMaxFontSize_.has_value() && adaptMaxFontSizeFloat_) {
532         lastMaxFontSize_ = adaptMaxFontSizeFloat_->Get();
533         textStyle.SetAdaptMaxFontSize(Dimension(adaptMaxFontSizeFloat_->Get(), DimensionUnit::PX));
534     }
535 }
536 
ModifyFontWeightInTextStyle(TextStyle & textStyle)537 void TextContentModifier::ModifyFontWeightInTextStyle(TextStyle& textStyle)
538 {
539     if (fontWeight_.has_value() && fontWeightFloat_) {
540         lastFontWeight_ = fontWeightFloat_->Get();
541         textStyle.SetFontWeight(static_cast<FontWeight>(std::floor(fontWeightFloat_->Get() + ROUND_VALUE)));
542     }
543 }
544 
ModifyTextColorInTextStyle(TextStyle & textStyle)545 void TextContentModifier::ModifyTextColorInTextStyle(TextStyle& textStyle)
546 {
547     if (textColor_.has_value() && animatableTextColor_) {
548         lastTextColor_.SetValue(animatableTextColor_->Get().GetValue());
549         textStyle.SetTextColor(Color(animatableTextColor_->Get().GetValue()));
550     }
551 }
552 
ModifyTextShadowsInTextStyle(TextStyle & textStyle)553 void TextContentModifier::ModifyTextShadowsInTextStyle(TextStyle& textStyle)
554 {
555     std::vector<Shadow> shadows;
556     shadows.reserve(shadows_.size());
557     for (auto&& shadow : shadows_) {
558         auto blurRadius = shadow.blurRadius->Get();
559         auto offsetX = shadow.offsetX->Get();
560         auto offsetY = shadow.offsetY->Get();
561         auto color = shadow.color->Get();
562         auto shadowValue = Shadow(blurRadius, 0, Offset(offsetX, offsetY), Color(color.GetValue()));
563         shadow.lastShadow = shadowValue;
564         shadows.emplace_back(shadowValue);
565     }
566     textStyle.SetTextShadows(shadows);
567 }
568 
ModifyDecorationInTextStyle(TextStyle & textStyle)569 void TextContentModifier::ModifyDecorationInTextStyle(TextStyle& textStyle)
570 {
571     if (textDecoration_.has_value() && textDecorationColor_.has_value() && textDecorationColorAlpha_) {
572         if (textDecorationAnimatable_) {
573             uint8_t alpha = static_cast<uint8_t>(std::floor(textDecorationColorAlpha_->Get() + ROUND_VALUE));
574             if (alpha == 0) {
575                 textStyle.SetTextDecoration(TextDecoration::NONE);
576                 textStyle.SetTextDecorationColor(textDecorationColor_.value());
577             } else {
578                 textStyle.SetTextDecoration(TextDecoration::UNDERLINE);
579                 textStyle.SetTextDecorationColor(Color(textDecorationColor_.value()).ChangeAlpha(alpha));
580             }
581             lastTextDecorationColorAlpha_ = textDecorationColorAlpha_->Get();
582         } else {
583             textStyle.SetTextDecoration(textDecoration_.value());
584             textStyle.SetTextDecorationColor(textDecorationColor_.value());
585         }
586     }
587 }
588 
ModifyBaselineOffsetInTextStyle(TextStyle & textStyle)589 void TextContentModifier::ModifyBaselineOffsetInTextStyle(TextStyle& textStyle)
590 {
591     if (baselineOffset_.has_value() && baselineOffsetFloat_) {
592         lastBaselineOffsetFloat_ = baselineOffsetFloat_->Get();
593         textStyle.SetBaselineOffset(Dimension(baselineOffsetFloat_->Get(), DimensionUnit::PX));
594     }
595 }
596 
ModifyLineHeightInTextStyle(TextStyle & textStyle)597 void TextContentModifier::ModifyLineHeightInTextStyle(TextStyle& textStyle)
598 {
599     if (lineHeight_.has_value() && lineHeightFloat_) {
600         lastLineHeight_ = lineHeightFloat_->Get();
601         textStyle.SetLineHeight(Dimension(lineHeightFloat_->Get(), DimensionUnit::PX));
602     }
603 }
604 
ModifyTextStyle(TextStyle & textStyle)605 void TextContentModifier::ModifyTextStyle(TextStyle& textStyle)
606 {
607     ModifyFontSizeInTextStyle(textStyle);
608     ModifyAdaptMinFontSizeInTextStyle(textStyle);
609     ModifyAdaptMaxFontSizeInTextStyle(textStyle);
610     ModifyFontWeightInTextStyle(textStyle);
611     ModifyTextColorInTextStyle(textStyle);
612     ModifyTextShadowsInTextStyle(textStyle);
613     ModifyDecorationInTextStyle(textStyle);
614     ModifyBaselineOffsetInTextStyle(textStyle);
615     ModifyLineHeightInTextStyle(textStyle);
616 }
617 
CheckNeedMeasure(float finalValue,float lastValue,float currentValue)618 bool TextContentModifier::CheckNeedMeasure(float finalValue, float lastValue, float currentValue)
619 {
620     return !NearEqual(finalValue, currentValue) || !NearEqual(lastValue, currentValue);
621 }
622 
UpdateFontSizeMeasureFlag(PropertyChangeFlag & flag)623 void TextContentModifier::UpdateFontSizeMeasureFlag(PropertyChangeFlag& flag)
624 {
625     if (fontSize_.has_value() && fontSizeFloat_ &&
626         CheckNeedMeasure(fontSize_.value().Value(), lastFontSize_, fontSizeFloat_->Get())) {
627         flag |= PROPERTY_UPDATE_MEASURE;
628         lastFontSize_ = fontSizeFloat_->Get();
629     }
630 }
631 
UpdateAdaptMinFontSizeMeasureFlag(PropertyChangeFlag & flag)632 void TextContentModifier::UpdateAdaptMinFontSizeMeasureFlag(PropertyChangeFlag& flag)
633 {
634     if (adaptMinFontSize_.has_value() && adaptMinFontSizeFloat_ &&
635         CheckNeedMeasure(adaptMinFontSize_.value().Value(), lastMinFontSize_, adaptMinFontSizeFloat_->Get())) {
636         flag |= PROPERTY_UPDATE_MEASURE;
637         lastMinFontSize_ = adaptMinFontSizeFloat_->Get();
638     }
639 }
640 
UpdateAdaptMaxFontSizeMeasureFlag(PropertyChangeFlag & flag)641 void TextContentModifier::UpdateAdaptMaxFontSizeMeasureFlag(PropertyChangeFlag& flag)
642 {
643     if (adaptMaxFontSize_.has_value() && adaptMaxFontSizeFloat_ &&
644         CheckNeedMeasure(adaptMaxFontSize_.value().Value(), lastMaxFontSize_, adaptMaxFontSizeFloat_->Get())) {
645         flag |= PROPERTY_UPDATE_MEASURE;
646         lastMaxFontSize_ = adaptMaxFontSizeFloat_->Get();
647     }
648 }
649 
UpdateFontWeightMeasureFlag(PropertyChangeFlag & flag)650 void TextContentModifier::UpdateFontWeightMeasureFlag(PropertyChangeFlag& flag)
651 {
652     if (fontWeight_.has_value() && fontWeightFloat_ &&
653         CheckNeedMeasure(
654             static_cast<float>(static_cast<int>(fontWeight_.value())), lastFontWeight_, fontWeightFloat_->Get())) {
655         flag |= PROPERTY_UPDATE_MEASURE;
656         lastFontWeight_ = fontWeightFloat_->Get();
657     }
658 }
659 
UpdateTextColorMeasureFlag(PropertyChangeFlag & flag)660 void TextContentModifier::UpdateTextColorMeasureFlag(PropertyChangeFlag& flag)
661 {
662     if (textColor_.has_value() && animatableTextColor_ &&
663         (textColor_->GetValue() != animatableTextColor_->Get().GetValue() ||
664             lastTextColor_.GetValue() != animatableTextColor_->Get().GetValue())) {
665         flag |= PROPERTY_UPDATE_MEASURE_SELF;
666         lastTextColor_.SetValue(animatableTextColor_->Get().GetValue());
667     }
668 }
669 
UpdateTextShadowMeasureFlag(PropertyChangeFlag & flag)670 void TextContentModifier::UpdateTextShadowMeasureFlag(PropertyChangeFlag& flag)
671 {
672     for (auto&& shadow : shadows_) {
673         auto blurRadius = shadow.blurRadius->Get();
674         auto offsetX = shadow.offsetX->Get();
675         auto offsetY = shadow.offsetY->Get();
676         auto color = shadow.color->Get();
677         auto compareShadow = Shadow(blurRadius, 0, Offset(offsetX, offsetY), Color(color.GetValue()));
678         if (shadow.shadow != compareShadow || shadow.lastShadow != compareShadow) {
679             flag |= PROPERTY_UPDATE_MEASURE;
680             shadow.lastShadow = compareShadow;
681             return;
682         }
683     }
684 }
685 
UpdateTextDecorationMeasureFlag(PropertyChangeFlag & flag)686 void TextContentModifier::UpdateTextDecorationMeasureFlag(PropertyChangeFlag& flag)
687 {
688     if (textDecoration_.has_value() && textDecorationColor_.has_value() && textDecorationColorAlpha_) {
689         uint8_t alpha = static_cast<uint8_t>(std::floor(textDecorationColorAlpha_->Get() + ROUND_VALUE));
690         if (textDecoration_.value() == TextDecoration::UNDERLINE &&
691             (alpha != textDecorationColor_.value().GetAlpha() ||
692                 !NearEqual(textDecorationColorAlpha_->Get(), lastTextDecorationColorAlpha_))) {
693             flag |= PROPERTY_UPDATE_MEASURE;
694         } else if (textDecoration_.value() == TextDecoration::NONE &&
695                    (alpha != 0.0 || !NearZero(lastTextDecorationColorAlpha_))) {
696             flag |= PROPERTY_UPDATE_MEASURE;
697         }
698         lastTextDecorationColorAlpha_ = textDecorationColorAlpha_->Get();
699     }
700 }
701 
UpdateBaselineOffsetMeasureFlag(PropertyChangeFlag & flag)702 void TextContentModifier::UpdateBaselineOffsetMeasureFlag(PropertyChangeFlag& flag)
703 {
704     if (baselineOffset_.has_value() && baselineOffsetFloat_ &&
705         CheckNeedMeasure(baselineOffset_.value().Value(), lastBaselineOffsetFloat_, baselineOffsetFloat_->Get())) {
706         flag |= PROPERTY_UPDATE_MEASURE;
707         lastBaselineOffsetFloat_ = baselineOffsetFloat_->Get();
708     }
709 }
710 
UpdateLineHeightMeasureFlag(PropertyChangeFlag & flag)711 void TextContentModifier::UpdateLineHeightMeasureFlag(PropertyChangeFlag& flag)
712 {
713     if (lineHeight_.has_value() && lineHeightFloat_ &&
714         CheckNeedMeasure(lineHeight_.value().Value(), lastLineHeight_, lineHeightFloat_->Get())) {
715         flag |= PROPERTY_UPDATE_MEASURE;
716         lastLineHeight_ = lineHeightFloat_->Get();
717     }
718 }
719 
NeedMeasureUpdate(PropertyChangeFlag & flag)720 bool TextContentModifier::NeedMeasureUpdate(PropertyChangeFlag& flag)
721 {
722     flag = 0;
723     UpdateFontSizeMeasureFlag(flag);
724     UpdateAdaptMinFontSizeMeasureFlag(flag);
725     UpdateAdaptMaxFontSizeMeasureFlag(flag);
726     UpdateFontWeightMeasureFlag(flag);
727     UpdateTextColorMeasureFlag(flag);
728     UpdateTextShadowMeasureFlag(flag);
729     UpdateTextDecorationMeasureFlag(flag);
730     UpdateBaselineOffsetMeasureFlag(flag);
731     UpdateLineHeightMeasureFlag(flag);
732     flag &= (PROPERTY_UPDATE_MEASURE | PROPERTY_UPDATE_MEASURE_SELF | PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
733     return flag;
734 }
735 
SetFontSize(const Dimension & value,const TextStyle & textStyle,bool isReset)736 void TextContentModifier::SetFontSize(const Dimension& value, const TextStyle& textStyle, bool isReset)
737 {
738     auto fontSizeValue =
739         value.ConvertToPxDistribute(textStyle.GetMinFontScale(), textStyle.GetMaxFontScale(), textStyle.IsAllowScale());
740     if (!isReset) {
741         fontSize_ = Dimension(fontSizeValue);
742     } else {
743         fontSize_ = std::nullopt;
744     }
745     CHECK_NULL_VOID(fontSizeFloat_);
746     fontSizeFloat_->Set(fontSizeValue);
747 }
748 
SetAdaptMinFontSize(const Dimension & value,const TextStyle & textStyle,bool isReset)749 void TextContentModifier::SetAdaptMinFontSize(const Dimension& value, const TextStyle& textStyle, bool isReset)
750 {
751     auto fontSizeValue =
752         value.ConvertToPxDistribute(textStyle.GetMinFontScale(), textStyle.GetMaxFontScale(), textStyle.IsAllowScale());
753     if (!isReset) {
754         adaptMinFontSize_ = Dimension(fontSizeValue);
755     } else {
756         adaptMinFontSize_ = std::nullopt;
757     }
758     CHECK_NULL_VOID(adaptMinFontSizeFloat_);
759     adaptMinFontSizeFloat_->Set(fontSizeValue);
760 }
761 
SetAdaptMaxFontSize(const Dimension & value,const TextStyle & textStyle,bool isReset)762 void TextContentModifier::SetAdaptMaxFontSize(const Dimension& value, const TextStyle& textStyle, bool isReset)
763 {
764     auto fontSizeValue =
765         value.ConvertToPxDistribute(textStyle.GetMinFontScale(), textStyle.GetMaxFontScale(), textStyle.IsAllowScale());
766     if (!isReset) {
767         adaptMaxFontSize_ = Dimension(fontSizeValue);
768     } else {
769         adaptMaxFontSize_ = std::nullopt;
770     }
771     CHECK_NULL_VOID(adaptMaxFontSizeFloat_);
772     adaptMaxFontSizeFloat_->Set(fontSizeValue);
773 }
774 
SetFontWeight(const FontWeight & value,bool isReset)775 void TextContentModifier::SetFontWeight(const FontWeight& value, bool isReset)
776 {
777     if (!isReset) {
778         fontWeight_ = ConvertFontWeight(value);
779     } else {
780         fontWeight_ = std::nullopt;
781     }
782     CHECK_NULL_VOID(fontWeightFloat_);
783     fontWeightFloat_->Set(static_cast<int>(ConvertFontWeight(value)));
784 }
785 
SetTextColor(const Color & value,bool isReset)786 void TextContentModifier::SetTextColor(const Color& value, bool isReset)
787 {
788     if (!isReset) {
789         textColor_ = value;
790     } else {
791         textColor_ = std::nullopt;
792     }
793     CHECK_NULL_VOID(animatableTextColor_);
794     animatableTextColor_->Set(LinearColor(value));
795 }
796 
SetTextShadow(const std::vector<Shadow> & value)797 void TextContentModifier::SetTextShadow(const std::vector<Shadow>& value)
798 {
799     while (value.size() > shadows_.size()) {
800         AddDefaultShadow();
801     }
802     // else
803     while (value.size() < shadows_.size()) {
804         shadows_.pop_back();
805     }
806 
807     for (size_t i = 0; i < shadows_.size(); ++i) {
808         auto&& newShadow = value[i];
809         Shadow textShadow;
810         textShadow.SetBlurRadius(newShadow.GetBlurRadius());
811         textShadow.SetOffset(newShadow.GetOffset());
812         textShadow.SetColor(newShadow.GetColor());
813         shadows_[i].shadow = textShadow;
814         shadows_[i].blurRadius->Set(newShadow.GetBlurRadius());
815         shadows_[i].offsetX->Set(newShadow.GetOffset().GetX());
816         shadows_[i].offsetY->Set(newShadow.GetOffset().GetY());
817         shadows_[i].color->Set(LinearColor(newShadow.GetColor()));
818     }
819 }
820 
SetTextDecoration(const TextDecoration & type,bool isReset)821 void TextContentModifier::SetTextDecoration(const TextDecoration& type, bool isReset)
822 {
823     auto oldTextDecoration = textDecoration_.value_or(TextDecoration::NONE);
824     if (oldTextDecoration == type) {
825         return;
826     }
827 
828     textDecorationAnimatable_ = (oldTextDecoration == TextDecoration::NONE && type == TextDecoration::UNDERLINE) ||
829                                 (oldTextDecoration == TextDecoration::UNDERLINE && type == TextDecoration::NONE);
830     if (!isReset) {
831         textDecoration_ = type;
832     } else {
833         textDecoration_ = std::nullopt;
834     }
835     CHECK_NULL_VOID(textDecorationColorAlpha_);
836 
837     if (textDecoration_.has_value() && textDecoration_.value() == TextDecoration::NONE) {
838         textDecorationColorAlpha_->Set(0.0f);
839     } else if (textDecorationColor_.has_value()) {
840         textDecorationColorAlpha_->Set(static_cast<float>(textDecorationColor_.value().GetAlpha()));
841     }
842 }
843 
SetTextDecorationColor(const Color & color,bool isReset)844 void TextContentModifier::SetTextDecorationColor(const Color& color, bool isReset)
845 {
846     if (!isReset) {
847         textDecorationColor_ = color;
848     } else {
849         textDecorationColor_ = std::nullopt;
850     }
851 }
852 
SetBaselineOffset(const Dimension & value,const TextStyle & textStyle,bool isReset)853 void TextContentModifier::SetBaselineOffset(const Dimension& value, const TextStyle& textStyle, bool isReset)
854 {
855     float baselineOffsetValue = 0.0f;
856     if (!isReset) {
857         baselineOffsetValue = value.ConvertToPxDistribute(
858             textStyle.GetMinFontScale(), textStyle.GetMaxFontScale(), textStyle.IsAllowScale());
859         baselineOffset_ = Dimension(baselineOffsetValue);
860     } else {
861         baselineOffset_ = std::nullopt;
862     }
863     CHECK_NULL_VOID(baselineOffsetFloat_);
864     baselineOffsetFloat_->Set(baselineOffsetValue);
865 }
866 
SetLineHeight(const Dimension & value,const TextStyle & textStyle,bool isReset)867 void TextContentModifier::SetLineHeight(const Dimension& value, const TextStyle& textStyle, bool isReset)
868 {
869     float lineHeightValue = 0.0f;
870     if (!isReset) {
871         lineHeightValue = value.ConvertToPxDistribute(
872             textStyle.GetMinFontScale(), textStyle.GetMaxFontScale(), textStyle.IsAllowScale());
873         lineHeight_ = Dimension(lineHeightValue);
874     } else {
875         lineHeight_ = std::nullopt;
876     }
877     CHECK_NULL_VOID(lineHeightFloat_);
878     lineHeightFloat_->Set(lineHeightValue);
879 }
880 
SetContentOffset(OffsetF & value)881 void TextContentModifier::SetContentOffset(OffsetF& value)
882 {
883     CHECK_NULL_VOID(contentOffset_);
884     contentOffset_->Set(value);
885 }
886 
SetContentSize(SizeF & value)887 void TextContentModifier::SetContentSize(SizeF& value)
888 {
889     CHECK_NULL_VOID(contentSize_);
890     contentSize_->Set(value);
891 }
892 
StartTextRace()893 void TextContentModifier::StartTextRace()
894 {
895     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
896         UpdateImageNodeVisible(VisibleType::INVISIBLE);
897     }
898     if (!CheckMarqueeState(MarqueeState::IDLE) && !CheckMarqueeState(MarqueeState::STOPPED)) {
899         return;
900     }
901 
902     textRaceSpaceWidth_ = RACE_SPACE_WIDTH;
903     auto pipeline = PipelineContext::GetCurrentContextSafely();
904     if (pipeline) {
905         textRaceSpaceWidth_ *= pipeline->GetDipScale();
906     }
907 
908     AnimationOption option = AnimationOption();
909     RefPtr<Curve> curve = MakeRefPtr<LinearCurve>();
910     option.SetDuration(GetDuration());
911     option.SetDelay(0);
912     option.SetCurve(curve);
913     option.SetIteration(-1);
914     raceAnimation_ = AnimationUtils::StartAnimation(option, [&]() { racePercentFloat_->Set(RACE_MOVE_PERCENT_MAX); });
915     SetMarqueeState(MarqueeState::RUNNING);
916 }
917 
StopTextRace()918 void TextContentModifier::StopTextRace()
919 {
920     if (!CheckMarqueeState(MarqueeState::RUNNING) && !CheckMarqueeState(MarqueeState::PAUSED)) {
921         return;
922     }
923     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
924         UpdateImageNodeVisible(VisibleType::VISIBLE);
925     }
926     if (raceAnimation_) {
927         AnimationUtils::StopAnimation(raceAnimation_);
928     }
929 
930     SetMarqueeState(MarqueeState::STOPPED);
931     racePercentFloat_->Set(RACE_MOVE_PERCENT_MIN);
932 }
933 
ResumeAnimation()934 void TextContentModifier::ResumeAnimation()
935 {
936     CHECK_NULL_VOID(raceAnimation_);
937     if (!CheckMarqueeState(MarqueeState::PAUSED)) {
938         return;
939     }
940     AnimationUtils::ResumeAnimation(raceAnimation_);
941     SetMarqueeState(MarqueeState::RUNNING);
942 }
943 
PauseAnimation()944 void TextContentModifier::PauseAnimation()
945 {
946     CHECK_NULL_VOID(raceAnimation_);
947     if (!CheckMarqueeState(MarqueeState::RUNNING)) {
948         return;
949     }
950     AnimationUtils::PauseAnimation(raceAnimation_);
951     SetMarqueeState(MarqueeState::PAUSED);
952 }
953 
GetTextRacePercent()954 float TextContentModifier::GetTextRacePercent()
955 {
956     float percent = 0;
957     if (racePercentFloat_) {
958         percent = racePercentFloat_->Get();
959     }
960     return percent;
961 }
962 
GetTextRaceDirection() const963 TextDirection TextContentModifier::GetTextRaceDirection() const
964 {
965     auto textPattern = DynamicCast<TextPattern>(pattern_.Upgrade());
966     CHECK_NULL_RETURN(textPattern, TextDirection::LTR);
967     auto frameNode = textPattern->GetHost();
968     CHECK_NULL_RETURN(frameNode, TextDirection::LTR);
969     auto layoutProperty = frameNode->GetLayoutProperty<TextLayoutProperty>();
970     CHECK_NULL_RETURN(layoutProperty, TextDirection::LTR);
971     return layoutProperty->GetNonAutoLayoutDirection();
972 }
973 
ContentChange()974 void TextContentModifier::ContentChange()
975 {
976     CHECK_NULL_VOID(contentChange_);
977     contentChange_->Set(contentChange_->Get() + 1);
978 }
979 
AddDefaultShadow()980 void TextContentModifier::AddDefaultShadow()
981 {
982     Shadow emptyShadow;
983     auto blurRadius = MakeRefPtr<AnimatablePropertyFloat>(emptyShadow.GetBlurRadius());
984     auto offsetX = MakeRefPtr<AnimatablePropertyFloat>(emptyShadow.GetOffset().GetX());
985     auto offsetY = MakeRefPtr<AnimatablePropertyFloat>(emptyShadow.GetOffset().GetY());
986     auto color = MakeRefPtr<AnimatablePropertyColor>(LinearColor(emptyShadow.GetColor()));
987     Shadow textShadow;
988     textShadow.SetBlurRadius(emptyShadow.GetBlurRadius());
989     textShadow.SetOffset(emptyShadow.GetOffset());
990     textShadow.SetColor(emptyShadow.GetColor());
991     shadows_.emplace_back(ShadowProp {
992         .shadow = textShadow, .blurRadius = blurRadius, .offsetX = offsetX, .offsetY = offsetY, .color = color });
993     AttachProperty(blurRadius);
994     AttachProperty(offsetX);
995     AttachProperty(offsetY);
996     AttachProperty(color);
997 }
998 
SetMarqueeState(MarqueeState state)999 void TextContentModifier::SetMarqueeState(MarqueeState state)
1000 {
1001     auto prevState = marqueeState_;
1002     marqueeState_ = state;
1003     auto pattern = DynamicCast<TextPattern>(pattern_.Upgrade());
1004     CHECK_NULL_VOID(pattern);
1005     auto host = pattern->GetHost();
1006     CHECK_NULL_VOID(host);
1007     TAG_LOGI(AceLogTag::ACE_TEXT, "SetMarqueeState: id %{public}d, from state %{public}d to state %{public}d",
1008         host->GetId(), prevState, state);
1009 }
1010 
GetDuration() const1011 int32_t TextContentModifier::GetDuration() const
1012 {
1013     auto pattern = DynamicCast<TextPattern>(pattern_.Upgrade());
1014     CHECK_NULL_RETURN(pattern, RACE_DURATION);
1015     auto pManager = pattern->GetParagraphManager();
1016     CHECK_NULL_RETURN(pManager, RACE_DURATION);
1017     CHECK_NULL_RETURN(!pManager->GetParagraphs().empty(), RACE_DURATION);
1018     auto paragraph = pManager->GetParagraphs().front().paragraph;
1019     CHECK_NULL_RETURN(paragraph, RACE_DURATION);
1020     auto textRaceWidth = paragraph->GetTextWidth() + textRaceSpaceWidth_;
1021     if (LessOrEqual(DEFAULT_MARQUEE_SCROLL_AMOUNT.ConvertToPx(), 0.0)) {
1022         return RACE_DURATION;
1023     }
1024     return static_cast<int32_t>(
1025         textRaceWidth / DEFAULT_MARQUEE_SCROLL_AMOUNT.ConvertToPx() * DEFAULT_MARQUEE_SCROLL_DELAY);
1026 }
1027 } // namespace OHOS::Ace::NG
1028