summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorbluebear94 <uruwi@protonmail.com>2023-09-28 05:15:09 -0400
committerGitHub <noreply@github.com>2023-09-28 11:15:09 +0200
commit553da642bdf6f0d360b1d57841fd78bd0dc873b6 (patch)
tree407ecdeaf0bdaebf08567cc7996c49cde9747202 /crates
parentffcd951bc8a698af99d43f5245aea47a7c09adaf (diff)
Handle compiler panics when handling infinite lengths (#2215)
Diffstat (limited to 'crates')
-rw-r--r--crates/typst-library/src/layout/page.rs8
-rw-r--r--crates/typst/src/eval/fields.rs4
-rw-r--r--crates/typst/src/export/pdf/page.rs2
-rw-r--r--crates/typst/src/export/render.rs2
-rw-r--r--crates/typst/src/export/svg.rs3
-rw-r--r--crates/typst/src/geom/abs.rs10
-rw-r--r--crates/typst/src/geom/angle.rs8
-rw-r--r--crates/typst/src/geom/em.rs12
-rw-r--r--crates/typst/src/geom/fr.rs8
-rw-r--r--crates/typst/src/geom/ratio.rs8
-rw-r--r--crates/typst/src/geom/scalar.rs63
-rw-r--r--crates/typst/src/geom/stroke.rs4
12 files changed, 84 insertions, 48 deletions
diff --git a/crates/typst-library/src/layout/page.rs b/crates/typst-library/src/layout/page.rs
index 19184d22..9ec69f58 100644
--- a/crates/typst-library/src/layout/page.rs
+++ b/crates/typst-library/src/layout/page.rs
@@ -738,12 +738,12 @@ pub struct Paper {
impl Paper {
/// The width of the paper.
pub fn width(self) -> Abs {
- Abs::mm(self.width.0)
+ Abs::mm(self.width.get())
}
/// The height of the paper.
pub fn height(self) -> Abs {
- Abs::mm(self.height.0)
+ Abs::mm(self.height.get())
}
}
@@ -756,8 +756,8 @@ macro_rules! papers {
impl Paper {
$(pub const $var: Self = Self {
name: $name,
- width: Scalar($width),
- height: Scalar($height),
+ width: Scalar::new($width),
+ height: Scalar::new($height),
};)*
}
diff --git a/crates/typst/src/eval/fields.rs b/crates/typst/src/eval/fields.rs
index 094cfa38..7d164497 100644
--- a/crates/typst/src/eval/fields.rs
+++ b/crates/typst/src/eval/fields.rs
@@ -34,7 +34,9 @@ pub(crate) fn field(value: &Value, field: &str) -> StrResult<Value> {
"cap" => stroke.line_cap.into_value(),
"join" => stroke.line_join.into_value(),
"dash" => stroke.dash_pattern.clone().into_value(),
- "miter-limit" => stroke.miter_limit.map(|limit| limit.0).into_value(),
+ "miter-limit" => {
+ stroke.miter_limit.map(|limit| limit.get()).into_value()
+ }
_ => return missing(),
}
} else if let Some(align) = dynamic.downcast::<Align>() {
diff --git a/crates/typst/src/export/pdf/page.rs b/crates/typst/src/export/pdf/page.rs
index d9798f54..caa8e394 100644
--- a/crates/typst/src/export/pdf/page.rs
+++ b/crates/typst/src/export/pdf/page.rs
@@ -336,7 +336,7 @@ impl PageContext<'_, '_> {
}
}
if self.state.stroke.as_ref().map(|s| &s.miter_limit) != Some(miter_limit) {
- self.content.set_miter_limit(miter_limit.0 as f32);
+ self.content.set_miter_limit(miter_limit.get() as f32);
}
self.state.stroke = Some(stroke.clone());
}
diff --git a/crates/typst/src/export/render.rs b/crates/typst/src/export/render.rs
index 81442ad0..df51f0bd 100644
--- a/crates/typst/src/export/render.rs
+++ b/crates/typst/src/export/render.rs
@@ -496,7 +496,7 @@ fn render_shape(
line_cap: line_cap.into(),
line_join: line_join.into(),
dash,
- miter_limit: miter_limit.0 as f32,
+ miter_limit: miter_limit.get() as f32,
};
canvas.stroke_path(&path, &paint, &stroke, ts, mask);
}
diff --git a/crates/typst/src/export/svg.rs b/crates/typst/src/export/svg.rs
index 518c40c3..6aef30fd 100644
--- a/crates/typst/src/export/svg.rs
+++ b/crates/typst/src/export/svg.rs
@@ -323,7 +323,8 @@ impl SVGRenderer {
LineJoin::Bevel => "bevel",
},
);
- self.xml.write_attribute("stroke-miterlimit", &stroke.miter_limit.0);
+ self.xml
+ .write_attribute("stroke-miterlimit", &stroke.miter_limit.get());
if let Some(pattern) = &stroke.dash_pattern {
self.xml.write_attribute("stroke-dashoffset", &pattern.phase.to_pt());
self.xml.write_attribute(
diff --git a/crates/typst/src/geom/abs.rs b/crates/typst/src/geom/abs.rs
index 4ca3a9a1..d177a304 100644
--- a/crates/typst/src/geom/abs.rs
+++ b/crates/typst/src/geom/abs.rs
@@ -7,22 +7,22 @@ pub struct Abs(Scalar);
impl Abs {
/// The zero length.
pub const fn zero() -> Self {
- Self(Scalar(0.0))
+ Self(Scalar::ZERO)
}
/// The infinite length.
pub const fn inf() -> Self {
- Self(Scalar(f64::INFINITY))
+ Self(Scalar::INFINITY)
}
/// Create an absolute length from a number of raw units.
pub const fn raw(raw: f64) -> Self {
- Self(Scalar(raw))
+ Self(Scalar::new(raw))
}
/// Create an absolute length from a value in a unit.
pub fn with_unit(val: f64, unit: AbsUnit) -> Self {
- Self(Scalar(val * unit.raw_scale()))
+ Self(Scalar::new(val * unit.raw_scale()))
}
/// Create an absolute length from a number of points.
@@ -47,7 +47,7 @@ impl Abs {
/// Get the value of this absolute length in raw units.
pub const fn to_raw(self) -> f64 {
- (self.0).0
+ (self.0).get()
}
/// Get the value of this absolute length in a unit.
diff --git a/crates/typst/src/geom/angle.rs b/crates/typst/src/geom/angle.rs
index 242c80c9..9786f903 100644
--- a/crates/typst/src/geom/angle.rs
+++ b/crates/typst/src/geom/angle.rs
@@ -18,17 +18,17 @@ pub struct Angle(Scalar);
impl Angle {
/// The zero angle.
pub const fn zero() -> Self {
- Self(Scalar(0.0))
+ Self(Scalar::ZERO)
}
/// Create an angle from a number of raw units.
pub const fn raw(raw: f64) -> Self {
- Self(Scalar(raw))
+ Self(Scalar::new(raw))
}
/// Create an angle from a value in a unit.
pub fn with_unit(val: f64, unit: AngleUnit) -> Self {
- Self(Scalar(val * unit.raw_scale()))
+ Self(Scalar::new(val * unit.raw_scale()))
}
/// Create an angle from a number of radians.
@@ -43,7 +43,7 @@ impl Angle {
/// Get the value of this angle in raw units.
pub const fn to_raw(self) -> f64 {
- (self.0).0
+ (self.0).get()
}
/// Get the value of this angle in a unit.
diff --git a/crates/typst/src/geom/em.rs b/crates/typst/src/geom/em.rs
index 8dda9ff6..e6597098 100644
--- a/crates/typst/src/geom/em.rs
+++ b/crates/typst/src/geom/em.rs
@@ -9,29 +9,29 @@ pub struct Em(Scalar);
impl Em {
/// The zero em length.
pub const fn zero() -> Self {
- Self(Scalar(0.0))
+ Self(Scalar::ZERO)
}
/// The font size.
pub const fn one() -> Self {
- Self(Scalar(1.0))
+ Self(Scalar::ONE)
}
/// Create a font-relative length.
pub const fn new(em: f64) -> Self {
- Self(Scalar(em))
+ Self(Scalar::new(em))
}
/// Create an em length from font units at the given units per em.
pub fn from_units(units: impl Into<f64>, units_per_em: f64) -> Self {
- Self(Scalar(units.into() / units_per_em))
+ Self(Scalar::new(units.into() / units_per_em))
}
/// Create an em length from a length at the given font size.
pub fn from_length(length: Abs, font_size: Abs) -> Self {
let result = length / font_size;
if result.is_finite() {
- Self(Scalar(result))
+ Self(Scalar::new(result))
} else {
Self::zero()
}
@@ -39,7 +39,7 @@ impl Em {
/// The number of em units.
pub const fn get(self) -> f64 {
- (self.0).0
+ (self.0).get()
}
/// The absolute value of this em length.
diff --git a/crates/typst/src/geom/fr.rs b/crates/typst/src/geom/fr.rs
index f7cec5d7..ad301558 100644
--- a/crates/typst/src/geom/fr.rs
+++ b/crates/typst/src/geom/fr.rs
@@ -19,22 +19,22 @@ pub struct Fr(Scalar);
impl Fr {
/// Takes up zero space: `0fr`.
pub const fn zero() -> Self {
- Self(Scalar(0.0))
+ Self(Scalar::ZERO)
}
/// Takes up as much space as all other items with this fraction: `1fr`.
pub const fn one() -> Self {
- Self(Scalar(1.0))
+ Self(Scalar::ONE)
}
/// Create a new fraction.
pub const fn new(ratio: f64) -> Self {
- Self(Scalar(ratio))
+ Self(Scalar::new(ratio))
}
/// Get the underlying number.
pub const fn get(self) -> f64 {
- (self.0).0
+ (self.0).get()
}
/// The absolute value of this fraction.
diff --git a/crates/typst/src/geom/ratio.rs b/crates/typst/src/geom/ratio.rs
index 76a09006..b1488276 100644
--- a/crates/typst/src/geom/ratio.rs
+++ b/crates/typst/src/geom/ratio.rs
@@ -18,22 +18,22 @@ pub struct Ratio(Scalar);
impl Ratio {
/// A ratio of `0%` represented as `0.0`.
pub const fn zero() -> Self {
- Self(Scalar(0.0))
+ Self(Scalar::ZERO)
}
/// A ratio of `100%` represented as `1.0`.
pub const fn one() -> Self {
- Self(Scalar(1.0))
+ Self(Scalar::ONE)
}
/// Create a new ratio from a value, where `1.0` means `100%`.
pub const fn new(ratio: f64) -> Self {
- Self(Scalar(ratio))
+ Self(Scalar::new(ratio))
}
/// Get the underlying ratio.
pub const fn get(self) -> f64 {
- (self.0).0
+ (self.0).get()
}
/// Whether the ratio is zero.
diff --git a/crates/typst/src/geom/scalar.rs b/crates/typst/src/geom/scalar.rs
index 71d30040..6801bbc0 100644
--- a/crates/typst/src/geom/scalar.rs
+++ b/crates/typst/src/geom/scalar.rs
@@ -4,7 +4,40 @@ use super::*;
///
/// Panics if it's `NaN` during any of those operations.
#[derive(Default, Copy, Clone)]
-pub struct Scalar(pub f64);
+pub struct Scalar(f64);
+
+// We have to detect NaNs this way since `f64::is_nan` isn’t const
+// on stable yet:
+// ([tracking issue](https://github.com/rust-lang/rust/issues/57241))
+#[allow(clippy::unusual_byte_groupings)]
+const fn is_nan_const(x: f64) -> bool {
+ // Safety: all bit patterns are valid for u64, and f64 has no padding bits.
+ // We cannot use `f64::to_bits` because it is not const.
+ let x_bits = unsafe { std::mem::transmute::<f64, u64>(x) };
+ (x_bits << 1 >> (64 - 12 + 1)) == 0b0_111_1111_1111 && (x_bits << 12) != 0
+}
+
+impl Scalar {
+ /// Creates a [`Scalar`] with the given value.
+ ///
+ /// If the value is NaN, then it is set to `0.0` in the result.
+ pub const fn new(x: f64) -> Self {
+ Self(if is_nan_const(x) { 0.0 } else { x })
+ }
+
+ /// Gets the value of this [`Scalar`].
+ #[inline]
+ pub const fn get(self) -> f64 {
+ self.0
+ }
+
+ /// The scalar containing `0.0`.
+ pub const ZERO: Self = Self(0.0);
+ /// The scalar containing `1.0`.
+ pub const ONE: Self = Self(1.0);
+ /// The scalar containing `f64::INFINITY`.
+ pub const INFINITY: Self = Self(f64::INFINITY);
+}
impl Numeric for Scalar {
fn zero() -> Self {
@@ -18,7 +51,7 @@ impl Numeric for Scalar {
impl From<f64> for Scalar {
fn from(float: f64) -> Self {
- Self(float)
+ Self::new(float)
}
}
@@ -88,7 +121,7 @@ impl Neg for Scalar {
type Output = Self;
fn neg(self) -> Self::Output {
- Self(-self.0)
+ Self::new(-self.0)
}
}
@@ -96,13 +129,13 @@ impl<T: Into<Self>> Add<T> for Scalar {
type Output = Self;
fn add(self, rhs: T) -> Self::Output {
- Self(self.0 + rhs.into().0)
+ Self::new(self.0 + rhs.into().0)
}
}
impl<T: Into<Self>> AddAssign<T> for Scalar {
fn add_assign(&mut self, rhs: T) {
- self.0 += rhs.into().0;
+ *self = *self + rhs.into();
}
}
@@ -110,13 +143,13 @@ impl<T: Into<Self>> Sub<T> for Scalar {
type Output = Self;
fn sub(self, rhs: T) -> Self::Output {
- Self(self.0 - rhs.into().0)
+ Self::new(self.0 - rhs.into().0)
}
}
impl<T: Into<Self>> SubAssign<T> for Scalar {
fn sub_assign(&mut self, rhs: T) {
- self.0 -= rhs.into().0;
+ *self = *self - rhs.into();
}
}
@@ -124,13 +157,13 @@ impl<T: Into<Self>> Mul<T> for Scalar {
type Output = Self;
fn mul(self, rhs: T) -> Self::Output {
- Self(self.0 * rhs.into().0)
+ Self::new(self.0 * rhs.into().0)
}
}
impl<T: Into<Self>> MulAssign<T> for Scalar {
fn mul_assign(&mut self, rhs: T) {
- self.0 *= rhs.into().0;
+ *self = *self * rhs.into();
}
}
@@ -138,13 +171,13 @@ impl<T: Into<Self>> Div<T> for Scalar {
type Output = Self;
fn div(self, rhs: T) -> Self::Output {
- Self(self.0 / rhs.into().0)
+ Self::new(self.0 / rhs.into().0)
}
}
impl<T: Into<Self>> DivAssign<T> for Scalar {
fn div_assign(&mut self, rhs: T) {
- self.0 /= rhs.into().0;
+ *self = *self / rhs.into();
}
}
@@ -152,24 +185,24 @@ impl<T: Into<Self>> Rem<T> for Scalar {
type Output = Self;
fn rem(self, rhs: T) -> Self::Output {
- Self(self.0 % rhs.into().0)
+ Self::new(self.0 % rhs.into().0)
}
}
impl<T: Into<Self>> RemAssign<T> for Scalar {
fn rem_assign(&mut self, rhs: T) {
- self.0 %= rhs.into().0;
+ *self = *self % rhs.into();
}
}
impl Sum for Scalar {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
- Self(iter.map(|s| s.0).sum())
+ Self::new(iter.map(|s| s.0).sum())
}
}
impl<'a> Sum<&'a Self> for Scalar {
fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
- Self(iter.map(|s| s.0).sum())
+ Self::new(iter.map(|s| s.0).sum())
}
}
diff --git a/crates/typst/src/geom/stroke.rs b/crates/typst/src/geom/stroke.rs
index 893ac2eb..91e7ee2e 100644
--- a/crates/typst/src/geom/stroke.rs
+++ b/crates/typst/src/geom/stroke.rs
@@ -266,7 +266,7 @@ cast! {
line_cap,
line_join,
dash_pattern,
- miter_limit: miter_limit.map(Scalar),
+ miter_limit: miter_limit.map(Scalar::new),
}
},
}
@@ -460,7 +460,7 @@ impl Default for FixedStroke {
line_cap: LineCap::Butt,
line_join: LineJoin::Miter,
dash_pattern: None,
- miter_limit: Scalar(4.0),
+ miter_limit: Scalar::new(4.0),
}
}
}