diff --git a/src/core/evaluator.js b/src/core/evaluator.js index 748914b76..bddbe7615 100644 --- a/src/core/evaluator.js +++ b/src/core/evaluator.js @@ -2311,6 +2311,13 @@ class PartialEvaluator { return ret; } + function shouldAddWhitepsace() { + return ( + twoLastChars[twoLastCharsPos] !== " " && + twoLastChars[(twoLastCharsPos + 1) % 2] === " " + ); + } + function resetLastChars() { twoLastChars[0] = twoLastChars[1] = " "; twoLastCharsPos = 0; @@ -2360,6 +2367,23 @@ class PartialEvaluator { let textState; + function pushWhitespace({ + width = 0, + height = 0, + transform = textContentItem.prevTransform, + fontName = textContentItem.fontName, + }) { + textContent.items.push({ + str: " ", + dir: "ltr", + width, + height, + transform, + fontName, + hasEOL: false, + }); + } + function getCurrentTextTransform() { // 9.4.4 Text Space Details const font = textState.font; @@ -2631,7 +2655,16 @@ class PartialEvaluator { } if (advanceY <= textOrientation * textContentItem.trackingSpaceMin) { - textContentItem.height += advanceY; + if (shouldAddWhitepsace()) { + // The space is very thin, hence it deserves to have its own span in + // order to avoid too much shift between the canvas and the text + // layer. + resetLastChars(); + flushTextContentItem(); + pushWhitespace({ height: Math.abs(advanceY) }); + } else { + textContentItem.height += advanceY; + } } else if ( !addFakeSpaces( advanceY, @@ -2641,15 +2674,7 @@ class PartialEvaluator { ) { if (textContentItem.str.length === 0) { resetLastChars(); - textContent.items.push({ - str: " ", - dir: "ltr", - width: 0, - height: Math.abs(advanceY), - transform: textContentItem.prevTransform, - fontName: textContentItem.fontName, - hasEOL: false, - }); + pushWhitespace({ height: Math.abs(advanceY) }); } else { textContentItem.height += advanceY; } @@ -2696,21 +2721,22 @@ class PartialEvaluator { } if (advanceX <= textOrientation * textContentItem.trackingSpaceMin) { - textContentItem.width += advanceX; + if (shouldAddWhitepsace()) { + // The space is very thin, hence it deserves to have its own span in + // order to avoid too much shift between the canvas and the text + // layer. + resetLastChars(); + flushTextContentItem(); + pushWhitespace({ width: Math.abs(advanceX) }); + } else { + textContentItem.width += advanceX; + } } else if ( !addFakeSpaces(advanceX, textContentItem.prevTransform, textOrientation) ) { if (textContentItem.str.length === 0) { resetLastChars(); - textContent.items.push({ - str: " ", - dir: "ltr", - width: Math.abs(advanceX), - height: 0, - transform: textContentItem.prevTransform, - fontName: textContentItem.fontName, - hasEOL: false, - }); + pushWhitespace({ width: Math.abs(advanceX) }); } else { textContentItem.width += advanceX; } @@ -2872,16 +2898,11 @@ class PartialEvaluator { flushTextContentItem(); resetLastChars(); - textContent.items.push({ - str: " ", - // TODO: check if using the orientation from last chunk is - // better or not. - dir: "ltr", + pushWhitespace({ width: Math.abs(width), height: Math.abs(height), transform: transf || getCurrentTextTransform(), fontName, - hasEOL: false, }); return true; diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index 7756d4512..faace5c91 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -582,3 +582,4 @@ !issue16067.pdf !bug1820909.1.pdf !issue16221.pdf +!issue16224.pdf diff --git a/test/pdfs/issue16224.pdf b/test/pdfs/issue16224.pdf new file mode 100755 index 000000000..97a0794b8 Binary files /dev/null and b/test/pdfs/issue16224.pdf differ diff --git a/test/test_manifest.json b/test/test_manifest.json index ba6324c3c..12abd2808 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -7517,5 +7517,12 @@ "md5": "62d93c9b3aa4ba3af5446504632e78a5", "rounds": 1, "type": "text" + }, + { + "id": "issue16224-text", + "file": "pdfs/issue16224.pdf", + "md5": "1aa34fbb2154f9a647c7fa9e90db0eff", + "rounds": 1, + "type": "text" } ]