Merge pull request #9982 from Snuffleupagus/mozcentral-FontLoadingAPI

Use the Font Loading API in `MOZCENTRAL` builds, and `GENERIC` builds for Firefox version 63 and above (issue 9945, bug 1088663)
This commit is contained in:
Brendan Dahl 2018-10-01 13:44:47 -07:00 committed by GitHub
commit 25446dbd8d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 342 additions and 344 deletions

View File

@ -589,8 +589,6 @@ var Font = (function FontClosure() {
this.toUnicode = properties.toUnicode; this.toUnicode = properties.toUnicode;
this.encoding = properties.baseEncoding; this.encoding = properties.baseEncoding;
this.seacMap = properties.seacMap; this.seacMap = properties.seacMap;
this.loading = true;
} }
Font.getFontID = (function () { Font.getFontID = (function () {
@ -1261,7 +1259,6 @@ var Font = (function FontClosure() {
}); });
} }
this.loadedName = fontName.split('-')[0]; this.loadedName = fontName.split('-')[0];
this.loading = false;
this.fontType = getFontType(type, subtype); this.fontType = getFontType(type, subtype);
}, },
@ -2944,7 +2941,7 @@ var ErrorFont = (function ErrorFontClosure() {
function ErrorFont(error) { function ErrorFont(error) {
this.error = error; this.error = error;
this.loadedName = 'g_font_error'; this.loadedName = 'g_font_error';
this.loading = false; this.missingFile = true;
} }
ErrorFont.prototype = { ErrorFont.prototype = {

View File

@ -14,125 +14,83 @@
*/ */
import { import {
assert, bytesToString, isEvalSupported, shadow, string32, assert, bytesToString, isEvalSupported, shadow, string32, unreachable,
UNSUPPORTED_FEATURES, warn UNSUPPORTED_FEATURES, warn
} from '../shared/util'; } from '../shared/util';
function FontLoader(docId) { class BaseFontLoader {
constructor(docId) {
if (this.constructor === BaseFontLoader) {
unreachable('Cannot initialize BaseFontLoader.');
}
this.docId = docId; this.docId = docId;
this.styleElement = null;
if (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('MOZCENTRAL')) {
this.nativeFontFaces = []; this.nativeFontFaces = [];
this.loadTestFontId = 0; this.styleElement = null;
this.loadingContext = { this.loadingContext = {
requests: [], requests: [],
nextRequestId: 0, nextRequestId: 0,
}; };
} }
addNativeFontFace(nativeFontFace) {
this.nativeFontFaces.push(nativeFontFace);
document.fonts.add(nativeFontFace);
} }
FontLoader.prototype = {
insertRule: function fontLoaderInsertRule(rule) { insertRule(rule) {
var styleElement = this.styleElement; let styleElement = this.styleElement;
if (!styleElement) { if (!styleElement) {
styleElement = this.styleElement = document.createElement('style'); styleElement = this.styleElement = document.createElement('style');
styleElement.id = 'PDFJS_FONT_STYLE_TAG_' + this.docId; styleElement.id = `PDFJS_FONT_STYLE_TAG_${this.docId}`;
document.documentElement.getElementsByTagName('head')[0].appendChild( document.documentElement.getElementsByTagName('head')[0].appendChild(
styleElement); styleElement);
} }
var styleSheet = styleElement.sheet; const styleSheet = styleElement.sheet;
styleSheet.insertRule(rule, styleSheet.cssRules.length); styleSheet.insertRule(rule, styleSheet.cssRules.length);
}, }
clear() {
this.nativeFontFaces.forEach(function(nativeFontFace) {
document.fonts.delete(nativeFontFace);
});
this.nativeFontFaces.length = 0;
clear: function fontLoaderClear() {
if (this.styleElement) { if (this.styleElement) {
// Note: ChildNode.remove doesn't throw if the parentNode is undefined. // Note: ChildNode.remove doesn't throw if the parentNode is undefined.
this.styleElement.remove(); this.styleElement.remove();
this.styleElement = null; this.styleElement = null;
} }
if (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('MOZCENTRAL')) {
this.nativeFontFaces.forEach(function(nativeFontFace) {
document.fonts.delete(nativeFontFace);
});
this.nativeFontFaces.length = 0;
} }
},
};
if (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('MOZCENTRAL')) { bind(fonts, callback) {
var getLoadTestFont = function () { const rules = [];
// This is a CFF font with 1 glyph for '.' that fills its entire width and const fontsToLoad = [];
// height. const fontLoadPromises = [];
return atob( const getNativeFontPromise = function(nativeFontFace) {
'T1RUTwALAIAAAwAwQ0ZGIDHtZg4AAAOYAAAAgUZGVE1lkzZwAAAEHAAAABxHREVGABQAFQ' +
'AABDgAAAAeT1MvMlYNYwkAAAEgAAAAYGNtYXABDQLUAAACNAAAAUJoZWFk/xVFDQAAALwA' +
'AAA2aGhlYQdkA+oAAAD0AAAAJGhtdHgD6AAAAAAEWAAAAAZtYXhwAAJQAAAAARgAAAAGbm' +
'FtZVjmdH4AAAGAAAAAsXBvc3T/hgAzAAADeAAAACAAAQAAAAEAALZRFsRfDzz1AAsD6AAA' +
'AADOBOTLAAAAAM4KHDwAAAAAA+gDIQAAAAgAAgAAAAAAAAABAAADIQAAAFoD6AAAAAAD6A' +
'ABAAAAAAAAAAAAAAAAAAAAAQAAUAAAAgAAAAQD6AH0AAUAAAKKArwAAACMAooCvAAAAeAA' +
'MQECAAACAAYJAAAAAAAAAAAAAQAAAAAAAAAAAAAAAFBmRWQAwAAuAC4DIP84AFoDIQAAAA' +
'AAAQAAAAAAAAAAACAAIAABAAAADgCuAAEAAAAAAAAAAQAAAAEAAAAAAAEAAQAAAAEAAAAA' +
'AAIAAQAAAAEAAAAAAAMAAQAAAAEAAAAAAAQAAQAAAAEAAAAAAAUAAQAAAAEAAAAAAAYAAQ' +
'AAAAMAAQQJAAAAAgABAAMAAQQJAAEAAgABAAMAAQQJAAIAAgABAAMAAQQJAAMAAgABAAMA' +
'AQQJAAQAAgABAAMAAQQJAAUAAgABAAMAAQQJAAYAAgABWABYAAAAAAAAAwAAAAMAAAAcAA' +
'EAAAAAADwAAwABAAAAHAAEACAAAAAEAAQAAQAAAC7//wAAAC7////TAAEAAAAAAAABBgAA' +
'AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAA' +
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAA' +
'AAAAD/gwAyAAAAAQAAAAAAAAAAAAAAAAAAAAABAAQEAAEBAQJYAAEBASH4DwD4GwHEAvgc' +
'A/gXBIwMAYuL+nz5tQXkD5j3CBLnEQACAQEBIVhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWF' +
'hYWFhYWFhYAAABAQAADwACAQEEE/t3Dov6fAH6fAT+fPp8+nwHDosMCvm1Cvm1DAz6fBQA' +
'AAAAAAABAAAAAMmJbzEAAAAAzgTjFQAAAADOBOQpAAEAAAAAAAAADAAUAAQAAAABAAAAAg' +
'ABAAAAAAAAAAAD6AAAAAAAAA==');
};
Object.defineProperty(FontLoader.prototype, 'loadTestFont', {
get() {
return shadow(this, 'loadTestFont', getLoadTestFont());
},
configurable: true,
});
FontLoader.prototype.addNativeFontFace =
function fontLoader_addNativeFontFace(nativeFontFace) {
this.nativeFontFaces.push(nativeFontFace);
document.fonts.add(nativeFontFace);
};
FontLoader.prototype.bind = function fontLoaderBind(fonts, callback) {
var rules = [];
var fontsToLoad = [];
var fontLoadPromises = [];
var getNativeFontPromise = function(nativeFontFace) {
// Return a promise that is always fulfilled, even when the font fails to // Return a promise that is always fulfilled, even when the font fails to
// load. // load.
return nativeFontFace.loaded.catch(function(e) { return nativeFontFace.loaded.catch(function(reason) {
warn('Failed to load font "' + nativeFontFace.family + '": ' + e); warn(`Failed to load font "${nativeFontFace.family}": ${reason}`);
}); });
}; };
// Firefox Font Loading API does not work with mozPrintCallback --
// disabling it in this case.
var isFontLoadingAPISupported = FontLoader.isFontLoadingAPISupported &&
!FontLoader.isSyncFontLoadingSupported;
for (var i = 0, ii = fonts.length; i < ii; i++) {
var font = fonts[i];
// Add the font to the DOM only once or skip if the font for (const font of fonts) {
// is already loaded. // Add the font to the DOM only once; skip if the font is already loaded.
if (font.attached || font.loading === false) { if (font.attached || font.missingFile) {
continue; continue;
} }
font.attached = true; font.attached = true;
if (isFontLoadingAPISupported) { if (this.isFontLoadingAPISupported) {
var nativeFontFace = font.createNativeFontFace(); const nativeFontFace = font.createNativeFontFace();
if (nativeFontFace) { if (nativeFontFace) {
this.addNativeFontFace(nativeFontFace); this.addNativeFontFace(nativeFontFace);
fontLoadPromises.push(getNativeFontPromise(nativeFontFace)); fontLoadPromises.push(getNativeFontPromise(nativeFontFace));
} }
} else { } else {
var rule = font.createFontFaceRule(); const rule = font.createFontFaceRule();
if (rule) { if (rule) {
this.insertRule(rule); this.insertRule(rule);
rules.push(rule); rules.push(rule);
@ -141,51 +99,149 @@ if (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('MOZCENTRAL')) {
} }
} }
var request = this.queueLoadingCallback(callback); const request = this._queueLoadingCallback(callback);
if (isFontLoadingAPISupported) { if (this.isFontLoadingAPISupported) {
Promise.all(fontLoadPromises).then(function() { Promise.all(fontLoadPromises).then(request.complete);
request.complete(); } else if (rules.length > 0 && !this.isSyncFontLoadingSupported) {
}); this._prepareFontLoadEvent(rules, fontsToLoad, request);
} else if (rules.length > 0 && !FontLoader.isSyncFontLoadingSupported) {
this.prepareFontLoadEvent(rules, fontsToLoad, request);
} else { } else {
request.complete(); request.complete();
} }
}; }
FontLoader.prototype.queueLoadingCallback = _queueLoadingCallback(callback) {
function FontLoader_queueLoadingCallback(callback) { function completeRequest() {
function LoadLoader_completeRequest() { assert(!request.done, 'completeRequest() cannot be called twice.');
assert(!request.end, 'completeRequest() cannot be called twice'); request.done = true;
request.end = Date.now();
// sending all completed requests in order how they were queued // Sending all completed requests in order of how they were queued.
while (context.requests.length > 0 && context.requests[0].end) { while (context.requests.length > 0 && context.requests[0].done) {
var otherRequest = context.requests.shift(); const otherRequest = context.requests.shift();
setTimeout(otherRequest.callback, 0); setTimeout(otherRequest.callback, 0);
} }
} }
var context = this.loadingContext; const context = this.loadingContext;
var requestId = 'pdfjs-font-loading-' + (context.nextRequestId++); const request = {
var request = { id: `pdfjs-font-loading-${context.nextRequestId++}`,
id: requestId, done: false,
complete: LoadLoader_completeRequest, complete: completeRequest,
callback, callback,
started: Date.now(),
}; };
context.requests.push(request); context.requests.push(request);
return request; return request;
}
get isFontLoadingAPISupported() {
unreachable('Abstract method `isFontLoadingAPISupported`.');
}
get isSyncFontLoadingSupported() {
unreachable('Abstract method `isSyncFontLoadingSupported`.');
}
get _loadTestFont() {
unreachable('Abstract method `_loadTestFont`.');
}
_prepareFontLoadEvent(rules, fontsToLoad, request) {
unreachable('Abstract method `_prepareFontLoadEvent`.');
}
}
let FontLoader;
if (typeof PDFJSDev !== 'undefined' && PDFJSDev.test('MOZCENTRAL')) {
FontLoader = class MozcentralFontLoader extends BaseFontLoader {
get isFontLoadingAPISupported() {
return shadow(this, 'isFontLoadingAPISupported',
typeof document !== 'undefined' && !!document.fonts);
}
get isSyncFontLoadingSupported() {
return shadow(this, 'isSyncFontLoadingSupported', true);
}
}; };
FontLoader.prototype.prepareFontLoadEvent = } else { // PDFJSDev.test('CHROME || GENERIC')
function fontLoaderPrepareFontLoadEvent(rules, fonts, request) {
FontLoader = class GenericFontLoader extends BaseFontLoader {
constructor(docId) {
super(docId);
this.loadTestFontId = 0;
}
get isFontLoadingAPISupported() {
let supported = (typeof document !== 'undefined' && !!document.fonts);
if ((typeof PDFJSDev === 'undefined' || !PDFJSDev.test('CHROME')) &&
(supported && typeof navigator !== 'undefined')) {
// The Firefox Font Loading API does not work with `mozPrintCallback`
// prior to version 63; see https://bugzilla.mozilla.org/show_bug.cgi?id=1473742
const m = /Mozilla\/5.0.*?rv:(\d+).*? Gecko/.exec(navigator.userAgent);
if (m && m[1] < 63) {
supported = false;
}
}
return shadow(this, 'isFontLoadingAPISupported', supported);
}
get isSyncFontLoadingSupported() {
let supported = false;
if (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('CHROME')) {
if (typeof navigator === 'undefined') {
// Node.js - we can pretend that sync font loading is supported.
supported = true;
} else {
// User agent string sniffing is bad, but there is no reliable way to
// tell if the font is fully loaded and ready to be used with canvas.
const m = /Mozilla\/5.0.*?rv:(\d+).*? Gecko/.exec(navigator.userAgent);
if (m && m[1] >= 14) {
supported = true;
}
// TODO - other browsers...
}
}
return shadow(this, 'isSyncFontLoadingSupported', supported);
}
get _loadTestFont() {
const getLoadTestFont = function() {
// This is a CFF font with 1 glyph for '.' that fills its entire width and
// height.
return atob(
'T1RUTwALAIAAAwAwQ0ZGIDHtZg4AAAOYAAAAgUZGVE1lkzZwAAAEHAAAABxHREVGABQA' +
'FQAABDgAAAAeT1MvMlYNYwkAAAEgAAAAYGNtYXABDQLUAAACNAAAAUJoZWFk/xVFDQAA' +
'ALwAAAA2aGhlYQdkA+oAAAD0AAAAJGhtdHgD6AAAAAAEWAAAAAZtYXhwAAJQAAAAARgA' +
'AAAGbmFtZVjmdH4AAAGAAAAAsXBvc3T/hgAzAAADeAAAACAAAQAAAAEAALZRFsRfDzz1' +
'AAsD6AAAAADOBOTLAAAAAM4KHDwAAAAAA+gDIQAAAAgAAgAAAAAAAAABAAADIQAAAFoD' +
'6AAAAAAD6AABAAAAAAAAAAAAAAAAAAAAAQAAUAAAAgAAAAQD6AH0AAUAAAKKArwAAACM' +
'AooCvAAAAeAAMQECAAACAAYJAAAAAAAAAAAAAQAAAAAAAAAAAAAAAFBmRWQAwAAuAC4D' +
'IP84AFoDIQAAAAAAAQAAAAAAAAAAACAAIAABAAAADgCuAAEAAAAAAAAAAQAAAAEAAAAA' +
'AAEAAQAAAAEAAAAAAAIAAQAAAAEAAAAAAAMAAQAAAAEAAAAAAAQAAQAAAAEAAAAAAAUA' +
'AQAAAAEAAAAAAAYAAQAAAAMAAQQJAAAAAgABAAMAAQQJAAEAAgABAAMAAQQJAAIAAgAB' +
'AAMAAQQJAAMAAgABAAMAAQQJAAQAAgABAAMAAQQJAAUAAgABAAMAAQQJAAYAAgABWABY' +
'AAAAAAAAAwAAAAMAAAAcAAEAAAAAADwAAwABAAAAHAAEACAAAAAEAAQAAQAAAC7//wAA' +
'AC7////TAAEAAAAAAAABBgAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
'AAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAD/gwAyAAAAAQAAAAAAAAAAAAAAAAAA' +
'AAABAAQEAAEBAQJYAAEBASH4DwD4GwHEAvgcA/gXBIwMAYuL+nz5tQXkD5j3CBLnEQAC' +
'AQEBIVhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYAAABAQAADwACAQEEE/t3' +
'Dov6fAH6fAT+fPp8+nwHDosMCvm1Cvm1DAz6fBQAAAAAAAABAAAAAMmJbzEAAAAAzgTj' +
'FQAAAADOBOQpAAEAAAAAAAAADAAUAAQAAAABAAAAAgABAAAAAAAAAAAD6AAAAAAAAA==');
};
return shadow(this, '_loadTestFont', getLoadTestFont());
}
_prepareFontLoadEvent(rules, fonts, request) {
/** Hack begin */ /** Hack begin */
// There's currently no event when a font has finished downloading so the // There's currently no event when a font has finished downloading so the
// following code is a dirty hack to 'guess' when a font is // following code is a dirty hack to 'guess' when a font is ready.
// ready. It's assumed fonts are loaded in order, so add a known test // It's assumed fonts are loaded in order, so add a known test font after
// font after the desired fonts and then test for the loading of that // the desired fonts and then test for the loading of that test font.
// test font.
function int32(data, offset) { function int32(data, offset) {
return (data.charCodeAt(offset) << 24) | return (data.charCodeAt(offset) << 24) |
@ -193,22 +249,20 @@ if (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('MOZCENTRAL')) {
(data.charCodeAt(offset + 2) << 8) | (data.charCodeAt(offset + 2) << 8) |
(data.charCodeAt(offset + 3) & 0xff); (data.charCodeAt(offset + 3) & 0xff);
} }
function spliceString(s, offset, remove, insert) { function spliceString(s, offset, remove, insert) {
var chunk1 = s.substring(0, offset); let chunk1 = s.substring(0, offset);
var chunk2 = s.substring(offset + remove); let chunk2 = s.substring(offset + remove);
return chunk1 + insert + chunk2; return chunk1 + insert + chunk2;
} }
let i, ii;
var i, ii;
// The temporary canvas is used to determine if fonts are loaded. // The temporary canvas is used to determine if fonts are loaded.
var canvas = document.createElement('canvas'); let canvas = document.createElement('canvas');
canvas.width = 1; canvas.width = 1;
canvas.height = 1; canvas.height = 1;
var ctx = canvas.getContext('2d'); let ctx = canvas.getContext('2d');
var called = 0; let called = 0;
function isFontReady(name, callback) { function isFontReady(name, callback) {
called++; called++;
// With setTimeout clamping this gives the font ~100ms to load. // With setTimeout clamping this gives the font ~100ms to load.
@ -219,7 +273,7 @@ if (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('MOZCENTRAL')) {
} }
ctx.font = '30px ' + name; ctx.font = '30px ' + name;
ctx.fillText('.', 0, 20); ctx.fillText('.', 0, 20);
var imageData = ctx.getImageData(0, 0, 1, 1); let imageData = ctx.getImageData(0, 0, 1, 1);
if (imageData.data[3] > 0) { if (imageData.data[3] > 0) {
callback(); callback();
return; return;
@ -227,47 +281,44 @@ if (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('MOZCENTRAL')) {
setTimeout(isFontReady.bind(null, name, callback)); setTimeout(isFontReady.bind(null, name, callback));
} }
var loadTestFontId = 'lt' + Date.now() + this.loadTestFontId++; const loadTestFontId = `lt${Date.now()}${this.loadTestFontId++}`;
// Chromium seems to cache fonts based on a hash of the actual font data, // Chromium seems to cache fonts based on a hash of the actual font data,
// so the font must be modified for each load test else it will appear to // so the font must be modified for each load test else it will appear to
// be loaded already. // be loaded already.
// TODO: This could maybe be made faster by avoiding the btoa of the full // TODO: This could maybe be made faster by avoiding the btoa of the full
// font by splitting it in chunks before hand and padding the font id. // font by splitting it in chunks before hand and padding the font id.
var data = this.loadTestFont; let data = this._loadTestFont;
var COMMENT_OFFSET = 976; // has to be on 4 byte boundary (for checksum) let COMMENT_OFFSET = 976; // has to be on 4 byte boundary (for checksum)
data = spliceString(data, COMMENT_OFFSET, loadTestFontId.length, data = spliceString(data, COMMENT_OFFSET, loadTestFontId.length,
loadTestFontId); loadTestFontId);
// CFF checksum is important for IE, adjusting it // CFF checksum is important for IE, adjusting it
var CFF_CHECKSUM_OFFSET = 16; let CFF_CHECKSUM_OFFSET = 16;
var XXXX_VALUE = 0x58585858; // the "comment" filled with 'X' let XXXX_VALUE = 0x58585858; // the "comment" filled with 'X'
var checksum = int32(data, CFF_CHECKSUM_OFFSET); let checksum = int32(data, CFF_CHECKSUM_OFFSET);
for (i = 0, ii = loadTestFontId.length - 3; i < ii; i += 4) { for (i = 0, ii = loadTestFontId.length - 3; i < ii; i += 4) {
checksum = (checksum - XXXX_VALUE + int32(loadTestFontId, i)) | 0; checksum = (checksum - XXXX_VALUE + int32(loadTestFontId, i)) | 0;
} }
if (i < loadTestFontId.length) { // align to 4 bytes boundary if (i < loadTestFontId.length) { // align to 4 bytes boundary
checksum = (checksum - XXXX_VALUE + checksum = (checksum - XXXX_VALUE + int32(loadTestFontId + 'XXX', i)) | 0;
int32(loadTestFontId + 'XXX', i)) | 0;
} }
data = spliceString(data, CFF_CHECKSUM_OFFSET, 4, string32(checksum)); data = spliceString(data, CFF_CHECKSUM_OFFSET, 4, string32(checksum));
var url = 'url(data:font/opentype;base64,' + btoa(data) + ');'; const url = `url(data:font/opentype;base64,${btoa(data)});`;
var rule = '@font-face { font-family:"' + loadTestFontId + '";src:' + const rule = `@font-face {font-family:"${loadTestFontId}";src:${url}}`;
url + '}';
this.insertRule(rule); this.insertRule(rule);
var names = []; let names = [];
for (i = 0, ii = fonts.length; i < ii; i++) { for (i = 0, ii = fonts.length; i < ii; i++) {
names.push(fonts[i].loadedName); names.push(fonts[i].loadedName);
} }
names.push(loadTestFontId); names.push(loadTestFontId);
var div = document.createElement('div'); let div = document.createElement('div');
div.setAttribute('style', div.setAttribute('style', 'visibility: hidden;' +
'visibility: hidden;' +
'width: 10px; height: 10px;' + 'width: 10px; height: 10px;' +
'position: absolute; top: 0px; left: 0px;'); 'position: absolute; top: 0px; left: 0px;');
for (i = 0, ii = names.length; i < ii; ++i) { for (i = 0, ii = names.length; i < ii; ++i) {
var span = document.createElement('span'); let span = document.createElement('span');
span.textContent = 'Hi'; span.textContent = 'Hi';
span.style.fontFamily = names[i]; span.style.fontFamily = names[i];
div.appendChild(span); div.appendChild(span);
@ -279,72 +330,26 @@ if (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('MOZCENTRAL')) {
request.complete(); request.complete();
}); });
/** Hack end */ /** Hack end */
}
}; };
} else {
FontLoader.prototype.bind = function fontLoaderBind(fonts, callback) {
for (var i = 0, ii = fonts.length; i < ii; i++) {
var font = fonts[i];
if (font.attached) {
continue;
}
font.attached = true; } // End of PDFJSDev.test('CHROME || GENERIC')
var rule = font.createFontFaceRule();
if (rule) {
this.insertRule(rule);
}
}
setTimeout(callback); const IsEvalSupportedCached = {
};
}
if (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('MOZCENTRAL')) {
FontLoader.isFontLoadingAPISupported = typeof document !== 'undefined' &&
!!document.fonts;
}
if (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('MOZCENTRAL || CHROME')) {
var isSyncFontLoadingSupported = function isSyncFontLoadingSupported() {
if (typeof navigator === 'undefined') {
// node.js - we can pretend sync font loading is supported.
return true;
}
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 m = /Mozilla\/5.0.*?rv:(\d+).*? Gecko/.exec(navigator.userAgent);
if (m && m[1] >= 14) {
supported = true;
}
// TODO other browsers
return supported;
};
Object.defineProperty(FontLoader, 'isSyncFontLoadingSupported', {
get() {
return shadow(FontLoader, 'isSyncFontLoadingSupported',
isSyncFontLoadingSupported());
},
enumerable: true,
configurable: true,
});
}
var IsEvalSupportedCached = {
get value() { get value() {
return shadow(this, 'value', isEvalSupported()); return shadow(this, 'value', isEvalSupported());
}, },
}; };
var FontFaceObject = (function FontFaceObjectClosure() { class FontFaceObject {
function FontFaceObject(translatedData, { isEvalSupported = true, constructor(translatedData, { isEvalSupported = true,
disableFontFace = false, disableFontFace = false,
ignoreErrors = false, ignoreErrors = false,
onUnsupportedFeature = null, onUnsupportedFeature = null,
fontRegistry = null, }) { fontRegistry = null, }) {
this.compiledGlyphs = Object.create(null); this.compiledGlyphs = Object.create(null);
// importing translated data // importing translated data
for (var i in translatedData) { for (let i in translatedData) {
this[i] = translatedData[i]; this[i] = translatedData[i];
} }
this.isEvalSupported = isEvalSupported !== false; this.isEvalSupported = isEvalSupported !== false;
@ -353,42 +358,33 @@ var FontFaceObject = (function FontFaceObjectClosure() {
this._onUnsupportedFeature = onUnsupportedFeature; this._onUnsupportedFeature = onUnsupportedFeature;
this.fontRegistry = fontRegistry; this.fontRegistry = fontRegistry;
} }
FontFaceObject.prototype = {
createNativeFontFace: function FontFaceObject_createNativeFontFace() {
if (typeof PDFJSDev !== 'undefined' && PDFJSDev.test('MOZCENTRAL')) {
throw new Error('Not implemented: createNativeFontFace');
}
createNativeFontFace() {
if (!this.data || this.disableFontFace) { if (!this.data || this.disableFontFace) {
return null; return null;
} }
const nativeFontFace = new FontFace(this.loadedName, this.data, {});
var nativeFontFace = new FontFace(this.loadedName, this.data, {});
if (this.fontRegistry) { if (this.fontRegistry) {
this.fontRegistry.registerFont(this); this.fontRegistry.registerFont(this);
} }
return nativeFontFace; return nativeFontFace;
}, }
createFontFaceRule: function FontFaceObject_createFontFaceRule() { createFontFaceRule() {
if (!this.data || this.disableFontFace) { if (!this.data || this.disableFontFace) {
return null; return null;
} }
const data = bytesToString(new Uint8Array(this.data));
var data = bytesToString(new Uint8Array(this.data)); // Add the @font-face rule to the document.
var fontName = this.loadedName; const url = `url(data:${this.mimetype};base64,${btoa(data)});`;
const rule = `@font-face {font-family:"${this.loadedName}";src:${url}}`;
// Add the font-face rule to the document
var url = ('url(data:' + this.mimetype + ';base64,' + btoa(data) + ');');
var rule = '@font-face { font-family:"' + fontName + '";src:' + url + '}';
if (this.fontRegistry) { if (this.fontRegistry) {
this.fontRegistry.registerFont(this, url); this.fontRegistry.registerFont(this, url);
} }
return rule; return rule;
}, }
getPathGenerator(objs, character) { getPathGenerator(objs, character) {
if (this.compiledGlyphs[character] !== undefined) { if (this.compiledGlyphs[character] !== undefined) {
@ -440,11 +436,8 @@ var FontFaceObject = (function FontFaceObjectClosure() {
c[current.cmd].apply(c, current.args); c[current.cmd].apply(c, current.args);
} }
}; };
}, }
}; }
return FontFaceObject;
})();
export { export {
FontFaceObject, FontFaceObject,

View File

@ -183,6 +183,14 @@ const hasDOM = typeof window === 'object' && typeof document === 'object';
String.fromCodePoint = require('core-js/fn/string/from-code-point'); String.fromCodePoint = require('core-js/fn/string/from-code-point');
})(); })();
// Support: IE
(function checkSymbol() {
if (globalScope.Symbol) {
return;
}
require('core-js/es6/symbol');
})();
} // End of !PDFJSDev.test('CHROME') } // End of !PDFJSDev.test('CHROME')
// Provides support for Object.values in legacy browsers. // Provides support for Object.values in legacy browsers.