Skip to content

Commit

Permalink
chore: use new BufferSlice API
Browse files Browse the repository at this point in the history
  • Loading branch information
Brooooooklyn committed Sep 19, 2024
1 parent 366d738 commit 2db5440
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 112 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
1 change: 1 addition & 0 deletions src/avif.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
148 changes: 78 additions & 70 deletions src/ctx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -2123,85 +2123,93 @@ pub enum ContextOutputData {
Avif(AvifData<'static>),
}

impl ContextOutputData {
pub(crate) fn into_buffer_slice<'a>(self, env: Env) -> Result<BufferSlice<'a>> {
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<ContextOutputData> {
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<Self::Output> {
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<Self::JsValue> {
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))
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ struct BitmapDecoder {
height: f64,
color_space: ColorSpace,
data: Option<Uint8Array>,
this_ref: Ref<()>,
this_ref: Ref<Object>,
}

#[derive(Debug)]
Expand Down
61 changes: 27 additions & 34 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -204,10 +205,10 @@ impl CanvasElement {
env: Env,
format: String,
quality_or_config: Either3<u32, AvifConfig, Unknown>,
) -> Result<JsBuffer> {
let mut task = self.encode_inner(format, quality_or_config)?;
let output = task.compute()?;
task.resolve(env, output)
) -> Result<BufferSlice> {
let data = self.encode_inner(format, quality_or_config)?;
let output = encode_surface(&data)?;
output.into_buffer_slice(env)
}

#[napi]
Expand All @@ -216,35 +217,33 @@ impl CanvasElement {
env: Env,
mime: String,
quality_or_config: Either3<u32, AvifConfig, Unknown>,
) -> Result<JsBuffer> {
) -> Result<BufferSlice> {
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<JsBuffer> {
pub fn data(&self, env: Env) -> Result<BufferSlice> {
let ctx2d = &self.ctx.context;

let surface_ref = ctx2d.surface.reference();
Expand All @@ -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")]
Expand Down Expand Up @@ -521,15 +516,13 @@ impl SVGCanvas {
}

#[napi]
pub fn get_content(&self, env: Env) -> Result<JsBuffer> {
pub fn get_content(&self, env: Env) -> Result<BufferSlice> {
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)
})
}
}
}
Expand Down
9 changes: 4 additions & 5 deletions src/svg.rs
Original file line number Diff line number Diff line change
@@ -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<Buffer, String, Unknown>,
) -> Result<JsBuffer> {
) -> Result<BufferSlice> {
let font = get_font().map_err(SkError::from)?;
sk_svg_text_to_path(input.as_bytes()?, &font)
.ok_or_else(|| {
Expand All @@ -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 {
Expand Down

0 comments on commit 2db5440

Please sign in to comment.