mirror of
https://github.com/penpot/penpot.git
synced 2026-09-13 15:38:38 +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();
|
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,
|
pub viewport_presented: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct InteractiveDragCrop {
|
pub struct InteractiveDragCrop {
|
||||||
pub src_doc_bounds: Rect,
|
pub src_doc_bounds: Rect,
|
||||||
pub src_selrect: Rect,
|
pub src_selrect: Rect,
|
||||||
@ -3725,7 +3726,21 @@ impl RenderState {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if use_cached {
|
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_image = &crop.image;
|
||||||
let crop_src_selrect = crop.src_selrect;
|
let crop_src_selrect = crop.src_selrect;
|
||||||
|
|
||||||
@ -3737,14 +3752,11 @@ impl RenderState {
|
|||||||
),
|
),
|
||||||
None => (0.0, 0.0),
|
None => (0.0, 0.0),
|
||||||
};
|
};
|
||||||
let scale = self.get_scale();
|
|
||||||
let translation = self
|
let translation = self
|
||||||
.surfaces
|
.surfaces
|
||||||
.get_render_context_translation(self.render_area, scale);
|
.get_render_context_translation(self.render_area, scale);
|
||||||
|
|
||||||
let canvas = self.surfaces.canvas(target_surface);
|
let canvas = self.surfaces.canvas(target_surface);
|
||||||
canvas.save();
|
|
||||||
canvas.reset_matrix();
|
|
||||||
// If the crop includes shadows/blur (extrect pixels outside the fill/stroke
|
// 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.
|
// 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();
|
let should_clip_crop = element.shadows.is_empty() && element.blur.is_none();
|
||||||
|
|||||||
@ -1535,6 +1535,10 @@ impl Shape {
|
|||||||
return false;
|
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
|
// 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
|
// 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.
|
// moving (children can extend beyond selrect). Be conservative and render live.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user