Browse Source

Refactors FontLoader to group fonts per document.

Yury Delendik 10 years ago
parent
commit
06c1904675
  1. 37
      examples/node/domstubs.js
  2. 2
      src/core/evaluator.js
  3. 11
      src/core/pdf_manager.js
  4. 12
      src/core/worker.js
  5. 7
      src/display/api.js
  6. 142
      src/display/font_loader.js

37
examples/node/domstubs.js

@ -1,17 +1,6 @@
/* Any copyright is dedicated to the Public Domain. /* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */ * http://creativecommons.org/publicdomain/zero/1.0/ */
var sheet = {
cssRules: [],
insertRule: function(rule) {
this.cssRules.push(rule);
},
};
var style = {
sheet: sheet,
};
function xmlEncode(s){ function xmlEncode(s){
var i = 0, ch; var i = 0, ch;
s = String(s); s = String(s);
@ -75,6 +64,15 @@ function DOMElement(name) {
this.childNodes = []; this.childNodes = [];
this.attributes = {}; this.attributes = {};
this.textContent = ''; this.textContent = '';
if (name === 'style') {
this.sheet = {
cssRules: [],
insertRule: function (rule) {
this.cssRules.push(rule);
},
};
}
} }
DOMElement.prototype = { DOMElement.prototype = {
@ -125,14 +123,23 @@ DOMElement.prototype = {
global.document = { global.document = {
childNodes : [], childNodes : [],
getElementById: function (id) { get documentElement() {
if (id === 'PDFJS_FONT_STYLE_TAG') { return this;
return style;
}
}, },
createElementNS: function (NS, element) { createElementNS: function (NS, element) {
var elObject = new DOMElement(element); var elObject = new DOMElement(element);
return elObject; return elObject;
}, },
createElement: function (element) {
return this.createElementNS('', element);
},
getElementsByTagName: function (element) {
if (element === 'head') {
return [this.head || (this.head = new DOMElement('head'))];
}
return [];
}
}; };

2
src/core/evaluator.js

@ -529,7 +529,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
// Keep track of each font we translated so the caller can // Keep track of each font we translated so the caller can
// load them asynchronously before calling display on a page. // load them asynchronously before calling display on a page.
font.loadedName = 'g_font_' + (fontRefIsDict ? font.loadedName = 'g_' + this.pdfManager.docId + '_f' + (fontRefIsDict ?
fontName.replace(/\W/g, '') : fontID); fontName.replace(/\W/g, '') : fontID);
font.translated = fontCapability.promise; font.translated = fontCapability.promise;

11
src/core/pdf_manager.js

@ -24,6 +24,10 @@ var BasePdfManager = (function BasePdfManagerClosure() {
} }
BasePdfManager.prototype = { BasePdfManager.prototype = {
get docId() {
return this._docId;
},
onLoadedStream: function BasePdfManager_onLoadedStream() { onLoadedStream: function BasePdfManager_onLoadedStream() {
throw new NotImplementedException(); throw new NotImplementedException();
}, },
@ -85,7 +89,8 @@ var BasePdfManager = (function BasePdfManagerClosure() {
})(); })();
var LocalPdfManager = (function LocalPdfManagerClosure() { var LocalPdfManager = (function LocalPdfManagerClosure() {
function LocalPdfManager(data, password) { function LocalPdfManager(docId, data, password) {
this._docId = docId;
var stream = new Stream(data); var stream = new Stream(data);
this.pdfDocument = new PDFDocument(this, stream, password); this.pdfDocument = new PDFDocument(this, stream, password);
this._loadedStreamCapability = createPromiseCapability(); this._loadedStreamCapability = createPromiseCapability();
@ -136,8 +141,8 @@ var LocalPdfManager = (function LocalPdfManagerClosure() {
})(); })();
var NetworkPdfManager = (function NetworkPdfManagerClosure() { var NetworkPdfManager = (function NetworkPdfManagerClosure() {
function NetworkPdfManager(args, msgHandler) { function NetworkPdfManager(docId, args, msgHandler) {
this._docId = docId;
this.msgHandler = msgHandler; this.msgHandler = msgHandler;
var params = { var params = {

12
src/core/worker.js

@ -92,9 +92,9 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
var cancelXHRs = null; var cancelXHRs = null;
var WorkerTasks = []; var WorkerTasks = [];
var mainHandlerName = data.docId; var docId = data.docId;
var workerHandlerName = data.docId + '_worker'; var workerHandlerName = data.docId + '_worker';
var handler = new MessageHandler(workerHandlerName, mainHandlerName, port); var handler = new MessageHandler(workerHandlerName, docId, port);
function ensureNotTerminated() { function ensureNotTerminated() {
if (terminated) { if (terminated) {
@ -153,7 +153,7 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
var disableRange = data.disableRange; var disableRange = data.disableRange;
if (source.data) { if (source.data) {
try { try {
pdfManager = new LocalPdfManager(source.data, source.password); pdfManager = new LocalPdfManager(docId, source.data, source.password);
pdfManagerCapability.resolve(pdfManager); pdfManagerCapability.resolve(pdfManager);
} catch (ex) { } catch (ex) {
pdfManagerCapability.reject(ex); pdfManagerCapability.reject(ex);
@ -161,7 +161,7 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
return pdfManagerCapability.promise; return pdfManagerCapability.promise;
} else if (source.chunkedViewerLoading) { } else if (source.chunkedViewerLoading) {
try { try {
pdfManager = new NetworkPdfManager(source, handler); pdfManager = new NetworkPdfManager(docId, source, handler);
pdfManagerCapability.resolve(pdfManager); pdfManagerCapability.resolve(pdfManager);
} catch (ex) { } catch (ex) {
pdfManagerCapability.reject(ex); pdfManagerCapability.reject(ex);
@ -218,7 +218,7 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
} }
try { try {
pdfManager = new NetworkPdfManager(source, handler); pdfManager = new NetworkPdfManager(docId, source, handler);
pdfManagerCapability.resolve(pdfManager); pdfManagerCapability.resolve(pdfManager);
} catch (ex) { } catch (ex) {
pdfManagerCapability.reject(ex); pdfManagerCapability.reject(ex);
@ -263,7 +263,7 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
// the data is array, instantiating directly from it // the data is array, instantiating directly from it
try { try {
pdfManager = new LocalPdfManager(pdfFile, source.password); pdfManager = new LocalPdfManager(docId, pdfFile, source.password);
pdfManagerCapability.resolve(pdfManager); pdfManagerCapability.resolve(pdfManager);
} catch (ex) { } catch (ex) {
pdfManagerCapability.reject(ex); pdfManagerCapability.reject(ex);

7
src/display/api.js

@ -1299,6 +1299,7 @@ var WorkerTransport = (function WorkerTransportClosure() {
this.loadingTask = loadingTask; this.loadingTask = loadingTask;
this.pdfDataRangeTransport = pdfDataRangeTransport; this.pdfDataRangeTransport = pdfDataRangeTransport;
this.commonObjs = new PDFObjects(); this.commonObjs = new PDFObjects();
this.fontLoader = new FontLoader(loadingTask.docId);
this.destroyed = false; this.destroyed = false;
this.destroyCapability = null; this.destroyCapability = null;
@ -1333,7 +1334,7 @@ var WorkerTransport = (function WorkerTransportClosure() {
var terminated = this.messageHandler.sendWithPromise('Terminate', null); var terminated = this.messageHandler.sendWithPromise('Terminate', null);
waitOn.push(terminated); waitOn.push(terminated);
Promise.all(waitOn).then(function () { Promise.all(waitOn).then(function () {
FontLoader.clear(); self.fontLoader.clear();
if (self.pdfDataRangeTransport) { if (self.pdfDataRangeTransport) {
self.pdfDataRangeTransport.abort(); self.pdfDataRangeTransport.abort();
self.pdfDataRangeTransport = null; self.pdfDataRangeTransport = null;
@ -1489,7 +1490,7 @@ var WorkerTransport = (function WorkerTransportClosure() {
font = new FontFaceObject(exportedData); font = new FontFaceObject(exportedData);
} }
FontLoader.bind( this.fontLoader.bind(
[font], [font],
function fontReady(fontObjs) { function fontReady(fontObjs) {
this.commonObjs.resolve(id, font); this.commonObjs.resolve(id, font);
@ -1697,7 +1698,7 @@ var WorkerTransport = (function WorkerTransportClosure() {
} }
} }
this.commonObjs.clear(); this.commonObjs.clear();
FontLoader.clear(); this.fontLoader.clear();
}.bind(this)); }.bind(this));
} }
}; };

142
src/display/font_loader.js

@ -19,12 +19,24 @@
PDFJS.disableFontFace = false; PDFJS.disableFontFace = false;
var FontLoader = { function FontLoader(docId) {
this.docId = docId;
this.styleElement = null;
//#if !(MOZCENTRAL)
this.nativeFontFaces = [];
this.loadTestFontId = 0;
this.loadingContext = {
requests: [],
nextRequestId: 0
};
//#endif
}
FontLoader.prototype = {
insertRule: function fontLoaderInsertRule(rule) { insertRule: function fontLoaderInsertRule(rule) {
var styleElement = document.getElementById('PDFJS_FONT_STYLE_TAG'); var styleElement = this.styleElement;
if (!styleElement) { if (!styleElement) {
styleElement = document.createElement('style'); styleElement = this.styleElement = document.createElement('style');
styleElement.id = 'PDFJS_FONT_STYLE_TAG'; styleElement.id = 'PDFJS_FONT_STYLE_TAG_' + this.docId;
document.documentElement.getElementsByTagName('head')[0].appendChild( document.documentElement.getElementsByTagName('head')[0].appendChild(
styleElement); styleElement);
} }
@ -34,7 +46,7 @@ var FontLoader = {
}, },
clear: function fontLoaderClear() { clear: function fontLoaderClear() {
var styleElement = document.getElementById('PDFJS_FONT_STYLE_TAG'); var styleElement = this.styleElement;
if (styleElement) { if (styleElement) {
styleElement.parentNode.removeChild(styleElement); styleElement.parentNode.removeChild(styleElement);
} }
@ -75,49 +87,6 @@ var FontLoader = {
)); ));
}, },
get isEvalSupported() {
var evalSupport = false;
if (PDFJS.isEvalSupported) {
try {
/* jshint evil: true */
new Function('');
evalSupport = true;
} catch (e) {}
}
return shadow(this, 'isEvalSupported', evalSupport);
},
loadTestFontId: 0,
loadingContext: {
requests: [],
nextRequestId: 0
},
isSyncFontLoadingSupported: (function detectSyncFontLoadingSupport() {
if (isWorker) {
return false;
}
// User agent string sniffing is bad, but there is no reliable way to tell
// if font is fully loaded and ready to be used with canvas.
var userAgent = window.navigator.userAgent;
var m = /Mozilla\/5.0.*?rv:(\d+).*? Gecko/.exec(userAgent);
if (m && m[1] >= 14) {
return true;
}
// TODO other browsers
if (userAgent === 'node') {
return true;
}
return false;
})(),
nativeFontFaces: [],
isFontLoadingAPISupported: (!isWorker && typeof document !== 'undefined' &&
!!document.fonts),
addNativeFontFace: function fontLoader_addNativeFontFace(nativeFontFace) { addNativeFontFace: function fontLoader_addNativeFontFace(nativeFontFace) {
this.nativeFontFaces.push(nativeFontFace); this.nativeFontFaces.push(nativeFontFace);
document.fonts.add(nativeFontFace); document.fonts.add(nativeFontFace);
@ -146,27 +115,29 @@ var FontLoader = {
} }
font.attached = true; font.attached = true;
if (this.isFontLoadingAPISupported) { if (FontLoader.isFontLoadingAPISupported) {
var nativeFontFace = font.createNativeFontFace(); var nativeFontFace = font.createNativeFontFace();
if (nativeFontFace) { if (nativeFontFace) {
this.addNativeFontFace(nativeFontFace);
fontLoadPromises.push(getNativeFontPromise(nativeFontFace)); fontLoadPromises.push(getNativeFontPromise(nativeFontFace));
} }
} else { } else {
var rule = font.bindDOM(); var rule = font.createFontFaceRule();
if (rule) { if (rule) {
this.insertRule(rule);
rules.push(rule); rules.push(rule);
fontsToLoad.push(font); fontsToLoad.push(font);
} }
} }
} }
var request = FontLoader.queueLoadingCallback(callback); var request = this.queueLoadingCallback(callback);
if (this.isFontLoadingAPISupported) { if (FontLoader.isFontLoadingAPISupported) {
Promise.all(fontLoadPromises).then(function() { Promise.all(fontLoadPromises).then(function() {
request.complete(); request.complete();
}); });
} else if (rules.length > 0 && !this.isSyncFontLoadingSupported) { } else if (rules.length > 0 && !FontLoader.isSyncFontLoadingSupported) {
FontLoader.prepareFontLoadEvent(rules, fontsToLoad, request); this.prepareFontLoadEvent(rules, fontsToLoad, request);
} else { } else {
request.complete(); request.complete();
} }
@ -184,7 +155,7 @@ var FontLoader = {
} }
} }
var context = FontLoader.loadingContext; var context = this.loadingContext;
var requestId = 'pdfjs-font-loading-' + (context.nextRequestId++); var requestId = 'pdfjs-font-loading-' + (context.nextRequestId++);
var request = { var request = {
id: requestId, id: requestId,
@ -271,7 +242,7 @@ var FontLoader = {
var url = 'url(data:font/opentype;base64,' + btoa(data) + ');'; var url = 'url(data:font/opentype;base64,' + btoa(data) + ');';
var rule = '@font-face { font-family:"' + loadTestFontId + '";src:' + var rule = '@font-face { font-family:"' + loadTestFontId + '";src:' +
url + '}'; url + '}';
FontLoader.insertRule(rule); this.insertRule(rule);
var names = []; var names = [];
for (i = 0, ii = fonts.length; i < ii; i++) { for (i = 0, ii = fonts.length; i < ii; i++) {
@ -316,19 +287,56 @@ var FontLoader = {
//} //}
//#endif //#endif
}; };
//#if !(MOZCENTRAL)
FontLoader.isFontLoadingAPISupported = (!isWorker &&
typeof document !== 'undefined' && !!document.fonts);
//#endif
//#if !(MOZCENTRAL || CHROME)
Object.defineProperty(FontLoader, 'isSyncFontLoadingSupported', {
get: function () {
var supported = false;
// User agent string sniffing is bad, but there is no reliable way to tell
// if font is fully loaded and ready to be used with canvas.
var userAgent = window.navigator.userAgent;
var m = /Mozilla\/5.0.*?rv:(\d+).*? Gecko/.exec(userAgent);
if (m && m[1] >= 14) {
supported = true;
}
// TODO other browsers
if (userAgent === 'node') {
supported = true;
}
return shadow(FontLoader, 'isSyncFontLoadingSupported', supported);
},
enumerable: true,
configurable: true
});
//#endif
var FontFaceObject = (function FontFaceObjectClosure() { var FontFaceObject = (function FontFaceObjectClosure() {
function FontFaceObject(name, file, properties) { function FontFaceObject(translatedData) {
this.compiledGlyphs = {}; this.compiledGlyphs = {};
if (arguments.length === 1) {
// importing translated data // importing translated data
var data = arguments[0]; for (var i in translatedData) {
for (var i in data) { this[i] = translatedData[i];
this[i] = data[i];
} }
return;
} }
Object.defineProperty(FontFaceObject, 'isEvalSupported', {
get: function () {
var evalSupport = false;
if (PDFJS.isEvalSupported) {
try {
/* jshint evil: true */
new Function('');
evalSupport = true;
} catch (e) {}
} }
return shadow(this, 'isEvalSupported', evalSupport);
},
enumerable: true,
configurable: true
});
FontFaceObject.prototype = { FontFaceObject.prototype = {
//#if !(MOZCENTRAL) //#if !(MOZCENTRAL)
createNativeFontFace: function FontFaceObject_createNativeFontFace() { createNativeFontFace: function FontFaceObject_createNativeFontFace() {
@ -343,8 +351,6 @@ var FontFaceObject = (function FontFaceObjectClosure() {
var nativeFontFace = new FontFace(this.loadedName, this.data, {}); var nativeFontFace = new FontFace(this.loadedName, this.data, {});
FontLoader.addNativeFontFace(nativeFontFace);
if (PDFJS.pdfBug && 'FontInspector' in globalScope && if (PDFJS.pdfBug && 'FontInspector' in globalScope &&
globalScope['FontInspector'].enabled) { globalScope['FontInspector'].enabled) {
globalScope['FontInspector'].fontAdded(this); globalScope['FontInspector'].fontAdded(this);
@ -353,7 +359,7 @@ var FontFaceObject = (function FontFaceObjectClosure() {
}, },
//#endif //#endif
bindDOM: function FontFaceObject_bindDOM() { createFontFaceRule: function FontFaceObject_createFontFaceRule() {
if (!this.data) { if (!this.data) {
return null; return null;
} }
@ -370,7 +376,6 @@ var FontFaceObject = (function FontFaceObjectClosure() {
var url = ('url(data:' + this.mimetype + ';base64,' + var url = ('url(data:' + this.mimetype + ';base64,' +
window.btoa(data) + ');'); window.btoa(data) + ');');
var rule = '@font-face { font-family:"' + fontName + '";src:' + url + '}'; var rule = '@font-face { font-family:"' + fontName + '";src:' + url + '}';
FontLoader.insertRule(rule);
if (PDFJS.pdfBug && 'FontInspector' in globalScope && if (PDFJS.pdfBug && 'FontInspector' in globalScope &&
globalScope['FontInspector'].enabled) { globalScope['FontInspector'].enabled) {
@ -380,13 +385,14 @@ var FontFaceObject = (function FontFaceObjectClosure() {
return rule; return rule;
}, },
getPathGenerator: function FontLoader_getPathGenerator(objs, character) { getPathGenerator:
function FontFaceObject_getPathGenerator(objs, character) {
if (!(character in this.compiledGlyphs)) { if (!(character in this.compiledGlyphs)) {
var cmds = objs.get(this.loadedName + '_path_' + character); var cmds = objs.get(this.loadedName + '_path_' + character);
var current, i, len; var current, i, len;
// If we can, compile cmds into JS for MAXIMUM SPEED // If we can, compile cmds into JS for MAXIMUM SPEED
if (FontLoader.isEvalSupported) { if (FontFaceObject.isEvalSupported) {
var args, js = ''; var args, js = '';
for (i = 0, len = cmds.length; i < len; i++) { for (i = 0, len = cmds.length; i < len; i++) {
current = cmds[i]; current = cmds[i];

Loading…
Cancel
Save