From 9e00f79d82eaf8a73d892ea41074dd4e7a7d9e02 Mon Sep 17 00:00:00 2001 From: Gerrit Brehmer Date: Sat, 7 Dec 2019 22:27:18 +0100 Subject: [PATCH] support rotation --- core/display.js | 138 ++++++++++++++++++++++++++++++++++++++++++++++-- core/rfb.js | 37 +++++++++++-- 2 files changed, 167 insertions(+), 8 deletions(-) diff --git a/core/display.js b/core/display.js index 097684db..de8e5a71 100644 --- a/core/display.js +++ b/core/display.js @@ -21,6 +21,7 @@ export default class Display { // the full frame buffer (logical canvas) size this._fb_width = 0; this._fb_height = 0; + this._rotate = ''; this._prevDrawStyle = ""; this._tile = null; @@ -80,6 +81,11 @@ export default class Display { // ===== PROPERTIES ===== + get rotate() { return this._rotate; } + set rotate(rotate) { + this._rotate = rotate; + } + get scale() { return this._scale; } set scale(scale) { this._rescale(scale); @@ -323,7 +329,32 @@ export default class Display { }); } else { this._setFillColor(color); - this._drawCtx.fillRect(x, y, width, height); + var x0; + var y0; + var w0; + var h0; + if (this._rotate === 'right') { + y0 = x; + x0 = this._fb_width - y - 1 - height; + w0 = height; + h0 = width; + } else if (this._rotate === 'left') { + y0 = this._fb_height - x - 1 - width; + x0 = y; + w0 = height; + h0 = width; + } else if (this._rotate === 'double') { + x0 = this._fb_width - x - 1 - width; + y0 = this._fb_height - y - 1 - height; + w0 = width; + h0 = height; + } else { + x0 = x; + y0 = y; + w0 = width; + h0 = height; + } + this._drawCtx.fillRect(x0, y0, w0, h0); this._damage(x, y, width, height); } } @@ -352,6 +383,26 @@ export default class Display { this._drawCtx.msImageSmoothingEnabled = false; this._drawCtx.imageSmoothingEnabled = false; + if (this._rotate === 'right') { + var a = old_x; + old_x = this._fb_width - old_y - 1 - h; + old_y = a; + a = new_x; + new_x = this._fb_width - new_y - 1; + new_y = a; + } else if (this._rotate === 'left') { + var a = old_y; + old_y = this._fb_height - old_x - 1 - w; + old_x = a; + var a = new_y; + new_y = this._fb_height - new_x - 1; + new_x = a; + } else if (this._rotate === 'double') { + old_y = this._fb_height - old_y - 1 - h; + old_x = this._fb_width - old_x - 1 - w; + new_y = this._fb_height - new_y - 1; + new_x = this._fb_width - new_x - 1; + } this._drawCtx.drawImage(this._backbuffer, old_x, old_y, w, h, new_x, new_y, w, h); @@ -416,7 +467,21 @@ export default class Display { // draw the current tile to the screen finishTile() { - this._drawCtx.putImageData(this._tile, this._tile_x, this._tile_y); + var x0 = this._tile_x; + var y0 = this._tile_y; + if (this._rotate === 'right') { + var a = x0; + x0 = this._fb_width - y0 - 1; + y0 = a; + } else if (this._rotate === 'left') { + var a = y0; + y0 = this._fb_height - x0 - 1; + x0 = a; + } else if (this._rotate === 'double') { + y0 = this._fb_height - y0 - 1; + x0 = this._fb_width - x0 - 1; + } + this._drawCtx.putImageData(this._tile, x0, y0); this._damage(this._tile_x, this._tile_y, this._tile.width, this._tile.height); } @@ -482,7 +547,21 @@ export default class Display { } drawImage(img, x, y) { - this._drawCtx.drawImage(img, x, y); + var x0 = x; + var y0 = y; + if (this._rotate === 'right') { + var a = x0; + x0 = this._fb_width - y0 - 1; + y0 = a; + } else if (this._rotate === 'left') { + var a = y0; + y0 = this._fb_height - x0 - 1; + x0 = a; + } else if (this._rotate === 'double') { + y0 = this._fb_height - y0 - 1; + x0 = this._fb_width - x0 - 1; + } + this._drawCtx.drawImage(img, x0, y0); this._damage(x, y, img.width, img.height); } @@ -552,13 +631,62 @@ export default class Display { _bgrxImageData(x, y, width, height, arr, offset) { const img = this._drawCtx.createImageData(width, height); const data = img.data; - for (let i = 0, j = offset; i < width * height * 4; i += 4, j += 4) { + + if (this._rotate === 'right') { + var j = offset; + for(var yv = 0; yv < height; yv++) { + for(var xv = 0; xv < width; xv++) { + var doff = ((xv * height) + (width - yv - 1)) * 4; + data[doff] = arr[j + 2]; + data[doff + 1] = arr[j + 1]; + data[doff + 2] = arr[j]; + data[doff + 3] = 255; // Alpha + j += 4; + } + } + } else if (this._rotate === 'left') { + var j = offset; + for(var yv = height - 1; yv >= 0; yv--) { + for(var xv = width - 1; xv >= 0; xv--) { + var doff = ((xv * height) + (width - yv - 1)) * 4; //((height - xv - 1) + (width * yv)) * 4; + data[doff] = arr[j + 2]; + data[doff + 1] = arr[j + 1]; + data[doff + 2] = arr[j]; + data[doff + 3] = 255; // Alpha + j += 4; + } + } + } else if (this._rotate === 'double') { + var length = width * height * 4; + for (var i = 4, j = offset; i <= length; i += 4, j += 4) { + data[length - i] = arr[j + 2]; + data[length - i + 1] = arr[j + 1]; + data[length - i + 2] = arr[j]; + data[length - i + 3] = 255; // Alpha + } + } else { + for (var i = 0, j = offset; i < width * height * 4; i += 4, j += 4) { data[i] = arr[j + 2]; data[i + 1] = arr[j + 1]; data[i + 2] = arr[j]; data[i + 3] = 255; // Alpha } - this._drawCtx.putImageData(img, x, y); + } + var x0 = x; + var y0 = y; + if (this._rotate === 'right') { + var a = x0; + x0 = this._fb_width - y0 - 1 - height; + y0 = a; + } else if (this._rotate === 'left') { + var a = y0; + y0 = this._fb_height - x0 - 1 - width; + x0 = a; + } else if (this._rotate === 'double') { + y0 = this._fb_height - y0 - 1 - height; + x0 = this._fb_width - x0 - 1 - width; + } + this._drawCtx.putImageData(img, x0, y0); this._damage(x, y, img.width, img.height); } diff --git a/core/rfb.js b/core/rfb.js index 6f02e4d2..bb57d955 100644 --- a/core/rfb.js +++ b/core/rfb.js @@ -65,6 +65,8 @@ export default class RFB extends EventTargetMixin { this._rfb_max_version = 3.8; this._rfb_tightvnc = false; this._rfb_xvp_ver = 0; + this._rotate = ''; + this._scale = false; this._fb_width = 0; this._fb_height = 0; @@ -276,6 +278,11 @@ export default class RFB extends EventTargetMixin { get touchButton() { return this._mouse.touchButton; } set touchButton(button) { this._mouse.touchButton = button; } + get rotate() { return this._rotate; } + set rotate(rotate) { this._rotate = rotate; } + get scale() { return this._scale; } + set scale(scale) { this._scale = scale; } + get clipViewport() { return this._clipViewport; } set clipViewport(viewport) { this._clipViewport = viewport; @@ -759,6 +766,7 @@ export default class RFB extends EventTargetMixin { // Send the button down event here, as the button up // event is sent at the end of this function. RFB.messages.pointerEvent(this._sock, + this._display, this._display.absX(x), this._display.absY(y), bmask); @@ -768,7 +776,7 @@ export default class RFB extends EventTargetMixin { if (this._viewOnly) { return; } // View only, skip mouse events if (this._rfb_connection_state !== 'connected') { return; } - RFB.messages.pointerEvent(this._sock, this._display.absX(x), this._display.absY(y), this._mouse_buttonMask); + RFB.messages.pointerEvent(this._sock, this._display, this._display.absX(x), this._display.absY(y), this._mouse_buttonMask); } _handleMouseMove(x, y) { @@ -791,7 +799,7 @@ export default class RFB extends EventTargetMixin { if (this._viewOnly) { return; } // View only, skip mouse events if (this._rfb_connection_state !== 'connected') { return; } - RFB.messages.pointerEvent(this._sock, this._display.absX(x), this._display.absY(y), this._mouse_buttonMask); + RFB.messages.pointerEvent(this._sock, this._display, this._display.absX(x), this._display.absY(y), this._mouse_buttonMask); } // Message Handlers @@ -1221,6 +1229,10 @@ export default class RFB extends EventTargetMixin { // we're past the point where we could backtrack, so it's safe to call this this._setDesktopName(name); this._resize(width, height); + this._display.rotate(this._rotate); + if (this._scale) { + this._display.scale(1.0); + } if (!this._viewOnly) { this._keyboard.grab(); } if (!this._viewOnly) { this._mouse.grab(); } @@ -1944,9 +1956,28 @@ RFB.messages = { sock.flush(); }, - pointerEvent(sock, x, y, mask) { + pointerEvent(sock, disp, x, y, mask) { const buff = sock._sQ; const offset = sock._sQlen; + x = x / disp._scale; + y = y / disp._scale; + switch(disp._rotate) { + case 'right': + var a = x; + x = y; + y = disp._fb_width - a - 1; + break; + case 'left': + var a = x; + x = disp._fb_height - y - 1; + y = a; + break; + case 'double': + x = disp._fb_width - x - 1; + y = disp._fb_height - y - 1; + break; + default: + } buff[offset] = 5; // msg-type