Files
designcraft/crates/render/tests/it/glyph_retention.rs
T

105 lines
4.4 KiB
Rust

//! Rendering cache identity and ownership regressions without allocator/RSS assumptions.
use std::sync::Arc;
use designcraft_compose::Cache;
use designcraft_doc::{Document, ParaFormat, SpreadRef};
use designcraft_geom::Rect;
use designcraft_render::{RenderOptions, Renderer};
fn serial_renderer() -> Renderer {
let mut renderer = Renderer::new();
renderer.threads = 0;
renderer
}
fn document() -> (Document, designcraft_doc::StoryId) {
let mut doc = Document::new(&Default::default());
let layer = doc.default_layer();
let (_, story) = doc
.add_text_frame(
SpreadRef::Doc(0),
Rect::new(36.0, 36.0, 500.0, 700.0),
layer,
&"A cached glyph path owns its outline. ".repeat(80),
ParaFormat::default(),
)
.unwrap();
(doc, story)
}
#[test]
fn glyph_paths_do_not_own_expired_composed_story_buffers() {
let (doc, sid) = document();
let cache = Cache::new();
let mut renderer = serial_renderer();
renderer.threads = 0;
let layout = cache.get(&doc, sid, None);
let lifetime = Arc::downgrade(&layout);
let initial = renderer.render_page(&doc, &cache, 0, 1.0, false, &RenderOptions::default()).unwrap();
let frames = renderer.cached_frames();
assert!(frames > 0, "the regression requires actual cached glyph paths");
drop(layout);
assert!(lifetime.upgrade().is_some(), "the composition cache still owns this layout");
cache.clear();
assert!(lifetime.upgrade().is_none(), "glyph-path identity must not keep all story layout buffers alive");
assert_eq!(renderer.cached_frames(), frames, "do not achieve release by evicting cached paths");
let fresh = serial_renderer().render_page(&doc, &Cache::new(), 0, 1.0, false, &RenderOptions::default()).unwrap();
let rebuilt = renderer.render_page(&doc, &cache, 0, 1.0, false, &RenderOptions::default()).unwrap();
assert_eq!(rebuilt.pixels, initial.pixels);
assert_eq!(rebuilt.pixels, fresh.pixels);
}
#[test]
fn repeated_cache_generations_preserve_pixels_and_do_not_pin_old_layouts() {
let (doc, sid) = document();
let cache = Cache::new();
let mut renderer = serial_renderer();
renderer.threads = 0;
let reference = serial_renderer().render_page(&doc, &Cache::new(), 0, 1.0, false, &RenderOptions::default()).unwrap();
for _ in 0..16 {
let layout = cache.get(&doc, sid, None);
let lifetime = Arc::downgrade(&layout);
let cold = renderer.render_page(&doc, &cache, 0, 1.0, false, &RenderOptions::default()).unwrap();
let frames = renderer.cached_frames();
let warm = renderer.render_page(&doc, &cache, 0, 1.0, false, &RenderOptions::default()).unwrap();
assert_eq!(cold.pixels, reference.pixels);
assert_eq!(warm.pixels, reference.pixels);
assert_eq!(renderer.cached_frames(), frames, "warm render must reuse existing glyph entries");
drop(layout);
cache.clear();
assert!(lifetime.upgrade().is_none());
}
}
#[test]
fn edit_style_decoration_and_snapshot_restoration_match_fresh_pixels() {
let (original, sid) = document();
let mut edited = original.clone();
edited.story_mut(sid).unwrap().insert(0, "é changed text. ");
assert!(edited.story(sid).unwrap().text.starts_with("é changed text. "));
let mut styled = edited.clone();
for style in &mut styled.styles_mut().paragraph {
style.chars.font_family = Some("Source Sans 3".into());
style.chars.underline = Some(true);
style.chars.strikethrough = Some(true);
}
let cache = Cache::new();
let mut renderer = serial_renderer();
renderer.threads = 0;
let mut states = Vec::new();
for doc in [&original, &edited, &styled, &edited, &original, &edited, &styled] {
doc.check().unwrap();
let warm = renderer.render_page(doc, &cache, 0, 1.0, false, &RenderOptions::default()).unwrap();
let fresh = serial_renderer().render_page(doc, &Cache::new(), 0, 1.0, false, &RenderOptions::default()).unwrap();
assert_eq!(warm.pixels, fresh.pixels);
states.push(warm.pixels);
}
assert_ne!(states[0], states[1], "text edit must affect the viewport");
assert_ne!(states[1], states[2], "font and decorations must affect the viewport");
assert_eq!(states[0], states[4], "original snapshot restored exactly");
assert_eq!(states[1], states[3]);
assert_eq!(states[1], states[5]);
assert_eq!(states[2], states[6], "styled snapshot restored exactly");
}