summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--benches/benchmarks.rs12
-rw-r--r--main/main.rs10
-rw-r--r--src/export/pdf.rs14
-rw-r--r--src/font.rs41
-rw-r--r--src/layout/text.rs13
-rw-r--r--src/layout/tree.rs2
-rw-r--r--tests/test_typeset.rs21
7 files changed, 56 insertions, 57 deletions
diff --git a/benches/benchmarks.rs b/benches/benchmarks.rs
index fce72585..52200e66 100644
--- a/benches/benchmarks.rs
+++ b/benches/benchmarks.rs
@@ -3,10 +3,9 @@ use std::rc::Rc;
use criterion::{criterion_group, criterion_main, Criterion};
use fontdock::fs::{FsIndex, FsProvider};
-use fontdock::FontLoader;
-use typstc::font::DynProvider;
-use typstc::syntax::parsing::parse;
+use typstc::font::FontLoader;
+use typstc::parse::parse;
use typstc::Typesetter;
const FONT_DIR: &str = "fonts";
@@ -25,10 +24,9 @@ fn typesetting_benchmark(c: &mut Criterion) {
let mut index = FsIndex::new();
index.search_dir(FONT_DIR);
- let (descriptors, files) = index.clone().into_vecs();
- let provider = FsProvider::new(files.clone());
- let dynamic = Box::new(provider) as Box<DynProvider>;
- let loader = FontLoader::new(dynamic, descriptors);
+ let (descriptors, files) = index.into_vecs();
+ let provider = FsProvider::new(files);
+ let loader = FontLoader::new(Box::new(provider), descriptors);
let loader = Rc::new(RefCell::new(loader));
let typesetter = Typesetter::new(loader.clone());
diff --git a/main/main.rs b/main/main.rs
index a0ca9edd..d3ad641b 100644
--- a/main/main.rs
+++ b/main/main.rs
@@ -5,11 +5,10 @@ use std::path::{Path, PathBuf};
use std::rc::Rc;
use fontdock::fs::{FsIndex, FsProvider};
-use fontdock::FontLoader;
use futures_executor::block_on;
use typstc::export::pdf;
-use typstc::font::DynProvider;
+use typstc::font::FontLoader;
use typstc::Typesetter;
fn main() {
@@ -37,9 +36,8 @@ fn main() {
index.search_os();
let (descriptors, files) = index.into_vecs();
- let provider = FsProvider::new(files.clone());
- let dynamic = Box::new(provider) as Box<DynProvider>;
- let loader = FontLoader::new(dynamic, descriptors);
+ let provider = FsProvider::new(files);
+ let loader = FontLoader::new(Box::new(provider), descriptors);
let loader = Rc::new(RefCell::new(loader));
let typesetter = Typesetter::new(loader.clone());
@@ -62,8 +60,8 @@ fn main() {
);
}
+ let loader = loader.borrow();
let file = File::create(&dest_path).expect("failed to create output file");
-
let writer = BufWriter::new(file);
pdf::export(&layouts, &loader, writer).expect("failed to export pdf");
}
diff --git a/src/export/pdf.rs b/src/export/pdf.rs
index c4c12713..b87b3181 100644
--- a/src/export/pdf.rs
+++ b/src/export/pdf.rs
@@ -13,10 +13,10 @@ use tide::font::{
use tide::{PdfWriter, Rect, Ref, Trailer, Version};
use ttf_parser::{name_id, GlyphId};
+use crate::font::FontLoader;
use crate::layout::elements::LayoutElement;
use crate::layout::BoxLayout;
use crate::length::Length;
-use crate::SharedFontLoader;
/// Export a list of layouts into a _PDF_ document.
///
@@ -28,7 +28,7 @@ use crate::SharedFontLoader;
/// bytes written.
pub fn export<W: Write>(
layout: &[BoxLayout],
- loader: &SharedFontLoader,
+ loader: &FontLoader,
target: W,
) -> io::Result<usize> {
PdfExporter::new(layout, loader, target)?.write()
@@ -37,7 +37,7 @@ pub fn export<W: Write>(
struct PdfExporter<'a, W: Write> {
writer: PdfWriter<W>,
layouts: &'a [BoxLayout],
- loader: &'a SharedFontLoader,
+ loader: &'a FontLoader,
/// We need to know exactly which indirect reference id will be used for
/// which objects up-front to correctly declare the document catalogue, page
/// tree and so on. These offsets are computed in the beginning and stored
@@ -61,7 +61,7 @@ const NUM_OBJECTS_PER_FONT: u32 = 5;
impl<'a, W: Write> PdfExporter<'a, W> {
fn new(
layouts: &'a [BoxLayout],
- loader: &'a SharedFontLoader,
+ loader: &'a FontLoader,
target: W,
) -> io::Result<Self> {
let (to_pdf, to_fontdock) = remap_fonts(layouts);
@@ -168,8 +168,8 @@ impl<'a, W: Write> PdfExporter<'a, W> {
let mut id = self.offsets.fonts.0;
for &face_id in &self.to_layout {
- let loader = self.loader.borrow();
- let face = loader.get_loaded(face_id);
+ let owned_face = self.loader.get_loaded(face_id);
+ let face = owned_face.get();
let name = face
.names()
@@ -269,7 +269,7 @@ impl<'a, W: Write> PdfExporter<'a, W> {
.write_obj(id + 3, &CMap::new("Custom", system_info, mapping))?;
// Write the face's bytes.
- self.writer.write_obj(id + 4, &FontStream::new(face.data()))?;
+ self.writer.write_obj(id + 4, &FontStream::new(owned_face.data()))?;
id += NUM_OBJECTS_PER_FONT;
}
diff --git a/src/font.rs b/src/font.rs
index 1e34ac05..539f3188 100644
--- a/src/font.rs
+++ b/src/font.rs
@@ -1,25 +1,34 @@
//! Font handling.
use std::cell::RefCell;
-use std::ops::Deref;
use std::rc::Rc;
-use fontdock::{ContainsChar, FaceFromVec, FontLoader, FontProvider};
+use fontdock::{ContainsChar, FaceFromVec, FontProvider};
use ttf_parser::Face;
-/// A referenced-count shared font loader backed by a dynamic provider.
-pub type SharedFontLoader = Rc<RefCell<FontLoader<Box<DynProvider>>>>;
+/// A reference-counted shared font loader backed by a dynamic font provider.
+pub type SharedFontLoader = Rc<RefCell<FontLoader>>;
-/// The dynamic font provider type backing the font loader.
+/// A font loader backed by a dynamic provider.
+pub type FontLoader = fontdock::FontLoader<Box<DynProvider>>;
+
+/// The dynamic font provider backing the font loader.
pub type DynProvider = dyn FontProvider<Face = OwnedFace>;
/// An owned font face.
pub struct OwnedFace {
- data: Vec<u8>,
+ data: Box<[u8]>,
face: Face<'static>,
}
impl OwnedFace {
+ /// Get a reference to the underlying face.
+ pub fn get<'a>(&'a self) -> &'a Face<'a> {
+ // We can't implement Deref because that would leak the internal 'static
+ // lifetime.
+ &self.face
+ }
+
/// The raw face data.
pub fn data(&self) -> &[u8] {
&self.data
@@ -28,13 +37,15 @@ impl OwnedFace {
impl FaceFromVec for OwnedFace {
fn from_vec(vec: Vec<u8>, i: u32) -> Option<Self> {
- // The vec's location is stable in memory since we don't touch it and
- // it can't be touched from outside this type.
+ let data = vec.into_boxed_slice();
+
+ // SAFETY: The slices's location is stable in memory since we don't
+ // touch it and it can't be touched from outside this type.
let slice: &'static [u8] =
- unsafe { std::slice::from_raw_parts(vec.as_ptr(), vec.len()) };
+ unsafe { std::slice::from_raw_parts(data.as_ptr(), data.len()) };
Some(Self {
- data: vec,
+ data,
face: Face::from_slice(slice, i).ok()?,
})
}
@@ -42,14 +53,6 @@ impl FaceFromVec for OwnedFace {
impl ContainsChar for OwnedFace {
fn contains_char(&self, c: char) -> bool {
- self.glyph_index(c).is_some()
- }
-}
-
-impl Deref for OwnedFace {
- type Target = Face<'static>;
-
- fn deref(&self) -> &Self::Target {
- &self.face
+ self.get().glyph_index(c).is_some()
}
}
diff --git a/src/layout/text.rs b/src/layout/text.rs
index 971d6be6..7dd557c9 100644
--- a/src/layout/text.rs
+++ b/src/layout/text.rs
@@ -9,7 +9,7 @@ use ttf_parser::GlyphId;
use super::elements::{LayoutElement, Shaped};
use super::*;
-use crate::font::SharedFontLoader;
+use crate::font::FontLoader;
use crate::geom::Size;
use crate::style::TextStyle;
@@ -30,11 +30,11 @@ struct TextLayouter<'a> {
}
/// The context for text layouting.
-#[derive(Debug, Copy, Clone)]
+#[derive(Debug)]
pub struct TextContext<'a> {
/// The font loader to retrieve fonts from when typesetting text with
/// `layout_text`.
- pub loader: &'a SharedFontLoader,
+ pub loader: &'a mut FontLoader,
/// The style for text: Font selection with classes, weights and variants,
/// font sizes, spacing and so on.
pub style: &'a TextStyle,
@@ -50,12 +50,12 @@ pub struct TextContext<'a> {
impl<'a> TextLayouter<'a> {
fn new(text: &'a str, ctx: TextContext<'a>) -> Self {
Self {
- ctx,
text,
shaped: Shaped::new(FaceId::MAX, ctx.style.font_size()),
elements: LayoutElements::new(),
start: 0.0,
width: 0.0,
+ ctx,
}
}
@@ -116,7 +116,6 @@ impl<'a> TextLayouter<'a> {
}
async fn select_font(&mut self, c: char) -> Option<(FaceId, GlyphId, f64)> {
- let mut loader = self.ctx.loader.borrow_mut();
let mut variant = self.ctx.style.variant;
if self.ctx.style.bolder {
@@ -137,7 +136,9 @@ impl<'a> TextLayouter<'a> {
c,
};
- if let Some((id, face)) = loader.query(query).await {
+ if let Some((id, owned_face)) = self.ctx.loader.query(query).await {
+ let face = owned_face.get();
+
// Determine the width of the char.
let units_per_em = face.units_per_em().unwrap_or(1000) as f64;
let ratio = 1.0 / units_per_em;
diff --git a/src/layout/tree.rs b/src/layout/tree.rs
index b6f9ab47..19bff091 100644
--- a/src/layout/tree.rs
+++ b/src/layout/tree.rs
@@ -107,7 +107,7 @@ impl<'a> TreeLayouter<'a> {
async fn layout_text(&mut self, text: &str) {
self.layouter.add(
layout_text(text, TextContext {
- loader: &self.ctx.loader,
+ loader: &mut self.ctx.loader.borrow_mut(),
style: &self.style.text,
dir: self.ctx.axes.primary,
align: self.ctx.align,
diff --git a/tests/test_typeset.rs b/tests/test_typeset.rs
index c7f4cd5d..e9051d10 100644
--- a/tests/test_typeset.rs
+++ b/tests/test_typeset.rs
@@ -7,13 +7,12 @@ use std::path::Path;
use std::rc::Rc;
use fontdock::fs::{FsIndex, FsProvider};
-use fontdock::FontLoader;
use futures_executor::block_on;
use raqote::{DrawTarget, PathBuilder, SolidSource, Source, Transform, Vector};
use ttf_parser::OutlineBuilder;
use typstc::export::pdf;
-use typstc::font::{DynProvider, SharedFontLoader};
+use typstc::font::{FontLoader, SharedFontLoader};
use typstc::geom::{Size, Value4};
use typstc::layout::elements::{LayoutElement, Shaped};
use typstc::layout::MultiLayout;
@@ -60,13 +59,12 @@ fn main() {
let mut index = FsIndex::new();
index.search_dir(FONT_DIR);
- let (descriptors, files) = index.clone().into_vecs();
- let provider = FsProvider::new(files.clone());
- let dynamic = Box::new(provider) as Box<DynProvider>;
- let loader = FontLoader::new(dynamic, descriptors);
+ let (descriptors, files) = index.into_vecs();
+ let provider = FsProvider::new(files);
+ let loader = FontLoader::new(Box::new(provider), descriptors);
let loader = Rc::new(RefCell::new(loader));
- let mut typesetter = Typesetter::new(loader.clone());
+ let mut typesetter = Typesetter::new(loader.clone());
typesetter.set_page_style(PageStyle {
class: PaperClass::Custom,
size: Size::with_all(Length::pt(250.0).as_raw()),
@@ -106,6 +104,8 @@ fn test(
);
}
+ let loader = loader.borrow();
+
let png_path = format!("{}/{}.png", OUT_DIR, name);
render(&layouts, &loader, 3.0).write_png(png_path).unwrap();
@@ -144,7 +144,7 @@ impl TestFilter {
}
}
-fn render(layouts: &MultiLayout, loader: &SharedFontLoader, scale: f64) -> DrawTarget {
+fn render(layouts: &MultiLayout, loader: &FontLoader, scale: f64) -> DrawTarget {
let pad = scale * 10.0;
let width = 2.0 * pad
+ layouts
@@ -191,13 +191,12 @@ fn render(layouts: &MultiLayout, loader: &SharedFontLoader, scale: f64) -> DrawT
fn render_shaped(
surface: &mut DrawTarget,
- loader: &SharedFontLoader,
+ loader: &FontLoader,
shaped: &Shaped,
pos: Size,
scale: f64,
) {
- let loader = loader.borrow();
- let face = loader.get_loaded(shaped.face);
+ let face = loader.get_loaded(shaped.face).get();
for (&glyph, &offset) in shaped.glyphs.iter().zip(&shaped.offsets) {
let mut builder = WrappedPathBuilder(PathBuilder::new());