From 72478946c261f04754c11f8a6abf6eb0f43dea31 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Wed, 21 Apr 2021 21:17:25 +0200 Subject: [PATCH] =?UTF-8?q?Make=20frames=20serializable=20=F0=9F=93=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This also makes serialization support non-optional since it's too much feature-management for too little benefit. --- .gitignore | 1 + Cargo.toml | 5 ++--- rustfmt.toml | 1 + src/color.rs | 6 ++++-- src/diag.rs | 11 ++++++----- src/env.rs | 2 ++ src/eval/scope.rs | 2 +- src/geom/angle.rs | 10 ++-------- src/geom/length.rs | 13 +++++-------- src/geom/path.rs | 7 +++++-- src/geom/point.rs | 4 +++- src/geom/size.rs | 4 +++- src/layout/background.rs | 2 +- src/layout/frame.rs | 23 ++++++++++++----------- src/layout/shaping.rs | 8 +++++++- src/syntax/node.rs | 14 +++++++------- src/syntax/span.rs | 13 ++++++------- tests/typeset.rs | 6 +++--- 18 files changed, 71 insertions(+), 61 deletions(-) diff --git a/.gitignore b/.gitignore index ae7d194bdcad..e713d0af7d06 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 a71d2765425a..38be3d795047 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 9196ae0994cc..d4c2fae03914 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 35b90e8ad448..5a93e0e9138c 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 c31bffdeef08..6158b5c0eceb 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 10230bbfd792..3b8fd4cddb80 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 69d519fdfcf1..20c183063f44 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 938141ee3d20..f1db841c56df 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 1c2a5f864f06..c75f79b55a87 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 c9fcf1c094f4..dcabb9cf865e 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 292985654a4d..5ed8bf1d3df9 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 2dd34a8735ed..0a64e6b908fa 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 d34081820599..515eef718c1f 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 21fdbf28cd18..24ba65ceb8f3 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 faa178d37448..47d19a62c6f0 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 537a5686acbd..5f76b56abf0c 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 d3683c1a07fd..f9b1d312a901 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 6aef274637a5..7aaa017d2b99 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);