Fixes Issue #1093.
Fixes an off-by-scroll issue in DOMImplMozillaOld.getAbsoluteTop/Left and
DOMImplSafari.getAbsoluteTop/Left. The implementation for Safari and older
Mozilla both took into account an element's scrollTop/Left in computing its
absolute position, which is incorrect as the scroll values are only relevant
to the element's children.

Review by: jgw



git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@1195 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/user/client/impl/DOMImplMozillaOld.java b/user/src/com/google/gwt/user/client/impl/DOMImplMozillaOld.java
index 9547e07..c710084 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImplMozillaOld.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImplMozillaOld.java
@@ -31,8 +31,8 @@
     var left = $doc.getBoxObjectFor(elem).x - Math.round(
         style.getPropertyCSSValue('border-left-width').getFloatValue(
         CSSPrimitiveValue.CSS_PX));
-    var parent = elem;
-
+        
+    var parent = elem.parentNode;
     while (parent) {
       // Sometimes get NAN.
       if (parent.scrollLeft > 0) {
@@ -51,7 +51,7 @@
         style.getPropertyCSSValue('border-top-width').getFloatValue(
         CSSPrimitiveValue.CSS_PX));
       
-    var parent = elem;
+    var parent = elem.parentNode;
     while (parent) {
       // Sometimes get NAN.
       if (parent.scrollTop > 0) {
diff --git a/user/src/com/google/gwt/user/client/impl/DOMImplSafari.java b/user/src/com/google/gwt/user/client/impl/DOMImplSafari.java
index 9639353..b196f20 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImplSafari.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImplSafari.java
@@ -44,12 +44,15 @@
     }
 
     var left = 0;
-    var curr = elem;
-    // This intentionally excludes body which has a null offsetParent.
-    while (curr.offsetParent) {
-      left -= curr.scrollLeft;
-      curr = curr.parentNode;
+    var curr = elem.parentNode;
+    if (curr) {
+      // This intentionally excludes body which has a null offsetParent.
+      while (curr.offsetParent) {
+        left -= curr.scrollLeft;
+        curr = curr.parentNode;
+      }
     }
+    
     while (elem) {
       left += elem.offsetLeft;
 
@@ -74,12 +77,15 @@
     }
 
     var top = 0;
-    var curr = elem;
-    // This intentionally excludes body which has a null offsetParent.
-    while (curr.offsetParent) {
-      top -= curr.scrollTop;
-      curr = curr.parentNode;
+    var curr = elem.parentNode;
+    if (curr) {
+      // This intentionally excludes body which has a null offsetParent.
+      while (curr.offsetParent) {
+        top -= curr.scrollTop;
+        curr = curr.parentNode;
+      }
     }
+    
     while (elem) {
       top += elem.offsetTop;
 
diff --git a/user/test/com/google/gwt/user/client/ui/DOMTest.java b/user/test/com/google/gwt/user/client/ui/DOMTest.java
index ca724f8..887d788 100644
--- a/user/test/com/google/gwt/user/client/ui/DOMTest.java
+++ b/user/test/com/google/gwt/user/client/ui/DOMTest.java
@@ -90,6 +90,39 @@
   }
 
   /**
+   * Tests {@link DOM#getAbsoluteTop(Element)} and
+   * {@link DOM#getAbsoluteLeft(Element)} for consistency when the element
+   * contains children and has scrollbars. See issue #1093 for more details.
+   * 
+   */
+  public void testGetAbsolutePositionWhenScrolled() {
+    final Element outer = DOM.createDiv();
+    final Element inner = DOM.createDiv();
+
+    DOM.setStyleAttribute(outer, "position", "absolute");
+    DOM.setStyleAttribute(outer, "top", "0px");
+    DOM.setStyleAttribute(outer, "left", "0px");
+    DOM.setStyleAttribute(outer, "overflow", "auto");
+    DOM.setStyleAttribute(outer, "width", "200px");
+    DOM.setStyleAttribute(outer, "height", "200px");
+   
+    DOM.setStyleAttribute(inner, "marginTop", "800px");
+    DOM.setStyleAttribute(inner, "marginLeft", "800px");
+
+    DOM.appendChild(outer, inner);
+    DOM.appendChild(RootPanel.getBodyElement(), outer);
+    DOM.setInnerText(inner, ":-)");
+    DOM.scrollIntoView(inner);
+
+    // Ensure that we are scrolled.
+    assertTrue(DOM.getElementPropertyInt(outer, "scrollTop") > 0);
+    assertTrue(DOM.getElementPropertyInt(outer, "scrollLeft") > 0);
+
+    assertEquals(0, DOM.getAbsoluteTop(outer));
+    assertEquals(0, DOM.getAbsoluteLeft(outer));
+  }
+
+  /**
    * Tests the ability to do a parent-ward walk in the DOM.
    */
   public void testGetParent() {
@@ -106,7 +139,7 @@
     // If we get here, we pass, because we encountered no errors going to the
     // top of the parent hierarchy.
   }
-  
+
   /**
    * Tests {@link DOM#insertChild(Element, Element, int)}.
    *
@@ -115,7 +148,8 @@
     Element parent = RootPanel.get().getElement();
     Element div = DOM.createDiv();
     DOM.insertChild(parent, div, Integer.MAX_VALUE);
-    Element child = DOM.getChild(RootPanel.get().getElement(), DOM.getChildCount(parent) - 1);
+    Element child = DOM.getChild(RootPanel.get().getElement(),
+        DOM.getChildCount(parent) - 1);
     assertEquals(div, child);
   }