diff options
Diffstat (limited to 'core/decoders/hextile.js')
-rw-r--r-- | core/decoders/hextile.js | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/core/decoders/hextile.js b/core/decoders/hextile.js new file mode 100644 index 0000000..91141aa --- /dev/null +++ b/core/decoders/hextile.js @@ -0,0 +1,139 @@ +/* + * noVNC: HTML5 VNC client + * Copyright (C) 2012 Joel Martin + * Copyright (C) 2018 Samuel Mannehed for Cendio AB + * Copyright (C) 2018 Pierre Ossman for Cendio AB + * Licensed under MPL 2.0 (see LICENSE.txt) + * + * See README.md for usage and integration instructions. + * + */ + +import * as Log from '../util/logging.js'; + +export default class HextileDecoder { + constructor() { + this._tiles = 0; + this._lastsubencoding = 0; + } + + decodeRect(x, y, width, height, sock, display, depth) { + if (this._tiles === 0) { + this._tiles_x = Math.ceil(width / 16); + this._tiles_y = Math.ceil(height / 16); + this._total_tiles = this._tiles_x * this._tiles_y; + this._tiles = this._total_tiles; + } + + while (this._tiles > 0) { + let bytes = 1; + + if (sock.rQwait("HEXTILE", bytes)) { + return false; + } + + let rQ = sock.get_rQ(); + let rQi = sock.get_rQi(); + + let subencoding = rQ[rQi]; // Peek + if (subencoding > 30) { // Raw + throw Error("Illegal hextile subencoding (subencoding: " + + subencoding + ")"); + } + + const curr_tile = this._total_tiles - this._tiles; + const tile_x = curr_tile % this._tiles_x; + const tile_y = Math.floor(curr_tile / this._tiles_x); + const tx = x + tile_x * 16; + const ty = y + tile_y * 16; + const tw = Math.min(16, (x + width) - tx); + const th = Math.min(16, (y + height) - ty); + + // Figure out how much we are expecting + if (subencoding & 0x01) { // Raw + bytes += tw * th * 4; + } else { + if (subencoding & 0x02) { // Background + bytes += 4; + } + if (subencoding & 0x04) { // Foreground + bytes += 4; + } + if (subencoding & 0x08) { // AnySubrects + bytes++; // Since we aren't shifting it off + + if (sock.rQwait("HEXTILE", bytes)) { + return false; + } + + let subrects = rQ[rQi + bytes - 1]; // Peek + if (subencoding & 0x10) { // SubrectsColoured + bytes += subrects * (4 + 2); + } else { + bytes += subrects * 2; + } + } + } + + if (sock.rQwait("HEXTILE", bytes)) { + return false; + } + + // We know the encoding and have a whole tile + rQi++; + if (subencoding === 0) { + if (this._lastsubencoding & 0x01) { + // Weird: ignore blanks are RAW + Log.Debug(" Ignoring blank after RAW"); + } else { + display.fillRect(tx, ty, tw, th, this._background); + } + } else if (subencoding & 0x01) { // Raw + display.blitImage(tx, ty, tw, th, rQ, rQi); + rQi += bytes - 1; + } else { + if (subencoding & 0x02) { // Background + this._background = [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2], rQ[rQi + 3]]; + rQi += 4; + } + if (subencoding & 0x04) { // Foreground + this._foreground = [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2], rQ[rQi + 3]]; + rQi += 4; + } + + display.startTile(tx, ty, tw, th, this._background); + if (subencoding & 0x08) { // AnySubrects + let subrects = rQ[rQi]; + rQi++; + + for (let s = 0; s < subrects; s++) { + let color; + if (subencoding & 0x10) { // SubrectsColoured + color = [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2], rQ[rQi + 3]]; + rQi += 4; + } else { + color = this._foreground; + } + const xy = rQ[rQi]; + rQi++; + const sx = (xy >> 4); + const sy = (xy & 0x0f); + + const wh = rQ[rQi]; + rQi++; + const sw = (wh >> 4) + 1; + const sh = (wh & 0x0f) + 1; + + display.subTile(sx, sy, sw, sh, color); + } + } + display.finishTile(); + } + sock.set_rQi(rQi); + this._lastsubencoding = subencoding; + this._tiles--; + } + + return true; + } +} |