From 8dbe1f4927e85219f39966a39573c94b380b63b8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=BCrg=20Lehni?= <juerg@scratchdisk.com>
Date: Wed, 8 May 2013 18:17:23 -0700
Subject: [PATCH] Fix issues with running paper.js in node.

We need to export the Object and Array definition into new context, to make Base.isPlainObject() work. See http://nodejs.org/api/vm.html#vm_globals
---
 src/node/index.js    | 49 +++++++++++++++++++++++++-------------------
 src/ui/CanvasView.js | 16 +++++++--------
 2 files changed, 36 insertions(+), 29 deletions(-)

diff --git a/src/node/index.js b/src/node/index.js
index 65bfbc42..520442f3 100644
--- a/src/node/index.js
+++ b/src/node/index.js
@@ -13,10 +13,17 @@
 var fs = require('fs'),
 	vm = require('vm'),
 	path = require('path'),
+	// Node Canvas library: https://github.com/learnboost/node-canvas
 	Canvas = require('canvas'),
-	jsdom = require('jsdom');
+	jsdom = require('jsdom'),
+	dirname = path.resolve(__dirname, '..');
 
-__dirname = path.resolve(__dirname, '..');
+var options = {
+	server: true,
+	svg: true,
+	parser: 'acorn',
+	version: 'dev'
+};
 
 // Create a window and document using jsdom, e.g. for exportSVG()
 var win = jsdom.createWindow(),
@@ -24,14 +31,12 @@ var win = jsdom.createWindow(),
 
 // Create the context within which we will run the source files:
 var context = vm.createContext({
-	options: {
-		server: true,
-		svg: true,
-		parser: 'acorn',
-		version: 'dev'
-	},
+	options: options,
 	fs: fs,
-	// Node Canvas library: https://github.com/learnboost/node-canvas
+	// We need to export the local Object definition, so Base.isPlainObject()
+	// works. See http://nodejs.org/api/vm.html#vm_globals
+	Object: Object,
+	Array: Array,
 	Canvas: Canvas,
 	HTMLCanvasElement: Canvas,
 	Image: Canvas.Image,
@@ -41,17 +46,16 @@ var context = vm.createContext({
     navigator: win.navigator,
     console: console,
 	require: require,
-	__dirname: __dirname,
-	__filename: __filename,
+	__dirname: dirname,
 	// Used to load and run source files within the same context:
 	include: function(uri) {
-		var source = fs.readFileSync(path.resolve(__dirname, uri), 'utf8');
-		// For relative includes, we save the current directory and then
-		// add the uri directory to __dirname:
-		var oldDirname = __dirname;
-		__dirname = path.resolve(__dirname, path.dirname(uri));
+		var source = fs.readFileSync(path.resolve(dirname, uri), 'utf8'),
+			// For relative includes, we save the current directory and then
+			// add the uri directory to dirname:
+			prevDirname = dirname;
+		dirname = path.resolve(dirname, path.dirname(uri));
 		vm.runInContext(source, context, uri);
-		__dirname = oldDirname;
+		dirname = prevDirname;
 	}
 });
 
@@ -63,15 +67,18 @@ context.Base.each(context, function(val, key) {
 	if (val && val.prototype instanceof context.Base)
 		context.PaperScope.prototype[key] = val;
 });
-context.PaperScope.prototype['Canvas'] = context.Canvas;
+context.PaperScope.prototype.Canvas = Canvas;
 
 require.extensions['.pjs'] = function(module, uri) {
 	var source = context.PaperScript.compile(fs.readFileSync(uri, 'utf8'));
-	var envVars = 'var __dirname = \'' + path.dirname(uri) + '\';' + 
-				 'var __filename = \'' + uri + '\';';
-	vm.runInContext(envVars, context);
+	var prevDirname = context.__dirname,
+		prevFilename = context.__filename;
+	context.__dirname = path.dirname(uri);
+	context.__filename = uri;
 	var scope = new context.PaperScope();
 	context.PaperScript.evaluate(source, scope);
+	context.__dirname = prevDirname;
+	context.__filename = prevFilename;
 	module.exports = scope;
 };
 
diff --git a/src/ui/CanvasView.js b/src/ui/CanvasView.js
index 37b1649d..077f2b1e 100644
--- a/src/ui/CanvasView.js
+++ b/src/ui/CanvasView.js
@@ -172,7 +172,6 @@ var CanvasView = View.extend(/** @lends CanvasView# */{
 /*#*/ if (options.server) {
 // Node.js server based image exporting code.
 CanvasView.inject(new function() {
-	var path = require('path');
 	// Utility function that converts a number to a string with
 	// x amount of padded 0 digits:
 	function toPaddedString(number, length) {
@@ -196,7 +195,8 @@ CanvasView.inject(new function() {
 			var view = this,
 				count = 0,
 				frameDuration = 1 / param.fps,
-				lastTime = startTime = Date.now();
+				startTime = Date.now(),
+				lastTime = startTime;
 
 			// Start exporting frames by exporting the first frame:
 			exportFrame(param);
@@ -204,8 +204,8 @@ CanvasView.inject(new function() {
 			function exportFrame(param) {
 				count++;
 				var filename = param.prefix + toPaddedString(count, 6) + '.png',
-					uri = param.directory + '/' + filename;
-				var out = view.exportImage(uri, function() {
+					path = param.directory + '/' + filename;
+				var out = view.exportImage(path, function() {
 					// When the file has been closed, export the next fame:
 					var then = Date.now();
 					if (param.onProgress) {
@@ -237,11 +237,11 @@ CanvasView.inject(new function() {
 				}
 			}
 		},
-		// DOCS: View#exportImage(uri, callback);
-		exportImage: function(uri, callback) {
+
+		// DOCS: View#exportImage(path, callback);
+		exportImage: function(path, callback) {
 			this.draw();
-			// TODO: is it necessary to resolve the path?
-			var out = fs.createWriteStream(path.resolve(__dirname, uri)),
+			var out = fs.createWriteStream(path),
 				stream = this._element.createPNGStream();
 			// Pipe the png stream to the write stream:
 			stream.pipe(out);