1 /*
2 * Copyright (C) 2007 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 "JSHTMLElement.h"
47 #include "JSHTMLElementWrapperFactory.h"
48 #include "JSNotation.h"
49 #include "JSProcessingInstruction.h"
50 #include "JSText.h"
51 #include "Node.h"
52 #include "Notation.h"
53 #include "ProcessingInstruction.h"
54 #include "Text.h"
55 #include <wtf/PassRefPtr.h>
56 #include <wtf/RefPtr.h>
57
58 #if ENABLE(SVG)
59 #include "JSSVGElementWrapperFactory.h"
60 #include "SVGElement.h"
61 #endif
62
63 using namespace JSC;
64
65 namespace WebCore {
66
67 typedef int ExpectionCode;
68
insertBefore(ExecState * exec,const ArgList & args)69 JSValuePtr JSNode::insertBefore(ExecState* exec, const ArgList& args)
70 {
71 ExceptionCode ec = 0;
72 bool ok = impl()->insertBefore(toNode(args.at(exec, 0)), toNode(args.at(exec, 1)), ec, true);
73 setDOMException(exec, ec);
74 if (ok)
75 return args.at(exec, 0);
76 return jsNull();
77 }
78
replaceChild(ExecState * exec,const ArgList & args)79 JSValuePtr JSNode::replaceChild(ExecState* exec, const ArgList& args)
80 {
81 ExceptionCode ec = 0;
82 bool ok = impl()->replaceChild(toNode(args.at(exec, 0)), toNode(args.at(exec, 1)), ec, true);
83 setDOMException(exec, ec);
84 if (ok)
85 return args.at(exec, 1);
86 return jsNull();
87 }
88
removeChild(ExecState * exec,const ArgList & args)89 JSValuePtr JSNode::removeChild(ExecState* exec, const ArgList& args)
90 {
91 ExceptionCode ec = 0;
92 bool ok = impl()->removeChild(toNode(args.at(exec, 0)), ec);
93 setDOMException(exec, ec);
94 if (ok)
95 return args.at(exec, 0);
96 return jsNull();
97 }
98
appendChild(ExecState * exec,const ArgList & args)99 JSValuePtr JSNode::appendChild(ExecState* exec, const ArgList& args)
100 {
101 ExceptionCode ec = 0;
102 bool ok = impl()->appendChild(toNode(args.at(exec, 0)), ec, true);
103 setDOMException(exec, ec);
104 if (ok)
105 return args.at(exec, 0);
106 return jsNull();
107 }
108
mark()109 void JSNode::mark()
110 {
111 ASSERT(!marked());
112
113 Node* node = m_impl.get();
114
115 // Nodes in the document are kept alive by JSDocument::mark,
116 // so we have no special responsibilities and can just call the base class here.
117 if (node->inDocument()) {
118 // But if the document isn't marked we have to mark it to ensure that
119 // nodes reachable from this one are also marked
120 if (Document* doc = node->ownerDocument())
121 if (DOMObject* docWrapper = getCachedDOMObjectWrapper(*Heap::heap(this)->globalData(), doc))
122 if (!docWrapper->marked())
123 docWrapper->mark();
124 DOMObject::mark();
125 return;
126 }
127
128 // This is a node outside the document, so find the root of the tree it is in,
129 // and start marking from there.
130 Node* root = node;
131 for (Node* current = m_impl.get(); current; current = current->parentNode())
132 root = current;
133
134 // If we're already marking this tree, then we can simply mark this wrapper
135 // by calling the base class; our caller is iterating the tree.
136 if (root->inSubtreeMark()) {
137 DOMObject::mark();
138 return;
139 }
140
141 // Mark the whole tree; use the global set of roots to avoid reentering.
142 root->setInSubtreeMark(true);
143 for (Node* nodeToMark = root; nodeToMark; nodeToMark = nodeToMark->traverseNextNode()) {
144 JSNode* wrapper = getCachedDOMNodeWrapper(m_impl->document(), nodeToMark);
145 if (wrapper) {
146 if (!wrapper->marked())
147 wrapper->mark();
148 } else if (nodeToMark == node) {
149 // This is the case where the map from the document to wrappers has
150 // been cleared out, but a wrapper is being marked. For now, we'll
151 // let the rest of the tree of wrappers get collected, because we have
152 // no good way of finding them. Later we should test behavior of other
153 // browsers and see if we need to preserve other wrappers in this case.
154 if (!marked())
155 mark();
156 }
157 }
158 root->setInSubtreeMark(false);
159
160 // Double check that we actually ended up marked. This assert caught problems in the past.
161 ASSERT(marked());
162 }
163
createWrapper(ExecState * exec,Node * node)164 static ALWAYS_INLINE JSValuePtr createWrapper(ExecState* exec, Node* node)
165 {
166 ASSERT(node);
167 ASSERT(!getCachedDOMNodeWrapper(node->document(), node));
168
169 JSNode* wrapper;
170 switch (node->nodeType()) {
171 case Node::ELEMENT_NODE:
172 if (node->isHTMLElement())
173 wrapper = createJSHTMLWrapper(exec, static_cast<HTMLElement*>(node));
174 #if ENABLE(SVG)
175 else if (node->isSVGElement())
176 wrapper = createJSSVGWrapper(exec, static_cast<SVGElement*>(node));
177 #endif
178 else
179 wrapper = CREATE_DOM_NODE_WRAPPER(exec, Element, node);
180 break;
181 case Node::ATTRIBUTE_NODE:
182 wrapper = CREATE_DOM_NODE_WRAPPER(exec, Attr, node);
183 break;
184 case Node::TEXT_NODE:
185 wrapper = CREATE_DOM_NODE_WRAPPER(exec, Text, node);
186 break;
187 case Node::CDATA_SECTION_NODE:
188 wrapper = CREATE_DOM_NODE_WRAPPER(exec, CDATASection, node);
189 break;
190 case Node::ENTITY_NODE:
191 wrapper = CREATE_DOM_NODE_WRAPPER(exec, Entity, node);
192 break;
193 case Node::PROCESSING_INSTRUCTION_NODE:
194 wrapper = CREATE_DOM_NODE_WRAPPER(exec, ProcessingInstruction, node);
195 break;
196 case Node::COMMENT_NODE:
197 wrapper = CREATE_DOM_NODE_WRAPPER(exec, Comment, node);
198 break;
199 case Node::DOCUMENT_NODE:
200 // we don't want to cache the document itself in the per-document dictionary
201 return toJS(exec, static_cast<Document*>(node));
202 case Node::DOCUMENT_TYPE_NODE:
203 wrapper = CREATE_DOM_NODE_WRAPPER(exec, DocumentType, node);
204 break;
205 case Node::NOTATION_NODE:
206 wrapper = CREATE_DOM_NODE_WRAPPER(exec, Notation, node);
207 break;
208 case Node::DOCUMENT_FRAGMENT_NODE:
209 wrapper = CREATE_DOM_NODE_WRAPPER(exec, DocumentFragment, node);
210 break;
211 case Node::ENTITY_REFERENCE_NODE:
212 wrapper = CREATE_DOM_NODE_WRAPPER(exec, EntityReference, node);
213 break;
214 default:
215 wrapper = CREATE_DOM_NODE_WRAPPER(exec, Node, node);
216 }
217
218 return wrapper;
219 }
220
toJSNewlyCreated(ExecState * exec,Node * node)221 JSValuePtr toJSNewlyCreated(ExecState* exec, Node* node)
222 {
223 if (!node)
224 return jsNull();
225
226 return createWrapper(exec, node);
227 }
228
toJS(ExecState * exec,Node * node)229 JSValuePtr toJS(ExecState* exec, Node* node)
230 {
231 if (!node)
232 return jsNull();
233
234 JSNode* wrapper = getCachedDOMNodeWrapper(node->document(), node);
235 if (wrapper)
236 return wrapper;
237
238 return createWrapper(exec, node);
239 }
240
241 } // namespace WebCore
242