printpdf icon indicating copy to clipboard operation
printpdf copied to clipboard

About shaping using allsorts

Open martin-kolarik opened this issue 8 months ago • 3 comments

I looked a bit more to how to use allsorts shaping in the current code and it seems difficult. More precisely, I do not know plans with printpdf, so I cannot speak about how things should or should not be done.

Technically:

  • allsorts shaping requires to create allsorts::Font, using FontProvider. This means, that if printpdf used it the whole bunch of code (PreparedFont) would be effectively duplicate (because it is needed for azul).
  • Using allsorts shaping naively, meaning just to create Font and to call shape, would require repeated parsing of whole font binary, if the Font was not cached. I already mentioned this, because font parsing is really slow, so I have created and I am using cache of Font (FontProvider). printpdf currently is lacking this (because it parses fonts on it own).
  • Existing printpdf ParsedFont could be used for shaping like allsorts does, but it would require copy out big amount of shaping code from allsorts. Likely 'all the cleverness'. It does not look for me as viable way.

So, I am stuck :-).

martin-kolarik avatar May 20 '25 21:05 martin-kolarik

printpdf currently is lacking this (because it parses fonts on it own)

No, if I remember correctly, it just "translates" a printpdf::ParsedFont to an azul::ParsedFont (which is a wrapper over an allsorts::Font), and then calls the shaping on that. If you want to fix shaping, it needs to be fixed in azul to use the allsorts

The dependency is:

printpdf -> azul-layout [feature = shaping] -> allsorts

The ParsedFont is done so to not directly expose the azul crate. But the parsing is not done again.

This is also why HTML is enabled: because it just enables the additional "layout" feature in azul-layout, which just adds a bit of extra code but you (should) get full HTML support.

fschutt avatar May 21 '25 14:05 fschutt

No, if I remember correctly, it just "translates" a printpdf::ParsedFont to an azul::ParsedFont (which is a wrapper over an

I meant in relation to caching. ParsedFont::from_bytes parses font independently on azul (and is using allsorts::Font @1061), but because then azul is used, using allsorts::shape would require new parsing.

allsorts::Font), and then calls the shaping on that. If you want to fix shaping, it needs to be fixed in azul to use the allsorts

Yes. azul does not call allsorts::shape, it has code copied out of allsorts (merged two or three allsorts functions), so fixing shaping would require to change azul. Not so much, I think, there only parameters to shaping are not given anywhere. Do you know about azul more? Esp., I am wonder why azul almost copied the code without calling allsorts?

martin-kolarik avatar May 21 '25 15:05 martin-kolarik

Esp., I am wonder why azul almost copied the code without calling allsorts?

I believe it's because ecause azul exposes a C API with very "open" fields, i.e. you can set the fields directly from C, so all structs need a #[repr(C)]. Originally there were also multiple font parsers, rusttype, allsorts, etc. Then allsorts emerged as the best so far. I am the creator of azul, so I know the project.

Also, it allows for better "mocking" and the translate_font_to_allsorts can be easily generated (or vibe-coded) because it just translates fields. So it's mostly removed in optimization passes.

Also, it helps against API breakage, for example if the underlying project breaks APIs very fast (not the case with allsorts).

fschutt avatar May 21 '25 16:05 fschutt