spice-html5-rails 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/COPYING +674 -0
- data/COPYING.LESSER +165 -0
- data/LICENSE.txt +15 -0
- data/README.md +35 -0
- data/lib/spice-html5-rails/version.rb +7 -0
- data/lib/spice-html5-rails.rb +10 -0
- data/vendor/assets/javascripts/spice-html5.js +25 -0
- data/vendor/assets/javascripts/spiceHTML5/atKeynames.js +183 -0
- data/vendor/assets/javascripts/spiceHTML5/bitmap.js +51 -0
- data/vendor/assets/javascripts/spiceHTML5/cursor.js +92 -0
- data/vendor/assets/javascripts/spiceHTML5/display.js +806 -0
- data/vendor/assets/javascripts/spiceHTML5/enums.js +282 -0
- data/vendor/assets/javascripts/spiceHTML5/inputs.js +271 -0
- data/vendor/assets/javascripts/spiceHTML5/lz.js +166 -0
- data/vendor/assets/javascripts/spiceHTML5/main.js +177 -0
- data/vendor/assets/javascripts/spiceHTML5/png.js +256 -0
- data/vendor/assets/javascripts/spiceHTML5/quic.js +1335 -0
- data/vendor/assets/javascripts/spiceHTML5/spiceconn.js +455 -0
- data/vendor/assets/javascripts/spiceHTML5/spicedataview.js +96 -0
- data/vendor/assets/javascripts/spiceHTML5/spicemsg.js +883 -0
- data/vendor/assets/javascripts/spiceHTML5/spicetype.js +480 -0
- data/vendor/assets/javascripts/spiceHTML5/thirdparty/jsbn.js +589 -0
- data/vendor/assets/javascripts/spiceHTML5/thirdparty/prng4.js +79 -0
- data/vendor/assets/javascripts/spiceHTML5/thirdparty/rng.js +102 -0
- data/vendor/assets/javascripts/spiceHTML5/thirdparty/rsa.js +146 -0
- data/vendor/assets/javascripts/spiceHTML5/thirdparty/sha1.js +346 -0
- data/vendor/assets/javascripts/spiceHTML5/ticket.js +250 -0
- data/vendor/assets/javascripts/spiceHTML5/utils.js +261 -0
- data/vendor/assets/javascripts/spiceHTML5/wire.js +123 -0
- metadata +108 -0
@@ -0,0 +1,806 @@
|
|
1
|
+
"use strict";
|
2
|
+
/*
|
3
|
+
Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com>
|
4
|
+
|
5
|
+
This file is part of spice-html5.
|
6
|
+
|
7
|
+
spice-html5 is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the GNU Lesser General Public License as published by
|
9
|
+
the Free Software Foundation, either version 3 of the License, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
spice-html5 is distributed in the hope that it will be useful,
|
13
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
GNU Lesser General Public License for more details.
|
16
|
+
|
17
|
+
You should have received a copy of the GNU Lesser General Public License
|
18
|
+
along with spice-html5. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
*/
|
20
|
+
|
21
|
+
|
22
|
+
/*----------------------------------------------------------------------------
|
23
|
+
** FIXME: putImageData does not support Alpha blending
|
24
|
+
** or compositing. So if we have data in an ImageData
|
25
|
+
** format, we have to draw it onto a context,
|
26
|
+
** and then use drawImage to put it onto the target,
|
27
|
+
** as drawImage does alpha.
|
28
|
+
**--------------------------------------------------------------------------*/
|
29
|
+
function putImageDataWithAlpha(context, d, x, y)
|
30
|
+
{
|
31
|
+
var c = document.createElement("canvas");
|
32
|
+
var t = c.getContext("2d");
|
33
|
+
c.setAttribute('width', d.width);
|
34
|
+
c.setAttribute('height', d.height);
|
35
|
+
t.putImageData(d, 0, 0);
|
36
|
+
context.drawImage(c, x, y, d.width, d.height);
|
37
|
+
}
|
38
|
+
|
39
|
+
/*----------------------------------------------------------------------------
|
40
|
+
** FIXME: Spice will send an image with '0' alpha when it is intended to
|
41
|
+
** go on a surface w/no alpha. So in that case, we have to strip
|
42
|
+
** out the alpha. The test case for this was flux box; in a Xspice
|
43
|
+
** server, right click on the desktop to get the menu; the top bar
|
44
|
+
** doesn't paint/highlight correctly w/out this change.
|
45
|
+
**--------------------------------------------------------------------------*/
|
46
|
+
function stripAlpha(d)
|
47
|
+
{
|
48
|
+
var i;
|
49
|
+
for (i = 0; i < (d.width * d.height * 4); i += 4)
|
50
|
+
d.data[i + 3] = 255;
|
51
|
+
}
|
52
|
+
|
53
|
+
/*----------------------------------------------------------------------------
|
54
|
+
** SpiceDisplayConn
|
55
|
+
** Drive the Spice Display Channel
|
56
|
+
**--------------------------------------------------------------------------*/
|
57
|
+
function SpiceDisplayConn()
|
58
|
+
{
|
59
|
+
SpiceConn.apply(this, arguments);
|
60
|
+
}
|
61
|
+
|
62
|
+
SpiceDisplayConn.prototype = Object.create(SpiceConn.prototype);
|
63
|
+
SpiceDisplayConn.prototype.process_channel_message = function(msg)
|
64
|
+
{
|
65
|
+
if (msg.type == SPICE_MSG_DISPLAY_MARK)
|
66
|
+
{
|
67
|
+
// FIXME - DISPLAY_MARK not implemented (may be hard or impossible)
|
68
|
+
this.known_unimplemented(msg.type, "Display Mark");
|
69
|
+
return true;
|
70
|
+
}
|
71
|
+
|
72
|
+
if (msg.type == SPICE_MSG_DISPLAY_RESET)
|
73
|
+
{
|
74
|
+
DEBUG > 2 && console.log("Display reset");
|
75
|
+
this.surfaces[this.primary_surface].canvas.context.restore();
|
76
|
+
return true;
|
77
|
+
}
|
78
|
+
|
79
|
+
if (msg.type == SPICE_MSG_DISPLAY_DRAW_COPY)
|
80
|
+
{
|
81
|
+
var draw_copy = new SpiceMsgDisplayDrawCopy(msg.data);
|
82
|
+
|
83
|
+
DEBUG > 1 && this.log_draw("DrawCopy", draw_copy);
|
84
|
+
|
85
|
+
if (! draw_copy.base.box.is_same_size(draw_copy.data.src_area))
|
86
|
+
this.log_warn("FIXME: DrawCopy src_area is a different size than base.box; we do not handle that yet.");
|
87
|
+
if (draw_copy.base.clip.type != SPICE_CLIP_TYPE_NONE)
|
88
|
+
this.log_warn("FIXME: DrawCopy we don't handle clipping yet");
|
89
|
+
if (draw_copy.data.rop_descriptor != SPICE_ROPD_OP_PUT)
|
90
|
+
this.log_warn("FIXME: DrawCopy we don't handle ropd type: " + draw_copy.data.rop_descriptor);
|
91
|
+
if (draw_copy.data.mask.flags)
|
92
|
+
this.log_warn("FIXME: DrawCopy we don't handle mask flag: " + draw_copy.data.mask.flags);
|
93
|
+
if (draw_copy.data.mask.bitmap)
|
94
|
+
this.log_warn("FIXME: DrawCopy we don't handle mask");
|
95
|
+
|
96
|
+
if (draw_copy.data && draw_copy.data.src_bitmap)
|
97
|
+
{
|
98
|
+
if (draw_copy.data.src_bitmap.descriptor.flags &&
|
99
|
+
draw_copy.data.src_bitmap.descriptor.flags != SPICE_IMAGE_FLAGS_CACHE_ME &&
|
100
|
+
draw_copy.data.src_bitmap.descriptor.flags != SPICE_IMAGE_FLAGS_HIGH_BITS_SET)
|
101
|
+
{
|
102
|
+
this.log_warn("FIXME: DrawCopy unhandled image flags: " + draw_copy.data.src_bitmap.descriptor.flags);
|
103
|
+
DEBUG <= 1 && this.log_draw("DrawCopy", draw_copy);
|
104
|
+
}
|
105
|
+
|
106
|
+
if (draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_QUIC)
|
107
|
+
{
|
108
|
+
var canvas = this.surfaces[draw_copy.base.surface_id].canvas;
|
109
|
+
if (! draw_copy.data.src_bitmap.quic)
|
110
|
+
{
|
111
|
+
this.log_warn("FIXME: DrawCopy could not handle this QUIC file.");
|
112
|
+
return false;
|
113
|
+
}
|
114
|
+
var source_img = convert_spice_quic_to_web(canvas.context,
|
115
|
+
draw_copy.data.src_bitmap.quic);
|
116
|
+
|
117
|
+
return this.draw_copy_helper(
|
118
|
+
{ base: draw_copy.base,
|
119
|
+
src_area: draw_copy.data.src_area,
|
120
|
+
image_data: source_img,
|
121
|
+
tag: "copyquic." + draw_copy.data.src_bitmap.quic.type,
|
122
|
+
has_alpha: (draw_copy.data.src_bitmap.quic.type == QUIC_IMAGE_TYPE_RGBA ? true : false) ,
|
123
|
+
descriptor : draw_copy.data.src_bitmap.descriptor
|
124
|
+
});
|
125
|
+
}
|
126
|
+
else if (draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_FROM_CACHE ||
|
127
|
+
draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_FROM_CACHE_LOSSLESS)
|
128
|
+
{
|
129
|
+
if (! this.cache || ! this.cache[draw_copy.data.src_bitmap.descriptor.id])
|
130
|
+
{
|
131
|
+
this.log_warn("FIXME: DrawCopy did not find image id " + draw_copy.data.src_bitmap.descriptor.id + " in cache.");
|
132
|
+
return false;
|
133
|
+
}
|
134
|
+
|
135
|
+
return this.draw_copy_helper(
|
136
|
+
{ base: draw_copy.base,
|
137
|
+
src_area: draw_copy.data.src_area,
|
138
|
+
image_data: this.cache[draw_copy.data.src_bitmap.descriptor.id],
|
139
|
+
tag: "copycache." + draw_copy.data.src_bitmap.descriptor.id,
|
140
|
+
has_alpha: true, /* FIXME - may want this to be false... */
|
141
|
+
descriptor : draw_copy.data.src_bitmap.descriptor
|
142
|
+
});
|
143
|
+
|
144
|
+
/* FIXME - LOSSLESS CACHE ramifications not understood or handled */
|
145
|
+
}
|
146
|
+
else if (draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_SURFACE)
|
147
|
+
{
|
148
|
+
var source_context = this.surfaces[draw_copy.data.src_bitmap.surface_id].canvas.context;
|
149
|
+
var target_context = this.surfaces[draw_copy.base.surface_id].canvas.context;
|
150
|
+
|
151
|
+
var source_img = source_context.getImageData(
|
152
|
+
draw_copy.data.src_area.left, draw_copy.data.src_area.top,
|
153
|
+
draw_copy.data.src_area.right - draw_copy.data.src_area.left,
|
154
|
+
draw_copy.data.src_area.bottom - draw_copy.data.src_area.top);
|
155
|
+
var computed_src_area = new SpiceRect;
|
156
|
+
computed_src_area.top = computed_src_area.left = 0;
|
157
|
+
computed_src_area.right = source_img.width;
|
158
|
+
computed_src_area.bottom = source_img.height;
|
159
|
+
|
160
|
+
/* FIXME - there is a potential optimization here.
|
161
|
+
That is, if the surface is from 0,0, and
|
162
|
+
both surfaces are alpha surfaces, you should
|
163
|
+
be able to just do a drawImage, which should
|
164
|
+
save time. */
|
165
|
+
|
166
|
+
return this.draw_copy_helper(
|
167
|
+
{ base: draw_copy.base,
|
168
|
+
src_area: computed_src_area,
|
169
|
+
image_data: source_img,
|
170
|
+
tag: "copysurf." + draw_copy.data.src_bitmap.surface_id,
|
171
|
+
has_alpha: this.surfaces[draw_copy.data.src_bitmap.surface_id].format == SPICE_SURFACE_FMT_32_xRGB ? false : true,
|
172
|
+
descriptor : draw_copy.data.src_bitmap.descriptor
|
173
|
+
});
|
174
|
+
|
175
|
+
return true;
|
176
|
+
}
|
177
|
+
else if (draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_JPEG)
|
178
|
+
{
|
179
|
+
if (! draw_copy.data.src_bitmap.jpeg)
|
180
|
+
{
|
181
|
+
this.log_warn("FIXME: DrawCopy could not handle this JPEG file.");
|
182
|
+
return false;
|
183
|
+
}
|
184
|
+
|
185
|
+
// FIXME - how lame is this. Be have it in binary format, and we have
|
186
|
+
// to put it into string to get it back into jpeg. Blech.
|
187
|
+
var tmpstr = "data:image/jpeg,";
|
188
|
+
var img = new Image;
|
189
|
+
var i;
|
190
|
+
var qdv = new Uint8Array(draw_copy.data.src_bitmap.jpeg.data);
|
191
|
+
for (i = 0; i < qdv.length; i++)
|
192
|
+
{
|
193
|
+
tmpstr += '%';
|
194
|
+
if (qdv[i] < 16)
|
195
|
+
tmpstr += '0';
|
196
|
+
tmpstr += qdv[i].toString(16);
|
197
|
+
}
|
198
|
+
|
199
|
+
img.o =
|
200
|
+
{ base: draw_copy.base,
|
201
|
+
tag: "jpeg." + draw_copy.data.src_bitmap.surface_id,
|
202
|
+
descriptor : draw_copy.data.src_bitmap.descriptor,
|
203
|
+
sc : this,
|
204
|
+
};
|
205
|
+
img.onload = handle_draw_jpeg_onload;
|
206
|
+
img.src = tmpstr;
|
207
|
+
|
208
|
+
return true;
|
209
|
+
}
|
210
|
+
else if (draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_JPEG_ALPHA)
|
211
|
+
{
|
212
|
+
if (! draw_copy.data.src_bitmap.jpeg_alpha)
|
213
|
+
{
|
214
|
+
this.log_warn("FIXME: DrawCopy could not handle this JPEG ALPHA file.");
|
215
|
+
return false;
|
216
|
+
}
|
217
|
+
|
218
|
+
// FIXME - how lame is this. Be have it in binary format, and we have
|
219
|
+
// to put it into string to get it back into jpeg. Blech.
|
220
|
+
var tmpstr = "data:image/jpeg,";
|
221
|
+
var img = new Image;
|
222
|
+
var i;
|
223
|
+
var qdv = new Uint8Array(draw_copy.data.src_bitmap.jpeg_alpha.data);
|
224
|
+
for (i = 0; i < qdv.length; i++)
|
225
|
+
{
|
226
|
+
tmpstr += '%';
|
227
|
+
if (qdv[i] < 16)
|
228
|
+
tmpstr += '0';
|
229
|
+
tmpstr += qdv[i].toString(16);
|
230
|
+
}
|
231
|
+
|
232
|
+
img.o =
|
233
|
+
{ base: draw_copy.base,
|
234
|
+
tag: "jpeg." + draw_copy.data.src_bitmap.surface_id,
|
235
|
+
descriptor : draw_copy.data.src_bitmap.descriptor,
|
236
|
+
sc : this,
|
237
|
+
};
|
238
|
+
|
239
|
+
if (this.surfaces[draw_copy.base.surface_id].format == SPICE_SURFACE_FMT_32_ARGB)
|
240
|
+
{
|
241
|
+
|
242
|
+
var canvas = this.surfaces[draw_copy.base.surface_id].canvas;
|
243
|
+
img.alpha_img = convert_spice_lz_to_web(canvas.context,
|
244
|
+
draw_copy.data.src_bitmap.jpeg_alpha.alpha);
|
245
|
+
}
|
246
|
+
img.onload = handle_draw_jpeg_onload;
|
247
|
+
img.src = tmpstr;
|
248
|
+
|
249
|
+
return true;
|
250
|
+
}
|
251
|
+
else if (draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_BITMAP)
|
252
|
+
{
|
253
|
+
var canvas = this.surfaces[draw_copy.base.surface_id].canvas;
|
254
|
+
if (! draw_copy.data.src_bitmap.bitmap)
|
255
|
+
{
|
256
|
+
this.log_err("null bitmap");
|
257
|
+
return false;
|
258
|
+
}
|
259
|
+
|
260
|
+
var source_img = convert_spice_bitmap_to_web(canvas.context,
|
261
|
+
draw_copy.data.src_bitmap.bitmap);
|
262
|
+
if (! source_img)
|
263
|
+
{
|
264
|
+
this.log_warn("FIXME: Unable to interpret bitmap of format: " +
|
265
|
+
draw_copy.data.src_bitmap.bitmap.format);
|
266
|
+
return false;
|
267
|
+
}
|
268
|
+
|
269
|
+
return this.draw_copy_helper(
|
270
|
+
{ base: draw_copy.base,
|
271
|
+
src_area: draw_copy.data.src_area,
|
272
|
+
image_data: source_img,
|
273
|
+
tag: "bitmap." + draw_copy.data.src_bitmap.bitmap.format,
|
274
|
+
has_alpha: draw_copy.data.src_bitmap.bitmap == SPICE_BITMAP_FMT_32BIT ? false : true,
|
275
|
+
descriptor : draw_copy.data.src_bitmap.descriptor
|
276
|
+
});
|
277
|
+
}
|
278
|
+
else if (draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_LZ_RGB)
|
279
|
+
{
|
280
|
+
var canvas = this.surfaces[draw_copy.base.surface_id].canvas;
|
281
|
+
if (! draw_copy.data.src_bitmap.lz_rgb)
|
282
|
+
{
|
283
|
+
this.log_err("null lz_rgb ");
|
284
|
+
return false;
|
285
|
+
}
|
286
|
+
|
287
|
+
if (draw_copy.data.src_bitmap.lz_rgb.top_down != 1)
|
288
|
+
this.log_warn("FIXME: Implement non top down support for lz_rgb");
|
289
|
+
|
290
|
+
var source_img = convert_spice_lz_to_web(canvas.context,
|
291
|
+
draw_copy.data.src_bitmap.lz_rgb);
|
292
|
+
if (! source_img)
|
293
|
+
{
|
294
|
+
this.log_warn("FIXME: Unable to interpret bitmap of type: " +
|
295
|
+
draw_copy.data.src_bitmap.lz_rgb.type);
|
296
|
+
return false;
|
297
|
+
}
|
298
|
+
|
299
|
+
return this.draw_copy_helper(
|
300
|
+
{ base: draw_copy.base,
|
301
|
+
src_area: draw_copy.data.src_area,
|
302
|
+
image_data: source_img,
|
303
|
+
tag: "lz_rgb." + draw_copy.data.src_bitmap.lz_rgb.type,
|
304
|
+
has_alpha: draw_copy.data.src_bitmap.lz_rgb.type == LZ_IMAGE_TYPE_RGBA ? true : false ,
|
305
|
+
descriptor : draw_copy.data.src_bitmap.descriptor
|
306
|
+
});
|
307
|
+
}
|
308
|
+
else
|
309
|
+
{
|
310
|
+
this.log_warn("FIXME: DrawCopy unhandled image type: " + draw_copy.data.src_bitmap.descriptor.type);
|
311
|
+
this.log_draw("DrawCopy", draw_copy);
|
312
|
+
return false;
|
313
|
+
}
|
314
|
+
}
|
315
|
+
|
316
|
+
this.log_warn("FIXME: DrawCopy no src_bitmap.");
|
317
|
+
return false;
|
318
|
+
}
|
319
|
+
|
320
|
+
if (msg.type == SPICE_MSG_DISPLAY_DRAW_FILL)
|
321
|
+
{
|
322
|
+
var draw_fill = new SpiceMsgDisplayDrawFill(msg.data);
|
323
|
+
|
324
|
+
DEBUG > 1 && this.log_draw("DrawFill", draw_fill);
|
325
|
+
|
326
|
+
if (draw_fill.data.rop_descriptor != SPICE_ROPD_OP_PUT)
|
327
|
+
this.log_warn("FIXME: DrawFill we don't handle ropd type: " + draw_fill.data.rop_descriptor);
|
328
|
+
if (draw_fill.data.mask.flags)
|
329
|
+
this.log_warn("FIXME: DrawFill we don't handle mask flag: " + draw_fill.data.mask.flags);
|
330
|
+
if (draw_fill.data.mask.bitmap)
|
331
|
+
this.log_warn("FIXME: DrawFill we don't handle mask");
|
332
|
+
|
333
|
+
if (draw_fill.data.brush.type == SPICE_BRUSH_TYPE_SOLID)
|
334
|
+
{
|
335
|
+
// FIXME - do brushes ever have alpha?
|
336
|
+
var color = draw_fill.data.brush.color & 0xffffff;
|
337
|
+
var color_str = "rgb(" + (color >> 16) + ", " + ((color >> 8) & 0xff) + ", " + (color & 0xff) + ")";
|
338
|
+
this.surfaces[draw_fill.base.surface_id].canvas.context.fillStyle = color_str;
|
339
|
+
|
340
|
+
this.surfaces[draw_fill.base.surface_id].canvas.context.fillRect(
|
341
|
+
draw_fill.base.box.left, draw_fill.base.box.top,
|
342
|
+
draw_fill.base.box.right - draw_fill.base.box.left,
|
343
|
+
draw_fill.base.box.bottom - draw_fill.base.box.top);
|
344
|
+
|
345
|
+
if (DUMP_DRAWS && this.parent.dump_id)
|
346
|
+
{
|
347
|
+
var debug_canvas = document.createElement("canvas");
|
348
|
+
debug_canvas.setAttribute('width', this.surfaces[draw_fill.base.surface_id].canvas.width);
|
349
|
+
debug_canvas.setAttribute('height', this.surfaces[draw_fill.base.surface_id].canvas.height);
|
350
|
+
debug_canvas.setAttribute('id', "fillbrush." + draw_fill.base.surface_id + "." + this.surfaces[draw_fill.base.surface_id].draw_count);
|
351
|
+
debug_canvas.getContext("2d").fillStyle = color_str;
|
352
|
+
debug_canvas.getContext("2d").fillRect(
|
353
|
+
draw_fill.base.box.left, draw_fill.base.box.top,
|
354
|
+
draw_fill.base.box.right - draw_fill.base.box.left,
|
355
|
+
draw_fill.base.box.bottom - draw_fill.base.box.top);
|
356
|
+
document.getElementById(this.parent.dump_id).appendChild(debug_canvas);
|
357
|
+
}
|
358
|
+
|
359
|
+
this.surfaces[draw_fill.base.surface_id].draw_count++;
|
360
|
+
|
361
|
+
}
|
362
|
+
else
|
363
|
+
{
|
364
|
+
this.log_warn("FIXME: DrawFill can't handle brush type: " + draw_fill.data.brush.type);
|
365
|
+
}
|
366
|
+
return true;
|
367
|
+
}
|
368
|
+
|
369
|
+
if (msg.type == SPICE_MSG_DISPLAY_COPY_BITS)
|
370
|
+
{
|
371
|
+
var copy_bits = new SpiceMsgDisplayCopyBits(msg.data);
|
372
|
+
|
373
|
+
DEBUG > 1 && this.log_draw("CopyBits", copy_bits);
|
374
|
+
|
375
|
+
var source_canvas = this.surfaces[copy_bits.base.surface_id].canvas;
|
376
|
+
var source_context = source_canvas.context;
|
377
|
+
|
378
|
+
var width = source_canvas.width - copy_bits.src_pos.x;
|
379
|
+
var height = source_canvas.height - copy_bits.src_pos.y;
|
380
|
+
if (width > (copy_bits.base.box.right - copy_bits.base.box.left))
|
381
|
+
width = copy_bits.base.box.right - copy_bits.base.box.left;
|
382
|
+
if (height > (copy_bits.base.box.bottom - copy_bits.base.box.top))
|
383
|
+
height = copy_bits.base.box.bottom - copy_bits.base.box.top;
|
384
|
+
|
385
|
+
var source_img = source_context.getImageData(
|
386
|
+
copy_bits.src_pos.x, copy_bits.src_pos.y, width, height);
|
387
|
+
//source_context.putImageData(source_img, copy_bits.base.box.left, copy_bits.base.box.top);
|
388
|
+
putImageDataWithAlpha(source_context, source_img, copy_bits.base.box.left, copy_bits.base.box.top);
|
389
|
+
|
390
|
+
if (DUMP_DRAWS && this.parent.dump_id)
|
391
|
+
{
|
392
|
+
var debug_canvas = document.createElement("canvas");
|
393
|
+
debug_canvas.setAttribute('width', width);
|
394
|
+
debug_canvas.setAttribute('height', height);
|
395
|
+
debug_canvas.setAttribute('id', "copybits" + copy_bits.base.surface_id + "." + this.surfaces[copy_bits.base.surface_id].draw_count);
|
396
|
+
debug_canvas.getContext("2d").putImageData(source_img, 0, 0);
|
397
|
+
document.getElementById(this.parent.dump_id).appendChild(debug_canvas);
|
398
|
+
}
|
399
|
+
|
400
|
+
|
401
|
+
this.surfaces[copy_bits.base.surface_id].draw_count++;
|
402
|
+
return true;
|
403
|
+
}
|
404
|
+
|
405
|
+
if (msg.type == SPICE_MSG_DISPLAY_INVAL_ALL_PALETTES)
|
406
|
+
{
|
407
|
+
this.known_unimplemented(msg.type, "Inval All Palettes");
|
408
|
+
return true;
|
409
|
+
}
|
410
|
+
|
411
|
+
if (msg.type == SPICE_MSG_DISPLAY_SURFACE_CREATE)
|
412
|
+
{
|
413
|
+
if (! ("surfaces" in this))
|
414
|
+
this.surfaces = [];
|
415
|
+
|
416
|
+
var m = new SpiceMsgSurfaceCreate(msg.data);
|
417
|
+
DEBUG > 1 && console.log(this.type + ": MsgSurfaceCreate id " + m.surface.surface_id
|
418
|
+
+ "; " + m.surface.width + "x" + m.surface.height
|
419
|
+
+ "; format " + m.surface.format
|
420
|
+
+ "; flags " + m.surface.flags);
|
421
|
+
if (m.surface.format != SPICE_SURFACE_FMT_32_xRGB &&
|
422
|
+
m.surface.format != SPICE_SURFACE_FMT_32_ARGB)
|
423
|
+
{
|
424
|
+
this.log_warn("FIXME: cannot handle surface format " + m.surface.format + " yet.");
|
425
|
+
return false;
|
426
|
+
}
|
427
|
+
|
428
|
+
var canvas = document.createElement("canvas");
|
429
|
+
canvas.setAttribute('width', m.surface.width);
|
430
|
+
canvas.setAttribute('height', m.surface.height);
|
431
|
+
canvas.setAttribute('id', "spice_surface_" + m.surface.surface_id);
|
432
|
+
canvas.setAttribute('tabindex', m.surface.surface_id);
|
433
|
+
canvas.context = canvas.getContext("2d");
|
434
|
+
|
435
|
+
if (DUMP_CANVASES && this.parent.dump_id)
|
436
|
+
document.getElementById(this.parent.dump_id).appendChild(canvas);
|
437
|
+
|
438
|
+
m.surface.canvas = canvas;
|
439
|
+
m.surface.draw_count = 0;
|
440
|
+
this.surfaces[m.surface.surface_id] = m.surface;
|
441
|
+
|
442
|
+
if (m.surface.flags & SPICE_SURFACE_FLAGS_PRIMARY)
|
443
|
+
{
|
444
|
+
this.primary_surface = m.surface.surface_id;
|
445
|
+
|
446
|
+
/* This .save() is done entirely to enable SPICE_MSG_DISPLAY_RESET */
|
447
|
+
canvas.context.save();
|
448
|
+
document.getElementById(this.parent.screen_id).appendChild(canvas);
|
449
|
+
document.getElementById(this.parent.screen_id).setAttribute('width', m.surface.width);
|
450
|
+
document.getElementById(this.parent.screen_id).setAttribute('height', m.surface.height);
|
451
|
+
this.hook_events();
|
452
|
+
}
|
453
|
+
return true;
|
454
|
+
}
|
455
|
+
|
456
|
+
if (msg.type == SPICE_MSG_DISPLAY_SURFACE_DESTROY)
|
457
|
+
{
|
458
|
+
var m = new SpiceMsgSurfaceDestroy(msg.data);
|
459
|
+
DEBUG > 1 && console.log(this.type + ": MsgSurfaceDestroy id " + m.surface_id);
|
460
|
+
this.delete_surface(m.surface_id);
|
461
|
+
return true;
|
462
|
+
}
|
463
|
+
|
464
|
+
if (msg.type == SPICE_MSG_DISPLAY_STREAM_CREATE)
|
465
|
+
{
|
466
|
+
var m = new SpiceMsgDisplayStreamCreate(msg.data);
|
467
|
+
DEBUG > 1 && console.log(this.type + ": MsgStreamCreate id" + m.id);
|
468
|
+
if (!this.streams)
|
469
|
+
this.streams = new Array();
|
470
|
+
if (this.streams[m.id])
|
471
|
+
console.log("Stream already exists");
|
472
|
+
else
|
473
|
+
this.streams[m.id] = m;
|
474
|
+
if (m.codec_type != SPICE_VIDEO_CODEC_TYPE_MJPEG)
|
475
|
+
console.log("Unhandled stream codec: "+m.codec_type);
|
476
|
+
return true;
|
477
|
+
}
|
478
|
+
|
479
|
+
if (msg.type == SPICE_MSG_DISPLAY_STREAM_DATA)
|
480
|
+
{
|
481
|
+
var m = new SpiceMsgDisplayStreamData(msg.data);
|
482
|
+
if (!this.streams[m.base.id])
|
483
|
+
{
|
484
|
+
console.log("no stream for data");
|
485
|
+
return false;
|
486
|
+
}
|
487
|
+
if (this.streams[m.base.id].codec_type === SPICE_VIDEO_CODEC_TYPE_MJPEG)
|
488
|
+
{
|
489
|
+
var tmpstr = "data:image/jpeg,";
|
490
|
+
var img = new Image;
|
491
|
+
var i;
|
492
|
+
for (i = 0; i < m.data.length; i++)
|
493
|
+
{
|
494
|
+
tmpstr += '%';
|
495
|
+
if (m.data[i] < 16)
|
496
|
+
tmpstr += '0';
|
497
|
+
tmpstr += m.data[i].toString(16);
|
498
|
+
}
|
499
|
+
var strm_base = new SpiceMsgDisplayBase();
|
500
|
+
strm_base.surface_id = this.streams[m.base.id].surface_id;
|
501
|
+
strm_base.box = this.streams[m.base.id].dest;
|
502
|
+
strm_base.clip = this.streams[m.base.id].clip;
|
503
|
+
img.o =
|
504
|
+
{ base: strm_base,
|
505
|
+
tag: "mjpeg." + m.base.id,
|
506
|
+
descriptor: null,
|
507
|
+
sc : this,
|
508
|
+
};
|
509
|
+
img.onload = handle_draw_jpeg_onload;
|
510
|
+
img.src = tmpstr;
|
511
|
+
}
|
512
|
+
return true;
|
513
|
+
}
|
514
|
+
|
515
|
+
if (msg.type == SPICE_MSG_DISPLAY_STREAM_CLIP)
|
516
|
+
{
|
517
|
+
var m = new SpiceMsgDisplayStreamClip(msg.data);
|
518
|
+
DEBUG > 1 && console.log(this.type + ": MsgStreamClip id" + m.id);
|
519
|
+
this.streams[m.id].clip = m.clip;
|
520
|
+
return true;
|
521
|
+
}
|
522
|
+
|
523
|
+
if (msg.type == SPICE_MSG_DISPLAY_STREAM_DESTROY)
|
524
|
+
{
|
525
|
+
var m = new SpiceMsgDisplayStreamDestroy(msg.data);
|
526
|
+
DEBUG > 1 && console.log(this.type + ": MsgStreamDestroy id" + m.id);
|
527
|
+
this.streams[m.id] = undefined;
|
528
|
+
return true;
|
529
|
+
}
|
530
|
+
|
531
|
+
return false;
|
532
|
+
}
|
533
|
+
|
534
|
+
SpiceDisplayConn.prototype.delete_surface = function(surface_id)
|
535
|
+
{
|
536
|
+
var canvas = document.getElementById("spice_surface_" + surface_id);
|
537
|
+
if (DUMP_CANVASES && this.parent.dump_id)
|
538
|
+
document.getElementById(this.parent.dump_id).removeChild(canvas);
|
539
|
+
if (this.primary_surface == surface_id)
|
540
|
+
{
|
541
|
+
this.unhook_events();
|
542
|
+
this.primary_surface = undefined;
|
543
|
+
document.getElementById(this.parent.screen_id).removeChild(canvas);
|
544
|
+
}
|
545
|
+
|
546
|
+
delete this.surfaces[surface_id];
|
547
|
+
}
|
548
|
+
|
549
|
+
|
550
|
+
SpiceDisplayConn.prototype.draw_copy_helper = function(o)
|
551
|
+
{
|
552
|
+
|
553
|
+
var canvas = this.surfaces[o.base.surface_id].canvas;
|
554
|
+
if (o.has_alpha)
|
555
|
+
{
|
556
|
+
/* FIXME - This is based on trial + error, not a serious thoughtful
|
557
|
+
analysis of what Spice requires. See display.js for more. */
|
558
|
+
if (this.surfaces[o.base.surface_id].format == SPICE_SURFACE_FMT_32_xRGB)
|
559
|
+
{
|
560
|
+
stripAlpha(o.image_data);
|
561
|
+
canvas.context.putImageData(o.image_data, o.base.box.left, o.base.box.top);
|
562
|
+
}
|
563
|
+
else
|
564
|
+
putImageDataWithAlpha(canvas.context, o.image_data,
|
565
|
+
o.base.box.left, o.base.box.top);
|
566
|
+
}
|
567
|
+
else
|
568
|
+
canvas.context.putImageData(o.image_data, o.base.box.left, o.base.box.top);
|
569
|
+
|
570
|
+
if (o.src_area.left > 0 || o.src_area.top > 0)
|
571
|
+
{
|
572
|
+
this.log_warn("FIXME: DrawCopy not shifting draw copies just yet...");
|
573
|
+
}
|
574
|
+
|
575
|
+
if (o.descriptor && (o.descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME))
|
576
|
+
{
|
577
|
+
if (! ("cache" in this))
|
578
|
+
this.cache = [];
|
579
|
+
this.cache[o.descriptor.id] = o.image_data;
|
580
|
+
}
|
581
|
+
|
582
|
+
if (DUMP_DRAWS && this.parent.dump_id)
|
583
|
+
{
|
584
|
+
var debug_canvas = document.createElement("canvas");
|
585
|
+
debug_canvas.setAttribute('width', o.image_data.width);
|
586
|
+
debug_canvas.setAttribute('height', o.image_data.height);
|
587
|
+
debug_canvas.setAttribute('id', o.tag + "." +
|
588
|
+
this.surfaces[o.base.surface_id].draw_count + "." +
|
589
|
+
o.base.surface_id + "@" + o.base.box.left + "x" + o.base.box.top);
|
590
|
+
debug_canvas.getContext("2d").putImageData(o.image_data, 0, 0);
|
591
|
+
document.getElementById(this.parent.dump_id).appendChild(debug_canvas);
|
592
|
+
}
|
593
|
+
|
594
|
+
this.surfaces[o.base.surface_id].draw_count++;
|
595
|
+
|
596
|
+
return true;
|
597
|
+
}
|
598
|
+
|
599
|
+
|
600
|
+
SpiceDisplayConn.prototype.log_draw = function(prefix, draw)
|
601
|
+
{
|
602
|
+
var str = prefix + "." + draw.base.surface_id + "." + this.surfaces[draw.base.surface_id].draw_count + ": ";
|
603
|
+
str += "base.box " + draw.base.box.left + ", " + draw.base.box.top + " to " +
|
604
|
+
draw.base.box.right + ", " + draw.base.box.bottom;
|
605
|
+
str += "; clip.type " + draw.base.clip.type;
|
606
|
+
|
607
|
+
if (draw.data)
|
608
|
+
{
|
609
|
+
if (draw.data.src_area)
|
610
|
+
str += "; src_area " + draw.data.src_area.left + ", " + draw.data.src_area.top + " to "
|
611
|
+
+ draw.data.src_area.right + ", " + draw.data.src_area.bottom;
|
612
|
+
|
613
|
+
if (draw.data.src_bitmap && draw.data.src_bitmap != null)
|
614
|
+
{
|
615
|
+
str += "; src_bitmap id: " + draw.data.src_bitmap.descriptor.id;
|
616
|
+
str += "; src_bitmap width " + draw.data.src_bitmap.descriptor.width + ", height " + draw.data.src_bitmap.descriptor.height;
|
617
|
+
str += "; src_bitmap type " + draw.data.src_bitmap.descriptor.type + ", flags " + draw.data.src_bitmap.descriptor.flags;
|
618
|
+
if (draw.data.src_bitmap.surface_id !== undefined)
|
619
|
+
str += "; src_bitmap surface_id " + draw.data.src_bitmap.surface_id;
|
620
|
+
if (draw.data.src_bitmap.quic)
|
621
|
+
str += "; QUIC type " + draw.data.src_bitmap.quic.type +
|
622
|
+
"; width " + draw.data.src_bitmap.quic.width +
|
623
|
+
"; height " + draw.data.src_bitmap.quic.height ;
|
624
|
+
if (draw.data.src_bitmap.lz_rgb)
|
625
|
+
str += "; LZ_RGB length " + draw.data.src_bitmap.lz_rgb.length +
|
626
|
+
"; magic " + draw.data.src_bitmap.lz_rgb.magic +
|
627
|
+
"; version 0x" + draw.data.src_bitmap.lz_rgb.version.toString(16) +
|
628
|
+
"; type " + draw.data.src_bitmap.lz_rgb.type +
|
629
|
+
"; width " + draw.data.src_bitmap.lz_rgb.width +
|
630
|
+
"; height " + draw.data.src_bitmap.lz_rgb.height +
|
631
|
+
"; stride " + draw.data.src_bitmap.lz_rgb.stride +
|
632
|
+
"; top down " + draw.data.src_bitmap.lz_rgb.top_down;
|
633
|
+
}
|
634
|
+
else
|
635
|
+
str += "; src_bitmap is null";
|
636
|
+
|
637
|
+
if (draw.data.brush)
|
638
|
+
{
|
639
|
+
if (draw.data.brush.type == SPICE_BRUSH_TYPE_SOLID)
|
640
|
+
str += "; brush.color 0x" + draw.data.brush.color.toString(16);
|
641
|
+
if (draw.data.brush.type == SPICE_BRUSH_TYPE_PATTERN)
|
642
|
+
{
|
643
|
+
str += "; brush.pat ";
|
644
|
+
if (draw.data.brush.pattern.pat != null)
|
645
|
+
str += "[SpiceImage]";
|
646
|
+
else
|
647
|
+
str += "[null]";
|
648
|
+
str += " at " + draw.data.brush.pattern.pos.x + ", " + draw.data.brush.pattern.pos.y;
|
649
|
+
}
|
650
|
+
}
|
651
|
+
|
652
|
+
str += "; rop_descriptor " + draw.data.rop_descriptor;
|
653
|
+
if (draw.data.scale_mode !== undefined)
|
654
|
+
str += "; scale_mode " + draw.data.scale_mode;
|
655
|
+
str += "; mask.flags " + draw.data.mask.flags;
|
656
|
+
str += "; mask.pos " + draw.data.mask.pos.x + ", " + draw.data.mask.pos.y;
|
657
|
+
if (draw.data.mask.bitmap != null)
|
658
|
+
{
|
659
|
+
str += "; mask.bitmap width " + draw.data.mask.bitmap.descriptor.width + ", height " + draw.data.mask.bitmap.descriptor.height;
|
660
|
+
str += "; mask.bitmap type " + draw.data.mask.bitmap.descriptor.type + ", flags " + draw.data.mask.bitmap.descriptor.flags;
|
661
|
+
}
|
662
|
+
else
|
663
|
+
str += "; mask.bitmap is null";
|
664
|
+
}
|
665
|
+
|
666
|
+
console.log(str);
|
667
|
+
}
|
668
|
+
|
669
|
+
SpiceDisplayConn.prototype.hook_events = function()
|
670
|
+
{
|
671
|
+
if (this.primary_surface !== undefined)
|
672
|
+
{
|
673
|
+
var canvas = this.surfaces[this.primary_surface].canvas;
|
674
|
+
canvas.sc = this.parent;
|
675
|
+
canvas.addEventListener('mousemove', handle_mousemove);
|
676
|
+
canvas.addEventListener('mousedown', handle_mousedown);
|
677
|
+
canvas.addEventListener('contextmenu', handle_contextmenu);
|
678
|
+
canvas.addEventListener('mouseup', handle_mouseup);
|
679
|
+
canvas.addEventListener('keydown', handle_keydown);
|
680
|
+
canvas.addEventListener('keyup', handle_keyup);
|
681
|
+
canvas.addEventListener('mouseout', handle_mouseout);
|
682
|
+
canvas.addEventListener('mouseover', handle_mouseover);
|
683
|
+
canvas.addEventListener('mousewheel', handle_mousewheel);
|
684
|
+
canvas.focus();
|
685
|
+
}
|
686
|
+
}
|
687
|
+
|
688
|
+
SpiceDisplayConn.prototype.unhook_events = function()
|
689
|
+
{
|
690
|
+
if (this.primary_surface !== undefined)
|
691
|
+
{
|
692
|
+
var canvas = this.surfaces[this.primary_surface].canvas;
|
693
|
+
canvas.removeEventListener('mousemove', handle_mousemove);
|
694
|
+
canvas.removeEventListener('mousedown', handle_mousedown);
|
695
|
+
canvas.removeEventListener('contextmenu', handle_contextmenu);
|
696
|
+
canvas.removeEventListener('mouseup', handle_mouseup);
|
697
|
+
canvas.removeEventListener('keydown', handle_keydown);
|
698
|
+
canvas.removeEventListener('keyup', handle_keyup);
|
699
|
+
canvas.removeEventListener('mouseout', handle_mouseout);
|
700
|
+
canvas.removeEventListener('mouseover', handle_mouseover);
|
701
|
+
canvas.removeEventListener('mousewheel', handle_mousewheel);
|
702
|
+
}
|
703
|
+
}
|
704
|
+
|
705
|
+
|
706
|
+
SpiceDisplayConn.prototype.destroy_surfaces = function()
|
707
|
+
{
|
708
|
+
for (var s in this.surfaces)
|
709
|
+
{
|
710
|
+
this.delete_surface(this.surfaces[s].surface_id);
|
711
|
+
}
|
712
|
+
|
713
|
+
this.surfaces = undefined;
|
714
|
+
}
|
715
|
+
|
716
|
+
|
717
|
+
function handle_mouseover(e)
|
718
|
+
{
|
719
|
+
this.focus();
|
720
|
+
}
|
721
|
+
|
722
|
+
function handle_mouseout(e)
|
723
|
+
{
|
724
|
+
this.blur();
|
725
|
+
}
|
726
|
+
|
727
|
+
function handle_draw_jpeg_onload()
|
728
|
+
{
|
729
|
+
var temp_canvas = null;
|
730
|
+
var context;
|
731
|
+
|
732
|
+
/*------------------------------------------------------------
|
733
|
+
** FIXME:
|
734
|
+
** The helper should be extended to be able to handle actual HtmlImageElements
|
735
|
+
** ...and the cache should be modified to do so as well
|
736
|
+
**----------------------------------------------------------*/
|
737
|
+
if (this.o.sc.surfaces[this.o.base.surface_id] === undefined)
|
738
|
+
{
|
739
|
+
// This can happen; if the jpeg image loads after our surface
|
740
|
+
// has been destroyed (e.g. open a menu, close it quickly),
|
741
|
+
// we'll find we have no surface.
|
742
|
+
DEBUG > 2 && this.o.sc.log_info("Discarding jpeg; presumed lost surface " + this.o.base.surface_id);
|
743
|
+
temp_canvas = document.createElement("canvas");
|
744
|
+
temp_canvas.setAttribute('width', this.o.base.box.right);
|
745
|
+
temp_canvas.setAttribute('height', this.o.base.box.bottom);
|
746
|
+
context = temp_canvas.getContext("2d");
|
747
|
+
}
|
748
|
+
else
|
749
|
+
context = this.o.sc.surfaces[this.o.base.surface_id].canvas.context;
|
750
|
+
|
751
|
+
if (this.alpha_img)
|
752
|
+
{
|
753
|
+
var c = document.createElement("canvas");
|
754
|
+
var t = c.getContext("2d");
|
755
|
+
c.setAttribute('width', this.alpha_img.width);
|
756
|
+
c.setAttribute('height', this.alpha_img.height);
|
757
|
+
t.putImageData(this.alpha_img, 0, 0);
|
758
|
+
t.globalCompositeOperation = 'source-in';
|
759
|
+
t.drawImage(this, 0, 0);
|
760
|
+
|
761
|
+
context.drawImage(c, this.o.base.box.left, this.o.base.box.top);
|
762
|
+
|
763
|
+
if (this.o.descriptor &&
|
764
|
+
(this.o.descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME))
|
765
|
+
{
|
766
|
+
if (! ("cache" in this.o.sc))
|
767
|
+
this.o.sc.cache = [];
|
768
|
+
|
769
|
+
this.o.sc.cache[this.o.descriptor.id] =
|
770
|
+
t.getImageData(0, 0,
|
771
|
+
this.alpha_img.width,
|
772
|
+
this.alpha_img.height);
|
773
|
+
}
|
774
|
+
}
|
775
|
+
else
|
776
|
+
{
|
777
|
+
context.drawImage(this, this.o.base.box.left, this.o.base.box.top);
|
778
|
+
|
779
|
+
if (this.o.descriptor &&
|
780
|
+
(this.o.descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME))
|
781
|
+
{
|
782
|
+
if (! ("cache" in this.o.sc))
|
783
|
+
this.o.sc.cache = [];
|
784
|
+
|
785
|
+
this.o.sc.cache[this.o.descriptor.id] =
|
786
|
+
context.getImageData(this.o.base.box.left, this.o.base.box.top,
|
787
|
+
this.o.base.box.right - this.o.base.box.left,
|
788
|
+
this.o.base.box.bottom - this.o.base.box.top);
|
789
|
+
}
|
790
|
+
}
|
791
|
+
|
792
|
+
if (temp_canvas == null)
|
793
|
+
{
|
794
|
+
if (DUMP_DRAWS && this.o.sc.parent.dump_id)
|
795
|
+
{
|
796
|
+
var debug_canvas = document.createElement("canvas");
|
797
|
+
debug_canvas.setAttribute('id', this.o.tag + "." +
|
798
|
+
this.o.sc.surfaces[this.o.base.surface_id].draw_count + "." +
|
799
|
+
this.o.base.surface_id + "@" + this.o.base.box.left + "x" + this.o.base.box.top);
|
800
|
+
debug_canvas.getContext("2d").drawImage(this, 0, 0);
|
801
|
+
document.getElementById(this.o.sc.parent.dump_id).appendChild(debug_canvas);
|
802
|
+
}
|
803
|
+
|
804
|
+
this.o.sc.surfaces[this.o.base.surface_id].draw_count++;
|
805
|
+
}
|
806
|
+
}
|