From 568af52ebcc85d9dd287c56b5c0208a22f815f4a Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Tue, 6 May 2025 17:23:46 +0200 Subject: [PATCH] :sparkles: Text grow width/height --- .../src/app/main/data/workspace/texts.cljs | 188 +++++++++++++----- .../app/main/data/workspace/transforms.cljs | 28 +++ .../shapes/text/text_edition_outline.cljs | 59 ++++-- .../ui/workspace/shapes/text/v2_editor.cljs | 9 +- .../workspace/sidebar/options/menus/text.cljs | 4 + .../app/main/ui/workspace/viewport_wasm.cljs | 8 +- frontend/src/app/render_wasm/api.cljs | 22 +- frontend/src/app/render_wasm/serializers.cljs | 7 + frontend/src/app/render_wasm/shape.cljs | 3 + render-wasm/src/render.rs | 1 + render-wasm/src/shapes.rs | 6 +- render-wasm/src/shapes/text.rs | 102 +++++++--- render-wasm/src/wasm/text.rs | 50 ++++- 13 files changed, 381 insertions(+), 106 deletions(-) diff --git a/frontend/src/app/main/data/workspace/texts.cljs b/frontend/src/app/main/data/workspace/texts.cljs index 829239531..d90a4472a 100644 --- a/frontend/src/app/main/data/workspace/texts.cljs +++ b/frontend/src/app/main/data/workspace/texts.cljs @@ -11,6 +11,7 @@ [app.common.data :as d] [app.common.data.macros :as dm] [app.common.files.helpers :as cfh] + [app.common.geom.matrix :as gmt] [app.common.geom.point :as gpt] [app.common.geom.shapes :as gsh] [app.common.math :as mth] @@ -28,6 +29,7 @@ [app.main.features :as features] [app.main.fonts :as fonts] [app.main.router :as rt] + [app.render-wasm.api :as wasm.api] [app.util.text-editor :as ted] [app.util.text.content.styles :as styles] [app.util.timers :as ts] @@ -47,6 +49,45 @@ (declare v2-update-text-shape-content) (declare v2-update-text-editor-styles) +(defn resize-wasm-text-modifiers + ([shape] + (resize-wasm-text-modifiers shape (:content shape))) + + ([{:keys [id points selrect] :as shape} content] + (wasm.api/use-shape id) + (wasm.api/set-shape-text-content content) + (let [dimension (wasm.api/text-dimensions) + resize-v + (gpt/point + (/ (:width dimension) (-> selrect :width)) + (/ (:height dimension) (-> selrect :height))) + + origin (first points)] + {id + {:modifiers + (ctm/resize-modifiers + resize-v + origin + (:transform shape (gmt/matrix)) + (:transform-inverse shape (gmt/matrix)))}}))) + +(defn resize-wasm-text + [id] + (ptk/reify ::resize-wasm-text + ptk/WatchEvent + (watch [_ state _] + (let [objects (dsh/lookup-page-objects state) + shape (get objects id)] + (rx/of (dwm/apply-wasm-modifiers (resize-wasm-text-modifiers shape))))))) + +(defn resize-wasm-text-all + [ids] + (ptk/reify ::resize-wasm-text-all + ptk/WatchEvent + (watch [_ _ _] + (->> (rx/from ids) + (rx/map resize-wasm-text))))) + ;; -- Editor (defn update-editor @@ -98,28 +139,50 @@ new-shape? (nil? (:content shape))] (if (ted/content-has-text? content) - (let [content (d/merge (ted/export-content content) - (dissoc (:content shape) :children)) - modifiers (get-in state [:workspace-text-modifier id])] - (rx/merge - (rx/of (update-editor-state shape nil)) - (when (and (not= content (:content shape)) - (some? (:current-page-id state)) - (some? shape)) - (rx/of - (dwsh/update-shapes - [id] - (fn [shape] - (let [{:keys [width height position-data]} modifiers] + (if (features/active-feature? state "render-wasm/v1") + (let [content (d/merge (ted/export-content content) + (dissoc (:content shape) :children))] + (rx/merge + (rx/of (update-editor-state shape nil)) + (when (and (not= content (:content shape)) + (some? (:current-page-id state)) + (some? shape)) + (rx/of + (dwsh/update-shapes + [id] + (fn [shape] (-> shape (assoc :content content) - (cond-> position-data - (assoc :position-data position-data)) (cond-> (and update-name? (some? name)) - (assoc :name name)) - (cond-> (or (some? width) (some? height)) - (gsh/transform-shape (ctm/change-size shape width height)))))) - {:undo-group (when new-shape? id)}))))) + (assoc :name name)))) + {:undo-group (when new-shape? id)}) + + (dwm/apply-wasm-modifiers + (resize-wasm-text-modifiers shape content) + {:undo-group (when new-shape? id)}))))) + + (let [content (d/merge (ted/export-content content) + (dissoc (:content shape) :children)) + modifiers (get-in state [:workspace-text-modifier id])] + (rx/merge + (rx/of (update-editor-state shape nil)) + (when (and (not= content (:content shape)) + (some? (:current-page-id state)) + (some? shape)) + (rx/of + (dwsh/update-shapes + [id] + (fn [shape] + (let [{:keys [width height position-data]} modifiers] + (-> shape + (assoc :content content) + (cond-> position-data + (assoc :position-data position-data)) + (cond-> (and update-name? (some? name)) + (assoc :name name)) + (cond-> (or (some? width) (some? height)) + (gsh/transform-shape (ctm/change-size shape width height)))))) + {:undo-group (when new-shape? id)})))))) (when (some? id) (rx/of (dws/deselect-shape id) @@ -733,7 +796,14 @@ (rx/empty))) (when (features/active-feature? state "text-editor/v2") - (rx/of (v2-update-text-editor-styles id attrs))))))) + (rx/of (v2-update-text-editor-styles id attrs))) + + (when (features/active-feature? state "render-wasm/v1") + ;; This delay is to give time for the font to be correctly rendered + ;; in wasm. + (cond->> (rx/of (resize-wasm-text id)) + (contains? attrs :font-id) + (rx/delay 200))))))) ptk/EffectEvent (effect [_ state _] @@ -852,34 +922,54 @@ (ptk/reify ::v2-update-text-shape-position-data ptk/UpdateEvent (update [_ state] - (let [] - (update-in state [:workspace-text-modifier shape-id] {:position-data position-data}))))) + (update-in state [:workspace-text-modifier shape-id] {:position-data position-data})))) (defn v2-update-text-shape-content - ([id content] - (v2-update-text-shape-content id content false nil)) - ([id content update-name?] - (v2-update-text-shape-content id content update-name? nil)) - ([id content update-name? name] - (ptk/reify ::v2-update-text-shape-content - ptk/WatchEvent - (watch [_ state _] - (let [objects (dsh/lookup-page-objects state) - shape (get objects id) - modifiers (get-in state [:workspace-text-modifier id]) - new-shape? (nil? (:content shape))] - (rx/of - (dwsh/update-shapes - [id] - (fn [shape] - (let [{:keys [width height position-data]} modifiers] - (let [new-shape (-> shape - (assoc :content content) - (cond-> position-data - (assoc :position-data position-data)) - (cond-> (and update-name? (some? name)) - (assoc :name name)) - (cond-> (or (some? width) (some? height)) - (gsh/transform-shape (ctm/change-size shape width height))))] - new-shape))) - {:undo-group (when new-shape? id)}))))))) + [id content & {:keys [update-name? name finalize?] + :or {update-name? false name nil finalize? false}}] + (ptk/reify ::v2-update-text-shape-content + ptk/WatchEvent + (watch [_ state _] + (if (features/active-feature? state "render-wasm/v1") + (let [objects (dsh/lookup-page-objects state) + shape (get objects id) + new-shape? (nil? (:content shape))] + (rx/of + (dwsh/update-shapes + [id] + (fn [shape] + (let [new-shape (-> shape + (assoc :content content) + (cond-> (and update-name? (some? name)) + (assoc :name name)))] + new-shape)) + {:undo-group (when new-shape? id)}) + + (if finalize? + (dwm/apply-wasm-modifiers + (resize-wasm-text-modifiers shape content) + {:undo-group (when new-shape? id)}) + + (dwm/set-wasm-modifiers + (resize-wasm-text-modifiers shape content) + {:undo-group (when new-shape? id)})))) + + (let [objects (dsh/lookup-page-objects state) + shape (get objects id) + modifiers (get-in state [:workspace-text-modifier id]) + new-shape? (nil? (:content shape))] + (rx/of + (dwsh/update-shapes + [id] + (fn [shape] + (let [{:keys [width height position-data]} modifiers] + (let [new-shape (-> shape + (assoc :content content) + (cond-> position-data + (assoc :position-data position-data)) + (cond-> (and update-name? (some? name)) + (assoc :name name)) + (cond-> (or (some? width) (some? height)) + (gsh/transform-shape (ctm/change-size shape width height))))] + new-shape))) + {:undo-group (when new-shape? id)}))))))) diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index 1e50a0dc3..5121d978a 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -1169,3 +1169,31 @@ (if (features/active-feature? state "render-wasm/v1") (rx/of (dwm/apply-wasm-modifiers modifiers {:undo-group undo-group})) (rx/of (dwm/apply-modifiers {:modifiers modifiers :undo-group undo-group}))))))) + +(defn resize-text-editor + [id {:keys [width height]}] + (ptk/reify ::resize-text-editor + ptk/WatchEvent + (watch [_ state _] + (let [objects (dsh/lookup-page-objects state) + shape (get objects id) + + resize-v + (gpt/point + (/ width (-> shape :selrect :width)) + (/ height (-> shape :selrect :height))) + + origin + (first (:points shape)) + + modifiers + {id + {:modifiers + (ctm/resize-modifiers + resize-v + origin + (:transform shape (gmt/matrix)) + (:transform-inverse shape (gmt/matrix)))}}] + + (.log js/console (clj->js modifiers)) + (rx/of (dwm/set-wasm-modifiers modifiers)))))) diff --git a/frontend/src/app/main/ui/workspace/shapes/text/text_edition_outline.cljs b/frontend/src/app/main/ui/workspace/shapes/text/text_edition_outline.cljs index 8a0082f1e..b76044b44 100644 --- a/frontend/src/app/main/ui/workspace/shapes/text/text_edition_outline.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/text/text_edition_outline.cljs @@ -8,35 +8,52 @@ (:require [app.common.geom.shapes :as gsh] [app.main.data.workspace.texts :as dwt] + [app.main.features :as features] [app.main.refs :as refs] + [app.main.store :as st] + [app.render-wasm.api :as wasm.api] [rumext.v2 :as mf])) (mf/defc text-edition-outline [{:keys [shape zoom modifiers]}] - (let [modifiers (get-in modifiers [(:id shape) :modifiers]) + (if (features/active-feature? @st/state "render-wasm/v1") + (let [transform (gsh/transform-str shape) + {:keys [id x y]} shape + {:keys [width height]} (wasm.api/text-dimensions id)] + [:rect.main.viewport-selrect + {:x x + :y y + :width width + :height height + :transform transform + :style {:stroke "var(--color-accent-tertiary)" + :stroke-width (/ 1 zoom) + :fill "none"}}]) - text-modifier-ref - (mf/use-memo (mf/deps (:id shape)) #(refs/workspace-text-modifier-by-id (:id shape))) + (let [modifiers (get-in modifiers [(:id shape) :modifiers]) - text-modifier - (mf/deref text-modifier-ref) + text-modifier-ref + (mf/use-memo (mf/deps (:id shape)) #(refs/workspace-text-modifier-by-id (:id shape))) - shape (cond-> shape - (some? modifiers) - (gsh/transform-shape modifiers) + text-modifier + (mf/deref text-modifier-ref) - (some? text-modifier) - (dwt/apply-text-modifier text-modifier)) + shape (cond-> shape + (some? modifiers) + (gsh/transform-shape modifiers) - transform (gsh/transform-str shape) - {:keys [x y width height]} shape] + (some? text-modifier) + (dwt/apply-text-modifier text-modifier)) - [:rect.main.viewport-selrect - {:x x - :y y - :width width - :height height - :transform transform - :style {:stroke "var(--color-accent-tertiary)" - :stroke-width (/ 1 zoom) - :fill "none"}}])) + transform (gsh/transform-str shape) + {:keys [x y width height]} shape] + + [:rect.main.viewport-selrect + {:x x + :y y + :width width + :height height + :transform transform + :style {:stroke "var(--color-accent-tertiary)" + :stroke-width (/ 1 zoom) + :fill "none"}}]))) diff --git a/frontend/src/app/main/ui/workspace/shapes/text/v2_editor.cljs b/frontend/src/app/main/ui/workspace/shapes/text/v2_editor.cljs index 62f773d1d..20ce73b3a 100644 --- a/frontend/src/app/main/ui/workspace/shapes/text/v2_editor.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/text/v2_editor.cljs @@ -69,7 +69,10 @@ on-blur (fn [] (when-let [content (content/dom->cljs (dwt/get-editor-root instance))] - (st/emit! (dwt/v2-update-text-shape-content shape-id content update-name? (gen-name instance)))) + (st/emit! (dwt/v2-update-text-shape-content shape-id content + :update-name? update-name? + :name (gen-name instance) + :finalize? true))) (let [container-node (mf/ref-val container-ref)] (dom/set-style! container-node "opacity" 0))) @@ -87,7 +90,7 @@ on-needs-layout (fn [] (when-let [content (content/dom->cljs (dwt/get-editor-root instance))] - (st/emit! (dwt/v2-update-text-shape-content shape-id content true))) + (st/emit! (dwt/v2-update-text-shape-content shape-id content :update-name? true))) ;; FIXME: We need to find a better way to trigger layout changes. #_(st/emit! (dwt/v2-update-text-shape-position-data shape-id []))) @@ -95,7 +98,7 @@ on-change (fn [] (when-let [content (content/dom->cljs (dwt/get-editor-root instance))] - (st/emit! (dwt/v2-update-text-shape-content shape-id content true))))] + (st/emit! (dwt/v2-update-text-shape-content shape-id content :update-name? true))))] (.addEventListener ^js global/document "keyup" on-key-up) (.addEventListener ^js instance "blur" on-blur) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/text.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/text.cljs index 74e645737..d5c36f08d 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/text.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/text.cljs @@ -15,6 +15,7 @@ [app.main.data.workspace.shortcuts :as sc] [app.main.data.workspace.texts :as dwt] [app.main.data.workspace.undo :as dwu] + [app.main.features :as features] [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.components.radio-buttons :refer [radio-button radio-buttons]] @@ -130,6 +131,9 @@ (st/emit! (dwu/start-undo-transaction uid) (dwsh/update-shapes ids #(assoc % :grow-type grow-type))) + + (when (features/active-feature? @st/state "render-wasm/v1") + (st/emit! (dwt/resize-wasm-text-all ids))) ;; We asynchronously commit so every sychronous event is resolved first and inside the transaction (ts/schedule #(st/emit! (dwu/commit-undo-transaction uid)))) (when (some? on-blur) (on-blur))))] diff --git a/frontend/src/app/main/ui/workspace/viewport_wasm.cljs b/frontend/src/app/main/ui/workspace/viewport_wasm.cljs index 0a1a84cb7..002dfcc16 100644 --- a/frontend/src/app/main/ui/workspace/viewport_wasm.cljs +++ b/frontend/src/app/main/ui/workspace/viewport_wasm.cljs @@ -16,6 +16,7 @@ [app.common.types.shape-tree :as ctt] [app.common.types.shape.layout :as ctl] [app.main.data.workspace.modifiers :as dwm] + [app.main.data.workspace.transforms :as dwt] [app.main.features :as features] [app.main.refs :as refs] [app.main.store :as st] @@ -305,9 +306,12 @@ (let [content (-> active-editor-state (ted/get-editor-current-content) (ted/export-content))] + (wasm.api/use-shape edition) (wasm.api/set-shape-text-content content) - (wasm.api/clear-drawing-cache) - (wasm.api/request-render "content"))))) + (let [dimension (wasm.api/text-dimensions)] + (st/emit! (dwt/resize-text-editor edition dimension)) + (wasm.api/clear-drawing-cache) + (wasm.api/request-render "content")))))) (mf/with-effect [vport] (when @canvas-init? diff --git a/frontend/src/app/render_wasm/api.cljs b/frontend/src/app/render_wasm/api.cljs index 62139a7e6..9a53c3637 100644 --- a/frontend/src/app/render_wasm/api.cljs +++ b/frontend/src/app/render_wasm/api.cljs @@ -582,6 +582,8 @@ (h/call wasm/internal-module "_add_shape_shadow" rgba blur spread x y (sr/translate-shadow-style style) hidden) (recur (inc index))))))) +(declare propagate-apply) + (defn set-shape-text-content [content] (h/call wasm/internal-module "_clear_shape_text") @@ -604,6 +606,22 @@ fonts)] (f/store-fonts fonts)))) +(defn set-shape-grow-type + [grow-type] + (h/call wasm/internal-module "_set_shape_grow_type" (sr/translate-grow-type grow-type))) + +(defn text-dimensions + ([id] + (use-shape id) + (text-dimensions)) + ([] + (let [offset (h/call wasm/internal-module "_get_text_dimensions") + heapf32 (mem/get-heap-f32) + width (aget heapf32 (mem/ptr8->ptr32 offset)) + height (aget heapf32 (mem/ptr8->ptr32 (+ offset 4)))] + (h/call wasm/internal-module "_free_bytes") + {:width width :height height}))) + (defn set-view-box [zoom vbox] (h/call wasm/internal-module "_set_view" zoom (- (:x vbox)) (- (:y vbox))) @@ -639,6 +657,7 @@ opacity (dm/get-prop shape :opacity) hidden (dm/get-prop shape :hidden) content (dm/get-prop shape :content) + grow-type (dm/get-prop shape :grow-type) blur (dm/get-prop shape :blur) corners (when (some? (dm/get-prop shape :r1)) [(dm/get-prop shape :r1) @@ -677,7 +696,8 @@ (when (some? shadows) (set-shape-shadows shadows)) (when (and (= type :text) (some? content)) (set-shape-text-content content)) - + (when (= type :text) + (set-shape-grow-type grow-type)) (when (or (ctl/any-layout? shape) (ctl/any-layout-immediate-child? objects shape)) (set-layout-child shape)) diff --git a/frontend/src/app/render_wasm/serializers.cljs b/frontend/src/app/render_wasm/serializers.cljs index c9d59a650..a7989c81b 100644 --- a/frontend/src/app/render_wasm/serializers.cljs +++ b/frontend/src/app/render_wasm/serializers.cljs @@ -283,6 +283,13 @@ :remove-children 1 :add-children 2)) +(defn translate-grow-type + [grow-type] + (case grow-type + :auto-width 1 + :auto-height 2 + 0)) + (defn- serialize-enum [value enum-map] (get enum-map value 0)) diff --git a/frontend/src/app/render_wasm/shape.cljs b/frontend/src/app/render_wasm/shape.cljs index 6f80a6598..02525afc9 100644 --- a/frontend/src/app/render_wasm/shape.cljs +++ b/frontend/src/app/render_wasm/shape.cljs @@ -152,6 +152,9 @@ (= (:type shape) :text) (into [] (api/set-shape-text-content v))) + :grow-type + (api/set-shape-grow-type v) + (:layout-item-margin :layout-item-margin-type :layout-item-h-sizing diff --git a/render-wasm/src/render.rs b/render-wasm/src/render.rs index aaf825d35..b445ab465 100644 --- a/render-wasm/src/render.rs +++ b/render-wasm/src/render.rs @@ -356,6 +356,7 @@ impl RenderState { s.canvas().concat(&matrix); }); + let text_content = text_content.new_bounds(shape.selrect()); let paragraphs = text_content.get_skia_paragraphs(&self.fonts.font_collection()); shadows::render_text_drop_shadows(self, &shape, ¶graphs, antialias); diff --git a/render-wasm/src/shapes.rs b/render-wasm/src/shapes.rs index afbd3177c..69e97c075 100644 --- a/render-wasm/src/shapes.rs +++ b/render-wasm/src/shapes.rs @@ -711,9 +711,9 @@ impl Shape { } pub fn clear_text(&mut self) { - match self.shape_type { - Type::Text(_) => { - let new_text_content = TextContent::new(self.selrect); + match &self.shape_type { + Type::Text(old_text_content) => { + let new_text_content = TextContent::new(self.selrect, old_text_content.grow_type()); self.shape_type = Type::Text(new_text_content); } _ => {} diff --git a/render-wasm/src/shapes/text.rs b/render-wasm/src/shapes/text.rs index 6ae677a93..d3455619a 100644 --- a/render-wasm/src/shapes/text.rs +++ b/render-wasm/src/shapes/text.rs @@ -12,19 +12,57 @@ use super::FontFamily; use crate::utils::uuid_from_u32; use crate::Uuid; +#[derive(Debug, PartialEq, Clone, Copy)] +pub enum GrowType { + Fixed, + AutoWidth, + AutoHeight, +} + +impl GrowType { + pub fn from(grow_type: u8) -> Self { + match grow_type { + 0 => Self::Fixed, + 1 => Self::AutoWidth, + 2 => Self::AutoHeight, + _ => unreachable!(), + } + } +} + #[derive(Debug, PartialEq, Clone)] pub struct TextContent { paragraphs: Vec, bounds: Rect, + grow_type: GrowType, +} + +pub fn set_paragraphs_width(width: f32, paragraphs: &mut Vec>) { + for group in paragraphs { + for paragraph in group { + paragraph.layout(width) + } + } } impl TextContent { - pub fn new(bounds: Rect) -> Self { + pub fn new(bounds: Rect, grow_type: GrowType) -> Self { let mut res = Self::default(); res.bounds = bounds; + res.grow_type = grow_type; res } + pub fn new_bounds(&self, bounds: Rect) -> Self { + let paragraphs = self.paragraphs.clone(); + let grow_type = self.grow_type; + Self { + paragraphs, + bounds, + grow_type, + } + } + pub fn set_xywh(&mut self, x: f32, y: f32, w: f32, h: f32) { self.bounds = Rect::from_xywh(x, y, w, h); } @@ -97,22 +135,25 @@ impl TextContent { paragraph_group } + pub fn collect_paragraphs( + &self, + mut paragraphs: Vec>, + ) -> Vec> { + if self.grow_type() == GrowType::AutoWidth { + set_paragraphs_width(f32::MAX, &mut paragraphs); + let max_width = auto_width(¶graphs).ceil(); + set_paragraphs_width(max_width, &mut paragraphs); + } else { + set_paragraphs_width(self.width(), &mut paragraphs); + } + paragraphs + } + pub fn get_skia_paragraphs( &self, fonts: &FontCollection, ) -> Vec> { - self.to_paragraphs(fonts) - .into_iter() - .map(|group| { - group - .into_iter() - .map(|mut paragraph| { - paragraph.layout(self.width()); - paragraph - }) - .collect() - }) - .collect() + self.collect_paragraphs(self.to_paragraphs(fonts)) } pub fn get_skia_stroke_paragraphs( @@ -120,18 +161,15 @@ impl TextContent { fonts: &FontCollection, paints: &Vec, ) -> Vec> { - self.to_stroke_paragraphs(fonts, paints) - .into_iter() - .map(|group| { - group - .into_iter() - .map(|mut paragraph| { - paragraph.layout(self.width()); - paragraph - }) - .collect() - }) - .collect() + self.collect_paragraphs(self.to_stroke_paragraphs(fonts, paints)) + } + + pub fn grow_type(&self) -> GrowType { + self.grow_type + } + + pub fn set_grow_type(&mut self, grow_type: GrowType) { + self.grow_type = grow_type; } } @@ -140,6 +178,7 @@ impl Default for TextContent { Self { paragraphs: vec![], bounds: Rect::default(), + grow_type: GrowType::Fixed, } } } @@ -495,3 +534,16 @@ impl From<&Vec> for RawTextData { Self { paragraph } } } + +pub fn auto_width(paragraphs: &Vec>) -> f32 { + paragraphs.iter().flatten().fold(0.0, |auto_width, p| { + f32::max(p.max_intrinsic_width(), auto_width) + }) +} + +pub fn auto_height(paragraphs: &Vec>) -> f32 { + paragraphs + .iter() + .flatten() + .fold(0.0, |auto_height, p| auto_height + p.height()) +} diff --git a/render-wasm/src/wasm/text.rs b/render-wasm/src/wasm/text.rs index 1fb3fd401..21c3befcd 100644 --- a/render-wasm/src/wasm/text.rs +++ b/render-wasm/src/wasm/text.rs @@ -1,7 +1,8 @@ use crate::mem; -use crate::shapes::RawTextData; -use crate::with_current_shape; +use crate::shapes::{auto_height, auto_width, GrowType, RawTextData, Type}; + use crate::STATE; +use crate::{with_current_shape, with_state}; #[no_mangle] pub extern "C" fn clear_shape_text() { @@ -22,3 +23,48 @@ pub extern "C" fn set_shape_text_content() { mem::free_bytes(); } + +#[no_mangle] +pub extern "C" fn set_shape_grow_type(grow_type: u8) { + with_current_shape!(state, |shape: &mut Shape| { + if let Type::Text(text_content) = &mut shape.shape_type { + text_content.set_grow_type(GrowType::from(grow_type)); + } + }); +} + +#[no_mangle] +pub extern "C" fn get_text_dimensions() -> *mut u8 { + let font_col; + with_state!(state, { + font_col = state.render_state.fonts.font_collection(); + }); + + let mut width = 0.01; + let mut height = 0.01; + with_current_shape!(state, |shape: &mut Shape| { + width = shape.selrect.width(); + height = shape.selrect.height(); + + if let Type::Text(content) = &shape.shape_type { + match content.grow_type() { + GrowType::AutoWidth => { + let paragraphs = content.get_skia_paragraphs(font_col); + width = auto_width(¶graphs); + height = auto_height(¶graphs); + } + GrowType::AutoHeight => { + let paragraphs = content.get_skia_paragraphs(font_col); + height = auto_height(¶graphs); + } + _ => {} + } + } + }); + + let mut bytes = Vec::::with_capacity(8); + bytes.resize(8, 0); + bytes[0..4].clone_from_slice(&width.to_le_bytes()); + bytes[4..8].clone_from_slice(&height.to_le_bytes()); + mem::write_bytes(bytes) +}