http://gwt-code-reviews.appspot.com/148802
This patch uses getBoundingClientRect on modern WebKit browsers for
getAbsoluteTop and getAbsoluteLeft. Sadly, we still support Safari3 so I had to
do this via runtime check (so we can use the old crazy impl for Safari3).
However, this is still well worth the change for Safari4 and Chrome.
Review by : jgw


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@7594 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 24ec4e3..bdd8ed4 100644
--- a/user/src/com/google/gwt/dom/client/DOMImplSafari.java
+++ b/user/src/com/google/gwt/dom/client/DOMImplSafari.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Google Inc.
+ * Copyright 2010 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
@@ -15,61 +15,28 @@
  */
 package com.google.gwt.dom.client;
 
+import com.google.gwt.core.client.JavaScriptObject;
+
 /**
  * Safari implementation of {@link com.google.gwt.user.client.impl.DOMImpl}.
  */
 class DOMImplSafari extends DOMImplStandard {
 
-  /**
-   * The type property on a button element is read-only in safari, so we need to 
-   * set it using setAttribute.
-   */
-  @Override
-  public native ButtonElement createButtonElement(Document doc, String type) /*-{
-    var e = doc.createElement("BUTTON");
-    e.setAttribute('type', type);
-    return e;
-  }-*/;
-
-  @Override
-  public native NativeEvent createKeyEvent(Document doc, String type, boolean canBubble,
-      boolean cancelable, boolean ctrlKey, boolean altKey, boolean shiftKey,
-      boolean metaKey, int keyCode, int charCode) /*-{
-    // The spec calls for KeyEvents/initKeyEvent(), but that doesn't exist on WebKit.
-    var evt = doc.createEvent('HTMLEvents');
-    evt.initEvent(type, canBubble, cancelable);
-    evt.ctrlKey = ctrlKey;
-    evt.altKey = altKey;
-    evt.shiftKey = shiftKey;
-    evt.metaKey = metaKey;
-    evt.keyCode = keyCode;
-    evt.charCode = charCode;
-
-    return evt;
-  }-*/;
-
-  /**
-   * Safari 2 does not support {@link ScriptElement#setText(String)}.
-   */
-  @Override
-  public ScriptElement createScriptElement(Document doc, String source) {
-    ScriptElement elem = (ScriptElement) createElement(doc, "script");
-    elem.setInnerText(source);
-    return elem;
+  private static class ClientRect extends JavaScriptObject {
+    @SuppressWarnings("unused")
+    protected ClientRect() {
+    }
+    
+    public final native int getLeft() /*-{
+      return this.left;
+    }-*/;
+    
+    public final native int getTop() /*-{
+      return this.top;
+    }-*/;
   }
 
-  @Override
-  public native EventTarget eventGetCurrentTarget(NativeEvent event) /*-{
-    return event.currentTarget || $wnd;
-  }-*/;
-
-  @Override
-  public native int eventGetMouseWheelVelocityY(NativeEvent evt) /*-{
-    return Math.round(-evt.wheelDelta / 40) || 0;
-  }-*/;
-
-  @Override
-  public native int getAbsoluteLeft(Element elem) /*-{
+  private static native int getAbsoluteLeftUsingOffsets(Element elem) /*-{
     // Unattached elements and elements (or their ancestors) with style
     // 'display: none' have no offsetLeft.
     if (elem.offsetLeft == null) {
@@ -122,8 +89,7 @@
     return left;
   }-*/;
 
-  @Override
-  public native int getAbsoluteTop(Element elem) /*-{
+  private static native int getAbsoluteTopUsingOffsets(Element elem) /*-{
     // Unattached elements and elements (or their ancestors) with style
     // 'display: none' have no offsetTop.
     if (elem.offsetTop == null) {
@@ -168,6 +134,74 @@
     return top;
   }-*/;
 
+  private static native ClientRect getBoundingClientRect(Element element) /*-{
+    return element.getBoundingClientRect && element.getBoundingClientRect();
+  }-*/;
+
+  /**
+   * The type property on a button element is read-only in safari, so we need to 
+   * set it using setAttribute.
+   */
+  @Override
+  public native ButtonElement createButtonElement(Document doc, String type) /*-{
+    var e = doc.createElement("BUTTON");
+    e.setAttribute('type', type);
+    return e;
+  }-*/;
+
+  @Override
+  public native NativeEvent createKeyEvent(Document doc, String type, boolean canBubble,
+      boolean cancelable, boolean ctrlKey, boolean altKey, boolean shiftKey,
+      boolean metaKey, int keyCode, int charCode) /*-{
+    // The spec calls for KeyEvents/initKeyEvent(), but that doesn't exist on WebKit.
+    var evt = doc.createEvent('HTMLEvents');
+    evt.initEvent(type, canBubble, cancelable);
+    evt.ctrlKey = ctrlKey;
+    evt.altKey = altKey;
+    evt.shiftKey = shiftKey;
+    evt.metaKey = metaKey;
+    evt.keyCode = keyCode;
+    evt.charCode = charCode;
+
+    return evt;
+  }-*/;
+
+  /**
+   * Safari 2 does not support {@link ScriptElement#setText(String)}.
+   */
+  @Override
+  public ScriptElement createScriptElement(Document doc, String source) {
+    ScriptElement elem = (ScriptElement) createElement(doc, "script");
+    elem.setInnerText(source);
+    return elem;
+  }
+
+  @Override
+  public native EventTarget eventGetCurrentTarget(NativeEvent event) /*-{
+    return event.currentTarget || $wnd;
+  }-*/;
+
+  @Override
+  public native int eventGetMouseWheelVelocityY(NativeEvent evt) /*-{
+    return Math.round(-evt.wheelDelta / 40) || 0;
+  }-*/;
+
+  @Override
+  public int getAbsoluteLeft(Element elem) {
+    ClientRect rect = getBoundingClientRect(elem);
+    return rect != null
+        ? rect.getLeft() + elem.getOwnerDocument().getBody().getScrollLeft()
+        : getAbsoluteLeftUsingOffsets(elem);
+  }
+
+  @Override
+  public int getAbsoluteTop(Element elem) {
+    ClientRect rect = getBoundingClientRect(elem);
+    return rect != null
+        ? rect.getTop() + elem.getOwnerDocument().getBody().getScrollTop()
+        : getAbsoluteTopUsingOffsets(elem);
+  }
+
   /*
    * textContent is used over innerText for two reasons:
    * 1 - It is consistent with DOMImplMozilla. textContent
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 1d73b75..16ce8cd 100644
--- a/user/test/com/google/gwt/user/client/ui/DOMTest.java
+++ b/user/test/com/google/gwt/user/client/ui/DOMTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Google Inc.
+ * Copyright 2010 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
@@ -181,8 +181,8 @@
     assertTrue(DOM.getElementPropertyInt(outer, "scrollLeft") > 0);
 
     Document doc = Document.get();
-    assertEquals(doc.getBodyOffsetLeft(), DOM.getAbsoluteTop(outer));
-    assertEquals(doc.getBodyOffsetTop(), DOM.getAbsoluteLeft(outer));
+    assertEquals(doc.getBodyOffsetLeft(), DOM.getAbsoluteLeft(outer));
+    assertEquals(doc.getBodyOffsetTop(), DOM.getAbsoluteTop(outer));
   }
 
   /**