mirror of
https://github.com/storytold/gridcraft.git
synced 2026-11-05 01:58:58 +00:00
Clipboard: refuse oversized pasted pictures before copying their pixels; document paste as desktop-only (#699)
This commit is contained in:
1 parent
ac27137cd8
commit
e56a722bb4
4 files changed
+27
-6
No files matched your search
@@ -74,8 +74,13 @@ impl SheetApp {
|
||||
/// Cmd/Ctrl+V with a picture and no text on the clipboard (egui's `Event::PasteImage`).
|
||||
pub fn paste_color_image(&mut self, image: &egui::ColorImage) {
|
||||
let [w, h] = image.size;
|
||||
// A side too large for u32 is too large to paste; check before copying the pixels.
|
||||
let (w, h) = (u32::try_from(w).unwrap_or(u32::MAX), u32::try_from(h).unwrap_or(u32::MAX));
|
||||
if let Err(e) = check_picture_size(w, h) {
|
||||
return self.alert(e);
|
||||
}
|
||||
let rgba = image.pixels.iter().flat_map(|c| c.to_srgba_unmultiplied()).collect();
|
||||
match u32::try_from(w).ok().zip(u32::try_from(h).ok()).and_then(|(w, h)| image::RgbaImage::from_raw(w, h, rgba)) {
|
||||
match image::RgbaImage::from_raw(w, h, rgba) {
|
||||
Some(image) => self.paste_picture(image),
|
||||
None => self.alert("The picture on the clipboard can't be read.".into()),
|
||||
}
|
||||
@@ -104,15 +109,21 @@ impl SheetApp {
|
||||
const MAX_PICTURE_SIDE: u32 = 16_384;
|
||||
const MAX_PICTURE_PIXELS: u64 = 64 * 1024 * 1024;
|
||||
|
||||
/// PNG bytes of a clipboard picture, refusing sizes that would exhaust memory.
|
||||
fn encode_png(image: &image::RgbaImage) -> Result<Vec<u8>, String> {
|
||||
let (w, h) = image.dimensions();
|
||||
/// Refuse empty clipboard pictures and sizes that would exhaust memory.
|
||||
fn check_picture_size(w: u32, h: u32) -> Result<(), String> {
|
||||
if w == 0 || h == 0 {
|
||||
return Err("The picture on the clipboard is empty.".into());
|
||||
}
|
||||
if w > MAX_PICTURE_SIDE || h > MAX_PICTURE_SIDE || u64::from(w) * u64::from(h) > MAX_PICTURE_PIXELS {
|
||||
return Err("The picture on the clipboard is too large to paste.".into());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// PNG bytes of a clipboard picture, refusing sizes that would exhaust memory.
|
||||
fn encode_png(image: &image::RgbaImage) -> Result<Vec<u8>, String> {
|
||||
let (w, h) = image.dimensions();
|
||||
check_picture_size(w, h)?;
|
||||
let mut png = Vec::new();
|
||||
image
|
||||
.write_to(&mut std::io::Cursor::new(&mut png), image::ImageFormat::Png)
|
||||
|
||||
@@ -522,6 +522,15 @@ fn a_malformed_clipboard_picture_is_refused_without_inserting() {
|
||||
h.input_mut().events.push(Event::PasteImage(std::sync::Arc::new(egui::ColorImage::new([0, 0], Vec::new()))));
|
||||
h.run_steps(2);
|
||||
assert!(pictures(&h).is_empty());
|
||||
|
||||
// Wider than the 16384-pixel limit: refused before its pixels are copied.
|
||||
dismiss(&mut h);
|
||||
let wide = egui::ColorImage::new([20_000, 1], vec![egui::Color32::WHITE; 20_000]);
|
||||
h.input_mut().events.push(Event::PasteImage(std::sync::Arc::new(wide)));
|
||||
h.run_steps(2);
|
||||
assert!(pictures(&h).is_empty());
|
||||
let message = format!("{:?}", h.state().message);
|
||||
assert!(message.contains("too large"), "{message}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -19,7 +19,8 @@ The command API accepts the same placement:
|
||||
|
||||
This initial feature handles static pictures. A picture on the operating system's clipboard (a
|
||||
screenshot, an image copied in a browser) pastes with Cmd/Ctrl+V or Paste as a floating picture
|
||||
at the active cell, as in Excel. Pasting it into a cell, converting between floating and cell
|
||||
at the active cell, as in Excel (desktop builds only: the web build's paste receives clipboard
|
||||
text alone, so a picture with no text pastes nothing there). Pasting it into a cell, converting between floating and cell
|
||||
pictures, and the `IMAGE()` function remain separate work. Formula references and arithmetic do not carry pictures: the calculation
|
||||
engine uses a `#VALUE!` fallback, including when a picture is referenced from another cell.
|
||||
Text-only exports also use that fallback. The picture cell still counts as occupied and
|
||||
|
||||
+1
-1
@@ -308,7 +308,7 @@ scrollbar bugs 2–4 · pixel/feel pass against observed Excel 7–12.
|
||||
| 2026-10-12 | minor | Ctrl+wheel zoom steps along a ladder of percentages about 20% apart that never skips 100%, gliding to each step with animations on, so a notch out undoes a notch in (it drifted: 100 → 122 → 101); Excel steps 15 points, see decisions.md |
|
||||
| 2026-10-12 | minor | Page Layout view: left/right/top/bottom margins are dragged on the rulers (#792) |
|
||||
| 2026-10-12 | minor | Alt+Down opens the active filter header's existing popup, with validation priority and mirrored anchoring on right-to-left sheets (part of #441) |
|
||||
| 2026-11-03 | minor | A picture on the system clipboard (a screenshot, an image copied in a browser or an image editor) pastes with Cmd/Ctrl+V, the ribbon's Paste and the Paste menu items as a floating picture whose top-left corner is the active cell, as Excel does; text on the clipboard still wins. Oversized or malformed pictures are refused with a message (#699, #3018, #3182) |
|
||||
| 2026-11-03 | minor | A picture on the system clipboard (a screenshot, an image copied in a browser or an image editor) pastes with Cmd/Ctrl+V, the ribbon's Paste and the Paste menu items as a floating picture whose top-left corner is the active cell, as Excel does; text on the clipboard still wins. Desktop only: the web build's paste receives clipboard text alone. Oversized or malformed pictures are refused with a message (#699, #3018, #3182) |
|
||||
| 2026-10-12 | minor | Paste from the ribbon (button and options menu), the cell and header context menus and the macOS menu bar's Edit menu pastes what is on the system clipboard, as Cmd/Ctrl+V does, instead of only GridCraft's own copy (the web build, which can't read the clipboard on request, still pastes GridCraft's copy). Copy and Cut by keytip (H,C / H,X) publish to the system clipboard like the ribbon buttons. After a control-channel or MCP copy, which leaves the system clipboard alone, Paste pastes that copy until other text is copied. Once a cut has been pasted, Paste (ribbon, menus or Cmd/Ctrl+V) doesn't paste the cut's clipboard text again over the moved cells (Excel pastes a cut once), and the Paste keytip (H,V,P) pastes the system clipboard like the button. Regression test for the Paste button click freeze in 0.5.0 (#273, fixed by #272); the Paste button gets an accessible "Paste" name for screen readers |
|
||||
| 2026-10-11 | minor | Ribbon: scroll arrows on a tab wider than the window, Formulas › AutoSum as a split button with its function menu, View › Show in two columns so Headings is no longer cut off |
|
||||
| 2026-10-11 | minor | Theme tokens for icon, reference, on-accent and sheet-control colours; WCAG 2 contrast test over both themes (dark danger red and selected header text adjusted) |
|
||||
|
||||
Reference in new issue
Block a user