Compare commits

...

3 Commits

Author SHA1 Message Date
frozolotl
96745a7ed2
Merge ed5f85e0cdc0dc7a7b8c5e7619d1a641520d9ae4 into 7278d887cf05fadc9a96478830e5876739b78f53 2025-07-23 16:23:18 +02:00
Tobias Schmitz
7278d887cf
Fix bounding box computation for lines in curves (#6647)
Co-authored-by: Laurenz <laurmaedje@gmail.com>
2025-07-23 14:17:03 +00:00
frozolotl
ed5f85e0cd Follow the comment on setting the State's mask
This does not actually change any existing behavior, as `with_mask` is
not used in a way that uses it. However, it should align reality with
expectations.

## Alternatives

There is a case to be made for simply removing the function, or for not
changing its behavior, but simply the code. I think the new behavior
(and the one written about in the code's comment) makes sense though.

## Postface

Interestingly, this PR was inspired by another AI-generated slop PR.[^1]

[^1]: https://github.com/typst/typst/pull/6640/files#diff-756093ac5fe76dbe9e281b08197b3cec0a930f18fab8d23a57c781c21886a606R174-R175
2025-07-22 02:43:46 +02:00
5 changed files with 24 additions and 21 deletions

View File

@ -476,26 +476,18 @@ impl Curve {
/// Computes the size of the bounding box of this curve. /// Computes the size of the bounding box of this curve.
pub fn bbox_size(&self) -> Size { pub fn bbox_size(&self) -> Size {
let mut min_x = Abs::inf(); let mut min = Point::splat(Abs::inf());
let mut min_y = Abs::inf(); let mut max = Point::splat(-Abs::inf());
let mut max_x = -Abs::inf();
let mut max_y = -Abs::inf();
let mut cursor = Point::zero(); let mut cursor = Point::zero();
for item in self.0.iter() { for item in self.0.iter() {
match item { match item {
CurveItem::Move(to) => { CurveItem::Move(to) => {
min_x = min_x.min(cursor.x);
min_y = min_y.min(cursor.y);
max_x = max_x.max(cursor.x);
max_y = max_y.max(cursor.y);
cursor = *to; cursor = *to;
} }
CurveItem::Line(to) => { CurveItem::Line(to) => {
min_x = min_x.min(cursor.x); min = min.min(cursor).min(*to);
min_y = min_y.min(cursor.y); max = max.max(cursor).max(*to);
max_x = max_x.max(cursor.x);
max_y = max_y.max(cursor.y);
cursor = *to; cursor = *to;
} }
CurveItem::Cubic(c0, c1, end) => { CurveItem::Cubic(c0, c1, end) => {
@ -507,17 +499,17 @@ impl Curve {
); );
let bbox = cubic.bounding_box(); let bbox = cubic.bounding_box();
min_x = min_x.min(Abs::pt(bbox.x0)).min(Abs::pt(bbox.x1)); min.x = min.x.min(Abs::pt(bbox.x0)).min(Abs::pt(bbox.x1));
min_y = min_y.min(Abs::pt(bbox.y0)).min(Abs::pt(bbox.y1)); min.y = min.y.min(Abs::pt(bbox.y0)).min(Abs::pt(bbox.y1));
max_x = max_x.max(Abs::pt(bbox.x0)).max(Abs::pt(bbox.x1)); max.x = max.x.max(Abs::pt(bbox.x0)).max(Abs::pt(bbox.x1));
max_y = max_y.max(Abs::pt(bbox.y0)).max(Abs::pt(bbox.y1)); max.y = max.y.max(Abs::pt(bbox.y0)).max(Abs::pt(bbox.y1));
cursor = *end; cursor = *end;
} }
CurveItem::Close => (), CurveItem::Close => (),
} }
} }
Size::new(max_x - min_x, max_y - min_y) Size::new(max.x - min.x, max.y - min.y)
} }
} }

View File

@ -93,7 +93,7 @@ struct State<'a> {
size: Size, size: Size,
} }
impl State<'_> { impl<'a> State<'a> {
fn new(size: Size, transform: sk::Transform, pixel_per_pt: f32) -> Self { fn new(size: Size, transform: sk::Transform, pixel_per_pt: f32) -> Self {
Self { Self {
size, size,
@ -128,9 +128,10 @@ impl State<'_> {
} }
/// Sets the current mask. /// Sets the current mask.
fn with_mask(self, mask: Option<&sk::Mask>) -> State<'_> { ///
// Ensure that we're using the parent's mask if we don't have one. /// If no mask is provided, the parent mask is used.
if mask.is_some() { State { mask, ..self } } else { State { mask: None, ..self } } fn with_mask(self, mask: Option<&'a sk::Mask>) -> State<'a> {
State { mask: mask.or(self.mask), ..self }
} }
/// Sets the size of the first hard frame in the hierarchy. /// Sets the size of the first hard frame in the hierarchy.

Binary file not shown.

After

Width:  |  Height:  |  Size: 399 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -130,6 +130,16 @@
down, up, down, up, down, down, up, down, up, down,
) )
--- curve-stroke-gradient-sharp ---
#set page(width: auto)
#let down = curve.line((40pt, 40pt), relative: true)
#let up = curve.line((40pt, -40pt), relative: true)
#curve(
stroke: 4pt + gradient.linear(red, blue).sharp(3),
down, up, down, up, down,
)
--- curve-fill-rule --- --- curve-fill-rule ---
#stack( #stack(
dir: ltr, dir: ltr,