diff --git a/crates/typst/src/layout/transform.rs b/crates/typst/src/layout/transform.rs index ad3668d10..dcb178fdb 100644 --- a/crates/typst/src/layout/transform.rs +++ b/crates/typst/src/layout/transform.rs @@ -12,6 +12,7 @@ use crate::layout::{ Abs, Alignment, Angle, Axes, BlockElem, FixedAlignment, Frame, HAlignment, Length, Point, Ratio, Region, Regions, Rel, Size, VAlignment, }; +use crate::utils::Numeric; /// Moves content without affecting layout. /// @@ -153,12 +154,11 @@ fn layout_rotate( let align = elem.origin(styles).resolve(styles); // Compute the new region's approximate size. - let size = region - .size - .to_point() - .transform_inf(Transform::rotate(angle)) - .map(Abs::abs) - .to_size(); + let size = if region.size.is_finite() { + compute_bounding_box(region.size, Transform::rotate(-angle)).1 + } else { + Size::splat(Abs::inf()) + }; measure_and_layout( engine, @@ -248,7 +248,10 @@ fn layout_scale( ) -> SourceResult { // Compute the new region's approximate size. let scale = elem.resolve_scale(engine, locator.relayout(), region.size, styles)?; - let size = region.size.zip_map(scale, |r, s| s.of(r)).map(Abs::abs); + let size = region + .size + .zip_map(scale, |r, s| if r.is_finite() { Ratio::new(1.0 / s).of(r) } else { r }) + .map(Abs::abs); measure_and_layout( engine, @@ -489,7 +492,7 @@ fn measure_and_layout( .pre_concat(Transform::translate(-x, -y)); // Compute the bounding box and offset and wrap in a new frame. - let (offset, size) = compute_bounding_box(&frame, ts); + let (offset, size) = compute_bounding_box(frame.size(), ts); frame.transform(ts); frame.translate(offset); frame.set_size(size); @@ -512,20 +515,20 @@ fn measure_and_layout( } } -/// Computes the bounding box and offset of a transformed frame. -fn compute_bounding_box(frame: &Frame, ts: Transform) -> (Point, Size) { +/// Computes the bounding box and offset of a transformed area. +fn compute_bounding_box(size: Size, ts: Transform) -> (Point, Size) { let top_left = Point::zero().transform_inf(ts); - let top_right = Point::new(frame.width(), Abs::zero()).transform_inf(ts); - let bottom_left = Point::new(Abs::zero(), frame.height()).transform_inf(ts); - let bottom_right = Point::new(frame.width(), frame.height()).transform_inf(ts); + let top_right = Point::with_x(size.x).transform_inf(ts); + let bottom_left = Point::with_y(size.y).transform_inf(ts); + let bottom_right = size.to_point().transform_inf(ts); - // We first compute the new bounding box of the rotated frame. + // We first compute the new bounding box of the rotated area. let min_x = top_left.x.min(top_right.x).min(bottom_left.x).min(bottom_right.x); let min_y = top_left.y.min(top_right.y).min(bottom_left.y).min(bottom_right.y); let max_x = top_left.x.max(top_right.x).max(bottom_left.x).max(bottom_right.x); let max_y = top_left.y.max(top_right.y).max(bottom_left.y).max(bottom_right.y); - // Then we compute the new size of the frame. + // Then we compute the new size of the area. let width = max_x - min_x; let height = max_y - min_y; diff --git a/tests/ref/transform-scale-relative-sizing.png b/tests/ref/transform-scale-relative-sizing.png index d10bd3ff4..a6c18a98e 100644 Binary files a/tests/ref/transform-scale-relative-sizing.png and b/tests/ref/transform-scale-relative-sizing.png differ diff --git a/tests/ref/transform-scale.png b/tests/ref/transform-scale.png index c95b90f1d..ea113aa1b 100644 Binary files a/tests/ref/transform-scale.png and b/tests/ref/transform-scale.png differ