diff --git a/__test__/filter.spec.ts b/__test__/filter.spec.ts index c355ac9a..81391aaf 100644 --- a/__test__/filter.spec.ts +++ b/__test__/filter.spec.ts @@ -110,6 +110,16 @@ test('filter-combine-contrast-brightness', async (t) => { await snapshotImage(t) }) +test('filter-save-restore', async (t) => { + const { ctx } = t.context + ctx.filter = 'none' + ctx.save() + ctx.filter = 'invert(100%)' + ctx.restore() + ctx.drawImage(await createImage('filter-invert.jpeg'), 0, 0) + await snapshotImage(t) +}) + async function createImage(name: string) { const i = new Image() i.src = await fs.readFile(join(__dirname, 'fixtures', name)) diff --git a/__test__/snapshots/filter-save-restore.png b/__test__/snapshots/filter-save-restore.png new file mode 100644 index 00000000..1a695b47 Binary files /dev/null and b/__test__/snapshots/filter-save-restore.png differ diff --git a/skia-c/skia_c.cpp b/skia-c/skia_c.cpp index fe4f0678..9d789d74 100644 --- a/skia-c/skia_c.cpp +++ b/skia-c/skia_c.cpp @@ -1331,6 +1331,12 @@ extern "C" } } + void skiac_image_filter_ref(skiac_image_filter *c_image_filter) + { + auto image_filter = IMAGE_FILTER_CAST; + image_filter->ref(); + } + void skiac_image_filter_destroy(skiac_image_filter *c_image_filter) { auto image_filter = IMAGE_FILTER_CAST; diff --git a/src/ctx.rs b/src/ctx.rs index a4bcbb2c..5cad2dfd 100644 --- a/src/ctx.rs +++ b/src/ctx.rs @@ -49,8 +49,6 @@ pub struct Context { pub height: u32, pub color_space: ColorSpace, pub stream: Option, - pub filter: Option, - filters_string: String, } impl Context { @@ -267,8 +265,6 @@ impl Context { height, color_space, stream: Some(stream), - filter: None, - filters_string: "none".to_owned(), }) } @@ -291,8 +287,6 @@ impl Context { height, color_space, stream: None, - filter: None, - filters_string: "none".to_owned(), }) } @@ -571,7 +565,7 @@ impl Context { .ok_or_else(|| SkError::Generic("Make line dash path effect failed".to_string()))?; paint.set_path_effect(&path_effect); } - if let Some(f) = &self.filter { + if let Some(f) = &self.state.filter { paint.set_image_filter(f); } Ok(paint) @@ -579,13 +573,13 @@ impl Context { pub fn set_filter(&mut self, filter_str: &str) -> result::Result<(), SkError> { if filter_str.trim() == "none" { - self.filters_string = "none".to_owned(); - self.filter = None; + self.state.filters_string = "none".to_owned(); + self.state.filter = None; } else { let (_, filters) = css_filter(filter_str).map_err(|e| SkError::StringToFillRuleError(format!("{}", e)))?; - self.filter = css_filters_to_image_filter(filters); - self.filters_string = filter_str.to_owned(); + self.state.filter = css_filters_to_image_filter(filters); + self.state.filters_string = filter_str.to_owned(); } Ok(()) } @@ -623,7 +617,7 @@ impl Context { .ok_or_else(|| SkError::Generic("Make line dash path effect failed".to_string()))?; paint.set_path_effect(&path_effect); } - if let Some(f) = &self.filter { + if let Some(f) = &self.state.filter { paint.set_image_filter(f); } Ok(paint) @@ -2005,7 +1999,9 @@ fn set_filter(ctx: CallContext) -> Result { fn get_filter(ctx: CallContext) -> Result { let this = ctx.this_unchecked::(); let context_2d = ctx.env.unwrap::(&this)?; - ctx.env.create_string(context_2d.filters_string.as_str()) + ctx + .env + .create_string(context_2d.state.filters_string.as_str()) } #[js_function] diff --git a/src/sk.rs b/src/sk.rs index ad2c6d57..a148d7b4 100644 --- a/src/sk.rs +++ b/src/sk.rs @@ -760,6 +760,8 @@ mod ffi { c_image_filter: *mut skiac_image_filter, ) -> *mut skiac_image_filter; + pub fn skiac_image_filter_ref(image_filter: *mut skiac_image_filter); + pub fn skiac_image_filter_destroy(image_filter: *mut skiac_image_filter); pub fn skiac_sk_data_destroy(c_data: *mut skiac_data); @@ -3143,6 +3145,15 @@ impl Drop for MaskFilter { #[derive(Debug)] pub struct ImageFilter(pub(crate) *mut ffi::skiac_image_filter); +impl Clone for ImageFilter { + fn clone(&self) -> Self { + unsafe { + ffi::skiac_image_filter_ref(self.0); + }; + Self(self.0) + } +} + impl ImageFilter { pub fn make_drop_shadow_only( dx: f32, diff --git a/src/state.rs b/src/state.rs index d5bf0b35..10226d68 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,6 +1,6 @@ use cssparser::RGBA; -use crate::sk::Matrix; +use crate::sk::{ImageFilter, Matrix}; use super::{ font::Font, @@ -30,6 +30,8 @@ pub struct Context2dRenderingState { pub text_baseline: TextBaseline, pub text_direction: TextDirection, pub transform: Matrix, + pub filter: Option, + pub filters_string: String, } impl Default for Context2dRenderingState { @@ -57,6 +59,8 @@ impl Default for Context2dRenderingState { text_baseline: TextBaseline::default(), text_direction: TextDirection::default(), transform: Matrix::identity(), + filter: None, + filters_string: "none".to_owned(), } } }