Fixes DOMImplSafari.getAbsoluteLeft/Top() to account for position:fixed (issue 3859).
Review: http://gwt-code-reviews.appspot.com/51809


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@5761 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/dom/client/DOMImplSafari.java b/user/src/com/google/gwt/dom/client/DOMImplSafari.java
index cd5b387..9d29a57 100644
--- a/user/src/com/google/gwt/dom/client/DOMImplSafari.java
+++ b/user/src/com/google/gwt/dom/client/DOMImplSafari.java
@@ -83,10 +83,15 @@
         curr = curr.parentNode;
       }
     }
-    
+
     while (elem) {
       left += elem.offsetLeft;
 
+      if (doc.defaultView.getComputedStyle(elem, '')['position'] == 'fixed') {
+        left += doc.body.scrollLeft;
+        return left;
+      }
+
       // Safari 3 does not include borders with offsetLeft, so we need to add
       // the borders of the parent manually.
       var parent = elem.offsetParent;
@@ -105,7 +110,7 @@
     }
     return left;
   }-*/;
-  
+
   @Override
   public native int getAbsoluteTop(Element elem) /*-{
     // Unattached elements and elements (or their ancestors) with style
@@ -124,10 +129,15 @@
         curr = curr.parentNode;
       }
     }
-    
+
     while (elem) {
       top += elem.offsetTop;
 
+      if (doc.defaultView.getComputedStyle(elem, '')['position'] == 'fixed') {
+        top += doc.body.scrollTop;
+        return top;
+      }
+
       // Safari 3 does not include borders with offsetTop, so we need to add the
       // borders of the parent manually.
       var parent = elem.offsetParent;
diff --git a/user/test/com/google/gwt/dom/client/ElementTest.java b/user/test/com/google/gwt/dom/client/ElementTest.java
index 4a2ff44..5c8ab14 100644
--- a/user/test/com/google/gwt/dom/client/ElementTest.java
+++ b/user/test/com/google/gwt/dom/client/ElementTest.java
@@ -198,7 +198,7 @@
         assertEquals(absLeft, elem.getAbsoluteLeft());
         assertEquals(absTop, elem.getAbsoluteTop());
 
-        if (isIE() && !doc.isCSS1Compat()) {
+        if (isIE6or7() && !doc.isCSS1Compat()) {
           // In IE/quirk, the interior decorations are considered part of the
           // width/height, so there's no need to account for them here.
           assertEquals(absLeft + width, elem.getAbsoluteRight());
@@ -228,6 +228,11 @@
     div.getStyle().setLeft(1000, Unit.PX);
     div.getStyle().setTop(1000, Unit.PX);
 
+    DivElement fixedDiv = doc.createDivElement();
+    body.appendChild(fixedDiv);
+    fixedDiv.setInnerText("foo");
+    fixedDiv.getStyle().setPosition(Position.FIXED);
+
     // Get the absolute position of the element when the body is unscrolled.
     int absLeft = div.getAbsoluteLeft();
     int absTop = div.getAbsoluteTop();
@@ -245,6 +250,15 @@
     // getAbsoluteLeft/Top() yet again for FF2.
     assertTrue(Math.abs(absLeft - div.getAbsoluteLeft()) <= 1);
     assertTrue(Math.abs(absTop - div.getAbsoluteTop()) <= 1);
+
+    // Ensure that the 'position:fixed' div's absolute position includes the
+    // body's scroll position.
+    //
+    // Don't do this on IE6/7 or old Gecko, which don't support position:fixed.
+    if (!isIE6or7() && !isOldGecko()) {
+      assertTrue(fixedDiv.getAbsoluteLeft() >= body.getScrollLeft());
+      assertTrue(fixedDiv.getAbsoluteTop() >= body.getScrollTop());
+    }
   }
 
   /**
@@ -581,8 +595,34 @@
     return {};
   }-*/;
 
-  private native boolean isIE() /*-{
+  // Stolen from UserAgent.gwt.xml.
+  private native boolean isIE6or7() /*-{
     var ua = navigator.userAgent.toLowerCase();
-    return ua.indexOf("msie") != -1;
+    if (ua.indexOf("msie") != -1) {
+      if (document.documentMode >= 8) {
+        return false;
+      }
+      return true;
+    }
+    return false;
+  }-*/;
+
+  // Stolen from UserAgent.gwt.xml.
+  private native boolean isOldGecko() /*-{
+    var makeVersion = function(result) {
+      return (parseInt(result[1]) * 1000) + parseInt(result[2]);
+    };
+
+    var ua = navigator.userAgent.toLowerCase();
+    if (ua.indexOf("gecko") != -1) {
+      var result = /rv:([0-9]+)\.([0-9]+)/.exec(ua);
+      if (result && result.length == 3) {
+        if (makeVersion(result) >= 1008) {
+          return false;
+        }
+      }
+      return true;
+    }
+    return false;
   }-*/;
 }