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