mirror of
https://github.com/penpot/penpot.git
synced 2026-05-14 20:43:55 +00:00
Merge pull request #9576 from penpot/superalex-fix-atlas-issues
🐛 Fix atlas corruption when dragging large shapes after zoom change
This commit is contained in:
commit
7617e42547
@ -62,6 +62,7 @@
|
||||
|
||||
### :bug: Bugs fixed
|
||||
|
||||
- Fix render-wasm atlas corruption when dragging large shapes after a zoom or pan change (stale multi-zoom-level pixels no longer appear at the old shape position).
|
||||
- Fix Alt/Option to draw shapes from center point (by @offreal) [Github #8361](https://github.com/penpot/penpot/pull/8361)
|
||||
- Add token name on broken token pill on sidebar [Taiga #13527](https://tree.taiga.io/project/penpot/issue/13527)
|
||||
- Fix tooltip activated when tab change [Taiga #13627](https://tree.taiga.io/project/penpot/issue/13627)
|
||||
|
||||
@ -3507,6 +3507,25 @@ impl RenderState {
|
||||
|
||||
let mut result = HashSet::<tiles::Tile>::with_capacity(old_tiles.len());
|
||||
|
||||
// When the shape has an active modifier (i.e. is being moved/resized),
|
||||
// clear its OLD doc-space extent from the atlas using the raw
|
||||
// (pre-modifier) shape. The per-tile clearing done later via
|
||||
// `clear_tile_in_atlas` only covers tiles tracked in `atlas_tile_doc_rects`
|
||||
// at the current zoom level. However, the atlas may also contain stale
|
||||
// pixels from previous zoom levels (tiles are larger / smaller in doc
|
||||
// space at different zoom scales) that were never re-tracked after a zoom
|
||||
// change. Clearing the full raw extrect here removes all such residual
|
||||
// content without growing the atlas.
|
||||
//
|
||||
// We intentionally skip this when there is NO modifier so that plain
|
||||
// zoom / pan tile-index rebuilds do NOT invalidate valid atlas content.
|
||||
if tree.get_modifier(&shape.id).is_some() {
|
||||
if let Some(raw_shape) = tree.get_raw(&shape.id) {
|
||||
let old_extrect = raw_shape.extrect(tree, 1.0);
|
||||
self.surfaces.clear_doc_rect_in_atlas_clipped(old_extrect);
|
||||
}
|
||||
}
|
||||
|
||||
// First, remove the shape from all tiles where it was previously located
|
||||
for tile in old_tiles {
|
||||
self.tiles.remove_shape_at(tile, shape.id);
|
||||
|
||||
@ -396,6 +396,58 @@ impl Surfaces {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Clears a doc-space rect from the atlas **without** growing it.
|
||||
///
|
||||
/// Unlike [`clear_doc_rect_in_atlas`], this method clips `doc_rect` to the
|
||||
/// current atlas bounds and skips silently if there is no overlap. Use this
|
||||
/// when evicting stale shape content (e.g. before a drag re-render) where
|
||||
/// growing the atlas to accommodate an out-of-range rect would be wasteful.
|
||||
pub fn clear_doc_rect_in_atlas_clipped(&mut self, doc_rect: skia::Rect) {
|
||||
if !self.has_atlas() || doc_rect.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let atlas_scale = self.atlas_scale.max(0.01);
|
||||
let atlas_doc_right = self.atlas_origin.x + (self.atlas_size.width as f32) / atlas_scale;
|
||||
let atlas_doc_bottom = self.atlas_origin.y + (self.atlas_size.height as f32) / atlas_scale;
|
||||
|
||||
// Intersect with current atlas bounds in doc space.
|
||||
let mut clipped = doc_rect;
|
||||
let atlas_bounds = skia::Rect::from_ltrb(
|
||||
self.atlas_origin.x,
|
||||
self.atlas_origin.y,
|
||||
atlas_doc_right,
|
||||
atlas_doc_bottom,
|
||||
);
|
||||
if !clipped.intersect(atlas_bounds) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply atlas_doc_bounds clamping.
|
||||
if let Some(bounds) = self.atlas_doc_bounds {
|
||||
if !clipped.intersect(bounds) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if clipped.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let dst = skia::Rect::from_xywh(
|
||||
(clipped.left - self.atlas_origin.x) * atlas_scale,
|
||||
(clipped.top - self.atlas_origin.y) * atlas_scale,
|
||||
clipped.width() * atlas_scale,
|
||||
clipped.height() * atlas_scale,
|
||||
);
|
||||
|
||||
let canvas = self.atlas.canvas();
|
||||
canvas.save();
|
||||
canvas.clip_rect(dst, None, true);
|
||||
canvas.clear(skia::Color::TRANSPARENT);
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
pub fn clear_tiles(&mut self) {
|
||||
self.tiles.clear();
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user