From c1dd872b34507a9f45b39a8a6ac70606b642a19d Mon Sep 17 00:00:00 2001 From: Laurenz Date: Sun, 4 Oct 2020 19:57:39 +0200 Subject: [PATCH] =?UTF-8?q?Remove=20unncessary=20wrappers=20and=20typedefs?= =?UTF-8?q?=20=F0=9F=9B=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/eval/value.rs | 6 +-- src/export/pdf.rs | 4 +- src/layout/elements.rs | 83 ----------------------------------------- src/layout/line.rs | 35 ++++++----------- src/layout/mod.rs | 51 +++++++++++++++---------- src/layout/primitive.rs | 10 ++--- src/layout/stack.rs | 45 ++++++++++------------ src/layout/tree.rs | 5 +-- src/lib.rs | 13 ++----- src/prelude.rs | 2 +- src/shaping.rs | 61 +++++++++++++++++++++++++----- tests/test_typeset.rs | 7 ++-- 12 files changed, 134 insertions(+), 188 deletions(-) delete mode 100644 src/layout/elements.rs diff --git a/src/eval/value.rs b/src/eval/value.rs index 4ba1b6ba9..f1ffc6de3 100644 --- a/src/eval/value.rs +++ b/src/eval/value.rs @@ -9,7 +9,7 @@ use fontdock::{FontStretch, FontStyle, FontWeight}; use super::dict::{Dict, SpannedEntry}; use crate::color::RgbaColor; use crate::geom::Linear; -use crate::layout::{Command, Commands, Dir, LayoutContext, SpecAlign}; +use crate::layout::{Command, Dir, LayoutContext, SpecAlign}; use crate::paper::Paper; use crate::syntax::{Ident, Span, SpanWith, Spanned, SynNode, SynTree}; use crate::{DynFuture, Feedback}; @@ -49,7 +49,7 @@ pub enum Value { /// An executable function. Func(ValueFunc), /// Layouting commands. - Commands(Commands), + Commands(Vec), /// The result of invalid operations. Error, } @@ -83,7 +83,7 @@ impl Spanned { /// /// If this is already a command-value, it is simply unwrapped, otherwise /// the value is represented as layoutable content in a reasonable way. - pub fn into_commands(self) -> Commands { + pub fn into_commands(self) -> Vec { match self.v { // Pass-through. Value::Commands(commands) => commands, diff --git a/src/export/pdf.rs b/src/export/pdf.rs index d4d1adf21..fb1b3e3b5 100644 --- a/src/export/pdf.rs +++ b/src/export/pdf.rs @@ -138,7 +138,7 @@ impl<'a, W: Write> PdfExporter<'a, W> { let mut face = FaceId::MAX; let mut size = 0.0; - for (pos, element) in &page.elements.0 { + for (pos, element) in &page.elements { match element { LayoutElement::Text(shaped) => { if shaped.face != face || shaped.size != size { @@ -287,7 +287,7 @@ fn remap_fonts(layouts: &[BoxLayout]) -> (HashMap, Vec) { // We want to find out which font faces are used at all. To do that, look at // each text element to find out which face is uses. for layout in layouts { - for (_, element) in &layout.elements.0 { + for (_, element) in &layout.elements { let LayoutElement::Text(shaped) = element; to_pdf.entry(shaped.face).or_insert_with(|| { let next_id = to_layout.len(); diff --git a/src/layout/elements.rs b/src/layout/elements.rs deleted file mode 100644 index b5f83bfe4..000000000 --- a/src/layout/elements.rs +++ /dev/null @@ -1,83 +0,0 @@ -//! Basic building blocks of layouts. - -use std::fmt::{self, Debug, Formatter}; - -use fontdock::FaceId; -use ttf_parser::GlyphId; - -use crate::geom::Point; - -/// A collection of absolutely positioned layout elements. -#[derive(Debug, Default, Clone, PartialEq)] -pub struct LayoutElements(pub Vec<(Point, LayoutElement)>); - -impl LayoutElements { - /// Create an new empty collection. - pub fn new() -> Self { - Self(vec![]) - } - - /// Add an element at a position. - pub fn push(&mut self, pos: Point, element: LayoutElement) { - self.0.push((pos, element)); - } - - /// Add all elements of another collection, placing them relative to the - /// given position. - pub fn push_elements(&mut self, pos: Point, more: Self) { - for (subpos, element) in more.0 { - self.0.push((pos + subpos.to_vec2(), element)); - } - } -} - -/// A layout element, the basic building block layouts are composed of. -#[derive(Debug, Clone, PartialEq)] -pub enum LayoutElement { - Text(Shaped), -} - -/// A shaped run of text. -#[derive(Clone, PartialEq)] -pub struct Shaped { - /// The shaped text. - pub text: String, - /// The font face the text was shaped with. - pub face: FaceId, - /// The shaped glyphs. - pub glyphs: Vec, - /// The horizontal offsets of the glyphs. This is indexed parallel to `glyphs`. - /// Vertical offets are not yet supported. - pub offsets: Vec, - /// The font size. - pub size: f64, -} - -impl Shaped { - /// Create a new shape run with empty `text`, `glyphs` and `offsets`. - pub fn new(face: FaceId, size: f64) -> Self { - Self { - text: String::new(), - face, - glyphs: vec![], - offsets: vec![], - size, - } - } - - /// Encode the glyph ids into a big-endian byte buffer. - pub fn encode_glyphs_be(&self) -> Vec { - let mut bytes = Vec::with_capacity(2 * self.glyphs.len()); - for &GlyphId(g) in &self.glyphs { - bytes.push((g >> 8) as u8); - bytes.push((g & 0xff) as u8); - } - bytes - } -} - -impl Debug for Shaped { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "Shaped({})", self.text) - } -} diff --git a/src/layout/line.rs b/src/layout/line.rs index c190c152d..9de8348c8 100644 --- a/src/layout/line.rs +++ b/src/layout/line.rs @@ -22,7 +22,7 @@ pub struct LineLayouter { #[derive(Debug, Clone)] pub struct LineContext { /// The spaces to layout into. - pub spaces: LayoutSpaces, + pub spaces: Vec, /// The initial layouting system, which can be updated through `set_sys`. pub sys: LayoutSystem, /// The alignment of the _resulting_ layout. This does not effect the line @@ -132,15 +132,6 @@ impl LineLayouter { self.run.last_spacing = LastSpacing::None; } - /// Add multiple layouts. - /// - /// This is equivalent to calling `add` repeatedly for each layout. - pub fn add_multiple(&mut self, layouts: MultiLayout) { - for layout in layouts { - self.add(layout); - } - } - /// The remaining usable size of the line. /// /// This specifies how much more would fit before a line break would be @@ -201,7 +192,7 @@ impl LineLayouter { /// If `replace_empty` is true, the current space is replaced if there are /// no boxes laid out into it yet. Otherwise, the followup spaces are /// replaced. - pub fn set_spaces(&mut self, spaces: LayoutSpaces, replace_empty: bool) { + pub fn set_spaces(&mut self, spaces: Vec, replace_empty: bool) { self.stack.set_spaces(spaces, replace_empty && self.line_is_empty()); } @@ -212,7 +203,7 @@ impl LineLayouter { /// The remaining inner spaces. If something is laid out into these spaces, /// it will fit into this layouter's underlying stack. - pub fn remaining(&self) -> LayoutSpaces { + pub fn remaining(&self) -> Vec { let mut spaces = self.stack.remaining(); *spaces[0].size.secondary_mut(self.ctx.sys) -= self.run.size.height; spaces @@ -224,7 +215,7 @@ impl LineLayouter { } /// Finish everything up and return the final collection of boxes. - pub fn finish(mut self) -> MultiLayout { + pub fn finish(mut self) -> Vec { self.finish_line_if_not_empty(); self.stack.finish() } @@ -239,27 +230,25 @@ impl LineLayouter { /// Finish the active line and start a new one. pub fn finish_line(&mut self) { - let mut elements = LayoutElements::new(); + let mut layout = BoxLayout::new( + self.run.size.specialized(self.ctx.sys), + self.run.align.unwrap_or_default(), + ); let layouts = std::mem::take(&mut self.run.layouts); - for (offset, layout) in layouts { + for (offset, child) in layouts { let x = match self.ctx.sys.primary.is_positive() { true => offset, - false => self.run.size.width - offset - layout.size.primary(self.ctx.sys), + false => self.run.size.width - offset - child.size.primary(self.ctx.sys), }; let pos = Point::new(x, 0.0); - elements.push_elements(pos, layout.elements); + layout.push_layout(pos, child); } - self.stack.add(BoxLayout { - size: self.run.size.specialized(self.ctx.sys), - align: self.run.align.unwrap_or(LayoutAlign::START), - elements, - }); + self.stack.add(layout); self.run = LineRun::new(); - self.stack.add_spacing(self.ctx.line_spacing, SpacingKind::LINE); } diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 1ee862e3b..75d7b96b2 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -1,13 +1,11 @@ -//! Layouting of syntax trees into box layouts. +//! Layouting of syntax trees. pub mod primitive; -mod elements; mod line; mod stack; mod tree; -pub use elements::*; pub use line::*; pub use primitive::*; pub use stack::*; @@ -17,6 +15,7 @@ use crate::geom::{Insets, Point, Rect, RectExt, Sides, Size, SizeExt}; use crate::eval::{PageState, State, TextState}; use crate::font::SharedFontLoader; +use crate::shaping::Shaped; use crate::syntax::SynTree; use crate::{Feedback, Pass}; @@ -25,7 +24,7 @@ pub async fn layout( tree: &SynTree, state: State, loader: SharedFontLoader, -) -> Pass { +) -> Pass> { let space = LayoutSpace { size: state.page.size, insets: state.page.insets(), @@ -51,9 +50,6 @@ pub async fn layout( Pass::new(layouts, ctx.f) } -/// A collection of layouts. -pub type MultiLayout = Vec; - /// A finished box with content at fixed positions. #[derive(Debug, Clone, PartialEq)] pub struct BoxLayout { @@ -62,7 +58,34 @@ pub struct BoxLayout { /// How to align this box in a parent container. pub align: LayoutAlign, /// The elements composing this layout. - pub elements: LayoutElements, + pub elements: Vec<(Point, LayoutElement)>, +} + +impl BoxLayout { + /// Create an new empty collection. + pub fn new(size: Size, align: LayoutAlign) -> Self { + Self { size, align, elements: vec![] } + } + + /// Add an element at a position. + pub fn push(&mut self, pos: Point, element: LayoutElement) { + self.elements.push((pos, element)); + } + + /// Add all elements of another collection, placing them relative to the + /// given position. + pub fn push_layout(&mut self, pos: Point, more: Self) { + for (subpos, element) in more.elements { + self.push(pos + subpos.to_vec2(), element); + } + } +} + +/// A layout element, the basic building block layouts are composed of. +#[derive(Debug, Clone, PartialEq)] +pub enum LayoutElement { + /// Shaped text. + Text(Shaped), } /// The context for layouting. @@ -86,15 +109,12 @@ pub struct LayoutConstraints { /// The unpadded size of this container (the base 100% for relative sizes). pub base: Size, /// The spaces to layout into. - pub spaces: LayoutSpaces, + pub spaces: Vec, /// Whether to spill over into copies of the last space or finish layouting /// when the last space is used up. pub repeat: bool, } -/// A collection of layout spaces. -pub type LayoutSpaces = Vec; - /// The space into which content is laid out. #[derive(Debug, Copy, Clone, PartialEq)] pub struct LayoutSpace { @@ -129,9 +149,6 @@ impl LayoutSpace { } } -/// A sequence of layouting commands. -pub type Commands = Vec; - /// Commands executable by the layouting engine. #[derive(Debug, Clone, PartialEq)] pub enum Command { @@ -146,10 +163,6 @@ pub enum Command { /// Add a finished layout. Add(BoxLayout), - /// Add multiple layouts, one after another. This is equivalent to multiple - /// `Add` commands. - AddMultiple(MultiLayout), - /// Add spacing of the given kind along the primary or secondary axis. The /// kind defines how the spacing interacts with surrounding spacing. AddSpacing(f64, SpacingKind, GenAxis), diff --git a/src/layout/primitive.rs b/src/layout/primitive.rs index cdbe63c2d..d13110e3e 100644 --- a/src/layout/primitive.rs +++ b/src/layout/primitive.rs @@ -17,12 +17,10 @@ impl Default for LayoutSystem { /// Specifies where to align a layout in a parent container. pub type LayoutAlign = Gen2; -impl LayoutAlign { - /// The layout alignment that has both components set to `Start`. - pub const START: Self = Self { - primary: GenAlign::Start, - secondary: GenAlign::Start, - }; +impl Default for LayoutAlign { + fn default() -> Self { + Self::new(GenAlign::Start, GenAlign::Start) + } } /// Whether to expand a layout to an area's full size or shrink it to fit its content. diff --git a/src/layout/stack.rs b/src/layout/stack.rs index a68fbac08..e69dc0715 100644 --- a/src/layout/stack.rs +++ b/src/layout/stack.rs @@ -24,7 +24,7 @@ use super::*; /// Performs the stack layouting. pub struct StackLayouter { ctx: StackContext, - layouts: MultiLayout, + layouts: Vec, /// The in-progress space. space: Space, } @@ -33,7 +33,7 @@ pub struct StackLayouter { #[derive(Debug, Clone)] pub struct StackContext { /// The spaces to layout into. - pub spaces: LayoutSpaces, + pub spaces: Vec, /// The initial layouting system, which can be updated through `set_sys`. pub sys: LayoutSystem, /// The alignment of the _resulting_ layout. This does not effect the line @@ -75,7 +75,7 @@ impl StackLayouter { let space = ctx.spaces[0]; Self { ctx, - layouts: MultiLayout::new(), + layouts: vec![], space: Space::new(0, true, space.usable()), } } @@ -110,15 +110,6 @@ impl StackLayouter { self.space.last_spacing = LastSpacing::None; } - /// Add multiple layouts to the stack. - /// - /// This is equivalent to calling `add` repeatedly for each layout. - pub fn add_multiple(&mut self, layouts: MultiLayout) { - for layout in layouts { - self.add(layout); - } - } - /// Add spacing to the stack. pub fn add_spacing(&mut self, mut spacing: f64, kind: SpacingKind) { match kind { @@ -129,11 +120,13 @@ impl StackLayouter { let size = Size::new(0.0, spacing); self.update_metrics(size); - self.space.layouts.push((self.ctx.sys, BoxLayout { - size: size.specialized(self.ctx.sys), - align: LayoutAlign::START, - elements: LayoutElements::new(), - })); + self.space.layouts.push(( + self.ctx.sys, + BoxLayout::new( + size.specialized(self.ctx.sys), + LayoutAlign::default(), + ), + )); self.space.last_spacing = LastSpacing::Hard; } @@ -208,7 +201,7 @@ impl StackLayouter { /// If `replace_empty` is true, the current space is replaced if there are /// no boxes laid out into it yet. Otherwise, the followup spaces are /// replaced. - pub fn set_spaces(&mut self, spaces: LayoutSpaces, replace_empty: bool) { + pub fn set_spaces(&mut self, spaces: Vec, replace_empty: bool) { if replace_empty && self.space_is_empty() { self.ctx.spaces = spaces; self.start_space(0, self.space.hard); @@ -233,7 +226,7 @@ impl StackLayouter { /// The remaining inner spaces. If something is laid out into these spaces, /// it will fit into this stack. - pub fn remaining(&self) -> LayoutSpaces { + pub fn remaining(&self) -> Vec { let size = self.usable(); let mut spaces = vec![LayoutSpace { @@ -267,7 +260,7 @@ impl StackLayouter { } /// Finish everything up and return the final collection of boxes. - pub fn finish(mut self) -> MultiLayout { + pub fn finish(mut self) -> Vec { if self.space.hard || !self.space_is_empty() { self.finish_space(false); } @@ -360,12 +353,12 @@ impl StackLayouter { // Step 4: Align each layout in its bounding box and collect everything // into a single finished layout. - let mut elements = LayoutElements::new(); + let mut layout = BoxLayout::new(size, self.ctx.align); let layouts = std::mem::take(&mut self.space.layouts); - for ((sys, layout), bound) in layouts.into_iter().zip(bounds) { - let size = layout.size.specialized(sys); - let align = layout.align; + for ((sys, child), bound) in layouts.into_iter().zip(bounds) { + let size = child.size.specialized(sys); + let align = child.align; // The space in which this layout is aligned is given by the // distances between the borders of its bounding box. @@ -373,10 +366,10 @@ impl StackLayouter { let local = usable.anchor(align, sys) - size.anchor(align, sys); let pos = bound.origin() + local.to_size().specialized(sys).to_vec2(); - elements.push_elements(pos, layout.elements); + layout.push_layout(pos, child); } - self.layouts.push(BoxLayout { size, align: self.ctx.align, elements }); + self.layouts.push(layout); // ------------------------------------------------------------------ // // Step 5: Start the next space. diff --git a/src/layout/tree.rs b/src/layout/tree.rs index e26b0eb26..791bf14bc 100644 --- a/src/layout/tree.rs +++ b/src/layout/tree.rs @@ -8,7 +8,7 @@ use crate::syntax::{ use crate::DynFuture; /// Layout a syntax tree in a given context. -pub async fn layout_tree(tree: &SynTree, ctx: &mut LayoutContext) -> MultiLayout { +pub async fn layout_tree(tree: &SynTree, ctx: &mut LayoutContext) -> Vec { let mut layouter = TreeLayouter::new(ctx); layouter.layout_tree(tree).await; layouter.finish() @@ -38,7 +38,7 @@ impl<'a> TreeLayouter<'a> { } } - fn finish(self) -> MultiLayout { + fn finish(self) -> Vec { self.layouter.finish() } @@ -175,7 +175,6 @@ impl<'a> TreeLayouter<'a> { LayoutSyntaxTree(tree) => self.layout_tree(&tree).await, Add(layout) => self.layouter.add(layout), - AddMultiple(layouts) => self.layouter.add_multiple(layouts), AddSpacing(space, kind, axis) => match axis { GenAxis::Primary => self.layouter.add_primary_spacing(space, kind), GenAxis::Secondary => self.layouter.add_secondary_spacing(space, kind), diff --git a/src/lib.rs b/src/lib.rs index 21fabbd2f..1cd948d71 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,9 +43,9 @@ use std::future::Future; use std::pin::Pin; use crate::diagnostic::Diagnostic; -use crate::eval::{State, Value}; +use crate::eval::State; use crate::font::SharedFontLoader; -use crate::layout::{Commands, MultiLayout}; +use crate::layout::BoxLayout; use crate::syntax::{Decoration, Offset, Pos, SpanVec}; /// Process source code directly into a collection of layouts. @@ -53,7 +53,7 @@ pub async fn typeset( src: &str, state: State, loader: SharedFontLoader, -) -> Pass { +) -> Pass> { let parsed = parse::parse(src); let layouted = layout::layout(&parsed.output, state, loader).await; let feedback = Feedback::merge(parsed.feedback, layouted.feedback); @@ -93,13 +93,6 @@ impl Pass { } } -impl Pass { - /// Create a new pass with a list of layouting commands. - pub fn commands(commands: Commands, feedback: Feedback) -> Self { - Pass::new(Value::Commands(commands), feedback) - } -} - /// Diagnostic and semantic syntax highlighting data. #[derive(Debug, Default, Clone, Eq, PartialEq)] pub struct Feedback { diff --git a/src/prelude.rs b/src/prelude.rs index f31288443..a7a0fd008 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -4,7 +4,7 @@ pub use crate::eval::{Dict, Value, ValueDict}; pub use crate::layout::primitive::*; #[doc(no_inline)] -pub use crate::layout::{layout_tree, Command, Commands, LayoutContext}; +pub use crate::layout::{layout_tree, Command, LayoutContext}; #[doc(no_inline)] pub use crate::syntax::{Span, Spanned, SynTree}; pub use crate::{Feedback, Pass}; diff --git a/src/shaping.rs b/src/shaping.rs index 092f5e6e9..f56fa4441 100644 --- a/src/shaping.rs +++ b/src/shaping.rs @@ -4,15 +4,17 @@ //! font for each individual character. When the direction is right-to-left, the //! word is spelled backwards. Vertical shaping is not supported. +use std::fmt::{self, Debug, Formatter}; + use fontdock::{FaceId, FaceQuery, FallbackTree, FontStyle, FontVariant}; use ttf_parser::GlyphId; use crate::eval::TextState; use crate::font::FontLoader; use crate::geom::{Point, Size}; -use crate::layout::{BoxLayout, Dir, LayoutAlign, LayoutElement, LayoutElements, Shaped}; +use crate::layout::{BoxLayout, Dir, LayoutAlign, LayoutElement}; -/// Shape text into a box. +/// Shape text into a box containing shaped runs. pub async fn shape( text: &str, dir: Dir, @@ -23,6 +25,51 @@ pub async fn shape( Shaper::new(text, dir, align, state, loader).shape().await } +/// A shaped run of text. +#[derive(Clone, PartialEq)] +pub struct Shaped { + /// The shaped text. + pub text: String, + /// The font face the text was shaped with. + pub face: FaceId, + /// The shaped glyphs. + pub glyphs: Vec, + /// The horizontal offsets of the glyphs. This is indexed parallel to `glyphs`. + /// Vertical offets are not yet supported. + pub offsets: Vec, + /// The font size. + pub size: f64, +} + +impl Shaped { + /// Create a new shape run with empty `text`, `glyphs` and `offsets`. + pub fn new(face: FaceId, size: f64) -> Self { + Self { + text: String::new(), + face, + glyphs: vec![], + offsets: vec![], + size, + } + } + + /// Encode the glyph ids into a big-endian byte buffer. + pub fn encode_glyphs_be(&self) -> Vec { + let mut bytes = Vec::with_capacity(2 * self.glyphs.len()); + for &GlyphId(g) in &self.glyphs { + bytes.push((g >> 8) as u8); + bytes.push((g & 0xff) as u8); + } + bytes + } +} + +impl Debug for Shaped { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "Shaped({})", self.text) + } +} + /// Performs super-basic text shaping. struct Shaper<'a> { text: &'a str, @@ -64,11 +111,7 @@ impl<'a> Shaper<'a> { fallback: &state.fallback, loader, shaped: Shaped::new(FaceId::MAX, state.font_size()), - layout: BoxLayout { - size: Size::new(0.0, state.font_size()), - align, - elements: LayoutElements::new(), - }, + layout: BoxLayout::new(Size::new(0.0, state.font_size()), align), offset: 0.0, } } @@ -88,7 +131,7 @@ impl<'a> Shaper<'a> { // Flush the last buffered parts of the word. if !self.shaped.text.is_empty() { let pos = Point::new(self.offset, 0.0); - self.layout.elements.push(pos, LayoutElement::Text(self.shaped)); + self.layout.push(pos, LayoutElement::Text(self.shaped)); } self.layout @@ -111,7 +154,7 @@ impl<'a> Shaper<'a> { ); let pos = Point::new(self.offset, 0.0); - self.layout.elements.push(pos, LayoutElement::Text(shaped)); + self.layout.push(pos, LayoutElement::Text(shaped)); self.offset = self.layout.size.width; } diff --git a/tests/test_typeset.rs b/tests/test_typeset.rs index 4c30f0ed4..3d3b2b8f1 100644 --- a/tests/test_typeset.rs +++ b/tests/test_typeset.rs @@ -15,8 +15,9 @@ use typstc::eval::State; use typstc::export::pdf; use typstc::font::{FontLoader, SharedFontLoader}; use typstc::geom::{Point, Vec2}; -use typstc::layout::{LayoutElement, MultiLayout, Shaped}; +use typstc::layout::{BoxLayout, LayoutElement}; use typstc::parse::LineMap; +use typstc::shaping::Shaped; use typstc::{typeset, Feedback, Pass}; const TEST_DIR: &str = "tests"; @@ -136,7 +137,7 @@ impl TestFilter { } } -fn render(layouts: &MultiLayout, loader: &FontLoader, scale: f64) -> DrawTarget { +fn render(layouts: &[BoxLayout], loader: &FontLoader, scale: f64) -> DrawTarget { let pad = scale * 10.0; let width = 2.0 * pad + layouts @@ -167,7 +168,7 @@ fn render(layouts: &MultiLayout, loader: &FontLoader, scale: f64) -> DrawTarget &Default::default(), ); - for &(pos, ref element) in &layout.elements.0 { + for (pos, element) in &layout.elements { match element { LayoutElement::Text(shaped) => render_shaped( &mut surface,