c485e303d5a36e31105f83fd574d5c3117ab2490
[WebKit-https.git] / Source / WebCore / bindings / js / JSNodeCustom.cpp
1 /*
2  * Copyright (C) 2007, 2009-2010, 2016 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 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 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 "HTMLAudioElement.h"
36 #include "HTMLCanvasElement.h"
37 #include "HTMLElement.h"
38 #include "HTMLFrameElementBase.h"
39 #include "HTMLImageElement.h"
40 #include "HTMLLinkElement.h"
41 #include "HTMLNames.h"
42 #include "HTMLScriptElement.h"
43 #include "HTMLStyleElement.h"
44 #include "JSAttr.h"
45 #include "JSCDATASection.h"
46 #include "JSComment.h"
47 #include "JSDOMBinding.h"
48 #include "JSDocument.h"
49 #include "JSDocumentFragment.h"
50 #include "JSDocumentType.h"
51 #include "JSEventListener.h"
52 #include "JSHTMLElement.h"
53 #include "JSHTMLElementWrapperFactory.h"
54 #include "JSProcessingInstruction.h"
55 #include "JSSVGElementWrapperFactory.h"
56 #include "JSShadowRoot.h"
57 #include "JSText.h"
58 #include "Node.h"
59 #include "ProcessingInstruction.h"
60 #include "RegisteredEventListener.h"
61 #include "SVGElement.h"
62 #include "ScriptState.h"
63 #include "ShadowRoot.h"
64 #include "StyleSheet.h"
65 #include "StyledElement.h"
66 #include "Text.h"
67
68
69 namespace WebCore {
70 using namespace JSC;
71
72 using namespace HTMLNames;
73
74 static inline bool isReachableFromDOM(Node* node, SlotVisitor& visitor, const char** reason)
75 {
76     if (!node->isConnected()) {
77         if (is<Element>(*node)) {
78             auto& element = downcast<Element>(*node);
79
80             // If a wrapper is the last reference to an image element
81             // that is loading but not in the document, the wrapper is observable
82             // because it is the only thing keeping the image element alive, and if
83             // the element is destroyed, its load event will not fire.
84             // FIXME: The DOM should manage this issue without the help of JavaScript wrappers.
85             if (is<HTMLImageElement>(element)) {
86                 if (downcast<HTMLImageElement>(element).hasPendingActivity()) {
87                     if (UNLIKELY(reason))
88                         *reason = "Image element with pending activity";
89                     return true;
90                 }
91             }
92 #if ENABLE(VIDEO)
93             else if (is<HTMLAudioElement>(element)) {
94                 if (!downcast<HTMLAudioElement>(element).paused()) {
95                     if (UNLIKELY(reason))
96                         *reason = "Audio element which is not paused";
97                     return true;
98                 }
99             }
100 #endif
101         }
102
103         // If a node is firing event listeners, its wrapper is observable because
104         // its wrapper is responsible for marking those event listeners.
105         if (node->isFiringEventListeners()) {
106             if (UNLIKELY(reason))
107                 *reason = "Node which is firing event listeners";
108             return true;
109         }
110     }
111
112     if (UNLIKELY(reason))
113         *reason = "Connected node";
114
115     return visitor.containsOpaqueRoot(root(node));
116 }
117
118 bool JSNodeOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
119 {
120     JSNode* jsNode = jsCast<JSNode*>(handle.slot()->asCell());
121     return isReachableFromDOM(&jsNode->wrapped(), visitor, reason);
122 }
123
124 JSScope* JSNode::pushEventHandlerScope(ExecState* exec, JSScope* node) const
125 {
126     if (inherits<JSHTMLElement>(exec->vm()))
127         return jsCast<const JSHTMLElement*>(this)->pushEventHandlerScope(exec, node);
128     return node;
129 }
130
131 void JSNode::visitAdditionalChildren(SlotVisitor& visitor)
132 {
133     visitor.addOpaqueRoot(root(wrapped()));
134 }
135
136 static ALWAYS_INLINE JSValue createWrapperInline(ExecState* exec, JSDOMGlobalObject* globalObject, Ref<Node>&& node)
137 {
138     ASSERT(!getCachedWrapper(globalObject->world(), node));
139     
140     JSDOMObject* wrapper;    
141     switch (node->nodeType()) {
142         case Node::ELEMENT_NODE:
143             if (is<HTMLElement>(node))
144                 wrapper = createJSHTMLWrapper(globalObject, static_reference_cast<HTMLElement>(WTFMove(node)));
145             else if (is<SVGElement>(node))
146                 wrapper = createJSSVGWrapper(globalObject, static_reference_cast<SVGElement>(WTFMove(node)));
147             else
148                 wrapper = createWrapper<Element>(globalObject, WTFMove(node));
149             break;
150         case Node::ATTRIBUTE_NODE:
151             wrapper = createWrapper<Attr>(globalObject, WTFMove(node));
152             break;
153         case Node::TEXT_NODE:
154             wrapper = createWrapper<Text>(globalObject, WTFMove(node));
155             break;
156         case Node::CDATA_SECTION_NODE:
157             wrapper = createWrapper<CDATASection>(globalObject, WTFMove(node));
158             break;
159         case Node::PROCESSING_INSTRUCTION_NODE:
160             wrapper = createWrapper<ProcessingInstruction>(globalObject, WTFMove(node));
161             break;
162         case Node::COMMENT_NODE:
163             wrapper = createWrapper<Comment>(globalObject, WTFMove(node));
164             break;
165         case Node::DOCUMENT_NODE:
166             // we don't want to cache the document itself in the per-document dictionary
167             return toJS(exec, globalObject, downcast<Document>(node.get()));
168         case Node::DOCUMENT_TYPE_NODE:
169             wrapper = createWrapper<DocumentType>(globalObject, WTFMove(node));
170             break;
171         case Node::DOCUMENT_FRAGMENT_NODE:
172             if (node->isShadowRoot())
173                 wrapper = createWrapper<ShadowRoot>(globalObject, WTFMove(node));
174             else
175                 wrapper = createWrapper<DocumentFragment>(globalObject, WTFMove(node));
176             break;
177         default:
178             wrapper = createWrapper<Node>(globalObject, WTFMove(node));
179     }
180
181     return wrapper;
182 }
183
184 JSValue createWrapper(ExecState* exec, JSDOMGlobalObject* globalObject, Ref<Node>&& node)
185 {
186     return createWrapperInline(exec, globalObject, WTFMove(node));
187 }
188     
189 JSValue toJSNewlyCreated(ExecState* exec, JSDOMGlobalObject* globalObject, Ref<Node>&& node)
190 {
191     return createWrapperInline(exec, globalObject, WTFMove(node));
192 }
193
194 JSC::JSObject* getOutOfLineCachedWrapper(JSDOMGlobalObject* globalObject, Node& node)
195 {
196     ASSERT(!globalObject->world().isNormal());
197     return globalObject->world().wrappers().get(&node);
198 }
199
200 void willCreatePossiblyOrphanedTreeByRemovalSlowCase(Node* root)
201 {
202     JSC::ExecState* scriptState = mainWorldExecState(root->document().frame());
203     if (!scriptState)
204         return;
205
206     JSLockHolder lock(scriptState);
207     toJS(scriptState, static_cast<JSDOMGlobalObject*>(scriptState->lexicalGlobalObject()), *root);
208 }
209
210 } // namespace WebCore