diff --git a/render-wasm/src/main.rs b/render-wasm/src/main.rs index 4d1e8805d..476a4a1d3 100644 --- a/render-wasm/src/main.rs +++ b/render-wasm/src/main.rs @@ -154,7 +154,7 @@ pub extern "C" fn add_shape_solid_fill(raw_color: u32) { let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer"); if let Some(shape) = state.current_shape() { let color = skia::Color::new(raw_color); - shape.add_fill(shapes::Fill::from(color)); + shape.add_fill(shapes::Fill::Solid(color)); } } diff --git a/render-wasm/src/math.rs b/render-wasm/src/math.rs index 1086eb66f..f58d04584 100644 --- a/render-wasm/src/math.rs +++ b/render-wasm/src/math.rs @@ -1,4 +1,3 @@ use skia_safe as skia; pub type Rect = skia::Rect; -pub type Matrix = skia::Matrix; diff --git a/render-wasm/src/shapes.rs b/render-wasm/src/shapes.rs index 8860d2411..dfe45266c 100644 --- a/render-wasm/src/shapes.rs +++ b/render-wasm/src/shapes.rs @@ -2,12 +2,17 @@ use crate::math; use skia_safe as skia; use uuid::Uuid; +mod blend; +mod fills; +pub use blend::*; +pub use fills::*; + #[derive(Debug, Clone, Copy)] pub enum Kind { Rect, } -type Color = skia::Color; +pub type Color = skia::Color; #[derive(Debug, Clone, Copy)] pub struct Matrix { @@ -32,110 +37,6 @@ impl Matrix { } } -#[derive(Debug, Clone, PartialEq)] -pub struct Gradient { - colors: Vec, - offsets: Vec, - opacity: f32, - start: (f32, f32), - end: (f32, f32), -} - -impl Gradient { - fn to_shader(&self, rect: &math::Rect) -> skia::Shader { - let start = ( - rect.left + self.start.0 * rect.width(), - rect.top + self.start.1 * rect.height(), - ); - let end = ( - rect.left + self.end.0 * rect.width(), - rect.top + self.end.1 * rect.height(), - ); - let shader = skia::shader::Shader::linear_gradient( - (start, end), - self.colors.as_slice(), - self.offsets.as_slice(), - skia::TileMode::Clamp, - None, - None, - ) - .unwrap(); - shader - } -} - -#[derive(Debug, Clone, PartialEq)] -pub enum Fill { - Solid(Color), - LinearGradient(Gradient), -} - -impl From for Fill { - fn from(value: Color) -> Self { - Self::Solid(value) - } -} - -impl Fill { - pub fn new_linear_gradient(start: (f32, f32), end: (f32, f32), opacity: f32) -> Self { - Self::LinearGradient(Gradient { - start, - end, - opacity, - colors: vec![], - offsets: vec![], - }) - } - - pub fn to_paint(&self, rect: &math::Rect) -> skia::Paint { - match self { - Self::Solid(color) => { - let mut p = skia::Paint::default(); - p.set_color(*color); - p.set_style(skia::PaintStyle::Fill); - p.set_anti_alias(true); - p.set_blend_mode(skia::BlendMode::SrcOver); - p - } - Self::LinearGradient(gradient) => { - let mut p = skia::Paint::default(); - p.set_shader(gradient.to_shader(&rect)); - p.set_alpha((gradient.opacity * 255.) as u8); - p.set_style(skia::PaintStyle::Fill); - p.set_blend_mode(skia::BlendMode::SrcOver); - p - } - } - } -} - -#[derive(Debug, PartialEq, Clone, Copy)] -pub struct BlendMode(skia::BlendMode); - -impl Default for BlendMode { - fn default() -> Self { - BlendMode(skia::BlendMode::SrcOver) - } -} - -impl From for BlendMode { - fn from(value: i32) -> Self { - if value <= skia::BlendMode::Luminosity as i32 { - unsafe { Self(std::mem::transmute(value)) } - } else { - Self::default() - } - } -} - -impl Into for BlendMode { - fn into(self) -> skia::BlendMode { - match self { - Self(skia_blend) => skia_blend, - } - } -} - #[derive(Debug, Clone)] #[allow(dead_code)] pub struct Shape { @@ -196,8 +97,7 @@ impl Shape { _ => Err("Active fill is not a gradient"), }?; - gradient.colors.push(color); - gradient.offsets.push(offset); + gradient.add_stop(color, offset); Ok(()) } diff --git a/render-wasm/src/shapes/blend.rs b/render-wasm/src/shapes/blend.rs new file mode 100644 index 000000000..3fb98b7f3 --- /dev/null +++ b/render-wasm/src/shapes/blend.rs @@ -0,0 +1,28 @@ +use skia_safe as skia; + +#[derive(Debug, PartialEq, Clone, Copy)] +pub struct BlendMode(skia::BlendMode); + +impl Default for BlendMode { + fn default() -> Self { + BlendMode(skia::BlendMode::SrcOver) + } +} + +impl From for BlendMode { + fn from(value: i32) -> Self { + if value <= skia::BlendMode::Luminosity as i32 { + unsafe { Self(std::mem::transmute(value)) } + } else { + Self::default() + } + } +} + +impl Into for BlendMode { + fn into(self) -> skia::BlendMode { + match self { + Self(skia_blend) => skia_blend, + } + } +} diff --git a/render-wasm/src/shapes/fills.rs b/render-wasm/src/shapes/fills.rs new file mode 100644 index 000000000..880e6194a --- /dev/null +++ b/render-wasm/src/shapes/fills.rs @@ -0,0 +1,80 @@ +use skia_safe as skia; + +use super::Color; +use crate::math; + +#[derive(Debug, Clone, PartialEq)] +pub struct Gradient { + colors: Vec, + offsets: Vec, + opacity: f32, + start: (f32, f32), + end: (f32, f32), +} + +impl Gradient { + pub fn add_stop(&mut self, color: Color, offset: f32) { + self.colors.push(color); + self.offsets.push(offset); + } + + fn to_shader(&self, rect: &math::Rect) -> skia::Shader { + let start = ( + rect.left + self.start.0 * rect.width(), + rect.top + self.start.1 * rect.height(), + ); + let end = ( + rect.left + self.end.0 * rect.width(), + rect.top + self.end.1 * rect.height(), + ); + let shader = skia::shader::Shader::linear_gradient( + (start, end), + self.colors.as_slice(), + self.offsets.as_slice(), + skia::TileMode::Clamp, + None, + None, + ) + .unwrap(); + shader + } +} + +#[derive(Debug, Clone, PartialEq)] +pub enum Fill { + Solid(Color), + LinearGradient(Gradient), +} + +impl Fill { + pub fn new_linear_gradient(start: (f32, f32), end: (f32, f32), opacity: f32) -> Self { + Self::LinearGradient(Gradient { + start, + end, + opacity, + colors: vec![], + offsets: vec![], + }) + } + + pub fn to_paint(&self, rect: &math::Rect) -> skia::Paint { + match self { + Self::Solid(color) => { + let mut p = skia::Paint::default(); + p.set_color(*color); + p.set_style(skia::PaintStyle::Fill); + p.set_anti_alias(true); + p.set_blend_mode(skia::BlendMode::SrcOver); + p + } + Self::LinearGradient(gradient) => { + let mut p = skia::Paint::default(); + p.set_shader(gradient.to_shader(&rect)); + p.set_alpha((gradient.opacity * 255.) as u8); + p.set_style(skia::PaintStyle::Fill); + p.set_blend_mode(skia::BlendMode::SrcOver); + p + } + } + } +}