فهرست منبع

Remove support for non-HTML5 browsers.

Display API change:
    - getTile -> startTile (no longer returns a tile)
    - setSubTile -> subTile (drop img/tile first parameter)
    - putTile -> finishTile (no longer takes img/tile paramter)

The Display tile logic uses canvas image data directly and
caches/reuses a 16x16 imageData tile (for other sizes, the tile is
create for each call). This gives a 30% speedup on Chrome
13 (and no significant change for Firefox 3.6/4.0).

Other:

- Remove rgbxImageFill and cmapImageFill routines.

- Simplify constructor tests and just error if createImageData is not
  supported by canvas instead of .

- Remove webkit canvas bug workaround that effects Chrome 7. Chrome
  7 usage share is now less than 0.5 percent and the workaround is
  ugly. Drop the function wrapping in the constructor and the canvas
  flush() routine.

- Remove support for getImageData (Opera 11+ now required)

Update browser support list:

    - Chrome 8+ (really any except 7)
    - Firefox 3.6+
    - Safari 4+
    - Opera 11+
    - IE9+
    - iOS 4.2+
Joel Martin 14 سال پیش
والد
کامیت
490d471c53
2فایلهای تغییر یافته به همراه45 افزوده شده و 145 حذف شده
  1. 41 141
      include/display.js
  2. 4 4
      include/rfb.js

+ 41 - 141
include/display.js

@@ -19,11 +19,9 @@ var that           = {},  // Public API methods
     c_ctx          = null,
     c_ctx          = null,
     c_forceCanvas  = false,
     c_forceCanvas  = false,
 
 
-    c_imageData, c_rgbxImage, c_cmapImage,
-
     // Predefine function variables (jslint)
     // Predefine function variables (jslint)
-    imageDataCreate, imageDataGet, rgbxImageData, cmapImageData,
-    rgbxImageFill, cmapImageFill, setFillColor, rescale, flush,
+    imageDataGet, rgbxImageData, cmapImageData,
+    setFillColor, rescale,
 
 
     // The full frame buffer (logical canvas) size
     // The full frame buffer (logical canvas) size
     fb_width        = 0,
     fb_width        = 0,
@@ -33,9 +31,11 @@ var that           = {},  // Public API methods
     cleanRect      = {'x1': 0, 'y1': 0, 'x2': -1, 'y2': -1},
     cleanRect      = {'x1': 0, 'y1': 0, 'x2': -1, 'y2': -1},
 
 
     c_prevStyle    = "",
     c_prevStyle    = "",
+    tile           = null,
+    tile16x16      = null,
+    tile_x         = 0,
+    tile_y         = 0;
 
 
-    c_webkit_bug   = false,
-    c_flush_timer  = null;
 
 
 // Configuration attributes
 // Configuration attributes
 Util.conf_defaults(conf, that, defaults, [
 Util.conf_defaults(conf, that, defaults, [
@@ -66,15 +66,6 @@ that.get_width = function() { return fb_width; };
 that.set_height = function (val) { that.resize(fb_width, val); };
 that.set_height = function (val) { that.resize(fb_width, val); };
 that.get_height = function() { return fb_height; };
 that.get_height = function() { return fb_height; };
 
 
-that.set_prefer_js = function(val) {
-    if (val && c_forceCanvas) {
-        Util.Warn("Preferring Javascript to Canvas ops is not supported");
-        return false;
-    }
-    conf.prefer_js = val;
-    return true;
-};
-
 
 
 
 
 //
 //
@@ -85,7 +76,7 @@ that.set_prefer_js = function(val) {
 function constructor() {
 function constructor() {
     Util.Debug(">> Display.constructor");
     Util.Debug(">> Display.constructor");
 
 
-    var c, func, imgTest, tval, i, curDat, curSave,
+    var c, func, i, curDat, curSave,
         has_imageData = false, UE = Util.Engine;
         has_imageData = false, UE = Util.Engine;
 
 
     if (! conf.target) { throw("target must be set"); }
     if (! conf.target) { throw("target must be set"); }
@@ -108,71 +99,20 @@ function constructor() {
 
 
     that.clear();
     that.clear();
 
 
-    /*
-     * Determine browser Canvas feature support
-     * and select fastest rendering methods
-     */
-    tval = 0;
-    try {
-        imgTest = c_ctx.getImageData(0, 0, 1,1);
-        imgTest.data[0] = 123;
-        imgTest.data[3] = 255;
-        c_ctx.putImageData(imgTest, 0, 0);
-        tval = c_ctx.getImageData(0, 0, 1, 1).data[0];
-        if (tval === 123) {
-            has_imageData = true;
-        }
-    } catch (exc1) {}
-
-    if (has_imageData) {
-        Util.Info("Canvas supports imageData");
-        c_forceCanvas = false;
-        if (c_ctx.createImageData) {
-            // If it's there, it's faster
-            Util.Info("Using Canvas createImageData");
-            conf.render_mode = "createImageData rendering";
-            c_imageData = imageDataCreate;
-        } else if (c_ctx.getImageData) {
-            // I think this is mostly just Opera
-            Util.Info("Using Canvas getImageData");
-            conf.render_mode = "getImageData rendering";
-            c_imageData = imageDataGet;
-        }
-        Util.Info("Prefering javascript operations");
-        if (conf.prefer_js === null) {
-            conf.prefer_js = true;
-        }
-        c_rgbxImage = rgbxImageData;
-        c_cmapImage = cmapImageData;
+    // Check canvas features
+    if ('createImageData' in c_ctx) {
+        conf.render_mode = "canvas rendering";
     } else {
     } else {
-        Util.Warn("Canvas lacks imageData, using fillRect (slow)");
-        conf.render_mode = "fillRect rendering (slow)";
-        c_forceCanvas = true;
-        conf.prefer_js = false;
-        c_rgbxImage = rgbxImageFill;
-        c_cmapImage = cmapImageFill;
-    }
-
-    if (UE.webkit && UE.webkit >= 534.7 && UE.webkit <= 534.9) {
-        // Workaround WebKit canvas rendering bug #46319
-        conf.render_mode += ", webkit bug workaround";
-        Util.Debug("Working around WebKit bug #46319");
-        c_webkit_bug = true;
-        for (func in {"fillRect":1, "copyImage":1, "rgbxImage":1,
-                "cmapImage":1, "blitStringImage":1}) {
-            that[func] = (function() {
-                var myfunc = that[func]; // Save original function
-                //Util.Debug("Wrapping " + func);
-                return function() {
-                    myfunc.apply(this, arguments);
-                    if (!c_flush_timer) {
-                        c_flush_timer = setTimeout(flush, 100);
-                    }
-                };
-            }());
-        }
+        throw("Canvas does not support createImageData");
+    }
+    if (conf.prefer_js === null) {
+        Util.Info("Prefering javascript operations");
+        conf.prefer_js = true;
     }
     }
 
 
+    // Initialize cached tile imageData
+    tile16x16 = c_ctx.createImageData(16, 16);
+
     /*
     /*
      * Determine browser support for setting the cursor via data URI
      * Determine browser support for setting the cursor via data URI
      * scheme
      * scheme
@@ -425,18 +365,6 @@ that.absY = function(y) {
 }
 }
 
 
 
 
-// Force canvas redraw (for webkit bug #46319 workaround)
-flush = function() {
-    var old_val;
-    //Util.Debug(">> flush");
-    old_val = conf.target.style.marginRight;
-    conf.target.style.marginRight = "1px";
-    c_flush_timer = null;
-    setTimeout(function () {
-            conf.target.style.marginRight = old_val;
-        }, 1);
-};
-
 setFillColor = function(color) {
 setFillColor = function(color) {
     var rgb, newStyle;
     var rgb, newStyle;
     if (conf.true_color) {
     if (conf.true_color) {
@@ -498,10 +426,16 @@ that.copyImage = function(old_x, old_y, new_x, new_y, w, h) {
  *   faster than direct Canvas fillStyle, fillRect rendering. In
  *   faster than direct Canvas fillStyle, fillRect rendering. In
  *   gecko, Javascript array handling is much slower.
  *   gecko, Javascript array handling is much slower.
  */
  */
-that.getTile = function(x, y, width, height, color) {
-    var img, data = [], rgb, red, green, blue, i;
-    img = {'x': x, 'y': y, 'width': width, 'height': height,
-           'data': data};
+that.startTile = function(x, y, width, height, color) {
+    var data, rgb, red, green, blue, i;
+    tile_x = x;
+    tile_y = y;
+    if ((width === 16) && (height === 16)) {
+        tile = tile16x16;
+    } else {
+        tile = c_ctx.createImageData(width, height);
+    }
+    data = tile.data;
     if (conf.prefer_js) {
     if (conf.prefer_js) {
         if (conf.true_color) {
         if (conf.true_color) {
             rgb = color;
             rgb = color;
@@ -515,18 +449,18 @@ that.getTile = function(x, y, width, height, color) {
             data[i    ] = red;
             data[i    ] = red;
             data[i + 1] = green;
             data[i + 1] = green;
             data[i + 2] = blue;
             data[i + 2] = blue;
+            data[i + 3] = 255;
         }
         }
     } else {
     } else {
         that.fillRect(x, y, width, height, color);
         that.fillRect(x, y, width, height, color);
     }
     }
-    return img;
 };
 };
 
 
-that.setSubTile = function(img, x, y, w, h, color) {
+that.subTile = function(x, y, w, h, color) {
     var data, p, rgb, red, green, blue, width, j, i, xend, yend;
     var data, p, rgb, red, green, blue, width, j, i, xend, yend;
     if (conf.prefer_js) {
     if (conf.prefer_js) {
-        data = img.data;
-        width = img.width;
+        data = tile.data;
+        width = tile.width;
         if (conf.true_color) {
         if (conf.true_color) {
             rgb = color;
             rgb = color;
         } else {
         } else {
@@ -543,25 +477,19 @@ that.setSubTile = function(img, x, y, w, h, color) {
                 data[p    ] = red;
                 data[p    ] = red;
                 data[p + 1] = green;
                 data[p + 1] = green;
                 data[p + 2] = blue;
                 data[p + 2] = blue;
+                data[p + 3] = 255;
             }   
             }   
         } 
         } 
     } else {
     } else {
-        that.fillRect(img.x + x, img.y + y, w, h, color);
+        that.fillRect(tile_x + x, tile_y + y, w, h, color);
     }
     }
 };
 };
 
 
-that.putTile = function(img) {
+that.finishTile = function() {
     if (conf.prefer_js) {
     if (conf.prefer_js) {
-        c_rgbxImage(img.x, img.y, img.width, img.height, img.data, 0);
+        c_ctx.putImageData(tile, tile_x - viewport.x, tile_y - viewport.y)
     }
     }
-    // else: No-op, under gecko already done by setSubTile
-};
-
-imageDataGet = function(width, height) {
-    return c_ctx.getImageData(0, 0, width, height);
-};
-imageDataCreate = function(width, height) {
-    return c_ctx.createImageData(width, height);
+    // else: No-op, if not prefer_js then already done by setSubTile
 };
 };
 
 
 rgbxImageData = function(x, y, width, height, arr, offset) {
 rgbxImageData = function(x, y, width, height, arr, offset) {
@@ -569,12 +497,11 @@ rgbxImageData = function(x, y, width, height, arr, offset) {
     /*
     /*
     if ((x - v.x >= v.w) || (y - v.y >= v.h) ||
     if ((x - v.x >= v.w) || (y - v.y >= v.h) ||
         (x - v.x + width < 0) || (y - v.y + height < 0)) {
         (x - v.x + width < 0) || (y - v.y + height < 0)) {
-        //console.log("skipping, out of bounds: ", x, y);
         // Skipping because outside of viewport
         // Skipping because outside of viewport
         return;
         return;
     }
     }
     */
     */
-    img = c_imageData(width, height);
+    img = c_ctx.createImageData(width, height);
     data = img.data;
     data = img.data;
     for (i=0, j=offset; i < (width * height * 4); i=i+4, j=j+4) {
     for (i=0, j=offset; i < (width * height * 4); i=i+4, j=j+4) {
         data[i    ] = arr[j    ];
         data[i    ] = arr[j    ];
@@ -585,22 +512,9 @@ rgbxImageData = function(x, y, width, height, arr, offset) {
     c_ctx.putImageData(img, x - v.x, y - v.y);
     c_ctx.putImageData(img, x - v.x, y - v.y);
 };
 };
 
 
-// really slow fallback if we don't have imageData
-rgbxImageFill = function(x, y, width, height, arr, offset) {
-    var i, j, sx = 0, sy = 0;
-    for (i=0, j=offset; i < (width * height); i+=1, j+=4) {
-        that.fillRect(x+sx, y+sy, 1, 1, [arr[j], arr[j+1], arr[j+2]]);
-        sx += 1;
-        if ((sx % width) === 0) {
-            sx = 0;
-            sy += 1;
-        }
-    }
-};
-
 cmapImageData = function(x, y, width, height, arr, offset) {
 cmapImageData = function(x, y, width, height, arr, offset) {
     var img, i, j, data, rgb, cmap;
     var img, i, j, data, rgb, cmap;
-    img = c_imageData(width, height);
+    img = c_ctx.createImageData(width, height);
     data = img.data;
     data = img.data;
     cmap = conf.colourMap;
     cmap = conf.colourMap;
     for (i=0, j=offset; i < (width * height * 4); i+=4, j+=1) {
     for (i=0, j=offset; i < (width * height * 4); i+=4, j+=1) {
@@ -613,25 +527,11 @@ cmapImageData = function(x, y, width, height, arr, offset) {
     c_ctx.putImageData(img, x - viewport.x, y - viewport.y);
     c_ctx.putImageData(img, x - viewport.x, y - viewport.y);
 };
 };
 
 
-cmapImageFill = function(x, y, width, height, arr, offset) {
-    var i, j, sx = 0, sy = 0, cmap;
-    cmap = conf.colourMap;
-    for (i=0, j=offset; i < (width * height); i+=1, j+=1) {
-        that.fillRect(x+sx, y+sy, 1, 1, [arr[j]]);
-        sx += 1;
-        if ((sx % width) === 0) {
-            sx = 0;
-            sy += 1;
-        }
-    }
-};
-
-
 that.blitImage = function(x, y, width, height, arr, offset) {
 that.blitImage = function(x, y, width, height, arr, offset) {
     if (conf.true_color) {
     if (conf.true_color) {
-        c_rgbxImage(x, y, width, height, arr, offset);
+        rgbxImageData(x, y, width, height, arr, offset);
     } else {
     } else {
-        c_cmapImage(x, y, width, height, arr, offset);
+        cmapImageData(x, y, width, height, arr, offset);
     }
     }
 };
 };
 
 

+ 4 - 4
include/rfb.js

@@ -1096,7 +1096,7 @@ encHandlers.RRE = function display_rre() {
 
 
 encHandlers.HEXTILE = function display_hextile() {
 encHandlers.HEXTILE = function display_hextile() {
     //Util.Debug(">> display_hextile");
     //Util.Debug(">> display_hextile");
-    var subencoding, subrects, tile, color, cur_tile,
+    var subencoding, subrects, color, cur_tile,
         tile_x, x, w, tile_y, y, h, xy, s, sx, sy, wh, sw, sh,
         tile_x, x, w, tile_y, y, h, xy, s, sx, sy, wh, sw, sh,
         rQ = ws.get_rQ(), rQi = ws.get_rQi(); 
         rQ = ws.get_rQ(), rQi = ws.get_rQi(); 
 
 
@@ -1185,7 +1185,7 @@ encHandlers.HEXTILE = function display_hextile() {
                 rQi += fb_Bpp;
                 rQi += fb_Bpp;
             }
             }
 
 
-            tile = display.getTile(x, y, w, h, FBU.background);
+            display.startTile(x, y, w, h, FBU.background);
             if (FBU.subencoding & 0x08) { // AnySubrects
             if (FBU.subencoding & 0x08) { // AnySubrects
                 subrects = rQ[rQi];
                 subrects = rQ[rQi];
                 rQi += 1;
                 rQi += 1;
@@ -1206,10 +1206,10 @@ encHandlers.HEXTILE = function display_hextile() {
                     sw = (wh >> 4)   + 1;
                     sw = (wh >> 4)   + 1;
                     sh = (wh & 0x0f) + 1;
                     sh = (wh & 0x0f) + 1;
 
 
-                    display.setSubTile(tile, sx, sy, sw, sh, color);
+                    display.subTile(sx, sy, sw, sh, color);
                 }
                 }
             }
             }
-            display.putTile(tile);
+            display.finishTile();
         }
         }
         ws.set_rQi(rQi);
         ws.set_rQi(rQi);
         FBU.lastsubencoding = FBU.subencoding;
         FBU.lastsubencoding = FBU.subencoding;