=== modified file 'src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.canvas_renderer.js' --- src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.canvas_renderer.js 2015-12-16 13:35:36 +0000 +++ src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.canvas_renderer.js 2016-01-11 17:33:23 +0000 @@ -20,6 +20,8 @@ ** 005 SBI 20151205 Changed to adjust clipping regions according to a new origin. ** 006 SBI 20151216 Changed to work around that the Chrome's implementation of getImageData ** rounds function parameters. +** SBI 20160111 Rewrite the copy of the target image taking into account the Chrome's +** getImageData implementation. */ "use strict"; @@ -432,15 +434,7 @@ { var w = imageData.width; var h = imageData.height; - var screenShot; - if (p2j.isChrome) - { - screenShot = this.ctx.getImageData(Math.round(x), Math.round(y), w, h); - } - else - { - screenShot = this.ctx.getImageData(x, y, w, h); - } + var screenShot = this.ctx.getImageData(x, y, w, h); var pixelsInBytes = 4 * w * h; for (var i = 0; i < pixelsInBytes; i += 4) { @@ -791,19 +785,79 @@ * Pixels must be returned as non-premultiplied alpha values according to: * http://www.w3.org/TR/2dcontext/#pixel-manipulation */ - var img; + var img = ctx.getImageData(xo, yo, width, height); + var data = img.data; if (p2j.isChrome) { - img = ctx.getImageData(Math.round(xo), Math.round(yo), width, height); + copyImage(img, data, imgData, width, height, imgDataOffset); } else { - img = ctx.getImageData(xo, yo, width, height); - } - var data = img.data; - var pixelsInBytes = width * height * 4; + // optimized version of copy image + var pixelsInBytes = width * height * 4; + var offset = imgDataOffset; + for (var p = 0; p < pixelsInBytes; p += 4, offset += 4) + { + var alpha = imgData[offset + 3]; + var beta = 256 - alpha; + if (alpha == 255) + { + /** server sends non-premultiplied image data */ + data[p] = imgData[offset]; + data[p + 1] = imgData[offset + 1]; + data[p + 2] = imgData[offset + 2]; + data[p + 3] = imgData[offset + 3]; + } + else if (alpha > 0) + { + /** server sends non-premultiplied image data */ + data[p] = (imgData[offset] * alpha + data[p] * beta) >> 8; + data[p + 1] = (imgData[offset + 1] * alpha + data[p + 1] * beta) >> 8; + data[p + 2] = (imgData[offset + 2] * alpha + data[p + 2] * beta) >> 8; + data[p + 3] = (imgData[offset + 3] * alpha + data[p + 3] * beta) >> 8; + }; + }; + } + var deltaX = xa - xo; + var deltaY = ya - yo; + if (this.compositeModeOn) + { + this.applyCompositeMode(img, xo, yo); + } + this.ctx.putImageData(img, xo, yo, deltaX, deltaY, xb - xa, yb - ya); +}; + +/** + * Copies a downloaded image encodded as an rgba byte array provided with its width and its height + * to the screen image given by its own width and height taking into account the coppied image + * alpha channel and places it at the zero coordinates relative to the screen image. + * + * @param {ImageData} img + * The screen image data + * @param {Uint8ClampedArray} data + * The screen image rgba byte array. + * @param {Array} imgData + * The rgba byte array of the coppied image. + * @param {Number} width + * The coppied image width. + * @param {Number} height + * The coppied image height. + * @param {Number} imgDataOffset + * The coppied image data offset from the 0-index of its data array, imgData. + * + * @return {Uint8ClampedArray} + * Returns the modified screen image data array with the target image. + * + */ +function copyImage(img, data, imgData, width, height, imgDataOffset) +{ + var awidth = img.width; + var aheight = img.height; + var x = 0; + var y = 0; + var pixelsInBytes = awidth * aheight * 4; var offset = imgDataOffset; - for (var p = 0; p < pixelsInBytes; p += 4, offset += 4) + for (var p = 0; p < pixelsInBytes; offset += 4) { var alpha = imgData[offset + 3]; var beta = 256 - alpha; @@ -823,14 +877,22 @@ data[p + 2] = (imgData[offset + 2] * alpha + data[p + 2] * beta) >> 8; data[p + 3] = (imgData[offset + 3] * alpha + data[p + 3] * beta) >> 8; }; + x++; + // p = (y * awidth + x) * 4 + // p1 - p0 = [(y1 - y0) * awidth + (x1 - x0)] * 4 = 4 or 4 * (awidth - width) + 4 + if (x == width) + { + y++; + x = 0; + p += ((awidth - width + 1) * 4); + } + else + { + p += 4; + } }; - var deltaX = xa - xo; - var deltaY = ya - yo; - if (this.compositeModeOn) - { - this.applyCompositeMode(img, xo, yo); - } - this.ctx.putImageData(img, xo, yo, deltaX, deltaY, xb - xa, yb - ya); + + return data; }; /**