susi-qemu 0.0.3 → 0.0.6

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.
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 +36 -13
  65. data/lib/vnc.rb +34 -30
  66. metadata +85 -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
+ }