• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/common/layout/constants.h"
23 #include "core/components_ng/pattern/text/text_layout_adapter.h"
24 #include "core/components_ng/pattern/text/text_pattern.h"
25 #include "core/components_ng/render/animation_utils.h"
26 #include "core/components_ng/render/drawing.h"
27 #include "core/components_ng/render/drawing_prop_convertor.h"
28 #include "core/components_ng/render/image_painter.h"
29 #include "core/components_v2/inspector/utils.h"
30 #include "core/pipeline_ng/pipeline_context.h"
31 #include "frameworks/core/components_ng/render/adapter/animated_image.h"
32 #include "frameworks/core/components_ng/render/adapter/pixelmap_image.h"
33 
34 namespace OHOS::Ace::NG {
35 namespace {
36 constexpr float RACE_DURATION_RATIO = 85.0f;
37 constexpr float RACE_MIN_GRADIENTPERCENT = 0.5f;
38 constexpr float DEFAULT_FADEOUT_GRADIENTPERCENT = 0.033f;
39 constexpr float RACE_MOVE_PERCENT_MIN = 0.0f;
40 constexpr float RACE_MOVE_PERCENT_MAX = 100.0f;
41 constexpr float RACE_SPACE_WIDTH = 48.0f;
42 constexpr float ROUND_VALUE = 0.5f;
43 constexpr uint32_t POINT_COUNT = 4;
44 constexpr float OBSCURED_ALPHA = 0.2f;
45 const FontWeight FONT_WEIGHT_CONVERT_MAP[] = {
46     FontWeight::W100,
47     FontWeight::W200,
48     FontWeight::W300,
49     FontWeight::W400,
50     FontWeight::W500,
51     FontWeight::W600,
52     FontWeight::W700,
53     FontWeight::W800,
54     FontWeight::W900,
55     FontWeight::W700,       // FontWeight::BOLD
56     FontWeight::W400,       // FontWeight::NORMAL
57     FontWeight::W900,       // FontWeight::BOLDER,
58     FontWeight::W100,       // FontWeight::LIGHTER
59     FontWeight::W500,       // FontWeight::MEDIUM
60     FontWeight::W400,       // FontWeight::REGULAR
61 };
62 
ConvertFontWeight(FontWeight fontWeight)63 inline FontWeight ConvertFontWeight(FontWeight fontWeight)
64 {
65     return FONT_WEIGHT_CONVERT_MAP[static_cast<int>(fontWeight)];
66 }
67 } // namespace
68 
TextContentModifier(const std::optional<TextStyle> & textStyle,const WeakPtr<Pattern> & pattern)69 TextContentModifier::TextContentModifier(const std::optional<TextStyle>& textStyle, const WeakPtr<Pattern>& pattern)
70     : pattern_(pattern)
71 {
72     auto patternUpgrade = pattern_.Upgrade();
73     CHECK_NULL_VOID(patternUpgrade);
74     auto textPattern = DynamicCast<TextPattern>(patternUpgrade);
75     CHECK_NULL_VOID(textPattern);
76     auto host = textPattern->GetHost();
77     CHECK_NULL_VOID(host);
78     auto geometryNode = host->GetGeometryNode();
79     CHECK_NULL_VOID(geometryNode);
80 
81     contentChange_ = MakeRefPtr<PropertyInt>(0);
82     AttachProperty(contentChange_);
83 
84     auto contentRect = geometryNode->GetContentRect();
85     contentOffset_ = MakeRefPtr<PropertyOffsetF>(contentRect.GetOffset());
86     contentSize_ = MakeRefPtr<PropertySizeF>(contentRect.GetSize());
87     AttachProperty(contentOffset_);
88     AttachProperty(contentSize_);
89     dragStatus_ = MakeRefPtr<PropertyBool>(false);
90     AttachProperty(dragStatus_);
91     if (textStyle.has_value()) {
92         SetDefaultAnimatablePropertyValue(textStyle.value(), host);
93     }
94 
95     textRaceSpaceWidth_ = RACE_SPACE_WIDTH;
96     auto pipeline = host->GetContext();
97     if (pipeline) {
98         textRaceSpaceWidth_ *= pipeline->GetDipScale();
99     }
100 
101     racePercentFloat_ = MakeRefPtr<AnimatablePropertyFloat>(0.0f);
102     AttachProperty(racePercentFloat_);
103 
104     if (host->LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
105         clip_ = MakeRefPtr<PropertyBool>(true);
106     } else {
107         clip_ = MakeRefPtr<PropertyBool>(false);
108     }
109     AttachProperty(clip_);
110     fontReady_ = MakeRefPtr<PropertyBool>(false);
111     AttachProperty(fontReady_);
112 
113     auto baselineOffset = textPattern->GetBaselineOffset();
114     paintOffset_ = contentRect.GetOffset() - OffsetF(0.0, std::min(baselineOffset, 0.0f));
115 }
116 
ChangeDragStatus()117 void TextContentModifier::ChangeDragStatus()
118 {
119     CHECK_NULL_VOID(dragStatus_);
120     dragStatus_->Set(!dragStatus_->Get());
121 }
122 
SetDefaultAnimatablePropertyValue(const TextStyle & textStyle,const RefPtr<FrameNode> & frameNode)123 void TextContentModifier::SetDefaultAnimatablePropertyValue(
124     const TextStyle& textStyle, const RefPtr<FrameNode>& frameNode)
125 {
126     SetDefaultFontSize(textStyle);
127     SetDefaultAdaptMinFontSize(textStyle);
128     SetDefaultAdaptMaxFontSize(textStyle);
129     SetDefaultFontWeight(textStyle);
130     SetDefaultTextColor(textStyle);
131     if (frameNode->GetTag() == V2::SYMBOL_ETS_TAG) {
132         SetDefaultSymbolColor(textStyle);
133     }
134     SetDefaultTextShadow(textStyle);
135     SetDefaultTextDecoration(textStyle);
136     SetDefaultBaselineOffset(textStyle);
137     SetDefaultLineHeight(textStyle);
138 }
139 
SetDefaultFontSize(const TextStyle & textStyle)140 void TextContentModifier::SetDefaultFontSize(const TextStyle& textStyle)
141 {
142     float fontSizeValue = textStyle.GetFontSize().ConvertToPxDistribute(
143         textStyle.GetMinFontScale(), textStyle.GetMaxFontScale(), textStyle.IsAllowScale());
144     fontSizeFloat_ = MakeRefPtr<AnimatablePropertyFloat>(fontSizeValue);
145     AttachProperty(fontSizeFloat_);
146 }
147 
SetDefaultAdaptMinFontSize(const TextStyle & textStyle)148 void TextContentModifier::SetDefaultAdaptMinFontSize(const TextStyle& textStyle)
149 {
150     float fontSizeValue = textStyle.GetFontSize().Value();
151     auto pipelineContext = PipelineContext::GetCurrentContextSafelyWithCheck();
152     if (pipelineContext) {
153         fontSizeValue = textStyle.GetAdaptMinFontSize().ConvertToPxDistribute(
154             textStyle.GetMinFontScale(), textStyle.GetMaxFontScale(), textStyle.IsAllowScale());
155     }
156 
157     adaptMinFontSizeFloat_ = MakeRefPtr<AnimatablePropertyFloat>(fontSizeValue);
158     AttachProperty(adaptMinFontSizeFloat_);
159 }
160 
SetDefaultAdaptMaxFontSize(const TextStyle & textStyle)161 void TextContentModifier::SetDefaultAdaptMaxFontSize(const TextStyle& textStyle)
162 {
163     float fontSizeValue = textStyle.GetFontSize().Value();
164     auto pipelineContext = PipelineContext::GetCurrentContextSafelyWithCheck();
165     if (pipelineContext) {
166         fontSizeValue = textStyle.GetAdaptMaxFontSize().ConvertToPxDistribute(
167             textStyle.GetMinFontScale(), textStyle.GetMaxFontScale(), textStyle.IsAllowScale());
168     }
169 
170     adaptMaxFontSizeFloat_ = MakeRefPtr<AnimatablePropertyFloat>(fontSizeValue);
171     AttachProperty(adaptMaxFontSizeFloat_);
172 }
173 
SetDefaultFontWeight(const TextStyle & textStyle)174 void TextContentModifier::SetDefaultFontWeight(const TextStyle& textStyle)
175 {
176     fontWeightFloat_ =
177         MakeRefPtr<AnimatablePropertyFloat>(static_cast<float>(ConvertFontWeight(textStyle.GetFontWeight())));
178     AttachProperty(fontWeightFloat_);
179 }
180 
SetDefaultTextColor(const TextStyle & textStyle)181 void TextContentModifier::SetDefaultTextColor(const TextStyle& textStyle)
182 {
183     animatableTextColor_ = MakeRefPtr<AnimatablePropertyColor>(LinearColor(textStyle.GetTextColor()));
184     AttachProperty(animatableTextColor_);
185 }
186 
SetDefaultSymbolColor(const TextStyle & textStyle)187 void TextContentModifier::SetDefaultSymbolColor(const TextStyle& textStyle)
188 {
189     animatableSymbolColor_ =
190         MakeRefPtr<AnimatablePropertyVectorLinearVector>(Convert2VectorLinearColor(textStyle.GetSymbolColorList()));
191     AttachProperty(animatableSymbolColor_);
192 }
193 
Convert2VectorLinearColor(const std::vector<Color> & colorList)194 LinearVector<LinearColor> TextContentModifier::Convert2VectorLinearColor(const std::vector<Color>& colorList)
195 {
196     LinearVector<LinearColor> colors;
197     for (auto color : colorList) {
198         colors.emplace_back(LinearColor(color));
199     }
200     return colors;
201 }
202 
SetDefaultTextShadow(const TextStyle & textStyle)203 void TextContentModifier::SetDefaultTextShadow(const TextStyle& textStyle)
204 {
205     auto&& textShadows = textStyle.GetTextShadows();
206     if (textShadows.empty()) {
207         AddDefaultShadow();
208         return;
209     }
210     shadows_.clear();
211     shadows_.reserve(textShadows.size());
212     for (auto&& textShadow : textShadows) {
213         AddShadow(textShadow);
214     }
215 }
216 
AddShadow(const Shadow & shadow)217 void TextContentModifier::AddShadow(const Shadow& shadow)
218 {
219     auto shadowBlurRadiusFloat = MakeRefPtr<AnimatablePropertyFloat>(shadow.GetBlurRadius());
220     auto shadowOffsetXFloat = MakeRefPtr<AnimatablePropertyFloat>(shadow.GetOffset().GetX());
221     auto shadowOffsetYFloat = MakeRefPtr<AnimatablePropertyFloat>(shadow.GetOffset().GetY());
222     auto shadowColor = MakeRefPtr<AnimatablePropertyColor>(LinearColor(shadow.GetColor()));
223     Shadow textShadow;
224     textShadow.SetBlurRadius(shadow.GetBlurRadius());
225     textShadow.SetOffset(shadow.GetOffset());
226     textShadow.SetColor(shadow.GetColor());
227     shadows_.emplace_back(ShadowProp { .shadow = textShadow,
228         .blurRadius = shadowBlurRadiusFloat,
229         .offsetX = shadowOffsetXFloat,
230         .offsetY = shadowOffsetYFloat,
231         .color = shadowColor });
232     AttachProperty(shadowBlurRadiusFloat);
233     AttachProperty(shadowOffsetXFloat);
234     AttachProperty(shadowOffsetYFloat);
235     AttachProperty(shadowColor);
236 }
237 
SetDefaultTextDecoration(const TextStyle & textStyle)238 void TextContentModifier::SetDefaultTextDecoration(const TextStyle& textStyle)
239 {
240     textDecoration_ = textStyle.GetTextDecoration();
241     textDecorationColor_ = textStyle.GetTextDecorationColor();
242     textDecorationColorAlpha_ = MakeRefPtr<AnimatablePropertyFloat>(
243         textDecoration_ == TextDecoration::NONE ? 0.0f : textDecorationColor_->GetAlpha());
244     AttachProperty(textDecorationColorAlpha_);
245 }
SetDefaultBaselineOffset(const TextStyle & textStyle)246 void TextContentModifier::SetDefaultBaselineOffset(const TextStyle& textStyle)
247 {
248     float baselineOffset = textStyle.GetBaselineOffset().Value();
249     auto pipelineContext = PipelineContext::GetCurrentContextSafelyWithCheck();
250     if (pipelineContext) {
251         baselineOffset = textStyle.GetBaselineOffset().ConvertToPxDistribute(
252             textStyle.GetMinFontScale(), textStyle.GetMaxFontScale(), textStyle.IsAllowScale());
253     }
254 
255     baselineOffsetFloat_ = MakeRefPtr<AnimatablePropertyFloat>(baselineOffset);
256     AttachProperty(baselineOffsetFloat_);
257 }
258 
SetDefaultLineHeight(const TextStyle & textStyle)259 void TextContentModifier::SetDefaultLineHeight(const TextStyle& textStyle)
260 {
261     float lineHeight = textStyle.GetLineHeight().Value();
262     auto pipelineContext = PipelineContext::GetCurrentContextSafelyWithCheck();
263     if (pipelineContext) {
264         lineHeight = textStyle.GetLineHeight().ConvertToPxDistribute(
265             textStyle.GetMinFontScale(), textStyle.GetMaxFontScale(), textStyle.IsAllowScale());
266     }
267 
268     lineHeightFloat_ = MakeRefPtr<AnimatablePropertyFloat>(lineHeight);
269     AttachProperty(lineHeightFloat_);
270 }
271 
SetClip(bool clip)272 void TextContentModifier::SetClip(bool clip)
273 {
274     if (clip_) {
275         clip_->Set(clip);
276     }
277 }
278 
SetFontReady(bool value)279 void TextContentModifier::SetFontReady(bool value)
280 {
281     if (fontReady_) {
282         fontReady_->Set(value);
283     }
284 }
285 
UpdateImageNodeVisible(const VisibleType visible)286 void TextContentModifier::UpdateImageNodeVisible(const VisibleType visible)
287 {
288     for (const auto& imageWeak : imageNodeList_) {
289         auto imageNode = imageWeak.Upgrade();
290         if (!imageNode) {
291             continue;
292         }
293         auto layoutProperty = imageNode->GetLayoutProperty();
294         if (!layoutProperty) {
295             continue;
296         }
297         layoutProperty->UpdateVisibility(visible, true);
298     }
299 }
300 
PaintImage(RSCanvas & canvas,float x,float y)301 void TextContentModifier::PaintImage(RSCanvas& canvas, float x, float y)
302 {
303     if (!AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
304         return;
305     }
306     auto pattern = DynamicCast<TextPattern>(pattern_.Upgrade());
307     CHECK_NULL_VOID(pattern);
308     size_t index = 0;
309     auto rectsForPlaceholders = pattern->GetRectsForPlaceholders();
310     auto placeHolderIndexVector = pattern->GetPlaceHolderIndex();
311     auto placeholdersSize = rectsForPlaceholders.size();
312     auto placeHolderIndexSize = static_cast<int32_t>(placeHolderIndexVector.size());
313     for (const auto& imageWeak : imageNodeList_) {
314         auto imageChild = imageWeak.Upgrade();
315         if (!imageChild) {
316             continue;
317         }
318         if (index >= placeholdersSize) {
319             return;
320         }
321         auto tmp = static_cast<int32_t>(placeHolderIndexVector.at(index));
322         if (tmp >= placeHolderIndexSize || tmp < 0) {
323             return;
324         }
325         auto rect = rectsForPlaceholders.at(tmp);
326         if (!DrawImage(imageChild, canvas, x, y, rect)) {
327             continue;
328         }
329         ++index;
330     }
331 }
332 
DrawImage(const RefPtr<FrameNode> & imageNode,RSCanvas & canvas,float x,float y,const RectF & rect)333 bool TextContentModifier::DrawImage(const RefPtr<FrameNode>& imageNode, RSCanvas& canvas, float x, float y,
334     const RectF& rect)
335 {
336     CHECK_NULL_RETURN(imageNode, false);
337     auto imagePattern = DynamicCast<ImagePattern>(imageNode->GetPattern());
338     if (!imagePattern) {
339         return false;
340     }
341     auto layoutProperty = imageNode->GetLayoutProperty<ImageLayoutProperty>();
342     if (!layoutProperty) {
343         return false;
344     }
345     const auto& marginProperty = layoutProperty->GetMarginProperty();
346     float marginTop = 0.0f;
347     float marginLeft = 0.0f;
348     if (marginProperty) {
349         marginLeft = marginProperty->left.has_value() ? marginProperty->left->GetDimension().ConvertToPx() : 0.0f;
350         marginTop = marginProperty->top.has_value() ? marginProperty->top->GetDimension().ConvertToPx() : 0.0f;
351     }
352     auto canvasImage = imagePattern->GetCanvasImage();
353     if (!canvasImage) {
354         canvasImage = imagePattern->GetAltCanvasImage();
355     }
356     if (AceType::InstanceOf<AnimatedImage>(canvasImage)) {
357         auto animatedImage = DynamicCast<AnimatedImage>(canvasImage);
358         if (!animatedImage->GetIsAnimating()) {
359             animatedImage->ControlAnimation(true);
360         }
361     }
362     auto geometryNode = imageNode->GetGeometryNode();
363     if (!canvasImage || !geometryNode) {
364         return false;
365     }
366     RectF imageRect(rect.Left() + x + marginLeft, rect.Top() + y + marginTop,
367         geometryNode->GetFrameSize().Width(), geometryNode->GetFrameSize().Height());
368     const auto config = canvasImage->GetPaintConfig();
369     SizeF imageSize(canvasImage->GetWidth(), canvasImage->GetHeight());
370     SizeF contentSize(geometryNode->GetFrameSize().Width(), geometryNode->GetFrameSize().Height());
371     RectF srcRect;
372     RectF dstRect;
373     ImagePainter::ApplyImageFit(config.imageFit_, imageSize, contentSize, srcRect, dstRect);
374     canvasImage->DrawRect(canvas, ToRSRect(srcRect), ToRSRect(imageRect));
375     return true;
376 }
377 
PaintCustomSpan(DrawingContext & drawingContext)378 void TextContentModifier::PaintCustomSpan(DrawingContext& drawingContext)
379 {
380     auto pattern = DynamicCast<TextPattern>(pattern_.Upgrade());
381     CHECK_NULL_VOID(pattern);
382     auto pManager = pattern->GetParagraphManager();
383     CHECK_NULL_VOID(pManager);
384     auto rectsForPlaceholders = pattern->GetRectsForPlaceholders();
385     auto customSpanPlaceholderInfo = pattern->GetCustomSpanPlaceholderInfo();
386     auto x = paintOffset_.GetX();
387     auto y = paintOffset_.GetY();
388     auto rectsForPlaceholderSize = rectsForPlaceholders.size();
389     for (const auto& customSpanPlaceholder : customSpanPlaceholderInfo) {
390         if (!customSpanPlaceholder.onDraw) {
391             continue;
392         }
393         auto index = customSpanPlaceholder.customSpanIndex;
394         if (index >= static_cast<int32_t>(rectsForPlaceholderSize) || index < 0) {
395             return;
396         }
397         auto rect = rectsForPlaceholders.at(index);
398         auto lineMetrics = pManager->GetLineMetricsByRectF(rect, customSpanPlaceholder.paragraphIndex);
399         CustomSpanOptions customSpanOptions;
400         customSpanOptions.x = static_cast<float>(rect.Left()) + x;
401         customSpanOptions.lineTop = lineMetrics.y + y;
402         customSpanOptions.lineBottom = lineMetrics.y + lineMetrics.height + y;
403         customSpanOptions.baseline = lineMetrics.y + lineMetrics.ascender + y;
404         customSpanPlaceholder.onDraw(drawingContext, customSpanOptions);
405     }
406 }
407 
onDraw(DrawingContext & drawingContext)408 void TextContentModifier::onDraw(DrawingContext& drawingContext)
409 {
410     auto info = GetFadeoutInfo(drawingContext);
411     if (!info.IsFadeout()) {
412         DrawContent(drawingContext, info);
413     } else {
414         DrawFadeout(drawingContext, info);
415     }
416 }
417 
DrawContent(DrawingContext & drawingContext,const FadeoutInfo & fadeoutInfo)418 void TextContentModifier::DrawContent(DrawingContext& drawingContext, const FadeoutInfo& fadeoutInfo)
419 {
420     auto textPattern = DynamicCast<TextPattern>(pattern_.Upgrade());
421     CHECK_NULL_VOID(textPattern);
422     auto pManager = textPattern->GetParagraphManager();
423     CHECK_NULL_VOID(pManager);
424     auto host = textPattern->GetHost();
425     CHECK_NULL_VOID(host);
426     if (pManager->GetParagraphs().empty()) {
427         textPattern->DumpRecord("onDraw GetParagraphs empty:" + std::to_string(host->GetId()));
428         return;
429     }
430     auto geometryNode = host->GetGeometryNode();
431     CHECK_NULL_VOID(geometryNode);
432     auto contentRect = geometryNode->GetContentRect();
433     ACE_SCOPED_TRACE("[Text][id:%d] paint[offset:%f,%f][contentRect:%s]", host->GetId(), paintOffset_.GetX(),
434         paintOffset_.GetY(), contentRect.ToString().c_str());
435 
436     PropertyChangeFlag flag = 0;
437     if (NeedMeasureUpdate(flag)) {
438         host->MarkDirtyNode(flag);
439         auto layoutProperty = host->GetLayoutProperty<TextLayoutProperty>();
440         CHECK_NULL_VOID(layoutProperty);
441         layoutProperty->OnPropertyChangeMeasure();
442     }
443     if (!ifPaintObscuration_) {
444         auto& canvas = drawingContext.canvas;
445         CHECK_NULL_VOID(contentSize_);
446         CHECK_NULL_VOID(contentOffset_);
447         auto contentSize = contentSize_->Get();
448         auto contentOffset = contentOffset_->Get();
449         canvas.Save();
450         if (clip_ && clip_->Get() &&
451             (!fontSize_.has_value() || !fontSizeFloat_ ||
452                 NearEqual(fontSize_.value().Value(), fontSizeFloat_->Get()))) {
453             RSRect clipInnerRect = RSRect(contentOffset.GetX(), contentOffset.GetY(),
454                 contentSize.Width() + contentOffset.GetX(), contentSize.Height() + contentOffset.GetY());
455             canvas.ClipRect(clipInnerRect, RSClipOp::INTERSECT);
456         }
457         if (!marqueeSet_) {
458             auto logTag = "DrawText IncludeIndent:" + std::to_string(pManager->GetTextWidthIncludeIndent());
459             textPattern->LogForFormRender(logTag);
460             auto paintOffsetY = paintOffset_.GetY();
461             auto paragraphs = pManager->GetParagraphs();
462             for (auto&& info : paragraphs) {
463                 auto paragraph = info.paragraph;
464                 CHECK_NULL_VOID(paragraph);
465                 ChangeParagraphColor(paragraph);
466                 paragraph->Paint(canvas, paintOffset_.GetX(), paintOffsetY);
467                 paintOffsetY += paragraph->GetHeight();
468             }
469         } else {
470             // Racing
471             DrawTextRacing(drawingContext, fadeoutInfo, pManager);
472         }
473         canvas.Restore();
474     } else {
475         DrawObscuration(drawingContext);
476     }
477     PaintCustomSpan(drawingContext);
478 }
479 
DrawText(RSCanvas & canvas,RefPtr<ParagraphManager> pManager)480 void TextContentModifier::DrawText(RSCanvas& canvas, RefPtr<ParagraphManager> pManager)
481 {
482     auto paintOffsetY = paintOffset_.GetY();
483     auto paragraphs = pManager->GetParagraphs();
484     for (auto&& info : paragraphs) {
485         auto paragraph = info.paragraph;
486         CHECK_NULL_VOID(paragraph);
487         ChangeParagraphColor(paragraph);
488         paragraph->Paint(canvas, paintOffset_.GetX(), paintOffsetY);
489         paintOffsetY += paragraph->GetHeight();
490     }
491 }
492 
DrawTextRacing(DrawingContext & drawingContext,const FadeoutInfo & info,RefPtr<ParagraphManager> pManager)493 void TextContentModifier::DrawTextRacing(DrawingContext& drawingContext, const FadeoutInfo& info,
494     RefPtr<ParagraphManager> pManager)
495 {
496     CHECK_NULL_VOID(pManager);
497     auto paragraph = pManager->GetParagraphs().front().paragraph;
498     CHECK_NULL_VOID(paragraph);
499     ChangeParagraphColor(paragraph);
500     RSCanvas& canvas = drawingContext.canvas;
501     if (info.paragraph1EndPosition > 0) {
502         paragraph->Paint(canvas, info.paragraph1StartPosition, paintOffset_.GetY());
503         PaintImage(canvas, info.paragraph1StartPosition, paintOffset_.GetY());
504     }
505     if (info.paragraph2StartPosition < drawingContext.width) {
506         paragraph->Paint(canvas, info.paragraph2StartPosition, paintOffset_.GetY());
507         PaintImage(canvas, info.paragraph2StartPosition, paintOffset_.GetY());
508     }
509 }
510 
ChangeParagraphColor(const RefPtr<Paragraph> & paragraph)511 void TextContentModifier::ChangeParagraphColor(const RefPtr<Paragraph>& paragraph)
512 {
513     CHECK_NULL_VOID(paragraph);
514     if (onlyTextColorAnimation_ && animatableTextColor_) {
515         auto length = paragraph->GetParagraphText().length();
516         paragraph->UpdateColor(0, length, Color(animatableTextColor_->Get().GetValue()));
517     }
518 }
519 
DrawObscuration(DrawingContext & drawingContext)520 void TextContentModifier::DrawObscuration(DrawingContext& drawingContext)
521 {
522     RSCanvas& canvas = drawingContext.canvas;
523     RSBrush brush;
524     std::vector<RSPoint> radiusXY(POINT_COUNT);
525     Dimension borderRadius = Dimension(2.0, DimensionUnit::VP);
526     for (auto& radius : radiusXY) {
527         radius.SetX(static_cast<float>(borderRadius.ConvertToPx()));
528         radius.SetY(static_cast<float>(borderRadius.ConvertToPx()));
529     }
530     CHECK_NULL_VOID(animatableTextColor_);
531     Color fillColor = Color(animatableTextColor_->Get().GetValue());
532     RSColor rrSColor(fillColor.GetRed(), fillColor.GetGreen(), fillColor.GetBlue(),
533         (uint32_t)(fillColor.GetAlpha() * OBSCURED_ALPHA));
534     brush.SetColor(rrSColor);
535     brush.SetAntiAlias(true);
536     canvas.AttachBrush(brush);
537     CHECK_NULL_VOID(fontSizeFloat_);
538     float fontSize = fontSizeFloat_->Get();
539     std::vector<float> textLineWidth;
540     float currentLineWidth = 0.0f;
541     int32_t maxLineCount = 0;
542     CHECK_NULL_VOID(contentSize_);
543     CHECK_NULL_VOID(contentOffset_);
544     for (auto i = 0U; i < drawObscuredRects_.size(); i++) {
545         if (!NearEqual(drawObscuredRects_[i].Width(), 0.0f) && !NearEqual(drawObscuredRects_[i].Height(), 0.0f)) {
546             currentLineWidth += drawObscuredRects_[i].Width();
547             if (i == (!drawObscuredRects_.empty() ? drawObscuredRects_.size() - 1 : 0)) {
548                 textLineWidth.push_back(currentLineWidth);
549                 maxLineCount += LessOrEqual(drawObscuredRects_[i].Bottom(), contentSize_->Get().Height()) ? 1 : 0;
550             } else if (!NearEqual(drawObscuredRects_[i].Bottom(), drawObscuredRects_[i + 1].Bottom())) {
551                 textLineWidth.push_back(currentLineWidth);
552                 maxLineCount += LessOrEqual(drawObscuredRects_[i].Bottom(), contentSize_->Get().Height()) ? 1 : 0;
553                 currentLineWidth = 0;
554             } else {
555                 /** nothing to do **/
556             }
557         }
558     }
559     CHECK_NULL_VOID(baselineOffsetFloat_);
560     auto baselineOffset = baselineOffsetFloat_->Get();
561     int32_t obscuredLineCount = std::min(maxLineCount, static_cast<int32_t>(textLineWidth.size()));
562     float offsetY = (contentSize_->Get().Height() - std::fabs(baselineOffset) - (obscuredLineCount * fontSize)) /
563                     (obscuredLineCount + 1);
564     for (auto i = 0; i < obscuredLineCount; i++) {
565         RSRoundRect rSRoundRect(
566             RSRect(contentOffset_->Get().GetX(),
567                 contentOffset_->Get().GetY() - std::min(baselineOffset, 0.0f) +
568                     std::max(offsetY + ((offsetY + fontSize) * i), 0.0f),
569                 contentOffset_->Get().GetX() + std::min(textLineWidth[i], contentSize_->Get().Width()),
570                 contentOffset_->Get().GetY() - std::min(baselineOffset, 0.0f) +
571                     std::min(offsetY + ((offsetY + fontSize) * i) + fontSize, contentSize_->Get().Height())),
572             radiusXY);
573         canvas.DrawRoundRect(rSRoundRect);
574     }
575     canvas.DetachBrush();
576 }
577 
ModifyFontSizeInTextStyle(TextStyle & textStyle)578 void TextContentModifier::ModifyFontSizeInTextStyle(TextStyle& textStyle)
579 {
580     if (fontSize_.has_value() && fontSizeFloat_) {
581         lastFontSize_ = fontSizeFloat_->Get();
582         textStyle.SetFontSize(Dimension(fontSizeFloat_->Get(), DimensionUnit::PX));
583     }
584 }
585 
ModifyAdaptMinFontSizeInTextStyle(TextStyle & textStyle)586 void TextContentModifier::ModifyAdaptMinFontSizeInTextStyle(TextStyle& textStyle)
587 {
588     if (adaptMinFontSize_.has_value() && adaptMinFontSizeFloat_) {
589         lastMinFontSize_ = adaptMinFontSizeFloat_->Get();
590         textStyle.SetAdaptMinFontSize(Dimension(adaptMinFontSizeFloat_->Get(), DimensionUnit::PX));
591     }
592 }
593 
ModifyAdaptMaxFontSizeInTextStyle(TextStyle & textStyle)594 void TextContentModifier::ModifyAdaptMaxFontSizeInTextStyle(TextStyle& textStyle)
595 {
596     if (adaptMaxFontSize_.has_value() && adaptMaxFontSizeFloat_) {
597         lastMaxFontSize_ = adaptMaxFontSizeFloat_->Get();
598         textStyle.SetAdaptMaxFontSize(Dimension(adaptMaxFontSizeFloat_->Get(), DimensionUnit::PX));
599     }
600 }
601 
ModifyFontWeightInTextStyle(TextStyle & textStyle)602 void TextContentModifier::ModifyFontWeightInTextStyle(TextStyle& textStyle)
603 {
604     if (fontWeight_.has_value() && fontWeightFloat_) {
605         lastFontWeight_ = fontWeightFloat_->Get();
606         textStyle.SetFontWeight(static_cast<FontWeight>(std::floor(fontWeightFloat_->Get() + ROUND_VALUE)));
607     }
608 }
609 
ModifyTextColorInTextStyle(TextStyle & textStyle)610 void TextContentModifier::ModifyTextColorInTextStyle(TextStyle& textStyle)
611 {
612     if (textColor_.has_value() && animatableTextColor_) {
613         lastTextColor_.SetValue(animatableTextColor_->Get().GetValue());
614         textStyle.SetTextColor(Color(animatableTextColor_->Get().GetValue()));
615     }
616 }
617 
ModifySymbolColorInTextStyle(TextStyle & textStyle)618 void TextContentModifier::ModifySymbolColorInTextStyle(TextStyle& textStyle)
619 {
620     if (symbolColors_.has_value() && animatableSymbolColor_) {
621         lastSymbolColors_= animatableSymbolColor_->Get();
622         textStyle.SetSymbolColorList(Convert2VectorColor(animatableSymbolColor_->Get()));
623     }
624 }
625 
Convert2VectorColor(const LinearVector<LinearColor> & colorList)626 std::vector<Color> TextContentModifier::Convert2VectorColor(const LinearVector<LinearColor>& colorList)
627 {
628     std::vector<Color> colors;
629     for (auto color : colorList) {
630         colors.emplace_back(Color(color.GetValue()));
631     }
632     return colors;
633 }
634 
ModifyTextShadowsInTextStyle(TextStyle & textStyle)635 void TextContentModifier::ModifyTextShadowsInTextStyle(TextStyle& textStyle)
636 {
637     std::vector<Shadow> shadows;
638     shadows.reserve(shadows_.size());
639     for (auto&& shadow : shadows_) {
640         auto blurRadius = shadow.blurRadius->Get();
641         auto offsetX = shadow.offsetX->Get();
642         auto offsetY = shadow.offsetY->Get();
643         auto color = shadow.color->Get();
644         auto shadowValue = Shadow(blurRadius, 0, Offset(offsetX, offsetY), Color(color.GetValue()));
645         shadow.lastShadow = shadowValue;
646         shadows.emplace_back(shadowValue);
647     }
648     textStyle.SetTextShadows(shadows);
649 }
650 
ModifyDecorationInTextStyle(TextStyle & textStyle)651 void TextContentModifier::ModifyDecorationInTextStyle(TextStyle& textStyle)
652 {
653     if (textDecoration_.has_value() && textDecorationColor_.has_value() && textDecorationColorAlpha_) {
654         if (textDecorationAnimatable_) {
655             uint8_t alpha = static_cast<uint8_t>(std::floor(textDecorationColorAlpha_->Get() + ROUND_VALUE));
656             if (alpha == 0) {
657                 textStyle.SetTextDecoration(TextDecoration::NONE);
658                 textStyle.SetTextDecorationColor(textDecorationColor_.value());
659             } else {
660                 textStyle.SetTextDecoration(TextDecoration::UNDERLINE);
661                 textStyle.SetTextDecorationColor(Color(textDecorationColor_.value()).ChangeAlpha(alpha));
662             }
663             lastTextDecorationColorAlpha_ = textDecorationColorAlpha_->Get();
664         } else {
665             textStyle.SetTextDecoration(textDecoration_.value());
666             textStyle.SetTextDecorationColor(textDecorationColor_.value());
667         }
668     }
669 }
670 
ModifyBaselineOffsetInTextStyle(TextStyle & textStyle)671 void TextContentModifier::ModifyBaselineOffsetInTextStyle(TextStyle& textStyle)
672 {
673     if (baselineOffset_.has_value() && baselineOffsetFloat_) {
674         lastBaselineOffsetFloat_ = baselineOffsetFloat_->Get();
675         textStyle.SetBaselineOffset(Dimension(baselineOffsetFloat_->Get(), DimensionUnit::PX));
676     }
677 }
678 
ModifyLineHeightInTextStyle(TextStyle & textStyle)679 void TextContentModifier::ModifyLineHeightInTextStyle(TextStyle& textStyle)
680 {
681     if (lineHeight_.has_value() && lineHeightFloat_) {
682         lastLineHeight_ = lineHeightFloat_->Get();
683         textStyle.SetLineHeight(Dimension(lineHeightFloat_->Get(), DimensionUnit::PX));
684     }
685 }
686 
ModifyTextStyle(TextStyle & textStyle)687 void TextContentModifier::ModifyTextStyle(TextStyle& textStyle)
688 {
689     ModifyFontSizeInTextStyle(textStyle);
690     ModifyAdaptMinFontSizeInTextStyle(textStyle);
691     ModifyAdaptMaxFontSizeInTextStyle(textStyle);
692     ModifyFontWeightInTextStyle(textStyle);
693     ModifyTextColorInTextStyle(textStyle);
694     ModifySymbolColorInTextStyle(textStyle);
695     ModifyTextShadowsInTextStyle(textStyle);
696     ModifyDecorationInTextStyle(textStyle);
697     ModifyBaselineOffsetInTextStyle(textStyle);
698     ModifyLineHeightInTextStyle(textStyle);
699 }
700 
CheckNeedMeasure(float finalValue,float lastValue,float currentValue)701 bool TextContentModifier::CheckNeedMeasure(float finalValue, float lastValue, float currentValue)
702 {
703     return !NearEqual(finalValue, currentValue) || !NearEqual(lastValue, currentValue);
704 }
705 
UpdateFontSizeMeasureFlag(PropertyChangeFlag & flag)706 void TextContentModifier::UpdateFontSizeMeasureFlag(PropertyChangeFlag& flag)
707 {
708     if (fontSize_.has_value() && fontSizeFloat_ &&
709         CheckNeedMeasure(fontSize_.value().Value(), lastFontSize_, fontSizeFloat_->Get())) {
710         flag |= PROPERTY_UPDATE_MEASURE;
711         lastFontSize_ = fontSizeFloat_->Get();
712     }
713 }
714 
UpdateAdaptMinFontSizeMeasureFlag(PropertyChangeFlag & flag)715 void TextContentModifier::UpdateAdaptMinFontSizeMeasureFlag(PropertyChangeFlag& flag)
716 {
717     if (adaptMinFontSize_.has_value() && adaptMinFontSizeFloat_ &&
718         CheckNeedMeasure(adaptMinFontSize_.value().Value(), lastMinFontSize_, adaptMinFontSizeFloat_->Get())) {
719         flag |= PROPERTY_UPDATE_MEASURE;
720         lastMinFontSize_ = adaptMinFontSizeFloat_->Get();
721     }
722 }
723 
UpdateAdaptMaxFontSizeMeasureFlag(PropertyChangeFlag & flag)724 void TextContentModifier::UpdateAdaptMaxFontSizeMeasureFlag(PropertyChangeFlag& flag)
725 {
726     if (adaptMaxFontSize_.has_value() && adaptMaxFontSizeFloat_ &&
727         CheckNeedMeasure(adaptMaxFontSize_.value().Value(), lastMaxFontSize_, adaptMaxFontSizeFloat_->Get())) {
728         flag |= PROPERTY_UPDATE_MEASURE;
729         lastMaxFontSize_ = adaptMaxFontSizeFloat_->Get();
730     }
731 }
732 
UpdateFontWeightMeasureFlag(PropertyChangeFlag & flag)733 void TextContentModifier::UpdateFontWeightMeasureFlag(PropertyChangeFlag& flag)
734 {
735     if (fontWeight_.has_value() && fontWeightFloat_ &&
736         CheckNeedMeasure(
737             static_cast<float>(static_cast<int>(fontWeight_.value())), lastFontWeight_, fontWeightFloat_->Get())) {
738         flag |= PROPERTY_UPDATE_MEASURE;
739         lastFontWeight_ = fontWeightFloat_->Get();
740     }
741 }
742 
UpdateTextColorMeasureFlag(PropertyChangeFlag & flag)743 void TextContentModifier::UpdateTextColorMeasureFlag(PropertyChangeFlag& flag)
744 {
745     if (textColor_.has_value() && animatableTextColor_ &&
746         (textColor_->GetValue() != animatableTextColor_->Get().GetValue() ||
747             lastTextColor_.GetValue() != animatableTextColor_->Get().GetValue())) {
748         flag |= PROPERTY_UPDATE_MEASURE_SELF;
749         lastTextColor_.SetValue(animatableTextColor_->Get().GetValue());
750     }
751 }
752 
UpdateSymbolColorMeasureFlag(PropertyChangeFlag & flag)753 void TextContentModifier::UpdateSymbolColorMeasureFlag(PropertyChangeFlag& flag)
754 {
755     if (!symbolColors_.has_value()) {
756         return;
757     }
758     auto pattern = DynamicCast<TextPattern>(pattern_.Upgrade());
759     auto host = pattern->GetHost();
760     CHECK_NULL_VOID(host);
761     auto layoutProperty = host->GetLayoutProperty<TextLayoutProperty>();
762     CHECK_NULL_VOID(layoutProperty);
763     auto symbolColors = layoutProperty->GetSymbolColorList();
764     CHECK_NULL_VOID(symbolColors);
765     if (!symbolColors.has_value()) {
766         return;
767     }
768     symbolColors_ = Convert2VectorLinearColor(symbolColors.value());
769     if (symbolColors_.has_value() && animatableSymbolColor_ &&
770         (symbolColors_ != animatableSymbolColor_->Get() || lastSymbolColors_ != animatableSymbolColor_->Get())) {
771         flag |= PROPERTY_UPDATE_MEASURE_SELF;
772         lastSymbolColors_ = animatableSymbolColor_->Get();
773     }
774 }
775 
UpdateTextShadowMeasureFlag(PropertyChangeFlag & flag)776 void TextContentModifier::UpdateTextShadowMeasureFlag(PropertyChangeFlag& flag)
777 {
778     for (auto&& shadow : shadows_) {
779         auto blurRadius = shadow.blurRadius->Get();
780         auto offsetX = shadow.offsetX->Get();
781         auto offsetY = shadow.offsetY->Get();
782         auto color = shadow.color->Get();
783         auto compareShadow = Shadow(blurRadius, 0, Offset(offsetX, offsetY), Color(color.GetValue()));
784         if (shadow.shadow != compareShadow || shadow.lastShadow != compareShadow) {
785             flag |= PROPERTY_UPDATE_MEASURE;
786             shadow.lastShadow = compareShadow;
787             return;
788         }
789     }
790 }
791 
UpdateTextDecorationMeasureFlag(PropertyChangeFlag & flag)792 void TextContentModifier::UpdateTextDecorationMeasureFlag(PropertyChangeFlag& flag)
793 {
794     if (textDecoration_.has_value() && textDecorationColor_.has_value() && textDecorationColorAlpha_) {
795         uint8_t alpha = static_cast<uint8_t>(std::floor(textDecorationColorAlpha_->Get() + ROUND_VALUE));
796         if (textDecoration_.value() == TextDecoration::UNDERLINE &&
797             (alpha != textDecorationColor_.value().GetAlpha() ||
798                 !NearEqual(textDecorationColorAlpha_->Get(), lastTextDecorationColorAlpha_))) {
799             flag |= PROPERTY_UPDATE_MEASURE;
800         } else if (textDecoration_.value() == TextDecoration::NONE &&
801                    (alpha != 0.0 || !NearZero(lastTextDecorationColorAlpha_))) {
802             flag |= PROPERTY_UPDATE_MEASURE;
803         }
804         lastTextDecorationColorAlpha_ = textDecorationColorAlpha_->Get();
805     }
806 }
807 
UpdateBaselineOffsetMeasureFlag(PropertyChangeFlag & flag)808 void TextContentModifier::UpdateBaselineOffsetMeasureFlag(PropertyChangeFlag& flag)
809 {
810     if (baselineOffset_.has_value() && baselineOffsetFloat_ &&
811         CheckNeedMeasure(baselineOffset_.value().Value(), lastBaselineOffsetFloat_, baselineOffsetFloat_->Get())) {
812         flag |= PROPERTY_UPDATE_MEASURE;
813         lastBaselineOffsetFloat_ = baselineOffsetFloat_->Get();
814     }
815 }
816 
UpdateLineHeightMeasureFlag(PropertyChangeFlag & flag)817 void TextContentModifier::UpdateLineHeightMeasureFlag(PropertyChangeFlag& flag)
818 {
819     if (lineHeight_.has_value() && lineHeightFloat_ &&
820         CheckNeedMeasure(lineHeight_.value().Value(), lastLineHeight_, lineHeightFloat_->Get())) {
821         flag |= PROPERTY_UPDATE_MEASURE;
822         lastLineHeight_ = lineHeightFloat_->Get();
823     }
824 }
825 
AnimationMeasureUpdate(const RefPtr<FrameNode> & host)826 void TextContentModifier::AnimationMeasureUpdate(const RefPtr<FrameNode>& host)
827 {
828     PropertyChangeFlag flag = 0;
829     if (NeedMeasureUpdate(flag)) {
830         host->MarkDirtyNode(flag);
831         auto layoutProperty = host->GetLayoutProperty<TextLayoutProperty>();
832         CHECK_NULL_VOID(layoutProperty);
833         layoutProperty->OnPropertyChangeMeasure();
834     }
835 }
836 
NeedMeasureUpdate(PropertyChangeFlag & flag)837 bool TextContentModifier::NeedMeasureUpdate(PropertyChangeFlag& flag)
838 {
839     flag = 0;
840     UpdateFontSizeMeasureFlag(flag);
841     UpdateAdaptMinFontSizeMeasureFlag(flag);
842     UpdateAdaptMaxFontSizeMeasureFlag(flag);
843     UpdateFontWeightMeasureFlag(flag);
844     UpdateTextShadowMeasureFlag(flag);
845     UpdateTextDecorationMeasureFlag(flag);
846     UpdateBaselineOffsetMeasureFlag(flag);
847     UpdateLineHeightMeasureFlag(flag);
848     flag &= (PROPERTY_UPDATE_MEASURE | PROPERTY_UPDATE_MEASURE_SELF | PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
849     if (flag) {
850         onlyTextColorAnimation_ = false;
851     }
852     if (!onlyTextColorAnimation_) {
853         UpdateTextColorMeasureFlag(flag);
854         flag &= (PROPERTY_UPDATE_MEASURE | PROPERTY_UPDATE_MEASURE_SELF | PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
855     }
856     UpdateSymbolColorMeasureFlag(flag);
857     return flag;
858 }
859 
SetFontSize(const Dimension & value,const TextStyle & textStyle,bool isReset)860 void TextContentModifier::SetFontSize(const Dimension& value, const TextStyle& textStyle, bool isReset)
861 {
862     auto fontSizeValue =
863         value.ConvertToPxDistribute(textStyle.GetMinFontScale(), textStyle.GetMaxFontScale(), textStyle.IsAllowScale());
864     if (!isReset) {
865         fontSize_ = Dimension(fontSizeValue);
866     } else {
867         fontSize_ = std::nullopt;
868     }
869     CHECK_NULL_VOID(fontSizeFloat_);
870     fontSizeFloat_->Set(fontSizeValue);
871 }
872 
SetAdaptMinFontSize(const Dimension & value,const TextStyle & textStyle,bool isReset)873 void TextContentModifier::SetAdaptMinFontSize(const Dimension& value, const TextStyle& textStyle, bool isReset)
874 {
875     auto fontSizeValue =
876         value.ConvertToPxDistribute(textStyle.GetMinFontScale(), textStyle.GetMaxFontScale(), textStyle.IsAllowScale());
877     if (!isReset) {
878         adaptMinFontSize_ = Dimension(fontSizeValue);
879     } else {
880         adaptMinFontSize_ = std::nullopt;
881     }
882     CHECK_NULL_VOID(adaptMinFontSizeFloat_);
883     adaptMinFontSizeFloat_->Set(fontSizeValue);
884 }
885 
SetAdaptMaxFontSize(const Dimension & value,const TextStyle & textStyle,bool isReset)886 void TextContentModifier::SetAdaptMaxFontSize(const Dimension& value, const TextStyle& textStyle, bool isReset)
887 {
888     auto fontSizeValue =
889         value.ConvertToPxDistribute(textStyle.GetMinFontScale(), textStyle.GetMaxFontScale(), textStyle.IsAllowScale());
890     if (!isReset) {
891         adaptMaxFontSize_ = Dimension(fontSizeValue);
892     } else {
893         adaptMaxFontSize_ = std::nullopt;
894     }
895     CHECK_NULL_VOID(adaptMaxFontSizeFloat_);
896     adaptMaxFontSizeFloat_->Set(fontSizeValue);
897 }
898 
SetFontWeight(const FontWeight & value,bool isReset)899 void TextContentModifier::SetFontWeight(const FontWeight& value, bool isReset)
900 {
901     if (!isReset) {
902         fontWeight_ = ConvertFontWeight(value);
903     } else {
904         fontWeight_ = std::nullopt;
905     }
906     CHECK_NULL_VOID(fontWeightFloat_);
907     fontWeightFloat_->Set(static_cast<int>(ConvertFontWeight(value)));
908 }
909 
SetTextColor(const Color & value,bool isReset)910 void TextContentModifier::SetTextColor(const Color& value, bool isReset)
911 {
912     onlyTextColorAnimation_ = false;
913     if (!isReset) {
914         textColor_ = value;
915     } else {
916         textColor_ = std::nullopt;
917     }
918     CHECK_NULL_VOID(animatableTextColor_);
919     animatableTextColor_->Set(LinearColor(value));
920 }
921 
TextColorModifier(const Color & value)922 void TextContentModifier::TextColorModifier(const Color& value)
923 {
924     SetTextColor(value);
925     onlyTextColorAnimation_ = true;
926 }
927 
SetSymbolColor(const std::vector<Color> & value,bool isReset)928 void TextContentModifier::SetSymbolColor(const std::vector<Color>& value, bool isReset)
929 {
930     if (!isReset) {
931         symbolColors_ = Convert2VectorLinearColor(value);
932     } else {
933         symbolColors_ = std::nullopt;
934     }
935     CHECK_NULL_VOID(animatableSymbolColor_);
936     animatableSymbolColor_->Set(Convert2VectorLinearColor(value));
937 }
938 
SetTextShadow(const std::vector<Shadow> & value)939 void TextContentModifier::SetTextShadow(const std::vector<Shadow>& value)
940 {
941     while (value.size() > shadows_.size()) {
942         AddDefaultShadow();
943     }
944     // else
945     while (value.size() < shadows_.size()) {
946         shadows_.pop_back();
947     }
948 
949     for (size_t i = 0; i < shadows_.size(); ++i) {
950         auto&& newShadow = value[i];
951         Shadow textShadow;
952         textShadow.SetBlurRadius(newShadow.GetBlurRadius());
953         textShadow.SetOffset(newShadow.GetOffset());
954         textShadow.SetColor(newShadow.GetColor());
955         shadows_[i].shadow = textShadow;
956         shadows_[i].blurRadius->Set(newShadow.GetBlurRadius());
957         shadows_[i].offsetX->Set(newShadow.GetOffset().GetX());
958         shadows_[i].offsetY->Set(newShadow.GetOffset().GetY());
959         shadows_[i].color->Set(LinearColor(newShadow.GetColor()));
960     }
961 }
962 
SetTextDecoration(const TextDecoration & type,bool isReset)963 void TextContentModifier::SetTextDecoration(const TextDecoration& type, bool isReset)
964 {
965     auto oldTextDecoration = textDecoration_.value_or(TextDecoration::NONE);
966     if (oldTextDecoration == type) {
967         return;
968     }
969 
970     textDecorationAnimatable_ = (oldTextDecoration == TextDecoration::NONE && type == TextDecoration::UNDERLINE) ||
971                                 (oldTextDecoration == TextDecoration::UNDERLINE && type == TextDecoration::NONE);
972     if (!isReset) {
973         textDecoration_ = type;
974     } else {
975         textDecoration_ = std::nullopt;
976     }
977     CHECK_NULL_VOID(textDecorationColorAlpha_);
978 
979     if (textDecoration_.has_value() && textDecoration_.value() == TextDecoration::NONE) {
980         textDecorationColorAlpha_->Set(0.0f);
981     } else if (textDecorationColor_.has_value()) {
982         textDecorationColorAlpha_->Set(static_cast<float>(textDecorationColor_.value().GetAlpha()));
983     }
984 }
985 
SetTextDecorationColor(const Color & color,bool isReset)986 void TextContentModifier::SetTextDecorationColor(const Color& color, bool isReset)
987 {
988     if (!isReset) {
989         textDecorationColor_ = color;
990     } else {
991         textDecorationColor_ = std::nullopt;
992     }
993 }
994 
SetBaselineOffset(const Dimension & value,const TextStyle & textStyle,bool isReset)995 void TextContentModifier::SetBaselineOffset(const Dimension& value, const TextStyle& textStyle, bool isReset)
996 {
997     float baselineOffsetValue = 0.0f;
998     if (!isReset) {
999         baselineOffsetValue = value.ConvertToPxDistribute(
1000             textStyle.GetMinFontScale(), textStyle.GetMaxFontScale(), textStyle.IsAllowScale());
1001         baselineOffset_ = Dimension(baselineOffsetValue);
1002     } else {
1003         baselineOffset_ = std::nullopt;
1004     }
1005     CHECK_NULL_VOID(baselineOffsetFloat_);
1006     baselineOffsetFloat_->Set(baselineOffsetValue);
1007 }
1008 
SetLineHeight(const Dimension & value,const TextStyle & textStyle,bool isReset)1009 void TextContentModifier::SetLineHeight(const Dimension& value, const TextStyle& textStyle, bool isReset)
1010 {
1011     float lineHeightValue = 0.0f;
1012     if (!isReset) {
1013         lineHeightValue = value.ConvertToPxDistribute(
1014             textStyle.GetMinFontScale(), textStyle.GetMaxFontScale(), textStyle.IsAllowScale());
1015         lineHeight_ = Dimension(lineHeightValue);
1016     } else {
1017         lineHeight_ = std::nullopt;
1018     }
1019     CHECK_NULL_VOID(lineHeightFloat_);
1020     lineHeightFloat_->Set(lineHeightValue);
1021 }
1022 
SetContentOffset(OffsetF & value)1023 void TextContentModifier::SetContentOffset(OffsetF& value)
1024 {
1025     CHECK_NULL_VOID(contentOffset_);
1026     contentOffset_->Set(value);
1027 }
1028 
SetContentSize(SizeF & value)1029 void TextContentModifier::SetContentSize(SizeF& value)
1030 {
1031     CHECK_NULL_VOID(contentSize_);
1032     contentSize_->Set(value);
1033 }
1034 
StartTextRace(const MarqueeOption & option)1035 void TextContentModifier::StartTextRace(const MarqueeOption& option)
1036 {
1037     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
1038         UpdateImageNodeVisible(VisibleType::INVISIBLE);
1039     }
1040     if (!SetTextRace(option)) {
1041         return;
1042     }
1043 
1044     if (!CheckMarqueeState(MarqueeState::IDLE) && !CheckMarqueeState(MarqueeState::STOPPED)) {
1045         PauseTextRace();
1046     }
1047 
1048     marqueeSet_ = true;
1049     ResumeTextRace(false);
1050 
1051     if (!IsMarqueeVisible()) {
1052         PauseAnimation();
1053     }
1054 }
1055 
StopTextRace()1056 void TextContentModifier::StopTextRace()
1057 {
1058     marqueeSet_ = false;
1059     if (!CheckMarqueeState(MarqueeState::RUNNING) && !CheckMarqueeState(MarqueeState::PAUSED)) {
1060         return;
1061     }
1062     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
1063         UpdateImageNodeVisible(VisibleType::VISIBLE);
1064     }
1065     PauseTextRace();
1066 }
1067 
ResumeAnimation()1068 void TextContentModifier::ResumeAnimation()
1069 {
1070     CHECK_NULL_VOID(raceAnimation_);
1071     if (!CheckMarqueeState(MarqueeState::PAUSED) || !IsMarqueeVisible()) {
1072         return;
1073     }
1074     AnimationUtils::ResumeAnimation(raceAnimation_);
1075     SetMarqueeState(MarqueeState::RUNNING);
1076 }
1077 
PauseAnimation()1078 void TextContentModifier::PauseAnimation()
1079 {
1080     CHECK_NULL_VOID(raceAnimation_);
1081     if (!CheckMarqueeState(MarqueeState::RUNNING)) {
1082         return;
1083     }
1084     AnimationUtils::PauseAnimation(raceAnimation_);
1085     SetMarqueeState(MarqueeState::PAUSED);
1086 }
1087 
GetTextRacePercent()1088 float TextContentModifier::GetTextRacePercent()
1089 {
1090     float percent = 0;
1091     if (racePercentFloat_) {
1092         percent = racePercentFloat_->Get();
1093     }
1094     return percent;
1095 }
1096 
GetTextRaceDirection() const1097 TextDirection TextContentModifier::GetTextRaceDirection() const
1098 {
1099     auto textPattern = DynamicCast<TextPattern>(pattern_.Upgrade());
1100     CHECK_NULL_RETURN(textPattern, TextDirection::LTR);
1101     auto frameNode = textPattern->GetHost();
1102     CHECK_NULL_RETURN(frameNode, TextDirection::LTR);
1103     auto layoutProperty = frameNode->GetLayoutProperty<TextLayoutProperty>();
1104     CHECK_NULL_RETURN(layoutProperty, TextDirection::LTR);
1105     auto direction = layoutProperty->GetLayoutDirection();
1106     if (direction == TextDirection::AUTO) {
1107         direction = GetTextRaceDirectionByContent();
1108     }
1109     return direction;
1110 }
1111 
GetTextRaceDirectionByContent() const1112 TextDirection TextContentModifier::GetTextRaceDirectionByContent() const
1113 {
1114     auto textPattern = DynamicCast<TextPattern>(pattern_.Upgrade());
1115     CHECK_NULL_RETURN(textPattern, TextDirection::LTR);
1116     auto pManager = textPattern->GetParagraphManager();
1117     CHECK_NULL_RETURN(pManager, TextDirection::LTR);
1118     if (pManager->GetParagraphs().size() == 0) {
1119         return TextDirection::LTR;
1120     }
1121     auto paragraph = pManager->GetParagraphs().front().paragraph;
1122     CHECK_NULL_RETURN(paragraph, TextDirection::LTR);
1123     auto paragraphText = StringUtils::Str16ToStr8(paragraph->GetParagraphText());
1124     auto content = StringUtils::ToWstring(paragraphText);
1125     for (const auto& charFromContent : content) {
1126         if (TextLayoutadapter::IsLeftToRight(charFromContent)) {
1127             return TextDirection::LTR;
1128         } else if (TextLayoutadapter::IsRightToLeft(charFromContent)) {
1129             return TextDirection::RTL;
1130         } else if (TextLayoutadapter::IsRightTOLeftArabic(charFromContent)) {
1131             return TextDirection::RTL;
1132         }
1133     }
1134     return AceApplicationInfo::GetInstance().IsRightToLeft() ?
1135         TextDirection::RTL : TextDirection::LTR;
1136 }
1137 
ResetTextRacePercent()1138 void TextContentModifier::ResetTextRacePercent()
1139 {
1140     if (GetTextRaceDirection() == TextDirection::LTR) {
1141         // LTR start 0%
1142         racePercentFloat_->Set(RACE_MOVE_PERCENT_MIN);
1143         marqueeRaceMaxPercent_ = RACE_MOVE_PERCENT_MAX + RACE_MOVE_PERCENT_MIN;
1144         return;
1145     }
1146     // RTL
1147     auto textPattern = DynamicCast<TextPattern>(pattern_.Upgrade());
1148     CHECK_NULL_VOID(textPattern);
1149     auto pManager = textPattern->GetParagraphManager();
1150     CHECK_NULL_VOID(pManager);
1151     if (pManager->GetParagraphs().size() == 0) {
1152         return;
1153     }
1154     auto paragraph = pManager->GetParagraphs().front().paragraph;
1155     CHECK_NULL_VOID(paragraph);
1156     auto textRectWidth = textPattern->GetTextRect().Width();
1157     float textWidth = paragraph->GetTextWidth();
1158     float racePercentFloat = 0.0f;
1159     if (marqueeOption_.direction == MarqueeDirection::LEFT) {
1160         racePercentFloat = (textWidth - textRectWidth) / (textWidth + textRaceSpaceWidth_) * RACE_MOVE_PERCENT_MAX;
1161     } else {
1162         racePercentFloat =
1163             (textRaceSpaceWidth_ + textRectWidth) / (textWidth + textRaceSpaceWidth_) * RACE_MOVE_PERCENT_MAX -
1164             RACE_MOVE_PERCENT_MAX;
1165     }
1166     marqueeRaceMaxPercent_ = RACE_MOVE_PERCENT_MAX + racePercentFloat;
1167     racePercentFloat_->Set(racePercentFloat);
1168 }
1169 
ContentChange()1170 void TextContentModifier::ContentChange()
1171 {
1172     CHECK_NULL_VOID(contentChange_);
1173     contentChange_->Set(contentChange_->Get() + 1);
1174 }
1175 
AddDefaultShadow()1176 void TextContentModifier::AddDefaultShadow()
1177 {
1178     Shadow emptyShadow;
1179     auto blurRadius = MakeRefPtr<AnimatablePropertyFloat>(emptyShadow.GetBlurRadius());
1180     auto offsetX = MakeRefPtr<AnimatablePropertyFloat>(emptyShadow.GetOffset().GetX());
1181     auto offsetY = MakeRefPtr<AnimatablePropertyFloat>(emptyShadow.GetOffset().GetY());
1182     auto color = MakeRefPtr<AnimatablePropertyColor>(LinearColor(emptyShadow.GetColor()));
1183     Shadow textShadow;
1184     textShadow.SetBlurRadius(emptyShadow.GetBlurRadius());
1185     textShadow.SetOffset(emptyShadow.GetOffset());
1186     textShadow.SetColor(emptyShadow.GetColor());
1187     shadows_.emplace_back(ShadowProp {
1188         .shadow = textShadow, .blurRadius = blurRadius, .offsetX = offsetX, .offsetY = offsetY, .color = color });
1189     AttachProperty(blurRadius);
1190     AttachProperty(offsetX);
1191     AttachProperty(offsetY);
1192     AttachProperty(color);
1193 }
1194 
SetMarqueeState(MarqueeState state)1195 void TextContentModifier::SetMarqueeState(MarqueeState state)
1196 {
1197     auto prevState = marqueeState_;
1198     marqueeState_ = state;
1199     auto pattern = DynamicCast<TextPattern>(pattern_.Upgrade());
1200     CHECK_NULL_VOID(pattern);
1201     auto host = pattern->GetHost();
1202     CHECK_NULL_VOID(host);
1203     TAG_LOGI(AceLogTag::ACE_TEXT, "SetMarqueeState: id %{public}d, from state %{public}d to state %{public}d",
1204         host->GetId(), prevState, state);
1205 }
1206 
ContentModifierDump()1207 void TextContentModifier::ContentModifierDump()
1208 {
1209     auto& dumpLog = DumpLog::GetInstance();
1210     if (animatableTextColor_) {
1211         dumpLog.AddDesc(
1212             std::string("animatableTextColor: ").append(Color(animatableTextColor_->Get().GetValue()).ColorToString()));
1213     }
1214     dumpLog.AddDesc(std::string("onlyTextColorAnimation: ").append(std::to_string(onlyTextColorAnimation_)));
1215 }
1216 
SetIsFocused(const bool isFocused)1217 void TextContentModifier::SetIsFocused(const bool isFocused)
1218 {
1219     marqueeFocused_ = isFocused;
1220     DetermineTextRace();
1221 }
1222 
SetIsHovered(const bool isHovered)1223 void TextContentModifier::SetIsHovered(const bool isHovered)
1224 {
1225     marqueeHovered_ = isHovered;
1226     DetermineTextRace();
1227 }
1228 
SetTextRace(const MarqueeOption & option)1229 bool TextContentModifier::SetTextRace(const MarqueeOption& option)
1230 {
1231     auto textPattern = DynamicCast<TextPattern>(pattern_.Upgrade());
1232     CHECK_NULL_RETURN(textPattern, false);
1233     auto pManager = textPattern->GetParagraphManager();
1234     CHECK_NULL_RETURN(pManager, false);
1235     textRaceSpaceWidth_ = RACE_SPACE_WIDTH;
1236     auto pipeline = PipelineContext::GetCurrentContext();
1237     if (pipeline) {
1238         textRaceSpaceWidth_ *= pipeline->GetDipScale();
1239     }
1240 
1241     auto duration =
1242         static_cast<int32_t>(std::abs(pManager->GetTextWidth() + textRaceSpaceWidth_) * RACE_DURATION_RATIO);
1243     if (option.step > 0) {
1244         duration = static_cast<int32_t>(duration / option.step);
1245     }
1246     if (duration <= 0) {
1247         return false;
1248     }
1249     auto optionTemp = option;
1250     if (optionTemp.direction == MarqueeDirection::DEFAULT ||
1251         optionTemp.direction == MarqueeDirection::DEFAULT_REVERSE) {
1252         auto textDirection = GetTextRaceDirection();
1253         optionTemp.direction =
1254             ((textDirection == TextDirection::LTR && optionTemp.direction == MarqueeDirection::DEFAULT) ||
1255                 (textDirection == TextDirection::RTL && optionTemp.direction == MarqueeDirection::DEFAULT_REVERSE))
1256                 ? MarqueeDirection::LEFT
1257                 : MarqueeDirection::RIGHT;
1258     }
1259     if (CheckMarqueeState(MarqueeState::RUNNING) && marqueeOption_ == optionTemp && duration == marqueeDuration_) {
1260         return false;
1261     }
1262 
1263     marqueeDuration_ = duration;
1264     marqueeOption_ = optionTemp;
1265     ResetTextRacePercent();
1266     marqueeGradientPercent_ = GetFadeoutPercent();
1267     return true;
1268 }
1269 
ResumeTextRace(bool bounce)1270 void TextContentModifier::ResumeTextRace(bool bounce)
1271 {
1272     if (!AllowTextRace()) {
1273         return;
1274     }
1275     if (!bounce) {
1276         marqueeCount_ = 0;
1277         auto textPattern = DynamicCast<TextPattern>(pattern_.Upgrade());
1278         CHECK_NULL_VOID(textPattern);
1279         textPattern->FireOnMarqueeStateChange(TextMarqueeState::START);
1280     }
1281 
1282     AnimationOption option = AnimationOption();
1283     RefPtr<Curve> curve = MakeRefPtr<LinearCurve>();
1284     option.SetDuration(marqueeDuration_);
1285     option.SetDelay(bounce ? marqueeOption_.delay : 0);
1286     option.SetCurve(curve);
1287     option.SetIteration(1);
1288     SetTextRaceAnimation(option);
1289 }
1290 
SetTextRaceAnimation(const AnimationOption & option)1291 void TextContentModifier::SetTextRaceAnimation(const AnimationOption& option)
1292 {
1293     marqueeAnimationId_++;
1294     ResetTextRacePercent();
1295     raceAnimation_ = AnimationUtils::StartAnimation(
1296         option, [weak = AceType::WeakClaim(this)]() {
1297              auto modifier = weak.Upgrade();
1298             CHECK_NULL_VOID(modifier);
1299             float startPercent = modifier->GetTextRacePercent();
1300             modifier->racePercentFloat_->Set(RACE_MOVE_PERCENT_MAX + startPercent);
1301         },
1302         [weak = AceType::WeakClaim(this), marqueeAnimationId = marqueeAnimationId_, id = Container::CurrentId()]() {
1303             auto modifier = weak.Upgrade();
1304             CHECK_NULL_VOID(modifier);
1305 
1306             ContainerScope scope(id);
1307             auto taskExecutor = Container::CurrentTaskExecutor();
1308             CHECK_NULL_VOID(taskExecutor);
1309 
1310             auto onFinish = [weak, marqueeAnimationId]() {
1311                 auto modifier = weak.Upgrade();
1312                 CHECK_NULL_VOID(modifier);
1313 
1314                 if (marqueeAnimationId != modifier->marqueeAnimationId_) {
1315                     return;
1316                 }
1317                 auto textPattern = DynamicCast<TextPattern>(modifier->pattern_.Upgrade());
1318                 CHECK_NULL_VOID(textPattern);
1319                 if (NearEqual(modifier->GetTextRacePercent(), modifier->marqueeRaceMaxPercent_)) {
1320                     textPattern->FireOnMarqueeStateChange(TextMarqueeState::BOUNCE);
1321                     modifier->marqueeCount_++;
1322                 }
1323                 if (!modifier->AllowTextRace()) {
1324                     textPattern->FireOnMarqueeStateChange(TextMarqueeState::FINISH);
1325                 } else {
1326                     auto frameNode = textPattern->GetHost();
1327                     CHECK_NULL_VOID(frameNode);
1328                     frameNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1329                     modifier->ResumeTextRace(true);
1330                 }
1331             };
1332 
1333             if (taskExecutor->WillRunOnCurrentThread(TaskExecutor::TaskType::UI)) {
1334                 onFinish();
1335             } else {
1336                 taskExecutor->PostTask(
1337                     [onFinish]() { onFinish(); }, TaskExecutor::TaskType::UI, "ArkUITextStartTextRace");
1338             }
1339         });
1340     SetMarqueeState(MarqueeState::RUNNING);
1341 }
1342 
PauseTextRace()1343 void TextContentModifier::PauseTextRace()
1344 {
1345     if (CheckMarqueeState(MarqueeState::IDLE) || CheckMarqueeState(MarqueeState::STOPPED)) {
1346         return;
1347     }
1348     if (raceAnimation_) {
1349         AnimationUtils::StopAnimation(raceAnimation_);
1350     }
1351 
1352     SetMarqueeState(MarqueeState::STOPPED);
1353     ResetTextRacePercent();
1354 }
1355 
AllowTextRace()1356 bool TextContentModifier::AllowTextRace()
1357 {
1358     if (!marqueeSet_ || !marqueeOption_.start) {
1359         return false;
1360     }
1361     if (marqueeOption_.loop > 0 && marqueeCount_ >= marqueeOption_.loop) {
1362         return false;
1363     }
1364     if (marqueeOption_.startPolicy == MarqueeStartPolicy::ON_FOCUS && !(marqueeFocused_ || marqueeHovered_)) {
1365         return false;
1366     }
1367 
1368     return true;
1369 }
1370 
DetermineTextRace()1371 void TextContentModifier::DetermineTextRace()
1372 {
1373     if (!marqueeSet_ || !marqueeOption_.start || marqueeOption_.startPolicy != MarqueeStartPolicy::ON_FOCUS) {
1374         return;
1375     }
1376 
1377     auto textRaceing = CheckMarqueeState(MarqueeState::RUNNING);
1378     if (textRaceing && !marqueeFocused_ && !marqueeHovered_) {
1379         PauseTextRace();
1380         return;
1381     }
1382     if (!textRaceing && (marqueeFocused_ || marqueeHovered_)) {
1383         ResumeTextRace(false);
1384     }
1385 }
1386 
GetFadeoutPercent()1387 float TextContentModifier::GetFadeoutPercent()
1388 {
1389     marqueeGradientPercent_ = DEFAULT_FADEOUT_GRADIENTPERCENT;
1390 
1391     auto contentWidth = contentSize_->Get().Width();
1392     if (contentWidth > 0) {
1393         auto pipeline = PipelineContext::GetCurrentContext();
1394         CHECK_NULL_RETURN(pipeline, marqueeGradientPercent_);
1395         auto theme = pipeline->GetTheme<TextTheme>();
1396         CHECK_NULL_RETURN(theme, marqueeGradientPercent_);
1397         auto fadeoutWidth = theme->GetFadeoutWidth();
1398         marqueeGradientPercent_ = fadeoutWidth.ConvertToPx() / contentWidth;
1399     }
1400     return marqueeGradientPercent_;
1401 }
1402 
GetFadeoutInfo(DrawingContext & drawingContext)1403 FadeoutInfo TextContentModifier::GetFadeoutInfo(DrawingContext& drawingContext)
1404 {
1405     FadeoutInfo info;
1406     if (!marqueeSet_) {
1407         return info;
1408     }
1409     CHECK_NULL_RETURN(contentSize_, info);
1410     CHECK_NULL_RETURN(contentOffset_, info);
1411     auto textPattern = DynamicCast<TextPattern>(pattern_.Upgrade());
1412     CHECK_NULL_RETURN(textPattern, info);
1413     auto pManager = textPattern->GetParagraphManager();
1414     CHECK_NULL_RETURN(pManager, info);
1415     float racePercent = GetTextRacePercent();
1416     float textRacePercent =
1417         marqueeOption_.direction == MarqueeDirection::LEFT ? racePercent : RACE_MOVE_PERCENT_MAX - racePercent;
1418     auto paragraphText = pManager->GetParagraphs().front().paragraph;
1419     float textWidth = paragraphText->GetTextWidth();
1420     info.paragraph1StartPosition =
1421         paintOffset_.GetX() + (textWidth + textRaceSpaceWidth_) * textRacePercent / RACE_MOVE_PERCENT_MAX * -1;
1422     info.paragraph1EndPosition = info.paragraph1StartPosition + textWidth;
1423     info.paragraph2StartPosition = info.paragraph1EndPosition + textRaceSpaceWidth_;
1424     info.paragraph2EndPosition = info.paragraph2StartPosition + textWidth;
1425     if (marqueeOption_.fadeout) {
1426         auto contentSize = contentSize_->Get();
1427         auto contentOffset = contentOffset_->Get();
1428         float contentStartPosition = contentOffset.GetX();
1429         float contentEndPosition = contentStartPosition + contentSize.Width();
1430         info.isLeftFadeout = (LessNotEqual(info.paragraph1StartPosition, contentStartPosition) &&
1431                                  GreatNotEqual(info.paragraph1EndPosition, contentStartPosition)) ||
1432                              (LessNotEqual(info.paragraph2StartPosition, contentStartPosition) &&
1433                                  GreatNotEqual(info.paragraph2EndPosition, contentStartPosition));
1434         info.isRightFadeout = (LessNotEqual(info.paragraph1StartPosition, contentEndPosition) &&
1435                                   GreatNotEqual(info.paragraph1EndPosition, contentEndPosition)) ||
1436                               (LessNotEqual(info.paragraph2StartPosition, contentEndPosition) &&
1437                                   GreatNotEqual(info.paragraph2EndPosition, contentEndPosition));
1438     } else {
1439         info.isLeftFadeout = false;
1440         info.isRightFadeout = false;
1441     }
1442     if (info.IsFadeout()) {
1443         marqueeGradientPercent_ = GetFadeoutPercent();
1444         if (marqueeGradientPercent_ > RACE_MIN_GRADIENTPERCENT) {
1445             marqueeGradientPercent_ = RACE_MIN_GRADIENTPERCENT;
1446         }
1447         info.fadeoutPercent = marqueeGradientPercent_;
1448     }
1449     return info;
1450 }
1451 
DrawFadeout(DrawingContext & drawingContext,const FadeoutInfo & info)1452 void TextContentModifier::DrawFadeout(DrawingContext& drawingContext, const FadeoutInfo& info)
1453 {
1454     auto textPattern = DynamicCast<TextPattern>(pattern_.Upgrade());
1455     CHECK_NULL_VOID(textPattern);
1456 
1457     RSCanvas& canvas = drawingContext.canvas;
1458     auto contentRect = textPattern->GetTextContentRect();
1459     auto contentSize = contentSize_->Get();
1460     RSRect clipInnerRect = RSRect(0, 0, drawingContext.width + ROUND_VALUE, drawingContext.height);
1461 
1462     RSSaveLayerOps slo(&clipInnerRect, nullptr);
1463     canvas.SaveLayer(slo);
1464 
1465     DrawContent(drawingContext, info);
1466 
1467     RSBrush brush;
1468     auto contentOffset = contentOffset_->Get();
1469     std::vector<RSPoint> points = { RSPoint(contentRect.Left(), contentRect.Top()),
1470         RSPoint(contentSize.Width() + contentOffset.GetX(), contentRect.Top()) };
1471     std::vector<RSColorQuad> colors = { Color::TRANSPARENT.GetValue(), Color::WHITE.GetValue(), Color::WHITE.GetValue(),
1472         Color::TRANSPARENT.GetValue() };
1473     std::vector<RSScalar> pos = { 0.0f, info.isLeftFadeout ? info.fadeoutPercent : 0.0f,
1474         info.isRightFadeout ? (1 - info.fadeoutPercent) : 1.0f, 1.0f };
1475     brush.SetShaderEffect(
1476         RSShaderEffect::CreateLinearGradient(points.at(0), points.at(1), colors, pos, RSTileMode::CLAMP));
1477     brush.SetBlendMode(RSBlendMode::DST_IN);
1478     canvas.AttachBrush(brush);
1479     canvas.DrawRect(clipInnerRect);
1480     canvas.DetachBrush();
1481     canvas.Restore();
1482 }
1483 
IsMarqueeVisible() const1484 bool TextContentModifier::IsMarqueeVisible() const
1485 {
1486     auto textPattern = DynamicCast<TextPattern>(pattern_.Upgrade());
1487     CHECK_NULL_RETURN(textPattern, true);
1488     auto host = textPattern->GetHost();
1489     CHECK_NULL_RETURN(host, true);
1490     RectF visibleRect;
1491     RectF visibleInnerRect;
1492     RectF frameRect;
1493     host->GetVisibleRectWithClip(visibleRect, visibleInnerRect, frameRect);
1494     return Positive(visibleInnerRect.Width()) && Positive(visibleInnerRect.Height());
1495 }
1496 } // namespace OHOS::Ace::NG
1497