mirror of
https://github.com/mozilla/pdf.js.git
synced 2026-02-08 00:21:11 +01:00
Merge pull request #20567 from calixteman/bug2009627
Hide the text in the text layer associated with MathML elements (bug 2009627)
This commit is contained in:
commit
6612d7afaf
@ -498,4 +498,50 @@ describe("accessibility", () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Text elements must be aria-hidden when there's MathML and annotations", () => {
|
||||
let pages;
|
||||
|
||||
beforeEach(async () => {
|
||||
pages = await loadAndWait("bug2009627.pdf", ".textLayer");
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await closePages(pages);
|
||||
});
|
||||
|
||||
it("must check that the text in text layer is aria-hidden", async () => {
|
||||
await Promise.all(
|
||||
pages.map(async ([browserName, page]) => {
|
||||
const isSanitizerSupported = await page.evaluate(() => {
|
||||
try {
|
||||
// eslint-disable-next-line no-undef
|
||||
return typeof Sanitizer !== "undefined";
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
const ariaHidden = await page.evaluate(() =>
|
||||
Array.from(
|
||||
document.querySelectorAll(".structTree :has(> math)")
|
||||
).map(el =>
|
||||
document
|
||||
.getElementById(el.getAttribute("aria-owns"))
|
||||
.getAttribute("aria-hidden")
|
||||
)
|
||||
);
|
||||
if (isSanitizerSupported) {
|
||||
expect(ariaHidden)
|
||||
.withContext(`In ${browserName}`)
|
||||
.toEqual(["true", "true", "true"]);
|
||||
} else {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(
|
||||
`Pending in Chrome: Sanitizer API (in ${browserName}) is not supported`
|
||||
);
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
1
test/pdfs/.gitignore
vendored
1
test/pdfs/.gitignore
vendored
@ -867,3 +867,4 @@
|
||||
!bitmap-trailing-7fff-stripped.pdf
|
||||
!bitmap.pdf
|
||||
!bomb_giant.pdf
|
||||
!bug2009627.pdf
|
||||
|
||||
BIN
test/pdfs/bug2009627.pdf
Executable file
BIN
test/pdfs/bug2009627.pdf
Executable file
Binary file not shown.
@ -493,7 +493,7 @@ class PDFPageView extends BasePDFPageView {
|
||||
const treeDom = await this.structTreeLayer?.render();
|
||||
if (treeDom) {
|
||||
this.l10n.pause();
|
||||
this.structTreeLayer?.addElementsToTextLayer();
|
||||
this.structTreeLayer?.updateTextLayer();
|
||||
if (this.canvas && treeDom.parentNode !== this.canvas) {
|
||||
// Pause translation when inserting the structTree in the DOM.
|
||||
this.canvas.append(treeDom);
|
||||
|
||||
@ -184,6 +184,10 @@ class StructTreeLayerBuilder {
|
||||
|
||||
#elementsToAddToTextLayer = null;
|
||||
|
||||
#elementsToHideInTextLayer = null;
|
||||
|
||||
#elementsToStealFromTextLayer = null;
|
||||
|
||||
/**
|
||||
* @param {StructTreeLayerBuilderOptions} options
|
||||
*/
|
||||
@ -304,15 +308,49 @@ class StructTreeLayerBuilder {
|
||||
return true;
|
||||
}
|
||||
|
||||
addElementsToTextLayer() {
|
||||
if (!this.#elementsToAddToTextLayer) {
|
||||
return;
|
||||
updateTextLayer() {
|
||||
if (this.#elementsToAddToTextLayer) {
|
||||
for (const [id, img] of this.#elementsToAddToTextLayer) {
|
||||
document.getElementById(id)?.append(img);
|
||||
}
|
||||
this.#elementsToAddToTextLayer.clear();
|
||||
this.#elementsToAddToTextLayer = null;
|
||||
}
|
||||
for (const [id, img] of this.#elementsToAddToTextLayer) {
|
||||
document.getElementById(id)?.append(img);
|
||||
if (this.#elementsToHideInTextLayer) {
|
||||
for (const id of this.#elementsToHideInTextLayer) {
|
||||
const elem = document.getElementById(id);
|
||||
if (elem) {
|
||||
elem.ariaHidden = true;
|
||||
}
|
||||
}
|
||||
this.#elementsToHideInTextLayer.length = 0;
|
||||
this.#elementsToHideInTextLayer = null;
|
||||
}
|
||||
if (this.#elementsToStealFromTextLayer) {
|
||||
for (
|
||||
let i = 0, ii = this.#elementsToStealFromTextLayer.length;
|
||||
i < ii;
|
||||
i += 2
|
||||
) {
|
||||
const element = this.#elementsToStealFromTextLayer[i];
|
||||
const ids = this.#elementsToStealFromTextLayer[i + 1];
|
||||
let textContent = "";
|
||||
for (const id of ids) {
|
||||
const elem = document.getElementById(id);
|
||||
if (elem) {
|
||||
textContent += elem.textContent.trim() || "";
|
||||
// Aria-hide the element in order to avoid duplicate reading of the
|
||||
// math content by screen readers.
|
||||
elem.ariaHidden = "true";
|
||||
}
|
||||
}
|
||||
if (textContent) {
|
||||
element.textContent = textContent;
|
||||
}
|
||||
}
|
||||
this.#elementsToStealFromTextLayer.length = 0;
|
||||
this.#elementsToStealFromTextLayer = null;
|
||||
}
|
||||
this.#elementsToAddToTextLayer.clear();
|
||||
this.#elementsToAddToTextLayer = null;
|
||||
}
|
||||
|
||||
#walk(node) {
|
||||
@ -325,21 +363,13 @@ class StructTreeLayerBuilder {
|
||||
const { role } = node;
|
||||
if (MathMLElements.has(role)) {
|
||||
element = document.createElementNS(MathMLNamespace, role);
|
||||
let text = "";
|
||||
const ids = [];
|
||||
(this.#elementsToStealFromTextLayer ||= []).push(element, ids);
|
||||
for (const { type, id } of node.children || []) {
|
||||
if (type !== "content" || !id) {
|
||||
continue;
|
||||
if (type === "content" && id) {
|
||||
ids.push(id);
|
||||
}
|
||||
const elem = document.getElementById(id);
|
||||
if (!elem) {
|
||||
continue;
|
||||
}
|
||||
text += elem.textContent.trim() || "";
|
||||
// Aria-hide the element in order to avoid duplicate reading of the
|
||||
// math content by screen readers.
|
||||
elem.ariaHidden = "true";
|
||||
}
|
||||
element.textContent = text;
|
||||
} else {
|
||||
element = document.createElement("span");
|
||||
}
|
||||
@ -365,10 +395,7 @@ class StructTreeLayerBuilder {
|
||||
if (!id) {
|
||||
continue;
|
||||
}
|
||||
const elem = document.getElementById(id);
|
||||
if (elem) {
|
||||
elem.ariaHidden = true;
|
||||
}
|
||||
(this.#elementsToHideInTextLayer ||= []).push(id);
|
||||
}
|
||||
// For now, we don't want to keep the alt text if there's valid
|
||||
// MathML (see https://github.com/w3c/mathml-aam/issues/37).
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user