Hi,
I prefer something more simple because I don't want to keep a static map
forever. Like this:
Map<String,GlyphArraySplitter> map = new WeakHashMap<>();
and in applyGsubFeature:
GlyphArraySplitter glyphArraySplitter =
map.computeIfAbsent(scriptFeature.getName(), (__) -> new
GlyphArraySplitterRegexImpl(allGlyphIdsForSubstitution));
is this what you had in mind?
Tilman
On 2026/07/17 10:08:44 Olivier Bruchez wrote:
> Hi Tilman,
>
> Thanks for your reply and for opening an issue.
>
>
> > I assume what you did was to check the gsubWorkers map before calling
> > gsubWorkerFactory.getGsubWorker(), correct?
> >
>
> Not exactly. I should have included my patch/"hack" in the original message
> for more clarity. I'm basically simply adding a global cache for the
> GlyphArraySplitter, inside GsubWorkerForLatin. I left setFont and the
> gsubWorkers map alone. It is built in applyGsubFeature (once per showText),
> not in the constructor, so reusing the GsubWorker alone would not stop the
> rebuild and the performance hit. I memoized the GlyphArraySplitter per font
> and then per script feature (I think this is correct, but I'm not 100%
> sure).
>
> The whole change is one line in applyGsubFeature:
>
> - GlyphArraySplitter glyphArraySplitter = new
> GlyphArraySplitterRegexImpl(scriptFeature.getAllGlyphIdsForSubstitution());
> + GlyphArraySplitter glyphArraySplitter = splitterFor(scriptFeature);
>
> https://github.com/apache/pdfbox/blob/3.0.4/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorkerForLatin.java#L91-L92
>
> Plus a static cache keyed on the font's GsubData and a small helper:
>
> private static final Map<GsubData, Map<String, GlyphArraySplitter>>
> SPLITTER_CACHE = new WeakHashMap<>();
>
> private GlyphArraySplitter splitterFor(ScriptFeature scriptFeature)
> {
> synchronized (SPLITTER_CACHE)
> {
> Map<String, GlyphArraySplitter> perFont =
> SPLITTER_CACHE.get(gsubData);
> if (perFont == null)
> {
> perFont = new HashMap<>();
> SPLITTER_CACHE.put(gsubData, perFont);
> }
> GlyphArraySplitter splitter = perFont.get(scriptFeature.getName());
> if (splitter == null)
> {
> splitter = new
> GlyphArraySplitterRegexImpl(scriptFeature.getAllGlyphIdsForSubstitution());
> perFont.put(scriptFeature.getName(), splitter);
> }
> return splitter;
> }
> }
>
> This is a proof of concept, of course. This was just to convince myself
> that rebuilding GlyphArraySplitter multiple times was indeed the problem I
> was observing. On larger PDF files (dozens of pages), the speedup with the
> code above is really huge (3-4x on the total PDF generation times).
>
> Thanks,
> Olivier
>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]