diff --git a/__test__/draw.spec.ts b/__test__/draw.spec.ts index e13dfff2..72caf727 100644 --- a/__test__/draw.spec.ts +++ b/__test__/draw.spec.ts @@ -408,9 +408,44 @@ test('save-restore', async (t) => { await snapshotImage(t) }) -test.todo('rotate') +test('rotate', async (t) => { + const { ctx } = t.context + // Point of transform origin + ctx.arc(0, 0, 5, 0, 2 * Math.PI) + ctx.fillStyle = 'blue' + ctx.fill() -test.todo('scale') + // Non-rotated rectangle + ctx.fillStyle = 'gray' + ctx.fillRect(100, 0, 80, 20) + + // Rotated rectangle + ctx.rotate((45 * Math.PI) / 180) + ctx.fillStyle = 'red' + ctx.fillRect(100, 0, 80, 20) + // Reset transformation matrix to the identity matrix + ctx.setTransform(1, 0, 0, 1, 0, 0) + + ctx.fillStyle = 'hotpink' + ctx.fillRect(100, 50, 80, 20) + await snapshotImage(t) +}) + +test('scale', async (t) => { + const { ctx } = t.context + // Scaled rectangle + ctx.scale(9, 3) + ctx.fillStyle = 'red' + ctx.fillRect(10, 10, 8, 20) + + // Reset current transformation matrix to the identity matrix + ctx.setTransform(1, 0, 0, 1, 0, 0) + + // Non-scaled rectangle + ctx.fillStyle = 'gray' + ctx.fillRect(10, 10, 8, 20) + await snapshotImage(t) +}) test('setLineDash', async (t) => { const { ctx } = t.context diff --git a/__test__/snapshots/rotate.png b/__test__/snapshots/rotate.png new file mode 100644 index 00000000..0b6fe359 Binary files /dev/null and b/__test__/snapshots/rotate.png differ diff --git a/__test__/snapshots/scale.png b/__test__/snapshots/scale.png new file mode 100644 index 00000000..d160004e Binary files /dev/null and b/__test__/snapshots/scale.png differ diff --git a/skia-c/skia_c.cpp b/skia-c/skia_c.cpp index b75b160a..2917430c 100644 --- a/skia-c/skia_c.cpp +++ b/skia-c/skia_c.cpp @@ -205,6 +205,11 @@ extern "C" CANVAS_CAST->translate(dx, dy); } + void skiac_canvas_rotate(skiac_canvas *c_canvas, float degrees) + { + CANVAS_CAST->rotate(degrees); + } + skiac_matrix *skiac_canvas_get_total_transform_matrix(skiac_canvas *c_canvas) { auto martix = CANVAS_CAST->getTotalMatrix(); diff --git a/skia-c/skia_c.hpp b/skia-c/skia_c.hpp index a230da7d..6eaa9977 100644 --- a/skia-c/skia_c.hpp +++ b/skia-c/skia_c.hpp @@ -82,6 +82,7 @@ extern "C" void skiac_canvas_concat(skiac_canvas *c_canvas, skiac_transform c_ts); void skiac_canvas_scale(skiac_canvas *c_canvas, float sx, float sy); void skiac_canvas_translate(skiac_canvas *c_canvas, float dx, float dy); + void skiac_canvas_rotate(skiac_canvas *c_canvas, float degrees); skiac_transform skiac_canvas_get_total_transform(skiac_canvas *c_canvas); skiac_matrix *skiac_canvas_get_total_transform_matrix(skiac_canvas *c_canvas); void skiac_canvas_draw_color(skiac_canvas *c_canvas, float r, float g, float b, float a); diff --git a/src/ctx.rs b/src/ctx.rs index 7dea3524..323a4a10 100644 --- a/src/ctx.rs +++ b/src/ctx.rs @@ -1,4 +1,5 @@ use std::convert::TryInto; +use std::f32::consts::PI; use std::mem; use std::result; use std::str::FromStr; @@ -101,6 +102,7 @@ impl Context { Property::new(&env, "rect")?.with_method(rect), Property::new(&env, "resetTransform")?.with_method(reset_transform), Property::new(&env, "restore")?.with_method(restore), + Property::new(&env, "rotate")?.with_method(rotate), Property::new(&env, "save")?.with_method(save), Property::new(&env, "scale")?.with_method(scale), Property::new(&env, "setLineDash")?.with_method(set_line_dash), @@ -558,6 +560,17 @@ fn restore(ctx: CallContext) -> Result { ctx.env.get_undefined() } +#[js_function(1)] +fn rotate(ctx: CallContext) -> Result { + let this = ctx.this_unchecked::(); + let context_2d = ctx.env.unwrap::(&this)?; + + let angle: f64 = ctx.get::(0)?.try_into()?; + context_2d.path.transform(&Transform::rotate(-angle as f32)); + context_2d.surface.canvas.rotate(angle as f32 / PI * 180f32); + ctx.env.get_undefined() +} + #[js_function(4)] fn clear_rect(ctx: CallContext) -> Result { let this = ctx.this_unchecked::(); diff --git a/src/sk.rs b/src/sk.rs index 4c18caee..cf7bc642 100644 --- a/src/sk.rs +++ b/src/sk.rs @@ -150,6 +150,8 @@ mod ffi { pub fn skiac_canvas_translate(canvas: *mut skiac_canvas, dx: f32, dy: f32); + pub fn skiac_canvas_rotate(canvas: *mut skiac_canvas, degrees: f32); + pub fn skiac_canvas_get_total_transform(canvas: *mut skiac_canvas) -> skiac_transform; pub fn skiac_canvas_get_total_transform_matrix(canvas: *mut skiac_canvas) -> *mut skiac_matrix; @@ -1131,6 +1133,13 @@ impl Canvas { } } + #[inline] + pub fn rotate(&mut self, degrees: f32) { + unsafe { + ffi::skiac_canvas_rotate(self.0, degrees); + } + } + #[inline] pub fn get_transform(&self) -> Transform { unsafe { ffi::skiac_canvas_get_total_transform(self.0).into() } @@ -1873,10 +1882,26 @@ pub struct Transform { } impl Transform { + #[inline] pub fn new(a: f32, b: f32, c: f32, d: f32, e: f32, f: f32) -> Self { Transform { a, b, c, d, e, f } } + #[inline] + pub fn rotate(radians: f32) -> Self { + let sin_v = radians.sin(); + let cos_v = radians.cos(); + + Self { + a: cos_v, + b: -sin_v, + c: 0f32, + d: sin_v, + e: cos_v, + f: 0f32, + } + } + #[inline] /// | A B C | | A/X B/X C/X | /// | D E F | -> | D/X E/X F/X | for X != 0