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