• 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 
18 #include "base/utils/utils.h"
19 #include "core/components_ng/render/drawing.h"
20 #include "core/components_v2/inspector/utils.h"
21 #include "core/pipeline_ng/pipeline_context.h"
22 
23 namespace OHOS::Ace::NG {
24 namespace {
25 constexpr float RACE_MOVE_PERCENT_MIN = 0.0f;
26 constexpr float RACE_MOVE_PERCENT_MAX = 100.0f;
27 constexpr float RACE_TEMPO = 0.2f;
28 constexpr uint32_t RACE_DURATION = 2000;
29 constexpr float RACE_SPACE_WIDTH = 48.0f;
30 constexpr float ROUND_VALUE = 0.5f;
31 constexpr uint32_t POINT_COUNT = 4;
32 constexpr float OBSCURED_ALPHA = 0.2f;
33 const FontWeight FONT_WEIGHT_CONVERT_MAP[] = {
34     FontWeight::W100,
35     FontWeight::W200,
36     FontWeight::W300,
37     FontWeight::W400,
38     FontWeight::W500,
39     FontWeight::W600,
40     FontWeight::W700,
41     FontWeight::W800,
42     FontWeight::W900,
43     FontWeight::W700,       // FontWeight::BOLD
44     FontWeight::W400,       // FontWeight::NORMAL
45     FontWeight::W900,       // FontWeight::BOLDER,
46     FontWeight::W100,       // FontWeight::LIGHTER
47     FontWeight::W500,       // FontWeight::MEDIUM
48     FontWeight::W400,       // FontWeight::REGULAR
49 };
50 
ConvertFontWeight(FontWeight fontWeight)51 inline FontWeight ConvertFontWeight(FontWeight fontWeight)
52 {
53     return FONT_WEIGHT_CONVERT_MAP[(int)fontWeight];
54 }
55 } // namespace
56 
TextContentModifier(const std::optional<TextStyle> textStyle)57 TextContentModifier::TextContentModifier(const std::optional<TextStyle> textStyle)
58 {
59     contentChange_ = AceType::MakeRefPtr<PropertyBool>(false);
60     AttachProperty(contentChange_);
61     contentOffset_ = AceType::MakeRefPtr<PropertyOffsetF>(OffsetF());
62     contentSize_ = AceType::MakeRefPtr<PropertySizeF>(SizeF());
63     AttachProperty(contentOffset_);
64     AttachProperty(contentSize_);
65 
66     if (textStyle.has_value()) {
67         SetDefaultAnimatablePropertyValue(textStyle.value());
68     }
69 
70     racePercentFloat_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(0.0f);
71     AttachProperty(racePercentFloat_);
72     clip_ = AceType::MakeRefPtr<PropertyBool>(true);
73     AttachProperty(clip_);
74     fontFamilyString_ = AceType::MakeRefPtr<PropertyString>("");
75     AttachProperty(fontFamilyString_);
76     fontReady_ = AceType::MakeRefPtr<PropertyBool>(false);
77     AttachProperty(fontReady_);
78 }
79 
SetDefaultAnimatablePropertyValue(const TextStyle & textStyle)80 void TextContentModifier::SetDefaultAnimatablePropertyValue(const TextStyle& textStyle)
81 {
82     SetDefaultFontSize(textStyle);
83     SetDefaultFontWeight(textStyle);
84     SetDefaultTextColor(textStyle);
85     SetDefaultTextShadow(textStyle);
86     SetDefaultTextDecoration(textStyle);
87     SetDefaultBaselineOffset(textStyle);
88 }
89 
SetDefaultFontSize(const TextStyle & textStyle)90 void TextContentModifier::SetDefaultFontSize(const TextStyle& textStyle)
91 {
92     float fontSizeValue = textStyle.GetFontSize().Value();
93     auto pipelineContext = PipelineContext::GetCurrentContext();
94     if (pipelineContext) {
95         fontSizeValue = pipelineContext->NormalizeToPx(textStyle.GetFontSize());
96         if (textStyle.IsAllowScale() || textStyle.GetFontSize().Unit() == DimensionUnit::FP) {
97             fontSizeValue = pipelineContext->NormalizeToPx(textStyle.GetFontSize() * pipelineContext->GetFontScale());
98         }
99     }
100 
101     fontSizeFloat_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(fontSizeValue);
102     AttachProperty(fontSizeFloat_);
103 }
104 
SetDefaultFontWeight(const TextStyle & textStyle)105 void TextContentModifier::SetDefaultFontWeight(const TextStyle& textStyle)
106 {
107     fontWeightFloat_ =
108         AceType::MakeRefPtr<AnimatablePropertyFloat>(static_cast<float>(ConvertFontWeight(textStyle.GetFontWeight())));
109     AttachProperty(fontWeightFloat_);
110 }
111 
SetDefaultTextColor(const TextStyle & textStyle)112 void TextContentModifier::SetDefaultTextColor(const TextStyle& textStyle)
113 {
114     animatableTextColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(textStyle.GetTextColor()));
115     AttachProperty(animatableTextColor_);
116 }
117 
SetDefaultTextShadow(const TextStyle & textStyle)118 void TextContentModifier::SetDefaultTextShadow(const TextStyle& textStyle)
119 {
120     auto textShadow = textStyle.GetTextShadows().empty() ? Shadow() : textStyle.GetTextShadows().at(0);
121     shadowBlurRadiusFloat_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(textShadow.GetBlurRadius());
122     shadowOffsetXFloat_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(textShadow.GetOffset().GetX());
123     shadowOffsetYFloat_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(textShadow.GetOffset().GetY());
124     shadowColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(textShadow.GetColor()));
125     AttachProperty(shadowBlurRadiusFloat_);
126     AttachProperty(shadowOffsetXFloat_);
127     AttachProperty(shadowOffsetYFloat_);
128     AttachProperty(shadowColor_);
129 }
SetDefaultTextDecoration(const TextStyle & textStyle)130 void TextContentModifier::SetDefaultTextDecoration(const TextStyle& textStyle)
131 {
132     textDecoration_ = textStyle.GetTextDecoration();
133     textDecorationColor_ = textStyle.GetTextDecorationColor();
134     textDecorationColorAlpha_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(
135         textDecoration_ == TextDecoration::NONE ? 0.0f : textDecorationColor_->GetAlpha());
136     AttachProperty(textDecorationColorAlpha_);
137 }
SetDefaultBaselineOffset(const TextStyle & textStyle)138 void TextContentModifier::SetDefaultBaselineOffset(const TextStyle& textStyle)
139 {
140     float baselineOffset = textStyle.GetBaselineOffset().Value();
141     auto pipelineContext = PipelineContext::GetCurrentContext();
142     if (pipelineContext) {
143         baselineOffset = pipelineContext->NormalizeToPx(textStyle.GetBaselineOffset());
144     }
145 
146     baselineOffsetFloat_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(baselineOffset);
147     AttachProperty(baselineOffsetFloat_);
148 }
149 
SetClip(bool clip)150 void TextContentModifier::SetClip(bool clip)
151 {
152     if (clip_) {
153         clip_->Set(clip);
154     }
155 }
156 
SetFontReady(bool value)157 void TextContentModifier::SetFontReady(bool value)
158 {
159     if (fontReady_) {
160         fontReady_->Set(value);
161     }
162 }
163 
onDraw(DrawingContext & drawingContext)164 void TextContentModifier::onDraw(DrawingContext& drawingContext)
165 {
166     bool ifPaintObscuration = std::any_of(obscuredReasons_.begin(), obscuredReasons_.end(),
167         [](const auto& reason) { return reason == ObscuredReasons::PLACEHOLDER; });
168     if (!ifPaintObscuration || ifHaveSpanItemChildren_) {
169         CHECK_NULL_VOID_NOLOG(paragraph_);
170         auto canvas = drawingContext.canvas;
171         canvas.Save();
172         if (!textRacing_) {
173             auto contentSize = contentSize_->Get();
174             auto contentOffset = contentOffset_->Get();
175             if (clip_ && clip_->Get() &&
176                 (!fontSize_.has_value() || !fontSizeFloat_ ||
177                     NearEqual(fontSize_.value().Value(), fontSizeFloat_->Get()))) {
178                 RSRect clipInnerRect = RSRect(contentOffset.GetX(), contentOffset.GetY(),
179                     contentSize.Width() + contentOffset.GetX(), contentSize.Height() + contentOffset.GetY());
180                 canvas.ClipRect(clipInnerRect, RSClipOp::INTERSECT);
181             }
182 
183             paragraph_->Paint(canvas, paintOffset_.GetX(), paintOffset_.GetY());
184         } else {
185             // Racing
186             float textRacePercent = GetTextRacePercent();
187             if (clip_ && clip_->Get()) {
188                 canvas.ClipRect(RSRect(0, 0, drawingContext.width, drawingContext.height), RSClipOp::INTERSECT);
189             }
190             float paragraph1Offset =
191                 (paragraph_->GetTextWidth() + textRaceSpaceWidth_) * textRacePercent / RACE_MOVE_PERCENT_MAX * -1;
192             if ((paintOffset_.GetX() + paragraph1Offset + paragraph_->GetTextWidth()) > 0) {
193                 paragraph_->Paint(drawingContext.canvas, paintOffset_.GetX() + paragraph1Offset, paintOffset_.GetY());
194             }
195             float paragraph2Offset = paragraph1Offset + paragraph_->GetTextWidth() + textRaceSpaceWidth_;
196             if ((paintOffset_.GetX() + paragraph2Offset) < drawingContext.width) {
197                 paragraph_->Paint(drawingContext.canvas, paintOffset_.GetX() + paragraph2Offset, paintOffset_.GetY());
198             }
199         }
200         canvas.Restore();
201     } else {
202         DrawObscuration(drawingContext);
203     }
204 }
205 
DrawObscuration(DrawingContext & drawingContext)206 void TextContentModifier::DrawObscuration(DrawingContext& drawingContext)
207 {
208     RSCanvas canvas = drawingContext.canvas;
209     RSBrush brush;
210     std::vector<RSPoint> radiusXY(POINT_COUNT);
211     Dimension borderRadius = Dimension(2.0, DimensionUnit::VP);
212     for (auto& radius : radiusXY) {
213         radius.SetX(static_cast<float>(borderRadius.ConvertToPx()));
214         radius.SetY(static_cast<float>(borderRadius.ConvertToPx()));
215     }
216     CHECK_NULL_VOID(animatableTextColor_);
217     Color fillColor = Color(animatableTextColor_->Get().GetValue());
218     RSColor rrSColor(fillColor.GetRed(), fillColor.GetGreen(), fillColor.GetBlue(),
219         (uint32_t)(fillColor.GetAlpha() * OBSCURED_ALPHA));
220     brush.SetColor(rrSColor);
221     brush.SetAntiAlias(true);
222     canvas.AttachBrush(brush);
223     CHECK_NULL_VOID(fontSizeFloat_);
224     float fontSize = fontSizeFloat_->Get();
225     std::vector<float> textLineWidth;
226     float currentLineWidth = 0.0f;
227     int32_t maxLineCount = 0;
228     CHECK_NULL_VOID(contentSize_);
229     CHECK_NULL_VOID(contentOffset_);
230     for (auto i = 0U; i < drawObscuredRects_.size(); i++) {
231         if (!NearEqual(drawObscuredRects_[i].Width(), 0.0f) && !NearEqual(drawObscuredRects_[i].Height(), 0.0f)) {
232             currentLineWidth += drawObscuredRects_[i].Width();
233             if (i == drawObscuredRects_.size() - 1) {
234                 textLineWidth.push_back(currentLineWidth);
235                 maxLineCount += LessOrEqual(drawObscuredRects_[i].Bottom(), contentSize_->Get().Height()) ? 1 : 0;
236             } else if (!NearEqual(drawObscuredRects_[i].Bottom(), drawObscuredRects_[i + 1].Bottom())) {
237                 textLineWidth.push_back(currentLineWidth);
238                 maxLineCount += LessOrEqual(drawObscuredRects_[i].Bottom(), contentSize_->Get().Height()) ? 1 : 0;
239                 currentLineWidth = 0;
240             } else {
241                 /** nothing to do **/
242             }
243         }
244     }
245     int32_t obscuredLineCount = std::min(maxLineCount, static_cast<int32_t>(textLineWidth.size()));
246     float offsetY = (contentSize_->Get().Height() - (obscuredLineCount * fontSize)) / (obscuredLineCount + 1);
247     for (auto i = 0; i < obscuredLineCount; i++) {
248         RSRoundRect rSRoundRect(RSRect(contentOffset_->Get().GetX(),
249             contentOffset_->Get().GetY() + std::max(offsetY + ((offsetY + fontSize) * i), 0.0f),
250             contentOffset_->Get().GetX() + std::min(textLineWidth[i], contentSize_->Get().Width()),
251             contentOffset_->Get().GetY() +
252                 std::min(offsetY + ((offsetY + fontSize) * i) + fontSize, contentSize_->Get().Height())), radiusXY);
253         canvas.DrawRoundRect(rSRoundRect);
254     }
255 }
256 
ModifyFontSizeInTextStyle(TextStyle & textStyle)257 void TextContentModifier::ModifyFontSizeInTextStyle(TextStyle& textStyle)
258 {
259     if (fontSize_.has_value() && fontSizeFloat_) {
260         textStyle.SetFontSize(Dimension(fontSizeFloat_->Get(), DimensionUnit::PX));
261     }
262 }
263 
ModifyFontWeightInTextStyle(TextStyle & textStyle)264 void TextContentModifier::ModifyFontWeightInTextStyle(TextStyle& textStyle)
265 {
266     if (fontWeight_.has_value() && fontWeightFloat_) {
267         textStyle.SetFontWeight(static_cast<FontWeight>(std::floor(fontWeightFloat_->Get() + ROUND_VALUE)));
268     }
269 }
270 
ModifyTextColorInTextStyle(TextStyle & textStyle)271 void TextContentModifier::ModifyTextColorInTextStyle(TextStyle& textStyle)
272 {
273     if (textColor_.has_value() && animatableTextColor_) {
274         textStyle.SetTextColor(Color(animatableTextColor_->Get().GetValue()));
275     }
276 }
277 
ModifyTextShadowsInTextStyle(TextStyle & textStyle)278 void TextContentModifier::ModifyTextShadowsInTextStyle(TextStyle& textStyle)
279 {
280     if (textShadow_.has_value() && shadowBlurRadiusFloat_ && shadowOffsetXFloat_ && shadowOffsetYFloat_ &&
281         shadowColor_) {
282         auto blurRadius = shadowBlurRadiusFloat_->Get();
283         auto offsetX = shadowOffsetXFloat_->Get();
284         auto offsetY = shadowOffsetYFloat_->Get();
285         auto color = shadowColor_->Get();
286         std::vector<Shadow> shadows = { Shadow(blurRadius, 0, Offset(offsetX, offsetY), Color(color.GetValue())) };
287         textStyle.SetTextShadows(std::move(shadows));
288     }
289 }
290 
ModifyDecorationInTextStyle(TextStyle & textStyle)291 void TextContentModifier::ModifyDecorationInTextStyle(TextStyle& textStyle)
292 {
293     if (textDecoration_.has_value() && textDecorationColor_.has_value() && textDecorationColorAlpha_) {
294         if (textDecorationAnimatable_) {
295             uint8_t alpha = static_cast<int>(std::floor(textDecorationColorAlpha_->Get() + ROUND_VALUE));
296             if (alpha == 0) {
297                 textStyle.SetTextDecoration(TextDecoration::NONE);
298                 textStyle.SetTextDecorationColor(textDecorationColor_.value());
299             } else {
300                 textStyle.SetTextDecoration(TextDecoration::UNDERLINE);
301                 textStyle.SetTextDecorationColor(Color(textDecorationColor_.value()).ChangeAlpha(alpha));
302             }
303         } else {
304             textStyle.SetTextDecoration(textDecoration_.value());
305             textStyle.SetTextDecorationColor(textDecorationColor_.value());
306         }
307     }
308 }
309 
ModifyBaselineOffsetInTextStyle(TextStyle & textStyle)310 void TextContentModifier::ModifyBaselineOffsetInTextStyle(TextStyle& textStyle)
311 {
312     if (baselineOffset_.has_value() && baselineOffsetFloat_) {
313         textStyle.SetBaselineOffset(Dimension(baselineOffsetFloat_->Get(), DimensionUnit::PX));
314     }
315 }
316 
ModifyTextStyle(TextStyle & textStyle)317 void TextContentModifier::ModifyTextStyle(TextStyle& textStyle)
318 {
319     ModifyFontSizeInTextStyle(textStyle);
320     ModifyFontWeightInTextStyle(textStyle);
321     ModifyTextColorInTextStyle(textStyle);
322     ModifyTextShadowsInTextStyle(textStyle);
323     ModifyDecorationInTextStyle(textStyle);
324     ModifyBaselineOffsetInTextStyle(textStyle);
325 }
326 
UpdateFontSizeMeasureFlag(PropertyChangeFlag & flag)327 void TextContentModifier::UpdateFontSizeMeasureFlag(PropertyChangeFlag& flag)
328 {
329     if (fontSize_.has_value() && fontSizeFloat_ && !NearEqual(fontSize_.value().Value(), fontSizeFloat_->Get())) {
330         flag |= PROPERTY_UPDATE_MEASURE;
331     }
332 }
333 
UpdateFontWeightMeasureFlag(PropertyChangeFlag & flag)334 void TextContentModifier::UpdateFontWeightMeasureFlag(PropertyChangeFlag& flag)
335 {
336     if (fontWeight_.has_value() && fontWeightFloat_ &&
337         !NearEqual(static_cast<float>(static_cast<int>(fontWeight_.value())), fontWeightFloat_->Get())) {
338         flag |= PROPERTY_UPDATE_MEASURE;
339     }
340 }
341 
UpdateTextColorMeasureFlag(PropertyChangeFlag & flag)342 void TextContentModifier::UpdateTextColorMeasureFlag(PropertyChangeFlag& flag)
343 {
344     if (textColor_.has_value() && animatableTextColor_ &&
345         textColor_->GetValue() != animatableTextColor_->Get().GetValue()) {
346         flag |= PROPERTY_UPDATE_MEASURE_SELF;
347     }
348 }
349 
UpdateTextShadowMeasureFlag(PropertyChangeFlag & flag)350 void TextContentModifier::UpdateTextShadowMeasureFlag(PropertyChangeFlag& flag)
351 {
352     if (textShadow_.has_value() && shadowBlurRadiusFloat_ && shadowOffsetXFloat_ && shadowOffsetYFloat_ &&
353         shadowColor_) {
354         auto blurRadius = shadowBlurRadiusFloat_->Get();
355         auto offsetX = shadowOffsetXFloat_->Get();
356         auto offsetY = shadowOffsetYFloat_->Get();
357         auto color = shadowColor_->Get();
358         if (textShadow_ != Shadow(blurRadius, 0, Offset(offsetX, offsetY), Color(color.GetValue()))) {
359             flag |= PROPERTY_UPDATE_MEASURE;
360         }
361     }
362 }
363 
UpdateTextDecorationMeasureFlag(PropertyChangeFlag & flag)364 void TextContentModifier::UpdateTextDecorationMeasureFlag(PropertyChangeFlag& flag)
365 {
366     if (textDecoration_.has_value() && textDecorationColor_.has_value() && textDecorationColorAlpha_) {
367         uint8_t alpha = static_cast<int>(std::floor(textDecorationColorAlpha_->Get() + ROUND_VALUE));
368         if (textDecoration_.value() == TextDecoration::UNDERLINE && alpha != textDecorationColor_.value().GetAlpha()) {
369             flag |= PROPERTY_UPDATE_MEASURE;
370         } else if (textDecoration_.value() == TextDecoration::NONE && alpha != 0.0) {
371             flag |= PROPERTY_UPDATE_MEASURE;
372         }
373     }
374 }
375 
UpdateBaselineOffsetMeasureFlag(PropertyChangeFlag & flag)376 void TextContentModifier::UpdateBaselineOffsetMeasureFlag(PropertyChangeFlag& flag)
377 {
378     if (baselineOffset_.has_value() && baselineOffsetFloat_ &&
379         !NearEqual(baselineOffset_.value().Value(), baselineOffsetFloat_->Get())) {
380         flag |= PROPERTY_UPDATE_MEASURE;
381     }
382 }
383 
NeedMeasureUpdate(PropertyChangeFlag & flag)384 bool TextContentModifier::NeedMeasureUpdate(PropertyChangeFlag& flag)
385 {
386     flag = 0;
387     UpdateFontSizeMeasureFlag(flag);
388     UpdateFontWeightMeasureFlag(flag);
389     UpdateTextColorMeasureFlag(flag);
390     UpdateTextShadowMeasureFlag(flag);
391     UpdateTextDecorationMeasureFlag(flag);
392     UpdateBaselineOffsetMeasureFlag(flag);
393     flag &= (PROPERTY_UPDATE_MEASURE | PROPERTY_UPDATE_MEASURE_SELF | PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
394     return flag;
395 }
396 
SetFontFamilies(const std::vector<std::string> & value)397 void TextContentModifier::SetFontFamilies(const std::vector<std::string>& value)
398 {
399     CHECK_NULL_VOID(fontFamilyString_);
400     fontFamilyString_->Set(V2::ConvertFontFamily(value));
401 }
402 
SetFontSize(const Dimension & value)403 void TextContentModifier::SetFontSize(const Dimension& value)
404 {
405     float fontSizeValue;
406     auto pipelineContext = PipelineContext::GetCurrentContext();
407     if (pipelineContext) {
408         fontSizeValue = pipelineContext->NormalizeToPx(value);
409     } else {
410         fontSizeValue = value.Value();
411     }
412     fontSize_ = Dimension(fontSizeValue);
413     CHECK_NULL_VOID(fontSizeFloat_);
414     fontSizeFloat_->Set(fontSizeValue);
415 }
416 
SetFontWeight(const FontWeight & value)417 void TextContentModifier::SetFontWeight(const FontWeight& value)
418 {
419     fontWeight_ = ConvertFontWeight(value);
420     CHECK_NULL_VOID(fontWeightFloat_);
421     fontWeightFloat_->Set(static_cast<int>(ConvertFontWeight(value)));
422 }
423 
SetTextColor(const Color & value)424 void TextContentModifier::SetTextColor(const Color& value)
425 {
426     textColor_ = value;
427     CHECK_NULL_VOID(animatableTextColor_);
428     animatableTextColor_->Set(LinearColor(value));
429 }
430 
SetTextShadow(const Shadow & value)431 void TextContentModifier::SetTextShadow(const Shadow& value)
432 {
433     textShadow_ = value;
434     CHECK_NULL_VOID(shadowBlurRadiusFloat_);
435     CHECK_NULL_VOID(shadowOffsetXFloat_);
436     CHECK_NULL_VOID(shadowOffsetYFloat_);
437     CHECK_NULL_VOID(shadowColor_);
438     shadowBlurRadiusFloat_->Set(value.GetBlurRadius());
439     shadowOffsetXFloat_->Set(value.GetOffset().GetX());
440     shadowOffsetYFloat_->Set(value.GetOffset().GetY());
441     shadowColor_->Set(LinearColor(value.GetColor()));
442 }
443 
SetTextDecoration(const TextDecoration & type)444 void TextContentModifier::SetTextDecoration(const TextDecoration& type)
445 {
446     auto oldTextDecoration = textDecoration_.value_or(TextDecoration::NONE);
447     if (oldTextDecoration == type) {
448         return;
449     }
450 
451     textDecorationAnimatable_ = (oldTextDecoration == TextDecoration::NONE && type == TextDecoration::UNDERLINE) ||
452         (oldTextDecoration == TextDecoration::UNDERLINE && type == TextDecoration::NONE);
453 
454     textDecoration_ = type;
455     CHECK_NULL_VOID(textDecorationColorAlpha_);
456 
457     oldColorAlpha_ = textDecorationColorAlpha_->Get();
458     if (textDecoration_ == TextDecoration::NONE) {
459         textDecorationColorAlpha_->Set(0.0f);
460     } else {
461         textDecorationColorAlpha_->Set(static_cast<float>(textDecorationColor_.value().GetAlpha()));
462     }
463 }
464 
SetTextDecorationColor(const Color & color)465 void TextContentModifier::SetTextDecorationColor(const Color& color)
466 {
467     textDecorationColor_ = color;
468 }
469 
SetBaselineOffset(const Dimension & value)470 void TextContentModifier::SetBaselineOffset(const Dimension& value)
471 {
472     float baselineOffsetValue;
473     auto pipelineContext = PipelineContext::GetCurrentContext();
474     if (pipelineContext) {
475         baselineOffsetValue = pipelineContext->NormalizeToPx(value);
476     } else {
477         baselineOffsetValue = value.Value();
478     }
479     baselineOffset_ = Dimension(baselineOffsetValue);
480     CHECK_NULL_VOID(baselineOffsetFloat_);
481     baselineOffsetFloat_->Set(baselineOffsetValue);
482 }
483 
SetContentOffset(OffsetF & value)484 void TextContentModifier::SetContentOffset(OffsetF& value)
485 {
486     CHECK_NULL_VOID(contentOffset_);
487     contentOffset_->Set(value);
488 }
489 
SetContentSize(SizeF & value)490 void TextContentModifier::SetContentSize(SizeF& value)
491 {
492     CHECK_NULL_VOID(contentSize_);
493     contentSize_->Set(value);
494 }
495 
StartTextRace()496 void TextContentModifier::StartTextRace()
497 {
498     if (textRacing_) {
499         return;
500     }
501 
502     textRacing_ = true;
503 
504     textRaceSpaceWidth_ = RACE_SPACE_WIDTH;
505     auto pipeline = PipelineContext::GetCurrentContext();
506     if (pipeline) {
507         textRaceSpaceWidth_ *= pipeline->GetDipScale();
508     }
509 
510     AnimationOption option = AnimationOption();
511     RefPtr<Curve> curve = AceType::MakeRefPtr<LinearCurve>();
512     option.SetDuration(RACE_DURATION);
513     option.SetDelay(0);
514     option.SetCurve(curve);
515     option.SetIteration(-1);
516     option.SetTempo(RACE_TEMPO);
517     raceAnimation_ = AnimationUtils::StartAnimation(option, [&]() { racePercentFloat_->Set(RACE_MOVE_PERCENT_MAX); });
518 }
519 
StopTextRace()520 void TextContentModifier::StopTextRace()
521 {
522     if (!textRacing_) {
523         return;
524     }
525 
526     if (raceAnimation_) {
527         AnimationUtils::StopAnimation(raceAnimation_);
528     }
529 
530     textRacing_ = false;
531     racePercentFloat_->Set(RACE_MOVE_PERCENT_MIN);
532 }
533 
GetTextRacePercent()534 float TextContentModifier::GetTextRacePercent()
535 {
536     float percent = 0;
537     if (racePercentFloat_) {
538         percent = racePercentFloat_->Get();
539     }
540     return percent;
541 }
542 
ContentChange()543 void TextContentModifier::ContentChange()
544 {
545     CHECK_NULL_VOID(contentChange_);
546     contentChange_->Set(!contentChange_->Get());
547 }
548 } // namespace OHOS::Ace::NG
549