40e0b2aff1b0dff13c60b50665844807fbd0cf50
[WebKit-https.git] / Source / WebCore / page / DOMWindow.cpp
1 /*
2  * Copyright (C) 2006, 2007, 2008, 2010 Apple Inc. All rights reserved.
3  * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
25  */
26
27 #include "config.h"
28 #include "DOMWindow.h"
29
30 #include "AbstractDatabase.h"
31 #include "BackForwardController.h"
32 #include "BarInfo.h"
33 #include "Base64.h"
34 #include "BeforeUnloadEvent.h"
35 #include "CSSComputedStyleDeclaration.h"
36 #include "CSSRuleList.h"
37 #include "Chrome.h"
38 #include "Console.h"
39 #include "Crypto.h"
40 #include "DOMApplicationCache.h"
41 #include "DOMSelection.h"
42 #include "DOMSettableTokenList.h"
43 #include "DOMStringList.h"
44 #include "DOMTimer.h"
45 #include "DOMTokenList.h"
46 #include "DOMURL.h"
47 #include "DOMWindowExtension.h"
48 #include "DOMWindowNotifications.h"
49 #include "Database.h"
50 #include "DatabaseCallback.h"
51 #include "DeviceMotionController.h"
52 #include "DeviceOrientationController.h"
53 #include "Document.h"
54 #include "DocumentLoader.h"
55 #include "Element.h"
56 #include "EventException.h"
57 #include "EventListener.h"
58 #include "EventNames.h"
59 #include "ExceptionCode.h"
60 #include "FloatRect.h"
61 #include "Frame.h"
62 #include "FrameLoadRequest.h"
63 #include "FrameLoader.h"
64 #include "FrameLoaderClient.h"
65 #include "FrameTree.h"
66 #include "FrameView.h"
67 #include "HTMLFrameOwnerElement.h"
68 #include "History.h"
69 #include "InspectorInstrumentation.h"
70 #include "KURL.h"
71 #include "Location.h"
72 #include "MediaQueryList.h"
73 #include "MediaQueryMatcher.h"
74 #include "MessageEvent.h"
75 #include "Navigator.h"
76 #include "Page.h"
77 #include "PageGroup.h"
78 #include "PageTransitionEvent.h"
79 #include "Performance.h"
80 #include "PlatformScreen.h"
81 #include "ScheduledAction.h"
82 #include "Screen.h"
83 #include "ScriptCallStack.h"
84 #include "ScriptCallStackFactory.h"
85 #include "SecurityOrigin.h"
86 #include "SerializedScriptValue.h"
87 #include "Settings.h"
88 #include "Storage.h"
89 #include "StorageArea.h"
90 #include "StorageInfo.h"
91 #include "StorageNamespace.h"
92 #include "StyleMedia.h"
93 #include "StyleResolver.h"
94 #include "SuddenTermination.h"
95 #include "WebKitPoint.h"
96 #include "WindowFeatures.h"
97 #include <algorithm>
98 #include <wtf/CurrentTime.h>
99 #include <wtf/MainThread.h>
100 #include <wtf/MathExtras.h>
101 #include <wtf/text/WTFString.h>
102
103 #if ENABLE(REQUEST_ANIMATION_FRAME)
104 #include "RequestAnimationFrameCallback.h"
105 #endif
106
107 using std::min;
108 using std::max;
109
110 namespace WebCore {
111
112 class PostMessageTimer : public TimerBase {
113 public:
114     PostMessageTimer(DOMWindow* window, PassRefPtr<SerializedScriptValue> message, const String& sourceOrigin, PassRefPtr<DOMWindow> source, PassOwnPtr<MessagePortChannelArray> channels, SecurityOrigin* targetOrigin, PassRefPtr<ScriptCallStack> stackTrace)
115         : m_window(window)
116         , m_message(message)
117         , m_origin(sourceOrigin)
118         , m_source(source)
119         , m_channels(channels)
120         , m_targetOrigin(targetOrigin)
121         , m_stackTrace(stackTrace)
122     {
123     }
124
125     PassRefPtr<MessageEvent> event(ScriptExecutionContext* context)
126     {
127         OwnPtr<MessagePortArray> messagePorts = MessagePort::entanglePorts(*context, m_channels.release());
128         return MessageEvent::create(messagePorts.release(), m_message, m_origin, "", m_source);
129     }
130     SecurityOrigin* targetOrigin() const { return m_targetOrigin.get(); }
131     ScriptCallStack* stackTrace() const { return m_stackTrace.get(); }
132
133 private:
134     virtual void fired()
135     {
136         m_window->postMessageTimerFired(adoptPtr(this));
137         // This object is deleted now.
138     }
139
140     RefPtr<DOMWindow> m_window;
141     RefPtr<SerializedScriptValue> m_message;
142     String m_origin;
143     RefPtr<DOMWindow> m_source;
144     OwnPtr<MessagePortChannelArray> m_channels;
145     RefPtr<SecurityOrigin> m_targetOrigin;
146     RefPtr<ScriptCallStack> m_stackTrace;
147 };
148
149 typedef HashCountedSet<DOMWindow*> DOMWindowSet;
150
151 static DOMWindowSet& windowsWithUnloadEventListeners()
152 {
153     DEFINE_STATIC_LOCAL(DOMWindowSet, windowsWithUnloadEventListeners, ());
154     return windowsWithUnloadEventListeners;
155 }
156
157 static DOMWindowSet& windowsWithBeforeUnloadEventListeners()
158 {
159     DEFINE_STATIC_LOCAL(DOMWindowSet, windowsWithBeforeUnloadEventListeners, ());
160     return windowsWithBeforeUnloadEventListeners;
161 }
162
163 static void addUnloadEventListener(DOMWindow* domWindow)
164 {
165     DOMWindowSet& set = windowsWithUnloadEventListeners();
166     if (set.isEmpty())
167         disableSuddenTermination();
168     set.add(domWindow);
169 }
170
171 static void removeUnloadEventListener(DOMWindow* domWindow)
172 {
173     DOMWindowSet& set = windowsWithUnloadEventListeners();
174     DOMWindowSet::iterator it = set.find(domWindow);
175     if (it == set.end())
176         return;
177     set.remove(it);
178     if (set.isEmpty())
179         enableSuddenTermination();
180 }
181
182 static void removeAllUnloadEventListeners(DOMWindow* domWindow)
183 {
184     DOMWindowSet& set = windowsWithUnloadEventListeners();
185     DOMWindowSet::iterator it = set.find(domWindow);
186     if (it == set.end())
187         return;
188     set.removeAll(it);
189     if (set.isEmpty())
190         enableSuddenTermination();
191 }
192
193 static void addBeforeUnloadEventListener(DOMWindow* domWindow)
194 {
195     DOMWindowSet& set = windowsWithBeforeUnloadEventListeners();
196     if (set.isEmpty())
197         disableSuddenTermination();
198     set.add(domWindow);
199 }
200
201 static void removeBeforeUnloadEventListener(DOMWindow* domWindow)
202 {
203     DOMWindowSet& set = windowsWithBeforeUnloadEventListeners();
204     DOMWindowSet::iterator it = set.find(domWindow);
205     if (it == set.end())
206         return;
207     set.remove(it);
208     if (set.isEmpty())
209         enableSuddenTermination();
210 }
211
212 static void removeAllBeforeUnloadEventListeners(DOMWindow* domWindow)
213 {
214     DOMWindowSet& set = windowsWithBeforeUnloadEventListeners();
215     DOMWindowSet::iterator it = set.find(domWindow);
216     if (it == set.end())
217         return;
218     set.removeAll(it);
219     if (set.isEmpty())
220         enableSuddenTermination();
221 }
222
223 static bool allowsBeforeUnloadListeners(DOMWindow* window)
224 {
225     ASSERT_ARG(window, window);
226     Frame* frame = window->frame();
227     if (!frame)
228         return false;
229     Page* page = frame->page();
230     if (!page)
231         return false;
232     return frame == page->mainFrame();
233 }
234
235 bool DOMWindow::dispatchAllPendingBeforeUnloadEvents()
236 {
237     DOMWindowSet& set = windowsWithBeforeUnloadEventListeners();
238     if (set.isEmpty())
239         return true;
240
241     static bool alreadyDispatched = false;
242     ASSERT(!alreadyDispatched);
243     if (alreadyDispatched)
244         return true;
245
246     Vector<RefPtr<DOMWindow> > windows;
247     DOMWindowSet::iterator end = set.end();
248     for (DOMWindowSet::iterator it = set.begin(); it != end; ++it)
249         windows.append(it->first);
250
251     size_t size = windows.size();
252     for (size_t i = 0; i < size; ++i) {
253         DOMWindow* window = windows[i].get();
254         if (!set.contains(window))
255             continue;
256
257         Frame* frame = window->frame();
258         if (!frame)
259             continue;
260
261         if (!frame->loader()->shouldClose())
262             return false;
263     }
264
265     enableSuddenTermination();
266
267     alreadyDispatched = true;
268
269     return true;
270 }
271
272 unsigned DOMWindow::pendingUnloadEventListeners() const
273 {
274     return windowsWithUnloadEventListeners().count(const_cast<DOMWindow*>(this));
275 }
276
277 void DOMWindow::dispatchAllPendingUnloadEvents()
278 {
279     DOMWindowSet& set = windowsWithUnloadEventListeners();
280     if (set.isEmpty())
281         return;
282
283     static bool alreadyDispatched = false;
284     ASSERT(!alreadyDispatched);
285     if (alreadyDispatched)
286         return;
287
288     Vector<RefPtr<DOMWindow> > windows;
289     DOMWindowSet::iterator end = set.end();
290     for (DOMWindowSet::iterator it = set.begin(); it != end; ++it)
291         windows.append(it->first);
292
293     size_t size = windows.size();
294     for (size_t i = 0; i < size; ++i) {
295         DOMWindow* window = windows[i].get();
296         if (!set.contains(window))
297             continue;
298
299         window->dispatchEvent(PageTransitionEvent::create(eventNames().pagehideEvent, false), window->document());
300         window->dispatchEvent(Event::create(eventNames().unloadEvent, false, false), window->document());
301     }
302
303     enableSuddenTermination();
304
305     alreadyDispatched = true;
306 }
307
308 // This function:
309 // 1) Validates the pending changes are not changing to NaN
310 // 2) Constrains the window rect to no smaller than 100 in each dimension and no
311 //    bigger than the the float rect's dimensions.
312 // 3) Constrain window rect to within the top and left boundaries of the screen rect
313 // 4) Constraint the window rect to within the bottom and right boundaries of the
314 //    screen rect.
315 // 5) Translate the window rect coordinates to be within the coordinate space of
316 //    the screen rect.
317 void DOMWindow::adjustWindowRect(const FloatRect& screen, FloatRect& window, const FloatRect& pendingChanges)
318 {
319     // Make sure we're in a valid state before adjusting dimensions.
320     ASSERT(isfinite(screen.x()));
321     ASSERT(isfinite(screen.y()));
322     ASSERT(isfinite(screen.width()));
323     ASSERT(isfinite(screen.height()));
324     ASSERT(isfinite(window.x()));
325     ASSERT(isfinite(window.y()));
326     ASSERT(isfinite(window.width()));
327     ASSERT(isfinite(window.height()));
328     
329     // Update window values if new requested values are not NaN.
330     if (!isnan(pendingChanges.x()))
331         window.setX(pendingChanges.x());
332     if (!isnan(pendingChanges.y()))
333         window.setY(pendingChanges.y());
334     if (!isnan(pendingChanges.width()))
335         window.setWidth(pendingChanges.width());
336     if (!isnan(pendingChanges.height()))
337         window.setHeight(pendingChanges.height());
338     
339     // Resize the window to between 100 and the screen width and height.
340     window.setWidth(min(max(100.0f, window.width()), screen.width()));
341     window.setHeight(min(max(100.0f, window.height()), screen.height()));
342     
343     // Constrain the window position to the screen.
344     window.setX(max(screen.x(), min(window.x(), screen.maxX() - window.width())));
345     window.setY(max(screen.y(), min(window.y(), screen.maxY() - window.height())));
346 }
347
348 // FIXME: We can remove this function once V8 showModalDialog is changed to use DOMWindow.
349 void DOMWindow::parseModalDialogFeatures(const String& string, HashMap<String, String>& map)
350 {
351     WindowFeatures::parseDialogFeatures(string, map);
352 }
353
354 bool DOMWindow::allowPopUp(Frame* firstFrame)
355 {
356     ASSERT(firstFrame);
357
358     if (ScriptController::processingUserGesture())
359         return true;
360
361     Settings* settings = firstFrame->settings();
362     return settings && settings->javaScriptCanOpenWindowsAutomatically();
363 }
364
365 bool DOMWindow::allowPopUp()
366 {
367     return m_frame && allowPopUp(m_frame);
368 }
369
370 bool DOMWindow::canShowModalDialog(const Frame* frame)
371 {
372     if (!frame)
373         return false;
374     Page* page = frame->page();
375     if (!page)
376         return false;
377     return page->chrome()->canRunModal();
378 }
379
380 bool DOMWindow::canShowModalDialogNow(const Frame* frame)
381 {
382     if (!frame)
383         return false;
384     Page* page = frame->page();
385     if (!page)
386         return false;
387     return page->chrome()->canRunModalNow();
388 }
389
390 DOMWindow::DOMWindow(Frame* frame)
391     : FrameDestructionObserver(frame)
392     , m_shouldPrintWhenFinishedLoading(false)
393     , m_suspendedForPageCache(false)
394 {
395 }
396
397 DOMWindow::~DOMWindow()
398 {
399 #ifndef NDEBUG
400     if (!m_suspendedForPageCache) {
401         ASSERT(!m_screen);
402         ASSERT(!m_history);
403         ASSERT(!m_crypto);
404         ASSERT(!m_locationbar);
405         ASSERT(!m_menubar);
406         ASSERT(!m_personalbar);
407         ASSERT(!m_scrollbars);
408         ASSERT(!m_statusbar);
409         ASSERT(!m_toolbar);
410         ASSERT(!m_console);
411         ASSERT(!m_navigator);
412 #if ENABLE(WEB_TIMING)
413         ASSERT(!m_performance);
414 #endif
415         ASSERT(!m_location);
416         ASSERT(!m_media);
417         ASSERT(!m_sessionStorage);
418         ASSERT(!m_localStorage);
419         ASSERT(!m_applicationCache);
420 #if ENABLE(BLOB)
421         ASSERT(!m_domURL);
422 #endif
423 #if ENABLE(QUOTA)
424         ASSERT(!m_storageInfo);
425 #endif
426     }
427 #endif
428
429     if (m_suspendedForPageCache)
430         willDestroyCachedFrame();
431     else
432         willDestroyDocumentInFrame();
433
434     // As the ASSERTs above indicate, this clear should only be necesary if this DOMWindow is suspended for the page cache.
435     // But we don't want to risk any of these objects hanging around after we've been destroyed.
436     clearDOMWindowProperties();
437
438     removeAllUnloadEventListeners(this);
439     removeAllBeforeUnloadEventListeners(this);
440 }
441
442 const AtomicString& DOMWindow::interfaceName() const
443 {
444     return eventNames().interfaceForDOMWindow;
445 }
446
447 ScriptExecutionContext* DOMWindow::scriptExecutionContext() const
448 {
449     return document();
450 }
451
452 DOMWindow* DOMWindow::toDOMWindow()
453 {
454     return this;
455 }
456
457 PassRefPtr<MediaQueryList> DOMWindow::matchMedia(const String& media)
458 {
459     return document() ? document()->mediaQueryMatcher()->matchMedia(media) : 0;
460 }
461
462 void DOMWindow::setSecurityOrigin(SecurityOrigin* securityOrigin)
463 {
464     m_securityOrigin = securityOrigin;
465 }
466
467 Page* DOMWindow::page()
468 {
469     return frame() ? frame()->page() : 0;
470 }
471
472 void DOMWindow::frameDestroyed()
473 {
474     willDestroyDocumentInFrame();
475     FrameDestructionObserver::frameDestroyed();
476     clearDOMWindowProperties();
477 }
478
479 void DOMWindow::willDetachPage()
480 {
481     InspectorInstrumentation::frameWindowDiscarded(m_frame, this);
482 }
483
484 void DOMWindow::willDestroyCachedFrame()
485 {
486     // It is necessary to copy m_properties to a separate vector because the DOMWindowProperties may
487     // unregister themselves from the DOMWindow as a result of the call to willDestroyGlobalObjectInCachedFrame.
488     Vector<DOMWindowProperty*> properties;
489     copyToVector(m_properties, properties);
490     for (size_t i = 0; i < properties.size(); ++i)
491         properties[i]->willDestroyGlobalObjectInCachedFrame();
492 }
493
494 void DOMWindow::willDestroyDocumentInFrame()
495 {
496     // It is necessary to copy m_properties to a separate vector because the DOMWindowProperties may
497     // unregister themselves from the DOMWindow as a result of the call to willDestroyGlobalObjectInFrame.
498     Vector<DOMWindowProperty*> properties;
499     copyToVector(m_properties, properties);
500     for (size_t i = 0; i < properties.size(); ++i)
501         properties[i]->willDestroyGlobalObjectInFrame();
502 }
503
504 void DOMWindow::willDetachDocumentFromFrame()
505 {
506     // It is necessary to copy m_properties to a separate vector because the DOMWindowProperties may
507     // unregister themselves from the DOMWindow as a result of the call to willDetachGlobalObjectFromFrame.
508     Vector<DOMWindowProperty*> properties;
509     copyToVector(m_properties, properties);
510     for (size_t i = 0; i < properties.size(); ++i)
511         properties[i]->willDetachGlobalObjectFromFrame();
512 }
513
514 void DOMWindow::registerProperty(DOMWindowProperty* property)
515 {
516     m_properties.add(property);
517 }
518
519 void DOMWindow::unregisterProperty(DOMWindowProperty* property)
520 {
521     m_properties.remove(property);
522 }
523
524 void DOMWindow::clear()
525 {
526     // The main frame will always try to clear its DOMWindow when a new load is committed, even if that
527     // DOMWindow is suspended in the page cache.
528     // In those cases we need to make sure we don't actually clear it.
529     if (m_suspendedForPageCache)
530         return;
531     
532     willDestroyDocumentInFrame();
533     clearDOMWindowProperties();
534 }
535
536 void DOMWindow::suspendForPageCache()
537 {
538     disconnectDOMWindowProperties();
539     m_suspendedForPageCache = true;
540 }
541
542 void DOMWindow::resumeFromPageCache()
543 {
544     reconnectDOMWindowProperties();
545     m_suspendedForPageCache = false;
546 }
547
548 void DOMWindow::disconnectDOMWindowProperties()
549 {
550     // It is necessary to copy m_properties to a separate vector because the DOMWindowProperties may
551     // unregister themselves from the DOMWindow as a result of the call to disconnectFrameForPageCache.
552     Vector<DOMWindowProperty*> properties;
553     copyToVector(m_properties, properties);
554     for (size_t i = 0; i < properties.size(); ++i)
555         properties[i]->disconnectFrameForPageCache();
556 }
557
558 void DOMWindow::reconnectDOMWindowProperties()
559 {
560     ASSERT(m_suspendedForPageCache);
561     // It is necessary to copy m_properties to a separate vector because the DOMWindowProperties may
562     // unregister themselves from the DOMWindow as a result of the call to reconnectFromPageCache.
563     Vector<DOMWindowProperty*> properties;
564     copyToVector(m_properties, properties);
565     for (size_t i = 0; i < properties.size(); ++i)
566         properties[i]->reconnectFrameFromPageCache(m_frame);
567 }
568
569 void DOMWindow::clearDOMWindowProperties()
570 {
571     m_properties.clear();
572
573     m_screen = 0;
574     m_history = 0;
575     m_crypto = 0;
576     m_locationbar = 0;
577     m_menubar = 0;
578     m_personalbar = 0;
579     m_scrollbars = 0;
580     m_statusbar = 0;
581     m_toolbar = 0;
582     m_console = 0;
583     m_navigator = 0;
584 #if ENABLE(WEB_TIMING)
585     m_performance = 0;
586 #endif
587     m_location = 0;
588     m_media = 0;
589     m_sessionStorage = 0;
590     m_localStorage = 0;
591     m_applicationCache = 0;
592 #if ENABLE(BLOB)
593     m_domURL = 0;
594 #endif
595 #if ENABLE(QUOTA)
596     m_storageInfo = 0;
597 #endif
598 }
599
600 bool DOMWindow::isCurrentlyDisplayedInFrame() const
601 {
602     return m_frame && m_frame->domWindow() == this;
603 }
604
605 #if ENABLE(ORIENTATION_EVENTS)
606 int DOMWindow::orientation() const
607 {
608     if (!m_frame)
609         return 0;
610
611     return m_frame->orientation();
612 }
613 #endif
614
615 Screen* DOMWindow::screen() const
616 {
617     if (!isCurrentlyDisplayedInFrame())
618         return 0;
619     if (!m_screen)
620         m_screen = Screen::create(m_frame);
621     return m_screen.get();
622 }
623
624 History* DOMWindow::history() const
625 {
626     if (!isCurrentlyDisplayedInFrame())
627         return 0;
628     if (!m_history)
629         m_history = History::create(m_frame);
630     return m_history.get();
631 }
632
633 Crypto* DOMWindow::crypto() const
634 {
635     if (!isCurrentlyDisplayedInFrame())
636         return 0;
637     if (!m_crypto)
638         m_crypto = Crypto::create();
639     return m_crypto.get();
640 }
641
642 BarInfo* DOMWindow::locationbar() const
643 {
644     if (!isCurrentlyDisplayedInFrame())
645         return 0;
646     if (!m_locationbar)
647         m_locationbar = BarInfo::create(m_frame, BarInfo::Locationbar);
648     return m_locationbar.get();
649 }
650
651 BarInfo* DOMWindow::menubar() const
652 {
653     if (!isCurrentlyDisplayedInFrame())
654         return 0;
655     if (!m_menubar)
656         m_menubar = BarInfo::create(m_frame, BarInfo::Menubar);
657     return m_menubar.get();
658 }
659
660 BarInfo* DOMWindow::personalbar() const
661 {
662     if (!isCurrentlyDisplayedInFrame())
663         return 0;
664     if (!m_personalbar)
665         m_personalbar = BarInfo::create(m_frame, BarInfo::Personalbar);
666     return m_personalbar.get();
667 }
668
669 BarInfo* DOMWindow::scrollbars() const
670 {
671     if (!isCurrentlyDisplayedInFrame())
672         return 0;
673     if (!m_scrollbars)
674         m_scrollbars = BarInfo::create(m_frame, BarInfo::Scrollbars);
675     return m_scrollbars.get();
676 }
677
678 BarInfo* DOMWindow::statusbar() const
679 {
680     if (!isCurrentlyDisplayedInFrame())
681         return 0;
682     if (!m_statusbar)
683         m_statusbar = BarInfo::create(m_frame, BarInfo::Statusbar);
684     return m_statusbar.get();
685 }
686
687 BarInfo* DOMWindow::toolbar() const
688 {
689     if (!isCurrentlyDisplayedInFrame())
690         return 0;
691     if (!m_toolbar)
692         m_toolbar = BarInfo::create(m_frame, BarInfo::Toolbar);
693     return m_toolbar.get();
694 }
695
696 Console* DOMWindow::console() const
697 {
698     if (!isCurrentlyDisplayedInFrame())
699         return 0;
700     if (!m_console)
701         m_console = Console::create(m_frame);
702     return m_console.get();
703 }
704
705 DOMApplicationCache* DOMWindow::applicationCache() const
706 {
707     if (!isCurrentlyDisplayedInFrame())
708         return 0;
709     if (!m_applicationCache)
710         m_applicationCache = DOMApplicationCache::create(m_frame);
711     return m_applicationCache.get();
712 }
713
714 Navigator* DOMWindow::navigator() const
715 {
716     if (!isCurrentlyDisplayedInFrame())
717         return 0;
718     if (!m_navigator)
719         m_navigator = Navigator::create(m_frame);
720     return m_navigator.get();
721 }
722
723 #if ENABLE(WEB_TIMING)
724 Performance* DOMWindow::performance() const
725 {
726     if (!isCurrentlyDisplayedInFrame())
727         return 0;
728     if (!m_performance)
729         m_performance = Performance::create(m_frame);
730     return m_performance.get();
731 }
732 #endif
733
734 Location* DOMWindow::location() const
735 {
736     if (!isCurrentlyDisplayedInFrame())
737         return 0;
738     if (!m_location)
739         m_location = Location::create(m_frame);
740     return m_location.get();
741 }
742
743 Storage* DOMWindow::sessionStorage(ExceptionCode& ec) const
744 {
745     if (!isCurrentlyDisplayedInFrame())
746         return 0;
747     if (m_sessionStorage)
748         return m_sessionStorage.get();
749
750     Document* document = this->document();
751     if (!document)
752         return 0;
753
754     if (!document->securityOrigin()->canAccessLocalStorage()) {
755         ec = SECURITY_ERR;
756         return 0;
757     }
758
759     Page* page = document->page();
760     if (!page)
761         return 0;
762
763     RefPtr<StorageArea> storageArea = page->sessionStorage()->storageArea(document->securityOrigin());
764     InspectorInstrumentation::didUseDOMStorage(page, storageArea.get(), false, m_frame);
765
766     m_sessionStorage = Storage::create(m_frame, storageArea.release());
767     return m_sessionStorage.get();
768 }
769
770 Storage* DOMWindow::localStorage(ExceptionCode& ec) const
771 {
772     if (!isCurrentlyDisplayedInFrame())
773         return 0;
774     if (m_localStorage)
775         return m_localStorage.get();
776
777     Document* document = this->document();
778     if (!document)
779         return 0;
780
781     if (!document->securityOrigin()->canAccessLocalStorage()) {
782         ec = SECURITY_ERR;
783         return 0;
784     }
785
786     Page* page = document->page();
787     if (!page)
788         return 0;
789
790     if (!page->settings()->localStorageEnabled())
791         return 0;
792
793     RefPtr<StorageArea> storageArea = page->group().localStorage()->storageArea(document->securityOrigin());
794     InspectorInstrumentation::didUseDOMStorage(page, storageArea.get(), true, m_frame);
795
796     m_localStorage = Storage::create(m_frame, storageArea.release());
797     return m_localStorage.get();
798 }
799
800 void DOMWindow::postMessage(PassRefPtr<SerializedScriptValue> message, MessagePort* port, const String& targetOrigin, DOMWindow* source, ExceptionCode& ec)
801 {
802     MessagePortArray ports;
803     if (port)
804         ports.append(port);
805     postMessage(message, &ports, targetOrigin, source, ec);
806 }
807
808 void DOMWindow::postMessage(PassRefPtr<SerializedScriptValue> message, const MessagePortArray* ports, const String& targetOrigin, DOMWindow* source, ExceptionCode& ec)
809 {
810     if (!isCurrentlyDisplayedInFrame())
811         return;
812
813     Document* sourceDocument = source->document();
814
815     // Compute the target origin.  We need to do this synchronously in order
816     // to generate the SYNTAX_ERR exception correctly.
817     RefPtr<SecurityOrigin> target;
818     if (targetOrigin == "/") {
819         if (!sourceDocument)
820             return;
821         target = sourceDocument->securityOrigin();
822     } else if (targetOrigin != "*") {
823         target = SecurityOrigin::createFromString(targetOrigin);
824         // It doesn't make sense target a postMessage at a unique origin
825         // because there's no way to represent a unique origin in a string.
826         if (target->isUnique()) {
827             ec = SYNTAX_ERR;
828             return;
829         }
830     }
831
832     OwnPtr<MessagePortChannelArray> channels = MessagePort::disentanglePorts(ports, ec);
833     if (ec)
834         return;
835
836     // Capture the source of the message.  We need to do this synchronously
837     // in order to capture the source of the message correctly.
838     if (!sourceDocument)
839         return;
840     String sourceOrigin = sourceDocument->securityOrigin()->toString();
841
842     // Capture stack trace only when inspector front-end is loaded as it may be time consuming.
843     RefPtr<ScriptCallStack> stackTrace;
844     if (InspectorInstrumentation::hasFrontends())
845         stackTrace = createScriptCallStack(ScriptCallStack::maxCallStackSizeToCapture, true);
846
847     // Schedule the message.
848     PostMessageTimer* timer = new PostMessageTimer(this, message, sourceOrigin, source, channels.release(), target.get(), stackTrace.release());
849     timer->startOneShot(0);
850 }
851
852 void DOMWindow::postMessageTimerFired(PassOwnPtr<PostMessageTimer> t)
853 {
854     OwnPtr<PostMessageTimer> timer(t);
855
856     if (!document() || !isCurrentlyDisplayedInFrame())
857         return;
858
859     RefPtr<MessageEvent> event = timer->event(document());
860
861     // Give the embedder a chance to intercept this postMessage because this
862     // DOMWindow might be a proxy for another in browsers that support
863     // postMessage calls across WebKit instances.
864     if (m_frame->loader()->client()->willCheckAndDispatchMessageEvent(timer->targetOrigin(), event.get()))
865         return;
866
867     dispatchMessageEventWithOriginCheck(timer->targetOrigin(), event, timer->stackTrace());
868 }
869
870 void DOMWindow::dispatchMessageEventWithOriginCheck(SecurityOrigin* intendedTargetOrigin, PassRefPtr<Event> event, PassRefPtr<ScriptCallStack> stackTrace)
871 {
872     if (intendedTargetOrigin) {
873         // Check target origin now since the target document may have changed since the timer was scheduled.
874         if (!intendedTargetOrigin->isSameSchemeHostPort(document()->securityOrigin())) {
875             String message = "Unable to post message to " + intendedTargetOrigin->toString() +
876                              ". Recipient has origin " + document()->securityOrigin()->toString() + ".\n";
877             console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, message, stackTrace);
878             return;
879         }
880     }
881
882     dispatchEvent(event);
883 }
884
885 DOMSelection* DOMWindow::getSelection()
886 {
887     if (!isCurrentlyDisplayedInFrame() || !m_frame)
888         return 0;
889
890     return m_frame->document()->getSelection();
891 }
892
893 Element* DOMWindow::frameElement() const
894 {
895     if (!m_frame)
896         return 0;
897
898     return m_frame->ownerElement();
899 }
900
901 void DOMWindow::focus()
902 {
903     if (!m_frame)
904         return;
905
906     Page* page = m_frame->page();
907     if (!page)
908         return;
909
910     // If we're a top level window, bring the window to the front.
911     if (m_frame == page->mainFrame())
912         page->chrome()->focus();
913
914     if (!m_frame)
915         return;
916
917     m_frame->eventHandler()->focusDocumentView();
918 }
919
920 void DOMWindow::blur()
921 {
922     if (!m_frame)
923         return;
924
925     Page* page = m_frame->page();
926     if (!page)
927         return;
928
929     if (m_frame != page->mainFrame())
930         return;
931
932     page->chrome()->unfocus();
933 }
934
935 void DOMWindow::close(ScriptExecutionContext* context)
936 {
937     if (!m_frame)
938         return;
939
940     Page* page = m_frame->page();
941     if (!page)
942         return;
943
944     if (m_frame != page->mainFrame())
945         return;
946
947     if (context) {
948         ASSERT(isMainThread());
949         Document* activeDocument = static_cast<Document*>(context);
950         if (!activeDocument)
951             return;
952
953         if (!activeDocument->canNavigate(m_frame))
954             return;
955     }
956
957     Settings* settings = m_frame->settings();
958     bool allowScriptsToCloseWindows = settings && settings->allowScriptsToCloseWindows();
959
960     if (!(page->openedByDOM() || page->backForward()->count() <= 1 || allowScriptsToCloseWindows))
961         return;
962
963     if (!m_frame->loader()->shouldClose())
964         return;
965
966     page->chrome()->closeWindowSoon();
967 }
968
969 void DOMWindow::print()
970 {
971     if (!m_frame)
972         return;
973
974     Page* page = m_frame->page();
975     if (!page)
976         return;
977
978     if (m_frame->loader()->activeDocumentLoader()->isLoading()) {
979         m_shouldPrintWhenFinishedLoading = true;
980         return;
981     }
982     m_shouldPrintWhenFinishedLoading = false;
983     page->chrome()->print(m_frame);
984 }
985
986 void DOMWindow::stop()
987 {
988     if (!m_frame)
989         return;
990
991     // We must check whether the load is complete asynchronously, because we might still be parsing
992     // the document until the callstack unwinds.
993     m_frame->loader()->stopForUserCancel(true);
994 }
995
996 void DOMWindow::alert(const String& message)
997 {
998     if (!m_frame)
999         return;
1000
1001     m_frame->document()->updateStyleIfNeeded();
1002
1003     Page* page = m_frame->page();
1004     if (!page)
1005         return;
1006
1007     page->chrome()->runJavaScriptAlert(m_frame, message);
1008 }
1009
1010 bool DOMWindow::confirm(const String& message)
1011 {
1012     if (!m_frame)
1013         return false;
1014
1015     m_frame->document()->updateStyleIfNeeded();
1016
1017     Page* page = m_frame->page();
1018     if (!page)
1019         return false;
1020
1021     return page->chrome()->runJavaScriptConfirm(m_frame, message);
1022 }
1023
1024 String DOMWindow::prompt(const String& message, const String& defaultValue)
1025 {
1026     if (!m_frame)
1027         return String();
1028
1029     m_frame->document()->updateStyleIfNeeded();
1030
1031     Page* page = m_frame->page();
1032     if (!page)
1033         return String();
1034
1035     String returnValue;
1036     if (page->chrome()->runJavaScriptPrompt(m_frame, message, defaultValue, returnValue))
1037         return returnValue;
1038
1039     return String();
1040 }
1041
1042 String DOMWindow::btoa(const String& stringToEncode, ExceptionCode& ec)
1043 {
1044     if (stringToEncode.isNull())
1045         return String();
1046
1047     if (!stringToEncode.containsOnlyLatin1()) {
1048         ec = INVALID_CHARACTER_ERR;
1049         return String();
1050     }
1051
1052     return base64Encode(stringToEncode.latin1());
1053 }
1054
1055 String DOMWindow::atob(const String& encodedString, ExceptionCode& ec)
1056 {
1057     if (encodedString.isNull())
1058         return String();
1059
1060     if (!encodedString.containsOnlyLatin1()) {
1061         ec = INVALID_CHARACTER_ERR;
1062         return String();
1063     }
1064
1065     Vector<char> out;
1066     if (!base64Decode(encodedString, out, FailOnInvalidCharacter)) {
1067         ec = INVALID_CHARACTER_ERR;
1068         return String();
1069     }
1070
1071     return String(out.data(), out.size());
1072 }
1073
1074 bool DOMWindow::find(const String& string, bool caseSensitive, bool backwards, bool wrap, bool /*wholeWord*/, bool /*searchInFrames*/, bool /*showDialog*/) const
1075 {
1076     if (!isCurrentlyDisplayedInFrame())
1077         return false;
1078
1079     // FIXME (13016): Support wholeWord, searchInFrames and showDialog
1080     return m_frame->editor()->findString(string, !backwards, caseSensitive, wrap, false);
1081 }
1082
1083 bool DOMWindow::offscreenBuffering() const
1084 {
1085     return true;
1086 }
1087
1088 int DOMWindow::outerHeight() const
1089 {
1090     if (!m_frame)
1091         return 0;
1092
1093     Page* page = m_frame->page();
1094     if (!page)
1095         return 0;
1096
1097     return static_cast<int>(page->chrome()->windowRect().height());
1098 }
1099
1100 int DOMWindow::outerWidth() const
1101 {
1102     if (!m_frame)
1103         return 0;
1104
1105     Page* page = m_frame->page();
1106     if (!page)
1107         return 0;
1108
1109     return static_cast<int>(page->chrome()->windowRect().width());
1110 }
1111
1112 int DOMWindow::innerHeight() const
1113 {
1114     if (!m_frame)
1115         return 0;
1116
1117     FrameView* view = m_frame->view();
1118     if (!view)
1119         return 0;
1120
1121     // If the device height is overridden, do not include the horizontal scrollbar into the innerHeight (since it is absent on the real device).
1122     bool includeScrollbars = !InspectorInstrumentation::shouldApplyScreenHeightOverride(m_frame);
1123     return view->mapFromLayoutToCSSUnits(static_cast<int>(view->visibleContentRect(includeScrollbars).height()));
1124 }
1125
1126 int DOMWindow::innerWidth() const
1127 {
1128     if (!m_frame)
1129         return 0;
1130
1131     FrameView* view = m_frame->view();
1132     if (!view)
1133         return 0;
1134
1135     // If the device width is overridden, do not include the vertical scrollbar into the innerWidth (since it is absent on the real device).
1136     bool includeScrollbars = !InspectorInstrumentation::shouldApplyScreenWidthOverride(m_frame);
1137     return view->mapFromLayoutToCSSUnits(static_cast<int>(view->visibleContentRect(includeScrollbars).width()));
1138 }
1139
1140 int DOMWindow::screenX() const
1141 {
1142     if (!m_frame)
1143         return 0;
1144
1145     Page* page = m_frame->page();
1146     if (!page)
1147         return 0;
1148
1149     return static_cast<int>(page->chrome()->windowRect().x());
1150 }
1151
1152 int DOMWindow::screenY() const
1153 {
1154     if (!m_frame)
1155         return 0;
1156
1157     Page* page = m_frame->page();
1158     if (!page)
1159         return 0;
1160
1161     return static_cast<int>(page->chrome()->windowRect().y());
1162 }
1163
1164 int DOMWindow::scrollX() const
1165 {
1166     if (!m_frame)
1167         return 0;
1168
1169     FrameView* view = m_frame->view();
1170     if (!view)
1171         return 0;
1172
1173     m_frame->document()->updateLayoutIgnorePendingStylesheets();
1174
1175     return view->mapFromLayoutToCSSUnits(view->scrollX());
1176 }
1177
1178 int DOMWindow::scrollY() const
1179 {
1180     if (!m_frame)
1181         return 0;
1182
1183     FrameView* view = m_frame->view();
1184     if (!view)
1185         return 0;
1186
1187     m_frame->document()->updateLayoutIgnorePendingStylesheets();
1188
1189     return view->mapFromLayoutToCSSUnits(view->scrollY());
1190 }
1191
1192 bool DOMWindow::closed() const
1193 {
1194     return !m_frame;
1195 }
1196
1197 unsigned DOMWindow::length() const
1198 {
1199     if (!isCurrentlyDisplayedInFrame())
1200         return 0;
1201
1202     return m_frame->tree()->scopedChildCount();
1203 }
1204
1205 String DOMWindow::name() const
1206 {
1207     if (!m_frame)
1208         return String();
1209
1210     return m_frame->tree()->name();
1211 }
1212
1213 void DOMWindow::setName(const String& string)
1214 {
1215     if (!m_frame)
1216         return;
1217
1218     m_frame->tree()->setName(string);
1219 }
1220
1221 void DOMWindow::setStatus(const String& string) 
1222 {
1223     m_status = string;
1224
1225     if (!m_frame)
1226         return;
1227
1228     Page* page = m_frame->page();
1229     if (!page)
1230         return;
1231
1232     ASSERT(m_frame->document()); // Client calls shouldn't be made when the frame is in inconsistent state.
1233     page->chrome()->setStatusbarText(m_frame, m_status);
1234
1235     
1236 void DOMWindow::setDefaultStatus(const String& string) 
1237 {
1238     m_defaultStatus = string;
1239
1240     if (!m_frame)
1241         return;
1242
1243     Page* page = m_frame->page();
1244     if (!page)
1245         return;
1246
1247     ASSERT(m_frame->document()); // Client calls shouldn't be made when the frame is in inconsistent state.
1248     page->chrome()->setStatusbarText(m_frame, m_defaultStatus);
1249 }
1250
1251 DOMWindow* DOMWindow::self() const
1252 {
1253     if (!m_frame)
1254         return 0;
1255
1256     return m_frame->domWindow();
1257 }
1258
1259 DOMWindow* DOMWindow::opener() const
1260 {
1261     if (!m_frame)
1262         return 0;
1263
1264     Frame* opener = m_frame->loader()->opener();
1265     if (!opener)
1266         return 0;
1267
1268     return opener->domWindow();
1269 }
1270
1271 DOMWindow* DOMWindow::parent() const
1272 {
1273     if (!m_frame)
1274         return 0;
1275
1276     Frame* parent = m_frame->tree()->parent(true);
1277     if (parent)
1278         return parent->domWindow();
1279
1280     return m_frame->domWindow();
1281 }
1282
1283 DOMWindow* DOMWindow::top() const
1284 {
1285     if (!m_frame)
1286         return 0;
1287
1288     Page* page = m_frame->page();
1289     if (!page)
1290         return 0;
1291
1292     return m_frame->tree()->top(true)->domWindow();
1293 }
1294
1295 Document* DOMWindow::document() const
1296 {
1297     if (!isCurrentlyDisplayedInFrame())
1298         return 0;
1299
1300     // FIXME: This function shouldn't need a frame to work.
1301     ASSERT(m_frame->document());
1302     return m_frame->document();
1303 }
1304
1305 PassRefPtr<StyleMedia> DOMWindow::styleMedia() const
1306 {
1307     if (!isCurrentlyDisplayedInFrame())
1308         return 0;
1309     if (!m_media)
1310         m_media = StyleMedia::create(m_frame);
1311     return m_media.get();
1312 }
1313
1314 PassRefPtr<CSSStyleDeclaration> DOMWindow::getComputedStyle(Element* elt, const String& pseudoElt) const
1315 {
1316     if (!elt)
1317         return 0;
1318
1319     return CSSComputedStyleDeclaration::create(elt, false, pseudoElt);
1320 }
1321
1322 PassRefPtr<CSSRuleList> DOMWindow::getMatchedCSSRules(Element* element, const String& pseudoElement, bool authorOnly) const
1323 {
1324     if (!isCurrentlyDisplayedInFrame())
1325         return 0;
1326
1327     unsigned colonStart = pseudoElement[0] == ':' ? (pseudoElement[1] == ':' ? 2 : 1) : 0;
1328     CSSSelector::PseudoType pseudoType = CSSSelector::parsePseudoType(AtomicString(pseudoElement.substring(colonStart)));
1329     if (pseudoType == CSSSelector::PseudoUnknown && !pseudoElement.isEmpty())
1330         return 0;
1331
1332     unsigned rulesToInclude = StyleResolver::AuthorCSSRules;
1333     if (!authorOnly)
1334         rulesToInclude |= StyleResolver::UAAndUserCSSRules;
1335     if (Settings* settings = m_frame->settings()) {
1336         if (settings->crossOriginCheckInGetMatchedCSSRulesDisabled())
1337             rulesToInclude |= StyleResolver::CrossOriginCSSRules;
1338     }
1339
1340     PseudoId pseudoId = CSSSelector::pseudoId(pseudoType);
1341
1342     return m_frame->document()->styleResolver()->pseudoStyleRulesForElement(element, pseudoId, rulesToInclude);
1343 }
1344
1345 PassRefPtr<WebKitPoint> DOMWindow::webkitConvertPointFromNodeToPage(Node* node, const WebKitPoint* p) const
1346 {
1347     if (!node || !p)
1348         return 0;
1349
1350     if (!document())
1351         return 0;
1352
1353     document()->updateLayoutIgnorePendingStylesheets();
1354
1355     FloatPoint pagePoint(p->x(), p->y());
1356     pagePoint = node->convertToPage(pagePoint);
1357     return WebKitPoint::create(pagePoint.x(), pagePoint.y());
1358 }
1359
1360 PassRefPtr<WebKitPoint> DOMWindow::webkitConvertPointFromPageToNode(Node* node, const WebKitPoint* p) const
1361 {
1362     if (!node || !p)
1363         return 0;
1364
1365     if (!document())
1366         return 0;
1367
1368     document()->updateLayoutIgnorePendingStylesheets();
1369
1370     FloatPoint nodePoint(p->x(), p->y());
1371     nodePoint = node->convertFromPage(nodePoint);
1372     return WebKitPoint::create(nodePoint.x(), nodePoint.y());
1373 }
1374
1375 double DOMWindow::devicePixelRatio() const
1376 {
1377     if (!m_frame)
1378         return 0.0;
1379
1380     Page* page = m_frame->page();
1381     if (!page)
1382         return 0.0;
1383
1384     return page->deviceScaleFactor();
1385 }
1386
1387 void DOMWindow::scrollBy(int x, int y) const
1388 {
1389     if (!isCurrentlyDisplayedInFrame())
1390         return;
1391
1392     document()->updateLayoutIgnorePendingStylesheets();
1393
1394     FrameView* view = m_frame->view();
1395     if (!view)
1396         return;
1397
1398     IntSize scaledOffset(view->mapFromCSSToLayoutUnits(x), view->mapFromCSSToLayoutUnits(y));
1399     view->scrollBy(scaledOffset);
1400 }
1401
1402 void DOMWindow::scrollTo(int x, int y) const
1403 {
1404     if (!isCurrentlyDisplayedInFrame())
1405         return;
1406
1407     document()->updateLayoutIgnorePendingStylesheets();
1408
1409     RefPtr<FrameView> view = m_frame->view();
1410     if (!view)
1411         return;
1412
1413     IntPoint layoutPos(view->mapFromCSSToLayoutUnits(x), view->mapFromCSSToLayoutUnits(y));
1414     view->setScrollPosition(layoutPos);
1415 }
1416
1417 void DOMWindow::moveBy(float x, float y) const
1418 {
1419     if (!m_frame)
1420         return;
1421
1422     Page* page = m_frame->page();
1423     if (!page)
1424         return;
1425
1426     if (m_frame != page->mainFrame())
1427         return;
1428
1429     FloatRect fr = page->chrome()->windowRect();
1430     FloatRect update = fr;
1431     update.move(x, y);
1432     // Security check (the spec talks about UniversalBrowserWrite to disable this check...)
1433     adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), fr, update);
1434     page->chrome()->setWindowRect(fr);
1435 }
1436
1437 void DOMWindow::moveTo(float x, float y) const
1438 {
1439     if (!m_frame)
1440         return;
1441
1442     Page* page = m_frame->page();
1443     if (!page)
1444         return;
1445
1446     if (m_frame != page->mainFrame())
1447         return;
1448
1449     FloatRect fr = page->chrome()->windowRect();
1450     FloatRect sr = screenAvailableRect(page->mainFrame()->view());
1451     fr.setLocation(sr.location());
1452     FloatRect update = fr;
1453     update.move(x, y);     
1454     // Security check (the spec talks about UniversalBrowserWrite to disable this check...)
1455     adjustWindowRect(sr, fr, update);
1456     page->chrome()->setWindowRect(fr);
1457 }
1458
1459 void DOMWindow::resizeBy(float x, float y) const
1460 {
1461     if (!m_frame)
1462         return;
1463
1464     Page* page = m_frame->page();
1465     if (!page)
1466         return;
1467
1468     if (m_frame != page->mainFrame())
1469         return;
1470
1471     FloatRect fr = page->chrome()->windowRect();
1472     FloatSize dest = fr.size() + FloatSize(x, y);
1473     FloatRect update(fr.location(), dest);
1474     adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), fr, update);
1475     page->chrome()->setWindowRect(fr);
1476 }
1477
1478 void DOMWindow::resizeTo(float width, float height) const
1479 {
1480     if (!m_frame)
1481         return;
1482
1483     Page* page = m_frame->page();
1484     if (!page)
1485         return;
1486
1487     if (m_frame != page->mainFrame())
1488         return;
1489
1490     FloatRect fr = page->chrome()->windowRect();
1491     FloatSize dest = FloatSize(width, height);
1492     FloatRect update(fr.location(), dest);
1493     adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), fr, update);
1494     page->chrome()->setWindowRect(fr);
1495 }
1496
1497 int DOMWindow::setTimeout(PassOwnPtr<ScheduledAction> action, int timeout, ExceptionCode& ec)
1498 {
1499     ScriptExecutionContext* context = scriptExecutionContext();
1500     if (!context) {
1501         ec = INVALID_ACCESS_ERR;
1502         return -1;
1503     }
1504     return DOMTimer::install(context, action, timeout, true);
1505 }
1506
1507 void DOMWindow::clearTimeout(int timeoutId)
1508 {
1509     ScriptExecutionContext* context = scriptExecutionContext();
1510     if (!context)
1511         return;
1512     DOMTimer::removeById(context, timeoutId);
1513 }
1514
1515 int DOMWindow::setInterval(PassOwnPtr<ScheduledAction> action, int timeout, ExceptionCode& ec)
1516 {
1517     ScriptExecutionContext* context = scriptExecutionContext();
1518     if (!context) {
1519         ec = INVALID_ACCESS_ERR;
1520         return -1;
1521     }
1522     return DOMTimer::install(context, action, timeout, false);
1523 }
1524
1525 void DOMWindow::clearInterval(int timeoutId)
1526 {
1527     ScriptExecutionContext* context = scriptExecutionContext();
1528     if (!context)
1529         return;
1530     DOMTimer::removeById(context, timeoutId);
1531 }
1532
1533 #if ENABLE(REQUEST_ANIMATION_FRAME)
1534 int DOMWindow::webkitRequestAnimationFrame(PassRefPtr<RequestAnimationFrameCallback> callback)
1535 {
1536     if (Document* d = document())
1537         return d->webkitRequestAnimationFrame(callback);
1538     return 0;
1539 }
1540
1541 void DOMWindow::webkitCancelAnimationFrame(int id)
1542 {
1543     if (Document* d = document())
1544         d->webkitCancelAnimationFrame(id);
1545 }
1546 #endif
1547
1548 bool DOMWindow::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
1549 {
1550     if (!EventTarget::addEventListener(eventType, listener, useCapture))
1551         return false;
1552
1553     if (Document* document = this->document()) {
1554         document->addListenerTypeIfNeeded(eventType);
1555         if (eventType == eventNames().mousewheelEvent)
1556             document->didAddWheelEventHandler();
1557         else if (eventNames().isTouchEventType(eventType))
1558             document->didAddTouchEventHandler();
1559     }
1560
1561     if (eventType == eventNames().unloadEvent)
1562         addUnloadEventListener(this);
1563     else if (eventType == eventNames().beforeunloadEvent && allowsBeforeUnloadListeners(this))
1564         addBeforeUnloadEventListener(this);
1565 #if ENABLE(DEVICE_ORIENTATION)
1566     else if (eventType == eventNames().devicemotionEvent) {
1567         if (DeviceMotionController* controller = DeviceMotionController::from(page()))
1568             controller->addListener(this);
1569     } else if (eventType == eventNames().deviceorientationEvent) {
1570         if (DeviceOrientationController* controller = DeviceOrientationController::from(page()))
1571             controller->addListener(this);
1572     }
1573 #endif
1574
1575     return true;
1576 }
1577
1578 bool DOMWindow::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
1579 {
1580     if (!EventTarget::removeEventListener(eventType, listener, useCapture))
1581         return false;
1582
1583     if (Document* document = this->document()) {
1584         if (eventType == eventNames().mousewheelEvent)
1585             document->didRemoveWheelEventHandler();
1586         else if (eventNames().isTouchEventType(eventType))
1587             document->didRemoveTouchEventHandler();
1588     }
1589
1590     if (eventType == eventNames().unloadEvent)
1591         removeUnloadEventListener(this);
1592     else if (eventType == eventNames().beforeunloadEvent && allowsBeforeUnloadListeners(this))
1593         removeBeforeUnloadEventListener(this);
1594 #if ENABLE(DEVICE_ORIENTATION)
1595     else if (eventType == eventNames().devicemotionEvent) {
1596         if (DeviceMotionController* controller = DeviceMotionController::from(page()))
1597             controller->removeListener(this);
1598     } else if (eventType == eventNames().deviceorientationEvent) {
1599         if (DeviceOrientationController* controller = DeviceOrientationController::from(page()))
1600             controller->removeListener(this);
1601     }
1602 #endif
1603
1604     return true;
1605 }
1606
1607 void DOMWindow::dispatchLoadEvent()
1608 {
1609     RefPtr<Event> loadEvent(Event::create(eventNames().loadEvent, false, false));
1610     if (m_frame && m_frame->loader()->documentLoader() && !m_frame->loader()->documentLoader()->timing()->loadEventStart()) {
1611         // The DocumentLoader (and thus its DocumentLoadTiming) might get destroyed while dispatching
1612         // the event, so protect it to prevent writing the end time into freed memory.
1613         RefPtr<DocumentLoader> documentLoader = m_frame->loader()->documentLoader();
1614         DocumentLoadTiming* timing = documentLoader->timing();
1615         timing->markLoadEventStart();
1616         dispatchEvent(loadEvent, document());
1617         timing->markLoadEventEnd();
1618     } else
1619         dispatchEvent(loadEvent, document());
1620
1621     // For load events, send a separate load event to the enclosing frame only.
1622     // This is a DOM extension and is independent of bubbling/capturing rules of
1623     // the DOM.
1624     Element* ownerElement = m_frame ? m_frame->ownerElement() : 0;
1625     if (ownerElement)
1626         ownerElement->dispatchEvent(Event::create(eventNames().loadEvent, false, false));
1627
1628     InspectorInstrumentation::loadEventFired(frame());
1629 }
1630
1631 bool DOMWindow::dispatchEvent(PassRefPtr<Event> prpEvent, PassRefPtr<EventTarget> prpTarget)
1632 {
1633     RefPtr<EventTarget> protect = this;
1634     RefPtr<Event> event = prpEvent;
1635
1636     event->setTarget(prpTarget ? prpTarget : this);
1637     event->setCurrentTarget(this);
1638     event->setEventPhase(Event::AT_TARGET);
1639
1640     InspectorInstrumentationCookie cookie = InspectorInstrumentation::willDispatchEventOnWindow(frame(), *event, this);
1641
1642     bool result = fireEventListeners(event.get());
1643
1644     InspectorInstrumentation::didDispatchEventOnWindow(cookie);
1645
1646     return result;
1647 }
1648
1649 void DOMWindow::removeAllEventListeners()
1650 {
1651     EventTarget::removeAllEventListeners();
1652
1653 #if ENABLE(DEVICE_ORIENTATION)
1654     if (DeviceMotionController* controller = DeviceMotionController::from(page()))
1655         controller->removeAllListeners(this);
1656     if (DeviceOrientationController* controller = DeviceOrientationController::from(page()))
1657         controller->removeAllListeners(this);
1658 #endif
1659
1660     removeAllUnloadEventListeners(this);
1661     removeAllBeforeUnloadEventListeners(this);
1662 }
1663
1664 void DOMWindow::captureEvents()
1665 {
1666     // Not implemented.
1667 }
1668
1669 void DOMWindow::releaseEvents()
1670 {
1671     // Not implemented.
1672 }
1673
1674 void DOMWindow::finishedLoading()
1675 {
1676     if (m_shouldPrintWhenFinishedLoading) {
1677         m_shouldPrintWhenFinishedLoading = false;
1678         print();
1679     }
1680 }
1681
1682 EventTargetData* DOMWindow::eventTargetData()
1683 {
1684     return &m_eventTargetData;
1685 }
1686
1687 EventTargetData* DOMWindow::ensureEventTargetData()
1688 {
1689     return &m_eventTargetData;
1690 }
1691
1692 void DOMWindow::setLocation(const String& urlString, DOMWindow* activeWindow, DOMWindow* firstWindow, SetLocationLocking locking)
1693 {
1694     if (!isCurrentlyDisplayedInFrame())
1695         return;
1696
1697     Document* activeDocument = activeWindow->document();
1698     if (!activeDocument)
1699         return;
1700
1701     if (!activeDocument->canNavigate(m_frame))
1702         return;
1703
1704     Frame* firstFrame = firstWindow->frame();
1705     if (!firstFrame)
1706         return;
1707
1708     KURL completedURL = firstFrame->document()->completeURL(urlString);
1709     if (completedURL.isNull())
1710         return;
1711
1712     if (isInsecureScriptAccess(activeWindow, completedURL))
1713         return;
1714
1715     // We want a new history item if we are processing a user gesture.
1716     m_frame->navigationScheduler()->scheduleLocationChange(activeDocument->securityOrigin(),
1717         // FIXME: What if activeDocument()->frame() is 0?
1718         completedURL, activeDocument->frame()->loader()->outgoingReferrer(),
1719         locking != LockHistoryBasedOnGestureState || !ScriptController::processingUserGesture(),
1720         locking != LockHistoryBasedOnGestureState);
1721 }
1722
1723 void DOMWindow::printErrorMessage(const String& message)
1724 {
1725     if (message.isEmpty())
1726         return;
1727
1728     Settings* settings = m_frame->settings();
1729     if (!settings)
1730         return;
1731     if (settings->privateBrowsingEnabled())
1732         return;
1733
1734     // FIXME: Add arguments so that we can provide a correct source URL and line number.
1735     RefPtr<ScriptCallStack> stackTrace = createScriptCallStack(ScriptCallStack::maxCallStackSizeToCapture, true);
1736     console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, message, stackTrace.release());
1737 }
1738
1739 String DOMWindow::crossDomainAccessErrorMessage(DOMWindow* activeWindow)
1740 {
1741     const KURL& activeWindowURL = activeWindow->url();
1742     if (activeWindowURL.isNull())
1743         return String();
1744
1745     // FIXME: This error message should contain more specifics of why the same origin check has failed.
1746     // Perhaps we should involve the security origin object in composing it.
1747     // FIXME: This message, and other console messages, have extra newlines. Should remove them.
1748     return "Unsafe JavaScript attempt to access frame with URL " + m_url.string() + " from frame with URL " + activeWindowURL.string() + ". Domains, protocols and ports must match.\n";
1749 }
1750
1751 bool DOMWindow::isInsecureScriptAccess(DOMWindow* activeWindow, const String& urlString)
1752 {
1753     if (!protocolIsJavaScript(urlString))
1754         return false;
1755
1756     // If this DOMWindow isn't currently active in the Frame, then there's no
1757     // way we should allow the access.
1758     // FIXME: Remove this check if we're able to disconnect DOMWindow from
1759     // Frame on navigation: https://bugs.webkit.org/show_bug.cgi?id=62054
1760     if (isCurrentlyDisplayedInFrame()) {
1761         // FIXME: Is there some way to eliminate the need for a separate "activeWindow == this" check?
1762         if (activeWindow == this)
1763             return false;
1764
1765         // FIXME: The name canAccess seems to be a roundabout way to ask "can execute script".
1766         // Can we name the SecurityOrigin function better to make this more clear?
1767         if (activeWindow->securityOrigin()->canAccess(securityOrigin()))
1768             return false;
1769     }
1770
1771     printErrorMessage(crossDomainAccessErrorMessage(activeWindow));
1772     return true;
1773 }
1774
1775 Frame* DOMWindow::createWindow(const String& urlString, const AtomicString& frameName, const WindowFeatures& windowFeatures,
1776     DOMWindow* activeWindow, Frame* firstFrame, Frame* openerFrame, PrepareDialogFunction function, void* functionContext)
1777 {
1778     Frame* activeFrame = activeWindow->frame();
1779
1780     // For whatever reason, Firefox uses the first frame to determine the outgoingReferrer. We replicate that behavior here.
1781     String referrer = firstFrame->loader()->outgoingReferrer();
1782
1783     KURL completedURL = urlString.isEmpty() ? KURL(ParsedURLString, emptyString()) : firstFrame->document()->completeURL(urlString);
1784     if (!completedURL.isEmpty() && !completedURL.isValid()) {
1785         // Don't expose client code to invalid URLs.
1786         activeWindow->printErrorMessage("Unable to open a window with invalid URL '" + completedURL.string() + "'.\n");
1787         return 0;
1788     }
1789
1790     ResourceRequest request(completedURL, referrer);
1791     FrameLoader::addHTTPOriginIfNeeded(request, firstFrame->loader()->outgoingOrigin());
1792     FrameLoadRequest frameRequest(activeWindow->securityOrigin(), request, frameName);
1793
1794     // We pass the opener frame for the lookupFrame in case the active frame is different from
1795     // the opener frame, and the name references a frame relative to the opener frame.
1796     bool created;
1797     Frame* newFrame = WebCore::createWindow(activeFrame, openerFrame, frameRequest, windowFeatures, created);
1798     if (!newFrame)
1799         return 0;
1800
1801     newFrame->loader()->setOpener(openerFrame);
1802     newFrame->page()->setOpenedByDOM();
1803
1804     if (newFrame->domWindow()->isInsecureScriptAccess(activeWindow, completedURL))
1805         return newFrame;
1806
1807     if (function)
1808         function(newFrame->domWindow(), functionContext);
1809
1810     if (created)
1811         newFrame->loader()->changeLocation(activeWindow->securityOrigin(), completedURL, referrer, false, false);
1812     else if (!urlString.isEmpty()) {
1813         bool lockHistory = !ScriptController::processingUserGesture();
1814         newFrame->navigationScheduler()->scheduleLocationChange(activeWindow->securityOrigin(), completedURL.string(), referrer, lockHistory, false);
1815     }
1816
1817     return newFrame;
1818 }
1819
1820 PassRefPtr<DOMWindow> DOMWindow::open(const String& urlString, const AtomicString& frameName, const String& windowFeaturesString,
1821     DOMWindow* activeWindow, DOMWindow* firstWindow)
1822 {
1823     if (!isCurrentlyDisplayedInFrame())
1824         return 0;
1825     Document* activeDocument = activeWindow->document();
1826     if (!activeDocument)
1827         return 0;
1828     Frame* firstFrame = firstWindow->frame();
1829     if (!firstFrame)
1830         return 0;
1831
1832     if (!firstWindow->allowPopUp()) {
1833         // Because FrameTree::find() returns true for empty strings, we must check for empty frame names.
1834         // Otherwise, illegitimate window.open() calls with no name will pass right through the popup blocker.
1835         if (frameName.isEmpty() || !m_frame->tree()->find(frameName))
1836             return 0;
1837     }
1838
1839     // Get the target frame for the special cases of _top and _parent.
1840     // In those cases, we schedule a location change right now and return early.
1841     Frame* targetFrame = 0;
1842     if (frameName == "_top")
1843         targetFrame = m_frame->tree()->top();
1844     else if (frameName == "_parent") {
1845         if (Frame* parent = m_frame->tree()->parent())
1846             targetFrame = parent;
1847         else
1848             targetFrame = m_frame;
1849     }
1850     if (targetFrame) {
1851         if (!activeDocument->canNavigate(targetFrame))
1852             return 0;
1853
1854         KURL completedURL = firstFrame->document()->completeURL(urlString);
1855
1856         if (targetFrame->domWindow()->isInsecureScriptAccess(activeWindow, completedURL))
1857             return targetFrame->domWindow();
1858
1859         if (urlString.isEmpty())
1860             return targetFrame->domWindow();
1861
1862         // For whatever reason, Firefox uses the first window rather than the active window to
1863         // determine the outgoing referrer. We replicate that behavior here.
1864         bool lockHistory = !ScriptController::processingUserGesture();
1865         targetFrame->navigationScheduler()->scheduleLocationChange(
1866             activeDocument->securityOrigin(),
1867             completedURL,
1868             firstFrame->loader()->outgoingReferrer(),
1869             lockHistory,
1870             false);
1871         return targetFrame->domWindow();
1872     }
1873
1874     WindowFeatures windowFeatures(windowFeaturesString);
1875     FloatRect windowRect(windowFeatures.xSet ? windowFeatures.x : 0, windowFeatures.ySet ? windowFeatures.y : 0,
1876         windowFeatures.widthSet ? windowFeatures.width : 0, windowFeatures.heightSet ? windowFeatures.height : 0);
1877     Page* page = m_frame->page();
1878     DOMWindow::adjustWindowRect(screenAvailableRect(page ? page->mainFrame()->view() : 0), windowRect, windowRect);
1879     windowFeatures.x = windowRect.x();
1880     windowFeatures.y = windowRect.y();
1881     windowFeatures.height = windowRect.height();
1882     windowFeatures.width = windowRect.width();
1883
1884     Frame* result = createWindow(urlString, frameName, windowFeatures, activeWindow, firstFrame, m_frame);
1885     return result ? result->domWindow() : 0;
1886 }
1887
1888 void DOMWindow::showModalDialog(const String& urlString, const String& dialogFeaturesString,
1889     DOMWindow* activeWindow, DOMWindow* firstWindow, PrepareDialogFunction function, void* functionContext)
1890 {
1891     if (!isCurrentlyDisplayedInFrame())
1892         return;
1893     Frame* activeFrame = activeWindow->frame();
1894     if (!activeFrame)
1895         return;
1896     Frame* firstFrame = firstWindow->frame();
1897     if (!firstFrame)
1898         return;
1899
1900     if (!canShowModalDialogNow(m_frame) || !firstWindow->allowPopUp())
1901         return;
1902
1903     Frame* dialogFrame = createWindow(urlString, emptyAtom, WindowFeatures(dialogFeaturesString, screenAvailableRect(m_frame->view())),
1904         activeWindow, firstFrame, m_frame, function, functionContext);
1905     if (!dialogFrame)
1906         return;
1907
1908     dialogFrame->page()->chrome()->runModal();
1909 }
1910
1911 #if ENABLE(QUOTA)
1912 StorageInfo* DOMWindow::webkitStorageInfo() const
1913 {
1914     if (!isCurrentlyDisplayedInFrame())
1915         return 0;
1916     if (!m_storageInfo)
1917         m_storageInfo = StorageInfo::create();
1918     return m_storageInfo.get();
1919 }
1920 #endif
1921
1922 } // namespace WebCore