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/Threading.h>
39 #include <wtf/text/StringConcatenate.h>
40
41 using namespace JSC;
42
43 namespace WebCore {
44
45 const ClassInfo JSDOMWindowBase::s_info = { "Window", &JSDOMGlobalObject::s_info, 0, 0 };
46
JSDOMWindowBase(JSGlobalData & globalData,Structure * structure,PassRefPtr<DOMWindow> window,JSDOMWindowShell * shell)47 JSDOMWindowBase::JSDOMWindowBase(JSGlobalData& globalData, Structure* structure, PassRefPtr<DOMWindow> window, JSDOMWindowShell* shell)
48 : JSDOMGlobalObject(globalData, structure, shell->world(), shell)
49 , m_impl(window)
50 , m_shell(shell)
51 {
52 ASSERT(inherits(&s_info));
53
54 GlobalPropertyInfo staticGlobals[] = {
55 GlobalPropertyInfo(Identifier(globalExec(), "document"), jsNull(), DontDelete | ReadOnly),
56 GlobalPropertyInfo(Identifier(globalExec(), "window"), m_shell, DontDelete | ReadOnly)
57 };
58
59 addStaticGlobals(staticGlobals, WTF_ARRAY_LENGTH(staticGlobals));
60 }
61
updateDocument()62 void JSDOMWindowBase::updateDocument()
63 {
64 ASSERT(m_impl->document());
65 ExecState* exec = globalExec();
66 symbolTablePutWithAttributes(exec->globalData(), Identifier(exec, "document"), toJS(exec, this, m_impl->document()), DontDelete | ReadOnly);
67 }
68
scriptExecutionContext() const69 ScriptExecutionContext* JSDOMWindowBase::scriptExecutionContext() const
70 {
71 return m_impl->document();
72 }
73
crossDomainAccessErrorMessage(const JSGlobalObject * other) const74 String JSDOMWindowBase::crossDomainAccessErrorMessage(const JSGlobalObject* other) const
75 {
76 return m_shell->window()->impl()->crossDomainAccessErrorMessage(asJSDOMWindow(other)->impl());
77 }
78
printErrorMessage(const String & message) const79 void JSDOMWindowBase::printErrorMessage(const String& message) const
80 {
81 printErrorMessageForFrame(impl()->frame(), message);
82 }
83
globalExec()84 ExecState* JSDOMWindowBase::globalExec()
85 {
86 // We need to make sure that any script execution happening in this
87 // frame does not destroy it
88 if (Frame *frame = impl()->frame())
89 frame->keepAlive();
90 return Base::globalExec();
91 }
92
supportsProfiling() const93 bool JSDOMWindowBase::supportsProfiling() const
94 {
95 #if !ENABLE(JAVASCRIPT_DEBUGGER) || !ENABLE(INSPECTOR)
96 return false;
97 #else
98 Frame* frame = impl()->frame();
99 if (!frame)
100 return false;
101
102 Page* page = frame->page();
103 if (!page)
104 return false;
105
106 return page->inspectorController()->profilerEnabled();
107 #endif
108 }
109
supportsRichSourceInfo() const110 bool JSDOMWindowBase::supportsRichSourceInfo() const
111 {
112 #if PLATFORM(ANDROID)
113 return true;
114 #elif !ENABLE(JAVASCRIPT_DEBUGGER) || !ENABLE(INSPECTOR)
115 return false;
116 #else
117 Frame* frame = impl()->frame();
118 if (!frame)
119 return false;
120
121 Page* page = frame->page();
122 if (!page)
123 return false;
124
125 bool enabled = page->inspectorController()->enabled();
126 ASSERT(enabled || !debugger());
127 ASSERT(enabled || !supportsProfiling());
128 return enabled;
129 #endif
130 }
131
shouldInterruptScript() const132 bool JSDOMWindowBase::shouldInterruptScript() const
133 {
134 ASSERT(impl()->frame());
135 Page* page = impl()->frame()->page();
136
137 // See <rdar://problem/5479443>. We don't think that page can ever be NULL
138 // in this case, but if it is, we've gotten into a state where we may have
139 // hung the UI, with no way to ask the client whether to cancel execution.
140 // For now, our solution is just to cancel execution no matter what,
141 // ensuring that we never hang. We might want to consider other solutions
142 // if we discover problems with this one.
143 ASSERT(page);
144 if (!page)
145 return true;
146
147 return page->chrome()->shouldInterruptJavaScript();
148 }
149
willRemoveFromWindowShell()150 void JSDOMWindowBase::willRemoveFromWindowShell()
151 {
152 setCurrentEvent(0);
153 }
154
toThisObject(ExecState *) const155 JSObject* JSDOMWindowBase::toThisObject(ExecState*) const
156 {
157 return shell();
158 }
159
toStrictThisObject(ExecState *) const160 JSValue JSDOMWindowBase::toStrictThisObject(ExecState*) const
161 {
162 return shell();
163 }
164
shell() const165 JSDOMWindowShell* JSDOMWindowBase::shell() const
166 {
167 return m_shell;
168 }
169
commonJSGlobalData()170 JSGlobalData* JSDOMWindowBase::commonJSGlobalData()
171 {
172 ASSERT(isMainThread());
173
174 static JSGlobalData* globalData = 0;
175 if (!globalData) {
176 globalData = JSGlobalData::createLeaked(ThreadStackTypeLarge).releaseRef();
177 globalData->timeoutChecker.setTimeoutInterval(10000); // 10 seconds
178 #ifndef NDEBUG
179 globalData->exclusiveThread = currentThread();
180 #endif
181 initNormalWorldClientData(globalData);
182 }
183
184 return globalData;
185 }
186
187 // JSDOMGlobalObject* is ignored, accessing a window in any context will
188 // use that DOMWindow's prototype chain.
toJS(ExecState * exec,JSDOMGlobalObject *,DOMWindow * domWindow)189 JSValue toJS(ExecState* exec, JSDOMGlobalObject*, DOMWindow* domWindow)
190 {
191 return toJS(exec, domWindow);
192 }
193
toJS(ExecState * exec,DOMWindow * domWindow)194 JSValue toJS(ExecState* exec, DOMWindow* domWindow)
195 {
196 if (!domWindow)
197 return jsNull();
198 Frame* frame = domWindow->frame();
199 if (!frame)
200 return jsNull();
201 return frame->script()->windowShell(currentWorld(exec));
202 }
203
toJSDOMWindow(Frame * frame,DOMWrapperWorld * world)204 JSDOMWindow* toJSDOMWindow(Frame* frame, DOMWrapperWorld* world)
205 {
206 if (!frame)
207 return 0;
208 return frame->script()->windowShell(world)->window();
209 }
210
toJSDOMWindow(JSValue value)211 JSDOMWindow* toJSDOMWindow(JSValue value)
212 {
213 if (!value.isObject())
214 return 0;
215 const ClassInfo* classInfo = asObject(value)->classInfo();
216 if (classInfo == &JSDOMWindow::s_info)
217 return static_cast<JSDOMWindow*>(asObject(value));
218 if (classInfo == &JSDOMWindowShell::s_info)
219 return static_cast<JSDOMWindowShell*>(asObject(value))->window();
220 return 0;
221 }
222
223 } // namespace WebCore
224