Fixed https://bugs.webkit.org/show_bug.cgi?id=29941
[WebKit.git] / 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 "CString.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 "ScriptController.h"
36 #include "SecurityOrigin.h"
37 #include "Settings.h"
38
39 using namespace JSC;
40
41 namespace WebCore {
42
43 const ClassInfo JSDOMWindowBase::s_info = { "Window", 0, 0, 0 };
44
45 JSDOMWindowBase::JSDOMWindowBase(NonNullPassRefPtr<Structure> structure, PassRefPtr<DOMWindow> window, JSDOMWindowShell* shell)
46     : JSDOMGlobalObject(structure, new JSDOMWindowBaseData(window, shell), shell)
47 {
48     GlobalPropertyInfo staticGlobals[] = {
49         GlobalPropertyInfo(Identifier(globalExec(), "document"), jsNull(), DontDelete | ReadOnly),
50         GlobalPropertyInfo(Identifier(globalExec(), "window"), d()->shell, DontDelete | ReadOnly)
51     };
52     
53     addStaticGlobals(staticGlobals, sizeof(staticGlobals) / sizeof(GlobalPropertyInfo));
54 }
55
56 void JSDOMWindowBase::updateDocument()
57 {
58     ASSERT(d()->impl->document());
59     ExecState* exec = globalExec();
60     symbolTablePutWithAttributes(Identifier(exec, "document"), toJS(exec, this, d()->impl->document()), DontDelete | ReadOnly);
61 }
62
63 ScriptExecutionContext* JSDOMWindowBase::scriptExecutionContext() const
64 {
65     return d()->impl->document();
66 }
67
68 String JSDOMWindowBase::crossDomainAccessErrorMessage(const JSGlobalObject* other) const
69 {
70     KURL originURL = asJSDOMWindow(other)->impl()->url();
71     KURL targetURL = impl()->frame()->document()->url();
72     if (originURL.isNull() || targetURL.isNull())
73         return String();
74
75     // FIXME: this error message should contain more specifics of why the same origin check has failed.
76     return String::format("Unsafe JavaScript attempt to access frame with URL %s from frame with URL %s. Domains, protocols and ports must match.\n",
77         targetURL.string().utf8().data(), originURL.string().utf8().data());
78 }
79
80 void JSDOMWindowBase::printErrorMessage(const String& message) const
81 {
82     if (message.isEmpty())
83         return;
84
85     Frame* frame = impl()->frame();
86     if (!frame)
87         return;
88
89     Settings* settings = frame->settings();
90     if (!settings)
91         return;
92     
93     if (settings->privateBrowsingEnabled())
94         return;
95
96     impl()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, message, 1, String()); // FIXME: provide a real line number and source URL.
97 }
98
99 ExecState* JSDOMWindowBase::globalExec()
100 {
101     // We need to make sure that any script execution happening in this
102     // frame does not destroy it
103     if (Frame *frame = impl()->frame())
104         frame->keepAlive();
105     return Base::globalExec();
106 }
107
108 bool JSDOMWindowBase::supportsProfiling() const
109 {
110 #if !ENABLE(JAVASCRIPT_DEBUGGER) || !ENABLE(INSPECTOR)
111     return false;
112 #else
113     Frame* frame = impl()->frame();
114     if (!frame)
115         return false;
116
117     Page* page = frame->page();
118     if (!page)
119         return false;
120
121     return page->inspectorController()->profilerEnabled();
122 #endif
123 }
124
125 bool JSDOMWindowBase::shouldInterruptScript() const
126 {
127     ASSERT(impl()->frame());
128     Page* page = impl()->frame()->page();
129
130     // See <rdar://problem/5479443>. We don't think that page can ever be NULL
131     // in this case, but if it is, we've gotten into a state where we may have
132     // hung the UI, with no way to ask the client whether to cancel execution.
133     // For now, our solution is just to cancel execution no matter what,
134     // ensuring that we never hang. We might want to consider other solutions
135     // if we discover problems with this one.
136     ASSERT(page);
137     if (!page)
138         return true;
139
140     return page->chrome()->shouldInterruptJavaScript();
141 }
142
143 void JSDOMWindowBase::willRemoveFromWindowShell()
144 {
145     setCurrentEvent(0);
146 }
147
148 JSObject* JSDOMWindowBase::toThisObject(ExecState*) const
149 {
150     return shell();
151 }
152
153 JSDOMWindowShell* JSDOMWindowBase::shell() const
154 {
155     return d()->shell;
156 }
157
158 JSGlobalData* JSDOMWindowBase::commonJSGlobalData()
159 {
160     static JSGlobalData* globalData;
161     if (!globalData) {
162         globalData = JSGlobalData::createLeaked().releaseRef();
163         globalData->timeoutChecker.setTimeoutInterval(10000); // 10 seconds
164 #ifndef NDEBUG
165         globalData->mainThreadOnly = true;
166 #endif
167     }
168
169     return globalData;
170 }
171
172 void JSDOMWindowBase::destroyJSDOMWindowBaseData(void* jsDOMWindowBaseData)
173 {
174     delete static_cast<JSDOMWindowBaseData*>(jsDOMWindowBaseData);
175 }
176
177 // JSDOMGlobalObject* is ignored, accesing a window in any context will
178 // use that DOMWindow's prototype chain.
179 JSValue toJS(ExecState* exec, JSDOMGlobalObject*, DOMWindow* domWindow)
180 {
181     return toJS(exec, domWindow);
182 }
183
184 JSValue toJS(ExecState*, DOMWindow* domWindow)
185 {
186     if (!domWindow)
187         return jsNull();
188     Frame* frame = domWindow->frame();
189     if (!frame)
190         return jsNull();
191     return frame->script()->windowShell();
192 }
193
194 JSDOMWindow* toJSDOMWindow(Frame* frame)
195 {
196     if (!frame)
197         return 0;
198     return frame->script()->windowShell()->window();
199 }
200
201 JSDOMWindow* toJSDOMWindow(JSValue value)
202 {
203     if (!value.isObject())
204         return 0;
205     const ClassInfo* classInfo = asObject(value)->classInfo();
206     if (classInfo == &JSDOMWindow::s_info)
207         return static_cast<JSDOMWindow*>(asObject(value));
208     if (classInfo == &JSDOMWindowShell::s_info)
209         return static_cast<JSDOMWindowShell*>(asObject(value))->window();
210     return 0;
211 }
212
213 } // namespace WebCore