Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: roundRect #601

Merged
merged 1 commit into from
Jan 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions __test__/draw.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -847,6 +847,42 @@ test('strokeRect', async (t) => {
await snapshotImage(t)
})

test('strokeRoundRect', async (t) => {
const canvas = createCanvas(700, 300)
const ctx = canvas.getContext('2d')
// Rounded rectangle with zero radius (specified as a number)
ctx.strokeStyle = 'red'
ctx.beginPath()
ctx.roundRect(10, 20, 150, 100, 0)
ctx.stroke()

// Rounded rectangle with 40px radius (single element list)
ctx.strokeStyle = 'blue'
ctx.beginPath()
ctx.roundRect(10, 20, 150, 100, [40])
ctx.stroke()

// Rounded rectangle with 2 different radii
ctx.strokeStyle = 'orange'
ctx.beginPath()
ctx.roundRect(10, 150, 150, 100, [10, 40])
ctx.stroke()

// Rounded rectangle with four different radii
ctx.strokeStyle = 'green'
ctx.beginPath()
ctx.roundRect(400, 20, 200, 100, [0, 30, 50, 60])
ctx.stroke()

// Same rectangle drawn backwards
ctx.strokeStyle = 'magenta'
ctx.beginPath()
ctx.roundRect(400, 150, -200, 100, [0, 30, 50, 60])
ctx.stroke()

await snapshotImage(t, { canvas, ctx })
})

test('strokeText', async (t) => {
const { ctx, canvas } = t.context
ctx.fillStyle = 'yellow'
Expand Down
Binary file added __test__/snapshots/strokeRoundRect.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ export class Path2D {
moveTo(x: number, y: number): void
quadraticCurveTo(cpx: number, cpy: number, x: number, y: number): void
rect(x: number, y: number, w: number, h: number): void
roundRect(x: number, y: number, w: number, h: number, radii?: number | number[]): void

// PathKit methods
op(path: Path2D, operation: PathOp): Path2D
Expand Down
21 changes: 21 additions & 0 deletions skia-c/skia_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -967,6 +967,27 @@ extern "C"
return result;
}

void skiac_path_round_rect(
skiac_path *c_path,
SkScalar x,
SkScalar y,
SkScalar width,
SkScalar height,
SkScalar *radii,
bool clockwise)
{
auto path = PATH_CAST;
SkScalar radii_vec[8];
for (size_t i = 0; i < 4; i++)
{
radii_vec[i * 2] = radii[i];
radii_vec[i * 2 + 1] = radii[i];
}
SkRect rect = SkRect::MakeXYWH(x, y, width, height);
auto ccw = clockwise ? SkPathDirection::kCW : SkPathDirection::kCCW;
path->addRoundRect(rect, radii_vec, ccw);
}

// PathEffect

skiac_path_effect *skiac_path_effect_make_dash_path(const float *intervals, int count, float phase)
Expand Down
8 changes: 8 additions & 0 deletions skia-c/skia_c.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,14 @@ extern "C"
bool skiac_path_is_empty(skiac_path *c_path);
bool skiac_path_hit_test(skiac_path *c_path, float x, float y, int type);
bool skiac_path_stroke_hit_test(skiac_path *c_path, float x, float y, float stroke_w);
void skiac_path_round_rect(
skiac_path *c_path,
SkScalar x,
SkScalar y,
SkScalar width,
SkScalar height,
SkScalar *radii,
bool clockwise);

// PathEffect
skiac_path_effect *skiac_path_effect_make_dash_path(const float *intervals, int count, float phase);
Expand Down
45 changes: 45 additions & 0 deletions src/ctx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,10 @@ impl Context {
self.path.add_rect(x, y, width, height);
}

pub fn round_rect(&mut self, x: f32, y: f32, width: f32, height: f32, radii: [f32; 4]) {
self.path.round_rect(x, y, width, height, radii);
}

pub fn save(&mut self) {
self.surface.canvas.save();
self.states.push(self.state.clone());
Expand Down Expand Up @@ -1294,6 +1298,47 @@ impl CanvasRenderingContext2D {
.rect(x as f32, y as f32, width as f32, height as f32);
}

#[napi]
pub fn round_rect(
&mut self,
x: f64,
y: f64,
width: f64,
height: f64,
radii: Either3<f64, Vec<f64>, Undefined>,
) {
// https://github.com/chromium/chromium/blob/111.0.5520.1/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.cc#L579
let radii_array: [f32; 4] = match radii {
Either3::A(radii) => [radii as f32; 4],
Either3::B(radii_vec) => match radii_vec.len() {
0 => [0f32; 4],
1 => [radii_vec[0] as f32; 4],
2 => [
radii_vec[0] as f32,
radii_vec[1] as f32,
radii_vec[0] as f32,
radii_vec[1] as f32,
],
3 => [
radii_vec[0] as f32,
radii_vec[1] as f32,
radii_vec[1] as f32,
radii_vec[2] as f32,
],
_ => [
radii_vec[0] as f32,
radii_vec[1] as f32,
radii_vec[2] as f32,
radii_vec[3] as f32,
],
},
Either3::C(_) => [0f32; 4],
};
self
.context
.round_rect(x as f32, y as f32, width as f32, height as f32, radii_array);
}

#[napi]
pub fn fill(
&mut self,
Expand Down
40 changes: 40 additions & 0 deletions src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,46 @@ impl Path {
.add_rect(x as f32, y as f32, width as f32, height as f32);
}

#[napi]
pub fn round_rect(
&mut self,
x: f64,
y: f64,
width: f64,
height: f64,
radii: Either3<f64, Vec<f64>, Undefined>,
) {
let radii_array: [f32; 4] = match radii {
Either3::A(radii) => [radii as f32; 4],
Either3::B(radii_vec) => match radii_vec.len() {
0 => [0f32; 4],
1 => [radii_vec[0] as f32; 4],
2 => [
radii_vec[0] as f32,
radii_vec[1] as f32,
radii_vec[0] as f32,
radii_vec[1] as f32,
],
3 => [
radii_vec[0] as f32,
radii_vec[1] as f32,
radii_vec[1] as f32,
radii_vec[2] as f32,
],
_ => [
radii_vec[0] as f32,
radii_vec[1] as f32,
radii_vec[2] as f32,
radii_vec[3] as f32,
],
},
Either3::C(_) => [0f32; 4],
};
self
.inner
.round_rect(x as f32, y as f32, width as f32, height as f32, radii_array);
}

#[napi]
pub fn op(&mut self, other: &Path, op: PathOp) -> &Self {
self.inner.op(&other.inner, op.into());
Expand Down
38 changes: 38 additions & 0 deletions src/sk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,16 @@ pub mod ffi {
pub fn skiac_path_stroke_hit_test(path: *mut skiac_path, x: f32, y: f32, stroke_w: f32)
-> bool;

pub fn skiac_path_round_rect(
path: *mut skiac_path,
x: f32,
y: f32,
width: f32,
height: f32,
radii: *const f32,
clockwise: bool,
);

pub fn skiac_path_effect_make_dash_path(
intervals: *const f32,
count: i32,
Expand Down Expand Up @@ -2680,6 +2690,34 @@ impl Path {
unsafe { ffi::skiac_path_dash(self.0, on, off, phase) }
}

pub fn round_rect(
&mut self,
mut x: f32,
mut y: f32,
mut width: f32,
mut height: f32,
mut radii: [f32; 4],
) {
// https://github.com/chromium/chromium/blob/111.0.5520.1/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.cc#L601
let mut clockwise = true;
if width < 0f32 {
clockwise = false;
x += width;
width = -width;
radii.swap(0, 1);
radii.swap(2, 3);
}
if height < 0f32 {
clockwise = !clockwise;
y += height;
height = -height;
radii.swap(0, 2);
radii.swap(1, 3);
}
unsafe { ffi::skiac_path_round_rect(self.0, x, y, width, height, radii.as_ptr(), clockwise) };
unsafe { ffi::skiac_path_move_to(self.0, x, y) };
}

fn ellipse_helper(&mut self, x: f32, y: f32, rx: f32, ry: f32, start_angle: f32, end_angle: f32) {
let sweep_degrees = radians_to_degrees(end_angle - start_angle);
let start_degrees = radians_to_degrees(start_angle);
Expand Down