Fixes Issue #1218
Improves the speed for DOM.isOrHasChild by adding more browser
specialization. The techniques used are:
IE6/7 - Node.contains with special case for equality.
Safari - Tree walk (Node.contains broken on Safari2).
Mozilla - Node.compareDocumentPosition
Opera - Node.contains

Patch by: mmastrac, knorton
Review by: jgw, ecc



git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@1829 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/user/client/impl/DOMImplIE6.java b/user/src/com/google/gwt/user/client/impl/DOMImplIE6.java
index 7902753..5dd4ba9 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImplIE6.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImplIE6.java
@@ -244,12 +244,9 @@
 
   @Override
   public native boolean isOrHasChild(Element parent, Element child) /*-{
-    while (child) {
-      if (parent.uniqueID == child.uniqueID)
-        return true;
-      child = child.parentElement;
-    }
-    return false;
+    // An extra equality check is required due to the fact that
+    // elem.contains(elem) is false if elem is not attached to the DOM.
+    return (parent.uniqueID == child.uniqueID) || parent.contains(child);  
   }-*/;
 
   @Override
diff --git a/user/src/com/google/gwt/user/client/impl/DOMImplMozilla.java b/user/src/com/google/gwt/user/client/impl/DOMImplMozilla.java
index 055b0f7..72b18c6 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImplMozilla.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImplMozilla.java
@@ -80,25 +80,9 @@
 
   @Override
   public native boolean isOrHasChild(Element parent, Element child) /*-{
-    while (child) {
-      if (parent.isSameNode(child)) {
-        return true;
-      }
-
-      try {
-        child = child.parentNode;
-      } catch(e) {
-        // Give up on 'Permission denied to get property
-        // HTMLDivElement.parentNode'
-        // See https://bugzilla.mozilla.org/show_bug.cgi?id=208427
-        return false;
-      }
-
-      if (child && (child.nodeType != 1)) {
-        child = null;
-      }
-    }
-    return false;
+    // For more information about compareDocumentPosition, see:
+    // http://www.quirksmode.org/blog/archives/2006/01/contains_for_mo.html
+    return parent.isSameNode(child) || !!(parent.compareDocumentPosition(child) & 16);  
   }-*/;
 
   @Override
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 5bad5b4..155e084 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImplSafari.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImplSafari.java
@@ -120,4 +120,18 @@
       select.insertBefore(newOption, select.children[index]);
     }
   }-*/;
+  
+  @Override
+  public native boolean isOrHasChild(Element parent, Element child) /*-{
+    while (child) {
+      if (parent == child) {
+        return true;
+      }
+      child = child.parentNode;
+      if (child && (child.nodeType != 1)) {
+        child = null;
+      }
+    }
+    return false;
+  }-*/; 
 }
diff --git a/user/src/com/google/gwt/user/client/impl/DOMImplStandard.java b/user/src/com/google/gwt/user/client/impl/DOMImplStandard.java
index 14367e7..64f0a73 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImplStandard.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImplStandard.java
@@ -169,16 +169,7 @@
 
   @Override
   public native boolean isOrHasChild(Element parent, Element child) /*-{
-    while (child) {
-      if (parent == child) {
-        return true;
-      }
-      child = child.parentNode;
-      if (child && (child.nodeType != 1)) {
-        child = null;
-      }
-    }
-    return false;
+    return parent.contains(child);  
   }-*/;
 
   @Override
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 b2904cc..195d813 100644
--- a/user/test/com/google/gwt/user/client/ui/DOMTest.java
+++ b/user/test/com/google/gwt/user/client/ui/DOMTest.java
@@ -167,10 +167,18 @@
   public void testIsOrHasChild() {
     Element div = DOM.createDiv();
     Element childDiv = DOM.createDiv();
+    
     assertFalse(DOM.isOrHasChild(div, childDiv));
+    assertTrue(DOM.isOrHasChild(div, div));
+    
     DOM.appendChild(div, childDiv);
     assertTrue(DOM.isOrHasChild(div, childDiv));
     assertFalse(DOM.isOrHasChild(childDiv, div));
+    
+    DOM.appendChild(RootPanel.getBodyElement(), div);
+    assertTrue(DOM.isOrHasChild(div, childDiv));
+    assertTrue(DOM.isOrHasChild(div, div));
+    assertFalse(DOM.isOrHasChild(childDiv, div));    
   }
 
   /**