[jira] [Created] (FOP-3330) MultiByteFont retains a java.awt.Rectangle per glyph for bounding boxes
"Jason Harrop (Jira)" <[email protected]> Thu, 30 Jul 2026 21:33:00 +0000 (UTC)
| Newsgroups | gmane.text.xml.fop.devel |
|---|---|
| Message-ID | <[email protected]> |
Jason Harrop created FOP-3330:
---------------------------------
Summary: MultiByteFont retains a java.awt.Rectangle per glyph =
for bounding boxes
Key: FOP-3330
URL: https://issues.apache.org/jira/browse/FOP-3330
Project: FOP
Issue Type: Improvement
Components: font/unqualified
Affects Versions: 2.11
Reporter: Jason Harrop
Attachments: fop-packed-bboxes.patch
`MultiByteFont` holds its glyph bounding boxes as `Rectangle[]`, one object=
per
glyph, populated eagerly by `OFFontLoader` for every CID font that is loade=
d:
multiFont.setBBoxArray(otf.getBoundingBoxes());
A `Rectangle` costs 32 bytes (with compressed oops) plus 4 bytes for the ar=
ray
slot, to carry four ints that need 16. Fonts are commonly 5,000+ glyphs, so=
this
is ~180 KB per loaded font, retained for as long as the font is; a 65,000-g=
lyph
CJK font costs ~2.3 MB.
Measured in a long-lived JVM that loads the metrics of every installed font
(1246 fonts, 6.9M glyphs, via a full-GC live-object histogram):
|=C2=A0|live set|
|=E2=80=94|=E2=80=94|
|6,944,575 java.awt.Rectangle|222 MB|
|1,246 Rectangle[]|28 MB|
|everything else in the loaded fonts|~40 MB|
Packing the same values into an `int[]` (x, y, width, height per glyph) tak=
es
that 250 MB to 111 MB, and 6.1M live objects to 594k.
Nothing reads the stored `Rectangle`s directly: `getBoundingBox(glyphIndex,=
size)`
already allocates a fresh, scaled `Rectangle` for its caller, and it is the=
only
reader of the field. So the change is invisible to callers
(`FOPGVTGlyphVector`, `AbstractIFPainter`, the Java2D font mappers) =E2=80=
=94 the values
are unchanged, only the storage.
Worth noting how little of this is usually read: for plain PDF output the a=
rray
is written at load and never touched.
*{*}Proposed patch{*}* (attached / PR):
1. `MultiByteFont.boundingBoxes` becomes `int[]`, packed 4 ints per glyph;
`getBoundingBox(int, int)` reads it directly.
2. `setBBoxArray(Rectangle[])` is retained =E2=80=94 it is public API =E2=
=80=94 and converts;
a `setBBoxArray(int[])` overload is added.
3. `OpenFont.getBoundingBoxesPacked()` returns the packed form, so
`OFFontLoader` no longer builds a `Rectangle[]` at load time either.
`getBoundingBoxes()` stays, still used by `copyGlyphMetricsSingleByte`.
Same arithmetic in both paths, so the values are bit-identical.
If a further reduction is wanted, the values are in 1/1000 em after
`convertTTFUnit2PDFUnit`, so a `short[]` would halve it again (55 MB in the
measurement above)...
--
This message was sent by Atlassian Jira
(v8.20.10#820010)