Skip to content

Commit 6612d7a

Browse files
authored
Merge pull request #20567 from calixteman/bug2009627
Hide the text in the text layer associated with MathML elements (bug 2009627)
2 parents f40ab1a + cffd54e commit 6612d7a

5 files changed

Lines changed: 98 additions & 24 deletions

File tree

test/integration/accessibility_spec.mjs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,4 +498,50 @@ describe("accessibility", () => {
498498
);
499499
});
500500
});
501+
502+
describe("Text elements must be aria-hidden when there's MathML and annotations", () => {
503+
let pages;
504+
505+
beforeEach(async () => {
506+
pages = await loadAndWait("bug2009627.pdf", ".textLayer");
507+
});
508+
509+
afterEach(async () => {
510+
await closePages(pages);
511+
});
512+
513+
it("must check that the text in text layer is aria-hidden", async () => {
514+
await Promise.all(
515+
pages.map(async ([browserName, page]) => {
516+
const isSanitizerSupported = await page.evaluate(() => {
517+
try {
518+
// eslint-disable-next-line no-undef
519+
return typeof Sanitizer !== "undefined";
520+
} catch {
521+
return false;
522+
}
523+
});
524+
const ariaHidden = await page.evaluate(() =>
525+
Array.from(
526+
document.querySelectorAll(".structTree :has(> math)")
527+
).map(el =>
528+
document
529+
.getElementById(el.getAttribute("aria-owns"))
530+
.getAttribute("aria-hidden")
531+
)
532+
);
533+
if (isSanitizerSupported) {
534+
expect(ariaHidden)
535+
.withContext(`In ${browserName}`)
536+
.toEqual(["true", "true", "true"]);
537+
} else {
538+
// eslint-disable-next-line no-console
539+
console.log(
540+
`Pending in Chrome: Sanitizer API (in ${browserName}) is not supported`
541+
);
542+
}
543+
})
544+
);
545+
});
546+
});
501547
});

test/pdfs/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -867,3 +867,4 @@
867867
!bitmap-trailing-7fff-stripped.pdf
868868
!bitmap.pdf
869869
!bomb_giant.pdf
870+
!bug2009627.pdf

test/pdfs/bug2009627.pdf

39.8 KB
Binary file not shown.

web/pdf_page_view.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,7 @@ class PDFPageView extends BasePDFPageView {
493493
const treeDom = await this.structTreeLayer?.render();
494494
if (treeDom) {
495495
this.l10n.pause();
496-
this.structTreeLayer?.addElementsToTextLayer();
496+
this.structTreeLayer?.updateTextLayer();
497497
if (this.canvas && treeDom.parentNode !== this.canvas) {
498498
// Pause translation when inserting the structTree in the DOM.
499499
this.canvas.append(treeDom);

web/struct_tree_layer_builder.js

Lines changed: 50 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,10 @@ class StructTreeLayerBuilder {
184184

185185
#elementsToAddToTextLayer = null;
186186

187+
#elementsToHideInTextLayer = null;
188+
189+
#elementsToStealFromTextLayer = null;
190+
187191
/**
188192
* @param {StructTreeLayerBuilderOptions} options
189193
*/
@@ -304,15 +308,49 @@ class StructTreeLayerBuilder {
304308
return true;
305309
}
306310

307-
addElementsToTextLayer() {
308-
if (!this.#elementsToAddToTextLayer) {
309-
return;
311+
updateTextLayer() {
312+
if (this.#elementsToAddToTextLayer) {
313+
for (const [id, img] of this.#elementsToAddToTextLayer) {
314+
document.getElementById(id)?.append(img);
315+
}
316+
this.#elementsToAddToTextLayer.clear();
317+
this.#elementsToAddToTextLayer = null;
310318
}
311-
for (const [id, img] of this.#elementsToAddToTextLayer) {
312-
document.getElementById(id)?.append(img);
319+
if (this.#elementsToHideInTextLayer) {
320+
for (const id of this.#elementsToHideInTextLayer) {
321+
const elem = document.getElementById(id);
322+
if (elem) {
323+
elem.ariaHidden = true;
324+
}
325+
}
326+
this.#elementsToHideInTextLayer.length = 0;
327+
this.#elementsToHideInTextLayer = null;
328+
}
329+
if (this.#elementsToStealFromTextLayer) {
330+
for (
331+
let i = 0, ii = this.#elementsToStealFromTextLayer.length;
332+
i < ii;
333+
i += 2
334+
) {
335+
const element = this.#elementsToStealFromTextLayer[i];
336+
const ids = this.#elementsToStealFromTextLayer[i + 1];
337+
let textContent = "";
338+
for (const id of ids) {
339+
const elem = document.getElementById(id);
340+
if (elem) {
341+
textContent += elem.textContent.trim() || "";
342+
// Aria-hide the element in order to avoid duplicate reading of the
343+
// math content by screen readers.
344+
elem.ariaHidden = "true";
345+
}
346+
}
347+
if (textContent) {
348+
element.textContent = textContent;
349+
}
350+
}
351+
this.#elementsToStealFromTextLayer.length = 0;
352+
this.#elementsToStealFromTextLayer = null;
313353
}
314-
this.#elementsToAddToTextLayer.clear();
315-
this.#elementsToAddToTextLayer = null;
316354
}
317355

318356
#walk(node) {
@@ -325,21 +363,13 @@ class StructTreeLayerBuilder {
325363
const { role } = node;
326364
if (MathMLElements.has(role)) {
327365
element = document.createElementNS(MathMLNamespace, role);
328-
let text = "";
366+
const ids = [];
367+
(this.#elementsToStealFromTextLayer ||= []).push(element, ids);
329368
for (const { type, id } of node.children || []) {
330-
if (type !== "content" || !id) {
331-
continue;
369+
if (type === "content" && id) {
370+
ids.push(id);
332371
}
333-
const elem = document.getElementById(id);
334-
if (!elem) {
335-
continue;
336-
}
337-
text += elem.textContent.trim() || "";
338-
// Aria-hide the element in order to avoid duplicate reading of the
339-
// math content by screen readers.
340-
elem.ariaHidden = "true";
341372
}
342-
element.textContent = text;
343373
} else {
344374
element = document.createElement("span");
345375
}
@@ -365,10 +395,7 @@ class StructTreeLayerBuilder {
365395
if (!id) {
366396
continue;
367397
}
368-
const elem = document.getElementById(id);
369-
if (elem) {
370-
elem.ariaHidden = true;
371-
}
398+
(this.#elementsToHideInTextLayer ||= []).push(id);
372399
}
373400
// For now, we don't want to keep the alt text if there's valid
374401
// MathML (see https://github.com/w3c/mathml-aam/issues/37).

0 commit comments

Comments
 (0)