Add client-side pixel format conversion support
I (@kelleyk) have updated the original patch to be compatible with the double-buffering changes made upstream, repaired some test cases, and cleaned up the patch a little bit. The author of the original patch is @jimdigriz (Alexander Clouter).
This commit is contained in:
parent
41f476a863
commit
7541906688
|
|
@ -140,6 +140,7 @@ WebSockets to TCP socket proxy. There is a python proxy included
|
|||
* UI and Icons : Pierre Ossman, Chris Gordon
|
||||
* Original Logo : Michael Sersen
|
||||
* tight encoding : Michael Tinglof (Mercuri.ca)
|
||||
* pixel format conversion : [Alexander Clouter](http://www.digriz.org.uk/)
|
||||
|
||||
* Included libraries:
|
||||
* as3crypto : Henri Torgemane (code.google.com/p/as3crypto)
|
||||
|
|
|
|||
|
|
@ -197,7 +197,6 @@ var UI;
|
|||
UI.initSetting('host', window.location.hostname);
|
||||
UI.initSetting('port', port);
|
||||
UI.initSetting('encrypt', (window.location.protocol === "https:"));
|
||||
UI.initSetting('true_color', true);
|
||||
UI.initSetting('cursor', !Util.isTouchDevice);
|
||||
UI.initSetting('resize', 'off');
|
||||
UI.initSetting('shared', true);
|
||||
|
|
@ -451,7 +450,6 @@ var UI;
|
|||
updateVisualState: function() {
|
||||
//Util.Debug(">> updateVisualState");
|
||||
document.getElementById('noVNC_setting_encrypt').disabled = UI.connected;
|
||||
document.getElementById('noVNC_setting_true_color').disabled = UI.connected;
|
||||
if (Util.browserSupportsCursorURIs()) {
|
||||
document.getElementById('noVNC_setting_cursor').disabled = UI.connected;
|
||||
} else {
|
||||
|
|
@ -825,7 +823,6 @@ var UI;
|
|||
settingsApply: function() {
|
||||
//Util.Debug(">> settingsApply");
|
||||
UI.saveSetting('encrypt');
|
||||
UI.saveSetting('true_color');
|
||||
if (Util.browserSupportsCursorURIs()) {
|
||||
UI.saveSetting('cursor');
|
||||
}
|
||||
|
|
@ -876,7 +873,6 @@ var UI;
|
|||
UI.openControlbar();
|
||||
|
||||
UI.updateSetting('encrypt');
|
||||
UI.updateSetting('true_color');
|
||||
if (Util.browserSupportsCursorURIs()) {
|
||||
UI.updateSetting('cursor');
|
||||
} else {
|
||||
|
|
@ -1060,7 +1056,6 @@ var UI;
|
|||
UI.closeConnectPanel();
|
||||
|
||||
UI.rfb.set_encrypt(UI.getSetting('encrypt'));
|
||||
UI.rfb.set_true_color(UI.getSetting('true_color'));
|
||||
UI.rfb.set_local_cursor(UI.getSetting('cursor'));
|
||||
UI.rfb.set_shared(UI.getSetting('shared'));
|
||||
UI.rfb.set_view_only(UI.getSetting('view_only'));
|
||||
|
|
|
|||
|
|
@ -456,7 +456,12 @@
|
|||
// else: No-op -- already done by setSubTile
|
||||
},
|
||||
|
||||
blitImage: function (x, y, width, height, arr, offset, from_queue) {
|
||||
// N.B.: You *cannot* call this during a test in RGBX-order true-color
|
||||
// mode, or PhantomJS dies with a Uint8ClampeddArray error.
|
||||
// N.B.: If you know that your data will always be RGB (that is, isRgb==true
|
||||
// and this._true_color==true), then you should be calling blitRgbxImage()
|
||||
// instead of blitImage() to avoid the extra branches.
|
||||
blitImage: function (x, y, width, height, arr, offset, isRgb, from_queue) {
|
||||
if (this._renderQ.length !== 0 && !from_queue) {
|
||||
// NB(directxman12): it's technically more performant here to use preallocated arrays,
|
||||
// but it's a lot of extra work for not a lot of payoff -- if we're using the render queue,
|
||||
|
|
@ -470,9 +475,14 @@
|
|||
'y': y,
|
||||
'width': width,
|
||||
'height': height,
|
||||
'isRgb': isRgb,
|
||||
});
|
||||
} else if (this._true_color) {
|
||||
this._bgrxImageData(x, y, width, height, arr, offset);
|
||||
if (isRgb) {
|
||||
this._rgbxImageData(x, y, width, height, arr, offset);
|
||||
} else {
|
||||
this._bgrxImageData(x, y, width, height, arr, offset);
|
||||
}
|
||||
} else {
|
||||
this._cmapImageData(x, y, width, height, arr, offset);
|
||||
}
|
||||
|
|
@ -501,6 +511,8 @@
|
|||
}
|
||||
},
|
||||
|
||||
// this is different from the above in that it assumes the data is always rgbx format, instead
|
||||
// of dealing with the possibility of cmap data
|
||||
blitRgbxImage: function (x, y, width, height, arr, offset, from_queue) {
|
||||
if (this._renderQ.length !== 0 && !from_queue) {
|
||||
// NB(directxman12): it's technically more performant here to use preallocated arrays,
|
||||
|
|
@ -716,10 +728,7 @@
|
|||
this.fillRect(a.x, a.y, a.width, a.height, a.color, true);
|
||||
break;
|
||||
case 'blit':
|
||||
this.blitImage(a.x, a.y, a.width, a.height, a.data, 0, true);
|
||||
break;
|
||||
case 'blitRgb':
|
||||
this.blitRgbImage(a.x, a.y, a.width, a.height, a.data, 0, true);
|
||||
this.blitImage(a.x, a.y, a.width, a.height, a.data, 0, a.rgb, true);
|
||||
break;
|
||||
case 'blitRgbx':
|
||||
this.blitRgbxImage(a.x, a.y, a.width, a.height, a.data, 0, true);
|
||||
|
|
|
|||
338
core/rfb.js
338
core/rfb.js
|
|
@ -88,6 +88,8 @@
|
|||
this._supportsContinuousUpdates = false;
|
||||
this._enabledContinuousUpdates = false;
|
||||
|
||||
this._convert_color = false;
|
||||
|
||||
// Frame buffer update state
|
||||
this._FBU = {
|
||||
rects: 0,
|
||||
|
|
@ -105,14 +107,14 @@
|
|||
zlib: [] // TIGHT zlib streams
|
||||
};
|
||||
|
||||
this._fb_Bpp = 4;
|
||||
this._fb_depth = 3;
|
||||
this._pixelFormat = {};
|
||||
this._fb_width = 0;
|
||||
this._fb_height = 0;
|
||||
this._fb_name = "";
|
||||
|
||||
this._destBuff = null;
|
||||
this._paletteBuff = new Uint8Array(1024); // 256 * 4 (max palette size * max bytes-per-pixel)
|
||||
this._paletteRawBuff = new Uint8Array(1024); // 256 * 4 (max palette size * max bytes-per-pixel)
|
||||
this._paletteConvertedBuff = new Uint8Array(1024); // 256 * 4 (max palette size * rgbx bytes-per-pixel)
|
||||
|
||||
this._rre_chunk_sz = 100;
|
||||
|
||||
|
|
@ -148,7 +150,6 @@
|
|||
'target': 'null', // VNC display rendering Canvas object
|
||||
'focusContainer': document, // DOM element that captures keyboard input
|
||||
'encrypt': false, // Use TLS/SSL/wss encryption
|
||||
'true_color': true, // Request true color pixel data
|
||||
'local_cursor': false, // Request locally rendered cursor
|
||||
'shared': true, // Request shared mode
|
||||
'view_only': false, // Disable client mouse/keyboard
|
||||
|
|
@ -414,6 +415,7 @@
|
|||
this._mouse_buttonMask = 0;
|
||||
this._mouse_arr = [];
|
||||
this._rfb_tightvnc = false;
|
||||
this._convert_color = false;
|
||||
|
||||
// Clear the per connection encoding stats
|
||||
var i;
|
||||
|
|
@ -1021,17 +1023,17 @@
|
|||
this._destBuff = new Uint8Array(this._fb_width * this._fb_height * 4);
|
||||
|
||||
/* PIXEL_FORMAT */
|
||||
var bpp = this._sock.rQshift8();
|
||||
var depth = this._sock.rQshift8();
|
||||
var big_endian = this._sock.rQshift8();
|
||||
var true_color = this._sock.rQshift8();
|
||||
this._pixelFormat.bpp = this._sock.rQshift8();
|
||||
this._pixelFormat.depth = this._sock.rQshift8();
|
||||
this._pixelFormat.big_endian = (this._sock.rQshift8() !== 0) ? true : false;
|
||||
this._pixelFormat.true_color = (this._sock.rQshift8() !== 0) ? true : false;
|
||||
|
||||
var red_max = this._sock.rQshift16();
|
||||
var green_max = this._sock.rQshift16();
|
||||
var blue_max = this._sock.rQshift16();
|
||||
var red_shift = this._sock.rQshift8();
|
||||
var green_shift = this._sock.rQshift8();
|
||||
var blue_shift = this._sock.rQshift8();
|
||||
this._pixelFormat.red_max = this._sock.rQshift16();
|
||||
this._pixelFormat.green_max = this._sock.rQshift16();
|
||||
this._pixelFormat.blue_max = this._sock.rQshift16();
|
||||
this._pixelFormat.red_shift = this._sock.rQshift8();
|
||||
this._pixelFormat.green_shift = this._sock.rQshift8();
|
||||
this._pixelFormat.blue_shift = this._sock.rQshift8();
|
||||
this._sock.rQskipBytes(3); // padding
|
||||
|
||||
// NB(directxman12): we don't want to call any callbacks or print messages until
|
||||
|
|
@ -1069,53 +1071,84 @@
|
|||
// NB(directxman12): these are down here so that we don't run them multiple times
|
||||
// if we backtrack
|
||||
Util.Info("Screen: " + this._fb_width + "x" + this._fb_height +
|
||||
", bpp: " + bpp + ", depth: " + depth +
|
||||
", big_endian: " + big_endian +
|
||||
", true_color: " + true_color +
|
||||
", red_max: " + red_max +
|
||||
", green_max: " + green_max +
|
||||
", blue_max: " + blue_max +
|
||||
", red_shift: " + red_shift +
|
||||
", green_shift: " + green_shift +
|
||||
", blue_shift: " + blue_shift);
|
||||
|
||||
if (big_endian !== 0) {
|
||||
Util.Warn("Server native endian is not little endian");
|
||||
}
|
||||
|
||||
if (red_shift !== 16) {
|
||||
Util.Warn("Server native red-shift is not 16");
|
||||
}
|
||||
|
||||
if (blue_shift !== 0) {
|
||||
Util.Warn("Server native blue-shift is not 0");
|
||||
}
|
||||
", bpp: " + this._pixelFormat.bpp + ", depth: " + this._pixelFormat.depth +
|
||||
", big_endian: " + this._pixelFormat.big_endian +
|
||||
", true_color: " + this._pixelFormat.true_color +
|
||||
", red_max: " + this._pixelFormat.red_max +
|
||||
", green_max: " + this._pixelFormat.green_max +
|
||||
", blue_max: " + this._pixelFormat.blue_max +
|
||||
", red_shift: " + this._pixelFormat.red_shift +
|
||||
", green_shift: " + this._pixelFormat.green_shift +
|
||||
", blue_shift: " + this._pixelFormat.blue_shift);
|
||||
|
||||
// we're past the point where we could backtrack, so it's safe to call this
|
||||
this._onDesktopName(this, this._fb_name);
|
||||
|
||||
if (this._true_color && this._fb_name === "Intel(r) AMT KVM") {
|
||||
Util.Warn("Intel AMT KVM only supports 8/16 bit depths. Disabling true color");
|
||||
this._true_color = false;
|
||||
if (this._fb_name === "Intel(r) AMT KVM") {
|
||||
Util.Warn("Intel AMT KVM only supports 8/16 bit depths, using server pixel format");
|
||||
this._convert_color = true;
|
||||
}
|
||||
|
||||
this._display.set_true_color(this._true_color);
|
||||
if (this._convert_color)
|
||||
this._display.set_true_color(this._pixelFormat.true_color);
|
||||
this._display.resize(this._fb_width, this._fb_height);
|
||||
this._onFBResize(this, this._fb_width, this._fb_height);
|
||||
|
||||
if (!this._view_only) { this._keyboard.grab(); }
|
||||
if (!this._view_only) { this._mouse.grab(); }
|
||||
|
||||
if (this._true_color) {
|
||||
this._fb_Bpp = 4;
|
||||
this._fb_depth = 3;
|
||||
// only send if not native, and we think the server will honor the conversion
|
||||
if (!this._convert_color) {
|
||||
if (this._pixelFormat.big_endian !== false ||
|
||||
this._pixelFormat.red_max !== 255 ||
|
||||
this._pixelFormat.green_max !== 255 ||
|
||||
this._pixelFormat.blue_max !== 255 ||
|
||||
this._pixelFormat.red_shift !== 16 ||
|
||||
this._pixelFormat.green_shift !== 8 ||
|
||||
this._pixelFormat.blue_shift !== 0 ||
|
||||
!(this._pixelFormat.bpp === 32 &&
|
||||
this._pixelFormat.depth === 24 &&
|
||||
this._pixelFormat.true_color === true) ||
|
||||
!(this._pixelFormat.bpp === 8 &&
|
||||
this._pixelFormat.depth === 8 &&
|
||||
this._pixelFormat.true_color === false)) {
|
||||
this._pixelFormat.big_endian = false;
|
||||
this._pixelFormat.red_max = 255;
|
||||
this._pixelFormat.green_max = 255;
|
||||
this._pixelFormat.blue_max = 255;
|
||||
this._pixelFormat.red_shift = 16;
|
||||
this._pixelFormat.green_shift = 8;
|
||||
this._pixelFormat.blue_shift = 0;
|
||||
if (this._pixelFormat.true_color) {
|
||||
this._pixelFormat.bpp = 32;
|
||||
this._pixelFormat.depth = 24;
|
||||
} else {
|
||||
this._pixelFormat.bpp = 8;
|
||||
this._pixelFormat.depth = 8;
|
||||
}
|
||||
RFB.messages.pixelFormat(this._sock, this._pixelFormat);
|
||||
} else {
|
||||
this._fb_Bpp = 1;
|
||||
this._fb_depth = 1;
|
||||
Util.Warn("Server pixel format matches our preferred native, disabling color conversion");
|
||||
this._convert_color = false;
|
||||
}
|
||||
}
|
||||
|
||||
RFB.messages.pixelFormat(this._sock, this._fb_Bpp, this._fb_depth, this._true_color);
|
||||
RFB.messages.clientEncodings(this._sock, this._encodings, this._local_cursor, this._true_color);
|
||||
this._pixelFormat.Bpp = this._pixelFormat.bpp / 8;
|
||||
this._pixelFormat.Bdepth = Math.ceil(this._pixelFormat.depth / 8);
|
||||
|
||||
if (this._pixelFormat.bpp < this._pixelFormat.depth) {
|
||||
return this._fail('server claims greater depth than bpp');
|
||||
}
|
||||
|
||||
var max_depth = Math.ceil(Math.log(this._pixelFormat.red_max)/Math.LN2) +
|
||||
Math.ceil(Math.log(this._pixelFormat.green_max)/Math.LN2) +
|
||||
Math.ceil(Math.log(this._pixelFormat.blue_max)/Math.LN2);
|
||||
|
||||
if (this._pixelFormat.true_color && this._pixelFormat.depth > max_depth) {
|
||||
return this._fail('server claims greater depth than sum of RGB maximums');
|
||||
}
|
||||
|
||||
RFB.messages.clientEncodings(this._sock, this._encodings, this._local_cursor, this._pixelFormat.true_color);
|
||||
RFB.messages.fbUpdateRequest(this._sock, false, 0, 0, this._fb_width, this._fb_height);
|
||||
|
||||
this._timing.fbu_rt_start = (new Date()).getTime();
|
||||
|
|
@ -1437,14 +1470,97 @@
|
|||
|
||||
RFB.messages.enableContinuousUpdates(this._sock, true, 0, 0,
|
||||
this._fb_width, this._fb_height);
|
||||
}
|
||||
},
|
||||
|
||||
// like _convert_color, but always outputs bgr, and for only one pixel
|
||||
_convert_one_color: function (arr, offset, Bpp) {
|
||||
if (Bpp === undefined) {
|
||||
Bpp = this._pixelFormat.Bpp;
|
||||
}
|
||||
|
||||
if (offset === undefined) {
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
if (!this._convert_color ||
|
||||
// HACK? Xtightvnc needs this and I have no idea why
|
||||
(this._FBU.encoding === 0x07 && this._pixelFormat.depth === 24)) {
|
||||
if (Bpp === 4) {
|
||||
return [arr[offset + 0], arr[offset + 1], arr[offset + 2], arr[offset + 3]];
|
||||
} else if (Bpp === 3) {
|
||||
return [arr[offset + 2], arr[offset + 1], arr[offset + 0]];
|
||||
} else {
|
||||
Util.Error('convert color disabled, but Bpp is not 3 or 4!');
|
||||
}
|
||||
}
|
||||
|
||||
var bgr = new Array(3);
|
||||
|
||||
var redMult = 256/(this._pixelFormat.red_max + 1);
|
||||
var greenMult = 256/(this._pixelFormat.red_max + 1);
|
||||
var blueMult = 256/(this._pixelFormat.blue_max + 1);
|
||||
|
||||
var pix = 0;
|
||||
for (var k = 0; k < Bpp; k++) {
|
||||
if (this._pixelFormat.big_endian) {
|
||||
pix = (pix << 8) | arr[k + offset];
|
||||
} else {
|
||||
pix = (arr[k + offset] << (k*8)) | pix;
|
||||
}
|
||||
}
|
||||
|
||||
bgr[2] = ((pix >>> this._pixelFormat.red_shift) & this._pixelFormat.red_max) * redMult;
|
||||
bgr[1] = ((pix >>> this._pixelFormat.green_shift) & this._pixelFormat.green_max) * greenMult;
|
||||
bgr[0] = ((pix >>> this._pixelFormat.blue_shift) & this._pixelFormat.blue_max) * blueMult;
|
||||
|
||||
return bgr;
|
||||
},
|
||||
|
||||
// takes a byte stream in the pixel format, and outputs rgbx into the output buffer
|
||||
_convert_color_and_copy: function (out_arr, in_arr, Bpp) {
|
||||
if (Bpp === undefined) {
|
||||
Bpp = this._pixelFormat.Bpp;
|
||||
}
|
||||
|
||||
if (!this._convert_color ||
|
||||
// HACK? Xtightvnc needs this and I have no idea why
|
||||
(this._FBU.encoding === 0x07 && this._pixelFormat.depth === 24)) {
|
||||
if (Bpp !== 4 && Bpp !== 3) {
|
||||
Util.Error('convert color disabled, but Bpp is not 3 or 4!');
|
||||
} else {
|
||||
out_arr.set(in_arr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var redMult = 256/(this._pixelFormat.red_max + 1);
|
||||
var greenMult = 256/(this._pixelFormat.red_max + 1);
|
||||
var blueMult = 256/(this._pixelFormat.blue_max + 1);
|
||||
|
||||
for (var i = 0, j = 0; i < in_arr.length; i += Bpp, j += 4) {
|
||||
var pix = 0;
|
||||
|
||||
for (var k = 0; k < Bpp; k++) {
|
||||
if (this._pixelFormat.big_endian) {
|
||||
pix = (pix << 8) | in_arr[i + k];
|
||||
} else {
|
||||
pix = (in_arr[i + k] << (k*8)) | pix;
|
||||
}
|
||||
}
|
||||
|
||||
out_arr[j] = ((pix >>> this._pixelFormat.red_shift) & this._pixelFormat.red_max) * redMult;
|
||||
out_arr[j + 1] = ((pix >>> this._pixelFormat.green_shift) & this._pixelFormat.green_max) * greenMult;
|
||||
out_arr[j + 2] = ((pix >>> this._pixelFormat.blue_shift) & this._pixelFormat.blue_max) * blueMult;
|
||||
out_arr[j + 3] = 255;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
Util.make_properties(RFB, [
|
||||
['target', 'wo', 'dom'], // VNC display rendering Canvas object
|
||||
['focusContainer', 'wo', 'dom'], // DOM element that captures keyboard input
|
||||
['encrypt', 'rw', 'bool'], // Use TLS/SSL/wss encryption
|
||||
['true_color', 'rw', 'bool'], // Request true color pixel data
|
||||
['convert_color', 'rw', 'bool'], // Client will not honor request for native color
|
||||
['local_cursor', 'rw', 'bool'], // Request locally rendered cursor
|
||||
['shared', 'rw', 'bool'], // Request shared mode
|
||||
['view_only', 'rw', 'bool'], // Disable client mouse/keyboard
|
||||
|
|
@ -1670,7 +1786,7 @@
|
|||
sock.flush();
|
||||
},
|
||||
|
||||
pixelFormat: function (sock, bpp, depth, true_color) {
|
||||
pixelFormat: function (sock, pf) {
|
||||
var buff = sock._sQ;
|
||||
var offset = sock._sQlen;
|
||||
|
||||
|
|
@ -1680,23 +1796,23 @@
|
|||
buff[offset + 2] = 0; // padding
|
||||
buff[offset + 3] = 0; // padding
|
||||
|
||||
buff[offset + 4] = bpp * 8; // bits-per-pixel
|
||||
buff[offset + 5] = depth * 8; // depth
|
||||
buff[offset + 6] = 0; // little-endian
|
||||
buff[offset + 7] = true_color ? 1 : 0; // true-color
|
||||
buff[offset + 4] = pf.bpp; // bits-per-pixel
|
||||
buff[offset + 5] = pf.depth; // depth
|
||||
buff[offset + 6] = pf.big_endian ? 1 : 0; // big-endian
|
||||
buff[offset + 7] = pf.true_color ? 1 : 0; // true-color
|
||||
|
||||
buff[offset + 8] = 0; // red-max
|
||||
buff[offset + 9] = 255; // red-max
|
||||
buff[offset + 8] = (pf.red_max >> 8) & 0xFF; // red-max
|
||||
buff[offset + 9] = pf.red_max & 0xFF; // red-max
|
||||
|
||||
buff[offset + 10] = 0; // green-max
|
||||
buff[offset + 11] = 255; // green-max
|
||||
buff[offset + 10] = (pf.green_max >> 8) & 0xFF; // green-max
|
||||
buff[offset + 11] = pf.green_max & 0xFF; // green-max
|
||||
|
||||
buff[offset + 12] = 0; // blue-max
|
||||
buff[offset + 13] = 255; // blue-max
|
||||
buff[offset + 12] = (pf.blue_max >> 8) & 0xFF; // blue-max
|
||||
buff[offset + 13] = (pf.blue_max) & 0xFF; // blue-max
|
||||
|
||||
buff[offset + 14] = 16; // red-shift
|
||||
buff[offset + 15] = 8; // green-shift
|
||||
buff[offset + 16] = 0; // blue-shift
|
||||
buff[offset + 14] = pf.red_shift; // red-shift
|
||||
buff[offset + 15] = pf.green_shift; // green-shift
|
||||
buff[offset + 16] = pf.blue_shift; // blue-shift
|
||||
|
||||
buff[offset + 17] = 0; // padding
|
||||
buff[offset + 18] = 0; // padding
|
||||
|
|
@ -1782,19 +1898,21 @@
|
|||
this._FBU.lines = this._FBU.height;
|
||||
}
|
||||
|
||||
this._FBU.bytes = this._FBU.width * this._fb_Bpp; // at least a line
|
||||
this._FBU.bytes = this._FBU.width * this._pixelFormat.Bpp; // at least a line
|
||||
if (this._sock.rQwait("RAW", this._FBU.bytes)) { return false; }
|
||||
var cur_y = this._FBU.y + (this._FBU.height - this._FBU.lines);
|
||||
var curr_height = Math.min(this._FBU.lines,
|
||||
Math.floor(this._sock.rQlen() / (this._FBU.width * this._fb_Bpp)));
|
||||
this._display.blitImage(this._FBU.x, cur_y, this._FBU.width,
|
||||
curr_height, this._sock.get_rQ(),
|
||||
this._sock.get_rQi());
|
||||
this._sock.rQskipBytes(this._FBU.width * curr_height * this._fb_Bpp);
|
||||
Math.floor(this._sock.rQlen() / (this._FBU.width * this._pixelFormat.Bpp)));
|
||||
|
||||
// NB(directxman12): renderQ_push automatically clones the data is we have to push
|
||||
// to the render queue
|
||||
this._convert_color_and_copy(this._destBuff, this._sock.rQshiftBytes(curr_height * this._FBU.width * this._pixelFormat.Bpp));
|
||||
this._display.blitImage(this._FBU.x, cur_y, this._FBU.width, curr_height, this._destBuff, 0, this._convert_color || this._pixelFormat.Bpp === 3, false);
|
||||
|
||||
this._FBU.lines -= curr_height;
|
||||
|
||||
if (this._FBU.lines > 0) {
|
||||
this._FBU.bytes = this._FBU.width * this._fb_Bpp; // At least another line
|
||||
this._FBU.bytes = this._FBU.width * this._pixelFormat.Bpp; // At least another line
|
||||
} else {
|
||||
this._FBU.rects--;
|
||||
this._FBU.bytes = 0;
|
||||
|
|
@ -1818,15 +1936,15 @@
|
|||
RRE: function () {
|
||||
var color;
|
||||
if (this._FBU.subrects === 0) {
|
||||
this._FBU.bytes = 4 + this._fb_Bpp;
|
||||
if (this._sock.rQwait("RRE", 4 + this._fb_Bpp)) { return false; }
|
||||
this._FBU.bytes = 4 + this._pixelFormat.Bpp;
|
||||
if (this._sock.rQwait("RRE", 4 + this._pixelFormat.Bpp)) { return false; }
|
||||
this._FBU.subrects = this._sock.rQshift32();
|
||||
color = this._sock.rQshiftBytes(this._fb_Bpp); // Background
|
||||
color = this._convert_one_color(this._sock.rQshiftBytes(this._pixelFormat.Bpp)); // Background
|
||||
this._display.fillRect(this._FBU.x, this._FBU.y, this._FBU.width, this._FBU.height, color);
|
||||
}
|
||||
|
||||
while (this._FBU.subrects > 0 && this._sock.rQlen() >= (this._fb_Bpp + 8)) {
|
||||
color = this._sock.rQshiftBytes(this._fb_Bpp);
|
||||
while (this._FBU.subrects > 0 && this._sock.rQlen() >= (this._pixelFormat.Bpp + 8)) {
|
||||
color = this._convert_one_color(this._sock.rQshiftBytes(this._pixelFormat.Bpp));
|
||||
var x = this._sock.rQshift16();
|
||||
var y = this._sock.rQshift16();
|
||||
var width = this._sock.rQshift16();
|
||||
|
|
@ -1837,7 +1955,7 @@
|
|||
|
||||
if (this._FBU.subrects > 0) {
|
||||
var chunk = Math.min(this._rre_chunk_sz, this._FBU.subrects);
|
||||
this._FBU.bytes = (this._fb_Bpp + 8) * chunk;
|
||||
this._FBU.bytes = (this._pixelFormat.Bpp + 8) * chunk;
|
||||
} else {
|
||||
this._FBU.rects--;
|
||||
this._FBU.bytes = 0;
|
||||
|
|
@ -1878,20 +1996,20 @@
|
|||
|
||||
// Figure out how much we are expecting
|
||||
if (subencoding & 0x01) { // Raw
|
||||
this._FBU.bytes += w * h * this._fb_Bpp;
|
||||
this._FBU.bytes += w * h * this._pixelFormat.Bpp;
|
||||
} else {
|
||||
if (subencoding & 0x02) { // Background
|
||||
this._FBU.bytes += this._fb_Bpp;
|
||||
this._FBU.bytes += this._pixelFormat.Bpp;
|
||||
}
|
||||
if (subencoding & 0x04) { // Foreground
|
||||
this._FBU.bytes += this._fb_Bpp;
|
||||
this._FBU.bytes += this._pixelFormat.Bpp;
|
||||
}
|
||||
if (subencoding & 0x08) { // AnySubrects
|
||||
this._FBU.bytes++; // Since we aren't shifting it off
|
||||
if (this._sock.rQwait("hextile subrects header", this._FBU.bytes)) { return false; }
|
||||
subrects = rQ[rQi + this._FBU.bytes - 1]; // Peek
|
||||
if (subencoding & 0x10) { // SubrectsColoured
|
||||
this._FBU.bytes += subrects * (this._fb_Bpp + 2);
|
||||
this._FBU.bytes += subrects * (this._pixelFormat.Bpp + 2);
|
||||
} else {
|
||||
this._FBU.bytes += subrects * 2;
|
||||
}
|
||||
|
|
@ -1911,26 +2029,19 @@
|
|||
this._display.fillRect(x, y, w, h, this._FBU.background);
|
||||
}
|
||||
} else if (this._FBU.subencoding & 0x01) { // Raw
|
||||
this._display.blitImage(x, y, w, h, rQ, rQi);
|
||||
// NB(directxman12): renderQ_push automatically clones the data is we have to push
|
||||
// to the render queue
|
||||
this._convert_color_and_copy(this._destBuff, new Uint8Array(rQ.buffer, rQi, this._FBU.bytes - 1));
|
||||
this._display.blitImage(x, y, w, h, this._destBuff, 0, this._convert_color || this._pixelFormat.Bpp === 3, false);
|
||||
rQi += this._FBU.bytes - 1;
|
||||
} else {
|
||||
if (this._FBU.subencoding & 0x02) { // Background
|
||||
if (this._fb_Bpp == 1) {
|
||||
this._FBU.background = rQ[rQi];
|
||||
} else {
|
||||
// fb_Bpp is 4
|
||||
this._FBU.background = [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2], rQ[rQi + 3]];
|
||||
}
|
||||
rQi += this._fb_Bpp;
|
||||
this._FBU.background = this._convert_one_color(rQ, rQi);
|
||||
rQi += this._pixelFormat.Bpp;
|
||||
}
|
||||
if (this._FBU.subencoding & 0x04) { // Foreground
|
||||
if (this._fb_Bpp == 1) {
|
||||
this._FBU.foreground = rQ[rQi];
|
||||
} else {
|
||||
// this._fb_Bpp is 4
|
||||
this._FBU.foreground = [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2], rQ[rQi + 3]];
|
||||
}
|
||||
rQi += this._fb_Bpp;
|
||||
this._FBU.foreground = this._convert_one_color(rQ, rQi);
|
||||
rQi += this._pixelFormat.Bpp;
|
||||
}
|
||||
|
||||
this._display.startTile(x, y, w, h, this._FBU.background);
|
||||
|
|
@ -1941,13 +2052,8 @@
|
|||
for (var s = 0; s < subrects; s++) {
|
||||
var color;
|
||||
if (this._FBU.subencoding & 0x10) { // SubrectsColoured
|
||||
if (this._fb_Bpp === 1) {
|
||||
color = rQ[rQi];
|
||||
} else {
|
||||
// _fb_Bpp is 4
|
||||
color = [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2], rQ[rQi + 3]];
|
||||
}
|
||||
rQi += this._fb_Bpp;
|
||||
color = this._convert_one_color(rQ, rQi);
|
||||
rQi += this._pixelFormat.Bpp;
|
||||
} else {
|
||||
color = this._FBU.foreground;
|
||||
}
|
||||
|
|
@ -1994,10 +2100,8 @@
|
|||
},
|
||||
|
||||
display_tight: function (isTightPNG) {
|
||||
if (this._fb_depth === 1) {
|
||||
this._fail("Internal error",
|
||||
"Tight protocol handler only implements " +
|
||||
"true color mode");
|
||||
if (this._pixelFormat.Bdepth === 1) {
|
||||
this._fail("Internal error", "Tight protocol handler only implements true color mode");
|
||||
}
|
||||
|
||||
this._FBU.bytes = 1; // compression-control byte
|
||||
|
|
@ -2115,7 +2219,7 @@
|
|||
|
||||
var handlePalette = function () {
|
||||
var numColors = rQ[rQi + 2] + 1;
|
||||
var paletteSize = numColors * this._fb_depth;
|
||||
var paletteSize = numColors * this._pixelFormat.Bdepth;
|
||||
this._FBU.bytes += paletteSize;
|
||||
if (this._sock.rQwait("TIGHT palette " + cmode, this._FBU.bytes)) { return false; }
|
||||
|
||||
|
|
@ -2149,8 +2253,8 @@
|
|||
|
||||
// Shift ctl, filter id, num colors, palette entries, and clength off
|
||||
this._sock.rQskipBytes(3);
|
||||
//var palette = this._sock.rQshiftBytes(paletteSize);
|
||||
this._sock.rQshiftTo(this._paletteBuff, paletteSize);
|
||||
this._sock.rQshiftTo(this._paletteRawBuff, paletteSize);
|
||||
this._convert_color_and_copy(this._paletteConvertedBuff, this._paletteRawBuff, this._pixelFormat.Bdepth);
|
||||
this._sock.rQskipBytes(cl_header);
|
||||
|
||||
if (raw) {
|
||||
|
|
@ -2162,10 +2266,10 @@
|
|||
// Convert indexed (palette based) image data to RGB
|
||||
var rgbx;
|
||||
if (numColors == 2) {
|
||||
rgbx = indexedToRGBX2Color(data, this._paletteBuff, this._FBU.width, this._FBU.height);
|
||||
rgbx = indexedToRGBX2Color(data, this._paletteConvertedBuff, this._FBU.width, this._FBU.height);
|
||||
this._display.blitRgbxImage(this._FBU.x, this._FBU.y, this._FBU.width, this._FBU.height, rgbx, 0, false);
|
||||
} else {
|
||||
rgbx = indexedToRGBX(data, this._paletteBuff, this._FBU.width, this._FBU.height);
|
||||
rgbx = indexedToRGBX(data, this._paletteConvertedBuff, this._FBU.width, this._FBU.height);
|
||||
this._display.blitRgbxImage(this._FBU.x, this._FBU.y, this._FBU.width, this._FBU.height, rgbx, 0, false);
|
||||
}
|
||||
|
||||
|
|
@ -2175,7 +2279,7 @@
|
|||
|
||||
var handleCopy = function () {
|
||||
var raw = false;
|
||||
var uncompressedSize = this._FBU.width * this._FBU.height * this._fb_depth;
|
||||
var uncompressedSize = this._FBU.width * this._FBU.height * this._pixelFormat.Bdepth;
|
||||
if (uncompressedSize < 12) {
|
||||
raw = true;
|
||||
cl_header = 0;
|
||||
|
|
@ -2208,7 +2312,8 @@
|
|||
data = decompress(this._sock.rQshiftBytes(cl_data), uncompressedSize);
|
||||
}
|
||||
|
||||
this._display.blitRgbImage(this._FBU.x, this._FBU.y, this._FBU.width, this._FBU.height, data, 0, false);
|
||||
this._convert_color_and_copy(this._destBuff, data, this._pixelFormat.Bdepth);
|
||||
this._display.blitImage(this._FBU.x, this._FBU.y, this._FBU.width, this._FBU.height, this._destBuff, 0, this._convert_color || this._pixelFormat.Bpp === 3, false);
|
||||
|
||||
return true;
|
||||
}.bind(this);
|
||||
|
|
@ -2239,7 +2344,7 @@
|
|||
switch (cmode) {
|
||||
// fill use fb_depth because TPIXELs drop the padding byte
|
||||
case "fill": // TPIXEL
|
||||
this._FBU.bytes += this._fb_depth;
|
||||
this._FBU.bytes += this._pixelFormat.Bdepth;
|
||||
break;
|
||||
case "jpeg": // max clength
|
||||
this._FBU.bytes += 3;
|
||||
|
|
@ -2260,8 +2365,9 @@
|
|||
switch (cmode) {
|
||||
case "fill":
|
||||
// skip ctl byte
|
||||
this._display.fillRect(this._FBU.x, this._FBU.y, this._FBU.width, this._FBU.height, [rQ[rQi + 3], rQ[rQi + 2], rQ[rQi + 1]], false);
|
||||
this._sock.rQskipBytes(4);
|
||||
var color = this._convert_one_color(rQ, rQi + 1, this._pixelFormat.Bdepth);
|
||||
this._display.fillRect(this._FBU.x, this._FBU.y, this._FBU.width, this._FBU.height, color, false);
|
||||
this._sock.rQskipBytes(this._pixelFormat.Bdepth + 1);
|
||||
break;
|
||||
case "png":
|
||||
case "jpeg":
|
||||
|
|
@ -2407,7 +2513,7 @@
|
|||
var w = this._FBU.width;
|
||||
var h = this._FBU.height;
|
||||
|
||||
var pixelslength = w * h * this._fb_Bpp;
|
||||
var pixelslength = w * h * this._pixelFormat.Bpp;
|
||||
var masklength = Math.floor((w + 7) / 8) * h;
|
||||
|
||||
this._FBU.bytes = pixelslength + masklength;
|
||||
|
|
|
|||
|
|
@ -392,19 +392,14 @@ describe('Display/Canvas Helper', function () {
|
|||
data[i * 4 + 2] = checked_data[i * 4];
|
||||
data[i * 4 + 3] = checked_data[i * 4 + 3];
|
||||
}
|
||||
|
||||
display.blitImage(0, 0, 4, 4, data, 0);
|
||||
display.flip();
|
||||
expect(display).to.have.displayed(checked_data);
|
||||
});
|
||||
|
||||
it('should support drawing RGB blit images with true color via #blitRgbImage', function () {
|
||||
var data = [];
|
||||
for (var i = 0; i < 16; i++) {
|
||||
data[i * 3] = checked_data[i * 4];
|
||||
data[i * 3 + 1] = checked_data[i * 4 + 1];
|
||||
data[i * 3 + 2] = checked_data[i * 4 + 2];
|
||||
}
|
||||
display.blitRgbImage(0, 0, 4, 4, data, 0);
|
||||
it('should support drawing RGBX blit images with true color via #blitImage', function () {
|
||||
display.blitImage(0, 0, 4, 4, checked_data, 0, true);
|
||||
display.flip();
|
||||
expect(display).to.have.displayed(checked_data);
|
||||
});
|
||||
|
|
@ -490,18 +485,19 @@ describe('Display/Canvas Helper', function () {
|
|||
expect(display.get_onFlush()).to.have.been.calledOnce;
|
||||
});
|
||||
|
||||
it('should draw a blit image on type "blit"', function () {
|
||||
it('should draw a blit image on type "blit" with "rgb" set to false', function () {
|
||||
display.blitImage = sinon.spy();
|
||||
display._renderQ_push({ type: 'blit', x: 3, y: 4, width: 5, height: 6, data: [7, 8, 9] });
|
||||
display._renderQ_push({ type: 'blit', x: 3, y: 4, width: 5, height: 6, data: [7, 8, 9], rgb: false });
|
||||
expect(display.blitImage).to.have.been.calledOnce;
|
||||
expect(display.blitImage).to.have.been.calledWith(3, 4, 5, 6, [7, 8, 9], 0);
|
||||
expect(display.blitImage).to.have.been.calledWith(3, 4, 5, 6, [7, 8, 9], 0, false);
|
||||
});
|
||||
|
||||
it('should draw a blit RGB image on type "blitRgb"', function () {
|
||||
display.blitRgbImage = sinon.spy();
|
||||
display._renderQ_push({ type: 'blitRgb', x: 3, y: 4, width: 5, height: 6, data: [7, 8, 9] });
|
||||
expect(display.blitRgbImage).to.have.been.calledOnce;
|
||||
expect(display.blitRgbImage).to.have.been.calledWith(3, 4, 5, 6, [7, 8, 9], 0);
|
||||
|
||||
it('should draw a blit RGBX image on type "blit" with "rgb" set to true', function () {
|
||||
display.blitImage = sinon.spy();
|
||||
display._renderQ_push({ type: 'blit', x: 3, y: 4, width: 5, height: 6, data: [7, 8, 9, 10], rgb: true });
|
||||
expect(display.blitImage).to.have.been.calledOnce;
|
||||
expect(display.blitImage).to.have.been.calledWith(3, 4, 5, 6, [7, 8, 9, 10], 0, true);
|
||||
});
|
||||
|
||||
it('should copy a region on type "copy"', function () {
|
||||
|
|
|
|||
|
|
@ -1103,8 +1103,6 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
|||
expect(client._fb_height).to.equal(84);
|
||||
});
|
||||
|
||||
// NB(sross): we just warn, not fail, for endian-ness and shifts, so we don't test them
|
||||
|
||||
it('should set the framebuffer name and call the callback', function () {
|
||||
client.set_onDesktopName(sinon.spy());
|
||||
send_server_init({ name: 'some name' }, client);
|
||||
|
|
@ -1134,14 +1132,6 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
|||
expect(client._rfb_connection_state).to.equal('connected');
|
||||
});
|
||||
|
||||
it('should set the true color mode on the display to the configuration variable', function () {
|
||||
client.set_true_color(false);
|
||||
sinon.spy(client._display, 'set_true_color');
|
||||
send_server_init({ true_color: 1 }, client);
|
||||
expect(client._display.set_true_color).to.have.been.calledOnce;
|
||||
expect(client._display.set_true_color).to.have.been.calledWith(false);
|
||||
});
|
||||
|
||||
it('should call the resize callback and resize the display', function () {
|
||||
client.set_onFBResize(sinon.spy());
|
||||
sinon.spy(client._display, 'resize');
|
||||
|
|
@ -1163,29 +1153,35 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
|||
expect(client._mouse.grab).to.have.been.calledOnce;
|
||||
});
|
||||
|
||||
it('should set the BPP and depth to 4 and 3 respectively if in true color mode', function () {
|
||||
client.set_true_color(true);
|
||||
send_server_init({}, client);
|
||||
expect(client._fb_Bpp).to.equal(4);
|
||||
expect(client._fb_depth).to.equal(3);
|
||||
it('should set the BPP and depth to 4 and 3 respectively if server can send native (true color)', function () {
|
||||
send_server_init({ true_color: 1, bpp: 8, depth: 8 }, client);
|
||||
expect(client._pixelFormat.Bpp).to.equal(4);
|
||||
expect(client._pixelFormat.Bdepth).to.equal(3);
|
||||
});
|
||||
|
||||
it('should set the BPP and depth to 1 and 1 respectively if not in true color mode', function () {
|
||||
client.set_true_color(false);
|
||||
send_server_init({}, client);
|
||||
expect(client._fb_Bpp).to.equal(1);
|
||||
expect(client._fb_depth).to.equal(1);
|
||||
it('should set the BPP and depth to 2 and 2 respectively if server cannot send native (true color)', function () {
|
||||
client.set_convert_color(true);
|
||||
send_server_init({ true_color: 1, bpp: 16, depth: 15 }, client);
|
||||
expect(client._pixelFormat.Bpp).to.equal(2);
|
||||
expect(client._pixelFormat.Bdepth).to.equal(2);
|
||||
});
|
||||
|
||||
it('should set the BPP and depth to 1 and 1 respectively if server cannot send native (not true color)', function () {
|
||||
client.set_convert_color(true);
|
||||
send_server_init({ true_color: 0, bpp: 8, depth: 8 }, client);
|
||||
expect(client._pixelFormat.Bpp).to.equal(1);
|
||||
expect(client._pixelFormat.Bdepth).to.equal(1);
|
||||
});
|
||||
|
||||
// TODO(directxman12): test the various options in this configuration matrix
|
||||
it('should reply with the pixel format, client encodings, and initial update request', function () {
|
||||
client.set_true_color(true);
|
||||
client.set_local_cursor(false);
|
||||
// we skip the cursor encoding
|
||||
var expected = {_sQ: new Uint8Array(34 + 4 * (client._encodings.length - 1)),
|
||||
_sQlen: 0,
|
||||
flush: function () {}};
|
||||
RFB.messages.pixelFormat(expected, 4, 3, true);
|
||||
var pf = { bpp: 32, depth: 24, big_endian: false, true_color: true, red_max: 255, green_max: 255, blue_max: 255, red_shift: 16, green_shift: 8, blue_shift: 0 };
|
||||
RFB.messages.pixelFormat(expected, pf);
|
||||
RFB.messages.clientEncodings(expected, client._encodings, false, true);
|
||||
RFB.messages.fbUpdateRequest(expected, false, 0, 0, 27, 32);
|
||||
|
||||
|
|
@ -1197,6 +1193,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
|||
send_server_init({}, client);
|
||||
expect(client._rfb_connection_state).to.equal('connected');
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -1224,13 +1221,14 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
|||
client._fb_name = 'some device';
|
||||
client._fb_width = 640;
|
||||
client._fb_height = 20;
|
||||
client._pixelFormat.Bpp = 4;
|
||||
});
|
||||
|
||||
var target_data_arr = [
|
||||
0xff, 0x00, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255,
|
||||
0x00, 0xff, 0x00, 255, 0xff, 0x00, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255,
|
||||
0xee, 0x00, 0xff, 255, 0x00, 0xee, 0xff, 255, 0xaa, 0xee, 0xff, 255, 0xab, 0xee, 0xff, 255,
|
||||
0xee, 0x00, 0xff, 255, 0x00, 0xee, 0xff, 255, 0xaa, 0xee, 0xff, 255, 0xab, 0xee, 0xff, 255
|
||||
0xf8, 0x00, 0x00, 255, 0x00, 0xf8, 0x00, 255, 0x00, 0x00, 0xf8, 255, 0x00, 0x00, 0xf8, 255,
|
||||
0x00, 0xf8, 0x00, 255, 0xf8, 0x00, 0x00, 255, 0x00, 0x00, 0xf8, 255, 0x00, 0x00, 0xf8, 255,
|
||||
0xe8, 0x00, 0xf8, 255, 0x00, 0xe8, 0xf8, 255, 0xa8, 0xe8, 0xf8, 255, 0xa8, 0xe8, 0xf8, 255,
|
||||
0xe8, 0x00, 0xf8, 255, 0x00, 0xe8, 0xf8, 255, 0xa8, 0xe8, 0xf8, 255, 0xa8, 0xe8, 0xf8, 255
|
||||
];
|
||||
var target_data;
|
||||
|
||||
|
|
@ -1379,24 +1377,98 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
|||
client._fb_width = 4;
|
||||
client._fb_height = 4;
|
||||
client._display.resize(4, 4);
|
||||
client._fb_Bpp = 4;
|
||||
client._pixelFormat.Bpp = 4;
|
||||
client._destBuff = new Uint8Array(client._fb_width * client._fb_height * 4);
|
||||
});
|
||||
|
||||
it('should handle the RAW encoding', function () {
|
||||
// warning: the fbupdates *overlap* so you have to send all rects for the numbers
|
||||
// to even make sense; this means (ironically) no iterative building of your tests
|
||||
describe('should handle the RAW encoding', function () {
|
||||
it('should handle 24bit depth (RGBX888) @ 32bpp [native]', function () {
|
||||
client._convert_color = true;
|
||||
client._pixelFormat.big_endian = false;
|
||||
client._pixelFormat.red_shift = 0;
|
||||
client._pixelFormat.red_max = 255;
|
||||
client._pixelFormat.green_shift = 8;
|
||||
client._pixelFormat.green_max = 255;
|
||||
client._pixelFormat.blue_shift = 16;
|
||||
client._pixelFormat.blue_max = 255;
|
||||
var info = [{ x: 0, y: 0, width: 2, height: 2, encoding: 0x00 },
|
||||
{ x: 2, y: 0, width: 2, height: 2, encoding: 0x00 },
|
||||
{ x: 0, y: 2, width: 4, height: 1, encoding: 0x00 },
|
||||
{ x: 0, y: 3, width: 4, height: 1, encoding: 0x00 }];
|
||||
var rects = [
|
||||
[0xf8, 0x00, 0x00, 0, 0x00, 0xf8, 0x00, 0, 0x00, 0xf8, 0x00, 0, 0xf8, 0x00, 0x00, 0],
|
||||
[0x00, 0x00, 0xf8, 0, 0x00, 0x00, 0xf8, 0, 0x00, 0x00, 0xf8, 0, 0x00, 0x00, 0xf8, 0],
|
||||
[0xe8, 0x00, 0xf8, 0, 0x00, 0xe8, 0xf8, 0, 0xa8, 0xe8, 0xf8, 0, 0xa8, 0xe8, 0xf8, 0],
|
||||
[0xe8, 0x00, 0xf8, 0, 0x00, 0xe8, 0xf8, 0, 0xa8, 0xe8, 0xf8, 0, 0xa8, 0xe8, 0xf8, 0]];
|
||||
send_fbu_msg(info, rects, client);
|
||||
expect(client._display).to.have.displayed(target_data);
|
||||
});
|
||||
|
||||
it('should handle 24bit depth (BGRX888) @ 32bpp', function () {
|
||||
var info = [{ x: 0, y: 0, width: 2, height: 2, encoding: 0x00 },
|
||||
{ x: 2, y: 0, width: 2, height: 2, encoding: 0x00 },
|
||||
{ x: 0, y: 2, width: 4, height: 1, encoding: 0x00 },
|
||||
{ x: 0, y: 3, width: 4, height: 1, encoding: 0x00 }];
|
||||
// data is in bgrx
|
||||
var rects = [
|
||||
[0x00, 0x00, 0xff, 0, 0x00, 0xff, 0x00, 0, 0x00, 0xff, 0x00, 0, 0x00, 0x00, 0xff, 0],
|
||||
[0xff, 0x00, 0x00, 0, 0xff, 0x00, 0x00, 0, 0xff, 0x00, 0x00, 0, 0xff, 0x00, 0x00, 0],
|
||||
[0xff, 0x00, 0xee, 0, 0xff, 0xee, 0x00, 0, 0xff, 0xee, 0xaa, 0, 0xff, 0xee, 0xab, 0],
|
||||
[0xff, 0x00, 0xee, 0, 0xff, 0xee, 0x00, 0, 0xff, 0xee, 0xaa, 0, 0xff, 0xee, 0xab, 0]];
|
||||
[0x00, 0x00, 0xf8, 0, 0x00, 0xf8, 0x00, 0, 0x00, 0xf8, 0x00, 0, 0x00, 0x00, 0xf8, 0],
|
||||
[0xf8, 0x00, 0x00, 0, 0xf8, 0x00, 0x00, 0, 0xf8, 0x00, 0x00, 0, 0xf8, 0x00, 0x00, 0],
|
||||
[0xf8, 0x00, 0xe8, 0, 0xf8, 0xe8, 0x00, 0, 0xf8, 0xe8, 0xa8, 0, 0xf8, 0xe8, 0xa8, 0],
|
||||
[0xf8, 0x00, 0xe8, 0, 0xf8, 0xe8, 0x00, 0, 0xf8, 0xe8, 0xa8, 0, 0xf8, 0xe8, 0xa8, 0]];
|
||||
send_fbu_msg(info, rects, client);
|
||||
expect(client._display).to.have.displayed(target_data);
|
||||
});
|
||||
|
||||
// for wisdom: perl -e '($w, $r, $g, $b) = @ARGV; $W=2**$w; $nb = $b*($W/256); $ng = $g*($W/256); $nr = $r*($W/256); printf "%f:%f:%f %04x\n", $nr, $ng, $nb, unpack("S", pack("n", ($nr << (2*$w)) | ($ng << (1*$w)) | ($nb << (0*$w))))' 5 0 248 0
|
||||
it('should handle 15bit depth (BGR555) @ 16bpp', function () {
|
||||
client._convert_color = true;
|
||||
client._pixelFormat.big_endian = false;
|
||||
client._pixelFormat.Bpp = 2;
|
||||
client._pixelFormat.red_shift = 10;
|
||||
client._pixelFormat.red_max = 31;
|
||||
client._pixelFormat.green_shift = 5;
|
||||
client._pixelFormat.green_max = 31;
|
||||
client._pixelFormat.blue_shift = 0;
|
||||
client._pixelFormat.blue_max = 31;
|
||||
var info = [{ x: 0, y: 0, width: 2, height: 2, encoding: 0x00 },
|
||||
{ x: 2, y: 0, width: 2, height: 2, encoding: 0x00 },
|
||||
{ x: 0, y: 2, width: 4, height: 1, encoding: 0x00 },
|
||||
{ x: 0, y: 3, width: 4, height: 1, encoding: 0x00 }];
|
||||
var rects = [
|
||||
[0x00, 0x7c, 0xe0, 0x03, 0xe0, 0x03, 0x00, 0x7c],
|
||||
[0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00],
|
||||
[0x1f, 0x74, 0xbf, 0x03, 0xbf, 0x57, 0xbf, 0x57],
|
||||
[0x1f, 0x74, 0xbf, 0x03, 0xbf, 0x57, 0xbf, 0x57]];
|
||||
send_fbu_msg(info, rects, client);
|
||||
expect(client._display).to.have.displayed(target_data);
|
||||
});
|
||||
|
||||
it('should handle 15bit depth (BGR555) @ 16bpp big-endian', function () {
|
||||
client._convert_color = true;
|
||||
client._pixelFormat.big_endian = false;
|
||||
client._pixelFormat.Bpp = 2;
|
||||
client._pixelFormat.big_endian = true;
|
||||
client._pixelFormat.red_shift = 10;
|
||||
client._pixelFormat.red_max = 31;
|
||||
client._pixelFormat.green_shift = 5;
|
||||
client._pixelFormat.green_max = 31;
|
||||
client._pixelFormat.blue_shift = 0;
|
||||
client._pixelFormat.blue_max = 31;
|
||||
var info = [{ x: 0, y: 0, width: 2, height: 2, encoding: 0x00 },
|
||||
{ x: 2, y: 0, width: 2, height: 2, encoding: 0x00 },
|
||||
{ x: 0, y: 2, width: 4, height: 1, encoding: 0x00 },
|
||||
{ x: 0, y: 3, width: 4, height: 1, encoding: 0x00 }];
|
||||
var rects = [
|
||||
[0x7c, 0x00, 0x03, 0xe0, 0x03, 0xe0, 0x7c, 0x00],
|
||||
[0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f],
|
||||
[0x74, 0x1f, 0x03, 0xbf, 0x57, 0xbf, 0x57, 0xbf],
|
||||
[0x74, 0x1f, 0x03, 0xbf, 0x57, 0xbf, 0x57, 0xbf]];
|
||||
send_fbu_msg(info, rects, client);
|
||||
expect(client._display).to.have.displayed(target_data);
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle the COPYRECT encoding', function () {
|
||||
// seed some initial data to copy
|
||||
client._display.blitRgbxImage(0, 0, 4, 2, new Uint8Array(target_data_check_arr.slice(0, 32)), 0);
|
||||
|
|
@ -1426,7 +1498,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
|||
push16(rect, 2); // width: 2
|
||||
push16(rect, 2); // height: 2
|
||||
rect.push(0xff); // becomes ff0000ff --> #0000FF color
|
||||
rect.push(0x00);
|
||||
rect.push(0x00); // becomes 0000ffff --> #0000FF color
|
||||
rect.push(0x00);
|
||||
rect.push(0xff);
|
||||
push16(rect, 2); // x: 2
|
||||
|
|
@ -1450,7 +1522,8 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
|||
client._fb_width = 4;
|
||||
client._fb_height = 4;
|
||||
client._display.resize(4, 4);
|
||||
client._fb_Bpp = 4;
|
||||
client._pixelFormat.Bpp = 4;
|
||||
client._destBuff = new Uint8Array(client._fb_width * client._fb_height * 4);
|
||||
});
|
||||
|
||||
it('should handle a tile with fg, bg specified, normal subrects', function () {
|
||||
|
|
|
|||
7
vnc.html
7
vnc.html
|
|
@ -11,9 +11,9 @@
|
|||
This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
|
||||
|
||||
Connect parameters are provided in query string:
|
||||
http://example.com/?host=HOST&port=PORT&encrypt=1&true_color=1
|
||||
http://example.com/?host=HOST&port=PORT&encrypt=1
|
||||
or the fragment:
|
||||
http://example.com/#host=HOST&port=PORT&encrypt=1&true_color=1
|
||||
http://example.com/#host=HOST&port=PORT&encrypt=1
|
||||
-->
|
||||
<title>noVNC</title>
|
||||
|
||||
|
|
@ -199,9 +199,6 @@
|
|||
<li>
|
||||
<div class="noVNC_expander">Advanced</div>
|
||||
<div><ul>
|
||||
<li>
|
||||
<label><input id="noVNC_setting_true_color" type="checkbox" checked /> True Color</label>
|
||||
</li>
|
||||
<li>
|
||||
<label><input id="noVNC_setting_cursor" type="checkbox" /> Local Cursor</label>
|
||||
</li>
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@
|
|||
This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
|
||||
|
||||
Connect parameters are provided in query string:
|
||||
http://example.com/?host=HOST&port=PORT&encrypt=1&true_color=1
|
||||
http://example.com/?host=HOST&port=PORT&encrypt=1
|
||||
or the fragment:
|
||||
http://example.com/#host=HOST&port=PORT&encrypt=1&true_color=1
|
||||
http://example.com/#host=HOST&port=PORT&encrypt=1
|
||||
-->
|
||||
<title>noVNC</title>
|
||||
|
||||
|
|
@ -261,7 +261,6 @@
|
|||
'encrypt': WebUtil.getConfigVar('encrypt',
|
||||
(window.location.protocol === "https:")),
|
||||
'repeaterID': WebUtil.getConfigVar('repeaterID', ''),
|
||||
'true_color': WebUtil.getConfigVar('true_color', true),
|
||||
'local_cursor': WebUtil.getConfigVar('cursor', true),
|
||||
'shared': WebUtil.getConfigVar('shared', true),
|
||||
'view_only': WebUtil.getConfigVar('view_only', false),
|
||||
|
|
@ -276,7 +275,6 @@
|
|||
status('Unable to create RFB client -- ' + exc, 'error');
|
||||
return; // don't continue trying to connect
|
||||
}
|
||||
|
||||
rfb.connect(host, port, password, path);
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
Loading…
Reference in New Issue