• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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_paint_method.h"
17 
18 #include "core/components/common/properties/marquee_option.h"
19 #include "core/components_ng/pattern/text/text_pattern.h"
20 
21 namespace OHOS::Ace::NG {
22 
23 namespace {
24 constexpr Dimension DEFAULT_MARQUEE_STEP_VP = 4.0_vp;
25 } // namespace
26 
TextPaintMethod(const WeakPtr<Pattern> & pattern,float baselineOffset,RefPtr<TextContentModifier> textContentModifier,RefPtr<TextOverlayModifier> textOverlayModifier)27 TextPaintMethod::TextPaintMethod(const WeakPtr<Pattern>& pattern, float baselineOffset,
28     RefPtr<TextContentModifier> textContentModifier, RefPtr<TextOverlayModifier> textOverlayModifier)
29     : pattern_(pattern), baselineOffset_(baselineOffset),
30       textContentModifier_(std::move(textContentModifier)), textOverlayModifier_(std::move(textOverlayModifier))
31 {}
32 
GetContentModifier(PaintWrapper * paintWrapper)33 RefPtr<Modifier> TextPaintMethod::GetContentModifier(PaintWrapper* paintWrapper)
34 {
35     return textContentModifier_;
36 }
37 
DoStartTextRace()38 void TextPaintMethod::DoStartTextRace()
39 {
40     CHECK_NULL_VOID(textContentModifier_);
41 
42     auto textPattern = DynamicCast<TextPattern>(pattern_.Upgrade());
43     CHECK_NULL_VOID(textPattern);
44     auto frameNode = textPattern->GetHost();
45     CHECK_NULL_VOID(frameNode);
46     auto pManager = textPattern->GetParagraphManager();
47     CHECK_NULL_VOID(pManager);
48     auto layoutProperty = frameNode->GetLayoutProperty<TextLayoutProperty>();
49     CHECK_NULL_VOID(layoutProperty);
50     auto pipeline = PipelineContext::GetCurrentContext();
51     CHECK_NULL_VOID(pipeline);
52     auto theme = pipeline->GetTheme<TextTheme>();
53     CHECK_NULL_VOID(theme);
54     if (!layoutProperty->HasTextMarqueeFadeout()) {
55         layoutProperty->UpdateTextMarqueeFadeout(theme->GetIsTextFadeout());
56     }
57     if (!layoutProperty->HasTextMarqueeStartPolicy()) {
58         layoutProperty->UpdateTextMarqueeStartPolicy(theme->GetMarqueeStartPolicy());
59     }
60 
61     MarqueeOption option;
62     option.start = layoutProperty->GetTextMarqueeStart().value_or(true);
63     option.step = layoutProperty->GetTextMarqueeStep().value_or(DEFAULT_MARQUEE_STEP_VP.ConvertToPx());
64     if (GreatNotEqual(option.step, pManager->GetTextWidth())) {
65         option.step = DEFAULT_MARQUEE_STEP_VP.ConvertToPx();
66     }
67     option.loop = layoutProperty->GetTextMarqueeLoop().value_or(-1);
68     option.direction = layoutProperty->GetTextMarqueeDirection().value_or(MarqueeDirection::DEFAULT);
69     option.delay = layoutProperty->GetTextMarqueeDelay().value_or(0);
70     option.fadeout = layoutProperty->GetTextMarqueeFadeout().value_or(theme->GetIsTextFadeout());
71     option.startPolicy = layoutProperty->GetTextMarqueeStartPolicy().value_or(theme->GetMarqueeStartPolicy());
72 
73     textContentModifier_->StartTextRace(option);
74 }
75 
UpdateParagraphAndImageSpanNodeList()76 void TextPaintMethod::UpdateParagraphAndImageSpanNodeList()
77 {
78     CHECK_NULL_VOID(textContentModifier_);
79     auto textPattern = DynamicCast<TextPattern>(pattern_.Upgrade());
80     CHECK_NULL_VOID(textPattern);
81     textContentModifier_->SetImageSpanNodeList(textPattern->GetImageSpanNodeList());
82 }
83 
UpdateContentModifier(PaintWrapper * paintWrapper)84 void TextPaintMethod::UpdateContentModifier(PaintWrapper* paintWrapper)
85 {
86     CHECK_NULL_VOID(paintWrapper);
87     CHECK_NULL_VOID(textContentModifier_);
88     auto pattern = DynamicCast<TextPattern>(pattern_.Upgrade());
89     CHECK_NULL_VOID(pattern);
90     auto pManager = pattern->GetParagraphManager();
91     CHECK_NULL_VOID(pManager);
92     UpdateParagraphAndImageSpanNodeList();
93     SizeF contentSize = paintWrapper->GetContentSize();
94     textContentModifier_->SetContentSize(contentSize);
95     auto offset = paintWrapper->GetContentOffset();
96     textContentModifier_->SetContentOffset(offset);
97     auto paintOffset = offset - OffsetF(0.0, std::min(baselineOffset_, 0.0f));
98     textContentModifier_->SetPrintOffset(paintOffset);
99     pattern->SetPrintInfo("ContentOffset:", paintOffset);
100     auto frameNode = pattern->GetHost();
101     CHECK_NULL_VOID(frameNode);
102     auto layoutProperty = frameNode->GetLayoutProperty<TextLayoutProperty>();
103     CHECK_NULL_VOID(layoutProperty);
104     auto renderContext = frameNode->GetRenderContext();
105     CHECK_NULL_VOID(renderContext);
106     auto textOverflow = layoutProperty->GetTextOverflow();
107     if (textOverflow.has_value() && textOverflow.value() == TextOverflow::MARQUEE &&
108         pManager->GetLongestLine() > contentSize.Width()) {
109         DoStartTextRace();
110     } else {
111         textContentModifier_->StopTextRace();
112     }
113 
114     // Privacy masking.
115     auto reasons = renderContext->GetObscured().value_or(std::vector<ObscuredReasons>());
116     bool ifPaintObscuration = std::any_of(reasons.begin(), reasons.end(),
117         [](const auto& reason) { return reason == ObscuredReasons::PLACEHOLDER; });
118     if (ifPaintObscuration) {
119         UpdateObscuredRects();
120     } else {
121         textContentModifier_->SetIfPaintObscuration(false);
122     }
123 
124     if (renderContext->GetClipEdge().has_value()) {
125         textContentModifier_->SetClip(renderContext->GetClipEdge().value());
126     }
127 }
128 
UpdateObscuredRects()129 void TextPaintMethod::UpdateObscuredRects()
130 {
131     auto pattern = DynamicCast<TextPattern>(pattern_.Upgrade());
132     CHECK_NULL_VOID(pattern);
133     auto pManager = pattern->GetParagraphManager();
134     CHECK_NULL_VOID(pManager);
135 
136     auto spanItemChildren = pattern->GetSpanItemChildren();
137     auto ifPaintObscuration = spanItemChildren.empty() && pattern->IsEnabledObscured();
138     textContentModifier_->SetIfPaintObscuration(ifPaintObscuration);
139     CHECK_NULL_VOID(ifPaintObscuration);
140 
141     auto wideTextLength = pattern->GetDisplayWideTextLength();
142     std::vector<RectF> drawObscuredRects;
143     if (wideTextLength != 0 && ifPaintObscuration) {
144         drawObscuredRects = pManager->GetRects(0, wideTextLength);
145     }
146     textContentModifier_->SetDrawObscuredRects(drawObscuredRects);
147 }
148 
GetOverlayModifier(PaintWrapper * paintWrapper)149 RefPtr<Modifier> TextPaintMethod::GetOverlayModifier(PaintWrapper* paintWrapper)
150 {
151     return textOverlayModifier_;
152 }
153 
UpdateOverlayModifier(PaintWrapper * paintWrapper)154 void TextPaintMethod::UpdateOverlayModifier(PaintWrapper* paintWrapper)
155 {
156     CHECK_NULL_VOID(paintWrapper);
157     CHECK_NULL_VOID(textOverlayModifier_);
158 
159     auto textPattern = DynamicCast<TextPattern>(pattern_.Upgrade());
160     CHECK_NULL_VOID(textPattern);
161     auto pManager = textPattern->GetParagraphManager();
162     CHECK_NULL_VOID(pManager);
163 
164     auto offset = paintWrapper->GetContentOffset();
165     auto paintOffset = offset - OffsetF(0.0, std::min(baselineOffset_, 0.0f));
166     textOverlayModifier_->SetPrintOffset(paintOffset);
167     auto host = textPattern->GetHost();
168     CHECK_NULL_VOID(host);
169     auto context = host->GetRenderContext();
170     CHECK_NULL_VOID(context);
171     const auto& selection = textPattern->GetTextSelector();
172     auto contentRect = textPattern->GetTextContentRect();
173     std::vector<RectF> selectedRects;
174     if (selection.GetTextStart() != selection.GetTextEnd()) {
175         auto rects = pManager->GetTextBoxesForSelect(selection.GetTextStart(), selection.GetTextEnd());
176         selectedRects = CalculateSelectedRect(rects, contentRect.Width());
177     }
178     textOverlayModifier_->SetContentRect(contentRect);
179     textOverlayModifier_->SetShowSelect(textPattern->GetShowSelect());
180     textOverlayModifier_->SetSelectedRects(selectedRects);
181     auto pipelineContext = host->GetContext();
182     CHECK_NULL_VOID(pipelineContext);
183     auto themeManager = pipelineContext->GetThemeManager();
184     CHECK_NULL_VOID(themeManager);
185     auto theme = themeManager->GetTheme<TextTheme>(host->GetThemeScopeId());
186     CHECK_NULL_VOID(theme);
187     auto layoutProperty = host->GetLayoutProperty<TextLayoutProperty>();
188     CHECK_NULL_VOID(layoutProperty);
189     auto cursorColor = layoutProperty->GetCursorColorValue(theme->GetCaretColor());
190     textOverlayModifier_->SetCursorColor(cursorColor.GetValue());
191     auto selectedColor = layoutProperty->GetSelectedBackgroundColorValue(theme->GetSelectedColor());
192     textOverlayModifier_->SetSelectedColor(selectedColor.GetValue());
193     if (context->GetClipEdge().has_value()) {
194         textOverlayModifier_->SetIsClip(context->GetClipEdge().value());
195     }
196 }
197 
CalculateSelectedRect(const std::vector<std::pair<std::vector<RectF>,ParagraphStyle>> & selectedRects,float contentWidth)198 std::vector<RectF> TextPaintMethod::CalculateSelectedRect(
199     const std::vector<std::pair<std::vector<RectF>, ParagraphStyle>>& selectedRects, float contentWidth)
200 {
201     const float blankWidth = TextBase::GetSelectedBlankLineWidth();
202     std::vector<RectF> result;
203     float lastLineBottom = -1.0f;
204     for (const auto& info : selectedRects) {
205         auto rects = info.first;
206         TextBase::CalculateSelectedRectEx(rects, lastLineBottom, info.second.direction);
207         auto textAlign = TextBase::CheckTextAlignByDirection(info.second.align, info.second.direction);
208         for (auto& rect : rects) {
209             TextBase::UpdateSelectedBlankLineRect(rect, blankWidth, textAlign, contentWidth);
210         }
211         result.insert(result.end(), rects.begin(), rects.end());
212         if (!result.empty()) {
213             lastLineBottom = result.back().Bottom();
214         }
215     }
216     return result;
217 }
218 } // namespace OHOS::Ace::NG