diff --git a/src/cursor.js b/src/cursor.js index c3bc05e..7d1c3c7 100644 --- a/src/cursor.js +++ b/src/cursor.js @@ -18,7 +18,6 @@ along with spice-html5. If not, see . */ -import { create_rgba_png } from './png.js'; import { Constants } from './enums.js'; import { DEBUG } from './utils.js'; import { @@ -124,11 +123,32 @@ SpiceCursorConn.prototype.process_channel_message = function(msg) return false; } +const offscreenCanvas = document.createElement("canvas"); +const offscreenCtx = offscreenCanvas.getContext("2d"); + +function create_bgra_png(width, height, bytes) { + offscreenCanvas.width = width; + offscreenCanvas.height = height; + + const imgData = offscreenCtx.createImageData(width, height); + const u8 = new Uint8Array(bytes); + + for (let i = 0; i < u8.length; i += 4) { + imgData.data[i + 0] = u8[i + 2]; // R + imgData.data[i + 1] = u8[i + 1]; // G + imgData.data[i + 2] = u8[i + 0]; // B + imgData.data[i + 3] = u8[i + 3]; // A + } + + offscreenCtx.putImageData(imgData, 0, 0); + return offscreenCanvas.toDataURL("image/png"); +} + SpiceCursorConn.prototype.set_cursor = function(cursor) { - var pngstr = create_rgba_png(cursor.header.width, cursor.header.height, cursor.data); - var curstr = 'url(data:image/png,' + pngstr + ') ' + - cursor.header.hot_spot_x + ' ' + cursor.header.hot_spot_y + ", default"; +var pngstr = create_bgra_png(cursor.header.width, cursor.header.height, cursor.data); +var curstr = 'url(' + pngstr + ') ' + + cursor.header.hot_spot_x + ' ' + cursor.header.hot_spot_y + ", default"; var screen = document.getElementById(this.parent.screen_id); screen.style.cursor = 'auto'; screen.style.cursor = curstr; diff --git a/src/png.js b/src/png.js deleted file mode 100644 index d6dd7ab..0000000 --- a/src/png.js +++ /dev/null @@ -1,262 +0,0 @@ -"use strict"; -/* - Copyright (C) 2012 by Jeremy P. White - - This file is part of spice-html5. - - spice-html5 is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - spice-html5 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with spice-html5. If not, see . -*/ - -/*---------------------------------------------------------------------------- -** crc logic from rfc2083 ported to Javascript -**--------------------------------------------------------------------------*/ - -import { SpiceDataView } from './spicedataview.js'; - -var rfc2083_crc_table = Array(256); -var rfc2083_crc_table_computed = 0; -/* Make the table for a fast CRC. */ -function rfc2083_make_crc_table() -{ - var c; - var n, k; - for (n = 0; n < 256; n++) - { - c = n; - for (k = 0; k < 8; k++) - { - if (c & 1) - c = ((0xedb88320 ^ (c >>> 1)) >>> 0) & 0xffffffff; - else - c = c >>> 1; - } - rfc2083_crc_table[n] = c; - } - - rfc2083_crc_table_computed = 1; -} - -/* Update a running CRC with the bytes buf[0..len-1]--the CRC - should be initialized to all 1's, and the transmitted value - is the 1's complement of the final running CRC (see the - crc() routine below)). */ - -function rfc2083_update_crc(crc, u8buf, at, len) -{ - var c = crc; - var n; - - if (!rfc2083_crc_table_computed) - rfc2083_make_crc_table(); - - for (n = 0; n < len; n++) - { - c = rfc2083_crc_table[(c ^ u8buf[at + n]) & 0xff] ^ (c >>> 8); - } - - return c; -} - -function rfc2083_crc(u8buf, at, len) -{ - return rfc2083_update_crc(0xffffffff, u8buf, at, len) ^ 0xffffffff; -} - -function crc32(mb, at, len) -{ - var u8 = new Uint8Array(mb); - return rfc2083_crc(u8, at, len); -} - -function PngIHDR(width, height) -{ - this.width = width; - this.height = height; - this.depth = 8; - this.type = 6; - this.compression = 0; - this.filter = 0; - this.interlace = 0; -} - -PngIHDR.prototype = -{ - to_buffer: function(a, at) - { - at = at || 0; - var orig = at; - var dv = new SpiceDataView(a); - dv.setUint32(at, this.buffer_size() - 12); at += 4; - dv.setUint8(at, 'I'.charCodeAt(0)); at++; - dv.setUint8(at, 'H'.charCodeAt(0)); at++; - dv.setUint8(at, 'D'.charCodeAt(0)); at++; - dv.setUint8(at, 'R'.charCodeAt(0)); at++; - dv.setUint32(at, this.width); at += 4; - dv.setUint32(at, this.height); at += 4; - dv.setUint8(at, this.depth); at++; - dv.setUint8(at, this.type); at++; - dv.setUint8(at, this.compression); at++; - dv.setUint8(at, this.filter); at++; - dv.setUint8(at, this.interlace); at++; - dv.setUint32(at, crc32(a, orig + 4, this.buffer_size() - 8)); at += 4; - return at; - }, - buffer_size: function() - { - return 12 + 13; - } -} - - -function adler() -{ - this.s1 = 1; - this.s2 = 0; -} - -adler.prototype.update = function(b) -{ - this.s1 += b; - this.s1 %= 65521; - this.s2 += this.s1; - this.s2 %= 65521; -} - -function PngIDAT(width, height, bytes) -{ - if (bytes.byteLength > 65535) - { - throw new Error("Cannot handle more than 64K"); - } - this.data = bytes; - this.width = width; - this.height = height; -} - -PngIDAT.prototype = -{ - to_buffer: function(a, at) - { - at = at || 0; - var orig = at; - var x, y, i, j; - var dv = new SpiceDataView(a); - var zsum = new adler(); - dv.setUint32(at, this.buffer_size() - 12); at += 4; - dv.setUint8(at, 'I'.charCodeAt(0)); at++; - dv.setUint8(at, 'D'.charCodeAt(0)); at++; - dv.setUint8(at, 'A'.charCodeAt(0)); at++; - dv.setUint8(at, 'T'.charCodeAt(0)); at++; - - /* zlib header. */ - dv.setUint8(at, 0x78); at++; - dv.setUint8(at, 0x01); at++; - - /* Deflate header. Specifies uncompressed, final bit */ - dv.setUint8(at, 0x80); at++; - dv.setUint16(at, this.data.byteLength + this.height); at += 2; - dv.setUint16(at, ~(this.data.byteLength + this.height)); at += 2; - var u8 = new Uint8Array(this.data); - for (i = 0, y = 0; y < this.height; y++) - { - /* Filter type 0 - uncompressed */ - dv.setUint8(at, 0); at++; - zsum.update(0); - for (x = 0; x < this.width && i < this.data.byteLength; x++) - { - zsum.update(u8[i]); - dv.setUint8(at, u8[i++]); at++; - zsum.update(u8[i]); - dv.setUint8(at, u8[i++]); at++; - zsum.update(u8[i]); - dv.setUint8(at, u8[i++]); at++; - zsum.update(u8[i]); - dv.setUint8(at, u8[i++]); at++; - } - } - - /* zlib checksum. */ - dv.setUint16(at, zsum.s2); at+=2; - dv.setUint16(at, zsum.s1); at+=2; - - /* FIXME - something is not quite right with the zlib code; - you get an error from libpng if you open the image in - gimp. But it works, so it's good enough for now... */ - - dv.setUint32(at, crc32(a, orig + 4, this.buffer_size() - 8)); at += 4; - return at; - }, - buffer_size: function() - { - return 12 + this.data.byteLength + this.height + 4 + 2 + 1 + 2 + 2; - } -} - - -function PngIEND() -{ -} - -PngIEND.prototype = -{ - to_buffer: function(a, at) - { - at = at || 0; - var orig = at; - var i; - var dv = new SpiceDataView(a); - dv.setUint32(at, this.buffer_size() - 12); at += 4; - dv.setUint8(at, 'I'.charCodeAt(0)); at++; - dv.setUint8(at, 'E'.charCodeAt(0)); at++; - dv.setUint8(at, 'N'.charCodeAt(0)); at++; - dv.setUint8(at, 'D'.charCodeAt(0)); at++; - dv.setUint32(at, crc32(a, orig + 4, this.buffer_size() - 8)); at += 4; - return at; - }, - buffer_size: function() - { - return 12; - } -} - - -function create_rgba_png(width, height, bytes) -{ - var i; - var ihdr = new PngIHDR(width, height); - var idat = new PngIDAT(width, height, bytes); - var iend = new PngIEND; - - var mb = new ArrayBuffer(ihdr.buffer_size() + idat.buffer_size() + iend.buffer_size()); - var at = ihdr.to_buffer(mb); - at = idat.to_buffer(mb, at); - at = iend.to_buffer(mb, at); - - var u8 = new Uint8Array(mb); - var str = ""; - for (i = 0; i < at; i++) - { - str += "%"; - if (u8[i] < 16) - str += "0"; - str += u8[i].toString(16); - } - - - return "%89PNG%0D%0A%1A%0A" + str; -} - -export { - create_rgba_png, -};