: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
operatorList.addOp(fn, args);
closePendingRestoreOPS();
if (reason instanceof AbortException) {
if (this.options.ignoreErrors) {
warn(`getOperatorList - ignoring errors during "${task.name}" ` + `task: "${reason}".`);
closePendingRestoreOPS();
includeMarkedContent = false,
markedContentData = null,
disableNormalization = false,
resources ||= Dict.empty;
stateManager ||= new StateManager(new TextState());
if (includeMarkedContent) {
styles: Object.create(null),
const textContentItem = {
trackingSpaceMin: Infinity,
negativeSpaceMax: -Infinity,
const twoLastChars = [" ", " "];
function saveLastChar(char) {
const nextPos = (twoLastCharsPos + 1) % 2;
const ret = twoLastChars[twoLastCharsPos] !== " " && twoLastChars[nextPos] === " ";
twoLastChars[twoLastCharsPos] = char;
twoLastCharsPos = nextPos;
return !keepWhiteSpace && ret;
function shouldAddWhitepsace() {
return !keepWhiteSpace && twoLastChars[twoLastCharsPos] !== " " && twoLastChars[(twoLastCharsPos + 1) % 2] === " ";
function resetLastChars() {
twoLastChars[0] = twoLastChars[1] = " ";
const TRACKING_SPACE_FACTOR = 0.102;
const NOT_A_SPACE_FACTOR = 0.03;
const NEGATIVE_SPACE_FACTOR = -0.2;
const SPACE_IN_FLOW_MIN_FACTOR = 0.102;
const SPACE_IN_FLOW_MAX_FACTOR = 0.6;
const VERTICAL_SHIFT_RATIO = 0.25;
const showSpacedTextBuffer = [];
const emptyXObjectCache = new LocalImageCache();
const emptyGStateCache = new LocalGStateCache();
const preprocessor = new EvaluatorPreprocessor(stream, xref, stateManager);
function pushWhitespace({
transform = textContentItem.prevTransform,
fontName = textContentItem.fontName
function getCurrentTextTransform() {
const font = textState.font;
const tsm = [textState.fontSize * textState.textHScale, 0, 0, textState.fontSize, 0, textState.textRise];
if (font.isType3Font && (textState.fontSize <= 1 || font.isCharBBox) && !isArrayEqual(textState.fontMatrix, FONT_IDENTITY_MATRIX)) {
const glyphHeight = font.bbox[3] - font.bbox[1];
tsm[3] *= glyphHeight * textState.fontMatrix[3];
return Util.transform(textState.ctm, Util.transform(textState.textMatrix, tsm));
function ensureTextContentItem() {
if (textContentItem.initialized) {
if (!seenStyles.has(loadedName)) {
seenStyles.add(loadedName);
textContent.styles[loadedName] = {
fontFamily: font.fallbackName,
if (self.options.fontExtraProperties && font.systemFontInfo) {
const style = textContent.styles[loadedName];
style.fontSubstitution = font.systemFontInfo.css;
style.fontSubstitutionLoadedName = font.systemFontInfo.loadedName;
textContentItem.fontName = loadedName;
const trm = textContentItem.transform = getCurrentTextTransform();
textContentItem.width = textContentItem.totalWidth = 0;
textContentItem.height = textContentItem.totalHeight = Math.hypot(trm[2], trm[3]);
textContentItem.vertical = false;
textContentItem.width = textContentItem.totalWidth = Math.hypot(trm[0], trm[1]);
textContentItem.height = textContentItem.totalHeight = 0;
textContentItem.vertical = true;
const scaleLineX = Math.hypot(textState.textLineMatrix[0], textState.textLineMatrix[1]);
const scaleCtmX = Math.hypot(textState.ctm[0], textState.ctm[1]);
textContentItem.textAdvanceScale = scaleCtmX * scaleLineX;
textContentItem.trackingSpaceMin = fontSize * TRACKING_SPACE_FACTOR;
textContentItem.notASpace = fontSize * NOT_A_SPACE_FACTOR;
textContentItem.negativeSpaceMax = fontSize * NEGATIVE_SPACE_FACTOR;
textContentItem.spaceInFlowMin = fontSize * SPACE_IN_FLOW_MIN_FACTOR;
textContentItem.spaceInFlowMax = fontSize * SPACE_IN_FLOW_MAX_FACTOR;
textContentItem.hasEOL = false;
textContentItem.initialized = true;
function updateAdvanceScale() {
if (!textContentItem.initialized) {
const scaleLineX = Math.hypot(textState.textLineMatrix[0], textState.textLineMatrix[1]);
const scaleCtmX = Math.hypot(textState.ctm[0], textState.ctm[1]);
const scaleFactor = scaleCtmX * scaleLineX;
if (scaleFactor === textContentItem.textAdvanceScale) {
if (!textContentItem.vertical) {
textContentItem.totalWidth += textContentItem.width * textContentItem.textAdvanceScale;
textContentItem.width = 0;
textContentItem.totalHeight += textContentItem.height * textContentItem.textAdvanceScale;
textContentItem.height = 0;
textContentItem.textAdvanceScale = scaleFactor;
function runBidiTransform(textChunk) {
let text = textChunk.str.join("");
if (!disableNormalization) {
text = normalizeUnicode(text);
const bidiResult = bidi(text, -1, textChunk.vertical);
width: Math.abs(textChunk.totalWidth),
height: Math.abs(textChunk.totalHeight),
transform: textChunk.transform,
fontName: textChunk.fontName,
async function handleSetFont(fontName, fontRef) {
const translated = await self.loadFont(fontName, fontRef, resources);
if (translated.font.isType3Font) {
await translated.loadType3Data(self, resources, task);
textState.loadedName = translated.loadedName;
textState.font = translated.font;
textState.fontMatrix = translated.font.fontMatrix || FONT_IDENTITY_MATRIX;
function applyInverseRotation(x, y, matrix) {
const scale = Math.hypot(matrix[0], matrix[1]);
return [(matrix[0] * x + matrix[1] * y) / scale, (matrix[2] * x + matrix[3] * y) / scale];
function compareWithLastPosition(glyphWidth) {
const currentTransform = getCurrentTextTransform();
let posX = currentTransform[4];
let posY = currentTransform[5];
if (textState.font?.vertical) {
if (posX < viewBox[0] || posX > viewBox[2] || posY + glyphWidth < viewBox[1] || posY > viewBox[3]) {
} else if (posX + glyphWidth < viewBox[0] || posX > viewBox[2] || posY < viewBox[1] || posY > viewBox[3]) {
if (!textState.font || !textContentItem.prevTransform) {
let lastPosX = textContentItem.prevTransform[4];
let lastPosY = textContentItem.prevTransform[5];
if (lastPosX === posX && lastPosY === posY) {
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;
[posX, posY] = [posY, posX];
[lastPosX, lastPosY] = [lastPosY, lastPosX];
[posX, posY, lastPosX, lastPosY] = [-posX, -posY, -lastPosX, -lastPosY];
[posX, posY] = [-posY, -posX];
[lastPosX, lastPosY] = [-lastPosY, -lastPosX];
[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;
const textOrientation = Math.sign(textContentItem.height);
if (advanceY < textOrientation * textContentItem.negativeSpaceMax) {
if (Math.abs(advanceX) > 0.5 * textContentItem.width) {
if (Math.abs(advanceX) > textContentItem.width) {
if (advanceY <= textOrientation * textContentItem.notASpace) {
if (advanceY <= textOrientation * textContentItem.trackingSpaceMin) {
if (shouldAddWhitepsace()) {
height: Math.abs(advanceY)
textContentItem.height += advanceY;
} else if (!addFakeSpaces(advanceY, textContentItem.prevTransform, textOrientation)) {
if (textContentItem.str.length === 0) {
height: Math.abs(advanceY)
textContentItem.height += advanceY;
if (Math.abs(advanceX) > textContentItem.width * VERTICAL_SHIFT_RATIO) {
const advanceX = (posX - lastPosX) / textContentItem.textAdvanceScale;
const advanceY = posY - lastPosY;
const textOrientation = Math.sign(textContentItem.width);
if (advanceX < textOrientation * textContentItem.negativeSpaceMax) {
if (Math.abs(advanceY) > 0.5 * textContentItem.height) {
if (Math.abs(advanceY) > textContentItem.height) {
if (advanceX <= textOrientation * textContentItem.notASpace) {
if (advanceX <= textOrientation * textContentItem.trackingSpaceMin) {
if (shouldAddWhitepsace()) {
width: Math.abs(advanceX)
textContentItem.width += advanceX;
} else if (!addFakeSpaces(advanceX, textContentItem.prevTransform, textOrientation)) {
if (textContentItem.str.length === 0) {
width: Math.abs(advanceX)
textContentItem.width += advanceX;
if (Math.abs(advanceY) > textContentItem.height * VERTICAL_SHIFT_RATIO) {
function buildTextContentItem({
const font = textState.font;
const charSpacing = textState.charSpacing + extraSpacing;
textState.translateTextMatrix(charSpacing * textState.textHScale, 0);
textState.translateTextMatrix(0, -charSpacing);
compareWithLastPosition(0);
const glyphs = font.charsToGlyphs(chars);
const scale = textState.fontMatrix[0] * textState.fontSize;
for (let i = 0, ii = glyphs.length; i < ii; i++) {
if (category.isInvisibleFormatMark) {
let charSpacing = textState.charSpacing + (i + 1 === ii ? extraSpacing : 0);
let glyphWidth = glyph.width;
glyphWidth = glyph.vmetric ? glyph.vmetric[0] : -glyphWidth;
let scaledDim = glyphWidth * scale;
if (!keepWhiteSpace && category.isWhitespace) {
charSpacing += scaledDim + textState.wordSpacing;
textState.translateTextMatrix(charSpacing * textState.textHScale, 0);
charSpacing += -scaledDim + textState.wordSpacing;
textState.translateTextMatrix(0, -charSpacing);
if (!category.isZeroWidthDiacritic && !compareWithLastPosition(scaledDim)) {
textState.translateTextMatrix(scaledDim * textState.textHScale, 0);
textState.translateTextMatrix(0, scaledDim);
const textChunk = ensureTextContentItem();
if (category.isZeroWidthDiacritic) {
scaledDim *= textState.textHScale;
textState.translateTextMatrix(scaledDim, 0);
textChunk.width += scaledDim;
textState.translateTextMatrix(0, scaledDim);
scaledDim = Math.abs(scaledDim);
textChunk.height += scaledDim;
textChunk.prevTransform = getCurrentTextTransform();
const glyphUnicode = glyph.unicode;
if (saveLastChar(glyphUnicode)) {
textChunk.str.push(glyphUnicode);
textState.translateTextMatrix(charSpacing * textState.textHScale, 0);
textState.translateTextMatrix(0, -charSpacing);
if (textContentItem.initialized) {
textContentItem.hasEOL = true;
transform: getCurrentTextTransform(),
fontName: textState.loadedName,
function addFakeSpaces(width, transf, textOrientation) {
if (textOrientation * textContentItem.spaceInFlowMin <= width && width <= textOrientation * textContentItem.spaceInFlowMax) {
if (textContentItem.initialized) {
textContentItem.str.push(" ");
const fontName = textContentItem.fontName;
if (textContentItem.vertical) {
height: Math.abs(height),
transform: transf || getCurrentTextTransform(),
function flushTextContentItem() {
if (!textContentItem.initialized || !textContentItem.str) {
if (!textContentItem.vertical) {
textContentItem.totalWidth += textContentItem.width * textContentItem.textAdvanceScale;
textContentItem.totalHeight += textContentItem.height * textContentItem.textAdvanceScale;
textContent.items.push(runBidiTransform(textContentItem));
textContentItem.initialized = false;
textContentItem.str.length = 0;
function enqueueChunk(batch = false) {
const length = textContent.items.length;
if (batch && length < TEXT_CHUNK_BATCH_SIZE) {