1
0
Fork 0
mirror of https://github.com/mozilla/pdf.js.git synced 2025-04-19 22:58:07 +02:00

[Editor] Make the stamp annotations alt text readable by either VO or NVDA (bug 1912001)

This commit is contained in:
Calixte Denizet 2024-09-03 16:49:22 +02:00
parent 0676ea19cf
commit deedbd1c4f
5 changed files with 110 additions and 37 deletions

View file

@ -92,11 +92,12 @@ class AnnotationLayerBuilder {
/**
* @param {PageViewport} viewport
* @param {Object} options
* @param {string} intent (default value is 'display')
* @returns {Promise<void>} A promise that is resolved when rendering of the
* annotations is complete.
*/
async render(viewport, intent = "display") {
async render(viewport, options, intent = "display") {
if (this.div) {
if (this._cancelled || !this.annotationLayer) {
return;
@ -136,6 +137,7 @@ class AnnotationLayerBuilder {
annotationEditorUIManager: this._annotationEditorUIManager,
page: this.pdfPage,
viewport: viewport.clone({ dontFlip: true }),
structTreeLayer: options?.structTreeLayer || null,
});
await this.annotationLayer.render({

View file

@ -383,7 +383,11 @@ class PDFPageView {
async #renderAnnotationLayer() {
let error = null;
try {
await this.annotationLayer.render(this.viewport, "display");
await this.annotationLayer.render(
this.viewport,
{ structTreeLayer: this.structTreeLayer },
"display"
);
} catch (ex) {
console.error(`#renderAnnotationLayer: "${ex}".`);
error = ex;
@ -468,16 +472,12 @@ class PDFPageView {
if (!this.textLayer) {
return;
}
this.structTreeLayer ||= new StructTreeLayerBuilder();
const tree = await (!this.structTreeLayer.renderingDone
? this.pdfPage.getStructTree()
: null);
const treeDom = this.structTreeLayer?.render(tree);
if (treeDom) {
const treeDom = await this.structTreeLayer?.render();
if (treeDom && this.canvas && treeDom.parentNode !== this.canvas) {
// Pause translation when inserting the structTree in the DOM.
this.l10n.pause();
this.canvas?.append(treeDom);
this.canvas.append(treeDom);
this.l10n.resume();
}
this.structTreeLayer?.show();
@ -760,9 +760,6 @@ class PDFPageView {
this.textLayer.cancel();
this.textLayer = null;
}
if (this.structTreeLayer && !this.textLayer) {
this.structTreeLayer = null;
}
if (
this.annotationLayer &&
(!keepAnnotationLayer || !this.annotationLayer.div)
@ -771,6 +768,9 @@ class PDFPageView {
this.annotationLayer = null;
this._annotationCanvasMap = null;
}
if (this.structTreeLayer && !(this.textLayer || this.annotationLayer)) {
this.structTreeLayer = null;
}
if (
this.annotationEditorLayer &&
(!keepAnnotationEditorLayer || !this.annotationEditorLayer.div)
@ -1067,6 +1067,10 @@ class PDFPageView {
showCanvas?.(true);
await this.#finishRenderTask(renderTask);
if (this.textLayer || this.annotationLayer) {
this.structTreeLayer ||= new StructTreeLayerBuilder(pdfPage);
}
this.#renderTextLayer();
if (this.annotationLayer) {

View file

@ -74,19 +74,29 @@ const PDF_ROLE_TO_HTML_ROLE = {
const HEADING_PATTERN = /^H(\d+)$/;
class StructTreeLayerBuilder {
#promise;
#treeDom = undefined;
get renderingDone() {
return this.#treeDom !== undefined;
#elementAttributes = new Map();
constructor(pdfPage) {
this.#promise = pdfPage.getStructTree();
}
render(structTree) {
async render() {
if (this.#treeDom !== undefined) {
return this.#treeDom;
}
const treeDom = this.#walk(structTree);
const treeDom = (this.#treeDom = this.#walk(await this.#promise));
this.#promise = null;
treeDom?.classList.add("structTree");
return (this.#treeDom = treeDom);
return treeDom;
}
async getAriaAttributes(annotationId) {
await this.render();
return this.#elementAttributes.get(annotationId);
}
hide() {
@ -104,7 +114,24 @@ class StructTreeLayerBuilder {
#setAttributes(structElement, htmlElement) {
const { alt, id, lang } = structElement;
if (alt !== undefined) {
htmlElement.setAttribute("aria-label", removeNullCharacters(alt));
// Don't add the label in the struct tree layer but on the annotation
// in the annotation layer.
let added = false;
const label = removeNullCharacters(alt);
for (const child of structElement.children) {
if (child.type === "annotation") {
let attrs = this.#elementAttributes.get(child.id);
if (!attrs) {
attrs = new Map();
this.#elementAttributes.set(child.id, attrs);
}
attrs.set("aria-label", label);
added = true;
}
}
if (!added) {
htmlElement.setAttribute("aria-label", label);
}
}
if (id !== undefined) {
htmlElement.setAttribute("aria-owns", id);