• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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