From 9dca4c2f7833055edd3c1682e98dcc3f86b7e31b Mon Sep 17 00:00:00 2001 From: Martin Haug Date: Wed, 8 Jun 2022 17:05:07 +0200 Subject: [PATCH] Preallocate Page Refs --- src/export/pdf.rs | 108 +++++++++++++++++++++------------------------- 1 file changed, 49 insertions(+), 59 deletions(-) diff --git a/src/export/pdf.rs b/src/export/pdf.rs index b5768755b..f8144ad93 100644 --- a/src/export/pdf.rs +++ b/src/export/pdf.rs @@ -53,6 +53,8 @@ struct PdfExporter<'a> { glyph_sets: HashMap>, image_map: Remapper, image_refs: Vec, + page_refs: Vec, + heading_tree: Vec, } impl<'a> PdfExporter<'a> { @@ -68,6 +70,8 @@ impl<'a> PdfExporter<'a> { glyph_sets: HashMap::new(), image_map: Remapper::new(), image_refs: vec![], + page_refs: vec![], + heading_tree: vec![], } } @@ -81,7 +85,9 @@ impl<'a> PdfExporter<'a> { fn build_pages(&mut self, frames: &[Arc]) { for frame in frames { - let page = PageExporter::new(self).export(frame); + let page_id = self.alloc.bump(); + self.page_refs.push(page_id); + let page = PageExporter::new(self, page_id).export(frame); self.pages.push(page); } } @@ -306,43 +312,34 @@ impl<'a> PdfExporter<'a> { let page_tree_ref = self.alloc.bump(); // The page objects (non-root nodes in the page tree). - let mut page_refs = vec![]; - let mut page_heights = vec![]; - for page in &self.pages { - let page_id = self.alloc.bump(); - page_refs.push(page_id); - page_heights.push(page.size.y.to_f32()); - } + let mut page_heights = + self.pages.iter().map(|page| page.size.y.to_f32()).collect(); let mut languages = HashMap::new(); - let mut heading_tree: Vec = vec![]; - for (page, page_id) in - std::mem::take(&mut self.pages).into_iter().zip(page_refs.iter()) + for (page, page_id) in std::mem::take(&mut self.pages) + .into_iter() + .zip(self.page_refs.clone().iter()) { self.write_page( page, *page_id, - &page_refs, page_tree_ref, &mut languages, - &mut heading_tree, &mut page_heights, ); } - self.write_page_tree(&page_refs, page_tree_ref); - self.write_catalog(page_tree_ref, &languages, &heading_tree); + self.write_page_tree(page_tree_ref); + self.write_catalog(page_tree_ref, &languages); } fn write_page( &mut self, page: Page, page_id: Ref, - page_refs: &[Ref], page_tree_ref: Ref, languages: &mut HashMap, - heading_tree: &mut Vec, page_heights: &mut Vec, ) { let content_id = self.alloc.bump(); @@ -371,7 +368,7 @@ impl<'a> PdfExporter<'a> { link.action() .action_type(ActionType::GoTo) .destination_direct() - .page(page_refs[index]) + .page(self.page_refs[index]) .xyz(loc.pos.x.to_f32(), height - loc.pos.y.to_f32(), None); } } @@ -387,24 +384,16 @@ impl<'a> PdfExporter<'a> { .or_insert_with(|| count); } - for heading in page.headings.into_iter() { - if let Some(last) = heading_tree.last_mut() { - if !last.insert(heading.clone(), page_id, 1) { - heading_tree.push(HeadingNode::leaf(heading, page_id)) - } - } else { - heading_tree.push(HeadingNode::leaf(heading, page_id)) - } - } - self.writer .stream(content_id, &deflate(&page.content.finish())) .filter(Filter::FlateDecode); } - fn write_page_tree(&mut self, page_refs: &[Ref], page_tree_ref: Ref) { + fn write_page_tree(&mut self, page_tree_ref: Ref) { let mut pages = self.writer.pages(page_tree_ref); - pages.count(page_refs.len() as i32).kids(page_refs.iter().copied()); + pages + .count(self.page_refs.len() as i32) + .kids(self.page_refs.iter().copied()); let mut resources = pages.resources(); let mut spaces = resources.color_spaces(); @@ -431,31 +420,26 @@ impl<'a> PdfExporter<'a> { pages.finish(); } - fn write_catalog( - &mut self, - page_tree_ref: Ref, - languages: &HashMap, - heading_tree: &Vec, - ) { + fn write_catalog(&mut self, page_tree_ref: Ref, languages: &HashMap) { // Build the outline tree. let outline_root_id = self.alloc.bump(); let outline_start_ref = self.alloc; - for (i, node) in heading_tree.iter().enumerate() { + for (i, node) in std::mem::take(&mut self.heading_tree).iter().enumerate() { self.write_outline_item( node, i == 0, - i + 1 == heading_tree.len(), + i + 1 == self.heading_tree.len(), outline_root_id, ); } - if !heading_tree.is_empty() { + if !self.heading_tree.is_empty() { let mut outline_root = self.writer.outline(outline_root_id); outline_root.first(outline_start_ref); outline_root.last(Ref::new(self.alloc.get() - 1)); - outline_root.count(heading_tree.len() as i32); + outline_root.count(self.heading_tree.len() as i32); } let lang = languages @@ -475,7 +459,7 @@ impl<'a> PdfExporter<'a> { catalog.pages(page_tree_ref); catalog.viewer_preferences().direction(dir); - if !heading_tree.is_empty() { + if !self.heading_tree.is_empty() { catalog.outlines(outline_root_id); } @@ -516,7 +500,7 @@ impl<'a> PdfExporter<'a> { } outline.title(TextStr(&node.heading.content)); - outline.dest_direct().page(node.page).xyz( + outline.dest_direct().page(node.heading.page).xyz( node.heading.position.x.to_f32(), (node.heading.position.y + Length::pt(3.0)).to_f32(), None, @@ -538,13 +522,14 @@ struct PageExporter<'a> { font_map: &'a mut Remapper, image_map: &'a mut Remapper, glyphs: &'a mut HashMap>, + heading_tree: &'a mut Vec, + page_ref: Ref, languages: HashMap, bottom: f32, content: Content, links: Vec<(Destination, Rect)>, state: State, saves: Vec, - headings: Vec, } /// Data for an exported page. @@ -553,7 +538,6 @@ struct Page { content: Content, links: Vec<(Destination, Rect)>, languages: HashMap, - headings: Vec, } /// A simulated graphics state used to deduplicate graphics state changes and @@ -574,57 +558,55 @@ struct Heading { content: EcoString, level: usize, position: Point, + page: Ref, } #[derive(Debug, Clone)] struct HeadingNode { heading: Heading, - page: Ref, children: Vec, } impl HeadingNode { - fn leaf(heading: Heading, page: Ref) -> Self { - HeadingNode { heading, page, children: Vec::new() } + fn leaf(heading: Heading) -> Self { + HeadingNode { heading, children: Vec::new() } } fn len(&self) -> usize { 1 + self.children.iter().map(|c| c.len()).sum::() } - fn insert(&mut self, other: Heading, page: Ref, level: usize) -> bool { + fn insert(&mut self, other: Heading, level: usize) -> bool { if level >= other.level { return false; } if !self.children.is_empty() && level + 1 > other.level { - return self.children.last_mut().unwrap().insert(other, page, level + 1); + return self.children.last_mut().unwrap().insert(other, level + 1); } - self.children.push(HeadingNode { - heading: other, - page, - children: Vec::new(), - }); + self.children + .push(HeadingNode { heading: other, children: Vec::new() }); true } } impl<'a> PageExporter<'a> { - fn new(exporter: &'a mut PdfExporter) -> Self { + fn new(exporter: &'a mut PdfExporter, page_ref: Ref) -> Self { Self { fonts: exporter.fonts, font_map: &mut exporter.face_map, image_map: &mut exporter.image_map, glyphs: &mut exporter.glyph_sets, + heading_tree: &mut exporter.heading_tree, + page_ref, languages: HashMap::new(), bottom: 0.0, content: Content::new(), links: vec![], state: State::default(), saves: vec![], - headings: vec![], } } @@ -645,17 +627,25 @@ impl<'a> PageExporter<'a> { content: self.content, links: self.links, languages: self.languages, - headings: self.headings, } } fn write_frame(&mut self, frame: &Frame) { if let Some(Role::Heading(level)) = frame.role() { - self.headings.push(Heading { + let heading = Heading { position: Point::new(self.state.transform.tx, self.state.transform.ty), content: frame.inner_text(), + page: self.page_ref, level, - }) + }; + + if let Some(last) = self.heading_tree.last_mut() { + if !last.insert(heading.clone(), 1) { + self.heading_tree.push(HeadingNode::leaf(heading)) + } + } else { + self.heading_tree.push(HeadingNode::leaf(heading)) + } } for &(pos, ref element) in &frame.elements {