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