mirror of
https://github.com/penpot/penpot.git
synced 2026-09-11 22:49:30 +00:00
🐛 Fix board clip on drag (#11620)
This commit is contained in:
parent
0913545b41
commit
32ed9b5a08
@ -626,3 +626,92 @@ test("Renders background blur clipped by a board with clip content", async ({
|
||||
|
||||
await expect(workspace.canvas).toHaveScreenshot();
|
||||
});
|
||||
|
||||
test("Clips a group dragged into a board with clip content", async ({
|
||||
page,
|
||||
}) => {
|
||||
const workspace = new WasmWorkspacePage(page);
|
||||
await workspace.setupEmptyFile();
|
||||
await workspace.mockGetFile("render-wasm/get-file-shapes-groups-boards.json");
|
||||
|
||||
await workspace.goToWorkspace({
|
||||
id: "53a7ff09-2228-81d3-8006-4b5eac177245",
|
||||
pageId: "53a7ff09-2228-81d3-8006-4b5eac177246",
|
||||
});
|
||||
await workspace.waitForFirstRenderWithoutUI();
|
||||
|
||||
// Select the group, then drag it so it straddles the right edge of the
|
||||
// board. The overflow must not be painted while the pointer is still down.
|
||||
await workspace.viewport.hover({ position: { x: 1028, y: 548 } });
|
||||
await page.mouse.down();
|
||||
await page.mouse.up();
|
||||
await page.waitForTimeout(200);
|
||||
|
||||
await page.mouse.down();
|
||||
for (const [x, y] of [
|
||||
[1000, 540],
|
||||
[920, 530],
|
||||
[830, 520],
|
||||
]) {
|
||||
await workspace.viewport.hover({ position: { x, y } });
|
||||
await page.waitForTimeout(100);
|
||||
}
|
||||
await page.waitForTimeout(600);
|
||||
|
||||
await expect(workspace.canvas).toHaveScreenshot();
|
||||
|
||||
await page.mouse.up();
|
||||
await page.waitForTimeout(800);
|
||||
|
||||
await expect(workspace.canvas).toHaveScreenshot();
|
||||
});
|
||||
|
||||
test("Clips a group dragged inside a board with clip content", async ({
|
||||
page,
|
||||
}) => {
|
||||
const workspace = new WasmWorkspacePage(page);
|
||||
await workspace.setupEmptyFile();
|
||||
await workspace.mockGetFile("render-wasm/get-file-shapes-groups-boards.json");
|
||||
|
||||
await workspace.goToWorkspace({
|
||||
id: "53a7ff09-2228-81d3-8006-4b5eac177245",
|
||||
pageId: "53a7ff09-2228-81d3-8006-4b5eac177246",
|
||||
});
|
||||
await workspace.waitForFirstRenderWithoutUI();
|
||||
|
||||
await workspace.viewport.hover({ position: { x: 1028, y: 548 } });
|
||||
await page.mouse.down();
|
||||
await page.mouse.up();
|
||||
await page.waitForTimeout(200);
|
||||
|
||||
// Drop the group inside the board so it becomes one of its children.
|
||||
await page.mouse.down();
|
||||
for (const [x, y] of [
|
||||
[900, 540],
|
||||
[700, 520],
|
||||
]) {
|
||||
await workspace.viewport.hover({ position: { x, y } });
|
||||
await page.waitForTimeout(100);
|
||||
}
|
||||
await page.waitForTimeout(600);
|
||||
await page.mouse.up();
|
||||
await page.waitForTimeout(800);
|
||||
|
||||
// Drag it towards the right edge, now as a board child.
|
||||
await page.mouse.down();
|
||||
for (const [x, y] of [
|
||||
[750, 520],
|
||||
[830, 520],
|
||||
]) {
|
||||
await workspace.viewport.hover({ position: { x, y } });
|
||||
await page.waitForTimeout(100);
|
||||
}
|
||||
await page.waitForTimeout(600);
|
||||
|
||||
await expect(workspace.canvas).toHaveScreenshot();
|
||||
|
||||
await page.mouse.up();
|
||||
await page.waitForTimeout(800);
|
||||
|
||||
await expect(workspace.canvas).toHaveScreenshot();
|
||||
});
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
@ -438,6 +438,7 @@ pub(crate) struct RenderState {
|
||||
pub viewport_presented: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct InteractiveDragCrop {
|
||||
pub src_doc_bounds: Rect,
|
||||
pub src_selrect: Rect,
|
||||
@ -3725,7 +3726,21 @@ impl RenderState {
|
||||
);
|
||||
|
||||
if use_cached {
|
||||
if let Some(crop) = self.backbuffer_crop_cache.get(&node_id) {
|
||||
if let Some(crop) = self.backbuffer_crop_cache.get(&node_id).cloned() {
|
||||
self.surfaces.canvas(target_surface).save();
|
||||
self.surfaces.canvas(target_surface).reset_matrix();
|
||||
|
||||
if let Some(clips) = clip_bounds.as_ref() {
|
||||
let antialias = element
|
||||
.should_use_antialias(scale, self.options.antialias_threshold);
|
||||
self.clip_target_surface_to_stack(
|
||||
clips,
|
||||
target_surface,
|
||||
scale,
|
||||
antialias,
|
||||
);
|
||||
}
|
||||
|
||||
let crop_image = &crop.image;
|
||||
let crop_src_selrect = crop.src_selrect;
|
||||
|
||||
@ -3737,14 +3752,11 @@ impl RenderState {
|
||||
),
|
||||
None => (0.0, 0.0),
|
||||
};
|
||||
let scale = self.get_scale();
|
||||
let translation = self
|
||||
.surfaces
|
||||
.get_render_context_translation(self.render_area, scale);
|
||||
|
||||
let canvas = self.surfaces.canvas(target_surface);
|
||||
canvas.save();
|
||||
canvas.reset_matrix();
|
||||
// If the crop includes shadows/blur (extrect pixels outside the fill/stroke
|
||||
// silhouette), do NOT apply the silhouette clip or we'd cut those pixels.
|
||||
let should_clip_crop = element.shadows.is_empty() && element.blur.is_none();
|
||||
|
||||
@ -1535,6 +1535,10 @@ impl Shape {
|
||||
return false;
|
||||
}
|
||||
|
||||
if matches!(self.shape_type, Type::Group(_)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If a frame shows overflow (clip_content=false) and its visible content exceeds the
|
||||
// frame bounds, a cached crop anchored to the frame can easily become incorrect while
|
||||
// moving (children can extend beyond selrect). Be conservative and render live.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user