summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2019-06-22 12:51:06 +0200
committerLaurenz <laurmaedje@gmail.com>2019-06-22 12:51:06 +0200
commitc7ee2b393a369325b3578557e045f2ff94ceab8f (patch)
tree063e371b764b119e378644817cc556c397ebd9dd /src
parentf6fe3b5cdd2805f3975985752f9cb0e04e3daf49 (diff)
Fix top-left text alignment 📐
Diffstat (limited to 'src')
-rw-r--r--src/doc.rs14
-rw-r--r--src/export/pdf.rs55
-rw-r--r--src/font.rs2
-rw-r--r--src/layout/boxed.rs6
-rw-r--r--src/layout/flex.rs4
-rw-r--r--src/layout/mod.rs16
-rw-r--r--src/layout/text.rs10
-rw-r--r--src/size.rs18
8 files changed, 70 insertions, 55 deletions
diff --git a/src/doc.rs b/src/doc.rs
index f08332f6..0b4db73e 100644
--- a/src/doc.rs
+++ b/src/doc.rs
@@ -20,19 +20,17 @@ pub struct Page {
pub width: Size,
/// The height of the page.
pub height: Size,
- /// Text actions specifying how to draw text content on the page.
- pub actions: Vec<TextAction>,
+ /// Layouting actions specifying how to draw content on the page.
+ pub actions: Vec<LayoutAction>,
}
-/// A text layouting action.
+/// A layouting action.
#[derive(Debug, Clone)]
-pub enum TextAction {
+pub enum LayoutAction {
/// Move to an absolute position.
MoveAbsolute(Size2D),
- /// Move from the _start_ of the current line by an (x, y) offset.
- MoveNewline(Size2D),
- /// Write text starting at the current position.
- WriteText(String),
/// Set the font by index and font size.
SetFont(usize, f32),
+ /// Write text starting at the current position.
+ WriteText(String),
}
diff --git a/src/export/pdf.rs b/src/export/pdf.rs
index 1c0d52b0..a09f3b0c 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, Page as DocPage, TextAction};
+use crate::doc::{Document, Page as DocPage, LayoutAction};
use crate::font::{Font, FontError};
-use crate::size::Size;
+use crate::size::{Size, Size2D};
/// Exports documents into _PDFs_.
@@ -72,8 +72,8 @@ impl<'d, W: Write> PdfEngine<'d, W> {
for page in &doc.pages {
for action in &page.actions {
match action {
- TextAction::WriteText(string) => chars[font].extend(string.chars()),
- TextAction::SetFont(id, _) => font = *id,
+ LayoutAction::WriteText(string) => chars[font].extend(string.chars()),
+ LayoutAction::SetFont(id, _) => font = *id,
_ => {},
}
}
@@ -123,7 +123,7 @@ impl<'d, W: Write> PdfEngine<'d, W> {
// The page objects
for (id, page) in ids(self.offsets.pages).zip(&self.doc.pages) {
self.writer.write_obj(id, Page::new(self.offsets.page_tree)
- .media_box(Rect::new(0.0, 0.0, page.width.to_points(), page.height.to_points()))
+ .media_box(Rect::new(0.0, 0.0, page.width.to_pt(), page.height.to_pt()))
.contents(ids(self.offsets.contents))
)?;
}
@@ -141,23 +141,40 @@ impl<'d, W: Write> PdfEngine<'d, W> {
/// 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();
+ // The currently used font.
+ let mut active_font = (std::usize::MAX, 0.0);
+
+ // The last set position and font, these get flushed when content is written.
+ let mut next_pos = Some(Size2D::zero());
+ let mut next_font = None;
- text.tm(1.0, 0.0, 0.0, 1.0, 0.0, page.height.to_points());
+ // The output text.
+ let mut text = Text::new();
for action in &page.actions {
match action {
- 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;
- text.tf(*id as u32 + 1, *size);
+ LayoutAction::MoveAbsolute(pos) => next_pos = Some(*pos),
+ LayoutAction::SetFont(id, size) => next_font = Some((*id, *size)),
+ LayoutAction::WriteText(string) => {
+ // Flush the font if it is different from the current.
+ if let Some((id, size)) = next_font {
+ if (id, size) != active_font {
+ text.tf(id as u32 + 1, size);
+ active_font = (id, size);
+ next_font = None;
+ }
+ }
+
+ // Flush the position.
+ if let Some(pos) = next_pos {
+ let x = pos.x.to_pt();
+ let y = (page.height - pos.y - Size::pt(active_font.1)).to_pt();
+ text.tm(1.0, 0.0, 0.0, 1.0, x, y);
+ next_pos = None;
+ }
+
+ // Write the text.
+ text.tj(self.fonts[active_font.0].encode(&string));
},
}
}
@@ -249,7 +266,7 @@ impl PdfFont {
fn new(font: &Font, chars: &HashSet<char>) -> PdfResult<PdfFont> {
/// Convert a size into a _PDF_ glyph unit.
fn size_to_glyph_unit(size: Size) -> GlyphUnit {
- (1000.0 * size.to_points()).round() as GlyphUnit
+ (1000.0 * size.to_pt()).round() as GlyphUnit
}
// Subset the font using the selected characters.
diff --git a/src/font.rs b/src/font.rs
index 9b13ed32..d11fe75c 100644
--- a/src/font.rs
+++ b/src/font.rs
@@ -60,7 +60,7 @@ impl Font {
// Create a conversion function between font units and sizes.
let font_unit_ratio = 1.0 / (head.units_per_em as f32);
- let font_unit_to_size = |x| Size::points(font_unit_ratio * x as f32);
+ let font_unit_to_size = |x| Size::pt(font_unit_ratio * x as f32);
// Find out the name of the font.
let font_name = name.get_decoded(NameEntry::PostScriptName)
diff --git a/src/layout/boxed.rs b/src/layout/boxed.rs
index e712f650..15af278a 100644
--- a/src/layout/boxed.rs
+++ b/src/layout/boxed.rs
@@ -1,6 +1,6 @@
//! Block-style layouting of boxes.
-use crate::doc::{Document, Page, TextAction};
+use crate::doc::{Document, Page, LayoutAction};
use crate::font::Font;
use crate::size::{Size, Size2D};
use super::{ActionList, LayoutSpace, LayoutResult, LayoutError};
@@ -12,7 +12,7 @@ pub struct BoxLayout {
/// The size of the box.
pub dimensions: Size2D,
/// The actions composing this layout.
- pub actions: Vec<TextAction>,
+ pub actions: Vec<LayoutAction>,
}
impl BoxLayout {
@@ -90,7 +90,7 @@ impl BoxLayouter {
pub fn add_box_absolute(&mut self, position: Size2D, layout: BoxLayout) {
// Move all actions into this layout and translate absolute positions.
self.actions.reset_origin();
- self.actions.add(TextAction::MoveAbsolute(position));
+ self.actions.add(LayoutAction::MoveAbsolute(position));
self.actions.set_origin(position);
self.actions.extend(layout.actions);
}
diff --git a/src/layout/flex.rs b/src/layout/flex.rs
index f966eae2..730b876e 100644
--- a/src/layout/flex.rs
+++ b/src/layout/flex.rs
@@ -1,6 +1,6 @@
//! Flexible and lazy layouting of boxes.
-use crate::doc::TextAction;
+use crate::doc::LayoutAction;
use crate::size::{Size, Size2D};
use super::{BoxLayout, ActionList, LayoutSpace, LayoutResult, LayoutError};
@@ -157,7 +157,7 @@ impl FlexFinisher {
fn append(&mut self, layout: BoxLayout) {
// Move all actions into this layout and translate absolute positions.
self.actions.reset_origin();
- self.actions.add(TextAction::MoveAbsolute(self.cursor));
+ self.actions.add(LayoutAction::MoveAbsolute(self.cursor));
self.actions.set_origin(self.cursor);
self.actions.extend(layout.actions);
diff --git a/src/layout/mod.rs b/src/layout/mod.rs
index 40948a13..b678ab2b 100644
--- a/src/layout/mod.rs
+++ b/src/layout/mod.rs
@@ -1,6 +1,6 @@
//! The layouting engine.
-use crate::doc::TextAction;
+use crate::doc::LayoutAction;
use crate::font::{FontLoader, FontError};
use crate::size::{Size, Size2D, SizeBox};
use crate::syntax::{SyntaxTree, Node};
@@ -86,7 +86,7 @@ impl<'a, 'p> Layouter<'a, 'p> {
padding: SizeBox::zero(),
shrink_to_fit: true,
},
- flex_spacing: (ctx.style.line_spacing - 1.0) * Size::points(ctx.style.font_size),
+ flex_spacing: (ctx.style.line_spacing - 1.0) * Size::pt(ctx.style.font_size),
};
// The mutable context for layouting single pieces of text.
@@ -192,7 +192,7 @@ impl<'a, 'p> Layouter<'a, 'p> {
/// Add the spacing between two paragraphs.
fn add_paragraph_spacing(&mut self) -> LayoutResult<()> {
- let size = Size::points(self.text_ctx.style.font_size)
+ let size = Size::pt(self.text_ctx.style.font_size)
* (self.text_ctx.style.line_spacing * self.text_ctx.style.paragraph_spacing - 1.0);
self.box_layouter.add_space(size)
}
@@ -201,7 +201,7 @@ impl<'a, 'p> Layouter<'a, 'p> {
/// Manipulates and optimizes a list of actions.
#[derive(Debug, Clone)]
pub struct ActionList {
- actions: Vec<TextAction>,
+ actions: Vec<LayoutAction>,
origin: Size2D,
active_font: (usize, f32),
}
@@ -218,8 +218,8 @@ impl ActionList {
/// Add an action to the list if it is not useless
/// (like changing to a font that is already active).
- pub fn add(&mut self, action: TextAction) {
- use TextAction::*;
+ pub fn add(&mut self, action: LayoutAction) {
+ use LayoutAction::*;
match action {
MoveAbsolute(pos) => self.actions.push(MoveAbsolute(self.origin + pos)),
SetFont(index, size) => if (index, size) != self.active_font {
@@ -231,7 +231,7 @@ impl ActionList {
}
/// Add a series of actions.
- pub fn extend<I>(&mut self, actions: I) where I: IntoIterator<Item=TextAction> {
+ pub fn extend<I>(&mut self, actions: I) where I: IntoIterator<Item=LayoutAction> {
for action in actions.into_iter() {
self.add(action);
}
@@ -254,7 +254,7 @@ impl ActionList {
}
/// Return the list of actions as a vector.
- pub fn into_vec(self) -> Vec<TextAction> {
+ pub fn into_vec(self) -> Vec<LayoutAction> {
self.actions
}
}
diff --git a/src/layout/text.rs b/src/layout/text.rs
index 8aa76c4c..0a0241a0 100644
--- a/src/layout/text.rs
+++ b/src/layout/text.rs
@@ -1,6 +1,6 @@
//! Layouting of text into boxes.
-use crate::doc::TextAction;
+use crate::doc::LayoutAction;
use crate::font::FontQuery;
use crate::size::{Size, Size2D};
use super::*;
@@ -39,11 +39,11 @@ pub fn layout(text: &str, ctx: &TextContext) -> LayoutResult<BoxLayout> {
// Change the font if necessary.
if active_font != index {
if !buffer.is_empty() {
- actions.push(TextAction::WriteText(buffer));
+ actions.push(LayoutAction::WriteText(buffer));
buffer = String::new();
}
- actions.push(TextAction::SetFont(index, ctx.style.font_size));
+ actions.push(LayoutAction::SetFont(index, ctx.style.font_size));
active_font = index;
}
@@ -52,11 +52,11 @@ pub fn layout(text: &str, ctx: &TextContext) -> LayoutResult<BoxLayout> {
// Write the remaining characters.
if !buffer.is_empty() {
- actions.push(TextAction::WriteText(buffer));
+ actions.push(LayoutAction::WriteText(buffer));
}
Ok(BoxLayout {
- dimensions: Size2D::new(width, Size::points(ctx.style.font_size)),
+ dimensions: Size2D::new(width, Size::pt(ctx.style.font_size)),
actions,
})
}
diff --git a/src/size.rs b/src/size.rs
index e1f54a4f..674abdb5 100644
--- a/src/size.rs
+++ b/src/size.rs
@@ -42,11 +42,7 @@ impl Size {
/// Create a size from an amount of points.
#[inline]
- pub fn points(points: f32) -> Size { Size { points } }
-
- /// Create a size from an amount of inches.
- #[inline]
- pub fn inches(inches: f32) -> Size { Size { points: 72.0 * inches } }
+ pub fn pt(points: f32) -> Size { Size { points } }
/// Create a size from an amount of millimeters.
#[inline]
@@ -56,13 +52,13 @@ impl Size {
#[inline]
pub fn cm(cm: f32) -> Size { Size { points: 28.3465 * cm } }
- /// Convert this size into points.
+ /// Create a size from an amount of inches.
#[inline]
- pub fn to_points(&self) -> f32 { self.points }
+ pub fn inches(inches: f32) -> Size { Size { points: 72.0 * inches } }
- /// Convert this size into inches.
+ /// Convert this size into points.
#[inline]
- pub fn to_inches(&self) -> f32 { self.points * 0.0138889 }
+ pub fn to_pt(&self) -> f32 { self.points }
/// Convert this size into millimeters.
#[inline]
@@ -71,6 +67,10 @@ impl Size {
/// Convert this size into centimeters.
#[inline]
pub fn to_cm(&self) -> f32 { self.points * 0.0352778 }
+
+ /// Convert this size into inches.
+ #[inline]
+ pub fn to_inches(&self) -> f32 { self.points * 0.0138889 }
}
impl Size2D {