//! What does `forced_backdrop` cost IN PIXELS on the screens it decides? //! //! `forced_backdrop_necessity.rs` answers "does the derived ORDER move", which is //! a property of the sort. The port agent then pointed out — correctly — that its //! re-run of that probe was **my code executed twice**, not a second witness, so //! the disc-wide 62 has one measurement behind it and only `GP_TITLE` has two. //! //! This does not fix that (it is still this crate), but it moves the question to a //! **different layer**: render each deciding build twice, once in the order //! `compose` derives and once with the `forced_backdrop` fallback removed, and //! count the pixels that differ. "The order moved" and "the picture moved" are not //! the same claim, and the second is the one anybody cares about — the tie-break //! work already found overlapping reorders that cost exactly zero pixels. //! //! Each entry carries its own CONTROL: the pixel count of the composite itself. //! If a build renders empty, its zero means the instrument saw nothing, not that //! the rule is free. //! //! cargo run -p sylpheed-formats --example forced_backdrop_pixel_cost -- [pak...] //! //! With no argument it walks **every `dat/*.pak`** — the necessity probe defaulted //! to `GP_TITLE`, which made a bare run report a thirteenth of the census and read //! like the whole thing. use std::path::PathBuf; use sylpheed_formats::{pak::PakArchive, ui_layout}; use ui_layout::ComposeOptions; fn order_without_rule(build: &ui_layout::UiBuild, bundle: &[u8]) -> Vec { let mut idx: Vec = (0..build.elements.len()).collect(); idx.sort_by_key(|&i| { let el = &build.elements[i]; ( ui_layout::sprite_layer_key(build, bundle, el) .or_else(|| ui_layout::implied_layer_key(&el.name)) .unwrap_or(u32::MAX), i, ) }); idx } fn main() { let root = PathBuf::from(std::env::var("SYLPHEED_DISC").expect("SYLPHEED_DISC")); let mut paks: Vec = std::env::args().skip(1).map(PathBuf::from).collect(); if paks.is_empty() { let mut all: Vec = std::fs::read_dir(root.join("dat")) .expect("dat/") .filter_map(|e| e.ok().map(|e| e.path())) .filter(|p| p.extension().is_some_and(|x| x == "pak")) .collect(); all.sort(); paks = all; } eprintln!("# scanning {} archive(s)", paks.len()); let opts = ComposeOptions { include_primitives: true, backdrop: [0, 0, 0, 255], ..Default::default() }; println!("# archive entry element changed_px total_px ink_px(control) pct"); let (mut decided, mut zero_cost, mut blind) = (0usize, 0usize, 0usize); for pak in &paks { let Ok(ar) = PakArchive::open(pak) else { continue; }; let name = pak.file_name().unwrap().to_string_lossy().to_string(); for (i, e) in ar.entries().iter().enumerate() { let Ok(by) = ar.read(e) else { continue }; let Some(b) = ui_layout::parse_build(&by) else { continue; }; let with = ui_layout::derived_paint_order(&b, &by); let without = order_without_rule(&b, &by); if with == without { continue; } let forced: Vec<&str> = b .elements .iter() .filter(|el| ui_layout::forced_backdrop(&b, el)) .map(|el| el.name.as_str()) .collect(); let a = ui_layout::compose_with_order(&b, &by, opts, None, Some(&with)); let c = ui_layout::compose_with_order(&b, &by, opts, None, Some(&without)); let n = a .rgba .as_chunks::<4>() .0 .iter() .zip(c.rgba.as_chunks::<4>().0.iter()) .filter(|(x, y)| x != y) .count(); // Control: does this build put any ink down at all, against the bare // backdrop? A build that renders to nothing cannot show a reorder. let ink = a .rgba .as_chunks::<4>() .0 .iter() .filter(|p| p[..3] != [0, 0, 0]) .count(); let total = a.rgba.len() / 4; decided += 1; if ink == 0 { blind += 1; } else if n == 0 { zero_cost += 1; } println!( " {name} {i} {} {n} {total} {ink} {:.2}%", forced.join(","), 100.0 * n as f64 / total as f64 ); } } println!("\n# builds whose ORDER the rule decides: {decided}"); println!("# of those, costing ZERO pixels: {zero_cost}"); println!("# of those, BLIND (build renders no ink, control fails): {blind}"); }