Compare commits

...

3 Commits

Author SHA1 Message Date
Tau
a2cb405d4a
Merge ce169026b329a35e57f45b0c57b32e706fa4b9e2 into 7278d887cf05fadc9a96478830e5876739b78f53 2025-07-23 17:44:42 +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
Alice Carroll
ce169026b3
feat: non-breaking hyphen shorthand
Closes #6355
2025-07-18 12:03:07 +03:00
10 changed files with 28 additions and 20 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

@ -595,6 +595,7 @@ impl Shorthand<'_> {
("--", '\u{2013}'), ("--", '\u{2013}'),
("---", '\u{2014}'), ("---", '\u{2014}'),
("-?", '\u{00AD}'), ("-?", '\u{00AD}'),
("-!", '\u{2011}'),
]; ];
/// Get the shorthanded character. /// Get the shorthanded character.

View File

@ -191,6 +191,7 @@ impl Lexer<'_> {
'-' if self.s.eat_if("--") => SyntaxKind::Shorthand, '-' if self.s.eat_if("--") => SyntaxKind::Shorthand,
'-' if self.s.eat_if('-') => SyntaxKind::Shorthand, '-' if self.s.eat_if('-') => SyntaxKind::Shorthand,
'-' if self.s.eat_if('?') => SyntaxKind::Shorthand, '-' if self.s.eat_if('?') => SyntaxKind::Shorthand,
'-' if self.s.eat_if('!') => SyntaxKind::Shorthand,
'-' if self.s.at(char::is_numeric) => SyntaxKind::Shorthand, '-' if self.s.at(char::is_numeric) => SyntaxKind::Shorthand,
'*' if !self.in_word() => SyntaxKind::Star, '*' if !self.in_word() => SyntaxKind::Star,
'_' if !self.in_word() => SyntaxKind::Underscore, '_' if !self.in_word() => SyntaxKind::Underscore,
@ -524,7 +525,7 @@ impl Lexer<'_> {
match s.eat() { match s.eat() {
Some(' ') if s.at(char::is_alphanumeric) => {} Some(' ') if s.at(char::is_alphanumeric) => {}
Some('/') if !s.at(['/', '*']) => {} Some('/') if !s.at(['/', '*']) => {}
Some('-') if !s.at(['-', '?']) => {} Some('-') if !s.at(['-', '?', '!']) => {}
Some('.') if !s.at("..") => {} Some('.') if !s.at("..") => {}
Some('h') if !s.at("ttp://") && !s.at("ttps://") => {} Some('h') if !s.at("ttp://") && !s.at("ttps://") => {}
Some('@') if !s.at(is_valid_in_label_literal) => {} Some('@') if !s.at(is_valid_in_label_literal) => {}

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -10,7 +10,7 @@ Supercalifragilisticexpialidocious Expialigoricmetrioxidation.
--- linebreak-hyphen-nbsp --- --- linebreak-hyphen-nbsp ---
// Test for non-breaking space and hyphen. // Test for non-breaking space and hyphen.
There are non\u{2011}breaking~characters. There are non-!breaking~characters.
--- linebreak-narrow-nbsp --- --- linebreak-narrow-nbsp ---
// Test for narrow non-breaking space. // Test for narrow non-breaking space.

View File

@ -1,7 +1,7 @@
// Test shorthands for unicode codepoints. // Test shorthands for unicode codepoints.
--- shorthand-nbsp-and-shy-hyphen --- --- shorthand-nbsp-and-shy-hyphen ---
The non-breaking space~does work, soft-?hyphen also does. The non-breaking space~does work, soft-?hyphen does, and non-!breaking hyphen also does.
--- shorthand-nbsp-width --- --- shorthand-nbsp-width ---
// Make sure non-breaking and normal space always // Make sure non-breaking and normal space always

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,

View File

@ -42,6 +42,10 @@
"name": "punctuation.definition.nonbreaking-space.typst", "name": "punctuation.definition.nonbreaking-space.typst",
"match": "~" "match": "~"
}, },
{
"name": "punctuation.definition.nonbreaking-hyphen.typst",
"match": "-!"
},
{ {
"name": "punctuation.definition.shy.typst", "name": "punctuation.definition.shy.typst",
"match": "-\\?" "match": "-\\?"