From 71140e7d0ffa15c85def7cb86186322751eee44c Mon Sep 17 00:00:00 2001 From: Tim van der Meij Date: Mon, 22 Dec 2025 19:37:01 +0100 Subject: [PATCH 1/4] Introduce a helper function to draw a line in the ink editor integration tests This commit extracts the logic to draw a line from one coordinate to another to both remove code duplication (8% of the total number of lines in the file are removed) and clarify the intent of the individual tests. --- test/integration/ink_editor_spec.mjs | 223 +++++++-------------------- 1 file changed, 58 insertions(+), 165 deletions(-) diff --git a/test/integration/ink_editor_spec.mjs b/test/integration/ink_editor_spec.mjs index c9977d93787a4..f9b8a0a2c54a0 100644 --- a/test/integration/ink_editor_spec.mjs +++ b/test/integration/ink_editor_spec.mjs @@ -52,6 +52,15 @@ const commit = async page => { const switchToInk = switchToEditor.bind(null, "Ink"); +const drawLine = async (page, x0, y0, x1, y1) => { + const clickHandle = await waitForPointerUp(page); + await page.mouse.move(x0, y0); + await page.mouse.down(); + await page.mouse.move(x1, y1); + await page.mouse.up(); + await awaitPromise(clickHandle); +}; + describe("Ink Editor", () => { describe("Basic operations", () => { let pages; @@ -74,13 +83,7 @@ describe("Ink Editor", () => { for (let i = 0; i < 3; i++) { const x = rect.x + 100 + i * 100; const y = rect.y + 100 + i * 100; - const clickHandle = await waitForPointerUp(page); - await page.mouse.move(x, y); - await page.mouse.down(); - await page.mouse.move(x + 50, y + 50); - await page.mouse.up(); - await awaitPromise(clickHandle); - + await drawLine(page, x, y, x + 50, y + 50); await commit(page); } @@ -107,15 +110,9 @@ describe("Ink Editor", () => { const rect = await getRect(page, ".annotationEditorLayer"); - const xStart = rect.x + 300; - const yStart = rect.y + 300; - const clickHandle = await waitForPointerUp(page); - await page.mouse.move(xStart, yStart); - await page.mouse.down(); - await page.mouse.move(xStart + 50, yStart + 50); - await page.mouse.up(); - await awaitPromise(clickHandle); - + const x = rect.x + 300; + const y = rect.y + 300; + await drawLine(page, x, y, x + 50, y + 50); await commit(page); const rectBefore = await getRect(page, ".canvasWrapper .draw"); @@ -149,13 +146,7 @@ describe("Ink Editor", () => { const x = rect.x + 100; const y = rect.y + 100; - const clickHandle = await waitForPointerUp(page); - await page.mouse.move(x, y); - await page.mouse.down(); - await page.mouse.move(x + 50, y + 50); - await page.mouse.up(); - await awaitPromise(clickHandle); - + await drawLine(page, x, y, x + 50, y + 50); await commit(page); const editorSelector = getEditorSelector(0); @@ -205,13 +196,7 @@ describe("Ink Editor", () => { const x = rect.x + 20; const y = rect.y + 20; - const clickHandle = await waitForPointerUp(page); - await page.mouse.move(x, y); - await page.mouse.down(); - await page.mouse.move(x + 50, y + 50); - await page.mouse.up(); - await awaitPromise(clickHandle); - + await drawLine(page, x, y, x + 50, y + 50); await commit(page); await selectAll(page); @@ -244,13 +229,7 @@ describe("Ink Editor", () => { const x = rect.x + 20; const y = rect.y + 20; - const clickHandle = await waitForPointerUp(page); - await page.mouse.move(x, y); - await page.mouse.down(); - await page.mouse.move(x + 50, y + 50); - await page.mouse.up(); - await awaitPromise(clickHandle); - + await drawLine(page, x, y, x + 50, y + 50); await commit(page); const oneToFourteen = Array.from(new Array(13).keys(), n => n + 2); @@ -299,12 +278,7 @@ describe("Ink Editor", () => { const x = rect.x + 20; const y = rect.y + 20; - const clickHandle = await waitForPointerUp(page); - await page.mouse.move(x, y); - await page.mouse.down(); - await page.mouse.move(x + 50, y + 50); - await page.mouse.up(); - await awaitPromise(clickHandle); + await drawLine(page, x, y, x + 50, y + 50); await page.mouse.click(rect.x - 10, rect.y + 10); await page.waitForSelector(`${getEditorSelector(0)}.disabled`); @@ -331,14 +305,9 @@ describe("Ink Editor", () => { const rect = await getRect(page, ".annotationEditorLayer"); - const xStart = rect.x + 300; - const yStart = rect.y + 300; - const clickHandle = await waitForPointerUp(page); - await page.mouse.move(xStart, yStart); - await page.mouse.down(); - await page.mouse.move(xStart + 50, yStart + 50); - await page.mouse.up(); - await awaitPromise(clickHandle); + const x = rect.x + 300; + const y = rect.y + 300; + await drawLine(page, x, y, x + 50, y + 50); await commit(page); const editorSelector = getEditorSelector(0); @@ -375,14 +344,9 @@ describe("Ink Editor", () => { const rect = await getRect(page, ".annotationEditorLayer"); - const xStart = rect.x + 300; - const yStart = rect.y + 300; - const clickHandle = await waitForPointerUp(page); - await page.mouse.move(xStart, yStart); - await page.mouse.down(); - await page.mouse.move(xStart + 50, yStart + 50); - await page.mouse.up(); - await awaitPromise(clickHandle); + const x = rect.x + 300; + const y = rect.y + 300; + await drawLine(page, x, y, x + 50, y + 50); await commit(page); const editorSelector = getEditorSelector(0); @@ -432,14 +396,9 @@ describe("Ink Editor", () => { const rect = await getRect(page, ".annotationEditorLayer"); - const xStart = rect.x + 300; - const yStart = rect.y + 300; - const clickHandle = await waitForPointerUp(page); - await page.mouse.move(xStart, yStart); - await page.mouse.down(); - await page.mouse.move(xStart + 50, yStart + 50); - await page.mouse.up(); - await awaitPromise(clickHandle); + const x = rect.x + 300; + const y = rect.y + 300; + await drawLine(page, x, y, x + 50, y + 50); await commit(page); const editorSelector = getEditorSelector(0); @@ -483,16 +442,11 @@ describe("Ink Editor", () => { await switchToInk(page); const rect = await getRect(page, ".annotationEditorLayer"); - let xStart = rect.x + 10; - const yStart = rect.y + 10; + let x = rect.x + 10; + const y = rect.y + 10; for (let i = 0; i < 5; i++) { - const clickHandle = await waitForPointerUp(page); - await page.mouse.move(xStart, yStart); - await page.mouse.down(); - await page.mouse.move(xStart + 50, yStart + 50); - await page.mouse.up(); - await awaitPromise(clickHandle); - xStart += 70; + await drawLine(page, x, y, x + 50, y + 50); + x += 70; } await commit(page); @@ -561,13 +515,7 @@ describe("Ink Editor", () => { const x = rect.x + 20; const y = rect.y + 20; - const clickHandle = await waitForPointerUp(page); - await page.mouse.move(x, y); - await page.mouse.down(); - await page.mouse.move(x + 50, y + 50); - await page.mouse.up(); - await awaitPromise(clickHandle); - + await drawLine(page, x, y, x + 50, y + 50); await commit(page); const drawSelector = `.page[data-page-number = "1"] .canvasWrapper .draw`; @@ -636,12 +584,7 @@ describe("Ink Editor", () => { const x = rect.x + 20; const y = rect.y + 20; - const clickHandle = await waitForPointerUp(page); - await page.mouse.move(x, y); - await page.mouse.down(); - await page.mouse.move(x + 50, y + 50); - await page.mouse.up(); - await awaitPromise(clickHandle); + await drawLine(page, x, y, x + 50, y + 50); const drawSelector = `.canvasWrapper svg.draw path[d]:not([d=""])`; await page.waitForSelector(drawSelector); @@ -680,12 +623,7 @@ describe("Ink Editor", () => { const x = rect.x + 20; const y = rect.y + 20; - const clickHandle = await waitForPointerUp(page); - await page.mouse.move(x, y); - await page.mouse.down(); - await page.mouse.move(x + 50, y + 50); - await page.mouse.up(); - await awaitPromise(clickHandle); + await drawLine(page, x, y, x + 50, y + 50); await page.evaluate(() => { window.focusedIds = []; @@ -884,14 +822,9 @@ describe("Ink Editor", () => { await switchToInk(page); const rect = await getRect(page, ".annotationEditorLayer"); - const xStart = rect.x + 300; - const yStart = rect.y + 300; - const clickHandle = await waitForPointerUp(page); - await page.mouse.move(xStart, yStart); - await page.mouse.down(); - await page.mouse.move(xStart + 50, yStart + 50); - await page.mouse.up(); - await awaitPromise(clickHandle); + const x = rect.x + 300; + const y = rect.y + 300; + await drawLine(page, x, y, x + 50, y + 50); await commit(page); await page.waitForSelector(editorSelector); @@ -918,14 +851,9 @@ describe("Ink Editor", () => { await switchToInk(page); const rect = await getRect(page, ".annotationEditorLayer"); - const xStart = rect.x + 300; - const yStart = rect.y + 300; - const clickHandle = await waitForPointerUp(page); - await page.mouse.move(xStart, yStart); - await page.mouse.down(); - await page.mouse.move(xStart + 50, yStart + 50); - await page.mouse.up(); - await awaitPromise(clickHandle); + const x = rect.x + 300; + const y = rect.y + 300; + await drawLine(page, x, y, x + 50, y + 50); await commit(page); await page.waitForSelector(editorSelector); @@ -957,14 +885,9 @@ describe("Ink Editor", () => { await switchToInk(page); const rect = await getRect(page, ".annotationEditorLayer"); - const xStart = rect.x + 300; - const yStart = rect.y + 300; - const clickHandle = await waitForPointerUp(page); - await page.mouse.move(xStart, yStart); - await page.mouse.down(); - await page.mouse.move(xStart + 50, yStart + 50); - await page.mouse.up(); - await awaitPromise(clickHandle); + const x = rect.x + 300; + const y = rect.y + 300; + await drawLine(page, x, y, x + 50, y + 50); await commit(page); await page.waitForSelector(editorSelector); @@ -976,14 +899,9 @@ describe("Ink Editor", () => { await page.waitForSelector("#editorUndoBar", { visible: true }); const newRect = await getRect(page, ".annotationEditorLayer"); - const newXStart = newRect.x + 300; - const newYStart = newRect.y + 300; - const newClickHandle = await waitForPointerUp(page); - await page.mouse.move(newXStart, newYStart); - await page.mouse.down(); - await page.mouse.move(newXStart + 50, newYStart + 50); - await page.mouse.up(); - await awaitPromise(newClickHandle); + const newX = newRect.x + 300; + const newY = newRect.y + 300; + await drawLine(page, newX, newY, newX + 50, newY + 50); await commit(page); await page.waitForSelector(getEditorSelector(1)); @@ -1014,12 +932,7 @@ describe("Ink Editor", () => { const x = rect.x + 20; const y = rect.y + 20; - const clickHandle = await waitForPointerUp(page); - await page.mouse.move(x, y); - await page.mouse.down(); - await page.mouse.move(x + 50, y + 50); - await page.mouse.up(); - await awaitPromise(clickHandle); + await drawLine(page, x, y, x + 50, y + 50); const svgSelector = ".canvasWrapper svg.draw"; const strokeWidth = await page.$eval(svgSelector, el => @@ -1082,14 +995,9 @@ describe("Ink Editor", () => { page, `${pageSelector} .annotationEditorLayer` ); - const xStart = rect.x + 10; - const yStart = rect.y + 10; - const clickHandle = await waitForPointerUp(page); - await page.mouse.move(xStart, yStart); - await page.mouse.down(); - await page.mouse.move(xStart + 10, yStart + 10); - await page.mouse.up(); - await awaitPromise(clickHandle); + const x = rect.x + 10; + const y = rect.y + 10; + await drawLine(page, x, y, x + 10, y + 10); await commit(page); } @@ -1148,15 +1056,10 @@ describe("Ink Editor", () => { await switchToInk(page); const editorLayerRect = await getRect(page, ".annotationEditorLayer"); - const drawStartX = editorLayerRect.x + 100; - const drawStartY = editorLayerRect.y + 100; - - const clickHandle = await waitForPointerUp(page); - await page.mouse.move(drawStartX, drawStartY); - await page.mouse.down(); - await page.mouse.move(drawStartX + 50, drawStartY + 50); - await page.mouse.up(); - await awaitPromise(clickHandle); + + const x = editorLayerRect.x + 100; + const y = editorLayerRect.y + 100; + await drawLine(page, x, y, x + 50, y + 50); await commit(page); const pageFinalPosition = await getRect( @@ -1257,16 +1160,10 @@ describe("Should switch from an editor and mode to others by double clicking", ( await switchToInk(page); const editorLayerRect = await getRect(page, ".annotationEditorLayer"); - const drawStartX = editorLayerRect.x + 100; - const drawStartY = editorLayerRect.y + 100; - const inkSelector = getEditorSelector(0); - const clickHandle = await waitForPointerUp(page); - await page.mouse.move(drawStartX, drawStartY); - await page.mouse.down(); - await page.mouse.move(drawStartX + 50, drawStartY + 50); - await page.mouse.up(); - await awaitPromise(clickHandle); + const x = editorLayerRect.x + 100; + const y = editorLayerRect.y + 100; + await drawLine(page, x, y, x + 50, y + 50); await commit(page); await switchToEditor("FreeText", page); @@ -1286,6 +1183,7 @@ describe("Should switch from an editor and mode to others by double clicking", ( await page.waitForSelector("#editorInkButton:not(.toggled)"); let modeChangedHandle = await waitForAnnotationModeChanged(page); + const inkSelector = getEditorSelector(0); await selectEditor(page, inkSelector, 2); await awaitPromise(modeChangedHandle); await page.waitForSelector("#editorInkButton.toggled"); @@ -1322,12 +1220,7 @@ describe("Ink must update its color", () => { const x = rect.x + 20; const y = rect.y + 20; - const clickHandle = await waitForPointerUp(page); - await page.mouse.move(x, y); - await page.mouse.down(); - await page.mouse.move(x + 50, y + 50); - await page.mouse.up(); - await awaitPromise(clickHandle); + await drawLine(page, x, y, x + 50, y + 50); await commit(page); const editorSelector = getEditorSelector(0); From 4ff582acbec780a3639f19e78fa8ff2293179073 Mon Sep 17 00:00:00 2001 From: calixteman Date: Tue, 23 Dec 2025 10:35:59 +0100 Subject: [PATCH 2/4] Avoid pattern creation with some basic gradients Some gradients are represented as patterns in PDF.js, because they mustn't be affected by the current transform. But in most of the cases, the gradient is attached to the origin and the current transform is very basic (dilatation + orthogonal + translation). In those cases, we can avoid creating the pattern because the gradient is transformed into another gradient when the inverse transform is applied. --- src/display/pattern_helper.js | 76 ++++++++++++++++++++++++++++++----- 1 file changed, 65 insertions(+), 11 deletions(-) diff --git a/src/display/pattern_helper.js b/src/display/pattern_helper.js index 6884eca9c7b6b..d460de365637e 100644 --- a/src/display/pattern_helper.js +++ b/src/display/pattern_helper.js @@ -71,23 +71,51 @@ class RadialAxialShadingPattern extends BaseShadingPattern { this.matrix = null; } - _createGradient(ctx) { + isOriginBased() { + return ( + this._p0[0] === 0 && + this._p0[1] === 0 && + (!this.isRadial() || (this._p1[0] === 0 && this._p1[1] === 0)) + ); + } + + isRadial() { + return this._type === "radial"; + } + + _createGradient(ctx, transform = null) { let grad; + let firstPoint = this._p0; + let secondPoint = this._p1; + if (transform) { + firstPoint = firstPoint.slice(); + secondPoint = secondPoint.slice(); + Util.applyTransform(firstPoint, transform); + Util.applyTransform(secondPoint, transform); + } if (this._type === "axial") { grad = ctx.createLinearGradient( - this._p0[0], - this._p0[1], - this._p1[0], - this._p1[1] + firstPoint[0], + firstPoint[1], + secondPoint[0], + secondPoint[1] ); } else if (this._type === "radial") { + let r0 = this._r0; + let r1 = this._r1; + if (transform) { + const scale = new Float32Array(2); + Util.singularValueDecompose2dScale(transform, scale); + r0 *= scale[0]; + r1 *= scale[0]; + } grad = ctx.createRadialGradient( - this._p0[0], - this._p0[1], - this._r0, - this._p1[0], - this._p1[1], - this._r1 + firstPoint[0], + firstPoint[1], + r0, + secondPoint[0], + secondPoint[1], + r1 ); } @@ -100,6 +128,32 @@ class RadialAxialShadingPattern extends BaseShadingPattern { getPattern(ctx, owner, inverse, pathType) { let pattern; if (pathType === PathType.STROKE || pathType === PathType.FILL) { + if (this.isOriginBased()) { + let transf = Util.transform(inverse, owner.baseTransform); + if (this.matrix) { + transf = Util.transform(transf, this.matrix); + } + const precision = 1e-3; + const n1 = Math.hypot(transf[0], transf[1]); + const n2 = Math.hypot(transf[2], transf[3]); + const ps = (transf[0] * transf[2] + transf[1] * transf[3]) / (n1 * n2); + if (Math.abs(ps) < precision) { + // The images of the basis vectors are orthogonal. + if (this.isRadial()) { + // If the images of the basis vectors are a square then the + // circles are transformed to circles and we can use a gradient + // directly. + if (Math.abs(n1 - n2) < precision) { + return this._createGradient(ctx, transf); + } + } else { + // The rectangles are transformed to rectangles and we can use a + // gradient directly. + return this._createGradient(ctx, transf); + } + } + } + const ownerBBox = owner.current.getClippedPathBoundingBox( pathType, getCurrentTransform(ctx) From 91033c2199888dd36f2ac0f373859748ddaab4d5 Mon Sep 17 00:00:00 2001 From: calixteman Date: Tue, 23 Dec 2025 14:05:17 +0100 Subject: [PATCH 3/4] Fix the encoding for some missing chinese fonts It fixes #20489. --- src/core/evaluator.js | 47 +++++++++++++++++++++++++- src/core/font_substitutions.js | 58 +++++++++++++++++++++++++++++++++ test/pdfs/.gitignore | 1 + test/pdfs/issue20489.pdf | Bin 0 -> 7337 bytes test/test_manifest.json | 7 ++++ 5 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 test/pdfs/issue20489.pdf diff --git a/src/core/evaluator.js b/src/core/evaluator.js index 55fb31669f30e..536a5682a140e 100644 --- a/src/core/evaluator.js +++ b/src/core/evaluator.js @@ -3588,7 +3588,7 @@ class PartialEvaluator { if (properties.composite) { // CIDSystemInfo helps to match CID to glyphs const cidSystemInfo = dict.get("CIDSystemInfo"); - if (cidSystemInfo instanceof Dict) { + if (cidSystemInfo instanceof Dict && !properties.cidSystemInfo) { properties.cidSystemInfo = { registry: stringToPDFString(cidSystemInfo.get("Registry")), ordering: stringToPDFString(cidSystemInfo.get("Ordering")), @@ -3670,6 +3670,51 @@ class PartialEvaluator { baseEncodingName = null; } + // Ignore incorrectly specified WinAnsiEncoding for non-embedded CJK fonts + // (fixes issue20489). Some chinese fonts often have WinAnsiEncoding in the + // PDF even though they should use Identity-H or GB-EUC-H encoding. + if ( + baseEncodingName === "WinAnsiEncoding" && + nonEmbeddedFont && + properties.name?.charCodeAt(0) >= 0xb7 + ) { + const fontName = properties.name; + // This list is built from some names from Pdfium and mupdf: + // - https://pdfium.googlesource.com/pdfium/+/master/core/fpdfapi/font/cpdf_font.cpp#41 + // - https://fossies.org/linux/mupdf/source/pdf/pdf-font.c#l_820 + const chineseFontNames = [ + "\xCB\xCE\xCC\xE5", // SimSun + "\xBA\xDA\xCC\xE5", // SimHei + "\xBF\xAC\xCC\xE5", // SimKai + "\xB7\xC2\xCB\xCE", // SimFang + "\xBF\xAC\xCC\xE5_GB2312", // SimKai + "\xB7\xC2\xCB\xCE_GB2312", // SimFang + "\xC1\xA5\xCA\xE9", // SimLi + "\xD0\xC2\xCB\xCE", // SimSun + ]; + + // Check for common Chinese font names and their GBK-encoded equivalents + // (which may appear as Latin-1 when incorrectly decoded). + if (chineseFontNames.includes(fontName)) { + baseEncodingName = null; + properties.defaultEncoding = "Adobe-GB1-UCS2"; + properties.composite = true; + properties.cidEncoding = Name.get("GBK-EUC-H"); + const cMap = await CMapFactory.create({ + encoding: properties.cidEncoding, + fetchBuiltInCMap: this._fetchBuiltInCMapBound, + useCMap: null, + }); + properties.cMap = cMap; + properties.vertical = properties.cMap.vertical; + properties.cidSystemInfo = { + registry: "Adobe", + ordering: "GB1", + supplement: 0, + }; + } + } + if (baseEncodingName) { properties.defaultEncoding = getEncoding(baseEncodingName); } else { diff --git a/src/core/font_substitutions.js b/src/core/font_substitutions.js index 1e87fabac5a3a..7325087b3a935 100644 --- a/src/core/font_substitutions.js +++ b/src/core/font_substitutions.js @@ -306,6 +306,64 @@ const substitutionMap = new Map([ alias: "Wingdings", }, ], + [ + "\xCB\xCE\xCC\xE5", + { + local: ["SimSun", "SimSun Regular", "NSimSun"], + style: NORMAL, + ultimate: "serif", + }, + ], + [ + "\xBA\xDA\xCC\xE5", + { + local: ["SimHei", "SimHei Regular"], + style: NORMAL, + ultimate: "sans-serif", + }, + ], + [ + "\xBF\xAC\xCC\xE5", + { + local: ["KaiTi", "SimKai", "SimKai Regular"], + style: NORMAL, + ultimate: "sans-serif", + }, + ], + [ + "\xB7\xC2\xCB\xCE", + { + local: ["FangSong", "SimFang", "SimFang Regular"], + style: NORMAL, + ultimate: "serif", + }, + ], + [ + "\xBF\xAC\xCC\xE5_GB2312", + { + alias: "\xBF\xAC\xCC\xE5", + }, + ], + [ + "\xB7\xC2\xCB\xCE_GB2312", + { + alias: "\xB7\xC2\xCB\xCE", + }, + ], + [ + "\xC1\xA5\xCA\xE9", + { + local: ["SimLi", "SimLi Regular"], + style: NORMAL, + ultimate: "serif", + }, + ], + [ + "\xD0\xC2\xCB\xCE", + { + alias: "\xCB\xCE\xCC\xE5", + }, + ], ]); const fontAliases = new Map([["Arial-Black", "ArialBlack"]]); diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index 352366971bffa..6080768c93f9e 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -767,3 +767,4 @@ !issue20225.pdf !issue20513.pdf !issue20516.pdf +!issue20489.pdf diff --git a/test/pdfs/issue20489.pdf b/test/pdfs/issue20489.pdf new file mode 100644 index 0000000000000000000000000000000000000000..1261d4d0b8723aedbaaecacdcc8855454e3a578f GIT binary patch literal 7337 zcmeHMc~}$I+E+vrs>KDDx(-E5f`pk&l1UTODk@mpn~5;(O$2Lwu(X#MeBwuE+FbXXCQ#)wten*pQqm+*W@|R%)IA4?{dz} z@4WAO9OV)jljVZjIBwZjb;*W>V2Czm)<7FKH#8(&N1|e-QJJWXN9D?R(txl*w*oop5sqK!$Rpo#oA8hIF{l@x(#|l;Vyj9AUu;QXn24s9dj&4JM5Uw1Xl9kSeuOq)m$i1Pn0p`3Rqb zN26lBR`)N+3awFTBoPewsWAe(3xBudCwt%?Mr3`RYvOtMMK|2fic%>~(@qxZsZ5C1M?;?o6kyU^)ZD<+Pf zTin;q=jNWOyv3@4c7-Cxw>f@KhU(7*`L5#F`V9Zde|chSOqqLgYn!0{1|b_cj`4%r zk=KmMfR>-XSX|gp5ubCs?1i>vI= z5vrVs)XB@D3Th6nQ+nU>7lroU9Vy^n^?sbIP4T%p_K+rGg5x42=cn0jj-utW@2)MK zn6OKB`GNQOT^n~aeDhrMShZ^Ele(f$*EnzX1kECcx*mQ}7)AudHR4wHwCzMh!g>U9|Rv?Xnc_tI@sA(EBDYjJtcdr7+B6<+S?i1s6}#kWVfx zzvi>z)R_A_JgrCh714v#YXW_iSTYUizN6P+bw{1&fSVEhl0pY(fa}d~m!1obxVhtA zZt`sT&&^ebcW=9Uw6ZPjgxA?jxM&$>L1&V&iIwMeDTSKBF^@b*Et*a z`02lKoYC<4n_F#to0^YLs9m;Lz6cB0H)W`zvHi5W>yFA%%2SO;?6cLoE+lTKYkSoA zf_1$dh-^#F z*E8=&^|JU|T{ z|H}Loy$%g8uZ+CiKUds)`{=qQ%X?4WlKzG3iSm(~S3PjfIp>x7#_M*UU!tM|tT-9& zlS6%MuKBJXS-7)x&C_SC`qe*duAiEIY=qOXW8=!h74$Kb+fVrsU4xD@i-rUJWh||7?18?W`v)^B!-$xMxwe z#Zy7_3OzjrOK6a(&P4dir@cdkW@5Q>f1BYs(j$AF=x3gi9U7q~{J4Qyk)40N3qqC8! zt!im6*PFB~boE=h&@;>`%R2&#@(r;ROU<8YECz8msLjUk481F>kISS2Q7)3JwUqANOo= z%X={1BaMfz_bq%SEe~Bp9xmGOs*FH|2K60>ypx$(|%n}%g@2W89N0A2-wA{x5f@YwPNi zZ|h3gy9XW`pFum(KEuXB%4r|mh%9}v&bkt7UfQo7&ztl~p7Yz$-;EEY$9Y*D?R&?1 z%$TpeBfnI7x8;PDJs#TcA4x&grDIP`*o*&yBf7bB*o<*7CDHe4q~x`l#5C=V5?PY;?Z!mMyN5UyPjogy}>9>Q0fsjhWaZz z?{O{{aH@<6U~?CMKnXSum;a&tKhD92HTds+|FCE(@RyK=SiM?j)ansF6@ho>81UH) zDZ2Slp&=G#6g)m3o_$-)INERP4#J*7-UWde|lFnMqwM1c-F zD7<+GUwlC7rH&P9;uB$>5Nsrq!azPWwNnp{3%V_ZS&EsZe}rkQZcG#E)yl+BjT+_+ z0m1(Xs&RR21U6tA)z};k!etRu<6}5Nut8$P!x5ZMP|eg&@k3hYIMbLvyZ#7vJf?d% z53s?0c!l~+eWt6)M$>@&^o?C}?{RX8sLuqlzwO_WlvN z;oayKtWF9})-a`MM$vx)ZSb>#t>>rr;r?AH`YYxGLhfIo=Yx*Fer^A3&i@6pbrhg` zK$}^;8RCyQwEZ7KHV(`i%_Fv+`10>ynpxGGs{3|P}~M{4`RniP;SSgK}{W$$H5=I5D3BPvHYE<0@V417}UQ(R8JQo;zV@}JSEWS zwefmo5(CuaK^JgQ0t)7I$z&YExfmN`voIDPV>4iFUzHq7>gkcDk^br!y;7f!;4T=8 zsmGbTXapqvDs8F(5u~AkAq-TQY)k;kLJg#Ta#vqq2rA&B0zLxC3^YV-OeE=nT7gmKabpBm?y$(^G-7270Gb1{$DM^{|k|!uc$M%jd8sVSE~f(ZKX{ZRtIaJbc7q zbb{ajcceTifwMR=oDgya7{S3ut&L^>6iuaL@pBy=HPDrB)R zk(ec8$#6DUMFES;11bdq8HVvhJvH_`jgV+#fl`FkaY{p#Jb>-$I5ny2oZde)zGp=y zTpm1wlGSk>((PiJo{X~r?*M`!v4! zSR5Y1yvN7EL1OqW4Mdk_^4M%HaO_<^HWvg(@6kA1bNe_vkP^Jd$K|s@n)j|e0>jK~ zA=q5-vAoB}6_}6ZnfpdSfa@A-)GO7Aq#hmyDzsW~7)J$?Xvaxk$H5mGtj-|8qM$yK zNH+mr!eK{A_v E0x@%o Date: Tue, 23 Dec 2025 15:26:07 +0100 Subject: [PATCH 4/4] Remove some files from talos tests because they aren't available on webarchive --- test/test_manifest.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/test_manifest.json b/test/test_manifest.json index c9b9a5400c321..a5194ec5cef8d 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -654,6 +654,7 @@ "md5": "8f9347b0d5620537850b24b8385b0982", "rounds": 1, "link": true, + "talos": false, "firstPage": 4, "lastPage": 4, "type": "eq" @@ -664,6 +665,7 @@ "md5": "8f9347b0d5620537850b24b8385b0982", "rounds": 1, "link": true, + "talos": false, "firstPage": 4, "lastPage": 4, "type": "eq",