• 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 "include/core/SkCanvas.h"
19 #include "include/core/SkPaint.h"
20 #include "include/effects/Sk1DPathEffect.h"
21 #include "include/effects/SkDashPathEffect.h"
22 #include "platform/common/rs_log.h"
23 
24 namespace OHOS {
25 namespace Rosen {
26 namespace {
27 constexpr int PARAM_DOUBLE = 2;
28 constexpr int32_t DASHED_LINE_LENGTH = 3;
29 constexpr float TOP_START = 225.0f;
30 constexpr float TOP_END = 270.0f;
31 constexpr float RIGHT_START = 315.0f;
32 constexpr float RIGHT_END = 0.0f;
33 constexpr float BOTTOM_START = 45.0f;
34 constexpr float BOTTOM_END = 90.0f;
35 constexpr float LEFT_START = 135.0f;
36 constexpr float LEFT_END = 180.0f;
37 constexpr float SWEEP_ANGLE = 45.0f;
38 constexpr float EXTEND = 1024.0f;
39 } // namespace
40 
SetColor(Color color)41 void RSBorder::SetColor(Color color)
42 {
43     colors_.clear();
44     colors_.push_back(color);
45 }
46 
SetWidth(float width)47 void RSBorder::SetWidth(float width)
48 {
49     widths_.clear();
50     widths_.push_back(width);
51 }
52 
SetStyle(BorderStyle style)53 void RSBorder::SetStyle(BorderStyle style)
54 {
55     styles_.clear();
56     styles_.push_back(style);
57 }
58 
GetColor(int idx) const59 Color RSBorder::GetColor(int idx) const
60 {
61     if (colors_.empty()) {
62         return RgbPalette::Transparent();
63     } else if (colors_.size() == 1) {
64         return colors_.front();
65     } else {
66         return colors_.at(idx);
67     }
68 }
69 
GetWidth(int idx) const70 float RSBorder::GetWidth(int idx) const
71 {
72     if (widths_.empty()) {
73         return 0.f;
74     } else if (widths_.size() == 1) {
75         return widths_.front();
76     } else {
77         return widths_.at(idx);
78     }
79 }
80 
GetStyle(int idx) const81 BorderStyle RSBorder::GetStyle(int idx) const
82 {
83     if (styles_.empty()) {
84         return BorderStyle::NONE;
85     } else if (styles_.size() == 1) {
86         return styles_.front();
87     } else {
88         return styles_.at(idx);
89     }
90 }
91 
SetColorFour(Vector4<Color> color)92 void RSBorder::SetColorFour(Vector4<Color> color)
93 {
94     if (color.x_ == color.y_ && color.x_ == color.z_ && color.x_ == color.w_) {
95         return SetColor(color.x_);
96     }
97     colors_ = { color.x_, color.y_, color.z_, color.w_ };
98 }
99 
SetWidthFour(Vector4f width)100 void RSBorder::SetWidthFour(Vector4f width)
101 {
102     if (width.x_ == width.y_ && width.x_ == width.z_ && width.x_ == width.w_) {
103         return SetWidth(width.x_);
104     }
105     widths_ = { width.x_, width.y_, width.z_, width.w_ };
106 }
107 
SetStyleFour(Vector4<uint32_t> style)108 void RSBorder::SetStyleFour(Vector4<uint32_t> style)
109 {
110     if (style.x_ == style.y_ && style.x_ == style.z_ && style.x_ == style.w_) {
111         return SetStyle(static_cast<BorderStyle>(style.x_));
112     }
113     styles_ = { static_cast<BorderStyle>(style.x_), static_cast<BorderStyle>(style.y_),
114                 static_cast<BorderStyle>(style.z_), static_cast<BorderStyle>(style.w_) };
115 }
116 
GetColorFour() const117 Vector4<Color> RSBorder::GetColorFour() const
118 {
119     if (colors_.size() == 4) {
120         return  Vector4<Color>(colors_[0], colors_[1], colors_[2], colors_[3]);
121     } else {
122         return Vector4<Color>(GetColor());
123     }
124 }
125 
GetWidthFour() const126 Vector4f RSBorder::GetWidthFour() const
127 {
128     if (widths_.size() == 4) {
129         return Vector4f(widths_[0], widths_[1], widths_[2], widths_[3]);
130     } else {
131         return Vector4f(GetWidth());
132     }
133 }
134 
GetStyleFour() const135 Vector4<uint32_t> RSBorder::GetStyleFour() const
136 {
137     if (styles_.size() == 4) {
138         return Vector4<uint32_t>(static_cast<uint32_t>(styles_[0]), static_cast<uint32_t>(styles_[1]),
139                                  static_cast<uint32_t>(styles_[2]), static_cast<uint32_t>(styles_[3]));
140     } else {
141         return Vector4<uint32_t>(static_cast<uint32_t>(GetStyle()));
142     }
143 }
144 
SetBorderEffect(SkPaint & paint,BorderStyle style,float width,float spaceBetweenDot,float borderLength)145 void SetBorderEffect(SkPaint& paint, BorderStyle style, float width, float spaceBetweenDot, float borderLength)
146 {
147     if (ROSEN_EQ(width, 0.f)) {
148         return;
149     }
150     if (style == BorderStyle::DOTTED) {
151         SkPath dotPath;
152         if (ROSEN_EQ(spaceBetweenDot, 0.f)) {
153             spaceBetweenDot = width * PARAM_DOUBLE;
154         }
155         dotPath.addCircle(0.0f, 0.0f, width / PARAM_DOUBLE);
156         paint.setPathEffect(SkPath1DPathEffect::Make(dotPath, spaceBetweenDot, 0.0, SkPath1DPathEffect::kRotate_Style));
157     } else if (style == BorderStyle::DASHED) {
158         double addLen = 0.0; // When left < 2 * gap, splits left to gaps.
159         double delLen = 0.0; // When left > 2 * gap, add one dash and shortening them.
160         if (!ROSEN_EQ(borderLength, 0.f)) {
161             float count = borderLength / width;
162             float leftLen = fmod((count - DASHED_LINE_LENGTH), (DASHED_LINE_LENGTH + 1));
163             if (leftLen > DASHED_LINE_LENGTH - 1) {
164                 delLen = (DASHED_LINE_LENGTH + 1 - leftLen) * width /
165                          static_cast<int>((count - DASHED_LINE_LENGTH) / (DASHED_LINE_LENGTH + 1) + 2);
166             } else {
167                 addLen = leftLen * width / static_cast<int>((count - DASHED_LINE_LENGTH) / (DASHED_LINE_LENGTH + 1));
168             }
169         }
170         const float intervals[] = { width * DASHED_LINE_LENGTH - delLen, width + addLen };
171         paint.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0.0));
172     } else {
173         paint.setPathEffect(nullptr);
174     }
175 }
176 
ApplyFillStyle(SkPaint & paint) const177 bool RSBorder::ApplyFillStyle(SkPaint& paint) const
178 {
179     if (colors_.size() != 1) {
180         return false;
181     }
182     if (styles_.size() != 1 || GetStyle() != BorderStyle::SOLID) {
183         return false;
184     }
185     paint.setStyle(SkPaint::Style::kFill_Style);
186     paint.setColor(GetColor().AsArgbInt());
187     return true;
188 }
189 
ApplyPathStyle(SkPaint & paint) const190 bool RSBorder::ApplyPathStyle(SkPaint& paint) const
191 {
192     if (colors_.size() != 1 || widths_.size() != 1 || styles_.size() != 1) {
193         return false;
194     }
195     paint.setStrokeWidth(widths_.front());
196     paint.setStyle(SkPaint::Style::kStroke_Style);
197     paint.setColor(colors_.front().AsArgbInt());
198     SetBorderEffect(paint, GetStyle(), widths_.front(), 0.f, 0.f);
199     return true;
200 }
201 
ApplyFourLine(SkPaint & paint) const202 bool RSBorder::ApplyFourLine(SkPaint& paint) const
203 {
204     if (colors_.size() != 1 || styles_.size() != 1) {
205         return false;
206     }
207     paint.setStyle(SkPaint::Style::kStroke_Style);
208     return true;
209 }
210 
ApplyLineStyle(SkPaint & paint,int borderIdx,float length) const211 bool RSBorder::ApplyLineStyle(SkPaint& paint, int borderIdx, float length) const
212 {
213     if (GetWidth(borderIdx) <= 0.0f) {
214         return false;
215     }
216     float borderWidth = GetWidth(borderIdx);
217     float addLen = (GetStyle(borderIdx) != BorderStyle::DOTTED) ? 0.0f : 0.5f;
218     auto borderLength = length - borderWidth * addLen * PARAM_DOUBLE;
219     int32_t rawNumber = borderLength / (PARAM_DOUBLE * borderWidth);
220     if (rawNumber == 0) {
221         return false;
222     }
223 
224     paint.setStrokeWidth(GetWidth(borderIdx));
225     Color color = GetColor(borderIdx);
226     paint.setColor(color.AsArgbInt());
227     SetBorderEffect(paint, GetStyle(borderIdx), borderWidth, borderLength / rawNumber, borderLength);
228     return true;
229 }
230 
PaintFourLine(SkCanvas & canvas,SkPaint & paint,RectF rect) const231 void RSBorder::PaintFourLine(SkCanvas& canvas, SkPaint& paint, RectF rect) const
232 {
233     float borderLeftWidth = GetWidth(RSBorder::LEFT);
234     float borderRightWidth = GetWidth(RSBorder::RIGHT);
235     float borderTopWidth = GetWidth(RSBorder::TOP);
236     float borderBottomWidth = GetWidth(RSBorder::BOTTOM);
237     if (ApplyLineStyle(paint, RSBorder::LEFT, rect.height_)) {
238         float addLen = (GetStyle(RSBorder::LEFT) != BorderStyle::DOTTED) ? 0.0f : 0.5f;
239         canvas.drawLine(
240             rect.left_ + borderLeftWidth / PARAM_DOUBLE, rect.top_ + addLen * borderTopWidth,
241             rect.left_ + borderLeftWidth / PARAM_DOUBLE, rect.GetBottom() - borderBottomWidth, paint);
242     }
243     if (ApplyLineStyle(paint, RSBorder::RIGHT, rect.height_)) {
244         float addLen = (GetStyle(RSBorder::RIGHT) != BorderStyle::DOTTED) ? 0.0f : 0.5f;
245         canvas.drawLine(
246             rect.GetRight() - borderRightWidth / PARAM_DOUBLE, rect.GetBottom() - addLen * borderBottomWidth,
247             rect.GetRight() - borderRightWidth / PARAM_DOUBLE, rect.top_ + borderTopWidth, paint);
248     }
249     if (ApplyLineStyle(paint, RSBorder::TOP, rect.width_)) {
250         float addLen = (GetStyle(RSBorder::TOP) != BorderStyle::DOTTED) ? 0.0f : 0.5f;
251         canvas.drawLine(
252             rect.GetRight() - addLen * borderRightWidth, rect.top_ + borderTopWidth / PARAM_DOUBLE,
253             rect.left_ + borderLeftWidth, rect.top_ + borderTopWidth / PARAM_DOUBLE, paint);
254     }
255     if (ApplyLineStyle(paint, RSBorder::BOTTOM, rect.width_)) {
256         float addLen = (GetStyle(RSBorder::BOTTOM) != BorderStyle::DOTTED) ? 0.0f : 0.5f;
257         canvas.drawLine(
258             rect.left_ + addLen * borderLeftWidth, rect.GetBottom() - borderBottomWidth / PARAM_DOUBLE,
259             rect.GetRight() - borderRightWidth, rect.GetBottom() - borderBottomWidth / PARAM_DOUBLE, paint);
260     }
261 }
262 
PaintTopPath(SkCanvas & canvas,SkPaint & paint,SkRRect & rrect) const263 void RSBorder::PaintTopPath(SkCanvas& canvas, SkPaint& paint, SkRRect& rrect) const
264 {
265     float offsetX = rrect.rect().x();
266     float offsetY = rrect.rect().y();
267     float width = rrect.rect().width();
268     float leftW = GetWidth(RSBorder::LEFT);
269     float topW = GetWidth(RSBorder::TOP);
270     float rightW = GetWidth(RSBorder::RIGHT);
271     float bottomW = GetWidth(RSBorder::BOTTOM);
272     float x = offsetX + leftW / 2.0f;
273     float y = offsetY + topW / 2.0f;
274     float w = std::max(0.0f, width - (leftW + rightW) / 2.0f);
275     float tlX = std::max(0.0f, rrect.radii(SkRRect::kUpperLeft_Corner).x() - (topW + leftW) / 4.0f);
276     float tlY = std::max(0.0f, rrect.radii(SkRRect::kUpperLeft_Corner).y() - (topW + leftW) / 4.0f);
277     float trX = std::max(0.0f, rrect.radii(SkRRect::kUpperRight_Corner).x() - (topW + rightW) / 4.0f);
278     float trY = std::max(0.0f, rrect.radii(SkRRect::kUpperRight_Corner).y() - (topW + rightW) / 4.0f);
279     if (topW > 0.f) {
280         ApplyLineStyle(paint, RSBorder::TOP, width);
281         auto rectStart = SkRect::MakeXYWH(x, y, tlX * 2.0f, tlY * 2.0f);
282         auto rectEnd = SkRect::MakeXYWH(x + w - trX * 2.0f, y, trX * 2.0f, trY * 2.0f);
283         SkPath topBorder;
284         paint.setStrokeWidth(std::max(std::max(leftW, topW), std::max(rightW, bottomW)));
285         SkAutoCanvasRestore acr(&canvas, true);
286         if (ROSEN_EQ(tlX, 0.f) && !ROSEN_EQ(leftW, 0.f)) {
287             topBorder.moveTo(offsetX, y);
288             topBorder.lineTo(x, y);
289             SkPath topClipPath;
290             topClipPath.moveTo(offsetX - leftW, offsetY - topW);
291             topClipPath.lineTo(offsetX + leftW * EXTEND, offsetY + topW * EXTEND);
292             topClipPath.lineTo(offsetX, offsetY + topW * EXTEND);
293             topClipPath.close();
294             canvas.clipPath(topClipPath, SkClipOp::kDifference, true);
295         }
296         topBorder.arcTo(rectStart, TOP_START, SWEEP_ANGLE, false);
297         topBorder.arcTo(rectEnd, TOP_END, SWEEP_ANGLE + 0.5f, false);
298         if (ROSEN_EQ(trX, 0.f) && !ROSEN_EQ(rightW, 0.f)) {
299             topBorder.lineTo(offsetX + width, y);
300             SkPath topClipPath;
301             topClipPath.moveTo(offsetX + width + rightW, offsetY - topW);
302             topClipPath.lineTo(offsetX + width - rightW * EXTEND, offsetY + topW * EXTEND);
303             topClipPath.lineTo(offsetX + width, offsetY + topW * EXTEND);
304             topClipPath.close();
305             canvas.clipPath(topClipPath, SkClipOp::kDifference, true);
306         }
307         canvas.drawPath(topBorder, paint);
308     }
309 }
310 
PaintRightPath(SkCanvas & canvas,SkPaint & paint,SkRRect & rrect) const311 void RSBorder::PaintRightPath(SkCanvas& canvas, SkPaint& paint, SkRRect& rrect) const
312 {
313     float offsetX = rrect.rect().x();
314     float offsetY = rrect.rect().y();
315     float width = rrect.rect().width();
316     float height = rrect.rect().height();
317     float leftW = GetWidth(RSBorder::LEFT);
318     float topW = GetWidth(RSBorder::TOP);
319     float rightW = GetWidth(RSBorder::RIGHT);
320     float bottomW = GetWidth(RSBorder::BOTTOM);
321     float x = offsetX + leftW / 2.0f;
322     float y = offsetY + topW / 2.0f;
323     float w = std::max(0.0f, width - (leftW + rightW) / 2.0f);
324     float h = std::max(0.0f, height - (topW + bottomW) / 2.0f);
325     float trX = std::max(0.0f, rrect.radii(SkRRect::kUpperRight_Corner).x() - (topW + rightW) / 4.0f);
326     float trY = std::max(0.0f, rrect.radii(SkRRect::kUpperRight_Corner).y() - (topW + rightW) / 4.0f);
327     float brX = std::max(0.0f, rrect.radii(SkRRect::kLowerRight_Corner).x() - (bottomW + rightW) / 4.0f);
328     float brY = std::max(0.0f, rrect.radii(SkRRect::kLowerRight_Corner).y() - (bottomW + rightW) / 4.0f);
329     if (rightW > 0.f) {
330         ApplyLineStyle(paint, RSBorder::RIGHT, height);
331         auto rectStart = SkRect::MakeXYWH(x + w - trX * 2.0f, y, trX * 2.0f, trY * 2.0f);
332         auto rectEnd = SkRect::MakeXYWH(x + w - brX * 2.0f, y + h - brY * 2.0f, brX * 2.0f, brY * 2.0f);
333         SkPath rightBorder;
334         paint.setStrokeWidth(std::max(std::max(leftW, topW), std::max(rightW, bottomW)));
335         SkAutoCanvasRestore acr(&canvas, true);
336         if (ROSEN_EQ(trX, 0.f) && !ROSEN_EQ(topW, 0.f)) {
337             rightBorder.moveTo(offsetX + width - rightW / 2.0f, offsetY);
338             rightBorder.lineTo(x + w - trX * 2.0f, y);
339             SkPath rightClipPath;
340             rightClipPath.moveTo(offsetX + width + rightW, offsetY - topW);
341             rightClipPath.lineTo(offsetX + width - rightW * EXTEND, offsetY + topW * EXTEND);
342             rightClipPath.lineTo(offsetX + width - rightW * EXTEND, offsetY);
343             rightClipPath.close();
344             canvas.clipPath(rightClipPath, SkClipOp::kDifference, true);
345         }
346         rightBorder.arcTo(rectStart, RIGHT_START, SWEEP_ANGLE, false);
347         rightBorder.arcTo(rectEnd, RIGHT_END, SWEEP_ANGLE + 0.5f, false);
348         if (ROSEN_EQ(brX, 0.f) && !ROSEN_EQ(bottomW, 0.f)) {
349             rightBorder.lineTo(offsetX + width - rightW / 2.0f, offsetY + height);
350             SkPath rightClipPath;
351             rightClipPath.moveTo(offsetX + width + rightW, offsetY + height + bottomW);
352             rightClipPath.lineTo(offsetX + width - rightW * EXTEND, offsetY + height - bottomW * EXTEND);
353             rightClipPath.lineTo(offsetX + width - rightW * EXTEND, offsetY + height);
354             rightClipPath.close();
355             canvas.clipPath(rightClipPath, SkClipOp::kDifference, true);
356         }
357         canvas.drawPath(rightBorder, paint);
358     }
359 }
360 
PaintBottomPath(SkCanvas & canvas,SkPaint & paint,SkRRect & rrect) const361 void RSBorder::PaintBottomPath(SkCanvas& canvas, SkPaint& paint, SkRRect& rrect) const
362 {
363     float offsetX = rrect.rect().x();
364     float offsetY = rrect.rect().y();
365     float width = rrect.rect().width();
366     float height = rrect.rect().height();
367     float leftW = GetWidth(RSBorder::LEFT);
368     float topW = GetWidth(RSBorder::TOP);
369     float rightW = GetWidth(RSBorder::RIGHT);
370     float bottomW = GetWidth(RSBorder::BOTTOM);
371     float x = offsetX + leftW / 2.0f;
372     float y = offsetY + topW / 2.0f;
373     float w = std::max(0.0f, width - (leftW + rightW) / 2.0f);
374     float h = std::max(0.0f, height - (topW + bottomW) / 2.0f);
375     float brX = std::max(0.0f, rrect.radii(SkRRect::kLowerRight_Corner).x() - (bottomW + rightW) / 4.0f);
376     float brY = std::max(0.0f, rrect.radii(SkRRect::kLowerRight_Corner).y() - (bottomW + rightW) / 4.0f);
377     float blX = std::max(0.0f, rrect.radii(SkRRect::kLowerLeft_Corner).x() - (bottomW + leftW) / 4.0f);
378     float blY = std::max(0.0f, rrect.radii(SkRRect::kLowerLeft_Corner).y() - (bottomW + leftW) / 4.0f);
379     if (bottomW > 0.f) {
380         ApplyLineStyle(paint, RSBorder::BOTTOM, width);
381         auto rectStart = SkRect::MakeXYWH(x + w - brX * 2.0f, y + h - brY * 2.0f, brX * 2.0f, brY * 2.0f);
382         auto rectEnd = SkRect::MakeXYWH(x, y + h - blY * 2.0f, blX * 2.0f, blY * 2.0f);
383         SkPath bottomBorder;
384         if (GetStyle(RSBorder::BOTTOM) != BorderStyle::DOTTED) {
385             paint.setStrokeWidth(std::max(std::max(leftW, topW), std::max(rightW, bottomW)));
386         }
387         SkAutoCanvasRestore acr(&canvas, true);
388         if (ROSEN_EQ(brX, 0.f) && !ROSEN_EQ(rightW, 0.f)) {
389             bottomBorder.moveTo(offsetX + width, offsetY + height - bottomW / 2.0f);
390             bottomBorder.lineTo(x + w - brX * 2.0f, y + h - brY * 2.0f);
391             SkPath bottomClipPath;
392             bottomClipPath.moveTo(offsetX + width + rightW, offsetY + height + bottomW);
393             bottomClipPath.lineTo(offsetX + width - rightW * EXTEND, offsetY + height - bottomW * EXTEND);
394             bottomClipPath.lineTo(offsetX + width, offsetY + height - bottomW * EXTEND);
395             bottomClipPath.close();
396             canvas.clipPath(bottomClipPath, SkClipOp::kDifference, true);
397         }
398         bottomBorder.arcTo(rectStart, BOTTOM_START, SWEEP_ANGLE, false);
399         bottomBorder.arcTo(rectEnd, BOTTOM_END, SWEEP_ANGLE + 0.5f, false);
400         if (ROSEN_EQ(blX, 0.f) && !ROSEN_EQ(leftW, 0.f)) {
401             bottomBorder.lineTo(offsetX, offsetY + height - bottomW / 2.0f);
402             SkPath bottomClipPath;
403             bottomClipPath.moveTo(offsetX - leftW, offsetY + height + bottomW);
404             bottomClipPath.lineTo(offsetX + leftW * EXTEND, offsetY + height - bottomW * EXTEND);
405             bottomClipPath.lineTo(offsetX, offsetY + height - bottomW * EXTEND);
406             bottomClipPath.close();
407             canvas.clipPath(bottomClipPath, SkClipOp::kDifference, true);
408         }
409         canvas.drawPath(bottomBorder, paint);
410     }
411 }
412 
PaintLeftPath(SkCanvas & canvas,SkPaint & paint,SkRRect & rrect) const413 void RSBorder::PaintLeftPath(SkCanvas& canvas, SkPaint& paint, SkRRect& rrect) const
414 {
415     float offsetX = rrect.rect().x();
416     float offsetY = rrect.rect().y();
417     float height = rrect.rect().height();
418     float leftW = GetWidth(RSBorder::LEFT);
419     float topW = GetWidth(RSBorder::TOP);
420     float rightW = GetWidth(RSBorder::RIGHT);
421     float bottomW = GetWidth(RSBorder::BOTTOM);
422     float x = offsetX + leftW / 2.0f;
423     float y = offsetY + topW / 2.0f;
424     float h = std::max(0.0f, height - (topW + bottomW) / 2.0f);
425     float tlX = std::max(0.0f, rrect.radii(SkRRect::kUpperLeft_Corner).x() - (topW + leftW) / 4.0f);
426     float tlY = std::max(0.0f, rrect.radii(SkRRect::kUpperLeft_Corner).y() - (topW + leftW) / 4.0f);
427     float blX = std::max(0.0f, rrect.radii(SkRRect::kLowerLeft_Corner).x() - (bottomW + leftW) / 4.0f);
428     float blY = std::max(0.0f, rrect.radii(SkRRect::kLowerLeft_Corner).y() - (bottomW + leftW) / 4.0f);
429     if (leftW > 0.f) {
430         ApplyLineStyle(paint, RSBorder::LEFT, height);
431         auto rectStart = SkRect::MakeXYWH(x, y + h - blY * 2.0f, blX * 2.0f, blY * 2.0f);
432         auto rectEnd = SkRect::MakeXYWH(x, y, tlX * 2.0f, tlY * 2.0f);
433         SkPath leftBorder;
434         if (GetStyle(RSBorder::LEFT) != BorderStyle::DOTTED) {
435             paint.setStrokeWidth(std::max(std::max(leftW, topW), std::max(rightW, bottomW)));
436         }
437         SkAutoCanvasRestore acr(&canvas, true);
438         if (ROSEN_EQ(blX, 0.f) && !ROSEN_EQ(bottomW, 0.f)) {
439             leftBorder.moveTo(offsetX + leftW / 2.0f, offsetY + height);
440             leftBorder.lineTo(x, y + h - blY * 2.0f);
441             SkPath leftClipPath;
442             leftClipPath.moveTo(offsetX - leftW, offsetY + height + bottomW);
443             leftClipPath.lineTo(offsetX + leftW * EXTEND, offsetY + height - bottomW * EXTEND);
444             leftClipPath.lineTo(offsetX + leftW * EXTEND, offsetY + height);
445             leftClipPath.close();
446             canvas.clipPath(leftClipPath, SkClipOp::kDifference, true);
447         }
448         leftBorder.arcTo(rectStart, LEFT_START, SWEEP_ANGLE, false);
449         leftBorder.arcTo(rectEnd, LEFT_END, SWEEP_ANGLE + 0.5f, false);
450         if (ROSEN_EQ(tlX, 0.f) && !ROSEN_EQ(topW, 0.f)) {
451             leftBorder.lineTo(offsetX + leftW / 2.0f, offsetY);
452             SkPath topClipPath;
453             topClipPath.moveTo(offsetX - leftW, offsetY - topW);
454             topClipPath.lineTo(offsetX + leftW * EXTEND, offsetY + topW * EXTEND);
455             topClipPath.lineTo(offsetX + leftW * EXTEND, offsetY);
456             topClipPath.close();
457             canvas.clipPath(topClipPath, SkClipOp::kDifference, true);
458         }
459         canvas.drawPath(leftBorder, paint);
460     }
461 }
462 
ToString() const463 std::string RSBorder::ToString() const
464     {
465         std::stringstream ss;
466         if (colors_.size() > 0) {
467             ss << "colors: ";
468         }
469         for (auto color : colors_) {
470             ss << color.AsArgbInt() << ", ";
471         }
472         if (widths_.size() > 0) {
473             ss << "widths: ";
474         }
475         for (auto width : widths_) {
476             ss << width << ", ";
477         }
478         if (styles_.size() > 0) {
479             ss << "styles: ";
480         }
481         for (auto style : styles_) {
482             ss << static_cast<uint32_t>(style) << ", ";
483         }
484         std::string output = ss.str();
485         return output;
486     }
487 } // namespace Rosen
488 } // namespace OHOS
489