typst / typst

A new markup-based typesetting system that is powerful and easy to learn.
https://typst.app
Apache License 2.0
35.67k stars 953 forks source link

When use grid with font awesome package, the output is weird #2578

Open tomowang opened 1 year ago

tomowang commented 1 year ago

Description

fa-icon("\u{f445}") and fa-chess-queen() works fine, but not fa-icon("chess-queen"), while fa-icon("chess-queen") works fine out of grid layout.

Sample code

#import "@preview/fontawesome:0.1.0": *
#grid(
  columns: auto,
  rows: auto,
  column-gutter: 1em,
  row-gutter: 1em,
  fa-icon("\u{f445}"),  // works
  fa-chess-queen(),  // works
  fa-icon("chess-queen"),  // not work
  fa-icon("chess-queen", fa-set: "Free Solid"),  // not work
)

#fa-icon("chess-queen")  // works

The output of above code is like:

image

I now use fa-icon("\u{f445}") for a workaround.

This issue seems to be similar with https://github.com/duskmoon314/typst-fontawesome/issues/2

Reproduction URL

https://typst.app/project/r4eYUzsDig3IrjArCX_02R

Operating system

Web app, macOS

Typst version

duskmoon314 commented 1 year ago

In the current package, fa-chess-queen is actually fa-icon.with("\u{f445}"). So, I think the weird output has something to do with ligature. However I have no idea how to find out what is happening.

pyxyne commented 8 months ago

I encountered this issue as well while using Font Awesome "manually" (without the package).

Here is a link to some simpler (?) experiments using boxes on the web app. It seems that a ligature can fail to be applied if the first line of the version before the ligature is applied overflows its container? The behavior seems quite arcane.

There is a simple workaround: place the icon in a box with an explicit, oversized width.

SillyFreak commented 8 months ago

It seems the ligature fails if this first line doesn't fit the container. However this begs the question of why the first ligature (#fa[chess]) succeeds...

That's pretty clearly because "chess" doesn't have any place where it could be broken across lines. the word "chess" overflows the box but stays on the same line, and then ligatures are applied, coincidentally making it fit the box after all.

pyxyne commented 8 months ago

That's pretty clearly because "chess" doesn't have any place where it could be broken across lines. the word "chess" overflows the box but stays on the same line, and then ligatures are applied, coincidentally making it fit the box after all.

Right you are! Then I guess the specific trigger for the bug is: have text that would otherwise be a ligature be broken over multiple lines, where the first one still doesn't fit the container.

SillyFreak commented 8 months ago

I was about to edit my comment because I don't agree with myself any more... it seems to be that way, but that is arcane: my hypothesis would explain (to me) why the "chess" ligature always works, but not why that specific width leads to "chess-queen" or even "network-wired" to work...

I would assume that rendering the ligatures leads to multiple layout passes; it would be interesting to see what happens on these individual layout passes.

duskmoon314 commented 4 months ago

I just added some println to shape and reshape functions in crates/typst/src/layout/inline/shaping.rs. Here is the code I tested and the output:

#text("chess-queen", font: "Font Awesome 6 Free")

divide

#box(width: 10pt)[
  #text("chess-queen", font: "Font Awesome 6 Free")
]

The box element is used to force a line break.

$ ./target/debug/typst c test.typ --font-path .
shape
shape:shape_segment: 0 "chess-queen"
range: 0..6, subrange: 0..11, item: Text("chess-queen")
reshape 0..6
shape
shape:shape_segment: 0 "chess-"
range: 0..11, subrange: 0..11, item: Text("chess-queen")
shape
shape:shape_segment: 0 "divide"
range: 0..6, subrange: 0..6, item: Text("divide")
shape
shape:shape_segment: 0 "chess-queen"
range: 0..6, subrange: 0..11, item: Text("chess-queen")
reshape 0..6
shape
shape:shape_segment: 0 "chess-"
range: 6..11, subrange: 0..11, item: Text("chess-queen")
reshape 6..11
shape
shape:shape_segment: 6 "queen"
range: 0..3, subrange: 0..3, item: Frame(Frame [Text("chess-"), Text("queen")], StyleChain [])

It seems that reshape uses the original text and doesn't consider the glyph after ligature. However, I still don't know how to fix this.