mirror of
https://github.com/storytold/designcraft.git
synced 2026-10-28 12:16:53 -06:00
fix(compose): key parent-page compositions by absolute page index
Parent-page text now uses the absolute page index as its cache key, so repeated page numbers and renumbering do not reuse another page's composition. Validation: targeted canvas and PDF regressions, plus all six cargo xtask ci gates on main after #514 (1,179 native tests passed, 3 ignored; 15 crates passed WASM compilation checks). Task: #523
This commit is contained in:
@@ -66,7 +66,7 @@ fn shadow(sigma: f64, color: peniko::Color) -> Filter {
|
||||
|
||||
impl Renderer {
|
||||
/// Draw an item with soft effects: below-effects, the (feathered) body, inner shadow.
|
||||
pub(crate) fn draw_item_fx(&mut self, ctx: &mut RenderContext, f: &Frame, it: &Item, bp: &BezPath, xf: Affine, page_name: Option<&str>) {
|
||||
pub(crate) fn draw_item_fx(&mut self, ctx: &mut RenderContext, f: &Frame, it: &Item, bp: &BezPath, xf: Affine, page: Option<usize>) {
|
||||
let doc = f.doc;
|
||||
let e = &it.effects;
|
||||
let sw = if it.stroke.is_none() { 0.0 } else { it.stroke.extent() };
|
||||
@@ -95,7 +95,7 @@ impl Renderer {
|
||||
let moved = Frame { view: fr.view * Affine::translate(off), ..*fr };
|
||||
c.set_transform(moved.view);
|
||||
c.push_layer(None, None, None, None, Some(filter));
|
||||
me.draw_body(c, &moved, it, bp, xf, page_name);
|
||||
me.draw_body(c, &moved, it, bp, xf, page);
|
||||
if grow > 0.0 && solid {
|
||||
c.set_transform(moved.view * xf);
|
||||
c.set_paint(peniko::Color::BLACK);
|
||||
@@ -119,7 +119,7 @@ impl Renderer {
|
||||
self.with_filters(ctx, f, reach, w / 4.0, |me, c, fr| {
|
||||
c.set_transform(fr.view * xf);
|
||||
c.push_clip_layer(bp);
|
||||
me.draw_body(c, fr, it, bp, xf, page_name);
|
||||
me.draw_body(c, fr, it, bp, xf, page);
|
||||
// Keep the body where the blurred inset silhouette is.
|
||||
c.set_transform(Affine::IDENTITY);
|
||||
c.push_layer(None, Some(BlendMode::new(Mix::Normal, Compose::DestIn)), None, None, None);
|
||||
@@ -139,7 +139,7 @@ impl Renderer {
|
||||
c.pop_layer();
|
||||
});
|
||||
} else {
|
||||
self.draw_body(ctx, f, it, bp, xf, page_name);
|
||||
self.draw_body(ctx, f, it, bp, xf, page);
|
||||
}
|
||||
// Directional feather: one fading ramp per side, multiplied in.
|
||||
let df = &e.directional_feather;
|
||||
|
||||
+13
-14
@@ -216,7 +216,7 @@ pub struct Renderer {
|
||||
resources: Resources,
|
||||
glyphs: text::GlyphCache,
|
||||
/// Composed stories looked up during the current render.
|
||||
stories: HashMap<(StoryId, Option<String>), Arc<ComposedStory>>,
|
||||
stories: HashMap<(StoryId, Option<usize>), Arc<ComposedStory>>,
|
||||
pub threads: u16,
|
||||
pub stats: FrameStats,
|
||||
}
|
||||
@@ -408,7 +408,6 @@ impl Renderer {
|
||||
let Some((ppi, ppage)) = doc.parent_page_for(first + pi) else { continue };
|
||||
let parent = &doc.parents[ppi];
|
||||
let dx = page.x - parent.pages[ppage].x;
|
||||
let page_name = doc.page_name(first + pi);
|
||||
let pr = parent.pages[ppage].bounds();
|
||||
for it in &parent.items {
|
||||
if it.layer != layer.id || page.overridden.contains(&it.id) {
|
||||
@@ -419,7 +418,7 @@ impl Renderer {
|
||||
continue;
|
||||
}
|
||||
let _ = pr;
|
||||
self.draw_item(ctx, f, it, Affine::translate((dx, 0.0)), Some(&page_name));
|
||||
self.draw_item(ctx, f, it, Affine::translate((dx, 0.0)), Some(first + pi));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -431,7 +430,7 @@ impl Renderer {
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_item(&mut self, ctx: &mut RenderContext, f: &Frame, it: &Item, parent: Affine, page_name: Option<&str>) {
|
||||
fn draw_item(&mut self, ctx: &mut RenderContext, f: &Frame, it: &Item, parent: Affine, page: Option<usize>) {
|
||||
if it.hidden || f.opts.hidden.contains(&it.id) || f.opts.printing_only && it.nonprinting {
|
||||
return;
|
||||
}
|
||||
@@ -458,7 +457,7 @@ impl Renderer {
|
||||
ctx.set_transform(f.view * xf);
|
||||
ctx.push_clip_layer(&bp);
|
||||
for c in it.children() {
|
||||
self.draw_item(ctx, f, c, xf, page_name);
|
||||
self.draw_item(ctx, f, c, xf, page);
|
||||
}
|
||||
ctx.pop_layer();
|
||||
if !it.stroke.is_none() {
|
||||
@@ -489,11 +488,11 @@ impl Renderer {
|
||||
ctx.fill_path(&c.path.to_bezpath());
|
||||
ctx.pop_layer();
|
||||
}
|
||||
self.draw_item(ctx, f, c, xf, page_name);
|
||||
self.draw_item(ctx, f, c, xf, page);
|
||||
}
|
||||
} else {
|
||||
for c in it.shown_children() {
|
||||
self.draw_item(ctx, f, c, xf, page_name);
|
||||
self.draw_item(ctx, f, c, xf, page);
|
||||
}
|
||||
}
|
||||
if layered {
|
||||
@@ -520,9 +519,9 @@ impl Renderer {
|
||||
ctx.push_layer(None, Some(blend_mode(it.blend)), Some(it.opacity), None, None);
|
||||
}
|
||||
if effects {
|
||||
self.draw_item_fx(ctx, f, it, &bp, xf, page_name);
|
||||
self.draw_item_fx(ctx, f, it, &bp, xf, page);
|
||||
} else {
|
||||
self.draw_body(ctx, f, it, &bp, xf, page_name);
|
||||
self.draw_body(ctx, f, it, &bp, xf, page);
|
||||
}
|
||||
if layered {
|
||||
ctx.pop_layer();
|
||||
@@ -531,18 +530,18 @@ impl Renderer {
|
||||
|
||||
/// The composed story for a frame (memoised for the current render: the cache lookup
|
||||
/// validates the whole thread each time).
|
||||
fn story(&mut self, f: &Frame, sid: StoryId, page_name: Option<&str>) -> Arc<ComposedStory> {
|
||||
let key = (sid, page_name.map(str::to_string));
|
||||
fn story(&mut self, f: &Frame, sid: StoryId, page: Option<usize>) -> Arc<ComposedStory> {
|
||||
let key = (sid, page);
|
||||
if let Some(cs) = self.stories.get(&key) {
|
||||
return cs.clone();
|
||||
}
|
||||
let cs = f.cache.get(f.doc, sid, page_name);
|
||||
let cs = f.cache.get(f.doc, sid, page);
|
||||
self.stories.insert(key, cs.clone());
|
||||
cs
|
||||
}
|
||||
|
||||
/// Fill, content and stroke of a leaf item (no opacity, blend or effects).
|
||||
pub(crate) fn draw_body(&mut self, ctx: &mut RenderContext, f: &Frame, it: &Item, bp: &BezPath, xf: Affine, page_name: Option<&str>) {
|
||||
pub(crate) fn draw_body(&mut self, ctx: &mut RenderContext, f: &Frame, it: &Item, bp: &BezPath, xf: Affine, page: Option<usize>) {
|
||||
let doc = f.doc;
|
||||
// Fill.
|
||||
if !it.fill.is_none() {
|
||||
@@ -575,7 +574,7 @@ impl Renderer {
|
||||
ctx.pop_layer();
|
||||
}
|
||||
Content::Text(tf) => {
|
||||
let cs = self.story(f, tf.story, page_name);
|
||||
let cs = self.story(f, tf.story, page);
|
||||
if let Some(ft) = cs.frame(it.id) {
|
||||
match &tf.options.path {
|
||||
Some(pt) => self.draw_path_text(ctx, f, &cs, ft, xf, bp, pt),
|
||||
|
||||
Reference in New Issue
Block a user