diff --git a/install.sh b/install.sh
index 5e6c35f8b2..c68d875e59 100755
--- a/install.sh
+++ b/install.sh
@@ -326,6 +326,7 @@ SUNSTONE_DIRS="$SUNSTONE_LOCATION/routes \
$SUNSTONE_LOCATION/public/locale/zh_CN \
$SUNSTONE_LOCATION/public/vendor \
$SUNSTONE_LOCATION/public/vendor/crypto-js \
+ $SUNSTONE_LOCATION/public/vendor/spice \
$SUNSTONE_LOCATION/public/vendor/noVNC \
$SUNSTONE_LOCATION/public/vendor/noVNC/web-socket-js \
$SUNSTONE_LOCATION/public/vendor/4.0 \
@@ -507,6 +508,7 @@ INSTALL_SUNSTONE_FILES=(
SUNSTONE_ROUTES_FILES:$SUNSTONE_LOCATION/routes
SUNSTONE_PUBLIC_CSS_FILES:$SUNSTONE_LOCATION/public/css
SUNSTONE_PUBLIC_VENDOR_CRYPTOJS:$SUNSTONE_LOCATION/public/vendor/crypto-js
+ SUNSTONE_PUBLIC_VENDOR_SPICE:$SUNSTONE_LOCATION/public/vendor/spice
SUNSTONE_PUBLIC_VENDOR_NOVNC:$SUNSTONE_LOCATION/public/vendor/noVNC
SUNSTONE_PUBLIC_VENDOR_NOVNC_WEBSOCKET:$SUNSTONE_LOCATION/public/vendor/noVNC/web-socket-js
SUNSTONE_PUBLIC_NEW_VENDOR_FLOT:$SUNSTONE_LOCATION/public/vendor/4.0/flot
@@ -1518,6 +1520,7 @@ SUNSTONE_MODELS_JSON_FILES="src/sunstone/models/OpenNebulaJSON/HostJSON.rb \
SUNSTONE_VIEWS_FILES="src/sunstone/views/index.erb \
src/sunstone/views/login.erb \
src/sunstone/views/vnc.erb \
+ src/sunstone/views/spice.erb \
src/sunstone/views/_login_standard.erb \
src/sunstone/views/_login_x509.erb"
@@ -1602,7 +1605,7 @@ SUNSTONE_PUBLIC_NEW_VENDOR_FONTAWESOME_FONT="\
src/sunstone/public/bower_components/fontawesome/fonts/FontAwesome.otf"
SUNSTONE_PUBLIC_VENDOR_NOVNC="\
- src/sunstone/public/bower_components/no-vnc/include/base.css \
+ src/sunstone/public/bower_components/no-vnc/include/novnc-custom.css \
src/sunstone/public/bower_components/no-vnc/include/base64.js \
src/sunstone/public/bower_components/no-vnc/include/black.css \
src/sunstone/public/bower_components/no-vnc/include/blue.css \
@@ -1627,6 +1630,36 @@ SUNSTONE_PUBLIC_VENDOR_NOVNC_WEBSOCKET="\
src/sunstone/public/bower_components/no-vnc/include/web-socket-js/swfobject.js \
src/sunstone/public/bower_components/no-vnc/include/web-socket-js/WebSocketMain.swf"
+SUNSTONE_PUBLIC_VENDOR_SPICE="\
+ src/sunstone/public/bower_components/spice-html5/spicearraybuffer.js \
+ src/sunstone/public/bower_components/spice-html5/enums.js \
+ src/sunstone/public/bower_components/spice-html5/atKeynames.js \
+ src/sunstone/public/bower_components/spice-html5/utils.js \
+ src/sunstone/public/bower_components/spice-html5/png.js \
+ src/sunstone/public/bower_components/spice-html5/lz.js \
+ src/sunstone/public/bower_components/spice-html5/quic.js \
+ src/sunstone/public/bower_components/spice-html5/bitmap.js \
+ src/sunstone/public/bower_components/spice-html5/spicedataview.js \
+ src/sunstone/public/bower_components/spice-html5/spicetype.js \
+ src/sunstone/public/bower_components/spice-html5/spicemsg.js \
+ src/sunstone/public/bower_components/spice-html5/wire.js \
+ src/sunstone/public/bower_components/spice-html5/spiceconn.js \
+ src/sunstone/public/bower_components/spice-html5/display.js \
+ src/sunstone/public/bower_components/spice-html5/main.js \
+ src/sunstone/public/bower_components/spice-html5/inputs.js \
+ src/sunstone/public/bower_components/spice-html5/webm.js \
+ src/sunstone/public/bower_components/spice-html5/playback.js \
+ src/sunstone/public/bower_components/spice-html5/simulatecursor.js \
+ src/sunstone/public/bower_components/spice-html5/cursor.js \
+ src/sunstone/public/bower_components/spice-html5/thirdparty/jsbn.js \
+ src/sunstone/public/bower_components/spice-html5/thirdparty/rsa.js \
+ src/sunstone/public/bower_components/spice-html5/thirdparty/prng4.js \
+ src/sunstone/public/bower_components/spice-html5/thirdparty/rng.js \
+ src/sunstone/public/bower_components/spice-html5/thirdparty/sha1.js \
+ src/sunstone/public/bower_components/spice-html5/ticket.js \
+ src/sunstone/public/bower_components/spice-html5/resize.js \
+ src/sunstone/public/bower_components/spice-html5/spice-custom.css"
+
# end bower
diff --git a/src/sunstone/OpenNebulaVNC.rb b/src/sunstone/OpenNebulaVNC.rb
index c6c76768fa..9f04a48e6c 100644
--- a/src/sunstone/OpenNebulaVNC.rb
+++ b/src/sunstone/OpenNebulaVNC.rb
@@ -167,7 +167,7 @@ class OpenNebulaVNC
end
if vm_resource['TEMPLATE/GRAPHICS/TYPE'].nil? ||
- vm_resource['TEMPLATE/GRAPHICS/TYPE'].downcase != "vnc"
+ !(["vnc", "spice"].include?(vm_resource['TEMPLATE/GRAPHICS/TYPE'].downcase))
return error(400,"VM has no VNC configured")
end
diff --git a/src/sunstone/public/bower.json b/src/sunstone/public/bower.json
index 90d33f48c9..4387d3d840 100644
--- a/src/sunstone/public/bower.json
+++ b/src/sunstone/public/bower.json
@@ -10,6 +10,7 @@
"foundation-datatables": "https://github.com/DataTables/Plugins.git",
"flot.tooltip": "latest",
"no-vnc": "*",
- "resumablejs": "*"
+ "resumablejs": "*",
+ "spice-html5": "git://anongit.freedesktop.org/spice/spice-html5"
}
}
diff --git a/src/sunstone/public/bower_components/no-vnc/include/base.css b/src/sunstone/public/bower_components/no-vnc/include/base.css
index e2c9a96d8e..2d0325e82c 100644
--- a/src/sunstone/public/bower_components/no-vnc/include/base.css
+++ b/src/sunstone/public/bower_components/no-vnc/include/base.css
@@ -11,9 +11,6 @@ body {
padding:0;
font-family: Helvetica;
/*Background image with light grey curve.*/
- background-color:#494949;
- background-repeat:no-repeat;
- background-position:right bottom;
height:100%;
}
@@ -93,7 +90,6 @@ html {
height:32px;
text-align: center;
font-weight: bold;
- color: #fff;
}
#noVNC_settings_menu {
@@ -122,8 +118,6 @@ html {
display: table;
width:100%;
height:100%;
- background-color:#313131;
- border-bottom-right-radius: 800px 600px;
/*border-top-left-radius: 800px 600px;*/
}
@@ -174,12 +168,8 @@ html {
left:20px;
padding:15px;
color:#000;
- background:#eee; /* default background for browsers without gradient support */
border:2px solid #E0E0E0;
- -webkit-border-radius:10px;
- -moz-border-radius:10px;
- border-radius:10px;
}
#noVNC_popup_status_panel {
@@ -195,7 +185,6 @@ html {
text-align:center;
font-weight:bold;
word-wrap:break-word;
- color:#fff;
background:rgba(0,0,0,0.65);
-webkit-border-radius:10px;
@@ -239,31 +228,13 @@ html {
*/
.noVNC_status_normal {
- background: #b2bdcd; /* Old browsers */
- background: -moz-linear-gradient(top, #b2bdcd 0%, #899cb3 49%, #7e93af 51%, #6e84a3 100%); /* FF3.6+ */
- background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#b2bdcd), color-stop(49%,#899cb3), color-stop(51%,#7e93af), color-stop(100%,#6e84a3)); /* Chrome,Safari4+ */
- background: -webkit-linear-gradient(top, #b2bdcd 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%); /* Chrome10+,Safari5.1+ */
- background: -o-linear-gradient(top, #b2bdcd 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%); /* Opera11.10+ */
- background: -ms-linear-gradient(top, #b2bdcd 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%); /* IE10+ */
- background: linear-gradient(top, #b2bdcd 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%); /* W3C */
+ color: #b2bdcd; /* Old browsers */
}
.noVNC_status_error {
- background: #f04040; /* Old browsers */
- background: -moz-linear-gradient(top, #f04040 0%, #899cb3 49%, #7e93af 51%, #6e84a3 100%); /* FF3.6+ */
- background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f04040), color-stop(49%,#899cb3), color-stop(51%,#7e93af), color-stop(100%,#6e84a3)); /* Chrome,Safari4+ */
- background: -webkit-linear-gradient(top, #f04040 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%); /* Chrome10+,Safari5.1+ */
- background: -o-linear-gradient(top, #f04040 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%); /* Opera11.10+ */
- background: -ms-linear-gradient(top, #f04040 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%); /* IE10+ */
- background: linear-gradient(top, #f04040 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%); /* W3C */
+ color: #f04040; /* Old browsers */
}
.noVNC_status_warn {
- background: #f0f040; /* Old browsers */
- background: -moz-linear-gradient(top, #f0f040 0%, #899cb3 49%, #7e93af 51%, #6e84a3 100%); /* FF3.6+ */
- background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f0f040), color-stop(49%,#899cb3), color-stop(51%,#7e93af), color-stop(100%,#6e84a3)); /* Chrome,Safari4+ */
- background: -webkit-linear-gradient(top, #f0f040 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%); /* Chrome10+,Safari5.1+ */
- background: -o-linear-gradient(top, #f0f040 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%); /* Opera11.10+ */
- background: -ms-linear-gradient(top, #f0f040 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%); /* IE10+ */
- background: linear-gradient(top, #f0f040 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%); /* W3C */
+ color: #f0f040; /* Old browsers */
}
/* Control bar */
diff --git a/src/sunstone/public/bower_components/no-vnc/include/novnc-custom.css b/src/sunstone/public/bower_components/no-vnc/include/novnc-custom.css
new file mode 100644
index 0000000000..f2f921cffc
--- /dev/null
+++ b/src/sunstone/public/bower_components/no-vnc/include/novnc-custom.css
@@ -0,0 +1,483 @@
+/*
+ * Based on the noVNC base CSS
+ * Copyright (C) 2012 Joel Martin
+ * Copyright (C) 2013 Samuel Mannehed for Cendio AB
+ * noVNC is licensed under the MPL 2.0 (see LICENSE.txt)
+ * This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
+ */
+
+body {
+ margin:0;
+ padding:0;
+ font-family: Helvetica;
+ /*Background image with light grey curve.*/
+ height:100%;
+}
+
+html {
+ height:100%;
+}
+
+#noVNC_controls ul {
+ list-style: none;
+ margin: 0px;
+ padding: 0px;
+}
+#noVNC_controls li {
+ padding-bottom:8px;
+}
+
+#noVNC_host {
+ width:150px;
+}
+#noVNC_port {
+ width: 80px;
+}
+#noVNC_password {
+ width: 150px;
+}
+#noVNC_encrypt {
+}
+#noVNC_path {
+ width: 100px;
+}
+#noVNC_connect_button {
+ width: 110px;
+ float:right;
+}
+
+#noVNC_buttons {
+ white-space: nowrap;
+}
+
+#noVNC_view_drag_button {
+ display: none;
+}
+#sendCtrlAltDelButton {
+ display: none;
+}
+#noVNC_xvp_buttons {
+ display: none;
+}
+#noVNC_mobile_buttons {
+ display: none;
+}
+
+#noVNC_extra_keys {
+ display: inline;
+ list-style-type: none;
+ padding: 0px;
+ margin: 0px;
+ position: relative;
+}
+
+.noVNC-buttons-left {
+ float: left;
+ z-index: 1;
+ position: relative;
+}
+
+.noVNC-buttons-right {
+ float:right;
+ right: 0px;
+ z-index: 2;
+ position: absolute;
+}
+
+#noVNC_status {
+ font-size: 12px;
+ padding-top: 4px;
+ height:32px;
+ text-align: center;
+ font-weight: bold;
+}
+
+#noVNC_settings_menu {
+ margin: 3px;
+ text-align: left;
+}
+#noVNC_settings_menu ul {
+ list-style: none;
+ margin: 0px;
+ padding: 0px;
+}
+
+#noVNC_apply {
+ float:right;
+}
+
+/* Do not set width/height for VNC_screen or VNC_canvas or incorrect
+ * scaling will occur. Canvas resizes to remote VNC settings */
+#noVNC_screen_pad {
+ margin: 0px;
+ padding: 0px;
+ height: 36px;
+}
+#noVNC_screen {
+ text-align: center;
+ display: table;
+ width:100%;
+ height:100%;
+ /*border-top-left-radius: 800px 600px;*/
+}
+
+#noVNC_container, #noVNC_canvas {
+ margin: 0px;
+ padding: 0px;
+}
+
+#noVNC_canvas {
+ left: 0px;
+}
+
+#VNC_clipboard_clear_button {
+ float:right;
+}
+#VNC_clipboard_text {
+ font-size: 11px;
+}
+
+#noVNC_clipboard_clear_button {
+ float:right;
+}
+
+/*Bubble contents divs*/
+#noVNC_settings {
+ display:none;
+ margin-top:73px;
+ right:20px;
+ position:fixed;
+}
+
+#noVNC_controls {
+ display:none;
+ margin-top:73px;
+ right:12px;
+ position:fixed;
+}
+#noVNC_controls.top:after {
+ right:15px;
+}
+
+#noVNC_description {
+ display:none;
+ position:fixed;
+
+ margin-top:73px;
+ right:20px;
+ left:20px;
+ padding:15px;
+ color:#000;
+
+ border:2px solid #E0E0E0;
+}
+
+#noVNC_popup_status_panel {
+ display:none;
+ position: fixed;
+ z-index: 1;
+
+ margin:15px;
+ margin-top:60px;
+ padding:15px;
+ width:auto;
+
+ text-align:center;
+ font-weight:bold;
+ word-wrap:break-word;
+ background:rgba(0,0,0,0.65);
+
+ -webkit-border-radius:10px;
+ -moz-border-radius:10px;
+ border-radius:10px;
+}
+
+#noVNC_xvp {
+ display:none;
+ margin-top:73px;
+ right:30px;
+ position:fixed;
+}
+#noVNC_xvp.top:after {
+ right:125px;
+}
+
+#noVNC_clipboard {
+ display:none;
+ margin-top:73px;
+ right:30px;
+ position:fixed;
+}
+#noVNC_clipboard.top:after {
+ right:85px;
+}
+
+#keyboardinput {
+ width:1px;
+ height:1px;
+ background-color:#fff;
+ color:#fff;
+ border:0;
+ position: relative;
+ left: -40px;
+ z-index: -1;
+}
+
+/*
+ * Advanced Styling
+ */
+
+.noVNC_status_normal {
+ color: #b2bdcd; /* Old browsers */
+}
+.noVNC_status_error {
+ color: #f04040; /* Old browsers */
+}
+.noVNC_status_warn {
+ color: #f0f040; /* Old browsers */
+}
+
+/* Control bar */
+#noVNC-control-bar {
+ position:fixed;
+
+ display:block;
+ height:36px;
+ left:0;
+ top:0;
+ width:100%;
+ z-index:200;
+}
+
+.noVNC_status_button {
+ padding: 4px 4px;
+ vertical-align: middle;
+ border:1px solid #869dbc;
+ -webkit-border-radius: 6px;
+ -moz-border-radius: 6px;
+ border-radius: 6px;
+ background: #b2bdcd; /* Old browsers */
+ background: -moz-linear-gradient(top, #b2bdcd 0%, #899cb3 49%, #7e93af 51%, #6e84a3 100%); /* FF3.6+ */
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#b2bdcd), color-stop(49%,#899cb3), color-stop(51%,#7e93af), color-stop(100%,#6e84a3)); /* Chrome,Safari4+ */
+ background: -webkit-linear-gradient(top, #b2bdcd 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%); /* Chrome10+,Safari5.1+ */
+ background: -o-linear-gradient(top, #b2bdcd 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%); /* Opera11.10+ */
+ background: -ms-linear-gradient(top, #b2bdcd 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%); /* IE10+ */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#b2bdcd', endColorstr='#6e84a3',GradientType=0 ); /* IE6-9 */
+ background: linear-gradient(top, #b2bdcd 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%); /* W3C */
+ /*box-shadow:inset 0.4px 0.4px 0.4px #000000;*/
+}
+
+.noVNC_status_button_selected {
+ padding: 4px 4px;
+ vertical-align: middle;
+ border:1px solid #4366a9;
+ -webkit-border-radius: 6px;
+ -moz-border-radius: 6px;
+ background: #779ced; /* Old browsers */
+ background: -moz-linear-gradient(top, #779ced 0%, #3970e0 49%, #2160dd 51%, #2463df 100%); /* FF3.6+ */
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#779ced), color-stop(49%,#3970e0), color-stop(51%,#2160dd), color-stop(100%,#2463df)); /* Chrome,Safari4+ */
+ background: -webkit-linear-gradient(top, #779ced 0%,#3970e0 49%,#2160dd 51%,#2463df 100%); /* Chrome10+,Safari5.1+ */
+ background: -o-linear-gradient(top, #779ced 0%,#3970e0 49%,#2160dd 51%,#2463df 100%); /* Opera11.10+ */
+ background: -ms-linear-gradient(top, #779ced 0%,#3970e0 49%,#2160dd 51%,#2463df 100%); /* IE10+ */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#779ced', endColorstr='#2463df',GradientType=0 ); /* IE6-9 */
+ background: linear-gradient(top, #779ced 0%,#3970e0 49%,#2160dd 51%,#2463df 100%); /* W3C */
+ /*box-shadow:inset 0.4px 0.4px 0.4px #000000;*/
+}
+
+
+/*Settings Bubble*/
+.triangle-right {
+ position:relative;
+ padding:15px;
+ margin:1em 0 3em;
+ color:#fff;
+ background:#fff; /* default background for browsers without gradient support */
+ /* css3 */
+ /*background:-webkit-gradient(linear, 0 0, 0 100%, from(#2e88c4), to(#075698));
+ background:-moz-linear-gradient(#2e88c4, #075698);
+ background:-o-linear-gradient(#2e88c4, #075698);
+ background:linear-gradient(#2e88c4, #075698);*/
+ -webkit-border-radius:10px;
+ -moz-border-radius:10px;
+ border-radius:10px;
+ color:#000;
+ border:2px solid #E0E0E0;
+}
+
+.triangle-right.top:after {
+ border-color: transparent #E0E0E0;
+ border-width: 20px 20px 0 0;
+ bottom: auto;
+ left: auto;
+ right: 50px;
+ top: -20px;
+}
+
+.triangle-right:after {
+ content:"";
+ position:absolute;
+ bottom:-20px; /* value = - border-top-width - border-bottom-width */
+ left:50px; /* controls horizontal position */
+ border-width:20px 0 0 20px; /* vary these values to change the angle of the vertex */
+ border-style:solid;
+ border-color:#E0E0E0 transparent;
+ /* reduce the damage in FF3.0 */
+ display:block;
+ width:0;
+}
+
+.triangle-right.top:after {
+ top:-40px; /* value = - border-top-width - border-bottom-width */
+ right:50px; /* controls horizontal position */
+ bottom:auto;
+ left:auto;
+ border-width:40px 40px 0 0; /* vary these values to change the angle of the vertex */
+ border-color:transparent #E0E0E0;
+}
+
+/*Default noVNC logo.*/
+/* From: http://fonts.googleapis.com/css?family=Orbitron:700 */
+@font-face {
+ font-family: 'Orbitron';
+ font-style: normal;
+ font-weight: 700;
+ src: local('?'), url('Orbitron700.woff') format('woff'),
+ url('Orbitron700.ttf') format('truetype');
+}
+
+#noVNC_logo {
+ margin-top: 170px;
+ margin-left: 10px;
+ color:yellow;
+ text-align:left;
+ font-family: 'Orbitron', 'OrbitronTTF', sans-serif;
+ line-height:90%;
+ text-shadow:
+ 5px 5px 0 #000,
+ -1px -1px 0 #000,
+ 1px -1px 0 #000,
+ -1px 1px 0 #000,
+ 1px 1px 0 #000;
+}
+
+
+#noVNC_logo span{
+ color:green;
+}
+
+/* ----------------------------------------
+ * Media sizing
+ * ----------------------------------------
+ */
+
+
+.noVNC_status_button {
+ font-size: 12px;
+}
+
+#noVNC_clipboard_text {
+ width: 500px;
+}
+
+#noVNC_logo {
+ font-size: 180px;
+}
+
+.noVNC-buttons-left {
+ padding-left: 10px;
+}
+
+.noVNC-buttons-right {
+ padding-right: 10px;
+}
+
+#noVNC_status {
+ z-index: 0;
+ position: absolute;
+ width: 100%;
+ margin-left: 0px;
+}
+
+#showExtraKeysButton { display: none; }
+#toggleCtrlButton { display: inline; }
+#toggleAltButton { display: inline; }
+#sendTabButton { display: inline; }
+#sendEscButton { display: inline; }
+
+/* left-align the status text on lower resolutions */
+@media screen and (max-width: 800px){
+ #noVNC_status {
+ z-index: 1;
+ position: relative;
+ width: auto;
+ float: left;
+ margin-left: 4px;
+ }
+}
+
+@media screen and (max-width: 640px){
+ #noVNC_clipboard_text {
+ width: 410px;
+ }
+ #noVNC_logo {
+ font-size: 150px;
+ }
+ .noVNC_status_button {
+ font-size: 10px;
+ }
+ .noVNC-buttons-left {
+ padding-left: 0px;
+ }
+ .noVNC-buttons-right {
+ padding-right: 0px;
+ }
+ /* collapse the extra keys on lower resolutions */
+ #showExtraKeysButton {
+ display: inline;
+ }
+ #toggleCtrlButton {
+ display: none;
+ position: absolute;
+ top: 30px;
+ left: 0px;
+ }
+ #toggleAltButton {
+ display: none;
+ position: absolute;
+ top: 65px;
+ left: 0px;
+ }
+ #sendTabButton {
+ display: none;
+ position: absolute;
+ top: 100px;
+ left: 0px;
+ }
+ #sendEscButton {
+ display: none;
+ position: absolute;
+ top: 135px;
+ left: 0px;
+ }
+}
+
+@media screen and (min-width: 321px) and (max-width: 480px) {
+ #noVNC_clipboard_text {
+ width: 250px;
+ }
+ #noVNC_logo {
+ font-size: 110px;
+ }
+}
+
+@media screen and (max-width: 320px) {
+ .noVNC_status_button {
+ font-size: 9px;
+ }
+ #noVNC_clipboard_text {
+ width: 220px;
+ }
+ #noVNC_logo {
+ font-size: 90px;
+ }
+}
diff --git a/src/sunstone/public/bower_components/spice-html5/.bower.json b/src/sunstone/public/bower_components/spice-html5/.bower.json
new file mode 100644
index 0000000000..5a2d893643
--- /dev/null
+++ b/src/sunstone/public/bower_components/spice-html5/.bower.json
@@ -0,0 +1,13 @@
+{
+ "name": "spice-html5",
+ "_release": "b926f062f3",
+ "_resolution": {
+ "type": "branch",
+ "branch": "master",
+ "commit": "b926f062f35e298f65828d9835f5b35895ec3729"
+ },
+ "_source": "git://anongit.freedesktop.org/spice/spice-html5",
+ "_target": "*",
+ "_originalSource": "git://anongit.freedesktop.org/spice/spice-html5",
+ "_direct": true
+}
\ No newline at end of file
diff --git a/src/sunstone/public/bower_components/spice-html5/.gitignore b/src/sunstone/public/bower_components/spice-html5/.gitignore
new file mode 100644
index 0000000000..33491a577a
--- /dev/null
+++ b/src/sunstone/public/bower_components/spice-html5/.gitignore
@@ -0,0 +1 @@
+spice-html5.spec
diff --git a/src/sunstone/public/bower_components/spice-html5/COPYING b/src/sunstone/public/bower_components/spice-html5/COPYING
new file mode 100644
index 0000000000..94a9ed024d
--- /dev/null
+++ b/src/sunstone/public/bower_components/spice-html5/COPYING
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
diff --git a/src/sunstone/public/bower_components/spice-html5/COPYING.LESSER b/src/sunstone/public/bower_components/spice-html5/COPYING.LESSER
new file mode 100644
index 0000000000..65c5ca88a6
--- /dev/null
+++ b/src/sunstone/public/bower_components/spice-html5/COPYING.LESSER
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/src/sunstone/public/bower_components/spice-html5/Makefile b/src/sunstone/public/bower_components/spice-html5/Makefile
new file mode 100644
index 0000000000..add307f4be
--- /dev/null
+++ b/src/sunstone/public/bower_components/spice-html5/Makefile
@@ -0,0 +1,68 @@
+# Copyright (C) 2012 by Jeremy P. White
+#
+# This file is part of spice-html5.
+#
+# spice-html5 is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# spice-html5 is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with spice-html5. If not, see .
+#
+
+DESTDIR := $(if $(DESTDIR),$(DESTDIR),/)
+datadir := $(if $(datadir),$(datadir),$(DESTDIR)/usr/share)
+tag := $(if $(tag),$(tag),HEAD)
+
+ifndef version
+ version = $(shell git describe $(tag)| grep spice-html5 | sed 's/^spice-html5-//')
+endif
+
+source_for_rpm = $(HOME)/rpmbuild/SOURCES/spice-html5-$(version).tar.gz
+
+.PHONY: usage spice-html5.spec rpm tar gittar local git install
+
+usage:
+ @echo "This project does not normally need to be built. See the README."
+ @echo " "
+ @echo "This Makefile is mostly used for creating RPM packages, which you"
+ @echo "can do by invoking 'make local' to use the current working directory,"
+ @echo "or 'make git' to use the latest git HEAD."
+ @echo "You can specify an alternate source tarball like this:"
+ @echo " make source=/my/alternate/source local"
+ @echo "You can specifcy a specific git tag like this:"
+ @echo " make tag=my_specific_tag git"
+ @echo "Results generally go in ~/rpmbuild"
+
+spice-html5.spec:
+ sed -e "s/VERSION/$(version)/" < spice-html5.spec.in > spice-html5.spec
+
+tar:
+ if [ "$(source)x" = "x" ] ; then \
+ tar -czf $(source_for_rpm) --exclude=.git --transform='s!^!spice-html5-$(version)/!' * ; \
+ else \
+ cp $(source) $(source_for_rpm) ; \
+ fi
+
+gittar:
+ if [ "$(source)x" = "x" ] ; then \
+ git archive --output=$(source_for_rpm) --prefix=spice-html5-$(version)/ $(tag) ; \
+ else \
+ cp $(source) $(source_for_rpm) ; \
+ fi
+
+rpm: spice-html5.spec
+ rpmbuild -ba spice-html5.spec
+
+local: tar rpm
+
+git: gittar rpm
+
+install:
+ find . \( -iname '*.html' -or -iname '*.js' -or -iname '*.css' \) -exec install --mode=644 -D {} $(datadir)/spice-html5/{} \;
diff --git a/src/sunstone/public/bower_components/spice-html5/README b/src/sunstone/public/bower_components/spice-html5/README
new file mode 100644
index 0000000000..506920907d
--- /dev/null
+++ b/src/sunstone/public/bower_components/spice-html5/README
@@ -0,0 +1,44 @@
+Spice Javascript client
+
+Instructions and status as of September, 2014.
+
+Requirements:
+
+ 1. Modern Firefox or Chrome (IE will work, but badly)
+
+ 2. A WebSocket proxy
+
+ I've used websockify:
+ https://github.com/kanaka/websockify
+ works great.
+
+
+ 3. A spice server
+
+ At this point, I've tested with qemu hosting
+ a Fedora image, a Vista image, and with Xspice.
+ Vista was pretty bad; I recommend either Linux or Xspice.
+
+Optional:
+ 1. A web server
+
+ With firefox, you can just open file:///your-path-to-spice.html-here
+
+ With Chrome, you have to set a secret config flag to do that, or
+ serve the files from a web server.
+
+
+Steps:
+
+ 1. Start the spice server
+
+ 2. Start websockify; my command line looks like this:
+ ./websockify 5959 localhost:5900
+
+ 3. Fire up spice.html, set host + port + password, and click start
+
+
+Status:
+
+ The TODO file should be a fairly comprehensive list of tasks
+ required to make this client more fully functional.
diff --git a/src/sunstone/public/bower_components/spice-html5/TODO b/src/sunstone/public/bower_components/spice-html5/TODO
new file mode 100644
index 0000000000..cf92c9c76b
--- /dev/null
+++ b/src/sunstone/public/bower_components/spice-html5/TODO
@@ -0,0 +1,59 @@
+Medium Tasks:
+
+ . Get the mouse event code out of spicemsg (and make spicemsg
+ *only* about messages)
+
+ . Change the message processing to be able to handle
+ an array of ArrayBuffers so we don't have to
+ use the combine function, which is presumed slow.
+
+ . Use the 'real' DataView if we have it
+
+ . Consider passing a status change event back to the front end
+ (e.g. indicators for numlock, connection status, all that jazz)
+
+ . Try to further Improve mouse position sends
+ - We now discard motions when we're more than 2 * SPICE_INPUT_MOTION_ACK_BUNCH
+ from an ack, just like the gtk client
+ - Other idea 1: queue them and only send when idle, but collapse first?
+ - Other idea 2: Time limit motion events
+
+ . Shift from the simplistic Makefile to an autoconf based Makefile
+ so we can try to support 'make install' on other systems.
+
+Big Tasks:
+
+ . Shift the code so it doesn't pollute the global namespace; that
+ will make it more usable as an embed or library
+
+ . Generate messages + enums from spice.proto
+
+ . Video:
+ - Need to pick a video codec and get support for it into spice server
+
+ . Explore clipboard
+ - Supporting it may require unpleasant hacks
+
+ . Fully flesh out image type support; plt, glz, and jpeg/alpha are likely
+ to be real work
+
+ . Fix the many limitations of Draw operation support (clipping, masking,
+ scaling, and so on)
+
+ . Implement direct websocket support for the spice server
+
+ . Profile the whole mess
+ - Initial profiling suggests image decompression is the big hog
+
+ . Improve agent support
+
+ . Build a test suite for measuring performance
+ - Latency, bandwidth, packet loss
+ - But how to quantify 'feel'?
+ - Suggestion: recordmydesktop to capture videos
+ Use something like cxtest to create scripts
+ Do this with varying latency/bandwidth, etc
+ We can play videos side by side
+ And potentially use tool like MSU Video Quality Measurement Tool
+ (SSIM is the concept for measuring how much frames differ)
+ - Key metric - how much cpu / memory / bandwidth per 'active' user
diff --git a/src/sunstone/public/bower_components/spice-html5/apache.conf.sample b/src/sunstone/public/bower_components/spice-html5/apache.conf.sample
new file mode 100644
index 0000000000..f3bd2fe08a
--- /dev/null
+++ b/src/sunstone/public/bower_components/spice-html5/apache.conf.sample
@@ -0,0 +1,10 @@
+#
+# spice-html5 is a Javascript SPICE client
+#
+Alias /spice /usr/share/spice-html5
+
+ # This page is broadly available, tune here to make it more restricted.
+ Allow from all
+ Satisfy Any
+ DirectoryIndex spice.html
+
diff --git a/src/sunstone/public/bower_components/spice-html5/atKeynames.js b/src/sunstone/public/bower_components/spice-html5/atKeynames.js
new file mode 100644
index 0000000000..e1e27fde8d
--- /dev/null
+++ b/src/sunstone/public/bower_components/spice-html5/atKeynames.js
@@ -0,0 +1,183 @@
+"use strict";
+/*
+ Copyright (C) 2012 by Aric Stewart
+
+ This file is part of spice-html5.
+
+ spice-html5 is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ spice-html5 is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with spice-html5. If not, see .
+*/
+/*
+ * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Thomas Roell not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Thomas Roell makes no representations
+ * about the suitability of this software for any purpose. It is provided
+ * "as is" without express or implied warranty.
+ *
+ * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THOMAS ROELL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+/*
+ * Copyright (c) 1994-2003 by The XFree86 Project, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of the copyright holder(s)
+ * and author(s) shall not be used in advertising or otherwise to promote
+ * the sale, use or other dealings in this Software without prior written
+ * authorization from the copyright holder(s) and author(s).
+ */
+
+/*
+ * NOTE: The AT/MF keyboards can generate (via the 8042) two (MF: three)
+ * sets of scancodes. Set3 can only be generated by a MF keyboard.
+ * Set2 sends a makecode for keypress, and the same code prefixed by a
+ * F0 for keyrelease. This is a little bit ugly to handle. Thus we use
+ * here for X386 the PC/XT compatible Set1. This set uses 8bit scancodes.
+ * Bit 7 ist set if the key is released. The code E0 switches to a
+ * different meaning to add the new MF cursorkeys, while not breaking old
+ * applications. E1 is another special prefix. Since I assume that there
+ * will be further versions of PC/XT scancode compatible keyboards, we
+ * may be in trouble one day.
+ *
+ * IDEA: 1) Use Set2 on AT84 keyboards and translate it to MF Set3.
+ * 2) Use the keyboards native set and translate it to common keysyms.
+ */
+
+/*
+ * definition of the AT84/MF101/MF102 Keyboard:
+ * ============================================================
+ * Defined Key Cap Glyphs Pressed value
+ * Key Name Main Also (hex) (dec)
+ * ---------------- ---------- ------- ------ ------
+ */
+
+var KEY_Escape =/* Escape 0x01 */ 1
+var KEY_1 =/* 1 ! 0x02 */ 2
+var KEY_2 =/* 2 @ 0x03 */ 3
+var KEY_3 =/* 3 # 0x04 */ 4
+var KEY_4 =/* 4 $ 0x05 */ 5
+var KEY_5 =/* 5 % 0x06 */ 6
+var KEY_6 =/* 6 ^ 0x07 */ 7
+var KEY_7 =/* 7 & 0x08 */ 8
+var KEY_8 =/* 8 * 0x09 */ 9
+var KEY_9 =/* 9 ( 0x0a */ 10
+var KEY_0 =/* 0 ) 0x0b */ 11
+var KEY_Minus =/* - (Minus) _ (Under) 0x0c */ 12
+var KEY_Equal =/* = (Equal) + 0x0d */ 13
+var KEY_BackSpace =/* Back Space 0x0e */ 14
+var KEY_Tab =/* Tab 0x0f */ 15
+var KEY_Q =/* Q 0x10 */ 16
+var KEY_W =/* W 0x11 */ 17
+var KEY_E =/* E 0x12 */ 18
+var KEY_R =/* R 0x13 */ 19
+var KEY_T =/* T 0x14 */ 20
+var KEY_Y =/* Y 0x15 */ 21
+var KEY_U =/* U 0x16 */ 22
+var KEY_I =/* I 0x17 */ 23
+var KEY_O =/* O 0x18 */ 24
+var KEY_P =/* P 0x19 */ 25
+var KEY_LBrace =/* [ { 0x1a */ 26
+var KEY_RBrace =/* ] } 0x1b */ 27
+var KEY_Enter =/* Enter 0x1c */ 28
+var KEY_LCtrl =/* Ctrl(left) 0x1d */ 29
+var KEY_A =/* A 0x1e */ 30
+var KEY_S =/* S 0x1f */ 31
+var KEY_D =/* D 0x20 */ 32
+var KEY_F =/* F 0x21 */ 33
+var KEY_G =/* G 0x22 */ 34
+var KEY_H =/* H 0x23 */ 35
+var KEY_J =/* J 0x24 */ 36
+var KEY_K =/* K 0x25 */ 37
+var KEY_L =/* L 0x26 */ 38
+var KEY_SemiColon =/* ;(SemiColon) :(Colon) 0x27 */ 39
+var KEY_Quote =/* ' (Apostr) " (Quote) 0x28 */ 40
+var KEY_Tilde =/* ` (Accent) ~ (Tilde) 0x29 */ 41
+var KEY_ShiftL =/* Shift(left) 0x2a */ 42
+var KEY_BSlash =/* \(BckSlash) |(VertBar)0x2b */ 43
+var KEY_Z =/* Z 0x2c */ 44
+var KEY_X =/* X 0x2d */ 45
+var KEY_C =/* C 0x2e */ 46
+var KEY_V =/* V 0x2f */ 47
+var KEY_B =/* B 0x30 */ 48
+var KEY_N =/* N 0x31 */ 49
+var KEY_M =/* M 0x32 */ 50
+var KEY_Comma =/* , (Comma) < (Less) 0x33 */ 51
+var KEY_Period =/* . (Period) >(Greater)0x34 */ 52
+var KEY_Slash =/* / (Slash) ? 0x35 */ 53
+var KEY_ShiftR =/* Shift(right) 0x36 */ 54
+var KEY_KP_Multiply =/* * 0x37 */ 55
+var KEY_Alt =/* Alt(left) 0x38 */ 56
+var KEY_Space =/* (SpaceBar) 0x39 */ 57
+var KEY_CapsLock =/* CapsLock 0x3a */ 58
+var KEY_F1 =/* F1 0x3b */ 59
+var KEY_F2 =/* F2 0x3c */ 60
+var KEY_F3 =/* F3 0x3d */ 61
+var KEY_F4 =/* F4 0x3e */ 62
+var KEY_F5 =/* F5 0x3f */ 63
+var KEY_F6 =/* F6 0x40 */ 64
+var KEY_F7 =/* F7 0x41 */ 65
+var KEY_F8 =/* F8 0x42 */ 66
+var KEY_F9 =/* F9 0x43 */ 67
+var KEY_F10 =/* F10 0x44 */ 68
+var KEY_NumLock =/* NumLock 0x45 */ 69
+var KEY_ScrollLock =/* ScrollLock 0x46 */ 70
+var KEY_KP_7 =/* 7 Home 0x47 */ 71
+var KEY_KP_8 =/* 8 Up 0x48 */ 72
+var KEY_KP_9 =/* 9 PgUp 0x49 */ 73
+var KEY_KP_Minus =/* - (Minus) 0x4a */ 74
+var KEY_KP_4 =/* 4 Left 0x4b */ 75
+var KEY_KP_5 =/* 5 0x4c */ 76
+var KEY_KP_6 =/* 6 Right 0x4d */ 77
+var KEY_KP_Plus =/* + (Plus) 0x4e */ 78
+var KEY_KP_1 =/* 1 End 0x4f */ 79
+var KEY_KP_2 =/* 2 Down 0x50 */ 80
+var KEY_KP_3 =/* 3 PgDown 0x51 */ 81
+var KEY_KP_0 =/* 0 Insert 0x52 */ 82
+var KEY_KP_Decimal =/* . (Decimal) Delete 0x53 */ 83
+var KEY_SysReqest =/* SysReqest 0x54 */ 84
+ /* NOTUSED 0x55 */
+var KEY_Less =/* < (Less) >(Greater) 0x56 */ 86
+var KEY_F11 =/* F11 0x57 */ 87
+var KEY_F12 =/* F12 0x58 */ 88
+
+var KEY_Prefix0 =/* special 0x60 */ 96
+var KEY_Prefix1 =/* specail 0x61 */ 97
diff --git a/src/sunstone/public/bower_components/spice-html5/bitmap.js b/src/sunstone/public/bower_components/spice-html5/bitmap.js
new file mode 100644
index 0000000000..03f512752b
--- /dev/null
+++ b/src/sunstone/public/bower_components/spice-html5/bitmap.js
@@ -0,0 +1,51 @@
+"use strict";
+/*
+ Copyright (C) 2012 by Jeremy P. White
+
+ This file is part of spice-html5.
+
+ spice-html5 is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ spice-html5 is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with spice-html5. If not, see .
+*/
+
+
+/*----------------------------------------------------------------------------
+** bitmap.js
+** Handle SPICE_IMAGE_TYPE_BITMAP
+**--------------------------------------------------------------------------*/
+function convert_spice_bitmap_to_web(context, spice_bitmap)
+{
+ var ret;
+ var offset, x;
+ var u8 = new Uint8Array(spice_bitmap.data);
+ if (spice_bitmap.format != SPICE_BITMAP_FMT_32BIT &&
+ spice_bitmap.format != SPICE_BITMAP_FMT_RGBA)
+ return undefined;
+
+ ret = context.createImageData(spice_bitmap.x, spice_bitmap.y);
+ for (offset = 0; offset < (spice_bitmap.y * spice_bitmap.stride); )
+ for (x = 0; x < spice_bitmap.x; x++, offset += 4)
+ {
+ ret.data[offset + 0 ] = u8[offset + 2];
+ ret.data[offset + 1 ] = u8[offset + 1];
+ ret.data[offset + 2 ] = u8[offset + 0];
+
+ // FIXME - We effectively treat all images as having SPICE_IMAGE_FLAGS_HIGH_BITS_SET
+ if (spice_bitmap.format == SPICE_BITMAP_FMT_32BIT)
+ ret.data[offset + 3] = 255;
+ else
+ ret.data[offset + 3] = u8[offset];
+ }
+
+ return ret;
+}
diff --git a/src/sunstone/public/bower_components/spice-html5/cursor.js b/src/sunstone/public/bower_components/spice-html5/cursor.js
new file mode 100644
index 0000000000..71e941d320
--- /dev/null
+++ b/src/sunstone/public/bower_components/spice-html5/cursor.js
@@ -0,0 +1,110 @@
+"use strict";
+/*
+ Copyright (C) 2012 by Jeremy P. White
+
+ This file is part of spice-html5.
+
+ spice-html5 is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ spice-html5 is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with spice-html5. If not, see .
+*/
+
+
+/*----------------------------------------------------------------------------
+** SpiceCursorConn
+** Drive the Spice Cursor Channel
+**--------------------------------------------------------------------------*/
+function SpiceCursorConn()
+{
+ SpiceConn.apply(this, arguments);
+}
+
+SpiceCursorConn.prototype = Object.create(SpiceConn.prototype);
+SpiceCursorConn.prototype.process_channel_message = function(msg)
+{
+ if (msg.type == SPICE_MSG_CURSOR_INIT)
+ {
+ var cursor_init = new SpiceMsgCursorInit(msg.data);
+ DEBUG > 1 && console.log("SpiceMsgCursorInit");
+ if (this.parent && this.parent.inputs &&
+ this.parent.inputs.mouse_mode == SPICE_MOUSE_MODE_SERVER)
+ {
+ // FIXME - this imagines that the server actually
+ // provides the current cursor position,
+ // instead of 0,0. As of May 11, 2012,
+ // that assumption was false :-(.
+ this.parent.inputs.mousex = cursor_init.position.x;
+ this.parent.inputs.mousey = cursor_init.position.y;
+ }
+ // FIXME - We don't handle most of the parameters here...
+ return true;
+ }
+
+ if (msg.type == SPICE_MSG_CURSOR_SET)
+ {
+ var cursor_set = new SpiceMsgCursorSet(msg.data);
+ DEBUG > 1 && console.log("SpiceMsgCursorSet");
+ if (cursor_set.flags & SPICE_CURSOR_FLAGS_NONE)
+ {
+ document.getElementById(this.parent.screen_id).style.cursor = "none";
+ return true;
+ }
+
+ if (cursor_set.flags > 0)
+ this.log_warn("FIXME: No support for cursor flags " + cursor_set.flags);
+
+ if (cursor_set.cursor.header.type != SPICE_CURSOR_TYPE_ALPHA)
+ {
+ this.log_warn("FIXME: No support for cursor type " + cursor_set.cursor.header.type);
+ return false;
+ }
+
+ this.set_cursor(cursor_set.cursor);
+
+ return true;
+ }
+
+ if (msg.type == SPICE_MSG_CURSOR_HIDE)
+ {
+ DEBUG > 1 && console.log("SpiceMsgCursorHide");
+ document.getElementById(this.parent.screen_id).style.cursor = "none";
+ return true;
+ }
+
+ if (msg.type == SPICE_MSG_CURSOR_RESET)
+ {
+ DEBUG > 1 && console.log("SpiceMsgCursorReset");
+ document.getElementById(this.parent.screen_id).style.cursor = "auto";
+ return true;
+ }
+
+ if (msg.type == SPICE_MSG_CURSOR_INVAL_ALL)
+ {
+ DEBUG > 1 && console.log("SpiceMsgCursorInvalAll");
+ // FIXME - There may be something useful to do here...
+ return true;
+ }
+
+ return false;
+}
+
+SpiceCursorConn.prototype.set_cursor = function(cursor)
+{
+ var pngstr = create_rgba_png(cursor.header.height, cursor.header.width, cursor.data);
+ var curstr = 'url(data:image/png,' + pngstr + ') ' +
+ cursor.header.hot_spot_x + ' ' + cursor.header.hot_spot_y + ", default";
+ var screen = document.getElementById(this.parent.screen_id);
+ screen.style.cursor = 'auto';
+ screen.style.cursor = curstr;
+ if (window.getComputedStyle(screen, null).cursor == 'auto')
+ SpiceSimulateCursor.simulate_cursor(this, cursor, screen, pngstr);
+}
diff --git a/src/sunstone/public/bower_components/spice-html5/display.js b/src/sunstone/public/bower_components/spice-html5/display.js
new file mode 100644
index 0000000000..2aa59850c1
--- /dev/null
+++ b/src/sunstone/public/bower_components/spice-html5/display.js
@@ -0,0 +1,823 @@
+"use strict";
+/*
+ Copyright (C) 2012 by Jeremy P. White
+
+ This file is part of spice-html5.
+
+ spice-html5 is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ spice-html5 is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with spice-html5. If not, see .
+*/
+
+
+/*----------------------------------------------------------------------------
+** FIXME: putImageData does not support Alpha blending
+** or compositing. So if we have data in an ImageData
+** format, we have to draw it onto a context,
+** and then use drawImage to put it onto the target,
+** as drawImage does alpha.
+**--------------------------------------------------------------------------*/
+function putImageDataWithAlpha(context, d, x, y)
+{
+ var c = document.createElement("canvas");
+ var t = c.getContext("2d");
+ c.setAttribute('width', d.width);
+ c.setAttribute('height', d.height);
+ t.putImageData(d, 0, 0);
+ context.drawImage(c, x, y, d.width, d.height);
+}
+
+/*----------------------------------------------------------------------------
+** FIXME: Spice will send an image with '0' alpha when it is intended to
+** go on a surface w/no alpha. So in that case, we have to strip
+** out the alpha. The test case for this was flux box; in a Xspice
+** server, right click on the desktop to get the menu; the top bar
+** doesn't paint/highlight correctly w/out this change.
+**--------------------------------------------------------------------------*/
+function stripAlpha(d)
+{
+ var i;
+ for (i = 0; i < (d.width * d.height * 4); i += 4)
+ d.data[i + 3] = 255;
+}
+
+/*----------------------------------------------------------------------------
+** SpiceDisplayConn
+** Drive the Spice Display Channel
+**--------------------------------------------------------------------------*/
+function SpiceDisplayConn()
+{
+ SpiceConn.apply(this, arguments);
+}
+
+SpiceDisplayConn.prototype = Object.create(SpiceConn.prototype);
+SpiceDisplayConn.prototype.process_channel_message = function(msg)
+{
+ if (msg.type == SPICE_MSG_DISPLAY_MARK)
+ {
+ // FIXME - DISPLAY_MARK not implemented (may be hard or impossible)
+ this.known_unimplemented(msg.type, "Display Mark");
+ return true;
+ }
+
+ if (msg.type == SPICE_MSG_DISPLAY_RESET)
+ {
+ DEBUG > 2 && console.log("Display reset");
+ this.surfaces[this.primary_surface].canvas.context.restore();
+ return true;
+ }
+
+ if (msg.type == SPICE_MSG_DISPLAY_DRAW_COPY)
+ {
+ var draw_copy = new SpiceMsgDisplayDrawCopy(msg.data);
+
+ DEBUG > 1 && this.log_draw("DrawCopy", draw_copy);
+
+ if (! draw_copy.base.box.is_same_size(draw_copy.data.src_area))
+ this.log_warn("FIXME: DrawCopy src_area is a different size than base.box; we do not handle that yet.");
+ if (draw_copy.base.clip.type != SPICE_CLIP_TYPE_NONE)
+ this.log_warn("FIXME: DrawCopy we don't handle clipping yet");
+ if (draw_copy.data.rop_descriptor != SPICE_ROPD_OP_PUT)
+ this.log_warn("FIXME: DrawCopy we don't handle ropd type: " + draw_copy.data.rop_descriptor);
+ if (draw_copy.data.mask.flags)
+ this.log_warn("FIXME: DrawCopy we don't handle mask flag: " + draw_copy.data.mask.flags);
+ if (draw_copy.data.mask.bitmap)
+ this.log_warn("FIXME: DrawCopy we don't handle mask");
+
+ if (draw_copy.data && draw_copy.data.src_bitmap)
+ {
+ if (draw_copy.data.src_bitmap.descriptor.flags &&
+ draw_copy.data.src_bitmap.descriptor.flags != SPICE_IMAGE_FLAGS_CACHE_ME &&
+ draw_copy.data.src_bitmap.descriptor.flags != SPICE_IMAGE_FLAGS_HIGH_BITS_SET)
+ {
+ this.log_warn("FIXME: DrawCopy unhandled image flags: " + draw_copy.data.src_bitmap.descriptor.flags);
+ DEBUG <= 1 && this.log_draw("DrawCopy", draw_copy);
+ }
+
+ if (draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_QUIC)
+ {
+ var canvas = this.surfaces[draw_copy.base.surface_id].canvas;
+ if (! draw_copy.data.src_bitmap.quic)
+ {
+ this.log_warn("FIXME: DrawCopy could not handle this QUIC file.");
+ return false;
+ }
+ var source_img = convert_spice_quic_to_web(canvas.context,
+ draw_copy.data.src_bitmap.quic);
+
+ return this.draw_copy_helper(
+ { base: draw_copy.base,
+ src_area: draw_copy.data.src_area,
+ image_data: source_img,
+ tag: "copyquic." + draw_copy.data.src_bitmap.quic.type,
+ has_alpha: (draw_copy.data.src_bitmap.quic.type == QUIC_IMAGE_TYPE_RGBA ? true : false) ,
+ descriptor : draw_copy.data.src_bitmap.descriptor
+ });
+ }
+ else if (draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_FROM_CACHE ||
+ draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_FROM_CACHE_LOSSLESS)
+ {
+ if (! this.cache || ! this.cache[draw_copy.data.src_bitmap.descriptor.id])
+ {
+ this.log_warn("FIXME: DrawCopy did not find image id " + draw_copy.data.src_bitmap.descriptor.id + " in cache.");
+ return false;
+ }
+
+ return this.draw_copy_helper(
+ { base: draw_copy.base,
+ src_area: draw_copy.data.src_area,
+ image_data: this.cache[draw_copy.data.src_bitmap.descriptor.id],
+ tag: "copycache." + draw_copy.data.src_bitmap.descriptor.id,
+ has_alpha: true, /* FIXME - may want this to be false... */
+ descriptor : draw_copy.data.src_bitmap.descriptor
+ });
+
+ /* FIXME - LOSSLESS CACHE ramifications not understood or handled */
+ }
+ else if (draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_SURFACE)
+ {
+ var source_context = this.surfaces[draw_copy.data.src_bitmap.surface_id].canvas.context;
+ var target_context = this.surfaces[draw_copy.base.surface_id].canvas.context;
+
+ var source_img = source_context.getImageData(
+ draw_copy.data.src_area.left, draw_copy.data.src_area.top,
+ draw_copy.data.src_area.right - draw_copy.data.src_area.left,
+ draw_copy.data.src_area.bottom - draw_copy.data.src_area.top);
+ var computed_src_area = new SpiceRect;
+ computed_src_area.top = computed_src_area.left = 0;
+ computed_src_area.right = source_img.width;
+ computed_src_area.bottom = source_img.height;
+
+ /* FIXME - there is a potential optimization here.
+ That is, if the surface is from 0,0, and
+ both surfaces are alpha surfaces, you should
+ be able to just do a drawImage, which should
+ save time. */
+
+ return this.draw_copy_helper(
+ { base: draw_copy.base,
+ src_area: computed_src_area,
+ image_data: source_img,
+ tag: "copysurf." + draw_copy.data.src_bitmap.surface_id,
+ has_alpha: this.surfaces[draw_copy.data.src_bitmap.surface_id].format == SPICE_SURFACE_FMT_32_xRGB ? false : true,
+ descriptor : draw_copy.data.src_bitmap.descriptor
+ });
+
+ return true;
+ }
+ else if (draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_JPEG)
+ {
+ if (! draw_copy.data.src_bitmap.jpeg)
+ {
+ this.log_warn("FIXME: DrawCopy could not handle this JPEG file.");
+ return false;
+ }
+
+ // FIXME - how lame is this. Be have it in binary format, and we have
+ // to put it into string to get it back into jpeg. Blech.
+ var tmpstr = "data:image/jpeg,";
+ var img = new Image;
+ var i;
+ var qdv = new Uint8Array(draw_copy.data.src_bitmap.jpeg.data);
+ for (i = 0; i < qdv.length; i++)
+ {
+ tmpstr += '%';
+ if (qdv[i] < 16)
+ tmpstr += '0';
+ tmpstr += qdv[i].toString(16);
+ }
+
+ img.o =
+ { base: draw_copy.base,
+ tag: "jpeg." + draw_copy.data.src_bitmap.surface_id,
+ descriptor : draw_copy.data.src_bitmap.descriptor,
+ sc : this,
+ };
+ img.onload = handle_draw_jpeg_onload;
+ img.src = tmpstr;
+
+ return true;
+ }
+ else if (draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_JPEG_ALPHA)
+ {
+ if (! draw_copy.data.src_bitmap.jpeg_alpha)
+ {
+ this.log_warn("FIXME: DrawCopy could not handle this JPEG ALPHA file.");
+ return false;
+ }
+
+ // FIXME - how lame is this. Be have it in binary format, and we have
+ // to put it into string to get it back into jpeg. Blech.
+ var tmpstr = "data:image/jpeg,";
+ var img = new Image;
+ var i;
+ var qdv = new Uint8Array(draw_copy.data.src_bitmap.jpeg_alpha.data);
+ for (i = 0; i < qdv.length; i++)
+ {
+ tmpstr += '%';
+ if (qdv[i] < 16)
+ tmpstr += '0';
+ tmpstr += qdv[i].toString(16);
+ }
+
+ img.o =
+ { base: draw_copy.base,
+ tag: "jpeg." + draw_copy.data.src_bitmap.surface_id,
+ descriptor : draw_copy.data.src_bitmap.descriptor,
+ sc : this,
+ };
+
+ if (this.surfaces[draw_copy.base.surface_id].format == SPICE_SURFACE_FMT_32_ARGB)
+ {
+
+ var canvas = this.surfaces[draw_copy.base.surface_id].canvas;
+ img.alpha_img = convert_spice_lz_to_web(canvas.context,
+ draw_copy.data.src_bitmap.jpeg_alpha.alpha);
+ }
+ img.onload = handle_draw_jpeg_onload;
+ img.src = tmpstr;
+
+ return true;
+ }
+ else if (draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_BITMAP)
+ {
+ var canvas = this.surfaces[draw_copy.base.surface_id].canvas;
+ if (! draw_copy.data.src_bitmap.bitmap)
+ {
+ this.log_err("null bitmap");
+ return false;
+ }
+
+ var source_img = convert_spice_bitmap_to_web(canvas.context,
+ draw_copy.data.src_bitmap.bitmap);
+ if (! source_img)
+ {
+ this.log_warn("FIXME: Unable to interpret bitmap of format: " +
+ draw_copy.data.src_bitmap.bitmap.format);
+ return false;
+ }
+
+ return this.draw_copy_helper(
+ { base: draw_copy.base,
+ src_area: draw_copy.data.src_area,
+ image_data: source_img,
+ tag: "bitmap." + draw_copy.data.src_bitmap.bitmap.format,
+ has_alpha: draw_copy.data.src_bitmap.bitmap == SPICE_BITMAP_FMT_32BIT ? false : true,
+ descriptor : draw_copy.data.src_bitmap.descriptor
+ });
+ }
+ else if (draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_LZ_RGB)
+ {
+ var canvas = this.surfaces[draw_copy.base.surface_id].canvas;
+ if (! draw_copy.data.src_bitmap.lz_rgb)
+ {
+ this.log_err("null lz_rgb ");
+ return false;
+ }
+
+ if (draw_copy.data.src_bitmap.lz_rgb.top_down != 1)
+ this.log_warn("FIXME: Implement non top down support for lz_rgb");
+
+ var source_img = convert_spice_lz_to_web(canvas.context,
+ draw_copy.data.src_bitmap.lz_rgb);
+ if (! source_img)
+ {
+ this.log_warn("FIXME: Unable to interpret bitmap of type: " +
+ draw_copy.data.src_bitmap.lz_rgb.type);
+ return false;
+ }
+
+ return this.draw_copy_helper(
+ { base: draw_copy.base,
+ src_area: draw_copy.data.src_area,
+ image_data: source_img,
+ tag: "lz_rgb." + draw_copy.data.src_bitmap.lz_rgb.type,
+ has_alpha: draw_copy.data.src_bitmap.lz_rgb.type == LZ_IMAGE_TYPE_RGBA ? true : false ,
+ descriptor : draw_copy.data.src_bitmap.descriptor
+ });
+ }
+ else
+ {
+ this.log_warn("FIXME: DrawCopy unhandled image type: " + draw_copy.data.src_bitmap.descriptor.type);
+ this.log_draw("DrawCopy", draw_copy);
+ return false;
+ }
+ }
+
+ this.log_warn("FIXME: DrawCopy no src_bitmap.");
+ return false;
+ }
+
+ if (msg.type == SPICE_MSG_DISPLAY_DRAW_FILL)
+ {
+ var draw_fill = new SpiceMsgDisplayDrawFill(msg.data);
+
+ DEBUG > 1 && this.log_draw("DrawFill", draw_fill);
+
+ if (draw_fill.data.rop_descriptor != SPICE_ROPD_OP_PUT)
+ this.log_warn("FIXME: DrawFill we don't handle ropd type: " + draw_fill.data.rop_descriptor);
+ if (draw_fill.data.mask.flags)
+ this.log_warn("FIXME: DrawFill we don't handle mask flag: " + draw_fill.data.mask.flags);
+ if (draw_fill.data.mask.bitmap)
+ this.log_warn("FIXME: DrawFill we don't handle mask");
+
+ if (draw_fill.data.brush.type == SPICE_BRUSH_TYPE_SOLID)
+ {
+ // FIXME - do brushes ever have alpha?
+ var color = draw_fill.data.brush.color & 0xffffff;
+ var color_str = "rgb(" + (color >> 16) + ", " + ((color >> 8) & 0xff) + ", " + (color & 0xff) + ")";
+ this.surfaces[draw_fill.base.surface_id].canvas.context.fillStyle = color_str;
+
+ this.surfaces[draw_fill.base.surface_id].canvas.context.fillRect(
+ draw_fill.base.box.left, draw_fill.base.box.top,
+ draw_fill.base.box.right - draw_fill.base.box.left,
+ draw_fill.base.box.bottom - draw_fill.base.box.top);
+
+ if (DUMP_DRAWS && this.parent.dump_id)
+ {
+ var debug_canvas = document.createElement("canvas");
+ debug_canvas.setAttribute('width', this.surfaces[draw_fill.base.surface_id].canvas.width);
+ debug_canvas.setAttribute('height', this.surfaces[draw_fill.base.surface_id].canvas.height);
+ debug_canvas.setAttribute('id', "fillbrush." + draw_fill.base.surface_id + "." + this.surfaces[draw_fill.base.surface_id].draw_count);
+ debug_canvas.getContext("2d").fillStyle = color_str;
+ debug_canvas.getContext("2d").fillRect(
+ draw_fill.base.box.left, draw_fill.base.box.top,
+ draw_fill.base.box.right - draw_fill.base.box.left,
+ draw_fill.base.box.bottom - draw_fill.base.box.top);
+ document.getElementById(this.parent.dump_id).appendChild(debug_canvas);
+ }
+
+ this.surfaces[draw_fill.base.surface_id].draw_count++;
+
+ }
+ else
+ {
+ this.log_warn("FIXME: DrawFill can't handle brush type: " + draw_fill.data.brush.type);
+ }
+ return true;
+ }
+
+ if (msg.type == SPICE_MSG_DISPLAY_COPY_BITS)
+ {
+ var copy_bits = new SpiceMsgDisplayCopyBits(msg.data);
+
+ DEBUG > 1 && this.log_draw("CopyBits", copy_bits);
+
+ var source_canvas = this.surfaces[copy_bits.base.surface_id].canvas;
+ var source_context = source_canvas.context;
+
+ var width = source_canvas.width - copy_bits.src_pos.x;
+ var height = source_canvas.height - copy_bits.src_pos.y;
+ if (width > (copy_bits.base.box.right - copy_bits.base.box.left))
+ width = copy_bits.base.box.right - copy_bits.base.box.left;
+ if (height > (copy_bits.base.box.bottom - copy_bits.base.box.top))
+ height = copy_bits.base.box.bottom - copy_bits.base.box.top;
+
+ var source_img = source_context.getImageData(
+ copy_bits.src_pos.x, copy_bits.src_pos.y, width, height);
+ //source_context.putImageData(source_img, copy_bits.base.box.left, copy_bits.base.box.top);
+ putImageDataWithAlpha(source_context, source_img, copy_bits.base.box.left, copy_bits.base.box.top);
+
+ if (DUMP_DRAWS && this.parent.dump_id)
+ {
+ var debug_canvas = document.createElement("canvas");
+ debug_canvas.setAttribute('width', width);
+ debug_canvas.setAttribute('height', height);
+ debug_canvas.setAttribute('id', "copybits" + copy_bits.base.surface_id + "." + this.surfaces[copy_bits.base.surface_id].draw_count);
+ debug_canvas.getContext("2d").putImageData(source_img, 0, 0);
+ document.getElementById(this.parent.dump_id).appendChild(debug_canvas);
+ }
+
+
+ this.surfaces[copy_bits.base.surface_id].draw_count++;
+ return true;
+ }
+
+ if (msg.type == SPICE_MSG_DISPLAY_INVAL_ALL_PALETTES)
+ {
+ this.known_unimplemented(msg.type, "Inval All Palettes");
+ return true;
+ }
+
+ if (msg.type == SPICE_MSG_DISPLAY_SURFACE_CREATE)
+ {
+ if (! ("surfaces" in this))
+ this.surfaces = [];
+
+ var m = new SpiceMsgSurfaceCreate(msg.data);
+ DEBUG > 1 && console.log(this.type + ": MsgSurfaceCreate id " + m.surface.surface_id
+ + "; " + m.surface.width + "x" + m.surface.height
+ + "; format " + m.surface.format
+ + "; flags " + m.surface.flags);
+ if (m.surface.format != SPICE_SURFACE_FMT_32_xRGB &&
+ m.surface.format != SPICE_SURFACE_FMT_32_ARGB)
+ {
+ this.log_warn("FIXME: cannot handle surface format " + m.surface.format + " yet.");
+ return false;
+ }
+
+ var canvas = document.createElement("canvas");
+ canvas.setAttribute('width', m.surface.width);
+ canvas.setAttribute('height', m.surface.height);
+ canvas.setAttribute('id', "spice_surface_" + m.surface.surface_id);
+ canvas.setAttribute('tabindex', m.surface.surface_id);
+ canvas.context = canvas.getContext("2d");
+
+ if (DUMP_CANVASES && this.parent.dump_id)
+ document.getElementById(this.parent.dump_id).appendChild(canvas);
+
+ m.surface.canvas = canvas;
+ m.surface.draw_count = 0;
+ this.surfaces[m.surface.surface_id] = m.surface;
+
+ if (m.surface.flags & SPICE_SURFACE_FLAGS_PRIMARY)
+ {
+ this.primary_surface = m.surface.surface_id;
+
+ /* This .save() is done entirely to enable SPICE_MSG_DISPLAY_RESET */
+ canvas.context.save();
+ document.getElementById(this.parent.screen_id).appendChild(canvas);
+
+ /* We're going to leave width dynamic, but correctly set the height */
+ document.getElementById(this.parent.screen_id).style.height = m.surface.height + "px";
+ this.hook_events();
+ }
+ return true;
+ }
+
+ if (msg.type == SPICE_MSG_DISPLAY_SURFACE_DESTROY)
+ {
+ var m = new SpiceMsgSurfaceDestroy(msg.data);
+ DEBUG > 1 && console.log(this.type + ": MsgSurfaceDestroy id " + m.surface_id);
+ this.delete_surface(m.surface_id);
+ return true;
+ }
+
+ if (msg.type == SPICE_MSG_DISPLAY_STREAM_CREATE)
+ {
+ var m = new SpiceMsgDisplayStreamCreate(msg.data);
+ DEBUG > 1 && console.log(this.type + ": MsgStreamCreate id" + m.id);
+ if (!this.streams)
+ this.streams = new Array();
+ if (this.streams[m.id])
+ console.log("Stream already exists");
+ else
+ this.streams[m.id] = m;
+ if (m.codec_type != SPICE_VIDEO_CODEC_TYPE_MJPEG)
+ console.log("Unhandled stream codec: "+m.codec_type);
+ return true;
+ }
+
+ if (msg.type == SPICE_MSG_DISPLAY_STREAM_DATA)
+ {
+ var m = new SpiceMsgDisplayStreamData(msg.data);
+ if (!this.streams[m.base.id])
+ {
+ console.log("no stream for data");
+ return false;
+ }
+ if (this.streams[m.base.id].codec_type === SPICE_VIDEO_CODEC_TYPE_MJPEG)
+ {
+ var tmpstr = "data:image/jpeg,";
+ var img = new Image;
+ var i;
+ for (i = 0; i < m.data.length; i++)
+ {
+ tmpstr += '%';
+ if (m.data[i] < 16)
+ tmpstr += '0';
+ tmpstr += m.data[i].toString(16);
+ }
+ var strm_base = new SpiceMsgDisplayBase();
+ strm_base.surface_id = this.streams[m.base.id].surface_id;
+ strm_base.box = this.streams[m.base.id].dest;
+ strm_base.clip = this.streams[m.base.id].clip;
+ img.o =
+ { base: strm_base,
+ tag: "mjpeg." + m.base.id,
+ descriptor: null,
+ sc : this,
+ };
+ img.onload = handle_draw_jpeg_onload;
+ img.src = tmpstr;
+ }
+ return true;
+ }
+
+ if (msg.type == SPICE_MSG_DISPLAY_STREAM_CLIP)
+ {
+ var m = new SpiceMsgDisplayStreamClip(msg.data);
+ DEBUG > 1 && console.log(this.type + ": MsgStreamClip id" + m.id);
+ this.streams[m.id].clip = m.clip;
+ return true;
+ }
+
+ if (msg.type == SPICE_MSG_DISPLAY_STREAM_DESTROY)
+ {
+ var m = new SpiceMsgDisplayStreamDestroy(msg.data);
+ DEBUG > 1 && console.log(this.type + ": MsgStreamDestroy id" + m.id);
+ this.streams[m.id] = undefined;
+ return true;
+ }
+ if (msg.type == SPICE_MSG_DISPLAY_INVAL_LIST)
+ {
+ var m = new SpiceMsgDisplayInvalList(msg.data);
+ var i;
+ DEBUG > 1 && console.log(this.type + ": MsgInvalList " + m.count + " items");
+ for (i = 0; i < m.count; i++)
+ if (this.cache[m.resources[i].id] != undefined)
+ delete this.cache[m.resources[i].id];
+ return true;
+ }
+
+ return false;
+}
+
+SpiceDisplayConn.prototype.delete_surface = function(surface_id)
+{
+ var canvas = document.getElementById("spice_surface_" + surface_id);
+ if (DUMP_CANVASES && this.parent.dump_id)
+ document.getElementById(this.parent.dump_id).removeChild(canvas);
+ if (this.primary_surface == surface_id)
+ {
+ this.unhook_events();
+ this.primary_surface = undefined;
+ document.getElementById(this.parent.screen_id).removeChild(canvas);
+ }
+
+ delete this.surfaces[surface_id];
+}
+
+
+SpiceDisplayConn.prototype.draw_copy_helper = function(o)
+{
+
+ var canvas = this.surfaces[o.base.surface_id].canvas;
+ if (o.has_alpha)
+ {
+ /* FIXME - This is based on trial + error, not a serious thoughtful
+ analysis of what Spice requires. See display.js for more. */
+ if (this.surfaces[o.base.surface_id].format == SPICE_SURFACE_FMT_32_xRGB)
+ {
+ stripAlpha(o.image_data);
+ canvas.context.putImageData(o.image_data, o.base.box.left, o.base.box.top);
+ }
+ else
+ putImageDataWithAlpha(canvas.context, o.image_data,
+ o.base.box.left, o.base.box.top);
+ }
+ else
+ canvas.context.putImageData(o.image_data, o.base.box.left, o.base.box.top);
+
+ if (o.src_area.left > 0 || o.src_area.top > 0)
+ {
+ this.log_warn("FIXME: DrawCopy not shifting draw copies just yet...");
+ }
+
+ if (o.descriptor && (o.descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME))
+ {
+ if (! ("cache" in this))
+ this.cache = {};
+ this.cache[o.descriptor.id] = o.image_data;
+ }
+
+ if (DUMP_DRAWS && this.parent.dump_id)
+ {
+ var debug_canvas = document.createElement("canvas");
+ debug_canvas.setAttribute('width', o.image_data.width);
+ debug_canvas.setAttribute('height', o.image_data.height);
+ debug_canvas.setAttribute('id', o.tag + "." +
+ this.surfaces[o.base.surface_id].draw_count + "." +
+ o.base.surface_id + "@" + o.base.box.left + "x" + o.base.box.top);
+ debug_canvas.getContext("2d").putImageData(o.image_data, 0, 0);
+ document.getElementById(this.parent.dump_id).appendChild(debug_canvas);
+ }
+
+ this.surfaces[o.base.surface_id].draw_count++;
+
+ return true;
+}
+
+
+SpiceDisplayConn.prototype.log_draw = function(prefix, draw)
+{
+ var str = prefix + "." + draw.base.surface_id + "." + this.surfaces[draw.base.surface_id].draw_count + ": ";
+ str += "base.box " + draw.base.box.left + ", " + draw.base.box.top + " to " +
+ draw.base.box.right + ", " + draw.base.box.bottom;
+ str += "; clip.type " + draw.base.clip.type;
+
+ if (draw.data)
+ {
+ if (draw.data.src_area)
+ str += "; src_area " + draw.data.src_area.left + ", " + draw.data.src_area.top + " to "
+ + draw.data.src_area.right + ", " + draw.data.src_area.bottom;
+
+ if (draw.data.src_bitmap && draw.data.src_bitmap != null)
+ {
+ str += "; src_bitmap id: " + draw.data.src_bitmap.descriptor.id;
+ str += "; src_bitmap width " + draw.data.src_bitmap.descriptor.width + ", height " + draw.data.src_bitmap.descriptor.height;
+ str += "; src_bitmap type " + draw.data.src_bitmap.descriptor.type + ", flags " + draw.data.src_bitmap.descriptor.flags;
+ if (draw.data.src_bitmap.surface_id !== undefined)
+ str += "; src_bitmap surface_id " + draw.data.src_bitmap.surface_id;
+ if (draw.data.src_bitmap.quic)
+ str += "; QUIC type " + draw.data.src_bitmap.quic.type +
+ "; width " + draw.data.src_bitmap.quic.width +
+ "; height " + draw.data.src_bitmap.quic.height ;
+ if (draw.data.src_bitmap.lz_rgb)
+ str += "; LZ_RGB length " + draw.data.src_bitmap.lz_rgb.length +
+ "; magic " + draw.data.src_bitmap.lz_rgb.magic +
+ "; version 0x" + draw.data.src_bitmap.lz_rgb.version.toString(16) +
+ "; type " + draw.data.src_bitmap.lz_rgb.type +
+ "; width " + draw.data.src_bitmap.lz_rgb.width +
+ "; height " + draw.data.src_bitmap.lz_rgb.height +
+ "; stride " + draw.data.src_bitmap.lz_rgb.stride +
+ "; top down " + draw.data.src_bitmap.lz_rgb.top_down;
+ }
+ else
+ str += "; src_bitmap is null";
+
+ if (draw.data.brush)
+ {
+ if (draw.data.brush.type == SPICE_BRUSH_TYPE_SOLID)
+ str += "; brush.color 0x" + draw.data.brush.color.toString(16);
+ if (draw.data.brush.type == SPICE_BRUSH_TYPE_PATTERN)
+ {
+ str += "; brush.pat ";
+ if (draw.data.brush.pattern.pat != null)
+ str += "[SpiceImage]";
+ else
+ str += "[null]";
+ str += " at " + draw.data.brush.pattern.pos.x + ", " + draw.data.brush.pattern.pos.y;
+ }
+ }
+
+ str += "; rop_descriptor " + draw.data.rop_descriptor;
+ if (draw.data.scale_mode !== undefined)
+ str += "; scale_mode " + draw.data.scale_mode;
+ str += "; mask.flags " + draw.data.mask.flags;
+ str += "; mask.pos " + draw.data.mask.pos.x + ", " + draw.data.mask.pos.y;
+ if (draw.data.mask.bitmap != null)
+ {
+ str += "; mask.bitmap width " + draw.data.mask.bitmap.descriptor.width + ", height " + draw.data.mask.bitmap.descriptor.height;
+ str += "; mask.bitmap type " + draw.data.mask.bitmap.descriptor.type + ", flags " + draw.data.mask.bitmap.descriptor.flags;
+ }
+ else
+ str += "; mask.bitmap is null";
+ }
+
+ console.log(str);
+}
+
+SpiceDisplayConn.prototype.hook_events = function()
+{
+ if (this.primary_surface !== undefined)
+ {
+ var canvas = this.surfaces[this.primary_surface].canvas;
+ canvas.sc = this.parent;
+ canvas.addEventListener('mousemove', handle_mousemove);
+ canvas.addEventListener('mousedown', handle_mousedown);
+ canvas.addEventListener('contextmenu', handle_contextmenu);
+ canvas.addEventListener('mouseup', handle_mouseup);
+ canvas.addEventListener('keydown', handle_keydown);
+ canvas.addEventListener('keyup', handle_keyup);
+ canvas.addEventListener('mouseout', handle_mouseout);
+ canvas.addEventListener('mouseover', handle_mouseover);
+ canvas.addEventListener('mousewheel', handle_mousewheel);
+ canvas.focus();
+ }
+}
+
+SpiceDisplayConn.prototype.unhook_events = function()
+{
+ if (this.primary_surface !== undefined)
+ {
+ var canvas = this.surfaces[this.primary_surface].canvas;
+ canvas.removeEventListener('mousemove', handle_mousemove);
+ canvas.removeEventListener('mousedown', handle_mousedown);
+ canvas.removeEventListener('contextmenu', handle_contextmenu);
+ canvas.removeEventListener('mouseup', handle_mouseup);
+ canvas.removeEventListener('keydown', handle_keydown);
+ canvas.removeEventListener('keyup', handle_keyup);
+ canvas.removeEventListener('mouseout', handle_mouseout);
+ canvas.removeEventListener('mouseover', handle_mouseover);
+ canvas.removeEventListener('mousewheel', handle_mousewheel);
+ }
+}
+
+
+SpiceDisplayConn.prototype.destroy_surfaces = function()
+{
+ for (var s in this.surfaces)
+ {
+ this.delete_surface(this.surfaces[s].surface_id);
+ }
+
+ this.surfaces = undefined;
+}
+
+
+function handle_mouseover(e)
+{
+ this.focus();
+}
+
+function handle_mouseout(e)
+{
+ if (this.sc && this.sc.cursor && this.sc.cursor.spice_simulated_cursor)
+ this.sc.cursor.spice_simulated_cursor.style.display = 'none';
+ this.blur();
+}
+
+function handle_draw_jpeg_onload()
+{
+ var temp_canvas = null;
+ var context;
+
+ /*------------------------------------------------------------
+ ** FIXME:
+ ** The helper should be extended to be able to handle actual HtmlImageElements
+ ** ...and the cache should be modified to do so as well
+ **----------------------------------------------------------*/
+ if (this.o.sc.surfaces[this.o.base.surface_id] === undefined)
+ {
+ // This can happen; if the jpeg image loads after our surface
+ // has been destroyed (e.g. open a menu, close it quickly),
+ // we'll find we have no surface.
+ DEBUG > 2 && this.o.sc.log_info("Discarding jpeg; presumed lost surface " + this.o.base.surface_id);
+ temp_canvas = document.createElement("canvas");
+ temp_canvas.setAttribute('width', this.o.base.box.right);
+ temp_canvas.setAttribute('height', this.o.base.box.bottom);
+ context = temp_canvas.getContext("2d");
+ }
+ else
+ context = this.o.sc.surfaces[this.o.base.surface_id].canvas.context;
+
+ if (this.alpha_img)
+ {
+ var c = document.createElement("canvas");
+ var t = c.getContext("2d");
+ c.setAttribute('width', this.alpha_img.width);
+ c.setAttribute('height', this.alpha_img.height);
+ t.putImageData(this.alpha_img, 0, 0);
+ t.globalCompositeOperation = 'source-in';
+ t.drawImage(this, 0, 0);
+
+ context.drawImage(c, this.o.base.box.left, this.o.base.box.top);
+
+ if (this.o.descriptor &&
+ (this.o.descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME))
+ {
+ if (! ("cache" in this.o.sc))
+ this.o.sc.cache = {};
+
+ this.o.sc.cache[this.o.descriptor.id] =
+ t.getImageData(0, 0,
+ this.alpha_img.width,
+ this.alpha_img.height);
+ }
+ }
+ else
+ {
+ context.drawImage(this, this.o.base.box.left, this.o.base.box.top);
+
+ // Give the Garbage collector a clue to recycle this; avoids
+ // fairly massive memory leaks during video playback
+ this.src = null;
+
+ if (this.o.descriptor &&
+ (this.o.descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME))
+ {
+ if (! ("cache" in this.o.sc))
+ this.o.sc.cache = {};
+
+ this.o.sc.cache[this.o.descriptor.id] =
+ context.getImageData(this.o.base.box.left, this.o.base.box.top,
+ this.o.base.box.right - this.o.base.box.left,
+ this.o.base.box.bottom - this.o.base.box.top);
+ }
+ }
+
+ if (temp_canvas == null)
+ {
+ if (DUMP_DRAWS && this.o.sc.parent.dump_id)
+ {
+ var debug_canvas = document.createElement("canvas");
+ debug_canvas.setAttribute('id', this.o.tag + "." +
+ this.o.sc.surfaces[this.o.base.surface_id].draw_count + "." +
+ this.o.base.surface_id + "@" + this.o.base.box.left + "x" + this.o.base.box.top);
+ debug_canvas.getContext("2d").drawImage(this, 0, 0);
+ document.getElementById(this.o.sc.parent.dump_id).appendChild(debug_canvas);
+ }
+
+ this.o.sc.surfaces[this.o.base.surface_id].draw_count++;
+ }
+}
diff --git a/src/sunstone/public/bower_components/spice-html5/enums.js b/src/sunstone/public/bower_components/spice-html5/enums.js
new file mode 100644
index 0000000000..d99b38edca
--- /dev/null
+++ b/src/sunstone/public/bower_components/spice-html5/enums.js
@@ -0,0 +1,324 @@
+"use strict";
+/*
+ Copyright (C) 2012 by Jeremy P. White
+
+ This file is part of spice-html5.
+
+ spice-html5 is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ spice-html5 is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with spice-html5. If not, see .
+*/
+
+
+/*----------------------------------------------------------------------------
+** enums.js
+** 'constants' for Spice
+**--------------------------------------------------------------------------*/
+var SPICE_MAGIC = "REDQ";
+var SPICE_VERSION_MAJOR = 2;
+var SPICE_VERSION_MINOR = 2;
+
+var SPICE_CONNECT_TIMEOUT = (30 * 1000);
+
+var SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION = 0;
+var SPICE_COMMON_CAP_AUTH_SPICE = 1;
+var SPICE_COMMON_CAP_AUTH_SASL = 2;
+var SPICE_COMMON_CAP_MINI_HEADER = 3;
+
+var SPICE_TICKET_KEY_PAIR_LENGTH = 1024;
+var SPICE_TICKET_PUBKEY_BYTES = (SPICE_TICKET_KEY_PAIR_LENGTH / 8 + 34);
+
+var SPICE_LINK_ERR_OK = 0,
+ SPICE_LINK_ERR_ERROR = 1,
+ SPICE_LINK_ERR_INVALID_MAGIC = 2,
+ SPICE_LINK_ERR_INVALID_DATA = 3,
+ SPICE_LINK_ERR_VERSION_MISMATCH = 4,
+ SPICE_LINK_ERR_NEED_SECURED = 5,
+ SPICE_LINK_ERR_NEED_UNSECURED = 6,
+ SPICE_LINK_ERR_PERMISSION_DENIED = 7,
+ SPICE_LINK_ERR_BAD_CONNECTION_ID = 8,
+ SPICE_LINK_ERR_CHANNEL_NOT_AVAILABLE = 9;
+
+var SPICE_MSG_MIGRATE = 1;
+var SPICE_MSG_MIGRATE_DATA = 2;
+var SPICE_MSG_SET_ACK = 3;
+var SPICE_MSG_PING = 4;
+var SPICE_MSG_WAIT_FOR_CHANNELS = 5;
+var SPICE_MSG_DISCONNECTING = 6;
+var SPICE_MSG_NOTIFY = 7;
+var SPICE_MSG_LIST = 8;
+
+var SPICE_MSG_MAIN_MIGRATE_BEGIN = 101;
+var SPICE_MSG_MAIN_MIGRATE_CANCEL = 102;
+var SPICE_MSG_MAIN_INIT = 103;
+var SPICE_MSG_MAIN_CHANNELS_LIST = 104;
+var SPICE_MSG_MAIN_MOUSE_MODE = 105;
+var SPICE_MSG_MAIN_MULTI_MEDIA_TIME = 106;
+var SPICE_MSG_MAIN_AGENT_CONNECTED = 107;
+var SPICE_MSG_MAIN_AGENT_DISCONNECTED = 108;
+var SPICE_MSG_MAIN_AGENT_DATA = 109;
+var SPICE_MSG_MAIN_AGENT_TOKEN = 110;
+var SPICE_MSG_MAIN_MIGRATE_SWITCH_HOST = 111;
+var SPICE_MSG_MAIN_MIGRATE_END = 112;
+var SPICE_MSG_MAIN_NAME = 113;
+var SPICE_MSG_MAIN_UUID = 114;
+var SPICE_MSG_MAIN_AGENT_CONNECTED_TOKENS = 115;
+var SPICE_MSG_MAIN_MIGRATE_BEGIN_SEAMLESS = 116;
+var SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_ACK = 117;
+var SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_NACK = 118;
+var SPICE_MSG_END_MAIN = 119;
+
+
+
+var SPICE_MSGC_ACK_SYNC = 1;
+var SPICE_MSGC_ACK = 2;
+var SPICE_MSGC_PONG = 3;
+var SPICE_MSGC_MIGRATE_FLUSH_MARK = 4;
+var SPICE_MSGC_MIGRATE_DATA = 5;
+var SPICE_MSGC_DISCONNECTING = 6;
+
+
+var SPICE_MSGC_MAIN_CLIENT_INFO = 101;
+var SPICE_MSGC_MAIN_MIGRATE_CONNECTED = 102;
+var SPICE_MSGC_MAIN_MIGRATE_CONNECT_ERROR = 103;
+var SPICE_MSGC_MAIN_ATTACH_CHANNELS = 104;
+var SPICE_MSGC_MAIN_MOUSE_MODE_REQUEST = 105;
+var SPICE_MSGC_MAIN_AGENT_START = 106;
+var SPICE_MSGC_MAIN_AGENT_DATA = 107;
+var SPICE_MSGC_MAIN_AGENT_TOKEN = 108;
+var SPICE_MSGC_MAIN_MIGRATE_END = 109;
+var SPICE_MSGC_END_MAIN = 110;
+
+var SPICE_MSG_DISPLAY_MODE = 101;
+var SPICE_MSG_DISPLAY_MARK = 102;
+var SPICE_MSG_DISPLAY_RESET = 103;
+var SPICE_MSG_DISPLAY_COPY_BITS = 104;
+var SPICE_MSG_DISPLAY_INVAL_LIST = 105;
+var SPICE_MSG_DISPLAY_INVAL_ALL_PIXMAPS = 106;
+var SPICE_MSG_DISPLAY_INVAL_PALETTE = 107;
+var SPICE_MSG_DISPLAY_INVAL_ALL_PALETTES= 108;
+
+var SPICE_MSG_DISPLAY_STREAM_CREATE = 122;
+var SPICE_MSG_DISPLAY_STREAM_DATA = 123;
+var SPICE_MSG_DISPLAY_STREAM_CLIP = 124;
+var SPICE_MSG_DISPLAY_STREAM_DESTROY = 125;
+var SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL= 126;
+
+var SPICE_MSG_DISPLAY_DRAW_FILL = 302;
+var SPICE_MSG_DISPLAY_DRAW_OPAQUE = 303;
+var SPICE_MSG_DISPLAY_DRAW_COPY = 304;
+var SPICE_MSG_DISPLAY_DRAW_BLEND = 305;
+var SPICE_MSG_DISPLAY_DRAW_BLACKNESS = 306;
+var SPICE_MSG_DISPLAY_DRAW_WHITENESS = 307;
+var SPICE_MSG_DISPLAY_DRAW_INVERS = 308;
+var SPICE_MSG_DISPLAY_DRAW_ROP3 = 309;
+var SPICE_MSG_DISPLAY_DRAW_STROKE = 310;
+var SPICE_MSG_DISPLAY_DRAW_TEXT = 311;
+var SPICE_MSG_DISPLAY_DRAW_TRANSPARENT = 312;
+var SPICE_MSG_DISPLAY_DRAW_ALPHA_BLEND = 313;
+var SPICE_MSG_DISPLAY_SURFACE_CREATE = 314;
+var SPICE_MSG_DISPLAY_SURFACE_DESTROY = 315;
+
+var SPICE_MSGC_DISPLAY_INIT = 101;
+
+var SPICE_MSG_INPUTS_INIT = 101;
+var SPICE_MSG_INPUTS_KEY_MODIFIERS = 102;
+
+var SPICE_MSG_INPUTS_MOUSE_MOTION_ACK = 111;
+
+var SPICE_MSGC_INPUTS_KEY_DOWN = 101;
+var SPICE_MSGC_INPUTS_KEY_UP = 102;
+var SPICE_MSGC_INPUTS_KEY_MODIFIERS = 103;
+
+var SPICE_MSGC_INPUTS_MOUSE_MOTION = 111;
+var SPICE_MSGC_INPUTS_MOUSE_POSITION = 112;
+var SPICE_MSGC_INPUTS_MOUSE_PRESS = 113;
+var SPICE_MSGC_INPUTS_MOUSE_RELEASE = 114;
+
+var SPICE_MSG_CURSOR_INIT = 101;
+var SPICE_MSG_CURSOR_RESET = 102;
+var SPICE_MSG_CURSOR_SET = 103;
+var SPICE_MSG_CURSOR_MOVE = 104;
+var SPICE_MSG_CURSOR_HIDE = 105;
+var SPICE_MSG_CURSOR_TRAIL = 106;
+var SPICE_MSG_CURSOR_INVAL_ONE = 107;
+var SPICE_MSG_CURSOR_INVAL_ALL = 108;
+
+var SPICE_MSG_PLAYBACK_DATA = 101;
+var SPICE_MSG_PLAYBACK_MODE = 102;
+var SPICE_MSG_PLAYBACK_START = 103;
+var SPICE_MSG_PLAYBACK_STOP = 104;
+var SPICE_MSG_PLAYBACK_VOLUME = 105;
+var SPICE_MSG_PLAYBACK_MUTE = 106;
+var SPICE_MSG_PLAYBACK_LATENCY = 107;
+
+var SPICE_PLAYBACK_CAP_CELT_0_5_1 = 0;
+var SPICE_PLAYBACK_CAP_VOLUME = 1;
+var SPICE_PLAYBACK_CAP_LATENCY = 2;
+var SPICE_PLAYBACK_CAP_OPUS = 3;
+
+var SPICE_AUDIO_DATA_MODE_INVALID = 0;
+var SPICE_AUDIO_DATA_MODE_RAW = 1;
+var SPICE_AUDIO_DATA_MODE_CELT_0_5_1 = 2;
+var SPICE_AUDIO_DATA_MODE_OPUS = 3;
+
+var SPICE_AUDIO_FMT_INVALID = 0;
+var SPICE_AUDIO_FMT_S16 = 1;
+
+var SPICE_CHANNEL_MAIN = 1;
+var SPICE_CHANNEL_DISPLAY = 2;
+var SPICE_CHANNEL_INPUTS = 3;
+var SPICE_CHANNEL_CURSOR = 4;
+var SPICE_CHANNEL_PLAYBACK = 5;
+var SPICE_CHANNEL_RECORD = 6;
+var SPICE_CHANNEL_TUNNEL = 7;
+var SPICE_CHANNEL_SMARTCARD = 8;
+var SPICE_CHANNEL_USBREDIR = 9;
+
+var SPICE_SURFACE_FLAGS_PRIMARY = (1 << 0);
+
+var SPICE_NOTIFY_SEVERITY_INFO = 0;
+var SPICE_NOTIFY_SEVERITY_WARN = 1;
+var SPICE_NOTIFY_SEVERITY_ERROR = 2;
+
+var SPICE_MOUSE_MODE_SERVER = (1 << 0),
+ SPICE_MOUSE_MODE_CLIENT = (1 << 1),
+ SPICE_MOUSE_MODE_MASK = 0x3;
+
+var SPICE_CLIP_TYPE_NONE = 0;
+var SPICE_CLIP_TYPE_RECTS = 1;
+
+var SPICE_IMAGE_TYPE_BITMAP = 0;
+var SPICE_IMAGE_TYPE_QUIC = 1;
+var SPICE_IMAGE_TYPE_RESERVED = 2;
+var SPICE_IMAGE_TYPE_LZ_PLT = 100;
+var SPICE_IMAGE_TYPE_LZ_RGB = 101;
+var SPICE_IMAGE_TYPE_GLZ_RGB = 102;
+var SPICE_IMAGE_TYPE_FROM_CACHE = 103;
+var SPICE_IMAGE_TYPE_SURFACE = 104;
+var SPICE_IMAGE_TYPE_JPEG = 105;
+var SPICE_IMAGE_TYPE_FROM_CACHE_LOSSLESS = 106;
+var SPICE_IMAGE_TYPE_ZLIB_GLZ_RGB = 107;
+var SPICE_IMAGE_TYPE_JPEG_ALPHA = 108;
+
+var SPICE_IMAGE_FLAGS_CACHE_ME = (1 << 0),
+ SPICE_IMAGE_FLAGS_HIGH_BITS_SET = (1 << 1),
+ SPICE_IMAGE_FLAGS_CACHE_REPLACE_ME = (1 << 2);
+
+var SPICE_BITMAP_FLAGS_PAL_CACHE_ME = (1 << 0),
+ SPICE_BITMAP_FLAGS_PAL_FROM_CACHE = (1 << 1),
+ SPICE_BITMAP_FLAGS_TOP_DOWN = (1 << 2),
+ SPICE_BITMAP_FLAGS_MASK = 0x7;
+
+var SPICE_BITMAP_FMT_INVALID = 0,
+ SPICE_BITMAP_FMT_1BIT_LE = 1,
+ SPICE_BITMAP_FMT_1BIT_BE = 2,
+ SPICE_BITMAP_FMT_4BIT_LE = 3,
+ SPICE_BITMAP_FMT_4BIT_BE = 4,
+ SPICE_BITMAP_FMT_8BIT = 5,
+ SPICE_BITMAP_FMT_16BIT = 6,
+ SPICE_BITMAP_FMT_24BIT = 7,
+ SPICE_BITMAP_FMT_32BIT = 8,
+ SPICE_BITMAP_FMT_RGBA = 9;
+
+
+var SPICE_CURSOR_FLAGS_NONE = (1 << 0),
+ SPICE_CURSOR_FLAGS_CACHE_ME = (1 << 1),
+ SPICE_CURSOR_FLAGS_FROM_CACHE = (1 << 2),
+ SPICE_CURSOR_FLAGS_MASK = 0x7;
+
+var SPICE_MOUSE_BUTTON_MASK_LEFT = (1 << 0),
+ SPICE_MOUSE_BUTTON_MASK_MIDDLE = (1 << 1),
+ SPICE_MOUSE_BUTTON_MASK_RIGHT = (1 << 2),
+ SPICE_MOUSE_BUTTON_MASK_MASK = 0x7;
+
+var SPICE_MOUSE_BUTTON_INVALID = 0;
+var SPICE_MOUSE_BUTTON_LEFT = 1;
+var SPICE_MOUSE_BUTTON_MIDDLE = 2;
+var SPICE_MOUSE_BUTTON_RIGHT = 3;
+var SPICE_MOUSE_BUTTON_UP = 4;
+var SPICE_MOUSE_BUTTON_DOWN = 5;
+
+var SPICE_BRUSH_TYPE_NONE = 0,
+ SPICE_BRUSH_TYPE_SOLID = 1,
+ SPICE_BRUSH_TYPE_PATTERN = 2;
+
+var SPICE_SURFACE_FMT_INVALID = 0,
+ SPICE_SURFACE_FMT_1_A = 1,
+ SPICE_SURFACE_FMT_8_A = 8,
+ SPICE_SURFACE_FMT_16_555 = 16,
+ SPICE_SURFACE_FMT_32_xRGB = 32,
+ SPICE_SURFACE_FMT_16_565 = 80,
+ SPICE_SURFACE_FMT_32_ARGB = 96;
+
+var SPICE_ROPD_INVERS_SRC = (1 << 0),
+ SPICE_ROPD_INVERS_BRUSH = (1 << 1),
+ SPICE_ROPD_INVERS_DEST = (1 << 2),
+ SPICE_ROPD_OP_PUT = (1 << 3),
+ SPICE_ROPD_OP_OR = (1 << 4),
+ SPICE_ROPD_OP_AND = (1 << 5),
+ SPICE_ROPD_OP_XOR = (1 << 6),
+ SPICE_ROPD_OP_BLACKNESS = (1 << 7),
+ SPICE_ROPD_OP_WHITENESS = (1 << 8),
+ SPICE_ROPD_OP_INVERS = (1 << 9),
+ SPICE_ROPD_INVERS_RES = (1 << 10),
+ SPICE_ROPD_MASK = 0x7ff;
+
+var LZ_IMAGE_TYPE_INVALID = 0,
+ LZ_IMAGE_TYPE_PLT1_LE = 1,
+ LZ_IMAGE_TYPE_PLT1_BE = 2, // PLT stands for palette
+ LZ_IMAGE_TYPE_PLT4_LE = 3,
+ LZ_IMAGE_TYPE_PLT4_BE = 4,
+ LZ_IMAGE_TYPE_PLT8 = 5,
+ LZ_IMAGE_TYPE_RGB16 = 6,
+ LZ_IMAGE_TYPE_RGB24 = 7,
+ LZ_IMAGE_TYPE_RGB32 = 8,
+ LZ_IMAGE_TYPE_RGBA = 9,
+ LZ_IMAGE_TYPE_XXXA = 10;
+
+
+var QUIC_IMAGE_TYPE_INVALID = 0,
+ QUIC_IMAGE_TYPE_GRAY = 1,
+ QUIC_IMAGE_TYPE_RGB16 = 2,
+ QUIC_IMAGE_TYPE_RGB24 = 3,
+ QUIC_IMAGE_TYPE_RGB32 = 4,
+ QUIC_IMAGE_TYPE_RGBA = 5;
+
+var SPICE_INPUT_MOTION_ACK_BUNCH = 4;
+
+
+var SPICE_CURSOR_TYPE_ALPHA = 0,
+ SPICE_CURSOR_TYPE_MONO = 1,
+ SPICE_CURSOR_TYPE_COLOR4 = 2,
+ SPICE_CURSOR_TYPE_COLOR8 = 3,
+ SPICE_CURSOR_TYPE_COLOR16 = 4,
+ SPICE_CURSOR_TYPE_COLOR24 = 5,
+ SPICE_CURSOR_TYPE_COLOR32 = 6;
+
+var SPICE_VIDEO_CODEC_TYPE_MJPEG = 1;
+
+var VD_AGENT_PROTOCOL = 1;
+
+var VD_AGENT_MOUSE_STATE = 1,
+ VD_AGENT_MONITORS_CONFIG = 2,
+ VD_AGENT_REPLY = 3,
+ VD_AGENT_CLIPBOARD = 4,
+ VD_AGENT_DISPLAY_CONFIG = 5,
+ VD_AGENT_ANNOUNCE_CAPABILITIES = 6,
+ VD_AGENT_CLIPBOARD_GRAB = 7,
+ VD_AGENT_CLIPBOARD_REQUEST = 8,
+ VD_AGENT_CLIPBOARD_RELEASE = 9,
+ VD_AGENT_FILE_XFER_START =10,
+ VD_AGENT_FILE_XFER_STATUS =11,
+ VD_AGENT_FILE_XFER_DATA =12,
+ VD_AGENT_CLIENT_DISCONNECTED =13,
+ VD_AGENT_MAX_CLIPBOARD =14;
diff --git a/src/sunstone/public/bower_components/spice-html5/inputs.js b/src/sunstone/public/bower_components/spice-html5/inputs.js
new file mode 100644
index 0000000000..c904eda4f1
--- /dev/null
+++ b/src/sunstone/public/bower_components/spice-html5/inputs.js
@@ -0,0 +1,280 @@
+"use strict";
+/*
+ Copyright (C) 2012 by Jeremy P. White
+
+ This file is part of spice-html5.
+
+ spice-html5 is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ spice-html5 is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with spice-html5. If not, see .
+*/
+
+/*----------------------------------------------------------------------------
+ ** Modifier Keystates
+ ** These need to be tracked because focus in and out can get the keyboard
+ ** out of sync.
+ **------------------------------------------------------------------------*/
+var Shift_state = -1;
+var Ctrl_state = -1;
+var Alt_state = -1;
+var Meta_state = -1;
+
+/*----------------------------------------------------------------------------
+** SpiceInputsConn
+** Drive the Spice Inputs channel (e.g. mouse + keyboard)
+**--------------------------------------------------------------------------*/
+function SpiceInputsConn()
+{
+ SpiceConn.apply(this, arguments);
+
+ this.mousex = undefined;
+ this.mousey = undefined;
+ this.button_state = 0;
+ this.waiting_for_ack = 0;
+}
+
+SpiceInputsConn.prototype = Object.create(SpiceConn.prototype);
+SpiceInputsConn.prototype.process_channel_message = function(msg)
+{
+ if (msg.type == SPICE_MSG_INPUTS_INIT)
+ {
+ var inputs_init = new SpiceMsgInputsInit(msg.data);
+ this.keyboard_modifiers = inputs_init.keyboard_modifiers;
+ DEBUG > 1 && console.log("MsgInputsInit - modifier " + this.keyboard_modifiers);
+ // FIXME - We don't do anything with the keyboard modifiers...
+ return true;
+ }
+ if (msg.type == SPICE_MSG_INPUTS_KEY_MODIFIERS)
+ {
+ var key = new SpiceMsgInputsKeyModifiers(msg.data);
+ this.keyboard_modifiers = key.keyboard_modifiers;
+ DEBUG > 1 && console.log("MsgInputsKeyModifiers - modifier " + this.keyboard_modifiers);
+ // FIXME - We don't do anything with the keyboard modifiers...
+ return true;
+ }
+ if (msg.type == SPICE_MSG_INPUTS_MOUSE_MOTION_ACK)
+ {
+ DEBUG > 1 && console.log("mouse motion ack");
+ this.waiting_for_ack -= SPICE_INPUT_MOTION_ACK_BUNCH;
+ return true;
+ }
+ return false;
+}
+
+
+
+function handle_mousemove(e)
+{
+ var msg = new SpiceMiniData();
+ var move;
+ if (this.sc.mouse_mode == SPICE_MOUSE_MODE_CLIENT)
+ {
+ move = new SpiceMsgcMousePosition(this.sc, e)
+ msg.build_msg(SPICE_MSGC_INPUTS_MOUSE_POSITION, move);
+ }
+ else
+ {
+ move = new SpiceMsgcMouseMotion(this.sc, e)
+ msg.build_msg(SPICE_MSGC_INPUTS_MOUSE_MOTION, move);
+ }
+ if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready")
+ {
+ if (this.sc.inputs.waiting_for_ack < (2 * SPICE_INPUT_MOTION_ACK_BUNCH))
+ {
+ this.sc.inputs.send_msg(msg);
+ this.sc.inputs.waiting_for_ack++;
+ }
+ else
+ {
+ DEBUG > 0 && this.sc.log_info("Discarding mouse motion");
+ }
+ }
+
+ if (this.sc && this.sc.cursor && this.sc.cursor.spice_simulated_cursor)
+ {
+ this.sc.cursor.spice_simulated_cursor.style.display = 'block';
+ this.sc.cursor.spice_simulated_cursor.style.left = e.pageX - this.sc.cursor.spice_simulated_cursor.spice_hot_x + 'px';
+ this.sc.cursor.spice_simulated_cursor.style.top = e.pageY - this.sc.cursor.spice_simulated_cursor.spice_hot_y + 'px';
+ e.preventDefault();
+ }
+
+}
+
+function handle_mousedown(e)
+{
+ var press = new SpiceMsgcMousePress(this.sc, e)
+ var msg = new SpiceMiniData();
+ msg.build_msg(SPICE_MSGC_INPUTS_MOUSE_PRESS, press);
+ if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready")
+ this.sc.inputs.send_msg(msg);
+
+ e.preventDefault();
+}
+
+function handle_contextmenu(e)
+{
+ e.preventDefault();
+ return false;
+}
+
+function handle_mouseup(e)
+{
+ var release = new SpiceMsgcMouseRelease(this.sc, e)
+ var msg = new SpiceMiniData();
+ msg.build_msg(SPICE_MSGC_INPUTS_MOUSE_RELEASE, release);
+ if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready")
+ this.sc.inputs.send_msg(msg);
+
+ e.preventDefault();
+}
+
+function handle_mousewheel(e)
+{
+ var press = new SpiceMsgcMousePress;
+ var release = new SpiceMsgcMouseRelease;
+ if (e.wheelDelta > 0)
+ press.button = release.button = SPICE_MOUSE_BUTTON_UP;
+ else
+ press.button = release.button = SPICE_MOUSE_BUTTON_DOWN;
+ press.buttons_state = 0;
+ release.buttons_state = 0;
+
+ var msg = new SpiceMiniData();
+ msg.build_msg(SPICE_MSGC_INPUTS_MOUSE_PRESS, press);
+ if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready")
+ this.sc.inputs.send_msg(msg);
+
+ msg.build_msg(SPICE_MSGC_INPUTS_MOUSE_RELEASE, release);
+ if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready")
+ this.sc.inputs.send_msg(msg);
+
+ e.preventDefault();
+}
+
+function handle_keydown(e)
+{
+ var key = new SpiceMsgcKeyDown(e)
+ var msg = new SpiceMiniData();
+ check_and_update_modifiers(e, key.code, this.sc);
+ msg.build_msg(SPICE_MSGC_INPUTS_KEY_DOWN, key);
+ if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready")
+ this.sc.inputs.send_msg(msg);
+
+ e.preventDefault();
+}
+
+function handle_keyup(e)
+{
+ var key = new SpiceMsgcKeyUp(e)
+ var msg = new SpiceMiniData();
+ check_and_update_modifiers(e, key.code, this.sc);
+ msg.build_msg(SPICE_MSGC_INPUTS_KEY_UP, key);
+ if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready")
+ this.sc.inputs.send_msg(msg);
+
+ e.preventDefault();
+}
+
+function sendCtrlAltDel()
+{
+ if (sc && sc.inputs && sc.inputs.state === "ready"){
+ var key = new SpiceMsgcKeyDown();
+ var msg = new SpiceMiniData();
+
+ update_modifier(true, KEY_LCtrl, sc);
+ update_modifier(true, KEY_Alt, sc);
+
+ key.code = KEY_KP_Decimal;
+ msg.build_msg(SPICE_MSGC_INPUTS_KEY_DOWN, key);
+ sc.inputs.send_msg(msg);
+ msg.build_msg(SPICE_MSGC_INPUTS_KEY_UP, key);
+ sc.inputs.send_msg(msg);
+
+ if(Ctrl_state == false) update_modifier(false, KEY_LCtrl, sc);
+ if(Alt_state == false) update_modifier(false, KEY_Alt, sc);
+ }
+}
+
+function update_modifier(state, code, sc)
+{
+ var msg = new SpiceMiniData();
+ if (!state)
+ {
+ var key = new SpiceMsgcKeyUp()
+ key.code =(0x80|code);
+ msg.build_msg(SPICE_MSGC_INPUTS_KEY_UP, key);
+ }
+ else
+ {
+ var key = new SpiceMsgcKeyDown()
+ key.code = code;
+ msg.build_msg(SPICE_MSGC_INPUTS_KEY_DOWN, key);
+ }
+
+ sc.inputs.send_msg(msg);
+}
+
+function check_and_update_modifiers(e, code, sc)
+{
+ if (Shift_state === -1)
+ {
+ Shift_state = e.shiftKey;
+ Ctrl_state = e.ctrlKey;
+ Alt_state = e.altKey;
+ Meta_state = e.metaKey;
+ }
+
+ if (code === KEY_ShiftL)
+ Shift_state = true;
+ else if (code === KEY_Alt)
+ Alt_state = true;
+ else if (code === KEY_LCtrl)
+ Ctrl_state = true;
+ else if (code === 0xE0B5)
+ Meta_state = true;
+ else if (code === (0x80|KEY_ShiftL))
+ Shift_state = false;
+ else if (code === (0x80|KEY_Alt))
+ Alt_state = false;
+ else if (code === (0x80|KEY_LCtrl))
+ Ctrl_state = false;
+ else if (code === (0x80|0xE0B5))
+ Meta_state = false;
+
+ if (sc && sc.inputs && sc.inputs.state === "ready")
+ {
+ if (Shift_state != e.shiftKey)
+ {
+ console.log("Shift state out of sync");
+ update_modifier(e.shiftKey, KEY_ShiftL, sc);
+ Shift_state = e.shiftKey;
+ }
+ if (Alt_state != e.altKey)
+ {
+ console.log("Alt state out of sync");
+ update_modifier(e.altKey, KEY_Alt, sc);
+ Alt_state = e.altKey;
+ }
+ if (Ctrl_state != e.ctrlKey)
+ {
+ console.log("Ctrl state out of sync");
+ update_modifier(e.ctrlKey, KEY_LCtrl, sc);
+ Ctrl_state = e.ctrlKey;
+ }
+ if (Meta_state != e.metaKey)
+ {
+ console.log("Meta state out of sync");
+ update_modifier(e.metaKey, 0xE0B5, sc);
+ Meta_state = e.metaKey;
+ }
+ }
+}
diff --git a/src/sunstone/public/bower_components/spice-html5/lz.js b/src/sunstone/public/bower_components/spice-html5/lz.js
new file mode 100644
index 0000000000..4292eac00e
--- /dev/null
+++ b/src/sunstone/public/bower_components/spice-html5/lz.js
@@ -0,0 +1,166 @@
+"use strict";
+/*
+ Copyright (C) 2012 by Jeremy P. White
+
+ This file is part of spice-html5.
+
+ spice-html5 is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ spice-html5 is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with spice-html5. If not, see .
+*/
+
+
+/*----------------------------------------------------------------------------
+** lz.js
+** Functions for handling SPICE_IMAGE_TYPE_LZ_RGB
+** Adapted from lz.c .
+**--------------------------------------------------------------------------*/
+function lz_rgb32_decompress(in_buf, at, out_buf, type, default_alpha)
+{
+ var encoder = at;
+ var op = 0;
+ var ctrl;
+ var ctr = 0;
+
+ for (ctrl = in_buf[encoder++]; (op * 4) < out_buf.length; ctrl = in_buf[encoder++])
+ {
+ var ref = op;
+ var len = ctrl >> 5;
+ var ofs = (ctrl & 31) << 8;
+
+//if (type == LZ_IMAGE_TYPE_RGBA)
+//console.log(ctr++ + ": from " + (encoder + 28) + ", ctrl " + ctrl + ", len " + len + ", ofs " + ofs + ", op " + op);
+ if (ctrl >= 32) {
+
+ var code;
+ len--;
+
+ if (len == 7 - 1) {
+ do {
+ code = in_buf[encoder++];
+ len += code;
+ } while (code == 255);
+ }
+ code = in_buf[encoder++];
+ ofs += code;
+
+
+ if (code == 255) {
+ if ((ofs - code) == (31 << 8)) {
+ ofs = in_buf[encoder++] << 8;
+ ofs += in_buf[encoder++];
+ ofs += 8191;
+ }
+ }
+ len += 1;
+ if (type == LZ_IMAGE_TYPE_RGBA)
+ len += 2;
+
+ ofs += 1;
+
+ ref -= ofs;
+ if (ref == (op - 1)) {
+ var b = ref;
+//if (type == LZ_IMAGE_TYPE_RGBA) console.log("alpha " + out_buf[(b*4)+3] + " dupped into pixel " + op + " through pixel " + (op + len));
+ for (; len; --len) {
+ if (type == LZ_IMAGE_TYPE_RGBA)
+ {
+ out_buf[(op*4) + 3] = out_buf[(b*4)+3];
+ }
+ else
+ {
+ for (i = 0; i < 4; i++)
+ out_buf[(op*4) + i] = out_buf[(b*4)+i];
+ }
+ op++;
+ }
+ } else {
+//if (type == LZ_IMAGE_TYPE_RGBA) console.log("alpha copied to pixel " + op + " through " + (op + len) + " from " + ref);
+ for (; len; --len) {
+ if (type == LZ_IMAGE_TYPE_RGBA)
+ {
+ out_buf[(op*4) + 3] = out_buf[(ref*4)+3];
+ }
+ else
+ {
+ for (i = 0; i < 4; i++)
+ out_buf[(op*4) + i] = out_buf[(ref*4)+i];
+ }
+ op++; ref++;
+ }
+ }
+ } else {
+ ctrl++;
+
+ if (type == LZ_IMAGE_TYPE_RGBA)
+ {
+//console.log("alpha " + in_buf[encoder] + " set into pixel " + op);
+ out_buf[(op*4) + 3] = in_buf[encoder++];
+ }
+ else
+ {
+ out_buf[(op*4) + 0] = in_buf[encoder + 2];
+ out_buf[(op*4) + 1] = in_buf[encoder + 1];
+ out_buf[(op*4) + 2] = in_buf[encoder + 0];
+ if (default_alpha)
+ out_buf[(op*4) + 3] = 255;
+ encoder += 3;
+ }
+ op++;
+
+
+ for (--ctrl; ctrl; ctrl--) {
+ if (type == LZ_IMAGE_TYPE_RGBA)
+ {
+//console.log("alpha " + in_buf[encoder] + " set into pixel " + op);
+ out_buf[(op*4) + 3] = in_buf[encoder++];
+ }
+ else
+ {
+ out_buf[(op*4) + 0] = in_buf[encoder + 2];
+ out_buf[(op*4) + 1] = in_buf[encoder + 1];
+ out_buf[(op*4) + 2] = in_buf[encoder + 0];
+ if (default_alpha)
+ out_buf[(op*4) + 3] = 255;
+ encoder += 3;
+ }
+ op++;
+ }
+ }
+
+ }
+ return encoder - 1;
+}
+
+function convert_spice_lz_to_web(context, lz_image)
+{
+ var at;
+ if (lz_image.type === LZ_IMAGE_TYPE_RGB32 || lz_image.type === LZ_IMAGE_TYPE_RGBA)
+ {
+ var u8 = new Uint8Array(lz_image.data);
+ var ret = context.createImageData(lz_image.width, lz_image.height);
+
+ at = lz_rgb32_decompress(u8, 0, ret.data, LZ_IMAGE_TYPE_RGB32, lz_image.type != LZ_IMAGE_TYPE_RGBA);
+ if (lz_image.type == LZ_IMAGE_TYPE_RGBA)
+ lz_rgb32_decompress(u8, at, ret.data, LZ_IMAGE_TYPE_RGBA, false);
+ }
+ else if (lz_image.type === LZ_IMAGE_TYPE_XXXA)
+ {
+ var u8 = new Uint8Array(lz_image.data);
+ var ret = context.createImageData(lz_image.width, lz_image.height);
+ lz_rgb32_decompress(u8, 0, ret.data, LZ_IMAGE_TYPE_RGBA, false);
+ }
+ else
+ return undefined;
+
+ return ret;
+}
diff --git a/src/sunstone/public/bower_components/spice-html5/main.js b/src/sunstone/public/bower_components/spice-html5/main.js
new file mode 100644
index 0000000000..e487551cc7
--- /dev/null
+++ b/src/sunstone/public/bower_components/spice-html5/main.js
@@ -0,0 +1,231 @@
+"use strict";
+/*
+ Copyright (C) 2012 by Jeremy P. White
+
+ This file is part of spice-html5.
+
+ spice-html5 is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ spice-html5 is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with spice-html5. If not, see .
+*/
+
+/*----------------------------------------------------------------------------
+** SpiceMainConn
+** This is the master Javascript class for establishing and
+** managing a connection to a Spice Server.
+**
+** Invocation: You must pass an object with properties as follows:
+** uri (required) Uri of a WebSocket listener that is
+** connected to a spice server.
+** password (required) Password to send to the spice server
+** message_id (optional) Identifier of an element in the DOM
+** where SpiceConn will write messages.
+** It will use classes spice-messages-x,
+** where x is one of info, warning, or error.
+** screen_id (optional) Identifier of an element in the DOM
+** where SpiceConn will create any new
+** client screens. This is the main UI.
+** dump_id (optional) If given, an element to use for
+** dumping every single image + canvas drawn.
+** Sometimes useful for debugging.
+** onerror (optional) If given, a function to receive async
+** errors. Note that you should also catch
+** errors for ones that occur inline
+** onagent (optional) If given, a function to be called when
+** a VD agent is connected; a good opportunity
+** to request a resize
+**
+** Throws error if there are troubles. Requires a modern (by 2012 standards)
+** browser, including WebSocket and WebSocket.binaryType == arraybuffer
+**
+**--------------------------------------------------------------------------*/
+function SpiceMainConn()
+{
+ if (typeof WebSocket === "undefined")
+ throw new Error("WebSocket unavailable. You need to use a different browser.");
+
+ SpiceConn.apply(this, arguments);
+
+}
+
+SpiceMainConn.prototype = Object.create(SpiceConn.prototype);
+SpiceMainConn.prototype.process_channel_message = function(msg)
+{
+ if (msg.type == SPICE_MSG_MAIN_INIT)
+ {
+ this.log_info("Connected to " + this.ws.url);
+ this.report_success("Connected")
+ this.main_init = new SpiceMsgMainInit(msg.data);
+ this.connection_id = this.main_init.session_id;
+
+ if (DEBUG > 0)
+ {
+ // FIXME - there is a lot here we don't handle; mouse modes, agent,
+ // ram_hint, multi_media_time
+ this.log_info("session id " + this.main_init.session_id +
+ " ; display_channels_hint " + this.main_init.display_channels_hint +
+ " ; supported_mouse_modes " + this.main_init.supported_mouse_modes +
+ " ; current_mouse_mode " + this.main_init.current_mouse_mode +
+ " ; agent_connected " + this.main_init.agent_connected +
+ " ; agent_tokens " + this.main_init.agent_tokens +
+ " ; multi_media_time " + this.main_init.multi_media_time +
+ " ; ram_hint " + this.main_init.ram_hint);
+ }
+
+ this.handle_mouse_mode(this.main_init.current_mouse_mode,
+ this.main_init.supported_mouse_modes);
+
+ if (this.main_init.agent_connected)
+ this.connect_agent();
+
+ var attach = new SpiceMiniData;
+ attach.type = SPICE_MSGC_MAIN_ATTACH_CHANNELS;
+ attach.size = attach.buffer_size();
+ this.send_msg(attach);
+ return true;
+ }
+
+ if (msg.type == SPICE_MSG_MAIN_MOUSE_MODE)
+ {
+ var mode = new SpiceMsgMainMouseMode(msg.data);
+ DEBUG > 0 && this.log_info("Mouse supported modes " + mode.supported_modes + "; current " + mode.current_mode);
+ this.handle_mouse_mode(mode.current_mode, mode.supported_modes);
+ return true;
+ }
+
+ if (msg.type == SPICE_MSG_MAIN_CHANNELS_LIST)
+ {
+ var i;
+ var chans;
+ DEBUG > 0 && console.log("channels");
+ chans = new SpiceMsgChannels(msg.data);
+ for (i = 0; i < chans.channels.length; i++)
+ {
+ var conn = {
+ uri: this.ws.url,
+ parent: this,
+ connection_id : this.connection_id,
+ type : chans.channels[i].type,
+ chan_id : chans.channels[i].id
+ };
+ if (chans.channels[i].type == SPICE_CHANNEL_DISPLAY)
+ this.display = new SpiceDisplayConn(conn);
+ else if (chans.channels[i].type == SPICE_CHANNEL_INPUTS)
+ {
+ this.inputs = new SpiceInputsConn(conn);
+ this.inputs.mouse_mode = this.mouse_mode;
+ }
+ else if (chans.channels[i].type == SPICE_CHANNEL_CURSOR)
+ this.cursor = new SpiceCursorConn(conn);
+ else if (chans.channels[i].type == SPICE_CHANNEL_PLAYBACK)
+ this.cursor = new SpicePlaybackConn(conn);
+ else
+ {
+ this.log_err("Channel type " + chans.channels[i].type + " unknown.");
+ if (! ("extra_channels" in this))
+ this.extra_channels = [];
+ this.extra_channels[i] = new SpiceConn(conn);
+ }
+
+ }
+
+ return true;
+ }
+
+ if (msg.type == SPICE_MSG_MAIN_AGENT_CONNECTED ||
+ msg.type == SPICE_MSG_MAIN_AGENT_CONNECTED_TOKENS)
+ {
+ this.connect_agent();
+ return true;
+ }
+
+ if (msg.type == SPICE_MSG_MAIN_AGENT_DISCONNECTED)
+ {
+ this.agent_connected = false;
+ return true;
+ }
+
+ return false;
+}
+
+SpiceMainConn.prototype.stop = function(msg)
+{
+ this.state = "closing";
+
+ if (this.inputs)
+ {
+ this.inputs.cleanup();
+ this.inputs = undefined;
+ }
+
+ if (this.cursor)
+ {
+ this.cursor.cleanup();
+ this.cursor = undefined;
+ }
+
+ if (this.display)
+ {
+ this.display.cleanup();
+ this.display.destroy_surfaces();
+ this.display = undefined;
+ }
+
+ this.cleanup();
+
+ if ("extra_channels" in this)
+ for (var e in this.extra_channels)
+ this.extra_channels[e].cleanup();
+ this.extra_channels = undefined;
+}
+
+SpiceMainConn.prototype.resize_window = function(flags, width, height, depth, x, y)
+{
+ if (this.agent_connected > 0)
+ {
+ var monitors_config = new VDAgentMonitorsConfig(flags, width, height, depth, x, y);
+ var agent_data = new SpiceMsgcMainAgentData(VD_AGENT_MONITORS_CONFIG, monitors_config);
+ var mr = new SpiceMiniData();
+ mr.build_msg(SPICE_MSGC_MAIN_AGENT_DATA, agent_data);
+ this.send_msg(mr);
+ }
+}
+
+SpiceMainConn.prototype.connect_agent = function()
+{
+ this.agent_connected = true;
+
+ var agent_start = new SpiceMsgcMainAgentStart(~0);
+ var mr = new SpiceMiniData();
+ mr.build_msg(SPICE_MSGC_MAIN_AGENT_START, agent_start);
+ this.send_msg(mr);
+
+ if (this.onagent !== undefined)
+ this.onagent(this);
+
+}
+
+SpiceMainConn.prototype.handle_mouse_mode = function(current, supported)
+{
+ this.mouse_mode = current;
+ if (current != SPICE_MOUSE_MODE_CLIENT && (supported & SPICE_MOUSE_MODE_CLIENT))
+ {
+ var mode_request = new SpiceMsgcMainMouseModeRequest(SPICE_MOUSE_MODE_CLIENT);
+ var mr = new SpiceMiniData();
+ mr.build_msg(SPICE_MSGC_MAIN_MOUSE_MODE_REQUEST, mode_request);
+ this.send_msg(mr);
+ }
+
+ if (this.inputs)
+ this.inputs.mouse_mode = current;
+}
+
diff --git a/src/sunstone/public/bower_components/spice-html5/playback.js b/src/sunstone/public/bower_components/spice-html5/playback.js
new file mode 100644
index 0000000000..7209fbe7a4
--- /dev/null
+++ b/src/sunstone/public/bower_components/spice-html5/playback.js
@@ -0,0 +1,278 @@
+"use strict";
+/*
+ Copyright (C) 2014 by Jeremy P. White
+
+ This file is part of spice-html5.
+
+ spice-html5 is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ spice-html5 is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with spice-html5. If not, see .
+*/
+
+/*----------------------------------------------------------------------------
+** SpicePlaybackConn
+** Drive the Spice Playback channel (sound out)
+**--------------------------------------------------------------------------*/
+function SpicePlaybackConn()
+{
+ SpiceConn.apply(this, arguments);
+
+ this.queue = new Array();
+ this.append_okay = false;
+ this.start_time = 0;
+ this.skip_until = 0;
+ this.gap_time = 0;
+}
+
+SpicePlaybackConn.prototype = Object.create(SpiceConn.prototype);
+SpicePlaybackConn.prototype.process_channel_message = function(msg)
+{
+ if (!!!window.MediaSource)
+ {
+ this.log_err('MediaSource API is not available');
+ return false;
+ }
+
+ if (msg.type == SPICE_MSG_PLAYBACK_START)
+ {
+ var start = new SpiceMsgPlaybackStart(msg.data);
+
+ DEBUG > 0 && console.log("PlaybackStart; frequency " + start.frequency);
+
+ if (start.frequency != OPUS_FREQUENCY)
+ {
+ this.log_err('This player cannot handle frequency ' + start.frequency);
+ return false;
+ }
+
+ if (start.channels != OPUS_CHANNELS)
+ {
+ this.log_err('This player cannot handle ' + start.channels + ' channels');
+ return false;
+ }
+
+ if (start.format != SPICE_AUDIO_FMT_S16)
+ {
+ this.log_err('This player cannot format ' + start.format);
+ return false;
+ }
+
+ if (! this.source_buffer)
+ {
+ this.media_source = new MediaSource();
+ this.media_source.spiceconn = this;
+
+ this.audio = document.createElement("audio");
+ this.audio.setAttribute('autoplay', true);
+ this.audio.src = window.URL.createObjectURL(this.media_source);
+ document.getElementById(this.parent.screen_id).appendChild(this.audio);
+
+ this.media_source.addEventListener('sourceopen', handle_source_open, false);
+ this.media_source.addEventListener('sourceended', handle_source_ended, false);
+ this.media_source.addEventListener('sourceclosed', handle_source_closed, false);
+
+ this.bytes_written = 0;
+
+ return true;
+ }
+ }
+
+ if (msg.type == SPICE_MSG_PLAYBACK_DATA)
+ {
+ var data = new SpiceMsgPlaybackData(msg.data);
+
+ // If this packet has the same time as the last, just bump up by one.
+ if (this.last_data_time && data.time <= this.last_data_time)
+ {
+ // FIXME - this is arguably wrong. But delaying the transmission was worse,
+ // in initial testing. Could use more research.
+ DEBUG > 1 && console.log("Hacking time of " + data.time + " to " + this.last_data_time + 1);
+ data.time = this.last_data_time + 1;
+ }
+
+ /* Gap detection: If there has been a delay since our last packet, then audio must
+ have paused. Handling that gets tricky. In Chrome, you can seek forward,
+ but you cannot in Firefox. And seeking forward in Chrome is nice, as it keeps
+ Chrome from being overly cautious in it's buffer strategy.
+
+ So we do two things. First, we seek forward. Second, we compute how much of a gap
+ there would have been, and essentially eliminate it.
+ */
+ if (this.last_data_time && data.time >= (this.last_data_time + GAP_DETECTION_THRESHOLD))
+ {
+ this.skip_until = data.time;
+ this.gap_time = (data.time - this.start_time) -
+ (this.source_buffer.buffered.end(this.source_buffer.buffered.end.length - 1) * 1000.0).toFixed(0);
+ }
+
+ this.last_data_time = data.time;
+
+
+ DEBUG > 1 && console.log("PlaybackData; time " + data.time + "; length " + data.data.byteLength);
+
+ if (! this.source_buffer)
+ return true;
+
+ if (this.start_time == 0)
+ this.start_playback(data);
+
+ else if (data.time - this.cluster_time >= MAX_CLUSTER_TIME || this.skip_until > 0)
+ this.new_cluster(data);
+
+ else
+ this.simple_block(data, false);
+
+ if (this.skip_until > 0)
+ {
+ this.audio.currentTime = (this.skip_until - this.start_time - this.gap_time) / 1000.0;
+ this.skip_until = 0;
+ }
+
+ if (this.audio.paused)
+ this.audio.play();
+
+ return true;
+ }
+
+ if (msg.type == SPICE_MSG_PLAYBACK_MODE)
+ {
+ var mode = new SpiceMsgPlaybackMode(msg.data);
+ if (mode.mode != SPICE_AUDIO_DATA_MODE_OPUS)
+ {
+ this.log_err('This player cannot handle mode ' + mode.mode);
+ delete this.source_buffer;
+ }
+ return true;
+ }
+
+ if (msg.type == SPICE_MSG_PLAYBACK_STOP)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+SpicePlaybackConn.prototype.start_playback = function(data)
+{
+ this.start_time = data.time;
+
+ var h = new webm_Header();
+
+ var mb = new ArrayBuffer(h.buffer_size())
+
+ this.bytes_written = h.to_buffer(mb);
+
+ this.source_buffer.addEventListener('error', handle_sourcebuffer_error, false);
+ this.source_buffer.addEventListener('updateend', handle_append_buffer_done, false);
+ playback_append_buffer(this, mb);
+
+ this.new_cluster(data);
+}
+
+SpicePlaybackConn.prototype.new_cluster = function(data)
+{
+ this.cluster_time = data.time;
+
+ var c = new webm_Cluster(data.time - this.start_time - this.gap_time);
+
+ var mb = new ArrayBuffer(c.buffer_size());
+ this.bytes_written += c.to_buffer(mb);
+
+ if (this.append_okay)
+ playback_append_buffer(this, mb);
+ else
+ this.queue.push(mb);
+
+ this.simple_block(data, true);
+}
+
+SpicePlaybackConn.prototype.simple_block = function(data, keyframe)
+{
+ var sb = new webm_SimpleBlock(data.time - this.cluster_time, data.data, keyframe);
+ var mb = new ArrayBuffer(sb.buffer_size());
+
+ this.bytes_written += sb.to_buffer(mb);
+
+ if (this.append_okay)
+ playback_append_buffer(this, mb);
+ else
+ this.queue.push(mb);
+}
+
+function handle_source_open(e)
+{
+ var p = this.spiceconn;
+
+ if (p.source_buffer)
+ return;
+
+ p.source_buffer = this.addSourceBuffer(SPICE_PLAYBACK_CODEC);
+ if (! p.source_buffer)
+ {
+ p.log_err('Codec ' + SPICE_PLAYBACK_CODEC + ' not available.');
+ return;
+ }
+ p.source_buffer.spiceconn = p;
+ p.source_buffer.mode = "segments";
+
+ // FIXME - Experimentation with segments and sequences was unsatisfying.
+ // Switching to sequence did not solve our gap problem,
+ // but the browsers didn't fully support the time seek capability
+ // we would expect to gain from 'segments'.
+ // Segments worked at the time of this patch, so segments it is for now.
+
+}
+
+function handle_source_ended(e)
+{
+ var p = this.spiceconn;
+ p.log_err('Audio source unexpectedly ended.');
+}
+
+function handle_source_closed(e)
+{
+ var p = this.spiceconn;
+ p.log_err('Audio source unexpectedly closed.');
+}
+
+function handle_append_buffer_done(b)
+{
+ var p = this.spiceconn;
+ if (p.queue.length > 0)
+ {
+ var mb = p.queue.shift();
+ playback_append_buffer(p, mb);
+ }
+ else
+ p.append_okay = true;
+
+}
+
+function handle_sourcebuffer_error(e)
+{
+ var p = this.spiceconn;
+ p.log_err('source_buffer error ' + e.message);
+}
+
+function playback_append_buffer(p, b)
+{
+ try
+ {
+ p.source_buffer.appendBuffer(b);
+ p.append_okay = false;
+ }
+ catch (e)
+ {
+ p.log_err("Error invoking appendBuffer: " + e.message);
+ }
+}
diff --git a/src/sunstone/public/bower_components/spice-html5/png.js b/src/sunstone/public/bower_components/spice-html5/png.js
new file mode 100644
index 0000000000..6a26151be8
--- /dev/null
+++ b/src/sunstone/public/bower_components/spice-html5/png.js
@@ -0,0 +1,256 @@
+"use strict";
+/*
+ Copyright (C) 2012 by Jeremy P. White
+
+ This file is part of spice-html5.
+
+ spice-html5 is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ spice-html5 is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with spice-html5. If not, see .
+*/
+
+/*----------------------------------------------------------------------------
+** crc logic from rfc2083 ported to Javascript
+**--------------------------------------------------------------------------*/
+
+var rfc2083_crc_table = Array(256);
+var rfc2083_crc_table_computed = 0;
+/* Make the table for a fast CRC. */
+function rfc2083_make_crc_table()
+{
+ var c;
+ var n, k;
+ for (n = 0; n < 256; n++)
+ {
+ c = n;
+ for (k = 0; k < 8; k++)
+ {
+ if (c & 1)
+ c = ((0xedb88320 ^ (c >>> 1)) >>> 0) & 0xffffffff;
+ else
+ c = c >>> 1;
+ }
+ rfc2083_crc_table[n] = c;
+ }
+
+ rfc2083_crc_table_computed = 1;
+}
+
+/* Update a running CRC with the bytes buf[0..len-1]--the CRC
+ should be initialized to all 1's, and the transmitted value
+ is the 1's complement of the final running CRC (see the
+ crc() routine below)). */
+
+function rfc2083_update_crc(crc, u8buf, at, len)
+{
+ var c = crc;
+ var n;
+
+ if (!rfc2083_crc_table_computed)
+ rfc2083_make_crc_table();
+
+ for (n = 0; n < len; n++)
+ {
+ c = rfc2083_crc_table[(c ^ u8buf[at + n]) & 0xff] ^ (c >>> 8);
+ }
+
+ return c;
+}
+
+function rfc2083_crc(u8buf, at, len)
+{
+ return rfc2083_update_crc(0xffffffff, u8buf, at, len) ^ 0xffffffff;
+}
+
+function crc32(mb, at, len)
+{
+ var u8 = new Uint8Array(mb);
+ return rfc2083_crc(u8, at, len);
+}
+
+function PngIHDR(width, height)
+{
+ this.width = width;
+ this.height = height;
+ this.depth = 8;
+ this.type = 6;
+ this.compression = 0;
+ this.filter = 0;
+ this.interlace = 0;
+}
+
+PngIHDR.prototype =
+{
+ to_buffer: function(a, at)
+ {
+ at = at || 0;
+ var orig = at;
+ var dv = new SpiceDataView(a);
+ dv.setUint32(at, this.buffer_size() - 12); at += 4;
+ dv.setUint8(at, 'I'.charCodeAt(0)); at++;
+ dv.setUint8(at, 'H'.charCodeAt(0)); at++;
+ dv.setUint8(at, 'D'.charCodeAt(0)); at++;
+ dv.setUint8(at, 'R'.charCodeAt(0)); at++;
+ dv.setUint32(at, this.width); at += 4;
+ dv.setUint32(at, this.height); at += 4;
+ dv.setUint8(at, this.depth); at++;
+ dv.setUint8(at, this.type); at++;
+ dv.setUint8(at, this.compression); at++;
+ dv.setUint8(at, this.filter); at++;
+ dv.setUint8(at, this.interlace); at++;
+ dv.setUint32(at, crc32(a, orig + 4, this.buffer_size() - 8)); at += 4;
+ return at;
+ },
+ buffer_size: function()
+ {
+ return 12 + 13;
+ }
+}
+
+
+function adler()
+{
+ this.s1 = 1;
+ this.s2 = 0;
+}
+
+adler.prototype.update = function(b)
+{
+ this.s1 += b;
+ this.s1 %= 65521;
+ this.s2 += this.s1;
+ this.s2 %= 65521;
+}
+
+function PngIDAT(width, height, bytes)
+{
+ if (bytes.byteLength > 65535)
+ {
+ throw new Error("Cannot handle more than 64K");
+ }
+ this.data = bytes;
+ this.width = width;
+ this.height = height;
+}
+
+PngIDAT.prototype =
+{
+ to_buffer: function(a, at)
+ {
+ at = at || 0;
+ var orig = at;
+ var x, y, i, j;
+ var dv = new SpiceDataView(a);
+ var zsum = new adler();
+ dv.setUint32(at, this.buffer_size() - 12); at += 4;
+ dv.setUint8(at, 'I'.charCodeAt(0)); at++;
+ dv.setUint8(at, 'D'.charCodeAt(0)); at++;
+ dv.setUint8(at, 'A'.charCodeAt(0)); at++;
+ dv.setUint8(at, 'T'.charCodeAt(0)); at++;
+
+ /* zlib header. */
+ dv.setUint8(at, 0x78); at++;
+ dv.setUint8(at, 0x01); at++;
+
+ /* Deflate header. Specifies uncompressed, final bit */
+ dv.setUint8(at, 0x80); at++;
+ dv.setUint16(at, this.data.byteLength + this.height); at += 2;
+ dv.setUint16(at, ~(this.data.byteLength + this.height)); at += 2;
+ var u8 = new Uint8Array(this.data);
+ for (i = 0, y = 0; y < this.height; y++)
+ {
+ /* Filter type 0 - uncompressed */
+ dv.setUint8(at, 0); at++;
+ zsum.update(0);
+ for (x = 0; x < this.width && i < this.data.byteLength; x++)
+ {
+ zsum.update(u8[i]);
+ dv.setUint8(at, u8[i++]); at++;
+ zsum.update(u8[i]);
+ dv.setUint8(at, u8[i++]); at++;
+ zsum.update(u8[i]);
+ dv.setUint8(at, u8[i++]); at++;
+ zsum.update(u8[i]);
+ dv.setUint8(at, u8[i++]); at++;
+ }
+ }
+
+ /* zlib checksum. */
+ dv.setUint16(at, zsum.s2); at+=2;
+ dv.setUint16(at, zsum.s1); at+=2;
+
+ /* FIXME - something is not quite right with the zlib code;
+ you get an error from libpng if you open the image in
+ gimp. But it works, so it's good enough for now... */
+
+ dv.setUint32(at, crc32(a, orig + 4, this.buffer_size() - 8)); at += 4;
+ return at;
+ },
+ buffer_size: function()
+ {
+ return 12 + this.data.byteLength + this.height + 4 + 2 + 1 + 2 + 2;
+ }
+}
+
+
+function PngIEND()
+{
+}
+
+PngIEND.prototype =
+{
+ to_buffer: function(a, at)
+ {
+ at = at || 0;
+ var orig = at;
+ var i;
+ var dv = new SpiceDataView(a);
+ dv.setUint32(at, this.buffer_size() - 12); at += 4;
+ dv.setUint8(at, 'I'.charCodeAt(0)); at++;
+ dv.setUint8(at, 'E'.charCodeAt(0)); at++;
+ dv.setUint8(at, 'N'.charCodeAt(0)); at++;
+ dv.setUint8(at, 'D'.charCodeAt(0)); at++;
+ dv.setUint32(at, crc32(a, orig + 4, this.buffer_size() - 8)); at += 4;
+ return at;
+ },
+ buffer_size: function()
+ {
+ return 12;
+ }
+}
+
+
+function create_rgba_png(width, height, bytes)
+{
+ var i;
+ var ihdr = new PngIHDR(width, height);
+ var idat = new PngIDAT(width, height, bytes);
+ var iend = new PngIEND;
+
+ var mb = new ArrayBuffer(ihdr.buffer_size() + idat.buffer_size() + iend.buffer_size());
+ var at = ihdr.to_buffer(mb);
+ at = idat.to_buffer(mb, at);
+ at = iend.to_buffer(mb, at);
+
+ var u8 = new Uint8Array(mb);
+ var str = "";
+ for (i = 0; i < at; i++)
+ {
+ str += "%";
+ if (u8[i] < 16)
+ str += "0";
+ str += u8[i].toString(16);
+ }
+
+
+ return "%89PNG%0D%0A%1A%0A" + str;
+}
diff --git a/src/sunstone/public/bower_components/spice-html5/quic.js b/src/sunstone/public/bower_components/spice-html5/quic.js
new file mode 100644
index 0000000000..9bb9f47b2d
--- /dev/null
+++ b/src/sunstone/public/bower_components/spice-html5/quic.js
@@ -0,0 +1,1335 @@
+/*"use strict";*/
+/* use strict is commented out because it results in a 5x slowdone in chrome */
+/*
+ * Copyright (C) 2012 by Jeremy P. White
+ * Copyright (C) 2012 by Aric Stewart
+ *
+ * This file is part of spice-html5.
+ *
+ * spice-html5 is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * spice-html5 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with spice-html5. If not, see .
+ */
+
+var encoder;
+
+var QUIC_IMAGE_TYPE_INVALID = 0;
+var QUIC_IMAGE_TYPE_GRAY = 1;
+var QUIC_IMAGE_TYPE_RGB16 = 2;
+var QUIC_IMAGE_TYPE_RGB24 = 3;
+var QUIC_IMAGE_TYPE_RGB32 = 4;
+var QUIC_IMAGE_TYPE_RGBA = 5;
+var DEFevol = 3;
+var DEFwmimax = 6;
+var DEFwminext = 2048;
+var need_init = true;
+var DEFmaxclen = 26;
+var evol = DEFevol;
+var wmimax = DEFwmimax;
+var wminext = DEFwminext;
+var family_5bpc = { nGRcodewords:[0,0,0,0,0,0,0,0],
+ notGRcwlen:[0,0,0,0,0,0,0,0],
+ notGRprefixmask:[0,0,0,0,0,0,0,0],
+ notGRsuffixlen:[0,0,0,0,0,0,0,0],
+ xlatU2L:[0,0,0,0,0,0,0,0],
+ xlatL2U:[0,0,0,0,0,0,0,0]
+ };
+var family_8bpc = { nGRcodewords:[0,0,0,0,0,0,0,0],
+ notGRcwlen:[0,0,0,0,0,0,0,0],
+ notGRprefixmask:[0,0,0,0,0,0,0,0],
+ notGRsuffixlen:[0,0,0,0,0,0,0,0],
+ xlatU2L:[0,0,0,0,0,0,0,0],
+ xlatL2U:[0,0,0,0,0,0,0,0]
+ };
+var bppmask = [ 0x00000000,
+ 0x00000001, 0x00000003, 0x00000007, 0x0000000f,
+ 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
+ 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
+ 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
+ 0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff,
+ 0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff,
+ 0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff,
+ 0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff];
+
+var zeroLUT = [];
+
+var besttrigtab = [
+ [ 550, 900, 800, 700, 500, 350, 300, 200, 180, 180, 160],
+ [ 110, 550, 900, 800, 550, 400, 350, 250, 140, 160, 140],
+ [ 100, 120, 550, 900, 700, 500, 400, 300, 220, 250, 160]];
+
+var J = [ 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 9, 10, 11, 12, 13, 14, 15];
+
+var lzeroes = [
+ 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0];
+
+var tabrand_chaos = [
+ 0x02c57542, 0x35427717, 0x2f5a2153, 0x9244f155, 0x7bd26d07, 0x354c6052,
+ 0x57329b28, 0x2993868e, 0x6cd8808c, 0x147b46e0, 0x99db66af, 0xe32b4cac,
+ 0x1b671264, 0x9d433486, 0x62a4c192, 0x06089a4b, 0x9e3dce44, 0xdaabee13,
+ 0x222425ea, 0xa46f331d, 0xcd589250, 0x8bb81d7f, 0xc8b736b9, 0x35948d33,
+ 0xd7ac7fd0, 0x5fbe2803, 0x2cfbc105, 0x013dbc4e, 0x7a37820f, 0x39f88e9e,
+ 0xedd58794, 0xc5076689, 0xfcada5a4, 0x64c2f46d, 0xb3ba3243, 0x8974b4f9,
+ 0x5a05aebd, 0x20afcd00, 0x39e2b008, 0x88a18a45, 0x600bde29, 0xf3971ace,
+ 0xf37b0a6b, 0x7041495b, 0x70b707ab, 0x06beffbb, 0x4206051f, 0xe13c4ee3,
+ 0xc1a78327, 0x91aa067c, 0x8295f72a, 0x732917a6, 0x1d871b4d, 0x4048f136,
+ 0xf1840e7e, 0x6a6048c1, 0x696cb71a, 0x7ff501c3, 0x0fc6310b, 0x57e0f83d,
+ 0x8cc26e74, 0x11a525a2, 0x946934c7, 0x7cd888f0, 0x8f9d8604, 0x4f86e73b,
+ 0x04520316, 0xdeeea20c, 0xf1def496, 0x67687288, 0xf540c5b2, 0x22401484,
+ 0x3478658a, 0xc2385746, 0x01979c2c, 0x5dad73c8, 0x0321f58b, 0xf0fedbee,
+ 0x92826ddf, 0x284bec73, 0x5b1a1975, 0x03df1e11, 0x20963e01, 0xa17cf12b,
+ 0x740d776e, 0xa7a6bf3c, 0x01b5cce4, 0x1118aa76, 0xfc6fac0a, 0xce927e9b,
+ 0x00bf2567, 0x806f216c, 0xbca69056, 0x795bd3e9, 0xc9dc4557, 0x8929b6c2,
+ 0x789d52ec, 0x3f3fbf40, 0xb9197368, 0xa38c15b5, 0xc3b44fa8, 0xca8333b0,
+ 0xb7e8d590, 0xbe807feb, 0xbf5f8360, 0xd99e2f5c, 0x372928e1, 0x7c757c4c,
+ 0x0db5b154, 0xc01ede02, 0x1fc86e78, 0x1f3985be, 0xb4805c77, 0x00c880fa,
+ 0x974c1b12, 0x35ab0214, 0xb2dc840d, 0x5b00ae37, 0xd313b026, 0xb260969d,
+ 0x7f4c8879, 0x1734c4d3, 0x49068631, 0xb9f6a021, 0x6b863e6f, 0xcee5debf,
+ 0x29f8c9fb, 0x53dd6880, 0x72b61223, 0x1f67a9fd, 0x0a0f6993, 0x13e59119,
+ 0x11cca12e, 0xfe6b6766, 0x16b6effc, 0x97918fc4, 0xc2b8a563, 0x94f2f741,
+ 0x0bfa8c9a, 0xd1537ae8, 0xc1da349c, 0x873c60ca, 0x95005b85, 0x9b5c080e,
+ 0xbc8abbd9, 0xe1eab1d2, 0x6dac9070, 0x4ea9ebf1, 0xe0cf30d4, 0x1ef5bd7b,
+ 0xd161043e, 0x5d2fa2e2, 0xff5d3cae, 0x86ed9f87, 0x2aa1daa1, 0xbd731a34,
+ 0x9e8f4b22, 0xb1c2c67a, 0xc21758c9, 0xa182215d, 0xccb01948, 0x8d168df7,
+ 0x04238cfe, 0x368c3dbc, 0x0aeadca5, 0xbad21c24, 0x0a71fee5, 0x9fc5d872,
+ 0x54c152c6, 0xfc329483, 0x6783384a, 0xeddb3e1c, 0x65f90e30, 0x884ad098,
+ 0xce81675a, 0x4b372f7d, 0x68bf9a39, 0x43445f1e, 0x40f8d8cb, 0x90d5acb6,
+ 0x4cd07282, 0x349eeb06, 0x0c9d5332, 0x520b24ef, 0x80020447, 0x67976491,
+ 0x2f931ca3, 0xfe9b0535, 0xfcd30220, 0x61a9e6cc, 0xa487d8d7, 0x3f7c5dd1,
+ 0x7d0127c5, 0x48f51d15, 0x60dea871, 0xc9a91cb7, 0x58b53bb3, 0x9d5e0b2d,
+ 0x624a78b4, 0x30dbee1b, 0x9bdf22e7, 0x1df5c299, 0x2d5643a7, 0xf4dd35ff,
+ 0x03ca8fd6, 0x53b47ed8, 0x6f2c19aa, 0xfeb0c1f4, 0x49e54438, 0x2f2577e6,
+ 0xbf876969, 0x72440ea9, 0xfa0bafb8, 0x74f5b3a0, 0x7dd357cd, 0x89ce1358,
+ 0x6ef2cdda, 0x1e7767f3, 0xa6be9fdb, 0x4f5f88f8, 0xba994a3a, 0x08ca6b65,
+ 0xe0893818, 0x9e00a16a, 0xf42bfc8f, 0x9972eedc, 0x749c8b51, 0x32c05f5e,
+ 0xd706805f, 0x6bfbb7cf, 0xd9210a10, 0x31a1db97, 0x923a9559, 0x37a7a1f6,
+ 0x059f8861, 0xca493e62, 0x65157e81, 0x8f6467dd, 0xab85ff9f, 0x9331aff2,
+ 0x8616b9f5, 0xedbd5695, 0xee7e29b1, 0x313ac44f, 0xb903112f, 0x432ef649,
+ 0xdc0a36c0, 0x61cf2bba, 0x81474925, 0xa8b6c7ad, 0xee5931de, 0xb2f8158d,
+ 0x59fb7409, 0x2e3dfaed, 0x9af25a3f, 0xe1fed4d5 ];
+
+var rgb32_pixel_pad = 3;
+var rgb32_pixel_r = 2;
+var rgb32_pixel_g = 1;
+var rgb32_pixel_b = 0;
+var rgb32_pixel_size = 4;
+
+/* Helper Functions */
+
+function ceil_log_2(val)
+{
+ if (val === 1)
+ return 0;
+
+ var result = 1;
+ val -= 1;
+ while (val = val >>> 1)
+ result++;
+
+ return result;
+}
+
+function family_init(family, bpc, limit)
+{
+ var l;
+ for (l = 0; l < bpc; l++)
+ {
+ var altprefixlen, altcodewords;
+ altprefixlen = limit - bpc;
+ if (altprefixlen > bppmask[bpc - l])
+ altprefixlen = bppmask[bpc - l];
+
+ altcodewords = bppmask[bpc] + 1 - (altprefixlen << l);
+ family.nGRcodewords[l] = (altprefixlen << l);
+ family.notGRcwlen[l] = altprefixlen + ceil_log_2(altcodewords);
+ family.notGRprefixmask[l] = bppmask[32 - altprefixlen]>>>0;
+ family.notGRsuffixlen[l] = ceil_log_2(altcodewords);
+ }
+
+ /* decorelate_init */
+ var pixelbitmask = bppmask[bpc];
+ var pixelbitmaskshr = pixelbitmask >>> 1;
+ var s;
+ for (s = 0; s <= pixelbitmask; s++) {
+ if (s <= pixelbitmaskshr) {
+ family.xlatU2L[s] = s << 1;
+ } else {
+ family.xlatU2L[s] = ((pixelbitmask - s) << 1) + 1;
+ }
+ }
+
+ /* corelate_init */
+ for (s = 0; s <= pixelbitmask; s++) {
+ if (s & 0x01) {
+ family.xlatL2U[s] = pixelbitmask - (s >>> 1);
+ } else {
+ family.xlatL2U[s] = (s >>> 1);
+ }
+ }
+}
+
+function quic_image_bpc(type)
+{
+ switch (type) {
+ case QUIC_IMAGE_TYPE_GRAY:
+ return 8;
+ case QUIC_IMAGE_TYPE_RGB16:
+ return 5;
+ case QUIC_IMAGE_TYPE_RGB24:
+ return 8;
+ case QUIC_IMAGE_TYPE_RGB32:
+ return 8;
+ case QUIC_IMAGE_TYPE_RGBA:
+ return 8;
+ case QUIC_IMAGE_TYPE_INVALID:
+ default:
+ console.log("quic: bad image type\n");
+ return 0;
+ }
+}
+
+function cnt_l_zeroes(bits)
+{
+ if (bits & 0xff800000) {
+ return lzeroes[bits >>> 24];
+ } else if (bits & 0xffff8000) {
+ return 8 + lzeroes[(bits >>> 16) & 0x000000ff];
+ } else if (bits & 0xffffff80) {
+ return 16 + lzeroes[(bits >>> 8) & 0x000000ff];
+ } else {
+ return 24 + lzeroes[bits & 0x000000ff];
+ }
+}
+
+function golomb_decoding_8bpc(l, bits)
+{
+ var rc;
+ var cwlen;
+
+ if (bits < 0 || bits > family_8bpc.notGRprefixmask[l])
+ {
+ var zeroprefix = cnt_l_zeroes(bits);
+ cwlen = zeroprefix + 1 + l;
+ rc = (zeroprefix << l) | (bits >> (32-cwlen)) & bppmask[l];
+ }
+ else
+ {
+ cwlen = family_8bpc.notGRcwlen[l];
+ rc = family_8bpc.nGRcodewords[l] + ((bits >> (32-cwlen)) & bppmask[family_8bpc.notGRsuffixlen[l]]);
+ }
+ return {'codewordlen':cwlen, 'rc':rc};
+}
+
+function golomb_code_len_8bpc(n, l)
+{
+ if (n < family_8bpc.nGRcodewords[l]) {
+ return (n >>> l) + 1 + l;
+ } else {
+ return family_8bpc.notGRcwlen[l];
+ }
+}
+
+function QuicModel(bpc)
+{
+ var bstart;
+ var bend = 0;
+
+ this.levels = 0x1 << bpc;
+ this.n_buckets_ptrs = 0;
+
+ switch (evol) {
+ case 1:
+ this.repfirst = 3;
+ this.firstsize = 1;
+ this.repnext = 2;
+ this.mulsize = 2;
+ break;
+ case 3:
+ this.repfirst = 1;
+ this.firstsize = 1;
+ this.repnext = 1;
+ this.mulsize = 2;
+ break;
+ case 5:
+ this.repfirst = 1;
+ this.firstsize = 1;
+ this.repnext = 1;
+ this.mulsize = 4;
+ break;
+ case 0:
+ case 2:
+ case 4:
+ console.log("quic: findmodelparams(): evol value obsolete!!!\n");
+ default:
+ console.log("quic: findmodelparams(): evol out of range!!!\n");
+ }
+
+ this.n_buckets = 0;
+ var repcntr = this.repfirst + 1;
+ var bsize = this.firstsize;
+
+ do {
+ if (this.n_buckets) {
+ bstart = bend + 1;
+ } else {
+ bstart = 0;
+ }
+
+ if (!--repcntr) {
+ repcntr = this.repnext;
+ bsize *= this.mulsize;
+ }
+
+ bend = bstart + bsize - 1;
+ if (bend + bsize >= this.levels) {
+ bend = this.levels - 1;
+ }
+
+ if (!this.n_buckets_ptrs) {
+ this.n_buckets_ptrs = this.levels;
+ }
+
+ (this.n_buckets)++;
+ } while (bend < this.levels - 1);
+}
+
+QuicModel.prototype = {
+ n_buckets : 0,
+ n_buckets_ptrs : 0,
+ repfirst : 0,
+ firstsize : 0,
+ repnext : 0,
+ mulsize : 0,
+ levels :0
+}
+
+function QuicBucket()
+{
+ this.counters = [0,0,0,0,0,0,0,0];
+}
+
+QuicBucket.prototype = {
+ bestcode: 0,
+
+ reste : function (bpp)
+ {
+ this.bestcode = bpp;
+ this.counters = [0,0,0,0,0,0,0,0];
+ },
+
+ update_model_8bpc : function (state, curval, bpp)
+ {
+ var i;
+
+ var bestcode = bpp - 1;
+ var bestcodelen = (this.counters[bestcode] += golomb_code_len_8bpc(curval, bestcode));
+
+ for (i = bpp - 2; i >= 0; i--) {
+ var ithcodelen = (this.counters[i] += golomb_code_len_8bpc(curval, i));
+
+ if (ithcodelen < bestcodelen) {
+ bestcode = i;
+ bestcodelen = ithcodelen;
+ }
+ }
+
+ this.bestcode = bestcode;
+
+ if (bestcodelen > state.wm_trigger) {
+ for (i = 0; i < bpp; i++) {
+ this.counters[i] = this.counters[i] >>> 1;
+ }
+ }
+ }
+}
+
+function QuicFamilyStat()
+{
+ this.buckets_ptrs = [];
+ this.buckets_buf = [];
+}
+
+QuicFamilyStat.prototype = {
+
+ fill_model_structures : function(model)
+ {
+ var bstart;
+ var bend = 0;
+ var bnumber = 0;
+
+ var repcntr = model.repfirst + 1;
+ var bsize = model.firstsize;
+
+ do {
+ if (bnumber) {
+ bstart = bend + 1;
+ } else {
+ bstart = 0;
+ }
+
+ if (!--repcntr) {
+ repcntr = model.repnext;
+ bsize *= model.mulsize;
+ }
+
+ bend = bstart + bsize - 1;
+ if (bend + bsize >= model.levels) {
+ bend = model.levels - 1;
+ }
+
+ this.buckets_buf[bnumber] = new QuicBucket;
+
+ var i;
+ for (i = bstart; i <= bend; i++) {
+ this.buckets_ptrs[i] = this.buckets_buf[bnumber];
+ }
+
+ bnumber++;
+ } while (bend < model.levels - 1);
+ return true;
+ }
+}
+
+function QuicChannel(model_8bpc, model_5bpc)
+{
+ this.state = new CommonState;
+ this.family_stat_8bpc = new QuicFamilyStat;
+ this.family_stat_5bpc = new QuicFamilyStat;
+ this.correlate_row = { zero: 0 , row:[] };
+ this.model_8bpc = model_8bpc;
+ this.model_5bpc = model_5bpc;
+ this.buckets_ptrs = [];
+
+ if (!this.family_stat_8bpc.fill_model_structures(this.model_8bpc))
+ return undefined;
+
+ if (!this.family_stat_5bpc.fill_model_structures(this.model_5bpc))
+ return undefined;
+}
+
+QuicChannel.prototype = {
+
+ reste : function (bpc)
+ {
+ var j;
+ this.correlate_row = { zero: 0 , row: []};
+
+ if (bpc == 8) {
+ for (j = 0; j < this.model_8bpc.n_buckets; j++)
+ this.family_stat_8bpc.buckets_buf[j].reste(7);
+ this.buckets_ptrs = this.family_stat_8bpc.buckets_ptrs;
+ } else if (bpc == 5) {
+ for (j = 0; j < this.model_5bpc.n_buckets; j++)
+ this.family_stat_8bpc.buckets_buf[j].reste(4);
+ this.buckets_ptrs = this.family_stat_5bpc.buckets_ptrs;
+ } else {
+ console.log("quic: %s: bad bpc %d\n", __FUNCTION__, bpc);
+ return false;
+ }
+
+ this.state.reste();
+ return true;
+ }
+}
+
+function CommonState()
+{
+}
+
+CommonState.prototype = {
+ waitcnt: 0,
+ tabrand_seed: 0xff,
+ wm_trigger: 0,
+ wmidx: 0,
+ wmileft: wminext,
+ melcstate: 0,
+ melclen: 0,
+ melcorder: 0,
+
+ set_wm_trigger : function()
+ {
+ var wm = this.wmidx;
+ if (wm > 10) {
+ wm = 10;
+ }
+
+ this.wm_trigger = besttrigtab[Math.floor(evol / 2)][wm];
+ },
+
+ reste : function()
+ {
+ this.waitcnt = 0;
+ this.tabrand_seed = 0x0ff;
+ this.wmidx = 0;
+ this.wmileft = wminext;
+
+ this.set_wm_trigger();
+
+ this.melcstate = 0;
+ this.melclen = J[0];
+ this.melcorder = 1 << this.melclen;
+ },
+
+ tabrand : function()
+ {
+ this.tabrand_seed++;
+ return tabrand_chaos[this.tabrand_seed & 0x0ff];
+ }
+}
+
+
+function QuicEncoder()
+{
+ this.rgb_state = new CommonState;
+ this.model_8bpc = new QuicModel(8);
+ this.model_5bpc = new QuicModel(5);
+ this.channels = [];
+
+ var i;
+ for (i = 0; i < 4; i++) {
+ this.channels[i] = new QuicChannel(this.model_8bpc, this.model_5bpc);
+ if (!this.channels[i])
+ {
+ console.log("quic: failed to create channel");
+ return undefined;
+ }
+ }
+}
+
+QuicEncoder.prototype = {
+ type: 0,
+ width: 0,
+ height: 0,
+ io_idx: 0,
+ io_available_bits: 0,
+ io_word: 0,
+ io_next_word: 0,
+ io_now: 0,
+ io_end: 0,
+ rows_completed: 0,
+ };
+
+QuicEncoder.prototype.reste = function(io_ptr)
+{
+ this.rgb_state.reste();
+
+ this.io_now = io_ptr;
+ this.io_end = this.io_now.length;
+ this.io_idx = 0;
+ this.rows_completed = 0;
+ return true;
+}
+
+QuicEncoder.prototype.read_io_word = function()
+{
+ if (this.io_idx >= this.io_end)
+ throw("quic: out of data");
+ this.io_next_word = this.io_now[this.io_idx++] | this.io_now[this.io_idx++]<<8 | this.io_now[this.io_idx++]<<16 | this.io_now[this.io_idx++]<<24;
+}
+
+QuicEncoder.prototype.decode_eatbits = function (len)
+{
+ this.io_word = this.io_word << len;
+
+ var delta = (this.io_available_bits - len);
+ if (delta >= 0)
+ {
+ this.io_available_bits = delta;
+ this.io_word |= this.io_next_word >>> this.io_available_bits;
+ }
+ else
+ {
+ delta = -1 * delta;
+ this.io_word |= this.io_next_word << delta;
+ this.read_io_word();
+ this.io_available_bits = 32 - delta;
+ this.io_word |= this.io_next_word >>> this.io_available_bits;
+ }
+}
+
+QuicEncoder.prototype.decode_eat32bits = function()
+{
+ this.decode_eatbits(16);
+ this.decode_eatbits(16);
+}
+
+QuicEncoder.prototype.reste_channels = function(bpc)
+{
+ var i;
+
+ for (i = 0; i < 4; i++)
+ if (!this.channels[i].reste(bpc))
+ return false;
+ return true;
+}
+
+QuicEncoder.prototype.quic_decode_begin = function(io_ptr)
+{
+ if (!this.reste(io_ptr)) {
+ return false;
+ }
+
+ this.io_idx = 0;
+ this.io_next_word = this.io_now[this.io_idx++] | this.io_now[this.io_idx++]<<8 | this.io_now[this.io_idx++]<<16 | this.io_now[this.io_idx++]<<24;
+ this.io_word = this.io_next_word;
+ this.io_available_bits = 0;
+
+ var magic = this.io_word;
+ this.decode_eat32bits();
+ if (magic != 0x43495551) /*QUIC*/ {
+ console.log("quic: bad magic "+magic.toString(16));
+ return false;
+ }
+
+ var version = this.io_word;
+ this.decode_eat32bits();
+ if (version != ((0 << 16) | (0 & 0xffff))) {
+ console.log("quic: bad version "+version.toString(16));
+ return false;
+ }
+
+ this.type = this.io_word;
+ this.decode_eat32bits();
+
+ this.width = this.io_word;
+ this.decode_eat32bits();
+
+ this.height = this.io_word;
+ this.decode_eat32bits();
+
+ var bpc = quic_image_bpc(this.type);
+
+ if (!this.reste_channels(bpc))
+ return false;
+
+ return true;
+}
+
+QuicEncoder.prototype.quic_rgb32_uncompress_row0_seg = function (i, cur_row, end,
+ waitmask, bpc, bpc_mask)
+{
+ var stopidx;
+ var n_channels = 3;
+ var c;
+ var a;
+
+ if (!i) {
+ cur_row[rgb32_pixel_pad] = 0;
+ c = 0;
+ do
+ {
+ a = golomb_decoding_8bpc(this.channels[c].buckets_ptrs[this.channels[c].correlate_row.zero].bestcode, this.io_word);
+ this.channels[c].correlate_row.row[0] = a.rc;
+ cur_row[2-c] = (family_8bpc.xlatL2U[a.rc]&0xFF);
+ this.decode_eatbits(a.codewordlen);
+ } while (++c < n_channels);
+
+ if (this.rgb_state.waitcnt) {
+ --this.rgb_state.waitcnt;
+ } else {
+ this.rgb_state.waitcnt = (this.rgb_state.tabrand() & waitmask);
+ c = 0;
+ do
+ {
+ this.channels[c].buckets_ptrs[this.channels[c].correlate_row.zero].update_model_8bpc(this.rgb_state, this.channels[c].correlate_row.row[0], bpc);
+ } while (++c < n_channels);
+ }
+ stopidx = ++i + this.rgb_state.waitcnt;
+ } else {
+ stopidx = i + this.rgb_state.waitcnt;
+ }
+
+ while (stopidx < end) {
+ for (; i <= stopidx; i++) {
+ cur_row[(i* rgb32_pixel_size)+rgb32_pixel_pad] = 0;
+ c = 0;
+ do
+ {
+ a = golomb_decoding_8bpc(this.channels[c].buckets_ptrs[this.channels[c].correlate_row.row[i - 1]].bestcode, this.io_word);
+ this.channels[c].correlate_row.row[i] = a.rc;
+ cur_row[(i* rgb32_pixel_size)+(2-c)] = (family_8bpc.xlatL2U[a.rc] + cur_row[((i-1) * rgb32_pixel_size) + (2-c)]) & bpc_mask;
+ this.decode_eatbits(a.codewordlen);
+ } while (++c < n_channels);
+ }
+ c = 0;
+ do
+ {
+ this.channels[c].buckets_ptrs[this.channels[c].correlate_row.row[stopidx - 1]].update_model_8bpc(this.rgb_state, this.channels[c].correlate_row.row[stopidx], bpc);
+ } while (++c < n_channels);
+ stopidx = i + (this.rgb_state.tabrand() & waitmask);
+ }
+
+ for (; i < end; i++) {
+ cur_row[(i* rgb32_pixel_size)+rgb32_pixel_pad] = 0;
+ c = 0;
+ do
+ {
+ a = golomb_decoding_8bpc(this.channels[c].buckets_ptrs[this.channels[c].correlate_row.row[i - 1]].bestcode, this.io_word);
+ this.channels[c].correlate_row.row[i] = a.rc;
+ cur_row[(i* rgb32_pixel_size)+(2-c)] = (family_8bpc.xlatL2U[a.rc] + cur_row[((i-1) * rgb32_pixel_size) + (2-c)]) & bpc_mask;
+ this.decode_eatbits(a.codewordlen);
+ } while (++c < n_channels);
+ }
+ this.rgb_state.waitcnt = stopidx - end;
+}
+
+QuicEncoder.prototype.quic_rgb32_uncompress_row0 = function (cur_row)
+{
+ var bpc = 8;
+ var bpc_mask = 0xff;
+ var pos = 0;
+ var width = this.width;
+
+ while ((wmimax > this.rgb_state.wmidx) && (this.rgb_state.wmileft <= width)) {
+ if (this.rgb_state.wmileft) {
+ this.quic_rgb32_uncompress_row0_seg(pos, cur_row,
+ pos + this.rgb_state.wmileft,
+ bppmask[this.rgb_state.wmidx],
+ bpc, bpc_mask);
+ pos += this.rgb_state.wmileft;
+ width -= this.rgb_state.wmileft;
+ }
+
+ this.rgb_state.wmidx++;
+ this.rgb_state.set_wm_trigger();
+ this.rgb_state.wmileft = wminext;
+ }
+
+ if (width) {
+ this.quic_rgb32_uncompress_row0_seg(pos, cur_row, pos + width,
+ bppmask[this.rgb_state.wmidx], bpc, bpc_mask);
+ if (wmimax > this.rgb_state.wmidx) {
+ this.rgb_state.wmileft -= width;
+ }
+ }
+}
+
+QuicEncoder.prototype.quic_rgb32_uncompress_row_seg = function( prev_row, cur_row, i, end, bpc, bpc_mask)
+{
+ var n_channels = 3;
+ var waitmask = bppmask[this.rgb_state.wmidx];
+
+ var a;
+ var run_index = 0;
+ var stopidx = 0;
+ var run_end = 0;
+ var c;
+
+ if (!i)
+ {
+ cur_row[rgb32_pixel_pad] = 0;
+
+ c = 0;
+ do {
+ a = golomb_decoding_8bpc(this.channels[c].buckets_ptrs[this.channels[c].correlate_row.zero].bestcode, this.io_word);
+ this.channels[c].correlate_row.row[0] = a.rc;
+ cur_row[2-c] = (family_8bpc.xlatL2U[this.channels[c].correlate_row.row[0]] + prev_row[2-c]) & bpc_mask;
+ this.decode_eatbits(a.codewordlen);
+ } while (++c < n_channels);
+
+ if (this.rgb_state.waitcnt) {
+ --this.rgb_state.waitcnt;
+ } else {
+ this.rgb_state.waitcnt = (this.rgb_state.tabrand() & waitmask);
+ c = 0;
+ do {
+ this.channels[c].buckets_ptrs[this.channels[c].correlate_row.zero].update_model_8bpc(this.rgb_state, this.channels[c].correlate_row.row[0], bpc);
+ } while (++c < n_channels);
+ }
+ stopidx = ++i + this.rgb_state.waitcnt;
+ } else {
+ stopidx = i + this.rgb_state.waitcnt;
+ }
+ for (;;) {
+ var rc = 0;
+ while (stopidx < end && !rc) {
+ for (; i <= stopidx && !rc; i++) {
+ var pixel = i * rgb32_pixel_size;
+ var pixelm1 = (i-1) * rgb32_pixel_size;
+ var pixelm2 = (i-2) * rgb32_pixel_size;
+
+ if ( prev_row[pixelm1+rgb32_pixel_r] == prev_row[pixel+rgb32_pixel_r] && prev_row[pixelm1+rgb32_pixel_g] == prev_row[pixel+rgb32_pixel_g] && prev_row[pixelm1 + rgb32_pixel_b] == prev_row[pixel+rgb32_pixel_b])
+ {
+ if (run_index != i && i > 2 && (cur_row[pixelm1+rgb32_pixel_r] == cur_row[pixelm2+rgb32_pixel_r] && cur_row[pixelm1+rgb32_pixel_g] == cur_row[pixelm2+rgb32_pixel_g] && cur_row[pixelm1+rgb32_pixel_b] == cur_row[pixelm2+rgb32_pixel_b]))
+ {
+ /* do run */
+ this.rgb_state.waitcnt = stopidx - i;
+ run_index = i;
+ run_end = i + this.decode_run(this.rgb_state);
+
+ for (; i < run_end; i++) {
+ var pixel = i * rgb32_pixel_size;
+ var pixelm1 = (i-1) * rgb32_pixel_size;
+ cur_row[pixel+rgb32_pixel_pad] = 0;
+ cur_row[pixel+rgb32_pixel_r] = cur_row[pixelm1+rgb32_pixel_r];
+ cur_row[pixel+rgb32_pixel_g] = cur_row[pixelm1+rgb32_pixel_g];
+ cur_row[pixel+rgb32_pixel_b] = cur_row[pixelm1+rgb32_pixel_b];
+ }
+
+ if (i == end) {
+ return;
+ }
+ else
+ {
+ stopidx = i + this.rgb_state.waitcnt;
+ rc = 1;
+ break;
+ }
+ }
+ }
+
+ c = 0;
+ cur_row[pixel+rgb32_pixel_pad] = 0;
+ do {
+ var cc = this.channels[c];
+ var cr = cc.correlate_row;
+
+ a = golomb_decoding_8bpc(cc.buckets_ptrs[cr.row[i-1]].bestcode, this.io_word);
+ cr.row[i] = a.rc;
+ cur_row[pixel+(2-c)] = (family_8bpc.xlatL2U[a.rc] + ((cur_row[pixelm1+(2-c)] + prev_row[pixel+(2-c)]) >> 1)) & bpc_mask;
+ this.decode_eatbits(a.codewordlen);
+ } while (++c < n_channels);
+ }
+ if (rc)
+ break;
+
+ c = 0;
+ do {
+ this.channels[c].buckets_ptrs[this.channels[c].correlate_row.row[stopidx - 1]].update_model_8bpc(this.rgb_state, this.channels[c].correlate_row.row[stopidx], bpc);
+ } while (++c < n_channels);
+
+ stopidx = i + (this.rgb_state.tabrand() & waitmask);
+ }
+
+ for (; i < end && !rc; i++) {
+ var pixel = i * rgb32_pixel_size;
+ var pixelm1 = (i-1) * rgb32_pixel_size;
+ var pixelm2 = (i-2) * rgb32_pixel_size;
+
+ if (prev_row[pixelm1+rgb32_pixel_r] == prev_row[pixel+rgb32_pixel_r] && prev_row[pixelm1+rgb32_pixel_g] == prev_row[pixel+rgb32_pixel_g] && prev_row[pixelm1+rgb32_pixel_b] == prev_row[pixel+rgb32_pixel_b])
+ {
+ if (run_index != i && i > 2 && (cur_row[pixelm1+rgb32_pixel_r] == cur_row[pixelm2+rgb32_pixel_r] && cur_row[pixelm1+rgb32_pixel_g] == cur_row[pixelm2+rgb32_pixel_g] && cur_row[pixelm1+rgb32_pixel_b] == cur_row[pixelm2+rgb32_pixel_b]))
+ {
+ /* do run */
+ this.rgb_state.waitcnt = stopidx - i;
+ run_index = i;
+ run_end = i + this.decode_run(this.rgb_state);
+
+ for (; i < run_end; i++) {
+ var pixel = i * rgb32_pixel_size;
+ var pixelm1 = (i-1) * rgb32_pixel_size;
+ cur_row[pixel+rgb32_pixel_pad] = 0;
+ cur_row[pixel+rgb32_pixel_r] = cur_row[pixelm1+rgb32_pixel_r];
+ cur_row[pixel+rgb32_pixel_g] = cur_row[pixelm1+rgb32_pixel_g];
+ cur_row[pixel+rgb32_pixel_b] = cur_row[pixelm1+rgb32_pixel_b];
+ }
+
+ if (i == end) {
+ return;
+ }
+ else
+ {
+ stopidx = i + this.rgb_state.waitcnt;
+ rc = 1;
+ break;
+ }
+ }
+ }
+
+ cur_row[pixel+rgb32_pixel_pad] = 0;
+ c = 0;
+ do
+ {
+ a = golomb_decoding_8bpc(this.channels[c].buckets_ptrs[this.channels[c].correlate_row.row[i-1]].bestcode, this.io_word);
+ this.channels[c].correlate_row.row[i] = a.rc;
+ cur_row[pixel+(2-c)] = (family_8bpc.xlatL2U[a.rc] + ((cur_row[pixelm1+(2-c)] + prev_row[pixel+(2-c)]) >> 1)) & bpc_mask;
+ this.decode_eatbits(a.codewordlen);
+ } while (++c < n_channels);
+ }
+
+ if (!rc)
+ {
+ this.rgb_state.waitcnt = stopidx - end;
+ return;
+ }
+ }
+}
+
+QuicEncoder.prototype.decode_run = function(state)
+{
+ var runlen = 0;
+
+ do {
+ var hits;
+ var x = (~(this.io_word >>> 24)>>>0)&0xff;
+ var temp = zeroLUT[x];
+
+ for (hits = 1; hits <= temp; hits++) {
+ runlen += state.melcorder;
+
+ if (state.melcstate < 32) {
+ state.melclen = J[++state.melcstate];
+ state.melcorder = (1 << state.melclen);
+ }
+ }
+ if (temp != 8) {
+ this.decode_eatbits(temp + 1);
+
+ break;
+ }
+ this.decode_eatbits(8);
+ } while (true);
+
+ if (state.melclen) {
+ runlen += this.io_word >>> (32 - state.melclen);
+ this.decode_eatbits(state.melclen);
+ }
+
+ if (state.melcstate) {
+ state.melclen = J[--state.melcstate];
+ state.melcorder = (1 << state.melclen);
+ }
+
+ return runlen;
+}
+
+QuicEncoder.prototype.quic_rgb32_uncompress_row = function (prev_row, cur_row)
+{
+ var bpc = 8;
+ var bpc_mask = 0xff;
+ var pos = 0;
+ var width = this.width;
+
+ while ((wmimax > this.rgb_state.wmidx) && (this.rgb_state.wmileft <= width)) {
+ if (this.rgb_state.wmileft) {
+ this.quic_rgb32_uncompress_row_seg(prev_row, cur_row, pos,
+ pos + this.rgb_state.wmileft, bpc, bpc_mask);
+ pos += this.rgb_state.wmileft;
+ width -= this.rgb_state.wmileft;
+ }
+
+ this.rgb_state.wmidx++;
+ this.rgb_state.set_wm_trigger();
+ this.rgb_state.wmileft = wminext;
+ }
+
+ if (width) {
+ this.quic_rgb32_uncompress_row_seg(prev_row, cur_row, pos,
+ pos + width, bpc, bpc_mask);
+ if (wmimax > this.rgb_state.wmidx) {
+ this.rgb_state.wmileft -= width;
+ }
+ }
+}
+
+QuicEncoder.prototype.quic_four_uncompress_row0_seg = function (channel, i,
+ correlate_row, cur_row, end, waitmask,
+ bpc, bpc_mask)
+{
+ var stopidx;
+ var a;
+
+ if (i == 0) {
+ a = golomb_decoding_8bpc(channel.buckets_ptrs[correlate_row.zero].bestcode, this.io_word);
+ correlate_row.row[0] = a.rc;
+ cur_row[rgb32_pixel_pad] = family_8bpc.xlatL2U[a.rc];
+ this.decode_eatbits(a.codewordlen);
+
+ if (channel.state.waitcnt) {
+ --channel.state.waitcnt;
+ } else {
+ channel.state.waitcnt = (channel.state.tabrand() & waitmask);
+ channel.buckets_ptrs[correlate_row.zero].update_model_8bpc(channel.state, correlate_row.row[0], bpc);
+ }
+ stopidx = ++i + channel.state.waitcnt;
+ } else {
+ stopidx = i + channel.state.waitcnt;
+ }
+
+ while (stopidx < end) {
+ var pbucket;
+
+ for (; i <= stopidx; i++) {
+ pbucket = channel.buckets_ptrs[correlate_row.row[i - 1]];
+
+ a = golomb_decoding_8bpc(pbucket.bestcode, this.io_word);
+ correlate_row.row[i] = a.rc;
+ cur_row[(i*rgb32_pixel_size)+rgb32_pixel_pad] = (family_8bpc.xlatL2U[a.rc] + cur_row[((i-1)*rgb32_pixel_size)+rgb32_pixel_pad]) & bpc_mask;
+ this.decode_eatbits(a.codewordlen);
+ }
+
+ pbucket.update_model_8bpc(channel.state, correlate_row.row[stopidx], bpc);
+
+ stopidx = i + (channel.state.tabrand() & waitmask);
+ }
+
+ for (; i < end; i++) {
+ a = golomb_decoding_8bpc(channel.buckets_ptrs[correlate_row.row[i-1]].bestcode, this.io_word);
+
+ correlate_row.row[i] = a.rc;
+ cur_row[(i*rgb32_pixel_size)+rgb32_pixel_pad] = (family_8bpc.xlatL2U[a.rc] + cur_row[((i-1)*rgb32_pixel_size)+rgb32_pixel_pad]) & bpc_mask;
+ this.decode_eatbits(a.codewordlen);
+ }
+ channel.state.waitcnt = stopidx - end;
+}
+
+QuicEncoder.prototype.quic_four_uncompress_row0 = function(channel, cur_row)
+{
+ var bpc = 8;
+ var bpc_mask = 0xff;
+ var correlate_row = channel.correlate_row;
+ var pos = 0;
+ var width = this.width;
+
+ while ((wmimax > channel.state.wmidx) && (channel.state.wmileft <= width)) {
+ if (channel.state.wmileft) {
+ this.quic_four_uncompress_row0_seg(channel, pos, correlate_row, cur_row,
+ pos + channel.state.wmileft, bppmask[channel.state.wmidx],
+ bpc, bpc_mask);
+ pos += channel.state.wmileft;
+ width -= channel.state.wmileft;
+ }
+
+ channel.state.wmidx++;
+ channel.state.set_wm_trigger();
+ channel.state.wmileft = wminext;
+ }
+
+ if (width) {
+ this.quic_four_uncompress_row0_seg(channel, pos, correlate_row, cur_row, pos + width,
+ bppmask[channel.state.wmidx], bpc, bpc_mask);
+ if (wmimax > channel.state.wmidx) {
+ channel.state.wmileft -= width;
+ }
+ }
+}
+
+QuicEncoder.prototype.quic_four_uncompress_row_seg = function (channel,
+ correlate_row, prev_row, cur_row, i,
+ end, bpc, bpc_mask)
+{
+ var waitmask = bppmask[channel.state.wmidx];
+ var stopidx;
+
+ var run_index = 0;
+ var run_end;
+
+ var a;
+
+ if (i == 0) {
+ a = golomb_decoding_8bpc(channel.buckets_ptrs[correlate_row.zero].bestcode, this.io_word);
+
+ correlate_row.row[0] = a.rc
+ cur_row[rgb32_pixel_pad] = (family_8bpc.xlatL2U[a.rc] + prev_row[rgb32_pixel_pad]) & bpc_mask;
+ this.decode_eatbits(a.codewordlen);
+
+ if (channel.state.waitcnt) {
+ --channel.state.waitcnt;
+ } else {
+ channel.state.waitcnt = (channel.state.tabrand() & waitmask);
+ channel.buckets_ptrs[correlate_row.zero].update_model_8bpc(channel.state, correlate_row.row[0], bpc);
+ }
+ stopidx = ++i + channel.state.waitcnt;
+ } else {
+ stopidx = i + channel.state.waitcnt;
+ }
+ for (;;) {
+ var rc = 0;
+ while (stopidx < end && !rc) {
+ var pbucket;
+ for (; i <= stopidx && !rc; i++) {
+ var pixel = i * rgb32_pixel_size;
+ var pixelm1 = (i-1) * rgb32_pixel_size;
+ var pixelm2 = (i-2) * rgb32_pixel_size;
+
+ if (prev_row[pixelm1+rgb32_pixel_pad] == prev_row[pixel+rgb32_pixel_pad])
+ {
+ if (run_index != i && i > 2 && cur_row[pixelm1+rgb32_pixel_pad] == cur_row[pixelm2+rgb32_pixel_pad])
+ {
+ /* do run */
+ channel.state.waitcnt = stopidx - i;
+ run_index = i;
+
+ run_end = i + this.decode_run(channel.state);
+
+ for (; i < run_end; i++) {
+ var pixel = i * rgb32_pixel_size;
+ var pixelm1 = (i-1) * rgb32_pixel_size;
+ cur_row[pixel+rgb32_pixel_pad] = cur_row[pixelm1+rgb32_pixel_pad];
+ }
+
+ if (i == end) {
+ return;
+ }
+ else
+ {
+ stopidx = i + channel.state.waitcnt;
+ rc = 1;
+ break;
+ }
+ }
+ }
+
+ pbucket = channel.buckets_ptrs[correlate_row.row[i - 1]];
+ a = golomb_decoding_8bpc(pbucket.bestcode, this.io_word);
+ correlate_row.row[i] = a.rc
+ cur_row[pixel+rgb32_pixel_pad] = (family_8bpc.xlatL2U[a.rc] + ((cur_row[pixelm1+rgb32_pixel_pad] + prev_row[pixel+rgb32_pixel_pad]) >> 1)) & bpc_mask;
+ this.decode_eatbits(a.codewordlen);
+ }
+ if (rc)
+ break;
+
+ pbucket.update_model_8bpc(channel.state, correlate_row.row[stopidx], bpc);
+
+ stopidx = i + (channel.state.tabrand() & waitmask);
+ }
+
+ for (; i < end && !rc; i++) {
+ var pixel = i * rgb32_pixel_size;
+ var pixelm1 = (i-1) * rgb32_pixel_size;
+ var pixelm2 = (i-2) * rgb32_pixel_size;
+ if (prev_row[pixelm1+rgb32_pixel_pad] == prev_row[pixel+rgb32_pixel_pad])
+ {
+ if (run_index != i && i > 2 && cur_row[pixelm1+rgb32_pixel_pad] == cur_row[pixelm2+rgb32_pixel_pad])
+ {
+ /* do run */
+ channel.state.waitcnt = stopidx - i;
+ run_index = i;
+
+ run_end = i + this.decode_run(channel.state);
+
+ for (; i < run_end; i++) {
+ var pixel = i * rgb32_pixel_size;
+ var pixelm1 = (i-1) * rgb32_pixel_size;
+ cur_row[pixel+rgb32_pixel_pad] = cur_row[pixelm1+rgb32_pixel_pad];
+ }
+
+ if (i == end) {
+ return;
+ }
+ else
+ {
+ stopidx = i + channel.state.waitcnt;
+ rc = 1;
+ break;
+ }
+ }
+ }
+
+ a = golomb_decoding_8bpc(channel.buckets_ptrs[correlate_row.row[i-1]].bestcode, this.io_word);
+ correlate_row.row[i] = a.rc;
+ cur_row[pixel+rgb32_pixel_pad] = (family_8bpc.xlatL2U[a.rc] + ((cur_row[pixelm1+rgb32_pixel_pad] + prev_row[pixel+rgb32_pixel_pad]) >> 1)) & bpc_mask;
+ this.decode_eatbits(a.codewordlen);
+ }
+
+ if (!rc)
+ {
+ channel.state.waitcnt = stopidx - end;
+ return;
+ }
+ }
+}
+
+QuicEncoder.prototype.quic_four_uncompress_row = function(channel, prev_row,
+ cur_row)
+{
+ var bpc = 8;
+ var bpc_mask = 0xff;
+ var correlate_row = channel.correlate_row;
+ var pos = 0;
+ var width = this.width;
+
+ while ((wmimax > channel.state.wmidx) && (channel.state.wmileft <= width)) {
+ if (channel.state.wmileft) {
+ this.quic_four_uncompress_row_seg(channel, correlate_row, prev_row, cur_row, pos,
+ pos + channel.state.wmileft, bpc, bpc_mask);
+ pos += channel.state.wmileft;
+ width -= channel.state.wmileft;
+ }
+
+ channel.state.wmidx++;
+ channel.state.set_wm_trigger();
+ channel.state.wmileft = wminext;
+ }
+
+ if (width) {
+ this.quic_four_uncompress_row_seg(channel, correlate_row, prev_row, cur_row, pos,
+ pos + width, bpc, bpc_mask);
+ if (wmimax > channel.state.wmidx) {
+ channel.state.wmileft -= width;
+ }
+ }
+}
+
+/* We need to be generating rgb32 or rgba */
+QuicEncoder.prototype.quic_decode = function(buf, stride)
+{
+ var row;
+
+ switch (this.type)
+ {
+ case QUIC_IMAGE_TYPE_RGB32:
+ case QUIC_IMAGE_TYPE_RGB24:
+ this.channels[0].correlate_row.zero = 0;
+ this.channels[1].correlate_row.zero = 0;
+ this.channels[2].correlate_row.zero = 0;
+ this.quic_rgb32_uncompress_row0(buf);
+
+ this.rows_completed++;
+ for (row = 1; row < this.height; row++)
+ {
+ var prev = buf;
+ buf = prev.subarray(stride);
+ this.channels[0].correlate_row.zero = this.channels[0].correlate_row.row[0];
+ this.channels[1].correlate_row.zero = this.channels[1].correlate_row.row[0];
+ this.channels[2].correlate_row.zero = this.channels[2].correlate_row.row[0];
+ this.quic_rgb32_uncompress_row(prev, buf);
+ this.rows_completed++;
+ };
+ break;
+ case QUIC_IMAGE_TYPE_RGB16:
+ console.log("quic: unsupported output format\n");
+ return false;
+ break;
+ case QUIC_IMAGE_TYPE_RGBA:
+ this.channels[0].correlate_row.zero = 0;
+ this.channels[1].correlate_row.zero = 0;
+ this.channels[2].correlate_row.zero = 0;
+ this.quic_rgb32_uncompress_row0(buf);
+
+ this.channels[3].correlate_row.zero = 0;
+ this.quic_four_uncompress_row0(this.channels[3], buf);
+
+ this.rows_completed++;
+ for (row = 1; row < this.height; row++) {
+ var prev = buf;
+ buf = prev.subarray(stride);
+
+ this.channels[0].correlate_row.zero = this.channels[0].correlate_row.row[0];
+ this.channels[1].correlate_row.zero = this.channels[1].correlate_row.row[0];
+ this.channels[2].correlate_row.zero = this.channels[2].correlate_row.row[0];
+ this.quic_rgb32_uncompress_row(prev, buf);
+
+ this.channels[3].correlate_row.zero = this.channels[3].correlate_row.row[0];
+ this.quic_four_uncompress_row(encoder.channels[3], prev, buf);
+ this.rows_completed++;
+ }
+ break;
+
+ case QUIC_IMAGE_TYPE_GRAY:
+ console.log("quic: unsupported output format\n");
+ return false;
+ break;
+
+ case QUIC_IMAGE_TYPE_INVALID:
+ default:
+ console.log("quic: bad image type\n");
+ return false;
+ }
+ return true;
+}
+
+QuicEncoder.prototype.simple_quic_decode = function(buf)
+{
+ var stride = 4; /* FIXME - proper stride calc please */
+ if (!this.quic_decode_begin(buf))
+ return undefined;
+ if (this.type != QUIC_IMAGE_TYPE_RGB32 && this.type != QUIC_IMAGE_TYPE_RGB24
+ && this.type != QUIC_IMAGE_TYPE_RGBA)
+ return undefined;
+ var out = new Uint8Array(this.width*this.height*4);
+ out[0] = 69;
+ if (this.quic_decode( out, (this.width * stride)))
+ return out;
+ return undefined;
+}
+
+function SpiceQuic()
+{
+}
+
+SpiceQuic.prototype =
+{
+ from_dv: function(dv, at, mb)
+ {
+ if (!encoder)
+ throw("quic: no quic encoder");
+ this.data_size = dv.getUint32(at, true);
+ at += 4;
+ var buf = new Uint8Array(mb.slice(at));
+ this.outptr = encoder.simple_quic_decode(buf);
+ if (this.outptr)
+ {
+ this.type = encoder.type;
+ this.width = encoder.width;
+ this.height = encoder.height;
+ }
+ at += buf.length;
+ return at;
+ },
+}
+
+function convert_spice_quic_to_web(context, spice_quic)
+{
+ var ret = context.createImageData(spice_quic.width, spice_quic.height);
+ var i;
+ for (i = 0; i < (ret.width * ret.height * 4); i+=4)
+ {
+ ret.data[i + 0] = spice_quic.outptr[i + 2];
+ ret.data[i + 1] = spice_quic.outptr[i + 1];
+ ret.data[i + 2] = spice_quic.outptr[i + 0];
+ if (spice_quic.type !== QUIC_IMAGE_TYPE_RGBA)
+ ret.data[i + 3] = 255;
+ else
+ ret.data[i + 3] = 255 - spice_quic.outptr[i + 3];
+ }
+ return ret;
+}
+
+/* Module initialization */
+if (need_init)
+{
+ need_init = false;
+
+ family_init(family_8bpc, 8, DEFmaxclen);
+ family_init(family_5bpc, 5, DEFmaxclen);
+ /* init_zeroLUT */
+ var i, j, k, l;
+
+ j = k = 1;
+ l = 8;
+ for (i = 0; i < 256; ++i) {
+ zeroLUT[i] = l;
+ --k;
+ if (k == 0) {
+ k = j;
+ --l;
+ j *= 2;
+ }
+ }
+
+ encoder = new QuicEncoder;
+
+ if (!encoder)
+ throw("quic: failed to create encoder");
+}
diff --git a/src/sunstone/public/bower_components/spice-html5/resize.js b/src/sunstone/public/bower_components/spice-html5/resize.js
new file mode 100644
index 0000000000..f5410d346c
--- /dev/null
+++ b/src/sunstone/public/bower_components/spice-html5/resize.js
@@ -0,0 +1,70 @@
+"use strict";
+/*
+ Copyright (C) 2014 by Jeremy P. White
+
+ This file is part of spice-html5.
+
+ spice-html5 is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ spice-html5 is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with spice-html5. If not, see .
+*/
+
+/*----------------------------------------------------------------------------
+** resize.js
+** This bit of Javascript is a set of logic to help with window
+** resizing, using the agent channel to request screen resizes.
+**
+** It's a bit tricky, as we want to wait for resizing to settle down
+** before sending a size. Further, while horizontal resizing to use the whole
+** browser width is fairly easy to arrange with css, resizing an element to use
+** the whole vertical space (or to force a middle div to consume the bulk of the browser
+** window size) is tricky, and the consensus seems to be that Javascript is
+** the only right way to do it.
+**--------------------------------------------------------------------------*/
+function resize_helper(sc)
+{
+ var w = document.getElementById(sc.screen_id).clientWidth;
+ var h = document.getElementById(sc.screen_id).clientHeight;
+
+ var m = document.getElementById(sc.message_id);
+
+ /* Resize vertically; basically we leave a 20 pixel margin
+ at the bottom, and use the position of the message window
+ to figure out how to resize */
+ var hd = window.innerHeight - m.offsetHeight - m.offsetTop - 20;
+
+ /* Xorg requires height be a multiple of 8; round up */
+ h = h + hd;
+ if (h % 8 > 0)
+ h += (8 - (h % 8));
+
+ /* Xorg requires width be a multiple of 8; round up */
+ if (w % 8 > 0)
+ w += (8 - (w % 8));
+
+
+ sc.resize_window(0, w, h, 32, 0, 0);
+ sc.spice_resize_timer = undefined;
+}
+
+function handle_resize(e)
+{
+ var sc = window.spice_connection;
+
+ if (sc && sc.spice_resize_timer)
+ {
+ window.clearTimeout(sc.spice_resize_timer);
+ sc.spice_resize_timer = undefined;
+ }
+
+ sc.spice_resize_timer = window.setTimeout(resize_helper, 200, sc);
+}
diff --git a/src/sunstone/public/bower_components/spice-html5/simulatecursor.js b/src/sunstone/public/bower_components/spice-html5/simulatecursor.js
new file mode 100644
index 0000000000..b1fce06866
--- /dev/null
+++ b/src/sunstone/public/bower_components/spice-html5/simulatecursor.js
@@ -0,0 +1,202 @@
+"use strict";
+/*
+ Copyright (C) 2013 by Jeremy P. White
+
+ This file is part of spice-html5.
+
+ spice-html5 is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ spice-html5 is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with spice-html5. If not, see .
+*/
+
+/*----------------------------------------------------------------------------
+** SpiceSimulateCursor
+** Internet Explorer 10 does not support data uri's in cursor assignment.
+** This file provides a number of gimmicks to compensate. First, if there
+** is a preloaded cursor available, we will use that. Failing that, we will
+** simulate a cursor using an image that is moved around the screen.
+**--------------------------------------------------------------------------*/
+var SpiceSimulateCursor = {
+
+cursors : new Array(),
+unknown_cursors : new Array(),
+warned: false,
+
+add_cursor: function(sha1, value)
+{
+ SpiceSimulateCursor.cursors[sha1] = value;
+},
+
+unknown_cursor: function(sha1, curdata)
+{
+ if (! SpiceSimulateCursor.warned)
+ {
+ SpiceSimulateCursor.warned = true;
+ alert("Internet Explorer does not support dynamic cursors. " +
+ "This page will now simulate cursors with images, " +
+ "which will be imperfect. We recommend using Chrome or Firefox instead. " +
+ "\n\nIf you need to use Internet Explorer, you can create a static cursor " +
+ "file for each cursor your application uses. " +
+ "View the console log for more information on creating static cursors for your environment.");
+ }
+
+ if (! SpiceSimulateCursor.unknown_cursors[sha1])
+ {
+ SpiceSimulateCursor.unknown_cursors[sha1] = curdata;
+ console.log('Unknown cursor. Simulation required. To avoid simulation for this cursor, create and include a custom javascript file, and add the following line:');
+ console.log('SpiceCursorSimulator.add_cursor("' + sha1 + '"), ".cur");');
+ console.log('And then run following command, redirecting output into .cur:');
+ console.log('php -r "echo urldecode(\'' + curdata + '\');"');
+ }
+},
+
+simulate_cursor: function (spicecursor, cursor, screen, pngstr)
+{
+ var cursor_sha = hex_sha1(pngstr + ' ' + cursor.header.hot_spot_x + ' ' + cursor.header.hot_spot_y);
+ if (typeof SpiceSimulateCursor.cursors != 'undefined')
+ if (typeof SpiceSimulateCursor.cursors[cursor_sha] != 'undefined')
+ {
+ var curstr = 'url(' + SpiceSimulateCursor.cursors[cursor_sha] + '), default';
+ screen.style.cursor = curstr;
+ }
+
+ if (window.getComputedStyle(screen, null).cursor == 'auto')
+ {
+ SpiceSimulateCursor.unknown_cursor(cursor_sha,
+ SpiceSimulateCursor.create_icondir(cursor.header.width, cursor.header.height,
+ cursor.data.byteLength, cursor.header.hot_spot_x, cursor.header.hot_spot_y) + pngstr);
+
+ document.getElementById(spicecursor.parent.screen_id).style.cursor = 'none';
+ if (! spicecursor.spice_simulated_cursor)
+ {
+ spicecursor.spice_simulated_cursor = document.createElement('img');
+
+ spicecursor.spice_simulated_cursor.style.position = 'absolute';
+ spicecursor.spice_simulated_cursor.style.display = 'none';
+ spicecursor.spice_simulated_cursor.style.overflow = 'hidden';
+
+ spicecursor.spice_simulated_cursor.spice_screen = document.getElementById(spicecursor.parent.screen_id);
+
+ spicecursor.spice_simulated_cursor.addEventListener('mousemove', SpiceSimulateCursor.handle_sim_mousemove);
+
+ spicecursor.spice_simulated_cursor.spice_screen.appendChild(spicecursor.spice_simulated_cursor);
+ }
+
+ spicecursor.spice_simulated_cursor.src = 'data:image/png,' + pngstr;
+
+ spicecursor.spice_simulated_cursor.spice_hot_x = cursor.header.hot_spot_x;
+ spicecursor.spice_simulated_cursor.spice_hot_y = cursor.header.hot_spot_y;
+
+ spicecursor.spice_simulated_cursor.style.pointerEvents = "none";
+ }
+ else
+ {
+ if (spicecursor.spice_simulated_cursor)
+ {
+ spicecursor.spice_simulated_cursor.spice_screen.removeChild(spicecursor.spice_simulated_cursor);
+ delete spicecursor.spice_simulated_cursor;
+ }
+ }
+},
+
+handle_sim_mousemove: function(e)
+{
+ var retval;
+ var f = SpiceSimulateCursor.duplicate_mouse_event(e, this.spice_screen);
+ return this.spice_screen.dispatchEvent(f);
+},
+
+duplicate_mouse_event: function(e, target)
+{
+ var evt = document.createEvent("mouseevent");
+ evt.initMouseEvent(e.type, true, true, e.view, e.detail,
+ e.screenX, e.screenY, e.clientX, e.clientY,
+ e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, e.button, e.relatedTarget);
+ return evt;
+},
+
+ICONDIR: function ()
+{
+},
+
+ICONDIRENTRY: function(width, height, bytes, hot_x, hot_y)
+{
+ this.width = width;
+ this.height = height;
+ this.bytes = bytes;
+ this.hot_x = hot_x;
+ this.hot_y = hot_y;
+},
+
+
+create_icondir: function (width, height, bytes, hot_x, hot_y)
+{
+ var i;
+ var header = new SpiceSimulateCursor.ICONDIR();
+ var entry = new SpiceSimulateCursor.ICONDIRENTRY(width, height, bytes, hot_x, hot_y);
+
+ var mb = new ArrayBuffer(header.buffer_size() + entry.buffer_size());
+ var at = header.to_buffer(mb);
+ at = entry.to_buffer(mb, at);
+
+ var u8 = new Uint8Array(mb);
+ var str = "";
+ for (i = 0; i < at; i++)
+ {
+ str += "%";
+ if (u8[i] < 16)
+ str += "0";
+ str += u8[i].toString(16);
+ }
+ return str;
+},
+
+};
+
+SpiceSimulateCursor.ICONDIR.prototype =
+{
+ to_buffer: function(a, at)
+ {
+ at = at || 0;
+ var dv = new SpiceDataView(a);
+ dv.setUint16(at, 0, true); at += 2;
+ dv.setUint16(at, 2, true); at += 2;
+ dv.setUint16(at, 1, true); at += 2;
+ return at;
+ },
+ buffer_size: function()
+ {
+ return 6;
+ }
+};
+
+SpiceSimulateCursor.ICONDIRENTRY.prototype =
+{
+ to_buffer: function(a, at)
+ {
+ at = at || 0;
+ var dv = new SpiceDataView(a);
+ dv.setUint8(at, this.width); at++;
+ dv.setUint8(at, this.height); at++;
+ dv.setUint8(at, 0); at++; /* color palette count, unused */
+ dv.setUint8(at, 0); at++; /* reserved */
+ dv.setUint16(at, this.hot_x, true); at += 2;
+ dv.setUint16(at, this.hot_y, true); at += 2;
+ dv.setUint32(at, this.bytes, true); at += 4;
+ dv.setUint32(at, at + 4, true); at += 4; /* Offset to bytes */
+ return at;
+ },
+ buffer_size: function()
+ {
+ return 16;
+ }
+};
diff --git a/src/sunstone/public/bower_components/spice-html5/spice-custom.css b/src/sunstone/public/bower_components/spice-html5/spice-custom.css
new file mode 100644
index 0000000000..3c28aed3ce
--- /dev/null
+++ b/src/sunstone/public/bower_components/spice-html5/spice-custom.css
@@ -0,0 +1,49 @@
+body
+{
+ margin: 0; padding: 0;
+ font-family: "Lucida Grande", "Lucida Sans Unicode", "Helvetica Neue", Helvetica, Arial, Verdana, sans-serif;
+ font-size: 12pt;
+ line-height: 1.5em;
+}
+
+* { margin: 0; }
+
+#spice-area
+{
+ height: 100%;
+ padding: 0;
+ margin-left: auto;
+ margin-right: auto;
+}
+.spice-screen
+{
+ min-height: 600px;
+ height: 100%;
+ margin-left: auto;
+ margin-right: auto;
+ padding: 0;
+ text-align: center;
+}
+.spice-message {
+ width: 700px;
+ height: 50px;
+ overflow: auto;
+ background-color: #efefef;
+ border: solid #c3c3c3 1px;
+ font-size: 8pt;
+ float: right;
+ margin-right: 30px;
+ line-height: 1.1em;
+ font-family: 'Andale Mono', monospace;
+}
+.spice-message p {
+ margin-bottom: 0em;
+ margin-top: 0em;
+}
+.spice-message-warning {
+ color: orange;
+}
+.spice-message-error {
+ color: red;
+}
+
diff --git a/src/sunstone/public/bower_components/spice-html5/spice-html5.spec.in b/src/sunstone/public/bower_components/spice-html5/spice-html5.spec.in
new file mode 100644
index 0000000000..f69e051772
--- /dev/null
+++ b/src/sunstone/public/bower_components/spice-html5/spice-html5.spec.in
@@ -0,0 +1,61 @@
+Name: spice-html5
+Version: VERSION
+Release: 1%{?dist}
+Summary: Pure Javascript SPICE client
+
+License: LGPLv3
+URL: http://www.spice-space.org
+Source0: http://people.freedesktop.org/~jwhite/%{name}/%{name}-%{version}.tar.gz
+
+BuildArch: noarch
+
+%description
+%{name} is a Javascript SPICE client. This includes a simple HTML
+page to initiate a session, and the client itself. It includes a configuration
+file for Apache, but should work with any web server.
+
+%prep
+%setup -q
+
+
+%build
+
+%install
+%make_install
+
+
+%files
+%{_datadir}/%{name}
+%doc COPYING COPYING.LESSER README TODO apache.conf.sample
+
+
+%changelog
+* Thu Sep 25 2014 Jeremy White 0.1.5-1
+- If an agent is attached, enable dynamic resizing of the guest screen.
+- Add support for audio streams using the Opus encoding.
+- Vladik Romanovsky: Use wss scheme when accessing with https protocol
+
+* Thu Sep 19 2013 Jeremy White 0.1.4-1
+- Reduce memory leaks
+- Ack every message.
+- Aric Stewart: Fix and implement cache handling
+- Jordan Pittier: Fix default websocket port detection in spice_auto.html
+- Alon Levy: remove default password
+- Thomas Goirand - Adds missing mapping of the alphanumeric minus key
+
+* Thu May 23 2013 Jeremy White 0.1.3-1
+- Correct spice_auto.html for a missing include for the spice array buffer.
+- Provide limited compatibility for IE10.
+- Amos Benari: added on succeess event and added sendCtrlAltDel method.
+
+* Mon Feb 25 2013 Jeremy White 0.1.2-2
+- Revise the .spec file to use %%{name}, and remove a few uneeded statements
+- No longer install apache.conf, just put a sample under doc/
+- Switch to an alternate download location, more easily updated
+
+* Wed Feb 13 2013 Jeremy White 0.1.1-1
+- Correct the license to LGPL
+- Revise the Apache configuration file to allow access more broadly
+
+* Fri Feb 8 2013 Jeremy White 0.1.0-1
+- Initial version for packaging.
diff --git a/src/sunstone/public/bower_components/spice-html5/spice.css b/src/sunstone/public/bower_components/spice-html5/spice.css
new file mode 100644
index 0000000000..3c28aed3ce
--- /dev/null
+++ b/src/sunstone/public/bower_components/spice-html5/spice.css
@@ -0,0 +1,49 @@
+body
+{
+ margin: 0; padding: 0;
+ font-family: "Lucida Grande", "Lucida Sans Unicode", "Helvetica Neue", Helvetica, Arial, Verdana, sans-serif;
+ font-size: 12pt;
+ line-height: 1.5em;
+}
+
+* { margin: 0; }
+
+#spice-area
+{
+ height: 100%;
+ padding: 0;
+ margin-left: auto;
+ margin-right: auto;
+}
+.spice-screen
+{
+ min-height: 600px;
+ height: 100%;
+ margin-left: auto;
+ margin-right: auto;
+ padding: 0;
+ text-align: center;
+}
+.spice-message {
+ width: 700px;
+ height: 50px;
+ overflow: auto;
+ background-color: #efefef;
+ border: solid #c3c3c3 1px;
+ font-size: 8pt;
+ float: right;
+ margin-right: 30px;
+ line-height: 1.1em;
+ font-family: 'Andale Mono', monospace;
+}
+.spice-message p {
+ margin-bottom: 0em;
+ margin-top: 0em;
+}
+.spice-message-warning {
+ color: orange;
+}
+.spice-message-error {
+ color: red;
+}
+
diff --git a/src/sunstone/public/bower_components/spice-html5/spice.html b/src/sunstone/public/bower_components/spice-html5/spice.html
new file mode 100644
index 0000000000..e830eb3d37
--- /dev/null
+++ b/src/sunstone/public/bower_components/spice-html5/spice.html
@@ -0,0 +1,149 @@
+
+
+
+
+
+
+ Spice Javascript client
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+