diff --git a/src/evaluator.js b/src/evaluator.js
index 23c9d1f65..ae443fa81 100644
--- a/src/evaluator.js
+++ b/src/evaluator.js
@@ -112,14 +112,33 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
};
function splitCombinedOperations(operations) {
- // Two operations can be combined together, trying to find which two
+ // Two or more operations can be combined together, trying to find which
// operations were concatenated.
- for (var i = operations.length - 1; i > 0; i--) {
- var op1 = operations.substring(0, i), op2 = operations.substring(i);
- if (op1 in OP_MAP && op2 in OP_MAP)
- return [op1, op2]; // operations found
+ var result = [];
+ var opIndex = 0;
+
+ if (!operations) {
+ return null;
}
- return null;
+
+ while (opIndex < operations.length) {
+ var currentOp = '';
+ for (var op in OP_MAP) {
+ if (op == operations.substr(opIndex, op.length) &&
+ op.length > currentOp.length) {
+ currentOp = op;
+ }
+ }
+
+ if (currentOp.length > 0) {
+ result.push(operations.substr(opIndex, currentOp.length));
+ opIndex += currentOp.length;
+ } else {
+ return null;
+ }
+ }
+
+ return result;
}
PartialEvaluator.prototype = {
@@ -267,14 +286,14 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var patterns = resources.get('Pattern') || new Dict();
var parser = new Parser(new Lexer(stream), false, xref);
var res = resources;
- var hasNextObj = false, nextObj;
+ var hasNextObj = false, nextObjs;
var args = [], obj;
var TILING_PATTERN = 1, SHADING_PATTERN = 2;
while (true) {
if (hasNextObj) {
- obj = nextObj;
- hasNextObj = false;
+ obj = nextObjs.pop();
+ hasNextObj = (nextObjs.length > 0);
} else {
obj = parser.getObj();
if (isEOF(obj))
@@ -290,9 +309,12 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
if (cmds) {
cmd = cmds[0];
fn = OP_MAP[cmd];
- // feeding other command on the next interation
+ // feeding other command on the next iteration
hasNextObj = true;
- nextObj = Cmd.get(cmds[1]);
+ nextObjs = [];
+ for (var idx = 1; idx < cmds.length; idx++) {
+ nextObjs.push(Cmd.get(cmds[idx]));
+ }
}
}
assertWellFormed(fn, 'Unknown command "' + cmd + '"');
diff --git a/test/unit/evaluator_spec.js b/test/unit/evaluator_spec.js
new file mode 100644
index 000000000..4ee0768a7
--- /dev/null
+++ b/test/unit/evaluator_spec.js
@@ -0,0 +1,83 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
+
+'use strict';
+
+describe('evaluator', function() {
+ function XrefMock(queue) {
+ this.queue = queue;
+ }
+ XrefMock.prototype = {
+ fetchIfRef: function() {
+ return this.queue.shift();
+ }
+ };
+ function HandlerMock() {
+ this.inputs = [];
+ }
+ HandlerMock.prototype = {
+ send: function(name, data) {
+ this.inputs({name: name, data: data});
+ }
+ };
+ function ResourcesMock() { }
+ ResourcesMock.prototype = {
+ get: function(name) {
+ return this[name];
+ }
+ };
+
+ describe('splitCombinedOperations', function() {
+ it('should reject unknown operations', function() {
+ var evaluator = new PartialEvaluator(new XrefMock(), new HandlerMock(),
+ 'prefix');
+ var stream = new StringStream('qTT');
+ var thrown = false;
+ try {
+ evaluator.getOperatorList(stream, new ResourcesMock(), []);
+ } catch (e) {
+ thrown = e;
+ }
+ expect(thrown).toNotEqual(false);
+ });
+
+ it('should handle one operations', function() {
+ var evaluator = new PartialEvaluator(new XrefMock(), new HandlerMock(),
+ 'prefix');
+ var stream = new StringStream('Q');
+ var result = evaluator.getOperatorList(stream, new ResourcesMock(), []);
+
+ expect(!!result.fnArray && !!result.argsArray).toEqual(true);
+ expect(result.fnArray.length).toEqual(1);
+ expect(result.fnArray[0]).toEqual('restore');
+ });
+
+ it('should handle two glued operations', function() {
+ var evaluator = new PartialEvaluator(new XrefMock(), new HandlerMock(),
+ 'prefix');
+ var resources = new ResourcesMock();
+ resources.Res1 = {};
+ var stream = new StringStream('/Res1 DoQ');
+ var result = evaluator.getOperatorList(stream, resources, []);
+
+ expect(!!result.fnArray && !!result.argsArray).toEqual(true);
+ expect(result.fnArray.length).toEqual(2);
+ expect(result.fnArray[0]).toEqual('paintXObject');
+ expect(result.fnArray[1]).toEqual('restore');
+ });
+
+ it('should handle tree glued operations', function() {
+ var evaluator = new PartialEvaluator(new XrefMock(), new HandlerMock(),
+ 'prefix');
+ var stream = new StringStream('qqq');
+ var result = evaluator.getOperatorList(stream, new ResourcesMock(), []);
+
+ expect(!!result.fnArray && !!result.argsArray).toEqual(true);
+ expect(result.fnArray.length).toEqual(3);
+ expect(result.fnArray[0]).toEqual('save');
+ expect(result.fnArray[1]).toEqual('save');
+ expect(result.fnArray[2]).toEqual('save');
+ });
+ });
+});
+
diff --git a/test/unit/unit_test.html b/test/unit/unit_test.html
index cdd0c297f..ca0a1aed1 100644
--- a/test/unit/unit_test.html
+++ b/test/unit/unit_test.html
@@ -39,6 +39,7 @@
+