Bug 134771

Summary: instanceof ecma operator does not work on DOM objects
Product: [Applications] konqueror Reporter: Germain Garand <germain>
Component: khtmlAssignee: Konqueror Developers <konq-bugs>
Status: RESOLVED FIXED    
Severity: normal CC: maksim
Priority: NOR    
Version: unspecified   
Target Milestone: ---   
Platform: Compiled Sources   
OS: Linux   
Latest Commit: Version Fixed In:
Attachments: patch for review

Description Germain Garand 2006-09-28 02:51:51 UTC
Version:            (using KDE Devel)
Installed from:    Compiled sources

In Mozilla and Opera browsers, instanceof works on DOM objects, so eg.

  (document.getElementsByTagName("body")[0] instanceof HTMLElement)
or
  (document instanceof HTMLDocument)

would evaluate to true.

As long as we did not expose (pseudo-)constructor functions it was not a big deal that we didn't follow this, because script would test e.g. window.HTMLDocument before using instanceof.

Now that we expose the constructor, it seems we must also honour instanceof queries, or we are going to have regressions...

An example of this is:
  http://hop.inria.fr => "Demos" tab

a sophisticated ajax demo that used to work but now fails because of the above.
Comment 1 Germain Garand 2006-09-28 03:01:46 UTC
Created attachment 17948 [details]
patch for review

I just lift implementations of hasInstance/implementsHasInstance
from KJS's InternalFunctionImp, as it seems a perfect fit...
Comment 2 Maksim Orlovich 2006-09-28 03:15:58 UTC
I suppose that's the best way of doing it, thanks for catching it...
Comment 3 Germain Garand 2006-09-28 03:30:42 UTC
> I suppose that's the best way of doing it, thanks for catching it...

glad to hear that as it was just voodoo programming :)

mmh now there is something I don't get at all,
  document instanceof HTMLDocument
is now true, whereas
  document instanceof Document
isn't...

At first sight, it doesn't seem to be a flaw in the implementsHasInstance logic as eg.
  document.getElementsByTagName("body")[0] instanceof Element

is OK, and it seems to properly walk the inheritance chain?

I feebly tried to follow the macros implementing the pseudo constructors, but all I got is a severe headache... 



Comment 4 Maksim Orlovich 2006-09-28 03:48:22 UTC
Ugh, the problem is that when we create a prototype with a parent, it doesn't actually setup a prototype link but delegates manually :-(

The element case works because we only have a single prototype for the entire hierarchy.
Comment 5 Maksim Orlovich 2006-09-28 04:01:59 UTC
.. So basically, to fix this, we would need yet another prototype macro. What ugliness :-(. Might try tomorrow evening... 
Comment 6 Germain Garand 2006-10-01 15:41:53 UTC
SVN commit 591021 by ggarand:

commiting partial fix for #134771 to get a working instanceof on most DOM objects

the rest of it is completely above my head and in the benevolent hands of Mighty Maksim...

CCBUG: 134771


 M  +22 -0     kjs_binding.cpp  
 M  +2 -1      kjs_binding.h  


--- branches/KDE/3.5/kdelibs/khtml/ecma/kjs_binding.cpp #591020:591021
@@ -92,6 +92,28 @@
   return "[object " + className() + "]";
 }
 
+Boolean DOMObject::hasInstance(ExecState *exec, const Value &value)
+{
+  if (value.type() != ObjectType)
+    return Boolean(false);
+
+  Value prot = get(exec,prototypePropertyName);
+  if (prot.type() != ObjectType && prot.type() != NullType) {
+    Object err = Error::create(exec, TypeError, "Invalid prototype encountered "
+                               "in instanceof operation.");
+    exec->setException(err);
+    return Boolean(false);
+  }
+
+  Object v = Object(static_cast<ObjectImp*>(value.imp()));
+  while ((v = Object::dynamicCast(v.prototype())).imp()) {
+    if (v.imp() == prot.imp())
+      return Boolean(true);
+  }
+  return Boolean(false);
+}
+
+
 Value DOMFunction::get(ExecState *exec, const Identifier &propertyName) const
 {
   try {
--- branches/KDE/3.5/kdelibs/khtml/ecma/kjs_binding.h #591020:591021
@@ -53,7 +53,8 @@
     virtual Value get(ExecState *exec, const Identifier &propertyName) const;
     virtual Value tryGet(ExecState *exec, const Identifier &propertyName) const
       { return ObjectImp::get(exec, propertyName); }
-
+    virtual bool implementsHasInstance() const { return true; }
+    virtual Boolean hasInstance(ExecState *exec, const Value &value);
     virtual void put(ExecState *exec, const Identifier &propertyName,
                      const Value &value, int attr = None);
     virtual void tryPut(ExecState *exec, const Identifier &propertyName,
Comment 7 Maksim Orlovich 2006-10-14 19:58:25 UTC
SVN commit 595530 by orlovich:

Backport newer prototype macros, that delegate using the prototype system and not directly.
FIxes #134771, and make this closer to trunk
BUG:134771


 M  +4 -4      domparser.cpp  
 M  +82 -17    kjs_binding.h  
 M  +27 -23    kjs_css.cpp  
 M  +26 -25    kjs_dom.cpp  
 M  +9 -5      kjs_dom.h  
 M  +23 -19    kjs_events.cpp  
 M  +11 -9     kjs_html.cpp  
 M  +9 -6      kjs_range.cpp  
 M  +14 -12    kjs_traversal.cpp  
 M  +2 -1      kjs_window.cpp  
 M  +5 -4      xmlhttprequest.cpp  
 M  +4 -4      xmlserializer.cpp  
Comment 8 Maksim Orlovich 2006-10-14 20:00:26 UTC
SVN commit 595531 by orlovich:

Regression test for #134771, and also shows some of the limitations of our implementation..
CCBUG:134771


 A             baseline/dom/instanceof_pseudoctor.html-dom  
 AM            baseline/dom/instanceof_pseudoctor.html-dump.png  
 A             baseline/dom/instanceof_pseudoctor.html-render  
 A             tests/dom/instanceof_pseudoctor.html  


** trunk/tests/khtmltests/regression/baseline/dom/instanceof_pseudoctor.html-dump.png #property svn:mime-type
   + image/png