SPB Git forge

spb/admin-ka

Public
41commits 1branches 0releases
172.9 MBsize
maindefault branch
19 days agolast push
JavaScript 65.5% Python 17.8% CSS 13% HTML 3.7%
19.8 KB · 588 lines javascript
Raw Blame History
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}();