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 "render/rs_border.h"
17
18 #ifndef USE_ROSEN_DRAWING
19 #include "include/core/SkCanvas.h"
20 #include "include/core/SkPaint.h"
21 #include "include/effects/Sk1DPathEffect.h"
22 #include "include/effects/SkDashPathEffect.h"
23 #else
24 #include "draw/path.h"
25 #endif
26 #include "platform/common/rs_log.h"
27
28 namespace OHOS {
29 namespace Rosen {
30 namespace {
31 constexpr int PARAM_DOUBLE = 2;
32 constexpr int32_t DASHED_LINE_LENGTH = 3;
33 constexpr float TOP_START = 225.0f;
34 constexpr float TOP_END = 270.0f;
35 constexpr float RIGHT_START = 315.0f;
36 constexpr float RIGHT_END = 0.0f;
37 constexpr float BOTTOM_START = 45.0f;
38 constexpr float BOTTOM_END = 90.0f;
39 constexpr float LEFT_START = 135.0f;
40 constexpr float LEFT_END = 180.0f;
41 constexpr float SWEEP_ANGLE = 45.0f;
42 constexpr float EXTEND = 1024.0f;
43 } // namespace
44
SetColor(Color color)45 void RSBorder::SetColor(Color color)
46 {
47 colors_.clear();
48 colors_.push_back(color);
49 }
50
SetWidth(float width)51 void RSBorder::SetWidth(float width)
52 {
53 widths_.clear();
54 widths_.push_back(width);
55 }
56
SetStyle(BorderStyle style)57 void RSBorder::SetStyle(BorderStyle style)
58 {
59 styles_.clear();
60 styles_.push_back(style);
61 }
62
GetColor(int idx) const63 Color RSBorder::GetColor(int idx) const
64 {
65 if (colors_.empty()) {
66 return RgbPalette::Transparent();
67 } else if (colors_.size() == 1) {
68 return colors_.front();
69 } else {
70 return colors_.at(idx);
71 }
72 }
73
GetWidth(int idx) const74 float RSBorder::GetWidth(int idx) const
75 {
76 if (widths_.empty()) {
77 return 0.f;
78 } else if (widths_.size() == 1) {
79 return widths_.front();
80 } else {
81 return widths_.at(idx);
82 }
83 }
84
GetStyle(int idx) const85 BorderStyle RSBorder::GetStyle(int idx) const
86 {
87 if (styles_.empty()) {
88 return BorderStyle::NONE;
89 } else if (styles_.size() == 1) {
90 return styles_.front();
91 } else {
92 return styles_.at(idx);
93 }
94 }
95
SetColorFour(Vector4<Color> color)96 void RSBorder::SetColorFour(Vector4<Color> color)
97 {
98 if (color.x_ == color.y_ && color.x_ == color.z_ && color.x_ == color.w_) {
99 return SetColor(color.x_);
100 }
101 colors_ = { color.x_, color.y_, color.z_, color.w_ };
102 }
103
SetWidthFour(Vector4f width)104 void RSBorder::SetWidthFour(Vector4f width)
105 {
106 if (width.x_ == width.y_ && width.x_ == width.z_ && width.x_ == width.w_) {
107 return SetWidth(width.x_);
108 }
109 widths_ = { width.x_, width.y_, width.z_, width.w_ };
110 }
111
SetStyleFour(Vector4<uint32_t> style)112 void RSBorder::SetStyleFour(Vector4<uint32_t> style)
113 {
114 if (style.x_ == style.y_ && style.x_ == style.z_ && style.x_ == style.w_) {
115 return SetStyle(static_cast<BorderStyle>(style.x_));
116 }
117 styles_ = { static_cast<BorderStyle>(style.x_), static_cast<BorderStyle>(style.y_),
118 static_cast<BorderStyle>(style.z_), static_cast<BorderStyle>(style.w_) };
119 }
120
GetColorFour() const121 Vector4<Color> RSBorder::GetColorFour() const
122 {
123 if (colors_.size() == 4) {
124 return Vector4<Color>(colors_[0], colors_[1], colors_[2], colors_[3]);
125 } else {
126 return Vector4<Color>(GetColor());
127 }
128 }
129
GetWidthFour() const130 Vector4f RSBorder::GetWidthFour() const
131 {
132 if (widths_.size() == 4) {
133 return Vector4f(widths_[0], widths_[1], widths_[2], widths_[3]);
134 } else {
135 return Vector4f(GetWidth());
136 }
137 }
138
GetStyleFour() const139 Vector4<uint32_t> RSBorder::GetStyleFour() const
140 {
141 if (styles_.size() == 4) {
142 return Vector4<uint32_t>(static_cast<uint32_t>(styles_[0]), static_cast<uint32_t>(styles_[1]),
143 static_cast<uint32_t>(styles_[2]), static_cast<uint32_t>(styles_[3]));
144 } else {
145 return Vector4<uint32_t>(static_cast<uint32_t>(GetStyle()));
146 }
147 }
148
149 #ifndef USE_ROSEN_DRAWING
SetBorderEffect(SkPaint & paint,BorderStyle style,float width,float spaceBetweenDot,float borderLength)150 void SetBorderEffect(SkPaint& paint, BorderStyle style, float width, float spaceBetweenDot, float borderLength)
151 #else
152 void SetBorderEffect(Drawing::Pen& pen, BorderStyle style, float width, float spaceBetweenDot, float borderLength)
153 #endif
154 {
155 if (ROSEN_EQ(width, 0.f)) {
156 return;
157 }
158 if (style == BorderStyle::DOTTED) {
159 #ifndef USE_ROSEN_DRAWING
160 SkPath dotPath;
161 #else
162 Drawing::Path dotPath;
163 #endif
164 if (ROSEN_EQ(spaceBetweenDot, 0.f)) {
165 spaceBetweenDot = width * PARAM_DOUBLE;
166 }
167 #ifndef USE_ROSEN_DRAWING
168 dotPath.addCircle(0.0f, 0.0f, width / PARAM_DOUBLE);
169 paint.setPathEffect(SkPath1DPathEffect::Make(dotPath, spaceBetweenDot, 0.0, SkPath1DPathEffect::kRotate_Style));
170 #else
171 dotPath.AddCircle(0.0f, 0.0f, width / PARAM_DOUBLE);
172 pen.SetPathEffect(Drawing::PathEffect::CreatePathDashEffect(dotPath, spaceBetweenDot, 0.0,
173 Drawing::PathDashStyle::ROTATE));
174 #endif
175 } else if (style == BorderStyle::DASHED) {
176 double addLen = 0.0; // When left < 2 * gap, splits left to gaps.
177 double delLen = 0.0; // When left > 2 * gap, add one dash and shortening them.
178 if (!ROSEN_EQ(borderLength, 0.f)) {
179 float count = borderLength / width;
180 float leftLen = fmod((count - DASHED_LINE_LENGTH), (DASHED_LINE_LENGTH + 1));
181 if (leftLen > DASHED_LINE_LENGTH - 1) {
182 delLen = (DASHED_LINE_LENGTH + 1 - leftLen) * width /
183 static_cast<int>((count - DASHED_LINE_LENGTH) / (DASHED_LINE_LENGTH + 1) + 2);
184 } else {
185 addLen = leftLen * width / static_cast<int>((count - DASHED_LINE_LENGTH) / (DASHED_LINE_LENGTH + 1));
186 }
187 }
188 const float intervals[] = { width * DASHED_LINE_LENGTH - delLen, width + addLen };
189 #ifndef USE_ROSEN_DRAWING
190 paint.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0.0));
191 } else {
192 paint.setPathEffect(nullptr);
193 #else
194 pen.SetPathEffect(Drawing::PathEffect::CreateDashPathEffect(intervals, sizeof(intervals)/sizeof(float), 0.0));
195 } else {
196 pen.SetPathEffect(nullptr);
197 #endif
198 }
199 }
200
201 #ifndef USE_ROSEN_DRAWING
ApplyFillStyle(SkPaint & paint) const202 bool RSBorder::ApplyFillStyle(SkPaint& paint) const
203 #else
204 bool RSBorder::ApplyFillStyle(Drawing::Brush& brush) const
205 #endif
206 {
207 if (colors_.size() != 1) {
208 return false;
209 }
210 if (styles_.size() != 1 || GetStyle() != BorderStyle::SOLID) {
211 return false;
212 }
213 #ifndef USE_ROSEN_DRAWING
214 paint.setStyle(SkPaint::Style::kFill_Style);
215 paint.setColor(GetColor().AsArgbInt());
216 #else
217 brush.SetColor(GetColor().AsArgbInt());
218 #endif
219 return true;
220 }
221
222 #ifndef USE_ROSEN_DRAWING
ApplyPathStyle(SkPaint & paint) const223 bool RSBorder::ApplyPathStyle(SkPaint& paint) const
224 #else
225 bool RSBorder::ApplyPathStyle(Drawing::Pen& pen) const
226 #endif
227 {
228 if (colors_.size() != 1 || widths_.size() != 1 || styles_.size() != 1) {
229 return false;
230 }
231 #ifndef USE_ROSEN_DRAWING
232 paint.setStrokeWidth(widths_.front());
233 paint.setStyle(SkPaint::Style::kStroke_Style);
234 paint.setColor(colors_.front().AsArgbInt());
235 SetBorderEffect(paint, GetStyle(), widths_.front(), 0.f, 0.f);
236 #else
237 pen.SetWidth(widths_.front());
238 pen.SetColor(colors_.front().AsArgbInt());
239 SetBorderEffect(pen, GetStyle(), widths_.front(), 0.f, 0.f);
240 #endif
241 return true;
242 }
243
244 #ifndef USE_ROSEN_DRAWING
ApplyFourLine(SkPaint & paint) const245 bool RSBorder::ApplyFourLine(SkPaint& paint) const
246 #else
247 bool RSBorder::ApplyFourLine(Drawing::Pen& pen) const
248 #endif
249 {
250 if (colors_.size() != 1 || styles_.size() != 1) {
251 return false;
252 }
253 #ifndef USE_ROSEN_DRAWING
254 paint.setStyle(SkPaint::Style::kStroke_Style);
255 #endif
256 return true;
257 }
258
259 #ifndef USE_ROSEN_DRAWING
ApplyLineStyle(SkPaint & paint,int borderIdx,float length) const260 bool RSBorder::ApplyLineStyle(SkPaint& paint, int borderIdx, float length) const
261 #else
262 bool RSBorder::ApplyLineStyle(Drawing::Pen& pen, int borderIdx, float length) const
263 #endif
264 {
265 if (GetWidth(borderIdx) <= 0.0f) {
266 return false;
267 }
268 float borderWidth = GetWidth(borderIdx);
269 float addLen = (GetStyle(borderIdx) != BorderStyle::DOTTED) ? 0.0f : 0.5f;
270 auto borderLength = length - borderWidth * addLen * PARAM_DOUBLE;
271 int32_t rawNumber = borderLength / (PARAM_DOUBLE * borderWidth);
272 if (rawNumber == 0) {
273 return false;
274 }
275
276 #ifndef USE_ROSEN_DRAWING
277 paint.setStrokeWidth(GetWidth(borderIdx));
278 Color color = GetColor(borderIdx);
279 paint.setColor(color.AsArgbInt());
280 SetBorderEffect(paint, GetStyle(borderIdx), borderWidth, borderLength / rawNumber, borderLength);
281 #else
282 pen.SetWidth(GetWidth(borderIdx));
283 Color color = GetColor(borderIdx);
284 pen.SetColor(color.AsArgbInt());
285 SetBorderEffect(pen, GetStyle(borderIdx), borderWidth, borderLength / rawNumber, borderLength);
286 #endif
287 return true;
288 }
289
290 #ifndef USE_ROSEN_DRAWING
PaintFourLine(SkCanvas & canvas,SkPaint & paint,RectF rect) const291 void RSBorder::PaintFourLine(SkCanvas& canvas, SkPaint& paint, RectF rect) const
292 #else
293 void RSBorder::PaintFourLine(Drawing::Canvas& canvas, Drawing::Pen& pen, RectF rect) const
294 #endif
295 {
296 float borderLeftWidth = GetWidth(RSBorder::LEFT);
297 float borderRightWidth = GetWidth(RSBorder::RIGHT);
298 float borderTopWidth = GetWidth(RSBorder::TOP);
299 float borderBottomWidth = GetWidth(RSBorder::BOTTOM);
300 #ifndef USE_ROSEN_DRAWING
301 if (ApplyLineStyle(paint, RSBorder::LEFT, rect.height_)) {
302 float addLen = (GetStyle(RSBorder::LEFT) != BorderStyle::DOTTED) ? 0.0f : 0.5f;
303 canvas.drawLine(
304 rect.left_ + borderLeftWidth / PARAM_DOUBLE, rect.top_ + addLen * borderTopWidth,
305 rect.left_ + borderLeftWidth / PARAM_DOUBLE, rect.GetBottom() - borderBottomWidth, paint);
306 }
307 if (ApplyLineStyle(paint, RSBorder::RIGHT, rect.height_)) {
308 float addLen = (GetStyle(RSBorder::RIGHT) != BorderStyle::DOTTED) ? 0.0f : 0.5f;
309 canvas.drawLine(
310 rect.GetRight() - borderRightWidth / PARAM_DOUBLE, rect.GetBottom() - addLen * borderBottomWidth,
311 rect.GetRight() - borderRightWidth / PARAM_DOUBLE, rect.top_ + borderTopWidth, paint);
312 }
313 if (ApplyLineStyle(paint, RSBorder::TOP, rect.width_)) {
314 float addLen = (GetStyle(RSBorder::TOP) != BorderStyle::DOTTED) ? 0.0f : 0.5f;
315 canvas.drawLine(
316 rect.GetRight() - addLen * borderRightWidth, rect.top_ + borderTopWidth / PARAM_DOUBLE,
317 rect.left_ + borderLeftWidth, rect.top_ + borderTopWidth / PARAM_DOUBLE, paint);
318 }
319 if (ApplyLineStyle(paint, RSBorder::BOTTOM, rect.width_)) {
320 float addLen = (GetStyle(RSBorder::BOTTOM) != BorderStyle::DOTTED) ? 0.0f : 0.5f;
321 canvas.drawLine(
322 rect.left_ + addLen * borderLeftWidth, rect.GetBottom() - borderBottomWidth / PARAM_DOUBLE,
323 rect.GetRight() - borderRightWidth, rect.GetBottom() - borderBottomWidth / PARAM_DOUBLE, paint);
324 }
325 #else
326 if (ApplyLineStyle(pen, RSBorder::LEFT, rect.height_)) {
327 float addLen = (GetStyle(RSBorder::LEFT) != BorderStyle::DOTTED) ? 0.0f : 0.5f;
328 canvas.AttachPen(pen);
329 canvas.DrawLine(
330 Drawing::Point(rect.left_ + borderLeftWidth / PARAM_DOUBLE, rect.top_ + addLen * borderTopWidth),
331 Drawing::Point(rect.left_ + borderLeftWidth / PARAM_DOUBLE, rect.GetBottom() - borderBottomWidth));
332 canvas.DetachPen();
333 }
334 if (ApplyLineStyle(pen, RSBorder::RIGHT, rect.height_)) {
335 float addLen = (GetStyle(RSBorder::RIGHT) != BorderStyle::DOTTED) ? 0.0f : 0.5f;
336 canvas.AttachPen(pen);
337 canvas.DrawLine(
338 Drawing::Point(rect.GetRight() - borderRightWidth / PARAM_DOUBLE,
339 rect.GetBottom() - addLen * borderBottomWidth),
340 Drawing::Point(rect.GetRight() - borderRightWidth / PARAM_DOUBLE, rect.top_ + borderTopWidth));
341 canvas.DetachPen();
342 }
343 if (ApplyLineStyle(pen, RSBorder::TOP, rect.width_)) {
344 float addLen = (GetStyle(RSBorder::TOP) != BorderStyle::DOTTED) ? 0.0f : 0.5f;
345 canvas.AttachPen(pen);
346 canvas.DrawLine(
347 Drawing::Point(rect.GetRight() - addLen * borderRightWidth, rect.top_ + borderTopWidth / PARAM_DOUBLE),
348 Drawing::Point(rect.left_ + borderLeftWidth, rect.top_ + borderTopWidth / PARAM_DOUBLE));
349 canvas.DetachPen();
350 }
351 if (ApplyLineStyle(pen, RSBorder::BOTTOM, rect.width_)) {
352 float addLen = (GetStyle(RSBorder::BOTTOM) != BorderStyle::DOTTED) ? 0.0f : 0.5f;
353 canvas.AttachPen(pen);
354 canvas.DrawLine(
355 Drawing::Point(rect.left_ + addLen * borderLeftWidth, rect.GetBottom() - borderBottomWidth / PARAM_DOUBLE),
356 Drawing::Point(rect.GetRight() - borderRightWidth, rect.GetBottom() - borderBottomWidth / PARAM_DOUBLE));
357 canvas.DetachPen();
358 }
359 #endif
360 }
361
362 #ifndef USE_ROSEN_DRAWING
PaintTopPath(SkCanvas & canvas,SkPaint & paint,SkRRect & rrect) const363 void RSBorder::PaintTopPath(SkCanvas& canvas, SkPaint& paint, SkRRect& rrect) const
364 #else
365 void RSBorder::PaintTopPath(Drawing::Canvas& canvas, Drawing::Pen& pen, Drawing::RoundRect& rrect) const
366 #endif
367 {
368 #ifndef USE_ROSEN_DRAWING
369 float offsetX = rrect.rect().x();
370 float offsetY = rrect.rect().y();
371 float width = rrect.rect().width();
372 #else
373 float offsetX = rrect.GetRect().GetLeft();
374 float offsetY = rrect.GetRect().GetTop();
375 float width = rrect.GetRect().GetWidth();
376 #endif
377 float leftW = GetWidth(RSBorder::LEFT);
378 float topW = GetWidth(RSBorder::TOP);
379 float rightW = GetWidth(RSBorder::RIGHT);
380 float bottomW = GetWidth(RSBorder::BOTTOM);
381 float x = offsetX + leftW / 2.0f;
382 float y = offsetY + topW / 2.0f;
383 float w = std::max(0.0f, width - (leftW + rightW) / 2.0f);
384 #ifndef USE_ROSEN_DRAWING
385 float tlX = std::max(0.0f, rrect.radii(SkRRect::kUpperLeft_Corner).x() - (topW + leftW) / 4.0f);
386 float tlY = std::max(0.0f, rrect.radii(SkRRect::kUpperLeft_Corner).y() - (topW + leftW) / 4.0f);
387 float trX = std::max(0.0f, rrect.radii(SkRRect::kUpperRight_Corner).x() - (topW + rightW) / 4.0f);
388 float trY = std::max(0.0f, rrect.radii(SkRRect::kUpperRight_Corner).y() - (topW + rightW) / 4.0f);
389 #else
390 float tlX = std::max(0.0f, rrect.GetCornerRadius(Drawing::RoundRect::TOP_LEFT_POS).GetX() - (topW + leftW) / 4.0f);
391 float tlY = std::max(0.0f, rrect.GetCornerRadius(Drawing::RoundRect::TOP_LEFT_POS).GetY() - (topW + leftW) / 4.0f);
392 float trX =
393 std::max(0.0f, rrect.GetCornerRadius(Drawing::RoundRect::TOP_RIGHT_POS).GetX() - (topW + rightW) / 4.0f);
394 float trY =
395 std::max(0.0f, rrect.GetCornerRadius(Drawing::RoundRect::TOP_RIGHT_POS).GetY() - (topW + rightW) / 4.0f);
396 #endif
397 if (topW > 0.f) {
398 #ifndef USE_ROSEN_DRAWING
399 ApplyLineStyle(paint, RSBorder::TOP, width);
400 auto rectStart = SkRect::MakeXYWH(x, y, tlX * 2.0f, tlY * 2.0f);
401 auto rectEnd = SkRect::MakeXYWH(x + w - trX * 2.0f, y, trX * 2.0f, trY * 2.0f);
402 SkPath topBorder;
403 paint.setStrokeWidth(std::max(std::max(leftW, topW), std::max(rightW, bottomW)));
404 SkAutoCanvasRestore acr(&canvas, true);
405 #else
406 ApplyLineStyle(pen, RSBorder::TOP, width);
407 auto rectStart = Drawing::Rect(x, y, x + tlX * 2.0f, y + tlY * 2.0f);
408 auto rectEnd = Drawing::Rect(x + w - trX * 2.0f, y, x + w, y + trY * 2.0f);
409 Drawing::Path topBorder;
410 pen.SetWidth(std::max(std::max(leftW, topW), std::max(rightW, bottomW)));
411 Drawing::AutoCanvasRestore acr(canvas, true);
412 #endif
413 if (ROSEN_EQ(tlX, 0.f) && !ROSEN_EQ(leftW, 0.f)) {
414 #ifndef USE_ROSEN_DRAWING
415 topBorder.moveTo(offsetX, y);
416 topBorder.lineTo(x, y);
417 SkPath topClipPath;
418 topClipPath.moveTo(offsetX - leftW, offsetY - topW);
419 topClipPath.lineTo(offsetX + leftW * EXTEND, offsetY + topW * EXTEND);
420 topClipPath.lineTo(offsetX, offsetY + topW * EXTEND);
421 topClipPath.close();
422 canvas.clipPath(topClipPath, SkClipOp::kDifference, true);
423 #else
424 topBorder.MoveTo(offsetX, y);
425 topBorder.LineTo(x, y);
426 Drawing::Path topClipPath;
427 topClipPath.MoveTo(offsetX - leftW, offsetY - topW);
428 topClipPath.LineTo(offsetX + leftW * EXTEND, offsetY + topW * EXTEND);
429 topClipPath.LineTo(offsetX, offsetY + topW * EXTEND);
430 topClipPath.Close();
431 canvas.ClipPath(topClipPath, Drawing::ClipOp::DIFFERENCE, true);
432 #endif
433 }
434 #ifndef USE_ROSEN_DRAWING
435 topBorder.arcTo(rectStart, TOP_START, SWEEP_ANGLE, false);
436 topBorder.arcTo(rectEnd, TOP_END, SWEEP_ANGLE + 0.5f, false);
437 #else
438 topBorder.ArcTo(rectStart.GetLeft(), rectStart.GetTop(), rectStart.GetRight(), rectStart.GetBottom(),
439 TOP_START, SWEEP_ANGLE);
440 topBorder.ArcTo(rectEnd.GetLeft(), rectEnd.GetTop(), rectEnd.GetRight(), rectEnd.GetBottom(),
441 TOP_END, SWEEP_ANGLE + 0.5f);
442 #endif
443 if (ROSEN_EQ(trX, 0.f) && !ROSEN_EQ(rightW, 0.f)) {
444 #ifndef USE_ROSEN_DRAWING
445 topBorder.lineTo(offsetX + width, y);
446 SkPath topClipPath;
447 topClipPath.moveTo(offsetX + width + rightW, offsetY - topW);
448 topClipPath.lineTo(offsetX + width - rightW * EXTEND, offsetY + topW * EXTEND);
449 topClipPath.lineTo(offsetX + width, offsetY + topW * EXTEND);
450 topClipPath.close();
451 canvas.clipPath(topClipPath, SkClipOp::kDifference, true);
452 #else
453 topBorder.LineTo(offsetX + width, y);
454 Drawing::Path topClipPath;
455 topClipPath.MoveTo(offsetX + width + rightW, offsetY - topW);
456 topClipPath.LineTo(offsetX + width - rightW * EXTEND, offsetY + topW * EXTEND);
457 topClipPath.LineTo(offsetX + width, offsetY + topW * EXTEND);
458 topClipPath.Close();
459 canvas.ClipPath(topClipPath, Drawing::ClipOp::DIFFERENCE, true);
460 #endif
461 }
462 #ifndef USE_ROSEN_DRAWING
463 canvas.drawPath(topBorder, paint);
464 #else
465 canvas.AttachPen(pen);
466 canvas.DrawPath(topBorder);
467 canvas.DetachPen();
468 #endif
469 }
470 }
471
472 #ifndef USE_ROSEN_DRAWING
PaintRightPath(SkCanvas & canvas,SkPaint & paint,SkRRect & rrect) const473 void RSBorder::PaintRightPath(SkCanvas& canvas, SkPaint& paint, SkRRect& rrect) const
474 {
475 float offsetX = rrect.rect().x();
476 float offsetY = rrect.rect().y();
477 float width = rrect.rect().width();
478 float height = rrect.rect().height();
479 #else
480 void RSBorder::PaintRightPath(Drawing::Canvas& canvas, Drawing::Pen& pen, Drawing::RoundRect& rrect) const
481 {
482 float offsetX = rrect.GetRect().GetLeft();
483 float offsetY = rrect.GetRect().GetTop();
484 float width = rrect.GetRect().GetWidth();
485 float height = rrect.GetRect().GetHeight();
486 #endif
487 float leftW = GetWidth(RSBorder::LEFT);
488 float topW = GetWidth(RSBorder::TOP);
489 float rightW = GetWidth(RSBorder::RIGHT);
490 float bottomW = GetWidth(RSBorder::BOTTOM);
491 float x = offsetX + leftW / 2.0f;
492 float y = offsetY + topW / 2.0f;
493 float w = std::max(0.0f, width - (leftW + rightW) / 2.0f);
494 float h = std::max(0.0f, height - (topW + bottomW) / 2.0f);
495 #ifndef USE_ROSEN_DRAWING
496 float trX = std::max(0.0f, rrect.radii(SkRRect::kUpperRight_Corner).x() - (topW + rightW) / 4.0f);
497 float trY = std::max(0.0f, rrect.radii(SkRRect::kUpperRight_Corner).y() - (topW + rightW) / 4.0f);
498 float brX = std::max(0.0f, rrect.radii(SkRRect::kLowerRight_Corner).x() - (bottomW + rightW) / 4.0f);
499 float brY = std::max(0.0f, rrect.radii(SkRRect::kLowerRight_Corner).y() - (bottomW + rightW) / 4.0f);
500 #else
501 float trX =
502 std::max(0.0f, rrect.GetCornerRadius(Drawing::RoundRect::TOP_RIGHT_POS).GetX() - (topW + rightW) / 4.0f);
503 float trY =
504 std::max(0.0f, rrect.GetCornerRadius(Drawing::RoundRect::TOP_RIGHT_POS).GetY() - (topW + rightW) / 4.0f);
505 float brX =
506 std::max(0.0f, rrect.GetCornerRadius(Drawing::RoundRect::BOTTOM_RIGHT_POS).GetX() - (bottomW + rightW) / 4.0f);
507 float brY =
508 std::max(0.0f, rrect.GetCornerRadius(Drawing::RoundRect::BOTTOM_RIGHT_POS).GetY() - (bottomW + rightW) / 4.0f);
509 #endif
510 if (rightW > 0.f) {
511 #ifndef USE_ROSEN_DRAWING
512 ApplyLineStyle(paint, RSBorder::RIGHT, height);
513 auto rectStart = SkRect::MakeXYWH(x + w - trX * 2.0f, y, trX * 2.0f, trY * 2.0f);
514 auto rectEnd = SkRect::MakeXYWH(x + w - brX * 2.0f, y + h - brY * 2.0f, brX * 2.0f, brY * 2.0f);
515 SkPath rightBorder;
516 paint.setStrokeWidth(std::max(std::max(leftW, topW), std::max(rightW, bottomW)));
517 SkAutoCanvasRestore acr(&canvas, true);
518 #else
519 ApplyLineStyle(pen, RSBorder::RIGHT, height);
520 auto rectStart = Drawing::Rect(x + w - trX * 2.0f, y, x + w, y + trY * 2.0f);
521 auto rectEnd = Drawing::Rect(x + w - brX * 2.0f, y + h - brY * 2.0f, x + w, y + h);
522 Drawing::Path rightBorder;
523 pen.SetWidth(std::max(std::max(leftW, topW), std::max(rightW, bottomW)));
524 Drawing::AutoCanvasRestore acr(canvas, true);
525 #endif
526 if (ROSEN_EQ(trX, 0.f) && !ROSEN_EQ(topW, 0.f)) {
527 #ifndef USE_ROSEN_DRAWING
528 rightBorder.moveTo(offsetX + width - rightW / 2.0f, offsetY);
529 rightBorder.lineTo(x + w - trX * 2.0f, y);
530 SkPath rightClipPath;
531 rightClipPath.moveTo(offsetX + width + rightW, offsetY - topW);
532 rightClipPath.lineTo(offsetX + width - rightW * EXTEND, offsetY + topW * EXTEND);
533 rightClipPath.lineTo(offsetX + width - rightW * EXTEND, offsetY);
534 rightClipPath.close();
535 canvas.clipPath(rightClipPath, SkClipOp::kDifference, true);
536 #else
537 rightBorder.MoveTo(offsetX + width - rightW / 2.0f, offsetY);
538 rightBorder.LineTo(x + w - trX * 2.0f, y);
539 Drawing::Path rightClipPath;
540 rightClipPath.MoveTo(offsetX + width + rightW, offsetY - topW);
541 rightClipPath.LineTo(offsetX + width - rightW * EXTEND, offsetY + topW * EXTEND);
542 rightClipPath.LineTo(offsetX + width - rightW * EXTEND, offsetY);
543 rightClipPath.Close();
544 canvas.ClipPath(rightClipPath, Drawing::ClipOp::DIFFERENCE, true);
545 #endif
546 }
547 #ifndef USE_ROSEN_DRAWING
548 rightBorder.arcTo(rectStart, RIGHT_START, SWEEP_ANGLE, false);
549 rightBorder.arcTo(rectEnd, RIGHT_END, SWEEP_ANGLE + 0.5f, false);
550 #else
551 rightBorder.ArcTo(rectStart.GetLeft(), rectStart.GetTop(), rectStart.GetRight(), rectStart.GetBottom(),
552 RIGHT_START, SWEEP_ANGLE);
553 rightBorder.ArcTo(rectEnd.GetLeft(), rectEnd.GetTop(), rectEnd.GetRight(), rectEnd.GetBottom(),
554 RIGHT_END, SWEEP_ANGLE + 0.5f);
555 #endif
556 if (ROSEN_EQ(brX, 0.f) && !ROSEN_EQ(bottomW, 0.f)) {
557 #ifndef USE_ROSEN_DRAWING
558 rightBorder.lineTo(offsetX + width - rightW / 2.0f, offsetY + height);
559 SkPath rightClipPath;
560 rightClipPath.moveTo(offsetX + width + rightW, offsetY + height + bottomW);
561 rightClipPath.lineTo(offsetX + width - rightW * EXTEND, offsetY + height - bottomW * EXTEND);
562 rightClipPath.lineTo(offsetX + width - rightW * EXTEND, offsetY + height);
563 rightClipPath.close();
564 canvas.clipPath(rightClipPath, SkClipOp::kDifference, true);
565 #else
566 rightBorder.LineTo(offsetX + width - rightW / 2.0f, offsetY + height);
567 Drawing::Path rightClipPath;
568 rightClipPath.MoveTo(offsetX + width + rightW, offsetY + height + bottomW);
569 rightClipPath.LineTo(offsetX + width - rightW * EXTEND, offsetY + height - bottomW * EXTEND);
570 rightClipPath.LineTo(offsetX + width - rightW * EXTEND, offsetY + height);
571 rightClipPath.Close();
572 canvas.ClipPath(rightClipPath, Drawing::ClipOp::DIFFERENCE, true);
573 #endif
574 }
575 #ifndef USE_ROSEN_DRAWING
576 canvas.drawPath(rightBorder, paint);
577 #else
578 canvas.AttachPen(pen);
579 canvas.DrawPath(rightBorder);
580 canvas.DetachPen();
581 #endif
582 }
583 }
584
585 #ifndef USE_ROSEN_DRAWING
586 void RSBorder::PaintBottomPath(SkCanvas& canvas, SkPaint& paint, SkRRect& rrect) const
587 {
588 float offsetX = rrect.rect().x();
589 float offsetY = rrect.rect().y();
590 float width = rrect.rect().width();
591 float height = rrect.rect().height();
592 #else
593 void RSBorder::PaintBottomPath(Drawing::Canvas& canvas, Drawing::Pen& pen, Drawing::RoundRect& rrect) const
594 {
595 float offsetX = rrect.GetRect().GetLeft();
596 float offsetY = rrect.GetRect().GetTop();
597 float width = rrect.GetRect().GetWidth();
598 float height = rrect.GetRect().GetHeight();
599 #endif
600 float leftW = GetWidth(RSBorder::LEFT);
601 float topW = GetWidth(RSBorder::TOP);
602 float rightW = GetWidth(RSBorder::RIGHT);
603 float bottomW = GetWidth(RSBorder::BOTTOM);
604 float x = offsetX + leftW / 2.0f;
605 float y = offsetY + topW / 2.0f;
606 float w = std::max(0.0f, width - (leftW + rightW) / 2.0f);
607 float h = std::max(0.0f, height - (topW + bottomW) / 2.0f);
608 #ifndef USE_ROSEN_DRAWING
609 float brX = std::max(0.0f, rrect.radii(SkRRect::kLowerRight_Corner).x() - (bottomW + rightW) / 4.0f);
610 float brY = std::max(0.0f, rrect.radii(SkRRect::kLowerRight_Corner).y() - (bottomW + rightW) / 4.0f);
611 float blX = std::max(0.0f, rrect.radii(SkRRect::kLowerLeft_Corner).x() - (bottomW + leftW) / 4.0f);
612 float blY = std::max(0.0f, rrect.radii(SkRRect::kLowerLeft_Corner).y() - (bottomW + leftW) / 4.0f);
613 #else
614 float brX =
615 std::max(0.0f, rrect.GetCornerRadius(Drawing::RoundRect::BOTTOM_RIGHT_POS).GetX() - (bottomW + rightW) / 4.0f);
616 float brY =
617 std::max(0.0f, rrect.GetCornerRadius(Drawing::RoundRect::BOTTOM_RIGHT_POS).GetY() - (bottomW + rightW) / 4.0f);
618 float blX =
619 std::max(0.0f, rrect.GetCornerRadius(Drawing::RoundRect::BOTTOM_LEFT_POS).GetX() - (bottomW + leftW) / 4.0f);
620 float blY =
621 std::max(0.0f, rrect.GetCornerRadius(Drawing::RoundRect::BOTTOM_LEFT_POS).GetY() - (bottomW + leftW) / 4.0f);
622 #endif
623 if (bottomW > 0.f) {
624 #ifndef USE_ROSEN_DRAWING
625 ApplyLineStyle(paint, RSBorder::BOTTOM, width);
626 auto rectStart = SkRect::MakeXYWH(x + w - brX * 2.0f, y + h - brY * 2.0f, brX * 2.0f, brY * 2.0f);
627 auto rectEnd = SkRect::MakeXYWH(x, y + h - blY * 2.0f, blX * 2.0f, blY * 2.0f);
628 SkPath bottomBorder;
629 if (GetStyle(RSBorder::BOTTOM) != BorderStyle::DOTTED) {
630 paint.setStrokeWidth(std::max(std::max(leftW, topW), std::max(rightW, bottomW)));
631 }
632 SkAutoCanvasRestore acr(&canvas, true);
633 #else
634 ApplyLineStyle(pen, RSBorder::BOTTOM, width);
635 auto rectStart = Drawing::Rect(x + w - brX * 2.0f, y + h - brY * 2.0f, x + w, y + h);
636 auto rectEnd = Drawing::Rect(x, y + h - blY * 2.0f, x + blX * 2.0f, y + h);
637 Drawing::Path bottomBorder;
638 if (GetStyle(RSBorder::BOTTOM) != BorderStyle::DOTTED) {
639 pen.SetWidth(std::max(std::max(leftW, topW), std::max(rightW, bottomW)));
640 }
641 Drawing::AutoCanvasRestore acr(canvas, true);
642 #endif
643 if (ROSEN_EQ(brX, 0.f) && !ROSEN_EQ(rightW, 0.f)) {
644 #ifndef USE_ROSEN_DRAWING
645 bottomBorder.moveTo(offsetX + width, offsetY + height - bottomW / 2.0f);
646 bottomBorder.lineTo(x + w - brX * 2.0f, y + h - brY * 2.0f);
647 SkPath bottomClipPath;
648 bottomClipPath.moveTo(offsetX + width + rightW, offsetY + height + bottomW);
649 bottomClipPath.lineTo(offsetX + width - rightW * EXTEND, offsetY + height - bottomW * EXTEND);
650 bottomClipPath.lineTo(offsetX + width, offsetY + height - bottomW * EXTEND);
651 bottomClipPath.close();
652 canvas.clipPath(bottomClipPath, SkClipOp::kDifference, true);
653 #else
654 bottomBorder.MoveTo(offsetX + width, offsetY + height - bottomW / 2.0f);
655 bottomBorder.LineTo(x + w - brX * 2.0f, y + h - brY * 2.0f);
656 Drawing::Path bottomClipPath;
657 bottomClipPath.MoveTo(offsetX + width + rightW, offsetY + height + bottomW);
658 bottomClipPath.LineTo(offsetX + width - rightW * EXTEND, offsetY + height - bottomW * EXTEND);
659 bottomClipPath.LineTo(offsetX + width, offsetY + height - bottomW * EXTEND);
660 bottomClipPath.Close();
661 canvas.ClipPath(bottomClipPath, Drawing::ClipOp::DIFFERENCE, true);
662 #endif
663 }
664 #ifndef USE_ROSEN_DRAWING
665 bottomBorder.arcTo(rectStart, BOTTOM_START, SWEEP_ANGLE, false);
666 bottomBorder.arcTo(rectEnd, BOTTOM_END, SWEEP_ANGLE + 0.5f, false);
667 #else
668 bottomBorder.ArcTo(rectStart.GetLeft(), rectStart.GetTop(), rectStart.GetRight(), rectStart.GetBottom(),
669 BOTTOM_START, SWEEP_ANGLE);
670 bottomBorder.ArcTo(rectEnd.GetLeft(), rectEnd.GetTop(), rectEnd.GetRight(), rectEnd.GetBottom(),
671 BOTTOM_END, SWEEP_ANGLE + 0.5f);
672 #endif
673 if (ROSEN_EQ(blX, 0.f) && !ROSEN_EQ(leftW, 0.f)) {
674 #ifndef USE_ROSEN_DRAWING
675 bottomBorder.lineTo(offsetX, offsetY + height - bottomW / 2.0f);
676 SkPath bottomClipPath;
677 bottomClipPath.moveTo(offsetX - leftW, offsetY + height + bottomW);
678 bottomClipPath.lineTo(offsetX + leftW * EXTEND, offsetY + height - bottomW * EXTEND);
679 bottomClipPath.lineTo(offsetX, offsetY + height - bottomW * EXTEND);
680 bottomClipPath.close();
681 canvas.clipPath(bottomClipPath, SkClipOp::kDifference, true);
682 #else
683 bottomBorder.LineTo(offsetX, offsetY + height - bottomW / 2.0f);
684 Drawing::Path bottomClipPath;
685 bottomClipPath.MoveTo(offsetX - leftW, offsetY + height + bottomW);
686 bottomClipPath.LineTo(offsetX + leftW * EXTEND, offsetY + height - bottomW * EXTEND);
687 bottomClipPath.LineTo(offsetX, offsetY + height - bottomW * EXTEND);
688 bottomClipPath.Close();
689 canvas.ClipPath(bottomClipPath, Drawing::ClipOp::DIFFERENCE, true);
690 #endif
691 }
692 #ifndef USE_ROSEN_DRAWING
693 canvas.drawPath(bottomBorder, paint);
694 #else
695 canvas.AttachPen(pen);
696 canvas.DrawPath(bottomBorder);
697 canvas.DetachPen();
698 #endif
699 }
700 }
701
702 #ifndef USE_ROSEN_DRAWING
703 void RSBorder::PaintLeftPath(SkCanvas& canvas, SkPaint& paint, SkRRect& rrect) const
704 {
705 float offsetX = rrect.rect().x();
706 float offsetY = rrect.rect().y();
707 float height = rrect.rect().height();
708 #else
709 void RSBorder::PaintLeftPath(Drawing::Canvas& canvas, Drawing::Pen& pen, Drawing::RoundRect& rrect) const
710 {
711 float offsetX = rrect.GetRect().GetLeft();
712 float offsetY = rrect.GetRect().GetTop();
713 float height = rrect.GetRect().GetHeight();
714 #endif
715 float leftW = GetWidth(RSBorder::LEFT);
716 float topW = GetWidth(RSBorder::TOP);
717 float rightW = GetWidth(RSBorder::RIGHT);
718 float bottomW = GetWidth(RSBorder::BOTTOM);
719 float x = offsetX + leftW / 2.0f;
720 float y = offsetY + topW / 2.0f;
721 float h = std::max(0.0f, height - (topW + bottomW) / 2.0f);
722 #ifndef USE_ROSEN_DRAWING
723 float tlX = std::max(0.0f, rrect.radii(SkRRect::kUpperLeft_Corner).x() - (topW + leftW) / 4.0f);
724 float tlY = std::max(0.0f, rrect.radii(SkRRect::kUpperLeft_Corner).y() - (topW + leftW) / 4.0f);
725 float blX = std::max(0.0f, rrect.radii(SkRRect::kLowerLeft_Corner).x() - (bottomW + leftW) / 4.0f);
726 float blY = std::max(0.0f, rrect.radii(SkRRect::kLowerLeft_Corner).y() - (bottomW + leftW) / 4.0f);
727 #else
728 float tlX = std::max(0.0f, rrect.GetCornerRadius(Drawing::RoundRect::TOP_LEFT_POS).GetX() - (topW + leftW) / 4.0f);
729 float tlY = std::max(0.0f, rrect.GetCornerRadius(Drawing::RoundRect::TOP_LEFT_POS).GetY() - (topW + leftW) / 4.0f);
730 float blX =
731 std::max(0.0f, rrect.GetCornerRadius(Drawing::RoundRect::BOTTOM_LEFT_POS).GetX() - (bottomW + leftW) / 4.0f);
732 float blY =
733 std::max(0.0f, rrect.GetCornerRadius(Drawing::RoundRect::BOTTOM_LEFT_POS).GetY() - (bottomW + leftW) / 4.0f);
734 #endif
735 if (leftW > 0.f) {
736 #ifndef USE_ROSEN_DRAWING
737 ApplyLineStyle(paint, RSBorder::LEFT, height);
738 auto rectStart = SkRect::MakeXYWH(x, y + h - blY * 2.0f, blX * 2.0f, blY * 2.0f);
739 auto rectEnd = SkRect::MakeXYWH(x, y, tlX * 2.0f, tlY * 2.0f);
740 SkPath leftBorder;
741 if (GetStyle(RSBorder::LEFT) != BorderStyle::DOTTED) {
742 paint.setStrokeWidth(std::max(std::max(leftW, topW), std::max(rightW, bottomW)));
743 }
744 SkAutoCanvasRestore acr(&canvas, true);
745 #else
746 ApplyLineStyle(pen, RSBorder::LEFT, height);
747 auto rectStart = Drawing::Rect(x, y + h - blY * 2.0f, x + blX * 2.0f, y + h);
748 auto rectEnd = Drawing::Rect(x, y, x + tlX * 2.0f, y + tlY * 2.0f);
749 Drawing::Path leftBorder;
750 if (GetStyle(RSBorder::LEFT) != BorderStyle::DOTTED) {
751 pen.SetWidth(std::max(std::max(leftW, topW), std::max(rightW, bottomW)));
752 }
753 Drawing::AutoCanvasRestore acr(canvas, true);
754 #endif
755 if (ROSEN_EQ(blX, 0.f) && !ROSEN_EQ(bottomW, 0.f)) {
756 #ifndef USE_ROSEN_DRAWING
757 leftBorder.moveTo(offsetX + leftW / 2.0f, offsetY + height);
758 leftBorder.lineTo(x, y + h - blY * 2.0f);
759 SkPath leftClipPath;
760 leftClipPath.moveTo(offsetX - leftW, offsetY + height + bottomW);
761 leftClipPath.lineTo(offsetX + leftW * EXTEND, offsetY + height - bottomW * EXTEND);
762 leftClipPath.lineTo(offsetX + leftW * EXTEND, offsetY + height);
763 leftClipPath.close();
764 canvas.clipPath(leftClipPath, SkClipOp::kDifference, true);
765 #else
766 leftBorder.MoveTo(offsetX + leftW / 2.0f, offsetY + height);
767 leftBorder.LineTo(x, y + h - blY * 2.0f);
768 Drawing::Path leftClipPath;
769 leftClipPath.MoveTo(offsetX - leftW, offsetY + height + bottomW);
770 leftClipPath.LineTo(offsetX + leftW * EXTEND, offsetY + height - bottomW * EXTEND);
771 leftClipPath.LineTo(offsetX + leftW * EXTEND, offsetY + height);
772 leftClipPath.Close();
773 canvas.ClipPath(leftClipPath, Drawing::ClipOp::DIFFERENCE, true);
774 #endif
775 }
776 #ifndef USE_ROSEN_DRAWING
777 leftBorder.arcTo(rectStart, LEFT_START, SWEEP_ANGLE, false);
778 leftBorder.arcTo(rectEnd, LEFT_END, SWEEP_ANGLE + 0.5f, false);
779 #else
780
781 leftBorder.ArcTo(rectStart.GetLeft(), rectStart.GetTop(), rectStart.GetRight(), rectStart.GetBottom(),
782 LEFT_START, SWEEP_ANGLE);
783 leftBorder.ArcTo(rectEnd.GetLeft(), rectEnd.GetTop(), rectEnd.GetRight(), rectEnd.GetBottom(),
784 LEFT_END, SWEEP_ANGLE + 0.5f);
785 #endif
786 if (ROSEN_EQ(tlX, 0.f) && !ROSEN_EQ(topW, 0.f)) {
787 #ifndef USE_ROSEN_DRAWING
788 leftBorder.lineTo(offsetX + leftW / 2.0f, offsetY);
789 SkPath topClipPath;
790 topClipPath.moveTo(offsetX - leftW, offsetY - topW);
791 topClipPath.lineTo(offsetX + leftW * EXTEND, offsetY + topW * EXTEND);
792 topClipPath.lineTo(offsetX + leftW * EXTEND, offsetY);
793 topClipPath.close();
794 canvas.clipPath(topClipPath, SkClipOp::kDifference, true);
795 #else
796 leftBorder.LineTo(offsetX + leftW / 2.0f, offsetY);
797 Drawing::Path topClipPath;
798 topClipPath.MoveTo(offsetX - leftW, offsetY - topW);
799 topClipPath.LineTo(offsetX + leftW * EXTEND, offsetY + topW * EXTEND);
800 topClipPath.LineTo(offsetX + leftW * EXTEND, offsetY);
801 topClipPath.Close();
802 canvas.ClipPath(topClipPath, Drawing::ClipOp::DIFFERENCE, true);
803 #endif
804 }
805 #ifndef USE_ROSEN_DRAWING
806 canvas.drawPath(leftBorder, paint);
807 #else
808 canvas.AttachPen(pen);
809 canvas.DrawPath(leftBorder);
810 canvas.DetachPen();
811 #endif
812 }
813 }
814
815 std::string RSBorder::ToString() const
816 {
817 std::stringstream ss;
818 if (colors_.size() > 0) {
819 ss << "colors: ";
820 }
821 for (auto color : colors_) {
822 ss << color.AsArgbInt() << ", ";
823 }
824 if (widths_.size() > 0) {
825 ss << "widths: ";
826 }
827 for (auto width : widths_) {
828 ss << width << ", ";
829 }
830 if (styles_.size() > 0) {
831 ss << "styles: ";
832 }
833 for (auto style : styles_) {
834 ss << static_cast<uint32_t>(style) << ", ";
835 }
836 std::string output = ss.str();
837 return output;
838 }
839
840 bool RSBorder::HasBorder() const
841 {
842 return !colors_.empty() && !widths_.empty() && !styles_.empty() &&
843 !std::all_of(colors_.begin(), colors_.end(), [](const Color& color) { return color.GetAlpha() == 0; }) &&
844 !std::all_of(widths_.begin(), widths_.end(), [](const float& width) { return width <= 0.f; }) &&
845 !std::all_of(
846 styles_.begin(), styles_.end(), [](const BorderStyle& style) { return style == BorderStyle::NONE; });
847 }
848 } // namespace Rosen
849 } // namespace OHOS
850