|
|
@ -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,126 +3408,187 @@ 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']; |
|
|
|
// Graphics state
|
|
|
|
var NORMAL_CLIP = {}; |
|
|
|
w: 'setLineWidth', |
|
|
|
var EO_CLIP = {}; |
|
|
|
J: 'setLineCap', |
|
|
|
|
|
|
|
j: 'setLineJoin', |
|
|
|
|
|
|
|
M: 'setMiterLimit', |
|
|
|
|
|
|
|
d: 'setDash', |
|
|
|
|
|
|
|
ri: 'setRenderingIntent', |
|
|
|
|
|
|
|
i: 'setFlatness', |
|
|
|
|
|
|
|
gs: 'setGState', |
|
|
|
|
|
|
|
q: 'save', |
|
|
|
|
|
|
|
Q: 'restore', |
|
|
|
|
|
|
|
cm: 'transform', |
|
|
|
|
|
|
|
|
|
|
|
// Used for tiling patterns
|
|
|
|
// Path
|
|
|
|
var PAINT_TYPE_COLORED = 1, PAINT_TYPE_UNCOLORED = 2; |
|
|
|
m: 'moveTo', |
|
|
|
|
|
|
|
l: 'lineTo', |
|
|
|
|
|
|
|
c: 'curveTo', |
|
|
|
|
|
|
|
v: 'curveTo2', |
|
|
|
|
|
|
|
y: 'curveTo3', |
|
|
|
|
|
|
|
h: 'closePath', |
|
|
|
|
|
|
|
re: 'rectangle', |
|
|
|
|
|
|
|
S: 'stroke', |
|
|
|
|
|
|
|
s: 'closeStroke', |
|
|
|
|
|
|
|
f: 'fill', |
|
|
|
|
|
|
|
F: 'fill', |
|
|
|
|
|
|
|
'f*': 'eoFill', |
|
|
|
|
|
|
|
B: 'fillStroke', |
|
|
|
|
|
|
|
'B*': 'eoFillStroke', |
|
|
|
|
|
|
|
b: 'closeFillStroke', |
|
|
|
|
|
|
|
'b*': 'closeEOFillStroke', |
|
|
|
|
|
|
|
n: 'endPath', |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Clipping
|
|
|
|
|
|
|
|
W: 'clip', |
|
|
|
|
|
|
|
'W*': 'eoClip', |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Text
|
|
|
|
|
|
|
|
BT: 'beginText', |
|
|
|
|
|
|
|
ET: 'endText', |
|
|
|
|
|
|
|
Tc: 'setCharSpacing', |
|
|
|
|
|
|
|
Tw: 'setWordSpacing', |
|
|
|
|
|
|
|
Tz: 'setHScale', |
|
|
|
|
|
|
|
TL: 'setLeading', |
|
|
|
|
|
|
|
Tf: 'setFont', |
|
|
|
|
|
|
|
Tr: 'setTextRenderingMode', |
|
|
|
|
|
|
|
Ts: 'setTextRise', |
|
|
|
|
|
|
|
Td: 'moveText', |
|
|
|
|
|
|
|
TD: 'setLeadingMoveText', |
|
|
|
|
|
|
|
Tm: 'setTextMatrix', |
|
|
|
|
|
|
|
'T*': 'nextLine', |
|
|
|
|
|
|
|
Tj: 'showText', |
|
|
|
|
|
|
|
TJ: 'showSpacedText', |
|
|
|
|
|
|
|
"'": 'nextLineShowText', |
|
|
|
|
|
|
|
'"': 'nextLineSetSpacingShowText', |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Type3 fonts
|
|
|
|
|
|
|
|
d0: 'setCharWidth', |
|
|
|
|
|
|
|
d1: 'setCharWidthAndBounds', |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Color
|
|
|
|
|
|
|
|
CS: 'setStrokeColorSpace', |
|
|
|
|
|
|
|
cs: 'setFillColorSpace', |
|
|
|
|
|
|
|
SC: 'setStrokeColor', |
|
|
|
|
|
|
|
SCN: 'setStrokeColorN', |
|
|
|
|
|
|
|
sc: 'setFillColor', |
|
|
|
|
|
|
|
scn: 'setFillColorN', |
|
|
|
|
|
|
|
G: 'setStrokeGray', |
|
|
|
|
|
|
|
g: 'setFillGray', |
|
|
|
|
|
|
|
RG: 'setStrokeRGBColor', |
|
|
|
|
|
|
|
rg: 'setFillRGBColor', |
|
|
|
|
|
|
|
K: 'setStrokeCMYKColor', |
|
|
|
|
|
|
|
k: 'setFillCMYKColor', |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Shading
|
|
|
|
|
|
|
|
sh: 'shadingFill', |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Images
|
|
|
|
|
|
|
|
BI: 'beginInlineImage', |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// XObjects
|
|
|
|
|
|
|
|
Do: 'paintXObject', |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Marked content
|
|
|
|
|
|
|
|
MP: 'markPoint', |
|
|
|
|
|
|
|
DP: 'markPointProps', |
|
|
|
|
|
|
|
BMC: 'beginMarkedContent', |
|
|
|
|
|
|
|
BDC: 'beginMarkedContentProps', |
|
|
|
|
|
|
|
EMC: 'endMarkedContent', |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Compatibility
|
|
|
|
|
|
|
|
BX: 'beginCompat', |
|
|
|
|
|
|
|
EX: 'endCompat' |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
constructor.prototype = { |
|
|
|
constructor.prototype = { |
|
|
|
map: { |
|
|
|
eval: function(stream, xref, resources, fonts) { |
|
|
|
// Graphics state
|
|
|
|
resources = xref.fetchIfRef(resources) || new Dict(); |
|
|
|
w: 'setLineWidth', |
|
|
|
var xobjs = xref.fetchIfRef(resources.get('XObject')) || new Dict(); |
|
|
|
J: 'setLineCap', |
|
|
|
|
|
|
|
j: 'setLineJoin', |
|
|
|
var parser = new Parser(new Lexer(stream), false); |
|
|
|
M: 'setMiterLimit', |
|
|
|
var objpool = []; |
|
|
|
d: 'setDash', |
|
|
|
|
|
|
|
ri: 'setRenderingIntent', |
|
|
|
function emitArg(arg) { |
|
|
|
i: 'setFlatness', |
|
|
|
if (typeof arg == 'object' || typeof arg == 'string') { |
|
|
|
gs: 'setGState', |
|
|
|
var index = objpool.length; |
|
|
|
q: 'save', |
|
|
|
objpool[index] = arg; |
|
|
|
Q: 'restore', |
|
|
|
return 'objpool[' + index + ']'; |
|
|
|
cm: 'transform', |
|
|
|
} |
|
|
|
|
|
|
|
return arg; |
|
|
|
// Path
|
|
|
|
} |
|
|
|
m: 'moveTo', |
|
|
|
|
|
|
|
l: 'lineTo', |
|
|
|
var src = ''; |
|
|
|
c: 'curveTo', |
|
|
|
|
|
|
|
v: 'curveTo2', |
|
|
|
var args = []; |
|
|
|
y: 'curveTo3', |
|
|
|
var obj; |
|
|
|
h: 'closePath', |
|
|
|
while (!IsEOF(obj = parser.getObj())) { |
|
|
|
re: 'rectangle', |
|
|
|
if (IsCmd(obj)) { |
|
|
|
S: 'stroke', |
|
|
|
var cmd = obj.cmd; |
|
|
|
s: 'closeStroke', |
|
|
|
var fn = OP_MAP[cmd]; |
|
|
|
f: 'fill', |
|
|
|
assertWellFormed(fn, "Unknown command '" + cmd + "'"); |
|
|
|
F: 'fill', |
|
|
|
// TODO figure out how to type-check vararg functions
|
|
|
|
'f*': 'eoFill', |
|
|
|
|
|
|
|
B: 'fillStroke', |
|
|
|
if (cmd == 'Do' && !args[0].code) { // eagerly compile XForm objects
|
|
|
|
'B*': 'eoFillStroke', |
|
|
|
var name = args[0].name; |
|
|
|
b: 'closeFillStroke', |
|
|
|
var xobj = xobjs.get(name); |
|
|
|
'b*': 'closeEOFillStroke', |
|
|
|
if (xobj) { |
|
|
|
n: 'endPath', |
|
|
|
xobj = xref.fetchIfRef(xobj); |
|
|
|
|
|
|
|
assertWellFormed(IsStream(xobj), 'XObject should be a stream'); |
|
|
|
// Clipping
|
|
|
|
|
|
|
|
W: 'clip', |
|
|
|
var type = xobj.dict.get('Subtype'); |
|
|
|
'W*': 'eoClip', |
|
|
|
assertWellFormed( |
|
|
|
|
|
|
|
IsName(type), |
|
|
|
// Text
|
|
|
|
'XObject should have a Name subtype' |
|
|
|
BT: 'beginText', |
|
|
|
); |
|
|
|
ET: 'endText', |
|
|
|
|
|
|
|
Tc: 'setCharSpacing', |
|
|
|
if ('Form' == type.name) { |
|
|
|
Tw: 'setWordSpacing', |
|
|
|
args[0].code = this.eval(xobj, |
|
|
|
Tz: 'setHScale', |
|
|
|
xref, |
|
|
|
TL: 'setLeading', |
|
|
|
xobj.dict.get('Resources'), |
|
|
|
Tf: 'setFont', |
|
|
|
fonts); |
|
|
|
Tr: 'setTextRenderingMode', |
|
|
|
} |
|
|
|
Ts: 'setTextRise', |
|
|
|
} |
|
|
|
Td: 'moveText', |
|
|
|
} else if (cmd == 'Tf') { // eagerly collect all fonts
|
|
|
|
TD: 'setLeadingMoveText', |
|
|
|
var fontRes = resources.get('Font'); |
|
|
|
Tm: 'setTextMatrix', |
|
|
|
if (fontRes) { |
|
|
|
'T*': 'nextLine', |
|
|
|
fontRes = xref.fetchIfRef(fontRes); |
|
|
|
Tj: 'showText', |
|
|
|
var font = xref.fetchIfRef(fontRes.get(args[0].name)); |
|
|
|
TJ: 'showSpacedText', |
|
|
|
assertWellFormed(IsDict(font)); |
|
|
|
"'": 'nextLineShowText', |
|
|
|
if (!font.translated) { |
|
|
|
'"': 'nextLineSetSpacingShowText', |
|
|
|
font.translated = this.translateFont(font, xref, resources); |
|
|
|
|
|
|
|
if (fonts && font.translated) { |
|
|
|
// Type3 fonts
|
|
|
|
// keep track of each font we translated so the caller can
|
|
|
|
d0: 'setCharWidth', |
|
|
|
// load them asynchronously before calling display on a page
|
|
|
|
d1: 'setCharWidthAndBounds', |
|
|
|
fonts.push(font.translated); |
|
|
|
|
|
|
|
} |
|
|
|
// Color
|
|
|
|
} |
|
|
|
CS: 'setStrokeColorSpace', |
|
|
|
} |
|
|
|
cs: 'setFillColorSpace', |
|
|
|
} |
|
|
|
SC: 'setStrokeColor', |
|
|
|
|
|
|
|
SCN: 'setStrokeColorN', |
|
|
|
src += 'this.'; |
|
|
|
sc: 'setFillColor', |
|
|
|
src += fn; |
|
|
|
scn: 'setFillColorN', |
|
|
|
src += '('; |
|
|
|
G: 'setStrokeGray', |
|
|
|
src += args.map(emitArg).join(','); |
|
|
|
g: 'setFillGray', |
|
|
|
src += ');\n'; |
|
|
|
RG: 'setStrokeRGBColor', |
|
|
|
|
|
|
|
rg: 'setFillRGBColor', |
|
|
|
args.length = 0; |
|
|
|
K: 'setStrokeCMYKColor', |
|
|
|
} else { |
|
|
|
k: 'setFillCMYKColor', |
|
|
|
assertWellFormed(args.length <= 33, 'Too many arguments'); |
|
|
|
|
|
|
|
args.push(obj); |
|
|
|
// Shading
|
|
|
|
} |
|
|
|
sh: 'shadingFill', |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Images
|
|
|
|
var fn = Function('objpool', src); |
|
|
|
BI: 'beginInlineImage', |
|
|
|
return function(gfx) { fn.call(gfx, objpool); }; |
|
|
|
|
|
|
|
|
|
|
|
// XObjects
|
|
|
|
|
|
|
|
Do: 'paintXObject', |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Marked content
|
|
|
|
|
|
|
|
MP: 'markPoint', |
|
|
|
|
|
|
|
DP: 'markPointProps', |
|
|
|
|
|
|
|
BMC: 'beginMarkedContent', |
|
|
|
|
|
|
|
BDC: 'beginMarkedContentProps', |
|
|
|
|
|
|
|
EMC: 'endMarkedContent', |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Compatibility
|
|
|
|
|
|
|
|
BX: 'beginCompat', |
|
|
|
|
|
|
|
EX: 'endCompat' |
|
|
|
|
|
|
|
}, |
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
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(); |
|
|
|
}, |
|
|
|
}, |
|
|
|