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