Refactor the FontLoader into proper, build-specific, ES6 classes

Also changes `var` to `let`/`const` in code already touched in the patch, and makes use of template strings in a few spots.
This commit is contained in:
Jonas Jenwald 2018-08-16 20:34:51 +02:00
parent 45d6651976
commit 05b021bcce

View File

@ -14,125 +14,86 @@
*/ */
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 {
this.docId = docId; constructor(docId) {
this.styleElement = null; if (this.constructor === BaseFontLoader) {
if (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('MOZCENTRAL')) { unreachable('Cannot initialize BaseFontLoader.');
}
this.docId = docId;
this.nativeFontFaces = []; this.nativeFontFaces = [];
this.loadTestFontId = 0; this.styleElement = null;
this.loadingContext = { this.loadingContext = {
requests: [], requests: [],
nextRequestId: 0, nextRequestId: 0,
}; };
} }
}
FontLoader.prototype = { addNativeFontFace(nativeFontFace) {
insertRule: function fontLoaderInsertRule(rule) { this.nativeFontFaces.push(nativeFontFace);
var styleElement = this.styleElement; document.fonts.add(nativeFontFace);
}
insertRule(rule) {
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 -- // Firefox Font Loading API does not work with mozPrintCallback --
// disabling it in this case. // disabling it in this case.
var isFontLoadingAPISupported = FontLoader.isFontLoadingAPISupported && const isFontLoadingAPISupported = this.isFontLoadingAPISupported &&
!FontLoader.isSyncFontLoadingSupported; !this.isSyncFontLoadingSupported;
for (var i = 0, ii = fonts.length; i < ii; i++) { for (const font of fonts) {
var font = fonts[i]; // Add the font to the DOM only once; skip if the font is already loaded.
// Add the font to the DOM only once or skip if the font
// is already loaded.
if (font.attached || font.missingFile) { if (font.attached || font.missingFile) {
continue; continue;
} }
font.attached = true; font.attached = true;
if (isFontLoadingAPISupported) { if (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,194 +102,231 @@ if (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('MOZCENTRAL')) {
} }
} }
var request = this.queueLoadingCallback(callback); const request = this._queueLoadingCallback(callback);
if (isFontLoadingAPISupported) { if (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.done, 'completeRequest() cannot be called twice.');
request.done = true; request.done = true;
// Sending all completed requests in order of how they were queued. // Sending all completed requests in order of how they were queued.
while (context.requests.length > 0 && context.requests[0].done) { 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, done: false,
complete: LoadLoader_completeRequest, complete: completeRequest,
callback, callback,
}; };
context.requests.push(request); context.requests.push(request);
return request; return request;
}; }
FontLoader.prototype.prepareFontLoadEvent = get isFontLoadingAPISupported() {
function fontLoaderPrepareFontLoadEvent(rules, fonts, request) { unreachable('Abstract method `isFontLoadingAPISupported`.');
/** Hack begin */ }
// 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
// ready. It's assumed fonts are loaded in order, so add a known test
// font after the desired fonts and then test for the loading of that
// test font.
function int32(data, offset) { get isSyncFontLoadingSupported() {
return (data.charCodeAt(offset) << 24) | unreachable('Abstract method `isSyncFontLoadingSupported`.');
(data.charCodeAt(offset + 1) << 16) | }
(data.charCodeAt(offset + 2) << 8) |
(data.charCodeAt(offset + 3) & 0xff);
}
function spliceString(s, offset, remove, insert) { get _loadTestFont() {
var chunk1 = s.substring(0, offset); unreachable('Abstract method `_loadTestFont`.');
var chunk2 = s.substring(offset + remove); }
return chunk1 + insert + chunk2;
}
var i, ii; _prepareFontLoadEvent(rules, fontsToLoad, request) {
unreachable('Abstract method `_prepareFontLoadEvent`.');
}
}
// The temporary canvas is used to determine if fonts are loaded. let FontLoader;
var canvas = document.createElement('canvas'); if (typeof PDFJSDev !== 'undefined' && PDFJSDev.test('MOZCENTRAL')) {
canvas.width = 1;
canvas.height = 1;
var ctx = canvas.getContext('2d');
var called = 0; FontLoader = class MozcentralFontLoader extends BaseFontLoader {
function isFontReady(name, callback) { get isFontLoadingAPISupported() {
called++; return shadow(this, 'isFontLoadingAPISupported',
// With setTimeout clamping this gives the font ~100ms to load. typeof document !== 'undefined' && !!document.fonts);
if (called > 30) { }
warn('Load test font never loaded.');
callback(); get isSyncFontLoadingSupported() {
return; return shadow(this, 'isSyncFontLoadingSupported', true);
}
};
} else { // PDFJSDev.test('CHROME || GENERIC')
FontLoader = class GenericFontLoader extends BaseFontLoader {
constructor(docId) {
super(docId);
this.loadTestFontId = 0;
}
get isFontLoadingAPISupported() {
let supported = (typeof document !== 'undefined' && !!document.fonts);
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;
} }
ctx.font = '30px ' + name; // TODO - other browsers...
ctx.fillText('.', 0, 20);
var imageData = ctx.getImageData(0, 0, 1, 1);
if (imageData.data[3] > 0) {
callback();
return;
}
setTimeout(isFontReady.bind(null, name, callback));
}
var loadTestFontId = 'lt' + Date.now() + this.loadTestFontId++;
// 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
// be loaded already.
// 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.
var data = this.loadTestFont;
var COMMENT_OFFSET = 976; // has to be on 4 byte boundary (for checksum)
data = spliceString(data, COMMENT_OFFSET, loadTestFontId.length,
loadTestFontId);
// CFF checksum is important for IE, adjusting it
var CFF_CHECKSUM_OFFSET = 16;
var XXXX_VALUE = 0x58585858; // the "comment" filled with 'X'
var checksum = int32(data, CFF_CHECKSUM_OFFSET);
for (i = 0, ii = loadTestFontId.length - 3; i < ii; i += 4) {
checksum = (checksum - XXXX_VALUE + int32(loadTestFontId, i)) | 0;
}
if (i < loadTestFontId.length) { // align to 4 bytes boundary
checksum = (checksum - XXXX_VALUE +
int32(loadTestFontId + 'XXX', i)) | 0;
}
data = spliceString(data, CFF_CHECKSUM_OFFSET, 4, string32(checksum));
var url = 'url(data:font/opentype;base64,' + btoa(data) + ');';
var rule = '@font-face { font-family:"' + loadTestFontId + '";src:' +
url + '}';
this.insertRule(rule);
var names = [];
for (i = 0, ii = fonts.length; i < ii; i++) {
names.push(fonts[i].loadedName);
}
names.push(loadTestFontId);
var div = document.createElement('div');
div.setAttribute('style',
'visibility: hidden;' +
'width: 10px; height: 10px;' +
'position: absolute; top: 0px; left: 0px;');
for (i = 0, ii = names.length; i < ii; ++i) {
var span = document.createElement('span');
span.textContent = 'Hi';
span.style.fontFamily = names[i];
div.appendChild(span);
}
document.body.appendChild(div);
isFontReady(loadTestFontId, function() {
document.body.removeChild(div);
request.complete();
});
/** 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;
var rule = font.createFontFaceRule();
if (rule) {
this.insertRule(rule);
} }
} }
return shadow(this, 'isSyncFontLoadingSupported', supported);
}
setTimeout(callback); get _loadTestFont() {
}; const getLoadTestFont = function() {
} // This is a CFF font with 1 glyph for '.' that fills its entire width and
if (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('MOZCENTRAL')) { // height.
FontLoader.isFontLoadingAPISupported = typeof document !== 'undefined' && return atob(
!!document.fonts; 'T1RUTwALAIAAAwAwQ0ZGIDHtZg4AAAOYAAAAgUZGVE1lkzZwAAAEHAAAABxHREVGABQA' +
} 'FQAABDgAAAAeT1MvMlYNYwkAAAEgAAAAYGNtYXABDQLUAAACNAAAAUJoZWFk/xVFDQAA' +
if (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('MOZCENTRAL || CHROME')) { 'ALwAAAA2aGhlYQdkA+oAAAD0AAAAJGhtdHgD6AAAAAAEWAAAAAZtYXhwAAJQAAAAARgA' +
var isSyncFontLoadingSupported = function isSyncFontLoadingSupported() { 'AAAGbmFtZVjmdH4AAAGAAAAAsXBvc3T/hgAzAAADeAAAACAAAQAAAAEAALZRFsRfDzz1' +
if (typeof navigator === 'undefined') { 'AAsD6AAAAADOBOTLAAAAAM4KHDwAAAAAA+gDIQAAAAgAAgAAAAAAAAABAAADIQAAAFoD' +
// node.js - we can pretend sync font loading is supported. '6AAAAAAD6AABAAAAAAAAAAAAAAAAAAAAAQAAUAAAAgAAAAQD6AH0AAUAAAKKArwAAACM' +
return true; '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 */
// 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 ready.
// It's assumed fonts are loaded in order, so add a known test font after
// the desired fonts and then test for the loading of that test font.
function int32(data, offset) {
return (data.charCodeAt(offset) << 24) |
(data.charCodeAt(offset + 1) << 16) |
(data.charCodeAt(offset + 2) << 8) |
(data.charCodeAt(offset + 3) & 0xff);
}
function spliceString(s, offset, remove, insert) {
let chunk1 = s.substring(0, offset);
let chunk2 = s.substring(offset + remove);
return chunk1 + insert + chunk2;
}
let i, ii;
// The temporary canvas is used to determine if fonts are loaded.
let canvas = document.createElement('canvas');
canvas.width = 1;
canvas.height = 1;
let ctx = canvas.getContext('2d');
let called = 0;
function isFontReady(name, callback) {
called++;
// With setTimeout clamping this gives the font ~100ms to load.
if (called > 30) {
warn('Load test font never loaded.');
callback();
return;
}
ctx.font = '30px ' + name;
ctx.fillText('.', 0, 20);
let imageData = ctx.getImageData(0, 0, 1, 1);
if (imageData.data[3] > 0) {
callback();
return;
}
setTimeout(isFontReady.bind(null, name, callback));
} }
var supported = false; const loadTestFontId = `lt${Date.now()}${this.loadTestFontId++}`;
// Chromium seems to cache fonts based on a hash of the actual font data,
// User agent string sniffing is bad, but there is no reliable way to tell // so the font must be modified for each load test else it will appear to
// if font is fully loaded and ready to be used with canvas. // be loaded already.
var m = /Mozilla\/5.0.*?rv:(\d+).*? Gecko/.exec(navigator.userAgent); // TODO: This could maybe be made faster by avoiding the btoa of the full
if (m && m[1] >= 14) { // font by splitting it in chunks before hand and padding the font id.
supported = true; let data = this._loadTestFont;
let COMMENT_OFFSET = 976; // has to be on 4 byte boundary (for checksum)
data = spliceString(data, COMMENT_OFFSET, loadTestFontId.length,
loadTestFontId);
// CFF checksum is important for IE, adjusting it
let CFF_CHECKSUM_OFFSET = 16;
let XXXX_VALUE = 0x58585858; // the "comment" filled with 'X'
let checksum = int32(data, CFF_CHECKSUM_OFFSET);
for (i = 0, ii = loadTestFontId.length - 3; i < ii; i += 4) {
checksum = (checksum - XXXX_VALUE + int32(loadTestFontId, i)) | 0;
} }
// TODO other browsers if (i < loadTestFontId.length) { // align to 4 bytes boundary
return supported; checksum = (checksum - XXXX_VALUE + int32(loadTestFontId + 'XXX', i)) | 0;
}; }
Object.defineProperty(FontLoader, 'isSyncFontLoadingSupported', { data = spliceString(data, CFF_CHECKSUM_OFFSET, 4, string32(checksum));
get() {
return shadow(FontLoader, 'isSyncFontLoadingSupported', const url = `url(data:font/opentype;base64,${btoa(data)});`;
isSyncFontLoadingSupported()); const rule = `@font-face {font-family:"${loadTestFontId}";src:${url}}`;
}, this.insertRule(rule);
enumerable: true,
configurable: true, let names = [];
}); for (i = 0, ii = fonts.length; i < ii; i++) {
} names.push(fonts[i].loadedName);
}
names.push(loadTestFontId);
let div = document.createElement('div');
div.setAttribute('style', 'visibility: hidden;' +
'width: 10px; height: 10px;' +
'position: absolute; top: 0px; left: 0px;');
for (i = 0, ii = names.length; i < ii; ++i) {
let span = document.createElement('span');
span.textContent = 'Hi';
span.style.fontFamily = names[i];
div.appendChild(span);
}
document.body.appendChild(div);
isFontReady(loadTestFontId, function() {
document.body.removeChild(div);
request.complete();
});
/** Hack end */
}
};
} // End of PDFJSDev.test('CHROME || GENERIC')
const IsEvalSupportedCached = { const IsEvalSupportedCached = {
get value() { get value() {