Skip to content

Enhance the handling of symbolic fonts combined with kerning and ligature option (#2143)#2144

Merged
speckyspooky merged 1 commit intoeclipse-birt:masterfrom
speckyspooky:enhance_pdf_webdings_font_2143
May 10, 2025
Merged

Enhance the handling of symbolic fonts combined with kerning and ligature option (#2143)#2144
speckyspooky merged 1 commit intoeclipse-birt:masterfrom
speckyspooky:enhance_pdf_webdings_font_2143

Conversation

@speckyspooky
Copy link
Contributor

No description provided.

@speckyspooky speckyspooky added this to the 4.20 milestone May 10, 2025
@speckyspooky speckyspooky self-assigned this May 10, 2025
@speckyspooky speckyspooky added the Enhancement Small change to improve the current supported functionality label May 10, 2025
@speckyspooky speckyspooky force-pushed the enhance_pdf_webdings_font_2143 branch from 19f062b to 3bf2ab6 Compare May 10, 2025 16:20
@speckyspooky speckyspooky merged commit 2aef7c4 into eclipse-birt:master May 10, 2025
3 checks passed
@speckyspooky speckyspooky linked an issue May 10, 2025 that may be closed by this pull request
@hvbtup
Copy link
Contributor

hvbtup commented May 12, 2025

@vk-github18 @speckyspooky I'm a bit worried regarding multi-threading.

BIRT is supposed to work in a multi-threading environment.

But OpenPDF uses a global LayoutProcessor (a class, with static objects, or a singleton, I don't remember ATM), with some flags.
And we switch these flags on and off possibly several times during processing a BIRT report.

Of course this works in simple test cases, but isn't this going to run into bugs due to race conditions in a MT environement under load? And these kind of bugs are very, very hard to reproduce and to analyze later.

Probably this cannot be solved in BIRT at all, but requires a change in OpenPDF?

@vk-github18
Copy link

vk-github18 commented May 12, 2025 via email

@hvbtup
Copy link
Contributor

hvbtup commented May 12, 2025

@vk-github18 Regarding "Why would you change the flags?" Because that's what 2aef7c4 does.

@vk-github18
Copy link

vk-github18 commented May 12, 2025 via email

@hvbtup
Copy link
Contributor

hvbtup commented May 12, 2025

Let me summarize the situation and please correct me if I'm wrong.

Since we updated to OpenPDF 2.0.3, several issues were reported regarding different non-latin fonts and ligatures with the Calibri font (#2143, #2133, #2119, #2058, #2043, #2033).

Thomas (with your help) tried his best to fix these issues, which all seem to be related to LayoutProcessor somehow (at least this is my impression).

Fixing the latest issue #2143 seems to require switching LayoutProcessor features on and off on a per-font basis before calling drawText (see the commit I mentioned above). This is a low-level internal routine which writes some text fragment in a given font, size and style at a given position to the page.

According to Volker, this is not really supported.

So what can we do now?

Note: Even if we had to fiddle with the LayoutProcessor settings only at report level instead of text fragment level, this would not remedy the situation. As long as OpenPDF uses global variables, which have to be set this way or that way for different fonts to achieve correct results, it is not really thread-safe.
The old iText library was thread-safe AFAIK, so shouldn't this be a design goal for OpenPDF as well?

@speckyspooky
Copy link
Contributor Author

If the LayoutProcessor is enabled then the kerning cannot be Set because the processor is already online.
But the LayoutProcessor must be online because the full disabling of the processor is controlled via enabling flag.
So it was my target to do it in this way.

Other ways will not work.

@vk-github18
Copy link

vk-github18 commented May 12, 2025 via email

@speckyspooky
Copy link
Contributor Author

The communication is to long.
I invested a lot of time for testing and my solution is working.

And I tested a lot of cases.
I can retest the cases of kerning but it the LayoutProcessor is sometimes misteriouse.

The current way is working for all issues which was addressed.

@hvbtup
Copy link
Contributor

hvbtup commented May 12, 2025

The sad truth about multi-threading is that race conditions occur in production only.
You cannot really test them with reasonable effort.
I bet a box of beer that this will lead to "wrong output" issues in the next 3 years.
And these errors will be very, very hard to reproduce and analyze.

@vk-github18, can you point us to the bug which is fixed in OpenPDF and what change was made in OpenPDFSaucer?

So to be consistent, either
A: Don't use LayoutProcessor
B: Use LayoutProcessor for all glyph layout and use only OpenType fonts.

If I understand the issues I mentioned correctly, then for some reports we need to disable the LayoutProcessor, and for others we need to enable it. So we can choose neither A nor B.

I still think a clean approach would require that OpenPDF supports different LayoutProcessor objects instead of just a class with static attributes.
Basically, the low-level routines which depend on the settings (probably in the PDFContentByte class) could be overloaded with an optional layoutProcessor argument, which BIRT could supply.
This way each BIRT report generation task could use its personal LayoutProcessor settings which don't affect other threads.

@speckyspooky
Copy link
Contributor Author

There is also e special case where the LayoutProcessor is to be enabled with usage flag "0".
Which means processor is active but without kerning and ligatures.

Because LayoutProcessor.disabled() is not like the same like LayoutProcessor.enable(0).
I don't know if this is a bug or a feature or a special constellation of handling.

@vk-github18
Copy link

@vk-github18, can you point us to the bug which is fixed in OpenPDF and what change was made in OpenPDFSaucer?
See https://github.com/openpdfsaucer/openpdfsaucer/pull/40
and LibrePDF/OpenPDF#1159

So to be consistent, either
A: Don't use LayoutProcessor
B: Use LayoutProcessor for all glyph layout and use only OpenType fonts.

If I understand the issues I mentioned correctly, then for some reports we need to disable the LayoutProcessor, and for others we need to enable it. So we can choose neither A nor B.

LayoutProcessor should be able to handle all cases. If you can provide an OpenPDF-only example I can have a look.

@vk-github18
Copy link

vk-github18 commented May 12, 2025

There is also e special case where the LayoutProcessor is to be enabled with usage flag "0". Which means processor is active but without kerning and ligatures.

Because LayoutProcessor.disabled() is not like the same like LayoutProcessor.enable(0). I don't know if this is a bug or a feature or a special constellation of handling.

You are calling enable(Font.LAYOUT_LEFT_TO_RIGHT), in most circumstances I would just call LayoutProcessor.enable();

And no -- calling disable is not the same as enable.
Again: LayoutProcessor is about glyph layout, substitution, reordering etc. Kerning and ligatures are just minor aspects.

@hvbtup
Copy link
Contributor

hvbtup commented May 19, 2025

@speckyspooky
I created an OpenPDF issue 1307 for this and in that issue Volker pointed to an OpenPDF example GlyphLayoutDocumentKernLigaPerFont.java which shows that the LayoutProcessor can be enabled once on startup and then kerning and ligature support can be specified on a per-font basis.

I think the code from commit 2aef7c4 and other places should be changed in such a way that is uses the same approach as the OpenPDF example, that is, enable or disable the LayoutProcessor only once at the beginning and then enable or disable kerning and/or ligatures using the LayoutProcessor methods LayoutProcessor.setLigatures(font) and LayoutProcessor.setKerning(font).

@vk-github18 Though I find the API not quite clear: Is it disabled by default? I mean, I would expect a boolean argument as well...

@vk-github18
Copy link

vk-github18 commented May 19, 2025 via email

@vk-github18
Copy link

vk-github18 commented May 19, 2025 via email

@vk-github18
Copy link

vk-github18 commented May 19, 2025

@hvbtup

enable or disable kerning and/or ligatures using the LayoutProcessor methods
LayoutProcessor.setLigatures(font) and LayoutProcessor.setKerning(font).

set means enable here.
These methods should also only called once at the start.

@hvbtup
Copy link
Contributor

hvbtup commented May 20, 2025

OK, so, if I understand everything correctly, the best practice would be:

  • Call LayoutProcessor.enable() once at BIRT startup time.
  • For kerning and ligatures, the default is false. Use LayoutProcessor.setLigatures(font) and/or LayoutProcessor.setKerning(font) (if the user wants to enable it for a specific font)exactly once for that, when the font is loaded for the first time (I recall vaguely that either OpenPDF or BIRT use a font cache).

For BIRT, this could be implemented as follows:

Have three global properties in fontsConfig.xml:

  1. whether the LayoutProcessor shall be enabled at all (the default should be true)

Document that all other settings only work if this first property is true.

  1. whether kerning shall be enabled by default (default: false)
  2. whether ligatures shall be enabled by default (default: false)

These settings only specify the defaults and can be overridden per font.

For each font, optionally override the defaults from 2. and 3. :
4. Override kerning property from 2.
5. Override ligatures property from 3.

In the code, when a font is used for the first time (and only then):
Check if property 4 is specified for this font. If yes, use this value.
Otherwise, use the value from property 2.
If the value is yes, call LayoutProcessor.setKerning(font), otherwise do nothing.

For ligatures, in the same way, use the values from the properties 5 and 3 and LayoutProcessor.setLigaturesfont).

Never call LayoutProcess.enableKernLiga() or LayoutProcessor.disable().
Note that the properties cannot be set for individual reports, but I guess that's OK.

I'm undecided about whether we need a special handling in the code for symbolic fonts.
Using the configuration options I described above, they can be configured in fontsConfig.xml.
OTOH modifying this file is not always easy, depending on the situation.
So the default for symbol fonts should "just work". If not, then we still need a special handling for these fonts, wich should be switched on by default. For these fonts, instead of the values from properties 2 and 3, the logic should use defaults for kerning and ligatures that just work.

@speckyspooky
Copy link
Contributor Author

Hi together,
the core problem was that the kerning and ligatures should be disabled to avoid automated handling at all.
So we cannot set by default the of LayoutProcessor to "true".
And there was also special handling of OpenPDF why LayoutProcessor.disable() was not working correctly therefore I used enabled(0).
And of course, the handling of symbolic fonts should be given by default. This was a side effect that I disabled all and the symbolic fonts are not displayed correctly. Which is now fixed.

I'm confused with the description of the comment:
grafik

Means this the method can only be called for this specific font 1 times or over all 1 times?

@hvbtup
Copy link
Contributor

hvbtup commented May 20, 2025

I don't mind if the default for the LayoutProcessor is enabled or disabled.

@vk-github18
Copy link

vk-github18 commented May 20, 2025 via email

@hvbtup
Copy link
Contributor

hvbtup commented May 20, 2025

@vk-github18
AFAIK we (BIRT) cannot use the trunk of OpenPDF, we must use a Maven release.
Do you know when the next release of OpenPDF is to be expected?

@vk-github18
Copy link

vk-github18 commented May 20, 2025 via email

@merks
Copy link
Contributor

merks commented May 20, 2025

FYI, the latest BIRT nightly build is using today's release of openpdf:

https://repo1.maven.org/maven2/com/github/librepdf/openpdf/2.0.4/

@vk-github18
Copy link

@hvbtup
I think, your proposal should work.
If you call LayoutProcessor.enable() as default, you are changing the processing of all reports,
this should work, but is a risk.
To be conservative, you can make the current processing the default, i.e.
call LayoutProcessor.enable() only if the option "complex-scripts" is set.
The options "kerning" and "ligatures" take only effect if Layoutprocessor is enabled and are otherwise ignored.

OpenPdf has a font cache, if you want to load a font more than once with different options, you can switch the cache off for this font.

In OpenType there are no symbolic fonts, these are legacy fonts, that should be ignored by LayoutProcessor.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Enhancement Small change to improve the current supported functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PDF, usage of "Webdings" font cause an exception (4.20 milestone)

4 participants