Skip to content

Commit be596c4

Browse files
committed
Add support for nonuniform rounded rects
1 parent 1d57c8e commit be596c4

File tree

9 files changed

+120
-19
lines changed

9 files changed

+120
-19
lines changed

package/cpp/api/JsiSkRRect.h

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,33 @@ class JsiSkRRect : public JsiSkWrappingSharedPtrHostObject<SkRRect> {
6161
} else {
6262
auto rect =
6363
JsiSkRect::fromValue(runtime, object.getProperty(runtime, "rect"));
64-
auto rx = object.getProperty(runtime, "rx").asNumber();
65-
auto ry = object.getProperty(runtime, "ry").asNumber();
66-
return std::make_shared<SkRRect>(SkRRect::MakeRectXY(*rect, rx, ry));
64+
if (!object.getProperty(runtime, "rx").isUndefined()) {
65+
auto rx = object.getProperty(runtime, "rx").asNumber();
66+
auto ry = object.getProperty(runtime, "ry").asNumber();
67+
return std::make_shared<SkRRect>(SkRRect::MakeRectXY(*rect, rx, ry));
68+
} else if (object.getProperty(runtime, "topLeft").isObject() &&
69+
object.getProperty(runtime, "topRight").isObject() &&
70+
object.getProperty(runtime, "bottomRight").isObject() &&
71+
object.getProperty(runtime, "bottomLeft").isObject()) {
72+
std::vector<SkPoint> points;
73+
std::shared_ptr<SkPoint> topLeft = JsiSkPoint::fromValue(
74+
runtime, object.getProperty(runtime, "topLeft").asObject(runtime));
75+
std::shared_ptr<SkPoint> topRight = JsiSkPoint::fromValue(
76+
runtime, object.getProperty(runtime, "topRight").asObject(runtime));
77+
std::shared_ptr<SkPoint> bottomRight = JsiSkPoint::fromValue(
78+
runtime, object.getProperty(runtime, "bottomRight").asObject(runtime));
79+
std::shared_ptr<SkPoint> bottomLeft = JsiSkPoint::fromValue(
80+
runtime, object.getProperty(runtime, "bottomLeft").asObject(runtime));
81+
points.push_back(*topLeft.get());
82+
points.push_back(*topRight.get());
83+
points.push_back(*bottomRight.get());
84+
points.push_back(*bottomLeft.get());
85+
auto rrect = SkRRect::MakeEmpty();
86+
rrect.setRectRadii(*rect, points.data());
87+
return std::make_shared<SkRRect>(rrect);
88+
} else {
89+
throw jsi::JSError(runtime, "Invalid RRect object");
90+
}
6791
}
6892
}
6993

package/src/dom/types/Common.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type {
44
BlendMode,
55
Color,
66
InputMatrix,
7+
InputRRect,
78
PaintStyle,
89
SkPaint,
910
SkPath,
@@ -48,7 +49,7 @@ export interface RRectCtor extends RectCtor {
4849
}
4950

5051
export type RectDef = RectCtor | { rect: SkRect };
51-
export type RRectDef = RRectCtor | { rect: SkRRect };
52+
export type RRectDef = RRectCtor | { rect: InputRRect };
5253

5354
export interface PointCircleDef {
5455
c?: Vector;

package/src/renderer/__tests__/e2e/Rect.spec.tsx

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
import { surface } from "../setup";
1+
import React from "react";
2+
3+
import { checkImage, docPath } from "../../../__tests__/setup";
4+
import { RoundedRect } from "../../components";
5+
import { importSkia, surface } from "../setup";
26

37
describe("Rects and rounded rects", () => {
48
it("The rounded rectangle radii should be scale to its maximum value", async () => {
@@ -26,4 +30,44 @@ describe("Rects and rounded rects", () => {
2630
});
2731
expect(result3).toEqual({ rx: 10, ry: 20 });
2832
});
33+
it("Should draw a rounded rect with uniform values (1)", async () => {
34+
const { width } = surface;
35+
const r = width * 0.2;
36+
const image = await surface.draw(
37+
<RoundedRect
38+
x={0}
39+
y={0}
40+
width={width}
41+
height={width}
42+
r={r}
43+
color="lightblue"
44+
/>
45+
);
46+
checkImage(image, docPath("rrect/uniform.png"));
47+
});
48+
it("Should draw a rounded rect with uniform values (2)", async () => {
49+
const { Skia } = importSkia();
50+
const { width } = surface;
51+
const r = width * 0.2;
52+
const rrct = Skia.RRectXY(Skia.XYWHRect(0, 0, width, width), r, r);
53+
const image = await surface.draw(
54+
<RoundedRect rect={rrct} color="lightblue" />
55+
);
56+
checkImage(image, docPath("rrect/uniform.png"));
57+
});
58+
it("Should draw a rounded rect with uniform values (3)", async () => {
59+
const { width } = surface;
60+
const r = width * 0.2;
61+
const rrct = {
62+
rect: { x: 0, y: 0, width, height: width },
63+
topLeft: { x: r, y: r },
64+
topRight: { x: r, y: r },
65+
bottomRight: { x: r, y: r },
66+
bottomLeft: { x: r, y: r },
67+
};
68+
const image = await surface.draw(
69+
<RoundedRect rect={rrct} color="lightblue" />
70+
);
71+
checkImage(image, docPath("rrect/uniform.png"));
72+
});
2973
});

package/src/skia/types/Canvas.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import type { SkPath } from "./Path";
55
import type { SkImage, MipmapMode, FilterMode, ImageInfo } from "./Image";
66
import type { SkSVG } from "./SVG";
77
import type { SkColor } from "./Color";
8-
import type { SkRRect } from "./RRect";
8+
import type { InputRRect } from "./RRect";
99
import type { BlendMode } from "./Paint/BlendMode";
1010
import type { SkPoint, PointMode } from "./Point";
1111
import type { InputMatrix } from "./Matrix";
@@ -278,7 +278,7 @@ export interface SkCanvas {
278278
* @param rrect
279279
* @param paint
280280
*/
281-
drawRRect(rrect: SkRRect, paint: SkPaint): void;
281+
drawRRect(rrect: InputRRect, paint: SkPaint): void;
282282

283283
/**
284284
* Draws RRect outer and inner using clip, Matrix, and Paint paint.
@@ -287,7 +287,7 @@ export interface SkCanvas {
287287
* @param inner
288288
* @param paint
289289
*/
290-
drawDRRect(outer: SkRRect, inner: SkRRect, paint: SkPaint): void;
290+
drawDRRect(outer: InputRRect, inner: InputRRect, paint: SkPaint): void;
291291

292292
/**
293293
* Draws an oval bounded by the given rectangle using the current clip, current matrix,
@@ -479,7 +479,7 @@ export interface SkCanvas {
479479
* @param op
480480
* @param doAntiAlias
481481
*/
482-
clipRRect(rrect: SkRRect, op: ClipOp, doAntiAlias: boolean): void;
482+
clipRRect(rrect: InputRRect, op: ClipOp, doAntiAlias: boolean): void;
483483

484484
/**
485485
* Replaces current matrix with m premultiplied with the existing matrix.

package/src/skia/types/Path/Path.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { SkRect } from "../Rect";
22
import type { SkPoint } from "../Point";
3-
import type { SkRRect } from "../RRect";
3+
import type { InputRRect } from "../RRect";
44
import type { StrokeJoin, StrokeCap } from "../Paint";
55
import type { InputMatrix, SkMatrix } from "../Matrix";
66
import type { SkJSIInstance } from "../JsiInstance";
@@ -439,7 +439,7 @@ export interface SkPath extends SkJSIInstance<"Path"> {
439439
* @param rrect
440440
* @param isCCW
441441
*/
442-
addRRect(rrect: SkRRect, isCCW?: boolean): SkPath;
442+
addRRect(rrect: InputRRect, isCCW?: boolean): SkPath;
443443

444444
/** Appends src to SkPath, transformed by matrix. Transformed curves may have
445445
different verbs, SkPoint, and conic weights.

package/src/skia/types/RRect.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { SkPoint } from "./Point";
12
import type { SkRect } from "./Rect";
23

34
export interface SkRRect {
@@ -6,6 +7,16 @@ export interface SkRRect {
67
readonly ry: number;
78
}
89

10+
export interface NonUniformRRect {
11+
readonly rect: SkRect;
12+
readonly topLeft: SkPoint;
13+
readonly topRight: SkPoint;
14+
readonly bottomRight: SkPoint;
15+
readonly bottomLeft: SkPoint;
16+
}
17+
18+
export type InputRRect = SkRRect | NonUniformRRect;
19+
920
// We have an issue to check property existence on JSI backed instances
1021
export const isRRect = (def: SkRect | SkRRect): def is SkRRect =>
1122
// eslint-disable-next-line @typescript-eslint/no-explicit-any

package/src/skia/web/JsiSkCanvas.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import type {
1919
SkPicture,
2020
SkPoint,
2121
SkRect,
22-
SkRRect,
22+
InputRRect,
2323
SkSVG,
2424
SkTextBlob,
2525
SkVertices,
@@ -235,14 +235,14 @@ export class JsiSkCanvas
235235
);
236236
}
237237

238-
drawRRect(rrect: SkRRect, paint: SkPaint) {
238+
drawRRect(rrect: InputRRect, paint: SkPaint) {
239239
this.ref.drawRRect(
240240
JsiSkRRect.fromValue(this.CanvasKit, rrect),
241241
JsiSkPaint.fromValue(paint)
242242
);
243243
}
244244

245-
drawDRRect(outer: SkRRect, inner: SkRRect, paint: SkPaint) {
245+
drawDRRect(outer: InputRRect, inner: InputRRect, paint: SkPaint) {
246246
this.ref.drawDRRect(
247247
JsiSkRRect.fromValue(this.CanvasKit, outer),
248248
JsiSkRRect.fromValue(this.CanvasKit, inner),
@@ -367,7 +367,7 @@ export class JsiSkCanvas
367367
);
368368
}
369369

370-
clipRRect(rrect: SkRRect, op: ClipOp, doAntiAlias: boolean) {
370+
clipRRect(rrect: InputRRect, op: ClipOp, doAntiAlias: boolean) {
371371
this.ref.clipRRect(
372372
JsiSkRRect.fromValue(this.CanvasKit, rrect),
373373
getEnum(this.CanvasKit.PathOp, op),

package/src/skia/web/JsiSkPath.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import type {
99
SkPath,
1010
SkPoint,
1111
SkRect,
12-
SkRRect,
12+
InputRRect,
1313
StrokeOpts,
1414
} from "../types";
1515

@@ -285,7 +285,7 @@ export class JsiSkPath extends HostObject<Path, "Path"> implements SkPath {
285285
return this;
286286
}
287287

288-
addRRect(rrect: SkRRect, isCCW?: boolean) {
288+
addRRect(rrect: InputRRect, isCCW?: boolean) {
289289
this.ref.addRRect(JsiSkRRect.fromValue(this.CanvasKit, rrect), isCCW);
290290
return this;
291291
}

package/src/skia/web/JsiSkRRect.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { CanvasKit, RRect } from "canvaskit-wasm";
22

3-
import type { SkRect, SkRRect } from "../types";
3+
import type { InputRRect, SkRect, SkRRect } from "../types";
44

55
import { BaseHostObject } from "./Host";
66
import { JsiSkRect } from "./JsiSkRect";
@@ -13,10 +13,31 @@ export class JsiSkRRect
1313
// Float32Array
1414
};
1515

16-
static fromValue(CanvasKit: CanvasKit, rect: SkRRect) {
16+
static fromValue(CanvasKit: CanvasKit, rect: InputRRect) {
1717
if (rect instanceof JsiSkRect) {
1818
return rect.ref;
1919
}
20+
if (
21+
"topLeft" in rect &&
22+
"topRight" in rect &&
23+
"bottomRight" in rect &&
24+
"bottomLeft" in rect
25+
) {
26+
return Float32Array.of(
27+
rect.rect.x,
28+
rect.rect.y,
29+
rect.rect.x + rect.rect.width,
30+
rect.rect.y + rect.rect.height,
31+
rect.topLeft.x,
32+
rect.topLeft.y,
33+
rect.topRight.x,
34+
rect.topRight.y,
35+
rect.bottomRight.x,
36+
rect.bottomRight.y,
37+
rect.bottomLeft.x,
38+
rect.bottomLeft.y
39+
);
40+
}
2041
return CanvasKit.RRectXY(
2142
JsiSkRect.fromValue(CanvasKit, rect.rect),
2243
rect.rx,

0 commit comments

Comments
 (0)