• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "draw/path.h"
19 #include "platform/common/rs_log.h"
20 
21 namespace OHOS {
22 namespace Rosen {
23 namespace {
24 constexpr int PARAM_DOUBLE = 2;
25 constexpr int32_t DASHED_LINE_LENGTH = 3;
26 constexpr float SWEEP_ANGLE = 60.0f;
27 constexpr float TOP_END = 270.0f;
28 constexpr float TOP_START = TOP_END - SWEEP_ANGLE;
29 constexpr float RIGHT_END = 0.0f;
30 constexpr float RIGHT_START = 360.0f - SWEEP_ANGLE;
31 constexpr float BOTTOM_END = 90.0f;
32 constexpr float BOTTOM_START = BOTTOM_END - SWEEP_ANGLE;
33 constexpr float LEFT_END = 180.0f;
34 constexpr float LEFT_START = LEFT_END - SWEEP_ANGLE;
35 } // namespace
36 
37 // defines short names for widths/half widths of each borders
38 #define LEFTW GetWidth(RSBorder::LEFT)
39 #define LEFTW2 GetWidth(RSBorder::LEFT) / 2.f
40 #define RIGHTW GetWidth(RSBorder::RIGHT)
41 #define RIGHTW2 GetWidth(RSBorder::RIGHT) / 2.f
42 #define TOPW GetWidth(RSBorder::TOP)
43 #define TOPW2 GetWidth(RSBorder::TOP) / 2.f
44 #define BOTTOMW GetWidth(RSBorder::BOTTOM)
45 #define BOTTOMW2 GetWidth(RSBorder::BOTTOM) / 2.f
46 
RSBorder(const bool & isOutline)47 RSBorder::RSBorder(const bool& isOutline)
48 {
49     if (isOutline) {
50         SetStyle(BorderStyle::SOLID);
51         SetColor(Color(0, 0, 0));
52     }
53 }
54 
SetColor(Color color)55 void RSBorder::SetColor(Color color)
56 {
57     colors_.clear();
58     colors_.push_back(color);
59 }
60 
SetWidth(float width)61 void RSBorder::SetWidth(float width)
62 {
63     widths_.clear();
64     widths_.push_back(width);
65 }
66 
SetStyle(BorderStyle style)67 void RSBorder::SetStyle(BorderStyle style)
68 {
69     styles_.clear();
70     styles_.push_back(style);
71 }
72 
SetDashWidth(float dashWidth)73 void RSBorder::SetDashWidth(float dashWidth)
74 {
75     dashWidth_.clear();
76     dashWidth_.push_back(dashWidth);
77 }
78 
SetDashGap(float dashGap)79 void RSBorder::SetDashGap(float dashGap)
80 {
81     dashGap_.clear();
82     dashGap_.push_back(dashGap);
83 }
84 
GetColor(int idx) const85 Color RSBorder::GetColor(int idx) const
86 {
87     if (colors_.empty()) {
88         return RgbPalette::Transparent();
89     } else if (colors_.size() == 1) {
90         return colors_.front();
91     } else {
92         return colors_.at(idx);
93     }
94 }
95 
GetWidth(int idx) const96 float RSBorder::GetWidth(int idx) const
97 {
98     if (widths_.empty()) {
99         return 0.f;
100     } else if (widths_.size() == 1) {
101         return widths_.front();
102     } else {
103         return widths_.at(idx);
104     }
105 }
106 
GetStyle(int idx) const107 BorderStyle RSBorder::GetStyle(int idx) const
108 {
109     if (styles_.empty()) {
110         return BorderStyle::NONE;
111     } else if (styles_.size() == 1) {
112         return styles_.front();
113     } else {
114         return styles_.at(idx);
115     }
116 }
117 
GetDashWidth(int idx) const118 float RSBorder::GetDashWidth(int idx) const
119 {
120     if (dashWidth_.empty()) {
121         // if dashWidth is not set, return -1 and the value will be calculated
122         return -1.f;
123     } else if (dashWidth_.size() == 1) {
124         return dashWidth_.front();
125     } else {
126         return dashWidth_.at(idx);
127     }
128 }
129 
GetDashGap(int idx) const130 float RSBorder::GetDashGap(int idx) const
131 {
132     if (dashGap_.empty()) {
133         // if dashGap is not set, return -1 and the value will be calculated
134         return -1.f;
135     } else if (dashGap_.size() == 1) {
136         return dashGap_.front();
137     } else {
138         return dashGap_.at(idx);
139     }
140 }
141 
SetColorFour(const Vector4<Color> & color)142 void RSBorder::SetColorFour(const Vector4<Color>& color)
143 {
144     if (color.x_ == color.y_ && color.x_ == color.z_ && color.x_ == color.w_) {
145         return SetColor(color.x_);
146     }
147     colors_ = { color.x_, color.y_, color.z_, color.w_ };
148 }
149 
SetWidthFour(const Vector4f & width)150 void RSBorder::SetWidthFour(const Vector4f& width)
151 {
152     if (width.x_ == width.y_ && width.x_ == width.z_ && width.x_ == width.w_) {
153         return SetWidth(width.x_);
154     }
155     widths_ = { width.x_, width.y_, width.z_, width.w_ };
156 }
157 
SetStyleFour(const Vector4<uint32_t> & style)158 void RSBorder::SetStyleFour(const Vector4<uint32_t>& style)
159 {
160     if (style.x_ == style.y_ && style.x_ == style.z_ && style.x_ == style.w_) {
161         return SetStyle(static_cast<BorderStyle>(style.x_));
162     }
163     styles_ = { static_cast<BorderStyle>(style.x_), static_cast<BorderStyle>(style.y_),
164                 static_cast<BorderStyle>(style.z_), static_cast<BorderStyle>(style.w_) };
165 }
166 
SetRadiusFour(const Vector4f & radius)167 void RSBorder::SetRadiusFour(const Vector4f& radius)
168 {
169     radius_ = { radius.x_, radius.y_, radius.z_, radius.w_ };
170 }
171 
SetDashWidthFour(const Vector4f & dashWidth)172 void RSBorder::SetDashWidthFour(const Vector4f& dashWidth)
173 {
174     if (dashWidth.x_ == dashWidth.y_ && dashWidth.x_ == dashWidth.z_ && dashWidth.x_ == dashWidth.w_) {
175         return SetDashWidth(dashWidth.x_);
176     }
177     dashWidth_ = { dashWidth.x_, dashWidth.y_, dashWidth.z_, dashWidth.w_ };
178 }
179 
SetDashGapFour(const Vector4f & dashGap)180 void RSBorder::SetDashGapFour(const Vector4f& dashGap)
181 {
182     if (dashGap.x_ == dashGap.y_ && dashGap.x_ == dashGap.z_ && dashGap.x_ == dashGap.w_) {
183         return SetDashGap(dashGap.x_);
184     }
185     dashGap_ = { dashGap.x_, dashGap.y_, dashGap.z_, dashGap.w_ };
186 }
187 
GetColorFour() const188 Vector4<Color> RSBorder::GetColorFour() const
189 {
190     if (colors_.size() == 4) {
191         return Vector4<Color>(colors_[0], colors_[1], colors_[2], colors_[3]);
192     } else {
193         return Vector4<Color>(GetColor());
194     }
195 }
196 
GetWidthFour() const197 Vector4f RSBorder::GetWidthFour() const
198 {
199     if (widths_.size() == 4) {
200         return Vector4f(widths_[0], widths_[1], widths_[2], widths_[3]);
201     } else {
202         return Vector4f(GetWidth());
203     }
204 }
205 
GetStyleFour() const206 Vector4<uint32_t> RSBorder::GetStyleFour() const
207 {
208     if (styles_.size() == 4) {
209         return Vector4<uint32_t>(static_cast<uint32_t>(styles_[0]), static_cast<uint32_t>(styles_[1]),
210                                  static_cast<uint32_t>(styles_[2]), static_cast<uint32_t>(styles_[3]));
211     } else {
212         return Vector4<uint32_t>(static_cast<uint32_t>(GetStyle()));
213     }
214 }
215 
GetRadiusFour() const216 Vector4f RSBorder::GetRadiusFour() const
217 {
218     return radius_;
219 }
220 
GetDashWidthFour() const221 Vector4f RSBorder::GetDashWidthFour() const
222 {
223     if (dashWidth_.size() <= 1) {
224         return Vector4f(GetDashWidth());
225     } else {
226         return Vector4f(GetDashWidth(BorderType::LEFT), GetDashWidth(BorderType::TOP),
227                         GetDashWidth(BorderType::RIGHT), GetDashWidth(BorderType::BOTTOM));
228     }
229 }
230 
GetDashGapFour() const231 Vector4f RSBorder::GetDashGapFour() const
232 {
233     if (dashGap_.size() <= 1) {
234         return Vector4f(GetDashGap());
235     } else {
236         return Vector4f(GetDashGap(BorderType::LEFT), GetDashGap(BorderType::TOP),
237                         GetDashGap(BorderType::RIGHT), GetDashGap(BorderType::BOTTOM));
238     }
239 }
240 
SetBorderEffect(Drawing::Pen & pen,int idx,float spaceBetweenDot,float borderLength) const241 void RSBorder::SetBorderEffect(Drawing::Pen& pen, int idx, float spaceBetweenDot, float borderLength) const
242 {
243     float width = GetWidth(idx);
244     if (ROSEN_EQ(width, 0.f)) {
245         return;
246     }
247     BorderStyle style = GetStyle(idx);
248     if (style == BorderStyle::DOTTED) {
249         Drawing::Path dotPath;
250         if (ROSEN_EQ(spaceBetweenDot, 0.f)) {
251             spaceBetweenDot = width * PARAM_DOUBLE;
252         }
253         dotPath.AddCircle(0.0f, 0.0f, width / PARAM_DOUBLE);
254         pen.SetPathEffect(Drawing::PathEffect::CreatePathDashEffect(dotPath, spaceBetweenDot, 0.0,
255             Drawing::PathDashStyle::ROTATE));
256         return;
257     }
258     if (style == BorderStyle::DASHED) {
259         float dashWidth = GetDashWidth(idx);
260         float dashGap = GetDashGap(idx);
261         bool bothZero = ROSEN_EQ(dashWidth, 0.f) && ROSEN_EQ(dashGap, 0.f);
262         if (dashWidth >= 0.f && dashGap >= 0.f) {
263             // Set fake gap for the case when dashWidth and dashGap params are both zero to prevent solid border line
264             float intervals[] = { dashWidth, bothZero ? 1.f : dashGap };
265             pen.SetPathEffect(
266                 Drawing::PathEffect::CreateDashPathEffect(intervals, sizeof(intervals)/sizeof(float), 0.0));
267             return;
268         }
269         double addLen = 0.0; // When left < 2 * gap, splits left to gaps.
270         double delLen = 0.0; // When left > 2 * gap, add one dash and shortening them.
271         if (!ROSEN_EQ(borderLength, 0.f) && width > 0) {
272             float count = borderLength / width;
273             float leftLen = fmod((count - DASHED_LINE_LENGTH), (DASHED_LINE_LENGTH + 1));
274             if (leftLen > DASHED_LINE_LENGTH - 1) {
275                 delLen = (DASHED_LINE_LENGTH + 1 - leftLen) * width /
276                          static_cast<int>((count - DASHED_LINE_LENGTH) / (DASHED_LINE_LENGTH + 1) + PARAM_DOUBLE);
277             } else {
278                 addLen = leftLen * width / static_cast<int>((count - DASHED_LINE_LENGTH) / (DASHED_LINE_LENGTH + 1));
279             }
280         }
281         float intervals[] = {
282             (dashWidth >= 0.f ? dashWidth : width * DASHED_LINE_LENGTH - delLen),
283             (dashGap >= 0.f ? dashGap : width + addLen) };
284         pen.SetPathEffect(Drawing::PathEffect::CreateDashPathEffect(intervals, sizeof(intervals)/sizeof(float), 0.0));
285         return;
286     }
287     pen.SetPathEffect(nullptr);
288 }
289 
ApplyFillStyle(Drawing::Brush & brush) const290 bool RSBorder::ApplyFillStyle(Drawing::Brush& brush) const
291 {
292     if (colors_.size() != 1) {
293         return false;
294     }
295     if (styles_.size() != 1 || GetStyle() != BorderStyle::SOLID) {
296         return false;
297     }
298     for (const float& width : widths_) {
299         if (ROSEN_LE(width, 0.f)) {
300             return false;
301         }
302     }
303     brush.SetColor(GetColor().AsArgbInt());
304     return true;
305 }
306 
ApplyPathStyle(Drawing::Pen & pen) const307 bool RSBorder::ApplyPathStyle(Drawing::Pen& pen) const
308 {
309     if (colors_.size() != 1 || widths_.size() != 1 || styles_.size() != 1 ||
310         dashWidth_.size() != 1 || dashGap_.size() != 1) {
311         return false;
312     }
313     pen.SetWidth(widths_.front());
314     pen.SetColor(colors_.front().AsArgbInt());
315     SetBorderEffect(pen, BorderType::LEFT, 0.f, 0.f);
316     return true;
317 }
318 
ApplyFourLine(Drawing::Pen & pen) const319 bool RSBorder::ApplyFourLine(Drawing::Pen& pen) const
320 {
321     if (colors_.size() != 1 || styles_.size() != 1) {
322         return false;
323     }
324     return true;
325 }
326 
ApplyLineStyle(Drawing::Pen & pen,int borderIdx,float length) const327 bool RSBorder::ApplyLineStyle(Drawing::Pen& pen, int borderIdx, float length) const
328 {
329     if (GetWidth(borderIdx) <= 0.0f) {
330         return false;
331     }
332     float borderWidth = GetWidth(borderIdx);
333     BorderStyle borderStyle = GetStyle(borderIdx);
334     float addLen = (borderStyle != BorderStyle::DOTTED) ? 0.0f : 0.5f;
335     auto borderLength = length - borderWidth * addLen * PARAM_DOUBLE;
336     int32_t rawNumber = borderLength / (PARAM_DOUBLE * borderWidth);
337     if (borderStyle == BorderStyle::DOTTED && rawNumber == 0) {
338         return false;
339     }
340 
341     pen.SetWidth(GetWidth(borderIdx));
342     Color color = GetColor(borderIdx);
343     pen.SetColor(color.AsArgbInt());
344     SetBorderEffect(pen, borderIdx, borderLength / rawNumber, borderLength);
345     return true;
346 }
347 
ApplySimpleBorder(const RRect & rrect) const348 bool RSBorder::ApplySimpleBorder(const RRect& rrect) const
349 {
350     if (!(colors_.size() == 1 && widths_.size() == 1 && styles_.size() == 1)) {
351         return false;
352     }
353     constexpr uint32_t NUM_OF_CORNERS_IN_RECT = 4u;
354     for (uint32_t i = 1; i < NUM_OF_CORNERS_IN_RECT; i++) {
355         if (rrect.radius_[0].x_ != rrect.radius_[i].x_) {
356             return false;
357         }
358     }
359     if (styles_.front() == BorderStyle::SOLID) {
360         return true;
361     }
362     // To avoid artefacts at corner - corner radius should be more than half the stroke width
363     return rrect.radius_[0].x_ > widths_.front() / PARAM_DOUBLE;
364 }
365 
PaintFourLine(Drawing::Canvas & canvas,Drawing::Pen & pen,RectF rect) const366 void RSBorder::PaintFourLine(Drawing::Canvas& canvas, Drawing::Pen& pen, RectF rect) const
367 {
368     float borderLeftWidth = GetWidth(RSBorder::LEFT);
369     float borderRightWidth = GetWidth(RSBorder::RIGHT);
370     float borderTopWidth = GetWidth(RSBorder::TOP);
371     float borderBottomWidth = GetWidth(RSBorder::BOTTOM);
372     if (ApplyLineStyle(pen, RSBorder::LEFT, rect.height_)) {
373         float addLen = (GetStyle(RSBorder::LEFT) != BorderStyle::DOTTED) ? 0.0f : 0.5f;
374         canvas.AttachPen(pen);
375         canvas.DrawLine(
376             Drawing::Point(rect.left_ + borderLeftWidth / PARAM_DOUBLE, rect.top_ + addLen * borderTopWidth),
377             Drawing::Point(rect.left_ + borderLeftWidth / PARAM_DOUBLE, rect.GetBottom() - borderBottomWidth));
378         canvas.DetachPen();
379     }
380     if (ApplyLineStyle(pen, RSBorder::RIGHT, rect.height_)) {
381         float addLen = (GetStyle(RSBorder::RIGHT) != BorderStyle::DOTTED) ? 0.0f : 0.5f;
382         canvas.AttachPen(pen);
383         canvas.DrawLine(
384             Drawing::Point(rect.GetRight() - borderRightWidth / PARAM_DOUBLE,
385                 rect.GetBottom() - addLen * borderBottomWidth),
386             Drawing::Point(rect.GetRight() - borderRightWidth / PARAM_DOUBLE, rect.top_ + borderTopWidth));
387         canvas.DetachPen();
388     }
389     if (ApplyLineStyle(pen, RSBorder::TOP, rect.width_)) {
390         float addLen = (GetStyle(RSBorder::TOP) != BorderStyle::DOTTED) ? 0.0f : 0.5f;
391         canvas.AttachPen(pen);
392         canvas.DrawLine(
393             Drawing::Point(rect.GetRight() - addLen * borderRightWidth, rect.top_ + borderTopWidth / PARAM_DOUBLE),
394             Drawing::Point(rect.left_ + borderLeftWidth, rect.top_ + borderTopWidth / PARAM_DOUBLE));
395         canvas.DetachPen();
396     }
397     if (ApplyLineStyle(pen, RSBorder::BOTTOM, rect.width_)) {
398         float addLen = (GetStyle(RSBorder::BOTTOM) != BorderStyle::DOTTED) ? 0.0f : 0.5f;
399         canvas.AttachPen(pen);
400         canvas.DrawLine(
401             Drawing::Point(rect.left_ + addLen * borderLeftWidth, rect.GetBottom() - borderBottomWidth / PARAM_DOUBLE),
402             Drawing::Point(rect.GetRight() - borderRightWidth, rect.GetBottom() - borderBottomWidth / PARAM_DOUBLE));
403         canvas.DetachPen();
404     }
405 }
406 
DrawBorders(Drawing::Canvas & canvas,Drawing::Pen & pen,RSBorderGeo & borderGeo) const407 void RSBorder::DrawBorders(Drawing::Canvas& canvas, Drawing::Pen& pen, RSBorderGeo& borderGeo) const
408 {
409     CalcBorderPath(borderGeo);
410 
411     int sameColorFlag = (CanBeCombined(RSBorder::LEFT, RSBorder::TOP) ? 1 << 3 : 0) |
412                         (CanBeCombined(RSBorder::TOP, RSBorder::RIGHT) ? 1 << 2 : 0) |
413                         (CanBeCombined(RSBorder::RIGHT, RSBorder::BOTTOM) ? 1 << 1 : 0) |
414                         (CanBeCombined(RSBorder::BOTTOM, RSBorder::LEFT) ? 1 : 0);
415 
416     switch (sameColorFlag) {
417         case 0b0000: // all different
418             for (int borderIdx = 0; borderIdx < MAX_BORDER_NUM; borderIdx++) {
419                 DrawBorderImpl(canvas, pen, borderGeo, borderIdx);
420             }
421             break;
422 
423         case 0b1000: // LT same
424             DrawBorderImpl(canvas, pen, borderGeo, RSBorder::RIGHT);
425             DrawBorderImpl(canvas, pen, borderGeo, RSBorder::BOTTOM);
426             DrawBorderImpl(canvas, pen, borderGeo, RSBorder::LEFT, RSBorder::TOP);
427             break;
428 
429         case 0b0100: // TR same
430             DrawBorderImpl(canvas, pen, borderGeo, RSBorder::BOTTOM);
431             DrawBorderImpl(canvas, pen, borderGeo, RSBorder::LEFT);
432             DrawBorderImpl(canvas, pen, borderGeo, RSBorder::TOP, RSBorder::RIGHT);
433             break;
434 
435         case 0b0010: // RB same
436             DrawBorderImpl(canvas, pen, borderGeo, RSBorder::TOP);
437             DrawBorderImpl(canvas, pen, borderGeo, RSBorder::LEFT);
438             DrawBorderImpl(canvas, pen, borderGeo, RSBorder::RIGHT, RSBorder::BOTTOM);
439             break;
440 
441         case 0b0001: // BL same
442             DrawBorderImpl(canvas, pen, borderGeo, RSBorder::TOP);
443             DrawBorderImpl(canvas, pen, borderGeo, RSBorder::RIGHT);
444             DrawBorderImpl(canvas, pen, borderGeo, RSBorder::BOTTOM, RSBorder::LEFT);
445             break;
446 
447         case 0b0101: // TR same, BL same
448             DrawBorderImpl(canvas, pen, borderGeo, RSBorder::TOP, RSBorder::RIGHT);
449             DrawBorderImpl(canvas, pen, borderGeo, RSBorder::BOTTOM, RSBorder::LEFT);
450             break;
451 
452         case 0b1010: // LT same, RB same
453             DrawBorderImpl(canvas, pen, borderGeo, RSBorder::LEFT, RSBorder::TOP);
454             DrawBorderImpl(canvas, pen, borderGeo, RSBorder::RIGHT, RSBorder::BOTTOM);
455             break;
456 
457         case 0b0110: // only LEFT different
458             DrawBorderImpl(canvas, pen, borderGeo, RSBorder::LEFT);
459             DrawBorderImpl(canvas, pen, borderGeo, RSBorder::TOP, RSBorder::RIGHT, RSBorder::BOTTOM);
460             break;
461 
462         case 0b0011: // only TOP different
463             DrawBorderImpl(canvas, pen, borderGeo, RSBorder::TOP);
464             DrawBorderImpl(canvas, pen, borderGeo, RSBorder::RIGHT, RSBorder::BOTTOM, RSBorder::LEFT);
465             break;
466 
467         case 0b1001: // only RIGHT different
468             DrawBorderImpl(canvas, pen, borderGeo, RSBorder::RIGHT);
469             DrawBorderImpl(canvas, pen, borderGeo, RSBorder::BOTTOM, RSBorder::LEFT, RSBorder::TOP);
470             break;
471 
472         case 0b1100: // only BOTTOM different
473             DrawBorderImpl(canvas, pen, borderGeo, RSBorder::BOTTOM);
474             DrawBorderImpl(canvas, pen, borderGeo, RSBorder::LEFT, RSBorder::TOP, RSBorder::RIGHT);
475             break;
476 
477         default:
478             ROSEN_LOGE("DrawBorders, style error: %{public}d, draw no border", sameColorFlag);
479             break;
480     }
481 
482     return;
483 }
484 
DrawBorderImpl(Drawing::Canvas & canvas,Drawing::Pen & pen,RSBorderGeo & borderGeo,int idx) const485 void RSBorder::DrawBorderImpl(
486     Drawing::Canvas& canvas, Drawing::Pen& pen, RSBorderGeo& borderGeo, int idx) const
487 {
488     Drawing::AutoCanvasRestore acr(canvas, true);
489     canvas.ClipPath(borderGeo.pathVec[idx], Drawing::ClipOp::INTERSECT, true);
490     if (GetStyle(idx) == BorderStyle::SOLID) {
491         uint32_t color = GetColor(idx).AsArgbInt();
492         DrawNestedRoundRect(canvas, borderGeo, color);
493     } else {
494         canvas.ClipRoundRect(borderGeo.rrect, Drawing::ClipOp::INTERSECT, true);
495         canvas.ClipRoundRect(borderGeo.innerRRect, Drawing::ClipOp::DIFFERENCE, true);
496         float width = borderGeo.rrect.GetRect().GetWidth();
497         ApplyLineStyle(pen, idx, width);
498         if (GetStyle(RSBorder::TOP) != BorderStyle::DOTTED) {
499             pen.SetWidth(std::max(std::max(LEFTW, TOPW), std::max(RIGHTW, BOTTOMW)));
500         }
501         switch (idx) {
502             case RSBorder::LEFT:
503                 DrawLeftBorder(canvas, pen, borderGeo);
504                 break;
505 
506             case RSBorder::TOP:
507                 DrawTopBorder(canvas, pen, borderGeo);
508                 break;
509 
510             case RSBorder::RIGHT:
511                 DrawRightBorder(canvas, pen, borderGeo);
512                 break;
513 
514             case RSBorder::BOTTOM:
515                 DrawBottomBorder(canvas, pen, borderGeo);
516                 break;
517 
518             default:
519                 break;
520         }
521     }
522 }
523 
DrawBorderImpl(Drawing::Canvas & canvas,Drawing::Pen & pen,RSBorderGeo & borderGeo,int idx1,int idx2) const524 void RSBorder::DrawBorderImpl(
525     Drawing::Canvas& canvas, Drawing::Pen& pen, RSBorderGeo& borderGeo, int idx1, int idx2) const
526 {
527     Drawing::AutoCanvasRestore acr(canvas, true);
528     Drawing::Path clipPath;
529     clipPath.Op(borderGeo.pathVec[idx1], borderGeo.pathVec[idx2], Drawing::PathOp::UNION);
530     canvas.ClipPath(clipPath, Drawing::ClipOp::INTERSECT, true);
531     DrawNestedRoundRect(canvas, borderGeo, GetColor(idx1).AsArgbInt());
532 }
533 
DrawBorderImpl(Drawing::Canvas & canvas,Drawing::Pen & pen,RSBorderGeo & borderGeo,int idx1,int idx2,int idx3) const534 void RSBorder::DrawBorderImpl(
535     Drawing::Canvas& canvas, Drawing::Pen& pen, RSBorderGeo& borderGeo, int idx1, int idx2, int idx3) const
536 {
537     Drawing::AutoCanvasRestore acr(canvas, true);
538     Drawing::Path clipPath;
539     clipPath.Op(borderGeo.pathVec[idx1], borderGeo.pathVec[idx2], Drawing::PathOp::UNION);
540     clipPath.Op(borderGeo.pathVec[idx3], clipPath, Drawing::PathOp::UNION);
541     canvas.ClipPath(clipPath, Drawing::ClipOp::INTERSECT, true);
542     DrawNestedRoundRect(canvas, borderGeo, GetColor(idx1).AsArgbInt());
543     return;
544 }
545 
CanBeCombined(int idx1,int idx2) const546 bool RSBorder::CanBeCombined(int idx1, int idx2) const
547 {
548     // same color, both solid style, both width > 0
549     if (GetColor(idx1).AsArgbInt() != GetColor(idx2).AsArgbInt() || GetStyle(idx1) != BorderStyle::SOLID ||
550         GetStyle(idx2) != BorderStyle::SOLID || ROSEN_LE(GetWidth(idx1), 0.f) ||
551         ROSEN_LE(GetWidth(idx2), 0.f)) {
552         return false;
553     }
554     return true;
555 }
556 
CalcBorderPath(RSBorderGeo & borderGeo) const557 void RSBorder::CalcBorderPath(RSBorderGeo& borderGeo) const
558 {
559     float offsetX = borderGeo.rrect.GetRect().GetLeft();
560     float offsetY = borderGeo.rrect.GetRect().GetTop();
561     float height = borderGeo.rrect.GetRect().GetHeight();
562     float width = borderGeo.rrect.GetRect().GetWidth();
563 
564     // calc top-left, top-right, bottom-right, top-right intersection point with innerRect center
565     Drawing::Point tlip = GetTLIP(borderGeo.rrect, borderGeo.center);
566     Drawing::Point trip = GetTRIP(borderGeo.rrect, borderGeo.center);
567     Drawing::Point brip = GetBRIP(borderGeo.rrect, borderGeo.center);
568     Drawing::Point blip = GetBLIP(borderGeo.rrect, borderGeo.center);
569 
570     if (TOPW > 0.f) {
571         borderGeo.pathVec[RSBorder::TOP].MoveTo(offsetX, offsetY);
572         borderGeo.pathVec[RSBorder::TOP].LineTo(tlip.GetX(), tlip.GetY());
573         borderGeo.pathVec[RSBorder::TOP].LineTo(trip.GetX(), trip.GetY());
574         borderGeo.pathVec[RSBorder::TOP].LineTo(offsetX + width, offsetY);
575         borderGeo.pathVec[RSBorder::TOP].Close();
576     }
577 
578     if (RIGHTW > 0.f) {
579         borderGeo.pathVec[RSBorder::RIGHT].MoveTo(offsetX + width, offsetY);
580         borderGeo.pathVec[RSBorder::RIGHT].LineTo(trip.GetX(), trip.GetY());
581         borderGeo.pathVec[RSBorder::RIGHT].LineTo(brip.GetX(), brip.GetY());
582         borderGeo.pathVec[RSBorder::RIGHT].LineTo(offsetX + width, offsetY + height);
583         borderGeo.pathVec[RSBorder::RIGHT].Close();
584     }
585 
586     if (BOTTOMW > 0.f) {
587         borderGeo.pathVec[RSBorder::BOTTOM].MoveTo(offsetX, offsetY + borderGeo.rrect.GetRect().GetHeight());
588         borderGeo.pathVec[RSBorder::BOTTOM].LineTo(blip.GetX(), blip.GetY());
589         borderGeo.pathVec[RSBorder::BOTTOM].LineTo(brip.GetX(), brip.GetY());
590         borderGeo.pathVec[RSBorder::BOTTOM].LineTo(offsetX + width, offsetY + borderGeo.rrect.GetRect().GetHeight());
591         borderGeo.pathVec[RSBorder::BOTTOM].Close();
592     }
593 
594     if (LEFTW > 0.f) {
595         borderGeo.pathVec[RSBorder::LEFT].MoveTo(offsetX, offsetY);
596         borderGeo.pathVec[RSBorder::LEFT].LineTo(tlip.GetX(), tlip.GetY());
597         borderGeo.pathVec[RSBorder::LEFT].LineTo(blip.GetX(), blip.GetY());
598         borderGeo.pathVec[RSBorder::LEFT].LineTo(offsetX, offsetY + height);
599         borderGeo.pathVec[RSBorder::LEFT].Close();
600     }
601     return;
602 }
603 
DrawNestedRoundRect(Drawing::Canvas & canvas,const RSBorderGeo & borderGeo,uint32_t color) const604 void RSBorder::DrawNestedRoundRect(Drawing::Canvas& canvas, const RSBorderGeo& borderGeo, uint32_t color) const
605 {
606     Drawing::Brush brush;
607     brush.SetColor(color);
608     canvas.AttachBrush(brush);
609     canvas.DrawNestedRoundRect(borderGeo.rrect, borderGeo.innerRRect);
610     canvas.DetachBrush();
611 }
612 
DrawTopBorder(Drawing::Canvas & canvas,Drawing::Pen & pen,const RSBorderGeo & borderGeo) const613 void RSBorder::DrawTopBorder(Drawing::Canvas& canvas, Drawing::Pen& pen, const RSBorderGeo& borderGeo) const
614 {
615     float width = borderGeo.rrect.GetRect().GetWidth();
616     float offsetX = borderGeo.rrect.GetRect().GetLeft();
617     float offsetY = borderGeo.rrect.GetRect().GetTop();
618     float x = offsetX + LEFTW2;
619     float y = offsetY + TOPW2;
620     Drawing::Point tlRad = borderGeo.rrect.GetCornerRadius(Drawing::RoundRect::TOP_LEFT_POS);
621     Drawing::Point trRad = borderGeo.rrect.GetCornerRadius(Drawing::RoundRect::TOP_RIGHT_POS);
622 
623     // calc rectangles to draw left top and right top arcs according to radii values
624     float startArcWidth = std::min(width - LEFTW, tlRad.GetX() * 2.f);
625     float endArcWidth = std::min(width - RIGHTW, trRad.GetX() * 2.f);
626     float startArcHeight = std::min(borderGeo.rrect.GetRect().GetHeight() - TOPW, tlRad.GetY() * 2.f);
627     float endArcHeight = std::min(borderGeo.rrect.GetRect().GetHeight() - TOPW, trRad.GetY() * 2.f);
628     auto rs = Drawing::Rect(x, y, x + startArcWidth, y + startArcHeight);
629     auto re = Drawing::Rect(
630         offsetX + width - RIGHTW / 2.f - endArcWidth, y, offsetX + width - RIGHTW / 2.f, y + endArcHeight);
631     // create drawing path from left top corner to right top corner
632     Drawing::Path topBorder;
633     topBorder.MoveTo(std::min(x, offsetX + tlRad.GetX() / 2.f), y + tlRad.GetY());
634     topBorder.ArcTo(rs.GetLeft(), rs.GetTop(), rs.GetRight(), rs.GetBottom(), TOP_START, SWEEP_ANGLE);
635     topBorder.ArcTo(re.GetLeft(), re.GetTop(), re.GetRight(), re.GetBottom(), TOP_END, SWEEP_ANGLE);
636     topBorder.LineTo(std::max(offsetX + width - RIGHTW2, offsetX + width - trRad.GetX() / 2.f), y + trRad.GetY());
637     canvas.AttachPen(pen);
638     canvas.DrawPath(topBorder);
639     canvas.DetachPen();
640 }
641 
DrawRightBorder(Drawing::Canvas & canvas,Drawing::Pen & pen,const RSBorderGeo & borderGeo) const642 void RSBorder::DrawRightBorder(Drawing::Canvas& canvas, Drawing::Pen& pen, const RSBorderGeo& borderGeo) const
643 {
644     float width = borderGeo.rrect.GetRect().GetWidth();
645     float height = borderGeo.rrect.GetRect().GetHeight();
646     float offsetX = borderGeo.rrect.GetRect().GetLeft();
647     float offsetY = borderGeo.rrect.GetRect().GetTop();
648     float x = offsetX + width - RIGHTW2;
649     float y = offsetY + TOPW2;
650     Drawing::Point trRad = borderGeo.rrect.GetCornerRadius(Drawing::RoundRect::TOP_RIGHT_POS);
651     Drawing::Point brRad = borderGeo.rrect.GetCornerRadius(Drawing::RoundRect::BOTTOM_RIGHT_POS);
652     // calc rectangles to draw right top and right bottom arcs according to radii values
653     float startArcWidth = std::min(width - RIGHTW, trRad.GetX() * 2.f);
654     float endArcWidth = std::min(width - RIGHTW, brRad.GetX() * 2.f);
655     float startArcHeight = std::min(height - TOPW, trRad.GetY() * 2.f);
656     float endArcHeight = std::min(height - BOTTOMW, brRad.GetY() * 2.f);
657     auto rs = Drawing::Rect(x - startArcWidth, y, x, y + startArcHeight);
658     auto re = Drawing::Rect(x - endArcWidth, height - BOTTOMW2 - endArcHeight, x, height - BOTTOMW2);
659     // create drawing path from right top corner to right bottom corner
660     Drawing::Path rightBorder;
661     rightBorder.MoveTo(x - trRad.GetX(), std::min(y, offsetY + trRad.GetY() / 2.f));
662     rightBorder.ArcTo(rs.GetLeft(), rs.GetTop(), rs.GetRight(), rs.GetBottom(), RIGHT_START, SWEEP_ANGLE);
663     rightBorder.ArcTo(re.GetLeft(), re.GetTop(), re.GetRight(), re.GetBottom(), RIGHT_END, SWEEP_ANGLE);
664     rightBorder.LineTo(x - brRad.GetX(), std::max(offsetY + height - BOTTOMW2, offsetY + height - brRad.GetY() / 2.f));
665     canvas.AttachPen(pen);
666     canvas.DrawPath(rightBorder);
667     canvas.DetachPen();
668 }
669 
DrawBottomBorder(Drawing::Canvas & canvas,Drawing::Pen & pen,const RSBorderGeo & borderGeo) const670 void RSBorder::DrawBottomBorder(Drawing::Canvas& canvas, Drawing::Pen& pen, const RSBorderGeo& borderGeo) const
671 {
672     float width = borderGeo.rrect.GetRect().GetWidth();
673     float offsetX = borderGeo.rrect.GetRect().GetLeft();
674     float offsetY = borderGeo.rrect.GetRect().GetTop();
675     float x = offsetX + LEFTW2;
676     float y = offsetY + borderGeo.rrect.GetRect().GetHeight() - BOTTOMW2;
677     Drawing::Point brRad = borderGeo.rrect.GetCornerRadius(Drawing::RoundRect::BOTTOM_RIGHT_POS);
678     Drawing::Point blRad = borderGeo.rrect.GetCornerRadius(Drawing::RoundRect::BOTTOM_LEFT_POS);
679     // calc rectangles to draw right bottom and left bottom arcs according to radii values
680     float startArcWidth = std::min(width - RIGHTW, brRad.GetX() * 2.f);
681     float endArcWidth = std::min(width - LEFTW, blRad.GetX() * 2.f);
682     float startArcHeight = std::min(borderGeo.rrect.GetRect().GetHeight() - BOTTOMW, brRad.GetY() * 2.f);
683     float endArcHeight = std::min(borderGeo.rrect.GetRect().GetHeight() - BOTTOMW, blRad.GetY() * 2.f);
684     auto rs =
685         Drawing::Rect(offsetX + width - RIGHTW2 - startArcWidth, y - startArcHeight, offsetX + width - RIGHTW2, y);
686     auto re = Drawing::Rect(x, y - endArcHeight, x + endArcWidth, y);
687     // create drawing path from right bottom corner to left bottom corner
688     Drawing::Path bottomBorder;
689     bottomBorder.MoveTo(std::max(offsetX + width - RIGHTW2, offsetY + width - brRad.GetX() / 2.f), y - brRad.GetY());
690     bottomBorder.ArcTo(rs.GetLeft(), rs.GetTop(), rs.GetRight(), rs.GetBottom(), BOTTOM_START, SWEEP_ANGLE);
691     bottomBorder.ArcTo(re.GetLeft(), re.GetTop(), re.GetRight(), re.GetBottom(), BOTTOM_END, SWEEP_ANGLE);
692     bottomBorder.LineTo(std::min(x, offsetX + blRad.GetX() / 2.f), y - blRad.GetY());
693     canvas.AttachPen(pen);
694     canvas.DrawPath(bottomBorder);
695     canvas.DetachPen();
696 }
697 
DrawLeftBorder(Drawing::Canvas & canvas,Drawing::Pen & pen,const RSBorderGeo & borderGeo) const698 void RSBorder::DrawLeftBorder(Drawing::Canvas& canvas, Drawing::Pen& pen, const RSBorderGeo& borderGeo) const
699 {
700     float offsetX = borderGeo.rrect.GetRect().GetLeft();
701     float offsetY = borderGeo.rrect.GetRect().GetTop();
702     float x = offsetX + LEFTW2;
703     float y = offsetY + TOPW2;
704     float height = borderGeo.rrect.GetRect().GetHeight();
705     Drawing::Point tlRad = borderGeo.rrect.GetCornerRadius(Drawing::RoundRect::TOP_LEFT_POS);
706     Drawing::Point blRad = borderGeo.rrect.GetCornerRadius(Drawing::RoundRect::BOTTOM_LEFT_POS);
707     // calc rectangles to draw left bottom and left top arcs according to radii values
708     float startArcWidth = std::min(borderGeo.rrect.GetRect().GetWidth() - LEFTW, blRad.GetX() * 2.f);
709     float endArcWidth = std::min(borderGeo.rrect.GetRect().GetWidth() - LEFTW, tlRad.GetX() * 2.f);
710     float startArcHeight = std::min(height - BOTTOMW, blRad.GetY() * 2.f);
711     float endArcHeight = std::min(height - TOPW, tlRad.GetY() * 2.f);
712     auto rs =
713         Drawing::Rect(x, offsetY + height - BOTTOMW2 - startArcHeight, x + startArcWidth, offsetY + height - BOTTOMW2);
714     auto re = Drawing::Rect(x, y, x + endArcWidth, y + endArcHeight);
715     // create drawing path from left bottom corner to left top corner
716     Drawing::Path leftBorder;
717     leftBorder.MoveTo(x + blRad.GetX(), std::max(offsetY + height - BOTTOMW2, offsetY + height - blRad.GetY() / 2.f));
718     leftBorder.ArcTo(rs.GetLeft(), rs.GetTop(), rs.GetRight(), rs.GetBottom(), LEFT_START, SWEEP_ANGLE);
719     leftBorder.ArcTo(re.GetLeft(), re.GetTop(), re.GetRight(), re.GetBottom(), LEFT_END, SWEEP_ANGLE);
720     leftBorder.LineTo(x + tlRad.GetX(), std::min(y, offsetY + tlRad.GetY() / 2.f));
721     canvas.AttachPen(pen);
722     canvas.DrawPath(leftBorder);
723     canvas.DetachPen();
724 }
725 
726 // Return top left intersection pos for clipping
GetTLIP(const Drawing::RoundRect & rrect,const Drawing::Point & center) const727 Drawing::Point RSBorder::GetTLIP(const Drawing::RoundRect& rrect, const Drawing::Point& center) const
728 {
729     // inner round rect center point
730     float x = center.GetX();
731     float y = center.GetY();
732     // width/height of inner round rect
733     float width = rrect.GetRect().GetWidth() - LEFTW - RIGHTW;
734     float height = rrect.GetRect().GetHeight() - TOPW - BOTTOMW;
735     if (width > 0) {
736         // kc is linear ratio of inner rect
737         float kc = height / width;
738         if (LEFTW > 0) {
739             // k is linear ratio for external rect (cutting angle at top left corner)
740             float k = TOPW / LEFTW;
741             // raduii values of external round rect for calculating clipping point
742             Drawing::Point tlRad = rrect.GetCornerRadius(Drawing::RoundRect::TOP_LEFT_POS);
743             Drawing::Point trRad = rrect.GetCornerRadius(Drawing::RoundRect::TOP_RIGHT_POS);
744             Drawing::Point blRad = rrect.GetCornerRadius(Drawing::RoundRect::BOTTOM_LEFT_POS);
745             // shows what center axis of inner round rect we intersect fist (x or y)
746             if (k <= kc) {
747                 // top left and right raduii for inner round rect
748                 float dlx = std::max(tlRad.GetX() - LEFTW, 0.f);
749                 float drx = std::max(trRad.GetX() - RIGHTW, 0.f);
750                 // calc delta to prevent overlapping of top right corner
751                 x = (dlx > 0) ? (x + std::min(dlx, width / 2.f - drx)) : (x - width / 2.f);
752                 y = rrect.GetRect().GetTop() + (x - rrect.GetRect().GetLeft()) * k;
753             } else {
754                 // left top and bottom raduii for inner round rect
755                 float dty = std::max(tlRad.GetY() - TOPW, 0.f);
756                 float dby = std::max(blRad.GetY() - BOTTOMW, 0.f);
757                 // calc delta to prevent overlapping of bottom left corner
758                 y = (dty > 0) ? (y = y + std::min(dty, height / 2.f - dby)) : (y - height / 2.f);
759                 x = rrect.GetRect().GetLeft() + (y - rrect.GetRect().GetTop()) / k;
760             }
761         } else {
762             x = rrect.GetRect().GetLeft();
763             y = std::max(y - height / 2.f,
764                          std::min(rrect.GetRect().GetTop() + rrect.GetRect().GetHeight() / 2.f,
765                                   rrect.GetRect().GetTop() + rrect.GetRect().GetHeight() - BOTTOMW));
766         }
767     } else {
768         y = rrect.GetRect().GetTop() + TOPW;
769     }
770     return Drawing::Point(x, y);
771 }
772 
773 // Return top right intersection pos for clipping
GetTRIP(const Drawing::RoundRect & rrect,const Drawing::Point & center) const774 Drawing::Point RSBorder::GetTRIP(const Drawing::RoundRect& rrect, const Drawing::Point& center) const
775 {
776     // inner round rect center point
777     float x = center.GetX();
778     float y = center.GetY();
779     // width/height of inner round rect
780     float width = rrect.GetRect().GetWidth() - LEFTW - RIGHTW;
781     float height = rrect.GetRect().GetHeight() - TOPW - BOTTOMW;
782     if (width > 0) {
783         // kc is linear ratio of inner rect
784         float kc = height / width;
785         if (RIGHTW > 0) {
786             // k is linear ratio for external rect (cutting angle at top right corner)
787             float k = TOPW / RIGHTW;
788             // raduii values of external round rect for calculating clipping point
789             Drawing::Point trRad = rrect.GetCornerRadius(Drawing::RoundRect::TOP_RIGHT_POS);
790             Drawing::Point tlRad = rrect.GetCornerRadius(Drawing::RoundRect::TOP_LEFT_POS);
791             Drawing::Point brRad = rrect.GetCornerRadius(Drawing::RoundRect::BOTTOM_RIGHT_POS);
792             // shows what center axis of inner round rect we intersect fist (x or y)
793             if (k <= kc) {
794                 // top left and right raduii for inner round rect
795                 float drx = std::max(trRad.GetX() - RIGHTW, 0.f);
796                 float dlx = std::max(tlRad.GetX() - LEFTW, 0.f);
797                 // calc delta to prevent overlapping of top left corner
798                 x = (drx > 0) ? (x - std::min(drx, width / 2.f - dlx)) : (x + width / 2.f);
799                 y = rrect.GetRect().GetTop() + (rrect.GetRect().GetRight() - x) * k;
800             } else {
801                 // right top and bottom raduii for inner round rect
802                 float dty = std::max(trRad.GetY() - TOPW, 0.f);
803                 float dby = std::max(brRad.GetY() - BOTTOMW, 0.f);
804                 // calc delta to prevent overlapping of bottom right corner
805                 y = (dty > 0) ? (y = y + std::min(dty, height / 2.f - dby)) : (y - height / 2.f);
806                 x = rrect.GetRect().GetRight() - (y - rrect.GetRect().GetTop()) / k;
807             }
808         } else {
809             x = rrect.GetRect().GetLeft() + rrect.GetRect().GetWidth();
810             y = std::max(y - height / 2.f,
811                          std::min(rrect.GetRect().GetTop() + rrect.GetRect().GetHeight() / 2.f,
812                                   rrect.GetRect().GetTop() + rrect.GetRect().GetHeight() - BOTTOMW));
813         }
814     } else {
815         y = rrect.GetRect().GetTop() + TOPW;
816     }
817     return Drawing::Point(x, y);
818 }
819 
820 // Return bottom left intersection pos for clipping
GetBLIP(const Drawing::RoundRect & rrect,const Drawing::Point & center) const821 Drawing::Point RSBorder::GetBLIP(const Drawing::RoundRect& rrect, const Drawing::Point& center) const
822 {
823     // inner round rect center point
824     float x = center.GetX();
825     float y = center.GetY();
826     // width/height of inner round rect
827     float width = rrect.GetRect().GetWidth() - LEFTW - RIGHTW;
828     float height = rrect.GetRect().GetHeight() - TOPW - BOTTOMW;
829     if (width > 0) {
830         // kc is linear ratio of inner rect
831         float kc = height / width;
832         if (LEFTW > 0) {
833             // k is linear ratio for external rect (cutting angle at bottom left corner)
834             float k = BOTTOMW / LEFTW;
835             // raduii values of external round rect for calculating clipping point
836             Drawing::Point blRad = rrect.GetCornerRadius(Drawing::RoundRect::BOTTOM_LEFT_POS);
837             Drawing::Point tlRad = rrect.GetCornerRadius(Drawing::RoundRect::TOP_LEFT_POS);
838             Drawing::Point brRad = rrect.GetCornerRadius(Drawing::RoundRect::BOTTOM_RIGHT_POS);
839             // shows what center axis of inner round rect we intersect fist (x or y)
840             if (k <= kc) {
841                 // bottom left and right raduii for inner round rect
842                 float dlx = std::max(blRad.GetX() - LEFTW, 0.f);
843                 float drx = std::max(brRad.GetX() - RIGHTW, 0.f);
844                 // calc delta to prevent overlapping of bottom right corner
845                 x = (dlx > 0) ? (x + std::min(dlx, width / 2.f - drx)) : (x - width / 2.f);
846                 y = rrect.GetRect().GetBottom() - (x - rrect.GetRect().GetLeft()) * k;
847             } else {
848                 // left bottom and top raduii for inner round rect
849                 float dby = std::max(blRad.GetY() - BOTTOMW, 0.f);
850                 float dty = std::max(tlRad.GetY() - TOPW, 0.f);
851                 // calc delta to prevent overlapping of top left corner
852                 y = (dby > 0) ? (y = y - std::min(dby, height / 2.f - dty)) : (y + height / 2.f);
853                 x = rrect.GetRect().GetLeft() + (rrect.GetRect().GetBottom() - y) / k;
854             }
855         } else {
856             x = rrect.GetRect().GetLeft();
857             y = std::min(y + height / 2.f,
858                          std::max(rrect.GetRect().GetTop() + rrect.GetRect().GetHeight() / 2.f,
859                                   rrect.GetRect().GetTop() + TOPW));
860         }
861     } else {
862         y = rrect.GetRect().GetTop() + rrect.GetRect().GetHeight() - BOTTOMW;
863     }
864     return Drawing::Point(x, y);
865 }
866 
867 // Return bottom right intersection pos for clipping
GetBRIP(const Drawing::RoundRect & rrect,const Drawing::Point & center) const868 Drawing::Point RSBorder::GetBRIP(const Drawing::RoundRect& rrect, const Drawing::Point& center) const
869 {
870     // inner round rect center point
871     float x = center.GetX();
872     float y = center.GetY();
873     // width/height of inner round rect
874     float width = rrect.GetRect().GetWidth() - LEFTW - RIGHTW;
875     float height = rrect.GetRect().GetHeight() - TOPW - BOTTOMW;
876     if (width > 0) {
877         // kc is linear ratio of inner rect
878         float kc = height / width;
879         if (RIGHTW > 0) {
880             // k is linear ratio for external rect (cutting angle at bottom right corner)
881             float k = BOTTOMW / RIGHTW;
882             // raduii values of external round rect for calculating clipping point
883             Drawing::Point brRad = rrect.GetCornerRadius(Drawing::RoundRect::BOTTOM_RIGHT_POS);
884             Drawing::Point blRad = rrect.GetCornerRadius(Drawing::RoundRect::BOTTOM_LEFT_POS);
885             Drawing::Point trRad = rrect.GetCornerRadius(Drawing::RoundRect::TOP_RIGHT_POS);
886             // shows what center axis of inner round rect we intersect fist (x or y)
887             if (k <= kc) {
888                 // bottom left and right raduii for inner round rect
889                 float drx = std::max(brRad.GetX() - RIGHTW, 0.f);
890                 float dlx = std::max(blRad.GetX() - LEFTW, 0.f);
891                 // calc delta to prevent overlapping of bottom left corner
892                 x = (drx > 0) ? (x - std::min(drx, width / 2.f - dlx)) : (x + width / 2.f);
893                 y = rrect.GetRect().GetBottom() - (rrect.GetRect().GetRight() - x) * k;
894             } else {
895                 // right bottom and top raduii for inner round rect
896                 float dby = std::max(brRad.GetY() - BOTTOMW, 0.f);
897                 float dty = std::max(trRad.GetY() - TOPW, 0.f);
898                 // calc delta to prevent overlapping of top right corner
899                 y = (dby > 0) ? (y = y - std::min(dby, height / 2.f - dty)) : (y + height / 2.f);
900                 x = rrect.GetRect().GetRight() - (rrect.GetRect().GetBottom() - y) / k;
901             }
902         } else {
903             x = rrect.GetRect().GetLeft() + rrect.GetRect().GetWidth();
904             y = std::min(y + height / 2.f,
905                          std::max(rrect.GetRect().GetTop() + rrect.GetRect().GetHeight() / 2.f,
906                                   rrect.GetRect().GetTop() + TOPW));
907         }
908     } else {
909         y = rrect.GetRect().GetTop() + rrect.GetRect().GetHeight() - BOTTOMW;
910     }
911     return Drawing::Point(x, y);
912 }
913 
ToString() const914 std::string RSBorder::ToString() const
915 {
916     std::stringstream ss;
917     if (colors_.size() > 0) {
918         ss << "colors: ";
919     }
920     for (auto color : colors_) {
921         ss << color.AsArgbInt() << ", ";
922     }
923     if (widths_.size() > 0) {
924         ss << "widths: ";
925     }
926     for (auto width : widths_) {
927         ss << width << ", ";
928     }
929     if (styles_.size() > 0) {
930         ss << "styles: ";
931     }
932     for (auto style : styles_) {
933         ss << static_cast<uint32_t>(style) << ", ";
934     }
935     std::string output = ss.str();
936     return output;
937 }
938 
HasBorder() const939 bool RSBorder::HasBorder() const
940 {
941     return !colors_.empty() && !widths_.empty() && !styles_.empty() &&
942         !std::all_of(colors_.begin(), colors_.end(), [](const Color& color) { return color.GetAlpha() == 0; }) &&
943         !std::all_of(widths_.begin(), widths_.end(), [](const float& width) { return width <= 0.f; }) &&
944         !std::all_of(
945             styles_.begin(), styles_.end(), [](const BorderStyle& style) { return style == BorderStyle::NONE; });
946 }
947 } // namespace Rosen
948 } // namespace OHOS
949