Compare commits

...

13 Commits

Author SHA1 Message Date
diquah
94f47fe609
Merge 4aa6dcf578ce3fde6209369c358bde012150146c into 7278d887cf05fadc9a96478830e5876739b78f53 2025-07-23 23:45:26 +07: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
diquah
4aa6dcf578
Merge branch 'main' into main 2025-05-02 18:53:25 -07:00
diquah
34e2e43445 Minor formatting fix 2025-05-02 17:09:18 -07:00
diquah
0148a5913d Merge branch 'main' of https://github.com/diquah/typst 2025-05-02 16:58:49 -07:00
diquah
c8d45148f1 Fix naming convention 2025-05-02 16:58:45 -07:00
diquah
a445a3108f
Merge branch 'main' into main 2025-04-11 12:24:55 -07:00
diquah
69d0d9e26d Formatting fix 2025-04-10 19:23:21 -07:00
diquah
4fa7e5cfd9 Fix warnings 2025-04-10 19:18:21 -07:00
diquah
7d6d46c4d8 Remove microjustification 2025-04-10 19:05:30 -07:00
diquah
07ba1c1636 Add microtype options for par 2025-04-10 19:01:02 -07:00
diquah
422eb36f16 Fix formatting issue 2025-04-10 00:15:44 -07:00
diquah
7f9adfac22 Add microjustification 2025-04-09 23:20:46 -07:00
6 changed files with 64 additions and 20 deletions

View File

@ -10,6 +10,7 @@ use typst_library::World;
use typst_library::engine::Engine; use typst_library::engine::Engine;
use typst_library::foundations::{Smart, StyleChain}; use typst_library::foundations::{Smart, StyleChain};
use typst_library::layout::{Abs, Dir, Em, Frame, FrameItem, Point, Size}; use typst_library::layout::{Abs, Dir, Em, Frame, FrameItem, Point, Size};
use typst_library::model::{Microtype, ParElem};
use typst_library::text::{ use typst_library::text::{
Font, FontFamily, FontVariant, Glyph, Lang, Region, ShiftSettings, TextEdgeBounds, Font, FontFamily, FontVariant, Glyph, Lang, Region, ShiftSettings, TextEdgeBounds,
TextElem, TextItem, families, features, is_default_ignorable, language, variant, TextElem, TextItem, families, features, is_default_ignorable, language, variant,
@ -144,7 +145,11 @@ impl ShapedGlyph {
|| self.c.is_ascii_digit() || self.c.is_ascii_digit()
} }
pub fn base_adjustability(&self, style: CjkPunctStyle) -> Adjustability { pub fn base_adjustability(
&self,
style: CjkPunctStyle,
microtype: Microtype,
) -> Adjustability {
let width = self.x_advance; let width = self.x_advance;
if self.is_space() { if self.is_space() {
Adjustability { Adjustability {
@ -168,7 +173,10 @@ impl ShapedGlyph {
shrinkability: (width / 4.0, width / 4.0), shrinkability: (width / 4.0, width / 4.0),
} }
} else { } else {
Adjustability::default() Adjustability {
stretchability: (Em::zero(), microtype.max_expand.em),
shrinkability: (Em::zero(), microtype.max_retract.em),
}
} }
} }
@ -1106,9 +1114,10 @@ fn track_and_space(ctx: &mut ShapingContext) {
/// and CJK punctuation adjustments according to Chinese Layout Requirements. /// and CJK punctuation adjustments according to Chinese Layout Requirements.
fn calculate_adjustability(ctx: &mut ShapingContext, lang: Lang, region: Option<Region>) { fn calculate_adjustability(ctx: &mut ShapingContext, lang: Lang, region: Option<Region>) {
let style = cjk_punct_style(lang, region); let style = cjk_punct_style(lang, region);
let microtype = ParElem::microtype_in(ctx.styles);
for glyph in &mut ctx.glyphs { for glyph in &mut ctx.glyphs {
glyph.adjustability = glyph.base_adjustability(style); glyph.adjustability = glyph.base_adjustability(style, microtype);
} }
let mut glyphs = ctx.glyphs.iter_mut().peekable(); let mut glyphs = ctx.glyphs.iter_mut().peekable();

View File

@ -136,6 +136,9 @@ pub struct ParElem {
#[default(false)] #[default(false)]
pub justify: bool, pub justify: bool,
/// Microtypographical settings that are used during justification.
pub microtype: Microtype,
/// How to determine line breaks. /// How to determine line breaks.
/// ///
/// When this property is set to `{auto}`, its default value, optimized line /// When this property is set to `{auto}`, its default value, optimized line
@ -224,6 +227,36 @@ impl ParElem {
type ParLine; type ParLine;
} }
/// Configuration for microtypographical settings to be used during
/// justification.
#[derive(Debug, Default, Copy, Clone, PartialEq, Hash)]
pub struct Microtype {
/// How much a glyph is allowed to translate into its neighbor.
pub max_retract: Length,
/// How much a glyph is allowed to translate away from its neighbor.
pub max_expand: Length,
}
cast! {
Microtype,
self => Value::Dict(self.into()),
mut dict: Dict => {
let max_retract = dict.take("max-retract")?.cast()?;
let max_expand = dict.take("max-expand")?.cast()?;
dict.finish(&["max-retract", "max-expand"])?;
Self { max_retract, max_expand }
},
}
impl From<Microtype> for Dict {
fn from(microtype: Microtype) -> Self {
dict! {
"max-retract" => microtype.max_retract,
"max-expand" => microtype.max_expand,
}
}
}
/// How to determine line breaks in a paragraph. /// How to determine line breaks in a paragraph.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Cast)] #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Cast)]
pub enum Linebreaks { pub enum Linebreaks {

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)
} }
} }

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,