Skip to content

Commit 7481405

Browse files
committed
Add COLRv1 rendering tests
Four tests using a subsetted Nabla COLRv1 font: - render produces a non-empty image - cached glyph tiles contain actual color (not just grayscale) - glyph cache is reused across words - same font compared to itself yields zero pixel diff
1 parent 7ab92cd commit 7481405

2 files changed

Lines changed: 79 additions & 0 deletions

File tree

diffenator3-lib/src/render/colorrenderer.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,85 @@ impl<'a> ColorRenderer<'a> {
272272
}
273273
}
274274

275+
#[cfg(test)]
276+
mod tests {
277+
use super::*;
278+
279+
fn load_test_font() -> Vec<u8> {
280+
std::fs::read("test-data/Nabla-subset.ttf").expect("missing test font")
281+
}
282+
283+
#[test]
284+
fn colrv1_render_produces_non_empty_image() {
285+
let data = load_test_font();
286+
let dfont = DFont::new(&data);
287+
let mut renderer = ColorRenderer::new(&dfont, 32.0, None, None);
288+
let (buffer, img) = renderer
289+
.render_string("hello")
290+
.expect("render_string returned None");
291+
292+
assert!(!buffer.is_empty(), "serialized buffer should not be empty");
293+
assert!(img.width() > 0 && img.height() > 0, "image has zero size");
294+
295+
let non_zero = img.pixels().filter(|p| p.0[0] > 0).count();
296+
assert!(non_zero > 0, "image is completely blank");
297+
}
298+
299+
#[test]
300+
fn colrv1_glyph_cache_is_reused() {
301+
let data = load_test_font();
302+
let dfont = DFont::new(&data);
303+
let mut renderer = ColorRenderer::new(&dfont, 32.0, None, None);
304+
305+
// "ll" shares the same glyph; after rendering, the cache should contain it
306+
renderer.render_string("hello").unwrap();
307+
let cache_size_after_hello = renderer.cache.len();
308+
309+
// "lo" reuses 'l' and 'o' which are already cached
310+
renderer.render_string("lo").unwrap();
311+
let cache_size_after_lo = renderer.cache.len();
312+
313+
assert_eq!(
314+
cache_size_after_hello, cache_size_after_lo,
315+
"cache grew when all glyphs should already have been cached"
316+
);
317+
}
318+
319+
#[test]
320+
fn colrv1_cached_tiles_contain_color() {
321+
let data = load_test_font();
322+
let dfont = DFont::new(&data);
323+
let mut renderer = ColorRenderer::new(&dfont, 32.0, None, None);
324+
325+
renderer.render_string("hello").unwrap();
326+
327+
// At least one cached tile should have pixels where the RGB channels
328+
// differ from each other, proving we're rendering actual color, not
329+
// just grayscale alpha.
330+
let has_color = renderer.cache.values().any(|tile| {
331+
tile.pixmap.pixels().iter().any(|px| {
332+
let (r, g, b) = (px.red(), px.green(), px.blue());
333+
px.alpha() > 0 && !(r == g && g == b)
334+
})
335+
});
336+
assert!(has_color, "no color pixels found in cached glyph tiles");
337+
}
338+
339+
#[test]
340+
fn colrv1_same_font_has_zero_diff() {
341+
let data = load_test_font();
342+
let dfont = DFont::new(&data);
343+
let mut renderer_a = ColorRenderer::new(&dfont, 32.0, None, None);
344+
let mut renderer_b = ColorRenderer::new(&dfont, 32.0, None, None);
345+
346+
let (_, img_a) = renderer_a.render_string("world").unwrap();
347+
let (_, img_b) = renderer_b.render_string("world").unwrap();
348+
349+
let diff = crate::render::utils::count_differences(img_a, img_b, 0);
350+
assert_eq!(diff, 0, "same font should produce identical images");
351+
}
352+
}
353+
275354
/// Read the first CPAL palette from a font.
276355
fn read_cpal_palette(font: &skrifa::FontRef) -> Vec<PaletteColor> {
277356
let cpal = match font.cpal() {
47 KB
Binary file not shown.

0 commit comments

Comments
 (0)