Move some types into better places 🧱

This commit is contained in:
Laurenz 2019-03-30 16:58:45 +01:00
parent f683bba400
commit db96ecae94
10 changed files with 230 additions and 219 deletions

Binary file not shown.

View File

@ -1,9 +1,10 @@
//! Abstract representation of a typesetted document.
//! Representation of typesetted documents.
use crate::font::Font;
use crate::engine::Size;
/// A representation of a typesetted document.
/// A complete typesetted document, which can be exported.
#[derive(Debug, Clone, PartialEq)]
pub struct Document {
/// The pages of the document.
@ -12,62 +13,6 @@ pub struct Document {
pub fonts: Vec<Font>,
}
/// Default styles for a document.
#[derive(Debug, Clone, PartialEq)]
pub struct Style {
/// The width of the paper.
pub width: Size,
/// The height of the paper.
pub height: Size,
/// The left margin of the paper.
pub margin_left: Size,
/// The top margin of the paper.
pub margin_top: Size,
/// The right margin of the paper.
pub margin_right: Size,
/// The bottom margin of the paper.
pub margin_bottom: Size,
/// A fallback list of font families to use.
pub font_families: Vec<FontFamily>,
/// The font size.
pub font_size: f32,
/// The line spacing (as a multiple of the font size).
pub line_spacing: f32,
}
/// A family of fonts (either generic or named).
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum FontFamily {
SansSerif,
Serif,
Monospace,
Named(String),
}
impl Default for Style {
fn default() -> Style {
use FontFamily::*;
Style {
// A4 paper.
width: Size::from_mm(210.0),
height: Size::from_mm(297.0),
// Margins. A bit more on top and bottom.
margin_left: Size::from_cm(2.5),
margin_top: Size::from_cm(3.0),
margin_right: Size::from_cm(2.5),
margin_bottom: Size::from_cm(3.0),
// Default font family, font size and line spacing.
font_families: vec![SansSerif, Serif, Monospace],
font_size: 12.0,
line_spacing: 1.25,
}
}
}
/// A page with text contents in a document.
#[derive(Debug, Clone, PartialEq)]
pub struct Page {
@ -96,144 +41,3 @@ pub enum TextCommand {
/// Use the indexed font in the documents font list with a given font size.
SetFont(usize, f32),
}
/// A general distance type that can convert between units.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Size {
/// The size in typographic points (1/72 inches).
points: f32,
}
impl Size {
/// Create an zeroed size.
#[inline]
pub fn zero() -> Size { Size { points: 0.0 } }
/// Create a size from a number of points.
#[inline]
pub fn from_points(points: f32) -> Size { Size { points } }
/// Create a size from a number of inches.
#[inline]
pub fn from_inches(inches: f32) -> Size { Size { points: 72.0 * inches } }
/// Create a size from a number of millimeters.
#[inline]
pub fn from_mm(mm: f32) -> Size { Size { points: 2.83465 * mm } }
/// Create a size from a number of centimeters.
#[inline]
pub fn from_cm(cm: f32) -> Size { Size { points: 28.3465 * cm } }
/// Create a size from a number of points.
#[inline]
pub fn to_points(&self) -> f32 { self.points }
/// Create a size from a number of inches.
#[inline]
pub fn to_inches(&self) -> f32 { self.points * 0.0138889 }
/// Create a size from a number of millimeters.
#[inline]
pub fn to_mm(&self) -> f32 { self.points * 0.352778 }
/// Create a size from a number of centimeters.
#[inline]
pub fn to_cm(&self) -> f32 { self.points * 0.0352778 }
}
mod size {
use super::Size;
use std::cmp::Ordering;
use std::fmt;
use std::iter::Sum;
use std::ops::*;
impl fmt::Display for Size {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}pt", self.points)
}
}
macro_rules! impl_reflexive {
($trait:ident, $func:ident, $assign_trait:ident, $assign_func:ident) => {
impl $trait for Size {
type Output = Size;
#[inline]
fn $func(self, other: Size) -> Size {
Size { points: $trait::$func(self.points, other.points) }
}
}
impl $assign_trait for Size {
#[inline]
fn $assign_func(&mut self, other: Size) {
$assign_trait::$assign_func(&mut self.points, other.points);
}
}
};
}
macro_rules! impl_num_back {
($trait:ident, $func:ident, $assign_trait:ident, $assign_func:ident, $ty:ty) => {
impl $trait<$ty> for Size {
type Output = Size;
#[inline]
fn $func(self, other: $ty) -> Size {
Size { points: $trait::$func(self.points, other as f32) }
}
}
impl $assign_trait<$ty> for Size {
#[inline]
fn $assign_func(&mut self, other: $ty) {
$assign_trait::$assign_func(&mut self.points, other as f32);
}
}
};
}
macro_rules! impl_num_both {
($trait:ident, $func:ident, $assign_trait:ident, $assign_func:ident, $ty:ty) => {
impl_num_back!($trait, $func, $assign_trait, $assign_func, $ty);
impl $trait<Size> for $ty {
type Output = Size;
#[inline]
fn $func(self, other: Size) -> Size {
Size { points: $trait::$func(self as f32, other.points) }
}
}
};
}
impl Neg for Size {
type Output = Size;
fn neg(self) -> Size {
Size { points: -self.points }
}
}
impl_reflexive!(Add, add, AddAssign, add_assign);
impl_reflexive!(Sub, sub, SubAssign, sub_assign);
impl_num_both!(Mul, mul, MulAssign, mul_assign, f32);
impl_num_both!(Mul, mul, MulAssign, mul_assign, i32);
impl_num_back!(Div, div, DivAssign, div_assign, f32);
impl_num_back!(Div, div, DivAssign, div_assign, i32);
impl PartialOrd for Size {
fn partial_cmp(&self, other: &Size) -> Option<Ordering> {
self.points.partial_cmp(&other.points)
}
}
impl Sum for Size {
fn sum<I>(iter: I) -> Size where I: Iterator<Item=Size> {
iter.fold(Size::zero(), Add::add)
}
}
}

View File

@ -1,10 +1,13 @@
//! Core typesetting engine.
use crate::syntax::{SyntaxTree, Node};
use crate::doc::{Document, Size, Page, Text, TextCommand};
use crate::font::{Font, FontConfig, FontError};
use crate::doc::{Document, Page, Text, TextCommand};
use crate::font::{Font, FontFamily, FontConfig, FontError};
use crate::Context;
mod size;
pub use size::Size;
/// The core typesetting engine, transforming an abstract syntax tree into a document.
pub(crate) struct Engine<'a> {
@ -138,6 +141,53 @@ impl<'a> Engine<'a> {
}
}
/// Default styles for a document.
#[derive(Debug, Clone, PartialEq)]
pub struct Style {
/// The width of the paper.
pub width: Size,
/// The height of the paper.
pub height: Size,
/// The left margin of the paper.
pub margin_left: Size,
/// The top margin of the paper.
pub margin_top: Size,
/// The right margin of the paper.
pub margin_right: Size,
/// The bottom margin of the paper.
pub margin_bottom: Size,
/// A fallback list of font families to use.
pub font_families: Vec<FontFamily>,
/// The font size.
pub font_size: f32,
/// The line spacing (as a multiple of the font size).
pub line_spacing: f32,
}
impl Default for Style {
fn default() -> Style {
use FontFamily::*;
Style {
// A4 paper.
width: Size::from_mm(210.0),
height: Size::from_mm(297.0),
// Margins. A bit more on top and bottom.
margin_left: Size::from_cm(2.5),
margin_top: Size::from_cm(3.0),
margin_right: Size::from_cm(2.5),
margin_bottom: Size::from_cm(3.0),
// Default font family, font size and line spacing.
font_families: vec![SansSerif, Serif, Monospace],
font_size: 12.0,
line_spacing: 1.25,
}
}
}
/// The error type for typesetting.
pub enum TypesetError {
/// There was no suitable font.

144
src/engine/size.rs Normal file
View File

@ -0,0 +1,144 @@
use std::cmp::Ordering;
use std::fmt::{self, Display, Debug, Formatter};
use std::iter::Sum;
use std::ops::*;
/// A general distance type that can convert between units.
#[derive(Copy, Clone, PartialEq)]
pub struct Size {
/// The size in typographic points (1/72 inches).
points: f32,
}
impl Size {
/// Create an zeroed size.
#[inline]
pub fn zero() -> Size { Size { points: 0.0 } }
/// Create a size from a number of points.
#[inline]
pub fn from_points(points: f32) -> Size { Size { points } }
/// Create a size from a number of inches.
#[inline]
pub fn from_inches(inches: f32) -> Size { Size { points: 72.0 * inches } }
/// Create a size from a number of millimeters.
#[inline]
pub fn from_mm(mm: f32) -> Size { Size { points: 2.83465 * mm } }
/// Create a size from a number of centimeters.
#[inline]
pub fn from_cm(cm: f32) -> Size { Size { points: 28.3465 * cm } }
/// Create a size from a number of points.
#[inline]
pub fn to_points(&self) -> f32 { self.points }
/// Create a size from a number of inches.
#[inline]
pub fn to_inches(&self) -> f32 { self.points * 0.0138889 }
/// Create a size from a number of millimeters.
#[inline]
pub fn to_mm(&self) -> f32 { self.points * 0.352778 }
/// Create a size from a number of centimeters.
#[inline]
pub fn to_cm(&self) -> f32 { self.points * 0.0352778 }
}
impl Display for Size {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}pt", self.points)
}
}
impl Debug for Size {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
Display::fmt(self, f)
}
}
impl PartialOrd for Size {
fn partial_cmp(&self, other: &Size) -> Option<Ordering> {
self.points.partial_cmp(&other.points)
}
}
impl Neg for Size {
type Output = Size;
fn neg(self) -> Size {
Size { points: -self.points }
}
}
impl Sum for Size {
fn sum<I>(iter: I) -> Size where I: Iterator<Item=Size> {
iter.fold(Size::zero(), Add::add)
}
}
macro_rules! impl_reflexive {
($trait:ident, $func:ident, $assign_trait:ident, $assign_func:ident) => {
impl $trait for Size {
type Output = Size;
#[inline]
fn $func(self, other: Size) -> Size {
Size { points: $trait::$func(self.points, other.points) }
}
}
impl $assign_trait for Size {
#[inline]
fn $assign_func(&mut self, other: Size) {
$assign_trait::$assign_func(&mut self.points, other.points);
}
}
};
}
macro_rules! impl_num_back {
($trait:ident, $func:ident, $assign_trait:ident, $assign_func:ident, $ty:ty) => {
impl $trait<$ty> for Size {
type Output = Size;
#[inline]
fn $func(self, other: $ty) -> Size {
Size { points: $trait::$func(self.points, other as f32) }
}
}
impl $assign_trait<$ty> for Size {
#[inline]
fn $assign_func(&mut self, other: $ty) {
$assign_trait::$assign_func(&mut self.points, other as f32);
}
}
};
}
macro_rules! impl_num_both {
($trait:ident, $func:ident, $assign_trait:ident, $assign_func:ident, $ty:ty) => {
impl_num_back!($trait, $func, $assign_trait, $assign_func, $ty);
impl $trait<Size> for $ty {
type Output = Size;
#[inline]
fn $func(self, other: Size) -> Size {
Size { points: $trait::$func(self as f32, other.points) }
}
}
};
}
impl_reflexive!(Add, add, AddAssign, add_assign);
impl_reflexive!(Sub, sub, SubAssign, sub_assign);
impl_num_both!(Mul, mul, MulAssign, mul_assign, f32);
impl_num_both!(Mul, mul, MulAssign, mul_assign, i32);
impl_num_back!(Div, div, DivAssign, div_assign, f32);
impl_num_back!(Div, div, DivAssign, div_assign, i32);

View File

@ -1,3 +1,5 @@
//! Error handling.
/// Create an error type.
macro_rules! error_type {
(

View File

@ -6,8 +6,9 @@ use pdf::{PdfWriter, Ref, Rect, Version, Trailer, Content};
use pdf::doc::{Catalog, PageTree, Page, Resource, Text};
use pdf::font::{Type0Font, CIDFont, CIDFontType, CIDSystemInfo, FontDescriptor, FontFlags};
use pdf::font::{GlyphUnit, CMapEncoding, WidthRecord, FontStream, EmbeddedFontType};
use crate::doc::{Document, Size, Text as DocText, TextCommand};
use crate::doc::{Document, Text as DocText, TextCommand};
use crate::font::{Font, FontError};
use crate::engine::Size;
/// Exports documents into _PDFs_.

View File

@ -1,6 +1,4 @@
//! Font loading, utility and subsetting.
#![macro_use]
//! Font loading and transforming.
use std::collections::HashMap;
use std::path::{Path, PathBuf};
@ -9,7 +7,7 @@ use byteorder::{BE, ReadBytesExt, WriteBytesExt};
use opentype::{Error as OpentypeError, OpenTypeReader, Outlines, TableRecord, Tag};
use opentype::tables::{Header, Name, CharMap, MaximumProfile, HorizontalMetrics, Post, OS2};
use opentype::global::{MacStyleFlags, NameEntry};
use crate::doc::{Size, FontFamily};
use crate::engine::Size;
/// An font wrapper which allows to subset a font.
@ -54,8 +52,8 @@ impl Font {
/// Create a new font from a font program.
pub fn new(program: Vec<u8>) -> FontResult<Font> {
// Create opentype reader to parse font tables
let mut readable = Cursor::new(&program);
let mut reader = OpenTypeReader::new(&mut readable);
let cursor = Cursor::new(&program);
let mut reader = OpenTypeReader::new(cursor);
// Read the relevant tables
// (all of these are required by the OpenType specification)
@ -586,8 +584,6 @@ impl<T> TakeInvalid<T> for Option<T> {
}
}
///////////////////////////////////////////////////////////////////////////////
/// A type that provides fonts matching given criteria.
pub trait FontProvider {
/// Returns a font matching the configuration
@ -599,8 +595,18 @@ pub trait FontProvider {
///
/// Automatically implemented for all types that are [`Read`] and [`Seek`].
pub trait FontSource: Read + Seek {}
impl<T> FontSource for T where T: Read + Seek {}
/// A family of fonts (either generic or named).
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum FontFamily {
SansSerif,
Serif,
Monospace,
Named(String),
}
/// Criteria to filter fonts.
#[derive(Debug, Clone, PartialEq)]
pub struct FontConfig {
@ -694,8 +700,8 @@ impl FileFontDescriptor<'_> {
#[macro_export]
macro_rules! file_font {
($family:expr, [$($generic:ident),*], $path:expr, $bold:expr, $italic:expr) => {{
let mut families = vec![$crate::doc::FontFamily::Named($family.to_string())];
families.extend([$($crate::doc::FontFamily::$generic),*].iter().cloned());
let mut families = vec![$crate::font::FontFamily::Named($family.to_string())];
families.extend([$($crate::font::FontFamily::$generic),*].iter().cloned());
$crate::font::FileFontDescriptor {
path: std::path::Path::new($path),
families,

View File

@ -33,16 +33,19 @@
//! let document = compiler.typeset(src).unwrap();
//!
//! // Export the document into a PDF file.
//! let mut file = File::create("hello-typeset.pdf").unwrap();
//! # /*
//! let file = File::create("hello-typeset.pdf").unwrap();
//! # */
//! # let file = File::create("../target/typeset-hello.pdf").unwrap();
//! let exporter = PdfExporter::new();
//! exporter.export(&document, &mut file).unwrap();
//! exporter.export(&document, file).unwrap();
//! ```
use crate::syntax::SyntaxTree;
use crate::parsing::{Tokens, Parser, ParseError};
use crate::doc::{Document, Style};
use crate::doc::Document;
use crate::font::FontProvider;
use crate::engine::{Engine, TypesetError};
use crate::engine::{Engine, Style, TypesetError};
#[macro_use]
mod error;
@ -50,6 +53,7 @@ mod utility;
pub mod doc;
pub mod engine;
pub mod export;
#[macro_use]
pub mod font;
pub mod parsing;
pub mod syntax;
@ -135,6 +139,7 @@ error_type! {
from: (TypesetError, Error::Typeset(err)),
}
#[cfg(test)]
mod test {
use std::fs::File;

View File

@ -1,4 +1,4 @@
//! Parsing of source code into tokens and syntax trees.
//! Tokenization and parsing of source code into syntax trees.
use std::fmt;
use std::iter::Peekable;
@ -475,7 +475,6 @@ mod token_tests {
}
}
#[cfg(test)]
mod parse_tests {
use super::*;

View File

@ -1,4 +1,4 @@
//! Token and abstract syntax tree representations.
//! Tokenized and syntax tree representations of source code.
/// A logical unit of the incoming text stream.