in src/core/evaluator.js [2672:2881]
function compareWithLastPosition(glyphWidth) {
const currentTransform = getCurrentTextTransform();
let posX = currentTransform[4];
let posY = currentTransform[5];
// Check if the glyph is in the viewbox.
if (textState.font?.vertical) {
if (
posX < viewBox[0] ||
posX > viewBox[2] ||
posY + glyphWidth < viewBox[1] ||
posY > viewBox[3]
) {
return false;
}
} else if (
posX + glyphWidth < viewBox[0] ||
posX > viewBox[2] ||
posY < viewBox[1] ||
posY > viewBox[3]
) {
return false;
}
if (!textState.font || !textContentItem.prevTransform) {
return true;
}
let lastPosX = textContentItem.prevTransform[4];
let lastPosY = textContentItem.prevTransform[5];
if (lastPosX === posX && lastPosY === posY) {
return true;
}
let rotate = -1;
// Take into account the rotation is the current transform.
if (
currentTransform[0] &&
currentTransform[1] === 0 &&
currentTransform[2] === 0
) {
rotate = currentTransform[0] > 0 ? 0 : 180;
} else if (
currentTransform[1] &&
currentTransform[0] === 0 &&
currentTransform[3] === 0
) {
rotate = currentTransform[1] > 0 ? 90 : 270;
}
switch (rotate) {
case 0:
break;
case 90:
[posX, posY] = [posY, posX];
[lastPosX, lastPosY] = [lastPosY, lastPosX];
break;
case 180:
[posX, posY, lastPosX, lastPosY] = [
-posX,
-posY,
-lastPosX,
-lastPosY,
];
break;
case 270:
[posX, posY] = [-posY, -posX];
[lastPosX, lastPosY] = [-lastPosY, -lastPosX];
break;
default:
// This is not a 0, 90, 180, 270 rotation so:
// - remove the scale factor from the matrix to get a rotation matrix
// - apply the inverse (which is the transposed) to the positions
// and we can then compare positions of the glyphes to detect
// a whitespace.
[posX, posY] = applyInverseRotation(posX, posY, currentTransform);
[lastPosX, lastPosY] = applyInverseRotation(
lastPosX,
lastPosY,
textContentItem.prevTransform
);
}
if (textState.font.vertical) {
const advanceY = (lastPosY - posY) / textContentItem.textAdvanceScale;
const advanceX = posX - lastPosX;
// When the total height of the current chunk is negative
// then we're writing from bottom to top.
const textOrientation = Math.sign(textContentItem.height);
if (advanceY < textOrientation * textContentItem.negativeSpaceMax) {
if (
Math.abs(advanceX) >
0.5 * textContentItem.width /* not the same column */
) {
appendEOL();
return true;
}
resetLastChars();
flushTextContentItem();
return true;
}
if (Math.abs(advanceX) > textContentItem.width) {
appendEOL();
return true;
}
if (advanceY <= textOrientation * textContentItem.notASpace) {
// The real spacing between 2 consecutive chars is thin enough to be
// considered a non-space.
resetLastChars();
}
if (advanceY <= textOrientation * textContentItem.trackingSpaceMin) {
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,
textContentItem.prevTransform,
textOrientation
)
) {
if (textContentItem.str.length === 0) {
resetLastChars();
pushWhitespace({ height: Math.abs(advanceY) });
} else {
textContentItem.height += advanceY;
}
}
if (Math.abs(advanceX) > textContentItem.width * VERTICAL_SHIFT_RATIO) {
flushTextContentItem();
}
return true;
}
const advanceX = (posX - lastPosX) / textContentItem.textAdvanceScale;
const advanceY = posY - lastPosY;
// When the total width of the current chunk is negative
// then we're writing from right to left.
const textOrientation = Math.sign(textContentItem.width);
if (advanceX < textOrientation * textContentItem.negativeSpaceMax) {
if (
Math.abs(advanceY) >
0.5 * textContentItem.height /* not the same line */
) {
appendEOL();
return true;
}
// We're moving back so in case the last char was a whitespace
// we cancel it: it doesn't make sense to insert it.
resetLastChars();
flushTextContentItem();
return true;
}
if (Math.abs(advanceY) > textContentItem.height) {
appendEOL();
return true;
}
if (advanceX <= textOrientation * textContentItem.notASpace) {
// The real spacing between 2 consecutive chars is thin enough to be
// considered a non-space.
resetLastChars();
}
if (advanceX <= textOrientation * textContentItem.trackingSpaceMin) {
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();
pushWhitespace({ width: Math.abs(advanceX) });
} else {
textContentItem.width += advanceX;
}
}
if (Math.abs(advanceY) > textContentItem.height * VERTICAL_SHIFT_RATIO) {
flushTextContentItem();
}
return true;
}