susi-qemu 0.0.2 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/bin/susi +9 -4
  3. data/lib/disk.rb +7 -5
  4. data/lib/novnc/core/base64.js +104 -0
  5. data/lib/novnc/core/crypto/aes.js +178 -0
  6. data/lib/novnc/core/crypto/bigint.js +34 -0
  7. data/lib/novnc/core/crypto/crypto.js +90 -0
  8. data/lib/novnc/core/crypto/des.js +330 -0
  9. data/lib/novnc/core/crypto/dh.js +55 -0
  10. data/lib/novnc/core/crypto/md5.js +82 -0
  11. data/lib/novnc/core/crypto/rsa.js +132 -0
  12. data/lib/novnc/core/decoders/copyrect.js +27 -0
  13. data/lib/novnc/core/decoders/h264.js +321 -0
  14. data/lib/novnc/core/decoders/hextile.js +181 -0
  15. data/lib/novnc/core/decoders/jpeg.js +146 -0
  16. data/lib/novnc/core/decoders/raw.js +59 -0
  17. data/lib/novnc/core/decoders/rre.js +44 -0
  18. data/lib/novnc/core/decoders/tight.js +393 -0
  19. data/lib/novnc/core/decoders/tightpng.js +27 -0
  20. data/lib/novnc/core/decoders/zlib.js +51 -0
  21. data/lib/novnc/core/decoders/zrle.js +185 -0
  22. data/lib/novnc/core/deflator.js +84 -0
  23. data/lib/novnc/core/display.js +575 -0
  24. data/lib/novnc/core/encodings.js +53 -0
  25. data/lib/novnc/core/inflator.js +65 -0
  26. data/lib/novnc/core/input/domkeytable.js +311 -0
  27. data/lib/novnc/core/input/fixedkeys.js +129 -0
  28. data/lib/novnc/core/input/gesturehandler.js +567 -0
  29. data/lib/novnc/core/input/keyboard.js +294 -0
  30. data/lib/novnc/core/input/keysym.js +616 -0
  31. data/lib/novnc/core/input/keysymdef.js +688 -0
  32. data/lib/novnc/core/input/util.js +191 -0
  33. data/lib/novnc/core/input/vkeys.js +116 -0
  34. data/lib/novnc/core/input/xtscancodes.js +173 -0
  35. data/lib/novnc/core/ra2.js +312 -0
  36. data/lib/novnc/core/rfb.js +3257 -0
  37. data/lib/novnc/core/util/browser.js +172 -0
  38. data/lib/novnc/core/util/cursor.js +249 -0
  39. data/lib/novnc/core/util/element.js +32 -0
  40. data/lib/novnc/core/util/events.js +138 -0
  41. data/lib/novnc/core/util/eventtarget.js +35 -0
  42. data/lib/novnc/core/util/int.js +15 -0
  43. data/lib/novnc/core/util/logging.js +56 -0
  44. data/lib/novnc/core/util/strings.js +28 -0
  45. data/lib/novnc/core/websock.js +365 -0
  46. data/lib/novnc/screen.html +21 -0
  47. data/lib/novnc/vendor/pako/lib/utils/common.js +45 -0
  48. data/lib/novnc/vendor/pako/lib/zlib/adler32.js +27 -0
  49. data/lib/novnc/vendor/pako/lib/zlib/constants.js +47 -0
  50. data/lib/novnc/vendor/pako/lib/zlib/crc32.js +36 -0
  51. data/lib/novnc/vendor/pako/lib/zlib/deflate.js +1846 -0
  52. data/lib/novnc/vendor/pako/lib/zlib/gzheader.js +35 -0
  53. data/lib/novnc/vendor/pako/lib/zlib/inffast.js +324 -0
  54. data/lib/novnc/vendor/pako/lib/zlib/inflate.js +1527 -0
  55. data/lib/novnc/vendor/pako/lib/zlib/inftrees.js +322 -0
  56. data/lib/novnc/vendor/pako/lib/zlib/messages.js +11 -0
  57. data/lib/novnc/vendor/pako/lib/zlib/trees.js +1195 -0
  58. data/lib/novnc/vendor/pako/lib/zlib/zstream.js +24 -0
  59. data/lib/output.rb +11 -0
  60. data/lib/qmp.rb +6 -0
  61. data/lib/ssh.rb +3 -1
  62. data/lib/susi.rb +7 -6
  63. data/lib/version.rb +1 -1
  64. data/lib/vm.rb +44 -26
  65. data/lib/vnc.rb +34 -31
  66. metadata +57 -1
@@ -0,0 +1,84 @@
1
+ /*
2
+ * noVNC: HTML5 VNC client
3
+ * Copyright (C) 2020 The noVNC Authors
4
+ * Licensed under MPL 2.0 (see LICENSE.txt)
5
+ *
6
+ * See README.md for usage and integration instructions.
7
+ */
8
+
9
+ import { deflateInit, deflate } from "../vendor/pako/lib/zlib/deflate.js";
10
+ import { Z_FULL_FLUSH, Z_DEFAULT_COMPRESSION } from "../vendor/pako/lib/zlib/deflate.js";
11
+ import ZStream from "../vendor/pako/lib/zlib/zstream.js";
12
+
13
+ export default class Deflator {
14
+ constructor() {
15
+ this.strm = new ZStream();
16
+ this.chunkSize = 1024 * 10 * 10;
17
+ this.outputBuffer = new Uint8Array(this.chunkSize);
18
+
19
+ deflateInit(this.strm, Z_DEFAULT_COMPRESSION);
20
+ }
21
+
22
+ deflate(inData) {
23
+ /* eslint-disable camelcase */
24
+ this.strm.input = inData;
25
+ this.strm.avail_in = this.strm.input.length;
26
+ this.strm.next_in = 0;
27
+ this.strm.output = this.outputBuffer;
28
+ this.strm.avail_out = this.chunkSize;
29
+ this.strm.next_out = 0;
30
+ /* eslint-enable camelcase */
31
+
32
+ let lastRet = deflate(this.strm, Z_FULL_FLUSH);
33
+ let outData = new Uint8Array(this.strm.output.buffer, 0, this.strm.next_out);
34
+
35
+ if (lastRet < 0) {
36
+ throw new Error("zlib deflate failed");
37
+ }
38
+
39
+ if (this.strm.avail_in > 0) {
40
+ // Read chunks until done
41
+
42
+ let chunks = [outData];
43
+ let totalLen = outData.length;
44
+ do {
45
+ /* eslint-disable camelcase */
46
+ this.strm.output = new Uint8Array(this.chunkSize);
47
+ this.strm.next_out = 0;
48
+ this.strm.avail_out = this.chunkSize;
49
+ /* eslint-enable camelcase */
50
+
51
+ lastRet = deflate(this.strm, Z_FULL_FLUSH);
52
+
53
+ if (lastRet < 0) {
54
+ throw new Error("zlib deflate failed");
55
+ }
56
+
57
+ let chunk = new Uint8Array(this.strm.output.buffer, 0, this.strm.next_out);
58
+ totalLen += chunk.length;
59
+ chunks.push(chunk);
60
+ } while (this.strm.avail_in > 0);
61
+
62
+ // Combine chunks into a single data
63
+
64
+ let newData = new Uint8Array(totalLen);
65
+ let offset = 0;
66
+
67
+ for (let i = 0; i < chunks.length; i++) {
68
+ newData.set(chunks[i], offset);
69
+ offset += chunks[i].length;
70
+ }
71
+
72
+ outData = newData;
73
+ }
74
+
75
+ /* eslint-disable camelcase */
76
+ this.strm.input = null;
77
+ this.strm.avail_in = 0;
78
+ this.strm.next_in = 0;
79
+ /* eslint-enable camelcase */
80
+
81
+ return outData;
82
+ }
83
+
84
+ }
@@ -0,0 +1,575 @@
1
+ /*
2
+ * noVNC: HTML5 VNC client
3
+ * Copyright (C) 2019 The noVNC Authors
4
+ * Licensed under MPL 2.0 (see LICENSE.txt)
5
+ *
6
+ * See README.md for usage and integration instructions.
7
+ */
8
+
9
+ import * as Log from './util/logging.js';
10
+ import Base64 from "./base64.js";
11
+ import { toSigned32bit } from './util/int.js';
12
+
13
+ export default class Display {
14
+ constructor(target) {
15
+ this._drawCtx = null;
16
+
17
+ this._renderQ = []; // queue drawing actions for in-oder rendering
18
+ this._flushPromise = null;
19
+
20
+ // the full frame buffer (logical canvas) size
21
+ this._fbWidth = 0;
22
+ this._fbHeight = 0;
23
+
24
+ this._prevDrawStyle = "";
25
+
26
+ Log.Debug(">> Display.constructor");
27
+
28
+ // The visible canvas
29
+ this._target = target;
30
+
31
+ if (!this._target) {
32
+ throw new Error("Target must be set");
33
+ }
34
+
35
+ if (typeof this._target === 'string') {
36
+ throw new Error('target must be a DOM element');
37
+ }
38
+
39
+ if (!this._target.getContext) {
40
+ throw new Error("no getContext method");
41
+ }
42
+
43
+ this._targetCtx = this._target.getContext('2d');
44
+
45
+ // the visible canvas viewport (i.e. what actually gets seen)
46
+ this._viewportLoc = { 'x': 0, 'y': 0, 'w': this._target.width, 'h': this._target.height };
47
+
48
+ // The hidden canvas, where we do the actual rendering
49
+ this._backbuffer = document.createElement('canvas');
50
+ this._drawCtx = this._backbuffer.getContext('2d');
51
+
52
+ this._damageBounds = { left: 0, top: 0,
53
+ right: this._backbuffer.width,
54
+ bottom: this._backbuffer.height };
55
+
56
+ Log.Debug("User Agent: " + navigator.userAgent);
57
+
58
+ Log.Debug("<< Display.constructor");
59
+
60
+ // ===== PROPERTIES =====
61
+
62
+ this._scale = 1.0;
63
+ this._clipViewport = false;
64
+ }
65
+
66
+ // ===== PROPERTIES =====
67
+
68
+ get scale() { return this._scale; }
69
+ set scale(scale) {
70
+ this._rescale(scale);
71
+ }
72
+
73
+ get clipViewport() { return this._clipViewport; }
74
+ set clipViewport(viewport) {
75
+ this._clipViewport = viewport;
76
+ // May need to readjust the viewport dimensions
77
+ const vp = this._viewportLoc;
78
+ this.viewportChangeSize(vp.w, vp.h);
79
+ this.viewportChangePos(0, 0);
80
+ }
81
+
82
+ get width() {
83
+ return this._fbWidth;
84
+ }
85
+
86
+ get height() {
87
+ return this._fbHeight;
88
+ }
89
+
90
+ // ===== PUBLIC METHODS =====
91
+
92
+ viewportChangePos(deltaX, deltaY) {
93
+ const vp = this._viewportLoc;
94
+ deltaX = Math.floor(deltaX);
95
+ deltaY = Math.floor(deltaY);
96
+
97
+ if (!this._clipViewport) {
98
+ deltaX = -vp.w; // clamped later of out of bounds
99
+ deltaY = -vp.h;
100
+ }
101
+
102
+ const vx2 = vp.x + vp.w - 1;
103
+ const vy2 = vp.y + vp.h - 1;
104
+
105
+ // Position change
106
+
107
+ if (deltaX < 0 && vp.x + deltaX < 0) {
108
+ deltaX = -vp.x;
109
+ }
110
+ if (vx2 + deltaX >= this._fbWidth) {
111
+ deltaX -= vx2 + deltaX - this._fbWidth + 1;
112
+ }
113
+
114
+ if (vp.y + deltaY < 0) {
115
+ deltaY = -vp.y;
116
+ }
117
+ if (vy2 + deltaY >= this._fbHeight) {
118
+ deltaY -= (vy2 + deltaY - this._fbHeight + 1);
119
+ }
120
+
121
+ if (deltaX === 0 && deltaY === 0) {
122
+ return;
123
+ }
124
+ Log.Debug("viewportChange deltaX: " + deltaX + ", deltaY: " + deltaY);
125
+
126
+ vp.x += deltaX;
127
+ vp.y += deltaY;
128
+
129
+ this._damage(vp.x, vp.y, vp.w, vp.h);
130
+
131
+ this.flip();
132
+ }
133
+
134
+ viewportChangeSize(width, height) {
135
+
136
+ if (!this._clipViewport ||
137
+ typeof(width) === "undefined" ||
138
+ typeof(height) === "undefined") {
139
+
140
+ Log.Debug("Setting viewport to full display region");
141
+ width = this._fbWidth;
142
+ height = this._fbHeight;
143
+ }
144
+
145
+ width = Math.floor(width);
146
+ height = Math.floor(height);
147
+
148
+ if (width > this._fbWidth) {
149
+ width = this._fbWidth;
150
+ }
151
+ if (height > this._fbHeight) {
152
+ height = this._fbHeight;
153
+ }
154
+
155
+ const vp = this._viewportLoc;
156
+ if (vp.w !== width || vp.h !== height) {
157
+ vp.w = width;
158
+ vp.h = height;
159
+
160
+ const canvas = this._target;
161
+ canvas.width = width;
162
+ canvas.height = height;
163
+
164
+ // The position might need to be updated if we've grown
165
+ this.viewportChangePos(0, 0);
166
+
167
+ this._damage(vp.x, vp.y, vp.w, vp.h);
168
+ this.flip();
169
+
170
+ // Update the visible size of the target canvas
171
+ this._rescale(this._scale);
172
+ }
173
+ }
174
+
175
+ absX(x) {
176
+ if (this._scale === 0) {
177
+ return 0;
178
+ }
179
+ return toSigned32bit(x / this._scale + this._viewportLoc.x);
180
+ }
181
+
182
+ absY(y) {
183
+ if (this._scale === 0) {
184
+ return 0;
185
+ }
186
+ return toSigned32bit(y / this._scale + this._viewportLoc.y);
187
+ }
188
+
189
+ resize(width, height) {
190
+ this._prevDrawStyle = "";
191
+
192
+ this._fbWidth = width;
193
+ this._fbHeight = height;
194
+
195
+ const canvas = this._backbuffer;
196
+ if (canvas.width !== width || canvas.height !== height) {
197
+
198
+ // We have to save the canvas data since changing the size will clear it
199
+ let saveImg = null;
200
+ if (canvas.width > 0 && canvas.height > 0) {
201
+ saveImg = this._drawCtx.getImageData(0, 0, canvas.width, canvas.height);
202
+ }
203
+
204
+ if (canvas.width !== width) {
205
+ canvas.width = width;
206
+ }
207
+ if (canvas.height !== height) {
208
+ canvas.height = height;
209
+ }
210
+
211
+ if (saveImg) {
212
+ this._drawCtx.putImageData(saveImg, 0, 0);
213
+ }
214
+ }
215
+
216
+ // Readjust the viewport as it may be incorrectly sized
217
+ // and positioned
218
+ const vp = this._viewportLoc;
219
+ this.viewportChangeSize(vp.w, vp.h);
220
+ this.viewportChangePos(0, 0);
221
+ }
222
+
223
+ getImageData() {
224
+ return this._drawCtx.getImageData(0, 0, this.width, this.height);
225
+ }
226
+
227
+ toDataURL(type, encoderOptions) {
228
+ return this._backbuffer.toDataURL(type, encoderOptions);
229
+ }
230
+
231
+ toBlob(callback, type, quality) {
232
+ return this._backbuffer.toBlob(callback, type, quality);
233
+ }
234
+
235
+ // Track what parts of the visible canvas that need updating
236
+ _damage(x, y, w, h) {
237
+ if (x < this._damageBounds.left) {
238
+ this._damageBounds.left = x;
239
+ }
240
+ if (y < this._damageBounds.top) {
241
+ this._damageBounds.top = y;
242
+ }
243
+ if ((x + w) > this._damageBounds.right) {
244
+ this._damageBounds.right = x + w;
245
+ }
246
+ if ((y + h) > this._damageBounds.bottom) {
247
+ this._damageBounds.bottom = y + h;
248
+ }
249
+ }
250
+
251
+ // Update the visible canvas with the contents of the
252
+ // rendering canvas
253
+ flip(fromQueue) {
254
+ if (this._renderQ.length !== 0 && !fromQueue) {
255
+ this._renderQPush({
256
+ 'type': 'flip'
257
+ });
258
+ } else {
259
+ let x = this._damageBounds.left;
260
+ let y = this._damageBounds.top;
261
+ let w = this._damageBounds.right - x;
262
+ let h = this._damageBounds.bottom - y;
263
+
264
+ let vx = x - this._viewportLoc.x;
265
+ let vy = y - this._viewportLoc.y;
266
+
267
+ if (vx < 0) {
268
+ w += vx;
269
+ x -= vx;
270
+ vx = 0;
271
+ }
272
+ if (vy < 0) {
273
+ h += vy;
274
+ y -= vy;
275
+ vy = 0;
276
+ }
277
+
278
+ if ((vx + w) > this._viewportLoc.w) {
279
+ w = this._viewportLoc.w - vx;
280
+ }
281
+ if ((vy + h) > this._viewportLoc.h) {
282
+ h = this._viewportLoc.h - vy;
283
+ }
284
+
285
+ if ((w > 0) && (h > 0)) {
286
+ // FIXME: We may need to disable image smoothing here
287
+ // as well (see copyImage()), but we haven't
288
+ // noticed any problem yet.
289
+ this._targetCtx.drawImage(this._backbuffer,
290
+ x, y, w, h,
291
+ vx, vy, w, h);
292
+ }
293
+
294
+ this._damageBounds.left = this._damageBounds.top = 65535;
295
+ this._damageBounds.right = this._damageBounds.bottom = 0;
296
+ }
297
+ }
298
+
299
+ pending() {
300
+ return this._renderQ.length > 0;
301
+ }
302
+
303
+ flush() {
304
+ if (this._renderQ.length === 0) {
305
+ return Promise.resolve();
306
+ } else {
307
+ if (this._flushPromise === null) {
308
+ this._flushPromise = new Promise((resolve) => {
309
+ this._flushResolve = resolve;
310
+ });
311
+ }
312
+ return this._flushPromise;
313
+ }
314
+ }
315
+
316
+ fillRect(x, y, width, height, color, fromQueue) {
317
+ if (this._renderQ.length !== 0 && !fromQueue) {
318
+ this._renderQPush({
319
+ 'type': 'fill',
320
+ 'x': x,
321
+ 'y': y,
322
+ 'width': width,
323
+ 'height': height,
324
+ 'color': color
325
+ });
326
+ } else {
327
+ this._setFillColor(color);
328
+ this._drawCtx.fillRect(x, y, width, height);
329
+ this._damage(x, y, width, height);
330
+ }
331
+ }
332
+
333
+ copyImage(oldX, oldY, newX, newY, w, h, fromQueue) {
334
+ if (this._renderQ.length !== 0 && !fromQueue) {
335
+ this._renderQPush({
336
+ 'type': 'copy',
337
+ 'oldX': oldX,
338
+ 'oldY': oldY,
339
+ 'x': newX,
340
+ 'y': newY,
341
+ 'width': w,
342
+ 'height': h,
343
+ });
344
+ } else {
345
+ // Due to this bug among others [1] we need to disable the image-smoothing to
346
+ // avoid getting a blur effect when copying data.
347
+ //
348
+ // 1. https://bugzilla.mozilla.org/show_bug.cgi?id=1194719
349
+ //
350
+ // We need to set these every time since all properties are reset
351
+ // when the the size is changed
352
+ this._drawCtx.mozImageSmoothingEnabled = false;
353
+ this._drawCtx.webkitImageSmoothingEnabled = false;
354
+ this._drawCtx.msImageSmoothingEnabled = false;
355
+ this._drawCtx.imageSmoothingEnabled = false;
356
+
357
+ this._drawCtx.drawImage(this._backbuffer,
358
+ oldX, oldY, w, h,
359
+ newX, newY, w, h);
360
+ this._damage(newX, newY, w, h);
361
+ }
362
+ }
363
+
364
+ imageRect(x, y, width, height, mime, arr) {
365
+ /* The internal logic cannot handle empty images, so bail early */
366
+ if ((width === 0) || (height === 0)) {
367
+ return;
368
+ }
369
+
370
+ const img = new Image();
371
+ img.src = "data: " + mime + ";base64," + Base64.encode(arr);
372
+
373
+ this._renderQPush({
374
+ 'type': 'img',
375
+ 'img': img,
376
+ 'x': x,
377
+ 'y': y,
378
+ 'width': width,
379
+ 'height': height
380
+ });
381
+ }
382
+
383
+ videoFrame(x, y, width, height, frame) {
384
+ this._renderQPush({
385
+ 'type': 'frame',
386
+ 'frame': frame,
387
+ 'x': x,
388
+ 'y': y,
389
+ 'width': width,
390
+ 'height': height
391
+ });
392
+ }
393
+
394
+ blitImage(x, y, width, height, arr, offset, fromQueue) {
395
+ if (this._renderQ.length !== 0 && !fromQueue) {
396
+ // NB(directxman12): it's technically more performant here to use preallocated arrays,
397
+ // but it's a lot of extra work for not a lot of payoff -- if we're using the render queue,
398
+ // this probably isn't getting called *nearly* as much
399
+ const newArr = new Uint8Array(width * height * 4);
400
+ newArr.set(new Uint8Array(arr.buffer, 0, newArr.length));
401
+ this._renderQPush({
402
+ 'type': 'blit',
403
+ 'data': newArr,
404
+ 'x': x,
405
+ 'y': y,
406
+ 'width': width,
407
+ 'height': height,
408
+ });
409
+ } else {
410
+ // NB(directxman12): arr must be an Type Array view
411
+ let data = new Uint8ClampedArray(arr.buffer,
412
+ arr.byteOffset + offset,
413
+ width * height * 4);
414
+ let img = new ImageData(data, width, height);
415
+ this._drawCtx.putImageData(img, x, y);
416
+ this._damage(x, y, width, height);
417
+ }
418
+ }
419
+
420
+ drawImage(img, ...args) {
421
+ this._drawCtx.drawImage(img, ...args);
422
+
423
+ if (args.length <= 4) {
424
+ const [x, y] = args;
425
+ this._damage(x, y, img.width, img.height);
426
+ } else {
427
+ const [,, sw, sh, dx, dy] = args;
428
+ this._damage(dx, dy, sw, sh);
429
+ }
430
+ }
431
+
432
+ autoscale(containerWidth, containerHeight) {
433
+ let scaleRatio;
434
+
435
+ if (containerWidth === 0 || containerHeight === 0) {
436
+ scaleRatio = 0;
437
+
438
+ } else {
439
+
440
+ const vp = this._viewportLoc;
441
+ const targetAspectRatio = containerWidth / containerHeight;
442
+ const fbAspectRatio = vp.w / vp.h;
443
+
444
+ if (fbAspectRatio >= targetAspectRatio) {
445
+ scaleRatio = containerWidth / vp.w;
446
+ } else {
447
+ scaleRatio = containerHeight / vp.h;
448
+ }
449
+ }
450
+
451
+ this._rescale(scaleRatio);
452
+ }
453
+
454
+ // ===== PRIVATE METHODS =====
455
+
456
+ _rescale(factor) {
457
+ this._scale = factor;
458
+ const vp = this._viewportLoc;
459
+
460
+ // NB(directxman12): If you set the width directly, or set the
461
+ // style width to a number, the canvas is cleared.
462
+ // However, if you set the style width to a string
463
+ // ('NNNpx'), the canvas is scaled without clearing.
464
+ const width = factor * vp.w + 'px';
465
+ const height = factor * vp.h + 'px';
466
+
467
+ if ((this._target.style.width !== width) ||
468
+ (this._target.style.height !== height)) {
469
+ this._target.style.width = width;
470
+ this._target.style.height = height;
471
+ }
472
+ }
473
+
474
+ _setFillColor(color) {
475
+ const newStyle = 'rgb(' + color[0] + ',' + color[1] + ',' + color[2] + ')';
476
+ if (newStyle !== this._prevDrawStyle) {
477
+ this._drawCtx.fillStyle = newStyle;
478
+ this._prevDrawStyle = newStyle;
479
+ }
480
+ }
481
+
482
+ _renderQPush(action) {
483
+ this._renderQ.push(action);
484
+ if (this._renderQ.length === 1) {
485
+ // If this can be rendered immediately it will be, otherwise
486
+ // the scanner will wait for the relevant event
487
+ this._scanRenderQ();
488
+ }
489
+ }
490
+
491
+ _resumeRenderQ() {
492
+ // "this" is the object that is ready, not the
493
+ // display object
494
+ this.removeEventListener('load', this._noVNCDisplay._resumeRenderQ);
495
+ this._noVNCDisplay._scanRenderQ();
496
+ }
497
+
498
+ _scanRenderQ() {
499
+ let ready = true;
500
+ while (ready && this._renderQ.length > 0) {
501
+ const a = this._renderQ[0];
502
+ switch (a.type) {
503
+ case 'flip':
504
+ this.flip(true);
505
+ break;
506
+ case 'copy':
507
+ this.copyImage(a.oldX, a.oldY, a.x, a.y, a.width, a.height, true);
508
+ break;
509
+ case 'fill':
510
+ this.fillRect(a.x, a.y, a.width, a.height, a.color, true);
511
+ break;
512
+ case 'blit':
513
+ this.blitImage(a.x, a.y, a.width, a.height, a.data, 0, true);
514
+ break;
515
+ case 'img':
516
+ if (a.img.complete) {
517
+ if (a.img.width !== a.width || a.img.height !== a.height) {
518
+ Log.Error("Decoded image has incorrect dimensions. Got " +
519
+ a.img.width + "x" + a.img.height + ". Expected " +
520
+ a.width + "x" + a.height + ".");
521
+ return;
522
+ }
523
+ this.drawImage(a.img, a.x, a.y);
524
+ } else {
525
+ a.img._noVNCDisplay = this;
526
+ a.img.addEventListener('load', this._resumeRenderQ);
527
+ // We need to wait for this image to 'load'
528
+ // to keep things in-order
529
+ ready = false;
530
+ }
531
+ break;
532
+ case 'frame':
533
+ if (a.frame.ready) {
534
+ // The encoded frame may be larger than the rect due to
535
+ // limitations of the encoder, so we need to crop the
536
+ // frame.
537
+ let frame = a.frame.frame;
538
+ if (frame.codedWidth < a.width || frame.codedHeight < a.height) {
539
+ Log.Warn("Decoded video frame does not cover its full rectangle area. Expecting at least " +
540
+ a.width + "x" + a.height + " but got " +
541
+ frame.codedWidth + "x" + frame.codedHeight);
542
+ }
543
+ const sx = 0;
544
+ const sy = 0;
545
+ const sw = a.width;
546
+ const sh = a.height;
547
+ const dx = a.x;
548
+ const dy = a.y;
549
+ const dw = sw;
550
+ const dh = sh;
551
+ this.drawImage(frame, sx, sy, sw, sh, dx, dy, dw, dh);
552
+ frame.close();
553
+ } else {
554
+ let display = this;
555
+ a.frame.promise.then(() => {
556
+ display._scanRenderQ();
557
+ });
558
+ ready = false;
559
+ }
560
+ break;
561
+ }
562
+
563
+ if (ready) {
564
+ this._renderQ.shift();
565
+ }
566
+ }
567
+
568
+ if (this._renderQ.length === 0 &&
569
+ this._flushPromise !== null) {
570
+ this._flushResolve();
571
+ this._flushPromise = null;
572
+ this._flushResolve = null;
573
+ }
574
+ }
575
+ }
@@ -0,0 +1,53 @@
1
+ /*
2
+ * noVNC: HTML5 VNC client
3
+ * Copyright (C) 2019 The noVNC Authors
4
+ * Licensed under MPL 2.0 (see LICENSE.txt)
5
+ *
6
+ * See README.md for usage and integration instructions.
7
+ */
8
+
9
+ export const encodings = {
10
+ encodingRaw: 0,
11
+ encodingCopyRect: 1,
12
+ encodingRRE: 2,
13
+ encodingHextile: 5,
14
+ encodingZlib: 6,
15
+ encodingTight: 7,
16
+ encodingZRLE: 16,
17
+ encodingTightPNG: -260,
18
+ encodingJPEG: 21,
19
+ encodingH264: 50,
20
+
21
+ pseudoEncodingQualityLevel9: -23,
22
+ pseudoEncodingQualityLevel0: -32,
23
+ pseudoEncodingDesktopSize: -223,
24
+ pseudoEncodingLastRect: -224,
25
+ pseudoEncodingCursor: -239,
26
+ pseudoEncodingQEMUExtendedKeyEvent: -258,
27
+ pseudoEncodingQEMULedEvent: -261,
28
+ pseudoEncodingDesktopName: -307,
29
+ pseudoEncodingExtendedDesktopSize: -308,
30
+ pseudoEncodingXvp: -309,
31
+ pseudoEncodingFence: -312,
32
+ pseudoEncodingContinuousUpdates: -313,
33
+ pseudoEncodingCompressLevel9: -247,
34
+ pseudoEncodingCompressLevel0: -256,
35
+ pseudoEncodingVMwareCursor: 0x574d5664,
36
+ pseudoEncodingExtendedClipboard: 0xc0a1e5ce
37
+ };
38
+
39
+ export function encodingName(num) {
40
+ switch (num) {
41
+ case encodings.encodingRaw: return "Raw";
42
+ case encodings.encodingCopyRect: return "CopyRect";
43
+ case encodings.encodingRRE: return "RRE";
44
+ case encodings.encodingHextile: return "Hextile";
45
+ case encodings.encodingZlib: return "Zlib";
46
+ case encodings.encodingTight: return "Tight";
47
+ case encodings.encodingZRLE: return "ZRLE";
48
+ case encodings.encodingTightPNG: return "TightPNG";
49
+ case encodings.encodingJPEG: return "JPEG";
50
+ case encodings.encodingH264: return "H.264";
51
+ default: return "[unknown encoding " + num + "]";
52
+ }
53
+ }