Skip to content

Commit

Permalink
feat: v-group (#7)
Browse files Browse the repository at this point in the history
* feat: playground support url code template

* feat: v-group basic usage

* feat: group basic shape clip
  • Loading branch information
boenfu authored Aug 13, 2023
1 parent 793f026 commit 508bf86
Show file tree
Hide file tree
Showing 18 changed files with 1,010 additions and 321 deletions.
283 changes: 148 additions & 135 deletions soft-skia-wasm/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
extern crate soft_skia;
mod utils;

use std::collections::HashMap;

use base64;
use soft_skia::provider::{Providers, Group, Provider, GroupClip};
use wasm_bindgen::prelude::*;
use soft_skia::instance::Instance;
use soft_skia::shape::{Circle, Line, Points, RoundRect, Shapes, PaintStyle};
use soft_skia::shape::{Circle, Line, Points, RoundRect, Shapes, PaintStyle, DrawContext};
use soft_skia::shape::Rect;
use soft_skia::shape::ColorU8;
use soft_skia::tree::Node;
Expand All @@ -29,17 +32,17 @@ pub struct WASMRectAttr {
height: u32,
x: u32,
y: u32,
color: String,
style: String,
color: Option<String>,
style: Option<String>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct WASMCircleAttr {
cx: u32,
cy: u32,
r: u32,
color: String,
style: String,
color: Option<String>,
style: Option<String>,
}

#[derive(Serialize, Deserialize, Debug)]
Expand All @@ -49,24 +52,39 @@ pub struct WASMRoundRectAttr {
r: u32,
x: u32,
y: u32,
color: String,
style: String,
color: Option<String>,
style: Option<String>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct WASMLineAttr {
p1: [u32; 2],
p2: [u32; 2],
color: String,
stroke_width: u32
color: Option<String>,
stroke_width: Option<u32>
}

#[derive(Serialize, Deserialize, Debug)]
pub struct WASMPointsAttr {
points: Vec<[u32; 2]>,
color: String,
stroke_width: u32,
style: String,
color: Option<String>,
stroke_width: Option<u32>,
style: Option<String>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct WASMGroupAttr {
x: Option<u32>,
y: Option<u32>,
color: Option<String>,
style: Option<String>,
stroke_width: Option<u32>,
invert_clip: Option<bool>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct WASMGroupClipAttr {
clip: usize,
}

#[derive(Serialize, Deserialize, Debug)]
Expand All @@ -76,6 +94,8 @@ pub enum WASMShapesAttr {
RR(WASMRoundRectAttr),
L(WASMLineAttr),
P(WASMPointsAttr),
G(WASMGroupAttr),
GC(WASMGroupClipAttr),
}

#[derive(Serialize, Deserialize, Debug)]
Expand Down Expand Up @@ -132,146 +152,139 @@ impl SoftSkiaWASM {
}

fn recursive_rasterization_node_to_pixmap(node: &mut Node, pixmap: &mut Pixmap) -> () {
for item in node.children_iter_mut() {
item.shape.draw(pixmap);
Self::recursive_rasterization_node_to_pixmap(&mut (*item), pixmap);
}
}

let context = node.provider.as_ref().and_then(|p| p.get_context());

#[wasm_bindgen(js_name = setShapeBySerde)]
pub fn set_shape_by_serde(&mut self, id: usize, value: JsValue) {
let message: WASMShape = serde_wasm_bindgen::from_value(value).unwrap();
for item in node.children.iter_mut() {
let inactive = *context
.and_then(|c| c.inactive_nodes_map.as_ref().and_then(|m| m.get(&item.id)))
.unwrap_or(&false);

match message.attr {
WASMShapesAttr::R(WASMRectAttr{ width, height, x, y , color, style}) => {
if inactive {
continue;
}

let mut parser_input = ParserInput::new(&color);
let mut parser = Parser::new(&mut parser_input);
let color = CSSColor::parse(&mut parser);

match color {
Ok(CSSColor::RGBA(rgba)) => {
drop(parser_input);
let style = match style.as_str() {
"stroke" => {
PaintStyle::Stroke
},
"fill" => {
PaintStyle::Fill
},
_ => {
PaintStyle::Stroke
item.draw(pixmap, context);

if let Some(provider) = item.provider.as_mut() {
provider.set_context(pixmap, node.provider.as_ref());

// 这段感觉放这有点重,想搬走
match provider {
Providers::G(group) => {
if let Some(clip) = &group.clip {
if let Some(clip_id) = clip.id {
if let Some(clip_path) = item
.children
.iter_mut()
.find(|n| n.id == clip_id)
.and_then(|n| Some(n.shape.get_path(group.context.as_ref().unwrap())))
{
group.set_context_mask(pixmap, &clip_path);
}
}
};
self.0.set_shape_to_child(id, Shapes::R(Rect { x, y, width, height, color: ColorU8::from_rgba(rgba.red, rgba.green, rgba.blue, rgba.alpha), style }))
}
_ => {
//
}
}
}

},
WASMShapesAttr::C(WASMCircleAttr{ cx, cy, r, color, style }) => {
}

let mut parser_input = ParserInput::new(&color);
let mut parser = Parser::new(&mut parser_input);
let color = CSSColor::parse(&mut parser);

match color {
Ok(CSSColor::RGBA(rgba)) => {
drop(parser_input);
let style = match style.as_str() {
"stroke" => {
PaintStyle::Stroke
},
"fill" => {
PaintStyle::Fill
},
_ => {
PaintStyle::Stroke
}
};
self.0.set_shape_to_child(id, Shapes::C(Circle { cx, cy, r, color: ColorU8::from_rgba(rgba.red, rgba.green, rgba.blue, rgba.alpha), style }))
}
_ => {
//
}
}
Self::recursive_rasterization_node_to_pixmap(item, pixmap);
}
}

#[wasm_bindgen(js_name = setAttrBySerde)]
pub fn set_attr_by_serde(&mut self, id: usize, value: JsValue) {
let message: WASMShape = serde_wasm_bindgen::from_value(value).unwrap();

match message.attr {
WASMShapesAttr::R(WASMRectAttr{ width, height, x, y , color, style}) => {
let color = parse_color(color);
let style = parse_style(style);
self.0.set_shape_to_child(id, Shapes::R(Rect { x, y, width, height, color, style }))
},
WASMShapesAttr::C(WASMCircleAttr{ cx, cy, r, color, style }) => {
let color = parse_color(color);
let style = parse_style(style);
self.0.set_shape_to_child(id, Shapes::C(Circle { cx, cy, r, color, style }))
},
WASMShapesAttr::RR(WASMRoundRectAttr{ width, height, r, x, y , color, style}) => {
let color = parse_color(color);
let style = parse_style(style);

let mut parser_input = ParserInput::new(&color);
let mut parser = Parser::new(&mut parser_input);
let color = CSSColor::parse(&mut parser);

match color {
Ok(CSSColor::RGBA(rgba)) => {
drop(parser_input);
let style = match style.as_str() {
"stroke" => {
PaintStyle::Stroke
},
"fill" => {
PaintStyle::Fill
},
_ => {
PaintStyle::Stroke
}
};
self.0.set_shape_to_child(id, Shapes::RR(RoundRect { x, y, r, width, height, color: ColorU8::from_rgba(rgba.red, rgba.green, rgba.blue, rgba.alpha), style }))
}
_ => {
//
}
}

self.0.set_shape_to_child(id, Shapes::RR(RoundRect { x, y, r, width, height, color, style }))
},
WASMShapesAttr::L(WASMLineAttr{ p1, p2, stroke_width, color}) => {

let mut parser_input = ParserInput::new(&color);
let mut parser = Parser::new(&mut parser_input);
let color = CSSColor::parse(&mut parser);

match color {
Ok(CSSColor::RGBA(rgba)) => {
drop(parser_input);
self.0.set_shape_to_child(id, Shapes::L(Line { p1, p2, stroke_width, color: ColorU8::from_rgba(rgba.red, rgba.green, rgba.blue, rgba.alpha) }))
}
_ => {
//
}
}

let color = parse_color(color);
self.0.set_shape_to_child(id, Shapes::L(Line { p1, p2, stroke_width, color }))
},
WASMShapesAttr::P(WASMPointsAttr{ points , color, stroke_width, style }) => {

let mut parser_input = ParserInput::new(&color);
let mut parser = Parser::new(&mut parser_input);
let color = CSSColor::parse(&mut parser);

match color {
Ok(CSSColor::RGBA(rgba)) => {
drop(parser_input);
let style = match style.as_str() {
"stroke" => {
PaintStyle::Stroke
},
"fill" => {
PaintStyle::Fill
},
_ => {
PaintStyle::Stroke
}
};
self.0.set_shape_to_child(id, Shapes::P(Points { points, stroke_width, color: ColorU8::from_rgba(rgba.red, rgba.green, rgba.blue, rgba.alpha), style }))
}
_ => {
//
}
}
let color = parse_color(color);
let style = parse_style(style);
self.0.set_shape_to_child(id, Shapes::P(Points { points, stroke_width, color, style }))
},
WASMShapesAttr::G(WASMGroupAttr {
x,
y,
color,
stroke_width,
style,
invert_clip,
}) => {
let color = parse_color(color);
let style = parse_style(style);
let mut clip = GroupClip::default();
clip.invert = invert_clip;

self.0.set_provider_to_child(
id,
Providers::G(Group {
x,
y,
color,
style,
stroke_width,
clip: Some(clip),
context: None,
}),
)
},
WASMShapesAttr::GC(WASMGroupClipAttr { clip }) => {
let provider = self
.0
.get_tree_node_by_id(id)
.unwrap()
.provider
.as_mut()
.unwrap();

match provider {
Providers::G(ref mut group) => group.set_clip_id(clip),
}
}
};
}
}

fn parse_color(color: Option<String>) -> Option<ColorU8> {
if let Some(color_str) = color {
let mut parser_input = ParserInput::new(&color_str);
let mut parser = Parser::new(&mut parser_input);

if let Ok(css_color) = CSSColor::parse(&mut parser) {
if let CSSColor::RGBA(rgba) = css_color {
return Some(ColorU8::from_rgba(
rgba.red, rgba.green, rgba.blue, rgba.alpha,
));
}
}
}
None
}

fn parse_style(style: Option<String>) -> Option<PaintStyle> {
match style.as_deref() {
Some("stroke") => Some(PaintStyle::Stroke),
Some("fill") => Some(PaintStyle::Fill),
_ => None,
}
}
10 changes: 8 additions & 2 deletions soft-skia/src/instance.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::collections::HashMap;

use crate::provider::Providers;
use crate::tree::Tree;
use crate::tree::Node;
use crate::shape::Shapes;
Expand Down Expand Up @@ -41,6 +42,11 @@ impl Instance {
child.shape = shape;
}

pub fn set_provider_to_child(&mut self, child_id: usize, provider: Providers) {
let mut child = self.get_tree_node_by_id(child_id).unwrap();
child.provider = Some(provider);
}

pub fn remove_child_from_container(&mut self, child_id: usize, container_id: usize) {
let container = self.get_tree_node_by_id(container_id).unwrap();
container.remove_child_by_id(child_id);
Expand Down Expand Up @@ -116,15 +122,15 @@ mod test {
}
}

instance.set_shape_to_child(1, Shapes::R(Rect { x: 20, y: 20, width: 200, height: 200, color: ColorU8::from_rgba(0, 100, 0, 255), style: PaintStyle::Fill }));
instance.set_shape_to_child(1, Shapes::R(Rect { x: 20, y: 20, width: 200, height: 200, color: Some(ColorU8::from_rgba(0, 100, 0, 255)), style: None }));

match instance.get_tree_node_by_id(1).unwrap().shape {
Shapes::R(Rect { x, y, width, height, color, style }) => {
assert_eq!(x, 20);
assert_eq!(y, 20);
assert_eq!(width, 200);
assert_eq!(height, 200);
assert_eq!(color.green(), 100);
assert_eq!(color.unwrap().green(), 100);
},
_ => {
panic!()
Expand Down
Loading

0 comments on commit 508bf86

Please sign in to comment.