|
|
@ -3385,18 +3385,13 @@ var Encodings = { |
|
|
|
|
|
|
|
|
|
|
|
var IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0]; |
|
|
|
var IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0]; |
|
|
|
|
|
|
|
|
|
|
|
// <canvas> contexts store most of the state we need natively.
|
|
|
|
var EvalState = (function() { |
|
|
|
// However, PDF needs a bit more state, which we store here.
|
|
|
|
|
|
|
|
var CanvasExtraState = (function() { |
|
|
|
|
|
|
|
function constructor() { |
|
|
|
function constructor() { |
|
|
|
// Are soft masks and alpha values shapes or opacities?
|
|
|
|
// Are soft masks and alpha values shapes or opacities?
|
|
|
|
this.alphaIsShape = false; |
|
|
|
this.alphaIsShape = false; |
|
|
|
this.fontSize = 0; |
|
|
|
this.fontSize = 0; |
|
|
|
this.textMatrix = IDENTITY_MATRIX; |
|
|
|
this.textMatrix = IDENTITY_MATRIX; |
|
|
|
this.leading = 0; |
|
|
|
this.leading = 0; |
|
|
|
// Current point (in user coordinates)
|
|
|
|
|
|
|
|
this.x = 0; |
|
|
|
|
|
|
|
this.y = 0; |
|
|
|
|
|
|
|
// Start of text line (in text coordinates)
|
|
|
|
// Start of text line (in text coordinates)
|
|
|
|
this.lineX = 0; |
|
|
|
this.lineX = 0; |
|
|
|
this.lineY = 0; |
|
|
|
this.lineY = 0; |
|
|
@ -3413,34 +3408,13 @@ var CanvasExtraState = (function() { |
|
|
|
return constructor; |
|
|
|
return constructor; |
|
|
|
})(); |
|
|
|
})(); |
|
|
|
|
|
|
|
|
|
|
|
function ScratchCanvas(width, height) { |
|
|
|
var PartialEvaluator = (function() { |
|
|
|
var canvas = document.createElement('canvas'); |
|
|
|
function constructor() { |
|
|
|
canvas.width = width; |
|
|
|
this.state = new EvalState(); |
|
|
|
canvas.height = height; |
|
|
|
this.stateStack = [ ]; |
|
|
|
return canvas; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var CanvasGraphics = (function() { |
|
|
|
|
|
|
|
function constructor(canvasCtx, imageCanvas) { |
|
|
|
|
|
|
|
this.ctx = canvasCtx; |
|
|
|
|
|
|
|
this.current = new CanvasExtraState(); |
|
|
|
|
|
|
|
this.stateStack = []; |
|
|
|
|
|
|
|
this.pendingClip = null; |
|
|
|
|
|
|
|
this.res = null; |
|
|
|
|
|
|
|
this.xobjs = null; |
|
|
|
|
|
|
|
this.ScratchCanvas = imageCanvas || ScratchCanvas; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var LINE_CAP_STYLES = ['butt', 'round', 'square']; |
|
|
|
var OP_MAP = { |
|
|
|
var LINE_JOIN_STYLES = ['miter', 'round', 'bevel']; |
|
|
|
|
|
|
|
var NORMAL_CLIP = {}; |
|
|
|
|
|
|
|
var EO_CLIP = {}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Used for tiling patterns
|
|
|
|
|
|
|
|
var PAINT_TYPE_COLORED = 1, PAINT_TYPE_UNCOLORED = 2; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor.prototype = { |
|
|
|
|
|
|
|
map: { |
|
|
|
|
|
|
|
// Graphics state
|
|
|
|
// Graphics state
|
|
|
|
w: 'setLineWidth', |
|
|
|
w: 'setLineWidth', |
|
|
|
J: 'setLineCap', |
|
|
|
J: 'setLineCap', |
|
|
@ -3533,6 +3507,88 @@ var CanvasGraphics = (function() { |
|
|
|
// Compatibility
|
|
|
|
// Compatibility
|
|
|
|
BX: 'beginCompat', |
|
|
|
BX: 'beginCompat', |
|
|
|
EX: 'endCompat' |
|
|
|
EX: 'endCompat' |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor.prototype = { |
|
|
|
|
|
|
|
eval: function(stream, xref, resources, fonts) { |
|
|
|
|
|
|
|
resources = xref.fetchIfRef(resources) || new Dict(); |
|
|
|
|
|
|
|
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 obj; |
|
|
|
|
|
|
|
while (!IsEOF(obj = parser.getObj())) { |
|
|
|
|
|
|
|
if (IsCmd(obj)) { |
|
|
|
|
|
|
|
var cmd = obj.cmd; |
|
|
|
|
|
|
|
var fn = OP_MAP[cmd]; |
|
|
|
|
|
|
|
assertWellFormed(fn, "Unknown command '" + cmd + "'"); |
|
|
|
|
|
|
|
// TODO figure out how to type-check vararg functions
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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.eval(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; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
assertWellFormed(args.length <= 33, 'Too many arguments'); |
|
|
|
|
|
|
|
args.push(obj); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var fn = Function('objpool', src); |
|
|
|
|
|
|
|
return function(gfx) { fn.call(gfx, objpool); }; |
|
|
|
}, |
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
translateFont: function(fontDict, xref, resources) { |
|
|
|
translateFont: function(fontDict, xref, resources) { |
|
|
@ -3697,7 +3753,66 @@ var CanvasGraphics = (function() { |
|
|
|
properties: properties |
|
|
|
properties: properties |
|
|
|
}; |
|
|
|
}; |
|
|
|
}, |
|
|
|
}, |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return constructor; |
|
|
|
|
|
|
|
})(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// <canvas> contexts store most of the state we need natively.
|
|
|
|
|
|
|
|
// However, PDF needs a bit more state, which we store here.
|
|
|
|
|
|
|
|
var CanvasExtraState = (function() { |
|
|
|
|
|
|
|
function constructor() { |
|
|
|
|
|
|
|
// Are soft masks and alpha values shapes or opacities?
|
|
|
|
|
|
|
|
this.alphaIsShape = false; |
|
|
|
|
|
|
|
this.fontSize = 0; |
|
|
|
|
|
|
|
this.textMatrix = IDENTITY_MATRIX; |
|
|
|
|
|
|
|
this.leading = 0; |
|
|
|
|
|
|
|
// Current point (in user coordinates)
|
|
|
|
|
|
|
|
this.x = 0; |
|
|
|
|
|
|
|
this.y = 0; |
|
|
|
|
|
|
|
// Start of text line (in text coordinates)
|
|
|
|
|
|
|
|
this.lineX = 0; |
|
|
|
|
|
|
|
this.lineY = 0; |
|
|
|
|
|
|
|
// Character and word spacing
|
|
|
|
|
|
|
|
this.charSpace = 0; |
|
|
|
|
|
|
|
this.wordSpace = 0; |
|
|
|
|
|
|
|
this.textHScale = 100; |
|
|
|
|
|
|
|
// Color spaces
|
|
|
|
|
|
|
|
this.fillColorSpace = null; |
|
|
|
|
|
|
|
this.strokeColorSpace = null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
constructor.prototype = { |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
return constructor; |
|
|
|
|
|
|
|
})(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function ScratchCanvas(width, height) { |
|
|
|
|
|
|
|
var canvas = document.createElement('canvas'); |
|
|
|
|
|
|
|
canvas.width = width; |
|
|
|
|
|
|
|
canvas.height = height; |
|
|
|
|
|
|
|
return canvas; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var CanvasGraphics = (function() { |
|
|
|
|
|
|
|
function constructor(canvasCtx, imageCanvas) { |
|
|
|
|
|
|
|
this.ctx = canvasCtx; |
|
|
|
|
|
|
|
this.current = new CanvasExtraState(); |
|
|
|
|
|
|
|
this.stateStack = []; |
|
|
|
|
|
|
|
this.pendingClip = null; |
|
|
|
|
|
|
|
this.res = null; |
|
|
|
|
|
|
|
this.xobjs = null; |
|
|
|
|
|
|
|
this.ScratchCanvas = imageCanvas || ScratchCanvas; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var LINE_CAP_STYLES = ['butt', 'round', 'square']; |
|
|
|
|
|
|
|
var LINE_JOIN_STYLES = ['miter', 'round', 'bevel']; |
|
|
|
|
|
|
|
var NORMAL_CLIP = {}; |
|
|
|
|
|
|
|
var EO_CLIP = {}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Used for tiling patterns
|
|
|
|
|
|
|
|
var PAINT_TYPE_COLORED = 1, PAINT_TYPE_UNCOLORED = 2; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor.prototype = { |
|
|
|
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(); |
|
|
@ -3705,6 +3820,11 @@ var CanvasGraphics = (function() { |
|
|
|
this.ctx.translate(0, -mediaBox.height); |
|
|
|
this.ctx.translate(0, -mediaBox.height); |
|
|
|
}, |
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
compile: function(stream, xref, resources, fonts) { |
|
|
|
|
|
|
|
var pe = new PartialEvaluator(); |
|
|
|
|
|
|
|
return pe.eval(stream, xref, resources, fonts); |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
execute: function(code, xref, resources) { |
|
|
|
execute: function(code, xref, resources) { |
|
|
|
resources = xref.fetchIfRef(resources) || new Dict(); |
|
|
|
resources = xref.fetchIfRef(resources) || new Dict(); |
|
|
|
var savedXref = this.xref, savedRes = this.res, savedXobjs = this.xobjs; |
|
|
|
var savedXref = this.xref, savedRes = this.res, savedXobjs = this.xobjs; |
|
|
@ -3719,88 +3839,6 @@ var CanvasGraphics = (function() { |
|
|
|
this.xref = savedXref; |
|
|
|
this.xref = savedXref; |
|
|
|
}, |
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
compile: function(stream, xref, resources, fonts) { |
|
|
|
|
|
|
|
resources = xref.fetchIfRef(resources) || new Dict(); |
|
|
|
|
|
|
|
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 map = this.map; |
|
|
|
|
|
|
|
var obj; |
|
|
|
|
|
|
|
while (!IsEOF(obj = parser.getObj())) { |
|
|
|
|
|
|
|
if (IsCmd(obj)) { |
|
|
|
|
|
|
|
var cmd = obj.cmd; |
|
|
|
|
|
|
|
var fn = map[cmd]; |
|
|
|
|
|
|
|
assertWellFormed(fn, "Unknown command '" + cmd + "'"); |
|
|
|
|
|
|
|
// TODO figure out how to type-check vararg functions
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
assertWellFormed(args.length <= 33, 'Too many arguments'); |
|
|
|
|
|
|
|
args.push(obj); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var fn = Function('objpool', src); |
|
|
|
|
|
|
|
return function(gfx) { fn.call(gfx, objpool); }; |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
endDrawing: function() { |
|
|
|
endDrawing: function() { |
|
|
|
this.ctx.restore(); |
|
|
|
this.ctx.restore(); |
|
|
|
}, |
|
|
|
}, |
|
|
|