From 985fe281665fb8dfac6d8ffaf8d09afb6eb1ef3e Mon Sep 17 00:00:00 2001 From: Laurenz Date: Tue, 6 Oct 2020 14:44:58 +0200 Subject: [PATCH] =?UTF-8?q?Fix=20bug=20in=20line=20layouter=20=E2=9C=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/geom.rs | 101 +++++++++++++++++++------------------- src/layout/line.rs | 14 +++--- src/layout/mod.rs | 2 +- src/layout/primitive.rs | 106 +++++++++++++++++++++++----------------- 4 files changed, 118 insertions(+), 105 deletions(-) diff --git a/src/geom.rs b/src/geom.rs index 0089aa4af..d69797b0f 100644 --- a/src/geom.rs +++ b/src/geom.rs @@ -6,18 +6,60 @@ pub use kurbo::*; use std::fmt::{self, Debug, Formatter}; use std::ops::*; -use crate::layout::primitive::{Dir, Gen2, GenAlign, Side, SpecAxis}; +use crate::layout::primitive::{Dir, Gen2, GenAlign, Get, Side, SpecAxis}; + +macro_rules! impl_get_2d { + ($t:ty, $x:ident, $y:ident) => { + impl Get for $t { + type Component = f64; + + fn get(self, axis: SpecAxis) -> f64 { + match axis { + SpecAxis::Horizontal => self.$x, + SpecAxis::Vertical => self.$y, + } + } + + fn get_mut(&mut self, axis: SpecAxis) -> &mut f64 { + match axis { + SpecAxis::Horizontal => &mut self.$x, + SpecAxis::Vertical => &mut self.$y, + } + } + } + }; +} + +impl_get_2d!(Point, x, y); +impl_get_2d!(Vec2, x, y); +impl_get_2d!(Size, width, height); + +impl Get for Rect { + type Component = f64; + + fn get(self, side: Side) -> f64 { + match side { + Side::Left => self.x0, + Side::Top => self.y0, + Side::Right => self.x1, + Side::Bottom => self.y1, + } + } + + fn get_mut(&mut self, side: Side) -> &mut f64 { + match side { + Side::Left => &mut self.x0, + Side::Top => &mut self.y0, + Side::Right => &mut self.x1, + Side::Bottom => &mut self.y1, + } + } +} /// Additional methods for [sizes]. /// /// [sizes]: ../../kurbo/struct.Size.html pub trait SizeExt { - /// Return the component for the specified axis. - fn get(self, axis: SpecAxis) -> f64; - - /// Borrow the component for the specified axis mutably. - fn get_mut(&mut self, axis: SpecAxis) -> &mut f64; - /// Returns the generalized version of a `Size` based on the current /// directions. /// @@ -43,20 +85,6 @@ pub trait SizeExt { } impl SizeExt for Size { - fn get(self, axis: SpecAxis) -> f64 { - match axis { - SpecAxis::Horizontal => self.width, - SpecAxis::Vertical => self.height, - } - } - - fn get_mut(&mut self, axis: SpecAxis) -> &mut f64 { - match axis { - SpecAxis::Horizontal => &mut self.width, - SpecAxis::Vertical => &mut self.height, - } - } - fn generalized(self, dirs: Gen2) -> Self { match dirs.main.axis() { SpecAxis::Horizontal => Self::new(self.height, self.width), @@ -90,37 +118,6 @@ impl SizeExt for Size { } } -/// Additional methods for [rectangles]. -/// -/// [rectangles]: ../../kurbo/struct.Rect.html -pub trait RectExt { - /// Return the value for the given side. - fn get(self, side: Side) -> f64; - - /// Borrow the value for the given side mutably. - fn get_mut(&mut self, side: Side) -> &mut f64; -} - -impl RectExt for Rect { - fn get(self, side: Side) -> f64 { - match side { - Side::Left => self.x0, - Side::Top => self.y0, - Side::Right => self.x1, - Side::Bottom => self.y1, - } - } - - fn get_mut(&mut self, side: Side) -> &mut f64 { - match side { - Side::Left => &mut self.x0, - Side::Top => &mut self.y0, - Side::Right => &mut self.x1, - Side::Bottom => &mut self.y1, - } - } -} - /// A function that depends linearly on one value. /// /// This represents a function `f(x) = rel * x + abs`. diff --git a/src/layout/line.rs b/src/layout/line.rs index acf143c0c..c1b5920f4 100644 --- a/src/layout/line.rs +++ b/src/layout/line.rs @@ -198,19 +198,17 @@ impl LineLayouter { pub fn finish_line(&mut self) { let mut layout = BoxLayout::new(self.run.size.specialized(self.ctx.dirs)); let aligns = self.run.aligns.unwrap_or_default(); + let cross = self.ctx.dirs.cross; let layouts = std::mem::take(&mut self.run.layouts); for (offset, child) in layouts { - let x = match self.ctx.dirs.cross.is_positive() { - true => offset, - false => { - self.run.size.width - - offset - - child.size.get(self.ctx.dirs.cross.axis()) - } + let mut pos = Point::ZERO; + *pos.get_mut(cross.axis()) = if cross.is_positive() { + offset + } else { + self.run.size.width - offset - child.size.get(cross.axis()) }; - let pos = Point::new(x, 0.0); layout.push_layout(pos, child); } diff --git a/src/layout/mod.rs b/src/layout/mod.rs index f9372e506..912ca0104 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -14,7 +14,7 @@ pub use tree::*; use crate::diag::Diag; use crate::eval::{PageState, State, TextState}; use crate::font::SharedFontLoader; -use crate::geom::{Insets, Point, Rect, RectExt, Size, SizeExt}; +use crate::geom::{Insets, Point, Rect, Size, SizeExt}; use crate::shaping::Shaped; use crate::syntax::{Deco, Spanned, SynTree}; use crate::{Feedback, Pass}; diff --git a/src/layout/primitive.rs b/src/layout/primitive.rs index 9070c9727..549c1f29f 100644 --- a/src/layout/primitive.rs +++ b/src/layout/primitive.rs @@ -2,6 +2,50 @@ use std::fmt::{self, Display, Formatter}; +/// Generic access to a structure's components. +pub trait Get { + /// The structure's component type. + type Component; + + /// Return the component for the specified index. + fn get(self, index: Index) -> Self::Component; + + /// Borrow the component for the specified index mutably. + fn get_mut(&mut self, index: Index) -> &mut Self::Component; +} + +/// Convert a type into its generic representation. +/// +/// The generic representation deals with main and cross axes while the specific +/// representation deals with horizontal and vertical axes. +/// +/// See also [`ToSpec`] for the inverse conversion. +/// +/// [`ToSpec`]: trait.ToSpec.html +pub trait ToGen { + /// The generic version of this type. + type Output; + + /// The generic version of this type based on the current directions. + fn to_gen(self, dirs: Gen2) -> Self::Output; +} + +/// Convert a type into its specific representation. +/// +/// The specific representation deals with horizontal and vertical axes while +/// the generic representation deals with main and cross axes. +/// +/// See also [`ToGen`] for the inverse conversion. +/// +/// [`ToGen`]: trait.ToGen.html +pub trait ToSpec { + /// The specific version of this type. + type Output; + + /// The specific version of this type based on the current directions. + fn to_spec(self, dirs: Gen2) -> Self::Output; +} + /// The four directions into which content can be laid out. #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum Dir { @@ -81,38 +125,6 @@ impl Display for Dir { } } -/// Convert a type into its generic representation. -/// -/// The generic representation deals with main and cross axes while the specific -/// representation deals with horizontal and vertical axes. -/// -/// See also [`ToSpec`] for the inverse conversion. -/// -/// [`ToSpec`]: trait.ToSpec.html -pub trait ToGen { - /// The generic version of this type. - type Output; - - /// The generic version of this type based on the current directions. - fn to_gen(self, dirs: Gen2) -> Self::Output; -} - -/// Convert a type into its specific representation. -/// -/// The specific representation deals with horizontal and vertical axes while -/// the generic representation deals with main and cross axes. -/// -/// See also [`ToGen`] for the inverse conversion. -/// -/// [`ToGen`]: trait.ToGen.html -pub trait ToSpec { - /// The specific version of this type. - type Output; - - /// The specific version of this type based on the current directions. - fn to_spec(self, dirs: Gen2) -> Self::Output; -} - /// A generic container with two components for the two generic axes. #[derive(Debug, Default, Copy, Clone, Eq, PartialEq)] pub struct Gen2 { @@ -127,17 +139,19 @@ impl Gen2 { pub fn new(main: T, cross: T) -> Self { Self { main, cross } } +} - /// Return the component for the specified generic axis. - pub fn get(self, axis: GenAxis) -> T { +impl Get for Gen2 { + type Component = T; + + fn get(self, axis: GenAxis) -> T { match axis { GenAxis::Main => self.main, GenAxis::Cross => self.cross, } } - /// Borrow the component for the specified generic axis mutably. - pub fn get_mut(&mut self, axis: GenAxis) -> &mut T { + fn get_mut(&mut self, axis: GenAxis) -> &mut T { match axis { GenAxis::Main => &mut self.main, GenAxis::Cross => &mut self.cross, @@ -170,17 +184,19 @@ impl Spec2 { pub fn new(horizontal: T, vertical: T) -> Self { Self { horizontal, vertical } } +} - /// Return the component for the given specific axis. - pub fn get(self, axis: SpecAxis) -> T { +impl Get for Spec2 { + type Component = T; + + fn get(self, axis: SpecAxis) -> T { match axis { SpecAxis::Horizontal => self.horizontal, SpecAxis::Vertical => self.vertical, } } - /// Borrow the component for the given specific axis mutably. - pub fn get_mut(&mut self, axis: SpecAxis) -> &mut T { + fn get_mut(&mut self, axis: SpecAxis) -> &mut T { match axis { SpecAxis::Horizontal => &mut self.horizontal, SpecAxis::Vertical => &mut self.vertical, @@ -416,9 +432,12 @@ impl Sides { bottom: value, } } +} - /// Return the component for the given side. - pub fn get(self, side: Side) -> T { +impl Get for Sides { + type Component = T; + + fn get(self, side: Side) -> T { match side { Side::Left => self.left, Side::Top => self.top, @@ -427,8 +446,7 @@ impl Sides { } } - /// Borrow the component for the given side mutably. - pub fn get_mut(&mut self, side: Side) -> &mut T { + fn get_mut(&mut self, side: Side) -> &mut T { match side { Side::Left => &mut self.left, Side::Top => &mut self.top,