mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-12 06:35:03 +00:00
PDF scan: note each font resource dictionary once per page walk
This commit is contained in:
@@ -455,12 +455,15 @@ fn blank_tail(mut bytes: &[u8]) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
struct Walker<'w, 'p> {
|
||||
pub(crate) struct Walker<'w, 'p> {
|
||||
ocgs: &'w mut Ocgs,
|
||||
/// The groups that are off for the interpreter (none once [`all_on`] turned them on).
|
||||
off: HashSet<ObjectIdentifier>,
|
||||
xref: &'p craft_pdf::syntax::xref::XRef,
|
||||
fonts: &'w mut FontNames,
|
||||
pub(crate) fonts: &'w mut FontNames,
|
||||
/// The font dictionaries ([`Dict::cache_key`]) whose fonts were noted: a form drawn again with
|
||||
/// the same resources isn't read for its fonts again.
|
||||
pub(crate) font_dicts: HashSet<u128>,
|
||||
visible: Vec<bool>,
|
||||
ops: usize,
|
||||
max_ops: usize,
|
||||
@@ -632,6 +635,9 @@ impl Walker<'_, '_> {
|
||||
}
|
||||
|
||||
fn note_fonts(&mut self, res: &Resources<'_>) {
|
||||
if !self.font_dicts.insert(res.fonts.cache_key()) {
|
||||
return;
|
||||
}
|
||||
for key in res.fonts.keys() {
|
||||
if let Some(f) = res.fonts.get::<Dict<'_>>(key.as_ref())
|
||||
&& let Some(name) = font_name(&f)
|
||||
@@ -1049,13 +1055,20 @@ pub(crate) fn scan_page(page: &Page<'_>, ocgs: &mut Ocgs, all_on: bool, fonts: &
|
||||
if scan.cut { Err(incomplete_content()) } else { Ok(scan) }
|
||||
}
|
||||
|
||||
fn walk_page<'w, 'p>(page: &Page<'p>, ocgs: &'w mut Ocgs, all_on: bool, fonts: &'w mut FontNames, max_form_bytes: usize) -> Walker<'w, 'p> {
|
||||
pub(crate) fn walk_page<'w, 'p>(
|
||||
page: &Page<'p>,
|
||||
ocgs: &'w mut Ocgs,
|
||||
all_on: bool,
|
||||
fonts: &'w mut FontNames,
|
||||
max_form_bytes: usize,
|
||||
) -> Walker<'w, 'p> {
|
||||
let off = if all_on { HashSet::new() } else { ocgs.off.clone() };
|
||||
let mut w = Walker {
|
||||
ocgs,
|
||||
off,
|
||||
xref: page.xref(),
|
||||
fonts,
|
||||
font_dicts: HashSet::new(),
|
||||
visible: vec![],
|
||||
ops: 0,
|
||||
max_ops: max_ops(),
|
||||
|
||||
@@ -474,6 +474,22 @@ fn a_composite_font_is_noted_by_its_cid_font_name() {
|
||||
assert_eq!(noted("<< /Type /Font /Subtype /Type1 /BaseFont /Vctest-Identity-H >>"), ["Vctest-Identity-H"]);
|
||||
}
|
||||
|
||||
/// A form drawn again and again without resources of its own reads the page's font dictionary once,
|
||||
/// not at every drawing; the fonts are noted all the same.
|
||||
#[test]
|
||||
fn a_form_drawn_many_times_reads_its_font_resources_once() {
|
||||
let form_no = first_extra(1);
|
||||
let form = stream("/Type /XObject /Subtype /Form /BBox [0 0 100 100]", "0 0 1 rg 50 50 30 30 re f");
|
||||
let resources = format!("/Font << /F1 << /Type /Font /Subtype /Type1 /BaseFont /Helvetica >> >> /XObject << /X0 {form_no} 0 R >>");
|
||||
let page = PdfPage { resources, ..PdfPage::new(100.0, 100.0, &format!("BT /F1 24 Tf 10 30 Td (Hi) Tj ET {}", "/X0 Do ".repeat(500))) };
|
||||
let pdf = craft_pdf::syntax::Pdf::new(pdf_with(&[page], &[&form], None)).unwrap();
|
||||
let mut fonts = crate::import_scan::FontNames::new();
|
||||
let mut ocgs = crate::import_scan::Ocgs::read(&pdf);
|
||||
let walk = crate::import_scan::walk_page(&pdf.pages()[0], &mut ocgs, false, &mut fonts, pdf.decode_limits().max_decoded_stream());
|
||||
assert_eq!(walk.font_dicts.len(), 1);
|
||||
assert_eq!(walk.fonts.len(), 1);
|
||||
}
|
||||
|
||||
/// A value of the page's font dictionary that the reader can't parse (a name with a broken `#`
|
||||
/// escape, a number with a stray `-`) is left out when the page's fonts are noted, and the fonts
|
||||
/// after it are noted.
|
||||
|
||||
Reference in New Issue
Block a user