Home | History | Annotate | Download | only in js
      1 /*
      2  * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "JSNode.h"
     28 
     29 #include "Attr.h"
     30 #include "CDATASection.h"
     31 #include "Comment.h"
     32 #include "Document.h"
     33 #include "DocumentFragment.h"
     34 #include "DocumentType.h"
     35 #include "Entity.h"
     36 #include "EntityReference.h"
     37 #include "HTMLElement.h"
     38 #include "JSAttr.h"
     39 #include "JSCDATASection.h"
     40 #include "JSComment.h"
     41 #include "JSDocument.h"
     42 #include "JSDocumentFragment.h"
     43 #include "JSDocumentType.h"
     44 #include "JSEntity.h"
     45 #include "JSEntityReference.h"
     46 #include "JSEventListener.h"
     47 #include "JSHTMLElement.h"
     48 #include "JSHTMLElementWrapperFactory.h"
     49 #include "JSNotation.h"
     50 #include "JSProcessingInstruction.h"
     51 #include "JSText.h"
     52 #include "Node.h"
     53 #include "Notation.h"
     54 #include "ProcessingInstruction.h"
     55 #include "RegisteredEventListener.h"
     56 #include "Text.h"
     57 #include <wtf/PassRefPtr.h>
     58 #include <wtf/RefPtr.h>
     59 
     60 #if ENABLE(SVG)
     61 #include "JSSVGElementWrapperFactory.h"
     62 #include "SVGElement.h"
     63 #endif
     64 
     65 using namespace JSC;
     66 
     67 namespace WebCore {
     68 
     69 typedef int ExpectionCode;
     70 
     71 JSValue JSNode::insertBefore(ExecState* exec, const ArgList& args)
     72 {
     73     ExceptionCode ec = 0;
     74     bool ok = impl()->insertBefore(toNode(args.at(0)), toNode(args.at(1)), ec, true);
     75     setDOMException(exec, ec);
     76     if (ok)
     77         return args.at(0);
     78     return jsNull();
     79 }
     80 
     81 JSValue JSNode::replaceChild(ExecState* exec, const ArgList& args)
     82 {
     83     ExceptionCode ec = 0;
     84     bool ok = impl()->replaceChild(toNode(args.at(0)), toNode(args.at(1)), ec, true);
     85     setDOMException(exec, ec);
     86     if (ok)
     87         return args.at(1);
     88     return jsNull();
     89 }
     90 
     91 JSValue JSNode::removeChild(ExecState* exec, const ArgList& args)
     92 {
     93     ExceptionCode ec = 0;
     94     bool ok = impl()->removeChild(toNode(args.at(0)), ec);
     95     setDOMException(exec, ec);
     96     if (ok)
     97         return args.at(0);
     98     return jsNull();
     99 }
    100 
    101 JSValue JSNode::appendChild(ExecState* exec, const ArgList& args)
    102 {
    103     ExceptionCode ec = 0;
    104     bool ok = impl()->appendChild(toNode(args.at(0)), ec, true);
    105     setDOMException(exec, ec);
    106     if (ok)
    107         return args.at(0);
    108     return jsNull();
    109 }
    110 
    111 JSValue JSNode::addEventListener(ExecState* exec, const ArgList& args)
    112 {
    113     JSValue listener = args.at(1);
    114     if (!listener.isObject())
    115         return jsUndefined();
    116 
    117     impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), this, false, currentWorld(exec)), args.at(2).toBoolean(exec));
    118     return jsUndefined();
    119 }
    120 
    121 JSValue JSNode::removeEventListener(ExecState* exec, const ArgList& args)
    122 {
    123     JSValue listener = args.at(1);
    124     if (!listener.isObject())
    125         return jsUndefined();
    126 
    127     impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), this, false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
    128     return jsUndefined();
    129 }
    130 
    131 void JSNode::pushEventHandlerScope(ExecState*, ScopeChain&) const
    132 {
    133 }
    134 
    135 void JSNode::markChildren(MarkStack& markStack)
    136 {
    137     Base::markChildren(markStack);
    138 
    139     Node* node = m_impl.get();
    140     node->markJSEventListeners(markStack);
    141 
    142     // Nodes in the document are kept alive by JSDocument::mark, so, if we're in
    143     // the document, we need to mark the document, but we don't need to explicitly
    144     // mark any other nodes.
    145     if (node->inDocument()) {
    146         if (Document* doc = node->ownerDocument())
    147             markDOMNodeWrapper(markStack, doc, doc);
    148         return;
    149     }
    150 
    151     // This is a node outside the document.
    152     // Find the the root, and the highest ancestor with a wrapper.
    153     Node* root = node;
    154     Node* outermostNodeWithWrapper = node;
    155     for (Node* current = m_impl.get(); current; current = current->parentNode()) {
    156         root = current;
    157         if (hasCachedDOMNodeWrapperUnchecked(current->document(), current))
    158             outermostNodeWithWrapper = current;
    159     }
    160 
    161     // Only nodes that have no ancestors with wrappers mark the subtree. In the common
    162     // case, the root of the detached subtree has a wrapper, so the tree will only
    163     // get marked once. Nodes that aren't outermost need to mark the outermost
    164     // in case it is otherwise unreachable.
    165     if (node != outermostNodeWithWrapper) {
    166         markDOMNodeWrapper(markStack, m_impl->document(), outermostNodeWithWrapper);
    167         return;
    168     }
    169 
    170     // Mark the whole tree subtree.
    171     for (Node* nodeToMark = root; nodeToMark; nodeToMark = nodeToMark->traverseNextNode())
    172         markDOMNodeWrapper(markStack, m_impl->document(), nodeToMark);
    173 }
    174 
    175 static ALWAYS_INLINE JSValue createWrapper(ExecState* exec, JSDOMGlobalObject* globalObject, Node* node)
    176 {
    177     ASSERT(node);
    178     ASSERT(!getCachedDOMNodeWrapper(exec, node->document(), node));
    179 
    180     JSNode* wrapper;
    181     switch (node->nodeType()) {
    182         case Node::ELEMENT_NODE:
    183             if (node->isHTMLElement())
    184                 wrapper = createJSHTMLWrapper(exec, globalObject, static_cast<HTMLElement*>(node));
    185 #if ENABLE(SVG)
    186             else if (node->isSVGElement())
    187                 wrapper = createJSSVGWrapper(exec, globalObject, static_cast<SVGElement*>(node));
    188 #endif
    189             else
    190                 wrapper = CREATE_DOM_NODE_WRAPPER(exec, globalObject, Element, node);
    191             break;
    192         case Node::ATTRIBUTE_NODE:
    193             wrapper = CREATE_DOM_NODE_WRAPPER(exec, globalObject, Attr, node);
    194             break;
    195         case Node::TEXT_NODE:
    196             wrapper = CREATE_DOM_NODE_WRAPPER(exec, globalObject, Text, node);
    197             break;
    198         case Node::CDATA_SECTION_NODE:
    199             wrapper = CREATE_DOM_NODE_WRAPPER(exec, globalObject, CDATASection, node);
    200             break;
    201         case Node::ENTITY_NODE:
    202             wrapper = CREATE_DOM_NODE_WRAPPER(exec, globalObject, Entity, node);
    203             break;
    204         case Node::PROCESSING_INSTRUCTION_NODE:
    205             wrapper = CREATE_DOM_NODE_WRAPPER(exec, globalObject, ProcessingInstruction, node);
    206             break;
    207         case Node::COMMENT_NODE:
    208             wrapper = CREATE_DOM_NODE_WRAPPER(exec, globalObject, Comment, node);
    209             break;
    210         case Node::DOCUMENT_NODE:
    211             // we don't want to cache the document itself in the per-document dictionary
    212             return toJS(exec, globalObject, static_cast<Document*>(node));
    213         case Node::DOCUMENT_TYPE_NODE:
    214             wrapper = CREATE_DOM_NODE_WRAPPER(exec, globalObject, DocumentType, node);
    215             break;
    216         case Node::NOTATION_NODE:
    217             wrapper = CREATE_DOM_NODE_WRAPPER(exec, globalObject, Notation, node);
    218             break;
    219         case Node::DOCUMENT_FRAGMENT_NODE:
    220             wrapper = CREATE_DOM_NODE_WRAPPER(exec, globalObject, DocumentFragment, node);
    221             break;
    222         case Node::ENTITY_REFERENCE_NODE:
    223             wrapper = CREATE_DOM_NODE_WRAPPER(exec, globalObject, EntityReference, node);
    224             break;
    225         default:
    226             wrapper = CREATE_DOM_NODE_WRAPPER(exec, globalObject, Node, node);
    227     }
    228 
    229     return wrapper;
    230 }
    231 
    232 JSValue toJSNewlyCreated(ExecState* exec, JSDOMGlobalObject* globalObject, Node* node)
    233 {
    234     if (!node)
    235         return jsNull();
    236 
    237     return createWrapper(exec, globalObject, node);
    238 }
    239 
    240 JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, Node* node)
    241 {
    242     if (!node)
    243         return jsNull();
    244 
    245     JSNode* wrapper = getCachedDOMNodeWrapper(exec, node->document(), node);
    246     if (wrapper)
    247         return wrapper;
    248 
    249     return createWrapper(exec, globalObject, node);
    250 }
    251 
    252 } // namespace WebCore
    253