Change incorrect calls to the constructor "EventNames()" to the correct accessor
[WebKit-https.git] / WebCore / page / DOMWindow.cpp
1 /*
2  * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27 #include "DOMWindow.h"
28
29 #include "BarInfo.h"
30 #include "BeforeUnloadEvent.h"
31 #include "CSSComputedStyleDeclaration.h"
32 #include "CSSRuleList.h"
33 #include "CSSStyleSelector.h"
34 #include "CString.h"
35 #include "Chrome.h"
36 #include "Console.h"
37 #include "Database.h"
38 #include "DOMApplicationCache.h"
39 #include "DOMSelection.h"
40 #include "DOMTimer.h"
41 #include "PageTransitionEvent.h"
42 #include "Document.h"
43 #include "Element.h"
44 #include "EventException.h"
45 #include "EventListener.h"
46 #include "EventNames.h"
47 #include "ExceptionCode.h"
48 #include "FloatRect.h"
49 #include "Frame.h"
50 #include "FrameLoader.h"
51 #include "FrameTree.h"
52 #include "FrameView.h"
53 #include "HTMLFrameOwnerElement.h"
54 #include "History.h"
55 #include "InspectorController.h"
56 #include "InspectorTimelineAgent.h"
57 #include "Location.h"
58 #include "Media.h"
59 #include "MessageEvent.h"
60 #include "Navigator.h"
61 #include "NotificationCenter.h"
62 #include "Page.h"
63 #include "PageGroup.h"
64 #include "PlatformScreen.h"
65 #include "PlatformString.h"
66 #include "Screen.h"
67 #include "SecurityOrigin.h"
68 #include "SerializedScriptValue.h"
69 #include "Settings.h"
70 #include "Storage.h"
71 #include "StorageArea.h"
72 #include "StorageNamespace.h"
73 #include "SuddenTermination.h"
74 #include "WebKitPoint.h"
75 #include <algorithm>
76 #include <wtf/MathExtras.h>
77
78 using std::min;
79 using std::max;
80
81 namespace WebCore {
82
83 class PostMessageTimer : public TimerBase {
84 public:
85     PostMessageTimer(DOMWindow* window, PassRefPtr<SerializedScriptValue> message, const String& sourceOrigin, PassRefPtr<DOMWindow> source, PassOwnPtr<MessagePortChannelArray> channels, SecurityOrigin* targetOrigin)
86         : m_window(window)
87         , m_message(message)
88         , m_origin(sourceOrigin)
89         , m_source(source)
90         , m_channels(channels)
91         , m_targetOrigin(targetOrigin)
92     {
93     }
94
95     PassRefPtr<MessageEvent> event(ScriptExecutionContext* context)
96     {
97         OwnPtr<MessagePortArray> messagePorts = MessagePort::entanglePorts(*context, m_channels.release());
98         return MessageEvent::create(messagePorts.release(), m_message, m_origin, "", m_source);
99     }
100     SecurityOrigin* targetOrigin() const { return m_targetOrigin.get(); }
101
102 private:
103     virtual void fired()
104     {
105         m_window->postMessageTimerFired(this);
106     }
107
108     RefPtr<DOMWindow> m_window;
109     RefPtr<SerializedScriptValue> m_message;
110     String m_origin;
111     RefPtr<DOMWindow> m_source;
112     OwnPtr<MessagePortChannelArray> m_channels;
113     RefPtr<SecurityOrigin> m_targetOrigin;
114 };
115
116 typedef HashCountedSet<DOMWindow*> DOMWindowSet;
117
118 static DOMWindowSet& windowsWithUnloadEventListeners()
119 {
120     DEFINE_STATIC_LOCAL(DOMWindowSet, windowsWithUnloadEventListeners, ());
121     return windowsWithUnloadEventListeners;
122 }
123
124 static DOMWindowSet& windowsWithBeforeUnloadEventListeners()
125 {
126     DEFINE_STATIC_LOCAL(DOMWindowSet, windowsWithBeforeUnloadEventListeners, ());
127     return windowsWithBeforeUnloadEventListeners;
128 }
129
130 static void addUnloadEventListener(DOMWindow* domWindow)
131 {
132     DOMWindowSet& set = windowsWithUnloadEventListeners();
133     if (set.isEmpty())
134         disableSuddenTermination();
135     set.add(domWindow);
136 }
137
138 static void removeUnloadEventListener(DOMWindow* domWindow)
139 {
140     DOMWindowSet& set = windowsWithUnloadEventListeners();
141     DOMWindowSet::iterator it = set.find(domWindow);
142     if (it == set.end())
143         return;
144     set.remove(it);
145     if (set.isEmpty())
146         enableSuddenTermination();
147 }
148
149 static void removeAllUnloadEventListeners(DOMWindow* domWindow)
150 {
151     DOMWindowSet& set = windowsWithUnloadEventListeners();
152     DOMWindowSet::iterator it = set.find(domWindow);
153     if (it == set.end())
154         return;
155     set.removeAll(it);
156     if (set.isEmpty())
157         enableSuddenTermination();
158 }
159
160 static void addBeforeUnloadEventListener(DOMWindow* domWindow)
161 {
162     DOMWindowSet& set = windowsWithBeforeUnloadEventListeners();
163     if (set.isEmpty())
164         disableSuddenTermination();
165     set.add(domWindow);
166 }
167
168 static void removeBeforeUnloadEventListener(DOMWindow* domWindow)
169 {
170     DOMWindowSet& set = windowsWithBeforeUnloadEventListeners();
171     DOMWindowSet::iterator it = set.find(domWindow);
172     if (it == set.end())
173         return;
174     set.remove(it);
175     if (set.isEmpty())
176         enableSuddenTermination();
177 }
178
179 static void removeAllBeforeUnloadEventListeners(DOMWindow* domWindow)
180 {
181     DOMWindowSet& set = windowsWithBeforeUnloadEventListeners();
182     DOMWindowSet::iterator it = set.find(domWindow);
183     if (it == set.end())
184         return;
185     set.removeAll(it);
186     if (set.isEmpty())
187         enableSuddenTermination();
188 }
189
190 static bool allowsBeforeUnloadListeners(DOMWindow* window)
191 {
192     ASSERT_ARG(window, window);
193     Frame* frame = window->frame();
194     if (!frame)
195         return false;
196     Page* page = frame->page();
197     if (!page)
198         return false;
199     return frame == page->mainFrame();
200 }
201
202 bool DOMWindow::dispatchAllPendingBeforeUnloadEvents()
203 {
204     DOMWindowSet& set = windowsWithBeforeUnloadEventListeners();
205     if (set.isEmpty())
206         return true;
207
208     static bool alreadyDispatched = false;
209     ASSERT(!alreadyDispatched);
210     if (alreadyDispatched)
211         return true;
212
213     Vector<RefPtr<DOMWindow> > windows;
214     DOMWindowSet::iterator end = set.end();
215     for (DOMWindowSet::iterator it = set.begin(); it != end; ++it)
216         windows.append(it->first);
217
218     size_t size = windows.size();
219     for (size_t i = 0; i < size; ++i) {
220         DOMWindow* window = windows[i].get();
221         if (!set.contains(window))
222             continue;
223
224         Frame* frame = window->frame();
225         if (!frame)
226             continue;
227
228         if (!frame->shouldClose())
229             return false;
230     }
231
232     enableSuddenTermination();
233
234     alreadyDispatched = true;
235
236     return true;
237 }
238
239 unsigned DOMWindow::pendingUnloadEventListeners() const
240 {
241     return windowsWithUnloadEventListeners().count(const_cast<DOMWindow*>(this));
242 }
243
244 void DOMWindow::dispatchAllPendingUnloadEvents()
245 {
246     DOMWindowSet& set = windowsWithUnloadEventListeners();
247     if (set.isEmpty())
248         return;
249
250     static bool alreadyDispatched = false;
251     ASSERT(!alreadyDispatched);
252     if (alreadyDispatched)
253         return;
254
255     Vector<RefPtr<DOMWindow> > windows;
256     DOMWindowSet::iterator end = set.end();
257     for (DOMWindowSet::iterator it = set.begin(); it != end; ++it)
258         windows.append(it->first);
259
260     size_t size = windows.size();
261     for (size_t i = 0; i < size; ++i) {
262         DOMWindow* window = windows[i].get();
263         if (!set.contains(window))
264             continue;
265
266         window->dispatchEvent(PageTransitionEvent::create(eventNames().pagehideEvent, false), window->document());
267         window->dispatchEvent(Event::create(eventNames().unloadEvent, false, false), window->document());
268     }
269
270     enableSuddenTermination();
271
272     alreadyDispatched = true;
273 }
274
275 // This function:
276 // 1) Validates the pending changes are not changing to NaN
277 // 2) Constrains the window rect to no smaller than 100 in each dimension and no
278 //    bigger than the the float rect's dimensions.
279 // 3) Constrain window rect to within the top and left boundaries of the screen rect
280 // 4) Constraint the window rect to within the bottom and right boundaries of the
281 //    screen rect.
282 // 5) Translate the window rect coordinates to be within the coordinate space of
283 //    the screen rect.
284 void DOMWindow::adjustWindowRect(const FloatRect& screen, FloatRect& window, const FloatRect& pendingChanges)
285 {
286     // Make sure we're in a valid state before adjusting dimensions.
287     ASSERT(isfinite(screen.x()));
288     ASSERT(isfinite(screen.y()));
289     ASSERT(isfinite(screen.width()));
290     ASSERT(isfinite(screen.height()));
291     ASSERT(isfinite(window.x()));
292     ASSERT(isfinite(window.y()));
293     ASSERT(isfinite(window.width()));
294     ASSERT(isfinite(window.height()));
295     
296     // Update window values if new requested values are not NaN.
297     if (!isnan(pendingChanges.x()))
298         window.setX(pendingChanges.x());
299     if (!isnan(pendingChanges.y()))
300         window.setY(pendingChanges.y());
301     if (!isnan(pendingChanges.width()))
302         window.setWidth(pendingChanges.width());
303     if (!isnan(pendingChanges.height()))
304         window.setHeight(pendingChanges.height());
305     
306     // Resize the window to between 100 and the screen width and height.
307     window.setWidth(min(max(100.0f, window.width()), screen.width()));
308     window.setHeight(min(max(100.0f, window.height()), screen.height()));
309     
310     // Constrain the window position to the screen.
311     window.setX(max(screen.x(), min(window.x(), screen.right() - window.width())));
312     window.setY(max(screen.y(), min(window.y(), screen.bottom() - window.height())));
313 }
314
315 void DOMWindow::parseModalDialogFeatures(const String& featuresArg, HashMap<String, String>& map)
316 {
317     Vector<String> features;
318     featuresArg.split(';', features);
319     Vector<String>::const_iterator end = features.end();
320     for (Vector<String>::const_iterator it = features.begin(); it != end; ++it) {
321         String s = *it;
322         int pos = s.find('=');
323         int colonPos = s.find(':');
324         if (pos >= 0 && colonPos >= 0)
325             continue; // ignore any strings that have both = and :
326         if (pos < 0)
327             pos = colonPos;
328         if (pos < 0) {
329             // null string for value means key without value
330             map.set(s.stripWhiteSpace().lower(), String());
331         } else {
332             String key = s.left(pos).stripWhiteSpace().lower();
333             String val = s.substring(pos + 1).stripWhiteSpace().lower();
334             int spacePos = val.find(' ');
335             if (spacePos != -1)
336                 val = val.left(spacePos);
337             map.set(key, val);
338         }
339     }
340 }
341
342 bool DOMWindow::allowPopUp(Frame* activeFrame)
343 {
344     ASSERT(activeFrame);
345     if (activeFrame->script()->processingUserGesture())
346         return true;
347     Settings* settings = activeFrame->settings();
348     return settings && settings->javaScriptCanOpenWindowsAutomatically();
349 }
350
351 bool DOMWindow::canShowModalDialog(const Frame* frame)
352 {
353     if (!frame)
354         return false;
355     Page* page = frame->page();
356     if (!page)
357         return false;
358     return page->chrome()->canRunModal();
359 }
360
361 bool DOMWindow::canShowModalDialogNow(const Frame* frame)
362 {
363     if (!frame)
364         return false;
365     Page* page = frame->page();
366     if (!page)
367         return false;
368     return page->chrome()->canRunModalNow();
369 }
370
371 DOMWindow::DOMWindow(Frame* frame)
372     : m_frame(frame)
373 {
374 }
375
376 DOMWindow::~DOMWindow()
377 {
378     if (m_frame)
379         m_frame->clearFormerDOMWindow(this);
380
381     removeAllUnloadEventListeners(this);
382     removeAllBeforeUnloadEventListeners(this);
383 }
384
385 ScriptExecutionContext* DOMWindow::scriptExecutionContext() const
386 {
387     return document();
388 }
389
390 void DOMWindow::disconnectFrame()
391 {
392     m_frame = 0;
393     clear();
394 }
395
396 void DOMWindow::clear()
397 {
398     if (m_screen)
399         m_screen->disconnectFrame();
400     m_screen = 0;
401
402     if (m_selection)
403         m_selection->disconnectFrame();
404     m_selection = 0;
405
406     if (m_history)
407         m_history->disconnectFrame();
408     m_history = 0;
409
410     if (m_locationbar)
411         m_locationbar->disconnectFrame();
412     m_locationbar = 0;
413
414     if (m_menubar)
415         m_menubar->disconnectFrame();
416     m_menubar = 0;
417
418     if (m_personalbar)
419         m_personalbar->disconnectFrame();
420     m_personalbar = 0;
421
422     if (m_scrollbars)
423         m_scrollbars->disconnectFrame();
424     m_scrollbars = 0;
425
426     if (m_statusbar)
427         m_statusbar->disconnectFrame();
428     m_statusbar = 0;
429
430     if (m_toolbar)
431         m_toolbar->disconnectFrame();
432     m_toolbar = 0;
433
434     if (m_console)
435         m_console->disconnectFrame();
436     m_console = 0;
437
438     if (m_navigator)
439         m_navigator->disconnectFrame();
440     m_navigator = 0;
441
442     if (m_location)
443         m_location->disconnectFrame();
444     m_location = 0;
445     
446 #if ENABLE(DOM_STORAGE)
447     if (m_sessionStorage)
448         m_sessionStorage->disconnectFrame();
449     m_sessionStorage = 0;
450
451     if (m_localStorage)
452         m_localStorage->disconnectFrame();
453     m_localStorage = 0;
454 #endif
455
456 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
457     if (m_applicationCache)
458         m_applicationCache->disconnectFrame();
459     m_applicationCache = 0;
460 #endif
461
462 #if ENABLE(NOTIFICATIONS)
463     m_notifications = 0;
464 #endif
465 }
466
467 #if ENABLE(ORIENTATION_EVENTS)
468 int DOMWindow::orientation() const
469 {
470     if (!m_frame)
471         return 0;
472     
473     return m_frame->orientation();
474 }
475 #endif
476
477 Screen* DOMWindow::screen() const
478 {
479     if (!m_screen)
480         m_screen = Screen::create(m_frame);
481     return m_screen.get();
482 }
483
484 History* DOMWindow::history() const
485 {
486     if (!m_history)
487         m_history = History::create(m_frame);
488     return m_history.get();
489 }
490
491 BarInfo* DOMWindow::locationbar() const
492 {
493     if (!m_locationbar)
494         m_locationbar = BarInfo::create(m_frame, BarInfo::Locationbar);
495     return m_locationbar.get();
496 }
497
498 BarInfo* DOMWindow::menubar() const
499 {
500     if (!m_menubar)
501         m_menubar = BarInfo::create(m_frame, BarInfo::Menubar);
502     return m_menubar.get();
503 }
504
505 BarInfo* DOMWindow::personalbar() const
506 {
507     if (!m_personalbar)
508         m_personalbar = BarInfo::create(m_frame, BarInfo::Personalbar);
509     return m_personalbar.get();
510 }
511
512 BarInfo* DOMWindow::scrollbars() const
513 {
514     if (!m_scrollbars)
515         m_scrollbars = BarInfo::create(m_frame, BarInfo::Scrollbars);
516     return m_scrollbars.get();
517 }
518
519 BarInfo* DOMWindow::statusbar() const
520 {
521     if (!m_statusbar)
522         m_statusbar = BarInfo::create(m_frame, BarInfo::Statusbar);
523     return m_statusbar.get();
524 }
525
526 BarInfo* DOMWindow::toolbar() const
527 {
528     if (!m_toolbar)
529         m_toolbar = BarInfo::create(m_frame, BarInfo::Toolbar);
530     return m_toolbar.get();
531 }
532
533 Console* DOMWindow::console() const
534 {
535     if (!m_console)
536         m_console = Console::create(m_frame);
537     return m_console.get();
538 }
539
540 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
541 DOMApplicationCache* DOMWindow::applicationCache() const
542 {
543     if (!m_applicationCache)
544         m_applicationCache = DOMApplicationCache::create(m_frame);
545     return m_applicationCache.get();
546 }
547 #endif
548
549 Navigator* DOMWindow::navigator() const
550 {
551     if (!m_navigator)
552         m_navigator = Navigator::create(m_frame);
553     return m_navigator.get();
554 }
555
556 Location* DOMWindow::location() const
557 {
558     if (!m_location)
559         m_location = Location::create(m_frame);
560     return m_location.get();
561 }
562
563 #if ENABLE(DOM_STORAGE)
564 Storage* DOMWindow::sessionStorage() const
565 {
566     if (m_sessionStorage)
567         return m_sessionStorage.get();
568
569     Document* document = this->document();
570     if (!document)
571         return 0;
572
573     Page* page = document->page();
574     if (!page)
575         return 0;
576
577     RefPtr<StorageArea> storageArea = page->sessionStorage()->storageArea(document->securityOrigin());
578 #if ENABLE(INSPECTOR)
579     page->inspectorController()->didUseDOMStorage(storageArea.get(), false, m_frame);
580 #endif
581
582     m_sessionStorage = Storage::create(m_frame, storageArea.release());
583     return m_sessionStorage.get();
584 }
585
586 Storage* DOMWindow::localStorage() const
587 {
588     if (m_localStorage)
589         return m_localStorage.get();
590     
591     Document* document = this->document();
592     if (!document)
593         return 0;
594         
595     Page* page = document->page();
596     if (!page)
597         return 0;
598
599     if (!page->settings()->localStorageEnabled())
600         return 0;
601
602     RefPtr<StorageArea> storageArea = page->group().localStorage()->storageArea(document->securityOrigin());
603 #if ENABLE(INSPECTOR)
604     page->inspectorController()->didUseDOMStorage(storageArea.get(), true, m_frame);
605 #endif
606
607     m_localStorage = Storage::create(m_frame, storageArea.release());
608     return m_localStorage.get();
609 }
610 #endif
611
612 #if ENABLE(NOTIFICATIONS)
613 NotificationCenter* DOMWindow::webkitNotifications() const
614 {
615     if (m_notifications)
616         return m_notifications.get();
617
618     Document* document = this->document();
619     if (!document)
620         return 0;
621     
622     Page* page = document->page();
623     if (!page)
624         return 0;
625
626     NotificationPresenter* provider = page->chrome()->notificationPresenter();
627     if (provider) 
628         m_notifications = NotificationCenter::create(document, provider);    
629       
630     return m_notifications.get();
631 }
632 #endif
633
634 void DOMWindow::postMessage(PassRefPtr<SerializedScriptValue> message, MessagePort* port, const String& targetOrigin, DOMWindow* source, ExceptionCode& ec)
635 {
636     MessagePortArray ports;
637     if (port)
638         ports.append(port);
639     postMessage(message, &ports, targetOrigin, source, ec);
640 }
641
642 void DOMWindow::postMessage(PassRefPtr<SerializedScriptValue> message, const MessagePortArray* ports, const String& targetOrigin, DOMWindow* source, ExceptionCode& ec)
643 {
644     if (!m_frame)
645         return;
646
647     // Compute the target origin.  We need to do this synchronously in order
648     // to generate the SYNTAX_ERR exception correctly.
649     RefPtr<SecurityOrigin> target;
650     if (targetOrigin != "*") {
651         target = SecurityOrigin::createFromString(targetOrigin);
652         if (target->isEmpty()) {
653             ec = SYNTAX_ERR;
654             return;
655         }
656     }
657
658     OwnPtr<MessagePortChannelArray> channels = MessagePort::disentanglePorts(ports, ec);
659     if (ec)
660         return;
661
662     // Capture the source of the message.  We need to do this synchronously
663     // in order to capture the source of the message correctly.
664     Document* sourceDocument = source->document();
665     if (!sourceDocument)
666         return;
667     String sourceOrigin = sourceDocument->securityOrigin()->toString();
668
669     // Schedule the message.
670     PostMessageTimer* timer = new PostMessageTimer(this, message, sourceOrigin, source, channels.release(), target.get());
671     timer->startOneShot(0);
672 }
673
674 void DOMWindow::postMessageTimerFired(PostMessageTimer* t)
675 {
676     OwnPtr<PostMessageTimer> timer(t);
677
678     if (!document())
679         return;
680
681     if (timer->targetOrigin()) {
682         // Check target origin now since the target document may have changed since the simer was scheduled.
683         if (!timer->targetOrigin()->isSameSchemeHostPort(document()->securityOrigin())) {
684             String message = String::format("Unable to post message to %s. Recipient has origin %s.\n", 
685                 timer->targetOrigin()->toString().utf8().data(), document()->securityOrigin()->toString().utf8().data());
686             console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, message, 0, String());
687             return;
688         }
689     }
690
691     dispatchEvent(timer->event(document()));
692 }
693
694 DOMSelection* DOMWindow::getSelection()
695 {
696     if (!m_selection)
697         m_selection = DOMSelection::create(m_frame);
698     return m_selection.get();
699 }
700
701 Element* DOMWindow::frameElement() const
702 {
703     if (!m_frame)
704         return 0;
705
706     return m_frame->ownerElement();
707 }
708
709 void DOMWindow::focus()
710 {
711     if (!m_frame)
712         return;
713
714     m_frame->focusWindow();
715 }
716
717 void DOMWindow::blur()
718 {
719     if (!m_frame)
720         return;
721
722     m_frame->unfocusWindow();
723 }
724
725 void DOMWindow::close()
726 {
727     if (!m_frame)
728         return;
729
730     Page* page = m_frame->page();
731     if (!page)
732         return;
733
734     if (m_frame != page->mainFrame())
735         return;
736
737     Settings* settings = m_frame->settings();
738     bool allowScriptsToCloseWindows = settings && settings->allowScriptsToCloseWindows();
739
740     if (page->openedByDOM() || page->getHistoryLength() <= 1 || allowScriptsToCloseWindows)
741         m_frame->scheduleClose();
742 }
743
744 void DOMWindow::print()
745 {
746     if (!m_frame)
747         return;
748
749     Page* page = m_frame->page();
750     if (!page)
751         return;
752
753     page->chrome()->print(m_frame);
754 }
755
756 void DOMWindow::stop()
757 {
758     if (!m_frame)
759         return;
760
761     // We must check whether the load is complete asynchronously, because we might still be parsing
762     // the document until the callstack unwinds.
763     m_frame->loader()->stopForUserCancel(true);
764 }
765
766 void DOMWindow::alert(const String& message)
767 {
768     if (!m_frame)
769         return;
770
771     m_frame->document()->updateStyleIfNeeded();
772
773     Page* page = m_frame->page();
774     if (!page)
775         return;
776
777     page->chrome()->runJavaScriptAlert(m_frame, message);
778 }
779
780 bool DOMWindow::confirm(const String& message)
781 {
782     if (!m_frame)
783         return false;
784
785     m_frame->document()->updateStyleIfNeeded();
786
787     Page* page = m_frame->page();
788     if (!page)
789         return false;
790
791     return page->chrome()->runJavaScriptConfirm(m_frame, message);
792 }
793
794 String DOMWindow::prompt(const String& message, const String& defaultValue)
795 {
796     if (!m_frame)
797         return String();
798
799     m_frame->document()->updateStyleIfNeeded();
800
801     Page* page = m_frame->page();
802     if (!page)
803         return String();
804
805     String returnValue;
806     if (page->chrome()->runJavaScriptPrompt(m_frame, message, defaultValue, returnValue))
807         return returnValue;
808
809     return String();
810 }
811
812 bool DOMWindow::find(const String& string, bool caseSensitive, bool backwards, bool wrap, bool /*wholeWord*/, bool /*searchInFrames*/, bool /*showDialog*/) const
813 {
814     if (!m_frame)
815         return false;
816
817     // FIXME (13016): Support wholeWord, searchInFrames and showDialog
818     return m_frame->findString(string, !backwards, caseSensitive, wrap, false);
819 }
820
821 bool DOMWindow::offscreenBuffering() const
822 {
823     return true;
824 }
825
826 int DOMWindow::outerHeight() const
827 {
828     if (!m_frame)
829         return 0;
830
831     Page* page = m_frame->page();
832     if (!page)
833         return 0;
834
835     return static_cast<int>(page->chrome()->windowRect().height());
836 }
837
838 int DOMWindow::outerWidth() const
839 {
840     if (!m_frame)
841         return 0;
842
843     Page* page = m_frame->page();
844     if (!page)
845         return 0;
846
847     return static_cast<int>(page->chrome()->windowRect().width());
848 }
849
850 int DOMWindow::innerHeight() const
851 {
852     if (!m_frame)
853         return 0;
854
855     FrameView* view = m_frame->view();
856     if (!view)
857         return 0;
858     
859     return static_cast<int>(view->height() / m_frame->pageZoomFactor());
860 }
861
862 int DOMWindow::innerWidth() const
863 {
864     if (!m_frame)
865         return 0;
866
867     FrameView* view = m_frame->view();
868     if (!view)
869         return 0;
870
871     return static_cast<int>(view->width() / m_frame->pageZoomFactor());
872 }
873
874 int DOMWindow::screenX() const
875 {
876     if (!m_frame)
877         return 0;
878
879     Page* page = m_frame->page();
880     if (!page)
881         return 0;
882
883     return static_cast<int>(page->chrome()->windowRect().x());
884 }
885
886 int DOMWindow::screenY() const
887 {
888     if (!m_frame)
889         return 0;
890
891     Page* page = m_frame->page();
892     if (!page)
893         return 0;
894
895     return static_cast<int>(page->chrome()->windowRect().y());
896 }
897
898 int DOMWindow::scrollX() const
899 {
900     if (!m_frame)
901         return 0;
902
903     FrameView* view = m_frame->view();
904     if (!view)
905         return 0;
906
907     m_frame->document()->updateLayoutIgnorePendingStylesheets();
908
909     return static_cast<int>(view->scrollX() / m_frame->pageZoomFactor());
910 }
911
912 int DOMWindow::scrollY() const
913 {
914     if (!m_frame)
915         return 0;
916
917     FrameView* view = m_frame->view();
918     if (!view)
919         return 0;
920
921     m_frame->document()->updateLayoutIgnorePendingStylesheets();
922
923     return static_cast<int>(view->scrollY() / m_frame->pageZoomFactor());
924 }
925
926 bool DOMWindow::closed() const
927 {
928     return !m_frame;
929 }
930
931 unsigned DOMWindow::length() const
932 {
933     if (!m_frame)
934         return 0;
935
936     return m_frame->tree()->childCount();
937 }
938
939 String DOMWindow::name() const
940 {
941     if (!m_frame)
942         return String();
943
944     return m_frame->tree()->name();
945 }
946
947 void DOMWindow::setName(const String& string)
948 {
949     if (!m_frame)
950         return;
951
952     m_frame->tree()->setName(string);
953 }
954
955 String DOMWindow::status() const
956 {
957     if (!m_frame)
958         return String();
959
960     return m_frame->jsStatusBarText();
961 }
962
963 void DOMWindow::setStatus(const String& string) 
964
965     if (!m_frame) 
966         return; 
967
968     m_frame->setJSStatusBarText(string); 
969
970     
971 String DOMWindow::defaultStatus() const
972 {
973     if (!m_frame)
974         return String();
975
976     return m_frame->jsDefaultStatusBarText();
977
978
979 void DOMWindow::setDefaultStatus(const String& string) 
980
981     if (!m_frame) 
982         return; 
983
984     m_frame->setJSDefaultStatusBarText(string);
985 }
986
987 DOMWindow* DOMWindow::self() const
988 {
989     if (!m_frame)
990         return 0;
991
992     return m_frame->domWindow();
993 }
994
995 DOMWindow* DOMWindow::opener() const
996 {
997     if (!m_frame)
998         return 0;
999
1000     Frame* opener = m_frame->loader()->opener();
1001     if (!opener)
1002         return 0;
1003
1004     return opener->domWindow();
1005 }
1006
1007 DOMWindow* DOMWindow::parent() const
1008 {
1009     if (!m_frame)
1010         return 0;
1011
1012     Frame* parent = m_frame->tree()->parent(true);
1013     if (parent)
1014         return parent->domWindow();
1015
1016     return m_frame->domWindow();
1017 }
1018
1019 DOMWindow* DOMWindow::top() const
1020 {
1021     if (!m_frame)
1022         return 0;
1023
1024     Page* page = m_frame->page();
1025     if (!page)
1026         return 0;
1027
1028     return m_frame->tree()->top(true)->domWindow();
1029 }
1030
1031 Document* DOMWindow::document() const
1032 {
1033     // FIXME: This function shouldn't need a frame to work.
1034     if (!m_frame)
1035         return 0;
1036
1037     // The m_frame pointer is not zeroed out when the window is put into b/f cache, so it can hold an unrelated document/window pair.
1038     // FIXME: We should always zero out the frame pointer on navigation to avoid accidentally accessing the new frame content.
1039     if (m_frame->domWindow() != this)
1040         return 0;
1041
1042     ASSERT(m_frame->document());
1043     return m_frame->document();
1044 }
1045
1046 PassRefPtr<Media> DOMWindow::media() const
1047 {
1048     return Media::create(const_cast<DOMWindow*>(this));
1049 }
1050
1051 PassRefPtr<CSSStyleDeclaration> DOMWindow::getComputedStyle(Element* elt, const String&) const
1052 {
1053     if (!elt)
1054         return 0;
1055
1056     // FIXME: This needs take pseudo elements into account.
1057     return computedStyle(elt);
1058 }
1059
1060 PassRefPtr<CSSRuleList> DOMWindow::getMatchedCSSRules(Element* elt, const String& pseudoElt, bool authorOnly) const
1061 {
1062     if (!m_frame)
1063         return 0;
1064
1065     Document* doc = m_frame->document();
1066
1067     if (!pseudoElt.isEmpty())
1068         return doc->styleSelector()->pseudoStyleRulesForElement(elt, pseudoElt, authorOnly);
1069     return doc->styleSelector()->styleRulesForElement(elt, authorOnly);
1070 }
1071
1072 PassRefPtr<WebKitPoint> DOMWindow::webkitConvertPointFromNodeToPage(Node* node, const WebKitPoint* p) const
1073 {
1074     if (!node || !p)
1075         return 0;
1076         
1077     FloatPoint pagePoint(p->x(), p->y());
1078     pagePoint = node->convertToPage(pagePoint);
1079     return WebKitPoint::create(pagePoint.x(), pagePoint.y());
1080 }
1081
1082 PassRefPtr<WebKitPoint> DOMWindow::webkitConvertPointFromPageToNode(Node* node, const WebKitPoint* p) const
1083 {
1084     if (!node || !p)
1085         return 0;
1086         
1087     FloatPoint nodePoint(p->x(), p->y());
1088     nodePoint = node->convertFromPage(nodePoint);
1089     return WebKitPoint::create(nodePoint.x(), nodePoint.y());
1090 }
1091
1092 double DOMWindow::devicePixelRatio() const
1093 {
1094     if (!m_frame)
1095         return 0.0;
1096
1097     Page* page = m_frame->page();
1098     if (!page)
1099         return 0.0;
1100
1101     return page->chrome()->scaleFactor();
1102 }
1103
1104 #if ENABLE(DATABASE)
1105 PassRefPtr<Database> DOMWindow::openDatabase(const String& name, const String& version, const String& displayName, unsigned long estimatedSize, ExceptionCode& ec)
1106 {
1107     if (!m_frame)
1108         return 0;
1109
1110     Document* doc = m_frame->document();
1111
1112     Settings* settings = m_frame->settings();
1113     if (!settings || !settings->databasesEnabled())
1114         return 0;
1115
1116     return Database::openDatabase(doc, name, version, displayName, estimatedSize, ec);
1117 }
1118 #endif
1119
1120 void DOMWindow::scrollBy(int x, int y) const
1121 {
1122     if (!m_frame)
1123         return;
1124
1125     m_frame->document()->updateLayoutIgnorePendingStylesheets();
1126
1127     FrameView* view = m_frame->view();
1128     if (!view)
1129         return;
1130
1131     view->scrollBy(IntSize(x, y));
1132 }
1133
1134 void DOMWindow::scrollTo(int x, int y) const
1135 {
1136     if (!m_frame)
1137         return;
1138
1139     m_frame->document()->updateLayoutIgnorePendingStylesheets();
1140
1141     FrameView* view = m_frame->view();
1142     if (!view)
1143         return;
1144
1145     int zoomedX = static_cast<int>(x * m_frame->pageZoomFactor());
1146     int zoomedY = static_cast<int>(y * m_frame->pageZoomFactor());
1147     view->setScrollPosition(IntPoint(zoomedX, zoomedY));
1148 }
1149
1150 void DOMWindow::moveBy(float x, float y) const
1151 {
1152     if (!m_frame)
1153         return;
1154
1155     Page* page = m_frame->page();
1156     if (!page)
1157         return;
1158
1159     if (m_frame != page->mainFrame())
1160         return;
1161
1162     FloatRect fr = page->chrome()->windowRect();
1163     FloatRect update = fr;
1164     update.move(x, y);
1165     // Security check (the spec talks about UniversalBrowserWrite to disable this check...)
1166     adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), fr, update);
1167     page->chrome()->setWindowRect(fr);
1168 }
1169
1170 void DOMWindow::moveTo(float x, float y) const
1171 {
1172     if (!m_frame)
1173         return;
1174
1175     Page* page = m_frame->page();
1176     if (!page)
1177         return;
1178
1179     if (m_frame != page->mainFrame())
1180         return;
1181
1182     FloatRect fr = page->chrome()->windowRect();
1183     FloatRect sr = screenAvailableRect(page->mainFrame()->view());
1184     fr.setLocation(sr.location());
1185     FloatRect update = fr;
1186     update.move(x, y);     
1187     // Security check (the spec talks about UniversalBrowserWrite to disable this check...)
1188     adjustWindowRect(sr, fr, update);
1189     page->chrome()->setWindowRect(fr);
1190 }
1191
1192 void DOMWindow::resizeBy(float x, float y) const
1193 {
1194     if (!m_frame)
1195         return;
1196
1197     Page* page = m_frame->page();
1198     if (!page)
1199         return;
1200
1201     if (m_frame != page->mainFrame())
1202         return;
1203
1204     FloatRect fr = page->chrome()->windowRect();
1205     FloatSize dest = fr.size() + FloatSize(x, y);
1206     FloatRect update(fr.location(), dest);
1207     adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), fr, update);
1208     page->chrome()->setWindowRect(fr);
1209 }
1210
1211 void DOMWindow::resizeTo(float width, float height) const
1212 {
1213     if (!m_frame)
1214         return;
1215
1216     Page* page = m_frame->page();
1217     if (!page)
1218         return;
1219
1220     if (m_frame != page->mainFrame())
1221         return;
1222
1223     FloatRect fr = page->chrome()->windowRect();
1224     FloatSize dest = FloatSize(width, height);
1225     FloatRect update(fr.location(), dest);
1226     adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), fr, update);
1227     page->chrome()->setWindowRect(fr);
1228 }
1229
1230 int DOMWindow::setTimeout(ScheduledAction* action, int timeout)
1231 {
1232     return DOMTimer::install(scriptExecutionContext(), action, timeout, true);
1233 }
1234
1235 void DOMWindow::clearTimeout(int timeoutId)
1236 {
1237     DOMTimer::removeById(scriptExecutionContext(), timeoutId);
1238 }
1239
1240 int DOMWindow::setInterval(ScheduledAction* action, int timeout)
1241 {
1242     return DOMTimer::install(scriptExecutionContext(), action, timeout, false);
1243 }
1244
1245 void DOMWindow::clearInterval(int timeoutId)
1246 {
1247     DOMTimer::removeById(scriptExecutionContext(), timeoutId);
1248 }
1249
1250 bool DOMWindow::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
1251 {
1252     if (!EventTarget::addEventListener(eventType, listener, useCapture))
1253         return false;
1254
1255     if (Document* document = this->document())
1256         document->addListenerTypeIfNeeded(eventType);
1257
1258     if (eventType == eventNames().unloadEvent)
1259         addUnloadEventListener(this);
1260     else if (eventType == eventNames().beforeunloadEvent && allowsBeforeUnloadListeners(this))
1261         addBeforeUnloadEventListener(this);
1262
1263     return true;
1264 }
1265
1266 bool DOMWindow::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
1267 {
1268     if (!EventTarget::removeEventListener(eventType, listener, useCapture))
1269         return false;
1270
1271     if (eventType == eventNames().unloadEvent)
1272         removeUnloadEventListener(this);
1273     else if (eventType == eventNames().beforeunloadEvent && allowsBeforeUnloadListeners(this))
1274         removeBeforeUnloadEventListener(this);
1275
1276     return true;
1277 }
1278
1279 void DOMWindow::dispatchLoadEvent()
1280 {
1281     dispatchEvent(Event::create(eventNames().loadEvent, false, false), document());
1282
1283     // For load events, send a separate load event to the enclosing frame only.
1284     // This is a DOM extension and is independent of bubbling/capturing rules of
1285     // the DOM.
1286     Element* ownerElement = document()->ownerElement();
1287     if (ownerElement) {
1288         RefPtr<Event> ownerEvent = Event::create(eventNames().loadEvent, false, false);
1289         ownerEvent->setTarget(ownerElement);
1290         ownerElement->dispatchGenericEvent(ownerEvent.release());
1291     }
1292
1293 #if ENABLE(INSPECTOR)
1294     if (!frame() || !frame()->page())
1295         return;
1296
1297     if (InspectorController* controller = frame()->page()->inspectorController())
1298         controller->mainResourceFiredLoadEvent(frame()->loader()->documentLoader(), url());
1299 #endif
1300 }
1301
1302 InspectorTimelineAgent* DOMWindow::inspectorTimelineAgent() 
1303 {
1304     if (frame() && frame()->page())
1305         return frame()->page()->inspectorTimelineAgent();
1306     return 0;
1307 }
1308
1309 bool DOMWindow::dispatchEvent(PassRefPtr<Event> prpEvent, PassRefPtr<EventTarget> prpTarget)
1310 {
1311     RefPtr<EventTarget> protect = this;
1312     RefPtr<Event> event = prpEvent;
1313
1314     event->setTarget(prpTarget ? prpTarget : this);
1315     event->setCurrentTarget(this);
1316     event->setEventPhase(Event::AT_TARGET);
1317
1318 #if ENABLE(INSPECTOR)
1319     InspectorTimelineAgent* timelineAgent = inspectorTimelineAgent();
1320     bool timelineAgentIsActive = timelineAgent && hasEventListeners(event->type());
1321     if (timelineAgentIsActive)
1322         timelineAgent->willDispatchEvent(*event);
1323 #endif
1324
1325     bool result = fireEventListeners(event.get());
1326
1327 #if ENABLE(INSPECTOR)
1328     if (timelineAgentIsActive) {
1329       timelineAgent = inspectorTimelineAgent();
1330       if (timelineAgent)
1331             timelineAgent->didDispatchEvent();
1332     }
1333 #endif
1334
1335     return result;
1336 }
1337
1338 void DOMWindow::removeAllEventListeners()
1339 {
1340     EventTarget::removeAllEventListeners();
1341
1342     removeAllUnloadEventListeners(this);
1343     removeAllBeforeUnloadEventListeners(this);
1344 }
1345
1346 void DOMWindow::captureEvents()
1347 {
1348     // Not implemented.
1349 }
1350
1351 void DOMWindow::releaseEvents()
1352 {
1353     // Not implemented.
1354 }
1355
1356 EventTargetData* DOMWindow::eventTargetData()
1357 {
1358     return &m_eventTargetData;
1359 }
1360
1361 EventTargetData* DOMWindow::ensureEventTargetData()
1362 {
1363     return &m_eventTargetData;
1364 }
1365
1366 } // namespace WebCore