Merge pull request #16886 from calixteman/struct_tree_annotation
Add tagged annotations in the structure tree (bug 1850797)
This commit is contained in:
		
						commit
						20b0be973c
					
				@ -77,10 +77,11 @@ class AnnotationFactory {
 | 
				
			|||||||
   * @param {PDFManager} pdfManager
 | 
					   * @param {PDFManager} pdfManager
 | 
				
			||||||
   * @param {Object} idFactory
 | 
					   * @param {Object} idFactory
 | 
				
			||||||
   * @param {boolean} collectFields
 | 
					   * @param {boolean} collectFields
 | 
				
			||||||
 | 
					   * @param {Object} [pageRef]
 | 
				
			||||||
   * @returns {Promise} A promise that is resolved with an {Annotation}
 | 
					   * @returns {Promise} A promise that is resolved with an {Annotation}
 | 
				
			||||||
   *   instance.
 | 
					   *   instance.
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  static create(xref, ref, pdfManager, idFactory, collectFields) {
 | 
					  static create(xref, ref, pdfManager, idFactory, collectFields, pageRef) {
 | 
				
			||||||
    return Promise.all([
 | 
					    return Promise.all([
 | 
				
			||||||
      pdfManager.ensureCatalog("acroForm"),
 | 
					      pdfManager.ensureCatalog("acroForm"),
 | 
				
			||||||
      // Only necessary to prevent the `pdfManager.docBaseUrl`-getter, used
 | 
					      // Only necessary to prevent the `pdfManager.docBaseUrl`-getter, used
 | 
				
			||||||
@ -91,18 +92,29 @@ class AnnotationFactory {
 | 
				
			|||||||
      pdfManager.ensureCatalog("attachments"),
 | 
					      pdfManager.ensureCatalog("attachments"),
 | 
				
			||||||
      pdfManager.ensureDoc("xfaDatasets"),
 | 
					      pdfManager.ensureDoc("xfaDatasets"),
 | 
				
			||||||
      collectFields ? this._getPageIndex(xref, ref, pdfManager) : -1,
 | 
					      collectFields ? this._getPageIndex(xref, ref, pdfManager) : -1,
 | 
				
			||||||
    ]).then(([acroForm, baseUrl, attachments, xfaDatasets, pageIndex]) =>
 | 
					      pageRef ? pdfManager.ensureCatalog("structTreeRoot") : null,
 | 
				
			||||||
      pdfManager.ensure(this, "_create", [
 | 
					    ]).then(
 | 
				
			||||||
        xref,
 | 
					      ([
 | 
				
			||||||
        ref,
 | 
					 | 
				
			||||||
        pdfManager,
 | 
					 | 
				
			||||||
        idFactory,
 | 
					 | 
				
			||||||
        acroForm,
 | 
					        acroForm,
 | 
				
			||||||
 | 
					        baseUrl,
 | 
				
			||||||
        attachments,
 | 
					        attachments,
 | 
				
			||||||
        xfaDatasets,
 | 
					        xfaDatasets,
 | 
				
			||||||
        collectFields,
 | 
					 | 
				
			||||||
        pageIndex,
 | 
					        pageIndex,
 | 
				
			||||||
      ])
 | 
					        structTreeRoot,
 | 
				
			||||||
 | 
					      ]) =>
 | 
				
			||||||
 | 
					        pdfManager.ensure(this, "_create", [
 | 
				
			||||||
 | 
					          xref,
 | 
				
			||||||
 | 
					          ref,
 | 
				
			||||||
 | 
					          pdfManager,
 | 
				
			||||||
 | 
					          idFactory,
 | 
				
			||||||
 | 
					          acroForm,
 | 
				
			||||||
 | 
					          attachments,
 | 
				
			||||||
 | 
					          xfaDatasets,
 | 
				
			||||||
 | 
					          collectFields,
 | 
				
			||||||
 | 
					          pageIndex,
 | 
				
			||||||
 | 
					          structTreeRoot,
 | 
				
			||||||
 | 
					          pageRef,
 | 
				
			||||||
 | 
					        ])
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -118,7 +130,9 @@ class AnnotationFactory {
 | 
				
			|||||||
    attachments = null,
 | 
					    attachments = null,
 | 
				
			||||||
    xfaDatasets,
 | 
					    xfaDatasets,
 | 
				
			||||||
    collectFields,
 | 
					    collectFields,
 | 
				
			||||||
    pageIndex = -1
 | 
					    pageIndex = -1,
 | 
				
			||||||
 | 
					    structTreeRoot = null,
 | 
				
			||||||
 | 
					    pageRef = null
 | 
				
			||||||
  ) {
 | 
					  ) {
 | 
				
			||||||
    const dict = xref.fetchIfRef(ref);
 | 
					    const dict = xref.fetchIfRef(ref);
 | 
				
			||||||
    if (!(dict instanceof Dict)) {
 | 
					    if (!(dict instanceof Dict)) {
 | 
				
			||||||
@ -150,6 +164,8 @@ class AnnotationFactory {
 | 
				
			|||||||
        !collectFields && acroFormDict.get("NeedAppearances") === true,
 | 
					        !collectFields && acroFormDict.get("NeedAppearances") === true,
 | 
				
			||||||
      pageIndex,
 | 
					      pageIndex,
 | 
				
			||||||
      evaluatorOptions: pdfManager.evaluatorOptions,
 | 
					      evaluatorOptions: pdfManager.evaluatorOptions,
 | 
				
			||||||
 | 
					      structTreeRoot,
 | 
				
			||||||
 | 
					      pageRef,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    switch (subtype) {
 | 
					    switch (subtype) {
 | 
				
			||||||
@ -594,6 +610,13 @@ class Annotation {
 | 
				
			|||||||
    const isLocked = !!(this.flags & AnnotationFlag.LOCKED);
 | 
					    const isLocked = !!(this.flags & AnnotationFlag.LOCKED);
 | 
				
			||||||
    const isContentLocked = !!(this.flags & AnnotationFlag.LOCKEDCONTENTS);
 | 
					    const isContentLocked = !!(this.flags & AnnotationFlag.LOCKEDCONTENTS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (params.structTreeRoot) {
 | 
				
			||||||
 | 
					      let structParent = dict.get("StructParent");
 | 
				
			||||||
 | 
					      structParent =
 | 
				
			||||||
 | 
					        Number.isInteger(structParent) && structParent >= 0 ? structParent : -1;
 | 
				
			||||||
 | 
					      params.structTreeRoot.addAnnotationIdToPage(params.pageRef, structParent);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Expose public properties using a data object.
 | 
					    // Expose public properties using a data object.
 | 
				
			||||||
    this.data = {
 | 
					    this.data = {
 | 
				
			||||||
      annotationFlags: this.flags,
 | 
					      annotationFlags: this.flags,
 | 
				
			||||||
 | 
				
			|||||||
@ -651,6 +651,9 @@ class Page {
 | 
				
			|||||||
    if (!structTreeRoot) {
 | 
					    if (!structTreeRoot) {
 | 
				
			||||||
      return null;
 | 
					      return null;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    // Ensure that the structTree will contain the page's annotations.
 | 
				
			||||||
 | 
					    await this._parsedAnnotations;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const structTree = await this.pdfManager.ensure(this, "_parseStructTree", [
 | 
					    const structTree = await this.pdfManager.ensure(this, "_parseStructTree", [
 | 
				
			||||||
      structTreeRoot,
 | 
					      structTreeRoot,
 | 
				
			||||||
    ]);
 | 
					    ]);
 | 
				
			||||||
@ -662,7 +665,7 @@ class Page {
 | 
				
			|||||||
   */
 | 
					   */
 | 
				
			||||||
  _parseStructTree(structTreeRoot) {
 | 
					  _parseStructTree(structTreeRoot) {
 | 
				
			||||||
    const tree = new StructTreePage(structTreeRoot, this.pageDict);
 | 
					    const tree = new StructTreePage(structTreeRoot, this.pageDict);
 | 
				
			||||||
    tree.parse();
 | 
					    tree.parse(this.ref);
 | 
				
			||||||
    return tree;
 | 
					    return tree;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -740,7 +743,8 @@ class Page {
 | 
				
			|||||||
              annotationRef,
 | 
					              annotationRef,
 | 
				
			||||||
              this.pdfManager,
 | 
					              this.pdfManager,
 | 
				
			||||||
              this._localIdFactory,
 | 
					              this._localIdFactory,
 | 
				
			||||||
              /* collectFields */ false
 | 
					              /* collectFields */ false,
 | 
				
			||||||
 | 
					              this.ref
 | 
				
			||||||
            ).catch(function (reason) {
 | 
					            ).catch(function (reason) {
 | 
				
			||||||
              warn(`_parsedAnnotations: "${reason}".`);
 | 
					              warn(`_parsedAnnotations: "${reason}".`);
 | 
				
			||||||
              return null;
 | 
					              return null;
 | 
				
			||||||
@ -1719,7 +1723,8 @@ class PDFDocument {
 | 
				
			|||||||
        fieldRef,
 | 
					        fieldRef,
 | 
				
			||||||
        this.pdfManager,
 | 
					        this.pdfManager,
 | 
				
			||||||
        this._localIdFactory,
 | 
					        this._localIdFactory,
 | 
				
			||||||
        /* collectFields */ true
 | 
					        /* collectFields */ true,
 | 
				
			||||||
 | 
					        /* pageRef */ null
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
        .then(annotation => annotation?.getFieldObject())
 | 
					        .then(annotation => annotation?.getFieldObject())
 | 
				
			||||||
        .catch(function (reason) {
 | 
					        .catch(function (reason) {
 | 
				
			||||||
 | 
				
			|||||||
@ -13,29 +13,48 @@
 | 
				
			|||||||
 * limitations under the License.
 | 
					 * limitations under the License.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Dict, isName, Name, Ref } from "./primitives.js";
 | 
					import { AnnotationPrefix, stringToPDFString, warn } from "../shared/util.js";
 | 
				
			||||||
import { stringToPDFString, warn } from "../shared/util.js";
 | 
					import { Dict, isName, Name, Ref, RefSetCache } from "./primitives.js";
 | 
				
			||||||
import { NumberTree } from "./name_number_tree.js";
 | 
					import { NumberTree } from "./name_number_tree.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const MAX_DEPTH = 40;
 | 
					const MAX_DEPTH = 40;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const StructElementType = {
 | 
					const StructElementType = {
 | 
				
			||||||
  PAGE_CONTENT: "PAGE_CONTENT",
 | 
					  PAGE_CONTENT: 1,
 | 
				
			||||||
  STREAM_CONTENT: "STREAM_CONTENT",
 | 
					  STREAM_CONTENT: 2,
 | 
				
			||||||
  OBJECT: "OBJECT",
 | 
					  OBJECT: 3,
 | 
				
			||||||
  ELEMENT: "ELEMENT",
 | 
					  ANNOTATION: 4,
 | 
				
			||||||
 | 
					  ELEMENT: 5,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class StructTreeRoot {
 | 
					class StructTreeRoot {
 | 
				
			||||||
  constructor(rootDict) {
 | 
					  constructor(rootDict) {
 | 
				
			||||||
    this.dict = rootDict;
 | 
					    this.dict = rootDict;
 | 
				
			||||||
    this.roleMap = new Map();
 | 
					    this.roleMap = new Map();
 | 
				
			||||||
 | 
					    this.structParentIds = null;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  init() {
 | 
					  init() {
 | 
				
			||||||
    this.readRoleMap();
 | 
					    this.readRoleMap();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  #addIdToPage(pageRef, id, type) {
 | 
				
			||||||
 | 
					    if (!(pageRef instanceof Ref) || id < 0) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.structParentIds ||= new RefSetCache();
 | 
				
			||||||
 | 
					    let ids = this.structParentIds.get(pageRef);
 | 
				
			||||||
 | 
					    if (!ids) {
 | 
				
			||||||
 | 
					      ids = [];
 | 
				
			||||||
 | 
					      this.structParentIds.put(pageRef, ids);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    ids.push([id, type]);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  addAnnotationIdToPage(pageRef, id) {
 | 
				
			||||||
 | 
					    this.#addIdToPage(pageRef, id, StructElementType.ANNOTATION);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  readRoleMap() {
 | 
					  readRoleMap() {
 | 
				
			||||||
    const roleMapDict = this.dict.get("RoleMap");
 | 
					    const roleMapDict = this.dict.get("RoleMap");
 | 
				
			||||||
    if (!(roleMapDict instanceof Dict)) {
 | 
					    if (!(roleMapDict instanceof Dict)) {
 | 
				
			||||||
@ -129,12 +148,10 @@ class StructElementNode {
 | 
				
			|||||||
      if (this.tree.pageDict.objId !== pageObjId) {
 | 
					      if (this.tree.pageDict.objId !== pageObjId) {
 | 
				
			||||||
        return null;
 | 
					        return null;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					      const kidRef = kidDict.getRaw("Stm");
 | 
				
			||||||
      return new StructElement({
 | 
					      return new StructElement({
 | 
				
			||||||
        type: StructElementType.STREAM_CONTENT,
 | 
					        type: StructElementType.STREAM_CONTENT,
 | 
				
			||||||
        refObjId:
 | 
					        refObjId: kidRef instanceof Ref ? kidRef.toString() : null,
 | 
				
			||||||
          kidDict.getRaw("Stm") instanceof Ref
 | 
					 | 
				
			||||||
            ? kidDict.getRaw("Stm").toString()
 | 
					 | 
				
			||||||
            : null,
 | 
					 | 
				
			||||||
        pageObjId,
 | 
					        pageObjId,
 | 
				
			||||||
        mcid: kidDict.get("MCID"),
 | 
					        mcid: kidDict.get("MCID"),
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
@ -144,12 +161,10 @@ class StructElementNode {
 | 
				
			|||||||
      if (this.tree.pageDict.objId !== pageObjId) {
 | 
					      if (this.tree.pageDict.objId !== pageObjId) {
 | 
				
			||||||
        return null;
 | 
					        return null;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					      const kidRef = kidDict.getRaw("Obj");
 | 
				
			||||||
      return new StructElement({
 | 
					      return new StructElement({
 | 
				
			||||||
        type: StructElementType.OBJECT,
 | 
					        type: StructElementType.OBJECT,
 | 
				
			||||||
        refObjId:
 | 
					        refObjId: kidRef instanceof Ref ? kidRef.toString() : null,
 | 
				
			||||||
          kidDict.getRaw("Obj") instanceof Ref
 | 
					 | 
				
			||||||
            ? kidDict.getRaw("Obj").toString()
 | 
					 | 
				
			||||||
            : null,
 | 
					 | 
				
			||||||
        pageObjId,
 | 
					        pageObjId,
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -186,7 +201,7 @@ class StructTreePage {
 | 
				
			|||||||
    this.nodes = [];
 | 
					    this.nodes = [];
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  parse() {
 | 
					  parse(pageRef) {
 | 
				
			||||||
    if (!this.root || !this.rootDict) {
 | 
					    if (!this.root || !this.rootDict) {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -196,18 +211,42 @@ class StructTreePage {
 | 
				
			|||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    const id = this.pageDict.get("StructParents");
 | 
					    const id = this.pageDict.get("StructParents");
 | 
				
			||||||
    if (!Number.isInteger(id)) {
 | 
					    const ids =
 | 
				
			||||||
      return;
 | 
					      pageRef instanceof Ref && this.root.structParentIds?.get(pageRef);
 | 
				
			||||||
    }
 | 
					    if (!Number.isInteger(id) && !ids) {
 | 
				
			||||||
    const numberTree = new NumberTree(parentTree, this.rootDict.xref);
 | 
					 | 
				
			||||||
    const parentArray = numberTree.get(id);
 | 
					 | 
				
			||||||
    if (!Array.isArray(parentArray)) {
 | 
					 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const map = new Map();
 | 
					    const map = new Map();
 | 
				
			||||||
    for (const ref of parentArray) {
 | 
					    const numberTree = new NumberTree(parentTree, this.rootDict.xref);
 | 
				
			||||||
      if (ref instanceof Ref) {
 | 
					
 | 
				
			||||||
        this.addNode(this.rootDict.xref.fetch(ref), map);
 | 
					    if (Number.isInteger(id)) {
 | 
				
			||||||
 | 
					      const parentArray = numberTree.get(id);
 | 
				
			||||||
 | 
					      if (Array.isArray(parentArray)) {
 | 
				
			||||||
 | 
					        for (const ref of parentArray) {
 | 
				
			||||||
 | 
					          if (ref instanceof Ref) {
 | 
				
			||||||
 | 
					            this.addNode(this.rootDict.xref.fetch(ref), map);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!ids) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for (const [elemId, type] of ids) {
 | 
				
			||||||
 | 
					      const obj = numberTree.get(elemId);
 | 
				
			||||||
 | 
					      if (obj) {
 | 
				
			||||||
 | 
					        const elem = this.addNode(this.rootDict.xref.fetchIfRef(obj), map);
 | 
				
			||||||
 | 
					        if (
 | 
				
			||||||
 | 
					          elem?.kids?.length === 1 &&
 | 
				
			||||||
 | 
					          elem.kids[0].type === StructElementType.OBJECT
 | 
				
			||||||
 | 
					        ) {
 | 
				
			||||||
 | 
					          // The node in the struct tree is wrapping an object (annotation
 | 
				
			||||||
 | 
					          // or xobject), so we need to update the type of the node to match
 | 
				
			||||||
 | 
					          // the type of the object.
 | 
				
			||||||
 | 
					          elem.kids[0].type = type;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -322,6 +361,11 @@ class StructTreePage {
 | 
				
			|||||||
            type: "object",
 | 
					            type: "object",
 | 
				
			||||||
            id: kid.refObjId,
 | 
					            id: kid.refObjId,
 | 
				
			||||||
          });
 | 
					          });
 | 
				
			||||||
 | 
					        } else if (kid.type === StructElementType.ANNOTATION) {
 | 
				
			||||||
 | 
					          obj.children.push({
 | 
				
			||||||
 | 
					            type: "annotation",
 | 
				
			||||||
 | 
					            id: `${AnnotationPrefix}${kid.refObjId}`,
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -21,6 +21,7 @@
 | 
				
			|||||||
import {
 | 
					import {
 | 
				
			||||||
  AnnotationBorderStyleType,
 | 
					  AnnotationBorderStyleType,
 | 
				
			||||||
  AnnotationEditorType,
 | 
					  AnnotationEditorType,
 | 
				
			||||||
 | 
					  AnnotationPrefix,
 | 
				
			||||||
  AnnotationType,
 | 
					  AnnotationType,
 | 
				
			||||||
  FeatureTest,
 | 
					  FeatureTest,
 | 
				
			||||||
  LINE_FACTOR,
 | 
					  LINE_FACTOR,
 | 
				
			||||||
@ -30,7 +31,6 @@ import {
 | 
				
			|||||||
  warn,
 | 
					  warn,
 | 
				
			||||||
} from "../shared/util.js";
 | 
					} from "../shared/util.js";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  AnnotationPrefix,
 | 
					 | 
				
			||||||
  DOMSVGFactory,
 | 
					  DOMSVGFactory,
 | 
				
			||||||
  getFilenameFromUrl,
 | 
					  getFilenameFromUrl,
 | 
				
			||||||
  PDFDateString,
 | 
					  PDFDateString,
 | 
				
			||||||
 | 
				
			|||||||
@ -31,8 +31,6 @@ import {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const SVG_NS = "http://www.w3.org/2000/svg";
 | 
					const SVG_NS = "http://www.w3.org/2000/svg";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const AnnotationPrefix = "pdfjs_internal_id_";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class PixelsPerInch {
 | 
					class PixelsPerInch {
 | 
				
			||||||
  static CSS = 96.0;
 | 
					  static CSS = 96.0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1005,7 +1003,6 @@ function setLayerDimensions(
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export {
 | 
					export {
 | 
				
			||||||
  AnnotationPrefix,
 | 
					 | 
				
			||||||
  deprecated,
 | 
					  deprecated,
 | 
				
			||||||
  DOMCanvasFactory,
 | 
					  DOMCanvasFactory,
 | 
				
			||||||
  DOMCMapReaderFactory,
 | 
					  DOMCMapReaderFactory,
 | 
				
			||||||
 | 
				
			|||||||
@ -1047,6 +1047,8 @@ function getUuid() {
 | 
				
			|||||||
  return bytesToString(buf);
 | 
					  return bytesToString(buf);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const AnnotationPrefix = "pdfjs_internal_id_";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export {
 | 
					export {
 | 
				
			||||||
  AbortException,
 | 
					  AbortException,
 | 
				
			||||||
  AnnotationActionEventType,
 | 
					  AnnotationActionEventType,
 | 
				
			||||||
@ -1057,6 +1059,7 @@ export {
 | 
				
			|||||||
  AnnotationFieldFlag,
 | 
					  AnnotationFieldFlag,
 | 
				
			||||||
  AnnotationFlag,
 | 
					  AnnotationFlag,
 | 
				
			||||||
  AnnotationMode,
 | 
					  AnnotationMode,
 | 
				
			||||||
 | 
					  AnnotationPrefix,
 | 
				
			||||||
  AnnotationReplyType,
 | 
					  AnnotationReplyType,
 | 
				
			||||||
  AnnotationType,
 | 
					  AnnotationType,
 | 
				
			||||||
  assert,
 | 
					  assert,
 | 
				
			||||||
 | 
				
			|||||||
@ -139,4 +139,35 @@ describe("accessibility", () => {
 | 
				
			|||||||
      );
 | 
					      );
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe("Stamp annotation accessibility", () => {
 | 
				
			||||||
 | 
					    let pages;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    beforeAll(async () => {
 | 
				
			||||||
 | 
					      pages = await loadAndWait("tagged_stamp.pdf", ".annotationLayer");
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    afterAll(async () => {
 | 
				
			||||||
 | 
					      await closePages(pages);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it("must check that the stamp annotation is linked to the struct tree", async () => {
 | 
				
			||||||
 | 
					      await Promise.all(
 | 
				
			||||||
 | 
					        pages.map(async ([browserName, page]) => {
 | 
				
			||||||
 | 
					          await page.waitForSelector(".structTree");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          const isLinkedToStampAnnotation = await page.$eval(
 | 
				
			||||||
 | 
					            ".structTree [role='figure']",
 | 
				
			||||||
 | 
					            el =>
 | 
				
			||||||
 | 
					              document
 | 
				
			||||||
 | 
					                .getElementById(el.getAttribute("aria-owns"))
 | 
				
			||||||
 | 
					                .classList.contains("stampAnnotation")
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
 | 
					          expect(isLinkedToStampAnnotation)
 | 
				
			||||||
 | 
					            .withContext(`In ${browserName}`)
 | 
				
			||||||
 | 
					            .toEqual(true);
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										1
									
								
								test/pdfs/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								test/pdfs/.gitignore
									
									
									
									
										vendored
									
									
								
							@ -610,3 +610,4 @@
 | 
				
			|||||||
!annotation_hidden_noview.pdf
 | 
					!annotation_hidden_noview.pdf
 | 
				
			||||||
!widget_hidden_print.pdf
 | 
					!widget_hidden_print.pdf
 | 
				
			||||||
!empty_protected.pdf
 | 
					!empty_protected.pdf
 | 
				
			||||||
 | 
					!tagged_stamp.pdf
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										
											BIN
										
									
								
								test/pdfs/tagged_stamp.pdf
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								test/pdfs/tagged_stamp.pdf
									
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							@ -100,14 +100,15 @@ class StructTreeLayerBuilder {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  #setAttributes(structElement, htmlElement) {
 | 
					  #setAttributes(structElement, htmlElement) {
 | 
				
			||||||
    if (structElement.alt !== undefined) {
 | 
					    const { alt, id, lang } = structElement;
 | 
				
			||||||
      htmlElement.setAttribute("aria-label", structElement.alt);
 | 
					    if (alt !== undefined) {
 | 
				
			||||||
 | 
					      htmlElement.setAttribute("aria-label", alt);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (structElement.id !== undefined) {
 | 
					    if (id !== undefined) {
 | 
				
			||||||
      htmlElement.setAttribute("aria-owns", structElement.id);
 | 
					      htmlElement.setAttribute("aria-owns", id);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (structElement.lang !== undefined) {
 | 
					    if (lang !== undefined) {
 | 
				
			||||||
      htmlElement.setAttribute("lang", structElement.lang);
 | 
					      htmlElement.setAttribute("lang", lang);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user