mirror of
https://github.com/storytold/deckcraft.git
synced 2026-11-09 11:59:36 -06:00
address review: share one clip-work allowance between fill and stroke
This commit is contained in:
@@ -168,7 +168,7 @@ pub(crate) fn clip_raw(raw: Raw, clip: &[P]) -> Vec<Raw> {
|
||||
return Vec::new();
|
||||
}
|
||||
let subs = flatten(&ops);
|
||||
if too_much_work(&subs, clip) {
|
||||
if too_much_work(&subs, clip, usize::from(fill.is_some()) + usize::from(stroke.is_some())) {
|
||||
return Vec::new();
|
||||
}
|
||||
let mut out = Vec::new();
|
||||
@@ -195,7 +195,7 @@ pub(crate) fn clip_raw(raw: Raw, clip: &[P]) -> Vec<Raw> {
|
||||
return Vec::new();
|
||||
}
|
||||
let subs = flatten(&ops);
|
||||
if too_much_work(&subs, clip) {
|
||||
if too_much_work(&subs, clip, 1) {
|
||||
return Vec::new();
|
||||
}
|
||||
let f = clip_fill(&subs, clip).unwrap_or_default();
|
||||
@@ -248,9 +248,11 @@ pub(crate) fn flatten(ops: &[Op]) -> Vec<(Vec<P>, bool)> {
|
||||
}
|
||||
|
||||
/// Whether cutting every subpath of one item by `clip` would exceed [`MAX_CLIP_WORK`]; the
|
||||
/// per-polygon check alone lets many small subpaths each spend the whole allowance.
|
||||
fn too_much_work(subs: &[(Vec<P>, bool)], clip: &[P]) -> bool {
|
||||
subs.iter().map(|s| s.0.len() + 1).sum::<usize>().saturating_mul(clip.len()) > MAX_CLIP_WORK
|
||||
/// per-polygon check alone lets many small subpaths each spend the whole allowance. `passes` is
|
||||
/// how many clipping passes the item gets (fill and stroke each cut every subpath), so one item
|
||||
/// shares a single allowance between them.
|
||||
fn too_much_work(subs: &[(Vec<P>, bool)], clip: &[P], passes: usize) -> bool {
|
||||
subs.iter().map(|s| s.0.len() + 1).sum::<usize>().saturating_mul(clip.len()).saturating_mul(passes) > MAX_CLIP_WORK
|
||||
}
|
||||
|
||||
/// The clipped fill of every subpath, its clipping work shared by all of them: `None` (the whole
|
||||
|
||||
@@ -2086,6 +2086,23 @@ fn clip_polygon_charges_actual_work_not_projected_growth() {
|
||||
assert!(clipped.len() > 100, "the intersection is kept: {}", clipped.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clip_work_is_shared_by_fill_and_stroke() {
|
||||
use crate::canvas::Raw;
|
||||
use crate::geom::Op;
|
||||
// One zigzag subpath crossing a 512-gon's edge: about 510k point-edge tests per pass, so a
|
||||
// fill alone fits the allowance but a fill plus a stroke would spend it twice.
|
||||
let clip: Vec<(f64, f64)> =
|
||||
(0..512).map(|i| (i as f64 / 512.0 * std::f64::consts::TAU).sin_cos()).map(|(s, c)| (100.0 + 100.0 * c, 100.0 + 100.0 * s)).collect();
|
||||
let mut ops = vec![Op::M((0.0, 95.0))];
|
||||
ops.extend((1..1000).map(|i| Op::L((i as f64 * 0.19, if i % 2 == 0 { 95.0 } else { 300.0 }))));
|
||||
ops.push(Op::Z);
|
||||
let raw = |fill, stroke| Raw::Path { ops: ops.clone(), fill, stroke, even_odd: false, region: None };
|
||||
let black = [0, 0, 0, 255];
|
||||
assert!(!crate::cliprect::clip_raw(raw(Some(black), None), &clip).is_empty(), "a fill alone is within the allowance");
|
||||
assert!(crate::cliprect::clip_raw(raw(Some(black), Some((black, 1.0))), &clip).is_empty(), "fill and stroke share one allowance");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clip_work_is_bounded_across_subpaths() {
|
||||
use crate::canvas::Raw;
|
||||
|
||||
Reference in New Issue
Block a user