🔧 Autogenerate serialization values for wasm enums (#7296)

* 🔧 Autogenerate serialization values for wasm enums

* 🔧 Add serializer values to the wasm api

*  Avoid converting to a clojure map the serializer js object

* 🔧 Update watch script for autoserialized enums

* 🐛 Fix missing serializer values
This commit is contained in:
Belén Albeza
2025-09-16 12:29:14 +02:00
committed by GitHub
parent 01e963ae35
commit e5e11b6383
26 changed files with 592 additions and 304 deletions

View File

@@ -1072,10 +1072,35 @@
(let [uri (cf/resolve-static-asset "js/render_wasm.js")] (let [uri (cf/resolve-static-asset "js/render_wasm.js")]
(->> (js/dynamicImport (str uri)) (->> (js/dynamicImport (str uri))
(p/mcat (fn [module] (p/mcat (fn [module]
(let [default (unchecked-get module "default")] (let [default (unchecked-get module "default")
serializers #js{:blur-type (unchecked-get module "BlurType")
:bool-type (unchecked-get module "BoolType")
:font-style (unchecked-get module "FontStyle")
:flex-direction (unchecked-get module "FlexDirection")
:grid-direction (unchecked-get module "GridDirection")
:grow-type (unchecked-get module "GrowType")
:align-items (unchecked-get module "AlignItems")
:align-self (unchecked-get module "AlignSelf")
:align-content (unchecked-get module "AlignContent")
:justify-items (unchecked-get module "JustifyItems")
:justify-content (unchecked-get module "JustifyContent")
:justify-self (unchecked-get module "JustifySelf")
:wrap-type (unchecked-get module "WrapType")
:grid-track-type (unchecked-get module "GridTrackType")
:shadow-style (unchecked-get module "ShadowStyle")
:stroke-style (unchecked-get module "StrokeStyle")
:stroke-cap (unchecked-get module "StrokeCap")
:shape-type (unchecked-get module "Type")
:constraint-h (unchecked-get module "ConstraintH")
:constraint-v (unchecked-get module "ConstraintV")
:sizing (unchecked-get module "Sizing")
:vertical-align (unchecked-get module "VerticalAlign")
:fill-data (unchecked-get module "RawFillData")
:segment-data (unchecked-get module "RawSegmentData")}]
(set! wasm/serializers serializers)
(default)))) (default))))
(p/fmap (fn [module] (p/fmap (fn [default]
(set! wasm/internal-module module) (set! wasm/internal-module default)
true)) true))
(p/merr (fn [cause] (p/merr (fn [cause]
(js/console.error cause) (js/console.error cause)

View File

@@ -4,10 +4,12 @@
;; ;;
;; Copyright (c) KALEIDOS INC ;; Copyright (c) KALEIDOS INC
(ns app.render-wasm.serializers (ns app.render-wasm.serializers
(:require (:require
[app.common.uuid :as uuid] [app.common.data :as d]
[cuerdas.core :as str])) [app.common.uuid :as uuid]
[app.render-wasm.wasm :as wasm]
[cuerdas.core :as str]))
(defn u8 (defn u8
[value] [value]
@@ -56,37 +58,21 @@
(defn translate-shape-type (defn translate-shape-type
[type] [type]
(case type (let [values (unchecked-get wasm/serializers "shape-type")
:frame 0 default (unchecked-get values "rect")]
:group 1 (d/nilv (unchecked-get values (d/name type)) default)))
:bool 2
:rect 3
:path 4
:text 5
:circle 6
:svg-raw 7
:image 8))
(defn translate-stroke-style (defn translate-stroke-style
[stroke-style] [stroke-style]
(case stroke-style (let [values (unchecked-get wasm/serializers "stroke-style")
:dotted 1 default (unchecked-get values "solid")]
:dashed 2 (d/nilv (unchecked-get values (d/name stroke-style)) default)))
:mixed 3
0))
(defn translate-stroke-cap (defn translate-stroke-cap
[stroke-cap] [stroke-cap]
(case stroke-cap (let [values (unchecked-get wasm/serializers "stroke-cap")
:line-arrow 1 default (unchecked-get values "none")]
:triangle-arrow 2 (d/nilv (unchecked-get values (d/name stroke-cap)) default)))
:square-marker 3
:circle-marker 4
:diamond-marker 5
:round 6
:square 7
0))
(defn serialize-path-attrs (defn serialize-path-attrs
[svg-attrs] [svg-attrs]
@@ -120,143 +106,99 @@
(defn translate-constraint-h (defn translate-constraint-h
[type] [type]
(case type (let [values (unchecked-get wasm/serializers "constraint-h")
:left 0 default 5] ;; TODO: fix code in rust so we have a proper None variant
:right 1 (d/nilv (unchecked-get values (d/name type)) default)))
:leftright 2
:center 3
:scale 4))
(defn translate-constraint-v (defn translate-constraint-v
[type] [type]
(case type (let [values (unchecked-get wasm/serializers "constraint-v")
:top 0 default 5] ;; TODO: fix code in rust so we have a proper None variant
:bottom 1 (d/nilv (unchecked-get values (d/name type)) default)))
:topbottom 2
:center 3
:scale 4))
(defn translate-bool-type (defn translate-bool-type
[bool-type] [bool-type]
(case bool-type (let [values (unchecked-get wasm/serializers "bool-type")
:union 0 default (unchecked-get values "union")]
:difference 1 (d/nilv (unchecked-get values (d/name bool-type)) default)))
:intersection 2
:exclude 3
0))
(defn translate-blur-type (defn translate-blur-type
[blur-type] [blur-type]
(case blur-type (let [values (unchecked-get wasm/serializers "blur-type")
:layer-blur 1 default (unchecked-get values "none")]
0)) (d/nilv (unchecked-get values (d/name blur-type)) default)))
(defn translate-layout-flex-dir (defn translate-layout-flex-dir
[flex-dir] [flex-dir]
(case flex-dir (let [values (unchecked-get wasm/serializers "flex-direction")]
:row 0 (unchecked-get values (d/name flex-dir))))
:row-reverse 1
:column 2
:column-reverse 3))
(defn translate-layout-grid-dir (defn translate-layout-grid-dir
[flex-dir] [grid-dir]
(case flex-dir (let [values (unchecked-get wasm/serializers "grid-direction")]
:row 0 (unchecked-get values (d/name grid-dir))))
:column 1))
(defn translate-layout-align-items (defn translate-layout-align-items
[align-items] [align-items]
(case align-items (let [values (unchecked-get wasm/serializers "align-items")
:start 0 default (unchecked-get values "start")]
:end 1 (d/nilv (unchecked-get values (d/name align-items)) default)))
:center 2
:stretch 3
0))
(defn translate-layout-align-content (defn translate-layout-align-content
[align-content] [align-content]
(case align-content (let [values (unchecked-get wasm/serializers "align-content")
:start 0 default (unchecked-get values "stretch")]
:end 1 (d/nilv (unchecked-get values (d/name align-content)) default)))
:center 2
:space-between 3
:space-around 4
:space-evenly 5
:stretch 6
6))
(defn translate-layout-justify-items (defn translate-layout-justify-items
[justify-items] [justify-items]
(case justify-items (let [values (unchecked-get wasm/serializers "justify-items")
:start 0 default (unchecked-get values "start")]
:end 1 (d/nilv (unchecked-get values (d/name justify-items)) default)))
:center 2
:stretch 3
0))
(defn translate-layout-justify-content (defn translate-layout-justify-content
[justify-content] [justify-content]
(case justify-content (let [values (unchecked-get wasm/serializers "justify-content")
:start 0 default (unchecked-get values "stretch")]
:end 1 (d/nilv (unchecked-get values (d/name justify-content)) default)))
:center 2
:space-between 3
:space-around 4
:space-evenly 5
:stretch 6
6))
(defn translate-layout-wrap-type (defn translate-layout-wrap-type
[wrap-type] [wrap-type]
(case wrap-type (let [values (unchecked-get wasm/serializers "wrap-type")
:wrap 0 default (unchecked-get values "nowrap")]
:nowrap 1 (d/nilv (unchecked-get values (d/name wrap-type)) default)))
1))
(defn translate-grid-track-type (defn translate-grid-track-type
[type] [type]
(case type (let [values (unchecked-get wasm/serializers "grid-track-type")]
:percent 0 (unchecked-get values (d/name type))))
:flex 1
:auto 2
:fixed 3))
(defn translate-layout-sizing (defn translate-layout-sizing
[value] [sizing]
(case value (let [values (unchecked-get wasm/serializers "sizing")
:fill 0 default (unchecked-get values "fix")]
:fix 1 (d/nilv (unchecked-get values (d/name sizing)) default)))
:auto 2
1))
(defn translate-align-self (defn translate-align-self
[value] [align-self]
(when value (let [values (unchecked-get wasm/serializers "align-self")]
(case value (unchecked-get values (d/name align-self))))
:auto 0
:start 1
:end 2
:center 3
:stretch 4)))
(defn translate-justify-self (defn translate-justify-self
[value] [justify-self]
(when value (let [values (unchecked-get wasm/serializers "justify-self")]
(case value (unchecked-get values (d/name justify-self))))
:auto 0
:start 1
:end 2
:center 3
:stretch 4)))
(defn translate-shadow-style (defn translate-shadow-style
[style] [style]
(case style (let [values (unchecked-get wasm/serializers "shadow-style")
:drop-shadow 0 default (unchecked-get values "drop-shadow")]
:inner-shadow 1 (d/nilv (unchecked-get values (d/name style)) default)))
0))
;; TODO: Find/Create a Rust enum for this
(defn translate-structure-modifier-type (defn translate-structure-modifier-type
[type] [type]
(case type (case type
@@ -266,19 +208,17 @@
(defn translate-grow-type (defn translate-grow-type
[grow-type] [grow-type]
(case grow-type (let [values (unchecked-get wasm/serializers "grow-type")
:auto-width 1 default (unchecked-get values "fixed")]
:auto-height 2 (d/nilv (unchecked-get values (d/name grow-type)) default)))
0))
(defn translate-vertical-align (defn translate-vertical-align
[vertical-align] [vertical-align]
(case vertical-align (let [values (unchecked-get wasm/serializers "vertical-align")
"top" 0 default (unchecked-get values "top")]
"center" 1 (d/nilv (unchecked-get values (d/name vertical-align)) default)))
"bottom" 2
0))
;; TODO: Find/Create a Rust enum for this
(defn translate-text-align (defn translate-text-align
[text-align] [text-align]
(case text-align (case text-align
@@ -288,6 +228,7 @@
"justify" 3 "justify" 3
0)) 0))
;; TODO: Find/Create a Rust enum for this
(defn translate-text-transform (defn translate-text-transform
[text-transform] [text-transform]
(case text-transform (case text-transform
@@ -298,6 +239,7 @@
nil 0 nil 0
0)) 0))
;; TODO: Find/Create a Rust enum for this
(defn translate-text-decoration (defn translate-text-decoration
[text-decoration] [text-decoration]
(case text-decoration (case text-decoration
@@ -308,6 +250,7 @@
nil 0 nil 0
0)) 0))
;; TODO: Find/Create a Rust enum for this
(defn translate-text-direction (defn translate-text-direction
[text-direction] [text-direction]
(case text-direction (case text-direction
@@ -318,8 +261,12 @@
(defn translate-font-style (defn translate-font-style
[font-style] [font-style]
(case font-style (let [values (unchecked-get wasm/serializers "font-style")
"normal" 0 default (unchecked-get values "normal")]
"regular" 0 (case font-style
"italic" 1 ;; NOTE: normal == regular!
0)) ;; is it OK to keep those two values in our cljs model?
"normal" (unchecked-get values "normal")
"regular" (unchecked-get values "normal")
"italic" (unchecked-get values "italic")
default)))

View File

@@ -1,4 +1,5 @@
(ns app.render-wasm.wasm) (ns app.render-wasm.wasm)
(defonce internal-frame-id nil) (defonce internal-frame-id nil)
(defonce internal-module #js {}) (defonce internal-module #js {})
(defonce serializers #js {})

17
render-wasm/Cargo.lock generated
View File

@@ -298,6 +298,14 @@ version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "macros"
version = "0.1.0"
dependencies = [
"heck",
"syn",
]
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.7.4" version = "2.7.4"
@@ -359,9 +367,9 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.88" version = "1.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c3a7fc5db1e57d5a779a352c8cdb57b29aa4c40cc69c3a68a7fedc815fbf2f9" checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@@ -422,6 +430,7 @@ dependencies = [
"gl", "gl",
"glam", "glam",
"indexmap", "indexmap",
"macros",
"skia-safe", "skia-safe",
"uuid", "uuid",
] ]
@@ -548,9 +557,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.82" version = "2.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83540f837a8afc019423a8edb95b52a8effe46957ee402287f4292fae35be021" checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",

View File

@@ -6,6 +6,8 @@ repository = "https://github.com/penpot/penpot"
license-file = "../LICENSE" license-file = "../LICENSE"
description = "Wasm-based canvas renderer for Penpot" description = "Wasm-based canvas renderer for Penpot"
build = "build.rs"
[features] [features]
default = [] default = []
profile = ["profile-macros", "profile-raf"] profile = ["profile-macros", "profile-raf"]
@@ -22,12 +24,13 @@ bezier-rs = "0.4.0"
gl = "0.14.0" gl = "0.14.0"
glam = "0.24.2" glam = "0.24.2"
indexmap = "2.7.1" indexmap = "2.7.1"
macros = { path = "macros" }
skia-safe = { version = "0.87.0", default-features = false, features = [ skia-safe = { version = "0.87.0", default-features = false, features = [
"gl", "gl",
"svg", "svg",
"textlayout", "textlayout",
"binary-cache", "binary-cache",
"webp" "webp",
] } ] }
uuid = { version = "1.11.0", features = ["v4", "js"] } uuid = { version = "1.11.0", features = ["v4", "js"] }

View File

@@ -13,7 +13,9 @@ export SKIA_BINARIES_URL=${SKIA_BINARIES_URL:-"https://github.com/penpot/skia-bi
cargo build $_CARGO_PARAMS cargo build $_CARGO_PARAMS
cp target/wasm32-unknown-emscripten/$_BUILD_MODE/render_wasm.js ../frontend/resources/public/js/$_BUILD_NAME.js _SHARED_FILE=$(find target/wasm32-unknown-emscripten -name render_wasm_shared.js | head -n 1);
cat target/wasm32-unknown-emscripten/$_BUILD_MODE/render_wasm.js "$_SHARED_FILE" > ../frontend/resources/public/js/$_BUILD_NAME.js
cp target/wasm32-unknown-emscripten/$_BUILD_MODE/render_wasm.wasm ../frontend/resources/public/js/$_BUILD_NAME.wasm cp target/wasm32-unknown-emscripten/$_BUILD_MODE/render_wasm.wasm ../frontend/resources/public/js/$_BUILD_NAME.wasm
sed -i "s/render_wasm.wasm/$_BUILD_NAME.wasm?version=develop/g" ../frontend/resources/public/js/$_BUILD_NAME.js; sed -i "s/render_wasm.wasm/$_BUILD_NAME.wasm?version=develop/g" ../frontend/resources/public/js/$_BUILD_NAME.js;

3
render-wasm/build.rs Normal file
View File

@@ -0,0 +1,3 @@
// We need this empty script so OUT_DIR is automatically set and we can build
// the macros crate
fn main() {}

View File

@@ -25,7 +25,7 @@ Horizontal constraints are serialized as `u8`:
| ----- | --------- | | ----- | --------- |
| 0 | Left | | 0 | Left |
| 1 | Right | | 1 | Right |
| 2 | LeftRight | | 2 | Leftright |
| 3 | Center | | 3 | Center |
| 4 | Scale | | 4 | Scale |
| \_ | None | | \_ | None |
@@ -38,11 +38,22 @@ Vertical constraints are serialized as `u8`:
| ----- | --------- | | ----- | --------- |
| 0 | Top | | 0 | Top |
| 1 | Bottom | | 1 | Bottom |
| 2 | TopBottom | | 2 | Topbottom |
| 3 | Center | | 3 | Center |
| 4 | Scale | | 4 | Scale |
| \_ | None | | \_ | None |
## Vertical Alignment
Vertical alignment is serialized as `u8`:
| Value | Field |
| ----- | ------ |
| 0 | Top |
| 1 | Center |
| 2 | Bottom |
| \_ | Top |
## Paths ## Paths
Paths are made of segments of **28 bytes** each. The layout (assuming positions in a `Uint8Array`) is the following: Paths are made of segments of **28 bytes** each. The layout (assuming positions in a `Uint8Array`) is the following:
@@ -126,16 +137,17 @@ Gradient stops are serialized as a sequence of `16` chunks with the following la
Stroke caps are serialized as `u8`: Stroke caps are serialized as `u8`:
| Value | Field | | Value | Field |
| ----- | --------- | | ----- | ------------- |
| 1 | Line | | 0 | None |
| 2 | Triangle | | 1 | LineArrow |
| 3 | Rectangle | | 2 | TriangleArrow |
| 4 | Circle | | 3 | SquareMarker |
| 5 | Diamond | | 4 | CircleMarker |
| 6 | Round | | 5 | DiamondMarker |
| 7 | Square | | 6 | Round |
| \_ | None | | 7 | Square |
| \_ | None |
## Stroke Sytles ## Stroke Sytles

52
render-wasm/macros/Cargo.lock generated Normal file
View File

@@ -0,0 +1,52 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "macros"
version = "0.1.0"
dependencies = [
"heck",
"syn",
]
[[package]]
name = "proc-macro2"
version = "1.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
[[package]]
name = "syn"
version = "2.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"

View File

@@ -0,0 +1,11 @@
[package]
name = "macros"
version = "0.1.0"
edition = "2024"
[lib]
proc-macro = true
[dependencies]
heck = "0.5.0"
syn = "2.0.106"

View File

@@ -0,0 +1,103 @@
use std::collections::HashMap;
use std::fs;
use std::io::Write;
use std::path::Path;
use std::sync;
use heck::{ToKebabCase, ToPascalCase};
use proc_macro::TokenStream;
type Result<T> = std::result::Result<T, String>;
#[proc_macro_derive(ToJs)]
pub fn derive_to_cljs(input: TokenStream) -> TokenStream {
let input = syn::parse_macro_input!(input as syn::DeriveInput);
let enum_id = input.ident.to_string();
let data_enum = match input.data {
syn::Data::Enum(data_enum) => data_enum,
_ => panic!("ToCljs can only be derived for enums"),
};
let raw_variants = data_enum
.variants
.to_owned()
.into_iter()
.collect::<Vec<_>>();
let variants = parse_variants(&raw_variants).expect("Failed to parse variants");
let js_code = generate_js_for_enum(&enum_id, &mut variants.into_iter().collect::<Vec<_>>());
if let Err(e) = write_enum_to_temp_file(&js_code) {
eprintln!("Error writing enum {} to file: {}", enum_id, e);
}
TokenStream::new() // we don't need to return any generated code
}
fn parse_variants(variants: &[syn::Variant]) -> Result<HashMap<String, u32>> {
let mut res = HashMap::new();
for variant in variants {
let value_expr = variant
.discriminant
.clone()
.ok_or(format!(
"No discriminant found for variant {}",
variant.ident
))?
.1;
let discriminant = parse_discriminant_value(value_expr)?;
res.insert(variant.ident.to_string(), discriminant);
}
Ok(res)
}
fn parse_discriminant_value(value: syn::Expr) -> Result<u32> {
match value {
syn::Expr::Lit(syn::ExprLit {
lit: syn::Lit::Int(int),
..
}) => Ok(int.base10_digits().parse().unwrap()),
_ => Err(format!("Invalid discriminant value")),
}
}
fn generate_js_for_enum(id: &str, variants: &mut [(String, u32)]) -> String {
variants.sort_by_key(|(_, discriminant)| *discriminant);
let output_variants: String = variants
.into_iter()
.map(|(variant, discriminant)| {
format!(r#" "{}": {},"#, variant.to_kebab_case(), discriminant)
})
.collect::<Vec<String>>()
.join("\n");
format!(
"export const {} = {{\n{}\n}};",
id.to_pascal_case(),
output_variants
)
}
static INIT: sync::Once = sync::Once::new();
fn write_enum_to_temp_file(js_code: &str) -> std::io::Result<()> {
let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR environment variable is not set");
let out_path = Path::new(&out_dir).join("render_wasm_shared.js");
// clean the file the first time this function is called
INIT.call_once(|| {
fs::OpenOptions::new()
.create(true)
.write(true)
.truncate(true)
.open(&out_path)
.expect("Failed to open output file");
});
let mut file = fs::OpenOptions::new().append(true).open(&out_path)?;
writeln!(file, "{}\n", js_code)?;
Ok(())
}

View File

@@ -563,19 +563,19 @@ impl RenderState {
let mut nested_blur_value = 0.; let mut nested_blur_value = 0.;
for nested_blur in self.nested_blurs.iter().flatten() { for nested_blur in self.nested_blurs.iter().flatten() {
if !nested_blur.hidden && nested_blur.blur_type == BlurType::Layer { if !nested_blur.hidden && nested_blur.blur_type == BlurType::LayerBlur {
nested_blur_value += nested_blur.value.powf(2.); nested_blur_value += nested_blur.value.powf(2.);
} }
} }
if !shape.blur.hidden && shape.blur.blur_type == BlurType::Layer { if !shape.blur.hidden && shape.blur.blur_type == BlurType::LayerBlur {
nested_blur_value += shape.blur.value.powf(2.); nested_blur_value += shape.blur.value.powf(2.);
} }
if nested_blur_value > 0. { if nested_blur_value > 0. {
shape shape
.to_mut() .to_mut()
.set_blur(BlurType::Layer as u8, false, nested_blur_value.sqrt()); .set_blur(BlurType::LayerBlur as u8, false, nested_blur_value.sqrt());
} }
let center = shape.center(); let center = shape.center();

View File

@@ -1,5 +1,7 @@
use skia_safe as skia; use skia_safe as skia;
// TODO: maybe move this to the wasm module?
// TODO: find a way to use the ToJS derive macro for this
#[derive(Debug, PartialEq, Clone, Copy)] #[derive(Debug, PartialEq, Clone, Copy)]
pub struct BlendMode(skia::BlendMode); pub struct BlendMode(skia::BlendMode);

View File

@@ -183,22 +183,22 @@ fn handle_stroke_cap(
paint.set_style(skia::PaintStyle::Fill); paint.set_style(skia::PaintStyle::Fill);
match cap { match cap {
StrokeCap::None => {} StrokeCap::None => {}
StrokeCap::Line => { StrokeCap::LineArrow => {
// We also draw this square cap to fill the gap between the path and the arrow // We also draw this square cap to fill the gap between the path and the arrow
draw_square_cap(canvas, paint, p1, p2, width, 0.); draw_square_cap(canvas, paint, p1, p2, width, 0.);
paint.set_style(skia::PaintStyle::Stroke); paint.set_style(skia::PaintStyle::Stroke);
draw_arrow_cap(canvas, paint, p1, p2, width * 4.); draw_arrow_cap(canvas, paint, p1, p2, width * 4.);
} }
StrokeCap::Triangle => { StrokeCap::TriangleArrow => {
draw_triangle_cap(canvas, paint, p1, p2, width * 4.); draw_triangle_cap(canvas, paint, p1, p2, width * 4.);
} }
StrokeCap::Rectangle => { StrokeCap::SquareMarker => {
draw_square_cap(canvas, paint, p1, p2, width * 4., 0.); draw_square_cap(canvas, paint, p1, p2, width * 4., 0.);
} }
StrokeCap::Circle => { StrokeCap::CircleMarker => {
canvas.draw_circle((p1.x, p1.y), width * 2., paint); canvas.draw_circle((p1.x, p1.y), width * 2., paint);
} }
StrokeCap::Diamond => { StrokeCap::DiamondMarker => {
draw_square_cap(canvas, paint, p1, p2, width * 4., 45.); draw_square_cap(canvas, paint, p1, p2, width * 4., 45.);
} }
StrokeCap::Round => { StrokeCap::Round => {

View File

@@ -1,3 +1,4 @@
use macros::ToJs;
use skia_safe::{self as skia}; use skia_safe::{self as skia};
use crate::render::BlendMode; use crate::render::BlendMode;
@@ -54,19 +55,22 @@ const MIN_VISIBLE_SIZE: f32 = 2.0;
const ANTIALIAS_THRESHOLD: f32 = 15.0; const ANTIALIAS_THRESHOLD: f32 = 15.0;
const MIN_STROKE_WIDTH: f32 = 0.001; const MIN_STROKE_WIDTH: f32 = 0.001;
#[derive(Debug, Clone, PartialEq)] // TODO: maybe move this to the wasm module?
#[derive(Debug, Clone, PartialEq, ToJs)]
#[repr(u8)]
pub enum Type { pub enum Type {
Frame(Frame), Frame(Frame) = 0,
Group(Group), Group(Group) = 1,
Bool(Bool), Bool(Bool) = 2,
Rect(Rect), Rect(Rect) = 3,
Path(Path), Path(Path) = 4,
Circle, Text(TextContent) = 5,
SVGRaw(SVGRaw), Circle = 6,
Text(TextContent), SVGRaw(SVGRaw) = 7,
} }
impl Type { impl Type {
// TODO: move this to the wasm module, use transmute
pub fn from(value: u8) -> Self { pub fn from(value: u8) -> Self {
match value { match value {
0 => Type::Frame(Frame::default()), 0 => Type::Frame(Frame::default()),
@@ -141,21 +145,24 @@ impl Type {
} }
} }
#[derive(Debug, Clone, PartialEq, Copy)] #[derive(Debug, Clone, PartialEq, Copy, ToJs)]
#[repr(u8)]
pub enum ConstraintH { pub enum ConstraintH {
Left, Left = 0,
Right, Right = 1,
LeftRight, Leftright = 2,
Center, Center = 3,
Scale, Scale = 4,
} }
impl ConstraintH { impl ConstraintH {
// TODO: we should implement a proper From trait for this
// TODO: use transmute
pub fn from(value: u8) -> Option<Self> { pub fn from(value: u8) -> Option<Self> {
match value { match value {
0 => Some(Self::Left), 0 => Some(Self::Left),
1 => Some(Self::Right), 1 => Some(Self::Right),
2 => Some(Self::LeftRight), 2 => Some(Self::Leftright),
3 => Some(Self::Center), 3 => Some(Self::Center),
4 => Some(Self::Scale), 4 => Some(Self::Scale),
_ => None, _ => None,
@@ -163,14 +170,18 @@ impl ConstraintH {
} }
} }
#[derive(Debug, Clone, PartialEq, Copy)] // TODO: maybe move this to the wasm module?
#[derive(Debug, Clone, PartialEq, Copy, ToJs)]
#[repr(u8)]
pub enum VerticalAlign { pub enum VerticalAlign {
Top, Top = 0,
Center, Center = 1,
Bottom, Bottom = 2,
} }
impl VerticalAlign { impl VerticalAlign {
// TODO: implement a proper From trait for this
// TODO: use transmute
pub fn from(value: u8) -> Self { pub fn from(value: u8) -> Self {
match value { match value {
0 => Self::Top, 0 => Self::Top,
@@ -181,21 +192,25 @@ impl VerticalAlign {
} }
} }
#[derive(Debug, Clone, PartialEq, Copy)] // TODO: maybe move this to the wasm module?
#[derive(Debug, Clone, PartialEq, Copy, ToJs)]
#[repr(u8)]
pub enum ConstraintV { pub enum ConstraintV {
Top, Top = 0,
Bottom, Bottom = 1,
TopBottom, Topbottom = 2,
Center, Center = 3,
Scale, Scale = 4,
} }
impl ConstraintV { impl ConstraintV {
// TODO: implement a proper From trait for this
// TODO: use transmute
pub fn from(value: u8) -> Option<Self> { pub fn from(value: u8) -> Option<Self> {
match value { match value {
0 => Some(Self::Top), 0 => Some(Self::Top),
1 => Some(Self::Bottom), 1 => Some(Self::Bottom),
2 => Some(Self::TopBottom), 2 => Some(Self::Topbottom),
3 => Some(Self::Center), 3 => Some(Self::Center),
4 => Some(Self::Scale), 4 => Some(Self::Scale),
_ => None, _ => None,
@@ -973,7 +988,7 @@ impl Shape {
if !self.blur.hidden { if !self.blur.hidden {
match self.blur.blur_type { match self.blur.blur_type {
BlurType::None => None, BlurType::None => None,
BlurType::Layer => skia::image_filters::blur( BlurType::LayerBlur => skia::image_filters::blur(
(self.blur.value * scale, self.blur.value * scale), (self.blur.value * scale, self.blur.value * scale),
None, None,
None, None,
@@ -990,7 +1005,7 @@ impl Shape {
if !self.blur.hidden { if !self.blur.hidden {
match self.blur.blur_type { match self.blur.blur_type {
BlurType::None => None, BlurType::None => None,
BlurType::Layer => skia::MaskFilter::blur( BlurType::LayerBlur => skia::MaskFilter::blur(
skia::BlurStyle::Normal, skia::BlurStyle::Normal,
self.blur.value * scale, self.blur.value * scale,
Some(true), Some(true),

View File

@@ -1,7 +1,10 @@
#[derive(Debug, Clone, Copy, PartialEq)] use macros::ToJs;
#[derive(Debug, Clone, Copy, PartialEq, ToJs)]
#[repr(u8)]
pub enum BlurType { pub enum BlurType {
None, None = 0,
Layer, LayerBlur = 1,
} }
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
@@ -11,10 +14,12 @@ pub struct Blur {
pub value: f32, pub value: f32,
} }
// TODO: maybe move this to the wasm module?
impl From<u8> for BlurType { impl From<u8> for BlurType {
// TODO: use transmute
fn from(value: u8) -> Self { fn from(value: u8) -> Self {
match value { match value {
1 => BlurType::Layer, 1 => BlurType::LayerBlur,
_ => BlurType::None, _ => BlurType::None,
} }
} }

View File

@@ -1,3 +1,5 @@
use macros::ToJs;
use super::Path; use super::Path;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@@ -6,12 +8,14 @@ pub struct Bool {
pub path: Path, pub path: Path,
} }
#[derive(Debug, Clone, Copy, PartialEq)] // TODO: maybe move this to the wasm module?
#[derive(Debug, Clone, Copy, PartialEq, ToJs)]
#[repr(u8)]
pub enum BoolType { pub enum BoolType {
Union, Union = 0,
Difference, Difference = 1,
Intersection, Intersection = 2,
Exclusion, Exclusion = 3,
} }
impl Default for Bool { impl Default for Bool {
@@ -23,7 +27,9 @@ impl Default for Bool {
} }
} }
// TODO: maybe move this to the wasm module?
impl From<u8> for BoolType { impl From<u8> for BoolType {
// TODO: use transmute
fn from(value: u8) -> Self { fn from(value: u8) -> Self {
match value { match value {
0 => Self::Union, 0 => Self::Union,

View File

@@ -1,14 +1,19 @@
use std::fmt; use std::fmt;
use crate::uuid::Uuid; use crate::uuid::Uuid;
use macros::ToJs;
#[derive(Debug, PartialEq, Clone, Copy)] // TODO: maybe move this to the wasm module?
#[derive(Debug, PartialEq, Clone, Copy, ToJs)]
#[repr(u8)]
pub enum FontStyle { pub enum FontStyle {
Normal, Normal = 0,
Italic, Italic = 1,
} }
// TODO: maybe move this to the wasm module?
impl From<u8> for FontStyle { impl From<u8> for FontStyle {
// TODO: use transmute
fn from(value: u8) -> Self { fn from(value: u8) -> Self {
match value { match value {
0 => Self::Normal, 0 => Self::Normal,

View File

@@ -1,3 +1,5 @@
use macros::ToJs;
use crate::utils::uuid_from_u32_quartet; use crate::utils::uuid_from_u32_quartet;
use crate::uuid::Uuid; use crate::uuid::Uuid;
@@ -22,15 +24,20 @@ impl Layout {
} }
} }
#[derive(Debug, Clone, PartialEq)] // TODO: maybe move this to the wasm module?
#[derive(Debug, Clone, PartialEq, ToJs)]
#[repr(u8)]
pub enum FlexDirection { pub enum FlexDirection {
Row, Row = 0,
RowReverse, RowReverse = 1,
Column, Column = 2,
ColumnReverse, ColumnReverse = 3,
} }
// TODO: maybe move this to the wasm module?
impl FlexDirection { impl FlexDirection {
// TODO: implement a proper From trait for this
// TODO: use transmute
pub fn from_u8(value: u8) -> Self { pub fn from_u8(value: u8) -> Self {
match value { match value {
0 => Self::Row, 0 => Self::Row,
@@ -42,13 +49,18 @@ impl FlexDirection {
} }
} }
#[derive(Debug, Clone, PartialEq)] // TODO: maybe move this to the wasm module?
#[derive(Debug, Clone, PartialEq, ToJs)]
#[repr(u8)]
pub enum GridDirection { pub enum GridDirection {
Row, Row = 0,
Column, Column = 1,
} }
// TODO: maybe move this to the wasm module?
impl GridDirection { impl GridDirection {
// TODO: implement a proper From trait for this
// TODO: use transmute
pub fn from_u8(value: u8) -> Self { pub fn from_u8(value: u8) -> Self {
match value { match value {
0 => Self::Row, 0 => Self::Row,
@@ -58,15 +70,20 @@ impl GridDirection {
} }
} }
#[derive(Debug, Clone, PartialEq, Copy)] // TODO: maybe move this to the wasm module?
#[derive(Debug, Clone, PartialEq, Copy, ToJs)]
#[repr(u8)]
pub enum AlignItems { pub enum AlignItems {
Start, Start = 0,
End, End = 1,
Center, Center = 2,
Stretch, Stretch = 3,
} }
// TODO: maybe move this to the wasm module?
impl AlignItems { impl AlignItems {
// TODO: implement a proper From trait for this
// TODO: use transmute
pub fn from_u8(value: u8) -> Self { pub fn from_u8(value: u8) -> Self {
match value { match value {
0 => Self::Start, 0 => Self::Start,
@@ -78,18 +95,23 @@ impl AlignItems {
} }
} }
#[derive(Debug, Clone, PartialEq, Copy)] // TODO: maybe move this to the wasm module?
#[derive(Debug, Clone, PartialEq, Copy, ToJs)]
#[repr(u8)]
pub enum AlignContent { pub enum AlignContent {
Start, Start = 0,
End, End = 1,
Center, Center = 2,
SpaceBetween, SpaceBetween = 3,
SpaceAround, SpaceAround = 4,
SpaceEvenly, SpaceEvenly = 5,
Stretch, Stretch = 6,
} }
// TODO: maybe move this to the wasm module?
impl AlignContent { impl AlignContent {
// TODO: implement a proper From trait for this
// TODO: use transmute
pub fn from_u8(value: u8) -> Self { pub fn from_u8(value: u8) -> Self {
match value { match value {
0 => Self::Start, 0 => Self::Start,
@@ -104,15 +126,20 @@ impl AlignContent {
} }
} }
#[derive(Debug, Clone, PartialEq, Copy)] // TODO: maybe move this to the wasm module?
#[derive(Debug, Clone, PartialEq, Copy, ToJs)]
#[repr(u8)]
pub enum JustifyItems { pub enum JustifyItems {
Start, Start = 0,
End, End = 1,
Center, Center = 2,
Stretch, Stretch = 3,
} }
// TODO: maybe move this to the wasm module?
impl JustifyItems { impl JustifyItems {
// TODO: implement a proper From trait for this
// TODO: use transmute
pub fn from_u8(value: u8) -> Self { pub fn from_u8(value: u8) -> Self {
match value { match value {
0 => Self::Start, 0 => Self::Start,
@@ -124,18 +151,23 @@ impl JustifyItems {
} }
} }
#[derive(Debug, Clone, PartialEq, Copy)] // TODO: maybe move this to the wasm module?
#[derive(Debug, Clone, PartialEq, Copy, ToJs)]
#[repr(u8)]
pub enum JustifyContent { pub enum JustifyContent {
Start, Start = 0,
End, End = 1,
Center, Center = 2,
SpaceBetween, SpaceBetween = 3,
SpaceAround, SpaceAround = 4,
SpaceEvenly, SpaceEvenly = 5,
Stretch, Stretch = 6,
} }
// TODO: maybe move this to the wasm module?
impl JustifyContent { impl JustifyContent {
// TODO: implement a proper From trait for this
// TODO: use transmute
pub fn from_u8(value: u8) -> Self { pub fn from_u8(value: u8) -> Self {
match value { match value {
0 => Self::Start, 0 => Self::Start,
@@ -150,30 +182,41 @@ impl JustifyContent {
} }
} }
#[derive(Debug, Clone, PartialEq)] // TODO: maybe move this to the wasm module?
#[derive(Debug, Clone, PartialEq, ToJs)]
#[repr(u8)]
pub enum WrapType { pub enum WrapType {
Wrap, Wrap = 0,
NoWrap, Nowrap = 1,
} }
// TODO: maybe move this to the wasm module?
impl WrapType { impl WrapType {
// TODO: implement a proper From trait for this
// TODO: use transmute
pub fn from_u8(value: u8) -> Self { pub fn from_u8(value: u8) -> Self {
match value { match value {
0 => Self::Wrap, 0 => Self::Wrap,
1 => Self::NoWrap, 1 => Self::Nowrap,
_ => unreachable!(), _ => unreachable!(),
} }
} }
} }
#[derive(Debug, Copy, Clone, PartialEq)]
// TODO: maybe move this to the wasm module?
#[derive(Debug, Copy, Clone, PartialEq, ToJs)]
#[repr(u8)]
pub enum GridTrackType { pub enum GridTrackType {
Percent, Percent = 0,
Flex, Flex = 1,
Auto, Auto = 2,
Fixed, Fixed = 3,
} }
// TODO: maybe move this to the wasm module?
impl GridTrackType { impl GridTrackType {
// TODO: implement a proper From trait for this
// TODO: use transmute
pub fn from_u8(value: u8) -> Self { pub fn from_u8(value: u8) -> Self {
match value { match value {
0 => Self::Percent, 0 => Self::Percent,
@@ -248,14 +291,19 @@ impl GridCell {
} }
} }
#[derive(Debug, Clone, PartialEq, Copy)] // TODO: maybe move this to the wasm module?
#[derive(Debug, Clone, PartialEq, Copy, ToJs)]
#[repr(u8)]
pub enum Sizing { pub enum Sizing {
Fill, Fill = 0,
Fix, Fix = 1,
Auto, Auto = 2,
} }
// TODO: maybe move this to the wasm module?
impl Sizing { impl Sizing {
// TODO: implement a proper From trait for this
// TODO: use transmute
pub fn from_u8(value: u8) -> Self { pub fn from_u8(value: u8) -> Self {
match value { match value {
0 => Self::Fill, 0 => Self::Fill,
@@ -291,16 +339,21 @@ impl LayoutData {
} }
} }
#[derive(Debug, Copy, Clone, PartialEq)] // TODO: maybe move this to the wasm module?
#[derive(Debug, Copy, Clone, PartialEq, ToJs)]
#[repr(u8)]
pub enum AlignSelf { pub enum AlignSelf {
Auto, Auto = 0,
Start, Start = 1,
End, End = 2,
Center, Center = 3,
Stretch, Stretch = 4,
} }
// TODO: maybe move this to the wasm module?
impl AlignSelf { impl AlignSelf {
// TODO: implement a proper From trait for this
// TODO: use transmute
pub fn from_u8(value: u8) -> Option<AlignSelf> { pub fn from_u8(value: u8) -> Option<AlignSelf> {
match value { match value {
0 => Some(Self::Auto), 0 => Some(Self::Auto),
@@ -313,16 +366,21 @@ impl AlignSelf {
} }
} }
#[derive(Debug, Copy, Clone, PartialEq)] // TODO: maybe move this to the wasm module?
#[derive(Debug, Copy, Clone, PartialEq, ToJs)]
#[repr(u8)]
pub enum JustifySelf { pub enum JustifySelf {
Auto, Auto = 0,
Start, Start = 1,
End, End = 2,
Center, Center = 3,
Stretch, Stretch = 4,
} }
// TODO: maybe move this to the wasm module?
impl JustifySelf { impl JustifySelf {
// TODO: implement a proper From trait for this
// TODO: use transmute
pub fn from_u8(value: u8) -> Option<JustifySelf> { pub fn from_u8(value: u8) -> Option<JustifySelf> {
match value { match value {
0 => Some(Self::Auto), 0 => Some(Self::Auto),
@@ -385,6 +443,7 @@ impl GridData {
} }
} }
// TODO: move this to the wasm module
// FIXME: use transmute // FIXME: use transmute
#[derive(Debug)] #[derive(Debug)]
#[repr(C)] #[repr(C)]

View File

@@ -13,7 +13,7 @@ pub fn calculate_resize(
ConstraintH::Left | ConstraintH::Right | ConstraintH::Center => { ConstraintH::Left | ConstraintH::Right | ConstraintH::Center => {
parent_before.width() / f32::max(0.01, parent_after.width()) parent_before.width() / f32::max(0.01, parent_after.width())
} }
ConstraintH::LeftRight => { ConstraintH::Leftright => {
let left = parent_before.left(child_before.nw); let left = parent_before.left(child_before.nw);
let right = parent_before.right(child_before.ne); let right = parent_before.right(child_before.ne);
let target_width = parent_after.width() - left - right; let target_width = parent_after.width() - left - right;
@@ -26,7 +26,7 @@ pub fn calculate_resize(
ConstraintV::Top | ConstraintV::Bottom | ConstraintV::Center => { ConstraintV::Top | ConstraintV::Bottom | ConstraintV::Center => {
parent_before.height() / f32::max(0.01, parent_after.height()) parent_before.height() / f32::max(0.01, parent_after.height())
} }
ConstraintV::TopBottom => { ConstraintV::Topbottom => {
let top = parent_before.top(child_before.nw); let top = parent_before.top(child_before.nw);
let bottom = parent_before.bottom(child_before.sw); let bottom = parent_before.bottom(child_before.sw);
let target_height = parent_after.height() - top - bottom; let target_height = parent_after.height() - top - bottom;
@@ -51,7 +51,7 @@ pub fn calculate_displacement(
child_after: &Bounds, child_after: &Bounds,
) -> Option<(f32, f32)> { ) -> Option<(f32, f32)> {
let delta_x = match constraint_h { let delta_x = match constraint_h {
ConstraintH::Left | ConstraintH::LeftRight => { ConstraintH::Left | ConstraintH::Leftright => {
let target_left = parent_before.left(child_before.nw); let target_left = parent_before.left(child_before.nw);
let current_left = parent_after.left(child_after.nw); let current_left = parent_after.left(child_after.nw);
target_left - current_left target_left - current_left
@@ -71,7 +71,7 @@ pub fn calculate_displacement(
}; };
let delta_y = match constraint_v { let delta_y = match constraint_v {
ConstraintV::Top | ConstraintV::TopBottom => { ConstraintV::Top | ConstraintV::Topbottom => {
let target_top = parent_before.top(child_before.nw); let target_top = parent_before.top(child_before.nw);
let current_top = parent_after.top(child_after.nw); let current_top = parent_after.top(child_after.nw);
target_top - current_top target_top - current_top

View File

@@ -1,15 +1,20 @@
use macros::ToJs;
use skia_safe::{self as skia, image_filters, ImageFilter, Paint}; use skia_safe::{self as skia, image_filters, ImageFilter, Paint};
use super::Color; use super::Color;
use crate::render::filters::compose_filters; use crate::render::filters::compose_filters;
#[derive(Debug, Clone, Copy, PartialEq)] // TODO: maybe move this to the wasm module?
#[derive(Debug, Clone, Copy, PartialEq, ToJs)]
#[repr(u8)]
pub enum ShadowStyle { pub enum ShadowStyle {
Drop, Drop = 0,
Inner, Inner = 1,
} }
// TODO: maybe move this to the wasm module?
impl From<u8> for ShadowStyle { impl From<u8> for ShadowStyle {
// TODO: use transmute
fn from(value: u8) -> Self { fn from(value: u8) -> Self {
match value { match value {
0 => Self::Drop, 0 => Self::Drop,

View File

@@ -1,18 +1,23 @@
use crate::shapes::fills::{Fill, SolidColor}; use crate::shapes::fills::{Fill, SolidColor};
use macros::ToJs;
use skia_safe::{self as skia, Rect}; use skia_safe::{self as skia, Rect};
use std::collections::HashMap; use std::collections::HashMap;
use super::Corners; use super::Corners;
#[derive(Debug, Clone, PartialEq)] // TODO: maybe move this to the wasm module?
#[derive(Debug, Clone, PartialEq, ToJs)]
#[repr(u8)]
pub enum StrokeStyle { pub enum StrokeStyle {
Solid, Solid = 0,
Dotted, Dotted = 1,
Dashed, Dashed = 2,
Mixed, Mixed = 3,
} }
// TODO: maybe move this to the wasm module?
impl From<u8> for StrokeStyle { impl From<u8> for StrokeStyle {
// TODO: use transmute
fn from(value: u8) -> Self { fn from(value: u8) -> Self {
match value { match value {
1 => StrokeStyle::Dotted, 1 => StrokeStyle::Dotted,
@@ -23,26 +28,29 @@ impl From<u8> for StrokeStyle {
} }
} }
#[derive(Debug, Clone, Copy, PartialEq)] // TODO: maybe move this to the wasm module?
#[derive(Debug, Clone, Copy, PartialEq, ToJs)]
pub enum StrokeCap { pub enum StrokeCap {
None, None = 0,
Line, LineArrow = 1,
Triangle, TriangleArrow = 2,
Rectangle, SquareMarker = 3,
Circle, CircleMarker = 4,
Diamond, DiamondMarker = 5,
Round, Round = 6,
Square, Square = 7,
} }
// TODO: maybe move this to the wasm module?
impl From<u8> for StrokeCap { impl From<u8> for StrokeCap {
// TODO: use transmute
fn from(value: u8) -> Self { fn from(value: u8) -> Self {
match value { match value {
1 => StrokeCap::Line, 1 => StrokeCap::LineArrow,
2 => StrokeCap::Triangle, 2 => StrokeCap::TriangleArrow,
3 => StrokeCap::Rectangle, 3 => StrokeCap::SquareMarker,
4 => StrokeCap::Circle, 4 => StrokeCap::CircleMarker,
5 => StrokeCap::Diamond, 5 => StrokeCap::DiamondMarker,
6 => StrokeCap::Round, 6 => StrokeCap::Round,
7 => StrokeCap::Square, 7 => StrokeCap::Square,
_ => StrokeCap::None, _ => StrokeCap::None,

View File

@@ -4,6 +4,7 @@ use crate::{
textlayout::paragraph_builder_group_from_text, textlayout::paragraph_builder_group_from_text,
}; };
use macros::ToJs;
use skia_safe::{ use skia_safe::{
self as skia, self as skia,
paint::{self, Paint}, paint::{self, Paint},
@@ -18,14 +19,18 @@ use crate::utils::uuid_from_u32;
use crate::wasm::fills::parse_fills_from_bytes; use crate::wasm::fills::parse_fills_from_bytes;
use crate::Uuid; use crate::Uuid;
#[derive(Debug, PartialEq, Clone, Copy)] // TODO: maybe move this to the wasm module?
#[derive(Debug, PartialEq, Clone, Copy, ToJs)]
#[repr(u8)]
pub enum GrowType { pub enum GrowType {
Fixed, Fixed = 0,
AutoWidth, AutoWidth = 1,
AutoHeight, AutoHeight = 2,
} }
// TODO: maybe move this to the wasm module?
impl GrowType { impl GrowType {
// TODO: use transmute
pub fn from(grow_type: u8) -> Self { pub fn from(grow_type: u8) -> Self {
match grow_type { match grow_type {
0 => Self::Fixed, 0 => Self::Fixed,
@@ -134,6 +139,8 @@ impl Default for TextContent {
} }
} }
// FIXME: Rethink this type. We'll probably need to move the serialization to the
// wasm moduel and store here meaningful model values (and/or skia type aliases)
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub struct Paragraph { pub struct Paragraph {
num_leaves: u32, num_leaves: u32,
@@ -207,6 +214,7 @@ impl Paragraph {
self.children.push(leaf); self.children.push(leaf);
} }
// FIXME: move serialization to wasm module
pub fn paragraph_to_style(&self) -> ParagraphStyle { pub fn paragraph_to_style(&self) -> ParagraphStyle {
let mut style = ParagraphStyle::default(); let mut style = ParagraphStyle::default();
style.set_text_align(match self.text_align { style.set_text_align(match self.text_align {

View File

@@ -1,16 +1,18 @@
mod gradient; use macros::ToJs;
mod image;
mod solid;
use crate::mem; use crate::mem;
use crate::shapes; use crate::shapes;
use crate::with_current_shape_mut; use crate::with_current_shape_mut;
use crate::STATE; use crate::STATE;
mod gradient;
mod image;
mod solid;
const RAW_FILL_DATA_SIZE: usize = std::mem::size_of::<RawFillData>(); const RAW_FILL_DATA_SIZE: usize = std::mem::size_of::<RawFillData>();
#[repr(C, u8, align(4))] #[repr(C, u8, align(4))]
#[derive(Debug, PartialEq, Clone, Copy)] #[derive(Debug, PartialEq, Clone, Copy, ToJs)]
#[allow(dead_code)] #[allow(dead_code)]
pub enum RawFillData { pub enum RawFillData {
Solid(solid::RawSolidData) = 0x00, Solid(solid::RawSolidData) = 0x00,

View File

@@ -1,5 +1,6 @@
#![allow(unused_mut, unused_variables)] #![allow(unused_mut, unused_variables)]
use indexmap::IndexSet; use indexmap::IndexSet;
use macros::ToJs;
use mem::SerializableResult; use mem::SerializableResult;
use uuid::Uuid; use uuid::Uuid;
@@ -11,7 +12,7 @@ use crate::{mem, with_current_shape, with_current_shape_mut, with_state, STATE};
const RAW_SEGMENT_DATA_SIZE: usize = size_of::<RawSegmentData>(); const RAW_SEGMENT_DATA_SIZE: usize = size_of::<RawSegmentData>();
#[repr(C, u16, align(4))] #[repr(C, u16, align(4))]
#[derive(Debug, PartialEq, Clone, Copy)] #[derive(Debug, PartialEq, Clone, Copy, ToJs)]
#[allow(dead_code)] #[allow(dead_code)]
enum RawSegmentData { enum RawSegmentData {
MoveTo(RawMoveCommand) = 0x01, MoveTo(RawMoveCommand) = 0x01,

View File

@@ -9,11 +9,15 @@ pushd $_SCRIPT_DIR;
export CARGO_BUILD_TARGET=${CARGO_BUILD_TARGET:-"wasm32-unknown-emscripten"}; export CARGO_BUILD_TARGET=${CARGO_BUILD_TARGET:-"wasm32-unknown-emscripten"};
export SKIA_BINARIES_URL=${SKIA_BINARIES_URL:-"https://github.com/penpot/skia-binaries/releases/download/0.87.0/skia-binaries-e551f334ad5cbdf43abf-wasm32-unknown-emscripten-gl-svg-textlayout-binary-cache-webp.tar.gz"} export SKIA_BINARIES_URL=${SKIA_BINARIES_URL:-"https://github.com/penpot/skia-binaries/releases/download/0.87.0/skia-binaries-e551f334ad5cbdf43abf-wasm32-unknown-emscripten-gl-svg-textlayout-binary-cache-webp.tar.gz"}
_SHARED_FILE=$(find target/wasm32-unknown-emscripten -name render_wasm_shared.js | head -n 1);
cat target/wasm32-unknown-emscripten/$_BUILD_MODE/render_wasm.js "$_SHARED_FILE" > ../frontend/resources/public/js/$_BUILD_NAME.js
cp target/wasm32-unknown-emscripten/$_BUILD_MODE/render_wasm.wasm ../frontend/resources/public/js/$_BUILD_NAME.wasm
pushd $_SCRIPT_DIR; pushd $_SCRIPT_DIR;
cargo watch \ cargo watch \
-x "build $_CARGO_PARAMS" \ -x "build $_CARGO_PARAMS" \
-s "cp target/wasm32-unknown-emscripten/$_BUILD_MODE/render_wasm.js ../frontend/resources/public/js/" \ -s "cat target/wasm32-unknown-emscripten/$_BUILD_MODE/render_wasm.js \"$_SHARED_FILE\" > ../frontend/resources/public/js/$_BUILD_NAME.js" \
-s "cp target/wasm32-unknown-emscripten/$_BUILD_MODE/render_wasm.wasm ../frontend/resources/public/js/" \ -s "cp target/wasm32-unknown-emscripten/$_BUILD_MODE/render_wasm.wasm ../frontend/resources/public/js/" \
-s "sed -i 's/render_wasm.wasm/render_wasm.wasm?version=develop/g' ../frontend/resources/public/js/render_wasm.js" \ -s "sed -i 's/render_wasm.wasm/render_wasm.wasm?version=develop/g' ../frontend/resources/public/js/render_wasm.js" \
-s "echo 'DONE\n'"; -s "echo 'DONE\n'";