From 2db5440333998df4935a4f2bce8663ba770d96f0 Mon Sep 17 00:00:00 2001 From: LongYinan Date: Thu, 19 Sep 2024 22:56:25 +0800 Subject: [PATCH] chore: use new BufferSlice API --- Cargo.toml | 4 +- src/avif.rs | 1 + src/ctx.rs | 148 +++++++++++++++++++++++++++------------------------ src/image.rs | 2 +- src/lib.rs | 61 ++++++++++----------- src/svg.rs | 9 ++-- 6 files changed, 113 insertions(+), 112 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 37bdd3de..a5925374 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,8 +14,8 @@ base64-simd = "0.8" cssparser = "0.29" infer = "0.16" libavif = { version = "0.14", default-features = false, features = ["codec-aom"] } -napi = { version = "3.0.0-alpha.8", default-features = false, features = ["napi3", "serde-json"] } -napi-derive = { version = "3.0.0-alpha.7", default-features = false } +napi = { version = "3.0.0-alpha.9", default-features = false, features = ["napi3", "serde-json"] } +napi-derive = { version = "3.0.0-alpha.8", default-features = false } nom = "7" num_cpus = "1" once_cell = "1" diff --git a/src/avif.rs b/src/avif.rs index f1118c2e..ed824ff3 100644 --- a/src/avif.rs +++ b/src/avif.rs @@ -24,6 +24,7 @@ pub struct AvifConfig { #[napi] /// https://en.wikipedia.org/wiki/Chroma_subsampling#Types_of_sampling_and_subsampling /// https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Video_concepts +#[derive(Clone, Copy)] pub enum ChromaSubsampling { /// Each of the three Y'CbCr components has the same sample rate, thus there is no chroma subsampling. This scheme is sometimes used in high-end film scanners and cinematic post-production. /// Note that "4:4:4" may instead be wrongly referring to R'G'B' color space, which implicitly also does not have any chroma subsampling (except in JPEG R'G'B' can be subsampled). diff --git a/src/ctx.rs b/src/ctx.rs index d512acf7..c32cb7b5 100644 --- a/src/ctx.rs +++ b/src/ctx.rs @@ -6,7 +6,7 @@ use std::str::FromStr; use cssparser::{Color as CSSColor, Parser, ParserInput, RGBA}; use libavif::AvifData; -use napi::{bindgen_prelude::*, JsBuffer, JsString, NapiRaw, NapiValue}; +use napi::{bindgen_prelude::*, JsString, NapiRaw, NapiValue}; use once_cell::sync::Lazy; use regex::Regex; @@ -2123,85 +2123,93 @@ pub enum ContextOutputData { Avif(AvifData<'static>), } +impl ContextOutputData { + pub(crate) fn into_buffer_slice<'a>(self, env: Env) -> Result> { + match self { + ContextOutputData::Skia(output) => unsafe { + BufferSlice::from_external(&env, output.0.ptr, output.0.size, output, |data_ref, _| { + mem::drop(data_ref) + }) + }, + ContextOutputData::Avif(output) => unsafe { + BufferSlice::from_external( + &env, + output.as_ptr().cast_mut(), + output.len(), + output, + |data_ref, _| mem::drop(data_ref), + ) + }, + } + } +} + +#[inline] +pub(crate) fn encode_surface(data: &ContextData) -> Result { + match data { + ContextData::Png(surface) => surface + .png_data() + .map(ContextOutputData::Skia) + .ok_or_else(|| { + Error::new( + Status::GenericFailure, + "Get png data from surface failed".to_string(), + ) + }), + ContextData::Jpeg(surface, quality) => surface + .encode_data(SkEncodedImageFormat::Jpeg, *quality) + .map(ContextOutputData::Skia) + .ok_or_else(|| { + Error::new( + Status::GenericFailure, + "Get jpeg data from surface failed".to_string(), + ) + }), + ContextData::Webp(surface, quality) => surface + .encode_data(SkEncodedImageFormat::Webp, *quality) + .map(ContextOutputData::Skia) + .ok_or_else(|| { + Error::new( + Status::GenericFailure, + "Get webp data from surface failed".to_string(), + ) + }), + ContextData::Avif(surface, config, width, height) => surface + .data() + .ok_or_else(|| { + Error::new( + Status::GenericFailure, + "Get avif data from surface failed".to_string(), + ) + }) + .and_then(|(data, size)| { + crate::avif::encode( + unsafe { slice::from_raw_parts(data, size) }, + *width, + *height, + config, + ) + .map(ContextOutputData::Avif) + .map_err(|e| Error::new(Status::GenericFailure, format!("{e}"))) + }), + } +} + unsafe impl Send for ContextOutputData {} unsafe impl Sync for ContextOutputData {} impl Task for ContextData { type Output = ContextOutputData; - type JsValue = JsBuffer; + type JsValue = Buffer; fn compute(&mut self) -> Result { - match self { - ContextData::Png(surface) => { - surface - .png_data() - .map(ContextOutputData::Skia) - .ok_or_else(|| { - Error::new( - Status::GenericFailure, - "Get png data from surface failed".to_string(), - ) - }) - } - ContextData::Jpeg(surface, quality) => surface - .encode_data(SkEncodedImageFormat::Jpeg, *quality) - .map(ContextOutputData::Skia) - .ok_or_else(|| { - Error::new( - Status::GenericFailure, - "Get jpeg data from surface failed".to_string(), - ) - }), - ContextData::Webp(surface, quality) => surface - .encode_data(SkEncodedImageFormat::Webp, *quality) - .map(ContextOutputData::Skia) - .ok_or_else(|| { - Error::new( - Status::GenericFailure, - "Get webp data from surface failed".to_string(), - ) - }), - ContextData::Avif(surface, config, width, height) => surface - .data() - .ok_or_else(|| { - Error::new( - Status::GenericFailure, - "Get avif data from surface failed".to_string(), - ) - }) - .and_then(|(data, size)| { - crate::avif::encode( - unsafe { slice::from_raw_parts(data, size) }, - *width, - *height, - config, - ) - .map(ContextOutputData::Avif) - .map_err(|e| Error::new(Status::GenericFailure, format!("{e}"))) - }), - } + encode_surface(self) } fn resolve(&mut self, env: Env, output_data: Self::Output) -> Result { - match output_data { - ContextOutputData::Skia(output) => unsafe { - env - .create_buffer_with_borrowed_data(output.0.ptr, output.0.size, output, |data_ref, _| { - mem::drop(data_ref) - }) - .map(|value| value.into_raw()) - }, - ContextOutputData::Avif(output) => unsafe { - env - .create_buffer_with_borrowed_data( - output.as_ptr().cast_mut(), - output.len(), - output, - |data_ref, _| mem::drop(data_ref), - ) - .map(|b| b.into_raw()) - }, - } + output_data + .into_buffer_slice(env) + .and_then(|slice| slice.into_buffer(&env)) } } diff --git a/src/image.rs b/src/image.rs index fb8262f3..aa958204 100644 --- a/src/image.rs +++ b/src/image.rs @@ -300,7 +300,7 @@ struct BitmapDecoder { height: f64, color_space: ColorSpace, data: Option, - this_ref: Ref<()>, + this_ref: Ref, } #[derive(Debug)] diff --git a/src/lib.rs b/src/lib.rs index f3d7cd83..b5e20a84 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,11 +14,12 @@ use std::str::FromStr; use std::{mem, slice}; use base64::Engine; +use bindgen_prelude::BufferSlice; use napi::bindgen_prelude::{AsyncTask, ClassInstance, Either3, This, Unknown}; use napi::*; use ctx::{ - CanvasRenderingContext2D, Context, ContextData, ContextOutputData, SvgExportFlag, + encode_surface, CanvasRenderingContext2D, Context, ContextData, ContextOutputData, SvgExportFlag, FILL_STYLE_HIDDEN_NAME, STROKE_STYLE_HIDDEN_NAME, }; use font::{init_font_regexp, FONT_REGEXP}; @@ -204,10 +205,10 @@ impl CanvasElement { env: Env, format: String, quality_or_config: Either3, - ) -> Result { - let mut task = self.encode_inner(format, quality_or_config)?; - let output = task.compute()?; - task.resolve(env, output) + ) -> Result { + let data = self.encode_inner(format, quality_or_config)?; + let output = encode_surface(&data)?; + output.into_buffer_slice(env) } #[napi] @@ -216,35 +217,33 @@ impl CanvasElement { env: Env, mime: String, quality_or_config: Either3, - ) -> Result { + ) -> Result { let mime = mime.as_str(); let context_data = get_data_ref(&self.ctx.context, mime, &quality_or_config)?; match context_data { ContextOutputData::Skia(data_ref) => unsafe { - env - .create_buffer_with_borrowed_data( - data_ref.0.ptr, - data_ref.0.size, - data_ref, - |data: SkiaDataRef, _| mem::drop(data), - ) - .map(|b| b.into_raw()) + BufferSlice::from_external( + &env, + data_ref.0.ptr, + data_ref.0.size, + data_ref, + |data: SkiaDataRef, _| mem::drop(data), + ) }, ContextOutputData::Avif(output) => unsafe { - env - .create_buffer_with_borrowed_data( - output.as_ptr().cast_mut(), - output.len(), - output, - |data, _| mem::drop(data), - ) - .map(|b| b.into_raw()) + BufferSlice::from_external( + &env, + output.as_ptr().cast_mut(), + output.len(), + output, + |data, _| mem::drop(data), + ) }, } } #[napi] - pub fn data(&self, env: Env) -> Result { + pub fn data(&self, env: Env) -> Result { let ctx2d = &self.ctx.context; let surface_ref = ctx2d.surface.reference(); @@ -255,11 +254,7 @@ impl CanvasElement { "Get png data from surface failed".to_string(), ) })?; - unsafe { - env - .create_buffer_with_borrowed_data(ptr.cast_mut(), size, 0, noop_finalize) - .map(|value| value.into_raw()) - } + unsafe { BufferSlice::from_external(&env, ptr.cast_mut(), size, 0, noop_finalize) } } #[napi(js_name = "toDataURLAsync")] @@ -521,15 +516,13 @@ impl SVGCanvas { } #[napi] - pub fn get_content(&self, env: Env) -> Result { + pub fn get_content(&self, env: Env) -> Result { let svg_data_stream = self.ctx.context.stream.as_ref().unwrap(); let svg_data = svg_data_stream.data(self.ctx.context.width, self.ctx.context.height); unsafe { - env - .create_buffer_with_borrowed_data(svg_data.0.ptr, svg_data.0.size, svg_data, |d, _| { - mem::drop(d) - }) - .map(|b| b.into_raw()) + BufferSlice::from_external(&env, svg_data.0.ptr, svg_data.0.size, svg_data, |d, _| { + mem::drop(d) + }) } } } diff --git a/src/svg.rs b/src/svg.rs index 767cfda5..37600b60 100644 --- a/src/svg.rs +++ b/src/svg.rs @@ -1,14 +1,14 @@ use std::mem; -use napi::{bindgen_prelude::*, JsBuffer}; +use napi::bindgen_prelude::*; use crate::{error::SkError, global_fonts::get_font, sk::sk_svg_text_to_path}; #[napi(js_name = "convertSVGTextToPath")] pub fn convert_svg_text_to_path( - env: Env, + env: &Env, input: Either3, -) -> Result { +) -> Result { let font = get_font().map_err(SkError::from)?; sk_svg_text_to_path(input.as_bytes()?, &font) .ok_or_else(|| { @@ -18,9 +18,8 @@ pub fn convert_svg_text_to_path( ) }) .and_then(|v| unsafe { - env.create_buffer_with_borrowed_data(v.0.ptr, v.0.size, v, |d, _| mem::drop(d)) + BufferSlice::from_external(env, v.0.ptr, v.0.size, v, |d, _| mem::drop(d)) }) - .map(|b| b.into_raw()) } trait AsBytes {