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