XFA - Add support for reftests
This commit is contained in:
parent
e7dc822e74
commit
63caa101f8
@ -2272,6 +2272,7 @@ class WorkerTransport {
|
||||
docId: loadingTask.docId,
|
||||
onUnsupportedFeature: this._onUnsupportedFeature.bind(this),
|
||||
ownerDocument: params.ownerDocument,
|
||||
styleElement: params.styleElement,
|
||||
});
|
||||
this._params = params;
|
||||
this.CMapReaderFactory = new params.CMapReaderFactory({
|
||||
|
@ -29,6 +29,8 @@ class BaseFontLoader {
|
||||
docId,
|
||||
onUnsupportedFeature,
|
||||
ownerDocument = globalThis.document,
|
||||
// For testing only.
|
||||
styleElement = null,
|
||||
}) {
|
||||
if (this.constructor === BaseFontLoader) {
|
||||
unreachable("Cannot initialize BaseFontLoader.");
|
||||
@ -38,7 +40,10 @@ class BaseFontLoader {
|
||||
this._document = ownerDocument;
|
||||
|
||||
this.nativeFontFaces = [];
|
||||
this.styleElement = null;
|
||||
this.styleElement =
|
||||
typeof PDFJSDev === "undefined" || PDFJSDev.test("!PRODUCTION || TESTING")
|
||||
? styleElement
|
||||
: null;
|
||||
}
|
||||
|
||||
addNativeFontFace(nativeFontFace) {
|
||||
@ -55,7 +60,6 @@ class BaseFontLoader {
|
||||
.getElementsByTagName("head")[0]
|
||||
.appendChild(styleElement);
|
||||
}
|
||||
|
||||
const styleSheet = styleElement.sheet;
|
||||
styleSheet.insertRule(rule, styleSheet.cssRules.length);
|
||||
}
|
||||
@ -121,7 +125,18 @@ class BaseFontLoader {
|
||||
}
|
||||
|
||||
get isFontLoadingAPISupported() {
|
||||
return shadow(this, "isFontLoadingAPISupported", !!this._document?.fonts);
|
||||
const hasFonts = !!this._document?.fonts;
|
||||
if (
|
||||
typeof PDFJSDev === "undefined" ||
|
||||
PDFJSDev.test("!PRODUCTION || TESTING")
|
||||
) {
|
||||
return shadow(
|
||||
this,
|
||||
"isFontLoadingAPISupported",
|
||||
hasFonts && !this.styleElement
|
||||
);
|
||||
}
|
||||
return shadow(this, "isFontLoadingAPISupported", hasFonts);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line getter-return
|
||||
|
229
test/driver.js
229
test/driver.js
@ -25,27 +25,60 @@ const STANDARD_FONT_DATA_URL = "/build/generic/web/standard_fonts/";
|
||||
const IMAGE_RESOURCES_PATH = "/web/images/";
|
||||
const WORKER_SRC = "../build/generic/build/pdf.worker.js";
|
||||
const RENDER_TASK_ON_CONTINUE_DELAY = 5; // ms
|
||||
const SVG_NS = "http://www.w3.org/2000/svg";
|
||||
|
||||
function loadStyles(styles) {
|
||||
styles = Object.values(styles);
|
||||
if (styles.every(style => style.promise)) {
|
||||
return Promise.all(styles.map(style => style.promise));
|
||||
}
|
||||
|
||||
for (const style of styles) {
|
||||
style.promise = new Promise(function (resolve, reject) {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", style.file);
|
||||
xhr.onload = function () {
|
||||
resolve(xhr.responseText);
|
||||
};
|
||||
xhr.onerror = function (e) {
|
||||
reject(new Error(`Error fetching style (${style.file}): ${e}`));
|
||||
};
|
||||
xhr.send(null);
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.all(styles.map(style => style.promise));
|
||||
}
|
||||
|
||||
function writeSVG(svgElement, ctx, resolve, reject) {
|
||||
// We need to have UTF-8 encoded XML.
|
||||
const svg_xml = unescape(
|
||||
encodeURIComponent(new XMLSerializer().serializeToString(svgElement))
|
||||
);
|
||||
const img = new Image();
|
||||
img.src = "data:image/svg+xml;base64," + btoa(svg_xml);
|
||||
img.onload = function () {
|
||||
ctx.drawImage(img, 0, 0);
|
||||
resolve();
|
||||
};
|
||||
img.onerror = function (e) {
|
||||
reject(new Error("Error rasterizing text layer " + e));
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @class
|
||||
*/
|
||||
var rasterizeTextLayer = (function rasterizeTextLayerClosure() {
|
||||
var SVG_NS = "http://www.w3.org/2000/svg";
|
||||
const styles = {
|
||||
common: {
|
||||
file: "./text_layer_test.css",
|
||||
promise: null,
|
||||
},
|
||||
};
|
||||
|
||||
var textLayerStylePromise = null;
|
||||
function getTextLayerStyle() {
|
||||
if (textLayerStylePromise) {
|
||||
return textLayerStylePromise;
|
||||
}
|
||||
textLayerStylePromise = new Promise(function (resolve) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", "./text_layer_test.css");
|
||||
xhr.onload = function () {
|
||||
resolve(xhr.responseText);
|
||||
};
|
||||
xhr.send(null);
|
||||
});
|
||||
return textLayerStylePromise;
|
||||
return loadStyles(styles);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-shadow
|
||||
@ -92,19 +125,7 @@ var rasterizeTextLayer = (function rasterizeTextLayerClosure() {
|
||||
task.expandTextDivs(true);
|
||||
svg.appendChild(foreignObject);
|
||||
|
||||
// We need to have UTF-8 encoded XML.
|
||||
var svg_xml = unescape(
|
||||
encodeURIComponent(new XMLSerializer().serializeToString(svg))
|
||||
);
|
||||
var img = new Image();
|
||||
img.src = "data:image/svg+xml;base64," + btoa(svg_xml);
|
||||
img.onload = function () {
|
||||
ctx.drawImage(img, 0, 0);
|
||||
resolve();
|
||||
};
|
||||
img.onerror = function (e) {
|
||||
reject(new Error("Error rasterizing text layer " + e));
|
||||
};
|
||||
writeSVG(svg, ctx, resolve, reject);
|
||||
})
|
||||
.catch(reason => {
|
||||
reject(new Error(`rasterizeTextLayer: "${reason?.message}".`));
|
||||
@ -119,8 +140,6 @@ var rasterizeTextLayer = (function rasterizeTextLayerClosure() {
|
||||
* @class
|
||||
*/
|
||||
var rasterizeAnnotationLayer = (function rasterizeAnnotationLayerClosure() {
|
||||
const SVG_NS = "http://www.w3.org/2000/svg";
|
||||
|
||||
/**
|
||||
* For the reference tests, the entire annotation layer must be visible. To
|
||||
* achieve this, we load the common styles as used by the viewer and extend
|
||||
@ -142,27 +161,7 @@ var rasterizeAnnotationLayer = (function rasterizeAnnotationLayerClosure() {
|
||||
};
|
||||
|
||||
function getAnnotationLayerStyle() {
|
||||
// Use the cached promises if they are available.
|
||||
if (styles.common.promise && styles.overrides.promise) {
|
||||
return Promise.all([styles.common.promise, styles.overrides.promise]);
|
||||
}
|
||||
|
||||
// Load the style files and cache the results.
|
||||
for (const key in styles) {
|
||||
styles[key].promise = new Promise(function (resolve, reject) {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", styles[key].file);
|
||||
xhr.onload = function () {
|
||||
resolve(xhr.responseText);
|
||||
};
|
||||
xhr.onerror = function (e) {
|
||||
reject(new Error("Error fetching annotation style " + e));
|
||||
};
|
||||
xhr.send(null);
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.all([styles.common.promise, styles.overrides.promise]);
|
||||
return loadStyles(styles);
|
||||
}
|
||||
|
||||
function inlineAnnotationImages(images) {
|
||||
@ -256,19 +255,7 @@ var rasterizeAnnotationLayer = (function rasterizeAnnotationLayerClosure() {
|
||||
foreignObject.appendChild(div);
|
||||
svg.appendChild(foreignObject);
|
||||
|
||||
// We need to have UTF-8 encoded XML.
|
||||
var svg_xml = unescape(
|
||||
encodeURIComponent(new XMLSerializer().serializeToString(svg))
|
||||
);
|
||||
var img = new Image();
|
||||
img.src = "data:image/svg+xml;base64," + btoa(svg_xml);
|
||||
img.onload = function () {
|
||||
ctx.drawImage(img, 0, 0);
|
||||
resolve();
|
||||
};
|
||||
img.onerror = function (e) {
|
||||
reject(new Error("Error rasterizing annotation layer " + e));
|
||||
};
|
||||
writeSVG(svg, ctx, resolve, reject);
|
||||
})
|
||||
.catch(reason => {
|
||||
reject(new Error(`rasterizeAnnotationLayer: "${reason?.message}".`));
|
||||
@ -279,6 +266,65 @@ var rasterizeAnnotationLayer = (function rasterizeAnnotationLayerClosure() {
|
||||
return rasterizeAnnotationLayer;
|
||||
})();
|
||||
|
||||
/**
|
||||
* @class
|
||||
*/
|
||||
var rasterizeXfaLayer = (function rasterizeXfaLayerClosure() {
|
||||
const styles = {
|
||||
common: {
|
||||
file: "../web/xfa_layer_builder.css",
|
||||
promise: null,
|
||||
},
|
||||
};
|
||||
|
||||
function getXfaLayerStyle() {
|
||||
return loadStyles(styles);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-shadow
|
||||
function rasterizeXfaLayer(ctx, viewport, xfa, fontRules) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
// Building SVG with size of the viewport.
|
||||
const svg = document.createElementNS(SVG_NS, "svg:svg");
|
||||
svg.setAttribute("width", viewport.width + "px");
|
||||
svg.setAttribute("height", viewport.height + "px");
|
||||
const foreignObject = document.createElementNS(
|
||||
SVG_NS,
|
||||
"svg:foreignObject"
|
||||
);
|
||||
foreignObject.setAttribute("x", "0");
|
||||
foreignObject.setAttribute("y", "0");
|
||||
foreignObject.setAttribute("width", viewport.width + "px");
|
||||
foreignObject.setAttribute("height", viewport.height + "px");
|
||||
const style = document.createElement("style");
|
||||
const stylePromise = getXfaLayerStyle();
|
||||
foreignObject.appendChild(style);
|
||||
const div = document.createElement("div");
|
||||
foreignObject.appendChild(div);
|
||||
|
||||
stylePromise
|
||||
.then(async cssRules => {
|
||||
style.textContent = fontRules + "\n" + cssRules;
|
||||
|
||||
pdfjsLib.XfaLayer.render({
|
||||
xfa,
|
||||
div,
|
||||
viewport: viewport.clone({ dontFlip: true }),
|
||||
});
|
||||
|
||||
svg.appendChild(foreignObject);
|
||||
|
||||
writeSVG(svg, ctx, resolve, reject);
|
||||
})
|
||||
.catch(reason => {
|
||||
reject(new Error(`rasterizeXfaLayer: "${reason?.message}".`));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return rasterizeXfaLayer;
|
||||
})();
|
||||
|
||||
/**
|
||||
* @typedef {Object} DriverOptions
|
||||
* @property {HTMLSpanElement} inflight - Field displaying the number of
|
||||
@ -392,6 +438,7 @@ var Driver = (function DriverClosure() {
|
||||
task.round = 0;
|
||||
task.pageNum = task.firstPage || 1;
|
||||
task.stats = { times: [] };
|
||||
task.enableXfa = task.enableXfa === true;
|
||||
|
||||
// Support *linked* test-cases for the other suites, e.g. unit- and
|
||||
// integration-tests, without needing to run them as reference-tests.
|
||||
@ -411,6 +458,17 @@ var Driver = (function DriverClosure() {
|
||||
|
||||
const absoluteUrl = new URL(task.file, window.location).href;
|
||||
try {
|
||||
let xfaStyleElement = null;
|
||||
if (task.enableXfa) {
|
||||
// Need to get the font definitions to inject them in the SVG.
|
||||
// So we create this element and those definitions will be
|
||||
// appended in font_loader.js.
|
||||
xfaStyleElement = document.createElement("style");
|
||||
document.documentElement
|
||||
.getElementsByTagName("head")[0]
|
||||
.appendChild(xfaStyleElement);
|
||||
}
|
||||
|
||||
const loadingTask = pdfjsLib.getDocument({
|
||||
url: absoluteUrl,
|
||||
password: task.password,
|
||||
@ -422,9 +480,18 @@ var Driver = (function DriverClosure() {
|
||||
pdfBug: true,
|
||||
useSystemFonts: task.useSystemFonts,
|
||||
useWorkerFetch: task.useWorkerFetch,
|
||||
enableXfa: task.enableXfa,
|
||||
styleElement: xfaStyleElement,
|
||||
});
|
||||
loadingTask.promise.then(
|
||||
doc => {
|
||||
if (task.enableXfa) {
|
||||
task.fontRules = "";
|
||||
for (const rule of xfaStyleElement.sheet.cssRules) {
|
||||
task.fontRules += rule.cssText + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
task.pdfDoc = doc;
|
||||
task.optionalContentConfigPromise =
|
||||
doc.getOptionalContentConfig();
|
||||
@ -552,7 +619,8 @@ var Driver = (function DriverClosure() {
|
||||
// Initialize various `eq` test subtypes, see comment below.
|
||||
var renderAnnotations = false,
|
||||
renderForms = false,
|
||||
renderPrint = false;
|
||||
renderPrint = false,
|
||||
renderXfa = false;
|
||||
|
||||
var textLayerCanvas, annotationLayerCanvas;
|
||||
var initPromise;
|
||||
@ -594,9 +662,10 @@ var Driver = (function DriverClosure() {
|
||||
renderAnnotations = !!task.annotations;
|
||||
renderForms = !!task.forms;
|
||||
renderPrint = !!task.print;
|
||||
renderXfa = !!task.enableXfa;
|
||||
|
||||
// Render the annotation layer if necessary.
|
||||
if (renderAnnotations || renderForms) {
|
||||
if (renderAnnotations || renderForms || renderXfa) {
|
||||
// Create a dummy canvas for the drawing operations.
|
||||
annotationLayerCanvas = self.annotationLayerCanvas;
|
||||
if (!annotationLayerCanvas) {
|
||||
@ -614,19 +683,31 @@ var Driver = (function DriverClosure() {
|
||||
annotationLayerCanvas.height
|
||||
);
|
||||
|
||||
// The annotation builder will draw its content on the canvas.
|
||||
initPromise = page
|
||||
.getAnnotations({ intent: "display" })
|
||||
.then(function (annotations) {
|
||||
return rasterizeAnnotationLayer(
|
||||
if (!renderXfa) {
|
||||
// The annotation builder will draw its content
|
||||
// on the canvas.
|
||||
initPromise = page
|
||||
.getAnnotations({ intent: "display" })
|
||||
.then(function (annotations) {
|
||||
return rasterizeAnnotationLayer(
|
||||
annotationLayerContext,
|
||||
viewport,
|
||||
annotations,
|
||||
page,
|
||||
IMAGE_RESOURCES_PATH,
|
||||
renderForms
|
||||
);
|
||||
});
|
||||
} else {
|
||||
initPromise = page.getXfa().then(function (xfa) {
|
||||
return rasterizeXfaLayer(
|
||||
annotationLayerContext,
|
||||
viewport,
|
||||
annotations,
|
||||
page,
|
||||
IMAGE_RESOURCES_PATH,
|
||||
renderForms
|
||||
xfa,
|
||||
task.fontRules
|
||||
);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
annotationLayerCanvas = null;
|
||||
initPromise = Promise.resolve();
|
||||
|
1
test/pdfs/hsbc.pdf.link
Normal file
1
test/pdfs/hsbc.pdf.link
Normal file
@ -0,0 +1 @@
|
||||
https://web.archive.org/web/20210607145115/https://www.hsbc.fr/content/dam/hsbc/fr/docs/pib/Contestation-Transaction-Carte-Bancaire.pdf
|
@ -2725,6 +2725,14 @@
|
||||
"rounds": 1,
|
||||
"type": "eq"
|
||||
},
|
||||
{ "id": "hsbc",
|
||||
"file": "pdfs/hsbc.pdf",
|
||||
"md5": "34a63a9ed9cdf3790562a3dfd1703e48",
|
||||
"rounds": 1,
|
||||
"link": true,
|
||||
"enableXfa": true,
|
||||
"type": "eq"
|
||||
},
|
||||
{ "id": "issue7580-text",
|
||||
"file": "pdfs/issue7580.pdf",
|
||||
"md5": "44dd5a9b4373fcab9890cf567722a766",
|
||||
|
@ -33,6 +33,8 @@
|
||||
vertical-align: inherit;
|
||||
box-sizing: border-box;
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.xfaLayer a {
|
||||
|
Loading…
Reference in New Issue
Block a user