File indexing completed on 2024-04-28 15:23:11

0001 /*
0002  *  This file is part of the KDE libraries
0003  *  Copyright (C) 2000 Harri Porten (porten@kde.org)
0004  *  Copyright (C) 2003 Apple Computer, Inc.
0005  *  Copyright (C) 2010 Maksim Orlovich (maksim@kde.org)
0006  *
0007  *  This library is free software; you can redistribute it and/or
0008  *  modify it under the terms of the GNU Library General Public
0009  *  License as published by the Free Software Foundation; either
0010  *  version 2 of the License, or (at your option) any later version.
0011  *
0012  *  This library is distributed in the hope that it will be useful,
0013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015  *  Library General Public License for more details.
0016  *
0017  *  You should have received a copy of the GNU Library General Public
0018  *  License along with this library; if not, write to the Free Software
0019  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
0020  */
0021 
0022 #include "kjs_dom.h"
0023 #include "kjs_dom.lut.h"
0024 
0025 #include <khtmlview.h>
0026 #include <xml/dom2_eventsimpl.h>
0027 #include <rendering/render_canvas.h>
0028 #include <rendering/render_layer.h>
0029 #include <xml/dom_nodeimpl.h>
0030 #include <xml/dom_docimpl.h>
0031 #include <xml/dom3_xpathimpl.h>
0032 #include <html/html_baseimpl.h>
0033 #include <html/html_documentimpl.h>
0034 #include <html/html_miscimpl.h>
0035 #include "HTMLAudioElement.h"
0036 #include "HTMLVideoElement.h"
0037 #include "JSHTMLAudioElement.h"
0038 #include "JSHTMLVideoElement.h"
0039 #include "khtml_debug.h"
0040 #include <khtml_part.h>
0041 #include <QList>
0042 
0043 #include "kjs_html.h"
0044 #include "kjs_css.h"
0045 #include "kjs_range.h"
0046 #include "kjs_traversal.h"
0047 #include "kjs_events.h"
0048 #include "kjs_views.h"
0049 #include "kjs_window.h"
0050 #include "kjs_xpath.h"
0051 #include "kjs_clientrect.h"
0052 #include "xmlhttprequest.h"
0053 #include <kjs/PropertyNameArray.h>
0054 #include <dom/dom_exception.h>
0055 #include <dom/html_document.h>
0056 #include <khtmlpart_p.h>
0057 
0058 // for win32, MinGW
0059 #undef FOCUS_EVENT
0060 #undef CreateEvent
0061 
0062 using namespace KJS;
0063 using namespace khtml;
0064 using namespace DOM;
0065 
0066 // -------------------------------------------------------------------------
0067 /* Source for DOMNodeConstantsTable.
0068 @begin DOMNodeConstantsTable 21
0069   ELEMENT_NODE      DOM::Node::ELEMENT_NODE     DontDelete|ReadOnly
0070   ATTRIBUTE_NODE    DOM::Node::ATTRIBUTE_NODE       DontDelete|ReadOnly
0071   TEXT_NODE     DOM::Node::TEXT_NODE        DontDelete|ReadOnly
0072   CDATA_SECTION_NODE    DOM::Node::CDATA_SECTION_NODE   DontDelete|ReadOnly
0073   ENTITY_REFERENCE_NODE DOM::Node::ENTITY_REFERENCE_NODE    DontDelete|ReadOnly
0074   ENTITY_NODE       DOM::Node::ENTITY_NODE      DontDelete|ReadOnly
0075   PROCESSING_INSTRUCTION_NODE DOM::Node::PROCESSING_INSTRUCTION_NODE DontDelete|ReadOnly
0076   COMMENT_NODE      DOM::Node::COMMENT_NODE     DontDelete|ReadOnly
0077   DOCUMENT_NODE     DOM::Node::DOCUMENT_NODE        DontDelete|ReadOnly
0078   DOCUMENT_TYPE_NODE    DOM::Node::DOCUMENT_TYPE_NODE   DontDelete|ReadOnly
0079   DOCUMENT_FRAGMENT_NODE DOM::Node::DOCUMENT_FRAGMENT_NODE  DontDelete|ReadOnly
0080   NOTATION_NODE     DOM::Node::NOTATION_NODE        DontDelete|ReadOnly
0081   XPATH_NAMESPACE_NODE  DOM::Node::XPATH_NAMESPACE_NODE         DontDelete|ReadOnly
0082   DOCUMENT_POSITION_DISCONNECTED                DOM::Node::DOCUMENT_POSITION_DISCONNECTED  DontDelete|ReadOnly
0083   DOCUMENT_POSITION_PRECEDING                   DOM::Node::DOCUMENT_POSITION_PRECEDING  DontDelete|ReadOnly
0084   DOCUMENT_POSITION_FOLLOWING                   DOM::Node::DOCUMENT_POSITION_FOLLOWING   DontDelete|ReadOnly
0085   DOCUMENT_POSITION_CONTAINS                    DOM::Node::DOCUMENT_POSITION_CONTAINS  DontDelete|ReadOnly
0086   DOCUMENT_POSITION_CONTAINED_BY                DOM::Node::DOCUMENT_POSITION_CONTAINED_BY  DontDelete|ReadOnly
0087   DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC     DOM::Node::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC  DontDelete|ReadOnly
0088 @end
0089 */
0090 IMPLEMENT_CONSTANT_TABLE(DOMNodeConstants, "DOMNodeConstants")
0091 
0092 // -------------------------------------------------------------------------
0093 /* Source for DOMNodeProtoTable.
0094 @begin DOMNodeProtoTable 13
0095   insertBefore  DOMNode::InsertBefore   DontDelete|Function 2
0096   replaceChild  DOMNode::ReplaceChild   DontDelete|Function 2
0097   removeChild   DOMNode::RemoveChild    DontDelete|Function 1
0098   appendChild   DOMNode::AppendChild    DontDelete|Function 1
0099   hasAttributes DOMNode::HasAttributes  DontDelete|Function 0
0100   hasChildNodes DOMNode::HasChildNodes  DontDelete|Function 0
0101   cloneNode DOMNode::CloneNode  DontDelete|Function 1
0102 # DOM2
0103   normalize DOMNode::Normalize  DontDelete|Function 0
0104   isSupported   DOMNode::IsSupported    DontDelete|Function 2
0105 # DOM3
0106   compareDocumentPosition   DOMNode::CompareDocumentPosition    DontDelete|Function 1
0107 # from the EventTarget interface
0108   addEventListener  DOMNode::AddEventListener   DontDelete|Function 3
0109   removeEventListener   DOMNode::RemoveEventListener    DontDelete|Function 3
0110   dispatchEvent     DOMNode::DispatchEvent  DontDelete|Function 1
0111 # IE extensions
0112   contains  DOMNode::Contains       DontDelete|Function 1
0113   insertAdjacentHTML    DOMNode::InsertAdjacentHTML DontDelete|Function 2
0114 @end
0115 */
0116 KJS_IMPLEMENT_PROTOFUNC(DOMNodeProtoFunc)
0117 KJS_IMPLEMENT_PROTOTYPE_IMP("DOMNode", DOMNodeProto, DOMNodeProtoFunc, DOMNodeConstants)
0118 {
0119     // We need to setup the constructor property to the ctor here, but NodeConstructor::self
0120     // will try to make us again, since we're in the middle of cacheGlobalObject.
0121     // To workaround that, register ourselves so the re-entry of cacheGlobalObject
0122     // will pick us. NodeCtor ctor does the same already, to fix the problem
0123     // in the other direction.
0124     exec->lexicalInterpreter()->globalObject()->put(exec, *name(), this, KJS::Internal | KJS::DontEnum);
0125     putDirect(exec->propertyNames().constructor, NodeConstructor::self(exec), DontEnum);
0126 }
0127 
0128 const ClassInfo DOMNode::info = { "Node", nullptr, &DOMNodeTable, nullptr };
0129 
0130 DOMNode::DOMNode(ExecState *exec, DOM::NodeImpl *n)
0131     : DOMObject(DOMNodeProto::self(exec)), m_impl(n)
0132 {}
0133 
0134 DOMNode::DOMNode(JSObject *proto, DOM::NodeImpl *n)
0135     : DOMObject(proto), m_impl(n)
0136 {}
0137 
0138 DOMNode::~DOMNode()
0139 {
0140     ScriptInterpreter::forgetDOMObject(m_impl.get());
0141 }
0142 
0143 bool DOMNode::toBoolean(ExecState *) const
0144 {
0145     return !m_impl.isNull();
0146 }
0147 
0148 /* Source for DOMNodeTable.
0149 @begin DOMNodeTable 53
0150   nodeName  DOMNode::NodeName   DontDelete|ReadOnly
0151   nodeValue DOMNode::NodeValue  DontDelete
0152   nodeType  DOMNode::NodeType   DontDelete|ReadOnly
0153   parentNode    DOMNode::ParentNode DontDelete|ReadOnly
0154   parentElement DOMNode::ParentElement  DontDelete|ReadOnly
0155   childNodes    DOMNode::ChildNodes DontDelete|ReadOnly
0156   firstChild    DOMNode::FirstChild DontDelete|ReadOnly
0157   lastChild DOMNode::LastChild  DontDelete|ReadOnly
0158   previousSibling  DOMNode::PreviousSibling DontDelete|ReadOnly
0159   nextSibling   DOMNode::NextSibling    DontDelete|ReadOnly
0160   attributes    DOMNode::Attributes DontDelete|ReadOnly
0161   namespaceURI  DOMNode::NamespaceURI   DontDelete|ReadOnly
0162 # DOM2
0163   prefix    DOMNode::Prefix     DontDelete
0164   localName DOMNode::LocalName  DontDelete|ReadOnly
0165   ownerDocument DOMNode::OwnerDocument  DontDelete|ReadOnly
0166 # DOM3
0167   textContent   DOMNode::TextContent    DontDelete
0168 # Event handlers
0169 # IE also has: onactivate, onbefore*, oncontextmenu, oncontrolselect, oncut,
0170 # ondeactivate, ondrag*, ondrop, onfocusin, onfocusout, onhelp, onmousewheel,
0171 # onmove*, onpaste, onpropertychange, onreadystatechange, onresizeend/start,
0172 # onselectionchange, onstop
0173   onabort   DOMNode::OnAbort        DontDelete
0174   onblur    DOMNode::OnBlur         DontDelete
0175   onchange  DOMNode::OnChange       DontDelete
0176   onclick   DOMNode::OnClick        DontDelete
0177   ondblclick    DOMNode::OnDblClick     DontDelete
0178   ondragdrop    DOMNode::OnDragDrop     DontDelete
0179   onerror   DOMNode::OnError        DontDelete
0180   onfocus   DOMNode::OnFocus            DontDelete
0181   onkeydown DOMNode::OnKeyDown      DontDelete
0182   onkeypress    DOMNode::OnKeyPress     DontDelete
0183   onkeyup   DOMNode::OnKeyUp        DontDelete
0184   onload    DOMNode::OnLoad         DontDelete
0185   onmousedown   DOMNode::OnMouseDown        DontDelete
0186   onmousemove   DOMNode::OnMouseMove        DontDelete
0187   onmouseout    DOMNode::OnMouseOut     DontDelete
0188   onmouseover   DOMNode::OnMouseOver        DontDelete
0189   onmouseup DOMNode::OnMouseUp      DontDelete
0190   onmove    DOMNode::OnMove         DontDelete
0191   onreset   DOMNode::OnReset        DontDelete
0192   onresize  DOMNode::OnResize       DontDelete
0193   onscroll      DOMNode::OnScroll               DontDelete
0194   onselect  DOMNode::OnSelect       DontDelete
0195   onsubmit  DOMNode::OnSubmit       DontDelete
0196   onunload  DOMNode::OnUnload       DontDelete
0197 # IE extensions
0198   offsetLeft    DOMNode::OffsetLeft     DontDelete|ReadOnly
0199   offsetTop DOMNode::OffsetTop      DontDelete|ReadOnly
0200   offsetWidth   DOMNode::OffsetWidth        DontDelete|ReadOnly
0201   offsetHeight  DOMNode::OffsetHeight       DontDelete|ReadOnly
0202   offsetParent  DOMNode::OffsetParent       DontDelete|ReadOnly
0203   clientWidth   DOMNode::ClientWidth        DontDelete|ReadOnly
0204   clientHeight  DOMNode::ClientHeight       DontDelete|ReadOnly
0205   clientLeft    DOMNode::ClientLeft     DontDelete|ReadOnly
0206   clientTop DOMNode::ClientTop      DontDelete|ReadOnly
0207   scrollLeft    DOMNode::ScrollLeft     DontDelete
0208   scrollTop DOMNode::ScrollTop      DontDelete
0209   scrollWidth   DOMNode::ScrollWidth            DontDelete|ReadOnly
0210   scrollHeight  DOMNode::ScrollHeight           DontDelete|ReadOnly
0211   sourceIndex   DOMNode::SourceIndex        DontDelete|ReadOnly
0212 @end
0213 */
0214 
0215 bool DOMNode::getOwnPropertySlot(ExecState *exec, const Identifier &propertyName, PropertySlot &slot)
0216 {
0217 #ifdef KJS_VERBOSE
0218     qCDebug(KHTML_LOG) << "DOMNode::getOwnPropertySlot " << propertyName.qstring();
0219 #endif
0220     return getStaticValueSlot<DOMNode, DOMObject>(exec, &DOMNodeTable, this, propertyName, slot);
0221 }
0222 
0223 static khtml::RenderObject *handleBodyRootQuirk(const DOM::NodeImpl *node, khtml::RenderObject *rend, int token)
0224 {
0225     //This emulates the quirks of various height/width properties on the viewport and root. Note that it
0226     //is (mostly) IE-compatible in quirks, and mozilla-compatible in strict.
0227     if (!rend) {
0228         return nullptr;
0229     }
0230 
0231     bool quirksMode = rend->style() && rend->style()->htmlHacks();
0232 
0233     //There are a couple quirks here. One is that in quirks mode body is always forwarded to root...
0234     //This is relevant for even the scrollTop/scrollLeft type properties.
0235     if (quirksMode && node->id() == ID_BODY) {
0236         while (rend->parent() && !rend->isRoot()) {
0237             rend = rend->parent();
0238         }
0239     }
0240 
0241     //Also, some properties of the root are really done in terms of the viewport.
0242     //These are  {offset/client}{Height/Width}. The offset versions do it only in
0243     //quirks mode, the client always.
0244     if (!rend->isRoot()) {
0245         return rend;    //Don't care about non-root things here!
0246     }
0247     bool needViewport = false;
0248 
0249     switch (token) {
0250     case DOMNode::OffsetHeight:
0251     case DOMNode::OffsetWidth:
0252         needViewport = quirksMode;
0253         break;
0254     case DOMNode::ClientHeight:
0255     case DOMNode::ClientWidth:
0256     case DOMNode::ClientLeft:
0257     case DOMNode::ClientTop:
0258         needViewport = true;
0259         break;
0260     }
0261 
0262     if (needViewport) {
0263         //Scan up to find the new target
0264         while (rend->parent()) {
0265             rend = rend->parent();
0266         }
0267     }
0268     return rend;
0269 }
0270 
0271 JSValue *DOMNode::getValueProperty(ExecState *exec, int token) const
0272 {
0273     NodeImpl &node = *impl();
0274     switch (token) {
0275     case NodeName:
0276         return jsString(node.nodeName());
0277     case NodeValue:
0278         return ::getStringOrNull(node.nodeValue()); // initially null, per domts/level1/core/hc_documentcreateelement.html
0279     case NodeType:
0280         return jsNumber((unsigned int)node.nodeType());
0281     case ParentNode:
0282         return getDOMNode(exec, node.parentNode());
0283     case ParentElement: // IE only apparently
0284         return getDOMNode(exec, node.parentNode());
0285     case ChildNodes:
0286         return getDOMNodeList(exec, node.childNodes().get());
0287     case FirstChild:
0288         return getDOMNode(exec, node.firstChild());
0289     case LastChild:
0290         return getDOMNode(exec, node.lastChild());
0291     case PreviousSibling:
0292         return getDOMNode(exec, node.previousSibling());
0293     case NextSibling:
0294         return getDOMNode(exec, node.nextSibling());
0295     case Attributes: {
0296         DOM::NamedNodeMapImpl *attrs = nullptr;
0297         if (node.isElementNode()) {
0298             DOM::ElementImpl &el = static_cast<DOM::ElementImpl &>(node);
0299             attrs = el.attributes();
0300         }
0301         return getDOMNamedNodeMap(exec, attrs);
0302     }
0303     case NamespaceURI:
0304         return ::getStringOrNull(node.namespaceURI()); // Moz returns null if not set (dom/namespaces.html)
0305     case Prefix:
0306         return ::getStringOrNull(node.prefix());  // Moz returns null if not set (dom/namespaces.html)
0307     case LocalName:
0308         return ::getStringOrNull(node.localName());  // Moz returns null if not set (dom/namespaces.html)
0309     case OwnerDocument:
0310         return getDOMNode(exec, node.ownerDocument());
0311     case TextContent:
0312         return ::getStringOrNull(node.textContent());
0313     case OnAbort:
0314         return getListener(DOM::EventImpl::ABORT_EVENT);
0315     case OnBlur:
0316         return getListener(DOM::EventImpl::BLUR_EVENT);
0317     case OnChange:
0318         return getListener(DOM::EventImpl::CHANGE_EVENT);
0319     case OnClick:
0320         return getListener(DOM::EventImpl::KHTML_ECMA_CLICK_EVENT);
0321     case OnDblClick:
0322         return getListener(DOM::EventImpl::KHTML_ECMA_DBLCLICK_EVENT);
0323     case OnDragDrop:
0324         return getListener(DOM::EventImpl::KHTML_DRAGDROP_EVENT);
0325     case OnError:
0326         return getListener(DOM::EventImpl::ERROR_EVENT);
0327     case OnFocus:
0328         return getListener(DOM::EventImpl::FOCUS_EVENT);
0329     case OnKeyDown:
0330         return getListener(DOM::EventImpl::KEYDOWN_EVENT);
0331     case OnKeyPress:
0332         return getListener(DOM::EventImpl::KEYPRESS_EVENT);
0333     case OnKeyUp:
0334         return getListener(DOM::EventImpl::KEYUP_EVENT);
0335     case OnLoad:
0336         return getListener(DOM::EventImpl::LOAD_EVENT);
0337     case OnMouseDown:
0338         return getListener(DOM::EventImpl::MOUSEDOWN_EVENT);
0339     case OnMouseMove:
0340         return getListener(DOM::EventImpl::MOUSEMOVE_EVENT);
0341     case OnMouseOut:
0342         return getListener(DOM::EventImpl::MOUSEOUT_EVENT);
0343     case OnMouseOver:
0344         return getListener(DOM::EventImpl::MOUSEOVER_EVENT);
0345     case OnMouseUp:
0346         return getListener(DOM::EventImpl::MOUSEUP_EVENT);
0347     case OnMove:
0348         return getListener(DOM::EventImpl::KHTML_MOVE_EVENT);
0349     case OnReset:
0350         return getListener(DOM::EventImpl::RESET_EVENT);
0351     case OnResize:
0352         return getListener(DOM::EventImpl::RESIZE_EVENT);
0353     case OnScroll:
0354         return getListener(DOM::EventImpl::SCROLL_EVENT);
0355     case OnSelect:
0356         return getListener(DOM::EventImpl::SELECT_EVENT);
0357     case OnSubmit:
0358         return getListener(DOM::EventImpl::SUBMIT_EVENT);
0359     case OnUnload:
0360         return getListener(DOM::EventImpl::UNLOAD_EVENT);
0361     case SourceIndex: {
0362         // Retrieves the ordinal position of the object, in source order, as the object
0363         // appears in the document's all collection
0364         // i.e. document.all[n.sourceIndex] == n
0365         DOM::DocumentImpl *doc = node.document();
0366         if (doc->isHTMLDocument()) {
0367             HTMLCollectionImpl all(doc, HTMLCollectionImpl::DOC_ALL);
0368             unsigned long i = 0;
0369             for (DOM::NodeImpl *n = all.firstItem(); n; n = all.nextItem()) {
0370                 if (n == impl()) {
0371                     return jsNumber(i);
0372                 }
0373                 ++i;
0374             }
0375         }
0376         return jsUndefined();
0377     }
0378     default:
0379         // no DOM standard, found in IE only
0380 
0381         // Make sure our layout is up to date before we allow a query on these attributes.
0382         DOM::DocumentImpl *docimpl = node.document();
0383         if (docimpl) {
0384             docimpl->updateLayout();
0385         }
0386 
0387         khtml::RenderObject *rend = node.renderer();
0388 
0389         //In quirks mode, may need to forward if to body.
0390         rend = handleBodyRootQuirk(impl(), rend, token);
0391 
0392         switch (token) {
0393         case OffsetLeft:
0394             return rend ? jsNumber(rend->offsetLeft()) : jsNumber(0);
0395         case OffsetTop:
0396             return rend ? jsNumber(rend->offsetTop()) : jsNumber(0);
0397         case OffsetWidth:
0398             return rend ? jsNumber(rend->offsetWidth()) : jsNumber(0);
0399         case OffsetHeight:
0400             return rend ? jsNumber(rend->offsetHeight()) : jsNumber(0);
0401         case OffsetParent: {
0402             khtml::RenderObject *par = rend ? rend->offsetParent() : nullptr;
0403             return getDOMNode(exec, par ? par->element() : nullptr);
0404         }
0405         case ClientWidth:
0406             return rend ? jsNumber(rend->clientWidth()) : jsNumber(0);
0407         case ClientHeight:
0408             return rend ? jsNumber(rend->clientHeight()) : jsNumber(0);
0409         case ClientLeft:
0410             return rend ? jsNumber(rend->clientLeft()) : jsNumber(0);
0411         case ClientTop:
0412             return rend ? jsNumber(rend->clientTop()) : jsNumber(0);
0413         case ScrollWidth:
0414             return rend ? jsNumber(rend->scrollWidth()) : jsNumber(0);
0415         case ScrollHeight:
0416             return rend ? jsNumber(rend->scrollHeight()) : jsNumber(0);
0417         case ScrollLeft:
0418             if (rend && rend->layer()) {
0419                 if (rend->isRoot() && !rend->hasOverflowClip()) {
0420                     return jsNumber(node.document()->view() ? node.document()->view()->contentsX() : 0);
0421                 }
0422                 return jsNumber(rend->hasOverflowClip() ? rend->layer()->scrollXOffset() : 0);
0423             }
0424             return jsNumber(0);
0425         case ScrollTop:
0426             if (rend && rend->layer()) {
0427                 if (rend->isRoot() && !rend->hasOverflowClip()) {
0428                     return jsNumber(node.document()->view() ? node.document()->view()->contentsY() : 0);
0429                 }
0430                 return jsNumber(rend->hasOverflowClip() ? rend->layer()->scrollYOffset() : 0);
0431             }
0432             return jsNumber(0);
0433         default:
0434             // qCDebug(KHTML_LOG) << "WARNING: Unhandled token in DOMNode::getValueProperty : " << token;
0435             break;
0436         }
0437     }
0438     return jsUndefined();
0439 }
0440 
0441 void DOMNode::put(ExecState *exec, const Identifier &propertyName, JSValue *value, int attr)
0442 {
0443 #ifdef KJS_VERBOSE
0444     qCDebug(KHTML_LOG) << "DOMNode::tryPut " << propertyName.qstring();
0445 #endif
0446     lookupPut<DOMNode, DOMObject>(exec, propertyName, value, attr,
0447                                   &DOMNodeTable, this);
0448 }
0449 
0450 void DOMNode::putValueProperty(ExecState *exec, int token, JSValue *value, int /*attr*/)
0451 {
0452     DOMExceptionTranslator exception(exec);
0453     NodeImpl &node = *impl();
0454 
0455     switch (token) {
0456     case NodeValue:
0457         node.setNodeValue(value->toString(exec).domString(), exception);
0458         break;
0459     case Prefix:
0460         node.setPrefix(value->toString(exec).domString(), exception);
0461         break;
0462     case TextContent:
0463         node.setTextContent(valueToStringWithNullCheck(exec, value), exception);
0464         break;
0465     case OnAbort:
0466         setListener(exec, DOM::EventImpl::ABORT_EVENT, value);
0467         break;
0468     case OnBlur:
0469         setListener(exec, DOM::EventImpl::BLUR_EVENT, value);
0470         break;
0471     case OnChange:
0472         setListener(exec, DOM::EventImpl::CHANGE_EVENT, value);
0473         break;
0474     case OnClick:
0475         setListener(exec, DOM::EventImpl::KHTML_ECMA_CLICK_EVENT, value);
0476         break;
0477     case OnDblClick:
0478         setListener(exec, DOM::EventImpl::KHTML_ECMA_DBLCLICK_EVENT, value);
0479         break;
0480     case OnDragDrop:
0481         setListener(exec, DOM::EventImpl::KHTML_DRAGDROP_EVENT, value);
0482         break;
0483     case OnError:
0484         setListener(exec, DOM::EventImpl::ERROR_EVENT, value);
0485         break;
0486     case OnFocus:
0487         setListener(exec, DOM::EventImpl::FOCUS_EVENT, value);
0488         break;
0489     case OnKeyDown:
0490         setListener(exec, DOM::EventImpl::KEYDOWN_EVENT, value);
0491         break;
0492     case OnKeyPress:
0493         setListener(exec, DOM::EventImpl::KEYPRESS_EVENT, value);
0494         break;
0495     case OnKeyUp:
0496         setListener(exec, DOM::EventImpl::KEYUP_EVENT, value);
0497         break;
0498     case OnLoad:
0499         setListener(exec, DOM::EventImpl::LOAD_EVENT, value);
0500         break;
0501     case OnMouseDown:
0502         setListener(exec, DOM::EventImpl::MOUSEDOWN_EVENT, value);
0503         break;
0504     case OnMouseMove:
0505         setListener(exec, DOM::EventImpl::MOUSEMOVE_EVENT, value);
0506         break;
0507     case OnMouseOut:
0508         setListener(exec, DOM::EventImpl::MOUSEOUT_EVENT, value);
0509         break;
0510     case OnMouseOver:
0511         setListener(exec, DOM::EventImpl::MOUSEOVER_EVENT, value);
0512         break;
0513     case OnMouseUp:
0514         setListener(exec, DOM::EventImpl::MOUSEUP_EVENT, value);
0515         break;
0516     case OnMove:
0517         setListener(exec, DOM::EventImpl::KHTML_MOVE_EVENT, value);
0518         break;
0519     case OnReset:
0520         setListener(exec, DOM::EventImpl::RESET_EVENT, value);
0521         break;
0522     case OnResize:
0523         setListener(exec, DOM::EventImpl::RESIZE_EVENT, value);
0524         break;
0525     case OnScroll:
0526         setListener(exec, DOM::EventImpl::SCROLL_EVENT, value);
0527         break;
0528     case OnSelect:
0529         setListener(exec, DOM::EventImpl::SELECT_EVENT, value);
0530         break;
0531     case OnSubmit:
0532         setListener(exec, DOM::EventImpl::SUBMIT_EVENT, value);
0533         break;
0534     case OnUnload:
0535         setListener(exec, DOM::EventImpl::UNLOAD_EVENT, value);
0536         break;
0537     default:
0538         // Make sure our layout is up to date
0539         DOM::DocumentImpl *docimpl = node.document();
0540         if (docimpl) {
0541             docimpl->updateLayout();
0542         }
0543 
0544         khtml::RenderObject *rend = node.renderer();
0545 
0546         //In quirks mode, may need to forward.
0547         rend = handleBodyRootQuirk(impl(), rend, token);
0548 
0549         switch (token) {
0550         case ScrollLeft:
0551             if (rend && rend->layer()) {
0552                 if (rend->hasOverflowClip()) {
0553                     rend->layer()->scrollToXOffset(value->toInt32(exec));
0554                 } else if (rend->isRoot()) {
0555                     KHTMLView *sview = node.document()->view();
0556                     if (sview) {
0557                         sview->setContentsPos(value->toInt32(exec), sview->contentsY());
0558                     }
0559                 }
0560             }
0561             break;
0562         case ScrollTop:
0563             if (rend && rend->layer()) {
0564                 if (rend->hasOverflowClip()) {
0565                     rend->layer()->scrollToYOffset(value->toInt32(exec));
0566                 } else if (rend->isRoot()) {
0567                     KHTMLView *sview = node.document()->view();
0568                     if (sview) {
0569                         sview->setContentsPos(sview->contentsX(), value->toInt32(exec));
0570                     }
0571                 }
0572             }
0573             break;
0574         default:
0575             // qCDebug(KHTML_LOG) << "WARNING: DOMNode::putValueProperty unhandled token " << token;
0576             break;
0577         }
0578     }
0579 }
0580 
0581 JSValue *DOMNode::toPrimitive(ExecState *exec, JSType /*preferred*/) const
0582 {
0583     if (m_impl.isNull()) {
0584         return jsNull();
0585     }
0586 
0587     return jsString(toString(exec));
0588 }
0589 
0590 UString DOMNode::toString(ExecState *) const
0591 {
0592     if (m_impl.isNull()) {
0593         return "null";
0594     }
0595     return "[object " + className() + "]";
0596 }
0597 
0598 void DOMNode::setListener(ExecState *exec, int eventId, JSValue *func) const
0599 {
0600     m_impl->setHTMLEventListener(eventId, Window::retrieveActive(exec)->getJSEventListener(func, true));
0601 }
0602 
0603 JSValue *DOMNode::getListener(int eventId) const
0604 {
0605     DOM::EventListener *listener = m_impl->getHTMLEventListener(eventId);
0606     JSEventListener *jsListener = static_cast<JSEventListener *>(listener);
0607     if (jsListener && jsListener->listenerObj()) {
0608         return jsListener->listenerObj();
0609     } else {
0610         return jsNull();
0611     }
0612 }
0613 
0614 void DOMNode::pushEventHandlerScope(ExecState *, ScopeChain &) const
0615 {
0616 }
0617 
0618 JSValue *DOMNodeProtoFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
0619 {
0620     KJS_CHECK_THIS(DOMNode, thisObj);
0621     DOMExceptionTranslator exception(exec);
0622     DOM::NodeImpl &node = *static_cast<DOMNode *>(thisObj)->impl();
0623     switch (id) {
0624     case DOMNode::HasAttributes:
0625         return jsBoolean(node.hasAttributes());
0626     case DOMNode::HasChildNodes:
0627         return jsBoolean(node.hasChildNodes());
0628     case DOMNode::CloneNode: {
0629         RefPtr<NodeImpl> clone = node.cloneNode(args[0]->toBoolean(exec));
0630         return getDOMNode(exec, clone.get());
0631     }
0632     case DOMNode::Normalize:
0633         node.normalize();
0634         return jsUndefined();
0635     case DOMNode::IsSupported:
0636         return jsBoolean(node.isSupported(args[0]->toString(exec).domString(), args[1]->toString(exec).domString()));
0637     case DOMNode::AddEventListener: {
0638         JSEventListener *listener = Window::retrieveActive(exec)->getJSEventListener(args[1]);
0639         EventName id = EventName::fromString(args[0]->toString(exec).domString());
0640         node.addEventListener(id, listener, args[2]->toBoolean(exec));
0641         return jsUndefined();
0642     }
0643     case DOMNode::RemoveEventListener: {
0644         JSEventListener *listener = Window::retrieveActive(exec)->getJSEventListener(args[1]);
0645         EventName id = EventName::fromString(args[0]->toString(exec).domString());
0646         node.removeEventListener(id, listener, args[2]->toBoolean(exec));
0647         return jsUndefined();
0648     }
0649     case DOMNode::DispatchEvent: {
0650         SharedPtr<DOM::EventImpl> evt = toEvent(args[0]);
0651         if (!evt) {
0652             setDOMException(exec, DOMException::NOT_FOUND_ERR);
0653             return jsUndefined();
0654         }
0655         node.dispatchEvent(evt.get(), exception);
0656         return jsBoolean(!evt->defaultPrevented());
0657     }
0658     case DOMNode::AppendChild:
0659         return getDOMNode(exec, node.appendChild(toNode(args[0]), exception));
0660     case DOMNode::RemoveChild: {
0661         SharedPtr<DOM::NodeImpl> oldKid = toNode(args[0]);
0662         node.removeChild(oldKid.get(), exception);
0663         return getDOMNode(exec, oldKid.get());
0664     }
0665     case DOMNode::InsertBefore:
0666         return getDOMNode(exec, node.insertBefore(toNode(args[0]), toNode(args[1]), exception));
0667     case DOMNode::ReplaceChild: {
0668         SharedPtr<DOM::NodeImpl> oldKid = toNode(args[1]);
0669         node.replaceChild(toNode(args[0]), oldKid.get(), exception);
0670         return getDOMNode(exec, oldKid.get());
0671     }
0672     case DOMNode::Contains: {
0673         DOM::NodeImpl *other = toNode(args[0]);
0674         if (other && other->isElementNode()) {
0675             return jsBoolean(other->isAncestor(&node));
0676         }
0677         setDOMException(exec, DOMException::TYPE_MISMATCH_ERR); // ### a guess
0678         return jsUndefined();
0679     }
0680     case DOMNode::InsertAdjacentHTML: {
0681         // see http://www.faqts.com/knowledge_base/view.phtml/aid/5756
0682         // and http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/insertAdjacentHTML.asp
0683         SharedPtr<DOM::RangeImpl> range = node.document()->createRange();
0684 
0685         range->setStartBefore(&node, exception);
0686         if (exception.triggered()) {
0687             return jsUndefined();
0688         }
0689 
0690         SharedPtr<DOM::DocumentFragmentImpl> docFrag =
0691             static_cast<DOM::DocumentFragmentImpl *>(range->createContextualFragment(args[1]->toString(exec).domString(), exception).handle());
0692         if (exception.triggered()) {
0693             return jsUndefined();
0694         }
0695 
0696         DOMString where = args[0]->toString(exec).domString().lower();
0697 
0698         if (where == "beforebegin") {
0699             node.parentNode()->insertBefore(docFrag.get(), &node, exception);
0700         } else if (where == "afterbegin") {
0701             node.insertBefore(docFrag.get(), node.firstChild(), exception);
0702         } else if (where == "beforeend") {
0703             return getDOMNode(exec, node.appendChild(docFrag.get(), exception));
0704         } else if (where == "afterend") {
0705             if (node.nextSibling()) {
0706                 node.parentNode()->insertBefore(docFrag.get(), node.nextSibling(), exception);
0707             } else {
0708                 node.parentNode()->appendChild(docFrag.get(), exception);
0709             }
0710         }
0711 
0712         return jsUndefined();
0713     }
0714     case DOMNode::CompareDocumentPosition: {
0715         DOM::NodeImpl *other = toNode(args[0]);
0716         if (!other) {
0717             setDOMException(exec, DOMException::TYPE_MISMATCH_ERR);
0718         } else {
0719             return jsNumber(node.compareDocumentPosition(other));
0720         }
0721     }
0722     }
0723 
0724     return jsUndefined();
0725 }
0726 
0727 // -------------------------------------------------------------------------
0728 
0729 /*
0730 @begin DOMNodeListProtoTable 2
0731   item      DOMNodeList::Item       DontDelete|Function 1
0732 # IE extension (IE treats DOMNodeList like an HTMLCollection)
0733   namedItem DOMNodeList::NamedItem      DontDelete|Function 1
0734 @end
0735 */
0736 KJS_DEFINE_PROTOTYPE(DOMNodeListProto)
0737 KJS_IMPLEMENT_PROTOFUNC(DOMNodeListProtoFunc)
0738 KJS_IMPLEMENT_PROTOTYPE("DOMNodeList", DOMNodeListProto, DOMNodeListProtoFunc, ObjectPrototype)
0739 
0740 IMPLEMENT_PSEUDO_CONSTRUCTOR(NodeListPseudoCtor, "NodeList", DOMNodeListProto)
0741 
0742 const ClassInfo DOMNodeList::info = { "NodeList", nullptr, nullptr, nullptr };
0743 
0744 DOMNodeList::DOMNodeList(ExecState *exec, DOM::NodeListImpl *l)
0745     : DOMObject(DOMNodeListProto::self(exec)), m_impl(l) { }
0746 
0747 DOMNodeList::~DOMNodeList()
0748 {
0749     ScriptInterpreter::forgetDOMObject(m_impl.get());
0750 }
0751 
0752 JSValue *DOMNodeList::indexGetter(ExecState *exec, unsigned index)
0753 {
0754     return getDOMNode(exec, m_impl->item(index));
0755 }
0756 
0757 JSValue *DOMNodeList::nameGetter(ExecState *exec, JSObject *, const Identifier &name, const PropertySlot &slot)
0758 {
0759     DOMNodeList *thisObj = static_cast<DOMNodeList *>(slot.slotBase());
0760     return getDOMNode(exec, thisObj->getByName(name));
0761 }
0762 
0763 JSValue *DOMNodeList::lengthGetter(ExecState *, JSObject *, const Identifier &, const PropertySlot &slot)
0764 {
0765     DOMNodeList *thisObj = static_cast<DOMNodeList *>(slot.slotBase());
0766     return jsNumber(thisObj->m_impl->length());
0767 }
0768 
0769 DOM::NodeImpl *DOMNodeList::getByName(const Identifier &name)
0770 {
0771     //### M.O.: I bet IE checks name only for some tags.
0772     DOMString domName = name.domString();
0773     unsigned long l   = m_impl->length();
0774     for (unsigned long i = 0; i < l; i++) {
0775         DOM::NodeImpl *n = m_impl->item(i);
0776         if (n->isElementNode()) {
0777             DOM::ElementImpl *e = static_cast<DOM::ElementImpl *>(n);
0778             if (e->getAttribute(ATTR_ID) == domName || e->getAttribute(ATTR_NAME) == domName) {
0779                 return n;
0780             }
0781         }
0782     }
0783     return nullptr;
0784 }
0785 
0786 bool DOMNodeList::getOwnPropertySlot(ExecState *exec, const Identifier &propertyName, PropertySlot &slot)
0787 {
0788     if (propertyName == exec->propertyNames().length) {
0789         slot.setCustom(this, lengthGetter);
0790         return true;
0791     }
0792 
0793     //### this could benefit from further nodelist/collection consolidation,
0794     //including moving nameditem down to nodelists.
0795 
0796     // Look in the prototype (for functions) before assuming it's an item's name
0797     JSObject *proto = prototype()->getObject();
0798     if (proto && proto->hasProperty(exec, propertyName)) {
0799         return false;
0800     }
0801 
0802     //May be it's an index?
0803     if (getIndexSlot(this, *m_impl, propertyName, slot)) {
0804         return true;
0805     }
0806 
0807     //May be it's a name -- check by ID
0808     //Check by id
0809     if (getByName(propertyName)) {
0810         slot.setCustom(this, nameGetter);
0811         return true;
0812     }
0813 
0814     return DOMObject::getOwnPropertySlot(exec, propertyName, slot);
0815 }
0816 
0817 void DOMNodeList::getOwnPropertyNames(ExecState *exec, PropertyNameArray &propertyNames, PropertyMap::PropertyMode mode)
0818 {
0819     for (unsigned i = 0; i < m_impl->length(); ++i) {
0820         propertyNames.add(Identifier::from(i));
0821     }
0822 
0823     propertyNames.add(exec->propertyNames().length);
0824 
0825     JSObject::getOwnPropertyNames(exec, propertyNames, mode);
0826 }
0827 
0828 // Need to support both get and call, so that list[0] and list(0) work.
0829 JSValue *DOMNodeList::callAsFunction(ExecState *exec, JSObject *, const List &args)
0830 {
0831     // Do not use thisObj here. See HTMLCollection.
0832     UString s = args[0]->toString(exec);
0833 
0834     // index-based lookup?
0835     bool ok;
0836     unsigned int u = s.qstring().toULong(&ok);
0837     if (ok) {
0838         return getDOMNode(exec, m_impl->item(u));
0839     }
0840 
0841     // try lookup by name
0842     // ### NodeList::namedItem() would be cool to have
0843     // ### do we need to support the same two arg overload as in HTMLCollection?
0844     JSValue *result = get(exec, Identifier(s));
0845 
0846     if (result) {
0847         return result;
0848     }
0849 
0850     return jsUndefined();
0851 }
0852 
0853 JSValue *DOMNodeListProtoFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
0854 {
0855     KJS_CHECK_THIS(KJS::DOMNodeList, thisObj);
0856     DOMNodeList *jsList     = static_cast<DOMNodeList *>(thisObj);
0857     DOM::NodeListImpl &list = *jsList->impl();
0858     switch (id) {
0859     case KJS::DOMNodeList::Item:
0860         return getDOMNode(exec, list.item(args[0]->toInt32(exec)));
0861     case KJS::DOMNodeList::NamedItem:
0862         return getDOMNode(exec, jsList->getByName(Identifier(args[0]->toString(exec))));
0863     default:
0864         return jsUndefined();
0865     }
0866 }
0867 
0868 // -------------------------------------------------------------------------
0869 
0870 //### FIXME: link to the node prototype.
0871 const ClassInfo DOMAttr::info = { "Attr", &DOMNode::info, &DOMAttrTable, nullptr };
0872 
0873 /* Source for DOMAttrTable.
0874 @begin DOMAttrTable 5
0875   name      DOMAttr::Name       DontDelete|ReadOnly
0876   specified DOMAttr::Specified  DontDelete|ReadOnly
0877   value     DOMAttr::ValueProperty  DontDelete
0878   ownerElement  DOMAttr::OwnerElement   DontDelete|ReadOnly
0879 @end
0880 */
0881 bool DOMAttr::getOwnPropertySlot(ExecState *exec, const Identifier &propertyName, PropertySlot &slot)
0882 {
0883 #ifdef KJS_VERBOSE
0884     qCDebug(KHTML_LOG) << "DOMAttr::tryGet " << propertyName.qstring();
0885 #endif
0886     return getStaticValueSlot<DOMAttr, DOMNode>(exec, &DOMAttrTable, this, propertyName, slot);
0887 }
0888 
0889 JSValue *DOMAttr::getValueProperty(ExecState *exec, int token) const
0890 {
0891     AttrImpl *attr = static_cast<AttrImpl *>(impl());
0892     switch (token) {
0893     case Name:
0894         return jsString(attr->name());
0895     case Specified:
0896         return jsBoolean(attr->specified());
0897     case ValueProperty:
0898         return jsString(attr->nodeValue());
0899     case OwnerElement: // DOM2
0900         return getDOMNode(exec, attr->ownerElement());
0901     }
0902     return jsNull(); // not reached
0903 }
0904 
0905 void DOMAttr::put(ExecState *exec, const Identifier &propertyName, JSValue *value, int attr)
0906 {
0907 #ifdef KJS_VERBOSE
0908     qCDebug(KHTML_LOG) << "DOMAttr::tryPut " << propertyName.qstring();
0909 #endif
0910     lookupPut<DOMAttr, DOMNode>(exec, propertyName, value, attr,
0911                                 &DOMAttrTable, this);
0912 }
0913 
0914 void DOMAttr::putValueProperty(ExecState *exec, int token, JSValue *value, int /*attr*/)
0915 {
0916     DOMExceptionTranslator exception(exec);
0917     switch (token) {
0918     case ValueProperty:
0919         static_cast<AttrImpl *>(impl())->setValue(value->toString(exec).domString(), exception);
0920         return;
0921     default:
0922         qCWarning(KHTML_LOG) << "DOMAttr::putValueProperty unhandled token " << token;
0923     }
0924 }
0925 
0926 AttrImpl *toAttr(JSValue *val)
0927 {
0928     if (!val || !val->isObject(&DOMAttr::info)) {
0929         return nullptr;
0930     }
0931     return static_cast<AttrImpl *>(static_cast<DOMNode *>(val)->impl());
0932 }
0933 
0934 // -------------------------------------------------------------------------
0935 
0936 /* Source for DOMDocumentProtoTable.
0937 @begin DOMDocumentProtoTable 23
0938   createElement   DOMDocument::CreateElement                   DontDelete|Function 1
0939   createDocumentFragment DOMDocument::CreateDocumentFragment   DontDelete|Function 1
0940   createTextNode  DOMDocument::CreateTextNode                  DontDelete|Function 1
0941   createComment   DOMDocument::CreateComment                   DontDelete|Function 1
0942   createCDATASection DOMDocument::CreateCDATASection           DontDelete|Function 1
0943   createProcessingInstruction DOMDocument::CreateProcessingInstruction DontDelete|Function 1
0944   createAttribute DOMDocument::CreateAttribute                 DontDelete|Function 1
0945   createEntityReference DOMDocument::CreateEntityReference     DontDelete|Function 1
0946   getElementsByTagName  DOMDocument::GetElementsByTagName      DontDelete|Function 1
0947   importNode           DOMDocument::ImportNode                 DontDelete|Function 2
0948   createElementNS      DOMDocument::CreateElementNS            DontDelete|Function 2
0949   createAttributeNS    DOMDocument::CreateAttributeNS          DontDelete|Function 2
0950   getElementsByTagNameNS  DOMDocument::GetElementsByTagNameNS  DontDelete|Function 2
0951   getElementById     DOMDocument::GetElementById               DontDelete|Function 1
0952   createRange        DOMDocument::CreateRange                  DontDelete|Function 0
0953   createNodeIterator DOMDocument::CreateNodeIterator           DontDelete|Function 3
0954   createTreeWalker   DOMDocument::CreateTreeWalker             DontDelete|Function 4
0955   createEvent        DOMDocument::CreateEvent                  DontDelete|Function 1
0956   getOverrideStyle   DOMDocument::GetOverrideStyle             DontDelete|Function 2
0957   abort              DOMDocument::Abort                        DontDelete|Function 0
0958   load               DOMDocument::Load                         DontDelete|Function 1
0959   loadXML            DOMDocument::LoadXML                      DontDelete|Function 2
0960   execCommand        DOMDocument::ExecCommand                  DontDelete|Function 3
0961   queryCommandEnabled DOMDocument::QueryCommandEnabled         DontDelete|Function 1
0962   queryCommandIndeterm DOMDocument::QueryCommandIndeterm       DontDelete|Function 1
0963   queryCommandState DOMDocument::QueryCommandState             DontDelete|Function 1
0964   queryCommandSupported DOMDocument::QueryCommandSupported     DontDelete|Function 1
0965   queryCommandValue DOMDocument::QueryCommandValue             DontDelete|Function 1
0966   getElementsByClassName DOMDocument::GetElementsByClassName   DontDelete|Function 1
0967   querySelector          DOMDocument::QuerySelector            DontDelete|Function 1
0968   querySelectorAll       DOMDocument::QuerySelectorAll         DontDelete|Function 1
0969   createExpression       DOMDocument::CreateExpression         DontDelete|Function 2
0970   createNSResolver       DOMDocument::CreateNSResolver         DontDelete|Function 1
0971   evaluate               DOMDocument::Evaluate                 DontDelete|Function 4
0972 @end
0973 */
0974 
0975 KJS_IMPLEMENT_PROTOFUNC(DOMDocumentProtoFunc)
0976 KJS_IMPLEMENT_PROTOTYPE("DOMDocument", DOMDocumentProto, DOMDocumentProtoFunc, DOMNodeProto)
0977 
0978 IMPLEMENT_PSEUDO_CONSTRUCTOR(DocumentPseudoCtor, "Document", DOMDocumentProto)
0979 
0980 const ClassInfo DOMDocument::info = { "Document", &DOMNode::info, &DOMDocumentTable, nullptr };
0981 
0982 /* Source for DOMDocumentTable.
0983 @begin DOMDocumentTable 4
0984   doctype         DOMDocument::DocType                         DontDelete|ReadOnly
0985   implementation  DOMDocument::Implementation                  DontDelete|ReadOnly
0986   characterSet    DOMDocument::CharacterSet                    DontDelete|ReadOnly
0987   documentElement DOMDocument::DocumentElement                 DontDelete|ReadOnly
0988   styleSheets     DOMDocument::StyleSheets                     DontDelete|ReadOnly
0989   preferredStylesheetSet  DOMDocument::PreferredStylesheetSet  DontDelete|ReadOnly
0990   selectedStylesheetSet  DOMDocument::SelectedStylesheetSet    DontDelete
0991   readyState      DOMDocument::ReadyState                      DontDelete|ReadOnly
0992   defaultView     DOMDocument::DefaultView                     DontDelete|ReadOnly
0993   async           DOMDocument::Async                           DontDelete
0994   title           DOMDocument::Title                           DontDelete
0995 @end
0996 */
0997 
0998 DOMDocument::DOMDocument(ExecState *exec, DOM::DocumentImpl *d)
0999     : DOMNode(exec, d)
1000 {
1001     setPrototype(DOMDocumentProto::self(exec));
1002 }
1003 
1004 DOMDocument::DOMDocument(JSObject *proto, DOM::DocumentImpl *d)
1005     : DOMNode(proto, d)
1006 {}
1007 
1008 bool DOMDocument::getOwnPropertySlot(ExecState *exec, const Identifier &propertyName, PropertySlot &slot)
1009 {
1010 #ifdef KJS_VERBOSE
1011     qCDebug(KHTML_LOG) << "DOMDocument::tryGet " << propertyName.qstring();
1012 #endif
1013     return getStaticValueSlot<DOMDocument, DOMNode>(
1014                exec, &DOMDocumentTable, this, propertyName, slot);
1015 }
1016 
1017 JSValue *DOMDocument::getValueProperty(ExecState *exec, int token) const
1018 {
1019     DOM::DocumentImpl &doc = *static_cast<DOM::DocumentImpl *>(m_impl.get());
1020 
1021     switch (token) {
1022     case DocType:
1023         return getDOMNode(exec, doc.doctype());
1024     case Implementation:
1025         return getDOMDOMImplementation(exec, doc.implementation());
1026     case DocumentElement:
1027         return getDOMNode(exec, doc.documentElement());
1028     case CharacterSet: {
1029         if (doc.part()) {
1030             return jsString(doc.part()->encoding());
1031         } else {
1032             return jsUndefined();
1033         }
1034     }
1035     case StyleSheets:
1036         //qCDebug(KHTML_LOG) << "DOMDocument::StyleSheets, returning " << doc.styleSheets().length() << " stylesheets";
1037         return getDOMStyleSheetList(exec, doc.styleSheets(), &doc);
1038     case DOMDocument::DefaultView: { // DOM2
1039         KHTMLPart *part = doc.part();
1040         if (part) {
1041             return Window::retrieve(part);
1042         }
1043         return getDOMAbstractView(exec, doc.defaultView());
1044     }
1045     case PreferredStylesheetSet:
1046         return jsString(doc.preferredStylesheetSet());
1047     case SelectedStylesheetSet:
1048         return jsString(doc.selectedStylesheetSet());
1049     case ReadyState: {
1050         if (KHTMLPart *part = doc.part()) {
1051             if (part->d->m_bComplete) {
1052                 return jsString("complete");
1053             }
1054             if (doc.parsing()) {
1055                 return jsString("loading");
1056             }
1057             return jsString("loaded");
1058             // What does the interactive value mean ?
1059             // Missing support for "uninitialized"
1060         }
1061         return jsUndefined();
1062     }
1063     case Async:
1064         return jsBoolean(doc.async());
1065     case Title:
1066         return jsString(doc.title());
1067     default:
1068         // qCDebug(KHTML_LOG) << "WARNING: DOMDocument::getValueProperty unhandled token " << token;
1069         return jsNull();
1070     }
1071 }
1072 
1073 void DOMDocument::put(ExecState *exec, const Identifier &propertyName, JSValue *value, int attr)
1074 {
1075 #ifdef KJS_VERBOSE
1076     qCDebug(KHTML_LOG) << "DOMDocument::tryPut " << propertyName.qstring();
1077 #endif
1078     lookupPut<DOMDocument, DOMNode>(exec, propertyName, value, attr, &DOMDocumentTable, this);
1079 }
1080 
1081 void DOMDocument::putValueProperty(ExecState *exec, int token, JSValue *value, int /*attr*/)
1082 {
1083     DOM::DocumentImpl &doc = *static_cast<DOM::DocumentImpl *>(impl());
1084     switch (token) {
1085     case SelectedStylesheetSet: {
1086         doc.setSelectedStylesheetSet(value->toString(exec).domString());
1087         break;
1088     }
1089     case Async: {
1090         doc.setAsync(value->toBoolean(exec));
1091         break;
1092     }
1093     case Title: {
1094         DOM::DOMString val = value->toString(exec).domString();
1095         if (doc.title() != val) {
1096             doc.setTitle(val);
1097         }
1098         break;
1099     }
1100     }
1101 }
1102 
1103 JSValue *DOMDocumentProtoFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
1104 {
1105     KJS_CHECK_THIS(KJS::DOMDocument, thisObj);
1106     DOMExceptionTranslator exception(exec);
1107     DOM::NodeImpl     &node = *static_cast<DOMNode *>(thisObj)->impl();
1108     DOM::DocumentImpl &doc  = static_cast<DOM::DocumentImpl &>(node);
1109 
1110     KJS::UString str = args[0]->toString(exec);
1111 
1112     // we can do it fast, without copying the data
1113     if (id == DOMDocument::GetElementById) {
1114 #ifdef KJS_VERBOSE
1115         qCDebug(KHTML_LOG) << "DOMDocument::GetElementById looking for " << args[0]->toString(exec).qstring();
1116 #endif
1117         // create DOMStringImpl without copying
1118         DOMStringImpl shallowCopy(DOMStringImpl::ShallowCopy, (QChar *)str.data(), str.size());
1119         return getDOMNode(exec, doc.getElementById(DOMString(&shallowCopy)));
1120     }
1121 
1122     DOM::DOMString s = str.domString();
1123 
1124     switch (id) {
1125     case DOMDocument::CreateElement:
1126         return getDOMNode(exec, doc.createElement(s, exception));
1127     case DOMDocument::CreateDocumentFragment:
1128         return getDOMNode(exec, doc.createDocumentFragment());
1129     case DOMDocument::CreateTextNode:
1130         return getDOMNode(exec, doc.createTextNode(s.implementation()));
1131     case DOMDocument::CreateComment:
1132         return getDOMNode(exec, doc.createComment(s.implementation()));
1133     case DOMDocument::CreateCDATASection:
1134         return getDOMNode(exec, doc.createCDATASection(s.implementation(), exception));
1135     case DOMDocument::CreateProcessingInstruction:
1136         return getDOMNode(exec, doc.createProcessingInstruction(args[0]->toString(exec).domString(),
1137                           args[1]->toString(exec).domString().implementation()));
1138     case DOMDocument::CreateAttribute:
1139         return getDOMNode(exec, doc.createAttribute(s, exception));
1140     case DOMDocument::CreateEntityReference:
1141         return getDOMNode(exec, doc.createEntityReference(args[0]->toString(exec).domString(), exception));
1142     case DOMDocument::GetElementsByTagName:
1143         return getDOMNodeList(exec, doc.getElementsByTagName(s));
1144     case DOMDocument::ImportNode: // DOM2
1145         return getDOMNode(exec, doc.importNode(toNode(args[0]), args[1]->toBoolean(exec), exception));
1146     case DOMDocument::CreateElementNS: // DOM2
1147         return getDOMNode(exec, doc.createElementNS(valueToStringWithNullCheck(exec, args[0]), args[1]->toString(exec).domString(), exception));
1148     case DOMDocument::CreateAttributeNS: // DOM2
1149         return getDOMNode(exec, doc.createAttributeNS(valueToStringWithNullCheck(exec, args[0]), args[1]->toString(exec).domString(), exception));
1150     case DOMDocument::GetElementsByTagNameNS: // DOM2
1151         return getDOMNodeList(exec, doc.getElementsByTagNameNS(args[0]->toString(exec).domString(),
1152                               args[1]->toString(exec).domString()));
1153     case DOMDocument::CreateRange:
1154         return getDOMRange(exec, doc.createRange());
1155     case DOMDocument::CreateNodeIterator:
1156         return getDOMNodeIterator(exec,
1157                                   doc.createNodeIterator(toNode(args[0]),
1158                                           (long unsigned int)(args[1]->toNumber(exec)),
1159                                           toNodeFilter(args[2]), args[3]->toBoolean(exec), exception));
1160     case DOMDocument::CreateTreeWalker:
1161         return getDOMTreeWalker(exec, doc.createTreeWalker(toNode(args[0]), (long unsigned int)(args[1]->toNumber(exec)),
1162                                 toNodeFilter(args[2]), args[3]->toBoolean(exec), exception));
1163     case DOMDocument::CreateEvent:
1164         return getDOMEvent(exec, doc.createEvent(s, exception));
1165     case DOMDocument::GetOverrideStyle: {
1166         DOM::NodeImpl *arg0 = toNode(args[0]);
1167         if (!arg0 || !arg0->isElementNode()) {
1168             return jsUndefined();    // throw exception?
1169         } else {
1170             return getDOMCSSStyleDeclaration(exec, doc.getOverrideStyle(static_cast<DOM::ElementImpl *>(arg0), args[1]->toString(exec).domString().implementation()));
1171         }
1172     }
1173     case DOMDocument::Abort:
1174         doc.abort();
1175         break;
1176     case DOMDocument::Load: {
1177         Window *active = Window::retrieveActive(exec);
1178         // Complete the URL using the "active part" (running interpreter). We do this for the security
1179         // check and to make sure we load exactly the same url as we have verified to be safe
1180         KHTMLPart *khtmlpart = qobject_cast<KHTMLPart *>(active->part());
1181         if (khtmlpart) {
1182             // Security: only allow documents to be loaded from the same host
1183             QString dstUrl = khtmlpart->htmlDocument().completeURL(s).string();
1184             KParts::ReadOnlyPart *part = static_cast<KJS::ScriptInterpreter *>(exec->dynamicInterpreter())->part();
1185             if (part->url().host() == QUrl(dstUrl).host()) {
1186                 // qCDebug(KHTML_LOG) << "JavaScript: access granted for document.load() of " << dstUrl;
1187                 doc.load(dstUrl);
1188             } else {
1189                 // qCDebug(KHTML_LOG) << "JavaScript: access denied for document.load() of " << dstUrl;
1190             }
1191         }
1192         break;
1193     }
1194     case DOMDocument::LoadXML:
1195         doc.loadXML(s);
1196         break;
1197     case DOMDocument::ExecCommand: {
1198         return jsBoolean(doc.execCommand(args[0]->toString(exec).domString(), args[1]->toBoolean(exec), args[2]->toString(exec).domString()));
1199     }
1200     case DOMDocument::QueryCommandEnabled: {
1201         return jsBoolean(doc.queryCommandEnabled(args[0]->toString(exec).domString()));
1202     }
1203     case DOMDocument::QueryCommandIndeterm: {
1204         return jsBoolean(doc.queryCommandIndeterm(args[0]->toString(exec).domString()));
1205     }
1206     case DOMDocument::QueryCommandState: {
1207         return jsBoolean(doc.queryCommandState(args[0]->toString(exec).domString()));
1208     }
1209     case DOMDocument::QueryCommandSupported: {
1210         return jsBoolean(doc.queryCommandSupported(args[0]->toString(exec).domString()));
1211     }
1212     case DOMDocument::QueryCommandValue: {
1213         DOM::DOMString commandValue(doc.queryCommandValue(args[0]->toString(exec).domString()));
1214         // Method returns null DOMString to signal command is unsupported.
1215         // Microsoft documentation for this method says:
1216         // "If not supported [for a command identifier], this method returns a Boolean set to false."
1217         if (commandValue.isNull()) {
1218             return jsBoolean(false);
1219         } else {
1220             return jsString(commandValue);
1221         }
1222     }
1223     case DOMDocument::GetElementsByClassName:
1224         return getDOMNodeList(exec, doc.getElementsByClassName(s));
1225     case DOMDocument::QuerySelector: {
1226         RefPtr<DOM::ElementImpl> e = doc.querySelector(s, exception);
1227         return getDOMNode(exec, e.get());
1228     }
1229     case DOMDocument::QuerySelectorAll: {
1230         RefPtr<DOM::NodeListImpl> l = doc.querySelectorAll(s, exception);
1231         return getDOMNodeList(exec, l.get());
1232     }
1233     case DOMDocument::CreateExpression: {
1234         RefPtr<khtml::XPathNSResolverImpl> res = toResolver(exec, args[1]);
1235         RefPtr<khtml::XPathExpressionImpl> e = doc.createExpression(s, res.get(), exception);
1236         JSValue *wrapper = getWrapper<KJS::XPathExpression>(exec, e.get());
1237 
1238         // protect the resolver if needed
1239         if (!wrapper->isNull() && res && res->type() == khtml::XPathNSResolverImpl::JS) {
1240             static_cast<XPathExpression *>(wrapper)->setAssociatedResolver(static_cast<JSXPathNSResolver *>(res.get())->resolverObject());
1241         }
1242         return wrapper;
1243     }
1244     case DOMDocument::CreateNSResolver: {
1245         DOM::NodeImpl *node = toNode(args[0]);
1246         return getWrapper<KJS::XPathNSResolver>(exec, doc.createNSResolver(node));
1247     }
1248     case DOMDocument::Evaluate: {
1249         return getWrapper<KJS::XPathResult>(exec,
1250                                             doc.evaluate(s, // expression
1251                                                     toNode(args[1]), // contextNode,
1252                                                     toResolver(exec, args[2]), // resolver
1253                                                     args[3]->toInt32(exec), // type
1254                                                     nullptr, // result reuse, ignored
1255                                                     exception));
1256     }
1257     default:
1258         break;
1259     }
1260 
1261     return jsUndefined();
1262 }
1263 
1264 // -------------------------------------------------------------------------
1265 
1266 /* Source for DOMElementProtoTable.
1267 @begin DOMElementProtoTable 17
1268   getAttribute      DOMElement::GetAttribute    DontDelete|Function 1
1269   setAttribute      DOMElement::SetAttribute    DontDelete|Function 2
1270   removeAttribute   DOMElement::RemoveAttribute DontDelete|Function 1
1271   getAttributeNode  DOMElement::GetAttributeNode    DontDelete|Function 1
1272   setAttributeNode  DOMElement::SetAttributeNode    DontDelete|Function 2
1273   removeAttributeNode   DOMElement::RemoveAttributeNode DontDelete|Function 1
1274   getElementsByTagName  DOMElement::GetElementsByTagName    DontDelete|Function 1
1275   hasAttribute      DOMElement::HasAttribute    DontDelete|Function 1
1276   getAttributeNS    DOMElement::GetAttributeNS  DontDelete|Function 2
1277   setAttributeNS    DOMElement::SetAttributeNS  DontDelete|Function 3
1278   removeAttributeNS DOMElement::RemoveAttributeNS   DontDelete|Function 2
1279   getAttributeNodeNS    DOMElement::GetAttributeNodeNS  DontDelete|Function 2
1280   setAttributeNodeNS    DOMElement::SetAttributeNodeNS  DontDelete|Function 1
1281   getElementsByTagNameNS DOMElement::GetElementsByTagNameNS DontDelete|Function 2
1282   hasAttributeNS    DOMElement::HasAttributeNS  DontDelete|Function 2
1283   getElementsByClassName DOMElement::GetElementsByClassName   DontDelete|Function 1
1284 # Extensions
1285   blur          DOMElement::Blur    DontDelete|Function 0
1286   focus         DOMElement::Focus   DontDelete|Function 0
1287   querySelector          DOMElement::QuerySelector            DontDelete|Function 1
1288   querySelectorAll       DOMElement::QuerySelectorAll         DontDelete|Function 1
1289   getClientRects         DOMElement::GetClientRects           DontDelete|Function 0
1290   getBoundingClientRect  DOMElement::GetBoundingClientRect    DontDelete|Function 0
1291 @end
1292 */
1293 KJS_IMPLEMENT_PROTOFUNC(DOMElementProtoFunc)
1294 KJS_IMPLEMENT_PROTOTYPE("DOMElement", DOMElementProto, DOMElementProtoFunc, DOMNodeProto)
1295 
1296 IMPLEMENT_PSEUDO_CONSTRUCTOR(ElementPseudoCtor, "Element", DOMElementProto)
1297 
1298 const ClassInfo DOMElement::info = { "Element", &DOMNode::info, &DOMElementTable, nullptr };
1299 /* Source for DOMElementTable.
1300 @begin DOMElementTable 7
1301   tagName       DOMElement::TagName                 DontDelete|ReadOnly
1302   style         DOMElement::Style                   DontDelete|ReadOnly
1303 # DOM 3 - ElementTraversal interface
1304   firstElementChild DOMElement::FirstElementChild       DontDelete|ReadOnly
1305   lastElementChild  DOMElement::LastElementChild        DontDelete|ReadOnly
1306   previousElementSibling DOMElement::PreviousElementSibling DontDelete|ReadOnly
1307   nextElementSibling    DOMElement::NextElementSibling      DontDelete|ReadOnly
1308   childElementCount DOMElement::ChildElementCount       DontDelete|ReadOnly
1309 @end
1310 */
1311 DOMElement::DOMElement(ExecState *exec, DOM::ElementImpl *e)
1312     : DOMNode(exec, e)
1313 {
1314     setPrototype(DOMElementProto::self(exec));
1315 }
1316 
1317 DOMElement::DOMElement(JSObject *proto, DOM::ElementImpl *e)
1318     : DOMNode(proto, e)
1319 {}
1320 
1321 JSValue *DOMElement::getValueProperty(ExecState *exec, int token) const
1322 {
1323     DOM::ElementImpl &element = static_cast<DOM::ElementImpl &>(*m_impl);
1324     switch (token) {
1325     case TagName:
1326         return jsString(element.tagName());
1327     case Style:
1328         return getDOMCSSStyleDeclaration(exec, element.getInlineStyleDecls());
1329     case FirstElementChild:
1330         return getDOMNode(exec, element.firstElementChild());
1331     case LastElementChild:
1332         return getDOMNode(exec, element.lastElementChild());
1333     case PreviousElementSibling:
1334         return getDOMNode(exec, element.previousElementSibling());
1335     case NextElementSibling:
1336         return getDOMNode(exec, element.nextElementSibling());
1337     case ChildElementCount:
1338         return jsNumber((unsigned int)element.childElementCount());
1339     default:
1340         // qCDebug(KHTML_LOG) << "WARNING: Unhandled token in DOMElement::getValueProperty : " << token;
1341         return jsUndefined();
1342     }
1343 }
1344 
1345 bool DOMElement::getOwnPropertySlot(ExecState *exec, const Identifier &propertyName, PropertySlot &slot)
1346 {
1347 #ifdef KJS_VERBOSE
1348     qCDebug(KHTML_LOG) << "DOMElement::getOwnPropertySlot " << propertyName.qstring();
1349 #endif
1350 
1351     //DOM::Element element = static_cast<DOM::Element>(node);
1352     if (getStaticOwnValueSlot(&DOMElementTable, this, propertyName, slot)) {
1353         return true;
1354     }
1355 
1356     return DOMNode::getOwnPropertySlot(exec, propertyName, slot);
1357 }
1358 
1359 JSValue *DOMElementProtoFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
1360 {
1361     KJS_CHECK_THIS(KJS::DOMNode, thisObj);   // node should be enough here, given the cast
1362     DOMExceptionTranslator exception(exec);
1363     DOM::NodeImpl    &node    = *static_cast<DOMNode *>(thisObj)->impl();
1364     DOM::ElementImpl &element = static_cast<DOM::ElementImpl &>(node);
1365 
1366     switch (id) {
1367     case DOMElement::GetAttribute:
1368         /** In theory, we should not return null here, as per DOM. In practice, that
1369          breaks websites */
1370         return getStringOrNull(element.getAttribute(args[0]->toString(exec).domString()));
1371     case DOMElement::SetAttribute:
1372         element.setAttribute(args[0]->toString(exec).domString(), args[1]->toString(exec).domString(), exception);
1373         return jsUndefined();
1374     case DOMElement::RemoveAttribute:
1375         element.removeAttribute(args[0]->toString(exec).domString(), exception);
1376         return jsUndefined();
1377     case DOMElement::GetAttributeNode:
1378         return getDOMNode(exec, element.getAttributeNode(args[0]->toString(exec).domString()));
1379     case DOMElement::SetAttributeNode: {
1380         DOM::Attr ret = element.setAttributeNode(KJS::toAttr(args[0]), exception);
1381         return getDOMNode(exec, ret.handle());
1382     }
1383     case DOMElement::RemoveAttributeNode: {
1384         DOM::Attr ret = element.removeAttributeNode(KJS::toAttr(args[0]), exception);
1385         return getDOMNode(exec, ret.handle());
1386     }
1387     case DOMElement::GetElementsByTagName:
1388         return getDOMNodeList(exec, element.getElementsByTagName(args[0]->toString(exec).domString()));
1389     case DOMElement::HasAttribute: // DOM2
1390         return jsBoolean(element.hasAttribute(args[0]->toString(exec).domString()));
1391     case DOMElement::GetAttributeNS: // DOM2
1392         return jsString(element.getAttributeNS(args[0]->toString(exec).domString(), args[1]->toString(exec).domString(), exception));
1393     case DOMElement::SetAttributeNS: // DOM2
1394         element.setAttributeNS(args[0]->toString(exec).domString(), args[1]->toString(exec).domString(), args[2]->toString(exec).domString(), exception);
1395         return jsUndefined();
1396     case DOMElement::RemoveAttributeNS: // DOM2
1397         element.removeAttributeNS(args[0]->toString(exec).domString(), args[1]->toString(exec).domString(), exception);
1398         return jsUndefined();
1399     case DOMElement::GetAttributeNodeNS: // DOM2
1400         return getDOMNode(exec, element.getAttributeNodeNS(args[0]->toString(exec).domString(), args[1]->toString(exec).domString(), exception));
1401     case DOMElement::SetAttributeNodeNS: {
1402         DOM::Attr toRet = element.setAttributeNodeNS(KJS::toAttr(args[0]), exception);
1403         return getDOMNode(exec, toRet.handle());
1404     }
1405     case DOMElement::GetElementsByTagNameNS: // DOM2
1406         return getDOMNodeList(exec, element.getElementsByTagNameNS(args[0]->toString(exec).domString(), args[1]->toString(exec).domString()));
1407     case DOMElement::HasAttributeNS: // DOM2
1408         return jsBoolean(element.hasAttributeNS(args[0]->toString(exec).domString(), args[1]->toString(exec).domString()));
1409     case DOMElement::GetElementsByClassName: // HTML 5
1410         return getDOMNodeList(exec, element.getElementsByClassName(args[0]->toString(exec).domString()));
1411     case DOMElement::QuerySelector: { // WA Selectors 1
1412         RefPtr<DOM::ElementImpl> e = element.querySelector(args[0]->toString(exec).domString(), exception);
1413         return getDOMNode(exec, e.get());
1414     }
1415     case DOMElement::QuerySelectorAll: {  // WA Selectors 1
1416         RefPtr<DOM::NodeListImpl> l = element.querySelectorAll(args[0]->toString(exec).domString(), exception);
1417         return getDOMNodeList(exec, l.get());
1418     }
1419     case DOMElement::GetClientRects: {
1420         DOM::DocumentImpl *docimpl = node.document();
1421         if (docimpl) {
1422             docimpl->updateLayout();
1423         }
1424 
1425         khtml::RenderObject *rend = node.renderer();
1426 
1427         if (!rend) {
1428             return new ClientRectList(exec);
1429         }
1430 
1431         //In quirks mode, may need to forward it to body.
1432         rend = handleBodyRootQuirk(static_cast<DOMNode *>(thisObj)->impl(), rend, DOMNode::ClientTop);
1433 
1434         return new ClientRectList(exec, rend->getClientRects());
1435     }
1436     case DOMElement::GetBoundingClientRect: {
1437         DOM::DocumentImpl *docimpl = node.document();
1438         if (docimpl) {
1439             docimpl->updateLayout();
1440         }
1441 
1442         khtml::RenderObject *rend = node.renderer();
1443 
1444         //In quirks mode, may need to forward it to body.
1445         rend = handleBodyRootQuirk(static_cast<DOMNode *>(thisObj)->impl(), rend, DOMNode::ClientTop);
1446 
1447         if (!rend) {
1448             return new ClientRect(exec, 0, 0, 0, 0);
1449         }
1450 
1451         QList<QRectF> list = rend->getClientRects();
1452         if (list.isEmpty()) {
1453             return new ClientRect(exec, 0, 0, 0, 0);
1454         } else {
1455             QRectF rect = list.first();
1456             for (int i = 1; i < list.length(); ++i) {
1457                 rect = rect.united(list.at(i));
1458             }
1459             return new ClientRect(exec, rect);
1460         }
1461     }
1462 
1463     default:
1464 
1465         // Make sure our layout is up to date before we call these
1466         DOM::DocumentImpl *docimpl = element.document();
1467         if (docimpl) {
1468             docimpl->updateLayout();
1469         }
1470         switch (id) {
1471         case DOMElement::Focus:
1472             element.focus();
1473             return jsUndefined();
1474         case DOMElement::Blur:
1475             element.blur();
1476             return jsUndefined();
1477         default:
1478             return jsUndefined();
1479         }
1480     }
1481 }
1482 
1483 DOM::ElementImpl *KJS::toElement(JSValue *v)
1484 {
1485     DOM::NodeImpl *node = toNode(v);
1486     if (node && node->isElementNode()) {
1487         return static_cast<DOM::ElementImpl *>(node);
1488     }
1489     return nullptr;
1490 }
1491 
1492 DOM::AttrImpl *KJS::toAttr(JSValue *v)
1493 {
1494     DOM::NodeImpl *node = toNode(v);
1495     if (node && node->isAttributeNode()) {
1496         return static_cast<DOM::AttrImpl *>(node);
1497     }
1498     return nullptr;
1499 }
1500 
1501 // -------------------------------------------------------------------------
1502 
1503 /* Source for DOMDOMImplementationProtoTable.
1504 @begin DOMDOMImplementationProtoTable 5
1505   hasFeature        DOMDOMImplementation::HasFeature        DontDelete|Function 2
1506   createCSSStyleSheet   DOMDOMImplementation::CreateCSSStyleSheet   DontDelete|Function 2
1507 # DOM2
1508   createDocumentType    DOMDOMImplementation::CreateDocumentType    DontDelete|Function 3
1509   createDocument    DOMDOMImplementation::CreateDocument        DontDelete|Function 3
1510   createHTMLDocument    DOMDOMImplementation::CreateHTMLDocument        DontDelete|Function 1
1511 @end
1512 */
1513 KJS_DEFINE_PROTOTYPE(DOMDOMImplementationProto)
1514 KJS_IMPLEMENT_PROTOFUNC(DOMDOMImplementationProtoFunc)
1515 KJS_IMPLEMENT_PROTOTYPE("DOMImplementation", DOMDOMImplementationProto, DOMDOMImplementationProtoFunc, ObjectPrototype)
1516 
1517 const ClassInfo DOMDOMImplementation::info = { "DOMImplementation", nullptr, nullptr, nullptr };
1518 
1519 DOMDOMImplementation::DOMDOMImplementation(ExecState *exec, DOM::DOMImplementationImpl *i)
1520     : DOMObject(DOMDOMImplementationProto::self(exec)), m_impl(i) { }
1521 
1522 DOMDOMImplementation::~DOMDOMImplementation()
1523 {
1524     ScriptInterpreter::forgetDOMObject(m_impl.get());
1525 }
1526 
1527 JSValue *DOMDOMImplementationProtoFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
1528 {
1529     KJS_CHECK_THIS(KJS::DOMDOMImplementation, thisObj);
1530     DOM::DOMImplementationImpl &implementation = *static_cast<DOMDOMImplementation *>(thisObj)->impl();
1531     DOMExceptionTranslator exception(exec);
1532 
1533     switch (id) {
1534     case DOMDOMImplementation::HasFeature:
1535         return jsBoolean(implementation.hasFeature(args[0]->toString(exec).domString(),
1536                          valueToStringWithNullCheck(exec, args[1])));
1537     case DOMDOMImplementation::CreateDocumentType: // DOM2
1538         return getDOMNode(exec, implementation.createDocumentType(args[0]->toString(exec).domString(), args[1]->toString(exec).domString(), args[2]->toString(exec).domString(), exception));
1539     case DOMDOMImplementation::CreateDocument: { // DOM2
1540         // Initially set the URL to document of the creator... this is so that it resides in the same
1541         // host/domain for security checks. The URL will be updated if Document.load() is called.
1542         KHTMLPart *part = qobject_cast<KHTMLPart *>(static_cast<KJS::ScriptInterpreter *>(exec->dynamicInterpreter())->part());
1543         if (part) {
1544             //### this should probably be pushed to the impl
1545             DOM::NodeImpl *supposedDocType = toNode(args[2]);
1546             if (supposedDocType && supposedDocType->nodeType() != DOM::Node::DOCUMENT_TYPE_NODE) {
1547                 setDOMException(exec, DOMException::NOT_FOUND_ERR);
1548                 return jsNull();
1549             }
1550 
1551             DOM::DocumentTypeImpl *docType = static_cast<DOM::DocumentTypeImpl *>(supposedDocType);
1552 
1553             // ### no real leak but lifetime of part is not tied to document
1554             KHTMLPart *newPart = new KHTMLPart(part->view(), part);
1555             DOM::DocumentImpl *doc = implementation.createDocument(valueToStringWithNullCheck(exec, args[0]),
1556                                      valueToStringWithNullCheck(exec, args[1]),
1557                                      docType,
1558                                      newPart->view(),
1559                                      exception);
1560             if (!doc) {
1561                 return jsNull();
1562             }
1563             QUrl url = static_cast<DocumentImpl *>(part->document().handle())->URL();
1564             doc->setURL(url.url());
1565             return getDOMNode(exec, doc);
1566         }
1567         break;
1568     }
1569     case DOMDOMImplementation::CreateCSSStyleSheet: // DOM2
1570         return getDOMStyleSheet(exec, implementation.createCSSStyleSheet(
1571                                     args[0]->toString(exec).domString().implementation(),
1572                                     args[1]->toString(exec).domString().implementation(), exception));
1573     case DOMDOMImplementation::CreateHTMLDocument: // DOM2-HTML
1574         return getDOMNode(exec, implementation.createHTMLDocument(args[0]->toString(exec).domString()));
1575     default:
1576         break;
1577     }
1578     return jsUndefined();
1579 }
1580 
1581 // -------------------------------------------------------------------------
1582 
1583 const ClassInfo DOMDocumentType::info = { "DocumentType", &DOMNode::info, &DOMDocumentTypeTable, nullptr };
1584 
1585 /* Source for DOMDocumentTypeTable.
1586 @begin DOMDocumentTypeTable 6
1587   name          DOMDocumentType::Name       DontDelete|ReadOnly
1588   entities      DOMDocumentType::Entities   DontDelete|ReadOnly
1589   notations     DOMDocumentType::Notations  DontDelete|ReadOnly
1590 # DOM2
1591   publicId      DOMDocumentType::PublicId   DontDelete|ReadOnly
1592   systemId      DOMDocumentType::SystemId   DontDelete|ReadOnly
1593   internalSubset    DOMDocumentType::InternalSubset DontDelete|ReadOnly
1594 @end
1595 */
1596 DOMDocumentType::DOMDocumentType(ExecState *exec, DOM::DocumentTypeImpl *dt)
1597     : DOMNode(/*### no proto yet*/exec, dt) { }
1598 
1599 bool DOMDocumentType::getOwnPropertySlot(ExecState *exec, const Identifier &propertyName, KJS::PropertySlot &slot)
1600 {
1601 #ifdef KJS_VERBOSE
1602     qCDebug(KHTML_LOG) << "DOMDocumentType::getOwnPropertySlot " << propertyName.qstring();
1603 #endif
1604     return getStaticValueSlot<DOMDocumentType, DOMNode>(exec, &DOMDocumentTypeTable, this, propertyName, slot);
1605 }
1606 
1607 JSValue *DOMDocumentType::getValueProperty(ExecState *exec, int token) const
1608 {
1609     DOM::DocumentTypeImpl &type = static_cast<DOM::DocumentTypeImpl &>(*m_impl);
1610     switch (token) {
1611     case Name:
1612         return jsString(type.name());
1613     case Entities:
1614         return getDOMNamedNodeMap(exec, type.entities());
1615     case Notations:
1616         return getDOMNamedNodeMap(exec, type.notations());
1617     case PublicId: // DOM2
1618         return jsString(type.publicId());
1619     case SystemId: // DOM2
1620         return jsString(type.systemId());
1621     case InternalSubset: // DOM2
1622         return ::getStringOrNull(type.internalSubset()); // can be null, see domts/level2/core/internalSubset01.html
1623     default:
1624         // qCDebug(KHTML_LOG) << "WARNING: DOMDocumentType::getValueProperty unhandled token " << token;
1625         return jsNull();
1626     }
1627 }
1628 
1629 // -------------------------------------------------------------------------
1630 
1631 /* Source for DOMNamedNodeMapProtoTable.
1632 @begin DOMNamedNodeMapProtoTable 7
1633   getNamedItem      DOMNamedNodeMap::GetNamedItem       DontDelete|Function 1
1634   setNamedItem      DOMNamedNodeMap::SetNamedItem       DontDelete|Function 1
1635   removeNamedItem   DOMNamedNodeMap::RemoveNamedItem    DontDelete|Function 1
1636   item          DOMNamedNodeMap::Item           DontDelete|Function 1
1637 # DOM2
1638   getNamedItemNS    DOMNamedNodeMap::GetNamedItemNS     DontDelete|Function 2
1639   setNamedItemNS    DOMNamedNodeMap::SetNamedItemNS     DontDelete|Function 1
1640   removeNamedItemNS DOMNamedNodeMap::RemoveNamedItemNS  DontDelete|Function 2
1641 @end
1642 @begin DOMNamedNodeMapTable 7
1643   length        DOMNamedNodeMap::Length         DontDelete|Function 1
1644 @end
1645 */
1646 KJS_DEFINE_PROTOTYPE(DOMNamedNodeMapProto)
1647 KJS_IMPLEMENT_PROTOFUNC(DOMNamedNodeMapProtoFunc)
1648 KJS_IMPLEMENT_PROTOTYPE("NamedNodeMap", DOMNamedNodeMapProto, DOMNamedNodeMapProtoFunc, ObjectPrototype)
1649 
1650 const ClassInfo DOMNamedNodeMap::info = { "NamedNodeMap", nullptr, &DOMNamedNodeMapTable, nullptr };
1651 
1652 DOMNamedNodeMap::DOMNamedNodeMap(ExecState *exec, DOM::NamedNodeMapImpl *m)
1653     : DOMObject(DOMNamedNodeMapProto::self(exec)), m_impl(m) { }
1654 
1655 DOMNamedNodeMap::~DOMNamedNodeMap()
1656 {
1657     ScriptInterpreter::forgetDOMObject(m_impl.get());
1658 }
1659 
1660 JSValue *DOMNamedNodeMap::indexGetter(ExecState *exec, unsigned index)
1661 {
1662     return getDOMNode(exec, m_impl->item(index));
1663 }
1664 
1665 JSValue *DOMNamedNodeMap::lengthGetter(ExecState *, JSObject *, const Identifier &, const PropertySlot &slot)
1666 {
1667     DOMNamedNodeMap *thisObj = static_cast<DOMNamedNodeMap *>(slot.slotBase());
1668     return jsNumber(thisObj->m_impl->length());
1669 }
1670 
1671 bool DOMNamedNodeMap::getOwnPropertySlot(ExecState *exec, const Identifier &propertyName, PropertySlot &slot)
1672 {
1673     if (propertyName == exec->propertyNames().length) {
1674         slot.setCustom(this, lengthGetter);
1675         return true;
1676     }
1677 
1678     // See if it's an item name get
1679     DOM::NodeImpl *attr = impl()->getNamedItem(propertyName.ustring().domString());
1680     if (attr) {
1681         return getImmediateValueSlot(this, getDOMNode(exec, attr), slot);
1682     }
1683 
1684     //May be it's an index?
1685     if (getIndexSlot(this, *m_impl, propertyName, slot)) {
1686         return true;
1687     }
1688 
1689     return DOMObject::getOwnPropertySlot(exec, propertyName, slot);
1690 }
1691 
1692 JSValue *DOMNamedNodeMapProtoFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
1693 {
1694     KJS_CHECK_THIS(KJS::DOMNamedNodeMap, thisObj);
1695     DOMExceptionTranslator exception(exec);
1696     DOM::NamedNodeMapImpl &map = *static_cast<DOMNamedNodeMap *>(thisObj)->impl();
1697 
1698     switch (id) {
1699     case DOMNamedNodeMap::GetNamedItem:
1700         return getDOMNode(exec, map.getNamedItem(args[0]->toString(exec).domString()));
1701     case DOMNamedNodeMap::SetNamedItem: {
1702         DOM::Node old = map.setNamedItem(toNode(args[0]), exception);
1703         return getDOMNode(exec, old.handle());
1704     }
1705     case DOMNamedNodeMap::RemoveNamedItem: {
1706         DOM::Attr toRet = map.removeNamedItem(args[0]->toString(exec).domString(), exception);
1707         return getDOMNode(exec, toRet.handle());
1708     }
1709     case DOMNamedNodeMap::Item:
1710         return getDOMNode(exec, map.item(args[0]->toInt32(exec)));
1711     case DOMNamedNodeMap::GetNamedItemNS: {// DOM2
1712         DOM::Node old = map.getNamedItemNS(args[0]->toString(exec).domString(), args[1]->toString(exec).domString());
1713         return getDOMNode(exec, old.handle());
1714     }
1715     case DOMNamedNodeMap::SetNamedItemNS: {// DOM2
1716         DOM::Node old = map.setNamedItemNS(toNode(args[0]), exception);
1717         return getDOMNode(exec, old.handle());
1718     }
1719     case DOMNamedNodeMap::RemoveNamedItemNS: { // DOM2
1720         DOM::Node old = map.removeNamedItemNS(args[0]->toString(exec).domString(), args[1]->toString(exec).domString(), exception);
1721         return getDOMNode(exec, old.handle());
1722     }
1723     default:
1724         break;
1725     }
1726 
1727     return jsUndefined();
1728 }
1729 
1730 // -------------------------------------------------------------------------
1731 //### FIXME: proto
1732 const ClassInfo DOMProcessingInstruction::info = { "ProcessingInstruction", &DOMNode::info, &DOMProcessingInstructionTable, nullptr };
1733 
1734 /* Source for DOMProcessingInstructionTable.
1735 @begin DOMProcessingInstructionTable 3
1736   target    DOMProcessingInstruction::Target    DontDelete|ReadOnly
1737   data      DOMProcessingInstruction::Data      DontDelete
1738   sheet     DOMProcessingInstruction::Sheet     DontDelete|ReadOnly
1739 @end
1740 */
1741 bool DOMProcessingInstruction::getOwnPropertySlot(ExecState *exec, const Identifier &propertyName, PropertySlot &slot)
1742 {
1743     return getStaticValueSlot<DOMProcessingInstruction, DOMNode>(exec, &DOMProcessingInstructionTable, this, propertyName, slot);
1744 }
1745 
1746 JSValue *DOMProcessingInstruction::getValueProperty(ExecState *exec, int token) const
1747 {
1748     DOM::ProcessingInstructionImpl &pi = *static_cast<DOM::ProcessingInstructionImpl *>(m_impl.get());
1749     switch (token) {
1750     case Target:
1751         return jsString(pi.target());
1752     case Data:
1753         return jsString(pi.data());
1754     case Sheet:
1755         return getDOMStyleSheet(exec, pi.sheet());
1756     default:
1757         // qCDebug(KHTML_LOG) << "WARNING: DOMProcessingInstruction::getValueProperty unhandled token " << token;
1758         return jsNull();
1759     }
1760 }
1761 
1762 void DOMProcessingInstruction::put(ExecState *exec, const Identifier &propertyName, JSValue *value, int attr)
1763 {
1764     DOM::ProcessingInstructionImpl &pi = *static_cast<DOM::ProcessingInstructionImpl *>(m_impl.get());
1765     // Not worth using the hashtable for this one ;)
1766     if (propertyName == "data") {
1767         DOMExceptionTranslator exception(exec);
1768         pi.setData(value->toString(exec).domString(), exception);
1769     } else {
1770         DOMNode::put(exec, propertyName, value, attr);
1771     }
1772 }
1773 
1774 // -------------------------------------------------------------------------
1775 
1776 const ClassInfo DOMNotation::info = { "Notation", &DOMNode::info, &DOMNotationTable, nullptr };
1777 
1778 /* Source for DOMNotationTable.
1779 @begin DOMNotationTable 2
1780   publicId      DOMNotation::PublicId   DontDelete|ReadOnly
1781   systemId      DOMNotation::SystemId   DontDelete|ReadOnly
1782 @end
1783 */
1784 bool DOMNotation::getOwnPropertySlot(ExecState *exec, const Identifier &propertyName, PropertySlot &slot)
1785 {
1786     return getStaticValueSlot<DOMNotation, DOMNode>(exec, &DOMNotationTable, this, propertyName, slot);
1787 }
1788 
1789 JSValue *DOMNotation::getValueProperty(ExecState *, int token) const
1790 {
1791     DOM::NotationImpl &nota = *static_cast<DOM::NotationImpl *>(m_impl.get());
1792     switch (token) {
1793     case PublicId:
1794         return jsString(nota.publicId());
1795     case SystemId:
1796         return jsString(nota.systemId());
1797     default:
1798         // qCDebug(KHTML_LOG) << "WARNING: DOMNotation::getValueProperty unhandled token " << token;
1799         return jsNull();
1800     }
1801 }
1802 
1803 // -------------------------------------------------------------------------
1804 
1805 const ClassInfo DOMEntity::info = { "Entity", &DOMNode::info, nullptr, nullptr };
1806 
1807 /* Source for DOMEntityTable.
1808 @begin DOMEntityTable 2
1809   publicId      DOMEntity::PublicId     DontDelete|ReadOnly
1810   systemId      DOMEntity::SystemId     DontDelete|ReadOnly
1811   notationName      DOMEntity::NotationName DontDelete|ReadOnly
1812 @end
1813 */
1814 bool DOMEntity::getOwnPropertySlot(ExecState *exec, const Identifier &propertyName, PropertySlot &slot)
1815 {
1816     return getStaticValueSlot<DOMEntity, DOMNode>(exec, &DOMEntityTable, this, propertyName, slot);
1817 }
1818 
1819 JSValue *DOMEntity::getValueProperty(ExecState *, int token) const
1820 {
1821     DOM::EntityImpl &entity = *static_cast<DOM::EntityImpl *>(m_impl.get());
1822     switch (token) {
1823     case PublicId:
1824         return jsString(entity.publicId());
1825     case SystemId:
1826         return jsString(entity.systemId());
1827     case NotationName:
1828         return jsString(entity.notationName());
1829     default:
1830         // qCDebug(KHTML_LOG) << "WARNING: DOMEntity::getValueProperty unhandled token " << token;
1831         return jsNull();
1832     }
1833 }
1834 
1835 // -------------------------------------------------------------------------
1836 
1837 bool KJS::checkNodeSecurity(ExecState *exec, const DOM::NodeImpl *n)
1838 {
1839     // Check to see if the currently executing interpreter is allowed to access the specified node
1840     if (!n) {
1841         return true;
1842     }
1843     KHTMLPart *part = n->document()->part();
1844     Window *win = part ? Window::retrieveWindow(part) : nullptr;
1845     if (!win || !win->isSafeScript(exec)) {
1846         return false;
1847     }
1848     return true;
1849 }
1850 
1851 // adopted from binding/JSHTMLElementFactory.cpp
1852 #define CREATE_WRAPPER_FUNCTION(name) \
1853     static DOMObject* create##name##Wrapper(ExecState* exec, DOM::NodeImpl* n) \
1854     { \
1855         return new JSHTML##name##Element(exec, static_cast<HTML##name##Element*>(n)); \
1856     }
1857 
1858 CREATE_WRAPPER_FUNCTION(Audio)
1859 CREATE_WRAPPER_FUNCTION(Video)
1860 
1861 JSValue *KJS::getEventTarget(ExecState *exec, DOM::EventTargetImpl *t)
1862 {
1863     if (!t) {
1864         return jsNull();
1865     }
1866     if (t->eventTargetType() == EventTargetImpl::DOM_NODE) {
1867         return getDOMNode(exec, static_cast<DOM::NodeImpl *>(t));
1868     } else if (t->eventTargetType() == EventTargetImpl::WINDOW) {
1869         Window *w = static_cast<WindowEventTargetImpl *>(t)->window();
1870         return w ? w : jsNull();
1871     } else {
1872         return static_cast<XMLHttpRequest *>(t);
1873     }
1874 }
1875 
1876 JSValue *KJS::getDOMNode(ExecState *exec, DOM::NodeImpl *n)
1877 {
1878     DOMObject *ret = nullptr;
1879     if (!n) {
1880         return jsNull();
1881     }
1882     ScriptInterpreter *interp = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter());
1883     if ((ret = interp->getDOMObject(n))) {
1884         return ret;
1885     }
1886 
1887     switch (n->nodeType()) {
1888     case DOM::Node::ELEMENT_NODE:
1889         switch (n->id()) {
1890         case ID_AUDIO:
1891             ret = createAudioWrapper(exec, n);
1892             break;
1893         case ID_VIDEO:
1894             ret = createVideoWrapper(exec, n);
1895             break;
1896         default:
1897             if (static_cast<DOM::ElementImpl *>(n)->isHTMLElement()) {
1898                 ret = new HTMLElement(exec, static_cast<DOM::HTMLElementImpl *>(n));
1899             } else {
1900                 ret = new DOMElement(exec, static_cast<DOM::ElementImpl *>(n));
1901             }
1902             break;
1903         }
1904         break;
1905     case DOM::Node::ATTRIBUTE_NODE:
1906         ret = new DOMAttr(exec, static_cast<DOM::AttrImpl *>(n));
1907         break;
1908     case DOM::Node::TEXT_NODE:
1909     case DOM::Node::CDATA_SECTION_NODE:
1910         ret = new DOMText(exec, static_cast<DOM::TextImpl *>(n));
1911         break;
1912     case DOM::Node::ENTITY_REFERENCE_NODE:
1913         ret = new DOMNode(exec, n);
1914         break;
1915     case DOM::Node::ENTITY_NODE:
1916         ret = new DOMEntity(exec, static_cast<DOM::EntityImpl *>(n));
1917         break;
1918     case DOM::Node::PROCESSING_INSTRUCTION_NODE:
1919         ret = new DOMProcessingInstruction(exec, static_cast<DOM::ProcessingInstructionImpl *>(n));
1920         break;
1921     case DOM::Node::COMMENT_NODE:
1922         ret = new DOMComment(exec, static_cast<DOM::CommentImpl *>(n));
1923         break;
1924     case DOM::Node::DOCUMENT_NODE:
1925         if (static_cast<DOM::DocumentImpl *>(n)->isHTMLDocument()) {
1926             ret = new HTMLDocument(exec, static_cast<DOM::HTMLDocumentImpl *>(n));
1927         } else {
1928             ret = new DOMDocument(exec, static_cast<DOM::DocumentImpl *>(n));
1929         }
1930         break;
1931     case DOM::Node::DOCUMENT_TYPE_NODE:
1932         ret = new DOMDocumentType(exec, static_cast<DOM::DocumentTypeImpl *>(n));
1933         break;
1934     case DOM::Node::DOCUMENT_FRAGMENT_NODE:
1935         ret = new DOMDocumentFragment(exec, static_cast<DOM::DocumentFragmentImpl *>(n));
1936         break;
1937     case DOM::Node::NOTATION_NODE:
1938         ret = new DOMNotation(exec, static_cast<DOM::NotationImpl *>(n));
1939         break;
1940     default:
1941         ret = new DOMNode(exec, n);
1942     }
1943     interp->putDOMObject(n, ret);
1944 
1945     return ret;
1946 }
1947 
1948 JSValue *KJS::getDOMNamedNodeMap(ExecState *exec, DOM::NamedNodeMapImpl *m)
1949 {
1950     return cacheDOMObject<DOM::NamedNodeMapImpl, KJS::DOMNamedNodeMap>(exec, m);
1951 }
1952 
1953 JSValue *KJS::getDOMNodeList(ExecState *exec, DOM::NodeListImpl *l)
1954 {
1955     return cacheDOMObject<DOM::NodeListImpl, KJS::DOMNodeList>(exec, l);
1956 }
1957 
1958 JSValue *KJS::getDOMDOMImplementation(ExecState *exec, DOM::DOMImplementationImpl *i)
1959 {
1960     return cacheDOMObject<DOM::DOMImplementationImpl, KJS::DOMDOMImplementation>(exec, i);
1961 }
1962 
1963 // -------------------------------------------------------------------------
1964 
1965 IMPLEMENT_PSEUDO_CONSTRUCTOR_WITH_PARENT(NodeConstructor, "NodeConstructor", DOMNodeProto, DOMNodeConstants)
1966 // -------------------------------------------------------------------------
1967 
1968 /* Source for DOMExceptionProtoTable.
1969 @begin DOMExceptionProtoTable 29
1970   INDEX_SIZE_ERR        DOM::DOMException::INDEX_SIZE_ERR       DontDelete|ReadOnly
1971   DOMSTRING_SIZE_ERR        DOM::DOMException::DOMSTRING_SIZE_ERR   DontDelete|ReadOnly
1972   HIERARCHY_REQUEST_ERR     DOM::DOMException::HIERARCHY_REQUEST_ERR    DontDelete|ReadOnly
1973   WRONG_DOCUMENT_ERR        DOM::DOMException::WRONG_DOCUMENT_ERR   DontDelete|ReadOnly
1974   INVALID_CHARACTER_ERR     DOM::DOMException::INVALID_CHARACTER_ERR    DontDelete|ReadOnly
1975   NO_DATA_ALLOWED_ERR       DOM::DOMException::NO_DATA_ALLOWED_ERR  DontDelete|ReadOnly
1976   NO_MODIFICATION_ALLOWED_ERR   DOM::DOMException::NO_MODIFICATION_ALLOWED_ERR  DontDelete|ReadOnly
1977   NOT_FOUND_ERR         DOM::DOMException::NOT_FOUND_ERR        DontDelete|ReadOnly
1978   NOT_SUPPORTED_ERR     DOM::DOMException::NOT_SUPPORTED_ERR    DontDelete|ReadOnly
1979   INUSE_ATTRIBUTE_ERR       DOM::DOMException::INUSE_ATTRIBUTE_ERR  DontDelete|ReadOnly
1980   INVALID_STATE_ERR     DOM::DOMException::INVALID_STATE_ERR    DontDelete|ReadOnly
1981   SYNTAX_ERR            DOM::DOMException::SYNTAX_ERR       DontDelete|ReadOnly
1982   INVALID_MODIFICATION_ERR  DOM::DOMException::INVALID_MODIFICATION_ERR DontDelete|ReadOnly
1983   NAMESPACE_ERR         DOM::DOMException::NAMESPACE_ERR        DontDelete|ReadOnly
1984   INVALID_ACCESS_ERR        DOM::DOMException::INVALID_ACCESS_ERR   DontDelete|ReadOnly
1985   VALIDATION_ERR               DOM::DOMException::VALIDATION_ERR      DontDelete|ReadOnly
1986   TYPE_MISMATCH_ERR            DOM::DOMException::TYPE_MISMATCH_ERR   DontDelete|ReadOnly
1987   SECURITY_ERR                 DOM::DOMException::SECURITY_ERR        DontDelete|ReadOnly
1988   NETWORK_ERR                  DOM::DOMException::NETWORK_ERR         DontDelete|ReadOnly
1989   ABORT_ERR                    DOM::DOMException::ABORT_ERR           DontDelete|ReadOnly
1990   URL_MISMATCH_ERR             DOM::DOMException::URL_MISMATCH_ERR    DontDelete|ReadOnly
1991   QUOTA_EXCEEDED_ERR           DOM::DOMException::QUOTA_EXCEEDED_ERR  DontDelete|ReadOnly
1992   TIMEOUT_ERR                  DOM::DOMException::TIMEOUT_ERR         DontDelete|ReadOnly
1993   NOT_READABLE_ERR             DOM::DOMException::NOT_READABLE_ERR    DontDelete|ReadOnly
1994   DATA_CLONE_ERR               DOM::DOMException::DATA_CLONE_ERR      DontDelete|ReadOnly
1995   ENCODING_ERR                 DOM::DOMException::ENCODING_ERR        DontDelete|ReadOnly
1996 @end
1997 */
1998 
1999 DEFINE_CONSTANT_TABLE(DOMExceptionProto)
2000 IMPLEMENT_CONSTANT_TABLE(DOMExceptionProto, "DOMException")
2001 
2002 IMPLEMENT_PSEUDO_CONSTRUCTOR_WITH_PARENT(DOMExceptionPseudoCtor,
2003         "DOMException",
2004         DOMExceptionProto, DOMExceptionProto)
2005 
2006 JSDOMException::JSDOMException(ExecState *exec)
2007     : DOMObject(DOMExceptionProto::self(exec))
2008 {
2009 }
2010 
2011 const ClassInfo JSDOMException::info = { "DOMException", nullptr, nullptr, nullptr };
2012 
2013 JSObject *KJS::getDOMExceptionConstructor(ExecState *exec)
2014 {
2015     return DOMExceptionPseudoCtor::self(exec);
2016 }
2017 
2018 // -------------------------------------------------------------------------
2019 
2020 /* Source for DOMNamedNodesCollection.
2021 @begin DOMNamedNodesCollectionTable 1
2022   length        KJS::DOMNamedNodesCollection::Length        DontDelete|ReadOnly
2023 @end
2024 */
2025 const ClassInfo KJS::DOMNamedNodesCollection::info = { "DOMNamedNodesCollection", nullptr, &DOMNamedNodesCollectionTable, nullptr };
2026 
2027 // Such a collection is usually very short-lived, it only exists
2028 // for constructs like document.forms.<name>[1],
2029 // so it shouldn't be a problem that it's storing all the nodes (with the same name). (David)
2030 DOMNamedNodesCollection::DOMNamedNodesCollection(ExecState *exec, const QList<SharedPtr<DOM::NodeImpl> > &nodes)
2031     : DOMObject(exec->lexicalInterpreter()->builtinObjectPrototype()),
2032       m_nodes(nodes)
2033 {
2034     // Maybe we should ref (and deref in the dtor) the nodes, though ?
2035 }
2036 
2037 JSValue *DOMNamedNodesCollection::indexGetter(ExecState *exec, unsigned index)
2038 {
2039     return getDOMNode(exec, m_nodes[index].get());
2040 }
2041 
2042 JSValue *DOMNamedNodesCollection::lengthGetter(ExecState *, JSObject *, const Identifier &, const PropertySlot &slot)
2043 {
2044     DOMNamedNodesCollection *thisObj = static_cast<DOMNamedNodesCollection *>(slot.slotBase());
2045     return jsNumber(thisObj->m_nodes.size());
2046 }
2047 
2048 bool DOMNamedNodesCollection::getOwnPropertySlot(ExecState *exec, const Identifier &propertyName, PropertySlot &slot)
2049 {
2050     // qCDebug(KHTML_LOG) << propertyName.ascii();
2051 
2052     if (propertyName == exec->propertyNames().length) {
2053         slot.setCustom(this, lengthGetter);
2054         return true;
2055     }
2056 
2057     //May be it's an index?
2058     if (getIndexSlot(this, m_nodes.size(), propertyName, slot)) {
2059         return true;
2060     }
2061 
2062     return DOMObject::getOwnPropertySlot(exec, propertyName, slot);
2063 }
2064 
2065 // -------------------------------------------------------------------------
2066 
2067 const ClassInfo DOMCharacterData::info = { "CharacterImp",
2068                                            &DOMNode::info, &DOMCharacterDataTable, nullptr
2069                                          };
2070 /*
2071 @begin DOMCharacterDataTable 2
2072   data      DOMCharacterData::Data      DontDelete
2073   length    DOMCharacterData::Length    DontDelete|ReadOnly
2074 @end
2075 @begin DOMCharacterDataProtoTable 7
2076   substringData DOMCharacterData::SubstringData DontDelete|Function 2
2077   appendData    DOMCharacterData::AppendData    DontDelete|Function 1
2078   insertData    DOMCharacterData::InsertData    DontDelete|Function 2
2079   deleteData    DOMCharacterData::DeleteData    DontDelete|Function 2
2080   replaceData   DOMCharacterData::ReplaceData   DontDelete|Function 2
2081 @end
2082 */
2083 KJS_DEFINE_PROTOTYPE(DOMCharacterDataProto)
2084 KJS_IMPLEMENT_PROTOFUNC(DOMCharacterDataProtoFunc)
2085 KJS_IMPLEMENT_PROTOTYPE("DOMCharacterData", DOMCharacterDataProto, DOMCharacterDataProtoFunc, DOMNodeProto)
2086 
2087 DOMCharacterData::DOMCharacterData(ExecState *exec, DOM::CharacterDataImpl *d)
2088     : DOMNode(exec, d)
2089 {
2090     setPrototype(DOMCharacterDataProto::self(exec));
2091 }
2092 
2093 bool DOMCharacterData::getOwnPropertySlot(ExecState *exec, const Identifier &propertyName, PropertySlot &slot)
2094 {
2095 #ifdef KJS_VERBOSE
2096     qCDebug(KHTML_LOG) << "DOMCharacterData::tryGet " << propertyName.qstring();
2097 #endif
2098     return getStaticValueSlot<DOMCharacterData, DOMNode>(exec, &DOMCharacterDataTable, this, propertyName, slot);
2099 }
2100 
2101 JSValue *DOMCharacterData::getValueProperty(ExecState *, int token) const
2102 {
2103     DOM::CharacterDataImpl &data = *impl();
2104     switch (token) {
2105     case Data:
2106         return jsString(data.data());
2107     case Length:
2108         return jsNumber(data.length());
2109     default:
2110         // qCDebug(KHTML_LOG) << "WARNING: Unhandled token in DOMCharacterData::getValueProperty : " << token;
2111         return jsNull();
2112     }
2113 }
2114 
2115 void DOMCharacterData::put(ExecState *exec, const Identifier &propertyName, JSValue *value, int attr)
2116 {
2117     if (propertyName == "data") {
2118         DOMExceptionTranslator exception(exec);
2119         impl()->setData(value->toString(exec).domString(), exception);
2120     } else {
2121         DOMNode::put(exec, propertyName, value, attr);
2122     }
2123 }
2124 
2125 JSValue *DOMCharacterDataProtoFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
2126 {
2127     KJS_CHECK_THIS(KJS::DOMCharacterData, thisObj);
2128     DOM::CharacterDataImpl &data = *static_cast<DOMCharacterData *>(thisObj)->impl();
2129     DOMExceptionTranslator exception(exec);
2130     switch (id) {
2131     case DOMCharacterData::SubstringData:
2132         return jsString(data.substringData(args[0]->toInteger(exec), args[1]->toInteger(exec), exception));
2133     case DOMCharacterData::AppendData:
2134         data.appendData(args[0]->toString(exec).domString(), exception);
2135         return jsUndefined();
2136         break;
2137     case DOMCharacterData::InsertData:
2138         data.insertData(args[0]->toInteger(exec), args[1]->toString(exec).domString(), exception);
2139         return  jsUndefined();
2140         break;
2141     case DOMCharacterData::DeleteData:
2142         data.deleteData(args[0]->toInteger(exec), args[1]->toInteger(exec), exception);
2143         return  jsUndefined();
2144         break;
2145     case DOMCharacterData::ReplaceData:
2146         data.replaceData(args[0]->toInteger(exec), args[1]->toInteger(exec), args[2]->toString(exec).domString(), exception);
2147         return jsUndefined();
2148     default:
2149         break;
2150     }
2151     return jsUndefined();
2152 }
2153 
2154 // -------------------------------------------------------------------------
2155 
2156 const ClassInfo DOMText::info = { "Text", &DOMCharacterData::info,
2157                                   &DOMTextTable, nullptr
2158                                 };
2159 
2160 /*
2161 @begin DOMTextTable 2
2162   wholeText        DOMText::WholeText        DontDelete|ReadOnly
2163 @end
2164 @begin DOMTextProtoTable 2
2165   splitText    DOMText::SplitText        DontDelete|Function 1
2166   replaceWholeText DOMText::ReplaceWholeText DontDelete|Function 1
2167 @end
2168 */
2169 KJS_DEFINE_PROTOTYPE(DOMTextProto)
2170 KJS_IMPLEMENT_PROTOFUNC(DOMTextProtoFunc)
2171 KJS_IMPLEMENT_PROTOTYPE("DOMText", DOMTextProto, DOMTextProtoFunc, DOMCharacterDataProto)
2172 
2173 DOMText::DOMText(ExecState *exec, DOM::TextImpl *t)
2174     : DOMCharacterData(exec, t)
2175 {
2176     setPrototype(DOMTextProto::self(exec));
2177 }
2178 
2179 bool DOMText::getOwnPropertySlot(ExecState *exec,
2180                                  const Identifier &propertyName,
2181                                  PropertySlot &slot)
2182 {
2183     return getStaticValueSlot<DOMText, DOMCharacterData>(exec, &DOMTextTable, this, propertyName, slot);
2184 }
2185 
2186 JSValue *DOMText::getValueProperty(ExecState *, int token) const
2187 {
2188     TextImpl *text = static_cast<TextImpl *>(impl());
2189     switch (token) {
2190     case WholeText:
2191         return jsString(text->wholeText());
2192     }
2193     return jsNull(); // not reached
2194 }
2195 
2196 JSValue *DOMTextProtoFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
2197 {
2198     KJS_CHECK_THIS(KJS::DOMText, thisObj);
2199     DOM::TextImpl &text = *static_cast<DOMText *>(thisObj)->impl();
2200     DOMExceptionTranslator exception(exec);
2201     switch (id) {
2202     case DOMText::SplitText:
2203         return getDOMNode(exec, text.splitText(args[0]->toInteger(exec), exception));
2204     case DOMText::ReplaceWholeText:
2205         return getDOMNode(exec, text.replaceWholeText(args[0]->toString(exec).domString(), exception));
2206     default:
2207         break;
2208     }
2209     return jsUndefined();
2210 }
2211 
2212 // -------------------------------------------------------------------------
2213 
2214 const ClassInfo DOMComment::info = { "Comment",
2215                                      &DOMCharacterData::info, nullptr, nullptr
2216                                    };
2217 /*
2218 @begin DOMCommentProtoTable 1
2219 @end
2220 */
2221 
2222 KJS_DEFINE_PROTOTYPE(DOMCommentProto)
2223 KJS_IMPLEMENT_PROTOFUNC(DOMCommentProtoFunc)
2224 KJS_IMPLEMENT_PROTOTYPE("DOMComment", DOMCommentProto, DOMCommentProtoFunc, DOMCharacterDataProto)
2225 
2226 DOMComment::DOMComment(ExecState *exec, DOM::CommentImpl *d)
2227     : DOMCharacterData(exec, d)
2228 {
2229     setPrototype(DOMCommentProto::self(exec));
2230 }
2231 
2232 JSValue *DOMCommentProtoFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List & /*args*/)
2233 {
2234     KJS_CHECK_THIS(KJS::DOMComment, thisObj);
2235     return jsUndefined();
2236 }
2237 
2238 // -------------------------------------------------------------------------
2239 
2240 const ClassInfo DOMDocumentFragment::info = { "DocumentFragment",
2241                                               &DOMNode::info, nullptr, nullptr
2242                                             };
2243 /*
2244 @begin DOMDocumentFragmentProtoTable 2
2245   querySelector          DOMDocumentFragment::QuerySelector            DontDelete|Function 1
2246   querySelectorAll       DOMDocumentFragment::QuerySelectorAll         DontDelete|Function 1
2247 @end
2248 */
2249 
2250 KJS_DEFINE_PROTOTYPE(DOMDocumentFragmentProto)
2251 KJS_IMPLEMENT_PROTOFUNC(DOMDocumentFragmentProtoFunc)
2252 KJS_IMPLEMENT_PROTOTYPE("DocumentFragment", DOMDocumentFragmentProto,
2253                         DOMDocumentFragmentProtoFunc, DOMNodeProto)
2254 IMPLEMENT_PSEUDO_CONSTRUCTOR(DocumentFragmentPseudoCtor, "DocumentFragment", DOMDocumentFragmentProto)
2255 
2256 DOMDocumentFragment::DOMDocumentFragment(ExecState *exec, DOM::DocumentFragmentImpl *i)
2257     : DOMNode(exec, i)
2258 {
2259     setPrototype(DOMDocumentFragmentProto::self(exec));
2260 }
2261 
2262 JSValue *DOMDocumentFragmentProtoFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
2263 {
2264     KJS_CHECK_THIS(KJS::DOMDocumentFragment, thisObj);
2265     DOMExceptionTranslator exception(exec);
2266 
2267     DOM::NodeImpl *n = static_cast<DOMDocumentFragment *>(thisObj)->impl();
2268     DOM::DOMString s = args[0]->toString(exec).domString();
2269 
2270     switch (id) {
2271     case DOMDocumentFragment::QuerySelector: {
2272         RefPtr<DOM::ElementImpl> e = n->querySelector(s, exception);
2273         return getDOMNode(exec, e.get());
2274     }
2275     case DOMDocumentFragment::QuerySelectorAll: {
2276         RefPtr<DOM::NodeListImpl> l = n->querySelectorAll(s, exception);
2277         return getDOMNodeList(exec, l.get());
2278     }
2279     }
2280     return jsUndefined();
2281 }
2282