Fix approximated size of reflow: true transformations (#4462)

Co-authored-by: Laurenz <laurmaedje@gmail.com>
This commit is contained in:
shinyfelix 2024-07-20 14:26:57 +02:00 committed by GitHub
parent 3ef0991fbb
commit 3aa18beacf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 18 additions and 15 deletions

View File

@ -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<Frame> {
// 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;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB