mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-08 06:01:22 +00:00
GUACAMOLE-187: Merge layer resize optimizations.
This commit is contained in:
@@ -42,6 +42,17 @@ Guacamole.Layer = function(width, height) {
|
|||||||
*/
|
*/
|
||||||
var layer = this;
|
var layer = this;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of pixels the width or height of a layer must change before
|
||||||
|
* the underlying canvas is resized. The underlying canvas will be kept at
|
||||||
|
* dimensions which are integer multiples of this factor.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @constant
|
||||||
|
* @type Number
|
||||||
|
*/
|
||||||
|
var CANVAS_SIZE_FACTOR = 64;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The canvas element backing this Layer.
|
* The canvas element backing this Layer.
|
||||||
* @private
|
* @private
|
||||||
@@ -55,6 +66,16 @@ Guacamole.Layer = function(width, height) {
|
|||||||
var context = canvas.getContext("2d");
|
var context = canvas.getContext("2d");
|
||||||
context.save();
|
context.save();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the layer has not yet been drawn to. Once any draw operation
|
||||||
|
* which affects the underlying canvas is invoked, this flag will be set to
|
||||||
|
* false.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @type Boolean
|
||||||
|
*/
|
||||||
|
var empty = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether a new path should be started with the next path drawing
|
* Whether a new path should be started with the next path drawing
|
||||||
* operations.
|
* operations.
|
||||||
@@ -98,57 +119,78 @@ Guacamole.Layer = function(width, height) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resizes the canvas element backing this Layer without testing the
|
* Resizes the canvas element backing this Layer. This function should only
|
||||||
* new size. This function should only be used internally.
|
* be used internally.
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
* @param {Number} newWidth The new width to assign to this Layer.
|
* @param {Number} [newWidth=0]
|
||||||
* @param {Number} newHeight The new height to assign to this Layer.
|
* The new width to assign to this Layer.
|
||||||
|
*
|
||||||
|
* @param {Number} [newHeight=0]
|
||||||
|
* The new height to assign to this Layer.
|
||||||
*/
|
*/
|
||||||
function resize(newWidth, newHeight) {
|
var resize = function resize(newWidth, newHeight) {
|
||||||
|
|
||||||
// Only preserve old data if width/height are both non-zero
|
// Default size to zero
|
||||||
var oldData = null;
|
newWidth = newWidth || 0;
|
||||||
if (layer.width !== 0 && layer.height !== 0) {
|
newHeight = newHeight || 0;
|
||||||
|
|
||||||
// Create canvas and context for holding old data
|
// Calculate new dimensions of internal canvas
|
||||||
oldData = document.createElement("canvas");
|
var canvasWidth = Math.ceil(newWidth / CANVAS_SIZE_FACTOR) * CANVAS_SIZE_FACTOR;
|
||||||
oldData.width = layer.width;
|
var canvasHeight = Math.ceil(newHeight / CANVAS_SIZE_FACTOR) * CANVAS_SIZE_FACTOR;
|
||||||
oldData.height = layer.height;
|
|
||||||
|
|
||||||
var oldDataContext = oldData.getContext("2d");
|
// Resize only if canvas dimensions are actually changing
|
||||||
|
if (canvas.width !== canvasWidth || canvas.height !== canvasHeight) {
|
||||||
|
|
||||||
// Copy image data from current
|
// Copy old data only if relevant and non-empty
|
||||||
oldDataContext.drawImage(canvas,
|
var oldData = null;
|
||||||
0, 0, layer.width, layer.height,
|
if (!empty && canvas.width !== 0 && canvas.height !== 0) {
|
||||||
0, 0, layer.width, layer.height);
|
|
||||||
|
// Create canvas and context for holding old data
|
||||||
|
oldData = document.createElement("canvas");
|
||||||
|
oldData.width = Math.min(layer.width, newWidth);
|
||||||
|
oldData.height = Math.min(layer.height, newHeight);
|
||||||
|
|
||||||
|
var oldDataContext = oldData.getContext("2d");
|
||||||
|
|
||||||
|
// Copy image data from current
|
||||||
|
oldDataContext.drawImage(canvas,
|
||||||
|
0, 0, oldData.width, oldData.height,
|
||||||
|
0, 0, oldData.width, oldData.height);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preserve composite operation
|
||||||
|
var oldCompositeOperation = context.globalCompositeOperation;
|
||||||
|
|
||||||
|
// Resize canvas
|
||||||
|
canvas.width = canvasWidth;
|
||||||
|
canvas.height = canvasHeight;
|
||||||
|
|
||||||
|
// Redraw old data, if any
|
||||||
|
if (oldData)
|
||||||
|
context.drawImage(oldData,
|
||||||
|
0, 0, oldData.width, oldData.height,
|
||||||
|
0, 0, oldData.width, oldData.height);
|
||||||
|
|
||||||
|
// Restore composite operation
|
||||||
|
context.globalCompositeOperation = oldCompositeOperation;
|
||||||
|
|
||||||
|
// Acknowledge reset of stack (happens on resize of canvas)
|
||||||
|
stackSize = 0;
|
||||||
|
context.save();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Preserve composite operation
|
// If the canvas size is not changing, manually force state reset
|
||||||
var oldCompositeOperation = context.globalCompositeOperation;
|
else
|
||||||
|
layer.reset();
|
||||||
// Resize canvas
|
|
||||||
canvas.width = newWidth;
|
|
||||||
canvas.height = newHeight;
|
|
||||||
|
|
||||||
// Redraw old data, if any
|
|
||||||
if (oldData)
|
|
||||||
context.drawImage(oldData,
|
|
||||||
0, 0, layer.width, layer.height,
|
|
||||||
0, 0, layer.width, layer.height);
|
|
||||||
|
|
||||||
// Restore composite operation
|
|
||||||
context.globalCompositeOperation = oldCompositeOperation;
|
|
||||||
|
|
||||||
|
// Assign new layer dimensions
|
||||||
layer.width = newWidth;
|
layer.width = newWidth;
|
||||||
layer.height = newHeight;
|
layer.height = newHeight;
|
||||||
|
|
||||||
// Acknowledge reset of stack (happens on resize of canvas)
|
};
|
||||||
stackSize = 0;
|
|
||||||
context.save();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given the X and Y coordinates of the upper-left corner of a rectangle
|
* Given the X and Y coordinates of the upper-left corner of a rectangle
|
||||||
@@ -257,6 +299,7 @@ Guacamole.Layer = function(width, height) {
|
|||||||
this.drawImage = function(x, y, image) {
|
this.drawImage = function(x, y, image) {
|
||||||
if (layer.autosize) fitRect(x, y, image.width, image.height);
|
if (layer.autosize) fitRect(x, y, image.width, image.height);
|
||||||
context.drawImage(image, x, y);
|
context.drawImage(image, x, y);
|
||||||
|
empty = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -335,6 +378,7 @@ Guacamole.Layer = function(width, height) {
|
|||||||
|
|
||||||
// Draw image data
|
// Draw image data
|
||||||
context.putImageData(dst, x, y);
|
context.putImageData(dst, x, y);
|
||||||
|
empty = false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -378,6 +422,7 @@ Guacamole.Layer = function(width, height) {
|
|||||||
// Get image data from src and dst
|
// Get image data from src and dst
|
||||||
var src = srcLayer.getCanvas().getContext("2d").getImageData(srcx, srcy, srcw, srch);
|
var src = srcLayer.getCanvas().getContext("2d").getImageData(srcx, srcy, srcw, srch);
|
||||||
context.putImageData(src, x, y);
|
context.putImageData(src, x, y);
|
||||||
|
empty = false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -421,6 +466,7 @@ Guacamole.Layer = function(width, height) {
|
|||||||
|
|
||||||
if (layer.autosize) fitRect(x, y, srcw, srch);
|
if (layer.autosize) fitRect(x, y, srcw, srch);
|
||||||
context.drawImage(srcCanvas, srcx, srcy, srcw, srch, x, y, srcw, srch);
|
context.drawImage(srcCanvas, srcx, srcy, srcw, srch, x, y, srcw, srch);
|
||||||
|
empty = false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -583,6 +629,7 @@ Guacamole.Layer = function(width, height) {
|
|||||||
context.lineWidth = thickness;
|
context.lineWidth = thickness;
|
||||||
context.strokeStyle = "rgba(" + r + "," + g + "," + b + "," + a/255.0 + ")";
|
context.strokeStyle = "rgba(" + r + "," + g + "," + b + "," + a/255.0 + ")";
|
||||||
context.stroke();
|
context.stroke();
|
||||||
|
empty = false;
|
||||||
|
|
||||||
// Path now implicitly closed
|
// Path now implicitly closed
|
||||||
pathClosed = true;
|
pathClosed = true;
|
||||||
@@ -605,6 +652,7 @@ Guacamole.Layer = function(width, height) {
|
|||||||
// Fill with color
|
// Fill with color
|
||||||
context.fillStyle = "rgba(" + r + "," + g + "," + b + "," + a/255.0 + ")";
|
context.fillStyle = "rgba(" + r + "," + g + "," + b + "," + a/255.0 + ")";
|
||||||
context.fill();
|
context.fill();
|
||||||
|
empty = false;
|
||||||
|
|
||||||
// Path now implicitly closed
|
// Path now implicitly closed
|
||||||
pathClosed = true;
|
pathClosed = true;
|
||||||
@@ -637,6 +685,7 @@ Guacamole.Layer = function(width, height) {
|
|||||||
"repeat"
|
"repeat"
|
||||||
);
|
);
|
||||||
context.stroke();
|
context.stroke();
|
||||||
|
empty = false;
|
||||||
|
|
||||||
// Path now implicitly closed
|
// Path now implicitly closed
|
||||||
pathClosed = true;
|
pathClosed = true;
|
||||||
@@ -661,6 +710,7 @@ Guacamole.Layer = function(width, height) {
|
|||||||
"repeat"
|
"repeat"
|
||||||
);
|
);
|
||||||
context.fill();
|
context.fill();
|
||||||
|
empty = false;
|
||||||
|
|
||||||
// Path now implicitly closed
|
// Path now implicitly closed
|
||||||
pathClosed = true;
|
pathClosed = true;
|
||||||
@@ -781,8 +831,7 @@ Guacamole.Layer = function(width, height) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Initialize canvas dimensions
|
// Initialize canvas dimensions
|
||||||
canvas.width = width;
|
resize(width, height);
|
||||||
canvas.height = height;
|
|
||||||
|
|
||||||
// Explicitly render canvas below other elements in the layer (such as
|
// Explicitly render canvas below other elements in the layer (such as
|
||||||
// child layers). Chrome and others may fail to render layers properly
|
// child layers). Chrome and others may fail to render layers properly
|
||||||
|
Reference in New Issue
Block a user