From 9255e0fb47fe450793d8018c1cbb1f47124e9344 Mon Sep 17 00:00:00 2001 From: Juanjo Diaz Date: Sat, 16 Feb 2019 23:31:58 +0200 Subject: [PATCH 1/8] Remove intermediate variable from mouse --- core/input/mouse.js | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/core/input/mouse.js b/core/input/mouse.js index c78f2ab8..58a2982a 100644 --- a/core/input/mouse.js +++ b/core/input/mouse.js @@ -238,43 +238,39 @@ export default class Mouse { // ===== PUBLIC METHODS ===== grab() { - const c = this._target; - if (isTouchDevice) { - c.addEventListener('touchstart', this._eventHandlers.mousedown); - c.addEventListener('touchend', this._eventHandlers.mouseup); - c.addEventListener('touchmove', this._eventHandlers.mousemove); + this._target.addEventListener('touchstart', this._eventHandlers.mousedown); + this._target.addEventListener('touchend', this._eventHandlers.mouseup); + this._target.addEventListener('touchmove', this._eventHandlers.mousemove); } - c.addEventListener('mousedown', this._eventHandlers.mousedown); - c.addEventListener('mouseup', this._eventHandlers.mouseup); - c.addEventListener('mousemove', this._eventHandlers.mousemove); - c.addEventListener('wheel', this._eventHandlers.mousewheel); + this._target.addEventListener('mousedown', this._eventHandlers.mousedown); + this._target.addEventListener('mouseup', this._eventHandlers.mouseup); + this._target.addEventListener('mousemove', this._eventHandlers.mousemove); + this._target.addEventListener('wheel', this._eventHandlers.mousewheel); /* Prevent middle-click pasting (see above for why we bind to document) */ document.addEventListener('click', this._eventHandlers.mousedisable); /* preventDefault() on mousedown doesn't stop this event for some reason so we have to explicitly block it */ - c.addEventListener('contextmenu', this._eventHandlers.mousedisable); + this._target.addEventListener('contextmenu', this._eventHandlers.mousedisable); } ungrab() { - const c = this._target; - this._resetWheelStepTimers(); if (isTouchDevice) { - c.removeEventListener('touchstart', this._eventHandlers.mousedown); - c.removeEventListener('touchend', this._eventHandlers.mouseup); - c.removeEventListener('touchmove', this._eventHandlers.mousemove); + this._target.removeEventListener('touchstart', this._eventHandlers.mousedown); + this._target.removeEventListener('touchend', this._eventHandlers.mouseup); + this._target.removeEventListener('touchmove', this._eventHandlers.mousemove); } - c.removeEventListener('mousedown', this._eventHandlers.mousedown); - c.removeEventListener('mouseup', this._eventHandlers.mouseup); - c.removeEventListener('mousemove', this._eventHandlers.mousemove); - c.removeEventListener('wheel', this._eventHandlers.mousewheel); + this._target.removeEventListener('mousedown', this._eventHandlers.mousedown); + this._target.removeEventListener('mouseup', this._eventHandlers.mouseup); + this._target.removeEventListener('mousemove', this._eventHandlers.mousemove); + this._target.removeEventListener('wheel', this._eventHandlers.mousewheel); document.removeEventListener('click', this._eventHandlers.mousedisable); - c.removeEventListener('contextmenu', this._eventHandlers.mousedisable); + this._target.removeEventListener('contextmenu', this._eventHandlers.mousedisable); } } From fe5974a740bea67c650147d67a85dcbda252784c Mon Sep 17 00:00:00 2001 From: Juanjo Diaz Date: Sat, 16 Feb 2019 23:33:49 +0200 Subject: [PATCH 2/8] Remove unnecessary constructor parameter from Cursor --- core/util/cursor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/util/cursor.js b/core/util/cursor.js index b032ab6c..b73f862b 100644 --- a/core/util/cursor.js +++ b/core/util/cursor.js @@ -9,7 +9,7 @@ import { supportsCursorURIs, isTouchDevice } from './browser.js'; const useFallback = !supportsCursorURIs() || isTouchDevice; export default class Cursor { - constructor(container) { + constructor() { this._target = null; this._canvas = document.createElement('canvas'); From 667f3cc20ece104ac1e841b67a7cc9f4e196f8ca Mon Sep 17 00:00:00 2001 From: Juanjo Diaz Date: Sat, 16 Feb 2019 23:34:13 +0200 Subject: [PATCH 3/8] Remove unnecessary context from eventtarget --- core/util/eventtarget.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/util/eventtarget.js b/core/util/eventtarget.js index d74ed28e..f54ca9bf 100644 --- a/core/util/eventtarget.js +++ b/core/util/eventtarget.js @@ -29,7 +29,7 @@ export default class EventTargetMixin { return true; } this._listeners.get(event.type) - .forEach(callback => callback.call(this, event), this); + .forEach(callback => callback.call(this, event)); return !event.defaultPrevented; } } From 9d2c9d1a75fa6cdec5a50bc51467df8b35290c0a Mon Sep 17 00:00:00 2001 From: Juanjo Diaz Date: Sat, 16 Feb 2019 23:36:16 +0200 Subject: [PATCH 4/8] Use default argument for base64 --- core/base64.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/core/base64.js b/core/base64.js index 42ba53b6..88e74546 100644 --- a/core/base64.js +++ b/core/base64.js @@ -56,9 +56,7 @@ export default { ], /* eslint-enable comma-spacing */ - decode(data, offset) { - offset = typeof(offset) !== 'undefined' ? offset : 0; - + decode(data, offset = 0) { let data_length = data.indexOf('=') - offset; if (data_length < 0) { data_length = data.length - offset; } From 0505214cd98476a8ae116dc388fccc7243460c27 Mon Sep 17 00:00:00 2001 From: Juanjo Diaz Date: Sun, 17 Feb 2019 00:25:33 +0200 Subject: [PATCH 5/8] Convert DES into a class --- core/des.js | 141 +++++++++++++++++++++++++--------------------------- core/rfb.js | 7 +-- 2 files changed, 71 insertions(+), 77 deletions(-) diff --git a/core/des.js b/core/des.js index 175066bc..d2f807b8 100644 --- a/core/des.js +++ b/core/des.js @@ -77,67 +77,68 @@ /* eslint-disable comma-spacing */ -export default function DES(passwd) { - "use strict"; +// Tables, permutations, S-boxes, etc. +const PC2 = [13,16,10,23, 0, 4, 2,27,14, 5,20, 9,22,18,11, 3, + 25, 7,15, 6,26,19,12, 1,40,51,30,36,46,54,29,39, + 50,44,32,47,43,48,38,55,33,52,45,41,49,35,28,31 ], + totrot = [ 1, 2, 4, 6, 8,10,12,14,15,17,19,21,23,25,27,28]; - // Tables, permutations, S-boxes, etc. - const PC2 = [13,16,10,23, 0, 4, 2,27,14, 5,20, 9,22,18,11, 3, - 25, 7,15, 6,26,19,12, 1,40,51,30,36,46,54,29,39, - 50,44,32,47,43,48,38,55,33,52,45,41,49,35,28,31 ], - totrot = [ 1, 2, 4, 6, 8,10,12,14,15,17,19,21,23,25,27,28], - z = 0x0, - keys = []; - let a,b,c,d,e,f; +const z = 0x0; +let a,b,c,d,e,f; +a=1<<16; b=1<<24; c=a|b; d=1<<2; e=1<<10; f=d|e; +const SP1 = [c|e,z|z,a|z,c|f,c|d,a|f,z|d,a|z,z|e,c|e,c|f,z|e,b|f,c|d,b|z,z|d, + z|f,b|e,b|e,a|e,a|e,c|z,c|z,b|f,a|d,b|d,b|d,a|d,z|z,z|f,a|f,b|z, + a|z,c|f,z|d,c|z,c|e,b|z,b|z,z|e,c|d,a|z,a|e,b|d,z|e,z|d,b|f,a|f, + c|f,a|d,c|z,b|f,b|d,z|f,a|f,c|e,z|f,b|e,b|e,z|z,a|d,a|e,z|z,c|d]; +a=1<<20; b=1<<31; c=a|b; d=1<<5; e=1<<15; f=d|e; +const SP2 = [c|f,b|e,z|e,a|f,a|z,z|d,c|d,b|f,b|d,c|f,c|e,b|z,b|e,a|z,z|d,c|d, + a|e,a|d,b|f,z|z,b|z,z|e,a|f,c|z,a|d,b|d,z|z,a|e,z|f,c|e,c|z,z|f, + z|z,a|f,c|d,a|z,b|f,c|z,c|e,z|e,c|z,b|e,z|d,c|f,a|f,z|d,z|e,b|z, + z|f,c|e,a|z,b|d,a|d,b|f,b|d,a|d,a|e,z|z,b|e,z|f,b|z,c|d,c|f,a|e]; +a=1<<17; b=1<<27; c=a|b; d=1<<3; e=1<<9; f=d|e; +const SP3 = [z|f,c|e,z|z,c|d,b|e,z|z,a|f,b|e,a|d,b|d,b|d,a|z,c|f,a|d,c|z,z|f, + b|z,z|d,c|e,z|e,a|e,c|z,c|d,a|f,b|f,a|e,a|z,b|f,z|d,c|f,z|e,b|z, + c|e,b|z,a|d,z|f,a|z,c|e,b|e,z|z,z|e,a|d,c|f,b|e,b|d,z|e,z|z,c|d, + b|f,a|z,b|z,c|f,z|d,a|f,a|e,b|d,c|z,b|f,z|f,c|z,a|f,z|d,c|d,a|e]; +a=1<<13; b=1<<23; c=a|b; d=1<<0; e=1<<7; f=d|e; +const SP4 = [c|d,a|f,a|f,z|e,c|e,b|f,b|d,a|d,z|z,c|z,c|z,c|f,z|f,z|z,b|e,b|d, + z|d,a|z,b|z,c|d,z|e,b|z,a|d,a|e,b|f,z|d,a|e,b|e,a|z,c|e,c|f,z|f, + b|e,b|d,c|z,c|f,z|f,z|z,z|z,c|z,a|e,b|e,b|f,z|d,c|d,a|f,a|f,z|e, + c|f,z|f,z|d,a|z,b|d,a|d,c|e,b|f,a|d,a|e,b|z,c|d,z|e,b|z,a|z,c|e]; +a=1<<25; b=1<<30; c=a|b; d=1<<8; e=1<<19; f=d|e; +const SP5 = [z|d,a|f,a|e,c|d,z|e,z|d,b|z,a|e,b|f,z|e,a|d,b|f,c|d,c|e,z|f,b|z, + a|z,b|e,b|e,z|z,b|d,c|f,c|f,a|d,c|e,b|d,z|z,c|z,a|f,a|z,c|z,z|f, + z|e,c|d,z|d,a|z,b|z,a|e,c|d,b|f,a|d,b|z,c|e,a|f,b|f,z|d,a|z,c|e, + c|f,z|f,c|z,c|f,a|e,z|z,b|e,c|z,z|f,a|d,b|d,z|e,z|z,b|e,a|f,b|d]; +a=1<<22; b=1<<29; c=a|b; d=1<<4; e=1<<14; f=d|e; +const SP6 = [b|d,c|z,z|e,c|f,c|z,z|d,c|f,a|z,b|e,a|f,a|z,b|d,a|d,b|e,b|z,z|f, + z|z,a|d,b|f,z|e,a|e,b|f,z|d,c|d,c|d,z|z,a|f,c|e,z|f,a|e,c|e,b|z, + b|e,z|d,c|d,a|e,c|f,a|z,z|f,b|d,a|z,b|e,b|z,z|f,b|d,c|f,a|e,c|z, + a|f,c|e,z|z,c|d,z|d,z|e,c|z,a|f,z|e,a|d,b|f,z|z,c|e,b|z,a|d,b|f]; +a=1<<21; b=1<<26; c=a|b; d=1<<1; e=1<<11; f=d|e; +const SP7 = [a|z,c|d,b|f,z|z,z|e,b|f,a|f,c|e,c|f,a|z,z|z,b|d,z|d,b|z,c|d,z|f, + b|e,a|f,a|d,b|e,b|d,c|z,c|e,a|d,c|z,z|e,z|f,c|f,a|e,z|d,b|z,a|e, + b|z,a|e,a|z,b|f,b|f,c|d,c|d,z|d,a|d,b|z,b|e,a|z,c|e,z|f,a|f,c|e, + z|f,b|d,c|f,c|z,a|e,z|z,z|d,c|f,z|z,a|f,c|z,z|e,b|d,b|e,z|e,a|d]; +a=1<<18; b=1<<28; c=a|b; d=1<<6; e=1<<12; f=d|e; +const SP8 = [b|f,z|e,a|z,c|f,b|z,b|f,z|d,b|z,a|d,c|z,c|f,a|e,c|e,a|f,z|e,z|d, + c|z,b|d,b|e,z|f,a|e,a|d,c|d,c|e,z|f,z|z,z|z,c|d,b|d,b|e,a|f,a|z, + a|f,a|z,c|e,z|e,z|d,c|d,z|e,a|f,b|e,z|d,b|d,c|z,c|d,b|z,a|z,b|f, + z|z,c|f,a|d,b|d,c|z,b|e,b|f,z|z,c|f,a|e,a|e,z|f,z|f,a|d,b|z,c|e]; - a=1<<16; b=1<<24; c=a|b; d=1<<2; e=1<<10; f=d|e; - const SP1 = [c|e,z|z,a|z,c|f,c|d,a|f,z|d,a|z,z|e,c|e,c|f,z|e,b|f,c|d,b|z,z|d, - z|f,b|e,b|e,a|e,a|e,c|z,c|z,b|f,a|d,b|d,b|d,a|d,z|z,z|f,a|f,b|z, - a|z,c|f,z|d,c|z,c|e,b|z,b|z,z|e,c|d,a|z,a|e,b|d,z|e,z|d,b|f,a|f, - c|f,a|d,c|z,b|f,b|d,z|f,a|f,c|e,z|f,b|e,b|e,z|z,a|d,a|e,z|z,c|d]; - a=1<<20; b=1<<31; c=a|b; d=1<<5; e=1<<15; f=d|e; - const SP2 = [c|f,b|e,z|e,a|f,a|z,z|d,c|d,b|f,b|d,c|f,c|e,b|z,b|e,a|z,z|d,c|d, - a|e,a|d,b|f,z|z,b|z,z|e,a|f,c|z,a|d,b|d,z|z,a|e,z|f,c|e,c|z,z|f, - z|z,a|f,c|d,a|z,b|f,c|z,c|e,z|e,c|z,b|e,z|d,c|f,a|f,z|d,z|e,b|z, - z|f,c|e,a|z,b|d,a|d,b|f,b|d,a|d,a|e,z|z,b|e,z|f,b|z,c|d,c|f,a|e]; - a=1<<17; b=1<<27; c=a|b; d=1<<3; e=1<<9; f=d|e; - const SP3 = [z|f,c|e,z|z,c|d,b|e,z|z,a|f,b|e,a|d,b|d,b|d,a|z,c|f,a|d,c|z,z|f, - b|z,z|d,c|e,z|e,a|e,c|z,c|d,a|f,b|f,a|e,a|z,b|f,z|d,c|f,z|e,b|z, - c|e,b|z,a|d,z|f,a|z,c|e,b|e,z|z,z|e,a|d,c|f,b|e,b|d,z|e,z|z,c|d, - b|f,a|z,b|z,c|f,z|d,a|f,a|e,b|d,c|z,b|f,z|f,c|z,a|f,z|d,c|d,a|e]; - a=1<<13; b=1<<23; c=a|b; d=1<<0; e=1<<7; f=d|e; - const SP4 = [c|d,a|f,a|f,z|e,c|e,b|f,b|d,a|d,z|z,c|z,c|z,c|f,z|f,z|z,b|e,b|d, - z|d,a|z,b|z,c|d,z|e,b|z,a|d,a|e,b|f,z|d,a|e,b|e,a|z,c|e,c|f,z|f, - b|e,b|d,c|z,c|f,z|f,z|z,z|z,c|z,a|e,b|e,b|f,z|d,c|d,a|f,a|f,z|e, - c|f,z|f,z|d,a|z,b|d,a|d,c|e,b|f,a|d,a|e,b|z,c|d,z|e,b|z,a|z,c|e]; - a=1<<25; b=1<<30; c=a|b; d=1<<8; e=1<<19; f=d|e; - const SP5 = [z|d,a|f,a|e,c|d,z|e,z|d,b|z,a|e,b|f,z|e,a|d,b|f,c|d,c|e,z|f,b|z, - a|z,b|e,b|e,z|z,b|d,c|f,c|f,a|d,c|e,b|d,z|z,c|z,a|f,a|z,c|z,z|f, - z|e,c|d,z|d,a|z,b|z,a|e,c|d,b|f,a|d,b|z,c|e,a|f,b|f,z|d,a|z,c|e, - c|f,z|f,c|z,c|f,a|e,z|z,b|e,c|z,z|f,a|d,b|d,z|e,z|z,b|e,a|f,b|d]; - a=1<<22; b=1<<29; c=a|b; d=1<<4; e=1<<14; f=d|e; - const SP6 = [b|d,c|z,z|e,c|f,c|z,z|d,c|f,a|z,b|e,a|f,a|z,b|d,a|d,b|e,b|z,z|f, - z|z,a|d,b|f,z|e,a|e,b|f,z|d,c|d,c|d,z|z,a|f,c|e,z|f,a|e,c|e,b|z, - b|e,z|d,c|d,a|e,c|f,a|z,z|f,b|d,a|z,b|e,b|z,z|f,b|d,c|f,a|e,c|z, - a|f,c|e,z|z,c|d,z|d,z|e,c|z,a|f,z|e,a|d,b|f,z|z,c|e,b|z,a|d,b|f]; - a=1<<21; b=1<<26; c=a|b; d=1<<1; e=1<<11; f=d|e; - const SP7 = [a|z,c|d,b|f,z|z,z|e,b|f,a|f,c|e,c|f,a|z,z|z,b|d,z|d,b|z,c|d,z|f, - b|e,a|f,a|d,b|e,b|d,c|z,c|e,a|d,c|z,z|e,z|f,c|f,a|e,z|d,b|z,a|e, - b|z,a|e,a|z,b|f,b|f,c|d,c|d,z|d,a|d,b|z,b|e,a|z,c|e,z|f,a|f,c|e, - z|f,b|d,c|f,c|z,a|e,z|z,z|d,c|f,z|z,a|f,c|z,z|e,b|d,b|e,z|e,a|d]; - a=1<<18; b=1<<28; c=a|b; d=1<<6; e=1<<12; f=d|e; - const SP8 = [b|f,z|e,a|z,c|f,b|z,b|f,z|d,b|z,a|d,c|z,c|f,a|e,c|e,a|f,z|e,z|d, - c|z,b|d,b|e,z|f,a|e,a|d,c|d,c|e,z|f,z|z,z|z,c|d,b|d,b|e,a|f,a|z, - a|f,a|z,c|e,z|e,z|d,c|d,z|e,a|f,b|e,z|d,b|d,c|z,c|d,b|z,a|z,b|f, - z|z,c|f,a|d,b|d,c|z,b|e,b|f,z|z,c|f,a|e,a|e,z|f,z|f,a|d,b|z,c|e]; +/* eslint-enable comma-spacing */ - // Set the key. - function setKeys(keyBlock) { +export default class DES { + constructor(password) { + this.keys = []; + + // Set the key. const pc1m = [], pcr = [], kn = []; for (let j = 0, l = 56; j < 56; ++j, l -= 8) { l += l < -5 ? 65 : l < -3 ? 31 : l < -1 ? 63 : l === 27 ? 35 : 0; // PC1 const m = l & 0x7; - pc1m[j] = ((keyBlock[l >>> 3] & (1<>> 3] & (1<>> 10; - keys[KnLi] |= (raw1 & 0x00000fc0) >>> 6; + this.keys[KnLi] = (raw0 & 0x00fc0000) << 6; + this.keys[KnLi] |= (raw0 & 0x00000fc0) << 10; + this.keys[KnLi] |= (raw1 & 0x00fc0000) >>> 10; + this.keys[KnLi] |= (raw1 & 0x00000fc0) >>> 6; ++KnLi; - keys[KnLi] = (raw0 & 0x0003f000) << 12; - keys[KnLi] |= (raw0 & 0x0000003f) << 16; - keys[KnLi] |= (raw1 & 0x0003f000) >>> 4; - keys[KnLi] |= (raw1 & 0x0000003f); + this.keys[KnLi] = (raw0 & 0x0003f000) << 12; + this.keys[KnLi] |= (raw0 & 0x0000003f) << 16; + this.keys[KnLi] |= (raw1 & 0x0003f000) >>> 4; + this.keys[KnLi] |= (raw1 & 0x0000003f); ++KnLi; } } // Encrypt 8 bytes of text - function enc8(text) { + enc8(text) { const b = text.slice(); let i = 0, l, r, x; // left, right, accumulator @@ -206,24 +207,24 @@ export default function DES(passwd) { for (let i = 0, keysi = 0; i < 8; ++i) { x = (r << 28) | (r >>> 4); - x ^= keys[keysi++]; + x ^= this.keys[keysi++]; let fval = SP7[x & 0x3f]; fval |= SP5[(x >>> 8) & 0x3f]; fval |= SP3[(x >>> 16) & 0x3f]; fval |= SP1[(x >>> 24) & 0x3f]; - x = r ^ keys[keysi++]; + x = r ^ this.keys[keysi++]; fval |= SP8[x & 0x3f]; fval |= SP6[(x >>> 8) & 0x3f]; fval |= SP4[(x >>> 16) & 0x3f]; fval |= SP2[(x >>> 24) & 0x3f]; l ^= fval; x = (l << 28) | (l >>> 4); - x ^= keys[keysi++]; + x ^= this.keys[keysi++]; fval = SP7[x & 0x3f]; fval |= SP5[(x >>> 8) & 0x3f]; fval |= SP3[(x >>> 16) & 0x3f]; fval |= SP1[(x >>> 24) & 0x3f]; - x = l ^ keys[keysi++]; + x = l ^ this.keys[keysi++]; fval |= SP8[x & 0x0000003f]; fval |= SP6[(x >>> 8) & 0x3f]; fval |= SP4[(x >>> 16) & 0x3f]; @@ -259,11 +260,7 @@ export default function DES(passwd) { } // Encrypt 16 bytes of text using passwd as key - function encrypt(t) { - return enc8(t.slice(0, 8)).concat(enc8(t.slice(8, 16))); + encrypt(t) { + return this.enc8(t.slice(0, 8)).concat(this.enc8(t.slice(8, 16))); } - - setKeys(passwd); // Setup keys - return {'encrypt': encrypt}; // Public interface - } diff --git a/core/rfb.js b/core/rfb.js index 3665583d..89b8130d 100644 --- a/core/rfb.js +++ b/core/rfb.js @@ -1718,11 +1718,8 @@ export default class RFB extends EventTargetMixin { } static genDES(password, challenge) { - const passwd = []; - for (let i = 0; i < password.length; i++) { - passwd.push(password.charCodeAt(i)); - } - return (new DES(passwd)).encrypt(challenge); + const passwordChars = password.split('').map(c => c.charCodeAt(0)); + return (new DES(passwordChars)).encrypt(challenge); } } From 44f4c5545f9f46f38e4bd4774df60b6f83b2e0cd Mon Sep 17 00:00:00 2001 From: Juanjo Diaz Date: Wed, 27 Feb 2019 10:13:50 +0200 Subject: [PATCH 6/8] Move support check from display to browser --- core/display.js | 11 ++--------- core/util/browser.js | 9 +++++++++ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/core/display.js b/core/display.js index 59ddb340..73e03873 100644 --- a/core/display.js +++ b/core/display.js @@ -8,14 +8,7 @@ import * as Log from './util/logging.js'; import Base64 from "./base64.js"; - -let SUPPORTS_IMAGEDATA_CONSTRUCTOR = false; -try { - new ImageData(new Uint8ClampedArray(4), 1, 1); - SUPPORTS_IMAGEDATA_CONSTRUCTOR = true; -} catch (ex) { - // ignore failure -} +import { supportsImageMetadata } from './util/browser.js'; export default class Display { constructor(target) { @@ -573,7 +566,7 @@ export default class Display { _rgbxImageData(x, y, width, height, arr, offset) { // NB(directxman12): arr must be an Type Array view let img; - if (SUPPORTS_IMAGEDATA_CONSTRUCTOR) { + if (supportsImageMetadata) { img = new ImageData(new Uint8ClampedArray(arr.buffer, arr.byteOffset, width * height * 4), width, height); } else { img = this._drawCtx.createImageData(width, height); diff --git a/core/util/browser.js b/core/util/browser.js index 026a31ab..78e104de 100644 --- a/core/util/browser.js +++ b/core/util/browser.js @@ -49,6 +49,15 @@ export function supportsCursorURIs() { return _cursor_uris_supported; } +let _supportsImageMetadata = false; +try { + new ImageData(new Uint8ClampedArray(4), 1, 1); + _supportsImageMetadata = true; +} catch (ex) { + // ignore failure +} +export const supportsImageMetadata = _supportsImageMetadata; + export function isMac() { return navigator && !!(/mac/i).exec(navigator.platform); } From 41ddb35458f2b64d1aaa2d262c7130e069ea2d99 Mon Sep 17 00:00:00 2001 From: Juanjo Diaz Date: Wed, 27 Feb 2019 10:14:50 +0200 Subject: [PATCH 7/8] Replace unnecessary function supportsCursorURIs by a constant variable --- core/util/browser.js | 32 +++++++++++++------------------- core/util/cursor.js | 2 +- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/core/util/browser.js b/core/util/browser.js index 78e104de..8996cfed 100644 --- a/core/util/browser.js +++ b/core/util/browser.js @@ -25,30 +25,24 @@ window.addEventListener('touchstart', function onFirstTouch() { // brings us a bit closer but is not optimal. export let dragThreshold = 10 * (window.devicePixelRatio || 1); -let _cursor_uris_supported = null; +let _supportsCursorURIs = false; -export function supportsCursorURIs() { - if (_cursor_uris_supported === null) { - try { - const target = document.createElement('canvas'); - target.style.cursor = 'url("data:image/x-icon;base64,AAACAAEACAgAAAIAAgA4AQAAFgAAACgAAAAIAAAAEAAAAAEAIAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AAAAAAAAAAAAAAAAAAAAAA==") 2 2, default'; +try { + const target = document.createElement('canvas'); + target.style.cursor = 'url("data:image/x-icon;base64,AAACAAEACAgAAAIAAgA4AQAAFgAAACgAAAAIAAAAEAAAAAEAIAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AAAAAAAAAAAAAAAAAAAAAA==") 2 2, default'; - if (target.style.cursor) { - Log.Info("Data URI scheme cursor supported"); - _cursor_uris_supported = true; - } else { - Log.Warn("Data URI scheme cursor not supported"); - _cursor_uris_supported = false; - } - } catch (exc) { - Log.Error("Data URI scheme cursor test exception: " + exc); - _cursor_uris_supported = false; - } + if (target.style.cursor) { + Log.Info("Data URI scheme cursor supported"); + _supportsCursorURIs = true; + } else { + Log.Warn("Data URI scheme cursor not supported"); } - - return _cursor_uris_supported; +} catch (exc) { + Log.Error("Data URI scheme cursor test exception: " + exc); } +export const supportsCursorURIs = _supportsCursorURIs; + let _supportsImageMetadata = false; try { new ImageData(new Uint8ClampedArray(4), 1, 1); diff --git a/core/util/cursor.js b/core/util/cursor.js index b73f862b..0d0b754a 100644 --- a/core/util/cursor.js +++ b/core/util/cursor.js @@ -6,7 +6,7 @@ import { supportsCursorURIs, isTouchDevice } from './browser.js'; -const useFallback = !supportsCursorURIs() || isTouchDevice; +const useFallback = !supportsCursorURIs || isTouchDevice; export default class Cursor { constructor() { From 1c9b904d1aa585e4f096fe922ca508bdb4c5106a Mon Sep 17 00:00:00 2001 From: Juanjo Diaz Date: Sun, 17 Feb 2019 14:12:28 +0200 Subject: [PATCH 8/8] Remove callbacks from UI in favour of promises --- app/ui.js | 43 ++++++++++++------------------- app/webutil.js | 60 +++++++++++++++++++------------------------ tests/test.webutil.js | 4 +-- 3 files changed, 46 insertions(+), 61 deletions(-) diff --git a/app/ui.js b/app/ui.js index aaabad72..67af7cda 100644 --- a/app/ui.js +++ b/app/ui.js @@ -39,22 +39,20 @@ const UI = { reconnect_callback: null, reconnect_password: null, - prime(callback) { - if (document.readyState === "interactive" || document.readyState === "complete") { - UI.load(callback); - } else { - document.addEventListener('DOMContentLoaded', UI.load.bind(UI, callback)); - } - }, + prime() { + return WebUtil.initSettings().then(() => { + if (document.readyState === "interactive" || document.readyState === "complete") { + return UI.start(); + } - // Setup rfb object, load settings from browser storage, then call - // UI.init to setup the UI/menus - load(callback) { - WebUtil.initSettings(UI.start, callback); + return new Promise((resolve, reject) => { + document.addEventListener('DOMContentLoaded', () => UI.start().then(resolve).catch(reject)); + }); + }); }, // Render default UI and initialize settings menu - start(callback) { + start() { UI.initSettings(); @@ -105,9 +103,7 @@ const UI = { UI.openConnectPanel(); } - if (typeof callback === "function") { - callback(UI.rfb); - } + return Promise.resolve(UI.rfb); }, initFullscreen() { @@ -1646,18 +1642,13 @@ const UI = { // Set up translations const LINGUAS = ["cs", "de", "el", "es", "ko", "nl", "pl", "sv", "tr", "zh_CN", "zh_TW"]; l10n.setup(LINGUAS); -if (l10n.language !== "en" && l10n.dictionary === undefined) { - WebUtil.fetchJSON('app/locale/' + l10n.language + '.json', (translations) => { - l10n.dictionary = translations; - - // wait for translations to load before loading the UI - UI.prime(); - }, (err) => { - Log.Error("Failed to load translations: " + err); - UI.prime(); - }); -} else { +if (l10n.language === "en" || l10n.dictionary !== undefined) { UI.prime(); +} else { + WebUtil.fetchJSON('app/locale/' + l10n.language + '.json') + .then((translations) => { l10n.dictionary = translations; }) + .catch(err => Log.Error("Failed to load translations: " + err)) + .then(UI.prime); } export default UI; diff --git a/app/webutil.js b/app/webutil.js index 922ddc10..98e1d9e6 100644 --- a/app/webutil.js +++ b/app/webutil.js @@ -114,22 +114,14 @@ export function eraseCookie(name) { let settings = {}; -export function initSettings(callback /*, ...callbackArgs */) { - "use strict"; - const callbackArgs = Array.prototype.slice.call(arguments, 1); - if (window.chrome && window.chrome.storage) { - window.chrome.storage.sync.get((cfg) => { - settings = cfg; - if (callback) { - callback.apply(this, callbackArgs); - } - }); - } else { +export function initSettings() { + if (!window.chrome || !window.chrome.storage) { settings = {}; - if (callback) { - callback.apply(this, callbackArgs); - } + return Promise.resolve(); } + + return new Promise(resolve => window.chrome.storage.sync.get(resolve)) + .then((cfg) => { settings = cfg; }); } // Update the settings cache, but do not write to permanent storage @@ -218,28 +210,30 @@ export function injectParamIfMissing(path, param, value) { // IE11 support or polyfill promises and fetch in IE11. // resolve will receive an object on success, while reject // will receive either an event or an error on failure. -export function fetchJSON(path, resolve, reject) { - // NB: IE11 doesn't support JSON as a responseType - const req = new XMLHttpRequest(); - req.open('GET', path); +export function fetchJSON(path) { + return new Promise((resolve, reject) => { + // NB: IE11 doesn't support JSON as a responseType + const req = new XMLHttpRequest(); + req.open('GET', path); - req.onload = () => { - if (req.status === 200) { - let resObj; - try { - resObj = JSON.parse(req.responseText); - } catch (err) { - reject(err); + req.onload = () => { + if (req.status === 200) { + let resObj; + try { + resObj = JSON.parse(req.responseText); + } catch (err) { + reject(err); + } + resolve(resObj); + } else { + reject(new Error("XHR got non-200 status while trying to load '" + path + "': " + req.status)); } - resolve(resObj); - } else { - reject(new Error("XHR got non-200 status while trying to load '" + path + "': " + req.status)); - } - }; + }; - req.onerror = evt => reject(new Error("XHR encountered an error while trying to load '" + path + "': " + evt.message)); + req.onerror = evt => reject(new Error("XHR encountered an error while trying to load '" + path + "': " + evt.message)); - req.ontimeout = evt => reject(new Error("XHR timed out while trying to load '" + path + "'")); + req.ontimeout = evt => reject(new Error("XHR timed out while trying to load '" + path + "'")); - req.send(); + req.send(); + }); } diff --git a/tests/test.webutil.js b/tests/test.webutil.js index 27397041..72e19421 100644 --- a/tests/test.webutil.js +++ b/tests/test.webutil.js @@ -39,7 +39,7 @@ describe('WebUtil', function () { window.localStorage.getItem = sinon.stub(); window.localStorage.removeItem = sinon.stub(); - WebUtil.initSettings(); + return WebUtil.initSettings(); }); afterEach(function () { Object.defineProperty(window, "localStorage", origLocalStorage); @@ -132,7 +132,7 @@ describe('WebUtil', function () { settings = {}; csSandbox.spy(window.chrome.storage.sync, 'set'); csSandbox.spy(window.chrome.storage.sync, 'remove'); - WebUtil.initSettings(); + return WebUtil.initSettings(); }); afterEach(function () { csSandbox.restore();