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_GRADIENT_PROPERTY_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_GRADIENT_PROPERTY_H
18 
19 #include <array>
20 #include <memory>
21 #include <optional>
22 #include <regex>
23 #include <vector>
24 
25 #include "base/geometry/dimension.h"
26 #include "base/geometry/ng/offset_t.h"
27 #include "base/json/json_util.h"
28 #include "base/log/log.h"
29 #include "base/memory/ace_type.h"
30 #include "base/utils/macros.h"
31 #include "base/utils/utils.h"
32 #include "core/components/common/properties/color.h"
33 
34 namespace OHOS::Ace::NG {
35 
36 constexpr float BOX_END_SIZE = 100.0f;
37 
38 enum class GradientDirection {
39     LEFT = 0,
40     TOP,
41     RIGHT,
42     BOTTOM,
43     LEFT_TOP,
44     LEFT_BOTTOM,
45     RIGHT_TOP,
46     RIGHT_BOTTOM,
47     NONE,
48     START_TO_END,
49     END_TO_START,
50 };
51 
52 enum class GradientType {
53     LINEAR,
54     RADIAL,
55     SWEEP,
56     CONIC,
57 };
58 
59 enum class RadialSizeType {
60     CLOSEST_SIDE,
61     CLOSEST_CORNER,
62     FARTHEST_SIDE,
63     FARTHEST_CORNER,
64     NONE,
65 };
66 
67 enum class RadialShapeType {
68     CIRCLE,
69     ELLIPSE,
70     NONE,
71 };
72 
73 enum class SpreadMethod {
74     PAD,
75     REFLECT,
76     REPEAT,
77 };
78 
79 struct LinearGradientInfo {
80     float x1 = 0.0f;
81     float x2 = 0.0f;
82     float y1 = 0.0f;
83     float y2 = 0.0f;
84     bool operator==(const LinearGradientInfo& other) const
85     {
86         return (
87             NearEqual(x1, other.x1) && NearEqual(x2, other.x2) && NearEqual(y1, other.y1) && NearEqual(y2, other.y2));
88     }
89 };
90 
91 struct RadialGradientInfo {
92     float r = 0.0f;
93     float cx = 0.0f;
94     float cy = 0.0f;
95     float fx = 0.0f;
96     float fy = 0.0f;
97     bool operator==(const RadialGradientInfo& other) const
98     {
99         return (NearEqual(r, other.r) && NearEqual(cx, other.cx) && NearEqual(cy, other.cy) &&
100                 NearEqual(fx, other.fx) && NearEqual(fy, other.fy));
101     }
102 };
103 
104 class GradientColor final {
105 public:
106     GradientColor() = default;
107     ~GradientColor() = default;
108 
GradientColor(const Color & color)109     explicit GradientColor(const Color& color)
110     {
111         color_ = color;
112     }
113 
114     void SetDimension(double value, DimensionUnit unit = DimensionUnit::PERCENT)
115     {
116         if (value < 0.0) {
117             return;
118         }
119         if (unit == DimensionUnit::PERCENT && value > BOX_END_SIZE) {
120             return;
121         }
122         dimension_ = Dimension(value, unit);
123     }
124 
SetDimension(const Dimension & dimension)125     void SetDimension(const Dimension& dimension)
126     {
127         if (dimension.Value() < 0.0) {
128             return;
129         }
130         if (dimension.Unit() == DimensionUnit::PERCENT && dimension.Value() > BOX_END_SIZE) {
131             return;
132         }
133         dimension_ = dimension;
134     }
135 
SetHasValue(bool hasValue)136     void SetHasValue(bool hasValue)
137     {
138         hasValue_ = hasValue;
139     }
140 
SetColor(const Color & color)141     void SetColor(const Color& color)
142     {
143         color_ = color;
144     }
145 
GetColor()146     const Color& GetColor() const
147     {
148         return color_;
149     }
150 
SetLinearColor(const LinearColor & linearColor)151     void SetLinearColor(const LinearColor& linearColor)
152     {
153         linearColor_ = linearColor;
154     }
155 
GetLinearColor()156     const LinearColor& GetLinearColor() const
157     {
158         return linearColor_;
159     }
160 
GetDimension()161     const Dimension& GetDimension() const
162     {
163         return dimension_;
164     }
165 
GetHasValue()166     bool GetHasValue() const
167     {
168         return hasValue_;
169     }
170 
SetOpacity(double opacity)171     void SetOpacity(double opacity)
172     {
173         opacity_ = opacity;
174     }
175 
GetOpacity()176     double GetOpacity() const
177     {
178         return opacity_;
179     }
180 
181     bool operator==(const GradientColor& other) const
182     {
183         return (hasValue_ == other.GetHasValue() && color_ == other.GetColor() && dimension_ == other.GetDimension() &&
184                 opacity_ == other.GetOpacity() && linearColor_ == other.GetLinearColor());
185     }
186 
187 private:
188     bool hasValue_ = true;
189     Color color_ { Color::TRANSPARENT };
190     LinearColor linearColor_ { LinearColor::TRANSPARENT };
191     Dimension dimension_ { BOX_END_SIZE, DimensionUnit::PERCENT };
192     float opacity_ = 1.0f;
193 };
194 
195 struct ACE_EXPORT RadialGradient {
196     // size type
197     std::optional<RadialSizeType> radialSizeType;
198     // shape circle or ellipse
199     std::optional<RadialShapeType> radialShape;
200     // size in x-axis
201     std::optional<Dimension> radialHorizontalSize;
202     // size in y-axis
203     std::optional<Dimension> radialVerticalSize;
204     // center of shape
205     std::optional<Dimension> radialCenterX;
206     std::optional<Dimension> radialCenterY;
207 
208     std::optional<Dimension> fRadialCenterX;
209     std::optional<Dimension> fRadialCenterY;
210 
211     bool operator==(const RadialGradient& other) const
212     {
213         return (radialSizeType == other.radialSizeType && radialShape == other.radialShape &&
214                 radialHorizontalSize == other.radialHorizontalSize && radialVerticalSize == other.radialVerticalSize &&
215                 radialCenterX == other.radialCenterX && radialCenterY == other.radialCenterY &&
216                 fRadialCenterX == other.fRadialCenterX && fRadialCenterY == other.fRadialCenterY);
217     }
218 };
219 
220 struct ACE_EXPORT LinearGradient {
221     // direction in x-axis
222     std::optional<GradientDirection> linearX;
223     // direction in y-axis
224     std::optional<GradientDirection> linearY;
225     // angle of gradient line in bearing angle
226     std::optional<Dimension> angle;
227 
228     std::optional<Dimension> x1;
229     std::optional<Dimension> y1;
230     std::optional<Dimension> x2;
231     std::optional<Dimension> y2;
232 
233     // is direction in x-axis
IsXAxisLinearGradient234     static bool IsXAxis(GradientDirection direction)
235     {
236         return (direction == GradientDirection::LEFT || direction == GradientDirection::RIGHT ||
237                 direction == GradientDirection::START_TO_END || direction == GradientDirection::END_TO_START);
238     }
239 
240     bool operator==(const LinearGradient& other) const
241     {
242         return (x1 == other.x1 && y1 == other.y1 && x2 == other.x2 && y2 == other.y2 && linearX == other.linearX &&
243                 linearY == other.linearY && angle == other.angle);
244     }
245 };
246 
247 struct ACE_EXPORT SweepGradient {
248     // center of x-axis
249     std::optional<Dimension> centerX;
250     // center of y-axis
251     std::optional<Dimension> centerY;
252     // startAngle in degree
253     std::optional<Dimension> startAngle;
254     // endAngle in degree
255     std::optional<Dimension> endAngle;
256     // rotation in degree
257     std::optional<Dimension> rotation;
258 
259     bool operator==(const OHOS::Ace::NG::SweepGradient& other) const
260     {
261         return (centerX == other.centerX && centerY == other.centerY && startAngle == other.startAngle &&
262                 endAngle == other.endAngle && rotation == other.rotation);
263     }
264 };
265 
266 class ACE_FORCE_EXPORT Gradient final {
267 public:
268     void AddColor(const GradientColor& color);
269 
270     void ClearColors();
271 
IsSweepGradientValid()272     bool IsSweepGradientValid() const
273     {
274         if (sweepGradient_->startAngle.has_value() && sweepGradient_->endAngle.has_value()) {
275             return LessOrEqual(sweepGradient_->startAngle.value().Value(), sweepGradient_->endAngle.value().Value());
276         }
277         if (sweepGradient_->startAngle.has_value() && !sweepGradient_->endAngle.has_value()) {
278             return LessOrEqual(sweepGradient_->startAngle.value().Value(), 0.0);
279         }
280         if (!sweepGradient_->startAngle.has_value() && sweepGradient_->endAngle.has_value()) {
281             return LessOrEqual(0.0, sweepGradient_->endAngle.value().Value());
282         }
283         return true;
284     }
285 
IsValid()286     bool IsValid() const
287     {
288         if (GetType() == GradientType::SWEEP) {
289             return IsSweepGradientValid() && colors_.size() > 1;
290         }
291         return colors_.size() > 1;
292     }
293 
SetRepeat(bool repeat)294     void SetRepeat(bool repeat)
295     {
296         repeat_ = repeat;
297     }
298 
GetRepeat()299     bool GetRepeat() const
300     {
301         return repeat_;
302     }
303 
GetColors()304     const std::vector<GradientColor>& GetColors() const
305     {
306         return colors_;
307     }
308 
GetBeginOffset()309     const std::shared_ptr<OffsetF>& GetBeginOffset() const
310     {
311         return beginOffset_;
312     }
313 
SetBeginOffset(const OffsetF & beginOffset)314     void SetBeginOffset(const OffsetF& beginOffset)
315     {
316         beginOffset_ = std::make_shared<OffsetF>(beginOffset);
317     }
318 
GetEndOffset()319     const std::shared_ptr<OffsetF>& GetEndOffset() const
320     {
321         return endOffset_;
322     }
323 
SetEndOffset(const OffsetF & endOffset)324     void SetEndOffset(const OffsetF& endOffset)
325     {
326         endOffset_ = std::make_shared<OffsetF>(endOffset);
327     }
328 
GetInnerRadius()329     double GetInnerRadius() const
330     {
331         return innerRadius_;
332     }
333 
SetInnerRadius(double innerRadius)334     void SetInnerRadius(double innerRadius)
335     {
336         innerRadius_ = innerRadius;
337     }
338 
GetOuterRadius()339     double GetOuterRadius() const
340     {
341         return outerRadius_;
342     }
343 
SetOuterRadius(double outerRadius)344     void SetOuterRadius(double outerRadius)
345     {
346         outerRadius_ = outerRadius;
347     }
348 
GetType()349     GradientType GetType() const
350     {
351         return type_;
352     }
353 
CreateGradientWithType(GradientType type)354     void CreateGradientWithType(GradientType type)
355     {
356         type_ = type;
357         switch (type_) {
358             case GradientType::LINEAR:
359                 linearGradient_ = std::make_shared<LinearGradient>();
360                 break;
361             case GradientType::RADIAL:
362                 radialGradient_ = std::make_shared<RadialGradient>();
363                 break;
364             case GradientType::SWEEP:
365                 sweepGradient_ = std::make_shared<SweepGradient>();
366                 break;
367             default:
368                 LOGE("GradientType not supported");
369         }
370     }
371 
ToString()372     std::string ToString() const
373     {
374         return std::string("Gradient (")
375             .append(beginOffset_->ToString())
376             .append(",")
377             .append(std::to_string(innerRadius_))
378             .append(" --- ")
379             .append(endOffset_->ToString())
380             .append(",")
381             .append(std::to_string(outerRadius_))
382             .append(")");
383     }
384 
GetSweepGradient()385     std::shared_ptr<SweepGradient> GetSweepGradient()
386     {
387         return sweepGradient_;
388     }
389 
GetSweepGradient()390     const std::shared_ptr<SweepGradient> GetSweepGradient() const
391     {
392         return sweepGradient_;
393     }
394 
SetSweepGradient(const SweepGradient & sweepGradient)395     void SetSweepGradient(const SweepGradient& sweepGradient)
396     {
397         sweepGradient_ = std::make_shared<SweepGradient>(sweepGradient);
398     }
399 
GetRadialGradient()400     std::shared_ptr<RadialGradient>& GetRadialGradient()
401     {
402         return radialGradient_;
403     }
404 
GetRadialGradient()405     const std::shared_ptr<RadialGradient>& GetRadialGradient() const
406     {
407         return radialGradient_;
408     }
409 
SetRadialGradient(const RadialGradient & radialGradient)410     void SetRadialGradient(const RadialGradient& radialGradient)
411     {
412         radialGradient_ = std::make_shared<RadialGradient>(radialGradient);
413     }
414 
GetLinearGradient()415     std::shared_ptr<LinearGradient>& GetLinearGradient()
416     {
417         return linearGradient_;
418     }
419 
GetLinearGradient()420     const std::shared_ptr<LinearGradient>& GetLinearGradient() const
421     {
422         return linearGradient_;
423     }
424 
SetLinearGradient(const LinearGradient & linearGradient)425     void SetLinearGradient(const LinearGradient& linearGradient)
426     {
427         linearGradient_ = std::make_shared<LinearGradient>(linearGradient);
428     }
429 
SetDirection(const GradientDirection & direction)430     void SetDirection(const GradientDirection& direction)
431     {
432         if (LinearGradient::IsXAxis(direction)) {
433             linearGradient_->linearX = direction;
434         } else {
435             linearGradient_->linearY = direction;
436         }
437     }
438 
SetSpreadMethod(SpreadMethod spreadMethod)439     void SetSpreadMethod(SpreadMethod spreadMethod)
440     {
441         spreadMethod_ = spreadMethod;
442     }
443 
SetGradientTransform(const std::string & gradientTransform)444     void SetGradientTransform(const std::string& gradientTransform)
445     {
446         gradientTransform_ = gradientTransform;
447     }
448 
GetSpreadMethod()449     SpreadMethod GetSpreadMethod() const
450     {
451         return spreadMethod_;
452     }
453 
GetGradientTransform()454     const std::string& GetGradientTransform() const
455     {
456         return gradientTransform_;
457     }
458 
GetRadialGradientInfo()459     const std::shared_ptr<RadialGradientInfo>& GetRadialGradientInfo() const
460     {
461         return radialGradientInfo_;
462     }
463 
SetRadialGradientInfo(const RadialGradientInfo & radialGradientInfo)464     void SetRadialGradientInfo(const RadialGradientInfo& radialGradientInfo)
465     {
466         radialGradientInfo_ = std::make_shared<RadialGradientInfo>(radialGradientInfo);
467     }
468 
GetLinearGradientInfo()469     const std::shared_ptr<LinearGradientInfo> GetLinearGradientInfo() const
470     {
471         return linearGradientInfo_;
472     }
473 
SetLinearGradientInfo(const LinearGradientInfo & linearGradientInfo)474     void SetLinearGradientInfo(const LinearGradientInfo& linearGradientInfo)
475     {
476         linearGradientInfo_ = std::make_shared<LinearGradientInfo>(linearGradientInfo);
477     }
478 
479     bool operator==(const Gradient& other) const
480     {
481         return (type_ == other.GetType() && repeat_ == other.GetRepeat() && colors_ == other.GetColors() &&
482                 radialGradient_ == other.GetRadialGradient() && linearGradient_ == other.GetLinearGradient() &&
483                 sweepGradient_ == other.GetSweepGradient() && beginOffset_ == other.GetBeginOffset() &&
484                 endOffset_ == other.GetEndOffset() && spreadMethod_ == other.GetSpreadMethod() &&
485                 gradientTransform_ == other.GetGradientTransform() &&
486                 linearGradientInfo_ == other.GetLinearGradientInfo() &&
487                 radialGradientInfo_ == other.GetRadialGradientInfo());
488     }
489 
490     bool operator!=(const Gradient& other) const
491     {
492         return !(*this == other);
493     }
494 
495     std::unique_ptr<JsonValue> LinearGradientToJson() const;
496     std::unique_ptr<JsonValue> SweepGradientToJson() const;
497     std::unique_ptr<JsonValue> RadialGradientToJson() const;
498 
499 private:
500     GradientType type_ = GradientType::LINEAR;
501     bool repeat_ = false;
502     std::vector<GradientColor> colors_;
503     // for RadialGradient
504     std::shared_ptr<RadialGradient> radialGradient_;
505     // for LinearGradient
506     std::shared_ptr<LinearGradient> linearGradient_;
507     // for SweepGradient
508     std::shared_ptr<SweepGradient> sweepGradient_;
509     // used for CanvasLinearGradient
510     std::shared_ptr<OffsetF> beginOffset_;
511     std::shared_ptr<OffsetF> endOffset_;
512     // used for CanvasRadialGradient
513     float innerRadius_ = 0.0f;
514     float outerRadius_ = 0.0;
515     SpreadMethod spreadMethod_ = SpreadMethod::PAD;
516     std::string gradientTransform_;
517     std::shared_ptr<LinearGradientInfo> linearGradientInfo_;
518     std::shared_ptr<RadialGradientInfo> radialGradientInfo_;
519 };
520 
521 
522 class LinearGradientBlurPara final {
523 public:
524     Dimension blurRadius_;
525     std::vector<std::pair<float, float>> fractionStops_;
526     GradientDirection direction_;
527 
LinearGradientBlurPara(const Dimension blurRadius,const std::vector<std::pair<float,float>> fractionStops,const GradientDirection direction)528     LinearGradientBlurPara(const Dimension blurRadius,
529         const std::vector<std::pair<float, float>>fractionStops, const GradientDirection direction)
530         : blurRadius_(blurRadius), fractionStops_(fractionStops), direction_(direction) {}
531     bool operator==(const LinearGradientBlurPara& other) const
532     {
533         return NearEqual(blurRadius_, other.blurRadius_) && NearEqual(fractionStops_, other.fractionStops_) &&
534                                                             NearEqual(direction_, other.direction_);
535     }
536 
537     ~LinearGradientBlurPara() = default;
538 };
539 
540 class MagnifierParams final {
541 public:
542     float factor_ = 0.f;
543     float width_ = 0.f;
544     float height_ = 0.f;
545     float borderWidth_ = 0.f;
546     float cornerRadius_ = 0.f;
547     float offsetX_ = 0.f;
548     float offsetY_ = 0.f;
549 
550     float shadowOffsetX_ = 0.f;
551     float shadowOffsetY_ = 0.f;
552     float shadowSize_ = 0.f;
553     float shadowStrength_ = 0.f;
554 
555     // rgba
556     uint32_t gradientMaskColor1_ = 0x00000000;
557     uint32_t gradientMaskColor2_ = 0x00000000;
558     uint32_t outerContourColor1_ = 0x00000000;
559     uint32_t outerContourColor2_ = 0x00000000;
560 
561     bool operator==(const MagnifierParams& other) const
562     {
563         return NearEqual(factor_, other.factor_) && NearEqual(width_, other.width_) &&
564                NearEqual(height_, other.height_) && NearEqual(borderWidth_, other.borderWidth_) &&
565                NearEqual(cornerRadius_, other.cornerRadius_) && NearEqual(offsetX_, other.offsetX_) &&
566                NearEqual(offsetY_, other.offsetY_) && NearEqual(shadowOffsetX_, other.shadowOffsetX_) &&
567                NearEqual(shadowOffsetY_, other.shadowOffsetY_) && NearEqual(shadowSize_, other.shadowSize_) &&
568                NearEqual(shadowStrength_, other.shadowStrength_) &&
569                NearEqual(gradientMaskColor1_, other.gradientMaskColor1_) &&
570                NearEqual(gradientMaskColor2_, other.gradientMaskColor2_) &&
571                NearEqual(outerContourColor1_, other.outerContourColor1_) &&
572                NearEqual(outerContourColor2_, other.outerContourColor2_);
573     }
574     MagnifierParams() = default;
575     ~MagnifierParams() = default;
576 };
577 } // namespace OHOS::Ace::NG
578 
579 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_GRADIENT_PROPERTY_H