summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/decoders/hextile.js21
-rw-r--r--core/decoders/raw.js10
-rw-r--r--core/decoders/tight.js26
-rw-r--r--core/display.js30
-rw-r--r--core/rfb.js4
-rw-r--r--core/util/browser.js9
-rw-r--r--tests/test.copyrect.js2
-rw-r--r--tests/test.display.js21
-rw-r--r--tests/test.hextile.js20
-rw-r--r--tests/test.raw.js22
-rw-r--r--tests/test.rre.js8
11 files changed, 93 insertions, 80 deletions
diff --git a/core/decoders/hextile.js b/core/decoders/hextile.js
index f12e7f6..ac21eff 100644
--- a/core/decoders/hextile.js
+++ b/core/decoders/hextile.js
@@ -88,6 +88,11 @@ export default class HextileDecoder {
display.fillRect(tx, ty, tw, th, this._background);
}
} else if (subencoding & 0x01) { // Raw
+ let pixels = tw * th;
+ // Max sure the image is fully opaque
+ for (let i = 0;i < pixels;i++) {
+ rQ[rQi + i * 4 + 3] = 255;
+ }
display.blitImage(tx, ty, tw, th, rQ, rQi);
rQi += bytes - 1;
} else {
@@ -143,24 +148,24 @@ export default class HextileDecoder {
this._tileW = width;
this._tileH = height;
- const red = color[2];
+ const red = color[0];
const green = color[1];
- const blue = color[0];
+ const blue = color[2];
const data = this._tileBuffer;
for (let i = 0; i < width * height * 4; i += 4) {
- data[i] = blue;
+ data[i] = red;
data[i + 1] = green;
- data[i + 2] = red;
+ data[i + 2] = blue;
data[i + 3] = 255;
}
}
// update sub-rectangle of the current tile
_subTile(x, y, w, h, color) {
- const red = color[2];
+ const red = color[0];
const green = color[1];
- const blue = color[0];
+ const blue = color[2];
const xend = x + w;
const yend = y + h;
@@ -169,9 +174,9 @@ export default class HextileDecoder {
for (let j = y; j < yend; j++) {
for (let i = x; i < xend; i++) {
const p = (i + (j * width)) * 4;
- data[p] = blue;
+ data[p] = red;
data[p + 1] = green;
- data[p + 2] = red;
+ data[p + 2] = blue;
data[p + 3] = 255;
}
}
diff --git a/core/decoders/raw.js b/core/decoders/raw.js
index 4d84d7d..d7a77ec 100644
--- a/core/decoders/raw.js
+++ b/core/decoders/raw.js
@@ -27,23 +27,29 @@ export default class RawDecoder {
const curY = y + (height - this._lines);
const currHeight = Math.min(this._lines,
Math.floor(sock.rQlen / bytesPerLine));
+ const pixels = width * currHeight;
+
let data = sock.rQ;
let index = sock.rQi;
// Convert data if needed
if (depth == 8) {
- const pixels = width * currHeight;
const newdata = new Uint8Array(pixels * 4);
for (let i = 0; i < pixels; i++) {
newdata[i * 4 + 0] = ((data[index + i] >> 0) & 0x3) * 255 / 3;
newdata[i * 4 + 1] = ((data[index + i] >> 2) & 0x3) * 255 / 3;
newdata[i * 4 + 2] = ((data[index + i] >> 4) & 0x3) * 255 / 3;
- newdata[i * 4 + 4] = 0;
+ newdata[i * 4 + 3] = 255;
}
data = newdata;
index = 0;
}
+ // Max sure the image is fully opaque
+ for (let i = 0; i < pixels; i++) {
+ data[i * 4 + 3] = 255;
+ }
+
display.blitImage(x, curY, width, currHeight, data, index);
sock.rQskipBytes(currHeight * bytesPerLine);
this._lines -= currHeight;
diff --git a/core/decoders/tight.js b/core/decoders/tight.js
index e61f132..8bc97d1 100644
--- a/core/decoders/tight.js
+++ b/core/decoders/tight.js
@@ -80,7 +80,7 @@ export default class TightDecoder {
const rQ = sock.rQ;
display.fillRect(x, y, width, height,
- [rQ[rQi + 2], rQ[rQi + 1], rQ[rQi]], false);
+ [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2]], false);
sock.rQskipBytes(3);
return true;
@@ -165,15 +165,15 @@ export default class TightDecoder {
this._zlibs[streamId].setInput(null);
}
- let bgrx = new Uint8Array(width * height * 4);
+ let rgbx = new Uint8Array(width * height * 4);
for (let i = 0, j = 0; i < width * height * 4; i += 4, j += 3) {
- bgrx[i] = data[j + 2];
- bgrx[i + 1] = data[j + 1];
- bgrx[i + 2] = data[j];
- bgrx[i + 3] = 255; // Alpha
+ 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, bgrx, 0, false);
+ display.blitImage(x, y, width, height, rgbx, 0, false);
return true;
}
@@ -245,9 +245,9 @@ export default class TightDecoder {
for (let 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 + 2];
+ dest[dp] = palette[sp];
dest[dp + 1] = palette[sp + 1];
- dest[dp + 2] = palette[sp];
+ dest[dp + 2] = palette[sp + 2];
dest[dp + 3] = 255;
}
}
@@ -255,9 +255,9 @@ export default class TightDecoder {
for (let 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 + 2];
+ dest[dp] = palette[sp];
dest[dp + 1] = palette[sp + 1];
- dest[dp + 2] = palette[sp];
+ dest[dp + 2] = palette[sp + 2];
dest[dp + 3] = 255;
}
}
@@ -271,9 +271,9 @@ export default class TightDecoder {
const total = width * height * 4;
for (let i = 0, j = 0; i < total; i += 4, j++) {
const sp = data[j] * 3;
- dest[i] = palette[sp + 2];
+ dest[i] = palette[sp];
dest[i + 1] = palette[sp + 1];
- dest[i + 2] = palette[sp];
+ dest[i + 2] = palette[sp + 2];
dest[i + 3] = 255;
}
diff --git a/core/display.js b/core/display.js
index f06aa37..494b7a3 100644
--- a/core/display.js
+++ b/core/display.js
@@ -8,6 +8,7 @@
import * as Log from './util/logging.js';
import Base64 from "./base64.js";
+import { supportsImageMetadata } from './util/browser.js';
export default class Display {
constructor(target) {
@@ -387,7 +388,19 @@ export default class Display {
'height': height,
});
} else {
- this._bgrxImageData(x, y, width, height, arr, offset);
+ // NB(directxman12): arr must be an Type Array view
+ let data = new Uint8ClampedArray(arr.buffer,
+ arr.byteOffset + offset,
+ width * height * 4);
+ let img;
+ if (supportsImageMetadata) {
+ img = new ImageData(data, width, height);
+ } else {
+ img = this._drawCtx.createImageData(width, height);
+ img.data.set(data);
+ }
+ this._drawCtx.putImageData(img, x, y);
+ this._damage(x, y, width, height);
}
}
@@ -439,26 +452,13 @@ export default class Display {
}
_setFillColor(color) {
- const newStyle = 'rgb(' + color[2] + ',' + color[1] + ',' + color[0] + ')';
+ const newStyle = 'rgb(' + color[0] + ',' + color[1] + ',' + color[2] + ')';
if (newStyle !== this._prevDrawStyle) {
this._drawCtx.fillStyle = newStyle;
this._prevDrawStyle = newStyle;
}
}
- _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) {
- 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);
- this._damage(x, y, img.width, img.height);
- }
-
_renderQPush(action) {
this._renderQ.push(action);
if (this._renderQ.length === 1) {
diff --git a/core/rfb.js b/core/rfb.js
index ca50779..4061196 100644
--- a/core/rfb.js
+++ b/core/rfb.js
@@ -2584,9 +2584,9 @@ RFB.messages = {
buff[offset + 12] = 0; // blue-max
buff[offset + 13] = (1 << bits) - 1; // blue-max
- buff[offset + 14] = bits * 2; // red-shift
+ buff[offset + 14] = bits * 0; // red-shift
buff[offset + 15] = bits * 1; // green-shift
- buff[offset + 16] = bits * 0; // blue-shift
+ buff[offset + 16] = bits * 2; // blue-shift
buff[offset + 17] = 0; // padding
buff[offset + 18] = 0; // padding
diff --git a/core/util/browser.js b/core/util/browser.js
index a18d5a4..1554801 100644
--- a/core/util/browser.js
+++ b/core/util/browser.js
@@ -45,6 +45,15 @@ try {
export const supportsCursorURIs = _supportsCursorURIs;
+let _supportsImageMetadata = false;
+try {
+ new ImageData(new Uint8ClampedArray(4), 1, 1);
+ _supportsImageMetadata = true;
+} catch (ex) {
+ // ignore failure
+}
+export const supportsImageMetadata = _supportsImageMetadata;
+
let _hasScrollbarGutter = true;
try {
// Create invisible container
diff --git a/tests/test.copyrect.js b/tests/test.copyrect.js
index fcf4219..e2277cb 100644
--- a/tests/test.copyrect.js
+++ b/tests/test.copyrect.js
@@ -38,7 +38,7 @@ describe('CopyRect Decoder', function () {
it('should handle the CopyRect encoding', function () {
// seed some initial data to copy
display.fillRect(0, 0, 4, 4, [ 0x11, 0x22, 0x33 ]);
- display.fillRect(0, 0, 2, 2, [ 0xff, 0x00, 0x00 ]);
+ display.fillRect(0, 0, 2, 2, [ 0x00, 0x00, 0xff ]);
display.fillRect(2, 0, 2, 2, [ 0x00, 0xff, 0x00 ]);
testDecodeRect(decoder, 0, 2, 2, 2,
diff --git a/tests/test.display.js b/tests/test.display.js
index 88c7607..bd5a55f 100644
--- a/tests/test.display.js
+++ b/tests/test.display.js
@@ -128,7 +128,7 @@ describe('Display/Canvas Helper', function () {
});
it('should keep the framebuffer data', function () {
- display.fillRect(0, 0, 4, 4, [0, 0, 0xff]);
+ display.fillRect(0, 0, 4, 4, [0xff, 0, 0]);
display.resize(2, 2);
display.flip();
const expected = [];
@@ -271,7 +271,7 @@ describe('Display/Canvas Helper', function () {
});
it('should not draw directly on the target canvas', function () {
- display.fillRect(0, 0, 4, 4, [0, 0, 0xff]);
+ display.fillRect(0, 0, 4, 4, [0xff, 0, 0]);
display.flip();
display.fillRect(0, 0, 4, 4, [0, 0xff, 0]);
const expected = [];
@@ -285,15 +285,15 @@ describe('Display/Canvas Helper', function () {
it('should support filling a rectangle with particular color via #fillRect', function () {
display.fillRect(0, 0, 4, 4, [0, 0xff, 0]);
- display.fillRect(0, 0, 2, 2, [0xff, 0, 0]);
- display.fillRect(2, 2, 2, 2, [0xff, 0, 0]);
+ display.fillRect(0, 0, 2, 2, [0, 0, 0xff]);
+ display.fillRect(2, 2, 2, 2, [0, 0, 0xff]);
display.flip();
expect(display).to.have.displayed(checkedData);
});
it('should support copying an portion of the canvas via #copyImage', function () {
display.fillRect(0, 0, 4, 4, [0, 0xff, 0]);
- display.fillRect(0, 0, 2, 2, [0xff, 0, 0x00]);
+ display.fillRect(0, 0, 2, 2, [0, 0, 0xff]);
display.copyImage(0, 0, 2, 2, 2, 2);
display.flip();
expect(display).to.have.displayed(checkedData);
@@ -309,15 +309,8 @@ describe('Display/Canvas Helper', function () {
display.flush();
});
- it('should support drawing BGRX blit images with true color via #blitImage', function () {
- const data = [];
- for (let i = 0; i < 16; i++) {
- data[i * 4] = checkedData[i * 4 + 2];
- data[i * 4 + 1] = checkedData[i * 4 + 1];
- data[i * 4 + 2] = checkedData[i * 4];
- data[i * 4 + 3] = checkedData[i * 4 + 3];
- }
- display.blitImage(0, 0, 4, 4, data, 0);
+ it('should support blit images with true color via #blitImage', function () {
+ display.blitImage(0, 0, 4, 4, checkedData, 0);
display.flip();
expect(display).to.have.displayed(checkedData);
});
diff --git a/tests/test.hextile.js b/tests/test.hextile.js
index 7c97527..052c82e 100644
--- a/tests/test.hextile.js
+++ b/tests/test.hextile.js
@@ -46,9 +46,9 @@ describe('Hextile Decoder', function () {
let data = [];
data.push(0x02 | 0x04 | 0x08); // bg spec, fg spec, anysubrects
push32(data, 0x00ff0000); // becomes 00ff0000 --> #00FF00 bg color
- data.push(0xff); // becomes ff000000 --> #0000FF fg color
- data.push(0x00);
+ data.push(0x00); // becomes 0000ff00 --> #0000FF fg color
data.push(0x00);
+ data.push(0xff);
data.push(0x00);
data.push(2); // 2 subrects
data.push(0); // x: 0, y: 0
@@ -79,9 +79,9 @@ describe('Hextile Decoder', function () {
let data = [];
data.push(0x01); // raw
for (let i = 0; i < targetData.length; i += 4) {
- data.push(targetData[i + 2]);
- data.push(targetData[i + 1]);
data.push(targetData[i]);
+ data.push(targetData[i + 1]);
+ data.push(targetData[i + 2]);
// Last byte zero to test correct alpha handling
data.push(0);
}
@@ -137,15 +137,15 @@ describe('Hextile Decoder', function () {
data.push(0x02 | 0x08 | 0x10); // bg spec, anysubrects, colouredsubrects
push32(data, 0x00ff0000); // becomes 00ff0000 --> #00FF00 bg color
data.push(2); // 2 subrects
- data.push(0xff); // becomes ff000000 --> #0000FF fg color
- data.push(0x00);
+ data.push(0x00); // becomes 0000ff00 --> #0000FF fg color
data.push(0x00);
+ data.push(0xff);
data.push(0x00);
data.push(0); // x: 0, y: 0
data.push(1 | (1 << 4)); // width: 2, height: 2
- data.push(0xff); // becomes ff000000 --> #0000FF fg color
- data.push(0x00);
+ data.push(0x00); // becomes 0000ff00 --> #0000FF fg color
data.push(0x00);
+ data.push(0xff);
data.push(0x00);
data.push(2 | (2 << 4)); // x: 2, y: 2
data.push(1 | (1 << 4)); // width: 2, height: 2
@@ -168,10 +168,10 @@ describe('Hextile Decoder', function () {
let data = [];
data.push(0x02 | 0x04 | 0x08); // bg spec, fg spec, anysubrects
push32(data, 0xff00ff); // becomes 00ff00ff --> #00FF00 bg color
- data.push(0xff); // becomes ff0000ff --> #0000FF fg color
- data.push(0x00);
+ data.push(0x00); // becomes 0000ffff --> #0000FF fg color
data.push(0x00);
data.push(0xff);
+ data.push(0xff);
data.push(8); // 8 subrects
for (let i = 0; i < 4; i++) {
data.push((0 << 4) | (i * 4)); // x: 0, y: i*4
diff --git a/tests/test.raw.js b/tests/test.raw.js
index b42e4f3..95a33af 100644
--- a/tests/test.raw.js
+++ b/tests/test.raw.js
@@ -37,20 +37,20 @@ describe('Raw Decoder', function () {
it('should handle the Raw encoding', function () {
testDecodeRect(decoder, 0, 0, 2, 2,
- [0x00, 0x00, 0xff, 0, 0x00, 0xff, 0x00, 0,
- 0x00, 0xff, 0x00, 0, 0x00, 0x00, 0xff, 0],
+ [0xff, 0x00, 0x00, 0, 0x00, 0xff, 0x00, 0,
+ 0x00, 0xff, 0x00, 0, 0xff, 0x00, 0x00, 0],
display, 24);
testDecodeRect(decoder, 2, 0, 2, 2,
- [0xff, 0x00, 0x00, 0, 0xff, 0x00, 0x00, 0,
- 0xff, 0x00, 0x00, 0, 0xff, 0x00, 0x00, 0],
+ [0x00, 0x00, 0xff, 0, 0x00, 0x00, 0xff, 0,
+ 0x00, 0x00, 0xff, 0, 0x00, 0x00, 0xff, 0],
display, 24);
testDecodeRect(decoder, 0, 2, 4, 1,
- [0xff, 0x00, 0xee, 0, 0xff, 0xee, 0x00, 0,
- 0xff, 0xee, 0xaa, 0, 0xff, 0xee, 0xab, 0],
+ [0xee, 0x00, 0xff, 0, 0x00, 0xee, 0xff, 0,
+ 0xaa, 0xee, 0xff, 0, 0xab, 0xee, 0xff, 0],
display, 24);
testDecodeRect(decoder, 0, 3, 4, 1,
- [0xff, 0x00, 0xee, 0, 0xff, 0xee, 0x00, 0,
- 0xff, 0xee, 0xaa, 0, 0xff, 0xee, 0xab, 0],
+ [0xee, 0x00, 0xff, 0, 0x00, 0xee, 0xff, 0,
+ 0xaa, 0xee, 0xff, 0, 0xab, 0xee, 0xff, 0],
display, 24);
let targetData = new Uint8Array([
@@ -65,16 +65,16 @@ describe('Raw Decoder', function () {
it('should handle the Raw encoding in low colour mode', function () {
testDecodeRect(decoder, 0, 0, 2, 2,
- [0x03, 0x03, 0x03, 0x03],
+ [0x30, 0x30, 0x30, 0x30],
display, 8);
testDecodeRect(decoder, 2, 0, 2, 2,
[0x0c, 0x0c, 0x0c, 0x0c],
display, 8);
testDecodeRect(decoder, 0, 2, 4, 1,
- [0x0c, 0x0c, 0x03, 0x03],
+ [0x0c, 0x0c, 0x30, 0x30],
display, 8);
testDecodeRect(decoder, 0, 3, 4, 1,
- [0x0c, 0x0c, 0x03, 0x03],
+ [0x0c, 0x0c, 0x30, 0x30],
display, 8);
let targetData = new Uint8Array([
diff --git a/tests/test.rre.js b/tests/test.rre.js
index 78b5eaa..fff1c94 100644
--- a/tests/test.rre.js
+++ b/tests/test.rre.js
@@ -53,17 +53,17 @@ describe('RRE Decoder', function () {
let data = [];
push32(data, 2); // 2 subrects
push32(data, 0x00ff0000); // becomes 00ff0000 --> #00FF00 bg color
- data.push(0xff); // becomes ff000000 --> #0000FF color
- data.push(0x00);
+ data.push(0x00); // becomes 0000ff00 --> #0000FF fg color
data.push(0x00);
+ data.push(0xff);
data.push(0x00);
push16(data, 0); // x: 0
push16(data, 0); // y: 0
push16(data, 2); // width: 2
push16(data, 2); // height: 2
- data.push(0xff); // becomes ff000000 --> #0000FF color
- data.push(0x00);
+ data.push(0x00); // becomes 0000ff00 --> #0000FF fg color
data.push(0x00);
+ data.push(0xff);
data.push(0x00);
push16(data, 2); // x: 2
push16(data, 2); // y: 2