Revision: 7092
Author: jlaba...@google.com
Date: Fri Nov 20 16:10:50 2009
Log: Ensures that onload events are fired for images even if the browser  
fires the onload event synchronously while the image is not attached.

Patch by: jlabanca
Review by: jgw (Partial TBR)


http://code.google.com/p/google-web-toolkit/source/detail?r=7092

Modified:
  /trunk/user/src/com/google/gwt/user/client/impl/DOMImplOpera.java
  /trunk/user/src/com/google/gwt/user/client/impl/DOMImplStandard.java
  /trunk/user/src/com/google/gwt/user/client/impl/DOMImplTrident.java
  /trunk/user/src/com/google/gwt/user/client/ui/Image.java
  /trunk/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImpl.java
  /trunk/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImplIE6.java
  /trunk/user/test/com/google/gwt/resources/client/ImageResourceTest.java
  /trunk/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java
  /trunk/user/test/com/google/gwt/user/client/ui/ImageTest.java
  /trunk/user/test/com/google/gwt/user/client/ui/TreeItemTest.java
  /trunk/user/test/com/google/gwt/user/client/ui/TreeTest.java

=======================================
--- /trunk/user/src/com/google/gwt/user/client/impl/DOMImplOpera.java   Tue  
Jul 21 07:10:53 2009
+++ /trunk/user/src/com/google/gwt/user/client/impl/DOMImplOpera.java   Fri  
Nov 20 16:10:50 2009
@@ -59,7 +59,7 @@
      elem.onscroll      = (bits & 0x04000) ?
          @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent :  
null;
      elem.onload        = (bits & 0x08000) ?
-        @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent :  
null;
+         
@com.google.gwt.user.client.impl.DOMImplStandard::dispatchUnhandledEvent :  
null;
      elem.onerror       = (bits & 0x10000) ?
          @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent :  
null;
      elem.onmousewheel  = (bits & 0x20000) ?
=======================================
--- /trunk/user/src/com/google/gwt/user/client/impl/DOMImplStandard.java        
 
Fri Oct 16 14:48:33 2009
+++ /trunk/user/src/com/google/gwt/user/client/impl/DOMImplStandard.java        
 
Fri Nov 20 16:10:50 2009
@@ -38,6 +38,9 @@
    @SuppressWarnings("unused")
    private static JavaScriptObject dispatchEvent;

+  @SuppressWarnings("unused")
+  private static JavaScriptObject dispatchUnhandledEvent;
+
    @Override
    public Element eventGetFromElement(Event evt) {
      if (evt.getType().equals("mouseover")) {
@@ -165,6 +168,11 @@
        return true;
      });

+     
@com.google.gwt.user.client.impl.DOMImplStandard::dispatchUnhandledEvent =  
$entry(function(evt) {
+      this.__gwtLastUnhandledEvent = evt.type;
+       
@com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent.call(this,  
evt);
+    });
+
      @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent =  
$entry(function(evt) {
        var listener, curElem = this;
        while (curElem && !(listener = curElem.__listener)) {
@@ -231,7 +239,7 @@
      if (chMask & 0x04000) elem.onscroll      = (bits & 0x04000) ?
          @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent :  
null;
      if (chMask & 0x08000) elem.onload        = (bits & 0x08000) ?
-        @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent :  
null;
+         
@com.google.gwt.user.client.impl.DOMImplStandard::dispatchUnhandledEvent :  
null;
      if (chMask & 0x10000) elem.onerror       = (bits & 0x10000) ?
          @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent :  
null;
      if (chMask & 0x20000) elem.onmousewheel  = (bits & 0x20000) ?
=======================================
--- /trunk/user/src/com/google/gwt/user/client/impl/DOMImplTrident.java Wed  
Oct 28 09:10:53 2009
+++ /trunk/user/src/com/google/gwt/user/client/impl/DOMImplTrident.java Fri  
Nov 20 16:10:50 2009
@@ -31,6 +31,9 @@
    @SuppressWarnings("unused")
    private static JavaScriptObject dispatchDblClickEvent;

+  @SuppressWarnings("unused")
+  private static JavaScriptObject dispatchUnhandledEvent;
+
    /**
     * Let every GWT app on the page preview the current event. If any app  
cancels
     * the event, the event will be canceled for all apps.
@@ -151,6 +154,11 @@
        }
      });

+     
@com.google.gwt.user.client.impl.DOMImplTrident::dispatchUnhandledEvent =  
$entry(function() {
+      this.__gwtLastUnhandledEvent = $wnd.event.type;
+       
@com.google.gwt.user.client.impl.DOMImplTrident::dispatchEvent.call(this);
+    });
+
      // We need to create these delegate functions to fix up the 'this'  
context.
      // Normally, 'this' is the firing element, but this is only true for
      // 'onclick = ...' event handlers, not for handlers setup via  
attachEvent().
@@ -243,7 +251,7 @@
      if (chMask & 0x04000) elem.onscroll      = (bits & 0x04000) ?
          @com.google.gwt.user.client.impl.DOMImplTrident::dispatchEvent :  
null;
      if (chMask & 0x08000) elem.onload        = (bits & 0x08000) ?
-        @com.google.gwt.user.client.impl.DOMImplTrident::dispatchEvent :  
null;
+         
@com.google.gwt.user.client.impl.DOMImplTrident::dispatchUnhandledEvent :  
null;
      if (chMask & 0x10000) elem.onerror       = (bits & 0x10000) ?
          @com.google.gwt.user.client.impl.DOMImplTrident::dispatchEvent :  
null;
      if (chMask & 0x20000) elem.onmousewheel  = (bits & 0x20000) ?
=======================================
--- /trunk/user/src/com/google/gwt/user/client/ui/Image.java    Thu Oct  8  
12:27:08 2009
+++ /trunk/user/src/com/google/gwt/user/client/ui/Image.java    Fri Nov 20  
16:10:50 2009
@@ -1,12 +1,12 @@
  /*
   * Copyright 2008 Google Inc.
- *
+ *
   * Licensed under the Apache License, Version 2.0 (the "License"); you may  
not
   * use this file except in compliance with the License. You may obtain a  
copy of
   * the License at
- *
+ *
   * http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,  
WITHOUT
   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -19,6 +19,7 @@
  import com.google.gwt.dom.client.Document;
  import com.google.gwt.dom.client.Element;
  import com.google.gwt.dom.client.ImageElement;
+import com.google.gwt.dom.client.NativeEvent;
  import com.google.gwt.event.dom.client.ClickEvent;
  import com.google.gwt.event.dom.client.ClickHandler;
  import com.google.gwt.event.dom.client.ErrorEvent;
@@ -43,6 +44,8 @@
  import com.google.gwt.event.dom.client.MouseWheelHandler;
  import com.google.gwt.event.shared.HandlerRegistration;
  import com.google.gwt.resources.client.ImageResource;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DeferredCommand;
  import com.google.gwt.user.client.Event;
  import com.google.gwt.user.client.ui.impl.ClippedImageImpl;

@@ -57,16 +60,20 @@
   * image is constructed, and how it is transformed after construction.  
Methods
   * will operate differently depending on the mode that the image is in.  
These
   * differences are detailed in the documentation for each method.
- *
+ *
   * <p>
   * If an image transitions between clipped mode and unclipped mode, any
   * {...@link Element}-specific attributes added by the user (including style
   * attributes, style names, and style modifiers), except for event  
listeners,
   * will be lost.
   * </p>
- *
- * <h3>CSS Style Rules</h3> <ul class="css"> <li>.gwt-Image { }</li> </ul>
- *
+ *
+ * <h3>CSS Style Rules</h3>
+ * <dl>
+ * <dt>.gwt-Image</dt>
+ * </dd>The outer element</dd>
+ * </dl>
+ *
   * Tranformations between clipped and unclipped state will result in a  
loss of
   * any style names that were set/added; the only style names that are  
preserved
   * are those that are mentioned in the static CSS style rules. Due to
@@ -75,7 +82,7 @@
   * expected when an image is in clipped mode. These limitations can  
usually be
   * easily worked around by encapsulating the image in a container widget  
that
   * can itself be styled.
- *
+ *
   * <p>
   * <h3>Example</h3>
   * {...@example com.google.gwt.examples.ImageExample}
@@ -86,6 +93,12 @@
      HasLoadHandlers, HasErrorHandlers, SourcesClickEvents,  
HasClickHandlers,
      HasAllMouseHandlers, SourcesMouseEvents {

+  /**
+   * The attribute that is set when an image fires a native load or error  
event
+   * before it is attached.
+   */
+  private static final String UNHANDLED_EVENT_ATTR  
= "__gwtLastUnhandledEvent";
+
    /**
     * Implementation of behaviors associated with the clipped state of an  
image.
     */
@@ -117,6 +130,11 @@
      public int getHeight(Image image) {
        return height;
      }
+
+    @Override
+    public ImageElement getImageElement(Image image) {
+      return impl.getImgElement(image).cast();
+    }

      @Override
      public int getOriginLeft() {
@@ -140,7 +158,10 @@

      @Override
      public void setUrl(Image image, String url) {
-      image.changeState(new UnclippedState(image, url));
+      image.changeState(new UnclippedState(image));
+      // Need to make sure we change the state before an onload event can  
fire,
+      // or handlers will be fired while we are in the old state.
+      image.setUrl(url);
      }

      @Override
@@ -156,7 +177,7 @@
          this.height = height;

          impl.adjust(image.getElement(), url, left, top, width, height);
-        impl.fireSyntheticLoadEvent(image);
+        fireSyntheticLoadEvent(image);
        }
      }

@@ -177,7 +198,7 @@
          this.height = height;

          impl.adjust(image.getElement(), url, left, top, width, height);
-        impl.fireSyntheticLoadEvent(image);
+        fireSyntheticLoadEvent(image);
        }
      }

@@ -196,6 +217,8 @@

      public abstract int getHeight(Image image);

+    public abstract ImageElement getImageElement(Image image);
+
      public abstract int getOriginLeft();

      public abstract int getOriginTop();
@@ -204,6 +227,16 @@

      public abstract int getWidth(Image image);

+    public void onLoad(Image image) {
+      // If an onload event fired while the image wasn't attached, we need  
to
+      // synthesize one now.
+      String unhandledEvent = getImageElement(image).getPropertyString(
+          UNHANDLED_EVENT_ATTR);
+      if ("load".equals(unhandledEvent)) {
+        fireSyntheticLoadEvent(image);
+      }
+    }
+
      public abstract void setUrl(Image image, String url);

      public abstract void setUrlAndVisibleRect(Image image, String url,
@@ -211,6 +244,27 @@

      public abstract void setVisibleRect(Image image, int left, int top,
          int width, int height);
+
+    /**
+     * We need to synthesize a load event in case the image loads  
synchronously,
+     * before our handlers can be attached.
+     *
+     * @param image the image on which to dispatch the event
+     */
+    protected void fireSyntheticLoadEvent(final Image image) {
+      /*
+       * We use a deferred command here to simulate the native version of  
the
+       * event as closely as possible. In the native event case, it is  
unlikely
+       * that a second load event would occur while you are in the load  
event
+       * handler.
+       */
+      DeferredCommand.addCommand(new Command() {
+        public void execute() {
+          NativeEvent evt = Document.get().createLoadEvent();
+          getImageElement(image).dispatchEvent(evt);
+        }
+      });
+    }

      // This method is used only by unit tests.
      protected abstract String getStateName();
@@ -248,7 +302,12 @@

      @Override
      public int getHeight(Image image) {
-      return image.getImageElement().getHeight();
+      return getImageElement(image).getHeight();
+    }
+
+    @Override
+    public ImageElement getImageElement(Image image) {
+      return image.getElement().cast();
      }

      @Override
@@ -263,17 +322,18 @@

      @Override
      public String getUrl(Image image) {
-      return image.getImageElement().getSrc();
+      return getImageElement(image).getSrc();
      }

      @Override
      public int getWidth(Image image) {
-      return image.getImageElement().getWidth();
+      return getImageElement(image).getWidth();
      }

      @Override
      public void setUrl(Image image, String url) {
-      image.getImageElement().setSrc(url);
+      image.clearUnhandledEvent();
+      getImageElement(image).setSrc(url);
      }

      @Override
@@ -305,7 +365,7 @@

    /**
     * Causes the browser to pre-fetch the image at a given URL.
-   *
+   *
     * @param url the URL of the image to be prefetched
     */
    public static void prefetch(String url) {
@@ -316,11 +376,11 @@

    /**
     * Creates a Image widget that wraps an existing &lt;img&gt; element.
-   *
+   *
     * This element must already be attached to the document. If the element  
is
     * removed from the document, you must call
     * {...@link RootPanel#detachNow(Widget)}.
-   *
+   *
     * @param element the element to be wrapped
     */
    public static Image wrap(Element element) {
@@ -349,18 +409,18 @@

    /**
     * Creates an image whose size and content are defined by an  
ImageResource.
-   *
+   *
     * @param resource the ImageResource to be displayed
     */
    public Image(ImageResource resource) {
-    this(resource.getURL(), resource.getLeft(),
-         resource.getTop(), resource.getWidth(), resource.getHeight());
+    this(resource.getURL(), resource.getLeft(), resource.getTop(),
+        resource.getWidth(), resource.getHeight());
    }

    /**
     * Creates an image with a specified URL. The load event will be fired  
once
     * the image at the given URL has been retrieved by the browser.
-   *
+   *
     * @param url the URL of the image to be displayed
     */
    public Image(String url) {
@@ -377,7 +437,7 @@
     * the width and height are specified explicitly by the user, this  
behavior
     * will not cause problems with retrieving the width and height of a  
clipped
     * image in a load event handler.
-   *
+   *
     * @param url the URL of the image to be displayed
     * @param left the horizontal co-ordinate of the upper-left vertex of the
     *          visibility rectangle
@@ -394,7 +454,7 @@
    /**
     * This constructor may be used by subclasses to explicitly use an  
existing
     * element. This element must be an &lt;img&gt; element.
-   *
+   *
     * @param element the element to be used
     */
    protected Image(Element element) {
@@ -436,9 +496,9 @@
    }

    /**
-   * @deprecated Use {...@link #addMouseOverHandler} {...@link
-   * #addMouseMoveHandler}, {...@link #addMouseDownHandler}, {...@link
-   * #addMouseUpHandler} and {...@link #addMouseOutHandler} instead
+   * @deprecated Use {...@link #addMouseOverHandler} {...@link  
#addMouseMoveHandler},
+   *             {...@link #addMouseDownHandler}, {...@link 
#addMouseUpHandler}  
and
+   *             {...@link #addMouseOutHandler} instead
     */
    @Deprecated
    public void addMouseListener(MouseListener listener) {
@@ -477,7 +537,7 @@
     * Gets the height of the image. When the image is in the unclipped  
state, the
     * height of the image is not known until the image has been loaded  
(i.e. load
     * event has been fired for the image).
-   *
+   *
     * @return the height of the image, or 0 if the height is unknown
     */
    public int getHeight() {
@@ -489,7 +549,7 @@
     * visibility rectangle. If the image is in the unclipped state, then the
     * visibility rectangle is assumed to be the rectangle which encompasses  
the
     * entire image, which has an upper-left vertex of (0,0).
-   *
+   *
     * @return the horizontal co-ordinate of the upper-left vertex of the  
image's
     *         visibility rectangle
     */
@@ -502,7 +562,7 @@
     * visibility rectangle. If the image is in the unclipped state, then the
     * visibility rectangle is assumed to be the rectangle which encompasses  
the
     * entire image, which has an upper-left vertex of (0,0).
-   *
+   *
     * @return the vertical co-ordinate of the upper-left vertex of the  
image's
     *         visibility rectangle
     */
@@ -514,7 +574,7 @@
     * Gets the URL of the image. The URL that is returned is not  
necessarily the
     * URL that was passed in by the user. It may have been transformed to an
     * absolute URL.
-   *
+   *
     * @return the image URL
     */
    public String getUrl() {
@@ -525,16 +585,27 @@
     * Gets the width of the image. When the image is in the unclipped  
state, the
     * width of the image is not known until the image has been loaded (i.e.  
load
     * event has been fired for the image).
-   *
+   *
     * @return the width of the image, or 0 if the width is unknown
     */
    public int getWidth() {
      return state.getWidth(this);
    }
+
+  @Override
+  public void onBrowserEvent(Event event) {
+    // We have to clear the unhandled event before firing handlers because  
the
+    // handlers could trigger onLoad, which would refire the event.
+    if (event.getTypeInt() == Event.ONLOAD) {
+      clearUnhandledEvent();
+    }
+
+    super.onBrowserEvent(event);
+  }

    /**
-   * @deprecated Use the {...@link HandlerRegistration#removeHandler} method  
on
-   * the object returned by {...@link #addClickHandler} instead
+   * @deprecated Use the {...@link HandlerRegistration#removeHandler} method  
on the
+   *             object returned by {...@link #addClickHandler} instead
     */
    @Deprecated
    public void removeClickListener(ClickListener listener) {
@@ -542,8 +613,8 @@
    }

    /**
-   * @deprecated Use the {...@link HandlerRegistration#removeHandler}
-   * method on the object returned by an add*Handler method instead
+   * @deprecated Use the {...@link HandlerRegistration#removeHandler} method  
on the
+   *             object returned by an add*Handler method instead
     */
    @Deprecated
    public void removeLoadListener(LoadListener listener) {
@@ -551,8 +622,8 @@
    }

    /**
-   * @deprecated Use the {...@link HandlerRegistration#removeHandler}
-   * method on the object returned by an add*Handler method instead
+   * @deprecated Use the {...@link HandlerRegistration#removeHandler} method  
on the
+   *             object returned by an add*Handler method instead
     */
    @Deprecated
    public void removeMouseListener(MouseListener listener) {
@@ -560,9 +631,8 @@
    }

    /**
-   * @deprecated Use the {...@link HandlerRegistration#removeHandler}
-   * method on the object returned by {...@link #addMouseWheelHandler}
-   * instead
+   * @deprecated Use the {...@link HandlerRegistration#removeHandler} method  
on the
+   *             object returned by {...@link #addMouseWheelHandler} instead
     */
    @Deprecated
    public void removeMouseWheelListener(MouseWheelListener listener) {
@@ -576,7 +646,7 @@
     * image's current url or current visibility rectangle co-ordinates. If  
the
     * image is currently in the unclipped state, a call to this method will  
cause
     * a transition to the clipped state.
-   *
+   *
     * @param resource the ImageResource to display
     */
    public void setResource(ImageResource resource) {
@@ -589,7 +659,7 @@
     * state, a call to this method will cause a transition of the image to  
the
     * unclipped state. Regardless of whether or not the image is in the  
clipped
     * or unclipped state, a load event will be fired.
-   *
+   *
     * @param url the image URL
     */
    public void setUrl(String url) {
@@ -603,7 +673,7 @@
     * visibility rectangle co-ordinates. If the image is currently in the
     * unclipped state, a call to this method will cause a transition to the
     * clipped state.
-   *
+   *
     * @param url the image URL
     * @param left the horizontal coordinate of the upper-left vertex of the
     *          visibility rectangle
@@ -626,7 +696,7 @@
     * is in the unclipped state, a call to this method will cause a  
transition of
     * the image to the clipped state. This transition will cause a load  
event to
     * fire.
-   *
+   *
     * @param left the horizontal coordinate of the upper-left vertex of the
     *          visibility rectangle
     * @param top the vertical coordinate of the upper-left vertex of the
@@ -637,12 +707,26 @@
    public void setVisibleRect(int left, int top, int width, int height) {
      state.setVisibleRect(this, left, top, width, height);
    }
+
+  @Override
+  protected void onLoad() {
+    super.onLoad();
+
+    // Issue 863: the state may need to fire a synthetic event if the  
native
+    // onload event fired while the image was detached.
+    state.onLoad(this);
+  }

    private void changeState(State newState) {
      state = newState;
    }

-  private ImageElement getImageElement() {
-    return getElement().cast();
+  /**
+   * Clear the unhandled event.
+   */
+  private void clearUnhandledEvent() {
+    if (state != null) {
+       
state.getImageElement(this).setPropertyString(UNHANDLED_EVENT_ATTR, "");
+    }
    }
  }
=======================================
---  
/trunk/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImpl.java        
 
Fri Feb  6 13:06:24 2009
+++  
/trunk/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImpl.java        
 
Fri Nov 20 16:10:50 2009
@@ -1,12 +1,12 @@
  /*
   * Copyright 2008 Google Inc.
- *
+ *
   * Licensed under the Apache License, Version 2.0 (the "License"); you may  
not
   * use this file except in compliance with the License. You may obtain a  
copy of
   * the License at
- *
+ *
   * http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,  
WITHOUT
   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -18,22 +18,19 @@
  import com.google.gwt.core.client.GWT;
  import com.google.gwt.dom.client.Document;
  import com.google.gwt.dom.client.Element;
-import com.google.gwt.dom.client.NativeEvent;
-import com.google.gwt.user.client.Command;
-import com.google.gwt.user.client.DeferredCommand;
  import com.google.gwt.user.client.ui.Image;

  /**
   * Uses a combination of a clear image and a background image to clip all  
except
   * a desired portion of an underlying image.
- *
+ *
   * Do not use this class - it is used for implementation only, and its  
methods
   * may change in the future.
   */
  public class ClippedImageImpl {

    public void adjust(Element img, String url, int left, int top, int width,
-                     int height) {
+      int height) {
      String style = "url(" + url + ") no-repeat " + (-left + "px ")
          + (-top + "px");
      img.getStyle().setProperty("background", style);
@@ -42,7 +39,7 @@
    }

    public Element createStructure(String url, int left, int top, int width,
-                                 int height) {
+      int height) {
      Element tmp = Document.get().createSpanElement();
      tmp.setInnerHTML(getHTML(url, left, top, width, height));
      return tmp.getFirstChildElement();
@@ -53,31 +50,15 @@
          + "px; background: url(" + url + ") no-repeat " + (-left + "px ")
          + (-top + "px");

-    String clippedImgHtml = "<img src='" + GWT.getModuleBaseURL() +
-        "clear.cache.gif' style='" + style + "' border='0'>";
+    String clippedImgHtml = "<img "
+        + "onload='this.__gwtLastUnhandledEvent=\"load\";' src='"
+        + GWT.getModuleBaseURL() + "clear.cache.gif' style='" + style
+        + "' border='0'>";

      return clippedImgHtml;
    }

-  public void fireSyntheticLoadEvent(final Image image) {
-    /*
-     * We need to synthesize a load event, because the native events that  
are
-     * fired would correspond to the loading of clear.cache.gif, which is
-     * incorrect. A native event would not even fire in Internet Explorer,
-     * because the root element is a wrapper element around the <img>  
element.
-     * Since we are synthesizing a load event, we do not need to sink the
-     * onload event.
-     *
-     * We use a deferred command here to simulate the native version of the
-     * load event as closely as possible. In the native event case, it is
-     * unlikely that a second load event would occur while you are in the  
load
-     * event handler.
-     */
-    DeferredCommand.addCommand(new Command() {
-      public void execute() {
-        NativeEvent evt = Document.get().createLoadEvent();
-        image.getElement().dispatchEvent(evt);
-      }
-    });
+  public Element getImgElement(Image image) {
+    return image.getElement();
    }
  }
=======================================
---  
/trunk/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImplIE6.java     
 
Tue Nov 10 11:56:03 2009
+++  
/trunk/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImplIE6.java     
 
Fri Nov 20 16:10:50 2009
@@ -16,11 +16,7 @@
  package com.google.gwt.user.client.ui.impl;

  import com.google.gwt.core.client.GWT;
-import com.google.gwt.dom.client.Document;
  import com.google.gwt.dom.client.Element;
-import com.google.gwt.dom.client.NativeEvent;
-import com.google.gwt.user.client.Command;
-import com.google.gwt.user.client.DeferredCommand;
  import com.google.gwt.user.client.Event;
  import com.google.gwt.user.client.ui.Image;

@@ -112,25 +108,6 @@
      Event.sinkEvents(img, Event.ONLOAD);
      return clipper;
    }
-
-  public void fireSyntheticLoadEvent(final Image image) {
-    if (!isIE6) {
-      super.fireSyntheticLoadEvent(image);
-      return;
-    }
-
-    // This is the same as the superclass' implementation, except that it
-    // explicitly checks for the 'clipper' element, and dispatches the  
event
-    // on the img (you can't dispatch events on the clipper).
-    DeferredCommand.addCommand(new Command() {
-      public void execute() {
-        NativeEvent evt = Document.get().createLoadEvent();
-        Element clipper = image.getElement();
-        Element img = clipper.getFirstChildElement();
-        img.dispatchEvent(evt);
-      }
-    });
-  }

    @Override
    public String getHTML(String url, int left, int top, int width, int  
height) {
@@ -158,7 +135,7 @@
       */
      String clippedImgHtml = "<gwt:clipper style=\""
          + clipperStyle
-        + "\"><img src='"
+        + "\"><img onload='this.__gwtLastUnhandledEvent=\"load\";' src='"
          + moduleBaseUrlProtocol
          + "'  
onerror='if(window.__gwt_transparentImgHandler)window.__gwt_transparentImgHandler(this);else
  
this.src=\"" + GWT.getModuleBaseURL() + "clear.cache.gif\"' style=\""
          + imgStyle + "\" width=" + (left + width) + " height=" + (top +  
height)
@@ -166,4 +143,12 @@

      return clippedImgHtml;
    }
-}
+
+  @Override
+  public Element getImgElement(Image image) {
+    if (!isIE6) {
+      return super.getImgElement(image);
+    }
+    return image.getElement().getFirstChildElement();
+  }
+}
=======================================
--- /trunk/user/test/com/google/gwt/resources/client/ImageResourceTest.java     
 
Wed Sep 30 16:46:38 2009
+++ /trunk/user/test/com/google/gwt/resources/client/ImageResourceTest.java     
 
Fri Nov 20 16:10:50 2009
@@ -92,13 +92,7 @@
      assertFalse(a.getURL().equals(r.i16x16().getURL()));
    }

-  /**
-   * Issue 863: Image.onload event does not fire on Internet Explorer when  
image
-   * is in cache.
-   *
-   * TODO(jlabanca): Reenable this test after fixing the issue.
-   */
-  public void disabledTestDedup() {
+  public void testDedup() {
      Resources r = GWT.create(Resources.class);

      ImageResource a = r.i64x64();
=======================================
--- /trunk/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java      
 
Mon Nov 16 10:04:26 2009
+++ /trunk/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java      
 
Fri Nov 20 16:10:50 2009
@@ -41,6 +41,7 @@
  /**
   * Functional test of UiBinder.
   */
+...@donotrunwith({Platform.HtmlUnit})
  public class UiBinderTest extends GWTTestCase {
    private WidgetBasedUi widgetUi;
    private DomBasedUi domUi;
=======================================
--- /trunk/user/test/com/google/gwt/user/client/ui/ImageTest.java       Mon Nov 
  
2 12:47:09 2009
+++ /trunk/user/test/com/google/gwt/user/client/ui/ImageTest.java       Fri Nov 
 
20 16:10:50 2009
@@ -1,12 +1,12 @@
  /*
   * Copyright 2008 Google Inc.
- *
+ *
   * Licensed under the Apache License, Version 2.0 (the "License"); you may  
not
   * use this file except in compliance with the License. You may obtain a  
copy of
   * the License at
- *
+ *
   * http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,  
WITHOUT
   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -27,12 +27,13 @@
  import com.google.gwt.junit.client.GWTTestCase;
  import com.google.gwt.resources.client.ClientBundle;
  import com.google.gwt.resources.client.ImageResource;
+import com.google.gwt.user.client.Timer;

  /**
   * Tests for the Image widget. Images in both clipped mode and unclipped  
mode
   * are tested, along with the transitions between the two modes.
   */
-...@suppresswarnings("deprecation")
+...@donotrunwith({Platform.HtmlUnit})
  public class ImageTest extends GWTTestCase {
    interface Bundle extends ClientBundle {
      ImageResource prettyPiccy();
@@ -49,6 +50,24 @@
        fail("The image " + image.getUrl() + " failed to load.");
      }
    }
+
+  private abstract static class TestLoadHandler implements LoadHandler {
+    private boolean finished = false;
+
+    /**
+     * Mark the test as finished.
+     */
+    public void finish() {
+      finished = true;
+    }
+
+    /**
+     * @return true if the test has finished
+     */
+    public boolean isFinished() {
+      return finished;
+    }
+  }

    @Deprecated
    private abstract static class TestLoadListener implements LoadListener {
@@ -82,7 +101,7 @@
     * Helper method that allows us to 'peek' at the private  
<code>state</code>
     * field in the Image object, and call the  
<code>state.getStateName()</code>
     * method.
-   *
+   *
     * @param image The image instance
     * @return "unclipped" if image is in the unclipped state, or "clipped"  
if the
     *         image is in the clipped state
@@ -95,26 +114,25 @@
    private int firedError;

    private int firedLoad;
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.user.UserTest";
+  }

    /**
     * Tests the transition from the clipped state to the unclipped state.
-   *
-   * Disabled because of issue #863 & #864. It fails intermittently in  
linux
-   * hosted mode tests.
     */
-  public void disabledTestChangeClippedImageToUnclipped() {
+  public void testChangeClippedImageToUnclipped() {
      final Image image = new Image("counting-forwards.png", 12, 13, 8, 8);
      assertEquals("clipped", getCurrentImageStateName(image));

      delayTestFinish(5000);
-    image.addLoadListener(new LoadListener() {
+    image.addErrorHandler(new TestErrorHandler(image));
+    image.addLoadHandler(new LoadHandler() {
        private int onLoadEventCount = 0;

-      public void onError(Widget sender) {
-        fail("The image " + ((Image) sender).getUrl() + " failed to  
load.");
-      }
-
-      public void onLoad(Widget sender) {
+      public void onLoad(LoadEvent event) {
          ++onLoadEventCount;
          if (onLoadEventCount == 1) { // Set the url after the first image  
loads
            image.setUrl("counting-forwards.png");
@@ -134,22 +152,17 @@

    /**
     * Tests the transition from the unclipped state to the clipped state.
-   *
-   * Disabled because of issue #863.
     */
-  public void disabledTestChangeImageToClipped() {
+  public void testChangeImageToClipped() {
      final Image image = new Image("counting-forwards.png");
      assertEquals("unclipped", getCurrentImageStateName(image));

      delayTestFinish(5000);
-    image.addLoadListener(new LoadListener() {
+    image.addErrorHandler(new TestErrorHandler(image));
+    image.addLoadHandler(new LoadHandler() {
        private int onLoadEventCount = 0;

-      public void onError(Widget sender) {
-        fail("The image " + ((Image) sender).getUrl() + " failed to  
load.");
-      }
-
-      public void onLoad(Widget sender) {
+      public void onLoad(LoadEvent event) {
          if (getCurrentImageStateName(image).equals("unclipped")) {
            image.setVisibleRect(12, 13, 8, 8);
          }
@@ -170,21 +183,16 @@

    /**
     * Tests the creation of an image in unclipped mode.
-   *
-   * Disabled because of issue #863 & #864.
     */
-  public void disabledTestCreateImage() {
+  public void testCreateImage() {
      final Image image = new Image("counting-forwards.png");

      delayTestFinish(5000);
-    image.addLoadListener(new LoadListener() {
+    image.addErrorHandler(new TestErrorHandler(image));
+    image.addLoadHandler(new LoadHandler() {
        private int onLoadEventCount = 0;

-      public void onError(Widget sender) {
-        fail("The image " + ((Image) sender).getUrl() + " failed to  
load.");
-      }
-
-      public void onLoad(Widget sender) {
+      public void onLoad(LoadEvent event) {
          if (++onLoadEventCount == 1) {
            assertEquals(32, image.getWidth());
            assertEquals(32, image.getHeight());
@@ -198,26 +206,42 @@
      assertEquals(0, image.getOriginTop());
      assertEquals("unclipped", getCurrentImageStateName(image));
    }
+
+  /**
+   * Tests the creation of an image that does not exist.
+   */
+  public void testCreateImageWithError() {
+    final Image image = new Image("imageDoesNotExist.png");
+
+    delayTestFinish(5000);
+    image.addErrorHandler(new ErrorHandler() {
+      public void onError(ErrorEvent event) {
+        finishTest();
+      }
+    });
+    image.addLoadHandler(new LoadHandler() {
+      public void onLoad(LoadEvent event) {
+        fail("The image " + image.getUrl() + " should have failed to  
load.");
+      }
+    });
+
+    RootPanel.get().add(image);
+  }

    /**
     * Tests the firing of onload events when
     * {...@link com.google.gwt.user.client.ui.Image#setUrl(String)} is called  
on an
     * unclipped image.
-   *
-   * Disabled because of issue #863
     */
-  public void disabledTestSetUrlAndLoadEventsOnUnclippedImage() {
+  public void testSetUrlAndLoadEventsOnUnclippedImage() {
      final Image image = new Image();

      delayTestFinish(5000);
-    image.addLoadListener(new LoadListener() {
+    image.addErrorHandler(new TestErrorHandler(image));
+    image.addLoadHandler(new LoadHandler() {
        private int onLoadEventCount = 0;

-      public void onError(Widget sender) {
-        fail("The image " + ((Image) sender).getUrl() + " failed to  
load.");
-      }
-
-      public void onLoad(Widget sender) {
+      public void onLoad(LoadEvent event) {
          if (++onLoadEventCount == 2) {
            finishTest();
          } else {
@@ -232,23 +256,19 @@

    /**
     * Tests the behavior of
-   * <code>setUrlAndVisibleRect(String, int, int, int, int)</code> method  
on
-   * an unclipped image, which causes a state transition to the clipped  
state.
-   *
-   * Disabled because of issue #863.
+   * <code>setUrlAndVisibleRect(String, int, int, int, int)</code> method  
on an
+   * unclipped image, which causes a state transition to the clipped state.
     */
-  public void disabledTestSetUrlAndVisibleRectOnUnclippedImage() {
+  public void testSetUrlAndVisibleRectOnUnclippedImage() {
      final Image image = new Image("counting-backwards.png");
+    assertEquals("unclipped", getCurrentImageStateName(image));

      delayTestFinish(5000);
-    image.addLoadListener(new LoadListener() {
+    image.addErrorHandler(new TestErrorHandler(image));
+    image.addLoadHandler(new LoadHandler() {
        private int onLoadEventCount = 0;

-      public void onError(Widget sender) {
-        fail("The image " + ((Image) sender).getUrl() + " failed to  
load.");
-      }
-
-      public void onLoad(Widget sender) {
+      public void onLoad(LoadEvent event) {
          if (getCurrentImageStateName(image).equals("unclipped")) {
            image.setUrlAndVisibleRect("counting-forwards.png", 0, 16, 16,  
16);
          }
@@ -265,19 +285,13 @@
      });

      RootPanel.get().add(image);
-    assertEquals("unclipped", getCurrentImageStateName(image));
-  }
-
-  @Override
-  public String getModuleName() {
-    return "com.google.gwt.user.UserTest";
    }

    /**
     * Tests the creation of an image in clipped mode.
     */
-  @DoNotRunWith({Platform.HtmlUnit})
-  public void disabledTestCreateClippedImage() {
+  @SuppressWarnings("deprecation")
+  public void testCreateClippedImage() {
      final Image image = new Image("counting-forwards.png", 16, 16, 16, 16);

      delayTestFinish(5000);
@@ -343,6 +357,83 @@
      assertEquals(1, firedError);
    }

+  /**
+   * Verify that detaching and reattaching an image in a handler does not  
fire a
+   * second onload event.
+   */
+  public void testNoEventOnReattachInHandler() {
+    final Image image = new Image("counting-forwards.png");
+
+    delayTestFinish(5000);
+    image.addErrorHandler(new TestErrorHandler(image));
+    image.addLoadHandler(new LoadHandler() {
+      private int onLoadEventCount = 0;
+
+      public void onLoad(LoadEvent event) {
+        if (++onLoadEventCount == 1) {
+          RootPanel.get().remove(image);
+          RootPanel.get().add(image);
+          // The extra onLoad would will fire synchronously before  
finishTest().
+          finishTest();
+        } else {
+          fail("onLoad fired on reattach.");
+        }
+      }
+    });
+
+    RootPanel.get().add(image);
+  }
+
+  public void testOneEventOnly() {
+    final Image image = new Image("counting-forwards.png");
+
+    final TestLoadHandler loadHandler = new TestLoadHandler() {
+      public void onLoad(LoadEvent event) {
+        if (isFinished()) {
+          fail("LoadHandler fired multiple times.");
+        }
+        finish();
+      }
+    };
+    delayTestFinish(6000);
+    new Timer() {
+      @Override
+      public void run() {
+        assertTrue(loadHandler.isFinished());
+        finishTest();
+      }
+    }.schedule(5000);
+    image.addErrorHandler(new TestErrorHandler(image));
+    image.addLoadHandler(loadHandler);
+
+    RootPanel.get().add(image);
+  }
+
+  public void testOneEventOnlyClippedImage() {
+    final Image image = new Image("counting-forwards.png", 12, 13, 8, 8);
+
+    final TestLoadHandler loadHandler = new TestLoadHandler() {
+      public void onLoad(LoadEvent event) {
+        if (isFinished()) {
+          fail("LoadHandler fired multiple times.");
+        }
+        finish();
+      }
+    };
+    delayTestFinish(6000);
+    new Timer() {
+      @Override
+      public void run() {
+        assertTrue(loadHandler.isFinished());
+        finishTest();
+      }
+    }.schedule(5000);
+    image.addErrorHandler(new TestErrorHandler(image));
+    image.addLoadHandler(loadHandler);
+
+    RootPanel.get().add(image);
+  }
+
    public void testResourceConstructor() {
      Bundle b = GWT.create(Bundle.class);
      Image image = new Image(b.prettyPiccy());
@@ -361,8 +452,8 @@
     * {...@link  
com.google.gwt.user.client.ui.Image#setUrlAndVisibleRect(String,int,int,int,int)}
     * on a clipped image.
     */
-  @DoNotRunWith({Platform.HtmlUnit})
-  public void disabledTestSetUrlAndVisibleRectOnClippedImage() {
+  @SuppressWarnings("deprecation")
+  public void testSetUrlAndVisibleRectOnClippedImage() {
      final Image image = new Image("counting-backwards.png", 12, 12, 12,  
12);
      delayTestFinish(5000);

@@ -412,8 +503,8 @@
     * {...@link  
com.google.gwt.user.client.ui.Image#setVisibleRect(int,int,int,int)}
     * on a clipped image.
     */
-  @DoNotRunWith({Platform.HtmlUnit})
-  public void disabledTestSetVisibleRectAndLoadEventsOnClippedImage() {
+  @SuppressWarnings("deprecation")
+  public void testSetVisibleRectAndLoadEventsOnClippedImage() {
      final Image image = new Image("counting-backwards.png", 16, 16, 16,  
16);

      delayTestFinish(5000);
=======================================
--- /trunk/user/test/com/google/gwt/user/client/ui/TreeItemTest.java    Wed  
Sep 23 10:15:52 2009
+++ /trunk/user/test/com/google/gwt/user/client/ui/TreeItemTest.java    Fri  
Nov 20 16:10:50 2009
@@ -15,6 +15,8 @@
   */
  package com.google.gwt.user.client.ui;

+import com.google.gwt.junit.DoNotRunWith;
+import com.google.gwt.junit.Platform;
  import com.google.gwt.junit.client.GWTTestCase;

  /**
@@ -39,6 +41,7 @@
      assertEquals("Test", widget.getText());
    }

+  @DoNotRunWith({Platform.HtmlUnit})
    public void testSetWidgetNullWithError() {
      // Create a widget that will throw an exception onUnload.
      BadWidget badWidget = new BadWidget();
=======================================
--- /trunk/user/test/com/google/gwt/user/client/ui/TreeTest.java        Mon Oct 
26  
16:46:02 2009
+++ /trunk/user/test/com/google/gwt/user/client/ui/TreeTest.java        Fri Nov 
20  
16:10:50 2009
@@ -15,6 +15,8 @@
   */
  package com.google.gwt.user.client.ui;

+import com.google.gwt.junit.DoNotRunWith;
+import com.google.gwt.junit.Platform;
  import com.google.gwt.junit.client.GWTTestCase;
  import com.google.gwt.user.client.DOM;
  import com.google.gwt.user.client.Element;
@@ -37,6 +39,7 @@
      return "com.google.gwt.user.DebugTest";
    }

+  @DoNotRunWith({Platform.HtmlUnit})
    public void testAttachDetachOrder() {
      HasWidgetsTester.testAll(new Tree(), new Adder(), true);
    }

-- 
http://groups.google.com/group/Google-Web-Toolkit-Contributors

Reply via email to