Explorar el Código

include/canvas.js: fix changeCursor data format.

Issues #27 (safari cursor rendering messed up) and #29 (firefox 3.6.10
segault).

Finally found some better reference on the icon/cursor format which is
added to the docs/links file.

It seems like I was missing the XOR section. So setting the cursor
would cause corruptin in Safari rendering or the segfault for firefox.
Joel Martin hace 14 años
padre
commit
9a23006e7a
Se han modificado 2 ficheros con 78 adiciones y 50 borrados
  1. 5 0
      docs/links
  2. 73 50
      include/canvas.js

+ 5 - 0
docs/links

@@ -35,6 +35,11 @@ Cursor appearance/style (for Cursor pseudo-encoding):
     https://developer.mozilla.org/en/Using_URL_values_for_the_cursor_property
     http://www.fileformat.info/format/bmp/egff.htm
 
+Icon/Cursor file format:
+    http://msdn.microsoft.com/en-us/library/ms997538
+    http://msdn.microsoft.com/en-us/library/aa921550.aspx
+    http://msdn.microsoft.com/en-us/library/aa930622.aspx
+
 
 RDP Protocol specification:
     http://msdn.microsoft.com/en-us/library/cc240445(v=PROT.10).aspx

+ 73 - 50
include/canvas.js

@@ -83,8 +83,6 @@ that.get_height = function() {
     return c_height;
 };
 
-
-
 //
 // Private functions
 //
@@ -192,7 +190,7 @@ function constructor() {
     }
     try {
         curSave = c.style.cursor;
-        that.changeCursor(curDat, curDat, 2, 2, 8, 8);
+        changeCursor(conf.target, curDat, curDat, 2, 2, 8, 8);
         if (c.style.cursor) {
             if (conf.cursor_uri === null) {
                 conf.cursor_uri = true;
@@ -596,14 +594,28 @@ that.blitStringImage = function(str, x, y) {
 };
 
 that.changeCursor = function(pixels, mask, hotx, hoty, w, h) {
-    var cur = [], cmap, rgb, IHDRsz, ANDsz, XORsz, url, idx, alpha, x, y;
-    //Util.Debug(">> changeCursor, x: " + hotx + ", y: " + hoty + ", w: " + w + ", h: " + h);
-    
     if (conf.cursor_uri === false) {
         Util.Warn("changeCursor called but no cursor data URI support");
         return;
     }
 
+    if (conf.true_color) {
+        changeCursor(conf.target, pixels, mask, hotx, hoty, w, h);
+    } else {
+        changeCursor(conf.target, pixels, mask, hotx, hoty, w, h, conf.colourMap);
+    }
+}
+
+return constructor();  // Return the public API interface
+
+}  // End of Canvas()
+
+
+/* Set CSS cursor property using data URI encoded cursor file */
+function changeCursor(target, pixels, mask, hotx, hoty, w, h, cmap) {
+    var cur = [], rgb, IHDRsz, RGBsz, ANDsz, XORsz, url, idx, alpha, x, y;
+    //Util.Debug(">> changeCursor, x: " + hotx + ", y: " + hoty + ", w: " + w + ", h: " + h);
+    
     // Push multi-byte little-endian values
     cur.push16le = function (num) {
         this.push((num     ) & 0xFF,
@@ -616,63 +628,77 @@ that.changeCursor = function(pixels, mask, hotx, hoty, w, h) {
                   (num >> 24) & 0xFF  );
     };
 
-    cmap = conf.colourMap;
     IHDRsz = 40;
-    ANDsz = w * h * 4;
+    RGBsz = w * h * 4;
     XORsz = Math.ceil( (w * h) / 8.0 );
+    ANDsz = 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
+    cur.push16le(0);      // 0: Reserved
+    cur.push16le(2);      // 2: .CUR type
+    cur.push16le(1);      // 4: Number of images, 1 for non-animated ico
+
+    // Cursor #1 header (ICONDIRENTRY)
+    cur.push(w);          // 6: width
+    cur.push(h);          // 7: height
+    cur.push(0);          // 8: colors, 0 -> true-color
+    cur.push(0);          // 9: reserved
+    cur.push16le(hotx);   // 10: hotspot x coordinate
+    cur.push16le(hoty);   // 12: hotspot y coordinate
+    cur.push32le(IHDRsz + RGBsz + XORsz + ANDsz);
+                          // 14: cursor data byte size
+    cur.push32le(22);     // 18: offset of cursor data in the file
+
+
+    // Cursor #1 InfoHeader (ICONIMAGE/BITMAPINFO)
+    cur.push32le(IHDRsz); // 22: Infoheader size
+    cur.push32le(w);      // 26: Cursor width
+    cur.push32le(h*2);    // 30: XOR+AND height
+    cur.push16le(1);      // 34: number of planes
+    cur.push16le(32);     // 36: bits per pixel
+    cur.push32le(0);      // 38: Type of compression
+
+    cur.push32le(XORsz + ANDsz); // 43: Size of Image
+                                 // Gimp leaves this as 0
+
+    cur.push32le(0);      // 46: reserved
+    cur.push32le(0);      // 50: reserved
+    cur.push32le(0);      // 54: reserved
+    cur.push32le(0);      // 58: reserved
+
+    // 62: color data (RGBQUAD icColors[])
     for (y = h-1; y >= 0; y -= 1) {
         for (x = 0; x < w; x += 1) {
             idx = y * Math.ceil(w / 8) + Math.floor(x/8);
             alpha = (mask[idx] << (x % 8)) & 0x80 ? 255 : 0;
 
-            if (conf.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 {
+            if (cmap) {
                 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
+            } else {
+                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);           // alpha
             }
         }
     }
 
-    // AND/bitmask data (ignored, just needs to be right size)
+    // XOR/bitmask data (BYTE icXOR[])
+    // (ignored, just needs to be right size)
+    for (y = 0; y < h; y += 1) {
+        for (x = 0; x < Math.ceil(w / 8); x += 1) {
+            cur.push(0x00);
+        }
+    }
+
+    // AND/bitmask data (BYTE icAND[])
+    // (ignored, just needs to be right size)
     for (y = 0; y < h; y += 1) {
         for (x = 0; x < Math.ceil(w / 8); x += 1) {
             cur.push(0x00);
@@ -680,17 +706,14 @@ that.changeCursor = function(pixels, mask, hotx, hoty, w, h) {
     }
 
     url = "data:image/x-icon;base64," + Base64.encode(cur);
-    conf.target.style.cursor = "url(" + url + ") " + hotx + " " + hoty + ", default";
+    Util.Info(url);
+    target.style.cursor = "url(" + url + ") " + hotx + " " + hoty + ", default";
+    //conf.target.style.cursor = "url(" + url + "), default";
     //Util.Debug("<< changeCursor, cur.length: " + cur.length);
 };
 
 
 
-return constructor();  // Return the public API interface
-
-}  // End of Canvas()
-
-
 /* Translate DOM key down/up event to keysym value */
 function getKeysym(e) {
     var evt, keysym;