// Everything namespaced inside Canvas
Canvas = {
-prefer_js : false,
-force_canvas : false,
+prefer_js : false, // make private
+force_canvas : false, // make private
+cursor_uri : true, // make private, create getter
true_color : false,
colourMap : [],
init: function (id) {
- var c, imgTest, arora;
+ var c, imgTest, tval, i, curTest, curSave;
Util.Debug(">> Canvas.init");
Canvas.id = id;
Canvas._cmapImage = Canvas._cmapImageFill;
}
+ /*
+ * Determine browser support for setting the cursor via data URI
+ * scheme
+ */
+ curDat = [];
+ for (i=0; i < 8 * 8 * 4; i++) {
+ curDat.push(255);
+ }
+ curSave = c.style.cursor;
+ Canvas.setCursor(curDat, curDat, 2, 2, 8, 8);
+ if (c.style.cursor) {
+ Util.Info("Data URI scheme cursor supported");
+ } else {
+ Canvas.cursor_uri = false;
+ Util.Warn("Data URI scheme cursor not supported");
+ }
+ c.style.cursor = curSave;
+
+
Canvas.colourMap = [];
Canvas.prevStyle = "";
Canvas.focused = true;
/* Work around right and middle click browser behaviors */
Util.removeEvent(document, 'click', Canvas.onMouseDisable);
Util.removeEvent(document.body, 'contextmenu', Canvas.onMouseDisable);
+
+ // Turn off cursor rendering
+ if (Canvas.cursor_uri) {
+ c.style.cursor = "default";
+ }
},
/*
}
return keysym;
-}
+},
+
+isCursor: function() {
+ return Canvas.cursor_uri;
+},
+
+setCursor: function(pixels, mask, hotx, hoty, w, h) {
+ var cur = [], cmap, IHDRsz, ANDsz, XORsz, url, idx, x, y;
+ //Util.Debug(">> setCursor, x: " + hotx + ", y: " + hoty + ", w: " + w + ", h: " + h);
+
+ if (!Canvas.cursor_uri) {
+ Util.Warn("setCursor called but no cursor data URI support");
+ return;
+ }
+
+ cmap = Canvas.colourMap;
+ IHDRsz = 40;
+ ANDsz = w * h * 4;
+ XORsz = Math.ceil( (w * h) / 8.0 );
+
+ // Main header
+ cur.push16le(0); // Reserved
+ cur.push16le(2); // .CUR type
+ cur.push16le(1); // Number of images, 1 for non-animated ico
+
+ // Cursor #1 header
+ cur.push(w); // width
+ cur.push(h); // height
+ cur.push(0); // colors, 0 -> true-color
+ cur.push(0); // reserved
+ cur.push16le(hotx); // hotspot x coordinate
+ cur.push16le(hoty); // hotspot y coordinate
+ cur.push32le(IHDRsz + XORsz + ANDsz); // cursor data byte size
+ cur.push32le(22); // offset of cursor data in the file
+
+ // Cursor #1 InfoHeader
+ cur.push32le(IHDRsz); // Infoheader size
+ cur.push32le(w); // Cursor width
+ cur.push32le(h*2); // XOR+AND height
+ cur.push16le(1); // number of planes
+ cur.push16le(32); // bits per pixel
+ cur.push32le(0); // Type of compression
+ cur.push32le(XORsz + ANDsz); // Size of Image
+ cur.push32le(0);
+ cur.push32le(0);
+ cur.push32le(0);
+ cur.push32le(0);
+
+ // XOR/color data
+ for (y = h-1; y >= 0; y--) {
+ for (x = 0; x < w; x++) {
+ idx = y * Math.ceil(w / 8) + Math.floor(x/8);
+ alpha = (mask[idx] << (x % 8)) & 0x80 ? 255 : 0;
+
+ if (Canvas.true_color) {
+ idx = ((w * y) + x) * 4;
+ cur.push(pixels[idx + 2]); // blue
+ cur.push(pixels[idx + 1]); // green
+ cur.push(pixels[idx + 0]); // red
+ cur.push(alpha); // red
+ } else {
+ idx = (w * y) + x;
+ rgb = cmap[pixels[idx]];
+ cur.push(rgb[2]); // blue
+ cur.push(rgb[1]); // green
+ cur.push(rgb[0]); // red
+ cur.push(alpha); // alpha
+ }
+ }
+ }
+
+ // AND/bitmask data (ignored, just needs to be right size)
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < Math.ceil(w / 8); x++) {
+ cur.push(0x00);
+ }
+ }
+
+ url = "data:image/x-icon;base64," + Base64.encode(cur);
+ $(Canvas.id).style.cursor = "url(" + url + ") " + hotx + " " + hoty + ", default";
+ //Util.Debug("<< setCursor, cur.length: " + cur.length);
+}
};
// ['compress_hi', -247, 'set_compress_level']
],
+encodingCursor :
+ ['Cursor', -239, 'set_cursor'],
+
+
setUpdateState: function(externalUpdateState) {
RFB.externalUpdateState = externalUpdateState;
},
RFB.updateState('fatal', "No working Canvas");
}
+ // Add Cursor pseudo-encoding if supported
+/*
+ if (Canvas.isCursor()) {
+ Util.Debug("Adding Cursor pseudo-encoding to encoding list");
+ RFB.encodings.push(RFB.encodingCursor);
+ }
+*/
+
// Populate encoding lookup tables
RFB.encHandlers = {};
RFB.encNames = {};
RFB.timing.fbu_rt_start = (new Date()).getTime();
// Send a new non-incremental request
RFB.send_array(RFB.fbUpdateRequest(0));
+
+ RFB.FBU.bytes = 0;
+ RFB.FBU.rects -= 1;
+
Util.Debug("<< set_desktopsize");
+},
+
+set_cursor: function () {
+ var x, y, w, h, pixelslength, masklength;
+ //Util.Debug(">> set_cursor");
+ x = RFB.FBU.x; // hotspot-x
+ y = RFB.FBU.y; // hotspot-y
+ w = RFB.FBU.width;
+ h = RFB.FBU.height;
+
+ pixelslength = w * h * RFB.fb_Bpp;
+ masklength = Math.floor((w + 7) / 8) * h;
+
+ if (RFB.RQ.length < (pixelslength + masklength)) {
+ //Util.Debug("waiting for cursor encoding bytes");
+ RFB.FBU.bytes = pixelslength + masklength;
+ return false;
+ }
+
+ //Util.Debug(" set_cursor, x: " + x + ", y: " + y + ", w: " + w + ", h: " + h);
+
+ Canvas.setCursor(RFB.RQ.shiftBytes(pixelslength),
+ RFB.RQ.shiftBytes(masklength),
+ x, y, w, h);
RFB.FBU.bytes = 0;
RFB.FBU.rects -= 1;
+
+ //Util.Debug("<< set_cursor");
},
set_jpeg_quality : function () {