mirror of
https://github.com/penpot/penpot.git
synced 2025-12-11 22:14:05 +01:00
♻️ Decouple shapes serialization from model (rust) (#7328)
* ♻️ Move shape type serialization to wasm module * ♻️ Refactor serialization of constraints and vertical alignment into wasm module * ♻️ Refactor serialization and model of shape blur * ♻️ Refactor bool serialization to the wasm module * ♻️ Split wasm::layout into submodules * ♻️ Refactor serialization of AlignItems, AlignContent, JustifyItems and JustifyContent * ♻️ Refactor serialization of WrapType and FlexDirection * ♻️ Refactor serialization of JustifySelf * ♻️ Refactor serialization of GridCell * ♻️ Refactor serialization of AlignSelf * 🐛 Fix AlignSelf not being serialized * ♻️ Refactor handling of None variants in Raw* enums * ♻️ Refactor serialization of grid direction * ♻️ Refactor serialization of GridTrack and GridTrackType * ♻️ Refactor serialization of Sizing * ♻️ Refactor serialization of ShadowStyle * ♻️ Refactor serialization of StrokeCap and StrokeStyle * ♻️ Refactor serialization of BlendMode * ♻️ Refactor serialization of FontStyle * ♻️ Refactor serialization of GrowType
This commit is contained in:
@@ -47,9 +47,9 @@
|
||||
(def ^:const MODIFIER-U32-SIZE (/ MODIFIER-U8-SIZE 4))
|
||||
(def ^:const MODIFIER-TRANSFORM-U8-OFFSET-SIZE 16)
|
||||
|
||||
(def ^:const GRID-LAYOUT-ROW-U8-SIZE 5)
|
||||
(def ^:const GRID-LAYOUT-COLUMN-U8-SIZE 5)
|
||||
(def ^:const GRID-LAYOUT-CELL-U8-SIZE 37)
|
||||
(def ^:const GRID-LAYOUT-ROW-U8-SIZE 8)
|
||||
(def ^:const GRID-LAYOUT-COLUMN-U8-SIZE 8)
|
||||
(def ^:const GRID-LAYOUT-CELL-U8-SIZE 36)
|
||||
|
||||
(def dpr
|
||||
(if use-dpr? (if (exists? js/window) js/window.devicePixelRatio 1.0) 1.0))
|
||||
@@ -364,18 +364,14 @@
|
||||
[bool-type]
|
||||
(h/call wasm/internal-module "_set_shape_bool_type" (sr/translate-bool-type bool-type)))
|
||||
|
||||
(defn- translate-blur-type
|
||||
[blur-type]
|
||||
(case blur-type
|
||||
:layer-blur 1
|
||||
0))
|
||||
|
||||
(defn set-shape-blur
|
||||
[blur]
|
||||
(let [type (-> blur :type sr/translate-blur-type)
|
||||
hidden (:hidden blur)
|
||||
value (:value blur)]
|
||||
(h/call wasm/internal-module "_set_shape_blur" type hidden value)))
|
||||
(if (some? blur)
|
||||
(let [type (-> blur :type sr/translate-blur-type)
|
||||
hidden (:hidden blur)
|
||||
value (:value blur)]
|
||||
(h/call wasm/internal-module "_set_shape_blur" type hidden value))
|
||||
(h/call wasm/internal-module "_clear_shape_blur")))
|
||||
|
||||
(defn set-shape-corners
|
||||
[corners]
|
||||
@@ -457,13 +453,9 @@
|
||||
dview (mem/get-data-view)]
|
||||
|
||||
(reduce (fn [offset {:keys [type value]}]
|
||||
;; NOTE: because of the nature of the grid row data
|
||||
;; structure memory layout we can't use fully 32 bits
|
||||
;; alligned writes, so for heteregeneus writes we use
|
||||
;; the buffer abstraction (DataView) for perform
|
||||
;; surgical writes.
|
||||
(-> offset
|
||||
(mem/write-u8 dview (sr/translate-grid-track-type type))
|
||||
(+ 3) ;; padding
|
||||
(mem/write-f32 dview value)
|
||||
(mem/assert-written offset GRID-LAYOUT-ROW-U8-SIZE)))
|
||||
|
||||
@@ -479,17 +471,11 @@
|
||||
dview (mem/get-data-view)]
|
||||
|
||||
(reduce (fn [offset {:keys [type value]}]
|
||||
;; NOTE: because of the nature of the grid column data
|
||||
;; structure memory layout we can't use fully 32 bits
|
||||
;; alligned writes, so for heteregeneus writes we use
|
||||
;; the buffer abstraction (DataView) for perform
|
||||
;; surgical writes.
|
||||
(-> offset
|
||||
(mem/write-u8 dview (sr/translate-grid-track-type type))
|
||||
(+ 3) ;; padding
|
||||
(mem/write-f32 dview value)
|
||||
(mem/assert-written offset GRID-LAYOUT-COLUMN-U8-SIZE)))
|
||||
|
||||
|
||||
offset
|
||||
entries)
|
||||
|
||||
@@ -504,38 +490,17 @@
|
||||
(reduce-kv (fn [offset _ cell]
|
||||
(let [shape-id (-> (get cell :shapes) first)]
|
||||
(-> offset
|
||||
;; row: [u8; 4],
|
||||
(mem/write-i32 dview (get cell :row))
|
||||
|
||||
;; row_span: [u8; 4],
|
||||
(mem/write-i32 dview (get cell :row-span))
|
||||
|
||||
;; column: [u8; 4],
|
||||
(mem/write-i32 dview (get cell :column))
|
||||
|
||||
;; column_span: [u8; 4],
|
||||
(mem/write-i32 dview (get cell :column-span))
|
||||
|
||||
;; has_align_self: u8,
|
||||
(mem/write-bool dview (some? (get cell :align-self)))
|
||||
|
||||
;; align_self: u8,
|
||||
(mem/write-u8 dview (get cell :align-self))
|
||||
|
||||
;; has_justify_self: u8,
|
||||
(mem/write-bool dview (get cell :justify-self))
|
||||
|
||||
;; justify_self: u8,
|
||||
(mem/write-u8 dview (sr/translate-align-self (get cell :align-self)))
|
||||
(mem/write-u8 dview (sr/translate-justify-self (get cell :justify-self)))
|
||||
|
||||
;; has_shape_id: u8,
|
||||
;; (.set heap (sr/bool->u8 (d/not-empty? (:shapes cell))) (+ current-offset 20))
|
||||
(mem/write-u8 dview (some? shape-id))
|
||||
;; padding
|
||||
(+ 2)
|
||||
|
||||
;; shape_id_a: [u8; 4],
|
||||
;; shape_id_b: [u8; 4],
|
||||
;; shape_id_c: [u8; 4],
|
||||
;; shape_id_d: [u8; 4],
|
||||
(mem/write-uuid dview (d/nilv shape-id uuid/zero))
|
||||
(mem/assert-written offset GRID-LAYOUT-CELL-U8-SIZE))))
|
||||
|
||||
@@ -589,7 +554,7 @@
|
||||
(d/nilv max-w 0)
|
||||
has-min-w
|
||||
(d/nilv min-w 0)
|
||||
(some? align-self)
|
||||
|
||||
(d/nilv align-self 0)
|
||||
is-absolute
|
||||
(d/nilv z-index))))
|
||||
@@ -756,10 +721,9 @@
|
||||
(set-shape-hidden hidden)
|
||||
(set-shape-children children)
|
||||
(set-shape-corners corners)
|
||||
(set-shape-blur blur)
|
||||
(when (and (= type :group) masked)
|
||||
(set-masked masked))
|
||||
(when (some? blur)
|
||||
(set-shape-blur blur))
|
||||
(when (= type :bool)
|
||||
(set-shape-bool-type bool-type))
|
||||
(when (and (some? content)
|
||||
@@ -1073,28 +1037,29 @@
|
||||
(->> (js/dynamicImport (str uri))
|
||||
(p/mcat (fn [module]
|
||||
(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")
|
||||
serializers #js{:blur-type (unchecked-get module "RawBlurType")
|
||||
:blend-mode (unchecked-get module "RawBlendMode")
|
||||
:bool-type (unchecked-get module "RawBoolType")
|
||||
:font-style (unchecked-get module "RawFontStyle")
|
||||
:flex-direction (unchecked-get module "RawFlexDirection")
|
||||
:grid-direction (unchecked-get module "RawGridDirection")
|
||||
:grow-type (unchecked-get module "RawGrowType")
|
||||
:align-items (unchecked-get module "RawAlignItems")
|
||||
:align-self (unchecked-get module "RawAlignSelf")
|
||||
:align-content (unchecked-get module "RawAlignContent")
|
||||
:justify-items (unchecked-get module "RawJustifyItems")
|
||||
:justify-content (unchecked-get module "RawJustifyContent")
|
||||
:justify-self (unchecked-get module "RawJustifySelf")
|
||||
:wrap-type (unchecked-get module "RawWrapType")
|
||||
:grid-track-type (unchecked-get module "RawGridTrackType")
|
||||
:shadow-style (unchecked-get module "RawShadowStyle")
|
||||
:stroke-style (unchecked-get module "RawStrokeStyle")
|
||||
:stroke-cap (unchecked-get module "RawStrokeCap")
|
||||
:shape-type (unchecked-get module "RawShapeType")
|
||||
:constraint-h (unchecked-get module "RawConstraintH")
|
||||
:constraint-v (unchecked-get module "RawConstraintV")
|
||||
:sizing (unchecked-get module "RawSizing")
|
||||
:vertical-align (unchecked-get module "RawVerticalAlign")
|
||||
:fill-data (unchecked-get module "RawFillData")
|
||||
:segment-data (unchecked-get module "RawSegmentData")}]
|
||||
(set! wasm/serializers serializers)
|
||||
|
||||
@@ -85,24 +85,9 @@
|
||||
|
||||
(defn translate-blend-mode
|
||||
[blend-mode]
|
||||
(case blend-mode
|
||||
:normal 3
|
||||
:darken 16
|
||||
:multiply 24
|
||||
:color-burn 19
|
||||
:lighten 17
|
||||
:screen 14
|
||||
:color-dodge 18
|
||||
:overlay 15
|
||||
:soft-light 21
|
||||
:hard-light 20
|
||||
:difference 22
|
||||
:exclusion 23
|
||||
:hue 25
|
||||
:saturation 26
|
||||
:color 27
|
||||
:luminosity 28
|
||||
3))
|
||||
(let [values (unchecked-get wasm/serializers "blend-mode")
|
||||
default (unchecked-get values "normal")]
|
||||
(d/nilv (unchecked-get values (d/name blend-mode)) default)))
|
||||
|
||||
(defn translate-constraint-h
|
||||
[type]
|
||||
@@ -126,7 +111,7 @@
|
||||
(defn translate-blur-type
|
||||
[blur-type]
|
||||
(let [values (unchecked-get wasm/serializers "blur-type")
|
||||
default (unchecked-get values "none")]
|
||||
default (unchecked-get values "layer-blur")]
|
||||
(d/nilv (unchecked-get values (d/name blur-type)) default)))
|
||||
|
||||
(defn translate-layout-flex-dir
|
||||
@@ -184,13 +169,15 @@
|
||||
|
||||
(defn translate-align-self
|
||||
[align-self]
|
||||
(let [values (unchecked-get wasm/serializers "align-self")]
|
||||
(unchecked-get values (d/name align-self))))
|
||||
(let [values (unchecked-get wasm/serializers "align-self")
|
||||
default (unchecked-get values "none")]
|
||||
(d/nilv (unchecked-get values (d/name align-self)) default)))
|
||||
|
||||
(defn translate-justify-self
|
||||
[justify-self]
|
||||
(let [values (unchecked-get wasm/serializers "justify-self")]
|
||||
(unchecked-get values (d/name justify-self))))
|
||||
(let [values (unchecked-get wasm/serializers "justify-self")
|
||||
default (unchecked-get values "none")]
|
||||
(d/nilv (unchecked-get values (d/name justify-self)) default)))
|
||||
|
||||
(defn translate-shadow-style
|
||||
[style]
|
||||
|
||||
@@ -221,16 +221,6 @@ Shadow styles are serialized as `u8`:
|
||||
| 3 | Stretch |
|
||||
| \_ | error |
|
||||
|
||||
### Align self
|
||||
|
||||
| Value | Field |
|
||||
| ----- | ------- |
|
||||
| 0 | Start |
|
||||
| 1 | End |
|
||||
| 2 | Center |
|
||||
| 3 | Stretch |
|
||||
| \_ | error |
|
||||
|
||||
### Align Content
|
||||
|
||||
| Value | Field |
|
||||
@@ -269,25 +259,27 @@ Shadow styles are serialized as `u8`:
|
||||
|
||||
### Align Self
|
||||
|
||||
| Value | Field |
|
||||
| ----- | ------- |
|
||||
| 0 | Auto |
|
||||
| 1 | Start |
|
||||
| 2 | End |
|
||||
| 3 | Center |
|
||||
| 4 | Stretch |
|
||||
| \_ | error |
|
||||
| Value | Field |
|
||||
| ----- | ------------- |
|
||||
| 0 | (none) |
|
||||
| 1 | Auto |
|
||||
| 2 | Start |
|
||||
| 3 | End |
|
||||
| 4 | Center |
|
||||
| 5 | Stretch |
|
||||
| \_ | (unsupported) |
|
||||
|
||||
### Justify Self
|
||||
|
||||
| Value | Field |
|
||||
| ----- | ------- |
|
||||
| 0 | Auto |
|
||||
| 1 | Start |
|
||||
| 2 | End |
|
||||
| 3 | Center |
|
||||
| 4 | Stretch |
|
||||
| \_ | error |
|
||||
| Value | Field |
|
||||
| ----- | ------------- |
|
||||
| 0 | (none) |
|
||||
| 1 | Auto |
|
||||
| 2 | Start |
|
||||
| 3 | End |
|
||||
| 4 | Center |
|
||||
| 5 | Stretch |
|
||||
| \_ | (unsupported) |
|
||||
|
||||
### Wrap type
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ mod wasm;
|
||||
use indexmap::IndexSet;
|
||||
use math::{Bounds, Matrix};
|
||||
use mem::SerializableResult;
|
||||
use shapes::{BoolType, StructureEntry, StructureEntryType, TransformEntry, Type};
|
||||
use shapes::{StructureEntry, StructureEntryType, TransformEntry};
|
||||
use skia_safe as skia;
|
||||
use state::State;
|
||||
use utils::uuid_from_u32_quartet;
|
||||
@@ -238,20 +238,6 @@ pub extern "C" fn set_shape_masked_group(masked: bool) {
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn set_shape_bool_type(raw_bool_type: u8) {
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
shape.set_bool_type(BoolType::from(raw_bool_type));
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn set_shape_type(shape_type: u8) {
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
shape.set_shape_type(Type::from(shape_type));
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn set_shape_selrect(left: f32, top: f32, right: f32, bottom: f32) {
|
||||
with_state_mut!(state, {
|
||||
@@ -365,13 +351,6 @@ pub extern "C" fn set_shape_svg_raw_content() {
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn set_shape_blend_mode(mode: i32) {
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
shape.set_blend_mode(render::BlendMode::from(mode));
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn set_shape_opacity(opacity: f32) {
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
@@ -386,13 +365,6 @@ pub extern "C" fn set_shape_hidden(hidden: bool) {
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn set_shape_blur(blur_type: u8, hidden: bool, value: f32) {
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
shape.set_blur(blur_type, hidden, value);
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn set_shape_corners(r1: f32, r2: f32, r3: f32, r4: f32) {
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
@@ -528,31 +500,6 @@ pub extern "C" fn set_modifiers() {
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn add_shape_shadow(
|
||||
raw_color: u32,
|
||||
blur: f32,
|
||||
spread: f32,
|
||||
x: f32,
|
||||
y: f32,
|
||||
raw_style: u8,
|
||||
hidden: bool,
|
||||
) {
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
let color = skia::Color::new(raw_color);
|
||||
let style = shapes::ShadowStyle::from(raw_style);
|
||||
let shadow = shapes::Shadow::new(color, blur, spread, (x, y), style, hidden);
|
||||
shape.add_shadow(shadow);
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn clear_shape_shadows() {
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
shape.clear_shadows();
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn update_shape_tiles() {
|
||||
with_state_mut!(state, {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
mod blend;
|
||||
mod debug;
|
||||
mod fills;
|
||||
pub mod filters;
|
||||
@@ -37,7 +36,6 @@ use crate::wapi;
|
||||
use crate::math;
|
||||
use crate::math::bools;
|
||||
|
||||
pub use blend::BlendMode;
|
||||
pub use fonts::*;
|
||||
pub use images::*;
|
||||
|
||||
@@ -253,7 +251,7 @@ pub(crate) struct RenderState {
|
||||
// can affect its child elements if they don't specify one themselves. If the planned
|
||||
// migration to remove group-level fills is completed, this code should be removed.
|
||||
pub nested_fills: Vec<Vec<Fill>>,
|
||||
pub nested_blurs: Vec<Option<Blur>>,
|
||||
pub nested_blurs: Vec<Option<Blur>>, // FIXME: why is this an option?
|
||||
pub show_grid: Option<Uuid>,
|
||||
pub focus_mode: FocusMode,
|
||||
}
|
||||
@@ -568,14 +566,15 @@ impl RenderState {
|
||||
}
|
||||
}
|
||||
|
||||
if !shape.blur.hidden && shape.blur.blur_type == BlurType::LayerBlur {
|
||||
nested_blur_value += shape.blur.value.powf(2.);
|
||||
if let Some(blur) = shape.blur {
|
||||
if !blur.hidden {
|
||||
nested_blur_value += blur.value.powf(2.);
|
||||
}
|
||||
}
|
||||
|
||||
if nested_blur_value > 0. {
|
||||
shape
|
||||
.to_mut()
|
||||
.set_blur(BlurType::LayerBlur as u8, false, nested_blur_value.sqrt());
|
||||
let blur = Blur::new(BlurType::LayerBlur, false, nested_blur_value.sqrt());
|
||||
shape.to_mut().set_blur(Some(blur));
|
||||
}
|
||||
|
||||
let center = shape.center();
|
||||
@@ -1170,7 +1169,7 @@ impl RenderState {
|
||||
plain_shape.to_mut().add_stroke(Stroke {
|
||||
fill: Fill::Solid(SolidColor(skia::Color::BLACK)),
|
||||
width: stroke.width,
|
||||
style: stroke.style.clone(),
|
||||
style: stroke.style,
|
||||
cap_end: stroke.cap_end,
|
||||
cap_start: stroke.cap_start,
|
||||
kind: stroke.kind,
|
||||
@@ -1449,7 +1448,9 @@ impl RenderState {
|
||||
|
||||
match element.shape_type {
|
||||
Type::Frame(_) | Type::Group(_) => {
|
||||
self.nested_blurs.push(Some(element.blur));
|
||||
if let Some(blur) = element.blur {
|
||||
self.nested_blurs.push(Some(blur));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
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)]
|
||||
pub struct BlendMode(skia::BlendMode);
|
||||
|
||||
impl Default for BlendMode {
|
||||
fn default() -> Self {
|
||||
BlendMode(skia::BlendMode::SrcOver)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i32> for BlendMode {
|
||||
fn from(value: i32) -> Self {
|
||||
if value <= skia::BlendMode::Luminosity as i32 {
|
||||
unsafe { Self(std::mem::transmute::<i32, skia_safe::BlendMode>(value)) }
|
||||
} else {
|
||||
Self::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BlendMode> for skia::BlendMode {
|
||||
fn from(val: BlendMode) -> Self {
|
||||
match val {
|
||||
BlendMode(skia_blend) => skia_blend,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -182,7 +182,6 @@ fn handle_stroke_cap(
|
||||
) {
|
||||
paint.set_style(skia::PaintStyle::Fill);
|
||||
match cap {
|
||||
StrokeCap::None => {}
|
||||
StrokeCap::LineArrow => {
|
||||
// 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.);
|
||||
@@ -241,23 +240,27 @@ fn handle_stroke_caps(
|
||||
paint_stroke.set_image_filter(filter.clone());
|
||||
}
|
||||
|
||||
handle_stroke_cap(
|
||||
canvas,
|
||||
stroke.cap_start,
|
||||
stroke.width,
|
||||
&mut paint_stroke,
|
||||
first_point,
|
||||
&points[1],
|
||||
);
|
||||
if let Some(cap) = stroke.cap_start {
|
||||
handle_stroke_cap(
|
||||
canvas,
|
||||
cap,
|
||||
stroke.width,
|
||||
&mut paint_stroke,
|
||||
first_point,
|
||||
&points[1],
|
||||
);
|
||||
}
|
||||
|
||||
handle_stroke_cap(
|
||||
canvas,
|
||||
stroke.cap_end,
|
||||
stroke.width,
|
||||
&mut paint_stroke,
|
||||
last_point,
|
||||
&points[c_points - 2],
|
||||
);
|
||||
if let Some(cap) = stroke.cap_end {
|
||||
handle_stroke_cap(
|
||||
canvas,
|
||||
cap,
|
||||
stroke.width,
|
||||
&mut paint_stroke,
|
||||
last_point,
|
||||
&points[c_points - 2],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
use macros::ToJs;
|
||||
use skia_safe::{self as skia};
|
||||
|
||||
use crate::render::BlendMode;
|
||||
use crate::uuid::Uuid;
|
||||
use std::borrow::Cow;
|
||||
use std::cell::OnceCell;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::iter::once;
|
||||
|
||||
mod blend;
|
||||
mod blurs;
|
||||
mod bools;
|
||||
mod corners;
|
||||
@@ -27,6 +26,7 @@ mod text;
|
||||
pub mod text_paths;
|
||||
mod transform;
|
||||
|
||||
pub use blend::*;
|
||||
pub use blurs::*;
|
||||
pub use bools::*;
|
||||
pub use corners::*;
|
||||
@@ -55,36 +55,19 @@ const MIN_VISIBLE_SIZE: f32 = 2.0;
|
||||
const ANTIALIAS_THRESHOLD: f32 = 15.0;
|
||||
const MIN_STROKE_WIDTH: f32 = 0.001;
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
#[derive(Debug, Clone, PartialEq, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Type {
|
||||
Frame(Frame) = 0,
|
||||
Group(Group) = 1,
|
||||
Bool(Bool) = 2,
|
||||
Rect(Rect) = 3,
|
||||
Path(Path) = 4,
|
||||
Text(TextContent) = 5,
|
||||
Circle = 6,
|
||||
SVGRaw(SVGRaw) = 7,
|
||||
Frame(Frame),
|
||||
Group(Group),
|
||||
Bool(Bool),
|
||||
Rect(Rect),
|
||||
Path(Path),
|
||||
Text(TextContent),
|
||||
Circle, // FIXME: shouldn't this have a rect inside, like the Rect variant?
|
||||
SVGRaw(SVGRaw),
|
||||
}
|
||||
|
||||
impl Type {
|
||||
// TODO: move this to the wasm module, use transmute
|
||||
pub fn from(value: u8) -> Self {
|
||||
match value {
|
||||
0 => Type::Frame(Frame::default()),
|
||||
1 => Type::Group(Group::default()),
|
||||
2 => Type::Bool(Bool::default()),
|
||||
3 => Type::Rect(Rect::default()),
|
||||
4 => Type::Path(Path::default()),
|
||||
5 => Type::Text(TextContent::default()),
|
||||
6 => Type::Circle,
|
||||
7 => Type::SVGRaw(SVGRaw::default()),
|
||||
_ => Type::Rect(Rect::default()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn corners(&self) -> Option<Corners> {
|
||||
match self {
|
||||
Type::Rect(Rect { corners, .. }) => *corners,
|
||||
@@ -145,77 +128,29 @@ impl Type {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Copy, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||
pub enum ConstraintH {
|
||||
Left = 0,
|
||||
Right = 1,
|
||||
Leftright = 2,
|
||||
Center = 3,
|
||||
Scale = 4,
|
||||
Left,
|
||||
Right,
|
||||
LeftRight,
|
||||
Center,
|
||||
Scale,
|
||||
}
|
||||
|
||||
impl ConstraintH {
|
||||
// TODO: we should implement a proper From trait for this
|
||||
// TODO: use transmute
|
||||
pub fn from(value: u8) -> Option<Self> {
|
||||
match value {
|
||||
0 => Some(Self::Left),
|
||||
1 => Some(Self::Right),
|
||||
2 => Some(Self::Leftright),
|
||||
3 => Some(Self::Center),
|
||||
4 => Some(Self::Scale),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
#[derive(Debug, Clone, PartialEq, Copy, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||
pub enum VerticalAlign {
|
||||
Top = 0,
|
||||
Center = 1,
|
||||
Bottom = 2,
|
||||
Top,
|
||||
Center,
|
||||
Bottom,
|
||||
}
|
||||
|
||||
impl VerticalAlign {
|
||||
// TODO: implement a proper From trait for this
|
||||
// TODO: use transmute
|
||||
pub fn from(value: u8) -> Self {
|
||||
match value {
|
||||
0 => Self::Top,
|
||||
1 => Self::Center,
|
||||
2 => Self::Bottom,
|
||||
_ => Self::Top,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
#[derive(Debug, Clone, PartialEq, Copy, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||
pub enum ConstraintV {
|
||||
Top = 0,
|
||||
Bottom = 1,
|
||||
Topbottom = 2,
|
||||
Center = 3,
|
||||
Scale = 4,
|
||||
}
|
||||
|
||||
impl ConstraintV {
|
||||
// TODO: implement a proper From trait for this
|
||||
// TODO: use transmute
|
||||
pub fn from(value: u8) -> Option<Self> {
|
||||
match value {
|
||||
0 => Some(Self::Top),
|
||||
1 => Some(Self::Bottom),
|
||||
2 => Some(Self::Topbottom),
|
||||
3 => Some(Self::Center),
|
||||
4 => Some(Self::Scale),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
Top,
|
||||
Bottom,
|
||||
TopBottom,
|
||||
Center,
|
||||
Scale,
|
||||
}
|
||||
|
||||
pub type Color = skia::Color;
|
||||
@@ -236,7 +171,7 @@ pub struct Shape {
|
||||
pub strokes: Vec<Stroke>,
|
||||
pub blend_mode: BlendMode,
|
||||
pub vertical_align: VerticalAlign,
|
||||
pub blur: Blur,
|
||||
pub blur: Option<Blur>,
|
||||
pub opacity: f32,
|
||||
pub hidden: bool,
|
||||
pub svg: Option<skia::svg::Dom>,
|
||||
@@ -265,7 +200,7 @@ impl Shape {
|
||||
vertical_align: VerticalAlign::Top,
|
||||
opacity: 1.,
|
||||
hidden: false,
|
||||
blur: Blur::default(),
|
||||
blur: None,
|
||||
svg: None,
|
||||
svg_attrs: HashMap::new(),
|
||||
shadows: Vec::with_capacity(1),
|
||||
@@ -285,7 +220,11 @@ impl Shape {
|
||||
.shadows
|
||||
.iter_mut()
|
||||
.for_each(|s| s.scale_content(value));
|
||||
result.blur.scale_content(value);
|
||||
|
||||
if let Some(blur) = result.blur.as_mut() {
|
||||
blur.scale_content(value);
|
||||
}
|
||||
|
||||
result
|
||||
.layout_item
|
||||
.iter_mut()
|
||||
@@ -518,39 +457,39 @@ impl Shape {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_grid_columns(&mut self, tracks: Vec<RawGridTrack>) {
|
||||
pub fn set_grid_columns(&mut self, tracks: Vec<GridTrack>) {
|
||||
let Type::Frame(frame_data) = &mut self.shape_type else {
|
||||
return;
|
||||
};
|
||||
let Some(Layout::GridLayout(_, grid_data)) = &mut frame_data.layout else {
|
||||
return;
|
||||
};
|
||||
grid_data.columns = tracks.iter().map(GridTrack::from_raw).collect();
|
||||
grid_data.columns = tracks;
|
||||
}
|
||||
|
||||
pub fn set_grid_rows(&mut self, tracks: Vec<RawGridTrack>) {
|
||||
pub fn set_grid_rows(&mut self, tracks: Vec<GridTrack>) {
|
||||
let Type::Frame(frame_data) = &mut self.shape_type else {
|
||||
return;
|
||||
};
|
||||
let Some(Layout::GridLayout(_, grid_data)) = &mut frame_data.layout else {
|
||||
return;
|
||||
};
|
||||
grid_data.rows = tracks.iter().map(GridTrack::from_raw).collect();
|
||||
grid_data.rows = tracks;
|
||||
}
|
||||
|
||||
pub fn set_grid_cells(&mut self, cells: Vec<RawGridCell>) {
|
||||
pub fn set_grid_cells(&mut self, cells: Vec<GridCell>) {
|
||||
let Type::Frame(frame_data) = &mut self.shape_type else {
|
||||
return;
|
||||
};
|
||||
let Some(Layout::GridLayout(_, grid_data)) = &mut frame_data.layout else {
|
||||
return;
|
||||
};
|
||||
grid_data.cells = cells.iter().map(GridCell::from_raw).collect();
|
||||
grid_data.cells = cells;
|
||||
}
|
||||
|
||||
pub fn set_blur(&mut self, blur_type: u8, hidden: bool, value: f32) {
|
||||
pub fn set_blur(&mut self, blur: Option<Blur>) {
|
||||
self.invalidate_extrect();
|
||||
self.blur = Blur::new(blur_type, hidden, value);
|
||||
self.blur = blur;
|
||||
}
|
||||
|
||||
pub fn add_child(&mut self, id: Uuid) {
|
||||
@@ -672,7 +611,7 @@ impl Shape {
|
||||
self.svg_attrs.insert(name, value);
|
||||
}
|
||||
|
||||
pub fn blend_mode(&self) -> crate::render::BlendMode {
|
||||
pub fn blend_mode(&self) -> BlendMode {
|
||||
self.blend_mode
|
||||
}
|
||||
|
||||
@@ -854,11 +793,13 @@ impl Shape {
|
||||
}
|
||||
}
|
||||
|
||||
if self.blur.blur_type != blurs::BlurType::None && !self.blur.hidden {
|
||||
rect.left -= self.blur.value;
|
||||
rect.top -= self.blur.value;
|
||||
rect.right += self.blur.value;
|
||||
rect.bottom += self.blur.value;
|
||||
if let Some(blur) = self.blur {
|
||||
if !blur.hidden {
|
||||
rect.left -= blur.value;
|
||||
rect.top -= blur.value;
|
||||
rect.right += blur.value;
|
||||
rect.bottom += blur.value;
|
||||
}
|
||||
}
|
||||
|
||||
// For groups and frames without clipping, extend the bounding rectangle to include all nested shapes
|
||||
@@ -985,35 +926,27 @@ impl Shape {
|
||||
}
|
||||
|
||||
pub fn image_filter(&self, scale: f32) -> Option<skia::ImageFilter> {
|
||||
if !self.blur.hidden {
|
||||
match self.blur.blur_type {
|
||||
BlurType::None => None,
|
||||
self.blur
|
||||
.filter(|blur| !blur.hidden)
|
||||
.and_then(|blur| match blur.blur_type {
|
||||
BlurType::LayerBlur => skia::image_filters::blur(
|
||||
(self.blur.value * scale, self.blur.value * scale),
|
||||
(blur.value * scale, blur.value * scale),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn mask_filter(&self, scale: f32) -> Option<skia::MaskFilter> {
|
||||
if !self.blur.hidden {
|
||||
match self.blur.blur_type {
|
||||
BlurType::None => None,
|
||||
BlurType::LayerBlur => skia::MaskFilter::blur(
|
||||
skia::BlurStyle::Normal,
|
||||
self.blur.value * scale,
|
||||
Some(true),
|
||||
),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
self.blur
|
||||
.filter(|blur| !blur.hidden)
|
||||
.and_then(|blur| match blur.blur_type {
|
||||
BlurType::LayerBlur => {
|
||||
skia::MaskFilter::blur(skia::BlurStyle::Normal, blur.value * scale, Some(true))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn is_recursive(&self) -> bool {
|
||||
|
||||
18
render-wasm/src/shapes/blend.rs
Normal file
18
render-wasm/src/shapes/blend.rs
Normal file
@@ -0,0 +1,18 @@
|
||||
use skia_safe as skia;
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
pub struct BlendMode(pub skia::BlendMode);
|
||||
|
||||
impl Default for BlendMode {
|
||||
fn default() -> Self {
|
||||
BlendMode(skia::BlendMode::SrcOver)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BlendMode> for skia::BlendMode {
|
||||
fn from(val: BlendMode) -> Self {
|
||||
match val {
|
||||
BlendMode(skia_blend) => skia_blend,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,6 @@
|
||||
use macros::ToJs;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum BlurType {
|
||||
None = 0,
|
||||
LayerBlur = 1,
|
||||
LayerBlur,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
@@ -14,28 +10,10 @@ pub struct Blur {
|
||||
pub value: f32,
|
||||
}
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
impl From<u8> for BlurType {
|
||||
// TODO: use transmute
|
||||
fn from(value: u8) -> Self {
|
||||
match value {
|
||||
1 => BlurType::LayerBlur,
|
||||
_ => BlurType::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Blur {
|
||||
pub fn default() -> Self {
|
||||
pub fn new(blur_type: BlurType, hidden: bool, value: f32) -> Self {
|
||||
Blur {
|
||||
blur_type: BlurType::None,
|
||||
hidden: true,
|
||||
value: 0.,
|
||||
}
|
||||
}
|
||||
pub fn new(blur_type: u8, hidden: bool, value: f32) -> Self {
|
||||
Blur {
|
||||
blur_type: BlurType::from(blur_type),
|
||||
blur_type,
|
||||
hidden,
|
||||
value,
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
use macros::ToJs;
|
||||
|
||||
use super::Path;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
@@ -8,14 +6,12 @@ pub struct Bool {
|
||||
pub path: Path,
|
||||
}
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
#[derive(Debug, Clone, Copy, PartialEq, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum BoolType {
|
||||
Union = 0,
|
||||
Difference = 1,
|
||||
Intersection = 2,
|
||||
Exclusion = 3,
|
||||
Union,
|
||||
Difference,
|
||||
Intersection,
|
||||
Exclusion,
|
||||
}
|
||||
|
||||
impl Default for Bool {
|
||||
@@ -27,20 +23,6 @@ impl Default for Bool {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
impl From<u8> for BoolType {
|
||||
// TODO: use transmute
|
||||
fn from(value: u8) -> Self {
|
||||
match value {
|
||||
0 => Self::Union,
|
||||
1 => Self::Difference,
|
||||
2 => Self::Intersection,
|
||||
3 => Self::Exclusion,
|
||||
_ => Self::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for BoolType {
|
||||
fn default() -> Self {
|
||||
Self::Union
|
||||
|
||||
@@ -1,26 +1,11 @@
|
||||
use std::fmt;
|
||||
|
||||
use crate::uuid::Uuid;
|
||||
use macros::ToJs;
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
#[derive(Debug, PartialEq, Clone, Copy, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
pub enum FontStyle {
|
||||
Normal = 0,
|
||||
Italic = 1,
|
||||
}
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
impl From<u8> for FontStyle {
|
||||
// TODO: use transmute
|
||||
fn from(value: u8) -> Self {
|
||||
match value {
|
||||
0 => Self::Normal,
|
||||
1 => Self::Italic,
|
||||
_ => Self::Normal,
|
||||
}
|
||||
}
|
||||
Normal,
|
||||
Italic,
|
||||
}
|
||||
|
||||
impl fmt::Display for FontStyle {
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
use macros::ToJs;
|
||||
|
||||
use crate::utils::uuid_from_u32_quartet;
|
||||
use crate::uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
@@ -24,208 +21,70 @@ impl Layout {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
#[derive(Debug, Clone, PartialEq, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||
pub enum FlexDirection {
|
||||
Row = 0,
|
||||
RowReverse = 1,
|
||||
Column = 2,
|
||||
ColumnReverse = 3,
|
||||
Row,
|
||||
RowReverse,
|
||||
Column,
|
||||
ColumnReverse,
|
||||
}
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
impl FlexDirection {
|
||||
// TODO: implement a proper From trait for this
|
||||
// TODO: use transmute
|
||||
pub fn from_u8(value: u8) -> Self {
|
||||
match value {
|
||||
0 => Self::Row,
|
||||
1 => Self::RowReverse,
|
||||
2 => Self::Column,
|
||||
3 => Self::ColumnReverse,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
#[derive(Debug, Clone, PartialEq, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||
pub enum GridDirection {
|
||||
Row = 0,
|
||||
Column = 1,
|
||||
Row,
|
||||
Column,
|
||||
}
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
impl GridDirection {
|
||||
// TODO: implement a proper From trait for this
|
||||
// TODO: use transmute
|
||||
pub fn from_u8(value: u8) -> Self {
|
||||
match value {
|
||||
0 => Self::Row,
|
||||
1 => Self::Column,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
#[derive(Debug, Clone, PartialEq, Copy, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||
pub enum AlignItems {
|
||||
Start = 0,
|
||||
End = 1,
|
||||
Center = 2,
|
||||
Stretch = 3,
|
||||
Start,
|
||||
End,
|
||||
Center,
|
||||
Stretch,
|
||||
}
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
impl AlignItems {
|
||||
// TODO: implement a proper From trait for this
|
||||
// TODO: use transmute
|
||||
pub fn from_u8(value: u8) -> Self {
|
||||
match value {
|
||||
0 => Self::Start,
|
||||
1 => Self::End,
|
||||
2 => Self::Center,
|
||||
3 => Self::Stretch,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
#[derive(Debug, Clone, PartialEq, Copy, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||
pub enum AlignContent {
|
||||
Start = 0,
|
||||
End = 1,
|
||||
Center = 2,
|
||||
SpaceBetween = 3,
|
||||
SpaceAround = 4,
|
||||
SpaceEvenly = 5,
|
||||
Stretch = 6,
|
||||
Start,
|
||||
End,
|
||||
Center,
|
||||
SpaceBetween,
|
||||
SpaceAround,
|
||||
SpaceEvenly,
|
||||
Stretch,
|
||||
}
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
impl AlignContent {
|
||||
// TODO: implement a proper From trait for this
|
||||
// TODO: use transmute
|
||||
pub fn from_u8(value: u8) -> Self {
|
||||
match value {
|
||||
0 => Self::Start,
|
||||
1 => Self::End,
|
||||
2 => Self::Center,
|
||||
3 => Self::SpaceBetween,
|
||||
4 => Self::SpaceAround,
|
||||
5 => Self::SpaceEvenly,
|
||||
6 => Self::Stretch,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
#[derive(Debug, Clone, PartialEq, Copy, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||
pub enum JustifyItems {
|
||||
Start = 0,
|
||||
End = 1,
|
||||
Center = 2,
|
||||
Stretch = 3,
|
||||
Start,
|
||||
End,
|
||||
Center,
|
||||
Stretch,
|
||||
}
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
impl JustifyItems {
|
||||
// TODO: implement a proper From trait for this
|
||||
// TODO: use transmute
|
||||
pub fn from_u8(value: u8) -> Self {
|
||||
match value {
|
||||
0 => Self::Start,
|
||||
1 => Self::End,
|
||||
2 => Self::Center,
|
||||
3 => Self::Stretch,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
#[derive(Debug, Clone, PartialEq, Copy, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||
pub enum JustifyContent {
|
||||
Start = 0,
|
||||
End = 1,
|
||||
Center = 2,
|
||||
SpaceBetween = 3,
|
||||
SpaceAround = 4,
|
||||
SpaceEvenly = 5,
|
||||
Stretch = 6,
|
||||
Start,
|
||||
End,
|
||||
Center,
|
||||
SpaceBetween,
|
||||
SpaceAround,
|
||||
SpaceEvenly,
|
||||
Stretch,
|
||||
}
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
impl JustifyContent {
|
||||
// TODO: implement a proper From trait for this
|
||||
// TODO: use transmute
|
||||
pub fn from_u8(value: u8) -> Self {
|
||||
match value {
|
||||
0 => Self::Start,
|
||||
1 => Self::End,
|
||||
2 => Self::Center,
|
||||
3 => Self::SpaceBetween,
|
||||
4 => Self::SpaceAround,
|
||||
5 => Self::SpaceEvenly,
|
||||
6 => Self::Stretch,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
#[derive(Debug, Clone, PartialEq, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum WrapType {
|
||||
Wrap = 0,
|
||||
Nowrap = 1,
|
||||
Wrap,
|
||||
NoWrap,
|
||||
}
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
impl WrapType {
|
||||
// TODO: implement a proper From trait for this
|
||||
// TODO: use transmute
|
||||
pub fn from_u8(value: u8) -> Self {
|
||||
match value {
|
||||
0 => Self::Wrap,
|
||||
1 => Self::Nowrap,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
#[derive(Debug, Copy, Clone, PartialEq, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
pub enum GridTrackType {
|
||||
Percent = 0,
|
||||
Flex = 1,
|
||||
Auto = 2,
|
||||
Fixed = 3,
|
||||
}
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
impl GridTrackType {
|
||||
// TODO: implement a proper From trait for this
|
||||
// TODO: use transmute
|
||||
pub fn from_u8(value: u8) -> Self {
|
||||
match value {
|
||||
0 => Self::Percent,
|
||||
1 => Self::Flex,
|
||||
2 => Self::Auto,
|
||||
3 => Self::Fixed,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
Percent,
|
||||
Flex,
|
||||
Auto,
|
||||
Fixed,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
@@ -235,13 +94,6 @@ pub struct GridTrack {
|
||||
}
|
||||
|
||||
impl GridTrack {
|
||||
pub fn from_raw(raw: &RawGridTrack) -> Self {
|
||||
Self {
|
||||
track_type: GridTrackType::from_u8(raw.track_type),
|
||||
value: f32::from_le_bytes(raw.value),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scale_content(&mut self, value: f32) {
|
||||
if self.track_type == GridTrackType::Fixed {
|
||||
self.value *= value;
|
||||
@@ -249,7 +101,7 @@ impl GridTrack {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||
pub struct GridCell {
|
||||
pub row: i32,
|
||||
pub row_span: i32,
|
||||
@@ -260,58 +112,11 @@ pub struct GridCell {
|
||||
pub shape: Option<Uuid>,
|
||||
}
|
||||
|
||||
impl GridCell {
|
||||
pub fn from_raw(raw: &RawGridCell) -> Self {
|
||||
Self {
|
||||
row: i32::from_le_bytes(raw.row),
|
||||
row_span: i32::from_le_bytes(raw.row_span),
|
||||
column: i32::from_le_bytes(raw.column),
|
||||
column_span: i32::from_le_bytes(raw.column_span),
|
||||
align_self: if raw.has_align_self == 1 {
|
||||
AlignSelf::from_u8(raw.align_self)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
justify_self: if raw.has_justify_self == 1 {
|
||||
JustifySelf::from_u8(raw.justify_self)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
shape: if raw.has_shape_id == 1 {
|
||||
Some(uuid_from_u32_quartet(
|
||||
u32::from_le_bytes(raw.shape_id_a),
|
||||
u32::from_le_bytes(raw.shape_id_b),
|
||||
u32::from_le_bytes(raw.shape_id_c),
|
||||
u32::from_le_bytes(raw.shape_id_d),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
#[derive(Debug, Clone, PartialEq, Copy, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||
pub enum Sizing {
|
||||
Fill = 0,
|
||||
Fix = 1,
|
||||
Auto = 2,
|
||||
}
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
impl Sizing {
|
||||
// TODO: implement a proper From trait for this
|
||||
// TODO: use transmute
|
||||
pub fn from_u8(value: u8) -> Self {
|
||||
match value {
|
||||
0 => Self::Fill,
|
||||
1 => Self::Fix,
|
||||
2 => Self::Auto,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
Fill,
|
||||
Fix,
|
||||
Auto,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
@@ -339,36 +144,17 @@ impl LayoutData {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
#[derive(Debug, Copy, Clone, PartialEq, ToJs)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
#[repr(u8)]
|
||||
pub enum AlignSelf {
|
||||
Auto = 0,
|
||||
Start = 1,
|
||||
End = 2,
|
||||
Center = 3,
|
||||
Stretch = 4,
|
||||
Auto,
|
||||
Start,
|
||||
End,
|
||||
Center,
|
||||
Stretch,
|
||||
}
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
impl AlignSelf {
|
||||
// TODO: implement a proper From trait for this
|
||||
// TODO: use transmute
|
||||
pub fn from_u8(value: u8) -> Option<AlignSelf> {
|
||||
match value {
|
||||
0 => Some(Self::Auto),
|
||||
1 => Some(Self::Start),
|
||||
2 => Some(Self::End),
|
||||
3 => Some(Self::Center),
|
||||
4 => Some(Self::Stretch),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
#[derive(Debug, Copy, Clone, PartialEq, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
pub enum JustifySelf {
|
||||
Auto = 0,
|
||||
Start = 1,
|
||||
@@ -377,22 +163,6 @@ pub enum JustifySelf {
|
||||
Stretch = 4,
|
||||
}
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
impl JustifySelf {
|
||||
// TODO: implement a proper From trait for this
|
||||
// TODO: use transmute
|
||||
pub fn from_u8(value: u8) -> Option<JustifySelf> {
|
||||
match value {
|
||||
0 => Some(Self::Auto),
|
||||
1 => Some(Self::Start),
|
||||
2 => Some(Self::End),
|
||||
3 => Some(Self::Center),
|
||||
4 => Some(Self::Stretch),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct FlexData {
|
||||
pub direction: FlexDirection,
|
||||
@@ -443,65 +213,6 @@ impl GridData {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: move this to the wasm module
|
||||
// FIXME: use transmute
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct RawGridTrack {
|
||||
track_type: u8,
|
||||
value: [u8; 4],
|
||||
}
|
||||
|
||||
impl RawGridTrack {
|
||||
pub fn from_bytes(bytes: [u8; 5]) -> Self {
|
||||
Self {
|
||||
track_type: bytes[0],
|
||||
value: [bytes[1], bytes[2], bytes[3], bytes[4]],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct RawGridCell {
|
||||
row: [u8; 4],
|
||||
row_span: [u8; 4],
|
||||
column: [u8; 4],
|
||||
column_span: [u8; 4],
|
||||
has_align_self: u8,
|
||||
align_self: u8,
|
||||
has_justify_self: u8,
|
||||
justify_self: u8,
|
||||
has_shape_id: u8,
|
||||
shape_id_a: [u8; 4],
|
||||
shape_id_b: [u8; 4],
|
||||
shape_id_c: [u8; 4],
|
||||
shape_id_d: [u8; 4],
|
||||
}
|
||||
|
||||
impl RawGridCell {
|
||||
pub fn from_bytes(bytes: [u8; 37]) -> Self {
|
||||
Self {
|
||||
row: [bytes[0], bytes[1], bytes[2], bytes[3]],
|
||||
row_span: [bytes[4], bytes[5], bytes[6], bytes[7]],
|
||||
column: [bytes[8], bytes[9], bytes[10], bytes[11]],
|
||||
column_span: [bytes[12], bytes[13], bytes[14], bytes[15]],
|
||||
|
||||
has_align_self: bytes[16],
|
||||
align_self: bytes[17],
|
||||
|
||||
has_justify_self: bytes[18],
|
||||
justify_self: bytes[19],
|
||||
|
||||
has_shape_id: bytes[20],
|
||||
shape_id_a: [bytes[21], bytes[22], bytes[23], bytes[24]],
|
||||
shape_id_b: [bytes[25], bytes[26], bytes[27], bytes[28]],
|
||||
shape_id_c: [bytes[29], bytes[30], bytes[31], bytes[32]],
|
||||
shape_id_d: [bytes[33], bytes[34], bytes[35], bytes[36]],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||
pub struct LayoutItem {
|
||||
pub margin_top: f32,
|
||||
|
||||
@@ -13,7 +13,7 @@ pub fn calculate_resize(
|
||||
ConstraintH::Left | ConstraintH::Right | ConstraintH::Center => {
|
||||
parent_before.width() / f32::max(0.01, parent_after.width())
|
||||
}
|
||||
ConstraintH::Leftright => {
|
||||
ConstraintH::LeftRight => {
|
||||
let left = parent_before.left(child_before.nw);
|
||||
let right = parent_before.right(child_before.ne);
|
||||
let target_width = parent_after.width() - left - right;
|
||||
@@ -26,7 +26,7 @@ pub fn calculate_resize(
|
||||
ConstraintV::Top | ConstraintV::Bottom | ConstraintV::Center => {
|
||||
parent_before.height() / f32::max(0.01, parent_after.height())
|
||||
}
|
||||
ConstraintV::Topbottom => {
|
||||
ConstraintV::TopBottom => {
|
||||
let top = parent_before.top(child_before.nw);
|
||||
let bottom = parent_before.bottom(child_before.sw);
|
||||
let target_height = parent_after.height() - top - bottom;
|
||||
@@ -51,7 +51,7 @@ pub fn calculate_displacement(
|
||||
child_after: &Bounds,
|
||||
) -> Option<(f32, f32)> {
|
||||
let delta_x = match constraint_h {
|
||||
ConstraintH::Left | ConstraintH::Leftright => {
|
||||
ConstraintH::Left | ConstraintH::LeftRight => {
|
||||
let target_left = parent_before.left(child_before.nw);
|
||||
let current_left = parent_after.left(child_after.nw);
|
||||
target_left - current_left
|
||||
@@ -71,7 +71,7 @@ pub fn calculate_displacement(
|
||||
};
|
||||
|
||||
let delta_y = match constraint_v {
|
||||
ConstraintV::Top | ConstraintV::Topbottom => {
|
||||
ConstraintV::Top | ConstraintV::TopBottom => {
|
||||
let target_top = parent_before.top(child_before.nw);
|
||||
let current_top = parent_after.top(child_after.nw);
|
||||
target_top - current_top
|
||||
|
||||
@@ -1,27 +1,12 @@
|
||||
use macros::ToJs;
|
||||
use skia_safe::{self as skia, image_filters, ImageFilter, Paint};
|
||||
|
||||
use super::Color;
|
||||
use crate::render::filters::compose_filters;
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
#[derive(Debug, Clone, Copy, PartialEq, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum ShadowStyle {
|
||||
Drop = 0,
|
||||
Inner = 1,
|
||||
}
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
impl From<u8> for ShadowStyle {
|
||||
// TODO: use transmute
|
||||
fn from(value: u8) -> Self {
|
||||
match value {
|
||||
0 => Self::Drop,
|
||||
1 => Self::Inner,
|
||||
_ => Self::default(),
|
||||
}
|
||||
}
|
||||
Drop,
|
||||
Inner,
|
||||
}
|
||||
|
||||
impl Default for ShadowStyle {
|
||||
@@ -40,7 +25,6 @@ pub struct Shadow {
|
||||
hidden: bool,
|
||||
}
|
||||
|
||||
// TODO: create shadows out of a chunk of bytes
|
||||
impl Shadow {
|
||||
pub fn new(
|
||||
color: Color,
|
||||
|
||||
@@ -1,61 +1,26 @@
|
||||
use crate::shapes::fills::{Fill, SolidColor};
|
||||
use macros::ToJs;
|
||||
use skia_safe::{self as skia, Rect};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use super::Corners;
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
#[derive(Debug, Clone, PartialEq, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||
pub enum StrokeStyle {
|
||||
Solid = 0,
|
||||
Dotted = 1,
|
||||
Dashed = 2,
|
||||
Mixed = 3,
|
||||
Solid,
|
||||
Dotted,
|
||||
Dashed,
|
||||
Mixed,
|
||||
}
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
impl From<u8> for StrokeStyle {
|
||||
// TODO: use transmute
|
||||
fn from(value: u8) -> Self {
|
||||
match value {
|
||||
1 => StrokeStyle::Dotted,
|
||||
2 => StrokeStyle::Dashed,
|
||||
3 => StrokeStyle::Mixed,
|
||||
_ => StrokeStyle::Solid,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
#[derive(Debug, Clone, Copy, PartialEq, ToJs)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum StrokeCap {
|
||||
None = 0,
|
||||
LineArrow = 1,
|
||||
TriangleArrow = 2,
|
||||
SquareMarker = 3,
|
||||
CircleMarker = 4,
|
||||
DiamondMarker = 5,
|
||||
Round = 6,
|
||||
Square = 7,
|
||||
}
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
impl From<u8> for StrokeCap {
|
||||
// TODO: use transmute
|
||||
fn from(value: u8) -> Self {
|
||||
match value {
|
||||
1 => StrokeCap::LineArrow,
|
||||
2 => StrokeCap::TriangleArrow,
|
||||
3 => StrokeCap::SquareMarker,
|
||||
4 => StrokeCap::CircleMarker,
|
||||
5 => StrokeCap::DiamondMarker,
|
||||
6 => StrokeCap::Round,
|
||||
7 => StrokeCap::Square,
|
||||
_ => StrokeCap::None,
|
||||
}
|
||||
}
|
||||
LineArrow,
|
||||
TriangleArrow,
|
||||
SquareMarker,
|
||||
CircleMarker,
|
||||
DiamondMarker,
|
||||
Round,
|
||||
Square,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
@@ -70,8 +35,8 @@ pub struct Stroke {
|
||||
pub fill: Fill,
|
||||
pub width: f32,
|
||||
pub style: StrokeStyle,
|
||||
pub cap_end: StrokeCap,
|
||||
pub cap_start: StrokeCap,
|
||||
pub cap_end: Option<StrokeCap>,
|
||||
pub cap_start: Option<StrokeCap>,
|
||||
pub kind: StrokeKind,
|
||||
}
|
||||
|
||||
@@ -85,35 +50,50 @@ impl Stroke {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_center_stroke(width: f32, style: u8, cap_start: u8, cap_end: u8) -> Self {
|
||||
pub fn new_center_stroke(
|
||||
width: f32,
|
||||
style: StrokeStyle,
|
||||
cap_start: Option<StrokeCap>,
|
||||
cap_end: Option<StrokeCap>,
|
||||
) -> Self {
|
||||
Stroke {
|
||||
fill: Fill::Solid(SolidColor(skia::Color::TRANSPARENT)),
|
||||
width,
|
||||
style: StrokeStyle::from(style),
|
||||
cap_end: StrokeCap::from(cap_end),
|
||||
cap_start: StrokeCap::from(cap_start),
|
||||
style,
|
||||
cap_end,
|
||||
cap_start,
|
||||
kind: StrokeKind::Center,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_inner_stroke(width: f32, style: u8, cap_start: u8, cap_end: u8) -> Self {
|
||||
pub fn new_inner_stroke(
|
||||
width: f32,
|
||||
style: StrokeStyle,
|
||||
cap_start: Option<StrokeCap>,
|
||||
cap_end: Option<StrokeCap>,
|
||||
) -> Self {
|
||||
Stroke {
|
||||
fill: Fill::Solid(SolidColor(skia::Color::TRANSPARENT)),
|
||||
width,
|
||||
style: StrokeStyle::from(style),
|
||||
cap_end: StrokeCap::from(cap_end),
|
||||
cap_start: StrokeCap::from(cap_start),
|
||||
style,
|
||||
cap_end,
|
||||
cap_start,
|
||||
kind: StrokeKind::Inner,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_outer_stroke(width: f32, style: u8, cap_start: u8, cap_end: u8) -> Self {
|
||||
pub fn new_outer_stroke(
|
||||
width: f32,
|
||||
style: StrokeStyle,
|
||||
cap_start: Option<StrokeCap>,
|
||||
cap_end: Option<StrokeCap>,
|
||||
) -> Self {
|
||||
Stroke {
|
||||
fill: Fill::Solid(SolidColor(skia::Color::TRANSPARENT)),
|
||||
width,
|
||||
style: StrokeStyle::from(style),
|
||||
cap_end: StrokeCap::from(cap_end),
|
||||
cap_start: StrokeCap::from(cap_start),
|
||||
style,
|
||||
cap_end,
|
||||
cap_start,
|
||||
kind: StrokeKind::Outer,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ use crate::{
|
||||
textlayout::paragraph_builder_group_from_text,
|
||||
};
|
||||
|
||||
use macros::ToJs;
|
||||
use skia_safe::{
|
||||
self as skia,
|
||||
paint::{self, Paint},
|
||||
@@ -19,26 +18,11 @@ use crate::utils::uuid_from_u32;
|
||||
use crate::wasm::fills::parse_fills_from_bytes;
|
||||
use crate::Uuid;
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
#[derive(Debug, PartialEq, Clone, Copy, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
pub enum GrowType {
|
||||
Fixed = 0,
|
||||
AutoWidth = 1,
|
||||
AutoHeight = 2,
|
||||
}
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
impl GrowType {
|
||||
// TODO: use transmute
|
||||
pub fn from(grow_type: u8) -> Self {
|
||||
match grow_type {
|
||||
0 => Self::Fixed,
|
||||
1 => Self::AutoWidth,
|
||||
2 => Self::AutoHeight,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
Fixed,
|
||||
AutoWidth,
|
||||
AutoHeight,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
@@ -572,10 +556,12 @@ impl RawTextData {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
pub struct RawTextData {
|
||||
pub paragraph: Paragraph,
|
||||
}
|
||||
|
||||
// TODO: maybe move this to the wasm module?
|
||||
impl From<&Vec<u8>> for RawTextData {
|
||||
fn from(bytes: &Vec<u8>) -> Self {
|
||||
let paragraph = RawParagraphData::try_from(&bytes[..RAW_PARAGRAPH_DATA_SIZE]).unwrap();
|
||||
@@ -596,12 +582,10 @@ impl From<&Vec<u8>> for RawTextData {
|
||||
|
||||
let font_id = uuid_from_u32(text_leaf.font_id);
|
||||
let font_variant_id = uuid_from_u32(text_leaf.font_variant_id);
|
||||
let font_style = crate::wasm::fonts::RawFontStyle::from(text_leaf.font_style);
|
||||
|
||||
let font_family = FontFamily::new(
|
||||
font_id,
|
||||
text_leaf.font_weight as u32,
|
||||
text_leaf.font_style.into(),
|
||||
);
|
||||
let font_family =
|
||||
FontFamily::new(font_id, text_leaf.font_weight as u32, font_style.into());
|
||||
|
||||
let new_text_leaf = TextLeaf::new(
|
||||
text,
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
pub mod blend;
|
||||
pub mod blurs;
|
||||
pub mod fills;
|
||||
pub mod fonts;
|
||||
pub mod layout;
|
||||
pub mod layouts;
|
||||
pub mod paths;
|
||||
pub mod shadows;
|
||||
pub mod shapes;
|
||||
pub mod strokes;
|
||||
pub mod text;
|
||||
|
||||
65
render-wasm/src/wasm/blend.rs
Normal file
65
render-wasm/src/wasm/blend.rs
Normal file
@@ -0,0 +1,65 @@
|
||||
use macros::ToJs;
|
||||
use skia_safe as skia;
|
||||
|
||||
use crate::shapes::BlendMode;
|
||||
use crate::{with_current_shape_mut, STATE};
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Copy, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[allow(dead_code)]
|
||||
pub enum RawBlendMode {
|
||||
Normal = 3,
|
||||
Screen = 14,
|
||||
Overlay = 15,
|
||||
Darken = 16,
|
||||
Lighten = 17,
|
||||
ColorDodge = 18,
|
||||
ColorBurn = 19,
|
||||
HardLight = 20,
|
||||
SoftLight = 21,
|
||||
Difference = 22,
|
||||
Exclusion = 23,
|
||||
Multiply = 24,
|
||||
Hue = 25,
|
||||
Saturation = 26,
|
||||
Color = 27,
|
||||
Luminosity = 28,
|
||||
}
|
||||
|
||||
impl From<u8> for RawBlendMode {
|
||||
fn from(value: u8) -> Self {
|
||||
unsafe { std::mem::transmute(value) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RawBlendMode> for BlendMode {
|
||||
fn from(value: RawBlendMode) -> Self {
|
||||
match value {
|
||||
RawBlendMode::Normal => BlendMode(skia::BlendMode::SrcOver),
|
||||
RawBlendMode::Screen => BlendMode(skia::BlendMode::Screen),
|
||||
RawBlendMode::Overlay => BlendMode(skia::BlendMode::Overlay),
|
||||
RawBlendMode::Darken => BlendMode(skia::BlendMode::Darken),
|
||||
RawBlendMode::Lighten => BlendMode(skia::BlendMode::Lighten),
|
||||
RawBlendMode::ColorDodge => BlendMode(skia::BlendMode::ColorDodge),
|
||||
RawBlendMode::ColorBurn => BlendMode(skia::BlendMode::ColorBurn),
|
||||
RawBlendMode::HardLight => BlendMode(skia::BlendMode::HardLight),
|
||||
RawBlendMode::SoftLight => BlendMode(skia::BlendMode::SoftLight),
|
||||
RawBlendMode::Difference => BlendMode(skia::BlendMode::Difference),
|
||||
RawBlendMode::Exclusion => BlendMode(skia::BlendMode::Exclusion),
|
||||
RawBlendMode::Multiply => BlendMode(skia::BlendMode::Multiply),
|
||||
RawBlendMode::Hue => BlendMode(skia::BlendMode::Hue),
|
||||
RawBlendMode::Saturation => BlendMode(skia::BlendMode::Saturation),
|
||||
RawBlendMode::Color => BlendMode(skia::BlendMode::Color),
|
||||
RawBlendMode::Luminosity => BlendMode(skia::BlendMode::Luminosity),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn set_shape_blend_mode(mode: u8) {
|
||||
let mode = RawBlendMode::from(mode);
|
||||
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
shape.set_blend_mode(mode.into());
|
||||
});
|
||||
}
|
||||
40
render-wasm/src/wasm/blurs.rs
Normal file
40
render-wasm/src/wasm/blurs.rs
Normal file
@@ -0,0 +1,40 @@
|
||||
use macros::ToJs;
|
||||
|
||||
use crate::shapes::{Blur, BlurType};
|
||||
use crate::{with_current_shape_mut, STATE};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[allow(dead_code)]
|
||||
pub enum RawBlurType {
|
||||
LayerBlur = 0, // odd naming to comply with cljs value
|
||||
}
|
||||
|
||||
impl From<u8> for RawBlurType {
|
||||
fn from(value: u8) -> Self {
|
||||
unsafe { std::mem::transmute(value) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RawBlurType> for BlurType {
|
||||
fn from(value: RawBlurType) -> Self {
|
||||
match value {
|
||||
RawBlurType::LayerBlur => BlurType::LayerBlur,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn set_shape_blur(blur_type: u8, hidden: bool, value: f32) {
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
let blur_type = RawBlurType::from(blur_type);
|
||||
shape.set_blur(Some(Blur::new(blur_type.into(), hidden, value)));
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn clear_shape_blur() {
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
shape.set_blur(None);
|
||||
});
|
||||
}
|
||||
@@ -1,9 +1,33 @@
|
||||
use macros::ToJs;
|
||||
|
||||
use crate::mem;
|
||||
use crate::shapes::{FontFamily, FontStyle};
|
||||
use crate::utils::uuid_from_u32_quartet;
|
||||
use crate::with_state_mut;
|
||||
use crate::STATE;
|
||||
|
||||
use crate::shapes::FontFamily;
|
||||
#[derive(Debug, PartialEq, Clone, Copy, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[allow(dead_code)]
|
||||
pub enum RawFontStyle {
|
||||
Normal = 0,
|
||||
Italic = 1,
|
||||
}
|
||||
|
||||
impl From<u8> for RawFontStyle {
|
||||
fn from(value: u8) -> Self {
|
||||
unsafe { std::mem::transmute(value) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RawFontStyle> for FontStyle {
|
||||
fn from(value: RawFontStyle) -> Self {
|
||||
match value {
|
||||
RawFontStyle::Normal => FontStyle::Normal,
|
||||
RawFontStyle::Italic => FontStyle::Italic,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn store_font(
|
||||
@@ -23,8 +47,9 @@ pub extern "C" fn store_font(
|
||||
with_state_mut!(state, {
|
||||
let id = uuid_from_u32_quartet(a2, b2, c2, d2);
|
||||
let font_bytes = mem::bytes();
|
||||
let font_style = RawFontStyle::from(style);
|
||||
|
||||
let family = FontFamily::new(id, weight, style.into());
|
||||
let family = FontFamily::new(id, weight, font_style.into());
|
||||
let _ =
|
||||
state
|
||||
.render_state_mut()
|
||||
@@ -52,7 +77,8 @@ pub extern "C" fn is_font_uploaded(
|
||||
) -> bool {
|
||||
with_state_mut!(state, {
|
||||
let id = uuid_from_u32_quartet(a, b, c, d);
|
||||
let family = FontFamily::new(id, weight, style.into());
|
||||
let font_style = RawFontStyle::from(style);
|
||||
let family = FontFamily::new(id, weight, font_style.into());
|
||||
let res = state.render_state().fonts().has_family(&family, is_emoji);
|
||||
|
||||
res
|
||||
|
||||
@@ -1,249 +0,0 @@
|
||||
use crate::mem;
|
||||
use crate::shapes::{self, ConstraintH, ConstraintV, VerticalAlign};
|
||||
use crate::{uuid_from_u32_quartet, with_current_shape_mut, with_state, with_state_mut, STATE};
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn set_shape_constraint_h(constraint: u8) {
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
shape.set_constraint_h(ConstraintH::from(constraint));
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn set_shape_constraint_v(constraint: u8) {
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
shape.set_constraint_v(ConstraintV::from(constraint));
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn clear_shape_constraints() {
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
shape.clear_constraints();
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn set_shape_vertical_align(align: u8) {
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
shape.set_vertical_align(VerticalAlign::from(align));
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn clear_shape_layout() {
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
shape.clear_layout();
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn set_flex_layout_data(
|
||||
dir: u8,
|
||||
row_gap: f32,
|
||||
column_gap: f32,
|
||||
align_items: u8,
|
||||
align_content: u8,
|
||||
justify_items: u8,
|
||||
justify_content: u8,
|
||||
wrap_type: u8,
|
||||
padding_top: f32,
|
||||
padding_right: f32,
|
||||
padding_bottom: f32,
|
||||
padding_left: f32,
|
||||
) {
|
||||
let dir = shapes::FlexDirection::from_u8(dir);
|
||||
let align_items = shapes::AlignItems::from_u8(align_items);
|
||||
let align_content = shapes::AlignContent::from_u8(align_content);
|
||||
let justify_items = shapes::JustifyItems::from_u8(justify_items);
|
||||
let justify_content = shapes::JustifyContent::from_u8(justify_content);
|
||||
let wrap_type = shapes::WrapType::from_u8(wrap_type);
|
||||
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
shape.set_flex_layout_data(
|
||||
dir,
|
||||
row_gap,
|
||||
column_gap,
|
||||
align_items,
|
||||
align_content,
|
||||
justify_items,
|
||||
justify_content,
|
||||
wrap_type,
|
||||
padding_top,
|
||||
padding_right,
|
||||
padding_bottom,
|
||||
padding_left,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn set_layout_child_data(
|
||||
margin_top: f32,
|
||||
margin_right: f32,
|
||||
margin_bottom: f32,
|
||||
margin_left: f32,
|
||||
h_sizing: u8,
|
||||
v_sizing: u8,
|
||||
has_max_h: bool,
|
||||
max_h: f32,
|
||||
has_min_h: bool,
|
||||
min_h: f32,
|
||||
has_max_w: bool,
|
||||
max_w: f32,
|
||||
has_min_w: bool,
|
||||
min_w: f32,
|
||||
has_align_self: bool,
|
||||
align_self: u8,
|
||||
is_absolute: bool,
|
||||
z_index: i32,
|
||||
) {
|
||||
let h_sizing = shapes::Sizing::from_u8(h_sizing);
|
||||
let v_sizing = shapes::Sizing::from_u8(v_sizing);
|
||||
let max_h = if has_max_h { Some(max_h) } else { None };
|
||||
let min_h = if has_min_h { Some(min_h) } else { None };
|
||||
let max_w = if has_max_w { Some(max_w) } else { None };
|
||||
let min_w = if has_min_w { Some(min_w) } else { None };
|
||||
let align_self = if has_align_self {
|
||||
shapes::AlignSelf::from_u8(align_self)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
shape.set_flex_layout_child_data(
|
||||
margin_top,
|
||||
margin_right,
|
||||
margin_bottom,
|
||||
margin_left,
|
||||
h_sizing,
|
||||
v_sizing,
|
||||
max_h,
|
||||
min_h,
|
||||
max_w,
|
||||
min_w,
|
||||
align_self,
|
||||
is_absolute,
|
||||
z_index,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn set_grid_layout_data(
|
||||
dir: u8,
|
||||
row_gap: f32,
|
||||
column_gap: f32,
|
||||
align_items: u8,
|
||||
align_content: u8,
|
||||
justify_items: u8,
|
||||
justify_content: u8,
|
||||
padding_top: f32,
|
||||
padding_right: f32,
|
||||
padding_bottom: f32,
|
||||
padding_left: f32,
|
||||
) {
|
||||
let dir = shapes::GridDirection::from_u8(dir);
|
||||
let align_items = shapes::AlignItems::from_u8(align_items);
|
||||
let align_content = shapes::AlignContent::from_u8(align_content);
|
||||
let justify_items = shapes::JustifyItems::from_u8(justify_items);
|
||||
let justify_content = shapes::JustifyContent::from_u8(justify_content);
|
||||
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
shape.set_grid_layout_data(
|
||||
dir,
|
||||
row_gap,
|
||||
column_gap,
|
||||
align_items,
|
||||
align_content,
|
||||
justify_items,
|
||||
justify_content,
|
||||
padding_top,
|
||||
padding_right,
|
||||
padding_bottom,
|
||||
padding_left,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn set_grid_columns() {
|
||||
let bytes = mem::bytes();
|
||||
|
||||
let entries: Vec<_> = bytes
|
||||
.chunks(size_of::<shapes::RawGridTrack>())
|
||||
.map(|data| shapes::RawGridTrack::from_bytes(data.try_into().unwrap()))
|
||||
.collect();
|
||||
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
shape.set_grid_columns(entries);
|
||||
});
|
||||
|
||||
mem::free_bytes();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn set_grid_rows() {
|
||||
let bytes = mem::bytes();
|
||||
|
||||
let entries: Vec<_> = bytes
|
||||
.chunks(size_of::<shapes::RawGridTrack>())
|
||||
.map(|data| shapes::RawGridTrack::from_bytes(data.try_into().unwrap()))
|
||||
.collect();
|
||||
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
shape.set_grid_rows(entries);
|
||||
});
|
||||
|
||||
mem::free_bytes();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn set_grid_cells() {
|
||||
let bytes = mem::bytes();
|
||||
|
||||
let entries: Vec<_> = bytes
|
||||
.chunks(size_of::<shapes::RawGridCell>())
|
||||
.map(|data| shapes::RawGridCell::from_bytes(data.try_into().unwrap()))
|
||||
.collect();
|
||||
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
shape.set_grid_cells(entries);
|
||||
});
|
||||
|
||||
mem::free_bytes();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn show_grid(a: u32, b: u32, c: u32, d: u32) {
|
||||
with_state_mut!(state, {
|
||||
let id = uuid_from_u32_quartet(a, b, c, d);
|
||||
state.render_state.show_grid = Some(id);
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn hide_grid() {
|
||||
with_state_mut!(state, {
|
||||
state.render_state.show_grid = None;
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn get_grid_coords(pos_x: f32, pos_y: f32) -> *mut u8 {
|
||||
let row: i32;
|
||||
let col: i32;
|
||||
with_state!(state, {
|
||||
if let Some((r, c)) = state.get_grid_coords(pos_x, pos_y) {
|
||||
row = r;
|
||||
col = c;
|
||||
} else {
|
||||
row = -1;
|
||||
col = -1;
|
||||
};
|
||||
});
|
||||
let mut bytes = vec![0; 8];
|
||||
bytes[0..4].clone_from_slice(&row.to_le_bytes());
|
||||
bytes[4..8].clone_from_slice(&col.to_le_bytes());
|
||||
mem::write_bytes(bytes)
|
||||
}
|
||||
90
render-wasm/src/wasm/layouts.rs
Normal file
90
render-wasm/src/wasm/layouts.rs
Normal file
@@ -0,0 +1,90 @@
|
||||
use crate::shapes::Sizing;
|
||||
use crate::{with_current_shape_mut, STATE};
|
||||
use macros::ToJs;
|
||||
|
||||
mod align;
|
||||
mod constraints;
|
||||
mod flex;
|
||||
mod grid;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Copy, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[allow(dead_code)]
|
||||
pub enum RawSizing {
|
||||
Fill = 0,
|
||||
Fix = 1,
|
||||
Auto = 2,
|
||||
}
|
||||
|
||||
impl From<u8> for RawSizing {
|
||||
fn from(value: u8) -> Self {
|
||||
unsafe { std::mem::transmute(value) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RawSizing> for Sizing {
|
||||
fn from(value: RawSizing) -> Self {
|
||||
match value {
|
||||
RawSizing::Fill => Sizing::Fill,
|
||||
RawSizing::Fix => Sizing::Fix,
|
||||
RawSizing::Auto => Sizing::Auto,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn clear_shape_layout() {
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
shape.clear_layout();
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn set_layout_child_data(
|
||||
margin_top: f32,
|
||||
margin_right: f32,
|
||||
margin_bottom: f32,
|
||||
margin_left: f32,
|
||||
h_sizing: u8,
|
||||
v_sizing: u8,
|
||||
has_max_h: bool,
|
||||
max_h: f32,
|
||||
has_min_h: bool,
|
||||
min_h: f32,
|
||||
has_max_w: bool,
|
||||
max_w: f32,
|
||||
has_min_w: bool,
|
||||
min_w: f32,
|
||||
align_self: u8,
|
||||
is_absolute: bool,
|
||||
z_index: i32,
|
||||
) {
|
||||
let h_sizing = RawSizing::from(h_sizing);
|
||||
let v_sizing = RawSizing::from(v_sizing);
|
||||
let max_h = if has_max_h { Some(max_h) } else { None };
|
||||
let min_h = if has_min_h { Some(min_h) } else { None };
|
||||
let max_w = if has_max_w { Some(max_w) } else { None };
|
||||
let min_w = if has_min_w { Some(min_w) } else { None };
|
||||
|
||||
let raw_align_self = align::RawAlignSelf::from(align_self);
|
||||
|
||||
let align_self = raw_align_self.try_into().ok();
|
||||
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
shape.set_flex_layout_child_data(
|
||||
margin_top,
|
||||
margin_right,
|
||||
margin_bottom,
|
||||
margin_left,
|
||||
h_sizing.into(),
|
||||
v_sizing.into(),
|
||||
max_h,
|
||||
min_h,
|
||||
max_w,
|
||||
min_w,
|
||||
align_self,
|
||||
is_absolute,
|
||||
z_index,
|
||||
);
|
||||
});
|
||||
}
|
||||
223
render-wasm/src/wasm/layouts/align.rs
Normal file
223
render-wasm/src/wasm/layouts/align.rs
Normal file
@@ -0,0 +1,223 @@
|
||||
use macros::ToJs;
|
||||
|
||||
use crate::shapes::{
|
||||
AlignContent, AlignItems, AlignSelf, JustifyContent, JustifyItems, JustifySelf, VerticalAlign,
|
||||
};
|
||||
use crate::{with_current_shape_mut, STATE};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Copy, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[allow(dead_code)]
|
||||
pub enum RawAlignItems {
|
||||
Start = 0,
|
||||
End = 1,
|
||||
Center = 2,
|
||||
Stretch = 3,
|
||||
}
|
||||
|
||||
impl From<u8> for RawAlignItems {
|
||||
fn from(value: u8) -> Self {
|
||||
unsafe { std::mem::transmute(value) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RawAlignItems> for AlignItems {
|
||||
fn from(value: RawAlignItems) -> Self {
|
||||
match value {
|
||||
RawAlignItems::Start => AlignItems::Start,
|
||||
RawAlignItems::End => AlignItems::End,
|
||||
RawAlignItems::Center => AlignItems::Center,
|
||||
RawAlignItems::Stretch => AlignItems::Stretch,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Copy, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[allow(dead_code)]
|
||||
pub enum RawAlignContent {
|
||||
Start = 0,
|
||||
End = 1,
|
||||
Center = 2,
|
||||
SpaceBetween = 3,
|
||||
SpaceAround = 4,
|
||||
SpaceEvenly = 5,
|
||||
Stretch = 6,
|
||||
}
|
||||
|
||||
impl From<u8> for RawAlignContent {
|
||||
fn from(value: u8) -> Self {
|
||||
unsafe { std::mem::transmute(value) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RawAlignContent> for AlignContent {
|
||||
fn from(value: RawAlignContent) -> Self {
|
||||
match value {
|
||||
RawAlignContent::Start => AlignContent::Start,
|
||||
RawAlignContent::End => AlignContent::End,
|
||||
RawAlignContent::Center => AlignContent::Center,
|
||||
RawAlignContent::SpaceBetween => AlignContent::SpaceBetween,
|
||||
RawAlignContent::SpaceAround => AlignContent::SpaceAround,
|
||||
RawAlignContent::SpaceEvenly => AlignContent::SpaceEvenly,
|
||||
RawAlignContent::Stretch => AlignContent::Stretch,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Copy, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[allow(dead_code)]
|
||||
pub enum RawJustifyItems {
|
||||
Start = 0,
|
||||
End = 1,
|
||||
Center = 2,
|
||||
Stretch = 3,
|
||||
}
|
||||
|
||||
impl From<u8> for RawJustifyItems {
|
||||
fn from(value: u8) -> Self {
|
||||
unsafe { std::mem::transmute(value) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RawJustifyItems> for JustifyItems {
|
||||
fn from(value: RawJustifyItems) -> Self {
|
||||
match value {
|
||||
RawJustifyItems::Start => JustifyItems::Start,
|
||||
RawJustifyItems::End => JustifyItems::End,
|
||||
RawJustifyItems::Center => JustifyItems::Center,
|
||||
RawJustifyItems::Stretch => JustifyItems::Stretch,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Copy, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[allow(dead_code)]
|
||||
pub enum RawJustifyContent {
|
||||
Start = 0,
|
||||
End = 1,
|
||||
Center = 2,
|
||||
SpaceBetween = 3,
|
||||
SpaceAround = 4,
|
||||
SpaceEvenly = 5,
|
||||
Stretch = 6,
|
||||
}
|
||||
|
||||
impl From<u8> for RawJustifyContent {
|
||||
fn from(value: u8) -> Self {
|
||||
unsafe { std::mem::transmute(value) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RawJustifyContent> for JustifyContent {
|
||||
fn from(value: RawJustifyContent) -> Self {
|
||||
match value {
|
||||
RawJustifyContent::Start => JustifyContent::Start,
|
||||
RawJustifyContent::End => JustifyContent::End,
|
||||
RawJustifyContent::Center => JustifyContent::Center,
|
||||
RawJustifyContent::SpaceBetween => JustifyContent::SpaceBetween,
|
||||
RawJustifyContent::SpaceAround => JustifyContent::SpaceAround,
|
||||
RawJustifyContent::SpaceEvenly => JustifyContent::SpaceEvenly,
|
||||
RawJustifyContent::Stretch => JustifyContent::Stretch,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[allow(dead_code)]
|
||||
pub enum RawJustifySelf {
|
||||
None = 0,
|
||||
Auto = 1,
|
||||
Start = 2,
|
||||
End = 3,
|
||||
Center = 4,
|
||||
Stretch = 5,
|
||||
}
|
||||
|
||||
impl From<u8> for RawJustifySelf {
|
||||
fn from(value: u8) -> Self {
|
||||
unsafe { std::mem::transmute(value) }
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<RawJustifySelf> for JustifySelf {
|
||||
type Error = ();
|
||||
fn try_from(value: RawJustifySelf) -> Result<JustifySelf, Self::Error> {
|
||||
match value {
|
||||
RawJustifySelf::None => Err(()),
|
||||
RawJustifySelf::Auto => Ok(JustifySelf::Auto),
|
||||
RawJustifySelf::Start => Ok(JustifySelf::Start),
|
||||
RawJustifySelf::End => Ok(JustifySelf::End),
|
||||
RawJustifySelf::Center => Ok(JustifySelf::Center),
|
||||
RawJustifySelf::Stretch => Ok(JustifySelf::Stretch),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[allow(dead_code)]
|
||||
pub enum RawAlignSelf {
|
||||
None = 0,
|
||||
Auto = 1,
|
||||
Start = 2,
|
||||
End = 3,
|
||||
Center = 4,
|
||||
Stretch = 5,
|
||||
}
|
||||
|
||||
impl From<u8> for RawAlignSelf {
|
||||
fn from(value: u8) -> Self {
|
||||
unsafe { std::mem::transmute(value) }
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<RawAlignSelf> for AlignSelf {
|
||||
type Error = ();
|
||||
fn try_from(value: RawAlignSelf) -> Result<AlignSelf, Self::Error> {
|
||||
match value {
|
||||
RawAlignSelf::None => Err(()),
|
||||
RawAlignSelf::Auto => Ok(AlignSelf::Auto),
|
||||
RawAlignSelf::Start => Ok(AlignSelf::Start),
|
||||
RawAlignSelf::End => Ok(AlignSelf::End),
|
||||
RawAlignSelf::Center => Ok(AlignSelf::Center),
|
||||
RawAlignSelf::Stretch => Ok(AlignSelf::Stretch),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Copy, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[allow(dead_code)]
|
||||
pub enum RawVerticalAlign {
|
||||
Top = 0,
|
||||
Center = 1,
|
||||
Bottom = 2,
|
||||
}
|
||||
|
||||
impl From<u8> for RawVerticalAlign {
|
||||
fn from(value: u8) -> Self {
|
||||
unsafe { std::mem::transmute(value) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RawVerticalAlign> for VerticalAlign {
|
||||
fn from(value: RawVerticalAlign) -> Self {
|
||||
match value {
|
||||
RawVerticalAlign::Top => VerticalAlign::Top,
|
||||
RawVerticalAlign::Center => VerticalAlign::Center,
|
||||
RawVerticalAlign::Bottom => VerticalAlign::Bottom,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn set_shape_vertical_align(align: u8) {
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
let align = RawVerticalAlign::from(align);
|
||||
shape.set_vertical_align(align.into());
|
||||
});
|
||||
}
|
||||
85
render-wasm/src/wasm/layouts/constraints.rs
Normal file
85
render-wasm/src/wasm/layouts/constraints.rs
Normal file
@@ -0,0 +1,85 @@
|
||||
use macros::ToJs;
|
||||
|
||||
use crate::shapes::{ConstraintH, ConstraintV};
|
||||
use crate::{with_current_shape_mut, STATE};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Copy, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[allow(dead_code)]
|
||||
pub enum RawConstraintH {
|
||||
Left = 0,
|
||||
Right = 1,
|
||||
Leftright = 2, // odd casing to comply with cljs value
|
||||
Center = 3,
|
||||
Scale = 4,
|
||||
}
|
||||
|
||||
impl From<u8> for RawConstraintH {
|
||||
fn from(value: u8) -> Self {
|
||||
unsafe { std::mem::transmute(value) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RawConstraintH> for ConstraintH {
|
||||
fn from(value: RawConstraintH) -> Self {
|
||||
match value {
|
||||
RawConstraintH::Left => ConstraintH::Left,
|
||||
RawConstraintH::Right => ConstraintH::Right,
|
||||
RawConstraintH::Leftright => ConstraintH::LeftRight,
|
||||
RawConstraintH::Center => ConstraintH::Center,
|
||||
RawConstraintH::Scale => ConstraintH::Scale,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Copy, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[allow(dead_code)]
|
||||
pub enum RawConstraintV {
|
||||
Top = 0,
|
||||
Bottom = 1,
|
||||
Topbottom = 2, // odd casing to comply with cljs value
|
||||
Center = 3,
|
||||
Scale = 4,
|
||||
}
|
||||
|
||||
impl From<u8> for RawConstraintV {
|
||||
fn from(value: u8) -> Self {
|
||||
unsafe { std::mem::transmute(value) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RawConstraintV> for ConstraintV {
|
||||
fn from(value: RawConstraintV) -> Self {
|
||||
match value {
|
||||
RawConstraintV::Top => ConstraintV::Top,
|
||||
RawConstraintV::Bottom => ConstraintV::Bottom,
|
||||
RawConstraintV::Topbottom => ConstraintV::TopBottom,
|
||||
RawConstraintV::Center => ConstraintV::Center,
|
||||
RawConstraintV::Scale => ConstraintV::Scale,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn set_shape_constraint_h(constraint: u8) {
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
let constraint = RawConstraintH::from(constraint);
|
||||
shape.set_constraint_h(Some(constraint.into()));
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn set_shape_constraint_v(constraint: u8) {
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
let constraint = RawConstraintV::from(constraint);
|
||||
shape.set_constraint_v(Some(constraint.into()));
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn clear_shape_constraints() {
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
shape.clear_constraints();
|
||||
});
|
||||
}
|
||||
95
render-wasm/src/wasm/layouts/flex.rs
Normal file
95
render-wasm/src/wasm/layouts/flex.rs
Normal file
@@ -0,0 +1,95 @@
|
||||
use crate::shapes::{FlexDirection, WrapType};
|
||||
use crate::{with_current_shape_mut, STATE};
|
||||
use macros::ToJs;
|
||||
|
||||
use super::align;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[allow(dead_code)]
|
||||
pub enum RawFlexDirection {
|
||||
Row = 0,
|
||||
RowReverse = 1,
|
||||
Column = 2,
|
||||
ColumnReverse = 3,
|
||||
}
|
||||
|
||||
impl From<u8> for RawFlexDirection {
|
||||
fn from(value: u8) -> Self {
|
||||
unsafe { std::mem::transmute(value) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RawFlexDirection> for FlexDirection {
|
||||
fn from(value: RawFlexDirection) -> Self {
|
||||
match value {
|
||||
RawFlexDirection::Row => FlexDirection::Row,
|
||||
RawFlexDirection::RowReverse => FlexDirection::RowReverse,
|
||||
RawFlexDirection::Column => FlexDirection::Column,
|
||||
RawFlexDirection::ColumnReverse => FlexDirection::ColumnReverse,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[allow(dead_code)]
|
||||
pub enum RawWrapType {
|
||||
Wrap = 0,
|
||||
Nowrap = 1, // odd casing to comply with cljs value
|
||||
}
|
||||
|
||||
impl From<u8> for RawWrapType {
|
||||
fn from(value: u8) -> Self {
|
||||
unsafe { std::mem::transmute(value) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RawWrapType> for WrapType {
|
||||
fn from(value: RawWrapType) -> Self {
|
||||
match value {
|
||||
RawWrapType::Wrap => WrapType::Wrap,
|
||||
RawWrapType::Nowrap => WrapType::NoWrap,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn set_flex_layout_data(
|
||||
dir: u8,
|
||||
row_gap: f32,
|
||||
column_gap: f32,
|
||||
align_items: u8,
|
||||
align_content: u8,
|
||||
justify_items: u8,
|
||||
justify_content: u8,
|
||||
wrap_type: u8,
|
||||
padding_top: f32,
|
||||
padding_right: f32,
|
||||
padding_bottom: f32,
|
||||
padding_left: f32,
|
||||
) {
|
||||
let dir = RawFlexDirection::from(dir);
|
||||
let align_items = align::RawAlignItems::from(align_items);
|
||||
let align_content = align::RawAlignContent::from(align_content);
|
||||
let justify_items = align::RawJustifyItems::from(justify_items);
|
||||
let justify_content = align::RawJustifyContent::from(justify_content);
|
||||
let wrap_type = RawWrapType::from(wrap_type);
|
||||
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
shape.set_flex_layout_data(
|
||||
dir.into(),
|
||||
row_gap,
|
||||
column_gap,
|
||||
align_items.into(),
|
||||
align_content.into(),
|
||||
justify_items.into(),
|
||||
justify_content.into(),
|
||||
wrap_type.into(),
|
||||
padding_top,
|
||||
padding_right,
|
||||
padding_bottom,
|
||||
padding_left,
|
||||
);
|
||||
});
|
||||
}
|
||||
253
render-wasm/src/wasm/layouts/grid.rs
Normal file
253
render-wasm/src/wasm/layouts/grid.rs
Normal file
@@ -0,0 +1,253 @@
|
||||
use macros::ToJs;
|
||||
|
||||
use crate::mem;
|
||||
use crate::shapes::{GridCell, GridDirection, GridTrack, GridTrackType};
|
||||
use crate::uuid::Uuid;
|
||||
use crate::{uuid_from_u32_quartet, with_current_shape_mut, with_state, with_state_mut, STATE};
|
||||
|
||||
use super::align;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C, align(1))]
|
||||
struct RawGridCell {
|
||||
row: i32,
|
||||
row_span: i32,
|
||||
column: i32,
|
||||
column_span: i32,
|
||||
align_self: u8,
|
||||
justify_self: u8,
|
||||
_padding: u16,
|
||||
shape_id_a: u32,
|
||||
shape_id_b: u32,
|
||||
shape_id_c: u32,
|
||||
shape_id_d: u32,
|
||||
}
|
||||
|
||||
impl From<[u8; size_of::<RawGridCell>()]> for RawGridCell {
|
||||
fn from(bytes: [u8; size_of::<RawGridCell>()]) -> Self {
|
||||
unsafe { std::mem::transmute(bytes) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RawGridCell> for GridCell {
|
||||
fn from(raw: RawGridCell) -> Self {
|
||||
let raw_justify_self = super::align::RawJustifySelf::from(raw.justify_self);
|
||||
let raw_align_self = super::align::RawAlignSelf::from(raw.align_self);
|
||||
let shape_id = uuid_from_u32_quartet(
|
||||
raw.shape_id_a,
|
||||
raw.shape_id_b,
|
||||
raw.shape_id_c,
|
||||
raw.shape_id_d,
|
||||
);
|
||||
|
||||
Self {
|
||||
row: raw.row,
|
||||
row_span: raw.row_span,
|
||||
column: raw.column,
|
||||
column_span: raw.column_span,
|
||||
align_self: raw_align_self.try_into().ok(),
|
||||
justify_self: raw_justify_self.try_into().ok(),
|
||||
shape: if shape_id != Uuid::nil() {
|
||||
Some(shape_id)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[allow(dead_code)]
|
||||
pub enum RawGridDirection {
|
||||
Row = 0,
|
||||
Column = 1,
|
||||
}
|
||||
|
||||
impl From<u8> for RawGridDirection {
|
||||
fn from(value: u8) -> Self {
|
||||
unsafe { std::mem::transmute(value) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RawGridDirection> for GridDirection {
|
||||
fn from(value: RawGridDirection) -> Self {
|
||||
match value {
|
||||
RawGridDirection::Row => Self::Row,
|
||||
RawGridDirection::Column => Self::Column,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[allow(dead_code)]
|
||||
pub enum RawGridTrackType {
|
||||
Percent = 0,
|
||||
Flex = 1,
|
||||
Auto = 2,
|
||||
Fixed = 3,
|
||||
}
|
||||
|
||||
impl From<u8> for RawGridTrackType {
|
||||
fn from(value: u8) -> Self {
|
||||
unsafe { std::mem::transmute(value) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RawGridTrackType> for GridTrackType {
|
||||
fn from(value: RawGridTrackType) -> Self {
|
||||
match value {
|
||||
RawGridTrackType::Percent => Self::Percent,
|
||||
RawGridTrackType::Flex => Self::Flex,
|
||||
RawGridTrackType::Auto => Self::Auto,
|
||||
RawGridTrackType::Fixed => Self::Fixed,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C, align(4))]
|
||||
#[allow(dead_code)]
|
||||
pub struct RawGridTrack {
|
||||
track_type: RawGridTrackType,
|
||||
_padding: [u8; 3],
|
||||
value: f32,
|
||||
}
|
||||
|
||||
impl From<[u8; size_of::<RawGridTrack>()]> for RawGridTrack {
|
||||
fn from(bytes: [u8; size_of::<RawGridTrack>()]) -> Self {
|
||||
unsafe { std::mem::transmute(bytes) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RawGridTrack> for GridTrack {
|
||||
fn from(raw: RawGridTrack) -> Self {
|
||||
Self {
|
||||
track_type: raw.track_type.into(),
|
||||
value: raw.value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn set_grid_layout_data(
|
||||
dir: u8,
|
||||
row_gap: f32,
|
||||
column_gap: f32,
|
||||
align_items: u8,
|
||||
align_content: u8,
|
||||
justify_items: u8,
|
||||
justify_content: u8,
|
||||
padding_top: f32,
|
||||
padding_right: f32,
|
||||
padding_bottom: f32,
|
||||
padding_left: f32,
|
||||
) {
|
||||
let dir = RawGridDirection::from(dir);
|
||||
let align_items = align::RawAlignItems::from(align_items);
|
||||
let align_content = align::RawAlignContent::from(align_content);
|
||||
let justify_items = align::RawJustifyItems::from(justify_items);
|
||||
let justify_content = align::RawJustifyContent::from(justify_content);
|
||||
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
shape.set_grid_layout_data(
|
||||
dir.into(),
|
||||
row_gap,
|
||||
column_gap,
|
||||
align_items.into(),
|
||||
align_content.into(),
|
||||
justify_items.into(),
|
||||
justify_content.into(),
|
||||
padding_top,
|
||||
padding_right,
|
||||
padding_bottom,
|
||||
padding_left,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn set_grid_columns() {
|
||||
let bytes = mem::bytes();
|
||||
|
||||
let entries: Vec<GridTrack> = bytes
|
||||
.chunks(size_of::<RawGridTrack>())
|
||||
.map(|data| data.try_into().unwrap())
|
||||
.map(|data: [u8; size_of::<RawGridTrack>()]| RawGridTrack::from(data).into())
|
||||
.collect();
|
||||
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
shape.set_grid_columns(entries);
|
||||
});
|
||||
|
||||
mem::free_bytes();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn set_grid_rows() {
|
||||
let bytes = mem::bytes();
|
||||
|
||||
let entries: Vec<GridTrack> = bytes
|
||||
.chunks(size_of::<RawGridTrack>())
|
||||
.map(|data| data.try_into().unwrap())
|
||||
.map(|data: [u8; size_of::<RawGridTrack>()]| RawGridTrack::from(data).into())
|
||||
.collect();
|
||||
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
shape.set_grid_rows(entries);
|
||||
});
|
||||
|
||||
mem::free_bytes();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn set_grid_cells() {
|
||||
let bytes = mem::bytes();
|
||||
|
||||
let cells: Vec<RawGridCell> = bytes
|
||||
.chunks(size_of::<RawGridCell>())
|
||||
.map(|data| data.try_into().expect("Invalid grid cell data"))
|
||||
.map(|data: [u8; size_of::<RawGridCell>()]| RawGridCell::from(data))
|
||||
.collect();
|
||||
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
shape.set_grid_cells(cells.into_iter().map(|raw| raw.into()).collect());
|
||||
});
|
||||
|
||||
mem::free_bytes();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn show_grid(a: u32, b: u32, c: u32, d: u32) {
|
||||
with_state_mut!(state, {
|
||||
let id = uuid_from_u32_quartet(a, b, c, d);
|
||||
state.render_state.show_grid = Some(id);
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn hide_grid() {
|
||||
with_state_mut!(state, {
|
||||
state.render_state.show_grid = None;
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn get_grid_coords(pos_x: f32, pos_y: f32) -> *mut u8 {
|
||||
let row: i32;
|
||||
let col: i32;
|
||||
with_state!(state, {
|
||||
if let Some((r, c)) = state.get_grid_coords(pos_x, pos_y) {
|
||||
row = r;
|
||||
col = c;
|
||||
} else {
|
||||
row = -1;
|
||||
col = -1;
|
||||
};
|
||||
});
|
||||
let mut bytes = vec![0; 8];
|
||||
bytes[0..4].clone_from_slice(&row.to_le_bytes());
|
||||
bytes[4..8].clone_from_slice(&col.to_le_bytes());
|
||||
mem::write_bytes(bytes)
|
||||
}
|
||||
@@ -1,16 +1,15 @@
|
||||
#![allow(unused_mut, unused_variables)]
|
||||
use indexmap::IndexSet;
|
||||
use macros::ToJs;
|
||||
use mem::SerializableResult;
|
||||
use uuid::Uuid;
|
||||
use std::mem::size_of;
|
||||
|
||||
use crate::math::bools;
|
||||
use crate::shapes::{BoolType, Path, Segment, ToPath};
|
||||
use crate::uuid;
|
||||
use crate::{mem, with_current_shape, with_current_shape_mut, with_state, STATE};
|
||||
use crate::shapes::{Path, Segment, ToPath};
|
||||
use crate::{mem, with_current_shape, with_current_shape_mut, STATE};
|
||||
|
||||
const RAW_SEGMENT_DATA_SIZE: usize = size_of::<RawSegmentData>();
|
||||
|
||||
pub mod bools;
|
||||
|
||||
#[repr(C, u16, align(4))]
|
||||
#[derive(Debug, PartialEq, Clone, Copy, ToJs)]
|
||||
#[allow(dead_code)]
|
||||
@@ -183,37 +182,6 @@ pub extern "C" fn current_to_path() -> *mut u8 {
|
||||
mem::write_vec(result)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn calculate_bool(raw_bool_type: u8) -> *mut u8 {
|
||||
let bytes = mem::bytes_or_empty();
|
||||
|
||||
let entries: IndexSet<Uuid> = bytes
|
||||
.chunks(size_of::<<Uuid as SerializableResult>::BytesType>())
|
||||
.map(|data| Uuid::from_bytes(data.try_into().unwrap()))
|
||||
.collect();
|
||||
|
||||
mem::free_bytes();
|
||||
|
||||
let bool_type = BoolType::from(raw_bool_type);
|
||||
let result;
|
||||
with_state!(state, {
|
||||
let path = bools::bool_from_shapes(
|
||||
bool_type,
|
||||
&entries,
|
||||
&state.shapes,
|
||||
&state.modifiers,
|
||||
&state.structure,
|
||||
);
|
||||
result = path
|
||||
.segments()
|
||||
.iter()
|
||||
.copied()
|
||||
.map(RawSegmentData::from_segment)
|
||||
.collect();
|
||||
});
|
||||
mem::write_vec(result)
|
||||
}
|
||||
|
||||
// Extracts a string from the bytes slice until the next null byte (0) and returns the result as a `String`.
|
||||
// Updates the `start` index to the end of the extracted string.
|
||||
fn extract_string(start: &mut usize, bytes: &[u8]) -> String {
|
||||
|
||||
75
render-wasm/src/wasm/paths/bools.rs
Normal file
75
render-wasm/src/wasm/paths/bools.rs
Normal file
@@ -0,0 +1,75 @@
|
||||
use macros::ToJs;
|
||||
|
||||
use indexmap::IndexSet;
|
||||
|
||||
use super::RawSegmentData;
|
||||
use crate::math;
|
||||
use crate::shapes::BoolType;
|
||||
use crate::uuid::Uuid;
|
||||
use crate::{mem, SerializableResult};
|
||||
use crate::{with_current_shape_mut, with_state, STATE};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[allow(dead_code)]
|
||||
pub enum RawBoolType {
|
||||
Union = 0,
|
||||
Difference = 1,
|
||||
Intersection = 2,
|
||||
Exclusion = 3,
|
||||
}
|
||||
|
||||
impl From<u8> for RawBoolType {
|
||||
fn from(value: u8) -> Self {
|
||||
unsafe { std::mem::transmute(value) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RawBoolType> for BoolType {
|
||||
fn from(value: RawBoolType) -> Self {
|
||||
match value {
|
||||
RawBoolType::Union => BoolType::Union,
|
||||
RawBoolType::Difference => BoolType::Difference,
|
||||
RawBoolType::Intersection => BoolType::Intersection,
|
||||
RawBoolType::Exclusion => BoolType::Exclusion,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn set_shape_bool_type(raw_bool_type: u8) {
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
shape.set_bool_type(RawBoolType::from(raw_bool_type).into());
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn calculate_bool(raw_bool_type: u8) -> *mut u8 {
|
||||
let bytes = mem::bytes_or_empty();
|
||||
|
||||
let entries: IndexSet<Uuid> = bytes
|
||||
.chunks(size_of::<<Uuid as SerializableResult>::BytesType>())
|
||||
.map(|data| Uuid::from_bytes(data.try_into().unwrap()))
|
||||
.collect();
|
||||
|
||||
mem::free_bytes();
|
||||
|
||||
let bool_type = RawBoolType::from(raw_bool_type).into();
|
||||
let result;
|
||||
with_state!(state, {
|
||||
let path = math::bools::bool_from_shapes(
|
||||
bool_type,
|
||||
&entries,
|
||||
&state.shapes,
|
||||
&state.modifiers,
|
||||
&state.structure,
|
||||
);
|
||||
result = path
|
||||
.segments()
|
||||
.iter()
|
||||
.copied()
|
||||
.map(RawSegmentData::from_segment)
|
||||
.collect();
|
||||
});
|
||||
mem::write_vec(result)
|
||||
}
|
||||
53
render-wasm/src/wasm/shadows.rs
Normal file
53
render-wasm/src/wasm/shadows.rs
Normal file
@@ -0,0 +1,53 @@
|
||||
use macros::ToJs;
|
||||
use skia_safe as skia;
|
||||
|
||||
use crate::shapes::{Shadow, ShadowStyle};
|
||||
use crate::{with_current_shape_mut, STATE};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[allow(dead_code)]
|
||||
pub enum RawShadowStyle {
|
||||
Drop = 0,
|
||||
Inner = 1,
|
||||
}
|
||||
|
||||
impl From<u8> for RawShadowStyle {
|
||||
fn from(value: u8) -> Self {
|
||||
unsafe { std::mem::transmute(value) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RawShadowStyle> for ShadowStyle {
|
||||
fn from(value: RawShadowStyle) -> Self {
|
||||
match value {
|
||||
RawShadowStyle::Drop => Self::Drop,
|
||||
RawShadowStyle::Inner => Self::Inner,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn add_shape_shadow(
|
||||
raw_color: u32,
|
||||
blur: f32,
|
||||
spread: f32,
|
||||
x: f32,
|
||||
y: f32,
|
||||
raw_style: u8,
|
||||
hidden: bool,
|
||||
) {
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
let color = skia::Color::new(raw_color);
|
||||
let style = RawShadowStyle::from(raw_style).into();
|
||||
let shadow = Shadow::new(color, blur, spread, (x, y), style, hidden);
|
||||
shape.add_shadow(shadow);
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn clear_shape_shadows() {
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
shape.clear_shadows();
|
||||
});
|
||||
}
|
||||
47
render-wasm/src/wasm/shapes.rs
Normal file
47
render-wasm/src/wasm/shapes.rs
Normal file
@@ -0,0 +1,47 @@
|
||||
use macros::ToJs;
|
||||
|
||||
use crate::shapes::{Bool, Frame, Group, Path, Rect, SVGRaw, TextContent, Type};
|
||||
use crate::{with_current_shape_mut, STATE};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[allow(dead_code)]
|
||||
pub enum RawShapeType {
|
||||
Frame = 0,
|
||||
Group = 1,
|
||||
Bool = 2,
|
||||
Rect = 3,
|
||||
Path = 4,
|
||||
Text = 5,
|
||||
Circle = 6,
|
||||
SVGRaw = 7,
|
||||
}
|
||||
|
||||
impl From<u8> for RawShapeType {
|
||||
fn from(value: u8) -> Self {
|
||||
unsafe { std::mem::transmute(value) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RawShapeType> for Type {
|
||||
fn from(value: RawShapeType) -> Self {
|
||||
match value {
|
||||
RawShapeType::Frame => Type::Frame(Frame::default()),
|
||||
RawShapeType::Group => Type::Group(Group::default()),
|
||||
RawShapeType::Bool => Type::Bool(Bool::default()),
|
||||
RawShapeType::Rect => Type::Rect(Rect::default()),
|
||||
RawShapeType::Path => Type::Path(Path::default()),
|
||||
RawShapeType::Text => Type::Text(TextContent::default()),
|
||||
RawShapeType::Circle => Type::Circle,
|
||||
RawShapeType::SVGRaw => Type::SVGRaw(SVGRaw::default()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn set_shape_type(shape_type: u8) {
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
let shape_type = RawShapeType::from(shape_type);
|
||||
shape.set_shape_type(shape_type.into());
|
||||
});
|
||||
}
|
||||
@@ -1,31 +1,118 @@
|
||||
use macros::ToJs;
|
||||
|
||||
use crate::mem;
|
||||
use crate::shapes;
|
||||
use crate::shapes::{self, StrokeCap, StrokeStyle};
|
||||
use crate::with_current_shape_mut;
|
||||
use crate::STATE;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Copy, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[allow(dead_code)]
|
||||
pub enum RawStrokeStyle {
|
||||
Solid = 0,
|
||||
Dotted = 1,
|
||||
Dashed = 2,
|
||||
Mixed = 3,
|
||||
}
|
||||
|
||||
impl From<u8> for RawStrokeStyle {
|
||||
fn from(value: u8) -> Self {
|
||||
unsafe { std::mem::transmute(value) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RawStrokeStyle> for StrokeStyle {
|
||||
fn from(value: RawStrokeStyle) -> Self {
|
||||
match value {
|
||||
RawStrokeStyle::Solid => StrokeStyle::Solid,
|
||||
RawStrokeStyle::Dotted => StrokeStyle::Dotted,
|
||||
RawStrokeStyle::Dashed => StrokeStyle::Dashed,
|
||||
RawStrokeStyle::Mixed => StrokeStyle::Mixed,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[allow(dead_code)]
|
||||
pub enum RawStrokeCap {
|
||||
None = 0,
|
||||
LineArrow = 1,
|
||||
TriangleArrow = 2,
|
||||
SquareMarker = 3,
|
||||
CircleMarker = 4,
|
||||
DiamondMarker = 5,
|
||||
Round = 6,
|
||||
Square = 7,
|
||||
}
|
||||
|
||||
impl From<u8> for RawStrokeCap {
|
||||
fn from(value: u8) -> Self {
|
||||
unsafe { std::mem::transmute(value) }
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<RawStrokeCap> for StrokeCap {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(value: RawStrokeCap) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
RawStrokeCap::None => Err(()),
|
||||
RawStrokeCap::LineArrow => Ok(StrokeCap::LineArrow),
|
||||
RawStrokeCap::TriangleArrow => Ok(StrokeCap::TriangleArrow),
|
||||
RawStrokeCap::SquareMarker => Ok(StrokeCap::SquareMarker),
|
||||
RawStrokeCap::CircleMarker => Ok(StrokeCap::CircleMarker),
|
||||
RawStrokeCap::DiamondMarker => Ok(StrokeCap::DiamondMarker),
|
||||
RawStrokeCap::Round => Ok(StrokeCap::Round),
|
||||
RawStrokeCap::Square => Ok(StrokeCap::Square),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn add_shape_center_stroke(width: f32, style: u8, cap_start: u8, cap_end: u8) {
|
||||
let stroke_style = RawStrokeStyle::from(style);
|
||||
let cap_start = RawStrokeCap::from(cap_start);
|
||||
let cap_end = RawStrokeCap::from(cap_end);
|
||||
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
shape.add_stroke(shapes::Stroke::new_center_stroke(
|
||||
width, style, cap_start, cap_end,
|
||||
width,
|
||||
stroke_style.into(),
|
||||
cap_start.try_into().ok(),
|
||||
cap_end.try_into().ok(),
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn add_shape_inner_stroke(width: f32, style: u8, cap_start: u8, cap_end: u8) {
|
||||
let stroke_style = RawStrokeStyle::from(style);
|
||||
let cap_start = RawStrokeCap::from(cap_start);
|
||||
let cap_end = RawStrokeCap::from(cap_end);
|
||||
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
shape.add_stroke(shapes::Stroke::new_inner_stroke(
|
||||
width, style, cap_start, cap_end,
|
||||
width,
|
||||
stroke_style.into(),
|
||||
cap_start.try_into().ok(),
|
||||
cap_end.try_into().ok(),
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn add_shape_outer_stroke(width: f32, style: u8, cap_start: u8, cap_end: u8) {
|
||||
let stroke_style = RawStrokeStyle::from(style);
|
||||
let cap_start = RawStrokeCap::from(cap_start);
|
||||
let cap_end = RawStrokeCap::from(cap_end);
|
||||
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
shape.add_stroke(shapes::Stroke::new_outer_stroke(
|
||||
width, style, cap_start, cap_end,
|
||||
width,
|
||||
stroke_style.into(),
|
||||
cap_start.try_into().ok(),
|
||||
cap_end.try_into().ok(),
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use macros::ToJs;
|
||||
|
||||
use crate::mem;
|
||||
use crate::shapes::{GrowType, RawTextData, Type};
|
||||
use crate::textlayout::{
|
||||
@@ -5,6 +7,31 @@ use crate::textlayout::{
|
||||
};
|
||||
use crate::{with_current_shape, with_current_shape_mut, STATE};
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Copy, ToJs)]
|
||||
#[repr(u8)]
|
||||
#[allow(dead_code)]
|
||||
pub enum RawGrowType {
|
||||
Fixed = 0,
|
||||
AutoWidth = 1,
|
||||
AutoHeight = 2,
|
||||
}
|
||||
|
||||
impl From<u8> for RawGrowType {
|
||||
fn from(value: u8) -> Self {
|
||||
unsafe { std::mem::transmute(value) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RawGrowType> for GrowType {
|
||||
fn from(value: RawGrowType) -> Self {
|
||||
match value {
|
||||
RawGrowType::Fixed => GrowType::Fixed,
|
||||
RawGrowType::AutoWidth => GrowType::AutoWidth,
|
||||
RawGrowType::AutoHeight => GrowType::AutoHeight,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn clear_shape_text() {
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
@@ -26,9 +53,11 @@ pub extern "C" fn set_shape_text_content() {
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn set_shape_grow_type(grow_type: u8) {
|
||||
let grow_type = RawGrowType::from(grow_type);
|
||||
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
if let Type::Text(text_content) = &mut shape.shape_type {
|
||||
text_content.set_grow_type(GrowType::from(grow_type));
|
||||
text_content.set_grow_type(grow_type.into());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user