JavaScript 65.5%
Python 17.8%
CSS 13%
HTML 3.7%
1"use strict";23Object.defineProperty(exports, "__esModule", {4 value: true5});6exports["default"] = void 0;7var Log = _interopRequireWildcard(require("./util/logging.js"));8var _base = _interopRequireDefault(require("./base64.js"));9var _int = require("./util/int.js");10function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }11function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }12function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { "default": e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n["default"] = e, t && t.set(e, n), n; }13function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }14function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }15function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }16function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }17function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }18function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } /*19 * noVNC: HTML5 VNC client20 * Copyright (C) 2019 The noVNC authors21 * Licensed under MPL 2.0 (see LICENSE.txt)22 *23 * See README.md for usage and integration instructions.24 */25var Display = exports["default"] = /*#__PURE__*/function () {26 function Display(target) {27 _classCallCheck(this, Display);28 this._drawCtx = null;29 this._renderQ = []; // queue drawing actions for in-oder rendering30 this._flushPromise = null;3132 // the full frame buffer (logical canvas) size33 this._fbWidth = 0;34 this._fbHeight = 0;35 this._prevDrawStyle = "";36 Log.Debug(">> Display.constructor");3738 // The visible canvas39 this._target = target;40 if (!this._target) {41 throw new Error("Target must be set");42 }43 if (typeof this._target === 'string') {44 throw new Error('target must be a DOM element');45 }46 if (!this._target.getContext) {47 throw new Error("no getContext method");48 }49 this._targetCtx = this._target.getContext('2d');5051 // the visible canvas viewport (i.e. what actually gets seen)52 this._viewportLoc = {53 'x': 0,54 'y': 0,55 'w': this._target.width,56 'h': this._target.height57 };5859 // The hidden canvas, where we do the actual rendering60 this._backbuffer = document.createElement('canvas');61 this._drawCtx = this._backbuffer.getContext('2d');62 this._damageBounds = {63 left: 0,64 top: 0,65 right: this._backbuffer.width,66 bottom: this._backbuffer.height67 };68 Log.Debug("User Agent: " + navigator.userAgent);69 Log.Debug("<< Display.constructor");7071 // ===== PROPERTIES =====7273 this._scale = 1.0;74 this._clipViewport = false;75 }7677 // ===== PROPERTIES =====78 return _createClass(Display, [{79 key: "scale",80 get: function get() {81 return this._scale;82 },83 set: function set(scale) {84 this._rescale(scale);85 }86 }, {87 key: "clipViewport",88 get: function get() {89 return this._clipViewport;90 },91 set: function set(viewport) {92 this._clipViewport = viewport;93 // May need to readjust the viewport dimensions94 var vp = this._viewportLoc;95 this.viewportChangeSize(vp.w, vp.h);96 this.viewportChangePos(0, 0);97 }98 }, {99 key: "width",100 get: function get() {101 return this._fbWidth;102 }103 }, {104 key: "height",105 get: function get() {106 return this._fbHeight;107 }108109 // ===== PUBLIC METHODS =====110 }, {111 key: "viewportChangePos",112 value: function viewportChangePos(deltaX, deltaY) {113 var vp = this._viewportLoc;114 deltaX = Math.floor(deltaX);115 deltaY = Math.floor(deltaY);116 if (!this._clipViewport) {117 deltaX = -vp.w; // clamped later of out of bounds118 deltaY = -vp.h;119 }120 var vx2 = vp.x + vp.w - 1;121 var vy2 = vp.y + vp.h - 1;122123 // Position change124125 if (deltaX < 0 && vp.x + deltaX < 0) {126 deltaX = -vp.x;127 }128 if (vx2 + deltaX >= this._fbWidth) {129 deltaX -= vx2 + deltaX - this._fbWidth + 1;130 }131 if (vp.y + deltaY < 0) {132 deltaY = -vp.y;133 }134 if (vy2 + deltaY >= this._fbHeight) {135 deltaY -= vy2 + deltaY - this._fbHeight + 1;136 }137 if (deltaX === 0 && deltaY === 0) {138 return;139 }140 Log.Debug("viewportChange deltaX: " + deltaX + ", deltaY: " + deltaY);141 vp.x += deltaX;142 vp.y += deltaY;143 this._damage(vp.x, vp.y, vp.w, vp.h);144 this.flip();145 }146 }, {147 key: "viewportChangeSize",148 value: function viewportChangeSize(width, height) {149 if (!this._clipViewport || typeof width === "undefined" || typeof height === "undefined") {150 Log.Debug("Setting viewport to full display region");151 width = this._fbWidth;152 height = this._fbHeight;153 }154 width = Math.floor(width);155 height = Math.floor(height);156 if (width > this._fbWidth) {157 width = this._fbWidth;158 }159 if (height > this._fbHeight) {160 height = this._fbHeight;161 }162 var vp = this._viewportLoc;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;169170 // The position might need to be updated if we've grown171 this.viewportChangePos(0, 0);172 this._damage(vp.x, vp.y, vp.w, vp.h);173 this.flip();174175 // Update the visible size of the target canvas176 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 return (0, _int.toSigned32bit)(x / this._scale + this._viewportLoc.x);186 }187 }, {188 key: "absY",189 value: function absY(y) {190 if (this._scale === 0) {191 return 0;192 }193 return (0, _int.toSigned32bit)(y / this._scale + this._viewportLoc.y);194 }195 }, {196 key: "resize",197 value: function resize(width, height) {198 this._prevDrawStyle = "";199 this._fbWidth = width;200 this._fbHeight = height;201 var canvas = this._backbuffer;202 if (canvas.width !== width || canvas.height !== height) {203 // We have to save the canvas data since changing the size will clear it204 var saveImg = null;205 if (canvas.width > 0 && canvas.height > 0) {206 saveImg = this._drawCtx.getImageData(0, 0, canvas.width, canvas.height);207 }208 if (canvas.width !== width) {209 canvas.width = width;210 }211 if (canvas.height !== height) {212 canvas.height = height;213 }214 if (saveImg) {215 this._drawCtx.putImageData(saveImg, 0, 0);216 }217 }218219 // Readjust the viewport as it may be incorrectly sized220 // and positioned221 var vp = this._viewportLoc;222 this.viewportChangeSize(vp.w, vp.h);223 this.viewportChangePos(0, 0);224 }225 }, {226 key: "getImageData",227 value: function getImageData() {228 return this._drawCtx.getImageData(0, 0, this.width, this.height);229 }230 }, {231 key: "toDataURL",232 value: function toDataURL(type, encoderOptions) {233 return this._backbuffer.toDataURL(type, encoderOptions);234 }235 }, {236 key: "toBlob",237 value: function toBlob(callback, type, quality) {238 return this._backbuffer.toBlob(callback, type, quality);239 }240241 // Track what parts of the visible canvas that need updating242 }, {243 key: "_damage",244 value: function _damage(x, y, w, h) {245 if (x < this._damageBounds.left) {246 this._damageBounds.left = x;247 }248 if (y < this._damageBounds.top) {249 this._damageBounds.top = y;250 }251 if (x + w > this._damageBounds.right) {252 this._damageBounds.right = x + w;253 }254 if (y + h > this._damageBounds.bottom) {255 this._damageBounds.bottom = y + h;256 }257 }258259 // Update the visible canvas with the contents of the260 // rendering canvas261 }, {262 key: "flip",263 value: function flip(fromQueue) {264 if (this._renderQ.length !== 0 && !fromQueue) {265 this._renderQPush({266 'type': 'flip'267 });268 } else {269 var x = this._damageBounds.left;270 var y = this._damageBounds.top;271 var w = this._damageBounds.right - x;272 var h = this._damageBounds.bottom - y;273 var vx = x - this._viewportLoc.x;274 var vy = y - this._viewportLoc.y;275 if (vx < 0) {276 w += vx;277 x -= vx;278 vx = 0;279 }280 if (vy < 0) {281 h += vy;282 y -= vy;283 vy = 0;284 }285 if (vx + w > this._viewportLoc.w) {286 w = this._viewportLoc.w - vx;287 }288 if (vy + h > this._viewportLoc.h) {289 h = this._viewportLoc.h - vy;290 }291 if (w > 0 && h > 0) {292 // FIXME: We may need to disable image smoothing here293 // as well (see copyImage()), but we haven't294 // noticed any problem yet.295 this._targetCtx.drawImage(this._backbuffer, x, y, w, h, vx, vy, w, h);296 }297 this._damageBounds.left = this._damageBounds.top = 65535;298 this._damageBounds.right = this._damageBounds.bottom = 0;299 }300 }301 }, {302 key: "pending",303 value: function pending() {304 return this._renderQ.length > 0;305 }306 }, {307 key: "flush",308 value: function flush() {309 var _this = this;310 if (this._renderQ.length === 0) {311 return Promise.resolve();312 } else {313 if (this._flushPromise === null) {314 this._flushPromise = new Promise(function (resolve) {315 _this._flushResolve = resolve;316 });317 }318 return this._flushPromise;319 }320 }321 }, {322 key: "fillRect",323 value: function fillRect(x, y, width, height, color, fromQueue) {324 if (this._renderQ.length !== 0 && !fromQueue) {325 this._renderQPush({326 'type': 'fill',327 'x': x,328 'y': y,329 'width': width,330 'height': height,331 'color': color332 });333 } else {334 this._setFillColor(color);335 this._drawCtx.fillRect(x, y, width, height);336 this._damage(x, y, width, height);337 }338 }339 }, {340 key: "copyImage",341 value: function copyImage(oldX, oldY, newX, newY, w, h, fromQueue) {342 if (this._renderQ.length !== 0 && !fromQueue) {343 this._renderQPush({344 'type': 'copy',345 'oldX': oldX,346 'oldY': oldY,347 'x': newX,348 'y': newY,349 'width': w,350 'height': h351 });352 } else {353 // Due to this bug among others [1] we need to disable the image-smoothing to354 // avoid getting a blur effect when copying data.355 //356 // 1. https://bugzilla.mozilla.org/show_bug.cgi?id=1194719357 //358 // We need to set these every time since all properties are reset359 // when the the size is changed360 this._drawCtx.mozImageSmoothingEnabled = false;361 this._drawCtx.webkitImageSmoothingEnabled = false;362 this._drawCtx.msImageSmoothingEnabled = false;363 this._drawCtx.imageSmoothingEnabled = false;364 this._drawCtx.drawImage(this._backbuffer, oldX, oldY, w, h, newX, newY, w, h);365 this._damage(newX, newY, w, h);366 }367 }368 }, {369 key: "imageRect",370 value: function imageRect(x, y, width, height, mime, arr) {371 /* The internal logic cannot handle empty images, so bail early */372 if (width === 0 || height === 0) {373 return;374 }375 var img = new Image();376 img.src = "data: " + mime + ";base64," + _base["default"].encode(arr);377 this._renderQPush({378 'type': 'img',379 'img': img,380 'x': x,381 'y': y,382 'width': width,383 'height': height384 });385 }386 }, {387 key: "videoFrame",388 value: function videoFrame(x, y, width, height, frame) {389 this._renderQPush({390 'type': 'frame',391 'frame': frame,392 'x': x,393 'y': y,394 'width': width,395 'height': height396 });397 }398 }, {399 key: "blitImage",400 value: function blitImage(x, y, width, height, arr, offset, fromQueue) {401 if (this._renderQ.length !== 0 && !fromQueue) {402 // NB(directxman12): it's technically more performant here to use preallocated arrays,403 // but it's a lot of extra work for not a lot of payoff -- if we're using the render queue,404 // this probably isn't getting called *nearly* as much405 var newArr = new Uint8Array(width * height * 4);406 newArr.set(new Uint8Array(arr.buffer, 0, newArr.length));407 this._renderQPush({408 'type': 'blit',409 'data': newArr,410 'x': x,411 'y': y,412 'width': width,413 'height': height414 });415 } else {416 // NB(directxman12): arr must be an Type Array view417 var data = new Uint8ClampedArray(arr.buffer, arr.byteOffset + offset, width * height * 4);418 var img = new ImageData(data, width, height);419 this._drawCtx.putImageData(img, x, y);420 this._damage(x, y, width, height);421 }422 }423 }, {424 key: "drawImage",425 value: function drawImage(img) {426 var _this$_drawCtx;427 for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {428 args[_key - 1] = arguments[_key];429 }430 (_this$_drawCtx = this._drawCtx).drawImage.apply(_this$_drawCtx, [img].concat(args));431 if (args.length <= 4) {432 var x = args[0],433 y = args[1];434 this._damage(x, y, img.width, img.height);435 } else {436 var sw = args[2],437 sh = args[3],438 dx = args[4],439 dy = args[5];440 this._damage(dx, dy, sw, sh);441 }442 }443 }, {444 key: "autoscale",445 value: function autoscale(containerWidth, containerHeight) {446 var scaleRatio;447 if (containerWidth === 0 || containerHeight === 0) {448 scaleRatio = 0;449 } else {450 var vp = this._viewportLoc;451 var targetAspectRatio = containerWidth / containerHeight;452 var fbAspectRatio = vp.w / vp.h;453 if (fbAspectRatio >= targetAspectRatio) {454 scaleRatio = containerWidth / vp.w;455 } else {456 scaleRatio = containerHeight / vp.h;457 }458 }459 this._rescale(scaleRatio);460 }461462 // ===== PRIVATE METHODS =====463 }, {464 key: "_rescale",465 value: function _rescale(factor) {466 this._scale = factor;467 var vp = this._viewportLoc;468469 // NB(directxman12): If you set the width directly, or set the470 // style width to a number, the canvas is cleared.471 // However, if you set the style width to a string472 // ('NNNpx'), the canvas is scaled without clearing.473 var width = factor * vp.w + 'px';474 var height = factor * vp.h + 'px';475 if (this._target.style.width !== width || this._target.style.height !== height) {476 this._target.style.width = width;477 this._target.style.height = height;478 }479 }480 }, {481 key: "_setFillColor",482 value: function _setFillColor(color) {483 var newStyle = 'rgb(' + color[0] + ',' + color[1] + ',' + color[2] + ')';484 if (newStyle !== this._prevDrawStyle) {485 this._drawCtx.fillStyle = newStyle;486 this._prevDrawStyle = newStyle;487 }488 }489 }, {490 key: "_renderQPush",491 value: function _renderQPush(action) {492 this._renderQ.push(action);493 if (this._renderQ.length === 1) {494 // If this can be rendered immediately it will be, otherwise495 // the scanner will wait for the relevant event496 this._scanRenderQ();497 }498 }499 }, {500 key: "_resumeRenderQ",501 value: function _resumeRenderQ() {502 // "this" is the object that is ready, not the503 // display object504 this.removeEventListener('load', this._noVNCDisplay._resumeRenderQ);505 this._noVNCDisplay._scanRenderQ();506 }507 }, {508 key: "_scanRenderQ",509 value: function _scanRenderQ() {510 var _this2 = this;511 var ready = true;512 var _loop = function _loop() {513 var a = _this2._renderQ[0];514 switch (a.type) {515 case 'flip':516 _this2.flip(true);517 break;518 case 'copy':519 _this2.copyImage(a.oldX, a.oldY, a.x, a.y, a.width, a.height, true);520 break;521 case 'fill':522 _this2.fillRect(a.x, a.y, a.width, a.height, a.color, true);523 break;524 case 'blit':525 _this2.blitImage(a.x, a.y, a.width, a.height, a.data, 0, true);526 break;527 case 'img':528 if (a.img.complete) {529 if (a.img.width !== a.width || a.img.height !== a.height) {530 Log.Error("Decoded image has incorrect dimensions. Got " + a.img.width + "x" + a.img.height + ". Expected " + a.width + "x" + a.height + ".");531 return {532 v: void 0533 };534 }535 _this2.drawImage(a.img, a.x, a.y);536 } else {537 a.img._noVNCDisplay = _this2;538 a.img.addEventListener('load', _this2._resumeRenderQ);539 // We need to wait for this image to 'load'540 // to keep things in-order541 ready = false;542 }543 break;544 case 'frame':545 if (a.frame.ready) {546 // The encoded frame may be larger than the rect due to547 // limitations of the encoder, so we need to crop the548 // frame.549 var frame = a.frame.frame;550 if (frame.codedWidth < a.width || frame.codedHeight < a.height) {551 Log.Warn("Decoded video frame does not cover its full rectangle area. Expecting at least " + a.width + "x" + a.height + " but got " + frame.codedWidth + "x" + frame.codedHeight);552 }553 var sx = 0;554 var sy = 0;555 var sw = a.width;556 var sh = a.height;557 var dx = a.x;558 var dy = a.y;559 var dw = sw;560 var dh = sh;561 _this2.drawImage(frame, sx, sy, sw, sh, dx, dy, dw, dh);562 frame.close();563 } else {564 var display = _this2;565 a.frame.promise.then(function () {566 display._scanRenderQ();567 });568 ready = false;569 }570 break;571 }572 if (ready) {573 _this2._renderQ.shift();574 }575 },576 _ret;577 while (ready && this._renderQ.length > 0) {578 _ret = _loop();579 if (_ret) return _ret.v;580 }581 if (this._renderQ.length === 0 && this._flushPromise !== null) {582 this._flushResolve();583 this._flushPromise = null;584 this._flushResolve = null;585 }586 }587 }]);588}();