mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-12 01:54:15 +00:00
Merge main into feat/character-anti-aliasing-method
This commit is contained in:
@@ -121,6 +121,8 @@ impl Renderer {
|
||||
}
|
||||
} else if f.opts.mark_undecoded_images && !pending && (!outline || f.doc.setup.outline_images) {
|
||||
self.draw_undecoded_mark(ctx, f, im, area);
|
||||
} else if !pending && !outline {
|
||||
self.image_left_out = self.image_left_out.map(|_| true);
|
||||
}
|
||||
if outline {
|
||||
let mut p = rect.to_path(0.1);
|
||||
|
||||
@@ -166,9 +166,9 @@ impl Renderer {
|
||||
// mask is rendered over those only.
|
||||
let bounds = self.bounds_of(f.symbols, a);
|
||||
let Some((r, sub)) = group::area(ctx, f, bounds) else { return };
|
||||
let mask = Some(self.mask_values(&sub, m, r.w, r.h));
|
||||
let Some(mask) = self.mask_values(&sub, m, r.w, r.h) else { return };
|
||||
let blends = a.blend != vectorcraft_color::BlendMode::Normal || (!a.isolate && self.blends_through(a));
|
||||
self.group(ctx, f, Composite { mask, blends, bounds, ..Default::default() }, &mut |r, c, fr| r.draw_arc_body(c, fr, a));
|
||||
self.group(ctx, f, Composite { mask: Some(mask), blends, bounds, ..Default::default() }, &mut |r, c, fr| r.draw_arc_body(c, fr, a));
|
||||
return;
|
||||
}
|
||||
self.draw_arc_body(ctx, f, a);
|
||||
@@ -176,7 +176,7 @@ impl Renderer {
|
||||
|
||||
/// The coverage of opacity mask `m` per output pixel (row-major): its art rendered offscreen,
|
||||
/// as luminance ([`mask_value`]).
|
||||
pub(super) fn mask_values(&mut self, f: &Frame, m: &vectorcraft_doc::OpacityMask, w: u16, h: u16) -> Vec<u8> {
|
||||
pub(super) fn mask_values(&mut self, f: &Frame, m: &vectorcraft_doc::OpacityMask, w: u16, h: u16) -> Option<Vec<u8>> {
|
||||
let mut mctx = f.offscreen_context(w, h);
|
||||
// Mask art is a picture of its own: it takes no part in a knockout group around the object,
|
||||
// and its luminance is that of its screen colours.
|
||||
@@ -187,10 +187,22 @@ impl Renderer {
|
||||
std::mem::take(&mut self.clip_paths),
|
||||
self.picture.take(),
|
||||
);
|
||||
let image_left_out = self.image_left_out.replace(false);
|
||||
let failures = crate::paint::decode_failures();
|
||||
let pattern_images_left_out = crate::pattern::images_left_out();
|
||||
self.draw_kept_node(&mut mctx, &Frame { mt: false, ink: Ink::Display, ..*f }, &m.art);
|
||||
// Pattern tiles are drawn without undecoded-image marks, so an image a tile left out counts
|
||||
// with the marks on too.
|
||||
let incomplete = self.image_left_out.unwrap_or(false)
|
||||
|| crate::pattern::images_left_out() > pattern_images_left_out
|
||||
|| (!f.opts.mark_undecoded_images && crate::paint::decode_failures() > failures);
|
||||
self.image_left_out = image_left_out.map(|outer| outer || incomplete);
|
||||
let pm = self.finish(&mut mctx, self.raster);
|
||||
(self.knockout, self.nested, self.backdrop, self.clip_paths, self.picture) = outer;
|
||||
pm.data().iter().map(|p| mask_value(p.r, p.g, p.b, p.a, m.clip, m.invert)).collect()
|
||||
if incomplete {
|
||||
return None;
|
||||
}
|
||||
Some(pm.data().iter().map(|p| mask_value(p.r, p.g, p.b, p.a, m.clip, m.invert)).collect())
|
||||
}
|
||||
|
||||
/// Everything [`Self::draw_arc`] does after culling.
|
||||
@@ -593,6 +605,13 @@ impl Renderer {
|
||||
if self.skipped(f, c) {
|
||||
continue;
|
||||
}
|
||||
// Hard-edge coverage is binary, so an opaque fill replaces its knockout shape exactly.
|
||||
// This also serves supersampled exports. Analytical AA keeps the erase/add passes:
|
||||
// their intermediate rounding can differ from source-over at partially covered edges.
|
||||
if f.opts.anti_alias == crate::AntiAlias::None && crate::node_checks::opaque_knockout_fill(c) {
|
||||
self.draw_arc(ctx, f, c);
|
||||
continue;
|
||||
}
|
||||
self.knockout_pass(ctx, f, c, Compose::DestOut);
|
||||
match &backdrop {
|
||||
Some(b) => self.knockout_over(ctx, f, c, b),
|
||||
|
||||
Reference in New Issue
Block a user