Most working, but once you add the font-css file to the web page, there is no font drawn at all

This commit is contained in:
Julian Viereck 2011-06-22 01:28:17 +02:00
parent 986ef148c4
commit e15328800a
5 changed files with 235 additions and 108 deletions

View File

@ -42,11 +42,17 @@ function CanvasProxy(width, height) {
"stroke", "stroke",
"clip", "clip",
"measureText", "measureText",
"isPointInPath" "isPointInPath",
"$setCurrentX",
"$addCurrentX",
"$saveCurrentX",
"$restoreCurrentX",
"$showText"
]; ];
function buildFuncCall(name) { function buildFuncCall(name) {
return function() { return function() {
console.log("funcCall", name) // console.log("funcCall", name)
stack.push([name, Array.prototype.slice.call(arguments)]); stack.push([name, Array.prototype.slice.call(arguments)]);
} }
} }
@ -103,6 +109,8 @@ function CanvasProxy(width, height) {
} }
CanvasProxy.prototype.flush = function() { CanvasProxy.prototype.flush = function() {
// postMessage("log");
// postMessage(JSON.stringify([this.$stack.length]));
postMessage("canvas_proxy_stack"); postMessage("canvas_proxy_stack");
postMessage(JSON.stringify(this.$stack)); postMessage(JSON.stringify(this.$stack));
this.$stack.length = 0; this.$stack.length = 0;

146
fonts.js
View File

@ -759,91 +759,109 @@ var Font = (function () {
var data = this.font; var data = this.font;
var fontName = this.name; var fontName = this.name;
var isWorker = (typeof window == "undefined");
/** Hack begin */ /** Hack begin */
if (!isWorker) {
// Actually there is not event when a font has finished downloading so // Actually there is not event when a font has finished downloading so
// the following code are a dirty hack to 'guess' when a font is ready // the following code are a dirty hack to 'guess' when a font is ready
var canvas = document.createElement("canvas"); var canvas = document.createElement("canvas");
var style = "border: 1px solid black; position:absolute; top: " + var style = "border: 1px solid black; position:absolute; top: " +
(debug ? (100 * fontCount) : "-200") + "px; left: 2px; width: 340px; height: 100px"; (debug ? (100 * fontCount) : "-200") + "px; left: 2px; width: 340px; height: 100px";
canvas.setAttribute("style", style); canvas.setAttribute("style", style);
canvas.setAttribute("width", 340); canvas.setAttribute("width", 340);
canvas.setAttribute("heigth", 100); canvas.setAttribute("heigth", 100);
document.body.appendChild(canvas); document.body.appendChild(canvas);
// Get the font size canvas think it will be for 'spaces' // Get the font size canvas think it will be for 'spaces'
var ctx = canvas.getContext("2d"); var ctx = canvas.getContext("2d");
ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial"; ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial";
var testString = " "; var testString = " ";
// When debugging use the characters provided by the charsets to visually // When debugging use the characters provided by the charsets to visually
// see what's happening instead of 'spaces' // see what's happening instead of 'spaces'
var debug = false; var debug = false;
if (debug) { if (debug) {
var name = document.createElement("font"); var name = document.createElement("font");
name.setAttribute("style", "position: absolute; left: 20px; top: " + name.setAttribute("style", "position: absolute; left: 20px; top: " +
(100 * fontCount + 60) + "px"); (100 * fontCount + 60) + "px");
name.innerHTML = fontName; name.innerHTML = fontName;
document.body.appendChild(name); document.body.appendChild(name);
// Retrieve font charset // Retrieve font charset
var charset = Fonts[fontName].properties.charset || []; var charset = Fonts[fontName].properties.charset || [];
// if the charset is too small make it repeat a few times // if the charset is too small make it repeat a few times
var count = 30; var count = 30;
while (count-- && charset.length <= 30) while (count-- && charset.length <= 30)
charset = charset.concat(charset.slice()); charset = charset.concat(charset.slice());
for (var i = 0; i < charset.length; i++) { for (var i = 0; i < charset.length; i++) {
var unicode = GlyphsUnicode[charset[i]]; var unicode = GlyphsUnicode[charset[i]];
if (!unicode) if (!unicode)
continue; continue;
testString += String.fromCharCode(unicode); testString += String.fromCharCode(unicode);
} }
ctx.fillText(testString, 20, 20); ctx.fillText(testString, 20, 20);
} }
// Periodicaly check for the width of the testString, it will be // Periodicaly check for the width of the testString, it will be
// different once the real font has loaded // different once the real font has loaded
var textWidth = ctx.measureText(testString).width; var textWidth = ctx.measureText(testString).width;
var interval = window.setInterval(function canvasInterval(self) { var interval = window.setInterval(function canvasInterval(self) {
this.start = this.start || Date.now(); this.start = this.start || Date.now();
ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial"; ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial";
// For some reasons the font has not loaded, so mark it loaded for the // For some reasons the font has not loaded, so mark it loaded for the
// page to proceed but cry // page to proceed but cry
if ((Date.now() - this.start) >= kMaxWaitForFontFace) { if ((Date.now() - this.start) >= kMaxWaitForFontFace) {
window.clearInterval(interval); window.clearInterval(interval);
Fonts[fontName].loading = false; Fonts[fontName].loading = false;
warn("Is " + fontName + " for charset: " + charset + " loaded?"); warn("Is " + fontName + " for charset: " + charset + " loaded?");
this.start = 0; this.start = 0;
} else if (textWidth != ctx.measureText(testString).width) { } else if (textWidth != ctx.measureText(testString).width) {
window.clearInterval(interval); window.clearInterval(interval);
Fonts[fontName].loading = false; Fonts[fontName].loading = false;
this.start = 0; this.start = 0;
} }
if (debug) if (debug)
ctx.fillText(testString, 20, 50); ctx.fillText(testString, 20, 50);
}, 30, this); }, 30, this);
}
/** Hack end */ /** Hack end */
//
// Get the base64 encoding of the binary font data // Get the base64 encoding of the binary font data
var str = ""; var str = "";
var length = data.length; var length = data.length;
for (var i = 0; i < length; ++i) for (var i = 0; i < length; ++i)
str += String.fromCharCode(data[i]); str += String.fromCharCode(data[i]);
var base64 = window.btoa(str); if (isWorker) {
postMessage("font");
postMessage(JSON.stringify({
str: str,
mimetype: this.mimetype,
fontName: fontName,
}));
// Add the @font-face rule to the document setTimeout(function() {
var url = "url(data:" + this.mimetype + ";base64," + base64 + ");"; Fonts[fontName].loading = false;
var rule = "@font-face { font-family:'" + fontName + "';src:" + url + "}"; }, kMaxWaitForFontFace);
var styleSheet = document.styleSheets[0]; } else {
styleSheet.insertRule(rule, styleSheet.length); var base64 = window.btoa(str);
// Add the @font-face rule to the document
var url = "url(data:" + this.mimetype + ";base64," + base64 + ");";
var rule = "@font-face { font-family:'" + fontName + "';src:" + url + "}";
var styleSheet = document.styleSheets[0];
styleSheet.insertRule(rule, styleSheet.length);
console.log("added font", fontName);
console.log(rule);
}
} }
}; };

34
pdf.js
View File

@ -2674,12 +2674,18 @@ var CanvasGraphics = (function() {
}, },
save: function() { save: function() {
this.ctx.save(); this.ctx.save();
if (this.ctx.$saveCurrentX) {
this.ctx.$saveCurrentX();
}
this.stateStack.push(this.current); this.stateStack.push(this.current);
this.current = new CanvasExtraState(); this.current = new CanvasExtraState();
}, },
restore: function() { restore: function() {
var prev = this.stateStack.pop(); var prev = this.stateStack.pop();
if (prev) { if (prev) {
if (this.ctx.$restoreCurrentX) {
this.ctx.$restoreCurrentX();
}
this.current = prev; this.current = prev;
this.ctx.restore(); this.ctx.restore();
} }
@ -2760,6 +2766,9 @@ var CanvasGraphics = (function() {
// Text // Text
beginText: function() { beginText: function() {
this.current.textMatrix = IDENTITY_MATRIX; this.current.textMatrix = IDENTITY_MATRIX;
if (this.ctx.$setCurrentX) {
this.ctx.$setCurrentX(0)
}
this.current.x = this.current.lineX = 0; this.current.x = this.current.lineX = 0;
this.current.y = this.current.lineY = 0; this.current.y = this.current.lineY = 0;
}, },
@ -2814,6 +2823,9 @@ var CanvasGraphics = (function() {
moveText: function (x, y) { moveText: function (x, y) {
this.current.x = this.current.lineX += x; this.current.x = this.current.lineX += x;
this.current.y = this.current.lineY += y; this.current.y = this.current.lineY += y;
if (this.ctx.$setCurrentX) {
this.ctx.$setCurrentX(this.current.x)
}
}, },
setLeadingMoveText: function(x, y) { setLeadingMoveText: function(x, y) {
this.setLeading(-y); this.setLeading(-y);
@ -2821,6 +2833,10 @@ var CanvasGraphics = (function() {
}, },
setTextMatrix: function(a, b, c, d, e, f) { setTextMatrix: function(a, b, c, d, e, f) {
this.current.textMatrix = [ a, b, c, d, e, f ]; this.current.textMatrix = [ a, b, c, d, e, f ];
if (this.ctx.$setCurrentX) {
this.$setCurrentX(0)
}
this.current.x = this.current.lineX = 0; this.current.x = this.current.lineX = 0;
this.current.y = this.current.lineY = 0; this.current.y = this.current.lineY = 0;
}, },
@ -2831,11 +2847,15 @@ var CanvasGraphics = (function() {
this.ctx.save(); this.ctx.save();
this.ctx.transform.apply(this.ctx, this.current.textMatrix); this.ctx.transform.apply(this.ctx, this.current.textMatrix);
this.ctx.scale(1, -1); this.ctx.scale(1, -1);
this.ctx.translate(0, -2 * this.current.y);
text = Fonts.charsToUnicode(text); if (this.ctx.$showText) {
this.ctx.fillText(text, this.current.x, this.current.y); this.ctx.$showText(this.current.y, Fonts.charsToUnicode(text));
this.current.x += this.ctx.measureText(text).width; } else {
console.log(text, this.current.x);
text = Fonts.charsToUnicode(text);
this.ctx.fillText(text, 0, 0);
this.current.x += this.ctx.measureText(text).width;
}
this.ctx.restore(); this.ctx.restore();
}, },
@ -2843,7 +2863,11 @@ var CanvasGraphics = (function() {
for (var i = 0; i < arr.length; ++i) { for (var i = 0; i < arr.length; ++i) {
var e = arr[i]; var e = arr[i];
if (IsNum(e)) { if (IsNum(e)) {
this.current.x -= e * 0.001 * this.current.fontSize; if (this.ctx.$addCurrentX) {
this.ctx.$addCurrentX(-e * 0.001 * this.current.fontSize)
} else {
this.current.x -= e * 0.001 * this.current.fontSize;
}
} else if (IsString(e)) { } else if (IsString(e)) {
this.showText(e); this.showText(e);
} else { } else {

View File

@ -11,11 +11,63 @@ var myWorker = new Worker('worker.js');
const WAIT = 0; const WAIT = 0;
const CANVAS_PROXY_STACK = 1; const CANVAS_PROXY_STACK = 1;
const LOG = 2; const LOG = 2;
const FONT = 3;
var currentX = 0;
var currentXStack = [];
var special = {
"$setCurrentX": function(value) {
currentX = value;
},
"$addCurrentX": function(value) {
currentX += value;
},
"$saveCurrentX": function() {
currentXStack.push(currentX);
},
"$restoreCurrentX": function() {
currentX = currentXStack.pop();
},
"$showText": function(y, text) {
console.log(text, currentX, y, this.measureText(text).width);
this.translate(currentX, -1 * y);
this.fillText(text, 0, 0);
currentX += this.measureText(text).width;
}
}
function renderProxyCanvas(stack) {
// for (var i = 0; i < stack.length; i++) {
for (var i = 0; i < 1000; i++) {
var opp = stack[i];
if (opp[0] == "$") {
// console.log("set property", opp[1], opp[2]);
if (opp[1] == "font") {
ctx[opp[1]] = opp[2];
// console.log("font", opp[2]);
} else {
ctx[opp[1]] = opp[2];
}
} else if (opp[0] in special) {
// console.log("sepcial", opp[0], opp[1])
special[opp[0]].apply(ctx, opp[1]);
} else {
// console.log("execute", opp[0], opp[1]);
ctx[opp[0]].apply(ctx, opp[1]);
}
}
}
var onMessageState = WAIT; var onMessageState = WAIT;
myWorker.onmessage = function(event) { myWorker.onmessage = function(event) {
var data = event.data; var data = event.data;
console.log("onMessageRaw", data); // console.log("onMessageRaw", data);
switch (onMessageState) { switch (onMessageState) {
case WAIT: case WAIT:
if (typeof data != "string") { if (typeof data != "string") {
@ -28,11 +80,31 @@ myWorker.onmessage = function(event) {
case "canvas_proxy_stack": case "canvas_proxy_stack":
onMessageState = CANVAS_PROXY_STACK; onMessageState = CANVAS_PROXY_STACK;
return; return;
case "font":
onMessageState = FONT;
return;
default: default:
throw "unkown state: " + data throw "unkown state: " + data
} }
break; break;
case FONT:
data = JSON.parse(data);
var base64 = window.btoa(data.str);
// Add the @font-face rule to the document
var url = "url(data:" + data.mimetype + ";base64," + base64 + ");";
var rule = "@font-face { font-family:'" + data.fontName + "';src:" + url + "}";
var styleSheet = document.styleSheets[0];
// ONCE you uncomment this, there is no font painted at all :(
// styleSheet.insertRule(rule, styleSheet.length);
console.log("added font", data.fontName);
// console.log(rule);
onMessageState = WAIT;
break;
case LOG: case LOG:
console.log.apply(console, JSON.parse(data)); console.log.apply(console, JSON.parse(data));
onMessageState = WAIT; onMessageState = WAIT;
@ -40,17 +112,14 @@ myWorker.onmessage = function(event) {
case CANVAS_PROXY_STACK: case CANVAS_PROXY_STACK:
var stack = JSON.parse(data); var stack = JSON.parse(data);
for (var i = 0; i < stack.length; i++) { console.log("canvas stack", stack.length)
var opp = stack[i]; // console.log(stack.length);
if (opp[0] == "$") {
console.log("set property", opp[1], opp[2]);
ctx[opp[1]] = opp[2];
} else {
console.log("execute", opp[0], opp[1]);
ctx[opp[0]].apply(ctx, opp[1]);
}
}
onMessageState = WAIT; onMessageState = WAIT;
// return;
setTimeout(function() {
renderProxyCanvas(stack);
}, 2000);
break; break;
} }
} }
@ -75,6 +144,10 @@ function open(url) {
window.onload = function() { window.onload = function() {
var ctx = window.ctx = document.getElementById("canvas").getContext("2d"); var ctx = window.ctx = document.getElementById("canvas").getContext("2d");
ctx.save();
ctx.fillStyle = "rgb(255, 255, 255)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.restore();
// for (var name in ctx) { // for (var name in ctx) {
// if (!(ctx[name] instanceof Function)) { // if (!(ctx[name] instanceof Function)) {
// console.log('"' + name + '": "' + ctx[name] + '",'); // console.log('"' + name + '": "' + ctx[name] + '",');

View File

@ -40,6 +40,7 @@ var canvas = new CanvasProxy(1224, 1584);
// canvas.flush(); // canvas.flush();
log("test"); log("test");
var pageInterval;
onmessage = function(event) { onmessage = function(event) {
var data = event.data; var data = event.data;
var pdfDocument = new PDFDoc(new Stream(data)); var pdfDocument = new PDFDoc(new Stream(data));
@ -59,36 +60,39 @@ onmessage = function(event) {
// //
var fontsReady = true; var fontsReady = true;
// Inspect fonts and translate the missing one // Inspect fonts and translate the missing one
var count = fonts.length; var count = fonts.length;
for (var i = 0; i < count; i++) { for (var i = 0; i < count; i++) {
var font = fonts[i]; var font = fonts[i];
if (Fonts[font.name]) { if (Fonts[font.name]) {
fontsReady = fontsReady && !Fonts[font.name].loading; fontsReady = fontsReady && !Fonts[font.name].loading;
continue; continue;
} }
new Font(font.name, font.file, font.properties); new Font(font.name, font.file, font.properties);
fontsReady = false; fontsReady = false;
} }
function delayLoadFont() { // function delayLoadFont() {
for (var i = 0; i < count; i++) { // for (var i = 0; i < count; i++) {
if (Fonts[font.name].loading) // if (Fonts[font.name].loading)
return; // return;
} // }
clearInterval(pageInterval); // clearInterval(pageInterval);
page.display(gfx); // page.display(gfx);
//
// log("flush");
// canvas.flush();
// };
canvas.flush(); // if (fontsReady) {
}; // delayLoadFont();
// } else {
// pageInterval = setInterval(delayLoadFont, 10);
// }
if (fontsReady) { page.display(gfx);
delayLoadFont(); canvas.flush();
} else {
pageInterval = setInterval(delayLoadFont, 10);
}
postMessage(page.code.src);
} }
// function open(url) { // function open(url) {