• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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