Make the fonts decoding code works with asynchronous data url
This commit is contained in:
parent
c03dd98075
commit
b0ee046b31
104
PDFFont.js
104
PDFFont.js
@ -11,6 +11,16 @@ var kMaxFontFileSize = 40000;
|
|||||||
*/
|
*/
|
||||||
var kMaxGlyphsCount = 1024;
|
var kMaxGlyphsCount = 1024;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum time to wait for a font to be loaded by @font-face
|
||||||
|
*/
|
||||||
|
var kMaxWaitForFontFace = 2000;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Useful for debugging when you want to certains operations depending on how
|
||||||
|
* many fonts are loaded.
|
||||||
|
*/
|
||||||
|
var fontCount = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hold a map of decoded fonts and of the standard fourteen Type1 fonts and
|
* Hold a map of decoded fonts and of the standard fourteen Type1 fonts and
|
||||||
@ -36,9 +46,10 @@ var Font = function(aFontName, aFontFile, aFontType) {
|
|||||||
|
|
||||||
// If the font has already been decoded simply return
|
// If the font has already been decoded simply return
|
||||||
if (Fonts[aFontName]) {
|
if (Fonts[aFontName]) {
|
||||||
this.font = Fonts[aFontName];
|
this.font = Fonts[aFontName].data;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
fontCount++;
|
||||||
|
|
||||||
var start = Date.now();
|
var start = Date.now();
|
||||||
switch (aFontType) {
|
switch (aFontType) {
|
||||||
@ -62,10 +73,13 @@ var Font = function(aFontName, aFontFile, aFontType) {
|
|||||||
}
|
}
|
||||||
var end = Date.now();
|
var end = Date.now();
|
||||||
|
|
||||||
|
Fonts[aFontName] = {
|
||||||
|
data: this.font,
|
||||||
|
loading: true
|
||||||
|
}
|
||||||
|
|
||||||
// Attach the font to the document
|
// Attach the font to the document
|
||||||
this.bind();
|
this.bind();
|
||||||
|
|
||||||
Fonts[aFontName] = this.font;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Font.prototype = {
|
Font.prototype = {
|
||||||
@ -84,10 +98,90 @@ Font.prototype = {
|
|||||||
: String.fromCharCode(data[i]));
|
: String.fromCharCode(data[i]));
|
||||||
|
|
||||||
var dataBase64 = window.btoa(str.join(""));
|
var dataBase64 = window.btoa(str.join(""));
|
||||||
|
var fontName = this.name;
|
||||||
|
|
||||||
|
/** Hack begin */
|
||||||
|
|
||||||
|
// Actually there is not event when a font has finished downloading so
|
||||||
|
// the following tons of code are a dirty hack to 'guess' when a font is
|
||||||
|
// ready
|
||||||
|
var debug = false;
|
||||||
|
|
||||||
|
var canvas = document.createElement("canvas");
|
||||||
|
var style = "position:absolute; left: " +
|
||||||
|
(debug ? (100 * fontCount) : "-200") + "px; top: -200px;";
|
||||||
|
canvas.setAttribute("style", style);
|
||||||
|
canvas.setAttribute("width", 100);
|
||||||
|
canvas.setAttribute("heigth", 100);
|
||||||
|
document.body.appendChild(canvas);
|
||||||
|
|
||||||
|
// Get the first character of the font
|
||||||
|
var page = pdfDocument.getPage(pageNum);
|
||||||
|
var xref = page.xref;
|
||||||
|
var resources = xref.fetchIfRef(page.resources);
|
||||||
|
var fontResource = resources.get("Font");
|
||||||
|
var charset = "";
|
||||||
|
for (var id in fontResource.map) {
|
||||||
|
var res = xref.fetch(fontResource.get(id));
|
||||||
|
var descriptor = xref.fetch(res.get("FontDescriptor"));
|
||||||
|
var name = descriptor.get("FontName").toString();
|
||||||
|
var font = Fonts[name.replace("+", "_")];
|
||||||
|
if (font && font.loading && name == fontName.replace("_", "+")) {
|
||||||
|
charset = descriptor.get("CharSet").split("/");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warn if the charset is not found, this is likely a bug!
|
||||||
|
var testCharset = charset;
|
||||||
|
if (!charset) {
|
||||||
|
warn("No charset found for: " + fontName);
|
||||||
|
} else {
|
||||||
|
// if the charset is too small make it repeat a few times
|
||||||
|
var count = 30;
|
||||||
|
while (count-- && testCharset.length <= 30)
|
||||||
|
testCharset = testCharset.concat(charset.slice());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the font size canvas think it will be
|
||||||
|
var ctx = canvas.getContext("2d");
|
||||||
|
var testString = "";
|
||||||
|
for (var i = 0; i < testCharset.length; i++) {
|
||||||
|
var unicode = new Number("0x" + GlyphsUnicode[testCharset[i]]);
|
||||||
|
if (!unicode)
|
||||||
|
error("Unicode for " + testCharset[i] + " is has not been found in the glyphs list");
|
||||||
|
testString += String.fromCharCode(unicode);
|
||||||
|
}
|
||||||
|
ctx.font = "20px " + fontName + ", Symbol";
|
||||||
|
var textWidth = ctx.mozMeasureText(testString);
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
ctx.fillText(testString, 20, 20);
|
||||||
|
|
||||||
|
var start = Date.now();
|
||||||
|
var interval = window.setInterval(function(self) {
|
||||||
|
ctx.font = "20px " + fontName + ", Symbol";
|
||||||
|
|
||||||
|
// For some reasons the font has not loaded, so mark it loaded for the
|
||||||
|
// page to proceed but cry
|
||||||
|
if ((Date.now() - start) >= kMaxWaitForFontFace) {
|
||||||
|
window.clearInterval(interval);
|
||||||
|
Fonts[fontName].loading = false;
|
||||||
|
warn("Is " + fontName + " for charset: " + charset + " loaded?");
|
||||||
|
} else if (textWidth != ctx.mozMeasureText(testString)) {
|
||||||
|
window.clearInterval(interval);
|
||||||
|
Fonts[fontName].loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
ctx.fillText(testString, 20, 60);
|
||||||
|
}, 150, this);
|
||||||
|
|
||||||
|
/** Hack end */
|
||||||
|
|
||||||
// Add the @font-face rule to the document
|
// Add the @font-face rule to the document
|
||||||
var url = "url(data:" + this.mimetype + ";base64," + dataBase64 + ");";
|
var url = "url(data:" + this.mimetype + ";base64," + dataBase64 + ");";
|
||||||
var rule = "@font-face { font-family:'" + this.name + "';src:" + url + "}";
|
var rule = "@font-face { font-family:'" + fontName + "';src:" + url + "}";
|
||||||
var styleSheet = document.styleSheets[0];
|
var styleSheet = document.styleSheets[0];
|
||||||
styleSheet.insertRule(rule, styleSheet.length);
|
styleSheet.insertRule(rule, styleSheet.length);
|
||||||
},
|
},
|
||||||
@ -473,7 +567,6 @@ var TrueType = function(aFontName, aFontFile) {
|
|||||||
*/
|
*/
|
||||||
var PSFonts = new Dict();
|
var PSFonts = new Dict();
|
||||||
|
|
||||||
|
|
||||||
var Stack = function(aStackSize) {
|
var Stack = function(aStackSize) {
|
||||||
var innerStack = new Array(aStackSize || 0);
|
var innerStack = new Array(aStackSize || 0);
|
||||||
|
|
||||||
@ -1136,7 +1229,6 @@ var Type1Parser = function(aAsciiStream, aBinaryStream) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
var CFF = function(aFontName, aFontFile) {
|
var CFF = function(aFontName, aFontFile) {
|
||||||
var start = Date.now();
|
var start = Date.now();
|
||||||
|
|
||||||
|
15
pdf.js
15
pdf.js
@ -1399,6 +1399,19 @@ var Page = (function() {
|
|||||||
? obj
|
? obj
|
||||||
: null));
|
: null));
|
||||||
},
|
},
|
||||||
|
get fonts() {
|
||||||
|
var xref = this.xref;
|
||||||
|
var fonts = [];
|
||||||
|
|
||||||
|
var resources = xref.fetchIfRef(this.resources);
|
||||||
|
var fontResource = resources.get("Font");
|
||||||
|
for (var id in fontResource.map) {
|
||||||
|
var res = xref.fetch(fontResource.get(id));
|
||||||
|
var descriptor = xref.fetch(res.get("FontDescriptor"));
|
||||||
|
fonts.push(descriptor.get("FontName").toString());
|
||||||
|
}
|
||||||
|
return shadow(this, "fonts", fonts);
|
||||||
|
},
|
||||||
display: function(gfx) {
|
display: function(gfx) {
|
||||||
var xref = this.xref;
|
var xref = this.xref;
|
||||||
var contents = xref.fetchIfRef(this.contents);
|
var contents = xref.fetchIfRef(this.contents);
|
||||||
@ -1843,7 +1856,7 @@ var CanvasGraphics = (function() {
|
|||||||
var fontFile = this.xref.fetchIfRef(fontDescriptor.get("FontFile"));
|
var fontFile = this.xref.fetchIfRef(fontDescriptor.get("FontFile"));
|
||||||
if (!fontFile)
|
if (!fontFile)
|
||||||
fontFile = this.xref.fetchIfRef(fontDescriptor.get("FontFile2"));
|
fontFile = this.xref.fetchIfRef(fontDescriptor.get("FontFile2"));
|
||||||
fontName = fontDescriptor.get("FontName").name.replace("+", " ");
|
fontName = fontDescriptor.get("FontName").name.replace("+", "_");
|
||||||
new Font(fontName, fontFile, subtype);
|
new Font(fontName, fontFile, subtype);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
43
test.js
43
test.js
@ -21,7 +21,6 @@ function queryParams() {
|
|||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function open(url) {
|
function open(url) {
|
||||||
document.title = url;
|
document.title = url;
|
||||||
req = new XMLHttpRequest();
|
req = new XMLHttpRequest();
|
||||||
@ -54,8 +53,8 @@ function displayPage(num) {
|
|||||||
|
|
||||||
var page = pdfDocument.getPage(pageNum = num);
|
var page = pdfDocument.getPage(pageNum = num);
|
||||||
|
|
||||||
|
function display() {
|
||||||
var t1 = Date.now();
|
var t1 = Date.now();
|
||||||
|
|
||||||
var ctx = canvas.getContext("2d");
|
var ctx = canvas.getContext("2d");
|
||||||
ctx.save();
|
ctx.save();
|
||||||
ctx.fillStyle = "rgb(255, 255, 255)";
|
ctx.fillStyle = "rgb(255, 255, 255)";
|
||||||
@ -66,9 +65,47 @@ function displayPage(num) {
|
|||||||
page.display(gfx);
|
page.display(gfx);
|
||||||
|
|
||||||
var t2 = Date.now();
|
var t2 = Date.now();
|
||||||
|
|
||||||
var infoDisplay = document.getElementById("info");
|
var infoDisplay = document.getElementById("info");
|
||||||
infoDisplay.innerHTML = "Time to render: "+ (t1 - t0) + "/" + (t2 - t1) + " ms";
|
infoDisplay.innerHTML = "Time to render: "+ (t1 - t0) + "/" + (t2 - t1) + " ms";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loading a font via data uri is asynchronous, so wait for all font
|
||||||
|
// of the page to be fully loaded before loading the page
|
||||||
|
var fontsReady = true;
|
||||||
|
var fonts = page.fonts;
|
||||||
|
for (var i = 0; i < fonts.length; i++) {
|
||||||
|
var fontName = fonts[i].replace("+", "_");
|
||||||
|
var font = Fonts[fontName];
|
||||||
|
if (!font) {
|
||||||
|
// load the new font
|
||||||
|
var xref = page.xref;
|
||||||
|
var resources = xref.fetchIfRef(page.resources);
|
||||||
|
var fontResource = resources.get("Font");
|
||||||
|
for (var id in fontResource.map) {
|
||||||
|
var res = xref.fetch(fontResource.get(id));
|
||||||
|
var descriptor = xref.fetch(res.get("FontDescriptor"));
|
||||||
|
var name = descriptor.get("FontName").toString();
|
||||||
|
if (name == fontName.replace("_", "+")) {
|
||||||
|
var subtype = res.get("Subtype").name;
|
||||||
|
var fontFile = page.xref.fetchIfRef(descriptor.get("FontFile"));
|
||||||
|
if (!fontFile)
|
||||||
|
fontFile = page.xref.fetchIfRef(descriptor.get("FontFile2"));
|
||||||
|
new Font(fontName, fontFile, subtype);
|
||||||
|
fontsReady = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (font.loading) {
|
||||||
|
fontsReady = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If everything is ready do not delayed the page loading any more
|
||||||
|
if (fontsReady)
|
||||||
|
display();
|
||||||
|
else
|
||||||
|
setTimeout(displayPage, 150, num);
|
||||||
}
|
}
|
||||||
|
|
||||||
function nextPage() {
|
function nextPage() {
|
||||||
|
Loading…
Reference in New Issue
Block a user