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 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_RENDER_OVERLAY_MODIFIER_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_RENDER_OVERLAY_MODIFIER_H
18 
19 #include <memory>
20 #include <string>
21 
22 #include "modifier/rs_animatable_arithmetic.h"
23 #include "render_service_client/core/modifier/rs_extended_modifier.h"
24 #include "render_service_client/core/modifier/rs_property.h"
25 
26 #include "base/geometry/ng/offset_t.h"
27 #include "base/i18n/localization.h"
28 #include "base/memory/referenced.h"
29 #include "core/common/font_manager.h"
30 #include "core/components/common/properties/alignment.h"
31 #include "core/components_ng/property/overlay_property.h"
32 #include "core/components_ng/render/drawing.h"
33 #include "core/components_ng/render/drawing_prop_convertor.h"
34 #include "core/components_ng/render/font_collection.h"
35 #include "core/pipeline/pipeline_base.h"
36 
37 namespace OHOS::Ace::NG {
38 
39 class OverlayTextData : public Rosen::RSArithmetic<OverlayTextData> {
40 public:
41     OverlayTextData() = default;
OverlayTextData(const OverlayOptions & overlay)42     explicit OverlayTextData(const OverlayOptions& overlay) : overlay_(overlay) {}
43     ~OverlayTextData() override = default;
44 
IsEqual(const OverlayTextData & other)45     bool IsEqual(const OverlayTextData& other) const override
46     {
47         return overlay_ == other.overlay_;
48     }
49 
GetOverlayOptions()50     OverlayOptions GetOverlayOptions()
51     {
52         return overlay_;
53     }
54 
55 private:
56     OverlayOptions overlay_;
57 };
58 
59 class OverlayTextModifier : public Rosen::RSOverlayStyleModifier {
60 public:
61     OverlayTextModifier() = default;
62     ~OverlayTextModifier() override = default;
63 
Draw(Rosen::RSDrawingContext & context)64     void Draw(Rosen::RSDrawingContext& context) const override
65     {
66         CHECK_NULL_VOID(property_);
67         auto overlayOptions = property_->Get().GetOverlayOptions();
68         auto paragraph = GetParagraph(context.width);
69         CHECK_NULL_VOID(paragraph);
70 #ifndef USE_GRAPHIC_TEXT_GINE
71         OffsetF offset = OverlayTextModifier::GetTextPosition(SizeF(context.width, context.height),
72             SizeF(paragraph->GetLongestLine(), paragraph->GetHeight()), overlayOptions);
73 #else
74         OffsetF offset = OverlayTextModifier::GetTextPosition(SizeF(context.width, context.height),
75             SizeF(static_cast<float>(paragraph->GetActualWidth()), static_cast<float>(paragraph->GetHeight())),
76             overlayOptions);
77 #endif
78 #ifndef USE_ROSEN_DRAWING
79         std::shared_ptr<SkCanvas> skCanvas { context.canvas, [](SkCanvas*) {} };
80         RSCanvas canvas(&skCanvas);
81         CHECK_NULL_VOID(&canvas);
82         paragraph->Paint(&canvas, offset.GetX(), offset.GetY());
83 #else
84         CHECK_NULL_VOID(context.canvas);
85         paragraph->Paint(context.canvas, offset.GetX(), offset.GetY());
86 #endif
87     }
88 
GetParagraph(double contextWidth)89     std::unique_ptr<Rosen::Typography> GetParagraph(double contextWidth) const
90     {
91         CHECK_NULL_RETURN(property_, nullptr);
92         const Dimension fontSize = Dimension(40);
93         auto overlayOptions = property_->Get().GetOverlayOptions();
94         // create paragraph
95         TextStyle textStyle;
96         textStyle.SetFontSize(fontSize);
97         RSParagraphStyle paraStyle;
98 #ifndef USE_GRAPHIC_TEXT_GINE
99         paraStyle.textAlign_ = ToRSTextAlign(textStyle.GetTextAlign());
100         paraStyle.maxLines_ = textStyle.GetMaxLines();
101         paraStyle.locale_ = Localization::GetInstance()->GetFontLocale();
102         paraStyle.wordBreakType_ = ToRSWordBreakType(textStyle.GetWordBreak());
103         paraStyle.fontSize_ = fontSize.Value();
104         auto builder = RSParagraphBuilder::CreateRosenBuilder(paraStyle, RSFontCollection::GetInstance(false));
105 #else
106         paraStyle.textAlign = ToRSTextAlign(textStyle.GetTextAlign());
107         paraStyle.maxLines = textStyle.GetMaxLines();
108         paraStyle.locale = Localization::GetInstance()->GetFontLocale();
109         paraStyle.wordBreakType = ToRSWordBreakType(textStyle.GetWordBreak());
110         paraStyle.fontSize = fontSize.Value();
111         auto builder = RSParagraphBuilder::Create(paraStyle, RSFontCollection::Create());
112 #endif
113         CHECK_NULL_RETURN(builder, nullptr);
114         auto pipelineContext = PipelineBase::GetCurrentContext();
115         CHECK_NULL_RETURN(pipelineContext, nullptr);
116         builder->PushStyle(ToRSTextStyle(pipelineContext, textStyle));
117 #ifndef USE_GRAPHIC_TEXT_GINE
118         builder->AddText(StringUtils::Str8ToStr16(overlayOptions.content));
119         builder->Pop();
120         auto paragraph = builder->Build();
121 #else
122         builder->AppendText(StringUtils::Str8ToStr16(overlayOptions.content));
123         builder->PopStyle();
124         auto paragraph = builder->CreateTypography();
125 #endif
126         CHECK_NULL_RETURN(paragraph, nullptr);
127         paragraph->Layout(contextWidth);
128         return paragraph;
129     }
130 
GetParagraphSize(double contextWidth)131     SizeF GetParagraphSize(double contextWidth) const
132     {
133         auto paragraph = GetParagraph(contextWidth);
134         CHECK_NULL_RETURN(paragraph, SizeF());
135         return SizeF(static_cast<float>(paragraph->GetActualWidth()), static_cast<float>(paragraph->GetHeight()));
136     }
137 
SetCustomData(const OverlayTextData & data)138     void SetCustomData(const OverlayTextData& data)
139     {
140         if (!property_) {
141             property_ = std::make_shared<Rosen::RSProperty<OverlayTextData>>(data);
142             AttachProperty(property_);
143         } else {
144             property_->Set(data);
145         }
146     }
147 
GetOverlayOffset()148     OffsetF GetOverlayOffset()
149     {
150         OffsetF overlayOffset;
151         if (property_) {
152             auto overlayOptions = property_->Get().GetOverlayOptions();
153             auto dx = overlayOptions.x.ConvertToPx();
154             auto dy = overlayOptions.y.ConvertToPx();
155             overlayOffset = OffsetF(dx, dy);
156         }
157         return overlayOffset;
158     }
159 
IsCustomFont()160     bool IsCustomFont()
161     {
162         auto pipelineContext = PipelineBase::GetCurrentContext();
163         CHECK_NULL_RETURN(pipelineContext, false);
164         auto fontManager = pipelineContext->GetFontManager();
165         CHECK_NULL_RETURN(fontManager, false);
166         return fontManager->IsDefaultFontChanged();
167     }
168 
169 private:
GetTextPosition(const SizeF & parentSize,const SizeF & childSize,OverlayOptions & overlay)170     static OffsetF GetTextPosition(const SizeF& parentSize, const SizeF& childSize, OverlayOptions& overlay)
171     {
172         const double dx = overlay.x.ConvertToPx();
173         const double dy = overlay.y.ConvertToPx();
174         const Alignment align = overlay.align;
175         OffsetF const offset = Alignment::GetAlignPosition(parentSize, childSize, align);
176         const float fx = static_cast<float>(dx) + offset.GetX();
177         const float fy = static_cast<float>(dy) + offset.GetY();
178         return { fx, fy };
179     }
180 
181     std::shared_ptr<Rosen::RSProperty<OverlayTextData>> property_;
182 };
183 
184 } // namespace OHOS::Ace::NG
185 
186 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_RENDER_OVERLAY_MODIFIER_H
187