mirror of
https://github.com/penpot/penpot.git
synced 2025-07-13 20:57:16 +02:00
🐛 Fix asynchronous content rendering
This commit is contained in:
parent
d0425cabda
commit
d71fa659d5
12 changed files with 166 additions and 100 deletions
|
@ -57,7 +57,7 @@
|
||||||
|
|
||||||
([{:keys [id points selrect] :as shape} content]
|
([{:keys [id points selrect] :as shape} content]
|
||||||
(wasm.api/use-shape id)
|
(wasm.api/use-shape id)
|
||||||
(wasm.api/set-shape-text content)
|
(wasm.api/set-shape-text id content)
|
||||||
(let [dimension (wasm.api/text-dimensions)
|
(let [dimension (wasm.api/text-dimensions)
|
||||||
resize-v
|
resize-v
|
||||||
(gpt/point
|
(gpt/point
|
||||||
|
|
|
@ -301,7 +301,7 @@
|
||||||
(ted/get-editor-current-content)
|
(ted/get-editor-current-content)
|
||||||
(ted/export-content))]
|
(ted/export-content))]
|
||||||
(wasm.api/use-shape edition)
|
(wasm.api/use-shape edition)
|
||||||
(wasm.api/set-shape-text-content content)
|
(wasm.api/set-shape-text-content edition content)
|
||||||
(let [dimension (wasm.api/text-dimensions)]
|
(let [dimension (wasm.api/text-dimensions)]
|
||||||
(st/emit! (dwt/resize-text-editor edition dimension))
|
(st/emit! (dwt/resize-text-editor edition dimension))
|
||||||
(wasm.api/clear-drawing-cache)
|
(wasm.api/clear-drawing-cache)
|
||||||
|
|
|
@ -190,9 +190,10 @@
|
||||||
(defn- get-string-length [string] (+ (count string) 1))
|
(defn- get-string-length [string] (+ (count string) 1))
|
||||||
|
|
||||||
(defn- fetch-image
|
(defn- fetch-image
|
||||||
[id]
|
[shape-id image-id]
|
||||||
(let [buffer (uuid/get-u32 id)
|
(let [buffer-shape-id (uuid/get-u32 shape-id)
|
||||||
url (cf/resolve-file-media {:id id})]
|
buffer-image-id (uuid/get-u32 image-id)
|
||||||
|
url (cf/resolve-file-media {:id image-id})]
|
||||||
{:key url
|
{:key url
|
||||||
:callback #(->> (http/send! {:method :get
|
:callback #(->> (http/send! {:method :get
|
||||||
:uri url
|
:uri url
|
||||||
|
@ -206,10 +207,14 @@
|
||||||
data (js/Uint8Array. image)]
|
data (js/Uint8Array. image)]
|
||||||
(.set heap data offset)
|
(.set heap data offset)
|
||||||
(h/call wasm/internal-module "_store_image"
|
(h/call wasm/internal-module "_store_image"
|
||||||
(aget buffer 0)
|
(aget buffer-shape-id 0)
|
||||||
(aget buffer 1)
|
(aget buffer-shape-id 1)
|
||||||
(aget buffer 2)
|
(aget buffer-shape-id 2)
|
||||||
(aget buffer 3))
|
(aget buffer-shape-id 3)
|
||||||
|
(aget buffer-image-id 0)
|
||||||
|
(aget buffer-image-id 1)
|
||||||
|
(aget buffer-image-id 2)
|
||||||
|
(aget buffer-image-id 3))
|
||||||
true))))}))
|
true))))}))
|
||||||
|
|
||||||
(defn- get-fill-images
|
(defn- get-fill-images
|
||||||
|
@ -217,7 +222,7 @@
|
||||||
(filter :fill-image (:fills leaf)))
|
(filter :fill-image (:fills leaf)))
|
||||||
|
|
||||||
(defn- process-fill-image
|
(defn- process-fill-image
|
||||||
[fill]
|
[shape-id fill]
|
||||||
(rx/from
|
(rx/from
|
||||||
(when-let [image (:fill-image fill)]
|
(when-let [image (:fill-image fill)]
|
||||||
(let [id (dm/get-prop image :id)
|
(let [id (dm/get-prop image :id)
|
||||||
|
@ -228,19 +233,19 @@
|
||||||
(aget buffer 2)
|
(aget buffer 2)
|
||||||
(aget buffer 3))]
|
(aget buffer 3))]
|
||||||
(when (zero? cached-image?)
|
(when (zero? cached-image?)
|
||||||
(fetch-image id))))))
|
(fetch-image shape-id id))))))
|
||||||
|
|
||||||
(defn set-shape-text-images
|
(defn set-shape-text-images
|
||||||
[content]
|
[shape-id content]
|
||||||
(let [paragraph-set (first (get content :children))
|
(let [paragraph-set (first (get content :children))
|
||||||
paragraphs (get paragraph-set :children)]
|
paragraphs (get paragraph-set :children)]
|
||||||
(->> paragraphs
|
(->> paragraphs
|
||||||
(mapcat :children)
|
(mapcat :children)
|
||||||
(mapcat get-fill-images)
|
(mapcat get-fill-images)
|
||||||
(map process-fill-image))))
|
(map #(process-fill-image shape-id %)))))
|
||||||
|
|
||||||
(defn set-shape-fills
|
(defn set-shape-fills
|
||||||
[fills]
|
[shape-id fills]
|
||||||
(when (not-empty? fills)
|
(when (not-empty? fills)
|
||||||
(let [fills (take types.fill/MAX-FILLS fills)
|
(let [fills (take types.fill/MAX-FILLS fills)
|
||||||
image-fills (filter :fill-image fills)
|
image-fills (filter :fill-image fills)
|
||||||
|
@ -270,11 +275,11 @@
|
||||||
(aget buffer 2)
|
(aget buffer 2)
|
||||||
(aget buffer 3))]
|
(aget buffer 3))]
|
||||||
(when (zero? cached-image?)
|
(when (zero? cached-image?)
|
||||||
(fetch-image id))))
|
(fetch-image shape-id id))))
|
||||||
image-fills))))
|
image-fills))))
|
||||||
|
|
||||||
(defn set-shape-strokes
|
(defn set-shape-strokes
|
||||||
[strokes]
|
[shape-id strokes]
|
||||||
(h/call wasm/internal-module "_clear_shape_strokes")
|
(h/call wasm/internal-module "_clear_shape_strokes")
|
||||||
(keep (fn [stroke]
|
(keep (fn [stroke]
|
||||||
(let [opacity (or (:stroke-opacity stroke) 1.0)
|
(let [opacity (or (:stroke-opacity stroke) 1.0)
|
||||||
|
@ -301,15 +306,15 @@
|
||||||
(h/call wasm/internal-module "_add_shape_stroke_fill"))
|
(h/call wasm/internal-module "_add_shape_stroke_fill"))
|
||||||
|
|
||||||
(some? image)
|
(some? image)
|
||||||
(let [id (dm/get-prop image :id)
|
(let [image-id (dm/get-prop image :id)
|
||||||
buffer (uuid/get-u32 id)
|
buffer (uuid/get-u32 image-id)
|
||||||
cached-image? (h/call wasm/internal-module "_is_image_cached" (aget buffer 0) (aget buffer 1) (aget buffer 2) (aget buffer 3))]
|
cached-image? (h/call wasm/internal-module "_is_image_cached" (aget buffer 0) (aget buffer 1) (aget buffer 2) (aget buffer 3))]
|
||||||
(sr-fills/write-image-fill! offset dview id opacity
|
(sr-fills/write-image-fill! offset dview image-id opacity
|
||||||
(dm/get-prop image :width)
|
(dm/get-prop image :width)
|
||||||
(dm/get-prop image :height))
|
(dm/get-prop image :height))
|
||||||
(h/call wasm/internal-module "_add_shape_stroke_fill")
|
(h/call wasm/internal-module "_add_shape_stroke_fill")
|
||||||
(when (== cached-image? 0)
|
(when (== cached-image? 0)
|
||||||
(fetch-image id)))
|
(fetch-image shape-id image-id)))
|
||||||
|
|
||||||
(some? color)
|
(some? color)
|
||||||
(do
|
(do
|
||||||
|
@ -623,7 +628,7 @@
|
||||||
(declare propagate-apply)
|
(declare propagate-apply)
|
||||||
|
|
||||||
(defn set-shape-text-content
|
(defn set-shape-text-content
|
||||||
[content]
|
[shape-id content]
|
||||||
(h/call wasm/internal-module "_clear_shape_text")
|
(h/call wasm/internal-module "_clear_shape_text")
|
||||||
(let [paragraph-set (first (dm/get-prop content :children))
|
(let [paragraph-set (first (dm/get-prop content :children))
|
||||||
paragraphs (dm/get-prop paragraph-set :children)
|
paragraphs (dm/get-prop paragraph-set :children)
|
||||||
|
@ -646,13 +651,13 @@
|
||||||
(-> fonts
|
(-> fonts
|
||||||
(cond-> @emoji? (f/add-emoji-font))
|
(cond-> @emoji? (f/add-emoji-font))
|
||||||
(f/add-noto-fonts @languages))]
|
(f/add-noto-fonts @languages))]
|
||||||
(f/store-fonts updated-fonts))))
|
(f/store-fonts shape-id updated-fonts))))
|
||||||
|
|
||||||
(defn set-shape-text
|
(defn set-shape-text
|
||||||
[content]
|
[shape-id content]
|
||||||
(concat
|
(concat
|
||||||
(set-shape-text-images content)
|
(set-shape-text-images shape-id content)
|
||||||
(set-shape-text-content content)))
|
(set-shape-text-content shape-id content)))
|
||||||
|
|
||||||
(defn set-shape-grow-type
|
(defn set-shape-grow-type
|
||||||
[grow-type]
|
[grow-type]
|
||||||
|
@ -759,9 +764,9 @@
|
||||||
(set-grid-layout shape))
|
(set-grid-layout shape))
|
||||||
|
|
||||||
(let [pending (into [] (concat
|
(let [pending (into [] (concat
|
||||||
(set-shape-text content)
|
(set-shape-text id content)
|
||||||
(set-shape-fills fills)
|
(set-shape-fills id fills)
|
||||||
(set-shape-strokes strokes)))]
|
(set-shape-strokes id strokes)))]
|
||||||
(perf/end-measure "set-object")
|
(perf/end-measure "set-object")
|
||||||
pending)))
|
pending)))
|
||||||
|
|
||||||
|
@ -772,11 +777,10 @@
|
||||||
pending (-> (d/index-by :key :callback pending) vals)]
|
pending (-> (d/index-by :key :callback pending) vals)]
|
||||||
(if (not-empty? pending)
|
(if (not-empty? pending)
|
||||||
(->> (rx/from pending)
|
(->> (rx/from pending)
|
||||||
(rx/mapcat (fn [callback] (callback)))
|
(rx/merge-map (fn [callback] (callback)))
|
||||||
|
(rx/tap (fn [_] (request-render "set-objects")))
|
||||||
(rx/reduce conj [])
|
(rx/reduce conj [])
|
||||||
(rx/subs! (fn [_]
|
(rx/subs! (fn [_]
|
||||||
(clear-drawing-cache)
|
|
||||||
(request-render "set-objects")
|
|
||||||
(.dispatchEvent ^js js/document event))))
|
(.dispatchEvent ^js js/document event))))
|
||||||
(.dispatchEvent ^js js/document event))))
|
(.dispatchEvent ^js js/document event))))
|
||||||
|
|
||||||
|
|
|
@ -77,18 +77,23 @@
|
||||||
|
|
||||||
;; IMPORTANT: It should be noted that only TTF fonts can be stored.
|
;; IMPORTANT: It should be noted that only TTF fonts can be stored.
|
||||||
(defn- store-font-buffer
|
(defn- store-font-buffer
|
||||||
[font-data font-array-buffer emoji? fallback?]
|
[shape-id font-data font-array-buffer emoji? fallback?]
|
||||||
(let [id-buffer (:family-id-buffer font-data)
|
(let [font-id-buffer (:family-id-buffer font-data)
|
||||||
|
shape-id-buffer (uuid/get-u32 shape-id)
|
||||||
size (.-byteLength font-array-buffer)
|
size (.-byteLength font-array-buffer)
|
||||||
ptr (h/call wasm/internal-module "_alloc_bytes" size)
|
ptr (h/call wasm/internal-module "_alloc_bytes" size)
|
||||||
heap (gobj/get ^js wasm/internal-module "HEAPU8")
|
heap (gobj/get ^js wasm/internal-module "HEAPU8")
|
||||||
mem (js/Uint8Array. (.-buffer heap) ptr size)]
|
mem (js/Uint8Array. (.-buffer heap) ptr size)]
|
||||||
(.set mem (js/Uint8Array. font-array-buffer))
|
(.set mem (js/Uint8Array. font-array-buffer))
|
||||||
(h/call wasm/internal-module "_store_font"
|
(h/call wasm/internal-module "_store_font"
|
||||||
(aget id-buffer 0)
|
(aget shape-id-buffer 0)
|
||||||
(aget id-buffer 1)
|
(aget shape-id-buffer 1)
|
||||||
(aget id-buffer 2)
|
(aget shape-id-buffer 2)
|
||||||
(aget id-buffer 3)
|
(aget shape-id-buffer 3)
|
||||||
|
(aget font-id-buffer 0)
|
||||||
|
(aget font-id-buffer 1)
|
||||||
|
(aget font-id-buffer 2)
|
||||||
|
(aget font-id-buffer 3)
|
||||||
(:weight font-data)
|
(:weight font-data)
|
||||||
(:style font-data)
|
(:style font-data)
|
||||||
emoji?
|
emoji?
|
||||||
|
@ -96,13 +101,13 @@
|
||||||
true))
|
true))
|
||||||
|
|
||||||
(defn- fetch-font
|
(defn- fetch-font
|
||||||
[font-data font-url emoji? fallback?]
|
[shape-id font-data font-url emoji? fallback?]
|
||||||
{:key font-url
|
{:key font-url
|
||||||
:callback #(->> (http/send! {:method :get
|
:callback #(->> (http/send! {:method :get
|
||||||
:uri font-url
|
:uri font-url
|
||||||
:response-type :buffer})
|
:response-type :buffer})
|
||||||
(rx/map (fn [{:keys [body]}]
|
(rx/map (fn [{:keys [body]}]
|
||||||
(store-font-buffer font-data body emoji? fallback?))))})
|
(store-font-buffer shape-id font-data body emoji? fallback?))))})
|
||||||
|
|
||||||
(defn- google-font-ttf-url
|
(defn- google-font-ttf-url
|
||||||
[font-id font-variant-id]
|
[font-id font-variant-id]
|
||||||
|
@ -122,7 +127,7 @@
|
||||||
(dm/str (u/join cf/public-uri "fonts/" asset-id))))
|
(dm/str (u/join cf/public-uri "fonts/" asset-id))))
|
||||||
|
|
||||||
(defn- store-font-id
|
(defn- store-font-id
|
||||||
[font-data asset-id emoji? fallback?]
|
[shape-id font-data asset-id emoji? fallback?]
|
||||||
(when asset-id
|
(when asset-id
|
||||||
(let [uri (font-id->ttf-url (:font-id font-data) asset-id (:font-variant-id font-data))
|
(let [uri (font-id->ttf-url (:font-id font-data) asset-id (:font-variant-id font-data))
|
||||||
id-buffer (uuid/get-u32 (:wasm-id font-data))
|
id-buffer (uuid/get-u32 (:wasm-id font-data))
|
||||||
|
@ -136,7 +141,7 @@
|
||||||
(:style font-data)
|
(:style font-data)
|
||||||
emoji?))]
|
emoji?))]
|
||||||
(when-not font-stored?
|
(when-not font-stored?
|
||||||
(fetch-font font-data uri emoji? fallback?)))))
|
(fetch-font shape-id font-data uri emoji? fallback?)))))
|
||||||
|
|
||||||
(defn serialize-font-style
|
(defn serialize-font-style
|
||||||
[font-style]
|
[font-style]
|
||||||
|
@ -167,7 +172,7 @@
|
||||||
(js/Number font-weight))
|
(js/Number font-weight))
|
||||||
|
|
||||||
(defn store-font
|
(defn store-font
|
||||||
[font]
|
[shape-id font]
|
||||||
(let [font-id (get font :font-id)
|
(let [font-id (get font :font-id)
|
||||||
font-variant-id (get font :font-variant-id)
|
font-variant-id (get font :font-variant-id)
|
||||||
emoji? (get font :is-emoji false)
|
emoji? (get font :is-emoji false)
|
||||||
|
@ -184,11 +189,11 @@
|
||||||
:font-variant-id font-variant-id
|
:font-variant-id font-variant-id
|
||||||
:style style
|
:style style
|
||||||
:weight weight}]
|
:weight weight}]
|
||||||
(store-font-id font-data asset-id emoji? fallback?)))
|
(store-font-id shape-id font-data asset-id emoji? fallback?)))
|
||||||
|
|
||||||
(defn store-fonts
|
(defn store-fonts
|
||||||
[fonts]
|
[shape-id fonts]
|
||||||
(keep (fn [font] (store-font font)) fonts))
|
(keep (fn [font] (store-font shape-id font)) fonts))
|
||||||
|
|
||||||
|
|
||||||
(defn add-emoji-font
|
(defn add-emoji-font
|
||||||
|
|
|
@ -112,7 +112,8 @@
|
||||||
|
|
||||||
(defn set-wasm-single-attr!
|
(defn set-wasm-single-attr!
|
||||||
[shape k]
|
[shape k]
|
||||||
(let [v (get shape k)]
|
(let [v (get shape k)
|
||||||
|
id (get shape :id)]
|
||||||
(case k
|
(case k
|
||||||
:parent-id (api/set-parent-id v)
|
:parent-id (api/set-parent-id v)
|
||||||
:type (api/set-shape-type v)
|
:type (api/set-shape-type v)
|
||||||
|
@ -123,8 +124,8 @@
|
||||||
(api/set-shape-clip-content false))
|
(api/set-shape-clip-content false))
|
||||||
:rotation (api/set-shape-rotation v)
|
:rotation (api/set-shape-rotation v)
|
||||||
:transform (api/set-shape-transform v)
|
:transform (api/set-shape-transform v)
|
||||||
:fills (into [] (api/set-shape-fills v))
|
:fills (into [] (api/set-shape-fills id v))
|
||||||
:strokes (into [] (api/set-shape-strokes v))
|
:strokes (into [] (api/set-shape-strokes id v))
|
||||||
:blend-mode (api/set-shape-blend-mode v)
|
:blend-mode (api/set-shape-blend-mode v)
|
||||||
:opacity (api/set-shape-opacity v)
|
:opacity (api/set-shape-opacity v)
|
||||||
:hidden (api/set-shape-hidden v)
|
:hidden (api/set-shape-hidden v)
|
||||||
|
@ -158,7 +159,7 @@
|
||||||
(api/set-shape-svg-raw-content (api/get-static-markup shape))
|
(api/set-shape-svg-raw-content (api/get-static-markup shape))
|
||||||
|
|
||||||
(= (:type shape) :text)
|
(= (:type shape) :text)
|
||||||
(api/set-shape-text v))
|
(api/set-shape-text id v))
|
||||||
|
|
||||||
:grow-type
|
:grow-type
|
||||||
(api/set-shape-grow-type v)
|
(api/set-shape-grow-type v)
|
||||||
|
|
|
@ -290,17 +290,31 @@ pub extern "C" fn set_children() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn store_image(a: u32, b: u32, c: u32, d: u32) {
|
pub extern "C" fn store_image(
|
||||||
|
a1: u32,
|
||||||
|
b1: u32,
|
||||||
|
c1: u32,
|
||||||
|
d1: u32,
|
||||||
|
a2: u32,
|
||||||
|
b2: u32,
|
||||||
|
c2: u32,
|
||||||
|
d2: u32,
|
||||||
|
) {
|
||||||
with_state!(state, {
|
with_state!(state, {
|
||||||
let id = uuid_from_u32_quartet(a, b, c, d);
|
let image_id = uuid_from_u32_quartet(a2, b2, c2, d2);
|
||||||
let image_bytes = mem::bytes();
|
let image_bytes = mem::bytes();
|
||||||
|
|
||||||
if let Err(msg) = state.render_state().add_image(id, &image_bytes) {
|
if let Err(msg) = state.render_state().add_image(image_id, &image_bytes) {
|
||||||
eprintln!("{}", msg);
|
eprintln!("{}", msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
mem::free_bytes();
|
mem::free_bytes();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
with_state!(state, {
|
||||||
|
let shape_id = uuid_from_u32_quartet(a1, b1, c1, d1);
|
||||||
|
state.update_tile_for_shape(shape_id);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
|
|
@ -220,14 +220,14 @@ impl RenderState {
|
||||||
let tiles = tiles::TileHashMap::new();
|
let tiles = tiles::TileHashMap::new();
|
||||||
|
|
||||||
RenderState {
|
RenderState {
|
||||||
gpu_state,
|
gpu_state: gpu_state.clone(),
|
||||||
options: RenderOptions::default(),
|
options: RenderOptions::default(),
|
||||||
surfaces,
|
surfaces,
|
||||||
fonts,
|
fonts,
|
||||||
viewbox,
|
viewbox,
|
||||||
cached_viewbox: Viewbox::new(0., 0.),
|
cached_viewbox: Viewbox::new(0., 0.),
|
||||||
cached_target_snapshot: None,
|
cached_target_snapshot: None,
|
||||||
images: ImageStore::new(),
|
images: ImageStore::new(gpu_state.context.clone()),
|
||||||
background_color: skia::Color::TRANSPARENT,
|
background_color: skia::Color::TRANSPARENT,
|
||||||
render_request_id: None,
|
render_request_id: None,
|
||||||
render_in_progress: false,
|
render_in_progress: false,
|
||||||
|
@ -257,7 +257,7 @@ impl RenderState {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_image(&mut self, id: Uuid, image_data: &[u8]) -> Result<(), String> {
|
pub fn add_image(&mut self, id: Uuid, image_data: &[u8]) -> Result<(), String> {
|
||||||
self.images.add(id, image_data, &mut self.gpu_state.context)
|
self.images.add(id, image_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_image(&mut self, id: &Uuid) -> bool {
|
pub fn has_image(&mut self, id: &Uuid) -> bool {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use skia_safe::gpu::{self, gl::FramebufferInfo, gl::TextureInfo, DirectContext};
|
use skia_safe::gpu::{self, gl::FramebufferInfo, gl::TextureInfo, DirectContext};
|
||||||
use skia_safe::{self as skia, ISize};
|
use skia_safe::{self as skia, ISize};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub struct GpuState {
|
pub struct GpuState {
|
||||||
pub context: DirectContext,
|
pub context: DirectContext,
|
||||||
framebuffer_info: FramebufferInfo,
|
framebuffer_info: FramebufferInfo,
|
||||||
|
|
|
@ -7,32 +7,55 @@ use std::collections::HashMap;
|
||||||
|
|
||||||
pub type Image = skia::Image;
|
pub type Image = skia::Image;
|
||||||
|
|
||||||
|
enum StoredImage {
|
||||||
|
Raw(Vec<u8>),
|
||||||
|
Gpu(Image),
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ImageStore {
|
pub struct ImageStore {
|
||||||
images: HashMap<Uuid, Image>,
|
images: HashMap<Uuid, StoredImage>,
|
||||||
|
context: Box<DirectContext>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ImageStore {
|
impl ImageStore {
|
||||||
pub fn new() -> Self {
|
pub fn new(context: DirectContext) -> Self {
|
||||||
Self {
|
Self {
|
||||||
images: HashMap::with_capacity(2048),
|
images: HashMap::with_capacity(2048),
|
||||||
|
context: Box::new(context),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add(
|
pub fn add(&mut self, id: Uuid, image_data: &[u8]) -> Result<(), String> {
|
||||||
&mut self,
|
if self.images.contains_key(&id) {
|
||||||
id: Uuid,
|
return Err("Image already exists".to_string());
|
||||||
image_data: &[u8],
|
}
|
||||||
context: &mut DirectContext,
|
|
||||||
) -> Result<(), String> {
|
self.images
|
||||||
let image_data = unsafe { skia::Data::new_bytes(image_data) };
|
.insert(id, StoredImage::Raw(image_data.to_vec()));
|
||||||
let image = Image::from_encoded(image_data).ok_or("Error decoding image data")?;
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn contains(&self, id: &Uuid) -> bool {
|
||||||
|
self.images.contains_key(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&mut self, id: &Uuid) -> Option<&Image> {
|
||||||
|
// Use entry API to mutate the HashMap in-place if needed
|
||||||
|
if let Some(entry) = self.images.get_mut(id) {
|
||||||
|
match entry {
|
||||||
|
StoredImage::Gpu(ref img) => Some(img),
|
||||||
|
StoredImage::Raw(raw_data) => {
|
||||||
|
// Decode and upload to GPU
|
||||||
|
let data = unsafe { skia::Data::new_bytes(raw_data) };
|
||||||
|
let image = Image::from_encoded(data)?;
|
||||||
|
|
||||||
let width = image.width();
|
let width = image.width();
|
||||||
let height = image.height();
|
let height = image.height();
|
||||||
|
|
||||||
let image_info = skia::ImageInfo::new_n32_premul((width, height), None);
|
let image_info = skia::ImageInfo::new_n32_premul((width, height), None);
|
||||||
|
|
||||||
let mut surface = surfaces::render_target(
|
let mut surface = surfaces::render_target(
|
||||||
context,
|
&mut self.context,
|
||||||
Budgeted::Yes,
|
Budgeted::Yes,
|
||||||
&image_info,
|
&image_info,
|
||||||
None,
|
None,
|
||||||
|
@ -40,27 +63,30 @@ impl ImageStore {
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
false,
|
false,
|
||||||
)
|
)?;
|
||||||
.ok_or("Can't create GPU surface")?;
|
|
||||||
|
|
||||||
let dest_rect = MathRect::from_xywh(0.0, 0.0, width as f32, height as f32);
|
let dest_rect = MathRect::from_xywh(0.0, 0.0, width as f32, height as f32);
|
||||||
|
|
||||||
surface
|
surface.canvas().draw_image_rect(
|
||||||
.canvas()
|
&image,
|
||||||
.draw_image_rect(&image, None, dest_rect, &skia::Paint::default());
|
None,
|
||||||
|
dest_rect,
|
||||||
|
&skia::Paint::default(),
|
||||||
|
);
|
||||||
|
|
||||||
let gpu_image = surface.image_snapshot();
|
let gpu_image = surface.image_snapshot();
|
||||||
|
|
||||||
// This way we store the image as a texture
|
// Replace raw data with GPU image
|
||||||
self.images.insert(id, gpu_image);
|
*entry = StoredImage::Gpu(gpu_image);
|
||||||
Ok(())
|
if let StoredImage::Gpu(ref img) = entry {
|
||||||
}
|
Some(img)
|
||||||
|
} else {
|
||||||
pub fn contains(&mut self, id: &Uuid) -> bool {
|
None
|
||||||
self.images.contains_key(id)
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
pub fn get(&self, id: &Uuid) -> Option<&Image> {
|
} else {
|
||||||
self.images.get(id)
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -388,13 +388,13 @@ fn draw_image_stroke_in_container(
|
||||||
image_fill: &ImageFill,
|
image_fill: &ImageFill,
|
||||||
antialias: bool,
|
antialias: bool,
|
||||||
) {
|
) {
|
||||||
|
let scale = render_state.get_scale();
|
||||||
let image = render_state.images.get(&image_fill.id());
|
let image = render_state.images.get(&image_fill.id());
|
||||||
if image.is_none() {
|
if image.is_none() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let size = image_fill.size();
|
let size = image_fill.size();
|
||||||
let scale = render_state.get_scale();
|
|
||||||
let canvas = render_state.surfaces.canvas(SurfaceId::Strokes);
|
let canvas = render_state.surfaces.canvas(SurfaceId::Strokes);
|
||||||
let container = &shape.selrect;
|
let container = &shape.selrect;
|
||||||
let path_transform = shape.to_path_transform();
|
let path_transform = shape.to_path_transform();
|
||||||
|
|
|
@ -191,6 +191,12 @@ impl<'a> State<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update_tile_for_shape(&mut self, shape_id: Uuid) {
|
||||||
|
if let Some(shape) = self.shapes.get_mut(&shape_id) {
|
||||||
|
self.render_state.update_tile_for(shape);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn update_tile_for_current_shape(&mut self) {
|
pub fn update_tile_for_current_shape(&mut self) {
|
||||||
match self.current_shape.as_mut() {
|
match self.current_shape.as_mut() {
|
||||||
Some(shape) => {
|
Some(shape) => {
|
||||||
|
|
|
@ -7,17 +7,21 @@ use crate::shapes::FontFamily;
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn store_font(
|
pub extern "C" fn store_font(
|
||||||
a: u32,
|
a1: u32,
|
||||||
b: u32,
|
b1: u32,
|
||||||
c: u32,
|
c1: u32,
|
||||||
d: u32,
|
d1: u32,
|
||||||
|
a2: u32,
|
||||||
|
b2: u32,
|
||||||
|
c2: u32,
|
||||||
|
d2: u32,
|
||||||
weight: u32,
|
weight: u32,
|
||||||
style: u8,
|
style: u8,
|
||||||
is_emoji: bool,
|
is_emoji: bool,
|
||||||
is_fallback: bool,
|
is_fallback: bool,
|
||||||
) {
|
) {
|
||||||
with_state!(state, {
|
with_state!(state, {
|
||||||
let id = uuid_from_u32_quartet(a, b, c, d);
|
let id = uuid_from_u32_quartet(a2, b2, c2, d2);
|
||||||
let font_bytes = mem::bytes();
|
let font_bytes = mem::bytes();
|
||||||
|
|
||||||
let family = FontFamily::new(id, weight, style.into());
|
let family = FontFamily::new(id, weight, style.into());
|
||||||
|
@ -28,6 +32,11 @@ pub extern "C" fn store_font(
|
||||||
|
|
||||||
mem::free_bytes();
|
mem::free_bytes();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
with_state!(state, {
|
||||||
|
let shape_id = uuid_from_u32_quartet(a1, b1, c1, d1);
|
||||||
|
state.update_tile_for_shape(shape_id);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue