Fix up merged PRs: EMF+ clipping alongside GDI clip regions

main added its own clip.rs (GDI rectangle regions carried on every drawn
item); #582 added a clip.rs that cuts drawing geometrically to the EMF+ clip
rectangle. Keep main's module, move #582's to cliprect.rs, keep the EMF+
rectangle on the canvas as plus_clip, and carry the region field through the
geometric clipper.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Brandon Thomas
2026-10-14 13:55:38 -04:00
co-authored by Claude Opus 5.5
parent eab5686393
commit 3450180f19
3 changed files with 13 additions and 13 deletions
+2 -2
View File
@@ -536,7 +536,7 @@ impl Canvas {
let dev: Vec<Op> = ops.iter().map(|o| self.map_op(*o)).collect();
if dev.len() >= 2 {
let even_odd = self.even_odd;
self.push(Raw::Pattern { ops: dev, even_odd, tile });
self.push(Raw::Pattern { ops: dev, even_odd, tile, region: None });
}
}
@@ -564,7 +564,7 @@ impl Canvas {
}
}
let even_odd = self.even_odd;
self.push(Raw::Pattern { ops: dev, even_odd, tile: Arc::new(RawTile { w, h, px, cell }) });
self.push(Raw::Pattern { ops: dev, even_odd, tile: Arc::new(RawTile { w, h, px, cell }), region: None });
}
/// Pushes the drawing state. Past [`MAX_STACK`] levels the parse stops, since later restores
+10 -10
View File
@@ -48,10 +48,10 @@ fn disjoint(b: [f64; 4], c: [f64; 4]) -> bool {
/// Clips one drawn item; a shape that is both filled and stroked comes back as two items.
pub(crate) fn clip_raw(raw: Raw, c: [f64; 4]) -> Vec<Raw> {
match raw {
Raw::Path { ops, fill, stroke, even_odd } => {
Raw::Path { ops, fill, stroke, even_odd, region } => {
let Some(b) = ops_bbox(&ops) else { return Vec::new() };
if inside(b, c) {
return vec![Raw::Path { ops, fill, stroke, even_odd }];
return vec![Raw::Path { ops, fill, stroke, even_odd, region }];
}
if disjoint(b, c) {
return Vec::new();
@@ -61,33 +61,33 @@ pub(crate) fn clip_raw(raw: Raw, c: [f64; 4]) -> Vec<Raw> {
if fill.is_some() {
let f = clip_fill(&subs, c);
if !f.is_empty() {
out.push(Raw::Path { ops: f, fill, stroke: None, even_odd });
out.push(Raw::Path { ops: f, fill, stroke: None, even_odd, region: region.clone() });
}
}
if stroke.is_some() {
let s = clip_stroke(&subs, c);
if !s.is_empty() {
out.push(Raw::Path { ops: s, fill: None, stroke, even_odd });
out.push(Raw::Path { ops: s, fill: None, stroke, even_odd, region });
}
}
out
}
Raw::Pattern { ops, even_odd, tile } => {
Raw::Pattern { ops, even_odd, tile, region } => {
let Some(b) = ops_bbox(&ops) else { return Vec::new() };
if inside(b, c) {
return vec![Raw::Pattern { ops, even_odd, tile }];
return vec![Raw::Pattern { ops, even_odd, tile, region }];
}
if disjoint(b, c) {
return Vec::new();
}
let f = clip_fill(&flatten(&ops), c);
if f.is_empty() { Vec::new() } else { vec![Raw::Pattern { ops: f, even_odd, tile }] }
if f.is_empty() { Vec::new() } else { vec![Raw::Pattern { ops: f, even_odd, tile, region }] }
}
Raw::Bitmap { rect, img } => crop(rect, img, c).map(|(rect, img)| vec![Raw::Bitmap { rect, img }]).unwrap_or_default(),
Raw::Text(mut t) => {
Raw::Bitmap { rect, img, region } => crop(rect, img, c).map(|(rect, img)| vec![Raw::Bitmap { rect, img, region }]).unwrap_or_default(),
Raw::Text { text: mut t, region } => {
let cur = t.clip.map_or(c, |[a, b, d, e]| intersect(c, [f64::from(a), f64::from(b), f64::from(d), f64::from(e)]));
t.clip = Some(cur.map(|v| v as f32));
vec![Raw::Text(t)]
vec![Raw::Text { text: t, region }]
}
}
}
+1 -1
View File
@@ -1733,7 +1733,7 @@ fn draw_image(id: u16, dst: [f32; 4]) -> Vec<u8> {
fn emfplus_draw_image_places_the_bitmap() {
let p = plus_pic(vec![prec(0x4008, 0x0500 | 4, &bitmap_2x2()), draw_image(4, [10.0, 10.0, 20.0, 40.0])]);
match &p.items[0] {
Item::Bitmap { rect, width, height, rgba } => {
Item::Bitmap { rect, width, height, rgba, .. } => {
assert_eq!((*width, *height), (2, 2));
assert_eq!(rect, &[0.0, 0.0, 20.0, 40.0]);
assert_eq!(&rgba[..8], &[255, 0, 0, 255, 0, 255, 0, 255]);