mirror of
https://github.com/typst/typst
synced 2025-05-20 12:05:27 +08:00
Add hash impls for all nodes
This prepares the incremental PR. Co-Authored-By: Laurenz <laurmaedje@gmail.com>
This commit is contained in:
parent
14f093bfee
commit
e27f6c1014
@ -21,6 +21,8 @@ debug = 0
|
|||||||
opt-level = 2
|
opt-level = 2
|
||||||
|
|
||||||
[dependencies]
|
[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"] }
|
image = { version = "0.23", default-features = false, features = ["jpeg", "png"] }
|
||||||
miniz_oxide = "0.3"
|
miniz_oxide = "0.3"
|
||||||
pdf-writer = { path = "../pdf-writer" }
|
pdf-writer = { path = "../pdf-writer" }
|
||||||
|
@ -6,7 +6,7 @@ use std::str::FromStr;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// A color in a dynamic format.
|
/// A color in a dynamic format.
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
||||||
pub enum Color {
|
pub enum Color {
|
||||||
/// An 8-bit RGBA color: `#423abaff`.
|
/// An 8-bit RGBA color: `#423abaff`.
|
||||||
Rgba(RgbaColor),
|
Rgba(RgbaColor),
|
||||||
@ -29,7 +29,7 @@ impl Debug for Color {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// An 8-bit RGBA color: `#423abaff`.
|
/// An 8-bit RGBA color: `#423abaff`.
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
||||||
pub struct RgbaColor {
|
pub struct RgbaColor {
|
||||||
/// Red channel.
|
/// Red channel.
|
||||||
pub r: u8,
|
pub r: u8,
|
||||||
|
@ -184,7 +184,7 @@ impl Default for FontState {
|
|||||||
size: Length::pt(11.0),
|
size: Length::pt(11.0),
|
||||||
top_edge: VerticalFontMetric::CapHeight,
|
top_edge: VerticalFontMetric::CapHeight,
|
||||||
bottom_edge: VerticalFontMetric::Baseline,
|
bottom_edge: VerticalFontMetric::Baseline,
|
||||||
scale: Linear::ONE,
|
scale: Linear::one(),
|
||||||
color: Fill::Color(Color::Rgba(RgbaColor::BLACK)),
|
color: Fill::Color(Color::Rgba(RgbaColor::BLACK)),
|
||||||
strong: false,
|
strong: false,
|
||||||
emph: false,
|
emph: false,
|
||||||
@ -193,7 +193,7 @@ impl Default for FontState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Properties used for font selection and layout.
|
/// Properties used for font selection and layout.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub struct FontProps {
|
pub struct FontProps {
|
||||||
/// The list of font families to use for shaping.
|
/// The list of font families to use for shaping.
|
||||||
pub families: Rc<FamilyList>,
|
pub families: Rc<FamilyList>,
|
||||||
@ -210,7 +210,7 @@ pub struct FontProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Font family definitions.
|
/// Font family definitions.
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
pub struct FamilyList {
|
pub struct FamilyList {
|
||||||
/// The user-defined list of font families.
|
/// The user-defined list of font families.
|
||||||
pub list: Vec<FontFamily>,
|
pub list: Vec<FontFamily>,
|
||||||
@ -255,7 +255,7 @@ impl Default for FamilyList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A generic or named font family.
|
/// A generic or named font family.
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
pub enum FontFamily {
|
pub enum FontFamily {
|
||||||
Serif,
|
Serif,
|
||||||
SansSerif,
|
SansSerif,
|
||||||
|
58
src/font.rs
58
src/font.rs
@ -92,7 +92,7 @@ impl Face {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Identifies a vertical metric of a font.
|
/// 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 {
|
pub enum VerticalFontMetric {
|
||||||
/// The distance from the baseline to the typographic ascender.
|
/// 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.
|
/// 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 {
|
pub struct FontVariant {
|
||||||
/// The style of the face (normal / italic / oblique).
|
/// The style of the face (normal / italic / oblique).
|
||||||
pub style: FontStyle,
|
pub style: FontStyle,
|
||||||
@ -187,7 +187,7 @@ impl FontVariant {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The style of a font face.
|
/// 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)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
pub enum FontStyle {
|
pub enum FontStyle {
|
||||||
@ -233,7 +233,8 @@ impl Display for FontStyle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The weight of a font face.
|
/// 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)]
|
#[serde(transparent)]
|
||||||
pub struct FontWeight(u16);
|
pub struct FontWeight(u16);
|
||||||
|
|
||||||
@ -353,42 +354,43 @@ impl Debug for FontWeight {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The width of a font face.
|
/// 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)]
|
#[serde(transparent)]
|
||||||
pub struct FontStretch(f32);
|
pub struct FontStretch(u16);
|
||||||
|
|
||||||
impl FontStretch {
|
impl FontStretch {
|
||||||
/// Ultra-condensed stretch (50%).
|
/// 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%).
|
/// Extra-condensed stretch weight (62.5%).
|
||||||
pub const EXTRA_CONDENSED: Self = Self(0.625);
|
pub const EXTRA_CONDENSED: Self = Self(625);
|
||||||
|
|
||||||
/// Condensed stretch (75%).
|
/// Condensed stretch (75%).
|
||||||
pub const CONDENSED: Self = Self(0.75);
|
pub const CONDENSED: Self = Self(750);
|
||||||
|
|
||||||
/// Semi-condensed stretch (87.5%).
|
/// Semi-condensed stretch (87.5%).
|
||||||
pub const SEMI_CONDENSED: Self = Self(0.875);
|
pub const SEMI_CONDENSED: Self = Self(875);
|
||||||
|
|
||||||
/// Normal stretch (100%).
|
/// Normal stretch (100%).
|
||||||
pub const NORMAL: Self = Self(1.0);
|
pub const NORMAL: Self = Self(1000);
|
||||||
|
|
||||||
/// Semi-expanded stretch (112.5%).
|
/// Semi-expanded stretch (112.5%).
|
||||||
pub const SEMI_EXPANDED: Self = Self(1.125);
|
pub const SEMI_EXPANDED: Self = Self(1125);
|
||||||
|
|
||||||
/// Expanded stretch (125%).
|
/// Expanded stretch (125%).
|
||||||
pub const EXPANDED: Self = Self(1.25);
|
pub const EXPANDED: Self = Self(1250);
|
||||||
|
|
||||||
/// Extra-expanded stretch (150%).
|
/// Extra-expanded stretch (150%).
|
||||||
pub const EXTRA_EXPANDED: Self = Self(1.5);
|
pub const EXTRA_EXPANDED: Self = Self(1500);
|
||||||
|
|
||||||
/// Ultra-expanded stretch (200%).
|
/// 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
|
/// Create a font stretch from a ratio between 0.5 and 2.0, clamping it if
|
||||||
/// necessary.
|
/// necessary.
|
||||||
pub fn from_ratio(ratio: f32) -> Self {
|
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,
|
/// 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.
|
/// The ratio between 0.5 and 2.0 corresponding to this stretch.
|
||||||
pub fn to_ratio(self) -> f32 {
|
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
|
/// The lowercase string representation of this stretch is one of the named
|
||||||
/// ones.
|
/// ones.
|
||||||
pub fn to_str(self) -> Option<&'static str> {
|
pub fn to_str(self) -> Option<&'static str> {
|
||||||
Some(match self {
|
Some(match self {
|
||||||
s if s == Self::ULTRA_CONDENSED => "ultra-condensed",
|
Self::ULTRA_CONDENSED => "ultra-condensed",
|
||||||
s if s == Self::EXTRA_CONDENSED => "extra-condensed",
|
Self::EXTRA_CONDENSED => "extra-condensed",
|
||||||
s if s == Self::CONDENSED => "condensed",
|
Self::CONDENSED => "condensed",
|
||||||
s if s == Self::SEMI_CONDENSED => "semi-condensed",
|
Self::SEMI_CONDENSED => "semi-condensed",
|
||||||
s if s == Self::NORMAL => "normal",
|
Self::NORMAL => "normal",
|
||||||
s if s == Self::SEMI_EXPANDED => "semi-expanded",
|
Self::SEMI_EXPANDED => "semi-expanded",
|
||||||
s if s == Self::EXPANDED => "expanded",
|
Self::EXPANDED => "expanded",
|
||||||
s if s == Self::EXTRA_EXPANDED => "extra-expanded",
|
Self::EXTRA_EXPANDED => "extra-expanded",
|
||||||
s if s == Self::ULTRA_EXPANDED => "ultra-expanded",
|
Self::ULTRA_EXPANDED => "ultra-expanded",
|
||||||
_ => return None,
|
_ => return None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The absolute ratio distance between this and another font stretch.
|
/// The absolute ratio distance between this and another font stretch.
|
||||||
pub fn distance(self, other: Self) -> f32 {
|
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 {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
match self.to_str() {
|
match self.to_str() {
|
||||||
Some(name) => f.pad(name),
|
Some(name) => f.pad(name),
|
||||||
None => write!(f, "{}", self.0),
|
None => write!(f, "{}", self.to_ratio()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// Where to align something along a directed axis.
|
/// 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 {
|
pub enum Align {
|
||||||
/// Align at the start of the axis.
|
/// Align at the start of the axis.
|
||||||
Start,
|
Start,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// The four directions into which content can be laid out.
|
/// 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 {
|
pub enum Dir {
|
||||||
/// Left to right.
|
/// Left to right.
|
||||||
LTR,
|
LTR,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// A container with a main and cross component.
|
/// 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> {
|
pub struct Gen<T> {
|
||||||
/// The cross component.
|
/// The cross component.
|
||||||
pub cross: T,
|
pub cross: T,
|
||||||
@ -26,7 +26,12 @@ impl<T> Gen<T> {
|
|||||||
|
|
||||||
impl Gen<Length> {
|
impl Gen<Length> {
|
||||||
/// The zero value.
|
/// 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> {
|
impl<T> Get<GenAxis> for Gen<T> {
|
||||||
|
@ -1,18 +1,22 @@
|
|||||||
use super::*;
|
use decorum::NotNan;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
/// An absolute length.
|
/// An absolute length.
|
||||||
#[derive(Default, Copy, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
|
#[derive(Default, Copy, Clone, PartialEq, PartialOrd, Hash)]
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct Length {
|
pub struct Length {
|
||||||
/// The length in raw units.
|
/// The length in raw units.
|
||||||
raw: f64,
|
raw: NotNan<f64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Length {
|
impl Length {
|
||||||
/// The zero 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.
|
/// Create a length from a number of points.
|
||||||
pub fn pt(pt: f64) -> Self {
|
pub fn pt(pt: f64) -> Self {
|
||||||
@ -35,8 +39,8 @@ impl Length {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a length from a number of raw units.
|
/// Create a length from a number of raw units.
|
||||||
pub const fn raw(raw: f64) -> Self {
|
pub fn raw(raw: f64) -> Self {
|
||||||
Self { raw }
|
Self { raw: raw.into() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert this to a number of points.
|
/// Convert this to a number of points.
|
||||||
@ -60,18 +64,18 @@ impl Length {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get the value of this length in raw units.
|
/// Get the value of this length in raw units.
|
||||||
pub const fn to_raw(self) -> f64 {
|
pub fn to_raw(self) -> f64 {
|
||||||
self.raw
|
self.raw.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a length from a value in a unit.
|
/// Create a length from a value in a unit.
|
||||||
pub fn with_unit(val: f64, unit: LengthUnit) -> Self {
|
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.
|
/// Get the value of this length in unit.
|
||||||
pub fn to_unit(self, unit: LengthUnit) -> f64 {
|
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.
|
/// The minimum of this and another length.
|
||||||
@ -106,17 +110,12 @@ impl Length {
|
|||||||
|
|
||||||
/// Whether the length is finite.
|
/// Whether the length is finite.
|
||||||
pub fn is_finite(self) -> bool {
|
pub fn is_finite(self) -> bool {
|
||||||
self.raw.is_finite()
|
self.raw.into_inner().is_finite()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether the length is infinite.
|
/// Whether the length is infinite.
|
||||||
pub fn is_infinite(self) -> bool {
|
pub fn is_infinite(self) -> bool {
|
||||||
self.raw.is_infinite()
|
self.raw.into_inner().is_infinite()
|
||||||
}
|
|
||||||
|
|
||||||
/// Whether the length is `NaN`.
|
|
||||||
pub fn is_nan(self) -> bool {
|
|
||||||
self.raw.is_nan()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,7 +188,7 @@ impl Div for Length {
|
|||||||
type Output = f64;
|
type Output = f64;
|
||||||
|
|
||||||
fn div(self, other: Self) -> 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 {
|
impl Sum for Length {
|
||||||
fn sum<I: Iterator<Item = Length>>(iter: I) -> Self {
|
fn sum<I: Iterator<Item = Length>>(iter: I) -> Self {
|
||||||
iter.fold(Length::ZERO, Add::add)
|
iter.fold(Length::zero(), Add::add)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// A combined relative and absolute length.
|
/// A combined relative and absolute length.
|
||||||
#[derive(Default, Copy, Clone, PartialEq)]
|
#[derive(Default, Copy, Clone, PartialEq, Hash)]
|
||||||
pub struct Linear {
|
pub struct Linear {
|
||||||
/// The relative part.
|
/// The relative part.
|
||||||
pub rel: Relative,
|
pub rel: Relative,
|
||||||
@ -11,10 +11,20 @@ pub struct Linear {
|
|||||||
|
|
||||||
impl Linear {
|
impl Linear {
|
||||||
/// The zero 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.
|
/// 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.
|
/// Create a new linear.
|
||||||
pub fn new(rel: Relative, abs: Length) -> Self {
|
pub fn new(rel: Relative, abs: Length) -> Self {
|
||||||
@ -46,13 +56,13 @@ impl Debug for Linear {
|
|||||||
|
|
||||||
impl From<Length> for Linear {
|
impl From<Length> for Linear {
|
||||||
fn from(abs: Length) -> Self {
|
fn from(abs: Length) -> Self {
|
||||||
Self { rel: Relative::ZERO, abs }
|
Self { rel: Relative::zero(), abs }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Relative> for Linear {
|
impl From<Relative> for Linear {
|
||||||
fn from(rel: Relative) -> Self {
|
fn from(rel: Relative) -> Self {
|
||||||
Self { rel, abs: Length::ZERO }
|
Self { rel, abs: Length::zero() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ impl Path {
|
|||||||
let m = 0.551784;
|
let m = 0.551784;
|
||||||
let mx = m * rx;
|
let mx = m * rx;
|
||||||
let my = m * ry;
|
let my = m * ry;
|
||||||
let z = Length::ZERO;
|
let z = Length::zero();
|
||||||
let point = Point::new;
|
let point = Point::new;
|
||||||
let mut path = Self::new();
|
let mut path = Self::new();
|
||||||
path.move_to(point(-rx, z));
|
path.move_to(point(-rx, z));
|
||||||
|
@ -13,7 +13,9 @@ pub struct Point {
|
|||||||
|
|
||||||
impl Point {
|
impl Point {
|
||||||
/// The origin 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.
|
/// Create a new point from x and y coordinate.
|
||||||
pub fn new(x: Length, y: Length) -> Self {
|
pub fn new(x: Length, y: Length) -> Self {
|
||||||
|
@ -1,34 +1,40 @@
|
|||||||
|
use decorum::NotNan;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// A relative length.
|
/// A relative length.
|
||||||
///
|
///
|
||||||
/// _Note_: `50%` is represented as `0.5` here, but stored as `50.0` in the
|
/// _Note_: `50%` is represented as `0.5` here, but stored as `50.0` in the
|
||||||
/// corresponding [literal](crate::syntax::Expr::Percent).
|
/// corresponding [literal](crate::syntax::Expr::Percent).
|
||||||
#[derive(Default, Copy, Clone, PartialEq, PartialOrd)]
|
#[derive(Default, Copy, Clone, PartialEq, PartialOrd, Hash)]
|
||||||
pub struct Relative(f64);
|
pub struct Relative(NotNan<f64>);
|
||||||
|
|
||||||
impl Relative {
|
impl Relative {
|
||||||
/// A ratio of `0%` represented as `0.0`.
|
/// 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`.
|
/// 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.
|
/// Create a new relative value.
|
||||||
pub fn new(ratio: f64) -> Self {
|
pub fn new(ratio: f64) -> Self {
|
||||||
Self(ratio)
|
Self(ratio.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the underlying ratio.
|
/// Get the underlying ratio.
|
||||||
pub fn get(self) -> f64 {
|
pub fn get(self) -> f64 {
|
||||||
self.0
|
self.0.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolve this relative to the given `length`.
|
/// Resolve this relative to the given `length`.
|
||||||
pub fn resolve(self, length: Length) -> Length {
|
pub fn resolve(self, length: Length) -> Length {
|
||||||
// We don't want NaNs.
|
// We don't want NaNs.
|
||||||
if length.is_infinite() {
|
if length.is_infinite() {
|
||||||
Length::ZERO
|
Length::zero()
|
||||||
} else {
|
} else {
|
||||||
self.get() * length
|
self.get() * length
|
||||||
}
|
}
|
||||||
@ -42,7 +48,7 @@ impl Relative {
|
|||||||
|
|
||||||
impl Display for Relative {
|
impl Display for Relative {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
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;
|
type Output = f64;
|
||||||
|
|
||||||
fn div(self, other: Self) -> f64 {
|
fn div(self, other: Self) -> f64 {
|
||||||
self.0 / other.0
|
self.get() / other.get()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// A container with left, top, right and bottom components.
|
/// 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> {
|
pub struct Sides<T> {
|
||||||
/// The value for the left side.
|
/// The value for the left side.
|
||||||
pub left: T,
|
pub left: T,
|
||||||
|
@ -13,10 +13,12 @@ pub struct Size {
|
|||||||
|
|
||||||
impl Size {
|
impl Size {
|
||||||
/// The zero size.
|
/// The zero size.
|
||||||
pub const ZERO: Self = Self {
|
pub fn zero() -> Self {
|
||||||
width: Length::ZERO,
|
Self {
|
||||||
height: Length::ZERO,
|
width: Length::zero(),
|
||||||
};
|
height: Length::zero(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a new size from width and height.
|
/// Create a new size from width and height.
|
||||||
pub fn new(width: Length, height: Length) -> Self {
|
pub fn new(width: Length, height: Length) -> Self {
|
||||||
@ -43,11 +45,6 @@ impl Size {
|
|||||||
self.width.is_infinite() || self.height.is_infinite()
|
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.
|
/// Convert to a point.
|
||||||
pub fn to_point(self) -> Point {
|
pub fn to_point(self) -> Point {
|
||||||
Point::new(self.width, self.height)
|
Point::new(self.width, self.height)
|
||||||
|
@ -29,10 +29,12 @@ impl<T> Spec<T> {
|
|||||||
|
|
||||||
impl Spec<Length> {
|
impl Spec<Length> {
|
||||||
/// The zero value.
|
/// The zero value.
|
||||||
pub const ZERO: Self = Self {
|
pub fn zero() -> Self {
|
||||||
horizontal: Length::ZERO,
|
Self {
|
||||||
vertical: Length::ZERO,
|
horizontal: Length::zero(),
|
||||||
};
|
vertical: Length::zero(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Convert to a point.
|
/// Convert to a point.
|
||||||
pub fn to_point(self) -> Point {
|
pub fn to_point(self) -> Point {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// A node that places a rectangular filled background behind its child.
|
/// A node that places a rectangular filled background behind its child.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub struct BackgroundNode {
|
pub struct BackgroundNode {
|
||||||
/// The kind of shape to use as a background.
|
/// The kind of shape to use as a background.
|
||||||
pub shape: BackgroundShape,
|
pub shape: BackgroundShape,
|
||||||
@ -12,7 +12,7 @@ pub struct BackgroundNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The kind of shape to use as a background.
|
/// 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 {
|
pub enum BackgroundShape {
|
||||||
Rect,
|
Rect,
|
||||||
Ellipse,
|
Ellipse,
|
||||||
@ -24,7 +24,7 @@ impl Layout for BackgroundNode {
|
|||||||
|
|
||||||
for frame in &mut frames {
|
for frame in &mut frames {
|
||||||
let (point, shape) = match self.shape {
|
let (point, shape) = match self.shape {
|
||||||
BackgroundShape::Rect => (Point::ZERO, Shape::Rect(frame.size)),
|
BackgroundShape::Rect => (Point::zero(), Shape::Rect(frame.size)),
|
||||||
BackgroundShape::Ellipse => {
|
BackgroundShape::Ellipse => {
|
||||||
(frame.size.to_point() / 2.0, Shape::Ellipse(frame.size))
|
(frame.size.to_point() / 2.0, Shape::Ellipse(frame.size))
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// A node that can fix its child's width and height.
|
/// A node that can fix its child's width and height.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub struct FixedNode {
|
pub struct FixedNode {
|
||||||
/// The fixed width, if any.
|
/// The fixed width, if any.
|
||||||
pub width: Option<Linear>,
|
pub width: Option<Linear>,
|
||||||
|
@ -96,7 +96,7 @@ pub enum Shape {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// How text and shapes are filled.
|
/// How text and shapes are filled.
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Copy, Clone, PartialEq, Hash, Serialize, Deserialize)]
|
||||||
pub enum Fill {
|
pub enum Fill {
|
||||||
/// A solid color.
|
/// A solid color.
|
||||||
Color(Color),
|
Color(Color),
|
||||||
|
@ -18,6 +18,10 @@ pub use stack::*;
|
|||||||
|
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::{self, Debug, Formatter};
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
|
|
||||||
|
use decorum::NotNan;
|
||||||
|
use fxhash::FxHasher64;
|
||||||
|
|
||||||
use crate::env::Env;
|
use crate::env::Env;
|
||||||
use crate::geom::*;
|
use crate::geom::*;
|
||||||
@ -64,39 +68,62 @@ impl PageRun {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A wrapper around a dynamic layouting node.
|
/// A wrapper around a dynamic layouting node.
|
||||||
pub struct AnyNode(Box<dyn Bounds>);
|
pub struct AnyNode {
|
||||||
|
node: Box<dyn Bounds>,
|
||||||
|
hash: u64,
|
||||||
|
}
|
||||||
|
|
||||||
impl AnyNode {
|
impl AnyNode {
|
||||||
/// Create a new instance from any node that satisifies the required bounds.
|
/// 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
|
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 {
|
impl Layout for AnyNode {
|
||||||
fn layout(&self, ctx: &mut LayoutContext, regions: &Regions) -> Vec<Frame> {
|
fn layout(&self, ctx: &mut LayoutContext, regions: &Regions) -> Vec<Frame> {
|
||||||
self.0.layout(ctx, regions)
|
self.node.layout(ctx, regions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for AnyNode {
|
impl Clone for AnyNode {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self(self.0.dyn_clone())
|
Self {
|
||||||
|
node: self.node.dyn_clone(),
|
||||||
|
hash: self.hash,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for AnyNode {
|
impl PartialEq for AnyNode {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
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 {
|
impl Debug for AnyNode {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
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.
|
/// If this is true, calling `next()` will have no effect.
|
||||||
pub fn in_full_last(&self) -> bool {
|
pub fn in_full_last(&self) -> bool {
|
||||||
self.backlog.is_empty()
|
self.backlog.is_empty() && self.last.map_or(true, |size| self.current == size)
|
||||||
&& self.last.map_or(true, |size| {
|
|
||||||
self.current.is_nan() || size.is_nan() || self.current == size
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Advance to the next region if there is any.
|
/// 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.
|
/// Shrink `current` to ensure that the aspect ratio can be satisfied.
|
||||||
pub fn apply_aspect_ratio(&mut self, aspect: f64) {
|
pub fn apply_aspect_ratio(&mut self, aspect: NotNan<f64>) {
|
||||||
let width = self.current.width.min(aspect * self.current.height);
|
let width = self.current.width.min(aspect.into_inner() * self.current.height);
|
||||||
let height = width / aspect;
|
let height = width / aspect.into_inner();
|
||||||
self.current = Size::new(width, height);
|
self.current = Size::new(width, height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// A node that adds padding to its child.
|
/// A node that adds padding to its child.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub struct PadNode {
|
pub struct PadNode {
|
||||||
/// The amount of padding.
|
/// The amount of padding.
|
||||||
pub padding: Sides<Linear>,
|
pub padding: Sides<Linear>,
|
||||||
|
@ -10,7 +10,7 @@ use crate::util::{RangeExt, SliceExt};
|
|||||||
type Range = std::ops::Range<usize>;
|
type Range = std::ops::Range<usize>;
|
||||||
|
|
||||||
/// A node that arranges its children into a paragraph.
|
/// A node that arranges its children into a paragraph.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub struct ParNode {
|
pub struct ParNode {
|
||||||
/// The inline direction of this paragraph.
|
/// The inline direction of this paragraph.
|
||||||
pub dir: Dir,
|
pub dir: Dir,
|
||||||
@ -21,7 +21,7 @@ pub struct ParNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A child of a paragraph node.
|
/// A child of a paragraph node.
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq, Hash)]
|
||||||
pub enum ParChild {
|
pub enum ParChild {
|
||||||
/// Spacing between other nodes.
|
/// Spacing between other nodes.
|
||||||
Spacing(Length),
|
Spacing(Length),
|
||||||
@ -255,7 +255,7 @@ impl ParItem<'_> {
|
|||||||
/// The size of the item.
|
/// The size of the item.
|
||||||
pub fn size(&self) -> Size {
|
pub fn size(&self) -> Size {
|
||||||
match self {
|
match self {
|
||||||
Self::Spacing(amount) => Size::new(*amount, Length::ZERO),
|
Self::Spacing(amount) => Size::new(*amount, Length::zero()),
|
||||||
Self::Text(shaped, _) => shaped.size,
|
Self::Text(shaped, _) => shaped.size,
|
||||||
Self::Frame(frame, _) => frame.size,
|
Self::Frame(frame, _) => frame.size,
|
||||||
}
|
}
|
||||||
@ -264,7 +264,7 @@ impl ParItem<'_> {
|
|||||||
/// The baseline of the item.
|
/// The baseline of the item.
|
||||||
pub fn baseline(&self) -> Length {
|
pub fn baseline(&self) -> Length {
|
||||||
match self {
|
match self {
|
||||||
Self::Spacing(_) => Length::ZERO,
|
Self::Spacing(_) => Length::zero(),
|
||||||
Self::Text(shaped, _) => shaped.baseline,
|
Self::Text(shaped, _) => shaped.baseline,
|
||||||
Self::Frame(frame, _) => frame.baseline,
|
Self::Frame(frame, _) => frame.baseline,
|
||||||
}
|
}
|
||||||
@ -287,7 +287,7 @@ impl<'a> LineStack<'a> {
|
|||||||
regions,
|
regions,
|
||||||
finished: vec![],
|
finished: vec![],
|
||||||
lines: 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 output = Frame::new(self.size, self.size.height);
|
||||||
let mut offset = Length::ZERO;
|
let mut offset = Length::zero();
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
|
|
||||||
for line in std::mem::take(&mut self.lines) {
|
for line in std::mem::take(&mut self.lines) {
|
||||||
let frame = line.build(self.size.width);
|
let frame = line.build(self.size.width);
|
||||||
|
|
||||||
let pos = Point::new(Length::ZERO, offset);
|
let pos = Point::new(Length::zero(), offset);
|
||||||
if first {
|
if first {
|
||||||
output.baseline = pos.y + frame.baseline;
|
output.baseline = pos.y + frame.baseline;
|
||||||
first = false;
|
first = false;
|
||||||
@ -326,7 +326,7 @@ impl<'a> LineStack<'a> {
|
|||||||
|
|
||||||
self.finished.push(output);
|
self.finished.push(output);
|
||||||
self.regions.next();
|
self.regions.next();
|
||||||
self.size = Size::ZERO;
|
self.size = Size::zero();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish(mut self) -> Vec<Frame> {
|
fn finish(mut self) -> Vec<Frame> {
|
||||||
@ -421,9 +421,9 @@ impl<'a> LineLayout<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut width = Length::ZERO;
|
let mut width = Length::zero();
|
||||||
let mut top = Length::ZERO;
|
let mut top = Length::zero();
|
||||||
let mut bottom = Length::ZERO;
|
let mut bottom = Length::zero();
|
||||||
|
|
||||||
// Measure the size of the line.
|
// Measure the size of the line.
|
||||||
for item in first.iter().chain(items).chain(&last) {
|
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 free = size.width - self.size.width;
|
||||||
|
|
||||||
let mut output = Frame::new(size, self.baseline);
|
let mut output = Frame::new(size, self.baseline);
|
||||||
let mut offset = Length::ZERO;
|
let mut offset = Length::zero();
|
||||||
let mut ruler = Align::Start;
|
let mut ruler = Align::Start;
|
||||||
|
|
||||||
self.reordered(|item| {
|
self.reordered(|item| {
|
||||||
|
@ -62,7 +62,7 @@ impl<'a> ShapedText<'a> {
|
|||||||
/// Build the shaped text's frame.
|
/// Build the shaped text's frame.
|
||||||
pub fn build(&self) -> Frame {
|
pub fn build(&self) -> Frame {
|
||||||
let mut frame = Frame::new(self.size, self.baseline);
|
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) {
|
for (face_id, group) in self.glyphs.as_ref().group_by_key(|g| g.face_id) {
|
||||||
let pos = Point::new(offset, self.baseline);
|
let pos = Point::new(offset, self.baseline);
|
||||||
@ -331,9 +331,9 @@ fn measure(
|
|||||||
glyphs: &[ShapedGlyph],
|
glyphs: &[ShapedGlyph],
|
||||||
props: &FontProps,
|
props: &FontProps,
|
||||||
) -> (Size, Length) {
|
) -> (Size, Length) {
|
||||||
let mut width = Length::ZERO;
|
let mut width = Length::zero();
|
||||||
let mut top = Length::ZERO;
|
let mut top = Length::zero();
|
||||||
let mut bottom = Length::ZERO;
|
let mut bottom = Length::zero();
|
||||||
let mut expand_vertical = |face: &Face| {
|
let mut expand_vertical = |face: &Face| {
|
||||||
top.set_max(face.vertical_metric(props.top_edge).to_length(props.size));
|
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));
|
bottom.set_max(-face.vertical_metric(props.bottom_edge).to_length(props.size));
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
|
use decorum::NotNan;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// A node that stacks its children.
|
/// A node that stacks its children.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub struct StackNode {
|
pub struct StackNode {
|
||||||
/// The `main` and `cross` directions of this stack.
|
/// 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 fixed aspect ratio between width and height, if any.
|
||||||
///
|
///
|
||||||
/// The resulting frames will satisfy `width = aspect * height`.
|
/// The resulting frames will satisfy `width = aspect * height`.
|
||||||
pub aspect: Option<f64>,
|
pub aspect: Option<NotNan<f64>>,
|
||||||
/// The nodes to be stacked.
|
/// The nodes to be stacked.
|
||||||
pub children: Vec<StackChild>,
|
pub children: Vec<StackChild>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A child of a stack node.
|
/// A child of a stack node.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub enum StackChild {
|
pub enum StackChild {
|
||||||
/// Spacing between other nodes.
|
/// Spacing between other nodes.
|
||||||
Spacing(Length),
|
Spacing(Length),
|
||||||
@ -56,7 +58,7 @@ impl From<StackNode> for AnyNode {
|
|||||||
|
|
||||||
struct StackLayouter {
|
struct StackLayouter {
|
||||||
dirs: Gen<Dir>,
|
dirs: Gen<Dir>,
|
||||||
aspect: Option<f64>,
|
aspect: Option<NotNan<f64>>,
|
||||||
main: SpecAxis,
|
main: SpecAxis,
|
||||||
regions: Regions,
|
regions: Regions,
|
||||||
finished: Vec<Frame>,
|
finished: Vec<Frame>,
|
||||||
@ -67,7 +69,7 @@ struct StackLayouter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl 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 {
|
if let Some(aspect) = aspect {
|
||||||
regions.apply_aspect_ratio(aspect);
|
regions.apply_aspect_ratio(aspect);
|
||||||
}
|
}
|
||||||
@ -79,7 +81,7 @@ impl StackLayouter {
|
|||||||
finished: vec![],
|
finished: vec![],
|
||||||
frames: vec![],
|
frames: vec![],
|
||||||
full: regions.current,
|
full: regions.current,
|
||||||
size: Gen::ZERO,
|
size: Gen::zero(),
|
||||||
ruler: Align::Start,
|
ruler: Align::Start,
|
||||||
regions,
|
regions,
|
||||||
}
|
}
|
||||||
@ -122,11 +124,11 @@ impl StackLayouter {
|
|||||||
if let Some(aspect) = self.aspect {
|
if let Some(aspect) = self.aspect {
|
||||||
let width = size
|
let width = size
|
||||||
.width
|
.width
|
||||||
.max(aspect * size.height)
|
.max(aspect.into_inner() * size.height)
|
||||||
.min(self.full.width)
|
.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);
|
let mut output = Frame::new(size, size.height);
|
||||||
@ -141,7 +143,7 @@ impl StackLayouter {
|
|||||||
// Align along the cross axis.
|
// Align along the cross axis.
|
||||||
let cross = aligns
|
let cross = aligns
|
||||||
.cross
|
.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.
|
// Align along the main axis.
|
||||||
let main = aligns.main.resolve(
|
let main = aligns.main.resolve(
|
||||||
@ -163,7 +165,7 @@ impl StackLayouter {
|
|||||||
output.push_frame(pos, frame);
|
output.push_frame(pos, frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.size = Gen::ZERO;
|
self.size = Gen::zero();
|
||||||
self.ruler = Align::Start;
|
self.ruler = Align::Start;
|
||||||
self.regions.next();
|
self.regions.next();
|
||||||
if let Some(aspect) = self.aspect {
|
if let Some(aspect) = self.aspect {
|
||||||
|
@ -68,7 +68,7 @@ pub fn font(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
|||||||
if let Some(linear) = size {
|
if let Some(linear) = size {
|
||||||
if linear.rel.is_zero() {
|
if linear.rel.is_zero() {
|
||||||
ctx.state.font.size = linear.abs;
|
ctx.state.font.size = linear.abs;
|
||||||
ctx.state.font.scale = Relative::ONE.into();
|
ctx.state.font.scale = Linear::one();
|
||||||
} else {
|
} else {
|
||||||
ctx.state.font.scale = linear;
|
ctx.state.font.scale = linear;
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ pub fn image(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// An image node.
|
/// An image node.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
struct ImageNode {
|
struct ImageNode {
|
||||||
/// The id of the image file.
|
/// The id of the image file.
|
||||||
id: ImageId,
|
id: ImageId,
|
||||||
@ -73,7 +73,7 @@ impl Layout for ImageNode {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut frame = Frame::new(size, size.height);
|
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]
|
vec![frame]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
use std::f64::consts::SQRT_2;
|
use std::f64::consts::SQRT_2;
|
||||||
|
|
||||||
|
use decorum::NotNan;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::color::Color;
|
use crate::color::Color;
|
||||||
use crate::layout::{BackgroundNode, BackgroundShape, Fill, FixedNode, PadNode};
|
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 height = width.is_none().then(|| args.eat_named(ctx, "height")).flatten();
|
||||||
let fill = args.eat_named(ctx, "fill");
|
let fill = args.eat_named(ctx, "fill");
|
||||||
let body = args.eat::<TemplateValue>(ctx).unwrap_or_default();
|
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(
|
fn rect_impl(
|
||||||
name: &str,
|
name: &str,
|
||||||
width: Option<Linear>,
|
width: Option<Linear>,
|
||||||
height: Option<Linear>,
|
height: Option<Linear>,
|
||||||
aspect: Option<f64>,
|
aspect: Option<NotNan<f64>>,
|
||||||
fill: Option<Color>,
|
fill: Option<Color>,
|
||||||
body: TemplateValue,
|
body: TemplateValue,
|
||||||
) -> Value {
|
) -> 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 height = width.is_none().then(|| args.eat_named(ctx, "height")).flatten();
|
||||||
let fill = args.eat_named(ctx, "fill");
|
let fill = args.eat_named(ctx, "fill");
|
||||||
let body = args.eat::<TemplateValue>(ctx).unwrap_or_default();
|
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(
|
fn ellipse_impl(
|
||||||
name: &str,
|
name: &str,
|
||||||
width: Option<Linear>,
|
width: Option<Linear>,
|
||||||
height: Option<Linear>,
|
height: Option<Linear>,
|
||||||
aspect: Option<f64>,
|
aspect: Option<NotNan<f64>>,
|
||||||
fill: Option<Color>,
|
fill: Option<Color>,
|
||||||
body: TemplateValue,
|
body: TemplateValue,
|
||||||
) -> Value {
|
) -> Value {
|
||||||
|
@ -132,7 +132,7 @@ impl<'a> PdfExporter<'a> {
|
|||||||
// We only write font switching actions when the used face changes. To
|
// We only write font switching actions when the used face changes. To
|
||||||
// do that, we need to remember the active face.
|
// do that, we need to remember the active face.
|
||||||
let mut face = FaceId::MAX;
|
let mut face = FaceId::MAX;
|
||||||
let mut size = Length::ZERO;
|
let mut size = Length::zero();
|
||||||
let mut fill: Option<Fill> = None;
|
let mut fill: Option<Fill> = None;
|
||||||
|
|
||||||
for (pos, element) in &page.elements {
|
for (pos, element) in &page.elements {
|
||||||
|
@ -742,7 +742,7 @@ mod tests {
|
|||||||
test_value(3.14, "3.14");
|
test_value(3.14, "3.14");
|
||||||
test_value(Length::pt(5.5), "5.5pt");
|
test_value(Length::pt(5.5), "5.5pt");
|
||||||
test_value(Angle::deg(90.0), "90deg");
|
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(Relative::new(0.3) + Length::cm(2.0), "30% + 2cm");
|
||||||
test_value(Color::Rgba(RgbaColor::new(1, 1, 1, 0xff)), "#010101");
|
test_value(Color::Rgba(RgbaColor::new(1, 1, 1, 0xff)), "#010101");
|
||||||
test_value("hello", r#""hello""#);
|
test_value("hello", r#""hello""#);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user