@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.
- package/AUTHORS +13 -0
- package/LICENSE.txt +2 -1
- package/README.md +69 -3
- package/core/base64.js +35 -41
- package/core/decoders/copyrect.js +22 -0
- package/core/decoders/hextile.js +137 -0
- package/core/decoders/raw.js +56 -0
- package/core/decoders/rre.js +44 -0
- package/core/decoders/tight.js +315 -0
- package/core/decoders/tightpng.js +27 -0
- package/core/deflator.js +85 -0
- package/core/des.js +90 -95
- package/core/display.js +254 -297
- package/core/encodings.js +7 -3
- package/core/inflator.js +48 -20
- package/core/input/domkeytable.js +21 -24
- package/core/input/fixedkeys.js +3 -1
- package/core/input/gesturehandler.js +567 -0
- package/core/input/keyboard.js +194 -120
- package/core/input/keysym.js +2 -0
- package/core/input/keysymdef.js +3 -3
- package/core/input/util.js +53 -12
- package/core/input/vkeys.js +2 -1
- package/core/rfb.js +1937 -1496
- package/core/util/browser.js +80 -29
- package/core/util/cursor.js +253 -0
- package/core/util/element.js +32 -0
- package/core/util/events.js +59 -55
- package/core/util/eventtarget.js +25 -30
- package/core/util/int.js +15 -0
- package/core/util/logging.js +21 -16
- package/core/util/polyfill.js +15 -8
- package/core/util/strings.js +21 -8
- package/core/websock.js +145 -167
- package/docs/API.md +31 -10
- package/lib/base64.js +115 -0
- package/lib/decoders/copyrect.js +44 -0
- package/lib/decoders/hextile.js +173 -0
- package/lib/decoders/raw.js +78 -0
- package/lib/decoders/rre.js +65 -0
- package/lib/decoders/tight.js +350 -0
- package/lib/decoders/tightpng.js +67 -0
- package/lib/deflator.js +99 -0
- package/lib/des.js +314 -0
- package/lib/display.js +733 -0
- package/lib/encodings.js +64 -0
- package/lib/inflator.js +87 -0
- package/lib/input/domkeytable.js +282 -0
- package/lib/input/fixedkeys.js +123 -0
- package/lib/input/gesturehandler.js +642 -0
- package/lib/input/keyboard.js +429 -0
- package/lib/input/keysym.js +1135 -0
- package/lib/input/keysymdef.js +1354 -0
- package/lib/input/util.js +304 -0
- package/lib/input/vkeys.js +127 -0
- package/lib/input/xtscancodes.js +505 -0
- package/lib/rfb.js +3448 -0
- package/lib/util/browser.js +131 -0
- package/lib/util/cursor.js +314 -0
- package/lib/util/element.js +43 -0
- package/lib/util/events.js +142 -0
- package/lib/util/eventtarget.js +64 -0
- package/lib/util/int.js +22 -0
- package/lib/util/logging.js +79 -0
- package/lib/util/polyfill.js +72 -0
- package/lib/util/strings.js +38 -0
- package/lib/vendor/pako/lib/utils/common.js +67 -0
- package/lib/vendor/pako/lib/zlib/adler32.js +33 -0
- package/lib/vendor/pako/lib/zlib/constants.js +51 -0
- package/lib/vendor/pako/lib/zlib/crc32.js +42 -0
- package/lib/vendor/pako/lib/zlib/deflate.js +2159 -0
- package/lib/vendor/pako/lib/zlib/gzheader.js +53 -0
- package/lib/vendor/pako/lib/zlib/inffast.js +445 -0
- package/lib/vendor/pako/lib/zlib/inflate.js +2114 -0
- package/lib/vendor/pako/lib/zlib/inftrees.js +418 -0
- package/lib/vendor/pako/lib/zlib/messages.js +36 -0
- package/lib/vendor/pako/lib/zlib/trees.js +1499 -0
- package/lib/vendor/pako/lib/zlib/zstream.js +46 -0
- package/lib/vendor/promise.js +255 -0
- package/lib/websock.js +374 -0
- package/package.json +48 -28
- package/vendor/pako/lib/zlib/deflate.js +30 -30
- package/vendor/pako/lib/zlib/inflate.js +17 -17
- package/core/input/mouse.js +0 -280
- package/docs/API-internal.md +0 -125
- package/docs/EMBEDDING.md +0 -83
- 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;
|