From 6e8cddcde1431a4b437f63fe76b8a45d1078cd3f Mon Sep 17 00:00:00 2001 From: Kakhnovich Raman Date: Fri, 6 Feb 2026 20:42:32 +0300 Subject: [PATCH 1/4] Fix glyph width calculation and Remove extra spaces --- .../gf/model/factory/chunks/ChunkParser.java | 41 +++++++++++++------ .../gf/model/factory/chunks/TextPieces.java | 8 ++++ 2 files changed, 36 insertions(+), 13 deletions(-) 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 53c6d4a9b..8ba1049c1 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 @@ -832,15 +832,28 @@ private List parseTextShowArgument(COSBase argument, StringBuilder unico double shift = - obj.getReal() / 1000 * graphicsState.getTextState().getTextFontSize() * graphicsState.getTextState().getHorizontalScaling(); - if (-obj.getReal() >= TextChunkUtils.TEXT_CHUNK_SPACE_RATIO && StaticStorages.getIsAddSpacesBetweenTextPieces()) { - textPieces.add(new TextPieces.TextPiece(" ", textPieces.getCurrentX(), - textPieces.getCurrentX() + shift)); - } else { - textPieces.shiftCurrentX(shift); - } + textPieces.shiftCurrentX(shift); } } } + double previousEnd = 0; + double currentStart = 0; + List spaces = new ArrayList<>(); + for (TextPieces.TextPiece textPiece: textPieces.getTextPieces()) { + if (textPiece.equals(textPieces.getTextPieces().first())) { + previousEnd = textPiece.getEndX(); + continue; + } + currentStart = textPiece.getStartX(); + if (currentStart - previousEnd > graphicsState.getTextState().getTextFontSize() * TextChunkUtils.TEXT_LINE_SPACE_RATIO) { + spaces.add(new TextPieces.TextPiece(" ", previousEnd, + currentStart)); + } + previousEnd = textPiece.getEndX(); + } + for (TextPieces.TextPiece space: spaces) { + textPieces.add(space); + } unicodeValue.append(textPieces.getValue()); if (!textPieces.isEmpty()) { textMatrix.concatenate(Matrix.getTranslateInstance(textPieces.getStartX(), 0)); @@ -867,17 +880,18 @@ private void parseString(COSString string, StringBuilder unicodeValue, TextPiece " in font" + graphicsState.getTextState().getTextFont().getName()); width = 0.0; } - double shift = (width * - graphicsState.getTextState().getTextFontSize() / 1000 + - graphicsState.getTextState().getCharacterSpacing() + (code == 32 ? + double shift = (graphicsState.getTextState().getCharacterSpacing() + (code == 32 ? graphicsState.getTextState().getWordSpacing() : 0)) * graphicsState.getTextState().getHorizontalScaling(); - String value = graphicsState.getTextState().getTextFont().toUnicode(code); + width = width * + graphicsState.getTextState().getTextFontSize() / 1000 * + graphicsState.getTextState().getHorizontalScaling(); + String value = graphicsState.getTextState().getTextFont().toUnicode(code); if (symbolEnds != null) { if (symbolEnds.isEmpty()) { - TextChunksHelper.updateSymbolEnds(symbolEnds, shift, 0, value != null ? value.length() : 0); + TextChunksHelper.updateSymbolEnds(symbolEnds, width, 0, value != null ? value.length() : 0); } else { - TextChunksHelper.updateSymbolEnds(symbolEnds, shift, symbolEnds.get(symbolEnds.size() - 1), + TextChunksHelper.updateSymbolEnds(symbolEnds, width, symbolEnds.get(symbolEnds.size() - 1), value != null ? value.length() : 0); } } @@ -892,7 +906,8 @@ private void parseString(COSString string, StringBuilder unicodeValue, TextPiece unicodeValue.append(result); } else { textPieces.add(new TextPieces.TextPiece(result, textPieces.getCurrentX(), - textPieces.getCurrentX() + shift)); + textPieces.getCurrentX() + width)); + textPieces.shiftCurrentX(shift); } } } catch (IOException e) { diff --git a/wcag-validation/src/main/java/org/verapdf/gf/model/factory/chunks/TextPieces.java b/wcag-validation/src/main/java/org/verapdf/gf/model/factory/chunks/TextPieces.java index fcd945bfd..879274d0a 100644 --- a/wcag-validation/src/main/java/org/verapdf/gf/model/factory/chunks/TextPieces.java +++ b/wcag-validation/src/main/java/org/verapdf/gf/model/factory/chunks/TextPieces.java @@ -35,6 +35,10 @@ public void add(TextPiece textPiece) { currentX = textPiece.endX; } + public SortedSet getTextPieces() { + return textPieces; + } + public String getValue() { StringBuilder unicodeValue = new StringBuilder(); for (TextPiece textPiece : textPieces) { @@ -91,6 +95,10 @@ public TextPiece(String value, double startX, double endX) { public double getEndX() { return endX; } + + public double getStartX() { + return startX; + } } public static class TextPieceComparator implements Comparator { From 002215e8007b224db0937ab7487ece336654336b Mon Sep 17 00:00:00 2001 From: Kakhnovich Raman Date: Mon, 9 Feb 2026 12:50:10 +0300 Subject: [PATCH 2/4] Create method addSpacesByShift --- .../gf/model/factory/chunks/ChunkParser.java | 27 +++++-------------- .../gf/model/factory/chunks/TextPieces.java | 22 +++++++++++++++ 2 files changed, 28 insertions(+), 21 deletions(-) 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 8ba1049c1..a6c6a459a 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 @@ -836,24 +836,9 @@ private List parseTextShowArgument(COSBase argument, StringBuilder unico } } } - double previousEnd = 0; - double currentStart = 0; - List spaces = new ArrayList<>(); - for (TextPieces.TextPiece textPiece: textPieces.getTextPieces()) { - if (textPiece.equals(textPieces.getTextPieces().first())) { - previousEnd = textPiece.getEndX(); - continue; - } - currentStart = textPiece.getStartX(); - if (currentStart - previousEnd > graphicsState.getTextState().getTextFontSize() * TextChunkUtils.TEXT_LINE_SPACE_RATIO) { - spaces.add(new TextPieces.TextPiece(" ", previousEnd, - currentStart)); - } - previousEnd = textPiece.getEndX(); - } - for (TextPieces.TextPiece space: spaces) { - textPieces.add(space); - } + double threshold = graphicsState.getTextState().getTextFontSize() * TextChunkUtils.TEXT_LINE_SPACE_RATIO; + textPieces.addSpacesByShift(threshold); + unicodeValue.append(textPieces.getValue()); if (!textPieces.isEmpty()) { textMatrix.concatenate(Matrix.getTranslateInstance(textPieces.getStartX(), 0)); @@ -889,9 +874,9 @@ private void parseString(COSString string, StringBuilder unicodeValue, TextPiece String value = graphicsState.getTextState().getTextFont().toUnicode(code); if (symbolEnds != null) { if (symbolEnds.isEmpty()) { - TextChunksHelper.updateSymbolEnds(symbolEnds, width, 0, value != null ? value.length() : 0); + TextChunksHelper.updateSymbolEnds(symbolEnds, shift + width, 0, value != null ? value.length() : 0); } else { - TextChunksHelper.updateSymbolEnds(symbolEnds, width, symbolEnds.get(symbolEnds.size() - 1), + TextChunksHelper.updateSymbolEnds(symbolEnds, shift + width, symbolEnds.get(symbolEnds.size() - 1), value != null ? value.length() : 0); } } @@ -906,7 +891,7 @@ private void parseString(COSString string, StringBuilder unicodeValue, TextPiece unicodeValue.append(result); } else { textPieces.add(new TextPieces.TextPiece(result, textPieces.getCurrentX(), - textPieces.getCurrentX() + width)); + textPieces.getCurrentX() + shift + width)); textPieces.shiftCurrentX(shift); } } diff --git a/wcag-validation/src/main/java/org/verapdf/gf/model/factory/chunks/TextPieces.java b/wcag-validation/src/main/java/org/verapdf/gf/model/factory/chunks/TextPieces.java index 879274d0a..4a833bebd 100644 --- a/wcag-validation/src/main/java/org/verapdf/gf/model/factory/chunks/TextPieces.java +++ b/wcag-validation/src/main/java/org/verapdf/gf/model/factory/chunks/TextPieces.java @@ -20,6 +20,8 @@ */ package org.verapdf.gf.model.factory.chunks; +import org.verapdf.wcag.algorithms.semanticalgorithms.utils.TextChunkUtils; + import java.util.*; /** @@ -81,6 +83,26 @@ public List getSymbolEnds() { return ends; } + public void addSpacesByShift(double threshold) { + List spaces = new ArrayList<>(); + Iterator it = textPieces.iterator(); + if (!it.hasNext()) { + return; + } + TextPiece prev = it.next(); + double previousEnd = prev.getEndX(); + + while (it.hasNext()) { + TextPiece piece = it.next(); + double currentStart = piece.getStartX(); + if (currentStart - previousEnd > threshold) { + spaces.add(new TextPieces.TextPiece(" ", previousEnd, currentStart)); + } + previousEnd = piece.getEndX(); + } + textPieces.addAll(spaces); + } + public static class TextPiece { private final String value; private final double startX; From 30b1bffe5d930b22afa8bd3e09e153c09ac083c0 Mon Sep 17 00:00:00 2001 From: Kakhnovich Raman Date: Mon, 9 Feb 2026 14:15:45 +0300 Subject: [PATCH 3/4] Update ChunkParser.java --- .../java/org/verapdf/gf/model/factory/chunks/ChunkParser.java | 2 +- 1 file changed, 1 insertion(+), 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 a6c6a459a..2c5d4b6da 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 @@ -891,7 +891,7 @@ private void parseString(COSString string, StringBuilder unicodeValue, TextPiece unicodeValue.append(result); } else { textPieces.add(new TextPieces.TextPiece(result, textPieces.getCurrentX(), - textPieces.getCurrentX() + shift + width)); + textPieces.getCurrentX() + width)); textPieces.shiftCurrentX(shift); } } From c6a0db9827f7d55c46e2d6d1b672ab550b6d866c Mon Sep 17 00:00:00 2001 From: Kakhnovich Raman Date: Mon, 9 Feb 2026 20:15:27 +0300 Subject: [PATCH 4/4] Some refactoring --- .../gf/model/factory/chunks/ChunkParser.java | 2 +- .../gf/model/factory/chunks/TextPieces.java | 18 ++++++------------ 2 files changed, 7 insertions(+), 13 deletions(-) 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 2c5d4b6da..1ab97758c 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 @@ -837,7 +837,7 @@ private List parseTextShowArgument(COSBase argument, StringBuilder unico } } double threshold = graphicsState.getTextState().getTextFontSize() * TextChunkUtils.TEXT_LINE_SPACE_RATIO; - textPieces.addSpacesByShift(threshold); + textPieces.addSpaces(threshold); unicodeValue.append(textPieces.getValue()); if (!textPieces.isEmpty()) { diff --git a/wcag-validation/src/main/java/org/verapdf/gf/model/factory/chunks/TextPieces.java b/wcag-validation/src/main/java/org/verapdf/gf/model/factory/chunks/TextPieces.java index 4a833bebd..73a8ed36b 100644 --- a/wcag-validation/src/main/java/org/verapdf/gf/model/factory/chunks/TextPieces.java +++ b/wcag-validation/src/main/java/org/verapdf/gf/model/factory/chunks/TextPieces.java @@ -20,8 +20,6 @@ */ package org.verapdf.gf.model.factory.chunks; -import org.verapdf.wcag.algorithms.semanticalgorithms.utils.TextChunkUtils; - import java.util.*; /** @@ -37,10 +35,6 @@ public void add(TextPiece textPiece) { currentX = textPiece.endX; } - public SortedSet getTextPieces() { - return textPieces; - } - public String getValue() { StringBuilder unicodeValue = new StringBuilder(); for (TextPiece textPiece : textPieces) { @@ -83,17 +77,17 @@ public List getSymbolEnds() { return ends; } - public void addSpacesByShift(double threshold) { + public void addSpaces(double threshold) { List spaces = new ArrayList<>(); - Iterator it = textPieces.iterator(); - if (!it.hasNext()) { + Iterator validation = textPieces.iterator(); + if (!validation.hasNext()) { return; } - TextPiece prev = it.next(); + TextPiece prev = validation.next(); double previousEnd = prev.getEndX(); - while (it.hasNext()) { - TextPiece piece = it.next(); + while (validation.hasNext()) { + TextPiece piece = validation.next(); double currentStart = piece.getStartX(); if (currentStart - previousEnd > threshold) { spaces.add(new TextPieces.TextPiece(" ", previousEnd, currentStart));