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 loaded:

multiFont.setBBoxArray(otf.getBoundingBoxes());

A `Rectangle` costs 32 bytes (with compressed oops) plus 4 bytes for the array
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-glyph
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):
| |live set|
|—|—|
|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) takes
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) — the values
are unchanged, only the storage.

Worth noting how little of this is usually read: for plain PDF output the array
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 — it is public API — 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)

Reply via email to