1 | /* |
2 | * Copyright (C) 2008-2018 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 | * |
8 | * 1. Redistributions of source code must retain the above copyright |
9 | * notice, this list of conditions and the following disclaimer. |
10 | * 2. Redistributions in binary form must reproduce the above copyright |
11 | * notice, this list of conditions and the following disclaimer in the |
12 | * documentation and/or other materials provided with the distribution. |
13 | * 3. Neither the name of Apple Inc. ("Apple") nor the names of |
14 | * its contributors may be used to endorse or promote products derived |
15 | * from this software without specific prior written permission. |
16 | * |
17 | * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
18 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
20 | * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
21 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
22 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
23 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
24 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | */ |
28 | |
29 | #include "config.h" |
30 | #include "JSWindowProxy.h" |
31 | |
32 | #include "AbstractFrame.h" |
33 | #include "CommonVM.h" |
34 | #include "GCController.h" |
35 | #include "JSDOMWindow.h" |
36 | #include "JSDOMWindowProperties.h" |
37 | #include "JSEventTarget.h" |
38 | #include "JSRemoteDOMWindow.h" |
39 | #include "ScriptController.h" |
40 | #include <JavaScriptCore/Debugger.h> |
41 | #include <JavaScriptCore/JSObject.h> |
42 | #include <JavaScriptCore/StrongInlines.h> |
43 | |
44 | namespace WebCore { |
45 | |
46 | using namespace JSC; |
47 | |
48 | const ClassInfo JSWindowProxy::s_info = { "JSWindowProxy" , &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSWindowProxy) }; |
49 | |
50 | inline JSWindowProxy::JSWindowProxy(VM& vm, Structure& structure, DOMWrapperWorld& world) |
51 | : Base(vm, &structure) |
52 | , m_world(world) |
53 | { |
54 | } |
55 | |
56 | void JSWindowProxy::finishCreation(VM& vm, AbstractDOMWindow& window) |
57 | { |
58 | Base::finishCreation(vm); |
59 | ASSERT(inherits(vm, info())); |
60 | setWindow(window); |
61 | } |
62 | |
63 | JSWindowProxy& JSWindowProxy::create(VM& vm, AbstractDOMWindow& window, DOMWrapperWorld& world) |
64 | { |
65 | auto& structure = *Structure::create(vm, 0, jsNull(), TypeInfo(PureForwardingProxyType, StructureFlags), info()); |
66 | auto& proxy = *new (NotNull, allocateCell<JSWindowProxy>(vm.heap)) JSWindowProxy(vm, structure, world); |
67 | proxy.finishCreation(vm, window); |
68 | return proxy; |
69 | } |
70 | |
71 | void JSWindowProxy::destroy(JSCell* cell) |
72 | { |
73 | static_cast<JSWindowProxy*>(cell)->JSWindowProxy::~JSWindowProxy(); |
74 | } |
75 | |
76 | void JSWindowProxy::setWindow(VM& vm, JSDOMGlobalObject& window) |
77 | { |
78 | ASSERT(window.classInfo() == JSDOMWindow::info() || window.classInfo() == JSRemoteDOMWindow::info()); |
79 | setTarget(vm, &window); |
80 | structure(vm)->setGlobalObject(vm, &window); |
81 | GCController::singleton().garbageCollectSoon(); |
82 | } |
83 | |
84 | void JSWindowProxy::setWindow(AbstractDOMWindow& domWindow) |
85 | { |
86 | // Replacing JSDOMWindow via telling JSWindowProxy to use the same DOMWindow it already uses makes no sense, |
87 | // so we'd better never try to. |
88 | ASSERT(!window() || &domWindow != &wrapped()); |
89 | |
90 | bool isRemoteDOMWindow = is<RemoteDOMWindow>(domWindow); |
91 | |
92 | VM& vm = commonVM(); |
93 | auto& prototypeStructure = isRemoteDOMWindow ? *JSRemoteDOMWindowPrototype::createStructure(vm, nullptr, jsNull()) : *JSDOMWindowPrototype::createStructure(vm, nullptr, jsNull()); |
94 | |
95 | // Explicitly protect the prototype so it isn't collected when we allocate the global object. |
96 | // (Once the global object is fully constructed, it will mark its own prototype.) |
97 | // FIXME: Why do we need to protect this when there's a pointer to it on the stack? |
98 | // Perhaps the issue is that structure objects aren't seen when scanning the stack? |
99 | Strong<JSNonFinalObject> prototype(vm, isRemoteDOMWindow ? static_cast<JSNonFinalObject*>(JSRemoteDOMWindowPrototype::create(vm, nullptr, &prototypeStructure)) : static_cast<JSNonFinalObject*>(JSDOMWindowPrototype::create(vm, nullptr, &prototypeStructure))); |
100 | |
101 | JSDOMGlobalObject* window = nullptr; |
102 | if (isRemoteDOMWindow) { |
103 | auto& windowStructure = *JSRemoteDOMWindow::createStructure(vm, nullptr, prototype.get()); |
104 | window = JSRemoteDOMWindow::create(vm, &windowStructure, downcast<RemoteDOMWindow>(domWindow), this); |
105 | } else { |
106 | auto& windowStructure = *JSDOMWindow::createStructure(vm, nullptr, prototype.get()); |
107 | window = JSDOMWindow::create(vm, &windowStructure, downcast<DOMWindow>(domWindow), this); |
108 | } |
109 | |
110 | prototype->structure(vm)->setGlobalObject(vm, window); |
111 | |
112 | auto& propertiesStructure = *JSDOMWindowProperties::createStructure(vm, window, JSEventTarget::prototype(vm, *window)); |
113 | auto& properties = *JSDOMWindowProperties::create(&propertiesStructure, *window); |
114 | prototype->structure(vm)->setPrototypeWithoutTransition(vm, &properties); |
115 | |
116 | setWindow(vm, *window); |
117 | |
118 | ASSERT(window->globalObject() == window); |
119 | ASSERT(prototype->globalObject() == window); |
120 | } |
121 | |
122 | WindowProxy* JSWindowProxy::windowProxy() const |
123 | { |
124 | auto& window = wrapped(); |
125 | return window.frame() ? &window.frame()->windowProxy() : nullptr; |
126 | } |
127 | |
128 | void JSWindowProxy::attachDebugger(JSC::Debugger* debugger) |
129 | { |
130 | auto* globalObject = window(); |
131 | JSLockHolder lock(globalObject->vm()); |
132 | |
133 | if (debugger) |
134 | debugger->attach(globalObject); |
135 | else if (auto* currentDebugger = globalObject->debugger()) |
136 | currentDebugger->detach(globalObject, JSC::Debugger::TerminatingDebuggingSession); |
137 | } |
138 | |
139 | AbstractDOMWindow& JSWindowProxy::wrapped() const |
140 | { |
141 | auto* window = this->window(); |
142 | if (auto* jsWindow = jsDynamicCast<JSRemoteDOMWindowBase*>(window->vm(), window)) |
143 | return jsWindow->wrapped(); |
144 | return jsCast<JSDOMWindowBase*>(window)->wrapped(); |
145 | } |
146 | |
147 | JSValue toJS(ExecState* state, WindowProxy& windowProxy) |
148 | { |
149 | auto* jsWindowProxy = windowProxy.jsWindowProxy(currentWorld(*state)); |
150 | return jsWindowProxy ? JSValue(jsWindowProxy) : jsNull(); |
151 | } |
152 | |
153 | JSWindowProxy* toJSWindowProxy(WindowProxy& windowProxy, DOMWrapperWorld& world) |
154 | { |
155 | return windowProxy.jsWindowProxy(world); |
156 | } |
157 | |
158 | WindowProxy* JSWindowProxy::toWrapped(VM& vm, JSValue value) |
159 | { |
160 | if (!value.isObject()) |
161 | return nullptr; |
162 | JSObject* object = asObject(value); |
163 | if (object->inherits<JSWindowProxy>(vm)) |
164 | return jsCast<JSWindowProxy*>(object)->windowProxy(); |
165 | return nullptr; |
166 | } |
167 | |
168 | } // namespace WebCore |
169 | |