Skip to content

Commit c04340b

Browse files
authored
Merge pull request #928 from erikbra/codex/document-glyph-layout-backends
Document glyph layout backend mapping
2 parents d6b3e3f + 3ebb3ee commit c04340b

2 files changed

Lines changed: 115 additions & 1 deletion

File tree

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,9 @@ small backend/provider contracts so the mechanical Java port stays portable.
5757
registers the supported SkiaSharp renderer plus ImageMagick image/color
5858
providers.
5959
- `PdfBox.Net.SkiaSharp` is the complete page rendering backend if you only
60-
want the renderer without the heavier ImageMagick providers.
60+
want the renderer without the heavier ImageMagick providers. It also
61+
provides the optional SkiaSharp/HarfBuzz glyph-layout backend for shaping
62+
Unicode text written into new PDF content streams and form appearances.
6163
- `PdfBox.Net.ImageMagick` provides JPX/JPEG2000, CMYK JPEG, TIFF import, and
6264
ICC color conversion support.
6365
- `PdfBox.Net.Cryptography` provides BouncyCastle-backed public-key encryption
@@ -69,6 +71,11 @@ small backend/provider contracts so the mechanical Java port stays portable.
6971
See [`reports/printing-backend-policy-2026-06-28.md`](reports/printing-backend-policy-2026-06-28.md)
7072
for the printing support matrix and platform limitations.
7173

74+
See [`docs/glyph-layout-backends.md`](docs/glyph-layout-backends.md) for the
75+
mapping between Apache PDFBox's new AWT/FOP glyph-layout modules and the
76+
SkiaSharp/HarfBuzz implementation in PDFBox.Net, including branch support and
77+
the `release/3.0` backport scope.
78+
7279
## Build and test
7380

7481
```sh

docs/glyph-layout-backends.md

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# Glyph Layout Backends
2+
3+
Status: 2026-08-01
4+
5+
## Upstream PDFBox functionality
6+
7+
Apache PDFBox added an opt-in glyph-layout pipeline under PDFBOX-4951 in July
8+
2026. The work is present on both the Apache `trunk` and `3.0` branches and is
9+
currently part of their `4.0.0-SNAPSHOT` and `3.0.9-SNAPSHOT` development
10+
lines.
11+
12+
The upstream work has three parts:
13+
14+
1. Core interfaces and content-stream integration in the `pdfbox` module.
15+
`PDPageContentStream`, appearance streams, and AcroForm appearance
16+
generation can delegate Unicode text to a registered glyph-layout
17+
processor.
18+
2. The optional `pdfbox-layout-awt` module, which shapes text using Java AWT
19+
font APIs.
20+
3. The optional `pdfbox-layout-fop` module, which shapes text using Apache FOP
21+
2.11 font classes.
22+
23+
The FOP module does not add XSL-FO document layout, paragraph flow, line
24+
breaking, or page composition to PDFBox. It uses FOP's font machinery to map a
25+
Unicode string to positioned glyph IDs before PDFBox writes that string into a
26+
PDF content stream. This supports capabilities such as OpenType substitutions
27+
and positioning, ligatures, kerning, combining marks, complex scripts,
28+
bidirectional text, and supplementary Unicode-plane characters. The same
29+
processor can be propagated into AcroForm appearance generation.
30+
31+
The upstream FOP implementation is opt-in. Existing `showText` behavior is
32+
used when no processor is registered or when the processor does not support
33+
the selected font. It currently targets Type 0 fonts backed by TrueType
34+
outlines; CFF-based OpenType fonts are outside its supported path.
35+
36+
References:
37+
38+
- [PDFBOX-4951](https://issues.apache.org/jira/browse/PDFBOX-4951)
39+
- [Apache PDFBox `pdfbox-layout-fop` module](https://github.com/apache/pdfbox/tree/3.0/pdfbox-layout-fop)
40+
- [Commit adding the FOP backend to the Apache 3.0 branch](https://github.com/apache/pdfbox/commit/bb497fe1543c0747f92b4e613788e3297c29c3a7)
41+
42+
## PDFBox.Net mapping
43+
44+
Apache FOP is a Java library, so `pdfbox-layout-fop` is intentionally not
45+
ported as a literal .NET module and remains an explicit exclusion in the
46+
source-parity inventory. This is a runtime-specific adaptation, not a decision
47+
to omit glyph shaping.
48+
49+
The .NET functional counterpart is `SkiaGlyphLayoutProcessor` in the optional
50+
`PdfBox.Net.SkiaSharp` package. It uses HarfBuzzSharp for shaping and SkiaSharp
51+
for font loading while implementing the upstream core
52+
`GlyphLayoutProcessorInterface`. It:
53+
54+
- registers the same TrueType font with PDFBox.Net and HarfBuzz;
55+
- resolves bidirectional text into visual runs;
56+
- emits shaped glyph IDs instead of raw Unicode values;
57+
- writes kerning, advances, and horizontal/vertical offsets as PDF text
58+
positioning operations; and
59+
- keeps SkiaSharp and HarfBuzzSharp types out of the core `PdfBox.Net` API.
60+
61+
This backend shapes Unicode text while creating new content streams and form
62+
appearances. It does not reshape glyph codes already present in an existing PDF
63+
during rendering. Existing PDF content already records the selected glyphs and
64+
positions; reshaping it would risk changing the author's content.
65+
66+
## Branch support matrix
67+
68+
| Capability | `main` | `release/3.0` |
69+
|---|---:|---:|
70+
| Core glyph-layout interfaces and content-stream hooks | Yes | Yes |
71+
| Upstream-compatible AWT-facing API adaptation | Yes | Yes |
72+
| SkiaSharp/HarfBuzz shaping backend | Yes | Not yet |
73+
| Literal Apache FOP runtime dependency | No, intentionally replaced | No, intentionally replaced |
74+
75+
The AWT-facing adaptation on `release/3.0` currently provides the compatible
76+
registration/content-stream surface but only a conservative Identity-H glyph
77+
code path. Full complex-script shaping on that branch requires backporting the
78+
existing SkiaSharp/HarfBuzz backend.
79+
80+
## Backport scope for `release/3.0`
81+
82+
The backport does not require designing a new shaping engine. The core
83+
interfaces it consumes are already present on `release/3.0`. The remaining
84+
work is bounded to:
85+
86+
1. Backport `SkiaGlyphLayoutProcessor` and `BidiTextRunResolver`.
87+
2. Add the HarfBuzzSharp native-asset and `Unicode.Bidi` package references to
88+
`PdfBox.Net.SkiaSharp`.
89+
3. Backport the generated-content tests for Latin kerning, Bengali
90+
substitution, Thai mark positioning, missing glyphs, and representative
91+
LTR/RTL visual runs.
92+
4. Run the normal solution, package, API-surface, and Java runtime-parity gates
93+
on `release/3.0`, including all supported native runtime packages.
94+
95+
A disposable backport rehearsal against `release/3.0` applied the production
96+
and test changes without any source-code conflicts. The only conflict was in a
97+
generated upstream-sync state report, which should not be copied from `main`.
98+
The backported project restored and built successfully, and all six focused
99+
`SkiaGlyphLayoutProcessorTest` cases passed on the first run.
100+
101+
Based on that rehearsal, the expected effort is approximately four to eight
102+
focused engineering hours, normally one calendar day including the full test,
103+
package, API-surface, runtime-parity, and CI gates. The main remaining risks are
104+
native-package packaging across Linux, macOS, and Windows, and keeping
105+
`Unicode.Bidi` behavior aligned with the Java `java.text.Bidi` fixtures. The
106+
shaping implementation itself is already exercised on `main` and does not
107+
appear to require branch-specific adaptation.

0 commit comments

Comments
 (0)