Add hash impls for all nodes

This prepares the incremental PR.

Co-Authored-By: Laurenz <laurmaedje@gmail.com>
This commit is contained in:
Martin Haug 2021-05-26 22:52:02 +02:00 committed by Laurenz
parent 14f093bfee
commit e27f6c1014
28 changed files with 198 additions and 145 deletions

View File

@ -21,6 +21,8 @@ debug = 0
opt-level = 2
[dependencies]
decorum = { version = "0.3.1", default-features = false, features = ["serialize-serde"] }
fxhash = "0.2.1"
image = { version = "0.23", default-features = false, features = ["jpeg", "png"] }
miniz_oxide = "0.3"
pdf-writer = { path = "../pdf-writer" }

View File

@ -6,7 +6,7 @@ use std::str::FromStr;
use serde::{Deserialize, Serialize};
/// A color in a dynamic format.
#[derive(Copy, Clone, Eq, PartialEq, Serialize, Deserialize)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub enum Color {
/// An 8-bit RGBA color: `#423abaff`.
Rgba(RgbaColor),
@ -29,7 +29,7 @@ impl Debug for Color {
}
/// An 8-bit RGBA color: `#423abaff`.
#[derive(Copy, Clone, Eq, PartialEq, Serialize, Deserialize)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct RgbaColor {
/// Red channel.
pub r: u8,

View File

@ -184,7 +184,7 @@ impl Default for FontState {
size: Length::pt(11.0),
top_edge: VerticalFontMetric::CapHeight,
bottom_edge: VerticalFontMetric::Baseline,
scale: Linear::ONE,
scale: Linear::one(),
color: Fill::Color(Color::Rgba(RgbaColor::BLACK)),
strong: false,
emph: false,
@ -193,7 +193,7 @@ impl Default for FontState {
}
/// Properties used for font selection and layout.
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq, Hash)]
pub struct FontProps {
/// The list of font families to use for shaping.
pub families: Rc<FamilyList>,
@ -210,7 +210,7 @@ pub struct FontProps {
}
/// Font family definitions.
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct FamilyList {
/// The user-defined list of font families.
pub list: Vec<FontFamily>,
@ -255,7 +255,7 @@ impl Default for FamilyList {
}
/// A generic or named font family.
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum FontFamily {
Serif,
SansSerif,

View File

@ -92,7 +92,7 @@ impl Face {
}
/// Identifies a vertical metric of a font.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum VerticalFontMetric {
/// The distance from the baseline to the typographic ascender.
///
@ -169,7 +169,7 @@ pub struct FaceInfo {
}
/// Properties that distinguish a face from other faces in the same family.
#[derive(Default, Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
#[derive(Default, Debug, Copy, Clone, PartialEq, Hash, Serialize, Deserialize)]
pub struct FontVariant {
/// The style of the face (normal / italic / oblique).
pub style: FontStyle,
@ -187,7 +187,7 @@ impl FontVariant {
}
/// The style of a font face.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum FontStyle {
@ -233,7 +233,8 @@ impl Display for FontStyle {
}
/// The weight of a font face.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[derive(Serialize, Deserialize)]
#[serde(transparent)]
pub struct FontWeight(u16);
@ -353,42 +354,43 @@ impl Debug for FontWeight {
}
/// The width of a font face.
#[derive(Copy, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[derive(Serialize, Deserialize)]
#[serde(transparent)]
pub struct FontStretch(f32);
pub struct FontStretch(u16);
impl FontStretch {
/// Ultra-condensed stretch (50%).
pub const ULTRA_CONDENSED: Self = Self(0.5);
pub const ULTRA_CONDENSED: Self = Self(500);
/// Extra-condensed stretch weight (62.5%).
pub const EXTRA_CONDENSED: Self = Self(0.625);
pub const EXTRA_CONDENSED: Self = Self(625);
/// Condensed stretch (75%).
pub const CONDENSED: Self = Self(0.75);
pub const CONDENSED: Self = Self(750);
/// Semi-condensed stretch (87.5%).
pub const SEMI_CONDENSED: Self = Self(0.875);
pub const SEMI_CONDENSED: Self = Self(875);
/// Normal stretch (100%).
pub const NORMAL: Self = Self(1.0);
pub const NORMAL: Self = Self(1000);
/// Semi-expanded stretch (112.5%).
pub const SEMI_EXPANDED: Self = Self(1.125);
pub const SEMI_EXPANDED: Self = Self(1125);
/// Expanded stretch (125%).
pub const EXPANDED: Self = Self(1.25);
pub const EXPANDED: Self = Self(1250);
/// Extra-expanded stretch (150%).
pub const EXTRA_EXPANDED: Self = Self(1.5);
pub const EXTRA_EXPANDED: Self = Self(1500);
/// Ultra-expanded stretch (200%).
pub const ULTRA_EXPANDED: Self = Self(2.0);
pub const ULTRA_EXPANDED: Self = Self(2000);
/// Create a font stretch from a ratio between 0.5 and 2.0, clamping it if
/// necessary.
pub fn from_ratio(ratio: f32) -> Self {
Self(ratio.max(0.5).min(2.0))
Self((ratio.max(0.5).min(2.0) * 1000.0) as u16)
}
/// Create a font stretch from an OpenType-style number between 1 and 9,
@ -425,29 +427,29 @@ impl FontStretch {
/// The ratio between 0.5 and 2.0 corresponding to this stretch.
pub fn to_ratio(self) -> f32 {
self.0
self.0 as f32 / 1000.0
}
/// The lowercase string representation of this stretch is one of the named
/// ones.
pub fn to_str(self) -> Option<&'static str> {
Some(match self {
s if s == Self::ULTRA_CONDENSED => "ultra-condensed",
s if s == Self::EXTRA_CONDENSED => "extra-condensed",
s if s == Self::CONDENSED => "condensed",
s if s == Self::SEMI_CONDENSED => "semi-condensed",
s if s == Self::NORMAL => "normal",
s if s == Self::SEMI_EXPANDED => "semi-expanded",
s if s == Self::EXPANDED => "expanded",
s if s == Self::EXTRA_EXPANDED => "extra-expanded",
s if s == Self::ULTRA_EXPANDED => "ultra-expanded",
Self::ULTRA_CONDENSED => "ultra-condensed",
Self::EXTRA_CONDENSED => "extra-condensed",
Self::CONDENSED => "condensed",
Self::SEMI_CONDENSED => "semi-condensed",
Self::NORMAL => "normal",
Self::SEMI_EXPANDED => "semi-expanded",
Self::EXPANDED => "expanded",
Self::EXTRA_EXPANDED => "extra-expanded",
Self::ULTRA_EXPANDED => "ultra-expanded",
_ => return None,
})
}
/// The absolute ratio distance between this and another font stretch.
pub fn distance(self, other: Self) -> f32 {
(self.0 - other.0).abs()
(self.to_ratio() - other.to_ratio()).abs()
}
}
@ -461,7 +463,7 @@ impl Display for FontStretch {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self.to_str() {
Some(name) => f.pad(name),
None => write!(f, "{}", self.0),
None => write!(f, "{}", self.to_ratio()),
}
}
}

View File

@ -1,7 +1,7 @@
use super::*;
/// Where to align something along a directed axis.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum Align {
/// Align at the start of the axis.
Start,

View File

@ -1,7 +1,7 @@
use super::*;
/// The four directions into which content can be laid out.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum Dir {
/// Left to right.
LTR,

View File

@ -1,7 +1,7 @@
use super::*;
/// A container with a main and cross component.
#[derive(Default, Copy, Clone, Eq, PartialEq)]
#[derive(Default, Copy, Clone, Eq, PartialEq, Hash)]
pub struct Gen<T> {
/// The cross component.
pub cross: T,
@ -26,7 +26,12 @@ impl<T> Gen<T> {
impl Gen<Length> {
/// The zero value.
pub const ZERO: Self = Self { main: Length::ZERO, cross: Length::ZERO };
pub fn zero() -> Self {
Self {
main: Length::zero(),
cross: Length::zero(),
}
}
}
impl<T> Get<GenAxis> for Gen<T> {

View File

@ -1,18 +1,22 @@
use super::*;
use decorum::NotNan;
use serde::{Deserialize, Serialize};
use super::*;
/// An absolute length.
#[derive(Default, Copy, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
#[derive(Default, Copy, Clone, PartialEq, PartialOrd, Hash)]
#[derive(Serialize, Deserialize)]
#[serde(transparent)]
pub struct Length {
/// The length in raw units.
raw: f64,
raw: NotNan<f64>,
}
impl Length {
/// The zero length.
pub const ZERO: Self = Self { raw: 0.0 };
pub fn zero() -> Self {
Self { raw: 0.0.into() }
}
/// Create a length from a number of points.
pub fn pt(pt: f64) -> Self {
@ -35,8 +39,8 @@ impl Length {
}
/// Create a length from a number of raw units.
pub const fn raw(raw: f64) -> Self {
Self { raw }
pub fn raw(raw: f64) -> Self {
Self { raw: raw.into() }
}
/// Convert this to a number of points.
@ -60,18 +64,18 @@ impl Length {
}
/// Get the value of this length in raw units.
pub const fn to_raw(self) -> f64 {
self.raw
pub fn to_raw(self) -> f64 {
self.raw.into()
}
/// Create a length from a value in a unit.
pub fn with_unit(val: f64, unit: LengthUnit) -> Self {
Self { raw: val * unit.raw_scale() }
Self { raw: (val * unit.raw_scale()).into() }
}
/// Get the value of this length in unit.
pub fn to_unit(self, unit: LengthUnit) -> f64 {
self.raw / unit.raw_scale()
self.to_raw() / unit.raw_scale()
}
/// The minimum of this and another length.
@ -106,17 +110,12 @@ impl Length {
/// Whether the length is finite.
pub fn is_finite(self) -> bool {
self.raw.is_finite()
self.raw.into_inner().is_finite()
}
/// Whether the length is infinite.
pub fn is_infinite(self) -> bool {
self.raw.is_infinite()
}
/// Whether the length is `NaN`.
pub fn is_nan(self) -> bool {
self.raw.is_nan()
self.raw.into_inner().is_infinite()
}
}
@ -189,7 +188,7 @@ impl Div for Length {
type Output = f64;
fn div(self, other: Self) -> f64 {
self.raw / other.raw
self.to_raw() / other.to_raw()
}
}
@ -200,7 +199,7 @@ assign_impl!(Length /= f64);
impl Sum for Length {
fn sum<I: Iterator<Item = Length>>(iter: I) -> Self {
iter.fold(Length::ZERO, Add::add)
iter.fold(Length::zero(), Add::add)
}
}

View File

@ -1,7 +1,7 @@
use super::*;
/// A combined relative and absolute length.
#[derive(Default, Copy, Clone, PartialEq)]
#[derive(Default, Copy, Clone, PartialEq, Hash)]
pub struct Linear {
/// The relative part.
pub rel: Relative,
@ -11,10 +11,20 @@ pub struct Linear {
impl Linear {
/// The zero linear.
pub const ZERO: Self = Self { rel: Relative::ZERO, abs: Length::ZERO };
pub fn zero() -> Self {
Self {
rel: Relative::zero(),
abs: Length::zero(),
}
}
/// The linear with a relative part of `100%` and no absolute part.
pub const ONE: Self = Self { rel: Relative::ONE, abs: Length::ZERO };
pub fn one() -> Self {
Self {
rel: Relative::one(),
abs: Length::zero(),
}
}
/// Create a new linear.
pub fn new(rel: Relative, abs: Length) -> Self {
@ -46,13 +56,13 @@ impl Debug for Linear {
impl From<Length> for Linear {
fn from(abs: Length) -> Self {
Self { rel: Relative::ZERO, abs }
Self { rel: Relative::zero(), abs }
}
}
impl From<Relative> for Linear {
fn from(rel: Relative) -> Self {
Self { rel, abs: Length::ZERO }
Self { rel, abs: Length::zero() }
}
}

View File

@ -30,7 +30,7 @@ impl Path {
let m = 0.551784;
let mx = m * rx;
let my = m * ry;
let z = Length::ZERO;
let z = Length::zero();
let point = Point::new;
let mut path = Self::new();
path.move_to(point(-rx, z));

View File

@ -13,7 +13,9 @@ pub struct Point {
impl Point {
/// The origin point.
pub const ZERO: Self = Self { x: Length::ZERO, y: Length::ZERO };
pub fn zero() -> Self {
Self { x: Length::zero(), y: Length::zero() }
}
/// Create a new point from x and y coordinate.
pub fn new(x: Length, y: Length) -> Self {

View File

@ -1,34 +1,40 @@
use decorum::NotNan;
use super::*;
/// A relative length.
///
/// _Note_: `50%` is represented as `0.5` here, but stored as `50.0` in the
/// corresponding [literal](crate::syntax::Expr::Percent).
#[derive(Default, Copy, Clone, PartialEq, PartialOrd)]
pub struct Relative(f64);
#[derive(Default, Copy, Clone, PartialEq, PartialOrd, Hash)]
pub struct Relative(NotNan<f64>);
impl Relative {
/// A ratio of `0%` represented as `0.0`.
pub const ZERO: Self = Self(0.0);
pub fn zero() -> Self {
Self(0.0.into())
}
/// A ratio of `100%` represented as `1.0`.
pub const ONE: Self = Self(1.0);
pub fn one() -> Self {
Self(1.0.into())
}
/// Create a new relative value.
pub fn new(ratio: f64) -> Self {
Self(ratio)
Self(ratio.into())
}
/// Get the underlying ratio.
pub fn get(self) -> f64 {
self.0
self.0.into()
}
/// Resolve this relative to the given `length`.
pub fn resolve(self, length: Length) -> Length {
// We don't want NaNs.
if length.is_infinite() {
Length::ZERO
Length::zero()
} else {
self.get() * length
}
@ -42,7 +48,7 @@ impl Relative {
impl Display for Relative {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}%", 100.0 * self.0)
write!(f, "{}%", 100.0 * self.get())
}
}
@ -98,7 +104,7 @@ impl Div for Relative {
type Output = f64;
fn div(self, other: Self) -> f64 {
self.0 / other.0
self.get() / other.get()
}
}

View File

@ -1,7 +1,7 @@
use super::*;
/// A container with left, top, right and bottom components.
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
pub struct Sides<T> {
/// The value for the left side.
pub left: T,

View File

@ -13,10 +13,12 @@ pub struct Size {
impl Size {
/// The zero size.
pub const ZERO: Self = Self {
width: Length::ZERO,
height: Length::ZERO,
};
pub fn zero() -> Self {
Self {
width: Length::zero(),
height: Length::zero(),
}
}
/// Create a new size from width and height.
pub fn new(width: Length, height: Length) -> Self {
@ -43,11 +45,6 @@ impl Size {
self.width.is_infinite() || self.height.is_infinite()
}
/// Whether any of the two components is `NaN`.
pub fn is_nan(self) -> bool {
self.width.is_nan() || self.height.is_nan()
}
/// Convert to a point.
pub fn to_point(self) -> Point {
Point::new(self.width, self.height)

View File

@ -29,10 +29,12 @@ impl<T> Spec<T> {
impl Spec<Length> {
/// The zero value.
pub const ZERO: Self = Self {
horizontal: Length::ZERO,
vertical: Length::ZERO,
};
pub fn zero() -> Self {
Self {
horizontal: Length::zero(),
vertical: Length::zero(),
}
}
/// Convert to a point.
pub fn to_point(self) -> Point {

View File

@ -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))
}

View File

@ -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>,

View File

@ -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),

View File

@ -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);
}
}

View File

@ -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>,

View File

@ -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| {

View File

@ -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));

View File

@ -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 {

View File

@ -68,7 +68,7 @@ pub fn font(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
if let Some(linear) = size {
if linear.rel.is_zero() {
ctx.state.font.size = linear.abs;
ctx.state.font.scale = Relative::ONE.into();
ctx.state.font.scale = Linear::one();
} else {
ctx.state.font.scale = linear;
}

View File

@ -32,7 +32,7 @@ pub fn image(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
}
/// An image node.
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq, Hash)]
struct ImageNode {
/// The id of the image file.
id: ImageId,
@ -73,7 +73,7 @@ impl Layout for ImageNode {
};
let mut frame = Frame::new(size, size.height);
frame.push(Point::ZERO, Element::Image(self.id, size));
frame.push(Point::zero(), Element::Image(self.id, size));
vec![frame]
}
}

View File

@ -1,5 +1,7 @@
use std::f64::consts::SQRT_2;
use decorum::NotNan;
use super::*;
use crate::color::Color;
use crate::layout::{BackgroundNode, BackgroundShape, Fill, FixedNode, PadNode};
@ -47,14 +49,14 @@ pub fn square(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
let height = width.is_none().then(|| args.eat_named(ctx, "height")).flatten();
let fill = args.eat_named(ctx, "fill");
let body = args.eat::<TemplateValue>(ctx).unwrap_or_default();
rect_impl("square", width, height, Some(1.0), fill, body)
rect_impl("square", width, height, Some(1.0.into()), fill, body)
}
fn rect_impl(
name: &str,
width: Option<Linear>,
height: Option<Linear>,
aspect: Option<f64>,
aspect: Option<NotNan<f64>>,
fill: Option<Color>,
body: TemplateValue,
) -> Value {
@ -119,14 +121,14 @@ pub fn circle(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
let height = width.is_none().then(|| args.eat_named(ctx, "height")).flatten();
let fill = args.eat_named(ctx, "fill");
let body = args.eat::<TemplateValue>(ctx).unwrap_or_default();
ellipse_impl("circle", width, height, Some(1.0), fill, body)
ellipse_impl("circle", width, height, Some(1.0.into()), fill, body)
}
fn ellipse_impl(
name: &str,
width: Option<Linear>,
height: Option<Linear>,
aspect: Option<f64>,
aspect: Option<NotNan<f64>>,
fill: Option<Color>,
body: TemplateValue,
) -> Value {

View File

@ -132,7 +132,7 @@ impl<'a> PdfExporter<'a> {
// We only write font switching actions when the used face changes. To
// do that, we need to remember the active face.
let mut face = FaceId::MAX;
let mut size = Length::ZERO;
let mut size = Length::zero();
let mut fill: Option<Fill> = None;
for (pos, element) in &page.elements {

View File

@ -742,7 +742,7 @@ mod tests {
test_value(3.14, "3.14");
test_value(Length::pt(5.5), "5.5pt");
test_value(Angle::deg(90.0), "90deg");
test_value(Relative::ONE / 2.0, "50%");
test_value(Relative::one() / 2.0, "50%");
test_value(Relative::new(0.3) + Length::cm(2.0), "30% + 2cm");
test_value(Color::Rgba(RgbaColor::new(1, 1, 1, 0xff)), "#010101");
test_value("hello", r#""hello""#);