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 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 "Console.h"
28 #include "DOMTimer.h"
29 #include "DOMWindow.h"
30 #include "Element.h"
31 #include "EventListener.h"
32 #include "ExceptionCode.h"
33 #include "FloatRect.h"
34 #include "Frame.h"
35 #include "FrameLoadRequest.h"
36 #include "FrameLoader.h"
37 #include "FrameTree.h"
38 #include "GCController.h"
39 #include "HTMLDocument.h"
40 #include "InspectorController.h"
41 #include "JSAudioConstructor.h"
42 #include "JSDOMWindowCustom.h"
43 #include "JSEvent.h"
44 #include "JSEventListener.h"
45 #include "JSHTMLCollection.h"
46 #include "JSImageConstructor.h"
47 #include "JSMessageChannelConstructor.h"
48 #include "JSNode.h"
49 #include "JSWebKitCSSMatrixConstructor.h"
50 #include "JSOptionConstructor.h"
51 #include "JSWorkerConstructor.h"
52 #include "JSXMLHttpRequestConstructor.h"
53 #include "JSXSLTProcessorConstructor.h"
54 #include "Logging.h"
55 #include "MediaPlayer.h"
56 #include "Page.h"
57 #include "PlatformScreen.h"
58 #include "PluginInfoStore.h"
59 #include "RenderView.h"
60 #include "ScheduledAction.h"
61 #include "ScriptController.h"
62 #include "SecurityOrigin.h"
63 #include "Settings.h"
64 #include "WindowFeatures.h"
65 #include "htmlediting.h"
66 #include <runtime/Error.h>
67 #include <runtime/JSLock.h>
68 #include <wtf/AlwaysInline.h>
69 #include <wtf/MathExtras.h>
70
71 using namespace JSC;
72
73 static JSValuePtr windowProtoFuncOpen(ExecState*, JSObject*, JSValuePtr, const ArgList&);
74 static JSValuePtr windowProtoFuncShowModalDialog(ExecState*, JSObject*, JSValuePtr, const ArgList&);
75 static JSValuePtr windowProtoFuncNotImplemented(ExecState*, JSObject*, JSValuePtr, const ArgList&);
76
77 static JSValuePtr jsDOMWindowBaseCrypto(ExecState*, const Identifier&, const PropertySlot&);
78 static JSValuePtr jsDOMWindowBaseEvent(ExecState*, const Identifier&, const PropertySlot&);
79 static void setJSDOMWindowBaseEvent(ExecState*, JSObject*, JSValuePtr);
80
81 // Constructors
82 static JSValuePtr jsDOMWindowBaseAudio(ExecState*, const Identifier&, const PropertySlot&);
83 static void setJSDOMWindowBaseAudio(ExecState*, JSObject*, JSValuePtr);
84 static JSValuePtr jsDOMWindowBaseImage(ExecState*, const Identifier&, const PropertySlot&);
85 static void setJSDOMWindowBaseImage(ExecState*, JSObject*, JSValuePtr);
86 static JSValuePtr jsDOMWindowBaseMessageChannel(ExecState*, const Identifier&, const PropertySlot&);
87 static void setJSDOMWindowBaseMessageChannel(ExecState*, JSObject*, JSValuePtr);
88 static JSValuePtr jsDOMWindowBaseWorker(ExecState*, const Identifier&, const PropertySlot&);
89 static void setJSDOMWindowBaseWorker(ExecState*, JSObject*, JSValuePtr);
90 static JSValuePtr jsDOMWindowBaseOption(ExecState*, const Identifier&, const PropertySlot&);
91 static void setJSDOMWindowBaseOption(ExecState*, JSObject*, JSValuePtr);
92 static JSValuePtr jsDOMWindowBaseWebKitCSSMatrix(ExecState*, const Identifier&, const PropertySlot&);
93 static void setJSDOMWindowBaseWebKitCSSMatrix(ExecState*, JSObject*, JSValuePtr);
94 static JSValuePtr jsDOMWindowBaseXMLHttpRequest(ExecState*, const Identifier&, const PropertySlot&);
95 static void setJSDOMWindowBaseXMLHttpRequest(ExecState*, JSObject*, JSValuePtr);
96 static JSValuePtr jsDOMWindowBaseXSLTProcessor(ExecState*, const Identifier&, const PropertySlot&);
97 static void setJSDOMWindowBaseXSLTProcessor(ExecState*, JSObject*, JSValuePtr);
98
99 #include "JSDOMWindowBase.lut.h"
100
101 namespace WebCore {
102
103 ////////////////////// JSDOMWindowBase Object ////////////////////////
104
105 const ClassInfo JSDOMWindowBase::s_info = { "Window", 0, &JSDOMWindowBaseTable, 0 };
106
107 /*
108 @begin JSDOMWindowBaseTable
109 # -- Functions --
110 open windowProtoFuncOpen DontDelete|Function 3
111 showModalDialog windowProtoFuncShowModalDialog DontDelete|Function 1
112 # Not implemented
113 captureEvents windowProtoFuncNotImplemented DontDelete|Function 0
114 releaseEvents windowProtoFuncNotImplemented DontDelete|Function 0
115 # -- Attributes --
116 crypto jsDOMWindowBaseCrypto DontDelete|ReadOnly
117 event jsDOMWindowBaseEvent DontDelete
118 # -- Constructors --
119 Audio jsDOMWindowBaseAudio DontDelete
120 Image jsDOMWindowBaseImage DontDelete
121 MessageChannel jsDOMWindowBaseMessageChannel DontDelete
122 Option jsDOMWindowBaseOption DontDelete
123 WebKitCSSMatrix jsDOMWindowBaseWebKitCSSMatrix DontDelete
124 Worker jsDOMWindowBaseWorker DontDelete
125 XMLHttpRequest jsDOMWindowBaseXMLHttpRequest DontDelete
126 XSLTProcessor jsDOMWindowBaseXSLTProcessor DontDelete
127 @end
128 */
129
JSDOMWindowBaseData(PassRefPtr<DOMWindow> window,JSDOMWindowShell * shell)130 JSDOMWindowBase::JSDOMWindowBaseData::JSDOMWindowBaseData(PassRefPtr<DOMWindow> window, JSDOMWindowShell* shell)
131 : impl(window)
132 , returnValueSlot(0)
133 , shell(shell)
134 {
135 }
136
JSDOMWindowBase(PassRefPtr<Structure> structure,PassRefPtr<DOMWindow> window,JSDOMWindowShell * shell)137 JSDOMWindowBase::JSDOMWindowBase(PassRefPtr<Structure> structure, PassRefPtr<DOMWindow> window, JSDOMWindowShell* shell)
138 : JSDOMGlobalObject(structure, new JSDOMWindowBaseData(window, shell), shell)
139 {
140 // Time in milliseconds before the script timeout handler kicks in.
141 setTimeoutTime(10000);
142
143 GlobalPropertyInfo staticGlobals[] = {
144 GlobalPropertyInfo(Identifier(globalExec(), "document"), jsNull(), DontDelete | ReadOnly),
145 GlobalPropertyInfo(Identifier(globalExec(), "window"), d()->shell, DontDelete | ReadOnly)
146 };
147
148 addStaticGlobals(staticGlobals, sizeof(staticGlobals) / sizeof(GlobalPropertyInfo));
149 }
150
updateDocument()151 void JSDOMWindowBase::updateDocument()
152 {
153 ASSERT(d()->impl->document());
154 ExecState* exec = globalExec();
155 symbolTablePutWithAttributes(Identifier(exec, "document"), toJS(exec, d()->impl->document()), DontDelete | ReadOnly);
156 }
157
~JSDOMWindowBase()158 JSDOMWindowBase::~JSDOMWindowBase()
159 {
160 }
161
scriptExecutionContext() const162 ScriptExecutionContext* JSDOMWindowBase::scriptExecutionContext() const
163 {
164 return d()->impl->document();
165 }
166
allowPopUp(ExecState * exec)167 static bool allowPopUp(ExecState* exec)
168 {
169 Frame* frame = asJSDOMWindow(exec->dynamicGlobalObject())->impl()->frame();
170
171 ASSERT(frame);
172 if (frame->script()->processingUserGesture())
173 return true;
174 Settings* settings = frame->settings();
175 return settings && settings->JavaScriptCanOpenWindowsAutomatically();
176 }
177
parseModalDialogFeatures(const String & featuresArg)178 static HashMap<String, String> parseModalDialogFeatures(const String& featuresArg)
179 {
180 HashMap<String, String> map;
181
182 Vector<String> features;
183 featuresArg.split(';', features);
184 Vector<String>::const_iterator end = features.end();
185 for (Vector<String>::const_iterator it = features.begin(); it != end; ++it) {
186 String s = *it;
187 int pos = s.find('=');
188 int colonPos = s.find(':');
189 if (pos >= 0 && colonPos >= 0)
190 continue; // ignore any strings that have both = and :
191 if (pos < 0)
192 pos = colonPos;
193 if (pos < 0) {
194 // null string for value means key without value
195 map.set(s.stripWhiteSpace().lower(), String());
196 } else {
197 String key = s.left(pos).stripWhiteSpace().lower();
198 String val = s.substring(pos + 1).stripWhiteSpace().lower();
199 int spacePos = val.find(' ');
200 if (spacePos != -1)
201 val = val.left(spacePos);
202 map.set(key, val);
203 }
204 }
205
206 return map;
207 }
208
createWindow(ExecState * exec,Frame * openerFrame,const String & url,const String & frameName,const WindowFeatures & windowFeatures,JSValuePtr dialogArgs)209 static Frame* createWindow(ExecState* exec, Frame* openerFrame, const String& url,
210 const String& frameName, const WindowFeatures& windowFeatures, JSValuePtr dialogArgs)
211 {
212 Frame* activeFrame = asJSDOMWindow(exec->dynamicGlobalObject())->impl()->frame();
213 ASSERT(activeFrame);
214
215 ResourceRequest request;
216
217 request.setHTTPReferrer(activeFrame->loader()->outgoingReferrer());
218 FrameLoader::addHTTPOriginIfNeeded(request, activeFrame->loader()->outgoingOrigin());
219 FrameLoadRequest frameRequest(request, frameName);
220
221 // FIXME: It's much better for client API if a new window starts with a URL, here where we
222 // know what URL we are going to open. Unfortunately, this code passes the empty string
223 // for the URL, but there's a reason for that. Before loading we have to set up the opener,
224 // openedByDOM, and dialogArguments values. Also, to decide whether to use the URL we currently
225 // do an allowsAccessFrom call using the window we create, which can't be done before creating it.
226 // We'd have to resolve all those issues to pass the URL instead of "".
227
228 bool created;
229 // We pass in the opener frame here so it can be used for looking up the frame name, in case the active frame
230 // is different from the opener frame, and the name references a frame relative to the opener frame, for example
231 // "_self" or "_parent".
232 Frame* newFrame = activeFrame->loader()->createWindow(openerFrame->loader(), frameRequest, windowFeatures, created);
233 if (!newFrame)
234 return 0;
235
236 newFrame->loader()->setOpener(openerFrame);
237 newFrame->loader()->setOpenedByDOM();
238
239 JSDOMWindow* newWindow = toJSDOMWindow(newFrame);
240
241 if (dialogArgs)
242 newWindow->putDirect(Identifier(exec, "dialogArguments"), dialogArgs);
243
244 if (!protocolIs(url, "javascript") || newWindow->allowsAccessFrom(exec)) {
245 KURL completedURL = url.isEmpty() ? KURL("") : activeFrame->document()->completeURL(url);
246 bool userGesture = activeFrame->script()->processingUserGesture();
247
248 if (created)
249 newFrame->loader()->changeLocation(completedURL, activeFrame->loader()->outgoingReferrer(), false, false, userGesture);
250 else if (!url.isEmpty())
251 newFrame->loader()->scheduleLocationChange(completedURL.string(), activeFrame->loader()->outgoingReferrer(), !activeFrame->script()->anyPageIsProcessingUserGesture(), false, userGesture);
252 }
253
254 return newFrame;
255 }
256
canShowModalDialog(const Frame * frame)257 static bool canShowModalDialog(const Frame* frame)
258 {
259 if (!frame)
260 return false;
261
262 Page* page = frame->page();
263 if (!page)
264 return false;
265
266 return page->chrome()->canRunModal();
267 }
268
canShowModalDialogNow(const Frame * frame)269 static bool canShowModalDialogNow(const Frame* frame)
270 {
271 if (!frame)
272 return false;
273
274 Page* page = frame->page();
275 if (!page)
276 return false;
277
278 return page->chrome()->canRunModalNow();
279 }
280
showModalDialog(ExecState * exec,Frame * frame,const String & url,JSValuePtr dialogArgs,const String & featureArgs)281 static JSValuePtr showModalDialog(ExecState* exec, Frame* frame, const String& url, JSValuePtr dialogArgs, const String& featureArgs)
282 {
283 if (!canShowModalDialogNow(frame) || !allowPopUp(exec))
284 return jsUndefined();
285
286 const HashMap<String, String> features = parseModalDialogFeatures(featureArgs);
287
288 const bool trusted = false;
289
290 // The following features from Microsoft's documentation are not implemented:
291 // - default font settings
292 // - width, height, left, and top specified in units other than "px"
293 // - edge (sunken or raised, default is raised)
294 // - dialogHide: trusted && boolFeature(features, "dialoghide"), makes dialog hide when you print
295 // - help: boolFeature(features, "help", true), makes help icon appear in dialog (what does it do on Windows?)
296 // - unadorned: trusted && boolFeature(features, "unadorned");
297
298 if (!frame)
299 return jsUndefined();
300
301 FloatRect screenRect = screenAvailableRect(frame->view());
302
303 WindowFeatures wargs;
304 wargs.width = WindowFeatures::floatFeature(features, "dialogwidth", 100, screenRect.width(), 620); // default here came from frame size of dialog in MacIE
305 wargs.widthSet = true;
306 wargs.height = WindowFeatures::floatFeature(features, "dialogheight", 100, screenRect.height(), 450); // default here came from frame size of dialog in MacIE
307 wargs.heightSet = true;
308
309 wargs.x = WindowFeatures::floatFeature(features, "dialogleft", screenRect.x(), screenRect.right() - wargs.width, -1);
310 wargs.xSet = wargs.x > 0;
311 wargs.y = WindowFeatures::floatFeature(features, "dialogtop", screenRect.y(), screenRect.bottom() - wargs.height, -1);
312 wargs.ySet = wargs.y > 0;
313
314 if (WindowFeatures::boolFeature(features, "center", true)) {
315 if (!wargs.xSet) {
316 wargs.x = screenRect.x() + (screenRect.width() - wargs.width) / 2;
317 wargs.xSet = true;
318 }
319 if (!wargs.ySet) {
320 wargs.y = screenRect.y() + (screenRect.height() - wargs.height) / 2;
321 wargs.ySet = true;
322 }
323 }
324
325 wargs.dialog = true;
326 wargs.resizable = WindowFeatures::boolFeature(features, "resizable");
327 wargs.scrollbarsVisible = WindowFeatures::boolFeature(features, "scroll", true);
328 wargs.statusBarVisible = WindowFeatures::boolFeature(features, "status", !trusted);
329 wargs.menuBarVisible = false;
330 wargs.toolBarVisible = false;
331 wargs.locationBarVisible = false;
332 wargs.fullscreen = false;
333
334 Frame* dialogFrame = createWindow(exec, frame, url, "", wargs, dialogArgs);
335 if (!dialogFrame)
336 return jsUndefined();
337
338 JSDOMWindow* dialogWindow = toJSDOMWindow(dialogFrame);
339
340 // Get the return value either just before clearing the dialog window's
341 // properties (in JSDOMWindowBase::clear), or when on return from runModal.
342 JSValuePtr returnValue = noValue();
343 dialogWindow->setReturnValueSlot(&returnValue);
344 dialogFrame->page()->chrome()->runModal();
345 dialogWindow->setReturnValueSlot(0);
346
347 // If we don't have a return value, get it now.
348 // Either JSDOMWindowBase::clear was not called yet, or there was no return value,
349 // and in that case, there's no harm in trying again (no benefit either).
350 if (!returnValue)
351 returnValue = dialogWindow->getDirect(Identifier(exec, "returnValue"));
352
353 return returnValue ? returnValue : jsUndefined();
354 }
355
356 } // namespace WebCore
357
358 using namespace WebCore;
359
jsDOMWindowBaseCrypto(ExecState *,const Identifier &,const PropertySlot &)360 JSValuePtr jsDOMWindowBaseCrypto(ExecState*, const Identifier&, const PropertySlot&)
361 {
362 return jsUndefined(); // FIXME: implement this
363 }
364
jsDOMWindowBaseEvent(ExecState * exec,const Identifier &,const PropertySlot & slot)365 JSValuePtr jsDOMWindowBaseEvent(ExecState* exec, const Identifier&, const PropertySlot& slot)
366 {
367 if (!static_cast<JSDOMWindowBase*>(asObject(slot.slotBase()))->allowsAccessFrom(exec))
368 return jsUndefined();
369 if (!static_cast<JSDOMWindowBase*>(asObject(slot.slotBase()))->currentEvent())
370 return jsUndefined();
371 return toJS(exec, static_cast<JSDOMWindowBase*>(asObject(slot.slotBase()))->currentEvent());
372 }
373
jsDOMWindowBaseImage(ExecState * exec,const Identifier &,const PropertySlot & slot)374 JSValuePtr jsDOMWindowBaseImage(ExecState* exec, const Identifier&, const PropertySlot& slot)
375 {
376 if (!static_cast<JSDOMWindowBase*>(asObject(slot.slotBase()))->allowsAccessFrom(exec))
377 return jsUndefined();
378 return getDOMConstructor<JSImageConstructor>(exec, static_cast<JSDOMWindowBase*>(asObject(slot.slotBase())));
379 }
380
381 #if !ENABLE(CHANNEL_MESSAGING)
382
jsDOMWindowBaseMessageChannel(ExecState *,const Identifier &,const PropertySlot &)383 JSValuePtr jsDOMWindowBaseMessageChannel(ExecState*, const Identifier&, const PropertySlot&)
384 {
385 return jsUndefined();
386 }
387
388 #else
389
jsDOMWindowBaseMessageChannel(ExecState * exec,const Identifier &,const PropertySlot & slot)390 JSValuePtr jsDOMWindowBaseMessageChannel(ExecState* exec, const Identifier&, const PropertySlot& slot)
391 {
392 if (!static_cast<JSDOMWindowBase*>(asObject(slot.slotBase()))->allowsAccessFrom(exec))
393 return jsUndefined();
394 return getDOMConstructor<JSMessageChannelConstructor>(exec, static_cast<JSDOMWindowBase*>(asObject(slot.slotBase())));
395 }
396
397 #endif
398
jsDOMWindowBaseOption(ExecState * exec,const Identifier &,const PropertySlot & slot)399 JSValuePtr jsDOMWindowBaseOption(ExecState* exec, const Identifier&, const PropertySlot& slot)
400 {
401 if (!static_cast<JSDOMWindowBase*>(asObject(slot.slotBase()))->allowsAccessFrom(exec))
402 return jsUndefined();
403 return getDOMConstructor<JSOptionConstructor>(exec, static_cast<JSDOMWindowBase*>(asObject(slot.slotBase())));
404 }
405
jsDOMWindowBaseWebKitCSSMatrix(ExecState * exec,const Identifier &,const PropertySlot & slot)406 JSValuePtr jsDOMWindowBaseWebKitCSSMatrix(ExecState* exec, const Identifier&, const PropertySlot& slot)
407 {
408 if (!static_cast<JSDOMWindowBase*>(asObject(slot.slotBase()))->allowsAccessFrom(exec))
409 return jsUndefined();
410 return getDOMConstructor<JSWebKitCSSMatrixConstructor>(exec, static_cast<JSDOMWindowBase*>(asObject(slot.slotBase())));
411 }
412
jsDOMWindowBaseXMLHttpRequest(ExecState * exec,const Identifier &,const PropertySlot & slot)413 JSValuePtr jsDOMWindowBaseXMLHttpRequest(ExecState* exec, const Identifier&, const PropertySlot& slot)
414 {
415 if (!static_cast<JSDOMWindowBase*>(asObject(slot.slotBase()))->allowsAccessFrom(exec))
416 return jsUndefined();
417 return getDOMConstructor<JSXMLHttpRequestConstructor>(exec, static_cast<JSDOMWindowBase*>(asObject(slot.slotBase())));
418 }
419
jsDOMWindowBaseAudio(ExecState * exec,const Identifier &,const PropertySlot & slot)420 JSValuePtr jsDOMWindowBaseAudio(ExecState* exec, const Identifier&, const PropertySlot& slot)
421 {
422 #if ENABLE(VIDEO)
423 if (!static_cast<JSDOMWindowBase*>(asObject(slot.slotBase()))->allowsAccessFrom(exec))
424 return jsUndefined();
425 if (!MediaPlayer::isAvailable())
426 return jsUndefined();
427 return getDOMConstructor<JSAudioConstructor>(exec, static_cast<JSDOMWindowBase*>(asObject(slot.slotBase())));
428 #else
429 return jsUndefined();
430 #endif
431 }
432
jsDOMWindowBaseWorker(ExecState * exec,const Identifier &,const PropertySlot & slot)433 JSValuePtr jsDOMWindowBaseWorker(ExecState* exec, const Identifier&, const PropertySlot& slot)
434 {
435 #if ENABLE(WORKERS)
436 if (!static_cast<JSDOMWindowBase*>(asObject(slot.slotBase()))->allowsAccessFrom(exec))
437 return jsUndefined();
438 return getDOMConstructor<JSWorkerConstructor>(exec);
439 #else
440 return jsUndefined();
441 #endif
442 }
443
jsDOMWindowBaseXSLTProcessor(ExecState * exec,const Identifier &,const PropertySlot & slot)444 JSValuePtr jsDOMWindowBaseXSLTProcessor(ExecState* exec, const Identifier&, const PropertySlot& slot)
445 {
446 #if ENABLE(XSLT)
447 if (!static_cast<JSDOMWindowBase*>(asObject(slot.slotBase()))->allowsAccessFrom(exec))
448 return jsUndefined();
449 return getDOMConstructor<JSXSLTProcessorConstructor>(exec);
450 #else
451 return jsUndefined();
452 #endif
453 }
454
setJSDOMWindowBaseEvent(ExecState * exec,JSObject * thisObject,JSValuePtr value)455 void setJSDOMWindowBaseEvent(ExecState* exec, JSObject* thisObject, JSValuePtr value)
456 {
457 if (!static_cast<JSDOMWindowBase*>(thisObject)->allowsAccessFrom(exec))
458 return;
459 // Shadowing a built-in constructor
460 static_cast<JSDOMWindowBase*>(thisObject)->putDirect(Identifier(exec, "Event"), value);
461 }
462
setJSDOMWindowBaseAudio(ExecState * exec,JSObject * thisObject,JSValuePtr value)463 void setJSDOMWindowBaseAudio(ExecState* exec, JSObject* thisObject, JSValuePtr value)
464 {
465 if (!static_cast<JSDOMWindowBase*>(thisObject)->allowsAccessFrom(exec))
466 return;
467 // Shadowing a built-in constructor
468 static_cast<JSDOMWindowBase*>(thisObject)->putDirect(Identifier(exec, "Audio"), value);
469 }
470
setJSDOMWindowBaseImage(ExecState * exec,JSObject * thisObject,JSValuePtr value)471 void setJSDOMWindowBaseImage(ExecState* exec, JSObject* thisObject, JSValuePtr value)
472 {
473 if (!static_cast<JSDOMWindowBase*>(thisObject)->allowsAccessFrom(exec))
474 return;
475 // Shadowing a built-in constructor
476 static_cast<JSDOMWindowBase*>(thisObject)->putDirect(Identifier(exec, "Image"), value);
477 }
478
setJSDOMWindowBaseMessageChannel(ExecState * exec,JSObject * thisObject,JSValuePtr value)479 void setJSDOMWindowBaseMessageChannel(ExecState* exec, JSObject* thisObject, JSValuePtr value)
480 {
481 if (!static_cast<JSDOMWindowBase*>(thisObject)->allowsAccessFrom(exec))
482 return;
483 // Shadowing a built-in constructor
484 static_cast<JSDOMWindowBase*>(thisObject)->putDirect(Identifier(exec, "MessageChannel"), value);
485 }
486
setJSDOMWindowBaseOption(ExecState * exec,JSObject * thisObject,JSValuePtr value)487 void setJSDOMWindowBaseOption(ExecState* exec, JSObject* thisObject, JSValuePtr value)
488 {
489 if (!static_cast<JSDOMWindowBase*>(thisObject)->allowsAccessFrom(exec))
490 return;
491 // Shadowing a built-in constructor
492 static_cast<JSDOMWindowBase*>(thisObject)->putDirect(Identifier(exec, "Option"), value);
493 }
494
setJSDOMWindowBaseWorker(ExecState * exec,JSObject * thisObject,JSValuePtr value)495 void setJSDOMWindowBaseWorker(ExecState* exec, JSObject* thisObject, JSValuePtr value)
496 {
497 if (!static_cast<JSDOMWindowBase*>(thisObject)->allowsAccessFrom(exec))
498 return;
499 // Shadowing a built-in constructor
500 static_cast<JSDOMWindowBase*>(thisObject)->putDirect(Identifier(exec, "Worker"), value);
501 }
502
setJSDOMWindowBaseWebKitCSSMatrix(ExecState * exec,JSObject * thisObject,JSValuePtr value)503 void setJSDOMWindowBaseWebKitCSSMatrix(ExecState* exec, JSObject* thisObject, JSValuePtr value)
504 {
505 if (!static_cast<JSDOMWindowBase*>(thisObject)->allowsAccessFrom(exec))
506 return;
507 // Shadowing a built-in constructor
508 static_cast<JSDOMWindowBase*>(thisObject)->putDirect(Identifier(exec, "WebKitCSSMatrix"), value);
509 }
510
setJSDOMWindowBaseXMLHttpRequest(ExecState * exec,JSObject * thisObject,JSValuePtr value)511 void setJSDOMWindowBaseXMLHttpRequest(ExecState* exec, JSObject* thisObject, JSValuePtr value)
512 {
513 if (!static_cast<JSDOMWindowBase*>(thisObject)->allowsAccessFrom(exec))
514 return;
515 // Shadowing a built-in constructor
516 static_cast<JSDOMWindowBase*>(thisObject)->putDirect(Identifier(exec, "XMLHttpRequest"), value);
517 }
518
setJSDOMWindowBaseXSLTProcessor(ExecState * exec,JSObject * thisObject,JSValuePtr value)519 void setJSDOMWindowBaseXSLTProcessor(ExecState* exec, JSObject* thisObject, JSValuePtr value)
520 {
521 if (!static_cast<JSDOMWindowBase*>(thisObject)->allowsAccessFrom(exec))
522 return;
523 // Shadowing a built-in constructor
524 static_cast<JSDOMWindowBase*>(thisObject)->putDirect(Identifier(exec, "XSLTProcessor"), value);
525 }
526
527 namespace WebCore {
528
childFrameGetter(ExecState * exec,const Identifier & propertyName,const PropertySlot & slot)529 JSValuePtr JSDOMWindowBase::childFrameGetter(ExecState* exec, const Identifier& propertyName, const PropertySlot& slot)
530 {
531 return toJS(exec, static_cast<JSDOMWindowBase*>(asObject(slot.slotBase()))->impl()->frame()->tree()->child(AtomicString(propertyName))->domWindow());
532 }
533
indexGetter(ExecState * exec,const Identifier &,const PropertySlot & slot)534 JSValuePtr JSDOMWindowBase::indexGetter(ExecState* exec, const Identifier&, const PropertySlot& slot)
535 {
536 return toJS(exec, static_cast<JSDOMWindowBase*>(asObject(slot.slotBase()))->impl()->frame()->tree()->child(slot.index())->domWindow());
537 }
538
namedItemGetter(ExecState * exec,const Identifier & propertyName,const PropertySlot & slot)539 JSValuePtr JSDOMWindowBase::namedItemGetter(ExecState* exec, const Identifier& propertyName, const PropertySlot& slot)
540 {
541 JSDOMWindowBase* thisObj = static_cast<JSDOMWindowBase*>(asObject(slot.slotBase()));
542 Document* doc = thisObj->impl()->frame()->document();
543 ASSERT(thisObj->allowsAccessFrom(exec));
544 ASSERT(doc);
545 ASSERT(doc->isHTMLDocument());
546
547 RefPtr<HTMLCollection> collection = doc->windowNamedItems(propertyName);
548 if (collection->length() == 1)
549 return toJS(exec, collection->firstItem());
550 return toJS(exec, collection.get());
551 }
552
getOwnPropertySlot(ExecState * exec,const Identifier & propertyName,PropertySlot & slot)553 bool JSDOMWindowBase::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
554 {
555 // Check for child frames by name before built-in properties to
556 // match Mozilla. This does not match IE, but some sites end up
557 // naming frames things that conflict with window properties that
558 // are in Moz but not IE. Since we have some of these, we have to do
559 // it the Moz way.
560 if (impl()->frame()->tree()->child(propertyName)) {
561 slot.setCustom(this, childFrameGetter);
562 return true;
563 }
564
565 const HashEntry* entry = JSDOMWindowBaseTable.entry(exec, propertyName);
566 if (entry) {
567 if (entry->attributes() & Function) {
568 if (entry->function() == windowProtoFuncShowModalDialog) {
569 if (!canShowModalDialog(impl()->frame()))
570 return false;
571 }
572 if (allowsAccessFrom(exec))
573 setUpStaticFunctionSlot(exec, entry, this, propertyName, slot);
574 else
575 slot.setUndefined();
576 } else
577 slot.setCustom(this, entry->propertyGetter());
578 return true;
579 }
580
581 // Do prototype lookup early so that functions and attributes in the prototype can have
582 // precedence over the index and name getters.
583 JSValuePtr proto = prototype();
584 if (proto.isObject()) {
585 if (asObject(proto)->getPropertySlot(exec, propertyName, slot)) {
586 if (!allowsAccessFrom(exec))
587 slot.setUndefined();
588 return true;
589 }
590 }
591
592 // FIXME: Search the whole frame hierachy somewhere around here.
593 // We need to test the correct priority order.
594
595 // allow window[1] or parent[1] etc. (#56983)
596 bool ok;
597 unsigned i = propertyName.toArrayIndex(&ok);
598 if (ok && i < impl()->frame()->tree()->childCount()) {
599 slot.setCustomIndex(this, i, indexGetter);
600 return true;
601 }
602
603 if (!allowsAccessFrom(exec)) {
604 slot.setUndefined();
605 return true;
606 }
607
608 // Allow shortcuts like 'Image1' instead of document.images.Image1
609 Document* document = impl()->frame()->document();
610 if (document && document->isHTMLDocument()) {
611 AtomicStringImpl* atomicPropertyName = AtomicString::find(propertyName);
612 if (atomicPropertyName && (static_cast<HTMLDocument*>(document)->hasNamedItem(atomicPropertyName) || document->hasElementWithId(atomicPropertyName))) {
613 slot.setCustom(this, namedItemGetter);
614 return true;
615 }
616 }
617
618 return Base::getOwnPropertySlot(exec, propertyName, slot);
619 }
620
put(ExecState * exec,const Identifier & propertyName,JSValuePtr value,PutPropertySlot & slot)621 void JSDOMWindowBase::put(ExecState* exec, const Identifier& propertyName, JSValuePtr value, PutPropertySlot& slot)
622 {
623 const HashEntry* entry = JSDOMWindowBaseTable.entry(exec, propertyName);
624 if (entry) {
625 if (entry->attributes() & Function) {
626 if (allowsAccessFrom(exec))
627 Base::put(exec, propertyName, value, slot);
628 return;
629 }
630 if (entry->attributes() & ReadOnly)
631 return;
632 }
633
634 if (allowsAccessFrom(exec))
635 Base::put(exec, propertyName, value, slot);
636 }
637
crossDomainAccessErrorMessage(const JSGlobalObject * other) const638 String JSDOMWindowBase::crossDomainAccessErrorMessage(const JSGlobalObject* other) const
639 {
640 KURL originURL = asJSDOMWindow(other)->impl()->url();
641 KURL targetURL = impl()->frame()->document()->url();
642 if (originURL.isNull() || targetURL.isNull())
643 return String();
644
645 // FIXME: this error message should contain more specifics of why the same origin check has failed.
646 return String::format("Unsafe JavaScript attempt to access frame with URL %s from frame with URL %s. Domains, protocols and ports must match.\n",
647 targetURL.string().utf8().data(), originURL.string().utf8().data());
648 }
649
printErrorMessage(const String & message) const650 void JSDOMWindowBase::printErrorMessage(const String& message) const
651 {
652 if (message.isEmpty())
653 return;
654
655 Frame* frame = impl()->frame();
656 if (!frame)
657 return;
658
659 Settings* settings = frame->settings();
660 if (!settings)
661 return;
662
663 if (settings->privateBrowsingEnabled())
664 return;
665
666 impl()->console()->addMessage(JSMessageSource, ErrorMessageLevel, message, 1, String()); // FIXME: provide a real line number and source URL.
667 }
668
globalExec()669 ExecState* JSDOMWindowBase::globalExec()
670 {
671 // We need to make sure that any script execution happening in this
672 // frame does not destroy it
673 if (Frame *frame = impl()->frame())
674 frame->keepAlive();
675 return Base::globalExec();
676 }
677
supportsProfiling() const678 bool JSDOMWindowBase::supportsProfiling() const
679 {
680 Frame* frame = impl()->frame();
681 if (!frame)
682 return false;
683
684 Page* page = frame->page();
685 if (!page)
686 return false;
687
688 return page->inspectorController()->profilerEnabled();
689 }
690
shouldInterruptScript() const691 bool JSDOMWindowBase::shouldInterruptScript() const
692 {
693 ASSERT(impl()->frame());
694 Page* page = impl()->frame()->page();
695
696 // See <rdar://problem/5479443>. We don't think that page can ever be NULL
697 // in this case, but if it is, we've gotten into a state where we may have
698 // hung the UI, with no way to ask the client whether to cancel execution.
699 // For now, our solution is just to cancel execution no matter what,
700 // ensuring that we never hang. We might want to consider other solutions
701 // if we discover problems with this one.
702 ASSERT(page);
703 if (!page)
704 return true;
705
706 return page->chrome()->shouldInterruptJavaScript();
707 }
708
clearHelperObjectProperties()709 void JSDOMWindowBase::clearHelperObjectProperties()
710 {
711 setCurrentEvent(0);
712 }
713
clear()714 void JSDOMWindowBase::clear()
715 {
716 JSLock lock(false);
717
718 if (d()->returnValueSlot && !*d()->returnValueSlot)
719 *d()->returnValueSlot = getDirect(Identifier(globalExec(), "returnValue"));
720
721 clearHelperObjectProperties();
722 }
723
toThisObject(ExecState *) const724 JSObject* JSDOMWindowBase::toThisObject(ExecState*) const
725 {
726 return shell();
727 }
728
shell() const729 JSDOMWindowShell* JSDOMWindowBase::shell() const
730 {
731 return d()->shell;
732 }
733
commonJSGlobalData()734 JSGlobalData* JSDOMWindowBase::commonJSGlobalData()
735 {
736 static JSGlobalData* globalData = JSGlobalData::createLeaked().releaseRef();
737 return globalData;
738 }
739
740 } // namespace WebCore
741
742 using namespace WebCore;
743
windowProtoFuncOpen(ExecState * exec,JSObject *,JSValuePtr thisValue,const ArgList & args)744 JSValuePtr windowProtoFuncOpen(ExecState* exec, JSObject*, JSValuePtr thisValue, const ArgList& args)
745 {
746 JSDOMWindow* window = toJSDOMWindow(thisValue);
747 if (!window)
748 return throwError(exec, TypeError);
749 if (!window->allowsAccessFrom(exec))
750 return jsUndefined();
751
752 Frame* frame = window->impl()->frame();
753 if (!frame)
754 return jsUndefined();
755 Frame* activeFrame = asJSDOMWindow(exec->dynamicGlobalObject())->impl()->frame();
756 if (!activeFrame)
757 return jsUndefined();
758
759 Page* page = frame->page();
760
761 String urlString = valueToStringWithUndefinedOrNullCheck(exec, args.at(exec, 0));
762 AtomicString frameName = args.at(exec, 1).isUndefinedOrNull() ? "_blank" : AtomicString(args.at(exec, 1).toString(exec));
763
764 // Because FrameTree::find() returns true for empty strings, we must check for empty framenames.
765 // Otherwise, illegitimate window.open() calls with no name will pass right through the popup blocker.
766 if (!allowPopUp(exec) && (frameName.isEmpty() || !frame->tree()->find(frameName)))
767 return jsUndefined();
768
769 // Get the target frame for the special cases of _top and _parent. In those
770 // cases, we can schedule a location change right now and return early.
771 bool topOrParent = false;
772 if (frameName == "_top") {
773 frame = frame->tree()->top();
774 topOrParent = true;
775 } else if (frameName == "_parent") {
776 if (Frame* parent = frame->tree()->parent())
777 frame = parent;
778 topOrParent = true;
779 }
780 if (topOrParent) {
781 if (!activeFrame->loader()->shouldAllowNavigation(frame))
782 return jsUndefined();
783
784 String completedURL;
785 if (!urlString.isEmpty())
786 completedURL = activeFrame->document()->completeURL(urlString).string();
787
788 const JSDOMWindow* targetedWindow = toJSDOMWindow(frame);
789 if (!completedURL.isEmpty() && (!protocolIs(completedURL, "javascript") || (targetedWindow && targetedWindow->allowsAccessFrom(exec)))) {
790 bool userGesture = activeFrame->script()->processingUserGesture();
791 frame->loader()->scheduleLocationChange(completedURL, activeFrame->loader()->outgoingReferrer(), !activeFrame->script()->anyPageIsProcessingUserGesture(), false, userGesture);
792 }
793 return toJS(exec, frame->domWindow());
794 }
795
796 // In the case of a named frame or a new window, we'll use the createWindow() helper
797 WindowFeatures windowFeatures(valueToStringWithUndefinedOrNullCheck(exec, args.at(exec, 2)));
798 FloatRect windowRect(windowFeatures.xSet ? windowFeatures.x : 0, windowFeatures.ySet ? windowFeatures.y : 0,
799 windowFeatures.widthSet ? windowFeatures.width : 0, windowFeatures.heightSet ? windowFeatures.height : 0);
800 DOMWindow::adjustWindowRect(screenAvailableRect(page ? page->mainFrame()->view() : 0), windowRect, windowRect);
801
802 windowFeatures.x = windowRect.x();
803 windowFeatures.y = windowRect.y();
804 windowFeatures.height = windowRect.height();
805 windowFeatures.width = windowRect.width();
806
807 frame = createWindow(exec, frame, urlString, frameName, windowFeatures, noValue());
808
809 if (!frame)
810 return jsUndefined();
811
812 return toJS(exec, frame->domWindow()); // global object
813 }
814
windowProtoFuncShowModalDialog(ExecState * exec,JSObject *,JSValuePtr thisValue,const ArgList & args)815 JSValuePtr windowProtoFuncShowModalDialog(ExecState* exec, JSObject*, JSValuePtr thisValue, const ArgList& args)
816 {
817 JSDOMWindow* window = toJSDOMWindow(thisValue);
818 if (!window)
819 return throwError(exec, TypeError);
820 if (!window->allowsAccessFrom(exec))
821 return jsUndefined();
822
823 Frame* frame = window->impl()->frame();
824 if (!frame)
825 return jsUndefined();
826
827 return showModalDialog(exec, frame, valueToStringWithUndefinedOrNullCheck(exec, args.at(exec, 0)), args.at(exec, 1), valueToStringWithUndefinedOrNullCheck(exec, args.at(exec, 2)));
828 }
829
windowProtoFuncNotImplemented(ExecState * exec,JSObject *,JSValuePtr thisValue,const ArgList &)830 JSValuePtr windowProtoFuncNotImplemented(ExecState* exec, JSObject*, JSValuePtr thisValue, const ArgList&)
831 {
832 if (!toJSDOMWindow(thisValue))
833 return throwError(exec, TypeError);
834 return jsUndefined();
835 }
836
837 namespace WebCore {
838
setReturnValueSlot(JSValuePtr * slot)839 void JSDOMWindowBase::setReturnValueSlot(JSValuePtr* slot)
840 {
841 d()->returnValueSlot = slot;
842 }
843
844 ////////////////////// timeouts ////////////////////////
845
installTimeout(ScheduledAction * a,int t,bool singleShot)846 int JSDOMWindowBase::installTimeout(ScheduledAction* a, int t, bool singleShot)
847 {
848 return DOMTimer::install(scriptExecutionContext(), a, t, singleShot);
849 }
850
installTimeout(const UString & handler,int t,bool singleShot)851 int JSDOMWindowBase::installTimeout(const UString& handler, int t, bool singleShot)
852 {
853 return installTimeout(new ScheduledAction(handler), t, singleShot);
854 }
855
installTimeout(ExecState * exec,JSValuePtr func,const ArgList & args,int t,bool singleShot)856 int JSDOMWindowBase::installTimeout(ExecState* exec, JSValuePtr func, const ArgList& args, int t, bool singleShot)
857 {
858 return installTimeout(new ScheduledAction(exec, func, args), t, singleShot);
859 }
860
removeTimeout(int timeoutId)861 void JSDOMWindowBase::removeTimeout(int timeoutId)
862 {
863 DOMTimer::removeById(scriptExecutionContext(), timeoutId);
864 }
865
disconnectFrame()866 void JSDOMWindowBase::disconnectFrame()
867 {
868 }
869
toJS(ExecState *,DOMWindow * domWindow)870 JSValuePtr toJS(ExecState*, DOMWindow* domWindow)
871 {
872 if (!domWindow)
873 return jsNull();
874 Frame* frame = domWindow->frame();
875 if (!frame)
876 return jsNull();
877 return frame->script()->windowShell();
878 }
879
toJSDOMWindow(Frame * frame)880 JSDOMWindow* toJSDOMWindow(Frame* frame)
881 {
882 if (!frame)
883 return 0;
884 return frame->script()->windowShell()->window();
885 }
886
toJSDOMWindow(JSValuePtr value)887 JSDOMWindow* toJSDOMWindow(JSValuePtr value)
888 {
889 if (!value.isObject())
890 return 0;
891 const ClassInfo* classInfo = asObject(value)->classInfo();
892 if (classInfo == &JSDOMWindow::s_info)
893 return static_cast<JSDOMWindow*>(asObject(value));
894 if (classInfo == &JSDOMWindowShell::s_info)
895 return static_cast<JSDOMWindowShell*>(asObject(value))->window();
896 return 0;
897 }
898
899 } // namespace WebCore
900