From bdff7730d6024f39c4e5359c5981e0d92620be99 Mon Sep 17 00:00:00 2001 From: Aitor Moreno Date: Mon, 6 Jul 2026 09:20:56 +0200 Subject: [PATCH] WIP --- render-wasm/src/main.rs | 25 ++------ render-wasm/src/render.rs | 104 +++++++++++++++++++++++++++++++ render-wasm/src/render/vector.rs | 3 +- 3 files changed, 111 insertions(+), 21 deletions(-) diff --git a/render-wasm/src/main.rs b/render-wasm/src/main.rs index e674a96a21..eb0ab2596f 100644 --- a/render-wasm/src/main.rs +++ b/render-wasm/src/main.rs @@ -20,10 +20,7 @@ use std::collections::HashMap; #[allow(unused_imports)] use crate::error::{Error, Result}; -use crate::{ - render::{FrameType, RenderFlag}, - shapes::Frame, -}; +use crate::render::FrameType; use globals::{get_design_state, get_gpu_state, get_render_state}; @@ -108,24 +105,12 @@ pub extern "C" fn set_canvas_background(raw_color: u32) -> Result<()> { #[no_mangle] #[wasm_error] -pub extern "C" fn render2(timestamp: i32, flags: u8) -> Result { +pub extern "C" fn render2(timestamp: i32, _flags: u8) -> Result { with_state!(state, { let render_state = get_render_state(); - - render_state.prepare_render_loop(&mut state.shapes)?; - let frame_type = if flags & RenderFlag::Partial as u8 == RenderFlag::Partial as u8 { - // TODO: Meter una flag que lo que haga es indicar - // si el render es sync o no y que esto no permita - let allow_stop = true; - render_state - .continue_render_loop(timestamp, allow_stop) - .map_err(|_| Error::RecoverableError("Error rendering".to_string()))? - } else { - let sync_render = false; - render_state - .start_render_loop(timestamp, sync_render) - .map_err(|_| Error::RecoverableError("Error rendering".to_string()))? - }; + let frame_type = render_state + .render_backbuffer_vector(&state.shapes, timestamp) + .map_err(|_| Error::RecoverableError("Error rendering".to_string()))?; render_state.end_render_loop(&frame_type); return Ok(frame_type); }); diff --git a/render-wasm/src/render.rs b/render-wasm/src/render.rs index 884b620405..c738584a83 100644 --- a/render-wasm/src/render.rs +++ b/render-wasm/src/render.rs @@ -1347,6 +1347,110 @@ impl RenderState { }; } + pub fn render_backbuffer_vector( + &mut self, + tree: ShapesPoolRef, + _timestamp: i32, + ) -> Result { + #[cfg(feature = "stats")] + self.stats.clear(); + + self.surfaces.clear_backbuffer(self.background_color); + self.surfaces.clear_target(self.background_color); + + self.pending_nodes.clear(); + self.nested_fills.clear(); + self.nested_blurs.clear(); + self.cached_layer_blur = None; + self.nested_shadows.clear(); + self.focus_mode.reset(); + + let tile_render_state = get_tile_render_state(); + tile_render_state.current = None; + + self.empty_grid_frame_ids.clear(); + if self.show_grid.is_some() { + for shape in tree.iter() { + if shape.id.is_nil() || !shape.children.is_empty() { + continue; + } + if let Type::Frame(frame) = &shape.shape_type { + if matches!(frame.layout, Some(Layout::GridLayout(_, _))) && !shape.deleted() { + self.empty_grid_frame_ids.insert(shape.id); + } + } + } + } + + let scale = self.get_scale(); + let offset = self.viewbox.get_offset(); + let pan = self.viewbox.pan(); + let area = self.viewbox.area; + + println!( + "VECTOR: scale={scale} pan=({},{}) area=({},{},{},{}) offset=({},{}) dpr={} zoom={}", + pan.x, pan.y, + area.left, area.top, area.right, area.bottom, + offset.x, offset.y, + self.viewbox.dpr, self.viewbox.zoom, + ); + + // Apply viewbox transform to backbuffer canvas. + self.surfaces.canvas(SurfaceId::Backbuffer).save(); + { + let canvas = self.surfaces.canvas(SurfaceId::Backbuffer); + canvas.restore_to_count(1); + canvas.save(); + canvas.scale((scale, scale)); + canvas.translate((-offset.x, -offset.y)); + } + + // Determine root frames to render. + self.viewer_render_root = self.base_object; + let root_ids: Vec = { + if let Some(shape_id) = self.base_object { + vec![shape_id] + } else if let Some(root) = tree.get(&Uuid::nil()) { + root.children_ids(false) + } else { + return Err(Error::CriticalError( + "Root shape not found".to_string(), + )); + } + }; + + // Render each root directly onto the backbuffer canvas using + // the vector renderer (CPU Skia canvas, no GPU surface pipelining). + for root_id in &root_ids { + let canvas_ptr: *const skia::Canvas = { + let canvas: &skia::Canvas = self.surfaces.canvas(SurfaceId::Backbuffer); + canvas as *const skia::Canvas + }; + let canvas = unsafe { &*canvas_ptr }; + vector::render_tree( + self, + canvas, + root_id, + tree, + scale, + vector::VectorTarget::Backbuffer, + )?; + } + + // Restore the viewbox transform. + self.surfaces.canvas(SurfaceId::Backbuffer).restore(); + + let saved_preview_mode = self.preview_mode; + self.preview_mode = true; + //self.present_frame(); + self.surfaces.copy_backbuffer_to_target(); + self.flush_and_submit(); + + self.preview_mode = saved_preview_mode; + + Ok(FrameType::Full) + } + pub fn start_render_loop(&mut self, timestamp: i32, sync_render: bool) -> Result { let design_state = get_design_state(); let tree = &design_state.shapes; diff --git a/render-wasm/src/render/vector.rs b/render-wasm/src/render/vector.rs index 721a02fbc5..0dad000a5a 100644 --- a/render-wasm/src/render/vector.rs +++ b/render-wasm/src/render/vector.rs @@ -16,10 +16,11 @@ use super::{get_dest_rect, get_source_rect}; // VectorTarget — vector export backend selector // --------------------------------------------------------------------------- -/// Vector export backend selector (PDF today; SVG could be added as a variant). +/// Vector backend selector (PDF export or realtime backbuffer rendering). #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(super) enum VectorTarget { Pdf, + Backbuffer, } // ---------------------------------------------------------------------------