Refactor rect, rename copyRect -> copy, add several necessary operations, remove...
authorMichael Jumper <zhangmaike@users.sourceforge.net>
Mon, 12 Mar 2012 03:16:36 +0000 (20:16 -0700)
committerMichael Jumper <zhangmaike@users.sourceforge.net>
Mon, 12 Mar 2012 03:16:36 +0000 (20:16 -0700)
src/main/resources/guacamole.js
src/main/resources/layer.js

index 88f4dba..0cbf024 100644 (file)
@@ -378,7 +378,7 @@ Guacamole.Client = function(tunnel) {
 
             dstL.setChannelMask(channelMask);
 
 
             dstL.setChannelMask(channelMask);
 
-            dstL.copyRect(
+            dstL.copy(
                 srcL,
                 srcX,
                 srcY,
                 srcL,
                 srcX,
                 srcY,
@@ -417,35 +417,21 @@ Guacamole.Client = function(tunnel) {
 
         "rect": function(parameters) {
 
 
         "rect": function(parameters) {
 
-            var channelMask = parseInt(parameters[0]);
-            var layer = getLayer(parseInt(parameters[1]));
-            var x = parseInt(parameters[2]);
-            var y = parseInt(parameters[3]);
-            var w = parseInt(parameters[4]);
-            var h = parseInt(parameters[5]);
-            var r = parseInt(parameters[6]);
-            var g = parseInt(parameters[7]);
-            var b = parseInt(parameters[8]);
-            var a = parseInt(parameters[9]);
-
-            layer.setChannelMask(channelMask);
+            var layer = getLayer(parseInt(parameters[0]));
+            var x = parseInt(parameters[1]);
+            var y = parseInt(parameters[2]);
+            var w = parseInt(parameters[3]);
+            var h = parseInt(parameters[4]);
 
 
-            layer.drawRect(
-                x, y, w, h,
-                r, g, b, a
-            );
+            layer.rect(x, y, w, h);
 
         },
 
         "clip": function(parameters) {
 
             var layer = getLayer(parseInt(parameters[0]));
 
         },
 
         "clip": function(parameters) {
 
             var layer = getLayer(parseInt(parameters[0]));
-            var x = parseInt(parameters[1]);
-            var y = parseInt(parameters[2]);
-            var w = parseInt(parameters[3]);
-            var h = parseInt(parameters[4]);
 
 
-            layer.clipRect(x, y, w, h);
+            layer.clip();
 
         },
 
 
         },
 
index 709d3ae..faac6ff 100644 (file)
@@ -72,7 +72,6 @@ Guacamole.Layer = function(width, height) {
      * @private
      */
     var displayContext = display.getContext("2d");
      * @private
      */
     var displayContext = display.getContext("2d");
-    displayContext.save();
 
     /**
      * The queue of all pending Tasks. Tasks will be run in order, with new
 
     /**
      * The queue of all pending Tasks. Tasks will be run in order, with new
@@ -83,6 +82,17 @@ Guacamole.Layer = function(width, height) {
     var tasks = new Array();
 
     /**
     var tasks = new Array();
 
     /**
+     * Whether a new path should be started with the next path drawing
+     * operations.
+     */
+    var pathClosed = true;
+
+    /**
+     * The number of states on the state stack.
+     */
+    var stackSize = 0;
+
+    /**
      * Map of all Guacamole channel masks to HTML5 canvas composite operation
      * names. Not all channel mask combinations are currently implemented.
      * @private
      * Map of all Guacamole channel masks to HTML5 canvas composite operation
      * names. Not all channel mask combinations are currently implemented.
      * @private
@@ -518,12 +528,12 @@ Guacamole.Layer = function(width, height) {
      * @param {Number} x The destination X coordinate.
      * @param {Number} y The destination Y coordinate.
      */
      * @param {Number} x The destination X coordinate.
      * @param {Number} y The destination Y coordinate.
      */
-    this.copyRect = function(srcLayer, srcx, srcy, srcw, srch, x, y) {
+    this.copy = function(srcLayer, srcx, srcy, srcw, srch, x, y) {
 
         var drawComplete = false;
         var srcLock = null;
 
 
         var drawComplete = false;
         var srcLock = null;
 
-        function doCopyRect() {
+        function doCopy() {
             if (layer.autosize != 0) fitRect(x, y, srcw, srch);
 
             var srcCanvas = srcLayer.getCanvas();
             if (layer.autosize != 0) fitRect(x, y, srcw, srch);
 
             var srcCanvas = srcLayer.getCanvas();
@@ -541,13 +551,13 @@ Guacamole.Layer = function(width, height) {
         // If we ARE the source layer, no need to sync.
         // Syncing would result in deadlock.
         if (layer === srcLayer)
         // If we ARE the source layer, no need to sync.
         // Syncing would result in deadlock.
         if (layer === srcLayer)
-            scheduleTask(doCopyRect);
+            scheduleTask(doCopy);
 
         // Otherwise synchronize copy operation with source layer
         else {
             
             // Currently blocked draw task
 
         // Otherwise synchronize copy operation with source layer
         else {
             
             // Currently blocked draw task
-            var task = scheduleTask(doCopyRect, true);
+            var task = scheduleTask(doCopy, true);
 
             // Unblock draw task once source layer is ready
             srcLayer.sync(task.unblock);
 
             // Unblock draw task once source layer is ready
             srcLayer.sync(task.unblock);
@@ -565,24 +575,32 @@ Guacamole.Layer = function(width, height) {
     };
 
     /**
     };
 
     /**
-     * Clear the specified rectangle of image data.
+     * Add the specified cubic bezier point to the current path.
      * 
      * 
-     * @param {Number} x The X coordinate of the upper-left corner of the
-     *                   rectangle to clear.
-     * @param {Number} y The Y coordinate of the upper-left corner of the
-     *                   rectangle to clear.
-     * @param {Number} w The width of the rectangle to clear.
-     * @param {Number} h The height of the rectangle to clear.
+     * @param {Number} x The X coordinate of the point to draw.
+     * @param {Number} y The Y coordinate of the point to draw.
+     * @param {Number} cp1x The X coordinate of the first control point.
+     * @param {Number} cp1y The Y coordinate of the first control point.
+     * @param {Number} cp2x The X coordinate of the second control point.
+     * @param {Number} cp2y The Y coordinate of the second control point.
      */
      */
-    this.clearRect = function(x, y, w, h) {
+    this.path = function(x, y, cp1x, cp1y, cp2x, cp2y) {
         scheduleTask(function() {
         scheduleTask(function() {
-            if (layer.autosize != 0) fitRect(x, y, w, h);
-            displayContext.clearRect(x, y, w, h);
+            
+            // Start a new path if current path is closed
+            if (pathClosed) {
+                displayContext.beginPath();
+                pathClosed = false;
+            }
+            
+            if (layer.autosize != 0) fitRect(x, y, 0, 0);
+            displayContext.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, y);
+            
         });
     };
 
     /**
         });
     };
 
     /**
-     * Fill the specified rectangle of image data with the specified color.
+     * Add the specified rectangle to the current path.
      * 
      * @param {Number} x The X coordinate of the upper-left corner of the
      *                   rectangle to draw.
      * 
      * @param {Number} x The X coordinate of the upper-left corner of the
      *                   rectangle to draw.
@@ -590,64 +608,141 @@ Guacamole.Layer = function(width, height) {
      *                   rectangle to draw.
      * @param {Number} w The width of the rectangle to draw.
      * @param {Number} h The height of the rectangle to draw.
      *                   rectangle to draw.
      * @param {Number} w The width of the rectangle to draw.
      * @param {Number} h The height of the rectangle to draw.
-     * @param {Number} r The red component of the color of the rectangle.
-     * @param {Number} g The green component of the color of the rectangle.
-     * @param {Number} b The blue component of the color of the rectangle.
-     * @param {Number} a The alpha component of the color of the rectangle.
      */
      */
-    this.drawRect = function(x, y, w, h, r, g, b, a) {
+    this.rect = function(x, y, w, h) {
         scheduleTask(function() {
         scheduleTask(function() {
+            
+            // Start a new path if current path is closed
+            if (pathClosed) {
+                displayContext.beginPath();
+                pathClosed = false;
+            }
+            
             if (layer.autosize != 0) fitRect(x, y, w, h);
             if (layer.autosize != 0) fitRect(x, y, w, h);
-            displayContext.fillStyle = "rgba("
-                        + r + "," + g + "," + b + "," + a / 255 + ")";
-            displayContext.fillRect(x, y, w, h);
+            displayContext.rect(x, y, w, h);
+            
         });
     };
 
     /**
         });
     };
 
     /**
-     * Clip all future drawing operations by the specified rectangle.
+     * Clip all future drawing operations by the current path. The current path
+     * is implicitly closed. The current path can continue to be reused
+     * for other operations (such as fillColor()) but a new path will be started
+     * once a path drawing operation (path() or rect()) is used.
+     */
+    this.clip = function() {
+        scheduleTask(function() {
+
+            // Set new clipping region
+            displayContext.clip();
+
+            // Path now implicitly closed
+            pathClosed = true;
+
+        });
+    };
+
+    /**
+     * Stroke the current path with the specified color. The current path
+     * is implicitly closed. The current path can continue to be reused
+     * for other operations (such as clip()) but a new path will be started
+     * once a path drawing operation (path() or rect()) is used.
      * 
      * 
-     * @param {Number} x The X coordinate of the upper-left corner of the
-     *                   rectangle to use for the clipping region.
-     * @param {Number} y The Y coordinate of the upper-left corner of the
-     *                   rectangle to use for the clipping region.
-     * @param {Number} w The width of the rectangle to use for the clipping region.
-     * @param {Number} h The height of the rectangle to use for the clipping region.
+     * @param {Number} r The red component of the color to fill.
+     * @param {Number} g The green component of the color to fill.
+     * @param {Number} b The blue component of the color to fill.
+     * @param {Number} a The alpha component of the color to fill.
      */
      */
-    this.clipRect = function(x, y, w, h) {
+    this.strokeColor = function(r, g, b, a) {
         scheduleTask(function() {
 
         scheduleTask(function() {
 
-            // Clear any current clipping region
-            displayContext.restore();
+            // Stroke with color
+            displayContext.strokeStyle = "rgba(" + r + "," + g + "," + b + "," + a/255.0 + ")";
+            displayContext.stroke();
+
+            // Path now implicitly closed
+            pathClosed = true;
+
+        });
+    };
+
+
+    /**
+     * Fills the current path with the specified color. The current path
+     * is implicitly closed. The current path can continue to be reused
+     * for other operations (such as clip()) but a new path will be started
+     * once a path drawing operation (path() or rect()) is used.
+     * 
+     * @param {Number} r The red component of the color to fill.
+     * @param {Number} g The green component of the color to fill.
+     * @param {Number} b The blue component of the color to fill.
+     * @param {Number} a The alpha component of the color to fill.
+     */
+    this.fillColor = function(r, g, b, a) {
+        scheduleTask(function() {
+
+            // Fill with color
+            displayContext.fillStyle = "rgba(" + r + "," + g + "," + b + "," + a/255.0 + ")";
+            displayContext.fill();
+
+            // Path now implicitly closed
+            pathClosed = true;
+
+        });
+    };
+
+    /**
+     * Push current layer state onto stack.
+     */
+    this.push = function() {
+        scheduleTask(function() {
+
+            // Save current state onto stack
             displayContext.save();
             displayContext.save();
+            stackSize++;
 
 
-            if (layer.autosize != 0) fitRect(x, y, w, h);
+        });
+    };
 
 
-            // Set new clipping region
-            displayContext.beginPath();
-            displayContext.rect(x, y, w, h);
-            displayContext.clip();
+    /**
+     * Pop layer state off stack.
+     */
+    this.pop = function() {
+        scheduleTask(function() {
+
+            // Restore current state from stack
+            if (stackSize > 0) {
+                displayContext.restore();
+                stackSize--;
+            }
 
         });
     };
 
     /**
 
         });
     };
 
     /**
-     * Provides the given filtering function with a writable snapshot of
-     * image data and the current width and height of the Layer.
-     * 
-     * @param {function} filter A function which accepts an array of image
-     *                          data (as returned by the canvas element's
-     *                          display context's getImageData() function),
-     *                          the width of the Layer, and the height of the
-     *                          Layer as parameters, in that order. This
-     *                          function must accomplish its filtering by
-     *                          modifying the given image data array directly.
-     */
-    this.filter = function(filter) {
+     * Reset the layer, clearing the stack, the current path, and any transform
+     * matrix.
+     */
+    this.reset = function() {
         scheduleTask(function() {
         scheduleTask(function() {
-            var imageData = displayContext.getImageData(0, 0, width, height);
-            filter(imageData.data, width, height);
-            displayContext.putImageData(imageData, 0, 0);
+
+            // Clear stack
+            while (stackSize > 0) {
+                displaycontext.restore();
+                stackSize--;
+            }
+
+            // Clear transform
+            displayContext.setTransform(
+                1, 0, 0,
+                0, 1, 0
+              /*0, 0, 1*/
+            );
+
+            // Clear path
+            displayContext.beginPath();
+            pathClosed = false;
+
         });
     };
 
         });
     };