GH-494 truetype font hinting tie in - #534
Open
pcorless wants to merge 8 commits into
Open
Conversation
pcorless
commented
Aug 31, 2026
Owner
- hook for a bunch of work gone into fontbox for supporting composite fonts hinting instructions.
Two conflicts, both from main reworking the same font paint paths this branch restructured for hinting. ZSimpleFont.getOutline: kept both sides — main's isSubstitutedNotdef guard plus this branch's unhinted cached outline (clipping/selection geometry must not be grid-fit). ZFontType2: this branch removed the paint() override in favour of the shared ZSimpleFont.paint(), so main's additions to it were carried across rather than kept in place — the isSubstitutedNotdef guard is already in the inherited paint(), and the null-safe trueTypeFont.getGlyph() check moved into getGlphyShape(). Main also widened that catch to RuntimeException for fontbox throwing on OTF/CFF fonts with no glyf table; the shared paint() already catches RuntimeException, and GlyphCache swallows IOException internally, so that path is preserved. Not compile-verified: this branch needs the fontbox 4.0.0-SNAPSHOT fork that provides getHintedPath(gid, ppem), which is not installed in the local repository. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WDXkgMFf1n9eaXi5q29exm
…box.ttf.hinting system property from FontBox fork
GH-535 landed the unhinted half of this branch's glyph cache on main, so the three cache files conflicted with the versions they were extracted from. Resolved by taking main as the base and re-applying the hinting layer on top: - GlyphCache keeps main's PDFBox attribution block and its FINE-level, RuntimeException-catching handler, with the (code, ppem) hinted map and the getPathForCharacterCode(code, ppem) overload added back. The grid-fit failure path picks up the same treatment - FINE rather than WARNING, and RuntimeException caught alongside IOException - since a failed grid-fit just falls back to a correct unhinted outline. - ZSimpleFont keeps resolveGlyphShape/getUnitsPerEm/getHintedGlphyShape/ hintingPpem and main's comment wording. - ZFontType2 keeps main's getGlphyShape() plus this branch's getUnitsPerEm() and getHintedGlphyShape() overrides. Not verified by a build: fontbox 4.0.0-SNAPSHOT is not installed locally. Compiling against stock 3.0.6 leaves exactly three unresolved symbols, all fork-only (isHintingEnabled x2, getHintedPath x1), and nothing structural. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Cw2YK2dUcKQuFdzJ26gwQV
Five glyph-ish names had accumulated in ZSimpleFont - getGlphyShape,
getHintedGlphyShape, resolveGlyphShape, hintingPpem, getGlyphCache - and three
of them said "hint". getHintedGlphyShape in particular read as getGlphyShape
plus a word, though one is the public FontFile API and the other a protected
hook, and GlyphCache had a getPathForCharacterCode overload whose two arities
consulted different maps and silently fell through to one another.
"Hinting" now names only the feature that is switched on and off - FontBox's
isHintingEnabled(), the -Dorg.apache.fontbox.ttf.hinting flag, the bytecode a
font does or does not carry. The code paths are named for what they do:
getHintedGlphyShape(char, int) -> getGridFitGlyphShape(char, int)
hintingPpem(AffineTransform) -> gridFitPpem(AffineTransform)
GlyphCache.getPathForCharacterCode(char, int)
-> getGridFitPathForCharacterCode(char, int)
GlyphCache.hintedCache -> gridFitCache
and "unhinted outline" becomes "plain outline" throughout, since it is just the
outline the font ships, not a variant. Javadoc and comments follow. The new
names spell Glyph correctly; getGlphyShape keeps its typo as it is existing
FontFile API, as does the unrelated FontFile.isHinted().
Rename and comments only, no behaviour change.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cw2YK2dUcKQuFdzJ26gwQV
Every core test failed under maven with 95 errors, all rooted in
NoClassDefFoundError: org/apache/logging/log4j/LogManager
at org.apache.fontbox.ttf.TrueTypeFont.<clinit>
The trailing "Could not initialize class org.apache.fontbox.cff.CFFParser /
PfbParser" errors are the same fault seen later: a class whose static
initialiser throws stays permanently unusable, so the first failure poisons
every font parser after it.
module-info declared `requires org.apache.commons.logging`, which was right for
fontbox 3.x. The 4.x line switched to log4j-api under PDFBOX-5695 (commit
1f95a1f876 on pdfbox trunk, never backported to the 3.0 branch), so the module
could not read the log4j classes it now needs. log4j-api is already on the
compile classpath transitively via fontbox; only the module graph was missing it.
Gradle never caught this because it compiles module-info but runs tests on the
plain classpath, where JPMS readability does not apply. Maven's surefire puts a
module with a module-info on the module path, where it does. `mvn install` is
the stricter check of the two on this repo.
`mvn install` with tests now passes the full reactor, core-awt 256 tests / 0
failures / 0 errors.
Branch-local, like the FONT_BOX_VERSION bump: on main with stock fontbox 3.0.6
log4j-api is not on the module path at all, so this requires clause would fail
to resolve. Must not be merged back without the fork.
Note that `requires org.apache.commons.logging` is now dead here - nothing in
core or viewer imports it, that clause was its only reference. Left in place
since the pom still declares commons-logging so it resolves harmlessly; removing
it and the pom dependency is a separate cleanup.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cw2YK2dUcKQuFdzJ26gwQV
`./gradlew :viewer:viewer-awt:run -Dorg.apache.fontbox.ttf.hinting=true` started the viewer with hinting off and no warning. The run task forks a JVM that does not inherit the daemon's system properties, and forwardProperties() bridges only an allowlist of prefixes - which did not include the fontbox one, so the flag was silently dropped. Added 'org.apache.fontbox.' to the allowlist. The whole prefix rather than the single hinting property, matching how the other five entries are written, so any future fontbox flag is covered too. Comment column realigned to the new longest prefix. ./gradle.sh with the same flag already worked - it re-exports -D args as JAVA_TOOL_OPTIONS, which every forked JVM honours regardless of the allowlist - and remains the fallback for anything not listed here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Cw2YK2dUcKQuFdzJ26gwQV
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.