fix(metafile): a full WMF object table is not rescanned for every creation

This commit is contained in:
Dylan M. Taylor
2026-11-03 22:17:45 +07:00
committed by bflatastic
parent 824310e611
commit f854b7a2cf
+25
View File
@@ -429,6 +429,9 @@ impl Player {
let start = self.free_hint.min(self.objects.len());
let i = self.objects.iter().skip(start).position(Option::is_none).map_or(self.objects.len(), |p| p + start);
if i > u16::MAX as usize {
// The table is full past the hint: the next creation looks from the end, not again
// through every slot.
self.free_hint = i;
return;
}
if i == self.objects.len() {
@@ -897,3 +900,25 @@ pub(crate) fn import(bytes: &[u8]) -> Result<Imported, String> {
None => Err("not an EMF or WMF file".into()),
}
}
#[cfg(test)]
mod table_tests {
use super::*;
/// Once the WMF table is full, a rejected creation leaves the hint at its end, so the next
/// ones don't scan every slot again; a freed slot is still found.
#[test]
fn a_full_object_table_is_not_rescanned() {
let mut p = Player::new(Kind::Wmf, Affine::IDENTITY, 1.0, Rect::new(0.0, 0.0, 10.0, 10.0));
for _ in 0..=u16::MAX as usize + 1 {
p.create(Obj::Other);
}
p.delete(5);
p.create(Obj::Other);
p.create(Obj::Other);
assert!(p.free_hint > u16::MAX as usize);
p.delete(7);
p.create(Obj::Other);
assert!(p.objects[7].is_some());
}
}