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