Best JavaScript code snippet using redwood
rfb.js
Source:rfb.js
...551 _negotiate_security: function () {552 if (this._rfb_version >= 3.7) {553 // Server sends supported list, client decides554 var num_types = this._sock.rQshift8();555 if (this._sock.rQwait("security type", num_types, 1)) { return false; }556 if (num_types === 0) {557 var strlen = this._sock.rQshift32();558 var reason = this._sock.rQshiftStr(strlen);559 return this._fail("Security failure: " + reason);560 }561 this._rfb_auth_scheme = 0;562 var types = this._sock.rQshiftBytes(num_types);563 Util.Debug("Server security types: " + types);564 for (var i = 0; i < types.length; i++) {565 if (types[i] > this._rfb_auth_scheme && (types[i] <= 16 || types[i] == 22)) {566 this._rfb_auth_scheme = types[i];567 }568 }569 if (this._rfb_auth_scheme === 0) {570 return this._fail("Unsupported security types: " + types);571 }572 this._sock.send([this._rfb_auth_scheme]);573 } else {574 // Server decides575 if (this._sock.rQwait("security scheme", 4)) { return false; }576 this._rfb_auth_scheme = this._sock.rQshift32();577 }578 this._updateState('Authentication', 'Authenticating using scheme: ' + this._rfb_auth_scheme);579 return this._init_msg(); // jump to authentication580 },581 // authentication582 _negotiate_xvp_auth: function () {583 var xvp_sep = this._xvp_password_sep;584 var xvp_auth = this._rfb_password.split(xvp_sep);585 if (xvp_auth.length < 3) {586 this._updateState('password', 'XVP credentials required (user' + xvp_sep +587 'target' + xvp_sep + 'password) -- got only ' + this._rfb_password);588 this._onPasswordRequired(this);589 return false;590 }591 var xvp_auth_str = String.fromCharCode(xvp_auth[0].length) +592 String.fromCharCode(xvp_auth[1].length) +593 xvp_auth[0] +594 xvp_auth[1];595 this._sock.send_string(xvp_auth_str);596 this._rfb_password = xvp_auth.slice(2).join(xvp_sep);597 this._rfb_auth_scheme = 2;598 return this._negotiate_authentication();599 },600 _negotiate_std_vnc_auth: function () {601 if (this._rfb_password.length === 0) {602 // Notify via both callbacks since it's kind of603 // an RFB state change and a UI interface issue604 this._updateState('password', "Password Required");605 this._onPasswordRequired(this);606 }607 if (this._sock.rQwait("auth challenge", 16)) { return false; }608 var challenge = this._sock.rQshiftBytes(16);609 var response = RFB.genDES(this._rfb_password, challenge);610 this._sock.send(response);611 this._updateState("SecurityResult");612 return true;613 },614 _negotiate_tight_tunnels: function (numTunnels) {615 var clientSupportedTunnelTypes = {616 0: { vendor: 'TGHT', signature: 'NOTUNNEL' }617 };618 var serverSupportedTunnelTypes = {};619 // receive tunnel capabilities620 for (var i = 0; i < numTunnels; i++) {621 var cap_code = this._sock.rQshift32();622 var cap_vendor = this._sock.rQshiftStr(4);623 var cap_signature = this._sock.rQshiftStr(8);624 serverSupportedTunnelTypes[cap_code] = { vendor: cap_vendor, signature: cap_signature };625 }626 // choose the notunnel type627 if (serverSupportedTunnelTypes[0]) {628 if (serverSupportedTunnelTypes[0].vendor != clientSupportedTunnelTypes[0].vendor ||629 serverSupportedTunnelTypes[0].signature != clientSupportedTunnelTypes[0].signature) {630 return this._fail("Client's tunnel type had the incorrect vendor or signature");631 }632 this._sock.send([0, 0, 0, 0]); // use NOTUNNEL633 return false; // wait until we receive the sub auth count to continue634 } else {635 return this._fail("Server wanted tunnels, but doesn't support the notunnel type");636 }637 },638 _negotiate_tight_auth: function () {639 if (!this._rfb_tightvnc) { // first pass, do the tunnel negotiation640 if (this._sock.rQwait("num tunnels", 4)) { return false; }641 var numTunnels = this._sock.rQshift32();642 if (numTunnels > 0 && this._sock.rQwait("tunnel capabilities", 16 * numTunnels, 4)) { return false; }643 this._rfb_tightvnc = true;644 if (numTunnels > 0) {645 this._negotiate_tight_tunnels(numTunnels);646 return false; // wait until we receive the sub auth to continue647 }648 }649 // second pass, do the sub-auth negotiation650 if (this._sock.rQwait("sub auth count", 4)) { return false; }651 var subAuthCount = this._sock.rQshift32();652 if (this._sock.rQwait("sub auth capabilities", 16 * subAuthCount, 4)) { return false; }653 var clientSupportedTypes = {654 'STDVNOAUTH__': 1,655 'STDVVNCAUTH_': 2656 };657 var serverSupportedTypes = [];658 for (var i = 0; i < subAuthCount; i++) {659 var capNum = this._sock.rQshift32();660 var capabilities = this._sock.rQshiftStr(12);661 serverSupportedTypes.push(capabilities);662 }663 for (var authType in clientSupportedTypes) {664 if (serverSupportedTypes.indexOf(authType) != -1) {665 this._sock.send([0, 0, 0, clientSupportedTypes[authType]]);666 switch (authType) {667 case 'STDVNOAUTH__': // no auth668 this._updateState('SecurityResult');669 return true;670 case 'STDVVNCAUTH_': // VNC auth671 this._rfb_auth_scheme = 2;672 return this._init_msg();673 default:674 return this._fail("Unsupported tiny auth scheme: " + authType);675 }676 }677 }678 this._fail("No supported sub-auth types!");679 },680 _negotiate_authentication: function () {681 switch (this._rfb_auth_scheme) {682 case 0: // connection failed683 if (this._sock.rQwait("auth reason", 4)) { return false; }684 var strlen = this._sock.rQshift32();685 var reason = this._sock.rQshiftStr(strlen);686 return this._fail("Auth failure: " + reason);687 case 1: // no auth688 if (this._rfb_version >= 3.8) {689 this._updateState('SecurityResult');690 return true;691 }692 this._updateState('ClientInitialisation', "No auth required");693 return this._init_msg();694 case 22: // XVP auth695 return this._negotiate_xvp_auth();696 case 2: // VNC authentication697 return this._negotiate_std_vnc_auth();698 case 16: // TightVNC Security Type699 return this._negotiate_tight_auth();700 default:701 return this._fail("Unsupported auth scheme: " + this._rfb_auth_scheme);702 }703 },704 _handle_security_result: function () {705 if (this._sock.rQwait('VNC auth response ', 4)) { return false; }706 switch (this._sock.rQshift32()) {707 case 0: // OK708 this._updateState('ClientInitialisation', 'Authentication OK');709 return this._init_msg();710 case 1: // failed711 if (this._rfb_version >= 3.8) {712 var length = this._sock.rQshift32();713 if (this._sock.rQwait("SecurityResult reason", length, 8)) { return false; }714 var reason = this._sock.rQshiftStr(length);715 return this._fail(reason);716 } else {717 return this._fail("Authentication failure");718 }719 return false;720 case 2:721 return this._fail("Too many auth attempts");722 }723 },724 _negotiate_server_init: function () {725 if (this._sock.rQwait("server initialization", 24)) { return false; }726 /* Screen size */727 this._fb_width = this._sock.rQshift16();728 this._fb_height = this._sock.rQshift16();729 /* PIXEL_FORMAT */730 var bpp = this._sock.rQshift8();731 var depth = this._sock.rQshift8();732 var big_endian = this._sock.rQshift8();733 var true_color = this._sock.rQshift8();734 var red_max = this._sock.rQshift16();735 var green_max = this._sock.rQshift16();736 var blue_max = this._sock.rQshift16();737 var red_shift = this._sock.rQshift8();738 var green_shift = this._sock.rQshift8();739 var blue_shift = this._sock.rQshift8();740 this._sock.rQskipBytes(3); // padding741 // NB(directxman12): we don't want to call any callbacks or print messages until742 // *after* we're past the point where we could backtrack743 /* Connection name/title */744 var name_length = this._sock.rQshift32();745 if (this._sock.rQwait('server init name', name_length, 24)) { return false; }746 this._fb_name = Util.decodeUTF8(this._sock.rQshiftStr(name_length));747 if (this._rfb_tightvnc) {748 if (this._sock.rQwait('TightVNC extended server init header', 8, 24 + name_length)) { return false; }749 // In TightVNC mode, ServerInit message is extended750 var numServerMessages = this._sock.rQshift16();751 var numClientMessages = this._sock.rQshift16();752 var numEncodings = this._sock.rQshift16();753 this._sock.rQskipBytes(2); // padding754 var totalMessagesLength = (numServerMessages + numClientMessages + numEncodings) * 16;755 if (this._sock.rQwait('TightVNC extended server init header', totalMessagesLength, 32 + name_length)) { return false; }756 var i;757 for (i = 0; i < numServerMessages; i++) {758 var srvMsg = this._sock.rQshiftStr(16);759 }760 for (i = 0; i < numClientMessages; i++) {761 var clientMsg = this._sock.rQshiftStr(16);762 }763 for (i = 0; i < numEncodings; i++) {764 var encoding = this._sock.rQshiftStr(16);765 }766 }767 // NB(directxman12): these are down here so that we don't run them multiple times768 // if we backtrack769 Util.Info("Screen: " + this._fb_width + "x" + this._fb_height +770 ", bpp: " + bpp + ", depth: " + depth +771 ", big_endian: " + big_endian +772 ", true_color: " + true_color +773 ", red_max: " + red_max +774 ", green_max: " + green_max +775 ", blue_max: " + blue_max +776 ", red_shift: " + red_shift +777 ", green_shift: " + green_shift +778 ", blue_shift: " + blue_shift);779 if (big_endian !== 0) {780 Util.Warn("Server native endian is not little endian");781 }782 if (red_shift !== 16) {783 Util.Warn("Server native red-shift is not 16");784 }785 if (blue_shift !== 0) {786 Util.Warn("Server native blue-shift is not 0");787 }788 // we're past the point where we could backtrack, so it's safe to call this789 this._onDesktopName(this, this._fb_name);790 if (this._true_color && this._fb_name === "Intel(r) AMT KVM") {791 Util.Warn("Intel AMT KVM only supports 8/16 bit depths. Disabling true color");792 this._true_color = false;793 }794 this._display.set_true_color(this._true_color);795 this._onFBResize(this, this._fb_width, this._fb_height);796 this._display.resize(this._fb_width, this._fb_height);797 this._keyboard.grab();798 this._mouse.grab();799 if (this._true_color) {800 this._fb_Bpp = 4;801 this._fb_depth = 3;802 } else {803 this._fb_Bpp = 1;804 this._fb_depth = 1;805 }806 var response = RFB.messages.pixelFormat(this._fb_Bpp, this._fb_depth, this._true_color);807 response = response.concat(808 RFB.messages.clientEncodings(this._encodings, this._local_cursor, this._true_color));809 response = response.concat(810 RFB.messages.fbUpdateRequests(this._display.getCleanDirtyReset(),811 this._fb_width, this._fb_height));812 this._timing.fbu_rt_start = (new Date()).getTime();813 this._timing.pixels = 0;814 this._sock.send(response);815 this._checkEvents();816 if (this._encrypt) {817 this._updateState('normal', 'Connected (encrypted) to: ' + this._fb_name);818 } else {819 this._updateState('normal', 'Connected (unencrypted) to: ' + this._fb_name);820 }821 },822 _init_msg: function () {823 switch (this._rfb_state) {824 case 'ProtocolVersion':825 return this._negotiate_protocol_version();826 case 'Security':827 return this._negotiate_security();828 case 'Authentication':829 return this._negotiate_authentication();830 case 'SecurityResult':831 return this._handle_security_result();832 case 'ClientInitialisation':833 this._sock.send([this._shared ? 1 : 0]); // ClientInitialisation834 this._updateState('ServerInitialisation', "Authentication OK");835 return true;836 case 'ServerInitialisation':837 return this._negotiate_server_init();838 }839 },840 _handle_set_colour_map_msg: function () {841 Util.Debug("SetColorMapEntries");842 this._sock.rQskip8(); // Padding843 var first_colour = this._sock.rQshift16();844 var num_colours = this._sock.rQshift16();845 if (this._sock.rQwait('SetColorMapEntries', num_colours * 6, 6)) { return false; }846 for (var c = 0; c < num_colours; c++) {847 var red = parseInt(this._sock.rQshift16() / 256, 10);848 var green = parseInt(this._sock.rQshift16() / 256, 10);849 var blue = parseInt(this._sock.rQshift16() / 256, 10);850 this._display.set_colourMap([blue, green, red], first_colour + c);851 }852 Util.Debug("colourMap: " + this._display.get_colourMap());853 Util.Info("Registered " + num_colours + " colourMap entries");854 return true;855 },856 _handle_server_cut_text: function () {857 Util.Debug("ServerCutText");858 if (this._sock.rQwait("ServerCutText header", 7, 1)) { return false; }859 this._sock.rQskipBytes(3); // Padding860 var length = this._sock.rQshift32();861 if (this._sock.rQwait("ServerCutText", length, 8)) { return false; }862 var text = this._sock.rQshiftStr(length);863 this._onClipboard(this, text);864 return true;865 },866 _handle_xvp_msg: function () {867 if (this._sock.rQwait("XVP version and message", 3, 1)) { return false; }868 this._sock.rQskip8(); // Padding869 var xvp_ver = this._sock.rQshift8();870 var xvp_msg = this._sock.rQshift8();871 switch (xvp_msg) {872 case 0: // XVP_FAIL873 this._updateState(this._rfb_state, "Operation Failed");874 break;875 case 1: // XVP_INIT876 this._rfb_xvp_ver = xvp_ver;877 Util.Info("XVP extensions enabled (version " + this._rfb_xvp_ver + ")");878 this._onXvpInit(this._rfb_xvp_ver);879 break;880 default:881 this._fail("Disconnected: illegal server XVP message " + xvp_msg);882 break;883 }884 return true;885 },886 _normal_msg: function () {887 var msg_type;888 if (this._FBU.rects > 0) {889 msg_type = 0;890 } else {891 msg_type = this._sock.rQshift8();892 }893 switch (msg_type) {894 case 0: // FramebufferUpdate895 var ret = this._framebufferUpdate();896 if (ret) {897 this._sock.send(RFB.messages.fbUpdateRequests(this._display.getCleanDirtyReset(),898 this._fb_width, this._fb_height));899 }900 return ret;901 case 1: // SetColorMapEntries902 return this._handle_set_colour_map_msg();903 case 2: // Bell904 Util.Debug("Bell");905 this._onBell(this);906 return true;907 case 3: // ServerCutText908 return this._handle_server_cut_text();909 case 250: // XVP910 return this._handle_xvp_msg();911 default:912 this._fail("Disconnected: illegal server message type " + msg_type);913 Util.Debug("sock.rQslice(0, 30): " + this._sock.rQslice(0, 30));914 return true;915 }916 },917 _framebufferUpdate: function () {918 var ret = true;919 var now;920 if (this._FBU.rects === 0) {921 if (this._sock.rQwait("FBU header", 3, 1)) { return false; }922 this._sock.rQskip8(); // Padding923 this._FBU.rects = this._sock.rQshift16();924 this._FBU.bytes = 0;925 this._timing.cur_fbu = 0;926 if (this._timing.fbu_rt_start > 0) {927 now = (new Date()).getTime();928 Util.Info("First FBU latency: " + (now - this._timing.fbu_rt_start));929 }930 }931 while (this._FBU.rects > 0) {932 if (this._rfb_state !== "normal") { return false; }933 if (this._sock.rQwait("FBU", this._FBU.bytes)) { return false; }934 if (this._FBU.bytes === 0) {935 if (this._sock.rQwait("rect header", 12)) { return false; }936 /* New FramebufferUpdate */937 var hdr = this._sock.rQshiftBytes(12);938 this._FBU.x = (hdr[0] << 8) + hdr[1];939 this._FBU.y = (hdr[2] << 8) + hdr[3];940 this._FBU.width = (hdr[4] << 8) + hdr[5];941 this._FBU.height = (hdr[6] << 8) + hdr[7];942 this._FBU.encoding = parseInt((hdr[8] << 24) + (hdr[9] << 16) +943 (hdr[10] << 8) + hdr[11], 10);944 this._onFBUReceive(this,945 {'x': this._FBU.x, 'y': this._FBU.y,946 'width': this._FBU.width, 'height': this._FBU.height,947 'encoding': this._FBU.encoding,948 'encodingName': this._encNames[this._FBU.encoding]});949 if (!this._encNames[this._FBU.encoding]) {950 this._fail("Disconnected: unsupported encoding " +951 this._FBU.encoding);952 return false;953 }954 }955 this._timing.last_fbu = (new Date()).getTime();956 ret = this._encHandlers[this._FBU.encoding]();957 now = (new Date()).getTime();958 this._timing.cur_fbu += (now - this._timing.last_fbu);959 if (ret) {960 this._encStats[this._FBU.encoding][0]++;961 this._encStats[this._FBU.encoding][1]++;962 this._timing.pixels += this._FBU.width * this._FBU.height;963 }964 if (this._timing.pixels >= (this._fb_width * this._fb_height)) {965 if ((this._FBU.width === this._fb_width && this._FBU.height === this._fb_height) ||966 this._timing.fbu_rt_start > 0) {967 this._timing.full_fbu_total += this._timing.cur_fbu;968 this._timing.full_fbu_cnt++;969 Util.Info("Timing of full FBU, curr: " +970 this._timing.cur_fbu + ", total: " +971 this._timing.full_fbu_total + ", cnt: " +972 this._timing.full_fbu_cnt + ", avg: " +973 (this._timing.full_fbu_total / this._timing.full_fbu_cnt));974 }975 if (this._timing.fbu_rt_start > 0) {976 var fbu_rt_diff = now - this._timing.fbu_rt_start;977 this._timing.fbu_rt_total += fbu_rt_diff;978 this._timing.fbu_rt_cnt++;979 Util.Info("full FBU round-trip, cur: " +980 fbu_rt_diff + ", total: " +981 this._timing.fbu_rt_total + ", cnt: " +982 this._timing.fbu_rt_cnt + ", avg: " +983 (this._timing.fbu_rt_total / this._timing.fbu_rt_cnt));984 this._timing.fbu_rt_start = 0;985 }986 }987 if (!ret) { return ret; } // need more data988 }989 this._onFBUComplete(this,990 {'x': this._FBU.x, 'y': this._FBU.y,991 'width': this._FBU.width, 'height': this._FBU.height,992 'encoding': this._FBU.encoding,993 'encodingName': this._encNames[this._FBU.encoding]});994 return true; // We finished this FBU995 },996 };997 Util.make_properties(RFB, [998 ['target', 'wo', 'dom'], // VNC display rendering Canvas object999 ['focusContainer', 'wo', 'dom'], // DOM element that captures keyboard input1000 ['encrypt', 'rw', 'bool'], // Use TLS/SSL/wss encryption1001 ['true_color', 'rw', 'bool'], // Request true color pixel data1002 ['local_cursor', 'rw', 'bool'], // Request locally rendered cursor1003 ['shared', 'rw', 'bool'], // Request shared mode1004 ['view_only', 'rw', 'bool'], // Disable client mouse/keyboard1005 ['xvp_password_sep', 'rw', 'str'], // Separator for XVP password fields1006 ['disconnectTimeout', 'rw', 'int'], // Time (s) to wait for disconnection1007 ['wsProtocols', 'rw', 'arr'], // Protocols to use in the WebSocket connection1008 ['repeaterID', 'rw', 'str'], // [UltraVNC] RepeaterID to connect to1009 ['viewportDrag', 'rw', 'bool'], // Move the viewport on mouse drags1010 // Callback functions1011 ['onUpdateState', 'rw', 'func'], // onUpdateState(rfb, state, oldstate, statusMsg): RFB state update/change1012 ['onPasswordRequired', 'rw', 'func'], // onPasswordRequired(rfb): VNC password is required1013 ['onClipboard', 'rw', 'func'], // onClipboard(rfb, text): RFB clipboard contents received1014 ['onBell', 'rw', 'func'], // onBell(rfb): RFB Bell message received1015 ['onFBUReceive', 'rw', 'func'], // onFBUReceive(rfb, fbu): RFB FBU received but not yet processed1016 ['onFBUComplete', 'rw', 'func'], // onFBUComplete(rfb, fbu): RFB FBU received and processed1017 ['onFBResize', 'rw', 'func'], // onFBResize(rfb, width, height): frame buffer resized1018 ['onDesktopName', 'rw', 'func'], // onDesktopName(rfb, name): desktop name received1019 ['onXvpInit', 'rw', 'func'], // onXvpInit(version): XVP extensions active for this connection1020 ]);1021 RFB.prototype.set_local_cursor = function (cursor) {1022 if (!cursor || (cursor in {'0': 1, 'no': 1, 'false': 1})) {1023 this._local_cursor = false;1024 } else {1025 if (this._display.get_cursor_uri()) {1026 this._local_cursor = true;1027 } else {1028 Util.Warn("Browser does not support local cursor");1029 }1030 }1031 };1032 RFB.prototype.get_display = function () { return this._display; };1033 RFB.prototype.get_keyboard = function () { return this._keyboard; };1034 RFB.prototype.get_mouse = function () { return this._mouse; };1035 // Class Methods1036 RFB.messages = {1037 keyEvent: function (keysym, down) {1038 var arr = [4];1039 arr.push8(down);1040 arr.push16(0);1041 arr.push32(keysym);1042 return arr;1043 },1044 pointerEvent: function (x, y, mask) {1045 var arr = [5]; // msg-type1046 arr.push8(mask);1047 arr.push16(x);1048 arr.push16(y);1049 return arr;1050 },1051 // TODO(directxman12): make this unicode compatible?1052 clientCutText: function (text) {1053 var arr = [6]; // msg-type1054 arr.push8(0); // padding1055 arr.push8(0); // padding1056 arr.push8(0); // padding1057 arr.push32(text.length);1058 var n = text.length;1059 for (var i = 0; i < n; i++) {1060 arr.push(text.charCodeAt(i));1061 }1062 return arr;1063 },1064 pixelFormat: function (bpp, depth, true_color) {1065 var arr = [0]; // msg-type1066 arr.push8(0); // padding1067 arr.push8(0); // padding1068 arr.push8(0); // padding1069 arr.push8(bpp * 8); // bits-per-pixel1070 arr.push8(depth * 8); // depth1071 arr.push8(0); // little-endian1072 arr.push8(true_color ? 1 : 0); // true-color1073 arr.push16(255); // red-max1074 arr.push16(255); // green-max1075 arr.push16(255); // blue-max1076 arr.push8(16); // red-shift1077 arr.push8(8); // green-shift1078 arr.push8(0); // blue-shift1079 arr.push8(0); // padding1080 arr.push8(0); // padding1081 arr.push8(0); // padding1082 return arr;1083 },1084 clientEncodings: function (encodings, local_cursor, true_color) {1085 var i, encList = [];1086 for (i = 0; i < encodings.length; i++) {1087 if (encodings[i][0] === "Cursor" && !local_cursor) {1088 Util.Debug("Skipping Cursor pseudo-encoding");1089 } else if (encodings[i][0] === "TIGHT" && !true_color) {1090 // TODO: remove this when we have tight+non-true-color1091 Util.Warn("Skipping tight as it is only supported with true color");1092 } else {1093 encList.push(encodings[i][1]);1094 }1095 }1096 var arr = [2]; // msg-type1097 arr.push8(0); // padding1098 arr.push16(encList.length); // encoding count1099 for (i = 0; i < encList.length; i++) {1100 arr.push32(encList[i]);1101 }1102 return arr;1103 },1104 fbUpdateRequests: function (cleanDirty, fb_width, fb_height) {1105 var arr = [];1106 var cb = cleanDirty.cleanBox;1107 var w, h;1108 if (cb.w > 0 && cb.h > 0) {1109 w = typeof cb.w === "undefined" ? fb_width : cb.w;1110 h = typeof cb.h === "undefined" ? fb_height : cb.h;1111 // Request incremental for clean box1112 arr = arr.concat(RFB.messages.fbUpdateRequest(1, cb.x, cb.y, w, h));1113 }1114 for (var i = 0; i < cleanDirty.dirtyBoxes.length; i++) {1115 var db = cleanDirty.dirtyBoxes[i];1116 // Force all (non-incremental) for dirty box1117 w = typeof db.w === "undefined" ? fb_width : db.w;1118 h = typeof db.h === "undefined" ? fb_height : db.h;1119 arr = arr.concat(RFB.messages.fbUpdateRequest(0, db.x, db.y, w, h));1120 }1121 return arr;1122 },1123 fbUpdateRequest: function (incremental, x, y, w, h) {1124 if (typeof(x) === "undefined") { x = 0; }1125 if (typeof(y) === "undefined") { y = 0; }1126 var arr = [3]; // msg-type1127 arr.push8(incremental);1128 arr.push16(x);1129 arr.push16(y);1130 arr.push16(w);1131 arr.push16(h);1132 return arr;1133 }1134 };1135 RFB.genDES = function (password, challenge) {1136 var passwd = [];1137 for (var i = 0; i < password.length; i++) {1138 passwd.push(password.charCodeAt(i));1139 }1140 return (new DES(passwd)).encrypt(challenge);1141 };1142 RFB.extract_data_uri = function (arr) {1143 return ";base64," + Base64.encode(arr);1144 };1145 RFB.encodingHandlers = {1146 RAW: function () {1147 if (this._FBU.lines === 0) {1148 this._FBU.lines = this._FBU.height;1149 }1150 this._FBU.bytes = this._FBU.width * this._fb_Bpp; // at least a line1151 if (this._sock.rQwait("RAW", this._FBU.bytes)) { return false; }1152 var cur_y = this._FBU.y + (this._FBU.height - this._FBU.lines);1153 var curr_height = Math.min(this._FBU.lines,1154 Math.floor(this._sock.rQlen() / (this._FBU.width * this._fb_Bpp)));1155 this._display.blitImage(this._FBU.x, cur_y, this._FBU.width,1156 curr_height, this._sock.get_rQ(),1157 this._sock.get_rQi());1158 this._sock.rQskipBytes(this._FBU.width * curr_height * this._fb_Bpp);1159 this._FBU.lines -= curr_height;1160 if (this._FBU.lines > 0) {1161 this._FBU.bytes = this._FBU.width * this._fb_Bpp; // At least another line1162 } else {1163 this._FBU.rects--;1164 this._FBU.bytes = 0;1165 }1166 return true;1167 },1168 COPYRECT: function () {1169 this._FBU.bytes = 4;1170 if (this._sock.rQwait("COPYRECT", 4)) { return false; }1171 this._display.renderQ_push({1172 'type': 'copy',1173 'old_x': this._sock.rQshift16(),1174 'old_y': this._sock.rQshift16(),1175 'x': this._FBU.x,1176 'y': this._FBU.y,1177 'width': this._FBU.width,1178 'height': this._FBU.height1179 });1180 this._FBU.rects--;1181 this._FBU.bytes = 0;1182 return true;1183 },1184 RRE: function () {1185 var color;1186 if (this._FBU.subrects === 0) {1187 this._FBU.bytes = 4 + this._fb_Bpp;1188 if (this._sock.rQwait("RRE", 4 + this._fb_Bpp)) { return false; }1189 this._FBU.subrects = this._sock.rQshift32();1190 color = this._sock.rQshiftBytes(this._fb_Bpp); // Background1191 this._display.fillRect(this._FBU.x, this._FBU.y, this._FBU.width, this._FBU.height, color);1192 }1193 while (this._FBU.subrects > 0 && this._sock.rQlen() >= (this._fb_Bpp + 8)) {1194 color = this._sock.rQshiftBytes(this._fb_Bpp);1195 var x = this._sock.rQshift16();1196 var y = this._sock.rQshift16();1197 var width = this._sock.rQshift16();1198 var height = this._sock.rQshift16();1199 this._display.fillRect(this._FBU.x + x, this._FBU.y + y, width, height, color);1200 this._FBU.subrects--;1201 }1202 if (this._FBU.subrects > 0) {1203 var chunk = Math.min(this._rre_chunk_sz, this._FBU.subrects);1204 this._FBU.bytes = (this._fb_Bpp + 8) * chunk;1205 } else {1206 this._FBU.rects--;1207 this._FBU.bytes = 0;1208 }1209 return true;1210 },1211 HEXTILE: function () {1212 var rQ = this._sock.get_rQ();1213 var rQi = this._sock.get_rQi();1214 if (this._FBU.tiles === 0) {1215 this._FBU.tiles_x = Math.ceil(this._FBU.width / 16);1216 this._FBU.tiles_y = Math.ceil(this._FBU.height / 16);1217 this._FBU.total_tiles = this._FBU.tiles_x * this._FBU.tiles_y;1218 this._FBU.tiles = this._FBU.total_tiles;1219 }1220 while (this._FBU.tiles > 0) {1221 this._FBU.bytes = 1;1222 if (this._sock.rQwait("HEXTILE subencoding", this._FBU.bytes)) { return false; }1223 var subencoding = rQ[rQi]; // Peek1224 if (subencoding > 30) { // Raw1225 this._fail("Disconnected: illegal hextile subencoding " + subencoding);1226 return false;1227 }1228 var subrects = 0;1229 var curr_tile = this._FBU.total_tiles - this._FBU.tiles;1230 var tile_x = curr_tile % this._FBU.tiles_x;1231 var tile_y = Math.floor(curr_tile / this._FBU.tiles_x);1232 var x = this._FBU.x + tile_x * 16;1233 var y = this._FBU.y + tile_y * 16;1234 var w = Math.min(16, (this._FBU.x + this._FBU.width) - x);1235 var h = Math.min(16, (this._FBU.y + this._FBU.height) - y);1236 // Figure out how much we are expecting1237 if (subencoding & 0x01) { // Raw1238 this._FBU.bytes += w * h * this._fb_Bpp;1239 } else {1240 if (subencoding & 0x02) { // Background1241 this._FBU.bytes += this._fb_Bpp;1242 }1243 if (subencoding & 0x04) { // Foreground1244 this._FBU.bytes += this._fb_Bpp;1245 }1246 if (subencoding & 0x08) { // AnySubrects1247 this._FBU.bytes++; // Since we aren't shifting it off1248 if (this._sock.rQwait("hextile subrects header", this._FBU.bytes)) { return false; }1249 subrects = rQ[rQi + this._FBU.bytes - 1]; // Peek1250 if (subencoding & 0x10) { // SubrectsColoured1251 this._FBU.bytes += subrects * (this._fb_Bpp + 2);1252 } else {1253 this._FBU.bytes += subrects * 2;1254 }1255 }1256 }1257 if (this._sock.rQwait("hextile", this._FBU.bytes)) { return false; }1258 // We know the encoding and have a whole tile1259 this._FBU.subencoding = rQ[rQi];1260 rQi++;1261 if (this._FBU.subencoding === 0) {1262 if (this._FBU.lastsubencoding & 0x01) {1263 // Weird: ignore blanks are RAW1264 Util.Debug(" Ignoring blank after RAW");1265 } else {1266 this._display.fillRect(x, y, w, h, this._FBU.background);1267 }1268 } else if (this._FBU.subencoding & 0x01) { // Raw1269 this._display.blitImage(x, y, w, h, rQ, rQi);1270 rQi += this._FBU.bytes - 1;1271 } else {1272 if (this._FBU.subencoding & 0x02) { // Background1273 this._FBU.background = rQ.slice(rQi, rQi + this._fb_Bpp);1274 rQi += this._fb_Bpp;1275 }1276 if (this._FBU.subencoding & 0x04) { // Foreground1277 this._FBU.foreground = rQ.slice(rQi, rQi + this._fb_Bpp);1278 rQi += this._fb_Bpp;1279 }1280 this._display.startTile(x, y, w, h, this._FBU.background);1281 if (this._FBU.subencoding & 0x08) { // AnySubrects1282 subrects = rQ[rQi];1283 rQi++;1284 for (var s = 0; s < subrects; s++) {1285 var color;1286 if (this._FBU.subencoding & 0x10) { // SubrectsColoured1287 color = rQ.slice(rQi, rQi + this._fb_Bpp);1288 rQi += this._fb_Bpp;1289 } else {1290 color = this._FBU.foreground;1291 }1292 var xy = rQ[rQi];1293 rQi++;1294 var sx = (xy >> 4);1295 var sy = (xy & 0x0f);1296 var wh = rQ[rQi];1297 rQi++;1298 var sw = (wh >> 4) + 1;1299 var sh = (wh & 0x0f) + 1;1300 this._display.subTile(sx, sy, sw, sh, color);1301 }1302 }1303 this._display.finishTile();1304 }1305 this._sock.set_rQi(rQi);1306 this._FBU.lastsubencoding = this._FBU.subencoding;1307 this._FBU.bytes = 0;1308 this._FBU.tiles--;1309 }1310 if (this._FBU.tiles === 0) {1311 this._FBU.rects--;1312 }1313 return true;1314 },1315 getTightCLength: function (arr) {1316 var header = 1, data = 0;1317 data += arr[0] & 0x7f;1318 if (arr[0] & 0x80) {1319 header++;1320 data += (arr[1] & 0x7f) << 7;1321 if (arr[1] & 0x80) {1322 header++;1323 data += arr[2] << 14;1324 }1325 }1326 return [header, data];1327 },1328 display_tight: function (isTightPNG) {1329 if (this._fb_depth === 1) {1330 this._fail("Tight protocol handler only implements true color mode");1331 }1332 this._FBU.bytes = 1; // compression-control byte1333 if (this._sock.rQwait("TIGHT compression-control", this._FBU.bytes)) { return false; }1334 var checksum = function (data) {1335 var sum = 0;1336 for (var i = 0; i < data.length; i++) {1337 sum += data[i];1338 if (sum > 65536) sum -= 65536;1339 }1340 return sum;1341 };1342 var resetStreams = 0;1343 var streamId = -1;1344 var decompress = function (data) {1345 for (var i = 0; i < 4; i++) {1346 if ((resetStreams >> i) & 1) {1347 this._FBU.zlibs[i].reset();1348 Util.Info("Reset zlib stream " + i);1349 }1350 }1351 var uncompressed = this._FBU.zlibs[streamId].uncompress(data, 0);1352 if (uncompressed.status !== 0) {1353 Util.Error("Invalid data in zlib stream");1354 }1355 return uncompressed.data;1356 }.bind(this);1357 var indexedToRGB = function (data, numColors, palette, width, height) {1358 // Convert indexed (palette based) image data to RGB1359 // TODO: reduce number of calculations inside loop1360 var dest = [];1361 var x, y, dp, sp;1362 if (numColors === 2) {1363 var w = Math.floor((width + 7) / 8);1364 var w1 = Math.floor(width / 8);1365 for (y = 0; y < height; y++) {1366 var b;1367 for (x = 0; x < w1; x++) {1368 for (b = 7; b >= 0; b--) {1369 dp = (y * width + x * 8 + 7 - b) * 3;1370 sp = (data[y * w + x] >> b & 1) * 3;1371 dest[dp] = palette[sp];1372 dest[dp + 1] = palette[sp + 1];1373 dest[dp + 2] = palette[sp + 2];1374 }1375 }1376 for (b = 7; b >= 8 - width % 8; b--) {1377 dp = (y * width + x * 8 + 7 - b) * 3;1378 sp = (data[y * w + x] >> b & 1) * 3;1379 dest[dp] = palette[sp];1380 dest[dp + 1] = palette[sp + 1];1381 dest[dp + 2] = palette[sp + 2];1382 }1383 }1384 } else {1385 for (y = 0; y < height; y++) {1386 for (x = 0; x < width; x++) {1387 dp = (y * width + x) * 3;1388 sp = data[y * width + x] * 3;1389 dest[dp] = palette[sp];1390 dest[dp + 1] = palette[sp + 1];1391 dest[dp + 2] = palette[sp + 2];1392 }1393 }1394 }1395 return dest;1396 }.bind(this);1397 var rQ = this._sock.get_rQ();1398 var rQi = this._sock.get_rQi();1399 var cmode, clength, data;1400 var handlePalette = function () {1401 var numColors = rQ[rQi + 2] + 1;1402 var paletteSize = numColors * this._fb_depth;1403 this._FBU.bytes += paletteSize;1404 if (this._sock.rQwait("TIGHT palette " + cmode, this._FBU.bytes)) { return false; }1405 var bpp = (numColors <= 2) ? 1 : 8;1406 var rowSize = Math.floor((this._FBU.width * bpp + 7) / 8);1407 var raw = false;1408 if (rowSize * this._FBU.height < 12) {1409 raw = true;1410 clength = [0, rowSize * this._FBU.height];1411 } else {1412 clength = RFB.encodingHandlers.getTightCLength(this._sock.rQslice(3 + paletteSize,1413 3 + paletteSize + 3));1414 }1415 this._FBU.bytes += clength[0] + clength[1];1416 if (this._sock.rQwait("TIGHT " + cmode, this._FBU.bytes)) { return false; }1417 // Shift ctl, filter id, num colors, palette entries, and clength off1418 this._sock.rQskipBytes(3);1419 var palette = this._sock.rQshiftBytes(paletteSize);1420 this._sock.rQskipBytes(clength[0]);1421 if (raw) {1422 data = this._sock.rQshiftBytes(clength[1]);1423 } else {1424 data = decompress(this._sock.rQshiftBytes(clength[1]));1425 }1426 // Convert indexed (palette based) image data to RGB1427 var rgb = indexedToRGB(data, numColors, palette, this._FBU.width, this._FBU.height);1428 this._display.renderQ_push({1429 'type': 'blitRgb',1430 'data': rgb,1431 'x': this._FBU.x,1432 'y': this._FBU.y,1433 'width': this._FBU.width,1434 'height': this._FBU.height1435 });1436 return true;1437 }.bind(this);1438 var handleCopy = function () {1439 var raw = false;1440 var uncompressedSize = this._FBU.width * this._FBU.height * this._fb_depth;1441 if (uncompressedSize < 12) {1442 raw = true;1443 clength = [0, uncompressedSize];1444 } else {1445 clength = RFB.encodingHandlers.getTightCLength(this._sock.rQslice(1, 4));1446 }1447 this._FBU.bytes = 1 + clength[0] + clength[1];1448 if (this._sock.rQwait("TIGHT " + cmode, this._FBU.bytes)) { return false; }1449 // Shift ctl, clength off1450 this._sock.rQshiftBytes(1 + clength[0]);1451 if (raw) {1452 data = this._sock.rQshiftBytes(clength[1]);1453 } else {1454 data = decompress(this._sock.rQshiftBytes(clength[1]));1455 }1456 this._display.renderQ_push({1457 'type': 'blitRgb',1458 'data': data,1459 'x': this._FBU.x,1460 'y': this._FBU.y,1461 'width': this._FBU.width,1462 'height': this._FBU.height1463 });1464 return true;1465 }.bind(this);1466 var ctl = this._sock.rQpeek8();1467 // Keep tight reset bits1468 resetStreams = ctl & 0xF;1469 // Figure out filter1470 ctl = ctl >> 4;1471 streamId = ctl & 0x3;1472 if (ctl === 0x08) cmode = "fill";1473 else if (ctl === 0x09) cmode = "jpeg";1474 else if (ctl === 0x0A) cmode = "png";1475 else if (ctl & 0x04) cmode = "filter";1476 else if (ctl < 0x04) cmode = "copy";1477 else return this._fail("Illegal tight compression received, ctl: " + ctl);1478 if (isTightPNG && (cmode === "filter" || cmode === "copy")) {1479 return this._fail("filter/copy received in tightPNG mode");1480 }1481 switch (cmode) {1482 // fill use fb_depth because TPIXELs drop the padding byte1483 case "fill": // TPIXEL1484 this._FBU.bytes += this._fb_depth;1485 break;1486 case "jpeg": // max clength1487 this._FBU.bytes += 3;1488 break;1489 case "png": // max clength1490 this._FBU.bytes += 3;1491 break;1492 case "filter": // filter id + num colors if palette1493 this._FBU.bytes += 2;1494 break;1495 case "copy":1496 break;1497 }1498 if (this._sock.rQwait("TIGHT " + cmode, this._FBU.bytes)) { return false; }1499 // Determine FBU.bytes1500 switch (cmode) {1501 case "fill":1502 this._sock.rQskip8(); // shift off ctl1503 var color = this._sock.rQshiftBytes(this._fb_depth);1504 this._display.renderQ_push({1505 'type': 'fill',1506 'x': this._FBU.x,1507 'y': this._FBU.y,1508 'width': this._FBU.width,1509 'height': this._FBU.height,1510 'color': [color[2], color[1], color[0]]1511 });1512 break;1513 case "png":1514 case "jpeg":1515 clength = RFB.encodingHandlers.getTightCLength(this._sock.rQslice(1, 4));1516 this._FBU.bytes = 1 + clength[0] + clength[1]; // ctl + clength size + jpeg-data1517 if (this._sock.rQwait("TIGHT " + cmode, this._FBU.bytes)) { return false; }1518 // We have everything, render it1519 this._sock.rQskipBytes(1 + clength[0]); // shift off clt + compact length1520 var img = new Image();1521 img.src = "data: image/" + cmode +1522 RFB.extract_data_uri(this._sock.rQshiftBytes(clength[1]));1523 this._display.renderQ_push({1524 'type': 'img',1525 'img': img,1526 'x': this._FBU.x,1527 'y': this._FBU.y1528 });1529 img = null;1530 break;1531 case "filter":1532 var filterId = rQ[rQi + 1];1533 if (filterId === 1) {1534 if (!handlePalette()) { return false; }1535 } else {1536 // Filter 0, Copy could be valid here, but servers don't send it as an explicit filter1537 // Filter 2, Gradient is valid but not use if jpeg is enabled1538 // TODO(directxman12): why aren't we just calling '_fail' here1539 throw new Error("Unsupported tight subencoding received, filter: " + filterId);1540 }1541 break;1542 case "copy":1543 if (!handleCopy()) { return false; }1544 break;1545 }1546 this._FBU.bytes = 0;1547 this._FBU.rects--;1548 return true;1549 },1550 TIGHT: function () { return this._encHandlers.display_tight(false); },1551 TIGHT_PNG: function () { return this._encHandlers.display_tight(true); },1552 last_rect: function () {1553 this._FBU.rects = 0;1554 return true;1555 },1556 DesktopSize: function () {1557 Util.Debug(">> set_desktopsize");1558 this._fb_width = this._FBU.width;1559 this._fb_height = this._FBU.height;1560 this._onFBResize(this, this._fb_width, this._fb_height);1561 this._display.resize(this._fb_width, this._fb_height);1562 this._timing.fbu_rt_start = (new Date()).getTime();1563 this._FBU.bytes = 0;1564 this._FBU.rects--;1565 Util.Debug("<< set_desktopsize");1566 return true;1567 },1568 Cursor: function () {1569 Util.Debug(">> set_cursor");1570 var x = this._FBU.x; // hotspot-x1571 var y = this._FBU.y; // hotspot-y1572 var w = this._FBU.width;1573 var h = this._FBU.height;1574 var pixelslength = w * h * this._fb_Bpp;1575 var masklength = Math.floor((w + 7) / 8) * h;1576 this._FBU.bytes = pixelslength + masklength;1577 if (this._sock.rQwait("cursor encoding", this._FBU.bytes)) { return false; }1578 this._display.changeCursor(this._sock.rQshiftBytes(pixelslength),1579 this._sock.rQshiftBytes(masklength),1580 x, y, w, h);1581 this._FBU.bytes = 0;1582 this._FBU.rects--;1583 Util.Debug("<< set_cursor");1584 return true;1585 },1586 JPEG_quality_lo: function () {1587 Util.Error("Server sent jpeg_quality pseudo-encoding");1588 },1589 compress_lo: function () {1590 Util.Error("Server sent compress level pseudo-encoding");1591 }...
tight.js
Source:tight.js
...24 }25 }26 decodeRect(x, y, width, height, sock, display, depth) {27 if (this._ctl === null) {28 if (sock.rQwait("TIGHT compression-control", 1)) {29 return false;30 }31 this._ctl = sock.rQshift8();32 // Reset streams if the server requests it33 for (let i = 0; i < 4; i++) {34 if ((this._ctl >> i) & 1) {35 this._zlibs[i].reset();36 Log.Info("Reset zlib stream " + i);37 }38 }39 // Figure out filter40 this._ctl = this._ctl >> 4;41 }42 let ret;43 if (this._ctl === 0x08) {44 ret = this._fillRect(x, y, width, height,45 sock, display, depth);46 } else if (this._ctl === 0x09) {47 ret = this._jpegRect(x, y, width, height,48 sock, display, depth);49 } else if (this._ctl === 0x0A) {50 ret = this._pngRect(x, y, width, height,51 sock, display, depth);52 } else if ((this._ctl & 0x80) == 0) {53 ret = this._basicRect(this._ctl, x, y, width, height,54 sock, display, depth);55 } else {56 throw new Error("Illegal tight compression received (ctl: " +57 this._ctl + ")");58 }59 if (ret) {60 this._ctl = null;61 }62 return ret;63 }64 _fillRect(x, y, width, height, sock, display, depth) {65 if (sock.rQwait("TIGHT", 3)) {66 return false;67 }68 const rQi = sock.rQi;69 const rQ = sock.rQ;70 display.fillRect(x, y, width, height,71 [rQ[rQi + 2], rQ[rQi + 1], rQ[rQi]], false);72 sock.rQskipBytes(3);73 return true;74 }75 _jpegRect(x, y, width, height, sock, display, depth) {76 let data = this._readData(sock);77 if (data === null) {78 return false;79 }80 display.imageRect(x, y, "image/jpeg", data);81 return true;82 }83 _pngRect(x, y, width, height, sock, display, depth) {84 throw new Error("PNG received in standard Tight rect");85 }86 _basicRect(ctl, x, y, width, height, sock, display, depth) {87 if (this._filter === null) {88 if (ctl & 0x4) {89 if (sock.rQwait("TIGHT", 1)) {90 return false;91 }92 this._filter = sock.rQshift8();93 } else {94 // Implicit CopyFilter95 this._filter = 0;96 }97 }98 let streamId = ctl & 0x3;99 let ret;100 switch (this._filter) {101 case 0: // CopyFilter102 ret = this._copyFilter(streamId, x, y, width, height,103 sock, display, depth);104 break;105 case 1: // PaletteFilter106 ret = this._paletteFilter(streamId, x, y, width, height,107 sock, display, depth);108 break;109 case 2: // GradientFilter110 ret = this._gradientFilter(streamId, x, y, width, height,111 sock, display, depth);112 break;113 default:114 throw new Error("Illegal tight filter received (ctl: " +115 this._filter + ")");116 }117 if (ret) {118 this._filter = null;119 }120 return ret;121 }122 _copyFilter(streamId, x, y, width, height, sock, display, depth) {123 const uncompressedSize = width * height * 3;124 let data;125 if (uncompressedSize < 12) {126 if (sock.rQwait("TIGHT", uncompressedSize)) {127 return false;128 }129 data = sock.rQshiftBytes(uncompressedSize);130 } else {131 data = this._readData(sock);132 if (data === null) {133 return false;134 }135 data = this._zlibs[streamId].inflate(data, true, uncompressedSize);136 if (data.length != uncompressedSize) {137 throw new Error("Incomplete zlib block");138 }139 }140 display.blitRgbImage(x, y, width, height, data, 0, false);141 return true;142 }143 _paletteFilter(streamId, x, y, width, height, sock, display, depth) {144 if (this._numColors === 0) {145 if (sock.rQwait("TIGHT palette", 1)) {146 return false;147 }148 const numColors = sock.rQpeek8() + 1;149 const paletteSize = numColors * 3;150 if (sock.rQwait("TIGHT palette", 1 + paletteSize)) {151 return false;152 }153 this._numColors = numColors;154 sock.rQskipBytes(1);155 sock.rQshiftTo(this._palette, paletteSize);156 }157 const bpp = (this._numColors <= 2) ? 1 : 8;158 const rowSize = Math.floor((width * bpp + 7) / 8);159 const uncompressedSize = rowSize * height;160 let data;161 if (uncompressedSize < 12) {162 if (sock.rQwait("TIGHT", uncompressedSize)) {163 return false;164 }165 data = sock.rQshiftBytes(uncompressedSize);166 } else {167 data = this._readData(sock);168 if (data === null) {169 return false;170 }171 data = this._zlibs[streamId].inflate(data, true, uncompressedSize);172 if (data.length != uncompressedSize) {173 throw new Error("Incomplete zlib block");174 }175 }176 // Convert indexed (palette based) image data to RGB177 if (this._numColors == 2) {178 this._monoRect(x, y, width, height, data, this._palette, display);179 } else {180 this._paletteRect(x, y, width, height, data, this._palette, display);181 }182 this._numColors = 0;183 return true;184 }185 _monoRect(x, y, width, height, data, palette, display) {186 // Convert indexed (palette based) image data to RGB187 // TODO: reduce number of calculations inside loop188 const dest = this._getScratchBuffer(width * height * 4);189 const w = Math.floor((width + 7) / 8);190 const w1 = Math.floor(width / 8);191 for (let y = 0; y < height; y++) {192 let dp, sp, x;193 for (x = 0; x < w1; x++) {194 for (let b = 7; b >= 0; b--) {195 dp = (y * width + x * 8 + 7 - b) * 4;196 sp = (data[y * w + x] >> b & 1) * 3;197 dest[dp] = palette[sp];198 dest[dp + 1] = palette[sp + 1];199 dest[dp + 2] = palette[sp + 2];200 dest[dp + 3] = 255;201 }202 }203 for (let b = 7; b >= 8 - width % 8; b--) {204 dp = (y * width + x * 8 + 7 - b) * 4;205 sp = (data[y * w + x] >> b & 1) * 3;206 dest[dp] = palette[sp];207 dest[dp + 1] = palette[sp + 1];208 dest[dp + 2] = palette[sp + 2];209 dest[dp + 3] = 255;210 }211 }212 display.blitRgbxImage(x, y, width, height, dest, 0, false);213 }214 _paletteRect(x, y, width, height, data, palette, display) {215 // Convert indexed (palette based) image data to RGB216 const dest = this._getScratchBuffer(width * height * 4);217 const total = width * height * 4;218 for (let i = 0, j = 0; i < total; i += 4, j++) {219 const sp = data[j] * 3;220 dest[i] = palette[sp];221 dest[i + 1] = palette[sp + 1];222 dest[i + 2] = palette[sp + 2];223 dest[i + 3] = 255;224 }225 display.blitRgbxImage(x, y, width, height, dest, 0, false);226 }227 _gradientFilter(streamId, x, y, width, height, sock, display, depth) {228 throw new Error("Gradient filter not implemented");229 }230 _readData(sock) {231 if (this._len === 0) {232 if (sock.rQwait("TIGHT", 3)) {233 return null;234 }235 let byte;236 byte = sock.rQshift8();237 this._len = byte & 0x7f;238 if (byte & 0x80) {239 byte = sock.rQshift8();240 this._len |= (byte & 0x7f) << 7;241 if (byte & 0x80) {242 byte = sock.rQshift8();243 this._len |= byte << 14;244 }245 }246 }247 if (sock.rQwait("TIGHT", this._len)) {248 return null;249 }250 let data = sock.rQshiftBytes(this._len);251 this._len = 0;252 return data;253 }254 _getScratchBuffer(size) {255 if (!this._scratchBuffer || (this._scratchBuffer.length < size)) {256 this._scratchBuffer = new Uint8Array(size);257 }258 return this._scratchBuffer;259 }...
Using AI Code Generation
1var redwood = require("redwood");2var rQwait = redwood.rQwait;3var rQ = redwood.rQ;4var rQwait = redwood.rQwait;5var rQall = redwood.rQall;6var rQrace = redwood.rQrace;7var p1 = new Promise(function(resolve,reject){8 setTimeout(function(){9 resolve(1);10 },1000);11});12var p2 = new Promise(function(resolve,reject){13 setTimeout(function(){14 resolve(2);15 },2000);16});17var p3 = new Promise(function(resolve,reject){18 setTimeout(function(){19 resolve(3);20 },3000);21});22var p4 = new Promise(function(resolve,reject){23 setTimeout(function(){24 resolve(4);25 },4000);26});27var p5 = new Promise(function(resolve,reject){28 setTimeout(function(){29 resolve(5);30 },5000);31});32var p6 = new Promise(function(resolve,reject){33 setTimeout(function(){34 resolve(6);35 },6000);36});37var p7 = new Promise(function(resolve,reject){38 setTimeout(function(){39 resolve(7);40 },7000);41});42var p8 = new Promise(function(resolve,reject){43 setTimeout(function(){44 resolve(8);45 },8000);46});47var p9 = new Promise(function(resolve,reject){48 setTimeout(function(){49 resolve(9);50 },9000);51});52var p10 = new Promise(function(resolve,reject){53 setTimeout(function(){54 resolve(10);55 },10000);56});57rQwait(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10).then(function(results){58 console.log("rQwait result: ",results);59 console.log("rQwait result: ",results[0].result);60 console.log("rQwait result: ",results[1].result);61 console.log("rQwait result: ",results[2].result);62 console.log("rQwait result: ",results[3].result);63 console.log("rQwait result: ",results[4].result);64 console.log("rQwait result: ",results[5].result);65 console.log("rQwait result: ",results[6].result);66 console.log("rQwait result: ",results[7].result);67 console.log("rQwait result
Using AI Code Generation
1var redwoodHQ = require('redwoodHQ');2redwoodHQ.rQwait(3000);3redwoodHQ.rQwait(5000);4redwoodHQ.rQwait(10000);5redwoodHQ.rQwait(20000);6redwoodHQ.rQwait(40000);7redwoodHQ.rQwait(60000);8redwoodHQ.rQwait(80000);9redwoodHQ.rQwait(100000);10redwoodHQ.rQwait(200000);11redwoodHQ.rQwait(400000);12redwoodHQ.rQwait(600000);13redwoodHQ.rQwait(800000);14redwoodHQ.rQwait(1000000);15var redwoodHQ = require('redwoodHQ');16redwoodHQ.rQwait(3000);17redwoodHQ.rQwait(5000);18redwoodHQ.rQwait(10000);19redwoodHQ.rQwait(20000);20redwoodHQ.rQwait(40000);21redwoodHQ.rQwait(60000);22redwoodHQ.rQwait(80000);23redwoodHQ.rQwait(100000);24redwoodHQ.rQwait(200000);25redwoodHQ.rQwait(400000);26redwoodHQ.rQwait(600000);27redwoodHQ.rQwait(800000);28redwoodHQ.rQwait(1000000);29var redwoodHQ = require('redwoodHQ');30redwoodHQ.rQwait(3000);31redwoodHQ.rQwait(5000);32redwoodHQ.rQwait(10000);33redwoodHQ.rQwait(20000);34redwoodHQ.rQwait(40000);35redwoodHQ.rQwait(60000);36redwoodHQ.rQwait(80000);37redwoodHQ.rQwait(100000);38redwoodHQ.rQwait(200000);39redwoodHQ.rQwait(400000);40redwoodHQ.rQwait(600000);41redwoodHQ.rQwait(800000);42redwoodHQ.rQwait(1000000);43var redwoodHQ = require('redwoodHQ');
Using AI Code Generation
1var rQwait = require('rQwait');2rQwait.init();3rQwait.add('test.js');4rQwait.add('test2.js');5rQwait.add('test3.js');6rQwait.wait(function(){7 console.log('all done');8});9var rQwait = require('rQwait');10rQwait.init();11rQwait.add('test2.js');12rQwait.add('test3.js');13rQwait.wait(function(){14 console.log('all done');15});16var rQwait = require('rQwait');17rQwait.init();18rQwait.add('test3.js');19rQwait.wait(function(){20 console.log('all done');21});
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!