Skip to content

Commit

Permalink
Revert "Revert "[api-minor] Allow loading pdf fonts into another docu…
Browse files Browse the repository at this point in the history
…ment.""

This reverts commit 05baa4c.
  • Loading branch information
timvandermeij committed Aug 1, 2020
1 parent c53e403 commit fd95b3f
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 19 deletions.
15 changes: 13 additions & 2 deletions src/display/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@ function setPDFNetworkStreamFactory(pdfNetworkStreamFactory) {
* parsed font data from the worker-thread. This may be useful for debugging
* purposes (and backwards compatibility), but note that it will lead to
* increased memory usage. The default value is `false`.
* @property {HTMLDocument} [ownerDocument] - Specify an explicit document
* context to create elements with and to load resources, such as fonts,
* into. Defaults to the current document.
* @property {boolean} [disableRange] - Disable range request loading
* of PDF files. When enabled, and if the server supports partial content
* requests, then the PDF will be fetched in chunks.
Expand Down Expand Up @@ -268,6 +271,9 @@ function getDocument(src) {
if (typeof params.disableFontFace !== "boolean") {
params.disableFontFace = apiCompatibilityParams.disableFontFace || false;
}
if (typeof params.ownerDocument === "undefined") {
params.ownerDocument = globalThis.document;
}

if (typeof params.disableRange !== "boolean") {
params.disableRange = false;
Expand Down Expand Up @@ -907,9 +913,10 @@ class PDFDocumentProxy {
* @alias PDFPageProxy
*/
class PDFPageProxy {
constructor(pageIndex, pageInfo, transport, pdfBug = false) {
constructor(pageIndex, pageInfo, transport, ownerDocument, pdfBug = false) {
this._pageIndex = pageIndex;
this._pageInfo = pageInfo;
this._ownerDocument = ownerDocument;
this._transport = transport;
this._stats = pdfBug ? new StatTimer() : null;
this._pdfBug = pdfBug;
Expand Down Expand Up @@ -1036,7 +1043,9 @@ class PDFPageProxy {
intentState.streamReaderCancelTimeout = null;
}

const canvasFactoryInstance = canvasFactory || new DefaultCanvasFactory();
const canvasFactoryInstance =
canvasFactory ||
new DefaultCanvasFactory({ ownerDocument: this._ownerDocument });
const webGLContext = new WebGLContext({
enable: enableWebGL,
});
Expand Down Expand Up @@ -1944,6 +1953,7 @@ class WorkerTransport {
this.fontLoader = new FontLoader({
docId: loadingTask.docId,
onUnsupportedFeature: this._onUnsupportedFeature.bind(this),
ownerDocument: params.ownerDocument,
});
this._params = params;
this.CMapReaderFactory = new params.CMapReaderFactory({
Expand Down Expand Up @@ -2400,6 +2410,7 @@ class WorkerTransport {
pageIndex,
pageInfo,
this,
this._params.ownerDocument,
this._params.pdfBug
);
this.pageCache[pageIndex] = page;
Expand Down
7 changes: 6 additions & 1 deletion src/display/display_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,16 @@ class BaseCanvasFactory {
}

class DOMCanvasFactory extends BaseCanvasFactory {
constructor({ ownerDocument = globalThis.document } = {}) {
super();
this._document = ownerDocument;
}

create(width, height) {
if (width <= 0 || height <= 0) {
throw new Error("Invalid canvas size");
}
const canvas = document.createElement("canvas");
const canvas = this._document.createElement("canvas");
const context = canvas.getContext("2d");
canvas.width = width;
canvas.height = height;
Expand Down
36 changes: 21 additions & 15 deletions src/display/font_loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,28 +25,33 @@ import {
} from "../shared/util.js";

class BaseFontLoader {
constructor({ docId, onUnsupportedFeature }) {
constructor({
docId,
onUnsupportedFeature,
ownerDocument = globalThis.document,
}) {
if (this.constructor === BaseFontLoader) {
unreachable("Cannot initialize BaseFontLoader.");
}
this.docId = docId;
this._onUnsupportedFeature = onUnsupportedFeature;
this._document = ownerDocument;

this.nativeFontFaces = [];
this.styleElement = null;
}

addNativeFontFace(nativeFontFace) {
this.nativeFontFaces.push(nativeFontFace);
document.fonts.add(nativeFontFace);
this._document.fonts.add(nativeFontFace);
}

insertRule(rule) {
let styleElement = this.styleElement;
if (!styleElement) {
styleElement = this.styleElement = document.createElement("style");
styleElement = this.styleElement = this._document.createElement("style");
styleElement.id = `PDFJS_FONT_STYLE_TAG_${this.docId}`;
document.documentElement
this._document.documentElement
.getElementsByTagName("head")[0]
.appendChild(styleElement);
}
Expand All @@ -56,8 +61,8 @@ class BaseFontLoader {
}

clear() {
this.nativeFontFaces.forEach(function (nativeFontFace) {
document.fonts.delete(nativeFontFace);
this.nativeFontFaces.forEach(nativeFontFace => {
this._document.fonts.delete(nativeFontFace);
});
this.nativeFontFaces.length = 0;

Expand Down Expand Up @@ -116,7 +121,8 @@ class BaseFontLoader {
}

get isFontLoadingAPISupported() {
const supported = typeof document !== "undefined" && !!document.fonts;
const supported =
typeof this._document !== "undefined" && !!this._document.fonts;
return shadow(this, "isFontLoadingAPISupported", supported);
}

Expand Down Expand Up @@ -146,8 +152,8 @@ if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) {
// PDFJSDev.test('CHROME || GENERIC')

FontLoader = class GenericFontLoader extends BaseFontLoader {
constructor(docId) {
super(docId);
constructor(params) {
super(params);
this.loadingContext = {
requests: [],
nextRequestId: 0,
Expand Down Expand Up @@ -254,7 +260,7 @@ if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) {
let i, ii;

// The temporary canvas is used to determine if fonts are loaded.
const canvas = document.createElement("canvas");
const canvas = this._document.createElement("canvas");
canvas.width = 1;
canvas.height = 1;
const ctx = canvas.getContext("2d");
Expand Down Expand Up @@ -316,22 +322,22 @@ if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) {
}
names.push(loadTestFontId);

const div = document.createElement("div");
const div = this._document.createElement("div");
div.style.visibility = "hidden";
div.style.width = div.style.height = "10px";
div.style.position = "absolute";
div.style.top = div.style.left = "0px";

for (i = 0, ii = names.length; i < ii; ++i) {
const span = document.createElement("span");
const span = this._document.createElement("span");
span.textContent = "Hi";
span.style.fontFamily = names[i];
div.appendChild(span);
}
document.body.appendChild(div);
this._document.body.appendChild(div);

isFontReady(loadTestFontId, function () {
document.body.removeChild(div);
isFontReady(loadTestFontId, () => {
this._document.body.removeChild(div);
request.complete();
});
/** Hack end */
Expand Down
3 changes: 2 additions & 1 deletion src/display/text_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,7 @@ var renderTextLayer = (function renderTextLayerClosure() {
this._textContent = textContent;
this._textContentStream = textContentStream;
this._container = container;
this._document = container.ownerDocument;
this._viewport = viewport;
this._textDivs = textDivs || [];
this._textContentItemsStr = textContentItemsStr || [];
Expand Down Expand Up @@ -614,7 +615,7 @@ var renderTextLayer = (function renderTextLayerClosure() {
let styleCache = Object.create(null);

// The temporary canvas is used to measure text length in the DOM.
const canvas = document.createElement("canvas");
const canvas = this._document.createElement("canvas");
if (
typeof PDFJSDev === "undefined" ||
PDFJSDev.test("MOZCENTRAL || GENERIC")
Expand Down
116 changes: 116 additions & 0 deletions test/unit/custom_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,119 @@ describe("custom canvas rendering", function () {
.catch(done.fail);
});
});

describe("alternate document context", function () {
const FontFace = global.FontFace;

let altDocument;
let CanvasFactory;
let elements;

beforeEach(() => {
global.FontFace = function MockFontFace(name) {
this.family = name;
};

elements = [];
const createElement = name => {
const element = {
tagName: name,
remove() {
this.remove.called = true;
},
};
if (name === "style") {
element.sheet = {
cssRules: [],
insertRule(rule) {
this.cssRules.push(rule);
},
};
}
elements.push(element);
return element;
};
altDocument = {
fonts: new Set(),
createElement,
documentElement: {
getElementsByTagName: () => [{ appendChild: () => {} }],
},
};

CanvasFactory = isNodeJS
? new NodeCanvasFactory()
: new DOMCanvasFactory({ ownerDocument: altDocument });
});

afterEach(() => {
global.FontFace = FontFace;
CanvasFactory = null;
elements = null;
});

it("should use given document for loading fonts (with Font Loading API)", async function () {
const getDocumentParams = buildGetDocumentParams(
"TrueType_without_cmap.pdf",
{
disableFontFace: false,
ownerDocument: altDocument,
}
);

const loadingTask = getDocument(getDocumentParams);
const doc = await loadingTask.promise;
const page = await doc.getPage(1);

const viewport = page.getViewport({ scale: 1 });
const canvasAndCtx = CanvasFactory.create(viewport.width, viewport.height);

await page.render({
canvasContext: canvasAndCtx.context,
viewport,
}).promise;

expect(elements).toEqual([]);
expect(altDocument.fonts.size).toBe(1);
const [font] = Array.from(altDocument.fonts);
expect(font.family).toMatch(/g_d\d+_f1/);

await doc.destroy();
await loadingTask.destroy();
CanvasFactory.destroy(canvasAndCtx);
expect(altDocument.fonts.size).toBe(0);
});

it("should use given document for loading fonts (with CSS rules)", async function () {
altDocument.fonts = null;
const getDocumentParams = buildGetDocumentParams(
"TrueType_without_cmap.pdf",
{
disableFontFace: false,
ownerDocument: altDocument,
}
);

const loadingTask = getDocument(getDocumentParams);
const doc = await loadingTask.promise;
const page = await doc.getPage(1);

const viewport = page.getViewport({ scale: 1 });
const canvasAndCtx = CanvasFactory.create(viewport.width, viewport.height);

await page.render({
canvasContext: canvasAndCtx.context,
viewport,
}).promise;

const style = elements.find(element => element.tagName === "style");
expect(style.sheet.cssRules.length).toBe(1);
expect(style.sheet.cssRules[0]).toMatch(
/^@font-face {font-family:"g_d\d+_f1";src:/
);
await doc.destroy();
await loadingTask.destroy();
CanvasFactory.destroy(canvasAndCtx);
expect(style.remove.called).toBe(true);
});
});

0 comments on commit fd95b3f

Please sign in to comment.