Author: tilman
Date: Sat Sep 5 16:27:11 2026
New Revision: 1937910
Log:
PDFBOX-5960: when the descriptor has contradictory flags and the Encoding
dictionary has a recognized /BaseEncoding, resolve by glyph name first, falling
back to the existing code-based cmap logic only if that yields GID 0, by Valery
Bokov; closes #523
Modified:
pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java
Modified:
pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java
==============================================================================
---
pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java
Sat Sep 5 16:27:07 2026 (r1937909)
+++
pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java
Sat Sep 5 16:27:11 2026 (r1937910)
@@ -40,6 +40,7 @@ import org.apache.pdfbox.pdmodel.PDDocum
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.common.PDStream;
import org.apache.pdfbox.pdmodel.font.encoding.BuiltInEncoding;
+import org.apache.pdfbox.pdmodel.font.encoding.DictionaryEncoding;
import org.apache.pdfbox.pdmodel.font.encoding.Encoding;
import org.apache.pdfbox.pdmodel.font.encoding.GlyphList;
import org.apache.pdfbox.pdmodel.font.encoding.MacOSRomanEncoding;
@@ -572,6 +573,20 @@ public class PDTrueTypeFont extends PDSi
}
else // symbolic
{
+ // PDFBOX-5960: some fonts have both the Symbolic and NonSymbolic
flags set in their
+ // FontDescriptor, which is self-contradictory. When such a font
also has an Encoding
+ // dictionary with a recognised /BaseEncoding, resolve the glyph
by name first (as if
+ // the font were non-symbolic), and fall back to the code-based
cmap lookup below only
+ // if that fails.
+ if (hasContradictorySymbolicFlags() && encoding instanceof
DictionaryEncoding
+ && isRecognizedBaseEncoding(((DictionaryEncoding)
encoding).getBaseEncoding()))
+ {
+ String name = encoding.getName(code);
+ if (name != null && !".notdef".equals(name))
+ {
+ gid = codeToGIDByName(name);
+ }
+ }
// PDFBOX-4755 / PDF.js #5501
// PDFBOX-3965: fallback for font has that the symbol flag but
isn't
if (gid == 0 && cmapWinUnicode != null)
@@ -597,7 +612,7 @@ public class PDTrueTypeFont extends PDSi
}
// (3, 0) - (Windows, Symbol)
- if (cmapWinSymbol != null)
+ if (gid == 0 && cmapWinSymbol != null)
{
gid = cmapWinSymbol.getGlyphId(code);
if (code >= 0 && code <= 0xFF)
@@ -671,6 +686,29 @@ public class PDTrueTypeFont extends PDSi
}
/**
+ * PDFBOX-5960: some malformed fonts have both the Symbolic and
NonSymbolic flags set in
+ * their FontDescriptor, which is self-contradictory and means the
Symbolic flag can't be
+ * trusted on its own.
+ *
+ * @return true if the font descriptor has both the Symbolic and
NonSymbolic flags set
+ */
+ private boolean hasContradictorySymbolicFlags()
+ {
+ PDFontDescriptor fd = getFontDescriptor();
+ return fd != null && fd.isSymbolic() && fd.isNonSymbolic();
+ }
+
+ /**
+ * @return true if the given encoding is one of the standard named
encodings, i.e. it came
+ * from a recognized /BaseEncoding entry rather than being synthesized as
a fallback.
+ */
+ private static boolean isRecognizedBaseEncoding(Encoding encoding)
+ {
+ return encoding instanceof StandardEncoding || encoding instanceof
WinAnsiEncoding
+ || encoding instanceof MacRomanEncoding;
+ }
+
+ /**
* extract all useful "cmap" subtables.
*/
private void extractCmapTable() throws IOException