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
42using namespace JSC;
43
44namespace WebCore {
45
46const ClassInfo JSDOMWindowBase::s_info = { "Window", &JSDOMGlobalObject::s_info, 0, 0 };
47
48JSDOMWindowBase::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
63void 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
70ScriptExecutionContext* JSDOMWindowBase::scriptExecutionContext() const
71{
72    return m_impl->document();
73}
74
75String JSDOMWindowBase::crossDomainAccessErrorMessage(const JSGlobalObject* other) const
76{
77    return m_shell->window()->impl()->crossDomainAccessErrorMessage(asJSDOMWindow(other)->impl());
78}
79
80void JSDOMWindowBase::printErrorMessage(const String& message) const
81{
82    printErrorMessageForFrame(impl()->frame(), message);
83}
84
85ExecState* 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
94bool 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
111bool 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
133bool 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
151void JSDOMWindowBase::willRemoveFromWindowShell()
152{
153    setCurrentEvent(0);
154}
155
156JSObject* JSDOMWindowBase::toThisObject(ExecState*) const
157{
158    return shell();
159}
160
161JSValue JSDOMWindowBase::toStrictThisObject(ExecState*) const
162{
163    return shell();
164}
165
166JSDOMWindowShell* JSDOMWindowBase::shell() const
167{
168    return m_shell;
169}
170
171JSGlobalData* 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.
190JSValue toJS(ExecState* exec, JSDOMGlobalObject*, DOMWindow* domWindow)
191{
192    return toJS(exec, domWindow);
193}
194
195JSValue 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
205JSDOMWindow* toJSDOMWindow(Frame* frame, DOMWrapperWorld* world)
206{
207    if (!frame)
208        return 0;
209    return frame->script()->windowShell(world)->window();
210}
211
212JSDOMWindow* 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