Separate out cursor handling

Make cursor handling more generic in preparation for generic handling
of corner cases.
This commit is contained in:
Pierre Ossman 2018-02-28 16:08:25 +01:00
parent e62b4ccb5e
commit b475eed5fa
4 changed files with 80 additions and 63 deletions

View File

@ -498,18 +498,6 @@ Display.prototype = {
this._damage(x, y, img.width, img.height);
},
changeCursor: function (pixels, mask, hotx, hoty, w, h) {
Display.changeCursor(this._target, pixels, mask, hotx, hoty, w, h);
},
defaultCursor: function () {
this._target.style.cursor = "default";
},
disableLocalCursor: function () {
this._target.style.cursor = "none";
},
autoscale: function (containerWidth, containerHeight) {
var vp = this._viewportLoc;
var targetAspectRatio = containerWidth / containerHeight;
@ -655,44 +643,3 @@ Display.prototype = {
}
},
};
// Class Methods
Display.changeCursor = function (target, pixels, mask, hotx, hoty, w, h) {
if ((w === 0) || (h === 0)) {
target.style.cursor = 'none';
return;
}
var cur = []
var y, x;
for (y = 0; y < h; y++) {
for (x = 0; x < w; x++) {
var idx = y * Math.ceil(w / 8) + Math.floor(x / 8);
var alpha = (mask[idx] << (x % 8)) & 0x80 ? 255 : 0;
idx = ((w * y) + x) * 4;
cur.push(pixels[idx + 2]); // red
cur.push(pixels[idx + 1]); // green
cur.push(pixels[idx]); // blue
cur.push(alpha); // alpha
}
}
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
canvas.width = w;
canvas.height = h;
var img;
if (SUPPORTS_IMAGEDATA_CONSTRUCTOR) {
img = new ImageData(new Uint8ClampedArray(cur), w, h);
} else {
img = ctx.createImageData(w, h);
img.data.set(new Uint8ClampedArray(cur));
}
ctx.clearRect(0, 0, w, h);
ctx.putImageData(img, 0, 0);
var url = canvas.toDataURL();
target.style.cursor = 'url(' + url + ')' + hotx + ' ' + hoty + ', default';
};

View File

@ -17,6 +17,7 @@ import EventTargetMixin from './util/eventtarget.js';
import Display from "./display.js";
import Keyboard from "./input/keyboard.js";
import Mouse from "./input/mouse.js";
import Cursor from "./util/cursor.js";
import Websock from "./websock.js";
import DES from "./des.js";
import KeyTable from "./input/keysym.js";
@ -164,6 +165,8 @@ export default function RFB(target, url, options) {
this._canvas.tabIndex = -1;
this._screen.appendChild(this._canvas);
this._cursor = new Cursor();
// populate encHandlers with bound versions
this._encHandlers[encodings.encodingRaw] = RFB.encodingHandlers.RAW.bind(this);
this._encHandlers[encodings.encodingCopyRect] = RFB.encodingHandlers.COPYRECT.bind(this);
@ -413,6 +416,8 @@ RFB.prototype = {
// Make our elements part of the page
this._target.appendChild(this._screen);
this._cursor.attach(this._canvas);
// Monitor size changes of the screen
// FIXME: Use ResizeObserver, or hidden overflow
window.addEventListener('resize', this._eventHandlers.windowResize);
@ -426,6 +431,7 @@ RFB.prototype = {
_disconnect: function () {
Log.Debug(">> RFB.disconnect");
this._cursor.detach();
this._canvas.removeEventListener("mousedown", this._eventHandlers.focusCanvas);
this._canvas.removeEventListener("touchstart", this._eventHandlers.focusCanvas);
window.removeEventListener('resize', this._eventHandlers.windowResize);
@ -1241,10 +1247,6 @@ RFB.prototype = {
this._timing.fbu_rt_start = (new Date()).getTime();
this._timing.pixels = 0;
// Cursor will be server side until the server decides to honor
// our request and send over the cursor image
this._display.disableLocalCursor();
this._updateConnectionState('connected');
return true;
},
@ -2522,7 +2524,7 @@ RFB.encodingHandlers = {
this._FBU.bytes = pixelslength + masklength;
if (this._sock.rQwait("cursor encoding", this._FBU.bytes)) { return false; }
this._display.changeCursor(this._sock.rQshiftBytes(pixelslength),
this._cursor.change(this._sock.rQshiftBytes(pixelslength),
this._sock.rQshiftBytes(masklength),
x, y, w, h);

71
core/util/cursor.js Normal file
View File

@ -0,0 +1,71 @@
/*
* noVNC: HTML5 VNC client
* Copyright 2018 Pierre Ossman for noVNC
* Licensed under MPL 2.0 or any later version (see LICENSE.txt)
*/
function Cursor(container) {
this._target = null;
}
Cursor.prototype = {
attach: function (target) {
if (this._target) {
this.detach();
}
this._target = target;
this.clear();
},
detach: function () {
this._target = null;
},
change: function (pixels, mask, hotx, hoty, w, h) {
if ((w === 0) || (h === 0)) {
this.clear();
return;
}
let cur = []
for (let y = 0; y < h; y++) {
for (let x = 0; x < w; x++) {
let idx = y * Math.ceil(w / 8) + Math.floor(x / 8);
let alpha = (mask[idx] << (x % 8)) & 0x80 ? 255 : 0;
idx = ((w * y) + x) * 4;
cur.push(pixels[idx + 2]); // red
cur.push(pixels[idx + 1]); // green
cur.push(pixels[idx]); // blue
cur.push(alpha); // alpha
}
}
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d');
canvas.width = w;
canvas.height = h;
let img;
try {
// IE doesn't support this
img = new ImageData(new Uint8ClampedArray(cur), w, h);
} catch (ex) {
img = ctx.createImageData(w, h);
img.data.set(new Uint8ClampedArray(cur));
}
ctx.clearRect(0, 0, w, h);
ctx.putImageData(img, 0, 0);
let url = this._canvas.toDataURL();
this._target.style.cursor = 'url(' + url + ')' + hotx + ' ' + hoty + ', default';
},
clear: function () {
this._target.style.cursor = 'none';
},
};
export default Cursor;

View File

@ -113,9 +113,6 @@ None
| blitRgbImage | (x, y, width, height, arr, offset, from_queue) | Blit RGB encoded image to display
| blitRgbxImage | (x, y, width, height, arr, offset, from_queue) | Blit RGBX encoded image to display
| drawImage | (img, x, y) | Draw image and track damage
| changeCursor | (pixels, mask, hotx, hoty, w, h) | Change cursor appearance
| defaultCursor | () | Restore default cursor appearance
| disableLocalCursor | () | Disable local (client-side) cursor
| autoscale | (containerWidth, containerHeight) | Scale the display
### 2.3.3 Callbacks