diff --git a/.gitignore b/.gitignore index ae7d194bd..e713d0af7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ # General .vscode _things +desktop.ini # Tests and benchmarks tests/png diff --git a/Cargo.toml b/Cargo.toml index a71d27654..38be3d795 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,6 @@ edition = "2018" default = ["fs"] fs = ["fontdock/fs"] cli = ["fs", "anyhow"] -# serde = [] [workspace] members = ["bench"] @@ -22,7 +21,7 @@ debug = 0 opt-level = 2 [dependencies] -fontdock = { path = "../fontdock", default-features = false } +fontdock = { path = "../fontdock", features = ["serde"], default-features = false } image = { version = "0.23", default-features = false, features = ["jpeg", "png"] } miniz_oxide = "0.3" pdf-writer = { path = "../pdf-writer" } @@ -32,7 +31,7 @@ unicode-bidi = "0.3.5" unicode-xid = "0.2" xi-unicode = "0.3" anyhow = { version = "1", optional = true } -serde = { version = "1", features = ["derive"], optional = true } +serde = { version = "1", features = ["derive"] } [dev-dependencies] walkdir = "2" diff --git a/rustfmt.toml b/rustfmt.toml index 9196ae099..d4c2fae03 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -3,6 +3,7 @@ unstable_features = true overflow_delimited_expr = true spaces_around_ranges = true use_field_init_shorthand = true +merge_derives = false max_width = 90 struct_lit_width = 40 diff --git a/src/color.rs b/src/color.rs index 35b90e8ad..5a93e0e91 100644 --- a/src/color.rs +++ b/src/color.rs @@ -3,8 +3,10 @@ use std::fmt::{self, Debug, Display, Formatter}; use std::str::FromStr; +use serde::{Deserialize, Serialize}; + /// A color in a dynamic format. -#[derive(Copy, Clone, Eq, PartialEq)] +#[derive(Copy, Clone, Eq, PartialEq, Serialize, Deserialize)] pub enum Color { /// An 8-bit RGBA color: `#423abaff`. Rgba(RgbaColor), @@ -27,7 +29,7 @@ impl Debug for Color { } /// An 8-bit RGBA color: `#423abaff`. -#[derive(Copy, Clone, Eq, PartialEq)] +#[derive(Copy, Clone, Eq, PartialEq, Serialize, Deserialize)] pub struct RgbaColor { /// Red channel. pub r: u8, diff --git a/src/diag.rs b/src/diag.rs index c31bffdee..6158b5c0e 100644 --- a/src/diag.rs +++ b/src/diag.rs @@ -5,10 +5,12 @@ use std::collections::BTreeSet; use std::fmt::{self, Display, Formatter}; +use serde::{Deserialize, Serialize}; + use crate::syntax::Span; /// The result of some pass: Some output `T` and diagnostics. -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] pub struct Pass { /// The output of this compilation pass. pub output: T, @@ -31,8 +33,7 @@ impl Pass { pub type DiagSet = BTreeSet; /// A diagnostic with severity level and message. -#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] -#[cfg_attr(feature = "serde", derive(serde::Serialize))] +#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)] pub struct Diag { /// The source code location. pub span: Span, @@ -61,8 +62,8 @@ impl Display for Diag { /// How severe / important a diagnostic is. #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] -#[cfg_attr(feature = "serde", derive(serde::Serialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] pub enum Level { Warning, Error, diff --git a/src/env.rs b/src/env.rs index 10230bbfd..3b8fd4cdd 100644 --- a/src/env.rs +++ b/src/env.rs @@ -10,6 +10,7 @@ use std::path::{Path, PathBuf}; use fontdock::{FaceId, FontSource}; use image::io::Reader as ImageReader; use image::{DynamicImage, GenericImageView, ImageFormat}; +use serde::{Deserialize, Serialize}; #[cfg(feature = "fs")] use fontdock::{FsIndex, FsSource}; @@ -72,6 +73,7 @@ pub struct ResourceLoader { /// A unique identifier for a resource. #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[derive(Serialize, Deserialize)] pub struct ResourceId(usize); impl ResourceLoader { diff --git a/src/eval/scope.rs b/src/eval/scope.rs index 69d519fdf..20c183063 100644 --- a/src/eval/scope.rs +++ b/src/eval/scope.rs @@ -10,7 +10,7 @@ use super::Value; pub type Slot = Rc>; /// A stack of scopes. -#[derive(Debug, Default, Clone, PartialEq)] +#[derive(Default, Debug, Clone, PartialEq)] pub struct Scopes<'a> { /// The active scope. pub top: Scope, diff --git a/src/geom/angle.rs b/src/geom/angle.rs index 938141ee3..f1db841c5 100644 --- a/src/geom/angle.rs +++ b/src/geom/angle.rs @@ -69,7 +69,7 @@ impl Display for Angle { impl Debug for Angle { fn fmt(&self, f: &mut Formatter) -> fmt::Result { let unit = AngularUnit::Deg; - write!(f, "{:?}{:?}", self.to_unit(unit), unit) + write!(f, "{}{}", self.to_unit(unit), unit) } } @@ -134,7 +134,7 @@ impl Sum for Angle { } } /// Different units of angular measurement. -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] pub enum AngularUnit { /// Radians. Rad, @@ -161,12 +161,6 @@ impl Display for AngularUnit { } } -impl Debug for AngularUnit { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - Display::fmt(self, f) - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/src/geom/length.rs b/src/geom/length.rs index 1c2a5f864..c75f79b55 100644 --- a/src/geom/length.rs +++ b/src/geom/length.rs @@ -1,7 +1,10 @@ use super::*; +use serde::{Deserialize, Serialize}; + /// An absolute length. -#[derive(Default, Copy, Clone, PartialEq, PartialOrd)] +#[derive(Default, Copy, Clone, PartialEq, PartialOrd, Serialize, Deserialize)] +#[serde(transparent)] pub struct Length { /// The length in raw units. raw: f64, @@ -192,7 +195,7 @@ impl Sum for Length { } /// Different units of length measurement. -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] pub enum LengthUnit { /// Points. Pt, @@ -227,12 +230,6 @@ impl Display for LengthUnit { } } -impl Debug for LengthUnit { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - Display::fmt(self, f) - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/src/geom/path.rs b/src/geom/path.rs index c9fcf1c09..dcabb9cf8 100644 --- a/src/geom/path.rs +++ b/src/geom/path.rs @@ -1,11 +1,14 @@ use super::*; +use serde::{Deserialize, Serialize}; + /// A bezier path. -#[derive(Default, Debug, Clone, PartialEq)] +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(transparent)] pub struct Path(pub Vec); /// An element in a bezier path. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub enum PathElement { MoveTo(Point), LineTo(Point), diff --git a/src/geom/point.rs b/src/geom/point.rs index 292985654..5ed8bf1d3 100644 --- a/src/geom/point.rs +++ b/src/geom/point.rs @@ -1,7 +1,9 @@ use super::*; +use serde::{Deserialize, Serialize}; + /// A point in 2D. -#[derive(Default, Copy, Clone, PartialEq)] +#[derive(Default, Copy, Clone, PartialEq, Serialize, Deserialize)] pub struct Point { /// The x coordinate. pub x: Length, diff --git a/src/geom/size.rs b/src/geom/size.rs index 2dd34a873..0a64e6b90 100644 --- a/src/geom/size.rs +++ b/src/geom/size.rs @@ -1,7 +1,9 @@ use super::*; +use serde::{Deserialize, Serialize}; + /// A size in 2D. -#[derive(Default, Copy, Clone, PartialEq)] +#[derive(Default, Copy, Clone, PartialEq, Serialize, Deserialize)] pub struct Size { /// The width. pub width: Length, diff --git a/src/layout/background.rs b/src/layout/background.rs index d34081820..515eef718 100644 --- a/src/layout/background.rs +++ b/src/layout/background.rs @@ -12,7 +12,7 @@ pub struct BackgroundNode { } /// The kind of shape to use as a background. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum BackgroundShape { Rect, Ellipse, diff --git a/src/layout/frame.rs b/src/layout/frame.rs index 21fdbf28c..24ba65ceb 100644 --- a/src/layout/frame.rs +++ b/src/layout/frame.rs @@ -1,12 +1,13 @@ use fontdock::FaceId; -use ttf_parser::GlyphId; use crate::color::Color; use crate::env::ResourceId; use crate::geom::{Length, Path, Point, Size}; +use serde::{Deserialize, Serialize}; + /// A finished layout with elements at fixed positions. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Frame { /// The size of the frame. pub size: Size, @@ -37,7 +38,7 @@ impl Frame { } /// The building block frames are composed of. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub enum Element { /// Shaped text. Text(Text), @@ -48,7 +49,7 @@ pub enum Element { } /// A run of shaped text. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Text { /// The font face the glyphs are contained in. pub face_id: FaceId, @@ -61,10 +62,10 @@ pub struct Text { } /// A glyph in a run of shaped text. -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)] pub struct Glyph { /// The glyph's ID in the face. - pub id: GlyphId, + pub id: u16, /// The advance width of the glyph. pub x_advance: Length, /// The horizontal offset of the glyph. @@ -76,7 +77,7 @@ impl Text { pub fn encode_glyphs_be(&self) -> Vec { let mut bytes = Vec::with_capacity(2 * self.glyphs.len()); for glyph in &self.glyphs { - let id = glyph.id.0; + let id = glyph.id; bytes.push((id >> 8) as u8); bytes.push((id & 0xff) as u8); } @@ -85,7 +86,7 @@ impl Text { } /// A shape with some kind of fill. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Geometry { /// The shape to draw. pub shape: Shape, @@ -98,7 +99,7 @@ pub struct Geometry { } /// Some shape. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub enum Shape { /// A rectangle with its origin in the topleft corner. Rect(Size), @@ -109,7 +110,7 @@ pub enum Shape { } /// The kind of graphic fill to be applied to a [`Shape`]. -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)] pub enum Fill { /// The fill is a color. Color(Color), @@ -118,7 +119,7 @@ pub enum Fill { } /// An image element. -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)] pub struct Image { /// The image resource. pub res: ResourceId, diff --git a/src/layout/shaping.rs b/src/layout/shaping.rs index faa178d37..47d19a62c 100644 --- a/src/layout/shaping.rs +++ b/src/layout/shaping.rs @@ -18,6 +18,7 @@ use crate::util::SliceExt; /// This type contains owned or borrowed shaped text runs, which can be /// measured, used to reshape substrings more quickly and converted into a /// frame. +#[derive(Clone)] pub struct ShapedText<'a> { /// The text that was shaped. pub text: &'a str, @@ -53,6 +54,7 @@ pub struct ShapedGlyph { } /// A visual side. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] enum Side { Left, Right, @@ -77,7 +79,11 @@ impl<'a> ShapedText<'a> { for glyph in group { let x_advance = face.convert(glyph.x_advance).scale(self.props.size); let x_offset = face.convert(glyph.x_offset).scale(self.props.size); - text.glyphs.push(Glyph { id: glyph.glyph_id, x_advance, x_offset }); + text.glyphs.push(Glyph { + id: glyph.glyph_id.0, + x_advance, + x_offset, + }); offset += x_advance; } diff --git a/src/syntax/node.rs b/src/syntax/node.rs index 537a5686a..5f76b56ab 100644 --- a/src/syntax/node.rs +++ b/src/syntax/node.rs @@ -37,15 +37,15 @@ impl Node { /// Desugar markup into a function call. pub fn desugar(&self) -> Option { match *self { - Node::Text(_) => None, - Node::Space => None, - Node::Linebreak(span) => Some(call(span, Self::LINEBREAK)), - Node::Parbreak(span) => Some(call(span, Self::PARBREAK)), - Node::Strong(span) => Some(call(span, Self::STRONG)), - Node::Emph(span) => Some(call(span, Self::EMPH)), + Self::Text(_) => None, + Self::Space => None, + Self::Linebreak(span) => Some(call(span, Self::LINEBREAK)), + Self::Parbreak(span) => Some(call(span, Self::PARBREAK)), + Self::Strong(span) => Some(call(span, Self::STRONG)), + Self::Emph(span) => Some(call(span, Self::EMPH)), Self::Heading(ref heading) => Some(heading.desugar()), Self::Raw(ref raw) => Some(raw.desugar()), - Node::Expr(_) => None, + Self::Expr(_) => None, } } } diff --git a/src/syntax/span.rs b/src/syntax/span.rs index d3683c1a0..f9b1d312a 100644 --- a/src/syntax/span.rs +++ b/src/syntax/span.rs @@ -2,13 +2,15 @@ use std::cell::Cell; use std::fmt::{self, Debug, Display, Formatter}; use std::ops::{Add, Range}; +use serde::{Deserialize, Serialize}; + thread_local! { static CMP_SPANS: Cell = Cell::new(true); } /// A value with the span it corresponds to in the source code. #[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] -#[cfg_attr(feature = "serde", derive(serde::Serialize))] +#[derive(Serialize, Deserialize)] pub struct Spanned { /// The spanned value. pub v: T, @@ -53,8 +55,7 @@ impl Debug for Spanned { } /// Bounds of a slice of source code. -#[derive(Copy, Clone, Ord, PartialOrd)] -#[cfg_attr(feature = "serde", derive(serde::Serialize))] +#[derive(Copy, Clone, Ord, PartialOrd, Serialize, Deserialize)] pub struct Span { /// The inclusive start position. pub start: Pos, @@ -158,8 +159,7 @@ impl Debug for Span { } /// A byte position in source code. -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] -#[cfg_attr(feature = "serde", derive(serde::Serialize))] +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)] pub struct Pos(pub u32); impl Pos { @@ -208,8 +208,7 @@ impl Debug for Pos { } /// A one-indexed line-column position in source code. -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] -#[cfg_attr(feature = "serde", derive(serde::Serialize))] +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)] pub struct Location { /// The one-indexed line. pub line: u32, diff --git a/tests/typeset.rs b/tests/typeset.rs index 6aef27463..7aaa017d2 100644 --- a/tests/typeset.rs +++ b/tests/typeset.rs @@ -11,7 +11,7 @@ use tiny_skia::{ Color, ColorU8, FillRule, FilterQuality, Paint, Pattern, Pixmap, Rect, SpreadMode, Transform, }; -use ttf_parser::OutlineBuilder; +use ttf_parser::{GlyphId, OutlineBuilder}; use walkdir::WalkDir; use typst::color; @@ -425,7 +425,7 @@ fn draw_text(canvas: &mut Pixmap, env: &Env, ts: Transform, shaped: &Text) { // Try drawing SVG if present. if let Some(tree) = ttf - .glyph_svg_image(glyph.id) + .glyph_svg_image(GlyphId(glyph.id)) .and_then(|data| std::str::from_utf8(data).ok()) .map(|svg| { let viewbox = format!("viewBox=\"0 0 {0} {0}\" xmlns", units_per_em); @@ -448,7 +448,7 @@ fn draw_text(canvas: &mut Pixmap, env: &Env, ts: Transform, shaped: &Text) { } else { // Otherwise, draw normal outline. let mut builder = WrappedPathBuilder(tiny_skia::PathBuilder::new()); - if ttf.outline_glyph(glyph.id, &mut builder).is_some() { + if ttf.outline_glyph(GlyphId(glyph.id), &mut builder).is_some() { let path = builder.0.finish().unwrap(); let ts = ts.pre_scale(s, -s); let mut paint = convert_typst_fill(shaped.color);