From 6fae194ab51afad3171f6d2cdecc59649d271bc6 Mon Sep 17 00:00:00 2001 From: Augusto Barbosa Villar Silva <64085472+augustovillar@users.noreply.github.com> Date: Tue, 16 Jun 2026 07:59:07 -0300 Subject: [PATCH] wcag/ChunkParser: scale Type3 glyph advances by /FontMatrix, not hardcoded 1/1000 PDFont.getWidth(code) returns the raw /Widths value in the font's glyph space. For Type3 fonts glyph space is defined by /FontMatrix, not 1/1000, so the hardcoded /1000 divisor produced advances off by (1000 * FontMatrix[0]) for any Type3 font whose FontMatrix != 1/1000 -- corrupting TextPiece end positions and text-chunk bounding boxes (dropped duplicate glyphs / spurious spaces downstream). Use the horizontal /FontMatrix component for a PDType3Font (null/length/zero guarded), 1/1000 otherwise. The TJ-array displacement path (obj.getReal()/1000, text-space thousandths and font-independent) is left unchanged. --- .../gf/model/factory/chunks/ChunkParser.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/wcag-validation/src/main/java/org/verapdf/gf/model/factory/chunks/ChunkParser.java b/wcag-validation/src/main/java/org/verapdf/gf/model/factory/chunks/ChunkParser.java index e98a4f492..6937452b7 100644 --- a/wcag-validation/src/main/java/org/verapdf/gf/model/factory/chunks/ChunkParser.java +++ b/wcag-validation/src/main/java/org/verapdf/gf/model/factory/chunks/ChunkParser.java @@ -38,6 +38,8 @@ import org.verapdf.pd.font.PDFontDescriptor; import org.verapdf.pd.images.PDXForm; import org.verapdf.pd.images.PDXObject; +import org.verapdf.pd.font.PDFont; +import org.verapdf.pd.font.type3.PDType3Font; import org.verapdf.pd.optionalcontent.PDOCMDDictionary; import org.verapdf.pd.optionalcontent.PDOptionalContentProperties; import org.verapdf.tools.StaticResources; @@ -856,6 +858,7 @@ private TextPieces parseTextShowArgument(COSBase argument) { private void parseString(COSString string, TextPieces textPieces) { byte[] bytes = string.get(); try (InputStream inputStream = new ByteArrayInputStream(bytes)) { + double glyphSpaceToTextSpace = getGlyphWidthToTextSpaceScale(graphicsState.getTextState().getTextFont()); while (inputStream.available() > 0) { int code = graphicsState.getTextState().getTextFont().readCode(inputStream); Double width = graphicsState.getTextState().getTextFont().getWidth(code); @@ -868,7 +871,7 @@ private void parseString(COSString string, TextPieces textPieces) { graphicsState.getTextState().getWordSpacing() : 0)) * graphicsState.getTextState().getHorizontalScaling(); width = width * - graphicsState.getTextState().getTextFontSize() / 1000 * + graphicsState.getTextState().getTextFontSize() * glyphSpaceToTextSpace * graphicsState.getTextState().getHorizontalScaling(); String value = graphicsState.getTextState().getTextFont().toUnicode(code); String result = value; @@ -887,6 +890,16 @@ private void parseString(COSString string, TextPieces textPieces) { } } + private static double getGlyphWidthToTextSpaceScale(PDFont font) { + if (font instanceof PDType3Font) { + double[] fontMatrix = ((PDType3Font) font).getFontMatrix(); + if (fontMatrix != null && fontMatrix.length >= 1 && fontMatrix[0] != 0.0) { + return fontMatrix[0]; + } + } + return 1.0 / 1000.0; + } + private TextChunk createTextChunk(List arguments, String operatorType, int operatorIndex) { org.verapdf.pd.font.PDFont font = graphicsState.getTextState().getTextFont(); COSBase argument = TextChunksHelper.getArgument(arguments, operatorType);