UNPKG

novnc

Version:
438 lines (433 loc) 17.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var Log = _interopRequireWildcard(require("../util/logging.js")); var _inflator = _interopRequireDefault(require("../inflator.js")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && 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; } function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 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, _toPropertyKey(descriptor.key), descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); } function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } var TightDecoder = /*#__PURE__*/function () { function TightDecoder(display) { _classCallCheck(this, TightDecoder); this._ctl = null; this._filter = null; this._numColors = 0; this._palette = new Uint8Array(1024); // 256 * 4 (max palette size * max bytes-per-pixel) this._len = 0; this._enableQOI = false; this._displayGlobal = display; this._zlibs = []; for (var i = 0; i < 4; i++) { this._zlibs[i] = new _inflator["default"](); } } _createClass(TightDecoder, [{ key: "enableQOI", value: function enableQOI() { if (!this._enableQOI) { this._enableQOIWorkers(); } return this._enableQOI; //did it succeed } }, { key: "decodeRect", value: function decodeRect(x, y, width, height, sock, display, depth, frame_id) { if (this._ctl === null) { if (sock.rQwait("TIGHT compression-control", 1)) { return false; } this._ctl = sock.rQshift8(); // Reset streams if the server requests it for (var i = 0; i < 4; i++) { if (this._ctl >> i & 1) { this._zlibs[i].reset(); Log.Info("Reset zlib stream " + i); } } // Figure out filter this._ctl = this._ctl >> 4; } var ret; if (this._ctl === 0x08) { ret = this._fillRect(x, y, width, height, sock, display, depth, frame_id); } else if (this._ctl === 0x09) { ret = this._jpegRect(x, y, width, height, sock, display, depth, frame_id); } else if (this._ctl === 0x0A) { ret = this._pngRect(x, y, width, height, sock, display, depth, frame_id); } else if ((this._ctl & 0x08) == 0) { ret = this._basicRect(this._ctl, x, y, width, height, sock, display, depth, frame_id); } else if (this._ctl === 0x0B) { ret = this._webpRect(x, y, width, height, sock, display, depth, frame_id); } else if (this._ctl === 0x0C) { ret = this._qoiRect(x, y, width, height, sock, display, depth, frame_id); } else { throw new Error("Illegal tight compression received (ctl: " + this._ctl + ")"); } if (ret) { this._ctl = null; } return ret; } }, { key: "_fillRect", value: function _fillRect(x, y, width, height, sock, display, depth, frame_id) { if (sock.rQwait("TIGHT", 3)) { return false; } var rQi = sock.rQi; var rQ = sock.rQ; display.fillRect(x, y, width, height, [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2]], frame_id, false); sock.rQskipBytes(3); return true; } }, { key: "_jpegRect", value: function _jpegRect(x, y, width, height, sock, display, depth, frame_id) { var data = this._readData(sock); if (data === null) { return false; } display.imageRect(x, y, width, height, "image/jpeg", data, frame_id); return true; } }, { key: "_webpRect", value: function _webpRect(x, y, width, height, sock, display, depth, frame_id) { var data = this._readData(sock); if (data === null) { return false; } display.imageRect(x, y, width, height, "image/webp", data, frame_id); return true; } }, { key: "_processRectQ", value: function _processRectQ() { while (this._availableWorkers.length > 0 && this._qoiRects.length > 0) { var i = this._availableWorkers.pop(); var worker = this._workers[i]; var rect = this._qoiRects.shift(); this._arrs[i].set(rect.data); worker.postMessage({ length: rect.data.length, x: rect.x, y: rect.y, width: rect.width, height: rect.height, depth: rect.depth, sab: this._sabs[i], sabR: this._sabsR[i], frame_id: rect.frame_id }); } } }, { key: "_qoiRect", value: function _qoiRect(x, y, width, height, sock, display, depth, frame_id) { var data = this._readData(sock); if (data === null) { return false; } if (this._enableQOI) { var dataClone = new Uint8Array(data); var item = { x: x, y: y, width: width, height: height, data: dataClone, depth: depth, frame_id: frame_id }; if (this._qoiRects.length < 1000) { this._qoiRects.push(item); this._processRectQ(); } else { Log.Warn("QOI queue exceeded limit."); this._qoiRects.splice(0, 500); } } return true; } }, { key: "_pngRect", value: function _pngRect(x, y, width, height, sock, display, depth, frame_id) { throw new Error("PNG received in standard Tight rect"); } }, { key: "_basicRect", value: function _basicRect(ctl, x, y, width, height, sock, display, depth, frame_id) { if (this._filter === null) { if (ctl & 0x4) { if (sock.rQwait("TIGHT", 1)) { return false; } this._filter = sock.rQshift8(); } else { // Implicit CopyFilter this._filter = 0; } } var streamId = ctl & 0x3; var ret; switch (this._filter) { case 0: // CopyFilter ret = this._copyFilter(streamId, x, y, width, height, sock, display, depth, frame_id); break; case 1: // PaletteFilter ret = this._paletteFilter(streamId, x, y, width, height, sock, display, depth, frame_id); break; case 2: // GradientFilter ret = this._gradientFilter(streamId, x, y, width, height, sock, display, depth, frame_id); break; default: throw new Error("Illegal tight filter received (ctl: " + this._filter + ")"); } if (ret) { this._filter = null; } return ret; } }, { key: "_copyFilter", value: function _copyFilter(streamId, x, y, width, height, sock, display, depth, frame_id) { var uncompressedSize = width * height * 3; var data; if (uncompressedSize === 0) { return true; } if (uncompressedSize < 12) { if (sock.rQwait("TIGHT", uncompressedSize)) { return false; } data = sock.rQshiftBytes(uncompressedSize); } else { data = this._readData(sock); if (data === null) { return false; } this._zlibs[streamId].setInput(data); data = this._zlibs[streamId].inflate(uncompressedSize); this._zlibs[streamId].setInput(null); } var rgbx = new Uint8Array(width * height * 4); for (var i = 0, j = 0; i < width * height * 4; i += 4, j += 3) { rgbx[i] = data[j]; rgbx[i + 1] = data[j + 1]; rgbx[i + 2] = data[j + 2]; rgbx[i + 3] = 255; // Alpha } display.blitImage(x, y, width, height, rgbx, 0, frame_id, false); return true; } }, { key: "_paletteFilter", value: function _paletteFilter(streamId, x, y, width, height, sock, display, depth, frame_id) { if (this._numColors === 0) { if (sock.rQwait("TIGHT palette", 1)) { return false; } var numColors = sock.rQpeek8() + 1; var paletteSize = numColors * 3; if (sock.rQwait("TIGHT palette", 1 + paletteSize)) { return false; } this._numColors = numColors; sock.rQskipBytes(1); sock.rQshiftTo(this._palette, paletteSize); } var bpp = this._numColors <= 2 ? 1 : 8; var rowSize = Math.floor((width * bpp + 7) / 8); var uncompressedSize = rowSize * height; var data; if (uncompressedSize === 0) { return true; } if (uncompressedSize < 12) { if (sock.rQwait("TIGHT", uncompressedSize)) { return false; } data = sock.rQshiftBytes(uncompressedSize); } else { data = this._readData(sock); if (data === null) { return false; } this._zlibs[streamId].setInput(data); data = this._zlibs[streamId].inflate(uncompressedSize); this._zlibs[streamId].setInput(null); } // Convert indexed (palette based) image data to RGB if (this._numColors == 2) { this._monoRect(x, y, width, height, data, this._palette, display, frame_id); } else { this._paletteRect(x, y, width, height, data, this._palette, display, frame_id); } this._numColors = 0; return true; } }, { key: "_monoRect", value: function _monoRect(x, y, width, height, data, palette, display, frame_id) { // Convert indexed (palette based) image data to RGB // TODO: reduce number of calculations inside loop var dest = this._getScratchBuffer(width * height * 4); var w = Math.floor((width + 7) / 8); var w1 = Math.floor(width / 8); for (var _y = 0; _y < height; _y++) { var dp = void 0, sp = void 0, _x = void 0; for (_x = 0; _x < w1; _x++) { for (var b = 7; b >= 0; b--) { dp = (_y * width + _x * 8 + 7 - b) * 4; sp = (data[_y * w + _x] >> b & 1) * 3; dest[dp] = palette[sp]; dest[dp + 1] = palette[sp + 1]; dest[dp + 2] = palette[sp + 2]; dest[dp + 3] = 255; } } for (var _b = 7; _b >= 8 - width % 8; _b--) { dp = (_y * width + _x * 8 + 7 - _b) * 4; sp = (data[_y * w + _x] >> _b & 1) * 3; dest[dp] = palette[sp]; dest[dp + 1] = palette[sp + 1]; dest[dp + 2] = palette[sp + 2]; dest[dp + 3] = 255; } } display.blitImage(x, y, width, height, dest, 0, frame_id, false); } }, { key: "_paletteRect", value: function _paletteRect(x, y, width, height, data, palette, display, frame_id) { // Convert indexed (palette based) image data to RGB var dest = this._getScratchBuffer(width * height * 4); var total = width * height * 4; for (var i = 0, j = 0; i < total; i += 4, j++) { var sp = data[j] * 3; dest[i] = palette[sp]; dest[i + 1] = palette[sp + 1]; dest[i + 2] = palette[sp + 2]; dest[i + 3] = 255; } display.blitImage(x, y, width, height, dest, 0, frame_id, false); } }, { key: "_gradientFilter", value: function _gradientFilter(streamId, x, y, width, height, sock, display, depth, frame_id) { throw new Error("Gradient filter not implemented"); } }, { key: "_readData", value: function _readData(sock) { if (this._len === 0) { if (sock.rQwait("TIGHT", 3)) { return null; } var _byte; _byte = sock.rQshift8(); this._len = _byte & 0x7f; if (_byte & 0x80) { _byte = sock.rQshift8(); this._len |= (_byte & 0x7f) << 7; if (_byte & 0x80) { _byte = sock.rQshift8(); this._len |= _byte << 14; } } } if (sock.rQwait("TIGHT", this._len)) { return null; } var data = sock.rQshiftBytes(this._len); this._len = 0; return data; } }, { key: "_getScratchBuffer", value: function _getScratchBuffer(size) { if (!this._scratchBuffer || this._scratchBuffer.length < size) { this._scratchBuffer = new Uint8Array(size); } return this._scratchBuffer; } }, { key: "_enableQOIWorkers", value: function _enableQOIWorkers() { var _this = this; var fullPath = window.location.pathname; var path = fullPath.substring(0, fullPath.lastIndexOf('/') + 1); var sabTest = typeof SharedArrayBuffer === "undefined" ? "undefined" : _typeof(SharedArrayBuffer); if (sabTest !== 'undefined') { this._enableQOI = true; if (window.navigator.hardwareConcurrency && window.navigator.hardwareConcurrency > 8) { this._threads = window.navigator.hardwareConcurrency; } else { this._threads = 8; } this._workerEnabled = false; this._workers = []; this._availableWorkers = []; this._sabs = []; this._sabsR = []; this._arrs = []; this._arrsR = []; this._qoiRects = []; this._rectQlooping = false; var _loop = function _loop(i) { _this._workers.push(new Worker("core/decoders/qoi/decoder.js")); _this._sabs.push(new SharedArrayBuffer(300000)); _this._sabsR.push(new SharedArrayBuffer(400000)); _this._arrs.push(new Uint8Array(_this._sabs[i])); _this._arrsR.push(new Uint8ClampedArray(_this._sabsR[i])); _this._workers[i].onmessage = function (evt) { _this._availableWorkers.push(i); switch (evt.data.result) { case 0: var data = new Uint8ClampedArray(evt.data.length); data.set(_this._arrsR[i].slice(0, evt.data.length)); var img = new ImageData(data, evt.data.img.width, evt.data.img.height, { colorSpace: evt.data.img.colorSpace }); _this._displayGlobal.blitQoi(evt.data.x, evt.data.y, evt.data.width, evt.data.height, img, 0, evt.data.frame_id, false); _this._processRectQ(); break; case 1: Log.Info("QOI Worker is now available."); break; case 2: Log.Info("Error on worker: " + evt.error); break; } }; }; for (var i = 0; i < this._threads; i++) { _loop(i); } for (var _i = 0; _i < this._threads; _i++) { this._workers[_i].postMessage({ path: path }); } } else { this._enableQOI = false; Log.Warn("Enabling QOI Failed, client not compatible."); } } }]); return TightDecoder; }(); exports["default"] = TightDecoder;