diff --git a/src/doc.rs b/src/doc.rs index a7d44897e..304b4936e 100644 --- a/src/doc.rs +++ b/src/doc.rs @@ -27,6 +27,8 @@ pub struct Page { /// A text layouting action. #[derive(Debug, Clone)] pub enum TextAction { + /// Move to an absolute position. + MoveAbsolute(Position), /// Move from the _start_ of the current line by an (x, y) offset. MoveNewline(Position), /// Write text starting at the current position. diff --git a/src/export/pdf.rs b/src/export/pdf.rs index 87b9d52c8..b521079ec 100644 --- a/src/export/pdf.rs +++ b/src/export/pdf.rs @@ -8,9 +8,9 @@ use pdf::doc::{Catalog, PageTree, Page, Resource, Text}; use pdf::font::{Type0Font, CIDFont, CIDFontType, CIDSystemInfo, FontDescriptor, FontFlags}; use pdf::font::{GlyphUnit, CMap, CMapEncoding, WidthRecord, FontStream}; -use crate::doc::{Document, TextAction}; +use crate::doc::{Document, Page as DocPage, TextAction}; use crate::font::{Font, FontError}; -use crate::layout::Size; +use crate::layout::{Size, Position}; /// Exports documents into _PDFs_. @@ -96,8 +96,8 @@ impl<'d, W: Write> PdfEngine<'d, W> { /// Write the complete document. fn write(&mut self) -> PdfResult { self.writer.write_header(&Version::new(1, 7))?; + self.write_page_tree()?; self.write_pages()?; - self.write_contents()?; self.write_fonts()?; self.writer.write_xref_table()?; self.writer.write_trailer(&Trailer::new(self.offsets.catalog))?; @@ -105,13 +105,14 @@ impl<'d, W: Write> PdfEngine<'d, W> { } /// Write the document catalog and page tree. - fn write_pages(&mut self) -> PdfResult<()> { + fn write_page_tree(&mut self) -> PdfResult<()> { // The document catalog self.writer.write_obj(self.offsets.catalog, &Catalog::new(self.offsets.page_tree))?; // The font resources + let offset = self.offsets.fonts.0; let fonts = (0 .. self.fonts.len()) - .map(|i| Resource::Font((i + 1) as u32, self.offsets.fonts.0 + 5 * i as u32)); + .map(|i| Resource::Font((i + 1) as u32, offset + 5 * i as u32)); // The root page tree self.writer.write_obj(self.offsets.page_tree, PageTree::new() @@ -131,21 +132,28 @@ impl<'d, W: Write> PdfEngine<'d, W> { } /// Write the contents of all pages. - fn write_contents(&mut self) -> PdfResult<()> { + fn write_pages(&mut self) -> PdfResult<()> { for (id, page) in ids(self.offsets.contents).zip(&self.doc.pages) { - self.write_text_actions(id, &page.actions)?; + self.write_page(id, &page)?; } Ok(()) } - /// Write a series of text actions. - fn write_text_actions(&mut self, id: u32, actions: &[TextAction]) -> PdfResult<()> { + /// Write the content of a page. + fn write_page(&mut self, id: u32, page: &DocPage) -> PdfResult<()> { let mut font = 0; let mut text = Text::new(); - for action in actions { + text.tm(1.0, 0.0, 0.0, 1.0, 0.0, page.height.to_points()); + + for action in &page.actions { match action { - TextAction::MoveNewline(x, y) => { text.td(x.to_points(), y.to_points()); }, + TextAction::MoveAbsolute(pos) => { + let x = pos.x.to_points(); + let y = (page.height - pos.y).to_points(); + text.tm(1.0, 0.0, 0.0, 1.0, x, y); + }, + TextAction::MoveNewline(pos) => { text.td(pos.x.to_points(), -pos.y.to_points()); }, TextAction::WriteText(string) => { text.tj(self.fonts[font].encode(&string)); }, TextAction::SetFont(id, size) => { font = *id; diff --git a/src/layout/boxed.rs b/src/layout/boxed.rs index cfdf51f24..c240db0be 100644 --- a/src/layout/boxed.rs +++ b/src/layout/boxed.rs @@ -22,7 +22,7 @@ impl<'a, 'p> BoxLayouter<'a, 'p> { /// Add a sublayout. pub fn add_layout_absolute(&mut self, position: Position, layout: Layout) { - self.actions.push(TextAction::MoveNewline(position)); + self.actions.push(TextAction::MoveAbsolute(position)); self.actions.extend(layout.actions); } } diff --git a/src/layout/size.rs b/src/layout/size.rs index c4686966e..92a4c1131 100644 --- a/src/layout/size.rs +++ b/src/layout/size.rs @@ -15,6 +15,12 @@ pub struct Position { pub y: Size, } +impl Position { + /// Create a zeroed position. + #[inline] + pub fn zero() -> Position { Position { x: Size::zero(), y: Size::zero() } } +} + /// Size of a box in 2-dimensional space. #[derive(Debug, Copy, Clone, PartialEq, Default)] pub struct Extent { diff --git a/src/layout/text.rs b/src/layout/text.rs index 0f1055313..11a1e38cf 100644 --- a/src/layout/text.rs +++ b/src/layout/text.rs @@ -145,8 +145,9 @@ impl<'a, 'p> TextFinisher<'a, 'p> { let mut units = Vec::new(); mem::swap(&mut self.layouter.units, &mut units); - // Move to the top-left corner of the layout space. - self.move_start(); + // Move from the origin one line below because the y-component of the origin is the + // baseline. + self.move_newline(1.0); for unit in units { match unit { @@ -206,29 +207,18 @@ impl<'a, 'p> TextFinisher<'a, 'p> { } } - /// Move to the top-left corner of the layout space. - fn move_start(&mut self) { - self.actions.push(TextAction::MoveNewline(Position { - x: Size::zero(), - y: self.layouter.ctx.max_extent.height - - Size::from_points(self.layouter.ctx.text_style.font_size) - })); - } - /// Move to the next line. A factor of 1.0 uses the default line spacing. fn move_newline(&mut self, factor: f32) { - if self.active_font != std::usize::MAX { - let vertical = Size::from_points(self.layouter.ctx.text_style.font_size) - * self.layouter.ctx.text_style.line_spacing - * factor; + let vertical = Size::from_points(self.layouter.ctx.text_style.font_size) + * self.layouter.ctx.text_style.line_spacing + * factor; - self.actions.push(TextAction::MoveNewline(Position { - x: Size::zero(), - y: -vertical - })); + self.actions.push(TextAction::MoveNewline(Position { + x: Size::zero(), + y: vertical + })); - self.current_width = Size::zero(); - } + self.current_width = Size::zero(); } /// Output a text action containing the buffered text and reset the buffer.