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