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