1 /*
2 * Copyright (c) 2025 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 "rosen_text/symbol_gradient.h"
17 #include "utils/text_log.h"
18
19 namespace OHOS::Rosen {
20
SetColors(const std::vector<Drawing::ColorQuad> & colors)21 void SymbolGradient::SetColors(const std::vector<Drawing::ColorQuad>& colors)
22 {
23 colors_ = colors;
24 }
25
SetPositions(const std::vector<float> & positions)26 void SymbolGradient::SetPositions(const std::vector<float>& positions)
27 {
28 positions_ = positions;
29 }
30
SetTileMode(Drawing::TileMode tileMode)31 void SymbolGradient::SetTileMode(Drawing::TileMode tileMode)
32 {
33 tileMode_ = tileMode;
34 }
35
GetColors() const36 const std::vector<Drawing::ColorQuad>& SymbolGradient::GetColors() const
37 {
38 return colors_;
39 }
40
GetPositions() const41 const std::vector<float>& SymbolGradient::GetPositions() const
42 {
43 return positions_;
44 }
45
GetTileMode() const46 Drawing::TileMode SymbolGradient::GetTileMode() const
47 {
48 return tileMode_;
49 }
50
GetGradientType() const51 GradientType SymbolGradient::GetGradientType() const
52 {
53 return gradientType_;
54 }
55
CreateGradientBrush()56 Drawing::Brush SymbolGradient::CreateGradientBrush()
57 {
58 Drawing::Point offset;
59 return CreateGradientBrush(offset);
60 }
61
CreateGradientPen()62 Drawing::Pen SymbolGradient::CreateGradientPen()
63 {
64 Drawing::Point offset;
65 return CreateGradientPen(offset);
66 }
67
CreateGradientBrush(const Drawing::Point & offset)68 Drawing::Brush SymbolGradient::CreateGradientBrush(const Drawing::Point& offset)
69 {
70 Drawing::Brush brush;
71 brush.SetAntiAlias(true);
72 if (!colors_.empty()) {
73 brush.SetColor(colors_[0]);
74 }
75 return brush;
76 }
77
CreateGradientPen(const Drawing::Point & offset)78 Drawing::Pen SymbolGradient::CreateGradientPen(const Drawing::Point& offset)
79 {
80 Drawing::Pen pen;
81 pen.SetAntiAlias(true);
82 if (!colors_.empty()) {
83 pen.SetColor(colors_[0]);
84 }
85 return pen;
86 }
87
CreateGradientShader(const Drawing::Point & offset)88 std::shared_ptr<Drawing::ShaderEffect> SymbolGradient::CreateGradientShader(const Drawing::Point& offset)
89 {
90 return nullptr;
91 }
92
IsNearlyEqual(const std::shared_ptr<SymbolGradient> & gradient)93 bool SymbolGradient::IsNearlyEqual(const std::shared_ptr<SymbolGradient>& gradient)
94 {
95 if (gradient == nullptr) {
96 return false;
97 }
98 bool isUnequal = gradientType_ != gradient->GetGradientType() || tileMode_ != gradient->GetTileMode() ||
99 colors_.size() != gradient->GetColors().size() || positions_.size() != gradient->GetPositions().size();
100 if (isUnequal) {
101 return false;
102 }
103
104 auto colors = gradient->GetColors();
105 for (size_t i = 0; i < colors_.size(); i++) {
106 if (colors_[i] != colors[i]) {
107 return false;
108 }
109 }
110
111 auto positions = gradient->GetPositions();
112 for (size_t i = 0; i < positions_.size(); i++) {
113 if (ROSEN_NE<float>(positions_[i], positions[i])) {
114 return false;
115 }
116 }
117 return true;
118 }
119
SymbolLineGradient(float rangle)120 SymbolLineGradient::SymbolLineGradient(float rangle) : rangle_(rangle)
121 {
122 gradientType_ = GradientType::LINE_GRADIENT;
123 }
124
SetAngle(float rangle)125 void SymbolLineGradient::SetAngle(float rangle)
126 {
127 rangle_ = rangle;
128 }
129
GetAngle() const130 float SymbolLineGradient::GetAngle() const
131 {
132 return rangle_;
133 }
134
Make(const Drawing::Rect & bounds)135 void SymbolLineGradient::Make(const Drawing::Rect& bounds)
136 {
137 PointsFromAngle(rangle_, bounds, startPoint_, endPoint_);
138 startPoint_.Offset(bounds.GetLeft(), bounds.GetTop());
139 endPoint_.Offset(bounds.GetLeft(), bounds.GetTop());
140 }
141
CreateGradientBrush(const Drawing::Point & offset)142 Drawing::Brush SymbolLineGradient::CreateGradientBrush(const Drawing::Point& offset)
143 {
144 Drawing::Brush brush;
145 brush.SetAntiAlias(true);
146 auto shader = CreateGradientShader(offset);
147 if (shader == nullptr) {
148 return brush;
149 }
150 brush.SetShaderEffect(shader);
151 return brush;
152 }
153
CreateGradientPen(const Drawing::Point & offset)154 Drawing::Pen SymbolLineGradient::CreateGradientPen(const Drawing::Point& offset)
155 {
156 Drawing::Pen pen;
157 pen.SetAntiAlias(true);
158 auto shader = CreateGradientShader(offset);
159 if (shader == nullptr) {
160 return pen;
161 }
162 pen.SetShaderEffect(shader);
163 return pen;
164 }
165
CreateGradientShader(const Drawing::Point & offset)166 std::shared_ptr<Drawing::ShaderEffect> SymbolLineGradient::CreateGradientShader(const Drawing::Point& offset)
167 {
168 if (colors_.empty()) {
169 return nullptr;
170 }
171 auto startPoint = startPoint_;
172 auto endPoint = endPoint_;
173 startPoint.Offset(offset.GetX(), offset.GetY());
174 endPoint.Offset(offset.GetX(), offset.GetY());
175 return Drawing::ShaderEffect::CreateLinearGradient(startPoint, endPoint, colors_, positions_, tileMode_);
176 }
177
AngleToRadian(float angle)178 static float AngleToRadian(float angle)
179 {
180 return static_cast<float>(angle * PI / 180.0f); // 180.0f is used for converting angles to radians
181 }
182
PointsFromAngle(float angle,const Drawing::Rect & bounds,Drawing::Point & firstPoint,Drawing::Point & secondPoint)183 void SymbolLineGradient::PointsFromAngle(float angle, const Drawing::Rect& bounds,
184 Drawing::Point& firstPoint, Drawing::Point& secondPoint)
185 {
186 float width = bounds.GetWidth();
187 float height = bounds.GetHeight();
188 angle = fmod(angle, 360.0f); // 360.0f is maximum angle
189 if (ROSEN_LNE(angle, 0.0f)) {
190 angle += 360.0f;
191 }
192 firstPoint = Drawing::Point(0.0f, 0.0f);
193 secondPoint = Drawing::Point(0.0f, 0.0f);
194
195 // 0.0f 90.0f 180.0f 270.0f is the Angle on the coordinate axis
196 if (ROSEN_EQ<float>(angle, 0.0f)) {
197 firstPoint = Drawing::Point(0.0f, height);
198 return;
199 } else if (ROSEN_EQ<float>(angle, 90.0f)) {
200 secondPoint = Drawing::Point(width, 0.0f);
201 return;
202 } else if (ROSEN_EQ<float>(angle, 180.0f)) {
203 secondPoint = Drawing::Point(0.0f, height);
204 return;
205 } else if (ROSEN_EQ<float>(angle, 270.0f)) {
206 firstPoint = Drawing::Point(width, 0.0f);
207 return;
208 }
209 // The Angle is calculated clockwise from point 0
210 float slope = tan(AngleToRadian(90.0f - angle)); // Convert to Cartesian coordinates
211 float perpendicularSlope = ROSEN_NE<float>(slope, 0.0f) ? -1 / slope : 1.0f; // the slope will not be zero
212
213 float halfHeight = height / 2; // 2 is half
214 float halfWidth = width / 2; // 2 is half
215 Drawing::Point cornerPoint { 0.0f, 0.0f };
216 if (angle < 90.0f) { // 90.0f: the first term on the coordinate axis
217 cornerPoint = Drawing::Point(halfWidth, halfHeight);
218 } else if (angle < 180.0f) { // 180.0f: the second term on the coorinate axis
219 cornerPoint = Drawing::Point(halfWidth, -halfHeight);
220 } else if (angle < 270.0f) { // 270.0f: the third term on the coordinate axis
221 cornerPoint = Drawing::Point(-halfWidth, -halfHeight);
222 } else {
223 cornerPoint = Drawing::Point(-halfWidth, halfHeight);
224 }
225
226 // Compute b (of y = kx + b) using the corner point.
227 float b = cornerPoint.GetY() - perpendicularSlope * cornerPoint.GetX();
228 float endX = b / (slope - perpendicularSlope);
229 float endY = perpendicularSlope * endX + b;
230
231 secondPoint = Drawing::Point(halfWidth + endX, halfHeight - endY);
232 firstPoint = Drawing::Point(halfWidth - endX, halfHeight + endY);
233 }
234
235
SymbolRadialGradient(const Drawing::Point & centerPtRatio,float radiusRatio)236 SymbolRadialGradient::SymbolRadialGradient(const Drawing::Point& centerPtRatio, float radiusRatio)
237 : centerPtRatio_(centerPtRatio)
238 {
239 radiusRatio_ = std::max(radiusRatio, 0.0f);
240 gradientType_ = GradientType::RADIAL_GRADIENT;
241 }
242
SetCenterPoint(const Drawing::Point & centerPtRatio)243 void SymbolRadialGradient::SetCenterPoint(const Drawing::Point& centerPtRatio)
244 {
245 centerPtRatio_ = centerPtRatio;
246 }
247
SetRadiusRatio(float radiusRatio)248 void SymbolRadialGradient::SetRadiusRatio(float radiusRatio)
249 {
250 radiusRatio_ = std::max(radiusRatio, 0.0f);
251 isRadiusRatio_ = true;
252 }
253
SetRadius(float radius)254 void SymbolRadialGradient::SetRadius(float radius)
255 {
256 radius_ = std::max(radius, 0.0f);
257 isRadiusRatio_ = false;
258 }
259
GetCenterPoint() const260 Drawing::Point SymbolRadialGradient::GetCenterPoint() const
261 {
262 return centerPtRatio_;
263 }
264
GetRadius() const265 float SymbolRadialGradient::GetRadius() const
266 {
267 return radius_;
268 }
269
GetRadiusRatio() const270 float SymbolRadialGradient::GetRadiusRatio() const
271 {
272 return radiusRatio_;
273 }
274
IsRadiusRatio() const275 bool SymbolRadialGradient::IsRadiusRatio() const
276 {
277 return isRadiusRatio_;
278 }
279
Make(const Drawing::Rect & bounds)280 void SymbolRadialGradient::Make(const Drawing::Rect& bounds)
281 {
282 float left = bounds.GetLeft();
283 float top = bounds.GetTop();
284 float w = bounds.GetWidth();
285 float h = bounds.GetHeight();
286 float distance = std::sqrt(w * w + h * h);
287 if (isRadiusRatio_) {
288 radius_ = radiusRatio_ > 0 ? distance * radiusRatio_ : 0.0f;
289 } else {
290 radiusRatio_ = distance > 0 ? radius_ / distance : 0.0f;
291 }
292
293 w = w * centerPtRatio_.GetX();
294 h = h * centerPtRatio_.GetY();
295 centerPt_ = { left + w, top + h};
296 }
297
CreateGradientBrush(const Drawing::Point & offset)298 Drawing::Brush SymbolRadialGradient::CreateGradientBrush(const Drawing::Point& offset)
299 {
300 Drawing::Brush brush;
301 brush.SetAntiAlias(true);
302 auto shader = CreateGradientShader(offset);
303 if (shader == nullptr) {
304 return brush;
305 }
306 brush.SetShaderEffect(shader);
307 return brush;
308 }
309
CreateGradientPen(const Drawing::Point & offset)310 Drawing::Pen SymbolRadialGradient::CreateGradientPen(const Drawing::Point& offset)
311 {
312 Drawing::Pen pen;
313 pen.SetAntiAlias(true);
314 auto shader = CreateGradientShader(offset);
315 if (shader == nullptr) {
316 return pen;
317 }
318 pen.SetShaderEffect(shader);
319 return pen;
320 }
321
CreateGradientShader(const Drawing::Point & offset)322 std::shared_ptr<Drawing::ShaderEffect> SymbolRadialGradient::CreateGradientShader(const Drawing::Point& offset)
323 {
324 if (colors_.empty()) {
325 return nullptr;
326 }
327 auto centerPt = centerPt_;
328 centerPt.Offset(offset.GetX(), offset.GetY());
329 return Drawing::ShaderEffect::CreateRadialGradient(centerPt, radius_, colors_, positions_, tileMode_);
330 }
331 } // namespace OHOS::Rosen