Merge from gal's master branch (got a regression on the mapping between char->glyph)
This commit is contained in:
commit
a57b53b3b3
@ -34,8 +34,8 @@ var Fonts = {
|
|||||||
return this._active || { encoding: {} };
|
return this._active || { encoding: {} };
|
||||||
},
|
},
|
||||||
|
|
||||||
set active(aFontName) {
|
set active(aName) {
|
||||||
this._active = this[aFontName];
|
this._active = this[aName];
|
||||||
},
|
},
|
||||||
|
|
||||||
unicodeFromCode: function fonts_unicodeFromCode(aCode) {
|
unicodeFromCode: function fonts_unicodeFromCode(aCode) {
|
||||||
|
644
pdf.js
644
pdf.js
@ -607,7 +607,7 @@ function IsString(v) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function IsNull(v) {
|
function IsNull(v) {
|
||||||
return v == null;
|
return v === null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function IsName(v) {
|
function IsName(v) {
|
||||||
@ -634,7 +634,7 @@ function IsRef(v) {
|
|||||||
return v instanceof Ref;
|
return v instanceof Ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
function IsFunction(v) {
|
function IsPDFFunction(v) {
|
||||||
var fnDict;
|
var fnDict;
|
||||||
if (typeof v != "object")
|
if (typeof v != "object")
|
||||||
return false;
|
return false;
|
||||||
@ -647,14 +647,6 @@ function IsFunction(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) {
|
||||||
@ -861,10 +853,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)) {
|
||||||
@ -1394,8 +1388,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"));
|
||||||
@ -1406,47 +1400,25 @@ var Page = (function() {
|
|||||||
? obj
|
? obj
|
||||||
: null));
|
: null));
|
||||||
},
|
},
|
||||||
get fonts() {
|
compile: function(gfx, fonts) {
|
||||||
var xref = this.xref;
|
if (!this.code) {
|
||||||
var resources = xref.fetchIfRef(this.resources);
|
var xref = this.xref;
|
||||||
var fontsDict = new Dict();
|
var content = xref.fetchIfRef(this.content);
|
||||||
|
var resources = xref.fetchIfRef(this.resources);
|
||||||
// Get the fonts use on the page if any
|
this.code = gfx.compile(content, xref, resources, fonts);
|
||||||
var fontResources = resources.get("Font");
|
|
||||||
if (IsDict(fontResources)) {
|
|
||||||
fontResources.forEach(function(fontKey, fontData) {
|
|
||||||
fontsDict.set(fontKey, xref.fetch(fontData))
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the fonts use on xobjects of the page if any
|
|
||||||
var xobjs = xref.fetchIfRef(resources.get("XObject"));
|
|
||||||
if (xobjs) {
|
|
||||||
xobjs.forEach(function(key, xobj) {
|
|
||||||
xobj = xref.fetchIfRef(xobj);
|
|
||||||
assertWellFormed(IsStream(xobj), "XObject should be a stream");
|
|
||||||
|
|
||||||
var xobjFonts = xobj.dict.get("Resources").get("Font");
|
|
||||||
xobjFonts.forEach(function(fontKey, fontData) {
|
|
||||||
fontsDict.set(fontKey, xref.fetch(fontData))
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return shadow(this, "fonts", fontsDict);
|
|
||||||
},
|
},
|
||||||
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();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1655,68 +1627,96 @@ 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,
|
M: "setMiterLimit",
|
||||||
ri: this.setRenderingIntent,
|
d: "setDash",
|
||||||
i: this.setFlatness,
|
ri: "setRenderingIntent",
|
||||||
gs: this.setGState,
|
i: "setFlatness",
|
||||||
q: this.save,
|
gs: "setGState",
|
||||||
Q: this.restore,
|
q: "save",
|
||||||
cm: this.transform,
|
Q: "restore",
|
||||||
|
cm: "transform",
|
||||||
|
|
||||||
// Path
|
// Path
|
||||||
m: this.moveTo,
|
m: "moveTo",
|
||||||
l: this.lineTo,
|
l: "lineTo",
|
||||||
c: this.curveTo,
|
c: "curveTo",
|
||||||
h: this.closePath,
|
v: "curveTo2",
|
||||||
re: this.rectangle,
|
y: "curveTo3",
|
||||||
S: this.stroke,
|
h: "closePath",
|
||||||
f: this.fill,
|
re: "rectangle",
|
||||||
"f*": this.eoFill,
|
S: "stroke",
|
||||||
B: this.fillStroke,
|
s: "closeStroke",
|
||||||
b: this.closeFillStroke,
|
f: "fill",
|
||||||
n: this.endPath,
|
"f*": "eoFill",
|
||||||
|
B: "fillStroke",
|
||||||
|
"B*": "eoFillStroke",
|
||||||
|
b: "closeFillStroke",
|
||||||
|
"b*": "closeEOFillStroke",
|
||||||
|
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,
|
Tc: "setCharSpacing",
|
||||||
Tf: this.setFont,
|
Tw: "setWordSpacing",
|
||||||
Td: this.moveText,
|
Tz: "setHScale",
|
||||||
Tm: this.setTextMatrix,
|
TL: "setLeading",
|
||||||
"T*": this.nextLine,
|
Tf: "setFont",
|
||||||
Tj: this.showText,
|
Tr: "setTextRenderingMode",
|
||||||
TJ: this.showSpacedText,
|
Ts: "setTextRise",
|
||||||
|
Td: "moveText",
|
||||||
|
TD: "setLeadingMoveText",
|
||||||
|
Tm: "setTextMatrix",
|
||||||
|
"T*": "nextLine",
|
||||||
|
Tj: "showText",
|
||||||
|
TJ: "showSpacedText",
|
||||||
|
"'": "nextLineShowText",
|
||||||
|
'"': "nextLineSetSpacingShowText",
|
||||||
|
|
||||||
// Type3 fonts
|
// Type3 fonts
|
||||||
|
d0: "setCharWidth",
|
||||||
|
d1: "setCharWidthAndBounds",
|
||||||
|
|
||||||
// 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",
|
||||||
|
K: "setStrokeCMYKColor",
|
||||||
|
k: "setFillCMYKColor",
|
||||||
|
|
||||||
// Shading
|
// Shading
|
||||||
sh: this.shadingFill,
|
sh: "shadingFill",
|
||||||
|
|
||||||
// Images
|
// Images
|
||||||
|
BI: "beginInlineImage",
|
||||||
|
|
||||||
// XObjects
|
// XObjects
|
||||||
Do: this.paintXObject,
|
Do: "paintXObject",
|
||||||
|
|
||||||
// Marked content
|
// Marked content
|
||||||
|
MP: "markPoint",
|
||||||
|
DP: "markPointProps",
|
||||||
|
BMC: "beginMarkedContent",
|
||||||
|
BDC: "beginMarkedContentProps",
|
||||||
|
EMC: "endMarkedContent",
|
||||||
|
|
||||||
// Compatibility
|
// Compatibility
|
||||||
|
BX: "beginCompat",
|
||||||
|
EX: "endCompat",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1726,6 +1726,52 @@ var CanvasGraphics = (function() {
|
|||||||
const EO_CLIP = {};
|
const EO_CLIP = {};
|
||||||
|
|
||||||
constructor.prototype = {
|
constructor.prototype = {
|
||||||
|
translateFont: function(fontDict, xref, resources) {
|
||||||
|
var descriptor = xref.fetch(fontDict.get("FontDescriptor"));
|
||||||
|
var fontName = descriptor.get("FontName").name;
|
||||||
|
fontName = fontName.replace("+", "_");
|
||||||
|
|
||||||
|
var font = Fonts[fontName];
|
||||||
|
if (!font) {
|
||||||
|
var fontFile = descriptor.get2("FontFile", "FontFile2");
|
||||||
|
fontFile = xref.fetchIfRef(fontFile);
|
||||||
|
|
||||||
|
// Generate the custom cmap of the font if needed
|
||||||
|
var encodingMap = {};
|
||||||
|
if (fontDict.has("Encoding")) {
|
||||||
|
var encoding = xref.fetchIfRef(fontDict.get("Encoding"));
|
||||||
|
if (IsDict(encoding)) {
|
||||||
|
// Build an map between codes and glyphs
|
||||||
|
var differences = encoding.get("Differences");
|
||||||
|
var index = 0;
|
||||||
|
for (var j = 0; j < differences.length; j++) {
|
||||||
|
var data = differences[j];
|
||||||
|
IsNum(data) ? index = data : encodingMap[index++] = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the font charset
|
||||||
|
var charset = descriptor.get("CharSet").split("/");
|
||||||
|
} else if (IsName(encoding)) {
|
||||||
|
var encoding = Encodings[encoding];
|
||||||
|
var widths = xref.fetchIfRef(fontDict.get("Widths"));
|
||||||
|
var firstchar = xref.fetchIfRef(fontDict.get("FirstChar"));
|
||||||
|
|
||||||
|
var charset = [];
|
||||||
|
for (var j = 0; j < widths.length; j++) {
|
||||||
|
var index = widths[j];
|
||||||
|
if (index)
|
||||||
|
charset.push(encoding[j + firstchar]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var fontBBox = descriptor.get("FontBBox");
|
||||||
|
var subtype = fontDict.get("Subtype").name;
|
||||||
|
new Font(fontName, fontFile, encodingMap, charset, fontBBox, subtype);
|
||||||
|
}
|
||||||
|
return Fonts[fontName];
|
||||||
|
},
|
||||||
|
|
||||||
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();
|
||||||
@ -1733,12 +1779,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;
|
||||||
@ -1749,7 +1818,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 {
|
||||||
@ -1758,9 +1866,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() {
|
||||||
@ -1777,8 +1884,12 @@ var CanvasGraphics = (function() {
|
|||||||
setLineJoin: function(style) {
|
setLineJoin: function(style) {
|
||||||
this.ctx.lineJoin = LINE_JOIN_STYLES[style];
|
this.ctx.lineJoin = LINE_JOIN_STYLES[style];
|
||||||
},
|
},
|
||||||
|
setMiterLimit: function(limit) {
|
||||||
|
this.ctx.miterLimit = limit;
|
||||||
|
},
|
||||||
setDash: function(dashArray, dashPhase) {
|
setDash: function(dashArray, dashPhase) {
|
||||||
TODO("set dash");
|
this.ctx.mozDash = dashArray;
|
||||||
|
this.ctx.mozDashOffset = dashPhase;
|
||||||
},
|
},
|
||||||
setRenderingIntent: function(intent) {
|
setRenderingIntent: function(intent) {
|
||||||
TODO("set rendering intent");
|
TODO("set rendering intent");
|
||||||
@ -1815,6 +1926,12 @@ var CanvasGraphics = (function() {
|
|||||||
curveTo: function(x1, y1, x2, y2, x3, y3) {
|
curveTo: function(x1, y1, x2, y2, x3, y3) {
|
||||||
this.ctx.bezierCurveTo(x1, y1, x2, y2, x3, y3);
|
this.ctx.bezierCurveTo(x1, y1, x2, y2, x3, y3);
|
||||||
},
|
},
|
||||||
|
curveTo2: function(x2, y2, x3, y3) {
|
||||||
|
TODO("'v' operator: need current point in gfx context");
|
||||||
|
},
|
||||||
|
curveTo3: function(x1, y1, x3, y3) {
|
||||||
|
this.curveTo(x1, y1, x3, y3, x3, y3);
|
||||||
|
},
|
||||||
closePath: function() {
|
closePath: function() {
|
||||||
this.ctx.closePath();
|
this.ctx.closePath();
|
||||||
},
|
},
|
||||||
@ -1825,6 +1942,10 @@ var CanvasGraphics = (function() {
|
|||||||
this.ctx.stroke();
|
this.ctx.stroke();
|
||||||
this.consumePath();
|
this.consumePath();
|
||||||
},
|
},
|
||||||
|
closeStroke: function() {
|
||||||
|
this.closePath();
|
||||||
|
this.stroke();
|
||||||
|
},
|
||||||
fill: function() {
|
fill: function() {
|
||||||
this.ctx.fill();
|
this.ctx.fill();
|
||||||
this.consumePath();
|
this.consumePath();
|
||||||
@ -1839,9 +1960,19 @@ var CanvasGraphics = (function() {
|
|||||||
this.ctx.stroke();
|
this.ctx.stroke();
|
||||||
this.consumePath();
|
this.consumePath();
|
||||||
},
|
},
|
||||||
|
eoFillStroke: function() {
|
||||||
|
var savedFillRule = this.setEOFillRule();
|
||||||
|
this.fillStroke();
|
||||||
|
this.restoreFillRule(savedFillRule);
|
||||||
|
},
|
||||||
closeFillStroke: function() {
|
closeFillStroke: function() {
|
||||||
return this.fillStroke();
|
return this.fillStroke();
|
||||||
},
|
},
|
||||||
|
closeEOFillStroke: function() {
|
||||||
|
var savedFillRule = this.setEOFillRule();
|
||||||
|
this.fillStroke();
|
||||||
|
this.restoreFillRule(savedFillRule);
|
||||||
|
},
|
||||||
endPath: function() {
|
endPath: function() {
|
||||||
this.consumePath();
|
this.consumePath();
|
||||||
},
|
},
|
||||||
@ -1862,6 +1993,15 @@ var CanvasGraphics = (function() {
|
|||||||
},
|
},
|
||||||
endText: function() {
|
endText: function() {
|
||||||
},
|
},
|
||||||
|
setCharSpacing: function(spacing) {
|
||||||
|
TODO("character (glyph?) spacing");
|
||||||
|
},
|
||||||
|
setWordSpacing: function(spacing) {
|
||||||
|
TODO("word spacing");
|
||||||
|
},
|
||||||
|
setHSpacing: function(scale) {
|
||||||
|
TODO("horizontal text scale");
|
||||||
|
},
|
||||||
setLeading: function(leading) {
|
setLeading: function(leading) {
|
||||||
this.current.leading = leading;
|
this.current.leading = leading;
|
||||||
},
|
},
|
||||||
@ -1886,10 +2026,20 @@ var CanvasGraphics = (function() {
|
|||||||
this.current.fontSize = size;
|
this.current.fontSize = size;
|
||||||
this.ctx.font = this.current.fontSize +'px "' + fontName + '"';
|
this.ctx.font = this.current.fontSize +'px "' + fontName + '"';
|
||||||
},
|
},
|
||||||
|
setTextRenderingMode: function(mode) {
|
||||||
|
TODO("text rendering mode");
|
||||||
|
},
|
||||||
|
setTextRise: function(rise) {
|
||||||
|
TODO("text rise");
|
||||||
|
},
|
||||||
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;
|
||||||
},
|
},
|
||||||
|
setLeadingMoveText: function(x, y) {
|
||||||
|
this.setLeading(-y);
|
||||||
|
this.moveText(x, y);
|
||||||
|
},
|
||||||
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 ];
|
||||||
this.current.x = this.current.lineX = 0;
|
this.current.x = this.current.lineX = 0;
|
||||||
@ -1921,8 +2071,23 @@ var CanvasGraphics = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
nextLineShowText: function(text) {
|
||||||
|
this.nextLine();
|
||||||
|
this.showText(text);
|
||||||
|
},
|
||||||
|
nextLineSetSpacingShowText: function(wordSpacing, charSpacing, text) {
|
||||||
|
this.setWordSpacing(wordSpacing);
|
||||||
|
this.setCharSpacing(charSpacing);
|
||||||
|
this.nextLineShowText(text);
|
||||||
|
},
|
||||||
|
|
||||||
// Type3 fonts
|
// Type3 fonts
|
||||||
|
setCharWidth: function(xWidth, yWidth) {
|
||||||
|
TODO("type 3 fonts ('d0' operator)");
|
||||||
|
},
|
||||||
|
setCharWidthAndBounds: function(xWidth, yWidth, llx, lly, urx, ury) {
|
||||||
|
TODO("type 3 fonts ('d1' operator)");
|
||||||
|
},
|
||||||
|
|
||||||
// Color
|
// Color
|
||||||
setStrokeColorSpace: function(space) {
|
setStrokeColorSpace: function(space) {
|
||||||
@ -1967,19 +2132,25 @@ var CanvasGraphics = (function() {
|
|||||||
setFillRGBColor: function(r, g, b) {
|
setFillRGBColor: function(r, g, b) {
|
||||||
this.ctx.fillStyle = this.makeCssRgb(r, g, b);
|
this.ctx.fillStyle = this.makeCssRgb(r, g, b);
|
||||||
},
|
},
|
||||||
|
setStrokeCMYKColor: function(c, m, y, k) {
|
||||||
|
TODO("CMYK space");
|
||||||
|
},
|
||||||
|
setFillCMYKColor: function(c, m, y, k) {
|
||||||
|
TODO("CMYK space");
|
||||||
|
},
|
||||||
|
|
||||||
// Shading
|
// Shading
|
||||||
shadingFill: function(entryRef) {
|
shadingFill: function(entryRef) {
|
||||||
var shadingRes = this.res.get("Shading");
|
var xref = this.xref;
|
||||||
|
var res = this.res;
|
||||||
|
|
||||||
|
var shadingRes = xref.fetchIfRef(res.get("Shading"));
|
||||||
if (!shadingRes)
|
if (!shadingRes)
|
||||||
return;
|
error("No shading resource found");
|
||||||
shadingRes = this.xref.fetchIfRef(shadingRes);
|
|
||||||
var shading = shadingRes.get(entryRef.name);
|
var shading = xref.fetchIfRef(shadingRes.get(entryRef.name));
|
||||||
if (!shading)
|
if (!shading)
|
||||||
return;
|
error("No shading object found");
|
||||||
shading = this.xref.fetchIfRef(shading);
|
|
||||||
if (!shading)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this.save();
|
this.save();
|
||||||
|
|
||||||
@ -1990,32 +2161,30 @@ var CanvasGraphics = (function() {
|
|||||||
this.endPath();
|
this.endPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var cs = shading.get2("ColorSpace", "CS");
|
||||||
TODO("shading-fill color space");
|
TODO("shading-fill color space");
|
||||||
|
|
||||||
var type = shading.get("ShadingType");
|
var background = shading.get("Background");
|
||||||
switch (type) {
|
if (background)
|
||||||
case 1:
|
TODO("handle background colors");
|
||||||
this.fillFunctionShading(shading);
|
|
||||||
break;
|
const types = [null, this.fillFunctionShading,
|
||||||
case 2:
|
this.fillAxialShading, this.fillRadialShading];
|
||||||
this.fillAxialShading(shading);
|
|
||||||
break;
|
var typeNum = shading.get("ShadingType");
|
||||||
case 3:
|
var fillFn = types[typeNum];
|
||||||
this.fillRadialShading(shading);
|
if (!fillFn)
|
||||||
break;
|
error("Unknown type of shading");
|
||||||
case 4: case 5: case 6: case 7:
|
fillFn.apply(this, [shading]);
|
||||||
TODO("shading fill type "+ type);
|
|
||||||
default:
|
|
||||||
malformed("Unknown shading type "+ type);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.restore();
|
this.restore();
|
||||||
},
|
},
|
||||||
|
|
||||||
fillAxialShading: function(sh) {
|
fillAxialShading: function(sh) {
|
||||||
var coordsArr = sh.get("Coords");
|
var coordsArr = sh.get("Coords");
|
||||||
var x0 = coordsArr[0], y0 = coordsArr[1],
|
var x0 = coordsArr[0], y0 = coordsArr[1],
|
||||||
x1 = coordsArr[2], y1 = coordsArr[3];
|
x1 = coordsArr[2], y1 = coordsArr[3];
|
||||||
|
|
||||||
var t0 = 0.0, t1 = 1.0;
|
var t0 = 0.0, t1 = 1.0;
|
||||||
if (sh.has("Domain")) {
|
if (sh.has("Domain")) {
|
||||||
var domainArr = sh.get("Domain");
|
var domainArr = sh.get("Domain");
|
||||||
@ -2026,19 +2195,39 @@ var CanvasGraphics = (function() {
|
|||||||
if (sh.has("Extend")) {
|
if (sh.has("Extend")) {
|
||||||
var extendArr = sh.get("Extend");
|
var extendArr = sh.get("Extend");
|
||||||
extendStart = extendArr[0], extendEnd = extendArr[1];
|
extendStart = extendArr[0], extendEnd = extendArr[1];
|
||||||
|
TODO("Support extend");
|
||||||
}
|
}
|
||||||
|
var fnObj = sh.get("Function");
|
||||||
var fn = sh.get("Function");
|
fnObj = this.xref.fetchIfRef(fnObj);
|
||||||
fn = this.xref.fetchIfRef(fn);
|
if (IsArray(fnObj))
|
||||||
|
error("No support for array of functions");
|
||||||
|
else if (!IsPDFFunction(fnObj))
|
||||||
|
error("Invalid function");
|
||||||
|
fn = new PDFFunction(this.xref, fnObj);
|
||||||
|
|
||||||
var gradient = this.ctx.createLinearGradient(x0, y0, x1, y1);
|
var gradient = this.ctx.createLinearGradient(x0, y0, x1, y1);
|
||||||
|
var step = (t1 - t0) / 10;
|
||||||
gradient.addColorStop(0, 'rgb(0,0,255)');
|
|
||||||
gradient.addColorStop(1, 'rgb(0,255,0)');
|
for (var i = t0; i <= t1; i += step) {
|
||||||
|
var c = fn.func([i]);
|
||||||
|
gradient.addColorStop(i, this.makeCssRgb.apply(this, c));
|
||||||
|
}
|
||||||
|
|
||||||
this.ctx.fillStyle = gradient;
|
this.ctx.fillStyle = gradient;
|
||||||
this.ctx.fill();
|
|
||||||
this.consumePath();
|
// HACK to draw the gradient onto an infinite rectangle.
|
||||||
|
// PDF gradients are drawn across the entire image while
|
||||||
|
// Canvas only allows gradients to be drawn in a rectangle
|
||||||
|
this.ctx.fillRect(-1e10, -1e10, 2e10, 2e10);
|
||||||
|
},
|
||||||
|
|
||||||
|
// Images
|
||||||
|
beginInlineImage: function() {
|
||||||
|
TODO("inline images");
|
||||||
|
error("(Stream will not be parsed properly, bailing now)");
|
||||||
|
// Like an inline stream:
|
||||||
|
// - key/value pairs up to Cmd(ID)
|
||||||
|
// - then image data up to Cmd(EI)
|
||||||
},
|
},
|
||||||
|
|
||||||
// XObjects
|
// XObjects
|
||||||
@ -2062,9 +2251,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 {
|
||||||
@ -2072,27 +2261,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
|
||||||
@ -2269,6 +2457,33 @@ var CanvasGraphics = (function() {
|
|||||||
this.restore();
|
this.restore();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Marked content
|
||||||
|
|
||||||
|
markPoint: function(tag) {
|
||||||
|
TODO("Marked content");
|
||||||
|
},
|
||||||
|
markPointProps: function(tag, properties) {
|
||||||
|
TODO("Marked content");
|
||||||
|
},
|
||||||
|
beginMarkedContent: function(tag) {
|
||||||
|
TODO("Marked content");
|
||||||
|
},
|
||||||
|
beginMarkedContentProps: function(tag, properties) {
|
||||||
|
TODO("Marked content");
|
||||||
|
},
|
||||||
|
endMarkedContent: function() {
|
||||||
|
TODO("Marked content");
|
||||||
|
},
|
||||||
|
|
||||||
|
// Compatibility
|
||||||
|
|
||||||
|
beginCompat: function() {
|
||||||
|
TODO("ignore undefined operators (should we do that anyway?)");
|
||||||
|
},
|
||||||
|
endCompat: function() {
|
||||||
|
TODO("stop ignoring undefined operators");
|
||||||
|
},
|
||||||
|
|
||||||
// Helper functions
|
// Helper functions
|
||||||
|
|
||||||
consumePath: function() {
|
consumePath: function() {
|
||||||
@ -2351,3 +2566,154 @@ var ColorSpace = (function() {
|
|||||||
|
|
||||||
return constructor;
|
return constructor;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
var PDFFunction = (function() {
|
||||||
|
function constructor(xref, fn) {
|
||||||
|
var dict = fn.dict;
|
||||||
|
if (!dict)
|
||||||
|
dict = fn;
|
||||||
|
|
||||||
|
const types = [this.constructSampled, null,
|
||||||
|
this.constructInterpolated, this.constructStiched,
|
||||||
|
this.constructPostScript];
|
||||||
|
|
||||||
|
var typeNum = dict.get("FunctionType");
|
||||||
|
var typeFn = types[typeNum];
|
||||||
|
if (!typeFn)
|
||||||
|
error("Unknown type of function");
|
||||||
|
|
||||||
|
typeFn.apply(this, [fn, dict]);
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor.prototype = {
|
||||||
|
constructSampled: function(str, dict) {
|
||||||
|
var domain = dict.get("Domain");
|
||||||
|
var range = dict.get("Range");
|
||||||
|
|
||||||
|
if (!domain || !range)
|
||||||
|
error("No domain or range");
|
||||||
|
|
||||||
|
var inputSize = domain.length / 2;
|
||||||
|
var outputSize = range.length / 2;
|
||||||
|
|
||||||
|
if (inputSize != 1)
|
||||||
|
error("No support for multi-variable inputs to functions");
|
||||||
|
|
||||||
|
var size = dict.get("Size");
|
||||||
|
var bps = dict.get("BitsPerSample");
|
||||||
|
var order = dict.get("Order");
|
||||||
|
if (!order)
|
||||||
|
order = 1;
|
||||||
|
if (order !== 1)
|
||||||
|
error ("No support for cubic spline interpolation");
|
||||||
|
|
||||||
|
var encode = dict.get("Encode");
|
||||||
|
if (!encode) {
|
||||||
|
encode = [];
|
||||||
|
for (var i = 0; i < inputSize; ++i) {
|
||||||
|
encode.push(0);
|
||||||
|
encode.push(size[i] - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var decode = dict.get("Decode");
|
||||||
|
if (!decode)
|
||||||
|
decode = range;
|
||||||
|
|
||||||
|
var samples = this.getSampleArray(size, outputSize, bps, str);
|
||||||
|
|
||||||
|
this.func = function(args) {
|
||||||
|
var clip = function(v, min, max) {
|
||||||
|
if (v > max)
|
||||||
|
v = max;
|
||||||
|
else if (v < min)
|
||||||
|
v = min
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputSize != args.length)
|
||||||
|
error("Incorrect number of arguments");
|
||||||
|
|
||||||
|
for (var i = 0; i < inputSize; i++) {
|
||||||
|
var i2 = i * 2;
|
||||||
|
|
||||||
|
// clip to the domain
|
||||||
|
var v = clip(args[i], domain[i2], domain[i2 + 1]);
|
||||||
|
|
||||||
|
// encode
|
||||||
|
v = encode[i2] + ((v - domain[i2]) *
|
||||||
|
(encode[i2 + 1] - encode[i2]) /
|
||||||
|
(domain[i2 + 1] - domain[i2]));
|
||||||
|
|
||||||
|
// clip to the size
|
||||||
|
args[i] = clip(v, 0, size[i] - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// interpolate to table
|
||||||
|
TODO("Multi-dimensional interpolation");
|
||||||
|
var floor = Math.floor(args[0]);
|
||||||
|
var ceil = Math.ceil(args[0]);
|
||||||
|
var scale = args[0] - floor;
|
||||||
|
|
||||||
|
floor *= outputSize;
|
||||||
|
ceil *= outputSize;
|
||||||
|
|
||||||
|
var output = [];
|
||||||
|
for (var i = 0; i < outputSize; ++i) {
|
||||||
|
if (ceil == floor) {
|
||||||
|
var v = samples[ceil + i];
|
||||||
|
} else {
|
||||||
|
var low = samples[floor + i];
|
||||||
|
var high = samples[ceil + i];
|
||||||
|
var v = low * scale + high * (1 - scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
var i2 = i * 2;
|
||||||
|
// decode
|
||||||
|
v = decode[i2] + (v * (decode[i2 + 1] - decode[i2]) /
|
||||||
|
((1 << bps) - 1));
|
||||||
|
|
||||||
|
// clip to the domain
|
||||||
|
output.push(clip(v, range[i2], range[i2 + 1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getSampleArray: function(size, outputSize, bps, str) {
|
||||||
|
var length = 1;
|
||||||
|
for (var i = 0; i < size.length; i++)
|
||||||
|
length *= size[i];
|
||||||
|
length *= outputSize;
|
||||||
|
|
||||||
|
var array = [];
|
||||||
|
var codeSize = 0;
|
||||||
|
var codeBuf = 0;
|
||||||
|
|
||||||
|
var strBytes = str.getBytes((length * bps + 7) / 8);
|
||||||
|
var strIdx = 0;
|
||||||
|
for (var i = 0; i < length; i++) {
|
||||||
|
var b;
|
||||||
|
while (codeSize < bps) {
|
||||||
|
codeBuf <<= 8;
|
||||||
|
codeBuf |= strBytes[strIdx++];
|
||||||
|
codeSize += 8;
|
||||||
|
}
|
||||||
|
codeSize -= bps
|
||||||
|
array.push(codeBuf >> codeSize);
|
||||||
|
codeBuf &= (1 << codeSize) - 1;
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
},
|
||||||
|
constructInterpolated: function() {
|
||||||
|
error("unhandled type of function");
|
||||||
|
},
|
||||||
|
constructStiched: function() {
|
||||||
|
error("unhandled type of function");
|
||||||
|
},
|
||||||
|
constructPostScript: function() {
|
||||||
|
error("unhandled type of function");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return constructor;
|
||||||
|
})();
|
||||||
|
98
test.js
98
test.js
@ -56,87 +56,35 @@ 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");
|
|
||||||
ctx.save();
|
|
||||||
ctx.fillStyle = "rgb(255, 255, 255)";
|
|
||||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
||||||
ctx.restore();
|
|
||||||
|
|
||||||
var gfx = new CanvasGraphics(ctx);
|
var ctx = canvas.getContext("2d");
|
||||||
page.display(gfx);
|
ctx.save();
|
||||||
|
ctx.fillStyle = "rgb(255, 255, 255)";
|
||||||
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
|
ctx.restore();
|
||||||
|
|
||||||
var t2 = Date.now();
|
var gfx = new CanvasGraphics(ctx);
|
||||||
var infoDisplay = document.getElementById("info");
|
|
||||||
infoDisplay.innerHTML = "Time to render: "+ (t1 - t0) + "/" + (t2 - t1) + " ms";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loading a font via data uri is asynchronous, so wait for all font
|
// page.compile will collect all fonts for us, once we have loaded them
|
||||||
// of the page to be fully loaded before loading the page
|
// we can trigger the actual page rendering with page.display
|
||||||
var fontsReady = true;
|
var fonts = [];
|
||||||
var fonts = page.fonts;
|
|
||||||
var xref = page.xref;
|
page.compile(gfx, fonts);
|
||||||
fonts.forEach(function(fontKey, fontDict) {
|
var t2 = Date.now();
|
||||||
var descriptor = xref.fetch(fontDict.get("FontDescriptor"));
|
|
||||||
var fontName = descriptor.get("FontName").name;
|
|
||||||
fontName = fontName.replace("+", "_");
|
|
||||||
|
|
||||||
// Check if the font has been loaded or is still loading
|
var interval = setInterval(function() {
|
||||||
var font = Fonts[fontName];
|
for (var i = 0; i < fonts.length; i++) {
|
||||||
if (!font) {
|
if (fonts[i].loading)
|
||||||
var fontFile = descriptor.get2("FontFile", "FontFile2");
|
return;
|
||||||
fontFile = xref.fetchIfRef(fontFile);
|
|
||||||
|
|
||||||
// Generate the custom cmap of the font if needed
|
|
||||||
var encodingMap = {};
|
|
||||||
if (fontDict.has("Encoding")) {
|
|
||||||
var encoding = xref.fetchIfRef(fontDict.get("Encoding"));
|
|
||||||
if (IsDict(encoding)) {
|
|
||||||
|
|
||||||
// Build an map between codes and glyphs
|
|
||||||
var differences = encoding.get("Differences");
|
|
||||||
var index = 0;
|
|
||||||
for (var j = 0; j < differences.length; j++) {
|
|
||||||
var data = differences[j];
|
|
||||||
IsNum(data) ? index = data : encodingMap[index++] = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the font charset
|
|
||||||
var charset = descriptor.get("CharSet").split("/");
|
|
||||||
|
|
||||||
} else if (IsName(encoding)) {
|
|
||||||
var encoding = Encodings[encoding];
|
|
||||||
var widths = xref.fetchIfRef(fontDict.get("Widths"));
|
|
||||||
var firstchar = xref.fetchIfRef(fontDict.get("FirstChar"));
|
|
||||||
|
|
||||||
var charset = [];
|
|
||||||
for (var j = 0; j < widths.length; j++) {
|
|
||||||
var index = widths[j];
|
|
||||||
if (index)
|
|
||||||
charset.push(encoding[j + firstchar]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var fontBBox = descriptor.get("FontBBox");
|
|
||||||
|
|
||||||
var subtype = fontDict.get("Subtype").name;
|
|
||||||
new Font(fontName, fontFile, encodingMap, charset, fontBBox, subtype);
|
|
||||||
return fontsReady = false;
|
|
||||||
} else if (font.loading) {
|
|
||||||
return fontsReady = false;
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
// If everything is ready do not delayed the page loading any more
|
page.display(gfx);
|
||||||
if (fontsReady)
|
var t3 = Date.now();
|
||||||
display();
|
var infoDisplay = document.getElementById("info");
|
||||||
else {
|
infoDisplay.innerHTML = "Time to load/compile/render: "+ (t1 - t0) + "/" + (t2 - t1) + "/" + (t3 - t2) + " ms";
|
||||||
// FIXME Relying on an event seems much more cleaner here instead
|
clearInterval(interval);
|
||||||
// of a setTimeout...
|
}, 10);
|
||||||
pageTimeout = window.setTimeout(displayPage, 150, num);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function nextPage() {
|
function nextPage() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user