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]

Reply via email to