[OpenLayers-Commits] r12241 - in trunk/openlayers: examples lib lib/OpenLayers lib/OpenLayers/Layer lib/OpenLayers/Tile lib/OpenLayers/Tile/Image tests tests/Layer/WMS tests/Tile tests/Tile/Image

commits-20090109 at openlayers.org commits-20090109 at openlayers.org
Fri Aug 12 20:59:02 EDT 2011


Author: ahocevar
Date: 2011-08-12 17:59:01 -0700 (Fri, 12 Aug 2011)
New Revision: 12241

Added:
   trunk/openlayers/lib/OpenLayers/Tile/BackBufferable.js
   trunk/openlayers/tests/Tile/BackBufferable.html
Modified:
   trunk/openlayers/examples/wms-long-url.js
   trunk/openlayers/lib/OpenLayers.js
   trunk/openlayers/lib/OpenLayers/Layer/Bing.js
   trunk/openlayers/lib/OpenLayers/Tile.js
   trunk/openlayers/lib/OpenLayers/Tile/Image.js
   trunk/openlayers/lib/OpenLayers/Tile/Image/IFrame.js
   trunk/openlayers/tests/Layer/WMS/Post.html
   trunk/openlayers/tests/Tile.html
   trunk/openlayers/tests/Tile/Image.html
   trunk/openlayers/tests/Tile/Image/IFrame.html
   trunk/openlayers/tests/list-tests.html
   trunk/openlayers/tests/run-tests.html
Log:
Tile.Image improvements and partial rewrite. Thanks erilem for the excellent collaboration during the review phase. p=me,erilem r=erilem (closes #3419)


Modified: trunk/openlayers/examples/wms-long-url.js
===================================================================
--- trunk/openlayers/examples/wms-long-url.js	2011-08-12 21:17:22 UTC (rev 12240)
+++ trunk/openlayers/examples/wms-long-url.js	2011-08-13 00:59:01 UTC (rev 12241)
@@ -5,12 +5,12 @@
 var base = new OpenLayers.Layer.WMS( "OpenLayers WMS",
     "http://vmap0.tiles.osgeo.org/wms/vmap0",
     {layers: 'basic', makeTheUrlLong: longText},
-    {tileOptions: {maxGetUrlLength: 2048}}
+    {tileOptions: {maxGetUrlLength: 2048}, transitionEffect: 'resize'}
 );
 var overlay = new OpenLayers.Layer.WMS("Overlay",
     "http://suite.opengeo.org/geoserver/wms",
     {layers: "usa:states", transparent: true, makeTheUrlLong: longText},
-    {ratio: 1, singleTile: true, tileOptions: {maxGetUrlLength: 2048}}
+    {ratio: 1, singleTile: true, tileOptions: {maxGetUrlLength: 2048}, transitionEffect: 'resize'}
 );
 map.addLayers([base, overlay]);
 map.zoomToMaxExtent();

Modified: trunk/openlayers/lib/OpenLayers/Layer/Bing.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Layer/Bing.js	2011-08-12 21:17:22 UTC (rev 12240)
+++ trunk/openlayers/lib/OpenLayers/Layer/Bing.js	2011-08-13 00:59:01 UTC (rev 12241)
@@ -159,7 +159,7 @@
      */
     getURL: function(bounds) {
         if (!this.url) {
-            return OpenLayers.Util.getImagesLocation() + "blank.gif";
+            return;
         }
         var xyz = this.getXYZ(bounds), x = xyz.x, y = xyz.y, z = xyz.z;
         var quadDigits = [];

Added: trunk/openlayers/lib/OpenLayers/Tile/BackBufferable.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Tile/BackBufferable.js	                        (rev 0)
+++ trunk/openlayers/lib/OpenLayers/Tile/BackBufferable.js	2011-08-13 00:59:01 UTC (rev 12241)
@@ -0,0 +1,201 @@
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for 
+ * full list of contributors). Published under the Clear BSD license.  
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/*
+ * @requires OpenLayers/Tile.js
+ * @requires OpenLayers/Util.js
+ */
+
+/*
+ * Class: OpenLayers.Tile.BackBufferable
+ * Base class for tiles that can have backbuffers during transitions. Do not
+ * create instances of this class.
+ */
+OpenLayers.Tile.BackBufferable = OpenLayers.Class(OpenLayers.Tile, {
+    
+    /**
+     * Property: backBufferMode
+     * {Integer} Bitmap: 0 for no backbuffering at all, 1 for singleTile
+     * layers, 2 for transition effect set, 3 for both.
+     */
+    backBufferMode: null,
+    
+    /**
+     * Property: backBufferData
+     * {Object} Object including the necessary data for the back
+     * buffer.
+     *
+     * The object includes three properties:
+     * tile - {DOMElement} The DOM element for the back buffer.
+     * bounds - {<OpenLayers.Bounds>} The bounds of the tile to back.
+     * resolution - {Number} The resolution of the tile to back.
+     */
+    backBufferData: null,
+
+    /** 
+     * Method: initialize
+     * Determines the backBuffer mode and registers events
+     */   
+    initialize: function() {
+        OpenLayers.Tile.prototype.initialize.apply(this, arguments);
+        
+        var transitionSupported = OpenLayers.Util.indexOf(
+                                    this.layer.SUPPORTED_TRANSITIONS,
+                                    this.layer.transitionEffect) != -1;
+        this.backBufferMode = (this.layer.singleTile && 1) |
+                              (transitionSupported && 2);
+
+        this.backBufferData = {};
+        if (!this.size) {
+            this.size = new OpenLayers.Size(256, 256);
+        }
+    },
+    
+    /**
+     * Method: draw
+     * Check that a tile should be drawn, and draw it.
+     * 
+     * Returns:
+     * {Boolean} Was a tile drawn?
+     */
+    draw: function() {
+        var draw = OpenLayers.Tile.prototype.shouldDraw.apply(this, arguments),
+            backBufferMode = this.backBufferMode;
+        if (draw) {
+            this.updateBackBuffer();
+        }
+        this.clear();
+        if (!draw) {
+            this.resetBackBuffer();
+        };
+        return draw;
+    },
+    
+    /**
+     * Method: getTile
+     * Get the tile's markup. To be implemented by subclasses.
+     *
+     * Returns:
+     * {DOMElement} The tile's markup
+     */
+
+    /**
+     * Method: createBackBuffer
+     * Create a copy of this tile's markup for the back buffer. To be
+     * implemented by subclasses.
+     *
+     * Returns:
+     * {DOMElement} A copy of the tile's markup.
+     */
+    
+    /**
+     * Method: setBackBufferData
+     * Stores the current bounds and resolution, for offset and ratio
+     * calculations
+     */
+    setBackBufferData: function() {
+        this.backBufferData = OpenLayers.Util.extend(this.backBufferData, {
+            bounds: this.bounds,
+            resolution: this.layer.map.getResolution()
+        });
+    },
+    
+    /**
+     * Method: updateBackBuffer
+     * Update the <backBufferData>, and return a new or reposition the
+     * backBuffer. When a backbuffer is returned, the tile's markup is not
+     * available any more.
+     *
+     * Returns:
+     * {HTMLDivElement} the tile's markup in a cloned element, or undefined if
+     *     no backbuffer is currently available or needed
+     */
+    updateBackBuffer: function() {
+        var layer = this.layer, map = layer.map,
+            backBufferMode = this.backBufferMode,
+            data = this.backBufferData,
+            tile = this.getTile(),
+            backBuffer = data.tile,
+            resolution = data.resolution,
+            ratio = resolution ? resolution / map.getResolution() : 1,
+            
+        // Cases where we don't position and return a back buffer, but only
+        // update backBufferData and return undefined:
+            // (1) current ratio and backBufferMode dont't require a backbuffer
+            notNeeded = !(ratio == 1 ? backBufferMode & 1 : backBufferMode & 2),
+            // (2) the tile is not appended to the layer's div
+            noParent = tile && tile.parentNode !== layer.div,
+            // (3) we don't have a tile available that we could use as buffer
+            noTile = !(tile && tile.childNodes.length > 0),
+            // (4) no backbuffer is displayed for a tile that's still loading
+            noBackBuffer = data.tile && !this.isLoading;            
+        if (notNeeded || noParent || noTile || noBackBuffer) {
+            this.setBackBufferData();
+            return;
+        }
+
+        // Create a back buffer tile and add it to the DOM
+        if (!backBuffer) {
+            backBuffer = this.createBackBuffer();
+            // some browsers fire the onload event before the image is
+            // displayed, so we keep the buffer until the whole layer finished
+            // loading to avoid visual glitches
+            layer.events.register("loadend", this, this.resetBackBuffer);
+            data.tile = backBuffer;
+            layer.div.insertBefore(backBuffer, tile);
+        }
+
+        // Position the back buffer now that we have one
+        var lonLat = {lon: data.bounds.left, lat: data.bounds.top},
+            position = map.getPixelFromLonLat(lonLat),
+            containerStyle = map.layerContainerDiv.style,
+            leftOffset = parseInt(containerStyle.left, 10),
+            topOffset = parseInt(containerStyle.top, 10),
+            style = backBuffer.style;
+        style.left = (position.x - leftOffset) + "px";
+        style.top = (position.y - topOffset) + "px";
+        style.width = (this.size.w * ratio) + "px";
+        style.height = (this.size.h * ratio) + "px";        
+
+        return backBuffer;
+    },
+    
+    /**
+     * Method: resetBackBuffer
+     * Handler for the layer's loadend event.
+     */
+    resetBackBuffer: function() {
+        this.layer.events.unregister("loadend", this, this.resetBackBuffer);
+        this.removeBackBuffer();
+        this.setBackBufferData();
+    },
+    
+    /**
+     * Method: removeBackBuffer
+     * Removes the backBuffer for this tile.
+     */
+    removeBackBuffer: function() {
+        var backBufferData = this.backBufferData;
+        var backBuffer = backBufferData.tile;
+        delete backBufferData.tile;
+        var parent = backBuffer && backBuffer.parentNode;
+        if (backBuffer) {
+            parent.removeChild(backBuffer);
+        }
+    },
+    
+    /** 
+     * APIMethod: destroy
+     * nullify references to prevent circular references and memory leaks
+     */
+    destroy: function() {
+        this.removeBackBuffer();
+        this.layer.events.unregister("loadend", this, this.resetBackBuffer);
+        this.backBufferData = null;
+        OpenLayers.Tile.prototype.destroy.apply(this, arguments);
+    }
+        
+});
\ No newline at end of file

Modified: trunk/openlayers/lib/OpenLayers/Tile/Image/IFrame.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Tile/Image/IFrame.js	2011-08-12 21:17:22 UTC (rev 12240)
+++ trunk/openlayers/lib/OpenLayers/Tile/Image/IFrame.js	2011-08-13 00:59:01 UTC (rev 12241)
@@ -14,14 +14,13 @@
  * remote services. Images will be loaded using HTTP-POST into an IFrame.
  *
  * This mixin will be applied to <OpenLayers.Tile.Image> instances
- * configured with <OpenLayers.Tile.Image.allowPost> or
- * <OpenLayers.Tile.Image.enforcePost> set to true.
+ * configured with <OpenLayers.Tile.Image.maxGetUrlLength> set.
  *
  * Inherits from:
  *  - <OpenLayers.Tile.Image>
  */
 OpenLayers.Tile.Image.IFrame = {
-    
+
     /**
      * Property: useIFrame
      * {Boolean} true if we are currently using an IFrame to render POST
@@ -30,159 +29,111 @@
     useIFrame: null,
 
     /**
-     * Method: clear
-     * Removes the iframe from DOM (avoids back-button problems).
+     * Property: blankImageUrl
+     * {String} This is only used as background image for the eventPane, so we
+     * don't care that this doesn't actually result in a blank image on all
+     * browsers
      */
-    clear: function() {
-        if (this.useIFrame) {
-            if (this.imgDiv) {
-                var iFrame = this.imgDiv.firstChild;
-                OpenLayers.Event.stopObservingElement(iFrame);
-                this.imgDiv.removeChild(iFrame);
-                delete iFrame;
-            }
-        } else {
-            OpenLayers.Tile.Image.prototype.clear.apply(this, arguments);
-        }
-    },
+    blankImageUrl: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAQAIBRAA7",
 
     /**
-     * Method: renderTile
+    * Method: updateBackBuffer
+    * Update the <backBufferData>, and return a new or reposition the
+    * backBuffer. When a backbuffer is returned, the tile's markup is not
+    * available any more.
+    *
+    * Returns:
+    * {HTMLDivElement} the tile's markup in a cloned element, or undefined if
+    *     no backbuffer is currently available or needed
      */
-     renderTile: function() {
-        if (OpenLayers.Tile.Image.prototype.renderTile.apply(this, arguments) &&
-                                                            this.useIFrame) {
-            // create a html form and add it temporary to the layer div
-            var form = this.createRequestForm();
-            this.imgDiv.appendChild(form);
-
-            // submit the form (means fetching the image)
-            form.submit();
-            this.imgDiv.removeChild(form);
-            delete form;
+    updateBackBuffer: function() {
+        this.url = this.layer.getURL(this.bounds);
+        var usedIFrame = this.useIFrame;
+        this.useIFrame = this.maxGetUrlLength !== null && !this.layer.async &&
+            this.url.length > this.maxGetUrlLength;
+        var fromIFrame = usedIFrame && !this.useIFrame;
+        var toIFrame = !usedIFrame && this.useIFrame;
+        if (fromIFrame || toIFrame) {
+            // switch between get (image) and post (iframe)
+            this.clear();
+            if (this.imgDiv && this.imgDiv.parentNode === this.frame) {
+                this.frame.removeChild(this.imgDiv);
+            }
+            this.imgDiv = null;
+            if (fromIFrame) {
+                // remove eventPane
+                this.frame.removeChild(this.frame.firstChild);
+                this.resetBackBuffer();
+            }
         }
-        return true;
+        if (!this.useIFrame) {
+            OpenLayers.Tile.Image.prototype.updateBackBuffer.apply(this, arguments);
+        }
     },
-
+    
     /**
-     * Method: initImgDiv
-     * Creates the imgDiv property on the tile.
+     * Method: createImage
+     * Creates the content for the frame on the tile.
      */
-    initImgDiv: function() {
-        this.useIFrame = this.maxGetUrlLength !== null && !this.layer.async &&
-            this.url.length > this.maxGetUrlLength;
-        if (this.imgDiv != null) {
-            var nodeName = this.imgDiv.nodeName.toLowerCase();
-            if ((this.useIFrame && nodeName == "img") ||
-                                        (!this.useIFrame && nodeName == "div")) {
-                // switch between get and post
-                this.removeImgDiv();
-                this.imgDiv = null;
+    createImage: function() {
+        if (this.useIFrame === true) {
+            if (!this.frame.childNodes.length) {
+                var eventPane = document.createElement("div"),
+                    style = eventPane.style;
+                style.position = "absolute";
+                style.width = "100%";
+                style.height = "100%";
+                style.zIndex = 1;
+                style.backgroundImage = "url(" + this.blankImageUrl + ")";
+                this.frame.appendChild(eventPane);
             }
-        }
-        if (this.useIFrame) {
-            if (this.imgDiv == null) {
-                var eventPane = document.createElement("div");
 
-                if(OpenLayers.BROWSER_NAME == "msie") {
-                    // IE cannot handle events on elements without backgroundcolor.
-                    // So we use this little hack to make elements transparent
-                    eventPane.style.backgroundColor = '#FFFFFF';
-                    eventPane.style.filter          = 'chroma(color=#FFFFFF)';
-                }
+            var id = this.id + '_iFrame', iframe;
+            if (parseFloat(navigator.appVersion.split("MSIE")[1]) < 9) {
+                // Older IE versions do not set the name attribute of an iFrame 
+                // properly via DOM manipulation, so we need to do it on our own with
+                // this hack.
+                iframe = document.createElement('<iframe name="'+id+'">');
 
-                OpenLayers.Util.modifyDOMElement(eventPane, null,
-                    new OpenLayers.Pixel(0,0), this.layer.getImageSize(), "absolute");
+                // IFrames in older IE versions are not transparent, if you set
+                // the backgroundColor transparent. This is a workaround to get 
+                // transparent iframes.
+                iframe.style.backgroundColor = '#FFFFFF';
+                iframe.style.filter          = 'chroma(color=#FFFFFF)';
+            }
+            else {
+                iframe = document.createElement('iframe');
+                iframe.style.backgroundColor = 'transparent';
 
-                this.imgDiv = document.createElement("div");
-                this.imgDiv.appendChild(eventPane);
+                // iframe.name needs to be an unique id, otherwise it 
+                // could happen that other iframes are overwritten.
+                iframe.name = id;
+            }
 
-                OpenLayers.Util.modifyDOMElement(this.imgDiv, this.id, null,
-                    this.layer.getImageSize(), "relative");
-                this.imgDiv.className = 'olTileImage';
+            // some special properties to avoid scaling the images and scrollbars 
+            // in the iframe
+            iframe.scrolling      = 'no';
+            iframe.marginWidth    = '0px';
+            iframe.marginHeight   = '0px';
+            iframe.frameBorder    = '0';
 
-                this.frame.appendChild(this.imgDiv); 
-                this.layer.div.appendChild(this.frame); 
+            iframe.style.position = "absolute";
+            iframe.style.width    = "100%";
+            iframe.style.height   = "100%";
 
-                if(this.layer.opacity != null) {
-
-                    OpenLayers.Util.modifyDOMElement(this.imgDiv, null, null,
-                                                     null, null, null, null, 
-                                                     this.layer.opacity);
-                }
-
-                // we need this reference to check back the viewRequestID
-                this.imgDiv.map = this.layer.map;
+            if (this.layer.opacity < 1) {
+                OpenLayers.Util.modifyDOMElement(iframe, null, null, null,
+                    null, null, null, this.layer.opacity);
             }
-            this.imgDiv.viewRequestID = this.layer.map.viewRequestID;
-
+            this.frame.appendChild(iframe);
+            this.imgDiv = iframe;
+            return iframe;
         } else {
-            OpenLayers.Tile.Image.prototype.initImgDiv.apply(this, arguments);
+            return OpenLayers.Tile.Image.prototype.createImage.apply(this, arguments);
         }
     },
 
     /**
-     * Method: createIFrame
-     * Create the IFrame which shows the image.
-     *
-     * Returns:
-     * {DOMElement} Iframe
-     */
-    createIFrame: function() {
-        var id = this.id+'_iFrame';
-        var iframe;
-        if(OpenLayers.BROWSER_NAME == "msie") {
-            // InternetExplorer does not set the name attribute of an iFrame 
-            // properly via DOM manipulation, so we need to do it on our own with
-            // this hack.
-            iframe = document.createElement('<iframe name="'+id+'">');
-
-            // IFrames in InternetExplorer are not transparent, if you set the
-            // backgroundColor transparent. This is a workarround to get 
-            // transparent iframes.
-            iframe.style.backgroundColor = '#FFFFFF';
-            iframe.style.filter          = 'chroma(color=#FFFFFF)';
-        }
-        else {
-            iframe = document.createElement('iframe');
-            iframe.style.backgroundColor = 'transparent';
-        
-            // iframe.name needs to be an unique id, otherwise it 
-            // could happen that other iframes are overwritten.
-            iframe.name = id;
-        }
-        iframe.id = id;
-
-        // some special properties to avoid scaling the images and scrollbars 
-        // in the iframe
-        iframe.scrolling             = 'no';
-        iframe.marginWidth           = '0px';
-        iframe.marginHeight          = '0px';
-        iframe.frameBorder           = '0';
-
-        OpenLayers.Util.modifyDOMElement(iframe, id, 
-            new OpenLayers.Pixel(0,0), this.layer.getImageSize(), "absolute");
-
-        //bind a listener to the onload of the iframe so that we
-        // can register when a tile has finished loading.
-        var onload = function() {
-            //normally isLoading should always be true here but there are some
-            // right funky conditions where loading and then reloading a tile
-            // with the same url *really*fast*. this check prevents sending
-            // a 'loadend' if the msg has already been sent
-            //
-            if (this.isLoading) {
-                this.isLoading = false;
-                this.events.triggerEvent("loadend");
-            }
-        };
-        OpenLayers.Event.observe(iframe, 'load',
-            OpenLayers.Function.bind(onload, this));
-
-        return iframe;
-    },
-    
-    /**
      * Method: createRequestForm
      * Create the html <form> element with width, height, bbox and all 
      * parameters specified in the layer params.
@@ -198,20 +149,16 @@
         var cacheId = this.layer.params["_OLSALT"];
         cacheId = (cacheId ? cacheId + "_" : "") + this.bounds.toBBOX();
         form.action = OpenLayers.Util.urlAppend(this.layer.url, cacheId);
+        form.target = this.id + '_iFrame';
 
-        // insert the iframe, which has been removed to avoid back-button
-        // problems
-        this.imgDiv.insertBefore(this.createIFrame(), this.imgDiv.firstChild);
-
-        form.target = this.id+'_iFrame';
-
         // adding all parameters in layer params as hidden fields to the html
         // form element
-        var imageSize = this.layer.getImageSize();
-        var params = OpenLayers.Util.getParameters(this.url);
+        var imageSize = this.layer.getImageSize(),
+            params = OpenLayers.Util.getParameters(this.url),
+            field;
             
         for(var par in params) {
-            var field = document.createElement('input');
+            field = document.createElement('input');
             field.type  = 'hidden';
             field.name  = par;
             field.value = params[par];
@@ -219,6 +166,31 @@
         }   
 
         return form;
+    },
+
+    /**
+     * Method: setImgSrc
+     * Sets the source for the tile image
+     *
+     * Parameters:
+     * url - {String}
+     */
+    setImgSrc: function(url) {
+        if (this.useIFrame === true) {
+            if (url) {
+                var form = this.createRequestForm();
+                this.frame.appendChild(this.imgDiv);
+                this.frame.appendChild(form);
+                form.submit();
+                this.frame.removeChild(form);
+            } else if (this.imgDiv.parentNode === this.frame) {
+                // we don't reuse iframes to avoid caching issues
+                this.frame.removeChild(this.imgDiv);
+                this.imgDiv = null;
+            }
+        } else {
+            OpenLayers.Tile.Image.prototype.setImgSrc.apply(this, arguments);
+        }
     }
-};
 
+};
\ No newline at end of file

Modified: trunk/openlayers/lib/OpenLayers/Tile/Image.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Tile/Image.js	2011-08-12 21:17:22 UTC (rev 12240)
+++ trunk/openlayers/lib/OpenLayers/Tile/Image.js	2011-08-13 00:59:01 UTC (rev 12241)
@@ -5,7 +5,7 @@
 
 
 /**
- * @requires OpenLayers/Tile.js
+ * @requires OpenLayers/Tile/BackBufferable.js
  */
 
 /**
@@ -15,9 +15,9 @@
  * <OpenLayers.Tile.Image> constructor.
  *
  * Inherits from:
- *  - <OpenLayers.Tile>
+ *  - <OpenLayers.Tile.BackBufferable>
  */
-OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, {
+OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile.BackBufferable, {
 
     /** 
      * Property: url
@@ -28,16 +28,22 @@
     
     /** 
      * Property: imgDiv
-     * {DOMElement} The div element which wraps the image.
+     * {HTMLImageElement} The image for this tile.
      */
     imgDiv: null,
-
+    
     /**
      * Property: frame
      * {DOMElement} The image element is appended to the frame.  Any gutter on
      * the image will be hidden behind the frame. 
      */ 
     frame: null, 
+
+    /** 
+     * Property: imageReloadAttempts
+     * {Integer} Attempts to load the image.
+     */
+    imageReloadAttempts: null,
     
     /**
      * Property: layerAlphaHack
@@ -46,30 +52,13 @@
     layerAlphaHack: null,
     
     /**
-     * Property: isBackBuffer
-     * {Boolean} Is this tile a back buffer tile?
+     * Property: asyncRequestId
+     * {Integer} ID of an request to see if request is still valid. This is a
+     * number which increments by 1 for each asynchronous request.
      */
-    isBackBuffer: false,
+    asyncRequestId: null,
     
     /**
-     * Property: isFirstDraw
-     * {Boolean} Is this the first time the tile is being drawn?
-     *     This is used to force resetBackBuffer to synchronize
-     *     the backBufferTile with the foreground tile the first time
-     *     the foreground tile loads so that if the user zooms
-     *     before the layer has fully loaded, the backBufferTile for
-     *     tiles that have been loaded can be used.
-     */
-    isFirstDraw: true,
-        
-    /**
-     * Property: backBufferTile
-     * {<OpenLayers.Tile>} A clone of the tile used to create transition
-     *     effects when the tile is moved or changes resolution.
-     */
-    backBufferTile: null,
-    
-    /**
      * APIProperty: maxGetUrlLength
      * {Number} If set, requests that would result in GET urls with more
      * characters than the number provided will be made using form-encoded
@@ -77,12 +66,9 @@
      * characters.
      *
      * Caution:
-     * Older versions of Gecko based browsers (e.g. Firefox < 3.5) and
-     * Opera < 10.0 do not fully support this option.
-     *
-     * Note:
-     * Do not use this option for layers that have a transitionEffect
-     * configured - IFrame tiles from POST requests can not be resized.
+     * Older versions of Gecko based browsers (e.g. Firefox < 3.5) and most
+     * Opera versions do not fully support this option. On all browsers,
+     * transition effects are not supported if POST requests are used.
      */
     maxGetUrlLength: null,
     
@@ -102,502 +88,258 @@
      * options - {Object}
      */   
     initialize: function(layer, position, bounds, url, size, options) {
-        OpenLayers.Tile.prototype.initialize.apply(this, arguments);
+        OpenLayers.Tile.BackBufferable.prototype.initialize.apply(this, arguments);
 
-        if (this.maxGetUrlLength != null) {
-            OpenLayers.Util.extend(this, OpenLayers.Tile.Image.IFrame);
-        }
-
         this.url = url; //deprecated remove me
+
+        this.frame = document.createElement("div");
+        this.frame.style.position = "absolute";
+        this.frame.style.overflow = "hidden";
         
-        this.frame = document.createElement('div'); 
-        this.frame.style.overflow = 'hidden'; 
-        this.frame.style.position = 'absolute'; 
+        this.layerAlphaHack = this.layer.alpha && OpenLayers.Util.alphaHack();
 
-        this.layerAlphaHack = this.layer.alpha && OpenLayers.Util.alphaHack();        
+        if (this.maxGetUrlLength != null) {
+            OpenLayers.Util.extend(this, OpenLayers.Tile.Image.IFrame);
+        }
     },
-
+    
     /** 
      * APIMethod: destroy
      * nullify references to prevent circular references and memory leaks
      */
     destroy: function() {
-        if (this.imgDiv != null)  {
-            this.removeImgDiv();
+        if (this.frame != null)  {
+            this.clear();
+            this.imgDiv = null;
+            this.frame = null;
         }
-        this.imgDiv = null;
-        if ((this.frame != null) && (this.frame.parentNode == this.layer.div)) { 
-            this.layer.div.removeChild(this.frame); 
-        }
-        this.frame = null; 
-        
-        /* clean up the backBufferTile if it exists */
-        if (this.backBufferTile) {
-            this.backBufferTile.destroy();
-            this.backBufferTile = null;
-        }
-        
-        this.layer.events.unregister("loadend", this, this.resetBackBuffer);
-        
-        OpenLayers.Tile.prototype.destroy.apply(this, arguments);
+        // don't handle async requests any more
+        this.asyncRequestId = null;
+        OpenLayers.Tile.BackBufferable.prototype.destroy.apply(this, arguments);
     },
     
     /**
-     * Method: clone
-     *
-     * Parameters:
-     * obj - {<OpenLayers.Tile.Image>} The tile to be cloned
-     *
-     * Returns:
-     * {<OpenLayers.Tile.Image>} An exact clone of this <OpenLayers.Tile.Image>
-     */
-    clone: function (obj) {
-        if (obj == null) {
-            obj = new OpenLayers.Tile.Image(this.layer, 
-                                            this.position, 
-                                            this.bounds, 
-                                            this.url, 
-                                            this.size);        
-        } 
-        
-        //pick up properties from superclass
-        obj = OpenLayers.Tile.prototype.clone.apply(this, [obj]);
-        
-        //dont want to directly copy the image div
-        obj.imgDiv = null;
-            
-        
-        return obj;
-    },
-    
-    /**
      * Method: draw
      * Check that a tile should be drawn, and draw it.
      * 
      * Returns:
-     * {Boolean} Always returns true.
+     * {Boolean} Was a tile drawn?
      */
     draw: function() {
-        if (this.layer != this.layer.map.baseLayer && this.layer.reproject) {
-            this.bounds = this.getBoundsFromBaseLayer(this.position);
-        }
-        var drawTile = OpenLayers.Tile.prototype.draw.apply(this, arguments);
-        
-        if ((OpenLayers.Util.indexOf(this.layer.SUPPORTED_TRANSITIONS, this.layer.transitionEffect) != -1) || 
-            this.layer.singleTile) {
-            if (drawTile) {
-                //we use a clone of this tile to create a double buffer for visual
-                //continuity.  The backBufferTile is used to create transition
-                //effects while the tile in the grid is repositioned and redrawn
-                if (!this.backBufferTile) {
-                    this.backBufferTile = this.clone();
-                    this.backBufferTile.hide();
-                    // this is important.  It allows the backBuffer to place itself
-                    // appropriately in the DOM.  The Image subclass needs to put
-                    // the backBufferTile behind the main tile so the tiles can
-                    // load over top and display as soon as they are loaded.
-                    this.backBufferTile.isBackBuffer = true;
-                    
-                    // potentially end any transition effects when the tile loads
-                    this.events.register('loadend', this, this.resetBackBuffer);
-                    
-                    // clear transition back buffer tile only after all tiles in
-                    // this layer have loaded to avoid visual glitches
-                    this.layer.events.register("loadend", this, this.resetBackBuffer);
-                }
-                // run any transition effects
-                this.startTransition();
+        var drawn = OpenLayers.Tile.BackBufferable.prototype.draw.apply(this, arguments);
+        if (drawn) {
+            if (this.layer != this.layer.map.baseLayer && this.layer.reproject) {
+                this.bounds = this.getBoundsFromBaseLayer(this.position);
+            }
+            if (this.isLoading) {
+                //if we're already loading, send 'reload' instead of 'loadstart'.
+                this.events.triggerEvent("reload"); 
             } else {
-                // if we aren't going to draw the tile, then the backBuffer should
-                // be hidden too!
-                if (this.backBufferTile) {
-                    this.backBufferTile.clear();
-                }
+                this.isLoading = true;
+                this.events.triggerEvent("loadstart");
             }
+            this.positionTile();
+            this.renderTile();
         } else {
-            if (drawTile && this.isFirstDraw) {
-                this.events.register('loadend', this, this.showTile);
-                this.isFirstDraw = false;
-            }   
-        }    
-        
-        if (!drawTile) {
-            return false;
+            this.unload();
         }
-        
-        if (this.isLoading) {
-            //if we're already loading, send 'reload' instead of 'loadstart'.
-            this.events.triggerEvent("reload"); 
-        } else {
-            this.isLoading = true;
-            this.events.triggerEvent("loadstart");
-        }
-        
-        return this.renderTile();
+        return drawn;
     },
     
-    /** 
-     * Method: resetBackBuffer
-     * Triggered by two different events, layer loadend, and tile loadend.
-     *     In any of these cases, we check to see if we can hide the 
-     *     backBufferTile yet and update its parameters to match the 
-     *     foreground tile.
-     *
-     * Basic logic:
-     *  - If the backBufferTile hasn't been drawn yet, reset it
-     *  - If layer is still loading, show foreground tile but don't hide
-     *    the backBufferTile yet
-     *  - If layer is done loading, reset backBuffer tile and show 
-     *    foreground tile
-     */
-    resetBackBuffer: function() {
-        this.showTile();
-        if (this.backBufferTile && 
-            (this.isFirstDraw || !this.layer.numLoadingTiles)) {
-            this.isFirstDraw = false;
-            // check to see if the backBufferTile is within the max extents
-            // before rendering it 
-            var maxExtent = this.layer.maxExtent;
-            var withinMaxExtent = (maxExtent &&
-                                   this.bounds.intersectsBounds(maxExtent, false));
-            if (withinMaxExtent) {
-                this.backBufferTile.position = this.position;
-                this.backBufferTile.bounds = this.bounds;
-                this.backBufferTile.size = this.size;
-                this.backBufferTile.imageSize = this.layer.getImageSize(this.bounds) || this.size;
-                this.backBufferTile.imageOffset = this.layer.imageOffset;
-                this.backBufferTile.resolution = this.layer.getResolution();
-                this.backBufferTile.renderTile();
-            }
-
-            this.backBufferTile.hide();
-        }
-    },
-    
     /**
      * Method: renderTile
      * Internal function to actually initialize the image tile,
      *     position it correctly, and set its url.
      */
     renderTile: function() {
+        this.layer.div.appendChild(this.frame);
         if (this.layer.async) {
-            this.initImgDiv();
-            // Asyncronous image requests call the asynchronous getURL method
+            // Asynchronous image requests call the asynchronous getURL method
             // on the layer to fetch an image that covers 'this.bounds', in the scope of
             // 'this', setting the 'url' property of the layer itself, and running
-            // the callback 'positionFrame' when the image request returns.
-            this.layer.getURLasync(this.bounds, this, "url", this.positionImage);
+            // the callback 'initImage' when the image request returns.
+            var myId = this.asyncRequestId = (this.asyncRequestId || 0) + 1;
+            this.layer.getURLasync(this.bounds, this, "url", function() {
+                if (myId == this.asyncRequestId) {
+                    this.initImage();
+                }
+            });
         } else {
-            // syncronous image requests get the url and position the frame immediately,
-            // and don't wait for an image request to come back.
-          
+            // synchronous image requests get the url immediately.
             this.url = this.layer.getURL(this.bounds);
-
-            this.initImgDiv();
-          
-            // position the frame immediately
-            this.positionImage(); 
+            this.initImage();
         }
-        return true;
     },
 
     /**
-     * Method: positionImage
+     * Method: positionTile
      * Using the properties currenty set on the layer, position the tile correctly.
      * This method is used both by the async and non-async versions of the Tile.Image
      * code.
      */
-     positionImage: function() {
-        // if the this layer doesn't exist at the point the image is
-        // returned, do not attempt to use it for size computation
-        if (this.layer === null) {
-            return;
-        }
-        // position the frame 
-        OpenLayers.Util.modifyDOMElement(this.frame, 
-                                          null, this.position, this.size);   
-
-        var imageSize = this.layer.getImageSize(this.bounds); 
-        if (this.layerAlphaHack) {
-            OpenLayers.Util.modifyAlphaImageDiv(this.imgDiv,
-                    null, null, imageSize, this.url);
-        } else {
-            OpenLayers.Util.modifyDOMElement(this.imgDiv,
-                    null, null, imageSize) ;
-            this.imgDiv.src = this.url;
-        }
+    positionTile: function() {
+        var style = this.frame.style;
+        style.left = this.position.x + "px";
+        style.top = this.position.y + "px";
+        style.width = this.size.w + "px";
+        style.height = this.size.h + "px";
     },
 
     /** 
      * Method: clear
-     *  Clear the tile of any bounds/position-related data so that it can 
-     *   be reused in a new location.
+     * Remove the tile from the DOM, clear it of any image related data so that
+     * it can be reused in a new location.
      */
     clear: function() {
-        if(this.imgDiv) {
-            this.hide();
-            if (OpenLayers.Tile.Image.useBlankTile) { 
-                this.imgDiv.src = OpenLayers.Util.getImagesLocation() + "blank.gif";
-            }    
+        var img = this.imgDiv;
+        if (img) {
+            OpenLayers.Event.stopObservingElement(img);
+            if (this.frame.parentNode === this.layer.div) {
+                this.layer.div.removeChild(this.frame);
+            }
+            this.setImgSrc();
+            if (this.layerAlphaHack === true) {
+                img.style.filter = "";
+            }
+            OpenLayers.Element.removeClass(img, "olImageLoadError");
         }
     },
-
+    
     /**
-     * Method: initImgDiv
-     * Creates the imgDiv property on the tile.
+     * Method: createImage
+     * Creates the content for the frame on the tile.
      */
-    initImgDiv: function() {
-        if (this.imgDiv == null) {
-            var offset = this.layer.imageOffset; 
-            var size = this.layer.getImageSize(this.bounds); 
+    createImage: function() {
+        var img = document.createElement("img");
+        this.imgDiv = img;
 
-            if (this.layerAlphaHack) {
-                this.imgDiv = OpenLayers.Util.createAlphaImageDiv(null,
-                                                               offset,
-                                                               size,
-                                                               null,
-                                                               "relative",
-                                                               null,
-                                                               null,
-                                                               null,
-                                                               true);
-            } else {
-                this.imgDiv = OpenLayers.Util.createImage(null,
-                                                          offset,
-                                                          size,
-                                                          null,
-                                                          "relative",
-                                                          null,
-                                                          null,
-                                                          true);
-            }
+        img.className = "olTileImage";
+        // avoid image gallery menu in IE6
+        img.galleryImg = "no";
 
-            // needed for changing to a different server for onload error
-            if (OpenLayers.Util.isArray(this.layer.url)) {
-                this.imgDiv.urls = this.layer.url.slice();
-            }
-      
-            this.imgDiv.className = 'olTileImage';
-
-            /* checkImgURL used to be used to called as a work around, but it
-               ended up hiding problems instead of solving them and broke things
-               like relative URLs. See discussion on the dev list:
-               http://openlayers.org/pipermail/dev/2007-January/000205.html
-
-            OpenLayers.Event.observe( this.imgDiv, "load",
-                OpenLayers.Function.bind(this.checkImgURL, this) );
-            */
-            this.frame.style.zIndex = this.isBackBuffer ? 0 : 1;
-            this.frame.appendChild(this.imgDiv); 
-            this.layer.div.appendChild(this.frame); 
-
-            if(this.layer.opacity < 1) {
-
-                OpenLayers.Util.modifyDOMElement(this.imgDiv, null, null, null,
-                                                 null, null, null, 
-                                                 this.layer.opacity);
-            }
-
-            // we need this reference to check back the viewRequestID
-            this.imgDiv.map = this.layer.map;
-
-            //bind a listener to the onload of the image div so that we 
-            // can register when a tile has finished loading.
-            var onload = function() {
-
-                //normally isLoading should always be true here but there are some 
-                // right funky conditions where loading and then reloading a tile
-                // with the same url *really*fast*. this check prevents sending 
-                // a 'loadend' if the msg has already been sent
-                //
-                if (this.isLoading) { 
-                    this.isLoading = false; 
-                    this.events.triggerEvent("loadend"); 
-                }
-            };
-
-            if (this.layerAlphaHack) { 
-                OpenLayers.Event.observe(this.imgDiv.childNodes[0], 'load', 
-                                         OpenLayers.Function.bind(onload, this));    
-            } else { 
-                OpenLayers.Event.observe(this.imgDiv, 'load', 
-                                     OpenLayers.Function.bind(onload, this)); 
-            } 
-
-
-            // Bind a listener to the onerror of the image div so that we
-            // can registere when a tile has finished loading with errors.
-            var onerror = function() {
-
-                // If we have gone through all image reload attempts, it is time
-                // to realize that we are done with this image. Since
-                // OpenLayers.Util.onImageLoadError already has taken care about
-                // the error, we can continue as if the image was loaded
-                // successfully.
-                if (this.imgDiv._attempts > OpenLayers.IMAGE_RELOAD_ATTEMPTS) {
-                    onload.call(this);
-                }
-            };
-            OpenLayers.Event.observe(this.imgDiv, "error",
-                                     OpenLayers.Function.bind(onerror, this));
+        var style = img.style,
+            gutter = this.layer.gutter;
+        if (gutter) {
+            var tileSize = this.layer.tileSize,
+                left = (gutter / tileSize.w * 100),
+                top = (gutter / tileSize.h * 100);
+            style.left = -left + "%";
+            style.top = -top + "%";
+            style.width = (2 * left + 100) + "%";
+            style.height = (2 * top + 100) + "%";
+            style.position = "absolute";
+        } else {
+            style.width = "100%";
+            style.height = "100%";
         }
-        
-        this.imgDiv.viewRequestID = this.layer.map.viewRequestID;
+        if (this.layer.opacity < 1) {
+            OpenLayers.Util.modifyDOMElement(img, null, null, null, null, null,
+                null, this.layer.opacity);
+        }
+        if (this.layerAlphaHack) {
+            // move the image out of sight
+            style.paddingTop = style.height;
+            style.height = "0";
+        }
+
+        this.frame.appendChild(img);
+        return img;
     },
 
     /**
-     * Method: removeImgDiv
-     * Removes the imgDiv from the DOM and stops listening to events on it.
+     * Method: initImage
+     * Creates the content for the frame on the tile.
      */
-    removeImgDiv: function() {
-        // unregister the "load" and "error" handlers. Only the "error" handler if
-        // this.layerAlphaHack is true.
-        OpenLayers.Event.stopObservingElement(this.imgDiv);
-        
-        if (this.imgDiv.parentNode == this.frame) {
-            this.frame.removeChild(this.imgDiv);
-            this.imgDiv.map = null;
-        }
-        this.imgDiv.urls = null;
-
-        var child = this.imgDiv.firstChild;
-        //check for children (alphaHack img or IFrame)
-        if (child) {
-            OpenLayers.Event.stopObservingElement(child);
-            this.imgDiv.removeChild(child);
-            delete child;
+    initImage: function() {
+        var img = this.imgDiv || this.createImage();
+        if (this.url && img.getAttribute("src") == this.url) {
+            this.onImageLoad();
         } else {
-            // abort any currently loading image
-            this.imgDiv.src = OpenLayers.Util.getImagesLocation() + "blank.gif";
+            OpenLayers.Event.observe(
+                img, "load", OpenLayers.Function.bind(this.onImageLoad, this)
+            );
+            OpenLayers.Event.observe(
+                img, "error", OpenLayers.Function.bind(this.onImageError, this)
+            );
+            this.imageReloadAttempts = 0;
+            this.setImgSrc(this.url);
         }
     },
-
+    
     /**
-     * Method: checkImgURL
-     * Make sure that the image that just loaded is the one this tile is meant
-     * to display, since panning/zooming might have changed the tile's URL in
-     * the meantime. If the tile URL did change before the image loaded, set
-     * the imgDiv display to 'none', as either (a) it will be reset to visible
-     * when the new URL loads in the image, or (b) we don't want to display
-     * this tile after all because its new bounds are outside our maxExtent.
-     * 
-     * This function should no longer  be neccesary with the improvements to
-     * Grid.js in OpenLayers 2.3. The lack of a good isEquivilantURL function
-     * caused problems in 2.2, but it's possible that with the improved 
-     * isEquivilant URL function, this might be neccesary at some point.
-     * 
-     * See discussion in the thread at 
-     * http://openlayers.org/pipermail/dev/2007-January/000205.html
+     * Method: setImgSrc
+     * Sets the source for the tile image
+     *
+     * Parameters:
+     * url - {String} or undefined to hide the image
      */
-    checkImgURL: function () {
-        // Sometimes our image will load after it has already been removed
-        // from the map, in which case this check is not needed.  
-        if (this.layer) {
-            var loaded = this.layerAlphaHack ? this.imgDiv.firstChild.src : this.imgDiv.src;
-            if (!OpenLayers.Util.isEquivalentUrl(loaded, this.url)) {
-                this.hide();
-            }
+    setImgSrc: function(url) {
+        this.imgDiv.style.display = "none";
+        if (url) {
+            this.imgDiv.src = url;
         }
     },
     
     /**
-     * Method: startTransition
-     * This method is invoked on tiles that are backBuffers for tiles in the
-     *     grid.  The grid tile is about to be cleared and a new tile source
-     *     loaded.  This is where the transition effect needs to be started
-     *     to provide visual continuity.
+     * Method: getTile
+     * Get the tile's markup.
+     *
+     * Returns:
+     * {DOMElement} The tile's markup
      */
-    startTransition: function() {
-        // backBufferTile has to be valid and ready to use
-        if (!this.backBufferTile || !this.backBufferTile.imgDiv) {
-            return;
-        }
+    getTile: function() {
+        return this.frame;
+    },
 
-        // calculate the ratio of change between the current resolution of the
-        // backBufferTile and the layer.  If several animations happen in a
-        // row, then the backBufferTile will scale itself appropriately for
-        // each request.
-        var ratio = 1;
-        if (this.backBufferTile.resolution) {
-            ratio = this.backBufferTile.resolution / this.layer.getResolution();
-        }
-        
-        // if the ratio is not the same as it was last time (i.e. we are
-        // zooming), then we need to adjust the backBuffer tile
-        if (ratio != 1) {
-            if (this.layer.transitionEffect == 'resize') {
-                // In this case, we can just immediately resize the 
-                // backBufferTile.
-                var upperLeft = new OpenLayers.LonLat(
-                    this.backBufferTile.bounds.left, 
-                    this.backBufferTile.bounds.top
-                );
-                var size = new OpenLayers.Size(
-                    this.backBufferTile.size.w * ratio,
-                    this.backBufferTile.size.h * ratio
-                );
+    /**
+     * Method: createBackBuffer
+     * Create a copy of this tile's markup for the <layer>'s backBufferDiv
+     *
+     * Returns:
+     * {DOMElement} a clone of the tile content
+     */
+    createBackBuffer: function() {
+        var frame = this.frame.cloneNode(false);
+        OpenLayers.Event.stopObservingElement(this.imgDiv);
+        frame.appendChild(this.imgDiv);
+        this.imgDiv = null;
+        return frame;
+    },
 
-                var px = this.layer.map.getLayerPxFromLonLat(upperLeft);
-                OpenLayers.Util.modifyDOMElement(this.backBufferTile.frame, 
-                                                 null, px, size);
-                var imageSize = this.backBufferTile.imageSize;
-                imageSize = new OpenLayers.Size(imageSize.w * ratio, 
-                                                imageSize.h * ratio);
-                var imageOffset = this.backBufferTile.imageOffset;
-                if(imageOffset) {
-                    imageOffset = new OpenLayers.Pixel(
-                        imageOffset.x * ratio, imageOffset.y * ratio
-                    );
-                }
+    /**
+     * Method: onImageLoad
+     * Handler for the image onload event
+     */
+    onImageLoad: function() {
+        var img = this.imgDiv;
+        img.style.display = "";
+        this.isLoading = false;
+        this.events.triggerEvent("loadend");
 
-                OpenLayers.Util.modifyDOMElement(
-                    this.backBufferTile.imgDiv, null, imageOffset, imageSize
-                ) ;
-
-                this.backBufferTile.show();
-            }
-        } else {
-            // default effect is just to leave the existing tile
-            // until the new one loads if this is a singleTile and
-            // there was no change in resolution.  Otherwise we
-            // don't bother to show the backBufferTile at all
-            if (this.layer.singleTile) {
-                this.backBufferTile.show();
-            } else {
-                this.backBufferTile.hide();
-            }
+        if (this.layerAlphaHack === true) {
+            img.style.filter =
+                "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" +
+                img.src + "', sizingMethod='scale')";
         }
-
     },
     
-    /** 
-     * Method: show
-     * Show the tile by showing its frame.
+    /**
+     * Method: onImageError
+     * Handler for the image onerror event
      */
-    show: function() {
-        this.frame.style.display = '';
-        // Force a reflow on gecko based browsers to actually show the element
-        // before continuing execution.
-        if (OpenLayers.Util.indexOf(this.layer.SUPPORTED_TRANSITIONS, 
-                this.layer.transitionEffect) != -1) {
-            if (OpenLayers.IS_GECKO === true) { 
-                this.frame.scrollLeft = this.frame.scrollLeft; 
-            } 
+    onImageError: function() {
+        var img = this.imgDiv;
+        if (img.src != null) {
+            this.imageReloadAttempts++;
+            if (this.imageReloadAttempts <= OpenLayers.IMAGE_RELOAD_ATTEMPTS) {
+                this.setImgSrc(this.layer.getURL(this.bounds));
+            } else {
+                OpenLayers.Element.addClass(img, "olImageLoadError");
+                this.onImageLoad();
+            }
         }
     },
-    
-    /** 
-     * Method: hide
-     * Hide the tile by hiding its frame.
-     */
-    hide: function() {
-        this.frame.style.display = 'none';
-    },
-    
+
     CLASS_NAME: "OpenLayers.Tile.Image"
-  }
-);
 
-OpenLayers.Tile.Image.useBlankTile = ( 
-    OpenLayers.BROWSER_NAME == "safari" || 
-    OpenLayers.BROWSER_NAME == "opera"); 
+});
\ No newline at end of file

Modified: trunk/openlayers/lib/OpenLayers/Tile.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Tile.js	2011-08-12 21:17:22 UTC (rev 12240)
+++ trunk/openlayers/lib/OpenLayers/Tile.js	2011-08-13 00:59:01 UTC (rev 12241)
@@ -77,7 +77,7 @@
      * {<OpenLayers.Pixel>} Top Left pixel of the tile
      */    
     position: null,
-
+    
     /**
      * Property: isLoading
      * {Boolean} Is the tile loading?
@@ -144,53 +144,37 @@
     },
     
     /**
-     * Method: clone
-     *
-     * Parameters:
-     * obj - {<OpenLayers.Tile>} The tile to be cloned
-     *
+     * Method: draw
+     * Clear whatever is currently in the tile, then return whether or not 
+     *     it should actually be re-drawn. This is an example implementation
+     *     that can be overridden by subclasses. The minimum thing to do here
+     *     is to call <clear> and return the result from <shouldDraw>.
+     * 
      * Returns:
-     * {<OpenLayers.Tile>} An exact clone of this <OpenLayers.Tile>
+     * {Boolean} Whether or not the tile should actually be drawn.
      */
-    clone: function (obj) {
-        if (obj == null) {
-            obj = new OpenLayers.Tile(this.layer, 
-                                      this.position, 
-                                      this.bounds, 
-                                      this.url, 
-                                      this.size);
-        } 
+    draw: function() {
+        //clear tile's contents and mark as not drawn
+        this.clear();
         
-        // catch any randomly tagged-on properties
-        OpenLayers.Util.applyDefaults(obj, this);
-        
-        return obj;
+        return this.shouldDraw();
     },
-
+    
     /**
-     * Method: draw
-     * Clear whatever is currently in the tile, then return whether or not 
-     *     it should actually be re-drawn.
+     * Method: shouldDraw
+     * Return whether or not the tile should actually be (re-)drawn. The only
+     * case where we *wouldn't* want to draw the tile is if the tile is outside
+     * its layer's maxExtent
      * 
      * Returns:
-     * {Boolean} Whether or not the tile should actually be drawn. Note that 
-     *     this is not really the best way of doing things, but such is 
-     *     the way the code has been developed. Subclasses call this and
-     *     depend on the return to know if they should draw or not.
+     * {Boolean} Whether or not the tile should actually be drawn.
      */
-    draw: function() {
+    shouldDraw: function() {
         var maxExtent = this.layer.maxExtent;
         var withinMaxExtent = (maxExtent &&
                                this.bounds.intersectsBounds(maxExtent, false));
- 
-        // The only case where we *wouldn't* want to draw the tile is if the 
-        // tile is outside its layer's maxExtent.
-        this.shouldDraw = (withinMaxExtent || this.layer.displayOutsideMaxExtent);
-                
-        //clear tile's contents and mark as not drawn
-        this.clear();
         
-        return this.shouldDraw;
+        return withinMaxExtent || this.layer.displayOutsideMaxExtent;
     },
     
     /** 
@@ -220,7 +204,7 @@
      * Clear the tile of any bounds/position-related data so that it can 
      *     be reused in a new location. To be implemented by subclasses.
      */
-    clear: function() {
+    clear: function(draw) {
         // to be implemented by subclasses
     },
     
@@ -260,29 +244,7 @@
                                        bottomRight.lon, 
                                        topLeft.lat);  
         return bounds;
-    },        
-        
-    /** 
-     * Method: showTile
-     * Show the tile only if it should be drawn.
-     */
-    showTile: function() { 
-        if (this.shouldDraw) {
-            this.show();
-        }
     },
     
-    /** 
-     * Method: show
-     * Show the tile.  To be implemented by subclasses.
-     */
-    show: function() { },
-    
-    /** 
-     * Method: hide
-     * Hide the tile.  To be implemented by subclasses.
-     */
-    hide: function() { },
-    
     CLASS_NAME: "OpenLayers.Tile"
 });

Modified: trunk/openlayers/lib/OpenLayers.js
===================================================================
--- trunk/openlayers/lib/OpenLayers.js	2011-08-12 21:17:22 UTC (rev 12240)
+++ trunk/openlayers/lib/OpenLayers.js	2011-08-13 00:59:01 UTC (rev 12241)
@@ -121,6 +121,7 @@
                 "OpenLayers/Marker/Box.js",
                 "OpenLayers/Popup.js",
                 "OpenLayers/Tile.js",
+                "OpenLayers/Tile/BackBufferable.js",
                 "OpenLayers/Tile/Google.js",
                 "OpenLayers/Tile/Image.js",
                 "OpenLayers/Tile/Image/IFrame.js",

Modified: trunk/openlayers/tests/Layer/WMS/Post.html
===================================================================
--- trunk/openlayers/tests/Layer/WMS/Post.html	2011-08-12 21:17:22 UTC (rev 12240)
+++ trunk/openlayers/tests/Layer/WMS/Post.html	2011-08-13 00:59:01 UTC (rev 12241)
@@ -73,8 +73,9 @@
         });
         map.addLayer(layer);
         var tile2 = layer.addTile(bounds, pixel);
-        t.ok(
-            tile2.createIFrame,
+        tile2.draw();
+        t.eq(
+            tile2.useIFrame, true,
             "supported browser: tile is created with the Tile.Image.IFrame mixin");
         map.destroy();
     }

Added: trunk/openlayers/tests/Tile/BackBufferable.html
===================================================================
--- trunk/openlayers/tests/Tile/BackBufferable.html	                        (rev 0)
+++ trunk/openlayers/tests/Tile/BackBufferable.html	2011-08-13 00:59:01 UTC (rev 12241)
@@ -0,0 +1,114 @@
+<html>
+<head>
+  <script src="../OLLoader.js"></script>
+  <script type="text/javascript">
+    var tile;
+    var layer = new OpenLayers.Layer.WMS(
+            "WMS",
+            window.location.href + "#",
+            null,
+            {transitionEffect: "resize"}); 
+    var position = new OpenLayers.Pixel(20,30);
+    var bounds = new OpenLayers.Bounds(1,2,3,4);
+
+    
+    function test_initialize (t) {
+        t.plan(2);
+        
+        tile = new OpenLayers.Tile.Image(layer, position, bounds, null);
+        t.eq(tile.backBufferData, {}, "back buffer data initialized");
+        t.eq(tile.size.w, 256, "size object with default width created");
+    }
+    
+    function test_backBufferMode(t) {
+        t.plan(4);
+
+        var l;
+
+        l = new OpenLayers.Layer.WMS('', window.location.href + '#');
+        tile = new OpenLayers.Tile.Image(l, position, bounds, null);
+        t.eq(tile.backBufferMode, 0,
+             'backBufferMode correctly set [tiled]');
+
+        l = new OpenLayers.Layer.WMS('', window.location.href + '#',
+                                     null, {singleTile: true});
+        tile = new OpenLayers.Tile.Image(l, position, bounds, null);
+        t.eq(tile.backBufferMode, 1,
+             'backBufferMode correctly set [singleTile]');
+
+        l = new OpenLayers.Layer.WMS('', window.location.href + '#',
+                                     null, {transitionEffect: 'resize'});
+        tile = new OpenLayers.Tile.Image(l, position, bounds, null);
+        t.eq(tile.backBufferMode, 2,
+             'backBufferMode correctly set [tiled, transition]');
+
+        l = new OpenLayers.Layer.WMS('', window.location.href + '#',
+                                     null, {singleTile: true,
+                                            transitionEffect: 'resize'});
+        tile = new OpenLayers.Tile.Image(l, position, bounds, null);
+        t.eq(tile.backBufferMode, 3,
+             'backBufferMode correctly set [singleTile, transition]');
+    }
+
+    function test_setBackBufferData(t) {
+        t.plan(2);
+
+        var map = new OpenLayers.Map("map");
+        map.addLayer(layer);
+        map.zoomToMaxExtent();
+        tile = new OpenLayers.Tile.Image(layer, position, bounds, null);
+        tile.draw();
+        // moveTo calls setBackBufferData
+        tile.moveTo(new OpenLayers.Bounds(1,2,3,4),
+                    new OpenLayers.Pixel(30,40), true);
+        t.eq(tile.backBufferData.bounds.toString(), bounds.toString(),
+             "bounds stored correctly");
+        t.eq(tile.backBufferData.resolution, map.getResolution(),
+             "resolution stored correctly");
+        map.removeLayer(layer);
+        map.destroy();
+    }
+    
+    function test_updateBackBuffer(t) {
+        t.plan(1);
+        
+        var map = new OpenLayers.Map("map");
+        map.addLayer(layer);
+        map.zoomToMaxExtent();
+        tile = new OpenLayers.Tile.Image(layer, position, bounds, null);
+        tile.draw();
+        tile.isLoading = false;
+        map.zoomIn();
+        tile.updateBackBuffer();
+        t.eq(tile.backBufferData.tile.style.width, (layer.tileSize.w*2)+"px",
+             "backBuffer frame correctly resized");
+        map.removeLayer(layer);
+        map.destroy();
+    }
+    
+    function test_removeBackBuffer(t) {
+        t.plan(2);
+        var map = new OpenLayers.Map("map");
+        map.addLayer(layer);
+        map.zoomToMaxExtent();
+        tile = new OpenLayers.Tile.Image(layer, position, bounds, null);
+        tile.draw();
+        tile.isLoading = false;
+        map.zoomIn();
+        tile.updateBackBuffer();
+        var backBuffer = tile.backBufferData.tile;
+        tile.removeBackBuffer();
+        t.eq(tile.backBufferData.tile, null,
+             "backBuffer reference removed");
+        t.ok(backBuffer.parentNode !== layer.div,
+             "backBuffer removed from layer");
+        map.removeLayer(layer);
+        map.destroy();
+    }
+        
+  </script>
+</head>
+<body>
+<div id="map" style="height:550px;width:500px"></div>
+</body>
+</html>
\ No newline at end of file

Modified: trunk/openlayers/tests/Tile/Image/IFrame.html
===================================================================
--- trunk/openlayers/tests/Tile/Image/IFrame.html	2011-08-12 21:17:22 UTC (rev 12240)
+++ trunk/openlayers/tests/Tile/Image/IFrame.html	2011-08-13 00:59:01 UTC (rev 12241)
@@ -15,26 +15,29 @@
     var wmsUrl   = "http://labs.metacarta.com/wms/vmap0?";
     
     function test_Tile_Image_IFrame_create (t) {
-        t.plan( 3 );
+        t.plan( 5 );
         map   = new OpenLayers.Map('map');
         var bar = new Array(205).join("1234567890");
-        layer = new OpenLayers.Layer.WMS(name, wmsUrl, {layers: 'basic', foo: bar}, {tileOptions: {maxGetUrlLength: 2048}}); 
+        layer = new OpenLayers.Layer.WMS(name, wmsUrl,
+                                         {layers: 'basic', foo: bar},
+                                         {tileOptions: {maxGetUrlLength: 2048},
+                                          transitionEffect: 'resize'});
         map.addLayer(layer);
 
         var tile = layer.addTile(bounds, position);
-        tile.renderTile();
-        tile.positionImage();
-        t.eq(tile.imgDiv.firstChild.nodeName.toLowerCase(), "iframe", "IFrame used for long URL");
+        t.eq(tile.backBufferMode, 2, "backBufferMode is 2 after tile creation");
+
+        tile.draw();
+        t.eq(tile.imgDiv.nodeName.toLowerCase(), "iframe", "IFrame used for long URL");
         
         layer.mergeNewParams({foo: null});
-        tile.renderTile();
-        tile.positionImage();
+        tile.draw();
         t.eq(tile.imgDiv.nodeName.toLowerCase(), "img", "IMG used for short URL");
+        t.eq(tile.backBufferMode, 2, "backBufferMode reset to 2");
         
         tile.maxGetUrlLength = 0;
-        tile.renderTile();
-        tile.positionImage();
-        t.eq(tile.imgDiv.firstChild.nodeName.toLowerCase(), "iframe", "IFrame used when maxGetUrlLength is 0");
+        tile.draw();
+        t.eq(tile.imgDiv.nodeName.toLowerCase(), "iframe", "IFrame used when maxGetUrlLength is 0");
         
         tile.destroy();
         layer.destroy();
@@ -52,22 +55,22 @@
         tile.clear();
 
         t.eq(
-            tile.imgDiv.firstChild.nodeName.toLowerCase(), "div",
-            "IFrame successfully removed from DOM");
+            tile.frame.getElementsByTagName("iframe").length, 0,
+            "IFrame removed on clear()");
         tile.destroy();
         layer.destroy();
         map.destroy();
     }
 
-    function test_Tile_Image_IFrame_initImgDiv (t) {
-        t.plan( 4 );
+    function test_Tile_Image_IFrame_initImage (t) {
+        t.plan( 2 );
 
         map   = new OpenLayers.Map('map');
         layer = new OpenLayers.Layer.WMS(name, wmsUrl, {layers: 'basic'}, {tileOptions: {maxGetUrlLength: 0}}); 
         map.addLayer(layer);  
         tile = layer.addTile(bounds, position);
         tile.url = layer.getURL(bounds);
-        tile.initImgDiv();
+        tile.initImage();
 
         if(isMozilla) {
             t.ok( tile.imgDiv instanceof HTMLElement, "tile.iFrame successfully created.");
@@ -75,63 +78,41 @@
         else {
             t.ok( tile.imgDiv != null, "tile.iFrame successfully created.");
         }
-        t.eq( tile.imgDiv.id, tile.id, "imgDiv id correctly set.");
         t.eq( tile.imgDiv.className, "olTileImage", "iFrame's className correctly set.");
-        t.ok( tile.imgDiv.map == map, "map correctly added to iFrame.");
 
         map.destroy();
     }
 
-    function test_Tile_Image_IFrame_createImgDiv (t) {
-        t.plan( 3 );
+    function test_Tile_Image_IFrame_createImage (t) {
+        t.plan( 9 );
 
         map   = new OpenLayers.Map('map');
         layer = new OpenLayers.Layer.WMS(name, wmsUrl, {layers: 'basic'}, {tileOptions: {maxGetUrlLength: 0}}); 
         map.addLayer(layer);  
         var tile = layer.addTile(bounds, position);
-        tile.renderTile();
-        var imgDiv = tile.imgDiv;
-        var iFrame    = imgDiv.firstChild;
-        var eventPane = imgDiv.childNodes[1];
+        tile.draw();
+        var iFrame    = tile.imgDiv;
+        var eventPane = tile.frame.childNodes[0];
 
+        t.ok(OpenLayers.String.contains(eventPane.style.backgroundImage,
+                    tile.blankImageUrl),
+             "backgroundImage of eventPane is set.");
+        t.eq(parseInt(eventPane.style.zIndex, 10), 1, "zIndex of eventPane is set.");
         if(isIE) {
             t.ok(iFrame != null, "IFrame successfully created.");
-            t.eq(eventPane.style.backgroundColor, '#ffffff', "backgroundColor of overlay pane is set in InternetExplorer.");
-            t.eq(eventPane.style.filter, 'chroma(color=#FFFFFF)', "filter of overlay pane is set in InternetExplorer.");
-        }
-        else {
-            t.ok(iFrame instanceof HTMLElement, "IFrame successfully created.");
-            t.ok(true, 'Skip eventPane backgroundColor test outside IE');
-            t.ok(true, 'Skip eventPane filter test outside IE');
-        }
-        map.destroy();
-    }
-
-    function test_Tile_Image_IFrame_createIFrame (t) {
-        t.plan( 8 );
-        
-        map   = new OpenLayers.Map('map');
-        layer = new OpenLayers.Layer.WMS(name, wmsUrl, {layers: 'basic'}, {tileOptions: {maxGetUrlLength: 0}}); 
-        map.addLayer(layer);  
-        var tile = layer.addTile(bounds, position);
-        var iFrame = tile.createIFrame();
-
-        var id = tile.id+'_iFrame';
-        t.eq(iFrame.id, id, "iframe id correctly set.");
-        t.eq(iFrame.name, id, "iframe name correctly set.");
-        
-        if(isIE) {
             t.eq(iFrame.style.backgroundColor, '#ffffff', "backgroundColor correctly set.");
             t.eq(iFrame.style.filter, 'chroma(color=#FFFFFF)', "filter correctly set.");
+        } else {
+            t.ok(iFrame instanceof HTMLElement, "IFrame successfully created.");
+            t.ok(true, 'Skip IFrame backgroundColor test outside IE');
+            t.ok(true, 'Skip IFrame filter test outside IE');
         }
-        else {
-            t.eq(iFrame.style.backgroundColor, 'transparent', "backgroundColor correctly set.");
-            t.ok(true, "Skip filter test outside InternetExplorer.");
-        }
         t.eq( iFrame.scrolling, 'no', "no scrolling");
         t.eq( parseFloat(iFrame.marginWidth), 0, "no margin width");
         t.eq( parseFloat(iFrame.marginHeight), 0, "no margin height");
         t.eq( parseFloat(iFrame.frameBorder), 0, "no iframe border");
+
+        map.destroy();
     }
 
     function test_Tile_Image_IFrame_createRequestForm (t) {
@@ -152,7 +133,7 @@
         map.addLayer(newLayer);  
         tile = newLayer.addTile(bounds, position);
         tile.url = newLayer.getURL(bounds);
-        tile.initImgDiv();
+        tile.initImage();
 
         tile.url = newLayer.getURL(bounds);
         var form = tile.createRequestForm();
@@ -182,9 +163,10 @@
 
         tile.draw();
         tile.clear();
+        tile.initImage();
         tile.createRequestForm();
         t.ok(
-            tile.imgDiv.firstChild.nodeName == "IFRAME",
+            tile.imgDiv.nodeName == "IFRAME",
             "Iframe has been reinserted properly"
         );
         

Modified: trunk/openlayers/tests/Tile/Image.html
===================================================================
--- trunk/openlayers/tests/Tile/Image.html	2011-08-12 21:17:22 UTC (rev 12240)
+++ trunk/openlayers/tests/Tile/Image.html	2011-08-13 00:59:01 UTC (rev 12241)
@@ -62,38 +62,16 @@
         map.destroy();
     }
 
-    function test_Tile_Image_clone (t) {
-        t.plan( 9 );
-        
-        var layer = new OpenLayers.Layer.WMS( "OpenLayers WMS", 
-            "http://labs.metacarta.com/wms/vmap0?", {layers: 'basic'}); 
-
-        var position = new OpenLayers.Pixel(20,30);
-        var bounds = new OpenLayers.Bounds(1,2,3,4);
-        var url = "http://www.openlayers.org/dev/tests/tileimage";
-        var size = new OpenLayers.Size(5,6);
-        tile = new OpenLayers.Tile.Image(layer, position, bounds, url, size);
-        tile.imgDiv = {};
-        var clone = tile.clone();
-        
-        t.ok( clone instanceof OpenLayers.Tile.Image, "OpenLayers.Tile.clone returns Tile.Image object" );
-        t.ok( clone.layer == layer, "clone.layer is set correctly");
-        t.ok( clone.position.equals(position), "clone.position is set correctly");
-        t.ok( clone.bounds.equals(bounds), "clone.bounds is set correctly");
-        t.eq( clone.url, url, "clone.url is set correctly");
-        t.ok( clone.size.equals(size), "clone.size is set correctly");
-        t.ok( clone.frame, "clone has a frame");
-        t.ok( clone.frame != tile.frame, "clone's frame is a new one");
-        t.ok( clone.imgDiv == null, "clone's imgDiv was not copied");
-    }
-    
-    function test_Tile_Image_IFrame_viewRequestID (t) {
-        t.plan( 2 );
+    function test_Tile_Image_async (t) {
+        t.plan( 3 );
         var map   = new OpenLayers.Map('map');
         var layer = new OpenLayers.Layer.WMS(
             "Name",
             "http://labs.metacarta.com/TESTURL?",
-            {layers: 'basic'}
+            {layers: 'basic'}, {async: true, getURLasync: function(bounds, scope, url, callback) {
+                scope.url = this.getURL(bounds);
+                callback.call(scope);
+            }}
         ); 
         map.addLayer(layer);
 
@@ -101,10 +79,10 @@
         var bounds = new OpenLayers.Bounds(1,2,3,4);
         tile = layer.addTile(bounds, position);
         tile.renderTile();
-        t.eq(tile.imgDiv.viewRequestID, map.viewRequestID, "viewRequestID correct after renderTile");
-        map.viewRequestID++;
+        t.eq(tile.imgDiv.src, layer.getURL(bounds), "image src correct for async request");
+        t.eq(tile.asyncRequestId, 1, "asyncRequestId correct after renderTile");
         tile.renderTile();
-        t.eq(tile.imgDiv.viewRequestID, map.viewRequestID, "viewRequestID correct after subsequent renderTile");
+        t.eq(tile.asyncRequestId, 2, "asyncRequestId correct after subsequent renderTile");
         tile.destroy();
         layer.destroy();
         map.destroy();
@@ -156,8 +134,8 @@
         t.eq( img.src,
              "http://labs.metacarta.com/TESTURL?" + OpenLayers.Util.getParameterString(tParams),
              "tile.draw creates an image");
-        t.eq( tile.imgDiv.style.width, "5px", "Image width is correct" );
-        t.eq( tile.imgDiv.style.height, "6px", "Image height is correct" );
+        t.eq( tile.imgDiv.style.width, "100%", "Image width is correct" );
+        t.eq( tile.imgDiv.style.height, "100%", "Image height is correct" );
 
         // this should trigger a "reload" event (since the image never actually
         // loads in tests)
@@ -260,14 +238,14 @@
         tile = new OpenLayers.Tile.Image(layer, position, new OpenLayers.Bounds(-90,-85,-90,85), url, size);
         tile.draw();
         tile.moveTo(new OpenLayers.Bounds(-185,-90,-180,-80), new OpenLayers.Pixel(-180,-85), true);
-        t.delay_call( 1, function() { t.eq(tile.imgDiv, null, "Tile imgDiv is null.") } );
+        t.delay_call( 1, function() { t.eq(tile.imgDiv.style.display, "none", "Tile image is invisible.") } );
         var layer = new OpenLayers.Layer.WMS( "OpenLayers WMS", 
             "http://labs.metacarta.com/wms/vmap0?", {layers: 'basic'}, {'reproject': true, 'alpha':true});
         map.addLayer(layer);
         tile = new OpenLayers.Tile.Image(layer, position, new OpenLayers.Bounds(-90,-85,-90,85), url, size);
         tile.draw();
         tile.moveTo(new OpenLayers.Bounds(-185,-90,-180,-80), new OpenLayers.Pixel(-180,-85), true)
-        t.delay_call( 1, function() { t.eq(tile.imgDiv, null, "Alpha tile imgDiv is null.") } );
+        t.delay_call( 1, function() { t.eq(tile.imgDiv.style.display, "none", "Alpha tile image is invisible.") } );
         
     }
 
@@ -316,6 +294,23 @@
         map.destroy();
     }
     
+    function test_createBackBuffer(t) {
+        t.plan(3);
+
+        var map = new OpenLayers.Map('map');
+        var layer = new OpenLayers.Layer.WMS( "OpenLayers WMS", 
+            "http://labs.metacarta.com/wms/vmap0?", {layers: 'basic'});
+        map.addLayer(layer);
+        map.setCenter(new OpenLayers.LonLat(0,0), 5);
+        var tile = layer.grid[0][0];
+        var img = tile.imgDiv;
+        var backBuffer = tile.createBackBuffer();
+        t.eq(backBuffer.style.left, tile.frame.style.left, "backBuffer tile has same left style as frame");
+        t.ok(backBuffer.firstChild === img, "image appended to backBuffer");
+        t.ok(tile.imgDiv == null, "image reference removed from tile");
+        map.destroy();
+    }
+    
   </script>
 </head>
 <body>

Modified: trunk/openlayers/tests/Tile.html
===================================================================
--- trunk/openlayers/tests/Tile.html	2011-08-12 21:17:22 UTC (rev 12240)
+++ trunk/openlayers/tests/Tile.html	2011-08-13 00:59:01 UTC (rev 12241)
@@ -31,32 +31,6 @@
         t.ok( tile.events != null, "tile's events intitialized");
     }
 
-    function test_Tile_clone (t) {
-        t.plan( 10 );
-     
-        var layer = {}; // bogus layer
-        var position = new OpenLayers.Pixel(10,20);
-        var bounds = new OpenLayers.Bounds(1,2,3,4);
-        var url = "bobob";
-        var size = new OpenLayers.Size(5,6);
-        
-        tile = new OpenLayers.Tile(layer, position, bounds, url, size);
-        var clone = tile.clone();
-        
-        t.ok( clone instanceof OpenLayers.Tile, "OpenLayers.Tile.clone returns Tile object" );
-        t.eq( clone.layer, layer, "clone.layer set correctly");
-        t.ok( clone.position.equals(position), "clone.position set correctly");
-        t.ok( clone.bounds.equals(bounds), "clone.bounds set correctly");
-        t.eq( clone.url, url, "clone.url set correctly");        
-        t.ok( clone.size.equals(size), "clone.size is set correctly" );
-
-        t.ok( clone.id != null, "clone is given an id");
-        t.ok( clone.id != tile.id, "clone is given a new id");
-        t.ok(OpenLayers.String.startsWith(clone.id, "Tile_"),
-             "clone's id starts correctly");
-        t.ok( clone.events != null, "clone's events intitialized");
-    }
-
     function test_Tile_destroy(t) {
         t.plan( 6 );
 

Modified: trunk/openlayers/tests/list-tests.html
===================================================================
--- trunk/openlayers/tests/list-tests.html	2011-08-12 21:17:22 UTC (rev 12240)
+++ trunk/openlayers/tests/list-tests.html	2011-08-13 00:59:01 UTC (rev 12241)
@@ -226,6 +226,7 @@
     <li>Tile.html</li>
     <li>Tile/Google.html</li>
     <li>Tile/Image.html</li>
+    <li>Tile/BackBufferable.html</li>
     <li>Tile/Image/IFrame.html</li>
     <li>Tile/WFS.html</li>
     <li>Tween.html</li>

Modified: trunk/openlayers/tests/run-tests.html
===================================================================
--- trunk/openlayers/tests/run-tests.html	2011-08-12 21:17:22 UTC (rev 12240)
+++ trunk/openlayers/tests/run-tests.html	2011-08-13 00:59:01 UTC (rev 12241)
@@ -1102,7 +1102,7 @@
 			if( finished ) {
 				try {
 					action.call_fn();
-				}catch( e ) {
+			    }catch( e ) {
 					Test.AnotherWay._handle_exception( test_object, e, "in delay_call" );
 				}
 			}



More information about the Commits mailing list