diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c533d85c..16fdc6da 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,6 +11,10 @@ jobs: steps: - uses: actions/checkout@v2 + - uses: actions/setup-node@v3.8.1 + with: + node-version: 16.x + # File containing the ve - uses: actions-rs/toolchain@v1 with: toolchain: stable @@ -28,21 +32,22 @@ jobs: - name: soft-skia-wasm run: | - cd soft-skia-wasm cargo install wasm-pack - wasm-pack build --release --target web + pnpm run build:wasm - name: vue-skia-framework run: | cd vue-skia-framework pnpm i - pnpm build + cd .. + pnpm run build:vue - name: vue-playground run: | cd vue-playground pnpm i - pnpm build + cd .. + pnpm --filter vue-playground build - name: Archive vue-skia-framework artifacts uses: actions/upload-artifact@v3 @@ -62,4 +67,4 @@ jobs: with: name: soft-skia-wasm path: | - soft-skia-wasm/pkg \ No newline at end of file + soft-skia-wasm/pkg diff --git a/.github/workflows/playground_use_latest.yml b/.github/workflows/playground_use_latest.yml index 1c2b4003..7df8a8dd 100644 --- a/.github/workflows/playground_use_latest.yml +++ b/.github/workflows/playground_use_latest.yml @@ -15,6 +15,9 @@ jobs: steps: - uses: actions/checkout@v2 + - uses: actions/setup-node@v3.8.1 + with: + node-version: 16.x - uses: actions-rs/toolchain@v1 with: toolchain: stable diff --git a/package.json b/package.json index e02b3daa..b863eea5 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,10 @@ "version": "0.1.0", "private": "true", "scripts": { - "serve": "pnpm -C vue-playground serve" + "serve": "pnpm --filter vue-playground serve", + "build": "pnpm build:wasm && pnpm build:vue", + "build:vue": "pnpm --filter vue-skia build", + "build:wasm": "cd soft-skia-wasm && wasm-pack build" }, "packageManager": "pnpm@7.32.0" } diff --git a/soft-skia-wasm/Cargo.toml b/soft-skia-wasm/Cargo.toml index 8696b289..12a599ba 100644 --- a/soft-skia-wasm/Cargo.toml +++ b/soft-skia-wasm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "soft-skia-wasm" -version = "0.6.0" +version = "0.7.0" authors = ["meloalright "] edition = "2018" diff --git a/soft-skia-wasm/src/lib.rs b/soft-skia-wasm/src/lib.rs index 9a762555..100a2334 100644 --- a/soft-skia-wasm/src/lib.rs +++ b/soft-skia-wasm/src/lib.rs @@ -1,17 +1,15 @@ 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, DrawContext, Image}; -use soft_skia::shape::Rect; +use soft_skia::provider::{Group, GroupClip, Providers}; use soft_skia::shape::ColorU8; -use soft_skia::tree::Node; use soft_skia::shape::Pixmap; +use soft_skia::shape::Rect; +use soft_skia::shape::{Circle, Image, Line, PaintStyle, Points, RoundRect, Shapes, Text}; +use soft_skia::tree::Node; +use wasm_bindgen::prelude::*; use cssparser::{Color as CSSColor, Parser, ParserInput}; @@ -24,7 +22,7 @@ static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; #[wasm_bindgen] pub struct SoftSkiaWASM(Instance); -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug)] pub struct WASMRectAttr { @@ -61,7 +59,7 @@ pub struct WASMLineAttr { p1: [u32; 2], p2: [u32; 2], color: Option, - stroke_width: Option + stroke_width: Option, } #[derive(Serialize, Deserialize, Debug)] @@ -96,6 +94,15 @@ pub struct WASMImageAttr { height: u32, } +#[derive(Serialize, Deserialize, Debug)] +pub struct WASMTextAttr { + text: String, + x: i32, + y: i32, + font_size: Option, + color: Option, + max_width: Option, +} #[derive(Serialize, Deserialize, Debug)] pub enum WASMShapesAttr { @@ -106,30 +113,42 @@ pub enum WASMShapesAttr { P(WASMPointsAttr), G(WASMGroupAttr), GC(WASMGroupClipAttr), - I(WASMImageAttr) + I(WASMImageAttr), + T(WASMTextAttr), } #[derive(Serialize, Deserialize, Debug)] pub struct WASMShape { - pub attr: WASMShapesAttr + pub attr: WASMShapesAttr, } #[wasm_bindgen] impl SoftSkiaWASM { #[wasm_bindgen(constructor)] pub fn new(id: usize) -> Self { + utils::set_panic_hook(); let instance = Instance::new(id); SoftSkiaWASM(instance) } #[wasm_bindgen(js_name = createChildAppendToContainer)] pub fn create_child_append_to_container(&mut self, child_id: usize, container_id: usize) { - self.0.create_child_append_to_container(child_id, container_id) + self.0 + .create_child_append_to_container(child_id, container_id) } #[wasm_bindgen(js_name = createChildInsertBeforeElementOfContainer)] - pub fn create_child_insert_before_element_of_container(&mut self, child_id: usize, insert_before_id: usize, container_id: usize) { - self.0.create_child_insert_before_element_of_container(child_id, insert_before_id, container_id); + pub fn create_child_insert_before_element_of_container( + &mut self, + child_id: usize, + insert_before_id: usize, + container_id: usize, + ) { + self.0.create_child_insert_before_element_of_container( + child_id, + insert_before_id, + container_id, + ); } #[wasm_bindgen(js_name = removeChildFromContainer)] @@ -147,12 +166,15 @@ impl SoftSkiaWASM { pub fn to_base64(&mut self) -> String { let root = self.0.tree.get_root(); let mut pixmap = match root.shape { - Shapes::R( Rect { x, y, width, height, color, style }) => { - Pixmap::new(width, height).unwrap() - }, - _ => { - Pixmap::new(0, 0).unwrap() - } + Shapes::R(Rect { + x, + y, + width, + height, + color, + style, + }) => Pixmap::new(width, height).unwrap(), + _ => Pixmap::new(0, 0).unwrap(), }; Self::recursive_rasterization_node_to_pixmap(root, &mut pixmap); @@ -184,11 +206,10 @@ impl SoftSkiaWASM { 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()))) + 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); } @@ -196,7 +217,6 @@ impl SoftSkiaWASM { } } } - } Self::recursive_rasterization_node_to_pixmap(item, pixmap); @@ -206,33 +226,109 @@ impl SoftSkiaWASM { #[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}) => { + 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 }) => { + 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}) => { + 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); - 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}) => { + 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 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 }) => { + self.0.set_shape_to_child( + id, + Shapes::L(Line { + p1, + p2, + stroke_width, + color, + }), + ) + } + WASMShapesAttr::P(WASMPointsAttr { + points, + color, + stroke_width, + 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 })) - }, + self.0.set_shape_to_child( + id, + Shapes::P(Points { + points, + stroke_width, + color, + style, + }), + ) + } WASMShapesAttr::G(WASMGroupAttr { x, y, @@ -258,7 +354,7 @@ impl SoftSkiaWASM { context: None, }), ) - }, + } WASMShapesAttr::GC(WASMGroupClipAttr { clip }) => { let provider = self .0 @@ -277,9 +373,38 @@ impl SoftSkiaWASM { y, image, width, - height + height, + }) => self.0.set_shape_to_child( + id, + Shapes::I(Image { + image, + x, + y, + width, + height, + }), + ), + WASMShapesAttr::T(WASMTextAttr { + x, + y, + text, + font_size, + color, + max_width, }) => { - self.0.set_shape_to_child(id, Shapes::I(Image { image, x, y, width, height })) + let color = parse_color(color); + let font_size = font_size.unwrap_or(16.0); + self.0.set_shape_to_child( + id, + Shapes::T(Text { + text, + x, + y, + font_size, + color, + max_width, + }), + ) } }; } @@ -307,4 +432,4 @@ fn parse_style(style: Option) -> Option { Some("fill") => Some(PaintStyle::Fill), _ => None, } -} \ No newline at end of file +} diff --git a/soft-skia/Cargo.toml b/soft-skia/Cargo.toml index 9d99f0ea..3248e426 100644 --- a/soft-skia/Cargo.toml +++ b/soft-skia/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "soft_skia" -version = "0.6.0" +version = "0.7.0" edition = "2021" description="software rasterization skia binding" license = "MIT" @@ -9,5 +9,12 @@ license = "MIT" [dependencies] png = "0.17.5" -tiny-skia = "0.9.0" -base64 = "0.21.0" \ No newline at end of file +tiny-skia = "0.10.0" +base64 = "0.21.0" +fontdue = "0.7.3" + +[dependencies.web-sys] +version = "0.3" +features = [ + "console", +] \ No newline at end of file diff --git a/soft-skia/assets/Roboto-Regular.ttf b/soft-skia/assets/Roboto-Regular.ttf new file mode 100644 index 00000000..8c082c8d Binary files /dev/null and b/soft-skia/assets/Roboto-Regular.ttf differ diff --git a/soft-skia/src/instance.rs b/soft-skia/src/instance.rs index fa4df1ed..29143ecc 100644 --- a/soft-skia/src/instance.rs +++ b/soft-skia/src/instance.rs @@ -1,23 +1,23 @@ use std::collections::HashMap; use crate::provider::Providers; -use crate::tree::Tree; -use crate::tree::Node; -use crate::shape::Shapes; -use crate::shape::Shape; use crate::shape::Rect; +use crate::shape::Shape; +use crate::shape::Shapes; +use crate::tree::Node; +use crate::tree::Tree; #[derive(Debug)] pub struct Instance { pub tree: Tree, - pub node_ptr_map: HashMap + pub node_ptr_map: HashMap, } impl Instance { pub fn new(id: usize) -> Self { Instance { tree: Tree::default(id), - node_ptr_map: HashMap::new() + node_ptr_map: HashMap::new(), } } @@ -29,7 +29,12 @@ impl Instance { self.node_ptr_map.insert(child_id, raw_child); } - pub fn create_child_insert_before_element_of_container(&mut self, child_id: usize, insert_before_id: usize, container_id: usize) { + pub fn create_child_insert_before_element_of_container( + &mut self, + child_id: usize, + insert_before_id: usize, + container_id: usize, + ) { let mut child = Box::new(Node::default(child_id, Shapes::R(Rect::default()))); let container = self.get_tree_node_by_id(container_id).unwrap(); let raw_child: *mut _ = &mut *child; @@ -61,12 +66,8 @@ impl Instance { } else { let raw_node = self.node_ptr_map.get(&id); match raw_node { - Some(row_node) => { - unsafe { - Some(&mut **row_node) - } - }, - _ => None + Some(row_node) => unsafe { Some(&mut **row_node) }, + _ => None, } } } @@ -74,11 +75,11 @@ impl Instance { #[cfg(test)] mod test { + use super::Instance; + use crate::shape::PaintStyle; use crate::shape::Rect; use crate::shape::Shapes; - use crate::shape::PaintStyle; - use super::Instance; - use tiny_skia::{ColorU8}; + use tiny_skia::ColorU8; #[test] fn test_get_tree_node_by_id() { @@ -95,43 +96,79 @@ mod test { #[test] fn test_append() { let mut instance = Instance::new(0); - assert_eq!(instance.get_tree_node_by_id(0).unwrap().get_children_len(), 0); + assert_eq!( + instance.get_tree_node_by_id(0).unwrap().get_children_len(), + 0 + ); instance.create_child_append_to_container(1, 0); instance.create_child_append_to_container(2, 0); instance.create_child_append_to_container(3, 0); - assert_eq!(instance.get_tree_node_by_id(0).unwrap().get_children_len(), 3); + assert_eq!( + instance.get_tree_node_by_id(0).unwrap().get_children_len(), + 3 + ); } #[test] fn test_set_shape() { let mut instance = Instance::new(0); - assert_eq!(instance.get_tree_node_by_id(0).unwrap().get_children_len(), 0); + assert_eq!( + instance.get_tree_node_by_id(0).unwrap().get_children_len(), + 0 + ); instance.create_child_append_to_container(1, 0); - assert_eq!(instance.get_tree_node_by_id(0).unwrap().get_children_len(), 1); + assert_eq!( + instance.get_tree_node_by_id(0).unwrap().get_children_len(), + 1 + ); match instance.get_tree_node_by_id(1).unwrap().shape { - Shapes::R(Rect { x, y, width, height, color, style }) => { + Shapes::R(Rect { + x, + y, + width, + height, + color, + style, + }) => { assert_eq!(x, 0); assert_eq!(y, 0); - }, + } _ => { panic!() } } - 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 })); + 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 }) => { + 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.unwrap().green(), 100); - }, + } _ => { panic!() } @@ -145,16 +182,28 @@ mod test { instance.create_child_append_to_container(2, 0); instance.create_child_append_to_container(3, 0); - assert_eq!(instance.get_tree_node_by_id(0).unwrap().get_children_len(), 3); + assert_eq!( + instance.get_tree_node_by_id(0).unwrap().get_children_len(), + 3 + ); instance.remove_child_from_container(2, 0); - assert_eq!(instance.get_tree_node_by_id(0).unwrap().get_children_len(), 2); + assert_eq!( + instance.get_tree_node_by_id(0).unwrap().get_children_len(), + 2 + ); instance.remove_child_from_container(3, 0); - assert_eq!(instance.get_tree_node_by_id(0).unwrap().get_children_len(), 1); + assert_eq!( + instance.get_tree_node_by_id(0).unwrap().get_children_len(), + 1 + ); instance.remove_child_from_container(1, 0); - assert_eq!(instance.get_tree_node_by_id(0).unwrap().get_children_len(), 0); + assert_eq!( + instance.get_tree_node_by_id(0).unwrap().get_children_len(), + 0 + ); instance.remove_child_from_container(1, 0); instance.remove_child_from_container(1, 0); @@ -162,6 +211,9 @@ mod test { instance.remove_child_from_container(100, 0); instance.remove_child_from_container(100, 0); instance.remove_child_from_container(100, 0); - assert_eq!(instance.get_tree_node_by_id(0).unwrap().get_children_len(), 0); + assert_eq!( + instance.get_tree_node_by_id(0).unwrap().get_children_len(), + 0 + ); } -} \ No newline at end of file +} diff --git a/soft-skia/src/lib.rs b/soft-skia/src/lib.rs index f4e3d102..6e678d25 100644 --- a/soft-skia/src/lib.rs +++ b/soft-skia/src/lib.rs @@ -1,4 +1,5 @@ -pub mod tree; -pub mod shape; pub mod instance; -pub mod provider; \ No newline at end of file +pub mod provider; +pub mod shape; +pub mod tree; +mod util; diff --git a/soft-skia/src/shape.rs b/soft-skia/src/shape.rs index a0636256..e5479f76 100644 --- a/soft-skia/src/shape.rs +++ b/soft-skia/src/shape.rs @@ -1,8 +1,15 @@ use std::collections::HashMap; +use fontdue::{ + layout::{CoordinateSystem, Layout, LayoutSettings, TextStyle}, + Font, Metrics, +}; +use std::iter::zip; pub use tiny_skia::{ColorU8, FillRule, Mask, Paint, PathBuilder, Pixmap, Stroke, Transform}; use tiny_skia::{LineCap, LineJoin, Path, PixmapPaint}; +use crate::log; + #[derive(Debug)] pub enum Shapes { R(Rect), @@ -11,6 +18,7 @@ pub enum Shapes { L(Line), P(Points), I(Image), + T(Text), } #[derive(Debug)] @@ -41,7 +49,10 @@ impl DrawContext { pub trait Shape { fn default() -> Self; fn draw(&self, pixmap: &mut Pixmap, context: &DrawContext) -> (); - fn get_path(&self, context: &DrawContext) -> Path; + fn get_path(&self, context: &DrawContext) -> Path { + let pb = PathBuilder::new(); + pb.finish().unwrap() + } } #[derive(Debug, Clone, Copy)] @@ -105,6 +116,16 @@ pub struct Image { pub height: u32, } +#[derive(Debug)] +pub struct Text { + pub text: String, + pub x: i32, + pub y: i32, + pub font_size: f32, + pub color: Option, + pub max_width: Option, +} + impl Shapes { pub fn draw(&self, pixmap: &mut Pixmap, context: &DrawContext) -> () { match self { @@ -114,6 +135,7 @@ impl Shapes { Shapes::L(line) => line.draw(pixmap, context), Shapes::P(points) => points.draw(pixmap, context), Shapes::I(image) => image.draw(pixmap, context), + Shapes::T(text) => text.draw(pixmap, context), } } @@ -125,6 +147,7 @@ impl Shapes { Shapes::L(line) => line.get_path(context), Shapes::P(points) => points.get_path(context), Shapes::I(image) => image.get_path(context), + Shapes::T(text) => text.get_path(context), } } } @@ -510,10 +533,86 @@ impl Shape for Image { None, ); } - fn get_path(&self, context: &DrawContext) -> Path { - let pb = PathBuilder::new(); - pb.finish().unwrap() +} + +impl Shape for Text { + fn default() -> Self { + todo!() + } + + fn draw(&self, pixmap: &mut Pixmap, context: &DrawContext) -> () { + let font = include_bytes!("../assets/Roboto-Regular.ttf") as &[u8]; + let roboto_regular = Font::from_bytes(font, fontdue::FontSettings::default()).unwrap(); + let fonts = &[roboto_regular]; + let mut layout = Layout::new(CoordinateSystem::PositiveYDown); + layout.reset(&LayoutSettings { + max_width: self.max_width, + ..LayoutSettings::default() + }); + layout.append(fonts, &TextStyle::new(&self.text, self.font_size, 0)); + + let mut glyphs: Vec> = vec![]; + self.text.chars().for_each(|c| { + let (_, bitmap) = fonts[0].rasterize(c, self.font_size); + glyphs.push(bitmap); + }); + let dim = compute_dim(&layout); + + let mut bitmap: Vec = vec![0; dim.0 * dim.1]; + for (pos, char_bitmap) in zip(layout.glyphs(), &glyphs) { + let x = pos.x as i32; + let y = pos.y as i32 as i32; + let width = pos.width as usize; + let height = pos.height as usize; + let mut i = 0; + for y in y..y + height as i32 { + for x in x..x + width as i32 { + let index = (y * dim.0 as i32 + x) as usize; + if index < bitmap.len() { + bitmap[index] = char_bitmap[i]; + } + i += 1; + } + } + } + let mut rgba_bitmap: Vec = vec![]; + for i in 0..bitmap.len() { + if bitmap[i] == 0 { + rgba_bitmap.extend([0, 0, 0, 0].iter()); + continue; + } + if let Some(color) = self.color { + rgba_bitmap.extend([color.red(), color.green(), color.blue(), bitmap[i]].iter()); + } else { + rgba_bitmap.extend([0, 0, 0, bitmap[i]].iter()); + } + } + + let p = Pixmap::from_vec( + rgba_bitmap, + tiny_skia::IntSize::from_wh(dim.0 as u32, dim.1 as u32).unwrap(), + ) + .unwrap(); + pixmap.draw_pixmap( + self.x, + self.y, + p.as_ref(), + &PixmapPaint::default(), + Transform::from_row(1.0, 0.0, 0.0, 1.0, 0.0, 0.0), + None, + ); + } +} + +fn compute_dim(layout: &Layout) -> (usize, usize) { + let (mut x1, mut y1, mut x2, mut y2): (i32, i32, i32, i32) = (0, 0, 0, 0); + for pos in layout.glyphs() { + x1 = x1.min(pos.x as i32); + y1 = y1.min(pos.y as i32); + x2 = x2.max(pos.x as i32 + pos.width as i32); + y2 = y2.max(pos.y as i32 + pos.height as i32); } + return (1 + (x2 - x1) as usize, (y2 - y1) as usize); } #[cfg(test)] diff --git a/soft-skia/src/tree.rs b/soft-skia/src/tree.rs index 70ef3c91..3c3f4c95 100644 --- a/soft-skia/src/tree.rs +++ b/soft-skia/src/tree.rs @@ -1,8 +1,8 @@ use crate::provider::Providers; use crate::shape::Circle; +use crate::shape::DrawContext; use crate::shape::Rect; use crate::shape::Shape; -use crate::shape::DrawContext; use crate::shape::Shapes; use std::slice::Iter; use std::slice::IterMut; diff --git a/soft-skia/src/util.rs b/soft-skia/src/util.rs new file mode 100644 index 00000000..6af2195c --- /dev/null +++ b/soft-skia/src/util.rs @@ -0,0 +1,9 @@ +extern crate web_sys; + +// A macro to provide `println!(..)`-style syntax for `console.log` logging. +#[macro_export] +macro_rules! log { + ( $( $t:tt )* ) => { + web_sys::console::log_1(&format!( $( $t )* ).into()); + } +} diff --git a/src/lib.rs b/src/lib.rs index ca7fcafd..98ecdb01 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,3 @@ fn main() { - todo!() + todo!() } diff --git a/vue-playground/package-ci.json b/vue-playground/package-ci.json index fa736a26..7202e498 100644 --- a/vue-playground/package-ci.json +++ b/vue-playground/package-ci.json @@ -1,6 +1,6 @@ { "name": "vue-playground", - "version": "0.6.0", + "version": "0.7.0", "private": true, "scripts": { "serve": "vue-cli-service serve", diff --git a/vue-playground/src/App.vue b/vue-playground/src/App.vue index 7ff732e1..9fe3f5c3 100644 --- a/vue-playground/src/App.vue +++ b/vue-playground/src/App.vue @@ -29,6 +29,7 @@ VLine, VPoints, VImage, + VText, }" @error="(e: any) => void 0" @input="input" @@ -98,6 +99,7 @@ import launch, { VLine, VPoints, VImage, + VText, } from "vue-skia"; import { VueLive } from "vue-live"; import GithubCorners from "@uivjs/vue-github-corners"; @@ -119,6 +121,7 @@ export default defineComponent({ VLine, VPoints, VImage, + VText }, data() { return { @@ -133,6 +136,7 @@ export default defineComponent({ VLine, VPoints, VImage, + VText, code, LoadingCode, debug: false, diff --git a/vue-playground/src/code.ts b/vue-playground/src/code.ts index 28e5cf28..53f23d48 100644 --- a/vue-playground/src/code.ts +++ b/vue-playground/src/code.ts @@ -28,6 +28,7 @@ export default ` + `; diff --git a/vue-skia-framework/components/VText.vue b/vue-skia-framework/components/VText.vue new file mode 100644 index 00000000..9fc44b43 --- /dev/null +++ b/vue-skia-framework/components/VText.vue @@ -0,0 +1,37 @@ + + + diff --git a/vue-skia-framework/launch.ts b/vue-skia-framework/launch.ts index 4b67a64e..4039f8c7 100644 --- a/vue-skia-framework/launch.ts +++ b/vue-skia-framework/launch.ts @@ -9,13 +9,11 @@ const launch = function () { SSWInitialHelper.initialStatus = 1; const wasm = import("soft-skia-wasm/soft_skia_wasm.js"); wasm.then((ssw) => { - ssw.default().then(() => { window.ssw = ssw; while (SSWInitialHelper.initialSucceedCallbackQueue.length) { SSWInitialHelper.initialSucceedCallbackQueue.pop()(); } resolve(void 0) - }) }) } else if (SSWInitialHelper.initialStatus === 1) { SSWInitialHelper.initialSucceedCallbackQueue.push(() => resolve(void 0)); diff --git a/vue-skia-framework/main.js b/vue-skia-framework/main.js index 40bf0ec2..e2a129e1 100644 --- a/vue-skia-framework/main.js +++ b/vue-skia-framework/main.js @@ -8,7 +8,8 @@ import VRoundRect from "./components/VRoundRect.vue"; import VLine from "./components/VLine.vue"; import VPoints from "./components/VPoints.vue"; import VImage from './components/VImage.vue'; +import VText from './components/VText.vue'; export default launch; export { plugin as VueSkia } -export { VSurface, VGroup, VRect, VCircle, VRoundRect, VLine, VPoints, VImage } \ No newline at end of file +export { VSurface, VGroup, VRect, VCircle, VRoundRect, VLine, VPoints, VImage, VText } \ No newline at end of file diff --git a/vue-skia-framework/package-publish.json b/vue-skia-framework/package-publish.json index 3476a74d..35a2a7da 100644 --- a/vue-skia-framework/package-publish.json +++ b/vue-skia-framework/package-publish.json @@ -1,6 +1,6 @@ { "name": "vue-skia", - "version": "0.0.6", + "version": "0.0.7", "files": [ "lib", "type.d.ts", @@ -13,6 +13,6 @@ "main": "./main.js", "module": "./main.js", "dependencies": { - "soft-skia-wasm": "0.6.0" + "soft-skia-wasm": "0.7.0" } } diff --git a/vue-skia-framework/plugin/index.ts b/vue-skia-framework/plugin/index.ts index 719b29d7..5b891f78 100644 --- a/vue-skia-framework/plugin/index.ts +++ b/vue-skia-framework/plugin/index.ts @@ -23,7 +23,8 @@ const WidgetList = [ 'RoundRect', 'Rect', 'Circle', - 'Image' + 'Image', + 'Text' ]; const VSKNode = (name: string) => { @@ -173,6 +174,20 @@ const VSKNode = (name: string) => { }, }); } + if (name === "Text") { + core.setAttrBySerde(instance._ssw_id, { + attr: { + T: { + text: attrs.text, + x: attrs.x, + y: attrs.y, + font_size: attrs.fontSize, + color: attrs.color, + max_width: attrs.maxWidth, + }, + }, + }); + } } onBeforeUnmount(() => {