f18a05e3b029708b3752674e32327eb0f14ed967
[WebKit-https.git] / Source / WebCore / bindings / js / JSDOMWindowBase.cpp
1 /*
2  *  Copyright (C) 2000 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2006 Jon Shier (jshier@iastate.edu)
4  *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reseved.
5  *  Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Lesser General Public
9  *  License as published by the Free Software Foundation; either
10  *  version 2 of the License, or (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public
18  *  License along with this library; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
20  *  USA
21  */
22
23 #include "config.h"
24 #include "JSDOMWindowBase.h"
25
26 #include "Chrome.h"
27 #include "Console.h"
28 #include "DOMWindow.h"
29 #include "Frame.h"
30 #include "InspectorController.h"
31 #include "JSDOMWindowCustom.h"
32 #include "JSNode.h"
33 #include "Logging.h"
34 #include "Page.h"
35 #include "SecurityOrigin.h"
36 #include "Settings.h"
37 #include "WebCoreJSClientData.h"
38 #include <wtf/MainThread.h>
39
40 using namespace JSC;
41
42 namespace WebCore {
43
44 const ClassInfo JSDOMWindowBase::s_info = { "Window", &JSDOMGlobalObject::s_info, 0, 0, CREATE_METHOD_TABLE(JSDOMWindowBase) };
45
46 const GlobalObjectMethodTable JSDOMWindowBase::s_globalObjectMethodTable = { &allowsAccessFrom, &supportsProfiling, &supportsRichSourceInfo, &shouldInterruptScript, &javaScriptExperimentsEnabled };
47
48 JSDOMWindowBase::JSDOMWindowBase(JSGlobalData& globalData, Structure* structure, PassRefPtr<DOMWindow> window, JSDOMWindowShell* shell)
49     : JSDOMGlobalObject(globalData, structure, shell->world(), &s_globalObjectMethodTable)
50     , m_impl(window)
51     , m_shell(shell)
52 {
53 }
54
55 void JSDOMWindowBase::finishCreation(JSGlobalData& globalData, JSDOMWindowShell* shell)
56 {
57     Base::finishCreation(globalData, shell);
58     ASSERT(inherits(&s_info));
59
60     GlobalPropertyInfo staticGlobals[] = {
61         GlobalPropertyInfo(Identifier(globalExec(), "document"), jsNull(), DontDelete | ReadOnly),
62         GlobalPropertyInfo(Identifier(globalExec(), "window"), m_shell, DontDelete | ReadOnly)
63     };
64     
65     addStaticGlobals(staticGlobals, WTF_ARRAY_LENGTH(staticGlobals));
66 }
67
68 void JSDOMWindowBase::destroy(JSCell* cell)
69 {
70     static_cast<JSDOMWindowBase*>(cell)->JSDOMWindowBase::~JSDOMWindowBase();
71 }
72
73 void JSDOMWindowBase::updateDocument()
74 {
75     ASSERT(m_impl->document());
76     ExecState* exec = globalExec();
77     symbolTablePutWithAttributes(this, exec->globalData(), Identifier(exec, "document"), toJS(exec, this, m_impl->document()), DontDelete | ReadOnly);
78 }
79
80 ScriptExecutionContext* JSDOMWindowBase::scriptExecutionContext() const
81 {
82     return m_impl->document();
83 }
84
85 String JSDOMWindowBase::crossDomainAccessErrorMessage(const JSGlobalObject* other) const
86 {
87     return m_shell->window()->impl()->crossDomainAccessErrorMessage(asJSDOMWindow(other)->impl());
88 }
89
90 void JSDOMWindowBase::printErrorMessage(const String& message) const
91 {
92     printErrorMessageForFrame(impl()->frame(), message);
93 }
94
95 // This method checks whether accesss to *this* global object is permitted from
96 // the given context; this differs from allowsAccessFromPrivate, since that
97 // method checks whether the given context is permitted to access the current
98 // window the shell is referencing (which may come from a different security
99 // origin to this global object).
100 bool JSDOMWindowBase::allowsAccessFrom(const JSGlobalObject* thisObject, ExecState* exec)
101 {
102     JSGlobalObject* otherObject = exec->lexicalGlobalObject();
103
104     const JSDOMWindow* originWindow = asJSDOMWindow(otherObject);
105     const JSDOMWindow* targetWindow = asJSDOMWindow(thisObject);
106
107     if (originWindow == targetWindow)
108         return true;
109
110     const SecurityOrigin* originSecurityOrigin = originWindow->impl()->securityOrigin();
111     const SecurityOrigin* targetSecurityOrigin = targetWindow->impl()->securityOrigin();
112
113     if (originSecurityOrigin->canAccess(targetSecurityOrigin))
114         return true;
115
116     targetWindow->printErrorMessage(targetWindow->crossDomainAccessErrorMessage(otherObject));
117     return false;
118 }
119
120 bool JSDOMWindowBase::supportsProfiling(const JSGlobalObject* object)
121 {
122 #if !ENABLE(JAVASCRIPT_DEBUGGER) || !ENABLE(INSPECTOR)
123     return false;
124 #else
125     const JSDOMWindowBase* thisObject = static_cast<const JSDOMWindowBase*>(object);
126     Frame* frame = thisObject->impl()->frame();
127     if (!frame)
128         return false;
129
130     Page* page = frame->page();
131     if (!page)
132         return false;
133
134     return page->inspectorController()->profilerEnabled();
135 #endif
136 }
137
138 bool JSDOMWindowBase::supportsRichSourceInfo(const JSGlobalObject* object)
139 {
140 #if !ENABLE(JAVASCRIPT_DEBUGGER) || !ENABLE(INSPECTOR)
141     return false;
142 #else
143     const JSDOMWindowBase* thisObject = static_cast<const JSDOMWindowBase*>(object);
144     Frame* frame = thisObject->impl()->frame();
145     if (!frame)
146         return false;
147
148     Page* page = frame->page();
149     if (!page)
150         return false;
151
152     bool enabled = page->inspectorController()->enabled();
153     ASSERT(enabled || !thisObject->debugger());
154     ASSERT(enabled || !supportsProfiling(thisObject));
155     return enabled;
156 #endif
157 }
158
159 bool JSDOMWindowBase::shouldInterruptScript(const JSGlobalObject* object)
160 {
161     const JSDOMWindowBase* thisObject = static_cast<const JSDOMWindowBase*>(object);
162     ASSERT(thisObject->impl()->frame());
163     Page* page = thisObject->impl()->frame()->page();
164
165     // See <rdar://problem/5479443>. We don't think that page can ever be NULL
166     // in this case, but if it is, we've gotten into a state where we may have
167     // hung the UI, with no way to ask the client whether to cancel execution.
168     // For now, our solution is just to cancel execution no matter what,
169     // ensuring that we never hang. We might want to consider other solutions
170     // if we discover problems with this one.
171     ASSERT(page);
172     if (!page)
173         return true;
174
175     return page->chrome()->shouldInterruptJavaScript();
176 }
177
178 bool JSDOMWindowBase::javaScriptExperimentsEnabled(const JSGlobalObject* object)
179 {
180     const JSDOMWindowBase* thisObject = static_cast<const JSDOMWindowBase*>(object);
181     Frame* frame = thisObject->impl()->frame();
182     if (!frame)
183         return false;
184     Settings* settings = frame->settings();
185     if (!settings)
186         return false;
187     return settings->javaScriptExperimentsEnabled();
188 }
189
190 void JSDOMWindowBase::willRemoveFromWindowShell()
191 {
192     setCurrentEvent(0);
193 }
194
195 JSObject* JSDOMWindowBase::toThisObject(JSCell* cell, ExecState*)
196 {
197     return jsCast<JSDOMWindowBase*>(cell)->shell();
198 }
199
200 JSDOMWindowShell* JSDOMWindowBase::shell() const
201 {
202     return m_shell;
203 }
204
205 JSGlobalData* JSDOMWindowBase::commonJSGlobalData()
206 {
207     ASSERT(isMainThread());
208
209     static JSGlobalData* globalData = 0;
210     if (!globalData) {
211         globalData = JSGlobalData::createLeaked(ThreadStackTypeLarge, LargeHeap).leakRef();
212         globalData->timeoutChecker.setTimeoutInterval(10000); // 10 seconds
213 #ifndef NDEBUG
214         globalData->exclusiveThread = currentThread();
215 #endif
216         initNormalWorldClientData(globalData);
217     }
218
219     return globalData;
220 }
221
222 // JSDOMGlobalObject* is ignored, accessing a window in any context will
223 // use that DOMWindow's prototype chain.
224 JSValue toJS(ExecState* exec, JSDOMGlobalObject*, DOMWindow* domWindow)
225 {
226     return toJS(exec, domWindow);
227 }
228
229 JSValue toJS(ExecState* exec, DOMWindow* domWindow)
230 {
231     if (!domWindow)
232         return jsNull();
233     Frame* frame = domWindow->frame();
234     if (!frame)
235         return jsNull();
236     return frame->script()->windowShell(currentWorld(exec));
237 }
238
239 JSDOMWindow* toJSDOMWindow(Frame* frame, DOMWrapperWorld* world)
240 {
241     if (!frame)
242         return 0;
243     return frame->script()->windowShell(world)->window();
244 }
245
246 JSDOMWindow* toJSDOMWindow(JSValue value)
247 {
248     if (!value.isObject())
249         return 0;
250     const ClassInfo* classInfo = asObject(value)->classInfo();
251     if (classInfo == &JSDOMWindow::s_info)
252         return jsCast<JSDOMWindow*>(asObject(value));
253     if (classInfo == &JSDOMWindowShell::s_info)
254         return jsCast<JSDOMWindowShell*>(asObject(value))->window();
255     return 0;
256 }
257
258 } // namespace WebCore