Naming and grammar ✔

This commit is contained in:
Laurenz 2020-10-12 18:01:22 +02:00
parent 5243878d81
commit 1a70cb6a33
18 changed files with 91 additions and 88 deletions

View File

@ -24,7 +24,7 @@ pub struct RgbaColor {
/// user-defined value was invalid. /// user-defined value was invalid.
/// ///
/// If this is true, the color may be replaced with any color deemed /// If this is true, the color may be replaced with any color deemed
/// approriate at the use-site. /// appropriate at the use-site.
pub healed: bool, pub healed: bool,
} }

View File

@ -19,7 +19,7 @@ pub trait Convert: Sized {
/// back the original value. /// back the original value.
/// ///
/// In addition to the result, the method can return an optional diagnostic /// In addition to the result, the method can return an optional diagnostic
/// to warn even when the conversion suceeded or to explain the problem when /// to warn even when the conversion succeeded or to explain the problem when
/// the conversion failed. /// the conversion failed.
/// ///
/// The function takes a `Spanned<Value>` instead of just a `Value` so that /// The function takes a `Spanned<Value>` instead of just a `Value` so that

View File

@ -45,7 +45,7 @@ pub fn eval(tree: &SynTree, state: State) -> Pass<Document> {
pub struct EvalContext { pub struct EvalContext {
/// The active evaluation state. /// The active evaluation state.
pub state: State, pub state: State,
/// The accumualted feedback. /// The accumulated feedback.
f: Feedback, f: Feedback,
/// The finished page runs. /// The finished page runs.
runs: Vec<Pages>, runs: Vec<Pages>,
@ -74,7 +74,7 @@ impl EvalContext {
/// Finish evaluation and return the created document. /// Finish evaluation and return the created document.
pub fn finish(self) -> Pass<Document> { pub fn finish(self) -> Pass<Document> {
assert!(self.groups.is_empty(), "unpoped group"); assert!(self.groups.is_empty(), "unfinished group");
Pass::new(Document { runs: self.runs }, self.f) Pass::new(Document { runs: self.runs }, self.f)
} }

View File

@ -125,14 +125,14 @@ impl Debug for Value {
/// ``` /// ```
pub type ValueDict = Dict<SpannedEntry<Value>>; pub type ValueDict = Dict<SpannedEntry<Value>>;
/// An wrapper around a reference-counted executable function value. /// An wrapper around a reference-counted function trait object.
/// ///
/// The dynamic function object is wrapped in an `Rc` to keep [`Value`] /// The dynamic function object is wrapped in an `Rc` to keep [`Value`]
/// clonable. /// cloneable.
/// ///
/// _Note_: This is needed because the compiler can't `derive(PartialEq)` for /// _Note_: This is needed because the compiler can't `derive(PartialEq)` for
/// [`Value`] when directly putting the boxed function in there, see the /// [`Value`] when directly putting the `Rc` in there, see the [Rust
/// [Rust Issue]. /// Issue].
/// ///
/// [`Value`]: enum.Value.html /// [`Value`]: enum.Value.html
/// [Rust Issue]: https://github.com/rust-lang/rust/issues/31740 /// [Rust Issue]: https://github.com/rust-lang/rust/issues/31740

View File

@ -1,4 +1,4 @@
//! Geometrical primitivies. //! Geometrical primitives.
#[macro_use] #[macro_use]
mod macros; mod macros;

View File

@ -34,6 +34,6 @@ impl Pages {
pub fn layout(&self, ctx: &mut LayoutContext) -> Vec<BoxLayout> { pub fn layout(&self, ctx: &mut LayoutContext) -> Vec<BoxLayout> {
let areas = Areas::repeat(self.size); let areas = Areas::repeat(self.size);
let layouted = self.child.layout(ctx, &areas); let layouted = self.child.layout(ctx, &areas);
layouted.into_boxes() layouted.into_layouts()
} }
} }

View File

@ -37,7 +37,7 @@ pub struct LayoutContext {
/// Layout a node. /// Layout a node.
pub trait Layout { pub trait Layout {
/// Layout the node in the given layout context. /// Layout the node into the given areas.
fn layout(&self, ctx: &mut LayoutContext, areas: &Areas) -> Layouted; fn layout(&self, ctx: &mut LayoutContext, areas: &Areas) -> Layouted;
} }
@ -120,26 +120,27 @@ impl Expansion {
} }
} }
/// An item that is produced by [layouting] a node. /// The result of [layouting] a node.
/// ///
/// [layouting]: trait.Layout.html#method.layout /// [layouting]: trait.Layout.html#method.layout
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum Layouted { pub enum Layouted {
/// Spacing that should be added to the parent. /// Spacing that should be added to the parent.
Spacing(Length), Spacing(Length),
/// A box that should be added to and aligned in the parent. /// A layout that should be added to and aligned in the parent.
Boxed(BoxLayout, Gen<Align>), Layout(BoxLayout, Gen<Align>),
/// Multiple boxes. /// Multiple layouts.
Boxes(Vec<(BoxLayout, Gen<Align>)>), Layouts(Vec<BoxLayout>, Gen<Align>),
} }
impl Layouted { impl Layouted {
/// Return the box if this if its a box variant. /// Return all layouts contained in this variant (zero, one or arbitrarily
pub fn into_boxes(self) -> Vec<BoxLayout> { /// many).
pub fn into_layouts(self) -> Vec<BoxLayout> {
match self { match self {
Self::Spacing(_) => vec![], Self::Spacing(_) => vec![],
Self::Boxed(boxed, _) => vec![boxed], Self::Layout(layout, _) => vec![layout],
Self::Boxes(boxes) => boxes.into_iter().map(|p| p.0).collect(), Self::Layouts(layouts, _) => layouts,
} }
} }
} }

View File

@ -29,7 +29,7 @@ impl Layout for LayoutNode {
match self { match self {
Self::Spacing(spacing) => spacing.layout(ctx, areas), Self::Spacing(spacing) => spacing.layout(ctx, areas),
Self::Text(text) => text.layout(ctx, areas), Self::Text(text) => text.layout(ctx, areas),
Self::Dyn(boxed) => boxed.layout(ctx, areas), Self::Dyn(dynamic) => dynamic.layout(ctx, areas),
} }
} }
} }
@ -39,16 +39,16 @@ impl Debug for LayoutNode {
match self { match self {
Self::Spacing(spacing) => spacing.fmt(f), Self::Spacing(spacing) => spacing.fmt(f),
Self::Text(text) => text.fmt(f), Self::Text(text) => text.fmt(f),
Self::Dyn(boxed) => boxed.fmt(f), Self::Dyn(dynamic) => dynamic.fmt(f),
} }
} }
} }
/// A wrapper around a boxed dynamic node. /// A wrapper around a boxed node trait object.
/// ///
/// _Note_: This is needed because the compiler can't `derive(PartialEq)` for /// _Note_: This is needed because the compiler can't `derive(PartialEq)` for
/// [`LayoutNode`] when directly putting the boxed node in there, see /// [`LayoutNode`] when directly putting the `Box` in there, see the
/// the [Rust Issue]. /// [Rust Issue].
/// ///
/// [`LayoutNode`]: enum.LayoutNode.html /// [`LayoutNode`]: enum.LayoutNode.html
/// [Rust Issue]: https://github.com/rust-lang/rust/issues/31740 /// [Rust Issue]: https://github.com/rust-lang/rust/issues/31740

View File

@ -17,10 +17,10 @@ impl Layout for Pad {
let mut layouted = self.child.layout(ctx, &areas); let mut layouted = self.child.layout(ctx, &areas);
match &mut layouted { match &mut layouted {
Layouted::Spacing(_) => {} Layouted::Spacing(_) => {}
Layouted::Boxed(boxed, _) => pad_box(boxed, self.padding), Layouted::Layout(layout, _) => pad_layout(layout, self.padding),
Layouted::Boxes(boxes) => { Layouted::Layouts(layouts, _) => {
for (boxed, _) in boxes { for layout in layouts {
pad_box(boxed, self.padding); pad_layout(layout, self.padding);
} }
} }
} }
@ -43,12 +43,12 @@ fn shrink_areas(areas: &Areas, padding: Sides<Linear>) -> Areas {
} }
/// Enlarge the box and move all elements inwards. /// Enlarge the box and move all elements inwards.
fn pad_box(boxed: &mut BoxLayout, padding: Sides<Linear>) { fn pad_layout(layout: &mut BoxLayout, padding: Sides<Linear>) {
let padding = padding.eval(boxed.size); let padding = padding.eval(layout.size);
let origin = Point::new(padding.left, padding.top); let origin = Point::new(padding.left, padding.top);
boxed.size += padding.size(); layout.size += padding.size();
for (point, _) in &mut boxed.elements { for (point, _) in &mut layout.elements {
*point += origin; *point += origin;
} }
} }

View File

@ -23,16 +23,18 @@ impl Layout for Par {
let mut layouter = ParLayouter::new(self, areas.clone()); let mut layouter = ParLayouter::new(self, areas.clone());
for child in &self.children { for child in &self.children {
match child.layout(ctx, &layouter.areas) { match child.layout(ctx, &layouter.areas) {
Layouted::Spacing(spacing) => layouter.spacing(spacing), Layouted::Spacing(spacing) => layouter.push_spacing(spacing),
Layouted::Boxed(boxed, aligns) => layouter.boxed(boxed, aligns.cross), Layouted::Layout(layout, aligns) => {
Layouted::Boxes(boxes) => { layouter.push_layout(layout, aligns.cross)
for (boxed, aligns) in boxes { }
layouter.boxed(boxed, aligns.cross); Layouted::Layouts(layouts, aligns) => {
for layout in layouts {
layouter.push_layout(layout, aligns.cross);
} }
} }
} }
} }
Layouted::Boxes(layouter.finish()) Layouted::Layouts(layouter.finish(), self.aligns)
} }
} }
@ -48,7 +50,7 @@ struct ParLayouter<'a> {
cross: SpecAxis, cross: SpecAxis,
dirs: Gen<Dir>, dirs: Gen<Dir>,
areas: Areas, areas: Areas,
layouted: Vec<(BoxLayout, Gen<Align>)>, finished: Vec<BoxLayout>,
lines: Vec<(Length, BoxLayout, Align)>, lines: Vec<(Length, BoxLayout, Align)>,
lines_size: Gen<Length>, lines_size: Gen<Length>,
run: Vec<(Length, BoxLayout, Align)>, run: Vec<(Length, BoxLayout, Align)>,
@ -64,7 +66,7 @@ impl<'a> ParLayouter<'a> {
cross: par.dirs.cross.axis(), cross: par.dirs.cross.axis(),
dirs: par.dirs, dirs: par.dirs,
areas, areas,
layouted: vec![], finished: vec![],
lines: vec![], lines: vec![],
lines_size: Gen::ZERO, lines_size: Gen::ZERO,
run: vec![], run: vec![],
@ -73,12 +75,12 @@ impl<'a> ParLayouter<'a> {
} }
} }
fn spacing(&mut self, amount: Length) { fn push_spacing(&mut self, amount: Length) {
let cross_full = self.areas.current.rem.get(self.cross); let cross_max = self.areas.current.rem.get(self.cross);
self.run_size.cross = (self.run_size.cross + amount).min(cross_full); self.run_size.cross = (self.run_size.cross + amount).min(cross_max);
} }
fn boxed(&mut self, layout: BoxLayout, align: Align) { fn push_layout(&mut self, layout: BoxLayout, align: Align) {
if self.run_ruler > align { if self.run_ruler > align {
self.finish_run(); self.finish_run();
} }
@ -112,12 +114,12 @@ impl<'a> ParLayouter<'a> {
} }
fn finish_run(&mut self) { fn finish_run(&mut self) {
let size = Gen::new(self.run_size.main, match self.par.cross_expansion { let full_size = Gen::new(self.run_size.main, match self.par.cross_expansion {
Expansion::Fill => self.areas.current.full.get(self.cross), Expansion::Fill => self.areas.current.full.get(self.cross),
Expansion::Fit => self.run_size.cross, Expansion::Fit => self.run_size.cross,
}); });
let mut output = BoxLayout::new(size.switch(self.dirs).to_size()); let mut output = BoxLayout::new(full_size.switch(self.dirs).to_size());
for (before, layout, align) in std::mem::take(&mut self.run) { for (before, layout, align) in std::mem::take(&mut self.run) {
let child_cross_size = layout.size.get(self.cross); let child_cross_size = layout.size.get(self.cross);
@ -125,11 +127,11 @@ impl<'a> ParLayouter<'a> {
// Position along the cross axis. // Position along the cross axis.
let cross = align.apply(if self.dirs.cross.is_positive() { let cross = align.apply(if self.dirs.cross.is_positive() {
let after_with_self = self.run_size.cross - before; let after_with_self = self.run_size.cross - before;
before .. size.cross - after_with_self before .. full_size.cross - after_with_self
} else { } else {
let before_with_self = before + child_cross_size; let before_with_self = before + child_cross_size;
let after = self.run_size.cross - (before + child_cross_size); let after = self.run_size.cross - (before + child_cross_size);
size.cross - before_with_self .. after full_size.cross - before_with_self .. after
}); });
let pos = Gen::new(Length::ZERO, cross).switch(self.dirs).to_point(); let pos = Gen::new(Length::ZERO, cross).switch(self.dirs).to_point();
@ -138,10 +140,10 @@ impl<'a> ParLayouter<'a> {
self.lines.push((self.lines_size.main, output, self.run_ruler)); self.lines.push((self.lines_size.main, output, self.run_ruler));
let main_offset = size.main + self.par.line_spacing; let main_offset = full_size.main + self.par.line_spacing;
*self.areas.current.rem.get_mut(self.main) -= main_offset; *self.areas.current.rem.get_mut(self.main) -= main_offset;
self.lines_size.main += main_offset; self.lines_size.main += main_offset;
self.lines_size.cross = self.lines_size.cross.max(size.cross); self.lines_size.cross = self.lines_size.cross.max(full_size.cross);
self.run_size = Gen::ZERO; self.run_size = Gen::ZERO;
self.run_ruler = Align::Start; self.run_ruler = Align::Start;
@ -172,15 +174,15 @@ impl<'a> ParLayouter<'a> {
output.push_layout(pos, run); output.push_layout(pos, run);
} }
self.layouted.push((output, self.par.aligns)); self.finished.push(output);
self.areas.next(); self.areas.next();
self.lines_size = Gen::ZERO; self.lines_size = Gen::ZERO;
} }
fn finish(mut self) -> Vec<(BoxLayout, Gen<Align>)> { fn finish(mut self) -> Vec<BoxLayout> {
self.finish_run(); self.finish_run();
self.finish_area(); self.finish_area();
self.layouted self.finished
} }
} }

View File

@ -21,16 +21,16 @@ impl Layout for Stack {
let mut layouter = StackLayouter::new(self, areas.clone()); let mut layouter = StackLayouter::new(self, areas.clone());
for child in &self.children { for child in &self.children {
match child.layout(ctx, &layouter.areas) { match child.layout(ctx, &layouter.areas) {
Layouted::Spacing(spacing) => layouter.spacing(spacing), Layouted::Spacing(spacing) => layouter.push_spacing(spacing),
Layouted::Boxed(boxed, aligns) => layouter.boxed(boxed, aligns), Layouted::Layout(layout, aligns) => layouter.push_layout(layout, aligns),
Layouted::Boxes(boxes) => { Layouted::Layouts(layouts, aligns) => {
for (boxed, aligns) in boxes { for layout in layouts {
layouter.boxed(boxed, aligns); layouter.push_layout(layout, aligns);
} }
} }
} }
} }
Layouted::Boxes(layouter.finish()) Layouted::Layouts(layouter.finish(), self.aligns)
} }
} }
@ -45,8 +45,8 @@ struct StackLayouter<'a> {
main: SpecAxis, main: SpecAxis,
dirs: Gen<Dir>, dirs: Gen<Dir>,
areas: Areas, areas: Areas,
layouted: Vec<(BoxLayout, Gen<Align>)>, finished: Vec<BoxLayout>,
boxes: Vec<(Length, BoxLayout, Gen<Align>)>, layouts: Vec<(Length, BoxLayout, Gen<Align>)>,
used: Gen<Length>, used: Gen<Length>,
ruler: Align, ruler: Align,
} }
@ -58,21 +58,21 @@ impl<'a> StackLayouter<'a> {
main: stack.dirs.main.axis(), main: stack.dirs.main.axis(),
dirs: stack.dirs, dirs: stack.dirs,
areas, areas,
layouted: vec![], finished: vec![],
boxes: vec![], layouts: vec![],
used: Gen::ZERO, used: Gen::ZERO,
ruler: Align::Start, ruler: Align::Start,
} }
} }
fn spacing(&mut self, amount: Length) { fn push_spacing(&mut self, amount: Length) {
let main_rest = self.areas.current.rem.get_mut(self.main); let main_rest = self.areas.current.rem.get_mut(self.main);
let capped = amount.min(*main_rest); let capped = amount.min(*main_rest);
*main_rest -= capped; *main_rest -= capped;
self.used.main += capped; self.used.main += capped;
} }
fn boxed(&mut self, layout: BoxLayout, aligns: Gen<Align>) { fn push_layout(&mut self, layout: BoxLayout, aligns: Gen<Align>) {
if self.ruler > aligns.main { if self.ruler > aligns.main {
self.finish_area(); self.finish_area();
} }
@ -88,7 +88,7 @@ impl<'a> StackLayouter<'a> {
} }
let size = layout.size.switch(self.dirs); let size = layout.size.switch(self.dirs);
self.boxes.push((self.used.main, layout, aligns)); self.layouts.push((self.used.main, layout, aligns));
*self.areas.current.rem.get_mut(self.main) -= size.main; *self.areas.current.rem.get_mut(self.main) -= size.main;
self.used.main += size.main; self.used.main += size.main;
@ -97,7 +97,7 @@ impl<'a> StackLayouter<'a> {
} }
fn finish_area(&mut self) { fn finish_area(&mut self) {
let size = { let full_size = {
let full = self.areas.current.full.switch(self.dirs); let full = self.areas.current.full.switch(self.dirs);
Gen::new( Gen::new(
match self.stack.expansion.main { match self.stack.expansion.main {
@ -111,41 +111,41 @@ impl<'a> StackLayouter<'a> {
) )
}; };
let mut output = BoxLayout::new(size.switch(self.dirs).to_size()); let mut output = BoxLayout::new(full_size.switch(self.dirs).to_size());
for (before, layout, aligns) in std::mem::take(&mut self.boxes) { for (before, layout, aligns) in std::mem::take(&mut self.layouts) {
let child_size = layout.size.switch(self.dirs); let child_size = layout.size.switch(self.dirs);
// Align along the main axis. // Align along the main axis.
let main = aligns.main.apply(if self.dirs.main.is_positive() { let main = aligns.main.apply(if self.dirs.main.is_positive() {
let after_with_self = self.used.main - before; let after_with_self = self.used.main - before;
before .. size.main - after_with_self before .. full_size.main - after_with_self
} else { } else {
let before_with_self = before + child_size.main; let before_with_self = before + child_size.main;
let after = self.used.main - (before + child_size.main); let after = self.used.main - (before + child_size.main);
size.main - before_with_self .. after full_size.main - before_with_self .. after
}); });
// Align along the cross axis. // Align along the cross axis.
let cross = aligns.cross.apply(if self.dirs.cross.is_positive() { let cross = aligns.cross.apply(if self.dirs.cross.is_positive() {
Length::ZERO .. size.cross - child_size.cross Length::ZERO .. full_size.cross - child_size.cross
} else { } else {
size.cross - child_size.cross .. Length::ZERO full_size.cross - child_size.cross .. Length::ZERO
}); });
let pos = Gen::new(main, cross).switch(self.dirs).to_point(); let pos = Gen::new(main, cross).switch(self.dirs).to_point();
output.push_layout(pos, layout); output.push_layout(pos, layout);
} }
self.layouted.push((output, self.stack.aligns)); self.finished.push(output);
self.areas.next(); self.areas.next();
self.used = Gen::ZERO; self.used = Gen::ZERO;
self.ruler = Align::Start; self.ruler = Align::Start;
} }
fn finish(mut self) -> Vec<(BoxLayout, Gen<Align>)> { fn finish(mut self) -> Vec<BoxLayout> {
self.finish_area(); self.finish_area();
self.layouted self.finished
} }
} }

View File

@ -26,7 +26,7 @@ pub struct Text {
impl Layout for Text { impl Layout for Text {
fn layout(&self, ctx: &mut LayoutContext, _: &Areas) -> Layouted { fn layout(&self, ctx: &mut LayoutContext, _: &Areas) -> Layouted {
let mut loader = ctx.loader.borrow_mut(); let mut loader = ctx.loader.borrow_mut();
Layouted::Boxed( Layouted::Layout(
shaping::shape( shaping::shape(
&mut loader, &mut loader,
&self.text, &self.text,

View File

@ -10,7 +10,7 @@
//! document tree are fully self-contained and order-independent and thus much //! document tree are fully self-contained and order-independent and thus much
//! better suited for layouting than the syntax tree. //! better suited for layouting than the syntax tree.
//! - **Layouting:** The next step is to [layout] the document into a portable //! - **Layouting:** The next step is to [layout] the document into a portable
//! version of the typesetted document. The output of this is a vector of //! version of the typeset document. The output of this is a vector of
//! [`BoxLayouts`] (corresponding to pages), ready for exporting. //! [`BoxLayouts`] (corresponding to pages), ready for exporting.
//! - **Exporting:** The finished layout can be exported into a supported //! - **Exporting:** The finished layout can be exported into a supported
//! format. Submodules for these formats are located in the [export] module. //! format. Submodules for these formats are located in the [export] module.

View File

@ -47,7 +47,7 @@ use crate::prelude::*;
/// [font: serif = ("Source Serif Pro", "Noto Serif")] /// [font: serif = ("Source Serif Pro", "Noto Serif")]
/// ``` /// ```
/// This class can be used in the fallback list or other fallback classes as /// This class can be used in the fallback list or other fallback classes as
/// long as the resulting fallback tree is acylic. /// long as the resulting fallback tree is acyclic.
/// ```typst /// ```typst
/// [font: "My Serif", serif] /// [font: "My Serif", serif]
/// ``` /// ```

View File

@ -268,8 +268,8 @@ fn dict_contents(p: &mut Parser) -> (LitDict, bool) {
comma_and_keyless = false; comma_and_keyless = false;
} }
let coercable = comma_and_keyless && !dict.0.is_empty(); let coercible = comma_and_keyless && !dict.0.is_empty();
(dict, coercable) (dict, coercible)
} }
/// Parse a single entry in a dictionary. /// Parse a single entry in a dictionary.
@ -458,9 +458,9 @@ fn content(p: &mut Parser) -> SynTree {
/// Parse a parenthesized expression: `(a + b)`, `(1, key="value"). /// Parse a parenthesized expression: `(a + b)`, `(1, key="value").
fn parenthesized(p: &mut Parser) -> Expr { fn parenthesized(p: &mut Parser) -> Expr {
p.start_group(Group::Paren); p.start_group(Group::Paren);
let (dict, coercable) = dict_contents(p); let (dict, coercible) = dict_contents(p);
let expr = if coercable { let expr = if coercible {
dict.0.into_iter().next().expect("dict is coercable").expr.v dict.0.into_iter().next().expect("dict is coercible").expr.v
} else { } else {
Expr::Lit(Lit::Dict(dict)) Expr::Lit(Lit::Dict(dict))
}; };

View File

@ -110,7 +110,7 @@ impl<'s> Parser<'s> {
// Check that we are indeed at the end of the group. // Check that we are indeed at the end of the group.
debug_assert_eq!(self.peek(), None, "unfinished group"); debug_assert_eq!(self.peek(), None, "unfinished group");
let group = self.groups.pop().expect("unstarted group"); let group = self.groups.pop().expect("no started group");
let end = match group { let end = match group {
Group::Paren => Some(Token::RightParen), Group::Paren => Some(Token::RightParen),
Group::Bracket => Some(Token::RightBracket), Group::Bracket => Some(Token::RightBracket),

View File

@ -42,7 +42,7 @@ pub fn resolve_string(string: &str) -> String {
out out
} }
/// Resolve a hexademical escape sequence into a character /// Resolve a hexadecimal escape sequence into a character
/// (only the inner hex letters without braces or `\u`). /// (only the inner hex letters without braces or `\u`).
pub fn resolve_hex(sequence: &str) -> Option<char> { pub fn resolve_hex(sequence: &str) -> Option<char> {
u32::from_str_radix(sequence, 16).ok().and_then(std::char::from_u32) u32::from_str_radix(sequence, 16).ok().and_then(std::char::from_u32)

View File

@ -23,7 +23,7 @@ pub struct Shaped {
/// The shaped glyphs. /// The shaped glyphs.
pub glyphs: Vec<GlyphId>, pub glyphs: Vec<GlyphId>,
/// The horizontal offsets of the glyphs. This is indexed parallel to /// The horizontal offsets of the glyphs. This is indexed parallel to
/// `glyphs`. Vertical offets are not yet supported. /// `glyphs`. Vertical offsets are not yet supported.
pub offsets: Vec<Length>, pub offsets: Vec<Length>,
/// The font size. /// The font size.
pub font_size: Length, pub font_size: Length,