#1899: keep at least 0.5% of a cropped axis, so nothing shown is culled

With 0.1% the whole source of a 4000 pt frame spanned up to 4,000,000 pt,
past the ±1,000,000 pt limit Picture::place uses to leave out items far
off the page, so a metafile cropped that narrow lost what the crop shows.
At 0.5% it spans at most 800,000 pt (CodeRabbit on #3247).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rabis
2026-10-20 11:10:12 +02:00
co-authored by Claude Opus 5.5
parent 0cca2f7d21
commit fc5063c38d
2 changed files with 26 additions and 5 deletions
+7 -5
View File
@@ -11,14 +11,16 @@ pub const MAX_BITMAP_SIDE: u32 = 30_000;
const MAX_COORD: f64 = 1e6;
/// Smallest placed bitmap side (target units), so the stretch onto it is never singular.
const MIN_BITMAP_SIDE: f64 = 1e-6;
/// The least of a source axis a crop keeps (0.1%). Files crop pictures to slivers (a header bar
/// that is 2.7% of a page-sized metafile, #1899); this only keeps the stretch finite.
const MIN_VISIBLE: f64 = 0.001;
/// The least of a source axis a crop keeps (0.5%). Files crop pictures to slivers (a header bar
/// that is 2.7% of a page-sized metafile, #1899). Layout makes a picture's frame at most 4000 pt
/// a side, so the whole source then spans at most 800,000 pt: what it covers stays inside
/// `MAX_COORD` and is never left out as far off the page.
const MIN_VISIBLE: f64 = 0.005;
/// The part of a picture's source that `crop` (left, top, right, bottom fractions of the source)
/// keeps, as fractions of the source: [left, top, width, height], bitmap or metafile alike. Each
/// side is taken as 0–1 (junk as 0). When the two sides of an axis leave less than 0.1% of it,
/// the left (top) side stands and 0.1% shows.
/// side is taken as 0–1 (junk as 0). When the two sides of an axis leave less than 0.5% of it,
/// the left (top) side stands and 0.5% shows.
pub fn crop_window(crop: [f32; 4]) -> [f64; 4] {
let [l, t, r, b] = crop.map(|v| if v.is_finite() { f64::from(v.clamp(0.0, 1.0)) } else { 0.0 });
let axis = |lo: f64, hi: f64| {
+19
View File
@@ -909,6 +909,25 @@ fn crop_window_keeps_a_sliver_and_stays_finite() {
}
}
/// The narrowest crop on the largest frame layout makes (4000 pt, far down a 22-inch page) still
/// places the source's content: none of it is left out as far off the page.
#[test]
fn the_narrowest_crop_on_the_largest_frame_keeps_its_content() {
let pic = crate::Picture {
width: 100.0,
height: 100.0,
items: vec![
Item::Bitmap { rect: [0.0, 0.0, 100.0, 100.0], width: 1, height: 1, rgba: vec![255; 4] },
Item::Path { segs: vec![Seg::Move(0.0, 0.0), Seg::Line(100.0, 100.0)], fill: None, stroke: Some(([0, 0, 0, 255], 1.0)), even_odd: false },
],
};
let frame = kurbo::Rect::new(1584.0, 1584.0, 5584.0, 5584.0);
// The last sliver, the first sliver, and sides that overlap.
for crop in [[1.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 1.0], [0.9999, 0.6, 0.5, 0.9999]] {
assert_eq!(pic.place(frame, crop).len(), 2, "{crop:?}");
}
}
#[test]
fn place_keeps_only_finite_bounded_bitmaps_with_area() {
let bitmap = |rect: [f32; 4]| Item::Bitmap { rect, width: 1, height: 1, rgba: vec![0; 4] };