clockwerk-guacamole – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 eva 1  
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 *
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
14 *
15 * The Original Code is guacamole-common-js.
16 *
17 * The Initial Developer of the Original Code is
18 * Michael Jumper.
19 * Portions created by the Initial Developer are Copyright (C) 2010
20 * the Initial Developer. All Rights Reserved.
21 *
22 * Contributor(s):
23 * Matt Hortman
24 *
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
36 *
37 * ***** END LICENSE BLOCK ***** */
38  
39 // Guacamole namespace
40 var Guacamole = Guacamole || {};
41  
42  
43 /**
44 * Guacamole protocol client. Given a display element and {@link Guacamole.Tunnel},
45 * automatically handles incoming and outgoing Guacamole instructions via the
46 * provided tunnel, updating the display using one or more canvas elements.
47 *
48 * @constructor
49 * @param {Guacamole.Tunnel} tunnel The tunnel to use to send and receive
50 * Guacamole instructions.
51 */
52 Guacamole.Client = function(tunnel) {
53  
54 var guac_client = this;
55  
56 var STATE_IDLE = 0;
57 var STATE_CONNECTING = 1;
58 var STATE_WAITING = 2;
59 var STATE_CONNECTED = 3;
60 var STATE_DISCONNECTING = 4;
61 var STATE_DISCONNECTED = 5;
62  
63 var currentState = STATE_IDLE;
64  
65 var currentTimestamp = 0;
66 var pingInterval = null;
67  
68 var displayWidth = 0;
69 var displayHeight = 0;
70 var displayScale = 1;
71  
72 /**
73 * Translation from Guacamole protocol line caps to Layer line caps.
74 */
75 var lineCap = {
76 0: "butt",
77 1: "round",
78 2: "square"
79 };
80  
81 /**
82 * Translation from Guacamole protocol line caps to Layer line caps.
83 */
84 var lineJoin = {
85 0: "bevel",
86 1: "miter",
87 2: "round"
88 };
89  
90 // Create bounding div
91 var bounds = document.createElement("div");
92 bounds.style.position = "relative";
93 bounds.style.width = (displayWidth*displayScale) + "px";
94 bounds.style.height = (displayHeight*displayScale) + "px";
95  
96 // Create display
97 var display = document.createElement("div");
98 display.style.position = "relative";
99 display.style.width = displayWidth + "px";
100 display.style.height = displayHeight + "px";
101  
102 // Ensure transformations on display originate at 0,0
103 display.style.transformOrigin =
104 display.style.webkitTransformOrigin =
105 display.style.MozTransformOrigin =
106 display.style.OTransformOrigin =
107 display.style.msTransformOrigin =
108 "0 0";
109  
110 // Create default layer
111 var default_layer_container = new Guacamole.Client.LayerContainer(displayWidth, displayHeight);
112  
113 // Position default layer
114 var default_layer_container_element = default_layer_container.getElement();
115 default_layer_container_element.style.position = "absolute";
116 default_layer_container_element.style.left = "0px";
117 default_layer_container_element.style.top = "0px";
118 default_layer_container_element.style.overflow = "hidden";
119  
120 // Create cursor layer
121 var cursor = new Guacamole.Client.LayerContainer(0, 0);
122 cursor.getLayer().setChannelMask(Guacamole.Layer.SRC);
123  
124 // Position cursor layer
125 var cursor_element = cursor.getElement();
126 cursor_element.style.position = "absolute";
127 cursor_element.style.left = "0px";
128 cursor_element.style.top = "0px";
129  
130 // Add default layer and cursor to display
131 display.appendChild(default_layer_container.getElement());
132 display.appendChild(cursor.getElement());
133  
134 // Add display to bounds
135 bounds.appendChild(display);
136  
137 // Initially, only default layer exists
138 var layers = [default_layer_container];
139  
140 // No initial buffers
141 var buffers = [];
142  
143 tunnel.onerror = function(message) {
144 if (guac_client.onerror)
145 guac_client.onerror(message);
146 };
147  
148 function setState(state) {
149 if (state != currentState) {
150 currentState = state;
151 if (guac_client.onstatechange)
152 guac_client.onstatechange(currentState);
153 }
154 }
155  
156 function isConnected() {
157 return currentState == STATE_CONNECTED
158 || currentState == STATE_WAITING;
159 }
160  
161 var cursorHotspotX = 0;
162 var cursorHotspotY = 0;
163  
164 var cursorX = 0;
165 var cursorY = 0;
166  
167 function moveCursor(x, y) {
168  
169 // Move cursor layer
170 cursor.translate(x - cursorHotspotX, y - cursorHotspotY);
171  
172 // Update stored position
173 cursorX = x;
174 cursorY = y;
175  
176 }
177  
178 guac_client.getDisplay = function() {
179 return bounds;
180 };
181  
182 guac_client.sendKeyEvent = function(pressed, keysym) {
183 // Do not send requests if not connected
184 if (!isConnected())
185 return;
186  
187 tunnel.sendMessage("key", keysym, pressed);
188 };
189  
190 guac_client.sendMouseState = function(mouseState) {
191  
192 // Do not send requests if not connected
193 if (!isConnected())
194 return;
195  
196 // Update client-side cursor
197 moveCursor(
198 Math.floor(mouseState.x),
199 Math.floor(mouseState.y)
200 );
201  
202 // Build mask
203 var buttonMask = 0;
204 if (mouseState.left) buttonMask |= 1;
205 if (mouseState.middle) buttonMask |= 2;
206 if (mouseState.right) buttonMask |= 4;
207 if (mouseState.up) buttonMask |= 8;
208 if (mouseState.down) buttonMask |= 16;
209  
210 // Send message
211 tunnel.sendMessage("mouse", Math.floor(mouseState.x), Math.floor(mouseState.y), buttonMask);
212 };
213  
214 guac_client.setClipboard = function(data) {
215  
216 // Do not send requests if not connected
217 if (!isConnected())
218 return;
219  
220 tunnel.sendMessage("clipboard", data);
221 };
222  
223 // Handlers
224 guac_client.onstatechange = null;
225 guac_client.onname = null;
226 guac_client.onerror = null;
227 guac_client.onclipboard = null;
228  
229 // Layers
230 function getBufferLayer(index) {
231  
232 index = -1 - index;
233 var buffer = buffers[index];
234  
235 // Create buffer if necessary
236 if (buffer == null) {
237 buffer = new Guacamole.Layer(0, 0);
238 buffer.autosize = 1;
239 buffers[index] = buffer;
240 }
241  
242 return buffer;
243  
244 }
245  
246 function getLayerContainer(index) {
247  
248 var layer = layers[index];
249 if (layer == null) {
250  
251 // Add new layer
252 layer = new Guacamole.Client.LayerContainer(displayWidth, displayHeight);
253 layers[index] = layer;
254  
255 // Get and position layer
256 var layer_element = layer.getElement();
257 layer_element.style.position = "absolute";
258 layer_element.style.left = "0px";
259 layer_element.style.top = "0px";
260 layer_element.style.overflow = "hidden";
261  
262 // Add to default layer container
263 default_layer_container.getElement().appendChild(layer_element);
264  
265 }
266  
267 return layer;
268  
269 }
270  
271 function getLayer(index) {
272  
273 // If buffer, just get layer
274 if (index < 0)
275 return getBufferLayer(index);
276  
277 // Otherwise, retrieve layer from layer container
278 return getLayerContainer(index).getLayer();
279  
280 }
281  
282 /**
283 * Handlers for all defined layer properties.
284 */
285 var layerPropertyHandlers = {
286  
287 "miter-limit": function(layer, value) {
288 layer.setMiterLimit(parseFloat(value));
289 }
290  
291 };
292  
293 /**
294 * Handlers for all instruction opcodes receivable by a Guacamole protocol
295 * client.
296 */
297 var instructionHandlers = {
298  
299 "arc": function(parameters) {
300  
301 var layer = getLayer(parseInt(parameters[0]));
302 var x = parseInt(parameters[1]);
303 var y = parseInt(parameters[2]);
304 var radius = parseInt(parameters[3]);
305 var startAngle = parseFloat(parameters[4]);
306 var endAngle = parseFloat(parameters[5]);
307 var negative = parseInt(parameters[6]);
308  
309 layer.arc(x, y, radius, startAngle, endAngle, negative != 0);
310  
311 },
312  
313 "cfill": function(parameters) {
314  
315 var channelMask = parseInt(parameters[0]);
316 var layer = getLayer(parseInt(parameters[1]));
317 var r = parseInt(parameters[2]);
318 var g = parseInt(parameters[3]);
319 var b = parseInt(parameters[4]);
320 var a = parseInt(parameters[5]);
321  
322 layer.setChannelMask(channelMask);
323  
324 layer.fillColor(r, g, b, a);
325  
326 },
327  
328 "clip": function(parameters) {
329  
330 var layer = getLayer(parseInt(parameters[0]));
331  
332 layer.clip();
333  
334 },
335  
336 "clipboard": function(parameters) {
337 if (guac_client.onclipboard) guac_client.onclipboard(parameters[0]);
338 },
339  
340 "close": function(parameters) {
341  
342 var layer = getLayer(parseInt(parameters[0]));
343  
344 layer.close();
345  
346 },
347  
348 "copy": function(parameters) {
349  
350 var srcL = getLayer(parseInt(parameters[0]));
351 var srcX = parseInt(parameters[1]);
352 var srcY = parseInt(parameters[2]);
353 var srcWidth = parseInt(parameters[3]);
354 var srcHeight = parseInt(parameters[4]);
355 var channelMask = parseInt(parameters[5]);
356 var dstL = getLayer(parseInt(parameters[6]));
357 var dstX = parseInt(parameters[7]);
358 var dstY = parseInt(parameters[8]);
359  
360 dstL.setChannelMask(channelMask);
361  
362 dstL.copy(
363 srcL,
364 srcX,
365 srcY,
366 srcWidth,
367 srcHeight,
368 dstX,
369 dstY
370 );
371  
372 },
373  
374 "cstroke": function(parameters) {
375  
376 var channelMask = parseInt(parameters[0]);
377 var layer = getLayer(parseInt(parameters[1]));
378 var cap = lineCap[parseInt(parameters[2])];
379 var join = lineJoin[parseInt(parameters[3])];
380 var thickness = parseInt(parameters[4]);
381 var r = parseInt(parameters[5]);
382 var g = parseInt(parameters[6]);
383 var b = parseInt(parameters[7]);
384 var a = parseInt(parameters[8]);
385  
386 layer.setChannelMask(channelMask);
387  
388 layer.strokeColor(cap, join, thickness, r, g, b, a);
389  
390 },
391  
392 "cursor": function(parameters) {
393  
394 cursorHotspotX = parseInt(parameters[0]);
395 cursorHotspotY = parseInt(parameters[1]);
396 var srcL = getLayer(parseInt(parameters[2]));
397 var srcX = parseInt(parameters[3]);
398 var srcY = parseInt(parameters[4]);
399 var srcWidth = parseInt(parameters[5]);
400 var srcHeight = parseInt(parameters[6]);
401  
402 // Reset cursor size
403 cursor.resize(srcWidth, srcHeight);
404  
405 // Draw cursor to cursor layer
406 cursor.getLayer().copy(
407 srcL,
408 srcX,
409 srcY,
410 srcWidth,
411 srcHeight,
412 0,
413  
414 );
415  
416 // Update cursor position (hotspot may have changed)
417 moveCursor(cursorX, cursorY);
418  
419 },
420  
421 "curve": function(parameters) {
422  
423 var layer = getLayer(parseInt(parameters[0]));
424 var cp1x = parseInt(parameters[1]);
425 var cp1y = parseInt(parameters[2]);
426 var cp2x = parseInt(parameters[3]);
427 var cp2y = parseInt(parameters[4]);
428 var x = parseInt(parameters[5]);
429 var y = parseInt(parameters[6]);
430  
431 layer.curveTo(cp1x, cp1y, cp2x, cp2y, x, y);
432  
433 },
434  
435 "dispose": function(parameters) {
436  
437 var layer_index = parseInt(parameters[0]);
438  
439 // If visible layer, remove from parent
440 if (layer_index > 0) {
441  
442 // Get container element
443 var layer_container = getLayerContainer(layer_index).getElement();
444  
445 // Remove from parent
446 layer_container.parentNode.removeChild(layer_container);
447  
448 // Delete reference
449 delete layers[layer_index];
450  
451 }
452  
453 // If buffer, just delete reference
454 else if (layer_index < 0)
455 delete buffers[-1 - layer_index];
456  
457 // Attempting to dispose the root layer currently has no effect.
458  
459 },
460  
461 "distort": function(parameters) {
462  
463 var layer_index = parseInt(parameters[0]);
464 var a = parseFloat(parameters[1]);
465 var b = parseFloat(parameters[2]);
466 var c = parseFloat(parameters[3]);
467 var d = parseFloat(parameters[4]);
468 var e = parseFloat(parameters[5]);
469 var f = parseFloat(parameters[6]);
470  
471 // Only valid for visible layers (not buffers)
472 if (layer_index >= 0) {
473  
474 // Get container element
475 var layer_container = getLayerContainer(layer_index).getElement();
476  
477 // Set layer transform
478 layer_container.transform(a, b, c, d, e, f);
479  
480 }
481  
482 },
483  
484 "error": function(parameters) {
485 if (guac_client.onerror) guac_client.onerror(parameters[0]);
486 guac_client.disconnect();
487 },
488  
489 "identity": function(parameters) {
490  
491 var layer = getLayer(parseInt(parameters[0]));
492  
493 layer.setTransform(1, 0, 0, 1, 0, 0);
494  
495 },
496  
497 "lfill": function(parameters) {
498  
499 var channelMask = parseInt(parameters[0]);
500 var layer = getLayer(parseInt(parameters[1]));
501 var srcLayer = getLayer(parseInt(parameters[2]));
502  
503 layer.setChannelMask(channelMask);
504  
505 layer.fillLayer(srcLayer);
506  
507 },
508  
509 "line": function(parameters) {
510  
511 var layer = getLayer(parseInt(parameters[0]));
512 var x = parseInt(parameters[1]);
513 var y = parseInt(parameters[2]);
514  
515 layer.lineTo(x, y);
516  
517 },
518  
519 "lstroke": function(parameters) {
520  
521 var channelMask = parseInt(parameters[0]);
522 var layer = getLayer(parseInt(parameters[1]));
523 var srcLayer = getLayer(parseInt(parameters[2]));
524  
525 layer.setChannelMask(channelMask);
526  
527 layer.strokeLayer(srcLayer);
528  
529 },
530  
531 "move": function(parameters) {
532  
533 var layer_index = parseInt(parameters[0]);
534 var parent_index = parseInt(parameters[1]);
535 var x = parseInt(parameters[2]);
536 var y = parseInt(parameters[3]);
537 var z = parseInt(parameters[4]);
538  
539 // Only valid for non-default layers
540 if (layer_index > 0 && parent_index >= 0) {
541  
542 // Get container element
543 var layer_container = getLayerContainer(layer_index);
544 var layer_container_element = layer_container.getElement();
545 var parent = getLayerContainer(parent_index).getElement();
546  
547 // Set parent if necessary
548 if (!(layer_container_element.parentNode === parent))
549 parent.appendChild(layer_container_element);
550  
551 // Move layer
552 layer_container.translate(x, y);
553 layer_container_element.style.zIndex = z;
554  
555 }
556  
557 },
558  
559 "name": function(parameters) {
560 if (guac_client.onname) guac_client.onname(parameters[0]);
561 },
562  
563 "png": function(parameters) {
564  
565 var channelMask = parseInt(parameters[0]);
566 var layer = getLayer(parseInt(parameters[1]));
567 var x = parseInt(parameters[2]);
568 var y = parseInt(parameters[3]);
569 var data = parameters[4];
570  
571 layer.setChannelMask(channelMask);
572  
573 layer.draw(
574 x,
575 y,
576 "data:image/png;base64," + data
577 );
578  
579 // If received first update, no longer waiting.
580 if (currentState == STATE_WAITING)
581 setState(STATE_CONNECTED);
582  
583 },
584  
585 "pop": function(parameters) {
586  
587 var layer = getLayer(parseInt(parameters[0]));
588  
589 layer.pop();
590  
591 },
592  
593 "push": function(parameters) {
594  
595 var layer = getLayer(parseInt(parameters[0]));
596  
597 layer.push();
598  
599 },
600  
601 "rect": function(parameters) {
602  
603 var layer = getLayer(parseInt(parameters[0]));
604 var x = parseInt(parameters[1]);
605 var y = parseInt(parameters[2]);
606 var w = parseInt(parameters[3]);
607 var h = parseInt(parameters[4]);
608  
609 layer.rect(x, y, w, h);
610  
611 },
612  
613 "reset": function(parameters) {
614  
615 var layer = getLayer(parseInt(parameters[0]));
616  
617 layer.reset();
618  
619 },
620  
621 "set": function(parameters) {
622  
623 var layer = getLayer(parseInt(parameters[0]));
624 var name = parameters[1];
625 var value = parameters[2];
626  
627 // Call property handler if defined
628 var handler = layerPropertyHandlers[name];
629 if (handler)
630 handler(layer, value);
631  
632 },
633  
634 "shade": function(parameters) {
635  
636 var layer_index = parseInt(parameters[0]);
637 var a = parseInt(parameters[1]);
638  
639 // Only valid for visible layers (not buffers)
640 if (layer_index >= 0) {
641  
642 // Get container element
643 var layer_container = getLayerContainer(layer_index).getElement();
644  
645 // Set layer opacity
646 layer_container.style.opacity = a/255.0;
647  
648 }
649  
650 },
651  
652 "size": function(parameters) {
653  
654 var layer_index = parseInt(parameters[0]);
655 var width = parseInt(parameters[1]);
656 var height = parseInt(parameters[2]);
657  
658 // Resize layer
659 var layer_container = getLayerContainer(layer_index);
660 layer_container.resize(width, height);
661  
662 // If layer is default, resize display
663 if (layer_index == 0) {
664  
665 displayWidth = width;
666 displayHeight = height;
667  
668 // Update (set) display size
669 display.style.width = displayWidth + "px";
670 display.style.height = displayHeight + "px";
671  
672 // Update bounds size
673 bounds.style.width = (displayWidth*displayScale) + "px";
674 bounds.style.height = (displayHeight*displayScale) + "px";
675  
676 }
677  
678 },
679  
680 "start": function(parameters) {
681  
682 var layer = getLayer(parseInt(parameters[0]));
683 var x = parseInt(parameters[1]);
684 var y = parseInt(parameters[2]);
685  
686 layer.moveTo(x, y);
687  
688 },
689  
690 "sync": function(parameters) {
691  
692 var timestamp = parameters[0];
693  
694 // When all layers have finished rendering all instructions
695 // UP TO THIS POINT IN TIME, send sync response.
696  
697 var layersToSync = 0;
698 function syncLayer() {
699  
700 layersToSync--;
701  
702 // Send sync response when layers are finished
703 if (layersToSync == 0) {
704 if (timestamp != currentTimestamp) {
705 tunnel.sendMessage("sync", timestamp);
706 currentTimestamp = timestamp;
707 }
708 }
709  
710 }
711  
712 // Count active, not-ready layers and install sync tracking hooks
713 for (var i=0; i
714  
715
716
717
718
719
720  
721
722  
723 / If all layers are ready, then we didn't install any hooks.
724 // Send sync message now,
725 if (layersToSync == 0) {
726 if (timestamp != currentTimestamp) {
727 tunnel.sendMessage("sync", timestamp);
728 currentTimestamp = timestamp;
729 }
730 }
731  
732 },
733  
734 "transfer": function(parameters) {
735  
736 var srcL = getLayer(parseInt(parameters[0]));
737 var srcX = parseInt(parameters[1]);
738 var srcY = parseInt(parameters[2]);
739 var srcWidth = parseInt(parameters[3]);
740 var srcHeight = parseInt(parameters[4]);
741 var transferFunction = Guacamole.Client.DefaultTransferFunction[parameters[5]];
742 var dstL = getLayer(parseInt(parameters[6]));
743 var dstX = parseInt(parameters[7]);
744 var dstY = parseInt(parameters[8]);
745  
746 dstL.transfer(
747 srcL,
748 srcX,
749 srcY,
750 srcWidth,
751 srcHeight,
752 dstX,
753 dstY,
754 transferFunction
755 );
756  
757 },
758  
759 "transform": function(parameters) {
760  
761 var layer = getLayer(parseInt(parameters[0]));
762 var a = parseFloat(parameters[1]);
763 var b = parseFloat(parameters[2]);
764 var c = parseFloat(parameters[3]);
765 var d = parseFloat(parameters[4]);
766 var e = parseFloat(parameters[5]);
767 var f = parseFloat(parameters[6]);
768  
769 layer.transform(a, b, c, d, e, f);
770  
771 }
772  
773 };
774  
775  
776 tunnel.oninstruction = function(opcode, parameters) {
777  
778 var handler = instructionHandlers[opcode];
779 if (handler)
780 handler(parameters);
781  
782 };
783  
784  
785 guac_client.disconnect = function() {
786  
787 // Only attempt disconnection not disconnected.
788 if (currentState != STATE_DISCONNECTED
789 && currentState != STATE_DISCONNECTING) {
790  
791 setState(STATE_DISCONNECTING);
792  
793 // Stop ping
794 if (pingInterval)
795 window.clearInterval(pingInterval);
796  
797 // Send disconnect message and disconnect
798 tunnel.sendMessage("disconnect");
799 tunnel.disconnect();
800 setState(STATE_DISCONNECTED);
801  
802 }
803  
804 };
805  
806 guac_client.connect = function(data) {
807  
808 setState(STATE_CONNECTING);
809  
810 try {
811 tunnel.connect(data);
812 }
813 catch (e) {
814 setState(STATE_IDLE);
815 throw e;
816 }
817  
818 // Ping every 5 seconds (ensure connection alive)
819 pingInterval = window.setInterval(function() {
820 tunnel.sendMessage("sync", currentTimestamp);
821 }, 5000);
822  
823 setState(STATE_WAITING);
824 };
825  
826 guac_client.scale = function(scale) {
827  
828 display.style.transform =
829 display.style.WebkitTransform =
830 display.style.MozTransform =
831 display.style.OTransform =
832 display.style.msTransform =
833  
834 "scale(" + scale + "," + scale + ")";
835  
836 displayScale = scale;
837  
838 // Update bounds size
839 bounds.style.width = (displayWidth*displayScale) + "px";
840 bounds.style.height = (displayHeight*displayScale) + "px";
841  
842 };
843  
844 guac_client.getScale = function() {
845 return displayScale;
846 };
847  
848 };
849  
850 /**
851 for Guacamole.Layer, allowing layers to be easily
852
853
854
855
856
857 in pixels. The canvas element
858 this Layer will be given this width.
859
860 in pixels. The canvas element
861 this Layer will be given this height.
862 /
863 Guacamole.Client.LayerContainer = function(width, height) {
864  
865 /**
866 this LayerContainer.
867 private
868 /
869 var layer_container = this;
870  
871 // Create layer with given size
872 var layer = new Guacamole.Layer(width, height);
873  
874 // Set layer position
875 var canvas = layer.getCanvas();
876 canvas.style.position = "absolute";
877 canvas.style.left = "0px";
878 canvas.style.top = "0px";
879  
880 // Create div with given size
881 var div = document.createElement("div");
882 div.appendChild(canvas);
883 div.style.width = width + "px";
884 div.style.height = height + "px";
885  
886 /**
887 this LayerContainer and the contained Layer to the
888
889
890 new width to assign to this Layer.
891 new height to assign to this Layer.
892 /
893 layer_container.resize = function(width, height) {
894  
895 // Resize layer
896 layer.resize(width, height);
897  
898 // Resize containing div
899 div.style.width = width + "px";
900 div.style.height = height + "px";
901  
902 };
903  
904 /**
905 this LayerContainer.
906 this LayerContainer.
907 /
908 layer_container.getLayer = function() {
909 return layer;
910 };
911  
912 /**
913 this LayerContainer.
914 this LayerContainer.
915 /
916 layer_container.getElement = function() {
917 return div;
918 };
919  
920 /**
921 this LayerContainer's transform.
922 */
923 var translate = "translate(0px, 0px)"; // (0, 0)
924  
925 /**
926 * The arbitrary matrix component of this LayerContainer's transform.
927 /
928 var matrix = "matrix(1, 0, 0, 1, 0, 0)"; // Identity
929  
930 /**
931 this LayerContainer to the given X and Y
932
933
934
935
936 /
937 layer_container.translate = function(x, y) {
938  
939 // Generate translation
940 translate = "translate("
941 + x + "px,"
942 + y + "px)";
943  
944 // Set layer transform
945 div.style.transform =
946 div.style.WebkitTransform =
947 div.style.MozTransform =
948 div.style.OTransform =
949 div.style.msTransform =
950  
951 translate + " " + matrix;
952  
953 };
954  
955 /**
956 with six values from the
957 's matrix).
958 *
959 * @param {Number} a The first value in the affine transform's matrix.
960 in the affine transform's matrix.
961 * @param {Number} c The third value in the affine transform's matrix.
962 in the affine transform's matrix.
963 * @param {Number} e The fifth value in the affine transform's matrix.
964 in the affine transform's matrix.
965 */
966 layer_container.transform = function(a, b, c, d, e, f) {
967  
968 // Generate matrix transformation
969 matrix =
970  
971 /* a c e
972 * b d f
973 * 0 0 1
974 */
975  
976 "matrix(" + a + "," + b + "," + c + "," + d + "," + e + "," + f + ")";
977  
978 // Set layer transform
979 div.style.transform =
980 div.style.WebkitTransform =
981 div.style.MozTransform =
982 div.style.OTransform =
983 div.style.msTransform =
984  
985 translate + " " + matrix;
986  
987 };
988  
989 };
990  
991 /**
992 * Map of all Guacamole binary raster operations to transfer functions.
993 * @private
994 */
995 Guacamole.Client.DefaultTransferFunction = {
996  
997 /* BLACK */
998 0x0: function (src, dst) {
999 dst.red = dst.green = dst.blue = 0x00;
1000 },
1001  
1002 /* WHITE */
1003 0xF: function (src, dst) {
1004 dst.red = dst.green = dst.blue = 0xFF;
1005 },
1006  
1007 /* SRC */
1008 0x3: function (src, dst) {
1009 dst.red = src.red;
1010 dst.green = src.green;
1011 dst.blue = src.blue;
1012 dst.alpha = src.alpha;
1013 },
1014  
1015 /* DEST (no-op) */
1016 0x5: function (src, dst) {
1017 // Do nothing
1018 },
1019  
1020 /* Invert SRC */
1021 0xC: function (src, dst) {
1022 dst.red = 0xFF & ~src.red;
1023 dst.green = 0xFF & ~src.green;
1024 dst.blue = 0xFF & ~src.blue;
1025 dst.alpha = src.alpha;
1026 },
1027  
1028 /* Invert DEST */
1029 0xA: function (src, dst) {
1030 dst.red = 0xFF & ~dst.red;
1031 dst.green = 0xFF & ~dst.green;
1032 dst.blue = 0xFF & ~dst.blue;
1033 },
1034  
1035 /* AND */
1036 0x1: function (src, dst) {
1037 dst.red = ( src.red & dst.red);
1038 dst.green = ( src.green & dst.green);
1039 dst.blue = ( src.blue & dst.blue);
1040 },
1041  
1042 /* NAND */
1043 0xE: function (src, dst) {
1044 dst.red = 0xFF & ~( src.red & dst.red);
1045 dst.green = 0xFF & ~( src.green & dst.green);
1046 dst.blue = 0xFF & ~( src.blue & dst.blue);
1047 },
1048  
1049 /* OR */
1050 0x7: function (src, dst) {
1051 dst.red = ( src.red | dst.red);
1052 dst.green = ( src.green | dst.green);
1053 dst.blue = ( src.blue | dst.blue);
1054 },
1055  
1056 /* NOR */
1057 0x8: function (src, dst) {
1058 dst.red = 0xFF & ~( src.red | dst.red);
1059 dst.green = 0xFF & ~( src.green | dst.green);
1060 dst.blue = 0xFF & ~( src.blue | dst.blue);
1061 },
1062  
1063 /* XOR */
1064 0x6: function (src, dst) {
1065 dst.red = ( src.red ^ dst.red);
1066 dst.green = ( src.green ^ dst.green);
1067 dst.blue = ( src.blue ^ dst.blue);
1068 },
1069  
1070 /* XNOR */
1071 0x9: function (src, dst) {
1072 dst.red = 0xFF & ~( src.red ^ dst.red);
1073 dst.green = 0xFF & ~( src.green ^ dst.green);
1074 dst.blue = 0xFF & ~( src.blue ^ dst.blue);
1075 },
1076  
1077 /* AND inverted source */
1078 0x4: function (src, dst) {
1079 dst.red = 0xFF & (~src.red & dst.red);
1080 dst.green = 0xFF & (~src.green & dst.green);
1081 dst.blue = 0xFF & (~src.blue & dst.blue);
1082 },
1083  
1084 /* OR inverted source */
1085 0xD: function (src, dst) {
1086 dst.red = 0xFF & (~src.red | dst.red);
1087 dst.green = 0xFF & (~src.green | dst.green);
1088 dst.blue = 0xFF & (~src.blue | dst.blue);
1089 },
1090  
1091 /* AND inverted destination */
1092 0x2: function (src, dst) {
1093 dst.red = 0xFF & ( src.red & ~dst.red);
1094 dst.green = 0xFF & ( src.green & ~dst.green);
1095 dst.blue = 0xFF & ( src.blue & ~dst.blue);
1096 },
1097  
1098 /* OR inverted destination */
1099 0xB: function (src, dst) {
1100 dst.red = 0xFF & ( src.red | ~dst.red);
1101 dst.green = 0xFF & ( src.green | ~dst.green);
1102 dst.blue = 0xFF & ( src.blue | ~dst.blue);
1103 }
1104  
1105 };