Merge branch 'master' of github.com:andreasgal/pdf.js

Conflicts:
	pdf.js
This commit is contained in:
sbarman 2011-06-15 12:37:05 -07:00
commit 7077ad5b67
2 changed files with 153 additions and 79 deletions

219
pdf.js
View File

@ -590,7 +590,7 @@ function IsString(v) {
} }
function IsNull(v) { function IsNull(v) {
return v == null; return v === null;
} }
function IsName(v) { function IsName(v) {
@ -630,14 +630,6 @@ function IsPDFFunction(v) {
return fnDict.has("FunctionType"); return fnDict.has("FunctionType");
} }
function IsFunctionDict(v) {
return IsFunction(v) && IsDict(v);
}
function IsFunctionStream(v) {
return IsFunction(v) && IsStream(v);
}
var EOF = {}; var EOF = {};
function IsEOF(v) { function IsEOF(v) {
@ -841,10 +833,12 @@ var Lexer = (function() {
ch = stream.getChar(); ch = stream.getChar();
if (ch == '>') { if (ch == '>') {
break; break;
} else if (!ch) { }
if (!ch) {
warn("Unterminated hex string"); warn("Unterminated hex string");
break; break;
} else if (specialChars[ch.charCodeAt(0)] != 1) { }
if (specialChars[ch.charCodeAt(0)] != 1) {
var x, x2; var x, x2;
if (((x = ToHexDigit(ch)) == -1) || if (((x = ToHexDigit(ch)) == -1) ||
((x2 = ToHexDigit(stream.getChar())) == -1)) { ((x2 = ToHexDigit(stream.getChar())) == -1)) {
@ -1373,8 +1367,8 @@ var Page = (function() {
} }
constructor.prototype = { constructor.prototype = {
get contents() { get content() {
return shadow(this, "contents", this.pageDict.get("Contents")); return shadow(this, "content", this.pageDict.get("Contents"));
}, },
get resources() { get resources() {
return shadow(this, "resources", this.pageDict.get("Resources")); return shadow(this, "resources", this.pageDict.get("Resources"));
@ -1385,18 +1379,25 @@ var Page = (function() {
? obj ? obj
: null)); : null));
}, },
compile: function(gfx, fonts) {
if (!this.code) {
var xref = this.xref;
var content = xref.fetchIfRef(this.content);
var resources = xref.fetchIfRef(this.resources);
this.code = gfx.compile(content, xref, resources, fonts);
}
},
display: function(gfx) { display: function(gfx) {
var xref = this.xref; var xref = this.xref;
var contents = xref.fetchIfRef(this.contents); var content = xref.fetchIfRef(this.content);
var resources = xref.fetchIfRef(this.resources); var resources = xref.fetchIfRef(this.resources);
var mediaBox = xref.fetchIfRef(this.mediaBox); var mediaBox = xref.fetchIfRef(this.mediaBox);
assertWellFormed(IsStream(contents) && IsDict(resources), assertWellFormed(IsStream(content) && IsDict(resources),
"invalid page contents or resources"); "invalid page content or resources");
gfx.beginDrawing({ x: mediaBox[0], y: mediaBox[1], gfx.beginDrawing({ x: mediaBox[0], y: mediaBox[1],
width: mediaBox[2] - mediaBox[0], width: mediaBox[2] - mediaBox[0],
height: mediaBox[3] - mediaBox[1] }); height: mediaBox[3] - mediaBox[1] });
gfx.interpret(new Parser(new Lexer(contents), false), gfx.execute(this.code, xref, resources);
xref, resources);
gfx.endDrawing(); gfx.endDrawing();
} }
}; };
@ -1605,65 +1606,65 @@ var CanvasGraphics = (function() {
this.xobjs = null; this.xobjs = null;
this.map = { this.map = {
// Graphics state // Graphics state
w: this.setLineWidth, w: "setLineWidth",
J: this.setLineCap, J: "setLineCap",
j: this.setLineJoin, j: "setLineJoin",
d: this.setDash, d: "setDash",
ri: this.setRenderingIntent, ri: "setRenderingIntent",
i: this.setFlatness, i: "setFlatness",
gs: this.setGState, gs: "setGState",
q: this.save, q: "save",
Q: this.restore, Q: "restore",
cm: this.transform, cm: "transform",
// Path // Path
m: this.moveTo, m: "moveTo",
l: this.lineTo, l: "lineTo",
c: this.curveTo, c: "curveTo",
h: this.closePath, h: "closePath",
re: this.rectangle, re: "rectangle",
S: this.stroke, S: "stroke",
f: this.fill, f: "fill",
"f*": this.eoFill, "f*": "eoFill",
B: this.fillStroke, B: "fillStroke",
b: this.closeFillStroke, b: "closeFillStroke",
n: this.endPath, n: "endPath",
// Clipping // Clipping
W: this.clip, W: "clip",
"W*": this.eoClip, "W*": "eoClip",
// Text // Text
BT: this.beginText, BT: "beginText",
ET: this.endText, ET: "endText",
TL: this.setLeading, TL: "setLeading",
Tf: this.setFont, Tf: "setFont",
Td: this.moveText, Td: "moveText",
Tm: this.setTextMatrix, Tm: "setTextMatrix",
"T*": this.nextLine, "T*": "nextLine",
Tj: this.showText, Tj: "showText",
TJ: this.showSpacedText, TJ: "showSpacedText",
// Type3 fonts // Type3 fonts
// Color // Color
CS: this.setStrokeColorSpace, CS: "setStrokeColorSpace",
cs: this.setFillColorSpace, cs: "setFillColorSpace",
SC: this.setStrokeColor, SC: "setStrokeColor",
SCN: this.setStrokeColorN, SCN: "setStrokeColorN",
sc: this.setFillColor, sc: "setFillColor",
scn: this.setFillColorN, scn: "setFillColorN",
G: this.setStrokeGray, G: "setStrokeGray",
g: this.setFillGray, g: "setFillGray",
RG: this.setStrokeRGBColor, RG: "setStrokeRGBColor",
rg: this.setFillRGBColor, rg: "setFillRGBColor",
// Shading // Shading
sh: this.shadingFill, sh: "shadingFill",
// Images // Images
// XObjects // XObjects
Do: this.paintXObject, Do: "paintXObject",
// Marked content // Marked content
// Compatibility // Compatibility
@ -1676,6 +1677,10 @@ var CanvasGraphics = (function() {
const EO_CLIP = {}; const EO_CLIP = {};
constructor.prototype = { constructor.prototype = {
translateFont: function(fontDict, xref, resources) {
return "translated";
},
beginDrawing: function(mediaBox) { beginDrawing: function(mediaBox) {
var cw = this.ctx.canvas.width, ch = this.ctx.canvas.height; var cw = this.ctx.canvas.width, ch = this.ctx.canvas.height;
this.ctx.save(); this.ctx.save();
@ -1683,12 +1688,35 @@ var CanvasGraphics = (function() {
this.ctx.translate(0, -mediaBox.height); this.ctx.translate(0, -mediaBox.height);
}, },
interpret: function(parser, xref, resources) { execute: function(code, xref, resources) {
var savedXref = this.xref, savedRes = this.res, savedXobjs = this.xobjs; var savedXref = this.xref, savedRes = this.res, savedXobjs = this.xobjs;
this.xref = xref; this.xref = xref;
this.res = resources || new Dict(); this.res = resources || new Dict();
this.xobjs = this.res.get("XObject") || new Dict(); this.xobjs = xref.fetchIfRef(this.res.get("XObject")) || new Dict();
this.xobjs = this.xref.fetchIfRef(this.xobjs);
code(this);
this.xobjs = savedXobjs;
this.res = savedRes;
this.xref = savedXref;
},
compile: function(stream, xref, resources, fonts) {
var xobjs = xref.fetchIfRef(resources.get("XObject")) || new Dict();
var parser = new Parser(new Lexer(stream), false);
var objpool = [];
function emitArg(arg) {
if (typeof arg == "object" || typeof arg == "string") {
var index = objpool.length;
objpool[index] = arg;
return "objpool[" + index + "]";
}
return arg;
}
var src = "";
var args = []; var args = [];
var map = this.map; var map = this.map;
@ -1699,7 +1727,46 @@ var CanvasGraphics = (function() {
var fn = map[cmd]; var fn = map[cmd];
assertWellFormed(fn, "Unknown command '" + cmd + "'"); assertWellFormed(fn, "Unknown command '" + cmd + "'");
// TODO figure out how to type-check vararg functions // TODO figure out how to type-check vararg functions
fn.apply(this, args);
if (cmd == "Do" && !args[0].code) { // eagerly compile XForm objects
var name = args[0].name;
var xobj = xobjs.get(name);
if (xobj) {
xobj = xref.fetchIfRef(xobj);
assertWellFormed(IsStream(xobj), "XObject should be a stream");
var type = xobj.dict.get("Subtype");
assertWellFormed(IsName(type), "XObject should have a Name subtype");
if ("Form" == type.name) {
args[0].code = this.compile(xobj,
xref,
xobj.dict.get("Resources"),
fonts);
}
}
} else if (cmd == "Tf") { // eagerly collect all fonts
var fontRes = resources.get("Font");
if (fontRes) {
fontRes = xref.fetchIfRef(fontRes);
var font = xref.fetchIfRef(fontRes.get(args[0].name));
assertWellFormed(IsDict(font));
if (!font.translated) {
font.translated = this.translateFont(font, xref, resources);
if (fonts && font.translated) {
// keep track of each font we translated so the caller can
// load them asynchronously before calling display on a page
fonts.push(font.translated);
}
}
}
}
src += "this.";
src += fn;
src += "(";
src += args.map(emitArg).join(",");
src += ");\n";
args.length = 0; args.length = 0;
} else { } else {
@ -1708,9 +1775,8 @@ var CanvasGraphics = (function() {
} }
} }
this.xobjs = savedXobjs; var fn = Function("objpool", src);
this.res = savedRes; return function (gfx) { fn.call(gfx, objpool); };
this.xref = savedXref;
}, },
endDrawing: function() { endDrawing: function() {
@ -2012,9 +2078,9 @@ var CanvasGraphics = (function() {
var type = xobj.dict.get("Subtype"); var type = xobj.dict.get("Subtype");
assertWellFormed(IsName(type), "XObject should have a Name subtype"); assertWellFormed(IsName(type), "XObject should have a Name subtype");
if ("Image" == type.name) { if ("Image" == type.name) {
this.paintImageXObject(xobj, false); this.paintImageXObject(obj, xobj, false);
} else if ("Form" == type.name) { } else if ("Form" == type.name) {
this.paintFormXObject(xobj); this.paintFormXObject(obj, xobj);
} else if ("PS" == type.name) { } else if ("PS" == type.name) {
warn("(deprecated) PostScript XObjects are not supported"); warn("(deprecated) PostScript XObjects are not supported");
} else { } else {
@ -2022,27 +2088,26 @@ var CanvasGraphics = (function() {
} }
}, },
paintFormXObject: function(form) { paintFormXObject: function(ref, stream) {
this.save(); this.save();
var matrix = form.dict.get("Matrix"); var matrix = stream.dict.get("Matrix");
if (matrix && IsArray(matrix) && 6 == matrix.length) if (matrix && IsArray(matrix) && 6 == matrix.length)
this.transform.apply(this, matrix); this.transform.apply(this, matrix);
var bbox = form.dict.get("BBox"); var bbox = stream.dict.get("BBox");
if (bbox && IsArray(bbox) && 4 == bbox.length) { if (bbox && IsArray(bbox) && 4 == bbox.length) {
this.rectangle.apply(this, bbox); this.rectangle.apply(this, bbox);
this.clip(); this.clip();
this.endPath(); this.endPath();
} }
this.interpret(new Parser(new Lexer(form), false), this.execute(ref.code, this.xref, stream.dict.get("Resources"));
this.xref, form.dict.get("Resources"));
this.restore(); this.restore();
}, },
paintImageXObject: function(image, inline) { paintImageXObject: function(ref, image, inline) {
this.save(); this.save();
if (image.getParams) { if (image.getParams) {
// JPX/JPEG2000 streams directly contain bits per component // JPX/JPEG2000 streams directly contain bits per component

View File

@ -95,11 +95,20 @@ function displayPage(num) {
ctx.restore(); ctx.restore();
var gfx = new CanvasGraphics(ctx); var gfx = new CanvasGraphics(ctx);
page.display(gfx);
// page.compile will collect all fonts for us, once we have loaded them
// we can trigger the actual page rendering with page.display
var fonts = [];
page.compile(gfx, fonts);
var t2 = Date.now(); var t2 = Date.now();
infoDisplay.innerHTML = "Time to render: "+ (t1 - t0) + "/" + (t2 - t1) + " ms"; // This should be called when font loading is complete
page.display(gfx);
var t3 = Date.now();
infoDisplay.innerHTML = "Time to load/compile/render: "+ (t1 - t0) + "/" + (t2 - t1) + "/" + (t3 - t2) + " ms";
} }
function nextPage() { function nextPage() {