diff options
Diffstat (limited to 'src/layout')
| -rw-r--r-- | src/layout/background.rs | 6 | ||||
| -rw-r--r-- | src/layout/fixed.rs | 2 | ||||
| -rw-r--r-- | src/layout/frame.rs | 2 | ||||
| -rw-r--r-- | src/layout/mod.rs | 54 | ||||
| -rw-r--r-- | src/layout/pad.rs | 2 | ||||
| -rw-r--r-- | src/layout/par.rs | 24 | ||||
| -rw-r--r-- | src/layout/shaping.rs | 8 | ||||
| -rw-r--r-- | src/layout/stack.rs | 24 |
8 files changed, 74 insertions, 48 deletions
diff --git a/src/layout/background.rs b/src/layout/background.rs index a5afbc4a..3a76a264 100644 --- a/src/layout/background.rs +++ b/src/layout/background.rs @@ -1,7 +1,7 @@ use super::*; /// A node that places a rectangular filled background behind its child. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Hash)] pub struct BackgroundNode { /// The kind of shape to use as a background. pub shape: BackgroundShape, @@ -12,7 +12,7 @@ pub struct BackgroundNode { } /// The kind of shape to use as a background. -#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum BackgroundShape { Rect, Ellipse, @@ -24,7 +24,7 @@ impl Layout for BackgroundNode { for frame in &mut frames { let (point, shape) = match self.shape { - BackgroundShape::Rect => (Point::ZERO, Shape::Rect(frame.size)), + BackgroundShape::Rect => (Point::zero(), Shape::Rect(frame.size)), BackgroundShape::Ellipse => { (frame.size.to_point() / 2.0, Shape::Ellipse(frame.size)) } diff --git a/src/layout/fixed.rs b/src/layout/fixed.rs index a0e5e973..7c28e8e5 100644 --- a/src/layout/fixed.rs +++ b/src/layout/fixed.rs @@ -1,7 +1,7 @@ use super::*; /// A node that can fix its child's width and height. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Hash)] pub struct FixedNode { /// The fixed width, if any. pub width: Option<Linear>, diff --git a/src/layout/frame.rs b/src/layout/frame.rs index cf8ddb09..61a84d6d 100644 --- a/src/layout/frame.rs +++ b/src/layout/frame.rs @@ -96,7 +96,7 @@ pub enum Shape { } /// How text and shapes are filled. -#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Copy, Clone, PartialEq, Hash, Serialize, Deserialize)] pub enum Fill { /// A solid color. Color(Color), diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 7997f584..207d5bed 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -18,6 +18,10 @@ pub use stack::*; use std::any::Any; use std::fmt::{self, Debug, Formatter}; +use std::hash::{Hash, Hasher}; + +use decorum::NotNan; +use fxhash::FxHasher64; use crate::env::Env; use crate::geom::*; @@ -64,39 +68,62 @@ impl PageRun { } /// A wrapper around a dynamic layouting node. -pub struct AnyNode(Box<dyn Bounds>); +pub struct AnyNode { + node: Box<dyn Bounds>, + hash: u64, +} impl AnyNode { /// Create a new instance from any node that satisifies the required bounds. - pub fn new<T>(any: T) -> Self + pub fn new<T>(node: T) -> Self where - T: Layout + Debug + Clone + PartialEq + 'static, + T: Layout + Debug + Clone + PartialEq + Hash + 'static, { - Self(Box::new(any)) + let hash = { + let mut state = FxHasher64::default(); + node.hash(&mut state); + state.finish() + }; + + Self { node: Box::new(node), hash } + } + + /// The cached hash for the boxed node. + pub fn hash(&self) -> u64 { + self.hash } } impl Layout for AnyNode { fn layout(&self, ctx: &mut LayoutContext, regions: &Regions) -> Vec<Frame> { - self.0.layout(ctx, regions) + self.node.layout(ctx, regions) } } impl Clone for AnyNode { fn clone(&self) -> Self { - Self(self.0.dyn_clone()) + Self { + node: self.node.dyn_clone(), + hash: self.hash, + } } } impl PartialEq for AnyNode { fn eq(&self, other: &Self) -> bool { - self.0.dyn_eq(other.0.as_ref()) + self.node.dyn_eq(other.node.as_ref()) + } +} + +impl Hash for AnyNode { + fn hash<H: Hasher>(&self, state: &mut H) { + state.write_u64(self.hash); } } impl Debug for AnyNode { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - self.0.fmt(f) + self.node.fmt(f) } } @@ -202,10 +229,7 @@ impl Regions { /// /// If this is true, calling `next()` will have no effect. pub fn in_full_last(&self) -> bool { - self.backlog.is_empty() - && self.last.map_or(true, |size| { - self.current.is_nan() || size.is_nan() || self.current == size - }) + self.backlog.is_empty() && self.last.map_or(true, |size| self.current == size) } /// Advance to the next region if there is any. @@ -217,9 +241,9 @@ impl Regions { } /// Shrink `current` to ensure that the aspect ratio can be satisfied. - pub fn apply_aspect_ratio(&mut self, aspect: f64) { - let width = self.current.width.min(aspect * self.current.height); - let height = width / aspect; + pub fn apply_aspect_ratio(&mut self, aspect: NotNan<f64>) { + let width = self.current.width.min(aspect.into_inner() * self.current.height); + let height = width / aspect.into_inner(); self.current = Size::new(width, height); } } diff --git a/src/layout/pad.rs b/src/layout/pad.rs index ad24d62c..ccf0d5e1 100644 --- a/src/layout/pad.rs +++ b/src/layout/pad.rs @@ -1,7 +1,7 @@ use super::*; /// A node that adds padding to its child. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Hash)] pub struct PadNode { /// The amount of padding. pub padding: Sides<Linear>, diff --git a/src/layout/par.rs b/src/layout/par.rs index 22400dd3..f21778de 100644 --- a/src/layout/par.rs +++ b/src/layout/par.rs @@ -10,7 +10,7 @@ use crate::util::{RangeExt, SliceExt}; type Range = std::ops::Range<usize>; /// A node that arranges its children into a paragraph. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Hash)] pub struct ParNode { /// The inline direction of this paragraph. pub dir: Dir, @@ -21,7 +21,7 @@ pub struct ParNode { } /// A child of a paragraph node. -#[derive(Clone, PartialEq)] +#[derive(Clone, PartialEq, Hash)] pub enum ParChild { /// Spacing between other nodes. Spacing(Length), @@ -255,7 +255,7 @@ impl ParItem<'_> { /// The size of the item. pub fn size(&self) -> Size { match self { - Self::Spacing(amount) => Size::new(*amount, Length::ZERO), + Self::Spacing(amount) => Size::new(*amount, Length::zero()), Self::Text(shaped, _) => shaped.size, Self::Frame(frame, _) => frame.size, } @@ -264,7 +264,7 @@ impl ParItem<'_> { /// The baseline of the item. pub fn baseline(&self) -> Length { match self { - Self::Spacing(_) => Length::ZERO, + Self::Spacing(_) => Length::zero(), Self::Text(shaped, _) => shaped.baseline, Self::Frame(frame, _) => frame.baseline, } @@ -287,7 +287,7 @@ impl<'a> LineStack<'a> { regions, finished: vec![], lines: vec![], - size: Size::ZERO, + size: Size::zero(), } } @@ -308,13 +308,13 @@ impl<'a> LineStack<'a> { } let mut output = Frame::new(self.size, self.size.height); - let mut offset = Length::ZERO; + let mut offset = Length::zero(); let mut first = true; for line in std::mem::take(&mut self.lines) { let frame = line.build(self.size.width); - let pos = Point::new(Length::ZERO, offset); + let pos = Point::new(Length::zero(), offset); if first { output.baseline = pos.y + frame.baseline; first = false; @@ -326,7 +326,7 @@ impl<'a> LineStack<'a> { self.finished.push(output); self.regions.next(); - self.size = Size::ZERO; + self.size = Size::zero(); } fn finish(mut self) -> Vec<Frame> { @@ -421,9 +421,9 @@ impl<'a> LineLayout<'a> { } } - let mut width = Length::ZERO; - let mut top = Length::ZERO; - let mut bottom = Length::ZERO; + let mut width = Length::zero(); + let mut top = Length::zero(); + let mut bottom = Length::zero(); // Measure the size of the line. for item in first.iter().chain(items).chain(&last) { @@ -452,7 +452,7 @@ impl<'a> LineLayout<'a> { let free = size.width - self.size.width; let mut output = Frame::new(size, self.baseline); - let mut offset = Length::ZERO; + let mut offset = Length::zero(); let mut ruler = Align::Start; self.reordered(|item| { diff --git a/src/layout/shaping.rs b/src/layout/shaping.rs index da25b7a6..f8ab7037 100644 --- a/src/layout/shaping.rs +++ b/src/layout/shaping.rs @@ -62,7 +62,7 @@ impl<'a> ShapedText<'a> { /// Build the shaped text's frame. pub fn build(&self) -> Frame { let mut frame = Frame::new(self.size, self.baseline); - let mut offset = Length::ZERO; + let mut offset = Length::zero(); for (face_id, group) in self.glyphs.as_ref().group_by_key(|g| g.face_id) { let pos = Point::new(offset, self.baseline); @@ -331,9 +331,9 @@ fn measure( glyphs: &[ShapedGlyph], props: &FontProps, ) -> (Size, Length) { - let mut width = Length::ZERO; - let mut top = Length::ZERO; - let mut bottom = Length::ZERO; + let mut width = Length::zero(); + let mut top = Length::zero(); + let mut bottom = Length::zero(); let mut expand_vertical = |face: &Face| { top.set_max(face.vertical_metric(props.top_edge).to_length(props.size)); bottom.set_max(-face.vertical_metric(props.bottom_edge).to_length(props.size)); diff --git a/src/layout/stack.rs b/src/layout/stack.rs index 11f9c3d7..bb767378 100644 --- a/src/layout/stack.rs +++ b/src/layout/stack.rs @@ -1,7 +1,9 @@ +use decorum::NotNan; + use super::*; /// A node that stacks its children. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Hash)] pub struct StackNode { /// The `main` and `cross` directions of this stack. /// @@ -11,13 +13,13 @@ pub struct StackNode { /// The fixed aspect ratio between width and height, if any. /// /// The resulting frames will satisfy `width = aspect * height`. - pub aspect: Option<f64>, + pub aspect: Option<NotNan<f64>>, /// The nodes to be stacked. pub children: Vec<StackChild>, } /// A child of a stack node. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Hash)] pub enum StackChild { /// Spacing between other nodes. Spacing(Length), @@ -56,7 +58,7 @@ impl From<StackNode> for AnyNode { struct StackLayouter { dirs: Gen<Dir>, - aspect: Option<f64>, + aspect: Option<NotNan<f64>>, main: SpecAxis, regions: Regions, finished: Vec<Frame>, @@ -67,7 +69,7 @@ struct StackLayouter { } impl StackLayouter { - fn new(dirs: Gen<Dir>, aspect: Option<f64>, mut regions: Regions) -> Self { + fn new(dirs: Gen<Dir>, aspect: Option<NotNan<f64>>, mut regions: Regions) -> Self { if let Some(aspect) = aspect { regions.apply_aspect_ratio(aspect); } @@ -79,7 +81,7 @@ impl StackLayouter { finished: vec![], frames: vec![], full: regions.current, - size: Gen::ZERO, + size: Gen::zero(), ruler: Align::Start, regions, } @@ -122,11 +124,11 @@ impl StackLayouter { if let Some(aspect) = self.aspect { let width = size .width - .max(aspect * size.height) + .max(aspect.into_inner() * size.height) .min(self.full.width) - .min(aspect * self.full.height); + .min(aspect.into_inner() * self.full.height); - size = Size::new(width, width / aspect); + size = Size::new(width, width / aspect.into_inner()); } let mut output = Frame::new(size, size.height); @@ -141,7 +143,7 @@ impl StackLayouter { // Align along the cross axis. let cross = aligns .cross - .resolve(self.dirs.cross, Length::ZERO .. size.cross - child.cross); + .resolve(self.dirs.cross, Length::zero() .. size.cross - child.cross); // Align along the main axis. let main = aligns.main.resolve( @@ -163,7 +165,7 @@ impl StackLayouter { output.push_frame(pos, frame); } - self.size = Gen::ZERO; + self.size = Gen::zero(); self.ruler = Align::Start; self.regions.next(); if let Some(aspect) = self.aspect { |
