Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 39 additions & 8 deletions base/core/evaluator.js
Original file line number Diff line number Diff line change
Expand Up @@ -895,21 +895,52 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
args[3], args[4], args[5]);
break;
case 'TJ':
// PDF 32000-1 §9.4.3: each numeric element is subtracted from the
// current horizontal coordinate (thousandths of a text-space unit).
// Positive number → cursor moves LEFT, negative → cursor moves RIGHT.
// Some generators lay glyphs out right-to-left using large positive
// jumps between strings; track each string's x position in text
// space and emit them in left-to-right reading order.
var items = args[0];
var tjX = 0;
var pieces = [];
for (var j = 0, jj = items.length; j < jj; j++) {
if (typeof items[j] === 'string') {
chunk += fontCharsToUnicode(items[j], font);
} else if (items[j] < 0 && font.spaceWidth > 0) {
var fakeSpaces = -items[j] / font.spaceWidth;
if (fakeSpaces > MULTI_SPACE_FACTOR) {
fakeSpaces = Math.round(fakeSpaces);
while (fakeSpaces--) {
var pieceText = fontCharsToUnicode(items[j], font);
var pieceWidth = 0;
var pieceGlyphs = font.charsToGlyphs(items[j]);
for (var k = 0, kk = pieceGlyphs.length; k < kk; k++) {
var pg = pieceGlyphs[k];
pieceWidth += (pg && pg.width) || font.defaultWidth || 0;
}
pieces.push({ text: pieceText, x: tjX, width: pieceWidth });
tjX += pieceWidth;
} else {
tjX -= items[j];
}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ln 912-919: Summing glyph widths alone ignores character and word spacing and can cause regression. Example: Courier, 10pt, 10 Tc [(A) 700 (B)] TJ. :

Tc adds 10 units of character spacing. After drawing A, the actual cursor advances 6 + 10 = 16 units. The 700 adjustment then moves it back 7 units, so B starts at x = 9, to the right of A.

With this change, it counts only the glyph width: 6 − 7 = −1, results in changing extraction from AB to BA.

}
// Stable sort by x so reverse-laid runs come out in reading order
// while same-x or already-forward pieces keep their original order.
pieces.sort(function (a, b) { return a.x - b.x; });
var prevEnd = null;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spatially reordering RTL test should be avoided before bidi processing. For a reverse-positioned Hebrew run, this sort puts the characters into left-to-right visual order, but the subsequent PDFJS.bidi(chunk, -1, font.vertical) reorders them again.

spatial reconstruction should be made direction-aware and coordinate with the existing bidi conversion.

for (var p = 0, pp = pieces.length; p < pp; p++) {
var piece = pieces[p];
if (prevEnd !== null && font.spaceWidth > 0) {
var gap = piece.x - prevEnd;
if (gap > 0) {
var fakeSpaces = gap / font.spaceWidth;
if (fakeSpaces > MULTI_SPACE_FACTOR) {
fakeSpaces = Math.round(fakeSpaces);
while (fakeSpaces--) {
chunk += ' ';
}
} else if (fakeSpaces > SPACE_FACTOR) {
chunk += ' ';
}
} else if (fakeSpaces > SPACE_FACTOR) {
chunk += ' ';
}
}
chunk += piece.text;
prevEnd = piece.x + piece.width;
}
break;
case 'Tj':
Expand Down