Compare commits

..
6 changed files with 23 additions and 33 deletions
+2 -2
View File
File diff suppressed because one or more lines are too long
+5 -2
View File
@@ -474,14 +474,17 @@ fn parse_blocks(lines: &[String], depth: usize, level: u8, refs: &Refs) -> Vec<F
let p = Para { align: a, inlines: parse_inlines(s, &Fmt::default(), depth, refs), ..Default::default() };
Cell { blocks: vec![FBlock::Para(p)], header, ..Default::default() }
};
table.rows.push(head.iter().zip(&aligns).map(|(s, a)| cell(s, true, *a)).collect());
// A document row keeps MAX_COLS cells: only those are built, so a wide header
// doesn't pad every sparse row below it out to its width.
let cols = aligns.len().min(wordcraft_doc::table::MAX_COLS);
table.rows.push(head.iter().zip(&aligns).take(cols).map(|(s, a)| cell(s, true, *a)).collect());
i += 2;
while let Some(l) = lines.get(i) {
if is_blank(l) || !l.contains('|') || interrupts(l) {
break;
}
let mut cells = split_row(l);
cells.resize(aligns.len(), String::new());
cells.resize(cols, String::new());
table.rows.push(cells.iter().zip(&aligns).map(|(s, a)| cell(s, false, *a)).collect());
i += 1;
}
+14
View File
@@ -714,3 +714,17 @@ fn exported_link_destinations_read_back_unchanged() {
assert_eq!(md("https://example.com/a b"), "[x](<https://example.com/a b>)");
assert_eq!(md("https://e.com/x\ny"), "[x](https://e.com/xy)");
}
#[test]
fn a_wide_table_builds_only_the_cells_a_row_keeps() {
// A 5,000-column header padded every one-cell row below it to 5,000 cells.
let n = 5000;
let md = format!("{}|\n{}|\n{}", "|h".repeat(n), "|-".repeat(n), "|x|\n".repeat(200));
let flow = parse(&md);
let FBlock::Table(t) = &flow.blocks[0] else { panic!("expected table") };
assert_eq!(t.rows.len(), 201);
assert!(t.rows.iter().all(|r| r.len() == wordcraft_doc::table::MAX_COLS));
// A narrow table is unchanged.
let FBlock::Table(t) = &parse("| a | b |\n| - | - |\n| x |\n").blocks[0] else { panic!("expected table") };
assert_eq!(t.rows[1].len(), 2);
}
+1 -13
View File
@@ -836,22 +836,10 @@ fn draw_image(ctx: &mut RenderContext, fr: &Frame, it: &Draw) {
}
}
/// Widest path drawn, in device pixels a side: 64 times the largest canvas. The rasteriser
/// flattens a curve into as many points as its size asks for, before clipping, so a path with
/// coordinates of 1e15 (file data in a native document) would take it forever or run out of
/// memory; one this far past every canvas shows nothing a real drawing would.
const MAX_PATH_PIXELS: f64 = 1_048_576.0;
/// Whether `path` under `view` is small enough to draw ([`MAX_PATH_PIXELS`]) and finite.
fn path_extent_ok(view: Affine, path: &kurbo::BezPath) -> bool {
let b = view.transform_rect_bbox(path.bounding_box());
path.is_finite() && [b.x0, b.y0, b.x1, b.y1].iter().all(|v| v.is_finite() && v.abs() <= MAX_PATH_PIXELS)
}
fn draw_path(ctx: &mut RenderContext, fr: &Frame, it: &Draw) {
let Draw::Path { segs, fill, stroke, stroke_width, dash, cap } = it else { return };
let path = wordcraft_layout::display::seg_path(segs);
if path.elements().is_empty() || !path_extent_ok(fr.view, &path) {
if path.elements().is_empty() {
return;
}
ctx.set_transform(fr.view);
-15
View File
@@ -1318,18 +1318,3 @@ fn a_line_runs_from_top_left_to_bottom_right() {
let p = shape_path(ShapeKind::Line, kurbo::Rect::new(10.0, 20.0, 30.0, 60.0), None);
assert_eq!(p.elements(), &[kurbo::PathEl::MoveTo((10.0, 20.0).into()), kurbo::PathEl::LineTo((30.0, 60.0).into())]);
}
#[test]
fn paths_far_past_every_canvas_are_not_flattened() {
let line = |x: f64| {
let mut p = kurbo::BezPath::new();
p.move_to((0.0, 0.0));
p.curve_to((x, 0.0), (x, x), (0.0, x));
p
};
assert!(path_extent_ok(Affine::IDENTITY, &line(500.0)));
assert!(path_extent_ok(Affine::scale(4.0), &line(200_000.0)), "a large page at a high zoom");
assert!(!path_extent_ok(Affine::IDENTITY, &line(1e15)));
assert!(!path_extent_ok(Affine::scale(1e12), &line(10.0)));
assert!(!path_extent_ok(Affine::IDENTITY, &line(f64::NAN)));
}
+1 -1
View File
File diff suppressed because one or more lines are too long