mirror of
https://github.com/penpot/penpot.git
synced 2025-12-11 22:14:05 +01:00
Merge branch 'staging-render' into develop
This commit is contained in:
Binary file not shown.
@@ -163,6 +163,19 @@ pub extern "C" fn render_sync() {
|
||||
pub extern "C" fn render_sync_shape(a: u32, b: u32, c: u32, d: u32) {
|
||||
with_state_mut!(state, {
|
||||
let id = uuid_from_u32_quartet(a, b, c, d);
|
||||
state.use_shape(id);
|
||||
|
||||
// look for an existing root shape, and create it if missing
|
||||
let mut was_root_missing = false;
|
||||
if !state.shapes.has(&Uuid::nil()) {
|
||||
state.shapes.add_shape(Uuid::nil());
|
||||
was_root_missing = true;
|
||||
}
|
||||
|
||||
if was_root_missing {
|
||||
state.set_parent_for_current_shape(Uuid::nil());
|
||||
}
|
||||
|
||||
state.rebuild_tiles_from(Some(&id));
|
||||
state
|
||||
.render_sync_shape(&id, performance::get_time())
|
||||
@@ -330,6 +343,10 @@ fn set_children_set(entries: Vec<Uuid>) {
|
||||
parent_id = Some(shape.id);
|
||||
(_, deleted) = shape.compute_children_differences(&entries);
|
||||
shape.children = entries.clone();
|
||||
|
||||
for id in entries {
|
||||
state.touch_shape(id);
|
||||
}
|
||||
});
|
||||
|
||||
with_state_mut!(state, {
|
||||
@@ -339,6 +356,7 @@ fn set_children_set(entries: Vec<Uuid>) {
|
||||
|
||||
for id in deleted {
|
||||
state.delete_shape_children(parent_id, id);
|
||||
state.touch_shape(id);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -650,6 +668,26 @@ pub extern "C" fn set_modifiers() {
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn start_temp_objects() {
|
||||
unsafe {
|
||||
#[allow(static_mut_refs)]
|
||||
let mut state = STATE.take().expect("Got an invalid state pointer");
|
||||
state = Box::new(state.start_temp_objects());
|
||||
STATE = Some(state);
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn end_temp_objects() {
|
||||
unsafe {
|
||||
#[allow(static_mut_refs)]
|
||||
let mut state = STATE.take().expect("Got an invalid state pointer");
|
||||
state = Box::new(state.end_temp_objects());
|
||||
STATE = Some(state);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
init_gl!();
|
||||
|
||||
@@ -34,9 +34,9 @@ pub use fonts::*;
|
||||
pub use images::*;
|
||||
|
||||
// This is the extra are used for tile rendering.
|
||||
const VIEWPORT_INTEREST_AREA_THRESHOLD: i32 = 1;
|
||||
const VIEWPORT_INTEREST_AREA_THRESHOLD: i32 = 2;
|
||||
const MAX_BLOCKING_TIME_MS: i32 = 32;
|
||||
const NODE_BATCH_THRESHOLD: i32 = 10;
|
||||
const NODE_BATCH_THRESHOLD: i32 = 3;
|
||||
|
||||
type ClipStack = Vec<(Rect, Option<Corners>, Matrix)>;
|
||||
|
||||
@@ -141,7 +141,20 @@ impl NodeRenderState {
|
||||
|
||||
match &element.shape_type {
|
||||
Type::Frame(_) => {
|
||||
let bounds = element.get_selrect_shadow_bounds(shadow);
|
||||
let mut bounds = element.get_selrect_shadow_bounds(shadow);
|
||||
let blur_inset = (shadow.blur * 2.).max(0.0);
|
||||
if blur_inset > 0.0 {
|
||||
let max_inset_x = (bounds.width() * 0.5).max(0.0);
|
||||
let max_inset_y = (bounds.height() * 0.5).max(0.0);
|
||||
// Clamp the inset so we never shrink more than half of the width/height;
|
||||
// otherwise the rect could end up inverted on small frames.
|
||||
let inset_x = blur_inset.min(max_inset_x);
|
||||
let inset_y = blur_inset.min(max_inset_y);
|
||||
if inset_x > 0.0 || inset_y > 0.0 {
|
||||
bounds.inset((inset_x, inset_y));
|
||||
}
|
||||
}
|
||||
|
||||
let mut transform = element.transform;
|
||||
transform.post_translate(element.center());
|
||||
transform.pre_translate(-element.center());
|
||||
@@ -1721,6 +1734,7 @@ impl RenderState {
|
||||
allow_stop: bool,
|
||||
) -> Result<(), String> {
|
||||
let mut should_stop = false;
|
||||
|
||||
while !should_stop {
|
||||
if let Some(current_tile) = self.current_tile {
|
||||
if self.surfaces.has_cached_tile_surface(current_tile) {
|
||||
@@ -1794,17 +1808,21 @@ impl RenderState {
|
||||
|
||||
if !self.surfaces.has_cached_tile_surface(next_tile) {
|
||||
if let Some(ids) = self.tiles.get_shapes_at(next_tile) {
|
||||
let root_ids_map: std::collections::HashMap<Uuid, usize> = root_ids
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, id)| (*id, i))
|
||||
.collect();
|
||||
|
||||
// We only need first level shapes
|
||||
let mut valid_ids: Vec<Uuid> = ids
|
||||
.iter()
|
||||
.filter(|id| root_ids.contains(id))
|
||||
.filter(|id| root_ids_map.contains_key(id))
|
||||
.copied()
|
||||
.collect();
|
||||
|
||||
// These shapes for the tile should be ordered as they are in the parent node
|
||||
valid_ids.sort_by_key(|id| {
|
||||
root_ids.iter().position(|x| x == id).unwrap_or(usize::MAX)
|
||||
});
|
||||
valid_ids.sort_by_key(|id| root_ids_map.get(id).unwrap_or(&usize::MAX));
|
||||
|
||||
self.pending_nodes.extend(valid_ids.into_iter().map(|id| {
|
||||
NodeRenderState {
|
||||
@@ -1821,6 +1839,7 @@ impl RenderState {
|
||||
should_stop = true;
|
||||
}
|
||||
}
|
||||
|
||||
self.render_in_progress = false;
|
||||
|
||||
self.surfaces.gc();
|
||||
|
||||
@@ -8,8 +8,8 @@ use super::{gpu_state::GpuState, tiles::Tile, tiles::TileViewbox, tiles::TILE_SI
|
||||
use base64::{engine::general_purpose, Engine as _};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
const TEXTURES_CACHE_CAPACITY: usize = 512;
|
||||
const TEXTURES_BATCH_DELETE: usize = 32;
|
||||
const TEXTURES_CACHE_CAPACITY: usize = 1024;
|
||||
const TEXTURES_BATCH_DELETE: usize = 256;
|
||||
// This is the amount of extra space we're going to give to all the surfaces to render shapes.
|
||||
// If it's too big it could affect performance.
|
||||
const TILE_SIZE_MULTIPLIER: i32 = 2;
|
||||
|
||||
@@ -290,7 +290,7 @@ fn propagate_reflow(
|
||||
let mut skip_reflow = false;
|
||||
if shape.is_layout_horizontal_fill() || shape.is_layout_vertical_fill() {
|
||||
if let Some(parent_id) = shape.parent_id {
|
||||
if !reflown.contains(&parent_id) {
|
||||
if parent_id != Uuid::nil() && !reflown.contains(&parent_id) {
|
||||
// If this is a fill layout but the parent has not been reflown yet
|
||||
// we wait for the next iteration for reflow
|
||||
skip_reflow = true;
|
||||
|
||||
@@ -53,15 +53,6 @@ struct LayoutAxis {
|
||||
is_auto_across: bool,
|
||||
}
|
||||
|
||||
impl LayoutAxis {
|
||||
fn main_space(&self) -> f32 {
|
||||
self.main_size - self.padding_main_start - self.padding_main_end
|
||||
}
|
||||
fn across_space(&self) -> f32 {
|
||||
self.across_size - self.padding_across_start - self.padding_across_end
|
||||
}
|
||||
}
|
||||
|
||||
impl LayoutAxis {
|
||||
fn new(
|
||||
shape: &Shape,
|
||||
@@ -101,6 +92,13 @@ impl LayoutAxis {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main_space(&self) -> f32 {
|
||||
self.main_size - self.padding_main_start - self.padding_main_end
|
||||
}
|
||||
fn across_space(&self) -> f32 {
|
||||
self.across_size - self.padding_across_start - self.padding_across_end
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
@@ -624,6 +622,9 @@ pub fn reflow_flex_layout(
|
||||
}
|
||||
|
||||
result.push_back(Modifier::transform_propagate(child.id, transform));
|
||||
if child.has_layout() {
|
||||
result.push_back(Modifier::reflow(child.id));
|
||||
}
|
||||
|
||||
shape_anchor = next_anchor(
|
||||
layout_data,
|
||||
@@ -654,7 +655,11 @@ pub fn reflow_flex_layout(
|
||||
.iter()
|
||||
.map(|track| {
|
||||
let nshapes = usize::max(track.shapes.len(), 1);
|
||||
track.shapes.iter().map(|s| s.main_size).sum::<f32>()
|
||||
track
|
||||
.shapes
|
||||
.iter()
|
||||
.map(|s| s.margin_main_start + s.margin_main_end + s.main_size)
|
||||
.sum::<f32>()
|
||||
+ (nshapes as f32 - 1.0) * layout_axis.gap_main
|
||||
})
|
||||
.reduce(f32::max)
|
||||
|
||||
@@ -792,6 +792,9 @@ pub fn reflow_grid_layout(
|
||||
}
|
||||
|
||||
result.push_back(Modifier::transform_propagate(child.id, transform));
|
||||
if child.has_layout() {
|
||||
result.push_back(Modifier::reflow(child.id));
|
||||
}
|
||||
}
|
||||
|
||||
if shape.is_layout_horizontal_auto() || shape.is_layout_vertical_auto() {
|
||||
|
||||
@@ -24,6 +24,7 @@ pub(crate) struct State<'a> {
|
||||
pub current_id: Option<Uuid>,
|
||||
pub current_browser: u8,
|
||||
pub shapes: ShapesPool<'a>,
|
||||
pub saved_shapes: Option<ShapesPool<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> State<'a> {
|
||||
@@ -34,9 +35,32 @@ impl<'a> State<'a> {
|
||||
current_id: None,
|
||||
current_browser: 0,
|
||||
shapes: ShapesPool::new(),
|
||||
// TODO: Maybe this can be moved to a different object
|
||||
saved_shapes: None,
|
||||
}
|
||||
}
|
||||
|
||||
// Creates a new temporary shapes pool.
|
||||
// Will panic if a previous temporary pool exists.
|
||||
pub fn start_temp_objects(mut self) -> Self {
|
||||
if self.saved_shapes.is_some() {
|
||||
panic!("Tried to start a temp objects while the previous have not been restored");
|
||||
}
|
||||
self.saved_shapes = Some(self.shapes);
|
||||
self.shapes = ShapesPool::new();
|
||||
self
|
||||
}
|
||||
|
||||
// Disposes of the temporary shapes pool restoring the normal pool
|
||||
// Will panic if a there is no temporary pool.
|
||||
pub fn end_temp_objects(mut self) -> Self {
|
||||
self.shapes = self
|
||||
.saved_shapes
|
||||
.expect("Tried to end temp objects but not content to be restored is present");
|
||||
self.saved_shapes = None;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn resize(&mut self, width: i32, height: i32) {
|
||||
self.render_state.resize(width, height);
|
||||
}
|
||||
|
||||
@@ -88,6 +88,7 @@ impl TileViewbox {
|
||||
}
|
||||
|
||||
pub fn is_visible(&self, tile: &Tile) -> bool {
|
||||
// TO CHECK self.interest_rect.contains(tile)
|
||||
self.visible_rect.contains(tile)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,18 +59,19 @@ pub extern "C" fn set_layout_child_data(
|
||||
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| {
|
||||
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();
|
||||
|
||||
shape.set_flex_layout_child_data(
|
||||
margin_top,
|
||||
margin_right,
|
||||
|
||||
Reference in New Issue
Block a user