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/render/adapter/gradient_style_modifier.h"
17 
18 #include "core/components_ng/render/adapter/rosen_render_context.h"
19 #ifndef USE_ROSEN_DRAWING
20 #include "core/components_ng/render/adapter/skia_decoration_painter.h"
21 #else
22 #include "core/components_ng/render/adapter/rosen/drawing_decoration_painter.h"
23 #endif
24 
25 namespace OHOS::Ace::NG {
26 namespace {
27 constexpr double MAX_COLOR_STOP = 100.0;
28 } // namespace
Draw(RSDrawingContext & context) const29 void GradientStyleModifier::Draw(RSDrawingContext& context) const
30 {
31     CHECK_NULL_VOID(colors_);
32     CHECK_NULL_VOID(colorStops_);
33     CHECK_NULL_VOID(sizeF_);
34 #ifndef USE_ROSEN_DRAWING
35     std::shared_ptr<SkCanvas> skCanvas { context.canvas, [](SkCanvas* /* unused */) {} };
36     SizeF contentSize(sizeF_->Get()[0], sizeF_->Get()[1]);
37     PaintGradient(*skCanvas, contentSize);
38 #else
39     CHECK_NULL_VOID(context.canvas);
40     SizeF contentSize(sizeF_->Get()[0], sizeF_->Get()[1]);
41     PaintGradient(*context.canvas, contentSize);
42 #endif
43 }
44 
45 #ifndef USE_ROSEN_DRAWING
PaintGradient(SkCanvas & canvas,const SizeF & frameSize) const46 void GradientStyleModifier::PaintGradient(SkCanvas& canvas, const SizeF& frameSize) const
47 {
48     if (Negative(frameSize.Height()) || Negative(frameSize.Width())) {
49         return;
50     }
51     auto shader = SkiaDecorationPainter::CreateGradientShader(GetGradient(), frameSize);
52     auto renderContext = renderContext_.Upgrade();
53     CHECK_NULL_VOID(renderContext);
54     if (!shader) {
55         renderContext->SetBackgroundShader(nullptr);
56         return;
57     }
58     renderContext->SetBackgroundShader(Rosen::RSShader::CreateRSShader(shader));
59 }
60 #else
PaintGradient(RSCanvas & canvas,const SizeF & frameSize) const61 void GradientStyleModifier::PaintGradient(RSCanvas& canvas, const SizeF& frameSize) const
62 {
63     if (Negative(frameSize.Height()) || Negative(frameSize.Width())) {
64         return;
65     }
66     auto shader = DrawingDecorationPainter::CreateGradientShader(GetGradient(), frameSize);
67     auto renderContext = renderContext_.Upgrade();
68     CHECK_NULL_VOID(renderContext);
69     if (!shader) {
70         renderContext->SetBackgroundShader(nullptr);
71         return;
72     }
73     renderContext->SetBackgroundShader(Rosen::RSShader::CreateRSShader(shader));
74 }
75 #endif
76 
GetGradient() const77 Gradient GradientStyleModifier::GetGradient() const
78 {
79     Gradient gradient;
80     std::vector<Color> colors = colors_->Get().GetColors();
81     std::vector<Dimension> stops = colorStops_->Get().GetColorStops();
82     if (gradient_) {
83         gradient = gradient_->Get();
84     }
85     auto size = colors.size();
86     gradient.ClearColors();
87     if (size > stops.size()) {
88         return gradient;
89     }
90     GradientColor color;
91     for (size_t index = 0; index < size; index++) {
92         color.SetColor(colors[index]);
93         auto colorStop =
94             stops[index].Value() > MAX_COLOR_STOP ? Dimension(MAX_COLOR_STOP, DimensionUnit::PERCENT) : stops[index];
95         color.SetDimension(colorStop);
96         gradient.AddColor(color);
97     }
98     return gradient;
99 }
100 
SetGradient(const Gradient & gradient)101 void GradientStyleModifier::SetGradient(const Gradient& gradient)
102 {
103     if (!colors_) {
104         colors_ = std::make_shared<Rosen::RSAnimatableProperty<ColorAnimatableArithmetic>>(
105             ColorAnimatableArithmetic(gradient));
106         AttachProperty(colors_);
107     } else {
108         auto colors = ColorAnimatableArithmetic(gradient);
109         PaddingColors(colors, gradient.GetRepeat());
110         colors_->Set(colors);
111     }
112     if (!colorStops_) {
113         colorStops_ = std::make_shared<Rosen::RSAnimatableProperty<ColorStopAnimatableArithmetic>>(
114             ColorStopAnimatableArithmetic(gradient));
115         AttachProperty(colorStops_);
116     } else {
117         auto colorStops = ColorStopAnimatableArithmetic(gradient);
118         PaddingColorStops(colorStops, gradient.GetRepeat());
119         colorStops_->Set(colorStops);
120     }
121     if (!gradient_) {
122         gradient_ = std::make_shared<Rosen::RSProperty<Gradient>>(gradient);
123         AttachProperty(gradient_);
124     } else {
125         gradient_->Set(gradient);
126     }
127 }
128 
PaddingColors(ColorAnimatableArithmetic & colors,bool repeat)129 void GradientStyleModifier::PaddingColors(ColorAnimatableArithmetic& colors, bool repeat)
130 {
131     if (repeat) {
132         return;
133     }
134     if (colors_->Get().GetColors().size() <= colors.GetColors().size()) {
135         return;
136     }
137     size_t paddingSize = colors_->Get().GetColors().size() - colors.GetColors().size();
138     colors.PaddingColors(paddingSize, Color::TRANSPARENT);
139 }
140 
PaddingColorStops(ColorStopAnimatableArithmetic & colorStops,bool repeat)141 void GradientStyleModifier::PaddingColorStops(ColorStopAnimatableArithmetic& colorStops, bool repeat)
142 {
143     if (repeat) {
144         return;
145     }
146     if (colorStops_->Get().GetColorStops().size() <= colorStops.GetColorStops().size()) {
147         return;
148     }
149     size_t paddingSize = colorStops_->Get().GetColorStops().size() - colorStops.GetColorStops().size();
150     colorStops.PaddingColorStops(paddingSize, Dimension(MAX_COLOR_STOP, DimensionUnit::PERCENT));
151 }
152 
SetSizeF(const SizeF & size)153 void GradientStyleModifier::SetSizeF(const SizeF& size)
154 {
155     if (!sizeF_) {
156         sizeF_ = std::make_shared<Rosen::RSAnimatableProperty<Rosen::Vector2f>>(
157             Rosen::Vector2f(size.Width(), size.Height()));
158         AttachProperty(sizeF_);
159     } else {
160         sizeF_->Set(Rosen::Vector2f(size.Width(), size.Height()));
161     }
162 }
163 
ColorAnimatableArithmetic(const Gradient & gradient)164 ColorAnimatableArithmetic::ColorAnimatableArithmetic(const Gradient& gradient)
165 {
166     for (const auto& color : gradient.GetColors()) {
167         colors_.push_back(color.GetColor());
168     }
169 }
170 
Add(const ColorAnimatableArithmetic & value) const171 ColorAnimatableArithmetic ColorAnimatableArithmetic::Add(const ColorAnimatableArithmetic& value) const
172 {
173     auto srcColorSize = colors_.size();
174     auto dstColorSize = value.colors_.size();
175     auto idealSize = std::min(srcColorSize, dstColorSize);
176 
177     ColorAnimatableArithmetic result;
178     size_t index = 0;
179     for (; index < idealSize; index++) {
180         Color color = Color::FromARGB(colors_[index].GetAlpha() + value.colors_[index].GetAlpha(),
181             colors_[index].GetRed() + value.colors_[index].GetRed(),
182             colors_[index].GetGreen() + value.colors_[index].GetGreen(),
183             colors_[index].GetBlue() + value.colors_[index].GetBlue());
184         result.colors_.push_back(color);
185     }
186     if (srcColorSize > dstColorSize) {
187         for (; index < srcColorSize; index++) {
188             result.colors_.push_back(colors_[index]);
189         }
190     } else {
191         for (; index < dstColorSize; index++) {
192             result.colors_.push_back(value.colors_[index]);
193         }
194     }
195     return result;
196 }
197 
Minus(const ColorAnimatableArithmetic & value) const198 ColorAnimatableArithmetic ColorAnimatableArithmetic::Minus(const ColorAnimatableArithmetic& value) const
199 {
200     auto srcColorSize = colors_.size();
201     auto dstColorSize = value.colors_.size();
202     auto idealSize = std::min(srcColorSize, dstColorSize);
203 
204     ColorAnimatableArithmetic result;
205     size_t index = 0;
206     for (; index < idealSize; index++) {
207         Color color = Color::FromARGB(colors_[index].GetAlpha() - value.colors_[index].GetAlpha(),
208             colors_[index].GetRed() - value.colors_[index].GetRed(),
209             colors_[index].GetGreen() - value.colors_[index].GetGreen(),
210             colors_[index].GetBlue() - value.colors_[index].GetBlue());
211         result.colors_.push_back(color);
212     }
213     if (srcColorSize > dstColorSize) {
214         for (; index < srcColorSize; index++) {
215             result.colors_.push_back(colors_[index]);
216         }
217     } else {
218         for (; index < dstColorSize; index++) {
219             result.colors_.push_back(value.colors_[index]);
220         }
221     }
222     return result;
223 }
224 
Multiply(const float scale) const225 ColorAnimatableArithmetic ColorAnimatableArithmetic::Multiply(const float scale) const
226 {
227     auto srcColorSize = colors_.size();
228     ColorAnimatableArithmetic result;
229     size_t index = 0;
230     for (; index < srcColorSize; index++) {
231         Color color = Color::FromARGB(colors_[index].GetAlpha() * scale, colors_[index].GetRed() * scale,
232             colors_[index].GetGreen() * scale, colors_[index].GetBlue() * scale);
233         result.colors_.push_back(color);
234     }
235     return result;
236 }
237 
IsEqual(const ColorAnimatableArithmetic & value) const238 bool ColorAnimatableArithmetic::IsEqual(const ColorAnimatableArithmetic& value) const
239 {
240     auto srcColorSize = colors_.size();
241     auto dstColorSize = value.colors_.size();
242     if (srcColorSize != dstColorSize) {
243         return false;
244     }
245     for (size_t index = 0; index < srcColorSize; index++) {
246         if (colors_[index] != value.colors_[index]) {
247             return false;
248         }
249     }
250     return true;
251 }
252 
ColorStopAnimatableArithmetic(const Gradient & gradient)253 ColorStopAnimatableArithmetic::ColorStopAnimatableArithmetic(const Gradient& gradient)
254 {
255     for (const auto& colorStop : gradient.GetColors()) {
256         colorStops_.push_back(colorStop.GetDimension());
257     }
258 }
259 
Add(const ColorStopAnimatableArithmetic & value) const260 ColorStopAnimatableArithmetic ColorStopAnimatableArithmetic::Add(const ColorStopAnimatableArithmetic& value) const
261 {
262     auto srcColorStopSize = colorStops_.size();
263     auto dstColorStopSize = value.colorStops_.size();
264     auto idealSize = std::min(srcColorStopSize, dstColorStopSize);
265 
266     ColorStopAnimatableArithmetic result;
267     size_t index = 0;
268     for (; index < idealSize; index++) {
269         auto colorStop = colorStops_[index].Value() + value.colorStops_[index].Value();
270         result.colorStops_.push_back(Dimension(colorStop, DimensionUnit::PERCENT));
271     }
272     if (srcColorStopSize > dstColorStopSize) {
273         for (; index < srcColorStopSize; index++) {
274             result.colorStops_.push_back(colorStops_[index]);
275         }
276     } else {
277         for (; index < dstColorStopSize; index++) {
278             result.colorStops_.push_back(value.colorStops_[index]);
279         }
280     }
281     return result;
282 }
283 
Minus(const ColorStopAnimatableArithmetic & value) const284 ColorStopAnimatableArithmetic ColorStopAnimatableArithmetic::Minus(const ColorStopAnimatableArithmetic& value) const
285 {
286     auto srcColorStopSize = colorStops_.size();
287     auto dstColorStopSize = value.colorStops_.size();
288     auto idealSize = std::min(srcColorStopSize, dstColorStopSize);
289 
290     ColorStopAnimatableArithmetic result;
291     size_t index = 0;
292     for (; index < idealSize; index++) {
293         auto colorStop = colorStops_[index].Value() - value.colorStops_[index].Value();
294         result.colorStops_.push_back(Dimension(colorStop, DimensionUnit::PERCENT));
295     }
296     if (srcColorStopSize > dstColorStopSize) {
297         for (; index < srcColorStopSize; index++) {
298             result.colorStops_.push_back(colorStops_[index]);
299         }
300     } else {
301         for (; index < dstColorStopSize; index++) {
302             result.colorStops_.push_back(value.colorStops_[index]);
303         }
304     }
305     return result;
306 }
307 
Multiply(const float scale) const308 ColorStopAnimatableArithmetic ColorStopAnimatableArithmetic::Multiply(const float scale) const
309 {
310     auto srcColorStopSize = colorStops_.size();
311 
312     ColorStopAnimatableArithmetic result;
313     for (size_t index = 0; index < srcColorStopSize; index++) {
314         auto colorStop = colorStops_[index].Value() * scale;
315         result.colorStops_.push_back(Dimension(colorStop, DimensionUnit::PERCENT));
316     }
317     return result;
318 }
319 
IsEqual(const ColorStopAnimatableArithmetic & value) const320 bool ColorStopAnimatableArithmetic::IsEqual(const ColorStopAnimatableArithmetic& value) const
321 {
322     auto srcColorStopSize = colorStops_.size();
323     auto dstColorStopSize = value.colorStops_.size();
324     if (srcColorStopSize != dstColorStopSize) {
325         return false;
326     }
327     for (size_t index = 0; index < srcColorStopSize; index++) {
328         if (!NearEqual(colorStops_[index].Value(), value.colorStops_[index].Value())) {
329             return false;
330         }
331     }
332     return true;
333 }
334 } // namespace OHOS::Ace::NG
335