@novnc/novnc 1.0.0 → 1.2.0

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 (87) hide show
  1. package/AUTHORS +13 -0
  2. package/LICENSE.txt +2 -1
  3. package/README.md +69 -3
  4. package/core/base64.js +35 -41
  5. package/core/decoders/copyrect.js +22 -0
  6. package/core/decoders/hextile.js +137 -0
  7. package/core/decoders/raw.js +56 -0
  8. package/core/decoders/rre.js +44 -0
  9. package/core/decoders/tight.js +315 -0
  10. package/core/decoders/tightpng.js +27 -0
  11. package/core/deflator.js +85 -0
  12. package/core/des.js +90 -95
  13. package/core/display.js +254 -297
  14. package/core/encodings.js +7 -3
  15. package/core/inflator.js +48 -20
  16. package/core/input/domkeytable.js +21 -24
  17. package/core/input/fixedkeys.js +3 -1
  18. package/core/input/gesturehandler.js +567 -0
  19. package/core/input/keyboard.js +194 -120
  20. package/core/input/keysym.js +2 -0
  21. package/core/input/keysymdef.js +3 -3
  22. package/core/input/util.js +53 -12
  23. package/core/input/vkeys.js +2 -1
  24. package/core/rfb.js +1937 -1496
  25. package/core/util/browser.js +80 -29
  26. package/core/util/cursor.js +253 -0
  27. package/core/util/element.js +32 -0
  28. package/core/util/events.js +59 -55
  29. package/core/util/eventtarget.js +25 -30
  30. package/core/util/int.js +15 -0
  31. package/core/util/logging.js +21 -16
  32. package/core/util/polyfill.js +15 -8
  33. package/core/util/strings.js +21 -8
  34. package/core/websock.js +145 -167
  35. package/docs/API.md +31 -10
  36. package/lib/base64.js +115 -0
  37. package/lib/decoders/copyrect.js +44 -0
  38. package/lib/decoders/hextile.js +173 -0
  39. package/lib/decoders/raw.js +78 -0
  40. package/lib/decoders/rre.js +65 -0
  41. package/lib/decoders/tight.js +350 -0
  42. package/lib/decoders/tightpng.js +67 -0
  43. package/lib/deflator.js +99 -0
  44. package/lib/des.js +314 -0
  45. package/lib/display.js +733 -0
  46. package/lib/encodings.js +64 -0
  47. package/lib/inflator.js +87 -0
  48. package/lib/input/domkeytable.js +282 -0
  49. package/lib/input/fixedkeys.js +123 -0
  50. package/lib/input/gesturehandler.js +642 -0
  51. package/lib/input/keyboard.js +429 -0
  52. package/lib/input/keysym.js +1135 -0
  53. package/lib/input/keysymdef.js +1354 -0
  54. package/lib/input/util.js +304 -0
  55. package/lib/input/vkeys.js +127 -0
  56. package/lib/input/xtscancodes.js +505 -0
  57. package/lib/rfb.js +3448 -0
  58. package/lib/util/browser.js +131 -0
  59. package/lib/util/cursor.js +314 -0
  60. package/lib/util/element.js +43 -0
  61. package/lib/util/events.js +142 -0
  62. package/lib/util/eventtarget.js +64 -0
  63. package/lib/util/int.js +22 -0
  64. package/lib/util/logging.js +79 -0
  65. package/lib/util/polyfill.js +72 -0
  66. package/lib/util/strings.js +38 -0
  67. package/lib/vendor/pako/lib/utils/common.js +67 -0
  68. package/lib/vendor/pako/lib/zlib/adler32.js +33 -0
  69. package/lib/vendor/pako/lib/zlib/constants.js +51 -0
  70. package/lib/vendor/pako/lib/zlib/crc32.js +42 -0
  71. package/lib/vendor/pako/lib/zlib/deflate.js +2159 -0
  72. package/lib/vendor/pako/lib/zlib/gzheader.js +53 -0
  73. package/lib/vendor/pako/lib/zlib/inffast.js +445 -0
  74. package/lib/vendor/pako/lib/zlib/inflate.js +2114 -0
  75. package/lib/vendor/pako/lib/zlib/inftrees.js +418 -0
  76. package/lib/vendor/pako/lib/zlib/messages.js +36 -0
  77. package/lib/vendor/pako/lib/zlib/trees.js +1499 -0
  78. package/lib/vendor/pako/lib/zlib/zstream.js +46 -0
  79. package/lib/vendor/promise.js +255 -0
  80. package/lib/websock.js +374 -0
  81. package/package.json +48 -28
  82. package/vendor/pako/lib/zlib/deflate.js +30 -30
  83. package/vendor/pako/lib/zlib/inflate.js +17 -17
  84. package/core/input/mouse.js +0 -280
  85. package/docs/API-internal.md +0 -125
  86. package/docs/EMBEDDING.md +0 -83
  87. package/docs/VERSION +0 -1
package/lib/display.js ADDED
@@ -0,0 +1,733 @@
1
+ "use strict";
2
+
3
+ function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.default = void 0;
9
+
10
+ var Log = _interopRequireWildcard(require("./util/logging.js"));
11
+
12
+ var _base = _interopRequireDefault(require("./base64.js"));
13
+
14
+ var _browser = require("./util/browser.js");
15
+
16
+ var _int = require("./util/int.js");
17
+
18
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
19
+
20
+ function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function _getRequireWildcardCache() { return cache; }; return cache; }
21
+
22
+ function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
23
+
24
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
25
+
26
+ function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
27
+
28
+ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
29
+
30
+ var Display = /*#__PURE__*/function () {
31
+ function Display(target) {
32
+ _classCallCheck(this, Display);
33
+
34
+ this._drawCtx = null;
35
+ this._renderQ = []; // queue drawing actions for in-oder rendering
36
+
37
+ this._flushing = false; // the full frame buffer (logical canvas) size
38
+
39
+ this._fbWidth = 0;
40
+ this._fbHeight = 0;
41
+ this._prevDrawStyle = "";
42
+ this._tile = null;
43
+ this._tile16x16 = null;
44
+ this._tileX = 0;
45
+ this._tileY = 0;
46
+ Log.Debug(">> Display.constructor"); // The visible canvas
47
+
48
+ this._target = target;
49
+
50
+ if (!this._target) {
51
+ throw new Error("Target must be set");
52
+ }
53
+
54
+ if (typeof this._target === 'string') {
55
+ throw new Error('target must be a DOM element');
56
+ }
57
+
58
+ if (!this._target.getContext) {
59
+ throw new Error("no getContext method");
60
+ }
61
+
62
+ this._targetCtx = this._target.getContext('2d'); // the visible canvas viewport (i.e. what actually gets seen)
63
+
64
+ this._viewportLoc = {
65
+ 'x': 0,
66
+ 'y': 0,
67
+ 'w': this._target.width,
68
+ 'h': this._target.height
69
+ }; // The hidden canvas, where we do the actual rendering
70
+
71
+ this._backbuffer = document.createElement('canvas');
72
+ this._drawCtx = this._backbuffer.getContext('2d');
73
+ this._damageBounds = {
74
+ left: 0,
75
+ top: 0,
76
+ right: this._backbuffer.width,
77
+ bottom: this._backbuffer.height
78
+ };
79
+ Log.Debug("User Agent: " + navigator.userAgent); // Check canvas features
80
+
81
+ if (!('createImageData' in this._drawCtx)) {
82
+ throw new Error("Canvas does not support createImageData");
83
+ }
84
+
85
+ this._tile16x16 = this._drawCtx.createImageData(16, 16);
86
+ Log.Debug("<< Display.constructor"); // ===== PROPERTIES =====
87
+
88
+ this._scale = 1.0;
89
+ this._clipViewport = false; // ===== EVENT HANDLERS =====
90
+
91
+ this.onflush = function () {}; // A flush request has finished
92
+
93
+ } // ===== PROPERTIES =====
94
+
95
+
96
+ _createClass(Display, [{
97
+ key: "viewportChangePos",
98
+ // ===== PUBLIC METHODS =====
99
+ value: function viewportChangePos(deltaX, deltaY) {
100
+ var vp = this._viewportLoc;
101
+ deltaX = Math.floor(deltaX);
102
+ deltaY = Math.floor(deltaY);
103
+
104
+ if (!this._clipViewport) {
105
+ deltaX = -vp.w; // clamped later of out of bounds
106
+
107
+ deltaY = -vp.h;
108
+ }
109
+
110
+ var vx2 = vp.x + vp.w - 1;
111
+ var vy2 = vp.y + vp.h - 1; // Position change
112
+
113
+ if (deltaX < 0 && vp.x + deltaX < 0) {
114
+ deltaX = -vp.x;
115
+ }
116
+
117
+ if (vx2 + deltaX >= this._fbWidth) {
118
+ deltaX -= vx2 + deltaX - this._fbWidth + 1;
119
+ }
120
+
121
+ if (vp.y + deltaY < 0) {
122
+ deltaY = -vp.y;
123
+ }
124
+
125
+ if (vy2 + deltaY >= this._fbHeight) {
126
+ deltaY -= vy2 + deltaY - this._fbHeight + 1;
127
+ }
128
+
129
+ if (deltaX === 0 && deltaY === 0) {
130
+ return;
131
+ }
132
+
133
+ Log.Debug("viewportChange deltaX: " + deltaX + ", deltaY: " + deltaY);
134
+ vp.x += deltaX;
135
+ vp.y += deltaY;
136
+
137
+ this._damage(vp.x, vp.y, vp.w, vp.h);
138
+
139
+ this.flip();
140
+ }
141
+ }, {
142
+ key: "viewportChangeSize",
143
+ value: function viewportChangeSize(width, height) {
144
+ if (!this._clipViewport || typeof width === "undefined" || typeof height === "undefined") {
145
+ Log.Debug("Setting viewport to full display region");
146
+ width = this._fbWidth;
147
+ height = this._fbHeight;
148
+ }
149
+
150
+ width = Math.floor(width);
151
+ height = Math.floor(height);
152
+
153
+ if (width > this._fbWidth) {
154
+ width = this._fbWidth;
155
+ }
156
+
157
+ if (height > this._fbHeight) {
158
+ height = this._fbHeight;
159
+ }
160
+
161
+ var vp = this._viewportLoc;
162
+
163
+ if (vp.w !== width || vp.h !== height) {
164
+ vp.w = width;
165
+ vp.h = height;
166
+ var canvas = this._target;
167
+ canvas.width = width;
168
+ canvas.height = height; // The position might need to be updated if we've grown
169
+
170
+ this.viewportChangePos(0, 0);
171
+
172
+ this._damage(vp.x, vp.y, vp.w, vp.h);
173
+
174
+ this.flip(); // Update the visible size of the target canvas
175
+
176
+ this._rescale(this._scale);
177
+ }
178
+ }
179
+ }, {
180
+ key: "absX",
181
+ value: function absX(x) {
182
+ if (this._scale === 0) {
183
+ return 0;
184
+ }
185
+
186
+ return (0, _int.toSigned32bit)(x / this._scale + this._viewportLoc.x);
187
+ }
188
+ }, {
189
+ key: "absY",
190
+ value: function absY(y) {
191
+ if (this._scale === 0) {
192
+ return 0;
193
+ }
194
+
195
+ return (0, _int.toSigned32bit)(y / this._scale + this._viewportLoc.y);
196
+ }
197
+ }, {
198
+ key: "resize",
199
+ value: function resize(width, height) {
200
+ this._prevDrawStyle = "";
201
+ this._fbWidth = width;
202
+ this._fbHeight = height;
203
+ var canvas = this._backbuffer;
204
+
205
+ if (canvas.width !== width || canvas.height !== height) {
206
+ // We have to save the canvas data since changing the size will clear it
207
+ var saveImg = null;
208
+
209
+ if (canvas.width > 0 && canvas.height > 0) {
210
+ saveImg = this._drawCtx.getImageData(0, 0, canvas.width, canvas.height);
211
+ }
212
+
213
+ if (canvas.width !== width) {
214
+ canvas.width = width;
215
+ }
216
+
217
+ if (canvas.height !== height) {
218
+ canvas.height = height;
219
+ }
220
+
221
+ if (saveImg) {
222
+ this._drawCtx.putImageData(saveImg, 0, 0);
223
+ }
224
+ } // Readjust the viewport as it may be incorrectly sized
225
+ // and positioned
226
+
227
+
228
+ var vp = this._viewportLoc;
229
+ this.viewportChangeSize(vp.w, vp.h);
230
+ this.viewportChangePos(0, 0);
231
+ } // Track what parts of the visible canvas that need updating
232
+
233
+ }, {
234
+ key: "_damage",
235
+ value: function _damage(x, y, w, h) {
236
+ if (x < this._damageBounds.left) {
237
+ this._damageBounds.left = x;
238
+ }
239
+
240
+ if (y < this._damageBounds.top) {
241
+ this._damageBounds.top = y;
242
+ }
243
+
244
+ if (x + w > this._damageBounds.right) {
245
+ this._damageBounds.right = x + w;
246
+ }
247
+
248
+ if (y + h > this._damageBounds.bottom) {
249
+ this._damageBounds.bottom = y + h;
250
+ }
251
+ } // Update the visible canvas with the contents of the
252
+ // rendering canvas
253
+
254
+ }, {
255
+ key: "flip",
256
+ value: function flip(fromQueue) {
257
+ if (this._renderQ.length !== 0 && !fromQueue) {
258
+ this._renderQPush({
259
+ 'type': 'flip'
260
+ });
261
+ } else {
262
+ var x = this._damageBounds.left;
263
+ var y = this._damageBounds.top;
264
+ var w = this._damageBounds.right - x;
265
+ var h = this._damageBounds.bottom - y;
266
+ var vx = x - this._viewportLoc.x;
267
+ var vy = y - this._viewportLoc.y;
268
+
269
+ if (vx < 0) {
270
+ w += vx;
271
+ x -= vx;
272
+ vx = 0;
273
+ }
274
+
275
+ if (vy < 0) {
276
+ h += vy;
277
+ y -= vy;
278
+ vy = 0;
279
+ }
280
+
281
+ if (vx + w > this._viewportLoc.w) {
282
+ w = this._viewportLoc.w - vx;
283
+ }
284
+
285
+ if (vy + h > this._viewportLoc.h) {
286
+ h = this._viewportLoc.h - vy;
287
+ }
288
+
289
+ if (w > 0 && h > 0) {
290
+ // FIXME: We may need to disable image smoothing here
291
+ // as well (see copyImage()), but we haven't
292
+ // noticed any problem yet.
293
+ this._targetCtx.drawImage(this._backbuffer, x, y, w, h, vx, vy, w, h);
294
+ }
295
+
296
+ this._damageBounds.left = this._damageBounds.top = 65535;
297
+ this._damageBounds.right = this._damageBounds.bottom = 0;
298
+ }
299
+ }
300
+ }, {
301
+ key: "pending",
302
+ value: function pending() {
303
+ return this._renderQ.length > 0;
304
+ }
305
+ }, {
306
+ key: "flush",
307
+ value: function flush() {
308
+ if (this._renderQ.length === 0) {
309
+ this.onflush();
310
+ } else {
311
+ this._flushing = true;
312
+ }
313
+ }
314
+ }, {
315
+ key: "fillRect",
316
+ value: function 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
+
329
+ this._drawCtx.fillRect(x, y, width, height);
330
+
331
+ this._damage(x, y, width, height);
332
+ }
333
+ }
334
+ }, {
335
+ key: "copyImage",
336
+ value: function copyImage(oldX, oldY, newX, newY, w, h, fromQueue) {
337
+ if (this._renderQ.length !== 0 && !fromQueue) {
338
+ this._renderQPush({
339
+ 'type': 'copy',
340
+ 'oldX': oldX,
341
+ 'oldY': oldY,
342
+ 'x': newX,
343
+ 'y': newY,
344
+ 'width': w,
345
+ 'height': h
346
+ });
347
+ } else {
348
+ // Due to this bug among others [1] we need to disable the image-smoothing to
349
+ // avoid getting a blur effect when copying data.
350
+ //
351
+ // 1. https://bugzilla.mozilla.org/show_bug.cgi?id=1194719
352
+ //
353
+ // We need to set these every time since all properties are reset
354
+ // when the the size is changed
355
+ this._drawCtx.mozImageSmoothingEnabled = false;
356
+ this._drawCtx.webkitImageSmoothingEnabled = false;
357
+ this._drawCtx.msImageSmoothingEnabled = false;
358
+ this._drawCtx.imageSmoothingEnabled = false;
359
+
360
+ this._drawCtx.drawImage(this._backbuffer, oldX, oldY, w, h, newX, newY, w, h);
361
+
362
+ this._damage(newX, newY, w, h);
363
+ }
364
+ }
365
+ }, {
366
+ key: "imageRect",
367
+ value: function imageRect(x, y, width, height, mime, arr) {
368
+ /* The internal logic cannot handle empty images, so bail early */
369
+ if (width === 0 || height === 0) {
370
+ return;
371
+ }
372
+
373
+ var img = new Image();
374
+ img.src = "data: " + mime + ";base64," + _base.default.encode(arr);
375
+
376
+ this._renderQPush({
377
+ 'type': 'img',
378
+ 'img': img,
379
+ 'x': x,
380
+ 'y': y,
381
+ 'width': width,
382
+ 'height': height
383
+ });
384
+ } // start updating a tile
385
+
386
+ }, {
387
+ key: "startTile",
388
+ value: function startTile(x, y, width, height, color) {
389
+ this._tileX = x;
390
+ this._tileY = y;
391
+
392
+ if (width === 16 && height === 16) {
393
+ this._tile = this._tile16x16;
394
+ } else {
395
+ this._tile = this._drawCtx.createImageData(width, height);
396
+ }
397
+
398
+ var red = color[2];
399
+ var green = color[1];
400
+ var blue = color[0];
401
+ var data = this._tile.data;
402
+
403
+ for (var i = 0; i < width * height * 4; i += 4) {
404
+ data[i] = red;
405
+ data[i + 1] = green;
406
+ data[i + 2] = blue;
407
+ data[i + 3] = 255;
408
+ }
409
+ } // update sub-rectangle of the current tile
410
+
411
+ }, {
412
+ key: "subTile",
413
+ value: function subTile(x, y, w, h, color) {
414
+ var red = color[2];
415
+ var green = color[1];
416
+ var blue = color[0];
417
+ var xend = x + w;
418
+ var yend = y + h;
419
+ var data = this._tile.data;
420
+ var width = this._tile.width;
421
+
422
+ for (var j = y; j < yend; j++) {
423
+ for (var i = x; i < xend; i++) {
424
+ var p = (i + j * width) * 4;
425
+ data[p] = red;
426
+ data[p + 1] = green;
427
+ data[p + 2] = blue;
428
+ data[p + 3] = 255;
429
+ }
430
+ }
431
+ } // draw the current tile to the screen
432
+
433
+ }, {
434
+ key: "finishTile",
435
+ value: function finishTile() {
436
+ this._drawCtx.putImageData(this._tile, this._tileX, this._tileY);
437
+
438
+ this._damage(this._tileX, this._tileY, this._tile.width, this._tile.height);
439
+ }
440
+ }, {
441
+ key: "blitImage",
442
+ value: function blitImage(x, y, width, height, arr, offset, fromQueue) {
443
+ if (this._renderQ.length !== 0 && !fromQueue) {
444
+ // NB(directxman12): it's technically more performant here to use preallocated arrays,
445
+ // but it's a lot of extra work for not a lot of payoff -- if we're using the render queue,
446
+ // this probably isn't getting called *nearly* as much
447
+ var newArr = new Uint8Array(width * height * 4);
448
+ newArr.set(new Uint8Array(arr.buffer, 0, newArr.length));
449
+
450
+ this._renderQPush({
451
+ 'type': 'blit',
452
+ 'data': newArr,
453
+ 'x': x,
454
+ 'y': y,
455
+ 'width': width,
456
+ 'height': height
457
+ });
458
+ } else {
459
+ this._bgrxImageData(x, y, width, height, arr, offset);
460
+ }
461
+ }
462
+ }, {
463
+ key: "blitRgbImage",
464
+ value: function blitRgbImage(x, y, width, height, arr, offset, fromQueue) {
465
+ if (this._renderQ.length !== 0 && !fromQueue) {
466
+ // NB(directxman12): it's technically more performant here to use preallocated arrays,
467
+ // but it's a lot of extra work for not a lot of payoff -- if we're using the render queue,
468
+ // this probably isn't getting called *nearly* as much
469
+ var newArr = new Uint8Array(width * height * 3);
470
+ newArr.set(new Uint8Array(arr.buffer, 0, newArr.length));
471
+
472
+ this._renderQPush({
473
+ 'type': 'blitRgb',
474
+ 'data': newArr,
475
+ 'x': x,
476
+ 'y': y,
477
+ 'width': width,
478
+ 'height': height
479
+ });
480
+ } else {
481
+ this._rgbImageData(x, y, width, height, arr, offset);
482
+ }
483
+ }
484
+ }, {
485
+ key: "blitRgbxImage",
486
+ value: function blitRgbxImage(x, y, width, height, arr, offset, fromQueue) {
487
+ if (this._renderQ.length !== 0 && !fromQueue) {
488
+ // NB(directxman12): it's technically more performant here to use preallocated arrays,
489
+ // but it's a lot of extra work for not a lot of payoff -- if we're using the render queue,
490
+ // this probably isn't getting called *nearly* as much
491
+ var newArr = new Uint8Array(width * height * 4);
492
+ newArr.set(new Uint8Array(arr.buffer, 0, newArr.length));
493
+
494
+ this._renderQPush({
495
+ 'type': 'blitRgbx',
496
+ 'data': newArr,
497
+ 'x': x,
498
+ 'y': y,
499
+ 'width': width,
500
+ 'height': height
501
+ });
502
+ } else {
503
+ this._rgbxImageData(x, y, width, height, arr, offset);
504
+ }
505
+ }
506
+ }, {
507
+ key: "drawImage",
508
+ value: function drawImage(img, x, y) {
509
+ this._drawCtx.drawImage(img, x, y);
510
+
511
+ this._damage(x, y, img.width, img.height);
512
+ }
513
+ }, {
514
+ key: "autoscale",
515
+ value: function autoscale(containerWidth, containerHeight) {
516
+ var scaleRatio;
517
+
518
+ if (containerWidth === 0 || containerHeight === 0) {
519
+ scaleRatio = 0;
520
+ } else {
521
+ var vp = this._viewportLoc;
522
+ var targetAspectRatio = containerWidth / containerHeight;
523
+ var fbAspectRatio = vp.w / vp.h;
524
+
525
+ if (fbAspectRatio >= targetAspectRatio) {
526
+ scaleRatio = containerWidth / vp.w;
527
+ } else {
528
+ scaleRatio = containerHeight / vp.h;
529
+ }
530
+ }
531
+
532
+ this._rescale(scaleRatio);
533
+ } // ===== PRIVATE METHODS =====
534
+
535
+ }, {
536
+ key: "_rescale",
537
+ value: function _rescale(factor) {
538
+ this._scale = factor;
539
+ var vp = this._viewportLoc; // NB(directxman12): If you set the width directly, or set the
540
+ // style width to a number, the canvas is cleared.
541
+ // However, if you set the style width to a string
542
+ // ('NNNpx'), the canvas is scaled without clearing.
543
+
544
+ var width = factor * vp.w + 'px';
545
+ var height = factor * vp.h + 'px';
546
+
547
+ if (this._target.style.width !== width || this._target.style.height !== height) {
548
+ this._target.style.width = width;
549
+ this._target.style.height = height;
550
+ }
551
+ }
552
+ }, {
553
+ key: "_setFillColor",
554
+ value: function _setFillColor(color) {
555
+ var newStyle = 'rgb(' + color[2] + ',' + color[1] + ',' + color[0] + ')';
556
+
557
+ if (newStyle !== this._prevDrawStyle) {
558
+ this._drawCtx.fillStyle = newStyle;
559
+ this._prevDrawStyle = newStyle;
560
+ }
561
+ }
562
+ }, {
563
+ key: "_rgbImageData",
564
+ value: function _rgbImageData(x, y, width, height, arr, offset) {
565
+ var img = this._drawCtx.createImageData(width, height);
566
+
567
+ var data = img.data;
568
+
569
+ for (var i = 0, j = offset; i < width * height * 4; i += 4, j += 3) {
570
+ data[i] = arr[j];
571
+ data[i + 1] = arr[j + 1];
572
+ data[i + 2] = arr[j + 2];
573
+ data[i + 3] = 255; // Alpha
574
+ }
575
+
576
+ this._drawCtx.putImageData(img, x, y);
577
+
578
+ this._damage(x, y, img.width, img.height);
579
+ }
580
+ }, {
581
+ key: "_bgrxImageData",
582
+ value: function _bgrxImageData(x, y, width, height, arr, offset) {
583
+ var img = this._drawCtx.createImageData(width, height);
584
+
585
+ var data = img.data;
586
+
587
+ for (var i = 0, j = offset; i < width * height * 4; i += 4, j += 4) {
588
+ data[i] = arr[j + 2];
589
+ data[i + 1] = arr[j + 1];
590
+ data[i + 2] = arr[j];
591
+ data[i + 3] = 255; // Alpha
592
+ }
593
+
594
+ this._drawCtx.putImageData(img, x, y);
595
+
596
+ this._damage(x, y, img.width, img.height);
597
+ }
598
+ }, {
599
+ key: "_rgbxImageData",
600
+ value: function _rgbxImageData(x, y, width, height, arr, offset) {
601
+ // NB(directxman12): arr must be an Type Array view
602
+ var img;
603
+
604
+ if (_browser.supportsImageMetadata) {
605
+ img = new ImageData(new Uint8ClampedArray(arr.buffer, arr.byteOffset, width * height * 4), width, height);
606
+ } else {
607
+ img = this._drawCtx.createImageData(width, height);
608
+ img.data.set(new Uint8ClampedArray(arr.buffer, arr.byteOffset, width * height * 4));
609
+ }
610
+
611
+ this._drawCtx.putImageData(img, x, y);
612
+
613
+ this._damage(x, y, img.width, img.height);
614
+ }
615
+ }, {
616
+ key: "_renderQPush",
617
+ value: function _renderQPush(action) {
618
+ this._renderQ.push(action);
619
+
620
+ if (this._renderQ.length === 1) {
621
+ // If this can be rendered immediately it will be, otherwise
622
+ // the scanner will wait for the relevant event
623
+ this._scanRenderQ();
624
+ }
625
+ }
626
+ }, {
627
+ key: "_resumeRenderQ",
628
+ value: function _resumeRenderQ() {
629
+ // "this" is the object that is ready, not the
630
+ // display object
631
+ this.removeEventListener('load', this._noVNCDisplay._resumeRenderQ);
632
+
633
+ this._noVNCDisplay._scanRenderQ();
634
+ }
635
+ }, {
636
+ key: "_scanRenderQ",
637
+ value: function _scanRenderQ() {
638
+ var ready = true;
639
+
640
+ while (ready && this._renderQ.length > 0) {
641
+ var a = this._renderQ[0];
642
+
643
+ switch (a.type) {
644
+ case 'flip':
645
+ this.flip(true);
646
+ break;
647
+
648
+ case 'copy':
649
+ this.copyImage(a.oldX, a.oldY, a.x, a.y, a.width, a.height, true);
650
+ break;
651
+
652
+ case 'fill':
653
+ this.fillRect(a.x, a.y, a.width, a.height, a.color, true);
654
+ break;
655
+
656
+ case 'blit':
657
+ this.blitImage(a.x, a.y, a.width, a.height, a.data, 0, true);
658
+ break;
659
+
660
+ case 'blitRgb':
661
+ this.blitRgbImage(a.x, a.y, a.width, a.height, a.data, 0, true);
662
+ break;
663
+
664
+ case 'blitRgbx':
665
+ this.blitRgbxImage(a.x, a.y, a.width, a.height, a.data, 0, true);
666
+ break;
667
+
668
+ case 'img':
669
+ /* IE tends to set "complete" prematurely, so check dimensions */
670
+ if (a.img.complete && a.img.width !== 0 && a.img.height !== 0) {
671
+ if (a.img.width !== a.width || a.img.height !== a.height) {
672
+ Log.Error("Decoded image has incorrect dimensions. Got " + a.img.width + "x" + a.img.height + ". Expected " + a.width + "x" + a.height + ".");
673
+ return;
674
+ }
675
+
676
+ this.drawImage(a.img, a.x, a.y);
677
+ } else {
678
+ a.img._noVNCDisplay = this;
679
+ a.img.addEventListener('load', this._resumeRenderQ); // We need to wait for this image to 'load'
680
+ // to keep things in-order
681
+
682
+ ready = false;
683
+ }
684
+
685
+ break;
686
+ }
687
+
688
+ if (ready) {
689
+ this._renderQ.shift();
690
+ }
691
+ }
692
+
693
+ if (this._renderQ.length === 0 && this._flushing) {
694
+ this._flushing = false;
695
+ this.onflush();
696
+ }
697
+ }
698
+ }, {
699
+ key: "scale",
700
+ get: function get() {
701
+ return this._scale;
702
+ },
703
+ set: function set(scale) {
704
+ this._rescale(scale);
705
+ }
706
+ }, {
707
+ key: "clipViewport",
708
+ get: function get() {
709
+ return this._clipViewport;
710
+ },
711
+ set: function set(viewport) {
712
+ this._clipViewport = viewport; // May need to readjust the viewport dimensions
713
+
714
+ var vp = this._viewportLoc;
715
+ this.viewportChangeSize(vp.w, vp.h);
716
+ this.viewportChangePos(0, 0);
717
+ }
718
+ }, {
719
+ key: "width",
720
+ get: function get() {
721
+ return this._fbWidth;
722
+ }
723
+ }, {
724
+ key: "height",
725
+ get: function get() {
726
+ return this._fbHeight;
727
+ }
728
+ }]);
729
+
730
+ return Display;
731
+ }();
732
+
733
+ exports.default = Display;