Compare commits

...

4 Commits

Author SHA1 Message Date
Alejandro Alonso
a904857a97 WIP 2026-01-19 17:48:50 +01:00
Alejandro Alonso
cb5674831a WIP 2026-01-19 17:44:42 +01:00
Alejandro Alonso
02065559da WIP 2026-01-19 17:40:59 +01:00
Alejandro Alonso
c291329fb4 WIP 2026-01-19 15:05:05 +01:00
2 changed files with 30 additions and 10 deletions

View File

@@ -258,10 +258,12 @@ pub extern "C" fn set_view_end() {
with_state_mut!(state, {
let _end_start = performance::begin_timed_log!("set_view_end");
performance::begin_measure!("set_view_end");
state.render_state.options.set_fast_mode(false);
state.render_state.cancel_animation_frame();
let zoom_changed = state.render_state.zoom_changed();
// Only rebuild tile indices when zoom has changed.
// During pan-only operations, shapes stay in the same tiles
// because tile_size = 1/scale * TILE_SIZE (depends only on zoom).
@@ -284,6 +286,10 @@ pub extern "C" fn set_view_end() {
performance::end_measure!("set_view_end::clear_tile_index");
performance::end_timed_log!("clear_tile_index", _clear_start);
}
// Sync cached_viewbox with current viewbox to ensure accurate
// comparison in subsequent calls, especially during rapid zoom+pan
// interactions where multiple set_view calls occur before set_view_end.
// state.render_state.sync_cached_viewbox();
performance::end_measure!("set_view_end");
performance::end_timed_log!("set_view_end", _end_start);
#[cfg(feature = "profile-macros")]

View File

@@ -1136,6 +1136,23 @@ impl RenderState {
) -> Result<(), String> {
let _start = performance::begin_timed_log!("start_render_loop");
let scale = self.get_scale();
let zoom_changed = self.zoom_changed();
// CRITICAL FIX: If zoom changed, we MUST rebuild the tile index before using it.
// Otherwise, the index will have tiles from the old zoom level, causing visible
// tiles to appear empty. This can happen if start_render_loop() is called before
// set_view_end() finishes rebuilding the index, or if set_view_end() hasn't been
// called yet. We have access to tree here, so we can rebuild the index ourselves.
//
// IMPORTANT: If there's a render in progress, we must cancel it first because
// rebuild_tiles_shallow() will invalidate the tile index, causing tiles already
// in pending_tiles to lose their shapes.
if zoom_changed {
if self.render_in_progress {
self.cancel_animation_frame();
}
self.rebuild_tiles_shallow(tree);
}
self.tile_viewbox.update(self.viewbox, scale);
self.focus_mode.reset();
@@ -1988,7 +2005,6 @@ impl RenderState {
self.background_color,
);
performance::end_measure!("render_shape_tree::cached");
if self.options.is_debug_visible() {
debug::render_workspace_current_tile(
self,
@@ -2001,7 +2017,6 @@ impl RenderState {
performance::begin_measure!("render_shape_tree::uncached");
let (is_empty, early_return) =
self.render_shape_tree_partial_uncached(tree, timestamp, allow_stop)?;
if early_return {
return Ok(());
}
@@ -2027,7 +2042,6 @@ impl RenderState {
}
}
}
self.surfaces
.canvas(SurfaceId::Current)
.clear(self.background_color);
@@ -2066,19 +2080,14 @@ impl RenderState {
self.render_in_progress = false;
self.surfaces.gc();
// Cache target surface in a texture
self.cached_viewbox = self.viewbox;
self.cached_target_snapshot = Some(self.surfaces.snapshot(SurfaceId::Cache));
if self.options.is_debug_visible() {
debug::render(self);
}
ui::render(self, tree);
debug::render_wasm_label(self);
Ok(())
}
@@ -2162,13 +2171,11 @@ impl RenderState {
}
}
}
// Update the changed tiles
self.surfaces.remove_cached_tiles(self.background_color);
for tile in all_tiles {
self.remove_cached_tile(tile);
}
performance::end_measure!("rebuild_tiles_shallow");
}
@@ -2292,6 +2299,13 @@ impl RenderState {
(self.viewbox.zoom - self.cached_viewbox.zoom).abs() > f32::EPSILON
}
/// Updates the cached viewbox to match the current viewbox.
/// This should be called at the end of view interactions to ensure
/// that cached_viewbox reflects the most recent state for the next comparison.
pub fn sync_cached_viewbox(&mut self) {
self.cached_viewbox = self.viewbox;
}
pub fn mark_touched(&mut self, uuid: Uuid) {
self.touched_ids.insert(uuid);
}