Merge pull request #15778 from Snuffleupagus/keep-structTree
Don't re-create the `structTreeLayer` on zooming and rotation
This commit is contained in:
commit
cdd39ec69e
@ -1623,9 +1623,7 @@ class PDFPageProxy {
|
|||||||
* or `null` when no structure tree is present for the current page.
|
* or `null` when no structure tree is present for the current page.
|
||||||
*/
|
*/
|
||||||
getStructTree() {
|
getStructTree() {
|
||||||
return (this._structTreePromise ||= this._transport.getStructTree(
|
return this._transport.getStructTree(this._pageIndex);
|
||||||
this._pageIndex
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1659,7 +1657,6 @@ class PDFPageProxy {
|
|||||||
this._bitmaps.clear();
|
this._bitmaps.clear();
|
||||||
this._annotationPromises.clear();
|
this._annotationPromises.clear();
|
||||||
this._jsActionsPromise = null;
|
this._jsActionsPromise = null;
|
||||||
this._structTreePromise = null;
|
|
||||||
this.pendingCleanup = false;
|
this.pendingCleanup = false;
|
||||||
return Promise.all(waitOn);
|
return Promise.all(waitOn);
|
||||||
}
|
}
|
||||||
@ -1694,7 +1691,6 @@ class PDFPageProxy {
|
|||||||
this.objs.clear();
|
this.objs.clear();
|
||||||
this._annotationPromises.clear();
|
this._annotationPromises.clear();
|
||||||
this._jsActionsPromise = null;
|
this._jsActionsPromise = null;
|
||||||
this._structTreePromise = null;
|
|
||||||
if (resetStats && this._stats) {
|
if (resetStats && this._stats) {
|
||||||
this._stats = new StatTimer();
|
this._stats = new StatTimer();
|
||||||
}
|
}
|
||||||
|
@ -144,18 +144,10 @@ class DefaultAnnotationEditorLayerFactory {
|
|||||||
*/
|
*/
|
||||||
class DefaultStructTreeLayerFactory {
|
class DefaultStructTreeLayerFactory {
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} CreateStructTreeLayerBuilderParameters
|
|
||||||
* @property {PDFPageProxy} pdfPage
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {CreateStructTreeLayerBuilderParameters}
|
|
||||||
* @returns {StructTreeLayerBuilder}
|
* @returns {StructTreeLayerBuilder}
|
||||||
*/
|
*/
|
||||||
createStructTreeLayerBuilder({ pdfPage }) {
|
createStructTreeLayerBuilder() {
|
||||||
return new StructTreeLayerBuilder({
|
return new StructTreeLayerBuilder();
|
||||||
pdfPage,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,15 +280,9 @@ class IPDFXfaLayerFactory {
|
|||||||
*/
|
*/
|
||||||
class IPDFStructTreeLayerFactory {
|
class IPDFStructTreeLayerFactory {
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} CreateStructTreeLayerBuilderParameters
|
|
||||||
* @property {PDFPageProxy} pdfPage
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {CreateStructTreeLayerBuilderParameters}
|
|
||||||
* @returns {StructTreeLayerBuilder}
|
* @returns {StructTreeLayerBuilder}
|
||||||
*/
|
*/
|
||||||
createStructTreeLayerBuilder({ pdfPage }) {}
|
createStructTreeLayerBuilder() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -318,6 +318,33 @@ class PDFPageView {
|
|||||||
numTextDivs: textLayer.numTextDivs,
|
numTextDivs: textLayer.numTextDivs,
|
||||||
error,
|
error,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (this.structTreeLayerFactory) {
|
||||||
|
this.#renderStructTreeLayer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The structure tree is currently only supported when the text layer is
|
||||||
|
* enabled and a canvas is used for rendering.
|
||||||
|
*
|
||||||
|
* The structure tree must be generated after the text layer for the
|
||||||
|
* aria-owns to work.
|
||||||
|
*/
|
||||||
|
async #renderStructTreeLayer() {
|
||||||
|
if (!this.textLayer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.structTreeLayer ||=
|
||||||
|
this.structTreeLayerFactory.createStructTreeLayerBuilder();
|
||||||
|
|
||||||
|
const tree = await (!this.structTreeLayer.renderingDone
|
||||||
|
? this.pdfPage.getStructTree()
|
||||||
|
: null);
|
||||||
|
const treeDom = this.structTreeLayer?.render(tree);
|
||||||
|
if (treeDom) {
|
||||||
|
this.canvas?.append(treeDom);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async _buildXfaTextContentItems(textDivs) {
|
async _buildXfaTextContentItems(textDivs) {
|
||||||
@ -578,6 +605,9 @@ class PDFPageView {
|
|||||||
this.textLayer.cancel();
|
this.textLayer.cancel();
|
||||||
this.textLayer = null;
|
this.textLayer = null;
|
||||||
}
|
}
|
||||||
|
if (this.structTreeLayer && !this.textLayer) {
|
||||||
|
this.structTreeLayer = null;
|
||||||
|
}
|
||||||
if (
|
if (
|
||||||
this.annotationLayer &&
|
this.annotationLayer &&
|
||||||
(!keepAnnotationLayer || !this.annotationLayer.div)
|
(!keepAnnotationLayer || !this.annotationLayer.div)
|
||||||
@ -598,10 +628,6 @@ class PDFPageView {
|
|||||||
this.xfaLayer = null;
|
this.xfaLayer = null;
|
||||||
this.textHighlighter?.disable();
|
this.textHighlighter?.disable();
|
||||||
}
|
}
|
||||||
if (this._onTextLayerRendered) {
|
|
||||||
this.eventBus._off("textlayerrendered", this._onTextLayerRendered);
|
|
||||||
this._onTextLayerRendered = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cssTransform({
|
cssTransform({
|
||||||
@ -844,38 +870,6 @@ class PDFPageView {
|
|||||||
this._renderXfaLayer();
|
this._renderXfaLayer();
|
||||||
}
|
}
|
||||||
|
|
||||||
// The structure tree is currently only supported when the text layer is
|
|
||||||
// enabled and a canvas is used for rendering.
|
|
||||||
if (this.structTreeLayerFactory && this.textLayer && this.canvas) {
|
|
||||||
// The structure tree must be generated after the text layer for the
|
|
||||||
// aria-owns to work.
|
|
||||||
this._onTextLayerRendered = event => {
|
|
||||||
if (event.pageNumber !== this.id) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.eventBus._off("textlayerrendered", this._onTextLayerRendered);
|
|
||||||
this._onTextLayerRendered = null;
|
|
||||||
|
|
||||||
if (!this.canvas) {
|
|
||||||
return; // The canvas was removed, prevent errors below.
|
|
||||||
}
|
|
||||||
this.pdfPage.getStructTree().then(tree => {
|
|
||||||
if (!tree) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!this.canvas) {
|
|
||||||
return; // The canvas was removed, prevent errors below.
|
|
||||||
}
|
|
||||||
const treeDom = this.structTreeLayer.render(tree);
|
|
||||||
treeDom.classList.add("structTree");
|
|
||||||
this.canvas.append(treeDom);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
this.eventBus._on("textlayerrendered", this._onTextLayerRendered);
|
|
||||||
this.structTreeLayer =
|
|
||||||
this.structTreeLayerFactory.createStructTreeLayerBuilder({ pdfPage });
|
|
||||||
}
|
|
||||||
|
|
||||||
div.setAttribute("data-loaded", true);
|
div.setAttribute("data-loaded", true);
|
||||||
|
|
||||||
this.eventBus.dispatch("pagerender", {
|
this.eventBus.dispatch("pagerender", {
|
||||||
|
@ -1794,18 +1794,10 @@ class PDFViewer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} CreateStructTreeLayerBuilderParameters
|
|
||||||
* @property {PDFPageProxy} pdfPage
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {CreateStructTreeLayerBuilderParameters}
|
|
||||||
* @returns {StructTreeLayerBuilder}
|
* @returns {StructTreeLayerBuilder}
|
||||||
*/
|
*/
|
||||||
createStructTreeLayerBuilder({ pdfPage }) {
|
createStructTreeLayerBuilder() {
|
||||||
return new StructTreeLayerBuilder({
|
return new StructTreeLayerBuilder();
|
||||||
pdfPage,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -13,8 +13,6 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @typedef {import("../src/display/api").PDFPageProxy} PDFPageProxy */
|
|
||||||
|
|
||||||
const PDF_ROLE_TO_HTML_ROLE = {
|
const PDF_ROLE_TO_HTML_ROLE = {
|
||||||
// Document level structure types
|
// Document level structure types
|
||||||
Document: null, // There's a "document" role, but it doesn't make sense here.
|
Document: null, // There's a "document" role, but it doesn't make sense here.
|
||||||
@ -73,24 +71,23 @@ const PDF_ROLE_TO_HTML_ROLE = {
|
|||||||
|
|
||||||
const HEADING_PATTERN = /^H(\d+)$/;
|
const HEADING_PATTERN = /^H(\d+)$/;
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {Object} StructTreeLayerBuilderOptions
|
|
||||||
* @property {PDFPageProxy} pdfPage
|
|
||||||
*/
|
|
||||||
|
|
||||||
class StructTreeLayerBuilder {
|
class StructTreeLayerBuilder {
|
||||||
/**
|
#treeDom = undefined;
|
||||||
* @param {StructTreeLayerBuilderOptions} options
|
|
||||||
*/
|
get renderingDone() {
|
||||||
constructor({ pdfPage }) {
|
return this.#treeDom !== undefined;
|
||||||
this.pdfPage = pdfPage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render(structTree) {
|
render(structTree) {
|
||||||
return this._walk(structTree);
|
if (this.#treeDom !== undefined) {
|
||||||
|
return this.#treeDom;
|
||||||
|
}
|
||||||
|
const treeDom = this.#walk(structTree);
|
||||||
|
treeDom?.classList.add("structTree");
|
||||||
|
return (this.#treeDom = treeDom);
|
||||||
}
|
}
|
||||||
|
|
||||||
_setAttributes(structElement, htmlElement) {
|
#setAttributes(structElement, htmlElement) {
|
||||||
if (structElement.alt !== undefined) {
|
if (structElement.alt !== undefined) {
|
||||||
htmlElement.setAttribute("aria-label", structElement.alt);
|
htmlElement.setAttribute("aria-label", structElement.alt);
|
||||||
}
|
}
|
||||||
@ -102,7 +99,7 @@ class StructTreeLayerBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_walk(node) {
|
#walk(node) {
|
||||||
if (!node) {
|
if (!node) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -119,16 +116,16 @@ class StructTreeLayerBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this._setAttributes(node, element);
|
this.#setAttributes(node, element);
|
||||||
|
|
||||||
if (node.children) {
|
if (node.children) {
|
||||||
if (node.children.length === 1 && "id" in node.children[0]) {
|
if (node.children.length === 1 && "id" in node.children[0]) {
|
||||||
// Often there is only one content node so just set the values on the
|
// Often there is only one content node so just set the values on the
|
||||||
// parent node to avoid creating an extra span.
|
// parent node to avoid creating an extra span.
|
||||||
this._setAttributes(node.children[0], element);
|
this.#setAttributes(node.children[0], element);
|
||||||
} else {
|
} else {
|
||||||
for (const kid of node.children) {
|
for (const kid of node.children) {
|
||||||
element.append(this._walk(kid));
|
element.append(this.#walk(kid));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user