diff --git a/__test__/draw.spec.ts b/__test__/draw.spec.ts index d4508bb4..9dea7734 100644 --- a/__test__/draw.spec.ts +++ b/__test__/draw.spec.ts @@ -16,6 +16,12 @@ test.beforeEach((t) => { t.context.ctx = canvas.getContext('2d')! }) +test('alpha-false', async (t) => { + const canvas = createCanvas(512, 512) + const ctx = canvas.getContext('2d', { alpha: false }) + await snapshotImage(t, { canvas, ctx }) +}) + test('arc', async (t) => { const { ctx } = t.context ctx.beginPath() @@ -284,7 +290,18 @@ test('fillRect', async (t) => { test.todo('fillText') -test.todo('getContextAttributes') +test('getContextAttributes', (t) => { + const defaultCtx = t.context.ctx + const defaultAttrs = defaultCtx.getContextAttributes() + t.is(defaultAttrs.alpha, true) + t.is(defaultAttrs.desynchronized, false) + + const canvas = createCanvas(512, 512) + const ctx = canvas.getContext('2d', { alpha: false }) + const customAttrs = ctx.getContextAttributes() + t.is(customAttrs.alpha, false) + t.is(customAttrs.desynchronized, false) +}) test('getImageData', async (t) => { const { ctx } = t.context @@ -314,7 +331,7 @@ test('isPointInPath', (t) => { t.is(ctx.isPointInPath(path, 50, 1), true) path.rect(40, 40, 20, 20) - t.is(ctx.isPointInPath(50, 50), true) + t.is(ctx.isPointInPath(path, 50, 50), true) t.is(ctx.isPointInPath(path, 50, 50, 'nonzero'), true) t.is(ctx.isPointInPath(path, 50, 50, 'evenodd'), false) }) diff --git a/__test__/image-snapshot.ts b/__test__/image-snapshot.ts index 732be7b7..5b6044af 100644 --- a/__test__/image-snapshot.ts +++ b/__test__/image-snapshot.ts @@ -6,9 +6,9 @@ import { ExecutionContext } from 'ava' const png = PNG() -export async function snapshotImage(t: ExecutionContext) { +export async function snapshotImage(t: ExecutionContext, context = t.context) { // @ts-expect-error - const { canvas } = t.context + const { canvas } = context const image = await canvas.png() const p = join(__dirname, 'snapshots', `${t.title}.png`) diff --git a/__test__/snapshots/alpha-false.png b/__test__/snapshots/alpha-false.png new file mode 100644 index 00000000..5bf5a138 Binary files /dev/null and b/__test__/snapshots/alpha-false.png differ diff --git a/index.d.ts b/index.d.ts index faf06888..593a768f 100644 --- a/index.d.ts +++ b/index.d.ts @@ -73,10 +73,11 @@ export interface SKRSContext2D extends Omit { - getContext(contextId: '2d'): SKRSContext2D + getContext(contextType: '2d', contextAttributes?: { alpha: boolean }): SKRSContext2D png(): Promise } diff --git a/src/ctx.rs b/src/ctx.rs index f8e3a86f..8e4acc18 100644 --- a/src/ctx.rs +++ b/src/ctx.rs @@ -24,6 +24,7 @@ impl From for Error { pub struct Context { pub(crate) surface: Surface, path: Path, + pub alpha: bool, pub(crate) states: Vec, } @@ -101,6 +102,7 @@ impl Context { Property::new(&env, "createLinearGradient")?.with_method(create_linear_gradient), Property::new(&env, "createRadialGradient")?.with_method(create_radial_gradient), Property::new(&env, "drawImage")?.with_method(draw_image), + Property::new(&env, "getContextAttributes")?.with_method(get_context_attributes), Property::new(&env, "isPointInPath")?.with_method(is_point_in_path), Property::new(&env, "isPointInStroke")?.with_method(is_point_in_stroke), Property::new(&env, "ellipse")?.with_method(ellipse), @@ -138,6 +140,7 @@ impl Context { states.push(Context2dRenderingState::default()); Ok(Context { surface, + alpha: true, path: Path::new(), states, }) @@ -262,7 +265,7 @@ impl Context { } #[inline(always)] - fn fill_paint(&self) -> result::Result { + pub fn fill_paint(&self) -> result::Result { let current_paint = &self.states.last().unwrap().paint; let mut paint = current_paint.clone(); paint.set_style(PaintStyle::Fill); @@ -695,6 +698,16 @@ fn draw_image(ctx: CallContext) -> Result { ctx.env.get_undefined() } +#[js_function] +fn get_context_attributes(ctx: CallContext) -> Result { + let this = ctx.this_unchecked::(); + let context_2d = ctx.env.unwrap::(&this)?; + let mut obj = ctx.env.create_object()?; + obj.set_named_property("alpha", ctx.env.get_boolean(context_2d.alpha)?)?; + obj.set_named_property("desynchronized", ctx.env.get_boolean(false)?)?; + Ok(obj) +} + #[js_function(4)] fn is_point_in_path(ctx: CallContext) -> Result { let this = ctx.this_unchecked::(); diff --git a/src/lib.rs b/src/lib.rs index 9e67ef72..47d643ff 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ extern crate napi_derive; use napi::*; +use std::convert::TryInto; use ctx::{Context, ContextData}; use font::{init_font_regexp, FONT_REGEXP}; @@ -74,7 +75,7 @@ fn canvas_element_constructor(ctx: CallContext) -> Result { ctx.env.get_undefined() } -#[js_function(1)] +#[js_function(2)] fn get_context(ctx: CallContext) -> Result { let context_type = ctx.get::(0)?.into_utf8()?; if context_type.as_str()? != "2d" { @@ -83,8 +84,29 @@ fn get_context(ctx: CallContext) -> Result { "Only supports 2d context".to_owned(), )); } + let this = ctx.this_unchecked::(); - this.get_named_property("ctx") + let ctx_js = this.get_named_property::("ctx")?; + let context_2d = ctx.env.unwrap::(&ctx_js)?; + + if ctx.length == 2 { + let attrs = ctx.get::(1)?; + let alpha = attrs + .get_named_property::("alpha")? + .get_value()?; + if !alpha { + let mut fill_paint = context_2d.fill_paint()?; + fill_paint.set_color(255, 255, 255, 255); + let w: f64 = this.get_named_property::("width")?.try_into()?; + let h: f64 = this.get_named_property::("height")?.try_into()?; + context_2d.alpha = false; + context_2d + .surface + .draw_rect(0f32, 0f32, w as f32, h as f32, &fill_paint); + } + } + + Ok(ctx_js) } #[js_function]