From 78b08d8f68abc65c889c81046b3328dd57747588 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Mon, 27 Feb 2012 11:20:25 -0800 Subject: [PATCH] Implement raster operations as transfer functions, rename setChannelMask to setCompositeOperation, supporting both channel masks and binary raster operations. --- src/main/resources/layer.js | 68 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 60 insertions(+), 8 deletions(-) diff --git a/src/main/resources/layer.js b/src/main/resources/layer.js index a38ffe8..790fd01 100644 --- a/src/main/resources/layer.js +++ b/src/main/resources/layer.js @@ -75,6 +75,12 @@ Guacamole.Layer = function(width, height) { displayContext.save(); /** + * The function to apply when drawing arbitrary source pixels over + * destination pixels. + */ + var transferFunction = null; + + /** * The queue of all pending Tasks. Tasks will be run in order, with new * tasks added at the end of the queue and old tasks removed from the * front of the queue (FIFO). @@ -107,6 +113,36 @@ Guacamole.Layer = function(width, height) { }; /** + * Map of all Guacamole binary raster operations to transfer functions. + * @private + */ + var binaryCompositeTransferFunction = { + + 0x10: function (src, dst) { return 0x00; }, /* BLACK */ + 0x1F: function (src, dst) { return 0xFF; }, /* WHITE */ + + 0x13: function (src, dst) { return src; }, /* SRC */ + 0x15: function (src, dst) { return dst; }, /* DEST */ + 0x1C: function (src, dst) { return ~src; }, /* NSRC */ + 0x1A: function (src, dst) { return ~dst; }, /* NDEST */ + + 0x11: function (src, dst) { return src & dst; }, /* AND */ + 0x1E: function (src, dst) { return ~(src & dst); }, /* NAND */ + + 0x17: function (src, dst) { return src | dst; }, /* OR */ + 0x18: function (src, dst) { return ~(src | dst); }, /* NOR */ + + 0x16: function (src, dst) { return src ^ dst; }, /* XOR */ + 0x19: function (src, dst) { return ~(src ^ dst); }, /* XNOR */ + + 0x14: function (src, dst) { return ~src & dst; }, /* AND inverted source */ + 0x1D: function (src, dst) { return ~src | dst; }, /* OR inverted source */ + 0x12: function (src, dst) { return src & ~dst; }, /* AND inverted destination */ + 0x1B: function (src, dst) { return src | ~dst; } /* OR inverted destination */ + + }; + + /** * Resizes the canvas element backing this Layer without testing the * new size. This function should only be used internally. * @@ -547,19 +583,35 @@ Guacamole.Layer = function(width, height) { }; /** - * Sets the channel mask for future operations on this Layer. The channel - * mask is a Guacamole-specific compositing operation identifier with a - * single bit representing each of four channels (in order): source image - * where destination transparent, source where destination opaque, + * Sets the composite operation for future operations on this Layer. This + * operation is either a channel mask, or the ID of a binary raster + * operation. + * + * The channel mask is a Guacamole-specific compositing operation identifier + * with a single bit representing each of four channels (in order): source + * image where destination transparent, source where destination opaque, * destination where source transparent, and destination where source * opaque. * - * @param {Number} mask The channel mask for future operations on this - * Layer. + * @param {Number} operation The composite operation (channel mask or binary + * raster operation) for future operations on this + * Layer. */ - this.setChannelMask = function(mask) { + this.setCompositeOperation = function(operation) { scheduleTask(function() { - displayContext.globalCompositeOperation = compositeOperation[mask]; + + // If channel mask, set composite operation only + if (operation <= 0xF) { + displayContext.globalCompositeOperation = compositeOperation[operation]; + transferFunction = null; + } + + // Otherwise, set binary raster operation + else { + displayContext.globalCompositeOperation = "source-over"; + transferFunction = binaryCompositeTransferFunction[operation]; + } + }); }; -- 1.7.10.4