2021-04-01 07:07:02 +09:00
|
|
|
/* Copyright 2021 Mozilla Foundation
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
2021-12-15 07:59:17 +09:00
|
|
|
/** @typedef {import("../src/display/api").PDFPageProxy} PDFPageProxy */
|
Fix Viewer API definitions and include in CI
The Viewer API definitions do not compile because of missing imports and
anonymous objects are typed as `Object`. These issues were not caught
during CI because the test project was not compiling anything from the
Viewer API.
As an example of the first problem:
```
/**
* @implements MyInterface
*/
export class MyClass {
...
}
```
will generate a broken definition that doesn’t import MyInterface:
```
/**
* @implements MyInterface
*/
export class MyClass implements MyInterface {
...
}
```
This can be fixed by adding a typedef jsdoc to specify the import:
```
/** @typedef {import("./otherFile").MyInterface} MyInterface */
```
See https://github.com/jsdoc/jsdoc/issues/1537 and
https://github.com/microsoft/TypeScript/issues/22160 for more details.
As an example of the second problem:
```
/**
* Gets the size of the specified page, converted from PDF units to inches.
* @param {Object} An Object containing the properties: {Array} `view`,
* {number} `userUnit`, and {number} `rotate`.
*/
function getPageSizeInches({ view, userUnit, rotate }) {
...
}
```
generates the broken definition:
```
function getPageSizeInches({ view, userUnit, rotate }: Object) {
...
}
```
The jsdoc should specify the type of each nested property:
```
/**
* Gets the size of the specified page, converted from PDF units to inches.
* @param {Object} options An object containing the properties: {Array} `view`,
* {number} `userUnit`, and {number} `rotate`.
* @param {number[]} options.view
* @param {number} options.userUnit
* @param {number} options.rotate
*/
```
2021-08-26 07:44:06 +09:00
|
|
|
|
2021-04-01 07:07:02 +09:00
|
|
|
const PDF_ROLE_TO_HTML_ROLE = {
|
|
|
|
// Document level structure types
|
|
|
|
Document: null, // There's a "document" role, but it doesn't make sense here.
|
|
|
|
DocumentFragment: null,
|
|
|
|
// Grouping level structure types
|
|
|
|
Part: "group",
|
|
|
|
Sect: "group", // XXX: There's a "section" role, but it's abstract.
|
|
|
|
Div: "group",
|
|
|
|
Aside: "note",
|
|
|
|
NonStruct: "none",
|
|
|
|
// Block level structure types
|
|
|
|
P: null,
|
|
|
|
// H<n>,
|
|
|
|
H: "heading",
|
|
|
|
Title: null,
|
|
|
|
FENote: "note",
|
|
|
|
// Sub-block level structure type
|
|
|
|
Sub: "group",
|
|
|
|
// General inline level structure types
|
|
|
|
Lbl: null,
|
|
|
|
Span: null,
|
|
|
|
Em: null,
|
|
|
|
Strong: null,
|
|
|
|
Link: "link",
|
|
|
|
Annot: "note",
|
|
|
|
Form: "form",
|
|
|
|
// Ruby and Warichu structure types
|
|
|
|
Ruby: null,
|
|
|
|
RB: null,
|
|
|
|
RT: null,
|
|
|
|
RP: null,
|
|
|
|
Warichu: null,
|
|
|
|
WT: null,
|
|
|
|
WP: null,
|
|
|
|
// List standard structure types
|
|
|
|
L: "list",
|
|
|
|
LI: "listitem",
|
|
|
|
LBody: null,
|
|
|
|
// Table standard structure types
|
|
|
|
Table: "table",
|
|
|
|
TR: "row",
|
|
|
|
TH: "columnheader",
|
|
|
|
TD: "cell",
|
|
|
|
THead: "columnheader",
|
|
|
|
TBody: null,
|
|
|
|
TFoot: null,
|
|
|
|
// Standard structure type Caption
|
|
|
|
Caption: null,
|
|
|
|
// Standard structure type Figure
|
|
|
|
Figure: "figure",
|
|
|
|
// Standard structure type Formula
|
|
|
|
Formula: null,
|
|
|
|
// standard structure type Artifact
|
|
|
|
Artifact: null,
|
|
|
|
};
|
|
|
|
|
|
|
|
const HEADING_PATTERN = /^H(\d+)$/;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @typedef {Object} StructTreeLayerBuilderOptions
|
2021-12-15 07:59:17 +09:00
|
|
|
* @property {PDFPageProxy} pdfPage
|
2021-04-01 07:07:02 +09:00
|
|
|
*/
|
|
|
|
|
|
|
|
class StructTreeLayerBuilder {
|
|
|
|
/**
|
|
|
|
* @param {StructTreeLayerBuilderOptions} options
|
|
|
|
*/
|
|
|
|
constructor({ pdfPage }) {
|
|
|
|
this.pdfPage = pdfPage;
|
|
|
|
}
|
|
|
|
|
|
|
|
render(structTree) {
|
|
|
|
return this._walk(structTree);
|
|
|
|
}
|
|
|
|
|
|
|
|
_setAttributes(structElement, htmlElement) {
|
|
|
|
if (structElement.alt !== undefined) {
|
|
|
|
htmlElement.setAttribute("aria-label", structElement.alt);
|
|
|
|
}
|
|
|
|
if (structElement.id !== undefined) {
|
|
|
|
htmlElement.setAttribute("aria-owns", structElement.id);
|
|
|
|
}
|
2021-11-11 22:36:18 +09:00
|
|
|
if (structElement.lang !== undefined) {
|
|
|
|
htmlElement.setAttribute("lang", structElement.lang);
|
|
|
|
}
|
2021-04-01 07:07:02 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
_walk(node) {
|
|
|
|
if (!node) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
const element = document.createElement("span");
|
|
|
|
if ("role" in node) {
|
|
|
|
const { role } = node;
|
|
|
|
const match = role.match(HEADING_PATTERN);
|
|
|
|
if (match) {
|
|
|
|
element.setAttribute("role", "heading");
|
|
|
|
element.setAttribute("aria-level", match[1]);
|
|
|
|
} else if (PDF_ROLE_TO_HTML_ROLE[role]) {
|
|
|
|
element.setAttribute("role", PDF_ROLE_TO_HTML_ROLE[role]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
this._setAttributes(node, element);
|
|
|
|
|
|
|
|
if (node.children) {
|
|
|
|
if (node.children.length === 1 && "id" in node.children[0]) {
|
|
|
|
// Often there is only one content node so just set the values on the
|
|
|
|
// parent node to avoid creating an extra span.
|
|
|
|
this._setAttributes(node.children[0], element);
|
|
|
|
} else {
|
|
|
|
for (const kid of node.children) {
|
2022-06-12 19:20:25 +09:00
|
|
|
element.append(this._walk(kid));
|
2021-04-01 07:07:02 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return element;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-15 21:54:29 +09:00
|
|
|
export { StructTreeLayerBuilder };
|