|
|
|
@ -30,101 +30,104 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
@@ -30,101 +30,104 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|
|
|
|
this.fontIdCounter = 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Specifies properties for each command
|
|
|
|
|
//
|
|
|
|
|
// If variableArgs === true: [0, `numArgs`] expected
|
|
|
|
|
// If variableArgs === false: exactly `numArgs` expected
|
|
|
|
|
var OP_MAP = { |
|
|
|
|
// Graphics state
|
|
|
|
|
w: 'setLineWidth', |
|
|
|
|
J: 'setLineCap', |
|
|
|
|
j: 'setLineJoin', |
|
|
|
|
M: 'setMiterLimit', |
|
|
|
|
d: 'setDash', |
|
|
|
|
ri: 'setRenderingIntent', |
|
|
|
|
i: 'setFlatness', |
|
|
|
|
gs: 'setGState', |
|
|
|
|
q: 'save', |
|
|
|
|
Q: 'restore', |
|
|
|
|
cm: 'transform', |
|
|
|
|
// Graphic state
|
|
|
|
|
w: { fnName: 'setLineWidth', numArgs: 1, variableArgs: false }, |
|
|
|
|
J: { fnName: 'setLineCap', numArgs: 1, variableArgs: false }, |
|
|
|
|
j: { fnName: 'setLineJoin', numArgs: 1, variableArgs: false }, |
|
|
|
|
M: { fnName: 'setMiterLimit', numArgs: 1, variableArgs: false }, |
|
|
|
|
d: { fnName: 'setDash', numArgs: 2, variableArgs: false }, |
|
|
|
|
ri: { fnName: 'setRenderingIntent', numArgs: 1, variableArgs: false }, |
|
|
|
|
i: { fnName: 'setFlatness', numArgs: 1, variableArgs: false }, |
|
|
|
|
gs: { fnName: 'setGState', numArgs: 1, variableArgs: false }, |
|
|
|
|
q: { fnName: 'save', numArgs: 0, variableArgs: false }, |
|
|
|
|
Q: { fnName: 'restore', numArgs: 0, variableArgs: false }, |
|
|
|
|
cm: { fnName: 'transform', numArgs: 6, variableArgs: false }, |
|
|
|
|
|
|
|
|
|
// Path
|
|
|
|
|
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', |
|
|
|
|
m: { fnName: 'moveTo', numArgs: 2, variableArgs: false }, |
|
|
|
|
l: { fnName: 'lineTo', numArgs: 2, variableArgs: false }, |
|
|
|
|
c: { fnName: 'curveTo', numArgs: 6, variableArgs: false }, |
|
|
|
|
v: { fnName: 'curveTo2', numArgs: 4, variableArgs: false }, |
|
|
|
|
y: { fnName: 'curveTo3', numArgs: 4, variableArgs: false }, |
|
|
|
|
h: { fnName: 'closePath', numArgs: 0, variableArgs: false }, |
|
|
|
|
re: { fnName: 'rectangle', numArgs: 4, variableArgs: false }, |
|
|
|
|
S: { fnName: 'stroke', numArgs: 0, variableArgs: false }, |
|
|
|
|
s: { fnName: 'closeStroke', numArgs: 0, variableArgs: false }, |
|
|
|
|
f: { fnName: 'fill', numArgs: 0, variableArgs: false }, |
|
|
|
|
F: { fnName: 'fill', numArgs: 0, variableArgs: false }, |
|
|
|
|
'f*': { fnName: 'eoFill', numArgs: 0, variableArgs: false }, |
|
|
|
|
B: { fnName: 'fillStroke', numArgs: 0, variableArgs: false }, |
|
|
|
|
'B*': { fnName: 'eoFillStroke', numArgs: 0, variableArgs: false }, |
|
|
|
|
b: { fnName: 'closeFillStroke', numArgs: 0, variableArgs: false }, |
|
|
|
|
'b*': { fnName: 'closeEOFillStroke', numArgs: 0, variableArgs: false }, |
|
|
|
|
n: { fnName: 'endPath', numArgs: 0, variableArgs: false }, |
|
|
|
|
|
|
|
|
|
// Clipping
|
|
|
|
|
W: 'clip', |
|
|
|
|
'W*': 'eoClip', |
|
|
|
|
W: { fnName: 'clip', numArgs: 0, variableArgs: false }, |
|
|
|
|
'W*': { fnName: 'eoClip', numArgs: 0, variableArgs: false }, |
|
|
|
|
|
|
|
|
|
// 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', |
|
|
|
|
BT: { fnName: 'beginText', numArgs: 0, variableArgs: false }, |
|
|
|
|
ET: { fnName: 'endText', numArgs: 0, variableArgs: false }, |
|
|
|
|
Tc: { fnName: 'setCharSpacing', numArgs: 1, variableArgs: false }, |
|
|
|
|
Tw: { fnName: 'setWordSpacing', numArgs: 1, variableArgs: false }, |
|
|
|
|
Tz: { fnName: 'setHScale', numArgs: 1, variableArgs: false }, |
|
|
|
|
TL: { fnName: 'setLeading', numArgs: 1, variableArgs: false }, |
|
|
|
|
Tf: { fnName: 'setFont', numArgs: 2, variableArgs: false }, |
|
|
|
|
Tr: { fnName: 'setTextRenderingMode', numArgs: 1, variableArgs: false }, |
|
|
|
|
Ts: { fnName: 'setTextRise', numArgs: 1, variableArgs: false }, |
|
|
|
|
Td: { fnName: 'moveText', numArgs: 2, variableArgs: false }, |
|
|
|
|
TD: { fnName: 'setLeadingMoveText', numArgs: 2, variableArgs: false }, |
|
|
|
|
Tm: { fnName: 'setTextMatrix', numArgs: 6, variableArgs: false }, |
|
|
|
|
'T*': { fnName: 'nextLine', numArgs: 0, variableArgs: false }, |
|
|
|
|
Tj: { fnName: 'showText', numArgs: 1, variableArgs: false }, |
|
|
|
|
TJ: { fnName: 'showSpacedText', numArgs: 1, variableArgs: false }, |
|
|
|
|
'\'': { fnName: 'nextLineShowText', numArgs: 1, variableArgs: false }, |
|
|
|
|
'"': { fnName: 'nextLineSetSpacingShowText', numArgs: 3, |
|
|
|
|
variableArgs: false }, |
|
|
|
|
|
|
|
|
|
// Type3 fonts
|
|
|
|
|
d0: 'setCharWidth', |
|
|
|
|
d1: 'setCharWidthAndBounds', |
|
|
|
|
d0: { fnName: 'setCharWidth', numArgs: 2, variableArgs: false }, |
|
|
|
|
d1: { fnName: 'setCharWidthAndBounds', numArgs: 6, variableArgs: false }, |
|
|
|
|
|
|
|
|
|
// 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', |
|
|
|
|
CS: { fnName: 'setStrokeColorSpace', numArgs: 1, variableArgs: false }, |
|
|
|
|
cs: { fnName: 'setFillColorSpace', numArgs: 1, variableArgs: false }, |
|
|
|
|
SC: { fnName: 'setStrokeColor', numArgs: 4, variableArgs: true }, |
|
|
|
|
SCN: { fnName: 'setStrokeColorN', numArgs: 33, variableArgs: true }, |
|
|
|
|
sc: { fnName: 'setFillColor', numArgs: 4, variableArgs: true }, |
|
|
|
|
scn: { fnName: 'setFillColorN', numArgs: 33, variableArgs: true }, |
|
|
|
|
G: { fnName: 'setStrokeGray', numArgs: 1, variableArgs: false }, |
|
|
|
|
g: { fnName: 'setFillGray', numArgs: 1, variableArgs: false }, |
|
|
|
|
RG: { fnName: 'setStrokeRGBColor', numArgs: 3, variableArgs: false }, |
|
|
|
|
rg: { fnName: 'setFillRGBColor', numArgs: 3, variableArgs: false }, |
|
|
|
|
K: { fnName: 'setStrokeCMYKColor', numArgs: 4, variableArgs: false }, |
|
|
|
|
k: { fnName: 'setFillCMYKColor', numArgs: 4, variableArgs: false }, |
|
|
|
|
|
|
|
|
|
// Shading
|
|
|
|
|
sh: 'shadingFill', |
|
|
|
|
sh: { fnName: 'shadingFill', numArgs: 1, variableArgs: false }, |
|
|
|
|
|
|
|
|
|
// Images
|
|
|
|
|
BI: 'beginInlineImage', |
|
|
|
|
ID: 'beginImageData', |
|
|
|
|
EI: 'endInlineImage', |
|
|
|
|
BI: { fnName: 'beginInlineImage', numArgs: 0, variableArgs: false }, |
|
|
|
|
ID: { fnName: 'beginImageData', numArgs: 0, variableArgs: false }, |
|
|
|
|
EI: { fnName: 'endInlineImage', numArgs: 0, variableArgs: false }, |
|
|
|
|
|
|
|
|
|
// XObjects
|
|
|
|
|
Do: 'paintXObject', |
|
|
|
|
|
|
|
|
|
// Marked content
|
|
|
|
|
MP: 'markPoint', |
|
|
|
|
DP: 'markPointProps', |
|
|
|
|
BMC: 'beginMarkedContent', |
|
|
|
|
BDC: 'beginMarkedContentProps', |
|
|
|
|
EMC: 'endMarkedContent', |
|
|
|
|
Do: { fnName: 'paintXObject', numArgs: 1, variableArgs: false }, |
|
|
|
|
MP: { fnName: 'markPoint', numArgs: 1, variableArgs: false }, |
|
|
|
|
DP: { fnName: 'markPointProps', numArgs: 2, variableArgs: false }, |
|
|
|
|
BMC: { fnName: 'beginMarkedContent', numArgs: 1, variableArgs: false }, |
|
|
|
|
BDC: { fnName: 'beginMarkedContentProps', numArgs: 2, variableArgs: false }, |
|
|
|
|
EMC: { fnName: 'endMarkedContent', numArgs: 0, variableArgs: false }, |
|
|
|
|
|
|
|
|
|
// Compatibility
|
|
|
|
|
BX: 'beginCompat', |
|
|
|
|
EX: 'endCompat', |
|
|
|
|
BX: { fnName: 'beginCompat', numArgs: 0, variableArgs: false }, |
|
|
|
|
EX: { fnName: 'endCompat', numArgs: 0, variableArgs: false }, |
|
|
|
|
|
|
|
|
|
// (reserved partial commands for the lexer)
|
|
|
|
|
BM: null, |
|
|
|
@ -314,6 +317,8 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
@@ -314,6 +317,8 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|
|
|
|
resources = resources || new Dict(); |
|
|
|
|
var xobjs = resources.get('XObject') || new Dict(); |
|
|
|
|
var patterns = resources.get('Pattern') || new Dict(); |
|
|
|
|
// TODO(mduan): pass array of knownCommands rather than OP_MAP
|
|
|
|
|
// dictionary
|
|
|
|
|
var parser = new Parser(new Lexer(stream, OP_MAP), false, xref); |
|
|
|
|
var res = resources; |
|
|
|
|
var args = [], obj; |
|
|
|
@ -321,13 +326,42 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
@@ -321,13 +326,42 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|
|
|
|
|
|
|
|
|
while (true) { |
|
|
|
|
obj = parser.getObj(); |
|
|
|
|
if (isEOF(obj)) |
|
|
|
|
if (isEOF(obj)) { |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (isCmd(obj)) { |
|
|
|
|
var cmd = obj.cmd; |
|
|
|
|
var fn = OP_MAP[cmd]; |
|
|
|
|
assertWellFormed(fn, 'Unknown command "' + cmd + '"'); |
|
|
|
|
|
|
|
|
|
// Check that the command is valid
|
|
|
|
|
var opSpec = OP_MAP[cmd]; |
|
|
|
|
if (!opSpec) { |
|
|
|
|
warn('Unknown command "' + cmd + '"'); |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var fn = opSpec.fnName; |
|
|
|
|
|
|
|
|
|
// Validate the number of arguments for the command
|
|
|
|
|
if (opSpec.variableArgs) { |
|
|
|
|
if (args.length > opSpec.numArgs) { |
|
|
|
|
info('Command ' + fn + ': expected [0,' + opSpec.numArgs + |
|
|
|
|
'] args, but received ' + args.length + ' args'); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
if (args.length < opSpec.numArgs) { |
|
|
|
|
// If we receive too few args, it's not possible to possible
|
|
|
|
|
// to execute the command, so skip the command
|
|
|
|
|
info('Command ' + fn + ': because expected ' + opSpec.numArgs + |
|
|
|
|
' args, but received ' + args.length + ' args; skipping'); |
|
|
|
|
args = []; |
|
|
|
|
continue; |
|
|
|
|
} else if (args.length > opSpec.numArgs) { |
|
|
|
|
info('Command ' + fn + ': expected ' + opSpec.numArgs + |
|
|
|
|
' args, but received ' + args.length + ' args'); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// TODO figure out how to type-check vararg functions
|
|
|
|
|
|
|
|
|
|
if ((cmd == 'SCN' || cmd == 'scn') && !args[args.length - 1].code) { |
|
|
|
@ -509,8 +543,8 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
@@ -509,8 +543,8 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|
|
|
|
argsArray.push(args); |
|
|
|
|
args = []; |
|
|
|
|
} else if (obj != null) { |
|
|
|
|
assertWellFormed(args.length <= 33, 'Too many arguments'); |
|
|
|
|
args.push(obj instanceof Dict ? obj.getAll() : obj); |
|
|
|
|
assertWellFormed(args.length <= 33, 'Too many arguments'); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|