mirror of
https://github.com/mozilla/pdf.js.git
synced 2025-04-22 08:08:07 +02:00
Merge pull request #13171 from brendandahl/struct-tree
[api-minor] Add support for basic structure tree for accessibility.
This commit is contained in:
commit
03c8c89002
22 changed files with 911 additions and 14 deletions
|
@ -572,6 +572,7 @@ var Driver = (function DriverClosure() {
|
|||
initPromise = page
|
||||
.getTextContent({
|
||||
normalizeWhitespace: true,
|
||||
includeMarkedContent: true,
|
||||
})
|
||||
.then(function (textContent) {
|
||||
return rasterizeTextLayer(
|
||||
|
|
|
@ -24,7 +24,11 @@ async function runTests(results) {
|
|||
jasmine.loadConfig({
|
||||
random: false,
|
||||
spec_dir: "integration",
|
||||
spec_files: ["scripting_spec.js", "annotation_spec.js"],
|
||||
spec_files: [
|
||||
"scripting_spec.js",
|
||||
"annotation_spec.js",
|
||||
"accessibility_spec.js",
|
||||
],
|
||||
});
|
||||
|
||||
jasmine.addReporter({
|
||||
|
|
69
test/integration/accessibility_spec.js
Normal file
69
test/integration/accessibility_spec.js
Normal file
|
@ -0,0 +1,69 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
const { closePages, loadAndWait } = require("./test_utils.js");
|
||||
|
||||
describe("accessibility", () => {
|
||||
describe("structure tree", () => {
|
||||
let pages;
|
||||
|
||||
beforeAll(async () => {
|
||||
pages = await loadAndWait("structure_simple.pdf", ".structTree");
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await closePages(pages);
|
||||
});
|
||||
|
||||
it("must build structure that maps to text layer", async () => {
|
||||
await Promise.all(
|
||||
pages.map(async ([browserName, page]) => {
|
||||
await page.waitForSelector(".structTree");
|
||||
|
||||
// Check the headings match up.
|
||||
const head1 = await page.$eval(
|
||||
".structTree [role='heading'][aria-level='1'] span",
|
||||
el =>
|
||||
document.getElementById(el.getAttribute("aria-owns")).textContent
|
||||
);
|
||||
expect(head1).withContext(`In ${browserName}`).toEqual("Heading 1");
|
||||
const head2 = await page.$eval(
|
||||
".structTree [role='heading'][aria-level='2'] span",
|
||||
el =>
|
||||
document.getElementById(el.getAttribute("aria-owns")).textContent
|
||||
);
|
||||
expect(head2).withContext(`In ${browserName}`).toEqual("Heading 2");
|
||||
|
||||
// Check the order of the content.
|
||||
const texts = await page.$$eval(".structTree [aria-owns]", nodes =>
|
||||
nodes.map(
|
||||
el =>
|
||||
document.getElementById(el.getAttribute("aria-owns"))
|
||||
.textContent
|
||||
)
|
||||
);
|
||||
expect(texts)
|
||||
.withContext(`In ${browserName}`)
|
||||
.toEqual([
|
||||
"Heading 1",
|
||||
"This paragraph 1.",
|
||||
"Heading 2",
|
||||
"This paragraph 2.",
|
||||
]);
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
1
test/pdfs/.gitignore
vendored
1
test/pdfs/.gitignore
vendored
|
@ -71,6 +71,7 @@
|
|||
!issue8570.pdf
|
||||
!issue8697.pdf
|
||||
!issue8702.pdf
|
||||
!structure_simple.pdf
|
||||
!issue12823.pdf
|
||||
!issue8707.pdf
|
||||
!issue8798r.pdf
|
||||
|
|
BIN
test/pdfs/structure_simple.pdf
Normal file
BIN
test/pdfs/structure_simple.pdf
Normal file
Binary file not shown.
|
@ -23,7 +23,7 @@
|
|||
bottom: 0;
|
||||
line-height: 1;
|
||||
}
|
||||
.textLayer > span {
|
||||
.textLayer span {
|
||||
position: absolute;
|
||||
white-space: pre;
|
||||
-webkit-transform-origin: 0% 0%;
|
||||
|
@ -37,3 +37,8 @@
|
|||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.textLayer .markedContent {
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
"pdf_history_spec.js",
|
||||
"primitives_spec.js",
|
||||
"stream_spec.js",
|
||||
"struct_tree_spec.js",
|
||||
"type1_parser_spec.js",
|
||||
"ui_utils_spec.js",
|
||||
"unicode_spec.js",
|
||||
|
|
|
@ -80,6 +80,7 @@ async function initializePDFJS(callback) {
|
|||
"pdfjs-test/unit/primitives_spec.js",
|
||||
"pdfjs-test/unit/scripting_spec.js",
|
||||
"pdfjs-test/unit/stream_spec.js",
|
||||
"pdfjs-test/unit/struct_tree_spec.js",
|
||||
"pdfjs-test/unit/type1_parser_spec.js",
|
||||
"pdfjs-test/unit/ui_utils_spec.js",
|
||||
"pdfjs-test/unit/unicode_spec.js",
|
||||
|
|
108
test/unit/struct_tree_spec.js
Normal file
108
test/unit/struct_tree_spec.js
Normal file
|
@ -0,0 +1,108 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
import { buildGetDocumentParams } from "./test_utils.js";
|
||||
import { getDocument } from "../../src/display/api.js";
|
||||
|
||||
function equalTrees(rootA, rootB) {
|
||||
function walk(a, b) {
|
||||
expect(a.role).toEqual(b.role);
|
||||
expect(a.type).toEqual(b.type);
|
||||
expect("children" in a).toEqual("children" in b);
|
||||
if (!a.children) {
|
||||
return;
|
||||
}
|
||||
expect(a.children.length).toEqual(b.children.length);
|
||||
for (let i = 0; i < rootA.children.length; i++) {
|
||||
walk(a.children[i], b.children[i]);
|
||||
}
|
||||
}
|
||||
return walk(rootA, rootB);
|
||||
}
|
||||
|
||||
describe("struct tree", function () {
|
||||
describe("getStructTree", function () {
|
||||
it("parses basic structure", async function () {
|
||||
const filename = "structure_simple.pdf";
|
||||
const params = buildGetDocumentParams(filename);
|
||||
const loadingTask = getDocument(params);
|
||||
const doc = await loadingTask.promise;
|
||||
const page = await doc.getPage(1);
|
||||
const struct = await page.getStructTree();
|
||||
equalTrees(
|
||||
{
|
||||
role: "Root",
|
||||
children: [
|
||||
{
|
||||
role: "Document",
|
||||
children: [
|
||||
{
|
||||
role: "H1",
|
||||
children: [
|
||||
{ role: "NonStruct", children: [{ type: "content" }] },
|
||||
],
|
||||
},
|
||||
{
|
||||
role: "P",
|
||||
children: [
|
||||
{ role: "NonStruct", children: [{ type: "content" }] },
|
||||
],
|
||||
},
|
||||
{
|
||||
role: "H2",
|
||||
children: [
|
||||
{ role: "NonStruct", children: [{ type: "content" }] },
|
||||
],
|
||||
},
|
||||
{
|
||||
role: "P",
|
||||
children: [
|
||||
{ role: "NonStruct", children: [{ type: "content" }] },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
struct
|
||||
);
|
||||
await loadingTask.destroy();
|
||||
});
|
||||
|
||||
it("parses structure with marked content reference", async function () {
|
||||
const filename = "issue6782.pdf";
|
||||
const params = buildGetDocumentParams(filename);
|
||||
const loadingTask = getDocument(params);
|
||||
const doc = await loadingTask.promise;
|
||||
const page = await doc.getPage(1);
|
||||
const struct = await page.getStructTree();
|
||||
equalTrees(
|
||||
{
|
||||
role: "Root",
|
||||
children: [
|
||||
{
|
||||
role: "Part",
|
||||
children: [
|
||||
{ role: "P", children: Array(27).fill({ type: "content" }) },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
struct
|
||||
);
|
||||
await loadingTask.destroy();
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue